xref: /freebsd/contrib/sendmail/rmail/rmail.c (revision b2ee1660ba2d5d3403da61ccd6a557960dc172c4)
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 
166c2aa98e2SPeter Wemm 	from_path = from_sys = from_user = NULL;
167c2aa98e2SPeter Wemm 	for (offset = 0;;) {
168c2aa98e2SPeter Wemm 
169c2aa98e2SPeter Wemm 		/* Get and nul-terminate the line. */
170c2aa98e2SPeter Wemm 		if (fgets(lbuf, sizeof(lbuf), stdin) == NULL)
171c2aa98e2SPeter Wemm 			exit (EX_DATAERR);
172c2aa98e2SPeter Wemm 		if ((p = strchr(lbuf, '\n')) == NULL)
173c2aa98e2SPeter Wemm 			err(EX_DATAERR, "line too long");
174c2aa98e2SPeter Wemm 		*p = '\0';
175c2aa98e2SPeter Wemm 
176c2aa98e2SPeter Wemm 		/* Parse lines until reach a non-"From" line. */
177c2aa98e2SPeter Wemm 		if (!strncmp(lbuf, "From ", 5))
178c2aa98e2SPeter Wemm 			addrp = lbuf + 5;
179c2aa98e2SPeter Wemm 		else if (!strncmp(lbuf, ">From ", 6))
180c2aa98e2SPeter Wemm 			addrp = lbuf + 6;
181c2aa98e2SPeter Wemm 		else if (offset == 0)
182c2aa98e2SPeter Wemm 			err(EX_DATAERR,
183c2aa98e2SPeter Wemm 			    "missing or empty From line: %s", lbuf);
184c2aa98e2SPeter Wemm 		else {
185c2aa98e2SPeter Wemm 			*p = '\n';
186c2aa98e2SPeter Wemm 			break;
187c2aa98e2SPeter Wemm 		}
188c2aa98e2SPeter Wemm 
189c2aa98e2SPeter Wemm 		if (*addrp == '\0')
190c2aa98e2SPeter Wemm 			err(EX_DATAERR, "corrupted From line: %s", lbuf);
191c2aa98e2SPeter Wemm 
192c2aa98e2SPeter Wemm 		/* Use the "remote from" if it exists. */
193c2aa98e2SPeter Wemm 		for (p = addrp; (p = strchr(p + 1, 'r')) != NULL;)
194c2aa98e2SPeter Wemm 			if (!strncmp(p, "remote from ", 12)) {
195c2aa98e2SPeter Wemm 				for (t = p += 12;
196c2aa98e2SPeter Wemm 				     *t && !(isascii(*t) && isspace(*t)); ++t);
197c2aa98e2SPeter Wemm 				*t = '\0';
198c2aa98e2SPeter Wemm 				if (debug)
199c2aa98e2SPeter Wemm 					(void)fprintf(stderr,
200c2aa98e2SPeter Wemm 					    "remote from: %s\n", p);
201c2aa98e2SPeter Wemm 				break;
202c2aa98e2SPeter Wemm 			}
203c2aa98e2SPeter Wemm 
204c2aa98e2SPeter Wemm 		/* Else use the string up to the last bang. */
205c2aa98e2SPeter Wemm 		if (p == NULL) {
206c2aa98e2SPeter Wemm 			if (*addrp == '!')
207c2aa98e2SPeter Wemm 				err(EX_DATAERR,
208c2aa98e2SPeter Wemm 				    "bang starts address: %s", addrp);
209c2aa98e2SPeter Wemm 			else if ((t = strrchr(addrp, '!')) != NULL) {
210c2aa98e2SPeter Wemm 				*t = '\0';
211c2aa98e2SPeter Wemm 				p = addrp;
212c2aa98e2SPeter Wemm 				addrp = t + 1;
213c2aa98e2SPeter Wemm 				if (*addrp == '\0')
214c2aa98e2SPeter Wemm 					err(EX_DATAERR,
215c2aa98e2SPeter Wemm 					    "corrupted From line: %s", lbuf);
216c2aa98e2SPeter Wemm 				if (debug)
217c2aa98e2SPeter Wemm 					(void)fprintf(stderr, "bang: %s\n", p);
218c2aa98e2SPeter Wemm 			}
219c2aa98e2SPeter Wemm 		}
220c2aa98e2SPeter Wemm 		/* 'p' now points to any system string from this line. */
221c2aa98e2SPeter Wemm 		if (p != NULL) {
222c2aa98e2SPeter Wemm 			/* Nul terminate it as necessary. */
223c2aa98e2SPeter Wemm 			for (t = p; *t && !(isascii(*t) && isspace(*t)); ++t);
224c2aa98e2SPeter Wemm 			*t = '\0';
225c2aa98e2SPeter Wemm 
226c2aa98e2SPeter Wemm 			/* If the first system, copy to the from_sys string. */
227c2aa98e2SPeter Wemm 			if (from_sys == NULL) {
228c2aa98e2SPeter Wemm 				from_sys = newstr(p);
229c2aa98e2SPeter Wemm 				if (debug)
230c2aa98e2SPeter Wemm 					(void)fprintf(stderr,
231c2aa98e2SPeter Wemm 					    "from_sys: %s\n", from_sys);
232c2aa98e2SPeter Wemm 			}
233c2aa98e2SPeter Wemm 
234c2aa98e2SPeter Wemm 			/* Concatenate to the path string. */
235c2aa98e2SPeter Wemm 			len = t - p;
236c2aa98e2SPeter Wemm 			if (from_path == NULL) {
237c2aa98e2SPeter Wemm 				fplen = 0;
238c2aa98e2SPeter Wemm 				if ((from_path = malloc(fptlen = 256)) == NULL)
239c2aa98e2SPeter Wemm 					err(EX_TEMPFAIL, NULL);
240c2aa98e2SPeter Wemm 			}
241c2aa98e2SPeter Wemm 			if (fplen + len + 2 > fptlen) {
242c2aa98e2SPeter Wemm 				fptlen += MAX(fplen + len + 2, 256);
243c2aa98e2SPeter Wemm 				if ((from_path =
244c2aa98e2SPeter Wemm 				    realloc(from_path, fptlen)) == NULL)
245c2aa98e2SPeter Wemm 					err(EX_TEMPFAIL, NULL);
246c2aa98e2SPeter Wemm 			}
247c2aa98e2SPeter Wemm 			memmove(from_path + fplen, p, len);
248c2aa98e2SPeter Wemm 			fplen += len;
249c2aa98e2SPeter Wemm 			from_path[fplen++] = '!';
250c2aa98e2SPeter Wemm 			from_path[fplen] = '\0';
251c2aa98e2SPeter Wemm 		}
252c2aa98e2SPeter Wemm 
253c2aa98e2SPeter Wemm 		/* Save off from user's address; the last one wins. */
254c2aa98e2SPeter Wemm 		for (p = addrp; *p && !(isascii(*p) && isspace(*p)); ++p);
255c2aa98e2SPeter Wemm 		*p = '\0';
256c2aa98e2SPeter Wemm 		if (*addrp == '\0')
257c2aa98e2SPeter Wemm 			addrp = "<>";
258c2aa98e2SPeter Wemm 		if (from_user != NULL)
259c2aa98e2SPeter Wemm 			free(from_user);
260c2aa98e2SPeter Wemm 		from_user = newstr(addrp);
261c2aa98e2SPeter Wemm 
262c2aa98e2SPeter Wemm 		if (debug) {
263c2aa98e2SPeter Wemm 			if (from_path != NULL)
264c2aa98e2SPeter Wemm 				(void)fprintf(stderr,
265c2aa98e2SPeter Wemm 				    "from_path: %s\n", from_path);
266c2aa98e2SPeter Wemm 			(void)fprintf(stderr, "from_user: %s\n", from_user);
267c2aa98e2SPeter Wemm 		}
268c2aa98e2SPeter Wemm 
269c2aa98e2SPeter Wemm 		if (offset != -1)
270c2aa98e2SPeter Wemm 			offset = (off_t)ftell(stdin);
271c2aa98e2SPeter Wemm 	}
272c2aa98e2SPeter Wemm 
273c2aa98e2SPeter Wemm 	i = 0;
274c2aa98e2SPeter Wemm 	args[i++] = _PATH_SENDMAIL;	/* Build sendmail's argument list. */
275c2aa98e2SPeter Wemm 	args[i++] = "-oee";		/* No errors, just status. */
276c2aa98e2SPeter Wemm 	args[i++] = "-odq";		/* Queue it, don't try to deliver. */
277c2aa98e2SPeter Wemm 	args[i++] = "-oi";		/* Ignore '.' on a line by itself. */
278c2aa98e2SPeter Wemm 
279c2aa98e2SPeter Wemm 	/* set from system and protocol used */
280c2aa98e2SPeter Wemm 	if (from_sys == NULL)
281c2aa98e2SPeter Wemm 		(void)snprintf(buf, sizeof(buf), "-p%s", domain);
282c2aa98e2SPeter Wemm 	else if (strchr(from_sys, '.') == NULL)
283c2aa98e2SPeter Wemm 		(void)snprintf(buf, sizeof(buf), "-p%s:%s.%s",
284c2aa98e2SPeter Wemm 			domain, from_sys, domain);
285c2aa98e2SPeter Wemm 	else
286c2aa98e2SPeter Wemm 		(void)snprintf(buf, sizeof(buf), "-p%s:%s", domain, from_sys);
287c2aa98e2SPeter Wemm 	args[i++] = newstr(buf);
288c2aa98e2SPeter Wemm 
289c2aa98e2SPeter Wemm 					/* Set name of ``from'' person. */
290c2aa98e2SPeter Wemm 	(void)snprintf(buf, sizeof(buf), "-f%s%s",
291c2aa98e2SPeter Wemm 	    from_path ? from_path : "", from_user);
292c2aa98e2SPeter Wemm 	args[i++] = newstr(buf);
293c2aa98e2SPeter Wemm 
294c2aa98e2SPeter Wemm 	/*
295c2aa98e2SPeter Wemm 	 * Don't copy arguments beginning with - as they will be
296c2aa98e2SPeter Wemm 	 * passed to sendmail and could be interpreted as flags.
297c2aa98e2SPeter Wemm 	 * To prevent confusion of sendmail wrap < and > around
298c2aa98e2SPeter Wemm 	 * the address (helps to pass addrs like @gw1,@gw2:aa@bb)
299c2aa98e2SPeter Wemm 	 */
300c2aa98e2SPeter Wemm 	while (*argv) {
301c2aa98e2SPeter Wemm 		if (**argv == '-')
302c2aa98e2SPeter Wemm 			err(EX_USAGE, "dash precedes argument: %s", *argv);
303c2aa98e2SPeter Wemm 		if (strchr(*argv, ',') == NULL || strchr(*argv, '<') != NULL)
304c2aa98e2SPeter Wemm 			args[i++] = *argv;
305c2aa98e2SPeter Wemm 		else {
306c2aa98e2SPeter Wemm 			if ((args[i] = malloc(strlen(*argv) + 3)) == NULL)
307c2aa98e2SPeter Wemm 				err(EX_TEMPFAIL, "Cannot malloc");
308c2aa98e2SPeter Wemm 			sprintf (args [i++], "<%s>", *argv);
309c2aa98e2SPeter Wemm 		}
310c2aa98e2SPeter Wemm 		argv++;
311c2aa98e2SPeter Wemm 	}
312c2aa98e2SPeter Wemm 	args[i] = 0;
313c2aa98e2SPeter Wemm 
314c2aa98e2SPeter Wemm 	if (debug) {
315c2aa98e2SPeter Wemm 		(void)fprintf(stderr, "Sendmail arguments:\n");
316c2aa98e2SPeter Wemm 		for (i = 0; args[i]; i++)
317c2aa98e2SPeter Wemm 			(void)fprintf(stderr, "\t%s\n", args[i]);
318c2aa98e2SPeter Wemm 	}
319c2aa98e2SPeter Wemm 
320c2aa98e2SPeter Wemm 	/*
321c2aa98e2SPeter Wemm 	 * If called with a regular file as standard input, seek to the right
322c2aa98e2SPeter Wemm 	 * position in the file and just exec sendmail.  Could probably skip
323c2aa98e2SPeter Wemm 	 * skip the stat, but it's not unreasonable to believe that a failed
324c2aa98e2SPeter Wemm 	 * seek will cause future reads to fail.
325c2aa98e2SPeter Wemm 	 */
326c2aa98e2SPeter Wemm 	if (!fstat(STDIN_FILENO, &sb) && S_ISREG(sb.st_mode)) {
327c2aa98e2SPeter Wemm 		if (lseek(STDIN_FILENO, offset, SEEK_SET) != offset)
328c2aa98e2SPeter Wemm 			err(EX_TEMPFAIL, "stdin seek");
329c2aa98e2SPeter Wemm 		execv(_PATH_SENDMAIL, args);
330c2aa98e2SPeter Wemm 		err(EX_OSERR, "%s", _PATH_SENDMAIL);
331c2aa98e2SPeter Wemm 	}
332c2aa98e2SPeter Wemm 
333c2aa98e2SPeter Wemm 	if (pipe(pdes) < 0)
334c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
335c2aa98e2SPeter Wemm 
336c2aa98e2SPeter Wemm 	switch (pid = FORK()) {
337c2aa98e2SPeter Wemm 	case -1:				/* Err. */
338c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
339c2aa98e2SPeter Wemm 	case 0:					/* Child. */
340c2aa98e2SPeter Wemm 		if (pdes[0] != STDIN_FILENO) {
341c2aa98e2SPeter Wemm 			(void)dup2(pdes[0], STDIN_FILENO);
342c2aa98e2SPeter Wemm 			(void)close(pdes[0]);
343c2aa98e2SPeter Wemm 		}
344c2aa98e2SPeter Wemm 		(void)close(pdes[1]);
345c2aa98e2SPeter Wemm 		execv(_PATH_SENDMAIL, args);
346c2aa98e2SPeter Wemm 		_exit(127);
347c2aa98e2SPeter Wemm 		/* NOTREACHED */
348c2aa98e2SPeter Wemm 	}
349c2aa98e2SPeter Wemm 
350c2aa98e2SPeter Wemm 	if ((fp = fdopen(pdes[1], "w")) == NULL)
351c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
352c2aa98e2SPeter Wemm 	(void)close(pdes[0]);
353c2aa98e2SPeter Wemm 
354c2aa98e2SPeter Wemm 	/* Copy the file down the pipe. */
355c2aa98e2SPeter Wemm 	do {
356c2aa98e2SPeter Wemm 		(void)fprintf(fp, "%s", lbuf);
357c2aa98e2SPeter Wemm 	} while (fgets(lbuf, sizeof(lbuf), stdin) != NULL);
358c2aa98e2SPeter Wemm 
359c2aa98e2SPeter Wemm 	if (ferror(stdin))
360c2aa98e2SPeter Wemm 		err(EX_TEMPFAIL, "stdin: %s", strerror(errno));
361c2aa98e2SPeter Wemm 
362c2aa98e2SPeter Wemm 	if (fclose(fp))
363c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
364c2aa98e2SPeter Wemm 
365c2aa98e2SPeter Wemm 	if ((waitpid(pid, &status, 0)) == -1)
366c2aa98e2SPeter Wemm 		err(EX_OSERR, "%s", _PATH_SENDMAIL);
367c2aa98e2SPeter Wemm 
368c2aa98e2SPeter Wemm 	if (!WIFEXITED(status))
369c2aa98e2SPeter Wemm 		err(EX_OSERR,
370c2aa98e2SPeter Wemm 		    "%s: did not terminate normally", _PATH_SENDMAIL);
371c2aa98e2SPeter Wemm 
372c2aa98e2SPeter Wemm 	if (WEXITSTATUS(status))
373c2aa98e2SPeter Wemm 		err(status, "%s: terminated with %d (non-zero) status",
374c2aa98e2SPeter Wemm 		    _PATH_SENDMAIL, WEXITSTATUS(status));
375c2aa98e2SPeter Wemm 	exit(EX_OK);
376c2aa98e2SPeter Wemm }
377c2aa98e2SPeter Wemm 
378c2aa98e2SPeter Wemm void
379c2aa98e2SPeter Wemm usage()
380c2aa98e2SPeter Wemm {
381c2aa98e2SPeter Wemm 	(void)fprintf(stderr, "usage: rmail [-T] [-D domain] user ...\n");
382c2aa98e2SPeter Wemm 	exit(EX_USAGE);
383c2aa98e2SPeter Wemm }
384c2aa98e2SPeter Wemm 
385c2aa98e2SPeter Wemm #ifdef __STDC__
386c2aa98e2SPeter Wemm #include <stdarg.h>
387c2aa98e2SPeter Wemm #else
388c2aa98e2SPeter Wemm #include <varargs.h>
389c2aa98e2SPeter Wemm #endif
390c2aa98e2SPeter Wemm 
391c2aa98e2SPeter Wemm void
392c2aa98e2SPeter Wemm #ifdef __STDC__
393c2aa98e2SPeter Wemm err(int eval, const char *fmt, ...)
394c2aa98e2SPeter Wemm #else
395c2aa98e2SPeter Wemm err(eval, fmt, va_alist)
396c2aa98e2SPeter Wemm 	int eval;
397c2aa98e2SPeter Wemm 	const char *fmt;
398c2aa98e2SPeter Wemm 	va_dcl
399c2aa98e2SPeter Wemm #endif
400c2aa98e2SPeter Wemm {
401c2aa98e2SPeter Wemm 	va_list ap;
402c2aa98e2SPeter Wemm #if __STDC__
403c2aa98e2SPeter Wemm 	va_start(ap, fmt);
404c2aa98e2SPeter Wemm #else
405c2aa98e2SPeter Wemm 	va_start(ap);
406c2aa98e2SPeter Wemm #endif
407c2aa98e2SPeter Wemm 	(void)fprintf(stderr, "rmail: ");
408c2aa98e2SPeter Wemm 	(void)vfprintf(stderr, fmt, ap);
409c2aa98e2SPeter Wemm 	va_end(ap);
410c2aa98e2SPeter Wemm 	(void)fprintf(stderr, "\n");
411c2aa98e2SPeter Wemm 	exit(eval);
412c2aa98e2SPeter Wemm }
413c2aa98e2SPeter Wemm 
414c2aa98e2SPeter Wemm #if !HASSTRERROR
415c2aa98e2SPeter Wemm 
416c2aa98e2SPeter Wemm char *
417c2aa98e2SPeter Wemm strerror(eno)
418c2aa98e2SPeter Wemm 	int eno;
419c2aa98e2SPeter Wemm {
420c2aa98e2SPeter Wemm 	extern int sys_nerr;
421c2aa98e2SPeter Wemm 	extern char *sys_errlist[];
422c2aa98e2SPeter Wemm 	static char ebuf[60];
423c2aa98e2SPeter Wemm 
424c2aa98e2SPeter Wemm 	if (eno >= 0 && eno < sys_nerr)
425c2aa98e2SPeter Wemm 		return sys_errlist[eno];
426c2aa98e2SPeter Wemm 	(void) sprintf(ebuf, "Error %d", eno);
427c2aa98e2SPeter Wemm 	return ebuf;
428c2aa98e2SPeter Wemm }
429c2aa98e2SPeter Wemm 
430c2aa98e2SPeter Wemm #endif /* !HASSTRERROR */
431