diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2023-11-08 14:07:20 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2023-11-08 14:07:20 +0100 |
commit | 58ca629fd27cd9d7f91a8ea90435cdb3f15381aa (patch) | |
tree | 6cd26e1bd56e7eed350ff8fa3d4aeecf58ef3a22 | |
parent | 2de67a62e812f2e4d13280f2b78712b6d344cfb7 (diff) | |
download | busybox-w32-58ca629fd27cd9d7f91a8ea90435cdb3f15381aa.tar.gz busybox-w32-58ca629fd27cd9d7f91a8ea90435cdb3f15381aa.tar.bz2 busybox-w32-58ca629fd27cd9d7f91a8ea90435cdb3f15381aa.zip |
start-stop-daemon: do not lose error messages with -b
function old new delta
start_stop_daemon_main 1186 1206 +20
bb_daemonize_or_rexec 196 212 +16
bb_banner 47 46 -1
packed_usage 34656 34645 -11
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/2 up/down: 36/-12) Total: 24 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | debianutils/start_stop_daemon.c | 57 | ||||
-rw-r--r-- | include/libbb.h | 11 | ||||
-rw-r--r-- | libbb/vfork_daemon_rexec.c | 9 |
3 files changed, 41 insertions, 36 deletions
diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 04ba8baa7..00fa0a82c 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c | |||
@@ -71,7 +71,7 @@ Options which are valid for --start only: | |||
71 | done after the chroot if the -r|--chroot option is set. | 71 | done after the chroot if the -r|--chroot option is set. |
72 | When not specified, start-stop-daemon will change directory to the | 72 | When not specified, start-stop-daemon will change directory to the |
73 | root directory before starting the process. | 73 | root directory before starting the process. |
74 | ^^^^ Seems to be false, no default "/" chdir is done. | 74 | ^^^^ Gentoo does not have the default chdir("/"). Debian does. |
75 | Tested -S with 1.21.22: | 75 | Tested -S with 1.21.22: |
76 | "start-stop-daemon -S -x /bin/pwd" is the minimum needed to run pwd. | 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. | 77 | "start-stop-daemon -S -a /bin/pwd -n pwd" works too. |
@@ -111,7 +111,6 @@ Misc options: | |||
111 | //config: -o|--oknodo ignored since we exit with 0 anyway | 111 | //config: -o|--oknodo ignored since we exit with 0 anyway |
112 | //config: -v|--verbose | 112 | //config: -v|--verbose |
113 | //config: -N|--nicelevel N | 113 | //config: -N|--nicelevel N |
114 | //config: -O|--output FILE | ||
115 | 114 | ||
116 | //applet:IF_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, BB_DIR_SBIN, BB_SUID_DROP, start_stop_daemon)) | 115 | //applet:IF_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, BB_DIR_SBIN, BB_SUID_DROP, start_stop_daemon)) |
117 | /* not NOEXEC: uses bb_common_bufsiz1 */ | 116 | /* not NOEXEC: uses bb_common_bufsiz1 */ |
@@ -136,6 +135,7 @@ Misc options: | |||
136 | //usage: "\n -x EXECUTABLE Program to run" | 135 | //usage: "\n -x EXECUTABLE Program to run" |
137 | //usage: "\n -a NAME Zeroth argument" | 136 | //usage: "\n -a NAME Zeroth argument" |
138 | //usage: "\n -b Background" | 137 | //usage: "\n -b Background" |
138 | //usage: "\n -O FILE Append stdout and stderr to FILE" | ||
139 | //usage: IF_FEATURE_START_STOP_DAEMON_FANCY( | 139 | //usage: IF_FEATURE_START_STOP_DAEMON_FANCY( |
140 | //usage: "\n -N N Change nice level" | 140 | //usage: "\n -N N Change nice level" |
141 | //usage: ) | 141 | //usage: ) |
@@ -150,7 +150,6 @@ Misc options: | |||
150 | //usage: "\n -o Exit with status 0 if nothing is done" | 150 | //usage: "\n -o Exit with status 0 if nothing is done" |
151 | //usage: "\n -v Verbose" | 151 | //usage: "\n -v Verbose" |
152 | //usage: "\n -q Quiet" | 152 | //usage: "\n -q Quiet" |
153 | //usage: "\n -O FILE Append stdout and stderr to FILE" | ||
154 | //usage: ) | 153 | //usage: ) |
155 | 154 | ||
156 | /* Override ENABLE_FEATURE_PIDFILE */ | 155 | /* Override ENABLE_FEATURE_PIDFILE */ |
@@ -178,20 +177,20 @@ enum { | |||
178 | OPT_d = (1 << 11), // -d | 177 | OPT_d = (1 << 11), // -d |
179 | OPT_x = (1 << 12), // -x | 178 | OPT_x = (1 << 12), // -x |
180 | OPT_p = (1 << 13), // -p | 179 | OPT_p = (1 << 13), // -p |
181 | OPT_OKNODO = (1 << 14) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -o | 180 | OPT_OUTPUT = (1 << 14), // -O |
182 | OPT_VERBOSE = (1 << 15) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -v | 181 | OPT_OKNODO = (1 << 15) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -o |
183 | OPT_NICELEVEL = (1 << 16) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -N | 182 | OPT_VERBOSE = (1 << 16) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -v |
184 | OPT_OUTPUT = (1 << 17) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -O | 183 | OPT_NICELEVEL = (1 << 17) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -N |
185 | }; | 184 | }; |
186 | #define QUIET (option_mask32 & OPT_QUIET) | 185 | #define QUIET (option_mask32 & OPT_QUIET) |
187 | #define TEST (option_mask32 & OPT_TEST) | 186 | #define TEST (option_mask32 & OPT_TEST) |
188 | 187 | ||
189 | struct globals { | 188 | struct globals { |
190 | struct pid_list *found_procs; | 189 | struct pid_list *found_procs; |
191 | char *userspec; | 190 | const char *userspec; |
192 | char *cmdname; | 191 | const char *cmdname; |
193 | char *execname; | 192 | const char *execname; |
194 | char *pidfile; | 193 | const char *pidfile; |
195 | char *execname_cmpbuf; | 194 | char *execname_cmpbuf; |
196 | unsigned execname_sizeof; | 195 | unsigned execname_sizeof; |
197 | int user_id; | 196 | int user_id; |
@@ -361,7 +360,7 @@ static void do_procinit(void) | |||
361 | 360 | ||
362 | static int do_stop(void) | 361 | static int do_stop(void) |
363 | { | 362 | { |
364 | char *what; | 363 | const char *what; |
365 | struct pid_list *p; | 364 | struct pid_list *p; |
366 | int killed = 0; | 365 | int killed = 0; |
367 | 366 | ||
@@ -408,7 +407,7 @@ static int do_stop(void) | |||
408 | } | 407 | } |
409 | ret: | 408 | ret: |
410 | if (ENABLE_FEATURE_CLEAN_UP) | 409 | if (ENABLE_FEATURE_CLEAN_UP) |
411 | free(what); | 410 | free((char *)what); |
412 | return killed; | 411 | return killed; |
413 | } | 412 | } |
414 | 413 | ||
@@ -449,22 +448,22 @@ int start_stop_daemon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
449 | int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | 448 | int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) |
450 | { | 449 | { |
451 | unsigned opt; | 450 | unsigned opt; |
452 | char *signame; | 451 | const char *signame; |
453 | char *startas = NULL; | 452 | const char *startas = NULL; |
454 | char *chuid; | 453 | char *chuid; |
455 | char *chdir; | 454 | const char *chdir; |
455 | const char *output = NULL; | ||
456 | #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY | 456 | #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY |
457 | // char *retry_arg = NULL; | 457 | // const char *retry_arg = NULL; |
458 | // int retries = -1; | 458 | // int retries = -1; |
459 | char *opt_N; | 459 | const char *opt_N; |
460 | char *output; | ||
461 | #endif | 460 | #endif |
462 | 461 | ||
463 | INIT_G(); | 462 | INIT_G(); |
464 | 463 | ||
465 | opt = GETOPT32(argv, "^" | 464 | opt = GETOPT32(argv, "^" |
466 | "KSbqtma:n:s:u:c:d:x:p:" | 465 | "KSbqtma:n:s:u:c:d:x:p:O:" |
467 | IF_FEATURE_START_STOP_DAEMON_FANCY("ovN:O:R:") | 466 | IF_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:") |
468 | "\0" | 467 | "\0" |
469 | "K:S:K--S:S--K" | 468 | "K:S:K--S:S--K" |
470 | /* -K or -S is required; they are mutually exclusive */ | 469 | /* -K or -S is required; they are mutually exclusive */ |
@@ -479,9 +478,8 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
479 | IF_FEATURE_START_STOP_DAEMON_FANCY(":q-v") /* -q turns off -v */ | 478 | IF_FEATURE_START_STOP_DAEMON_FANCY(":q-v") /* -q turns off -v */ |
480 | , | 479 | , |
481 | LONGOPTS | 480 | LONGOPTS |
482 | &startas, &cmdname, &signame, &userspec, &chuid, &chdir, &execname, &pidfile | 481 | &startas, &cmdname, &signame, &userspec, &chuid, &chdir, &execname, &pidfile, &output |
483 | IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N) | 482 | IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N) |
484 | IF_FEATURE_START_STOP_DAEMON_FANCY(,&output) | ||
485 | /* We accept and ignore -R <param> / --retry <param> */ | 483 | /* We accept and ignore -R <param> / --retry <param> */ |
486 | IF_FEATURE_START_STOP_DAEMON_FANCY(,NULL) | 484 | IF_FEATURE_START_STOP_DAEMON_FANCY(,NULL) |
487 | ); | 485 | ); |
@@ -519,7 +517,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
519 | } | 517 | } |
520 | 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] */ |
521 | startas = execname; | 519 | startas = execname; |
522 | *--argv = startas; | 520 | *--argv = (char *)startas; |
523 | } | 521 | } |
524 | if (execname) { | 522 | if (execname) { |
525 | G.execname_sizeof = strlen(execname) + 1; | 523 | G.execname_sizeof = strlen(execname) + 1; |
@@ -578,8 +576,11 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
578 | } | 576 | } |
579 | /* Child */ | 577 | /* Child */ |
580 | setsid(); /* detach from controlling tty */ | 578 | setsid(); /* detach from controlling tty */ |
581 | /* Redirect stdio to /dev/null, close extra FDs */ | 579 | /* Redirect stdin to /dev/null, close extra FDs */ |
582 | 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 */ | ||
583 | /* On Linux, session leader can acquire ctty | 584 | /* On Linux, session leader can acquire ctty |
584 | * unknowingly, by opening a tty. | 585 | * unknowingly, by opening a tty. |
585 | * Prevent this: stop being a session leader. | 586 | * Prevent this: stop being a session leader. |
@@ -618,14 +619,12 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
618 | if (opt & OPT_d) { | 619 | if (opt & OPT_d) { |
619 | xchdir(chdir); | 620 | xchdir(chdir); |
620 | } | 621 | } |
621 | #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY | 622 | if (output) { |
622 | if (opt & OPT_OUTPUT) { | ||
623 | int outfd = xopen(output, O_WRONLY | O_CREAT | O_APPEND); | 623 | int outfd = xopen(output, O_WRONLY | O_CREAT | O_APPEND); |
624 | xmove_fd(outfd, STDOUT_FILENO); | 624 | xmove_fd(outfd, STDOUT_FILENO); |
625 | xdup2(STDOUT_FILENO, STDERR_FILENO); | 625 | xdup2(STDOUT_FILENO, STDERR_FILENO); |
626 | /* on execv error, the message goes to -O file. This is intended */ | 626 | /* on execv error, the message goes to -O file. This is intended */ |
627 | } | 627 | } |
628 | #endif | ||
629 | /* Try: | 628 | /* Try: |
630 | * 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 |
631 | * should exec "/bin/usleep", but argv[0] should be "qwerty": | 630 | * should exec "/bin/usleep", but argv[0] should be "qwerty": |
diff --git a/include/libbb.h b/include/libbb.h index 0883fb565..ef5d04713 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -1309,10 +1309,12 @@ void _exit_FAILURE(void) NORETURN FAST_FUNC; | |||
1309 | */ | 1309 | */ |
1310 | enum { | 1310 | enum { |
1311 | DAEMON_CHDIR_ROOT = 1 << 0, | 1311 | DAEMON_CHDIR_ROOT = 1 << 0, |
1312 | DAEMON_DEVNULL_STDIO = 1 << 1, | 1312 | DAEMON_DEVNULL_STDIN = 1 << 1, |
1313 | DAEMON_CLOSE_EXTRA_FDS = 1 << 2, | 1313 | DAEMON_DEVNULL_OUTERR = 2 << 1, |
1314 | DAEMON_ONLY_SANITIZE = 1 << 3, /* internal use */ | 1314 | DAEMON_DEVNULL_STDIO = 3 << 1, |
1315 | //DAEMON_DOUBLE_FORK = 1 << 4, /* double fork to avoid controlling tty */ | 1315 | DAEMON_CLOSE_EXTRA_FDS = 1 << 3, |
1316 | DAEMON_ONLY_SANITIZE = 1 << 4, /* internal use */ | ||
1317 | //DAEMON_DOUBLE_FORK = 1 << 5, /* double fork to avoid controlling tty */ | ||
1316 | }; | 1318 | }; |
1317 | #if BB_MMU | 1319 | #if BB_MMU |
1318 | enum { re_execed = 0 }; | 1320 | enum { re_execed = 0 }; |
@@ -1335,6 +1337,7 @@ enum { | |||
1335 | # define bb_daemonize(a) BUG_bb_daemonize_is_unavailable_on_nommu() | 1337 | # define bb_daemonize(a) BUG_bb_daemonize_is_unavailable_on_nommu() |
1336 | #endif | 1338 | #endif |
1337 | void bb_daemonize_or_rexec(int flags, char **argv) FAST_FUNC; | 1339 | void bb_daemonize_or_rexec(int flags, char **argv) FAST_FUNC; |
1340 | /* Unlike bb_daemonize_or_rexec, these two helpers do not setsid: */ | ||
1338 | void bb_sanitize_stdio(void) FAST_FUNC; | 1341 | void bb_sanitize_stdio(void) FAST_FUNC; |
1339 | #define bb_daemon_helper(arg) bb_daemonize_or_rexec((arg) | DAEMON_ONLY_SANITIZE, NULL) | 1342 | #define bb_daemon_helper(arg) bb_daemonize_or_rexec((arg) | DAEMON_ONLY_SANITIZE, NULL) |
1340 | /* Clear dangerous stuff, set PATH. Return 1 if was run by different user. */ | 1343 | /* Clear dangerous stuff, set PATH. Return 1 if was run by different user. */ |
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index a570ddbf2..2055c4b71 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c | |||
@@ -296,9 +296,12 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv) | |||
296 | } | 296 | } |
297 | 297 | ||
298 | if (flags & DAEMON_DEVNULL_STDIO) { | 298 | if (flags & DAEMON_DEVNULL_STDIO) { |
299 | xdup2(fd, 0); | 299 | if (flags & DAEMON_DEVNULL_STDIN) |
300 | xdup2(fd, 1); | 300 | xdup2(fd, 0); |
301 | xdup2(fd, 2); | 301 | if (flags & DAEMON_DEVNULL_OUTERR) { |
302 | xdup2(fd, 1); | ||
303 | xdup2(fd, 2); | ||
304 | } | ||
302 | } else { | 305 | } else { |
303 | /* have 0,1,2 open at least to /dev/null */ | 306 | /* have 0,1,2 open at least to /dev/null */ |
304 | while ((unsigned)fd < 2) | 307 | while ((unsigned)fd < 2) |