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

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

  ViewVC Help
Powered by ViewVC 1.1.20