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.43 (Berkeley) 08/07/94"; 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 /* some systems can't handle size zero mallocs */ 78 if (sz <= 0) 79 sz = 1; 80 81 p = malloc((unsigned) sz); 82 if (p == NULL) 83 { 84 syserr("Out of memory!!"); 85 abort(); 86 /* exit(EX_UNAVAILABLE); */ 87 } 88 return (p); 89 } 90 /* 91 ** COPYPLIST -- copy list of pointers. 92 ** 93 ** This routine is the equivalent of newstr for lists of 94 ** pointers. 95 ** 96 ** Parameters: 97 ** list -- list of pointers to copy. 98 ** Must be NULL terminated. 99 ** copycont -- if TRUE, copy the contents of the vector 100 ** (which must be a string) also. 101 ** 102 ** Returns: 103 ** a copy of 'list'. 104 ** 105 ** Side Effects: 106 ** none. 107 */ 108 109 char ** 110 copyplist(list, copycont) 111 char **list; 112 bool copycont; 113 { 114 register char **vp; 115 register char **newvp; 116 117 for (vp = list; *vp != NULL; vp++) 118 continue; 119 120 vp++; 121 122 newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); 123 bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); 124 125 if (copycont) 126 { 127 for (vp = newvp; *vp != NULL; vp++) 128 *vp = newstr(*vp); 129 } 130 131 return (newvp); 132 } 133 /* 134 ** COPYQUEUE -- copy address queue. 135 ** 136 ** This routine is the equivalent of newstr for address queues 137 ** addresses marked with QDONTSEND aren't copied 138 ** 139 ** Parameters: 140 ** addr -- list of address structures to copy. 141 ** 142 ** Returns: 143 ** a copy of 'addr'. 144 ** 145 ** Side Effects: 146 ** none. 147 */ 148 149 ADDRESS * 150 copyqueue(addr) 151 ADDRESS *addr; 152 { 153 register ADDRESS *newaddr; 154 ADDRESS *ret; 155 register ADDRESS **tail = &ret; 156 157 while (addr != NULL) 158 { 159 if (!bitset(QDONTSEND, addr->q_flags)) 160 { 161 newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS)); 162 STRUCTCOPY(*addr, *newaddr); 163 *tail = newaddr; 164 tail = &newaddr->q_next; 165 } 166 addr = addr->q_next; 167 } 168 *tail = NULL; 169 170 return ret; 171 } 172 /* 173 ** PRINTAV -- print argument vector. 174 ** 175 ** Parameters: 176 ** av -- argument vector. 177 ** 178 ** Returns: 179 ** none. 180 ** 181 ** Side Effects: 182 ** prints av. 183 */ 184 185 printav(av) 186 register char **av; 187 { 188 while (*av != NULL) 189 { 190 if (tTd(0, 44)) 191 printf("\n\t%08x=", *av); 192 else 193 (void) putchar(' '); 194 xputs(*av++); 195 } 196 (void) putchar('\n'); 197 } 198 /* 199 ** LOWER -- turn letter into lower case. 200 ** 201 ** Parameters: 202 ** c -- character to turn into lower case. 203 ** 204 ** Returns: 205 ** c, in lower case. 206 ** 207 ** Side Effects: 208 ** none. 209 */ 210 211 char 212 lower(c) 213 register char c; 214 { 215 return((isascii(c) && isupper(c)) ? tolower(c) : c); 216 } 217 /* 218 ** XPUTS -- put string doing control escapes. 219 ** 220 ** Parameters: 221 ** s -- string to put. 222 ** 223 ** Returns: 224 ** none. 225 ** 226 ** Side Effects: 227 ** output to stdout 228 */ 229 230 xputs(s) 231 register char *s; 232 { 233 register int c; 234 register struct metamac *mp; 235 extern struct metamac MetaMacros[]; 236 237 if (s == NULL) 238 { 239 printf("<null>"); 240 return; 241 } 242 while ((c = (*s++ & 0377)) != '\0') 243 { 244 if (!isascii(c)) 245 { 246 if (c == MATCHREPL || c == MACROEXPAND) 247 { 248 putchar('$'); 249 continue; 250 } 251 for (mp = MetaMacros; mp->metaname != '\0'; mp++) 252 { 253 if ((mp->metaval & 0377) == c) 254 { 255 printf("$%c", mp->metaname); 256 break; 257 } 258 } 259 if (mp->metaname != '\0') 260 continue; 261 (void) putchar('\\'); 262 c &= 0177; 263 } 264 if (isprint(c)) 265 { 266 putchar(c); 267 continue; 268 } 269 270 /* wasn't a meta-macro -- find another way to print it */ 271 switch (c) 272 { 273 case '\0': 274 continue; 275 276 case '\n': 277 c = 'n'; 278 break; 279 280 case '\r': 281 c = 'r'; 282 break; 283 284 case '\t': 285 c = 't'; 286 break; 287 288 default: 289 (void) putchar('^'); 290 (void) putchar(c ^ 0100); 291 continue; 292 } 293 } 294 (void) fflush(stdout); 295 } 296 /* 297 ** MAKELOWER -- Translate a line into lower case 298 ** 299 ** Parameters: 300 ** p -- the string to translate. If NULL, return is 301 ** immediate. 302 ** 303 ** Returns: 304 ** none. 305 ** 306 ** Side Effects: 307 ** String pointed to by p is translated to lower case. 308 ** 309 ** Called By: 310 ** parse 311 */ 312 313 makelower(p) 314 register char *p; 315 { 316 register char c; 317 318 if (p == NULL) 319 return; 320 for (; (c = *p) != '\0'; p++) 321 if (isascii(c) && isupper(c)) 322 *p = tolower(c); 323 } 324 /* 325 ** BUILDFNAME -- build full name from gecos style entry. 326 ** 327 ** This routine interprets the strange entry that would appear 328 ** in the GECOS field of the password file. 329 ** 330 ** Parameters: 331 ** p -- name to build. 332 ** login -- the login name of this user (for &). 333 ** buf -- place to put the result. 334 ** 335 ** Returns: 336 ** none. 337 ** 338 ** Side Effects: 339 ** none. 340 */ 341 342 buildfname(gecos, login, buf) 343 register char *gecos; 344 char *login; 345 char *buf; 346 { 347 register char *p; 348 register char *bp = buf; 349 int l; 350 351 if (*gecos == '*') 352 gecos++; 353 354 /* find length of final string */ 355 l = 0; 356 for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 357 { 358 if (*p == '&') 359 l += strlen(login); 360 else 361 l++; 362 } 363 364 /* now fill in buf */ 365 for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 366 { 367 if (*p == '&') 368 { 369 (void) strcpy(bp, login); 370 *bp = toupper(*bp); 371 while (*bp != '\0') 372 bp++; 373 } 374 else 375 *bp++ = *p; 376 } 377 *bp = '\0'; 378 } 379 /* 380 ** SAFEFILE -- return true if a file exists and is safe for a user. 381 ** 382 ** Parameters: 383 ** fn -- filename to check. 384 ** uid -- user id to compare against. 385 ** gid -- group id to compare against. 386 ** uname -- user name to compare against (used for group 387 ** sets). 388 ** flags -- modifiers: 389 ** SFF_MUSTOWN -- "uid" must own this file. 390 ** SFF_NOSLINK -- file cannot be a symbolic link. 391 ** mode -- mode bits that must match. 392 ** 393 ** Returns: 394 ** 0 if fn exists, is owned by uid, and matches mode. 395 ** An errno otherwise. The actual errno is cleared. 396 ** 397 ** Side Effects: 398 ** none. 399 */ 400 401 #include <grp.h> 402 403 #ifndef S_IXOTH 404 # define S_IXOTH (S_IEXEC >> 6) 405 #endif 406 407 #ifndef S_IXGRP 408 # define S_IXGRP (S_IEXEC >> 3) 409 #endif 410 411 #ifndef S_IXUSR 412 # define S_IXUSR (S_IEXEC) 413 #endif 414 415 int 416 safefile(fn, uid, gid, uname, flags, mode) 417 char *fn; 418 uid_t uid; 419 gid_t gid; 420 char *uname; 421 int flags; 422 int mode; 423 { 424 register char *p; 425 register struct group *gr = NULL; 426 struct stat stbuf; 427 428 if (tTd(54, 4)) 429 printf("safefile(%s, uid=%d, gid=%d, flags=%x, mode=%o):\n", 430 fn, uid, gid, flags, mode); 431 errno = 0; 432 433 for (p = fn; (p = strchr(++p, '/')) != NULL; *p = '/') 434 { 435 *p = '\0'; 436 if (stat(fn, &stbuf) < 0) 437 break; 438 if (uid == 0 && !bitset(SFF_ROOTOK, flags)) 439 { 440 if (bitset(S_IXOTH, stbuf.st_mode)) 441 continue; 442 break; 443 } 444 if (stbuf.st_uid == uid && bitset(S_IXUSR, stbuf.st_mode)) 445 continue; 446 if (stbuf.st_gid == gid && bitset(S_IXGRP, stbuf.st_mode)) 447 continue; 448 #ifndef NO_GROUP_SET 449 if (uname != NULL && 450 ((gr != NULL && gr->gr_gid == stbuf.st_gid) || 451 (gr = getgrgid(stbuf.st_gid)) != NULL)) 452 { 453 register char **gp; 454 455 for (gp = gr->gr_mem; *gp != NULL; gp++) 456 if (strcmp(*gp, uname) == 0) 457 break; 458 if (*gp != NULL && bitset(S_IXGRP, stbuf.st_mode)) 459 continue; 460 } 461 #endif 462 if (!bitset(S_IXOTH, stbuf.st_mode)) 463 break; 464 } 465 if (p != NULL) 466 { 467 int ret = errno; 468 469 if (ret == 0) 470 ret = EACCES; 471 if (tTd(54, 4)) 472 printf("\t[dir %s] %s\n", fn, errstring(ret)); 473 *p = '/'; 474 return ret; 475 } 476 477 #ifdef HASLSTAT 478 if ((bitset(SFF_NOSLINK, flags) ? lstat(fn, &stbuf) 479 : stat(fn, &stbuf)) < 0) 480 #else 481 if (stat(fn, &stbuf) < 0) 482 #endif 483 { 484 int ret = errno; 485 486 if (tTd(54, 4)) 487 printf("\t%s\n", errstring(ret)); 488 489 errno = 0; 490 return ret; 491 } 492 493 #ifdef S_ISLNK 494 if (bitset(SFF_NOSLINK, flags) && S_ISLNK(stbuf.st_mode)) 495 { 496 if (tTd(54, 4)) 497 printf("\t[slink mode %o]\tEPERM\n", stbuf.st_mode); 498 return EPERM; 499 } 500 #endif 501 502 if (uid == 0 && !bitset(SFF_ROOTOK, flags)) 503 mode >>= 6; 504 else if (stbuf.st_uid != uid) 505 { 506 mode >>= 3; 507 if (stbuf.st_gid == gid) 508 ; 509 #ifndef NO_GROUP_SET 510 else if (uname != NULL && 511 ((gr != NULL && gr->gr_gid == stbuf.st_gid) || 512 (gr = getgrgid(stbuf.st_gid)) != NULL)) 513 { 514 register char **gp; 515 516 for (gp = gr->gr_mem; *gp != NULL; gp++) 517 if (strcmp(*gp, uname) == 0) 518 break; 519 if (*gp == NULL) 520 mode >>= 3; 521 } 522 #endif 523 else 524 mode >>= 3; 525 } 526 if (tTd(54, 4)) 527 printf("\t[uid %d, stat %o, mode %o] ", 528 stbuf.st_uid, stbuf.st_mode, mode); 529 if ((stbuf.st_uid == uid || stbuf.st_uid == 0 || 530 !bitset(SFF_MUSTOWN, flags)) && 531 (stbuf.st_mode & mode) == mode) 532 { 533 if (tTd(54, 4)) 534 printf("\tOK\n"); 535 return 0; 536 } 537 if (tTd(54, 4)) 538 printf("\tEACCES\n"); 539 return EACCES; 540 } 541 /* 542 ** FIXCRLF -- fix <CR><LF> in line. 543 ** 544 ** Looks for the <CR><LF> combination and turns it into the 545 ** UNIX canonical <NL> character. It only takes one line, 546 ** i.e., it is assumed that the first <NL> found is the end 547 ** of the line. 548 ** 549 ** Parameters: 550 ** line -- the line to fix. 551 ** stripnl -- if true, strip the newline also. 552 ** 553 ** Returns: 554 ** none. 555 ** 556 ** Side Effects: 557 ** line is changed in place. 558 */ 559 560 fixcrlf(line, stripnl) 561 char *line; 562 bool stripnl; 563 { 564 register char *p; 565 566 p = strchr(line, '\n'); 567 if (p == NULL) 568 return; 569 if (p > line && p[-1] == '\r') 570 p--; 571 if (!stripnl) 572 *p++ = '\n'; 573 *p = '\0'; 574 } 575 /* 576 ** DFOPEN -- determined file open 577 ** 578 ** This routine has the semantics of fopen, except that it will 579 ** keep trying a few times to make this happen. The idea is that 580 ** on very loaded systems, we may run out of resources (inodes, 581 ** whatever), so this tries to get around it. 582 */ 583 584 #ifndef O_ACCMODE 585 # define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) 586 #endif 587 588 struct omodes 589 { 590 int mask; 591 int mode; 592 char *farg; 593 } OpenModes[] = 594 { 595 O_ACCMODE, O_RDONLY, "r", 596 O_ACCMODE|O_APPEND, O_WRONLY, "w", 597 O_ACCMODE|O_APPEND, O_WRONLY|O_APPEND, "a", 598 O_TRUNC, 0, "w+", 599 O_APPEND, O_APPEND, "a+", 600 0, 0, "r+", 601 }; 602 603 FILE * 604 dfopen(filename, omode, cmode) 605 char *filename; 606 int omode; 607 int cmode; 608 { 609 register int tries; 610 int fd; 611 register struct omodes *om; 612 struct stat st; 613 614 for (om = OpenModes; om->mask != 0; om++) 615 if ((omode & om->mask) == om->mode) 616 break; 617 618 for (tries = 0; tries < 10; tries++) 619 { 620 sleep((unsigned) (10 * tries)); 621 errno = 0; 622 fd = open(filename, omode, cmode); 623 if (fd >= 0) 624 break; 625 switch (errno) 626 { 627 case ENFILE: /* system file table full */ 628 case EINTR: /* interrupted syscall */ 629 #ifdef ETXTBSY 630 case ETXTBSY: /* Apollo: net file locked */ 631 #endif 632 continue; 633 } 634 break; 635 } 636 if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) 637 { 638 int locktype; 639 640 /* lock the file to avoid accidental conflicts */ 641 if ((omode & O_ACCMODE) != O_RDONLY) 642 locktype = LOCK_EX; 643 else 644 locktype = LOCK_SH; 645 (void) lockfile(fd, filename, NULL, locktype); 646 errno = 0; 647 } 648 if (fd < 0) 649 return NULL; 650 else 651 return fdopen(fd, om->farg); 652 } 653 /* 654 ** PUTLINE -- put a line like fputs obeying SMTP conventions 655 ** 656 ** This routine always guarantees outputing a newline (or CRLF, 657 ** as appropriate) at the end of the string. 658 ** 659 ** Parameters: 660 ** l -- line to put. 661 ** mci -- the mailer connection information. 662 ** 663 ** Returns: 664 ** none 665 ** 666 ** Side Effects: 667 ** output of l to fp. 668 */ 669 670 putline(l, mci) 671 register char *l; 672 register MCI *mci; 673 { 674 register char *p; 675 register char svchar; 676 int slop = 0; 677 678 /* strip out 0200 bits -- these can look like TELNET protocol */ 679 if (bitset(MCIF_7BIT, mci->mci_flags)) 680 { 681 for (p = l; (svchar = *p) != '\0'; ++p) 682 if (bitset(0200, svchar)) 683 *p = svchar &~ 0200; 684 } 685 686 do 687 { 688 /* find the end of the line */ 689 p = strchr(l, '\n'); 690 if (p == NULL) 691 p = &l[strlen(l)]; 692 693 if (TrafficLogFile != NULL) 694 fprintf(TrafficLogFile, "%05d >>> ", getpid()); 695 696 /* check for line overflow */ 697 while (mci->mci_mailer->m_linelimit > 0 && 698 (p - l + slop) > mci->mci_mailer->m_linelimit) 699 { 700 register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1]; 701 702 svchar = *q; 703 *q = '\0'; 704 if (l[0] == '.' && slop == 0 && 705 bitnset(M_XDOT, mci->mci_mailer->m_flags)) 706 { 707 (void) putc('.', mci->mci_out); 708 if (TrafficLogFile != NULL) 709 (void) putc('.', TrafficLogFile); 710 } 711 fputs(l, mci->mci_out); 712 (void) putc('!', mci->mci_out); 713 fputs(mci->mci_mailer->m_eol, mci->mci_out); 714 (void) putc(' ', mci->mci_out); 715 if (TrafficLogFile != NULL) 716 fprintf(TrafficLogFile, "%s!\n%05d >>> ", 717 l, getpid()); 718 *q = svchar; 719 l = q; 720 slop = 1; 721 } 722 723 /* output last part */ 724 if (l[0] == '.' && slop == 0 && 725 bitnset(M_XDOT, mci->mci_mailer->m_flags)) 726 { 727 (void) putc('.', mci->mci_out); 728 if (TrafficLogFile != NULL) 729 (void) putc('.', TrafficLogFile); 730 } 731 if (TrafficLogFile != NULL) 732 fprintf(TrafficLogFile, "%.*s\n", p - l, l); 733 for ( ; l < p; ++l) 734 (void) putc(*l, mci->mci_out); 735 fputs(mci->mci_mailer->m_eol, mci->mci_out); 736 if (*l == '\n') 737 ++l; 738 } while (l[0] != '\0'); 739 } 740 /* 741 ** XUNLINK -- unlink a file, doing logging as appropriate. 742 ** 743 ** Parameters: 744 ** f -- name of file to unlink. 745 ** 746 ** Returns: 747 ** none. 748 ** 749 ** Side Effects: 750 ** f is unlinked. 751 */ 752 753 xunlink(f) 754 char *f; 755 { 756 register int i; 757 758 # ifdef LOG 759 if (LogLevel > 98) 760 syslog(LOG_DEBUG, "%s: unlink %s", CurEnv->e_id, f); 761 # endif /* LOG */ 762 763 i = unlink(f); 764 # ifdef LOG 765 if (i < 0 && LogLevel > 97) 766 syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 767 # endif /* LOG */ 768 } 769 /* 770 ** XFCLOSE -- close a file, doing logging as appropriate. 771 ** 772 ** Parameters: 773 ** fp -- file pointer for the file to close 774 ** a, b -- miscellaneous crud to print for debugging 775 ** 776 ** Returns: 777 ** none. 778 ** 779 ** Side Effects: 780 ** fp is closed. 781 */ 782 783 xfclose(fp, a, b) 784 FILE *fp; 785 char *a, *b; 786 { 787 if (tTd(53, 99)) 788 printf("xfclose(%x) %s %s\n", fp, a, b); 789 #ifdef XDEBUG 790 if (fileno(fp) == 1) 791 syserr("xfclose(%s %s): fd = 1", a, b); 792 #endif 793 if (fclose(fp) < 0 && tTd(53, 99)) 794 printf("xfclose FAILURE: %s\n", errstring(errno)); 795 } 796 /* 797 ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 798 ** 799 ** Parameters: 800 ** buf -- place to put the input line. 801 ** siz -- size of buf. 802 ** fp -- file to read from. 803 ** timeout -- the timeout before error occurs. 804 ** during -- what we are trying to read (for error messages). 805 ** 806 ** Returns: 807 ** NULL on error (including timeout). This will also leave 808 ** buf containing a null string. 809 ** buf otherwise. 810 ** 811 ** Side Effects: 812 ** none. 813 */ 814 815 static jmp_buf CtxReadTimeout; 816 static int readtimeout(); 817 818 char * 819 sfgets(buf, siz, fp, timeout, during) 820 char *buf; 821 int siz; 822 FILE *fp; 823 time_t timeout; 824 char *during; 825 { 826 register EVENT *ev = NULL; 827 register char *p; 828 829 if (fp == NULL) 830 { 831 buf[0] = '\0'; 832 return NULL; 833 } 834 835 /* set the timeout */ 836 if (timeout != 0) 837 { 838 if (setjmp(CtxReadTimeout) != 0) 839 { 840 # ifdef LOG 841 syslog(LOG_NOTICE, 842 "timeout waiting for input from %s during %s\n", 843 CurHostName? CurHostName: "local", during); 844 # endif 845 errno = 0; 846 usrerr("451 timeout waiting for input during %s", 847 during); 848 buf[0] = '\0'; 849 #ifdef XDEBUG 850 checkfd012(during); 851 #endif 852 return (NULL); 853 } 854 ev = setevent(timeout, readtimeout, 0); 855 } 856 857 /* try to read */ 858 p = NULL; 859 while (!feof(fp) && !ferror(fp)) 860 { 861 errno = 0; 862 p = fgets(buf, siz, fp); 863 if (p != NULL || errno != EINTR) 864 break; 865 clearerr(fp); 866 } 867 868 /* clear the event if it has not sprung */ 869 clrevent(ev); 870 871 /* clean up the books and exit */ 872 LineNumber++; 873 if (p == NULL) 874 { 875 buf[0] = '\0'; 876 if (TrafficLogFile != NULL) 877 fprintf(TrafficLogFile, "%05d <<< [EOF]\n", getpid()); 878 return (NULL); 879 } 880 if (TrafficLogFile != NULL) 881 fprintf(TrafficLogFile, "%05d <<< %s", getpid(), buf); 882 if (SevenBitInput) 883 { 884 for (p = buf; *p != '\0'; p++) 885 *p &= ~0200; 886 } 887 else if (!HasEightBits) 888 { 889 for (p = buf; *p != '\0'; p++) 890 { 891 if (bitset(0200, *p)) 892 { 893 HasEightBits = TRUE; 894 break; 895 } 896 } 897 } 898 return (buf); 899 } 900 901 static 902 readtimeout(timeout) 903 time_t timeout; 904 { 905 longjmp(CtxReadTimeout, 1); 906 } 907 /* 908 ** FGETFOLDED -- like fgets, but know about folded lines. 909 ** 910 ** Parameters: 911 ** buf -- place to put result. 912 ** n -- bytes available. 913 ** f -- file to read from. 914 ** 915 ** Returns: 916 ** input line(s) on success, NULL on error or EOF. 917 ** This will normally be buf -- unless the line is too 918 ** long, when it will be xalloc()ed. 919 ** 920 ** Side Effects: 921 ** buf gets lines from f, with continuation lines (lines 922 ** with leading white space) appended. CRLF's are mapped 923 ** into single newlines. Any trailing NL is stripped. 924 */ 925 926 char * 927 fgetfolded(buf, n, f) 928 char *buf; 929 register int n; 930 FILE *f; 931 { 932 register char *p = buf; 933 char *bp = buf; 934 register int i; 935 936 n--; 937 while ((i = getc(f)) != EOF) 938 { 939 if (i == '\r') 940 { 941 i = getc(f); 942 if (i != '\n') 943 { 944 if (i != EOF) 945 (void) ungetc(i, f); 946 i = '\r'; 947 } 948 } 949 if (--n <= 0) 950 { 951 /* allocate new space */ 952 char *nbp; 953 int nn; 954 955 nn = (p - bp); 956 if (nn < MEMCHUNKSIZE) 957 nn *= 2; 958 else 959 nn += MEMCHUNKSIZE; 960 nbp = xalloc(nn); 961 bcopy(bp, nbp, p - bp); 962 p = &nbp[p - bp]; 963 if (bp != buf) 964 free(bp); 965 bp = nbp; 966 n = nn - (p - bp); 967 } 968 *p++ = i; 969 if (i == '\n') 970 { 971 LineNumber++; 972 i = getc(f); 973 if (i != EOF) 974 (void) ungetc(i, f); 975 if (i != ' ' && i != '\t') 976 break; 977 } 978 } 979 if (p == bp) 980 return (NULL); 981 *--p = '\0'; 982 return (bp); 983 } 984 /* 985 ** CURTIME -- return current time. 986 ** 987 ** Parameters: 988 ** none. 989 ** 990 ** Returns: 991 ** the current time. 992 ** 993 ** Side Effects: 994 ** none. 995 */ 996 997 time_t 998 curtime() 999 { 1000 auto time_t t; 1001 1002 (void) time(&t); 1003 return (t); 1004 } 1005 /* 1006 ** ATOBOOL -- convert a string representation to boolean. 1007 ** 1008 ** Defaults to "TRUE" 1009 ** 1010 ** Parameters: 1011 ** s -- string to convert. Takes "tTyY" as true, 1012 ** others as false. 1013 ** 1014 ** Returns: 1015 ** A boolean representation of the string. 1016 ** 1017 ** Side Effects: 1018 ** none. 1019 */ 1020 1021 bool 1022 atobool(s) 1023 register char *s; 1024 { 1025 if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL) 1026 return (TRUE); 1027 return (FALSE); 1028 } 1029 /* 1030 ** ATOOCT -- convert a string representation to octal. 1031 ** 1032 ** Parameters: 1033 ** s -- string to convert. 1034 ** 1035 ** Returns: 1036 ** An integer representing the string interpreted as an 1037 ** octal number. 1038 ** 1039 ** Side Effects: 1040 ** none. 1041 */ 1042 1043 atooct(s) 1044 register char *s; 1045 { 1046 register int i = 0; 1047 1048 while (*s >= '0' && *s <= '7') 1049 i = (i << 3) | (*s++ - '0'); 1050 return (i); 1051 } 1052 /* 1053 ** WAITFOR -- wait for a particular process id. 1054 ** 1055 ** Parameters: 1056 ** pid -- process id to wait for. 1057 ** 1058 ** Returns: 1059 ** status of pid. 1060 ** -1 if pid never shows up. 1061 ** 1062 ** Side Effects: 1063 ** none. 1064 */ 1065 1066 int 1067 waitfor(pid) 1068 int pid; 1069 { 1070 #ifdef WAITUNION 1071 union wait st; 1072 #else 1073 auto int st; 1074 #endif 1075 int i; 1076 1077 do 1078 { 1079 errno = 0; 1080 i = wait(&st); 1081 } while ((i >= 0 || errno == EINTR) && i != pid); 1082 if (i < 0) 1083 return -1; 1084 #ifdef WAITUNION 1085 return st.w_status; 1086 #else 1087 return st; 1088 #endif 1089 } 1090 /* 1091 ** BITINTERSECT -- tell if two bitmaps intersect 1092 ** 1093 ** Parameters: 1094 ** a, b -- the bitmaps in question 1095 ** 1096 ** Returns: 1097 ** TRUE if they have a non-null intersection 1098 ** FALSE otherwise 1099 ** 1100 ** Side Effects: 1101 ** none. 1102 */ 1103 1104 bool 1105 bitintersect(a, b) 1106 BITMAP a; 1107 BITMAP b; 1108 { 1109 int i; 1110 1111 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 1112 if ((a[i] & b[i]) != 0) 1113 return (TRUE); 1114 return (FALSE); 1115 } 1116 /* 1117 ** BITZEROP -- tell if a bitmap is all zero 1118 ** 1119 ** Parameters: 1120 ** map -- the bit map to check 1121 ** 1122 ** Returns: 1123 ** TRUE if map is all zero. 1124 ** FALSE if there are any bits set in map. 1125 ** 1126 ** Side Effects: 1127 ** none. 1128 */ 1129 1130 bool 1131 bitzerop(map) 1132 BITMAP map; 1133 { 1134 int i; 1135 1136 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 1137 if (map[i] != 0) 1138 return (FALSE); 1139 return (TRUE); 1140 } 1141 /* 1142 ** STRCONTAINEDIN -- tell if one string is contained in another 1143 ** 1144 ** Parameters: 1145 ** a -- possible substring. 1146 ** b -- possible superstring. 1147 ** 1148 ** Returns: 1149 ** TRUE if a is contained in b. 1150 ** FALSE otherwise. 1151 */ 1152 1153 bool 1154 strcontainedin(a, b) 1155 register char *a; 1156 register char *b; 1157 { 1158 int la; 1159 int lb; 1160 int c; 1161 1162 la = strlen(a); 1163 lb = strlen(b); 1164 c = *a; 1165 if (isascii(c) && isupper(c)) 1166 c = tolower(c); 1167 for (; lb-- >= la; b++) 1168 { 1169 if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c) 1170 continue; 1171 if (strncasecmp(a, b, la) == 0) 1172 return TRUE; 1173 } 1174 return FALSE; 1175 } 1176 /* 1177 ** CHECKFD012 -- check low numbered file descriptors 1178 ** 1179 ** File descriptors 0, 1, and 2 should be open at all times. 1180 ** This routine verifies that, and fixes it if not true. 1181 ** 1182 ** Parameters: 1183 ** where -- a tag printed if the assertion failed 1184 ** 1185 ** Returns: 1186 ** none 1187 */ 1188 1189 checkfd012(where) 1190 char *where; 1191 { 1192 #ifdef XDEBUG 1193 register int i; 1194 struct stat stbuf; 1195 1196 for (i = 0; i < 3; i++) 1197 { 1198 if (fstat(i, &stbuf) < 0 && errno != EOPNOTSUPP) 1199 { 1200 /* oops.... */ 1201 int fd; 1202 1203 syserr("%s: fd %d not open", where, i); 1204 fd = open("/dev/null", i == 0 ? O_RDONLY : O_WRONLY, 0666); 1205 if (fd != i) 1206 { 1207 (void) dup2(fd, i); 1208 (void) close(fd); 1209 } 1210 } 1211 } 1212 #endif /* XDEBUG */ 1213 } 1214 /* 1215 ** PRINTOPENFDS -- print the open file descriptors (for debugging) 1216 ** 1217 ** Parameters: 1218 ** logit -- if set, send output to syslog; otherwise 1219 ** print for debugging. 1220 ** 1221 ** Returns: 1222 ** none. 1223 */ 1224 1225 #include <netdb.h> 1226 #include <arpa/inet.h> 1227 1228 printopenfds(logit) 1229 bool logit; 1230 { 1231 register int fd; 1232 extern int DtableSize; 1233 1234 for (fd = 0; fd < DtableSize; fd++) 1235 dumpfd(fd, FALSE, logit); 1236 } 1237 /* 1238 ** DUMPFD -- dump a file descriptor 1239 ** 1240 ** Parameters: 1241 ** fd -- the file descriptor to dump. 1242 ** printclosed -- if set, print a notification even if 1243 ** it is closed; otherwise print nothing. 1244 ** logit -- if set, send output to syslog instead of stdout. 1245 */ 1246 1247 dumpfd(fd, printclosed, logit) 1248 int fd; 1249 bool printclosed; 1250 bool logit; 1251 { 1252 register struct hostent *hp; 1253 register char *p; 1254 char *fmtstr; 1255 struct sockaddr_in sin; 1256 auto int slen; 1257 struct stat st; 1258 char buf[200]; 1259 1260 p = buf; 1261 sprintf(p, "%3d: ", fd); 1262 p += strlen(p); 1263 1264 if (fstat(fd, &st) < 0) 1265 { 1266 if (printclosed || errno != EBADF) 1267 { 1268 sprintf(p, "CANNOT STAT (%s)", errstring(errno)); 1269 goto printit; 1270 } 1271 return; 1272 } 1273 1274 slen = fcntl(fd, F_GETFL, NULL); 1275 if (slen != -1) 1276 { 1277 sprintf(p, "fl=0x%x, ", slen); 1278 p += strlen(p); 1279 } 1280 1281 sprintf(p, "mode=%o: ", st.st_mode); 1282 p += strlen(p); 1283 switch (st.st_mode & S_IFMT) 1284 { 1285 #ifdef S_IFSOCK 1286 case S_IFSOCK: 1287 sprintf(p, "SOCK "); 1288 p += strlen(p); 1289 slen = sizeof sin; 1290 if (getsockname(fd, (struct sockaddr *) &sin, &slen) < 0) 1291 sprintf(p, "(badsock)"); 1292 else 1293 { 1294 hp = gethostbyaddr((char *) &sin.sin_addr, 1295 INADDRSZ, AF_INET); 1296 sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr) 1297 : hp->h_name, ntohs(sin.sin_port)); 1298 } 1299 p += strlen(p); 1300 sprintf(p, "->"); 1301 p += strlen(p); 1302 slen = sizeof sin; 1303 if (getpeername(fd, (struct sockaddr *) &sin, &slen) < 0) 1304 sprintf(p, "(badsock)"); 1305 else 1306 { 1307 hp = gethostbyaddr((char *) &sin.sin_addr, 1308 INADDRSZ, AF_INET); 1309 sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr) 1310 : hp->h_name, ntohs(sin.sin_port)); 1311 } 1312 break; 1313 #endif 1314 1315 case S_IFCHR: 1316 sprintf(p, "CHR: "); 1317 p += strlen(p); 1318 goto defprint; 1319 1320 case S_IFBLK: 1321 sprintf(p, "BLK: "); 1322 p += strlen(p); 1323 goto defprint; 1324 1325 #if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) 1326 case S_IFIFO: 1327 sprintf(p, "FIFO: "); 1328 p += strlen(p); 1329 goto defprint; 1330 #endif 1331 1332 #ifdef S_IFDIR 1333 case S_IFDIR: 1334 sprintf(p, "DIR: "); 1335 p += strlen(p); 1336 goto defprint; 1337 #endif 1338 1339 #ifdef S_IFLNK 1340 case S_IFLNK: 1341 sprintf(p, "LNK: "); 1342 p += strlen(p); 1343 goto defprint; 1344 #endif 1345 1346 default: 1347 defprint: 1348 if (sizeof st.st_size > sizeof (long)) 1349 fmtstr = "dev=%d/%d, ino=%d, nlink=%d, u/gid=%d/%d, size=%qd"; 1350 else 1351 fmtstr = "dev=%d/%d, ino=%d, nlink=%d, u/gid=%d/%d, size=%ld"; 1352 sprintf(p, fmtstr, 1353 major(st.st_dev), minor(st.st_dev), st.st_ino, 1354 st.st_nlink, st.st_uid, st.st_gid, st.st_size); 1355 break; 1356 } 1357 1358 printit: 1359 #ifdef LOG 1360 if (logit) 1361 syslog(LOG_DEBUG, "%s", buf); 1362 else 1363 #endif 1364 printf("%s\n", buf); 1365 } 1366 /* 1367 ** SHORTENSTRING -- return short version of a string 1368 ** 1369 ** If the string is already short, just return it. If it is too 1370 ** long, return the head and tail of the string. 1371 ** 1372 ** Parameters: 1373 ** s -- the string to shorten. 1374 ** m -- the max length of the string. 1375 ** 1376 ** Returns: 1377 ** Either s or a short version of s. 1378 */ 1379 1380 #ifndef MAXSHORTSTR 1381 # define MAXSHORTSTR 203 1382 #endif 1383 1384 char * 1385 shortenstring(s, m) 1386 register char *s; 1387 int m; 1388 { 1389 int l; 1390 static char buf[MAXSHORTSTR + 1]; 1391 1392 l = strlen(s); 1393 if (l < m) 1394 return s; 1395 if (m > MAXSHORTSTR) 1396 m = MAXSHORTSTR; 1397 else if (m < 10) 1398 { 1399 if (m < 5) 1400 { 1401 strncpy(buf, s, m); 1402 buf[m] = '\0'; 1403 return buf; 1404 } 1405 strncpy(buf, s, m - 3); 1406 strcpy(buf + m - 3, "..."); 1407 return buf; 1408 } 1409 m = (m - 3) / 2; 1410 strncpy(buf, s, m); 1411 strcpy(buf + m, "..."); 1412 strcpy(buf + m + 3, s + l - m); 1413 return buf; 1414 } 1415