From 40e84374ec658ab44e3065b170d268b0ea0cbb27 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Sat, 18 Apr 2009 11:23:38 +0000 Subject: hush: implement unset -f; beautify the handling of signal-killed pipe four TODOs are gone function old new delta builtin_unset 271 364 +93 checkjobs 394 428 +34 builtin_exit 49 47 -2 --- shell/hush.c | 91 +++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 23 deletions(-) (limited to 'shell/hush.c') diff --git a/shell/hush.c b/shell/hush.c index edb67747e..1da9707e0 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1185,7 +1185,6 @@ static int check_and_run_traps(int sig) // G.count_SIGCHLD++; // break; case SIGINT: -//TODO: add putchar('\n') also when we detect that child was killed (sleep 5 + ^C) /* Builtin was ^C'ed, make it look prettier: */ bb_putchar('\n'); G.flag_SIGINT = 1; @@ -2842,6 +2841,31 @@ static struct function *new_function(char *name) return funcp; } +static void unset_func(const char *name) +{ + struct function *funcp; + struct function **funcpp = &G.top_func; + + while ((funcp = *funcpp) != NULL) { + if (strcmp(funcp->name, name) == 0) { + *funcpp = funcp->next; + /* funcp is unlinked now, deleting it */ + free(funcp->name); + /* Note: if !funcp->body, do not free body_as_string! + * This is a special case of "-F name body" function: + * body_as_string was not malloced! */ + if (funcp->body) { + free_pipe_list(funcp->body); +#if !BB_MMU + free(funcp->body_as_string); +#endif + } + free(funcp); + break; + } + } +} + #if BB_MMU #define exec_function(nommu_save, funcp, argv) \ exec_function(funcp, argv) @@ -3223,6 +3247,13 @@ static int checkjobs(struct pipe* fg_pipe) /* last process gives overall exitstatus */ rcode = WEXITSTATUS(status); IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) + /* bash prints killing signal's name for *last* + * process in pipe (prints just newline for SIGINT). + * we just print newline for any sig: + */ + if (WIFSIGNALED(status)) { + bb_putchar('\n'); + } } } else { fg_pipe->cmds[i].is_stopped = 1; @@ -6372,11 +6403,19 @@ static int builtin_exec(char **argv) static int builtin_exit(char **argv) { debug_printf_exec("%s()\n", __func__); -// TODO: bash does it ONLY on top-level sh exit (+interacive only?) - //puts("exit"); /* bash does it */ -// TODO: warn if we have background jobs: "There are stopped jobs" -// On second consecutive 'exit', exit anyway. -// perhaps use G.exiting = -1 as indicator "last cmd was exit" + + /* interactive bash: + * # trap "echo EEE" EXIT + * # exit + * exit + * There are stopped jobs. + * (if there are _stopped_ jobs, running ones don't count) + * # exit + * exit + # EEE (then bash exits) + * + * we can use G.exiting = -1 as indicator "last cmd was exit" + */ /* note: EXIT trap is run by hush_exit */ if (*++argv == NULL) @@ -6776,28 +6815,34 @@ static int builtin_unset(char **argv) { int ret; char var; + char *arg; if (!*++argv) return EXIT_SUCCESS; - var = 'v'; - if (argv[0][0] == '-') { - switch (argv[0][1]) { - case 'v': - case 'f': - var = argv[0][1]; - break; - default: - bb_error_msg("unset: %s: invalid option", *argv); - return EXIT_FAILURE; + var = 0; + while ((arg = *argv) != NULL && arg[0] == '-') { + while (*++arg) { + switch (*arg) { + case 'v': + case 'f': + if (var == 0 || var == *arg) { + var = *arg; + break; + } + /* else: unset -vf, which is illegal. + * fall through */ + default: + bb_error_msg("unset: %s: invalid option", *argv); + return EXIT_FAILURE; + } } -//TODO: disallow "unset -vf ..." too argv++; } ret = EXIT_SUCCESS; while (*argv) { - if (var == 'v') { + if (var != 'f') { if (unset_local_var(*argv)) { /* unset doesn't fail. * Error is when one tries to unset RO var. @@ -6805,11 +6850,11 @@ static int builtin_unset(char **argv) ret = EXIT_FAILURE; } } -//#if ENABLE_HUSH_FUNCTIONS -// else { -// unset_local_func(*argv); -// } -//#endif +#if ENABLE_HUSH_FUNCTIONS + else { + unset_func(*argv); + } +#endif argv++; } return ret; -- cgit v1.2.3