Index: stable/11/usr.bin/mail/cmd1.c =================================================================== --- stable/11/usr.bin/mail/cmd1.c (revision 335692) +++ stable/11/usr.bin/mail/cmd1.c (revision 335693) @@ -1,466 +1,466 @@ /*- * 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. * 4. 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. */ #ifndef lint #if 0 static char sccsid[] = "@(#)cmd1.c 8.2 (Berkeley) 4/20/95"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include "rcv.h" #include "extern.h" /* * Mail -- a mail program * * User commands. */ extern const struct cmd cmdtab[]; /* * Print the current active headings. * Don't change dot if invoker didn't give an argument. */ static int screen; int headers(int *msgvec) { int n, mesg, flag, size; struct message *mp; size = screensize(); n = msgvec[0]; if (n != 0) screen = (n-1)/size; if (screen < 0) screen = 0; mp = &message[screen * size]; if (mp >= &message[msgCount]) mp = &message[msgCount - size]; if (mp < &message[0]) mp = &message[0]; flag = 0; mesg = mp - &message[0]; if (dot != &message[n-1]) dot = mp; for (; mp < &message[msgCount]; mp++) { mesg++; if (mp->m_flag & MDELETED) continue; if (flag++ >= size) break; printhead(mesg); } if (flag == 0) { printf("No more mail.\n"); return (1); } return (0); } /* * Scroll to the next/previous screen */ int scroll(char arg[]) { int s, size; int cur[1]; cur[0] = 0; size = screensize(); s = screen; switch (*arg) { case 0: case '+': s++; if (s * size >= msgCount) { printf("On last screenful of messages\n"); return (0); } screen = s; break; case '-': if (--s < 0) { printf("On first screenful of messages\n"); return (0); } screen = s; break; default: printf("Unrecognized scrolling command \"%s\"\n", arg); return (1); } return (headers(cur)); } /* * Compute screen size. */ int screensize(void) { int s; char *cp; if ((cp = value("screen")) != NULL && (s = atoi(cp)) > 0) return (s); return (screenheight - 4); } /* * Print out the headlines for each message * in the passed message list. */ int from(int *msgvec) { int *ip; for (ip = msgvec; *ip != 0; ip++) printhead(*ip); if (--ip >= msgvec) dot = &message[*ip - 1]; return (0); } /* * Print out the header of a specific message. * This is a slight improvement to the standard one. */ void printhead(int mesg) { struct message *mp; char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind; char pbuf[BUFSIZ]; struct headline hl; int subjlen; char *name; mp = &message[mesg-1]; (void)readline(setinput(mp), headline, LINESIZE); if ((subjline = hfield("subject", mp)) == NULL) subjline = hfield("subj", mp); /* * Bletch! */ curind = dot == mp ? '>' : ' '; dispc = ' '; if (mp->m_flag & MSAVED) dispc = '*'; if (mp->m_flag & MPRESERVE) dispc = 'P'; if ((mp->m_flag & (MREAD|MNEW)) == MNEW) dispc = 'N'; if ((mp->m_flag & (MREAD|MNEW)) == 0) dispc = 'U'; if (mp->m_flag & MBOX) dispc = 'M'; parse(headline, &hl, pbuf); sprintf(wcount, "%3ld/%-5ld", mp->m_lines, mp->m_size); subjlen = screenwidth - 50 - strlen(wcount); name = value("show-rcpt") != NULL ? skin(hfield("to", mp)) : nameof(mp, 0); if (subjline == NULL || subjlen < 0) /* pretty pathetic */ printf("%c%c%3d %-20.20s %16.16s %s\n", curind, dispc, mesg, name, hl.l_date, wcount); else printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n", curind, dispc, mesg, name, hl.l_date, wcount, subjlen, subjline); } /* * Print out the value of dot. */ int pdot(void) { printf("%td\n", dot - &message[0] + 1); return (0); } /* * Print out all the possible commands. */ int pcmdlist(void) { const struct cmd *cp; int cc; printf("Commands are:\n"); for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) { cc += strlen(cp->c_name) + 2; if (cc > 72) { printf("\n"); cc = strlen(cp->c_name) + 2; } if ((cp+1)->c_name != NULL) printf("%s, ", cp->c_name); else printf("%s\n", cp->c_name); } return (0); } /* * Paginate messages, honor ignored fields. */ int more(int *msgvec) { return (type1(msgvec, 1, 1)); } /* * Paginate messages, even printing ignored fields. */ int More(int *msgvec) { return (type1(msgvec, 0, 1)); } /* * Type out messages, honor ignored fields. */ int type(int *msgvec) { return (type1(msgvec, 1, 0)); } /* * Type out messages, even printing ignored fields. */ int Type(int *msgvec) { return (type1(msgvec, 0, 0)); } /* * Type out the messages requested. */ static jmp_buf pipestop; int type1(int *msgvec, int doign, int page) { int nlines, *ip; struct message *mp; char *cp; FILE *obuf; obuf = stdout; if (setjmp(pipestop)) goto close_pipe; if (value("interactive") != NULL && (page || (cp = value("crt")) != NULL)) { nlines = 0; if (!page) { for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) nlines += message[*ip - 1].m_lines; } if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) { cp = value("PAGER"); if (cp == NULL || *cp == '\0') cp = _PATH_MORE; obuf = Popen(cp, "w"); if (obuf == NULL) { warnx("%s", cp); obuf = stdout; } else (void)signal(SIGPIPE, brokpipe); } } /* * Send messages to the output. * */ for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) { mp = &message[*ip - 1]; touch(mp); dot = mp; if (value("quiet") == NULL) fprintf(obuf, "Message %d:\n", *ip); (void)sendmessage(mp, obuf, doign ? ignore : 0, NULL); } close_pipe: if (obuf != stdout) { /* * Ignore SIGPIPE so it can't cause a duplicate close. */ (void)signal(SIGPIPE, SIG_IGN); (void)Pclose(obuf); (void)signal(SIGPIPE, SIG_DFL); } return (0); } /* * Respond to a broken pipe signal -- * probably caused by quitting more. */ /*ARGSUSED*/ void brokpipe(int signo __unused) { longjmp(pipestop, 1); } /* * Print the top so many lines of each desired message. * The number of lines is taken from the variable "toplines" * and defaults to 5. */ int top(int *msgvec) { int *ip; struct message *mp; int c, topl, lines, lineb; char *valtop, linebuf[LINESIZE]; FILE *ibuf; topl = 5; valtop = value("toplines"); if (valtop != NULL) { topl = atoi(valtop); if (topl < 0 || topl > 10000) topl = 5; } lineb = 1; for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { mp = &message[*ip - 1]; touch(mp); dot = mp; if (value("quiet") == NULL) printf("Message %d:\n", *ip); ibuf = setinput(mp); c = mp->m_lines; if (!lineb) printf("\n"); for (lines = 0; lines < c && lines <= topl; lines++) { if (readline(ibuf, linebuf, sizeof(linebuf)) < 0) break; puts(linebuf); lineb = strspn(linebuf, " \t") == strlen(linebuf); } } return (0); } /* * Touch all the given messages so that they will * get mboxed. */ int stouch(int msgvec[]) { int *ip; for (ip = msgvec; *ip != 0; ip++) { dot = &message[*ip-1]; dot->m_flag |= MTOUCH; dot->m_flag &= ~MPRESERVE; } return (0); } /* * Make sure all passed messages get mboxed. */ int mboxit(int msgvec[]) { int *ip; for (ip = msgvec; *ip != 0; ip++) { dot = &message[*ip-1]; dot->m_flag |= MTOUCH|MBOX; dot->m_flag &= ~MPRESERVE; } return (0); } /* * List the folders the user currently has. */ int folders(void) { char dirname[PATHSIZE]; char *cmd; if (getfold(dirname, sizeof(dirname)) < 0) { printf("No value set for \"folder\"\n"); return (1); } if ((cmd = value("LISTER")) == NULL) cmd = "ls"; - (void)run_command(cmd, 0, -1, -1, dirname, NULL, NULL); + (void)run_command(cmd, 0, -1, -1, dirname, NULL); return (0); } /* * Update the mail file with any new messages that have * come in since we started reading mail. */ int inc(void *v __unused) { int nmsg, mdot; nmsg = incfile(); if (nmsg == 0) printf("No new mail.\n"); else if (nmsg > 0) { mdot = newfileinfo(msgCount - nmsg); dot = &message[mdot - 1]; } else printf("\"inc\" command failed...\n"); return (0); } Index: stable/11/usr.bin/mail/cmd2.c =================================================================== --- stable/11/usr.bin/mail/cmd2.c (revision 335692) +++ stable/11/usr.bin/mail/cmd2.c (revision 335693) @@ -1,504 +1,506 @@ /* * 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. * 4. 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. */ #ifndef lint #if 0 static char sccsid[] = "@(#)cmd2.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include "rcv.h" #include #include "extern.h" /* * Mail -- a mail program * * More user commands. */ extern int wait_status; /* * If any arguments were given, go to the next applicable argument * following dot, otherwise, go to the next applicable message. * If given as first command with no arguments, print first message. */ int next(int *msgvec) { struct message *mp; int *ip, *ip2, list[2], mdot; if (*msgvec != 0) { /* * If some messages were supplied, find the * first applicable one following dot using * wrap around. */ mdot = dot - &message[0] + 1; /* * Find the first message in the supplied * message list which follows dot. */ for (ip = msgvec; *ip != 0; ip++) if (*ip > mdot) break; if (*ip == 0) ip = msgvec; ip2 = ip; do { mp = &message[*ip2 - 1]; if ((mp->m_flag & MDELETED) == 0) { dot = mp; goto hitit; } if (*ip2 != 0) ip2++; if (*ip2 == 0) ip2 = msgvec; } while (ip2 != ip); printf("No messages applicable\n"); return (1); } /* * If this is the first command, select message 1. * Note that this must exist for us to get here at all. */ if (!sawcom) goto hitit; /* * Just find the next good message after dot, no * wraparound. */ for (mp = dot+1; mp < &message[msgCount]; mp++) if ((mp->m_flag & (MDELETED|MSAVED)) == 0) break; if (mp >= &message[msgCount]) { printf("At EOF\n"); return (0); } dot = mp; hitit: /* * Print dot. */ list[0] = dot - &message[0] + 1; list[1] = 0; return (type(list)); } /* * Save a message in a file. Mark the message as saved * so we can discard when the user quits. */ int -save(char str[]) +save(void *v) { + char *str = v; return (save1(str, 1, "save", saveignore)); } /* * Copy a message to a file without affected its saved-ness */ int -copycmd(char str[]) +copycmd(void *v) { + char *str = v; return (save1(str, 0, "copy", saveignore)); } /* * Save/copy the indicated messages at the end of the passed file name. * If mark is true, mark the message "saved." */ int save1(char str[], int mark, const char *cmd, struct ignoretab *ignore) { struct message *mp; char *file; const char *disp; int f, *msgvec, *ip; FILE *obuf; msgvec = (int *)salloc((msgCount + 2) * sizeof(*msgvec)); if ((file = snarf(str, &f)) == NULL) return (1); if (!f) { *msgvec = first(0, MMNORM); if (*msgvec == 0) { printf("No messages to %s.\n", cmd); return (1); } msgvec[1] = 0; } if (f && getmsglist(str, msgvec, 0) < 0) return (1); if ((file = expand(file)) == NULL) return (1); printf("\"%s\" ", file); (void)fflush(stdout); if (access(file, 0) >= 0) disp = "[Appended]"; else disp = "[New file]"; if ((obuf = Fopen(file, "a")) == NULL) { warn((char *)NULL); return (1); } for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { mp = &message[*ip - 1]; touch(mp); if (sendmessage(mp, obuf, ignore, NULL) < 0) { warnx("%s", file); (void)Fclose(obuf); return (1); } if (mark) mp->m_flag |= MSAVED; } (void)fflush(obuf); if (ferror(obuf)) warn("%s", file); (void)Fclose(obuf); printf("%s\n", disp); return (0); } /* * Write the indicated messages at the end of the passed * file name, minus header and trailing blank line. */ int swrite(char str[]) { return (save1(str, 1, "write", ignoreall)); } /* * Snarf the file from the end of the command line and * return a pointer to it. If there is no file attached, * just return NULL. Put a null in front of the file * name so that the message list processing won't see it, * unless the file name is the only thing on the line, in * which case, return 0 in the reference flag variable. */ char * snarf(char linebuf[], int *flag) { char *cp; *flag = 1; cp = strlen(linebuf) + linebuf - 1; /* * Strip away trailing blanks. */ while (cp > linebuf && isspace((unsigned char)*cp)) cp--; *++cp = '\0'; /* * Now search for the beginning of the file name. */ while (cp > linebuf && !isspace((unsigned char)*cp)) cp--; if (*cp == '\0') { printf("No file specified.\n"); return (NULL); } if (isspace((unsigned char)*cp)) *cp++ = '\0'; else *flag = 0; return (cp); } /* * Delete messages. */ int delete(int msgvec[]) { delm(msgvec); return (0); } /* * Delete messages, then type the new dot. */ int deltype(int msgvec[]) { int list[2]; int lastdot; lastdot = dot - &message[0] + 1; if (delm(msgvec) >= 0) { list[0] = dot - &message[0] + 1; if (list[0] > lastdot) { touch(dot); list[1] = 0; return (type(list)); } printf("At EOF\n"); } else printf("No more messages\n"); return (0); } /* * Delete the indicated messages. * Set dot to some nice place afterwards. * Internal interface. */ int delm(int *msgvec) { struct message *mp; int *ip, last; last = 0; for (ip = msgvec; *ip != 0; ip++) { mp = &message[*ip - 1]; touch(mp); mp->m_flag |= MDELETED|MTOUCH; mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); last = *ip; } if (last != 0) { dot = &message[last-1]; last = first(0, MDELETED); if (last != 0) { dot = &message[last-1]; return (0); } else { dot = &message[0]; return (-1); } } /* * Following can't happen -- it keeps lint happy */ return (-1); } /* * Undelete the indicated messages. */ int undelete_messages(int *msgvec) { struct message *mp; int *ip; for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { mp = &message[*ip - 1]; touch(mp); dot = mp; mp->m_flag &= ~MDELETED; } return (0); } /* * Interactively dump core on "core" */ int core(void) { int pid; switch (pid = fork()) { case -1: warn("fork"); return (1); case 0: abort(); _exit(1); } printf("Okie dokie"); (void)fflush(stdout); wait_child(pid); if (WIFSIGNALED(wait_status) && WCOREDUMP(wait_status)) printf(" -- Core dumped.\n"); else printf(" -- Can't dump core.\n"); return (0); } /* * Clobber as many bytes of stack as the user requests. */ int clobber(char **argv) { int times; if (argv[0] == 0) times = 1; else times = (atoi(argv[0]) + 511) / 512; clob1(times); return (0); } /* * Clobber the stack. */ void clob1(int n) { char buf[512]; char *cp; if (n <= 0) return; for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) ; clob1(n - 1); } /* * Add the given header fields to the retained list. * If no arguments, print the current list of retained fields. */ int retfield(char *list[]) { return (ignore1(list, ignore + 1, "retained")); } /* * Add the given header fields to the ignored list. * If no arguments, print the current list of ignored fields. */ int igfield(char *list[]) { return (ignore1(list, ignore, "ignored")); } int saveretfield(char *list[]) { return (ignore1(list, saveignore + 1, "retained")); } int saveigfield(char *list[]) { return (ignore1(list, saveignore, "ignored")); } int ignore1(char *list[], struct ignoretab *tab, const char *which) { char field[LINESIZE]; int h; struct ignore *igp; char **ap; if (*list == NULL) return (igshow(tab, which)); for (ap = list; *ap != 0; ap++) { istrncpy(field, *ap, sizeof(field)); if (member(field, tab)) continue; h = hash(field); igp = calloc(1, sizeof(struct ignore)); igp->i_field = calloc((unsigned)strlen(field) + 1, sizeof(char)); strcpy(igp->i_field, field); igp->i_link = tab->i_head[h]; tab->i_head[h] = igp; tab->i_count++; } return (0); } /* * Print out all currently retained fields. */ int igshow(struct ignoretab *tab, const char *which) { int h; struct ignore *igp; char **ap, **ring; if (tab->i_count == 0) { printf("No fields currently being %s.\n", which); return (0); } ring = (char **)salloc((tab->i_count + 1) * sizeof(char *)); ap = ring; for (h = 0; h < HSHSIZE; h++) for (igp = tab->i_head[h]; igp != NULL; igp = igp->i_link) *ap++ = igp->i_field; *ap = 0; qsort(ring, tab->i_count, sizeof(char *), igcomp); for (ap = ring; *ap != 0; ap++) printf("%s\n", *ap); return (0); } /* * Compare two names for sorting ignored field list. */ int igcomp(const void *l, const void *r) { return (strcmp(*(const char **)l, *(const char **)r)); } Index: stable/11/usr.bin/mail/cmd3.c =================================================================== --- stable/11/usr.bin/mail/cmd3.c (revision 335692) +++ stable/11/usr.bin/mail/cmd3.c (revision 335693) @@ -1,716 +1,716 @@ /* * 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. * 4. 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. */ #ifndef lint #if 0 static char sccsid[] = "@(#)cmd3.c 8.2 (Berkeley) 4/20/95"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include "rcv.h" #include "extern.h" /* * Mail -- a mail program * * Still more user commands. */ /* * Process a shell escape by saving signals, ignoring signals, * and forking a sh -c */ int shell(char *str) { sig_t sigint = signal(SIGINT, SIG_IGN); char *sh; char cmd[BUFSIZ]; if (strlcpy(cmd, str, sizeof(cmd)) >= sizeof(cmd)) return (1); if (bangexp(cmd, sizeof(cmd)) < 0) return (1); if ((sh = value("SHELL")) == NULL) sh = _PATH_CSHELL; (void)run_command(sh, 0, -1, -1, "-c", cmd, NULL); (void)signal(SIGINT, sigint); printf("!\n"); return (0); } /* * Fork an interactive shell. */ /*ARGSUSED*/ int dosh(char *str __unused) { sig_t sigint = signal(SIGINT, SIG_IGN); char *sh; if ((sh = value("SHELL")) == NULL) sh = _PATH_CSHELL; - (void)run_command(sh, 0, -1, -1, NULL, NULL, NULL); + (void)run_command(sh, 0, -1, -1, NULL); (void)signal(SIGINT, sigint); printf("\n"); return (0); } /* * Expand the shell escape by expanding unescaped !'s into the * last issued command where possible. */ int bangexp(char *str, size_t strsize) { char bangbuf[BUFSIZ]; static char lastbang[BUFSIZ]; char *cp, *cp2; int n, changed = 0; cp = str; cp2 = bangbuf; n = sizeof(bangbuf); while (*cp != '\0') { if (*cp == '!') { - if (n < strlen(lastbang)) { + if (n < (int)strlen(lastbang)) { overf: printf("Command buffer overflow\n"); return (-1); } changed++; if (strlcpy(cp2, lastbang, sizeof(bangbuf) - (cp2 - bangbuf)) >= sizeof(bangbuf) - (cp2 - bangbuf)) goto overf; cp2 += strlen(lastbang); n -= strlen(lastbang); cp++; continue; } if (*cp == '\\' && cp[1] == '!') { if (--n <= 1) goto overf; *cp2++ = '!'; cp += 2; changed++; } if (--n <= 1) goto overf; *cp2++ = *cp++; } *cp2 = 0; if (changed) { printf("!%s\n", bangbuf); (void)fflush(stdout); } if (strlcpy(str, bangbuf, strsize) >= strsize) goto overf; if (strlcpy(lastbang, bangbuf, sizeof(lastbang)) >= sizeof(lastbang)) goto overf; return (0); } /* * Print out a nice help message from some file or another. */ int help(void) { int c; FILE *f; if ((f = Fopen(_PATH_HELP, "r")) == NULL) { warn("%s", _PATH_HELP); return (1); } while ((c = getc(f)) != EOF) putchar(c); (void)Fclose(f); return (0); } /* * Change user's working directory. */ int schdir(char **arglist) { char *cp; if (*arglist == NULL) { if (homedir == NULL) return (1); cp = homedir; } else if ((cp = expand(*arglist)) == NULL) return (1); if (chdir(cp) < 0) { warn("%s", cp); return (1); } return (0); } int respond(int *msgvec) { if (value("Replyall") == NULL && value("flipr") == NULL) return (dorespond(msgvec)); else return (doRespond(msgvec)); } /* * Reply to a list of messages. Extract each name from the * message header and send them off to mail1() */ int dorespond(int *msgvec) { struct message *mp; char *cp, *rcv, *replyto; char **ap; struct name *np; struct header head; if (msgvec[1] != 0) { printf("Sorry, can't reply to multiple messages at once\n"); return (1); } mp = &message[msgvec[0] - 1]; touch(mp); dot = mp; if ((rcv = skin(hfield("from", mp))) == NULL) rcv = skin(nameof(mp, 1)); if ((replyto = skin(hfield("reply-to", mp))) != NULL) np = extract(replyto, GTO); else if ((cp = skin(hfield("to", mp))) != NULL) np = extract(cp, GTO); else np = NULL; np = elide(np); /* * Delete my name from the reply list, * and with it, all my alternate names. */ np = delname(np, myname); if (altnames) for (ap = altnames; *ap != NULL; ap++) np = delname(np, *ap); if (np != NULL && replyto == NULL) np = cat(np, extract(rcv, GTO)); else if (np == NULL) { if (replyto != NULL) printf("Empty reply-to field -- replying to author\n"); np = extract(rcv, GTO); } head.h_to = np; if ((head.h_subject = hfield("subject", mp)) == NULL) head.h_subject = hfield("subj", mp); head.h_subject = reedit(head.h_subject); if (replyto == NULL && (cp = skin(hfield("cc", mp))) != NULL) { np = elide(extract(cp, GCC)); np = delname(np, myname); if (altnames != 0) for (ap = altnames; *ap != NULL; ap++) np = delname(np, *ap); head.h_cc = np; } else head.h_cc = NULL; head.h_bcc = NULL; head.h_smopts = NULL; head.h_replyto = value("REPLYTO"); head.h_inreplyto = skin(hfield("message-id", mp)); mail1(&head, 1); return (0); } /* * Modify the subject we are replying to to begin with Re: if * it does not already. */ char * reedit(char *subj) { char *newsubj; if (subj == NULL) return (NULL); if ((subj[0] == 'r' || subj[0] == 'R') && (subj[1] == 'e' || subj[1] == 'E') && subj[2] == ':') return (subj); newsubj = salloc(strlen(subj) + 5); sprintf(newsubj, "Re: %s", subj); return (newsubj); } /* * Preserve the named messages, so that they will be sent * back to the system mailbox. */ int preserve(int *msgvec) { int *ip, mesg; struct message *mp; if (edit) { printf("Cannot \"preserve\" in edit mode\n"); return (1); } for (ip = msgvec; *ip != 0; ip++) { mesg = *ip; mp = &message[mesg-1]; mp->m_flag |= MPRESERVE; mp->m_flag &= ~MBOX; dot = mp; } return (0); } /* * Mark all given messages as unread. */ int unread(int msgvec[]) { int *ip; for (ip = msgvec; *ip != 0; ip++) { dot = &message[*ip-1]; dot->m_flag &= ~(MREAD|MTOUCH); dot->m_flag |= MSTATUS; } return (0); } /* * Print the size of each message. */ int messize(int *msgvec) { struct message *mp; int *ip, mesg; for (ip = msgvec; *ip != 0; ip++) { mesg = *ip; mp = &message[mesg-1]; printf("%d: %ld/%ld\n", mesg, mp->m_lines, mp->m_size); } return (0); } /* * Quit quickly. If we are sourcing, just pop the input level * by returning an error. */ int rexit(int e __unused) { if (sourcing) return (1); exit(0); /*NOTREACHED*/ } /* * Set or display a variable value. Syntax is similar to that * of csh. */ int set(char **arglist) { struct var *vp; char *cp, *cp2; char varbuf[BUFSIZ], **ap, **p; int errs, h, s; if (*arglist == NULL) { for (h = 0, s = 1; h < HSHSIZE; h++) for (vp = variables[h]; vp != NULL; vp = vp->v_link) s++; ap = (char **)salloc(s * sizeof(*ap)); for (h = 0, p = ap; h < HSHSIZE; h++) for (vp = variables[h]; vp != NULL; vp = vp->v_link) *p++ = vp->v_name; *p = NULL; sort(ap); for (p = ap; *p != NULL; p++) printf("%s\t%s\n", *p, value(*p)); return (0); } errs = 0; for (ap = arglist; *ap != NULL; ap++) { cp = *ap; cp2 = varbuf; while (cp2 < varbuf + sizeof(varbuf) - 1 && *cp != '=' && *cp != '\0') *cp2++ = *cp++; *cp2 = '\0'; if (*cp == '\0') cp = ""; else cp++; if (equal(varbuf, "")) { printf("Non-null variable name required\n"); errs++; continue; } assign(varbuf, cp); } return (errs); } /* * Unset a bunch of variable values. */ int unset(char **arglist) { struct var *vp, *vp2; int errs, h; char **ap; errs = 0; for (ap = arglist; *ap != NULL; ap++) { if ((vp2 = lookup(*ap)) == NULL) { if (getenv(*ap)) unsetenv(*ap); else if (!sourcing) { printf("\"%s\": undefined variable\n", *ap); errs++; } continue; } h = hash(*ap); if (vp2 == variables[h]) { variables[h] = variables[h]->v_link; vfree(vp2->v_name); vfree(vp2->v_value); (void)free(vp2); continue; } for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link) ; vp->v_link = vp2->v_link; vfree(vp2->v_name); vfree(vp2->v_value); (void)free(vp2); } return (errs); } /* * Put add users to a group. */ int group(char **argv) { struct grouphead *gh; struct group *gp; char **ap, *gname, **p; int h, s; if (*argv == NULL) { for (h = 0, s = 1; h < HSHSIZE; h++) for (gh = groups[h]; gh != NULL; gh = gh->g_link) s++; ap = (char **)salloc(s * sizeof(*ap)); for (h = 0, p = ap; h < HSHSIZE; h++) for (gh = groups[h]; gh != NULL; gh = gh->g_link) *p++ = gh->g_name; *p = NULL; sort(ap); for (p = ap; *p != NULL; p++) printgroup(*p); return (0); } if (argv[1] == NULL) { printgroup(*argv); return (0); } gname = *argv; h = hash(gname); if ((gh = findgroup(gname)) == NULL) { if ((gh = calloc(1, sizeof(*gh))) == NULL) err(1, "Out of memory"); gh->g_name = vcopy(gname); gh->g_list = NULL; gh->g_link = groups[h]; groups[h] = gh; } /* * Insert names from the command list into the group. * Who cares if there are duplicates? They get tossed * later anyway. */ for (ap = argv+1; *ap != NULL; ap++) { if ((gp = calloc(1, sizeof(*gp))) == NULL) err(1, "Out of memory"); gp->ge_name = vcopy(*ap); gp->ge_link = gh->g_list; gh->g_list = gp; } return (0); } /* * Sort the passed string vecotor into ascending dictionary * order. */ void sort(char **list) { char **ap; for (ap = list; *ap != NULL; ap++) ; if (ap-list < 2) return; qsort(list, ap-list, sizeof(*list), diction); } /* * Do a dictionary order comparison of the arguments from * qsort. */ int diction(const void *a, const void *b) { return (strcmp(*(const char **)a, *(const char **)b)); } /* * The do nothing command for comments. */ /*ARGSUSED*/ int null(int e __unused) { return (0); } /* * Change to another file. With no argument, print information about * the current file. */ int file(char **argv) { if (argv[0] == NULL) { newfileinfo(0); return (0); } if (setfile(*argv) < 0) return (1); announce(); return (0); } /* * Expand file names like echo */ int echo(char **argv) { char **ap, *cp; for (ap = argv; *ap != NULL; ap++) { cp = *ap; if ((cp = expand(cp)) != NULL) { if (ap != argv) printf(" "); printf("%s", cp); } } printf("\n"); return (0); } int Respond(int *msgvec) { if (value("Replyall") == NULL && value("flipr") == NULL) return (doRespond(msgvec)); else return (dorespond(msgvec)); } /* * Reply to a series of messages by simply mailing to the senders * and not messing around with the To: and Cc: lists as in normal * reply. */ int doRespond(int msgvec[]) { struct header head; struct message *mp; int *ap; char *cp, *mid; head.h_to = NULL; for (ap = msgvec; *ap != 0; ap++) { mp = &message[*ap - 1]; touch(mp); dot = mp; if ((cp = skin(hfield("from", mp))) == NULL) cp = skin(nameof(mp, 2)); head.h_to = cat(head.h_to, extract(cp, GTO)); mid = skin(hfield("message-id", mp)); } if (head.h_to == NULL) return (0); mp = &message[msgvec[0] - 1]; if ((head.h_subject = hfield("subject", mp)) == NULL) head.h_subject = hfield("subj", mp); head.h_subject = reedit(head.h_subject); head.h_cc = NULL; head.h_bcc = NULL; head.h_smopts = NULL; head.h_replyto = value("REPLYTO"); head.h_inreplyto = mid; mail1(&head, 1); return (0); } /* * Conditional commands. These allow one to parameterize one's * .mailrc and do some things if sending, others if receiving. */ int ifcmd(char **argv) { char *cp; if (cond != CANY) { printf("Illegal nested \"if\"\n"); return (1); } cond = CANY; cp = argv[0]; switch (*cp) { case 'r': case 'R': cond = CRCV; break; case 's': case 'S': cond = CSEND; break; default: printf("Unrecognized if-keyword: \"%s\"\n", cp); return (1); } return (0); } /* * Implement 'else'. This is pretty simple -- we just * flip over the conditional flag. */ int elsecmd(void) { switch (cond) { case CANY: printf("\"Else\" without matching \"if\"\n"); return (1); case CSEND: cond = CRCV; break; case CRCV: cond = CSEND; break; default: printf("Mail's idea of conditions is screwed up\n"); cond = CANY; break; } return (0); } /* * End of if statement. Just set cond back to anything. */ int endifcmd(void) { if (cond == CANY) { printf("\"Endif\" without matching \"if\"\n"); return (1); } cond = CANY; return (0); } /* * Set the list of alternate names. */ int alternates(char **namelist) { int c; char **ap, **ap2, *cp; c = argcount(namelist) + 1; if (c == 1) { if (altnames == 0) return (0); for (ap = altnames; *ap != NULL; ap++) printf("%s ", *ap); printf("\n"); return (0); } if (altnames != 0) (void)free(altnames); if ((altnames = calloc((unsigned)c, sizeof(char *))) == NULL) err(1, "Out of memory"); for (ap = namelist, ap2 = altnames; *ap != NULL; ap++, ap2++) { cp = calloc((unsigned)strlen(*ap) + 1, sizeof(char)); strcpy(cp, *ap); *ap2 = cp; } *ap2 = 0; return (0); } Index: stable/11/usr.bin/mail/edit.c =================================================================== --- stable/11/usr.bin/mail/edit.c (revision 335692) +++ stable/11/usr.bin/mail/edit.c (revision 335693) @@ -1,214 +1,214 @@ /* * 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. * 4. 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. */ #ifndef lint #if 0 static char sccsid[] = "@(#)edit.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include "rcv.h" #include #include "extern.h" /* * Mail -- a mail program * * Perform message editing functions. */ /* * Edit a message list. */ int editor(int *msgvec) { return (edit1(msgvec, 'e')); } /* * Invoke the visual editor on a message list. */ int visual(int *msgvec) { return (edit1(msgvec, 'v')); } /* * Edit a message by writing the message into a funnily-named file * (which should not exist) and forking an editor on it. * We get the editor from the stuff above. */ int edit1(int *msgvec, int type) { int c, i; FILE *fp; struct message *mp; off_t size; /* * Deal with each message to be edited . . . */ for (i = 0; i < msgCount && msgvec[i]; i++) { sig_t sigint; if (i > 0) { char buf[100]; char *p; printf("Edit message %d [ynq]? ", msgvec[i]); if (fgets(buf, sizeof(buf), stdin) == NULL) break; for (p = buf; *p == ' ' || *p == '\t'; p++) ; if (*p == 'q') break; if (*p == 'n') continue; } dot = mp = &message[msgvec[i] - 1]; touch(mp); sigint = signal(SIGINT, SIG_IGN); fp = run_editor(setinput(mp), mp->m_size, type, readonly); if (fp != NULL) { (void)fseeko(otf, (off_t)0, SEEK_END); size = ftello(otf); mp->m_block = blockof(size); mp->m_offset = boffsetof(size); mp->m_size = (long)fsize(fp); mp->m_lines = 0; mp->m_flag |= MODIFY; rewind(fp); while ((c = getc(fp)) != EOF) { if (c == '\n') mp->m_lines++; if (putc(c, otf) == EOF) break; } if (ferror(otf)) warnx("/tmp"); (void)Fclose(fp); } (void)signal(SIGINT, sigint); } return (0); } /* * Run an editor on the file at "fpp" of "size" bytes, * and return a new file pointer. * Signals must be handled by the caller. * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI. */ FILE * run_editor(FILE *fp, off_t size, int type, int readonly) { FILE *nf = NULL; int t; time_t modtime; char *edit, tempname[PATHSIZE]; struct stat statb; (void)snprintf(tempname, sizeof(tempname), "%s/mail.ReXXXXXXXXXX", tmpdir); if ((t = mkstemp(tempname)) == -1 || (nf = Fdopen(t, "w")) == NULL) { warn("%s", tempname); goto out; } if (readonly && fchmod(t, 0400) == -1) { warn("%s", tempname); (void)rm(tempname); goto out; } if (size >= 0) while (--size >= 0 && (t = getc(fp)) != EOF) (void)putc(t, nf); else while ((t = getc(fp)) != EOF) (void)putc(t, nf); (void)fflush(nf); if (fstat(fileno(nf), &statb) < 0) modtime = 0; else modtime = statb.st_mtime; if (ferror(nf)) { (void)Fclose(nf); warnx("%s", tempname); (void)rm(tempname); nf = NULL; goto out; } if (Fclose(nf) < 0) { warn("%s", tempname); (void)rm(tempname); nf = NULL; goto out; } nf = NULL; if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NULL) edit = type == 'e' ? _PATH_EX : _PATH_VI; - if (run_command(edit, 0, -1, -1, tempname, NULL, NULL) < 0) { + if (run_command(edit, 0, -1, -1, tempname, NULL) < 0) { (void)rm(tempname); goto out; } /* * If in read only mode or file unchanged, just remove the editor * temporary and return. */ if (readonly) { (void)rm(tempname); goto out; } if (stat(tempname, &statb) < 0) { warn("%s", tempname); goto out; } if (modtime == statb.st_mtime) { (void)rm(tempname); goto out; } /* * Now switch to new file. */ if ((nf = Fopen(tempname, "a+")) == NULL) { warn("%s", tempname); (void)rm(tempname); goto out; } (void)rm(tempname); out: return (nf); } Index: stable/11/usr.bin/mail/extern.h =================================================================== --- stable/11/usr.bin/mail/extern.h (revision 335692) +++ stable/11/usr.bin/mail/extern.h (revision 335693) @@ -1,252 +1,252 @@ /*- * Copyright (c) 1992, 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. * 4. 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. * * @(#)extern.h 8.2 (Berkeley) 4/20/95 * * $FreeBSD$ */ struct name *cat(struct name *, struct name *); struct name *delname(struct name *, char []); struct name *elide(struct name *); struct name *extract(char [], int); struct name *gexpand(struct name *, struct grouphead *, int, int); struct name *nalloc(char [], int); struct name *outof(struct name *, FILE *, struct header *); struct name *put(struct name *, struct name *); struct name *tailof(struct name *); struct name *usermap(struct name *); FILE *Fdopen(int, const char *); FILE *Fopen(const char *, const char *); FILE *Popen(char *, const char *); FILE *collect(struct header *, int); char *copyin(char *, char **); char *detract(struct name *, int); char *expand(char *); char *getdeadletter(void); -char *getname(int); +char *getname(uid_t); char *hfield(const char *, struct message *); FILE *infix(struct header *, FILE *); char *ishfield(char [], char *, const char *); char *name1(struct message *, int); char *nameof(struct message *, int); char *nextword(char *, char *); char *readtty(const char *, char []); char *reedit(char *); FILE *run_editor(FILE *, off_t, int, int); char *salloc(int); char *savestr(char *); FILE *setinput(struct message *); char *skin(char *); char *skip_comment(char *); char *snarf(char [], int *); char *username(void); char *value(const char *); char *vcopy(const char *); char *yankword(char *, char []); char *yanklogin(char *, char []); int Fclose(FILE *); int More(int *); int Pclose(FILE *); int Respond(int *); int Type(int *); int doRespond(int []); int dorespond(int *); void alter(char *); int alternates(char **); void announce(void); int append(struct message *, FILE *); int argcount(char **); void assign(const char *, const char *); int bangexp(char *, size_t); void brokpipe(int); int charcount(char *, int); int check(int, int); void clob1(int); int clobber(char **); void close_all_files(void); int cmatch(char *, char *); void collhup(int); void collint(int); void collstop(int); void commands(void); -int copycmd(char []); +int copycmd(void *v); int core(void); int count(struct name *); int delete(int []); int delm(int []); int deltype(int []); void demail(void); int diction(const void *, const void *); int dosh(char *); int echo(char **); int edit1(int *, int); int editor(int *); void edstop(void); int elsecmd(void); int endifcmd(void); int evalcol(int); int execute(char [], int); int exwrite(char [], FILE *, int); void fail(const char *, const char *); int file(char **); struct grouphead * findgroup(char []); void findmail(char *, char *, int); int first(int, int); void fixhead(struct header *, struct name *); void fmt(const char *, struct name *, FILE *, int); int folders(void); int forward(char [], FILE *, char *, int); void free_child(int); int from(int *); off_t fsize(FILE *); int getfold(char *, int); int gethfield(FILE *, char [], int, char **); int getmsglist(char *, int *, int); int getrawlist(char [], char **, int); -int getuserid(char []); +uid_t getuserid(char []); int grabh(struct header *, int); int group(char **); void hangup(int); int hash(const char *); void hdrstop(int); int headers(int *); int help(void); void holdsigs(void); int ifcmd(char **); int igcomp(const void *, const void *); int igfield(char *[]); int ignore1(char *[], struct ignoretab *, const char *); int igshow(struct ignoretab *, const char *); int inc(void *); int incfile(void); void intr(int); int isdate(char []); int isdir(char []); int isfileaddr(char *); int ishead(char []); int isign(const char *, struct ignoretab []); int isprefix(const char *, const char *); void istrncpy(char *, const char *, size_t); const struct cmd * lex(char []); void load(char *); struct var * lookup(const char *); int mail(struct name *, struct name *, struct name *, struct name *, char *, char *); void mail1(struct header *, int); void makemessage(FILE *, int); void mark(int); int markall(char [], int); int matchsender(char *, int); int matchfield(char *, int); int mboxit(int []); int member(char *, struct ignoretab *); void mesedit(FILE *, int); void mespipe(FILE *, char []); int messize(int *); int metamess(int, int); int more(int *); int newfileinfo(int); int next(int *); int null(int); void parse(char [], struct headline *, char []); int pcmdlist(void); int pdot(void); void prepare_child(sigset_t *, int, int); int preserve(int *); void prettyprint(struct name *); void printgroup(char []); void printhead(int); int puthead(struct header *, FILE *, int); int putline(FILE *, char *, int); int pversion(int); void quit(void); int quitcmd(void); int readline(FILE *, char *, int); void register_file(FILE *, int, int); void regret(int); void relsesigs(void); int respond(int *); int retfield(char *[]); int rexit(int); int rm(char *); -int run_command(char *, sigset_t *, int, int, char *, char *, char *); -int save(char []); +int run_command(char *, sigset_t *, int, int, ...); +int save(void *v); int save1(char [], int, const char *, struct ignoretab *); void savedeadletter(FILE *); int saveigfield(char *[]); int savemail(char [], FILE *); int saveretfield(char *[]); int scan(char **); void scaninit(void); int schdir(char **); int screensize(void); int scroll(char []); int sendmessage(struct message *, FILE *, struct ignoretab *, char *); int sendmail(char *); int set(char **); int setfile(char *); void setmsize(int); void setptr(FILE *, off_t); void setscreensize(void); int shell(char *); void sigchild(int); void sort(char **); int source(char **); void spreserve(void); void sreset(void); -int start_command(char *, sigset_t *, int, int, char *, char *, char *); +int start_command(char *, sigset_t *, int, int, ...); void statusput(struct message *, FILE *, char *); void stop(int); int stouch(int []); int swrite(char []); void tinit(void); int top(int *); void touch(struct message *); void ttyint(int); void ttystop(int); int type(int *); int type1(int *, int, int); int undelete_messages(int *); void unmark(int); char **unpack(struct name *); int unread(int []); void unregister_file(FILE *); int unset(char **); int unstack(void); void vfree(char *); int visual(int *); int wait_child(int); int wait_command(int); int writeback(FILE *); extern char *__progname; extern char *tmpdir; Index: stable/11/usr.bin/mail/fio.c =================================================================== --- stable/11/usr.bin/mail/fio.c (revision 335692) +++ stable/11/usr.bin/mail/fio.c (revision 335693) @@ -1,451 +1,451 @@ /* * 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. * 4. 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. */ #ifndef lint #if 0 static char sccsid[] = "@(#)fio.c 8.2 (Berkeley) 4/20/95"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include "rcv.h" #include #include #include #include #include #include "extern.h" /* * Mail -- a mail program * * File I/O. */ extern int wait_status; /* * Set up the input pointers while copying the mail file into /tmp. */ void setptr(FILE *ibuf, off_t offset) { int c, count; char *cp, *cp2; struct message this; FILE *mestmp; int maybe, inhead; char linebuf[LINESIZE], pathbuf[PATHSIZE]; int omsgCount; /* Get temporary file. */ (void)snprintf(pathbuf, sizeof(pathbuf), "%s/mail.XXXXXXXXXX", tmpdir); if ((c = mkstemp(pathbuf)) == -1 || (mestmp = Fdopen(c, "r+")) == NULL) err(1, "can't open %s", pathbuf); (void)rm(pathbuf); if (offset == 0) { msgCount = 0; } else { /* Seek into the file to get to the new messages */ (void)fseeko(ibuf, offset, SEEK_SET); /* * We need to make "offset" a pointer to the end of * the temp file that has the copy of the mail file. * If any messages have been edited, this will be * different from the offset into the mail file. */ (void)fseeko(otf, (off_t)0, SEEK_END); offset = ftello(otf); } omsgCount = msgCount; maybe = 1; inhead = 0; this.m_flag = MUSED|MNEW; this.m_size = 0; this.m_lines = 0; this.m_block = 0; this.m_offset = 0; for (;;) { if (fgets(linebuf, sizeof(linebuf), ibuf) == NULL) { if (append(&this, mestmp)) errx(1, "temporary file"); makemessage(mestmp, omsgCount); return; } count = strlen(linebuf); /* * Transforms lines ending in to just . * This allows mail to be able to read Eudora mailboxes. */ if (count >= 2 && linebuf[count - 1] == '\n' && linebuf[count - 2] == '\r') { count--; linebuf[count - 1] = '\n'; } (void)fwrite(linebuf, sizeof(*linebuf), count, otf); if (ferror(otf)) errx(1, "/tmp"); if (count) linebuf[count - 1] = '\0'; if (maybe && linebuf[0] == 'F' && ishead(linebuf)) { msgCount++; if (append(&this, mestmp)) errx(1, "temporary file"); this.m_flag = MUSED|MNEW; this.m_size = 0; this.m_lines = 0; this.m_block = blockof(offset); this.m_offset = boffsetof(offset); inhead = 1; } else if (linebuf[0] == 0) { inhead = 0; } else if (inhead) { for (cp = linebuf, cp2 = "status";; cp++) { if ((c = *cp2++) == '\0') { while (isspace((unsigned char)*cp++)) ; if (cp[-1] != ':') break; while ((c = *cp++) != '\0') if (c == 'R') this.m_flag |= MREAD; else if (c == 'O') this.m_flag &= ~MNEW; inhead = 0; break; } if (*cp != c && *cp != toupper((unsigned char)c)) break; } } offset += count; this.m_size += count; this.m_lines++; maybe = linebuf[0] == 0; } } /* * Drop the passed line onto the passed output buffer. * If a write error occurs, return -1, else the count of * characters written, including the newline if requested. */ int putline(FILE *obuf, char *linebuf, int outlf) { int c; c = strlen(linebuf); (void)fwrite(linebuf, sizeof(*linebuf), c, obuf); if (outlf) { fprintf(obuf, "\n"); c++; } if (ferror(obuf)) return (-1); return (c); } /* * Read up a line from the specified input into the line * buffer. Return the number of characters read. Do not * include the newline (or carriage return) at the end. */ int readline(FILE *ibuf, char *linebuf, int linesize) { int n; clearerr(ibuf); if (fgets(linebuf, linesize, ibuf) == NULL) return (-1); n = strlen(linebuf); if (n > 0 && linebuf[n - 1] == '\n') linebuf[--n] = '\0'; if (n > 0 && linebuf[n - 1] == '\r') linebuf[--n] = '\0'; return (n); } /* * Return a file buffer all ready to read up the * passed message pointer. */ FILE * setinput(struct message *mp) { (void)fflush(otf); if (fseeko(itf, positionof(mp->m_block, mp->m_offset), SEEK_SET) < 0) err(1, "fseeko"); return (itf); } /* * Take the data out of the passed ghost file and toss it into * a dynamically allocated message structure. */ void makemessage(FILE *f, int omsgCount) { size_t size; struct message *nmessage; size = (msgCount + 1) * sizeof(struct message); nmessage = (struct message *)realloc(message, size); if (nmessage == NULL) errx(1, "Insufficient memory for %d messages\n", msgCount); if (omsgCount == 0 || message == NULL) dot = nmessage; else dot = nmessage + (dot - message); message = nmessage; size -= (omsgCount + 1) * sizeof(struct message); (void)fflush(f); (void)lseek(fileno(f), (off_t)sizeof(*message), 0); - if (read(fileno(f), (char *)&message[omsgCount], size) != size) + if (read(fileno(f), (void *)&message[omsgCount], size) != size) errx(1, "Message temporary file corrupted"); message[msgCount].m_size = 0; message[msgCount].m_lines = 0; (void)Fclose(f); } /* * Append the passed message descriptor onto the temp file. * If the write fails, return 1, else 0 */ int append(struct message *mp, FILE *f) { return (fwrite((char *)mp, sizeof(*mp), 1, f) != 1); } /* * Delete a file, but only if the file is a plain file. */ int rm(char *name) { struct stat sb; if (stat(name, &sb) < 0) return (-1); if (!S_ISREG(sb.st_mode)) { errno = EISDIR; return (-1); } return (unlink(name)); } static int sigdepth; /* depth of holdsigs() */ static sigset_t nset, oset; /* * Hold signals SIGHUP, SIGINT, and SIGQUIT. */ 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. */ void relsesigs(void) { if (--sigdepth == 0) (void)sigprocmask(SIG_SETMASK, &oset, NULL); } /* * Determine the size of the file possessed by * the passed buffer. */ off_t fsize(FILE *iob) { struct stat sbuf; if (fstat(fileno(iob), &sbuf) < 0) return (0); return (sbuf.st_size); } /* * Evaluate the string given as a new mailbox name. * Supported meta characters: * % for my system mail box * %user for user's system mail box * # for previous file * & invoker's mbox file * +file file in folder directory * any shell meta character * Return the file name as a dynamic string. */ char * expand(char *name) { char xname[PATHSIZE]; char cmdbuf[PATHSIZE]; /* also used for file names */ int pid, l; char *cp, *sh; int pivec[2]; struct stat sbuf; /* * The order of evaluation is "%" and "#" expand into constants. * "&" can expand into "+". "+" can expand into shell meta characters. * Shell meta characters expand into constants. * This way, we make no recursive expansion. */ switch (*name) { case '%': findmail(name[1] ? name + 1 : myname, xname, sizeof(xname)); return (savestr(xname)); case '#': if (name[1] != 0) break; if (prevfile[0] == 0) { printf("No previous file\n"); return (NULL); } return (savestr(prevfile)); case '&': if (name[1] == 0 && (name = value("MBOX")) == NULL) name = "~/mbox"; /* fall through */ } if (name[0] == '+' && getfold(cmdbuf, sizeof(cmdbuf)) >= 0) { (void)snprintf(xname, sizeof(xname), "%s/%s", cmdbuf, name + 1); name = savestr(xname); } /* catch the most common shell meta character */ if (name[0] == '~' && homedir != NULL && (name[1] == '/' || name[1] == '\0')) { (void)snprintf(xname, sizeof(xname), "%s%s", homedir, name + 1); name = savestr(xname); } if (!strpbrk(name, "~{[*?$`'\"\\")) return (savestr(name)); if (pipe(pivec) < 0) { warn("pipe"); return (NULL); } (void)snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name); if ((sh = value("SHELL")) == NULL) sh = _PATH_CSHELL; pid = start_command(sh, 0, -1, pivec[1], "-c", cmdbuf, NULL); if (pid < 0) { (void)close(pivec[0]); (void)close(pivec[1]); return (NULL); } (void)close(pivec[1]); l = read(pivec[0], xname, BUFSIZ); (void)close(pivec[0]); if (wait_child(pid) < 0 && WIFSIGNALED(wait_status) && WTERMSIG(wait_status) != SIGPIPE) { fprintf(stderr, "\"%s\": Expansion failed.\n", name); return (NULL); } if (l < 0) { warn("read"); return (NULL); } if (l == 0) { fprintf(stderr, "\"%s\": No match.\n", name); return (NULL); } if (l == BUFSIZ) { fprintf(stderr, "\"%s\": Expansion buffer overflow.\n", name); return (NULL); } xname[l] = '\0'; for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) ; cp[1] = '\0'; if (strchr(xname, ' ') && stat(xname, &sbuf) < 0) { fprintf(stderr, "\"%s\": Ambiguous.\n", name); return (NULL); } return (savestr(xname)); } /* * Determine the current folder directory name. */ int getfold(char *name, int namelen) { char *folder; int copylen; if ((folder = value("folder")) == NULL) return (-1); if (*folder == '/') copylen = strlcpy(name, folder, namelen); else copylen = snprintf(name, namelen, "%s/%s", homedir ? homedir : ".", folder); return (copylen < 0 || copylen >= namelen ? (-1) : (0)); } /* * Return the name of the dead.letter file. */ char * getdeadletter(void) { char *cp; if ((cp = value("DEAD")) == NULL || (cp = expand(cp)) == NULL) cp = expand("~/dead.letter"); else if (*cp != '/') { char buf[PATHSIZE]; (void)snprintf(buf, sizeof(buf), "~/%s", cp); cp = expand(buf); } return (cp); } Index: stable/11/usr.bin/mail/getname.c =================================================================== --- stable/11/usr.bin/mail/getname.c (revision 335692) +++ stable/11/usr.bin/mail/getname.c (revision 335693) @@ -1,69 +1,69 @@ /* * 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. * 4. 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. */ #ifndef lint #if 0 static char sccsid[] = "@(#)getname.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include "rcv.h" #include #include "extern.h" /* Getname / getuserid for those with hashed passwd data base). */ /* * Search the passwd file for a uid. Return name on success, NULL on failure. */ char * -getname(int uid) +getname(uid_t uid) { struct passwd *pw; if ((pw = getpwuid(uid)) == NULL) return (NULL); return (pw->pw_name); } /* * Convert the passed name to a user id and return it. Return -1 * on error. */ -int +uid_t getuserid(char name[]) { struct passwd *pw; if ((pw = getpwnam(name)) == NULL) return (-1); return (pw->pw_uid); } Index: stable/11/usr.bin/mail/popen.c =================================================================== --- stable/11/usr.bin/mail/popen.c (revision 335692) +++ stable/11/usr.bin/mail/popen.c (revision 335693) @@ -1,373 +1,410 @@ /* * 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. * 4. 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. */ #ifndef lint #if 0 static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include "rcv.h" #include #include +#include +#include #include "extern.h" #define READ 0 #define WRITE 1 struct fp { FILE *fp; int pipe; - int pid; + pid_t pid; struct fp *link; }; static struct fp *fp_head; struct child { - int pid; + pid_t pid; char done; char free; int status; struct child *link; }; -static struct child *child; -static struct child *findchild(int); +static struct child *child, *child_freelist = NULL; + static void delchild(struct child *); -static int file_pid(FILE *); +static pid_t file_pid(FILE *); +static pid_t start_commandv(char *, sigset_t *, int, int, va_list); FILE * Fopen(const char *path, const char *mode) { FILE *fp; if ((fp = fopen(path, mode)) != NULL) { register_file(fp, 0, 0); (void)fcntl(fileno(fp), F_SETFD, 1); } return (fp); } FILE * Fdopen(int fd, const char *mode) { FILE *fp; if ((fp = fdopen(fd, mode)) != NULL) { register_file(fp, 0, 0); (void)fcntl(fileno(fp), F_SETFD, 1); } return (fp); } int Fclose(FILE *fp) { + unregister_file(fp); return (fclose(fp)); } FILE * Popen(char *cmd, const char *mode) { int p[2]; int myside, hisside, fd0, fd1; - int pid; + pid_t pid; sigset_t nset; FILE *fp; if (pipe(p) < 0) return (NULL); (void)fcntl(p[READ], F_SETFD, 1); (void)fcntl(p[WRITE], F_SETFD, 1); if (*mode == 'r') { myside = p[READ]; - fd0 = -1; - hisside = fd1 = p[WRITE]; + hisside = fd0 = fd1 = p[WRITE]; } else { myside = p[WRITE]; hisside = fd0 = p[READ]; fd1 = -1; } (void)sigemptyset(&nset); - if ((pid = start_command(cmd, &nset, fd0, fd1, NULL, NULL, NULL)) < 0) { + pid = start_command(value("SHELL"), &nset, fd0, fd1, "-c", cmd, NULL); + if (pid < 0) { (void)close(p[READ]); (void)close(p[WRITE]); return (NULL); } (void)close(hisside); if ((fp = fdopen(myside, mode)) != NULL) register_file(fp, 1, pid); return (fp); } int Pclose(FILE *ptr) { int i; sigset_t nset, oset; i = file_pid(ptr); unregister_file(ptr); (void)fclose(ptr); (void)sigemptyset(&nset); (void)sigaddset(&nset, SIGINT); (void)sigaddset(&nset, SIGHUP); (void)sigprocmask(SIG_BLOCK, &nset, &oset); i = wait_child(i); (void)sigprocmask(SIG_SETMASK, &oset, NULL); return (i); } void close_all_files(void) { while (fp_head != NULL) if (fp_head->pipe) (void)Pclose(fp_head->fp); else (void)Fclose(fp_head->fp); } void -register_file(FILE *fp, int pipe, int pid) +register_file(FILE *fp, int pipe, pid_t pid) { struct fp *fpp; if ((fpp = malloc(sizeof(*fpp))) == NULL) err(1, "Out of memory"); fpp->fp = fp; fpp->pipe = pipe; fpp->pid = pid; fpp->link = fp_head; fp_head = fpp; } void unregister_file(FILE *fp) { struct fp **pp, *p; for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link) if (p->fp == fp) { *pp = p->link; (void)free(p); return; } errx(1, "Invalid file pointer"); /*NOTREACHED*/ } -int +pid_t file_pid(FILE *fp) { struct fp *p; for (p = fp_head; p != NULL; p = p->link) if (p->fp == fp) return (p->pid); errx(1, "Invalid file pointer"); /*NOTREACHED*/ } /* * Run a command without a shell, with optional arguments and splicing - * of stdin and stdout. The command name can be a sequence of words. + * of stdin (-1 means none) and stdout. The command name can be a sequence + * of words. * Signals must be handled by the caller. - * "Mask" contains the signals to ignore in the new process. - * SIGINT is enabled unless it's in the mask. + * "nset" contains the signals to ignore in the new process. + * SIGINT is enabled unless it's in "nset". */ -/*VARARGS4*/ -int -run_command(char *cmd, sigset_t *mask, int infd, int outfd, char *a0, - char *a1, char *a2) +static pid_t +start_commandv(char *cmd, sigset_t *nset, int infd, int outfd, va_list args) { - int pid; + pid_t pid; - if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0) - return (-1); - return (wait_command(pid)); -} - -/*VARARGS4*/ -int -start_command(char *cmd, sigset_t *mask, int infd, int outfd, char *a0, - char *a1, char *a2) -{ - int pid; - if ((pid = fork()) < 0) { warn("fork"); return (-1); } if (pid == 0) { char *argv[100]; int i = getrawlist(cmd, argv, sizeof(argv) / sizeof(*argv)); - if ((argv[i++] = a0) != NULL && - (argv[i++] = a1) != NULL && - (argv[i++] = a2) != NULL) - argv[i] = NULL; - prepare_child(mask, infd, outfd); + while ((argv[i++] = va_arg(args, char *))) + ; + argv[i] = NULL; + prepare_child(nset, infd, outfd); execvp(argv[0], argv); warn("%s", argv[0]); _exit(1); } return (pid); } +int +run_command(char *cmd, sigset_t *nset, int infd, int outfd, ...) +{ + pid_t pid; + va_list args; + + va_start(args, outfd); + pid = start_commandv(cmd, nset, infd, outfd, args); + va_end(args); + if (pid < 0) + return -1; + return wait_command(pid); +} + +int +start_command(char *cmd, sigset_t *nset, int infd, int outfd, ...) +{ + va_list args; + int r; + + va_start(args, outfd); + r = start_commandv(cmd, nset, infd, outfd, args); + va_end(args); + return r; +} + void prepare_child(sigset_t *nset, int infd, int outfd) { int i; sigset_t eset; /* * All file descriptors other than 0, 1, and 2 are supposed to be * close-on-exec. */ if (infd >= 0) dup2(infd, 0); if (outfd >= 0) dup2(outfd, 1); for (i = 1; i < NSIG; i++) if (nset != NULL && sigismember(nset, i)) (void)signal(i, SIG_IGN); if (nset == NULL || !sigismember(nset, SIGINT)) (void)signal(SIGINT, SIG_DFL); (void)sigemptyset(&eset); (void)sigprocmask(SIG_SETMASK, &eset, NULL); } int -wait_command(int pid) +wait_command(pid_t pid) { if (wait_child(pid) < 0) { printf("Fatal error in process.\n"); return (-1); } return (0); } static struct child * -findchild(int pid) +findchild(pid_t pid, int dont_alloc) { struct child **cpp; for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; cpp = &(*cpp)->link) ; if (*cpp == NULL) { - *cpp = malloc(sizeof(struct child)); - if (*cpp == NULL) - err(1, "Out of memory"); + if (dont_alloc) + return(NULL); + if (child_freelist) { + *cpp = child_freelist; + child_freelist = (*cpp)->link; + } else { + *cpp = malloc(sizeof(struct child)); + if (*cpp == NULL) + err(1, "malloc"); + } (*cpp)->pid = pid; (*cpp)->done = (*cpp)->free = 0; (*cpp)->link = NULL; } return (*cpp); } static void delchild(struct child *cp) { struct child **cpp; for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) ; *cpp = cp->link; - (void)free(cp); + cp->link = child_freelist; + child_freelist = cp; } /*ARGSUSED*/ void sigchild(int signo __unused) { - int pid; + pid_t pid; int status; struct child *cp; + int save_errno; + save_errno = errno; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { - cp = findchild(pid); + cp = findchild(pid, 1); if (cp->free) delchild(cp); else { cp->done = 1; cp->status = status; } } + errno = save_errno; } int wait_status; /* * Wait for a specific child to die. */ int -wait_child(int pid) +wait_child(pid_t pid) { - sigset_t nset, oset; struct child *cp; + sigset_t nset, oset; + pid_t rv = 0; (void)sigemptyset(&nset); (void)sigaddset(&nset, SIGCHLD); - (void)sigprocmask(SIG_BLOCK, &nset, &oset); - - cp = findchild(pid); - - while (!cp->done) - (void)sigsuspend(&oset); - wait_status = cp->status; - delchild(cp); + (void)sigprocmask(SIG_BLOCK, &nset, &oset); + /* + * If we have not already waited on the pid (via sigchild) + * wait on it now. Otherwise, use the wait status stashed + * by sigchild. + */ + cp = findchild(pid, 1); + if (cp == NULL || !cp->done) + rv = waitpid(pid, &wait_status, 0); + else + wait_status = cp->status; + if (cp != NULL) + delchild(cp); (void)sigprocmask(SIG_SETMASK, &oset, NULL); - return ((WIFEXITED(wait_status) && WEXITSTATUS(wait_status)) ? -1 : 0); + if (rv == -1 || (WIFEXITED(wait_status) && WEXITSTATUS(wait_status))) + return -1; + else + return 0; } /* * Mark a child as don't care. */ void -free_child(int pid) +free_child(pid_t pid) { + struct child *cp; sigset_t nset, oset; - struct child *cp = findchild(pid); (void)sigemptyset(&nset); (void)sigaddset(&nset, SIGCHLD); - (void)sigprocmask(SIG_BLOCK, &nset, &oset); - - if (cp->done) - delchild(cp); - else - cp->free = 1; + (void)sigprocmask(SIG_BLOCK, &nset, &oset); + if ((cp = findchild(pid, 0)) != NULL) { + if (cp->done) + delchild(cp); + else + cp->free = 1; + } (void)sigprocmask(SIG_SETMASK, &oset, NULL); }