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 |