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/debianutils/start_stop_daemon.c

    r1765 r2725  
    66 * Adapted for busybox David Kimdon <dwhedon@gordian.com>
    77 *
    8  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    99 */
    1010
    11 /* NB: we have a problem here with /proc/NN/exe usage, similar to
    12  * one fixed in killall/pidof */
    13 
    14 #include <getopt.h>
     11/*
     12This is how it is supposed to work:
     13
     14start-stop-daemon [OPTIONS] [--start|--stop] [[--] arguments...]
     15
     16One (only) of these must be given:
     17        -S,--start              Start
     18        -K,--stop               Stop
     19
     20Search for matching processes.
     21If --stop is given, stop all matching processes (by sending a signal).
     22If --start is given, start a new process unless a matching process was found.
     23
     24Options controlling process matching
     25(if multiple conditions are specified, all must match):
     26        -u,--user USERNAME|UID  Only consider this user's processes
     27        -n,--name PROCESS_NAME  Look for processes by matching PROCESS_NAME
     28                                with comm field in /proc/$PID/stat.
     29                                Only basename is compared:
     30                                "ntpd" == "./ntpd" == "/path/to/ntpd".
     31[TODO: can PROCESS_NAME be a full pathname? Should we require full match then
     32with /proc/$PID/exe or argv[0] (comm can't be matched, it never contains path)]
     33        -x,--exec EXECUTABLE    Look for processes that were started with this
     34                                command in /proc/$PID/cmdline.
     35                                Unlike -n, we match against the full path:
     36                                "ntpd" != "./ntpd" != "/path/to/ntpd"
     37        -p,--pidfile PID_FILE   Look for processes with PID from this file
     38
     39Options which are valid for --start only:
     40        -x,--exec EXECUTABLE    Program to run (1st arg of execvp). Mandatory.
     41        -a,--startas NAME       argv[0] (defaults to EXECUTABLE)
     42        -b,--background         Put process into background
     43        -N,--nicelevel N        Add N to process' nice level
     44        -c,--chuid USER[:[GRP]] Change to specified user [and group]
     45        -m,--make-pidfile       Write PID to the pidfile
     46                                (both -m and -p must be given!)
     47
     48Options which are valid for --stop only:
     49        -s,--signal SIG         Signal to send (default:TERM)
     50        -t,--test               Exit with status 0 if process is found
     51                                (we don't actually start or stop daemons)
     52
     53Misc options:
     54        -o,--oknodo             Exit with status 0 if nothing is done
     55        -q,--quiet              Quiet
     56        -v,--verbose            Verbose
     57*/
     58
    1559#include <sys/resource.h>
    1660
     
    1862#define WANT_PIDFILE 1
    1963#include "libbb.h"
    20 
    21 static int signal_nr = 15;
    22 static int user_id = -1;
    23 static char *userspec;
    24 static char *cmdname;
    25 static char *execname;
    26 static char *pidfile;
    27 static smallint quiet;
    2864
    2965struct pid_list {
     
    3268};
    3369
    34 static struct pid_list *found;
    35 
    36 static int pid_is_exec(pid_t pid, const char *name)
    37 {
    38     char buf[sizeof("/proc//exe") + sizeof(int)*3];
    39     char *execbuf;
    40     int n;
    41 
    42     sprintf(buf, "/proc/%u/exe", pid);
    43     n = strlen(name) + 1;
    44     execbuf = xzalloc(n + 1);
    45     readlink(buf, execbuf, n);
    46 
    47     /* if readlink fails, execbuf still contains "" */
    48     n = strcmp(execbuf, name);
    49     if (ENABLE_FEATURE_CLEAN_UP)
    50         free(execbuf);
    51     return !n; /* nonzero (true) if execbuf == name */
    52 }
    53 
    54 static int pid_is_user(int pid, int uid)
     70enum {
     71    CTX_STOP       = (1 <<  0),
     72    CTX_START      = (1 <<  1),
     73    OPT_BACKGROUND = (1 <<  2), // -b
     74    OPT_QUIET      = (1 <<  3), // -q
     75    OPT_TEST       = (1 <<  4), // -t
     76    OPT_MAKEPID    = (1 <<  5), // -m
     77    OPT_a          = (1 <<  6), // -a
     78    OPT_n          = (1 <<  7), // -n
     79    OPT_s          = (1 <<  8), // -s
     80    OPT_u          = (1 <<  9), // -u
     81    OPT_c          = (1 << 10), // -c
     82    OPT_x          = (1 << 11), // -x
     83    OPT_p          = (1 << 12), // -p
     84    OPT_OKNODO     = (1 << 13) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -o
     85    OPT_VERBOSE    = (1 << 14) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -v
     86    OPT_NICELEVEL  = (1 << 15) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -N
     87};
     88#define QUIET (option_mask32 & OPT_QUIET)
     89#define TEST  (option_mask32 & OPT_TEST)
     90
     91struct globals {
     92    struct pid_list *found_procs;
     93    char *userspec;
     94    char *cmdname;
     95    char *execname;
     96    char *pidfile;
     97    char *execname_cmpbuf;
     98    unsigned execname_sizeof;
     99    int user_id;
     100    smallint signal_nr;
     101} FIX_ALIASING;
     102#define G (*(struct globals*)&bb_common_bufsiz1)
     103#define userspec          (G.userspec            )
     104#define cmdname           (G.cmdname             )
     105#define execname          (G.execname            )
     106#define pidfile           (G.pidfile             )
     107#define user_id           (G.user_id             )
     108#define signal_nr         (G.signal_nr           )
     109#define INIT_G() do { \
     110    user_id = -1; \
     111    signal_nr = 15; \
     112} while (0)
     113
     114#ifdef OLDER_VERSION_OF_X
     115/* -x,--exec EXECUTABLE
     116 * Look for processes with matching /proc/$PID/exe.
     117 * Match is performed using device+inode.
     118 */
     119static int pid_is_exec(pid_t pid)
     120{
     121    struct stat st;
     122    char buf[sizeof("/proc/%u/exe") + sizeof(int)*3];
     123
     124    sprintf(buf, "/proc/%u/exe", (unsigned)pid);
     125    if (stat(buf, &st) < 0)
     126        return 0;
     127    if (st.st_dev == execstat.st_dev
     128     && st.st_ino == execstat.st_ino)
     129        return 1;
     130    return 0;
     131}
     132#endif
     133
     134static int pid_is_exec(pid_t pid)
     135{
     136    ssize_t bytes;
     137    char buf[sizeof("/proc/%u/cmdline") + sizeof(int)*3];
     138
     139    sprintf(buf, "/proc/%u/cmdline", (unsigned)pid);
     140    bytes = open_read_close(buf, G.execname_cmpbuf, G.execname_sizeof);
     141    if (bytes > 0) {
     142        G.execname_cmpbuf[bytes] = '\0';
     143        return strcmp(execname, G.execname_cmpbuf) == 0;
     144    }
     145    return 0;
     146}
     147
     148static int pid_is_name(pid_t pid)
     149{
     150    /* /proc/PID/stat is "PID (comm_15_bytes_max) ..." */
     151    char buf[32]; /* should be enough */
     152    char *p, *pe;
     153
     154    sprintf(buf, "/proc/%u/stat", (unsigned)pid);
     155    if (open_read_close(buf, buf, sizeof(buf) - 1) < 0)
     156        return 0;
     157    buf[sizeof(buf) - 1] = '\0'; /* paranoia */
     158    p = strchr(buf, '(');
     159    if (!p)
     160        return 0;
     161    pe = strrchr(++p, ')');
     162    if (!pe)
     163        return 0;
     164    *pe = '\0';
     165    /* we require comm to match and to not be truncated */
     166    /* in Linux, if comm is 15 chars, it may be a truncated
     167     * name, so we don't allow that to match */
     168    if (strlen(p) >= COMM_LEN - 1) /* COMM_LEN is 16 */
     169        return 0;
     170    return strcmp(p, cmdname) == 0;
     171}
     172
     173static int pid_is_user(int pid)
    55174{
    56175    struct stat sb;
    57176    char buf[sizeof("/proc/") + sizeof(int)*3];
    58177
    59     sprintf(buf, "/proc/%u", pid);
     178    sprintf(buf, "/proc/%u", (unsigned)pid);
    60179    if (stat(buf, &sb) != 0)
    61180        return 0;
    62     return (sb.st_uid == uid);
    63 }
    64 
    65 static int pid_is_cmd(pid_t pid, const char *name)
    66 {
    67     char fname[sizeof("/proc//stat") + sizeof(int)*3];
    68     char *buf;
    69     int r = 0;
    70 
    71     sprintf(fname, "/proc/%u/stat", pid);
    72     buf = xmalloc_open_read_close(fname, NULL);
    73     if (buf) {
    74         char *p = strchr(buf, '(');
    75         if (p) {
    76             char *pe = strrchr(++p, ')');
    77             if (pe) {
    78                 *pe = '\0';
    79                 r = !strcmp(p, name);
    80             }
    81         }
    82         free(buf);
    83     }
    84     return r;
     181    return (sb.st_uid == (uid_t)user_id);
    85182}
    86183
     
    89186    struct pid_list *p;
    90187
    91     if (execname && !pid_is_exec(pid, execname)) {
     188    if (execname && !pid_is_exec(pid)) {
    92189        return;
    93190    }
    94     if (userspec && !pid_is_user(pid, user_id)) {
     191    if (cmdname && !pid_is_name(pid)) {
    95192        return;
    96193    }
    97     if (cmdname && !pid_is_cmd(pid, cmdname)) {
     194    if (userspec && !pid_is_user(pid)) {
    98195        return;
    99196    }
    100197    p = xmalloc(sizeof(*p));
    101     p->next = found;
     198    p->next = G.found_procs;
    102199    p->pid = pid;
    103     found = p;
     200    G.found_procs = p;
    104201}
    105202
     
    109206    unsigned pid;
    110207
    111     f = fopen(pidfile, "r");
     208    f = fopen_for_read(pidfile);
    112209    if (f) {
    113210        if (fscanf(f, "%u", &pid) == 1)
     
    122219    DIR *procdir;
    123220    struct dirent *entry;
    124     int foundany, pid;
     221    int pid;
    125222
    126223    if (pidfile) {
     
    131228    procdir = xopendir("/proc");
    132229
    133     foundany = 0;
    134     while ((entry = readdir(procdir)) != NULL) {
     230    pid = 0;
     231    while (1) {
     232        errno = 0; /* clear any previous error */
     233        entry = readdir(procdir);
     234// TODO: this check is too generic, it's better
     235// to check for exact errno(s) which mean that we got stale entry
     236        if (errno) /* Stale entry, process has died after opendir */
     237            continue;
     238        if (!entry) /* EOF, no more entries */
     239            break;
    135240        pid = bb_strtou(entry->d_name, NULL, 10);
    136         if (errno)
     241        if (errno) /* NaN */
    137242            continue;
    138         foundany++;
    139243        check(pid);
    140244    }
    141245    closedir(procdir);
    142     if (!foundany)
     246    if (!pid)
    143247        bb_error_msg_and_die("nothing in /proc - not mounted?");
    144248}
     
    149253    struct pid_list *p;
    150254    int killed = 0;
    151 
    152     do_procinit();
    153255
    154256    if (cmdname) {
     
    158260        if (ENABLE_FEATURE_CLEAN_UP) what = xstrdup(execname);
    159261        if (!ENABLE_FEATURE_CLEAN_UP) what = execname;
    160     } else if (pidfile)
     262    } else if (pidfile) {
    161263        what = xasprintf("process in pidfile '%s'", pidfile);
    162     else if (userspec)
     264    } else if (userspec) {
    163265        what = xasprintf("process(es) owned by '%s'", userspec);
    164     else
     266    } else {
    165267        bb_error_msg_and_die("internal error, please report");
    166 
    167     if (!found) {
    168         if (!quiet)
     268    }
     269
     270    if (!G.found_procs) {
     271        if (!QUIET)
    169272            printf("no %s found; none killed\n", what);
    170273        killed = -1;
    171274        goto ret;
    172275    }
    173     for (p = found; p; p = p->next) {
    174         if (kill(p->pid, signal_nr) == 0) {
    175             p->pid = - p->pid;
     276    for (p = G.found_procs; p; p = p->next) {
     277        if (TEST || kill(p->pid, signal_nr) == 0) {
    176278            killed++;
    177279        } else {
    178             bb_perror_msg("warning: killing process %u", p->pid);
     280            p->pid = 0;
     281            bb_perror_msg("warning: killing process %u", (unsigned)p->pid);
    179282        }
    180283    }
    181     if (!quiet && killed) {
     284    if (!QUIET && killed) {
    182285        printf("stopped %s (pid", what);
    183         for (p = found; p; p = p->next)
    184             if (p->pid < 0)
    185                 printf(" %u", - p->pid);
     286        for (p = G.found_procs; p; p = p->next)
     287            if (p->pid)
     288                printf(" %u", (unsigned)p->pid);
    186289        puts(")");
    187290    }
     
    198301    "background\0"   No_argument       "b"
    199302    "quiet\0"        No_argument       "q"
     303    "test\0"         No_argument       "t"
    200304    "make-pidfile\0" No_argument       "m"
    201305#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
     
    217321#endif
    218322
    219 enum {
    220     CTX_STOP       = 0x1,
    221     CTX_START      = 0x2,
    222     OPT_BACKGROUND = 0x4, // -b
    223     OPT_QUIET      = 0x8, // -q
    224     OPT_MAKEPID    = 0x10, // -m
    225     OPT_a          = 0x20, // -a
    226     OPT_n          = 0x40, // -n
    227     OPT_s          = 0x80, // -s
    228     OPT_u          = 0x100, // -u
    229     OPT_c          = 0x200, // -c
    230     OPT_x          = 0x400, // -x
    231     OPT_p          = 0x800, // -p
    232     OPT_OKNODO     = 0x1000 * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -o
    233     OPT_VERBOSE    = 0x2000 * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -v
    234     OPT_NICELEVEL  = 0x4000 * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -N
    235 };
    236 
    237 int start_stop_daemon_main(int argc, char **argv);
    238 int start_stop_daemon_main(int argc, char **argv)
     323int start_stop_daemon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     324int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
    239325{
    240326    unsigned opt;
     
    242328    char *startas;
    243329    char *chuid;
     330#ifdef OLDER_VERSION_OF_X
     331    struct stat execstat;
     332#endif
    244333#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
    245334//  char *retry_arg = NULL;
     
    247336    char *opt_N;
    248337#endif
     338
     339    INIT_G();
     340
    249341#if ENABLE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS
    250342    applet_long_options = start_stop_daemon_longopts;
    251343#endif
    252344
    253     /* Check required one context option was given */
    254     opt_complementary = "K:S:K--S:S--K:m?p:K?xpun:S?xa";
    255     opt = getopt32(argv, "KSbqma:n:s:u:c:x:p:"
    256         USE_FEATURE_START_STOP_DAEMON_FANCY("ovN:"),
    257 //      USE_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:"),
     345    /* -K or -S is required; they are mutually exclusive */
     346    /* -p is required if -m is given */
     347    /* -xpun (at least one) is required if -K is given */
     348    /* -xa (at least one) is required if -S is given */
     349    /* -q turns off -v */
     350    opt_complementary = "K:S:K--S:S--K:m?p:K?xpun:S?xa"
     351        IF_FEATURE_START_STOP_DAEMON_FANCY("q-v");
     352    opt = getopt32(argv, "KSbqtma:n:s:u:c:x:p:"
     353        IF_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:"),
    258354        &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile
    259         USE_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N)
    260 //      USE_FEATURE_START_STOP_DAEMON_FANCY(,&retry_arg)
     355        IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N)
     356        /* We accept and ignore -R <param> / --retry <param> */
     357        IF_FEATURE_START_STOP_DAEMON_FANCY(,NULL)
    261358    );
    262 
    263     quiet = (opt & OPT_QUIET) && !(opt & OPT_VERBOSE);
    264359
    265360    if (opt & OPT_s) {
     
    270365    if (!(opt & OPT_a))
    271366        startas = execname;
    272 
    273 //  USE_FEATURE_START_STOP_DAEMON_FANCY(
     367    if (!execname) /* in case -a is given and -x is not */
     368        execname = startas;
     369    if (execname) {
     370        G.execname_sizeof = strlen(execname) + 1;
     371        G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1);
     372    }
     373
     374//  IF_FEATURE_START_STOP_DAEMON_FANCY(
    274375//      if (retry_arg)
    275 //          retries = xatoi_u(retry_arg);
     376//          retries = xatoi_positive(retry_arg);
    276377//  )
    277     argc -= optind;
     378    //argc -= optind;
    278379    argv += optind;
    279380
     
    283384            user_id = xuname2uid(userspec);
    284385    }
     386    /* Both start and stop need to know current processes */
     387    do_procinit();
    285388
    286389    if (opt & CTX_STOP) {
     
    289392    }
    290393
    291     do_procinit();
    292 
    293     if (found) {
    294         if (!quiet)
    295             printf("%s already running\n%d\n", execname, found->pid);
     394    if (G.found_procs) {
     395        if (!QUIET)
     396            printf("%s is already running\n%u\n", execname, (unsigned)G.found_procs->pid);
    296397        return !(opt & OPT_OKNODO);
    297398    }
     399
     400#ifdef OLDER_VERSION_OF_X
     401    if (execname)
     402        xstat(execname, &execstat);
     403#endif
     404
    298405    *--argv = startas;
    299406    if (opt & OPT_BACKGROUND) {
    300407#if BB_MMU
    301         bb_daemonize(0);
     408        bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS);
     409        /* DAEMON_DEVNULL_STDIO is superfluous -
     410         * it's always done by bb_daemonize() */
    302411#else
    303         pid_t pid = vfork();
    304         if (pid < 0) /* error */
    305             bb_perror_msg_and_die("vfork");
     412        pid_t pid = xvfork();
    306413        if (pid != 0) {
    307414            /* parent */
    308415            /* why _exit? the child may have changed the stack,
    309416             * so "return 0" may do bad things */
    310             _exit(0);
     417            _exit(EXIT_SUCCESS);
    311418        }
    312         /* child */
     419        /* Child */
    313420        setsid(); /* detach from controlling tty */
    314421        /* Redirect stdio to /dev/null, close extra FDs.
    315422         * We do not actually daemonize because of DAEMON_ONLY_SANITIZE */
    316         bb_daemonize_or_rexec(
    317             DAEMON_DEVNULL_STDIO
     423        bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO
    318424            + DAEMON_CLOSE_EXTRA_FDS
    319425            + DAEMON_ONLY_SANITIZE,
     
    322428    }
    323429    if (opt & OPT_MAKEPID) {
    324         /* user wants _us_ to make the pidfile */
     430        /* User wants _us_ to make the pidfile */
    325431        write_pidfile(pidfile);
    326432    }
    327433    if (opt & OPT_c) {
    328         struct bb_uidgid_t ugid;
     434        struct bb_uidgid_t ugid = { -1, -1 };
    329435        parse_chown_usergroup_or_die(&ugid, chuid);
    330436        if (ugid.gid != (gid_t) -1) xsetgid(ugid.gid);
     
    340446    }
    341447#endif
    342     execv(startas, argv);
    343     bb_perror_msg_and_die("cannot start %s", startas);
    344 }
     448    execvp(startas, argv);
     449    bb_perror_msg_and_die("can't execute '%s'", startas);
     450}
Note: See TracChangeset for help on using the changeset viewer.