aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libbb.h14
-rw-r--r--libbb/vfork_daemon_rexec.c41
-rw-r--r--shell/hush.c40
3 files changed, 58 insertions, 37 deletions
diff --git a/include/libbb.h b/include/libbb.h
index fce10f310..9950c61f2 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 78f3c4ad4..aef74e994 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 c87f3b566..b2ff0cb2e 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);