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