aboutsummaryrefslogtreecommitdiff
path: root/debianutils/start_stop_daemon.c
diff options
context:
space:
mode:
Diffstat (limited to 'debianutils/start_stop_daemon.c')
-rw-r--r--debianutils/start_stop_daemon.c131
1 files changed, 98 insertions, 33 deletions
diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c
index 3e5dd9faa..271bc4edf 100644
--- a/debianutils/start_stop_daemon.c
+++ b/debianutils/start_stop_daemon.c
@@ -11,11 +11,16 @@
11/* 11/*
12This is how it is supposed to work: 12This is how it is supposed to work:
13 13
14start-stop-daemon [OPTIONS] [--start|--stop] [[--] arguments...] 14start-stop-daemon [OPTIONS] [--start|--stop] [[--] ARGS]
15 15
16One (only) of these must be given: 16One (only) of these must be given:
17 -S,--start Start 17 -S,--start Start
18 -K,--stop Stop 18 -K,--stop Stop
19 -T,--status Check for the existence of a process, return exitcode (since version 1.16.1)
20 0 - program is running
21 1 - program is not running and the pid file exists
22 3 - program is not running
23 4 - can't determine program status
19 24
20Search for matching processes. 25Search for matching processes.
21If --stop is given, stop all matching processes (by sending a signal). 26If --stop is given, stop all matching processes (by sending a signal).
@@ -36,20 +41,49 @@ with /proc/$PID/exe or argv[0] (comm can't be matched, it never contains path)]
36 Unlike -n, we match against the full path: 41 Unlike -n, we match against the full path:
37 "ntpd" != "./ntpd" != "/path/to/ntpd" 42 "ntpd" != "./ntpd" != "/path/to/ntpd"
38 -p,--pidfile PID_FILE Look for processes with PID from this file 43 -p,--pidfile PID_FILE Look for processes with PID from this file
44 --pid PID Look for process with this pid (since version 1.17.6)
45 --ppid PPID Look for processes with parent pid (since version 1.17.7)
39 46
40Options which are valid for --start only: 47Options which are valid for --start only:
41 -x,--exec EXECUTABLE Program to run (1st arg of execvp). Mandatory. 48 -x,--exec EXECUTABLE Program to run (1st arg of execvp).
49 If no -x, EXECUTABLE is taken from ARGS[0]
42 -a,--startas NAME argv[0] (defaults to EXECUTABLE) 50 -a,--startas NAME argv[0] (defaults to EXECUTABLE)
43 -b,--background Put process into background 51 -b,--background Put process into background
52 -O,--output FILE Redirect stdout and stderr to FILE when forcing the
53 daemon into the background (since version 1.20.6).
54 Requires --background and absolute pathname (tested with 1.21.22).
55 Uses O_CREAT|O_APPEND!
56 If execv fails, error message goes to FILE.
44 -N,--nicelevel N Add N to process' nice level 57 -N,--nicelevel N Add N to process' nice level
45 -c,--chuid USER[:[GRP]] Change to specified user [and group] 58 -c,--chuid USER[:[GRP]] Change to specified user [and group]
46 -m,--make-pidfile Write PID to the pidfile 59 -m,--make-pidfile Write PID to the pidfile
47 (both -m and -p must be given!) 60 (both -m and -p must be given!)
61 -P,--procsched policy:priority
62 This alters the process scheduler policy and priority of the
63 process before starting it (since version 1.15.0). The
64 priority can be optionally specified by appending a :
65 followed by the value. The default priority is 0. The
66 currently supported policy values are other, fifo and rr.
67 -r,--chroot DIR Change directory and chroot to DIR before starting the
68 process. Please note that the pidfile is also written after
69 the chroot.
70 -d,--chdir DIR Change directory to DIR before starting the process. This is
71 done after the chroot if the -r|--chroot option is set.
72 When not specified, start-stop-daemon will change directory to the
73 root directory before starting the process.
74 ^^^^ Gentoo does not have the default chdir("/"). Debian does.
75 Tested -S with 1.21.22:
76 "start-stop-daemon -S -x /bin/pwd" is the minimum needed to run pwd.
77 "start-stop-daemon -S -a /bin/pwd -n pwd" works too.
78 "start-stop-daemon -S -a /bin/pwd" does NOT work.
79 Earlier versions were less picky (which? Or is it only Gentoo's clone?)
48 80
49Options which are valid for --stop only: 81Options which are valid for --stop only:
50 -s,--signal SIG Signal to send (default:TERM) 82 -s,--signal SIG Signal to send (default:TERM)
51 -t,--test Exit with status 0 if process is found 83 -t,--test Exit with status 0 if process is found
52 (we don't actually start or stop daemons) 84 (we don't actually start or stop daemons)
85 --remove-pidfile Used when stopping a program that does not remove its own pid
86 file (since version 1.17.19). Requires -p PIDFILE?
53 87
54Misc options: 88Misc options:
55 -o,--oknodo Exit with status 0 if nothing is done 89 -o,--oknodo Exit with status 0 if nothing is done
@@ -84,11 +118,11 @@ Misc options:
84//kbuild:lib-$(CONFIG_START_STOP_DAEMON) += start_stop_daemon.o 118//kbuild:lib-$(CONFIG_START_STOP_DAEMON) += start_stop_daemon.o
85 119
86//usage:#define start_stop_daemon_trivial_usage 120//usage:#define start_stop_daemon_trivial_usage
87//usage: "[OPTIONS] [-S|-K] ... [-- ARGS...]" 121//usage: "-S|-K [OPTIONS] [-- ARGS]"
88//usage:#define start_stop_daemon_full_usage "\n\n" 122//usage:#define start_stop_daemon_full_usage "\n\n"
89//usage: "Search for matching processes, and then\n" 123//usage: "Search for matching processes, and then\n"
90//usage: "-K: stop all matching processes\n"
91//usage: "-S: start a process unless a matching process is found\n" 124//usage: "-S: start a process unless a matching process is found\n"
125//usage: "-K: stop all matching processes\n"
92//usage: "\nProcess matching:" 126//usage: "\nProcess matching:"
93//usage: "\n -u USERNAME|UID Match only this user's processes" 127//usage: "\n -u USERNAME|UID Match only this user's processes"
94//usage: "\n -n NAME Match processes with NAME" 128//usage: "\n -n NAME Match processes with NAME"
@@ -101,10 +135,12 @@ Misc options:
101//usage: "\n -x EXECUTABLE Program to run" 135//usage: "\n -x EXECUTABLE Program to run"
102//usage: "\n -a NAME Zeroth argument" 136//usage: "\n -a NAME Zeroth argument"
103//usage: "\n -b Background" 137//usage: "\n -b Background"
138//usage: "\n -O FILE Append stdout and stderr to FILE"
104//usage: IF_FEATURE_START_STOP_DAEMON_FANCY( 139//usage: IF_FEATURE_START_STOP_DAEMON_FANCY(
105//usage: "\n -N N Change nice level" 140//usage: "\n -N N Change nice level"
106//usage: ) 141//usage: )
107//usage: "\n -c USER[:[GRP]] Change user/group" 142//usage: "\n -c USER[:[GRP]] Change user/group"
143//usage: "\n -d DIR Change to DIR"
108//usage: "\n -m Write PID to pidfile specified by -p" 144//usage: "\n -m Write PID to pidfile specified by -p"
109//usage: "\n-K only:" 145//usage: "\n-K only:"
110//usage: "\n -s SIG Signal to send" 146//usage: "\n -s SIG Signal to send"
@@ -113,8 +149,8 @@ Misc options:
113//usage: IF_FEATURE_START_STOP_DAEMON_FANCY( 149//usage: IF_FEATURE_START_STOP_DAEMON_FANCY(
114//usage: "\n -o Exit with status 0 if nothing is done" 150//usage: "\n -o Exit with status 0 if nothing is done"
115//usage: "\n -v Verbose" 151//usage: "\n -v Verbose"
116//usage: )
117//usage: "\n -q Quiet" 152//usage: "\n -q Quiet"
153//usage: )
118 154
119/* Override ENABLE_FEATURE_PIDFILE */ 155/* Override ENABLE_FEATURE_PIDFILE */
120#define WANT_PIDFILE 1 156#define WANT_PIDFILE 1
@@ -138,21 +174,23 @@ enum {
138 OPT_s = (1 << 8), // -s 174 OPT_s = (1 << 8), // -s
139 OPT_u = (1 << 9), // -u 175 OPT_u = (1 << 9), // -u
140 OPT_c = (1 << 10), // -c 176 OPT_c = (1 << 10), // -c
141 OPT_x = (1 << 11), // -x 177 OPT_d = (1 << 11), // -d
142 OPT_p = (1 << 12), // -p 178 OPT_x = (1 << 12), // -x
143 OPT_OKNODO = (1 << 13) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -o 179 OPT_p = (1 << 13), // -p
144 OPT_VERBOSE = (1 << 14) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -v 180 OPT_OUTPUT = (1 << 14), // -O
145 OPT_NICELEVEL = (1 << 15) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -N 181 OPT_OKNODO = (1 << 15) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -o
182 OPT_VERBOSE = (1 << 16) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -v
183 OPT_NICELEVEL = (1 << 17) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -N
146}; 184};
147#define QUIET (option_mask32 & OPT_QUIET) 185#define QUIET (option_mask32 & OPT_QUIET)
148#define TEST (option_mask32 & OPT_TEST) 186#define TEST (option_mask32 & OPT_TEST)
149 187
150struct globals { 188struct globals {
151 struct pid_list *found_procs; 189 struct pid_list *found_procs;
152 char *userspec; 190 const char *userspec;
153 char *cmdname; 191 const char *cmdname;
154 char *execname; 192 const char *execname;
155 char *pidfile; 193 const char *pidfile;
156 char *execname_cmpbuf; 194 char *execname_cmpbuf;
157 unsigned execname_sizeof; 195 unsigned execname_sizeof;
158 int user_id; 196 int user_id;
@@ -322,7 +360,7 @@ static void do_procinit(void)
322 360
323static int do_stop(void) 361static int do_stop(void)
324{ 362{
325 char *what; 363 const char *what;
326 struct pid_list *p; 364 struct pid_list *p;
327 int killed = 0; 365 int killed = 0;
328 366
@@ -369,7 +407,7 @@ static int do_stop(void)
369 } 407 }
370 ret: 408 ret:
371 if (ENABLE_FEATURE_CLEAN_UP) 409 if (ENABLE_FEATURE_CLEAN_UP)
372 free(what); 410 free((char *)what);
373 return killed; 411 return killed;
374} 412}
375 413
@@ -381,6 +419,7 @@ static const char start_stop_daemon_longopts[] ALIGN1 =
381 "quiet\0" No_argument "q" 419 "quiet\0" No_argument "q"
382 "test\0" No_argument "t" 420 "test\0" No_argument "t"
383 "make-pidfile\0" No_argument "m" 421 "make-pidfile\0" No_argument "m"
422 "output\0" Required_argument "O"
384# if ENABLE_FEATURE_START_STOP_DAEMON_FANCY 423# if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
385 "oknodo\0" No_argument "o" 424 "oknodo\0" No_argument "o"
386 "verbose\0" No_argument "v" 425 "verbose\0" No_argument "v"
@@ -391,6 +430,7 @@ static const char start_stop_daemon_longopts[] ALIGN1 =
391 "signal\0" Required_argument "s" 430 "signal\0" Required_argument "s"
392 "user\0" Required_argument "u" 431 "user\0" Required_argument "u"
393 "chuid\0" Required_argument "c" 432 "chuid\0" Required_argument "c"
433 "chdir\0" Required_argument "d"
394 "exec\0" Required_argument "x" 434 "exec\0" Required_argument "x"
395 "pidfile\0" Required_argument "p" 435 "pidfile\0" Required_argument "p"
396# if ENABLE_FEATURE_START_STOP_DAEMON_FANCY 436# if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
@@ -408,36 +448,49 @@ int start_stop_daemon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
408int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) 448int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
409{ 449{
410 unsigned opt; 450 unsigned opt;
411 char *signame; 451 const char *signame;
412 char *startas = NULL; 452 const char *startas = NULL;
413 char *chuid; 453 char *chuid;
454 const char *chdir;
455 const char *output = NULL;
414#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY 456#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
415// char *retry_arg = NULL; 457// const char *retry_arg = NULL;
416// int retries = -1; 458// int retries = -1;
417 char *opt_N; 459 const char *opt_N;
418#endif 460#endif
419 461
420 INIT_G(); 462 INIT_G();
421 463
422 opt = GETOPT32(argv, "^" 464 opt = GETOPT32(argv, "^"
423 "KSbqtma:n:s:u:c:x:p:" 465 "KSbqtma:n:s:u:c:d:x:p:O:"
424 IF_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:") 466 IF_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:")
425 /* -K or -S is required; they are mutually exclusive */
426 /* -p is required if -m is given */
427 /* -xpun (at least one) is required if -K is given */
428// /* -xa (at least one) is required if -S is given */
429//WRONG: "start-stop-daemon -S -- sleep 5" is a valid invocation
430 /* -q turns off -v */
431 "\0" 467 "\0"
432 "K:S:K--S:S--K:m?p:K?xpun" 468 "K:S:K--S:S--K"
433 IF_FEATURE_START_STOP_DAEMON_FANCY("q-v"), 469 /* -K or -S is required; they are mutually exclusive */
470 ":m?p" /* -p is required if -m is given */
471 ":K?xpun" /* -xpun (at least one) is required if -K is given */
472 /* (the above does not seem to be enforced by Gentoo, it does nothing
473 * if no matching is specified with -K, and it ignores ARGS
474 * - does not take ARGS[0] as program name to kill)
475 */
476// ":S?xa" /* -xa (at least one) is required if -S is given */
477//Gentoo clone: "start-stop-daemon -S -- sleep 5" is a valid invocation
478 IF_FEATURE_START_STOP_DAEMON_FANCY(":q-v") /* -q turns off -v */
479 ,
434 LONGOPTS 480 LONGOPTS
435 &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile 481 &startas, &cmdname, &signame, &userspec, &chuid, &chdir, &execname, &pidfile, &output
436 IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N) 482 IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N)
437 /* We accept and ignore -R <param> / --retry <param> */ 483 /* We accept and ignore -R <param> / --retry <param> */
438 IF_FEATURE_START_STOP_DAEMON_FANCY(,NULL) 484 IF_FEATURE_START_STOP_DAEMON_FANCY(,NULL)
439 ); 485 );
440 486
487//-O requires --background and absolute pathname (tested with 1.21.22).
488//We don't bother requiring that (smaller code):
489//#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
490// if ((opt & OPT_OUTPUT) && !(opt & OPT_BACKGROUND))
491// bb_show_usage();
492//#endif
493
441 if (opt & OPT_s) { 494 if (opt & OPT_s) {
442 signal_nr = get_signum(signame); 495 signal_nr = get_signum(signame);
443 if (signal_nr < 0) bb_show_usage(); 496 if (signal_nr < 0) bb_show_usage();
@@ -464,7 +517,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
464 } 517 }
465 if (!startas) /* -a is not given: use -x EXECUTABLE or argv[0] */ 518 if (!startas) /* -a is not given: use -x EXECUTABLE or argv[0] */
466 startas = execname; 519 startas = execname;
467 *--argv = startas; 520 *--argv = (char *)startas;
468 } 521 }
469 if (execname) { 522 if (execname) {
470 G.execname_sizeof = strlen(execname) + 1; 523 G.execname_sizeof = strlen(execname) + 1;
@@ -523,8 +576,11 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
523 } 576 }
524 /* Child */ 577 /* Child */
525 setsid(); /* detach from controlling tty */ 578 setsid(); /* detach from controlling tty */
526 /* Redirect stdio to /dev/null, close extra FDs */ 579 /* Redirect stdin to /dev/null, close extra FDs */
527 bb_daemon_helper(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); 580 /* Testcase: "start-stop-daemon -Sb -d /does/not/exist usleep 1" should not eat error message */
581 bb_daemon_helper(DAEMON_DEVNULL_STDIN + DAEMON_CLOSE_EXTRA_FDS);
582 if (!output)
583 output = bb_dev_null; /* redirect output just before execv */
528 /* On Linux, session leader can acquire ctty 584 /* On Linux, session leader can acquire ctty
529 * unknowingly, by opening a tty. 585 * unknowingly, by opening a tty.
530 * Prevent this: stop being a session leader. 586 * Prevent this: stop being a session leader.
@@ -560,6 +616,15 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
560 setgroups(1, &ugid.gid); 616 setgroups(1, &ugid.gid);
561 } 617 }
562 } 618 }
619 if (opt & OPT_d) {
620 xchdir(chdir);
621 }
622 if (output) {
623 int outfd = xopen(output, O_WRONLY | O_CREAT | O_APPEND);
624 xmove_fd(outfd, STDOUT_FILENO);
625 xdup2(STDOUT_FILENO, STDERR_FILENO);
626 /* on execv error, the message goes to -O file. This is intended */
627 }
563 /* Try: 628 /* Try:
564 * strace -oLOG start-stop-daemon -S -x /bin/usleep -a qwerty 500000 629 * strace -oLOG start-stop-daemon -S -x /bin/usleep -a qwerty 500000
565 * should exec "/bin/usleep", but argv[0] should be "qwerty": 630 * should exec "/bin/usleep", but argv[0] should be "qwerty":