rc

[fork] interactive rc shell
Log | Files | Refs | README | LICENSE

commit da63ba04988e68bca1395eff60cc362ea14e3c34
parent 134ea56bac17a42cf71742807a50f4ca4ac72474
Author: Bert Münnich <ber.t@posteo.de>
Date:   Sat, 18 Nov 2017 13:58:07 +0100

Restore tty attributes if interactive child is terminated by signal

Some programs like su(1) do not restore tty attributes like ECHO when they are
terminated by receiving SIGINT. Other shells (bash, mksh, zsh) save tty
attributes before executing an external command and restore them if the child
exited due to the receipt of a signal. rc now does the same if it is
interactive.

Diffstat:
Mexec.c | 7+++++++
Mglom.c | 7+++++++
Mwalk.c | 14+++++++++++++-
3 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/exec.c b/exec.c @@ -4,6 +4,8 @@ #include <errno.h> #include <signal.h> +#include <termios.h> +#include <unistd.h> #include "wait.h" @@ -19,6 +21,7 @@ extern void exec(List *s, bool parent) { builtin_t *b; char *path = NULL; bool didfork, returning, saw_exec, saw_builtin; + struct termios t; av = list2array(s, dashex); saw_builtin = saw_exec = FALSE; do { @@ -68,6 +71,8 @@ extern void exec(List *s, bool parent) { must fork no matter what. */ if ((parent && (b == NULL || redirq != NULL)) || outstanding_cmdarg()) { + if (interactive) + tcgetattr(0, &t); pid = rc_fork(); didfork = TRUE; } else { @@ -110,6 +115,8 @@ extern void exec(List *s, bool parent) { default: redirq = NULL; rc_wait4(pid, &stat, TRUE); + if (interactive && WIFSIGNALED(stat)) + tcsetattr(0, TCSANOW, &t); setstatus(-1, stat); /* There is a very good reason for having this weird diff --git a/glom.c b/glom.c @@ -5,6 +5,8 @@ #include <sys/stat.h> #include <signal.h> #include <errno.h> +#include <termios.h> +#include <unistd.h> static List *backq(Node *, Node *); static List *bqinput(List *, int); @@ -249,12 +251,15 @@ static List *backq(Node *ifs, Node *n) { int p[2], sp; pid_t pid; List *bq; + struct termios t; if (n == NULL) return NULL; if (pipe(p) < 0) { uerror("pipe"); rc_error(NULL); } + if (interactive) + tcgetattr(0, &t); if ((pid = rc_fork()) == 0) { mvfd(p[1], 1); close(p[0]); @@ -266,6 +271,8 @@ static List *backq(Node *ifs, Node *n) { bq = bqinput(glom(ifs), p[0]); close(p[0]); rc_wait4(pid, &sp, TRUE); + if (interactive && WIFSIGNALED(sp)) + tcsetattr(0, TCSANOW, &t); setstatus(-1, sp); varassign("bqstatus", word(strstatus(sp), NULL), FALSE); sigchk(); diff --git a/walk.c b/walk.c @@ -4,6 +4,8 @@ #include <signal.h> #include <setjmp.h> +#include <termios.h> +#include <unistd.h> #include "jbwrap.h" @@ -322,11 +324,16 @@ static bool isallpre(Node *n) { static bool dofork(bool parent) { int pid, sp; + struct termios t; + if (interactive) + tcgetattr(0, &t); if (!parent || (pid = rc_fork()) == 0) return TRUE; redirq = NULL; /* clear out the pre-redirection queue in the parent */ rc_wait4(pid, &sp, TRUE); + if (interactive && WIFSIGNALED(sp)) + tcsetattr(0, TCSANOW, &t); setstatus(-1, sp); sigchk(); return FALSE; @@ -336,7 +343,10 @@ static void dopipe(Node *n) { int i, j, sp, pid, fd_prev, fd_out, pids[512], stats[512], p[2]; bool intr; Node *r; + struct termios t; + if (interactive) + tcgetattr(0, &t); fd_prev = fd_out = 1; for (r = n, i = 0; r != NULL && r->type == nPipe; r = r->u[2].p, i++) { if (i > 500) /* the only hard-wired limit in rc? */ @@ -379,8 +389,10 @@ static void dopipe(Node *n) { for (j = 0; j < i; j++) { rc_wait4(pids[j], &sp, TRUE); stats[j] = sp; - intr |= (sp == SIGINT); + intr |= WIFSIGNALED(sp); } + if (interactive && intr) + tcsetattr(0, TCSANOW, &t); setpipestatus(stats, i); sigchk(); }