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