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