diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-18 11:23:38 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-18 11:23:38 +0000 |
| commit | 40e84374ec658ab44e3065b170d268b0ea0cbb27 (patch) | |
| tree | 45d4a5adf332c928c7a0759a117d1c5b2e17e325 /shell | |
| parent | eb85849b50a3c8af6ef0d3dbbf0fd1387e37d1f8 (diff) | |
| download | busybox-w32-40e84374ec658ab44e3065b170d268b0ea0cbb27.tar.gz busybox-w32-40e84374ec658ab44e3065b170d268b0ea0cbb27.tar.bz2 busybox-w32-40e84374ec658ab44e3065b170d268b0ea0cbb27.zip | |
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
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/hush.c | 91 |
1 files changed, 68 insertions, 23 deletions
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) | |||
| 1185 | // G.count_SIGCHLD++; | 1185 | // G.count_SIGCHLD++; |
| 1186 | // break; | 1186 | // break; |
| 1187 | case SIGINT: | 1187 | case SIGINT: |
| 1188 | //TODO: add putchar('\n') also when we detect that child was killed (sleep 5 + ^C) | ||
| 1189 | /* Builtin was ^C'ed, make it look prettier: */ | 1188 | /* Builtin was ^C'ed, make it look prettier: */ |
| 1190 | bb_putchar('\n'); | 1189 | bb_putchar('\n'); |
| 1191 | G.flag_SIGINT = 1; | 1190 | G.flag_SIGINT = 1; |
| @@ -2842,6 +2841,31 @@ static struct function *new_function(char *name) | |||
| 2842 | return funcp; | 2841 | return funcp; |
| 2843 | } | 2842 | } |
| 2844 | 2843 | ||
| 2844 | static void unset_func(const char *name) | ||
| 2845 | { | ||
| 2846 | struct function *funcp; | ||
| 2847 | struct function **funcpp = &G.top_func; | ||
| 2848 | |||
| 2849 | while ((funcp = *funcpp) != NULL) { | ||
| 2850 | if (strcmp(funcp->name, name) == 0) { | ||
| 2851 | *funcpp = funcp->next; | ||
| 2852 | /* funcp is unlinked now, deleting it */ | ||
| 2853 | free(funcp->name); | ||
| 2854 | /* Note: if !funcp->body, do not free body_as_string! | ||
| 2855 | * This is a special case of "-F name body" function: | ||
| 2856 | * body_as_string was not malloced! */ | ||
| 2857 | if (funcp->body) { | ||
| 2858 | free_pipe_list(funcp->body); | ||
| 2859 | #if !BB_MMU | ||
| 2860 | free(funcp->body_as_string); | ||
| 2861 | #endif | ||
| 2862 | } | ||
| 2863 | free(funcp); | ||
| 2864 | break; | ||
| 2865 | } | ||
| 2866 | } | ||
| 2867 | } | ||
| 2868 | |||
| 2845 | #if BB_MMU | 2869 | #if BB_MMU |
| 2846 | #define exec_function(nommu_save, funcp, argv) \ | 2870 | #define exec_function(nommu_save, funcp, argv) \ |
| 2847 | exec_function(funcp, argv) | 2871 | exec_function(funcp, argv) |
| @@ -3223,6 +3247,13 @@ static int checkjobs(struct pipe* fg_pipe) | |||
| 3223 | /* last process gives overall exitstatus */ | 3247 | /* last process gives overall exitstatus */ |
| 3224 | rcode = WEXITSTATUS(status); | 3248 | rcode = WEXITSTATUS(status); |
| 3225 | IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) | 3249 | IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) |
| 3250 | /* bash prints killing signal's name for *last* | ||
| 3251 | * process in pipe (prints just newline for SIGINT). | ||
| 3252 | * we just print newline for any sig: | ||
| 3253 | */ | ||
| 3254 | if (WIFSIGNALED(status)) { | ||
| 3255 | bb_putchar('\n'); | ||
| 3256 | } | ||
| 3226 | } | 3257 | } |
| 3227 | } else { | 3258 | } else { |
| 3228 | fg_pipe->cmds[i].is_stopped = 1; | 3259 | fg_pipe->cmds[i].is_stopped = 1; |
| @@ -6372,11 +6403,19 @@ static int builtin_exec(char **argv) | |||
| 6372 | static int builtin_exit(char **argv) | 6403 | static int builtin_exit(char **argv) |
| 6373 | { | 6404 | { |
| 6374 | debug_printf_exec("%s()\n", __func__); | 6405 | debug_printf_exec("%s()\n", __func__); |
| 6375 | // TODO: bash does it ONLY on top-level sh exit (+interacive only?) | 6406 | |
| 6376 | //puts("exit"); /* bash does it */ | 6407 | /* interactive bash: |
| 6377 | // TODO: warn if we have background jobs: "There are stopped jobs" | 6408 | * # trap "echo EEE" EXIT |
| 6378 | // On second consecutive 'exit', exit anyway. | 6409 | * # exit |
| 6379 | // perhaps use G.exiting = -1 as indicator "last cmd was exit" | 6410 | * exit |
| 6411 | * There are stopped jobs. | ||
| 6412 | * (if there are _stopped_ jobs, running ones don't count) | ||
| 6413 | * # exit | ||
| 6414 | * exit | ||
| 6415 | # EEE (then bash exits) | ||
| 6416 | * | ||
| 6417 | * we can use G.exiting = -1 as indicator "last cmd was exit" | ||
| 6418 | */ | ||
| 6380 | 6419 | ||
| 6381 | /* note: EXIT trap is run by hush_exit */ | 6420 | /* note: EXIT trap is run by hush_exit */ |
| 6382 | if (*++argv == NULL) | 6421 | if (*++argv == NULL) |
| @@ -6776,28 +6815,34 @@ static int builtin_unset(char **argv) | |||
| 6776 | { | 6815 | { |
| 6777 | int ret; | 6816 | int ret; |
| 6778 | char var; | 6817 | char var; |
| 6818 | char *arg; | ||
| 6779 | 6819 | ||
| 6780 | if (!*++argv) | 6820 | if (!*++argv) |
| 6781 | return EXIT_SUCCESS; | 6821 | return EXIT_SUCCESS; |
| 6782 | 6822 | ||
| 6783 | var = 'v'; | 6823 | var = 0; |
| 6784 | if (argv[0][0] == '-') { | 6824 | while ((arg = *argv) != NULL && arg[0] == '-') { |
| 6785 | switch (argv[0][1]) { | 6825 | while (*++arg) { |
| 6786 | case 'v': | 6826 | switch (*arg) { |
| 6787 | case 'f': | 6827 | case 'v': |
| 6788 | var = argv[0][1]; | 6828 | case 'f': |
| 6789 | break; | 6829 | if (var == 0 || var == *arg) { |
| 6790 | default: | 6830 | var = *arg; |
| 6791 | bb_error_msg("unset: %s: invalid option", *argv); | 6831 | break; |
| 6792 | return EXIT_FAILURE; | 6832 | } |
| 6833 | /* else: unset -vf, which is illegal. | ||
| 6834 | * fall through */ | ||
| 6835 | default: | ||
| 6836 | bb_error_msg("unset: %s: invalid option", *argv); | ||
| 6837 | return EXIT_FAILURE; | ||
| 6838 | } | ||
| 6793 | } | 6839 | } |
| 6794 | //TODO: disallow "unset -vf ..." too | ||
| 6795 | argv++; | 6840 | argv++; |
| 6796 | } | 6841 | } |
| 6797 | 6842 | ||
| 6798 | ret = EXIT_SUCCESS; | 6843 | ret = EXIT_SUCCESS; |
| 6799 | while (*argv) { | 6844 | while (*argv) { |
| 6800 | if (var == 'v') { | 6845 | if (var != 'f') { |
| 6801 | if (unset_local_var(*argv)) { | 6846 | if (unset_local_var(*argv)) { |
| 6802 | /* unset <nonexistent_var> doesn't fail. | 6847 | /* unset <nonexistent_var> doesn't fail. |
| 6803 | * Error is when one tries to unset RO var. | 6848 | * Error is when one tries to unset RO var. |
| @@ -6805,11 +6850,11 @@ static int builtin_unset(char **argv) | |||
| 6805 | ret = EXIT_FAILURE; | 6850 | ret = EXIT_FAILURE; |
| 6806 | } | 6851 | } |
| 6807 | } | 6852 | } |
| 6808 | //#if ENABLE_HUSH_FUNCTIONS | 6853 | #if ENABLE_HUSH_FUNCTIONS |
| 6809 | // else { | 6854 | else { |
| 6810 | // unset_local_func(*argv); | 6855 | unset_func(*argv); |
| 6811 | // } | 6856 | } |
| 6812 | //#endif | 6857 | #endif |
| 6813 | argv++; | 6858 | argv++; |
| 6814 | } | 6859 | } |
| 6815 | return ret; | 6860 | return ret; |
