123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- /* vi: set sw=4 ts=4: */
- /*
- * Licensed under GPLv2 or later, see file LICENSE in this source tree.
- */
- #include "libbb.h"
- #include "bb_archive.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[] ALIGN_PTR = {
- // "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_die_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__sctx[PAX_NEXT_FILE];
- if (!sctx)
- sctx = archive_handle->tar__sctx[PAX_GLOBAL];
- if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
- setfscreatecon(sctx);
- free(archive_handle->tar__sctx[PAX_NEXT_FILE]);
- archive_handle->tar__sctx[PAX_NEXT_FILE] = 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 ? xfork() : xvfork();
- if (pid == 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(archive_handle->tar__to_command_shell,
- archive_handle->tar__to_command_shell,
- "-c",
- archive_handle->tar__to_command,
- (char *)0);
- bb_perror_msg_and_die("can't execute '%s'", archive_handle->tar__to_command_shell);
- }
- 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]);
- status = wait_for_exitstatus(pid);
- 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 by 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
- }
|