diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-04-28 16:48:04 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-04-28 16:48:04 +0000 |
commit | b81b3df1fa387fa5c6a3fe577969285858f494ce (patch) | |
tree | f681253ed7bc21ff3291ae13430db89933f83d29 /shell/hush.c | |
parent | 0937be5fa64e9dc0f2dc525225c34ab7c52f256c (diff) | |
download | busybox-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.c | 116 |
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 | ||
171 | struct redir_struct { | 181 | struct 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 | ||
192 | struct pipe { | 202 | struct 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 | ||
207 | struct close_me { | 219 | struct close_me { |
208 | int fd; | ||
209 | struct close_me *next; | 220 | struct close_me *next; |
221 | int fd; | ||
210 | }; | 222 | }; |
211 | 223 | ||
212 | struct variables { | 224 | struct 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]; | |||
230 | static int fake_mode; | 242 | static int fake_mode; |
231 | static struct close_me *close_me_head; | 243 | static struct close_me *close_me_head; |
232 | static const char *cwd; | 244 | static const char *cwd; |
233 | static struct pipe *job_list; | ||
234 | static unsigned last_bg_pid; | 245 | static unsigned last_bg_pid; |
246 | #if ENABLE_HUSH_INTERACTIVE | ||
235 | static int last_jobid; | 247 | static int last_jobid; |
248 | static 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 */ |
238 | static int interactive_fd; | 251 | static int interactive_fd; |
239 | static pid_t saved_task_pgrp; | 252 | static pid_t saved_task_pgrp; |
240 | static pid_t saved_tty_pgrp; | 253 | static pid_t saved_tty_pgrp; |
254 | #else | ||
255 | enum { interactive_fd = 0 }; | ||
256 | #endif | ||
241 | 257 | ||
242 | static const char *PS1; | 258 | static const char *PS1; |
243 | static const char *PS2; | 259 | static const char *PS2; |
244 | static struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 }; | 260 | static struct variables shell_ver = { NULL, "HUSH_VERSION", "0.01", 1, 1 }; |
245 | static struct variables *top_vars = &shell_ver; | 261 | static struct variables *top_vars = &shell_ver; |
246 | 262 | ||
247 | 263 | ||
@@ -322,9 +338,11 @@ static int builtin_eval(char **argv); | |||
322 | static int builtin_exec(char **argv); | 338 | static int builtin_exec(char **argv); |
323 | static int builtin_exit(char **argv); | 339 | static int builtin_exit(char **argv); |
324 | static int builtin_export(char **argv); | 340 | static int builtin_export(char **argv); |
341 | #if ENABLE_HUSH_INTERACTIVE | ||
325 | static int builtin_fg_bg(char **argv); | 342 | static int builtin_fg_bg(char **argv); |
326 | static int builtin_help(char **argv); | ||
327 | static int builtin_jobs(char **argv); | 343 | static int builtin_jobs(char **argv); |
344 | #endif | ||
345 | static int builtin_help(char **argv); | ||
328 | static int builtin_pwd(char **argv); | 346 | static int builtin_pwd(char **argv); |
329 | static int builtin_read(char **argv); | 347 | static int builtin_read(char **argv); |
330 | static int builtin_set(char **argv); | 348 | static int builtin_set(char **argv); |
@@ -387,10 +405,14 @@ static int parse_string_outer(const char *s, int flag); | |||
387 | static int parse_file_outer(FILE *f); | 405 | static int parse_file_outer(FILE *f); |
388 | /* job management: */ | 406 | /* job management: */ |
389 | static int checkjobs(struct pipe* fg_pipe); | 407 | static int checkjobs(struct pipe* fg_pipe); |
408 | #if ENABLE_HUSH_INTERACTIVE | ||
390 | static int checkjobs_and_fg_shell(struct pipe* fg_pipe); | 409 | static int checkjobs_and_fg_shell(struct pipe* fg_pipe); |
391 | static void insert_bg_job(struct pipe *pi); | 410 | static void insert_bg_job(struct pipe *pi); |
392 | static void remove_bg_job(struct pipe *pi); | 411 | static void remove_bg_job(struct pipe *pi); |
393 | static void delete_finished_bg_job(struct pipe *pi); | 412 | static void delete_finished_bg_job(struct pipe *pi); |
413 | #else | ||
414 | int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */ | ||
415 | #endif | ||
394 | /* local variable support */ | 416 | /* local variable support */ |
395 | static char **make_list_in(char **inp, char *name); | 417 | static char **make_list_in(char **inp, char *name); |
396 | static char *insert_var_value(char *inp); | 418 | static 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. */ |
407 | static const struct built_in_command bltins[] = { | 429 | static 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? */ |
435 | static void signal_SA_RESTART(int sig, void (*handler)(int)) | 464 | static 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 */ |
445 | static void set_fatal_sighandler(void (*handler)(int)) | 475 | static 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 | ||
472 | static void set_every_sighandler(void (*handler)(int)) | 503 | static 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 | ||
511 | static struct pipe *nofork_pipe; | ||
480 | struct nofork_save_area nofork_save; | 512 | struct nofork_save_area nofork_save; |
481 | static sigjmp_buf nofork_jb; | 513 | static sigjmp_buf nofork_jb; |
482 | static struct pipe *nofork_pipe; | ||
483 | 514 | ||
484 | static void handler_ctrl_c(int sig) | 515 | static 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 | |||
562 | static const char *set_cwd(void) | 605 | static 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 */ |
688 | static int builtin_fg_bg(char **argv) | 732 | static 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 */ |
750 | static int builtin_help(char **argv ATTRIBUTE_UNUSED) | 795 | static 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 */ |
766 | static int builtin_jobs(char **argv ATTRIBUTE_UNUSED) | 812 | static 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 */ |
783 | static int builtin_pwd(char **argv ATTRIBUTE_UNUSED) | 830 | static 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 | ||
1287 | static const char *get_cmdtext(struct pipe *pi) | 1337 | static 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 | ||
1316 | static void insert_bg_job(struct pipe *pi) | 1368 | static 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 | ||
1494 | static int checkjobs_and_fg_shell(struct pipe* fg_pipe) | 1560 | static 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 */ |
1507 | static int run_single_fg_nofork(struct pipe *pi, const struct bb_applet *a, | 1575 | static 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 | ||
3077 | int hush_main(int argc, char **argv); | 3162 | int hush_main(int argc, char **argv); |
3078 | int hush_main(int argc, char **argv) | 3163 | int 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); |