1 | /* vi: set sw=4 ts=4: */
|
---|
2 | /*
|
---|
3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
---|
4 | */
|
---|
5 |
|
---|
6 | #include "libbb.h"
|
---|
7 | #include "bb_archive.h"
|
---|
8 |
|
---|
9 | enum {
|
---|
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 |
|
---|
24 | static 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 |
|
---|
38 | static void xputenv(char *str)
|
---|
39 | {
|
---|
40 | if (putenv(str))
|
---|
41 | bb_error_msg_and_die(bb_msg_memory_exhausted);
|
---|
42 | }
|
---|
43 |
|
---|
44 | static 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 |
|
---|
50 | static 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 |
|
---|
56 | static 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 |
|
---|
62 | void 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__sctx[PAX_NEXT_FILE];
|
---|
68 | if (!sctx)
|
---|
69 | sctx = archive_handle->tar__sctx[PAX_GLOBAL];
|
---|
70 | if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
|
---|
71 | setfscreatecon(sctx);
|
---|
72 | free(archive_handle->tar__sctx[PAX_NEXT_FILE]);
|
---|
73 | archive_handle->tar__sctx[PAX_NEXT_FILE] = 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(archive_handle->tar__to_command_shell,
|
---|
103 | archive_handle->tar__to_command_shell,
|
---|
104 | "-c",
|
---|
105 | archive_handle->tar__to_command,
|
---|
106 | NULL);
|
---|
107 | bb_perror_msg_and_die("can't execute '%s'", archive_handle->tar__to_command_shell);
|
---|
108 | }
|
---|
109 | close(p[0]);
|
---|
110 | /* Our caller is expected to do signal(SIGPIPE, SIG_IGN)
|
---|
111 | * so that we don't die if child don't read all the input: */
|
---|
112 | bb_copyfd_exact_size(archive_handle->src_fd, p[1], -file_header->size);
|
---|
113 | close(p[1]);
|
---|
114 |
|
---|
115 | if (safe_waitpid(pid, &status, 0) == -1)
|
---|
116 | bb_perror_msg_and_die("waitpid");
|
---|
117 | if (WIFEXITED(status) && WEXITSTATUS(status))
|
---|
118 | bb_error_msg_and_die("'%s' returned status %d",
|
---|
119 | archive_handle->tar__to_command, WEXITSTATUS(status));
|
---|
120 | if (WIFSIGNALED(status))
|
---|
121 | bb_error_msg_and_die("'%s' terminated on signal %d",
|
---|
122 | archive_handle->tar__to_command, WTERMSIG(status));
|
---|
123 |
|
---|
124 | if (!BB_MMU) {
|
---|
125 | int i;
|
---|
126 | for (i = 0; i < TAR_MAX; i++) {
|
---|
127 | if (tar_env[i])
|
---|
128 | bb_unsetenv_and_free(tar_env[i]);
|
---|
129 | }
|
---|
130 | }
|
---|
131 | }
|
---|
132 |
|
---|
133 | #if 0 /* ENABLE_FEATURE_TAR_SELINUX */
|
---|
134 | if (sctx)
|
---|
135 | /* reset the context after creating an entry */
|
---|
136 | setfscreatecon(NULL);
|
---|
137 | #endif
|
---|
138 | }
|
---|