diff --git a/usr.bin/mail/Makefile b/usr.bin/mail/Makefile index 6a01e3743419..cdba6c7d0782 100644 --- a/usr.bin/mail/Makefile +++ b/usr.bin/mail/Makefile @@ -1,20 +1,30 @@ -# $NetBSD: Makefile,v 1.30 2007/05/28 12:06:28 tls Exp $ +# $NetBSD: Makefile,v 1.31 2009/04/10 13:08:24 christos Exp $ # @(#)Makefile 8.3 (Berkeley) 4/20/95 .include USE_FORT?= yes # data-driven bugs? -USE_EDITLINE=yes -MIME_SUPPORT=yes # currently requires USE_EDITLINE -CHARSET_SUPPORT=yes # requires MIME_SUPPORT -THREAD_SUPPORT=yes # EXPERIMENTAL +USE_EDITLINE?=yes +MIME_SUPPORT?=yes # currently requires USE_EDITLINE +CHARSET_SUPPORT?=yes # requires MIME_SUPPORT +THREAD_SUPPORT?=yes # EXPERIMENTAL + +# Work around some problems in -current. +# See the source code for more info. +# +CPPFLAGS+= -DBROKEN_EXEC_TTY_RESTORE # broken since 4.99.10 +CPPFLAGS+= -DBROKEN_CLONE_STAT # see PRs 37878 and 37550 + +# Debugging options (most should go away - please leave for now). +# +#CPPFLAGS+= -DDEBUG_FILE_LEAK PROG= mail SRCS= version.c support.c cmd1.c cmd2.c cmd3.c cmd4.c cmdtab.c collect.c \ dotlock.c edit.c fio.c format.c getname.c head.c v7.local.c lex.c \ - list.c main.c names.c popen.c quit.c send.c strings.c temp.c tty.c \ - vars.c + list.c main.c names.c popen.c quit.c send.c sig.c strings.c temp.c \ + tty.c vars.c LINKS= ${BINDIR}/mail ${BINDIR}/Mail ${BINDIR}/mail ${BINDIR}/mailx MLINKS= mail.1 Mail.1 mail.1 mailx.1 diff --git a/usr.bin/mail/cmd1.c b/usr.bin/mail/cmd1.c index 5e1a47fa23be..2a495c387e04 100644 --- a/usr.bin/mail/cmd1.c +++ b/usr.bin/mail/cmd1.c @@ -1,4 +1,4 @@ -/* $NetBSD: cmd1.c,v 1.29 2007/10/29 23:20:37 christos Exp $ */ +/* $NetBSD: cmd1.c,v 1.30 2009/04/10 13:08:24 christos Exp $ */ /*- * Copyright (c) 1980, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)cmd1.c 8.2 (Berkeley) 4/20/95"; #else -__RCSID("$NetBSD: cmd1.c,v 1.29 2007/10/29 23:20:37 christos Exp $"); +__RCSID("$NetBSD: cmd1.c,v 1.30 2009/04/10 13:08:24 christos Exp $"); #endif #endif /* not lint */ @@ -46,6 +46,7 @@ __RCSID("$NetBSD: cmd1.c,v 1.29 2007/10/29 23:20:37 christos Exp $"); #ifdef MIME_SUPPORT #include "mime.h" #endif +#include "sig.h" #include "thread.h" @@ -88,6 +89,7 @@ printhead(int mesg) if (screenwidth > 0) msgline[screenwidth] = '\0'; (void)printf("%s\n", msgline); + sig_check(); } /* @@ -97,11 +99,13 @@ printhead(int mesg) PUBLIC int headers(void *v) { - int *msgvec = v; - int n, flag; + int *msgvec; + int n; + int flag; struct message *mp; int size; + msgvec = v; size = screensize(); n = msgvec[0]; if (n != 0) @@ -140,10 +144,12 @@ headers(void *v) PUBLIC int scroll(void *v) { - char *arg = v; - int s, size; + char *arg; + int s; + int size; int cur[1]; + arg = v; cur[0] = 0; size = screensize(); s = screen; @@ -180,9 +186,10 @@ scroll(void *v) PUBLIC int from(void *v) { - int *msgvec = v; + int *msgvec; int *ip; + msgvec = v; for (ip = msgvec; *ip != 0; ip++) printhead(*ip); if (--ip >= msgvec) @@ -214,10 +221,11 @@ PUBLIC int pcmdlist(void *v __unused) { const struct cmd *cp; - int cc; + size_t cc; (void)printf("Commands are:\n"); - for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) { + cc = 0; + for (cp = cmdtab; cp->c_name != NULL; cp++) { cc += strlen(cp->c_name) + 2; if (cc > 72) { (void)printf("\n"); @@ -227,6 +235,7 @@ pcmdlist(void *v __unused) (void)printf("%s, ", cp->c_name); else (void)printf("%s\n", cp->c_name); + sig_check(); } return 0; } @@ -236,6 +245,7 @@ PUBLIC char * sget_msgnum(struct message *mp, struct message *parent) { char *p; + if (parent == NULL || parent == mp) { (void)sasprintf(&p, "%d", mp->m_index); return p; @@ -249,6 +259,7 @@ sget_msgnum(struct message *mp, struct message *parent) PUBLIC void show_msgnum(FILE *obuf, struct message *mp, struct message *parent) { + if (value(ENAME_QUIET) == NULL) (void)fprintf(obuf, "Message %s:\n", sget_msgnum(mp, parent)); } @@ -278,6 +289,7 @@ type1_core(struct message *mp, void *v) #else (void)sendmessage(mp, args->obuf, args->igtab, NULL, NULL); #endif + sig_check(); return 0; } @@ -289,8 +301,9 @@ static jmp_buf pipestop; /*ARGSUSED*/ static void -brokpipe(int signo __unused) +cmd1_brokpipe(int signo __unused) { + longjmp(pipestop, 1); } @@ -311,25 +324,27 @@ type1(int *msgvec, int doign, int mime_decode) * starting values. Note it is the variable that is volatile, * not what it is pointing at! */ - FILE *volatile obuf; /* avoid longjmp clobbering? */ + FILE *volatile obuf; /* avoid longjmp clobbering */ + sig_t volatile oldsigpipe; /* avoid longjmp clobbering? */ #ifdef MIME_SUPPORT - sig_t volatile oldsigpipe; /* XXX - is volatile needed? */ - struct mime_info *volatile mip; /* avoid longjmp clobbering - needed */ + struct mime_info *volatile mip; /* avoid longjmp clobbering? */ + + mip = NULL; #endif if ((obuf = last_registered_file(0)) == NULL) obuf = stdout; -#ifdef MIME_SUPPORT - mip = NULL; - - oldsigpipe = signal(SIGPIPE, SIG_IGN); - + /* + * Even without MIME_SUPPORT, we need to handle SIGPIPE here + * or else the handler in execute() will grab things and our + * exit code will never be seen. + */ + sig_check(); + oldsigpipe = sig_signal(SIGPIPE, cmd1_brokpipe); if (setjmp(pipestop)) goto close_pipe; - (void)signal(SIGPIPE, brokpipe); -#endif msgCount = get_msgCount(); recursive = do_recursion(); @@ -349,17 +364,22 @@ type1(int *msgvec, int doign, int mime_decode) #endif (void)thread_recursion(mp, type1_core, &args); } -#ifdef MIME_SUPPORT close_pipe: +#ifdef MIME_SUPPORT if (mip != NULL) { + struct sigaction osa; + sigset_t oset; + /* * Ignore SIGPIPE so it can't cause a duplicate close. */ - (void)signal(SIGPIPE, SIG_IGN); + (void)sig_ignore(SIGPIPE, &osa, &oset); mime_decode_close(mip); - (void)signal(SIGPIPE, oldsigpipe); + (void)sig_restore(SIGPIPE, &osa, &oset); } #endif + (void)sig_signal(SIGPIPE, oldsigpipe); + sig_check(); return 0; } @@ -367,6 +387,7 @@ close_pipe: static int de_mime(void) { + return value(ENAME_MIME_DECODE_MSG) != NULL; } @@ -376,7 +397,9 @@ de_mime(void) PUBLIC int view(void *v) { - int *msgvec = v; + int *msgvec; + + msgvec = v; return type1(msgvec, 1, !de_mime()); } @@ -386,8 +409,9 @@ view(void *v) PUBLIC int View(void *v) { - int *msgvec = v; + int *msgvec; + msgvec = v; return type1(msgvec, 0, !de_mime()); } #endif /* MIME_SUPPORT */ @@ -398,8 +422,9 @@ View(void *v) PUBLIC int type(void *v) { - int *msgvec = v; + int *msgvec; + msgvec = v; return type1(msgvec, 1, de_mime()); } @@ -409,8 +434,9 @@ type(void *v) PUBLIC int Type(void *v) { - int *msgvec = v; + int *msgvec; + msgvec = v; return type1(msgvec, 0, de_mime()); } @@ -420,9 +446,11 @@ Type(void *v) PUBLIC int pipecmd(void *v) { - char *cmd = v; - FILE *volatile obuf; /* void longjmp clobbering - we want - the current value not start value */ + char *cmd; + FILE *volatile obuf; /* void longjmp clobbering */ + sig_t volatile oldsigpipe; /* XXX - is volatile needed? */ + + cmd = v; if (dot == NULL) { warn("pipcmd: no current message"); return 1; @@ -432,30 +460,36 @@ pipecmd(void *v) if (setjmp(pipestop)) goto close_pipe; + sig_check(); obuf = Popen(cmd, "w"); if (obuf == NULL) { warn("pipecmd: Popen failed: %s", cmd); return 1; - } else - (void)signal(SIGPIPE, brokpipe); + } + + oldsigpipe = sig_signal(SIGPIPE, cmd1_brokpipe); (void)sendmessage(dot, obuf, ignoreall, NULL, NULL); close_pipe: + sig_check(); if (obuf != stdout) { + struct sigaction osa; + sigset_t oset; /* * Ignore SIGPIPE so it can't cause a duplicate close. */ - (void)signal(SIGPIPE, SIG_IGN); + (void)sig_ignore(SIGPIPE, &osa, &oset); (void)Pclose(obuf); - (void)signal(SIGPIPE, SIG_DFL); + (void)sig_restore(SIGPIPE, &osa, &oset); } + (void)sig_signal(SIGPIPE, oldsigpipe); + sig_check(); return 0; } - struct top_core_args_s { int lineb; - int topl; + size_t topl; struct message *parent; }; static int @@ -464,8 +498,8 @@ top_core(struct message *mp, void *v) char buffer[LINESIZE]; struct top_core_args_s *args; FILE *ibuf; - int lines; - int c; + size_t lines; + size_t c; args = v; touch(mp); @@ -475,11 +509,13 @@ top_core(struct message *mp, void *v) ibuf = setinput(mp); c = mp->m_lines; for (lines = 0; lines < c && lines <= args->topl; lines++) { - if (mail_readline(ibuf, buffer, sizeof(buffer)) < 0) + sig_check(); + if (readline(ibuf, buffer, (int)sizeof(buffer), 0) < 0) break; (void)puts(buffer); args->lineb = blankline(buffer); } + sig_check(); return 0; } @@ -494,11 +530,12 @@ top(void *v) struct top_core_args_s args; int recursive; int msgCount; - int *msgvec = v; + int *msgvec; int *ip; int topl; char *valtop; + msgvec = v; topl = 5; valtop = value(ENAME_TOPLINES); if (valtop != NULL) { @@ -528,12 +565,14 @@ top(void *v) PUBLIC int stouch(void *v) { - int *msgvec = v; + int *msgvec; int *ip; - for (ip = msgvec; *ip != 0; ip++) + msgvec = v; + for (ip = msgvec; *ip != 0; ip++) { + sig_check(); dot = set_m_flag(*ip, ~(MPRESERVE | MTOUCH), MTOUCH); - + } return 0; } @@ -543,13 +582,15 @@ stouch(void *v) PUBLIC int mboxit(void *v) { - int *msgvec = v; + int *msgvec; int *ip; - for (ip = msgvec; *ip != 0; ip++) + msgvec = v; + for (ip = msgvec; *ip != 0; ip++) { + sig_check(); dot = set_m_flag(*ip, ~(MPRESERVE | MTOUCH | MBOX), MTOUCH | MBOX); - + } return 0; } @@ -569,7 +610,7 @@ folders(void *v __unused) } if ((cmd = value(ENAME_LISTER)) == NULL) cmd = "ls"; - (void)run_command(cmd, 0, -1, -1, dirname, NULL); + (void)run_command(cmd, NULL, -1, -1, dirname, NULL); return 0; } @@ -581,7 +622,8 @@ folders(void *v __unused) PUBLIC int inc(void *v __unused) { - int nmsg, mdot; + int nmsg; + int mdot; nmsg = incfile(); @@ -595,6 +637,5 @@ inc(void *v __unused) } else { (void)printf("\"inc\" command failed...\n"); } - return 0; } diff --git a/usr.bin/mail/cmd2.c b/usr.bin/mail/cmd2.c index ccedf00ee600..ce597e4084ba 100644 --- a/usr.bin/mail/cmd2.c +++ b/usr.bin/mail/cmd2.c @@ -1,4 +1,4 @@ -/* $NetBSD: cmd2.c,v 1.23 2007/10/27 15:14:50 christos Exp $ */ +/* $NetBSD: cmd2.c,v 1.24 2009/04/10 13:08:24 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)cmd2.c 8.1 (Berkeley) 6/6/93"; #else -__RCSID("$NetBSD: cmd2.c,v 1.23 2007/10/27 15:14:50 christos Exp $"); +__RCSID("$NetBSD: cmd2.c,v 1.24 2009/04/10 13:08:24 christos Exp $"); #endif #endif /* not lint */ @@ -60,11 +60,12 @@ __RCSID("$NetBSD: cmd2.c,v 1.23 2007/10/27 15:14:50 christos Exp $"); PUBLIC int next(void *v) { - int *msgvec = v; + int *msgvec; struct message *mp; int *ip, *ip2; int list[2], mdot; + msgvec = v; if (*msgvec != 0) { /* @@ -151,15 +152,13 @@ snarf(char linebuf[], int *flag, const char *string) /* * Strip away trailing blanks. */ - - while (cp > linebuf && isspace((unsigned char)*cp)) + while (cp >= linebuf && isspace((unsigned char)*cp)) cp--; - *++cp = 0; + *++cp = '\0'; /* * Now search for the beginning of the file name. */ - while (cp > linebuf && !isspace((unsigned char)*cp)) cp--; if (*cp == '\0') { @@ -167,7 +166,7 @@ snarf(char linebuf[], int *flag, const char *string) return NULL; } if (isspace((unsigned char)*cp)) - *cp++ = 0; + *cp++ = '\0'; else *flag = 0; return cp; @@ -182,8 +181,8 @@ static int save1_core(struct message *mp, void *v) { struct save1_core_args_s *args; - args = v; + args = v; touch(mp); if (sendmessage(mp, args->obuf, args->igtab, NULL, NULL) < 0) @@ -264,8 +263,9 @@ save1(char str[], int markmsg, const char *cmd, struct ignoretab *igtab) PUBLIC int save(void *v) { - char *str = v; + char *str; + str = v; return save1(str, 1, "save", saveignore); } @@ -277,8 +277,9 @@ save(void *v) PUBLIC int Save(void *v) { - char *str = v; + char *str; + str = v; return save1(str, 1, "Save", NULL); } @@ -288,8 +289,9 @@ Save(void *v) PUBLIC int copycmd(void *v) { - char *str = v; + char *str; + str = v; return save1(str, 0, "copy", saveignore); } @@ -300,8 +302,9 @@ copycmd(void *v) PUBLIC int swrite(void *v) { - char *str = v; + char *str; + str = v; return save1(str, 1, "write", ignoreall); } @@ -349,7 +352,9 @@ delm(int *msgvec) PUBLIC int delete(void *v) { - int *msgvec = v; + int *msgvec; + + msgvec = v; (void)delm(msgvec); return 0; } @@ -360,10 +365,11 @@ delete(void *v) PUBLIC int deltype(void *v) { - int *msgvec = v; + int *msgvec; int list[2]; int lastdot; + msgvec = v; lastdot = get_msgnum(dot); if (delm(msgvec) >= 0) { list[0] = get_msgnum(dot); @@ -449,9 +455,10 @@ clob1(int n) PUBLIC int clobber(void *v) { - char **argv = v; + char **argv; int times; + argv = v; if (argv[0] == 0) times = 1; else @@ -519,8 +526,9 @@ ignore1(char *list[], struct ignoretab *tab, const char *which) PUBLIC int retfield(void *v) { - char **list = v; + char **list; + list = v; return ignore1(list, ignore + 1, "retained"); } @@ -531,8 +539,9 @@ retfield(void *v) PUBLIC int igfield(void *v) { - char **list = v; + char **list; + list = v; return ignore1(list, ignore, "ignored"); } @@ -543,8 +552,9 @@ igfield(void *v) PUBLIC int saveretfield(void *v) { - char **list = v; + char **list; + list = v; return ignore1(list, saveignore + 1, "retained"); } @@ -555,8 +565,9 @@ saveretfield(void *v) PUBLIC int saveigfield(void *v) { - char **list = v; + char **list; + list = v; return ignore1(list, saveignore, "ignored"); } @@ -595,7 +606,7 @@ check_dirname(char *filename) if (access(canon_name, W_OK|X_OK) == -1) { warnx("access: %s is not writable", canon_name); canon_name = NULL; - /* goto done; */ + goto done; } done: if (fname != filename) @@ -604,7 +615,6 @@ check_dirname(char *filename) return canon_name ? savestr(canon_name) : NULL; } - struct detach1_core_args_s { struct message *parent; struct ignoretab *igtab; @@ -683,6 +693,7 @@ detach1(void *v, int do_unnamed) for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) { struct detach1_core_args_s args; struct message *mp; + mp = get_message(*ip); dot = mp; args.parent = recursive ? mp : NULL; @@ -699,6 +710,7 @@ detach1(void *v, int do_unnamed) PUBLIC int detach(void *v) { + return detach1(v, 0); } @@ -708,6 +720,7 @@ detach(void *v) PUBLIC int Detach(void *v) { + return detach1(v, 1); } #endif /* MIME_SUPPORT */ diff --git a/usr.bin/mail/cmd3.c b/usr.bin/mail/cmd3.c index b410ad9e4713..dfd5a3271ac2 100644 --- a/usr.bin/mail/cmd3.c +++ b/usr.bin/mail/cmd3.c @@ -1,4 +1,4 @@ -/* $NetBSD: cmd3.c,v 1.39 2007/10/30 16:08:11 christos Exp $ */ +/* $NetBSD: cmd3.c,v 1.40 2009/04/10 13:08:24 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)cmd3.c 8.2 (Berkeley) 4/20/95"; #else -__RCSID("$NetBSD: cmd3.c,v 1.39 2007/10/30 16:08:11 christos Exp $"); +__RCSID("$NetBSD: cmd3.c,v 1.40 2009/04/10 13:08:24 christos Exp $"); #endif #endif /* not lint */ @@ -43,6 +43,7 @@ __RCSID("$NetBSD: cmd3.c,v 1.39 2007/10/30 16:08:11 christos Exp $"); #include #include "extern.h" #include "mime.h" +#include "sig.h" #include "thread.h" /* @@ -59,6 +60,7 @@ __RCSID("$NetBSD: cmd3.c,v 1.39 2007/10/30 16:08:11 christos Exp $"); static int diction(const void *a, const void *b) { + return strcmp(*(const char *const *)a, *(const char *const *)b); } @@ -73,9 +75,9 @@ sort(const char **list) for (ap = list; *ap != NULL; ap++) continue; - if (ap-list < 2) + if (ap - list < 2) return; - qsort(list, (size_t)(ap-list), sizeof(*list), diction); + qsort(list, (size_t)(ap - list), sizeof(*list), diction); } /* @@ -88,16 +90,17 @@ bangexp(char *str) static char lastbang[128]; char bangbuf[LINESIZE]; char *cp, *cp2; - int n; - int changed = 0; + ssize_t n; + int changed; + changed = 0; cp = str; cp2 = bangbuf; n = sizeof(bangbuf); /* bytes left in bangbuf */ while (*cp) { if (*cp == '!') { if (n < (int)strlen(lastbang)) { -overf: + overf: (void)printf("Command buffer overflow\n"); return -1; } @@ -136,19 +139,24 @@ overf: PUBLIC int shell(void *v) { - char *str = v; - sig_t sigint = signal(SIGINT, SIG_IGN); + struct sigaction osa; + sigset_t oset; + char *str; const char *shellcmd; char cmd[LINESIZE]; + str = v; + sig_check(); + (void)sig_ignore(SIGINT, &osa, &oset); (void)strcpy(cmd, str); if (bangexp(cmd) < 0) return 1; if ((shellcmd = value(ENAME_SHELL)) == NULL) shellcmd = _PATH_CSHELL; - (void)run_command(shellcmd, 0, 0, 1, "-c", cmd, NULL); - (void)signal(SIGINT, sigint); + (void)run_command(shellcmd, NULL, 0, 1, "-c", cmd, NULL); + (void)sig_restore(SIGINT, &osa, &oset); (void)printf("!\n"); + sig_check(); return 0; } @@ -159,14 +167,18 @@ shell(void *v) PUBLIC int dosh(void *v __unused) { - sig_t sigint = signal(SIGINT, SIG_IGN); + struct sigaction osa; + sigset_t oset; const char *shellcmd; + sig_check(); + (void)sig_ignore(SIGINT, &osa, &oset); if ((shellcmd = value(ENAME_SHELL)) == NULL) shellcmd = _PATH_CSHELL; - (void)run_command(shellcmd, 0, 0, 1, NULL); - (void)signal(SIGINT, sigint); + (void)run_command(shellcmd, NULL, 0, 1, NULL); + (void)sig_restore(SIGINT, &osa, &oset); (void)putchar('\n'); + sig_check(); return 0; } @@ -178,6 +190,7 @@ dosh(void *v __unused) PUBLIC int help(void *v __unused) { + cathelp(_PATH_HELP); return 0; } @@ -188,9 +201,10 @@ help(void *v __unused) PUBLIC int schdir(void *v) { - char **arglist = v; + char **arglist; const char *cp; + arglist = v; if (*arglist == NULL) cp = homedir; else @@ -210,9 +224,11 @@ static struct name * set_smopts(struct message *mp) { char *cp; - struct name *np = NULL; - char *reply_as_recipient = value(ENAME_REPLYASRECIPIENT); + struct name *np; + char *reply_as_recipient; + np = NULL; + reply_as_recipient = value(ENAME_REPLYASRECIPIENT); if (reply_as_recipient && (cp = skin(hfield("to", mp))) != NULL && extract(cp, GTO)->n_flink == NULL) { /* check for one recipient */ @@ -540,12 +556,13 @@ bounce_one(int msgno, const char **smargs, struct name *h_to) PUBLIC int bounce(void *v) { - int *msgvec = v; + int *msgvec; int *ip; const char **smargs; struct header hdr; int rval; + msgvec = v; if (bouncetab[0].i_count == 0) { /* setup the bounce tab */ add_ignore("Status", bouncetab); @@ -576,9 +593,10 @@ bounce(void *v) PUBLIC int preserve(void *v) { - int *msgvec = v; + int *msgvec; int *ip; + msgvec = v; if (edit) { (void)printf("Cannot \"preserve\" in edit mode\n"); return 1; @@ -595,9 +613,10 @@ preserve(void *v) PUBLIC int unread(void *v) { - int *msgvec = v; + int *msgvec; int *ip; + msgvec = v; for (ip = msgvec; *ip != 0; ip++) dot = set_m_flag(*ip, ~(MREAD | MTOUCH | MSTATUS), MSTATUS); @@ -610,9 +629,10 @@ unread(void *v) PUBLIC int markread(void *v) { - int *msgvec = v; + int *msgvec; int *ip; + msgvec = v; for (ip = msgvec; *ip != 0; ip++) dot = set_m_flag(*ip, ~(MNEW | MTOUCH | MREAD | MSTATUS), MREAD | MSTATUS); @@ -626,10 +646,11 @@ markread(void *v) PUBLIC int messize(void *v) { - int *msgvec = v; + int *msgvec; struct message *mp; int *ip, mesg; + msgvec = v; for (ip = msgvec; *ip != 0; ip++) { mesg = *ip; mp = get_message(mesg); diff --git a/usr.bin/mail/cmd4.c b/usr.bin/mail/cmd4.c index 9ec59a76b0c6..9233472eb4b0 100644 --- a/usr.bin/mail/cmd4.c +++ b/usr.bin/mail/cmd4.c @@ -1,4 +1,4 @@ -/* $NetBSD: cmd4.c,v 1.4 2008/04/28 20:24:14 martin Exp $ */ +/* $NetBSD: cmd4.c,v 1.5 2009/04/10 13:08:24 christos Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ #if 0 static char sccsid[] = "@(#)cmd3.c 8.2 (Berkeley) 4/20/95"; #else -__RCSID("$NetBSD: cmd4.c,v 1.4 2008/04/28 20:24:14 martin Exp $"); +__RCSID("$NetBSD: cmd4.c,v 1.5 2009/04/10 13:08:24 christos Exp $"); #endif #endif /* not lint */ @@ -55,6 +55,7 @@ void showname(struct name *); void showname(struct name *np) { + for (/*EMPTY*/; np; np = np->n_flink) (void)printf("np: %p np->n_type: %d np->n_name: '%s' (%p)\n", np, np->n_type, np->n_name, np->n_name); @@ -64,6 +65,7 @@ __unused static void showsmopts(struct smopts_s *sp) { + (void)printf("%s (%p)\n", sp->s_name, sp); showname(sp->s_smopts); } @@ -74,6 +76,7 @@ static int hashcase(const char *key) { char *lckey; + lckey = salloc(strlen(key) + 1); istrcpy(lckey, key); return hash(lckey); @@ -128,18 +131,19 @@ static void printsmoptstbl(void) { struct smopts_s *sp; - const char **argv, **ap; + const char **argv; + const char **ap; int h; int cnt; cnt = 1; - for (h = 0; h < (int)sizeofarray(smoptstbl); h++ ) + for (h = 0; h < (int)__arraycount(smoptstbl); h++ ) for (sp = smoptstbl[h]; sp && sp->s_name != NULL; sp = sp->s_link) cnt++; argv = salloc(cnt * sizeof(*argv)); ap = argv; - for (h = 0; h < (int)sizeofarray(smoptstbl); h++ ) + for (h = 0; h < (int)__arraycount(smoptstbl); h++ ) for (sp = smoptstbl[h]; sp && sp->s_name != NULL; sp = sp->s_link) *ap++ = sp->s_name; *ap = NULL; @@ -180,7 +184,8 @@ static void smopts_core(const char *sname, char **argv) { struct smopts_s *sp; - struct name *np, *t; + struct name *np; + struct name *t; int h; char **ap; @@ -217,8 +222,9 @@ PUBLIC int smoptscmd(void *v) { struct name *np; - char **argv = v; + char **argv; + argv = v; if (*argv == NULL) { printsmoptstbl(); return 0; @@ -240,6 +246,7 @@ static void free_name(struct name *np) { struct name *next_np; + for (/*EMPTY*/; np; np = next_np) { next_np = np->n_flink; free(next_np); @@ -269,11 +276,112 @@ PUBLIC int unsmoptscmd(void *v) { struct name *np; - char **argv, **ap; + char **ap; - argv = v; - for (ap = argv; *ap != NULL; ap++) + for (ap = v; *ap != NULL; ap++) for (np = name_expand(*ap, GTO); np; np = np->n_flink) delsmopts(np->n_name); return 0; } + +static struct name * +alloc_Header(char *str) +{ + struct name *np; + + /* + * Don't use salloc() routines here as these strings must persist. + */ + np = ecalloc(1, sizeof(*np)); + np->n_name = estrdup(str); + np->n_type = GMISC; + return np; +} + +static int +free_Header(char *str) +{ + struct name *np; + struct name *next_np; + size_t len; + + len = strlen(str); + for (np = extra_headers; np != NULL; np = next_np) { + next_np = np->n_flink; + if (strncasecmp(np->n_name, str, len) == 0) { + if (np == extra_headers) { + extra_headers = np->n_flink; + if (extra_headers) + extra_headers->n_blink = NULL; + } + else { + struct name *bp; + struct name *fp; + + bp = np->n_blink; + fp = np->n_flink; + if (bp) + bp->n_flink = fp; + if (fp) + fp->n_blink = bp; + } + if (np->n_name) + free(np->n_name); + free(np); + } + } + return 0; +} + +/* + * Takes a string and includes it in the header. + */ +PUBLIC int +Header(void *v) +{ + struct name *np; + char *str; + char *p; + + str = v; + if (str == NULL) + return 0; + + (void)strip_WSP(str); /* strip trailing whitespace */ + + if (str[0] == '\0') { /* Show the extra headers */ + for (np = extra_headers; np != NULL; np = np->n_flink) + (void)printf("%s\n", np->n_name); + return 0; + } + + /* + * Check for a valid header line: find the end of its name. + */ + for (p = str; *p != '\0' && *p != ':' && !is_WSP(*p); p++) + continue; + + if (p[0] == ':' && p[1] == '\0') /* free headers of this type */ + return free_Header(str); + + /* + * Check for a valid header name. + */ + if (*p != ':' || !is_WSP(p[1])) { + (void)printf("invalid header string: `%s'\n", str); + return 0; + } + + np = alloc_Header(str); + if (extra_headers == NULL) + extra_headers = np; + else { + struct name *tp; + + for (tp = extra_headers; tp->n_flink; tp = tp->n_flink) + continue; + tp->n_flink = np; + np->n_blink = tp; + } + return 0; +} diff --git a/usr.bin/mail/cmdtab.c b/usr.bin/mail/cmdtab.c index 196a1f3a88ff..606348a030f2 100644 --- a/usr.bin/mail/cmdtab.c +++ b/usr.bin/mail/cmdtab.c @@ -1,4 +1,4 @@ -/* $NetBSD: cmdtab.c,v 1.20 2007/10/30 02:28:31 christos Exp $ */ +/* $NetBSD: cmdtab.c,v 1.21 2009/04/10 13:08:24 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)cmdtab.c 8.2 (Berkeley) 4/20/95"; #else -__RCSID("$NetBSD: cmdtab.c,v 1.20 2007/10/30 02:28:31 christos Exp $"); +__RCSID("$NetBSD: cmdtab.c,v 1.21 2009/04/10 13:08:24 christos Exp $"); #endif #endif /* not lint */ @@ -62,7 +62,7 @@ __RCSID("$NetBSD: cmdtab.c,v 1.20 2007/10/30 02:28:31 christos Exp $"); /* R - in left comment means recursive */ const struct cmd cmdtab[] = { { "next", next, C, CMP(n) NDMLIST, 0, MMNDEL }, - { "alias", group, S, CMP(A) M|RAWLIST, 0, 1000 }, + { "alias", group, S, CMP(A) T|M|RAWLIST, 0, 1000 }, /* R */ { "print", type, C, CMP(n) MSGLIST, 0, MMNDEL }, /* R */ { "Print", Type, C, CMP(n) MSGLIST, 0, MMNDEL }, /* R */ { "type", type, C, CMP(n) MSGLIST, 0, MMNDEL }, @@ -75,7 +75,7 @@ const struct cmd cmdtab[] = { /* R */ { "dp", deltype, C, CMP(n) W|MSGLIST, 0, MMNDEL }, /* R */ { "dt", deltype, C, CMP(n) W|MSGLIST, 0, MMNDEL }, /* R */ { "undelete", undeletecmd, 0, CMP(n) P|MSGLIST, MDELETED, MMNDEL }, - { "unset", unset, 0, CMP(S) M|RAWLIST, 1, 1000 }, + { "unset", unset, 0, CMP(S) T|M|RAWLIST, 1, 1000 }, { "mail", sendmail, 0, CMP(A) R|M|I|STRLIST, 0, 0 }, /* R */ { "mbox", mboxit, 0, CMP(n) W|MSGLIST, 0, MMNDEL }, /* R */ { "more", type, A, CMP(n) MSGLIST, 0, MMNDEL }, @@ -86,21 +86,21 @@ const struct cmd cmdtab[] = { /* R */ { "view", view, A, CMP(n) MSGLIST, 0, MMNDEL }, /* R */ { "View", View, A, CMP(n) MSGLIST, 0, MMNDEL }, #endif - { "unalias", unalias, 0, CMP(A) M|RAWLIST, 1, 1000 }, + { "unalias", unalias, 0, CMP(A) T|M|RAWLIST, 1, 1000 }, /* R */ { "unread", unread, 0, CMP(n) MSGLIST, 0, MMNDEL }, - { "!", shell, 0, CMP(xF) I|STRLIST, 0, 0 }, + { "!", shell, 0, CMP(xF) T|I|STRLIST, 0, 0 }, { "|", pipecmd, 0, CMP(xF) I|STRLIST, 0, 0 }, /* R */ { "copy", copycmd, 0, CMP(F) M|STRLIST, 0, 0 }, - { "chdir", schdir, 0, CMP(F) M|RAWLIST, 0, 1 }, - { "cd", schdir, 0, CMP(F) M|RAWLIST, 0, 1 }, + { "chdir", schdir, 0, CMP(F) T|M|RAWLIST, 0, 1 }, + { "cd", schdir, 0, CMP(F) T|M|RAWLIST, 0, 1 }, /* R */ { "save", save, 0, CMP(F) STRLIST, 0, 0 }, /* R */ { "Save", Save, 0, CMP(F) STRLIST, 0, 0 }, - { "source", source, 0, CMP(F) M|RAWLIST, 1, 1 }, - { "set", set, S, CMP(sF) M|RAWLIST, 0, 1000 }, - { "shell", dosh, 0, CMP(n) I|NOLIST, 0, 0 }, - { "show", show, S, CMP(S) M|RAWLIST, 0, 1000 }, - { "version", pversion, S, CMP(n) M|NOLIST, 0, 0 }, - { "group", group, S, CMP(a) M|RAWLIST, 0, 1000 }, + { "source", source, 0, CMP(F) T|M|RAWLIST, 1, 1 }, + { "set", set, S, CMP(sF) T|M|RAWLIST, 0, 1000 }, + { "shell", dosh, 0, CMP(n) T|I|NOLIST, 0, 0 }, + { "show", show, S, CMP(S) T|M|RAWLIST, 0, 1000 }, + { "version", pversion, S, CMP(n) T|M|NOLIST, 0, 0 }, + { "group", group, S, CMP(a) T|M|RAWLIST, 0, 1000 }, /* R */ { "write", swrite, 0, CMP(F) STRLIST, 0, 0 }, { "from", from, S, CMP(n) MSGLIST, 0, MMNORM }, { "file", file, 0, CMP(f) T|M|RAWLIST, 0, 1 }, @@ -110,42 +110,42 @@ const struct cmd cmdtab[] = { { "forward", forward, 0, CMP(n) R|I|MSGLIST, 0, 0 }, #endif { "bounce", bounce, 0, CMP(n) R|I|MSGLIST, 0, 0 }, - { "?", help, S, CMP(n) M|NOLIST, 0, 0 }, + { "?", help, S, CMP(n) T|M|NOLIST, 0, 0 }, { "z", scroll, S, CMP(n) M|STRLIST, 0, 0 }, - { "headers", headers, S, CMP(n) MSGLIST, 0, MMNDEL }, - { "help", help, S, CMP(n) M|NOLIST, 0, 0 }, - { "=", pdot, S, CMP(n) MSGLIST, 0, MMNDEL }, + { "headers", headers, S, CMP(n) T|MSGLIST, 0, MMNDEL }, + { "help", help, S, CMP(n) T|M|NOLIST, 0, 0 }, + { "=", pdot, S, CMP(n) T|MSGLIST, 0, MMNDEL }, { "Reply", Respond, 0, CMP(n) R|I|MSGLIST, 0, MMNDEL }, { "Respond", Respond, 0, CMP(n) R|I|MSGLIST, 0, MMNDEL }, { "reply", respond, 0, CMP(n) R|I|MSGLIST, 0, MMNDEL }, { "respond", respond, 0, CMP(n) R|I|MSGLIST, 0, MMNDEL }, { "edit", editor, 0, CMP(n) I|MSGLIST, 0, MMNORM }, - { "echo", echo, S, CMP(F) M|RAWLIST, 0, 1000 }, + { "echo", echo, S, CMP(F) T|M|RAWLIST, 0, 1000 }, { "quit", quitcmd, 0, CMP(n) NOLIST, 0, 0 }, - { "list", pcmdlist, S, CMP(n) M|NOLIST, 0, 0 }, + { "list", pcmdlist, S, CMP(n) T|M|NOLIST, 0, 0 }, { "xit", rexit, 0, CMP(n) M|NOLIST, 0, 0 }, { "exit", rexit, 0, CMP(n) M|NOLIST, 0, 0 }, - { "size", messize, S, CMP(n) MSGLIST, 0, MMNDEL }, + { "size", messize, S, CMP(n) T|MSGLIST, 0, MMNDEL }, /* R */ { "hold", preserve, 0, CMP(n) W|MSGLIST, 0, MMNDEL }, - { "if", ifcmd, 0, CMP(F) F|M|RAWLIST, 1, 1 }, - { "ifdef", ifdefcmd, 0, CMP(F) F|M|RAWLIST, 1, 1 }, - { "ifndef", ifndefcmd, 0, CMP(F) F|M|RAWLIST, 1, 1 }, - { "else", elsecmd, 0, CMP(F) F|M|RAWLIST, 0, 0 }, - { "endif", endifcmd, 0, CMP(F) F|M|RAWLIST, 0, 0 }, - { "alternates", alternates, S, CMP(n) M|RAWLIST, 0, 1000 }, - { "ignore", igfield, S, CMP(n) M|RAWLIST, 0, 1000 }, - { "discard", igfield, S, CMP(n) M|RAWLIST, 0, 1000 }, - { "retain", retfield, S, CMP(n) M|RAWLIST, 0, 1000 }, - { "saveignore", saveigfield, S, CMP(n) M|RAWLIST, 0, 1000 }, - { "savediscard",saveigfield, S, CMP(n) M|RAWLIST, 0, 1000 }, - { "saveretain", saveretfield, S, CMP(n) M|RAWLIST, 0, 1000 }, -/* { "Header", Header, S, CMP(n) STRLIST, 0, 1000 }, */ - { "core", core, 0, CMP(F) M|NOLIST, 0, 0 }, - { "#", null, 0, CMP(n) M|NOLIST, 0, 0 }, - { "clobber", clobber, 0, CMP(n) M|RAWLIST, 0, 1 }, + { "if", ifcmd, 0, CMP(F) T|F|M|RAWLIST, 1, 1 }, + { "ifdef", ifdefcmd, 0, CMP(F) T|F|M|RAWLIST, 1, 1 }, + { "ifndef", ifndefcmd, 0, CMP(F) T|F|M|RAWLIST, 1, 1 }, + { "else", elsecmd, 0, CMP(F) T|F|M|RAWLIST, 0, 0 }, + { "endif", endifcmd, 0, CMP(F) T|F|M|RAWLIST, 0, 0 }, + { "alternates", alternates, S, CMP(n) T|M|RAWLIST, 0, 1000 }, + { "ignore", igfield, S, CMP(n) T|M|RAWLIST, 0, 1000 }, + { "discard", igfield, S, CMP(n) T|M|RAWLIST, 0, 1000 }, + { "retain", retfield, S, CMP(n) T|M|RAWLIST, 0, 1000 }, + { "saveignore", saveigfield, S, CMP(n) T|M|RAWLIST, 0, 1000 }, + { "savediscard",saveigfield, S, CMP(n) T|M|RAWLIST, 0, 1000 }, + { "saveretain", saveretfield, S, CMP(n) T|M|RAWLIST, 0, 1000 }, + { "Header", Header, S, CMP(n) T|M|STRLIST, 0, 1000 }, + { "core", core, 0, CMP(F) T|M|NOLIST, 0, 0 }, + { "#", null, 0, CMP(n) T|M|NOLIST, 0, 0 }, + { "clobber", clobber, 0, CMP(n) T|M|RAWLIST, 0, 1 }, { "inc", inc, S, CMP(n) T|NOLIST, 0, 0 }, - { "smopts", smoptscmd, S, CMP(m) M|RAWLIST, 0, 1000 }, - { "unsmopts", unsmoptscmd, S, CMP(M) M|RAWLIST, 1, 1000 }, + { "smopts", smoptscmd, S, CMP(m) T|M|RAWLIST, 0, 1000 }, + { "unsmopts", unsmoptscmd, S, CMP(M) T|M|RAWLIST, 1, 1000 }, /* R */ { "mkread", markread, 0, CMP(n) MSGLIST, 0, MMNDEL }, #ifdef MIME_SUPPORT /* R */ { "detach", detach, S, CMP(F) STRLIST, 0, 0 }, diff --git a/usr.bin/mail/collect.c b/usr.bin/mail/collect.c index d37758128905..396d10bd2544 100644 --- a/usr.bin/mail/collect.c +++ b/usr.bin/mail/collect.c @@ -1,4 +1,4 @@ -/* $NetBSD: collect.c,v 1.42 2007/10/29 23:20:38 christos Exp $ */ +/* $NetBSD: collect.c,v 1.43 2009/04/10 13:08:24 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)collect.c 8.2 (Berkeley) 4/19/94"; #else -__RCSID("$NetBSD: collect.c,v 1.42 2007/10/29 23:20:38 christos Exp $"); +__RCSID("$NetBSD: collect.c,v 1.43 2009/04/10 13:08:24 christos Exp $"); #endif #endif /* not lint */ @@ -54,6 +54,7 @@ __RCSID("$NetBSD: collect.c,v 1.42 2007/10/29 23:20:38 christos Exp $"); #ifdef MIME_SUPPORT #include "mime.h" #endif +#include "sig.h" #include "thread.h" @@ -67,19 +68,12 @@ __RCSID("$NetBSD: collect.c,v 1.42 2007/10/29 23:20:38 christos Exp $"); * receipt of an interrupt signal, the partial message can be salted * 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 jmp_buf colljmp; /* To get back to work */ -static int colljmp_p; /* whether to long jump */ -static jmp_buf collabort; /* To end collection with error */ - +static jmp_buf abort_jmpbuf; /* To end collection with error */ +static jmp_buf reset_jmpbuf; /* To get back to work */ +static int reset_on_stop; /* To do job control longjmp. */ /* * Write a file, ex-like if f set. @@ -133,15 +127,20 @@ exwrite(const char name[], FILE *fp, int f) static void mesedit(FILE *fp, int c) { - sig_t sigint = signal(SIGINT, SIG_IGN); - FILE *nf = run_editor(fp, (off_t)-1, c, 0); + struct sigaction osa; + sigset_t oset; + FILE *nf; + sig_check(); + (void)sig_ignore(SIGINT, &osa, &oset); + nf = run_editor(fp, (off_t)-1, c, 0); if (nf != NULL) { (void)fseek(nf, 0L, 2); collf = nf; (void)Fclose(fp); } - (void)signal(SIGINT, sigint); + (void)sig_restore(SIGINT, &osa, &oset); + sig_check(); } /* @@ -154,11 +153,15 @@ static void mespipe(FILE *fp, char cmd[]) { FILE *nf; - sig_t sigint = signal(SIGINT, SIG_IGN); + struct sigaction osa; + sigset_t oset; const char *shellcmd; int fd; char tempname[PATHSIZE]; + sig_check(); + (void)sig_ignore(SIGINT, &osa, &oset); + (void)snprintf(tempname, sizeof(tempname), "%s/mail.ReXXXXXXXXXX", tmpdir); if ((fd = mkstemp(tempname)) == -1 || @@ -176,7 +179,7 @@ mespipe(FILE *fp, char cmd[]) if ((shellcmd = value(ENAME_SHELL)) == NULL) shellcmd = _PATH_CSHELL; if (run_command(shellcmd, - 0, fileno(fp), fileno(nf), "-c", cmd, NULL) < 0) { + NULL, fileno(fp), fileno(nf), "-c", cmd, NULL) < 0) { (void)Fclose(nf); goto out; } @@ -191,8 +194,9 @@ mespipe(FILE *fp, char cmd[]) (void)fseek(nf, 0L, 2); collf = nf; (void)Fclose(fp); -out: - (void)signal(SIGINT, sigint); + out: + (void)sig_restore(SIGINT, &osa, &oset); + sig_check(); } /* @@ -267,29 +271,6 @@ interpolate(char ms[], FILE *fp, char *fn, int f) return 0; } -/* - * Print (continue) when continued after ^Z. - */ -/*ARGSUSED*/ -static void -collstop(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; - longjmp(colljmp, 1); - } -} - /* * Append the contents of the file to the end of the deadletter file. */ @@ -309,6 +290,7 @@ savedeadletter(FILE *fp) (void)umask(m); if (dbuf == NULL) return; + (void)printf("Saving message body to `%s'.\n", cp); while ((c = getc(fp)) != EOF) (void)putc(c, dbuf); (void)Fclose(dbuf); @@ -319,10 +301,10 @@ savedeadletter(FILE *fp) * On interrupt, come here to save the partial message in ~/dead.letter. * Then jump out of the collection loop. */ -/*ARGSUSED*/ static void -collint(int s __unused) +coll_int(int signo) { + /* * the control flow is subtle, because we can be called from ~q. */ @@ -334,30 +316,50 @@ collint(int s __unused) return; } hadintr = 1; - longjmp(colljmp, 1); + longjmp(reset_jmpbuf, signo); } rewind(collf); if (value(ENAME_NOSAVE) == NULL) savedeadletter(collf); - longjmp(collabort, 1); + longjmp(abort_jmpbuf, signo); } /*ARGSUSED*/ static void -collhup(int s __unused) +coll_hup(int signo __unused) { + rewind(collf); savedeadletter(collf); /* * Let's pretend nobody else wants to clean up, * a true statement at this time. */ - exit(1); + exit(EXIT_FAILURE); +} + +/* + * Print (continue) when continued after ^Z. + */ +static void +coll_stop(int signo) +{ + + if (reset_on_stop) { + reset_on_stop = 0; + hadintr = 0; + longjmp(reset_jmpbuf, signo); + } } PUBLIC FILE * collect(struct header *hp, int printheaders) { + volatile sig_t old_sigint; + volatile sig_t old_sighup; + volatile sig_t old_sigtstp; + volatile sig_t old_sigttin; + volatile sig_t old_sigttou; FILE *fbuf; int lc, cc; int c, fd, t; @@ -365,11 +367,10 @@ collect(struct header *hp, int printheaders) const char *cp; char tempname[PATHSIZE]; char mailtempname[PATHSIZE]; - int lastlong, rc; /* So we don't make 2 or more lines - out of a long input line. */ int eofcount; int longline; - sigset_t nset; + int lastlong, rc; /* So we don't make 2 or more lines + out of a long input line. */ /* The following are declared volatile to avoid longjmp clobbering. */ char volatile getsub; @@ -377,26 +378,20 @@ collect(struct header *hp, int printheaders) (void)memset(mailtempname, 0, sizeof(mailtempname)); collf = NULL; - /* - * Start catching signals from here, but we're still die on interrupts - * until we're in the main loop. - */ - (void)sigemptyset(&nset); - (void)sigaddset(&nset, SIGINT); - (void)sigaddset(&nset, SIGHUP); - (void)sigprocmask(SIG_BLOCK, &nset, NULL); - 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 (setjmp(collabort) || setjmp(colljmp)) { + + if (setjmp(abort_jmpbuf) || setjmp(reset_jmpbuf)) { (void)rm(mailtempname); goto err; } - (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); + sig_check(); + + sig_hold(); + old_sigint = sig_signal(SIGINT, coll_int); + old_sighup = sig_signal(SIGHUP, coll_hup); + old_sigtstp = sig_signal(SIGTSTP, coll_stop); + old_sigttin = sig_signal(SIGTTIN, coll_stop); + old_sigttou = sig_signal(SIGTTOU, coll_stop); + sig_release(); noreset++; (void)snprintf(mailtempname, sizeof(mailtempname), @@ -415,11 +410,13 @@ collect(struct header *hp, int printheaders) * refrain from printing a newline after * the headers (since some people mind). */ - t = GTO|GSUBJECT|GCC|GNL|GSMOPTS; + t = GTO | GSUBJECT | GCC | GNL | GSMOPTS; getsub = 0; if (hp->h_subject == NULL && value(ENAME_INTERACTIVE) != NULL && - (value(ENAME_ASK) != NULL || value(ENAME_ASKSUB) != NULL)) - t &= ~GNL, getsub++; + (value(ENAME_ASK) != NULL || value(ENAME_ASKSUB) != NULL)) { + t &= ~GNL; + getsub++; + } if (printheaders) { (void)puthead(hp, stdout, t); (void)fflush(stdout); @@ -428,8 +425,8 @@ collect(struct header *hp, int printheaders) escape = *cp; else escape = ESCAPE; - hadintr = 0; /* static - no longjmp problem */ - if (!setjmp(colljmp)) { + hadintr = 0; + if (setjmp(reset_jmpbuf) == 0) { if (getsub) (void)grabh(hp, GSUBJECT); } else { @@ -438,7 +435,7 @@ collect(struct header *hp, int printheaders) * Duplicate messages won't be printed because * the write is aborted if we get a SIGTTOU. */ -cont: + cont: if (hadintr) { (void)fflush(stdout); (void)fprintf(stderr, @@ -451,12 +448,13 @@ cont: eofcount = 0; /* reset after possible longjmp */ longline = 0; /* reset after possible longjmp */ for (;;) { - colljmp_p = 1; - c = mail_readline(stdin, linebuf, LINESIZE); - colljmp_p = 0; -#ifdef USE_EDITLINE + reset_on_stop = 1; + c = readline(stdin, linebuf, LINESIZE, reset_on_stop); + reset_on_stop = 0; + if (c < 0) { char *p; + if (value(ENAME_INTERACTIVE) != NULL && (p = value(ENAME_IGNOREEOF)) != NULL && ++eofcount < (*p == 0 ? 25 : atoi(p))) { @@ -465,18 +463,8 @@ cont: } break; } -#else - if (c < 0) { - if (value(ENAME_INTERACTIVE) != NULL && - value(ENAME_IGNOREEOF) != NULL && ++eofcount < 25) { - (void)printf("Use \".\" to terminate letter\n"); - continue; - } - break; - } -#endif lastlong = longline; - longline = c == LINESIZE-1; + longline = c == LINESIZE - 1; eofcount = 0; hadintr = 0; if (linebuf[0] == '.' && linebuf[1] == '\0' && @@ -540,7 +528,7 @@ cont: * Act like an interrupt happened. */ hadintr++; - collint(SIGINT); + coll_int(SIGINT); exit(1); /*NOTREACHED*/ @@ -551,7 +539,7 @@ cont: /* * Grab a bunch of headers. */ - (void)grabh(hp, GTO|GSUBJECT|GCC|GBCC|GSMOPTS); + (void)grabh(hp, GTO | GSUBJECT | GCC | GBCC | GSMOPTS); goto cont; case 't': /* @@ -651,7 +639,7 @@ cont: if ((shellcmd = value(ENAME_SHELL)) == NULL) shellcmd = _PATH_CSHELL; - rc2 = run_command(shellcmd, 0, nullfd, fileno(fbuf), "-c", cp + 1, NULL); + rc2 = run_command(shellcmd, NULL, nullfd, fileno(fbuf), "-c", cp + 1, NULL); (void)close(nullfd); @@ -680,7 +668,7 @@ cont: (void)fflush(stdout); lc = 0; cc = 0; - while ((rc = mail_readline(fbuf, linebuf, LINESIZE)) >= 0) { + while ((rc = readline(fbuf, linebuf, LINESIZE, 0)) >= 0) { if (rc != LINESIZE-1) lc++; if ((t = putline(collf, linebuf, rc != LINESIZE-1)) < 0) { @@ -729,7 +717,8 @@ cont: */ rewind(collf); (void)printf("-------\nMessage contains:\n"); - (void)puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); + (void)puthead(hp, stdout, + GTO | GSUBJECT | GCC | GBCC | GSMOPTS | GNL); while ((t = getc(collf)) != EOF) (void)putchar(t); goto cont; @@ -754,21 +743,24 @@ cont: } } goto out; -err: + err: if (collf != NULL) { (void)Fclose(collf); collf = NULL; } -out: + out: if (collf != NULL) rewind(collf); noreset--; - (void)sigprocmask(SIG_BLOCK, &nset, NULL); - (void)signal(SIGINT, saveint); - (void)signal(SIGHUP, savehup); - (void)signal(SIGTSTP, savetstp); - (void)signal(SIGTTOU, savettou); - (void)signal(SIGTTIN, savettin); - (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); + + sig_hold(); + (void)sig_signal(SIGINT, old_sigint); + (void)sig_signal(SIGHUP, old_sighup); + (void)sig_signal(SIGTSTP, old_sigtstp); + (void)sig_signal(SIGTTIN, old_sigttin); + (void)sig_signal(SIGTTOU, old_sigttou); + sig_release(); + + sig_check(); return collf; } diff --git a/usr.bin/mail/complete.c b/usr.bin/mail/complete.c index e079040fcd9d..f3a430bcc57a 100644 --- a/usr.bin/mail/complete.c +++ b/usr.bin/mail/complete.c @@ -1,4 +1,4 @@ -/* $NetBSD: complete.c,v 1.18 2009/02/11 19:22:22 christos Exp $ */ +/* $NetBSD: complete.c,v 1.19 2009/04/10 13:08:24 christos Exp $ */ /*- * Copyright (c) 1997-2000,2005,2006 The NetBSD Foundation, Inc. @@ -34,11 +34,10 @@ */ #ifdef USE_EDITLINE -#undef NO_EDITCOMPLETE #include #ifndef lint -__RCSID("$NetBSD: complete.c,v 1.18 2009/02/11 19:22:22 christos Exp $"); +__RCSID("$NetBSD: complete.c,v 1.19 2009/04/10 13:08:24 christos Exp $"); #endif /* not lint */ /* @@ -66,6 +65,7 @@ __RCSID("$NetBSD: complete.c,v 1.18 2009/02/11 19:22:22 christos Exp $"); #ifdef MIME_SUPPORT #include "mime.h" #endif +#include "sig.h" #ifdef THREAD_SUPPORT #include "thread.h" #endif @@ -738,6 +738,7 @@ static int is_emacs_mode(EditLine *el) { char *mode; + if (el_get(el, EL_EDITOR, &mode) == -1) return 0; return equal(mode, "emacs"); @@ -747,6 +748,7 @@ static int emacs_ctrl_d(EditLine *el, const LineInfo *lf, int ch) { static char delunder[3] = { CTRL('f'), CTRL('h'), '\0' }; + if (ch == CTRL('d') && is_emacs_mode(el)) { /* CTRL-D is special */ if (lf->buffer == lf->lastchar) return CC_EOF; @@ -882,7 +884,7 @@ split_word(int *cmpltype, const char *cmplarray, LineInfo *li) } /* check for 'continuation' completes (which are uppercase) */ - arraylen = strlen(cmplarray); + arraylen = (int)strlen(cmplarray); if (cursorc >= arraylen && arraylen > 0 && isupper((unsigned char)cmplarray[arraylen - 1])) @@ -1068,12 +1070,10 @@ mime_enc_complete(EditLine *el, int ch) * Initializes of all editline and completion data strutures. * * my_gets() - * Returns the next line of input as a NULL termnated string without - * the trailing newline. - * - * my_getline() - * Same as my_gets(), but strips leading and trailing whitespace - * and returns an empty line if it gets a SIGINT. + * Displays prompt, calls el_gets() and deals with history. + * Returns the next line of input as a NULL termnated string + * without the trailing newline, or NULL if el_gets() sees is an + * error or signal. */ static const char *el_prompt; @@ -1085,30 +1085,68 @@ show_prompt(EditLine *e __unused) return el_prompt; } +/* + * Write the current INTR character to fp in a friendly form. + */ +static void +echo_INTR(void *p) +{ + struct termios ttybuf; + char buf[5]; + FILE *fp; + + fp = p; + if (tcgetattr(fileno(stdin), &ttybuf) == -1) + warn("tcgetattr"); + else { + (void)vis(buf, ttybuf.c_cc[VINTR], VIS_SAFE | VIS_NOSLASH, 0); + (void)fprintf(fp, "%s", buf); + (void)fflush(fp); + } +} + +static sig_t old_sigint; +static void +comp_intr(int signo) +{ + + echo_INTR(stdout); + old_sigint(signo); +} + PUBLIC char * my_gets(el_mode_t *em, const char *prompt, char *string) { - int cnt; + static char line[LINE_MAX]; size_t len; + int cnt; const char *buf; HistEvent ev; - static char line[LINE_MAX]; + + sig_check(); el_prompt = prompt; - if (string) el_push(em->el, string); + /* + * Let el_gets() deal with flow control. Also, make sure we + * output a ^C when we get a SIGINT as el_gets() doesn't echo + * one. + */ + old_sigint = sig_signal(SIGINT, comp_intr); buf = el_gets(em->el, &cnt); + (void)sig_signal(SIGINT, old_sigint); - if (buf == NULL || cnt <= 0) { - if (cnt == 0) - (void)putc('\n', stdout); + if (buf == NULL) { + sig_check(); return NULL; } + assert(cnt > 0); if (buf[cnt - 1] == '\n') cnt--; /* trash the trailing LF */ + len = MIN(sizeof(line) - 1, (size_t)cnt); (void)memcpy(line, buf, len); line[cnt] = '\0'; @@ -1116,56 +1154,15 @@ my_gets(el_mode_t *em, const char *prompt, char *string) /* enter non-empty lines into history */ if (em->hist) { const char *p; + p = skip_WSP(line); if (*p && history(em->hist, &ev, H_ENTER, line) == 0) (void)printf("Failed history entry: %s", line); } + sig_check(); return line; } -#ifdef MIME_SUPPORT -/* XXX - do we really want this here? */ - -static jmp_buf intjmp; -/*ARGSUSED*/ -static void -sigint(int signum __unused) -{ - siglongjmp(intjmp, 1); -} - -PUBLIC char * -my_getline(el_mode_t *em, const char *prompt, const char *str) -{ - sig_t saveint; - char *cp; - char *line; - - saveint = signal(SIGINT, sigint); - if (sigsetjmp(intjmp, 1)) { - (void)signal(SIGINT, saveint); - (void)putc('\n', stdout); - return __UNCONST(""); - } - - line = my_gets(em, prompt, __UNCONST(str)); - /* LINTED */ - line = line ? savestr(line) : __UNCONST(""); - - (void)signal(SIGINT, saveint); - - /* strip trailing white space */ - for (cp = line + strlen(line) - 1; - cp >= line && is_WSP(*cp); cp--) - *cp = '\0'; - - /* skip leading white space */ - cp = skip_WSP(line); - - return cp; -} -#endif /* MIME_SUPPORT */ - static el_mode_t init_el_mode( const char *el_editor, diff --git a/usr.bin/mail/complete.h b/usr.bin/mail/complete.h index 1dfc184c541b..ae6d5f0d41fc 100644 --- a/usr.bin/mail/complete.h +++ b/usr.bin/mail/complete.h @@ -1,4 +1,4 @@ -/* $NetBSD: complete.h,v 1.5 2008/04/28 20:24:14 martin Exp $ */ +/* $NetBSD: complete.h,v 1.6 2009/04/10 13:08:24 christos Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. @@ -50,7 +50,6 @@ struct el_modes_s { extern struct el_modes_s elm; char *my_gets(el_mode_t *, const char *, char *); -char *my_getline(el_mode_t *, const char *, const char *); void init_editline(void); /* diff --git a/usr.bin/mail/def.h b/usr.bin/mail/def.h index 3c27483d84e8..acd17a57cf5a 100644 --- a/usr.bin/mail/def.h +++ b/usr.bin/mail/def.h @@ -1,4 +1,4 @@ -/* $NetBSD: def.h,v 1.26 2007/10/27 15:14:50 christos Exp $ */ +/* $NetBSD: def.h,v 1.27 2009/04/10 13:08:24 christos Exp $ */ /* * Copyright (c) 1980, 1993 * The Regents of the University of California. All rights reserved. @@ -28,7 +28,7 @@ * SUCH DAMAGE. * * @(#)def.h 8.4 (Berkeley) 4/20/95 - * $NetBSD: def.h,v 1.26 2007/10/27 15:14:50 christos Exp $ + * $NetBSD: def.h,v 1.27 2009/04/10 13:08:24 christos Exp $ */ /* @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +62,8 @@ #include #include #include +#include + #include "pathnames.h" #define APPEND /* New mail goes to end of mailbox */ @@ -111,6 +114,7 @@ #define ENAME_METOO "metoo" #define ENAME_NOHEADER "noheader" #define ENAME_NOSAVE "nosave" +#define ENAME_PAGE_ALSO "page-also" #define ENAME_PAGER "PAGER" #define ENAME_PAGER_OFF "pager-off" #define ENAME_PROMPT "prompt" @@ -131,7 +135,6 @@ #define ENAME_VERBOSE "verbose" #define ENAME_VISUAL "VISUAL" -#define sizeofarray(a) (sizeof(a)/sizeof(*a)) #define equal(a, b) (strcmp(a,b)==0)/* A nice function to string compare */ struct message { @@ -249,7 +252,7 @@ struct headline { #ifdef MIME_SUPPORT #define GMIME 0x040 /* mime flag */ #endif -#define GMASK (GTO|GSUBJECT|GCC|GBCC|GSMOPTS) +#define GMASK (GTO | GSUBJECT | GCC | GBCC | GSMOPTS) /* Mask of places from whence */ #define GNL 0x100 /* Print blank line after */ @@ -318,14 +321,14 @@ struct attachment { */ struct header { - struct name *h_to; /* Dynamic "To:" string */ - char *h_subject; /* Subject string */ - struct name *h_cc; /* Carbon copies string */ - struct name *h_bcc; /* Blind carbon copies */ - struct name *h_smopts; /* Sendmail options */ - char *h_in_reply_to; - struct name *h_references; - char *h_extra; /* extra lines to output */ + struct name *h_to; /* Dynamic "To:" string */ + char *h_subject; /* Subject string */ + struct name *h_cc; /* Carbon copies string */ + struct name *h_bcc; /* Blind carbon copies */ + struct name *h_smopts; /* Sendmail options */ + char *h_in_reply_to; /* In-Reply-To: field */ + struct name *h_references; /* References: field */ + struct name *h_extra; /* extra header fields */ #ifdef MIME_SUPPORT char *h_mime_boundary; /* MIME multipart boundary string */ struct Content h_Content; /* MIME content for message */ @@ -406,13 +409,6 @@ enum mailmode_e { mm_hdrsonly /* headers only mode */ }; -/* - * Kludges to handle the change from setexit / reset to setjmp / longjmp - */ - -#define setexit() (void)setjmp(srbuf) -#define reset(x) longjmp(srbuf, x) - /* * Truncate a file to the last character written. This is * useful just before closing an old file that was opened @@ -438,7 +434,7 @@ is_WSP(int c) return c == ' ' || c == '\t'; } -static inline char* +static inline char * skip_WSP(const char *cp) { while (is_WSP(*cp)) @@ -446,7 +442,7 @@ skip_WSP(const char *cp) return __UNCONST(cp); } -static inline char* +static inline char * skip_space(char *p) { while (isspace((unsigned char)*p)) @@ -454,4 +450,19 @@ skip_space(char *p) return p; } +/* + * strip trailing white space + */ +static inline char * +strip_WSP(char *line) +{ + char *cp; + + cp = line + strlen(line) - 1; + while (cp >= line && is_WSP(*cp)) + cp--; + *++cp = '\0'; + return cp; +} + #endif /* __DEF_H__ */ diff --git a/usr.bin/mail/dotlock.c b/usr.bin/mail/dotlock.c index cb7c0e4f23b6..4662fb46bb99 100644 --- a/usr.bin/mail/dotlock.c +++ b/usr.bin/mail/dotlock.c @@ -1,4 +1,4 @@ -/* $NetBSD: dotlock.c,v 1.9 2007/10/29 23:20:38 christos Exp $ */ +/* $NetBSD: dotlock.c,v 1.10 2009/04/10 13:08:24 christos Exp $ */ /* * Copyright (c) 1996 Christos Zoulas. All rights reserved. @@ -31,11 +31,12 @@ #include #ifndef lint -__RCSID("$NetBSD: dotlock.c,v 1.9 2007/10/29 23:20:38 christos Exp $"); +__RCSID("$NetBSD: dotlock.c,v 1.10 2009/04/10 13:08:24 christos Exp $"); #endif #include "rcv.h" #include "extern.h" +#include "sig.h" #ifndef O_SYNC #define O_SYNC 0 @@ -139,6 +140,7 @@ dot_lock(const char *fname, int pollinterval, FILE *fp, const char *msg) { char path[MAXPATHLEN]; sigset_t nset, oset; + int retval; (void)sigemptyset(&nset); (void)sigaddset(&nset, SIGHUP); @@ -152,17 +154,20 @@ dot_lock(const char *fname, int pollinterval, FILE *fp, const char *msg) (void)snprintf(path, sizeof(path), "%s.lock", fname); + retval = -1; for (;;) { + sig_check(); (void)sigprocmask(SIG_BLOCK, &nset, &oset); if (create_exclusive(path) != -1) { (void)sigprocmask(SIG_SETMASK, &oset, NULL); - return 0; + retval = 0; + break; } else (void)sigprocmask(SIG_SETMASK, &oset, NULL); if (errno != EEXIST) - return -1; + break; if (fp && msg) (void)fputs(msg, fp); @@ -170,11 +175,13 @@ dot_lock(const char *fname, int pollinterval, FILE *fp, const char *msg) if (pollinterval) { if (pollinterval == -1) { errno = EEXIST; - return -1; + break; } (void)sleep((unsigned int)pollinterval); } } + sig_check(); + return retval; } PUBLIC void diff --git a/usr.bin/mail/edit.c b/usr.bin/mail/edit.c index 8ca9bbe6f805..cf37d4b94f1f 100644 --- a/usr.bin/mail/edit.c +++ b/usr.bin/mail/edit.c @@ -1,4 +1,4 @@ -/* $NetBSD: edit.c,v 1.24 2007/10/29 23:20:38 christos Exp $ */ +/* $NetBSD: edit.c,v 1.25 2009/04/10 13:08:24 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -34,13 +34,14 @@ #if 0 static char sccsid[] = "@(#)edit.c 8.1 (Berkeley) 6/6/93"; #else -__RCSID("$NetBSD: edit.c,v 1.24 2007/10/29 23:20:38 christos Exp $"); +__RCSID("$NetBSD: edit.c,v 1.25 2009/04/10 13:08:24 christos Exp $"); #endif #endif /* not lint */ #include "rcv.h" #include "extern.h" #include "thread.h" +#include "sig.h" /* * Mail -- a mail program @@ -107,10 +108,10 @@ run_editor(FILE *fp, off_t size, int editortype, int readonlyflag) goto out; } nf = NULL; - if ((editcmd = - value(editortype == 'e' ? ENAME_EDITOR : ENAME_VISUAL)) == NULL) + editcmd = value(editortype == 'e' ? ENAME_EDITOR : ENAME_VISUAL); + if (editcmd == NULL) editcmd = editortype == 'e' ? _PATH_EX : _PATH_VI; - if (run_command(editcmd, 0, 0, -1, tempname, NULL) < 0) { + if (run_command(editcmd, NULL, 0, -1, tempname, NULL) < 0) { (void)unlink(tempname); goto out; } @@ -163,14 +164,15 @@ edit1(int *msgvec, int editortype) */ msgCount = get_msgCount(); for (i = 0; msgvec[i] && i < msgCount; i++) { - sig_t sigint; + sigset_t oset; + struct sigaction osa; if (i > 0) { char buf[100]; char *p; (void)printf("Edit message %d [ynq]? ", msgvec[i]); - if (fgets(buf, sizeof(buf), stdin) == 0) + if (fgets(buf, (int)sizeof(buf), stdin) == 0) break; p = skip_WSP(buf); if (*p == 'q') @@ -180,7 +182,8 @@ edit1(int *msgvec, int editortype) } dot = mp = get_message(msgvec[i]); touch(mp); - sigint = signal(SIGINT, SIG_IGN); + sig_check(); + (void)sig_ignore(SIGINT, &osa, &oset); fp = run_editor(setinput(mp), mp->m_size, editortype, readonly); if (fp != NULL) { @@ -213,7 +216,8 @@ edit1(int *msgvec, int editortype) warn("/tmp"); (void)Fclose(fp); } - (void)signal(SIGINT, sigint); + (void)sig_restore(SIGINT, &osa, &oset); + sig_check(); } return 0; } diff --git a/usr.bin/mail/extern.h b/usr.bin/mail/extern.h index 7ff31951c7d7..986a935b39d8 100644 --- a/usr.bin/mail/extern.h +++ b/usr.bin/mail/extern.h @@ -1,4 +1,4 @@ -/* $NetBSD: extern.h,v 1.30 2007/10/27 15:14:50 christos Exp $ */ +/* $NetBSD: extern.h,v 1.31 2009/04/10 13:08:24 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -29,7 +29,7 @@ * SUCH DAMAGE. * * @(#)extern.h 8.2 (Berkeley) 4/20/95 - * $NetBSD: extern.h,v 1.30 2007/10/27 15:14:50 christos Exp $ + * $NetBSD: extern.h,v 1.31 2009/04/10 13:08:24 christos Exp $ */ #ifndef __EXTERN_H__ @@ -126,6 +126,7 @@ void sort(const char **); struct smopts_s *findsmopts(const char *, int); int smoptscmd(void *); int unsmoptscmd(void *); +int Header(void *); /* * from cmdtab.c @@ -158,10 +159,11 @@ const char *expand(const char *); off_t fsize(FILE *); const char *getdeadletter(void); int getfold(char *, size_t); -void holdsigs(void); -int mail_readline(FILE *, char *, int); +#ifdef USE_EDITLINE +#define readline xreadline /* readline() is defined in libedit */ +#endif +int readline(FILE *, char *, int, int); int putline(FILE *, const char *, int); -void relsesigs(void); int rm(char *); FILE * setinput(const struct message *); void setptr(FILE *, off_t); @@ -201,7 +203,7 @@ int first(int, int); int get_Hflag(char **); int getmsglist(char *, int *, int); int getrawlist(const char [], char **, int); -int show_headers_and_exit(int) __attribute__((__noreturn__)); +int show_headers_and_exit(int) __dead; /* * from main.c @@ -253,7 +255,7 @@ void flush_files(FILE *, int); /* * from quit.c */ -void quit(void); +void quit(jmp_buf); int quitcmd(void *); /* diff --git a/usr.bin/mail/fio.c b/usr.bin/mail/fio.c index 333f17ad6683..8d2df06ccfcb 100644 --- a/usr.bin/mail/fio.c +++ b/usr.bin/mail/fio.c @@ -1,4 +1,4 @@ -/* $NetBSD: fio.c,v 1.31 2007/10/29 23:20:38 christos Exp $ */ +/* $NetBSD: fio.c,v 1.32 2009/04/10 13:08:24 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -34,13 +34,14 @@ #if 0 static char sccsid[] = "@(#)fio.c 8.2 (Berkeley) 4/20/95"; #else -__RCSID("$NetBSD: fio.c,v 1.31 2007/10/29 23:20:38 christos Exp $"); +__RCSID("$NetBSD: fio.c,v 1.32 2009/04/10 13:08:24 christos Exp $"); #endif #endif /* not lint */ #include "rcv.h" #include "extern.h" #include "thread.h" +#include "sig.h" /* * Mail -- a mail program @@ -215,10 +216,8 @@ setptr(FILE *ibuf, off_t offset) for (;;) { if (fgets(linebuf, LINESIZE, ibuf) == NULL) { - if (append(&this, mestmp)) { - warn("temporary file"); - exit(1); - } + if (append(&this, mestmp)) + err(EXIT_FAILURE, "temporary file"); makemessage(mestmp, omsgCount, nmsgCount); return; } @@ -234,18 +233,14 @@ setptr(FILE *ibuf, off_t offset) len--; } (void)fwrite(linebuf, sizeof(*linebuf), len, otf); - if (ferror(otf)) { - warn("/tmp"); - exit(1); - } + if (ferror(otf)) + err(EXIT_FAILURE, "/tmp"); if(len) linebuf[len - 1] = 0; if (maybe && linebuf[0] == 'F' && ishead(linebuf)) { nmsgCount++; - if (append(&this, mestmp)) { - warn("temporary file"); - exit(1); - } + if (append(&this, mestmp)) + err(EXIT_FAILURE, "temporary file"); message_init(&this, offset, MUSED|MNEW); inhead = 1; } else if (linebuf[0] == 0) { @@ -274,7 +269,7 @@ setptr(FILE *ibuf, off_t offset) this.m_lines++; if (!inhead) { int lines_plus_wraps = 1; - size_t linelen = strlen(linebuf); + int linelen = (int)strlen(linebuf); if (screenwidth && (int)linelen > screenwidth) { lines_plus_wraps = linelen / screenwidth; @@ -305,7 +300,7 @@ putline(FILE *obuf, const char *linebuf, int outlf) } if (ferror(obuf)) return -1; - return c; + return (int)c; } /* @@ -314,16 +309,34 @@ putline(FILE *obuf, const char *linebuf, int outlf) * include the newline at the end. */ PUBLIC int -mail_readline(FILE *ibuf, char *linebuf, int linesize) +readline(FILE *ibuf, char *linebuf, int linesize, int no_restart) { + struct sigaction osa_sigtstp; + struct sigaction osa_sigttin; + struct sigaction osa_sigttou; int n; clearerr(ibuf); + + sig_check(); + if (no_restart) { + (void)sig_setflags(SIGTSTP, 0, &osa_sigtstp); + (void)sig_setflags(SIGTTIN, 0, &osa_sigttin); + (void)sig_setflags(SIGTTOU, 0, &osa_sigttou); + } if (fgets(linebuf, linesize, ibuf) == NULL) - return -1; - n = strlen(linebuf); - if (n > 0 && linebuf[n - 1] == '\n') - linebuf[--n] = '\0'; + n = -1; + else { + n = (int)strlen(linebuf); + if (n > 0 && linebuf[n - 1] == '\n') + linebuf[--n] = '\0'; + } + if (no_restart) { + (void)sigaction(SIGTSTP, &osa_sigtstp, NULL); + (void)sigaction(SIGTTIN, &osa_sigttin, NULL); + (void)sigaction(SIGTTOU, &osa_sigttou, NULL); + } + sig_check(); return n; } @@ -358,35 +371,6 @@ rm(char *name) return unlink(name); } -static int sigdepth; /* depth of holdsigs() */ -static sigset_t nset, oset; -/* - * Hold signals SIGHUP, SIGINT, and SIGQUIT. - */ -PUBLIC void -holdsigs(void) -{ - - if (sigdepth++ == 0) { - (void)sigemptyset(&nset); - (void)sigaddset(&nset, SIGHUP); - (void)sigaddset(&nset, SIGINT); - (void)sigaddset(&nset, SIGQUIT); - (void)sigprocmask(SIG_BLOCK, &nset, &oset); - } -} - -/* - * Release signals SIGHUP, SIGINT, and SIGQUIT. - */ -PUBLIC void -relsesigs(void) -{ - - if (--sigdepth == 0) - (void)sigprocmask(SIG_SETMASK, &oset, NULL); -} - /* * Determine the size of the file possessed by * the passed buffer. @@ -434,7 +418,8 @@ expand(const char *name) { char xname[PATHSIZE]; char cmdbuf[PATHSIZE]; /* also used for file names */ - int pid, l; + pid_t pid; + ssize_t l; char *cp; const char *shellcmd; int pivec[2]; @@ -481,7 +466,7 @@ expand(const char *name) (void)snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name); if ((shellcmd = value(ENAME_SHELL)) == NULL) shellcmd = _PATH_CSHELL; - pid = start_command(shellcmd, 0, -1, pivec[1], "-c", cmdbuf, NULL); + pid = start_command(shellcmd, NULL, -1, pivec[1], "-c", cmdbuf, NULL); if (pid < 0) { (void)close(pivec[0]); (void)close(pivec[1]); diff --git a/usr.bin/mail/format.c b/usr.bin/mail/format.c index a8f3b836c237..1d48108d7679 100644 --- a/usr.bin/mail/format.c +++ b/usr.bin/mail/format.c @@ -1,4 +1,4 @@ -/* $NetBSD: format.c,v 1.13 2008/04/28 20:24:14 martin Exp $ */ +/* $NetBSD: format.c,v 1.14 2009/04/10 13:08:24 christos Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ #include #ifndef __lint__ -__RCSID("$NetBSD: format.c,v 1.13 2008/04/28 20:24:14 martin Exp $"); +__RCSID("$NetBSD: format.c,v 1.14 2009/04/10 13:08:24 christos Exp $"); #endif /* not __lint__ */ #include @@ -796,7 +796,7 @@ dateof(struct tm *tm, struct message *mp, int use_hl_date) */ tm->tm_isdst = -1; /* let mktime(3) determine tm_isdst */ headline[0] = '\0'; - (void)mail_readline(setinput(mp), headline, sizeof(headline)); + (void)readline(setinput(mp), headline, (int)sizeof(headline), 0); parse(headline, &hl, pbuf); if (hl.l_date == NULL) warnx("invalid headline: `%s'", headline); diff --git a/usr.bin/mail/glob.h b/usr.bin/mail/glob.h index e7adc57c90ee..246def67b43e 100644 --- a/usr.bin/mail/glob.h +++ b/usr.bin/mail/glob.h @@ -1,4 +1,4 @@ -/* $NetBSD: glob.h,v 1.11 2007/10/30 02:28:31 christos Exp $ */ +/* $NetBSD: glob.h,v 1.12 2009/04/10 13:08:25 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -29,7 +29,7 @@ * SUCH DAMAGE. * * from: @(#)glob.h 8.1 (Berkeley) 6/6/93 - * $NetBSD: glob.h,v 1.11 2007/10/30 02:28:31 christos Exp $ + * $NetBSD: glob.h,v 1.12 2009/04/10 13:08:25 christos Exp $ */ /* @@ -90,8 +90,6 @@ EXTERN int wait_status; /* wait status set by wait_child() */ EXTERN int cond; /* Current state of conditional exc. */ EXTERN struct cond_stack_s *cond_stack; /* stack for if/else/endif condition */ -#include - -EXTERN jmp_buf srbuf; +EXTERN struct name *extra_headers; /* extra header lines */ #endif /* __GLOB_H__ */ diff --git a/usr.bin/mail/lex.c b/usr.bin/mail/lex.c index a69dc4bd4c76..d2af18fc42d6 100644 --- a/usr.bin/mail/lex.c +++ b/usr.bin/mail/lex.c @@ -1,4 +1,4 @@ -/* $NetBSD: lex.c,v 1.36 2007/12/17 22:06:00 christos Exp $ */ +/* $NetBSD: lex.c,v 1.37 2009/04/10 13:08:25 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -34,19 +34,20 @@ #if 0 static char sccsid[] = "@(#)lex.c 8.2 (Berkeley) 4/20/95"; #else -__RCSID("$NetBSD: lex.c,v 1.36 2007/12/17 22:06:00 christos Exp $"); +__RCSID("$NetBSD: lex.c,v 1.37 2009/04/10 13:08:25 christos Exp $"); #endif #endif /* not lint */ #include +#include #include "rcv.h" -#include #include "extern.h" #ifdef USE_EDITLINE #include "complete.h" #endif #include "format.h" +#include "sig.h" #include "thread.h" /* @@ -57,8 +58,88 @@ __RCSID("$NetBSD: lex.c,v 1.36 2007/12/17 22:06:00 christos Exp $"); static const char *prompt = DEFAULT_PROMPT; static int *msgvec; -static int reset_on_stop; /* do a reset() if stopped */ +static int inithdr; /* Am printing startup headers. */ +static jmp_buf jmpbuf; /* The reset jmpbuf */ +static int reset_on_stop; /* To do job control longjmp. */ +#ifdef DEBUG_FILE_LEAK +struct glue { + struct glue *next; + int niobs; + FILE *iobs; +}; +extern struct glue __sglue; + +static int open_fd_cnt; +static int open_fp_cnt; + +static int +file_count(void) +{ + struct glue *gp; + FILE *fp; + int n; + int cnt; + + cnt = 0; + for (gp = &__sglue; gp; gp = gp->next) { + for (fp = gp->iobs, n = gp->niobs; --n >= 0; fp++) + if (fp->_flags) + cnt++; + } + return cnt; +} + +static int +fds_count(void) +{ + int maxfd; + int cnt; + int fd; + + maxfd = fcntl(0, F_MAXFD); + if (maxfd == -1) { + warn("fcntl"); + return -1; + } + + cnt = 0; + for (fd = 0; fd <= maxfd; fd++) { + struct stat sb; + + if (fstat(fd, &sb) != -1) + cnt++; + else if (errno != EBADF +#ifdef BROKEN_CLONE_STAT /* see PRs 37878 and 37550 */ + && errno != EOPNOTSUPP +#endif + ) + warn("fstat(%d): errno=%d", fd, errno); + } + return cnt; +} + +static void +file_leak_init(void) +{ + open_fd_cnt = fds_count(); + open_fp_cnt = file_count(); +} + +static void +file_leak_check(void) +{ + if (open_fp_cnt != file_count() || + open_fd_cnt != fds_count()) { + (void)printf("FILE LEAK WARNING: " + "fp-count: %d (%d) " + "fd-count: %d (%d) max-fd: %d\n", + file_count(), open_fp_cnt, + fds_count(), open_fd_cnt, + fcntl(0, F_MAXFD)); + } +} +#endif /* DEBUG_FILE_LEAK */ /* * Set the size of the message vector used to construct argument @@ -129,9 +210,10 @@ setfile(const char *name) * the message[] data structure. */ - holdsigs(); + sig_check(); + sig_hold(); if (shudclob) - quit(); + quit(jmpbuf); /* * Copy the messages into /tmp @@ -172,7 +254,8 @@ setfile(const char *name) */ mailsize = ftell(ibuf); (void)Fclose(ibuf); - relsesigs(); + sig_release(); + sig_check(); sawcom = 0; if (!edit && get_abs_msgCount() == 0) { nomail: @@ -199,7 +282,8 @@ incfile(void) ibuf = Fopen(mailname, "r"); if (ibuf == NULL) return -1; - holdsigs(); + sig_check(); + sig_hold(); newsize = fsize(ibuf); if (newsize == 0 || /* mail box is now empty??? */ newsize < mailsize) { /* mail box has shrunk??? */ @@ -216,7 +300,8 @@ incfile(void) rval = get_abs_msgCount() - omsgCount; done: (void)Fclose(ibuf); - relsesigs(); + sig_release(); + sig_check(); return rval; } @@ -244,29 +329,6 @@ comment_char(char *line) return NULL; } -/* - * When we wake up after ^Z, reprint the prompt. - */ -static void -stop(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 (reset_on_stop) { - reset_on_stop = 0; - reset(0); - } -} - - - /* * Signal handler is hooked by setup_piping(). * Respond to a broken pipe signal -- @@ -276,9 +338,10 @@ static jmp_buf pipestop; /*ARGSUSED*/ static void -brokpipe(int signo __unused) +lex_brokpipe(int signo) { - longjmp(pipestop, 1); + + longjmp(pipestop, signo); } /* @@ -331,19 +394,51 @@ shellpr(char *cp) return NULL; } +static int +do_paging(const char *cmd, int c_pipe) +{ + char *cp, *p; + + if (value(ENAME_PAGER_OFF) != NULL) + return 0; + + if (c_pipe & C_PIPE_PAGER) + return 1; + + if (c_pipe & C_PIPE_CRT && value(ENAME_CRT) != NULL) + return 1; + + if ((cp = value(ENAME_PAGE_ALSO)) == NULL) + return 0; + + if ((p = strcasestr(cp, cmd)) == NULL) + return 0; + + if (p != cp && p[-1] != ',' && !is_WSP(p[-1])) + return 0; + + p += strlen(cmd); + + return (*p == '\0' || *p == ',' || is_WSP(*p)); +} + /* * Setup any pipe or redirection that the command line indicates. * If none, then setup the pager unless "pager-off" is defined. */ static FILE *fp_stop = NULL; static int oldfd1 = -1; +static sig_t old_sigpipe; + static int -setup_piping(char *cmdline, int c_pipe) +setup_piping(const char *cmd, char *cmdline, int c_pipe) { FILE *fout; FILE *last_file; char *cp; + sig_check(); + last_file = last_registered_file(0); fout = NULL; @@ -374,8 +469,7 @@ setup_piping(char *cmdline, int c_pipe) } } - else if (value(ENAME_PAGER_OFF) == NULL && (c_pipe & C_PIPE_PAGER || - (c_pipe & C_PIPE_CRT && value(ENAME_CRT) != NULL))) { + else if (do_paging(cmd, c_pipe)) { const char *pager; pager = value(ENAME_PAGER); if (pager == NULL || *pager == '\0') @@ -388,7 +482,7 @@ setup_piping(char *cmdline, int c_pipe) } if (fout) { - (void)signal(SIGPIPE, brokpipe); + old_sigpipe = sig_signal(SIGPIPE, lex_brokpipe); (void)fflush(stdout); if ((oldfd1 = dup(STDOUT_FILENO)) == -1) err(EXIT_FAILURE, "dup failed"); @@ -405,19 +499,26 @@ setup_piping(char *cmdline, int c_pipe) static void close_piping(void) { + sigset_t oset; + struct sigaction osa; + if (oldfd1 != -1) { (void)fflush(stdout); if (fileno(stdout) != oldfd1 && dup2(oldfd1, STDOUT_FILENO) == -1) err(EXIT_FAILURE, "dup2 failed"); - (void)signal(SIGPIPE, SIG_IGN); + (void)sig_ignore(SIGPIPE, &osa, &oset); + close_top_files(fp_stop); fp_stop = NULL; (void)close(oldfd1); oldfd1 = -1; - (void)signal(SIGPIPE, SIG_DFL); + + (void)sig_signal(SIGPIPE, old_sigpipe); + (void)sig_restore(SIGPIPE, &osa, &oset); } + sig_check(); } /* @@ -486,6 +587,7 @@ execute(char linebuf[], enum execute_contxt_e contxt) char *arglist[MAXARGC]; const struct cmd *com = NULL; char *volatile cp; + int retval; int c; int e = 1; @@ -563,10 +665,12 @@ execute(char linebuf[], enum execute_contxt_e contxt) } if (!sourcing && com->c_pipe && value(ENAME_INTERACTIVE) != NULL) { + + sig_check(); if (setjmp(pipestop)) goto out; - if (setup_piping(cp, com->c_pipe) == -1) + if (setup_piping(com->c_name, cp, com->c_pipe) == -1) goto out; } switch (com->c_argtype & ARGTYPE_MASK) { @@ -619,8 +723,7 @@ execute(char linebuf[], enum execute_contxt_e contxt) /* * A vector of strings, in shell style. */ - if ((c = getrawlist(cp, arglist, - sizeof(arglist) / sizeof(*arglist))) < 0) + if ((c = getrawlist(cp, arglist, (int)__arraycount(arglist))) < 0) break; if (c < com->c_minargs) { (void)printf("%s requires at least %d arg(s)\n", @@ -654,39 +757,38 @@ out: * Exit the current source file on * error. */ + retval = 0; if (e) { if (e < 0) - return 1; - if (loading) - return 1; - if (sourcing) + retval = 1; + else if (loading) + retval = 1; + else if (sourcing) (void)unstack(); - return 0; } - if (com == NULL) - return 0; - if (contxt != ec_autoprint && com->c_argtype & P && - value(ENAME_AUTOPRINT) != NULL && (dot->m_flag & MDELETED) == 0) - (void)execute(__UNCONST("print ."), ec_autoprint); - if (!sourcing && (com->c_argtype & T) == 0) - sawcom = 1; - return 0; + else if (com != NULL) { + if (contxt != ec_autoprint && com->c_argtype & P && + value(ENAME_AUTOPRINT) != NULL && + (dot->m_flag & MDELETED) == 0) + (void)execute(__UNCONST("print ."), ec_autoprint); + if (!sourcing && (com->c_argtype & T) == 0) + sawcom = 1; + } + sig_check(); + return retval; } - /* * The following gets called on receipt of an interrupt. This is * to abort printout of a command, mainly. - * Dispatching here when command() is inactive crashes rcv. + * Dispatching here when commands() is inactive crashes rcv. * Close all open files except 0, 1, 2, and the temporary. * Also, unstack all source files. */ -static int inithdr; /* am printing startup headers */ - -/*ARGSUSED*/ static void -intr(int s __unused) +lex_intr(int signo) { + noreset = 0; if (!inithdr) sawcom++; @@ -702,7 +804,7 @@ intr(int s __unused) image = -1; } (void)fprintf(stderr, "Interrupt\n"); - reset(0); + longjmp(jmpbuf, signo); } /* @@ -710,10 +812,27 @@ intr(int s __unused) */ /*ARGSUSED*/ static void -hangup(int s __unused) +lex_hangup(int s __unused) { + /* nothing to do? */ - exit(1); + exit(EXIT_FAILURE); +} + +/* + * When we wake up after ^Z, reprint the prompt. + * + * NOTE: EditLine deals with the prompt and job control, so with it + * this does nothing, i.e., reset_on_stop == 0. + */ +static void +lex_stop(int signo) +{ + + if (reset_on_stop) { + reset_on_stop = 0; + longjmp(jmpbuf, signo); + } } /* @@ -727,18 +846,27 @@ commands(void) char linebuf[LINESIZE]; int eofloop; +#ifdef DEBUG_FILE_LEAK + file_leak_init(); +#endif + if (!sourcing) { - if (signal(SIGINT, SIG_IGN) != SIG_IGN) - (void)signal(SIGINT, intr); - if (signal(SIGHUP, SIG_IGN) != SIG_IGN) - (void)signal(SIGHUP, hangup); - (void)signal(SIGTSTP, stop); - (void)signal(SIGTTOU, stop); - (void)signal(SIGTTIN, stop); + sig_check(); + + sig_hold(); + (void)sig_signal(SIGINT, lex_intr); + (void)sig_signal(SIGHUP, lex_hangup); + (void)sig_signal(SIGTSTP, lex_stop); + (void)sig_signal(SIGTTOU, lex_stop); + (void)sig_signal(SIGTTIN, lex_stop); + sig_release(); } - setexit(); /* defined as (void)setjmp(srbuf) in def.h */ + + (void)setjmp(jmpbuf); /* "reset" location if we got an interrupt */ + eofloop = 0; /* initialize this after a possible longjmp */ for (;;) { + sig_check(); (void)fflush(stdout); sreset(); /* @@ -751,82 +879,83 @@ commands(void) prompt = smsgprintf(prompt, dot); if ((value(ENAME_AUTOINC) != NULL) && (incfile() > 0)) (void)printf("New mail has arrived.\n"); - reset_on_stop = 1; + #ifndef USE_EDITLINE + reset_on_stop = 1; /* enable job control longjmp */ (void)printf("%s", prompt); #endif } +#ifdef DEBUG_FILE_LEAK + file_leak_check(); +#endif /* * Read a line of commands from the current input * and handle end of file specially. */ n = 0; for (;;) { + sig_check(); #ifdef USE_EDITLINE if (!sourcing) { char *line; - if ((line = my_gets(&elm.command, prompt, NULL)) == NULL) { + + line = my_gets(&elm.command, prompt, NULL); + if (line == NULL) { if (n == 0) n = -1; break; } (void)strlcpy(linebuf, line, sizeof(linebuf)); - setscreensize(); /* so we can resize a window */ } else { - if (mail_readline(input, &linebuf[n], LINESIZE - n) < 0) { + if (readline(input, &linebuf[n], LINESIZE - n, 0) < 0) { if (n == 0) n = -1; break; } } #else /* USE_EDITLINE */ - if (mail_readline(input, &linebuf[n], LINESIZE - n) < 0) { + if (readline(input, &linebuf[n], LINESIZE - n, reset_on_stop) < 0) { if (n == 0) n = -1; break; } #endif /* USE_EDITLINE */ + if (!sourcing) + setscreensize(); /* so we can resize window */ if (sourcing) { /* allow comments in source files */ char *ptr; if ((ptr = comment_char(linebuf)) != NULL) *ptr = '\0'; } - if ((n = strlen(linebuf)) == 0) + if ((n = (int)strlen(linebuf)) == 0) break; n--; if (linebuf[n] != '\\') break; linebuf[n++] = ' '; } - reset_on_stop = 0; +#ifndef USE_EDITLINE + sig_check(); + reset_on_stop = 0; /* disable job control longjmp */ +#endif if (n < 0) { - /* eof */ + char *p; + + /* eof */ if (loading) break; if (sourcing) { (void)unstack(); continue; } -#ifdef USE_EDITLINE - { - char *p; - if (value(ENAME_INTERACTIVE) != NULL && - (p = value(ENAME_IGNOREEOF)) != NULL && - ++eofloop < (*p == '\0' ? 25 : atoi(p))) { - (void)printf("Use \"quit\" to quit.\n"); - continue; - } - } -#else if (value(ENAME_INTERACTIVE) != NULL && - value(ENAME_IGNOREEOF) != NULL && - ++eofloop < 25) { + (p = value(ENAME_IGNOREEOF)) != NULL && + ++eofloop < (*p == '\0' ? 25 : atoi(p))) { (void)printf("Use \"quit\" to quit.\n"); continue; } -#endif break; } eofloop = 0; diff --git a/usr.bin/mail/list.c b/usr.bin/mail/list.c index afdaee421e0b..2fa9cdb87787 100644 --- a/usr.bin/mail/list.c +++ b/usr.bin/mail/list.c @@ -1,4 +1,4 @@ -/* $NetBSD: list.c,v 1.24 2008/12/07 19:21:00 christos Exp $ */ +/* $NetBSD: list.c,v 1.25 2009/04/10 13:08:25 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)list.c 8.4 (Berkeley) 5/1/95"; #else -__RCSID("$NetBSD: list.c,v 1.24 2008/12/07 19:21:00 christos Exp $"); +__RCSID("$NetBSD: list.c,v 1.25 2009/04/10 13:08:25 christos Exp $"); #endif #endif /* not lint */ @@ -727,7 +727,7 @@ matchfrom(int (*cmpfn)(void *, char *, size_t), #ifdef __lint__ fieldname = fieldname; #endif - (void)mail_readline(setinput(mp), headline, sizeof(headline)); + (void)readline(setinput(mp), headline, (int)sizeof(headline), 0); field = savestr(headline); if (strncmp(field, "From ", 5) != 0) return 1; @@ -1286,7 +1286,7 @@ getmsglist(char *buf, int *vector, int flags) if (mp->m_flag & MMARK) *ip++ = get_msgnum(mp); *ip = 0; - return ip - vector; + return (int)(ip - vector); } /* @@ -1320,6 +1320,10 @@ show_headers_and_exit(int flags) { struct message *mp; + /* We are exiting anyway, so use the default signal handler. */ + if (signal(SIGINT, SIG_DFL) == SIG_IGN) + (void)signal(SIGINT, SIG_IGN); + flags &= CMMASK; for (mp = get_message(1); mp; mp = next_message(mp)) if (flags == 0 || !ignore_message(mp->m_flag, flags)) diff --git a/usr.bin/mail/mail.1 b/usr.bin/mail/mail.1 index 574de643ccac..17668e50fbde 100644 --- a/usr.bin/mail/mail.1 +++ b/usr.bin/mail/mail.1 @@ -1,4 +1,4 @@ -.\" $NetBSD: mail.1,v 1.55 2009/03/23 17:02:06 joerg Exp $ +.\" $NetBSD: mail.1,v 1.56 2009/04/10 13:08:25 christos Exp $ .\" .\" Copyright (c) 1980, 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" @(#)mail.1 8.8 (Berkeley) 4/28/95 .\" -.Dd December 7, 2008 +.Dd February 18, 2009 .Dt MAIL 1 .Os .Sh NAME @@ -43,9 +43,10 @@ .Op Fl a Ar file .Op Fl b Ar bcc-addr .Op Fl c Ar cc-addr +.Op Fl r Ar rcfile .Op Fl s Ar subject .Ar to-addr ... -.Op Ar sendmail-flags +.Op - Ar sendmail-flags .Nm .Op Fl EIiNnv .Op Fl H Ns Op colon-modifier @@ -118,6 +119,13 @@ when reading mail or editing a mail folder. Inhibits reading .Pa /etc/mail.rc upon startup. +.It Fl r +Specify an alternate user rcfile to load. +This overrides the value specified in the environment variable +.Ev MAILRC +which in turn overrides the default +.Pa ~/.mailrc +file. .It Fl s Specify subject on command line (only the first argument after the @@ -499,6 +507,33 @@ but also saves MIME parts that don't have a filename associated with them. For the unnamed parts, a filename is suggested containing the message and part numbers, and the subtype. +.It Ic Header +.Pq Ic H +Specify or show additional header fields. +This is intended for adding extra header fields like +.Dq Reply-To: +or +.Dq X-Organization: +to the header. +For example: +.Bd -literal -offset 0 + Header X-Mailer: NetBSD mail(1) 9.1 +.Ed +.Pp +would add the +.Dq X-Mailer: NetBSD mail(1) 9.1 +line to the message header. +Without any arguments, the extra header fields are displayed. +With only a header name (including the +.Sq \&: ) , +it will delete all extra header fields with that name. +Note: Although some syntax checking is done on the header line, care +should be taken to ensure that it complies with RFC 2821 and 2822. +Also, the extra header lines are not currently displayed by the +.Ic \&~h +tilde command when sending mail (use +.Ic \&~:Header +to see them). .It Ic More .Pq Ic M Like @@ -1292,7 +1327,7 @@ Message headers currently being ignored (by the or .Ic retain command) are not included. -.It Ic \&~F Ns Ar messages +.It Ic \&~ Identical to .Ic \&~f , except all message headers are included. @@ -1428,6 +1463,8 @@ and .Ic Type commands. Normally these commands do not invoke the pager. +(See +.Va page-also . ) .It Ar debug Setting the binary option .Ar debug @@ -1572,6 +1609,17 @@ in your home directory. Setting the binary option .Ar nosave prevents this. +.It Ar page-also +A comma or whitespace delimited list of additional commands to page. +The comparisons are case insensitive, so if +.Ic view +is in the list, both +.Ic view +and +.Ic View +will page. +.It Ar pager-off +If set, disable the pager on all commands. .It Ar quiet Suppresses the printing of the version when first invoked. .It Ar recursive-commands diff --git a/usr.bin/mail/main.c b/usr.bin/mail/main.c index d6c63e9843a3..907c111e333e 100644 --- a/usr.bin/mail/main.c +++ b/usr.bin/mail/main.c @@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.29 2008/07/21 14:19:24 lukem Exp $ */ +/* $NetBSD: main.c,v 1.30 2009/04/10 13:08:25 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1980, 1993\ #if 0 static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 4/20/95"; #else -__RCSID("$NetBSD: main.c,v 1.29 2008/07/21 14:19:24 lukem Exp $"); +__RCSID("$NetBSD: main.c,v 1.30 2009/04/10 13:08:25 christos Exp $"); #endif #endif /* not lint */ @@ -50,6 +50,7 @@ __RCSID("$NetBSD: main.c,v 1.29 2008/07/21 14:19:24 lukem Exp $"); #include #include "extern.h" +#include "sig.h" #ifdef USE_EDITLINE #include "complete.h" @@ -68,19 +69,26 @@ __RCSID("$NetBSD: main.c,v 1.29 2008/07/21 14:19:24 lukem Exp $"); * Startup -- interface with user. */ -static jmp_buf hdrjmp; - -/* - * Interrupt printing of the headers. - */ -/*ARGSUSED*/ +__dead static void -hdrstop(int signo __unused) +usage(void) { - - (void)fflush(stdout); - (void)fprintf(stderr, "\nInterrupt\n"); - longjmp(hdrjmp, 1); +#ifdef MIME_SUPPORT + (void)fputs("\ +Usage: mail [-EiInv] [-r rcfile] [-s subject] [-a file] [-c cc-addr]\n\ + [-b bcc-addr] to-addr ... [- sendmail-options ...]\n\ + mail [-EiInNv] [-H[colon-modifier]] -f [name]\n\ + mail [-EiInNv] [-H[colon-modifier]] [-u user]\n", + stderr); +#else /* MIME_SUPPORT */ + (void)fputs("\ +Usage: mail [-EiInv] [-r rcfile] [-s subject] [-c cc-addr] [-b bcc-addr]\n\ + to-addr ... [- sendmail-options ...]\n\ + mail [-EiInNv] [-H[colon-modifier]] -f [name]\n\ + mail [-EiInNv] [-H[colon-modifier]] [-u user]\n", + stderr); +#endif /* MIME_SUPPORT */ + exit(1); } /* @@ -168,7 +176,8 @@ lexpand(char *str, int ntype) PUBLIC int main(int argc, char *argv[]) { - int i; + jmp_buf jmpbuf; + struct sigaction sa; struct name *to, *cc, *bcc, *smopts; #ifdef MIME_SUPPORT struct name *attach_optargs; @@ -177,9 +186,9 @@ main(int argc, char *argv[]) char *subject; const char *ef; char nosrc = 0; - sig_t prevint; const char *rc; - int volatile Hflag; + int Hflag; + int i; /* * For portability, call setprogname() early, before @@ -191,11 +200,17 @@ main(int argc, char *argv[]) * Set up a reasonable environment. * Figure out whether we are being run interactively, * start the SIGCHLD catcher, and so forth. + * (Other signals are setup later by sig_setup().) */ - (void)signal(SIGCHLD, sigchild); + (void)sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = sigchild; + (void)sigaction(SIGCHLD, &sa, NULL); + if (isatty(0)) assign(ENAME_INTERACTIVE, ""); image = -1; + /* * Now, determine how we are being used. * We successively pick off - flags. @@ -203,6 +218,7 @@ main(int argc, char *argv[]) * of users to mail to. Argp will be set to point to the * first of these users. */ + rc = NULL; ef = NULL; to = NULL; cc = NULL; @@ -213,9 +229,9 @@ main(int argc, char *argv[]) #ifdef MIME_SUPPORT attach_optargs = NULL; attach_end = NULL; - while ((i = getopt(argc, argv, ":~EH:INT:a:b:c:dfins:u:v")) != -1) + while ((i = getopt(argc, argv, ":~EH:INT:a:b:c:dfinr:s:u:v")) != -1) #else - while ((i = getopt(argc, argv, ":~EH:INT:b:c:dfins:u:v")) != -1) + while ((i = getopt(argc, argv, ":~EH:INT:b:c:dfinr:s:u:v")) != -1) #endif { switch (i) { @@ -262,6 +278,9 @@ main(int argc, char *argv[]) case 'd': debug++; break; + case 'r': + rc = optarg; + break; case 's': /* * Give a subject field for sending from @@ -356,23 +375,8 @@ main(int argc, char *argv[]) (void)fprintf(stderr, "%s: unknown option -- %c\n", getprogname(), optopt); -#ifdef MIME_SUPPORT - (void)fputs("\ -Usage: mail [-EiInv] [-s subject] [-a file] [-c cc-addr] [-b bcc-addr] to-addr ...\n\ - [- sendmail-options ...]\n\ - mail [-EiInNv] [-H[colon-modifier]] -f [name]\n\ - mail [-EiInNv] [-H[colon-modifier]] [-u user]\n", - stderr); -#else /* MIME_SUPPORT */ - (void)fputs("\ -Usage: mail [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\ - [- sendmail-options ...]\n\ - mail [-EiInNv] [-H[colon-modifier]] -f [name]\n\ - mail [-EiInNv] [-H[colon-modifier]] [-u user]\n", - stderr); -#endif /* MIME_SUPPORT */ - - exit(1); + usage(); /* print usage message and die */ + /*NOTREACHED*/ } } for (i = optind; (argv[i]) && (*argv[i] != '-'); i++) @@ -405,7 +409,7 @@ Usage: mail [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\ * Expand returns a savestr, but load only uses the file name * for fopen, so it's safe to do this. */ - if ((rc = getenv("MAILRC")) == 0) + if (rc == NULL && (rc = getenv("MAILRC")) == NULL) rc = "~/.mailrc"; load(expand(rc)); setscreensize(); /* do this after loading the rcfile */ @@ -420,6 +424,8 @@ Usage: mail [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\ init_editline(); #endif + sig_setup(); + switch (mailmode) { case mm_sending: (void)mail(to, cc, bcc, smopts, subject, @@ -441,23 +447,25 @@ Usage: mail [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\ ef = "%"; if (setfile(ef) < 0) exit(1); /* error already reported */ - if (setjmp(hdrjmp) == 0) { - if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN) - (void)signal(SIGINT, hdrstop); - if (value(ENAME_QUIET) == NULL) - (void)printf("Mail version %s. Type ? for help.\n", - version); - if (mailmode == mm_hdrsonly) - show_headers_and_exit(Hflag); /* NORETURN */ - announce(); - (void)fflush(stdout); - (void)signal(SIGINT, prevint); + if (value(ENAME_QUIET) == NULL) + (void)printf("Mail version %s. Type ? for help.\n", + version); + if (mailmode == mm_hdrsonly) + show_headers_and_exit(Hflag); /* NORETURN */ + announce(); + (void)fflush(stdout); + + if (setjmp(jmpbuf) != 0) { + /* Return here if quit() fails below. */ + (void)printf("Use 'exit' to quit without saving changes.\n"); } commands(); + + /* Ignore these signals from now on! */ (void)signal(SIGHUP, SIG_IGN); (void)signal(SIGINT, SIG_IGN); (void)signal(SIGQUIT, SIG_IGN); - quit(); + quit(jmpbuf); break; default: diff --git a/usr.bin/mail/mime_attach.c b/usr.bin/mail/mime_attach.c index dbda9038b456..c2f5002c8605 100644 --- a/usr.bin/mail/mime_attach.c +++ b/usr.bin/mail/mime_attach.c @@ -1,4 +1,4 @@ -/* $NetBSD: mime_attach.c,v 1.11 2009/03/11 01:10:05 christos Exp $ */ +/* $NetBSD: mime_attach.c,v 1.12 2009/04/10 13:08:25 christos Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. @@ -33,7 +33,7 @@ #include #ifndef __lint__ -__RCSID("$NetBSD: mime_attach.c,v 1.11 2009/03/11 01:10:05 christos Exp $"); +__RCSID("$NetBSD: mime_attach.c,v 1.12 2009/04/10 13:08:25 christos Exp $"); #endif /* not __lint__ */ #include @@ -41,7 +41,6 @@ __RCSID("$NetBSD: mime_attach.c,v 1.11 2009/03/11 01:10:05 christos Exp $"); #include #include #include -#include #include #include #include @@ -60,6 +59,7 @@ __RCSID("$NetBSD: mime_attach.c,v 1.11 2009/03/11 01:10:05 christos Exp $"); #include "mime_child.h" #endif #include "glob.h" +#include "sig.h" #if 0 /* @@ -373,7 +373,7 @@ content_type_by_name(char *filename) } cp = magic_file(magic, filename); if (cp == NULL) { - warnx("magic_file: %s", magic_error(magic)); + warnx("magic_load: %s", magic_error(magic)); return NULL; } if (filename && @@ -787,9 +787,15 @@ get_line(el_mode_t *em, const char *pr, const char *str, int i) * seems to handle it badly. */ (void)easprintf(&prompt, "#%-7d %s: ", i, pr); - line = my_getline(em, prompt, __UNCONST(str)); - /* LINTED */ - line = line ? savestr(line) : __UNCONST(""); + line = my_gets(em, prompt, __UNCONST(str)); + if (line != NULL) { + (void)strip_WSP(line); /* strip trailing whitespace */ + line = skip_WSP(line); /* skip leading white space */ + line = savestr(line); /* XXX - do we need this? */ + } + else { + line = __UNCONST(""); + } free(prompt); return line; @@ -800,8 +806,8 @@ sget_line(el_mode_t *em, const char *pr, const char **str, int i) { char *line; line = get_line(em, pr, *str, i); - if (strcmp(line, *str) != 0) - *str = savestr(line); + if (line != NULL && strcmp(line, *str) != 0) + *str = line; } static void @@ -949,14 +955,14 @@ edit_attachlist(struct attachment *alist) * Hook used by the '~@' escape to attach files. */ PUBLIC struct attachment* -mime_attach_files(struct attachment *attach, char *linebuf) +mime_attach_files(struct attachment * volatile attach, char *linebuf) { struct attachment *ap; char *argv[MAXARGC]; int argc; int attach_num; - argc = getrawlist(linebuf, argv, sizeofarray(argv)); + argc = getrawlist(linebuf, argv, (int)__arraycount(argv)); attach_num = 1; for (ap = attach; ap && ap->a_flink; ap = ap->a_flink) attach_num++; @@ -1004,7 +1010,8 @@ mime_attach_optargs(struct name *optargs) int i; if (expand_optargs != NULL) - argc = getrawlist(np->n_name, argv, sizeofarray(argv)); + argc = getrawlist(np->n_name, + argv, (int)__arraycount(argv)); else { if (np->n_name == '\0') argc = 0; diff --git a/usr.bin/mail/mime_codecs.c b/usr.bin/mail/mime_codecs.c index 809e51351bf7..c019e0266981 100644 --- a/usr.bin/mail/mime_codecs.c +++ b/usr.bin/mail/mime_codecs.c @@ -1,4 +1,4 @@ -/* $NetBSD: mime_codecs.c,v 1.8 2009/01/18 01:29:57 lukem Exp $ */ +/* $NetBSD: mime_codecs.c,v 1.9 2009/04/10 13:08:25 christos Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. @@ -52,7 +52,7 @@ #include #ifndef __lint__ -__RCSID("$NetBSD: mime_codecs.c,v 1.8 2009/01/18 01:29:57 lukem Exp $"); +__RCSID("$NetBSD: mime_codecs.c,v 1.9 2009/04/10 13:08:25 christos Exp $"); #endif /* not __lint__ */ #include @@ -276,7 +276,7 @@ mime_bintob64(char *b64, const char *bin, size_t cnt) static const char b64table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const unsigned char *p = (const unsigned char*)bin; - int i; + ssize_t i; for (i = cnt; i > 0; i -= 3) { unsigned a = p[0]; @@ -314,7 +314,7 @@ mime_fB64_encode(FILE *fi, FILE *fo, void *cookie __unused) { static char b64[MIME_BASE64_LINE_MAX]; static char mem[3 * (MIME_BASE64_LINE_MAX / 4)]; - int cnt; + size_t cnt; char *cp; size_t limit; #ifdef __lint__ @@ -530,9 +530,9 @@ mime_fQP_decode(FILE *fi, FILE *fo, void *cookie __unused) cookie = cookie; #endif while ((line = fgetln(fi, &len)) != NULL) { - int c; char *p; char *end; + end = line + len; for (p = line; p < end; p++) { if (*p == '=') { @@ -540,11 +540,13 @@ mime_fQP_decode(FILE *fi, FILE *fo, void *cookie __unused) while (p < end && is_WSP(*p)) p++; if (*p != '\n' && p + 1 < end) { + int c; char buf[3]; + buf[0] = *p++; buf[1] = *p; buf[2] = '\0'; - c = strtol(buf, NULL, 16); + c = (int)strtol(buf, NULL, 16); (void)fputc(c, fo); } } diff --git a/usr.bin/mail/mime_decode.c b/usr.bin/mail/mime_decode.c index ad129bb72477..2a597aa8549f 100644 --- a/usr.bin/mail/mime_decode.c +++ b/usr.bin/mail/mime_decode.c @@ -1,4 +1,4 @@ -/* $NetBSD: mime_decode.c,v 1.14 2009/01/18 01:29:57 lukem Exp $ */ +/* $NetBSD: mime_decode.c,v 1.15 2009/04/10 13:08:25 christos Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. @@ -34,14 +34,13 @@ #include #ifndef __lint__ -__RCSID("$NetBSD: mime_decode.c,v 1.14 2009/01/18 01:29:57 lukem Exp $"); +__RCSID("$NetBSD: mime_decode.c,v 1.15 2009/04/10 13:08:25 christos Exp $"); #endif /* not __lint__ */ #include #include #include #include -#include #include #include #include diff --git a/usr.bin/mail/mime_detach.c b/usr.bin/mail/mime_detach.c index 6375d2951fe9..a7a3a63f9e7a 100644 --- a/usr.bin/mail/mime_detach.c +++ b/usr.bin/mail/mime_detach.c @@ -1,4 +1,4 @@ -/* $NetBSD: mime_detach.c,v 1.3 2008/04/28 20:24:14 martin Exp $ */ +/* $NetBSD: mime_detach.c,v 1.4 2009/04/10 13:08:25 christos Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ #include #ifndef __lint__ -__RCSID("$NetBSD: mime_detach.c,v 1.3 2008/04/28 20:24:14 martin Exp $"); +__RCSID("$NetBSD: mime_detach.c,v 1.4 2009/04/10 13:08:25 christos Exp $"); #endif /* not __lint__ */ #include @@ -54,6 +54,7 @@ __RCSID("$NetBSD: mime_detach.c,v 1.3 2008/04/28 20:24:14 martin Exp $"); #include "mime_codecs.h" #include "mime_detach.h" #endif +#include "sig.h" static struct { @@ -95,8 +96,12 @@ detach_get_fname(char *prompt, char *pathname) { if (!detach_ctl.batch) { char *fname; + fname = my_gets(&elm.filec, prompt, pathname); - fname = skip_WSP(fname); /* XXX - do this? */ + if (fname == NULL) /* ignore this attachment */ + return NULL; + (void)strip_WSP(fname); + fname = skip_WSP(fname); if (*fname == '\0') /* ignore this attachment */ return NULL; pathname = savestr(fname); /* save this or it gets trashed */ @@ -130,7 +135,12 @@ detach_open_core(char *fname, const char *partstr) (void)sasprintf(&p, "%-7s overwrite: Always/Never/once/next/rename (ANonr)[n]? ", partstr, fname); p = my_gets(&elm.string, p, NULL); + if (p == NULL) + goto start; + + (void)strip_WSP(p); p = skip_WSP(p); + switch (*p) { case 'A': detach_ctl.overwrite = 1; detach_ctl.batch = 1; diff --git a/usr.bin/mail/mime_header.c b/usr.bin/mail/mime_header.c index fb9301e99c95..c189bedddb6c 100644 --- a/usr.bin/mail/mime_header.c +++ b/usr.bin/mail/mime_header.c @@ -1,4 +1,4 @@ -/* $NetBSD: mime_header.c,v 1.7 2009/01/18 01:29:57 lukem Exp $ */ +/* $NetBSD: mime_header.c,v 1.8 2009/04/10 13:08:25 christos Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. @@ -39,9 +39,10 @@ #include #ifndef __lint__ -__RCSID("$NetBSD: mime_header.c,v 1.7 2009/01/18 01:29:57 lukem Exp $"); +__RCSID("$NetBSD: mime_header.c,v 1.8 2009/04/10 13:08:25 christos Exp $"); #endif /* not __lint__ */ +#include #include #include #include @@ -91,16 +92,17 @@ mime_QPh_decode(char *outbuf, size_t outlen, const char *inbuf, size_t inlen) if (*p == '=') { p++; if (p + 1 < inend) { - int c; + size_t c; char *bufend; char buf[3]; + buf[0] = *p++; buf[1] = *p; buf[2] = '\0'; c = strtol(buf, &bufend, 16); if (bufend != &buf[2]) return -1; - *q++ = c; + *q++ = (char)c; } else return -1; @@ -181,8 +183,11 @@ decode_word(const char **ibuf, char **obuf, char *oend, const char *to_cs) if (iend > *ibuf + 75) return -1; + if (oend < *obuf + 1) { + assert(/*CONSTCOND*/ 0); /* We have a coding error! */ + return -1; + } dstend = to_cs ? decword : *obuf; -/* XXX: what if oend <= *obuf, or decword == "" ? */ dstlen = (to_cs ? sizeof(decword) : (size_t)(oend - *obuf)) - 1; if (enctype == 'B' || enctype == 'b') diff --git a/usr.bin/mail/popen.c b/usr.bin/mail/popen.c index 28a48a28bcb3..45ae64bdebde 100644 --- a/usr.bin/mail/popen.c +++ b/usr.bin/mail/popen.c @@ -1,4 +1,4 @@ -/* $NetBSD: popen.c,v 1.24 2007/10/30 02:28:31 christos Exp $ */ +/* $NetBSD: popen.c,v 1.25 2009/04/10 13:08:25 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93"; #else -__RCSID("$NetBSD: popen.c,v 1.24 2007/10/30 02:28:31 christos Exp $"); +__RCSID("$NetBSD: popen.c,v 1.25 2009/04/10 13:08:25 christos Exp $"); #endif #endif /* not lint */ @@ -46,6 +46,7 @@ __RCSID("$NetBSD: popen.c,v 1.24 2007/10/30 02:28:31 christos Exp $"); #include "rcv.h" #include "extern.h" +#include "sig.h" #define READ 0 #define WRITE 1 @@ -146,6 +147,10 @@ Fdopen(int fd, const char *mode) PUBLIC int Fclose(FILE *fp) { + + if (fp == NULL) + return 0; + unregister_file(fp); return fclose(fp); } @@ -169,17 +174,17 @@ prepare_child(sigset_t *nset, int infd, int outfd) } if (outfd >= 0 && outfd != 1) (void)dup2(outfd, 1); - if (nset == NULL) - return; + if (nset != NULL) { - for (i = 1; i < NSIG; i++) + for (i = 1; i < NSIG; i++) { if (sigismember(nset, i)) (void)signal(i, SIG_IGN); + } + if (!sigismember(nset, SIGINT)) + (void)signal(SIGINT, SIG_DFL); + (void)sigemptyset(&eset); + (void)sigprocmask(SIG_SETMASK, &eset, NULL); } - if (nset == NULL || !sigismember(nset, SIGINT)) - (void)signal(SIGINT, SIG_DFL); - (void)sigemptyset(&eset); - (void)sigprocmask(SIG_SETMASK, &eset, NULL); } /* @@ -196,15 +201,18 @@ start_commandv(const char *cmd, sigset_t *nset, int infd, int outfd, { pid_t pid; + sig_check(); if ((pid = fork()) < 0) { warn("fork"); return -1; } if (pid == 0) { char *argv[100]; - int i = getrawlist(cmd, argv, sizeof(argv)/ sizeof(*argv)); + size_t i; - while ((argv[i++] = va_arg(args, char *)) != NULL) + i = getrawlist(cmd, argv, (int)__arraycount(argv)); + while (i < __arraycount(argv) - 1 && + (argv[i++] = va_arg(args, char *)) != NULL) continue; argv[i] = NULL; prepare_child(nset, infd, outfd); @@ -350,6 +358,9 @@ Pclose(FILE *ptr) int i; sigset_t nset, oset; + if (ptr == NULL) + return 0; + i = file_pid(ptr); unregister_file(ptr); (void)fclose(ptr); @@ -429,13 +440,48 @@ run_command(const char *cmd, sigset_t *nset, int infd, int outfd, ...) { pid_t pid; va_list args; + int rval; +#ifdef BROKEN_EXEC_TTY_RESTORE + struct termios ttybuf; + int tcrval; + /* + * XXX - grab the tty settings as currently they can get + * trashed by emacs-21 when suspending with bash-3.2.25 as the + * shell. + * + * 1) from the mail editor, start "emacs -nw" (21.4) + * 2) suspend emacs to the shell (bash 3.2.25) + * 3) resume emacs + * 4) exit emacs back to the mail editor + * 5) discover the tty is screwed: the mail editor is no + * longer receiving characters + * + * - This occurs on both i386 and amd64. + * - This did _NOT_ occur before 4.99.10. + * - This does _NOT_ occur if the editor is vi(1) or if the shell + * is /bin/sh. + * - This _DOES_ happen with the old mail(1) from 2006-01-01 (long + * before my changes). + * + * This is the commit that introduced this "feature": + * http://mail-index.netbsd.org/source-changes/2007/02/09/0020.html + */ + if ((tcrval = tcgetattr(fileno(stdin), &ttybuf)) == -1) + warn("tcgetattr"); +#endif va_start(args, outfd); pid = start_commandv(cmd, nset, infd, outfd, args); va_end(args); if (pid < 0) return -1; - return wait_command(pid); + rval = wait_command(pid); +#ifdef BROKEN_EXEC_TTY_RESTORE + if (tcrval != -1 && tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf) == -1) + warn("tcsetattr"); +#endif + return rval; + } /*ARGSUSED*/ @@ -445,15 +491,15 @@ sigchild(int signo __unused) pid_t pid; int status; struct child *cp; - int save_errno = errno; + int save_errno; - while ((pid = - waitpid((pid_t)-1, &status, WNOHANG)) > 0) { - cp = findchild(pid, 1); + save_errno = errno; + while ((pid = waitpid((pid_t)-1, &status, WNOHANG)) > 0) { + cp = findchild(pid, 1); /* async-signal-safe: we don't alloc */ if (!cp) continue; if (cp->free) - delchild(cp); + delchild(cp); /* async-signal-safe: list changes */ else { cp->done = 1; cp->status = status; diff --git a/usr.bin/mail/quit.c b/usr.bin/mail/quit.c index 77d72e056baf..eaf0aad6a375 100644 --- a/usr.bin/mail/quit.c +++ b/usr.bin/mail/quit.c @@ -1,4 +1,4 @@ -/* $NetBSD: quit.c,v 1.26 2006/11/28 18:45:32 christos Exp $ */ +/* $NetBSD: quit.c,v 1.27 2009/04/10 13:08:25 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -34,13 +34,14 @@ #if 0 static char sccsid[] = "@(#)quit.c 8.2 (Berkeley) 4/28/95"; #else -__RCSID("$NetBSD: quit.c,v 1.26 2006/11/28 18:45:32 christos Exp $"); +__RCSID("$NetBSD: quit.c,v 1.27 2009/04/10 13:08:25 christos Exp $"); #endif #endif /* not lint */ #include "rcv.h" #include "extern.h" #include "thread.h" +#include "sig.h" /* * Rcv -- receive mail rationally. @@ -132,18 +133,22 @@ writeback(FILE *res) * file from the temporary. Save any new stuff appended to the file. */ static void -edstop(void) +edstop(jmp_buf jmpbuf) { int gotcha, c; struct message *mp; - FILE *obuf, *ibuf, *readstat = NULL; + FILE *obuf; + FILE *ibuf; + FILE *readstat; struct stat statb; char tempname[PATHSIZE]; int fd; + sig_check(); if (readonly) return; - holdsigs(); + + readstat = NULL; if (Tflag != NULL) { if ((readstat = Fopen(Tflag, "w")) == NULL) Tflag = NULL; @@ -175,15 +180,15 @@ edstop(void) warn("%s", tempname); if (fd != -1) (void)close(fd); - relsesigs(); - reset(0); + sig_release(); + longjmp(jmpbuf, -11); } if ((ibuf = Fopen(mailname, "r")) == NULL) { warn("%s", mailname); (void)Fclose(obuf); (void)rm(tempname); - relsesigs(); - reset(0); + sig_release(); + longjmp(jmpbuf, -1); } (void)fseek(ibuf, (long)mailsize, 0); while ((c = getc(ibuf)) != EOF) @@ -194,16 +199,16 @@ edstop(void) (void)Fclose(obuf); (void)Fclose(ibuf); (void)rm(tempname); - relsesigs(); - reset(0); + sig_release(); + longjmp(jmpbuf, -1); } (void)Fclose(ibuf); (void)Fclose(obuf); if ((ibuf = Fopen(tempname, "r")) == NULL) { warn("%s", tempname); (void)rm(tempname); - relsesigs(); - reset(0); + sig_release(); + longjmp(jmpbuf, -1); } (void)rm(tempname); } @@ -211,8 +216,8 @@ edstop(void) (void)fflush(stdout); if ((obuf = Fopen(mailname, "r+")) == NULL) { warn("%s", mailname); - relsesigs(); - reset(0); + sig_release(); + longjmp(jmpbuf, -1); } trunc(obuf); c = 0; @@ -222,8 +227,8 @@ edstop(void) c++; if (sendmessage(mp, obuf, NULL, NULL, NULL) < 0) { warn("%s", mailname); - relsesigs(); - reset(0); + sig_release(); + longjmp(jmpbuf, -1); } } gotcha = (c == 0 && ibuf == NULL); @@ -235,8 +240,8 @@ edstop(void) (void)fflush(obuf); if (ferror(obuf)) { warn("%s", mailname); - relsesigs(); - reset(0); + sig_release(); + longjmp(jmpbuf, -1); } (void)Fclose(obuf); if (gotcha) { @@ -247,7 +252,8 @@ edstop(void) (void)fflush(stdout); done: - relsesigs(); + sig_release(); + sig_check(); } /* @@ -256,20 +262,21 @@ done: * Remove the system mailbox, if none saved there. */ PUBLIC void -quit(void) +quit(jmp_buf jmpbuf) { int mcount, p, modify, autohold, anystat, holdbit, nohold; - FILE *ibuf = NULL, *obuf, *fbuf, *rbuf, *readstat = NULL, *abuf; + _Bool append; + FILE *ibuf, *obuf, *fbuf, *rbuf, *readstat, *abuf; struct message *mp; int c, fd; struct stat minfo; const char *mbox; char tempname[PATHSIZE]; -#ifdef __GNUC__ - obuf = NULL; /* XXX gcc -Wuninitialized */ +#ifdef __GNUC__ /* XXX gcc -Wuninitialized */ + ibuf = NULL; + readstat = NULL; #endif - /* * If we are read only, we can't do anything, * so just return quickly. @@ -286,7 +293,7 @@ quit(void) * in edstop() */ if (edit) { - edstop(); + edstop(jmpbuf); return; } @@ -418,7 +425,8 @@ nolock: mbox = expand("&"); mcount = c; - if (value(ENAME_APPEND) == NULL) { + append = value(ENAME_APPEND) != NULL; + if (!append) { (void)snprintf(tempname, sizeof(tempname), "%s/mail.RmXXXXXXXXXX", tmpdir); if ((fd = mkstemp(tempname)) == -1 || @@ -476,7 +484,8 @@ nolock: if (mp->m_flag & MBOX) if (sendmessage(mp, obuf, saveignore, NULL, NULL) < 0) { warn("%s", mbox); - (void)Fclose(ibuf); + if (!append) + (void)Fclose(ibuf); (void)Fclose(obuf); (void)Fclose(fbuf); dot_unlock(mailname); @@ -489,7 +498,7 @@ nolock: * If we are appending, this is unnecessary. */ - if (value(ENAME_APPEND) == NULL) { + if (!append) { rewind(ibuf); c = getc(ibuf); while (c != EOF) { diff --git a/usr.bin/mail/send.c b/usr.bin/mail/send.c index 759f1b9cdb62..a64fe4aa43fc 100644 --- a/usr.bin/mail/send.c +++ b/usr.bin/mail/send.c @@ -1,4 +1,4 @@ -/* $NetBSD: send.c,v 1.33 2009/01/25 14:07:18 lukem Exp $ */ +/* $NetBSD: send.c,v 1.34 2009/04/10 13:08:25 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -34,16 +34,18 @@ #if 0 static char sccsid[] = "@(#)send.c 8.1 (Berkeley) 6/6/93"; #else -__RCSID("$NetBSD: send.c,v 1.33 2009/01/25 14:07:18 lukem Exp $"); +__RCSID("$NetBSD: send.c,v 1.34 2009/04/10 13:08:25 christos Exp $"); #endif #endif /* not lint */ +#include + #include "rcv.h" #include "extern.h" #ifdef MIME_SUPPORT #include "mime.h" #endif - +#include "sig.h" /* * Mail -- a mail program @@ -125,9 +127,11 @@ sendmessage(struct message *mp, FILE *obuf, struct ignoretab *doign, char *cp; size_t prefixlen; size_t linelen; + int rval; ignoring = 0; prefixlen = 0; + rval = -1; /* * Compute the prefix string, without trailing whitespace @@ -145,6 +149,8 @@ sendmessage(struct message *mp, FILE *obuf, struct ignoretab *doign, dostat = doign == 0 || !isign("status", doign); infld = 0; firstline = 1; + + sig_check(); /* * Process headers first */ @@ -153,7 +159,8 @@ sendmessage(struct message *mp, FILE *obuf, struct ignoretab *doign, obuf = mime_decode_header(mip); #endif while (len > 0 && isheadflag) { - if (fgets(line, sizeof(line), ibuf) == NULL) + sig_check(); + if (fgets(line, (int)sizeof(line), ibuf) == NULL) break; len -= linelen = strlen(line); if (firstline) { @@ -254,26 +261,32 @@ sendmessage(struct message *mp, FILE *obuf, struct ignoretab *doign, } (void)fwrite(line, sizeof(*line), linelen, obuf); if (ferror(obuf)) - return -1; + goto out; } } + sig_check(); + /* * Copy out message body */ #ifdef MIME_SUPPORT if (mip) { obuf = mime_decode_body(mip); - if (obuf == NULL) /* XXX - early out */ - return 0; + sig_check(); + if (obuf == NULL) { /* XXX - early out */ + rval = 0; + goto out; + } } #endif if (doign == ignoreall) len--; /* skip final blank line */ linelen = 0; /* needed for in case len == 0 */ - if (prefix != NULL) + if (prefix != NULL) { while (len > 0) { - if (fgets(line, sizeof(line), ibuf) == NULL) { + sig_check(); + if (fgets(line, (int)sizeof(line), ibuf) == NULL) { linelen = 0; break; } @@ -289,24 +302,33 @@ sendmessage(struct message *mp, FILE *obuf, struct ignoretab *doign, prefixlen, obuf); (void)fwrite(line, sizeof(*line), linelen, obuf); if (ferror(obuf)) - return -1; + goto out; } - else + } + else { while (len > 0) { + sig_check(); linelen = (size_t)len < sizeof(line) ? (size_t)len : sizeof(line); - if ((linelen = fread(line, sizeof(*line), linelen, ibuf)) == 0) + if ((linelen = fread(line, sizeof(*line), linelen, ibuf)) == 0) { break; + } len -= linelen; if (fwrite(line, sizeof(*line), linelen, obuf) != linelen) - return -1; + goto out; } + } + sig_check(); if (doign == ignoreall && linelen > 0 && line[linelen - 1] != '\n') { int c; + /* no final blank line */ if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF) - return -1; + goto out; } - return 0; + rval = 0; + out: + sig_check(); + return rval; } /* @@ -340,9 +362,10 @@ fixhead(struct header *hp, struct name *tolist) * Format the given header line to not exceed 72 characters. */ static void -fmt(const char *str, struct name *np, FILE *fo, int comma) +fmt(const char *str, struct name *np, FILE *fo, size_t comma) { - int col, len; + size_t col; + size_t len; comma = comma ? 1 : 0; col = strlen(str); @@ -366,6 +389,51 @@ fmt(const char *str, struct name *np, FILE *fo, int comma) (void)putc('\n', fo); } +/* + * Formatting for extra_header lines: try to wrap them before 72 + * characters. + * + * XXX - should this allow for quoting? + */ +static void +fmt2(const char *str, FILE *fo) +{ + const char *p; + size_t col; + + col = 0; + p = strchr(str, ':'); + assert(p != NULL); /* this is a coding error */ + + while (str <= p) { /* output the header name */ + (void)putc(*str, fo); + str++; + col++; + } + assert(is_WSP(*str)); /* this is a coding error */ + + (void)putc(' ', fo); /* output a single space after the ':' */ + str = skip_WSP(str); + + while (*str != '\0') { + if (p <= str) { + p = strpbrk(str, " \t"); + if (p == NULL) + p = str + strlen(str); + if (col + (p - str) > 72 && col > 4) { + (void)fputs("\n ", fo); + col = 4; + str = skip_WSP(str); + continue; + } + } + (void)putc(*str, fo); + str++; + col++; + } + (void)putc('\n', fo); +} + /* * Dump the to, subject, cc header on the * passed file buffer. @@ -373,23 +441,29 @@ fmt(const char *str, struct name *np, FILE *fo, int comma) PUBLIC int puthead(struct header *hp, FILE *fo, int w) { + struct name *np; int gotcha; gotcha = 0; if (hp->h_to != NULL && w & GTO) - fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++; + fmt("To:", hp->h_to, fo, w & GCOMMA), gotcha++; if (hp->h_subject != NULL && w & GSUBJECT) (void)fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; - if (hp->h_smopts != NULL && w & GSMOPTS) - (void)fprintf(fo, "(sendmail options: %s)\n", detract(hp->h_smopts, GSMOPTS)), gotcha++; if (hp->h_cc != NULL && w & GCC) - fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++; + fmt("Cc:", hp->h_cc, fo, w & GCOMMA), gotcha++; if (hp->h_bcc != NULL && w & GBCC) - fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++; + fmt("Bcc:", hp->h_bcc, fo, w & GCOMMA), gotcha++; if (hp->h_in_reply_to != NULL && w & GMISC) (void)fprintf(fo, "In-Reply-To: %s\n", hp->h_in_reply_to), gotcha++; if (hp->h_references != NULL && w & GMISC) - fmt("References:", hp->h_references, fo, w&GCOMMA), gotcha++; + fmt("References:", hp->h_references, fo, w & GCOMMA), gotcha++; + if (hp->h_extra != NULL && w & GMISC) { + for (np = hp->h_extra; np != NULL; np = np->n_flink) + fmt2(np->n_name, fo); + gotcha++; + } + if (hp->h_smopts != NULL && w & GSMOPTS) + (void)fprintf(fo, "(sendmail options: %s)\n", detract(hp->h_smopts, GSMOPTS)), gotcha++; #ifdef MIME_SUPPORT if (w & GMIME && (hp->h_attach || value(ENAME_MIME_ENCODE_MSG))) mime_putheader(fo, hp), gotcha++; @@ -426,11 +500,12 @@ infix(struct header *hp, FILE *fi) return fi; } (void)rm(tempname); + (void)puthead(hp, nfo, + GTO | GSUBJECT | GCC | GBCC | GMISC | GNL | GCOMMA #ifdef MIME_SUPPORT - (void)puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GMISC|GMIME|GNL|GCOMMA); -#else - (void)puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GMISC|GNL|GCOMMA); + | GMIME #endif + ); c = getc(fi); while (c != EOF) { @@ -576,6 +651,28 @@ mail2(FILE *mtf, const char **namelist) } } +static struct name * +ncopy(struct name *np) +{ + struct name *rv; + struct name *lp; + struct name *tp; + + rv = NULL; + for (/*EMPTY*/; np; np = np->n_flink) { + tp = nalloc(np->n_name, np->n_type); + if (rv == NULL) + rv = tp; + else { + /*LINTED*/ + lp->n_flink = tp; + tp->n_blink = lp; + } + lp = tp; + } + return rv; +} + /* * Mail a message on standard input to the people indicated * in the passed header. (Internal interface). @@ -594,6 +691,12 @@ mail1(struct header *hp, int printheaders) if ((mtf = collect(hp, printheaders)) == NULL) return; + /* + * Grab any extra header lines. Do this after collect() so + * that we can add header lines while collecting. + */ + hp->h_extra = ncopy(extra_headers); + if (value(ENAME_INTERACTIVE) != NULL) { if (value(ENAME_ASKCC) != NULL || value(ENAME_ASKBCC) != NULL) { if (value(ENAME_ASKCC) != NULL) diff --git a/usr.bin/mail/sig.c b/usr.bin/mail/sig.c new file mode 100644 index 000000000000..adaa5f489539 --- /dev/null +++ b/usr.bin/mail/sig.c @@ -0,0 +1,424 @@ +/* $NetBSD: sig.c,v 1.1 2009/04/10 13:08:25 christos Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: sig.c,v 1.1 2009/04/10 13:08:25 christos Exp $"); +#endif /* not lint */ + +#include +#include +#include + +#include "rcv.h" +#include "extern.h" +#include "sig.h" + +/* + * Mail -- a mail program + * + * Signal routines. + */ + +static sig_t sigarray[NSIG]; + +typedef struct q_entry_s { + int qe_signo; + sig_t qe_handler; + struct q_entry_s *qe_next; +} q_entry_t; + +static struct { + q_entry_t *qe_first; + q_entry_t **qe_last; +} sigqueue = { NULL, &sigqueue.qe_first }; +#define SIGQUEUE_INIT(p) do {\ + (p)->qe_first = NULL;\ + (p)->qe_last = &((p)->qe_first);\ + } while (/*CONSTCOND*/ 0) + +/* + * The routines alloc_entry() and free_entry() manage the queue + * elements. + * + * Currently, they just assign one element per signo from a fix array + * as we don't support POSIX signal queues. We leave them as this may + * change in the future and the modifications will be isolated. + */ +static q_entry_t * +alloc_entry(int signo) +{ + static q_entry_t entries[NSIG]; + q_entry_t *e; + + /* + * We currently only post one signal per signal number, so + * there is no need to make this complicated. + */ + e = &entries[signo]; + if (e->qe_signo != 0) + return NULL; + + e->qe_signo = signo; + e->qe_handler = sigarray[signo]; + e->qe_next = NULL; + + return e; +} + +static void +free_entry(q_entry_t *e) +{ + + e->qe_signo = 0; + e->qe_handler = NULL; + e->qe_next = NULL; +} + +/* + * Attempt to post a signal to the sigqueue. + */ +static void +sig_post(int signo) +{ + q_entry_t *e; + + if (sigarray[signo] == SIG_DFL || sigarray[signo] == SIG_IGN) + return; + + e = alloc_entry(signo); + if (e != NULL) { + *sigqueue.qe_last = e; + sigqueue.qe_last = &e->qe_next; + } +} + +/* + * Check the sigqueue for any pending signals. If any are found, + * preform the required actions and remove them from the queue. + */ +PUBLIC void +sig_check(void) +{ + q_entry_t *e; + sigset_t nset; + sigset_t oset; + void (*handler)(int); + int signo; + + (void)sigfillset(&nset); + (void)sigprocmask(SIG_SETMASK, &nset, &oset); + + while ((e = sigqueue.qe_first) != NULL) { + signo = e->qe_signo; + handler = e->qe_handler; + + /* + * Remove the entry from the queue and free it. + */ + sigqueue.qe_first = e->qe_next; + if (sigqueue.qe_first == NULL) + sigqueue.qe_last = &sigqueue.qe_first; + free_entry(e); + + if (handler == SIG_DFL || handler == SIG_IGN) { + assert(/*CONSTCOND*/ 0); /* These should not get posted. */ + } + else { + (void)sigprocmask(SIG_SETMASK, &oset, NULL); + handler(signo); + (void)sigprocmask(SIG_SETMASK, &nset, NULL); + } + } + (void)sigprocmask(SIG_SETMASK, &oset, NULL); +} + +PUBLIC sig_t +sig_signal(int signo, sig_t handler) +{ + sig_t old_handler; + sigset_t nset; + sigset_t oset; + + assert(signo > 0 && signo < NSIG); + + (void)sigemptyset(&nset); + (void)sigaddset(&nset, signo); + (void)sigprocmask(SIG_BLOCK, &nset, &oset); + + old_handler = sigarray[signo]; + sigarray[signo] = handler; + + (void)sigprocmask(SIG_SETMASK, &oset, NULL); + + return old_handler; +} + +static void +do_default_handler(int signo, int flags) +{ + struct sigaction nsa; + struct sigaction osa; + sigset_t nset; + sigset_t oset; + int save_errno; + + save_errno = errno; + (void)sigemptyset(&nsa.sa_mask); + nsa.sa_flags = flags; + nsa.sa_handler = SIG_DFL; + (void)sigaction(signo, &nsa, &osa); + + (void)sigemptyset(&nset); + (void)sigaddset(&nset, signo); + (void)sigprocmask(SIG_UNBLOCK, &nset, &oset); + + (void)kill(0, signo); + + (void)sigprocmask(SIG_SETMASK, &oset, NULL); + (void)sigaction(signo, &osa, NULL); + errno = save_errno; +} + +/* + * Our generic signal handler. + */ +static void +sig_handler(int signo) +{ + sigset_t nset; + sigset_t oset; + + (void)sigfillset(&nset); + (void)sigprocmask(SIG_SETMASK, &nset, &oset); + + assert (signo > 0 && signo < NSIG); /* Should be guaranteed. */ + + sig_post(signo); + + switch (signo) { + case SIGCONT: + assert(/*CONSTCOND*/ 0); /* We should not be seeing these. */ + do_default_handler(signo, 0); + break; + + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + do_default_handler(signo, 0); + break; + + case SIGINT: + case SIGHUP: + case SIGQUIT: + case SIGPIPE: + default: + if (sigarray[signo] == SIG_DFL) + do_default_handler(signo, SA_RESTART); + break; + } + (void)sigprocmask(SIG_SETMASK, &oset, NULL); +} + +/* + * Setup the signal handlers. + */ +PUBLIC void +sig_setup(void) +{ + sigset_t nset; + sigset_t oset; + struct sigaction sa; + struct sigaction osa; + + /* Block all signals while setting things. */ + (void)sigfillset(&nset); + (void)sigprocmask(SIG_BLOCK, &nset, &oset); + + /* + * Flow Control - SIGTSTP, SIGTTIN, SIGTTOU, SIGCONT: + * + * We grab SIGTSTP, SIGTTIN, and SIGTTOU so that we post the + * signals before suspending so that they are available when + * we resume. If we were to use SIGCONT instead, they will + * not get posted until SIGCONT is unblocked, even though the + * process has resumed. + * + * NOTE: We default these to SA_RESTART here, but we need to + * change this in certain cases, e.g., when reading from a + * tty. + */ + (void)sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = sig_handler; + (void)sigaction(SIGTSTP, &sa, NULL); + (void)sigaction(SIGTTIN, &sa, NULL); + (void)sigaction(SIGTTOU, &sa, NULL); + + /* + * SIGHUP, SIGINT, and SIGQUIT: + * + * SIGHUP and SIGINT are trapped unless they are being + * ignored. + * + * Currently, we let the default handler deal with SIGQUIT. + */ + (void)sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = sig_handler; + + if (sigaction(SIGHUP, &sa, &osa) != -1 && osa.sa_handler == SIG_IGN) + (void)signal(SIGHUP, SIG_IGN); + + if (sigaction(SIGINT, &sa, &osa) != -1 && osa.sa_handler == SIG_IGN) + (void)signal(SIGINT, SIG_IGN); +#if 0 + if (signal(SIGQUIT, SIG_DFL) == SIG_IGN) + (void)signal(SIGQUIT, SIG_IGN); +#endif + /* + * SIGCHLD and SIGPIPE: + * + * SIGCHLD is setup early in main. The handler lives in + * popen.c as it uses internals of that module. + * + * SIGPIPE is grabbed here. It is only used in + * lex.c:setup_piping(), cmd1.c:type1(), and cmd1.c:pipecmd(). + */ + (void)sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = sig_handler; + (void)sigaction(SIGPIPE, &sa, NULL); + + /* + * Make sure our structures are initialized. + * XXX: This should be unnecessary. + */ + (void)memset(sigarray, 0, sizeof(sigarray)); + SIGQUEUE_INIT(&sigqueue); + + /* Restore the signal mask. */ + (void)sigprocmask(SIG_SETMASK, &oset, NULL); +} + +static struct { /* data shared by sig_hold() and sig_release() */ + int depth; /* depth of sig_hold() */ + sigset_t oset; /* old signal mask saved by sig_hold() */ +} hold; + +/* + * Hold signals SIGHUP, SIGINT, and SIGQUIT. + */ +PUBLIC void +sig_hold(void) +{ + sigset_t nset; + + if (hold.depth++ == 0) { + (void)sigemptyset(&nset); + (void)sigaddset(&nset, SIGHUP); + (void)sigaddset(&nset, SIGINT); + (void)sigaddset(&nset, SIGQUIT); + (void)sigprocmask(SIG_BLOCK, &nset, &hold.oset); + } +} + +/* + * Release signals SIGHUP, SIGINT, and SIGQUIT. + */ +PUBLIC void +sig_release(void) +{ + + if (--hold.depth == 0) + (void)sigprocmask(SIG_SETMASK, &hold.oset, NULL); +} + +/* + * Unblock and ignore a signal. + */ +PUBLIC int +sig_ignore(int sig, struct sigaction *osa, sigset_t *oset) +{ + struct sigaction act; + sigset_t nset; + int error; + + (void)sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + act.sa_handler = SIG_IGN; + error = sigaction(sig, &act, osa); + + if (error != -1) { + (void)sigemptyset(&nset); + (void)sigaddset(&nset, sig); + (void)sigprocmask(SIG_UNBLOCK, &nset, oset); + } else if (oset != NULL) + (void)sigprocmask(SIG_UNBLOCK, NULL, oset); + + return error; +} + +/* + * Restore a signal and the current signal mask. + */ +PUBLIC int +sig_restore(int sig, struct sigaction *osa, sigset_t *oset) +{ + int error; + + error = 0; + if (oset) + error = sigprocmask(SIG_SETMASK, oset, NULL); + if (osa) + error = sigaction(sig, osa, NULL); + + return error; +} + +/* + * Change the current flags and (optionally) return the old sigaction + * structure so we can restore things later. This is used to turn + * SA_RESTART on or off. + */ +PUBLIC int +sig_setflags(int signo, int flags, struct sigaction *osa) +{ + struct sigaction sa; + + if (sigaction(signo, NULL, &sa) == -1) + return -1; + if (osa) + *osa = sa; + sa.sa_flags = flags; + return sigaction(signo, &sa, NULL); +} + diff --git a/usr.bin/mail/sig.h b/usr.bin/mail/sig.h new file mode 100644 index 000000000000..4f65b04c693e --- /dev/null +++ b/usr.bin/mail/sig.h @@ -0,0 +1,44 @@ +/* $NetBSD: sig.h,v 1.1 2009/04/10 13:08:25 christos Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SIG_H__ +#define __SIG_H__ + +int sig_ignore(int, struct sigaction *, sigset_t *); +int sig_restore(int, struct sigaction *, sigset_t *); +int sig_setflags(int, int, struct sigaction *); + +void sig_hold(void); +void sig_release(void); /* XXX: should this be named sig_relse()? */ + +void sig_check(void); +void sig_setup(void); +sig_t sig_signal(int, sig_t); + +#endif /* __SIG_H__ */ + diff --git a/usr.bin/mail/strings.c b/usr.bin/mail/strings.c index 458ff5fb3319..48f631bee22b 100644 --- a/usr.bin/mail/strings.c +++ b/usr.bin/mail/strings.c @@ -1,4 +1,4 @@ -/* $NetBSD: strings.c,v 1.16 2007/10/29 23:20:39 christos Exp $ */ +/* $NetBSD: strings.c,v 1.17 2009/04/10 13:08:25 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)strings.c 8.1 (Berkeley) 6/6/93"; #else -__RCSID("$NetBSD: strings.c,v 1.16 2007/10/29 23:20:39 christos Exp $"); +__RCSID("$NetBSD: strings.c,v 1.17 2009/04/10 13:08:25 christos Exp $"); #endif #endif /* not lint */ @@ -61,7 +61,7 @@ __RCSID("$NetBSD: strings.c,v 1.16 2007/10/29 23:20:39 christos Exp $"); static struct strings { char *s_topFree; /* Beginning of this area */ char *s_nextFree; /* Next alloctable place here */ - unsigned s_nleft; /* Number of bytes left here */ + size_t s_nleft; /* Number of bytes left here */ } stringdope[NSPACE]; /* @@ -71,7 +71,6 @@ static struct strings { * The string spaces are of exponentially increasing size, to satisfy * the occasional user with enormous string size requests. */ - PUBLIC void * salloc(size_t size) { @@ -94,7 +93,7 @@ salloc(size_t size) if (sp >= &stringdope[NSPACE]) errx(1, "String too large"); if (sp->s_topFree == NULL) { - idx = sp - &stringdope[0]; + idx = (int)(sp - &stringdope[0]); sp->s_topFree = malloc(STRINGSIZE << idx); if (sp->s_topFree == NULL) errx(1, "No room for space %d", idx); diff --git a/usr.bin/mail/support.c b/usr.bin/mail/support.c index fab7bd806e41..0b09b4c2c75a 100644 --- a/usr.bin/mail/support.c +++ b/usr.bin/mail/support.c @@ -1,4 +1,4 @@ -/* $NetBSD: support.c,v 1.21 2008/04/24 01:27:07 christos Exp $ */ +/* $NetBSD: support.c,v 1.22 2009/04/10 13:08:25 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)aux.c 8.1 (Berkeley) 6/6/93"; #else -__RCSID("$NetBSD: support.c,v 1.21 2008/04/24 01:27:07 christos Exp $"); +__RCSID("$NetBSD: support.c,v 1.22 2009/04/10 13:08:25 christos Exp $"); #endif #endif /* not lint */ @@ -169,7 +169,7 @@ argcount(char **argv) for (ap = argv; *ap++ != NULL; /*EMPTY*/) continue; - return ap - argv - 1; + return (int)(ap - argv - 1); } /* @@ -211,7 +211,7 @@ gethfield(FILE *f, char linebuf[], int rem, char **colon) for (;;) { if (--rem < 0) return -1; - if ((c = mail_readline(f, linebuf, LINESIZE)) <= 0) + if ((c = readline(f, linebuf, LINESIZE, 0)) <= 0) return -1; for (cp = linebuf; isprint((unsigned char)*cp) && *cp != ' ' && *cp != ':'; @@ -234,11 +234,11 @@ gethfield(FILE *f, char linebuf[], int rem, char **colon) (void)ungetc(c = getc(f), f); if (!is_WSP(c)) break; - if ((c = mail_readline(f, line2, LINESIZE)) < 0) + if ((c = readline(f, line2, LINESIZE, 0)) < 0) break; rem--; cp2 = skip_WSP(line2); - c -= cp2 - line2; + c -= (int)(cp2 - line2); if (cp + c >= linebuf + LINESIZE - 2) break; *cp++ = ' '; @@ -271,9 +271,9 @@ hfield(const char field[], const struct message *mp) #endif ibuf = setinput(mp); - if ((lc = mp->m_lines - 1) < 0) + if ((lc = (int)(mp->m_lines - 1)) < 0) return NULL; - if (mail_readline(ibuf, linebuf, LINESIZE) < 0) + if (readline(ibuf, linebuf, LINESIZE, 0) < 0) return NULL; while (lc > 0) { if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0) @@ -571,7 +571,7 @@ name1(struct message *mp, int reptype) return cp; ibuf = setinput(mp); namebuf[0] = '\0'; - if (mail_readline(ibuf, linebuf, LINESIZE) < 0) + if (readline(ibuf, linebuf, LINESIZE, 0) < 0) return savestr(namebuf); newname: for (cp = linebuf; *cp && *cp != ' '; cp++) @@ -582,7 +582,7 @@ name1(struct message *mp, int reptype) /*EMPTY*/) *cp2++ = *cp++; *cp2 = '\0'; - if (mail_readline(ibuf, linebuf, LINESIZE) < 0) + if (readline(ibuf, linebuf, LINESIZE, 0) < 0) return savestr(namebuf); if ((cp = strchr(linebuf, 'F')) == NULL) return savestr(namebuf); diff --git a/usr.bin/mail/thread.c b/usr.bin/mail/thread.c index b5d139ad141d..dce5ef2ee2d2 100644 --- a/usr.bin/mail/thread.c +++ b/usr.bin/mail/thread.c @@ -1,4 +1,4 @@ -/* $NetBSD: thread.c,v 1.7 2009/01/18 01:29:57 lukem Exp $ */ +/* $NetBSD: thread.c,v 1.8 2009/04/10 13:08:25 christos Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ #include #ifndef __lint__ -__RCSID("$NetBSD: thread.c,v 1.7 2009/01/18 01:29:57 lukem Exp $"); +__RCSID("$NetBSD: thread.c,v 1.8 2009/04/10 13:08:25 christos Exp $"); #endif /* not __lint__ */ #include @@ -780,7 +780,7 @@ link_array(struct key_sort_s *marray, size_t mcount) struct message *lastmp; lastmp = NULL; for (i = 0; i < mcount; i++) { - marray[i].mp->m_index = i + 1; + marray[i].mp->m_index = (int)i + 1; marray[i].mp->m_blink = lastmp; marray[i].mp->m_flink = NULL; if (lastmp) diff --git a/usr.bin/mail/tty.c b/usr.bin/mail/tty.c index 952bb842bd62..7de1ec1ab727 100644 --- a/usr.bin/mail/tty.c +++ b/usr.bin/mail/tty.c @@ -1,4 +1,4 @@ -/* $NetBSD: tty.c,v 1.27 2006/11/28 18:45:32 christos Exp $ */ +/* $NetBSD: tty.c,v 1.28 2009/04/10 13:08:25 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)tty.c 8.2 (Berkeley) 6/6/93"; #else -__RCSID("$NetBSD: tty.c,v 1.27 2006/11/28 18:45:32 christos Exp $"); +__RCSID("$NetBSD: tty.c,v 1.28 2009/04/10 13:08:25 christos Exp $"); #endif #endif /* not lint */ @@ -47,77 +47,55 @@ __RCSID("$NetBSD: tty.c,v 1.27 2006/11/28 18:45:32 christos Exp $"); #include "rcv.h" #include "extern.h" #ifdef USE_EDITLINE -#include "complete.h" +# include "complete.h" #endif +#include "sig.h" -#if !defined(USE_EDITLINE) || !defined(TIOCSTI) +static jmp_buf tty_jmpbuf; /* Place to go when interrupted */ + +#ifndef USE_EDITLINE static cc_t c_erase; /* Current erase char */ static cc_t c_kill; /* Current kill char */ -#endif -#ifndef USE_EDITLINE -static jmp_buf rewrite; /* Place to go when continued */ -#endif -static jmp_buf intjmp; /* Place to go when interrupted */ -#ifndef TIOCSTI +# ifndef TIOCSTI static int ttyset; /* We must now do erase/kill */ -#endif - +# endif +#endif /* USE_EDITLINE */ /* * Read up a header from standard input. * The source string has the preliminary contents to * be read. * + * Returns: an salloc'ed copy of the line read if successful, or NULL + * if no characters were read or if an error occurred. + * */ #ifdef USE_EDITLINE static char * -readtty(const char pr[], char src[]) +readtty(const char *pr, char *src) { char *line; + line = my_gets(&elm.string, pr, src); -#if 0 + sig_check(); + if (line == NULL) + (void)putc('\n', stdout); + return line ? savestr(line) : __UNCONST(""); -#else - if (line) - return savestr(line); - else - return __UNCONST(""); -#endif } -#else /* USE_EDITLINE */ - -/* - * Receipt continuation. - */ -static void -ttystop(int s) -{ - sig_t old_action = signal(s, SIG_DFL); - sigset_t nset; - - (void)sigemptyset(&nset); - (void)sigaddset(&nset, s); - (void)sigprocmask(SIG_BLOCK, &nset, NULL); - (void)kill(0, s); - (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); - (void)signal(s, old_action); - longjmp(rewrite, 1); -} +#else /* not USE_EDITLINE */ static char * -readtty(const char pr[], char src[]) +readtty(const char *pr, char *src) { - /* XXX - watch for potential setjmp/longjmp clobbering! - * Currently there appear to be none. - */ char canonb[LINESIZE]; - int c; char *cp, *cp2; + int c; #ifdef TIOCSTI char ch; - static char empty[] = ""; #endif + (void)fputs(pr, stdout); (void)fflush(stdout); if (src != NULL && strlen(src) > sizeof(canonb) - 2) { @@ -128,11 +106,12 @@ readtty(const char pr[], char src[]) if (src != NULL) cp = copy(src, canonb); else - cp = copy("", canonb); + cp = copy(__UNCONST(""), canonb); + c = *cp; (void)fputs(canonb, stdout); (void)fflush(stdout); #else - cp = src == NULL ? empty : src; + cp = src == NULL ? __UNCONST("") : src; while ((c = *cp++) != '\0') { if ((c_erase != _POSIX_VDISABLE && c == c_erase) || (c_kill != _POSIX_VDISABLE && c == c_kill)) { @@ -143,30 +122,25 @@ readtty(const char pr[], char src[]) (void)ioctl(0, TIOCSTI, &ch); } cp = canonb; - *cp = 0; + *cp = '\0'; #endif - cp2 = cp; - while (cp2 < canonb + sizeof(canonb)) - *cp2++ = 0; - cp2 = cp; - if (setjmp(rewrite)) - goto redo; - (void)signal(SIGTSTP, ttystop); - (void)signal(SIGTTOU, ttystop); - (void)signal(SIGTTIN, ttystop); clearerr(stdin); - while (cp2 < canonb + sizeof(canonb)) { + cp2 = cp; + while (cp2 < canonb + sizeof(canonb) - 1) { c = getc(stdin); - if (c == EOF || c == '\n') + sig_check(); + if (c == EOF) { + if (feof(stdin)) + (void)putc('\n', stdout); + break; + } + if (c == '\n') break; *cp2++ = c; } - *cp2 = 0; - (void)signal(SIGTSTP, SIG_DFL); - (void)signal(SIGTTOU, SIG_DFL); - (void)signal(SIGTTIN, SIG_DFL); + *cp2 = '\0'; + if (c == EOF && ferror(stdin)) { -redo: cp = strlen(canonb) > 0 ? canonb : NULL; clearerr(stdin); return readtty(pr, cp); @@ -174,9 +148,13 @@ redo: #ifndef TIOCSTI if (cp == NULL || *cp == '\0') return src; - cp2 = cp; - if (!ttyset) + if (ttyset == 0) return strlen(canonb) > 0 ? savestr(canonb) : NULL; + + /* + * Do erase and kill. + */ + cp2 = cp; while (*cp != '\0') { c = *cp++; if (c_erase != _POSIX_VDISABLE && c == c_erase) { @@ -203,173 +181,193 @@ redo: } *cp2 = '\0'; #endif - if (equal("", canonb)) - return NULL; + if (canonb[0] == '\0') + return __UNCONST(""); return savestr(canonb); } #endif /* USE_EDITLINE */ +#ifdef USE_EDITLINE +# define save_erase_and_kill(t) 0 +#else +static int +save_erase_and_kill(struct termios *t) +{ + +# ifndef TIOCSTI + ttyset = 0; +#endif + if (tcgetattr(fileno(stdin), t) == -1) { + warn("tcgetattr"); + return -1; + } + c_erase = t->c_cc[VERASE]; + c_kill = t->c_cc[VKILL]; + return 0; +} +#endif + +#if defined(USE_EDITLINE) || defined(TIOCSTI) +# define disable_erase_and_kill(t) +#else +static void +disable_erase_and_kill(struct termios *t) +{ + + if (ttyset == 0) { + ttyset = 1; + t->c_cc[VERASE] = _POSIX_VDISABLE; + t->c_cc[VKILL] = _POSIX_VDISABLE; + (void)tcsetattr(fileno(stdin), TCSADRAIN, t); + } +} +#endif + +#if defined(USE_EDITLINE) || defined(TIOCSTI) +# define restore_erase_and_kill(t) +#else +static void +restore_erase_and_kill(struct termios *t) +{ + + if (ttyset != 0) { + ttyset = 0; + t->c_cc[VERASE] = c_erase; + t->c_cc[VKILL] = c_kill; + (void)tcsetattr(fileno(stdin), TCSADRAIN, t); + } +} +#endif + +/* + * Do a shell-like extraction of a line + * and make a list of name from it. + * Return the list or NULL if none found. + */ +static struct name * +shextract(char *line, int ntype) +{ + struct name *begin, *np, *t; + char *argv[MAXARGC]; + size_t argc, i; + + begin = NULL; + if (line) { + np = NULL; + argc = getrawlist(line, argv, (int)__arraycount(argv)); + for (i = 0; i < argc; i++) { + t = nalloc(argv[i], ntype); + if (begin == NULL) + begin = t; + else + np->n_flink = t; + t->n_blink = np; + np = t; + } + } + return begin; +} /*ARGSUSED*/ static void -ttyint(int s __unused) +tty_sigint(int signo __unused) { - longjmp(intjmp, 1); + + longjmp(tty_jmpbuf, 1); } /* * Read all relevant header fields. + * Returns 0 on success; 1 if there was an error or signal. */ PUBLIC int grabh(struct header *hp, int gflags) { - struct termios ttybuf; - - /* The following are declared volatile to avoid longjmp - * clobbering, though they seem safe without it! */ - sig_t volatile saveint; - sig_t volatile savetstp; - sig_t volatile savettou; - sig_t volatile savettin; -#ifndef TIOCSTI - sig_t volatile savequit; -#else -# ifdef TIOCEXT - int volatile extproc; -# endif /* TIOCEXT */ -#endif /* TIOCSTI */ + sig_t volatile old_sigint; int retval; +#ifndef USE_EDITLINE + struct termios ttybuf; +# if defined(TIOCSTI) && defined(TIOCEXT) + int extproc; +# endif - savetstp = signal(SIGTSTP, SIG_DFL); - savettou = signal(SIGTTOU, SIG_DFL); - savettin = signal(SIGTTIN, SIG_DFL); -#ifndef TIOCSTI - ttyset = 0; -#endif - if (tcgetattr(fileno(stdin), &ttybuf) < 0) { - warn("tcgetattr"); + if (save_erase_and_kill(&ttybuf)) return -1; - } -#if !defined(USE_EDITLINE) || !defined(TIOCSTI) - c_erase = ttybuf.c_cc[VERASE]; - c_kill = ttybuf.c_cc[VKILL]; -#endif -#ifndef TIOCSTI - ttybuf.c_cc[VERASE] = _POSIX_VDISABLE; - ttybuf.c_cc[VKILL] = _POSIX_VDISABLE; - 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); -#else -# ifdef TIOCEXT + +# if defined(TIOCSTI) && defined(TIOCEXT) extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0); if (extproc) { int flag; + flag = 0; - if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) + if (ioctl(fileno(stdin), TIOCEXT, &flag) == -1) warn("TIOCEXT: off"); } -# endif /* TIOCEXT */ - saveint = signal(SIGINT, ttyint); /* must precede setjmp to be saved */ - if ((retval = setjmp(intjmp)) != 0) { - (void)fputc('\n', stdout); +# endif +#endif /* USE_EDITLINE */ + + sig_check(); + old_sigint = sig_signal(SIGINT, tty_sigint); + + /* return here if we detect a SIGINT */ + if ((retval = setjmp(tty_jmpbuf)) != 0) { + (void)putc('\n', stdout); goto out; } -#endif + + /* + * Do this irrespective of whether the initial string is empty. + * Otherwise, the editing is inconsistent. + */ + disable_erase_and_kill(&ttybuf); + if (gflags & GTO) { -#ifndef TIOCSTI - if (!ttyset && hp->h_to != NULL) - ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); -#endif hp->h_to = - extract(readtty("To: ", detract(hp->h_to, 0)), GTO); + extract(readtty("To: ", detract(hp->h_to, 0)), 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); } if (gflags & GCC) { -#ifndef TIOCSTI - if (!ttyset && hp->h_cc != NULL) - ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); -#endif hp->h_cc = - extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC); + extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC); } if (gflags & GBCC) { -#ifndef TIOCSTI - if (!ttyset && hp->h_bcc != NULL) - ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); -#endif hp->h_bcc = - extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC); + extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC); } if (gflags & GSMOPTS) { - char *smopts; -#ifndef TIOCSTI - if (!ttyset && hp->h_smopts != NULL) - ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); -#endif - smopts = readtty("Smopts: ", detract(hp->h_smopts, GSMOPTS)); - - /* Parse smopts with getrawlist() rather than expand() - * to get a shell-like expansion. - */ - hp->h_smopts = NULL; - if (smopts) { - struct name *np, *t; - char *argv[MAXARGC]; - int argc, i; - - np = NULL; - argc = getrawlist(smopts, argv, sizeof(argv)/sizeof(*argv)); - for (i = 0; i < argc; i++) { - t = nalloc(argv[i], GSMOPTS); - if (hp->h_smopts == NULL) - hp->h_smopts = t; - else - np->n_flink = t; - t->n_blink = np; - np = t; - } - } + hp->h_smopts = + shextract(readtty("Smopts: ", detract(hp->h_smopts, 0)), + GSMOPTS); + } #ifdef MIME_SUPPORT + if (gflags & GSMOPTS) { /* XXX - Use a new flag for this? */ if (hp->h_attach) { struct attachment *ap; int i; + i = 0; for (ap = hp->h_attach; ap; ap = ap->a_flink) i++; (void)printf("Attachment%s: %d\n", i > 1 ? "s" : "", i); } -#endif } -#ifdef TIOCSTI -out: #endif - (void)signal(SIGTSTP, savetstp); - (void)signal(SIGTTOU, savettou); - (void)signal(SIGTTIN, savettin); -#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); -#else -# ifdef TIOCEXT + out: + restore_erase_and_kill(&ttybuf); + +#ifndef USE_EDITLINE +# if defined(TIOCSTI) && defined(TIOCEXT) if (extproc) { int flag; flag = 1; - if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) + if (ioctl(fileno(stdin), TIOCEXT, &flag) == -1) warn("TIOCEXT: on"); } -# endif /* TIOCEXT */ +# endif #endif - (void)signal(SIGINT, saveint); + (void)sig_signal(SIGINT, old_sigint); + sig_check(); return retval; } diff --git a/usr.bin/mail/version.c b/usr.bin/mail/version.c index 12e8f237c779..a55990b4a9bc 100644 --- a/usr.bin/mail/version.c +++ b/usr.bin/mail/version.c @@ -1,4 +1,4 @@ -/* $NetBSD: version.c,v 1.12 2007/02/15 17:18:15 christos Exp $ */ +/* $NetBSD: version.c,v 1.13 2009/04/10 13:08:25 christos Exp $ */ /* * Copyright (c) 1980, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)version.c 8.1 (Berkeley) 6/6/93"; #else -__RCSID("$NetBSD: version.c,v 1.12 2007/02/15 17:18:15 christos Exp $"); +__RCSID("$NetBSD: version.c,v 1.13 2009/04/10 13:08:25 christos Exp $"); #endif #endif /* not lint */ @@ -45,4 +45,4 @@ __RCSID("$NetBSD: version.c,v 1.12 2007/02/15 17:18:15 christos Exp $"); * Just keep track of the date/sid of this version of Mail. * Load this file first to get a "total" Mail version. */ -const char *version = "9.0beta 2007-02-15"; +const char *version = "9.1alpha 2009-02-25";