Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/runit/runsvdir.c

    r1765 r2725  
    2626*/
    2727
    28 /* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
     28/* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
    2929/* TODO: depends on runit_lib.c - review and reduce/eliminate */
    3030
     
    3636#define MAXSERVICES 1000
    3737
     38/* Should be not needed - all dirs are on same FS, right? */
     39#define CHECK_DEVNO_TOO 0
     40
    3841struct service {
     42#if CHECK_DEVNO_TOO
    3943    dev_t dev;
     44#endif
    4045    ino_t ino;
    4146    pid_t pid;
     
    4348};
    4449
    45 struct service *sv;
    46 static char *svdir;
    47 static int svnum;
    48 static char *rplog;
    49 static int rploglen;
    50 static int logpipe[2];
    51 static struct pollfd pfd[1];
    52 static unsigned stamplog;
    53 static smallint check = 1;
    54 static smallint exitsoon;
    55 static smallint set_pgrp;
     50struct globals {
     51    struct service *sv;
     52    char *svdir;
     53    int svnum;
     54#if ENABLE_FEATURE_RUNSVDIR_LOG
     55    char *rplog;
     56    int rploglen;
     57    struct fd_pair logpipe;
     58    struct pollfd pfd[1];
     59    unsigned stamplog;
     60#endif
     61} FIX_ALIASING;
     62#define G (*(struct globals*)&bb_common_bufsiz1)
     63#define sv          (G.sv          )
     64#define svdir       (G.svdir       )
     65#define svnum       (G.svnum       )
     66#define rplog       (G.rplog       )
     67#define rploglen    (G.rploglen    )
     68#define logpipe     (G.logpipe     )
     69#define pfd         (G.pfd         )
     70#define stamplog    (G.stamplog    )
     71#define INIT_G() do { \
     72} while (0)
    5673
    5774static void fatal2_cannot(const char *m1, const char *m2)
    5875{
    59     bb_perror_msg_and_die("%s: fatal: cannot %s%s", svdir, m1, m2);
     76    bb_perror_msg_and_die("%s: fatal: can't %s%s", svdir, m1, m2);
    6077    /* was exiting 100 */
    6178}
     
    6683static void warn2_cannot(const char *m1, const char *m2)
    6784{
    68     warn3x("cannot ", m1, m2);
    69 }
     85    warn3x("can't ", m1, m2);
     86}
     87#if ENABLE_FEATURE_RUNSVDIR_LOG
    7088static void warnx(const char *m1)
    7189{
    7290    warn3x(m1, "", "");
    7391}
    74 
    75 static void s_term(int sig_no)
    76 {
    77     exitsoon = 1;
    78 }
    79 static void s_hangup(int sig_no)
    80 {
    81     exitsoon = 2;
    82 }
    83 
    84 static void runsv(int no, const char *name)
     92#endif
     93
     94/* inlining + vfork -> bigger code */
     95static NOINLINE pid_t runsv(const char *name)
    8596{
    8697    pid_t pid;
    87     char *prog[3];
    88 
    89     prog[0] = (char*)"runsv";
    90     prog[1] = (char*)name;
    91     prog[2] = NULL;
     98
     99    /* If we got signaled, stop spawning children at once! */
     100    if (bb_got_signal)
     101        return 0;
    92102
    93103    pid = vfork();
    94 
    95104    if (pid == -1) {
    96105        warn2_cannot("vfork", "");
    97         return;
     106        return 0;
    98107    }
    99108    if (pid == 0) {
    100109        /* child */
    101         if (set_pgrp)
     110        if (option_mask32 & 1) /* -P option? */
    102111            setsid();
    103         signal(SIGHUP, SIG_DFL);
    104         signal(SIGTERM, SIG_DFL);
    105         execvp(prog[0], prog);
     112/* man execv:
     113 * "Signals set to be caught by the calling process image
     114 *  shall be set to the default action in the new process image."
     115 * Therefore, we do not need this: */
     116#if 0
     117        bb_signals(0
     118            | (1 << SIGHUP)
     119            | (1 << SIGTERM)
     120            , SIG_DFL);
     121#endif
     122        execlp("runsv", "runsv", name, (char *) NULL);
    106123        fatal2_cannot("start runsv ", name);
    107124    }
    108     sv[no].pid = pid;
    109 }
    110 
    111 static void runsvdir(void)
     125    return pid;
     126}
     127
     128/* gcc 4.3.0 does better with NOINLINE */
     129static NOINLINE int do_rescan(void)
    112130{
    113131    DIR *dir;
    114     direntry *d;
     132    struct dirent *d;
    115133    int i;
    116134    struct stat s;
     135    int need_rescan = 0;
    117136
    118137    dir = opendir(".");
    119138    if (!dir) {
    120139        warn2_cannot("open directory ", svdir);
    121         return;
     140        return 1; /* need to rescan again soon */
    122141    }
    123142    for (i = 0; i < svnum; i++)
    124143        sv[i].isgone = 1;
    125     errno = 0;
    126     while ((d = readdir(dir))) {
     144
     145    while (1) {
     146        errno = 0;
     147        d = readdir(dir);
     148        if (!d)
     149            break;
    127150        if (d->d_name[0] == '.')
    128151            continue;
    129152        if (stat(d->d_name, &s) == -1) {
    130153            warn2_cannot("stat ", d->d_name);
    131             errno = 0;
    132154            continue;
    133155        }
    134156        if (!S_ISDIR(s.st_mode))
    135157            continue;
     158        /* Do we have this service listed already? */
    136159        for (i = 0; i < svnum; i++) {
    137             if ((sv[i].ino == s.st_ino) && (sv[i].dev == s.st_dev)) {
    138                 sv[i].isgone = 0;
    139                 if (!sv[i].pid)
    140                     runsv(i, d->d_name);
    141                 break;
    142             }
    143         }
    144         if (i == svnum) {
    145             /* new service */
     160            if ((sv[i].ino == s.st_ino)
     161#if CHECK_DEVNO_TOO
     162             && (sv[i].dev == s.st_dev)
     163#endif
     164            ) {
     165                if (sv[i].pid == 0) /* restart if it has died */
     166                    goto run_ith_sv;
     167                sv[i].isgone = 0; /* "we still see you" */
     168                goto next_dentry;
     169            }
     170        }
     171        { /* Not found, make new service */
    146172            struct service *svnew = realloc(sv, (i+1) * sizeof(*sv));
    147173            if (!svnew) {
    148                 warn3x("cannot start runsv ", d->d_name,
    149                         " too many services");
     174                warn2_cannot("start runsv ", d->d_name);
     175                need_rescan = 1;
    150176                continue;
    151177            }
    152178            sv = svnew;
    153179            svnum++;
    154             memset(&sv[i], 0, sizeof(sv[i]));
     180#if CHECK_DEVNO_TOO
     181            sv[i].dev = s.st_dev;
     182#endif
    155183            sv[i].ino = s.st_ino;
    156             sv[i].dev = s.st_dev;
    157             /*sv[i].pid = 0;*/
    158             /*sv[i].isgone = 0;*/
    159             runsv(i, d->d_name);
    160             check = 1;
    161         }
    162     }
    163     if (errno) {
     184 run_ith_sv:
     185            sv[i].pid = runsv(d->d_name);
     186            sv[i].isgone = 0;
     187        }
     188 next_dentry: ;
     189    }
     190    i = errno;
     191    closedir(dir);
     192    if (i) { /* readdir failed */
    164193        warn2_cannot("read directory ", svdir);
    165         closedir(dir);
    166         check = 1;
    167         return;
    168     }
    169     closedir(dir);
    170 
    171     /* SIGTERM removed runsv's */
     194        return 1; /* need to rescan again soon */
     195    }
     196
     197    /* Send SIGTERM to runsv whose directories
     198     * were no longer found (-> must have been removed) */
    172199    for (i = 0; i < svnum; i++) {
    173200        if (!sv[i].isgone)
     
    175202        if (sv[i].pid)
    176203            kill(sv[i].pid, SIGTERM);
    177         sv[i] = sv[--svnum];
    178         check = 1;
    179     }
    180 }
    181 
    182 static int setup_log(void)
    183 {
    184     rploglen = strlen(rplog);
    185     if (rploglen < 7) {
    186         warnx("log must have at least seven characters");
    187         return 0;
    188     }
    189     if (pipe(logpipe)) {
    190         warnx("cannot create pipe for log");
    191         return -1;
    192     }
    193     coe(logpipe[1]);
    194     coe(logpipe[0]);
    195     ndelay_on(logpipe[0]);
    196     ndelay_on(logpipe[1]);
    197     if (dup2(logpipe[1], 2) == -1) {
    198         warnx("cannot set filedescriptor for log");
    199         return -1;
    200     }
    201     pfd[0].fd = logpipe[0];
    202     pfd[0].events = POLLIN;
    203     stamplog = monotonic_sec();
    204     return 1;
    205 }
    206 
    207 int runsvdir_main(int argc, char **argv);
    208 int runsvdir_main(int argc, char **argv)
     204        svnum--;
     205        sv[i] = sv[svnum];
     206        i--; /* so that we don't skip new sv[i] (bug was here!) */
     207    }
     208    return need_rescan;
     209}
     210
     211int runsvdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     212int runsvdir_main(int argc UNUSED_PARAM, char **argv)
    209213{
    210214    struct stat s;
     
    214218    int wstat;
    215219    int curdir;
    216     int pid;
     220    pid_t pid;
    217221    unsigned deadline;
    218222    unsigned now;
    219223    unsigned stampcheck;
    220     char ch;
    221224    int i;
    222 
    223     argv++;
    224     if (!*argv)
    225         bb_show_usage();
    226     if (argv[0][0] == '-') {
    227         switch (argv[0][1]) {
    228         case 'P': set_pgrp = 1;
    229         case '-': ++argv;
    230         }
    231         if (!*argv)
    232             bb_show_usage();
    233     }
    234 
    235     sig_catch(SIGTERM, s_term);
    236     sig_catch(SIGHUP, s_hangup);
     225    int need_rescan = 1;
     226    char *opt_s_argv[3];
     227
     228    INIT_G();
     229
     230    opt_complementary = "-1";
     231    opt_s_argv[0] = NULL;
     232    opt_s_argv[2] = NULL;
     233    getopt32(argv, "Ps:", &opt_s_argv[0]);
     234    argv += optind;
     235
     236    bb_signals(0
     237        | (1 << SIGTERM)
     238        | (1 << SIGHUP)
     239        /* For busybox's init, SIGTERM == reboot,
     240         * SIGUSR1 == halt
     241         * SIGUSR2 == poweroff
     242         * so we need to intercept SIGUSRn too.
     243         * Note that we do not implement actual reboot
     244         * (killall(TERM) + umount, etc), we just pause
     245         * respawing and avoid exiting (-> making kernel oops).
     246         * The user is responsible for the rest. */
     247        | (getpid() == 1 ? ((1 << SIGUSR1) | (1 << SIGUSR2)) : 0)
     248        , record_signo);
    237249    svdir = *argv++;
    238     if (argv && *argv) {
     250
     251#if ENABLE_FEATURE_RUNSVDIR_LOG
     252    /* setup log */
     253    if (*argv) {
    239254        rplog = *argv;
    240         if (setup_log() != 1) {
    241             rplog = 0;
    242             warnx("log service disabled");
    243         }
    244     }
    245     curdir = open_read(".");
     255        rploglen = strlen(rplog);
     256        if (rploglen < 7) {
     257            warnx("log must have at least seven characters");
     258        } else if (piped_pair(logpipe)) {
     259            warnx("can't create pipe for log");
     260        } else {
     261            close_on_exec_on(logpipe.rd);
     262            close_on_exec_on(logpipe.wr);
     263            ndelay_on(logpipe.rd);
     264            ndelay_on(logpipe.wr);
     265            if (dup2(logpipe.wr, 2) == -1) {
     266                warnx("can't set filedescriptor for log");
     267            } else {
     268                pfd[0].fd = logpipe.rd;
     269                pfd[0].events = POLLIN;
     270                stamplog = monotonic_sec();
     271                goto run;
     272            }
     273        }
     274        rplog = NULL;
     275        warnx("log service disabled");
     276    }
     277 run:
     278#endif
     279    curdir = open(".", O_RDONLY|O_NDELAY);
    246280    if (curdir == -1)
    247281        fatal2_cannot("open current directory", "");
    248     coe(curdir);
     282    close_on_exec_on(curdir);
    249283
    250284    stampcheck = monotonic_sec();
     
    253287        /* collect children */
    254288        for (;;) {
    255             pid = wait_nohang(&wstat);
     289            pid = wait_any_nohang(&wstat);
    256290            if (pid <= 0)
    257291                break;
    258292            for (i = 0; i < svnum; i++) {
    259293                if (pid == sv[i].pid) {
    260                     /* runsv has gone */
     294                    /* runsv has died */
    261295                    sv[i].pid = 0;
    262                     check = 1;
    263                     break;
     296                    need_rescan = 1;
    264297                }
    265298            }
     
    272305
    273306            if (stat(svdir, &s) != -1) {
    274                 if (check || s.st_mtime != last_mtime
     307                if (need_rescan || s.st_mtime != last_mtime
    275308                 || s.st_ino != last_ino || s.st_dev != last_dev
    276309                ) {
     
    280313                        last_dev = s.st_dev;
    281314                        last_ino = s.st_ino;
    282                         check = 0;
    283                         //if (now <= mtime)
    284                         //  sleep(1);
    285                         runsvdir();
     315                        /* if the svdir changed this very second, wait until the
     316                         * next second, because we won't be able to detect more
     317                         * changes within this second */
     318                        while (time(NULL) == last_mtime)
     319                            usleep(100000);
     320                        need_rescan = do_rescan();
    286321                        while (fchdir(curdir) == -1) {
    287322                            warn2_cannot("change directory, pausing", "");
    288323                            sleep(5);
    289324                        }
    290                     } else
     325                    } else {
    291326                        warn2_cannot("change directory to ", svdir);
     327                    }
    292328                }
    293             } else
     329            } else {
    294330                warn2_cannot("stat ", svdir);
    295         }
    296 
     331            }
     332        }
     333
     334#if ENABLE_FEATURE_RUNSVDIR_LOG
    297335        if (rplog) {
    298336            if ((int)(now - stamplog) >= 0) {
    299                 write(logpipe[1], ".", 1);
     337                write(logpipe.wr, ".", 1);
    300338                stamplog = now + 900;
    301339            }
    302340        }
    303 
    304341        pfd[0].revents = 0;
     342#endif
     343        deadline = (need_rescan ? 1 : 5);
    305344        sig_block(SIGCHLD);
    306         deadline = (check ? 1 : 5);
     345#if ENABLE_FEATURE_RUNSVDIR_LOG
    307346        if (rplog)
    308347            poll(pfd, 1, deadline*1000);
    309348        else
     349#endif
    310350            sleep(deadline);
    311351        sig_unblock(SIGCHLD);
    312352
     353#if ENABLE_FEATURE_RUNSVDIR_LOG
    313354        if (pfd[0].revents & POLLIN) {
    314             while (read(logpipe[0], &ch, 1) > 0) {
    315                 if (ch) {
    316                     for (i = 6; i < rploglen; i++)
    317                         rplog[i-1] = rplog[i];
    318                     rplog[rploglen-1] = ch;
    319                 }
    320             }
    321         }
    322 
    323         switch (exitsoon) {
    324         case 1:
    325             _exit(0);
    326         case 2:
     355            char ch;
     356            while (read(logpipe.rd, &ch, 1) > 0) {
     357                if (ch < ' ')
     358                    ch = ' ';
     359                for (i = 6; i < rploglen; i++)
     360                    rplog[i-1] = rplog[i];
     361                rplog[rploglen-1] = ch;
     362            }
     363        }
     364#endif
     365        if (!bb_got_signal)
     366            continue;
     367
     368        /* -s SCRIPT: useful if we are init.
     369         * In this case typically script never returns,
     370         * it halts/powers off/reboots the system. */
     371        if (opt_s_argv[0]) {
     372            /* Single parameter: signal# */
     373            opt_s_argv[1] = utoa(bb_got_signal);
     374            pid = spawn(opt_s_argv);
     375            if (pid > 0) {
     376                /* Remembering to wait for _any_ children,
     377                 * not just pid */
     378                while (wait(NULL) != pid)
     379                    continue;
     380            }
     381        }
     382
     383        if (bb_got_signal == SIGHUP) {
    327384            for (i = 0; i < svnum; i++)
    328385                if (sv[i].pid)
    329386                    kill(sv[i].pid, SIGTERM);
    330             _exit(111);
    331         }
    332     }
    333     /* not reached */
    334     return 0;
    335 }
     387        }
     388        /* SIGHUP or SIGTERM (or SIGUSRn if we are init) */
     389        /* Exit unless we are init */
     390        if (getpid() != 1)
     391            return (SIGHUP == bb_got_signal) ? 111 : EXIT_SUCCESS;
     392
     393        /* init continues to monitor services forever */
     394        bb_got_signal = 0;
     395    } /* for (;;) */
     396}
Note: See TracChangeset for help on using the changeset viewer.