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