diff --git a/include/libbb.h b/include/libbb.h index d79843a2d..2f24ecbc3 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1127,9 +1127,8 @@ enum { extern const char *msg_eol; extern smallint syslog_level; extern smallint logmode; -extern int die_sleep; extern uint8_t xfunc_error_retval; -extern jmp_buf die_jmp; +extern void (*die_func)(void); extern void xfunc_die(void) NORETURN FAST_FUNC; extern void bb_show_usage(void) NORETURN FAST_FUNC; extern void bb_error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; diff --git a/init/init.c b/init/init.c index b2fe85635..80c5d0f74 100644 --- a/init/init.c +++ b/init/init.c @@ -1015,6 +1015,11 @@ void handle_sigsegv(int sig, siginfo_t *info, void *ucontext) } #endif +static void sleep_much(void) +{ + sleep(30 * 24*60*60); +} + int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int init_main(int argc UNUSED_PARAM, char **argv) { @@ -1051,12 +1056,12 @@ int init_main(int argc UNUSED_PARAM, char **argv) /* If, say, xmalloc would ever die, we don't want to oops kernel * by exiting. - * NB: we set die_sleep *after* PID 1 check and bb_show_usage. + * NB: we set die_func *after* PID 1 check and bb_show_usage. * Otherwise, for example, "init u" ("please rexec yourself" * command for sysvinit) will show help text (which isn't too bad), * *and sleep forever* (which is bad!) */ - die_sleep = 30 * 24*60*60; + die_func = sleep_much; /* Figure out where the default console should be */ console_init(); diff --git a/libbb/fflush_stdout_and_exit.c b/libbb/fflush_stdout_and_exit.c index 9ad5dbf96..b4bed865f 100644 --- a/libbb/fflush_stdout_and_exit.c +++ b/libbb/fflush_stdout_and_exit.c @@ -15,15 +15,10 @@ void FAST_FUNC fflush_stdout_and_exit(int retval) { + xfunc_error_retval = retval; if (fflush(stdout)) bb_perror_msg_and_die(bb_msg_standard_output); - - if (ENABLE_FEATURE_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); + /* In case we are in NOFORK applet. Do not exit() directly, + * but use xfunc_die() */ + xfunc_die(); } diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index ed1f86f0c..d6ca7b263 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -69,28 +69,44 @@ pid_t FAST_FUNC xspawn(char **argv) } #if ENABLE_FEATURE_PREFER_APPLETS +static jmp_buf die_jmp; +static void jump(void) +{ + /* 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! + */ + /* | 0x100 allows to pass zero exitcode (longjmp can't pass 0). + * This works because exitcodes are bytes, + * run_nofork_applet() ensures that by "& 0xff" */ + longjmp(die_jmp, xfunc_error_retval | 0x100); +} + struct nofork_save_area { jmp_buf die_jmp; + void (*die_func)(void); const char *applet_name; uint32_t option_mask32; - int die_sleep; uint8_t xfunc_error_retval; }; static void save_nofork_data(struct nofork_save_area *save) { memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp)); + save->die_func = die_func; save->applet_name = applet_name; - save->xfunc_error_retval = xfunc_error_retval; save->option_mask32 = option_mask32; - save->die_sleep = die_sleep; + save->xfunc_error_retval = xfunc_error_retval; } static void restore_nofork_data(struct nofork_save_area *save) { memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp)); + die_func = save->die_func; applet_name = save->applet_name; - xfunc_error_retval = save->xfunc_error_retval; option_mask32 = save->option_mask32; - die_sleep = save->die_sleep; + xfunc_error_retval = save->xfunc_error_retval; } int FAST_FUNC run_nofork_applet(int applet_no, char **argv) @@ -133,11 +149,8 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) while (argv[argc]) argc++; - /* Special flag for xfunc_die(). If xfunc will "die" - * in NOFORK applet, xfunc_die() sees negative - * die_sleep and longjmp here instead. */ - die_sleep = -1; - + /* If xfunc "dies" in NOFORK applet, die_func longjmp's here instead */ + die_func = jump; rc = setjmp(die_jmp); if (!rc) { /* Some callers (xargs) @@ -146,10 +159,8 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0])); /* Finally we can call NOFORK applet's main() */ rc = applet_main[applet_no](argc, tmp_argv); - } else { /* xfunc died in NOFORK applet */ - /* in case they meant to return 0... */ - if (rc == -2222) - rc = 0; + } else { + /* xfunc died in NOFORK applet */ } /* Restoring some globals */ diff --git a/libbb/xfunc_die.c b/libbb/xfunc_die.c index 204e5e49d..73f7998e5 100644 --- a/libbb/xfunc_die.c +++ b/libbb/xfunc_die.c @@ -7,34 +7,16 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ -/* Keeping it separate allows to NOT suck in stdio for VERY small applets. +/* Keeping it separate allows to NOT pull in stdio for VERY small applets. * Try building busybox with only "true" enabled... */ #include "libbb.h" -int die_sleep; -#if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_HUSH -jmp_buf die_jmp; -#endif +void (*die_func)(void); void FAST_FUNC xfunc_die(void) { - if (die_sleep) { - if ((ENABLE_FEATURE_PREFER_APPLETS || ENABLE_HUSH) - && 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! - */ - /* -2222 means "zero" (longjmp can't pass 0) - * run_nofork_applet() catches -2222. */ - longjmp(die_jmp, xfunc_error_retval ? xfunc_error_retval : -2222); - } - sleep(die_sleep); - } + if (die_func) + die_func(); exit(xfunc_error_retval); } diff --git a/loginutils/getty.c b/loginutils/getty.c index 174542841..762d5c773 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -520,6 +520,11 @@ static void alarm_handler(int sig UNUSED_PARAM) _exit(EXIT_SUCCESS); } +static void sleep10(void) +{ + sleep(10); +} + int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int getty_main(int argc UNUSED_PARAM, char **argv) { @@ -599,7 +604,7 @@ int getty_main(int argc UNUSED_PARAM, char **argv) close(n--); /* Logging. We want special flavor of error_msg_and_die */ - die_sleep = 10; + die_func = sleep10; msg_eol = "\r\n"; /* most likely will internally use fd #3 in CLOEXEC mode: */ openlog(applet_name, LOG_PID, LOG_AUTH); diff --git a/shell/hush.c b/shell/hush.c index f085ed3eb..0d107715f 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1479,10 +1479,11 @@ static sighandler_t install_sighandler(int sig, sighandler_t handler) #if ENABLE_HUSH_JOB +static void xfunc_has_died(void); /* After [v]fork, in child: do not restore tty pgrp on xfunc death */ -# define disable_restore_tty_pgrp_on_exit() (die_sleep = 0) +# define disable_restore_tty_pgrp_on_exit() (die_func = NULL) /* After [v]fork, in parent: restore tty pgrp on xfunc death */ -# define enable_restore_tty_pgrp_on_exit() (die_sleep = -1) +# define enable_restore_tty_pgrp_on_exit() (die_func = xfunc_has_died) /* Restores tty foreground process group, and exits. * May be called as signal handler for fatal signal @@ -1587,6 +1588,15 @@ static void hush_exit(int exitcode) #endif } +static void xfunc_has_died(void) NORETURN; +static void xfunc_has_died(void) +{ + /* xfunc has failed! die die die */ + /* no EXIT traps, this is an escape hatch! */ + G.exiting = 1; + hush_exit(xfunc_error_retval); +} + //TODO: return a mask of ALL handled sigs? static int check_and_run_traps(void) @@ -7866,12 +7876,7 @@ int hush_main(int argc, char **argv) /* Initialize some more globals to non-zero values */ cmdedit_update_prompt(); - if (setjmp(die_jmp)) { - /* xfunc has failed! die die die */ - /* no EXIT traps, this is an escape hatch! */ - G.exiting = 1; - hush_exit(xfunc_error_retval); - } + die_func = xfunc_has_died; /* Shell is non-interactive at first. We need to call * install_special_sighandlers() if we are going to execute "sh