xref: /csrg-svn/usr.sbin/sendmail/src/err.c (revision 51951)
122705Sdist /*
234921Sbostic  * Copyright (c) 1983 Eric P. Allman
333729Sbostic  * Copyright (c) 1988 Regents of the University of California.
433729Sbostic  * All rights reserved.
533729Sbostic  *
642826Sbostic  * %sccs.include.redist.c%
733729Sbostic  */
822705Sdist 
922705Sdist #ifndef lint
10*51951Seric static char sccsid[] = "@(#)err.c	5.12 (Berkeley) 12/15/91";
1133729Sbostic #endif /* not lint */
1222705Sdist 
133311Seric # include "sendmail.h"
1424943Seric # include <errno.h>
1525526Smiriam # include <netdb.h>
16295Seric 
17295Seric /*
181514Seric **  SYSERR -- Print error message.
19295Seric **
20295Seric **	Prints an error message via printf to the diagnostic
21295Seric **	output.  If LOG is defined, it logs it also.
22295Seric **
23295Seric **	Parameters:
24295Seric **		f -- the format string
25295Seric **		a, b, c, d, e -- parameters
26295Seric **
27295Seric **	Returns:
284084Seric **		none
297762Seric **		Through TopFrame if QuickAbort is set.
30295Seric **
31295Seric **	Side Effects:
321514Seric **		increments Errors.
331514Seric **		sets ExitStat.
34295Seric */
35295Seric 
364084Seric # ifdef lint
374084Seric int	sys_nerr;
384084Seric char	*sys_errlist[];
394084Seric # endif lint
4010147Seric char	MsgBuf[BUFSIZ*2];	/* text of most recent message */
414084Seric 
4246928Sbostic static void fmtmsg();
4346928Sbostic 
44295Seric /*VARARGS1*/
45295Seric syserr(fmt, a, b, c, d, e)
46295Seric 	char *fmt;
47295Seric {
4816901Seric 	register char *p;
4916901Seric 	int olderrno = errno;
507957Seric 	extern char Arpa_PSyserr[];
517957Seric 	extern char Arpa_TSyserr[];
52295Seric 
537525Seric 	/* format and output the error message */
5416901Seric 	if (olderrno == 0)
557957Seric 		p = Arpa_PSyserr;
567957Seric 	else
577957Seric 		p = Arpa_TSyserr;
5816901Seric 	fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, a, b, c, d, e);
599389Seric 	puterrmsg(MsgBuf);
604063Seric 
61295Seric 	/* determine exit status if not already set */
62295Seric 	if (ExitStat == EX_OK)
63295Seric 	{
6416901Seric 		if (olderrno == 0)
65295Seric 			ExitStat = EX_SOFTWARE;
66295Seric 		else
671598Seric 			ExitStat = EX_OSERR;
68295Seric 	}
69295Seric 
70295Seric # ifdef LOG
717674Seric 	if (LogLevel > 0)
7225277Seric 		syslog(LOG_CRIT, "%s: SYSERR: %s",
7325277Seric 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
7425277Seric 			&MsgBuf[4]);
75295Seric # endif LOG
76295Seric 	errno = 0;
777762Seric 	if (QuickAbort)
787762Seric 		longjmp(TopFrame, 2);
79295Seric }
80295Seric /*
81295Seric **  USRERR -- Signal user error.
82295Seric **
83295Seric **	This is much like syserr except it is for user errors.
84295Seric **
85295Seric **	Parameters:
86295Seric **		fmt, a, b, c, d -- printf strings
87295Seric **
88295Seric **	Returns:
894084Seric **		none
907762Seric **		Through TopFrame if QuickAbort is set.
91295Seric **
92295Seric **	Side Effects:
931514Seric **		increments Errors.
94295Seric */
95295Seric 
96295Seric /*VARARGS1*/
97295Seric usrerr(fmt, a, b, c, d, e)
98295Seric 	char *fmt;
99295Seric {
100295Seric 	extern char SuprErrs;
1014167Seric 	extern char Arpa_Usrerr[];
10216901Seric 	extern int errno;
103295Seric 
104295Seric 	if (SuprErrs)
1054084Seric 		return;
106295Seric 
10716901Seric 	fmtmsg(MsgBuf, CurEnv->e_to, Arpa_Usrerr, errno, fmt, a, b, c, d, e);
1089389Seric 	puterrmsg(MsgBuf);
1098239Seric 
110*51951Seric # ifdef LOG
111*51951Seric 	if (LogLevel > 1 && LogUsrErrs)
112*51951Seric 		syslog(LOG_NOTICE, "%s: %s",
113*51951Seric 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
114*51951Seric 			&MsgBuf[4]);
115*51951Seric # endif LOG
116*51951Seric 
1177762Seric 	if (QuickAbort)
1187762Seric 		longjmp(TopFrame, 1);
1194063Seric }
1204063Seric /*
1214063Seric **  MESSAGE -- print message (not necessarily an error)
1224063Seric **
1234063Seric **	Parameters:
1244063Seric **		num -- the default ARPANET error number (in ascii)
1254063Seric **		msg -- the message (printf fmt) -- if it begins
1264063Seric **			with a digit, this number overrides num.
1274063Seric **		a, b, c, d, e -- printf arguments
1284063Seric **
1294063Seric **	Returns:
1304063Seric **		none
1314063Seric **
1324063Seric **	Side Effects:
1334063Seric **		none.
1344063Seric */
1354063Seric 
1364084Seric /*VARARGS2*/
1374063Seric message(num, msg, a, b, c, d, e)
1384063Seric 	register char *num;
1394063Seric 	register char *msg;
1404063Seric {
1414711Seric 	errno = 0;
14216901Seric 	fmtmsg(MsgBuf, CurEnv->e_to, num, 0, msg, a, b, c, d, e);
1439108Seric 	putmsg(MsgBuf, FALSE);
1447613Seric }
1457613Seric /*
1468239Seric **  NMESSAGE -- print message (not necessarily an error)
1478239Seric **
1488239Seric **	Just like "message" except it never puts the to... tag on.
1498239Seric **
1508239Seric **	Parameters:
1518239Seric **		num -- the default ARPANET error number (in ascii)
1528239Seric **		msg -- the message (printf fmt) -- if it begins
15324943Seric **			with three digits, this number overrides num.
1548239Seric **		a, b, c, d, e -- printf arguments
1558239Seric **
1568239Seric **	Returns:
1578239Seric **		none
1588239Seric **
1598239Seric **	Side Effects:
1608239Seric **		none.
1618239Seric */
1628239Seric 
1638239Seric /*VARARGS2*/
1648239Seric nmessage(num, msg, a, b, c, d, e)
1658239Seric 	register char *num;
1668239Seric 	register char *msg;
1678239Seric {
1688239Seric 	errno = 0;
16916901Seric 	fmtmsg(MsgBuf, (char *) NULL, num, 0, msg, a, b, c, d, e);
1709108Seric 	putmsg(MsgBuf, FALSE);
1718239Seric }
1728239Seric /*
1737613Seric **  PUTMSG -- output error message to transcript and channel
1747613Seric **
1757613Seric **	Parameters:
1767613Seric **		msg -- message to output (in SMTP format).
1779108Seric **		holdmsg -- if TRUE, don't output a copy of the message to
1789108Seric **			our output channel.
1797613Seric **
1807613Seric **	Returns:
1817613Seric **		none.
1827613Seric **
1837613Seric **	Side Effects:
1847613Seric **		Outputs msg to the transcript.
1857613Seric **		If appropriate, outputs it to the channel.
1867613Seric **		Deletes SMTP reply code number as appropriate.
1877613Seric */
1884711Seric 
1899108Seric putmsg(msg, holdmsg)
1907613Seric 	char *msg;
1919108Seric 	bool holdmsg;
1927613Seric {
19314900Seric 	/* output to transcript if serious */
19414900Seric 	if (CurEnv->e_xfp != NULL && (msg[0] == '4' || msg[0] == '5'))
19514900Seric 		fprintf(CurEnv->e_xfp, "%s\n", msg);
1964711Seric 
1974711Seric 	/* output to channel if appropriate */
1989108Seric 	if (!holdmsg && (Verbose || msg[0] != '0'))
1994063Seric 	{
2007275Seric 		(void) fflush(stdout);
2019277Seric 		if (OpMode == MD_SMTP || OpMode == MD_ARPAFTP)
2027613Seric 			fprintf(OutChannel, "%s\r\n", msg);
2034711Seric 		else
2047613Seric 			fprintf(OutChannel, "%s\n", &msg[4]);
2054711Seric 		(void) fflush(OutChannel);
2064063Seric 	}
2079389Seric }
2089389Seric /*
2099389Seric **  PUTERRMSG -- like putmsg, but does special processing for error messages
2109389Seric **
2119389Seric **	Parameters:
2129389Seric **		msg -- the message to output.
2139389Seric **
2149389Seric **	Returns:
2159389Seric **		none.
2169389Seric **
2179389Seric **	Side Effects:
2189389Seric **		Sets the fatal error bit in the envelope as appropriate.
2199389Seric */
2208239Seric 
2219389Seric puterrmsg(msg)
2229389Seric 	char *msg;
2239389Seric {
2249389Seric 	/* output the message as usual */
2259389Seric 	putmsg(msg, HoldErrs);
2269389Seric 
2279389Seric 	/* signal the error */
2289389Seric 	Errors++;
2299389Seric 	if (msg[0] == '5')
2309336Seric 		CurEnv->e_flags |= EF_FATALERRS;
2314711Seric }
2324711Seric /*
2334711Seric **  FMTMSG -- format a message into buffer.
2344711Seric **
2354711Seric **	Parameters:
2364711Seric **		eb -- error buffer to get result.
2374711Seric **		to -- the recipient tag for this message.
2384711Seric **		num -- arpanet error number.
23916901Seric **		en -- the error number to display.
2404711Seric **		fmt -- format of string.
2414711Seric **		a, b, c, d, e -- arguments.
2424711Seric **
2434711Seric **	Returns:
2444711Seric **		none.
2454711Seric **
2464711Seric **	Side Effects:
2474711Seric **		none.
2484711Seric */
2494063Seric 
25016901Seric /*VARARGS5*/
25146928Sbostic static void
25216901Seric fmtmsg(eb, to, num, eno, fmt, a, b, c, d, e)
2534711Seric 	register char *eb;
2544711Seric 	char *to;
2554711Seric 	char *num;
25616904Seric 	int eno;
2574711Seric 	char *fmt;
2584711Seric {
2594711Seric 	char del;
2604711Seric 
2614711Seric 	/* output the reply code */
26224943Seric 	if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2]))
2634577Seric 	{
2644711Seric 		num = fmt;
2654711Seric 		fmt += 4;
2664711Seric 	}
2674711Seric 	if (num[3] == '-')
2684711Seric 		del = '-';
2694711Seric 	else
2704711Seric 		del = ' ';
2714711Seric 	(void) sprintf(eb, "%3.3s%c", num, del);
2724711Seric 	eb += 4;
2734063Seric 
2749372Seric 	/* output the file name and line number */
2759372Seric 	if (FileName != NULL)
2769372Seric 	{
2779372Seric 		(void) sprintf(eb, "%s: line %d: ", FileName, LineNumber);
2789372Seric 		eb += strlen(eb);
2799372Seric 	}
2809372Seric 
2814711Seric 	/* output the "to" person */
2824711Seric 	if (to != NULL && to[0] != '\0')
2834711Seric 	{
2844711Seric 		(void) sprintf(eb, "%s... ", to);
2855201Seric 		while (*eb != '\0')
2865201Seric 			*eb++ &= 0177;
2874711Seric 	}
2884711Seric 
2894711Seric 	/* output the message */
2904711Seric 	(void) sprintf(eb, fmt, a, b, c, d, e);
2915201Seric 	while (*eb != '\0')
2925201Seric 		*eb++ &= 0177;
2934711Seric 
2944711Seric 	/* output the error code, if any */
29516904Seric 	if (eno != 0)
2964711Seric 	{
29715136Seric 		extern char *errstring();
29815136Seric 
29916904Seric 		(void) sprintf(eb, ": %s", errstring(eno));
3004711Seric 		eb += strlen(eb);
3014577Seric 	}
302295Seric }
30315136Seric /*
30415136Seric **  ERRSTRING -- return string description of error code
30515136Seric **
30615136Seric **	Parameters:
30715136Seric **		errno -- the error number to translate
30815136Seric **
30915136Seric **	Returns:
31015136Seric **		A string description of errno.
31115136Seric **
31215136Seric **	Side Effects:
31315136Seric **		none.
31415136Seric */
31515136Seric 
31615136Seric char *
31715136Seric errstring(errno)
31815136Seric 	int errno;
31915136Seric {
32015136Seric 	extern char *sys_errlist[];
32115136Seric 	extern int sys_nerr;
32224943Seric 	static char buf[100];
32324943Seric # ifdef SMTP
32424943Seric 	extern char *SmtpPhase;
32524943Seric # endif SMTP
32615136Seric 
32724943Seric # ifdef DAEMON
32824943Seric # ifdef VMUNIX
32924943Seric 	/*
33024943Seric 	**  Handle special network error codes.
33124943Seric 	**
33224943Seric 	**	These are 4.2/4.3bsd specific; they should be in daemon.c.
33324943Seric 	*/
33424943Seric 
33524943Seric 	switch (errno)
33624943Seric 	{
33724943Seric 	  case ETIMEDOUT:
33824943Seric 	  case ECONNRESET:
33924943Seric 		(void) strcpy(buf, sys_errlist[errno]);
34024943Seric 		if (SmtpPhase != NULL)
34124943Seric 		{
34224943Seric 			(void) strcat(buf, " during ");
34324943Seric 			(void) strcat(buf, SmtpPhase);
34424943Seric 		}
34525050Seric 		if (CurHostName != NULL)
34624943Seric 		{
34724943Seric 			(void) strcat(buf, " with ");
34825050Seric 			(void) strcat(buf, CurHostName);
34924943Seric 		}
35024943Seric 		return (buf);
35124943Seric 
35224943Seric 	  case EHOSTDOWN:
35325050Seric 		if (CurHostName == NULL)
35424943Seric 			break;
35525050Seric 		(void) sprintf(buf, "Host %s is down", CurHostName);
35624943Seric 		return (buf);
35724943Seric 
35824943Seric 	  case ECONNREFUSED:
35925050Seric 		if (CurHostName == NULL)
36024943Seric 			break;
36125050Seric 		(void) sprintf(buf, "Connection refused by %s", CurHostName);
36224943Seric 		return (buf);
36325526Smiriam 
36425526Smiriam 	  case (TRY_AGAIN+MAX_ERRNO):
36525526Smiriam 		(void) sprintf(buf, "Host Name Lookup Failure");
36625526Smiriam 		return (buf);
36724943Seric 	}
36824943Seric # endif VMUNIX
36924943Seric # endif DAEMON
37024943Seric 
37115136Seric 	if (errno > 0 && errno < sys_nerr)
37215136Seric 		return (sys_errlist[errno]);
37315136Seric 
37415136Seric 	(void) sprintf(buf, "Error %d", errno);
37515136Seric 	return (buf);
37615136Seric }
377