mirror of
https://github.com/sheumann/hush.git
synced 2024-12-22 14:30:31 +00:00
first pass at trap
support in hush
This commit is contained in:
parent
0d907eab6c
commit
9f8128f480
139
shell/hush.c
139
shell/hush.c
@ -489,6 +489,10 @@ struct globals {
|
|||||||
#endif
|
#endif
|
||||||
unsigned char charmap[256];
|
unsigned char charmap[256];
|
||||||
char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2];
|
char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2];
|
||||||
|
struct {
|
||||||
|
char *cmd;
|
||||||
|
struct sigaction oact;
|
||||||
|
} *traps;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define G (*ptr_to_globals)
|
#define G (*ptr_to_globals)
|
||||||
@ -517,6 +521,8 @@ static int builtin_help(char **argv);
|
|||||||
static int builtin_pwd(char **argv);
|
static int builtin_pwd(char **argv);
|
||||||
static int builtin_read(char **argv);
|
static int builtin_read(char **argv);
|
||||||
static int builtin_test(char **argv);
|
static int builtin_test(char **argv);
|
||||||
|
static void handle_trap(int sig);
|
||||||
|
static int builtin_trap(char **argv);
|
||||||
static int builtin_true(char **argv);
|
static int builtin_true(char **argv);
|
||||||
static int builtin_set(char **argv);
|
static int builtin_set(char **argv);
|
||||||
static int builtin_set_mode(const char, const char);
|
static int builtin_set_mode(const char, const char);
|
||||||
@ -578,8 +584,8 @@ static const struct built_in_command bltins[] = {
|
|||||||
// BLTIN("return", builtin_not_written, "Return from a function"),
|
// BLTIN("return", builtin_not_written, "Return from a function"),
|
||||||
BLTIN("set" , builtin_set, "Set/unset shell local variables"),
|
BLTIN("set" , builtin_set, "Set/unset shell local variables"),
|
||||||
BLTIN("shift" , builtin_shift, "Shift positional parameters"),
|
BLTIN("shift" , builtin_shift, "Shift positional parameters"),
|
||||||
// BLTIN("trap" , builtin_not_written, "Trap signals"),
|
|
||||||
BLTIN("test" , builtin_test, "Test condition"),
|
BLTIN("test" , builtin_test, "Test condition"),
|
||||||
|
BLTIN("trap" , builtin_trap, "Trap signals"),
|
||||||
// BLTIN("ulimit", builtin_not_written, "Control resource limits"),
|
// BLTIN("ulimit", builtin_not_written, "Control resource limits"),
|
||||||
BLTIN("umask" , builtin_umask, "Set file creation mask"),
|
BLTIN("umask" , builtin_umask, "Set file creation mask"),
|
||||||
BLTIN("unset" , builtin_unset, "Unset environment variable"),
|
BLTIN("unset" , builtin_unset, "Unset environment variable"),
|
||||||
@ -857,22 +863,27 @@ static void sigexit(int sig)
|
|||||||
kill_myself_with_sig(sig); /* does not return */
|
kill_myself_with_sig(sig); /* does not return */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restores tty foreground process group, and exits. */
|
|
||||||
static void hush_exit(int exitcode) NORETURN;
|
|
||||||
static void hush_exit(int exitcode)
|
|
||||||
{
|
|
||||||
fflush(NULL); /* flush all streams */
|
|
||||||
sigexit(- (exitcode & 0xff));
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* !JOB */
|
#else /* !JOB */
|
||||||
|
|
||||||
#define set_fatal_sighandler(handler) ((void)0)
|
#define set_fatal_sighandler(handler) ((void)0)
|
||||||
#define set_jobctrl_sighandler(handler) ((void)0)
|
#define set_jobctrl_sighandler(handler) ((void)0)
|
||||||
#define hush_exit(e) exit(e)
|
|
||||||
|
|
||||||
#endif /* JOB */
|
#endif /* JOB */
|
||||||
|
|
||||||
|
/* Restores tty foreground process group, and exits. */
|
||||||
|
static void hush_exit(int exitcode) NORETURN;
|
||||||
|
static void hush_exit(int exitcode)
|
||||||
|
{
|
||||||
|
if (G.traps && G.traps[0].cmd)
|
||||||
|
handle_trap(0);
|
||||||
|
|
||||||
|
if (ENABLE_HUSH_JOB) {
|
||||||
|
fflush(NULL); /* flush all streams */
|
||||||
|
sigexit(- (exitcode & 0xff));
|
||||||
|
} else
|
||||||
|
exit(exitcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char *set_cwd(void)
|
static const char *set_cwd(void)
|
||||||
{
|
{
|
||||||
@ -4516,6 +4527,114 @@ int lash_main(int argc, char **argv)
|
|||||||
/*
|
/*
|
||||||
* Built-ins
|
* Built-ins
|
||||||
*/
|
*/
|
||||||
|
/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_28
|
||||||
|
*
|
||||||
|
* Traps are also evaluated immediately instead of being delayed properly:
|
||||||
|
* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_11
|
||||||
|
* Example: hush -c 'trap "echo hi" 31; sleep 10; echo moo' & sleep 1; kill -31 $!
|
||||||
|
* "hi" should not be displayed until the sleep finishes
|
||||||
|
* This will have to get fixed ...
|
||||||
|
*/
|
||||||
|
static void handle_trap(int sig)
|
||||||
|
{
|
||||||
|
int save_errno, save_rcode;
|
||||||
|
char *argv[] = { NULL, G.traps[sig].cmd, NULL };
|
||||||
|
/* Race! We transitioned from handled to ignore/default, but
|
||||||
|
* the signal came in after updating .cmd but before we could
|
||||||
|
* register the new signal handler.
|
||||||
|
*/
|
||||||
|
if (!argv[1] || argv[1][0] == '\0')
|
||||||
|
return;
|
||||||
|
/* need to save/restore errno/$? across traps */
|
||||||
|
save_errno = errno;
|
||||||
|
save_rcode = G.last_return_code;
|
||||||
|
builtin_eval(argv);
|
||||||
|
errno = save_errno;
|
||||||
|
G.last_return_code = save_rcode;
|
||||||
|
}
|
||||||
|
static int builtin_trap(char **argv)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
int sig;
|
||||||
|
bool ign = false;
|
||||||
|
char *new_cmd = NULL;
|
||||||
|
|
||||||
|
if (!G.traps)
|
||||||
|
G.traps = xzalloc(sizeof(*G.traps) * NSIG);
|
||||||
|
|
||||||
|
if (!argv[1]) {
|
||||||
|
/* No args: print all trapped. This isn't 100% correct as we should
|
||||||
|
* be escaping the cmd so that it can be pasted back in ...
|
||||||
|
*/
|
||||||
|
for (i = 0; i < NSIG; ++i)
|
||||||
|
if (G.traps[i].cmd)
|
||||||
|
printf("trap -- '%s' %s\n", G.traps[i].cmd, get_signame(i));
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first arg is decimal: reset all specified */
|
||||||
|
sig = bb_strtou(argv[1], NULL, 10);
|
||||||
|
if (errno == 0) {
|
||||||
|
int ret;
|
||||||
|
i = 0;
|
||||||
|
set_all:
|
||||||
|
ret = EXIT_SUCCESS;
|
||||||
|
while (argv[++i]) {
|
||||||
|
char *old_cmd;
|
||||||
|
|
||||||
|
sig = get_signum(argv[i]);
|
||||||
|
if (sig < 0 || sig >= NSIG) {
|
||||||
|
ret = EXIT_FAILURE;
|
||||||
|
bb_perror_msg("trap: %s: invalid signal specification", argv[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure .cmd is always a valid command list since
|
||||||
|
* signals can occur at any time ...
|
||||||
|
*/
|
||||||
|
old_cmd = G.traps[sig].cmd;
|
||||||
|
G.traps[sig].cmd = xstrdup(new_cmd);
|
||||||
|
free(old_cmd);
|
||||||
|
|
||||||
|
debug_printf("trap: setting SIG%s (%i) to: %s",
|
||||||
|
get_signame(sig), sig, G.traps[sig].cmd);
|
||||||
|
|
||||||
|
/* There is no signal for 0 (EXIT) */
|
||||||
|
if (sig == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (new_cmd) {
|
||||||
|
/* add/update a handler */
|
||||||
|
struct sigaction act = {
|
||||||
|
.sa_handler = ign ? SIG_IGN : handle_trap,
|
||||||
|
.sa_flags = SA_RESTART,
|
||||||
|
};
|
||||||
|
sigemptyset(&act.sa_mask);
|
||||||
|
sigaction(sig, &act, old_cmd ? NULL : &G.traps[sig].oact);
|
||||||
|
} else if (old_cmd && !new_cmd)
|
||||||
|
/* there was a handler, and we are removing it */
|
||||||
|
sigaction_set(sig, &G.traps[sig].oact);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first arg is "-": reset all specified to default */
|
||||||
|
/* first arg is "": ignore all specified */
|
||||||
|
/* everything else: execute first arg upon signal */
|
||||||
|
if (!argv[2]) {
|
||||||
|
bb_error_msg("trap: invalid arguments");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if (LONE_DASH(argv[1]))
|
||||||
|
/* nothing! */;
|
||||||
|
else
|
||||||
|
new_cmd = argv[1];
|
||||||
|
if (argv[1][0] == '\0')
|
||||||
|
ign = true;
|
||||||
|
i = 1;
|
||||||
|
goto set_all;
|
||||||
|
}
|
||||||
|
|
||||||
static int builtin_true(char **argv UNUSED_PARAM)
|
static int builtin_true(char **argv UNUSED_PARAM)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user