diff options
Diffstat (limited to 'debianutils/start_stop_daemon.c')
-rw-r--r-- | debianutils/start_stop_daemon.c | 131 |
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 | /* |
12 | This is how it is supposed to work: | 12 | This is how it is supposed to work: |
13 | 13 | ||
14 | start-stop-daemon [OPTIONS] [--start|--stop] [[--] arguments...] | 14 | start-stop-daemon [OPTIONS] [--start|--stop] [[--] ARGS] |
15 | 15 | ||
16 | One (only) of these must be given: | 16 | One (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 | ||
20 | Search for matching processes. | 25 | Search for matching processes. |
21 | If --stop is given, stop all matching processes (by sending a signal). | 26 | If --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 | ||
40 | Options which are valid for --start only: | 47 | Options 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 | ||
49 | Options which are valid for --stop only: | 81 | Options 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 | ||
54 | Misc options: | 88 | Misc 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 | ||
150 | struct globals { | 188 | struct 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 | ||
323 | static int do_stop(void) | 361 | static 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; | |||
408 | int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | 448 | int 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": |