start-stop-daemon.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  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. #include <errno.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <stdarg.h>
  18. #include <signal.h>
  19. #include <sys/stat.h>
  20. #include <dirent.h>
  21. #include <unistd.h>
  22. #include <getopt.h>
  23. #include <pwd.h>
  24. #define VERSION "version 0.4.1, 1997-01-29"
  25. static int testmode = 0;
  26. static int quietmode = 0;
  27. static int exitnodo = 1;
  28. static int start = 0;
  29. static int stop = 0;
  30. static int signal_nr = 15;
  31. static const char *signal_str = NULL;
  32. static int user_id = -1;
  33. static const char *userspec = NULL;
  34. static const char *cmdname = NULL;
  35. static char *execname = NULL;
  36. static char *startas = NULL;
  37. static const char *pidfile = NULL;
  38. static const char *progname = "";
  39. static struct stat exec_stat;
  40. struct pid_list {
  41. struct pid_list *next;
  42. int pid;
  43. };
  44. static struct pid_list *found = NULL;
  45. static struct pid_list *killed = NULL;
  46. static void *xmalloc(int size);
  47. static void push(struct pid_list **list, int pid);
  48. static void do_help(void);
  49. static void parse_options(int argc, char * const *argv);
  50. static int pid_is_exec(int pid, const struct stat *esb);
  51. static int pid_is_user(int pid, int uid);
  52. static int pid_is_cmd(int pid, const char *name);
  53. static void check(int pid);
  54. static void do_pidfile(const char *name);
  55. static void do_procfs(void);
  56. static void do_stop(void);
  57. #ifdef __GNUC__
  58. static void fatal(const char *format, ...)
  59. __attribute__((noreturn, format(printf, 1, 2)));
  60. static void badusage(const char *msg)
  61. __attribute__((noreturn));
  62. #else
  63. static void fatal(const char *format, ...);
  64. static void badusage(const char *msg);
  65. #endif
  66. static void
  67. fatal(const char *format, ...)
  68. {
  69. va_list arglist;
  70. fprintf(stderr, "%s: ", progname);
  71. va_start(arglist, format);
  72. vfprintf(stderr, format, arglist);
  73. va_end(arglist);
  74. putc('\n', stderr);
  75. exit(2);
  76. }
  77. static void *
  78. xmalloc(int size)
  79. {
  80. void *ptr;
  81. ptr = malloc(size);
  82. if (ptr)
  83. return ptr;
  84. fatal("malloc(%d) failed", size);
  85. }
  86. static void
  87. push(struct pid_list **list, int pid)
  88. {
  89. struct pid_list *p;
  90. p = xmalloc(sizeof(*p));
  91. p->next = *list;
  92. p->pid = pid;
  93. *list = p;
  94. }
  95. static void
  96. do_help(void)
  97. {
  98. printf("\
  99. start-stop-daemon for Debian Linux - small and fast C version written by\n\
  100. Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
  101. VERSION "\n\
  102. \n\
  103. Usage:
  104. start-stop-daemon -S|--start options ... -- arguments ...\n\
  105. start-stop-daemon -K|--stop options ...\n\
  106. start-stop-daemon -H|--help\n\
  107. start-stop-daemon -V|--version\n\
  108. \n\
  109. Options (at least one of --exec|--pidfile|--user is required):
  110. -x|--exec <executable> program to start/check if it is running\n\
  111. -p|--pidfile <pid-file> pid file to check\n\
  112. -u|--user <username>|<uid> stop processes owned by this user\n\
  113. -n|--name <process-name> stop processes with this name\n\
  114. -s|--signal <signal> signal to send (default TERM)\n\
  115. -a|--startas <pathname> program to start (default is <executable>)\n\
  116. -t|--test test mode, don't do anything\n\
  117. -o|--oknodo exit status 0 (not 1) if nothing done\n\
  118. -q|--quiet be more quiet\n\
  119. -v|--verbose be more verbose\n\
  120. \n\
  121. Exit status: 0 = done 1 = nothing done (=> 0 if --oknodo) 2 = trouble\n");
  122. }
  123. static void
  124. badusage(const char *msg)
  125. {
  126. if (msg)
  127. fprintf(stderr, "%s: %s\n", progname, msg);
  128. fprintf(stderr, "Try `%s --help' for more information.\n", progname);
  129. exit(2);
  130. }
  131. struct sigpair {
  132. const char *name;
  133. int signal;
  134. };
  135. const struct sigpair siglist[] = {
  136. { "ABRT", SIGABRT },
  137. { "ALRM", SIGALRM },
  138. { "FPE", SIGFPE },
  139. { "HUP", SIGHUP },
  140. { "ILL", SIGILL },
  141. { "INT", SIGINT },
  142. { "KILL", SIGKILL },
  143. { "PIPE", SIGPIPE },
  144. { "QUIT", SIGQUIT },
  145. { "SEGV", SIGSEGV },
  146. { "TERM", SIGTERM },
  147. { "USR1", SIGUSR1 },
  148. { "USR2", SIGUSR2 },
  149. { "CHLD", SIGCHLD },
  150. { "CONT", SIGCONT },
  151. { "STOP", SIGSTOP },
  152. { "TSTP", SIGTSTP },
  153. { "TTIN", SIGTTIN },
  154. { "TTOU", SIGTTOU }
  155. };
  156. static int parse_signal (const char *signal_str, int *signal_nr)
  157. {
  158. int i;
  159. for (i = 0; i < sizeof (siglist) / sizeof (siglist[0]); i++) {
  160. if (strcmp (signal_str, siglist[i].name) == 0) {
  161. *signal_nr = siglist[i].signal;
  162. return 0;
  163. }
  164. }
  165. return -1;
  166. }
  167. static void
  168. parse_options(int argc, char * const *argv)
  169. {
  170. static struct option longopts[] = {
  171. { "help", 0, NULL, 'H'},
  172. { "stop", 0, NULL, 'K'},
  173. { "start", 0, NULL, 'S'},
  174. { "version", 0, NULL, 'V'},
  175. { "startas", 1, NULL, 'a'},
  176. { "name", 1, NULL, 'n'},
  177. { "oknodo", 0, NULL, 'o'},
  178. { "pidfile", 1, NULL, 'p'},
  179. { "quiet", 0, NULL, 'q'},
  180. { "signal", 1, NULL, 's'},
  181. { "test", 0, NULL, 't'},
  182. { "user", 1, NULL, 'u'},
  183. { "verbose", 0, NULL, 'v'},
  184. { "exec", 1, NULL, 'x'},
  185. { NULL, 0, NULL, 0}
  186. };
  187. int c;
  188. for (;;) {
  189. c = getopt_long(argc, argv, "HKSVa:n:op:qs:tu:vx:",
  190. longopts, (int *) 0);
  191. if (c == -1)
  192. break;
  193. switch (c) {
  194. case 'H': /* --help */
  195. do_help();
  196. exit(0);
  197. case 'K': /* --stop */
  198. stop = 1;
  199. break;
  200. case 'S': /* --start */
  201. start = 1;
  202. break;
  203. case 'V': /* --version */
  204. printf("start-stop-daemon " VERSION "\n");
  205. exit(0);
  206. case 'a': /* --startas <pathname> */
  207. startas = optarg;
  208. break;
  209. case 'n': /* --name <process-name> */
  210. cmdname = optarg;
  211. break;
  212. case 'o': /* --oknodo */
  213. exitnodo = 0;
  214. break;
  215. case 'p': /* --pidfile <pid-file> */
  216. pidfile = optarg;
  217. break;
  218. case 'q': /* --quiet */
  219. quietmode = 1;
  220. break;
  221. case 's': /* --signal <signal> */
  222. signal_str = optarg;
  223. break;
  224. case 't': /* --test */
  225. testmode = 1;
  226. break;
  227. case 'u': /* --user <username>|<uid> */
  228. userspec = optarg;
  229. break;
  230. case 'v': /* --verbose */
  231. quietmode = -1;
  232. break;
  233. case 'x': /* --exec <executable> */
  234. execname = optarg;
  235. break;
  236. default:
  237. badusage(NULL); /* message printed by getopt */
  238. }
  239. }
  240. if (signal_str != NULL) {
  241. if (sscanf (signal_str, "%d", &signal_nr) != 1) {
  242. if (parse_signal (signal_str, &signal_nr) != 0) {
  243. badusage ("--signal takes a numeric argument or name of signal (KILL, INTR, ...)");
  244. }
  245. }
  246. }
  247. if (start == stop)
  248. badusage("need one of --start or --stop");
  249. if (!execname && !pidfile && !userspec)
  250. badusage("need at least one of --exec, --pidfile or --user");
  251. if (!startas)
  252. startas = execname;
  253. if (start && !startas)
  254. badusage("--start needs --exec or --startas");
  255. }
  256. static int
  257. pid_is_exec(int pid, const struct stat *esb)
  258. {
  259. struct stat sb;
  260. char buf[32];
  261. sprintf(buf, "/proc/%d/exe", pid);
  262. if (stat(buf, &sb) != 0)
  263. return 0;
  264. return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
  265. }
  266. static int
  267. pid_is_user(int pid, int uid)
  268. {
  269. struct stat sb;
  270. char buf[32];
  271. sprintf(buf, "/proc/%d", pid);
  272. if (stat(buf, &sb) != 0)
  273. return 0;
  274. return (sb.st_uid == uid);
  275. }
  276. static int
  277. pid_is_cmd(int pid, const char *name)
  278. {
  279. char buf[32];
  280. FILE *f;
  281. int c;
  282. sprintf(buf, "/proc/%d/stat", pid);
  283. f = fopen(buf, "r");
  284. if (!f)
  285. return 0;
  286. while ((c = getc(f)) != EOF && c != '(')
  287. ;
  288. if (c != '(') {
  289. fclose(f);
  290. return 0;
  291. }
  292. /* this hopefully handles command names containing ')' */
  293. while ((c = getc(f)) != EOF && c == *name)
  294. name++;
  295. fclose(f);
  296. return (c == ')' && *name == '\0');
  297. }
  298. static void
  299. check(int pid)
  300. {
  301. if (execname && !pid_is_exec(pid, &exec_stat))
  302. return;
  303. if (userspec && !pid_is_user(pid, user_id))
  304. return;
  305. if (cmdname && !pid_is_cmd(pid, cmdname))
  306. return;
  307. push(&found, pid);
  308. }
  309. static void
  310. do_pidfile(const char *name)
  311. {
  312. FILE *f;
  313. int pid;
  314. f = fopen(name, "r");
  315. if (f) {
  316. if (fscanf(f, "%d", &pid) == 1)
  317. check(pid);
  318. fclose(f);
  319. }
  320. }
  321. static void
  322. do_procfs(void)
  323. {
  324. DIR *procdir;
  325. struct dirent *entry;
  326. int foundany, pid;
  327. procdir = opendir("/proc");
  328. if (!procdir)
  329. fatal("opendir /proc: %s", strerror(errno));
  330. foundany = 0;
  331. while ((entry = readdir(procdir)) != NULL) {
  332. if (sscanf(entry->d_name, "%d", &pid) != 1)
  333. continue;
  334. foundany++;
  335. check(pid);
  336. }
  337. closedir(procdir);
  338. if (!foundany)
  339. fatal("nothing in /proc - not mounted?");
  340. }
  341. static void
  342. do_stop(void)
  343. {
  344. char what[1024];
  345. struct pid_list *p;
  346. if (cmdname)
  347. strcpy(what, cmdname);
  348. else if (execname)
  349. strcpy(what, execname);
  350. else if (pidfile)
  351. sprintf(what, "process in pidfile `%s'", pidfile);
  352. else if (userspec)
  353. sprintf(what, "process(es) owned by `%s'", userspec);
  354. else
  355. fatal("internal error, please report");
  356. if (!found) {
  357. if (quietmode <= 0)
  358. printf("No %s found running; none killed.\n", what);
  359. exit(exitnodo);
  360. }
  361. for (p = found; p; p = p->next) {
  362. if (testmode)
  363. printf("Would send signal %d to %d.\n",
  364. signal_nr, p->pid);
  365. else if (kill(p->pid, signal_nr) == 0)
  366. push(&killed, p->pid);
  367. else
  368. printf("%s: warning: failed to kill %d: %s\n",
  369. progname, p->pid, strerror(errno));
  370. }
  371. if (quietmode < 0 && killed) {
  372. printf("Stopped %s (pid", what);
  373. for (p = killed; p; p = p->next)
  374. printf(" %d", p->pid);
  375. printf(").\n");
  376. }
  377. }
  378. int
  379. main(int argc, char **argv)
  380. {
  381. progname = argv[0];
  382. parse_options(argc, argv);
  383. argc -= optind;
  384. argv += optind;
  385. if (execname && stat(execname, &exec_stat))
  386. fatal("stat %s: %s", execname, strerror(errno));
  387. if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
  388. struct passwd *pw;
  389. pw = getpwnam(userspec);
  390. if (!pw)
  391. fatal("user `%s' not found\n", userspec);
  392. user_id = pw->pw_uid;
  393. }
  394. if (pidfile)
  395. do_pidfile(pidfile);
  396. else
  397. do_procfs();
  398. if (stop) {
  399. do_stop();
  400. exit(0);
  401. }
  402. if (found) {
  403. if (quietmode <= 0)
  404. printf("%s already running.\n", execname);
  405. exit(exitnodo);
  406. }
  407. if (testmode) {
  408. printf("Would start %s ", startas);
  409. while (argc-- > 0)
  410. printf("%s ", *argv++);
  411. printf(".\n");
  412. exit(0);
  413. }
  414. if (quietmode < 0)
  415. printf("Starting %s...\n", startas);
  416. *--argv = startas;
  417. execv(startas, argv);
  418. fatal("Unable to start %s: %s", startas, strerror(errno));
  419. }