/[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 1711 - (hide annotations) (download) (as text)
Sun Jun 5 18:54:44 2011 UTC (2 years, 10 months ago) by maksbotan
File MIME type: text/x-csrc
File size: 36643 byte(s)
Fix baselayout-prefix on OpenBSD (kinfo_proc error)

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

  ViewVC Help
Powered by ViewVC 1.1.20