xref: /csrg-svn/usr.sbin/sendmail/src/err.c (revision 58020)
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	6.5 (Berkeley) 02/16/93";
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 #ifdef __STDC__
46 syserr(char *fmt, ...)
47 #else
48 syserr(fmt, va_alist)
49 	char *fmt;
50 	va_dcl
51 #endif
52 {
53 	register char *p;
54 	int olderrno = errno;
55 	VA_LOCAL_DECL
56 	extern char Arpa_PSyserr[];
57 	extern char Arpa_TSyserr[];
58 
59 	/* format and output the error message */
60 	if (olderrno == 0)
61 		p = Arpa_PSyserr;
62 	else
63 		p = Arpa_TSyserr;
64 	VA_START(fmt);
65 	fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap);
66 	VA_END;
67 	puterrmsg(MsgBuf);
68 
69 	/* determine exit status if not already set */
70 	if (ExitStat == EX_OK)
71 	{
72 		if (olderrno == 0)
73 			ExitStat = EX_SOFTWARE;
74 		else
75 			ExitStat = EX_OSERR;
76 	}
77 
78 # ifdef LOG
79 	if (LogLevel > 0)
80 		syslog(LOG_CRIT, "%s: SYSERR: %s",
81 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
82 			&MsgBuf[4]);
83 # endif /* LOG */
84 	errno = 0;
85 	if (QuickAbort)
86 		longjmp(TopFrame, 2);
87 }
88 /*
89 **  USRERR -- Signal user error.
90 **
91 **	This is much like syserr except it is for user errors.
92 **
93 **	Parameters:
94 **		fmt, a, b, c, d -- printf strings
95 **
96 **	Returns:
97 **		none
98 **		Through TopFrame if QuickAbort is set.
99 **
100 **	Side Effects:
101 **		increments Errors.
102 */
103 
104 /*VARARGS1*/
105 #ifdef __STDC__
106 usrerr(char *fmt, ...)
107 #else
108 usrerr(fmt, va_alist)
109 	char *fmt;
110 	va_dcl
111 #endif
112 {
113 	VA_LOCAL_DECL
114 	extern char SuprErrs;
115 	extern char Arpa_Usrerr[];
116 	extern int errno;
117 
118 	if (SuprErrs)
119 		return;
120 
121 	VA_START(fmt);
122 	fmtmsg(MsgBuf, CurEnv->e_to, Arpa_Usrerr, errno, fmt, ap);
123 	VA_END;
124 	puterrmsg(MsgBuf);
125 
126 # ifdef LOG
127 	if (LogLevel > 3 && LogUsrErrs)
128 		syslog(LOG_NOTICE, "%s: %s",
129 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
130 			&MsgBuf[4]);
131 # endif /* LOG */
132 
133 	if (QuickAbort)
134 		longjmp(TopFrame, 1);
135 }
136 /*
137 **  MESSAGE -- print message (not necessarily an error)
138 **
139 **	Parameters:
140 **		num -- the default ARPANET error number (in ascii)
141 **		msg -- the message (printf fmt) -- if it begins
142 **			with a digit, this number overrides num.
143 **		a, b, c, d, e -- printf arguments
144 **
145 **	Returns:
146 **		none
147 **
148 **	Side Effects:
149 **		none.
150 */
151 
152 /*VARARGS2*/
153 #ifdef __STDC__
154 message(char *num, char *msg, ...)
155 #else
156 message(num, msg, va_alist)
157 	char *num;
158 	char *msg;
159 	va_dcl
160 #endif
161 {
162 	VA_LOCAL_DECL
163 
164 	errno = 0;
165 	VA_START(msg);
166 	fmtmsg(MsgBuf, CurEnv->e_to, num, 0, msg, ap);
167 	VA_END;
168 	putmsg(MsgBuf, FALSE);
169 }
170 /*
171 **  NMESSAGE -- print message (not necessarily an error)
172 **
173 **	Just like "message" except it never puts the to... tag on.
174 **
175 **	Parameters:
176 **		num -- the default ARPANET error number (in ascii)
177 **		msg -- the message (printf fmt) -- if it begins
178 **			with three digits, this number overrides num.
179 **		a, b, c, d, e -- printf arguments
180 **
181 **	Returns:
182 **		none
183 **
184 **	Side Effects:
185 **		none.
186 */
187 
188 /*VARARGS2*/
189 #ifdef __STDC__
190 nmessage(char *num, char *msg, ...)
191 #else
192 nmessage(num, msg, va_alist)
193 	char *num;
194 	char *msg;
195 	va_dcl
196 #endif
197 {
198 	VA_LOCAL_DECL
199 
200 	errno = 0;
201 	VA_START(msg);
202 	fmtmsg(MsgBuf, (char *) NULL, num, 0, msg, ap);
203 	VA_END;
204 	putmsg(MsgBuf, FALSE);
205 }
206 /*
207 **  PUTMSG -- output error message to transcript and channel
208 **
209 **	Parameters:
210 **		msg -- message to output (in SMTP format).
211 **		holdmsg -- if TRUE, don't output a copy of the message to
212 **			our output channel.
213 **
214 **	Returns:
215 **		none.
216 **
217 **	Side Effects:
218 **		Outputs msg to the transcript.
219 **		If appropriate, outputs it to the channel.
220 **		Deletes SMTP reply code number as appropriate.
221 */
222 
223 putmsg(msg, holdmsg)
224 	char *msg;
225 	bool holdmsg;
226 {
227 	/* output to transcript if serious */
228 	if (CurEnv->e_xfp != NULL && (msg[0] == '4' || msg[0] == '5'))
229 		fprintf(CurEnv->e_xfp, "%s\n", msg);
230 
231 	/* output to channel if appropriate */
232 	if (!holdmsg && (Verbose || msg[0] != '0'))
233 	{
234 		(void) fflush(stdout);
235 		if (OpMode == MD_SMTP)
236 			fprintf(OutChannel, "%s\r\n", msg);
237 		else
238 			fprintf(OutChannel, "%s\n", &msg[4]);
239 		(void) fflush(OutChannel);
240 	}
241 }
242 /*
243 **  PUTERRMSG -- like putmsg, but does special processing for error messages
244 **
245 **	Parameters:
246 **		msg -- the message to output.
247 **
248 **	Returns:
249 **		none.
250 **
251 **	Side Effects:
252 **		Sets the fatal error bit in the envelope as appropriate.
253 */
254 
255 puterrmsg(msg)
256 	char *msg;
257 {
258 	/* output the message as usual */
259 	putmsg(msg, HoldErrs);
260 
261 	/* signal the error */
262 	Errors++;
263 	if (msg[0] == '5')
264 		CurEnv->e_flags |= EF_FATALERRS;
265 }
266 /*
267 **  FMTMSG -- format a message into buffer.
268 **
269 **	Parameters:
270 **		eb -- error buffer to get result.
271 **		to -- the recipient tag for this message.
272 **		num -- arpanet error number.
273 **		en -- the error number to display.
274 **		fmt -- format of string.
275 **		a, b, c, d, e -- arguments.
276 **
277 **	Returns:
278 **		none.
279 **
280 **	Side Effects:
281 **		none.
282 */
283 
284 static void
285 fmtmsg(eb, to, num, eno, fmt, ap)
286 	register char *eb;
287 	char *to;
288 	char *num;
289 	int eno;
290 	char *fmt;
291 	va_list ap;
292 {
293 	char del;
294 
295 	/* output the reply code */
296 	if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2]))
297 	{
298 		num = fmt;
299 		fmt += 4;
300 	}
301 	if (num[3] == '-')
302 		del = '-';
303 	else
304 		del = ' ';
305 	(void) sprintf(eb, "%3.3s%c", num, del);
306 	eb += 4;
307 
308 	/* output the file name and line number */
309 	if (FileName != NULL)
310 	{
311 		(void) sprintf(eb, "%s: line %d: ", FileName, LineNumber);
312 		eb += strlen(eb);
313 	}
314 
315 	/* output the "to" person */
316 	if (to != NULL && to[0] != '\0')
317 	{
318 		(void) sprintf(eb, "%s... ", to);
319 		while (*eb != '\0')
320 			*eb++ &= 0177;
321 	}
322 
323 	/* output the message */
324 	(void) vsprintf(eb, fmt, ap);
325 	while (*eb != '\0')
326 		*eb++ &= 0177;
327 
328 	/* output the error code, if any */
329 	if (eno != 0)
330 	{
331 		extern char *errstring();
332 
333 		(void) sprintf(eb, ": %s", errstring(eno));
334 		eb += strlen(eb);
335 	}
336 }
337 /*
338 **  ERRSTRING -- return string description of error code
339 **
340 **	Parameters:
341 **		errno -- the error number to translate
342 **
343 **	Returns:
344 **		A string description of errno.
345 **
346 **	Side Effects:
347 **		none.
348 */
349 
350 char *
351 errstring(errno)
352 	int errno;
353 {
354 	extern char *sys_errlist[];
355 	extern int sys_nerr;
356 	static char buf[MAXLINE];
357 # ifdef SMTP
358 	extern char *SmtpPhase;
359 # endif /* SMTP */
360 
361 # ifdef DAEMON
362 # ifdef ETIMEDOUT
363 	/*
364 	**  Handle special network error codes.
365 	**
366 	**	These are 4.2/4.3bsd specific; they should be in daemon.c.
367 	*/
368 
369 	switch (errno)
370 	{
371 	  case ETIMEDOUT:
372 	  case ECONNRESET:
373 		(void) strcpy(buf, sys_errlist[errno]);
374 		if (SmtpPhase != NULL)
375 		{
376 			(void) strcat(buf, " during ");
377 			(void) strcat(buf, SmtpPhase);
378 		}
379 		if (CurHostName != NULL)
380 		{
381 			(void) strcat(buf, " with ");
382 			(void) strcat(buf, CurHostName);
383 		}
384 		return (buf);
385 
386 	  case EHOSTDOWN:
387 		if (CurHostName == NULL)
388 			break;
389 		(void) sprintf(buf, "Host %s is down", CurHostName);
390 		return (buf);
391 
392 	  case ECONNREFUSED:
393 		if (CurHostName == NULL)
394 			break;
395 		(void) sprintf(buf, "Connection refused by %s", CurHostName);
396 		return (buf);
397 
398 # ifdef NAMED_BIND
399 	  case HOST_NOT_FOUND + MAX_ERRNO:
400 		return ("Name server: host not found");
401 
402 	  case TRY_AGAIN + MAX_ERRNO:
403 		return ("Name server: host name lookup failure");
404 
405 	  case NO_RECOVERY + MAX_ERRNO:
406 		return ("Name server: non-recoverable error");
407 
408 	  case NO_DATA + MAX_ERRNO:
409 		return ("Name server: no data known for name");
410 # endif
411 	}
412 # endif
413 # endif
414 
415 	if (errno > 0 && errno < sys_nerr)
416 		return (sys_errlist[errno]);
417 
418 	(void) sprintf(buf, "Error %d", errno);
419 	return (buf);
420 }
421