xref: /csrg-svn/usr.sbin/sendmail/src/err.c (revision 58690)
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*58690Seric static char sccsid[] = "@(#)err.c	6.8 (Berkeley) 03/17/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 **
23*58690Seric **	If the first character of the syserr message is `!' it will
24*58690Seric **	log this as an ALERT message and exit immediately.  This can
25*58690Seric **	leave queue files in an indeterminate state, so it should not
26*58690Seric **	be used lightly.
27*58690Seric **
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 
49295Seric /*VARARGS1*/
5057642Seric #ifdef __STDC__
5157642Seric syserr(char *fmt, ...)
5257642Seric #else
5357642Seric syserr(fmt, va_alist)
54295Seric 	char *fmt;
5557642Seric 	va_dcl
5657642Seric #endif
57295Seric {
5816901Seric 	register char *p;
5916901Seric 	int olderrno = errno;
60*58690Seric 	bool panic;
6156852Seric 	VA_LOCAL_DECL
62295Seric 
63*58690Seric 	panic = *fmt == '!';
64*58690Seric 	if (panic)
65*58690Seric 		fmt++;
66*58690Seric 
677525Seric 	/* format and output the error message */
6816901Seric 	if (olderrno == 0)
6958151Seric 		p = "554";
707957Seric 	else
7158151Seric 		p = "451";
7256852Seric 	VA_START(fmt);
7356852Seric 	fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap);
7456852Seric 	VA_END;
759389Seric 	puterrmsg(MsgBuf);
764063Seric 
77295Seric 	/* determine exit status if not already set */
78295Seric 	if (ExitStat == EX_OK)
79295Seric 	{
8016901Seric 		if (olderrno == 0)
81295Seric 			ExitStat = EX_SOFTWARE;
82295Seric 		else
831598Seric 			ExitStat = EX_OSERR;
84295Seric 	}
85295Seric 
86295Seric # ifdef LOG
877674Seric 	if (LogLevel > 0)
88*58690Seric 		syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR: %s",
8925277Seric 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
9025277Seric 			&MsgBuf[4]);
9156795Seric # endif /* LOG */
92*58690Seric 	if (panic)
93*58690Seric 		exit(EX_OSERR);
94295Seric 	errno = 0;
957762Seric 	if (QuickAbort)
967762Seric 		longjmp(TopFrame, 2);
97295Seric }
98295Seric /*
99295Seric **  USRERR -- Signal user error.
100295Seric **
101295Seric **	This is much like syserr except it is for user errors.
102295Seric **
103295Seric **	Parameters:
104295Seric **		fmt, a, b, c, d -- printf strings
105295Seric **
106295Seric **	Returns:
1074084Seric **		none
1087762Seric **		Through TopFrame if QuickAbort is set.
109295Seric **
110295Seric **	Side Effects:
1111514Seric **		increments Errors.
112295Seric */
113295Seric 
114295Seric /*VARARGS1*/
11557642Seric #ifdef __STDC__
11657642Seric usrerr(char *fmt, ...)
11757642Seric #else
11857642Seric usrerr(fmt, va_alist)
119295Seric 	char *fmt;
12057642Seric 	va_dcl
12157642Seric #endif
122295Seric {
12356852Seric 	VA_LOCAL_DECL
124295Seric 	extern char SuprErrs;
12516901Seric 	extern int errno;
126295Seric 
127295Seric 	if (SuprErrs)
1284084Seric 		return;
129295Seric 
13056852Seric 	VA_START(fmt);
13158524Seric 	fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap);
13256852Seric 	VA_END;
1339389Seric 	puterrmsg(MsgBuf);
1348239Seric 
13551951Seric # ifdef LOG
13658020Seric 	if (LogLevel > 3 && LogUsrErrs)
13751951Seric 		syslog(LOG_NOTICE, "%s: %s",
13851951Seric 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
13951951Seric 			&MsgBuf[4]);
14056795Seric # endif /* LOG */
14151951Seric 
1427762Seric 	if (QuickAbort)
1437762Seric 		longjmp(TopFrame, 1);
1444063Seric }
1454063Seric /*
1464063Seric **  MESSAGE -- print message (not necessarily an error)
1474063Seric **
1484063Seric **	Parameters:
1494063Seric **		num -- the default ARPANET error number (in ascii)
1504063Seric **		msg -- the message (printf fmt) -- if it begins
1514063Seric **			with a digit, this number overrides num.
1524063Seric **		a, b, c, d, e -- printf arguments
1534063Seric **
1544063Seric **	Returns:
1554063Seric **		none
1564063Seric **
1574063Seric **	Side Effects:
1584063Seric **		none.
1594063Seric */
1604063Seric 
1614084Seric /*VARARGS2*/
16257642Seric #ifdef __STDC__
16358151Seric message(char *msg, ...)
16457642Seric #else
16558151Seric message(msg, va_alist)
16656852Seric 	char *msg;
16757642Seric 	va_dcl
16857642Seric #endif
1694063Seric {
17056852Seric 	VA_LOCAL_DECL
17156852Seric 
1724711Seric 	errno = 0;
17356852Seric 	VA_START(msg);
17458151Seric 	fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap);
17556852Seric 	VA_END;
1769108Seric 	putmsg(MsgBuf, FALSE);
1777613Seric }
1787613Seric /*
1798239Seric **  NMESSAGE -- print message (not necessarily an error)
1808239Seric **
1818239Seric **	Just like "message" except it never puts the to... tag on.
1828239Seric **
1838239Seric **	Parameters:
1848239Seric **		num -- the default ARPANET error number (in ascii)
1858239Seric **		msg -- the message (printf fmt) -- if it begins
18624943Seric **			with three digits, this number overrides num.
1878239Seric **		a, b, c, d, e -- printf arguments
1888239Seric **
1898239Seric **	Returns:
1908239Seric **		none
1918239Seric **
1928239Seric **	Side Effects:
1938239Seric **		none.
1948239Seric */
1958239Seric 
1968239Seric /*VARARGS2*/
19757642Seric #ifdef __STDC__
19858151Seric nmessage(char *msg, ...)
19957642Seric #else
20058151Seric nmessage(msg, va_alist)
20156852Seric 	char *msg;
20257642Seric 	va_dcl
20357642Seric #endif
2048239Seric {
20556852Seric 	VA_LOCAL_DECL
20656852Seric 
2078239Seric 	errno = 0;
20856852Seric 	VA_START(msg);
20958151Seric 	fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap);
21056852Seric 	VA_END;
2119108Seric 	putmsg(MsgBuf, FALSE);
2128239Seric }
2138239Seric /*
2147613Seric **  PUTMSG -- output error message to transcript and channel
2157613Seric **
2167613Seric **	Parameters:
2177613Seric **		msg -- message to output (in SMTP format).
2189108Seric **		holdmsg -- if TRUE, don't output a copy of the message to
2199108Seric **			our output channel.
2207613Seric **
2217613Seric **	Returns:
2227613Seric **		none.
2237613Seric **
2247613Seric **	Side Effects:
2257613Seric **		Outputs msg to the transcript.
2267613Seric **		If appropriate, outputs it to the channel.
2277613Seric **		Deletes SMTP reply code number as appropriate.
2287613Seric */
2294711Seric 
2309108Seric putmsg(msg, holdmsg)
2317613Seric 	char *msg;
2329108Seric 	bool holdmsg;
2337613Seric {
23414900Seric 	/* output to transcript if serious */
23514900Seric 	if (CurEnv->e_xfp != NULL && (msg[0] == '4' || msg[0] == '5'))
23614900Seric 		fprintf(CurEnv->e_xfp, "%s\n", msg);
2374711Seric 
2384711Seric 	/* output to channel if appropriate */
2399108Seric 	if (!holdmsg && (Verbose || msg[0] != '0'))
2404063Seric 	{
2417275Seric 		(void) fflush(stdout);
24252220Seric 		if (OpMode == MD_SMTP)
2437613Seric 			fprintf(OutChannel, "%s\r\n", msg);
2444711Seric 		else
2457613Seric 			fprintf(OutChannel, "%s\n", &msg[4]);
2464711Seric 		(void) fflush(OutChannel);
2474063Seric 	}
2489389Seric }
2499389Seric /*
2509389Seric **  PUTERRMSG -- like putmsg, but does special processing for error messages
2519389Seric **
2529389Seric **	Parameters:
2539389Seric **		msg -- the message to output.
2549389Seric **
2559389Seric **	Returns:
2569389Seric **		none.
2579389Seric **
2589389Seric **	Side Effects:
2599389Seric **		Sets the fatal error bit in the envelope as appropriate.
2609389Seric */
2618239Seric 
2629389Seric puterrmsg(msg)
2639389Seric 	char *msg;
2649389Seric {
2659389Seric 	/* output the message as usual */
2669389Seric 	putmsg(msg, HoldErrs);
2679389Seric 
2689389Seric 	/* signal the error */
2699389Seric 	Errors++;
2709389Seric 	if (msg[0] == '5')
2719336Seric 		CurEnv->e_flags |= EF_FATALERRS;
2724711Seric }
2734711Seric /*
2744711Seric **  FMTMSG -- format a message into buffer.
2754711Seric **
2764711Seric **	Parameters:
2774711Seric **		eb -- error buffer to get result.
2784711Seric **		to -- the recipient tag for this message.
2794711Seric **		num -- arpanet error number.
28016901Seric **		en -- the error number to display.
2814711Seric **		fmt -- format of string.
2824711Seric **		a, b, c, d, e -- arguments.
2834711Seric **
2844711Seric **	Returns:
2854711Seric **		none.
2864711Seric **
2874711Seric **	Side Effects:
2884711Seric **		none.
2894711Seric */
2904063Seric 
29146928Sbostic static void
29256852Seric fmtmsg(eb, to, num, eno, fmt, ap)
2934711Seric 	register char *eb;
2944711Seric 	char *to;
2954711Seric 	char *num;
29616904Seric 	int eno;
2974711Seric 	char *fmt;
29856852Seric 	va_list ap;
2994711Seric {
3004711Seric 	char del;
3014711Seric 
3024711Seric 	/* output the reply code */
30324943Seric 	if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2]))
3044577Seric 	{
3054711Seric 		num = fmt;
3064711Seric 		fmt += 4;
3074711Seric 	}
3084711Seric 	if (num[3] == '-')
3094711Seric 		del = '-';
3104711Seric 	else
3114711Seric 		del = ' ';
3124711Seric 	(void) sprintf(eb, "%3.3s%c", num, del);
3134711Seric 	eb += 4;
3144063Seric 
3159372Seric 	/* output the file name and line number */
3169372Seric 	if (FileName != NULL)
3179372Seric 	{
3189372Seric 		(void) sprintf(eb, "%s: line %d: ", FileName, LineNumber);
3199372Seric 		eb += strlen(eb);
3209372Seric 	}
3219372Seric 
3224711Seric 	/* output the "to" person */
3234711Seric 	if (to != NULL && to[0] != '\0')
3244711Seric 	{
3254711Seric 		(void) sprintf(eb, "%s... ", to);
3265201Seric 		while (*eb != '\0')
3275201Seric 			*eb++ &= 0177;
3284711Seric 	}
3294711Seric 
3304711Seric 	/* output the message */
33156852Seric 	(void) vsprintf(eb, fmt, ap);
3325201Seric 	while (*eb != '\0')
3335201Seric 		*eb++ &= 0177;
3344711Seric 
3354711Seric 	/* output the error code, if any */
33616904Seric 	if (eno != 0)
3374711Seric 	{
33815136Seric 		extern char *errstring();
33915136Seric 
34016904Seric 		(void) sprintf(eb, ": %s", errstring(eno));
3414711Seric 		eb += strlen(eb);
3424577Seric 	}
343295Seric }
34415136Seric /*
34515136Seric **  ERRSTRING -- return string description of error code
34615136Seric **
34715136Seric **	Parameters:
34815136Seric **		errno -- the error number to translate
34915136Seric **
35015136Seric **	Returns:
35115136Seric **		A string description of errno.
35215136Seric **
35315136Seric **	Side Effects:
35415136Seric **		none.
35515136Seric */
35615136Seric 
35715136Seric char *
35815136Seric errstring(errno)
35915136Seric 	int errno;
36015136Seric {
36115136Seric 	extern char *sys_errlist[];
36215136Seric 	extern int sys_nerr;
36357232Seric 	static char buf[MAXLINE];
36424943Seric # ifdef SMTP
36524943Seric 	extern char *SmtpPhase;
36656795Seric # endif /* SMTP */
36715136Seric 
36824943Seric # ifdef DAEMON
36952107Seric # ifdef ETIMEDOUT
37024943Seric 	/*
37124943Seric 	**  Handle special network error codes.
37224943Seric 	**
37324943Seric 	**	These are 4.2/4.3bsd specific; they should be in daemon.c.
37424943Seric 	*/
37524943Seric 
37624943Seric 	switch (errno)
37724943Seric 	{
37824943Seric 	  case ETIMEDOUT:
37924943Seric 	  case ECONNRESET:
38024943Seric 		(void) strcpy(buf, sys_errlist[errno]);
38124943Seric 		if (SmtpPhase != NULL)
38224943Seric 		{
38324943Seric 			(void) strcat(buf, " during ");
38424943Seric 			(void) strcat(buf, SmtpPhase);
38524943Seric 		}
38625050Seric 		if (CurHostName != NULL)
38724943Seric 		{
38824943Seric 			(void) strcat(buf, " with ");
38925050Seric 			(void) strcat(buf, CurHostName);
39024943Seric 		}
39124943Seric 		return (buf);
39224943Seric 
39324943Seric 	  case EHOSTDOWN:
39425050Seric 		if (CurHostName == NULL)
39524943Seric 			break;
39625050Seric 		(void) sprintf(buf, "Host %s is down", CurHostName);
39724943Seric 		return (buf);
39824943Seric 
39924943Seric 	  case ECONNREFUSED:
40025050Seric 		if (CurHostName == NULL)
40124943Seric 			break;
40225050Seric 		(void) sprintf(buf, "Connection refused by %s", CurHostName);
40324943Seric 		return (buf);
40425526Smiriam 
40557736Seric # ifdef NAMED_BIND
40658010Seric 	  case HOST_NOT_FOUND + MAX_ERRNO:
40758010Seric 		return ("Name server: host not found");
40858010Seric 
40958010Seric 	  case TRY_AGAIN + MAX_ERRNO:
41058010Seric 		return ("Name server: host name lookup failure");
41158010Seric 
41258010Seric 	  case NO_RECOVERY + MAX_ERRNO:
41358010Seric 		return ("Name server: non-recoverable error");
41458010Seric 
41558010Seric 	  case NO_DATA + MAX_ERRNO:
41658010Seric 		return ("Name server: no data known for name");
41757736Seric # endif
41824943Seric 	}
41952107Seric # endif
42052107Seric # endif
42124943Seric 
42215136Seric 	if (errno > 0 && errno < sys_nerr)
42315136Seric 		return (sys_errlist[errno]);
42415136Seric 
42515136Seric 	(void) sprintf(buf, "Error %d", errno);
42615136Seric 	return (buf);
42715136Seric }
428