00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083 #include "gw-config.h"
00084
00085 #if defined(linux)
00086 #define OSLinux
00087 #elif defined(__GNU__)
00088 #define OSHURD
00089 #elif defined(SunOS)
00090 #elif defined(__CYGWIN__)
00091 #elif defined(__FreeBSD__) || defined(__APPLE__)
00092 #define FreeBSD
00093 #else
00094 #error Unknown architecture - cannot build start-stop-daemon
00095 #endif
00096
00097 #ifdef HAVE_HURH_H
00098 #include <hurd.h>
00099 #endif
00100 #ifdef HAVE_PS_H
00101 #include <ps.h>
00102 #endif
00103
00104 #include <errno.h>
00105 #include <stdio.h>
00106 #include <stdlib.h>
00107 #include <string.h>
00108 #include <stdarg.h>
00109 #include <signal.h>
00110 #include <sys/stat.h>
00111 #include <dirent.h>
00112 #include <unistd.h>
00113 #if HAVE_GETOPT_H
00114 #include <getopt.h>
00115 #endif
00116 #include <unistd.h>
00117 #include <pwd.h>
00118 #include <grp.h>
00119 #include <sys/ioctl.h>
00120 #include <sys/types.h>
00121 #include <sys/termios.h>
00122 #include <fcntl.h>
00123
00124
00125
00126 #define _STRUCTURED_PROC 1
00127 #ifdef SunOS
00128 #include <sys/procfs.h>
00129 #endif
00130
00131
00132 #ifdef HAVE_ERROR_H
00133 #include <error.h>
00134 #endif
00135 #ifdef HURD_IHASH_H
00136 #include <hurd/ihash.h>
00137 #endif
00138
00139 static int testmode = 0;
00140 static int quietmode = 0;
00141 static int exitnodo = 1;
00142 static int start = 0;
00143 static int stop = 0;
00144 static int background = 0;
00145 static int mpidfile = 0;
00146 static int signal_nr = 15;
00147 static const char *signal_str = NULL;
00148 static int user_id = -1;
00149 static int runas_uid = -1;
00150 static int runas_gid = -1;
00151 static const char *userspec = NULL;
00152 static char *changeuser = NULL;
00153 static char *changegroup = NULL;
00154 static char *changeroot = NULL;
00155 static const char *cmdname = NULL;
00156 static char *execname = NULL;
00157 static char *startas = NULL;
00158 static const char *pidfile = NULL;
00159 static const char *progname = "";
00160
00161 static struct stat exec_stat;
00162 #if defined(OSHURD)
00163 static struct ps_context *context;
00164 static struct proc_stat_list *procset;
00165 #endif
00166
00167
00168 struct pid_list {
00169 struct pid_list *next;
00170 int pid;
00171 };
00172
00173 static struct pid_list *found = NULL;
00174 static struct pid_list *killed = NULL;
00175
00176 static void *xmalloc(int size);
00177 static void push(struct pid_list **list, int pid);
00178 static void do_help(void);
00179 static void parse_options(int argc, char * const *argv);
00180 #if defined(OSLinux) || defined(OSHURD) || defined(SunOS) || defined(FreeBSD)
00181 static int pid_is_user(int pid, int uid);
00182 static int pid_is_cmd(int pid, const char *name);
00183 #endif
00184 static void check(int pid);
00185 static void do_pidfile(const char *name);
00186 static int do_stop(void);
00187 #if defined(OSLinux)
00188 static int pid_is_exec(int pid, const struct stat *esb);
00189 #endif
00190 #if defined(OSHURD)
00191 static void do_psinit(void);
00192 #endif
00193
00194
00195 #ifdef __GNUC__
00196 static void fatal(const char *format, ...)
00197 __attribute__((noreturn, format(printf, 1, 2)));
00198 static void badusage(const char *msg)
00199 __attribute__((noreturn));
00200 #else
00201 static void fatal(const char *format, ...);
00202 static void badusage(const char *msg);
00203 #endif
00204
00205 static void
00206 fatal(const char *format, ...)
00207 {
00208 va_list arglist;
00209
00210 fprintf(stderr, "%s: ", progname);
00211 va_start(arglist, format);
00212 vfprintf(stderr, format, arglist);
00213 va_end(arglist);
00214 putc('\n', stderr);
00215 exit(2);
00216 }
00217
00218
00219 static void *
00220 xmalloc(int size)
00221 {
00222 void *ptr;
00223
00224 ptr = malloc(size);
00225 if (ptr)
00226 return ptr;
00227 fatal("malloc(%d) failed", size);
00228 }
00229
00230
00231 static void
00232 push(struct pid_list **list, int pid)
00233 {
00234 struct pid_list *p;
00235
00236 p = xmalloc(sizeof(*p));
00237 p->next = *list;
00238 p->pid = pid;
00239 *list = p;
00240 }
00241
00242
00243 static void
00244 do_help(void)
00245 {
00246
00247
00248
00249 #ifndef SunOS
00250
00251 printf("\
00252 start-stop-daemon for Debian GNU/Linux - small and fast C version written by\n\
00253 Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
00254 GW_VERSION "\n\
00255 \n\
00256 Usage:\n\
00257 start-stop-daemon -S|--start options ... -- arguments ...\n\
00258 start-stop-daemon -K|--stop options ...\n\
00259 start-stop-daemon -H|--help\n\
00260 start-stop-daemon -V|--version\n\
00261 \n\
00262 Options (at least one of --exec|--pidfile|--user is required):\n\
00263 -x|--exec <executable> program to start/check if it is running\n\
00264 -p|--pidfile <pid-file> pid file to check\n\
00265 -c|--chuid <name|uid[:group|gid]>\n\
00266 change to this user/group before starting process\n\
00267 -u|--user <username>|<uid> stop processes owned by this user\n\
00268 -n|--name <process-name> stop processes with this name\n\
00269 -s|--signal <signal> signal to send (default TERM)\n\
00270 -a|--startas <pathname> program to start (default is <executable>)\n\
00271 -b|--background force the process to detach\n\
00272 -m|--make-pidfile create the pidfile before starting\n\
00273 -t|--test test mode, don't do anything\n\
00274 -o|--oknodo exit status 0 (not 1) if nothing done\n\
00275 -q|--quiet be more quiet\n\
00276 -v|--verbose be more verbose\n\
00277 \n\
00278 Exit status: 0 = done 1 = nothing done (=> 0 if --oknodo) 2 = trouble\n");
00279
00280 #else
00281
00282 printf("\
00283 start-stop-daemon for Debian GNU/Linux - small and fast C version written by\n\
00284 Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
00285 GW_VERSION "\n\
00286 \n\
00287 Usage:\n\
00288 start-stop-daemon -S options ... -- arguments ...\n\
00289 start-stop-daemon -K options ...\n\
00290 start-stop-daemon -H\n\
00291 start-stop-daemon -V\n\
00292 \n\
00293 Options (at least one of --exec|--pidfile|--user is required):\n\
00294 -x <executable> program to start/check if it is running\n\
00295 -p <pid-file> pid file to check\n\
00296 -c <name|uid[:group|gid]> change to this user/group before starting process\n\
00297 -u <username>|<uid> stop processes owned by this user\n\
00298 -n <process-name> stop processes with this name\n\
00299 -s <signal> signal to send (default TERM)\n\
00300 -a <pathname> program to start (default is <executable>)\n\
00301 -b force the process to detach\n\
00302 -m create the pidfile before starting\n\
00303 -t test mode, don't do anything\n\
00304 -o exit status 0 (not 1) if nothing done\n\
00305 -q be more quiet\n\
00306 -v be more verbose\n\
00307 \n\
00308 Exit status: 0 = done 1 = nothing done (=> 0 if -o) 2 = trouble\n");
00309 #endif
00310 }
00311
00312
00313 static void
00314 badusage(const char *msg)
00315 {
00316 if (msg)
00317 fprintf(stderr, "%s: %s\n", progname, msg);
00318
00319 #ifndef SunOS
00320 fprintf(stderr, "Try `%s --help' for more information.\n", progname);
00321 #else
00322 fprintf(stderr, "Try `%s -H' for more information.\n", progname);
00323 #endif
00324
00325 exit(2);
00326 }
00327
00328 struct sigpair {
00329 const char *name;
00330 int signal;
00331 };
00332
00333 static const struct sigpair siglist[] = {
00334 { "ABRT", SIGABRT },
00335 { "ALRM", SIGALRM },
00336 { "FPE", SIGFPE },
00337 { "HUP", SIGHUP },
00338 { "ILL", SIGILL },
00339 { "INT", SIGINT },
00340 { "KILL", SIGKILL },
00341 { "PIPE", SIGPIPE },
00342 { "QUIT", SIGQUIT },
00343 { "SEGV", SIGSEGV },
00344 { "TERM", SIGTERM },
00345 { "USR1", SIGUSR1 },
00346 { "USR2", SIGUSR2 },
00347 { "CHLD", SIGCHLD },
00348 { "CONT", SIGCONT },
00349 { "STOP", SIGSTOP },
00350 { "TSTP", SIGTSTP },
00351 { "TTIN", SIGTTIN },
00352 { "TTOU", SIGTTOU }
00353 };
00354 static int sigcount = sizeof (siglist) / sizeof (siglist[0]);
00355
00356 static int parse_signal (const char *signal_str, int *signal_nr)
00357 {
00358 int i;
00359 for (i = 0; i < sigcount; i++) {
00360 if (strcmp (signal_str, siglist[i].name) == 0) {
00361 *signal_nr = siglist[i].signal;
00362 return 0;
00363 }
00364 }
00365 return -1;
00366 }
00367
00368 static void
00369 parse_options(int argc, char * const *argv)
00370 {
00371
00372 #if HAVE_GETOPT_LONG
00373 static struct option longopts[] = {
00374 { "help", 0, NULL, 'H'},
00375 { "stop", 0, NULL, 'K'},
00376 { "start", 0, NULL, 'S'},
00377 { "version", 0, NULL, 'V'},
00378 { "startas", 1, NULL, 'a'},
00379 { "name", 1, NULL, 'n'},
00380 { "oknodo", 0, NULL, 'o'},
00381 { "pidfile", 1, NULL, 'p'},
00382 { "quiet", 0, NULL, 'q'},
00383 { "signal", 1, NULL, 's'},
00384 { "test", 0, NULL, 't'},
00385 { "user", 1, NULL, 'u'},
00386 { "chroot", 1, NULL, 'r'},
00387 { "verbose", 0, NULL, 'v'},
00388 { "exec", 1, NULL, 'x'},
00389 { "chuid", 1, NULL, 'c'},
00390 { "background", 0, NULL, 'b'},
00391 { "make-pidfile", 0, NULL, 'm'},
00392 { NULL, 0, NULL, 0}
00393 };
00394 #endif
00395 int c;
00396
00397 for (;;) {
00398 #if HAVE_GETOPT_LONG
00399 c = getopt_long(argc, argv, "HKSVa:n:op:qr:s:tu:vx:c:bm",
00400 longopts, (int *) 0);
00401 #else
00402 c = getopt(argc, argv, "HKSVa:n:op:qr:s:tu:vx:c:bm");
00403 #endif
00404 if (c == -1)
00405 break;
00406 switch (c) {
00407 case 'H':
00408 do_help();
00409 exit(0);
00410 case 'K':
00411 stop = 1;
00412 break;
00413 case 'S':
00414 start = 1;
00415 break;
00416 case 'V':
00417 printf("start-stop-daemon " GW_VERSION "\n");
00418 exit(0);
00419 case 'a':
00420 startas = optarg;
00421 break;
00422 case 'n':
00423 cmdname = optarg;
00424 break;
00425 case 'o':
00426 exitnodo = 0;
00427 break;
00428 case 'p':
00429 pidfile = optarg;
00430 break;
00431 case 'q':
00432 quietmode = 1;
00433 break;
00434 case 's':
00435 signal_str = optarg;
00436 break;
00437 case 't':
00438 testmode = 1;
00439 break;
00440 case 'u':
00441 userspec = optarg;
00442 break;
00443 case 'v':
00444 quietmode = -1;
00445 break;
00446 case 'x':
00447 execname = optarg;
00448 break;
00449 case 'c':
00450
00451
00452 changeuser = strdup(optarg);
00453 changeuser = strtok(changeuser, ":");
00454 changegroup = strtok(NULL, ":");
00455 break;
00456 case 'r':
00457 changeroot = optarg;
00458 break;
00459 case 'b':
00460 background = 1;
00461 break;
00462 case 'm':
00463 mpidfile = 1;
00464 break;
00465 default:
00466 badusage(NULL);
00467 }
00468 }
00469
00470 if (signal_str != NULL) {
00471 if (sscanf (signal_str, "%d", &signal_nr) != 1) {
00472 if (parse_signal (signal_str, &signal_nr) != 0) {
00473 badusage ("--signal takes a numeric argument or name of signal (KILL, INTR, ...)");
00474 }
00475 }
00476 }
00477
00478 if (start == stop)
00479 #ifndef SunOS
00480 badusage("need one of --start or --stop");
00481 #else
00482 badusage("need one of -S (start) or -K (stop)");
00483 #endif
00484
00485 if (!execname && !pidfile && !userspec)
00486 badusage("need at least one of --exec, --pidfile or --user");
00487
00488 if (!startas)
00489 startas = execname;
00490
00491 if (start && !startas)
00492 badusage("--start needs --exec or --startas");
00493
00494 if (mpidfile && pidfile == NULL)
00495 badusage("--make-pidfile is only relevant with --pidfile");
00496
00497 if (background && !start)
00498 badusage("--background is only relevant with --start");
00499
00500 }
00501
00502 #if defined(OSLinux)
00503 static int
00504 pid_is_exec(int pid, const struct stat *esb)
00505 {
00506 struct stat sb;
00507 char buf[32];
00508
00509 sprintf(buf, "/proc/%d/exe", pid);
00510 if (stat(buf, &sb) != 0)
00511 return 0;
00512 return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
00513 }
00514
00515
00516 static int
00517 pid_is_user(int pid, int uid)
00518 {
00519 struct stat sb;
00520 char buf[32];
00521
00522 sprintf(buf, "/proc/%d", pid);
00523 if (stat(buf, &sb) != 0)
00524 return 0;
00525 return ((int) sb.st_uid == uid);
00526 }
00527
00528
00529 static int
00530 pid_is_cmd(int pid, const char *name)
00531 {
00532 char buf[32];
00533 FILE *f;
00534 int c;
00535
00536 sprintf(buf, "/proc/%d/stat", pid);
00537 f = fopen(buf, "r");
00538 if (!f)
00539 return 0;
00540 while ((c = getc(f)) != EOF && c != '(')
00541 ;
00542 if (c != '(') {
00543 fclose(f);
00544 return 0;
00545 }
00546
00547 while ((c = getc(f)) != EOF && c == *name)
00548 name++;
00549 fclose(f);
00550 return (c == ')' && *name == '\0');
00551 }
00552 #endif
00553
00554 #if defined(OSHURD)
00555 static int
00556 pid_is_user(int pid, int uid)
00557 {
00558 struct stat sb;
00559 char buf[32];
00560 struct proc_stat *pstat;
00561
00562 sprintf(buf, "/proc/%d", pid);
00563 if (stat(buf, &sb) != 0)
00564 return 0;
00565 return (sb.st_uid == uid);
00566 pstat = proc_stat_list_pid_proc_stat (procset, pid);
00567 if (pstat == NULL)
00568 fatal ("Error getting process information: NULL proc_stat struct");
00569 proc_stat_set_flags (pstat, PSTAT_PID | PSTAT_OWNER_UID);
00570 return (pstat->owner_uid == uid);
00571 }
00572
00573 static int
00574 pid_is_cmd(int pid, const char *name)
00575 {
00576 struct proc_stat *pstat;
00577 pstat = proc_stat_list_pid_proc_stat (procset, pid);
00578 if (pstat == NULL)
00579 fatal ("Error getting process information: NULL proc_stat struct");
00580 proc_stat_set_flags (pstat, PSTAT_PID | PSTAT_ARGS);
00581 return (!strcmp (name, pstat->args));
00582 }
00583 #endif
00584
00585 #if defined(SunOS)
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597 static int
00598 pid_is_user(int pid, int uid)
00599 {
00600 struct stat sb;
00601 char buf[32];
00602
00603 sprintf(buf, "/proc/%d", pid);
00604 if (stat(buf, &sb) != 0)
00605 return 0;
00606 return ((int) sb.st_uid == uid);
00607 }
00608
00609
00610
00611
00612
00613
00614 static int
00615 pid_is_cmd(int pid, const char *name)
00616 {
00617 char buf[32];
00618 FILE *f;
00619 psinfo_t pid_info;
00620
00621 sprintf(buf, "/proc/%d/psinfo", pid);
00622 f = fopen(buf, "r");
00623 if (!f)
00624 return 0;
00625 fread(&pid_info,sizeof(psinfo_t),1,f);
00626 return (!strcmp(name,pid_info.pr_fname));
00627 }
00628 #endif
00629
00630 #ifdef FreeBSD
00631 static int pid_is_user(int pid, int uid)
00632 {
00633 struct stat sb;
00634 char buf[32];
00635
00636 sprintf(buf, "/proc/%d", pid);
00637 if (stat(buf, &sb) != 0)
00638 return 0;
00639 return ((int) sb.st_uid == uid);
00640 }
00641
00642 static int
00643 pid_is_cmd(int pid, const char *name)
00644 {
00645 char buf[32];
00646 FILE *f;
00647 int c;
00648
00649 sprintf(buf, "/proc/%d/stat", pid);
00650 f = fopen(buf, "r");
00651 if (!f)
00652 return 0;
00653 while ((c = getc(f)) != EOF && c != '(')
00654 ;
00655 if (c != '(') {
00656 fclose(f);
00657 return 0;
00658 }
00659
00660 while ((c = getc(f)) != EOF && c == *name)
00661 name++;
00662 fclose(f);
00663 return (c == ')' && *name == '\0');
00664 }
00665 #endif
00666
00667 static void
00668 check(int pid)
00669 {
00670 #if defined(OSLinux)
00671 if (execname && !pid_is_exec(pid, &exec_stat))
00672 return;
00673 #elif defined(OSHURD)
00674
00675 if (execname && !pid_is_cmd(pid, execname))
00676 return;
00677 #endif
00678 if (userspec && !pid_is_user(pid, user_id))
00679 return;
00680 if (cmdname && !pid_is_cmd(pid, cmdname))
00681 return;
00682 push(&found, pid);
00683 }
00684
00685
00686 static void
00687 do_pidfile(const char *name)
00688 {
00689 FILE *f;
00690 int pid;
00691
00692 f = fopen(name, "r");
00693 if (f) {
00694 if (fscanf(f, "%d", &pid) == 1)
00695 check(pid);
00696 fclose(f);
00697 }
00698 }
00699
00700
00701
00702 #if defined(OSLinux) || defined (SunOS) || defined(FreeBSD)
00703 static void
00704 do_procinit(void)
00705 {
00706 DIR *procdir;
00707 struct dirent *entry;
00708 int foundany, pid;
00709
00710 procdir = opendir("/proc");
00711 if (!procdir)
00712 fatal("opendir /proc: %s", strerror(errno));
00713
00714 foundany = 0;
00715 while ((entry = readdir(procdir)) != NULL) {
00716 if (sscanf(entry->d_name, "%d", &pid) != 1)
00717 continue;
00718 foundany++;
00719 check(pid);
00720 }
00721 closedir(procdir);
00722 if (!foundany)
00723 fatal("nothing in /proc - not mounted?");
00724 }
00725 #endif
00726
00727
00728 #if defined(OSHURD)
00729 error_t
00730 check_all (void *ptr)
00731 {
00732 struct proc_stat *pstat = ptr;
00733
00734 check (pstat->pid);
00735 return (0);
00736 }
00737
00738 static void
00739 do_psinit(void)
00740 error_t err;
00741
00742 err = ps_context_create (getproc (), &context);
00743 if (err)
00744 error (1, err, "ps_context_create");
00745
00746 err = proc_stat_list_create (context, &procset);
00747 if (err)
00748 error (1, err, "proc_stat_list_create");
00749
00750 err = proc_stat_list_add_all (procset, 0, 0);
00751 if (err)
00752 error (1, err, "proc_stat_list_add_all");
00753
00754
00755 ihash_iterate (context->procs, check_all);
00756 }
00757 #endif
00758
00759
00760 static int
00761 do_stop(void)
00762 {
00763 char what[1024];
00764 struct pid_list *p;
00765 int retval = 0;
00766
00767 if (cmdname)
00768 strcpy(what, cmdname);
00769 else if (execname)
00770 strcpy(what, execname);
00771 else if (pidfile)
00772 sprintf(what, "process in pidfile `%s'", pidfile);
00773 else if (userspec)
00774 sprintf(what, "process(es) owned by `%s'", userspec);
00775 else
00776 fatal("internal error, please report");
00777
00778 if (!found) {
00779 if (quietmode <= 0)
00780 printf("No %s found running; none killed.\n", what);
00781 exit(exitnodo);
00782 }
00783 for (p = found; p; p = p->next) {
00784 if (testmode)
00785 printf("Would send signal %d to %d.\n",
00786 signal_nr, p->pid);
00787 else if (kill(p->pid, signal_nr) == 0)
00788 push(&killed, p->pid);
00789 else {
00790 printf("%s: warning: failed to kill %d: %s\n",
00791 progname, p->pid, strerror(errno));
00792 retval += exitnodo;
00793 }
00794 }
00795 if (quietmode < 0 && killed) {
00796 printf("Stopped %s (pid", what);
00797 for (p = killed; p; p = p->next)
00798 printf(" %d", p->pid);
00799 printf(").\n");
00800 }
00801 return retval;
00802 }
00803
00804
00805 int
00806 main(int argc, char **argv)
00807 {
00808 progname = argv[0];
00809
00810 parse_options(argc, argv);
00811 argc -= optind;
00812 argv += optind;
00813
00814 if (execname && stat(execname, &exec_stat))
00815 fatal("stat %s: %s", execname, strerror(errno));
00816
00817 if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
00818 struct passwd *pw;
00819
00820 pw = getpwnam(userspec);
00821 if (!pw)
00822 fatal("user `%s' not found\n", userspec);
00823
00824 user_id = pw->pw_uid;
00825 }
00826
00827 if (changegroup && sscanf(changegroup, "%d", &runas_gid) != 1) {
00828 struct group *gr = getgrnam(changegroup);
00829 if (!gr)
00830 fatal("group `%s' not found\n", changegroup);
00831 runas_gid = gr->gr_gid;
00832 }
00833 if (changeuser && sscanf(changeuser, "%d", &runas_uid) != 1) {
00834 struct passwd *pw = getpwnam(changeuser);
00835 if (!pw)
00836 fatal("user `%s' not found\n", changeuser);
00837 runas_uid = pw->pw_uid;
00838 if (changegroup == NULL) {
00839 changegroup = "";
00840 runas_gid = pw->pw_gid;
00841 }
00842 }
00843
00844 if (pidfile)
00845 do_pidfile(pidfile);
00846 else
00847 do_procinit();
00848
00849 if (stop) {
00850 int i = do_stop();
00851 if (i) {
00852 if (quietmode <= 0)
00853 printf("%d pids were not killed\n", i);
00854 exit(1);
00855 }
00856 exit(0);
00857 }
00858
00859 if (found) {
00860 if (quietmode <= 0)
00861 printf("%s already running.\n", execname);
00862 exit(exitnodo);
00863 }
00864 if (testmode) {
00865 printf("Would start %s ", startas);
00866 while (argc-- > 0)
00867 printf("%s ", *argv++);
00868 if (changeuser != NULL) {
00869 printf(" (as user %s[%d]", changeuser, runas_uid);
00870 if (changegroup != NULL)
00871 printf(", and group %s[%d])", changegroup, runas_gid);
00872 else
00873 printf(")");
00874 }
00875 if (changeroot != NULL)
00876 printf(" in directory %s", changeroot);
00877 printf(".\n");
00878 exit(0);
00879 }
00880 if (quietmode < 0)
00881 printf("Starting %s...\n", startas);
00882 *--argv = startas;
00883 if (changeroot != NULL) {
00884 if (chdir(changeroot) < 0)
00885 fatal("Unable to chdir() to %s", changeroot);
00886 if (chroot(changeroot) < 0)
00887 fatal("Unable to chroot() to %s", changeroot);
00888 }
00889 if (changeuser != NULL) {
00890 if (setgid(runas_gid))
00891 fatal("Unable to set gid to %d", runas_gid);
00892 if (initgroups(changeuser, runas_gid))
00893 fatal("Unable to set initgroups() with gid %d", runas_gid);
00894 if (setuid(runas_uid))
00895 fatal("Unable to set uid to %s", changeuser);
00896 }
00897
00898 if (background) {
00899 int i, fd;
00900 if (quietmode < 0)
00901 printf("Detatching to start %s...", startas);
00902 i = fork();
00903 if (i<0) {
00904 fatal("Unable to fork.\n");
00905 }
00906 if (i) {
00907 if (quietmode < 0)
00908 printf("done.\n");
00909 exit(0);
00910 }
00911
00912
00913 for (i=getdtablesize()-1; i>=0; --i) close(i);
00914
00915 fd = open("/dev/tty", O_RDWR);
00916 ioctl(fd, TIOCNOTTY, 0);
00917 close(fd);
00918 chdir("/");
00919 umask(022);
00920 #ifndef FreeBSD
00921 setpgrp();
00922 #else
00923 setpgrp(0, runas_gid);
00924 #endif
00925 fd=open("/dev/null", O_RDWR);
00926 dup(fd);
00927 dup(fd);
00928 }
00929 if (mpidfile && pidfile != NULL) {
00930 FILE *pidf = fopen(pidfile, "w");
00931 pid_t pidt = getpid();
00932 if (pidf == NULL)
00933 fatal("Unable to open pidfile `%s' for writing: %s", pidfile,
00934 strerror(errno));
00935 fprintf(pidf, "%d\n", (int)pidt);
00936 fclose(pidf);
00937 }
00938 execv(startas, argv);
00939 fatal("Unable to start %s: %s", startas, strerror(errno));
00940 }
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.