📄 err.c
字号:
/* * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)err.c 8.27 (Berkeley) 4/18/94";#endif /* not lint */# include "sendmail.h"# include <errno.h># include <netdb.h># include <pwd.h>/*** SYSERR -- Print error message.**** Prints an error message via printf to the diagnostic** output. If LOG is defined, it logs it also.**** If the first character of the syserr message is `!' it will** log this as an ALERT message and exit immediately. This can** leave queue files in an indeterminate state, so it should not** be used lightly.**** Parameters:** f -- the format string** a, b, c, d, e -- parameters**** Returns:** none** Through TopFrame if QuickAbort is set.**** Side Effects:** increments Errors.** sets ExitStat.*/char MsgBuf[BUFSIZ*2]; /* text of most recent message */static void fmtmsg();#if NAMED_BIND && !defined(NO_DATA)# define NO_DATA NO_ADDRESS#endifvoid/*VARARGS1*/#ifdef __STDC__syserr(const char *fmt, ...)#elsesyserr(fmt, va_alist) const char *fmt; va_dcl#endif{ register char *p; int olderrno = errno; bool panic;#ifdef LOG char *uname; struct passwd *pw; char ubuf[80];#endif VA_LOCAL_DECL panic = *fmt == '!'; if (panic) fmt++; /* format and output the error message */ if (olderrno == 0) p = "554"; else p = "451"; VA_START(fmt); fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap); VA_END; puterrmsg(MsgBuf); /* determine exit status if not already set */ if (ExitStat == EX_OK) { if (olderrno == 0) ExitStat = EX_SOFTWARE; else ExitStat = EX_OSERR; if (tTd(54, 1)) printf("syserr: ExitStat = %d\n", ExitStat); }# ifdef LOG pw = getpwuid(getuid()); if (pw != NULL) uname = pw->pw_name; else { uname = ubuf; sprintf(ubuf, "UID%d", getuid()); } if (LogLevel > 0) syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR(%s): %s", CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, uname, &MsgBuf[4]);# endif /* LOG */ if (olderrno == EMFILE) { printopenfds(TRUE); mci_dump_all(TRUE); } if (panic) {#ifdef XLA xla_all_end();#endif exit(EX_OSERR); } errno = 0; if (QuickAbort) longjmp(TopFrame, 2);}/*** USRERR -- Signal user error.**** This is much like syserr except it is for user errors.**** Parameters:** fmt, a, b, c, d -- printf strings**** Returns:** none** Through TopFrame if QuickAbort is set.**** Side Effects:** increments Errors.*//*VARARGS1*/void#ifdef __STDC__usrerr(const char *fmt, ...)#elseusrerr(fmt, va_alist) const char *fmt; va_dcl#endif{ VA_LOCAL_DECL if (SuprErrs) return; VA_START(fmt); fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap); VA_END; puterrmsg(MsgBuf);# ifdef LOG if (LogLevel > 3 && LogUsrErrs) syslog(LOG_NOTICE, "%s: %s", CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, &MsgBuf[4]);# endif /* LOG */ if (QuickAbort) longjmp(TopFrame, 1);}/*** MESSAGE -- print message (not necessarily an error)**** Parameters:** msg -- the message (printf fmt) -- it can begin with** an SMTP reply code. If not, 050 is assumed.** a, b, c, d, e -- printf arguments**** Returns:** none**** Side Effects:** none.*//*VARARGS2*/void#ifdef __STDC__message(const char *msg, ...)#elsemessage(msg, va_alist) const char *msg; va_dcl#endif{ VA_LOCAL_DECL errno = 0; VA_START(msg); fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap); VA_END; putoutmsg(MsgBuf, FALSE);}/*** NMESSAGE -- print message (not necessarily an error)**** Just like "message" except it never puts the to... tag on.**** Parameters:** num -- the default ARPANET error number (in ascii)** msg -- the message (printf fmt) -- if it begins** with three digits, this number overrides num.** a, b, c, d, e -- printf arguments**** Returns:** none**** Side Effects:** none.*//*VARARGS2*/void#ifdef __STDC__nmessage(const char *msg, ...)#elsenmessage(msg, va_alist) const char *msg; va_dcl#endif{ VA_LOCAL_DECL errno = 0; VA_START(msg); fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap); VA_END; putoutmsg(MsgBuf, FALSE);}/*** PUTOUTMSG -- output error message to transcript and channel**** Parameters:** msg -- message to output (in SMTP format).** holdmsg -- if TRUE, don't output a copy of the message to** our output channel.**** Returns:** none.**** Side Effects:** Outputs msg to the transcript.** If appropriate, outputs it to the channel.** Deletes SMTP reply code number as appropriate.*/putoutmsg(msg, holdmsg) char *msg; bool holdmsg;{ /* display for debugging */ if (tTd(54, 8)) printf("--- %s%s\n", msg, holdmsg ? " (held)" : ""); /* output to transcript if serious */ if (CurEnv->e_xfp != NULL && strchr("456", msg[0]) != NULL) fprintf(CurEnv->e_xfp, "%s\n", msg); /* output to channel if appropriate */ if (holdmsg || (!Verbose && msg[0] == '0')) return; /* map warnings to something SMTP can handle */ if (msg[0] == '6') msg[0] = '5'; (void) fflush(stdout); /* if DisConnected, OutChannel now points to the transcript */ if (!DisConnected && (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP)) fprintf(OutChannel, "%s\r\n", msg); else fprintf(OutChannel, "%s\n", &msg[4]); if (TrafficLogFile != NULL) fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), (OpMode == MD_SMTP || OpMode == MD_DAEMON) ? msg : &msg[4]); if (msg[3] == ' ') (void) fflush(OutChannel); if (!ferror(OutChannel) || DisConnected) return; /* ** Error on output -- if reporting lost channel, just ignore it. ** Also, ignore errors from QUIT response (221 message) -- some ** rude servers don't read result. */ if (feof(InChannel) || ferror(InChannel) || strncmp(msg, "221", 3) == 0) return; /* can't call syserr, 'cause we are using MsgBuf */ HoldErrs = TRUE;#ifdef LOG if (LogLevel > 0) syslog(LOG_CRIT, "%s: SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s", CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, CurHostName == NULL ? "NO-HOST" : CurHostName, msg, errstring(errno));#endif}/*** PUTERRMSG -- like putoutmsg, but does special processing for error messages**** Parameters:** msg -- the message to output.**** Returns:** none.**** Side Effects:** Sets the fatal error bit in the envelope as appropriate.*/puterrmsg(msg) char *msg;{ char msgcode = msg[0]; /* output the message as usual */ putoutmsg(msg, HoldErrs); /* signal the error */ Errors++; if (msgcode == '6') { /* notify the postmaster */ CurEnv->e_flags |= EF_PM_NOTIFY; } else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags)) { /* mark long-term fatal errors */ CurEnv->e_flags |= EF_FATALERRS; }}/*** FMTMSG -- format a message into buffer.**** Parameters:** eb -- error buffer to get result.** to -- the recipient tag for this message.** num -- arpanet error number.** en -- the error number to display.** fmt -- format of string.** a, b, c, d, e -- arguments.**** Returns:** none.**** Side Effects:** none.*/static voidfmtmsg(eb, to, num, eno, fmt, ap) register char *eb; char *to; char *num; int eno; char *fmt; va_list ap;{ char del; char *meb; /* output the reply code */ if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2])) { num = fmt; fmt += 4; } if (num[3] == '-') del = '-'; else del = ' '; (void) sprintf(eb, "%3.3s%c", num, del); eb += 4; /* output the file name and line number */ if (FileName != NULL) { (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber); eb += strlen(eb); } /* output the "to" person */ if (to != NULL && to[0] != '\0') { (void) sprintf(eb, "%s... ", shortenstring(to, 203)); while (*eb != '\0') *eb++ &= 0177; } meb = eb; /* output the message */ (void) vsprintf(eb, fmt, ap); while (*eb != '\0') *eb++ &= 0177; /* output the error code, if any */ if (eno != 0) { (void) sprintf(eb, ": %s", errstring(eno)); eb += strlen(eb); } if (num[0] == '5' || (CurEnv->e_message == NULL && num[0] == '4')) { if (CurEnv->e_message != NULL) free(CurEnv->e_message); CurEnv->e_message = newstr(meb); }}/*** ERRSTRING -- return string description of error code**** Parameters:** errnum -- the error number to translate**** Returns:** A string description of errnum.**** Side Effects:** none.*/const char *errstring(errnum) int errnum;{ char *dnsmsg; static char buf[MAXLINE];# ifndef ERRLIST_PREDEFINED extern char *sys_errlist[]; extern int sys_nerr;# endif# ifdef SMTP extern char *SmtpPhase;# endif /* SMTP */ /* ** Handle special network error codes. ** ** These are 4.2/4.3bsd specific; they should be in daemon.c. */ dnsmsg = NULL; switch (errnum) {# if defined(DAEMON) && defined(ETIMEDOUT) case ETIMEDOUT: case ECONNRESET: (void) strcpy(buf, sys_errlist[errnum]); if (SmtpPhase != NULL) { (void) strcat(buf, " during "); (void) strcat(buf, SmtpPhase); } if (CurHostName != NULL) { (void) strcat(buf, " with "); (void) strcat(buf, CurHostName); } return (buf); case EHOSTDOWN: if (CurHostName == NULL) break; (void) sprintf(buf, "Host %s is down", CurHostName); return (buf); case ECONNREFUSED: if (CurHostName == NULL) break; (void) sprintf(buf, "Connection refused by %s", CurHostName); return (buf);# endif case EOPENTIMEOUT: return "Timeout on file open";# if NAMED_BIND case HOST_NOT_FOUND + E_DNSBASE: dnsmsg = "host not found"; break; case TRY_AGAIN + E_DNSBASE: dnsmsg = "host name lookup failure"; break; case NO_RECOVERY + E_DNSBASE: dnsmsg = "non-recoverable error"; break; case NO_DATA + E_DNSBASE: dnsmsg = "no data known"; break;# endif case EPERM: /* SunOS gives "Not owner" -- this is the POSIX message */ return "Operation not permitted"; } if (dnsmsg != NULL) { (void) strcpy(buf, "Name server: "); if (CurHostName != NULL) { (void) strcat(buf, CurHostName); (void) strcat(buf, ": "); } (void) strcat(buf, dnsmsg); return buf; } if (errnum > 0 && errnum < sys_nerr) return (sys_errlist[errnum]); (void) sprintf(buf, "Error %d", errnum); return (buf);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -