1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123#include <sys/resource.h>
124
125
126#define WANT_PIDFILE 1
127#include "libbb.h"
128
129struct pid_list {
130 struct pid_list *next;
131 pid_t pid;
132};
133
134enum {
135 CTX_STOP = (1 << 0),
136 CTX_START = (1 << 1),
137 OPT_BACKGROUND = (1 << 2),
138 OPT_QUIET = (1 << 3),
139 OPT_TEST = (1 << 4),
140 OPT_MAKEPID = (1 << 5),
141 OPT_a = (1 << 6),
142 OPT_n = (1 << 7),
143 OPT_s = (1 << 8),
144 OPT_u = (1 << 9),
145 OPT_c = (1 << 10),
146 OPT_x = (1 << 11),
147 OPT_p = (1 << 12),
148 OPT_OKNODO = (1 << 13) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY,
149 OPT_VERBOSE = (1 << 14) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY,
150 OPT_NICELEVEL = (1 << 15) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY,
151};
152#define QUIET (option_mask32 & OPT_QUIET)
153#define TEST (option_mask32 & OPT_TEST)
154
155struct globals {
156 struct pid_list *found_procs;
157 char *userspec;
158 char *cmdname;
159 char *execname;
160 char *pidfile;
161 char *execname_cmpbuf;
162 unsigned execname_sizeof;
163 int user_id;
164 smallint signal_nr;
165} FIX_ALIASING;
166#define G (*(struct globals*)&bb_common_bufsiz1)
167#define userspec (G.userspec )
168#define cmdname (G.cmdname )
169#define execname (G.execname )
170#define pidfile (G.pidfile )
171#define user_id (G.user_id )
172#define signal_nr (G.signal_nr )
173#define INIT_G() do { \
174 user_id = -1; \
175 signal_nr = 15; \
176} while (0)
177
178#ifdef OLDER_VERSION_OF_X
179
180
181
182
183static int pid_is_exec(pid_t pid)
184{
185 struct stat st;
186 char buf[sizeof("/proc/%u/exe") + sizeof(int)*3];
187
188 sprintf(buf, "/proc/%u/exe", (unsigned)pid);
189 if (stat(buf, &st) < 0)
190 return 0;
191 if (st.st_dev == execstat.st_dev
192 && st.st_ino == execstat.st_ino)
193 return 1;
194 return 0;
195}
196#endif
197
198static int pid_is_exec(pid_t pid)
199{
200 ssize_t bytes;
201 char buf[sizeof("/proc/%u/cmdline") + sizeof(int)*3];
202 char *procname, *exelink;
203 int match;
204
205 procname = buf + sprintf(buf, "/proc/%u/exe", (unsigned)pid) - 3;
206
207 exelink = xmalloc_readlink(buf);
208 match = (exelink && strcmp(execname, exelink) == 0);
209 free(exelink);
210 if (match)
211 return match;
212
213 strcpy(procname, "cmdline");
214 bytes = open_read_close(buf, G.execname_cmpbuf, G.execname_sizeof);
215 if (bytes > 0) {
216 G.execname_cmpbuf[bytes] = '\0';
217 return strcmp(execname, G.execname_cmpbuf) == 0;
218 }
219 return 0;
220}
221
222static int pid_is_name(pid_t pid)
223{
224
225 char buf[32];
226 char *p, *pe;
227
228 sprintf(buf, "/proc/%u/stat", (unsigned)pid);
229 if (open_read_close(buf, buf, sizeof(buf) - 1) < 0)
230 return 0;
231 buf[sizeof(buf) - 1] = '\0';
232 p = strchr(buf, '(');
233 if (!p)
234 return 0;
235 pe = strrchr(++p, ')');
236 if (!pe)
237 return 0;
238 *pe = '\0';
239
240
241
242 if (strlen(p) >= COMM_LEN - 1)
243 return 0;
244 return strcmp(p, cmdname) == 0;
245}
246
247static int pid_is_user(int pid)
248{
249 struct stat sb;
250 char buf[sizeof("/proc/") + sizeof(int)*3];
251
252 sprintf(buf, "/proc/%u", (unsigned)pid);
253 if (stat(buf, &sb) != 0)
254 return 0;
255 return (sb.st_uid == (uid_t)user_id);
256}
257
258static void check(int pid)
259{
260 struct pid_list *p;
261
262 if (execname && !pid_is_exec(pid)) {
263 return;
264 }
265 if (cmdname && !pid_is_name(pid)) {
266 return;
267 }
268 if (userspec && !pid_is_user(pid)) {
269 return;
270 }
271 p = xmalloc(sizeof(*p));
272 p->next = G.found_procs;
273 p->pid = pid;
274 G.found_procs = p;
275}
276
277static void do_pidfile(void)
278{
279 FILE *f;
280 unsigned pid;
281
282 f = fopen_for_read(pidfile);
283 if (f) {
284 if (fscanf(f, "%u", &pid) == 1)
285 check(pid);
286 fclose(f);
287 } else if (errno != ENOENT)
288 bb_perror_msg_and_die("open pidfile %s", pidfile);
289}
290
291static void do_procinit(void)
292{
293 DIR *procdir;
294 struct dirent *entry;
295 int pid;
296
297 if (pidfile) {
298 do_pidfile();
299 return;
300 }
301
302 procdir = xopendir("/proc");
303
304 pid = 0;
305 while (1) {
306 errno = 0;
307 entry = readdir(procdir);
308
309
310 if (errno)
311 continue;
312 if (!entry)
313 break;
314 pid = bb_strtou(entry->d_name, NULL, 10);
315 if (errno)
316 continue;
317 check(pid);
318 }
319 closedir(procdir);
320 if (!pid)
321 bb_error_msg_and_die("nothing in /proc - not mounted?");
322}
323
324static int do_stop(void)
325{
326 char *what;
327 struct pid_list *p;
328 int killed = 0;
329
330 if (cmdname) {
331 if (ENABLE_FEATURE_CLEAN_UP) what = xstrdup(cmdname);
332 if (!ENABLE_FEATURE_CLEAN_UP) what = cmdname;
333 } else if (execname) {
334 if (ENABLE_FEATURE_CLEAN_UP) what = xstrdup(execname);
335 if (!ENABLE_FEATURE_CLEAN_UP) what = execname;
336 } else if (pidfile) {
337 what = xasprintf("process in pidfile '%s'", pidfile);
338 } else if (userspec) {
339 what = xasprintf("process(es) owned by '%s'", userspec);
340 } else {
341 bb_error_msg_and_die("internal error, please report");
342 }
343
344 if (!G.found_procs) {
345 if (!QUIET)
346 printf("no %s found; none killed\n", what);
347 killed = -1;
348 goto ret;
349 }
350 for (p = G.found_procs; p; p = p->next) {
351 if (kill(p->pid, TEST ? 0 : signal_nr) == 0) {
352 killed++;
353 } else {
354 bb_perror_msg("warning: killing process %u", (unsigned)p->pid);
355 p->pid = 0;
356 if (TEST) {
357
358
359 killed = -1;
360 goto ret;
361 }
362 }
363 }
364 if (!QUIET && killed) {
365 printf("stopped %s (pid", what);
366 for (p = G.found_procs; p; p = p->next)
367 if (p->pid)
368 printf(" %u", (unsigned)p->pid);
369 puts(")");
370 }
371 ret:
372 if (ENABLE_FEATURE_CLEAN_UP)
373 free(what);
374 return killed;
375}
376
377#if ENABLE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS
378static const char start_stop_daemon_longopts[] ALIGN1 =
379 "stop\0" No_argument "K"
380 "start\0" No_argument "S"
381 "background\0" No_argument "b"
382 "quiet\0" No_argument "q"
383 "test\0" No_argument "t"
384 "make-pidfile\0" No_argument "m"
385#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
386 "oknodo\0" No_argument "o"
387 "verbose\0" No_argument "v"
388 "nicelevel\0" Required_argument "N"
389#endif
390 "startas\0" Required_argument "a"
391 "name\0" Required_argument "n"
392 "signal\0" Required_argument "s"
393 "user\0" Required_argument "u"
394 "chuid\0" Required_argument "c"
395 "exec\0" Required_argument "x"
396 "pidfile\0" Required_argument "p"
397#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
398 "retry\0" Required_argument "R"
399#endif
400 ;
401#endif
402
403int start_stop_daemon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
404int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
405{
406 unsigned opt;
407 char *signame;
408 char *startas;
409 char *chuid;
410#ifdef OLDER_VERSION_OF_X
411 struct stat execstat;
412#endif
413#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
414
415
416 char *opt_N;
417#endif
418
419 INIT_G();
420
421#if ENABLE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS
422 applet_long_options = start_stop_daemon_longopts;
423#endif
424
425
426
427
428
429
430 opt_complementary = "K:S:K--S:S--K:m?p:K?xpun:S?xa"
431 IF_FEATURE_START_STOP_DAEMON_FANCY("q-v");
432 opt = getopt32(argv, "KSbqtma:n:s:u:c:x:p:"
433 IF_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:"),
434 &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile
435 IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N)
436
437 IF_FEATURE_START_STOP_DAEMON_FANCY(,NULL)
438 );
439
440 if (opt & OPT_s) {
441 signal_nr = get_signum(signame);
442 if (signal_nr < 0) bb_show_usage();
443 }
444
445 if (!(opt & OPT_a))
446 startas = execname;
447 if (!execname)
448 execname = startas;
449 if (execname) {
450 G.execname_sizeof = strlen(execname) + 1;
451 G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1);
452 }
453
454
455
456
457
458
459 argv += optind;
460
461 if (userspec) {
462 user_id = bb_strtou(userspec, NULL, 10);
463 if (errno)
464 user_id = xuname2uid(userspec);
465 }
466
467 do_procinit();
468
469 if (opt & CTX_STOP) {
470 int i = do_stop();
471 return (opt & OPT_OKNODO) ? 0 : (i <= 0);
472 }
473
474 if (G.found_procs) {
475 if (!QUIET)
476 printf("%s is already running\n%u\n", execname, (unsigned)G.found_procs->pid);
477 return !(opt & OPT_OKNODO);
478 }
479
480#ifdef OLDER_VERSION_OF_X
481 if (execname)
482 xstat(execname, &execstat);
483#endif
484
485 *--argv = startas;
486 if (opt & OPT_BACKGROUND) {
487#if BB_MMU
488 bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS + DAEMON_DOUBLE_FORK);
489
490
491#else
492 pid_t pid = xvfork();
493 if (pid != 0) {
494
495
496
497 _exit(EXIT_SUCCESS);
498 }
499
500 setsid();
501
502
503 bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO
504 + DAEMON_CLOSE_EXTRA_FDS
505 + DAEMON_ONLY_SANITIZE,
506 NULL );
507#endif
508 }
509 if (opt & OPT_MAKEPID) {
510
511 write_pidfile(pidfile);
512 }
513 if (opt & OPT_c) {
514 struct bb_uidgid_t ugid = { -1, -1 };
515 parse_chown_usergroup_or_die(&ugid, chuid);
516 if (ugid.uid != (uid_t) -1) {
517 struct passwd *pw = xgetpwuid(ugid.uid);
518 if (ugid.gid != (gid_t) -1)
519 pw->pw_gid = ugid.gid;
520
521 change_identity(pw);
522 } else if (ugid.gid != (gid_t) -1) {
523 xsetgid(ugid.gid);
524 setgroups(1, &ugid.gid);
525 }
526 }
527#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
528 if (opt & OPT_NICELEVEL) {
529
530 int prio = getpriority(PRIO_PROCESS, 0) + xatoi_range(opt_N, INT_MIN/2, INT_MAX/2);
531 if (setpriority(PRIO_PROCESS, 0, prio) < 0) {
532 bb_perror_msg_and_die("setpriority(%d)", prio);
533 }
534 }
535#endif
536 execvp(startas, argv);
537 bb_perror_msg_and_die("can't execute '%s'", startas);
538}
539