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