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[] = "@(#)util.c 6.10 (Berkeley) 03/01/93"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include <sys/stat.h> 15 # include <sysexits.h> 16 /* 17 ** STRIPQUOTES -- Strip quotes & quote bits from a string. 18 ** 19 ** Runs through a string and strips off unquoted quote 20 ** characters and quote bits. This is done in place. 21 ** 22 ** Parameters: 23 ** s -- the string to strip. 24 ** 25 ** Returns: 26 ** none. 27 ** 28 ** Side Effects: 29 ** none. 30 ** 31 ** Called By: 32 ** deliver 33 */ 34 35 stripquotes(s) 36 char *s; 37 { 38 register char *p; 39 register char *q; 40 register char c; 41 42 if (s == NULL) 43 return; 44 45 p = q = s; 46 do 47 { 48 c = *p++; 49 if (c == '\\') 50 c = *p++; 51 else if (c == '"') 52 continue; 53 *q++ = c; 54 } while (c != '\0'); 55 } 56 /* 57 ** CAPITALIZE -- return a copy of a string, properly capitalized. 58 ** 59 ** Parameters: 60 ** s -- the string to capitalize. 61 ** 62 ** Returns: 63 ** a pointer to a properly capitalized string. 64 ** 65 ** Side Effects: 66 ** none. 67 */ 68 69 char * 70 capitalize(s) 71 register char *s; 72 { 73 static char buf[50]; 74 register char *p; 75 76 p = buf; 77 78 for (;;) 79 { 80 while (!(isascii(*s) && isalpha(*s)) && *s != '\0') 81 *p++ = *s++; 82 if (*s == '\0') 83 break; 84 *p++ = toupper(*s); 85 s++; 86 while (isascii(*s) && isalpha(*s)) 87 *p++ = *s++; 88 } 89 90 *p = '\0'; 91 return (buf); 92 } 93 /* 94 ** XALLOC -- Allocate memory and bitch wildly on failure. 95 ** 96 ** THIS IS A CLUDGE. This should be made to give a proper 97 ** error -- but after all, what can we do? 98 ** 99 ** Parameters: 100 ** sz -- size of area to allocate. 101 ** 102 ** Returns: 103 ** pointer to data region. 104 ** 105 ** Side Effects: 106 ** Memory is allocated. 107 */ 108 109 char * 110 xalloc(sz) 111 register int sz; 112 { 113 register char *p; 114 115 p = malloc((unsigned) sz); 116 if (p == NULL) 117 { 118 syserr("Out of memory!!"); 119 abort(); 120 /* exit(EX_UNAVAILABLE); */ 121 } 122 return (p); 123 } 124 /* 125 ** COPYPLIST -- copy list of pointers. 126 ** 127 ** This routine is the equivalent of newstr for lists of 128 ** pointers. 129 ** 130 ** Parameters: 131 ** list -- list of pointers to copy. 132 ** Must be NULL terminated. 133 ** copycont -- if TRUE, copy the contents of the vector 134 ** (which must be a string) also. 135 ** 136 ** Returns: 137 ** a copy of 'list'. 138 ** 139 ** Side Effects: 140 ** none. 141 */ 142 143 char ** 144 copyplist(list, copycont) 145 char **list; 146 bool copycont; 147 { 148 register char **vp; 149 register char **newvp; 150 151 for (vp = list; *vp != NULL; vp++) 152 continue; 153 154 vp++; 155 156 newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); 157 bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); 158 159 if (copycont) 160 { 161 for (vp = newvp; *vp != NULL; vp++) 162 *vp = newstr(*vp); 163 } 164 165 return (newvp); 166 } 167 /* 168 ** COPYQUEUE -- copy address queue. 169 ** 170 ** This routine is the equivalent of newstr for address queues 171 ** addresses marked with QDONTSEND aren't copied 172 ** 173 ** Parameters: 174 ** addr -- list of address structures to copy. 175 ** 176 ** Returns: 177 ** a copy of 'addr'. 178 ** 179 ** Side Effects: 180 ** none. 181 */ 182 183 ADDRESS * 184 copyqueue(addr) 185 ADDRESS *addr; 186 { 187 register ADDRESS *newaddr; 188 ADDRESS *ret; 189 register ADDRESS **tail = &ret; 190 191 while (addr != NULL) 192 { 193 if (!bitset(QDONTSEND, addr->q_flags)) 194 { 195 newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS)); 196 STRUCTCOPY(*addr, *newaddr); 197 *tail = newaddr; 198 tail = &newaddr->q_next; 199 } 200 addr = addr->q_next; 201 } 202 *tail = NULL; 203 204 return ret; 205 } 206 /* 207 ** PRINTAV -- print argument vector. 208 ** 209 ** Parameters: 210 ** av -- argument vector. 211 ** 212 ** Returns: 213 ** none. 214 ** 215 ** Side Effects: 216 ** prints av. 217 */ 218 219 printav(av) 220 register char **av; 221 { 222 while (*av != NULL) 223 { 224 if (tTd(0, 44)) 225 printf("\n\t%08x=", *av); 226 else 227 (void) putchar(' '); 228 xputs(*av++); 229 } 230 (void) putchar('\n'); 231 } 232 /* 233 ** LOWER -- turn letter into lower case. 234 ** 235 ** Parameters: 236 ** c -- character to turn into lower case. 237 ** 238 ** Returns: 239 ** c, in lower case. 240 ** 241 ** Side Effects: 242 ** none. 243 */ 244 245 char 246 lower(c) 247 register char c; 248 { 249 return((isascii(c) && isupper(c)) ? tolower(c) : c); 250 } 251 /* 252 ** XPUTS -- put string doing control escapes. 253 ** 254 ** Parameters: 255 ** s -- string to put. 256 ** 257 ** Returns: 258 ** none. 259 ** 260 ** Side Effects: 261 ** output to stdout 262 */ 263 264 xputs(s) 265 register char *s; 266 { 267 register int c; 268 register struct metamac *mp; 269 extern struct metamac MetaMacros[]; 270 271 if (s == NULL) 272 { 273 printf("<null>"); 274 return; 275 } 276 while ((c = (*s++ & 0377)) != '\0') 277 { 278 if (!isascii(c)) 279 { 280 if (c == MATCHREPL || c == MACROEXPAND) 281 { 282 putchar('$'); 283 continue; 284 } 285 for (mp = MetaMacros; mp->metaname != '\0'; mp++) 286 { 287 if ((mp->metaval & 0377) == c) 288 { 289 printf("$%c", mp->metaname); 290 break; 291 } 292 } 293 if (mp->metaname != '\0') 294 continue; 295 (void) putchar('\\'); 296 c &= 0177; 297 } 298 if (isprint(c)) 299 { 300 putchar(c); 301 continue; 302 } 303 304 /* wasn't a meta-macro -- find another way to print it */ 305 switch (c) 306 { 307 case '\0': 308 continue; 309 310 case '\n': 311 c = 'n'; 312 break; 313 314 case '\r': 315 c = 'r'; 316 break; 317 318 case '\t': 319 c = 't'; 320 break; 321 322 default: 323 (void) putchar('^'); 324 (void) putchar(c ^ 0100); 325 continue; 326 } 327 } 328 (void) fflush(stdout); 329 } 330 /* 331 ** MAKELOWER -- Translate a line into lower case 332 ** 333 ** Parameters: 334 ** p -- the string to translate. If NULL, return is 335 ** immediate. 336 ** 337 ** Returns: 338 ** none. 339 ** 340 ** Side Effects: 341 ** String pointed to by p is translated to lower case. 342 ** 343 ** Called By: 344 ** parse 345 */ 346 347 makelower(p) 348 register char *p; 349 { 350 register char c; 351 352 if (p == NULL) 353 return; 354 for (; (c = *p) != '\0'; p++) 355 if (isascii(c) && isupper(c)) 356 *p = tolower(c); 357 } 358 /* 359 ** BUILDFNAME -- build full name from gecos style entry. 360 ** 361 ** This routine interprets the strange entry that would appear 362 ** in the GECOS field of the password file. 363 ** 364 ** Parameters: 365 ** p -- name to build. 366 ** login -- the login name of this user (for &). 367 ** buf -- place to put the result. 368 ** 369 ** Returns: 370 ** none. 371 ** 372 ** Side Effects: 373 ** none. 374 */ 375 376 buildfname(gecos, login, buf) 377 register char *gecos; 378 char *login; 379 char *buf; 380 { 381 register char *p; 382 register char *bp = buf; 383 int l; 384 385 if (*gecos == '*') 386 gecos++; 387 388 /* find length of final string */ 389 l = 0; 390 for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 391 { 392 if (*p == '&') 393 l += strlen(login); 394 else 395 l++; 396 } 397 398 /* now fill in buf */ 399 for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 400 { 401 if (*p == '&') 402 { 403 (void) strcpy(bp, login); 404 *bp = toupper(*bp); 405 while (*bp != '\0') 406 bp++; 407 } 408 else 409 *bp++ = *p; 410 } 411 *bp = '\0'; 412 } 413 /* 414 ** SAFEFILE -- return true if a file exists and is safe for a user. 415 ** 416 ** Parameters: 417 ** fn -- filename to check. 418 ** uid -- uid to compare against. 419 ** mode -- mode bits that must match. 420 ** 421 ** Returns: 422 ** 0 if fn exists, is owned by uid, and matches mode. 423 ** An errno otherwise. The actual errno is cleared. 424 ** 425 ** Side Effects: 426 ** none. 427 */ 428 429 int 430 safefile(fn, uid, mode) 431 char *fn; 432 uid_t uid; 433 int mode; 434 { 435 struct stat stbuf; 436 437 if (stat(fn, &stbuf) < 0) 438 { 439 int ret = errno; 440 441 errno = 0; 442 return ret; 443 } 444 if (stbuf.st_uid == uid && (stbuf.st_mode & mode) == mode) 445 return 0; 446 return EPERM; 447 } 448 /* 449 ** FIXCRLF -- fix <CR><LF> in line. 450 ** 451 ** Looks for the <CR><LF> combination and turns it into the 452 ** UNIX canonical <NL> character. It only takes one line, 453 ** i.e., it is assumed that the first <NL> found is the end 454 ** of the line. 455 ** 456 ** Parameters: 457 ** line -- the line to fix. 458 ** stripnl -- if true, strip the newline also. 459 ** 460 ** Returns: 461 ** none. 462 ** 463 ** Side Effects: 464 ** line is changed in place. 465 */ 466 467 fixcrlf(line, stripnl) 468 char *line; 469 bool stripnl; 470 { 471 register char *p; 472 473 p = strchr(line, '\n'); 474 if (p == NULL) 475 return; 476 if (p > line && p[-1] == '\r') 477 p--; 478 if (!stripnl) 479 *p++ = '\n'; 480 *p = '\0'; 481 } 482 /* 483 ** DFOPEN -- determined file open 484 ** 485 ** This routine has the semantics of fopen, except that it will 486 ** keep trying a few times to make this happen. The idea is that 487 ** on very loaded systems, we may run out of resources (inodes, 488 ** whatever), so this tries to get around it. 489 */ 490 491 FILE * 492 dfopen(filename, mode) 493 char *filename; 494 char *mode; 495 { 496 register int tries; 497 register FILE *fp; 498 499 for (tries = 0; tries < 10; tries++) 500 { 501 sleep((unsigned) (10 * tries)); 502 errno = 0; 503 fp = fopen(filename, mode); 504 if (fp != NULL) 505 break; 506 if (errno != ENFILE && errno != EINTR) 507 break; 508 } 509 if (fp != NULL) 510 { 511 #ifdef FLOCK 512 int locktype; 513 514 /* lock the file to avoid accidental conflicts */ 515 if (*mode == 'w' || *mode == 'a') 516 locktype = LOCK_EX; 517 else 518 locktype = LOCK_SH; 519 (void) flock(fileno(fp), locktype); 520 #endif 521 errno = 0; 522 } 523 return (fp); 524 } 525 /* 526 ** PUTLINE -- put a line like fputs obeying SMTP conventions 527 ** 528 ** This routine always guarantees outputing a newline (or CRLF, 529 ** as appropriate) at the end of the string. 530 ** 531 ** Parameters: 532 ** l -- line to put. 533 ** fp -- file to put it onto. 534 ** m -- the mailer used to control output. 535 ** 536 ** Returns: 537 ** none 538 ** 539 ** Side Effects: 540 ** output of l to fp. 541 */ 542 543 putline(l, fp, m) 544 register char *l; 545 FILE *fp; 546 MAILER *m; 547 { 548 register char *p; 549 register char svchar; 550 551 /* strip out 0200 bits -- these can look like TELNET protocol */ 552 if (bitnset(M_7BITS, m->m_flags)) 553 { 554 for (p = l; svchar = *p; ++p) 555 if (svchar & 0200) 556 *p = svchar &~ 0200; 557 } 558 559 do 560 { 561 /* find the end of the line */ 562 p = strchr(l, '\n'); 563 if (p == NULL) 564 p = &l[strlen(l)]; 565 566 /* check for line overflow */ 567 while (m->m_linelimit > 0 && (p - l) > m->m_linelimit) 568 { 569 register char *q = &l[m->m_linelimit - 1]; 570 571 svchar = *q; 572 *q = '\0'; 573 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 574 (void) putc('.', fp); 575 fputs(l, fp); 576 (void) putc('!', fp); 577 fputs(m->m_eol, fp); 578 *q = svchar; 579 l = q; 580 } 581 582 /* output last part */ 583 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 584 (void) putc('.', fp); 585 for ( ; l < p; ++l) 586 (void) putc(*l, fp); 587 fputs(m->m_eol, fp); 588 if (*l == '\n') 589 ++l; 590 } while (l[0] != '\0'); 591 } 592 /* 593 ** XUNLINK -- unlink a file, doing logging as appropriate. 594 ** 595 ** Parameters: 596 ** f -- name of file to unlink. 597 ** 598 ** Returns: 599 ** none. 600 ** 601 ** Side Effects: 602 ** f is unlinked. 603 */ 604 605 xunlink(f) 606 char *f; 607 { 608 register int i; 609 610 # ifdef LOG 611 if (LogLevel > 98) 612 syslog(LOG_DEBUG, "%s: unlink %s", CurEnv->e_id, f); 613 # endif /* LOG */ 614 615 i = unlink(f); 616 # ifdef LOG 617 if (i < 0 && LogLevel > 97) 618 syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 619 # endif /* LOG */ 620 } 621 /* 622 ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 623 ** 624 ** Parameters: 625 ** buf -- place to put the input line. 626 ** siz -- size of buf. 627 ** fp -- file to read from. 628 ** timeout -- the timeout before error occurs. 629 ** 630 ** Returns: 631 ** NULL on error (including timeout). This will also leave 632 ** buf containing a null string. 633 ** buf otherwise. 634 ** 635 ** Side Effects: 636 ** none. 637 */ 638 639 static jmp_buf CtxReadTimeout; 640 641 char * 642 sfgets(buf, siz, fp, timeout) 643 char *buf; 644 int siz; 645 FILE *fp; 646 time_t timeout; 647 { 648 register EVENT *ev = NULL; 649 register char *p; 650 static int readtimeout(); 651 652 /* set the timeout */ 653 if (timeout != 0) 654 { 655 if (setjmp(CtxReadTimeout) != 0) 656 { 657 # ifdef LOG 658 syslog(LOG_NOTICE, 659 "timeout waiting for input from %s\n", 660 CurHostName? CurHostName: "local"); 661 # endif 662 errno = 0; 663 usrerr("451 timeout waiting for input"); 664 buf[0] = '\0'; 665 return (NULL); 666 } 667 ev = setevent(timeout, readtimeout, 0); 668 } 669 670 /* try to read */ 671 p = NULL; 672 while (p == NULL && !feof(fp) && !ferror(fp)) 673 { 674 errno = 0; 675 p = fgets(buf, siz, fp); 676 if (errno == EINTR) 677 clearerr(fp); 678 } 679 680 /* clear the event if it has not sprung */ 681 clrevent(ev); 682 683 /* clean up the books and exit */ 684 LineNumber++; 685 if (p == NULL) 686 { 687 buf[0] = '\0'; 688 return (NULL); 689 } 690 if (!EightBit) 691 for (p = buf; *p != '\0'; p++) 692 *p &= ~0200; 693 return (buf); 694 } 695 696 static 697 readtimeout() 698 { 699 longjmp(CtxReadTimeout, 1); 700 } 701 /* 702 ** FGETFOLDED -- like fgets, but know about folded lines. 703 ** 704 ** Parameters: 705 ** buf -- place to put result. 706 ** n -- bytes available. 707 ** f -- file to read from. 708 ** 709 ** Returns: 710 ** input line(s) on success, NULL on error or EOF. 711 ** This will normally be buf -- unless the line is too 712 ** long, when it will be xalloc()ed. 713 ** 714 ** Side Effects: 715 ** buf gets lines from f, with continuation lines (lines 716 ** with leading white space) appended. CRLF's are mapped 717 ** into single newlines. Any trailing NL is stripped. 718 */ 719 720 char * 721 fgetfolded(buf, n, f) 722 char *buf; 723 register int n; 724 FILE *f; 725 { 726 register char *p = buf; 727 char *bp = buf; 728 register int i; 729 730 n--; 731 while ((i = getc(f)) != EOF) 732 { 733 if (i == '\r') 734 { 735 i = getc(f); 736 if (i != '\n') 737 { 738 if (i != EOF) 739 (void) ungetc(i, f); 740 i = '\r'; 741 } 742 } 743 if (--n <= 0) 744 { 745 /* allocate new space */ 746 char *nbp; 747 int nn; 748 749 nn = (p - bp); 750 if (nn < MEMCHUNKSIZE) 751 nn *= 2; 752 else 753 nn += MEMCHUNKSIZE; 754 nbp = xalloc(nn); 755 bcopy(bp, nbp, p - bp); 756 p = &nbp[p - bp]; 757 if (bp != buf) 758 free(bp); 759 bp = nbp; 760 n = nn - (p - bp); 761 } 762 *p++ = i; 763 if (i == '\n') 764 { 765 LineNumber++; 766 i = getc(f); 767 if (i != EOF) 768 (void) ungetc(i, f); 769 if (i != ' ' && i != '\t') 770 break; 771 } 772 } 773 if (p == bp) 774 return (NULL); 775 *--p = '\0'; 776 return (bp); 777 } 778 /* 779 ** CURTIME -- return current time. 780 ** 781 ** Parameters: 782 ** none. 783 ** 784 ** Returns: 785 ** the current time. 786 ** 787 ** Side Effects: 788 ** none. 789 */ 790 791 time_t 792 curtime() 793 { 794 auto time_t t; 795 796 (void) time(&t); 797 return (t); 798 } 799 /* 800 ** ATOBOOL -- convert a string representation to boolean. 801 ** 802 ** Defaults to "TRUE" 803 ** 804 ** Parameters: 805 ** s -- string to convert. Takes "tTyY" as true, 806 ** others as false. 807 ** 808 ** Returns: 809 ** A boolean representation of the string. 810 ** 811 ** Side Effects: 812 ** none. 813 */ 814 815 bool 816 atobool(s) 817 register char *s; 818 { 819 if (*s == '\0' || strchr("tTyY", *s) != NULL) 820 return (TRUE); 821 return (FALSE); 822 } 823 /* 824 ** ATOOCT -- convert a string representation to octal. 825 ** 826 ** Parameters: 827 ** s -- string to convert. 828 ** 829 ** Returns: 830 ** An integer representing the string interpreted as an 831 ** octal number. 832 ** 833 ** Side Effects: 834 ** none. 835 */ 836 837 atooct(s) 838 register char *s; 839 { 840 register int i = 0; 841 842 while (*s >= '0' && *s <= '7') 843 i = (i << 3) | (*s++ - '0'); 844 return (i); 845 } 846 /* 847 ** WAITFOR -- wait for a particular process id. 848 ** 849 ** Parameters: 850 ** pid -- process id to wait for. 851 ** 852 ** Returns: 853 ** status of pid. 854 ** -1 if pid never shows up. 855 ** 856 ** Side Effects: 857 ** none. 858 */ 859 860 waitfor(pid) 861 int pid; 862 { 863 auto int st; 864 int i; 865 866 do 867 { 868 errno = 0; 869 i = wait(&st); 870 } while ((i >= 0 || errno == EINTR) && i != pid); 871 if (i < 0) 872 st = -1; 873 return (st); 874 } 875 /* 876 ** BITINTERSECT -- tell if two bitmaps intersect 877 ** 878 ** Parameters: 879 ** a, b -- the bitmaps in question 880 ** 881 ** Returns: 882 ** TRUE if they have a non-null intersection 883 ** FALSE otherwise 884 ** 885 ** Side Effects: 886 ** none. 887 */ 888 889 bool 890 bitintersect(a, b) 891 BITMAP a; 892 BITMAP b; 893 { 894 int i; 895 896 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 897 if ((a[i] & b[i]) != 0) 898 return (TRUE); 899 return (FALSE); 900 } 901 /* 902 ** BITZEROP -- tell if a bitmap is all zero 903 ** 904 ** Parameters: 905 ** map -- the bit map to check 906 ** 907 ** Returns: 908 ** TRUE if map is all zero. 909 ** FALSE if there are any bits set in map. 910 ** 911 ** Side Effects: 912 ** none. 913 */ 914 915 bool 916 bitzerop(map) 917 BITMAP map; 918 { 919 int i; 920 921 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 922 if (map[i] != 0) 923 return (FALSE); 924 return (TRUE); 925 } 926 /* 927 ** STRCONTAINEDIN -- tell if one string is contained in another 928 ** 929 ** Parameters: 930 ** a -- possible substring. 931 ** b -- possible superstring. 932 ** 933 ** Returns: 934 ** TRUE if a is contained in b. 935 ** FALSE otherwise. 936 */ 937 938 bool 939 strcontainedin(a, b) 940 register char *a; 941 register char *b; 942 { 943 int l; 944 945 l = strlen(a); 946 for (;;) 947 { 948 b = strchr(b, a[0]); 949 if (b == NULL) 950 return FALSE; 951 if (strncmp(a, b, l) == 0) 952 return TRUE; 953 b++; 954 } 955 } 956 /* 957 ** TRANSIENTERROR -- tell if an error code indicates a transient failure 958 ** 959 ** This looks at an errno value and tells if this is likely to 960 ** go away if retried later. 961 ** 962 ** Parameters: 963 ** err -- the errno code to classify. 964 ** 965 ** Returns: 966 ** TRUE if this is probably transient. 967 ** FALSE otherwise. 968 */ 969 970 bool 971 transienterror(err) 972 int err; 973 { 974 switch (err) 975 { 976 case EIO: /* I/O error */ 977 case ENXIO: /* Device not configured */ 978 case EAGAIN: /* Resource temporarily unavailable */ 979 case ENOMEM: /* Cannot allocate memory */ 980 case ENODEV: /* Operation not supported by device */ 981 case ENFILE: /* Too many open files in system */ 982 case EMFILE: /* Too many open files */ 983 case ENOSPC: /* No space left on device */ 984 #ifdef ETIMEDOUT 985 case ETIMEDOUT: /* Connection timed out */ 986 #endif 987 #ifdef ESTALE 988 case ESTALE: /* Stale NFS file handle */ 989 #endif 990 #ifdef ENETDOWN 991 case ENETDOWN: /* Network is down */ 992 #endif 993 #ifdef ENETUNREACH 994 case ENETUNREACH: /* Network is unreachable */ 995 #endif 996 #ifdef ENETRESET 997 case ENETRESET: /* Network dropped connection on reset */ 998 #endif 999 #ifdef ECONNABORTED 1000 case ECONNABORTED: /* Software caused connection abort */ 1001 #endif 1002 #ifdef ECONNRESET 1003 case ECONNRESET: /* Connection reset by peer */ 1004 #endif 1005 #ifdef ENOBUFS 1006 case ENOBUFS: /* No buffer space available */ 1007 #endif 1008 #ifdef ESHUTDOWN 1009 case ESHUTDOWN: /* Can't send after socket shutdown */ 1010 #endif 1011 #ifdef ECONNREFUSED 1012 case ECONNREFUSED: /* Connection refused */ 1013 #endif 1014 #ifdef EHOSTDOWN 1015 case EHOSTDOWN: /* Host is down */ 1016 #endif 1017 #ifdef EHOSTUNREACH 1018 case EHOSTUNREACH: /* No route to host */ 1019 #endif 1020 #ifdef EDQUOT 1021 case EDQUOT: /* Disc quota exceeded */ 1022 #endif 1023 #ifdef EPROCLIM 1024 case EPROCLIM: /* Too many processes */ 1025 #endif 1026 #ifdef EUSERS 1027 case EUSERS: /* Too many users */ 1028 #endif 1029 #ifdef EDEADLK 1030 case EDEADLK: /* Resource deadlock avoided */ 1031 #endif 1032 return TRUE; 1033 } 1034 1035 /* nope, must be permanent */ 1036 return FALSE; 1037 } 1038