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 | |
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
-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; |