tar: optional support for --to-command

function                                             old     new   delta
data_extract_to_command                                -     430    +430
dec2env                                                -      44     +44
tar_main                                             778     819     +41
str2env                                                -      37     +37
tar_var                                                -      32     +32
xputenv                                                -      22     +22
tar_longopts                                         257     270     +13
------------------------------------------------------------------------------
(add/remove: 6/0 grow/shrink: 2/0 up/down: 619/0)             Total: 619 bytes

Signed-off-by: Ladislav Michl <Ladislav.Michl@seznam.cz>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Ladislav Michl 2010-06-25 01:33:00 +02:00 committed by Denys Vlasenko
parent 51fa147c9b
commit 2b46fd49b1
5 changed files with 163 additions and 0 deletions

View File

@ -280,6 +280,15 @@ config FEATURE_TAR_LONG_OPTIONS
help
Enable use of long options, increases size by about 400 Bytes
config FEATURE_TAR_TO_COMMAND
bool "Support for writing to an external program"
default y
depends on TAR && FEATURE_TAR_LONG_OPTIONS
help
If you enable this option you'll be able to instruct tar to send
the contents of each extracted file to the standard input of an
external program.
config FEATURE_TAR_UNAME_GNAME
bool "Enable use of user and group names"
default y

View File

@ -53,6 +53,7 @@ lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2
lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o get_header_tar_lzma.o
lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o
lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o
lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o
ifneq ($(lib-y),)
lib-y += $(COMMON_FILES)

View File

@ -0,0 +1,137 @@
/* vi: set sw=4 ts=4: */
/*
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
#include "libbb.h"
#include "unarchive.h"
enum {
//TAR_FILETYPE,
TAR_MODE,
TAR_FILENAME,
TAR_REALNAME,
#if ENABLE_FEATURE_TAR_UNAME_GNAME
TAR_UNAME,
TAR_GNAME,
#endif
TAR_SIZE,
TAR_UID,
TAR_GID,
TAR_MAX,
};
static const char *const tar_var[] = {
// "FILETYPE",
"MODE",
"FILENAME",
"REALNAME",
#if ENABLE_FEATURE_TAR_UNAME_GNAME
"UNAME",
"GNAME",
#endif
"SIZE",
"UID",
"GID",
};
static void xputenv(char *str)
{
if (putenv(str))
bb_error_msg_and_die(bb_msg_memory_exhausted);
}
static void str2env(char *env[], int idx, const char *str)
{
env[idx] = xasprintf("TAR_%s=%s", tar_var[idx], str);
xputenv(env[idx]);
}
static void dec2env(char *env[], int idx, unsigned long long val)
{
env[idx] = xasprintf("TAR_%s=%llu", tar_var[idx], val);
xputenv(env[idx]);
}
static void oct2env(char *env[], int idx, unsigned long val)
{
env[idx] = xasprintf("TAR_%s=%lo", tar_var[idx], val);
xputenv(env[idx]);
}
void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle)
{
file_header_t *file_header = archive_handle->file_header;
#if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */
char *sctx = archive_handle->tar__next_file_sctx;
if (!sctx)
sctx = archive_handle->tar__global_sctx;
if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
setfscreatecon(sctx);
free(archive_handle->tar__next_file_sctx);
archive_handle->tar__next_file_sctx = NULL;
}
#endif
if ((file_header->mode & S_IFMT) == S_IFREG) {
pid_t pid;
int p[2], status;
char *tar_env[TAR_MAX];
memset(tar_env, 0, sizeof(tar_env));
xpipe(p);
pid = BB_MMU ? fork() : vfork();
switch (pid) {
case -1:
bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork");
case 0:
/* Child */
/* str2env(tar_env, TAR_FILETYPE, "f"); - parent should do it once */
oct2env(tar_env, TAR_MODE, file_header->mode);
str2env(tar_env, TAR_FILENAME, file_header->name);
str2env(tar_env, TAR_REALNAME, file_header->name);
#if ENABLE_FEATURE_TAR_UNAME_GNAME
str2env(tar_env, TAR_UNAME, file_header->tar__uname);
str2env(tar_env, TAR_GNAME, file_header->tar__gname);
#endif
dec2env(tar_env, TAR_SIZE, file_header->size);
dec2env(tar_env, TAR_UID, file_header->uid);
dec2env(tar_env, TAR_GID, file_header->gid);
close(p[1]);
xdup2(p[0], STDIN_FILENO);
signal(SIGPIPE, SIG_DFL);
execl("/bin/sh", "/bin/sh" + 5, "-c", archive_handle->tar__to_command, NULL);
bb_perror_msg_and_die("can't execute '%s'", "/bin/sh");
}
close(p[0]);
/* Our caller is expected to do signal(SIGPIPE, SIG_IGN)
* so that we don't die if child don't read all the input: */
bb_copyfd_exact_size(archive_handle->src_fd, p[1], file_header->size);
close(p[1]);
if (safe_waitpid(pid, &status, 0) == -1)
bb_perror_msg_and_die("waitpid");
if (WIFEXITED(status) && WEXITSTATUS(status))
bb_error_msg_and_die("'%s' returned status %d",
archive_handle->tar__to_command, WEXITSTATUS(status));
if (WIFSIGNALED(status))
bb_error_msg_and_die("'%s' terminated on signal %d",
archive_handle->tar__to_command, WTERMSIG(status));
if (!BB_MMU) {
int i;
for (i = 0; i < TAR_MAX; i++) {
if (tar_env[i])
bb_unsetenv_and_free(tar_env[i]);
}
}
}
#if 0 /* ENABLE_FEATURE_TAR_SELINUX */
if (sctx)
/* reset the context after creating an entry */
setfscreatecon(NULL);
#endif
}

