xref: /csrg-svn/usr.sbin/sendmail/src/err.c (revision 59065)
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*59065Seric static char sccsid[] = "@(#)err.c	6.12 (Berkeley) 04/13/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 **
2358690Seric **	If the first character of the syserr message is `!' it will
2458690Seric **	log this as an ALERT message and exit immediately.  This can
2558690Seric **	leave queue files in an indeterminate state, so it should not
2658690Seric **	be used lightly.
2758690Seric **
28295Seric **	Parameters:
29295Seric **		f -- the format string
30295Seric **		a, b, c, d, e -- parameters
31295Seric **
32295Seric **	Returns:
334084Seric **		none
347762Seric **		Through TopFrame if QuickAbort is set.
35295Seric **
36295Seric **	Side Effects:
371514Seric **		increments Errors.
381514Seric **		sets ExitStat.
39295Seric */
40295Seric 
414084Seric # ifdef lint
424084Seric int	sys_nerr;
434084Seric char	*sys_errlist[];
444084Seric # endif lint
4510147Seric char	MsgBuf[BUFSIZ*2];	/* text of most recent message */
464084Seric 
4746928Sbostic static void fmtmsg();
4846928Sbostic 
4958824Seric void
50295Seric /*VARARGS1*/
5157642Seric #ifdef __STDC__
5257642Seric syserr(char *fmt, ...)
5357642Seric #else
5457642Seric syserr(fmt, va_alist)
55295Seric 	char *fmt;
5657642Seric 	va_dcl
5757642Seric #endif
58295Seric {
5916901Seric 	register char *p;
6016901Seric 	int olderrno = errno;
6158690Seric 	bool panic;
6256852Seric 	VA_LOCAL_DECL
63295Seric 
6458690Seric 	panic = *fmt == '!';
6558690Seric 	if (panic)
6658690Seric 		fmt++;
6758690Seric 
687525Seric 	/* format and output the error message */
6916901Seric 	if (olderrno == 0)
7058151Seric 		p = "554";
717957Seric 	else
7258151Seric 		p = "451";
7356852Seric 	VA_START(fmt);
7456852Seric 	fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap);
7556852Seric 	VA_END;
769389Seric 	puterrmsg(MsgBuf);
774063Seric 
78295Seric 	/* determine exit status if not already set */
79295Seric 	if (ExitStat == EX_OK)
80295Seric 	{
8116901Seric 		if (olderrno == 0)
82295Seric 			ExitStat = EX_SOFTWARE;
83295Seric 		else
841598Seric 			ExitStat = EX_OSERR;
85295Seric 	}
86295Seric 
87295Seric # ifdef LOG
887674Seric 	if (LogLevel > 0)
8958690Seric 		syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR: %s",
9025277Seric 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
9125277Seric 			&MsgBuf[4]);
9256795Seric # endif /* LOG */
9358690Seric 	if (panic)
9458690Seric 		exit(EX_OSERR);
95295Seric 	errno = 0;
967762Seric 	if (QuickAbort)
977762Seric 		longjmp(TopFrame, 2);
98295Seric }
99295Seric /*
100295Seric **  USRERR -- Signal user error.
101295Seric **
102295Seric **	This is much like syserr except it is for user errors.
103295Seric **
104295Seric **	Parameters:
105295Seric **		fmt, a, b, c, d -- printf strings
106295Seric **
107295Seric **	Returns:
1084084Seric **		none
1097762Seric **		Through TopFrame if QuickAbort is set.
110295Seric **
111295Seric **	Side Effects:
1121514Seric **		increments Errors.
113295Seric */
114295Seric 
115295Seric /*VARARGS1*/
11658824Seric void
11757642Seric #ifdef __STDC__
11857642Seric usrerr(char *fmt, ...)
11957642Seric #else
12057642Seric usrerr(fmt, va_alist)
121295Seric 	char *fmt;
12257642Seric 	va_dcl
12357642Seric #endif
124295Seric {
12556852Seric 	VA_LOCAL_DECL
126295Seric 	extern char SuprErrs;
12716901Seric 	extern int errno;
128295Seric 
129295Seric 	if (SuprErrs)
1304084Seric 		return;
131295Seric 
13256852Seric 	VA_START(fmt);
13358524Seric 	fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap);
13456852Seric 	VA_END;
1359389Seric 	puterrmsg(MsgBuf);
1368239Seric 
13751951Seric # ifdef LOG
13858020Seric 	if (LogLevel > 3 && LogUsrErrs)
13951951Seric 		syslog(LOG_NOTICE, "%s: %s",
14051951Seric 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
14151951Seric 			&MsgBuf[4]);
14256795Seric # endif /* LOG */
14351951Seric 
1447762Seric 	if (QuickAbort)
1457762Seric 		longjmp(TopFrame, 1);
1464063Seric }
1474063Seric /*
1484063Seric **  MESSAGE -- print message (not necessarily an error)
1494063Seric **
1504063Seric **	Parameters:
1514063Seric **		num -- the default ARPANET error number (in ascii)
1524063Seric **		msg -- the message (printf fmt) -- if it begins
1534063Seric **			with a digit, this number overrides num.
1544063Seric **		a, b, c, d, e -- printf arguments
1554063Seric **
1564063Seric **	Returns:
1574063Seric **		none
1584063Seric **
1594063Seric **	Side Effects:
1604063Seric **		none.
1614063Seric */
1624063Seric 
1634084Seric /*VARARGS2*/
16458826Seric void
16557642Seric #ifdef __STDC__
16658151Seric message(char *msg, ...)
16757642Seric #else
16858151Seric message(msg, va_alist)
16956852Seric 	char *msg;
17057642Seric 	va_dcl
17157642Seric #endif
1724063Seric {
17356852Seric 	VA_LOCAL_DECL
17456852Seric 
1754711Seric 	errno = 0;
17656852Seric 	VA_START(msg);
17758151Seric 	fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap);
17856852Seric 	VA_END;
1799108Seric 	putmsg(MsgBuf, FALSE);
1807613Seric }
1817613Seric /*
1828239Seric **  NMESSAGE -- print message (not necessarily an error)
1838239Seric **
1848239Seric **	Just like "message" except it never puts the to... tag on.
1858239Seric **
1868239Seric **	Parameters:
1878239Seric **		num -- the default ARPANET error number (in ascii)
1888239Seric **		msg -- the message (printf fmt) -- if it begins
18924943Seric **			with three digits, this number overrides num.
1908239Seric **		a, b, c, d, e -- printf arguments
1918239Seric **
1928239Seric **	Returns:
1938239Seric **		none
1948239Seric **
1958239Seric **	Side Effects:
1968239Seric **		none.
1978239Seric */
1988239Seric 
1998239Seric /*VARARGS2*/
20058826Seric void
20157642Seric #ifdef __STDC__
20258151Seric nmessage(char *msg, ...)
20357642Seric #else
20458151Seric nmessage(msg, va_alist)
20556852Seric 	char *msg;
20657642Seric 	va_dcl
20757642Seric #endif
2088239Seric {
20956852Seric 	VA_LOCAL_DECL
21056852Seric 
2118239Seric 	errno = 0;
21256852Seric 	VA_START(msg);
21358151Seric 	fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap);
21456852Seric 	VA_END;
2159108Seric 	putmsg(MsgBuf, FALSE);
2168239Seric }
2178239Seric /*
2187613Seric **  PUTMSG -- output error message to transcript and channel
2197613Seric **
2207613Seric **	Parameters:
2217613Seric **		msg -- message to output (in SMTP format).
2229108Seric **		holdmsg -- if TRUE, don't output a copy of the message to
2239108Seric **			our output channel.
2247613Seric **
2257613Seric **	Returns:
2267613Seric **		none.
2277613Seric **
2287613Seric **	Side Effects:
2297613Seric **		Outputs msg to the transcript.
2307613Seric **		If appropriate, outputs it to the channel.
2317613Seric **		Deletes SMTP reply code number as appropriate.
2327613Seric */
2334711Seric 
2349108Seric putmsg(msg, holdmsg)
2357613Seric 	char *msg;
2369108Seric 	bool holdmsg;
2377613Seric {
23814900Seric 	/* output to transcript if serious */
23914900Seric 	if (CurEnv->e_xfp != NULL && (msg[0] == '4' || msg[0] == '5'))
24014900Seric 		fprintf(CurEnv->e_xfp, "%s\n", msg);
2414711Seric 
2424711Seric 	/* output to channel if appropriate */
2439108Seric 	if (!holdmsg && (Verbose || msg[0] != '0'))
2444063Seric 	{
2457275Seric 		(void) fflush(stdout);
24652220Seric 		if (OpMode == MD_SMTP)
2477613Seric 			fprintf(OutChannel, "%s\r\n", msg);
2484711Seric 		else
2497613Seric 			fprintf(OutChannel, "%s\n", &msg[4]);
2504711Seric 		(void) fflush(OutChannel);
251*59065Seric 		if (ferror(OutChannel))
252*59065Seric 		{
253*59065Seric 			HoldErrs = TRUE;
254*59065Seric 			syserr("putmsg: error on output channel");
255*59065Seric 		}
2564063Seric 	}
2579389Seric }
2589389Seric /*
2599389Seric **  PUTERRMSG -- like putmsg, but does special processing for error messages
2609389Seric **
2619389Seric **	Parameters:
2629389Seric **		msg -- the message to output.
2639389Seric **
2649389Seric **	Returns:
2659389Seric **		none.
2669389Seric **
2679389Seric **	Side Effects:
2689389Seric **		Sets the fatal error bit in the envelope as appropriate.
2699389Seric */
2708239Seric 
2719389Seric puterrmsg(msg)
2729389Seric 	char *msg;
2739389Seric {
2749389Seric 	/* output the message as usual */
2759389Seric 	putmsg(msg, HoldErrs);
2769389Seric 
2779389Seric 	/* signal the error */
2789389Seric 	Errors++;
2799389Seric 	if (msg[0] == '5')
2809336Seric 		CurEnv->e_flags |= EF_FATALERRS;
2814711Seric }
2824711Seric /*
2834711Seric **  FMTMSG -- format a message into buffer.
2844711Seric **
2854711Seric **	Parameters:
2864711Seric **		eb -- error buffer to get result.
2874711Seric **		to -- the recipient tag for this message.
2884711Seric **		num -- arpanet error number.
28916901Seric **		en -- the error number to display.
2904711Seric **		fmt -- format of string.
2914711Seric **		a, b, c, d, e -- arguments.
2924711Seric **
2934711Seric **	Returns:
2944711Seric **		none.
2954711Seric **
2964711Seric **	Side Effects:
2974711Seric **		none.
2984711Seric */
2994063Seric 
30046928Sbostic static void
30156852Seric fmtmsg(eb, to, num, eno, fmt, ap)
3024711Seric 	register char *eb;
3034711Seric 	char *to;
3044711Seric 	char *num;
30516904Seric 	int eno;
3064711Seric 	char *fmt;
30756852Seric 	va_list ap;
3084711Seric {
3094711Seric 	char del;
3104711Seric 
3114711Seric 	/* output the reply code */
31224943Seric 	if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2]))
3134577Seric 	{
3144711Seric 		num = fmt;
3154711Seric 		fmt += 4;
3164711Seric 	}
3174711Seric 	if (num[3] == '-')
3184711Seric 		del = '-';
3194711Seric 	else
3204711Seric 		del = ' ';
3214711Seric 	(void) sprintf(eb, "%3.3s%c", num, del);
3224711Seric 	eb += 4;
3234063Seric 
3249372Seric 	/* output the file name and line number */
3259372Seric 	if (FileName != NULL)
3269372Seric 	{
3279372Seric 		(void) sprintf(eb, "%s: line %d: ", FileName, LineNumber);
3289372Seric 		eb += strlen(eb);
3299372Seric 	}
3309372Seric 
3314711Seric 	/* output the "to" person */
3324711Seric 	if (to != NULL && to[0] != '\0')
3334711Seric 	{
3344711Seric 		(void) sprintf(eb, "%s... ", to);
3355201Seric 		while (*eb != '\0')
3365201Seric 			*eb++ &= 0177;
3374711Seric 	}
3384711Seric 
3394711Seric 	/* output the message */
34056852Seric 	(void) vsprintf(eb, fmt, ap);
3415201Seric 	while (*eb != '\0')
3425201Seric 		*eb++ &= 0177;
3434711Seric 
3444711Seric 	/* output the error code, if any */
34516904Seric 	if (eno != 0)
3464711Seric 	{
34715136Seric 		extern char *errstring();
34815136Seric 
34916904Seric 		(void) sprintf(eb, ": %s", errstring(eno));
3504711Seric 		eb += strlen(eb);
3514577Seric 	}
352295Seric }
35315136Seric /*
35415136Seric **  ERRSTRING -- return string description of error code
35515136Seric **
35615136Seric **	Parameters:
35715136Seric **		errno -- the error number to translate
35815136Seric **
35915136Seric **	Returns:
36015136Seric **		A string description of errno.
36115136Seric **
36215136Seric **	Side Effects:
36315136Seric **		none.
36415136Seric */
36515136Seric 
36615136Seric char *
36715136Seric errstring(errno)
36815136Seric 	int errno;
36915136Seric {
37015136Seric 	extern char *sys_errlist[];
37115136Seric 	extern int sys_nerr;
37257232Seric 	static char buf[MAXLINE];
37324943Seric # ifdef SMTP
37424943Seric 	extern char *SmtpPhase;
37556795Seric # endif /* SMTP */
37615136Seric 
37724943Seric # ifdef DAEMON
37852107Seric # ifdef ETIMEDOUT
37924943Seric 	/*
38024943Seric 	**  Handle special network error codes.
38124943Seric 	**
38224943Seric 	**	These are 4.2/4.3bsd specific; they should be in daemon.c.
38324943Seric 	*/
38424943Seric 
38524943Seric 	switch (errno)
38624943Seric 	{
38724943Seric 	  case ETIMEDOUT:
38824943Seric 	  case ECONNRESET:
38924943Seric 		(void) strcpy(buf, sys_errlist[errno]);
39024943Seric 		if (SmtpPhase != NULL)
39124943Seric 		{
39224943Seric 			(void) strcat(buf, " during ");
39324943Seric 			(void) strcat(buf, SmtpPhase);
39424943Seric 		}
39525050Seric 		if (CurHostName != NULL)
39624943Seric 		{
39724943Seric 			(void) strcat(buf, " with ");
39825050Seric 			(void) strcat(buf, CurHostName);
39924943Seric 		}
40024943Seric 		return (buf);
40124943Seric 
40224943Seric 	  case EHOSTDOWN:
40325050Seric 		if (CurHostName == NULL)
40424943Seric 			break;
40525050Seric 		(void) sprintf(buf, "Host %s is down", CurHostName);
40624943Seric 		return (buf);
40724943Seric 
40824943Seric 	  case ECONNREFUSED:
40925050Seric 		if (CurHostName == NULL)
41024943Seric 			break;
41125050Seric 		(void) sprintf(buf, "Connection refused by %s", CurHostName);
41224943Seric 		return (buf);
41325526Smiriam 
41457736Seric # ifdef NAMED_BIND
41558010Seric 	  case HOST_NOT_FOUND + MAX_ERRNO:
41658010Seric 		return ("Name server: host not found");
41758010Seric 
41858010Seric 	  case TRY_AGAIN + MAX_ERRNO:
41958010Seric 		return ("Name server: host name lookup failure");
42058010Seric 
42158010Seric 	  case NO_RECOVERY + MAX_ERRNO:
42258010Seric 		return ("Name server: non-recoverable error");
42358010Seric 
42458010Seric 	  case NO_DATA + MAX_ERRNO:
42558010Seric 		return ("Name server: no data known for name");
42657736Seric # endif
42724943Seric 	}
42852107Seric # endif
42952107Seric # endif
43024943Seric 
43115136Seric 	if (errno > 0 && errno < sys_nerr)
43215136Seric 		return (sys_errlist[errno]);
43315136Seric 
43415136Seric 	(void) sprintf(buf, "Error %d", errno);
43515136Seric 	return (buf);
43615136Seric }
437