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