start_stop_daemon.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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. * public domain.
  7. * Adapted for busybox David Kimdon <dwhedon@gordian.com>
  8. */
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <stdarg.h>
  13. #include <signal.h>
  14. #include <errno.h>
  15. #include <sys/stat.h>
  16. #include <dirent.h>
  17. #include <unistd.h>
  18. #include <getopt.h>
  19. #include "busybox.h"
  20. #include "pwd_.h"
  21. static int signal_nr = 15;
  22. static int user_id = -1;
  23. static int quiet = 0;
  24. static char *userspec = NULL;
  25. static char *cmdname = NULL;
  26. static char *execname = NULL;
  27. static char *pidfile = NULL;
  28. struct pid_list {
  29. struct pid_list *next;
  30. pid_t pid;
  31. };
  32. static struct pid_list *found = NULL;
  33. static inline void
  34. push(pid_t pid)
  35. {
  36. struct pid_list *p;
  37. p = xmalloc(sizeof(*p));
  38. p->next = found;
  39. p->pid = pid;
  40. found = p;
  41. }
  42. static int
  43. pid_is_exec(pid_t pid, const char *name)
  44. {
  45. char buf[32];
  46. struct stat sb, exec_stat;
  47. if (name && stat(name, &exec_stat))
  48. bb_perror_msg_and_die("stat %s", name);
  49. sprintf(buf, "/proc/%d/exe", pid);
  50. if (stat(buf, &sb) != 0)
  51. return 0;
  52. return (sb.st_dev == exec_stat.st_dev && sb.st_ino == exec_stat.st_ino);
  53. }
  54. static int
  55. pid_is_user(int pid, int uid)
  56. {
  57. struct stat sb;
  58. char buf[32];
  59. sprintf(buf, "/proc/%d", pid);
  60. if (stat(buf, &sb) != 0)
  61. return 0;
  62. return (sb.st_uid == uid);
  63. }
  64. static int
  65. pid_is_cmd(pid_t pid, const char *name)
  66. {
  67. char buf[32];
  68. FILE *f;
  69. int c;
  70. sprintf(buf, "/proc/%d/stat", pid);
  71. f = fopen(buf, "r");
  72. if (!f)
  73. return 0;
  74. while ((c = getc(f)) != EOF && c != '(')
  75. ;
  76. if (c != '(') {
  77. fclose(f);
  78. return 0;
  79. }
  80. /* this hopefully handles command names containing ')' */
  81. while ((c = getc(f)) != EOF && c == *name)
  82. name++;
  83. fclose(f);
  84. return (c == ')' && *name == '\0');
  85. }
  86. static void
  87. check(int pid)
  88. {
  89. if (execname && !pid_is_exec(pid, execname)) {
  90. return;
  91. }
  92. if (userspec && !pid_is_user(pid, user_id)) {
  93. return;
  94. }
  95. if (cmdname && !pid_is_cmd(pid, cmdname)) {
  96. return;
  97. }
  98. push(pid);
  99. }
  100. static void
  101. do_pidfile(void)
  102. {
  103. FILE *f;
  104. pid_t pid;
  105. f = fopen(pidfile, "r");
  106. if (f) {
  107. if (fscanf(f, "%d", &pid) == 1)
  108. check(pid);
  109. fclose(f);
  110. } else if (errno != ENOENT)
  111. bb_perror_msg_and_die("open pidfile %s", pidfile);
  112. }
  113. static void
  114. do_procinit(void)
  115. {
  116. DIR *procdir;
  117. struct dirent *entry;
  118. int foundany, pid;
  119. if (pidfile) {
  120. do_pidfile();
  121. return;
  122. }
  123. procdir = opendir("/proc");
  124. if (!procdir)
  125. bb_perror_msg_and_die ("opendir /proc");
  126. foundany = 0;
  127. while ((entry = readdir(procdir)) != NULL) {
  128. if (sscanf(entry->d_name, "%d", &pid) != 1)
  129. continue;
  130. foundany++;
  131. check(pid);
  132. }
  133. closedir(procdir);
  134. if (!foundany)
  135. bb_error_msg_and_die ("nothing in /proc - not mounted?");
  136. }
  137. static void
  138. do_stop(void)
  139. {
  140. char what[1024];
  141. struct pid_list *p;
  142. int killed = 0;
  143. do_procinit();
  144. if (cmdname)
  145. strcpy(what, cmdname);
  146. else if (execname)
  147. strcpy(what, execname);
  148. else if (pidfile)
  149. sprintf(what, "process in pidfile `%.200s'", pidfile);
  150. else if (userspec)
  151. sprintf(what, "process(es) owned by `%s'", userspec);
  152. else
  153. bb_error_msg_and_die ("internal error, please report");
  154. if (!found) {
  155. if (!quiet)
  156. printf("no %s found; none killed.\n", what);
  157. return;
  158. }
  159. for (p = found; p; p = p->next) {
  160. if (kill(p->pid, signal_nr) == 0) {
  161. p->pid = -p->pid;
  162. killed++;
  163. } else {
  164. bb_perror_msg("warning: failed to kill %d", p->pid);
  165. }
  166. }
  167. if (!quiet && killed) {
  168. printf("stopped %s (pid", what);
  169. for (p = found; p; p = p->next)
  170. if(p->pid < 0)
  171. printf(" %d", -p->pid);
  172. printf(").\n");
  173. }
  174. }
  175. static const struct option ssd_long_options[] = {
  176. { "stop", 0, NULL, 'K' },
  177. { "start", 0, NULL, 'S' },
  178. { "background", 0, NULL, 'b' },
  179. { "quiet", 0, NULL, 'q' },
  180. { "make-pidfile", 0, NULL, 'm' },
  181. { "startas", 1, NULL, 'a' },
  182. { "name", 1, NULL, 'n' },
  183. { "signal", 1, NULL, 's' },
  184. { "user", 1, NULL, 'u' },
  185. { "exec", 1, NULL, 'x' },
  186. { "pidfile", 1, NULL, 'p' },
  187. { 0, 0, 0, 0 }
  188. };
  189. #define SSD_CTX_STOP 1
  190. #define SSD_CTX_START 2
  191. #define SSD_OPT_BACKGROUND 4
  192. #define SSD_OPT_QUIET 8
  193. #define SSD_OPT_MAKEPID 16
  194. int
  195. start_stop_daemon_main(int argc, char **argv)
  196. {
  197. unsigned long opt;
  198. char *signame = NULL;
  199. char *startas = NULL;
  200. bb_applet_long_options = ssd_long_options;
  201. bb_opt_complementaly = "K~S:S~K";
  202. opt = bb_getopt_ulflags(argc, argv, "KSbqma:n:s:u:x:p:",
  203. &startas, &cmdname, &signame, &userspec, &execname, &pidfile);
  204. /* Check one and only one context option was given */
  205. if ((opt & BB_GETOPT_ERROR) || (opt & (SSD_CTX_STOP | SSD_CTX_START)) == 0) {
  206. bb_show_usage();
  207. }
  208. if (signame) {
  209. signal_nr = bb_xgetlarg(signame, 10, 0, NSIG);
  210. }
  211. if (!execname && !pidfile && !userspec && !cmdname)
  212. bb_error_msg_and_die ("need at least one of -x, -p, -u, or -n");
  213. if (!startas)
  214. startas = execname;
  215. if ((opt & SSD_CTX_START) && !startas)
  216. bb_error_msg_and_die ("-S needs -x or -a");
  217. if ((opt & SSD_OPT_MAKEPID) && pidfile == NULL)
  218. bb_error_msg_and_die ("-m needs -p");
  219. argc -= optind;
  220. argv += optind;
  221. if (userspec && sscanf(userspec, "%d", &user_id) != 1)
  222. user_id = my_getpwnam(userspec);
  223. if (opt & SSD_CTX_STOP) {
  224. do_stop();
  225. return EXIT_SUCCESS;
  226. }
  227. do_procinit();
  228. if (found) {
  229. if (!quiet)
  230. printf("%s already running.\n%d\n", execname ,found->pid);
  231. return EXIT_SUCCESS;
  232. }
  233. *--argv = startas;
  234. if (opt & SSD_OPT_BACKGROUND) {
  235. if (daemon(0, 0) == -1)
  236. bb_perror_msg_and_die ("unable to fork");
  237. setsid();
  238. }
  239. if (opt & SSD_OPT_MAKEPID) {
  240. /* user wants _us_ to make the pidfile */
  241. FILE *pidf = fopen(pidfile, "w");
  242. pid_t pidt = getpid();
  243. if (pidf == NULL)
  244. bb_perror_msg_and_die("Unable to write pidfile '%s'", pidfile);
  245. fprintf(pidf, "%d\n", pidt);
  246. fclose(pidf);
  247. }
  248. execv(startas, argv);
  249. bb_perror_msg_and_die ("unable to start %s", startas);
  250. }