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