blob: 0fcabb4a987b7a812aaac15eb6b3b94a2e1f71fb [file] [log] [blame]
Ladislav Michl2b46fd42010-06-25 01:33:00 +02001/* vi: set sw=4 ts=4: */
2/*
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02003 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Ladislav Michl2b46fd42010-06-25 01:33:00 +02004 */
Ladislav Michl2b46fd42010-06-25 01:33:00 +02005#include "libbb.h"
Denys Vlasenkod184a722011-09-22 12:45:14 +02006#include "bb_archive.h"
Ladislav Michl2b46fd42010-06-25 01:33:00 +02007
8enum {
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
23static 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
37static void xputenv(char *str)
38{
39 if (putenv(str))
Denys Vlasenko899ae532018-04-01 19:59:37 +020040 bb_die_memory_exhausted();
Ladislav Michl2b46fd42010-06-25 01:33:00 +020041}
42
43static 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
49static 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
55static 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
61void 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 */
Denys Vlasenko6111f962012-02-23 13:45:18 +010066 char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE];
Ladislav Michl2b46fd42010-06-25 01:33:00 +020067 if (!sctx)
Denys Vlasenko6111f962012-02-23 13:45:18 +010068 sctx = archive_handle->tar__sctx[PAX_GLOBAL];
Ladislav Michl2b46fd42010-06-25 01:33:00 +020069 if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
70 setfscreatecon(sctx);
Denys Vlasenko6111f962012-02-23 13:45:18 +010071 free(archive_handle->tar__sctx[PAX_NEXT_FILE]);
72 archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL;
Ladislav Michl2b46fd42010-06-25 01:33:00 +020073 }
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);
Pascal Bellard926031b2010-07-04 15:32:38 +020084 pid = BB_MMU ? xfork() : xvfork();
85 if (pid == 0) {
Ladislav Michl2b46fd42010-06-25 01:33:00 +020086 /* 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);
Denys Vlasenko681efe22011-03-08 21:00:36 +0100101 execl(archive_handle->tar__to_command_shell,
102 archive_handle->tar__to_command_shell,
103 "-c",
104 archive_handle->tar__to_command,
Rich Felker16614e92013-06-30 13:45:17 +0200105 (char *)0);
Denys Vlasenko681efe22011-03-08 21:00:36 +0100106 bb_perror_msg_and_die("can't execute '%s'", archive_handle->tar__to_command_shell);
Ladislav Michl2b46fd42010-06-25 01:33:00 +0200107 }
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: */
Denys Vlasenkod0a8a0d2010-06-26 18:11:44 +0200111 bb_copyfd_exact_size(archive_handle->src_fd, p[1], -file_header->size);
Ladislav Michl2b46fd42010-06-25 01:33:00 +0200112 close(p[1]);
113
Denys Vlasenkoc4199f22016-04-01 22:12:44 +0200114 status = wait_for_exitstatus(pid);
Ladislav Michl2b46fd42010-06-25 01:33:00 +0200115 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))
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +0200119 bb_error_msg_and_die("'%s' terminated by signal %d",
Ladislav Michl2b46fd42010-06-25 01:33:00 +0200120 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}