1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include "busybox.h"
18#include "NUM_APPLETS.h"
19
20#define NOFORK_SUPPORT ((NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_NOFORK))
21#define NOEXEC_SUPPORT ((NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE))
22
23#if defined(__linux__) && (NUM_APPLETS > 1)
24# include <sys/prctl.h>
25# ifndef PR_SET_NAME
26# define PR_SET_NAME 15
27# endif
28# ifndef PR_GET_NAME
29# define PR_GET_NAME 16
30# endif
31# if ENABLE_FEATURE_SH_STANDALONE || ENABLE_FEATURE_PREFER_APPLETS || !BB_MMU
32int FAST_FUNC re_execed_comm(void)
33{
34 const char *e, *expected_comm;
35 char comm[16];
36
37 BUILD_BUG_ON(CONFIG_BUSYBOX_EXEC_PATH[0] != '/');
38 e = CONFIG_BUSYBOX_EXEC_PATH;
39
40 expected_comm = bb_busybox_exec_path + (strrchr(e, '/') - e) + 1;
41
42 prctl(PR_GET_NAME, (long)comm, 0, 0, 0);
43
44 return strcmp(comm, expected_comm) == 0;
45}
46# endif
47void FAST_FUNC set_task_comm(const char *comm)
48{
49
50 prctl(PR_SET_NAME, (long)comm, 0, 0, 0);
51}
52#endif
53
54
55
56
57#if NOFORK_SUPPORT
58static jmp_buf die_jmp;
59static void jump(void)
60{
61
62
63
64
65
66
67
68
69
70
71
72 longjmp(die_jmp, xfunc_error_retval | 0x100);
73}
74
75struct nofork_save_area {
76 jmp_buf die_jmp;
77 void (*die_func)(void);
78 const char *applet_name;
79 uint32_t option_mask32;
80 smallint logmode;
81 uint8_t xfunc_error_retval;
82};
83static void save_nofork_data(struct nofork_save_area *save)
84{
85 memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp));
86 save->die_func = die_func;
87 save->applet_name = applet_name;
88 save->option_mask32 = option_mask32;
89 save->logmode = logmode;
90 save->xfunc_error_retval = xfunc_error_retval;
91}
92static void restore_nofork_data(struct nofork_save_area *save)
93{
94 memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp));
95 die_func = save->die_func;
96 applet_name = save->applet_name;
97 option_mask32 = save->option_mask32;
98 logmode = save->logmode;
99 xfunc_error_retval = save->xfunc_error_retval;
100}
101
102int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
103{
104 int rc, argc;
105 struct nofork_save_area old;
106
107 save_nofork_data(&old);
108
109 logmode = LOGMODE_STDIO;
110 xfunc_error_retval = EXIT_FAILURE;
111
112
113
114
115 GETOPT_RESET();
116
117 argc = string_array_len(argv);
118
119
120 die_func = jump;
121 rc = setjmp(die_jmp);
122 if (!rc) {
123
124
125 char *tmp_argv[argc+1];
126 memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0]));
127 applet_name = tmp_argv[0];
128
129
130 show_usage_if_dash_dash_help(applet_no, argv);
131
132
133 rc = applet_main[applet_no](argc, tmp_argv);
134
135
136 fflush_all();
137 } else {
138
139 }
140
141
142 restore_nofork_data(&old);
143
144 GETOPT_RESET();
145
146 return rc & 0xff;
147}
148#endif
149
150#if NOEXEC_SUPPORT
151void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv)
152{
153
154
155 logmode = LOGMODE_STDIO;
156 xfunc_error_retval = EXIT_FAILURE;
157 die_func = NULL;
158 GETOPT_RESET();
159
160
161
162
163
164 set_task_comm(name);
165
166 run_applet_no_and_exit(a, name, argv);
167}
168#endif
169
170
171
172
173
174
175
176pid_t FAST_FUNC spawn(char **argv)
177{
178
179 volatile int failed;
180 pid_t pid;
181
182 fflush_all();
183
184
185 failed = 0;
186 pid = vfork();
187 if (pid < 0)
188 return pid;
189 if (!pid) {
190
191 BB_EXECVP(argv[0], argv);
192
193
194
195
196
197 failed = errno;
198
199
200 _exit(111);
201 }
202
203
204
205
206
207
208 if (failed) {
209 safe_waitpid(pid, NULL, 0);
210 errno = failed;
211 return -1;
212 }
213 return pid;
214}
215
216
217pid_t FAST_FUNC xspawn(char **argv)
218{
219 pid_t pid = spawn(argv);
220 if (pid < 0)
221 bb_simple_perror_msg_and_die(*argv);
222 return pid;
223}
224
225int FAST_FUNC spawn_and_wait(char **argv)
226{
227 int rc;
228#if ENABLE_FEATURE_PREFER_APPLETS && (NUM_APPLETS > 1)
229 int a = find_applet_by_name(argv[0]);
230
231 if (a >= 0) {
232 if (APPLET_IS_NOFORK(a))
233 return run_nofork_applet(a, argv);
234# if BB_MMU
235 if (APPLET_IS_NOEXEC(a)) {
236 fflush_all();
237 rc = fork();
238 if (rc)
239 return wait4pid(rc);
240
241
242 run_noexec_applet_and_exit(a, argv[0], argv);
243 }
244# endif
245 }
246#endif
247 rc = spawn(argv);
248 return wait4pid(rc);
249}
250
251#if !BB_MMU
252void FAST_FUNC re_exec(char **argv)
253{
254
255
256 argv[0][0] |= 0x80;
257 execv(bb_busybox_exec_path, argv);
258 bb_perror_msg_and_die("can't execute '%s'", bb_busybox_exec_path);
259}
260
261pid_t FAST_FUNC fork_or_rexec(char **argv)
262{
263 pid_t pid;
264
265 if (re_execed)
266 return 0;
267
268
269
270 pid = xvfork();
271 if (pid)
272 return pid;
273
274 re_exec(argv);
275}
276#endif
277
278
279
280void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv)
281{
282 int fd;
283
284 if (flags & DAEMON_CHDIR_ROOT)
285 xchdir("/");
286
287 fd = open(bb_dev_null, O_RDWR);
288 if (fd < 0) {
289
290
291
292
293 fd = xopen("/", O_RDONLY);
294 }
295
296 if (flags & DAEMON_DEVNULL_STDIO) {
297 xdup2(fd, 0);
298 xdup2(fd, 1);
299 xdup2(fd, 2);
300 } else {
301
302 while ((unsigned)fd < 2)
303 fd = dup(fd);
304 }
305
306 if (!(flags & DAEMON_ONLY_SANITIZE)) {
307
308
309
310 if (fork_or_rexec(argv))
311 _exit_SUCCESS();
312
313 setsid();
314 dup2(fd, 0);
315 dup2(fd, 1);
316 dup2(fd, 2);
317
318
319
320
321
322
323
324
325 }
326 while (fd > 2) {
327 close(fd--);
328 if (!(flags & DAEMON_CLOSE_EXTRA_FDS))
329 return;
330
331 }
332}
333
334void FAST_FUNC bb_sanitize_stdio(void)
335{
336 bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL);
337}
338