aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-04-09 21:32:30 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-04-09 21:32:30 +0000
commitcd7001f7055c3fc2d6298ab9e3befe91e951c652 (patch)
treeb9509ed21e0a7af26128b796a66a3294ae4dc5b0
parent1b4b2cb20e5291c319ce0c7721e64445e2749b10 (diff)
downloadbusybox-w32-cd7001f7055c3fc2d6298ab9e3befe91e951c652.tar.gz
busybox-w32-cd7001f7055c3fc2d6298ab9e3befe91e951c652.tar.bz2
busybox-w32-cd7001f7055c3fc2d6298ab9e3befe91e951c652.zip
factor out NOFORK/NOEXEC code from find. Use it for xargs too.
-rw-r--r--findutils/find.c32
-rw-r--r--findutils/xargs.c35
-rw-r--r--include/libbb.h35
-rw-r--r--libbb/vfork_daemon_rexec.c42
4 files changed, 76 insertions, 68 deletions
diff --git a/findutils/find.c b/findutils/find.c
index 7b5a09d56..1a1301b38 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -238,37 +238,19 @@ ACTF(inum)
238ACTF(exec) 238ACTF(exec)
239{ 239{
240 int i, rc; 240 int i, rc;
241 char *argv[ap->exec_argc+1]; 241 char *argv[ap->exec_argc + 1];
242 for (i = 0; i < ap->exec_argc; i++) 242 for (i = 0; i < ap->exec_argc; i++)
243 argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName); 243 argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName);
244 argv[i] = NULL; /* terminate the list */ 244 argv[i] = NULL; /* terminate the list */
245 245
246 if (ENABLE_FEATURE_EXEC_PREFER_APPLETS) { 246 rc = spawn_and_wait(argv);
247 const struct BB_applet *a = find_applet_by_name(argv[0]);
248 if (a) {
249 if (a->nofork) {
250 rc = a->main(ap->exec_argc, argv);
251 goto f;
252 }
253#ifndef BB_NOMMU
254 if (a->noexec) {
255 rc = fork();
256 if (rc) goto w;
257 current_applet = a;
258 run_current_applet_and_exit(ap->exec_argc, argv);
259 }
260#endif
261 }
262 }
263 rc = spawn(argv);
264 w:
265 rc = wait4pid(rc);
266 if (rc < 0) 247 if (rc < 0)
267 bb_perror_msg("%s", argv[0]); 248 bb_perror_msg("%s", argv[0]);
268 f: 249
269 for (i = 0; i < ap->exec_argc; i++) 250 i = 0;
270 free(argv[i]); 251 while (argv[i])
271 return rc == 0; /* return 1 if success */ 252 free(argv[i++]);
253 return rc == 0; /* return 1 if exitcode 0 */
272} 254}
273#endif 255#endif
274 256
diff --git a/findutils/xargs.c b/findutils/xargs.c
index ea7c22060..b4dd9f876 100644
--- a/findutils/xargs.c
+++ b/findutils/xargs.c
@@ -48,47 +48,32 @@
48 This function has special algorithm. 48 This function has special algorithm.
49 Don't use fork and include to main! 49 Don't use fork and include to main!
50*/ 50*/
51static int xargs_exec(char *const *args) 51static int xargs_exec(char **args)
52{ 52{
53 pid_t p;
54 volatile int exec_errno = 0; /* shared vfork stack */
55 int status; 53 int status;
56 54
57 p = vfork(); 55 status = spawn_and_wait(args);
58 if (p < 0) 56 if (status < 0) {
59 bb_perror_msg_and_die("vfork");
60
61 if (p == 0) {
62 /* vfork -- child */
63 BB_EXECVP(args[0], args);
64 exec_errno = errno; /* set error to shared stack */
65 _exit(1);
66 }
67
68 /* vfork -- parent */
69 while (wait(&status) == (pid_t) -1)
70 if (errno != EINTR)
71 break;
72 if (exec_errno) {
73 errno = exec_errno;
74 bb_perror_msg("%s", args[0]); 57 bb_perror_msg("%s", args[0]);
75 return exec_errno == ENOENT ? 127 : 126; 58 return errno == ENOENT ? 127 : 126;
76 } 59 }
77 if (WEXITSTATUS(status) == 255) { 60 if (status == 255) {
78 bb_error_msg("%s: exited with status 255; aborting", args[0]); 61 bb_error_msg("%s: exited with status 255; aborting", args[0]);
79 return 124; 62 return 124;
80 } 63 }
64/* Huh? I think we won't see this, ever. We don't wait with WUNTRACED!
81 if (WIFSTOPPED(status)) { 65 if (WIFSTOPPED(status)) {
82 bb_error_msg("%s: stopped by signal %d", 66 bb_error_msg("%s: stopped by signal %d",
83 args[0], WSTOPSIG(status)); 67 args[0], WSTOPSIG(status));
84 return 125; 68 return 125;
85 } 69 }
86 if (WIFSIGNALED(status)) { 70*/
71 if (status >= 1000) {
87 bb_error_msg("%s: terminated by signal %d", 72 bb_error_msg("%s: terminated by signal %d",
88 args[0], WTERMSIG(status)); 73 args[0], status - 1000);
89 return 125; 74 return 125;
90 } 75 }
91 if (WEXITSTATUS(status)) 76 if (status)
92 return 123; 77 return 123;
93 return 0; 78 return 0;
94} 79}
diff --git a/include/libbb.h b/include/libbb.h
index 4fc5d183f..cec31a7f4 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -269,17 +269,6 @@ char *xrealloc_getcwd_or_warn(char *cwd);
269char *xmalloc_readlink_or_warn(const char *path); 269char *xmalloc_readlink_or_warn(const char *path);
270char *xmalloc_realpath(const char *path); 270char *xmalloc_realpath(const char *path);
271 271
272/* Unlike waitpid, waits ONLY for one process,
273 * It's safe to pass negative 'pids' from failed [v]fork -
274 * wait4pid will return -1 and ECHILD in errno.
275 * IOW: rc = wait4pid(spawn(argv));
276 * if (rc < 0) bb_perror_msg("%s", argv[0]);
277 * if (rc > 0) bb_error_msg("exit code: %d", rc);
278 */
279extern int wait4pid(int pid);
280extern int wait_pid(int *wstat, int pid);
281extern int wait_nohang(int *wstat);
282//TODO: signal(sid, f) is the same? then why?
283extern void sig_catch(int,void (*)(int)); 272extern void sig_catch(int,void (*)(int));
284//#define sig_ignore(s) (sig_catch((s), SIG_IGN)) 273//#define sig_ignore(s) (sig_catch((s), SIG_IGN))
285//#define sig_uncatch(s) (sig_catch((s), SIG_DFL)) 274//#define sig_uncatch(s) (sig_catch((s), SIG_DFL))
@@ -288,10 +277,6 @@ extern void sig_unblock(int);
288/* UNUSED: extern void sig_blocknone(void); */ 277/* UNUSED: extern void sig_blocknone(void); */
289extern void sig_pause(void); 278extern void sig_pause(void);
290 279
291#define wait_crashed(w) ((w) & 127)
292#define wait_exitcode(w) ((w) >> 8)
293#define wait_stopsig(w) ((w) >> 8)
294#define wait_stopped(w) (((w) & 127) == 127)
295 280
296 281
297void xsetgid(gid_t gid); 282void xsetgid(gid_t gid);
@@ -528,6 +513,25 @@ int bb_execvp(const char *file, char *const argv[]);
528/* NOMMU friendy fork+exec */ 513/* NOMMU friendy fork+exec */
529pid_t spawn(char **argv); 514pid_t spawn(char **argv);
530pid_t xspawn(char **argv); 515pid_t xspawn(char **argv);
516
517/* Unlike waitpid, waits ONLY for one process,
518 * It's safe to pass negative 'pids' from failed [v]fork -
519 * wait4pid will return -1 and ECHILD in errno.
520 * IOW: rc = wait4pid(spawn(argv));
521 * if (rc < 0) bb_perror_msg("%s", argv[0]);
522 * if (rc > 0) bb_error_msg("exit code: %d", rc);
523 */
524int wait_pid(int *wstat, int pid);
525int wait_nohang(int *wstat);
526int wait4pid(int pid);
527//TODO: signal(sid, f) is the same? then why?
528#define wait_crashed(w) ((w) & 127)
529#define wait_exitcode(w) ((w) >> 8)
530#define wait_stopsig(w) ((w) >> 8)
531#define wait_stopped(w) (((w) & 127) == 127)
532/* wait4pid(spawn(argv)) + NOFORK/NOEXEC (if configured) */
533int spawn_and_wait(char **argv);
534
531/* Helpers for daemonization. 535/* Helpers for daemonization.
532 * 536 *
533 * bb_daemonize(flags) = daemonize, does not compile on NOMMU 537 * bb_daemonize(flags) = daemonize, does not compile on NOMMU
@@ -573,6 +577,7 @@ void bb_daemonize_or_rexec(int flags, char **argv);
573void bb_sanitize_stdio(void); 577void bb_sanitize_stdio(void);
574 578
575 579
580// TODO: always error out?
576enum { BB_GETOPT_ERROR = 0x80000000 }; 581enum { BB_GETOPT_ERROR = 0x80000000 };
577extern const char *opt_complementary; 582extern const char *opt_complementary;
578#if ENABLE_GETOPT_LONG 583#if ENABLE_GETOPT_LONG
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index ff2b0bceb..d25693917 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -16,7 +16,7 @@
16 */ 16 */
17 17
18#include <paths.h> 18#include <paths.h>
19#include "libbb.h" 19#include "busybox.h" /* for struct BB_applet */
20 20
21/* This does a fork/exec in one call, using vfork(). Returns PID of new child, 21/* This does a fork/exec in one call, using vfork(). Returns PID of new child,
22 * -1 for failure. Runs argv[0], searching path if that has no / in it. */ 22 * -1 for failure. Runs argv[0], searching path if that has no / in it. */
@@ -72,7 +72,8 @@ int wait4pid(int pid)
72 int status; 72 int status;
73 73
74 if (pid <= 0) { 74 if (pid <= 0) {
75 /*errno = ECHILD; -- wrong. we expect errno to be set from failed exec */ 75 /*errno = ECHILD; -- wrong. */
76 /* we expect errno to be already set from failed [v]fork/exec */
76 return -1; 77 return -1;
77 } 78 }
78 if (waitpid(pid, &status, 0) == -1) 79 if (waitpid(pid, &status, 0) == -1)
@@ -80,7 +81,7 @@ int wait4pid(int pid)
80 if (WIFEXITED(status)) 81 if (WIFEXITED(status))
81 return WEXITSTATUS(status); 82 return WEXITSTATUS(status);
82 if (WIFSIGNALED(status)) 83 if (WIFSIGNALED(status))
83 return WTERMSIG(status) + 10000; 84 return WTERMSIG(status) + 1000;
84 return 0; 85 return 0;
85} 86}
86 87
@@ -99,6 +100,41 @@ int wait_pid(int *wstat, int pid)
99 return r; 100 return r;
100} 101}
101 102
103int spawn_and_wait(char **argv)
104{
105 int rc;
106
107 if (ENABLE_FEATURE_EXEC_PREFER_APPLETS) {
108 const struct BB_applet *a = find_applet_by_name(argv[0]);
109 if (a && (a->nofork
110#ifndef BB_NOMMU
111 || a->noexec /* NOEXEC cannot be used on NOMMU */
112#endif
113 )) {
114 int argc = 1;
115 char **pp = argv;
116 while (*++pp)
117 argc++;
118#ifdef BB_NOMMU
119 return a->main(argc, argv);
120#else
121 if (a->nofork)
122 return a->main(argc, argv);
123 /* a->noexec is true */
124 rc = fork();
125 if (rc)
126 goto w;
127 /* child */
128 current_applet = a;
129 run_current_applet_and_exit(argc, argv);
130#endif
131 }
132 }
133 rc = spawn(argv);
134 w:
135 return wait4pid(rc);
136}
137
102#if 0 //ndef BB_NOMMU 138#if 0 //ndef BB_NOMMU
103// Die with an error message if we can't daemonize. 139// Die with an error message if we can't daemonize.
104void xdaemon(int nochdir, int noclose) 140void xdaemon(int nochdir, int noclose)