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