summaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-04-28 16:48:04 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-04-28 16:48:04 +0000
commitb81b3df1fa387fa5c6a3fe577969285858f494ce (patch)
treef681253ed7bc21ff3291ae13430db89933f83d29 /shell/hush.c
parent0937be5fa64e9dc0f2dc525225c34ab7c52f256c (diff)
downloadbusybox-w32-b81b3df1fa387fa5c6a3fe577969285858f494ce.tar.gz
busybox-w32-b81b3df1fa387fa5c6a3fe577969285858f494ce.tar.bz2
busybox-w32-b81b3df1fa387fa5c6a3fe577969285858f494ce.zip
hush: make job control and interactiveness configurable, part 1
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c116
1 files changed, 102 insertions, 14 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 25eb78f4e..57a4ac04f 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -51,7 +51,7 @@
51 * Here Documents ( << word ) 51 * Here Documents ( << word )
52 * Functions 52 * Functions
53 * Major bugs: 53 * Major bugs:
54 * job handling woefully incomplete and buggy 54 * job handling woefully incomplete and buggy (improved --vda)
55 * reserved word execution woefully incomplete and buggy 55 * reserved word execution woefully incomplete and buggy
56 * to-do: 56 * to-do:
57 * port selected bugfixes from post-0.49 busybox lash - done? 57 * port selected bugfixes from post-0.49 busybox lash - done?
@@ -86,6 +86,16 @@
86/* Finer-grained debug switch */ 86/* Finer-grained debug switch */
87//#define DEBUG_SHELL_JOBS 87//#define DEBUG_SHELL_JOBS
88 88
89//TODO: rename HUSH_INTERACTIVE -> HUSH_JOB,
90//create HUSH_INTERACTIVE which controls only prompt + line editing,
91//make HUSH_JOB dependent on it
92
93#if !ENABLE_HUSH_INTERACTIVE
94#undef ENABLE_FEATURE_EDITING
95#define ENABLE_FEATURE_EDITING 0
96#undef ENABLE_FEATURE_EDITING_FANCY_PROMPT
97#define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0
98#endif
89 99
90#define SPECIAL_VAR_SYMBOL 03 100#define SPECIAL_VAR_SYMBOL 03
91#define FLAG_EXIT_FROM_LOOP 1 101#define FLAG_EXIT_FROM_LOOP 1
@@ -169,10 +179,10 @@ struct p_context {
169}; 179};
170 180
171struct redir_struct { 181struct redir_struct {
182 struct redir_struct *next; /* pointer to the next redirect in the list */
172 redir_type type; /* type of redirection */ 183 redir_type type; /* type of redirection */
173 int fd; /* file descriptor being redirected */ 184 int fd; /* file descriptor being redirected */
174 int dup; /* -1, or file descriptor being duplicated */ 185 int dup; /* -1, or file descriptor being duplicated */
175 struct redir_struct *next; /* pointer to the next redirect in the list */
176 glob_t word; /* *word.gl_pathv is the filename */ 186 glob_t word; /* *word.gl_pathv is the filename */
177}; 187};
178 188
@@ -190,14 +200,16 @@ struct child_prog {
190}; 200};
191 201
192struct pipe { 202struct pipe {
193 int jobid; /* job number */ 203 struct pipe *next;
194 int num_progs; /* total number of programs in job */ 204 int num_progs; /* total number of programs in job */
195 int running_progs; /* number of programs running (not exited) */ 205 int running_progs; /* number of programs running (not exited) */
196 char *cmdtext; /* name of job */
197 char *cmdbuf; /* buffer various argv's point into */ 206 char *cmdbuf; /* buffer various argv's point into */
207#if ENABLE_HUSH_INTERACTIVE
208 int jobid; /* job number */
209 char *cmdtext; /* name of job */
198 pid_t pgrp; /* process group ID for the job */ 210 pid_t pgrp; /* process group ID for the job */
211#endif
199 struct child_prog *progs; /* array of commands in pipe */ 212 struct child_prog *progs; /* array of commands in pipe */
200 struct pipe *next; /* to track background commands */
201 int stopped_progs; /* number of programs alive, but stopped */ 213 int stopped_progs; /* number of programs alive, but stopped */
202 int job_context; /* bitmask defining current context */ 214 int job_context; /* bitmask defining current context */
203 pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ 215 pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
@@ -205,16 +217,16 @@ struct pipe {
205}; 217};
206 218
207struct close_me { 219struct close_me {
208 int fd;
209 struct close_me *next; 220 struct close_me *next;
221 int fd;
210}; 222};
211 223
212struct variables { 224struct variables {
225 struct variables *next;
213 const char *name; 226 const char *name;
214 const char *value; 227 const char *value;
215 int flg_export; 228 int flg_export;
216 int flg_read_only; 229 int flg_read_only;
217 struct variables *next;
218}; 230};
219 231
220/* globals, connect us to the outside world 232/* globals, connect us to the outside world
@@ -230,18 +242,22 @@ static unsigned char map[256];
230static int fake_mode; 242static int fake_mode;
231static struct close_me *close_me_head; 243static struct close_me *close_me_head;
232static const char *cwd; 244static const char *cwd;
233static struct pipe *job_list;
234static unsigned last_bg_pid; 245static unsigned last_bg_pid;
246#if ENABLE_HUSH_INTERACTIVE
235static int last_jobid; 247static int last_jobid;
248static struct pipe *job_list;
236/* 'interactive_fd' is a fd# open to ctty, if we have one 249/* 'interactive_fd' is a fd# open to ctty, if we have one
237 * _AND_ if we decided to mess with job control */ 250 * _AND_ if we decided to mess with job control */
238static int interactive_fd; 251static int interactive_fd;
239static pid_t saved_task_pgrp; 252static pid_t saved_task_pgrp;
240static pid_t saved_tty_pgrp; 253static pid_t saved_tty_pgrp;
254#else
255enum { interactive_fd = 0 };
256#endif
241 257
242static const char *PS1; 258static const char *PS1;
243static const char *PS2; 259static const char *PS2;
244static struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 }; 260static struct variables shell_ver = { NULL, "HUSH_VERSION", "0.01", 1, 1 };
245static struct variables *top_vars = &shell_ver; 261static struct variables *top_vars = &shell_ver;
246 262
247 263
@@ -322,9 +338,11 @@ static int builtin_eval(char **argv);
322static int builtin_exec(char **argv); 338static int builtin_exec(char **argv);
323static int builtin_exit(char **argv); 339static int builtin_exit(char **argv);
324static int builtin_export(char **argv); 340static int builtin_export(char **argv);
341#if ENABLE_HUSH_INTERACTIVE
325static int builtin_fg_bg(char **argv); 342static int builtin_fg_bg(char **argv);
326static int builtin_help(char **argv);
327static int builtin_jobs(char **argv); 343static int builtin_jobs(char **argv);
344#endif
345static int builtin_help(char **argv);
328static int builtin_pwd(char **argv); 346static int builtin_pwd(char **argv);
329static int builtin_read(char **argv); 347static int builtin_read(char **argv);
330static int builtin_set(char **argv); 348static int builtin_set(char **argv);
@@ -387,10 +405,14 @@ static int parse_string_outer(const char *s, int flag);
387static int parse_file_outer(FILE *f); 405static int parse_file_outer(FILE *f);
388/* job management: */ 406/* job management: */
389static int checkjobs(struct pipe* fg_pipe); 407static int checkjobs(struct pipe* fg_pipe);
408#if ENABLE_HUSH_INTERACTIVE
390static int checkjobs_and_fg_shell(struct pipe* fg_pipe); 409static int checkjobs_and_fg_shell(struct pipe* fg_pipe);
391static void insert_bg_job(struct pipe *pi); 410static void insert_bg_job(struct pipe *pi);
392static void remove_bg_job(struct pipe *pi); 411static void remove_bg_job(struct pipe *pi);
393static void delete_finished_bg_job(struct pipe *pi); 412static void delete_finished_bg_job(struct pipe *pi);
413#else
414int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */
415#endif
394/* local variable support */ 416/* local variable support */
395static char **make_list_in(char **inp, char *name); 417static char **make_list_in(char **inp, char *name);
396static char *insert_var_value(char *inp); 418static char *insert_var_value(char *inp);
@@ -405,7 +427,9 @@ static void unset_local_var(const char *name);
405 * For example, 'unset foo | whatever' will parse and run, but foo will 427 * For example, 'unset foo | whatever' will parse and run, but foo will
406 * still be set at the end. */ 428 * still be set at the end. */
407static const struct built_in_command bltins[] = { 429static const struct built_in_command bltins[] = {
430#if ENABLE_HUSH_INTERACTIVE
408 { "bg", "Resume a job in the background", builtin_fg_bg }, 431 { "bg", "Resume a job in the background", builtin_fg_bg },
432#endif
409 { "break", "Exit for, while or until loop", builtin_not_written }, 433 { "break", "Exit for, while or until loop", builtin_not_written },
410 { "cd", "Change working directory", builtin_cd }, 434 { "cd", "Change working directory", builtin_cd },
411 { "continue", "Continue for, while or until loop", builtin_not_written }, 435 { "continue", "Continue for, while or until loop", builtin_not_written },
@@ -415,8 +439,10 @@ static const struct built_in_command bltins[] = {
415 builtin_exec }, 439 builtin_exec },
416 { "exit", "Exit from shell()", builtin_exit }, 440 { "exit", "Exit from shell()", builtin_exit },
417 { "export", "Set environment variable", builtin_export }, 441 { "export", "Set environment variable", builtin_export },
442#if ENABLE_HUSH_INTERACTIVE
418 { "fg", "Bring job into the foreground", builtin_fg_bg }, 443 { "fg", "Bring job into the foreground", builtin_fg_bg },
419 { "jobs", "Lists the active jobs", builtin_jobs }, 444 { "jobs", "Lists the active jobs", builtin_jobs },
445#endif
420 { "pwd", "Print current directory", builtin_pwd }, 446 { "pwd", "Print current directory", builtin_pwd },
421 { "read", "Input environment variable", builtin_read }, 447 { "read", "Input environment variable", builtin_read },
422 { "return", "Return from a function", builtin_not_written }, 448 { "return", "Return from a function", builtin_not_written },
@@ -431,6 +457,9 @@ static const struct built_in_command bltins[] = {
431 { NULL, NULL, NULL } 457 { NULL, NULL, NULL }
432}; 458};
433 459
460#if ENABLE_HUSH_INTERACTIVE
461
462#if ENABLE_FEATURE_SH_STANDALONE
434/* move to libbb? */ 463/* move to libbb? */
435static void signal_SA_RESTART(int sig, void (*handler)(int)) 464static void signal_SA_RESTART(int sig, void (*handler)(int))
436{ 465{
@@ -440,6 +469,7 @@ static void signal_SA_RESTART(int sig, void (*handler)(int))
440 sigemptyset(&sa.sa_mask); 469 sigemptyset(&sa.sa_mask);
441 sigaction(sig, &sa, NULL); 470 sigaction(sig, &sa, NULL);
442} 471}
472#endif
443 473
444/* Signals are grouped, we handle them in batches */ 474/* Signals are grouped, we handle them in batches */
445static void set_fatal_sighandler(void (*handler)(int)) 475static void set_fatal_sighandler(void (*handler)(int))
@@ -469,6 +499,7 @@ static void set_misc_sighandler(void (*handler)(int))
469} 499}
470/* SIGCHLD is special and handled separately */ 500/* SIGCHLD is special and handled separately */
471 501
502#if ENABLE_FEATURE_SH_STANDALONE
472static void set_every_sighandler(void (*handler)(int)) 503static void set_every_sighandler(void (*handler)(int))
473{ 504{
474 set_fatal_sighandler(handler); 505 set_fatal_sighandler(handler);
@@ -477,9 +508,9 @@ static void set_every_sighandler(void (*handler)(int))
477 signal(SIGCHLD, handler); 508 signal(SIGCHLD, handler);
478} 509}
479 510
511static struct pipe *nofork_pipe;
480struct nofork_save_area nofork_save; 512struct nofork_save_area nofork_save;
481static sigjmp_buf nofork_jb; 513static sigjmp_buf nofork_jb;
482static struct pipe *nofork_pipe;
483 514
484static void handler_ctrl_c(int sig) 515static void handler_ctrl_c(int sig)
485{ 516{
@@ -522,6 +553,8 @@ static void handler_ctrl_z(int sig)
522 siglongjmp(nofork_jb, 1); 553 siglongjmp(nofork_jb, 1);
523} 554}
524 555
556#endif
557
525/* Restores tty foreground process group, and exits. 558/* Restores tty foreground process group, and exits.
526 * May be called as signal handler for fatal signal 559 * May be called as signal handler for fatal signal
527 * (will faithfully resend signal to itself, producing correct exit state) 560 * (will faithfully resend signal to itself, producing correct exit state)
@@ -559,6 +592,16 @@ static void hush_exit(int exitcode)
559 sigexit(- (exitcode & 0xff)); 592 sigexit(- (exitcode & 0xff));
560} 593}
561 594
595#else /* !INTERACTIVE */
596
597#define set_fatal_sighandler(handler) ((void)0)
598#define set_jobctrl_sighandler(handler) ((void)0)
599#define set_misc_sighandler(handler) ((void)0)
600#define hush_exit(e) exit(-(e))
601
602#endif /* INTERACTIVE */
603
604
562static const char *set_cwd(void) 605static const char *set_cwd(void)
563{ 606{
564 if (cwd == bb_msg_unknown) 607 if (cwd == bb_msg_unknown)
@@ -684,6 +727,7 @@ static int builtin_export(char **argv)
684 return res; 727 return res;
685} 728}
686 729
730#if ENABLE_HUSH_INTERACTIVE
687/* built-in 'fg' and 'bg' handler */ 731/* built-in 'fg' and 'bg' handler */
688static int builtin_fg_bg(char **argv) 732static int builtin_fg_bg(char **argv)
689{ 733{
@@ -745,6 +789,7 @@ static int builtin_fg_bg(char **argv)
745 } 789 }
746 return EXIT_SUCCESS; 790 return EXIT_SUCCESS;
747} 791}
792#endif
748 793
749/* built-in 'help' handler */ 794/* built-in 'help' handler */
750static int builtin_help(char **argv ATTRIBUTE_UNUSED) 795static int builtin_help(char **argv ATTRIBUTE_UNUSED)
@@ -762,6 +807,7 @@ static int builtin_help(char **argv ATTRIBUTE_UNUSED)
762 return EXIT_SUCCESS; 807 return EXIT_SUCCESS;
763} 808}
764 809
810#if ENABLE_HUSH_INTERACTIVE
765/* built-in 'jobs' handler */ 811/* built-in 'jobs' handler */
766static int builtin_jobs(char **argv ATTRIBUTE_UNUSED) 812static int builtin_jobs(char **argv ATTRIBUTE_UNUSED)
767{ 813{
@@ -778,6 +824,7 @@ static int builtin_jobs(char **argv ATTRIBUTE_UNUSED)
778 } 824 }
779 return EXIT_SUCCESS; 825 return EXIT_SUCCESS;
780} 826}
827#endif
781 828
782/* built-in 'pwd' handler */ 829/* built-in 'pwd' handler */
783static int builtin_pwd(char **argv ATTRIBUTE_UNUSED) 830static int builtin_pwd(char **argv ATTRIBUTE_UNUSED)
@@ -1272,7 +1319,9 @@ static void pseudo_exec(struct child_prog *child)
1272 if (child->group) { 1319 if (child->group) {
1273 debug_printf("runtime nesting to group\n"); 1320 debug_printf("runtime nesting to group\n");
1274 // FIXME: do not modify globals! Think vfork! 1321 // FIXME: do not modify globals! Think vfork!
1322#if ENABLE_HUSH_INTERACTIVE
1275 interactive_fd = 0; /* crucial!!!! */ 1323 interactive_fd = 0; /* crucial!!!! */
1324#endif
1276 rcode = run_list_real(child->group); 1325 rcode = run_list_real(child->group);
1277 /* OK to leak memory by not calling free_pipe_list, 1326 /* OK to leak memory by not calling free_pipe_list,
1278 * since this process is about to exit */ 1327 * since this process is about to exit */
@@ -1284,6 +1333,7 @@ static void pseudo_exec(struct child_prog *child)
1284 _exit(EXIT_SUCCESS); 1333 _exit(EXIT_SUCCESS);
1285} 1334}
1286 1335
1336#if ENABLE_HUSH_INTERACTIVE
1287static const char *get_cmdtext(struct pipe *pi) 1337static const char *get_cmdtext(struct pipe *pi)
1288{ 1338{
1289 char **argv; 1339 char **argv;
@@ -1312,7 +1362,9 @@ static const char *get_cmdtext(struct pipe *pi)
1312 p[-1] = '\0'; 1362 p[-1] = '\0';
1313 return pi->cmdtext; 1363 return pi->cmdtext;
1314} 1364}
1365#endif
1315 1366
1367#if ENABLE_HUSH_INTERACTIVE
1316static void insert_bg_job(struct pipe *pi) 1368static void insert_bg_job(struct pipe *pi)
1317{ 1369{
1318 struct pipe *thejob; 1370 struct pipe *thejob;
@@ -1376,6 +1428,7 @@ static void delete_finished_bg_job(struct pipe *pi)
1376 free_pipe(pi, 0); 1428 free_pipe(pi, 0);
1377 free(pi); 1429 free(pi);
1378} 1430}
1431#endif
1379 1432
1380/* Checks to see if any processes have exited -- if they 1433/* Checks to see if any processes have exited -- if they
1381 have, figure out why and see if a job has completed */ 1434 have, figure out why and see if a job has completed */
@@ -1383,8 +1436,10 @@ static int checkjobs(struct pipe* fg_pipe)
1383{ 1436{
1384 int attributes; 1437 int attributes;
1385 int status; 1438 int status;
1439#if ENABLE_HUSH_INTERACTIVE
1386 int prognum = 0; 1440 int prognum = 0;
1387 struct pipe *pi; 1441 struct pipe *pi;
1442#endif
1388 pid_t childpid; 1443 pid_t childpid;
1389 int rcode = 0; 1444 int rcode = 0;
1390 1445
@@ -1401,6 +1456,10 @@ static int checkjobs(struct pipe* fg_pipe)
1401 * 1 <========== bg pipe is not fully done, but exitcode is already known! 1456 * 1 <========== bg pipe is not fully done, but exitcode is already known!
1402 */ 1457 */
1403 1458
1459//FIXME: non-interactive bash does not continue even if all processes in fg pipe
1460//are stopped. Testcase: "cat | cat" in a script (not on command line)
1461// + killall -STOP cat
1462
1404 wait_more: 1463 wait_more:
1405 while ((childpid = waitpid(-1, &status, attributes)) > 0) { 1464 while ((childpid = waitpid(-1, &status, attributes)) > 0) {
1406 const int dead = WIFEXITED(status) || WIFSIGNALED(status); 1465 const int dead = WIFEXITED(status) || WIFSIGNALED(status);
@@ -1437,8 +1496,10 @@ static int checkjobs(struct pipe* fg_pipe)
1437 fg_pipe->running_progs, fg_pipe->stopped_progs); 1496 fg_pipe->running_progs, fg_pipe->stopped_progs);
1438 if (fg_pipe->running_progs - fg_pipe->stopped_progs <= 0) { 1497 if (fg_pipe->running_progs - fg_pipe->stopped_progs <= 0) {
1439 /* All processes in fg pipe have exited/stopped */ 1498 /* All processes in fg pipe have exited/stopped */
1499#if ENABLE_HUSH_INTERACTIVE
1440 if (fg_pipe->running_progs) 1500 if (fg_pipe->running_progs)
1441 insert_bg_job(fg_pipe); 1501 insert_bg_job(fg_pipe);
1502#endif
1442 return rcode; 1503 return rcode;
1443 } 1504 }
1444 /* There are still running processes in the fg pipe */ 1505 /* There are still running processes in the fg pipe */
@@ -1448,6 +1509,7 @@ static int checkjobs(struct pipe* fg_pipe)
1448 /* fall through to searching process in bg pipes */ 1509 /* fall through to searching process in bg pipes */
1449 } 1510 }
1450 1511
1512#if ENABLE_HUSH_INTERACTIVE
1451 /* We asked to wait for bg or orphaned children */ 1513 /* We asked to wait for bg or orphaned children */
1452 /* No need to remember exitcode in this case */ 1514 /* No need to remember exitcode in this case */
1453 for (pi = job_list; pi; pi = pi->next) { 1515 for (pi = job_list; pi; pi = pi->next) {
@@ -1458,11 +1520,13 @@ static int checkjobs(struct pipe* fg_pipe)
1458 prognum++; 1520 prognum++;
1459 } 1521 }
1460 } 1522 }
1523#endif
1461 1524
1462 /* Happens when shell is used as init process (init=/bin/sh) */ 1525 /* Happens when shell is used as init process (init=/bin/sh) */
1463 debug_printf("checkjobs: pid %d was not in our list!\n", childpid); 1526 debug_printf("checkjobs: pid %d was not in our list!\n", childpid);
1464 goto wait_more; 1527 goto wait_more;
1465 1528
1529#if ENABLE_HUSH_INTERACTIVE
1466 found_pi_and_prognum: 1530 found_pi_and_prognum:
1467 if (dead) { 1531 if (dead) {
1468 /* child exited */ 1532 /* child exited */
@@ -1478,6 +1542,7 @@ static int checkjobs(struct pipe* fg_pipe)
1478 pi->stopped_progs++; 1542 pi->stopped_progs++;
1479 pi->progs[prognum].is_stopped = 1; 1543 pi->progs[prognum].is_stopped = 1;
1480 } 1544 }
1545#endif
1481 } 1546 }
1482 1547
1483 /* wait found no children or failed */ 1548 /* wait found no children or failed */
@@ -1491,6 +1556,7 @@ static int checkjobs(struct pipe* fg_pipe)
1491 return rcode; 1556 return rcode;
1492} 1557}
1493 1558
1559#if ENABLE_HUSH_INTERACTIVE
1494static int checkjobs_and_fg_shell(struct pipe* fg_pipe) 1560static int checkjobs_and_fg_shell(struct pipe* fg_pipe)
1495{ 1561{
1496 pid_t p; 1562 pid_t p;
@@ -1502,11 +1568,14 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe)
1502 bb_perror_msg("tcsetpgrp-4a"); 1568 bb_perror_msg("tcsetpgrp-4a");
1503 return rcode; 1569 return rcode;
1504} 1570}
1571#endif
1505 1572
1573#if ENABLE_FEATURE_SH_STANDALONE
1506/* run_pipe_real's helper */ 1574/* run_pipe_real's helper */
1507static int run_single_fg_nofork(struct pipe *pi, const struct bb_applet *a, 1575static int run_single_fg_nofork(struct pipe *pi, const struct bb_applet *a,
1508 char **argv) 1576 char **argv)
1509{ 1577{
1578#if ENABLE_HUSH_INTERACTIVE
1510 int rcode; 1579 int rcode;
1511 /* TSTP handler will store pid etc in pi */ 1580 /* TSTP handler will store pid etc in pi */
1512 nofork_pipe = pi; 1581 nofork_pipe = pi;
@@ -1532,7 +1601,11 @@ static int run_single_fg_nofork(struct pipe *pi, const struct bb_applet *a,
1532 else 1601 else
1533 putchar('\n'); /* bash does this on Ctrl-C */ 1602 putchar('\n'); /* bash does this on Ctrl-C */
1534 return 0; 1603 return 0;
1604#else
1605 return run_nofork_applet(a, argv);
1606#endif
1535} 1607}
1608#endif
1536 1609
1537/* run_pipe_real() starts all the jobs, but doesn't wait for anything 1610/* run_pipe_real() starts all the jobs, but doesn't wait for anything
1538 * to finish. See checkjobs(). 1611 * to finish. See checkjobs().
@@ -1564,7 +1637,9 @@ static int run_pipe_real(struct pipe *pi)
1564 const int single_fg = (pi->num_progs == 1 && pi->followup != PIPE_BG); 1637 const int single_fg = (pi->num_progs == 1 && pi->followup != PIPE_BG);
1565 1638
1566 nextin = 0; 1639 nextin = 0;
1640#if ENABLE_HUSH_INTERACTIVE
1567 pi->pgrp = -1; 1641 pi->pgrp = -1;
1642#endif
1568 pi->running_progs = 0; 1643 pi->running_progs = 0;
1569 pi->stopped_progs = 0; 1644 pi->stopped_progs = 0;
1570 1645
@@ -1691,6 +1766,7 @@ static int run_pipe_real(struct pipe *pi)
1691 if (!child->pid) { /* child */ 1766 if (!child->pid) { /* child */
1692 /* Every child adds itself to new process group 1767 /* Every child adds itself to new process group
1693 * with pgid == pid of first child in pipe */ 1768 * with pgid == pid of first child in pipe */
1769#if ENABLE_HUSH_INTERACTIVE
1694 if (interactive_fd) { 1770 if (interactive_fd) {
1695 /* Don't do pgrp restore anymore on fatal signals */ 1771 /* Don't do pgrp restore anymore on fatal signals */
1696 set_fatal_sighandler(SIG_DFL); 1772 set_fatal_sighandler(SIG_DFL);
@@ -1702,6 +1778,7 @@ static int run_pipe_real(struct pipe *pi)
1702 tcsetpgrp(interactive_fd, pi->pgrp); 1778 tcsetpgrp(interactive_fd, pi->pgrp);
1703 } 1779 }
1704 } 1780 }
1781#endif
1705 // in non-interactive case fatal sigs are already SIG_DFL 1782 // in non-interactive case fatal sigs are already SIG_DFL
1706 close_all(); 1783 close_all();
1707 if (nextin != 0) { 1784 if (nextin != 0) {
@@ -1728,9 +1805,11 @@ static int run_pipe_real(struct pipe *pi)
1728 1805
1729 pi->running_progs++; 1806 pi->running_progs++;
1730 1807
1808#if ENABLE_HUSH_INTERACTIVE
1731 /* Second and next children need to know pid of first one */ 1809 /* Second and next children need to know pid of first one */
1732 if (pi->pgrp < 0) 1810 if (pi->pgrp < 0)
1733 pi->pgrp = child->pid; 1811 pi->pgrp = child->pid;
1812#endif
1734 1813
1735 /* Don't check for errors. The child may be dead already, 1814 /* Don't check for errors. The child may be dead already,
1736 * in which case setpgid returns error code EACCES. */ 1815 * in which case setpgid returns error code EACCES. */
@@ -1858,7 +1937,9 @@ static int run_list_real(struct pipe *pi)
1858 /* XXX check bash's behavior with nontrivial pipes */ 1937 /* XXX check bash's behavior with nontrivial pipes */
1859 /* XXX compute jobid */ 1938 /* XXX compute jobid */
1860 /* XXX what does bash do with attempts to background builtins? */ 1939 /* XXX what does bash do with attempts to background builtins? */
1940#if ENABLE_HUSH_INTERACTIVE
1861 insert_bg_job(pi); 1941 insert_bg_job(pi);
1942#endif
1862 rcode = EXIT_SUCCESS; 1943 rcode = EXIT_SUCCESS;
1863 } else { 1944 } else {
1864 if (interactive_fd) { 1945 if (interactive_fd) {
@@ -1931,8 +2012,10 @@ static int free_pipe(struct pipe *pi, int indent)
1931 } 2012 }
1932 free(pi->progs); /* children are an array, they get freed all at once */ 2013 free(pi->progs); /* children are an array, they get freed all at once */
1933 pi->progs = NULL; 2014 pi->progs = NULL;
2015#if ENABLE_HUSH_INTERACTIVE
1934 free(pi->cmdtext); 2016 free(pi->cmdtext);
1935 pi->cmdtext = NULL; 2017 pi->cmdtext = NULL;
2018#endif
1936 return ret_code; 2019 return ret_code;
1937} 2020}
1938 2021
@@ -3041,6 +3124,7 @@ static int parse_file_outer(FILE *f)
3041 return rcode; 3124 return rcode;
3042} 3125}
3043 3126
3127#if ENABLE_HUSH_INTERACTIVE
3044/* Make sure we have a controlling tty. If we get started under a job 3128/* Make sure we have a controlling tty. If we get started under a job
3045 * aware app (like bash for example), make sure we are now in charge so 3129 * aware app (like bash for example), make sure we are now in charge so
3046 * we don't fight over who gets the foreground */ 3130 * we don't fight over who gets the foreground */
@@ -3055,7 +3139,7 @@ static void setup_job_control(void)
3055 /* If we were ran as 'hush &', 3139 /* If we were ran as 'hush &',
3056 * sleep until we are in the foreground. */ 3140 * sleep until we are in the foreground. */
3057 while (tcgetpgrp(interactive_fd) != shell_pgrp) { 3141 while (tcgetpgrp(interactive_fd) != shell_pgrp) {
3058 /* Send TTIN to ourself (will stop us) */ 3142 /* Send TTIN to ourself (should stop us) */
3059 kill(- shell_pgrp, SIGTTIN); 3143 kill(- shell_pgrp, SIGTTIN);
3060 shell_pgrp = getpgrp(); 3144 shell_pgrp = getpgrp();
3061 } 3145 }
@@ -3073,6 +3157,7 @@ static void setup_job_control(void)
3073 /* Grab control of the terminal. */ 3157 /* Grab control of the terminal. */
3074 tcsetpgrp(interactive_fd, getpid()); 3158 tcsetpgrp(interactive_fd, getpid());
3075} 3159}
3160#endif
3076 3161
3077int hush_main(int argc, char **argv); 3162int hush_main(int argc, char **argv);
3078int hush_main(int argc, char **argv) 3163int hush_main(int argc, char **argv)
@@ -3095,11 +3180,13 @@ int hush_main(int argc, char **argv)
3095 ifs = NULL; 3180 ifs = NULL;
3096 /* map[] is taken care of with call to update_ifs_map() */ 3181 /* map[] is taken care of with call to update_ifs_map() */
3097 fake_mode = 0; 3182 fake_mode = 0;
3098 interactive_fd = 0;
3099 close_me_head = NULL; 3183 close_me_head = NULL;
3184#if ENABLE_HUSH_INTERACTIVE
3185 interactive_fd = 0;
3100 last_bg_pid = 0; 3186 last_bg_pid = 0;
3101 job_list = NULL; 3187 job_list = NULL;
3102 last_jobid = 0; 3188 last_jobid = 0;
3189#endif
3103 3190
3104 /* Initialize some more globals to non-zero values */ 3191 /* Initialize some more globals to non-zero values */
3105 set_cwd(); 3192 set_cwd();
@@ -3154,6 +3241,7 @@ int hush_main(int argc, char **argv)
3154#endif 3241#endif
3155 } 3242 }
3156 } 3243 }
3244#if ENABLE_HUSH_INTERACTIVE
3157 /* A shell is interactive if the '-i' flag was given, or if all of 3245 /* A shell is interactive if the '-i' flag was given, or if all of
3158 * the following conditions are met: 3246 * the following conditions are met:
3159 * no -c command 3247 * no -c command
@@ -3180,7 +3268,6 @@ int hush_main(int argc, char **argv)
3180 // to (inadvertently) close/redirect it 3268 // to (inadvertently) close/redirect it
3181 } 3269 }
3182 } 3270 }
3183
3184 debug_printf("\ninteractive_fd=%d\n", interactive_fd); 3271 debug_printf("\ninteractive_fd=%d\n", interactive_fd);
3185 if (interactive_fd) { 3272 if (interactive_fd) {
3186 /* Looks like they want an interactive shell */ 3273 /* Looks like they want an interactive shell */
@@ -3196,6 +3283,7 @@ int hush_main(int argc, char **argv)
3196 printf("Enter 'help' for a list of built-in commands.\n\n"); 3283 printf("Enter 'help' for a list of built-in commands.\n\n");
3197#endif 3284#endif
3198 } 3285 }
3286#endif
3199 3287
3200 if (argv[optind] == NULL) { 3288 if (argv[optind] == NULL) {
3201 opt = parse_file_outer(stdin); 3289 opt = parse_file_outer(stdin);