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