aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-10-09 12:54:58 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-10-09 12:54:58 +0000
commit9af22c762652ff92f3f207a754f71f3c4bf2c078 (patch)
tree8c55f180aa907e151924d1cb8c8e5622eec2f5cb
parent578de8644c46cd17667812f7e335bf9fefbca00d (diff)
downloadbusybox-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.c408
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 */
295struct 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
311struct redir_struct { 293struct 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
319struct child_prog { 301struct 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
336struct pipe { 318struct 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 */
335struct 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);
523static int free_pipe_list(struct pipe *head, int indent); 522static int free_pipe_list(struct pipe *head, int indent);
524static int free_pipe(struct pipe *pi, int indent); 523static int free_pipe(struct pipe *pi, int indent);
525/* really run the final data structures: */ 524/* really run the final data structures: */
526static int setup_redirects(struct child_prog *prog, int squirrel[]); 525static int setup_redirects(struct command *prog, int squirrel[]);
527static int run_list(struct pipe *pi); 526static 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
534static void pseudo_exec_argv(char **ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) NORETURN; 533static void pseudo_exec_argv(char **ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) NORETURN;
535static void pseudo_exec(char **ptrs2free, struct child_prog *child, char **argv_expanded) NORETURN; 534static void pseudo_exec(char **ptrs2free, struct command *command, char **argv_expanded) NORETURN;
536static int run_pipe(struct pipe *pi); 535static int run_pipe(struct pipe *pi);
537/* data structure manipulation: */ 536/* data structure manipulation: */
538static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input); 537static int setup_redirect(struct parse_context *ctx, int fd, redir_type style, struct in_str *input);
539static void initialize_context(struct p_context *ctx); 538static void initialize_context(struct parse_context *ctx);
540static int done_word(o_string *dest, struct p_context *ctx); 539static int done_word(o_string *dest, struct parse_context *ctx);
541static int done_command(struct p_context *ctx); 540static int done_command(struct parse_context *ctx);
542static void done_pipe(struct p_context *ctx, pipe_style type); 541static void done_pipe(struct parse_context *ctx, pipe_style type);
543/* primary string parsing: */ 542/* primary string parsing: */
544static int redirect_dup_num(struct in_str *input); 543static int redirect_dup_num(struct in_str *input);
545static int redirect_opt_num(o_string *o); 544static int redirect_opt_num(o_string *o);
@@ -547,11 +546,11 @@ static int redirect_opt_num(o_string *o);
547static int process_command_subs(o_string *dest, 546static 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
550static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); 549static int parse_group(o_string *dest, struct parse_context *ctx, struct in_str *input, int ch);
551static const char *lookup_param(const char *src); 550static const char *lookup_param(const char *src);
552static int handle_dollar(o_string *dest, 551static int handle_dollar(o_string *dest,
553 struct in_str *input); 552 struct in_str *input);
554static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger); 553static int parse_stream(o_string *dest, struct parse_context *ctx, struct in_str *input0, const char *end_trigger);
555/* setup: */ 554/* setup: */
556static int parse_and_run_stream(struct in_str *inp, int parse_flag); 555static int parse_and_run_stream(struct in_str *inp, int parse_flag);
557static int parse_and_run_string(const char *s, int parse_flag); 556static 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. */
1337static int setup_redirects(struct child_prog *prog, int squirrel[]) 1336static 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 */
1470static void pseudo_exec(char **ptrs2free, struct child_prog *child, char **argv_expanded) 1469static 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)
1585static void delete_finished_bg_job(struct pipe *pi) 1584static 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)
2349static int free_pipe(struct pipe *pi, int indent) 2348static 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 */
2836static int setup_redirect(struct p_context *ctx, int fd, redir_type style, 2835static 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
2890static void initialize_context(struct p_context *ctx) 2889static 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
2907static int reserved_word(o_string *word, struct p_context *ctx) 2906static 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. */
3023static int done_word(o_string *word, struct p_context *ctx) 3022static 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. */
3134static int done_command(struct p_context *ctx) 3133static 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
3167static void done_pipe(struct p_context *ctx, pipe_style type) 3166static 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
3370static int parse_group(o_string *dest, struct p_context *ctx, 3369static 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 */
3620static int parse_stream(o_string *dest, struct p_context *ctx, 3622static 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() */
3948static int parse_and_run_stream(struct in_str *inp, int parse_flag) 3952static 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";