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