aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-10 19:05:43 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-10 19:05:43 +0000
commitb7d8c0dbbd250649d647142edd33226822f3c879 (patch)
treea315a2c6a2fa6b062fe66aacf0eea66587737a54
parent835fcfd33d574d471d9b67a69116281d9ff42040 (diff)
downloadbusybox-w32-b7d8c0dbbd250649d647142edd33226822f3c879.tar.gz
busybox-w32-b7d8c0dbbd250649d647142edd33226822f3c879.tar.bz2
busybox-w32-b7d8c0dbbd250649d647142edd33226822f3c879.zip
hush: first stab at function support. argv passing is not coded yet.
Only very rudimentary testing was done. With function support off, code growth is zero, with it on: function old new delta run_list 2158 2339 +181 parse_stream 1929 2044 +115 find_builtin 24 67 +43 find_function - 36 +36 file_get 244 264 +20 pseudo_exec_argv 145 160 +15 free_strings - 7 +7 free_pipe 183 181 -2 done_word 735 728 -7 expand_variables 2227 2204 -23 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 5/3 up/down: 417/-32) Total: 385 bytes
-rw-r--r--shell/hush.c233
1 files changed, 169 insertions, 64 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 9adf0e127..3728583fc 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -86,7 +86,7 @@
86 */ 86 */
87#define HUSH_DEBUG 1 87#define HUSH_DEBUG 1
88/* In progress... */ 88/* In progress... */
89#define ENABLE_HUSH_FUNCTIONS 0 89#define ENABLE_HUSH_FUNCTIONS 1
90 90
91 91
92#if BUILD_AS_NOMMU 92#if BUILD_AS_NOMMU
@@ -374,12 +374,12 @@ struct command {
374#define GRP_NORMAL 0 374#define GRP_NORMAL 0
375#define GRP_SUBSHELL 1 375#define GRP_SUBSHELL 1
376#if ENABLE_HUSH_FUNCTIONS 376#if ENABLE_HUSH_FUNCTIONS
377#define GRP_FUNCTION 2 377# define GRP_FUNCTION 2
378#endif 378#endif
379 379
380struct pipe { 380struct pipe {
381 struct pipe *next; 381 struct pipe *next;
382 int num_cmds; /* total number of commands in job */ 382 int num_cmds; /* total number of commands in pipe */
383 int alive_cmds; /* number of commands running (not exited) */ 383 int alive_cmds; /* number of commands running (not exited) */
384 int stopped_cmds; /* number of commands alive, but stopped */ 384 int stopped_cmds; /* number of commands alive, but stopped */
385#if ENABLE_HUSH_JOB 385#if ENABLE_HUSH_JOB
@@ -452,6 +452,12 @@ enum {
452 BC_CONTINUE = 2, 452 BC_CONTINUE = 2,
453}; 453};
454 454
455struct function {
456 struct function *next;
457 char *name;
458 struct pipe *body;
459};
460
455 461
456/* "Globals" within this file */ 462/* "Globals" within this file */
457/* Sorted roughly by size (smaller offsets == smaller code) */ 463/* Sorted roughly by size (smaller offsets == smaller code) */
@@ -504,6 +510,7 @@ struct globals {
504 const char *cwd; 510 const char *cwd;
505 struct variable *top_var; /* = &G.shell_ver (set in main()) */ 511 struct variable *top_var; /* = &G.shell_ver (set in main()) */
506 struct variable shell_ver; 512 struct variable shell_ver;
513 struct function *top_func;
507 /* Signal and trap handling */ 514 /* Signal and trap handling */
508// unsigned count_SIGCHLD; 515// unsigned count_SIGCHLD;
509// unsigned handled_SIGCHLD; 516// unsigned handled_SIGCHLD;
@@ -2585,6 +2592,35 @@ static void free_pipe_list(struct pipe *head, int indent)
2585} 2592}
2586 2593
2587 2594
2595static const struct built_in_command* find_builtin(const char *name)
2596{
2597 const struct built_in_command *x;
2598 for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) {
2599 if (strcmp(name, x->cmd) != 0)
2600 continue;
2601 debug_printf_exec("found builtin '%s'\n", name);
2602 return x;
2603 }
2604 return NULL;
2605}
2606
2607# if ENABLE_HUSH_FUNCTIONS
2608static const struct function *find_function(const char *name)
2609{
2610 const struct function *funcp = G.top_func;
2611 while (funcp) {
2612 if (strcmp(name, funcp->name) != 0)
2613 continue;
2614 return funcp;
2615 debug_printf_exec("found function '%s'\n", name);
2616 }
2617 return NULL;
2618}
2619#endif
2620
2621
2622static int run_list(struct pipe *pi);
2623
2588#if BB_MMU 2624#if BB_MMU
2589#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ 2625#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \
2590 pseudo_exec_argv(argv, assignment_cnt, argv_expanded) 2626 pseudo_exec_argv(argv, assignment_cnt, argv_expanded)
@@ -2627,6 +2663,11 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save,
2627#endif 2663#endif
2628 } 2664 }
2629 2665
2666#if ENABLE_FEATURE_SH_STANDALONE || BB_MMU
2667 if (strchr(argv[0], '/') != NULL)
2668 goto skip;
2669#endif
2670
2630 /* On NOMMU, we must never block! 2671 /* On NOMMU, we must never block!
2631 * Example: { sleep 99999 | read line } & echo Ok 2672 * Example: { sleep 99999 | read line } & echo Ok
2632 * read builtin will block on read syscall, leaving parent blocked 2673 * read builtin will block on read syscall, leaving parent blocked
@@ -2640,30 +2681,38 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save,
2640 */ 2681 */
2641 { 2682 {
2642 int rcode; 2683 int rcode;
2643 const struct built_in_command *x; 2684 const struct built_in_command *x = find_builtin(argv[0]);
2644 for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { 2685 if (x) {
2645 if (strcmp(argv[0], x->cmd) == 0) { 2686 rcode = x->function(argv);
2646 debug_printf_exec("running builtin '%s'\n", 2687 fflush(NULL);
2647 argv[0]); 2688 _exit(rcode);
2648 rcode = x->function(argv);
2649 fflush(NULL);
2650 _exit(rcode);
2651 }
2652 } 2689 }
2653 } 2690 }
2691# if ENABLE_HUSH_FUNCTIONS
2692 /* Check if the command matches any functions */
2693 {
2694 int rcode;
2695 const struct function *funcp = find_function(argv[0]);
2696 if (funcp) {
2697 rcode = run_list(funcp->body);
2698 fflush(NULL);
2699 _exit(rcode);
2700 }
2701 }
2702# endif
2654#endif 2703#endif
2655 2704
2656#if ENABLE_FEATURE_SH_STANDALONE 2705#if ENABLE_FEATURE_SH_STANDALONE
2657 /* Check if the command matches any busybox applets */ 2706 /* Check if the command matches any busybox applets */
2658 if (strchr(argv[0], '/') == NULL) { 2707 {
2659 int a = find_applet_by_name(argv[0]); 2708 int a = find_applet_by_name(argv[0]);
2660 if (a >= 0) { 2709 if (a >= 0) {
2661#if BB_MMU /* see above why on NOMMU it is not allowed */ 2710# if BB_MMU /* see above why on NOMMU it is not allowed */
2662 if (APPLET_IS_NOEXEC(a)) { 2711 if (APPLET_IS_NOEXEC(a)) {
2663 debug_printf_exec("running applet '%s'\n", argv[0]); 2712 debug_printf_exec("running applet '%s'\n", argv[0]);
2664 run_applet_no_and_exit(a, argv); 2713 run_applet_no_and_exit(a, argv);
2665 } 2714 }
2666#endif 2715# endif
2667 /* Re-exec ourselves */ 2716 /* Re-exec ourselves */
2668 debug_printf_exec("re-execing applet '%s'\n", argv[0]); 2717 debug_printf_exec("re-execing applet '%s'\n", argv[0]);
2669 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 2718 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL);
@@ -2674,6 +2723,7 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save,
2674 } 2723 }
2675#endif 2724#endif
2676 2725
2726 skip:
2677 debug_printf_exec("execing '%s'\n", argv[0]); 2727 debug_printf_exec("execing '%s'\n", argv[0]);
2678 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 2728 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL);
2679 execvp(argv[0], argv); 2729 execvp(argv[0], argv);
@@ -2681,8 +2731,6 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save,
2681 _exit(EXIT_FAILURE); 2731 _exit(EXIT_FAILURE);
2682} 2732}
2683 2733
2684static int run_list(struct pipe *pi);
2685
2686/* Called after [v]fork() in run_pipe 2734/* Called after [v]fork() in run_pipe
2687 */ 2735 */
2688static void pseudo_exec(nommu_save_t *nommu_save, 2736static void pseudo_exec(nommu_save_t *nommu_save,
@@ -3031,8 +3079,35 @@ static int run_pipe(struct pipe *pi)
3031 if (command->group) { 3079 if (command->group) {
3032#if ENABLE_HUSH_FUNCTIONS 3080#if ENABLE_HUSH_FUNCTIONS
3033 if (command->grp_type == GRP_FUNCTION) { 3081 if (command->grp_type == GRP_FUNCTION) {
3034 /* func () { list } */ 3082 /* "executing" func () { list } */
3035 bb_error_msg("here we ought to remember function definition, and go on"); 3083 struct function *funcp;
3084 struct function **funcpp = &G.top_func;
3085
3086 while ((funcp = *funcpp) != NULL) {
3087 if (strcmp(funcp->name, command->argv[0]) == 0) {
3088 debug_printf_exec("replacing function '%s'", funcp->name);
3089 free(funcp->name);
3090 free_pipe_list(funcp->body, /* indent: */ 0);
3091 goto skip;
3092 }
3093 funcpp = &funcp->next;
3094 }
3095 debug_printf_exec("remembering new function '%s'", funcp->name);
3096 funcp = *funcpp = xzalloc(sizeof(*funcp));
3097 /*funcp->next = NULL;*/
3098 skip:
3099 funcp->name = command->argv[0];
3100 funcp->body = command->group;
3101 command->group = NULL;
3102 command->argv[0] = NULL;
3103 free_strings(command->argv);
3104 command->argv = NULL;
3105 /* note: if we are in a loop, future "executions"
3106 * of func def will see it as null command since
3107 * command->group == NULL and command->argv == NULL */
3108//this isn't exactly right: while...do f1() {a;}; f1; f1 {b;}; done
3109//second loop will execute b!
3110
3036 return EXIT_SUCCESS; 3111 return EXIT_SUCCESS;
3037 } 3112 }
3038#endif 3113#endif
@@ -3052,6 +3127,11 @@ static int run_pipe(struct pipe *pi)
3052 argv = command->argv ? command->argv : (char **) &null_ptr; 3127 argv = command->argv ? command->argv : (char **) &null_ptr;
3053 { 3128 {
3054 const struct built_in_command *x; 3129 const struct built_in_command *x;
3130#if ENABLE_HUSH_FUNCTIONS
3131 const struct function *funcp;
3132#else
3133 enum { funcp = 0 };
3134#endif
3055 char **new_env = NULL; 3135 char **new_env = NULL;
3056 char **old_env = NULL; 3136 char **old_env = NULL;
3057 3137
@@ -3078,13 +3158,18 @@ static int run_pipe(struct pipe *pi)
3078 /* Expand the rest into (possibly) many strings each */ 3158 /* Expand the rest into (possibly) many strings each */
3079 argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); 3159 argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt);
3080 3160
3081 for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { 3161 x = find_builtin(argv_expanded[0]);
3082 if (strcmp(argv_expanded[0], x->cmd) != 0) 3162#if ENABLE_HUSH_FUNCTIONS
3083 continue; 3163 if (!x)
3084 if (x->function == builtin_exec && argv_expanded[1] == NULL) { 3164 funcp = find_function(argv_expanded[0]);
3085 debug_printf("exec with redirects only\n"); 3165#endif
3086 rcode = setup_redirects(command, NULL); 3166 if (x || funcp) {
3087 goto clean_up_and_ret1; 3167 if (!funcp) {
3168 if (x->function == builtin_exec && argv_expanded[1] == NULL) {
3169 debug_printf("exec with redirects only\n");
3170 rcode = setup_redirects(command, NULL);
3171 goto clean_up_and_ret1;
3172 }
3088 } 3173 }
3089 debug_printf("builtin inline %s\n", argv_expanded[0]); 3174 debug_printf("builtin inline %s\n", argv_expanded[0]);
3090 /* XXX setup_redirects acts on file descriptors, not FILEs. 3175 /* XXX setup_redirects acts on file descriptors, not FILEs.
@@ -3095,9 +3180,18 @@ static int run_pipe(struct pipe *pi)
3095 if (rcode == 0) { 3180 if (rcode == 0) {
3096 new_env = expand_assignments(argv, command->assignment_cnt); 3181 new_env = expand_assignments(argv, command->assignment_cnt);
3097 old_env = putenv_all_and_save_old(new_env); 3182 old_env = putenv_all_and_save_old(new_env);
3098 debug_printf_exec(": builtin '%s' '%s'...\n", 3183 if (!funcp) {
3184 debug_printf_exec(": builtin '%s' '%s'...\n",
3099 x->cmd, argv_expanded[1]); 3185 x->cmd, argv_expanded[1]);
3100 rcode = x->function(argv_expanded) & 0xff; 3186 rcode = x->function(argv_expanded) & 0xff;
3187 }
3188#if ENABLE_HUSH_FUNCTIONS
3189 else {
3190 debug_printf_exec(": function '%s' '%s'...\n",
3191 funcp->name, argv_expanded[1]);
3192 rcode = run_list(funcp->body) & 0xff;
3193 }
3194#endif
3101 } 3195 }
3102#if ENABLE_FEATURE_SH_STANDALONE 3196#if ENABLE_FEATURE_SH_STANDALONE
3103 clean_up_and_ret: 3197 clean_up_and_ret:
@@ -3114,6 +3208,7 @@ static int run_pipe(struct pipe *pi)
3114 debug_printf_exec("run_pipe return %d\n", rcode); 3208 debug_printf_exec("run_pipe return %d\n", rcode);
3115 return rcode; 3209 return rcode;
3116 } 3210 }
3211
3117#if ENABLE_FEATURE_SH_STANDALONE 3212#if ENABLE_FEATURE_SH_STANDALONE
3118 i = find_applet_by_name(argv_expanded[0]); 3213 i = find_applet_by_name(argv_expanded[0]);
3119 if (i >= 0 && APPLET_IS_NOFORK(i)) { 3214 if (i >= 0 && APPLET_IS_NOFORK(i)) {
@@ -4081,6 +4176,10 @@ static int done_word(o_string *word, struct parse_context *ctx)
4081 } 4176 }
4082 } 4177 }
4083 command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); 4178 command->argv = add_string_to_strings(command->argv, xstrdup(word->data));
4179//SEGV, but good idea.
4180// command->argv = add_string_to_strings(command->argv, word->data);
4181// word->data = NULL;
4182// word->length = 0;
4084 debug_print_strings("word appended to argv", command->argv); 4183 debug_print_strings("word appended to argv", command->argv);
4085 } 4184 }
4086 4185
@@ -4089,7 +4188,7 @@ static int done_word(o_string *word, struct parse_context *ctx)
4089 if (word->o_quoted 4188 if (word->o_quoted
4090 || !is_well_formed_var_name(command->argv[0], '\0') 4189 || !is_well_formed_var_name(command->argv[0], '\0')
4091 ) { 4190 ) {
4092 /* bash says "not a valid identifier" */ 4191 /* bash says just "not a valid identifier" */
4093 syntax_error("not a valid identifier in for"); 4192 syntax_error("not a valid identifier in for");
4094 return 1; 4193 return 1;
4095 } 4194 }
@@ -4462,27 +4561,55 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
4462 4561
4463 debug_printf_parse("parse_group entered\n"); 4562 debug_printf_parse("parse_group entered\n");
4464#if ENABLE_HUSH_FUNCTIONS 4563#if ENABLE_HUSH_FUNCTIONS
4465 if (ch == 'F') { /* function definition? */ 4564 if (ch == '(') {
4466 bb_error_msg("aha '%s' is a function, parsing it...", dest->data); 4565 if (!dest->o_quoted) {
4467 //command->fname = dest->data; 4566 if (dest->length)
4468 command->grp_type = GRP_FUNCTION; 4567 done_word(dest, ctx);
4469 memset(dest, 0, sizeof(*dest)); 4568 if (!command->argv)
4569 goto skip; /* (... */
4570 if (command->argv[1]) { /* word word ... (... */
4571 syntax_error("unexpected character (");
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 }
4470 } 4592 }
4471#endif 4593#endif
4472 if (command->argv /* word [word](... */ 4594 if (command->argv /* word [word]{... */
4473 || dest->length /* word(... */ 4595 || dest->length /* word{... */
4474 || dest->o_quoted /* ""(... */ 4596 || dest->o_quoted /* ""{... */
4475 ) { 4597 ) {
4476 syntax_error(NULL); 4598 syntax_error(NULL);
4477 debug_printf_parse("parse_group return 1: " 4599 debug_printf_parse("parse_group return 1: "
4478 "syntax error, groups and arglists don't mix\n"); 4600 "syntax error, groups and arglists don't mix\n");
4479 return 1; 4601 return 1;
4480 } 4602 }
4603
4604#if ENABLE_HUSH_FUNCTIONS
4605 skip:
4606#endif
4481 endch = '}'; 4607 endch = '}';
4482 if (ch == '(') { 4608 if (ch == '(') {
4483 endch = ')'; 4609 endch = ')';
4484 command->grp_type = GRP_SUBSHELL; 4610 command->grp_type = GRP_SUBSHELL;
4485 } 4611 }
4612
4486 { 4613 {
4487#if !BB_MMU 4614#if !BB_MMU
4488 char *as_string = NULL; 4615 char *as_string = NULL;
@@ -5311,28 +5438,6 @@ static struct pipe *parse_stream(char **pstring,
5311 continue; 5438 continue;
5312 } 5439 }
5313#endif 5440#endif
5314#if ENABLE_HUSH_FUNCTIONS
5315 if (dest.length != 0 /* not just () but word() */
5316 && dest.o_quoted == 0 /* not a"b"c() */
5317 && ctx.command->argv == NULL /* it's the first word */
5318//TODO: "func ( ) {...}" - note spaces - is valid format too in bash
5319 && i_peek(input) == ')'
5320 && !match_reserved_word(&dest)
5321 ) {
5322 bb_error_msg("seems like a function definition");
5323 i_getch(input);
5324//if !BB_MMU o_addchr(&ctx.as_string...
5325 do {
5326//TODO: do it properly.
5327 ch = i_getch(input);
5328 } while (ch == ' ' || ch == '\n');
5329 if (ch != '{') {
5330 syntax_error("was expecting {");
5331 goto parse_error;
5332 }
5333 ch = 'F'; /* magic value */
5334 }
5335#endif
5336 case '{': 5441 case '{':
5337 if (parse_group(&dest, &ctx, input, ch) != 0) { 5442 if (parse_group(&dest, &ctx, input, ch) != 0) {
5338 goto parse_error; 5443 goto parse_error;
@@ -6427,11 +6532,11 @@ static int builtin_unset(char **argv)
6427 ret = EXIT_FAILURE; 6532 ret = EXIT_FAILURE;
6428 } 6533 }
6429 } 6534 }
6430#if ENABLE_HUSH_FUNCTIONS 6535//#if ENABLE_HUSH_FUNCTIONS
6431 else { 6536// else {
6432 unset_local_func(*argv); 6537// unset_local_func(*argv);
6433 } 6538// }
6434#endif 6539//#endif
6435 argv++; 6540 argv++;
6436 } 6541 }
6437 return ret; 6542 return ret;