diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2019-01-14 14:45:18 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2019-01-14 14:47:21 +0100 |
| commit | 088fec36fedff2cd50437c95b7fb430abf8d303c (patch) | |
| tree | f0dd190ed56fdf4b43710331e3527149903d87d2 | |
| parent | b67d900395a847e29f2afa81198f783004c80fc5 (diff) | |
| download | busybox-w32-088fec36fedff2cd50437c95b7fb430abf8d303c.tar.gz busybox-w32-088fec36fedff2cd50437c95b7fb430abf8d303c.tar.bz2 busybox-w32-088fec36fedff2cd50437c95b7fb430abf8d303c.zip | |
start-stop-daemon: create pidfile before parent exits, closes 8596
This removes DAEMON_DOUBLE_FORK flag from bb_daemonize_or_rexec(),
as SSD was the only user.
Also includes fix for -S: now works without -a and -x,
does not print pids
(compat with "start-stop-daemon (OpenRC) 0.34.11 (Gentoo Linux)").
function old new delta
start_stop_daemon_main 1018 1084 +66
add_interface 99 103 +4
fail_hunk 139 136 -3
bb_daemonize_or_rexec 205 183 -22
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/2 up/down: 70/-25) Total: 45 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | debianutils/start_stop_daemon.c | 66 | ||||
| -rw-r--r-- | include/libbb.h | 10 | ||||
| -rw-r--r-- | libbb/vfork_daemon_rexec.c | 16 | ||||
| -rwxr-xr-x | testsuite/start-stop-daemon.tests | 5 |
4 files changed, 62 insertions, 35 deletions
diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 43b6fca26..fa08f48cf 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c | |||
| @@ -409,7 +409,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
| 409 | { | 409 | { |
| 410 | unsigned opt; | 410 | unsigned opt; |
| 411 | char *signame; | 411 | char *signame; |
| 412 | char *startas; | 412 | char *startas = NULL; |
| 413 | char *chuid; | 413 | char *chuid; |
| 414 | #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY | 414 | #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY |
| 415 | // char *retry_arg = NULL; | 415 | // char *retry_arg = NULL; |
| @@ -425,10 +425,11 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
| 425 | /* -K or -S is required; they are mutually exclusive */ | 425 | /* -K or -S is required; they are mutually exclusive */ |
| 426 | /* -p is required if -m is given */ | 426 | /* -p is required if -m is given */ |
| 427 | /* -xpun (at least one) is required if -K is given */ | 427 | /* -xpun (at least one) is required if -K is given */ |
| 428 | /* -xa (at least one) is required if -S 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 | ||
| 429 | /* -q turns off -v */ | 430 | /* -q turns off -v */ |
| 430 | "\0" | 431 | "\0" |
| 431 | "K:S:K--S:S--K:m?p:K?xpun:S?xa" | 432 | "K:S:K--S:S--K:m?p:K?xpun" |
| 432 | IF_FEATURE_START_STOP_DAEMON_FANCY("q-v"), | 433 | IF_FEATURE_START_STOP_DAEMON_FANCY("q-v"), |
| 433 | LONGOPTS | 434 | LONGOPTS |
| 434 | &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile | 435 | &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile |
| @@ -442,21 +443,34 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
| 442 | if (signal_nr < 0) bb_show_usage(); | 443 | if (signal_nr < 0) bb_show_usage(); |
| 443 | } | 444 | } |
| 444 | 445 | ||
| 445 | if (!(opt & OPT_a)) | 446 | //argc -= optind; |
| 446 | startas = execname; | 447 | argv += optind; |
| 447 | if (!execname) /* in case -a is given and -x is not */ | 448 | // ARGS contains zeroth arg if -x/-a is not given, else it starts with 1st arg. |
| 449 | // These will try to execute "[/bin/]sleep 5": | ||
| 450 | // "start-stop-daemon -S -- sleep 5" | ||
| 451 | // "start-stop-daemon -S -x /bin/sleep -- 5" | ||
| 452 | // "start-stop-daemon -S -a sleep -- 5" | ||
| 453 | // NB: -n option does _not_ behave in this way: this will try to execute "5": | ||
| 454 | // "start-stop-daemon -S -n sleep -- 5" | ||
| 455 | if (!execname) { /* -x is not given */ | ||
| 448 | execname = startas; | 456 | execname = startas; |
| 449 | if (execname) { | 457 | if (!execname) { /* neither -x nor -a is given */ |
| 450 | G.execname_sizeof = strlen(execname) + 1; | 458 | execname = argv[0]; |
| 451 | G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1); | 459 | if (!execname) |
| 460 | bb_show_usage(); | ||
| 461 | argv++; | ||
| 462 | } | ||
| 452 | } | 463 | } |
| 464 | if (!startas) /* -a is not given: use -x EXECUTABLE or argv[0] */ | ||
| 465 | startas = execname; | ||
| 466 | *--argv = startas; | ||
| 467 | G.execname_sizeof = strlen(execname) + 1; | ||
| 468 | G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1); | ||
| 453 | 469 | ||
| 454 | // IF_FEATURE_START_STOP_DAEMON_FANCY( | 470 | // IF_FEATURE_START_STOP_DAEMON_FANCY( |
| 455 | // if (retry_arg) | 471 | // if (retry_arg) |
| 456 | // retries = xatoi_positive(retry_arg); | 472 | // retries = xatoi_positive(retry_arg); |
| 457 | // ) | 473 | // ) |
| 458 | //argc -= optind; | ||
| 459 | argv += optind; | ||
| 460 | 474 | ||
| 461 | if (userspec) { | 475 | if (userspec) { |
| 462 | user_id = bb_strtou(userspec, NULL, 10); | 476 | user_id = bb_strtou(userspec, NULL, 10); |
| @@ -473,7 +487,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
| 473 | 487 | ||
| 474 | if (G.found_procs) { | 488 | if (G.found_procs) { |
| 475 | if (!QUIET) | 489 | if (!QUIET) |
| 476 | printf("%s is already running\n%u\n", execname, (unsigned)G.found_procs->pid); | 490 | printf("%s is already running\n", execname); |
| 477 | return !(opt & OPT_OKNODO); | 491 | return !(opt & OPT_OKNODO); |
| 478 | } | 492 | } |
| 479 | 493 | ||
| @@ -482,30 +496,37 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
| 482 | xstat(execname, &G.execstat); | 496 | xstat(execname, &G.execstat); |
| 483 | #endif | 497 | #endif |
| 484 | 498 | ||
| 485 | *--argv = startas; | ||
| 486 | if (opt & OPT_BACKGROUND) { | 499 | if (opt & OPT_BACKGROUND) { |
| 487 | #if BB_MMU | ||
| 488 | bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS + DAEMON_DOUBLE_FORK); | ||
| 489 | /* DAEMON_DEVNULL_STDIO is superfluous - | ||
| 490 | * it's always done by bb_daemonize() */ | ||
| 491 | #else | ||
| 492 | /* Daemons usually call bb_daemonize_or_rexec(), but SSD can do | 500 | /* Daemons usually call bb_daemonize_or_rexec(), but SSD can do |
| 493 | * without: SSD is not itself a daemon, it _execs_ a daemon. | 501 | * without: SSD is not itself a daemon, it _execs_ a daemon. |
| 494 | * The usual NOMMU problem of "child can't run indefinitely, | 502 | * The usual NOMMU problem of "child can't run indefinitely, |
| 495 | * it must exec" does not bite us: we exec anyway. | 503 | * it must exec" does not bite us: we exec anyway. |
| 504 | * | ||
| 505 | * bb_daemonize(DAEMON_DEVNULL_STDIO | DAEMON_CLOSE_EXTRA_FDS | DAEMON_DOUBLE_FORK) | ||
| 506 | * can be used on MMU systems, but use of vfork() | ||
| 507 | * is preferable since we want to create pidfile | ||
| 508 | * _before_ parent returns, and vfork() on Linux | ||
| 509 | * ensures that (by blocking parent until exec in the child). | ||
| 496 | */ | 510 | */ |
| 497 | pid_t pid = xvfork(); | 511 | pid_t pid = xvfork(); |
| 498 | if (pid != 0) { | 512 | if (pid != 0) { |
| 499 | /* parent */ | 513 | /* Parent */ |
| 500 | /* why _exit? the child may have changed the stack, | 514 | /* why _exit? the child may have changed the stack, |
| 501 | * so "return 0" may do bad things */ | 515 | * so "return 0" may do bad things |
| 516 | */ | ||
| 502 | _exit(EXIT_SUCCESS); | 517 | _exit(EXIT_SUCCESS); |
| 503 | } | 518 | } |
| 504 | /* Child */ | 519 | /* Child */ |
| 505 | setsid(); /* detach from controlling tty */ | 520 | setsid(); /* detach from controlling tty */ |
| 506 | /* Redirect stdio to /dev/null, close extra FDs */ | 521 | /* Redirect stdio to /dev/null, close extra FDs */ |
| 507 | bb_daemon_helper(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); | 522 | bb_daemon_helper(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); |
| 508 | #endif | 523 | /* On Linux, session leader can acquire ctty |
| 524 | * unknowingly, by opening a tty. | ||
| 525 | * Prevent this: stop being a session leader. | ||
| 526 | */ | ||
| 527 | pid = xvfork(); | ||
| 528 | if (pid != 0) | ||
| 529 | _exit(EXIT_SUCCESS); /* Parent */ | ||
| 509 | } | 530 | } |
| 510 | if (opt & OPT_MAKEPID) { | 531 | if (opt & OPT_MAKEPID) { |
| 511 | /* User wants _us_ to make the pidfile */ | 532 | /* User wants _us_ to make the pidfile */ |
| @@ -534,6 +555,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
| 534 | } | 555 | } |
| 535 | } | 556 | } |
| 536 | #endif | 557 | #endif |
| 537 | execvp(startas, argv); | 558 | //bb_error_msg("HERE %d '%s'%s'", __LINE__, argv[0], argv[1]); |
| 559 | execvp(argv[0], argv); | ||
| 538 | bb_perror_msg_and_die("can't execute '%s'", startas); | 560 | bb_perror_msg_and_die("can't execute '%s'", startas); |
| 539 | } | 561 | } |
diff --git a/include/libbb.h b/include/libbb.h index d2563999a..3366df30f 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
| @@ -1201,11 +1201,11 @@ void set_task_comm(const char *comm) FAST_FUNC; | |||
| 1201 | * to /dev/null if they are not. | 1201 | * to /dev/null if they are not. |
| 1202 | */ | 1202 | */ |
| 1203 | enum { | 1203 | enum { |
| 1204 | DAEMON_CHDIR_ROOT = 1, | 1204 | DAEMON_CHDIR_ROOT = 1 << 0, |
| 1205 | DAEMON_DEVNULL_STDIO = 2, | 1205 | DAEMON_DEVNULL_STDIO = 1 << 1, |
| 1206 | DAEMON_CLOSE_EXTRA_FDS = 4, | 1206 | DAEMON_CLOSE_EXTRA_FDS = 1 << 2, |
| 1207 | DAEMON_ONLY_SANITIZE = 8, /* internal use */ | 1207 | DAEMON_ONLY_SANITIZE = 1 << 3, /* internal use */ |
| 1208 | DAEMON_DOUBLE_FORK = 16, /* double fork to avoid controlling tty */ | 1208 | //DAEMON_DOUBLE_FORK = 1 << 4, /* double fork to avoid controlling tty */ |
| 1209 | }; | 1209 | }; |
| 1210 | #if BB_MMU | 1210 | #if BB_MMU |
| 1211 | enum { re_execed = 0 }; | 1211 | enum { re_execed = 0 }; |
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index c0bea0ed2..1aac27b36 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c | |||
| @@ -292,14 +292,14 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv) | |||
| 292 | dup2(fd, 0); | 292 | dup2(fd, 0); |
| 293 | dup2(fd, 1); | 293 | dup2(fd, 1); |
| 294 | dup2(fd, 2); | 294 | dup2(fd, 2); |
| 295 | if (flags & DAEMON_DOUBLE_FORK) { | 295 | // if (flags & DAEMON_DOUBLE_FORK) { |
| 296 | /* On Linux, session leader can acquire ctty | 296 | // /* On Linux, session leader can acquire ctty |
| 297 | * unknowingly, by opening a tty. | 297 | // * unknowingly, by opening a tty. |
| 298 | * Prevent this: stop being a session leader. | 298 | // * Prevent this: stop being a session leader. |
| 299 | */ | 299 | // */ |
| 300 | if (fork_or_rexec(argv)) | 300 | // if (fork_or_rexec(argv)) |
| 301 | _exit(EXIT_SUCCESS); /* parent */ | 301 | // _exit(EXIT_SUCCESS); /* parent */ |
| 302 | } | 302 | // } |
| 303 | } | 303 | } |
| 304 | while (fd > 2) { | 304 | while (fd > 2) { |
| 305 | close(fd--); | 305 | close(fd--); |
diff --git a/testsuite/start-stop-daemon.tests b/testsuite/start-stop-daemon.tests index d07aeef0e..be1c1a856 100755 --- a/testsuite/start-stop-daemon.tests +++ b/testsuite/start-stop-daemon.tests | |||
| @@ -16,4 +16,9 @@ testing "start-stop-daemon -a without -x" \ | |||
| 16 | "1\n" \ | 16 | "1\n" \ |
| 17 | "" "" | 17 | "" "" |
| 18 | 18 | ||
| 19 | testing "start-stop-daemon without -x and -a" \ | ||
| 20 | 'start-stop-daemon -S false 2>&1; echo $?' \ | ||
| 21 | "1\n" \ | ||
| 22 | "" "" | ||
| 23 | |||
| 19 | exit $FAILCOUNT | 24 | exit $FAILCOUNT |
