Start 1.33.0 development cycle
[oweals/busybox.git] / archival / libarchive / data_extract_to_command.c
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[] = {
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
37 static void xputenv(char *str)
38 {
39         if (putenv(str))
40                 bb_die_memory_exhausted();
41 }
42
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
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
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
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 }