From 9af22c762652ff92f3f207a754f71f3c4bf2c078 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Thu, 9 Oct 2008 12:54:58 +0000 Subject: [PATCH] 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 '(' --- shell/hush.c | 408 ++++++++++++++++++++++++++------------------------- 1 file 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 @@ * aliases * Arithmetic Expansion * <(list) and >(list) Process Substitution - * reserved words: case, esac, select, function + * reserved words: select, function * Here Documents ( << word ) * Functions * Major bugs: * job handling woefully incomplete and buggy (improved --vda) - * reserved word execution woefully incomplete and buggy * to-do: * port selected bugfixes from post-0.49 busybox lash - done? * change { and } from special chars to reserved words @@ -291,23 +290,6 @@ typedef enum reserved_style { RES_SNTX } reserved_style; -/* This holds pointers to the various results of parsing */ -struct p_context { - struct child_prog *child; - struct pipe *list_head; - struct pipe *pipe; - struct redir_struct *pending_redirect; -#if HAS_KEYWORDS - smallint ctx_res_w; - smallint ctx_inverted; /* "! cmd | cmd" */ -#if ENABLE_HUSH_CASE - smallint ctx_dsemicolon; /* ";;" seen */ -#endif - int old_flag; /* bitmask of FLAG_xxx, for figuring out valid reserved words */ - struct p_context *stack; -#endif -}; - struct redir_struct { struct redir_struct *next; char *rd_filename; /* filename */ @@ -316,14 +298,14 @@ struct redir_struct { smallint /*enum redir_type*/ rd_type; }; -struct child_prog { +struct command { pid_t pid; /* 0 if exited */ int assignment_cnt; /* how many argv[i] are assignments? */ - smallint is_stopped; /* is the program currently running? */ + smallint is_stopped; /* is the command currently running? */ smallint subshell; /* flag, non-zero if group must be forked */ struct pipe *group; /* if non-NULL, this "prog" is {} group, * subshell, or a compound statement */ - char **argv; /* program name and arguments */ + char **argv; /* command name and arguments */ struct redir_struct *redirects; /* I/O redirections */ }; /* argv vector may contain variable references (^Cvar^C, ^C0^C etc) @@ -335,20 +317,37 @@ struct child_prog { struct pipe { struct pipe *next; - int num_progs; /* total number of programs in job */ - int alive_progs; /* number of programs running (not exited) */ - int stopped_progs; /* number of programs alive, but stopped */ + int num_cmds; /* total number of commands in job */ + int alive_cmds; /* number of commands running (not exited) */ + int stopped_cmds; /* number of commands alive, but stopped */ #if ENABLE_HUSH_JOB int jobid; /* job number */ pid_t pgrp; /* process group ID for the job */ char *cmdtext; /* name of job */ #endif - struct child_prog *progs; /* array of commands in pipe */ + struct command *cmds; /* array of commands in pipe */ smallint followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ IF_HAS_KEYWORDS(smallint pi_inverted;) /* "! cmd | cmd" */ IF_HAS_KEYWORDS(smallint res_word;) /* needed for if, for, while, until... */ }; +/* This holds pointers to the various results of parsing */ +struct parse_context { + struct command *command; + struct pipe *list_head; + struct pipe *pipe; + struct redir_struct *pending_redirect; +#if HAS_KEYWORDS + smallint ctx_res_w; + smallint ctx_inverted; /* "! cmd | cmd" */ +#if ENABLE_HUSH_CASE + smallint ctx_dsemicolon; /* ";;" seen */ +#endif + int old_flag; /* bitmask of FLAG_xxx, for figuring out valid reserved words */ + struct parse_context *stack; +#endif +}; + /* On program start, environ points to initial environment. * putenv adds new pointers into it, unsetenv removes them. * Neither of these (de)allocates the strings. @@ -523,23 +522,23 @@ static void setup_string_in_str(struct in_str *i, const char *s); static int free_pipe_list(struct pipe *head, int indent); static int free_pipe(struct pipe *pi, int indent); /* really run the final data structures: */ -static int setup_redirects(struct child_prog *prog, int squirrel[]); +static int setup_redirects(struct command *prog, int squirrel[]); static int run_list(struct pipe *pi); #if BB_MMU #define pseudo_exec_argv(ptrs2free, argv, assignment_cnt, argv_expanded) \ pseudo_exec_argv(argv, assignment_cnt, argv_expanded) -#define pseudo_exec(ptrs2free, child, argv_expanded) \ - pseudo_exec(child, argv_expanded) +#define pseudo_exec(ptrs2free, command, argv_expanded) \ + pseudo_exec(command, argv_expanded) #endif static void pseudo_exec_argv(char **ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) NORETURN; -static void pseudo_exec(char **ptrs2free, struct child_prog *child, char **argv_expanded) NORETURN; +static void pseudo_exec(char **ptrs2free, struct command *command, char **argv_expanded) NORETURN; static int run_pipe(struct pipe *pi); /* data structure manipulation: */ -static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input); -static void initialize_context(struct p_context *ctx); -static int done_word(o_string *dest, struct p_context *ctx); -static int done_command(struct p_context *ctx); -static void done_pipe(struct p_context *ctx, pipe_style type); +static int setup_redirect(struct parse_context *ctx, int fd, redir_type style, struct in_str *input); +static void initialize_context(struct parse_context *ctx); +static int done_word(o_string *dest, struct parse_context *ctx); +static int done_command(struct parse_context *ctx); +static void done_pipe(struct parse_context *ctx, pipe_style type); /* primary string parsing: */ static int redirect_dup_num(struct in_str *input); static int redirect_opt_num(o_string *o); @@ -547,11 +546,11 @@ static int redirect_opt_num(o_string *o); static int process_command_subs(o_string *dest, struct in_str *input, const char *subst_end); #endif -static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); +static int parse_group(o_string *dest, struct parse_context *ctx, struct in_str *input, int ch); static const char *lookup_param(const char *src); static int handle_dollar(o_string *dest, struct in_str *input); -static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger); +static int parse_stream(o_string *dest, struct parse_context *ctx, struct in_str *input0, const char *end_trigger); /* setup: */ static int parse_and_run_stream(struct in_str *inp, int parse_flag); 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) /* parent */ /* finish filling up pipe info */ G.toplevel_list->pgrp = pid; /* child is in its own pgrp */ - G.toplevel_list->progs[0].pid = pid; + G.toplevel_list->cmds[0].pid = pid; /* parent needs to longjmp out of running nofork. * we will "return" exitcode 0, with child put in background */ // 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) /* squirrel != NULL means we squirrel away copies of stdin, stdout, * and stderr if they are redirected. */ -static int setup_redirects(struct child_prog *prog, int squirrel[]) +static int setup_redirects(struct command *prog, int squirrel[]) { int openfd, mode; struct redir_struct *redir; @@ -1467,18 +1466,18 @@ static void pseudo_exec_argv(char **ptrs2free, char **argv, int assignment_cnt, /* Called after [v]fork() in run_pipe() */ -static void pseudo_exec(char **ptrs2free, struct child_prog *child, char **argv_expanded) +static void pseudo_exec(char **ptrs2free, struct command *command, char **argv_expanded) { - if (child->argv) - pseudo_exec_argv(ptrs2free, child->argv, child->assignment_cnt, argv_expanded); + if (command->argv) + pseudo_exec_argv(ptrs2free, command->argv, command->assignment_cnt, argv_expanded); - if (child->group) { + if (command->group) { #if !BB_MMU bb_error_msg_and_die("nested lists are not supported on NOMMU"); #else int rcode; debug_printf_exec("pseudo_exec: run_list\n"); - rcode = run_list(child->group); + rcode = run_list(command->group); /* OK to leak memory by not calling free_pipe_list, * since this process is about to exit */ _exit(rcode); @@ -1502,7 +1501,7 @@ static const char *get_cmdtext(struct pipe *pi) * On subsequent bg argv is trashed, but we won't use it */ if (pi->cmdtext) return pi->cmdtext; - argv = pi->progs[0].argv; + argv = pi->cmds[0].argv; if (!argv || !argv[0]) { pi->cmdtext = xzalloc(1); return pi->cmdtext; @@ -1511,7 +1510,7 @@ static const char *get_cmdtext(struct pipe *pi) len = 0; do len += strlen(*argv) + 1; while (*++argv); pi->cmdtext = p = xmalloc(len); - argv = pi->progs[0].argv; + argv = pi->cmds[0].argv; do { len = strlen(*argv); memcpy(p, *argv, len); @@ -1545,12 +1544,12 @@ static void insert_bg_job(struct pipe *pi) /* Physically copy the struct job */ memcpy(thejob, pi, sizeof(struct pipe)); - thejob->progs = xzalloc(sizeof(pi->progs[0]) * pi->num_progs); - /* We cannot copy entire pi->progs[] vector! Double free()s will happen */ - for (i = 0; i < pi->num_progs; i++) { + thejob->cmds = xzalloc(sizeof(pi->cmds[0]) * pi->num_cmds); + /* We cannot copy entire pi->cmds[] vector! Double free()s will happen */ + for (i = 0; i < pi->num_cmds; i++) { // TODO: do we really need to have so many fields which are just dead weight // at execution stage? - thejob->progs[i].pid = pi->progs[i].pid; + thejob->cmds[i].pid = pi->cmds[i].pid; /* all other fields are not used and stay zero */ } thejob->next = NULL; @@ -1558,8 +1557,8 @@ static void insert_bg_job(struct pipe *pi) /* We don't wait for background thejobs to return -- append it to the list of backgrounded thejobs and leave it alone */ - printf("[%d] %d %s\n", thejob->jobid, thejob->progs[0].pid, thejob->cmdtext); - G.last_bg_pid = thejob->progs[0].pid; + printf("[%d] %d %s\n", thejob->jobid, thejob->cmds[0].pid, thejob->cmdtext); + G.last_bg_pid = thejob->cmds[0].pid; G.last_jobid = thejob->jobid; } @@ -1585,7 +1584,7 @@ static void remove_bg_job(struct pipe *pi) static void delete_finished_bg_job(struct pipe *pi) { remove_bg_job(pi); - pi->stopped_progs = 0; + pi->stopped_cmds = 0; free_pipe(pi, 0); free(pi); } @@ -1637,29 +1636,29 @@ static int checkjobs(struct pipe* fg_pipe) #endif /* Were we asked to wait for fg pipe? */ if (fg_pipe) { - for (i = 0; i < fg_pipe->num_progs; i++) { - debug_printf_jobs("check pid %d\n", fg_pipe->progs[i].pid); - if (fg_pipe->progs[i].pid != childpid) + for (i = 0; i < fg_pipe->num_cmds; i++) { + debug_printf_jobs("check pid %d\n", fg_pipe->cmds[i].pid); + if (fg_pipe->cmds[i].pid != childpid) continue; /* printf("process %d exit %d\n", i, WEXITSTATUS(status)); */ if (dead) { - fg_pipe->progs[i].pid = 0; - fg_pipe->alive_progs--; - if (i == fg_pipe->num_progs - 1) { + fg_pipe->cmds[i].pid = 0; + fg_pipe->alive_cmds--; + if (i == fg_pipe->num_cmds - 1) { /* last process gives overall exitstatus */ rcode = WEXITSTATUS(status); IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) } } else { - fg_pipe->progs[i].is_stopped = 1; - fg_pipe->stopped_progs++; + fg_pipe->cmds[i].is_stopped = 1; + fg_pipe->stopped_cmds++; } - debug_printf_jobs("fg_pipe: alive_progs %d stopped_progs %d\n", - fg_pipe->alive_progs, fg_pipe->stopped_progs); - if (fg_pipe->alive_progs - fg_pipe->stopped_progs <= 0) { + debug_printf_jobs("fg_pipe: alive_cmds %d stopped_cmds %d\n", + fg_pipe->alive_cmds, fg_pipe->stopped_cmds); + if (fg_pipe->alive_cmds - fg_pipe->stopped_cmds <= 0) { /* All processes in fg pipe have exited/stopped */ #if ENABLE_HUSH_JOB - if (fg_pipe->alive_progs) + if (fg_pipe->alive_cmds) insert_bg_job(fg_pipe); #endif return rcode; @@ -1674,8 +1673,8 @@ static int checkjobs(struct pipe* fg_pipe) /* We asked to wait for bg or orphaned children */ /* No need to remember exitcode in this case */ for (pi = G.job_list; pi; pi = pi->next) { - for (i = 0; i < pi->num_progs; i++) { - if (pi->progs[i].pid == childpid) + for (i = 0; i < pi->num_cmds; i++) { + if (pi->cmds[i].pid == childpid) goto found_pi_and_prognum; } } @@ -1686,17 +1685,17 @@ static int checkjobs(struct pipe* fg_pipe) found_pi_and_prognum: if (dead) { /* child exited */ - pi->progs[i].pid = 0; - pi->alive_progs--; - if (!pi->alive_progs) { + pi->cmds[i].pid = 0; + pi->alive_cmds--; + if (!pi->alive_cmds) { printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->cmdtext); delete_finished_bg_job(pi); } } else { /* child stopped */ - pi->progs[i].is_stopped = 1; - pi->stopped_progs++; + pi->cmds[i].is_stopped = 1; + pi->stopped_cmds++; } #endif } /* while (waitpid succeeds)... */ @@ -1745,7 +1744,7 @@ static int run_pipe(struct pipe *pi) int i; int nextin; int pipefds[2]; /* pipefds[0] is for reading */ - struct child_prog *child; + struct command *command; char **argv_expanded = NULL; char **argv; const struct built_in_command *x; @@ -1753,36 +1752,36 @@ static int run_pipe(struct pipe *pi) /* it is not always needed, but we aim to smaller code */ int squirrel[] = { -1, -1, -1 }; int rcode; - const int single_and_fg = (pi->num_progs == 1 && pi->followup != PIPE_BG); + const int single_and_fg = (pi->num_cmds == 1 && pi->followup != PIPE_BG); debug_printf_exec("run_pipe start: single_and_fg=%d\n", single_and_fg); #if ENABLE_HUSH_JOB pi->pgrp = -1; #endif - pi->alive_progs = 1; - pi->stopped_progs = 0; + pi->alive_cmds = 1; + pi->stopped_cmds = 0; /* Check if this is a simple builtin (not part of a pipe). * Builtins within pipes have to fork anyway, and are handled in * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. */ - child = &(pi->progs[0]); - if (single_and_fg && child->group && child->subshell == 0) { + command = &(pi->cmds[0]); + if (single_and_fg && command->group && command->subshell == 0) { debug_printf("non-subshell grouping\n"); - setup_redirects(child, squirrel); + setup_redirects(command, squirrel); debug_printf_exec(": run_list\n"); - rcode = run_list(child->group) & 0xff; + rcode = run_list(command->group) & 0xff; restore_redirects(squirrel); debug_printf_exec("run_pipe return %d\n", rcode); IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) return rcode; } - argv = child->argv; + argv = command->argv; if (single_and_fg && argv != NULL) { - i = child->assignment_cnt; + i = command->assignment_cnt; if (i != 0 && argv[i] == NULL) { /* assignments, but no command: set local environment */ for (i = 0; argv[i] != NULL; i++) { @@ -1794,7 +1793,7 @@ static int run_pipe(struct pipe *pi) } /* Expand assignments into one string each */ - for (i = 0; i < child->assignment_cnt; i++) { + for (i = 0; i < command->assignment_cnt; i++) { p = expand_string_to_string(argv[i]); putenv(p); //FIXME: do we leak p?! @@ -1807,7 +1806,7 @@ static int run_pipe(struct pipe *pi) if (strcmp(argv_expanded[0], x->cmd) == 0) { if (x->function == builtin_exec && argv_expanded[1] == NULL) { debug_printf("magic exec\n"); - setup_redirects(child, NULL); + setup_redirects(command, NULL); return EXIT_SUCCESS; } debug_printf("builtin inline %s\n", argv_expanded[0]); @@ -1815,7 +1814,7 @@ static int run_pipe(struct pipe *pi) * This is perfect for work that comes after exec(). * Is it really safe for inline use? Experimentally, * things seem to work with glibc. */ - setup_redirects(child, squirrel); + setup_redirects(command, squirrel); debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv_expanded[1]); rcode = x->function(argv_expanded) & 0xff; free(argv_expanded); @@ -1829,7 +1828,7 @@ static int run_pipe(struct pipe *pi) { int a = find_applet_by_name(argv_expanded[0]); if (a >= 0 && APPLET_IS_NOFORK(a)) { - setup_redirects(child, squirrel); + setup_redirects(command, squirrel); save_nofork_data(&G.nofork_save); debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); rcode = run_nofork_applet_prime(&G.nofork_save, a, argv_expanded); @@ -1852,18 +1851,18 @@ static int run_pipe(struct pipe *pi) set_jobctrl_sighandler(SIG_IGN); /* Going to fork a child per each pipe member */ - pi->alive_progs = 0; + pi->alive_cmds = 0; nextin = 0; - for (i = 0; i < pi->num_progs; i++) { + for (i = 0; i < pi->num_cmds; i++) { #if !BB_MMU char **ptrs2free = NULL; #endif - child = &(pi->progs[i]); - if (child->argv) { - debug_printf_exec(": pipe member '%s' '%s'...\n", child->argv[0], child->argv[1]); + command = &(pi->cmds[i]); + if (command->argv) { + debug_printf_exec(": pipe member '%s' '%s'...\n", command->argv[0], command->argv[1]); #if !BB_MMU - ptrs2free = alloc_ptrs(child->argv); + ptrs2free = alloc_ptrs(command->argv); #endif } else debug_printf_exec(": pipe member with no argv\n"); @@ -1871,11 +1870,11 @@ static int run_pipe(struct pipe *pi) /* pipes are inserted between pairs of commands */ pipefds[0] = 0; pipefds[1] = 1; - if ((i + 1) < pi->num_progs) + if ((i + 1) < pi->num_cmds) xpipe(pipefds); - child->pid = BB_MMU ? fork() : vfork(); - if (!child->pid) { /* child */ + command->pid = BB_MMU ? fork() : vfork(); + if (!command->pid) { /* child */ if (ENABLE_HUSH_JOB) die_sleep = 0; /* let nofork's xfuncs die */ #if ENABLE_HUSH_JOB @@ -1901,45 +1900,45 @@ static int run_pipe(struct pipe *pi) close(pipefds[0]); /* read end */ /* Like bash, explicit redirects override pipes, * and the pipe fd is available for dup'ing. */ - setup_redirects(child, NULL); + setup_redirects(command, NULL); /* Restore default handlers just prior to exec */ set_jobctrl_sighandler(SIG_DFL); set_misc_sighandler(SIG_DFL); signal(SIGCHLD, SIG_DFL); - pseudo_exec(ptrs2free, child, argv_expanded); /* does not return */ + pseudo_exec(ptrs2free, command, argv_expanded); /* does not return */ } free(argv_expanded); argv_expanded = NULL; #if !BB_MMU free_strings(ptrs2free); #endif - if (child->pid < 0) { /* [v]fork failed */ + if (command->pid < 0) { /* [v]fork failed */ /* Clearly indicate, was it fork or vfork */ bb_perror_msg(BB_MMU ? "fork" : "vfork"); } else { - pi->alive_progs++; + pi->alive_cmds++; #if ENABLE_HUSH_JOB /* Second and next children need to know pid of first one */ if (pi->pgrp < 0) - pi->pgrp = child->pid; + pi->pgrp = command->pid; #endif } if (i) close(nextin); - if ((i + 1) < pi->num_progs) + if ((i + 1) < pi->num_cmds) close(pipefds[1]); /* write end */ /* Pass read (output) pipe end to next iteration */ nextin = pipefds[0]; } - if (!pi->alive_progs) { + if (!pi->alive_cmds) { debug_printf_exec("run_pipe return 1 (all forks failed, no children)\n"); return 1; } - debug_printf_exec("run_pipe return -1 (%u children started)\n", pi->alive_progs); + debug_printf_exec("run_pipe return -1 (%u children started)\n", pi->alive_cmds); return -1; } @@ -1988,16 +1987,16 @@ static void debug_print_tree(struct pipe *pi, int lvl) fprintf(stderr, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); prn = 0; - while (prn < pi->num_progs) { - struct child_prog *child = &pi->progs[prn]; - char **argv = child->argv; + while (prn < pi->num_cmds) { + struct command *command = &pi->cmds[prn]; + char **argv = command->argv; - fprintf(stderr, "%*s prog %d assignment_cnt:%d", lvl*2, "", prn, child->assignment_cnt); - if (child->group) { + fprintf(stderr, "%*s prog %d assignment_cnt:%d", lvl*2, "", prn, command->assignment_cnt); + if (command->group) { fprintf(stderr, " group %s: (argv=%p)\n", - (child->subshell ? "()" : "{}"), + (command->subshell ? "()" : "{}"), argv); - debug_print_tree(child->group, lvl+1); + debug_print_tree(command->group, lvl+1); prn++; continue; } @@ -2151,7 +2150,7 @@ static int run_list(struct pipe *pi) } #endif #if ENABLE_HUSH_LOOPS - if (rword == RES_FOR) { /* && pi->num_progs - always == 1 */ + if (rword == RES_FOR) { /* && pi->num_cmds - always == 1 */ if (!for_lcur) { /* first loop through for */ @@ -2166,31 +2165,31 @@ static int run_list(struct pipe *pi) vals = (char**)encoded_dollar_at_argv; if (pi->next->res_word == RES_IN) { /* if no variable values after "in" we skip "for" */ - if (!pi->next->progs[0].argv) + if (!pi->next->cmds[0].argv) break; - vals = pi->next->progs[0].argv; + vals = pi->next->cmds[0].argv; } /* else: "for var; do..." -> assume "$@" list */ /* create list of variable values */ debug_print_strings("for_list made from", vals); for_list = expand_strvec_to_strvec(vals); for_lcur = for_list; debug_print_strings("for_list", for_list); - for_varname = pi->progs[0].argv[0]; - pi->progs[0].argv[0] = NULL; + for_varname = pi->cmds[0].argv[0]; + pi->cmds[0].argv[0] = NULL; } - free(pi->progs[0].argv[0]); + free(pi->cmds[0].argv[0]); if (!*for_lcur) { /* "for" loop is over, clean up */ free(for_list); for_list = NULL; for_lcur = NULL; - pi->progs[0].argv[0] = for_varname; + pi->cmds[0].argv[0] = for_varname; break; } /* insert next value from for_lcur */ //TODO: does it need escaping? - pi->progs[0].argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); - pi->progs[0].assignment_cnt = 1; + pi->cmds[0].argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); + pi->cmds[0].assignment_cnt = 1; } if (rword == RES_IN) /* "for v IN list;..." - "in" has no cmds anyway */ continue; @@ -2200,7 +2199,7 @@ static int run_list(struct pipe *pi) #endif #if ENABLE_HUSH_CASE if (rword == RES_CASE) { - case_word = expand_strvec_to_string(pi->progs->argv); + case_word = expand_strvec_to_string(pi->cmds->argv); continue; } if (rword == RES_MATCH) { @@ -2209,7 +2208,7 @@ static int run_list(struct pipe *pi) if (!case_word) /* "case ... matched_word) ... WORD)": we executed selected branch, stop */ break; /* all prev words didn't match, does this one match? */ - argv = pi->progs->argv; + argv = pi->cmds->argv; while (*argv) { char *pattern = expand_string_to_string(*argv); /* TODO: which FNM_xxx flags to use? */ @@ -2229,14 +2228,14 @@ static int run_list(struct pipe *pi) continue; /* not matched yet, skip this pipe */ } #endif - if (pi->num_progs == 0) + if (pi->num_cmds == 0) continue; /* After analyzing all keywords and conditions, we decided * to execute this pipe. NB: has to do checkjobs(NULL) * after run_pipe() to collect any background children, * even if list execution is to be stopped. */ - debug_printf_exec(": run_pipe with %d members\n", pi->num_progs); + debug_printf_exec(": run_pipe with %d members\n", pi->num_cmds); { int r; #if ENABLE_HUSH_LOOPS @@ -2349,30 +2348,30 @@ static int run_list(struct pipe *pi) static int free_pipe(struct pipe *pi, int indent) { char **p; - struct child_prog *child; + struct command *command; struct redir_struct *r, *rnext; int a, i, ret_code = 0; - if (pi->stopped_progs > 0) + if (pi->stopped_cmds > 0) return ret_code; debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid()); - for (i = 0; i < pi->num_progs; i++) { - child = &pi->progs[i]; + for (i = 0; i < pi->num_cmds; i++) { + command = &pi->cmds[i]; debug_printf_clean("%s command %d:\n", indenter(indent), i); - if (child->argv) { - for (a = 0, p = child->argv; *p; a++, p++) { + if (command->argv) { + for (a = 0, p = command->argv; *p; a++, p++) { debug_printf_clean("%s argv[%d] = %s\n", indenter(indent), a, *p); } - free_strings(child->argv); - child->argv = NULL; - } else if (child->group) { - debug_printf_clean("%s begin group (subshell:%d)\n", indenter(indent), child->subshell); - ret_code = free_pipe_list(child->group, indent+3); + free_strings(command->argv); + command->argv = NULL; + } else if (command->group) { + debug_printf_clean("%s begin group (subshell:%d)\n", indenter(indent), command->subshell); + ret_code = free_pipe_list(command->group, indent+3); debug_printf_clean("%s end group\n", indenter(indent)); } else { debug_printf_clean("%s (nil)\n", indenter(indent)); } - for (r = child->redirects; r; r = rnext) { + for (r = command->redirects; r; r = rnext) { debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->rd_type].descrip); if (r->dup == -1) { /* guard against the case >$FOO, where foo is unset or blank */ @@ -2387,10 +2386,10 @@ static int free_pipe(struct pipe *pi, int indent) rnext = r->next; free(r); } - child->redirects = NULL; + command->redirects = NULL; } - free(pi->progs); /* children are an array, they get freed all at once */ - pi->progs = NULL; + free(pi->cmds); /* children are an array, they get freed all at once */ + pi->cmds = NULL; #if ENABLE_HUSH_JOB free(pi->cmdtext); pi->cmdtext = NULL; @@ -2422,7 +2421,7 @@ static int run_and_free_list(struct pipe *pi) int rcode = 0; debug_printf_exec("run_and_free_list entered\n"); if (!G.fake_mode) { - debug_printf_exec(": run_list with %d members\n", pi->num_progs); + debug_printf_exec(": run_list with %d members\n", pi->num_cmds); rcode = run_list(pi); } /* free_pipe_list has the side effect of clearing memory. @@ -2833,11 +2832,11 @@ static void unset_local_var(const char *name) * for file descriptor duplication, e.g., "2>&1". * Return code is 0 normally, 1 if a syntax error is detected in src. * Resource errors (in xmalloc) cause the process to exit */ -static int setup_redirect(struct p_context *ctx, int fd, redir_type style, +static int setup_redirect(struct parse_context *ctx, int fd, redir_type style, struct in_str *input) { - struct child_prog *child = ctx->child; - struct redir_struct *redir = child->redirects; + struct command *command = ctx->command; + struct redir_struct *redir = command->redirects; struct redir_struct *last_redir = NULL; /* 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, if (last_redir) { last_redir->next = redir; } else { - child->redirects = redir; + command->redirects = redir; } redir->rd_type = style; @@ -2887,13 +2886,13 @@ static struct pipe *new_pipe(void) return pi; } -static void initialize_context(struct p_context *ctx) +static void initialize_context(struct parse_context *ctx) { memset(ctx, 0, sizeof(*ctx)); ctx->pipe = ctx->list_head = new_pipe(); - /* Create the memory for child, roughly: - * ctx->pipe->progs = new struct child_prog; - * ctx->child = &ctx->pipe->progs[0]; + /* Create the memory for command, roughly: + * ctx->pipe->cmds = new struct command; + * ctx->command = &ctx->pipe->cmds[0]; */ done_command(ctx); } @@ -2904,7 +2903,7 @@ static void initialize_context(struct p_context *ctx) * case, function, and select are obnoxious, save those for later. */ #if HAS_KEYWORDS -static int reserved_word(o_string *word, struct p_context *ctx) +static int reserved_word(o_string *word, struct parse_context *ctx) { struct reserved_combo { char literal[6]; @@ -2988,7 +2987,7 @@ static int reserved_word(o_string *word, struct p_context *ctx) return 1; } if (r->flag & FLAG_START) { - struct p_context *new; + struct parse_context *new; debug_printf("push stack\n"); new = xmalloc(sizeof(*new)); *new = *ctx; /* physical copy */ @@ -3002,12 +3001,12 @@ static int reserved_word(o_string *word, struct p_context *ctx) ctx->ctx_res_w = r->res; ctx->old_flag = r->flag; if (ctx->old_flag & FLAG_END) { - struct p_context *old; + struct parse_context *old; debug_printf("pop stack\n"); done_pipe(ctx, PIPE_SEQ); old = ctx->stack; - old->child->group = ctx->list_head; - old->child->subshell = 0; + old->command->group = ctx->list_head; + old->command->subshell = 0; *ctx = *old; /* physical copy */ free(old); } @@ -3020,11 +3019,11 @@ static int reserved_word(o_string *word, struct p_context *ctx) /* Word is complete, look at it and update parsing context. * Normal return is 0. Syntax errors return 1. */ -static int done_word(o_string *word, struct p_context *ctx) +static int done_word(o_string *word, struct parse_context *ctx) { - struct child_prog *child = ctx->child; + struct command *command = ctx->command; - debug_printf_parse("done_word entered: '%s' %p\n", word->data, child); + debug_printf_parse("done_word entered: '%s' %p\n", word->data, command); if (word->length == 0 && word->nonnull == 0) { debug_printf_parse("done_word return 0: true null, ignored\n"); return 0; @@ -3037,7 +3036,7 @@ static int done_word(o_string *word, struct p_context *ctx) word->o_assignment = NOT_ASSIGNMENT; } else { if (word->o_assignment == DEFINITELY_ASSIGNMENT) - child->assignment_cnt++; + command->assignment_cnt++; word->o_assignment = MAYBE_ASSIGNMENT; } @@ -3050,7 +3049,7 @@ static int done_word(o_string *word, struct p_context *ctx) } else { /* "{ echo foo; } echo bar" - bad */ /* NB: bash allows e.g. "if true; then { echo foo; } fi". TODO? */ - if (child->group) { + if (command->group) { syntax(NULL); debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); return 1; @@ -3066,7 +3065,7 @@ static int done_word(o_string *word, struct p_context *ctx) } else #endif - if (!child->argv /* if it's the first word... */ + if (!command->argv /* if it's the first word... */ #if ENABLE_HUSH_LOOPS && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ && ctx->ctx_res_w != RES_IN @@ -3102,8 +3101,8 @@ static int done_word(o_string *word, struct p_context *ctx) o_addchr(word, SPECIAL_VAR_SYMBOL); } } - child->argv = add_malloced_string_to_strings(child->argv, xstrdup(word->data)); - debug_print_strings("word appended to argv", child->argv); + command->argv = add_malloced_string_to_strings(command->argv, xstrdup(word->data)); + debug_print_strings("word appended to argv", command->argv); } o_reset(word); @@ -3115,7 +3114,7 @@ static int done_word(o_string *word, struct p_context *ctx) * as it is "for v; in ...". FOR and IN become two pipe structs * in parse tree. */ if (ctx->ctx_res_w == RES_FOR) { -//TODO: check that child->argv[0] is a valid variable name! +//TODO: check that command->argv[0] is a valid variable name! done_pipe(ctx, PIPE_SEQ); } #endif @@ -3131,40 +3130,40 @@ static int done_word(o_string *word, struct p_context *ctx) /* Command (member of a pipe) is complete. The only possible error here * is out of memory, in which case xmalloc exits. */ -static int done_command(struct p_context *ctx) +static int done_command(struct parse_context *ctx) { - /* The child is really already in the pipe structure, so - * advance the pipe counter and make a new, null child. */ + /* The command is really already in the pipe structure, so + * advance the pipe counter and make a new, null command. */ struct pipe *pi = ctx->pipe; - struct child_prog *child = ctx->child; + struct command *command = ctx->command; - if (child) { - if (child->group == NULL - && child->argv == NULL - && child->redirects == NULL + if (command) { + if (command->group == NULL + && command->argv == NULL + && command->redirects == NULL ) { - debug_printf_parse("done_command: skipping null cmd, num_progs=%d\n", pi->num_progs); - return pi->num_progs; + debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds); + return pi->num_cmds; } - pi->num_progs++; - debug_printf_parse("done_command: ++num_progs=%d\n", pi->num_progs); + pi->num_cmds++; + debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds); } else { - debug_printf_parse("done_command: initializing, num_progs=%d\n", pi->num_progs); + debug_printf_parse("done_command: initializing, num_cmds=%d\n", pi->num_cmds); } /* Only real trickiness here is that the uncommitted - * child structure is not counted in pi->num_progs. */ - pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1)); - child = &pi->progs[pi->num_progs]; - memset(child, 0, sizeof(*child)); + * command structure is not counted in pi->num_cmds. */ + pi->cmds = xrealloc(pi->cmds, sizeof(*pi->cmds) * (pi->num_cmds+1)); + command = &pi->cmds[pi->num_cmds]; + memset(command, 0, sizeof(*command)); - ctx->child = child; + ctx->command = command; /* but ctx->pipe and ctx->list_head remain unchanged */ - return pi->num_progs; /* used only for 0/nonzero check */ + return pi->num_cmds; /* used only for 0/nonzero check */ } -static void done_pipe(struct p_context *ctx, pipe_style type) +static void done_pipe(struct parse_context *ctx, pipe_style type) { int not_null; @@ -3189,7 +3188,7 @@ static void done_pipe(struct p_context *ctx, pipe_style type) new_p = new_pipe(); ctx->pipe->next = new_p; ctx->pipe = new_p; - ctx->child = NULL; /* needed! */ + ctx->command = NULL; /* needed! */ /* RES_THEN, RES_DO etc are "sticky" - * they remain set for commands inside if/while. * This is used to control execution. @@ -3205,9 +3204,9 @@ static void done_pipe(struct p_context *ctx, pipe_style type) if (ctx->ctx_res_w == RES_MATCH) ctx->ctx_res_w = RES_CASEI; #endif - /* Create the memory for child, roughly: - * ctx->pipe->progs = new struct child_prog; - * ctx->child = &ctx->pipe->progs[0]; + /* Create the memory for command, roughly: + * ctx->pipe->cmds = new struct command; + * ctx->command = &ctx->pipe->cmds[0]; */ done_command(ctx); } @@ -3320,7 +3319,7 @@ static int process_command_subs(o_string *dest, { int retcode, ch, eol_cnt; o_string result = NULL_O_STRING; - struct p_context inner; + struct parse_context inner; FILE *p; struct in_str pipe_str; @@ -3367,7 +3366,7 @@ static int process_command_subs(o_string *dest, } #endif -static int parse_group(o_string *dest, struct p_context *ctx, +static int parse_group(o_string *dest, struct parse_context *ctx, struct in_str *input, int ch) { /* 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, * if we (ab)use caller's one. */ int rcode; const char *endch = NULL; - struct p_context sub; - struct child_prog *child = ctx->child; + struct parse_context sub; + struct command *command = ctx->command; debug_printf_parse("parse_group entered\n"); - if (child->argv) { + if (command->argv /* word [word](... */ + || dest->length /* word(... */ + || dest->nonnull /* ""(... */ + ) { syntax(NULL); debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n"); return 1; @@ -3388,17 +3390,17 @@ static int parse_group(o_string *dest, struct p_context *ctx, endch = "}"; if (ch == '(') { endch = ")"; - child->subshell = 1; + command->subshell = 1; } rcode = parse_stream(dest, &sub, input, endch); if (rcode == 0) { done_word(dest, &sub); /* finish off the final word in the subcontext */ done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */ - child->group = sub.list_head; + command->group = sub.list_head; } debug_printf_parse("parse_group return %d\n", rcode); return rcode; - /* child remains "open", available for possible redirects */ + /* command remains "open", available for possible redirects */ } /* Basically useful version until someone wants to get fancier, @@ -3617,7 +3619,7 @@ static int handle_dollar(o_string *dest, struct in_str *input) * Return code is 0 if end_trigger char is met, * -1 on EOF (but if end_trigger == NULL then return 0), * 1 for syntax error */ -static int parse_stream(o_string *dest, struct p_context *ctx, +static int parse_stream(o_string *dest, struct parse_context *ctx, struct in_str *input, const char *end_trigger) { int ch, m; @@ -3883,8 +3885,10 @@ static int parse_stream(o_string *dest, struct p_context *ctx, case '(': #if ENABLE_HUSH_CASE /* "case... in [(]word)..." - skip '(' */ - if (dest->length == 0 // && argv[0] == NULL + if (dest->length == 0 /* not word(... */ + && dest->nonnull == 0 /* not ""(... */ && ctx->ctx_res_w == RES_MATCH + && ctx->command->argv == NULL /* not (word|(... */ ) { continue; } @@ -3947,7 +3951,7 @@ static void update_charmap(void) * from builtin_source() and builtin_eval() */ static int parse_and_run_stream(struct in_str *inp, int parse_flag) { - struct p_context ctx; + struct parse_context ctx; o_string temp = NULL_O_STRING; int rcode; @@ -4408,12 +4412,12 @@ static int builtin_fg_bg(char **argv) } /* Restart the processes in the job */ - debug_printf_jobs("reviving %d procs, pgrp %d\n", pi->num_progs, pi->pgrp); - for (i = 0; i < pi->num_progs; i++) { - debug_printf_jobs("reviving pid %d\n", pi->progs[i].pid); - pi->progs[i].is_stopped = 0; + debug_printf_jobs("reviving %d procs, pgrp %d\n", pi->num_cmds, pi->pgrp); + for (i = 0; i < pi->num_cmds; i++) { + debug_printf_jobs("reviving pid %d\n", pi->cmds[i].pid); + pi->cmds[i].is_stopped = 0; } - pi->stopped_progs = 0; + pi->stopped_cmds = 0; i = kill(- pi->pgrp, SIGCONT); if (i < 0) { @@ -4455,7 +4459,7 @@ static int builtin_jobs(char **argv UNUSED_PARAM) const char *status_string; for (job = G.job_list; job; job = job->next) { - if (job->alive_progs == job->stopped_progs) + if (job->alive_cmds == job->stopped_cmds) status_string = "Stopped"; else status_string = "Running"; -- 2.25.1