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