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;
}
#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)
{
/* 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();
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();
}
}
#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)
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)
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 */
* 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);
}
_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)
{
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);
#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
#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)
/* 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 <script>",
/* Grab control of the terminal */
tcsetpgrp(G_interactive_fd, getpid());
}
- /* -1 is special - makes xfuncs longjmp, not exit
- * (we reset die_sleep = 0 whereever we [v]fork) */
- enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */
+ enable_restore_tty_pgrp_on_exit();
# if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0
{