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
8 enum {
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
23 static const char *const tar_var[] ALIGN_PTR = {
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
xputenv(char * str)37 static void xputenv(char *str)
38 {
39 if (putenv(str))
40 bb_die_memory_exhausted();
41 }
42
str2env(char * env[],int idx,const char * str)43 static 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
dec2env(char * env[],int idx,unsigned long long val)49 static 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
oct2env(char * env[],int idx,unsigned long val)55 static 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
data_extract_to_command(archive_handle_t * archive_handle)61 void 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