diff options
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/hush.c | 347 |
1 files changed, 308 insertions, 39 deletions
diff --git a/shell/hush.c b/shell/hush.c index 27afd3e7c..08b3b295f 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -116,6 +116,10 @@ | |||
| 116 | #undef CONFIG_FEATURE_SH_FANCY_PROMPT | 116 | #undef CONFIG_FEATURE_SH_FANCY_PROMPT |
| 117 | #define BB_BANNER | 117 | #define BB_BANNER |
| 118 | #endif | 118 | #endif |
| 119 | #define SPECIAL_VAR_SYMBOL 03 | ||
| 120 | #define FLAG_EXIT_FROM_LOOP 1 | ||
| 121 | #define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */ | ||
| 122 | #define FLAG_REPARSING (1 << 2) /* >=2nd pass */ | ||
| 119 | 123 | ||
| 120 | typedef enum { | 124 | typedef enum { |
| 121 | REDIRECT_INPUT = 1, | 125 | REDIRECT_INPUT = 1, |
| @@ -157,7 +161,8 @@ typedef enum { | |||
| 157 | RES_DO = 9, | 161 | RES_DO = 9, |
| 158 | RES_DONE = 10, | 162 | RES_DONE = 10, |
| 159 | RES_XXXX = 11, | 163 | RES_XXXX = 11, |
| 160 | RES_SNTX = 12 | 164 | RES_IN = 12, |
| 165 | RES_SNTX = 13 | ||
| 161 | } reserved_style; | 166 | } reserved_style; |
| 162 | #define FLAG_END (1<<RES_NONE) | 167 | #define FLAG_END (1<<RES_NONE) |
| 163 | #define FLAG_IF (1<<RES_IF) | 168 | #define FLAG_IF (1<<RES_IF) |
| @@ -170,6 +175,7 @@ typedef enum { | |||
| 170 | #define FLAG_UNTIL (1<<RES_UNTIL) | 175 | #define FLAG_UNTIL (1<<RES_UNTIL) |
| 171 | #define FLAG_DO (1<<RES_DO) | 176 | #define FLAG_DO (1<<RES_DO) |
| 172 | #define FLAG_DONE (1<<RES_DONE) | 177 | #define FLAG_DONE (1<<RES_DONE) |
| 178 | #define FLAG_IN (1<<RES_IN) | ||
| 173 | #define FLAG_START (1<<RES_XXXX) | 179 | #define FLAG_START (1<<RES_XXXX) |
| 174 | 180 | ||
| 175 | /* This holds pointers to the various results of parsing */ | 181 | /* This holds pointers to the various results of parsing */ |
| @@ -181,6 +187,7 @@ struct p_context { | |||
| 181 | reserved_style w; | 187 | reserved_style w; |
| 182 | int old_flag; /* for figuring out valid reserved words */ | 188 | int old_flag; /* for figuring out valid reserved words */ |
| 183 | struct p_context *stack; | 189 | struct p_context *stack; |
| 190 | int type; /* define type of parser : ";$" common or special symbol */ | ||
| 184 | /* How about quoting status? */ | 191 | /* How about quoting status? */ |
| 185 | }; | 192 | }; |
| 186 | 193 | ||
| @@ -201,6 +208,8 @@ struct child_prog { | |||
| 201 | glob_t glob_result; /* result of parameter globbing */ | 208 | glob_t glob_result; /* result of parameter globbing */ |
| 202 | int is_stopped; /* is the program currently running? */ | 209 | int is_stopped; /* is the program currently running? */ |
| 203 | struct pipe *family; /* pointer back to the child's parent pipe */ | 210 | struct pipe *family; /* pointer back to the child's parent pipe */ |
| 211 | int sp; /* number of SPECIAL_VAR_SYMBOL */ | ||
| 212 | int type; | ||
| 204 | }; | 213 | }; |
| 205 | 214 | ||
| 206 | struct pipe { | 215 | struct pipe { |
| @@ -319,6 +328,7 @@ static void __syntax(char *file, int line) { | |||
| 319 | /* function prototypes for builtins */ | 328 | /* function prototypes for builtins */ |
| 320 | static int builtin_cd(struct child_prog *child); | 329 | static int builtin_cd(struct child_prog *child); |
| 321 | static int builtin_env(struct child_prog *child); | 330 | static int builtin_env(struct child_prog *child); |
| 331 | static int builtin_eval(struct child_prog *child); | ||
| 322 | static int builtin_exec(struct child_prog *child); | 332 | static int builtin_exec(struct child_prog *child); |
| 323 | static int builtin_exit(struct child_prog *child); | 333 | static int builtin_exit(struct child_prog *child); |
| 324 | static int builtin_export(struct child_prog *child); | 334 | static int builtin_export(struct child_prog *child); |
| @@ -376,19 +386,22 @@ static int redirect_dup_num(struct in_str *input); | |||
| 376 | static int redirect_opt_num(o_string *o); | 386 | static int redirect_opt_num(o_string *o); |
| 377 | static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end); | 387 | static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end); |
| 378 | static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); | 388 | static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); |
| 379 | static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src); | 389 | static char *lookup_param(char *src); |
| 390 | static char *make_string(char **inp); | ||
| 380 | static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); | 391 | static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); |
| 381 | static int parse_string(o_string *dest, struct p_context *ctx, const char *src); | 392 | static int parse_string(o_string *dest, struct p_context *ctx, const char *src); |
| 382 | static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger); | 393 | static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger); |
| 383 | /* setup: */ | 394 | /* setup: */ |
| 384 | static int parse_stream_outer(struct in_str *inp); | 395 | static int parse_stream_outer(struct in_str *inp, int flag); |
| 385 | static int parse_string_outer(const char *s); | 396 | static int parse_string_outer(const char *s, int flag); |
| 386 | static int parse_file_outer(FILE *f); | 397 | static int parse_file_outer(FILE *f); |
| 387 | /* job management: */ | 398 | /* job management: */ |
| 388 | static int checkjobs(struct pipe* fg_pipe); | 399 | static int checkjobs(struct pipe* fg_pipe); |
| 389 | static void insert_bg_job(struct pipe *pi); | 400 | static void insert_bg_job(struct pipe *pi); |
| 390 | static void remove_bg_job(struct pipe *pi); | 401 | static void remove_bg_job(struct pipe *pi); |
| 391 | /* local variable support */ | 402 | /* local variable support */ |
| 403 | static char **make_list_in(char **inp, char *name); | ||
| 404 | static char *insert_var_value(char *inp); | ||
| 392 | static char *get_local_var(const char *var); | 405 | static char *get_local_var(const char *var); |
| 393 | static void unset_local_var(const char *name); | 406 | static void unset_local_var(const char *name); |
| 394 | static int set_local_var(const char *s, int flg_export); | 407 | static int set_local_var(const char *s, int flg_export); |
| @@ -405,7 +418,7 @@ static struct built_in_command bltins[] = { | |||
| 405 | {"cd", "Change working directory", builtin_cd}, | 418 | {"cd", "Change working directory", builtin_cd}, |
| 406 | {"continue", "Continue for, while or until loop", builtin_not_written}, | 419 | {"continue", "Continue for, while or until loop", builtin_not_written}, |
| 407 | {"env", "Print all environment variables", builtin_env}, | 420 | {"env", "Print all environment variables", builtin_env}, |
| 408 | {"eval", "Construct and run shell command", builtin_not_written}, | 421 | {"eval", "Construct and run shell command", builtin_eval}, |
| 409 | {"exec", "Exec command, replacing this shell with the exec'd process", | 422 | {"exec", "Exec command, replacing this shell with the exec'd process", |
| 410 | builtin_exec}, | 423 | builtin_exec}, |
| 411 | {"exit", "Exit from shell()", builtin_exit}, | 424 | {"exit", "Exit from shell()", builtin_exit}, |
| @@ -436,6 +449,21 @@ static const char *set_cwd(void) | |||
| 436 | return cwd; | 449 | return cwd; |
| 437 | } | 450 | } |
| 438 | 451 | ||
| 452 | /* built-in 'eval' handler */ | ||
| 453 | static int builtin_eval(struct child_prog *child) | ||
| 454 | { | ||
| 455 | char *str = NULL; | ||
| 456 | int rcode = EXIT_SUCCESS; | ||
| 457 | |||
| 458 | if (child->argv[1]) { | ||
| 459 | str = make_string(child->argv + 1); | ||
| 460 | parse_string_outer(str, FLAG_EXIT_FROM_LOOP | | ||
| 461 | FLAG_PARSE_SEMICOLON); | ||
| 462 | free(str); | ||
| 463 | rcode = last_return_code; | ||
| 464 | } | ||
| 465 | return rcode; | ||
| 466 | } | ||
| 439 | 467 | ||
| 440 | /* built-in 'cd <path>' handler */ | 468 | /* built-in 'cd <path>' handler */ |
| 441 | static int builtin_cd(struct child_prog *child) | 469 | static int builtin_cd(struct child_prog *child) |
| @@ -1046,11 +1074,14 @@ static void restore_redirects(int squirrel[]) | |||
| 1046 | static void pseudo_exec(struct child_prog *child) | 1074 | static void pseudo_exec(struct child_prog *child) |
| 1047 | { | 1075 | { |
| 1048 | int i, rcode; | 1076 | int i, rcode; |
| 1077 | char *p; | ||
| 1049 | struct built_in_command *x; | 1078 | struct built_in_command *x; |
| 1050 | if (child->argv) { | 1079 | if (child->argv) { |
| 1051 | for (i=0; is_assignment(child->argv[i]); i++) { | 1080 | for (i=0; is_assignment(child->argv[i]); i++) { |
| 1052 | debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]); | 1081 | debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]); |
| 1053 | putenv(strdup(child->argv[i])); | 1082 | p = insert_var_value(child->argv[i]); |
| 1083 | putenv(strdup(p)); | ||
| 1084 | if (p != child->argv[i]) free(p); | ||
| 1054 | } | 1085 | } |
| 1055 | child->argv+=i; /* XXX this hack isn't so horrible, since we are about | 1086 | child->argv+=i; /* XXX this hack isn't so horrible, since we are about |
| 1056 | to exit, and therefore don't need to keep data | 1087 | to exit, and therefore don't need to keep data |
| @@ -1317,6 +1348,7 @@ static int run_pipe_real(struct pipe *pi) | |||
| 1317 | int pipefds[2]; /* pipefds[0] is for reading */ | 1348 | int pipefds[2]; /* pipefds[0] is for reading */ |
| 1318 | struct child_prog *child; | 1349 | struct child_prog *child; |
| 1319 | struct built_in_command *x; | 1350 | struct built_in_command *x; |
| 1351 | char *p; | ||
| 1320 | 1352 | ||
| 1321 | nextin = 0; | 1353 | nextin = 0; |
| 1322 | pi->pgrp = -1; | 1354 | pi->pgrp = -1; |
| @@ -1359,10 +1391,28 @@ static int run_pipe_real(struct pipe *pi) | |||
| 1359 | export_me=1; | 1391 | export_me=1; |
| 1360 | } | 1392 | } |
| 1361 | free(name); | 1393 | free(name); |
| 1362 | set_local_var(child->argv[i], export_me); | 1394 | p = insert_var_value(child->argv[i]); |
| 1395 | set_local_var(p, export_me); | ||
| 1396 | if (p != child->argv[i]) free(p); | ||
| 1363 | } | 1397 | } |
| 1364 | return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ | 1398 | return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ |
| 1365 | } | 1399 | } |
| 1400 | for (i = 0; is_assignment(child->argv[i]); i++) { | ||
| 1401 | p = insert_var_value(child->argv[i]); | ||
| 1402 | putenv(strdup(p)); | ||
| 1403 | if (p != child->argv[i]) { | ||
| 1404 | child->sp--; | ||
| 1405 | free(p); | ||
| 1406 | } | ||
| 1407 | } | ||
| 1408 | if (child->sp) { | ||
| 1409 | char * str = NULL; | ||
| 1410 | |||
| 1411 | str = make_string((child->argv + i)); | ||
| 1412 | parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING); | ||
| 1413 | free(str); | ||
| 1414 | return last_return_code; | ||
| 1415 | } | ||
| 1366 | for (x = bltins; x->cmd; x++) { | 1416 | for (x = bltins; x->cmd; x++) { |
| 1367 | if (strcmp(child->argv[i], x->cmd) == 0 ) { | 1417 | if (strcmp(child->argv[i], x->cmd) == 0 ) { |
| 1368 | int squirrel[] = {-1, -1, -1}; | 1418 | int squirrel[] = {-1, -1, -1}; |
| @@ -1378,9 +1428,6 @@ static int run_pipe_real(struct pipe *pi) | |||
| 1378 | * Is it really safe for inline use? Experimentally, | 1428 | * Is it really safe for inline use? Experimentally, |
| 1379 | * things seem to work with glibc. */ | 1429 | * things seem to work with glibc. */ |
| 1380 | setup_redirects(child, squirrel); | 1430 | setup_redirects(child, squirrel); |
| 1381 | for (i=0; is_assignment(child->argv[i]); i++) { | ||
| 1382 | putenv(strdup(child->argv[i])); | ||
| 1383 | } | ||
| 1384 | child->argv+=i; /* XXX horrible hack */ | 1431 | child->argv+=i; /* XXX horrible hack */ |
| 1385 | rcode = x->function(child); | 1432 | rcode = x->function(child); |
| 1386 | child->argv-=i; /* XXX restore hack so free() can work right */ | 1433 | child->argv-=i; /* XXX restore hack so free() can work right */ |
| @@ -1474,19 +1521,97 @@ static int run_pipe_real(struct pipe *pi) | |||
| 1474 | 1521 | ||
| 1475 | static int run_list_real(struct pipe *pi) | 1522 | static int run_list_real(struct pipe *pi) |
| 1476 | { | 1523 | { |
| 1477 | int rcode=0; | 1524 | char *save_name = NULL; |
| 1525 | char **list = NULL; | ||
| 1526 | char **save_list = NULL; | ||
| 1527 | struct pipe *rpipe; | ||
| 1528 | int flag_rep = 0; | ||
| 1529 | int save_num_progs; | ||
| 1530 | int rcode=0, flag_skip=1; | ||
| 1531 | int flag_restore = 0; | ||
| 1478 | int if_code=0, next_if_code=0; /* need double-buffer to handle elif */ | 1532 | int if_code=0, next_if_code=0; /* need double-buffer to handle elif */ |
| 1479 | reserved_style rmode, skip_more_in_this_rmode=RES_XXXX; | 1533 | reserved_style rmode, skip_more_in_this_rmode=RES_XXXX; |
| 1480 | for (;pi;pi=pi->next) { | 1534 | /* check syntax for "for" */ |
| 1535 | for (rpipe = pi; rpipe; rpipe = rpipe->next) { | ||
| 1536 | if ((rpipe->r_mode == RES_IN || | ||
| 1537 | rpipe->r_mode == RES_FOR) && | ||
| 1538 | (rpipe->next == NULL)) { | ||
| 1539 | syntax(); | ||
| 1540 | return 1; | ||
| 1541 | } | ||
| 1542 | if ((rpipe->r_mode == RES_IN && | ||
| 1543 | (rpipe->next->r_mode == RES_IN && | ||
| 1544 | rpipe->next->progs->argv != NULL))|| | ||
| 1545 | (rpipe->r_mode == RES_FOR && | ||
| 1546 | rpipe->next->r_mode != RES_IN)) { | ||
| 1547 | syntax(); | ||
| 1548 | return 1; | ||
| 1549 | } | ||
| 1550 | } | ||
| 1551 | for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) { | ||
| 1552 | if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL || | ||
| 1553 | pi->r_mode == RES_FOR) { | ||
| 1554 | flag_restore = 0; | ||
| 1555 | if (!rpipe) { | ||
| 1556 | flag_rep = 0; | ||
| 1557 | rpipe = pi; | ||
| 1558 | } | ||
| 1559 | } | ||
| 1481 | rmode = pi->r_mode; | 1560 | rmode = pi->r_mode; |
| 1482 | debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode); | 1561 | debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode); |
| 1483 | if (rmode == skip_more_in_this_rmode) continue; | 1562 | if (rmode == skip_more_in_this_rmode && flag_skip) { |
| 1563 | if (pi->followup == PIPE_SEQ) flag_skip=0; | ||
| 1564 | continue; | ||
| 1565 | } | ||
| 1566 | flag_skip = 1; | ||
| 1484 | skip_more_in_this_rmode = RES_XXXX; | 1567 | skip_more_in_this_rmode = RES_XXXX; |
| 1485 | if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code; | 1568 | if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code; |
| 1486 | if (rmode == RES_THEN && if_code) continue; | 1569 | if (rmode == RES_THEN && if_code) continue; |
| 1487 | if (rmode == RES_ELSE && !if_code) continue; | 1570 | if (rmode == RES_ELSE && !if_code) continue; |
| 1488 | if (rmode == RES_ELIF && !if_code) continue; | 1571 | if (rmode == RES_ELIF && !if_code) continue; |
| 1572 | if (rmode == RES_FOR && pi->num_progs) { | ||
| 1573 | if (!list) { | ||
| 1574 | /* if no variable values after "in" we skip "for" */ | ||
| 1575 | if (!pi->next->progs->argv) continue; | ||
| 1576 | /* create list of variable values */ | ||
| 1577 | list = make_list_in(pi->next->progs->argv, | ||
| 1578 | pi->progs->argv[0]); | ||
| 1579 | save_list = list; | ||
| 1580 | save_name = pi->progs->argv[0]; | ||
| 1581 | pi->progs->argv[0] = NULL; | ||
| 1582 | flag_rep = 1; | ||
| 1583 | } | ||
| 1584 | if (!(*list)) { | ||
| 1585 | free(pi->progs->argv[0]); | ||
| 1586 | free(save_list); | ||
| 1587 | list = NULL; | ||
| 1588 | flag_rep = 0; | ||
| 1589 | pi->progs->argv[0] = save_name; | ||
| 1590 | pi->progs->glob_result.gl_pathv[0] = | ||
| 1591 | pi->progs->argv[0]; | ||
| 1592 | continue; | ||
| 1593 | } else { | ||
| 1594 | /* insert new value from list for variable */ | ||
| 1595 | if (pi->progs->argv[0]) | ||
| 1596 | free(pi->progs->argv[0]); | ||
| 1597 | pi->progs->argv[0] = *list++; | ||
| 1598 | pi->progs->glob_result.gl_pathv[0] = | ||
| 1599 | pi->progs->argv[0]; | ||
| 1600 | } | ||
| 1601 | } | ||
| 1602 | if (rmode == RES_IN) continue; | ||
| 1603 | if (rmode == RES_DO) { | ||
| 1604 | if (!flag_rep) continue; | ||
| 1605 | } | ||
| 1606 | if ((rmode == RES_DONE)) { | ||
| 1607 | if (flag_rep) { | ||
| 1608 | flag_restore = 1; | ||
| 1609 | } else { | ||
| 1610 | rpipe = NULL; | ||
| 1611 | } | ||
| 1612 | } | ||
| 1489 | if (pi->num_progs == 0) continue; | 1613 | if (pi->num_progs == 0) continue; |
| 1614 | save_num_progs = pi->num_progs; /* save number of programs */ | ||
| 1490 | rcode = run_pipe_real(pi); | 1615 | rcode = run_pipe_real(pi); |
| 1491 | debug_printf("run_pipe_real returned %d\n",rcode); | 1616 | debug_printf("run_pipe_real returned %d\n",rcode); |
| 1492 | if (rcode!=-1) { | 1617 | if (rcode!=-1) { |
| @@ -1513,8 +1638,13 @@ static int run_list_real(struct pipe *pi) | |||
| 1513 | debug_printf("checkjobs returned %d\n",rcode); | 1638 | debug_printf("checkjobs returned %d\n",rcode); |
| 1514 | } | 1639 | } |
| 1515 | last_return_code=rcode; | 1640 | last_return_code=rcode; |
| 1641 | pi->num_progs = save_num_progs; /* restore number of programs */ | ||
| 1516 | if ( rmode == RES_IF || rmode == RES_ELIF ) | 1642 | if ( rmode == RES_IF || rmode == RES_ELIF ) |
| 1517 | next_if_code=rcode; /* can be overwritten a number of times */ | 1643 | next_if_code=rcode; /* can be overwritten a number of times */ |
| 1644 | if (rmode == RES_WHILE) | ||
| 1645 | flag_rep = !last_return_code; | ||
| 1646 | if (rmode == RES_UNTIL) | ||
| 1647 | flag_rep = last_return_code; | ||
| 1518 | if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) || | 1648 | if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) || |
| 1519 | (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) ) | 1649 | (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) ) |
| 1520 | skip_more_in_this_rmode=rmode; | 1650 | skip_more_in_this_rmode=rmode; |
| @@ -1898,6 +2028,7 @@ static void initialize_context(struct p_context *ctx) | |||
| 1898 | ctx->pipe=ctx->list_head; | 2028 | ctx->pipe=ctx->list_head; |
| 1899 | ctx->w=RES_NONE; | 2029 | ctx->w=RES_NONE; |
| 1900 | ctx->stack=NULL; | 2030 | ctx->stack=NULL; |
| 2031 | ctx->old_flag=0; | ||
| 1901 | done_command(ctx); /* creates the memory for working child */ | 2032 | done_command(ctx); /* creates the memory for working child */ |
| 1902 | } | 2033 | } |
| 1903 | 2034 | ||
| @@ -1924,9 +2055,10 @@ int reserved_word(o_string *dest, struct p_context *ctx) | |||
| 1924 | { "elif", RES_ELIF, FLAG_THEN }, | 2055 | { "elif", RES_ELIF, FLAG_THEN }, |
| 1925 | { "else", RES_ELSE, FLAG_FI }, | 2056 | { "else", RES_ELSE, FLAG_FI }, |
| 1926 | { "fi", RES_FI, FLAG_END }, | 2057 | { "fi", RES_FI, FLAG_END }, |
| 1927 | { "for", RES_FOR, FLAG_DO | FLAG_START }, | 2058 | { "for", RES_FOR, FLAG_IN | FLAG_START }, |
| 1928 | { "while", RES_WHILE, FLAG_DO | FLAG_START }, | 2059 | { "while", RES_WHILE, FLAG_DO | FLAG_START }, |
| 1929 | { "until", RES_UNTIL, FLAG_DO | FLAG_START }, | 2060 | { "until", RES_UNTIL, FLAG_DO | FLAG_START }, |
| 2061 | { "in", RES_IN, FLAG_DO }, | ||
| 1930 | { "do", RES_DO, FLAG_DONE }, | 2062 | { "do", RES_DO, FLAG_DONE }, |
| 1931 | { "done", RES_DONE, FLAG_END } | 2063 | { "done", RES_DONE, FLAG_END } |
| 1932 | }; | 2064 | }; |
| @@ -1939,13 +2071,20 @@ int reserved_word(o_string *dest, struct p_context *ctx) | |||
| 1939 | if (r->flag & FLAG_START) { | 2071 | if (r->flag & FLAG_START) { |
| 1940 | struct p_context *new = xmalloc(sizeof(struct p_context)); | 2072 | struct p_context *new = xmalloc(sizeof(struct p_context)); |
| 1941 | debug_printf("push stack\n"); | 2073 | debug_printf("push stack\n"); |
| 2074 | if (ctx->w == RES_IN || ctx->w == RES_FOR) { | ||
| 2075 | syntax(); | ||
| 2076 | free(new); | ||
| 2077 | ctx->w = RES_SNTX; | ||
| 2078 | b_reset(dest); | ||
| 2079 | return 1; | ||
| 2080 | } | ||
| 1942 | *new = *ctx; /* physical copy */ | 2081 | *new = *ctx; /* physical copy */ |
| 1943 | initialize_context(ctx); | 2082 | initialize_context(ctx); |
| 1944 | ctx->stack=new; | 2083 | ctx->stack=new; |
| 1945 | } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) { | 2084 | } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) { |
| 1946 | syntax(); | 2085 | syntax(); |
| 1947 | ctx->w = RES_SNTX; | 2086 | ctx->w = RES_SNTX; |
| 1948 | b_reset (dest); | 2087 | b_reset(dest); |
| 1949 | return 1; | 2088 | return 1; |
| 1950 | } | 2089 | } |
| 1951 | ctx->w=r->code; | 2090 | ctx->w=r->code; |
| @@ -1953,6 +2092,7 @@ int reserved_word(o_string *dest, struct p_context *ctx) | |||
| 1953 | if (ctx->old_flag & FLAG_END) { | 2092 | if (ctx->old_flag & FLAG_END) { |
| 1954 | struct p_context *old; | 2093 | struct p_context *old; |
| 1955 | debug_printf("pop stack\n"); | 2094 | debug_printf("pop stack\n"); |
| 2095 | done_pipe(ctx,PIPE_SEQ); | ||
| 1956 | old = ctx->stack; | 2096 | old = ctx->stack; |
| 1957 | old->child->group = ctx->list_head; | 2097 | old->child->group = ctx->list_head; |
| 1958 | old->child->subshell = 0; | 2098 | old->child->subshell = 0; |
| @@ -1986,7 +2126,7 @@ static int done_word(o_string *dest, struct p_context *ctx) | |||
| 1986 | syntax(); | 2126 | syntax(); |
| 1987 | return 1; /* syntax error, groups and arglists don't mix */ | 2127 | return 1; /* syntax error, groups and arglists don't mix */ |
| 1988 | } | 2128 | } |
| 1989 | if (!child->argv) { | 2129 | if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) { |
| 1990 | debug_printf("checking %s for reserved-ness\n",dest->data); | 2130 | debug_printf("checking %s for reserved-ness\n",dest->data); |
| 1991 | if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX; | 2131 | if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX; |
| 1992 | } | 2132 | } |
| @@ -2006,6 +2146,10 @@ static int done_word(o_string *dest, struct p_context *ctx) | |||
| 2006 | } else { | 2146 | } else { |
| 2007 | child->argv = glob_target->gl_pathv; | 2147 | child->argv = glob_target->gl_pathv; |
| 2008 | } | 2148 | } |
| 2149 | if (ctx->w == RES_FOR) { | ||
| 2150 | done_word(dest,ctx); | ||
| 2151 | done_pipe(ctx,PIPE_SEQ); | ||
| 2152 | } | ||
| 2009 | return 0; | 2153 | return 0; |
| 2010 | } | 2154 | } |
| 2011 | 2155 | ||
| @@ -2041,8 +2185,10 @@ static int done_command(struct p_context *ctx) | |||
| 2041 | prog->group = NULL; | 2185 | prog->group = NULL; |
| 2042 | prog->glob_result.gl_pathv = NULL; | 2186 | prog->glob_result.gl_pathv = NULL; |
| 2043 | prog->family = pi; | 2187 | prog->family = pi; |
| 2188 | prog->sp = 0; | ||
| 2189 | ctx->child = prog; | ||
| 2190 | prog->type = ctx->type; | ||
| 2044 | 2191 | ||
| 2045 | ctx->child=prog; | ||
| 2046 | /* but ctx->pipe and ctx->list_head remain unchanged */ | 2192 | /* but ctx->pipe and ctx->list_head remain unchanged */ |
| 2047 | return 0; | 2193 | return 0; |
| 2048 | } | 2194 | } |
| @@ -2227,32 +2373,32 @@ static int parse_group(o_string *dest, struct p_context *ctx, | |||
| 2227 | 2373 | ||
| 2228 | /* basically useful version until someone wants to get fancier, | 2374 | /* basically useful version until someone wants to get fancier, |
| 2229 | * see the bash man page under "Parameter Expansion" */ | 2375 | * see the bash man page under "Parameter Expansion" */ |
| 2230 | static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src) | 2376 | static char *lookup_param(char *src) |
| 2231 | { | 2377 | { |
| 2232 | const char *p=NULL; | 2378 | char *p=NULL; |
| 2233 | if (src->data) { | 2379 | if (src) { |
| 2234 | p = getenv(src->data); | 2380 | p = getenv(src); |
| 2235 | if (!p) | 2381 | if (!p) |
| 2236 | p = get_local_var(src->data); | 2382 | p = get_local_var(src); |
| 2237 | } | 2383 | } |
| 2238 | if (p) parse_string(dest, ctx, p); /* recursion */ | 2384 | return p; |
| 2239 | b_free(src); | ||
| 2240 | } | 2385 | } |
| 2241 | 2386 | ||
| 2242 | /* return code: 0 for OK, 1 for syntax error */ | 2387 | /* return code: 0 for OK, 1 for syntax error */ |
| 2243 | static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input) | 2388 | static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input) |
| 2244 | { | 2389 | { |
| 2245 | int i, advance=0; | 2390 | int i, advance=0; |
| 2246 | o_string alt=NULL_O_STRING; | ||
| 2247 | char sep[]=" "; | 2391 | char sep[]=" "; |
| 2248 | int ch = input->peek(input); /* first character after the $ */ | 2392 | int ch = input->peek(input); /* first character after the $ */ |
| 2249 | debug_printf("handle_dollar: ch=%c\n",ch); | 2393 | debug_printf("handle_dollar: ch=%c\n",ch); |
| 2250 | if (isalpha(ch)) { | 2394 | if (isalpha(ch)) { |
| 2395 | b_addchr(dest, SPECIAL_VAR_SYMBOL); | ||
| 2396 | ctx->child->sp++; | ||
| 2251 | while(ch=b_peek(input),isalnum(ch) || ch=='_') { | 2397 | while(ch=b_peek(input),isalnum(ch) || ch=='_') { |
| 2252 | b_getch(input); | 2398 | b_getch(input); |
| 2253 | b_addchr(&alt,ch); | 2399 | b_addchr(dest,ch); |
| 2254 | } | 2400 | } |
| 2255 | lookup_param(dest, ctx, &alt); | 2401 | b_addchr(dest, SPECIAL_VAR_SYMBOL); |
| 2256 | } else if (isdigit(ch)) { | 2402 | } else if (isdigit(ch)) { |
| 2257 | i = ch-'0'; /* XXX is $0 special? */ | 2403 | i = ch-'0'; /* XXX is $0 special? */ |
| 2258 | if (i<global_argc) { | 2404 | if (i<global_argc) { |
| @@ -2277,16 +2423,18 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i | |||
| 2277 | advance = 1; | 2423 | advance = 1; |
| 2278 | break; | 2424 | break; |
| 2279 | case '{': | 2425 | case '{': |
| 2426 | b_addchr(dest, SPECIAL_VAR_SYMBOL); | ||
| 2427 | ctx->child->sp++; | ||
| 2280 | b_getch(input); | 2428 | b_getch(input); |
| 2281 | /* XXX maybe someone will try to escape the '}' */ | 2429 | /* XXX maybe someone will try to escape the '}' */ |
| 2282 | while(ch=b_getch(input),ch!=EOF && ch!='}') { | 2430 | while(ch=b_getch(input),ch!=EOF && ch!='}') { |
| 2283 | b_addchr(&alt,ch); | 2431 | b_addchr(dest,ch); |
| 2284 | } | 2432 | } |
| 2285 | if (ch != '}') { | 2433 | if (ch != '}') { |
| 2286 | syntax(); | 2434 | syntax(); |
| 2287 | return 1; | 2435 | return 1; |
| 2288 | } | 2436 | } |
| 2289 | lookup_param(dest, ctx, &alt); | 2437 | b_addchr(dest, SPECIAL_VAR_SYMBOL); |
| 2290 | break; | 2438 | break; |
| 2291 | case '(': | 2439 | case '(': |
| 2292 | b_getch(input); | 2440 | b_getch(input); |
| @@ -2348,7 +2496,9 @@ int parse_stream(o_string *dest, struct p_context *ctx, | |||
| 2348 | b_addqchr(dest, ch, dest->quote); | 2496 | b_addqchr(dest, ch, dest->quote); |
| 2349 | } else { | 2497 | } else { |
| 2350 | if (m==2) { /* unquoted IFS */ | 2498 | if (m==2) { /* unquoted IFS */ |
| 2351 | done_word(dest, ctx); | 2499 | if (done_word(dest, ctx)) { |
| 2500 | return 1; | ||
| 2501 | } | ||
| 2352 | /* If we aren't performing a substitution, treat a newline as a | 2502 | /* If we aren't performing a substitution, treat a newline as a |
| 2353 | * command separator. */ | 2503 | * command separator. */ |
| 2354 | if (end_trigger != '\0' && ch=='\n') | 2504 | if (end_trigger != '\0' && ch=='\n') |
| @@ -2509,30 +2659,46 @@ void update_ifs_map(void) | |||
| 2509 | 2659 | ||
| 2510 | /* most recursion does not come through here, the exeception is | 2660 | /* most recursion does not come through here, the exeception is |
| 2511 | * from builtin_source() */ | 2661 | * from builtin_source() */ |
| 2512 | int parse_stream_outer(struct in_str *inp) | 2662 | int parse_stream_outer(struct in_str *inp, int flag) |
| 2513 | { | 2663 | { |
| 2514 | 2664 | ||
| 2515 | struct p_context ctx; | 2665 | struct p_context ctx; |
| 2516 | o_string temp=NULL_O_STRING; | 2666 | o_string temp=NULL_O_STRING; |
| 2517 | int rcode; | 2667 | int rcode; |
| 2518 | do { | 2668 | do { |
| 2669 | ctx.type = flag; | ||
| 2519 | initialize_context(&ctx); | 2670 | initialize_context(&ctx); |
| 2520 | update_ifs_map(); | 2671 | update_ifs_map(); |
| 2672 | if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset(";$&|", 0); | ||
| 2521 | inp->promptmode=1; | 2673 | inp->promptmode=1; |
| 2522 | rcode = parse_stream(&temp, &ctx, inp, '\n'); | 2674 | rcode = parse_stream(&temp, &ctx, inp, '\n'); |
| 2523 | done_word(&temp, &ctx); | 2675 | if (rcode != 1 && ctx.old_flag != 0) { |
| 2524 | done_pipe(&ctx,PIPE_SEQ); | 2676 | syntax(); |
| 2525 | run_list(ctx.list_head); | 2677 | } |
| 2678 | if (rcode != 1 && ctx.old_flag == 0) { | ||
| 2679 | done_word(&temp, &ctx); | ||
| 2680 | done_pipe(&ctx,PIPE_SEQ); | ||
| 2681 | run_list(ctx.list_head); | ||
| 2682 | } else { | ||
| 2683 | if (ctx.old_flag != 0) { | ||
| 2684 | free(ctx.stack); | ||
| 2685 | b_reset(&temp); | ||
| 2686 | } | ||
| 2687 | temp.nonnull = 0; | ||
| 2688 | temp.quote = 0; | ||
| 2689 | inp->p = NULL; | ||
| 2690 | free_pipe_list(ctx.list_head,0); | ||
| 2691 | } | ||
| 2526 | b_free(&temp); | 2692 | b_free(&temp); |
| 2527 | } while (rcode != -1); /* loop on syntax errors, return on EOF */ | 2693 | } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ |
| 2528 | return 0; | 2694 | return 0; |
| 2529 | } | 2695 | } |
| 2530 | 2696 | ||
| 2531 | static int parse_string_outer(const char *s) | 2697 | static int parse_string_outer(const char *s, int flag) |
| 2532 | { | 2698 | { |
| 2533 | struct in_str input; | 2699 | struct in_str input; |
| 2534 | setup_string_in_str(&input, s); | 2700 | setup_string_in_str(&input, s); |
| 2535 | return parse_stream_outer(&input); | 2701 | return parse_stream_outer(&input, flag); |
| 2536 | } | 2702 | } |
| 2537 | 2703 | ||
| 2538 | static int parse_file_outer(FILE *f) | 2704 | static int parse_file_outer(FILE *f) |
| @@ -2540,7 +2706,7 @@ static int parse_file_outer(FILE *f) | |||
| 2540 | int rcode; | 2706 | int rcode; |
| 2541 | struct in_str input; | 2707 | struct in_str input; |
| 2542 | setup_file_in_str(&input, f); | 2708 | setup_file_in_str(&input, f); |
| 2543 | rcode = parse_stream_outer(&input); | 2709 | rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON); |
| 2544 | return rcode; | 2710 | return rcode; |
| 2545 | } | 2711 | } |
| 2546 | 2712 | ||
| @@ -2630,7 +2796,7 @@ int hush_main(int argc, char **argv) | |||
| 2630 | { | 2796 | { |
| 2631 | global_argv = argv+optind; | 2797 | global_argv = argv+optind; |
| 2632 | global_argc = argc-optind; | 2798 | global_argc = argc-optind; |
| 2633 | opt = parse_string_outer(optarg); | 2799 | opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON); |
| 2634 | goto final_return; | 2800 | goto final_return; |
| 2635 | } | 2801 | } |
| 2636 | break; | 2802 | break; |
| @@ -2703,3 +2869,106 @@ int hush_main(int argc, char **argv) | |||
| 2703 | final_return: | 2869 | final_return: |
| 2704 | return(opt?opt:last_return_code); | 2870 | return(opt?opt:last_return_code); |
| 2705 | } | 2871 | } |
| 2872 | |||
| 2873 | static char *insert_var_value(char *inp) | ||
| 2874 | { | ||
| 2875 | int res_str_len = 0; | ||
| 2876 | int len; | ||
| 2877 | int done = 0; | ||
| 2878 | char *p, *p1, *res_str = NULL; | ||
| 2879 | |||
| 2880 | while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) { | ||
| 2881 | if (p != inp) { | ||
| 2882 | len = p - inp; | ||
| 2883 | res_str = xrealloc(res_str, (res_str_len + len)); | ||
| 2884 | strncpy((res_str + res_str_len), inp, len); | ||
| 2885 | res_str_len += len; | ||
| 2886 | } | ||
| 2887 | inp = ++p; | ||
| 2888 | p = strchr(inp, SPECIAL_VAR_SYMBOL); | ||
| 2889 | *p = '\0'; | ||
| 2890 | if ((p1 = lookup_param(inp))) { | ||
| 2891 | len = res_str_len + strlen(p1); | ||
| 2892 | res_str = xrealloc(res_str, (1 + len)); | ||
| 2893 | strcpy((res_str + res_str_len), p1); | ||
| 2894 | res_str_len = len; | ||
| 2895 | } | ||
| 2896 | *p = SPECIAL_VAR_SYMBOL; | ||
| 2897 | inp = ++p; | ||
| 2898 | done = 1; | ||
| 2899 | } | ||
| 2900 | if (done) { | ||
| 2901 | res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp))); | ||
| 2902 | strcpy((res_str + res_str_len), inp); | ||
| 2903 | while ((p = strchr(res_str, '\n'))) { | ||
| 2904 | *p = ' '; | ||
| 2905 | } | ||
| 2906 | } | ||
| 2907 | return (res_str == NULL) ? inp : res_str; | ||
| 2908 | } | ||
| 2909 | |||
| 2910 | static char **make_list_in(char **inp, char *name) | ||
| 2911 | { | ||
| 2912 | int len, i; | ||
| 2913 | int name_len = strlen(name); | ||
| 2914 | int n = 0; | ||
| 2915 | char **list; | ||
| 2916 | char *p1, *p2, *p3; | ||
| 2917 | |||
| 2918 | /* create list of variable values */ | ||
| 2919 | list = xmalloc(sizeof(*list)); | ||
| 2920 | for (i = 0; inp[i]; i++) { | ||
| 2921 | p3 = insert_var_value(inp[i]); | ||
| 2922 | p1 = p3; | ||
| 2923 | while (*p1) { | ||
| 2924 | if ((*p1 == ' ')) { | ||
| 2925 | p1++; | ||
| 2926 | continue; | ||
| 2927 | } | ||
| 2928 | if ((p2 = strchr(p1, ' '))) { | ||
| 2929 | len = p2 - p1; | ||
| 2930 | } else { | ||
| 2931 | len = strlen(p1); | ||
| 2932 | p2 = p1 + len; | ||
| 2933 | } | ||
| 2934 | /* we use n + 2 in realloc for list,because we add | ||
| 2935 | * new element and then we will add NULL element */ | ||
| 2936 | list = xrealloc(list, sizeof(*list) * (n + 2)); | ||
| 2937 | list[n] = xmalloc(2 + name_len + len); | ||
| 2938 | strcpy(list[n], name); | ||
| 2939 | strcat(list[n], "="); | ||
| 2940 | strncat(list[n], p1, len); | ||
| 2941 | list[n++][name_len + len + 1] = '\0'; | ||
| 2942 | p1 = p2; | ||
| 2943 | } | ||
| 2944 | if (p3 != inp[i]) free(p3); | ||
| 2945 | } | ||
| 2946 | list[n] = NULL; | ||
| 2947 | return list; | ||
| 2948 | } | ||
| 2949 | |||
| 2950 | /* Make new string for parser */ | ||
| 2951 | static char * make_string(char ** inp) | ||
| 2952 | { | ||
| 2953 | char *p; | ||
| 2954 | char *str = NULL; | ||
| 2955 | int n; | ||
| 2956 | int len = 2; | ||
| 2957 | |||
| 2958 | for (n = 0; inp[n]; n++) { | ||
| 2959 | p = insert_var_value(inp[n]); | ||
| 2960 | str = xrealloc(str, (len + strlen(p))); | ||
| 2961 | if (n) { | ||
| 2962 | strcat(str, " "); | ||
| 2963 | } else { | ||
| 2964 | *str = '\0'; | ||
| 2965 | } | ||
| 2966 | strcat(str, p); | ||
| 2967 | len = strlen(str) + 3; | ||
| 2968 | if (p != inp[n]) free(p); | ||
| 2969 | } | ||
| 2970 | len = strlen(str); | ||
| 2971 | *(str + len) = '\n'; | ||
| 2972 | *(str + len + 1) = '\0'; | ||
| 2973 | return str; | ||
| 2974 | } | ||
