summaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-04-21 00:03:36 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-04-21 00:03:36 +0000
commit54e7ffb3a405ab058d12fbed9a63314ba996be90 (patch)
tree8e78848fb5cf60d0455feec2e68de6e41c0e5775 /shell/hush.c
parent5f786c24e4a80d5341f7a7449df5b32ec2dd440a (diff)
downloadbusybox-w32-54e7ffb3a405ab058d12fbed9a63314ba996be90.tar.gz
busybox-w32-54e7ffb3a405ab058d12fbed9a63314ba996be90.tar.bz2
busybox-w32-54e7ffb3a405ab058d12fbed9a63314ba996be90.zip
hush: begin fixing non-functional job control
Diffstat (limited to '')
-rw-r--r--shell/hush.c270
1 files changed, 198 insertions, 72 deletions
diff --git a/shell/hush.c b/shell/hush.c
index e2ff012d7..7792887a5 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -81,9 +81,6 @@
81#include <glob.h> /* glob, of course */ 81#include <glob.h> /* glob, of course */
82#include <getopt.h> /* should be pretty obvious */ 82#include <getopt.h> /* should be pretty obvious */
83 83
84//#include <sys/wait.h>
85//#include <signal.h>
86
87/* #include <dmalloc.h> */ 84/* #include <dmalloc.h> */
88/* #define DEBUG_SHELL */ 85/* #define DEBUG_SHELL */
89 86
@@ -91,7 +88,7 @@
91#define SPECIAL_VAR_SYMBOL 03 88#define SPECIAL_VAR_SYMBOL 03
92#define FLAG_EXIT_FROM_LOOP 1 89#define FLAG_EXIT_FROM_LOOP 1
93#define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */ 90#define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */
94#define FLAG_REPARSING (1 << 2) /* >=2nd pass */ 91#define FLAG_REPARSING (1 << 2) /* >=2nd pass */
95 92
96typedef enum { 93typedef enum {
97 REDIRECT_INPUT = 1, 94 REDIRECT_INPUT = 1,
@@ -193,7 +190,7 @@ struct child_prog {
193struct pipe { 190struct pipe {
194 int jobid; /* job number */ 191 int jobid; /* job number */
195 int num_progs; /* total number of programs in job */ 192 int num_progs; /* total number of programs in job */
196 int running_progs; /* number of programs running */ 193 int running_progs; /* number of programs running (not exited) */
197 char *text; /* name of job */ 194 char *text; /* name of job */
198 char *cmdbuf; /* buffer various argv's point into */ 195 char *cmdbuf; /* buffer various argv's point into */
199 pid_t pgrp; /* process group ID for the job */ 196 pid_t pgrp; /* process group ID for the job */
@@ -229,13 +226,17 @@ extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
229static const char *ifs; 226static const char *ifs;
230static unsigned char map[256]; 227static unsigned char map[256];
231static int fake_mode; 228static int fake_mode;
232static int interactive;
233static struct close_me *close_me_head; 229static struct close_me *close_me_head;
234static const char *cwd; 230static const char *cwd;
235static struct pipe *job_list; 231static struct pipe *job_list;
236static unsigned last_bg_pid; 232static unsigned last_bg_pid;
237static int last_jobid; 233static int last_jobid;
238static unsigned shell_terminal; 234/* 'interactive_fd' is a fd# open to ctty, if we have one
235 * _AND_ if we decided to mess with job control */
236static int interactive_fd;
237static pid_t saved_task_pgrp;
238static pid_t saved_tty_pgrp;
239
239static const char *PS1; 240static const char *PS1;
240static const char *PS2; 241static const char *PS2;
241static struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 }; 242static struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
@@ -308,7 +309,7 @@ static void __syntax(const char *file, int line)
308{ 309{
309 bb_error_msg("syntax error %s:%d", file, line); 310 bb_error_msg("syntax error %s:%d", file, line);
310} 311}
311// NB: was __FILE__, but that produces full path sometimes, so... 312/* NB: was __FILE__, but that produces full path sometimes, so... */
312#define syntax() __syntax("hush.c", __LINE__) 313#define syntax() __syntax("hush.c", __LINE__)
313 314
314/* Index of subroutines: */ 315/* Index of subroutines: */
@@ -425,6 +426,84 @@ static const struct built_in_command bltins[] = {
425 { NULL, NULL, NULL } 426 { NULL, NULL, NULL }
426}; 427};
427 428
429/* Restores tty foreground process group, and exits.
430 * May be called as signal handler for fatal signal
431 * (will faithfully resend signal to itself, producing correct exit state)
432 * or called directly with -EXITCODE.
433 * We also call it if xfunc is exiting. */
434static void sigexit(int sig) ATTRIBUTE_NORETURN;
435static void sigexit(int sig)
436{
437 sigset_t block_all;
438
439 /* Disable all signals: job control, SIGPIPE, etc. */
440 sigfillset(&block_all);
441 sigprocmask(SIG_SETMASK, &block_all, NULL);
442
443 if (interactive_fd) {
444 if (sig > 0) {
445 enum { KILLED = sizeof("Killed by signal ")-1 };
446 char buf[KILLED + sizeof(int)*3 + 1];
447 char *p;
448
449 /* bash actually says "Illegal instruction" and the like */
450 strcpy(buf, "Killed by signal ");
451 p = utoa_to_buf(sig, buf+KILLED, sizeof(buf)-KILLED);
452 *p++ = '\n';
453 write(interactive_fd, buf, p-buf);
454 }
455 tcsetpgrp(interactive_fd, saved_tty_pgrp);
456 }
457
458 /* Not a signal, just exit */
459 if (sig <= 0)
460 _exit(- sig);
461
462 /* Enable only this sig and kill ourself with it */
463 signal(sig, SIG_DFL);
464 sigdelset(&block_all, sig);
465 sigprocmask(SIG_SETMASK, &block_all, NULL);
466 raise(sig);
467 _exit(1); /* Should not reach it */
468}
469
470/* Restores tty foreground process group, and exits. */
471static void hush_exit(int exitcode) ATTRIBUTE_NORETURN;
472static void hush_exit(int exitcode)
473{
474 fflush(NULL); /* flush all streams */
475 sigexit(- (exitcode & 0xff));
476}
477
478/* Signals are grouped, we handle them in batches */
479static void set_fatal_sighandler(void (*handler)(int))
480{
481 signal(SIGILL , handler);
482 signal(SIGTRAP, handler);
483 signal(SIGABRT, handler);
484 signal(SIGFPE , handler);
485 signal(SIGBUS , handler);
486 signal(SIGSEGV, handler);
487 /* bash 3.2 seems to handle these just like 'fatal' ones,
488 * but _without_ printing signal name. TODO: mimic this too? */
489 signal(SIGHUP , handler);
490 signal(SIGPIPE, handler);
491 signal(SIGALRM, handler);
492}
493static void set_jobctrl_sighandler(void (*handler)(int))
494{
495 signal(SIGTSTP, handler);
496 signal(SIGTTIN, handler);
497 signal(SIGTTOU, handler);
498}
499static void set_misc_sighandler(void (*handler)(int))
500{
501 signal(SIGINT , handler);
502 signal(SIGQUIT, handler);
503 signal(SIGTERM, handler);
504}
505/* SIGCHLD is special and handled separately */
506
428static const char *set_cwd(void) 507static const char *set_cwd(void)
429{ 508{
430 if (cwd == bb_msg_unknown) 509 if (cwd == bb_msg_unknown)
@@ -493,13 +572,15 @@ static int builtin_exec(struct child_prog *child)
493/* built-in 'exit' handler */ 572/* built-in 'exit' handler */
494static int builtin_exit(struct child_prog *child) 573static int builtin_exit(struct child_prog *child)
495{ 574{
496 /* bash prints "exit\n" here, then: */ 575// TODO: bash does it ONLY on top-level sh exit (+interacive only?)
576 //puts("exit"); /* bash does it */
577
497 if (child->argv[1] == NULL) 578 if (child->argv[1] == NULL)
498 exit(last_return_code); 579 hush_exit(last_return_code);
499 /* mimic bash: exit 123abc == exit 255 + error msg */ 580 /* mimic bash: exit 123abc == exit 255 + error msg */
500 xfunc_error_retval = 255; 581 xfunc_error_retval = 255;
501 /* bash: exit -2 == exit 254, no error msg */ 582 /* bash: exit -2 == exit 254, no error msg */
502 exit(xatoi(child->argv[1])); 583 hush_exit(xatoi(child->argv[1]));
503} 584}
504 585
505/* built-in 'export VAR=value' handler */ 586/* built-in 'export VAR=value' handler */
@@ -555,7 +636,7 @@ static int builtin_fg_bg(struct child_prog *child)
555 int i, jobnum; 636 int i, jobnum;
556 struct pipe *pi; 637 struct pipe *pi;
557 638
558 if (!interactive) 639 if (!interactive_fd)
559 return EXIT_FAILURE; 640 return EXIT_FAILURE;
560 /* If they gave us no args, assume they want the last backgrounded task */ 641 /* If they gave us no args, assume they want the last backgrounded task */
561 if (!child->argv[1]) { 642 if (!child->argv[1]) {
@@ -581,7 +662,7 @@ static int builtin_fg_bg(struct child_prog *child)
581 found: 662 found:
582 if (*child->argv[0] == 'f') { 663 if (*child->argv[0] == 'f') {
583 /* Put the job into the foreground. */ 664 /* Put the job into the foreground. */
584 tcsetpgrp(shell_terminal, pi->pgrp); 665 tcsetpgrp(interactive_fd, pi->pgrp);
585 } 666 }
586 667
587 /* Restart the processes in the job */ 668 /* Restart the processes in the job */
@@ -915,8 +996,8 @@ static int file_get(struct in_str *i)
915 } else { 996 } else {
916 /* need to double check i->file because we might be doing something 997 /* need to double check i->file because we might be doing something
917 * more complicated by now, like sourcing or substituting. */ 998 * more complicated by now, like sourcing or substituting. */
918 if (i->__promptme && interactive && i->file == stdin) { 999 if (i->__promptme && interactive_fd && i->file == stdin) {
919 while (!i->p || !(interactive && strlen(i->p))) { 1000 while (!i->p || !(interactive_fd && strlen(i->p))) {
920 get_user_input(i); 1001 get_user_input(i);
921 } 1002 }
922 i->promptmode = 2; 1003 i->promptmode = 2;
@@ -1116,7 +1197,7 @@ static void pseudo_exec(struct child_prog *child)
1116 1197
1117 if (child->group) { 1198 if (child->group) {
1118 debug_printf("runtime nesting to group\n"); 1199 debug_printf("runtime nesting to group\n");
1119 interactive = 0; /* crucial!!!! */ 1200 interactive_fd = 0; /* crucial!!!! */
1120 rcode = run_list_real(child->group); 1201 rcode = run_list_real(child->group);
1121 /* OK to leak memory by not calling free_pipe_list, 1202 /* OK to leak memory by not calling free_pipe_list,
1122 * since this process is about to exit */ 1203 * since this process is about to exit */
@@ -1203,25 +1284,39 @@ static int checkjobs(struct pipe* fg_pipe)
1203 int prognum = 0; 1284 int prognum = 0;
1204 struct pipe *pi; 1285 struct pipe *pi;
1205 pid_t childpid; 1286 pid_t childpid;
1287 int rcode = 0;
1206 1288
1207 attributes = WUNTRACED; 1289 attributes = WUNTRACED;
1290//WUNTRACED?? huh, what will happed on Ctrl-Z? fg waiting code
1291//doesn't seem to be ready for stopped children! (only exiting ones)...
1208 if (fg_pipe == NULL) { 1292 if (fg_pipe == NULL) {
1209 attributes |= WNOHANG; 1293 attributes |= WNOHANG;
1210 } 1294 }
1211 1295
1296 wait_more:
1212 while ((childpid = waitpid(-1, &status, attributes)) > 0) { 1297 while ((childpid = waitpid(-1, &status, attributes)) > 0) {
1298 /* Were we asked to wait for fg pipe? */
1213 if (fg_pipe) { 1299 if (fg_pipe) {
1214 int i, rcode = 0; 1300 int i;
1215 for (i = 0; i < fg_pipe->num_progs; i++) { 1301 for (i = 0; i < fg_pipe->num_progs; i++) {
1216 if (fg_pipe->progs[i].pid == childpid) { 1302 if (fg_pipe->progs[i].pid == childpid) {
1303 /* printf("process %d exit %d\n", i, WEXITSTATUS(status)); */
1304 fg_pipe->progs[i].pid = 0;
1217 if (i == fg_pipe->num_progs-1) 1305 if (i == fg_pipe->num_progs-1)
1306 /* last process gives overall exitstatus */
1218 rcode = WEXITSTATUS(status); 1307 rcode = WEXITSTATUS(status);
1219 fg_pipe->num_progs--; 1308 if (--fg_pipe->running_progs <= 0)
1220 return rcode; 1309 /* All processes in fg pipe have exited */
1310 return rcode;
1311 /* There are still running processes in the fg pipe */
1312 goto wait_more;
1221 } 1313 }
1222 } 1314 }
1223 } 1315 }
1224 1316
1317 /* We asked to wait for bg or orphaned children */
1318 /* No need to remember exitcode in this case */
1319
1225 for (pi = job_list; pi; pi = pi->next) { 1320 for (pi = job_list; pi; pi = pi->next) {
1226 prognum = 0; 1321 prognum = 0;
1227 while (prognum < pi->num_progs) { 1322 while (prognum < pi->num_progs) {
@@ -1257,9 +1352,9 @@ static int checkjobs(struct pipe* fg_pipe)
1257 bb_perror_msg("waitpid"); 1352 bb_perror_msg("waitpid");
1258 1353
1259 /* move the shell to the foreground */ 1354 /* move the shell to the foreground */
1260 //if (interactive && tcsetpgrp(shell_terminal, getpgid(0))) 1355 //if (interactive_fd && tcsetpgrp(interactive_fd, getpgid(0)))
1261 // bb_perror_msg("tcsetpgrp-2"); 1356 // bb_perror_msg("tcsetpgrp-2");
1262 return -1; 1357 return rcode;
1263} 1358}
1264 1359
1265/* run_pipe_real() starts all the jobs, but doesn't wait for anything 1360/* run_pipe_real() starts all the jobs, but doesn't wait for anything
@@ -1376,6 +1471,8 @@ static int run_pipe_real(struct pipe *pi)
1376 } 1471 }
1377#if ENABLE_FEATURE_SH_STANDALONE 1472#if ENABLE_FEATURE_SH_STANDALONE
1378 { 1473 {
1474// FIXME: applet runs like part of shell - for example, it ignores
1475// SIGINT! Try to Ctrl-C out of "rm -i"... doesn't work
1379 const struct bb_applet *a = find_applet_by_name(child->argv[i]); 1476 const struct bb_applet *a = find_applet_by_name(child->argv[i]);
1380 if (a && a->nofork) { 1477 if (a && a->nofork) {
1381 setup_redirects(child, squirrel); 1478 setup_redirects(child, squirrel);
@@ -1387,6 +1484,11 @@ static int run_pipe_real(struct pipe *pi)
1387#endif 1484#endif
1388 } 1485 }
1389 1486
1487 /* Disable job control signals for shell (parent) and
1488 * for initial child code after fork */
1489 set_jobctrl_sighandler(SIG_IGN);
1490
1491 pi->running_progs = 0;
1390 for (i = 0; i < pi->num_progs; i++) { 1492 for (i = 0; i < pi->num_progs; i++) {
1391 child = &(pi->progs[i]); 1493 child = &(pi->progs[i]);
1392 1494
@@ -1406,18 +1508,22 @@ static int run_pipe_real(struct pipe *pi)
1406#else 1508#else
1407 child->pid = vfork(); 1509 child->pid = vfork();
1408#endif 1510#endif
1409 if (!child->pid) { 1511 if (!child->pid) { /* child */
1410 /* Set the handling for job control signals back to the default. */ 1512 /* Every child adds itself to new process group
1411 signal(SIGINT, SIG_DFL); 1513 * with pgid == pid of first child in pipe */
1412 signal(SIGQUIT, SIG_DFL); 1514 if (interactive_fd) {
1413 signal(SIGTERM, SIG_DFL); 1515 if (pi->pgrp < 0) /* true for 1st process only */
1414 signal(SIGTSTP, SIG_DFL); 1516 pi->pgrp = getpid();
1415 signal(SIGTTIN, SIG_DFL); 1517 if (setpgid(0, pi->pgrp) == 0 && pi->followup != PIPE_BG) {
1416 signal(SIGTTOU, SIG_DFL); 1518 /* We do it in *every* child, not just first,
1417 signal(SIGCHLD, SIG_DFL); 1519 * to avoid races */
1520 tcsetpgrp(interactive_fd, pi->pgrp);
1521 }
1522 /* Don't do pgrp restore anymore on fatal signals */
1523 set_fatal_sighandler(SIG_DFL);
1524 }
1418 1525
1419 close_all(); 1526 close_all();
1420
1421 if (nextin != 0) { 1527 if (nextin != 0) {
1422 dup2(nextin, 0); 1528 dup2(nextin, 0);
1423 close(nextin); 1529 close(nextin);
@@ -1429,33 +1535,28 @@ static int run_pipe_real(struct pipe *pi)
1429 if (pipefds[0] != -1) { 1535 if (pipefds[0] != -1) {
1430 close(pipefds[0]); /* opposite end of our output pipe */ 1536 close(pipefds[0]); /* opposite end of our output pipe */
1431 } 1537 }
1432
1433 /* Like bash, explicit redirects override pipes, 1538 /* Like bash, explicit redirects override pipes,
1434 * and the pipe fd is available for dup'ing. */ 1539 * and the pipe fd is available for dup'ing. */
1435 setup_redirects(child, NULL); 1540 setup_redirects(child, NULL);
1436 1541
1437 if (interactive && pi->followup != PIPE_BG) { 1542 /* Restore default handlers just prior to exec */
1438 /* If we (the child) win the race, put ourselves in the process 1543 set_jobctrl_sighandler(SIG_DFL);
1439 * group whose leader is the first process in this pipe. */ 1544 set_misc_sighandler(SIG_DFL);
1440 if (pi->pgrp < 0) { 1545 signal(SIGCHLD, SIG_DFL);
1441 pi->pgrp = getpid();
1442 }
1443 if (setpgid(0, pi->pgrp) == 0) {
1444 tcsetpgrp(2, pi->pgrp);
1445 }
1446 }
1447
1448 pseudo_exec(child); 1546 pseudo_exec(child);
1449 } 1547 }
1450 1548
1451 /* put our child in the process group whose leader is the 1549 pi->running_progs++;
1452 first process in this pipe */ 1550
1453 if (pi->pgrp < 0) { 1551 /* Second and next children need to know ipd of first one */
1552 if (pi->pgrp < 0)
1454 pi->pgrp = child->pid; 1553 pi->pgrp = child->pid;
1455 } 1554
1456 /* Don't check for errors. The child may be dead already, 1555 /* Don't check for errors. The child may be dead already,
1457 * in which case setpgid returns error code EACCES. */ 1556 * in which case setpgid returns error code EACCES. */
1458 setpgid(child->pid, pi->pgrp); 1557 //why we do it at all?? child does it itself
1558 //if (interactive_fd)
1559 // setpgid(child->pid, pi->pgrp);
1459 1560
1460 if (nextin != 0) 1561 if (nextin != 0)
1461 close(nextin); 1562 close(nextin);
@@ -1580,14 +1681,14 @@ static int run_list_real(struct pipe *pi)
1580 insert_bg_job(pi); 1681 insert_bg_job(pi);
1581 rcode = EXIT_SUCCESS; 1682 rcode = EXIT_SUCCESS;
1582 } else { 1683 } else {
1583 if (interactive) { 1684 if (interactive_fd) {
1584 /* move the new process group into the foreground */ 1685 pid_t p;
1585 if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY)
1586 bb_perror_msg("tcsetpgrp-3");
1587 rcode = checkjobs(pi); 1686 rcode = checkjobs(pi);
1588 /* move the shell to the foreground */ 1687 /* move the shell to the foreground */
1589 if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY) 1688 p = getpgid(0);
1689 if (tcsetpgrp(interactive_fd, p) && errno != ENOTTY)
1590 bb_perror_msg("tcsetpgrp-4"); 1690 bb_perror_msg("tcsetpgrp-4");
1691 debug_printf("getpgid(0)=%d\n", (int)p);
1591 } else { 1692 } else {
1592 rcode = checkjobs(pi); 1693 rcode = checkjobs(pi);
1593 } 1694 }
@@ -2660,28 +2761,33 @@ static int parse_file_outer(FILE *f)
2660 * we don't fight over who gets the foreground */ 2761 * we don't fight over who gets the foreground */
2661static void setup_job_control(void) 2762static void setup_job_control(void)
2662{ 2763{
2663 /*static --why?? */ pid_t shell_pgrp; 2764 pid_t shell_pgrp;
2765
2766 fcntl(interactive_fd, F_SETFD, FD_CLOEXEC);
2664 2767
2665 /* Loop until we are in the foreground. */ 2768 /* Loop until we are in the foreground. */
2666 while (tcgetpgrp(shell_terminal) != (shell_pgrp = getpgrp())) 2769 while (1) {
2770 shell_pgrp = getpgrp();
2771 if (tcgetpgrp(interactive_fd) == shell_pgrp)
2772 break;
2773// and this does... what? need a comment here
2667 kill(- shell_pgrp, SIGTTIN); 2774 kill(- shell_pgrp, SIGTTIN);
2775 }
2776
2777 /* Ignore job-control and misc signals. */
2778 set_jobctrl_sighandler(SIG_IGN);
2779 set_misc_sighandler(SIG_IGN);
2780//huh? signal(SIGCHLD, SIG_IGN);
2668 2781
2669 /* Ignore interactive and job-control signals. */ 2782 /* We _must_ do cleanup on fatal signals */
2670 signal(SIGINT, SIG_IGN); 2783 set_fatal_sighandler(sigexit);
2671 signal(SIGQUIT, SIG_IGN);
2672 signal(SIGTERM, SIG_IGN);
2673 signal(SIGTSTP, SIG_IGN);
2674 signal(SIGTTIN, SIG_IGN);
2675 signal(SIGTTOU, SIG_IGN);
2676 signal(SIGCHLD, SIG_IGN);
2677 2784
2678 /* Put ourselves in our own process group. */ 2785 /* Put ourselves in our own process group. */
2679 setsid();
2680 shell_pgrp = getpid(); 2786 shell_pgrp = getpid();
2681 setpgid(shell_pgrp, shell_pgrp); 2787 setpgrp(); /* is the same as setpgid(shell_pgrp, shell_pgrp); */
2682 2788
2683 /* Grab control of the terminal. */ 2789 /* Grab control of the terminal. */
2684 tcsetpgrp(shell_terminal, shell_pgrp); 2790 tcsetpgrp(interactive_fd, shell_pgrp);
2685} 2791}
2686 2792
2687int hush_main(int argc, char **argv); 2793int hush_main(int argc, char **argv);
@@ -2705,7 +2811,7 @@ int hush_main(int argc, char **argv)
2705 ifs = NULL; 2811 ifs = NULL;
2706 /* map[] is taken care of with call to update_ifs_map() */ 2812 /* map[] is taken care of with call to update_ifs_map() */
2707 fake_mode = 0; 2813 fake_mode = 0;
2708 interactive = 0; 2814 interactive_fd = 0;
2709 close_me_head = NULL; 2815 close_me_head = NULL;
2710 last_bg_pid = 0; 2816 last_bg_pid = 0;
2711 job_list = NULL; 2817 job_list = NULL;
@@ -2747,7 +2853,7 @@ int hush_main(int argc, char **argv)
2747 opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON); 2853 opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON);
2748 goto final_return; 2854 goto final_return;
2749 case 'i': 2855 case 'i':
2750 interactive++; 2856 /*interactive_fd++;*/ //huh??
2751 break; 2857 break;
2752 case 'f': 2858 case 'f':
2753 fake_mode++; 2859 fake_mode++;
@@ -2772,11 +2878,25 @@ int hush_main(int argc, char **argv)
2772 if (argv[optind] == NULL && input == stdin 2878 if (argv[optind] == NULL && input == stdin
2773 && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) 2879 && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)
2774 ) { 2880 ) {
2775 interactive++; 2881 saved_tty_pgrp = tcgetpgrp(STDIN_FILENO);
2882 debug_printf("saved_tty_pgrp=%d\n", saved_tty_pgrp);
2883 if (saved_tty_pgrp >= 0) {
2884 saved_task_pgrp = getpgrp();
2885 debug_printf("saved_task_pgrp=%d\n", saved_task_pgrp);
2886 /* try to dup to high fd#, >= 255 */
2887 interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255);
2888 if (interactive_fd < 0) {
2889 /* try to dup to any fd */
2890 interactive_fd = dup(STDIN_FILENO);
2891 if (interactive_fd < 0)
2892 /* give up */
2893 interactive_fd = 0;
2894 }
2895 }
2776 } 2896 }
2777 2897
2778 debug_printf("\ninteractive=%d\n", interactive); 2898 debug_printf("\ninteractive_fd=%d\n", interactive_fd);
2779 if (interactive) { 2899 if (interactive_fd) {
2780 /* Looks like they want an interactive shell */ 2900 /* Looks like they want an interactive shell */
2781#if !ENABLE_FEATURE_SH_EXTRA_QUIET 2901#if !ENABLE_FEATURE_SH_EXTRA_QUIET
2782 printf( "\n\n%s hush - the humble shell v0.01 (testing)\n", 2902 printf( "\n\n%s hush - the humble shell v0.01 (testing)\n",
@@ -2784,6 +2904,12 @@ int hush_main(int argc, char **argv)
2784 printf( "Enter 'help' for a list of built-in commands.\n\n"); 2904 printf( "Enter 'help' for a list of built-in commands.\n\n");
2785#endif 2905#endif
2786 setup_job_control(); 2906 setup_job_control();
2907 /* Make xfuncs do cleanup on exit */
2908 die_sleep = -1; /* flag */
2909 if (setjmp(die_jmp)) {
2910 /* xfunc has failed! die die die */
2911 hush_exit(xfunc_error_retval);
2912 }
2787 } 2913 }
2788 2914
2789 if (argv[optind] == NULL) { 2915 if (argv[optind] == NULL) {
@@ -2815,7 +2941,7 @@ int hush_main(int argc, char **argv)
2815#endif 2941#endif
2816 2942
2817 final_return: 2943 final_return:
2818 return opt ? opt : last_return_code; 2944 hush_exit(opt ? opt : last_return_code);
2819} 2945}
2820 2946
2821static char *insert_var_value(char *inp) 2947static char *insert_var_value(char *inp)