xref: /csrg-svn/usr.sbin/sendmail/src/err.c (revision 57736)
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*57736Seric static char sccsid[] = "@(#)err.c	6.3 (Berkeley) 01/28/93";
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*/
4557642Seric #ifdef __STDC__
4657642Seric syserr(char *fmt, ...)
4757642Seric #else
4857642Seric syserr(fmt, va_alist)
49295Seric 	char *fmt;
5057642Seric 	va_dcl
5157642Seric #endif
52295Seric {
5316901Seric 	register char *p;
5416901Seric 	int olderrno = errno;
5556852Seric 	VA_LOCAL_DECL
567957Seric 	extern char Arpa_PSyserr[];
577957Seric 	extern char Arpa_TSyserr[];
58295Seric 
597525Seric 	/* format and output the error message */
6016901Seric 	if (olderrno == 0)
617957Seric 		p = Arpa_PSyserr;
627957Seric 	else
637957Seric 		p = Arpa_TSyserr;
6456852Seric 	VA_START(fmt);
6556852Seric 	fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap);
6656852Seric 	VA_END;
679389Seric 	puterrmsg(MsgBuf);
684063Seric 
69295Seric 	/* determine exit status if not already set */
70295Seric 	if (ExitStat == EX_OK)
71295Seric 	{
7216901Seric 		if (olderrno == 0)
73295Seric 			ExitStat = EX_SOFTWARE;
74295Seric 		else
751598Seric 			ExitStat = EX_OSERR;
76295Seric 	}
77295Seric 
78295Seric # ifdef LOG
797674Seric 	if (LogLevel > 0)
8025277Seric 		syslog(LOG_CRIT, "%s: SYSERR: %s",
8125277Seric 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
8225277Seric 			&MsgBuf[4]);
8356795Seric # endif /* LOG */
84295Seric 	errno = 0;
857762Seric 	if (QuickAbort)
867762Seric 		longjmp(TopFrame, 2);
87295Seric }
88295Seric /*
89295Seric **  USRERR -- Signal user error.
90295Seric **
91295Seric **	This is much like syserr except it is for user errors.
92295Seric **
93295Seric **	Parameters:
94295Seric **		fmt, a, b, c, d -- printf strings
95295Seric **
96295Seric **	Returns:
974084Seric **		none
987762Seric **		Through TopFrame if QuickAbort is set.
99295Seric **
100295Seric **	Side Effects:
1011514Seric **		increments Errors.
102295Seric */
103295Seric 
104295Seric /*VARARGS1*/
10557642Seric #ifdef __STDC__
10657642Seric usrerr(char *fmt, ...)
10757642Seric #else
10857642Seric usrerr(fmt, va_alist)
109295Seric 	char *fmt;
11057642Seric 	va_dcl
11157642Seric #endif
112295Seric {
11356852Seric 	VA_LOCAL_DECL
114295Seric 	extern char SuprErrs;
1154167Seric 	extern char Arpa_Usrerr[];
11616901Seric 	extern int errno;
117295Seric 
118295Seric 	if (SuprErrs)
1194084Seric 		return;
120295Seric 
12156852Seric 	VA_START(fmt);
12256852Seric 	fmtmsg(MsgBuf, CurEnv->e_to, Arpa_Usrerr, errno, fmt, ap);
12356852Seric 	VA_END;
1249389Seric 	puterrmsg(MsgBuf);
1258239Seric 
12651951Seric # ifdef LOG
12751951Seric 	if (LogLevel > 1 && LogUsrErrs)
12851951Seric 		syslog(LOG_NOTICE, "%s: %s",
12951951Seric 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
13051951Seric 			&MsgBuf[4]);
13156795Seric # endif /* LOG */
13251951Seric 
1337762Seric 	if (QuickAbort)
1347762Seric 		longjmp(TopFrame, 1);
1354063Seric }
1364063Seric /*
1374063Seric **  MESSAGE -- print message (not necessarily an error)
1384063Seric **
1394063Seric **	Parameters:
1404063Seric **		num -- the default ARPANET error number (in ascii)
1414063Seric **		msg -- the message (printf fmt) -- if it begins
1424063Seric **			with a digit, this number overrides num.
1434063Seric **		a, b, c, d, e -- printf arguments
1444063Seric **
1454063Seric **	Returns:
1464063Seric **		none
1474063Seric **
1484063Seric **	Side Effects:
1494063Seric **		none.
1504063Seric */
1514063Seric 
1524084Seric /*VARARGS2*/
15357642Seric #ifdef __STDC__
15457642Seric message(char *num, char *msg, ...)
15557642Seric #else
15657642Seric message(num, msg, va_alist)
15756852Seric 	char *num;
15856852Seric 	char *msg;
15957642Seric 	va_dcl
16057642Seric #endif
1614063Seric {
16256852Seric 	VA_LOCAL_DECL
16356852Seric 
1644711Seric 	errno = 0;
16556852Seric 	VA_START(msg);
16656852Seric 	fmtmsg(MsgBuf, CurEnv->e_to, num, 0, msg, ap);
16756852Seric 	VA_END;
1689108Seric 	putmsg(MsgBuf, FALSE);
1697613Seric }
1707613Seric /*
1718239Seric **  NMESSAGE -- print message (not necessarily an error)
1728239Seric **
1738239Seric **	Just like "message" except it never puts the to... tag on.
1748239Seric **
1758239Seric **	Parameters:
1768239Seric **		num -- the default ARPANET error number (in ascii)
1778239Seric **		msg -- the message (printf fmt) -- if it begins
17824943Seric **			with three digits, this number overrides num.
1798239Seric **		a, b, c, d, e -- printf arguments
1808239Seric **
1818239Seric **	Returns:
1828239Seric **		none
1838239Seric **
1848239Seric **	Side Effects:
1858239Seric **		none.
1868239Seric */
1878239Seric 
1888239Seric /*VARARGS2*/
18957642Seric #ifdef __STDC__
19057642Seric nmessage(char *num, char *msg, ...)
19157642Seric #else
19257642Seric nmessage(num, msg, va_alist)
19356852Seric 	char *num;
19456852Seric 	char *msg;
19557642Seric 	va_dcl
19657642Seric #endif
1978239Seric {
19856852Seric 	VA_LOCAL_DECL
19956852Seric 
2008239Seric 	errno = 0;
20156852Seric 	VA_START(msg);
20256852Seric 	fmtmsg(MsgBuf, (char *) NULL, num, 0, msg, ap);
20356852Seric 	VA_END;
2049108Seric 	putmsg(MsgBuf, FALSE);
2058239Seric }
2068239Seric /*
2077613Seric **  PUTMSG -- output error message to transcript and channel
2087613Seric **
2097613Seric **	Parameters:
2107613Seric **		msg -- message to output (in SMTP format).
2119108Seric **		holdmsg -- if TRUE, don't output a copy of the message to
2129108Seric **			our output channel.
2137613Seric **
2147613Seric **	Returns:
2157613Seric **		none.
2167613Seric **
2177613Seric **	Side Effects:
2187613Seric **		Outputs msg to the transcript.
2197613Seric **		If appropriate, outputs it to the channel.
2207613Seric **		Deletes SMTP reply code number as appropriate.
2217613Seric */
2224711Seric 
2239108Seric putmsg(msg, holdmsg)
2247613Seric 	char *msg;
2259108Seric 	bool holdmsg;
2267613Seric {
22714900Seric 	/* output to transcript if serious */
22814900Seric 	if (CurEnv->e_xfp != NULL && (msg[0] == '4' || msg[0] == '5'))
22914900Seric 		fprintf(CurEnv->e_xfp, "%s\n", msg);
2304711Seric 
2314711Seric 	/* output to channel if appropriate */
2329108Seric 	if (!holdmsg && (Verbose || msg[0] != '0'))
2334063Seric 	{
2347275Seric 		(void) fflush(stdout);
23552220Seric 		if (OpMode == MD_SMTP)
2367613Seric 			fprintf(OutChannel, "%s\r\n", msg);
2374711Seric 		else
2387613Seric 			fprintf(OutChannel, "%s\n", &msg[4]);
2394711Seric 		(void) fflush(OutChannel);
2404063Seric 	}
2419389Seric }
2429389Seric /*
2439389Seric **  PUTERRMSG -- like putmsg, but does special processing for error messages
2449389Seric **
2459389Seric **	Parameters:
2469389Seric **		msg -- the message to output.
2479389Seric **
2489389Seric **	Returns:
2499389Seric **		none.
2509389Seric **
2519389Seric **	Side Effects:
2529389Seric **		Sets the fatal error bit in the envelope as appropriate.
2539389Seric */
2548239Seric 
2559389Seric puterrmsg(msg)
2569389Seric 	char *msg;
2579389Seric {
2589389Seric 	/* output the message as usual */
2599389Seric 	putmsg(msg, HoldErrs);
2609389Seric 
2619389Seric 	/* signal the error */
2629389Seric 	Errors++;
2639389Seric 	if (msg[0] == '5')
2649336Seric 		CurEnv->e_flags |= EF_FATALERRS;
2654711Seric }
2664711Seric /*
2674711Seric **  FMTMSG -- format a message into buffer.
2684711Seric **
2694711Seric **	Parameters:
2704711Seric **		eb -- error buffer to get result.
2714711Seric **		to -- the recipient tag for this message.
2724711Seric **		num -- arpanet error number.
27316901Seric **		en -- the error number to display.
2744711Seric **		fmt -- format of string.
2754711Seric **		a, b, c, d, e -- arguments.
2764711Seric **
2774711Seric **	Returns:
2784711Seric **		none.
2794711Seric **
2804711Seric **	Side Effects:
2814711Seric **		none.
2824711Seric */
2834063Seric 
28446928Sbostic static void
28556852Seric fmtmsg(eb, to, num, eno, fmt, ap)
2864711Seric 	register char *eb;
2874711Seric 	char *to;
2884711Seric 	char *num;
28916904Seric 	int eno;
2904711Seric 	char *fmt;
29156852Seric 	va_list ap;
2924711Seric {
2934711Seric 	char del;
2944711Seric 
2954711Seric 	/* output the reply code */
29624943Seric 	if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2]))
2974577Seric 	{
2984711Seric 		num = fmt;
2994711Seric 		fmt += 4;
3004711Seric 	}
3014711Seric 	if (num[3] == '-')
3024711Seric 		del = '-';
3034711Seric 	else
3044711Seric 		del = ' ';
3054711Seric 	(void) sprintf(eb, "%3.3s%c", num, del);
3064711Seric 	eb += 4;
3074063Seric 
3089372Seric 	/* output the file name and line number */
3099372Seric 	if (FileName != NULL)
3109372Seric 	{
3119372Seric 		(void) sprintf(eb, "%s: line %d: ", FileName, LineNumber);
3129372Seric 		eb += strlen(eb);
3139372Seric 	}
3149372Seric 
3154711Seric 	/* output the "to" person */
3164711Seric 	if (to != NULL && to[0] != '\0')
3174711Seric 	{
3184711Seric 		(void) sprintf(eb, "%s... ", to);
3195201Seric 		while (*eb != '\0')
3205201Seric 			*eb++ &= 0177;
3214711Seric 	}
3224711Seric 
3234711Seric 	/* output the message */
32456852Seric 	(void) vsprintf(eb, fmt, ap);
3255201Seric 	while (*eb != '\0')
3265201Seric 		*eb++ &= 0177;
3274711Seric 
3284711Seric 	/* output the error code, if any */
32916904Seric 	if (eno != 0)
3304711Seric 	{
33115136Seric 		extern char *errstring();
33215136Seric 
33316904Seric 		(void) sprintf(eb, ": %s", errstring(eno));
3344711Seric 		eb += strlen(eb);
3354577Seric 	}
336295Seric }
33715136Seric /*
33815136Seric **  ERRSTRING -- return string description of error code
33915136Seric **
34015136Seric **	Parameters:
34115136Seric **		errno -- the error number to translate
34215136Seric **
34315136Seric **	Returns:
34415136Seric **		A string description of errno.
34515136Seric **
34615136Seric **	Side Effects:
34715136Seric **		none.
34815136Seric */
34915136Seric 
35015136Seric char *
35115136Seric errstring(errno)
35215136Seric 	int errno;
35315136Seric {
35415136Seric 	extern char *sys_errlist[];
35515136Seric 	extern int sys_nerr;
35657232Seric 	static char buf[MAXLINE];
35724943Seric # ifdef SMTP
35824943Seric 	extern char *SmtpPhase;
35956795Seric # endif /* SMTP */
36015136Seric 
36124943Seric # ifdef DAEMON
36252107Seric # ifdef ETIMEDOUT
36324943Seric 	/*
36424943Seric 	**  Handle special network error codes.
36524943Seric 	**
36624943Seric 	**	These are 4.2/4.3bsd specific; they should be in daemon.c.
36724943Seric 	*/
36824943Seric 
36924943Seric 	switch (errno)
37024943Seric 	{
37124943Seric 	  case ETIMEDOUT:
37224943Seric 	  case ECONNRESET:
37324943Seric 		(void) strcpy(buf, sys_errlist[errno]);
37424943Seric 		if (SmtpPhase != NULL)
37524943Seric 		{
37624943Seric 			(void) strcat(buf, " during ");
37724943Seric 			(void) strcat(buf, SmtpPhase);
37824943Seric 		}
37925050Seric 		if (CurHostName != NULL)
38024943Seric 		{
38124943Seric 			(void) strcat(buf, " with ");
38225050Seric 			(void) strcat(buf, CurHostName);
38324943Seric 		}
38424943Seric 		return (buf);
38524943Seric 
38624943Seric 	  case EHOSTDOWN:
38725050Seric 		if (CurHostName == NULL)
38824943Seric 			break;
38925050Seric 		(void) sprintf(buf, "Host %s is down", CurHostName);
39024943Seric 		return (buf);
39124943Seric 
39224943Seric 	  case ECONNREFUSED:
39325050Seric 		if (CurHostName == NULL)
39424943Seric 			break;
39525050Seric 		(void) sprintf(buf, "Connection refused by %s", CurHostName);
39624943Seric 		return (buf);
39725526Smiriam 
398*57736Seric # ifdef NAMED_BIND
39925526Smiriam 	  case (TRY_AGAIN+MAX_ERRNO):
40025526Smiriam 		(void) sprintf(buf, "Host Name Lookup Failure");
40125526Smiriam 		return (buf);
402*57736Seric # endif
40324943Seric 	}
40452107Seric # endif
40552107Seric # endif
40624943Seric 
40715136Seric 	if (errno > 0 && errno < sys_nerr)
40815136Seric 		return (sys_errlist[errno]);
40915136Seric 
41015136Seric 	(void) sprintf(buf, "Error %d", errno);
41115136Seric 	return (buf);
41215136Seric }
413