/[gentoo-alt]/trunk/baselayout-prefix/src/start-stop-daemon.c
Gentoo

Contents of /trunk/baselayout-prefix/src/start-stop-daemon.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1711 - (show annotations) (download) (as text)
Sun Jun 5 18:54:44 2011 UTC (3 years, 4 months ago) by maksbotan
File MIME type: text/x-csrc
File size: 36643 byte(s)
Fix baselayout-prefix on OpenBSD (kinfo_proc error)

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

  ViewVC Help
Powered by ViewVC 1.1.20