diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-04-09 21:32:30 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-04-09 21:32:30 +0000 |
| commit | cd7001f7055c3fc2d6298ab9e3befe91e951c652 (patch) | |
| tree | b9509ed21e0a7af26128b796a66a3294ae4dc5b0 | |
| parent | 1b4b2cb20e5291c319ce0c7721e64445e2749b10 (diff) | |
| download | busybox-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.c | 32 | ||||
| -rw-r--r-- | findutils/xargs.c | 35 | ||||
| -rw-r--r-- | include/libbb.h | 35 | ||||
| -rw-r--r-- | libbb/vfork_daemon_rexec.c | 42 |
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) | |||
| 238 | ACTF(exec) | 238 | ACTF(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 | */ |
| 51 | static int xargs_exec(char *const *args) | 51 | static 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); | |||
| 269 | char *xmalloc_readlink_or_warn(const char *path); | 269 | char *xmalloc_readlink_or_warn(const char *path); |
| 270 | char *xmalloc_realpath(const char *path); | 270 | char *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 | */ | ||
| 279 | extern int wait4pid(int pid); | ||
| 280 | extern int wait_pid(int *wstat, int pid); | ||
| 281 | extern int wait_nohang(int *wstat); | ||
| 282 | //TODO: signal(sid, f) is the same? then why? | ||
| 283 | extern void sig_catch(int,void (*)(int)); | 272 | extern 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); */ |
| 289 | extern void sig_pause(void); | 278 | extern 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 | ||
| 297 | void xsetgid(gid_t gid); | 282 | void 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 */ |
| 529 | pid_t spawn(char **argv); | 514 | pid_t spawn(char **argv); |
| 530 | pid_t xspawn(char **argv); | 515 | pid_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 | */ | ||
| 524 | int wait_pid(int *wstat, int pid); | ||
| 525 | int wait_nohang(int *wstat); | ||
| 526 | int 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) */ | ||
| 533 | int 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); | |||
| 573 | void bb_sanitize_stdio(void); | 577 | void bb_sanitize_stdio(void); |
| 574 | 578 | ||
| 575 | 579 | ||
| 580 | // TODO: always error out? | ||
| 576 | enum { BB_GETOPT_ERROR = 0x80000000 }; | 581 | enum { BB_GETOPT_ERROR = 0x80000000 }; |
| 577 | extern const char *opt_complementary; | 582 | extern 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 | ||
| 103 | int 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. |
| 104 | void xdaemon(int nochdir, int noclose) | 140 | void xdaemon(int nochdir, int noclose) |
