diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-05 10:39:03 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-05 10:39:03 +0000 |
commit | 46f9b6db80e4fd0a1c50d435bc387ad28d12abb2 (patch) | |
tree | 99bf6bc0b7db612cfac96ae5d4ac4b653d3b3a3e /shell | |
parent | 232be3e79b97eceae617fe8af020d23b49e01de1 (diff) | |
download | busybox-w32-46f9b6db80e4fd0a1c50d435bc387ad28d12abb2.tar.gz busybox-w32-46f9b6db80e4fd0a1c50d435bc387ad28d12abb2.tar.bz2 busybox-w32-46f9b6db80e4fd0a1c50d435bc387ad28d12abb2.zip |
hush: pass $! thru re-execution; try harder on re-exec; give error
msg if re-exec didn't work; other tweaks in main()
function old new delta
hush_main 1144 1199 +55
re_execute_shell 237 286 +49
file_get 240 260 +20
clean_up_after_re_execute 58 66 +8
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 4/0 up/down: 132/0) Total: 132 bytes
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 98 |
1 files changed, 57 insertions, 41 deletions
diff --git a/shell/hush.c b/shell/hush.c index 39d3c01de..eba7a86df 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -487,7 +487,8 @@ struct globals { | |||
487 | int global_argc; | 487 | int global_argc; |
488 | char **global_argv; | 488 | char **global_argv; |
489 | #if !BB_MMU | 489 | #if !BB_MMU |
490 | char **argv_for_re_execing; | 490 | char *argv0_for_re_execing; |
491 | char **argv_from_re_execing; | ||
491 | #endif | 492 | #endif |
492 | #if ENABLE_HUSH_LOOPS | 493 | #if ENABLE_HUSH_LOOPS |
493 | unsigned depth_break_continue; | 494 | unsigned depth_break_continue; |
@@ -2356,18 +2357,19 @@ static void re_execute_shell(const char *s) | |||
2356 | char **argv, **pp, **pp2; | 2357 | char **argv, **pp, **pp2; |
2357 | unsigned cnt; | 2358 | unsigned cnt; |
2358 | 2359 | ||
2359 | /* 1:hush 2:-$<pid> 3:-?<exitcode> 4:-D<depth> <vars...> | 2360 | /* 1:hush 2:-$<pid> 3:-!<pid> 4:-?<exitcode> 5:-D<depth> <vars...> |
2360 | * 5:-c 6:<cmd> <argN...> 7:NULL | 2361 | * 6:-c 7:<cmd> <argN...> 8:NULL |
2361 | */ | 2362 | */ |
2362 | cnt = 7 + G.global_argc; | 2363 | cnt = 8 + G.global_argc; |
2363 | for (cur = G.top_var; cur; cur = cur->next) { | 2364 | for (cur = G.top_var; cur; cur = cur->next) { |
2364 | if (!cur->flg_export || cur->flg_read_only) | 2365 | if (!cur->flg_export || cur->flg_read_only) |
2365 | cnt += 2; | 2366 | cnt += 2; |
2366 | } | 2367 | } |
2367 | G.argv_for_re_execing = pp = xzalloc(sizeof(argv[0]) * cnt); | 2368 | G.argv_from_re_execing = pp = xzalloc(sizeof(argv[0]) * cnt); |
2368 | *pp++ = (char *) applet_name; | 2369 | *pp++ = (char *) G.argv0_for_re_execing; |
2369 | *pp++ = xasprintf("-$%u", G.root_pid); | 2370 | *pp++ = xasprintf("-$%u", (unsigned) G.root_pid); |
2370 | *pp++ = xasprintf("-?%u", G.last_return_code); | 2371 | *pp++ = xasprintf("-!%u", (unsigned) G.last_bg_pid); |
2372 | *pp++ = xasprintf("-?%u", (unsigned) G.last_return_code); | ||
2371 | #if ENABLE_HUSH_LOOPS | 2373 | #if ENABLE_HUSH_LOOPS |
2372 | *pp++ = xasprintf("-D%u", G.depth_of_loop); | 2374 | *pp++ = xasprintf("-D%u", G.depth_of_loop); |
2373 | #endif | 2375 | #endif |
@@ -2392,23 +2394,27 @@ static void re_execute_shell(const char *s) | |||
2392 | 2394 | ||
2393 | debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); | 2395 | debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); |
2394 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); | 2396 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); |
2395 | execv(bb_busybox_exec_path, G.argv_for_re_execing); | 2397 | execv(bb_busybox_exec_path, G.argv_from_re_execing); |
2396 | //TODO: fallback for init=/bin/hush? | 2398 | /* Fallback. Useful for init=/bin/hush usage etc */ |
2397 | _exit(127); | 2399 | if (G.argv0_for_re_execing[0] == '/') |
2400 | execv(G.argv0_for_re_execing, G.argv_from_re_execing); | ||
2401 | xfunc_error_retval = 127; | ||
2402 | bb_error_msg_and_die("can't re-execute the shell"); | ||
2398 | } | 2403 | } |
2399 | 2404 | ||
2400 | static void clean_up_after_re_execute(void) | 2405 | static void clean_up_after_re_execute(void) |
2401 | { | 2406 | { |
2402 | char **pp = G.argv_for_re_execing; | 2407 | char **pp = G.argv_from_re_execing; |
2403 | if (pp) { | 2408 | if (pp) { |
2404 | /* Must match re_execute_shell's allocations */ | 2409 | /* Must match re_execute_shell's allocations */ |
2405 | free(pp[1]); | 2410 | free(pp[1]); |
2406 | free(pp[2]); | 2411 | free(pp[2]); |
2407 | #if ENABLE_HUSH_LOOPS | ||
2408 | free(pp[3]); | 2412 | free(pp[3]); |
2413 | #if ENABLE_HUSH_LOOPS | ||
2414 | free(pp[4]); | ||
2409 | #endif | 2415 | #endif |
2410 | free(pp); | 2416 | free(pp); |
2411 | G.argv_for_re_execing = NULL; | 2417 | G.argv_from_re_execing = NULL; |
2412 | } | 2418 | } |
2413 | } | 2419 | } |
2414 | #else | 2420 | #else |
@@ -3001,8 +3007,8 @@ static void debug_print_tree(struct pipe *pi, int lvl) | |||
3001 | [RES_SNTX ] = "SNTX" , | 3007 | [RES_SNTX ] = "SNTX" , |
3002 | }; | 3008 | }; |
3003 | static const char *const GRPTYPE[] = { | 3009 | static const char *const GRPTYPE[] = { |
3004 | "()", | ||
3005 | "{}", | 3010 | "{}", |
3011 | "()", | ||
3006 | #if ENABLE_HUSH_FUNCTIONS | 3012 | #if ENABLE_HUSH_FUNCTIONS |
3007 | "func()", | 3013 | "func()", |
3008 | #endif | 3014 | #endif |
@@ -4990,14 +4996,15 @@ int hush_main(int argc, char **argv) | |||
4990 | }; | 4996 | }; |
4991 | 4997 | ||
4992 | int opt; | 4998 | int opt; |
4993 | FILE *input; | ||
4994 | char **e; | 4999 | char **e; |
4995 | struct variable *cur_var; | 5000 | struct variable *cur_var; |
4996 | 5001 | ||
4997 | INIT_G(); | 5002 | INIT_G(); |
4998 | 5003 | if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, is already done */ | |
4999 | G.root_pid = getpid(); | 5004 | G.last_return_code = EXIT_SUCCESS; |
5000 | 5005 | #if !BB_MMU | |
5006 | G.argv0_for_re_execing = argv[0]; | ||
5007 | #endif | ||
5001 | /* Deal with HUSH_VERSION */ | 5008 | /* Deal with HUSH_VERSION */ |
5002 | G.shell_ver = const_shell_ver; /* copying struct here */ | 5009 | G.shell_ver = const_shell_ver; /* copying struct here */ |
5003 | G.top_var = &G.shell_ver; | 5010 | G.top_var = &G.shell_ver; |
@@ -5020,11 +5027,9 @@ int hush_main(int argc, char **argv) | |||
5020 | } | 5027 | } |
5021 | debug_printf_env("putenv '%s'\n", hush_version_str); | 5028 | debug_printf_env("putenv '%s'\n", hush_version_str); |
5022 | putenv((char *)hush_version_str); /* reinstate HUSH_VERSION */ | 5029 | putenv((char *)hush_version_str); /* reinstate HUSH_VERSION */ |
5023 | |||
5024 | #if ENABLE_FEATURE_EDITING | 5030 | #if ENABLE_FEATURE_EDITING |
5025 | G.line_input_state = new_line_input_t(FOR_SHELL); | 5031 | G.line_input_state = new_line_input_t(FOR_SHELL); |
5026 | #endif | 5032 | #endif |
5027 | /* XXX what should these be while sourcing /etc/profile? */ | ||
5028 | G.global_argc = argc; | 5033 | G.global_argc = argc; |
5029 | G.global_argv = argv; | 5034 | G.global_argv = argv; |
5030 | /* Initialize some more globals to non-zero values */ | 5035 | /* Initialize some more globals to non-zero values */ |
@@ -5035,31 +5040,19 @@ int hush_main(int argc, char **argv) | |||
5035 | G.PS2 = "> "; | 5040 | G.PS2 = "> "; |
5036 | #endif | 5041 | #endif |
5037 | 5042 | ||
5038 | if (EXIT_SUCCESS) /* otherwise is already done */ | ||
5039 | G.last_return_code = EXIT_SUCCESS; | ||
5040 | |||
5041 | if (argv[0] && argv[0][0] == '-') { | ||
5042 | debug_printf("sourcing /etc/profile\n"); | ||
5043 | input = fopen_for_read("/etc/profile"); | ||
5044 | if (input != NULL) { | ||
5045 | close_on_exec_on(fileno(input)); | ||
5046 | parse_and_run_file(input); | ||
5047 | fclose(input); | ||
5048 | } | ||
5049 | } | ||
5050 | input = stdin; | ||
5051 | |||
5052 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ | 5043 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ |
5053 | while (1) { | 5044 | while (1) { |
5054 | opt = getopt(argc, argv, "c:xins" | 5045 | opt = getopt(argc, argv, "c:xins" |
5055 | #if !BB_MMU | 5046 | #if !BB_MMU |
5056 | "$:?:D:R:V:" | 5047 | "$:!:?:D:R:V:" |
5057 | #endif | 5048 | #endif |
5058 | ); | 5049 | ); |
5059 | if (opt <= 0) | 5050 | if (opt <= 0) |
5060 | break; | 5051 | break; |
5061 | switch (opt) { | 5052 | switch (opt) { |
5062 | case 'c': | 5053 | case 'c': |
5054 | if (!G.root_pid) | ||
5055 | G.root_pid = getpid(); | ||
5063 | G.global_argv = argv + optind; | 5056 | G.global_argv = argv + optind; |
5064 | if (!argv[optind]) { | 5057 | if (!argv[optind]) { |
5065 | /* -c 'script' (no params): prevent empty $0 */ | 5058 | /* -c 'script' (no params): prevent empty $0 */ |
@@ -5082,6 +5075,9 @@ int hush_main(int argc, char **argv) | |||
5082 | case '$': | 5075 | case '$': |
5083 | G.root_pid = xatoi_u(optarg); | 5076 | G.root_pid = xatoi_u(optarg); |
5084 | break; | 5077 | break; |
5078 | case '!': | ||
5079 | G.last_bg_pid = xatoi_u(optarg); | ||
5080 | break; | ||
5085 | case '?': | 5081 | case '?': |
5086 | G.last_return_code = xatoi_u(optarg); | 5082 | G.last_return_code = xatoi_u(optarg); |
5087 | break; | 5083 | break; |
@@ -5109,6 +5105,21 @@ int hush_main(int argc, char **argv) | |||
5109 | #endif | 5105 | #endif |
5110 | } | 5106 | } |
5111 | } | 5107 | } |
5108 | |||
5109 | if (!G.root_pid) | ||
5110 | G.root_pid = getpid(); | ||
5111 | if (argv[0] && argv[0][0] == '-') { | ||
5112 | FILE *input; | ||
5113 | /* XXX what should argv be while sourcing /etc/profile? */ | ||
5114 | debug_printf("sourcing /etc/profile\n"); | ||
5115 | input = fopen_for_read("/etc/profile"); | ||
5116 | if (input != NULL) { | ||
5117 | close_on_exec_on(fileno(input)); | ||
5118 | parse_and_run_file(input); | ||
5119 | fclose(input); | ||
5120 | } | ||
5121 | } | ||
5122 | |||
5112 | #if ENABLE_HUSH_JOB | 5123 | #if ENABLE_HUSH_JOB |
5113 | /* A shell is interactive if the '-i' flag was given, or if all of | 5124 | /* A shell is interactive if the '-i' flag was given, or if all of |
5114 | * the following conditions are met: | 5125 | * the following conditions are met: |
@@ -5117,7 +5128,7 @@ int hush_main(int argc, char **argv) | |||
5117 | * standard input is a terminal | 5128 | * standard input is a terminal |
5118 | * standard output is a terminal | 5129 | * standard output is a terminal |
5119 | * Refer to Posix.2, the description of the 'sh' utility. */ | 5130 | * Refer to Posix.2, the description of the 'sh' utility. */ |
5120 | if (argv[optind] == NULL && input == stdin | 5131 | if (argv[optind] == NULL |
5121 | && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) | 5132 | && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) |
5122 | ) { | 5133 | ) { |
5123 | G.saved_tty_pgrp = tcgetpgrp(STDIN_FILENO); | 5134 | G.saved_tty_pgrp = tcgetpgrp(STDIN_FILENO); |
@@ -5132,8 +5143,8 @@ int hush_main(int argc, char **argv) | |||
5132 | /* give up */ | 5143 | /* give up */ |
5133 | G_interactive_fd = 0; | 5144 | G_interactive_fd = 0; |
5134 | } | 5145 | } |
5135 | // TODO: track & disallow any attempts of user | 5146 | // TODO: track & disallow any attempts of user |
5136 | // to (inadvertently) close/redirect it | 5147 | // to (inadvertently) close/redirect it |
5137 | } | 5148 | } |
5138 | } | 5149 | } |
5139 | init_signal_mask(); /* note: ensures SIGCHLD is not masked */ | 5150 | init_signal_mask(); /* note: ensures SIGCHLD is not masked */ |
@@ -5152,7 +5163,7 @@ int hush_main(int argc, char **argv) | |||
5152 | } | 5163 | } |
5153 | #elif ENABLE_HUSH_INTERACTIVE | 5164 | #elif ENABLE_HUSH_INTERACTIVE |
5154 | /* no job control compiled, only prompt/line editing */ | 5165 | /* no job control compiled, only prompt/line editing */ |
5155 | if (argv[optind] == NULL && input == stdin | 5166 | if (argv[optind] == NULL |
5156 | && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) | 5167 | && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) |
5157 | ) { | 5168 | ) { |
5158 | G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); | 5169 | G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); |
@@ -5169,10 +5180,12 @@ int hush_main(int argc, char **argv) | |||
5169 | } | 5180 | } |
5170 | init_signal_mask(); /* note: ensures SIGCHLD is not masked */ | 5181 | init_signal_mask(); /* note: ensures SIGCHLD is not masked */ |
5171 | #else | 5182 | #else |
5183 | //TODO: we didn't do it for -c or /etc/profile! Shouldn't we? | ||
5172 | init_signal_mask(); | 5184 | init_signal_mask(); |
5173 | #endif | 5185 | #endif |
5174 | /* POSIX allows shell to re-enable SIGCHLD | 5186 | /* POSIX allows shell to re-enable SIGCHLD |
5175 | * even if it was SIG_IGN on entry */ | 5187 | * even if it was SIG_IGN on entry */ |
5188 | //TODO: we didn't do it for -c or /etc/profile! Shouldn't we? | ||
5176 | // G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ | 5189 | // G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ |
5177 | signal(SIGCHLD, SIG_DFL); // SIGCHLD_handler); | 5190 | signal(SIGCHLD, SIG_DFL); // SIGCHLD_handler); |
5178 | 5191 | ||
@@ -5186,18 +5199,21 @@ int hush_main(int argc, char **argv) | |||
5186 | if (argv[optind] == NULL) { | 5199 | if (argv[optind] == NULL) { |
5187 | parse_and_run_file(stdin); | 5200 | parse_and_run_file(stdin); |
5188 | } else { | 5201 | } else { |
5202 | FILE *input; | ||
5189 | debug_printf("\nrunning script '%s'\n", argv[optind]); | 5203 | debug_printf("\nrunning script '%s'\n", argv[optind]); |
5190 | G.global_argv = argv + optind; | 5204 | G.global_argv = argv + optind; |
5191 | G.global_argc = argc - optind; | 5205 | G.global_argc = argc - optind; |
5192 | input = xfopen_for_read(argv[optind]); | 5206 | input = xfopen_for_read(argv[optind]); |
5193 | fcntl(fileno(input), F_SETFD, FD_CLOEXEC); | 5207 | fcntl(fileno(input), F_SETFD, FD_CLOEXEC); |
5194 | parse_and_run_file(input); | 5208 | parse_and_run_file(input); |
5209 | #if ENABLE_FEATURE_CLEAN_UP | ||
5210 | fclose(input); | ||
5211 | #endif | ||
5195 | } | 5212 | } |
5196 | 5213 | ||
5197 | final_return: | 5214 | final_return: |
5198 | 5215 | ||
5199 | #if ENABLE_FEATURE_CLEAN_UP | 5216 | #if ENABLE_FEATURE_CLEAN_UP |
5200 | fclose(input); | ||
5201 | if (G.cwd != bb_msg_unknown) | 5217 | if (G.cwd != bb_msg_unknown) |
5202 | free((char*)G.cwd); | 5218 | free((char*)G.cwd); |
5203 | cur_var = G.top_var->next; | 5219 | cur_var = G.top_var->next; |