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
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;
}
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))
/* 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);
/* 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
void bb_sanitize_stdio(void);
+// TODO: always error out?
enum { BB_GETOPT_ERROR = 0x80000000 };
extern const char *opt_complementary;
#if ENABLE_GETOPT_LONG
*/
#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. */
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)
if (WIFEXITED(status))
return WEXITSTATUS(status);
if (WIFSIGNALED(status))
- return WTERMSIG(status) + 10000;
+ return WTERMSIG(status) + 1000;
return 0;
}
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)