factor out NOFORK/NOEXEC code from find. Use it for xargs too.
No binary (build failed)
—
(log yok)
| @@ -238,37 +238,19 @@ ACTF(inum) | |
| ACTF(exec) | |
| { | |
| int i, rc; | |
| - | char *argv[ap->exec_argc+1]; |
| + | char *argv[ap->exec_argc + 1]; |
| for (i = 0; i < ap->exec_argc; i++) | |
| argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName); | |
| argv[i] = NULL; /* terminate the list */ | |
| - | if (ENABLE_FEATURE_EXEC_PREFER_APPLETS) { |
| - | const struct BB_applet *a = find_applet_by_name(argv[0]); |
| - | if (a) { |
| - | if (a->nofork) { |
| - | rc = a->main(ap->exec_argc, argv); |
| - | goto f; |
| - | } |
| - | #ifndef BB_NOMMU |
| - | if (a->noexec) { |
| - | rc = fork(); |
| - | if (rc) goto w; |
| - | current_applet = a; |
| - | run_current_applet_and_exit(ap->exec_argc, argv); |
| - | } |
| - | #endif |
| - | } |
| - | } |
| - | rc = spawn(argv); |
| - | w: |
| - | rc = wait4pid(rc); |
| + | rc = spawn_and_wait(argv); |
| if (rc < 0) | |
| bb_perror_msg("%s", argv[0]); | |
| - | f: |
| - | for (i = 0; i < ap->exec_argc; i++) |
| - | free(argv[i]); |
| - | return rc == 0; /* return 1 if success */ |
| + | |
| + | i = 0; |
| + | while (argv[i]) |
| + | free(argv[i++]); |
| + | return rc == 0; /* return 1 if exitcode 0 */ |
| } | |
| #endif | |
| @@ -48,47 +48,32 @@ | |
| This function has special algorithm. | |
| Don't use fork and include to main! | |
| */ | |
| - | static int xargs_exec(char *const *args) |
| + | static int xargs_exec(char **args) |
| { | |
| - | pid_t p; |
| - | volatile int exec_errno = 0; /* shared vfork stack */ |
| int status; | |
| - | p = vfork(); |
| - | if (p < 0) |
| - | bb_perror_msg_and_die("vfork"); |
| - | |
| - | if (p == 0) { |
| - | /* vfork -- child */ |
| - | BB_EXECVP(args[0], args); |
| - | exec_errno = errno; /* set error to shared stack */ |
| - | _exit(1); |
| - | } |
| - | |
| - | /* vfork -- parent */ |
| - | while (wait(&status) == (pid_t) -1) |
| - | if (errno != EINTR) |
| - | break; |
| - | if (exec_errno) { |
| - | errno = exec_errno; |
| + | status = spawn_and_wait(args); |
| + | if (status < 0) { |
| bb_perror_msg("%s", args[0]); | |
| - | return exec_errno == ENOENT ? 127 : 126; |
| + | return errno == ENOENT ? 127 : 126; |
| } | |
| - | if (WEXITSTATUS(status) == 255) { |
| + | if (status == 255) { |
| bb_error_msg("%s: exited with status 255; aborting", args[0]); | |
| return 124; | |
| } | |
| + | /* Huh? I think we won't see this, ever. We don't wait with WUNTRACED! |
| if (WIFSTOPPED(status)) { | |
| bb_error_msg("%s: stopped by signal %d", | |
| args[0], WSTOPSIG(status)); | |
| return 125; | |
| } | |
| - | if (WIFSIGNALED(status)) { |
| + | */ |
| + | if (status >= 1000) { |
| bb_error_msg("%s: terminated by signal %d", | |
| - | args[0], WTERMSIG(status)); |
| + | args[0], status - 1000); |
| return 125; | |
| } | |
| - | if (WEXITSTATUS(status)) |
| + | if (status) |
| return 123; | |
| return 0; | |
| } | |
| @@ -269,17 +269,6 @@ char *xrealloc_getcwd_or_warn(char *cwd); | |
| char *xmalloc_readlink_or_warn(const char *path); | |
| char *xmalloc_realpath(const char *path); | |
| - | /* Unlike waitpid, waits ONLY for one process, |
| - | * It's safe to pass negative 'pids' from failed [v]fork - |
| - | * wait4pid will return -1 and ECHILD in errno. |
| - | * IOW: rc = wait4pid(spawn(argv)); |
| - | * if (rc < 0) bb_perror_msg("%s", argv[0]); |
| - | * if (rc > 0) bb_error_msg("exit code: %d", rc); |
| - | */ |
| - | extern int wait4pid(int pid); |
| - | extern int wait_pid(int *wstat, int pid); |
| - | extern int wait_nohang(int *wstat); |
| - | //TODO: signal(sid, f) is the same? then why? |
| extern void sig_catch(int,void (*)(int)); | |
| //#define sig_ignore(s) (sig_catch((s), SIG_IGN)) | |
| //#define sig_uncatch(s) (sig_catch((s), SIG_DFL)) | |
| @@ -288,10 +277,6 @@ extern void sig_unblock(int); | |
| /* UNUSED: extern void sig_blocknone(void); */ | |
| extern void sig_pause(void); | |
| - | #define wait_crashed(w) ((w) & 127) |
| - | #define wait_exitcode(w) ((w) >> 8) |
| - | #define wait_stopsig(w) ((w) >> 8) |
| - | #define wait_stopped(w) (((w) & 127) == 127) |
| void xsetgid(gid_t gid); | |
| @@ -528,6 +513,25 @@ int bb_execvp(const char *file, char *const argv[]); | |
| /* NOMMU friendy fork+exec */ | |
| pid_t spawn(char **argv); | |
| pid_t xspawn(char **argv); | |
| + | |
| + | /* Unlike waitpid, waits ONLY for one process, |
| + | * It's safe to pass negative 'pids' from failed [v]fork - |
| + | * wait4pid will return -1 and ECHILD in errno. |
| + | * IOW: rc = wait4pid(spawn(argv)); |
| + | * if (rc < 0) bb_perror_msg("%s", argv[0]); |
| + | * if (rc > 0) bb_error_msg("exit code: %d", rc); |
| + | */ |
| + | int wait_pid(int *wstat, int pid); |
| + | int wait_nohang(int *wstat); |
| + | int wait4pid(int pid); |
| + | //TODO: signal(sid, f) is the same? then why? |
| + | #define wait_crashed(w) ((w) & 127) |
| + | #define wait_exitcode(w) ((w) >> 8) |
| + | #define wait_stopsig(w) ((w) >> 8) |
| + | #define wait_stopped(w) (((w) & 127) == 127) |
| + | /* wait4pid(spawn(argv)) + NOFORK/NOEXEC (if configured) */ |
| + | int spawn_and_wait(char **argv); |
| + | |
| /* Helpers for daemonization. | |
| * | |
| * bb_daemonize(flags) = daemonize, does not compile on NOMMU | |
| @@ -573,6 +577,7 @@ void bb_daemonize_or_rexec(int flags, char **argv); | |
| void bb_sanitize_stdio(void); | |
| + | // TODO: always error out? |
| enum { BB_GETOPT_ERROR = 0x80000000 }; | |
| extern const char *opt_complementary; | |
| #if ENABLE_GETOPT_LONG | |
| @@ -16,7 +16,7 @@ | |
| */ | |
| #include <paths.h> | |
| - | #include "libbb.h" |
| + | #include "busybox.h" /* for struct BB_applet */ |
| /* This does a fork/exec in one call, using vfork(). Returns PID of new child, | |
| * -1 for failure. Runs argv[0], searching path if that has no / in it. */ | |
| @@ -72,7 +72,8 @@ int wait4pid(int pid) | |
| int status; | |
| if (pid <= 0) { | |
| - | /*errno = ECHILD; -- wrong. we expect errno to be set from failed exec */ |
| + | /*errno = ECHILD; -- wrong. */ |
| + | /* we expect errno to be already set from failed [v]fork/exec */ |
| return -1; | |
| } | |
| if (waitpid(pid, &status, 0) == -1) | |
| @@ -80,7 +81,7 @@ int wait4pid(int pid) | |
| if (WIFEXITED(status)) | |
| return WEXITSTATUS(status); | |
| if (WIFSIGNALED(status)) | |
| - | return WTERMSIG(status) + 10000; |
| + | return WTERMSIG(status) + 1000; |
| return 0; | |
| } | |
| @@ -99,6 +100,41 @@ int wait_pid(int *wstat, int pid) | |
| return r; | |
| } | |
| + | int spawn_and_wait(char **argv) |
| + | { |
| + | int rc; |
| + | |
| + | if (ENABLE_FEATURE_EXEC_PREFER_APPLETS) { |
| + | const struct BB_applet *a = find_applet_by_name(argv[0]); |
| + | if (a && (a->nofork |
| + | #ifndef BB_NOMMU |
| + | || a->noexec /* NOEXEC cannot be used on NOMMU */ |
| + | #endif |
| + | )) { |
| + | int argc = 1; |
| + | char **pp = argv; |
| + | while (*++pp) |
| + | argc++; |
| + | #ifdef BB_NOMMU |
| + | return a->main(argc, argv); |
| + | #else |
| + | if (a->nofork) |
| + | return a->main(argc, argv); |
| + | /* a->noexec is true */ |
| + | rc = fork(); |
| + | if (rc) |
| + | goto w; |
| + | /* child */ |
| + | current_applet = a; |
| + | run_current_applet_and_exit(argc, argv); |
| + | #endif |
| + | } |
| + | } |
| + | rc = spawn(argv); |
| + | w: |
| + | return wait4pid(rc); |
| + | } |
| + | |
| #if 0 //ndef BB_NOMMU | |
| // Die with an error message if we can't daemonize. | |
| void xdaemon(int nochdir, int noclose) | |