summaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
authorDenis Vlasenko2009-04-18 11:23:38 +0000
committerDenis Vlasenko2009-04-18 11:23:38 +0000
commit40e84374ec658ab44e3065b170d268b0ea0cbb27 (patch)
tree45d4a5adf332c928c7a0759a117d1c5b2e17e325 /shell/hush.c
parenteb85849b50a3c8af6ef0d3dbbf0fd1387e37d1f8 (diff)
downloadbusybox-40e84374ec658ab44e3065b170d268b0ea0cbb27.zip
busybox-40e84374ec658ab44e3065b170d268b0ea0cbb27.tar.gz
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/hush.c')
-rw-r--r--shell/hush.c91
1 files changed, 68 insertions, 23 deletions
diff --git a/shell/hush.c b/shell/hush.c
index edb6774..1da9707 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 <nonexistent_var> 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;