aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-10 21:22:02 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-10 21:22:02 +0000
commitc0ea329297862003a32570a7a38fa2bcb20e57f1 (patch)
tree7c48bd11a6710c9e2a948bab2faf845bd44b32f0
parentb7d8c0dbbd250649d647142edd33226822f3c879 (diff)
downloadbusybox-w32-c0ea329297862003a32570a7a38fa2bcb20e57f1.tar.gz
busybox-w32-c0ea329297862003a32570a7a38fa2bcb20e57f1.tar.bz2
busybox-w32-c0ea329297862003a32570a7a38fa2bcb20e57f1.zip
hush: fix a few thinkos in function support; make it work on NOMMU;
functions in child shells now even have $n passed to them! :) (in main shell it still doesn't work)
-rw-r--r--shell/hush.c189
1 files changed, 120 insertions, 69 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 3728583fc..dd5031951 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -452,11 +452,16 @@ enum {
452 BC_CONTINUE = 2, 452 BC_CONTINUE = 2,
453}; 453};
454 454
455#if ENABLE_HUSH_FUNCTIONS
455struct function { 456struct function {
456 struct function *next; 457 struct function *next;
457 char *name; 458 char *name;
458 struct pipe *body; 459 struct pipe *body;
460#if !BB_MMU
461 char *body_as_string;
462#endif
459}; 463};
464#endif
460 465
461 466
462/* "Globals" within this file */ 467/* "Globals" within this file */
@@ -510,7 +515,9 @@ struct globals {
510 const char *cwd; 515 const char *cwd;
511 struct variable *top_var; /* = &G.shell_ver (set in main()) */ 516 struct variable *top_var; /* = &G.shell_ver (set in main()) */
512 struct variable shell_ver; 517 struct variable shell_ver;
518#if ENABLE_HUSH_FUNCTIONS
513 struct function *top_func; 519 struct function *top_func;
520#endif
514 /* Signal and trap handling */ 521 /* Signal and trap handling */
515// unsigned count_SIGCHLD; 522// unsigned count_SIGCHLD;
516// unsigned handled_SIGCHLD; 523// unsigned handled_SIGCHLD;
@@ -675,11 +682,12 @@ static void xxfree(void *ptr)
675 * HUSH_DEBUG >= 2 prints line number in this file where it was detected. 682 * HUSH_DEBUG >= 2 prints line number in this file where it was detected.
676 */ 683 */
677#if HUSH_DEBUG < 2 684#if HUSH_DEBUG < 2
678# define die_if_script(lineno, fmt...) die_if_script(fmt) 685# define die_if_script(lineno, fmt...) die_if_script(fmt)
679# define syntax_error(lineno, msg) syntax_error(msg) 686# define syntax_error(lineno, msg) syntax_error(msg)
680# define syntax_error_at(lineno, msg) syntax_error_at(msg) 687# define syntax_error_at(lineno, msg) syntax_error_at(msg)
681# define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch) 688# define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch)
682# define syntax_error_unterm_str(lineno, s) syntax_error_unterm_str(s) 689# define syntax_error_unterm_str(lineno, s) syntax_error_unterm_str(s)
690# define syntax_error_unexpected_ch(lineno, ch) syntax_error_unexpected_ch(ch)
683#endif 691#endif
684 692
685static void die_if_script(unsigned lineno, const char *fmt, ...) 693static void die_if_script(unsigned lineno, const char *fmt, ...)
@@ -729,18 +737,29 @@ static void syntax_error_unterm_str(unsigned lineno, const char *s)
729 die_if_script(lineno, "syntax error: unterminated %s", s); 737 die_if_script(lineno, "syntax error: unterminated %s", s);
730} 738}
731 739
740static void syntax_error_unexpected_ch(unsigned lineno, char ch)
741{
742 char msg[2];
743 msg[0] = ch;
744 msg[1] = '\0';
745 die_if_script(lineno, "syntax error: unexpected %s", msg);
746 xfunc_die();
747}
748
732#if HUSH_DEBUG < 2 749#if HUSH_DEBUG < 2
733# undef die_if_script 750# undef die_if_script
734# undef syntax_error 751# undef syntax_error
735# undef syntax_error_at 752# undef syntax_error_at
736# undef syntax_error_unterm_ch 753# undef syntax_error_unterm_ch
737# undef syntax_error_unterm_str 754# undef syntax_error_unterm_str
755# undef syntax_error_unexpected_ch
738#else 756#else
739# define die_if_script(fmt...) die_if_script(__LINE__, fmt) 757# define die_if_script(fmt...) die_if_script(__LINE__, fmt)
740# define syntax_error(msg) syntax_error(__LINE__, msg) 758# define syntax_error(msg) syntax_error(__LINE__, msg)
741# define syntax_error_at(msg) syntax_error_at(__LINE__, msg) 759# define syntax_error_at(msg) syntax_error_at(__LINE__, msg)
742# define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch) 760# define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch)
743# define syntax_error_unterm_str(s) syntax_error_unterm_str(__LINE__, s) 761# define syntax_error_unterm_str(s) syntax_error_unterm_str(__LINE__, s)
762# define syntax_error_unexpected_ch(ch) syntax_error_unexpected_ch(__LINE__, ch)
744#endif 763#endif
745 764
746 765
@@ -2234,8 +2253,11 @@ static char **expand_assignments(char **argv, int count)
2234 2253
2235 2254
2236#if BB_MMU 2255#if BB_MMU
2237void re_execute_shell(const char *s, int is_heredoc); /* never called */ 2256/* never called */
2257void re_execute_shell(const char *s, char *argv0, char **argv);
2258
2238#define clean_up_after_re_execute() ((void)0) 2259#define clean_up_after_re_execute() ((void)0)
2260
2239static void reset_traps_to_defaults(void) 2261static void reset_traps_to_defaults(void)
2240{ 2262{
2241 unsigned sig; 2263 unsigned sig;
@@ -2266,16 +2288,16 @@ static void reset_traps_to_defaults(void)
2266 2288
2267#else /* !BB_MMU */ 2289#else /* !BB_MMU */
2268 2290
2269static void re_execute_shell(const char *s, int is_heredoc) NORETURN; 2291static void re_execute_shell(const char *s, char *g_argv0, char **g_argv) NORETURN;
2270static void re_execute_shell(const char *s, int is_heredoc) 2292static void re_execute_shell(const char *s, char *g_argv0, char **g_argv)
2271{ 2293{
2272 char param_buf[sizeof("-$%x:%x:%x:%x") + sizeof(unsigned) * 4]; 2294 char param_buf[sizeof("-$%x:%x:%x:%x") + sizeof(unsigned) * 4];
2273 char *heredoc_argv[4]; 2295 char *heredoc_argv[4];
2274 struct variable *cur; 2296 struct variable *cur;
2275 char **argv, **pp, **pp2; 2297 char **argv, **pp;
2276 unsigned cnt; 2298 unsigned cnt;
2277 2299
2278 if (is_heredoc) { 2300 if (!g_argv0) { /* heredoc */
2279 argv = heredoc_argv; 2301 argv = heredoc_argv;
2280 argv[0] = (char *) G.argv0_for_re_execing; 2302 argv[0] = (char *) G.argv0_for_re_execing;
2281 argv[1] = (char *) "-<"; 2303 argv[1] = (char *) "-<";
@@ -2292,13 +2314,16 @@ static void re_execute_shell(const char *s, int is_heredoc)
2292 USE_HUSH_LOOPS(, G.depth_of_loop) 2314 USE_HUSH_LOOPS(, G.depth_of_loop)
2293 ); 2315 );
2294 /* 1:hush 2:-$<pid>:<pid>:<exitcode>:<depth> <vars...> 2316 /* 1:hush 2:-$<pid>:<pid>:<exitcode>:<depth> <vars...>
2295 * 3:-c 4:<cmd> <argN...> 5:NULL 2317 * 3:-c 4:<cmd> 5:<arg0> <argN...> 6:NULL
2296 */ 2318 */
2297 cnt = 5 + G.global_argc; 2319 cnt = 6;
2298 for (cur = G.top_var; cur; cur = cur->next) { 2320 for (cur = G.top_var; cur; cur = cur->next) {
2299 if (!cur->flg_export || cur->flg_read_only) 2321 if (!cur->flg_export || cur->flg_read_only)
2300 cnt += 2; 2322 cnt += 2;
2301 } 2323 }
2324 pp = g_argv;
2325 while (*pp++)
2326 cnt++;
2302 G.argv_from_re_execing = argv = pp = xzalloc(sizeof(argv[0]) * cnt); 2327 G.argv_from_re_execing = argv = pp = xzalloc(sizeof(argv[0]) * cnt);
2303 *pp++ = (char *) G.argv0_for_re_execing; 2328 *pp++ = (char *) G.argv0_for_re_execing;
2304 *pp++ = param_buf; 2329 *pp++ = param_buf;
@@ -2335,9 +2360,9 @@ static void re_execute_shell(const char *s, int is_heredoc)
2335 */ 2360 */
2336 *pp++ = (char *) "-c"; 2361 *pp++ = (char *) "-c";
2337 *pp++ = (char *) s; 2362 *pp++ = (char *) s;
2338 pp2 = G.global_argv; 2363 *pp++ = g_argv0;
2339 while (*pp2) 2364 while (*g_argv)
2340 *pp++ = *pp2++; 2365 *pp++ = *g_argv++;
2341 /* *pp = NULL; - is already there */ 2366 /* *pp = NULL; - is already there */
2342 pp = environ; 2367 pp = environ;
2343 2368
@@ -2426,7 +2451,7 @@ static void setup_heredoc(struct redir_struct *redir)
2426 /* Delegate blocking writes to another process */ 2451 /* Delegate blocking writes to another process */
2427 disable_restore_tty_pgrp_on_exit(); 2452 disable_restore_tty_pgrp_on_exit();
2428 xmove_fd(pair.wr, STDOUT_FILENO); 2453 xmove_fd(pair.wr, STDOUT_FILENO);
2429 re_execute_shell(heredoc, 1); 2454 re_execute_shell(heredoc, NULL, NULL);
2430#endif 2455#endif
2431 } 2456 }
2432 /* parent */ 2457 /* parent */
@@ -2592,6 +2617,8 @@ static void free_pipe_list(struct pipe *head, int indent)
2592} 2617}
2593 2618
2594 2619
2620static int run_list(struct pipe *pi);
2621
2595static const struct built_in_command* find_builtin(const char *name) 2622static const struct built_in_command* find_builtin(const char *name)
2596{ 2623{
2597 const struct built_in_command *x; 2624 const struct built_in_command *x;
@@ -2604,22 +2631,39 @@ static const struct built_in_command* find_builtin(const char *name)
2604 return NULL; 2631 return NULL;
2605} 2632}
2606 2633
2607# if ENABLE_HUSH_FUNCTIONS 2634#if ENABLE_HUSH_FUNCTIONS
2608static const struct function *find_function(const char *name) 2635static const struct function *find_function(const char *name)
2609{ 2636{
2610 const struct function *funcp = G.top_func; 2637 const struct function *funcp = G.top_func;
2611 while (funcp) { 2638 while (funcp) {
2612 if (strcmp(name, funcp->name) != 0) 2639 if (strcmp(name, funcp->name) == 0) {
2613 continue; 2640 break;
2614 return funcp; 2641 }
2615 debug_printf_exec("found function '%s'\n", name); 2642 funcp = funcp->next;
2616 } 2643 }
2617 return NULL; 2644 debug_printf_exec("found function '%s'\n", name);
2645 return funcp;
2618} 2646}
2619#endif 2647static void exec_function(const struct function *funcp, char **argv) NORETURN;
2648static void exec_function(const struct function *funcp, char **argv)
2649{
2650# if BB_MMU
2651 int n = 1;
2620 2652
2653 argv[0] = G.global_argv[0];
2654 G.global_argv = argv;
2655 while (*++argv)
2656 n++;
2657 G.global_argc = n;
2658 n = run_list(funcp->body);
2659 fflush(NULL);
2660 _exit(n);
2661# else
2662 re_execute_shell(funcp->body_as_string, G.global_argv[0], argv + 1);
2663#endif
2664}
2665#endif
2621 2666
2622static int run_list(struct pipe *pi);
2623 2667
2624#if BB_MMU 2668#if BB_MMU
2625#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ 2669#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \
@@ -2688,18 +2732,15 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save,
2688 _exit(rcode); 2732 _exit(rcode);
2689 } 2733 }
2690 } 2734 }
2691# if ENABLE_HUSH_FUNCTIONS 2735#endif
2736#if ENABLE_HUSH_FUNCTIONS
2692 /* Check if the command matches any functions */ 2737 /* Check if the command matches any functions */
2693 { 2738 {
2694 int rcode;
2695 const struct function *funcp = find_function(argv[0]); 2739 const struct function *funcp = find_function(argv[0]);
2696 if (funcp) { 2740 if (funcp) {
2697 rcode = run_list(funcp->body); 2741 exec_function(funcp, argv);
2698 fflush(NULL);
2699 _exit(rcode);
2700 } 2742 }
2701 } 2743 }
2702# endif
2703#endif 2744#endif
2704 2745
2705#if ENABLE_FEATURE_SH_STANDALONE 2746#if ENABLE_FEATURE_SH_STANDALONE
@@ -2723,7 +2764,9 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save,
2723 } 2764 }
2724#endif 2765#endif
2725 2766
2767#if ENABLE_FEATURE_SH_STANDALONE || BB_MMU
2726 skip: 2768 skip:
2769#endif
2727 debug_printf_exec("execing '%s'\n", argv[0]); 2770 debug_printf_exec("execing '%s'\n", argv[0]);
2728 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 2771 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL);
2729 execvp(argv[0], argv); 2772 execvp(argv[0], argv);
@@ -2761,7 +2804,9 @@ static void pseudo_exec(nommu_save_t *nommu_save,
2761 * since this process is about to exit */ 2804 * since this process is about to exit */
2762 _exit(rcode); 2805 _exit(rcode);
2763#else 2806#else
2764 re_execute_shell(command->group_as_string, 0); 2807 re_execute_shell(command->group_as_string,
2808 G.global_argv[0],
2809 G.global_argv + 1);
2765#endif 2810#endif
2766 } 2811 }
2767 2812
@@ -3085,19 +3130,23 @@ static int run_pipe(struct pipe *pi)
3085 3130
3086 while ((funcp = *funcpp) != NULL) { 3131 while ((funcp = *funcpp) != NULL) {
3087 if (strcmp(funcp->name, command->argv[0]) == 0) { 3132 if (strcmp(funcp->name, command->argv[0]) == 0) {
3088 debug_printf_exec("replacing function '%s'", funcp->name); 3133 debug_printf_exec("replacing function '%s'\n", funcp->name);
3089 free(funcp->name); 3134 free(funcp->name);
3090 free_pipe_list(funcp->body, /* indent: */ 0); 3135 free_pipe_list(funcp->body, /* indent: */ 0);
3091 goto skip; 3136 goto skip;
3092 } 3137 }
3093 funcpp = &funcp->next; 3138 funcpp = &funcp->next;
3094 } 3139 }
3095 debug_printf_exec("remembering new function '%s'", funcp->name); 3140 debug_printf_exec("remembering new function '%s'\n", command->argv[0]);
3096 funcp = *funcpp = xzalloc(sizeof(*funcp)); 3141 funcp = *funcpp = xzalloc(sizeof(*funcp));
3097 /*funcp->next = NULL;*/ 3142 /*funcp->next = NULL;*/
3098 skip: 3143 skip:
3099 funcp->name = command->argv[0]; 3144 funcp->name = command->argv[0];
3100 funcp->body = command->group; 3145 funcp->body = command->group;
3146#if !BB_MMU
3147 funcp->body_as_string = command->group_as_string;
3148 command->group_as_string = NULL;
3149#endif
3101 command->group = NULL; 3150 command->group = NULL;
3102 command->argv[0] = NULL; 3151 command->argv[0] = NULL;
3103 free_strings(command->argv); 3152 free_strings(command->argv);
@@ -3160,6 +3209,7 @@ static int run_pipe(struct pipe *pi)
3160 3209
3161 x = find_builtin(argv_expanded[0]); 3210 x = find_builtin(argv_expanded[0]);
3162#if ENABLE_HUSH_FUNCTIONS 3211#if ENABLE_HUSH_FUNCTIONS
3212 funcp = NULL;
3163 if (!x) 3213 if (!x)
3164 funcp = find_function(argv_expanded[0]); 3214 funcp = find_function(argv_expanded[0]);
3165#endif 3215#endif
@@ -3171,7 +3221,6 @@ static int run_pipe(struct pipe *pi)
3171 goto clean_up_and_ret1; 3221 goto clean_up_and_ret1;
3172 } 3222 }
3173 } 3223 }
3174 debug_printf("builtin inline %s\n", argv_expanded[0]);
3175 /* XXX setup_redirects acts on file descriptors, not FILEs. 3224 /* XXX setup_redirects acts on file descriptors, not FILEs.
3176 * This is perfect for work that comes after exec(). 3225 * This is perfect for work that comes after exec().
3177 * Is it really safe for inline use? Experimentally, 3226 * Is it really safe for inline use? Experimentally,
@@ -3681,7 +3730,7 @@ static int run_list(struct pipe *pi)
3681 /* We only ran a builtin: rcode is already known 3730 /* We only ran a builtin: rcode is already known
3682 * and we don't need to wait for anything. */ 3731 * and we don't need to wait for anything. */
3683 G.last_exitcode = rcode; 3732 G.last_exitcode = rcode;
3684 debug_printf_exec(": builtin exitcode %d\n", rcode); 3733 debug_printf_exec(": builtin/func exitcode %d\n", rcode);
3685 check_and_run_traps(0); 3734 check_and_run_traps(0);
3686#if ENABLE_HUSH_LOOPS 3735#if ENABLE_HUSH_LOOPS
3687 /* Was it "break" or "continue"? */ 3736 /* Was it "break" or "continue"? */
@@ -4497,7 +4546,9 @@ static FILE *generate_stream_from_string(const char *s)
4497 * huge=`cat BIG` # was blocking here forever 4546 * huge=`cat BIG` # was blocking here forever
4498 * echo OK 4547 * echo OK
4499 */ 4548 */
4500 re_execute_shell(s, 0); 4549 re_execute_shell(s,
4550 G.global_argv[0],
4551 G.global_argv + 1);
4501#endif 4552#endif
4502 } 4553 }
4503 4554
@@ -4561,34 +4612,34 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
4561 4612
4562 debug_printf_parse("parse_group entered\n"); 4613 debug_printf_parse("parse_group entered\n");
4563#if ENABLE_HUSH_FUNCTIONS 4614#if ENABLE_HUSH_FUNCTIONS
4564 if (ch == '(') { 4615 if (ch == '(' && !dest->o_quoted) {
4565 if (!dest->o_quoted) { 4616 if (dest->length)
4566 if (dest->length) 4617 done_word(dest, ctx);
4567 done_word(dest, ctx); 4618 if (!command->argv)
4568 if (!command->argv) 4619 goto skip; /* (... */
4569 goto skip; /* (... */ 4620 if (command->argv[1]) { /* word word ... (... */
4570 if (command->argv[1]) { /* word word ... (... */ 4621 syntax_error_unexpected_ch('(');
4571 syntax_error("unexpected character ("); 4622 return 1;
4572 return 1;
4573 }
4574 /* it is "word(..." or "word (..." */
4575 do
4576 ch = i_getch(input);
4577 while (ch == ' ' || ch == '\t');
4578 if (ch != ')') {
4579 syntax_error("unexpected character X");
4580 return 1;
4581 }
4582 do
4583 ch = i_getch(input);
4584 while (ch == ' ' || ch == '\t' || ch == '\n');
4585 if (ch != '{') {
4586 syntax_error("unexpected character X");
4587 return 1;
4588 }
4589 command->grp_type = GRP_FUNCTION;
4590 goto skip;
4591 } 4623 }
4624 /* it is "word(..." or "word (..." */
4625 do
4626 ch = i_getch(input);
4627 while (ch == ' ' || ch == '\t');
4628 if (ch != ')') {
4629 syntax_error_unexpected_ch(ch);
4630 return 1;
4631 }
4632 nommu_addchr(&ctx->as_string, ch);
4633 do
4634 ch = i_getch(input);
4635 while (ch == ' ' || ch == '\t' || ch == '\n');
4636 if (ch != '{') {
4637 syntax_error_unexpected_ch(ch);
4638 return 1;
4639 }
4640 nommu_addchr(&ctx->as_string, ch);
4641 command->grp_type = GRP_FUNCTION;
4642 goto skip;
4592 } 4643 }
4593#endif 4644#endif
4594 if (command->argv /* word [word]{... */ 4645 if (command->argv /* word [word]{... */
@@ -5452,7 +5503,7 @@ static struct pipe *parse_stream(char **pstring,
5452 /* proper use of this character is caught by end_trigger: 5503 /* proper use of this character is caught by end_trigger:
5453 * if we see {, we call parse_group(..., end_trigger='}') 5504 * if we see {, we call parse_group(..., end_trigger='}')
5454 * and it will match } earlier (not here). */ 5505 * and it will match } earlier (not here). */
5455 syntax_error("unexpected } or )"); 5506 syntax_error_unexpected_ch(ch);
5456 goto parse_error; 5507 goto parse_error;
5457 default: 5508 default:
5458 if (HUSH_DEBUG) 5509 if (HUSH_DEBUG)