start_stop_daemon.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Mini start-stop-daemon implementation(s) for busybox
  4. *
  5. * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
  6. * Adapted for busybox David Kimdon <dwhedon@gordian.com>
  7. *
  8. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  9. */
  10. /* NB: we have a problem here with /proc/NN/exe usage, similar to
  11. * one fixed in killall/pidof */
  12. #include <getopt.h>
  13. #include <sys/resource.h>
  14. /* Override ENABLE_FEATURE_PIDFILE */
  15. #define WANT_PIDFILE 1
  16. #include "libbb.h"
  17. static int signal_nr = 15;
  18. static int user_id = -1;
  19. static char *userspec;
  20. static char *cmdname;
  21. static char *execname;
  22. static char *pidfile;
  23. static smallint quiet;
  24. struct pid_list {
  25. struct pid_list *next;
  26. pid_t pid;
  27. };
  28. static struct pid_list *found;
  29. static int pid_is_exec(pid_t pid, const char *name)
  30. {
  31. char buf[sizeof("/proc//exe") + sizeof(int)*3];
  32. char *execbuf;
  33. int n;
  34. sprintf(buf, "/proc/%u/exe", pid);
  35. n = strlen(name) + 1;
  36. execbuf = xzalloc(n + 1);
  37. readlink(buf, execbuf, n);
  38. /* if readlink fails, execbuf still contains "" */
  39. n = strcmp(execbuf, name);
  40. if (ENABLE_FEATURE_CLEAN_UP)
  41. free(execbuf);
  42. return !n; /* nonzero (true) if execbuf == name */
  43. }
  44. static int pid_is_user(int pid, int uid)
  45. {
  46. struct stat sb;
  47. char buf[sizeof("/proc/") + sizeof(int)*3];
  48. sprintf(buf, "/proc/%u", pid);
  49. if (stat(buf, &sb) != 0)
  50. return 0;
  51. return (sb.st_uid == uid);
  52. }
  53. static int pid_is_cmd(pid_t pid, const char *name)
  54. {
  55. char fname[sizeof("/proc//stat") + sizeof(int)*3];
  56. char *buf;
  57. int r = 0;
  58. sprintf(fname, "/proc/%u/stat", pid);
  59. buf = xmalloc_open_read_close(fname, NULL);
  60. if (buf) {
  61. char *p = strchr(buf, '(');
  62. if (p) {
  63. char *pe = strrchr(++p, ')');
  64. if (pe) {
  65. *pe = '\0';
  66. r = !strcmp(p, name);
  67. }
  68. }
  69. free(buf);
  70. }
  71. return r;
  72. }
  73. static void check(int pid)
  74. {
  75. struct pid_list *p;
  76. if (execname && !pid_is_exec(pid, execname)) {
  77. return;
  78. }
  79. if (userspec && !pid_is_user(pid, user_id)) {
  80. return;
  81. }
  82. if (cmdname && !pid_is_cmd(pid, cmdname)) {
  83. return;
  84. }
  85. p = xmalloc(sizeof(*p));
  86. p->next = found;
  87. p->pid = pid;
  88. found = p;
  89. }
  90. static void do_pidfile(void)
  91. {
  92. FILE *f;
  93. unsigned pid;
  94. f = fopen(pidfile, "r");
  95. if (f) {
  96. if (fscanf(f, "%u", &pid) == 1)
  97. check(pid);
  98. fclose(f);
  99. } else if (errno != ENOENT)
  100. bb_perror_msg_and_die("open pidfile %s", pidfile);
  101. }
  102. static void do_procinit(void)
  103. {
  104. DIR *procdir;
  105. struct dirent *entry;
  106. int foundany, pid;
  107. if (pidfile) {
  108. do_pidfile();
  109. return;
  110. }
  111. procdir = xopendir("/proc");
  112. foundany = 0;
  113. while ((entry = readdir(procdir)) != NULL) {
  114. pid = bb_strtou(entry->d_name, NULL, 10);
  115. if (errno)
  116. continue;
  117. foundany++;
  118. check(pid);
  119. }
  120. closedir(procdir);
  121. if (!foundany)
  122. bb_error_msg_and_die("nothing in /proc - not mounted?");
  123. }
  124. static int do_stop(void)
  125. {
  126. char *what;
  127. struct pid_list *p;
  128. int killed = 0;
  129. do_procinit();
  130. if (cmdname) {
  131. if (ENABLE_FEATURE_CLEAN_UP) what = xstrdup(cmdname);
  132. if (!ENABLE_FEATURE_CLEAN_UP) what = cmdname;
  133. } else if (execname) {
  134. if (ENABLE_FEATURE_CLEAN_UP) what = xstrdup(execname);
  135. if (!ENABLE_FEATURE_CLEAN_UP) what = execname;
  136. } else if (pidfile)
  137. what = xasprintf("process in pidfile '%s'", pidfile);
  138. else if (userspec)
  139. what = xasprintf("process(es) owned by '%s'", userspec);
  140. else
  141. bb_error_msg_and_die("internal error, please report");
  142. if (!found) {
  143. if (!quiet)
  144. printf("no %s found; none killed\n", what);
  145. killed = -1;
  146. goto ret;
  147. }
  148. for (p = found; p; p = p->next) {
  149. if (kill(p->pid, signal_nr) == 0) {
  150. p->pid = - p->pid;
  151. killed++;
  152. } else {
  153. bb_perror_msg("warning: killing process %u", p->pid);
  154. }
  155. }
  156. if (!quiet && killed) {
  157. printf("stopped %s (pid", what);
  158. for (p = found; p; p = p->next)
  159. if (p->pid < 0)
  160. printf(" %u", - p->pid);
  161. puts(")");
  162. }
  163. ret:
  164. if (ENABLE_FEATURE_CLEAN_UP)
  165. free(what);
  166. return killed;
  167. }
  168. #if ENABLE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS
  169. static const char start_stop_daemon_longopts[] ALIGN1 =
  170. "stop\0" No_argument "K"
  171. "start\0" No_argument "S"
  172. "background\0" No_argument "b"
  173. "quiet\0" No_argument "q"
  174. "make-pidfile\0" No_argument "m"
  175. #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
  176. "oknodo\0" No_argument "o"
  177. "verbose\0" No_argument "v"
  178. "nicelevel\0" Required_argument "N"
  179. #endif
  180. "startas\0" Required_argument "a"
  181. "name\0" Required_argument "n"
  182. "signal\0" Required_argument "s"
  183. "user\0" Required_argument "u"
  184. "chuid\0" Required_argument "c"
  185. "exec\0" Required_argument "x"
  186. "pidfile\0" Required_argument "p"
  187. #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
  188. "retry\0" Required_argument "R"
  189. #endif
  190. ;
  191. #endif
  192. enum {
  193. CTX_STOP = 0x1,
  194. CTX_START = 0x2,
  195. OPT_BACKGROUND = 0x4, // -b
  196. OPT_QUIET = 0x8, // -q
  197. OPT_MAKEPID = 0x10, // -m
  198. OPT_a = 0x20, // -a
  199. OPT_n = 0x40, // -n
  200. OPT_s = 0x80, // -s
  201. OPT_u = 0x100, // -u
  202. OPT_c = 0x200, // -c
  203. OPT_x = 0x400, // -x
  204. OPT_p = 0x800, // -p
  205. OPT_OKNODO = 0x1000 * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -o
  206. OPT_VERBOSE = 0x2000 * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -v
  207. OPT_NICELEVEL = 0x4000 * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -N
  208. };
  209. int start_stop_daemon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  210. int start_stop_daemon_main(int argc, char **argv)
  211. {
  212. unsigned opt;
  213. char *signame;
  214. char *startas;
  215. char *chuid;
  216. #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
  217. // char *retry_arg = NULL;
  218. // int retries = -1;
  219. char *opt_N;
  220. #endif
  221. #if ENABLE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS
  222. applet_long_options = start_stop_daemon_longopts;
  223. #endif
  224. /* Check required one context option was given */
  225. opt_complementary = "K:S:K--S:S--K:m?p:K?xpun:S?xa";
  226. opt = getopt32(argv, "KSbqma:n:s:u:c:x:p:"
  227. USE_FEATURE_START_STOP_DAEMON_FANCY("ovN:"),
  228. // USE_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:"),
  229. &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile
  230. USE_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N)
  231. // USE_FEATURE_START_STOP_DAEMON_FANCY(,&retry_arg)
  232. );
  233. quiet = (opt & OPT_QUIET) && !(opt & OPT_VERBOSE);
  234. if (opt & OPT_s) {
  235. signal_nr = get_signum(signame);
  236. if (signal_nr < 0) bb_show_usage();
  237. }
  238. if (!(opt & OPT_a))
  239. startas = execname;
  240. // USE_FEATURE_START_STOP_DAEMON_FANCY(
  241. // if (retry_arg)
  242. // retries = xatoi_u(retry_arg);
  243. // )
  244. argc -= optind;
  245. argv += optind;
  246. if (userspec) {
  247. user_id = bb_strtou(userspec, NULL, 10);
  248. if (errno)
  249. user_id = xuname2uid(userspec);
  250. }
  251. if (opt & CTX_STOP) {
  252. int i = do_stop();
  253. return (opt & OPT_OKNODO) ? 0 : (i <= 0);
  254. }
  255. do_procinit();
  256. if (found) {
  257. if (!quiet)
  258. printf("%s already running\n%d\n", execname, found->pid);
  259. return !(opt & OPT_OKNODO);
  260. }
  261. *--argv = startas;
  262. if (opt & OPT_BACKGROUND) {
  263. #if BB_MMU
  264. bb_daemonize(0);
  265. #else
  266. pid_t pid = vfork();
  267. if (pid < 0) /* error */
  268. bb_perror_msg_and_die("vfork");
  269. if (pid != 0) {
  270. /* parent */
  271. /* why _exit? the child may have changed the stack,
  272. * so "return 0" may do bad things */
  273. _exit(0);
  274. }
  275. /* child */
  276. setsid(); /* detach from controlling tty */
  277. /* Redirect stdio to /dev/null, close extra FDs.
  278. * We do not actually daemonize because of DAEMON_ONLY_SANITIZE */
  279. bb_daemonize_or_rexec(
  280. DAEMON_DEVNULL_STDIO
  281. + DAEMON_CLOSE_EXTRA_FDS
  282. + DAEMON_ONLY_SANITIZE,
  283. NULL /* argv, unused */ );
  284. #endif
  285. }
  286. if (opt & OPT_MAKEPID) {
  287. /* user wants _us_ to make the pidfile */
  288. write_pidfile(pidfile);
  289. }
  290. if (opt & OPT_c) {
  291. struct bb_uidgid_t ugid;
  292. parse_chown_usergroup_or_die(&ugid, chuid);
  293. if (ugid.gid != (gid_t) -1) xsetgid(ugid.gid);
  294. if (ugid.uid != (uid_t) -1) xsetuid(ugid.uid);
  295. }
  296. #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
  297. if (opt & OPT_NICELEVEL) {
  298. /* Set process priority */
  299. int prio = getpriority(PRIO_PROCESS, 0) + xatoi_range(opt_N, INT_MIN/2, INT_MAX/2);
  300. if (setpriority(PRIO_PROCESS, 0, prio) < 0) {
  301. bb_perror_msg_and_die("setpriority(%d)", prio);
  302. }
  303. }
  304. #endif
  305. execv(startas, argv);
  306. bb_perror_msg_and_die("cannot start %s", startas);
  307. }