diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-04-28 16:43:18 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-04-28 16:43:18 +0000 |
commit | 18e19f2b0d36c0d9566d871942dfe282e9cf5a28 (patch) | |
tree | 22d3da65f1031bac1833c4f53c24b4f7876d5d6b | |
parent | a6a1785a30d6fe011eeabec3c19e154dc475b1b0 (diff) | |
download | busybox-w32-18e19f2b0d36c0d9566d871942dfe282e9cf5a28.tar.gz busybox-w32-18e19f2b0d36c0d9566d871942dfe282e9cf5a28.tar.bz2 busybox-w32-18e19f2b0d36c0d9566d871942dfe282e9cf5a28.zip |
hush: fix nofork + ctrl-Z clobbering of globals
-rw-r--r-- | include/libbb.h | 14 | ||||
-rw-r--r-- | libbb/vfork_daemon_rexec.c | 41 | ||||
-rw-r--r-- | shell/hush.c | 40 |
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); | |||
509 | #define wait_exitcode(w) ((w) >> 8) | 509 | #define wait_exitcode(w) ((w) >> 8) |
510 | #define wait_stopsig(w) ((w) >> 8) | 510 | #define wait_stopsig(w) ((w) >> 8) |
511 | #define wait_stopped(w) (((w) & 127) == 127) | 511 | #define wait_stopped(w) (((w) & 127) == 127) |
512 | /* Does NOT check that applet is NOFORK, just blindly runs it */ | ||
513 | int run_nofork_applet(const struct bb_applet *a, char **argv); | ||
514 | /* wait4pid(spawn(argv)) + NOFORK/NOEXEC (if configured) */ | 512 | /* wait4pid(spawn(argv)) + NOFORK/NOEXEC (if configured) */ |
515 | int spawn_and_wait(char **argv); | 513 | int spawn_and_wait(char **argv); |
514 | struct nofork_save_area { | ||
515 | const struct bb_applet *current_applet; | ||
516 | int xfunc_error_retval; | ||
517 | uint32_t option_mask32; | ||
518 | int die_sleep; | ||
519 | smallint saved; | ||
520 | }; | ||
521 | void save_nofork_data(struct nofork_save_area *save); | ||
522 | void restore_nofork_data(struct nofork_save_area *save); | ||
523 | /* Does NOT check that applet is NOFORK, just blindly runs it */ | ||
524 | int run_nofork_applet(const struct bb_applet *a, char **argv); | ||
525 | int run_nofork_applet_prime(struct nofork_save_area *old, const struct bb_applet *a, char **argv); | ||
516 | 526 | ||
517 | /* Helpers for daemonization. | 527 | /* Helpers for daemonization. |
518 | * | 528 | * |
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) | |||
100 | return r; | 100 | return r; |
101 | } | 101 | } |
102 | 102 | ||
103 | int run_nofork_applet(const struct bb_applet *a, char **argv) | 103 | void save_nofork_data(struct nofork_save_area *save) |
104 | { | 104 | { |
105 | int rc, argc; | 105 | save->current_applet = current_applet; |
106 | save->xfunc_error_retval = xfunc_error_retval; | ||
107 | save->option_mask32 = option_mask32; | ||
108 | save->die_sleep = die_sleep; | ||
109 | save->saved = 1; | ||
110 | } | ||
106 | 111 | ||
107 | /* Save some shared globals */ | 112 | void restore_nofork_data(struct nofork_save_area *save) |
108 | const struct bb_applet *old_a = current_applet; | 113 | { |
109 | int old_x = xfunc_error_retval; | 114 | current_applet = save->current_applet; |
110 | uint32_t old_m = option_mask32; | 115 | xfunc_error_retval = save->xfunc_error_retval; |
111 | int old_sleep = die_sleep; | 116 | option_mask32 = save->option_mask32; |
117 | die_sleep = save->die_sleep; | ||
118 | |||
119 | applet_name = current_applet->name; | ||
120 | } | ||
121 | |||
122 | int run_nofork_applet_prime(struct nofork_save_area *old, const struct bb_applet *a, char **argv) | ||
123 | { | ||
124 | int rc, argc; | ||
112 | 125 | ||
113 | current_applet = a; | 126 | current_applet = a; |
114 | applet_name = a->name; | 127 | applet_name = a->name; |
@@ -138,14 +151,18 @@ int run_nofork_applet(const struct bb_applet *a, char **argv) | |||
138 | } | 151 | } |
139 | 152 | ||
140 | /* Restoring globals */ | 153 | /* Restoring globals */ |
141 | current_applet = old_a; | 154 | restore_nofork_data(old); |
142 | applet_name = old_a->name; | ||
143 | xfunc_error_retval = old_x; | ||
144 | option_mask32 = old_m; | ||
145 | die_sleep = old_sleep; | ||
146 | return rc; | 155 | return rc; |
147 | } | 156 | } |
148 | 157 | ||
158 | int run_nofork_applet(const struct bb_applet *a, char **argv) | ||
159 | { | ||
160 | struct nofork_save_area old; | ||
161 | /* Saving globals */ | ||
162 | save_nofork_data(&old); | ||
163 | return run_nofork_applet_prime(&old, a, argv); | ||
164 | } | ||
165 | |||
149 | int spawn_and_wait(char **argv) | 166 | int spawn_and_wait(char **argv) |
150 | { | 167 | { |
151 | int rc; | 168 | 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)) | |||
441 | sigaction(sig, &sa, NULL); | 441 | sigaction(sig, &sa, NULL); |
442 | } | 442 | } |
443 | 443 | ||
444 | struct nofork_save_area nofork_save; | ||
444 | static sigjmp_buf nofork_jb; | 445 | static sigjmp_buf nofork_jb; |
445 | static smallint nofork_flag; | ||
446 | static struct pipe *nofork_pipe; | 446 | static struct pipe *nofork_pipe; |
447 | 447 | ||
448 | static void handler_ctrl_z(int sig) | 448 | static void handler_ctrl_z(int sig) |
449 | { | 449 | { |
450 | pid_t pid; | 450 | pid_t pid; |
451 | 451 | ||
452 | fprintf(stderr, "got tty sig %d\n", sig); | 452 | debug_jobs_printf("got tty sig %d\n", sig); |
453 | if (!nofork_flag) | ||
454 | return; | ||
455 | pid = fork(); | 453 | pid = fork(); |
456 | if (pid < 0) /* can't fork. Pretend there were no Ctrl-Z */ | 454 | if (pid < 0) /* can't fork. Pretend there were no Ctrl-Z */ |
457 | return; | 455 | return; |
458 | fprintf(stderr, "bg'ing nofork\n"); | 456 | debug_jobs_printf("bg'ing nofork\n"); |
459 | nofork_flag = 0; | 457 | nofork_save.saved = 0; /* flag the fact that Ctrl-Z was handled */ |
460 | nofork_pipe->running_progs = 1; | 458 | nofork_pipe->running_progs = 1; |
461 | nofork_pipe->stopped_progs = 0; | 459 | nofork_pipe->stopped_progs = 0; |
462 | if (!pid) { /* child */ | 460 | if (!pid) { /* child */ |
463 | fprintf(stderr, "setting pgrp for child\n"); | 461 | debug_jobs_printf("setting pgrp for child\n"); |
464 | setpgrp(); | 462 | setpgrp(); |
465 | signal(sig, SIG_DFL); /* make child do default action (stop) */ | 463 | signal(SIGTSTP, SIG_DFL); /* make child do default action (stop) */ |
466 | raise(sig); /* resend TSTP so that child will be stopped */ | 464 | raise(SIGTSTP); /* resend TSTP so that child will be stopped */ |
467 | fprintf(stderr, "returning to child\n"); | 465 | debug_jobs_printf("returning to child\n"); |
468 | /* return to nofork, it will eventually exit now, | 466 | /* return to nofork, it will eventually exit now, |
469 | * not return back to shell */ | 467 | * not return back to shell */ |
470 | return; | 468 | return; |
@@ -1588,25 +1586,23 @@ static int run_pipe_real(struct pipe *pi) | |||
1588 | const struct bb_applet *a = find_applet_by_name(argv[i]); | 1586 | const struct bb_applet *a = find_applet_by_name(argv[i]); |
1589 | if (a && a->nofork) { | 1587 | if (a && a->nofork) { |
1590 | setup_redirects(child, squirrel); | 1588 | setup_redirects(child, squirrel); |
1589 | /* TSTP handler will store pid etc in pi */ | ||
1590 | nofork_pipe = pi; | ||
1591 | save_nofork_data(&nofork_save); | ||
1591 | if (sigsetjmp(nofork_jb, 1) == 0) { | 1592 | if (sigsetjmp(nofork_jb, 1) == 0) { |
1592 | // enable ctrl_z here, not globally? | 1593 | signal_SA_RESTART(SIGTSTP, handler_ctrl_z); |
1593 | nofork_flag = 1; | 1594 | rcode = run_nofork_applet_prime(&nofork_save, a, argv + i); |
1594 | /* TSTP handler will store pid there etc */ | 1595 | if (--nofork_save.saved != 0) |
1595 | nofork_pipe = pi; | ||
1596 | rcode = run_nofork_applet(a, argv + i); | ||
1597 | if (--nofork_flag != 0) | ||
1598 | /* Ctrl-Z! forked, we are child */ | 1596 | /* Ctrl-Z! forked, we are child */ |
1599 | exit(rcode); | 1597 | exit(rcode); |
1600 | restore_redirects(squirrel); | 1598 | restore_redirects(squirrel); |
1601 | return rcode; | 1599 | return rcode; |
1602 | } else { | 1600 | } else { |
1603 | fprintf(stderr, "Exiting nofork early\n"); | ||
1604 | /* Ctrl-Z, forked, we are parent. | 1601 | /* Ctrl-Z, forked, we are parent. |
1605 | * Sighandler has longjmped us here */ | 1602 | * Sighandler has longjmped us here */ |
1606 | //problem: run_nofork_applet did not do the | 1603 | signal(SIGTSTP, SIG_IGN); |
1607 | // "restore" trick and globals are trashed: | 1604 | debug_jobs_printf("Exiting nofork early\n"); |
1608 | // for one, applet_name is not "hush" :) | 1605 | restore_nofork_data(&nofork_save); |
1609 | // need to split run_nofork_applet into setup/run/restore... | ||
1610 | restore_redirects(squirrel); | 1606 | restore_redirects(squirrel); |
1611 | insert_bg_job(pi); | 1607 | insert_bg_job(pi); |
1612 | return 0; | 1608 | return 0; |
@@ -3021,8 +3017,6 @@ static void setup_job_control(void) | |||
3021 | 3017 | ||
3022 | /* Grab control of the terminal. */ | 3018 | /* Grab control of the terminal. */ |
3023 | tcsetpgrp(interactive_fd, shell_pgrp); | 3019 | tcsetpgrp(interactive_fd, shell_pgrp); |
3024 | |||
3025 | signal_SA_RESTART(SIGTSTP, handler_ctrl_z); | ||
3026 | } | 3020 | } |
3027 | 3021 | ||
3028 | int hush_main(int argc, char **argv); | 3022 | int hush_main(int argc, char **argv); |