From 18e19f2b0d36c0d9566d871942dfe282e9cf5a28 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Sat, 28 Apr 2007 16:43:18 +0000 Subject: [PATCH] hush: fix nofork + ctrl-Z clobbering of globals --- include/libbb.h | 14 ++++++++++++-- libbb/vfork_daemon_rexec.c | 41 +++++++++++++++++++++++++++++------------ shell/hush.c | 40 +++++++++++++++++----------------------- 3 files changed, 58 insertions(+), 37 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index fce10f3..9950c61 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -509,10 +509,20 @@ int wait_nohang(int *wstat); #define wait_exitcode(w) ((w) >> 8) #define wait_stopsig(w) ((w) >> 8) #define wait_stopped(w) (((w) & 127) == 127) -/* Does NOT check that applet is NOFORK, just blindly runs it */ -int run_nofork_applet(const struct bb_applet *a, char **argv); /* wait4pid(spawn(argv)) + NOFORK/NOEXEC (if configured) */ int spawn_and_wait(char **argv); +struct nofork_save_area { + const struct bb_applet *current_applet; + int xfunc_error_retval; + uint32_t option_mask32; + int die_sleep; + smallint saved; +}; +void save_nofork_data(struct nofork_save_area *save); +void restore_nofork_data(struct nofork_save_area *save); +/* Does NOT check that applet is NOFORK, just blindly runs it */ +int run_nofork_applet(const struct bb_applet *a, char **argv); +int run_nofork_applet_prime(struct nofork_save_area *old, const struct bb_applet *a, char **argv); /* Helpers for daemonization. * diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 78f3c4a..aef74e9 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -100,15 +100,28 @@ int wait_pid(int *wstat, int pid) return r; } -int run_nofork_applet(const struct bb_applet *a, char **argv) +void save_nofork_data(struct nofork_save_area *save) { - int rc, argc; + save->current_applet = current_applet; + save->xfunc_error_retval = xfunc_error_retval; + save->option_mask32 = option_mask32; + save->die_sleep = die_sleep; + save->saved = 1; +} - /* Save some shared globals */ - const struct bb_applet *old_a = current_applet; - int old_x = xfunc_error_retval; - uint32_t old_m = option_mask32; - int old_sleep = die_sleep; +void restore_nofork_data(struct nofork_save_area *save) +{ + current_applet = save->current_applet; + xfunc_error_retval = save->xfunc_error_retval; + option_mask32 = save->option_mask32; + die_sleep = save->die_sleep; + + applet_name = current_applet->name; +} + +int run_nofork_applet_prime(struct nofork_save_area *old, const struct bb_applet *a, char **argv) +{ + int rc, argc; current_applet = a; applet_name = a->name; @@ -138,14 +151,18 @@ int run_nofork_applet(const struct bb_applet *a, char **argv) } /* Restoring globals */ - current_applet = old_a; - applet_name = old_a->name; - xfunc_error_retval = old_x; - option_mask32 = old_m; - die_sleep = old_sleep; + restore_nofork_data(old); return rc; } +int run_nofork_applet(const struct bb_applet *a, char **argv) +{ + struct nofork_save_area old; + /* Saving globals */ + save_nofork_data(&old); + return run_nofork_applet_prime(&old, a, argv); +} + int spawn_and_wait(char **argv) { int rc; diff --git a/shell/hush.c b/shell/hush.c index c87f3b5..b2ff0cb 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -441,30 +441,28 @@ static void signal_SA_RESTART(int sig, void (*handler)(int)) sigaction(sig, &sa, NULL); } +struct nofork_save_area nofork_save; static sigjmp_buf nofork_jb; -static smallint nofork_flag; static struct pipe *nofork_pipe; static void handler_ctrl_z(int sig) { pid_t pid; - fprintf(stderr, "got tty sig %d\n", sig); - if (!nofork_flag) - return; + debug_jobs_printf("got tty sig %d\n", sig); pid = fork(); if (pid < 0) /* can't fork. Pretend there were no Ctrl-Z */ return; - fprintf(stderr, "bg'ing nofork\n"); - nofork_flag = 0; + debug_jobs_printf("bg'ing nofork\n"); + nofork_save.saved = 0; /* flag the fact that Ctrl-Z was handled */ nofork_pipe->running_progs = 1; nofork_pipe->stopped_progs = 0; if (!pid) { /* child */ - fprintf(stderr, "setting pgrp for child\n"); + debug_jobs_printf("setting pgrp for child\n"); setpgrp(); - signal(sig, SIG_DFL); /* make child do default action (stop) */ - raise(sig); /* resend TSTP so that child will be stopped */ - fprintf(stderr, "returning to child\n"); + signal(SIGTSTP, SIG_DFL); /* make child do default action (stop) */ + raise(SIGTSTP); /* resend TSTP so that child will be stopped */ + debug_jobs_printf("returning to child\n"); /* return to nofork, it will eventually exit now, * not return back to shell */ return; @@ -1588,25 +1586,23 @@ static int run_pipe_real(struct pipe *pi) const struct bb_applet *a = find_applet_by_name(argv[i]); if (a && a->nofork) { setup_redirects(child, squirrel); + /* TSTP handler will store pid etc in pi */ + nofork_pipe = pi; + save_nofork_data(&nofork_save); if (sigsetjmp(nofork_jb, 1) == 0) { -// enable ctrl_z here, not globally? - nofork_flag = 1; - /* TSTP handler will store pid there etc */ - nofork_pipe = pi; - rcode = run_nofork_applet(a, argv + i); - if (--nofork_flag != 0) + signal_SA_RESTART(SIGTSTP, handler_ctrl_z); + rcode = run_nofork_applet_prime(&nofork_save, a, argv + i); + if (--nofork_save.saved != 0) /* Ctrl-Z! forked, we are child */ exit(rcode); restore_redirects(squirrel); return rcode; } else { - fprintf(stderr, "Exiting nofork early\n"); /* Ctrl-Z, forked, we are parent. * Sighandler has longjmped us here */ -//problem: run_nofork_applet did not do the -// "restore" trick and globals are trashed: -// for one, applet_name is not "hush" :) -// need to split run_nofork_applet into setup/run/restore... + signal(SIGTSTP, SIG_IGN); + debug_jobs_printf("Exiting nofork early\n"); + restore_nofork_data(&nofork_save); restore_redirects(squirrel); insert_bg_job(pi); return 0; @@ -3021,8 +3017,6 @@ static void setup_job_control(void) /* Grab control of the terminal. */ tcsetpgrp(interactive_fd, shell_pgrp); - - signal_SA_RESTART(SIGTSTP, handler_ctrl_z); } int hush_main(int argc, char **argv); -- 2.7.4