diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-09 12:54:58 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-09 12:54:58 +0000 |
commit | 9af22c762652ff92f3f207a754f71f3c4bf2c078 (patch) | |
tree | 8c55f180aa907e151924d1cb8c8e5622eec2f5cb | |
parent | 578de8644c46cd17667812f7e335bf9fefbca00d (diff) | |
download | busybox-w32-9af22c762652ff92f3f207a754f71f3c4bf2c078.tar.gz busybox-w32-9af22c762652ff92f3f207a754f71f3c4bf2c078.tar.bz2 busybox-w32-9af22c762652ff92f3f207a754f71f3c4bf2c078.zip |
hush: massive renaming of ill-named structures and fields
hush: error out on constructs like:
$ abc(def) - was working as if it was (abcdef)
$ case b in abc(a|(b) echo YES; esac - was ignoring 'abc' and extra '('
-rw-r--r-- | shell/hush.c | 408 |
1 files changed, 206 insertions, 202 deletions
diff --git a/shell/hush.c b/shell/hush.c index 6677f893a..c26b9e420 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -45,12 +45,11 @@ | |||
45 | * aliases | 45 | * aliases |
46 | * Arithmetic Expansion | 46 | * Arithmetic Expansion |
47 | * <(list) and >(list) Process Substitution | 47 | * <(list) and >(list) Process Substitution |
48 | * reserved words: case, esac, select, function | 48 | * reserved words: select, function |
49 | * Here Documents ( << word ) | 49 | * Here Documents ( << word ) |
50 | * Functions | 50 | * Functions |
51 | * Major bugs: | 51 | * Major bugs: |
52 | * job handling woefully incomplete and buggy (improved --vda) | 52 | * job handling woefully incomplete and buggy (improved --vda) |
53 | * reserved word execution woefully incomplete and buggy | ||
54 | * to-do: | 53 | * to-do: |
55 | * port selected bugfixes from post-0.49 busybox lash - done? | 54 | * port selected bugfixes from post-0.49 busybox lash - done? |
56 | * change { and } from special chars to reserved words | 55 | * change { and } from special chars to reserved words |
@@ -291,23 +290,6 @@ typedef enum reserved_style { | |||
291 | RES_SNTX | 290 | RES_SNTX |
292 | } reserved_style; | 291 | } reserved_style; |
293 | 292 | ||
294 | /* This holds pointers to the various results of parsing */ | ||
295 | struct p_context { | ||
296 | struct child_prog *child; | ||
297 | struct pipe *list_head; | ||
298 | struct pipe *pipe; | ||
299 | struct redir_struct *pending_redirect; | ||
300 | #if HAS_KEYWORDS | ||
301 | smallint ctx_res_w; | ||
302 | smallint ctx_inverted; /* "! cmd | cmd" */ | ||
303 | #if ENABLE_HUSH_CASE | ||
304 | smallint ctx_dsemicolon; /* ";;" seen */ | ||
305 | #endif | ||
306 | int old_flag; /* bitmask of FLAG_xxx, for figuring out valid reserved words */ | ||
307 | struct p_context *stack; | ||
308 | #endif | ||
309 | }; | ||
310 | |||
311 | struct redir_struct { | 293 | struct redir_struct { |
312 | struct redir_struct *next; | 294 | struct redir_struct *next; |
313 | char *rd_filename; /* filename */ | 295 | char *rd_filename; /* filename */ |
@@ -316,14 +298,14 @@ struct redir_struct { | |||
316 | smallint /*enum redir_type*/ rd_type; | 298 | smallint /*enum redir_type*/ rd_type; |
317 | }; | 299 | }; |
318 | 300 | ||
319 | struct child_prog { | 301 | struct command { |
320 | pid_t pid; /* 0 if exited */ | 302 | pid_t pid; /* 0 if exited */ |
321 | int assignment_cnt; /* how many argv[i] are assignments? */ | 303 | int assignment_cnt; /* how many argv[i] are assignments? */ |
322 | smallint is_stopped; /* is the program currently running? */ | 304 | smallint is_stopped; /* is the command currently running? */ |
323 | smallint subshell; /* flag, non-zero if group must be forked */ | 305 | smallint subshell; /* flag, non-zero if group must be forked */ |
324 | struct pipe *group; /* if non-NULL, this "prog" is {} group, | 306 | struct pipe *group; /* if non-NULL, this "prog" is {} group, |
325 | * subshell, or a compound statement */ | 307 | * subshell, or a compound statement */ |
326 | char **argv; /* program name and arguments */ | 308 | char **argv; /* command name and arguments */ |
327 | struct redir_struct *redirects; /* I/O redirections */ | 309 | struct redir_struct *redirects; /* I/O redirections */ |
328 | }; | 310 | }; |
329 | /* argv vector may contain variable references (^Cvar^C, ^C0^C etc) | 311 | /* argv vector may contain variable references (^Cvar^C, ^C0^C etc) |
@@ -335,20 +317,37 @@ struct child_prog { | |||
335 | 317 | ||
336 | struct pipe { | 318 | struct pipe { |
337 | struct pipe *next; | 319 | struct pipe *next; |
338 | int num_progs; /* total number of programs in job */ | 320 | int num_cmds; /* total number of commands in job */ |
339 | int alive_progs; /* number of programs running (not exited) */ | 321 | int alive_cmds; /* number of commands running (not exited) */ |
340 | int stopped_progs; /* number of programs alive, but stopped */ | 322 | int stopped_cmds; /* number of commands alive, but stopped */ |
341 | #if ENABLE_HUSH_JOB | 323 | #if ENABLE_HUSH_JOB |
342 | int jobid; /* job number */ | 324 | int jobid; /* job number */ |
343 | pid_t pgrp; /* process group ID for the job */ | 325 | pid_t pgrp; /* process group ID for the job */ |
344 | char *cmdtext; /* name of job */ | 326 | char *cmdtext; /* name of job */ |
345 | #endif | 327 | #endif |
346 | struct child_prog *progs; /* array of commands in pipe */ | 328 | struct command *cmds; /* array of commands in pipe */ |
347 | smallint followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ | 329 | smallint followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ |
348 | IF_HAS_KEYWORDS(smallint pi_inverted;) /* "! cmd | cmd" */ | 330 | IF_HAS_KEYWORDS(smallint pi_inverted;) /* "! cmd | cmd" */ |
349 | IF_HAS_KEYWORDS(smallint res_word;) /* needed for if, for, while, until... */ | 331 | IF_HAS_KEYWORDS(smallint res_word;) /* needed for if, for, while, until... */ |
350 | }; | 332 | }; |
351 | 333 | ||
334 | /* This holds pointers to the various results of parsing */ | ||
335 | struct parse_context { | ||
336 | struct command *command; | ||
337 | struct pipe *list_head; | ||
338 | struct pipe *pipe; | ||
339 | struct redir_struct *pending_redirect; | ||
340 | #if HAS_KEYWORDS | ||
341 | smallint ctx_res_w; | ||
342 | smallint ctx_inverted; /* "! cmd | cmd" */ | ||
343 | #if ENABLE_HUSH_CASE | ||
344 | smallint ctx_dsemicolon; /* ";;" seen */ | ||
345 | #endif | ||
346 | int old_flag; /* bitmask of FLAG_xxx, for figuring out valid reserved words */ | ||
347 | struct parse_context *stack; | ||
348 | #endif | ||
349 | }; | ||
350 | |||
352 | /* On program start, environ points to initial environment. | 351 | /* On program start, environ points to initial environment. |
353 | * putenv adds new pointers into it, unsetenv removes them. | 352 | * putenv adds new pointers into it, unsetenv removes them. |
354 | * Neither of these (de)allocates the strings. | 353 | * Neither of these (de)allocates the strings. |
@@ -523,23 +522,23 @@ static void setup_string_in_str(struct in_str *i, const char *s); | |||
523 | static int free_pipe_list(struct pipe *head, int indent); | 522 | static int free_pipe_list(struct pipe *head, int indent); |
524 | static int free_pipe(struct pipe *pi, int indent); | 523 | static int free_pipe(struct pipe *pi, int indent); |
525 | /* really run the final data structures: */ | 524 | /* really run the final data structures: */ |
526 | static int setup_redirects(struct child_prog *prog, int squirrel[]); | 525 | static int setup_redirects(struct command *prog, int squirrel[]); |
527 | static int run_list(struct pipe *pi); | 526 | static int run_list(struct pipe *pi); |
528 | #if BB_MMU | 527 | #if BB_MMU |
529 | #define pseudo_exec_argv(ptrs2free, argv, assignment_cnt, argv_expanded) \ | 528 | #define pseudo_exec_argv(ptrs2free, argv, assignment_cnt, argv_expanded) \ |
530 | pseudo_exec_argv(argv, assignment_cnt, argv_expanded) | 529 | pseudo_exec_argv(argv, assignment_cnt, argv_expanded) |
531 | #define pseudo_exec(ptrs2free, child, argv_expanded) \ | 530 | #define pseudo_exec(ptrs2free, command, argv_expanded) \ |
532 | pseudo_exec(child, argv_expanded) | 531 | pseudo_exec(command, argv_expanded) |
533 | #endif | 532 | #endif |
534 | static void pseudo_exec_argv(char **ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) NORETURN; | 533 | static void pseudo_exec_argv(char **ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) NORETURN; |
535 | static void pseudo_exec(char **ptrs2free, struct child_prog *child, char **argv_expanded) NORETURN; | 534 | static void pseudo_exec(char **ptrs2free, struct command *command, char **argv_expanded) NORETURN; |
536 | static int run_pipe(struct pipe *pi); | 535 | static int run_pipe(struct pipe *pi); |
537 | /* data structure manipulation: */ | 536 | /* data structure manipulation: */ |
538 | static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input); | 537 | static int setup_redirect(struct parse_context *ctx, int fd, redir_type style, struct in_str *input); |
539 | static void initialize_context(struct p_context *ctx); | 538 | static void initialize_context(struct parse_context *ctx); |
540 | static int done_word(o_string *dest, struct p_context *ctx); | 539 | static int done_word(o_string *dest, struct parse_context *ctx); |
541 | static int done_command(struct p_context *ctx); | 540 | static int done_command(struct parse_context *ctx); |
542 | static void done_pipe(struct p_context *ctx, pipe_style type); | 541 | static void done_pipe(struct parse_context *ctx, pipe_style type); |
543 | /* primary string parsing: */ | 542 | /* primary string parsing: */ |
544 | static int redirect_dup_num(struct in_str *input); | 543 | static int redirect_dup_num(struct in_str *input); |
545 | static int redirect_opt_num(o_string *o); | 544 | static int redirect_opt_num(o_string *o); |
@@ -547,11 +546,11 @@ static int redirect_opt_num(o_string *o); | |||
547 | static int process_command_subs(o_string *dest, | 546 | static int process_command_subs(o_string *dest, |
548 | struct in_str *input, const char *subst_end); | 547 | struct in_str *input, const char *subst_end); |
549 | #endif | 548 | #endif |
550 | static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); | 549 | static int parse_group(o_string *dest, struct parse_context *ctx, struct in_str *input, int ch); |
551 | static const char *lookup_param(const char *src); | 550 | static const char *lookup_param(const char *src); |
552 | static int handle_dollar(o_string *dest, | 551 | static int handle_dollar(o_string *dest, |
553 | struct in_str *input); | 552 | struct in_str *input); |
554 | static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger); | 553 | static int parse_stream(o_string *dest, struct parse_context *ctx, struct in_str *input0, const char *end_trigger); |
555 | /* setup: */ | 554 | /* setup: */ |
556 | static int parse_and_run_stream(struct in_str *inp, int parse_flag); | 555 | static int parse_and_run_stream(struct in_str *inp, int parse_flag); |
557 | static int parse_and_run_string(const char *s, int parse_flag); | 556 | static int parse_and_run_string(const char *s, int parse_flag); |
@@ -837,7 +836,7 @@ static void handler_ctrl_z(int sig UNUSED_PARAM) | |||
837 | /* parent */ | 836 | /* parent */ |
838 | /* finish filling up pipe info */ | 837 | /* finish filling up pipe info */ |
839 | G.toplevel_list->pgrp = pid; /* child is in its own pgrp */ | 838 | G.toplevel_list->pgrp = pid; /* child is in its own pgrp */ |
840 | G.toplevel_list->progs[0].pid = pid; | 839 | G.toplevel_list->cmds[0].pid = pid; |
841 | /* parent needs to longjmp out of running nofork. | 840 | /* parent needs to longjmp out of running nofork. |
842 | * we will "return" exitcode 0, with child put in background */ | 841 | * we will "return" exitcode 0, with child put in background */ |
843 | // as usual we can have all kinds of nasty problems with leaked malloc data here | 842 | // as usual we can have all kinds of nasty problems with leaked malloc data here |
@@ -1334,7 +1333,7 @@ static void setup_string_in_str(struct in_str *i, const char *s) | |||
1334 | 1333 | ||
1335 | /* squirrel != NULL means we squirrel away copies of stdin, stdout, | 1334 | /* squirrel != NULL means we squirrel away copies of stdin, stdout, |
1336 | * and stderr if they are redirected. */ | 1335 | * and stderr if they are redirected. */ |
1337 | static int setup_redirects(struct child_prog *prog, int squirrel[]) | 1336 | static int setup_redirects(struct command *prog, int squirrel[]) |
1338 | { | 1337 | { |
1339 | int openfd, mode; | 1338 | int openfd, mode; |
1340 | struct redir_struct *redir; | 1339 | struct redir_struct *redir; |
@@ -1467,18 +1466,18 @@ static void pseudo_exec_argv(char **ptrs2free, char **argv, int assignment_cnt, | |||
1467 | 1466 | ||
1468 | /* Called after [v]fork() in run_pipe() | 1467 | /* Called after [v]fork() in run_pipe() |
1469 | */ | 1468 | */ |
1470 | static void pseudo_exec(char **ptrs2free, struct child_prog *child, char **argv_expanded) | 1469 | static void pseudo_exec(char **ptrs2free, struct command *command, char **argv_expanded) |
1471 | { | 1470 | { |
1472 | if (child->argv) | 1471 | if (command->argv) |
1473 | pseudo_exec_argv(ptrs2free, child->argv, child->assignment_cnt, argv_expanded); | 1472 | pseudo_exec_argv(ptrs2free, command->argv, command->assignment_cnt, argv_expanded); |
1474 | 1473 | ||
1475 | if (child->group) { | 1474 | if (command->group) { |
1476 | #if !BB_MMU | 1475 | #if !BB_MMU |
1477 | bb_error_msg_and_die("nested lists are not supported on NOMMU"); | 1476 | bb_error_msg_and_die("nested lists are not supported on NOMMU"); |
1478 | #else | 1477 | #else |
1479 | int rcode; | 1478 | int rcode; |
1480 | debug_printf_exec("pseudo_exec: run_list\n"); | 1479 | debug_printf_exec("pseudo_exec: run_list\n"); |
1481 | rcode = run_list(child->group); | 1480 | rcode = run_list(command->group); |
1482 | /* OK to leak memory by not calling free_pipe_list, | 1481 | /* OK to leak memory by not calling free_pipe_list, |
1483 | * since this process is about to exit */ | 1482 | * since this process is about to exit */ |
1484 | _exit(rcode); | 1483 | _exit(rcode); |
@@ -1502,7 +1501,7 @@ static const char *get_cmdtext(struct pipe *pi) | |||
1502 | * On subsequent bg argv is trashed, but we won't use it */ | 1501 | * On subsequent bg argv is trashed, but we won't use it */ |
1503 | if (pi->cmdtext) | 1502 | if (pi->cmdtext) |
1504 | return pi->cmdtext; | 1503 | return pi->cmdtext; |
1505 | argv = pi->progs[0].argv; | 1504 | argv = pi->cmds[0].argv; |
1506 | if (!argv || !argv[0]) { | 1505 | if (!argv || !argv[0]) { |
1507 | pi->cmdtext = xzalloc(1); | 1506 | pi->cmdtext = xzalloc(1); |
1508 | return pi->cmdtext; | 1507 | return pi->cmdtext; |
@@ -1511,7 +1510,7 @@ static const char *get_cmdtext(struct pipe *pi) | |||
1511 | len = 0; | 1510 | len = 0; |
1512 | do len += strlen(*argv) + 1; while (*++argv); | 1511 | do len += strlen(*argv) + 1; while (*++argv); |
1513 | pi->cmdtext = p = xmalloc(len); | 1512 | pi->cmdtext = p = xmalloc(len); |
1514 | argv = pi->progs[0].argv; | 1513 | argv = pi->cmds[0].argv; |
1515 | do { | 1514 | do { |
1516 | len = strlen(*argv); | 1515 | len = strlen(*argv); |
1517 | memcpy(p, *argv, len); | 1516 | memcpy(p, *argv, len); |
@@ -1545,12 +1544,12 @@ static void insert_bg_job(struct pipe *pi) | |||
1545 | 1544 | ||
1546 | /* Physically copy the struct job */ | 1545 | /* Physically copy the struct job */ |
1547 | memcpy(thejob, pi, sizeof(struct pipe)); | 1546 | memcpy(thejob, pi, sizeof(struct pipe)); |
1548 | thejob->progs = xzalloc(sizeof(pi->progs[0]) * pi->num_progs); | 1547 | thejob->cmds = xzalloc(sizeof(pi->cmds[0]) * pi->num_cmds); |
1549 | /* We cannot copy entire pi->progs[] vector! Double free()s will happen */ | 1548 | /* We cannot copy entire pi->cmds[] vector! Double free()s will happen */ |
1550 | for (i = 0; i < pi->num_progs; i++) { | 1549 | for (i = 0; i < pi->num_cmds; i++) { |
1551 | // TODO: do we really need to have so many fields which are just dead weight | 1550 | // TODO: do we really need to have so many fields which are just dead weight |
1552 | // at execution stage? | 1551 | // at execution stage? |
1553 | thejob->progs[i].pid = pi->progs[i].pid; | 1552 | thejob->cmds[i].pid = pi->cmds[i].pid; |
1554 | /* all other fields are not used and stay zero */ | 1553 | /* all other fields are not used and stay zero */ |
1555 | } | 1554 | } |
1556 | thejob->next = NULL; | 1555 | thejob->next = NULL; |
@@ -1558,8 +1557,8 @@ static void insert_bg_job(struct pipe *pi) | |||
1558 | 1557 | ||
1559 | /* We don't wait for background thejobs to return -- append it | 1558 | /* We don't wait for background thejobs to return -- append it |
1560 | to the list of backgrounded thejobs and leave it alone */ | 1559 | to the list of backgrounded thejobs and leave it alone */ |
1561 | printf("[%d] %d %s\n", thejob->jobid, thejob->progs[0].pid, thejob->cmdtext); | 1560 | printf("[%d] %d %s\n", thejob->jobid, thejob->cmds[0].pid, thejob->cmdtext); |
1562 | G.last_bg_pid = thejob->progs[0].pid; | 1561 | G.last_bg_pid = thejob->cmds[0].pid; |
1563 | G.last_jobid = thejob->jobid; | 1562 | G.last_jobid = thejob->jobid; |
1564 | } | 1563 | } |
1565 | 1564 | ||
@@ -1585,7 +1584,7 @@ static void remove_bg_job(struct pipe *pi) | |||
1585 | static void delete_finished_bg_job(struct pipe *pi) | 1584 | static void delete_finished_bg_job(struct pipe *pi) |
1586 | { | 1585 | { |
1587 | remove_bg_job(pi); | 1586 | remove_bg_job(pi); |
1588 | pi->stopped_progs = 0; | 1587 | pi->stopped_cmds = 0; |
1589 | free_pipe(pi, 0); | 1588 | free_pipe(pi, 0); |
1590 | free(pi); | 1589 | free(pi); |
1591 | } | 1590 | } |
@@ -1637,29 +1636,29 @@ static int checkjobs(struct pipe* fg_pipe) | |||
1637 | #endif | 1636 | #endif |
1638 | /* Were we asked to wait for fg pipe? */ | 1637 | /* Were we asked to wait for fg pipe? */ |
1639 | if (fg_pipe) { | 1638 | if (fg_pipe) { |
1640 | for (i = 0; i < fg_pipe->num_progs; i++) { | 1639 | for (i = 0; i < fg_pipe->num_cmds; i++) { |
1641 | debug_printf_jobs("check pid %d\n", fg_pipe->progs[i].pid); | 1640 | debug_printf_jobs("check pid %d\n", fg_pipe->cmds[i].pid); |
1642 | if (fg_pipe->progs[i].pid != childpid) | 1641 | if (fg_pipe->cmds[i].pid != childpid) |
1643 | continue; | 1642 | continue; |
1644 | /* printf("process %d exit %d\n", i, WEXITSTATUS(status)); */ | 1643 | /* printf("process %d exit %d\n", i, WEXITSTATUS(status)); */ |
1645 | if (dead) { | 1644 | if (dead) { |
1646 | fg_pipe->progs[i].pid = 0; | 1645 | fg_pipe->cmds[i].pid = 0; |
1647 | fg_pipe->alive_progs--; | 1646 | fg_pipe->alive_cmds--; |
1648 | if (i == fg_pipe->num_progs - 1) { | 1647 | if (i == fg_pipe->num_cmds - 1) { |
1649 | /* last process gives overall exitstatus */ | 1648 | /* last process gives overall exitstatus */ |
1650 | rcode = WEXITSTATUS(status); | 1649 | rcode = WEXITSTATUS(status); |
1651 | IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) | 1650 | IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) |
1652 | } | 1651 | } |
1653 | } else { | 1652 | } else { |
1654 | fg_pipe->progs[i].is_stopped = 1; | 1653 | fg_pipe->cmds[i].is_stopped = 1; |
1655 | fg_pipe->stopped_progs++; | 1654 | fg_pipe->stopped_cmds++; |
1656 | } | 1655 | } |
1657 | debug_printf_jobs("fg_pipe: alive_progs %d stopped_progs %d\n", | 1656 | debug_printf_jobs("fg_pipe: alive_cmds %d stopped_cmds %d\n", |
1658 | fg_pipe->alive_progs, fg_pipe->stopped_progs); | 1657 | fg_pipe->alive_cmds, fg_pipe->stopped_cmds); |
1659 | if (fg_pipe->alive_progs - fg_pipe->stopped_progs <= 0) { | 1658 | if (fg_pipe->alive_cmds - fg_pipe->stopped_cmds <= 0) { |
1660 | /* All processes in fg pipe have exited/stopped */ | 1659 | /* All processes in fg pipe have exited/stopped */ |
1661 | #if ENABLE_HUSH_JOB | 1660 | #if ENABLE_HUSH_JOB |
1662 | if (fg_pipe->alive_progs) | 1661 | if (fg_pipe->alive_cmds) |
1663 | insert_bg_job(fg_pipe); | 1662 | insert_bg_job(fg_pipe); |
1664 | #endif | 1663 | #endif |
1665 | return rcode; | 1664 | return rcode; |
@@ -1674,8 +1673,8 @@ static int checkjobs(struct pipe* fg_pipe) | |||
1674 | /* We asked to wait for bg or orphaned children */ | 1673 | /* We asked to wait for bg or orphaned children */ |
1675 | /* No need to remember exitcode in this case */ | 1674 | /* No need to remember exitcode in this case */ |
1676 | for (pi = G.job_list; pi; pi = pi->next) { | 1675 | for (pi = G.job_list; pi; pi = pi->next) { |
1677 | for (i = 0; i < pi->num_progs; i++) { | 1676 | for (i = 0; i < pi->num_cmds; i++) { |
1678 | if (pi->progs[i].pid == childpid) | 1677 | if (pi->cmds[i].pid == childpid) |
1679 | goto found_pi_and_prognum; | 1678 | goto found_pi_and_prognum; |
1680 | } | 1679 | } |
1681 | } | 1680 | } |
@@ -1686,17 +1685,17 @@ static int checkjobs(struct pipe* fg_pipe) | |||
1686 | found_pi_and_prognum: | 1685 | found_pi_and_prognum: |
1687 | if (dead) { | 1686 | if (dead) { |
1688 | /* child exited */ | 1687 | /* child exited */ |
1689 | pi->progs[i].pid = 0; | 1688 | pi->cmds[i].pid = 0; |
1690 | pi->alive_progs--; | 1689 | pi->alive_cmds--; |
1691 | if (!pi->alive_progs) { | 1690 | if (!pi->alive_cmds) { |
1692 | printf(JOB_STATUS_FORMAT, pi->jobid, | 1691 | printf(JOB_STATUS_FORMAT, pi->jobid, |
1693 | "Done", pi->cmdtext); | 1692 | "Done", pi->cmdtext); |
1694 | delete_finished_bg_job(pi); | 1693 | delete_finished_bg_job(pi); |
1695 | } | 1694 | } |
1696 | } else { | 1695 | } else { |
1697 | /* child stopped */ | 1696 | /* child stopped */ |
1698 | pi->progs[i].is_stopped = 1; | 1697 | pi->cmds[i].is_stopped = 1; |
1699 | pi->stopped_progs++; | 1698 | pi->stopped_cmds++; |
1700 | } | 1699 | } |
1701 | #endif | 1700 | #endif |
1702 | } /* while (waitpid succeeds)... */ | 1701 | } /* while (waitpid succeeds)... */ |
@@ -1745,7 +1744,7 @@ static int run_pipe(struct pipe *pi) | |||
1745 | int i; | 1744 | int i; |
1746 | int nextin; | 1745 | int nextin; |
1747 | int pipefds[2]; /* pipefds[0] is for reading */ | 1746 | int pipefds[2]; /* pipefds[0] is for reading */ |
1748 | struct child_prog *child; | 1747 | struct command *command; |
1749 | char **argv_expanded = NULL; | 1748 | char **argv_expanded = NULL; |
1750 | char **argv; | 1749 | char **argv; |
1751 | const struct built_in_command *x; | 1750 | const struct built_in_command *x; |
@@ -1753,36 +1752,36 @@ static int run_pipe(struct pipe *pi) | |||
1753 | /* it is not always needed, but we aim to smaller code */ | 1752 | /* it is not always needed, but we aim to smaller code */ |
1754 | int squirrel[] = { -1, -1, -1 }; | 1753 | int squirrel[] = { -1, -1, -1 }; |
1755 | int rcode; | 1754 | int rcode; |
1756 | const int single_and_fg = (pi->num_progs == 1 && pi->followup != PIPE_BG); | 1755 | const int single_and_fg = (pi->num_cmds == 1 && pi->followup != PIPE_BG); |
1757 | 1756 | ||
1758 | debug_printf_exec("run_pipe start: single_and_fg=%d\n", single_and_fg); | 1757 | debug_printf_exec("run_pipe start: single_and_fg=%d\n", single_and_fg); |
1759 | 1758 | ||
1760 | #if ENABLE_HUSH_JOB | 1759 | #if ENABLE_HUSH_JOB |
1761 | pi->pgrp = -1; | 1760 | pi->pgrp = -1; |
1762 | #endif | 1761 | #endif |
1763 | pi->alive_progs = 1; | 1762 | pi->alive_cmds = 1; |
1764 | pi->stopped_progs = 0; | 1763 | pi->stopped_cmds = 0; |
1765 | 1764 | ||
1766 | /* Check if this is a simple builtin (not part of a pipe). | 1765 | /* Check if this is a simple builtin (not part of a pipe). |
1767 | * Builtins within pipes have to fork anyway, and are handled in | 1766 | * Builtins within pipes have to fork anyway, and are handled in |
1768 | * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. | 1767 | * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. |
1769 | */ | 1768 | */ |
1770 | child = &(pi->progs[0]); | 1769 | command = &(pi->cmds[0]); |
1771 | if (single_and_fg && child->group && child->subshell == 0) { | 1770 | if (single_and_fg && command->group && command->subshell == 0) { |
1772 | debug_printf("non-subshell grouping\n"); | 1771 | debug_printf("non-subshell grouping\n"); |
1773 | setup_redirects(child, squirrel); | 1772 | setup_redirects(command, squirrel); |
1774 | debug_printf_exec(": run_list\n"); | 1773 | debug_printf_exec(": run_list\n"); |
1775 | rcode = run_list(child->group) & 0xff; | 1774 | rcode = run_list(command->group) & 0xff; |
1776 | restore_redirects(squirrel); | 1775 | restore_redirects(squirrel); |
1777 | debug_printf_exec("run_pipe return %d\n", rcode); | 1776 | debug_printf_exec("run_pipe return %d\n", rcode); |
1778 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) | 1777 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) |
1779 | return rcode; | 1778 | return rcode; |
1780 | } | 1779 | } |
1781 | 1780 | ||
1782 | argv = child->argv; | 1781 | argv = command->argv; |
1783 | 1782 | ||
1784 | if (single_and_fg && argv != NULL) { | 1783 | if (single_and_fg && argv != NULL) { |
1785 | i = child->assignment_cnt; | 1784 | i = command->assignment_cnt; |
1786 | if (i != 0 && argv[i] == NULL) { | 1785 | if (i != 0 && argv[i] == NULL) { |
1787 | /* assignments, but no command: set local environment */ | 1786 | /* assignments, but no command: set local environment */ |
1788 | for (i = 0; argv[i] != NULL; i++) { | 1787 | for (i = 0; argv[i] != NULL; i++) { |
@@ -1794,7 +1793,7 @@ static int run_pipe(struct pipe *pi) | |||
1794 | } | 1793 | } |
1795 | 1794 | ||
1796 | /* Expand assignments into one string each */ | 1795 | /* Expand assignments into one string each */ |
1797 | for (i = 0; i < child->assignment_cnt; i++) { | 1796 | for (i = 0; i < command->assignment_cnt; i++) { |
1798 | p = expand_string_to_string(argv[i]); | 1797 | p = expand_string_to_string(argv[i]); |
1799 | putenv(p); | 1798 | putenv(p); |
1800 | //FIXME: do we leak p?! | 1799 | //FIXME: do we leak p?! |
@@ -1807,7 +1806,7 @@ static int run_pipe(struct pipe *pi) | |||
1807 | if (strcmp(argv_expanded[0], x->cmd) == 0) { | 1806 | if (strcmp(argv_expanded[0], x->cmd) == 0) { |
1808 | if (x->function == builtin_exec && argv_expanded[1] == NULL) { | 1807 | if (x->function == builtin_exec && argv_expanded[1] == NULL) { |
1809 | debug_printf("magic exec\n"); | 1808 | debug_printf("magic exec\n"); |
1810 | setup_redirects(child, NULL); | 1809 | setup_redirects(command, NULL); |
1811 | return EXIT_SUCCESS; | 1810 | return EXIT_SUCCESS; |
1812 | } | 1811 | } |
1813 | debug_printf("builtin inline %s\n", argv_expanded[0]); | 1812 | debug_printf("builtin inline %s\n", argv_expanded[0]); |
@@ -1815,7 +1814,7 @@ static int run_pipe(struct pipe *pi) | |||
1815 | * This is perfect for work that comes after exec(). | 1814 | * This is perfect for work that comes after exec(). |
1816 | * Is it really safe for inline use? Experimentally, | 1815 | * Is it really safe for inline use? Experimentally, |
1817 | * things seem to work with glibc. */ | 1816 | * things seem to work with glibc. */ |
1818 | setup_redirects(child, squirrel); | 1817 | setup_redirects(command, squirrel); |
1819 | debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv_expanded[1]); | 1818 | debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv_expanded[1]); |
1820 | rcode = x->function(argv_expanded) & 0xff; | 1819 | rcode = x->function(argv_expanded) & 0xff; |
1821 | free(argv_expanded); | 1820 | free(argv_expanded); |
@@ -1829,7 +1828,7 @@ static int run_pipe(struct pipe *pi) | |||
1829 | { | 1828 | { |
1830 | int a = find_applet_by_name(argv_expanded[0]); | 1829 | int a = find_applet_by_name(argv_expanded[0]); |
1831 | if (a >= 0 && APPLET_IS_NOFORK(a)) { | 1830 | if (a >= 0 && APPLET_IS_NOFORK(a)) { |
1832 | setup_redirects(child, squirrel); | 1831 | setup_redirects(command, squirrel); |
1833 | save_nofork_data(&G.nofork_save); | 1832 | save_nofork_data(&G.nofork_save); |
1834 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); | 1833 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); |
1835 | rcode = run_nofork_applet_prime(&G.nofork_save, a, argv_expanded); | 1834 | rcode = run_nofork_applet_prime(&G.nofork_save, a, argv_expanded); |
@@ -1852,18 +1851,18 @@ static int run_pipe(struct pipe *pi) | |||
1852 | set_jobctrl_sighandler(SIG_IGN); | 1851 | set_jobctrl_sighandler(SIG_IGN); |
1853 | 1852 | ||
1854 | /* Going to fork a child per each pipe member */ | 1853 | /* Going to fork a child per each pipe member */ |
1855 | pi->alive_progs = 0; | 1854 | pi->alive_cmds = 0; |
1856 | nextin = 0; | 1855 | nextin = 0; |
1857 | 1856 | ||
1858 | for (i = 0; i < pi->num_progs; i++) { | 1857 | for (i = 0; i < pi->num_cmds; i++) { |
1859 | #if !BB_MMU | 1858 | #if !BB_MMU |
1860 | char **ptrs2free = NULL; | 1859 | char **ptrs2free = NULL; |
1861 | #endif | 1860 | #endif |
1862 | child = &(pi->progs[i]); | 1861 | command = &(pi->cmds[i]); |
1863 | if (child->argv) { | 1862 | if (command->argv) { |
1864 | debug_printf_exec(": pipe member '%s' '%s'...\n", child->argv[0], child->argv[1]); | 1863 | debug_printf_exec(": pipe member '%s' '%s'...\n", command->argv[0], command->argv[1]); |
1865 | #if !BB_MMU | 1864 | #if !BB_MMU |
1866 | ptrs2free = alloc_ptrs(child->argv); | 1865 | ptrs2free = alloc_ptrs(command->argv); |
1867 | #endif | 1866 | #endif |
1868 | } else | 1867 | } else |
1869 | debug_printf_exec(": pipe member with no argv\n"); | 1868 | debug_printf_exec(": pipe member with no argv\n"); |
@@ -1871,11 +1870,11 @@ static int run_pipe(struct pipe *pi) | |||
1871 | /* pipes are inserted between pairs of commands */ | 1870 | /* pipes are inserted between pairs of commands */ |
1872 | pipefds[0] = 0; | 1871 | pipefds[0] = 0; |
1873 | pipefds[1] = 1; | 1872 | pipefds[1] = 1; |
1874 | if ((i + 1) < pi->num_progs) | 1873 | if ((i + 1) < pi->num_cmds) |
1875 | xpipe(pipefds); | 1874 | xpipe(pipefds); |
1876 | 1875 | ||
1877 | child->pid = BB_MMU ? fork() : vfork(); | 1876 | command->pid = BB_MMU ? fork() : vfork(); |
1878 | if (!child->pid) { /* child */ | 1877 | if (!command->pid) { /* child */ |
1879 | if (ENABLE_HUSH_JOB) | 1878 | if (ENABLE_HUSH_JOB) |
1880 | die_sleep = 0; /* let nofork's xfuncs die */ | 1879 | die_sleep = 0; /* let nofork's xfuncs die */ |
1881 | #if ENABLE_HUSH_JOB | 1880 | #if ENABLE_HUSH_JOB |
@@ -1901,45 +1900,45 @@ static int run_pipe(struct pipe *pi) | |||
1901 | close(pipefds[0]); /* read end */ | 1900 | close(pipefds[0]); /* read end */ |
1902 | /* Like bash, explicit redirects override pipes, | 1901 | /* Like bash, explicit redirects override pipes, |
1903 | * and the pipe fd is available for dup'ing. */ | 1902 | * and the pipe fd is available for dup'ing. */ |
1904 | setup_redirects(child, NULL); | 1903 | setup_redirects(command, NULL); |
1905 | 1904 | ||
1906 | /* Restore default handlers just prior to exec */ | 1905 | /* Restore default handlers just prior to exec */ |
1907 | set_jobctrl_sighandler(SIG_DFL); | 1906 | set_jobctrl_sighandler(SIG_DFL); |
1908 | set_misc_sighandler(SIG_DFL); | 1907 | set_misc_sighandler(SIG_DFL); |
1909 | signal(SIGCHLD, SIG_DFL); | 1908 | signal(SIGCHLD, SIG_DFL); |
1910 | pseudo_exec(ptrs2free, child, argv_expanded); /* does not return */ | 1909 | pseudo_exec(ptrs2free, command, argv_expanded); /* does not return */ |
1911 | } | 1910 | } |
1912 | free(argv_expanded); | 1911 | free(argv_expanded); |
1913 | argv_expanded = NULL; | 1912 | argv_expanded = NULL; |
1914 | #if !BB_MMU | 1913 | #if !BB_MMU |
1915 | free_strings(ptrs2free); | 1914 | free_strings(ptrs2free); |
1916 | #endif | 1915 | #endif |
1917 | if (child->pid < 0) { /* [v]fork failed */ | 1916 | if (command->pid < 0) { /* [v]fork failed */ |
1918 | /* Clearly indicate, was it fork or vfork */ | 1917 | /* Clearly indicate, was it fork or vfork */ |
1919 | bb_perror_msg(BB_MMU ? "fork" : "vfork"); | 1918 | bb_perror_msg(BB_MMU ? "fork" : "vfork"); |
1920 | } else { | 1919 | } else { |
1921 | pi->alive_progs++; | 1920 | pi->alive_cmds++; |
1922 | #if ENABLE_HUSH_JOB | 1921 | #if ENABLE_HUSH_JOB |
1923 | /* Second and next children need to know pid of first one */ | 1922 | /* Second and next children need to know pid of first one */ |
1924 | if (pi->pgrp < 0) | 1923 | if (pi->pgrp < 0) |
1925 | pi->pgrp = child->pid; | 1924 | pi->pgrp = command->pid; |
1926 | #endif | 1925 | #endif |
1927 | } | 1926 | } |
1928 | 1927 | ||
1929 | if (i) | 1928 | if (i) |
1930 | close(nextin); | 1929 | close(nextin); |
1931 | if ((i + 1) < pi->num_progs) | 1930 | if ((i + 1) < pi->num_cmds) |
1932 | close(pipefds[1]); /* write end */ | 1931 | close(pipefds[1]); /* write end */ |
1933 | /* Pass read (output) pipe end to next iteration */ | 1932 | /* Pass read (output) pipe end to next iteration */ |
1934 | nextin = pipefds[0]; | 1933 | nextin = pipefds[0]; |
1935 | } | 1934 | } |
1936 | 1935 | ||
1937 | if (!pi->alive_progs) { | 1936 | if (!pi->alive_cmds) { |
1938 | debug_printf_exec("run_pipe return 1 (all forks failed, no children)\n"); | 1937 | debug_printf_exec("run_pipe return 1 (all forks failed, no children)\n"); |
1939 | return 1; | 1938 | return 1; |
1940 | } | 1939 | } |
1941 | 1940 | ||
1942 | debug_printf_exec("run_pipe return -1 (%u children started)\n", pi->alive_progs); | 1941 | debug_printf_exec("run_pipe return -1 (%u children started)\n", pi->alive_cmds); |
1943 | return -1; | 1942 | return -1; |
1944 | } | 1943 | } |
1945 | 1944 | ||
@@ -1988,16 +1987,16 @@ static void debug_print_tree(struct pipe *pi, int lvl) | |||
1988 | fprintf(stderr, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", | 1987 | fprintf(stderr, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", |
1989 | pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); | 1988 | pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); |
1990 | prn = 0; | 1989 | prn = 0; |
1991 | while (prn < pi->num_progs) { | 1990 | while (prn < pi->num_cmds) { |
1992 | struct child_prog *child = &pi->progs[prn]; | 1991 | struct command *command = &pi->cmds[prn]; |
1993 | char **argv = child->argv; | 1992 | char **argv = command->argv; |
1994 | 1993 | ||
1995 | fprintf(stderr, "%*s prog %d assignment_cnt:%d", lvl*2, "", prn, child->assignment_cnt); | 1994 | fprintf(stderr, "%*s prog %d assignment_cnt:%d", lvl*2, "", prn, command->assignment_cnt); |
1996 | if (child->group) { | 1995 | if (command->group) { |
1997 | fprintf(stderr, " group %s: (argv=%p)\n", | 1996 | fprintf(stderr, " group %s: (argv=%p)\n", |
1998 | (child->subshell ? "()" : "{}"), | 1997 | (command->subshell ? "()" : "{}"), |
1999 | argv); | 1998 | argv); |
2000 | debug_print_tree(child->group, lvl+1); | 1999 | debug_print_tree(command->group, lvl+1); |
2001 | prn++; | 2000 | prn++; |
2002 | continue; | 2001 | continue; |
2003 | } | 2002 | } |
@@ -2151,7 +2150,7 @@ static int run_list(struct pipe *pi) | |||
2151 | } | 2150 | } |
2152 | #endif | 2151 | #endif |
2153 | #if ENABLE_HUSH_LOOPS | 2152 | #if ENABLE_HUSH_LOOPS |
2154 | if (rword == RES_FOR) { /* && pi->num_progs - always == 1 */ | 2153 | if (rword == RES_FOR) { /* && pi->num_cmds - always == 1 */ |
2155 | if (!for_lcur) { | 2154 | if (!for_lcur) { |
2156 | /* first loop through for */ | 2155 | /* first loop through for */ |
2157 | 2156 | ||
@@ -2166,31 +2165,31 @@ static int run_list(struct pipe *pi) | |||
2166 | vals = (char**)encoded_dollar_at_argv; | 2165 | vals = (char**)encoded_dollar_at_argv; |
2167 | if (pi->next->res_word == RES_IN) { | 2166 | if (pi->next->res_word == RES_IN) { |
2168 | /* if no variable values after "in" we skip "for" */ | 2167 | /* if no variable values after "in" we skip "for" */ |
2169 | if (!pi->next->progs[0].argv) | 2168 | if (!pi->next->cmds[0].argv) |
2170 | break; | 2169 | break; |
2171 | vals = pi->next->progs[0].argv; | 2170 | vals = pi->next->cmds[0].argv; |
2172 | } /* else: "for var; do..." -> assume "$@" list */ | 2171 | } /* else: "for var; do..." -> assume "$@" list */ |
2173 | /* create list of variable values */ | 2172 | /* create list of variable values */ |
2174 | debug_print_strings("for_list made from", vals); | 2173 | debug_print_strings("for_list made from", vals); |
2175 | for_list = expand_strvec_to_strvec(vals); | 2174 | for_list = expand_strvec_to_strvec(vals); |
2176 | for_lcur = for_list; | 2175 | for_lcur = for_list; |
2177 | debug_print_strings("for_list", for_list); | 2176 | debug_print_strings("for_list", for_list); |
2178 | for_varname = pi->progs[0].argv[0]; | 2177 | for_varname = pi->cmds[0].argv[0]; |
2179 | pi->progs[0].argv[0] = NULL; | 2178 | pi->cmds[0].argv[0] = NULL; |
2180 | } | 2179 | } |
2181 | free(pi->progs[0].argv[0]); | 2180 | free(pi->cmds[0].argv[0]); |
2182 | if (!*for_lcur) { | 2181 | if (!*for_lcur) { |
2183 | /* "for" loop is over, clean up */ | 2182 | /* "for" loop is over, clean up */ |
2184 | free(for_list); | 2183 | free(for_list); |
2185 | for_list = NULL; | 2184 | for_list = NULL; |
2186 | for_lcur = NULL; | 2185 | for_lcur = NULL; |
2187 | pi->progs[0].argv[0] = for_varname; | 2186 | pi->cmds[0].argv[0] = for_varname; |
2188 | break; | 2187 | break; |
2189 | } | 2188 | } |
2190 | /* insert next value from for_lcur */ | 2189 | /* insert next value from for_lcur */ |
2191 | //TODO: does it need escaping? | 2190 | //TODO: does it need escaping? |
2192 | pi->progs[0].argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); | 2191 | pi->cmds[0].argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); |
2193 | pi->progs[0].assignment_cnt = 1; | 2192 | pi->cmds[0].assignment_cnt = 1; |
2194 | } | 2193 | } |
2195 | if (rword == RES_IN) /* "for v IN list;..." - "in" has no cmds anyway */ | 2194 | if (rword == RES_IN) /* "for v IN list;..." - "in" has no cmds anyway */ |
2196 | continue; | 2195 | continue; |
@@ -2200,7 +2199,7 @@ static int run_list(struct pipe *pi) | |||
2200 | #endif | 2199 | #endif |
2201 | #if ENABLE_HUSH_CASE | 2200 | #if ENABLE_HUSH_CASE |
2202 | if (rword == RES_CASE) { | 2201 | if (rword == RES_CASE) { |
2203 | case_word = expand_strvec_to_string(pi->progs->argv); | 2202 | case_word = expand_strvec_to_string(pi->cmds->argv); |
2204 | continue; | 2203 | continue; |
2205 | } | 2204 | } |
2206 | if (rword == RES_MATCH) { | 2205 | if (rword == RES_MATCH) { |
@@ -2209,7 +2208,7 @@ static int run_list(struct pipe *pi) | |||
2209 | if (!case_word) /* "case ... matched_word) ... WORD)": we executed selected branch, stop */ | 2208 | if (!case_word) /* "case ... matched_word) ... WORD)": we executed selected branch, stop */ |
2210 | break; | 2209 | break; |
2211 | /* all prev words didn't match, does this one match? */ | 2210 | /* all prev words didn't match, does this one match? */ |
2212 | argv = pi->progs->argv; | 2211 | argv = pi->cmds->argv; |
2213 | while (*argv) { | 2212 | while (*argv) { |
2214 | char *pattern = expand_string_to_string(*argv); | 2213 | char *pattern = expand_string_to_string(*argv); |
2215 | /* TODO: which FNM_xxx flags to use? */ | 2214 | /* TODO: which FNM_xxx flags to use? */ |
@@ -2229,14 +2228,14 @@ static int run_list(struct pipe *pi) | |||
2229 | continue; /* not matched yet, skip this pipe */ | 2228 | continue; /* not matched yet, skip this pipe */ |
2230 | } | 2229 | } |
2231 | #endif | 2230 | #endif |
2232 | if (pi->num_progs == 0) | 2231 | if (pi->num_cmds == 0) |
2233 | continue; | 2232 | continue; |
2234 | 2233 | ||
2235 | /* After analyzing all keywords and conditions, we decided | 2234 | /* After analyzing all keywords and conditions, we decided |
2236 | * to execute this pipe. NB: has to do checkjobs(NULL) | 2235 | * to execute this pipe. NB: has to do checkjobs(NULL) |
2237 | * after run_pipe() to collect any background children, | 2236 | * after run_pipe() to collect any background children, |
2238 | * even if list execution is to be stopped. */ | 2237 | * even if list execution is to be stopped. */ |
2239 | debug_printf_exec(": run_pipe with %d members\n", pi->num_progs); | 2238 | debug_printf_exec(": run_pipe with %d members\n", pi->num_cmds); |
2240 | { | 2239 | { |
2241 | int r; | 2240 | int r; |
2242 | #if ENABLE_HUSH_LOOPS | 2241 | #if ENABLE_HUSH_LOOPS |
@@ -2349,30 +2348,30 @@ static int run_list(struct pipe *pi) | |||
2349 | static int free_pipe(struct pipe *pi, int indent) | 2348 | static int free_pipe(struct pipe *pi, int indent) |
2350 | { | 2349 | { |
2351 | char **p; | 2350 | char **p; |
2352 | struct child_prog *child; | 2351 | struct command *command; |
2353 | struct redir_struct *r, *rnext; | 2352 | struct redir_struct *r, *rnext; |
2354 | int a, i, ret_code = 0; | 2353 | int a, i, ret_code = 0; |
2355 | 2354 | ||
2356 | if (pi->stopped_progs > 0) | 2355 | if (pi->stopped_cmds > 0) |
2357 | return ret_code; | 2356 | return ret_code; |
2358 | debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid()); | 2357 | debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid()); |
2359 | for (i = 0; i < pi->num_progs; i++) { | 2358 | for (i = 0; i < pi->num_cmds; i++) { |
2360 | child = &pi->progs[i]; | 2359 | command = &pi->cmds[i]; |
2361 | debug_printf_clean("%s command %d:\n", indenter(indent), i); | 2360 | debug_printf_clean("%s command %d:\n", indenter(indent), i); |
2362 | if (child->argv) { | 2361 | if (command->argv) { |
2363 | for (a = 0, p = child->argv; *p; a++, p++) { | 2362 | for (a = 0, p = command->argv; *p; a++, p++) { |
2364 | debug_printf_clean("%s argv[%d] = %s\n", indenter(indent), a, *p); | 2363 | debug_printf_clean("%s argv[%d] = %s\n", indenter(indent), a, *p); |
2365 | } | 2364 | } |
2366 | free_strings(child->argv); | 2365 | free_strings(command->argv); |
2367 | child->argv = NULL; | 2366 | command->argv = NULL; |
2368 | } else if (child->group) { | 2367 | } else if (command->group) { |
2369 | debug_printf_clean("%s begin group (subshell:%d)\n", indenter(indent), child->subshell); | 2368 | debug_printf_clean("%s begin group (subshell:%d)\n", indenter(indent), command->subshell); |
2370 | ret_code = free_pipe_list(child->group, indent+3); | 2369 | ret_code = free_pipe_list(command->group, indent+3); |
2371 | debug_printf_clean("%s end group\n", indenter(indent)); | 2370 | debug_printf_clean("%s end group\n", indenter(indent)); |
2372 | } else { | 2371 | } else { |
2373 | debug_printf_clean("%s (nil)\n", indenter(indent)); | 2372 | debug_printf_clean("%s (nil)\n", indenter(indent)); |
2374 | } | 2373 | } |
2375 | for (r = child->redirects; r; r = rnext) { | 2374 | for (r = command->redirects; r; r = rnext) { |
2376 | debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->rd_type].descrip); | 2375 | debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->rd_type].descrip); |
2377 | if (r->dup == -1) { | 2376 | if (r->dup == -1) { |
2378 | /* guard against the case >$FOO, where foo is unset or blank */ | 2377 | /* guard against the case >$FOO, where foo is unset or blank */ |
@@ -2387,10 +2386,10 @@ static int free_pipe(struct pipe *pi, int indent) | |||
2387 | rnext = r->next; | 2386 | rnext = r->next; |
2388 | free(r); | 2387 | free(r); |
2389 | } | 2388 | } |
2390 | child->redirects = NULL; | 2389 | command->redirects = NULL; |
2391 | } | 2390 | } |
2392 | free(pi->progs); /* children are an array, they get freed all at once */ | 2391 | free(pi->cmds); /* children are an array, they get freed all at once */ |
2393 | pi->progs = NULL; | 2392 | pi->cmds = NULL; |
2394 | #if ENABLE_HUSH_JOB | 2393 | #if ENABLE_HUSH_JOB |
2395 | free(pi->cmdtext); | 2394 | free(pi->cmdtext); |
2396 | pi->cmdtext = NULL; | 2395 | pi->cmdtext = NULL; |
@@ -2422,7 +2421,7 @@ static int run_and_free_list(struct pipe *pi) | |||
2422 | int rcode = 0; | 2421 | int rcode = 0; |
2423 | debug_printf_exec("run_and_free_list entered\n"); | 2422 | debug_printf_exec("run_and_free_list entered\n"); |
2424 | if (!G.fake_mode) { | 2423 | if (!G.fake_mode) { |
2425 | debug_printf_exec(": run_list with %d members\n", pi->num_progs); | 2424 | debug_printf_exec(": run_list with %d members\n", pi->num_cmds); |
2426 | rcode = run_list(pi); | 2425 | rcode = run_list(pi); |
2427 | } | 2426 | } |
2428 | /* free_pipe_list has the side effect of clearing memory. | 2427 | /* free_pipe_list has the side effect of clearing memory. |
@@ -2833,11 +2832,11 @@ static void unset_local_var(const char *name) | |||
2833 | * for file descriptor duplication, e.g., "2>&1". | 2832 | * for file descriptor duplication, e.g., "2>&1". |
2834 | * Return code is 0 normally, 1 if a syntax error is detected in src. | 2833 | * Return code is 0 normally, 1 if a syntax error is detected in src. |
2835 | * Resource errors (in xmalloc) cause the process to exit */ | 2834 | * Resource errors (in xmalloc) cause the process to exit */ |
2836 | static int setup_redirect(struct p_context *ctx, int fd, redir_type style, | 2835 | static int setup_redirect(struct parse_context *ctx, int fd, redir_type style, |
2837 | struct in_str *input) | 2836 | struct in_str *input) |
2838 | { | 2837 | { |
2839 | struct child_prog *child = ctx->child; | 2838 | struct command *command = ctx->command; |
2840 | struct redir_struct *redir = child->redirects; | 2839 | struct redir_struct *redir = command->redirects; |
2841 | struct redir_struct *last_redir = NULL; | 2840 | struct redir_struct *last_redir = NULL; |
2842 | 2841 | ||
2843 | /* Create a new redir_struct and drop it onto the end of the linked list */ | 2842 | /* Create a new redir_struct and drop it onto the end of the linked list */ |
@@ -2851,7 +2850,7 @@ static int setup_redirect(struct p_context *ctx, int fd, redir_type style, | |||
2851 | if (last_redir) { | 2850 | if (last_redir) { |
2852 | last_redir->next = redir; | 2851 | last_redir->next = redir; |
2853 | } else { | 2852 | } else { |
2854 | child->redirects = redir; | 2853 | command->redirects = redir; |
2855 | } | 2854 | } |
2856 | 2855 | ||
2857 | redir->rd_type = style; | 2856 | redir->rd_type = style; |
@@ -2887,13 +2886,13 @@ static struct pipe *new_pipe(void) | |||
2887 | return pi; | 2886 | return pi; |
2888 | } | 2887 | } |
2889 | 2888 | ||
2890 | static void initialize_context(struct p_context *ctx) | 2889 | static void initialize_context(struct parse_context *ctx) |
2891 | { | 2890 | { |
2892 | memset(ctx, 0, sizeof(*ctx)); | 2891 | memset(ctx, 0, sizeof(*ctx)); |
2893 | ctx->pipe = ctx->list_head = new_pipe(); | 2892 | ctx->pipe = ctx->list_head = new_pipe(); |
2894 | /* Create the memory for child, roughly: | 2893 | /* Create the memory for command, roughly: |
2895 | * ctx->pipe->progs = new struct child_prog; | 2894 | * ctx->pipe->cmds = new struct command; |
2896 | * ctx->child = &ctx->pipe->progs[0]; | 2895 | * ctx->command = &ctx->pipe->cmds[0]; |
2897 | */ | 2896 | */ |
2898 | done_command(ctx); | 2897 | done_command(ctx); |
2899 | } | 2898 | } |
@@ -2904,7 +2903,7 @@ static void initialize_context(struct p_context *ctx) | |||
2904 | * case, function, and select are obnoxious, save those for later. | 2903 | * case, function, and select are obnoxious, save those for later. |
2905 | */ | 2904 | */ |
2906 | #if HAS_KEYWORDS | 2905 | #if HAS_KEYWORDS |
2907 | static int reserved_word(o_string *word, struct p_context *ctx) | 2906 | static int reserved_word(o_string *word, struct parse_context *ctx) |
2908 | { | 2907 | { |
2909 | struct reserved_combo { | 2908 | struct reserved_combo { |
2910 | char literal[6]; | 2909 | char literal[6]; |
@@ -2988,7 +2987,7 @@ static int reserved_word(o_string *word, struct p_context *ctx) | |||
2988 | return 1; | 2987 | return 1; |
2989 | } | 2988 | } |
2990 | if (r->flag & FLAG_START) { | 2989 | if (r->flag & FLAG_START) { |
2991 | struct p_context *new; | 2990 | struct parse_context *new; |
2992 | debug_printf("push stack\n"); | 2991 | debug_printf("push stack\n"); |
2993 | new = xmalloc(sizeof(*new)); | 2992 | new = xmalloc(sizeof(*new)); |
2994 | *new = *ctx; /* physical copy */ | 2993 | *new = *ctx; /* physical copy */ |
@@ -3002,12 +3001,12 @@ static int reserved_word(o_string *word, struct p_context *ctx) | |||
3002 | ctx->ctx_res_w = r->res; | 3001 | ctx->ctx_res_w = r->res; |
3003 | ctx->old_flag = r->flag; | 3002 | ctx->old_flag = r->flag; |
3004 | if (ctx->old_flag & FLAG_END) { | 3003 | if (ctx->old_flag & FLAG_END) { |
3005 | struct p_context *old; | 3004 | struct parse_context *old; |
3006 | debug_printf("pop stack\n"); | 3005 | debug_printf("pop stack\n"); |
3007 | done_pipe(ctx, PIPE_SEQ); | 3006 | done_pipe(ctx, PIPE_SEQ); |
3008 | old = ctx->stack; | 3007 | old = ctx->stack; |
3009 | old->child->group = ctx->list_head; | 3008 | old->command->group = ctx->list_head; |
3010 | old->child->subshell = 0; | 3009 | old->command->subshell = 0; |
3011 | *ctx = *old; /* physical copy */ | 3010 | *ctx = *old; /* physical copy */ |
3012 | free(old); | 3011 | free(old); |
3013 | } | 3012 | } |
@@ -3020,11 +3019,11 @@ static int reserved_word(o_string *word, struct p_context *ctx) | |||
3020 | 3019 | ||
3021 | /* Word is complete, look at it and update parsing context. | 3020 | /* Word is complete, look at it and update parsing context. |
3022 | * Normal return is 0. Syntax errors return 1. */ | 3021 | * Normal return is 0. Syntax errors return 1. */ |
3023 | static int done_word(o_string *word, struct p_context *ctx) | 3022 | static int done_word(o_string *word, struct parse_context *ctx) |
3024 | { | 3023 | { |
3025 | struct child_prog *child = ctx->child; | 3024 | struct command *command = ctx->command; |
3026 | 3025 | ||
3027 | debug_printf_parse("done_word entered: '%s' %p\n", word->data, child); | 3026 | debug_printf_parse("done_word entered: '%s' %p\n", word->data, command); |
3028 | if (word->length == 0 && word->nonnull == 0) { | 3027 | if (word->length == 0 && word->nonnull == 0) { |
3029 | debug_printf_parse("done_word return 0: true null, ignored\n"); | 3028 | debug_printf_parse("done_word return 0: true null, ignored\n"); |
3030 | return 0; | 3029 | return 0; |
@@ -3037,7 +3036,7 @@ static int done_word(o_string *word, struct p_context *ctx) | |||
3037 | word->o_assignment = NOT_ASSIGNMENT; | 3036 | word->o_assignment = NOT_ASSIGNMENT; |
3038 | } else { | 3037 | } else { |
3039 | if (word->o_assignment == DEFINITELY_ASSIGNMENT) | 3038 | if (word->o_assignment == DEFINITELY_ASSIGNMENT) |
3040 | child->assignment_cnt++; | 3039 | command->assignment_cnt++; |
3041 | word->o_assignment = MAYBE_ASSIGNMENT; | 3040 | word->o_assignment = MAYBE_ASSIGNMENT; |
3042 | } | 3041 | } |
3043 | 3042 | ||
@@ -3050,7 +3049,7 @@ static int done_word(o_string *word, struct p_context *ctx) | |||
3050 | } else { | 3049 | } else { |
3051 | /* "{ echo foo; } echo bar" - bad */ | 3050 | /* "{ echo foo; } echo bar" - bad */ |
3052 | /* NB: bash allows e.g. "if true; then { echo foo; } fi". TODO? */ | 3051 | /* NB: bash allows e.g. "if true; then { echo foo; } fi". TODO? */ |
3053 | if (child->group) { | 3052 | if (command->group) { |
3054 | syntax(NULL); | 3053 | syntax(NULL); |
3055 | debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); | 3054 | debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); |
3056 | return 1; | 3055 | return 1; |
@@ -3066,7 +3065,7 @@ static int done_word(o_string *word, struct p_context *ctx) | |||
3066 | } else | 3065 | } else |
3067 | #endif | 3066 | #endif |
3068 | 3067 | ||
3069 | if (!child->argv /* if it's the first word... */ | 3068 | if (!command->argv /* if it's the first word... */ |
3070 | #if ENABLE_HUSH_LOOPS | 3069 | #if ENABLE_HUSH_LOOPS |
3071 | && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ | 3070 | && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ |
3072 | && ctx->ctx_res_w != RES_IN | 3071 | && ctx->ctx_res_w != RES_IN |
@@ -3102,8 +3101,8 @@ static int done_word(o_string *word, struct p_context *ctx) | |||
3102 | o_addchr(word, SPECIAL_VAR_SYMBOL); | 3101 | o_addchr(word, SPECIAL_VAR_SYMBOL); |
3103 | } | 3102 | } |
3104 | } | 3103 | } |
3105 | child->argv = add_malloced_string_to_strings(child->argv, xstrdup(word->data)); | 3104 | command->argv = add_malloced_string_to_strings(command->argv, xstrdup(word->data)); |
3106 | debug_print_strings("word appended to argv", child->argv); | 3105 | debug_print_strings("word appended to argv", command->argv); |
3107 | } | 3106 | } |
3108 | 3107 | ||
3109 | o_reset(word); | 3108 | o_reset(word); |
@@ -3115,7 +3114,7 @@ static int done_word(o_string *word, struct p_context *ctx) | |||
3115 | * as it is "for v; in ...". FOR and IN become two pipe structs | 3114 | * as it is "for v; in ...". FOR and IN become two pipe structs |
3116 | * in parse tree. */ | 3115 | * in parse tree. */ |
3117 | if (ctx->ctx_res_w == RES_FOR) { | 3116 | if (ctx->ctx_res_w == RES_FOR) { |
3118 | //TODO: check that child->argv[0] is a valid variable name! | 3117 | //TODO: check that command->argv[0] is a valid variable name! |
3119 | done_pipe(ctx, PIPE_SEQ); | 3118 | done_pipe(ctx, PIPE_SEQ); |
3120 | } | 3119 | } |
3121 | #endif | 3120 | #endif |
@@ -3131,40 +3130,40 @@ static int done_word(o_string *word, struct p_context *ctx) | |||
3131 | 3130 | ||
3132 | /* Command (member of a pipe) is complete. The only possible error here | 3131 | /* Command (member of a pipe) is complete. The only possible error here |
3133 | * is out of memory, in which case xmalloc exits. */ | 3132 | * is out of memory, in which case xmalloc exits. */ |
3134 | static int done_command(struct p_context *ctx) | 3133 | static int done_command(struct parse_context *ctx) |
3135 | { | 3134 | { |
3136 | /* The child is really already in the pipe structure, so | 3135 | /* The command is really already in the pipe structure, so |
3137 | * advance the pipe counter and make a new, null child. */ | 3136 | * advance the pipe counter and make a new, null command. */ |
3138 | struct pipe *pi = ctx->pipe; | 3137 | struct pipe *pi = ctx->pipe; |
3139 | struct child_prog *child = ctx->child; | 3138 | struct command *command = ctx->command; |
3140 | 3139 | ||
3141 | if (child) { | 3140 | if (command) { |
3142 | if (child->group == NULL | 3141 | if (command->group == NULL |
3143 | && child->argv == NULL | 3142 | && command->argv == NULL |
3144 | && child->redirects == NULL | 3143 | && command->redirects == NULL |
3145 | ) { | 3144 | ) { |
3146 | debug_printf_parse("done_command: skipping null cmd, num_progs=%d\n", pi->num_progs); | 3145 | debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds); |
3147 | return pi->num_progs; | 3146 | return pi->num_cmds; |
3148 | } | 3147 | } |
3149 | pi->num_progs++; | 3148 | pi->num_cmds++; |
3150 | debug_printf_parse("done_command: ++num_progs=%d\n", pi->num_progs); | 3149 | debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds); |
3151 | } else { | 3150 | } else { |
3152 | debug_printf_parse("done_command: initializing, num_progs=%d\n", pi->num_progs); | 3151 | debug_printf_parse("done_command: initializing, num_cmds=%d\n", pi->num_cmds); |
3153 | } | 3152 | } |
3154 | 3153 | ||
3155 | /* Only real trickiness here is that the uncommitted | 3154 | /* Only real trickiness here is that the uncommitted |
3156 | * child structure is not counted in pi->num_progs. */ | 3155 | * command structure is not counted in pi->num_cmds. */ |
3157 | pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1)); | 3156 | pi->cmds = xrealloc(pi->cmds, sizeof(*pi->cmds) * (pi->num_cmds+1)); |
3158 | child = &pi->progs[pi->num_progs]; | 3157 | command = &pi->cmds[pi->num_cmds]; |
3159 | memset(child, 0, sizeof(*child)); | 3158 | memset(command, 0, sizeof(*command)); |
3160 | 3159 | ||
3161 | ctx->child = child; | 3160 | ctx->command = command; |
3162 | /* but ctx->pipe and ctx->list_head remain unchanged */ | 3161 | /* but ctx->pipe and ctx->list_head remain unchanged */ |
3163 | 3162 | ||
3164 | return pi->num_progs; /* used only for 0/nonzero check */ | 3163 | return pi->num_cmds; /* used only for 0/nonzero check */ |
3165 | } | 3164 | } |
3166 | 3165 | ||
3167 | static void done_pipe(struct p_context *ctx, pipe_style type) | 3166 | static void done_pipe(struct parse_context *ctx, pipe_style type) |
3168 | { | 3167 | { |
3169 | int not_null; | 3168 | int not_null; |
3170 | 3169 | ||
@@ -3189,7 +3188,7 @@ static void done_pipe(struct p_context *ctx, pipe_style type) | |||
3189 | new_p = new_pipe(); | 3188 | new_p = new_pipe(); |
3190 | ctx->pipe->next = new_p; | 3189 | ctx->pipe->next = new_p; |
3191 | ctx->pipe = new_p; | 3190 | ctx->pipe = new_p; |
3192 | ctx->child = NULL; /* needed! */ | 3191 | ctx->command = NULL; /* needed! */ |
3193 | /* RES_THEN, RES_DO etc are "sticky" - | 3192 | /* RES_THEN, RES_DO etc are "sticky" - |
3194 | * they remain set for commands inside if/while. | 3193 | * they remain set for commands inside if/while. |
3195 | * This is used to control execution. | 3194 | * This is used to control execution. |
@@ -3205,9 +3204,9 @@ static void done_pipe(struct p_context *ctx, pipe_style type) | |||
3205 | if (ctx->ctx_res_w == RES_MATCH) | 3204 | if (ctx->ctx_res_w == RES_MATCH) |
3206 | ctx->ctx_res_w = RES_CASEI; | 3205 | ctx->ctx_res_w = RES_CASEI; |
3207 | #endif | 3206 | #endif |
3208 | /* Create the memory for child, roughly: | 3207 | /* Create the memory for command, roughly: |
3209 | * ctx->pipe->progs = new struct child_prog; | 3208 | * ctx->pipe->cmds = new struct command; |
3210 | * ctx->child = &ctx->pipe->progs[0]; | 3209 | * ctx->command = &ctx->pipe->cmds[0]; |
3211 | */ | 3210 | */ |
3212 | done_command(ctx); | 3211 | done_command(ctx); |
3213 | } | 3212 | } |
@@ -3320,7 +3319,7 @@ static int process_command_subs(o_string *dest, | |||
3320 | { | 3319 | { |
3321 | int retcode, ch, eol_cnt; | 3320 | int retcode, ch, eol_cnt; |
3322 | o_string result = NULL_O_STRING; | 3321 | o_string result = NULL_O_STRING; |
3323 | struct p_context inner; | 3322 | struct parse_context inner; |
3324 | FILE *p; | 3323 | FILE *p; |
3325 | struct in_str pipe_str; | 3324 | struct in_str pipe_str; |
3326 | 3325 | ||
@@ -3367,7 +3366,7 @@ static int process_command_subs(o_string *dest, | |||
3367 | } | 3366 | } |
3368 | #endif | 3367 | #endif |
3369 | 3368 | ||
3370 | static int parse_group(o_string *dest, struct p_context *ctx, | 3369 | static int parse_group(o_string *dest, struct parse_context *ctx, |
3371 | struct in_str *input, int ch) | 3370 | struct in_str *input, int ch) |
3372 | { | 3371 | { |
3373 | /* NB: parse_group may create and use its own o_string, | 3372 | /* NB: parse_group may create and use its own o_string, |
@@ -3375,11 +3374,14 @@ static int parse_group(o_string *dest, struct p_context *ctx, | |||
3375 | * if we (ab)use caller's one. */ | 3374 | * if we (ab)use caller's one. */ |
3376 | int rcode; | 3375 | int rcode; |
3377 | const char *endch = NULL; | 3376 | const char *endch = NULL; |
3378 | struct p_context sub; | 3377 | struct parse_context sub; |
3379 | struct child_prog *child = ctx->child; | 3378 | struct command *command = ctx->command; |
3380 | 3379 | ||
3381 | debug_printf_parse("parse_group entered\n"); | 3380 | debug_printf_parse("parse_group entered\n"); |
3382 | if (child->argv) { | 3381 | if (command->argv /* word [word](... */ |
3382 | || dest->length /* word(... */ | ||
3383 | || dest->nonnull /* ""(... */ | ||
3384 | ) { | ||
3383 | syntax(NULL); | 3385 | syntax(NULL); |
3384 | debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n"); | 3386 | debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n"); |
3385 | return 1; | 3387 | return 1; |
@@ -3388,17 +3390,17 @@ static int parse_group(o_string *dest, struct p_context *ctx, | |||
3388 | endch = "}"; | 3390 | endch = "}"; |
3389 | if (ch == '(') { | 3391 | if (ch == '(') { |
3390 | endch = ")"; | 3392 | endch = ")"; |
3391 | child->subshell = 1; | 3393 | command->subshell = 1; |
3392 | } | 3394 | } |
3393 | rcode = parse_stream(dest, &sub, input, endch); | 3395 | rcode = parse_stream(dest, &sub, input, endch); |
3394 | if (rcode == 0) { | 3396 | if (rcode == 0) { |
3395 | done_word(dest, &sub); /* finish off the final word in the subcontext */ | 3397 | done_word(dest, &sub); /* finish off the final word in the subcontext */ |
3396 | done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */ | 3398 | done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */ |
3397 | child->group = sub.list_head; | 3399 | command->group = sub.list_head; |
3398 | } | 3400 | } |
3399 | debug_printf_parse("parse_group return %d\n", rcode); | 3401 | debug_printf_parse("parse_group return %d\n", rcode); |
3400 | return rcode; | 3402 | return rcode; |
3401 | /* child remains "open", available for possible redirects */ | 3403 | /* command remains "open", available for possible redirects */ |
3402 | } | 3404 | } |
3403 | 3405 | ||
3404 | /* Basically useful version until someone wants to get fancier, | 3406 | /* Basically useful version until someone wants to get fancier, |
@@ -3617,7 +3619,7 @@ static int handle_dollar(o_string *dest, struct in_str *input) | |||
3617 | * Return code is 0 if end_trigger char is met, | 3619 | * Return code is 0 if end_trigger char is met, |
3618 | * -1 on EOF (but if end_trigger == NULL then return 0), | 3620 | * -1 on EOF (but if end_trigger == NULL then return 0), |
3619 | * 1 for syntax error */ | 3621 | * 1 for syntax error */ |
3620 | static int parse_stream(o_string *dest, struct p_context *ctx, | 3622 | static int parse_stream(o_string *dest, struct parse_context *ctx, |
3621 | struct in_str *input, const char *end_trigger) | 3623 | struct in_str *input, const char *end_trigger) |
3622 | { | 3624 | { |
3623 | int ch, m; | 3625 | int ch, m; |
@@ -3883,8 +3885,10 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3883 | case '(': | 3885 | case '(': |
3884 | #if ENABLE_HUSH_CASE | 3886 | #if ENABLE_HUSH_CASE |
3885 | /* "case... in [(]word)..." - skip '(' */ | 3887 | /* "case... in [(]word)..." - skip '(' */ |
3886 | if (dest->length == 0 // && argv[0] == NULL | 3888 | if (dest->length == 0 /* not word(... */ |
3889 | && dest->nonnull == 0 /* not ""(... */ | ||
3887 | && ctx->ctx_res_w == RES_MATCH | 3890 | && ctx->ctx_res_w == RES_MATCH |
3891 | && ctx->command->argv == NULL /* not (word|(... */ | ||
3888 | ) { | 3892 | ) { |
3889 | continue; | 3893 | continue; |
3890 | } | 3894 | } |
@@ -3947,7 +3951,7 @@ static void update_charmap(void) | |||
3947 | * from builtin_source() and builtin_eval() */ | 3951 | * from builtin_source() and builtin_eval() */ |
3948 | static int parse_and_run_stream(struct in_str *inp, int parse_flag) | 3952 | static int parse_and_run_stream(struct in_str *inp, int parse_flag) |
3949 | { | 3953 | { |
3950 | struct p_context ctx; | 3954 | struct parse_context ctx; |
3951 | o_string temp = NULL_O_STRING; | 3955 | o_string temp = NULL_O_STRING; |
3952 | int rcode; | 3956 | int rcode; |
3953 | 3957 | ||
@@ -4408,12 +4412,12 @@ static int builtin_fg_bg(char **argv) | |||
4408 | } | 4412 | } |
4409 | 4413 | ||
4410 | /* Restart the processes in the job */ | 4414 | /* Restart the processes in the job */ |
4411 | debug_printf_jobs("reviving %d procs, pgrp %d\n", pi->num_progs, pi->pgrp); | 4415 | debug_printf_jobs("reviving %d procs, pgrp %d\n", pi->num_cmds, pi->pgrp); |
4412 | for (i = 0; i < pi->num_progs; i++) { | 4416 | for (i = 0; i < pi->num_cmds; i++) { |
4413 | debug_printf_jobs("reviving pid %d\n", pi->progs[i].pid); | 4417 | debug_printf_jobs("reviving pid %d\n", pi->cmds[i].pid); |
4414 | pi->progs[i].is_stopped = 0; | 4418 | pi->cmds[i].is_stopped = 0; |
4415 | } | 4419 | } |
4416 | pi->stopped_progs = 0; | 4420 | pi->stopped_cmds = 0; |
4417 | 4421 | ||
4418 | i = kill(- pi->pgrp, SIGCONT); | 4422 | i = kill(- pi->pgrp, SIGCONT); |
4419 | if (i < 0) { | 4423 | if (i < 0) { |
@@ -4455,7 +4459,7 @@ static int builtin_jobs(char **argv UNUSED_PARAM) | |||
4455 | const char *status_string; | 4459 | const char *status_string; |
4456 | 4460 | ||
4457 | for (job = G.job_list; job; job = job->next) { | 4461 | for (job = G.job_list; job; job = job->next) { |
4458 | if (job->alive_progs == job->stopped_progs) | 4462 | if (job->alive_cmds == job->stopped_cmds) |
4459 | status_string = "Stopped"; | 4463 | status_string = "Stopped"; |
4460 | else | 4464 | else |
4461 | status_string = "Running"; | 4465 | status_string = "Running"; |