Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (16 years ago)
Author:
Bruno Cornec
Message:

Update to busybox 1.7.2

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.5/mindi-busybox/libbb/vfork_daemon_rexec.c

    r821 r1765  
    1616 */
    1717
    18 #include <unistd.h>
    19 #include <stdio.h>
    20 #include <fcntl.h>
    2118#include <paths.h>
    22 #include "libbb.h"
    23 
    24 
    25 #ifdef BB_NOMMU
    26 void vfork_daemon_rexec(int nochdir, int noclose,
    27         int argc, char **argv, char *foreground_opt)
     19#include "busybox.h" /* for struct bb_applet */
     20
     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. */
     23pid_t spawn(char **argv)
     24{
     25    /* Compiler should not optimize stores here */
     26    volatile int failed;
     27    pid_t pid;
     28
     29// Ain't it a good place to fflush(NULL)?
     30
     31    /* Be nice to nommu machines. */
     32    failed = 0;
     33    pid = vfork();
     34    if (pid < 0) /* error */
     35        return pid;
     36    if (!pid) { /* child */
     37        /* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */
     38        BB_EXECVP(argv[0], argv);
     39
     40        /* We are (maybe) sharing a stack with blocked parent,
     41         * let parent know we failed and then exit to unblock parent
     42         * (but don't run atexit() stuff, which would screw up parent.)
     43         */
     44        failed = errno;
     45        _exit(111);
     46    }
     47    /* parent */
     48    /* Unfortunately, this is not reliable: according to standards
     49     * vfork() can be equivalent to fork() and we won't see value
     50     * of 'failed'.
     51     * Interested party can wait on pid and learn exit code.
     52     * If 111 - then it (most probably) failed to exec */
     53    if (failed) {
     54        errno = failed;
     55        return -1;
     56    }
     57    return pid;
     58}
     59
     60/* Die with an error message if we can't spawn a child process. */
     61pid_t xspawn(char **argv)
     62{
     63    pid_t pid = spawn(argv);
     64    if (pid < 0)
     65        bb_perror_msg_and_die("%s", *argv);
     66    return pid;
     67}
     68
     69// Wait for the specified child PID to exit, returning child's error return.
     70int wait4pid(int pid)
     71{
     72    int status;
     73
     74    if (pid <= 0) {
     75        /*errno = ECHILD; -- wrong. */
     76        /* we expect errno to be already set from failed [v]fork/exec */
     77        return -1;
     78    }
     79    if (waitpid(pid, &status, 0) == -1)
     80        return -1;
     81    if (WIFEXITED(status))
     82        return WEXITSTATUS(status);
     83    if (WIFSIGNALED(status))
     84        return WTERMSIG(status) + 1000;
     85    return 0;
     86}
     87
     88int wait_nohang(int *wstat)
     89{
     90    return waitpid(-1, wstat, WNOHANG);
     91}
     92
     93int wait_pid(int *wstat, int pid)
     94{
     95    int r;
     96
     97    do
     98        r = waitpid(pid, wstat, 0);
     99    while ((r == -1) && (errno == EINTR));
     100    return r;
     101}
     102
     103#if ENABLE_FEATURE_PREFER_APPLETS
     104void save_nofork_data(struct nofork_save_area *save)
     105{
     106    memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp));
     107    save->current_applet = current_applet;
     108    save->xfunc_error_retval = xfunc_error_retval;
     109    save->option_mask32 = option_mask32;
     110    save->die_sleep = die_sleep;
     111    save->saved = 1;
     112}
     113
     114void restore_nofork_data(struct nofork_save_area *save)
     115{
     116    memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp));
     117    current_applet = save->current_applet;
     118    xfunc_error_retval = save->xfunc_error_retval;
     119    option_mask32 = save->option_mask32;
     120    die_sleep = save->die_sleep;
     121
     122    applet_name = current_applet->name;
     123}
     124
     125int run_nofork_applet_prime(struct nofork_save_area *old, const struct bb_applet *a, char **argv)
     126{
     127    int rc, argc;
     128
     129    current_applet = a;
     130    applet_name = a->name;
     131    xfunc_error_retval = EXIT_FAILURE;
     132    /*option_mask32 = 0; - not needed */
     133    /* special flag for xfunc_die(). If xfunc will "die"
     134     * in NOFORK applet, xfunc_die() sees negative
     135     * die_sleep and longjmp here instead. */
     136    die_sleep = -1;
     137
     138    argc = 1;
     139    while (argv[argc])
     140        argc++;
     141
     142    rc = setjmp(die_jmp);
     143    if (!rc) {
     144        /* Some callers (xargs)
     145         * need argv untouched because they free argv[i]! */
     146        char *tmp_argv[argc+1];
     147        memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0]));
     148        /* Finally we can call NOFORK applet's main() */
     149        rc = a->main(argc, tmp_argv);
     150    } else { /* xfunc died in NOFORK applet */
     151        /* in case they meant to return 0... */
     152        if (rc == -2222)
     153            rc = 0;
     154    }
     155
     156    /* Restoring globals */
     157    restore_nofork_data(old);
     158    return rc;
     159}
     160
     161int run_nofork_applet(const struct bb_applet *a, char **argv)
     162{
     163    struct nofork_save_area old;
     164
     165    /* Saving globals */
     166    save_nofork_data(&old);
     167    return run_nofork_applet_prime(&old, a, argv);
     168}
     169#endif /* FEATURE_PREFER_APPLETS */
     170
     171int spawn_and_wait(char **argv)
     172{
     173    int rc;
     174#if ENABLE_FEATURE_PREFER_APPLETS
     175    const struct bb_applet *a = find_applet_by_name(argv[0]);
     176
     177    if (a && (a->nofork
     178#if BB_MMU
     179         || a->noexec /* NOEXEC trick needs fork() */
     180#endif
     181    )) {
     182#if BB_MMU
     183        if (a->nofork)
     184#endif
     185        {
     186            return run_nofork_applet(a, argv);
     187        }
     188#if BB_MMU
     189        /* MMU only */
     190        /* a->noexec is true */
     191        rc = fork();
     192        if (rc) /* parent or error */
     193            return wait4pid(rc);
     194        /* child */
     195        xfunc_error_retval = EXIT_FAILURE;
     196        current_applet = a;
     197        run_current_applet_and_exit(argv);
     198#endif
     199    }
     200#endif /* FEATURE_PREFER_APPLETS */
     201    rc = spawn(argv);
     202    return wait4pid(rc);
     203}
     204
     205#if !BB_MMU
     206void re_exec(char **argv)
     207{
     208    /* high-order bit of first char in argv[0] is a hidden
     209     * "we have (already) re-execed, don't do it again" flag */
     210    argv[0][0] |= 0x80;
     211    execv(bb_busybox_exec_path, argv);
     212    bb_perror_msg_and_die("exec %s", bb_busybox_exec_path);
     213}
     214
     215void forkexit_or_rexec(char **argv)
     216{
     217    pid_t pid;
     218    /* Maybe we are already re-execed and come here again? */
     219    if (re_execed)
     220        return;
     221
     222    pid = vfork();
     223    if (pid < 0) /* wtf? */
     224        bb_perror_msg_and_die("vfork");
     225    if (pid) /* parent */
     226        exit(0);
     227    /* child - re-exec ourself */
     228    re_exec(argv);
     229}
     230#else
     231/* Dance around (void)...*/
     232#undef forkexit_or_rexec
     233void forkexit_or_rexec(void)
     234{
     235    pid_t pid;
     236    pid = fork();
     237    if (pid < 0) /* wtf? */
     238        bb_perror_msg_and_die("fork");
     239    if (pid) /* parent */
     240        exit(0);
     241    /* child */
     242}
     243#define forkexit_or_rexec(argv) forkexit_or_rexec()
     244#endif
     245
     246/* Due to a #define in libbb.h on MMU systems we actually have 1 argument -
     247 * char **argv "vanishes" */
     248void bb_daemonize_or_rexec(int flags, char **argv)
    28249{
    29250    int fd;
    30     char **vfork_args;
    31     int a = 0;
    32 
    33     setsid();
    34 
    35     if (!nochdir)
    36         chdir("/");
    37 
    38     if (!noclose && (fd = open(bb_dev_null, O_RDWR, 0)) != -1) {
    39         dup2(fd, STDIN_FILENO);
    40         dup2(fd, STDOUT_FILENO);
    41         dup2(fd, STDERR_FILENO);
    42         if (fd > 2)
    43             close(fd);
    44     }
    45 
    46     vfork_args = xcalloc(sizeof(char *), argc + 3);
    47     vfork_args[a++] = "/bin/busybox";
    48     while(*argv) {
    49         vfork_args[a++] = *argv;
    50         argv++;
    51     }
    52     vfork_args[a] = foreground_opt;
    53     switch (vfork()) {
    54     case 0: /* child */
    55         /* Make certain we are not a session leader, or else we
    56          * might reacquire a controlling terminal */
    57         if (vfork())
    58             _exit(0);
    59         execv(vfork_args[0], vfork_args);
    60         bb_perror_msg_and_die("execv %s", vfork_args[0]);
    61     case -1: /* error */
    62         bb_perror_msg_and_die("vfork");
    63     default: /* parent */
    64         exit(0);
    65     }
    66 }
    67 #endif /* BB_NOMMU */
     251
     252    if (flags & DAEMON_CHDIR_ROOT)
     253        xchdir("/");
     254
     255    if (flags & DAEMON_DEVNULL_STDIO) {
     256        close(0);
     257        close(1);
     258        close(2);
     259    }
     260
     261    fd = xopen(bb_dev_null, O_RDWR);
     262
     263    while ((unsigned)fd < 2)
     264        fd = dup(fd); /* have 0,1,2 open at least to /dev/null */
     265
     266    if (!(flags & DAEMON_ONLY_SANITIZE)) {
     267        forkexit_or_rexec(argv);
     268        /* if daemonizing, make sure we detach from stdio & ctty */
     269        setsid();
     270        dup2(fd, 0);
     271        dup2(fd, 1);
     272        dup2(fd, 2);
     273    }
     274    while (fd > 2) {
     275        close(fd--);
     276        if (!(flags & DAEMON_CLOSE_EXTRA_FDS))
     277            return;
     278        /* else close everything after fd#2 */
     279    }
     280}
     281
     282void bb_sanitize_stdio(void)
     283{
     284    bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL);
     285}
Note: See TracChangeset for help on using the changeset viewer.