factor out NOFORK/NOEXEC code from find. Use it for xargs too.
authorDenis Vlasenko <vda.linux@googlemail.com>
Mon, 9 Apr 2007 21:32:30 +0000 (21:32 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Mon, 9 Apr 2007 21:32:30 +0000 (21:32 -0000)
findutils/find.c
findutils/xargs.c
include/libbb.h
libbb/vfork_daemon_rexec.c

index 7b5a09d56ebc67c411004c4fd5ba5d5fbc0d8349..1a1301b38c1d33f2651eea265a7199e956a1d3db 100644 (file)
@@ -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
 
index ea7c220604e717e3016dacc60ce18295184d1af3..b4dd9f876b4159c62c75007bb0d6541278c714b5 100644 (file)
    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;
 }
index 4fc5d183f9e2cfe6b6f27c38c4b21193dd136546..cec31a7f486e686f1647b975eb8d02fd68a06401 100644 (file)
@@ -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
index ff2b0bcebc300aa1ec5421da6ca481216f119024..d25693917be8ea6d29908339e923d56229482357 100644 (file)
@@ -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)