diff options
-rw-r--r-- | shell/ash.c | 2 | ||||
-rw-r--r-- | shell/hush.c | 274 | ||||
-rw-r--r-- | shell/lash_unused.c | 2 | ||||
-rw-r--r-- | shell/msh.c | 2 |
4 files changed, 186 insertions, 94 deletions
diff --git a/shell/ash.c b/shell/ash.c index 1e7429cb1..cc5802c30 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -12233,7 +12233,7 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12233 | unsigned col; | 12233 | unsigned col; |
12234 | unsigned i; | 12234 | unsigned i; |
12235 | 12235 | ||
12236 | out1fmt("\n" | 12236 | out1fmt( |
12237 | "Built-in commands:\n" | 12237 | "Built-in commands:\n" |
12238 | "------------------\n"); | 12238 | "------------------\n"); |
12239 | for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) { | 12239 | for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) { |
diff --git a/shell/hush.c b/shell/hush.c index f34fdd402..e82766093 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -50,7 +50,7 @@ | |||
50 | * | 50 | * |
51 | * TODOs: | 51 | * TODOs: |
52 | * grep for "TODO" and fix (some of them are easy) | 52 | * grep for "TODO" and fix (some of them are easy) |
53 | * builtins: ulimit, local | 53 | * builtins: ulimit |
54 | * follow IFS rules more precisely, including update semantics | 54 | * follow IFS rules more precisely, including update semantics |
55 | * export builtin should be special, its arguments are assignments | 55 | * export builtin should be special, its arguments are assignments |
56 | * and therefore expansion of them should be "one-word" expansion: | 56 | * and therefore expansion of them should be "one-word" expansion: |
@@ -593,56 +593,58 @@ struct built_in_command { | |||
593 | #endif | 593 | #endif |
594 | }; | 594 | }; |
595 | 595 | ||
596 | /* For now, echo and test are unconditionally enabled. | 596 | static const struct built_in_command bltins1[] = { |
597 | * Maybe make it configurable? */ | 597 | BLTIN("." , builtin_source , "Run commands in a file"), |
598 | static const struct built_in_command bltins[] = { | 598 | BLTIN(":" , builtin_true , NULL), |
599 | BLTIN("." , builtin_source , "Run commands in a file"), | ||
600 | BLTIN(":" , builtin_true , "No-op"), | ||
601 | BLTIN("[" , builtin_test , "Test condition"), | ||
602 | #if ENABLE_HUSH_JOB | 599 | #if ENABLE_HUSH_JOB |
603 | BLTIN("bg" , builtin_fg_bg , "Resume a job in the background"), | 600 | BLTIN("bg" , builtin_fg_bg , "Resume a job in the background"), |
604 | #endif | 601 | #endif |
605 | #if ENABLE_HUSH_LOOPS | 602 | #if ENABLE_HUSH_LOOPS |
606 | BLTIN("break" , builtin_break , "Exit from a loop"), | 603 | BLTIN("break" , builtin_break , "Exit from a loop"), |
607 | #endif | 604 | #endif |
608 | BLTIN("cd" , builtin_cd , "Change directory"), | 605 | BLTIN("cd" , builtin_cd , "Change directory"), |
609 | #if ENABLE_HUSH_LOOPS | 606 | #if ENABLE_HUSH_LOOPS |
610 | BLTIN("continue", builtin_continue, "Start new loop iteration"), | 607 | BLTIN("continue" , builtin_continue, "Start new loop iteration"), |
611 | #endif | 608 | #endif |
612 | BLTIN("echo" , builtin_echo , "Write to stdout"), | 609 | BLTIN("eval" , builtin_eval , "Construct and run shell command"), |
613 | BLTIN("eval" , builtin_eval , "Construct and run shell command"), | 610 | BLTIN("exec" , builtin_exec , "Execute command, don't return to shell"), |
614 | BLTIN("exec" , builtin_exec , "Execute command, don't return to shell"), | 611 | BLTIN("exit" , builtin_exit , "Exit"), |
615 | BLTIN("exit" , builtin_exit , "Exit"), | 612 | BLTIN("export" , builtin_export , "Set environment variables"), |
616 | BLTIN("export" , builtin_export , "Set environment variable"), | ||
617 | #if ENABLE_HUSH_JOB | 613 | #if ENABLE_HUSH_JOB |
618 | BLTIN("fg" , builtin_fg_bg , "Bring job into the foreground"), | 614 | BLTIN("fg" , builtin_fg_bg , "Bring job into the foreground"), |
619 | #endif | 615 | #endif |
620 | #if ENABLE_HUSH_HELP | 616 | #if ENABLE_HUSH_HELP |
621 | BLTIN("help" , builtin_help , "List shell built-in commands"), | 617 | BLTIN("help" , builtin_help , NULL), |
622 | #endif | 618 | #endif |
623 | #if ENABLE_HUSH_JOB | 619 | #if ENABLE_HUSH_JOB |
624 | BLTIN("jobs" , builtin_jobs , "List active jobs"), | 620 | BLTIN("jobs" , builtin_jobs , "List jobs"), |
625 | #endif | 621 | #endif |
626 | #if ENABLE_HUSH_LOCAL | 622 | #if ENABLE_HUSH_LOCAL |
627 | BLTIN("local" , builtin_local , "Set local variable"), | 623 | BLTIN("local" , builtin_local , "Set local variables"), |
628 | #endif | 624 | #endif |
629 | #if HUSH_DEBUG | 625 | #if HUSH_DEBUG |
630 | BLTIN("memleak" , builtin_memleak , "Debug tool"), | 626 | BLTIN("memleak" , builtin_memleak , NULL), |
631 | #endif | 627 | #endif |
632 | BLTIN("pwd" , builtin_pwd , "Print current directory"), | 628 | BLTIN("read" , builtin_read , "Input into variable"), |
633 | BLTIN("read" , builtin_read , "Input environment variable"), | ||
634 | #if ENABLE_HUSH_FUNCTIONS | 629 | #if ENABLE_HUSH_FUNCTIONS |
635 | BLTIN("return" , builtin_return , "Return from a function"), | 630 | BLTIN("return" , builtin_return , "Return from a function"), |
636 | #endif | 631 | #endif |
637 | BLTIN("set" , builtin_set , "Set/unset shell local variables"), | 632 | BLTIN("set" , builtin_set , "Set/unset positional parameters"), |
638 | BLTIN("shift" , builtin_shift , "Shift positional parameters"), | 633 | BLTIN("shift" , builtin_shift , "Shift positional parameters"), |
639 | BLTIN("test" , builtin_test , "Test condition"), | 634 | BLTIN("trap" , builtin_trap , "Trap signals"), |
640 | BLTIN("trap" , builtin_trap , "Trap signals"), | 635 | BLTIN("type" , builtin_type , "Write a description of command type"), |
641 | BLTIN("type" , builtin_type , "Write a description of command type"), | 636 | // BLTIN("ulimit" , builtin_ulimit , "Control resource limits"), |
642 | // BLTIN("ulimit" , builtin_ulimit , "Control resource limits"), | 637 | BLTIN("umask" , builtin_umask , "Set file creation mask"), |
643 | BLTIN("umask" , builtin_umask , "Set file creation mask"), | 638 | BLTIN("unset" , builtin_unset , "Unset variables"), |
644 | BLTIN("unset" , builtin_unset , "Unset environment variable"), | 639 | BLTIN("wait" , builtin_wait , "Wait for process"), |
645 | BLTIN("wait" , builtin_wait , "Wait for process"), | 640 | }; |
641 | /* For now, echo and test are unconditionally enabled. | ||
642 | * Maybe make it configurable? */ | ||
643 | static const struct built_in_command bltins2[] = { | ||
644 | BLTIN("[" , builtin_test , NULL), | ||
645 | BLTIN("echo" , builtin_echo , NULL), | ||
646 | BLTIN("pwd" , builtin_pwd , NULL), | ||
647 | BLTIN("test" , builtin_test , NULL), | ||
646 | }; | 648 | }; |
647 | 649 | ||
648 | 650 | ||
@@ -1231,15 +1233,17 @@ static int check_and_run_traps(int sig) | |||
1231 | } | 1233 | } |
1232 | 1234 | ||
1233 | 1235 | ||
1234 | static const char *set_cwd(void) | 1236 | static const char *get_cwd(int force) |
1235 | { | 1237 | { |
1236 | /* xrealloc_getcwd_or_warn(arg) calls free(arg), | 1238 | if (force || G.cwd == NULL) { |
1237 | * we must not try to free(bb_msg_unknown) */ | 1239 | /* xrealloc_getcwd_or_warn(arg) calls free(arg), |
1238 | if (G.cwd == bb_msg_unknown) | 1240 | * we must not try to free(bb_msg_unknown) */ |
1239 | G.cwd = NULL; | 1241 | if (G.cwd == bb_msg_unknown) |
1240 | G.cwd = xrealloc_getcwd_or_warn((char *)G.cwd); | 1242 | G.cwd = NULL; |
1241 | if (!G.cwd) | 1243 | G.cwd = xrealloc_getcwd_or_warn((char *)G.cwd); |
1242 | G.cwd = bb_msg_unknown; | 1244 | if (!G.cwd) |
1245 | G.cwd = bb_msg_unknown; | ||
1246 | } | ||
1243 | return G.cwd; | 1247 | return G.cwd; |
1244 | } | 1248 | } |
1245 | 1249 | ||
@@ -1579,7 +1583,7 @@ static const char* setup_prompt_string(int promptmode) | |||
1579 | /* Set up the prompt */ | 1583 | /* Set up the prompt */ |
1580 | if (promptmode == 0) { /* PS1 */ | 1584 | if (promptmode == 0) { /* PS1 */ |
1581 | free((char*)G.PS1); | 1585 | free((char*)G.PS1); |
1582 | G.PS1 = xasprintf("%s %c ", G.cwd, (geteuid() != 0) ? '$' : '#'); | 1586 | G.PS1 = xasprintf("%s %c ", get_cwd(0), (geteuid() != 0) ? '$' : '#'); |
1583 | prompt_str = G.PS1; | 1587 | prompt_str = G.PS1; |
1584 | } else | 1588 | } else |
1585 | prompt_str = G.PS2; | 1589 | prompt_str = G.PS2; |
@@ -2511,7 +2515,9 @@ static char **expand_assignments(char **argv, int count) | |||
2511 | 2515 | ||
2512 | #if BB_MMU | 2516 | #if BB_MMU |
2513 | /* never called */ | 2517 | /* never called */ |
2514 | void re_execute_shell(char ***to_free, const char *s, char *argv0, char **argv); | 2518 | void re_execute_shell(char ***to_free, const char *s, |
2519 | char *g_argv0, char **g_argv, | ||
2520 | char **builtin_argv) NORETURN; | ||
2515 | 2521 | ||
2516 | static void reset_traps_to_defaults(void) | 2522 | static void reset_traps_to_defaults(void) |
2517 | { | 2523 | { |
@@ -2563,10 +2569,14 @@ static void reset_traps_to_defaults(void) | |||
2563 | 2569 | ||
2564 | #else /* !BB_MMU */ | 2570 | #else /* !BB_MMU */ |
2565 | 2571 | ||
2566 | static void re_execute_shell(char ***to_free, const char *s, char *g_argv0, char **g_argv) NORETURN; | 2572 | static void re_execute_shell(char ***to_free, const char *s, |
2567 | static void re_execute_shell(char ***to_free, const char *s, char *g_argv0, char **g_argv) | 2573 | char *g_argv0, char **g_argv, |
2574 | char **builtin_argv) NORETURN; | ||
2575 | static void re_execute_shell(char ***to_free, const char *s, | ||
2576 | char *g_argv0, char **g_argv, | ||
2577 | char **builtin_argv) | ||
2568 | { | 2578 | { |
2569 | char param_buf[sizeof("-$%x:%x:%x:%x") + sizeof(unsigned) * 4]; | 2579 | char param_buf[sizeof("-$%x:%x:%x:%x:%x") + sizeof(unsigned) * 2]; |
2570 | char *heredoc_argv[4]; | 2580 | char *heredoc_argv[4]; |
2571 | struct variable *cur; | 2581 | struct variable *cur; |
2572 | #if ENABLE_HUSH_FUNCTIONS | 2582 | #if ENABLE_HUSH_FUNCTIONS |
@@ -2585,16 +2595,22 @@ static void re_execute_shell(char ***to_free, const char *s, char *g_argv0, char | |||
2585 | goto do_exec; | 2595 | goto do_exec; |
2586 | } | 2596 | } |
2587 | 2597 | ||
2588 | sprintf(param_buf, "-$%x:%x:%x" IF_HUSH_LOOPS(":%x") | 2598 | cnt = 0; |
2599 | pp = builtin_argv; | ||
2600 | if (pp) while (*pp++) | ||
2601 | cnt++; | ||
2602 | |||
2603 | sprintf(param_buf, "-$%x:%x:%x:%x" IF_HUSH_LOOPS(":%x") | ||
2589 | , (unsigned) G.root_pid | 2604 | , (unsigned) G.root_pid |
2590 | , (unsigned) G.last_bg_pid | 2605 | , (unsigned) G.last_bg_pid |
2591 | , (unsigned) G.last_exitcode | 2606 | , (unsigned) G.last_exitcode |
2607 | , cnt | ||
2592 | IF_HUSH_LOOPS(, G.depth_of_loop) | 2608 | IF_HUSH_LOOPS(, G.depth_of_loop) |
2593 | ); | 2609 | ); |
2594 | /* 1:hush 2:-$<pid>:<pid>:<exitcode>:<depth> <vars...> <funcs...> | 2610 | /* 1:hush 2:-$<pid>:<pid>:<exitcode>:<depth> <vars...> <funcs...> |
2595 | * 3:-c 4:<cmd> 5:<arg0> <argN...> 6:NULL | 2611 | * 3:-c 4:<cmd> 5:<arg0> <argN...> 6:NULL |
2596 | */ | 2612 | */ |
2597 | cnt = 6; | 2613 | cnt += 6; |
2598 | for (cur = G.top_var; cur; cur = cur->next) { | 2614 | for (cur = G.top_var; cur; cur = cur->next) { |
2599 | if (!cur->flg_export || cur->flg_read_only) | 2615 | if (!cur->flg_export || cur->flg_read_only) |
2600 | cnt += 2; | 2616 | cnt += 2; |
@@ -2648,6 +2664,11 @@ static void re_execute_shell(char ***to_free, const char *s, char *g_argv0, char | |||
2648 | */ | 2664 | */ |
2649 | *pp++ = (char *) "-c"; | 2665 | *pp++ = (char *) "-c"; |
2650 | *pp++ = (char *) s; | 2666 | *pp++ = (char *) s; |
2667 | if (builtin_argv) { | ||
2668 | while (*++builtin_argv) | ||
2669 | *pp++ = *builtin_argv; | ||
2670 | *pp++ = (char *) ""; | ||
2671 | } | ||
2651 | *pp++ = g_argv0; | 2672 | *pp++ = g_argv0; |
2652 | while (*g_argv) | 2673 | while (*g_argv) |
2653 | *pp++ = *g_argv++; | 2674 | *pp++ = *g_argv++; |
@@ -2735,7 +2756,7 @@ static void setup_heredoc(struct redir_struct *redir) | |||
2735 | #else | 2756 | #else |
2736 | /* Delegate blocking writes to another process */ | 2757 | /* Delegate blocking writes to another process */ |
2737 | xmove_fd(pair.wr, STDOUT_FILENO); | 2758 | xmove_fd(pair.wr, STDOUT_FILENO); |
2738 | re_execute_shell(&to_free, heredoc, NULL, NULL); | 2759 | re_execute_shell(&to_free, heredoc, NULL, NULL, NULL); |
2739 | #endif | 2760 | #endif |
2740 | } | 2761 | } |
2741 | /* parent */ | 2762 | /* parent */ |
@@ -2958,17 +2979,31 @@ static char *find_in_path(const char *arg) | |||
2958 | return ret; | 2979 | return ret; |
2959 | } | 2980 | } |
2960 | 2981 | ||
2961 | static const struct built_in_command* find_builtin(const char *name) | 2982 | static const struct built_in_command* find_builtin_helper(const char *name, |
2983 | const struct built_in_command *x, | ||
2984 | const struct built_in_command *end) | ||
2962 | { | 2985 | { |
2963 | const struct built_in_command *x; | 2986 | while (x != end) { |
2964 | for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { | 2987 | if (strcmp(name, x->cmd) != 0) { |
2965 | if (strcmp(name, x->cmd) != 0) | 2988 | x++; |
2966 | continue; | 2989 | continue; |
2990 | } | ||
2967 | debug_printf_exec("found builtin '%s'\n", name); | 2991 | debug_printf_exec("found builtin '%s'\n", name); |
2968 | return x; | 2992 | return x; |
2969 | } | 2993 | } |
2970 | return NULL; | 2994 | return NULL; |
2971 | } | 2995 | } |
2996 | static const struct built_in_command* find_builtin1(const char *name) | ||
2997 | { | ||
2998 | return find_builtin_helper(name, bltins1, &bltins1[ARRAY_SIZE(bltins1)]); | ||
2999 | } | ||
3000 | static const struct built_in_command* find_builtin(const char *name) | ||
3001 | { | ||
3002 | const struct built_in_command *x = find_builtin1(name); | ||
3003 | if (x) | ||
3004 | return x; | ||
3005 | return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]); | ||
3006 | } | ||
2972 | 3007 | ||
2973 | #if ENABLE_HUSH_FUNCTIONS | 3008 | #if ENABLE_HUSH_FUNCTIONS |
2974 | static const struct function *find_function(const char *name) | 3009 | static const struct function *find_function(const char *name) |
@@ -3084,7 +3119,8 @@ static void exec_function(nommu_save_t *nommu_save, | |||
3084 | re_execute_shell(&nommu_save->argv_from_re_execing, | 3119 | re_execute_shell(&nommu_save->argv_from_re_execing, |
3085 | funcp->body_as_string, | 3120 | funcp->body_as_string, |
3086 | G.global_argv[0], | 3121 | G.global_argv[0], |
3087 | argv + 1); | 3122 | argv + 1, |
3123 | NULL); | ||
3088 | # endif | 3124 | # endif |
3089 | } | 3125 | } |
3090 | 3126 | ||
@@ -3148,6 +3184,37 @@ static int run_function(const struct function *funcp, char **argv) | |||
3148 | #endif /* ENABLE_HUSH_FUNCTIONS */ | 3184 | #endif /* ENABLE_HUSH_FUNCTIONS */ |
3149 | 3185 | ||
3150 | 3186 | ||
3187 | # if BB_MMU | ||
3188 | #define exec_builtin(nommu_save, x, argv) \ | ||
3189 | exec_builtin(x, argv) | ||
3190 | # else | ||
3191 | #define exec_builtin(nommu_save, x, argv) \ | ||
3192 | exec_builtin(nommu_save, argv) | ||
3193 | # endif | ||
3194 | static void exec_builtin(nommu_save_t *nommu_save, | ||
3195 | const struct built_in_command *x, | ||
3196 | char **argv) NORETURN; | ||
3197 | static void exec_builtin(nommu_save_t *nommu_save, | ||
3198 | const struct built_in_command *x, | ||
3199 | char **argv) | ||
3200 | { | ||
3201 | # if BB_MMU | ||
3202 | int rcode = x->function(argv); | ||
3203 | fflush(NULL); | ||
3204 | _exit(rcode); | ||
3205 | # else | ||
3206 | /* On NOMMU, we must never block! | ||
3207 | * Example: { sleep 99 | read line; } & echo Ok | ||
3208 | */ | ||
3209 | re_execute_shell(&nommu_save->argv_from_re_execing, | ||
3210 | argv[0], | ||
3211 | G.global_argv[0], | ||
3212 | G.global_argv + 1, | ||
3213 | argv); | ||
3214 | # endif | ||
3215 | } | ||
3216 | |||
3217 | |||
3151 | #if BB_MMU | 3218 | #if BB_MMU |
3152 | #define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ | 3219 | #define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ |
3153 | pseudo_exec_argv(argv, assignment_cnt, argv_expanded) | 3220 | pseudo_exec_argv(argv, assignment_cnt, argv_expanded) |
@@ -3197,27 +3264,22 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
3197 | goto skip; | 3264 | goto skip; |
3198 | #endif | 3265 | #endif |
3199 | 3266 | ||
3200 | /* On NOMMU, we must never block! | ||
3201 | * Example: { sleep 99999 | read line } & echo Ok | ||
3202 | * read builtin will block on read syscall, leaving parent blocked | ||
3203 | * in vfork. Therefore we can't do this: | ||
3204 | */ | ||
3205 | #if BB_MMU | ||
3206 | /* Check if the command matches any of the builtins. | 3267 | /* Check if the command matches any of the builtins. |
3207 | * Depending on context, this might be redundant. But it's | 3268 | * Depending on context, this might be redundant. But it's |
3208 | * easier to waste a few CPU cycles than it is to figure out | 3269 | * easier to waste a few CPU cycles than it is to figure out |
3209 | * if this is one of those cases. | 3270 | * if this is one of those cases. |
3210 | */ | 3271 | */ |
3211 | { | 3272 | { |
3212 | int rcode; | 3273 | /* On NOMMU, it is more expensive to re-execute shell |
3213 | const struct built_in_command *x = find_builtin(argv[0]); | 3274 | * just in order to run echo or test builtin. |
3275 | * It's better to skip it here and run corresponding | ||
3276 | * non-builtin later. */ | ||
3277 | const struct built_in_command *x; | ||
3278 | x = BB_MMU ? find_builtin(argv[0]) : find_builtin1(argv[0]); | ||
3214 | if (x) { | 3279 | if (x) { |
3215 | rcode = x->function(argv); | 3280 | exec_builtin(nommu_save, x, argv); |
3216 | fflush(NULL); | ||
3217 | _exit(rcode); | ||
3218 | } | 3281 | } |
3219 | } | 3282 | } |
3220 | #endif | ||
3221 | #if ENABLE_HUSH_FUNCTIONS | 3283 | #if ENABLE_HUSH_FUNCTIONS |
3222 | /* Check if the command matches any functions */ | 3284 | /* Check if the command matches any functions */ |
3223 | { | 3285 | { |
@@ -3292,7 +3354,8 @@ static void pseudo_exec(nommu_save_t *nommu_save, | |||
3292 | re_execute_shell(&nommu_save->argv_from_re_execing, | 3354 | re_execute_shell(&nommu_save->argv_from_re_execing, |
3293 | command->group_as_string, | 3355 | command->group_as_string, |
3294 | G.global_argv[0], | 3356 | G.global_argv[0], |
3295 | G.global_argv + 1); | 3357 | G.global_argv + 1, |
3358 | NULL); | ||
3296 | #endif | 3359 | #endif |
3297 | } | 3360 | } |
3298 | 3361 | ||
@@ -5030,7 +5093,8 @@ static FILE *generate_stream_from_string(const char *s) | |||
5030 | re_execute_shell(&to_free, | 5093 | re_execute_shell(&to_free, |
5031 | s, | 5094 | s, |
5032 | G.global_argv[0], | 5095 | G.global_argv[0], |
5033 | G.global_argv + 1); | 5096 | G.global_argv + 1, |
5097 | NULL); | ||
5034 | #endif | 5098 | #endif |
5035 | } | 5099 | } |
5036 | 5100 | ||
@@ -6240,6 +6304,7 @@ int hush_main(int argc, char **argv) | |||
6240 | }; | 6304 | }; |
6241 | int signal_mask_is_inited = 0; | 6305 | int signal_mask_is_inited = 0; |
6242 | int opt; | 6306 | int opt; |
6307 | unsigned builtin_argc; | ||
6243 | char **e; | 6308 | char **e; |
6244 | struct variable *cur_var; | 6309 | struct variable *cur_var; |
6245 | 6310 | ||
@@ -6277,7 +6342,6 @@ int hush_main(int argc, char **argv) | |||
6277 | G.global_argc = argc; | 6342 | G.global_argc = argc; |
6278 | G.global_argv = argv; | 6343 | G.global_argv = argv; |
6279 | /* Initialize some more globals to non-zero values */ | 6344 | /* Initialize some more globals to non-zero values */ |
6280 | set_cwd(); | ||
6281 | cmdedit_update_prompt(); | 6345 | cmdedit_update_prompt(); |
6282 | 6346 | ||
6283 | if (setjmp(die_jmp)) { | 6347 | if (setjmp(die_jmp)) { |
@@ -6297,6 +6361,7 @@ int hush_main(int argc, char **argv) | |||
6297 | 6361 | ||
6298 | /* Parse options */ | 6362 | /* Parse options */ |
6299 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ | 6363 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ |
6364 | builtin_argc = 0; | ||
6300 | while (1) { | 6365 | while (1) { |
6301 | opt = getopt(argc, argv, "c:xins" | 6366 | opt = getopt(argc, argv, "c:xins" |
6302 | #if !BB_MMU | 6367 | #if !BB_MMU |
@@ -6310,15 +6375,40 @@ int hush_main(int argc, char **argv) | |||
6310 | break; | 6375 | break; |
6311 | switch (opt) { | 6376 | switch (opt) { |
6312 | case 'c': | 6377 | case 'c': |
6378 | /* Possibilities: | ||
6379 | * sh ... -c 'script' | ||
6380 | * sh ... -c 'script' ARG0 [ARG1...] | ||
6381 | * On NOMMU, if builtin_argc != 0, | ||
6382 | * sh ... -c 'builtin' [BARGV...] "" ARG0 [ARG1...] | ||
6383 | * "" needs to be replaced with NULL | ||
6384 | * and BARGV vector fed to builtin function. | ||
6385 | * Note: this form never happens: | ||
6386 | * sh ... -c 'builtin' [BARGV...] "" | ||
6387 | */ | ||
6313 | if (!G.root_pid) | 6388 | if (!G.root_pid) |
6314 | G.root_pid = getpid(); | 6389 | G.root_pid = getpid(); |
6315 | G.global_argv = argv + optind; | 6390 | G.global_argv = argv + optind; |
6316 | if (!argv[optind]) { | ||
6317 | /* -c 'script' (no params): prevent empty $0 */ | ||
6318 | *--G.global_argv = argv[0]; | ||
6319 | optind--; | ||
6320 | } /* else -c 'script' PAR0 PAR1: $0 is PAR0 */ | ||
6321 | G.global_argc = argc - optind; | 6391 | G.global_argc = argc - optind; |
6392 | if (builtin_argc) { | ||
6393 | /* -c 'builtin' [BARGV...] "" ARG0 [ARG1...] */ | ||
6394 | const struct built_in_command *x; | ||
6395 | |||
6396 | block_signals(0); /* 0: called 1st time */ | ||
6397 | x = find_builtin(optarg); | ||
6398 | if (x) { /* paranoia */ | ||
6399 | G.global_argc -= builtin_argc; /* skip [BARGV...] "" */ | ||
6400 | G.global_argv += builtin_argc; | ||
6401 | G.global_argv[-1] = NULL; /* replace "" */ | ||
6402 | G.last_exitcode = x->function(argv + optind - 1); | ||
6403 | } | ||
6404 | goto final_return; | ||
6405 | } | ||
6406 | if (!G.global_argv[0]) { | ||
6407 | /* -c 'script' (no params): prevent empty $0 */ | ||
6408 | G.global_argv--; /* points to argv[i] of 'script' */ | ||
6409 | G.global_argv[0] = argv[0]; | ||
6410 | G.global_argc--; | ||
6411 | } /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */ | ||
6322 | block_signals(0); /* 0: called 1st time */ | 6412 | block_signals(0); /* 0: called 1st time */ |
6323 | parse_and_run_string(optarg); | 6413 | parse_and_run_string(optarg); |
6324 | goto final_return; | 6414 | goto final_return; |
@@ -6341,6 +6431,8 @@ int hush_main(int argc, char **argv) | |||
6341 | G.last_bg_pid = bb_strtou(optarg, &optarg, 16); | 6431 | G.last_bg_pid = bb_strtou(optarg, &optarg, 16); |
6342 | optarg++; | 6432 | optarg++; |
6343 | G.last_exitcode = bb_strtou(optarg, &optarg, 16); | 6433 | G.last_exitcode = bb_strtou(optarg, &optarg, 16); |
6434 | optarg++; | ||
6435 | builtin_argc = bb_strtou(optarg, &optarg, 16); | ||
6344 | # if ENABLE_HUSH_LOOPS | 6436 | # if ENABLE_HUSH_LOOPS |
6345 | optarg++; | 6437 | optarg++; |
6346 | G.depth_of_loop = bb_strtou(optarg, &optarg, 16); | 6438 | G.depth_of_loop = bb_strtou(optarg, &optarg, 16); |
@@ -6617,7 +6709,7 @@ static int FAST_FUNC builtin_cd(char **argv) | |||
6617 | bb_perror_msg("cd: %s", newdir); | 6709 | bb_perror_msg("cd: %s", newdir); |
6618 | return EXIT_FAILURE; | 6710 | return EXIT_FAILURE; |
6619 | } | 6711 | } |
6620 | set_cwd(); | 6712 | get_cwd(1); |
6621 | return EXIT_SUCCESS; | 6713 | return EXIT_SUCCESS; |
6622 | } | 6714 | } |
6623 | 6715 | ||
@@ -6663,17 +6755,16 @@ static int FAST_FUNC builtin_exit(char **argv) | |||
6663 | 6755 | ||
6664 | static void print_escaped(const char *s) | 6756 | static void print_escaped(const char *s) |
6665 | { | 6757 | { |
6758 | if (*s == '\'') | ||
6759 | goto squote; | ||
6666 | do { | 6760 | do { |
6667 | if (*s != '\'') { | 6761 | const char *p = strchrnul(s, '\''); |
6668 | const char *p; | 6762 | /* print 'xxxx', possibly just '' */ |
6669 | 6763 | printf("'%.*s'", (int)(p - s), s); | |
6670 | p = strchrnul(s, '\''); | 6764 | if (*p == '\0') |
6671 | /* print 'xxxx', possibly just '' */ | 6765 | break; |
6672 | printf("'%.*s'", (int)(p - s), s); | 6766 | s = p; |
6673 | if (*p == '\0') | 6767 | squote: |
6674 | break; | ||
6675 | s = p; | ||
6676 | } | ||
6677 | /* s points to '; print "'''...'''" */ | 6768 | /* s points to '; print "'''...'''" */ |
6678 | putchar('"'); | 6769 | putchar('"'); |
6679 | do putchar('\''); while (*++s == '\''); | 6770 | do putchar('\''); while (*++s == '\''); |
@@ -6980,13 +7071,14 @@ static int FAST_FUNC builtin_help(char **argv UNUSED_PARAM) | |||
6980 | { | 7071 | { |
6981 | const struct built_in_command *x; | 7072 | const struct built_in_command *x; |
6982 | 7073 | ||
6983 | printf("\n" | 7074 | printf( |
6984 | "Built-in commands:\n" | 7075 | "Built-in commands:\n" |
6985 | "------------------\n"); | 7076 | "------------------\n"); |
6986 | for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { | 7077 | for (x = bltins1; x != &bltins1[ARRAY_SIZE(bltins1)]; x++) { |
6987 | printf("%s\t%s\n", x->cmd, x->descr); | 7078 | if (x->descr) |
7079 | printf("%s\t%s\n", x->cmd, x->descr); | ||
6988 | } | 7080 | } |
6989 | printf("\n\n"); | 7081 | bb_putchar('\n'); |
6990 | return EXIT_SUCCESS; | 7082 | return EXIT_SUCCESS; |
6991 | } | 7083 | } |
6992 | #endif | 7084 | #endif |
@@ -7041,7 +7133,7 @@ static int FAST_FUNC builtin_memleak(char **argv UNUSED_PARAM) | |||
7041 | 7133 | ||
7042 | static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM) | 7134 | static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM) |
7043 | { | 7135 | { |
7044 | puts(set_cwd()); | 7136 | puts(get_cwd(0)); |
7045 | return EXIT_SUCCESS; | 7137 | return EXIT_SUCCESS; |
7046 | } | 7138 | } |
7047 | 7139 | ||
diff --git a/shell/lash_unused.c b/shell/lash_unused.c index 21ea5471b..2574987c5 100644 --- a/shell/lash_unused.c +++ b/shell/lash_unused.c | |||
@@ -312,7 +312,7 @@ static int builtin_help(struct child_prog UNUSED_PARAM *dummy) | |||
312 | { | 312 | { |
313 | const struct built_in_command *x; | 313 | const struct built_in_command *x; |
314 | 314 | ||
315 | printf("\n" | 315 | printf( |
316 | "Built-in commands:\n" | 316 | "Built-in commands:\n" |
317 | "------------------\n"); | 317 | "------------------\n"); |
318 | for (x = bltins; x <= &VEC_LAST(bltins); x++) { | 318 | for (x = bltins; x <= &VEC_LAST(bltins); x++) { |
diff --git a/shell/msh.c b/shell/msh.c index dffacf02a..fe85a8170 100644 --- a/shell/msh.c +++ b/shell/msh.c | |||
@@ -3174,7 +3174,7 @@ static int dohelp(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM) | |||
3174 | int col; | 3174 | int col; |
3175 | const struct builtincmd *x; | 3175 | const struct builtincmd *x; |
3176 | 3176 | ||
3177 | printf("\n" | 3177 | printf( |
3178 | "Built-in commands:\n" | 3178 | "Built-in commands:\n" |
3179 | "------------------\n"); | 3179 | "------------------\n"); |
3180 | 3180 | ||