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