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