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.16 (Berkeley) 11/08/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 -- user id to compare against. 381 ** gid -- group id to compare against. 382 ** uname -- user name to compare against (used for group 383 ** sets). 384 ** mustown -- to be safe, this uid must own the file. 385 ** mode -- mode bits that must match. 386 ** 387 ** Returns: 388 ** 0 if fn exists, is owned by uid, and matches mode. 389 ** An errno otherwise. The actual errno is cleared. 390 ** 391 ** Side Effects: 392 ** none. 393 */ 394 395 #include <grp.h> 396 397 #ifndef S_IXOTH 398 # define S_IXOTH (S_IEXEC >> 6) 399 #endif 400 401 #ifndef S_IXGRP 402 # define S_IXGRP (S_IEXEC >> 3) 403 #endif 404 405 #ifndef S_IXUSR 406 # define S_IXUSR (S_IEXEC) 407 #endif 408 409 int 410 safefile(fn, uid, gid, uname, mustown, mode) 411 char *fn; 412 uid_t uid; 413 gid_t gid; 414 char *uname; 415 bool mustown; 416 int mode; 417 { 418 register char *p; 419 register struct group *gr = NULL; 420 struct stat stbuf; 421 422 if (tTd(54, 4)) 423 printf("safefile(%s, uid=%d, gid=%d, mustown=%d, mode=%o):\n", 424 fn, uid, gid, mustown, mode); 425 errno = 0; 426 427 for (p = fn; (p = strchr(++p, '/')) != NULL; *p = '/') 428 { 429 *p = '\0'; 430 if (stat(fn, &stbuf) < 0) 431 break; 432 if (stbuf.st_uid == uid && bitset(S_IXUSR, stbuf.st_mode)) 433 continue; 434 if (stbuf.st_gid == gid && bitset(S_IXGRP, stbuf.st_mode)) 435 continue; 436 #ifndef NO_GROUP_SET 437 if (uname != NULL && 438 ((gr != NULL && gr->gr_gid == stbuf.st_gid) || 439 (gr = getgrgid(stbuf.st_gid)) != NULL)) 440 { 441 register char **gp; 442 443 for (gp = gr->gr_mem; *gp != NULL; gp++) 444 if (strcmp(*gp, uname) == 0) 445 break; 446 if (*gp != NULL && bitset(S_IXGRP, stbuf.st_mode)) 447 continue; 448 } 449 #endif 450 if (!bitset(S_IXOTH, stbuf.st_mode)) 451 break; 452 } 453 if (p != NULL) 454 { 455 int ret = errno; 456 457 if (ret == 0) 458 ret = EACCES; 459 if (tTd(54, 4)) 460 printf("\t[dir %s] %s\n", fn, errstring(ret)); 461 *p = '/'; 462 return ret; 463 } 464 465 if (stat(fn, &stbuf) < 0) 466 { 467 int ret = errno; 468 469 if (tTd(54, 4)) 470 printf("\t%s\n", errstring(ret)); 471 472 errno = 0; 473 return ret; 474 } 475 if (uid == 0) 476 mode >>= 6; 477 else if (stbuf.st_uid != uid) 478 { 479 mode >>= 3; 480 if (stbuf.st_gid == gid) 481 ; 482 #ifndef NO_GROUP_SET 483 else if (uname != NULL && 484 ((gr != NULL && gr->gr_gid == stbuf.st_gid) || 485 (gr = getgrgid(stbuf.st_gid)) != NULL)) 486 { 487 register char **gp; 488 489 for (gp = gr->gr_mem; *gp != NULL; gp++) 490 if (strcmp(*gp, uname) == 0) 491 break; 492 if (*gp == NULL) 493 mode >>= 3; 494 } 495 #endif 496 else 497 mode >>= 3; 498 } 499 if (tTd(54, 4)) 500 printf("\t[uid %d, stat %o, mode %o] ", 501 stbuf.st_uid, stbuf.st_mode, mode); 502 if ((stbuf.st_uid == uid || stbuf.st_uid == 0 || !mustown) && 503 (stbuf.st_mode & mode) == mode) 504 { 505 if (tTd(54, 4)) 506 printf("\tOK\n"); 507 return 0; 508 } 509 if (tTd(54, 4)) 510 printf("\tEACCES\n"); 511 return EACCES; 512 } 513 /* 514 ** FIXCRLF -- fix <CR><LF> in line. 515 ** 516 ** Looks for the <CR><LF> combination and turns it into the 517 ** UNIX canonical <NL> character. It only takes one line, 518 ** i.e., it is assumed that the first <NL> found is the end 519 ** of the line. 520 ** 521 ** Parameters: 522 ** line -- the line to fix. 523 ** stripnl -- if true, strip the newline also. 524 ** 525 ** Returns: 526 ** none. 527 ** 528 ** Side Effects: 529 ** line is changed in place. 530 */ 531 532 fixcrlf(line, stripnl) 533 char *line; 534 bool stripnl; 535 { 536 register char *p; 537 538 p = strchr(line, '\n'); 539 if (p == NULL) 540 return; 541 if (p > line && p[-1] == '\r') 542 p--; 543 if (!stripnl) 544 *p++ = '\n'; 545 *p = '\0'; 546 } 547 /* 548 ** DFOPEN -- determined file open 549 ** 550 ** This routine has the semantics of fopen, except that it will 551 ** keep trying a few times to make this happen. The idea is that 552 ** on very loaded systems, we may run out of resources (inodes, 553 ** whatever), so this tries to get around it. 554 */ 555 556 #ifndef O_ACCMODE 557 # define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) 558 #endif 559 560 struct omodes 561 { 562 int mask; 563 int mode; 564 char *farg; 565 } OpenModes[] = 566 { 567 O_ACCMODE, O_RDONLY, "r", 568 O_ACCMODE|O_APPEND, O_WRONLY, "w", 569 O_ACCMODE|O_APPEND, O_WRONLY|O_APPEND, "a", 570 O_TRUNC, 0, "w+", 571 O_APPEND, O_APPEND, "a+", 572 0, 0, "r+", 573 }; 574 575 FILE * 576 dfopen(filename, omode, cmode) 577 char *filename; 578 int omode; 579 int cmode; 580 { 581 register int tries; 582 int fd; 583 register struct omodes *om; 584 struct stat st; 585 586 for (om = OpenModes; om->mask != 0; om++) 587 if ((omode & om->mask) == om->mode) 588 break; 589 590 for (tries = 0; tries < 10; tries++) 591 { 592 sleep((unsigned) (10 * tries)); 593 errno = 0; 594 fd = open(filename, omode, cmode); 595 if (fd >= 0) 596 break; 597 if (errno != ENFILE && errno != EINTR) 598 break; 599 } 600 if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) 601 { 602 int locktype; 603 604 /* lock the file to avoid accidental conflicts */ 605 if ((omode & O_ACCMODE) != O_RDONLY) 606 locktype = LOCK_EX; 607 else 608 locktype = LOCK_SH; 609 (void) lockfile(fd, filename, NULL, locktype); 610 errno = 0; 611 } 612 if (fd < 0) 613 return NULL; 614 else 615 return fdopen(fd, om->farg); 616 } 617 /* 618 ** PUTLINE -- put a line like fputs obeying SMTP conventions 619 ** 620 ** This routine always guarantees outputing a newline (or CRLF, 621 ** as appropriate) at the end of the string. 622 ** 623 ** Parameters: 624 ** l -- line to put. 625 ** fp -- file to put it onto. 626 ** m -- the mailer used to control output. 627 ** 628 ** Returns: 629 ** none 630 ** 631 ** Side Effects: 632 ** output of l to fp. 633 */ 634 635 putline(l, fp, m) 636 register char *l; 637 FILE *fp; 638 MAILER *m; 639 { 640 register char *p; 641 register char svchar; 642 643 /* strip out 0200 bits -- these can look like TELNET protocol */ 644 if (bitnset(M_7BITS, m->m_flags)) 645 { 646 for (p = l; (svchar = *p) != '\0'; ++p) 647 if (bitset(0200, svchar)) 648 *p = svchar &~ 0200; 649 } 650 651 do 652 { 653 /* find the end of the line */ 654 p = strchr(l, '\n'); 655 if (p == NULL) 656 p = &l[strlen(l)]; 657 658 if (TrafficLogFile != NULL) 659 fprintf(TrafficLogFile, "%05d >>> ", getpid()); 660 661 /* check for line overflow */ 662 while (m->m_linelimit > 0 && (p - l) > m->m_linelimit) 663 { 664 register char *q = &l[m->m_linelimit - 1]; 665 666 svchar = *q; 667 *q = '\0'; 668 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 669 { 670 (void) putc('.', fp); 671 if (TrafficLogFile != NULL) 672 (void) putc('.', TrafficLogFile); 673 } 674 fputs(l, fp); 675 (void) putc('!', fp); 676 fputs(m->m_eol, fp); 677 if (TrafficLogFile != NULL) 678 fprintf(TrafficLogFile, "%s!\n%05d >>> ", 679 l, getpid()); 680 *q = svchar; 681 l = q; 682 } 683 684 /* output last part */ 685 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 686 { 687 (void) putc('.', fp); 688 if (TrafficLogFile != NULL) 689 (void) putc('.', TrafficLogFile); 690 } 691 if (TrafficLogFile != NULL) 692 fprintf(TrafficLogFile, "%.*s\n", p - l, l); 693 for ( ; l < p; ++l) 694 (void) putc(*l, fp); 695 fputs(m->m_eol, fp); 696 if (*l == '\n') 697 ++l; 698 } while (l[0] != '\0'); 699 } 700 /* 701 ** XUNLINK -- unlink a file, doing logging as appropriate. 702 ** 703 ** Parameters: 704 ** f -- name of file to unlink. 705 ** 706 ** Returns: 707 ** none. 708 ** 709 ** Side Effects: 710 ** f is unlinked. 711 */ 712 713 xunlink(f) 714 char *f; 715 { 716 register int i; 717 718 # ifdef LOG 719 if (LogLevel > 98) 720 syslog(LOG_DEBUG, "%s: unlink %s", CurEnv->e_id, f); 721 # endif /* LOG */ 722 723 i = unlink(f); 724 # ifdef LOG 725 if (i < 0 && LogLevel > 97) 726 syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 727 # endif /* LOG */ 728 } 729 /* 730 ** XFCLOSE -- close a file, doing logging as appropriate. 731 ** 732 ** Parameters: 733 ** fp -- file pointer for the file to close 734 ** a, b -- miscellaneous crud to print for debugging 735 ** 736 ** Returns: 737 ** none. 738 ** 739 ** Side Effects: 740 ** fp is closed. 741 */ 742 743 xfclose(fp, a, b) 744 FILE *fp; 745 char *a, *b; 746 { 747 if (tTd(53, 99)) 748 printf("xfclose(%x) %s %s\n", fp, a, b); 749 #ifdef XDEBUG 750 if (fileno(fp) == 1) 751 syserr("xfclose(%s %s): fd = 1", a, b); 752 #endif 753 if (fclose(fp) < 0 && tTd(53, 99)) 754 printf("xfclose FAILURE: %s\n", errstring(errno)); 755 } 756 /* 757 ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 758 ** 759 ** Parameters: 760 ** buf -- place to put the input line. 761 ** siz -- size of buf. 762 ** fp -- file to read from. 763 ** timeout -- the timeout before error occurs. 764 ** during -- what we are trying to read (for error messages). 765 ** 766 ** Returns: 767 ** NULL on error (including timeout). This will also leave 768 ** buf containing a null string. 769 ** buf otherwise. 770 ** 771 ** Side Effects: 772 ** none. 773 */ 774 775 static jmp_buf CtxReadTimeout; 776 static int readtimeout(); 777 778 char * 779 sfgets(buf, siz, fp, timeout, during) 780 char *buf; 781 int siz; 782 FILE *fp; 783 time_t timeout; 784 char *during; 785 { 786 register EVENT *ev = NULL; 787 register char *p; 788 789 /* set the timeout */ 790 if (timeout != 0) 791 { 792 if (setjmp(CtxReadTimeout) != 0) 793 { 794 # ifdef LOG 795 syslog(LOG_NOTICE, 796 "timeout waiting for input from %s during %s\n", 797 CurHostName? CurHostName: "local", during); 798 # endif 799 errno = 0; 800 usrerr("451 timeout waiting for input during %s", 801 during); 802 buf[0] = '\0'; 803 #ifdef XDEBUG 804 checkfd012(during); 805 #endif 806 return (NULL); 807 } 808 ev = setevent(timeout, readtimeout, 0); 809 } 810 811 /* try to read */ 812 p = NULL; 813 while (p == NULL && !feof(fp) && !ferror(fp)) 814 { 815 errno = 0; 816 p = fgets(buf, siz, fp); 817 if (errno == EINTR) 818 clearerr(fp); 819 } 820 821 /* clear the event if it has not sprung */ 822 clrevent(ev); 823 824 /* clean up the books and exit */ 825 LineNumber++; 826 if (p == NULL) 827 { 828 buf[0] = '\0'; 829 if (TrafficLogFile != NULL) 830 fprintf(TrafficLogFile, "%05d <<< [EOF]\n", getpid()); 831 return (NULL); 832 } 833 if (TrafficLogFile != NULL) 834 fprintf(TrafficLogFile, "%05d <<< %s", getpid(), buf); 835 if (SevenBit) 836 for (p = buf; *p != '\0'; p++) 837 *p &= ~0200; 838 return (buf); 839 } 840 841 static 842 readtimeout() 843 { 844 longjmp(CtxReadTimeout, 1); 845 } 846 /* 847 ** FGETFOLDED -- like fgets, but know about folded lines. 848 ** 849 ** Parameters: 850 ** buf -- place to put result. 851 ** n -- bytes available. 852 ** f -- file to read from. 853 ** 854 ** Returns: 855 ** input line(s) on success, NULL on error or EOF. 856 ** This will normally be buf -- unless the line is too 857 ** long, when it will be xalloc()ed. 858 ** 859 ** Side Effects: 860 ** buf gets lines from f, with continuation lines (lines 861 ** with leading white space) appended. CRLF's are mapped 862 ** into single newlines. Any trailing NL is stripped. 863 */ 864 865 char * 866 fgetfolded(buf, n, f) 867 char *buf; 868 register int n; 869 FILE *f; 870 { 871 register char *p = buf; 872 char *bp = buf; 873 register int i; 874 875 n--; 876 while ((i = getc(f)) != EOF) 877 { 878 if (i == '\r') 879 { 880 i = getc(f); 881 if (i != '\n') 882 { 883 if (i != EOF) 884 (void) ungetc(i, f); 885 i = '\r'; 886 } 887 } 888 if (--n <= 0) 889 { 890 /* allocate new space */ 891 char *nbp; 892 int nn; 893 894 nn = (p - bp); 895 if (nn < MEMCHUNKSIZE) 896 nn *= 2; 897 else 898 nn += MEMCHUNKSIZE; 899 nbp = xalloc(nn); 900 bcopy(bp, nbp, p - bp); 901 p = &nbp[p - bp]; 902 if (bp != buf) 903 free(bp); 904 bp = nbp; 905 n = nn - (p - bp); 906 } 907 *p++ = i; 908 if (i == '\n') 909 { 910 LineNumber++; 911 i = getc(f); 912 if (i != EOF) 913 (void) ungetc(i, f); 914 if (i != ' ' && i != '\t') 915 break; 916 } 917 } 918 if (p == bp) 919 return (NULL); 920 *--p = '\0'; 921 return (bp); 922 } 923 /* 924 ** CURTIME -- return current time. 925 ** 926 ** Parameters: 927 ** none. 928 ** 929 ** Returns: 930 ** the current time. 931 ** 932 ** Side Effects: 933 ** none. 934 */ 935 936 time_t 937 curtime() 938 { 939 auto time_t t; 940 941 (void) time(&t); 942 return (t); 943 } 944 /* 945 ** ATOBOOL -- convert a string representation to boolean. 946 ** 947 ** Defaults to "TRUE" 948 ** 949 ** Parameters: 950 ** s -- string to convert. Takes "tTyY" as true, 951 ** others as false. 952 ** 953 ** Returns: 954 ** A boolean representation of the string. 955 ** 956 ** Side Effects: 957 ** none. 958 */ 959 960 bool 961 atobool(s) 962 register char *s; 963 { 964 if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL) 965 return (TRUE); 966 return (FALSE); 967 } 968 /* 969 ** ATOOCT -- convert a string representation to octal. 970 ** 971 ** Parameters: 972 ** s -- string to convert. 973 ** 974 ** Returns: 975 ** An integer representing the string interpreted as an 976 ** octal number. 977 ** 978 ** Side Effects: 979 ** none. 980 */ 981 982 atooct(s) 983 register char *s; 984 { 985 register int i = 0; 986 987 while (*s >= '0' && *s <= '7') 988 i = (i << 3) | (*s++ - '0'); 989 return (i); 990 } 991 /* 992 ** WAITFOR -- wait for a particular process id. 993 ** 994 ** Parameters: 995 ** pid -- process id to wait for. 996 ** 997 ** Returns: 998 ** status of pid. 999 ** -1 if pid never shows up. 1000 ** 1001 ** Side Effects: 1002 ** none. 1003 */ 1004 1005 int 1006 waitfor(pid) 1007 int pid; 1008 { 1009 #ifdef WAITUNION 1010 union wait st; 1011 #else 1012 auto int st; 1013 #endif 1014 int i; 1015 1016 do 1017 { 1018 errno = 0; 1019 i = wait(&st); 1020 } while ((i >= 0 || errno == EINTR) && i != pid); 1021 if (i < 0) 1022 return -1; 1023 #ifdef WAITUNION 1024 return st.w_status; 1025 #else 1026 return st; 1027 #endif 1028 } 1029 /* 1030 ** BITINTERSECT -- tell if two bitmaps intersect 1031 ** 1032 ** Parameters: 1033 ** a, b -- the bitmaps in question 1034 ** 1035 ** Returns: 1036 ** TRUE if they have a non-null intersection 1037 ** FALSE otherwise 1038 ** 1039 ** Side Effects: 1040 ** none. 1041 */ 1042 1043 bool 1044 bitintersect(a, b) 1045 BITMAP a; 1046 BITMAP b; 1047 { 1048 int i; 1049 1050 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 1051 if ((a[i] & b[i]) != 0) 1052 return (TRUE); 1053 return (FALSE); 1054 } 1055 /* 1056 ** BITZEROP -- tell if a bitmap is all zero 1057 ** 1058 ** Parameters: 1059 ** map -- the bit map to check 1060 ** 1061 ** Returns: 1062 ** TRUE if map is all zero. 1063 ** FALSE if there are any bits set in map. 1064 ** 1065 ** Side Effects: 1066 ** none. 1067 */ 1068 1069 bool 1070 bitzerop(map) 1071 BITMAP map; 1072 { 1073 int i; 1074 1075 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 1076 if (map[i] != 0) 1077 return (FALSE); 1078 return (TRUE); 1079 } 1080 /* 1081 ** STRCONTAINEDIN -- tell if one string is contained in another 1082 ** 1083 ** Parameters: 1084 ** a -- possible substring. 1085 ** b -- possible superstring. 1086 ** 1087 ** Returns: 1088 ** TRUE if a is contained in b. 1089 ** FALSE otherwise. 1090 */ 1091 1092 bool 1093 strcontainedin(a, b) 1094 register char *a; 1095 register char *b; 1096 { 1097 int l; 1098 1099 l = strlen(a); 1100 for (;;) 1101 { 1102 b = strchr(b, a[0]); 1103 if (b == NULL) 1104 return FALSE; 1105 if (strncmp(a, b, l) == 0) 1106 return TRUE; 1107 b++; 1108 } 1109 } 1110 /* 1111 ** CHECKFD012 -- check low numbered file descriptors 1112 ** 1113 ** File descriptors 0, 1, and 2 should be open at all times. 1114 ** This routine verifies that, and fixes it if not true. 1115 ** 1116 ** Parameters: 1117 ** where -- a tag printed if the assertion failed 1118 ** 1119 ** Returns: 1120 ** none 1121 */ 1122 1123 checkfd012(where) 1124 char *where; 1125 { 1126 #ifdef XDEBUG 1127 register int i; 1128 struct stat stbuf; 1129 1130 for (i = 0; i < 3; i++) 1131 { 1132 if (fstat(i, &stbuf) < 0 && errno != EOPNOTSUPP) 1133 { 1134 /* oops.... */ 1135 int fd; 1136 1137 syserr("%s: fd %d not open", where, i); 1138 fd = open("/dev/null", i == 0 ? O_RDONLY : O_WRONLY, 0666); 1139 if (fd != i) 1140 { 1141 (void) dup2(fd, i); 1142 (void) close(fd); 1143 } 1144 } 1145 } 1146 #endif /* XDEBUG */ 1147 } 1148 /* 1149 ** PRINTOPENFDS -- print the open file descriptors (for debugging) 1150 ** 1151 ** Parameters: 1152 ** logit -- if set, send output to syslog; otherwise 1153 ** print for debugging. 1154 ** 1155 ** Returns: 1156 ** none. 1157 */ 1158 1159 #include <netdb.h> 1160 #include <arpa/inet.h> 1161 1162 printopenfds(logit) 1163 bool logit; 1164 { 1165 register int fd; 1166 extern int DtableSize; 1167 1168 for (fd = 0; fd < DtableSize; fd++) 1169 dumpfd(fd, FALSE, logit); 1170 } 1171 /* 1172 ** DUMPFD -- dump a file descriptor 1173 ** 1174 ** Parameters: 1175 ** fd -- the file descriptor to dump. 1176 ** printclosed -- if set, print a notification even if 1177 ** it is closed; otherwise print nothing. 1178 ** logit -- if set, send output to syslog instead of stdout. 1179 */ 1180 1181 dumpfd(fd, printclosed, logit) 1182 int fd; 1183 bool printclosed; 1184 bool logit; 1185 { 1186 register struct hostent *hp; 1187 register char *p; 1188 struct sockaddr_in sin; 1189 auto int slen; 1190 struct stat st; 1191 char buf[200]; 1192 1193 p = buf; 1194 sprintf(p, "%3d: ", fd); 1195 p += strlen(p); 1196 1197 if (fstat(fd, &st) < 0) 1198 { 1199 if (printclosed || errno != EBADF) 1200 { 1201 sprintf(p, "CANNOT STAT (%s)", errstring(errno)); 1202 goto printit; 1203 } 1204 return; 1205 } 1206 1207 slen = fcntl(fd, F_GETFL, NULL); 1208 if (slen != -1) 1209 { 1210 sprintf(p, "fl=0x%x, ", slen); 1211 p += strlen(p); 1212 } 1213 1214 sprintf(p, "mode=%o: ", st.st_mode); 1215 p += strlen(p); 1216 switch (st.st_mode & S_IFMT) 1217 { 1218 #ifdef S_IFSOCK 1219 case S_IFSOCK: 1220 sprintf(p, "SOCK "); 1221 p += strlen(p); 1222 slen = sizeof sin; 1223 if (getsockname(fd, (struct sockaddr *) &sin, &slen) < 0) 1224 sprintf(p, "(badsock)"); 1225 else 1226 { 1227 hp = gethostbyaddr((char *) &sin.sin_addr, slen, AF_INET); 1228 sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr) 1229 : hp->h_name, ntohs(sin.sin_port)); 1230 } 1231 p += strlen(p); 1232 sprintf(p, "->"); 1233 p += strlen(p); 1234 slen = sizeof sin; 1235 if (getpeername(fd, (struct sockaddr *) &sin, &slen) < 0) 1236 sprintf(p, "(badsock)"); 1237 else 1238 { 1239 hp = gethostbyaddr((char *) &sin.sin_addr, slen, AF_INET); 1240 sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr) 1241 : hp->h_name, ntohs(sin.sin_port)); 1242 } 1243 break; 1244 #endif 1245 1246 case S_IFCHR: 1247 sprintf(p, "CHR: "); 1248 p += strlen(p); 1249 goto defprint; 1250 1251 case S_IFBLK: 1252 sprintf(p, "BLK: "); 1253 p += strlen(p); 1254 goto defprint; 1255 1256 default: 1257 defprint: 1258 sprintf(p, "dev=%d/%d, ino=%d, nlink=%d, u/gid=%d/%d, size=%ld", 1259 major(st.st_dev), minor(st.st_dev), st.st_ino, 1260 st.st_nlink, st.st_uid, st.st_gid, st.st_size); 1261 break; 1262 } 1263 1264 printit: 1265 if (logit) 1266 syslog(LOG_INFO, "%s", buf); 1267 else 1268 printf("%s\n", buf); 1269 } 1270