/[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 - (show annotations) (download) (as text)
Thu Mar 31 14:11:17 2011 UTC (4 years ago) by grobian
File MIME type: text/x-csrc
File size: 34874 byte(s)
Add original code base from baselayout-1.12.5
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 *
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