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