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