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