start-stop-daemon.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:21k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /* This utility was added to the Kannel source tree for the benefit of
  2.  * those distributions that aren't Debian.  It is used by kannel-init.d
  3.  * to start and stop the run_kannel_box daemon. 
  4.  * It was copied from the dpkg 1.6.11 source tree on 21 March 2000.
  5.  * If that was very long ago, refreshing the copy would be a good idea,
  6.  * in case bugs were fixed.
  7.  * Richard Braakman
  8.  */
  9. /*
  10.  * A rewrite of the original Debian's start-stop-daemon Perl script
  11.  * in C (faster - it is executed many times during system startup).
  12.  *
  13.  * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
  14.  * public domain.  Based conceptually on start-stop-daemon.pl, by Ian
  15.  * Jackson <ijackson@gnu.ai.mit.edu>.  May be used and distributed
  16.  * freely for any purpose.  Changes by Christian Schwarz
  17.  * <schwarz@monet.m.isar.de>, to make output conform to the Debian
  18.  * Console Message Standard, also placed in public domain.  Minor
  19.  * changes by Klee Dienes <klee@debian.org>, also placed in the Public
  20.  * Domain.
  21.  *
  22.  * Changes by Ben Collins <bcollins@debian.org>, added --chuid, --background
  23.  * and --make-pidfile options, placed in public domain aswell.
  24.  */
  25. #include "config.h"
  26. #if defined(linux)
  27. #define OSLinux
  28. #elif defined(__GNU__)
  29. #define OSHURD
  30. #elif defined(SunOS)
  31. #elif defined(__FreeBSD__) || defined(__APPLE__)
  32. #define FreeBSD
  33. #else
  34. #error Unknown architecture - cannot build start-stop-daemon
  35. #endif
  36. #ifdef HAVE_HURH_H
  37. #include <hurd.h>
  38. #endif
  39. #ifdef HAVE_PS_H
  40. #include <ps.h>
  41. #endif
  42. #include <errno.h>
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <stdarg.h>
  47. #include <signal.h>
  48. #include <sys/stat.h>
  49. #include <dirent.h>
  50. #include <unistd.h>
  51. #if HAVE_GETOPT_H
  52. #include <getopt.h>
  53. #endif
  54. #include <unistd.h>
  55. #include <pwd.h>
  56. #include <grp.h>
  57. #include <sys/ioctl.h>
  58. #include <sys/types.h>
  59. #include <sys/termios.h>
  60. #include <fcntl.h>
  61. /*Solaris needs to be told how
  62. to talk to it's proc filesystem*/
  63. #define _STRUCTURED_PROC 1
  64. #ifdef SunOS
  65. #include <sys/procfs.h>
  66. #endif
  67. #ifdef HAVE_ERROR_H
  68. #include <error.h>
  69. #endif
  70. #ifdef HURD_IHASH_H
  71. #include <hurd/ihash.h>
  72. #endif
  73. static int testmode = 0;
  74. static int quietmode = 0;
  75. static int exitnodo = 1;
  76. static int start = 0;
  77. static int stop = 0;
  78. static int background = 0;
  79. static int mpidfile = 0;
  80. static int signal_nr = 15;
  81. static const char *signal_str = NULL;
  82. static int user_id = -1;
  83. static int runas_uid = -1;
  84. static int runas_gid = -1;
  85. static const char *userspec = NULL;
  86. static char *changeuser = NULL;
  87. static char *changegroup = NULL;
  88. static char *changeroot = NULL;
  89. static const char *cmdname = NULL;
  90. static char *execname = NULL;
  91. static char *startas = NULL;
  92. static const char *pidfile = NULL;
  93. static const char *progname = "";
  94. static struct stat exec_stat;
  95. #if defined(OSHURD)
  96. static struct ps_context *context;
  97. static struct proc_stat_list *procset;
  98. #endif
  99. struct pid_list {
  100. struct pid_list *next;
  101. int pid;
  102. };
  103. static struct pid_list *found = NULL;
  104. static struct pid_list *killed = NULL;
  105. static void *xmalloc(int size);
  106. static void push(struct pid_list **list, int pid);
  107. static void do_help(void);
  108. static void parse_options(int argc, char * const *argv);
  109. #if defined(OSLinux) || defined(OSHURD) || defined(SunOS) || defined(FreeBSD)
  110. static int pid_is_user(int pid, int uid);
  111. static int pid_is_cmd(int pid, const char *name);
  112. #endif
  113. static void check(int pid);
  114. static void do_pidfile(const char *name);
  115. static int do_stop(void);
  116. #if defined(OSLinux)
  117. static int pid_is_exec(int pid, const struct stat *esb);
  118. #endif
  119. #if defined(OSHURD)
  120. static void do_psinit(void);
  121. #endif
  122. #ifdef __GNUC__
  123. static void fatal(const char *format, ...)
  124. __attribute__((noreturn, format(printf, 1, 2)));
  125. static void badusage(const char *msg)
  126. __attribute__((noreturn));
  127. #else
  128. static void fatal(const char *format, ...);
  129. static void badusage(const char *msg);
  130. #endif
  131. static void
  132. fatal(const char *format, ...)
  133. {
  134. va_list arglist;
  135. fprintf(stderr, "%s: ", progname);
  136. va_start(arglist, format);
  137. vfprintf(stderr, format, arglist);
  138. va_end(arglist);
  139. putc('n', stderr);
  140. exit(2);
  141. }
  142. static void *
  143. xmalloc(int size)
  144. {
  145. void *ptr;
  146. ptr = malloc(size);
  147. if (ptr)
  148. return ptr;
  149. fatal("malloc(%d) failed", size);
  150. }
  151. static void
  152. push(struct pid_list **list, int pid)
  153. {
  154. struct pid_list *p;
  155. p = xmalloc(sizeof(*p));
  156. p->next = *list;
  157. p->pid = pid;
  158. *list = p;
  159. }
  160. static void
  161. do_help(void)
  162. {
  163. /*Print the help for systems that have getopt long*/
  164. #ifndef SunOS     /*Solaris doesn't*/
  165. printf("
  166. start-stop-daemon for Debian GNU/Linux - small and fast C version written byn
  167. Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.n"
  168. VERSION "n
  169. n
  170. Usage:n
  171.   start-stop-daemon -S|--start options ... -- arguments ...n
  172.   start-stop-daemon -K|--stop options ...n
  173.   start-stop-daemon -H|--helpn
  174.   start-stop-daemon -V|--versionn
  175. n
  176. Options (at least one of --exec|--pidfile|--user is required):n
  177.   -x|--exec <executable>        program to start/check if it is runningn
  178.   -p|--pidfile <pid-file>       pid file to checkn
  179.   -c|--chuid <name|uid[:group|gid]>n
  180.    change to this user/group before starting processn
  181.   -u|--user <username>|<uid>    stop processes owned by this usern
  182.   -n|--name <process-name>      stop processes with this namen
  183.   -s|--signal <signal>          signal to send (default TERM)n
  184.   -a|--startas <pathname>       program to start (default is <executable>)n
  185.   -b|--background               force the process to detachn
  186.   -m|--make-pidfile             create the pidfile before startingn
  187.   -t|--test                     test mode, don't do anythingn
  188.   -o|--oknodo                   exit status 0 (not 1) if nothing donen
  189.   -q|--quiet                    be more quietn
  190.   -v|--verbose                  be more verbosen
  191. n
  192. Exit status:  0 = done  1 = nothing done (=> 0 if --oknodo)  2 = troublen");
  193. #else /* Deal with systems that don't have getopt long, like Solaris*/
  194. printf("
  195. start-stop-daemon for Debian GNU/Linux - small and fast C version written byn
  196. Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.n"
  197. VERSION "n
  198. n
  199. Usage:n
  200.   start-stop-daemon -S options ... -- arguments ...n
  201.   start-stop-daemon -K options ...n
  202.   start-stop-daemon -Hn
  203.   start-stop-daemon -Vn
  204. n
  205. Options (at least one of --exec|--pidfile|--user is required):n
  206.   -x <executable>               program to start/check if it is runningn
  207.   -p <pid-file>                 pid file to checkn
  208.   -c <name|uid[:group|gid]>     change to this user/group before starting processn
  209.   -u <username>|<uid>           stop processes owned by this usern
  210.   -n <process-name>             stop processes with this namen
  211.   -s <signal>                   signal to send (default TERM)n
  212.   -a <pathname>                 program to start (default is <executable>)n
  213.   -b                            force the process to detachn
  214.   -m                            create the pidfile before startingn
  215.   -t                            test mode, don't do anythingn
  216.   -o                            exit status 0 (not 1) if nothing donen
  217.   -q                            be more quietn
  218.   -v                            be more verbosen
  219. n
  220. Exit status:  0 = done  1 = nothing done (=> 0 if -o)  2 = troublen");
  221. #endif   /*No more OS ( getopt ) specific stuff this function... */
  222. }
  223. static void
  224. badusage(const char *msg)
  225. {
  226. if (msg)
  227. fprintf(stderr, "%s: %sn", progname, msg);
  228. #ifndef SunOS
  229. fprintf(stderr, "Try `%s --help' for more information.n", progname);
  230. #else
  231. fprintf(stderr, "Try `%s -H' for more information.n", progname);
  232. #endif
  233. exit(2);
  234. }
  235. struct sigpair {
  236. const char *name;
  237. int signal;
  238. };
  239. static const struct sigpair siglist[] = {
  240. { "ABRT", SIGABRT },
  241. { "ALRM", SIGALRM },
  242. { "FPE", SIGFPE },
  243. { "HUP", SIGHUP },
  244. { "ILL", SIGILL },
  245. { "INT", SIGINT },
  246. { "KILL", SIGKILL },
  247. { "PIPE", SIGPIPE },
  248. { "QUIT", SIGQUIT },
  249. { "SEGV", SIGSEGV },
  250. { "TERM", SIGTERM },
  251. { "USR1", SIGUSR1 },
  252. { "USR2", SIGUSR2 },
  253. { "CHLD", SIGCHLD },
  254. { "CONT", SIGCONT },
  255. { "STOP", SIGSTOP },
  256. { "TSTP", SIGTSTP },
  257. { "TTIN", SIGTTIN },
  258. { "TTOU", SIGTTOU }
  259. };
  260. static int sigcount = sizeof (siglist) / sizeof (siglist[0]);
  261. static int parse_signal (const char *signal_str, int *signal_nr)
  262. {
  263. int i;
  264. for (i = 0; i < sigcount; i++) {
  265. if (strcmp (signal_str, siglist[i].name) == 0) {
  266. *signal_nr = siglist[i].signal;
  267. return 0;
  268. }
  269. }
  270. return -1;
  271. }
  272. static void
  273. parse_options(int argc, char * const *argv)
  274. {
  275. #if HAVE_GETOPT_LONG
  276. static struct option longopts[] = {
  277. { "help",   0, NULL, 'H'},
  278. { "stop",   0, NULL, 'K'},
  279. { "start",   0, NULL, 'S'},
  280. { "version",   0, NULL, 'V'},
  281. { "startas",   1, NULL, 'a'},
  282. { "name",   1, NULL, 'n'},
  283. { "oknodo",   0, NULL, 'o'},
  284. { "pidfile",   1, NULL, 'p'},
  285. { "quiet",   0, NULL, 'q'},
  286. { "signal",   1, NULL, 's'},
  287. { "test",   0, NULL, 't'},
  288. { "user",   1, NULL, 'u'},
  289. { "chroot",   1, NULL, 'r'},
  290. { "verbose",   0, NULL, 'v'},
  291. { "exec",   1, NULL, 'x'},
  292. { "chuid",   1, NULL, 'c'},
  293. { "background",   0, NULL, 'b'},
  294. { "make-pidfile", 0, NULL, 'm'},
  295. { NULL, 0, NULL, 0}
  296. };
  297. #endif
  298. int c;
  299. for (;;) {
  300. #if HAVE_GETOPT_LONG
  301. c = getopt_long(argc, argv, "HKSVa:n:op:qr:s:tu:vx:c:bm",
  302. longopts, (int *) 0);
  303. #else
  304. c = getopt(argc, argv, "HKSVa:n:op:qr:s:tu:vx:c:bm");
  305. #endif
  306. if (c == -1)
  307. break;
  308. switch (c) {
  309. case 'H':  /* --help */
  310. do_help();
  311. exit(0);
  312. case 'K':  /* --stop */
  313. stop = 1;
  314. break;
  315. case 'S':  /* --start */
  316. start = 1;
  317. break;
  318. case 'V':  /* --version */
  319. printf("start-stop-daemon " VERSION "n");
  320. exit(0);
  321. case 'a':  /* --startas <pathname> */
  322. startas = optarg;
  323. break;
  324. case 'n':  /* --name <process-name> */
  325. cmdname = optarg;
  326. break;
  327. case 'o':  /* --oknodo */
  328. exitnodo = 0;
  329. break;
  330. case 'p':  /* --pidfile <pid-file> */
  331. pidfile = optarg;
  332. break;
  333. case 'q':  /* --quiet */
  334. quietmode = 1;
  335. break;
  336. case 's':  /* --signal <signal> */
  337. signal_str = optarg;
  338. break;
  339. case 't':  /* --test */
  340. testmode = 1;
  341. break;
  342. case 'u':  /* --user <username>|<uid> */
  343. userspec = optarg;
  344. break;
  345. case 'v':  /* --verbose */
  346. quietmode = -1;
  347. break;
  348. case 'x':  /* --exec <executable> */
  349. execname = optarg;
  350. break;
  351. case 'c':  /* --chuid <username>|<uid> */
  352. /* we copy the string just in case we need the
  353.  * argument later. */
  354. changeuser = strdup(optarg);
  355. changeuser = strtok(changeuser, ":");
  356. changegroup = strtok(NULL, ":");
  357. break;
  358. case 'r':  /* --chroot /new/root */
  359. changeroot = optarg;
  360. break;
  361. case 'b':  /* --background */
  362. background = 1;
  363. break;
  364. case 'm':  /* --make-pidfile */
  365. mpidfile = 1;
  366. break;
  367. default:
  368. badusage(NULL);  /* message printed by getopt */
  369. }
  370. }
  371. if (signal_str != NULL) {
  372. if (sscanf (signal_str, "%d", &signal_nr) != 1) {
  373. if (parse_signal (signal_str, &signal_nr) != 0) {
  374. badusage ("--signal takes a numeric argument or name of signal (KILL, INTR, ...)");
  375. }
  376. }
  377. }
  378. if (start == stop)
  379. #ifndef SunOS
  380. badusage("need one of --start or --stop");
  381. #else
  382. badusage("need one of -S (start) or -K (stop)");
  383. #endif
  384. if (!execname && !pidfile && !userspec)
  385. badusage("need at least one of --exec, --pidfile or --user");
  386. if (!startas)
  387. startas = execname;
  388. if (start && !startas)
  389. badusage("--start needs --exec or --startas");
  390. if (mpidfile && pidfile == NULL)
  391. badusage("--make-pidfile is only relevant with --pidfile");
  392. if (background && !start)
  393. badusage("--background is only relevant with --start");
  394. }
  395. #if defined(OSLinux)
  396. static int
  397. pid_is_exec(int pid, const struct stat *esb)
  398. {
  399. struct stat sb;
  400. char buf[32];
  401. sprintf(buf, "/proc/%d/exe", pid);
  402. if (stat(buf, &sb) != 0)
  403. return 0;
  404. return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
  405. }
  406. static int
  407. pid_is_user(int pid, int uid)
  408. {
  409. struct stat sb;
  410. char buf[32];
  411. sprintf(buf, "/proc/%d", pid);
  412. if (stat(buf, &sb) != 0)
  413. return 0;
  414. return ((int) sb.st_uid == uid);
  415. }
  416. static int
  417. pid_is_cmd(int pid, const char *name)
  418. {
  419. char buf[32];
  420. FILE *f;
  421. int c;
  422. sprintf(buf, "/proc/%d/stat", pid);
  423. f = fopen(buf, "r");
  424. if (!f)
  425. return 0;
  426. while ((c = getc(f)) != EOF && c != '(')
  427. ;
  428. if (c != '(') {
  429. fclose(f);
  430. return 0;
  431. }
  432. /* this hopefully handles command names containing ')' */
  433. while ((c = getc(f)) != EOF && c == *name)
  434. name++;
  435. fclose(f);
  436. return (c == ')' && *name == '');
  437. }
  438. #endif /* OSLinux */
  439. #if defined(OSHURD)
  440. static int
  441. pid_is_user(int pid, int uid)
  442. {
  443.    struct stat sb;
  444.    char buf[32];
  445.    struct proc_stat *pstat;
  446.    sprintf(buf, "/proc/%d", pid);
  447.    if (stat(buf, &sb) != 0)
  448.        return 0;
  449.    return (sb.st_uid == uid);
  450.    pstat = proc_stat_list_pid_proc_stat (procset, pid);
  451.    if (pstat == NULL)
  452.        fatal ("Error getting process information: NULL proc_stat struct");
  453.    proc_stat_set_flags (pstat, PSTAT_PID | PSTAT_OWNER_UID);
  454.    return (pstat->owner_uid == uid);
  455. }
  456. static int
  457. pid_is_cmd(int pid, const char *name)
  458. {
  459.    struct proc_stat *pstat;
  460.    pstat = proc_stat_list_pid_proc_stat (procset, pid);
  461.    if (pstat == NULL)
  462.        fatal ("Error getting process information: NULL proc_stat struct");
  463.    proc_stat_set_flags (pstat, PSTAT_PID | PSTAT_ARGS);
  464.    return (!strcmp (name, pstat->args));
  465. }
  466. #endif /* OSHURD */
  467. #if defined(SunOS)
  468. /*
  469. Lots of lovely system dependant functions for Solaris.  I used to like the
  470. idea of proc, but now I'm not so sure.  It feels to much like a kludge.
  471. */
  472. /*
  473. pid_is_user, takes the pid and a uid, normally ours, but can be someone
  474. elses, to allow you to identify the process' owner. returns zero on success,
  475. and either true or the uid of the owner on failure (this may be undefined,
  476. or I may be misremembering.
  477. */
  478. static int
  479. pid_is_user(int pid, int uid)
  480. {
  481.    struct stat sb;
  482.    char buf[32];
  483.    sprintf(buf, "/proc/%d", pid);
  484.    if (stat(buf, &sb) != 0)
  485.       return 0; /*I can stat it so it seems to be mine...*/
  486.    return ((int) sb.st_uid == uid);
  487. }
  488. /*
  489. pid_is_cmd, takes a pid, and a string representing the process' (supposed)
  490. name.  Compares the process' supposed name with the name reported by the
  491. system.  Returns zero on failure, and nonzero on success.
  492. */
  493. static int
  494. pid_is_cmd(int pid, const char *name)
  495. {
  496.    char buf[32];
  497.    FILE *f;
  498.    psinfo_t pid_info;
  499.    sprintf(buf, "/proc/%d/psinfo", pid);
  500.    f = fopen(buf, "r");
  501.    if (!f)
  502.       return 0;
  503.    fread(&pid_info,sizeof(psinfo_t),1,f);
  504.    return (!strcmp(name,pid_info.pr_fname));
  505. }
  506. #endif /*SunOS*/
  507. #ifdef FreeBSD
  508. static int pid_is_user(int pid, int uid)
  509. {
  510.  struct stat sb;
  511.  char buf[32];
  512.  sprintf(buf, "/proc/%d", pid);
  513.  if (stat(buf, &sb) != 0)
  514.   return 0;
  515.  return ((int) sb.st_uid == uid);
  516. }
  517. static int
  518. pid_is_cmd(int pid, const char *name)
  519. {
  520. char buf[32];
  521. FILE *f;
  522. int c;
  523. sprintf(buf, "/proc/%d/stat", pid);
  524. f = fopen(buf, "r");
  525. if (!f)
  526. return 0;
  527. while ((c = getc(f)) != EOF && c != '(')
  528. ;
  529. if (c != '(') {
  530. fclose(f);
  531. return 0;
  532. }
  533. /* this hopefully handles command names containing ')' */
  534. while ((c = getc(f)) != EOF && c == *name)
  535. name++;
  536. fclose(f);
  537. return (c == ')' && *name == '');
  538. }
  539. #endif /*FreeBSD*/
  540. static void
  541. check(int pid)
  542. {
  543. #if defined(OSLinux)
  544. if (execname && !pid_is_exec(pid, &exec_stat))
  545. #elif defined(OSHURD)
  546.     /* I will try this to see if it works */
  547. if (execname && !pid_is_cmd(pid, execname))
  548. #endif
  549. return;
  550. if (userspec && !pid_is_user(pid, user_id))
  551. return;
  552. if (cmdname && !pid_is_cmd(pid, cmdname))
  553. return;
  554. push(&found, pid);
  555. }
  556. static void
  557. do_pidfile(const char *name)
  558. {
  559. FILE *f;
  560. int pid;
  561. f = fopen(name, "r");
  562. if (f) {
  563. if (fscanf(f, "%d", &pid) == 1)
  564. check(pid);
  565. fclose(f);
  566. }
  567. }
  568. /* WTA: this  needs to be an autoconf check for /proc/pid existance.
  569.  */
  570. #if defined(OSLinux) || defined (SunOS) || defined(FreeBSD)
  571. static void
  572. do_procinit(void)
  573. {
  574. DIR *procdir;
  575. struct dirent *entry;
  576. int foundany, pid;
  577. procdir = opendir("/proc");
  578. if (!procdir)
  579. fatal("opendir /proc: %s", strerror(errno));
  580. foundany = 0;
  581. while ((entry = readdir(procdir)) != NULL) {
  582. if (sscanf(entry->d_name, "%d", &pid) != 1)
  583. continue;
  584. foundany++;
  585. check(pid);
  586. }
  587. closedir(procdir);
  588. if (!foundany)
  589. fatal("nothing in /proc - not mounted?");
  590. }
  591. #endif /* OSLinux */
  592. #if defined(OSHURD)
  593. error_t
  594. check_all (void *ptr)
  595. {
  596.    struct proc_stat *pstat = ptr;
  597.    check (pstat->pid);
  598.    return (0);
  599. }
  600. static void
  601. do_psinit(void)
  602.    error_t err;
  603.    err = ps_context_create (getproc (), &context);
  604.    if (err)
  605.        error (1, err, "ps_context_create");
  606.    err = proc_stat_list_create (context, &procset);
  607.    if (err)
  608.        error (1, err, "proc_stat_list_create");
  609.    err = proc_stat_list_add_all (procset, 0, 0);
  610.    if (err)
  611.        error (1, err, "proc_stat_list_add_all");
  612.    /* Check all pids */
  613.    ihash_iterate (context->procs, check_all);
  614. }
  615. #endif /* OSHURD */
  616. /* return 1 on failure */
  617. static int
  618. do_stop(void)
  619. {
  620. char what[1024];
  621. struct pid_list *p;
  622. int retval = 0;
  623. if (cmdname)
  624. strcpy(what, cmdname);
  625. else if (execname)
  626. strcpy(what, execname);
  627. else if (pidfile)
  628. sprintf(what, "process in pidfile `%s'", pidfile);
  629. else if (userspec)
  630. sprintf(what, "process(es) owned by `%s'", userspec);
  631. else
  632. fatal("internal error, please report");
  633. if (!found) {
  634. if (quietmode <= 0)
  635. printf("No %s found running; none killed.n", what);
  636. exit(exitnodo);
  637. }
  638. for (p = found; p; p = p->next) {
  639. if (testmode)
  640. printf("Would send signal %d to %d.n",
  641.        signal_nr, p->pid);
  642. else if (kill(p->pid, signal_nr) == 0)
  643. push(&killed, p->pid);
  644. else {
  645. printf("%s: warning: failed to kill %d: %sn",
  646.        progname, p->pid, strerror(errno));
  647. retval += exitnodo;
  648. }
  649. }
  650. if (quietmode < 0 && killed) {
  651. printf("Stopped %s (pid", what);
  652. for (p = killed; p; p = p->next)
  653. printf(" %d", p->pid);
  654. printf(").n");
  655. }
  656. return retval;
  657. }
  658. int
  659. main(int argc, char **argv)
  660. {
  661. progname = argv[0];
  662. parse_options(argc, argv);
  663. argc -= optind;
  664. argv += optind;
  665. if (execname && stat(execname, &exec_stat))
  666. fatal("stat %s: %s", execname, strerror(errno));
  667. if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
  668. struct passwd *pw;
  669. pw = getpwnam(userspec);
  670. if (!pw)
  671. fatal("user `%s' not foundn", userspec);
  672. user_id = pw->pw_uid;
  673. }
  674. if (changegroup && sscanf(changegroup, "%d", &runas_gid) != 1) {
  675. struct group *gr = getgrnam(changegroup);
  676. if (!gr)
  677. fatal("group `%s' not foundn", changegroup);
  678. runas_gid = gr->gr_gid;
  679. }
  680. if (changeuser && sscanf(changeuser, "%d", &runas_uid) != 1) {
  681. struct passwd *pw = getpwnam(changeuser);
  682. if (!pw)
  683. fatal("user `%s' not foundn", changeuser);
  684. runas_uid = pw->pw_uid;
  685. if (changegroup == NULL) { /* pass the default group of this user */
  686. changegroup = ""; /* just empty */
  687. runas_gid = pw->pw_gid;
  688. }
  689. }
  690. if (pidfile)
  691. do_pidfile(pidfile);
  692. else
  693. do_procinit();
  694. if (stop) {
  695. int i = do_stop();
  696. if (i) {
  697. if (quietmode <= 0)
  698. printf("%d pids were not killedn", i);
  699. exit(1);
  700. }
  701. exit(0);
  702. }
  703. if (found) {
  704. if (quietmode <= 0)
  705. printf("%s already running.n", execname);
  706. exit(exitnodo);
  707. }
  708. if (testmode) {
  709. printf("Would start %s ", startas);
  710. while (argc-- > 0)
  711. printf("%s ", *argv++);
  712. if (changeuser != NULL) {
  713. printf(" (as user %s[%d]", changeuser, runas_uid);
  714. if (changegroup != NULL)
  715. printf(", and group %s[%d])", changegroup, runas_gid);
  716. else
  717. printf(")");
  718. }
  719. if (changeroot != NULL)
  720. printf(" in directory %s", changeroot);
  721. printf(".n");
  722. exit(0);
  723. }
  724. if (quietmode < 0)
  725. printf("Starting %s...n", startas);
  726. *--argv = startas;
  727. if (changeroot != NULL) {
  728. if (chdir(changeroot) < 0)
  729. fatal("Unable to chdir() to %s", changeroot);
  730. if (chroot(changeroot) < 0)
  731. fatal("Unable to chroot() to %s", changeroot);
  732. }
  733. if (changeuser != NULL) {
  734.   if (setgid(runas_gid))
  735.   fatal("Unable to set gid to %d", runas_gid);
  736. if (initgroups(changeuser, runas_gid))
  737. fatal("Unable to set initgroups() with gid %d", runas_gid);
  738. if (setuid(runas_uid))
  739. fatal("Unable to set uid to %s", changeuser);
  740. }
  741. if (background) { /* ok, we need to detach this process */
  742. int i, fd;
  743. if (quietmode < 0)
  744. printf("Detatching to start %s...", startas);
  745. i = fork();
  746. if (i<0) {
  747. fatal("Unable to fork.n");
  748. }
  749. if (i) { /* parent */
  750. if (quietmode < 0)
  751. printf("done.n");
  752. exit(0);
  753. }
  754.  /* child continues here */
  755.  /* now close all extra fds */
  756. for (i=getdtablesize()-1; i>=0; --i) close(i);
  757.  /* change tty */
  758. fd = open("/dev/tty", O_RDWR);
  759. ioctl(fd, TIOCNOTTY, 0);
  760. close(fd);
  761. chdir("/");
  762. umask(022); /* set a default for dumb programs */
  763. #ifndef FreeBSD
  764. setpgrp();  /* set the process group */
  765. #else
  766. setpgrp(0, runas_gid);  /* set the process group */
  767. #endif
  768. fd=open("/dev/null", O_RDWR); /* stdin */
  769. dup(fd); /* stdout */
  770. dup(fd); /* stderr */
  771. }
  772. if (mpidfile && pidfile != NULL) { /* user wants _us_ to make the pidfile :) */
  773. FILE *pidf = fopen(pidfile, "w");
  774. pid_t pidt = getpid();
  775. if (pidf == NULL)
  776. fatal("Unable to open pidfile `%s' for writing: %s", pidfile,
  777. strerror(errno));
  778. fprintf(pidf, "%dn", (int)pidt);
  779. fclose(pidf);
  780. }
  781. execv(startas, argv);
  782. fatal("Unable to start %s: %s", startas, strerror(errno));
  783. }