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