/[gentoo-alt]/trunk/baselayout-prefix/src/start-stop-daemon.c
Gentoo

Contents of /trunk/baselayout-prefix/src/start-stop-daemon.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1682 - (hide annotations) (download) (as text)
Thu Mar 31 14:11:17 2011 UTC (3 years, 3 months ago) by grobian
File MIME type: text/x-csrc
File size: 34874 byte(s)
Add original code base from baselayout-1.12.5
1 grobian 1682 /*
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 aswell.
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     * Changes by Quequero <quequero@bitchx.it>:
24     * Added -e|--env for setting an environment variable before starting the
25     * process.
26     * Moved --make-pidfile after chrooting process (pid file will be wrote in
27     * new root if -r option is used!).
28     * Daemon binary will be stat()ed correctly if it's going to be chrooted
29     * with -r|--chroot.
30     *
31     */
32    
33     #define VERSION "1.13.11+gentoo"
34    
35     #define NONRETURNPRINTFFORMAT(x, y) \
36     __attribute__((noreturn, format(printf, x, y)))
37     #define NONRETURNING \
38     __attribute__((noreturn))
39    
40     #if defined(linux) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__))
41     # define OSLinux
42     #elif defined(__GNU__)
43     # define OSHURD
44     #elif defined(__sparc__)
45     # define OSsunos
46     #elif defined(OPENBSD) || defined(__OpenBSD__)
47     # define OSOpenBSD
48     #elif defined(hpux)
49     # define OShpux
50     #elif defined(__FreeBSD__)
51     # define OSFreeBSD
52     #elif defined(__NetBSD__)
53     # define OSNetBSD
54     #elif defined(__APPLE__)
55     # define OSDarwin
56     #else
57     # error Unknown architecture - cannot build start-stop-daemon
58     #endif
59    
60     #define MIN_POLL_INTERVAL 20000 /*us*/
61    
62     #if defined(OSHURD)
63     # include <hurd.h>
64     # include <ps.h>
65     #endif
66    
67     #if defined(OSOpenBSD) || defined(OSFreeBSD) || defined(OSNetBSD) || defined(OSDarwin)
68     #include <sys/param.h>
69     #include <sys/user.h>
70     #include <sys/proc.h>
71     #include <sys/stat.h>
72     #include <sys/sysctl.h>
73     #include <sys/types.h>
74    
75     #include <err.h>
76     #include <kvm.h>
77     #include <limits.h>
78     #endif
79    
80     #if defined(OShpux)
81     #include <sys/param.h>
82     #include <sys/pstat.h>
83     #endif
84    
85     #include <errno.h>
86     #include <stdio.h>
87     #include <stdlib.h>
88     #include <string.h>
89     #include <stdarg.h>
90     #include <signal.h>
91     #include <sys/stat.h>
92     #include <dirent.h>
93     #include <sys/time.h>
94     #include <unistd.h>
95     #include <getopt.h>
96     #include <pwd.h>
97     #include <grp.h>
98     #include <sys/ioctl.h>
99     #include <sys/types.h>
100     #include <sys/termios.h>
101     #include <fcntl.h>
102     #include <limits.h>
103     #include <assert.h>
104     #include <ctype.h>
105    
106     #include <stddef.h>
107    
108     #include "headers.h"
109    
110     #ifdef HURD_IHASH_H
111     # include <hurd/ihash.h>
112     #endif
113    
114     static int testmode = 0;
115     static int quietmode = 0;
116     static int exitnodo = 1;
117     static int start = 0;
118     static int stop = 0;
119     static int background = 0;
120     static int mpidfile = 0;
121     static int signal_nr = 15;
122     static const char *signal_str = NULL;
123     static int user_id = -1;
124     static int runas_uid = -1;
125     static int runas_gid = -1;
126     static char *env = NULL;
127     static const char *userspec = NULL;
128     static char *changeuser = NULL;
129     static const char *changegroup = NULL;
130     static char *changeroot = NULL;
131     static const char *changedir = "/";
132     static const char *cmdname = NULL;
133     static char *execname = NULL;
134     static char *startas = NULL;
135     static const char *pidfile = NULL;
136     static char what_stop[1024];
137     static const char *schedule_str = NULL;
138     static const char *progname = "";
139     static int nicelevel = 0;
140    
141     static struct stat exec_stat;
142     #if defined(OSHURD)
143     static struct proc_stat_list *procset = NULL;
144     #endif
145    
146    
147     struct pid_list {
148     struct pid_list *next;
149     pid_t pid;
150     };
151    
152     static struct pid_list *found = NULL;
153     static struct pid_list *killed = NULL;
154    
155     struct schedule_item {
156     enum { sched_timeout, sched_signal, sched_goto, sched_forever } type;
157     int value; /* seconds, signal no., or index into array */
158     /* sched_forever is only seen within parse_schedule and callees */
159     };
160    
161     static int schedule_length;
162     static struct schedule_item *schedule = NULL;
163    
164     static void *xmalloc(int size);
165     static void push(struct pid_list **list, pid_t pid);
166     static void do_help(void);
167     static void parse_options(int argc, char * const *argv);
168     static int pid_is_user(pid_t pid, uid_t uid);
169     static int pid_is_cmd(pid_t pid, const char *name);
170     static void check(pid_t pid);
171     static void do_pidfile(const char *name);
172     static void do_stop(int signal_nr, int quietmode,
173     int *n_killed, int *n_notkilled, int retry_nr);
174     #if defined(OSLinux) || defined(OShpux)
175     static int pid_is_exec(pid_t pid, const struct stat *esb);
176     #endif
177    
178     #ifdef __GNUC__
179     static void fatal(const char *format, ...)
180     NONRETURNPRINTFFORMAT(1, 2);
181     static void badusage(const char *msg)
182     NONRETURNING;
183     #else
184     static void fatal(const char *format, ...);
185     static void badusage(const char *msg);
186     #endif
187    
188     /* This next part serves only to construct the TVCALC macro, which
189     * is used for doing arithmetic on struct timeval's. It works like this:
190     * TVCALC(result, expression);
191     * where result is a struct timeval (and must be an lvalue) and
192     * expression is the single expression for both components. In this
193     * expression you can use the special values TVELEM, which when fed a
194     * const struct timeval* gives you the relevant component, and
195     * TVADJUST. TVADJUST is necessary when subtracting timevals, to make
196     * it easier to renormalise. Whenver you subtract timeval elements,
197     * you must make sure that TVADJUST is added to the result of the
198     * subtraction (before any resulting multiplication or what have you).
199     * TVELEM must be linear in TVADJUST.
200     */
201     typedef long tvselector(const struct timeval*);
202     static long tvselector_sec(const struct timeval *tv) { return tv->tv_sec; }
203     static long tvselector_usec(const struct timeval *tv) { return tv->tv_usec; }
204     #define TVCALC_ELEM(result, expr, sec, adj) \
205     { \
206     const long TVADJUST = adj; \
207     long (*const TVELEM)(const struct timeval*) = tvselector_##sec; \
208     (result).tv_##sec = (expr); \
209     }
210     #define TVCALC(result,expr) \
211     do { \
212     TVCALC_ELEM(result, expr, sec, (-1)); \
213     TVCALC_ELEM(result, expr, usec, (+1000000)); \
214     (result).tv_sec += (result).tv_usec / 1000000; \
215     (result).tv_usec %= 1000000; \
216     } while(0)
217    
218    
219     static void
220     fatal(const char *format, ...)
221     {
222     va_list arglist;
223    
224     fprintf(stderr, "%s: ", progname);
225     va_start(arglist, format);
226     vfprintf(stderr, format, arglist);
227     va_end(arglist);
228     fprintf(stderr, " (%s)\n", strerror (errno));
229     exit(2);
230     }
231    
232    
233     static void *
234     xmalloc(int size)
235     {
236     void *ptr;
237    
238     ptr = malloc(size);
239     if (ptr)
240     return ptr;
241     fatal("malloc(%d) failed", size);
242     }
243    
244    
245     static void
246     xgettimeofday(struct timeval *tv)
247     {
248     if (gettimeofday(tv,0) != 0)
249     fatal("gettimeofday failed: %s", strerror(errno));
250     }
251    
252    
253     static void
254     push(struct pid_list **list, pid_t pid)
255     {
256     struct pid_list *p;
257    
258     p = xmalloc(sizeof(*p));
259     p->next = *list;
260     p->pid = pid;
261     *list = p;
262     }
263    
264     static void
265     clear(struct pid_list **list)
266     {
267     struct pid_list *here, *next;
268    
269     for (here = *list; here != NULL; here = next) {
270     next = here->next;
271     free(here);
272     }
273    
274     *list = NULL;
275     }
276    
277     static void
278     do_help(void)
279     {
280     printf(
281     "start-stop-daemon " VERSION " for Debian - small and fast C version written by\n"
282     "Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
283     "\n"
284     "Usage:\n"
285     " start-stop-daemon -S|--start options ... -- arguments ...\n"
286     " start-stop-daemon -K|--stop options ...\n"
287     " start-stop-daemon -H|--help\n"
288     " start-stop-daemon -V|--version\n"
289     "\n"
290     "Options (at least one of --exec|--pidfile|--user is required):\n"
291     " -x|--exec <executable> program to start/check if it is running\n"
292     " -p|--pidfile <pid-file> pid file to check\n"
293     " -c|--chuid <name|uid[:group|gid]>\n"
294     " change to this user/group before starting process\n"
295     " -u|--user <username>|<uid> stop processes owned by this user\n"
296     " -g|--group <group|gid> run process as this group\n"
297     " -n|--name <process-name> stop processes with this name\n"
298     " -s|--signal <signal> signal to send (default TERM)\n"
299     " -a|--startas <pathname> program to start (default is <executable>)\n"
300     " -C|--chdir <directory> Change to <directory>(default is /)\n"
301     " -N|--nicelevel <incr> add incr to the process's nice level\n"
302     " -b|--background force the process to detach\n"
303     " -m|--make-pidfile create the pidfile before starting\n"
304     " -R|--retry <schedule> check whether processes die, and retry\n"
305     " -e|--env <env-name> set an environment variable (PWD=\"/\")\n"
306     " -r|--chroot <path> chroot process to given directory\n"
307     " -t|--test test mode, don't do anything\n"
308     " -o|--oknodo exit status 0 (not 1) if nothing done\n"
309     " -q|--quiet be more quiet\n"
310     " -v|--verbose be more verbose\n"
311     "Retry <schedule> is <item>|/<item>/... where <item> is one of\n"
312     " -<signal-num>|[-]<signal-name> send that signal\n"
313     " <timeout> wait that many seconds\n"
314     " forever repeat remainder forever\n"
315     "or <schedule> may be just <timeout>, meaning <signal>/<timeout>/KILL/<timeout>\n"
316     "\n"
317     "Exit status: 0 = done 1 = nothing done (=> 0 if --oknodo)\n"
318     " 3 = trouble 2 = with --retry, processes wouldn't die\n");
319     }
320    
321    
322     static void
323     badusage(const char *msg)
324     {
325     if (msg)
326     fprintf(stderr, "%s: %s\n", progname, msg);
327     fprintf(stderr, "Try `%s --help' for more information.\n", progname);
328     exit(3);
329     }
330    
331     struct sigpair {
332     const char *name;
333     int signal;
334     };
335    
336     const struct sigpair siglist[] = {
337     { "ABRT", SIGABRT },
338     { "ALRM", SIGALRM },
339     { "FPE", SIGFPE },
340     { "HUP", SIGHUP },
341     { "ILL", SIGILL },
342     { "INT", SIGINT },
343     { "KILL", SIGKILL },
344     { "PIPE", SIGPIPE },
345     { "QUIT", SIGQUIT },
346     { "SEGV", SIGSEGV },
347     { "TERM", SIGTERM },
348     { "USR1", SIGUSR1 },
349     { "USR2", SIGUSR2 },
350     { "CHLD", SIGCHLD },
351     { "CONT", SIGCONT },
352     { "STOP", SIGSTOP },
353     { "TSTP", SIGTSTP },
354     { "TTIN", SIGTTIN },
355     { "TTOU", SIGTTOU }
356     };
357    
358     static int parse_integer(const char *string, int *value_r) {
359     unsigned long ul;
360     char *ep;
361    
362     if (!string[0])
363     return -1;
364    
365     ul= strtoul(string,&ep,10);
366     if (ul > INT_MAX || *ep != '\0')
367     return -1;
368    
369     *value_r= ul;
370     return 0;
371     }
372    
373     static int parse_signal(const char *signal_str, int *signal_nr)
374     {
375     unsigned int i;
376    
377     if (parse_integer(signal_str, signal_nr) == 0)
378     return 0;
379    
380     for (i = 0; i < sizeof (siglist) / sizeof (siglist[0]); i++) {
381     if (strcmp (signal_str, siglist[i].name) == 0) {
382     *signal_nr = siglist[i].signal;
383     return 0;
384     }
385     }
386     return -1;
387     }
388    
389     static void
390     parse_schedule_item(const char *string, struct schedule_item *item) {
391     const char *after_hyph;
392    
393     if (!strcmp(string,"forever")) {
394     item->type = sched_forever;
395     } else if (isdigit(string[0])) {
396     item->type = sched_timeout;
397     if (parse_integer(string, &item->value) != 0)
398     badusage("invalid timeout value in schedule");
399     } else if ((after_hyph = string + (string[0] == '-')) &&
400     parse_signal(after_hyph, &item->value) == 0) {
401     item->type = sched_signal;
402     } else {
403     badusage("invalid schedule item (must be [-]<signal-name>, "
404     "-<signal-number>, <timeout> or `forever'");
405     }
406     }
407    
408     static void
409     parse_schedule(const char *schedule_str) {
410     char item_buf[20];
411     const char *slash;
412     int count, repeatat;
413     ptrdiff_t str_len;
414    
415     count = 0;
416     for (slash = schedule_str; *slash; slash++)
417     if (*slash == '/')
418     count++;
419    
420     schedule_length = (count == 0) ? 4 : count+1;
421     schedule = xmalloc(sizeof(*schedule) * schedule_length);
422    
423     if (count == 0) {
424     schedule[0].type = sched_signal;
425     schedule[0].value = signal_nr;
426     parse_schedule_item(schedule_str, &schedule[1]);
427     if (schedule[1].type != sched_timeout) {
428     badusage ("--retry takes timeout, or schedule list"
429     " of at least two items");
430     }
431     schedule[2].type = sched_signal;
432     schedule[2].value = SIGKILL;
433     schedule[3]= schedule[1];
434     } else {
435     count = 0;
436     repeatat = -1;
437     while (schedule_str != NULL) {
438     slash = strchr(schedule_str,'/');
439     str_len = slash ? slash - schedule_str : strlen(schedule_str);
440     if (str_len >= (ptrdiff_t)sizeof(item_buf))
441     badusage("invalid schedule item: far too long"
442     " (you must delimit items with slashes)");
443     memcpy(item_buf, schedule_str, str_len);
444     item_buf[str_len] = 0;
445     schedule_str = slash ? slash+1 : NULL;
446    
447     parse_schedule_item(item_buf, &schedule[count]);
448     if (schedule[count].type == sched_forever) {
449     if (repeatat >= 0)
450     badusage("invalid schedule: `forever'"
451     " appears more than once");
452     repeatat = count;
453     continue;
454     }
455     count++;
456     }
457     if (repeatat >= 0) {
458     schedule[count].type = sched_goto;
459     schedule[count].value = repeatat;
460     count++;
461     }
462     assert(count == schedule_length);
463     }
464     }
465    
466     static void
467     parse_options(int argc, char * const *argv)
468     {
469     static struct option longopts[] = {
470     { "help", 0, NULL, 'H'},
471     { "stop", 0, NULL, 'K'},
472     { "start", 0, NULL, 'S'},
473     { "version", 0, NULL, 'V'},
474     { "startas", 1, NULL, 'a'},
475     { "env", 1, NULL, 'e'},
476     { "name", 1, NULL, 'n'},
477     { "oknodo", 0, NULL, 'o'},
478     { "pidfile", 1, NULL, 'p'},
479     { "quiet", 0, NULL, 'q'},
480     { "signal", 1, NULL, 's'},
481     { "test", 0, NULL, 't'},
482     { "user", 1, NULL, 'u'},
483     { "group", 1, NULL, 'g'},
484     { "chroot", 1, NULL, 'r'},
485     { "verbose", 0, NULL, 'v'},
486     { "exec", 1, NULL, 'x'},
487     { "chuid", 1, NULL, 'c'},
488     { "nicelevel", 1, NULL, 'N'},
489     { "background", 0, NULL, 'b'},
490     { "make-pidfile", 0, NULL, 'm'},
491     { "retry", 1, NULL, 'R'},
492     { "chdir", 1, NULL, 'd'},
493     { NULL, 0, NULL, 0}
494     };
495     int c;
496    
497     for (;;) {
498     c = getopt_long(argc, argv, "HKSVa:n:op:qr:e:s:tu:vx:c:N:bmR:g:d:",
499     longopts, (int *) 0);
500     if (c == -1)
501     break;
502     switch (c) {
503     case 'H': /* --help */
504     do_help();
505     exit(0);
506     case 'K': /* --stop */
507     stop = 1;
508     break;
509     case 'S': /* --start */
510     start = 1;
511     break;
512     case 'V': /* --version */
513     printf("start-stop-daemon " VERSION "\n");
514     exit(0);
515     case 'a': /* --startas <pathname> */
516     startas = optarg;
517     break;
518     case 'n': /* --name <process-name> */
519     cmdname = optarg;
520     break;
521     case 'o': /* --oknodo */
522     exitnodo = 0;
523     break;
524     case 'p': /* --pidfile <pid-file> */
525     pidfile = optarg;
526     break;
527     case 'q': /* --quiet */
528     quietmode = 1;
529     break;
530     case 's': /* --signal <signal> */
531     signal_str = optarg;
532     break;
533     case 't': /* --test */
534     testmode = 1;
535     break;
536     case 'u': /* --user <username>|<uid> */
537     userspec = optarg;
538     break;
539     case 'v': /* --verbose */
540     quietmode = -1;
541     break;
542     case 'x': /* --exec <executable> */
543     execname = optarg;
544     break;
545     case 'c': /* --chuid <username>|<uid> */
546     /* we copy the string just in case we need the
547     * argument later. */
548     changeuser = strdup(optarg);
549     changeuser = strtok(changeuser, ":");
550     changegroup = strtok(NULL, ":");
551     break;
552     case 'g': /* --group <group>|<gid> */
553     changegroup = optarg;
554     break;
555     case 'r': /* --chroot /new/root */
556     changeroot = optarg;
557     break;
558     case 'e': /* --env <env-name> */
559     env = optarg;
560     break;
561     case 'N': /* --nice */
562     nicelevel = atoi(optarg);
563     break;
564     case 'b': /* --background */
565     background = 1;
566     break;
567     case 'm': /* --make-pidfile */
568     mpidfile = 1;
569     break;
570     case 'R': /* --retry <schedule>|<timeout> */
571     schedule_str = optarg;
572     break;
573     case 'd': /* --chdir /new/dir */
574     changedir = optarg;
575     break;
576     default:
577     badusage(NULL); /* message printed by getopt */
578     }
579     }
580    
581     if (signal_str != NULL) {
582     if (parse_signal (signal_str, &signal_nr) != 0)
583     badusage("signal value must be numeric or name"
584     " of signal (KILL, INT, ...)");
585     }
586    
587     if (schedule_str != NULL) {
588     parse_schedule(schedule_str);
589     }
590    
591     if (start == stop)
592     badusage("need one of --start or --stop");
593    
594     if (!execname && !pidfile && !userspec && !cmdname)
595     badusage("need at least one of --exec, --pidfile, --user or --name");
596    
597     if (!startas)
598     startas = execname;
599    
600     if (start && !startas)
601     badusage("--start needs --exec or --startas");
602    
603     if (mpidfile && pidfile == NULL)
604     badusage("--make-pidfile is only relevant with --pidfile");
605    
606     if (background && !start)
607     badusage("--background is only relevant with --start");
608    
609     }
610    
611     #if defined(OSLinux)
612     static int
613     pid_is_exec(pid_t pid, const struct stat *esb)
614     {
615     struct stat sb;
616     char buf[32];
617    
618     sprintf(buf, "/proc/%d/exe", pid);
619     if (stat(buf, &sb) != 0)
620     return 0;
621     return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
622     }
623    
624    
625     static int
626     pid_is_user(pid_t pid, uid_t uid)
627     {
628     struct stat sb;
629     char buf[32];
630    
631     sprintf(buf, "/proc/%d", pid);
632     if (stat(buf, &sb) != 0)
633     return 0;
634     return (sb.st_uid == uid);
635     }
636    
637    
638     static int
639     pid_is_cmd(pid_t pid, const char *name)
640     {
641     char buf[32];
642     FILE *f;
643     int c;
644    
645     sprintf(buf, "/proc/%d/stat", pid);
646     f = fopen(buf, "r");
647     if (!f)
648     return 0;
649     while ((c = getc(f)) != EOF && c != '(')
650     ;
651     if (c != '(') {
652     fclose(f);
653     return 0;
654     }
655     /* this hopefully handles command names containing ')' */
656     while ((c = getc(f)) != EOF && c == *name)
657     name++;
658     fclose(f);
659     return (c == ')' && *name == '\0');
660     }
661     #endif /* OSLinux */
662    
663    
664     #if defined(OSHURD)
665     static void
666     init_procset(void)
667     {
668     struct ps_context *context;
669     error_t err;
670    
671     err = ps_context_create(getproc(), &context);
672     if (err)
673     error(1, err, "ps_context_create");
674    
675     err = proc_stat_list_create(context, &procset);
676     if (err)
677     error(1, err, "proc_stat_list_create");
678    
679     err = proc_stat_list_add_all(procset, 0, 0);
680     if (err)
681     error(1, err, "proc_stat_list_add_all");
682     }
683    
684     static struct proc_stat *
685     get_proc_stat (pid_t pid, ps_flags_t flags)
686     {
687     struct proc_stat *ps;
688     ps_flags_t wanted_flags = PSTAT_PID | flags;
689    
690     if (!procset)
691     init_procset();
692    
693     ps = proc_stat_list_pid_proc_stat(procset, pid);
694     if (!ps)
695     return NULL;
696     if (proc_stat_set_flags(ps, wanted_flags))
697     return NULL;
698     if ((proc_stat_flags(ps) & wanted_flags) != wanted_flags)
699     return NULL;
700    
701     return ps;
702     }
703    
704     static int
705     pid_is_user(pid_t pid, uid_t uid)
706     {
707     struct proc_stat *ps;
708    
709     ps = get_proc_stat(pid, PSTAT_OWNER_UID);
710     return ps && proc_stat_owner_uid(ps) == uid;
711     }
712    
713     static int
714     pid_is_cmd(pid_t pid, const char *name)
715     {
716     struct proc_stat *ps;
717    
718     ps = get_proc_stat(pid, PSTAT_ARGS);
719     return ps && !strcmp(proc_stat_args(ps), name);
720     }
721    
722     static int
723     pid_is_running(pid_t pid)
724     {
725     return get_proc_stat(pid, 0) != NULL;
726     }
727    
728     #else /* !OSHURD */
729    
730     static int
731     pid_is_running(pid_t pid)
732     {
733     struct stat sb;
734     char buf[32];
735    
736     sprintf(buf, "/proc/%d", pid);
737     if (stat(buf, &sb) != 0) {
738     if (errno!=ENOENT)
739     fatal("Error stating %s: %s", buf, strerror(errno));
740     return 0;
741     }
742    
743     return 1;
744     }
745    
746     #endif /* OSHURD */
747    
748     static void
749     check(pid_t pid)
750     {
751     #if defined(OSLinux) || defined(OShpux)
752     if (execname && !pid_is_exec(pid, &exec_stat))
753     return;
754     #elif defined(OSHURD) || defined(OSFreeBSD) || defined(OSNetBSD) || defined(OSDarwin)
755     /* I will try this to see if it works */
756     if (execname && !pid_is_cmd(pid, execname))
757     return;
758     #endif
759     if (userspec && !pid_is_user(pid, user_id))
760     return;
761     if (cmdname && !pid_is_cmd(pid, cmdname))
762     return;
763     if (start && !pid_is_running(pid))
764     return;
765     push(&found, pid);
766     }
767    
768     static void
769     do_pidfile(const char *name)
770     {
771     FILE *f;
772     pid_t pid;
773    
774     f = fopen(name, "r");
775     if (f) {
776     if (fscanf(f, "%d", &pid) == 1)
777     check(pid);
778     fclose(f);
779     } else if (errno != ENOENT)
780     fatal("open pidfile %s: %s", name, strerror(errno));
781    
782     }
783    
784     /* WTA: this needs to be an autoconf check for /proc/pid existance.
785     */
786    
787     #if defined(OSLinux) || defined (OSsunos) || defined(OSfreebsd)
788     static void
789     do_procinit(void)
790     {
791     DIR *procdir;
792     struct dirent *entry;
793     int foundany;
794     pid_t pid;
795    
796     procdir = opendir("/proc");
797     if (!procdir)
798     fatal("opendir /proc: %s", strerror(errno));
799    
800     foundany = 0;
801     while ((entry = readdir(procdir)) != NULL) {
802     if (sscanf(entry->d_name, "%d", &pid) != 1)
803     continue;
804     foundany++;
805     check(pid);
806     }
807     closedir(procdir);
808     if (!foundany)
809     fatal("nothing in /proc - not mounted?");
810     }
811     #endif /* OSLinux */
812    
813    
814     #if defined(OSHURD)
815     static int
816     check_proc_stat (struct proc_stat *ps)
817     {
818     check(ps->pid);
819     return 0;
820     }
821    
822     static void
823     do_procinit(void)
824     {
825     if (!procset)
826     init_procset();
827    
828     proc_stat_list_for_each (procset, check_proc_stat);
829     }
830     #endif /* OSHURD */
831    
832    
833     #if defined(OSOpenBSD) || defined(OSFreeBSD) || defined(OSNetBSD)
834    
835     # if defined(OSNetBSD)
836     # define _KINFO_PROC2 kinfo_proc2
837     # define _GET_KINFO_UID(kp) (kp->p_ruid)
838     # define _GET_KINFO_COMM(kp) (kp->p_comm)
839     # else
840     # define _KINFO_PROC2 kinfo_proc
841     # define _GET_KINFO_UID(kp) (kp->ki_ruid)
842     # define _GET_KINFO_COMM(kp) (kp->ki_comm)
843     # endif
844    
845     static int
846     pid_is_cmd(pid_t pid, const char *name)
847     {
848     kvm_t *kd;
849     int nentries, argv_len=0;
850     struct kinfo_proc *kp;
851     char errbuf[_POSIX2_LINE_MAX], buf[_POSIX2_LINE_MAX];
852     char **pid_argv_p;
853     char *start_argv_0_p, *end_argv_0_p;
854    
855     kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
856     if (kd == 0)
857     errx(1, "%s", errbuf);
858     if ((kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries)) == 0)
859     errx(1, "%s", kvm_geterr(kd));
860     if ((pid_argv_p = kvm_getargv(kd, kp, argv_len)) == 0)
861     errx(1, "%s", kvm_geterr(kd));
862    
863     start_argv_0_p = *pid_argv_p;
864     /* find and compare string */
865    
866     /* find end of argv[0] then copy and cut of str there. */
867     if ((end_argv_0_p = strchr(*pid_argv_p, ' ')) == 0 )
868     /* There seems to be no space, so we have the command
869     * allready in its desired form. */
870     start_argv_0_p = *pid_argv_p;
871     else {
872     /* Tests indicate that this never happens, since
873     * kvm_getargv itselfe cuts of tailing stuff. This is
874     * not what the manpage says, however. */
875     strncpy(buf, *pid_argv_p, (end_argv_0_p - start_argv_0_p));
876     buf[(end_argv_0_p - start_argv_0_p) + 1] = '\0';
877     start_argv_0_p = buf;
878     }
879    
880     if (strlen(name) != strlen(start_argv_0_p))
881     return 0;
882     return (strcmp(name, start_argv_0_p) == 0) ? 1 : 0;
883     }
884    
885     static int
886     pid_is_user(pid_t pid, uid_t uid)
887     {
888     kvm_t *kd;
889     int nentries; /* Value not used */
890     uid_t proc_uid;
891     struct _KINFO_PROC2 *kp;
892     char errbuf[_POSIX2_LINE_MAX];
893    
894     kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
895     if (kd == 0)
896     errx(1, "%s", errbuf);
897     if ((kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries)) == 0)
898     errx(1, "%s", kvm_geterr(kd));
899     if (_GET_KINFO_UID(kp))
900     kvm_read(kd, (u_long)&(_GET_KINFO_UID(kp)),
901     &proc_uid, sizeof(uid_t));
902     else
903     return 0;
904     return (proc_uid == (uid_t)uid);
905     }
906    
907     static int
908     pid_is_exec(pid_t pid, const char *name)
909     {
910     kvm_t *kd;
911     int nentries;
912     struct _KINFO_PROC2 *kp;
913     char errbuf[_POSIX2_LINE_MAX], *pidexec;
914    
915     kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
916     if (kd == 0)
917     errx(1, "%s", errbuf);
918     if ((kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries)) == 0)
919     errx(1, "%s", kvm_geterr(kd));
920     pidexec = _GET_KINFO_COMM(kp);
921     if (strlen(name) != strlen(pidexec))
922     return 0;
923     return (strcmp(name, pidexec) == 0) ? 1 : 0;
924     }
925    
926    
927     static void
928     do_procinit(void)
929     {
930     /* Nothing to do */
931     }
932    
933     #endif /* OSOpenBSD */
934    
935     #if defined(OSDarwin)
936     int
937     pid_is_user(pid_t pid, uid_t uid)
938     {
939     int mib[4];
940     size_t size;
941     struct kinfo_proc ki;
942    
943     size = sizeof(ki);
944     mib[0] = CTL_KERN;
945     mib[1] = KERN_PROC;
946     mib[2] = KERN_PROC_PID;
947     mib[3] = pid;
948     if (sysctl(mib, 4, &ki, &size, NULL, 0) < 0)
949     errx(1, "%s", "Failure calling sysctl");
950     return (uid == ki.kp_eproc.e_pcred.p_ruid);
951     }
952    
953     static int
954     pid_is_cmd(pid_t pid, const char *name)
955     {
956     int mib[4];
957     size_t size;
958     struct kinfo_proc ki;
959    
960     size = sizeof(ki);
961     mib[0] = CTL_KERN;
962     mib[1] = KERN_PROC;
963     mib[2] = KERN_PROC_PID;
964     mib[3] = pid;
965     if (sysctl(mib, 4, &ki, &size, NULL, 0) < 0)
966     errx(1, "%s", "Failure calling sysctl");
967     return (!strncmp(name, ki.kp_proc.p_comm, MAXCOMLEN));
968     }
969    
970     static void
971     do_procinit(void)
972     {
973     int mib[3];
974     size_t size;
975     int nprocs, ret, i;
976     struct kinfo_proc *procs = NULL, *newprocs;
977    
978     mib[0] = CTL_KERN;
979     mib[1] = KERN_PROC;
980     mib[2] = KERN_PROC_ALL;
981     ret = sysctl(mib, 3, NULL, &size, NULL, 0);
982     /* Allocate enough memory for entire process table */
983     do {
984     size += size / 10;
985     newprocs = realloc(procs, size);
986     if (newprocs == NULL) {
987     if (procs)
988     free(procs);
989     errx(1, "%s", "Could not reallocate memory");
990     }
991     procs = newprocs;
992     ret = sysctl(mib, 3, procs, &size, NULL, 0);
993     } while (ret >= 0 && errno == ENOMEM);
994    
995     if (ret < 0)
996     errx(1, "%s", "Failure calling sysctl");
997    
998     /* Verify size of proc structure */
999     if (size % sizeof(struct kinfo_proc) != 0)
1000     errx(1, "%s", "proc size mismatch, userland out of sync with kernel");
1001     nprocs = size / sizeof(struct kinfo_proc);
1002     for (i = 0; i < nprocs; i++) {
1003     check(procs[i].kp_proc.p_pid);
1004     }
1005     }
1006     #endif /* OSDarwin */
1007    
1008     #if defined(OShpux)
1009     static int
1010     pid_is_user(pid_t pid, uid_t uid)
1011     {
1012     struct pst_status pst;
1013    
1014     if (pstat_getproc(&pst, sizeof(pst), (size_t) 0, (int) pid) < 0)
1015     return 0;
1016     return ((uid_t) pst.pst_uid == uid);
1017     }
1018    
1019     static int
1020     pid_is_cmd(pid_t pid, const char *name)
1021     {
1022     struct pst_status pst;
1023    
1024     if (pstat_getproc(&pst, sizeof(pst), (size_t) 0, (int) pid) < 0)
1025     return 0;
1026     return (strcmp(pst.pst_ucomm, name) == 0);
1027     }
1028    
1029     static int
1030     pid_is_exec(pid_t pid, const struct stat *esb)
1031     {
1032     struct pst_status pst;
1033    
1034     if (pstat_getproc(&pst, sizeof(pst), (size_t) 0, (int) pid) < 0)
1035     return 0;
1036     return ((dev_t) pst.pst_text.psf_fsid.psfs_id == esb->st_dev
1037     && (ino_t) pst.pst_text.psf_fileid == esb->st_ino);
1038     }
1039    
1040     static void
1041     do_procinit(void)
1042     {
1043     struct pst_status pst[10];
1044     int i, count;
1045     int idx = 0;
1046    
1047     while ((count = pstat_getproc(pst, sizeof(pst[0]), 10, idx)) > 0) {
1048     for (i = 0; i < count; i++)
1049     check(pst[i].pst_pid);
1050     idx = pst[count - 1].pst_idx + 1;
1051     }
1052     }
1053     #endif /* OShpux */
1054    
1055    
1056     static void
1057     do_findprocs(void)
1058     {
1059     clear(&found);
1060    
1061     if (pidfile)
1062     do_pidfile(pidfile);
1063     else
1064     do_procinit();
1065     }
1066    
1067     /* return 1 on failure */
1068     static void
1069     do_stop(int signal_nr, int quietmode, int *n_killed, int *n_notkilled, int retry_nr)
1070     {
1071     struct pid_list *p;
1072    
1073     do_findprocs();
1074    
1075     *n_killed = 0;
1076     *n_notkilled = 0;
1077    
1078     if (!found)
1079     return;
1080    
1081     clear(&killed);
1082    
1083     for (p = found; p; p = p->next) {
1084     if (testmode) {
1085     printf("Would send signal %d to %d.\n",
1086     signal_nr, p->pid);
1087     (*n_killed)++;
1088     } else if (kill(p->pid, signal_nr) == 0) {
1089     push(&killed, p->pid);
1090     (*n_killed)++;
1091     } else {
1092     printf("%s: warning: failed to kill %d: %s\n",
1093     progname, p->pid, strerror(errno));
1094     (*n_notkilled)++;
1095     }
1096     }
1097     if (quietmode < 0 && killed) {
1098     printf("Stopped %s (pid", what_stop);
1099     for (p = killed; p; p = p->next)
1100     printf(" %d", p->pid);
1101     putchar(')');
1102     if (retry_nr > 0)
1103     printf(", retry #%d", retry_nr);
1104     printf(".\n");
1105     }
1106     }
1107    
1108    
1109     static void
1110     set_what_stop(const char *str)
1111     {
1112     strncpy(what_stop, str, sizeof(what_stop));
1113     what_stop[sizeof(what_stop)-1] = '\0';
1114     }
1115    
1116     static int
1117     run_stop_schedule(void)
1118     {
1119     int r, position, n_killed, n_notkilled, value, ratio, anykilled, retry_nr;
1120     struct timeval stopat, before, after, interval, maxinterval;
1121    
1122     if (testmode) {
1123     if (schedule != NULL) {
1124     printf("Ignoring --retry in test mode\n");
1125     schedule = NULL;
1126     }
1127     }
1128    
1129     if (cmdname)
1130     set_what_stop(cmdname);
1131     else if (execname)
1132     set_what_stop(execname);
1133     else if (pidfile)
1134     sprintf(what_stop, "process in pidfile `%.200s'", pidfile);
1135     else if (userspec)
1136     sprintf(what_stop, "process(es) owned by `%.200s'", userspec);
1137     else
1138     fatal("internal error, please report");
1139    
1140     anykilled = 0;
1141     retry_nr = 0;
1142    
1143     if (schedule == NULL) {
1144     do_stop(signal_nr, quietmode, &n_killed, &n_notkilled, 0);
1145     if (n_notkilled > 0 && quietmode <= 0)
1146     printf("%d pids were not killed\n", n_notkilled);
1147     if (n_killed)
1148     anykilled = 1;
1149     goto x_finished;
1150     }
1151    
1152     for (position = 0; position < schedule_length; ) {
1153     value= schedule[position].value;
1154     n_notkilled = 0;
1155    
1156     switch (schedule[position].type) {
1157    
1158     case sched_goto:
1159     position = value;
1160     continue;
1161    
1162     case sched_signal:
1163     do_stop(value, quietmode, &n_killed, &n_notkilled, retry_nr++);
1164     if (!n_killed)
1165     goto x_finished;
1166     else
1167     anykilled = 1;
1168     goto next_item;
1169    
1170     case sched_timeout:
1171     /* We want to keep polling for the processes, to see if they've exited,
1172     * or until the timeout expires.
1173     *
1174     * This is a somewhat complicated algorithm to try to ensure that we
1175     * notice reasonably quickly when all the processes have exited, but
1176     * don't spend too much CPU time polling. In particular, on a fast
1177     * machine with quick-exiting daemons we don't want to delay system
1178     * shutdown too much, whereas on a slow one, or where processes are
1179     * taking some time to exit, we want to increase the polling
1180     * interval.
1181     *
1182     * The algorithm is as follows: we measure the elapsed time it takes
1183     * to do one poll(), and wait a multiple of this time for the next
1184     * poll. However, if that would put us past the end of the timeout
1185     * period we wait only as long as the timeout period, but in any case
1186     * we always wait at least MIN_POLL_INTERVAL (20ms). The multiple
1187     * (`ratio') starts out as 2, and increases by 1 for each poll to a
1188     * maximum of 10; so we use up to between 30% and 10% of the
1189     * machine's resources (assuming a few reasonable things about system
1190     * performance).
1191     */
1192     xgettimeofday(&stopat);
1193     stopat.tv_sec += value;
1194     ratio = 1;
1195     for (;;) {
1196     xgettimeofday(&before);
1197     if (timercmp(&before,&stopat,>))
1198     goto next_item;
1199    
1200     do_stop(0, 1, &n_killed, &n_notkilled, 0);
1201     if (!n_killed)
1202     goto x_finished;
1203    
1204     xgettimeofday(&after);
1205    
1206     if (!timercmp(&after,&stopat,<))
1207     goto next_item;
1208    
1209     if (ratio < 10)
1210     ratio++;
1211    
1212     TVCALC(interval, ratio * (TVELEM(&after) - TVELEM(&before) + TVADJUST));
1213     TVCALC(maxinterval, TVELEM(&stopat) - TVELEM(&after) + TVADJUST);
1214    
1215     if (timercmp(&interval,&maxinterval,>))
1216     interval = maxinterval;
1217    
1218     if (interval.tv_sec == 0 &&
1219     interval.tv_usec <= MIN_POLL_INTERVAL)
1220     interval.tv_usec = MIN_POLL_INTERVAL;
1221    
1222     r = select(0,0,0,0,&interval);
1223     if (r < 0 && errno != EINTR)
1224     fatal("select() failed for pause: %s",
1225     strerror(errno));
1226     }
1227    
1228     default:
1229     assert(!"schedule[].type value must be valid");
1230    
1231     }
1232    
1233     next_item:
1234     position++;
1235     }
1236    
1237     if (quietmode <= 0)
1238     printf("Program %s, %d process(es), refused to die.\n",
1239     what_stop, n_killed);
1240    
1241     return 2;
1242    
1243     x_finished:
1244     if (!anykilled) {
1245     if (quietmode <= 0)
1246     printf("No %s found running; none killed.\n", what_stop);
1247     return exitnodo;
1248     } else {
1249     return 0;
1250     }
1251     }
1252    
1253    
1254     int
1255     main(int argc, char **argv)
1256     {
1257     int devnull_fd = -1;
1258     #ifdef HAVE_TIOCNOTTY
1259     int tty_fd = -1;
1260     #endif
1261     progname = argv[0];
1262    
1263     parse_options(argc, argv);
1264     argc -= optind;
1265     argv += optind;
1266    
1267     if (changeroot == NULL) {
1268     if (execname && stat(execname, &exec_stat))
1269     fatal("stat %s: %s", execname, strerror(errno));
1270     } else {
1271     if (execname) {
1272     char *tmp = NULL;
1273    
1274     tmp = malloc(strlen(changeroot) + strlen(execname) + 1);
1275     strncpy(tmp, changeroot, strlen(changeroot));
1276     strncat(tmp, execname, strlen(execname));
1277    
1278     if (stat(tmp, &exec_stat)) {
1279     fatal("stat %s: %s", tmp, strerror(errno));
1280     free(tmp);
1281     } else {
1282     free(tmp);
1283     }
1284     }
1285     }
1286    
1287     if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
1288     struct passwd *pw;
1289    
1290     pw = getpwnam(userspec);
1291     if (!pw)
1292     fatal("user `%s' not found\n", userspec);
1293    
1294     user_id = pw->pw_uid;
1295     }
1296    
1297     if (changegroup && sscanf(changegroup, "%d", &runas_gid) != 1) {
1298     struct group *gr = getgrnam(changegroup);
1299     if (!gr)
1300     fatal("group `%s' not found\n", changegroup);
1301     runas_gid = gr->gr_gid;
1302     }
1303     if (changeuser && sscanf(changeuser, "%d", &runas_uid) != 1) {
1304     struct passwd *pw = getpwnam(changeuser);
1305     if (!pw)
1306     fatal("user `%s' not found\n", changeuser);
1307     runas_uid = pw->pw_uid;
1308     if (changegroup == NULL) { /* pass the default group of this user */
1309     changegroup = ""; /* just empty */
1310     runas_gid = pw->pw_gid;
1311     }
1312     }
1313    
1314     if (stop) {
1315     int i = run_stop_schedule();
1316     exit(i);
1317     }
1318    
1319     do_findprocs();
1320    
1321     if (found) {
1322     if (quietmode <= 0)
1323     printf("%s already running.\n", execname ? execname : "process");
1324     exit(exitnodo);
1325     }
1326     if (testmode) {
1327     printf("Would start %s ", startas);
1328     while (argc-- > 0)
1329     printf("%s ", *argv++);
1330     if (changeuser != NULL) {
1331     printf(" (as user %s[%d]", changeuser, runas_uid);
1332     if (changegroup != NULL)
1333     printf(", and group %s[%d])", changegroup, runas_gid);
1334     else
1335     printf(")");
1336     }
1337     if (changeroot != NULL)
1338     printf(" in directory %s", changeroot);
1339     if (nicelevel)
1340     printf(", and add %i to the priority", nicelevel);
1341     printf(".\n");
1342     exit(0);
1343     }
1344     if (quietmode < 0)
1345     printf("Starting %s...\n", startas);
1346     *--argv = startas;
1347     if (background) { /* ok, we need to detach this process */
1348     int i;
1349     if (quietmode < 0)
1350     printf("Detaching to start %s...", startas);
1351     i = fork();
1352     if (i<0) {
1353     fatal("Unable to fork.\n");
1354     }
1355     if (i) { /* parent */
1356     if (quietmode < 0)
1357     printf("done.\n");
1358     exit(0);
1359     }
1360     /* child continues here */
1361    
1362     #ifdef HAVE_TIOCNOTTY
1363     tty_fd=open("/dev/tty", O_RDWR);
1364     #endif
1365     devnull_fd=open("/dev/null", O_RDWR);
1366     }
1367     if (nicelevel) {
1368     errno=0;
1369     if ((nice(nicelevel)==-1) && (errno!=0))
1370     fatal("Unable to alter nice level by %i: %s", nicelevel,
1371     strerror(errno));
1372     }
1373     if (changeroot != NULL) {
1374     if (chdir(changeroot) < 0)
1375     fatal("Unable to chdir() to %s", changeroot);
1376     if (chroot(changeroot) < 0)
1377     fatal("Unable to chroot() to %s", changeroot);
1378     }
1379     if (chdir(changedir) < 0)
1380     fatal("Unable to chdir() to %s", changedir);
1381     if (mpidfile && pidfile != NULL) { /* user wants _us_ to make the pidfile :) */
1382     FILE *pidf = fopen(pidfile, "w");
1383     pid_t pidt = getpid();
1384     if (pidf == NULL)
1385     fatal("Unable to open pidfile `%s' for writing: %s", pidfile,
1386     strerror(errno));
1387     fprintf(pidf, "%d\n", pidt);
1388     fclose(pidf);
1389     }
1390     if (changeuser != NULL) {
1391     if (setgid(runas_gid))
1392     fatal("Unable to set gid to %d", runas_gid);
1393     if (initgroups(changeuser, runas_gid))
1394     fatal("Unable to set initgroups() with gid %d", runas_gid);
1395     if (setuid(runas_uid))
1396     fatal("Unable to set uid to %s", changeuser);
1397     }
1398     if (env != NULL) {
1399     if(putenv(env))
1400     fatal("Unable to set variable: %s", env);
1401     }
1402     if (background) { /* continue background setup */
1403     int i;
1404     #ifdef HAVE_TIOCNOTTY
1405     /* change tty */
1406     ioctl(tty_fd, TIOCNOTTY, 0);
1407     close(tty_fd);
1408     #endif
1409     umask(022); /* set a default for dumb programs */
1410     dup2(devnull_fd,0); /* stdin */
1411     dup2(devnull_fd,1); /* stdout */
1412     dup2(devnull_fd,2); /* stderr */
1413     #if defined(OShpux)
1414     /* now close all extra fds */
1415     for (i=sysconf(_SC_OPEN_MAX)-1; i>=3; --i) close(i);
1416     #else
1417     /* now close all extra fds */
1418     for (i=getdtablesize()-1; i>=3; --i) close(i);
1419     #endif
1420    
1421     /* create a new session */
1422     #ifdef HAVE_SETSID
1423     setsid();
1424     #else
1425     setpgid(0,0);
1426     #endif
1427     }
1428     execv(startas, argv);
1429     fatal("Unable to start %s: %s", startas, strerror(errno));
1430     }

  ViewVC Help
Powered by ViewVC 1.1.20