xref: /freebsd/contrib/sendmail/rmail/rmail.c (revision 3edfa581)
1c2aa98e2SPeter Wemm /*
2b4662009SGregory Neil Shapiro  * Copyright (c) 1998-2001 Proofpoint, Inc. and its suppliers.
33299c2f1SGregory Neil Shapiro  *	All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
5c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
6c2aa98e2SPeter Wemm  *
7c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
8c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
9c2aa98e2SPeter Wemm  * the sendmail distribution.
10c2aa98e2SPeter Wemm  *
113edfa581SGregory Neil Shapiro  * $FreeBSD$
123edfa581SGregory Neil Shapiro  *
13c2aa98e2SPeter Wemm  */
14c2aa98e2SPeter Wemm 
1512ed1c7cSGregory Neil Shapiro #include <sm/gen.h>
1612ed1c7cSGregory Neil Shapiro 
1712ed1c7cSGregory Neil Shapiro SM_IDSTR(copyright,
18c0c4794dSGregory Neil Shapiro "@(#) Copyright (c) 1998-2001 Proofpoint, Inc. and its suppliers.\n\
193299c2f1SGregory Neil Shapiro 	All rights reserved.\n\
203299c2f1SGregory Neil Shapiro      Copyright (c) 1988, 1993\n\
2112ed1c7cSGregory Neil Shapiro 	The Regents of the University of California.  All rights reserved.\n")
22c2aa98e2SPeter Wemm 
2388ad41d4SGregory Neil Shapiro SM_IDSTR(id, "@(#)$Id: rmail.c,v 8.63 2013-11-22 20:51:53 ca Exp $")
243299c2f1SGregory Neil Shapiro 
25c2aa98e2SPeter Wemm /*
26c2aa98e2SPeter Wemm  * RMAIL -- UUCP mail server.
27c2aa98e2SPeter Wemm  *
28c2aa98e2SPeter Wemm  * This program reads the >From ... remote from ... lines that UUCP is so
29c2aa98e2SPeter Wemm  * fond of and turns them into something reasonable.  It then execs sendmail
30c2aa98e2SPeter Wemm  * with various options built from these lines.
31c2aa98e2SPeter Wemm  *
32c2aa98e2SPeter Wemm  * The expected syntax is:
33c2aa98e2SPeter Wemm  *
34c2aa98e2SPeter Wemm  *	 <user> := [-a-z0-9]+
35c2aa98e2SPeter Wemm  *	 <date> := ctime format
36c2aa98e2SPeter Wemm  *	 <site> := [-a-z0-9!]+
37c2aa98e2SPeter Wemm  * <blank line> := "^\n$"
38c2aa98e2SPeter Wemm  *	 <from> := "From" <space> <user> <space> <date>
39c2aa98e2SPeter Wemm  *		  [<space> "remote from" <space> <site>]
40c2aa98e2SPeter Wemm  *    <forward> := ">" <from>
41c2aa98e2SPeter Wemm  *	    msg := <from> <forward>* <blank-line> <body>
42c2aa98e2SPeter Wemm  *
43c2aa98e2SPeter Wemm  * The output of rmail(8) compresses the <forward> lines into a single
44c2aa98e2SPeter Wemm  * from path.
45c2aa98e2SPeter Wemm  *
46c2aa98e2SPeter Wemm  * The err(3) routine is included here deliberately to make this code
47c2aa98e2SPeter Wemm  * a bit more portable.
48c2aa98e2SPeter Wemm  */
493299c2f1SGregory Neil Shapiro 
503299c2f1SGregory Neil Shapiro #include <sys/types.h>
51c2aa98e2SPeter Wemm #include <sys/param.h>
52c2aa98e2SPeter Wemm #include <sys/stat.h>
53c2aa98e2SPeter Wemm #include <sys/wait.h>
54c2aa98e2SPeter Wemm 
55c2aa98e2SPeter Wemm #include <ctype.h>
56c2aa98e2SPeter Wemm #include <fcntl.h>
5712ed1c7cSGregory Neil Shapiro #include <sm/io.h>
58c2aa98e2SPeter Wemm #include <stdlib.h>
5912ed1c7cSGregory Neil Shapiro #include <sm/string.h>
60c2aa98e2SPeter Wemm #include <unistd.h>
61c2aa98e2SPeter Wemm #ifdef EX_OK
62c2aa98e2SPeter Wemm # undef EX_OK		/* unistd.h may have another use for this */
633299c2f1SGregory Neil Shapiro #endif
64c2aa98e2SPeter Wemm #include <sysexits.h>
65c2aa98e2SPeter Wemm 
6612ed1c7cSGregory Neil Shapiro #include <sm/conf.h>
6712ed1c7cSGregory Neil Shapiro #include <sm/errstring.h>
6812ed1c7cSGregory Neil Shapiro #include <sendmail/pathnames.h>
693299c2f1SGregory Neil Shapiro 
703299c2f1SGregory Neil Shapiro static void err __P((int, const char *, ...));
713299c2f1SGregory Neil Shapiro static void usage __P((void));
723299c2f1SGregory Neil Shapiro static char *xalloc __P((int));
73c2aa98e2SPeter Wemm 
74c2aa98e2SPeter Wemm #define newstr(s)	strcpy(xalloc(strlen(s) + 1), s)
75c2aa98e2SPeter Wemm 
763299c2f1SGregory Neil Shapiro static char *
xalloc(sz)77c2aa98e2SPeter Wemm xalloc(sz)
78c2aa98e2SPeter Wemm 	register int sz;
79c2aa98e2SPeter Wemm {
80c2aa98e2SPeter Wemm 	register char *p;
81c2aa98e2SPeter Wemm 
82c2aa98e2SPeter Wemm 	/* some systems can't handle size zero mallocs */
83c2aa98e2SPeter Wemm 	if (sz <= 0)
84c2aa98e2SPeter Wemm 		sz = 1;
85c2aa98e2SPeter Wemm 
8612ed1c7cSGregory Neil Shapiro 	p = malloc(sz);
87c2aa98e2SPeter Wemm 	if (p == NULL)
88c2aa98e2SPeter Wemm 		err(EX_TEMPFAIL, "out of memory");
89c2aa98e2SPeter Wemm 	return (p);
90c2aa98e2SPeter Wemm }
91c2aa98e2SPeter Wemm 
92c2aa98e2SPeter Wemm int
main(argc,argv)93c2aa98e2SPeter Wemm main(argc, argv)
94c2aa98e2SPeter Wemm 	int argc;
95c2aa98e2SPeter Wemm 	char *argv[];
96c2aa98e2SPeter Wemm {
973299c2f1SGregory Neil Shapiro 	int ch, debug, i, pdes[2], pid, status;
9876b7bf71SPeter Wemm 	size_t fplen = 0, fptlen = 0, len;
99c2aa98e2SPeter Wemm 	off_t offset;
10012ed1c7cSGregory Neil Shapiro 	SM_FILE_T *fp;
10176b7bf71SPeter Wemm 	char *addrp = NULL, *domain, *p, *t;
102c2aa98e2SPeter Wemm 	char *from_path, *from_sys, *from_user;
103d995d2baSGregory Neil Shapiro 	char **args, buf[2048], lbuf[2048];
1043299c2f1SGregory Neil Shapiro 	struct stat sb;
1053299c2f1SGregory Neil Shapiro 	extern char *optarg;
1063299c2f1SGregory Neil Shapiro 	extern int optind;
107c2aa98e2SPeter Wemm 
108c2aa98e2SPeter Wemm 	debug = 0;
109c2aa98e2SPeter Wemm 	domain = "UUCP";		/* Default "domain". */
110b2ee1660SPeter Wemm 	while ((ch = getopt(argc, argv, "D:T")) != -1)
1113299c2f1SGregory Neil Shapiro 	{
1123299c2f1SGregory Neil Shapiro 		switch (ch)
1133299c2f1SGregory Neil Shapiro 		{
114c2aa98e2SPeter Wemm 		  case 'T':
115c2aa98e2SPeter Wemm 			debug = 1;
116c2aa98e2SPeter Wemm 			break;
1173299c2f1SGregory Neil Shapiro 
118c2aa98e2SPeter Wemm 		  case 'D':
119c2aa98e2SPeter Wemm 			domain = optarg;
120c2aa98e2SPeter Wemm 			break;
1213299c2f1SGregory Neil Shapiro 
122c2aa98e2SPeter Wemm 		  case '?':
123c2aa98e2SPeter Wemm 		  default:
124c2aa98e2SPeter Wemm 			usage();
125c2aa98e2SPeter Wemm 		}
1263299c2f1SGregory Neil Shapiro 	}
1273299c2f1SGregory Neil Shapiro 
128c2aa98e2SPeter Wemm 	argc -= optind;
129c2aa98e2SPeter Wemm 	argv += optind;
130c2aa98e2SPeter Wemm 
131c2aa98e2SPeter Wemm 	if (argc < 1)
132c2aa98e2SPeter Wemm 		usage();
133c2aa98e2SPeter Wemm 
134c2aa98e2SPeter Wemm 	from_path = from_sys = from_user = NULL;
1353299c2f1SGregory Neil Shapiro 	for (offset = 0; ; )
1363299c2f1SGregory Neil Shapiro 	{
137c2aa98e2SPeter Wemm 		/* Get and nul-terminate the line. */
13812ed1c7cSGregory Neil Shapiro 		if (sm_io_fgets(smioin, SM_TIME_DEFAULT, lbuf,
13912ed1c7cSGregory Neil Shapiro 				sizeof(lbuf)) < 0)
14012ed1c7cSGregory Neil Shapiro 			err(EX_DATAERR, "no data");
141c2aa98e2SPeter Wemm 		if ((p = strchr(lbuf, '\n')) == NULL)
142c2aa98e2SPeter Wemm 			err(EX_DATAERR, "line too long");
143c2aa98e2SPeter Wemm 		*p = '\0';
144c2aa98e2SPeter Wemm 
145c2aa98e2SPeter Wemm 		/* Parse lines until reach a non-"From" line. */
146c2aa98e2SPeter Wemm 		if (!strncmp(lbuf, "From ", 5))
147c2aa98e2SPeter Wemm 			addrp = lbuf + 5;
148c2aa98e2SPeter Wemm 		else if (!strncmp(lbuf, ">From ", 6))
149c2aa98e2SPeter Wemm 			addrp = lbuf + 6;
150c2aa98e2SPeter Wemm 		else if (offset == 0)
151c2aa98e2SPeter Wemm 			err(EX_DATAERR,
152c2aa98e2SPeter Wemm 			    "missing or empty From line: %s", lbuf);
1533299c2f1SGregory Neil Shapiro 		else
1543299c2f1SGregory Neil Shapiro 		{
155c2aa98e2SPeter Wemm 			*p = '\n';
156c2aa98e2SPeter Wemm 			break;
157c2aa98e2SPeter Wemm 		}
158c2aa98e2SPeter Wemm 
1593299c2f1SGregory Neil Shapiro 		if (addrp == NULL || *addrp == '\0')
160c2aa98e2SPeter Wemm 			err(EX_DATAERR, "corrupted From line: %s", lbuf);
161c2aa98e2SPeter Wemm 
162c2aa98e2SPeter Wemm 		/* Use the "remote from" if it exists. */
163c2aa98e2SPeter Wemm 		for (p = addrp; (p = strchr(p + 1, 'r')) != NULL; )
1643299c2f1SGregory Neil Shapiro 		{
1653299c2f1SGregory Neil Shapiro 			if (!strncmp(p, "remote from ", 12))
1663299c2f1SGregory Neil Shapiro 			{
1673299c2f1SGregory Neil Shapiro 				for (t = p += 12; *t != '\0'; ++t)
1683299c2f1SGregory Neil Shapiro 				{
1693299c2f1SGregory Neil Shapiro 					if (isascii(*t) && isspace(*t))
1703299c2f1SGregory Neil Shapiro 						break;
1713299c2f1SGregory Neil Shapiro 				}
172c2aa98e2SPeter Wemm 				*t = '\0';
173c2aa98e2SPeter Wemm 				if (debug)
17412ed1c7cSGregory Neil Shapiro 					(void) sm_io_fprintf(smioerr,
17512ed1c7cSGregory Neil Shapiro 							     SM_TIME_DEFAULT,
17612ed1c7cSGregory Neil Shapiro 							     "remote from: %s\n",
17712ed1c7cSGregory Neil Shapiro 							     p);
178c2aa98e2SPeter Wemm 				break;
179c2aa98e2SPeter Wemm 			}
1803299c2f1SGregory Neil Shapiro 		}
181c2aa98e2SPeter Wemm 
182c2aa98e2SPeter Wemm 		/* Else use the string up to the last bang. */
1833299c2f1SGregory Neil Shapiro 		if (p == NULL)
1843299c2f1SGregory Neil Shapiro 		{
185c2aa98e2SPeter Wemm 			if (*addrp == '!')
1863299c2f1SGregory Neil Shapiro 				err(EX_DATAERR, "bang starts address: %s",
1873299c2f1SGregory Neil Shapiro 				    addrp);
1883299c2f1SGregory Neil Shapiro 			else if ((t = strrchr(addrp, '!')) != NULL)
1893299c2f1SGregory Neil Shapiro 			{
190c2aa98e2SPeter Wemm 				*t = '\0';
191c2aa98e2SPeter Wemm 				p = addrp;
192c2aa98e2SPeter Wemm 				addrp = t + 1;
193c2aa98e2SPeter Wemm 				if (*addrp == '\0')
194c2aa98e2SPeter Wemm 					err(EX_DATAERR,
195c2aa98e2SPeter Wemm 					    "corrupted From line: %s", lbuf);
196c2aa98e2SPeter Wemm 				if (debug)
19712ed1c7cSGregory Neil Shapiro 					(void) sm_io_fprintf(smioerr,
19812ed1c7cSGregory Neil Shapiro 							     SM_TIME_DEFAULT,
19912ed1c7cSGregory Neil Shapiro 							     "bang: %s\n", p);
200c2aa98e2SPeter Wemm 			}
201c2aa98e2SPeter Wemm 		}
2023299c2f1SGregory Neil Shapiro 
203c2aa98e2SPeter Wemm 		/* 'p' now points to any system string from this line. */
2043299c2f1SGregory Neil Shapiro 		if (p != NULL)
2053299c2f1SGregory Neil Shapiro 		{
206c2aa98e2SPeter Wemm 			/* Nul terminate it as necessary. */
2073299c2f1SGregory Neil Shapiro 			for (t = p; *t != '\0'; ++t)
2083299c2f1SGregory Neil Shapiro 			{
2093299c2f1SGregory Neil Shapiro 				if (isascii(*t) && isspace(*t))
2103299c2f1SGregory Neil Shapiro 					break;
2113299c2f1SGregory Neil Shapiro 			}
212c2aa98e2SPeter Wemm 			*t = '\0';
213c2aa98e2SPeter Wemm 
214c2aa98e2SPeter Wemm 			/* If the first system, copy to the from_sys string. */
2153299c2f1SGregory Neil Shapiro 			if (from_sys == NULL)
2163299c2f1SGregory Neil Shapiro 			{
217c2aa98e2SPeter Wemm 				from_sys = newstr(p);
218c2aa98e2SPeter Wemm 				if (debug)
21912ed1c7cSGregory Neil Shapiro 					(void) sm_io_fprintf(smioerr,
22012ed1c7cSGregory Neil Shapiro 							     SM_TIME_DEFAULT,
22112ed1c7cSGregory Neil Shapiro 							     "from_sys: %s\n",
2223299c2f1SGregory Neil Shapiro 							     from_sys);
223c2aa98e2SPeter Wemm 			}
224c2aa98e2SPeter Wemm 
225c2aa98e2SPeter Wemm 			/* Concatenate to the path string. */
226c2aa98e2SPeter Wemm 			len = t - p;
2273299c2f1SGregory Neil Shapiro 			if (from_path == NULL)
2283299c2f1SGregory Neil Shapiro 			{
229c2aa98e2SPeter Wemm 				fplen = 0;
230c2aa98e2SPeter Wemm 				if ((from_path = malloc(fptlen = 256)) == NULL)
23112ed1c7cSGregory Neil Shapiro 					err(EX_TEMPFAIL, "out of memory");
232c2aa98e2SPeter Wemm 			}
2333299c2f1SGregory Neil Shapiro 			if (fplen + len + 2 > fptlen)
2343299c2f1SGregory Neil Shapiro 			{
23512ed1c7cSGregory Neil Shapiro 				fptlen += SM_MAX(fplen + len + 2, 256);
2363299c2f1SGregory Neil Shapiro 				if ((from_path = realloc(from_path,
2373299c2f1SGregory Neil Shapiro 							 fptlen)) == NULL)
23812ed1c7cSGregory Neil Shapiro 					err(EX_TEMPFAIL, "out of memory");
239c2aa98e2SPeter Wemm 			}
240c2aa98e2SPeter Wemm 			memmove(from_path + fplen, p, len);
241c2aa98e2SPeter Wemm 			fplen += len;
242c2aa98e2SPeter Wemm 			from_path[fplen++] = '!';
243c2aa98e2SPeter Wemm 			from_path[fplen] = '\0';
244c2aa98e2SPeter Wemm 		}
245c2aa98e2SPeter Wemm 
246c2aa98e2SPeter Wemm 		/* Save off from user's address; the last one wins. */
2473299c2f1SGregory Neil Shapiro 		for (p = addrp; *p != '\0'; ++p)
2483299c2f1SGregory Neil Shapiro 		{
2493299c2f1SGregory Neil Shapiro 			if (isascii(*p) && isspace(*p))
2503299c2f1SGregory Neil Shapiro 				break;
2513299c2f1SGregory Neil Shapiro 		}
252c2aa98e2SPeter Wemm 		*p = '\0';
253c2aa98e2SPeter Wemm 		if (*addrp == '\0')
254c2aa98e2SPeter Wemm 			addrp = "<>";
255c2aa98e2SPeter Wemm 		if (from_user != NULL)
256c2aa98e2SPeter Wemm 			free(from_user);
257c2aa98e2SPeter Wemm 		from_user = newstr(addrp);
258c2aa98e2SPeter Wemm 
2593299c2f1SGregory Neil Shapiro 		if (debug)
2603299c2f1SGregory Neil Shapiro 		{
261c2aa98e2SPeter Wemm 			if (from_path != NULL)
26212ed1c7cSGregory Neil Shapiro 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
26312ed1c7cSGregory Neil Shapiro 						     "from_path: %s\n",
26412ed1c7cSGregory Neil Shapiro 						     from_path);
26512ed1c7cSGregory Neil Shapiro 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
26612ed1c7cSGregory Neil Shapiro 					     "from_user: %s\n", from_user);
267c2aa98e2SPeter Wemm 		}
268c2aa98e2SPeter Wemm 
269c2aa98e2SPeter Wemm 		if (offset != -1)
27012ed1c7cSGregory Neil Shapiro 			offset = (off_t)sm_io_tell(smioin, SM_TIME_DEFAULT);
271c2aa98e2SPeter Wemm 	}
272c2aa98e2SPeter Wemm 
273d995d2baSGregory Neil Shapiro 
27412ed1c7cSGregory Neil Shapiro 	/* Allocate args (with room for sendmail args as well as recipients */
275d995d2baSGregory Neil Shapiro 	args = (char **)xalloc(sizeof(*args) * (10 + argc));
276d995d2baSGregory Neil Shapiro 
277c2aa98e2SPeter Wemm 	i = 0;
278c2aa98e2SPeter Wemm 	args[i++] = _PATH_SENDMAIL;	/* Build sendmail's argument list. */
27912ed1c7cSGregory Neil Shapiro 	args[i++] = "-G";		/* relay submission */
280c2aa98e2SPeter Wemm 	args[i++] = "-oee";		/* No errors, just status. */
281829be59cSPeter Wemm #ifdef QUEUE_ONLY
282c2aa98e2SPeter Wemm 	args[i++] = "-odq";		/* Queue it, don't try to deliver. */
283829be59cSPeter Wemm #else
284829be59cSPeter Wemm 	args[i++] = "-odi";		/* Deliver in foreground. */
285829be59cSPeter Wemm #endif
286c2aa98e2SPeter Wemm 	args[i++] = "-oi";		/* Ignore '.' on a line by itself. */
287c2aa98e2SPeter Wemm 
288c2aa98e2SPeter Wemm 	/* set from system and protocol used */
289c2aa98e2SPeter Wemm 	if (from_sys == NULL)
29012ed1c7cSGregory Neil Shapiro 		sm_snprintf(buf, sizeof(buf), "-p%s", domain);
291c2aa98e2SPeter Wemm 	else if (strchr(from_sys, '.') == NULL)
29212ed1c7cSGregory Neil Shapiro 		sm_snprintf(buf, sizeof(buf), "-p%s:%s.%s",
293c2aa98e2SPeter Wemm 			domain, from_sys, domain);
294c2aa98e2SPeter Wemm 	else
29512ed1c7cSGregory Neil Shapiro 		sm_snprintf(buf, sizeof(buf), "-p%s:%s", domain, from_sys);
296c2aa98e2SPeter Wemm 	args[i++] = newstr(buf);
297c2aa98e2SPeter Wemm 
298c2aa98e2SPeter Wemm 	/* Set name of ``from'' person. */
29912ed1c7cSGregory Neil Shapiro 	sm_snprintf(buf, sizeof(buf), "-f%s%s",
300c2aa98e2SPeter Wemm 		 from_path ? from_path : "", from_user);
301c2aa98e2SPeter Wemm 	args[i++] = newstr(buf);
302c2aa98e2SPeter Wemm 
303c2aa98e2SPeter Wemm 	/*
3043299c2f1SGregory Neil Shapiro 	**  Don't copy arguments beginning with - as they will be
3053299c2f1SGregory Neil Shapiro 	**  passed to sendmail and could be interpreted as flags.
3063299c2f1SGregory Neil Shapiro 	**  To prevent confusion of sendmail wrap < and > around
3073299c2f1SGregory Neil Shapiro 	**  the address (helps to pass addrs like @gw1,@gw2:aa@bb)
308c2aa98e2SPeter Wemm 	*/
3093299c2f1SGregory Neil Shapiro 
310d995d2baSGregory Neil Shapiro 	while (*argv != NULL)
3113299c2f1SGregory Neil Shapiro 	{
312c2aa98e2SPeter Wemm 		if (**argv == '-')
313c2aa98e2SPeter Wemm 			err(EX_USAGE, "dash precedes argument: %s", *argv);
3143299c2f1SGregory Neil Shapiro 
315c2aa98e2SPeter Wemm 		if (strchr(*argv, ',') == NULL || strchr(*argv, '<') != NULL)
316c2aa98e2SPeter Wemm 			args[i++] = *argv;
3173299c2f1SGregory Neil Shapiro 		else
3183299c2f1SGregory Neil Shapiro 		{
3193299c2f1SGregory Neil Shapiro 			len = strlen(*argv) + 3;
3203299c2f1SGregory Neil Shapiro 			if ((args[i] = malloc(len)) == NULL)
321c2aa98e2SPeter Wemm 				err(EX_TEMPFAIL, "Cannot malloc");
32212ed1c7cSGregory Neil Shapiro 			sm_snprintf(args[i++], len, "<%s>", *argv);
323c2aa98e2SPeter Wemm 		}
324c2aa98e2SPeter Wemm 		argv++;
325d995d2baSGregory Neil Shapiro 		argc--;
326d995d2baSGregory Neil Shapiro 
327d995d2baSGregory Neil Shapiro 		/* Paranoia check, argc used for args[] bound */
328d995d2baSGregory Neil Shapiro 		if (argc < 0)
329d995d2baSGregory Neil Shapiro 			err(EX_SOFTWARE, "Argument count mismatch");
330c2aa98e2SPeter Wemm 	}
331d995d2baSGregory Neil Shapiro 	args[i] = NULL;
332c2aa98e2SPeter Wemm 
3333299c2f1SGregory Neil Shapiro 	if (debug)
3343299c2f1SGregory Neil Shapiro 	{
33512ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
33612ed1c7cSGregory Neil Shapiro 				     "Sendmail arguments:\n");
337d995d2baSGregory Neil Shapiro 		for (i = 0; args[i] != NULL; i++)
33812ed1c7cSGregory Neil Shapiro 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
33912ed1c7cSGregory Neil Shapiro 					     "\t%s\n", args[i]);
340c2aa98e2SPeter Wemm 	}
341c2aa98e2SPeter Wemm 
342c2aa98e2SPeter Wemm 	/*
3433299c2f1SGregory Neil Shapiro 	**  If called with a regular file as standard input, seek to the right
3443299c2f1SGregory Neil Shapiro 	**  position in the file and just exec sendmail.  Could probably skip
3453299c2f1SGregory Neil Shapiro 	**  skip the stat, but it's not unreasonable to believe that a failed
3463299c2f1SGregory Neil Shapiro 	**  seek will cause future reads to fail.
347c2aa98e2SPeter Wemm 	*/
3483299c2f1SGregory Neil Shapiro 
3493299c2f1SGregory Neil Shapiro 	if (!fstat(STDIN_FILENO, &sb) && S_ISREG(sb.st_mode))
3503299c2f1SGregory Neil Shapiro 	{
351c2aa98e2SPeter Wemm 		if (lseek(STDIN_FILENO, offset, SEEK_SET) != offset)
352c2aa98e2SPeter Wemm 			err(EX_TEMPFAIL, "stdin seek");
3533299c2f1SGregory Neil Shapiro 		(void) execv(_PATH_SENDMAIL, args);
354c2aa98e2SPeter Wemm 		err(EX_OSERR, "%s", _PATH_SENDMAIL);
355c2aa98e2SPeter Wemm 	}
356c2aa98e2SPeter Wemm 
357c2aa98e2SPeter Wemm 	if (pipe(pdes) < 0)
35812ed1c7cSGregory Neil Shapiro 		err(EX_OSERR, "pipe failed");
359c2aa98e2SPeter Wemm 
36012ed1c7cSGregory Neil Shapiro 	switch (pid = fork())
3613299c2f1SGregory Neil Shapiro 	{
362c2aa98e2SPeter Wemm 	  case -1:				/* Err. */
36312ed1c7cSGregory Neil Shapiro 		err(EX_OSERR, "fork failed");
3643299c2f1SGregory Neil Shapiro 		/* NOTREACHED */
3653299c2f1SGregory Neil Shapiro 
366c2aa98e2SPeter Wemm 	  case 0:				/* Child. */
3673299c2f1SGregory Neil Shapiro 		if (pdes[0] != STDIN_FILENO)
3683299c2f1SGregory Neil Shapiro 		{
369c2aa98e2SPeter Wemm 			(void) dup2(pdes[0], STDIN_FILENO);
370c2aa98e2SPeter Wemm 			(void) close(pdes[0]);
371c2aa98e2SPeter Wemm 		}
372c2aa98e2SPeter Wemm 		(void) close(pdes[1]);
3733299c2f1SGregory Neil Shapiro 		(void) execv(_PATH_SENDMAIL, args);
37412ed1c7cSGregory Neil Shapiro 		err(EX_UNAVAILABLE, "%s", _PATH_SENDMAIL);
375c2aa98e2SPeter Wemm 		/* NOTREACHED */
376c2aa98e2SPeter Wemm 	}
377c2aa98e2SPeter Wemm 
37812ed1c7cSGregory Neil Shapiro 	if ((fp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &(pdes[1]),
37912ed1c7cSGregory Neil Shapiro 			     SM_IO_WRONLY, NULL)) == NULL)
38012ed1c7cSGregory Neil Shapiro 		err(EX_OSERR, "sm_io_open failed");
381c2aa98e2SPeter Wemm 	(void) close(pdes[0]);
382c2aa98e2SPeter Wemm 
383c2aa98e2SPeter Wemm 	/* Copy the file down the pipe. */
3843299c2f1SGregory Neil Shapiro 	do
3853299c2f1SGregory Neil Shapiro 	{
38612ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", lbuf);
38712ed1c7cSGregory Neil Shapiro 	} while (sm_io_fgets(smioin, SM_TIME_DEFAULT, lbuf,
38812ed1c7cSGregory Neil Shapiro 			     sizeof(lbuf)) >= 0);
389c2aa98e2SPeter Wemm 
39012ed1c7cSGregory Neil Shapiro 	if (sm_io_error(smioin))
39112ed1c7cSGregory Neil Shapiro 		err(EX_TEMPFAIL, "stdin: %s", sm_errstring(errno));
392c2aa98e2SPeter Wemm 
39312ed1c7cSGregory Neil Shapiro 	if (sm_io_close(fp, SM_TIME_DEFAULT))
39412ed1c7cSGregory Neil Shapiro 		err(EX_OSERR, "sm_io_close failed");
395c2aa98e2SPeter Wemm 
396c2aa98e2SPeter Wemm 	if ((waitpid(pid, &status, 0)) == -1)
397c2aa98e2SPeter Wemm 		err(EX_OSERR, "%s", _PATH_SENDMAIL);
398c2aa98e2SPeter Wemm 
399c2aa98e2SPeter Wemm 	if (!WIFEXITED(status))
4003299c2f1SGregory Neil Shapiro 		err(EX_OSERR, "%s: did not terminate normally", _PATH_SENDMAIL);
401c2aa98e2SPeter Wemm 
402c2aa98e2SPeter Wemm 	if (WEXITSTATUS(status))
403c2aa98e2SPeter Wemm 		err(status, "%s: terminated with %d (non-zero) status",
404c2aa98e2SPeter Wemm 		    _PATH_SENDMAIL, WEXITSTATUS(status));
405c2aa98e2SPeter Wemm 	exit(EX_OK);
4063299c2f1SGregory Neil Shapiro 	/* NOTREACHED */
4073299c2f1SGregory Neil Shapiro 	return EX_OK;
408c2aa98e2SPeter Wemm }
409c2aa98e2SPeter Wemm 
4103299c2f1SGregory Neil Shapiro static void
usage()411c2aa98e2SPeter Wemm usage()
412c2aa98e2SPeter Wemm {
41312ed1c7cSGregory Neil Shapiro 	(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
41412ed1c7cSGregory Neil Shapiro 			     "usage: rmail [-T] [-D domain] user ...\n");
415c2aa98e2SPeter Wemm 	exit(EX_USAGE);
416c2aa98e2SPeter Wemm }
417c2aa98e2SPeter Wemm 
4183299c2f1SGregory Neil Shapiro static void
419c2aa98e2SPeter Wemm #ifdef __STDC__
err(int eval,const char * fmt,...)420c2aa98e2SPeter Wemm err(int eval, const char *fmt, ...)
4213299c2f1SGregory Neil Shapiro #else /* __STDC__ */
422c2aa98e2SPeter Wemm err(eval, fmt, va_alist)
423c2aa98e2SPeter Wemm 	int eval;
424c2aa98e2SPeter Wemm 	const char *fmt;
425c2aa98e2SPeter Wemm 	va_dcl
4263299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
427c2aa98e2SPeter Wemm {
42812ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
42912ed1c7cSGregory Neil Shapiro 
43012ed1c7cSGregory Neil Shapiro 	if (fmt != NULL)
43112ed1c7cSGregory Neil Shapiro 	{
43212ed1c7cSGregory Neil Shapiro 		SM_VA_START(ap, fmt);
43312ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "rmail: ");
43412ed1c7cSGregory Neil Shapiro 		(void) sm_io_vfprintf(smioerr, SM_TIME_DEFAULT, fmt, ap);
43512ed1c7cSGregory Neil Shapiro 		SM_VA_END(ap);
43612ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "\n");
43712ed1c7cSGregory Neil Shapiro 	}
438c2aa98e2SPeter Wemm 	exit(eval);
439c2aa98e2SPeter Wemm }
440