Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


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