diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-15 00:11:22 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-15 00:11:22 +0000 |
| commit | 8f0c89e05a7b52f8c5ae7b451de6fd50732aeb45 (patch) | |
| tree | 9bf309fce9eff03da8980e84d3de5741627bf96d /shell/hush.c | |
| parent | bc7177187f6b4f32c2f9562358294dfc7b521f67 (diff) | |
| download | busybox-w32-1_13_4.tar.gz busybox-w32-1_13_4.tar.bz2 busybox-w32-1_13_4.zip | |
apply post-1.13.3 fixes, bump version to 1.13.41_13_4
Diffstat (limited to 'shell/hush.c')
| -rw-r--r-- | shell/hush.c | 95 |
1 files changed, 82 insertions, 13 deletions
diff --git a/shell/hush.c b/shell/hush.c index 421272971..9e7b10535 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -458,8 +458,11 @@ struct globals { | |||
| 458 | smallint fake_mode; | 458 | smallint fake_mode; |
| 459 | /* these three support $?, $#, and $1 */ | 459 | /* these three support $?, $#, and $1 */ |
| 460 | smalluint last_return_code; | 460 | smalluint last_return_code; |
| 461 | char **global_argv; | 461 | /* is global_argv and global_argv[1..n] malloced? (note: not [0]) */ |
| 462 | smalluint global_args_malloced; | ||
| 463 | /* how many non-NULL argv's we have. NB: $# + 1 */ | ||
| 462 | int global_argc; | 464 | int global_argc; |
| 465 | char **global_argv; | ||
| 463 | #if ENABLE_HUSH_LOOPS | 466 | #if ENABLE_HUSH_LOOPS |
| 464 | unsigned depth_break_continue; | 467 | unsigned depth_break_continue; |
| 465 | unsigned depth_of_loop; | 468 | unsigned depth_of_loop; |
| @@ -633,7 +636,7 @@ static char *unbackslash(char *src) | |||
| 633 | return dst; | 636 | return dst; |
| 634 | } | 637 | } |
| 635 | 638 | ||
| 636 | static char **add_strings_to_strings(char **strings, char **add) | 639 | static char **add_strings_to_strings(char **strings, char **add, int need_to_dup) |
| 637 | { | 640 | { |
| 638 | int i; | 641 | int i; |
| 639 | unsigned count1; | 642 | unsigned count1; |
| @@ -658,7 +661,7 @@ static char **add_strings_to_strings(char **strings, char **add) | |||
| 658 | v[count1 + count2] = NULL; | 661 | v[count1 + count2] = NULL; |
| 659 | i = count2; | 662 | i = count2; |
| 660 | while (--i >= 0) | 663 | while (--i >= 0) |
| 661 | v[count1 + i] = add[i]; | 664 | v[count1 + i] = (need_to_dup ? xstrdup(add[i]) : add[i]); |
| 662 | return v; | 665 | return v; |
| 663 | } | 666 | } |
| 664 | 667 | ||
| @@ -667,7 +670,7 @@ static char **add_string_to_strings(char **strings, char *add) | |||
| 667 | char *v[2]; | 670 | char *v[2]; |
| 668 | v[0] = add; | 671 | v[0] = add; |
| 669 | v[1] = NULL; | 672 | v[1] = NULL; |
| 670 | return add_strings_to_strings(strings, v); | 673 | return add_strings_to_strings(strings, v, /*dup:*/ 0); |
| 671 | } | 674 | } |
| 672 | 675 | ||
| 673 | static void putenv_all(char **strings) | 676 | static void putenv_all(char **strings) |
| @@ -1213,8 +1216,13 @@ static int o_glob(o_string *o, int n) | |||
| 1213 | * Otherwise, just finish current list[] and start new */ | 1216 | * Otherwise, just finish current list[] and start new */ |
| 1214 | static int o_save_ptr(o_string *o, int n) | 1217 | static int o_save_ptr(o_string *o, int n) |
| 1215 | { | 1218 | { |
| 1216 | if (o->o_glob) | 1219 | if (o->o_glob) { /* if globbing is requested */ |
| 1217 | return o_glob(o, n); /* o_save_ptr_helper is inside */ | 1220 | /* If o->has_empty_slot, list[n] was already globbed |
| 1221 | * (if it was requested back then when it was filled) | ||
| 1222 | * so don't do that again! */ | ||
| 1223 | if (!o->has_empty_slot) | ||
| 1224 | return o_glob(o, n); /* o_save_ptr_helper is inside */ | ||
| 1225 | } | ||
| 1218 | return o_save_ptr_helper(o, n); | 1226 | return o_save_ptr_helper(o, n); |
| 1219 | } | 1227 | } |
| 1220 | 1228 | ||
| @@ -4279,6 +4287,11 @@ int hush_main(int argc, char **argv) | |||
| 4279 | switch (opt) { | 4287 | switch (opt) { |
| 4280 | case 'c': | 4288 | case 'c': |
| 4281 | G.global_argv = argv + optind; | 4289 | G.global_argv = argv + optind; |
| 4290 | if (!argv[optind]) { | ||
| 4291 | /* -c 'script' (no params): prevent empty $0 */ | ||
| 4292 | *--G.global_argv = argv[0]; | ||
| 4293 | optind--; | ||
| 4294 | } /* else -c 'script' PAR0 PAR1: $0 is PAR0 */ | ||
| 4282 | G.global_argc = argc - optind; | 4295 | G.global_argc = argc - optind; |
| 4283 | opt = parse_and_run_string(optarg, 0 /* parse_flag */); | 4296 | opt = parse_and_run_string(optarg, 0 /* parse_flag */); |
| 4284 | goto final_return; | 4297 | goto final_return; |
| @@ -4639,17 +4652,68 @@ static int builtin_read(char **argv) | |||
| 4639 | return set_local_var(string, 0); | 4652 | return set_local_var(string, 0); |
| 4640 | } | 4653 | } |
| 4641 | 4654 | ||
| 4642 | /* built-in 'set [VAR=value]' handler */ | 4655 | /* built-in 'set' handler |
| 4656 | * SUSv3 says: | ||
| 4657 | * set [-abCefmnuvx] [-h] [-o option] [argument...] | ||
| 4658 | * set [+abCefmnuvx] [+h] [+o option] [argument...] | ||
| 4659 | * set -- [argument...] | ||
| 4660 | * set -o | ||
| 4661 | * set +o | ||
| 4662 | * Implementations shall support the options in both their hyphen and | ||
| 4663 | * plus-sign forms. These options can also be specified as options to sh. | ||
| 4664 | * Examples: | ||
| 4665 | * Write out all variables and their values: set | ||
| 4666 | * Set $1, $2, and $3 and set "$#" to 3: set c a b | ||
| 4667 | * Turn on the -x and -v options: set -xv | ||
| 4668 | * Unset all positional parameters: set -- | ||
| 4669 | * Set $1 to the value of x, even if it begins with '-' or '+': set -- "$x" | ||
| 4670 | * Set the positional parameters to the expansion of x, even if x expands | ||
| 4671 | * with a leading '-' or '+': set -- $x | ||
| 4672 | * | ||
| 4673 | * So far, we only support "set -- [argument...]" by ignoring all options | ||
| 4674 | * (also, "-o option" will be mishandled by taking "option" as parameter #1). | ||
| 4675 | */ | ||
| 4643 | static int builtin_set(char **argv) | 4676 | static int builtin_set(char **argv) |
| 4644 | { | 4677 | { |
| 4645 | char *temp = argv[1]; | ||
| 4646 | struct variable *e; | 4678 | struct variable *e; |
| 4679 | char **pp; | ||
| 4680 | char *arg = *++argv; | ||
| 4647 | 4681 | ||
| 4648 | if (temp == NULL) | 4682 | if (arg == NULL) { |
| 4649 | for (e = G.top_var; e; e = e->next) | 4683 | for (e = G.top_var; e; e = e->next) |
| 4650 | puts(e->varstr); | 4684 | puts(e->varstr); |
| 4651 | else | 4685 | } else { |
| 4652 | set_local_var(xstrdup(temp), 0); | 4686 | /* NB: G.global_argv[0] ($0) is never freed/changed */ |
| 4687 | |||
| 4688 | if (G.global_args_malloced) { | ||
| 4689 | pp = G.global_argv; | ||
| 4690 | while (*++pp) | ||
| 4691 | free(*pp); | ||
| 4692 | G.global_argv[1] = NULL; | ||
| 4693 | } else { | ||
| 4694 | G.global_args_malloced = 1; | ||
| 4695 | pp = xzalloc(sizeof(pp[0]) * 2); | ||
| 4696 | pp[0] = G.global_argv[0]; /* retain $0 */ | ||
| 4697 | G.global_argv = pp; | ||
| 4698 | } | ||
| 4699 | do { | ||
| 4700 | if (arg[0] == '+') | ||
| 4701 | continue; | ||
| 4702 | if (arg[0] != '-') | ||
| 4703 | break; | ||
| 4704 | if (arg[1] == '-' && arg[2] == '\0') { | ||
| 4705 | argv++; | ||
| 4706 | break; | ||
| 4707 | } | ||
| 4708 | } while ((arg = *++argv) != NULL); | ||
| 4709 | /* Now argv[0] is 1st argument */ | ||
| 4710 | |||
| 4711 | /* This realloc's G.global_argv */ | ||
| 4712 | G.global_argv = pp = add_strings_to_strings(G.global_argv, argv, /*dup:*/ 1); | ||
| 4713 | G.global_argc = 1; | ||
| 4714 | while (*++pp) | ||
| 4715 | G.global_argc++; | ||
| 4716 | } | ||
| 4653 | 4717 | ||
| 4654 | return EXIT_SUCCESS; | 4718 | return EXIT_SUCCESS; |
| 4655 | } | 4719 | } |
| @@ -4661,9 +4725,14 @@ static int builtin_shift(char **argv) | |||
| 4661 | n = atoi(argv[1]); | 4725 | n = atoi(argv[1]); |
| 4662 | } | 4726 | } |
| 4663 | if (n >= 0 && n < G.global_argc) { | 4727 | if (n >= 0 && n < G.global_argc) { |
| 4664 | G.global_argv[n] = G.global_argv[0]; | 4728 | if (G.global_args_malloced) { |
| 4729 | int m = 1; | ||
| 4730 | while (m <= n) | ||
| 4731 | free(G.global_argv[m++]); | ||
| 4732 | } | ||
| 4665 | G.global_argc -= n; | 4733 | G.global_argc -= n; |
| 4666 | G.global_argv += n; | 4734 | memmove(&G.global_argv[1], &G.global_argv[n+1], |
| 4735 | G.global_argc * sizeof(G.global_argv[0])); | ||
| 4667 | return EXIT_SUCCESS; | 4736 | return EXIT_SUCCESS; |
| 4668 | } | 4737 | } |
| 4669 | return EXIT_FAILURE; | 4738 | return EXIT_FAILURE; |