View File

@ -750,6 +750,7 @@ enum {
IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,) // 16th bit
IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,)
#if ENABLE_FEATURE_TAR_LONG_OPTIONS
IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND ,)
OPTBIT_NUMERIC_OWNER,
OPTBIT_NOPRESERVE_PERM,
OPTBIT_OVERWRITE,
@ -772,6 +773,7 @@ enum {
OPT_GZIP = IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP )) + 0, // z
OPT_COMPRESS = IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS )) + 0, // Z
OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m
OPT_2COMMAND = IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND )) + 0, // to-command
OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner
OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions
OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite
@ -812,6 +814,9 @@ static const char tar_longopts[] ALIGN1 =
# endif
# if ENABLE_FEATURE_TAR_NOPRESERVE_TIME
"touch\0" No_argument "m"
# endif
# if ENABLE_FEATURE_TAR_TO_COMMAND
"to-command\0" Required_argument "\xfb"
# endif
/* use numeric uid/gid from tar header, not textual */
"numeric-owner\0" No_argument "\xfc"
@ -904,6 +909,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
, &tar_filename // -f filename
IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X
IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command)) // --to-command
#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
, &excludes // --exclude
#endif
@ -922,6 +928,12 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
if (opt & OPT_2STDOUT)
tar_handle->action_data = data_extract_to_stdout;
if (opt & OPT_2COMMAND) {
putenv((char*)"TAR_FILETYPE=f");
signal(SIGPIPE, SIG_IGN);
tar_handle->action_data = data_extract_to_command;
}
if (opt & OPT_KEEP_OLD)
tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;

View File

@ -75,6 +75,9 @@ typedef struct archive_handle_t {
char* tar__longname;
char* tar__linkname;
# endif
#if ENABLE_FEATURE_TAR_TO_COMMAND
char* tar__to_command;
#endif
# if ENABLE_FEATURE_TAR_SELINUX
char* tar__global_sctx;
char* tar__next_file_sctx;
@ -128,6 +131,7 @@ extern void unpack_ar_archive(archive_handle_t *ar_archive) FAST_FUNC;
extern void data_skip(archive_handle_t *archive_handle) FAST_FUNC;
extern void data_extract_all(archive_handle_t *archive_handle) FAST_FUNC;
extern void data_extract_to_stdout(archive_handle_t *archive_handle) FAST_FUNC;
extern void data_extract_to_command(archive_handle_t *archive_handle) FAST_FUNC;
extern void header_skip(const file_header_t *file_header) FAST_FUNC;
extern void header_list(const file_header_t *file_header) FAST_FUNC;