summaryrefslogtreecommitdiff
path: root/usr.bin/mail/collect.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/collect.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/collect.c')
-rw-r--r--usr.bin/mail/collect.c234
1 files changed, 88 insertions, 146 deletions
diff --git a/usr.bin/mail/collect.c b/usr.bin/mail/collect.c
index 0274b3115c7..60d14da6a70 100644
--- a/usr.bin/mail/collect.c
+++ b/usr.bin/mail/collect.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: collect.c,v 1.21 2001/06/23 23:04:21 millert Exp $ */
+/* $OpenBSD: collect.c,v 1.22 2001/11/20 20:50:00 millert Exp $ */
/* $NetBSD: collect.c,v 1.9 1997/07/09 05:25:45 mikel Exp $ */
/*
@@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)collect.c 8.2 (Berkeley) 4/19/94";
#else
-static char rcsid[] = "$OpenBSD: collect.c,v 1.21 2001/06/23 23:04:21 millert Exp $";
+static char rcsid[] = "$OpenBSD: collect.c,v 1.22 2001/11/20 20:50:00 millert Exp $";
#endif
#endif /* not lint */
@@ -63,55 +63,31 @@ static char rcsid[] = "$OpenBSD: collect.c,v 1.21 2001/06/23 23:04:21 millert Ex
* away on dead.letter.
*/
-static sig_t saveint; /* Previous SIGINT value */
-static sig_t savehup; /* Previous SIGHUP value */
-static sig_t savetstp; /* Previous SIGTSTP value */
-static sig_t savettou; /* Previous SIGTTOU value */
-static sig_t savettin; /* Previous SIGTTIN value */
static FILE *collf; /* File for saving away */
static int hadintr; /* Have seen one SIGINT so far */
-static sigjmp_buf colljmp; /* To get back to work */
-static int colljmp_p; /* whether to long jump */
-static sigjmp_buf collabort; /* To end collection with error */
-
FILE *
collect(hp, printheaders)
struct header *hp;
int printheaders;
{
FILE *fbuf;
- int lc, cc, fd, c, t, lastlong, rc;
- volatile int escape, eofcount, longline;
- volatile char getsub;
+ int lc, cc, fd, c, t, lastlong, rc, sig;
+ int escape, eofcount, longline;
+ char getsub;
char linebuf[LINESIZE], tempname[PATHSIZE], *cp;
- sigset_t oset, nset;
collf = NULL;
- /*
- * Start catching signals from here, but we're still die on interrupts
- * until we're in the main loop.
- */
- sigemptyset(&nset);
- sigaddset(&nset, SIGINT);
- sigaddset(&nset, SIGHUP);
- sigprocmask(SIG_BLOCK, &nset, &oset);
- if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
- (void)signal(SIGINT, collint);
- if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN)
- (void)signal(SIGHUP, collhup);
- savetstp = signal(SIGTSTP, collstop);
- savettou = signal(SIGTTOU, collstop);
- savettin = signal(SIGTTIN, collstop);
- if (sigsetjmp(collabort, 1) || sigsetjmp(colljmp, 1)) {
- (void)rm(tempname);
- goto err;
- }
- sigdelset(&oset, SIGINT);
- sigdelset(&oset, SIGHUP);
- sigprocmask(SIG_SETMASK, &oset, NULL);
-
+ eofcount = 0;
+ hadintr = 0;
+ lastlong = 0;
+ longline = 0;
+ if ((cp = value("escape")) != NULL)
+ escape = *cp;
+ else
+ escape = ESCAPE;
noreset++;
+
(void)snprintf(tempname, sizeof(tempname),
"%s/mail.RsXXXXXXXXXX", tmpdir);
if ((fd = mkstemp(tempname)) == -1 ||
@@ -135,40 +111,43 @@ collect(hp, printheaders)
puthead(hp, stdout, t);
fflush(stdout);
}
- if ((cp = value("escape")) != NULL)
- escape = *cp;
- else
- escape = ESCAPE;
- eofcount = 0;
- hadintr = 0;
- lastlong = 0;
- longline = 0;
+ if (getsub && gethfromtty(hp, GSUBJECT) == -1)
+ goto err;
- if (!sigsetjmp(colljmp, 1)) {
- if (getsub)
- gethfromtty(hp, GSUBJECT);
- } else {
- /*
- * Come here for printing the after-signal message.
- * Duplicate messages won't be printed because
- * the write is aborted if we get a SIGTTOU.
- */
+ if (0) {
cont:
- if (hadintr) {
+ /* Come here for printing the after-suspend message. */
+ if (isatty(0)) {
+ puts("(continue)");
fflush(stdout);
- fputs("\n(Interrupt -- one more to kill letter)\n",
- stderr);
- } else {
- if (isatty(0)) {
- puts("(continue)");
- fflush(stdout);
- }
}
}
for (;;) {
- colljmp_p = 1;
- c = readline(stdin, linebuf, LINESIZE);
- colljmp_p = 0;
+ c = readline(stdin, linebuf, LINESIZE, &sig);
+
+ /* Act on any signal caught during readline() ignoring 'c' */
+ switch (sig) {
+ case 0:
+ break;
+ case SIGINT:
+ if (collabort())
+ goto err;
+ continue;
+ case SIGHUP:
+ rewind(collf);
+ savedeadletter(collf);
+ /*
+ * Let's pretend nobody else wants to clean up,
+ * a true statement at this time.
+ */
+ exit(1);
+ default:
+ /* Stopped due to job control */
+ (void)kill(0, sig);
+ goto cont;
+ }
+
+ /* No signal, check for error */
if (c < 0) {
if (value("interactive") != NULL &&
value("ignoreeof") != NULL && ++eofcount < 25) {
@@ -236,8 +215,9 @@ cont:
* Act like an interrupt happened.
*/
hadintr++;
- collint(SIGINT);
- exit(1);
+ collabort();
+ fputs("Interrupt\n", stderr);
+ goto err;
case 'h':
/*
* Grab a bunch of headers.
@@ -304,7 +284,7 @@ cont:
fflush(stdout);
lc = 0;
cc = 0;
- while ((rc = readline(fbuf, linebuf, LINESIZE)) >= 0) {
+ while ((rc = readline(fbuf, linebuf, LINESIZE, NULL)) >= 0) {
if (rc != LINESIZE - 1)
lc++;
if ((t = putline(collf, linebuf,
@@ -389,10 +369,14 @@ cont:
if (value("interactive") != NULL) {
if (value("askcc") != NULL || value("askbcc") != NULL) {
- if (value("askcc") != NULL)
- gethfromtty(hp, GCC);
- if (value("askbcc") != NULL)
- gethfromtty(hp, GBCC);
+ if (value("askcc") != NULL) {
+ if (gethfromtty(hp, GCC) == -1)
+ goto err;
+ }
+ if (value("askbcc") != NULL) {
+ if (gethfromtty(hp, GBCC) == -1)
+ goto err;
+ }
} else {
puts("EOT");
(void)fflush(stdout);
@@ -408,16 +392,6 @@ out:
if (collf != NULL)
rewind(collf);
noreset--;
- (void)sigemptyset(&nset);
- (void)sigaddset(&nset, SIGINT);
- (void)sigaddset(&nset, SIGHUP);
- (void)sigprocmask(SIG_BLOCK, &nset, &oset);
- (void)signal(SIGINT, saveint);
- (void)signal(SIGHUP, savehup);
- (void)signal(SIGTSTP, savetstp);
- (void)signal(SIGTTOU, savettou);
- (void)signal(SIGTTIN, savettin);
- (void)sigprocmask(SIG_SETMASK, &oset, NULL);
return(collf);
}
@@ -477,15 +451,19 @@ mesedit(fp, c)
FILE *fp;
int c;
{
- sig_t sigint = signal(SIGINT, SIG_IGN);
- FILE *nf = run_editor(fp, (off_t)-1, c, 0);
+ FILE *nf;
+ struct sigaction oact;
+ sigset_t oset;
+ (void)ignoresig(SIGINT, &oact, &oset);
+ nf = run_editor(fp, (off_t)-1, c, 0);
if (nf != NULL) {
fseek(nf, 0L, 2);
collf = nf;
(void)Fclose(fp);
}
- (void)signal(SIGINT, sigint);
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+ (void)sigaction(SIGINT, &oact, NULL);
}
/*
@@ -501,9 +479,11 @@ mespipe(fp, cmd)
{
FILE *nf;
int fd;
- sig_t sigint = signal(SIGINT, SIG_IGN);
char *shell, tempname[PATHSIZE];
+ struct sigaction oact;
+ sigset_t oset;
+ (void)ignoresig(SIGINT, &oact, &oset);
(void)snprintf(tempname, sizeof(tempname),
"%s/mail.ReXXXXXXXXXX", tmpdir);
if ((fd = mkstemp(tempname)) == -1 ||
@@ -534,7 +514,8 @@ mespipe(fp, cmd)
collf = nf;
(void)Fclose(fp);
out:
- (void)signal(SIGINT, sigint);
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+ (void)sigaction(SIGINT, &oact, NULL);
}
/*
@@ -590,37 +571,11 @@ forward(ms, fp, fn, f)
}
/*
- * Print (continue) when continued after ^Z.
+ * User aborted during message composition.
+ * Save the partial message in ~/dead.letter.
*/
-/*ARGSUSED*/
-void
-collstop(s)
- int s;
-{
- sig_t old_action = signal(s, SIG_DFL);
- sigset_t nset;
-
- (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);
- if (colljmp_p) {
- colljmp_p = 0;
- hadintr = 0;
- siglongjmp(colljmp, 1);
- }
-}
-
-/*
- * On interrupt, come here to save the partial message in ~/dead.letter.
- * Then jump out of the collection loop.
- */
-/*ARGSUSED*/
-void
-collint(s)
- int s;
+int
+collabort()
{
/*
* the control flow is subtle, because we can be called from ~q.
@@ -630,29 +585,19 @@ collint(s)
puts("@");
fflush(stdout);
clearerr(stdin);
- return;
+ } else {
+ fflush(stdout);
+ fputs("\n(Interrupt -- one more to kill letter)\n",
+ stderr);
+ hadintr++;
}
- hadintr = 1;
- siglongjmp(colljmp, 1);
+ return(0);
}
+ fflush(stdout);
rewind(collf);
if (value("nosave") == NULL)
savedeadletter(collf);
- siglongjmp(collabort, 1);
-}
-
-/*ARGSUSED*/
-void
-collhup(s)
- int s;
-{
- rewind(collf);
- savedeadletter(collf);
- /*
- * Let's pretend nobody else wants to clean up,
- * a true statement at this time.
- */
- exit(1);
+ return(1);
}
void
@@ -677,19 +622,16 @@ savedeadletter(fp)
rewind(fp);
}
-void
+int
gethfromtty(hp, gflags)
struct header *hp;
int gflags;
{
- if (grabh(hp, gflags) == SIGINT) {
- fflush(stdout);
- fputs("\n(Interrupt -- one more to kill letter)\n",
- stderr);
- if (grabh(hp, gflags) == SIGINT) {
- hadintr++;
- collint(SIGINT);
- exit(1);
- }
+
+ hadintr = 0;
+ while (grabh(hp, gflags) != 0) {
+ if (collabort())
+ return(-1);
}
+ return(0);
}