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
This commit is contained in:
parent
eb85849b50
commit
40e84374ec
91
shell/hush.c
91
shell/hush.c
@ -1185,7 +1185,6 @@ static int check_and_run_traps(int sig)
|
|||||||
// G.count_SIGCHLD++;
|
// G.count_SIGCHLD++;
|
||||||
// break;
|
// break;
|
||||||
case SIGINT:
|
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: */
|
/* Builtin was ^C'ed, make it look prettier: */
|
||||||
bb_putchar('\n');
|
bb_putchar('\n');
|
||||||
G.flag_SIGINT = 1;
|
G.flag_SIGINT = 1;
|
||||||
@ -2842,6 +2841,31 @@ static struct function *new_function(char *name)
|
|||||||
return funcp;
|
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
|
#if BB_MMU
|
||||||
#define exec_function(nommu_save, funcp, argv) \
|
#define exec_function(nommu_save, funcp, argv) \
|
||||||
exec_function(funcp, argv)
|
exec_function(funcp, argv)
|
||||||
@ -3223,6 +3247,13 @@ static int checkjobs(struct pipe* fg_pipe)
|
|||||||
/* last process gives overall exitstatus */
|
/* last process gives overall exitstatus */
|
||||||
rcode = WEXITSTATUS(status);
|
rcode = WEXITSTATUS(status);
|
||||||
IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;)
|
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 {
|
} else {
|
||||||
fg_pipe->cmds[i].is_stopped = 1;
|
fg_pipe->cmds[i].is_stopped = 1;
|
||||||
@ -6372,11 +6403,19 @@ static int builtin_exec(char **argv)
|
|||||||
static int builtin_exit(char **argv)
|
static int builtin_exit(char **argv)
|
||||||
{
|
{
|
||||||
debug_printf_exec("%s()\n", __func__);
|
debug_printf_exec("%s()\n", __func__);
|
||||||
// TODO: bash does it ONLY on top-level sh exit (+interacive only?)
|
|
||||||
//puts("exit"); /* bash does it */
|
/* interactive bash:
|
||||||
// TODO: warn if we have background jobs: "There are stopped jobs"
|
* # trap "echo EEE" EXIT
|
||||||
// On second consecutive 'exit', exit anyway.
|
* # exit
|
||||||
// perhaps use G.exiting = -1 as indicator "last cmd was 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 */
|
/* note: EXIT trap is run by hush_exit */
|
||||||
if (*++argv == NULL)
|
if (*++argv == NULL)
|
||||||
@ -6776,28 +6815,34 @@ static int builtin_unset(char **argv)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
char var;
|
char var;
|
||||||
|
char *arg;
|
||||||
|
|
||||||
if (!*++argv)
|
if (!*++argv)
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
var = 'v';
|
var = 0;
|
||||||
if (argv[0][0] == '-') {
|
while ((arg = *argv) != NULL && arg[0] == '-') {
|
||||||
switch (argv[0][1]) {
|
while (*++arg) {
|
||||||
case 'v':
|
switch (*arg) {
|
||||||
case 'f':
|
case 'v':
|
||||||
var = argv[0][1];
|
case 'f':
|
||||||
break;
|
if (var == 0 || var == *arg) {
|
||||||
default:
|
var = *arg;
|
||||||
bb_error_msg("unset: %s: invalid option", *argv);
|
break;
|
||||||
return EXIT_FAILURE;
|
}
|
||||||
|
/* 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++;
|
argv++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = EXIT_SUCCESS;
|
ret = EXIT_SUCCESS;
|
||||||
while (*argv) {
|
while (*argv) {
|
||||||
if (var == 'v') {
|
if (var != 'f') {
|
||||||
if (unset_local_var(*argv)) {
|
if (unset_local_var(*argv)) {
|
||||||
/* unset <nonexistent_var> doesn't fail.
|
/* unset <nonexistent_var> doesn't fail.
|
||||||
* Error is when one tries to unset RO var.
|
* Error is when one tries to unset RO var.
|
||||||
@ -6805,11 +6850,11 @@ static int builtin_unset(char **argv)
|
|||||||
ret = EXIT_FAILURE;
|
ret = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//#if ENABLE_HUSH_FUNCTIONS
|
#if ENABLE_HUSH_FUNCTIONS
|
||||||
// else {
|
else {
|
||||||
// unset_local_func(*argv);
|
unset_func(*argv);
|
||||||
// }
|
}
|
||||||
//#endif
|
#endif
|
||||||
argv++;
|
argv++;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user