Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (17 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/debianutils/start_stop_daemon.c

    r821 r1765  
    44 *
    55 * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
    6  * public domain.
    76 * Adapted for busybox David Kimdon <dwhedon@gordian.com>
     7 *
     8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    89 */
    910
    10 #include "busybox.h"
    11 #include <stdio.h>
    12 #include <stdlib.h>
    13 #include <string.h>
    14 #include <stdarg.h>
    15 #include <signal.h>
    16 #include <errno.h>
    17 #include <sys/stat.h>
    18 #include <dirent.h>
    19 #include <unistd.h>
    20 #include <getopt.h> /* struct option */
    21 #include "pwd_.h"
     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>
     15#include <sys/resource.h>
     16
     17/* Override ENABLE_FEATURE_PIDFILE */
     18#define WANT_PIDFILE 1
     19#include "libbb.h"
    2220
    2321static int signal_nr = 15;
    2422static int user_id = -1;
    25 static int quiet;
    26 static char *userspec = NULL;
    27 static char *cmdname = NULL;
    28 static char *execname = NULL;
    29 static char *pidfile = NULL;
     23static char *userspec;
     24static char *cmdname;
     25static char *execname;
     26static char *pidfile;
     27static smallint quiet;
    3028
    3129struct pid_list {
     
    3432};
    3533
    36 static struct pid_list *found = NULL;
    37 
    38 static inline void push(pid_t pid)
     34static struct pid_list *found;
     35
     36static 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
     54static int pid_is_user(int pid, int uid)
     55{
     56    struct stat sb;
     57    char buf[sizeof("/proc/") + sizeof(int)*3];
     58
     59    sprintf(buf, "/proc/%u", pid);
     60    if (stat(buf, &sb) != 0)
     61        return 0;
     62    return (sb.st_uid == uid);
     63}
     64
     65static 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;
     85}
     86
     87static void check(int pid)
    3988{
    4089    struct pid_list *p;
    4190
     91    if (execname && !pid_is_exec(pid, execname)) {
     92        return;
     93    }
     94    if (userspec && !pid_is_user(pid, user_id)) {
     95        return;
     96    }
     97    if (cmdname && !pid_is_cmd(pid, cmdname)) {
     98        return;
     99    }
    42100    p = xmalloc(sizeof(*p));
    43101    p->next = found;
     
    46104}
    47105
    48 static int pid_is_exec(pid_t pid, const char *name)
    49 {
    50     char buf[32];
    51     struct stat sb, exec_stat;
    52 
    53     if (name)
    54         xstat(name, &exec_stat);
    55 
    56     sprintf(buf, "/proc/%d/exe", pid);
    57     if (stat(buf, &sb) != 0)
    58         return 0;
    59     return (sb.st_dev == exec_stat.st_dev && sb.st_ino == exec_stat.st_ino);
    60 }
    61 
    62 static int pid_is_user(int pid, int uid)
    63 {
    64     struct stat sb;
    65     char buf[32];
    66 
    67     sprintf(buf, "/proc/%d", pid);
    68     if (stat(buf, &sb) != 0)
    69         return 0;
    70     return (sb.st_uid == uid);
    71 }
    72 
    73 static int pid_is_cmd(pid_t pid, const char *name)
    74 {
    75     char buf[32];
     106static void do_pidfile(void)
     107{
    76108    FILE *f;
    77     int c;
    78 
    79     sprintf(buf, "/proc/%d/stat", pid);
    80     f = fopen(buf, "r");
    81     if (!f)
    82         return 0;
    83     while ((c = getc(f)) != EOF && c != '(')
    84         ;
    85     if (c != '(') {
    86         fclose(f);
    87         return 0;
    88     }
    89     /* this hopefully handles command names containing ')' */
    90     while ((c = getc(f)) != EOF && c == *name)
    91         name++;
    92     fclose(f);
    93     return (c == ')' && *name == '\0');
    94 }
    95 
    96 
    97 static void check(int pid)
    98 {
    99     if (execname && !pid_is_exec(pid, execname)) {
    100         return;
    101     }
    102     if (userspec && !pid_is_user(pid, user_id)) {
    103         return;
    104     }
    105     if (cmdname && !pid_is_cmd(pid, cmdname)) {
    106         return;
    107     }
    108     push(pid);
    109 }
    110 
    111 
    112 static void do_pidfile(void)
    113 {
    114     FILE *f;
    115     pid_t pid;
     109    unsigned pid;
    116110
    117111    f = fopen(pidfile, "r");
    118112    if (f) {
    119         if (fscanf(f, "%d", &pid) == 1)
     113        if (fscanf(f, "%u", &pid) == 1)
    120114            check(pid);
    121115        fclose(f);
    122116    } else if (errno != ENOENT)
    123117        bb_perror_msg_and_die("open pidfile %s", pidfile);
    124 
    125118}
    126119
     
    136129    }
    137130
    138     procdir = bb_xopendir("/proc");
     131    procdir = xopendir("/proc");
    139132
    140133    foundany = 0;
    141134    while ((entry = readdir(procdir)) != NULL) {
    142         if (sscanf(entry->d_name, "%d", &pid) != 1)
     135        pid = bb_strtou(entry->d_name, NULL, 10);
     136        if (errno)
    143137            continue;
    144138        foundany++;
     
    147141    closedir(procdir);
    148142    if (!foundany)
    149         bb_error_msg_and_die ("nothing in /proc - not mounted?");
    150 }
    151 
     143        bb_error_msg_and_die("nothing in /proc - not mounted?");
     144}
    152145
    153146static int do_stop(void)
    154147{
    155     RESERVE_CONFIG_BUFFER(what, 1024);
     148    char *what;
    156149    struct pid_list *p;
    157150    int killed = 0;
     
    159152    do_procinit();
    160153
    161     if (cmdname)
    162         strcpy(what, cmdname);
    163     else if (execname)
    164         strcpy(what, execname);
    165     else if (pidfile)
    166         sprintf(what, "process in pidfile `%.200s'", pidfile);
     154    if (cmdname) {
     155        if (ENABLE_FEATURE_CLEAN_UP) what = xstrdup(cmdname);
     156        if (!ENABLE_FEATURE_CLEAN_UP) what = cmdname;
     157    } else if (execname) {
     158        if (ENABLE_FEATURE_CLEAN_UP) what = xstrdup(execname);
     159        if (!ENABLE_FEATURE_CLEAN_UP) what = execname;
     160    } else if (pidfile)
     161        what = xasprintf("process in pidfile '%s'", pidfile);
    167162    else if (userspec)
    168         sprintf(what, "process(es) owned by `%s'", userspec);
     163        what = xasprintf("process(es) owned by '%s'", userspec);
    169164    else
    170         bb_error_msg_and_die ("internal error, please report");
     165        bb_error_msg_and_die("internal error, please report");
    171166
    172167    if (!found) {
    173168        if (!quiet)
    174             printf("no %s found; none killed.\n", what);
    175         if (ENABLE_FEATURE_CLEAN_UP)
    176             RELEASE_CONFIG_BUFFER(what);
    177         return -1;
     169            printf("no %s found; none killed\n", what);
     170        killed = -1;
     171        goto ret;
    178172    }
    179173    for (p = found; p; p = p->next) {
    180174        if (kill(p->pid, signal_nr) == 0) {
    181             p->pid = -p->pid;
     175            p->pid = - p->pid;
    182176            killed++;
    183177        } else {
    184             bb_perror_msg("warning: failed to kill %d", p->pid);
     178            bb_perror_msg("warning: killing process %u", p->pid);
    185179        }
    186180    }
     
    188182        printf("stopped %s (pid", what);
    189183        for (p = found; p; p = p->next)
    190             if(p->pid < 0)
    191                 printf(" %d", -p->pid);
    192         printf(").\n");
    193     }
     184            if (p->pid < 0)
     185                printf(" %u", - p->pid);
     186        puts(")");
     187    }
     188 ret:
    194189    if (ENABLE_FEATURE_CLEAN_UP)
    195         RELEASE_CONFIG_BUFFER(what);
     190        free(what);
    196191    return killed;
    197192}
    198193
    199194#if ENABLE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS
    200 static const struct option ssd_long_options[] = {
    201     { "stop",           0,      NULL,       'K' },
    202     { "start",          0,      NULL,       'S' },
    203     { "background",     0,      NULL,       'b' },
    204     { "quiet",          0,      NULL,       'q' },
    205     { "make-pidfile",   0,      NULL,       'm' },
     195static const char start_stop_daemon_longopts[] ALIGN1 =
     196    "stop\0"         No_argument       "K"
     197    "start\0"        No_argument       "S"
     198    "background\0"   No_argument       "b"
     199    "quiet\0"        No_argument       "q"
     200    "make-pidfile\0" No_argument       "m"
    206201#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
    207     { "oknodo",         0,      NULL,       'o' },
    208     { "verbose",        0,      NULL,       'v' },
    209 #endif
    210     { "startas",        1,      NULL,       'a' },
    211     { "name",           1,      NULL,       'n' },
    212     { "signal",         1,      NULL,       's' },
    213     { "user",           1,      NULL,       'u' },
    214     { "exec",           1,      NULL,       'x' },
    215     { "pidfile",        1,      NULL,       'p' },
     202    "oknodo\0"       No_argument       "o"
     203    "verbose\0"      No_argument       "v"
     204    "nicelevel\0"    Required_argument "N"
     205#endif
     206    "startas\0"      Required_argument "a"
     207    "name\0"         Required_argument "n"
     208    "signal\0"       Required_argument "s"
     209    "user\0"         Required_argument "u"
     210    "chuid\0"        Required_argument "c"
     211    "exec\0"         Required_argument "x"
     212    "pidfile\0"      Required_argument "p"
    216213#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
    217     { "retry",          1,      NULL,       'R' },
    218 #endif
    219     { 0,                0,      0,      0 }
     214    "retry\0"        Required_argument "R"
     215#endif
     216    ;
     217#endif
     218
     219enum {
     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
    220235};
    221 #endif
    222 
    223 #define SSD_CTX_STOP        1
    224 #define SSD_CTX_START       2
    225 #define SSD_OPT_BACKGROUND  4
    226 #define SSD_OPT_QUIET       8
    227 #define SSD_OPT_MAKEPID     16
    228 #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
    229 #define SSD_OPT_OKNODO      32
    230 #define SSD_OPT_VERBOSE     64
    231 
    232 #endif
    233 
     236
     237int start_stop_daemon_main(int argc, char **argv);
    234238int start_stop_daemon_main(int argc, char **argv)
    235239{
    236     unsigned long opt;
    237     char *signame = NULL;
    238     char *startas = NULL;
     240    unsigned opt;
     241    char *signame;
     242    char *startas;
     243    char *chuid;
    239244#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
    240245//  char *retry_arg = NULL;
    241246//  int retries = -1;
     247    char *opt_N;
    242248#endif
    243249#if ENABLE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS
    244     bb_applet_long_options = ssd_long_options;
     250    applet_long_options = start_stop_daemon_longopts;
    245251#endif
    246252
    247253    /* Check required one context option was given */
    248     bb_opt_complementally = "K:S:?:K--S:S--K:m?p:K?xpun:S?xa";
    249     opt = bb_getopt_ulflags(argc, argv, "KSbqm"
    250 //      USE_FEATURE_START_STOP_DAEMON_FANCY("ovR:")
    251         USE_FEATURE_START_STOP_DAEMON_FANCY("ov")
    252         "a:n:s:u:x:p:"
     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:"),
     258        &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile
     259        USE_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N)
    253260//      USE_FEATURE_START_STOP_DAEMON_FANCY(,&retry_arg)
    254         ,&startas, &cmdname, &signame, &userspec, &execname, &pidfile);
    255 
    256     quiet = (opt & SSD_OPT_QUIET)
    257             USE_FEATURE_START_STOP_DAEMON_FANCY(&& !(opt & SSD_OPT_VERBOSE));
    258 
    259     if (signame) {
    260         signal_nr = bb_xgetlarg(signame, 10, 0, NSIG);
    261     }
    262 
    263     if (!startas)
     261    );
     262
     263    quiet = (opt & OPT_QUIET) && !(opt & OPT_VERBOSE);
     264
     265    if (opt & OPT_s) {
     266        signal_nr = get_signum(signame);
     267        if (signal_nr < 0) bb_show_usage();
     268    }
     269
     270    if (!(opt & OPT_a))
    264271        startas = execname;
    265272
    266273//  USE_FEATURE_START_STOP_DAEMON_FANCY(
    267274//      if (retry_arg)
    268 //          retries = bb_xgetlarg(retry_arg, 10, 0, INT_MAX);
     275//          retries = xatoi_u(retry_arg);
    269276//  )
    270277    argc -= optind;
    271278    argv += optind;
    272279
    273     if (userspec && sscanf(userspec, "%d", &user_id) != 1)
    274         user_id = bb_xgetpwnam(userspec);
    275 
    276     if (opt & SSD_CTX_STOP) {
     280    if (userspec) {
     281        user_id = bb_strtou(userspec, NULL, 10);
     282        if (errno)
     283            user_id = xuname2uid(userspec);
     284    }
     285
     286    if (opt & CTX_STOP) {
    277287        int i = do_stop();
    278         return
    279             USE_FEATURE_START_STOP_DAEMON_FANCY((opt & SSD_OPT_OKNODO)
    280                 ? 0 :) !!(i<=0);
     288        return (opt & OPT_OKNODO) ? 0 : (i <= 0);
    281289    }
    282290
     
    285293    if (found) {
    286294        if (!quiet)
    287             printf("%s already running.\n%d\n", execname ,found->pid);
    288         USE_FEATURE_START_STOP_DAEMON_FANCY(return !(opt & SSD_OPT_OKNODO);)
    289         SKIP_FEATURE_START_STOP_DAEMON_FANCY(return EXIT_FAILURE;)
     295            printf("%s already running\n%d\n", execname, found->pid);
     296        return !(opt & OPT_OKNODO);
    290297    }
    291298    *--argv = startas;
    292     if (opt & SSD_OPT_BACKGROUND) {
    293         bb_xdaemon(0, 0);
    294         setsid();
    295     }
    296     if (opt & SSD_OPT_MAKEPID) {
     299    if (opt & OPT_BACKGROUND) {
     300#if BB_MMU
     301        bb_daemonize(0);
     302#else
     303        pid_t pid = vfork();
     304        if (pid < 0) /* error */
     305            bb_perror_msg_and_die("vfork");
     306        if (pid != 0) {
     307            /* parent */
     308            /* why _exit? the child may have changed the stack,
     309             * so "return 0" may do bad things */
     310            _exit(0);
     311        }
     312        /* child */
     313        setsid(); /* detach from controlling tty */
     314        /* Redirect stdio to /dev/null, close extra FDs.
     315         * We do not actually daemonize because of DAEMON_ONLY_SANITIZE */
     316        bb_daemonize_or_rexec(
     317            DAEMON_DEVNULL_STDIO
     318            + DAEMON_CLOSE_EXTRA_FDS
     319            + DAEMON_ONLY_SANITIZE,
     320            NULL /* argv, unused */ );
     321#endif
     322    }
     323    if (opt & OPT_MAKEPID) {
    297324        /* user wants _us_ to make the pidfile */
    298         FILE *pidf = bb_xfopen(pidfile, "w");
    299 
    300         pid_t pidt = getpid();
    301         fprintf(pidf, "%d\n", pidt);
    302         fclose(pidf);
    303     }
     325        write_pidfile(pidfile);
     326    }
     327    if (opt & OPT_c) {
     328        struct bb_uidgid_t ugid;
     329        parse_chown_usergroup_or_die(&ugid, chuid);
     330        if (ugid.gid != (gid_t) -1) xsetgid(ugid.gid);
     331        if (ugid.uid != (uid_t) -1) xsetuid(ugid.uid);
     332    }
     333#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
     334    if (opt & OPT_NICELEVEL) {
     335        /* Set process priority */
     336        int prio = getpriority(PRIO_PROCESS, 0) + xatoi_range(opt_N, INT_MIN/2, INT_MAX/2);
     337        if (setpriority(PRIO_PROCESS, 0, prio) < 0) {
     338            bb_perror_msg_and_die("setpriority(%d)", prio);
     339        }
     340    }
     341#endif
    304342    execv(startas, argv);
    305     bb_perror_msg_and_die ("unable to start %s", startas);
    306 }
     343    bb_perror_msg_and_die("cannot start %s", startas);
     344}
Note: See TracChangeset for help on using the changeset viewer.