/[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 1687 - (show annotations) (download) (as text)
Thu Mar 31 14:12:21 2011 UTC (3 years, 3 months ago) by grobian
File MIME type: text/x-csrc
File size: 35016 byte(s)
applied baselayout-1.12.5-termios_h.patch

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

  ViewVC Help
Powered by ViewVC 1.1.20