From cd7001f7055c3fc2d6298ab9e3befe91e951c652 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Mon, 9 Apr 2007 21:32:30 +0000 Subject: [PATCH] factor out NOFORK/NOEXEC code from find. Use it for xargs too. --- findutils/find.c | 32 +++++++---------------------- findutils/xargs.c | 35 +++++++++---------------------- include/libbb.h | 35 +++++++++++++++++-------------- 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) 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 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 @@ 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; } 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); 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 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 @@ */ #include -#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) -- 2.25.1