From 46f9b6db80e4fd0a1c50d435bc387ad28d12abb2 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Sun, 5 Apr 2009 10:39:03 +0000 Subject: 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 --- shell/hush.c | 98 +++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 57 insertions(+), 41 deletions(-) (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index 39d3c01..eba7a86 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -487,7 +487,8 @@ struct globals { int global_argc; char **global_argv; #if !BB_MMU - char **argv_for_re_execing; + char *argv0_for_re_execing; + char **argv_from_re_execing; #endif #if ENABLE_HUSH_LOOPS unsigned depth_break_continue; @@ -2356,18 +2357,19 @@ static void re_execute_shell(const char *s) char **argv, **pp, **pp2; unsigned cnt; - /* 1:hush 2:-$ 3:-? 4:-D - * 5:-c 6: 7:NULL + /* 1:hush 2:-$ 3:-! 4:-? 5:-D + * 6:-c 7: 8:NULL */ - cnt = 7 + G.global_argc; + cnt = 8 + G.global_argc; for (cur = G.top_var; cur; cur = cur->next) { if (!cur->flg_export || cur->flg_read_only) cnt += 2; } - G.argv_for_re_execing = pp = xzalloc(sizeof(argv[0]) * cnt); - *pp++ = (char *) applet_name; - *pp++ = xasprintf("-$%u", G.root_pid); - *pp++ = xasprintf("-?%u", G.last_return_code); + G.argv_from_re_execing = pp = xzalloc(sizeof(argv[0]) * cnt); + *pp++ = (char *) G.argv0_for_re_execing; + *pp++ = xasprintf("-$%u", (unsigned) G.root_pid); + *pp++ = xasprintf("-!%u", (unsigned) G.last_bg_pid); + *pp++ = xasprintf("-?%u", (unsigned) G.last_return_code); #if ENABLE_HUSH_LOOPS *pp++ = xasprintf("-D%u", G.depth_of_loop); #endif @@ -2392,23 +2394,27 @@ static void re_execute_shell(const char *s) debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); - execv(bb_busybox_exec_path, G.argv_for_re_execing); -//TODO: fallback for init=/bin/hush? - _exit(127); + execv(bb_busybox_exec_path, G.argv_from_re_execing); + /* Fallback. Useful for init=/bin/hush usage etc */ + if (G.argv0_for_re_execing[0] == '/') + execv(G.argv0_for_re_execing, G.argv_from_re_execing); + xfunc_error_retval = 127; + bb_error_msg_and_die("can't re-execute the shell"); } static void clean_up_after_re_execute(void) { - char **pp = G.argv_for_re_execing; + char **pp = G.argv_from_re_execing; if (pp) { /* Must match re_execute_shell's allocations */ free(pp[1]); free(pp[2]); -#if ENABLE_HUSH_LOOPS free(pp[3]); +#if ENABLE_HUSH_LOOPS + free(pp[4]); #endif free(pp); - G.argv_for_re_execing = NULL; + G.argv_from_re_execing = NULL; } } #else @@ -3001,8 +3007,8 @@ static void debug_print_tree(struct pipe *pi, int lvl) [RES_SNTX ] = "SNTX" , }; static const char *const GRPTYPE[] = { - "()", "{}", + "()", #if ENABLE_HUSH_FUNCTIONS "func()", #endif @@ -4990,14 +4996,15 @@ int hush_main(int argc, char **argv) }; int opt; - FILE *input; char **e; struct variable *cur_var; INIT_G(); - - G.root_pid = getpid(); - + if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, is already done */ + G.last_return_code = EXIT_SUCCESS; +#if !BB_MMU + G.argv0_for_re_execing = argv[0]; +#endif /* Deal with HUSH_VERSION */ G.shell_ver = const_shell_ver; /* copying struct here */ G.top_var = &G.shell_ver; @@ -5020,11 +5027,9 @@ int hush_main(int argc, char **argv) } debug_printf_env("putenv '%s'\n", hush_version_str); putenv((char *)hush_version_str); /* reinstate HUSH_VERSION */ - #if ENABLE_FEATURE_EDITING G.line_input_state = new_line_input_t(FOR_SHELL); #endif - /* XXX what should these be while sourcing /etc/profile? */ G.global_argc = argc; G.global_argv = argv; /* Initialize some more globals to non-zero values */ @@ -5035,31 +5040,19 @@ int hush_main(int argc, char **argv) G.PS2 = "> "; #endif - if (EXIT_SUCCESS) /* otherwise is already done */ - G.last_return_code = EXIT_SUCCESS; - - if (argv[0] && argv[0][0] == '-') { - debug_printf("sourcing /etc/profile\n"); - input = fopen_for_read("/etc/profile"); - if (input != NULL) { - close_on_exec_on(fileno(input)); - parse_and_run_file(input); - fclose(input); - } - } - input = stdin; - /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ while (1) { opt = getopt(argc, argv, "c:xins" #if !BB_MMU - "$:?:D:R:V:" + "$:!:?:D:R:V:" #endif ); if (opt <= 0) break; switch (opt) { case 'c': + if (!G.root_pid) + G.root_pid = getpid(); G.global_argv = argv + optind; if (!argv[optind]) { /* -c 'script' (no params): prevent empty $0 */ @@ -5082,6 +5075,9 @@ int hush_main(int argc, char **argv) case '$': G.root_pid = xatoi_u(optarg); break; + case '!': + G.last_bg_pid = xatoi_u(optarg); + break; case '?': G.last_return_code = xatoi_u(optarg); break; @@ -5109,6 +5105,21 @@ int hush_main(int argc, char **argv) #endif } } + + if (!G.root_pid) + G.root_pid = getpid(); + if (argv[0] && argv[0][0] == '-') { + FILE *input; + /* XXX what should argv be while sourcing /etc/profile? */ + debug_printf("sourcing /etc/profile\n"); + input = fopen_for_read("/etc/profile"); + if (input != NULL) { + close_on_exec_on(fileno(input)); + parse_and_run_file(input); + fclose(input); + } + } + #if ENABLE_HUSH_JOB /* A shell is interactive if the '-i' flag was given, or if all of * the following conditions are met: @@ -5117,7 +5128,7 @@ int hush_main(int argc, char **argv) * standard input is a terminal * standard output is a terminal * Refer to Posix.2, the description of the 'sh' utility. */ - if (argv[optind] == NULL && input == stdin + if (argv[optind] == NULL && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) ) { G.saved_tty_pgrp = tcgetpgrp(STDIN_FILENO); @@ -5132,8 +5143,8 @@ int hush_main(int argc, char **argv) /* give up */ G_interactive_fd = 0; } - // TODO: track & disallow any attempts of user - // to (inadvertently) close/redirect it +// TODO: track & disallow any attempts of user +// to (inadvertently) close/redirect it } } init_signal_mask(); /* note: ensures SIGCHLD is not masked */ @@ -5152,7 +5163,7 @@ int hush_main(int argc, char **argv) } #elif ENABLE_HUSH_INTERACTIVE /* no job control compiled, only prompt/line editing */ - if (argv[optind] == NULL && input == stdin + if (argv[optind] == NULL && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) ) { G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); @@ -5169,10 +5180,12 @@ int hush_main(int argc, char **argv) } init_signal_mask(); /* note: ensures SIGCHLD is not masked */ #else +//TODO: we didn't do it for -c or /etc/profile! Shouldn't we? init_signal_mask(); #endif /* POSIX allows shell to re-enable SIGCHLD * even if it was SIG_IGN on entry */ +//TODO: we didn't do it for -c or /etc/profile! Shouldn't we? // G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ signal(SIGCHLD, SIG_DFL); // SIGCHLD_handler); @@ -5186,18 +5199,21 @@ int hush_main(int argc, char **argv) if (argv[optind] == NULL) { parse_and_run_file(stdin); } else { + FILE *input; debug_printf("\nrunning script '%s'\n", argv[optind]); G.global_argv = argv + optind; G.global_argc = argc - optind; input = xfopen_for_read(argv[optind]); fcntl(fileno(input), F_SETFD, FD_CLOEXEC); parse_and_run_file(input); +#if ENABLE_FEATURE_CLEAN_UP + fclose(input); +#endif } final_return: #if ENABLE_FEATURE_CLEAN_UP - fclose(input); if (G.cwd != bb_msg_unknown) free((char*)G.cwd); cur_var = G.top_var->next; -- cgit v1.1