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