aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-18 11:23:38 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-18 11:23:38 +0000
commit40e84374ec658ab44e3065b170d268b0ea0cbb27 (patch)
tree45d4a5adf332c928c7a0759a117d1c5b2e17e325
parenteb85849b50a3c8af6ef0d3dbbf0fd1387e37d1f8 (diff)
downloadbusybox-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.c91
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
2844static 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)
6372static int builtin_exit(char **argv) 6403static 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;