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