122717Sdist /* 222717Sdist ** Sendmail 322717Sdist ** Copyright (c) 1983 Eric P. Allman 422717Sdist ** Berkeley, California 522717Sdist ** 622717Sdist ** Copyright (c) 1983 Regents of the University of California. 722717Sdist ** All rights reserved. The Berkeley software License Agreement 822717Sdist ** specifies the terms and conditions for redistribution. 922717Sdist */ 1022717Sdist 1122717Sdist #ifndef lint 12*23105Seric static char SccsId[] = "@(#)util.c 5.4 (Berkeley) 06/08/85"; 1322717Sdist #endif not lint 1422717Sdist 153151Seric # include <stdio.h> 164538Seric # include <sys/types.h> 174538Seric # include <sys/stat.h> 18298Seric # include <sysexits.h> 196890Seric # include <errno.h> 202900Seric # include <ctype.h> 216890Seric # include "sendmail.h" 22298Seric 23298Seric /* 24298Seric ** STRIPQUOTES -- Strip quotes & quote bits from a string. 25298Seric ** 26298Seric ** Runs through a string and strips off unquoted quote 27298Seric ** characters and quote bits. This is done in place. 28298Seric ** 29298Seric ** Parameters: 30298Seric ** s -- the string to strip. 314101Seric ** qf -- if set, remove actual `` " '' characters 324101Seric ** as well as the quote bits. 33298Seric ** 34298Seric ** Returns: 35298Seric ** none. 36298Seric ** 37298Seric ** Side Effects: 38298Seric ** none. 39298Seric ** 40298Seric ** Called By: 41298Seric ** deliver 42298Seric */ 43298Seric 444101Seric stripquotes(s, qf) 45298Seric char *s; 464101Seric bool qf; 47298Seric { 48298Seric register char *p; 49298Seric register char *q; 50298Seric register char c; 51298Seric 524101Seric if (s == NULL) 534101Seric return; 544101Seric 55298Seric for (p = q = s; (c = *p++) != '\0'; ) 56298Seric { 574101Seric if (c != '"' || !qf) 58298Seric *q++ = c & 0177; 59298Seric } 60298Seric *q = '\0'; 61298Seric } 62298Seric /* 639043Seric ** QSTRLEN -- give me the string length assuming 0200 bits add a char 649043Seric ** 659043Seric ** Parameters: 669043Seric ** s -- the string to measure. 679043Seric ** 689043Seric ** Reurns: 699043Seric ** The length of s, including space for backslash escapes. 709043Seric ** 719043Seric ** Side Effects: 729043Seric ** none. 739043Seric */ 749043Seric 759043Seric qstrlen(s) 769043Seric register char *s; 779043Seric { 789043Seric register int l = 0; 799043Seric register char c; 809043Seric 819043Seric while ((c = *s++) != '\0') 829043Seric { 839043Seric if (bitset(0200, c)) 849043Seric l++; 859043Seric l++; 869043Seric } 879043Seric return (l); 889043Seric } 899043Seric /* 902900Seric ** CAPITALIZE -- return a copy of a string, properly capitalized. 912900Seric ** 922900Seric ** Parameters: 932900Seric ** s -- the string to capitalize. 942900Seric ** 952900Seric ** Returns: 962900Seric ** a pointer to a properly capitalized string. 972900Seric ** 982900Seric ** Side Effects: 992900Seric ** none. 1002900Seric */ 1012900Seric 1022900Seric char * 1032900Seric capitalize(s) 1042900Seric register char *s; 1052900Seric { 1062900Seric static char buf[50]; 1072900Seric register char *p; 1082900Seric 1092900Seric p = buf; 1102900Seric 1112900Seric for (;;) 1122900Seric { 1132900Seric while (!isalpha(*s) && *s != '\0') 1142900Seric *p++ = *s++; 1152900Seric if (*s == '\0') 1162900Seric break; 1172900Seric *p++ = toupper(*s++); 1182900Seric while (isalpha(*s)) 1192900Seric *p++ = *s++; 1202900Seric } 1212900Seric 1222900Seric *p = '\0'; 1232900Seric return (buf); 1242900Seric } 1252900Seric /* 126298Seric ** XALLOC -- Allocate memory and bitch wildly on failure. 127298Seric ** 128298Seric ** THIS IS A CLUDGE. This should be made to give a proper 129298Seric ** error -- but after all, what can we do? 130298Seric ** 131298Seric ** Parameters: 132298Seric ** sz -- size of area to allocate. 133298Seric ** 134298Seric ** Returns: 135298Seric ** pointer to data region. 136298Seric ** 137298Seric ** Side Effects: 138298Seric ** Memory is allocated. 139298Seric */ 140298Seric 141298Seric char * 142298Seric xalloc(sz) 1437007Seric register int sz; 144298Seric { 145298Seric register char *p; 146298Seric 147298Seric p = malloc(sz); 148298Seric if (p == NULL) 149298Seric { 150298Seric syserr("Out of memory!!"); 15110685Seric abort(); 15210685Seric /* exit(EX_UNAVAILABLE); */ 153298Seric } 154298Seric return (p); 155298Seric } 156298Seric /* 1573151Seric ** COPYPLIST -- copy list of pointers. 1583151Seric ** 1593151Seric ** This routine is the equivalent of newstr for lists of 1603151Seric ** pointers. 1613151Seric ** 1623151Seric ** Parameters: 1633151Seric ** list -- list of pointers to copy. 1643151Seric ** Must be NULL terminated. 1653151Seric ** copycont -- if TRUE, copy the contents of the vector 1663151Seric ** (which must be a string) also. 1673151Seric ** 1683151Seric ** Returns: 1693151Seric ** a copy of 'list'. 1703151Seric ** 1713151Seric ** Side Effects: 1723151Seric ** none. 1733151Seric */ 1743151Seric 1753151Seric char ** 1763151Seric copyplist(list, copycont) 1773151Seric char **list; 1783151Seric bool copycont; 1793151Seric { 1803151Seric register char **vp; 1813151Seric register char **newvp; 1823151Seric 1833151Seric for (vp = list; *vp != NULL; vp++) 1843151Seric continue; 1853151Seric 1863151Seric vp++; 1873151Seric 18816897Seric newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); 18916897Seric bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); 1903151Seric 1913151Seric if (copycont) 1923151Seric { 1933151Seric for (vp = newvp; *vp != NULL; vp++) 1943151Seric *vp = newstr(*vp); 1953151Seric } 1963151Seric 1973151Seric return (newvp); 1983151Seric } 1993151Seric /* 2003151Seric ** PRINTAV -- print argument vector. 2013151Seric ** 2023151Seric ** Parameters: 2033151Seric ** av -- argument vector. 2043151Seric ** 2053151Seric ** Returns: 2063151Seric ** none. 2073151Seric ** 2083151Seric ** Side Effects: 2093151Seric ** prints av. 2103151Seric */ 2113151Seric 2123151Seric printav(av) 2133151Seric register char **av; 2143151Seric { 2153151Seric while (*av != NULL) 2163151Seric { 2178063Seric if (tTd(0, 44)) 2188063Seric printf("\n\t%08x=", *av); 2198063Seric else 220*23105Seric (void) putchar(' '); 2213151Seric xputs(*av++); 2223151Seric } 223*23105Seric (void) putchar('\n'); 2243151Seric } 2253151Seric /* 2263151Seric ** LOWER -- turn letter into lower case. 2273151Seric ** 2283151Seric ** Parameters: 2293151Seric ** c -- character to turn into lower case. 2303151Seric ** 2313151Seric ** Returns: 2323151Seric ** c, in lower case. 2333151Seric ** 2343151Seric ** Side Effects: 2353151Seric ** none. 2363151Seric */ 2373151Seric 2383151Seric char 2393151Seric lower(c) 2403151Seric register char c; 2413151Seric { 2423151Seric if (isascii(c) && isupper(c)) 2433151Seric c = c - 'A' + 'a'; 2443151Seric return (c); 2453151Seric } 2463151Seric /* 2473151Seric ** XPUTS -- put string doing control escapes. 2483151Seric ** 2493151Seric ** Parameters: 2503151Seric ** s -- string to put. 2513151Seric ** 2523151Seric ** Returns: 2533151Seric ** none. 2543151Seric ** 2553151Seric ** Side Effects: 2563151Seric ** output to stdout 2573151Seric */ 2583151Seric 2593151Seric xputs(s) 2603151Seric register char *s; 2613151Seric { 2623151Seric register char c; 2633151Seric 2648055Seric if (s == NULL) 2658055Seric { 2668055Seric printf("<null>"); 2678055Seric return; 2688055Seric } 269*23105Seric (void) putchar('"'); 2703151Seric while ((c = *s++) != '\0') 2713151Seric { 2723151Seric if (!isascii(c)) 2733151Seric { 274*23105Seric (void) putchar('\\'); 2753151Seric c &= 0177; 2763151Seric } 27710326Seric if (c < 040 || c >= 0177) 2783151Seric { 279*23105Seric (void) putchar('^'); 28010326Seric c ^= 0100; 2813151Seric } 282*23105Seric (void) putchar(c); 2833151Seric } 284*23105Seric (void) putchar('"'); 2854086Seric (void) fflush(stdout); 2863151Seric } 2873151Seric /* 2883151Seric ** MAKELOWER -- Translate a line into lower case 2893151Seric ** 2903151Seric ** Parameters: 2913151Seric ** p -- the string to translate. If NULL, return is 2923151Seric ** immediate. 2933151Seric ** 2943151Seric ** Returns: 2953151Seric ** none. 2963151Seric ** 2973151Seric ** Side Effects: 2983151Seric ** String pointed to by p is translated to lower case. 2993151Seric ** 3003151Seric ** Called By: 3013151Seric ** parse 3023151Seric */ 3033151Seric 3043151Seric makelower(p) 3053151Seric register char *p; 3063151Seric { 3073151Seric register char c; 3083151Seric 3093151Seric if (p == NULL) 3103151Seric return; 3113151Seric for (; (c = *p) != '\0'; p++) 3123151Seric if (isascii(c) && isupper(c)) 3133151Seric *p = c - 'A' + 'a'; 3143151Seric } 3154059Seric /* 3164059Seric ** SAMEWORD -- return TRUE if the words are the same 3174059Seric ** 3184059Seric ** Ignores case. 3194059Seric ** 3204059Seric ** Parameters: 3214059Seric ** a, b -- the words to compare. 3224059Seric ** 3234059Seric ** Returns: 3244059Seric ** TRUE if a & b match exactly (modulo case) 3254059Seric ** FALSE otherwise. 3264059Seric ** 3274059Seric ** Side Effects: 3284059Seric ** none. 3294059Seric */ 3304059Seric 3314059Seric bool 3324059Seric sameword(a, b) 3334059Seric register char *a, *b; 3344059Seric { 33517350Seric char ca, cb; 33617350Seric 33717350Seric do 3384059Seric { 33917350Seric ca = *a++; 34017350Seric cb = *b++; 34117350Seric if (isascii(ca) && isupper(ca)) 34217350Seric ca = ca - 'A' + 'a'; 34317350Seric if (isascii(cb) && isupper(cb)) 34417350Seric cb = cb - 'A' + 'a'; 34517350Seric } while (ca != '\0' && ca == cb); 34617350Seric return (ca == cb); 3474059Seric } 3484086Seric /* 3495196Seric ** BUILDFNAME -- build full name from gecos style entry. 3504375Seric ** 3515196Seric ** This routine interprets the strange entry that would appear 3525196Seric ** in the GECOS field of the password file. 3535196Seric ** 3544375Seric ** Parameters: 3555196Seric ** p -- name to build. 3565196Seric ** login -- the login name of this user (for &). 3575196Seric ** buf -- place to put the result. 3584375Seric ** 3594375Seric ** Returns: 3604375Seric ** none. 3614375Seric ** 3624375Seric ** Side Effects: 3634375Seric ** none. 3644375Seric */ 3654375Seric 3665196Seric buildfname(p, login, buf) 3675196Seric register char *p; 3685196Seric char *login; 3694375Seric char *buf; 3704375Seric { 3714375Seric register char *bp = buf; 3724375Seric 3734438Seric if (*p == '*') 3744438Seric p++; 3756278Seric while (*p != '\0' && *p != ',' && *p != ';' && *p != '%') 3764375Seric { 3774375Seric if (*p == '&') 3784375Seric { 3795196Seric (void) strcpy(bp, login); 3804375Seric *bp = toupper(*bp); 3814375Seric while (*bp != '\0') 3824375Seric bp++; 3834375Seric p++; 3844375Seric } 3854375Seric else 3864375Seric *bp++ = *p++; 3874375Seric } 3884375Seric *bp = '\0'; 3894375Seric } 3904375Seric /* 3914538Seric ** SAFEFILE -- return true if a file exists and is safe for a user. 3924538Seric ** 3934538Seric ** Parameters: 3944538Seric ** fn -- filename to check. 3954538Seric ** uid -- uid to compare against. 3964538Seric ** mode -- mode bits that must match. 3974538Seric ** 3984538Seric ** Returns: 3994538Seric ** TRUE if fn exists, is owned by uid, and matches mode. 4004538Seric ** FALSE otherwise. 4014538Seric ** 4024538Seric ** Side Effects: 4034538Seric ** none. 4044538Seric */ 4054538Seric 4064538Seric bool 4074538Seric safefile(fn, uid, mode) 4084538Seric char *fn; 4094538Seric int uid; 4104538Seric int mode; 4114538Seric { 4124538Seric struct stat stbuf; 4134538Seric 4144538Seric if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && 4154538Seric (stbuf.st_mode & mode) == mode) 4164538Seric return (TRUE); 41711936Seric errno = 0; 4184538Seric return (FALSE); 4194538Seric } 4204538Seric /* 4214557Seric ** FIXCRLF -- fix <CR><LF> in line. 4224557Seric ** 4234557Seric ** Looks for the <CR><LF> combination and turns it into the 4244557Seric ** UNIX canonical <NL> character. It only takes one line, 4254557Seric ** i.e., it is assumed that the first <NL> found is the end 4264557Seric ** of the line. 4274557Seric ** 4284557Seric ** Parameters: 4294557Seric ** line -- the line to fix. 4304557Seric ** stripnl -- if true, strip the newline also. 4314557Seric ** 4324557Seric ** Returns: 4334557Seric ** none. 4344557Seric ** 4354557Seric ** Side Effects: 4364557Seric ** line is changed in place. 4374557Seric */ 4384557Seric 4394557Seric fixcrlf(line, stripnl) 4404557Seric char *line; 4414557Seric bool stripnl; 4424557Seric { 4434557Seric register char *p; 4444557Seric 4454557Seric p = index(line, '\n'); 4464557Seric if (p == NULL) 4474557Seric return; 4484794Seric if (p[-1] == '\r') 4494557Seric p--; 4504557Seric if (!stripnl) 4514557Seric *p++ = '\n'; 4524557Seric *p = '\0'; 4534557Seric } 4544557Seric /* 4556890Seric ** DFOPEN -- determined file open 4566890Seric ** 4576890Seric ** This routine has the semantics of fopen, except that it will 4586890Seric ** keep trying a few times to make this happen. The idea is that 4596890Seric ** on very loaded systems, we may run out of resources (inodes, 4606890Seric ** whatever), so this tries to get around it. 4616890Seric */ 4626890Seric 4636890Seric FILE * 4646890Seric dfopen(filename, mode) 4656890Seric char *filename; 4666890Seric char *mode; 4676890Seric { 4686890Seric register int tries; 4696890Seric register FILE *fp; 4706890Seric 4716890Seric for (tries = 0; tries < 10; tries++) 4726890Seric { 4736890Seric sleep(10 * tries); 4746890Seric errno = 0; 4756890Seric fp = fopen(filename, mode); 4769376Seric if (fp != NULL) 4776890Seric break; 4789376Seric if (errno != ENFILE && errno != EINTR) 4799376Seric break; 4806890Seric } 48111936Seric errno = 0; 4826890Seric return (fp); 4836890Seric } 4847124Seric /* 4857124Seric ** PUTLINE -- put a line like fputs obeying SMTP conventions 4867124Seric ** 4877753Seric ** This routine always guarantees outputing a newline (or CRLF, 4887753Seric ** as appropriate) at the end of the string. 4897753Seric ** 4907124Seric ** Parameters: 4917124Seric ** l -- line to put. 4927124Seric ** fp -- file to put it onto. 49310172Seric ** m -- the mailer used to control output. 4947124Seric ** 4957124Seric ** Returns: 4967124Seric ** none 4977124Seric ** 4987124Seric ** Side Effects: 4997124Seric ** output of l to fp. 5007124Seric */ 5017124Seric 5027753Seric # define SMTPLINELIM 990 /* maximum line length */ 5037124Seric 50410172Seric putline(l, fp, m) 5057753Seric register char *l; 5067124Seric FILE *fp; 50710172Seric MAILER *m; 5087124Seric { 5097124Seric register char *p; 5107753Seric char svchar; 5117124Seric 51211275Seric /* strip out 0200 bits -- these can look like TELNET protocol */ 51311275Seric if (bitnset(M_LIMITS, m->m_flags)) 51411275Seric { 51511275Seric p = l; 51611275Seric while ((*p++ &= ~0200) != 0) 51711275Seric continue; 51811275Seric } 51911275Seric 5207753Seric do 5217124Seric { 5227753Seric /* find the end of the line */ 5237753Seric p = index(l, '\n'); 5247753Seric if (p == NULL) 5257753Seric p = &l[strlen(l)]; 5267124Seric 5277753Seric /* check for line overflow */ 52811275Seric while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags)) 5297753Seric { 5307753Seric register char *q = &l[SMTPLINELIM - 1]; 5317124Seric 5327753Seric svchar = *q; 5337753Seric *q = '\0'; 53410685Seric if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 535*23105Seric (void) putc('.', fp); 5367753Seric fputs(l, fp); 537*23105Seric (void) putc('!', fp); 53810326Seric fputs(m->m_eol, fp); 5397753Seric *q = svchar; 5407753Seric l = q; 5417753Seric } 5427124Seric 5437753Seric /* output last part */ 5447753Seric svchar = *p; 5457753Seric *p = '\0'; 54610685Seric if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 547*23105Seric (void) putc('.', fp); 5487124Seric fputs(l, fp); 54910326Seric fputs(m->m_eol, fp); 5507753Seric *p = svchar; 5517753Seric l = p; 5527753Seric if (*l == '\n') 5537753Seric l++; 5547753Seric } while (l[0] != '\0'); 5557124Seric } 5567676Seric /* 5577676Seric ** XUNLINK -- unlink a file, doing logging as appropriate. 5587676Seric ** 5597676Seric ** Parameters: 5607676Seric ** f -- name of file to unlink. 5617676Seric ** 5627676Seric ** Returns: 5637676Seric ** none. 5647676Seric ** 5657676Seric ** Side Effects: 5667676Seric ** f is unlinked. 5677676Seric */ 5687676Seric 5697676Seric xunlink(f) 5707676Seric char *f; 5717676Seric { 5727676Seric register int i; 5737676Seric 5747676Seric # ifdef LOG 5757676Seric if (LogLevel > 20) 5767812Seric syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f); 5777676Seric # endif LOG 5787676Seric 5797676Seric i = unlink(f); 5807676Seric # ifdef LOG 5817676Seric if (i < 0 && LogLevel > 21) 5827942Seric syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 5837676Seric # endif LOG 5847676Seric } 5857685Seric /* 58614885Seric ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 5877685Seric ** 5887685Seric ** Parameters: 5897685Seric ** buf -- place to put the input line. 5907685Seric ** siz -- size of buf. 5917685Seric ** fp -- file to read from. 5927685Seric ** 5937685Seric ** Returns: 59415533Seric ** NULL on error (including timeout). This will also leave 59515533Seric ** buf containing a null string. 5967685Seric ** buf otherwise. 5977685Seric ** 5987685Seric ** Side Effects: 5997685Seric ** none. 6007685Seric */ 6017685Seric 60214885Seric static jmp_buf CtxReadTimeout; 6037685Seric 60416138Seric #ifndef ETIMEDOUT 60516138Seric #define ETIMEDOUT EINTR 60616138Seric #endif 60716138Seric 6087685Seric char * 6097685Seric sfgets(buf, siz, fp) 6107685Seric char *buf; 6117685Seric int siz; 6127685Seric FILE *fp; 6137685Seric { 6147942Seric register EVENT *ev = NULL; 6157685Seric register char *p; 6167685Seric extern readtimeout(); 6177685Seric 61814885Seric /* set the timeout */ 6197942Seric if (ReadTimeout != 0) 62014885Seric { 62114885Seric if (setjmp(CtxReadTimeout) != 0) 62214885Seric { 62316138Seric errno = ETIMEDOUT; 62414885Seric syserr("sfgets: timeout on read (mailer may be hung)"); 62519037Seric buf[0] = '\0'; 62614885Seric return (NULL); 62714885Seric } 62816138Seric ev = setevent((time_t) ReadTimeout, readtimeout, 0); 62914885Seric } 63014885Seric 63114885Seric /* try to read */ 63215533Seric p = NULL; 63315533Seric while (p == NULL && !feof(fp) && !ferror(fp)) 6347942Seric { 6357942Seric errno = 0; 6367942Seric p = fgets(buf, siz, fp); 63715533Seric if (errno == EINTR) 63815533Seric clearerr(fp); 63915533Seric } 64014885Seric 64114885Seric /* clear the event if it has not sprung */ 6427685Seric clrevent(ev); 64314885Seric 64414885Seric /* clean up the books and exit */ 6458055Seric LineNumber++; 64615533Seric if (p == NULL) 64716880Seric { 64815533Seric buf[0] = '\0'; 64916880Seric return (NULL); 65016880Seric } 65116880Seric for (p = buf; *p != '\0'; p++) 65216880Seric *p &= ~0200; 65316880Seric return (buf); 6547685Seric } 6557685Seric 6567685Seric static 6577685Seric readtimeout() 6587685Seric { 65914885Seric longjmp(CtxReadTimeout, 1); 6607685Seric } 6617786Seric /* 6627786Seric ** FGETFOLDED -- like fgets, but know about folded lines. 6637786Seric ** 6647786Seric ** Parameters: 6657786Seric ** buf -- place to put result. 6667786Seric ** n -- bytes available. 6677786Seric ** f -- file to read from. 6687786Seric ** 6697786Seric ** Returns: 6707786Seric ** buf on success, NULL on error or EOF. 6717786Seric ** 6727786Seric ** Side Effects: 6737786Seric ** buf gets lines from f, with continuation lines (lines 6747786Seric ** with leading white space) appended. CRLF's are mapped 6757786Seric ** into single newlines. Any trailing NL is stripped. 6767786Seric */ 6777786Seric 6787786Seric char * 6797786Seric fgetfolded(buf, n, f) 6807786Seric char *buf; 6817786Seric register int n; 6827786Seric FILE *f; 6837786Seric { 6847786Seric register char *p = buf; 6857786Seric register int i; 6867786Seric 6877786Seric n--; 68817350Seric while ((i = getc(f)) != EOF) 6897786Seric { 69017350Seric if (i == '\r') 69117350Seric { 69217350Seric i = getc(f); 69317350Seric if (i != '\n') 69417350Seric { 69517350Seric if (i != EOF) 696*23105Seric (void) ungetc(i, f); 69717350Seric i = '\r'; 69817350Seric } 69917350Seric } 70017350Seric if (--n > 0) 70117350Seric *p++ = i; 70217350Seric if (i == '\n') 70317350Seric { 70417350Seric LineNumber++; 70517350Seric i = getc(f); 70617350Seric if (i != EOF) 707*23105Seric (void) ungetc(i, f); 70817350Seric if (i != ' ' && i != '\t') 70917350Seric { 71017350Seric *--p = '\0'; 71117350Seric return (buf); 71217350Seric } 71317350Seric } 7147786Seric } 7157786Seric return (NULL); 7167786Seric } 7177860Seric /* 7187886Seric ** CURTIME -- return current time. 7197886Seric ** 7207886Seric ** Parameters: 7217886Seric ** none. 7227886Seric ** 7237886Seric ** Returns: 7247886Seric ** the current time. 7257886Seric ** 7267886Seric ** Side Effects: 7277886Seric ** none. 7287886Seric */ 7297886Seric 7307886Seric time_t 7317886Seric curtime() 7327886Seric { 7337886Seric auto time_t t; 7347886Seric 7357886Seric (void) time(&t); 7367886Seric return (t); 7377886Seric } 7388264Seric /* 7398264Seric ** ATOBOOL -- convert a string representation to boolean. 7408264Seric ** 7418264Seric ** Defaults to "TRUE" 7428264Seric ** 7438264Seric ** Parameters: 7448264Seric ** s -- string to convert. Takes "tTyY" as true, 7458264Seric ** others as false. 7468264Seric ** 7478264Seric ** Returns: 7488264Seric ** A boolean representation of the string. 7498264Seric ** 7508264Seric ** Side Effects: 7518264Seric ** none. 7528264Seric */ 7538264Seric 7548264Seric bool 7558264Seric atobool(s) 7568264Seric register char *s; 7578264Seric { 7588264Seric if (*s == '\0' || index("tTyY", *s) != NULL) 7598264Seric return (TRUE); 7608264Seric return (FALSE); 7618264Seric } 7629048Seric /* 7639048Seric ** ATOOCT -- convert a string representation to octal. 7649048Seric ** 7659048Seric ** Parameters: 7669048Seric ** s -- string to convert. 7679048Seric ** 7689048Seric ** Returns: 7699048Seric ** An integer representing the string interpreted as an 7709048Seric ** octal number. 7719048Seric ** 7729048Seric ** Side Effects: 7739048Seric ** none. 7749048Seric */ 7759048Seric 7769048Seric atooct(s) 7779048Seric register char *s; 7789048Seric { 7799048Seric register int i = 0; 7809048Seric 7819048Seric while (*s >= '0' && *s <= '7') 7829048Seric i = (i << 3) | (*s++ - '0'); 7839048Seric return (i); 7849048Seric } 7859376Seric /* 7869376Seric ** WAITFOR -- wait for a particular process id. 7879376Seric ** 7889376Seric ** Parameters: 7899376Seric ** pid -- process id to wait for. 7909376Seric ** 7919376Seric ** Returns: 7929376Seric ** status of pid. 7939376Seric ** -1 if pid never shows up. 7949376Seric ** 7959376Seric ** Side Effects: 7969376Seric ** none. 7979376Seric */ 7989376Seric 7999376Seric waitfor(pid) 8009376Seric int pid; 8019376Seric { 8029376Seric auto int st; 8039376Seric int i; 8049376Seric 8059376Seric do 8069376Seric { 8079376Seric errno = 0; 8089376Seric i = wait(&st); 8099376Seric } while ((i >= 0 || errno == EINTR) && i != pid); 8109376Seric if (i < 0) 8119376Seric st = -1; 8129376Seric return (st); 8139376Seric } 8149376Seric /* 81510685Seric ** BITINTERSECT -- tell if two bitmaps intersect 81610685Seric ** 81710685Seric ** Parameters: 81810685Seric ** a, b -- the bitmaps in question 81910685Seric ** 82010685Seric ** Returns: 82110685Seric ** TRUE if they have a non-null intersection 82210685Seric ** FALSE otherwise 82310685Seric ** 82410685Seric ** Side Effects: 82510685Seric ** none. 82610685Seric */ 82710685Seric 82810685Seric bool 82910685Seric bitintersect(a, b) 83010685Seric BITMAP a; 83110685Seric BITMAP b; 83210685Seric { 83310685Seric int i; 83410685Seric 83510685Seric for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 83610685Seric if ((a[i] & b[i]) != 0) 83710685Seric return (TRUE); 83810685Seric return (FALSE); 83910685Seric } 84010685Seric /* 84110685Seric ** BITZEROP -- tell if a bitmap is all zero 84210685Seric ** 84310685Seric ** Parameters: 84410685Seric ** map -- the bit map to check 84510685Seric ** 84610685Seric ** Returns: 84710685Seric ** TRUE if map is all zero. 84810685Seric ** FALSE if there are any bits set in map. 84910685Seric ** 85010685Seric ** Side Effects: 85110685Seric ** none. 85210685Seric */ 85310685Seric 85410685Seric bool 85510685Seric bitzerop(map) 85610685Seric BITMAP map; 85710685Seric { 85810685Seric int i; 85910685Seric 86010685Seric for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 86110685Seric if (map[i] != 0) 86210685Seric return (FALSE); 86310685Seric return (TRUE); 86410685Seric } 865