summaryrefslogtreecommitdiff
path: root/usr.bin/mail/tty.c
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2001-11-20 20:50:01 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2001-11-20 20:50:01 +0000
commita773d207e5326979dbae610af9f727ba9d9aab9a (patch)
tree25eae41092ce63d11c23e2bde172d49858a6b094 /usr.bin/mail/tty.c
parent65d78d4142675bd4f69ddc0d983e59907c358f64 (diff)
Major signal overhaul. We no longer longjmp all over the place.
Instead, routines responsible to gathering user input (or in some cases outputting data) catch the signals and set flags as needed. Because of this some handlers are install without the SA_RESTART flag so syscalls are not restarted and we can check the flag. All signal handlers are now safe. This should make the flow of control a bit more grokable but the code is still ugly.
Diffstat (limited to 'usr.bin/mail/tty.c')
-rw-r--r--usr.bin/mail/tty.c152
1 files changed, 99 insertions, 53 deletions
diff --git a/usr.bin/mail/tty.c b/usr.bin/mail/tty.c
index 0bfb6006ebc..0acd5bf1861 100644
--- a/usr.bin/mail/tty.c
+++ b/usr.bin/mail/tty.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty.c,v 1.12 2001/06/23 23:04:23 millert Exp $ */
+/* $OpenBSD: tty.c,v 1.13 2001/11/20 20:50:00 millert Exp $ */
/* $NetBSD: tty.c,v 1.7 1997/07/09 05:25:46 mikel Exp $ */
/*
@@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)tty.c 8.2 (Berkeley) 4/20/95";
#else
-static char rcsid[] = "$OpenBSD: tty.c,v 1.12 2001/06/23 23:04:23 millert Exp $";
+static char rcsid[] = "$OpenBSD: tty.c,v 1.13 2001/11/20 20:50:00 millert Exp $";
#endif
#endif /* not lint */
@@ -51,14 +51,14 @@ static char rcsid[] = "$OpenBSD: tty.c,v 1.12 2001/06/23 23:04:23 millert Exp $"
#include "rcv.h"
#include "extern.h"
#include <sys/ioctl.h>
+#include <errno.h>
static cc_t c_erase; /* Current erase char */
static cc_t c_kill; /* Current kill char */
-static sigjmp_buf rewrite; /* Place to go when continued */
-static sigjmp_buf intjmp; /* Place to go when interrupted */
#ifndef TIOCSTI
static int ttyset; /* We must now do erase/kill */
#endif
+static volatile sig_atomic_t ttysignal; /* Interrupted by a signal? */
/*
* Read all relevant header fields.
@@ -70,24 +70,28 @@ grabh(hp, gflags)
int gflags;
{
struct termios ttybuf;
- volatile sig_t saveint;
#ifndef TIOCSTI
- sig_t savequit;
+ struct sigaction savequit;
#else
# ifdef TIOCEXT
- volatile int extproc;
+ int extproc;
int flag;
# endif /* TIOCEXT */
#endif
- sig_t savetstp;
- sig_t savettou;
- sig_t savettin;
- volatile int errs = 0;
+ struct sigaction savetstp;
+ struct sigaction savettou;
+ struct sigaction savettin;
+ struct sigaction act;
+ char *s;
+ int error;
- savetstp = signal(SIGTSTP, SIG_DFL);
- savettou = signal(SIGTTOU, SIG_DFL);
- savettin = signal(SIGTTIN, SIG_DFL);
- errs = 0;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_RESTART;
+ act.sa_handler = SIG_DFL;
+ (void)sigaction(SIGTSTP, &act, &savetstp);
+ (void)sigaction(SIGTTOU, &act, &savettou);
+ (void)sigaction(SIGTTIN, &act, &savettin);
+ error = 1;
#ifndef TIOCSTI
ttyset = 0;
#endif
@@ -100,10 +104,10 @@ grabh(hp, gflags)
#ifndef TIOCSTI
ttybuf.c_cc[VERASE] = 0;
ttybuf.c_cc[VKILL] = 0;
- if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL)
- (void)signal(SIGINT, SIG_DFL);
- if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL)
- (void)signal(SIGQUIT, SIG_DFL);
+ act.sa_handler = SIG_IGN;
+ if (sigaction(SIGQUIT, &act, &savequit) == 0 &&
+ savequit.sa_handler == SIG_DFL)
+ (void)sigaction(SIGQUIT, &savequit, NULL);
#else
# ifdef TIOCEXT
extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0);
@@ -113,53 +117,58 @@ grabh(hp, gflags)
warn("TIOCEXT: off");
}
# endif /* TIOCEXT */
- if (sigsetjmp(intjmp, 1)) {
- errs = SIGINT;
- goto out;
- }
- saveint = signal(SIGINT, ttyint);
#endif
if (gflags & GTO) {
#ifndef TIOCSTI
if (!ttyset && hp->h_to != NIL)
ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
#endif
- hp->h_to =
- extract(readtty("To: ", detract(hp->h_to, 0)), GTO);
+ s = readtty("To: ", detract(hp->h_to, 0));
+ if (s == NULL)
+ goto out;
+ hp->h_to = extract(s, GTO);
}
if (gflags & GSUBJECT) {
#ifndef TIOCSTI
if (!ttyset && hp->h_subject != NULL)
ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
#endif
- hp->h_subject = readtty("Subject: ", hp->h_subject);
+ s = readtty("Subject: ", hp->h_subject);
+ if (s == NULL)
+ goto out;
+ hp->h_subject = s;
}
if (gflags & GCC) {
#ifndef TIOCSTI
if (!ttyset && hp->h_cc != NIL)
ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
#endif
- hp->h_cc =
- extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC);
+ s = readtty("Cc: ", detract(hp->h_cc, 0));
+ if (s == NULL)
+ goto out;
+ hp->h_cc = extract(s, GCC);
}
if (gflags & GBCC) {
#ifndef TIOCSTI
if (!ttyset && hp->h_bcc != NIL)
ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
#endif
- hp->h_bcc =
- extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC);
+ s = readtty("Bcc: ", detract(hp->h_bcc, 0));
+ if (s == NULL)
+ goto out;
+ hp->h_bcc = extract(s, GBCC);
}
+ error = 0;
out:
- (void)signal(SIGTSTP, savetstp);
- (void)signal(SIGTTOU, savettou);
- (void)signal(SIGTTIN, savettin);
+ (void)sigaction(SIGTSTP, &savetstp, NULL);
+ (void)sigaction(SIGTTOU, &savettou, NULL);
+ (void)sigaction(SIGTTIN, &savettin, NULL);
#ifndef TIOCSTI
ttybuf.c_cc[VERASE] = c_erase;
ttybuf.c_cc[VKILL] = c_kill;
if (ttyset)
tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
- (void)signal(SIGQUIT, savequit);
+ (void)sigaction(SIGQUIT, &savequit, NULL);
#else
# ifdef TIOCEXT
if (extproc) {
@@ -169,8 +178,7 @@ out:
}
# endif /* TIOCEXT */
#endif
- (void)signal(SIGINT, saveint);
- return(errs);
+ return(error);
}
/*
@@ -184,9 +192,11 @@ char *
readtty(pr, src)
char pr[], src[];
{
+ struct sigaction act, oact;
+ sigset_t oset;
char ch, canonb[BUFSIZ];
- volatile int c;
- char *cp, * volatile cp2;
+ char *cp, *cp2;
+ int c;
fputs(pr, stdout);
fflush(stdout);
@@ -219,26 +229,50 @@ readtty(pr, src)
while (cp2 < canonb + BUFSIZ)
*cp2++ = 0;
cp2 = cp;
- if (sigsetjmp(rewrite, 1))
- goto redo;
- (void)signal(SIGTSTP, ttystop);
- (void)signal(SIGTTOU, ttystop);
- (void)signal(SIGTTIN, ttystop);
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0; /* Note: will not restart syscalls */
+ act.sa_handler = ttyint;
+ (void)sigaction(SIGINT, &act, &oact);
+ act.sa_handler = ttystop;
+ (void)sigaction(SIGTSTP, &act, NULL);
+ (void)sigaction(SIGTTOU, &act, NULL);
+ (void)sigaction(SIGTTIN, &act, NULL);
+ (void)sigprocmask(SIG_UNBLOCK, &intset, &oset);
clearerr(stdin);
while (cp2 < canonb + BUFSIZ) {
c = getc(stdin);
+ switch (ttysignal) {
+ case SIGINT:
+ ttysignal = 0;
+ cp2 = NULL;
+ c = EOF;
+ /* FALLTHROUGH */
+ case 0:
+ break;
+ default:
+ ttysignal = 0;
+ goto redo;
+ }
if (c == EOF || c == '\n')
break;
*cp2++ = c;
}
- *cp2 = 0;
- (void)signal(SIGTSTP, SIG_DFL);
- (void)signal(SIGTTOU, SIG_DFL);
- (void)signal(SIGTTIN, SIG_DFL);
+ act.sa_handler = SIG_DFL;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_RESTART;
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+ (void)sigaction(SIGTSTP, &act, NULL);
+ (void)sigaction(SIGTTOU, &act, NULL);
+ (void)sigaction(SIGTTIN, &act, NULL);
+ (void)sigaction(SIGTTIN, &oact, NULL);
+ if (cp2 == NULL)
+ return(NULL); /* user hit ^C */
+ *cp2 = '\0';
if (c == EOF && ferror(stdin)) {
redo:
cp = strlen(canonb) > 0 ? canonb : NULL;
clearerr(stdin);
+ /* XXX - make iterative, not recursive */
return(readtty(pr, cp));
}
#ifndef TIOCSTI
@@ -274,7 +308,7 @@ redo:
*cp2 = '\0';
#endif
if (equal("", canonb))
- return(NULL);
+ return("");
return(savestr(canonb));
}
@@ -285,16 +319,27 @@ void
ttystop(s)
int s;
{
- sig_t old_action = signal(s, SIG_DFL);
+ struct sigaction act, oact;
sigset_t nset;
+ int save_errno;
+ /*
+ * Save old handler and set to default.
+ * Unblock receipt of 's' and then resend it.
+ */
+ save_errno = errno;
+ (void)sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_RESTART;
+ act.sa_handler = SIG_DFL;
+ (void)sigaction(s, &act, &oact);
(void)sigemptyset(&nset);
(void)sigaddset(&nset, s);
(void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
(void)kill(0, s);
(void)sigprocmask(SIG_BLOCK, &nset, NULL);
- (void)signal(s, old_action);
- siglongjmp(rewrite, 1);
+ (void)sigaction(s, &oact, NULL);
+ ttysignal = s;
+ errno = save_errno;
}
/*ARGSUSED*/
@@ -302,5 +347,6 @@ void
ttyint(s)
int s;
{
- siglongjmp(intjmp, 1);
+
+ ttysignal = s;
}