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