From 335b63d8d1876ce4e172ebcc9d64544785682244 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Tue, 10 Apr 2007 21:38:30 +0000 Subject: make a few struct bb_applet members conditional rename sllep_and_die -> xfunc_die make fflush_stdout_and_exit NOFORK-safe fix some buglets found by randomconfig --- libbb/copyfd.c | 4 ++-- libbb/error_msg_and_die.c | 21 ++++++++++++++++----- libbb/fflush_stdout_and_exit.c | 14 +++++++++----- libbb/herror_msg_and_die.c | 5 +---- libbb/perror_msg_and_die.c | 6 +----- libbb/vfork_daemon_rexec.c | 23 ++++++++++++++++++----- libbb/xconnect.c | 2 +- libbb/xfuncs.c | 2 +- 8 files changed, 49 insertions(+), 28 deletions(-) (limited to 'libbb') diff --git a/libbb/copyfd.c b/libbb/copyfd.c index e0596d5f6..aa8fbb967 100644 --- a/libbb/copyfd.c +++ b/libbb/copyfd.c @@ -74,7 +74,7 @@ void complain_copyfd_and_die(off_t sz) if (sz != -1) bb_error_msg_and_die("short read"); /* if sz == -1, bb_copyfd_XX already complained */ - sleep_and_die(); + xfunc_die(); } #endif @@ -94,7 +94,7 @@ void bb_copyfd_exact_size(int fd1, int fd2, off_t size) if (sz != -1) bb_error_msg_and_die("short read"); /* if sz == -1, bb_copyfd_XX already complained */ - sleep_and_die(); + xfunc_die(); } off_t bb_copyfd_eof(int fd1, int fd2) diff --git a/libbb/error_msg_and_die.c b/libbb/error_msg_and_die.c index 39178a3ce..4a9049364 100644 --- a/libbb/error_msg_and_die.c +++ b/libbb/error_msg_and_die.c @@ -10,14 +10,25 @@ #include "libbb.h" int die_sleep; +#if ENABLE_FEATURE_EXEC_PREFER_APPLETS jmp_buf die_jmp; +#endif -void sleep_and_die(void) +void xfunc_die(void) { if (die_sleep) { - /* Special case: don't die, but jump */ - if (die_sleep < 0) - longjmp(die_jmp, xfunc_error_retval); + if (ENABLE_FEATURE_EXEC_PREFER_APPLETS && die_sleep < 0) { + /* Special case. We arrive here if NOFORK applet + * calls xfunc, which then decides to die. + * We don't die, but jump instead back to caller. + * NOFORK applets still cannot carelessly call xfuncs: + * p = xmalloc(10); + * q = xmalloc(10); // BUG! if this dies, we leak p! + */ + /* -111 means "zero" (longjmp can't pass 0) + * spawn_and_wait() catches -111. */ + longjmp(die_jmp, xfunc_error_retval ? xfunc_error_retval : -111); + } sleep(die_sleep); } exit(xfunc_error_retval); @@ -30,5 +41,5 @@ void bb_error_msg_and_die(const char *s, ...) va_start(p, s); bb_verror_msg(s, p, NULL); va_end(p); - sleep_and_die(); + xfunc_die(); } diff --git a/libbb/fflush_stdout_and_exit.c b/libbb/fflush_stdout_and_exit.c index ae68222b4..d79827f45 100644 --- a/libbb/fflush_stdout_and_exit.c +++ b/libbb/fflush_stdout_and_exit.c @@ -13,13 +13,17 @@ #include "libbb.h" -// TODO: make it safe to call from NOFORK applets -// Currently, it can exit(0). Even if it is made to do longjmp trick -// (see sleep_and_die internals), zero cannot be passed thru this way! - void fflush_stdout_and_exit(int retval) { if (fflush(stdout)) - sleep_and_die(); + xfunc_die(); + + if (ENABLE_FEATURE_EXEC_PREFER_APPLETS && die_sleep < 0) { + /* We are in NOFORK applet. Do not exit() directly, + * but use xfunc_die() */ + xfunc_error_retval = retval; + xfunc_die(); + } + exit(retval); } diff --git a/libbb/herror_msg_and_die.c b/libbb/herror_msg_and_die.c index a7a22caf7..8c77378d7 100644 --- a/libbb/herror_msg_and_die.c +++ b/libbb/herror_msg_and_die.c @@ -7,9 +7,6 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include - #include "libbb.h" void bb_herror_msg_and_die(const char *s, ...) @@ -19,5 +16,5 @@ void bb_herror_msg_and_die(const char *s, ...) va_start(p, s); bb_vherror_msg(s, p); va_end(p); - sleep_and_die(); + xfunc_die(); } diff --git a/libbb/perror_msg_and_die.c b/libbb/perror_msg_and_die.c index 7521e7157..3a06b654b 100644 --- a/libbb/perror_msg_and_die.c +++ b/libbb/perror_msg_and_die.c @@ -7,10 +7,6 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include -#include -#include #include "libbb.h" void bb_perror_msg_and_die(const char *s, ...) @@ -20,5 +16,5 @@ void bb_perror_msg_and_die(const char *s, ...) va_start(p, s); bb_vperror_msg(s, p); va_end(p); - sleep_and_die(); + xfunc_die(); } diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 286ee2678..dabd1a6d6 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -16,7 +16,7 @@ */ #include -#include "busybox.h" /* for struct BB_applet */ +#include "busybox.h" /* for struct bb_applet */ /* This does a fork/exec in one call, using vfork(). Returns PID of new child, * -1 for failure. Runs argv[0], searching path if that has no / in it. */ @@ -104,8 +104,9 @@ int spawn_and_wait(char **argv) { int rc; - if (ENABLE_FEATURE_EXEC_PREFER_APPLETS) { - const struct BB_applet *a = find_applet_by_name(argv[0]); +#if ENABLE_FEATURE_EXEC_PREFER_APPLETS + { + const struct bb_applet *a = find_applet_by_name(argv[0]); if (a && (a->nofork #ifndef BB_NOMMU || a->noexec /* NOEXEC cannot be used on NOMMU */ @@ -120,19 +121,27 @@ int spawn_and_wait(char **argv) #endif { int old_sleep = die_sleep; + int old_x = xfunc_error_retval; die_sleep = -1; /* special flag */ - /* sleep_and_die() checks for it */ + /* xfunc_die() checks for it */ + rc = setjmp(die_jmp); if (!rc) { - const struct BB_applet *old_a = current_applet; + const struct bb_applet *old_a = current_applet; current_applet = a; applet_name = a->name; // what else should we save/restore? rc = a->main(argc, argv); current_applet = old_a; applet_name = old_a->name; + } else { + /* xfunc died in NOFORK applet */ + if (rc == -111) + rc = 0; } + die_sleep = old_sleep; + xfunc_error_retval = old_x; return rc; } #ifndef BB_NOMMU /* MMU only */ @@ -145,9 +154,13 @@ int spawn_and_wait(char **argv) run_current_applet_and_exit(argc, argv); #endif } + } rc = spawn(argv); w: +#else /* !FEATURE_EXEC_PREFER_APPLETS */ + rc = spawn(argv); +#endif /* FEATURE_EXEC_PREFER_APPLETS */ return wait4pid(rc); } diff --git a/libbb/xconnect.c b/libbb/xconnect.c index 8466325c7..e7d510678 100644 --- a/libbb/xconnect.c +++ b/libbb/xconnect.c @@ -166,7 +166,7 @@ USE_FEATURE_IPV6(sa_family_t af,) if (rc || !result) { bb_error_msg("bad address '%s'", org_host); if (ai_flags & DIE_ON_ERROR) - sleep_and_die(); + xfunc_die(); goto ret; } r = xmalloc(offsetof(len_and_sockaddr, sa) + result->ai_addrlen); diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index fa4a15236..b9d013a24 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c @@ -476,7 +476,7 @@ void xprint_and_close_file(FILE *file) fflush(stdout); // copyfd outputs error messages for us. if (bb_copyfd_eof(fileno(file), 1) == -1) - sleep_and_die(); + xfunc_die(); fclose(file); } -- cgit v1.2.3