xref: /original-bsd/usr.sbin/sendmail/src/err.c (revision e1db577d)
1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988 Regents of the University of California.
4  * All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)err.c	5.14 (Berkeley) 01/18/92";
11 #endif /* not lint */
12 
13 # include "sendmail.h"
14 # include <errno.h>
15 # include <netdb.h>
16 
17 /*
18 **  SYSERR -- Print error message.
19 **
20 **	Prints an error message via printf to the diagnostic
21 **	output.  If LOG is defined, it logs it also.
22 **
23 **	Parameters:
24 **		f -- the format string
25 **		a, b, c, d, e -- parameters
26 **
27 **	Returns:
28 **		none
29 **		Through TopFrame if QuickAbort is set.
30 **
31 **	Side Effects:
32 **		increments Errors.
33 **		sets ExitStat.
34 */
35 
36 # ifdef lint
37 int	sys_nerr;
38 char	*sys_errlist[];
39 # endif lint
40 char	MsgBuf[BUFSIZ*2];	/* text of most recent message */
41 
42 static void fmtmsg();
43 
44 /*VARARGS1*/
45 syserr(fmt, a, b, c, d, e)
46 	char *fmt;
47 {
48 	register char *p;
49 	int olderrno = errno;
50 	extern char Arpa_PSyserr[];
51 	extern char Arpa_TSyserr[];
52 
53 	/* format and output the error message */
54 	if (olderrno == 0)
55 		p = Arpa_PSyserr;
56 	else
57 		p = Arpa_TSyserr;
58 	fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, a, b, c, d, e);
59 	puterrmsg(MsgBuf);
60 
61 	/* determine exit status if not already set */
62 	if (ExitStat == EX_OK)
63 	{
64 		if (olderrno == 0)
65 			ExitStat = EX_SOFTWARE;
66 		else
67 			ExitStat = EX_OSERR;
68 	}
69 
70 # ifdef LOG
71 	if (LogLevel > 0)
72 		syslog(LOG_CRIT, "%s: SYSERR: %s",
73 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
74 			&MsgBuf[4]);
75 # endif LOG
76 	errno = 0;
77 	if (QuickAbort)
78 		longjmp(TopFrame, 2);
79 }
80 /*
81 **  USRERR -- Signal user error.
82 **
83 **	This is much like syserr except it is for user errors.
84 **
85 **	Parameters:
86 **		fmt, a, b, c, d -- printf strings
87 **
88 **	Returns:
89 **		none
90 **		Through TopFrame if QuickAbort is set.
91 **
92 **	Side Effects:
93 **		increments Errors.
94 */
95 
96 /*VARARGS1*/
97 usrerr(fmt, a, b, c, d, e)
98 	char *fmt;
99 {
100 	extern char SuprErrs;
101 	extern char Arpa_Usrerr[];
102 	extern int errno;
103 
104 	if (SuprErrs)
105 		return;
106 
107 	fmtmsg(MsgBuf, CurEnv->e_to, Arpa_Usrerr, errno, fmt, a, b, c, d, e);
108 	puterrmsg(MsgBuf);
109 
110 # ifdef LOG
111 	if (LogLevel > 1 && LogUsrErrs)
112 		syslog(LOG_NOTICE, "%s: %s",
113 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
114 			&MsgBuf[4]);
115 # endif LOG
116 
117 	if (QuickAbort)
118 		longjmp(TopFrame, 1);
119 }
120 /*
121 **  MESSAGE -- print message (not necessarily an error)
122 **
123 **	Parameters:
124 **		num -- the default ARPANET error number (in ascii)
125 **		msg -- the message (printf fmt) -- if it begins
126 **			with a digit, this number overrides num.
127 **		a, b, c, d, e -- printf arguments
128 **
129 **	Returns:
130 **		none
131 **
132 **	Side Effects:
133 **		none.
134 */
135 
136 /*VARARGS2*/
137 message(num, msg, a, b, c, d, e)
138 	register char *num;
139 	register char *msg;
140 {
141 	errno = 0;
142 	fmtmsg(MsgBuf, CurEnv->e_to, num, 0, msg, a, b, c, d, e);
143 	putmsg(MsgBuf, FALSE);
144 }
145 /*
146 **  NMESSAGE -- print message (not necessarily an error)
147 **
148 **	Just like "message" except it never puts the to... tag on.
149 **
150 **	Parameters:
151 **		num -- the default ARPANET error number (in ascii)
152 **		msg -- the message (printf fmt) -- if it begins
153 **			with three digits, this number overrides num.
154 **		a, b, c, d, e -- printf arguments
155 **
156 **	Returns:
157 **		none
158 **
159 **	Side Effects:
160 **		none.
161 */
162 
163 /*VARARGS2*/
164 nmessage(num, msg, a, b, c, d, e)
165 	register char *num;
166 	register char *msg;
167 {
168 	errno = 0;
169 	fmtmsg(MsgBuf, (char *) NULL, num, 0, msg, a, b, c, d, e);
170 	putmsg(MsgBuf, FALSE);
171 }
172 /*
173 **  PUTMSG -- output error message to transcript and channel
174 **
175 **	Parameters:
176 **		msg -- message to output (in SMTP format).
177 **		holdmsg -- if TRUE, don't output a copy of the message to
178 **			our output channel.
179 **
180 **	Returns:
181 **		none.
182 **
183 **	Side Effects:
184 **		Outputs msg to the transcript.
185 **		If appropriate, outputs it to the channel.
186 **		Deletes SMTP reply code number as appropriate.
187 */
188 
189 putmsg(msg, holdmsg)
190 	char *msg;
191 	bool holdmsg;
192 {
193 	/* output to transcript if serious */
194 	if (CurEnv->e_xfp != NULL && (msg[0] == '4' || msg[0] == '5'))
195 		fprintf(CurEnv->e_xfp, "%s\n", msg);
196 
197 	/* output to channel if appropriate */
198 	if (!holdmsg && (Verbose || msg[0] != '0'))
199 	{
200 		(void) fflush(stdout);
201 		if (OpMode == MD_SMTP)
202 			fprintf(OutChannel, "%s\r\n", msg);
203 		else
204 			fprintf(OutChannel, "%s\n", &msg[4]);
205 		(void) fflush(OutChannel);
206 	}
207 }
208 /*
209 **  PUTERRMSG -- like putmsg, but does special processing for error messages
210 **
211 **	Parameters:
212 **		msg -- the message to output.
213 **
214 **	Returns:
215 **		none.
216 **
217 **	Side Effects:
218 **		Sets the fatal error bit in the envelope as appropriate.
219 */
220 
221 puterrmsg(msg)
222 	char *msg;
223 {
224 	/* output the message as usual */
225 	putmsg(msg, HoldErrs);
226 
227 	/* signal the error */
228 	Errors++;
229 	if (msg[0] == '5')
230 		CurEnv->e_flags |= EF_FATALERRS;
231 }
232 /*
233 **  FMTMSG -- format a message into buffer.
234 **
235 **	Parameters:
236 **		eb -- error buffer to get result.
237 **		to -- the recipient tag for this message.
238 **		num -- arpanet error number.
239 **		en -- the error number to display.
240 **		fmt -- format of string.
241 **		a, b, c, d, e -- arguments.
242 **
243 **	Returns:
244 **		none.
245 **
246 **	Side Effects:
247 **		none.
248 */
249 
250 /*VARARGS5*/
251 static void
252 fmtmsg(eb, to, num, eno, fmt, a, b, c, d, e)
253 	register char *eb;
254 	char *to;
255 	char *num;
256 	int eno;
257 	char *fmt;
258 {
259 	char del;
260 
261 	/* output the reply code */
262 	if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2]))
263 	{
264 		num = fmt;
265 		fmt += 4;
266 	}
267 	if (num[3] == '-')
268 		del = '-';
269 	else
270 		del = ' ';
271 	(void) sprintf(eb, "%3.3s%c", num, del);
272 	eb += 4;
273 
274 	/* output the file name and line number */
275 	if (FileName != NULL)
276 	{
277 		(void) sprintf(eb, "%s: line %d: ", FileName, LineNumber);
278 		eb += strlen(eb);
279 	}
280 
281 	/* output the "to" person */
282 	if (to != NULL && to[0] != '\0')
283 	{
284 		(void) sprintf(eb, "%s... ", to);
285 		while (*eb != '\0')
286 			*eb++ &= 0177;
287 	}
288 
289 	/* output the message */
290 	(void) sprintf(eb, fmt, a, b, c, d, e);
291 	while (*eb != '\0')
292 		*eb++ &= 0177;
293 
294 	/* output the error code, if any */
295 	if (eno != 0)
296 	{
297 		extern char *errstring();
298 
299 		(void) sprintf(eb, ": %s", errstring(eno));
300 		eb += strlen(eb);
301 	}
302 }
303 /*
304 **  ERRSTRING -- return string description of error code
305 **
306 **	Parameters:
307 **		errno -- the error number to translate
308 **
309 **	Returns:
310 **		A string description of errno.
311 **
312 **	Side Effects:
313 **		none.
314 */
315 
316 char *
317 errstring(errno)
318 	int errno;
319 {
320 	extern char *sys_errlist[];
321 	extern int sys_nerr;
322 	static char buf[100];
323 # ifdef SMTP
324 	extern char *SmtpPhase;
325 # endif SMTP
326 
327 # ifdef DAEMON
328 # ifdef ETIMEDOUT
329 	/*
330 	**  Handle special network error codes.
331 	**
332 	**	These are 4.2/4.3bsd specific; they should be in daemon.c.
333 	*/
334 
335 	switch (errno)
336 	{
337 	  case ETIMEDOUT:
338 	  case ECONNRESET:
339 		(void) strcpy(buf, sys_errlist[errno]);
340 		if (SmtpPhase != NULL)
341 		{
342 			(void) strcat(buf, " during ");
343 			(void) strcat(buf, SmtpPhase);
344 		}
345 		if (CurHostName != NULL)
346 		{
347 			(void) strcat(buf, " with ");
348 			(void) strcat(buf, CurHostName);
349 		}
350 		return (buf);
351 
352 	  case EHOSTDOWN:
353 		if (CurHostName == NULL)
354 			break;
355 		(void) sprintf(buf, "Host %s is down", CurHostName);
356 		return (buf);
357 
358 	  case ECONNREFUSED:
359 		if (CurHostName == NULL)
360 			break;
361 		(void) sprintf(buf, "Connection refused by %s", CurHostName);
362 		return (buf);
363 
364 	  case (TRY_AGAIN+MAX_ERRNO):
365 		(void) sprintf(buf, "Host Name Lookup Failure");
366 		return (buf);
367 	}
368 # endif
369 # endif
370 
371 	if (errno > 0 && errno < sys_nerr)
372 		return (sys_errlist[errno]);
373 
374 	(void) sprintf(buf, "Error %d", errno);
375 	return (buf);
376 }
377