source: tools/start-stop-daemon/start-stop-daemon.c @ 33

Last change on this file since 33 was 33, checked in by alloc, 10 years ago

SSD with more defines

File size: 33.9 KB
Line 
1/*
2 * A rewrite of the original Debian's start-stop-daemon Perl script
3 * in C (faster - it is executed many times during system startup).
4 *
5 * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
6 * public domain.  Based conceptually on start-stop-daemon.pl, by Ian
7 * Jackson <ijackson@gnu.ai.mit.edu>.  May be used and distributed
8 * freely for any purpose.  Changes by Christian Schwarz
9 * <schwarz@monet.m.isar.de>, to make output conform to the Debian
10 * Console Message Standard, also placed in public domain.  Minor
11 * changes by Klee Dienes <klee@debian.org>, also placed in the Public
12 * Domain.
13 *
14 * Changes by Ben Collins <bcollins@debian.org>, added --chuid, --background
15 * and --make-pidfile options, placed in public domain as well.
16 *
17 * Port to OpenBSD by Sontri Tomo Huynh <huynh.29@osu.edu>
18 *                 and Andreas Schuldei <andreas@schuldei.org>
19 *
20 * Changes by Ian Jackson: added --retry (and associated rearrangements).
21 */
22
23/*
24 * MODIFIED TO NOT DEPEND ON EXTERNAL HEADERS!
25 * By Christian Illy <christian@illy.bz>
26 * Used dpkg source package from https://packages.debian.org/stable/dpkg
27 * Version 1.16.14
28 */
29
30// from config.h, generated by configure:
31#define VERSION "1.16.14_01"
32
33//*****************************************
34// Stuff from dpkg/macros.h
35#define DPKG_ATTR_NORET
36#define DPKG_ATTR_PRINTF(n)
37/**
38 * @def array_count
39 *
40 * Returns the amount of items in an array.
41 */
42#ifndef array_count
43#define array_count(a) (sizeof(a) / sizeof((a)[0]))
44#endif
45// End of stuff from dpkg/macros.h
46//*****************************************
47
48//*****************************************
49// Required on some systems to get O_NOFOLLOW:
50#define _POSIX_C_SOURCE 200809L
51#define _GNU_SOURCE
52//*****************************************
53
54
55#define OSLinux
56
57#define MIN_POLL_INTERVAL 20000 /* µs */
58
59#include <sys/syscall.h>
60
61#include <sys/types.h>
62#include <sys/time.h>
63#include <sys/stat.h>
64#include <sys/ioctl.h>
65#include <sys/termios.h>
66
67#include <assert.h>
68#include <errno.h>
69#include <limits.h>
70#include <fcntl.h>
71#include <dirent.h>
72#include <ctype.h>
73#include <string.h>
74#include <pwd.h>
75#include <grp.h>
76#include <signal.h>
77#include <unistd.h>
78#include <stddef.h>
79#include <stdbool.h>
80#include <stdarg.h>
81#include <stdlib.h>
82#include <stdio.h>
83#include <getopt.h>
84
85#include <error.h>
86
87#ifdef _POSIX_PRIORITY_SCHEDULING
88#include <sched.h>
89#else
90#define SCHED_OTHER -1
91#define SCHED_FIFO -1
92#define SCHED_RR -1
93#endif
94
95/* This comes from TASK_COMM_LEN defined in Linux' include/linux/sched.h. */
96#define PROCESS_NAME_SIZE 15
97
98#if defined(SYS_ioprio_set)
99#define HAVE_IOPRIO_SET
100#endif
101
102enum {
103        IOPRIO_WHO_PROCESS = 1,
104        IOPRIO_WHO_PGRP,
105        IOPRIO_WHO_USER,
106};
107
108enum {
109        IOPRIO_CLASS_NONE,
110        IOPRIO_CLASS_RT,
111        IOPRIO_CLASS_BE,
112        IOPRIO_CLASS_IDLE,
113};
114
115enum action_code {
116        action_none,
117        action_start,
118        action_stop,
119        action_status,
120};
121
122static enum action_code action;
123static int testmode = 0;
124static int quietmode = 0;
125static int exitnodo = 1;
126static int background = 0;
127static int close_io = 1;
128static int mpidfile = 0;
129static int signal_nr = SIGTERM;
130static int user_id = -1;
131static int runas_uid = -1;
132static int runas_gid = -1;
133static const char *userspec = NULL;
134static char *changeuser = NULL;
135static const char *changegroup = NULL;
136static char *changeroot = NULL;
137static const char *changedir = "/";
138static const char *cmdname = NULL;
139static char *execname = NULL;
140static char *startas = NULL;
141static const char *pidfile = NULL;
142static char what_stop[1024];
143static const char *progname = "";
144static int nicelevel = 0;
145static int umask_value = -1;
146
147#define IOPRIO_CLASS_SHIFT 13
148#define IOPRIO_PRIO_VALUE(class, prio) (((class) << IOPRIO_CLASS_SHIFT) | (prio))
149#define IO_SCHED_PRIO_MIN 0
150#define IO_SCHED_PRIO_MAX 7
151
152static struct stat exec_stat;
153
154/* LSB Init Script process status exit codes. */
155enum status_code {
156        status_ok = 0,
157        status_dead_pidfile = 1,
158        status_dead_lockfile = 2,
159        status_dead = 3,
160        status_unknown = 4,
161};
162
163struct pid_list {
164        struct pid_list *next;
165        pid_t pid;
166};
167
168static struct pid_list *found = NULL;
169static struct pid_list *killed = NULL;
170
171/* Resource scheduling policy. */
172struct res_schedule {
173        const char *policy_name;
174        int policy;
175        int priority;
176};
177
178struct schedule_item {
179        enum {
180                sched_timeout,
181                sched_signal,
182                sched_goto,
183                /* Only seen within parse_schedule and callees. */
184                sched_forever,
185        } type;
186        /* Seconds, signal no., or index into array. */
187        int value;
188};
189
190static struct res_schedule *proc_sched = NULL;
191static struct res_schedule *io_sched = NULL;
192
193static int schedule_length;
194static struct schedule_item *schedule = NULL;
195
196
197static void DPKG_ATTR_PRINTF(1)
198warning(const char *format, ...)
199{
200        va_list arglist;
201
202        fprintf(stderr, "%s: warning: ", progname);
203        va_start(arglist, format);
204        vfprintf(stderr, format, arglist);
205        va_end(arglist);
206}
207
208static void DPKG_ATTR_NORET DPKG_ATTR_PRINTF(1)
209fatal(const char *format, ...)
210{
211        va_list arglist;
212        int errno_fatal = errno;
213
214        fprintf(stderr, "%s: ", progname);
215        va_start(arglist, format);
216        vfprintf(stderr, format, arglist);
217        va_end(arglist);
218        if (errno_fatal)
219                fprintf(stderr, " (%s)\n", strerror(errno_fatal));
220        else
221                fprintf(stderr, "\n");
222
223        if (action == action_status)
224                exit(status_unknown);
225        else
226                exit(2);
227}
228
229static void *
230xmalloc(int size)
231{
232        void *ptr;
233
234        ptr = malloc(size);
235        if (ptr)
236                return ptr;
237        fatal("malloc(%d) failed", size);
238}
239
240static char *
241xstrdup(const char *str)
242{
243        char *new_str;
244
245        new_str = strdup(str);
246        if (new_str)
247                return new_str;
248        fatal("strdup(%s) failed", str);
249}
250
251static void
252xgettimeofday(struct timeval *tv)
253{
254        if (gettimeofday(tv, NULL) != 0)
255                fatal("gettimeofday failed");
256}
257
258static void
259tmul(struct timeval *a, int b)
260{
261        a->tv_sec *= b;
262        a->tv_usec *= b;
263        a->tv_sec = a->tv_sec + a->tv_usec / 1000000;
264        a->tv_usec %= 1000000;
265}
266
267static char *
268newpath(const char *dirname, const char *filename)
269{
270        char *path;
271        size_t path_len;
272
273        path_len = strlen(dirname) + 1 + strlen(filename) + 1;
274        path = xmalloc(path_len);
275        snprintf(path, path_len, "%s/%s", dirname, filename);
276
277        return path;
278}
279
280static long
281get_open_fd_max(void)
282{
283        return getdtablesize();
284}
285
286static void
287daemonize(void)
288{
289        pid_t pid;
290
291        if (quietmode < 0)
292                printf("Detaching to start %s...", startas);
293
294        pid = fork();
295        if (pid < 0)
296                fatal("unable to do first fork");
297        else if (pid) /* Parent. */
298                _exit(0);
299
300        /* Create a new session. */
301        setsid();
302
303        pid = fork();
304        if (pid < 0)
305                fatal("unable to do second fork");
306        else if (pid) /* Parent. */
307                _exit(0);
308
309        if (quietmode < 0)
310                printf("done.\n");
311}
312
313static void
314write_pidfile(const char *filename, pid_t pid)
315{
316        FILE *fp;
317        int fd;
318
319        fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, 0666);
320        if (fd < 0)
321                fp = NULL;
322        else
323                fp = fdopen(fd, "w");
324
325        if (fp == NULL)
326                fatal("unable to open pidfile '%s' for writing", filename);
327
328        fprintf(fp, "%d\n", pid);
329
330        if (fclose(fp))
331                fatal("unable to close pidfile '%s'", filename);
332}
333
334static void
335pid_list_push(struct pid_list **list, pid_t pid)
336{
337        struct pid_list *p;
338
339        p = xmalloc(sizeof(*p));
340        p->next = *list;
341        p->pid = pid;
342        *list = p;
343}
344
345static void
346pid_list_free(struct pid_list **list)
347{
348        struct pid_list *here, *next;
349
350        for (here = *list; here != NULL; here = next) {
351                next = here->next;
352                free(here);
353        }
354
355        *list = NULL;
356}
357
358static void
359usage(void)
360{
361        printf(
362"Usage: start-stop-daemon [<option> ...] <command>\n"
363"\n"
364"Commands:\n"
365"  -S|--start -- <argument> ...  start a program and pass <arguments> to it\n"
366"  -K|--stop                     stop a program\n"
367"  -T|--status                   get the program status\n"
368"  -H|--help                     print help information\n"
369"  -V|--version                  print version\n"
370"\n"
371"Matching options (at least one is required):\n"
372"  -p|--pidfile <pid-file>       pid file to check\n"
373"  -x|--exec <executable>        program to start/check if it is running\n"
374"  -n|--name <process-name>      process name to check\n"
375"  -u|--user <username|uid>      process owner to check\n"
376"\n"
377"Options:\n"
378"  -g|--group <group|gid>        run process as this group\n"
379"  -c|--chuid <name|uid[:group|gid]>\n"
380"                                change to this user/group before starting\n"
381"                                  process\n"
382"  -s|--signal <signal>          signal to send (default TERM)\n"
383"  -a|--startas <pathname>       program to start (default is <executable>)\n"
384"  -r|--chroot <directory>       chroot to <directory> before starting\n"
385"  -d|--chdir <directory>        change to <directory> (default is /)\n"
386"  -N|--nicelevel <incr>         add incr to the process' nice level\n"
387"  -P|--procsched <policy[:prio]>\n"
388"                                use <policy> with <prio> for the kernel\n"
389"                                  process scheduler (default prio is 0)\n"
390"  -I|--iosched <class[:prio]>   use <class> with <prio> to set the IO\n"
391"                                  scheduler (default prio is 4)\n"
392"  -k|--umask <mask>             change the umask to <mask> before starting\n"
393"  -b|--background               force the process to detach\n"
394"  -C|--no-close                 do not close any file descriptor\n"
395"  -m|--make-pidfile             create the pidfile before starting\n"
396"  -R|--retry <schedule>         check whether processes die, and retry\n"
397"  -t|--test                     test mode, don't do anything\n"
398"  -o|--oknodo                   exit status 0 (not 1) if nothing done\n"
399"  -q|--quiet                    be more quiet\n"
400"  -v|--verbose                  be more verbose\n"
401"\n"
402"Retry <schedule> is <item>|/<item>/... where <item> is one of\n"
403" -<signal-num>|[-]<signal-name>  send that signal\n"
404" <timeout>                       wait that many seconds\n"
405" forever                         repeat remainder forever\n"
406"or <schedule> may be just <timeout>, meaning <signal>/<timeout>/KILL/<timeout>\n"
407"\n"
408"The process scheduler <policy> can be one of:\n"
409"  other, fifo or rr\n"
410"\n"
411"The IO scheduler <class> can be one of:\n"
412"  real-time, best-effort or idle\n"
413"\n"
414"Exit status:\n"
415"  0 = done\n"
416"  1 = nothing done (=> 0 if --oknodo)\n"
417"  2 = with --retry, processes would not die\n"
418"  3 = trouble\n"
419"Exit status with --status:\n"
420"  0 = program is running\n"
421"  1 = program is not running and the pid file exists\n"
422"  3 = program is not running\n"
423"  4 = unable to determine status\n");
424}
425
426static void
427do_version(void)
428{
429        printf("start-stop-daemon %s for non-Debian\n\n", VERSION);
430
431        printf("Written by Marek Michalkiewicz, public domain.\n");
432}
433
434static void DPKG_ATTR_NORET
435badusage(const char *msg)
436{
437        if (msg)
438                fprintf(stderr, "%s: %s\n", progname, msg);
439        fprintf(stderr, "Try '%s --help' for more information.\n", progname);
440
441        if (action == action_status)
442                exit(status_unknown);
443        else
444                exit(3);
445}
446
447struct sigpair {
448        const char *name;
449        int signal;
450};
451
452static const struct sigpair siglist[] = {
453        { "ABRT",       SIGABRT },
454        { "ALRM",       SIGALRM },
455        { "FPE",        SIGFPE  },
456        { "HUP",        SIGHUP  },
457        { "ILL",        SIGILL  },
458        { "INT",        SIGINT  },
459        { "KILL",       SIGKILL },
460        { "PIPE",       SIGPIPE },
461        { "QUIT",       SIGQUIT },
462        { "SEGV",       SIGSEGV },
463        { "TERM",       SIGTERM },
464        { "USR1",       SIGUSR1 },
465        { "USR2",       SIGUSR2 },
466        { "CHLD",       SIGCHLD },
467        { "CONT",       SIGCONT },
468        { "STOP",       SIGSTOP },
469        { "TSTP",       SIGTSTP },
470        { "TTIN",       SIGTTIN },
471        { "TTOU",       SIGTTOU }
472};
473
474static int
475parse_unsigned(const char *string, int base, int *value_r)
476{
477        long value;
478        char *endptr;
479
480        if (!string[0])
481                return -1;
482
483        errno = 0;
484        value = strtol(string, &endptr, base);
485        if (string == endptr || *endptr != '\0' || errno != 0)
486                return -1;
487        if (value < 0 || value > INT_MAX)
488                return -1;
489
490        *value_r = value;
491        return 0;
492}
493
494static int
495parse_signal(const char *sig_str, int *sig_num)
496{
497        unsigned int i;
498
499        if (parse_unsigned(sig_str, 10, sig_num) == 0)
500                return 0;
501
502        for (i = 0; i < array_count(siglist); i++) {
503                if (strcmp(sig_str, siglist[i].name) == 0) {
504                        *sig_num = siglist[i].signal;
505                        return 0;
506                }
507        }
508        return -1;
509}
510
511static int
512parse_umask(const char *string, int *value_r)
513{
514        return parse_unsigned(string, 0, value_r);
515}
516
517static void
518validate_proc_schedule(void)
519{
520#ifdef _POSIX_PRIORITY_SCHEDULING
521        int prio_min, prio_max;
522
523        prio_min = sched_get_priority_min(proc_sched->policy);
524        prio_max = sched_get_priority_max(proc_sched->policy);
525
526        if (proc_sched->priority < prio_min)
527                badusage("process scheduler priority less than min");
528        if (proc_sched->priority > prio_max)
529                badusage("process scheduler priority greater than max");
530#endif
531}
532
533static void
534parse_proc_schedule(const char *string)
535{
536        char *policy_str, *prio_str;
537        int prio = 0;
538
539        policy_str = xstrdup(string);
540        policy_str = strtok(policy_str, ":");
541        prio_str = strtok(NULL, ":");
542
543        if (prio_str && parse_unsigned(prio_str, 10, &prio) != 0)
544                fatal("invalid process scheduler priority");
545
546        proc_sched = xmalloc(sizeof(*proc_sched));
547        proc_sched->policy_name = policy_str;
548
549        if (strcmp(policy_str, "other") == 0) {
550                proc_sched->policy = SCHED_OTHER;
551                proc_sched->priority = 0;
552        } else if (strcmp(policy_str, "fifo") == 0) {
553                proc_sched->policy = SCHED_FIFO;
554                proc_sched->priority = prio;
555        } else if (strcmp(policy_str, "rr") == 0) {
556                proc_sched->policy = SCHED_RR;
557                proc_sched->priority = prio;
558        } else
559                badusage("invalid process scheduler policy");
560
561        validate_proc_schedule();
562}
563
564static void
565parse_io_schedule(const char *string)
566{
567        char *class_str, *prio_str;
568        int prio = 4;
569
570        class_str = xstrdup(string);
571        class_str = strtok(class_str, ":");
572        prio_str = strtok(NULL, ":");
573
574        if (prio_str && parse_unsigned(prio_str, 10, &prio) != 0)
575                fatal("invalid IO scheduler priority");
576
577        io_sched = xmalloc(sizeof(*io_sched));
578        io_sched->policy_name = class_str;
579
580        if (strcmp(class_str, "real-time") == 0) {
581                io_sched->policy = IOPRIO_CLASS_RT;
582                io_sched->priority = prio;
583        } else if (strcmp(class_str, "best-effort") == 0) {
584                io_sched->policy = IOPRIO_CLASS_BE;
585                io_sched->priority = prio;
586        } else if (strcmp(class_str, "idle") == 0) {
587                io_sched->policy = IOPRIO_CLASS_IDLE;
588                io_sched->priority = 7;
589        } else
590                badusage("invalid IO scheduler policy");
591
592        if (io_sched->priority < IO_SCHED_PRIO_MIN)
593                badusage("IO scheduler priority less than min");
594        if (io_sched->priority > IO_SCHED_PRIO_MAX)
595                badusage("IO scheduler priority greater than max");
596}
597
598static void
599set_proc_schedule(struct res_schedule *sched)
600{
601#ifdef _POSIX_PRIORITY_SCHEDULING
602        struct sched_param param;
603
604        param.sched_priority = sched->priority;
605
606        if (sched_setscheduler(getpid(), sched->policy, &param) == -1)
607                fatal("unable to set process scheduler");
608#endif
609}
610
611#ifdef HAVE_IOPRIO_SET
612static inline int
613ioprio_set(int which, int who, int ioprio)
614{
615        return syscall(SYS_ioprio_set, which, who, ioprio);
616}
617#endif
618
619static void
620set_io_schedule(struct res_schedule *sched)
621{
622#ifdef HAVE_IOPRIO_SET
623        int io_sched_mask;
624
625        io_sched_mask = IOPRIO_PRIO_VALUE(sched->policy, sched->priority);
626        if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), io_sched_mask) == -1)
627                warning("unable to alter IO priority to mask %i (%s)\n",
628                        io_sched_mask, strerror(errno));
629#endif
630}
631
632static void
633parse_schedule_item(const char *string, struct schedule_item *item)
634{
635        const char *after_hyph;
636
637        if (strcmp(string, "forever") == 0) {
638                item->type = sched_forever;
639        } else if (isdigit(string[0])) {
640                item->type = sched_timeout;
641                if (parse_unsigned(string, 10, &item->value) != 0)
642                        badusage("invalid timeout value in schedule");
643        } else if ((after_hyph = string + (string[0] == '-')) &&
644                   parse_signal(after_hyph, &item->value) == 0) {
645                item->type = sched_signal;
646        } else {
647                badusage("invalid schedule item (must be [-]<signal-name>, "
648                         "-<signal-number>, <timeout> or 'forever'");
649        }
650}
651
652static void
653parse_schedule(const char *schedule_str)
654{
655        char item_buf[20];
656        const char *slash;
657        int count, repeatat;
658        size_t str_len;
659
660        count = 0;
661        for (slash = schedule_str; *slash; slash++)
662                if (*slash == '/')
663                        count++;
664
665        schedule_length = (count == 0) ? 4 : count + 1;
666        schedule = xmalloc(sizeof(*schedule) * schedule_length);
667
668        if (count == 0) {
669                schedule[0].type = sched_signal;
670                schedule[0].value = signal_nr;
671                parse_schedule_item(schedule_str, &schedule[1]);
672                if (schedule[1].type != sched_timeout) {
673                        badusage ("--retry takes timeout, or schedule list"
674                                  " of at least two items");
675                }
676                schedule[2].type = sched_signal;
677                schedule[2].value = SIGKILL;
678                schedule[3] = schedule[1];
679        } else {
680                count = 0;
681                repeatat = -1;
682                while (schedule_str != NULL) {
683                        slash = strchr(schedule_str, '/');
684                        str_len = slash ? (size_t)(slash - schedule_str) : strlen(schedule_str);
685                        if (str_len >= sizeof(item_buf))
686                                badusage("invalid schedule item: far too long"
687                                         " (you must delimit items with slashes)");
688                        memcpy(item_buf, schedule_str, str_len);
689                        item_buf[str_len] = '\0';
690                        schedule_str = slash ? slash + 1 : NULL;
691
692                        parse_schedule_item(item_buf, &schedule[count]);
693                        if (schedule[count].type == sched_forever) {
694                                if (repeatat >= 0)
695                                        badusage("invalid schedule: 'forever'"
696                                                 " appears more than once");
697                                repeatat = count;
698                                continue;
699                        }
700                        count++;
701                }
702                if (repeatat == count)
703                        badusage("invalid schedule: 'forever' appears last, "
704                                 "nothing to repeat");
705                if (repeatat >= 0) {
706                        schedule[count].type = sched_goto;
707                        schedule[count].value = repeatat;
708                        count++;
709                }
710                assert(count == schedule_length);
711        }
712}
713
714static void
715set_action(enum action_code new_action)
716{
717        if (action == new_action)
718                return;
719
720        if (action != action_none)
721                badusage("only one command can be specified");
722
723        action = new_action;
724}
725
726static void
727parse_options(int argc, char * const *argv)
728{
729        static struct option longopts[] = {
730                { "help",         0, NULL, 'H'},
731                { "stop",         0, NULL, 'K'},
732                { "start",        0, NULL, 'S'},
733                { "status",       0, NULL, 'T'},
734                { "version",      0, NULL, 'V'},
735                { "startas",      1, NULL, 'a'},
736                { "name",         1, NULL, 'n'},
737                { "oknodo",       0, NULL, 'o'},
738                { "pidfile",      1, NULL, 'p'},
739                { "quiet",        0, NULL, 'q'},
740                { "signal",       1, NULL, 's'},
741                { "test",         0, NULL, 't'},
742                { "user",         1, NULL, 'u'},
743                { "group",        1, NULL, 'g'},
744                { "chroot",       1, NULL, 'r'},
745                { "verbose",      0, NULL, 'v'},
746                { "exec",         1, NULL, 'x'},
747                { "chuid",        1, NULL, 'c'},
748                { "nicelevel",    1, NULL, 'N'},
749                { "procsched",    1, NULL, 'P'},
750                { "iosched",      1, NULL, 'I'},
751                { "umask",        1, NULL, 'k'},
752                { "background",   0, NULL, 'b'},
753                { "no-close",     0, NULL, 'C'},
754                { "make-pidfile", 0, NULL, 'm'},
755                { "retry",        1, NULL, 'R'},
756                { "chdir",        1, NULL, 'd'},
757                { NULL,           0, NULL, 0  }
758        };
759        const char *umask_str = NULL;
760        const char *signal_str = NULL;
761        const char *schedule_str = NULL;
762        const char *proc_schedule_str = NULL;
763        const char *io_schedule_str = NULL;
764        int c;
765
766        for (;;) {
767                c = getopt_long(argc, argv,
768                                "HKSVTa:n:op:qr:s:tu:vx:c:N:P:I:k:bCmR:g:d:",
769                                longopts, NULL);
770                if (c == -1)
771                        break;
772                switch (c) {
773                case 'H':  /* --help */
774                        usage();
775                        exit(0);
776                case 'K':  /* --stop */
777                        set_action(action_stop);
778                        break;
779                case 'S':  /* --start */
780                        set_action(action_start);
781                        break;
782                case 'T':  /* --status */
783                        set_action(action_status);
784                        break;
785                case 'V':  /* --version */
786                        do_version();
787                        exit(0);
788                case 'a':  /* --startas <pathname> */
789                        startas = optarg;
790                        break;
791                case 'n':  /* --name <process-name> */
792                        cmdname = optarg;
793                        break;
794                case 'o':  /* --oknodo */
795                        exitnodo = 0;
796                        break;
797                case 'p':  /* --pidfile <pid-file> */
798                        pidfile = optarg;
799                        break;
800                case 'q':  /* --quiet */
801                        quietmode = 1;
802                        break;
803                case 's':  /* --signal <signal> */
804                        signal_str = optarg;
805                        break;
806                case 't':  /* --test */
807                        testmode = 1;
808                        break;
809                case 'u':  /* --user <username>|<uid> */
810                        userspec = optarg;
811                        break;
812                case 'v':  /* --verbose */
813                        quietmode = -1;
814                        break;
815                case 'x':  /* --exec <executable> */
816                        execname = optarg;
817                        break;
818                case 'c':  /* --chuid <username>|<uid> */
819                        /* We copy the string just in case we need the
820                         * argument later. */
821                        changeuser = xstrdup(optarg);
822                        changeuser = strtok(changeuser, ":");
823                        changegroup = strtok(NULL, ":");
824                        break;
825                case 'g':  /* --group <group>|<gid> */
826                        changegroup = optarg;
827                        break;
828                case 'r':  /* --chroot /new/root */
829                        changeroot = optarg;
830                        break;
831                case 'N':  /* --nice */
832                        nicelevel = atoi(optarg);
833                        break;
834                case 'P':  /* --procsched */
835                        proc_schedule_str = optarg;
836                        break;
837                case 'I':  /* --iosched */
838                        io_schedule_str = optarg;
839                        break;
840                case 'k':  /* --umask <mask> */
841                        umask_str = optarg;
842                        break;
843                case 'b':  /* --background */
844                        background = 1;
845                        break;
846                case 'C': /* --no-close */
847                        close_io = 0;
848                        break;
849                case 'm':  /* --make-pidfile */
850                        mpidfile = 1;
851                        break;
852                case 'R':  /* --retry <schedule>|<timeout> */
853                        schedule_str = optarg;
854                        break;
855                case 'd':  /* --chdir /new/dir */
856                        changedir = optarg;
857                        break;
858                default:
859                        /* Message printed by getopt. */
860                        badusage(NULL);
861                }
862        }
863
864        if (signal_str != NULL) {
865                if (parse_signal(signal_str, &signal_nr) != 0)
866                        badusage("signal value must be numeric or name"
867                                 " of signal (KILL, INT, ...)");
868        }
869
870        if (schedule_str != NULL) {
871                parse_schedule(schedule_str);
872        }
873
874        if (proc_schedule_str != NULL)
875                parse_proc_schedule(proc_schedule_str);
876
877        if (io_schedule_str != NULL)
878                parse_io_schedule(io_schedule_str);
879
880        if (umask_str != NULL) {
881                if (parse_umask(umask_str, &umask_value) != 0)
882                        badusage("umask value must be a positive number");
883        }
884
885        if (action == action_none)
886                badusage("need one of --start or --stop or --status");
887
888        if (!execname && !pidfile && !userspec && !cmdname)
889                badusage("need at least one of --exec, --pidfile, --user or --name");
890
891        if (cmdname && strlen(cmdname) > PROCESS_NAME_SIZE)
892                warning("this system is not able to track process names\n"
893                        "longer than %d characters, please use --exec "
894                        "instead of --name.\n", PROCESS_NAME_SIZE);
895
896        if (!startas)
897                startas = execname;
898
899        if (action == action_start && !startas)
900                badusage("--start needs --exec or --startas");
901
902        if (mpidfile && pidfile == NULL)
903                badusage("--make-pidfile requires --pidfile");
904
905        if (background && action != action_start)
906                badusage("--background is only relevant with --start");
907
908        if (!close_io && !background)
909                badusage("--no-close is only relevant with --background");
910}
911
912static bool
913pid_is_exec(pid_t pid, const struct stat *esb)
914{
915        char lname[32];
916        char lcontents[_POSIX_PATH_MAX];
917        const char deleted[] = " (deleted)";
918        int nread;
919        struct stat sb;
920
921        sprintf(lname, "/proc/%d/exe", pid);
922        nread = readlink(lname, lcontents, sizeof(lcontents));
923        if (nread == -1)
924                return false;
925
926        lcontents[nread] = '\0';
927        if (strcmp(lcontents + nread - strlen(deleted), deleted) == 0)
928                lcontents[nread - strlen(deleted)] = '\0';
929
930        if (stat(lcontents, &sb) != 0)
931                return false;
932
933        return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
934}
935
936static bool
937pid_is_user(pid_t pid, uid_t uid)
938{
939        struct stat sb;
940        char buf[32];
941
942        sprintf(buf, "/proc/%d", pid);
943        if (stat(buf, &sb) != 0)
944                return false;
945        return (sb.st_uid == uid);
946}
947
948static bool
949pid_is_cmd(pid_t pid, const char *name)
950{
951        char buf[32];
952        FILE *f;
953        int c;
954
955        sprintf(buf, "/proc/%d/stat", pid);
956        f = fopen(buf, "r");
957        if (!f)
958                return false;
959        while ((c = getc(f)) != EOF && c != '(')
960                ;
961        if (c != '(') {
962                fclose(f);
963                return false;
964        }
965        /* This hopefully handles command names containing ‘)’. */
966        while ((c = getc(f)) != EOF && c == *name)
967                name++;
968        fclose(f);
969        return (c == ')' && *name == '\0');
970}
971
972static bool
973pid_is_running(pid_t pid)
974{
975        if (kill(pid, 0) == 0 || errno == EPERM)
976                return true;
977        else if (errno == ESRCH)
978                return false;
979        else
980                fatal("error checking pid %u status", pid);
981}
982
983static enum status_code
984pid_check(pid_t pid)
985{
986        if (execname && !pid_is_exec(pid, &exec_stat))
987                return status_dead;
988        if (userspec && !pid_is_user(pid, user_id))
989                return status_dead;
990        if (cmdname && !pid_is_cmd(pid, cmdname))
991                return status_dead;
992        if (action != action_stop && !pid_is_running(pid))
993                return status_dead;
994
995        pid_list_push(&found, pid);
996
997        return status_ok;
998}
999
1000static enum status_code
1001do_pidfile(const char *name)
1002{
1003        FILE *f;
1004        static pid_t pid = 0;
1005
1006        if (pid)
1007                return pid_check(pid);
1008
1009        f = fopen(name, "r");
1010        if (f) {
1011                enum status_code pid_status;
1012
1013                if (fscanf(f, "%d", &pid) == 1)
1014                        pid_status = pid_check(pid);
1015                else
1016                        pid_status = status_unknown;
1017                fclose(f);
1018
1019                if (pid_status == status_dead)
1020                        return status_dead_pidfile;
1021                else
1022                        return pid_status;
1023        } else if (errno == ENOENT)
1024                return status_dead;
1025        else
1026                fatal("unable to open pidfile %s", name);
1027}
1028
1029static enum status_code
1030do_procinit(void)
1031{
1032        DIR *procdir;
1033        struct dirent *entry;
1034        int foundany;
1035        pid_t pid;
1036        enum status_code prog_status = status_dead;
1037
1038        procdir = opendir("/proc");
1039        if (!procdir)
1040                fatal("unable to opendir /proc");
1041
1042        foundany = 0;
1043        while ((entry = readdir(procdir)) != NULL) {
1044                enum status_code pid_status;
1045
1046                if (sscanf(entry->d_name, "%d", &pid) != 1)
1047                        continue;
1048                foundany++;
1049
1050                pid_status = pid_check(pid);
1051                if (pid_status < prog_status)
1052                        prog_status = pid_status;
1053        }
1054        closedir(procdir);
1055        if (!foundany)
1056                fatal("nothing in /proc - not mounted?");
1057
1058        return prog_status;
1059}
1060
1061static enum status_code
1062do_findprocs(void)
1063{
1064        pid_list_free(&found);
1065
1066        if (pidfile)
1067                return do_pidfile(pidfile);
1068        else
1069                return do_procinit();
1070}
1071
1072static void
1073do_stop(int sig_num, int *n_killed, int *n_notkilled)
1074{
1075        struct pid_list *p;
1076
1077        do_findprocs();
1078
1079        *n_killed = 0;
1080        *n_notkilled = 0;
1081
1082        if (!found)
1083                return;
1084
1085        pid_list_free(&killed);
1086
1087        for (p = found; p; p = p->next) {
1088                if (testmode) {
1089                        if (quietmode <= 0)
1090                                printf("Would send signal %d to %d.\n",
1091                                       sig_num, p->pid);
1092                        (*n_killed)++;
1093                } else if (kill(p->pid, sig_num) == 0) {
1094                        pid_list_push(&killed, p->pid);
1095                        (*n_killed)++;
1096                } else {
1097                        if (sig_num)
1098                                warning("failed to kill %d: %s\n",
1099                                        p->pid, strerror(errno));
1100                        (*n_notkilled)++;
1101                }
1102        }
1103}
1104
1105static void
1106do_stop_summary(int retry_nr)
1107{
1108        struct pid_list *p;
1109
1110        if (quietmode >= 0 || !killed)
1111                return;
1112
1113        printf("Stopped %s (pid", what_stop);
1114        for (p = killed; p; p = p->next)
1115                printf(" %d", p->pid);
1116        putchar(')');
1117        if (retry_nr > 0)
1118                printf(", retry #%d", retry_nr);
1119        printf(".\n");
1120}
1121
1122static void
1123set_what_stop(const char *str)
1124{
1125        strncpy(what_stop, str, sizeof(what_stop));
1126        what_stop[sizeof(what_stop) - 1] = '\0';
1127}
1128
1129/*
1130 * We want to keep polling for the processes, to see if they've exited, or
1131 * until the timeout expires.
1132 *
1133 * This is a somewhat complicated algorithm to try to ensure that we notice
1134 * reasonably quickly when all the processes have exited, but don't spend
1135 * too much CPU time polling. In particular, on a fast machine with
1136 * quick-exiting daemons we don't want to delay system shutdown too much,
1137 * whereas on a slow one, or where processes are taking some time to exit,
1138 * we want to increase the polling interval.
1139 *
1140 * The algorithm is as follows: we measure the elapsed time it takes to do
1141 * one poll(), and wait a multiple of this time for the next poll. However,
1142 * if that would put us past the end of the timeout period we wait only as
1143 * long as the timeout period, but in any case we always wait at least
1144 * MIN_POLL_INTERVAL (20ms). The multiple (‘ratio’) starts out as 2, and
1145 * increases by 1 for each poll to a maximum of 10; so we use up to between
1146 * 30% and 10% of the machine's resources (assuming a few reasonable things
1147 * about system performance).
1148 */
1149static bool
1150do_stop_timeout(int timeout, int *n_killed, int *n_notkilled)
1151{
1152        struct timeval stopat, before, after, interval, maxinterval;
1153        int r, ratio;
1154
1155        xgettimeofday(&stopat);
1156        stopat.tv_sec += timeout;
1157        ratio = 1;
1158        for (;;) {
1159                xgettimeofday(&before);
1160                if (timercmp(&before, &stopat, >))
1161                        return false;
1162
1163                do_stop(0, n_killed, n_notkilled);
1164                if (!*n_killed)
1165                        return true;
1166
1167                xgettimeofday(&after);
1168
1169                if (!timercmp(&after, &stopat, <))
1170                        return false;
1171
1172                if (ratio < 10)
1173                        ratio++;
1174
1175                timersub(&stopat, &after, &maxinterval);
1176                timersub(&after, &before, &interval);
1177                tmul(&interval, ratio);
1178
1179                if (interval.tv_sec < 0 || interval.tv_usec < 0)
1180                        interval.tv_sec = interval.tv_usec = 0;
1181
1182                if (timercmp(&interval, &maxinterval, >))
1183                        interval = maxinterval;
1184
1185                if (interval.tv_sec == 0 &&
1186                    interval.tv_usec <= MIN_POLL_INTERVAL)
1187                        interval.tv_usec = MIN_POLL_INTERVAL;
1188
1189                r = select(0, NULL, NULL, NULL, &interval);
1190                if (r < 0 && errno != EINTR)
1191                        fatal("select() failed for pause");
1192        }
1193}
1194
1195static int
1196finish_stop_schedule(bool anykilled)
1197{
1198        if (anykilled)
1199                return 0;
1200
1201        if (quietmode <= 0)
1202                printf("No %s found running; none killed.\n", what_stop);
1203
1204        return exitnodo;
1205}
1206
1207static int
1208run_stop_schedule(void)
1209{
1210        int position, n_killed, n_notkilled, value, retry_nr;
1211        bool anykilled;
1212
1213        if (testmode) {
1214                if (schedule != NULL) {
1215                        if (quietmode <= 0)
1216                                printf("Ignoring --retry in test mode\n");
1217                        schedule = NULL;
1218                }
1219        }
1220
1221        if (cmdname)
1222                set_what_stop(cmdname);
1223        else if (execname)
1224                set_what_stop(execname);
1225        else if (pidfile)
1226                sprintf(what_stop, "process in pidfile '%.200s'", pidfile);
1227        else if (userspec)
1228                sprintf(what_stop, "process(es) owned by '%.200s'", userspec);
1229        else
1230                fatal("internal error, no match option, please report");
1231
1232        anykilled = false;
1233        retry_nr = 0;
1234
1235        if (schedule == NULL) {
1236                do_stop(signal_nr, &n_killed, &n_notkilled);
1237                do_stop_summary(0);
1238                if (n_notkilled > 0 && quietmode <= 0)
1239                        printf("%d pids were not killed\n", n_notkilled);
1240                if (n_killed)
1241                        anykilled = true;
1242                return finish_stop_schedule(anykilled);
1243        }
1244
1245        for (position = 0; position < schedule_length; position++) {
1246        reposition:
1247                value = schedule[position].value;
1248                n_notkilled = 0;
1249
1250                switch (schedule[position].type) {
1251                case sched_goto:
1252                        position = value;
1253                        goto reposition;
1254                case sched_signal:
1255                        do_stop(value, &n_killed, &n_notkilled);
1256                        do_stop_summary(retry_nr++);
1257                        if (!n_killed)
1258                                return finish_stop_schedule(anykilled);
1259                        else
1260                                anykilled = true;
1261                        continue;
1262                case sched_timeout:
1263                        if (do_stop_timeout(value, &n_killed, &n_notkilled))
1264                                return finish_stop_schedule(anykilled);
1265                        else
1266                                continue;
1267                default:
1268                        assert(!"schedule[].type value must be valid");
1269                }
1270        }
1271
1272        if (quietmode <= 0)
1273                printf("Program %s, %d process(es), refused to die.\n",
1274                       what_stop, n_killed);
1275
1276        return 2;
1277}
1278
1279int
1280main(int argc, char **argv)
1281{
1282        enum status_code prog_status;
1283        int devnull_fd = -1;
1284        gid_t rgid;
1285        uid_t ruid;
1286        progname = argv[0];
1287
1288        parse_options(argc, argv);
1289        argc -= optind;
1290        argv += optind;
1291
1292        if (execname) {
1293                char *fullexecname;
1294
1295                /* If it's a relative path, normalize it. */
1296                if (execname[0] != '/')
1297                        execname = newpath(changedir, execname);
1298
1299                if (changeroot)
1300                        fullexecname = newpath(changeroot, execname);
1301                else
1302                        fullexecname = execname;
1303
1304                if (stat(fullexecname, &exec_stat))
1305                        fatal("unable to stat %s", fullexecname);
1306
1307                if (fullexecname != execname)
1308                        free(fullexecname);
1309        }
1310
1311        if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
1312                struct passwd *pw;
1313
1314                pw = getpwnam(userspec);
1315                if (!pw)
1316                        fatal("user '%s' not found", userspec);
1317
1318                user_id = pw->pw_uid;
1319        }
1320
1321        if (changegroup && sscanf(changegroup, "%d", &runas_gid) != 1) {
1322                struct group *gr = getgrnam(changegroup);
1323                if (!gr)
1324                        fatal("group '%s' not found", changegroup);
1325                changegroup = gr->gr_name;
1326                runas_gid = gr->gr_gid;
1327        }
1328        if (changeuser) {
1329                struct passwd *pw;
1330                struct stat st;
1331
1332                if (sscanf(changeuser, "%d", &runas_uid) == 1)
1333                        pw = getpwuid(runas_uid);
1334                else
1335                        pw = getpwnam(changeuser);
1336                if (!pw)
1337                        fatal("user '%s' not found", changeuser);
1338                changeuser = pw->pw_name;
1339                runas_uid = pw->pw_uid;
1340                if (changegroup == NULL) {
1341                        /* Pass the default group of this user. */
1342                        changegroup = ""; /* Just empty. */
1343                        runas_gid = pw->pw_gid;
1344                }
1345                if (stat(pw->pw_dir, &st) == 0)
1346                        setenv("HOME", pw->pw_dir, 1);
1347        }
1348
1349        if (action == action_stop) {
1350                int i = run_stop_schedule();
1351                exit(i);
1352        }
1353
1354        prog_status = do_findprocs();
1355
1356        if (action == action_status)
1357                exit(prog_status);
1358
1359        if (found) {
1360                if (quietmode <= 0)
1361                        printf("%s already running.\n", execname ? execname : "process");
1362                exit(exitnodo);
1363        }
1364        if (testmode && quietmode <= 0) {
1365                printf("Would start %s ", startas);
1366                while (argc-- > 0)
1367                        printf("%s ", *argv++);
1368                if (changeuser != NULL) {
1369                        printf(" (as user %s[%d]", changeuser, runas_uid);
1370                        if (changegroup != NULL)
1371                                printf(", and group %s[%d])", changegroup, runas_gid);
1372                        else
1373                                printf(")");
1374                }
1375                if (changeroot != NULL)
1376                        printf(" in directory %s", changeroot);
1377                if (nicelevel)
1378                        printf(", and add %i to the priority", nicelevel);
1379                if (proc_sched)
1380                        printf(", with scheduling policy %s with priority %i",
1381                               proc_sched->policy_name, proc_sched->priority);
1382                if (io_sched)
1383                        printf(", with IO scheduling class %s with priority %i",
1384                               io_sched->policy_name, io_sched->priority);
1385                printf(".\n");
1386        }
1387        if (testmode)
1388                exit(0);
1389        if (quietmode < 0)
1390                printf("Starting %s...\n", startas);
1391        *--argv = startas;
1392        if (background)
1393                /* Ok, we need to detach this process. */
1394                daemonize();
1395        if (background && close_io) {
1396                devnull_fd = open("/dev/null", O_RDWR);
1397                if (devnull_fd < 0)
1398                        fatal("unable to open '%s'", "/dev/null");
1399        }
1400        if (nicelevel) {
1401                errno = 0;
1402                if ((nice(nicelevel) == -1) && (errno != 0))
1403                        fatal("unable to alter nice level by %i", nicelevel);
1404        }
1405        if (proc_sched)
1406                set_proc_schedule(proc_sched);
1407        if (io_sched)
1408                set_io_schedule(io_sched);
1409        if (umask_value >= 0)
1410                umask(umask_value);
1411        if (mpidfile && pidfile != NULL)
1412                /* User wants _us_ to make the pidfile. */
1413                write_pidfile(pidfile, getpid());
1414        if (changeroot != NULL) {
1415                if (chdir(changeroot) < 0)
1416                        fatal("unable to chdir() to %s", changeroot);
1417                if (chroot(changeroot) < 0)
1418                        fatal("unable to chroot() to %s", changeroot);
1419        }
1420        if (chdir(changedir) < 0)
1421                fatal("unable to chdir() to %s", changedir);
1422
1423        rgid = getgid();
1424        ruid = getuid();
1425        if (changegroup != NULL) {
1426                if (rgid != (gid_t)runas_gid)
1427                        if (setgid(runas_gid))
1428                                fatal("unable to set gid to %d", runas_gid);
1429        }
1430        if (changeuser != NULL) {
1431                /* We assume that if our real user and group are the same as
1432                 * the ones we should switch to, the supplementary groups
1433                 * will be already in place. */
1434                if (rgid != (gid_t)runas_gid || ruid != (uid_t)runas_uid)
1435                        if (initgroups(changeuser, runas_gid))
1436                                fatal("unable to set initgroups() with gid %d",
1437                                      runas_gid);
1438
1439                if (ruid != (uid_t)runas_uid)
1440                        if (setuid(runas_uid))
1441                                fatal("unable to set uid to %s", changeuser);
1442        }
1443
1444        /* Set a default umask for dumb programs. */
1445        if (background && umask_value < 0)
1446                umask(022);
1447
1448        if (background && close_io) {
1449                int i;
1450
1451                dup2(devnull_fd, 0); /* stdin */
1452                dup2(devnull_fd, 1); /* stdout */
1453                dup2(devnull_fd, 2); /* stderr */
1454
1455                 /* Now close all extra fds. */
1456                for (i = get_open_fd_max() - 1; i >= 3; --i)
1457                        close(i);
1458        }
1459        execv(startas, argv);
1460        fatal("unable to start %s", startas);
1461}
Note: See TracBrowser for help on using the repository browser.