Magellan Linux

Contents of /tags/init-0_6_0/src/start-stop-daemon.c

Parent Directory Parent Directory | Revision Log Revision Log


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