This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / usr.sbin / sendmail / src / err.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1983 Eric P. Allman
78ed81a3 3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
15637ed4
RG
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#ifndef lint
78ed81a3 36static char sccsid[] = "@(#)err.c 8.2 (Berkeley) 7/11/93";
15637ed4
RG
37#endif /* not lint */
38
39# include "sendmail.h"
40# include <errno.h>
41# include <netdb.h>
42
43/*
44** SYSERR -- Print error message.
45**
46** Prints an error message via printf to the diagnostic
47** output. If LOG is defined, it logs it also.
48**
78ed81a3 49** If the first character of the syserr message is `!' it will
50** log this as an ALERT message and exit immediately. This can
51** leave queue files in an indeterminate state, so it should not
52** be used lightly.
53**
15637ed4
RG
54** Parameters:
55** f -- the format string
56** a, b, c, d, e -- parameters
57**
58** Returns:
59** none
60** Through TopFrame if QuickAbort is set.
61**
62** Side Effects:
63** increments Errors.
64** sets ExitStat.
65*/
66
67# ifdef lint
68int sys_nerr;
69char *sys_errlist[];
70# endif lint
71char MsgBuf[BUFSIZ*2]; /* text of most recent message */
72
73static void fmtmsg();
74
78ed81a3 75void
15637ed4 76/*VARARGS1*/
78ed81a3 77#ifdef __STDC__
78syserr(const char *fmt, ...)
79#else
80syserr(fmt, va_alist)
81 const char *fmt;
82 va_dcl
83#endif
15637ed4
RG
84{
85 register char *p;
86 int olderrno = errno;
78ed81a3 87 bool panic;
88 VA_LOCAL_DECL
89
90 panic = *fmt == '!';
91 if (panic)
92 fmt++;
15637ed4
RG
93
94 /* format and output the error message */
95 if (olderrno == 0)
78ed81a3 96 p = "554";
15637ed4 97 else
78ed81a3 98 p = "451";
99 VA_START(fmt);
100 fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap);
101 VA_END;
15637ed4
RG
102 puterrmsg(MsgBuf);
103
104 /* determine exit status if not already set */
105 if (ExitStat == EX_OK)
106 {
107 if (olderrno == 0)
108 ExitStat = EX_SOFTWARE;
109 else
110 ExitStat = EX_OSERR;
111 }
112
113# ifdef LOG
114 if (LogLevel > 0)
78ed81a3 115 syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR: %s",
15637ed4
RG
116 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
117 &MsgBuf[4]);
78ed81a3 118# endif /* LOG */
119 if (panic)
120 {
121#ifdef XLA
122 xla_all_end();
123#endif
124 exit(EX_OSERR);
125 }
15637ed4
RG
126 errno = 0;
127 if (QuickAbort)
128 longjmp(TopFrame, 2);
129}
130\f/*
131** USRERR -- Signal user error.
132**
133** This is much like syserr except it is for user errors.
134**
135** Parameters:
136** fmt, a, b, c, d -- printf strings
137**
138** Returns:
139** none
140** Through TopFrame if QuickAbort is set.
141**
142** Side Effects:
143** increments Errors.
144*/
145
146/*VARARGS1*/
78ed81a3 147void
148#ifdef __STDC__
149usrerr(const char *fmt, ...)
150#else
151usrerr(fmt, va_alist)
152 const char *fmt;
153 va_dcl
154#endif
15637ed4 155{
78ed81a3 156 VA_LOCAL_DECL
15637ed4 157 extern char SuprErrs;
15637ed4
RG
158 extern int errno;
159
160 if (SuprErrs)
161 return;
162
78ed81a3 163 VA_START(fmt);
164 fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap);
165 VA_END;
15637ed4
RG
166 puterrmsg(MsgBuf);
167
78ed81a3 168# ifdef LOG
169 if (LogLevel > 3 && LogUsrErrs)
170 syslog(LOG_NOTICE, "%s: %s",
171 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
172 &MsgBuf[4]);
173# endif /* LOG */
174
15637ed4
RG
175 if (QuickAbort)
176 longjmp(TopFrame, 1);
177}
178\f/*
179** MESSAGE -- print message (not necessarily an error)
180**
181** Parameters:
78ed81a3 182** msg -- the message (printf fmt) -- it can begin with
183** an SMTP reply code. If not, 050 is assumed.
15637ed4
RG
184** a, b, c, d, e -- printf arguments
185**
186** Returns:
187** none
188**
189** Side Effects:
190** none.
191*/
192
193/*VARARGS2*/
78ed81a3 194void
195#ifdef __STDC__
196message(const char *msg, ...)
197#else
198message(msg, va_alist)
199 const char *msg;
200 va_dcl
201#endif
15637ed4 202{
78ed81a3 203 VA_LOCAL_DECL
204
15637ed4 205 errno = 0;
78ed81a3 206 VA_START(msg);
207 fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap);
208 VA_END;
209 putoutmsg(MsgBuf, FALSE);
15637ed4
RG
210}
211\f/*
212** NMESSAGE -- print message (not necessarily an error)
213**
214** Just like "message" except it never puts the to... tag on.
215**
216** Parameters:
217** num -- the default ARPANET error number (in ascii)
218** msg -- the message (printf fmt) -- if it begins
219** with three digits, this number overrides num.
220** a, b, c, d, e -- printf arguments
221**
222** Returns:
223** none
224**
225** Side Effects:
226** none.
227*/
228
229/*VARARGS2*/
78ed81a3 230void
231#ifdef __STDC__
232nmessage(const char *msg, ...)
233#else
234nmessage(msg, va_alist)
235 const char *msg;
236 va_dcl
237#endif
15637ed4 238{
78ed81a3 239 VA_LOCAL_DECL
240
15637ed4 241 errno = 0;
78ed81a3 242 VA_START(msg);
243 fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap);
244 VA_END;
245 putoutmsg(MsgBuf, FALSE);
15637ed4
RG
246}
247\f/*
78ed81a3 248** PUTOUTMSG -- output error message to transcript and channel
15637ed4
RG
249**
250** Parameters:
251** msg -- message to output (in SMTP format).
252** holdmsg -- if TRUE, don't output a copy of the message to
253** our output channel.
254**
255** Returns:
256** none.
257**
258** Side Effects:
259** Outputs msg to the transcript.
260** If appropriate, outputs it to the channel.
261** Deletes SMTP reply code number as appropriate.
262*/
263
78ed81a3 264putoutmsg(msg, holdmsg)
15637ed4
RG
265 char *msg;
266 bool holdmsg;
267{
268 /* output to transcript if serious */
269 if (CurEnv->e_xfp != NULL && (msg[0] == '4' || msg[0] == '5'))
270 fprintf(CurEnv->e_xfp, "%s\n", msg);
271
272 /* output to channel if appropriate */
78ed81a3 273 if (holdmsg || (!Verbose && msg[0] == '0'))
274 return;
275
276 (void) fflush(stdout);
277 if (OpMode == MD_SMTP)
278 fprintf(OutChannel, "%s\r\n", msg);
279 else
280 fprintf(OutChannel, "%s\n", &msg[4]);
281 if (TrafficLogFile != NULL)
282 fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(),
283 OpMode == MD_SMTP ? msg : &msg[4]);
284 if (msg[3] == ' ')
15637ed4 285 (void) fflush(OutChannel);
78ed81a3 286 if (!ferror(OutChannel))
287 return;
288
289 /* error on output -- if reporting lost channel, just ignore it */
290 if (feof(InChannel) || ferror(InChannel))
291 return;
292
293 /* can't call syserr, 'cause we are using MsgBuf */
294 HoldErrs = TRUE;
295#ifdef LOG
296 if (LogLevel > 0)
297 syslog(LOG_CRIT,
298 "%s: SYSERR: putoutmsg (%s): error on output channel sending \"%s\"",
299 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
300 CurHostName, msg);
301#endif
15637ed4
RG
302}
303\f/*
78ed81a3 304** PUTERRMSG -- like putoutmsg, but does special processing for error messages
15637ed4
RG
305**
306** Parameters:
307** msg -- the message to output.
308**
309** Returns:
310** none.
311**
312** Side Effects:
313** Sets the fatal error bit in the envelope as appropriate.
314*/
315
316puterrmsg(msg)
317 char *msg;
318{
319 /* output the message as usual */
78ed81a3 320 putoutmsg(msg, HoldErrs);
15637ed4
RG
321
322 /* signal the error */
323 Errors++;
324 if (msg[0] == '5')
325 CurEnv->e_flags |= EF_FATALERRS;
326}
327\f/*
328** FMTMSG -- format a message into buffer.
329**
330** Parameters:
331** eb -- error buffer to get result.
332** to -- the recipient tag for this message.
333** num -- arpanet error number.
334** en -- the error number to display.
335** fmt -- format of string.
336** a, b, c, d, e -- arguments.
337**
338** Returns:
339** none.
340**
341** Side Effects:
342** none.
343*/
344
15637ed4 345static void
78ed81a3 346fmtmsg(eb, to, num, eno, fmt, ap)
15637ed4
RG
347 register char *eb;
348 char *to;
349 char *num;
350 int eno;
351 char *fmt;
78ed81a3 352 va_list ap;
15637ed4
RG
353{
354 char del;
78ed81a3 355 char *meb;
15637ed4
RG
356
357 /* output the reply code */
358 if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2]))
359 {
360 num = fmt;
361 fmt += 4;
362 }
363 if (num[3] == '-')
364 del = '-';
365 else
366 del = ' ';
367 (void) sprintf(eb, "%3.3s%c", num, del);
368 eb += 4;
369
370 /* output the file name and line number */
371 if (FileName != NULL)
372 {
373 (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber);
374 eb += strlen(eb);
375 }
376
377 /* output the "to" person */
378 if (to != NULL && to[0] != '\0')
379 {
380 (void) sprintf(eb, "%s... ", to);
381 while (*eb != '\0')
382 *eb++ &= 0177;
383 }
384
78ed81a3 385 meb = eb;
386
15637ed4 387 /* output the message */
78ed81a3 388 (void) vsprintf(eb, fmt, ap);
15637ed4
RG
389 while (*eb != '\0')
390 *eb++ &= 0177;
391
392 /* output the error code, if any */
393 if (eno != 0)
394 {
15637ed4
RG
395 (void) sprintf(eb, ": %s", errstring(eno));
396 eb += strlen(eb);
397 }
78ed81a3 398
399 if (CurEnv->e_message == NULL && strchr("45", num[0]) != NULL)
400 CurEnv->e_message = newstr(meb);
15637ed4
RG
401}
402\f/*
403** ERRSTRING -- return string description of error code
404**
405** Parameters:
406** errno -- the error number to translate
407**
408** Returns:
409** A string description of errno.
410**
411** Side Effects:
412** none.
413*/
414
78ed81a3 415const char *
15637ed4
RG
416errstring(errno)
417 int errno;
418{
78ed81a3 419 extern const char *const sys_errlist[];
15637ed4 420 extern int sys_nerr;
78ed81a3 421 static char buf[MAXLINE];
15637ed4
RG
422# ifdef SMTP
423 extern char *SmtpPhase;
78ed81a3 424# endif /* SMTP */
15637ed4
RG
425
426# ifdef DAEMON
78ed81a3 427# ifdef ETIMEDOUT
15637ed4
RG
428 /*
429 ** Handle special network error codes.
430 **
431 ** These are 4.2/4.3bsd specific; they should be in daemon.c.
432 */
433
434 switch (errno)
435 {
436 case ETIMEDOUT:
437 case ECONNRESET:
438 (void) strcpy(buf, sys_errlist[errno]);
439 if (SmtpPhase != NULL)
440 {
441 (void) strcat(buf, " during ");
442 (void) strcat(buf, SmtpPhase);
443 }
444 if (CurHostName != NULL)
445 {
446 (void) strcat(buf, " with ");
447 (void) strcat(buf, CurHostName);
448 }
449 return (buf);
450
451 case EHOSTDOWN:
452 if (CurHostName == NULL)
453 break;
454 (void) sprintf(buf, "Host %s is down", CurHostName);
455 return (buf);
456
457 case ECONNREFUSED:
458 if (CurHostName == NULL)
459 break;
460 (void) sprintf(buf, "Connection refused by %s", CurHostName);
461 return (buf);
462
78ed81a3 463# ifdef NAMED_BIND
464 case HOST_NOT_FOUND + MAX_ERRNO:
465 return ("Name server: host not found");
466
467 case TRY_AGAIN + MAX_ERRNO:
468 return ("Name server: host name lookup failure");
469
470 case NO_RECOVERY + MAX_ERRNO:
471 return ("Name server: non-recoverable error");
472
473 case NO_DATA + MAX_ERRNO:
474 return ("Name server: no data known for name");
475# endif
15637ed4 476 }
78ed81a3 477# endif
478# endif
15637ed4
RG
479
480 if (errno > 0 && errno < sys_nerr)
481 return (sys_errlist[errno]);
482
483 (void) sprintf(buf, "Error %d", errno);
484 return (buf);
485}