busybox/archival/libarchive/data_extract_to_command.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   4 */
   5#include "libbb.h"
   6#include "bb_archive.h"
   7
   8enum {
   9        //TAR_FILETYPE,
  10        TAR_MODE,
  11        TAR_FILENAME,
  12        TAR_REALNAME,
  13#if ENABLE_FEATURE_TAR_UNAME_GNAME
  14        TAR_UNAME,
  15        TAR_GNAME,
  16#endif
  17        TAR_SIZE,
  18        TAR_UID,
  19        TAR_GID,
  20        TAR_MAX,
  21};
  22
  23static const char *const tar_var[] = {
  24        // "FILETYPE",
  25        "MODE",
  26        "FILENAME",
  27        "REALNAME",
  28#if ENABLE_FEATURE_TAR_UNAME_GNAME
  29        "UNAME",
  30        "GNAME",
  31#endif
  32        "SIZE",
  33        "UID",
  34        "GID",
  35};
  36
  37static void xputenv(char *str)
  38{
  39        if (putenv(str))
  40                bb_die_memory_exhausted();
  41}
  42
  43static void str2env(char *env[], int idx, const char *str)
  44{
  45        env[idx] = xasprintf("TAR_%s=%s", tar_var[idx], str);
  46        xputenv(env[idx]);
  47}
  48
  49static void dec2env(char *env[], int idx, unsigned long long val)
  50{
  51        env[idx] = xasprintf("TAR_%s=%llu", tar_var[idx], val);
  52        xputenv(env[idx]);
  53}
  54
  55static void oct2env(char *env[], int idx, unsigned long val)
  56{
  57        env[idx] = xasprintf("TAR_%s=%lo", tar_var[idx], val);
  58        xputenv(env[idx]);
  59}
  60
  61void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle)
  62{
  63        file_header_t *file_header = archive_handle->file_header;
  64
  65#if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */
  66        char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE];
  67        if (!sctx)
  68                sctx = archive_handle->tar__sctx[PAX_GLOBAL];
  69        if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
  70                setfscreatecon(sctx);
  71                free(archive_handle->tar__sctx[PAX_NEXT_FILE]);
  72                archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL;
  73        }
  74#endif
  75
  76        if ((file_header->mode & S_IFMT) == S_IFREG) {
  77                pid_t pid;
  78                int p[2], status;
  79                char *tar_env[TAR_MAX];
  80
  81                memset(tar_env, 0, sizeof(tar_env));
  82
  83                xpipe(p);
  84                pid = BB_MMU ? xfork() : xvfork();
  85                if (pid == 0) {
  86                        /* Child */
  87                        /* str2env(tar_env, TAR_FILETYPE, "f"); - parent should do it once */
  88                        oct2env(tar_env, TAR_MODE, file_header->mode);
  89                        str2env(tar_env, TAR_FILENAME, file_header->name);
  90                        str2env(tar_env, TAR_REALNAME, file_header->name);
  91#if ENABLE_FEATURE_TAR_UNAME_GNAME
  92                        str2env(tar_env, TAR_UNAME, file_header->tar__uname);
  93                        str2env(tar_env, TAR_GNAME, file_header->tar__gname);
  94#endif
  95                        dec2env(tar_env, TAR_SIZE, file_header->size);
  96                        dec2env(tar_env, TAR_UID, file_header->uid);
  97                        dec2env(tar_env, TAR_GID, file_header->gid);
  98                        close(p[1]);
  99                        xdup2(p[0], STDIN_FILENO);
 100                        signal(SIGPIPE, SIG_DFL);
 101                        execl(archive_handle->tar__to_command_shell,
 102                                archive_handle->tar__to_command_shell,
 103                                "-c",
 104                                archive_handle->tar__to_command,
 105                                (char *)0);
 106                        bb_perror_msg_and_die("can't execute '%s'", archive_handle->tar__to_command_shell);
 107                }
 108                close(p[0]);
 109                /* Our caller is expected to do signal(SIGPIPE, SIG_IGN)
 110                 * so that we don't die if child don't read all the input: */
 111                bb_copyfd_exact_size(archive_handle->src_fd, p[1], -file_header->size);
 112                close(p[1]);
 113
 114                status = wait_for_exitstatus(pid);
 115                if (WIFEXITED(status) && WEXITSTATUS(status))
 116                        bb_error_msg_and_die("'%s' returned status %d",
 117                                archive_handle->tar__to_command, WEXITSTATUS(status));
 118                if (WIFSIGNALED(status))
 119                        bb_error_msg_and_die("'%s' terminated by signal %d",
 120                                archive_handle->tar__to_command, WTERMSIG(status));
 121
 122                if (!BB_MMU) {
 123                        int i;
 124                        for (i = 0; i < TAR_MAX; i++) {
 125                                if (tar_env[i])
 126                                        bb_unsetenv_and_free(tar_env[i]);
 127                        }
 128                }
 129        }
 130
 131#if 0 /* ENABLE_FEATURE_TAR_SELINUX */
 132        if (sctx)
 133                /* reset the context after creating an entry */
 134                setfscreatecon(NULL);
 135#endif
 136}
 137