xref: /freebsd/contrib/sendmail/rmail/rmail.c (revision 829be59c37be72a88c37d79c285ff8470d4444e2)
1c2aa98e2SPeter Wemm /*
2c2aa98e2SPeter Wemm  * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
4c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
5c2aa98e2SPeter Wemm  *
6c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
7c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
8c2aa98e2SPeter Wemm  * the sendmail distribution.
9c2aa98e2SPeter Wemm  *
10c2aa98e2SPeter Wemm  */
11c2aa98e2SPeter Wemm 
12c2aa98e2SPeter Wemm #ifndef lint
13c2aa98e2SPeter Wemm static char copyright[] =
14c2aa98e2SPeter Wemm "@(#) Copyright (c) 1988, 1993\n\
15c2aa98e2SPeter Wemm 	The Regents of the University of California.  All rights reserved.\n";
16c2aa98e2SPeter Wemm #endif /* not lint */
17c2aa98e2SPeter Wemm 
18c2aa98e2SPeter Wemm #ifndef lint
19c2aa98e2SPeter Wemm static char sccsid[] = "@(#)rmail.c	8.17 (Berkeley) 5/19/98";
20c2aa98e2SPeter Wemm #endif /* not lint */
21c2aa98e2SPeter Wemm 
22c2aa98e2SPeter Wemm /*
23c2aa98e2SPeter Wemm  * RMAIL -- UUCP mail server.
24c2aa98e2SPeter Wemm  *
25c2aa98e2SPeter Wemm  * This program reads the >From ... remote from ... lines that UUCP is so
26c2aa98e2SPeter Wemm  * fond of and turns them into something reasonable.  It then execs sendmail
27c2aa98e2SPeter Wemm  * with various options built from these lines.
28c2aa98e2SPeter Wemm  *
29c2aa98e2SPeter Wemm  * The expected syntax is:
30c2aa98e2SPeter Wemm  *
31c2aa98e2SPeter Wemm  *	 <user> := [-a-z0-9]+
32c2aa98e2SPeter Wemm  *	 <date> := ctime format
33c2aa98e2SPeter Wemm  *	 <site> := [-a-z0-9!]+
34c2aa98e2SPeter Wemm  * <blank line> := "^\n$"
35c2aa98e2SPeter Wemm  *	 <from> := "From" <space> <user> <space> <date>
36c2aa98e2SPeter Wemm  *		  [<space> "remote from" <space> <site>]
37c2aa98e2SPeter Wemm  *    <forward> := ">" <from>
38c2aa98e2SPeter Wemm  *	    msg := <from> <forward>* <blank-line> <body>
39c2aa98e2SPeter Wemm  *
40c2aa98e2SPeter Wemm  * The output of rmail(8) compresses the <forward> lines into a single
41c2aa98e2SPeter Wemm  * from path.
42c2aa98e2SPeter Wemm  *
43c2aa98e2SPeter Wemm  * The err(3) routine is included here deliberately to make this code
44c2aa98e2SPeter Wemm  * a bit more portable.
45c2aa98e2SPeter Wemm  */
46c2aa98e2SPeter Wemm #include <sys/param.h>
47c2aa98e2SPeter Wemm #include <sys/stat.h>
48c2aa98e2SPeter Wemm #include <sys/wait.h>
49c2aa98e2SPeter Wemm 
50c2aa98e2SPeter Wemm #include <ctype.h>
51c2aa98e2SPeter Wemm #include <fcntl.h>
52c2aa98e2SPeter Wemm #ifdef BSD4_4
53c2aa98e2SPeter Wemm # define FORK vfork
54c2aa98e2SPeter Wemm # include <paths.h>
55c2aa98e2SPeter Wemm #else
56c2aa98e2SPeter Wemm # define FORK fork
57c2aa98e2SPeter Wemm # ifndef _PATH_SENDMAIL
58c2aa98e2SPeter Wemm #  define _PATH_SENDMAIL "/usr/lib/sendmail"
59c2aa98e2SPeter Wemm # endif
60c2aa98e2SPeter Wemm #endif
61c2aa98e2SPeter Wemm #include <stdio.h>
62c2aa98e2SPeter Wemm #include <stdlib.h>
63c2aa98e2SPeter Wemm #include <string.h>
64c2aa98e2SPeter Wemm #include <unistd.h>
65c2aa98e2SPeter Wemm #ifdef EX_OK
66c2aa98e2SPeter Wemm # undef EX_OK		/* unistd.h may have another use for this */
67c2aa98e2SPeter Wemm #endif
68c2aa98e2SPeter Wemm #include <sysexits.h>
69c2aa98e2SPeter Wemm 
70c2aa98e2SPeter Wemm #ifndef MAX
71c2aa98e2SPeter Wemm # define MAX(a, b)	((a) < (b) ? (b) : (a))
72c2aa98e2SPeter Wemm #endif
73c2aa98e2SPeter Wemm 
74c2aa98e2SPeter Wemm #ifndef __P
75c2aa98e2SPeter Wemm # ifdef __STDC__
76c2aa98e2SPeter Wemm #  define __P(protos)	protos
77c2aa98e2SPeter Wemm # else
78c2aa98e2SPeter Wemm #  define __P(protos)	()
79c2aa98e2SPeter Wemm #  define const
80c2aa98e2SPeter Wemm # endif
81c2aa98e2SPeter Wemm #endif
82c2aa98e2SPeter Wemm 
83c2aa98e2SPeter Wemm #if defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206)
84c2aa98e2SPeter Wemm # define HASSNPRINTF	1
85c2aa98e2SPeter Wemm #endif
86c2aa98e2SPeter Wemm 
87c2aa98e2SPeter Wemm #if defined(IRIX64) || defined(IRIX5) || defined(IRIX6) || \
88c2aa98e2SPeter Wemm     defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__)
89c2aa98e2SPeter Wemm # ifndef HASSTRERROR
90c2aa98e2SPeter Wemm #  define HASSTRERROR	1	/* has strerror(3) */
91c2aa98e2SPeter Wemm # endif
92c2aa98e2SPeter Wemm #endif
93c2aa98e2SPeter Wemm 
94c2aa98e2SPeter Wemm #if !HASSTRERROR
95c2aa98e2SPeter Wemm extern char	*strerror __P((int));
96c2aa98e2SPeter Wemm #endif
97c2aa98e2SPeter Wemm 
98c2aa98e2SPeter Wemm #if defined(sun) && !defined(BSD) && !defined(SOLARIS) && !defined(__svr4__) && !defined(__SVR4)
99c2aa98e2SPeter Wemm #  define memmove(d, s, l)	(bcopy((s), (d), (l)))
100c2aa98e2SPeter Wemm #endif
101c2aa98e2SPeter Wemm 
102c2aa98e2SPeter Wemm #if !HASSNPRINTF
103c2aa98e2SPeter Wemm extern int	snprintf __P((char *, size_t, const char *, ...));
104c2aa98e2SPeter Wemm #endif /* !HASSNPRINTF */
105c2aa98e2SPeter Wemm 
106c2aa98e2SPeter Wemm u_char	tTdvect[100];
107c2aa98e2SPeter Wemm 
108c2aa98e2SPeter Wemm void err __P((int, const char *, ...));
109c2aa98e2SPeter Wemm void usage __P((void));
110c2aa98e2SPeter Wemm char *xalloc __P((int));
111c2aa98e2SPeter Wemm 
112c2aa98e2SPeter Wemm #define newstr(s)	strcpy(xalloc(strlen(s) + 1), s)
113c2aa98e2SPeter Wemm 
114c2aa98e2SPeter Wemm char *
115c2aa98e2SPeter Wemm xalloc(sz)
116c2aa98e2SPeter Wemm 	register int sz;
117c2aa98e2SPeter Wemm {
118c2aa98e2SPeter Wemm 	register char *p;
119c2aa98e2SPeter Wemm 
120c2aa98e2SPeter Wemm 	/* some systems can't handle size zero mallocs */
121c2aa98e2SPeter Wemm 	if (sz <= 0)
122c2aa98e2SPeter Wemm 		sz = 1;
123c2aa98e2SPeter Wemm 
124c2aa98e2SPeter Wemm 	p = malloc((unsigned) sz);
125c2aa98e2SPeter Wemm 	if (p == NULL)
126c2aa98e2SPeter Wemm 		err(EX_TEMPFAIL, "out of memory");
127c2aa98e2SPeter Wemm 	return (p);
128c2aa98e2SPeter Wemm }
129c2aa98e2SPeter Wemm 
130c2aa98e2SPeter Wemm int
131c2aa98e2SPeter Wemm main(argc, argv)
132c2aa98e2SPeter Wemm 	int argc;
133c2aa98e2SPeter Wemm 	char *argv[];
134c2aa98e2SPeter Wemm {
135c2aa98e2SPeter Wemm 	extern char *optarg;
136c2aa98e2SPeter Wemm 	extern int errno, optind;
137c2aa98e2SPeter Wemm 	FILE *fp;
138c2aa98e2SPeter Wemm 	struct stat sb;
139c2aa98e2SPeter Wemm 	size_t fplen, fptlen, len;
140c2aa98e2SPeter Wemm 	off_t offset;
141c2aa98e2SPeter Wemm 	int ch, debug, i, pdes[2], pid, status;
142c2aa98e2SPeter Wemm 	char *addrp, *domain, *p, *t;
143c2aa98e2SPeter Wemm 	char *from_path, *from_sys, *from_user;
144c2aa98e2SPeter Wemm 	char *args[100], buf[2048], lbuf[2048];
145c2aa98e2SPeter Wemm 
146c2aa98e2SPeter Wemm 	debug = 0;
147c2aa98e2SPeter Wemm 	domain = "UUCP";		/* Default "domain". */
148b2ee1660SPeter Wemm 	while ((ch = getopt(argc, argv, "D:T")) != -1)
149c2aa98e2SPeter Wemm 		switch (ch) {
150c2aa98e2SPeter Wemm 		case 'T':
151c2aa98e2SPeter Wemm 			debug = 1;
152c2aa98e2SPeter Wemm 			break;
153c2aa98e2SPeter Wemm 		case 'D':
154c2aa98e2SPeter Wemm 			domain = optarg;
155c2aa98e2SPeter Wemm 			break;
156c2aa98e2SPeter Wemm 		case '?':
157c2aa98e2SPeter Wemm 		default:
158c2aa98e2SPeter Wemm 			usage();
159c2aa98e2SPeter Wemm 		}
160c2aa98e2SPeter Wemm 	argc -= optind;
161c2aa98e2SPeter Wemm 	argv += optind;
162c2aa98e2SPeter Wemm 
163c2aa98e2SPeter Wemm 	if (argc < 1)
164c2aa98e2SPeter Wemm 		usage();
165c2aa98e2SPeter Wemm 
166829be59cSPeter Wemm 	fplen = fptlen = 0;
167829be59cSPeter Wemm 	addrp = "";
168c2aa98e2SPeter Wemm 	from_path = from_sys = from_user = NULL;
169c2aa98e2SPeter Wemm 	for (offset = 0;;) {
170c2aa98e2SPeter Wemm 
171c2aa98e2SPeter Wemm 		/* Get and nul-terminate the line. */
172c2aa98e2SPeter Wemm 		if (fgets(lbuf, sizeof(lbuf), stdin) == NULL)
173c2aa98e2SPeter Wemm 			exit (EX_DATAERR);
174c2aa98e2SPeter Wemm 		if ((p = strchr(lbuf, '\n')) == NULL)
175c2aa98e2SPeter Wemm 			err(EX_DATAERR, "line too long");
176c2aa98e2SPeter Wemm 		*p = '\0';
177c2aa98e2SPeter Wemm 
178c2aa98e2SPeter Wemm 		/* Parse lines until reach a non-"From" line. */
179c2aa98e2SPeter Wemm 		if (!strncmp(lbuf, "From ", 5))
180c2aa98e2SPeter Wemm 			addrp = lbuf + 5;
181c2aa98e2SPeter Wemm 		else if (!strncmp(lbuf, ">From ", 6))
182c2aa98e2SPeter Wemm 			addrp = lbuf + 6;
183c2aa98e2SPeter Wemm 		else if (offset == 0)
184c2aa98e2SPeter Wemm 			err(EX_DATAERR,
185c2aa98e2SPeter Wemm 			    "missing or empty From line: %s", lbuf);
186c2aa98e2SPeter Wemm 		else {
187c2aa98e2SPeter Wemm 			*p = '\n';
188c2aa98e2SPeter Wemm 			break;
189c2aa98e2SPeter Wemm 		}
190c2aa98e2SPeter Wemm 
191c2aa98e2SPeter Wemm 		if (*addrp == '\0')
192c2aa98e2SPeter Wemm 			err(EX_DATAERR, "corrupted From line: %s", lbuf);
193c2aa98e2SPeter Wemm 
194c2aa98e2SPeter Wemm 		/* Use the "remote from" if it exists. */
195c2aa98e2SPeter Wemm 		for (p = addrp; (p = strchr(p + 1, 'r')) != NULL;)
196c2aa98e2SPeter Wemm 			if (!strncmp(p, "remote from ", 12)) {
197c2aa98e2SPeter Wemm 				for (t = p += 12;
198c2aa98e2SPeter Wemm 				     *t && !(isascii(*t) && isspace(*t)); ++t);
199c2aa98e2SPeter Wemm 				*t = '\0';
200c2aa98e2SPeter Wemm 				if (debug)
201c2aa98e2SPeter Wemm 					(void)fprintf(stderr,
202c2aa98e2SPeter Wemm 					    "remote from: %s\n", p);
203c2aa98e2SPeter Wemm 				break;
204c2aa98e2SPeter Wemm 			}
205c2aa98e2SPeter Wemm 
206c2aa98e2SPeter Wemm 		/* Else use the string up to the last bang. */
207c2aa98e2SPeter Wemm 		if (p == NULL) {
208c2aa98e2SPeter Wemm 			if (*addrp == '!')
209c2aa98e2SPeter Wemm 				err(EX_DATAERR,
210c2aa98e2SPeter Wemm 				    "bang starts address: %s", addrp);
211c2aa98e2SPeter Wemm 			else if ((t = strrchr(addrp, '!')) != NULL) {
212c2aa98e2SPeter Wemm 				*t = '\0';
213c2aa98e2SPeter Wemm 				p = addrp;
214c2aa98e2SPeter Wemm 				addrp = t + 1;
215c2aa98e2SPeter Wemm 				if (*addrp == '\0')
216c2aa98e2SPeter Wemm 					err(EX_DATAERR,
217c2aa98e2SPeter Wemm 					    "corrupted From line: %s", lbuf);
218c2aa98e2SPeter Wemm 				if (debug)
219c2aa98e2SPeter Wemm 					(void)fprintf(stderr, "bang: %s\n", p);
220c2aa98e2SPeter Wemm 			}
221c2aa98e2SPeter Wemm 		}
222c2aa98e2SPeter Wemm 		/* 'p' now points to any system string from this line. */
223c2aa98e2SPeter Wemm 		if (p != NULL) {
224c2aa98e2SPeter Wemm 			/* Nul terminate it as necessary. */
225c2aa98e2SPeter Wemm 			for (t = p; *t && !(isascii(*t) && isspace(*t)); ++t);
226c2aa98e2SPeter Wemm 			*t = '\0';
227c2aa98e2SPeter Wemm 
228c2aa98e2SPeter Wemm 			/* If the first system, copy to the from_sys string. */
229c2aa98e2SPeter Wemm 			if (from_sys == NULL) {
230c2aa98e2SPeter Wemm 				from_sys = newstr(p);
231c2aa98e2SPeter Wemm 				if (debug)
232c2aa98e2SPeter Wemm 					(void)fprintf(stderr,
233c2aa98e2SPeter Wemm 					    "from_sys: %s\n", from_sys);
234c2aa98e2SPeter Wemm 			}
235c2aa98e2SPeter Wemm 
236c2aa98e2SPeter Wemm 			/* Concatenate to the path string. */
237c2aa98e2SPeter Wemm 			len = t - p;
238c2aa98e2SPeter Wemm 			if (from_path == NULL) {
239c2aa98e2SPeter Wemm 				fplen = 0;
240c2aa98e2SPeter Wemm 				if ((from_path = malloc(fptlen = 256)) == NULL)
241c2aa98e2SPeter Wemm 					err(EX_TEMPFAIL, NULL);
242c2aa98e2SPeter Wemm 			}
243c2aa98e2SPeter Wemm 			if (fplen + len + 2 > fptlen) {
244c2aa98e2SPeter Wemm 				fptlen += MAX(fplen + len + 2, 256);
245c2aa98e2SPeter Wemm 				if ((from_path =
246c2aa98e2SPeter Wemm 				    realloc(from_path, fptlen)) == NULL)
247c2aa98e2SPeter Wemm 					err(EX_TEMPFAIL, NULL);
248c2aa98e2SPeter Wemm 			}
249c2aa98e2SPeter Wemm 			memmove(from_path + fplen, p, len);
250c2aa98e2SPeter Wemm 			fplen += len;
251c2aa98e2SPeter Wemm 			from_path[fplen++] = '!';
252c2aa98e2SPeter Wemm 			from_path[fplen] = '\0';
253c2aa98e2SPeter Wemm 		}
254c2aa98e2SPeter Wemm 
255c2aa98e2SPeter Wemm 		/* Save off from user's address; the last one wins. */
256c2aa98e2SPeter Wemm 		for (p = addrp; *p && !(isascii(*p) && isspace(*p)); ++p);
257c2aa98e2SPeter Wemm 		*p = '\0';
258c2aa98e2SPeter Wemm 		if (*addrp == '\0')
259c2aa98e2SPeter Wemm 			addrp = "<>";
260c2aa98e2SPeter Wemm 		if (from_user != NULL)
261c2aa98e2SPeter Wemm 			free(from_user);
262c2aa98e2SPeter Wemm 		from_user = newstr(addrp);
263c2aa98e2SPeter Wemm 
264c2aa98e2SPeter Wemm 		if (debug) {
265c2aa98e2SPeter Wemm 			if (from_path != NULL)
266c2aa98e2SPeter Wemm 				(void)fprintf(stderr,
267c2aa98e2SPeter Wemm 				    "from_path: %s\n", from_path);
268c2aa98e2SPeter Wemm 			(void)fprintf(stderr, "from_user: %s\n", from_user);
269c2aa98e2SPeter Wemm 		}
270c2aa98e2SPeter Wemm 
271c2aa98e2SPeter Wemm 		if (offset != -1)
272c2aa98e2SPeter Wemm 			offset = (off_t)ftell(stdin);
273c2aa98e2SPeter Wemm 	}
274c2aa98e2SPeter Wemm 
275c2aa98e2SPeter Wemm 	i = 0;
276c2aa98e2SPeter Wemm 	args[i++] = _PATH_SENDMAIL;	/* Build sendmail's argument list. */
277c2aa98e2SPeter Wemm 	args[i++] = "-oee";		/* No errors, just status. */
278829be59cSPeter Wemm #ifdef QUEUE_ONLY
279c2aa98e2SPeter Wemm 	args[i++] = "-odq";		/* Queue it, don't try to deliver. */
280829be59cSPeter Wemm #else
281829be59cSPeter Wemm 	args[i++] = "-odi";		/* Deliver in foreground. */
282829be59cSPeter Wemm #endif
283c2aa98e2SPeter Wemm 	args[i++] = "-oi";		/* Ignore '.' on a line by itself. */
284c2aa98e2SPeter Wemm 
285c2aa98e2SPeter Wemm 	/* set from system and protocol used */
286c2aa98e2SPeter Wemm 	if (from_sys == NULL)
287c2aa98e2SPeter Wemm 		(void)snprintf(buf, sizeof(buf), "-p%s", domain);
288c2aa98e2SPeter Wemm 	else if (strchr(from_sys, '.') == NULL)
289c2aa98e2SPeter Wemm 		(void)snprintf(buf, sizeof(buf), "-p%s:%s.%s",
290c2aa98e2SPeter Wemm 			domain, from_sys, domain);
291c2aa98e2SPeter Wemm 	else
292c2aa98e2SPeter Wemm 		(void)snprintf(buf, sizeof(buf), "-p%s:%s", domain, from_sys);
293c2aa98e2SPeter Wemm 	args[i++] = newstr(buf);
294c2aa98e2SPeter Wemm 
295c2aa98e2SPeter Wemm 					/* Set name of ``from'' person. */
296c2aa98e2SPeter Wemm 	(void)snprintf(buf, sizeof(buf), "-f%s%s",
297c2aa98e2SPeter Wemm 	    from_path ? from_path : "", from_user);
298c2aa98e2SPeter Wemm 	args[i++] = newstr(buf);
299c2aa98e2SPeter Wemm 
300c2aa98e2SPeter Wemm 	/*
301c2aa98e2SPeter Wemm 	 * Don't copy arguments beginning with - as they will be
302c2aa98e2SPeter Wemm 	 * passed to sendmail and could be interpreted as flags.
303c2aa98e2SPeter Wemm 	 * To prevent confusion of sendmail wrap < and > around
304c2aa98e2SPeter Wemm 	 * the address (helps to pass addrs like @gw1,@gw2:aa@bb)
305c2aa98e2SPeter Wemm 	 */
306c2aa98e2SPeter Wemm 	while (*argv) {
307c2aa98e2SPeter Wemm 		if (**argv == '-')
308c2aa98e2SPeter Wemm 			err(EX_USAGE, "dash precedes argument: %s", *argv);
309c2aa98e2SPeter Wemm 		if (strchr(*argv, ',') == NULL || strchr(*argv, '<') != NULL)
310c2aa98e2SPeter Wemm 			args[i++] = *argv;
311c2aa98e2SPeter Wemm 		else {
312c2aa98e2SPeter Wemm 			if ((args[i] = malloc(strlen(*argv) + 3)) == NULL)
313c2aa98e2SPeter Wemm 				err(EX_TEMPFAIL, "Cannot malloc");
314c2aa98e2SPeter Wemm 			sprintf (args [i++], "<%s>", *argv);
315c2aa98e2SPeter Wemm 		}
316c2aa98e2SPeter Wemm 		argv++;
317c2aa98e2SPeter Wemm 	}
318c2aa98e2SPeter Wemm 	args[i] = 0;
319c2aa98e2SPeter Wemm 
320c2aa98e2SPeter Wemm 	if (debug) {
321c2aa98e2SPeter Wemm 		(void)fprintf(stderr, "Sendmail arguments:\n");
322c2aa98e2SPeter Wemm 		for (i = 0; args[i]; i++)
323c2aa98e2SPeter Wemm 			(void)fprintf(stderr, "\t%s\n", args[i]);
324c2aa98e2SPeter Wemm 	}
325c2aa98e2SPeter Wemm 
326c2aa98e2SPeter Wemm 	/*
327c2aa98e2SPeter Wemm 	 * If called with a regular file as standard input, seek to the right
328c2aa98e2SPeter Wemm 	 * position in the file and just exec sendmail.  Could probably skip
329c2aa98e2SPeter Wemm 	 * skip the stat, but it's not unreasonable to believe that a failed
330c2aa98e2SPeter Wemm 	 * seek will cause future reads to fail.
331c2aa98e2SPeter Wemm 	 */
332c2aa98e2SPeter Wemm 	if (!fstat(STDIN_FILENO, &sb) && S_ISREG(sb.st_mode)) {
333c2aa98e2SPeter Wemm 		if (lseek(STDIN_FILENO, offset, SEEK_SET) != offset)
334c2aa98e2SPeter Wemm 			err(EX_TEMPFAIL, "stdin seek");
335c2aa98e2SPeter Wemm 		execv(_PATH_SENDMAIL, args);
336c2aa98e2SPeter Wemm 		err(EX_OSERR, "%s", _PATH_SENDMAIL);
337c2aa98e2SPeter Wemm 	}
338c2aa98e2SPeter Wemm 
339c2aa98e2SPeter Wemm 	if (pipe(pdes) < 0)
340c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
341c2aa98e2SPeter Wemm 
342c2aa98e2SPeter Wemm 	switch (pid = FORK()) {
343c2aa98e2SPeter Wemm 	case -1:				/* Err. */
344c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
345c2aa98e2SPeter Wemm 	case 0:					/* Child. */
346c2aa98e2SPeter Wemm 		if (pdes[0] != STDIN_FILENO) {
347c2aa98e2SPeter Wemm 			(void)dup2(pdes[0], STDIN_FILENO);
348c2aa98e2SPeter Wemm 			(void)close(pdes[0]);
349c2aa98e2SPeter Wemm 		}
350c2aa98e2SPeter Wemm 		(void)close(pdes[1]);
351c2aa98e2SPeter Wemm 		execv(_PATH_SENDMAIL, args);
352c2aa98e2SPeter Wemm 		_exit(127);
353c2aa98e2SPeter Wemm 		/* NOTREACHED */
354c2aa98e2SPeter Wemm 	}
355c2aa98e2SPeter Wemm 
356c2aa98e2SPeter Wemm 	if ((fp = fdopen(pdes[1], "w")) == NULL)
357c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
358c2aa98e2SPeter Wemm 	(void)close(pdes[0]);
359c2aa98e2SPeter Wemm 
360c2aa98e2SPeter Wemm 	/* Copy the file down the pipe. */
361c2aa98e2SPeter Wemm 	do {
362c2aa98e2SPeter Wemm 		(void)fprintf(fp, "%s", lbuf);
363c2aa98e2SPeter Wemm 	} while (fgets(lbuf, sizeof(lbuf), stdin) != NULL);
364c2aa98e2SPeter Wemm 
365c2aa98e2SPeter Wemm 	if (ferror(stdin))
366c2aa98e2SPeter Wemm 		err(EX_TEMPFAIL, "stdin: %s", strerror(errno));
367c2aa98e2SPeter Wemm 
368c2aa98e2SPeter Wemm 	if (fclose(fp))
369c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
370c2aa98e2SPeter Wemm 
371c2aa98e2SPeter Wemm 	if ((waitpid(pid, &status, 0)) == -1)
372c2aa98e2SPeter Wemm 		err(EX_OSERR, "%s", _PATH_SENDMAIL);
373c2aa98e2SPeter Wemm 
374c2aa98e2SPeter Wemm 	if (!WIFEXITED(status))
375c2aa98e2SPeter Wemm 		err(EX_OSERR,
376c2aa98e2SPeter Wemm 		    "%s: did not terminate normally", _PATH_SENDMAIL);
377c2aa98e2SPeter Wemm 
378c2aa98e2SPeter Wemm 	if (WEXITSTATUS(status))
379c2aa98e2SPeter Wemm 		err(status, "%s: terminated with %d (non-zero) status",
380c2aa98e2SPeter Wemm 		    _PATH_SENDMAIL, WEXITSTATUS(status));
381c2aa98e2SPeter Wemm 	exit(EX_OK);
382c2aa98e2SPeter Wemm }
383c2aa98e2SPeter Wemm 
384c2aa98e2SPeter Wemm void
385c2aa98e2SPeter Wemm usage()
386c2aa98e2SPeter Wemm {
387c2aa98e2SPeter Wemm 	(void)fprintf(stderr, "usage: rmail [-T] [-D domain] user ...\n");
388c2aa98e2SPeter Wemm 	exit(EX_USAGE);
389c2aa98e2SPeter Wemm }
390c2aa98e2SPeter Wemm 
391c2aa98e2SPeter Wemm #ifdef __STDC__
392c2aa98e2SPeter Wemm #include <stdarg.h>
393c2aa98e2SPeter Wemm #else
394c2aa98e2SPeter Wemm #include <varargs.h>
395c2aa98e2SPeter Wemm #endif
396c2aa98e2SPeter Wemm 
397c2aa98e2SPeter Wemm void
398c2aa98e2SPeter Wemm #ifdef __STDC__
399c2aa98e2SPeter Wemm err(int eval, const char *fmt, ...)
400c2aa98e2SPeter Wemm #else
401c2aa98e2SPeter Wemm err(eval, fmt, va_alist)
402c2aa98e2SPeter Wemm 	int eval;
403c2aa98e2SPeter Wemm 	const char *fmt;
404c2aa98e2SPeter Wemm 	va_dcl
405c2aa98e2SPeter Wemm #endif
406c2aa98e2SPeter Wemm {
407c2aa98e2SPeter Wemm 	va_list ap;
408c2aa98e2SPeter Wemm #if __STDC__
409c2aa98e2SPeter Wemm 	va_start(ap, fmt);
410c2aa98e2SPeter Wemm #else
411c2aa98e2SPeter Wemm 	va_start(ap);
412c2aa98e2SPeter Wemm #endif
413c2aa98e2SPeter Wemm 	(void)fprintf(stderr, "rmail: ");
414c2aa98e2SPeter Wemm 	(void)vfprintf(stderr, fmt, ap);
415c2aa98e2SPeter Wemm 	va_end(ap);
416c2aa98e2SPeter Wemm 	(void)fprintf(stderr, "\n");
417c2aa98e2SPeter Wemm 	exit(eval);
418c2aa98e2SPeter Wemm }
419c2aa98e2SPeter Wemm 
420c2aa98e2SPeter Wemm #if !HASSTRERROR
421c2aa98e2SPeter Wemm 
422c2aa98e2SPeter Wemm char *
423c2aa98e2SPeter Wemm strerror(eno)
424c2aa98e2SPeter Wemm 	int eno;
425c2aa98e2SPeter Wemm {
426c2aa98e2SPeter Wemm 	extern int sys_nerr;
427c2aa98e2SPeter Wemm 	extern char *sys_errlist[];
428c2aa98e2SPeter Wemm 	static char ebuf[60];
429c2aa98e2SPeter Wemm 
430c2aa98e2SPeter Wemm 	if (eno >= 0 && eno < sys_nerr)
431c2aa98e2SPeter Wemm 		return sys_errlist[eno];
432c2aa98e2SPeter Wemm 	(void) sprintf(ebuf, "Error %d", eno);
433c2aa98e2SPeter Wemm 	return ebuf;
434c2aa98e2SPeter Wemm }
435c2aa98e2SPeter Wemm 
436c2aa98e2SPeter Wemm #endif /* !HASSTRERROR */
437