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