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*25618Seric static char SccsId[] = "@(#)util.c 5.8 (Berkeley) 12/17/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; 14623121Seric extern char *malloc(); 147298Seric 14823121Seric p = malloc((unsigned) sz); 149298Seric if (p == NULL) 150298Seric { 151298Seric syserr("Out of memory!!"); 15210685Seric abort(); 15310685Seric /* exit(EX_UNAVAILABLE); */ 154298Seric } 155298Seric return (p); 156298Seric } 157298Seric /* 1583151Seric ** COPYPLIST -- copy list of pointers. 1593151Seric ** 1603151Seric ** This routine is the equivalent of newstr for lists of 1613151Seric ** pointers. 1623151Seric ** 1633151Seric ** Parameters: 1643151Seric ** list -- list of pointers to copy. 1653151Seric ** Must be NULL terminated. 1663151Seric ** copycont -- if TRUE, copy the contents of the vector 1673151Seric ** (which must be a string) also. 1683151Seric ** 1693151Seric ** Returns: 1703151Seric ** a copy of 'list'. 1713151Seric ** 1723151Seric ** Side Effects: 1733151Seric ** none. 1743151Seric */ 1753151Seric 1763151Seric char ** 1773151Seric copyplist(list, copycont) 1783151Seric char **list; 1793151Seric bool copycont; 1803151Seric { 1813151Seric register char **vp; 1823151Seric register char **newvp; 1833151Seric 1843151Seric for (vp = list; *vp != NULL; vp++) 1853151Seric continue; 1863151Seric 1873151Seric vp++; 1883151Seric 18916897Seric newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); 19016897Seric bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); 1913151Seric 1923151Seric if (copycont) 1933151Seric { 1943151Seric for (vp = newvp; *vp != NULL; vp++) 1953151Seric *vp = newstr(*vp); 1963151Seric } 1973151Seric 1983151Seric return (newvp); 1993151Seric } 2003151Seric /* 2013151Seric ** PRINTAV -- print argument vector. 2023151Seric ** 2033151Seric ** Parameters: 2043151Seric ** av -- argument vector. 2053151Seric ** 2063151Seric ** Returns: 2073151Seric ** none. 2083151Seric ** 2093151Seric ** Side Effects: 2103151Seric ** prints av. 2113151Seric */ 2123151Seric 2133151Seric printav(av) 2143151Seric register char **av; 2153151Seric { 2163151Seric while (*av != NULL) 2173151Seric { 2188063Seric if (tTd(0, 44)) 2198063Seric printf("\n\t%08x=", *av); 2208063Seric else 22123105Seric (void) putchar(' '); 2223151Seric xputs(*av++); 2233151Seric } 22423105Seric (void) putchar('\n'); 2253151Seric } 2263151Seric /* 2273151Seric ** LOWER -- turn letter into lower case. 2283151Seric ** 2293151Seric ** Parameters: 2303151Seric ** c -- character to turn into lower case. 2313151Seric ** 2323151Seric ** Returns: 2333151Seric ** c, in lower case. 2343151Seric ** 2353151Seric ** Side Effects: 2363151Seric ** none. 2373151Seric */ 2383151Seric 2393151Seric char 2403151Seric lower(c) 2413151Seric register char c; 2423151Seric { 2433151Seric if (isascii(c) && isupper(c)) 2443151Seric c = c - 'A' + 'a'; 2453151Seric return (c); 2463151Seric } 2473151Seric /* 2483151Seric ** XPUTS -- put string doing control escapes. 2493151Seric ** 2503151Seric ** Parameters: 2513151Seric ** s -- string to put. 2523151Seric ** 2533151Seric ** Returns: 2543151Seric ** none. 2553151Seric ** 2563151Seric ** Side Effects: 2573151Seric ** output to stdout 2583151Seric */ 2593151Seric 2603151Seric xputs(s) 2613151Seric register char *s; 2623151Seric { 2633151Seric register char c; 2643151Seric 2658055Seric if (s == NULL) 2668055Seric { 2678055Seric printf("<null>"); 2688055Seric return; 2698055Seric } 27023105Seric (void) putchar('"'); 2713151Seric while ((c = *s++) != '\0') 2723151Seric { 2733151Seric if (!isascii(c)) 2743151Seric { 27523105Seric (void) putchar('\\'); 2763151Seric c &= 0177; 2773151Seric } 27810326Seric if (c < 040 || c >= 0177) 2793151Seric { 28023105Seric (void) putchar('^'); 28110326Seric c ^= 0100; 2823151Seric } 28323105Seric (void) putchar(c); 2843151Seric } 28523105Seric (void) putchar('"'); 2864086Seric (void) fflush(stdout); 2873151Seric } 2883151Seric /* 2893151Seric ** MAKELOWER -- Translate a line into lower case 2903151Seric ** 2913151Seric ** Parameters: 2923151Seric ** p -- the string to translate. If NULL, return is 2933151Seric ** immediate. 2943151Seric ** 2953151Seric ** Returns: 2963151Seric ** none. 2973151Seric ** 2983151Seric ** Side Effects: 2993151Seric ** String pointed to by p is translated to lower case. 3003151Seric ** 3013151Seric ** Called By: 3023151Seric ** parse 3033151Seric */ 3043151Seric 3053151Seric makelower(p) 3063151Seric register char *p; 3073151Seric { 3083151Seric register char c; 3093151Seric 3103151Seric if (p == NULL) 3113151Seric return; 3123151Seric for (; (c = *p) != '\0'; p++) 3133151Seric if (isascii(c) && isupper(c)) 3143151Seric *p = c - 'A' + 'a'; 3153151Seric } 3164059Seric /* 3174059Seric ** SAMEWORD -- return TRUE if the words are the same 3184059Seric ** 3194059Seric ** Ignores case. 3204059Seric ** 3214059Seric ** Parameters: 3224059Seric ** a, b -- the words to compare. 3234059Seric ** 3244059Seric ** Returns: 3254059Seric ** TRUE if a & b match exactly (modulo case) 3264059Seric ** FALSE otherwise. 3274059Seric ** 3284059Seric ** Side Effects: 3294059Seric ** none. 3304059Seric */ 3314059Seric 3324059Seric bool 3334059Seric sameword(a, b) 3344059Seric register char *a, *b; 3354059Seric { 33617350Seric char ca, cb; 33717350Seric 33817350Seric do 3394059Seric { 34017350Seric ca = *a++; 34117350Seric cb = *b++; 34217350Seric if (isascii(ca) && isupper(ca)) 34317350Seric ca = ca - 'A' + 'a'; 34417350Seric if (isascii(cb) && isupper(cb)) 34517350Seric cb = cb - 'A' + 'a'; 34617350Seric } while (ca != '\0' && ca == cb); 34717350Seric return (ca == cb); 3484059Seric } 3494086Seric /* 3505196Seric ** BUILDFNAME -- build full name from gecos style entry. 3514375Seric ** 3525196Seric ** This routine interprets the strange entry that would appear 3535196Seric ** in the GECOS field of the password file. 3545196Seric ** 3554375Seric ** Parameters: 3565196Seric ** p -- name to build. 3575196Seric ** login -- the login name of this user (for &). 3585196Seric ** buf -- place to put the result. 3594375Seric ** 3604375Seric ** Returns: 3614375Seric ** none. 3624375Seric ** 3634375Seric ** Side Effects: 3644375Seric ** none. 3654375Seric */ 3664375Seric 3675196Seric buildfname(p, login, buf) 3685196Seric register char *p; 3695196Seric char *login; 3704375Seric char *buf; 3714375Seric { 3724375Seric register char *bp = buf; 3734375Seric 3744438Seric if (*p == '*') 3754438Seric p++; 3766278Seric while (*p != '\0' && *p != ',' && *p != ';' && *p != '%') 3774375Seric { 3784375Seric if (*p == '&') 3794375Seric { 3805196Seric (void) strcpy(bp, login); 3814375Seric *bp = toupper(*bp); 3824375Seric while (*bp != '\0') 3834375Seric bp++; 3844375Seric p++; 3854375Seric } 3864375Seric else 3874375Seric *bp++ = *p++; 3884375Seric } 3894375Seric *bp = '\0'; 3904375Seric } 3914375Seric /* 3924538Seric ** SAFEFILE -- return true if a file exists and is safe for a user. 3934538Seric ** 3944538Seric ** Parameters: 3954538Seric ** fn -- filename to check. 3964538Seric ** uid -- uid to compare against. 3974538Seric ** mode -- mode bits that must match. 3984538Seric ** 3994538Seric ** Returns: 4004538Seric ** TRUE if fn exists, is owned by uid, and matches mode. 4014538Seric ** FALSE otherwise. 4024538Seric ** 4034538Seric ** Side Effects: 4044538Seric ** none. 4054538Seric */ 4064538Seric 4074538Seric bool 4084538Seric safefile(fn, uid, mode) 4094538Seric char *fn; 4104538Seric int uid; 4114538Seric int mode; 4124538Seric { 4134538Seric struct stat stbuf; 4144538Seric 4154538Seric if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && 4164538Seric (stbuf.st_mode & mode) == mode) 4174538Seric return (TRUE); 41811936Seric errno = 0; 4194538Seric return (FALSE); 4204538Seric } 4214538Seric /* 4224557Seric ** FIXCRLF -- fix <CR><LF> in line. 4234557Seric ** 4244557Seric ** Looks for the <CR><LF> combination and turns it into the 4254557Seric ** UNIX canonical <NL> character. It only takes one line, 4264557Seric ** i.e., it is assumed that the first <NL> found is the end 4274557Seric ** of the line. 4284557Seric ** 4294557Seric ** Parameters: 4304557Seric ** line -- the line to fix. 4314557Seric ** stripnl -- if true, strip the newline also. 4324557Seric ** 4334557Seric ** Returns: 4344557Seric ** none. 4354557Seric ** 4364557Seric ** Side Effects: 4374557Seric ** line is changed in place. 4384557Seric */ 4394557Seric 4404557Seric fixcrlf(line, stripnl) 4414557Seric char *line; 4424557Seric bool stripnl; 4434557Seric { 4444557Seric register char *p; 4454557Seric 4464557Seric p = index(line, '\n'); 4474557Seric if (p == NULL) 4484557Seric return; 4494794Seric if (p[-1] == '\r') 4504557Seric p--; 4514557Seric if (!stripnl) 4524557Seric *p++ = '\n'; 4534557Seric *p = '\0'; 4544557Seric } 4554557Seric /* 4566890Seric ** DFOPEN -- determined file open 4576890Seric ** 4586890Seric ** This routine has the semantics of fopen, except that it will 4596890Seric ** keep trying a few times to make this happen. The idea is that 4606890Seric ** on very loaded systems, we may run out of resources (inodes, 4616890Seric ** whatever), so this tries to get around it. 4626890Seric */ 4636890Seric 4646890Seric FILE * 4656890Seric dfopen(filename, mode) 4666890Seric char *filename; 4676890Seric char *mode; 4686890Seric { 4696890Seric register int tries; 4706890Seric register FILE *fp; 4716890Seric 4726890Seric for (tries = 0; tries < 10; tries++) 4736890Seric { 474*25618Seric sleep((unsigned) (10 * tries)); 4756890Seric errno = 0; 4766890Seric fp = fopen(filename, mode); 4779376Seric if (fp != NULL) 4786890Seric break; 4799376Seric if (errno != ENFILE && errno != EINTR) 4809376Seric break; 4816890Seric } 48211936Seric errno = 0; 4836890Seric return (fp); 4846890Seric } 4857124Seric /* 4867124Seric ** PUTLINE -- put a line like fputs obeying SMTP conventions 4877124Seric ** 4887753Seric ** This routine always guarantees outputing a newline (or CRLF, 4897753Seric ** as appropriate) at the end of the string. 4907753Seric ** 4917124Seric ** Parameters: 4927124Seric ** l -- line to put. 4937124Seric ** fp -- file to put it onto. 49410172Seric ** m -- the mailer used to control output. 4957124Seric ** 4967124Seric ** Returns: 4977124Seric ** none 4987124Seric ** 4997124Seric ** Side Effects: 5007124Seric ** output of l to fp. 5017124Seric */ 5027124Seric 5037753Seric # define SMTPLINELIM 990 /* maximum line length */ 5047124Seric 50510172Seric putline(l, fp, m) 5067753Seric register char *l; 5077124Seric FILE *fp; 50810172Seric MAILER *m; 5097124Seric { 5107124Seric register char *p; 5117753Seric char svchar; 5127124Seric 51311275Seric /* strip out 0200 bits -- these can look like TELNET protocol */ 51411275Seric if (bitnset(M_LIMITS, m->m_flags)) 51511275Seric { 51611275Seric p = l; 51711275Seric while ((*p++ &= ~0200) != 0) 51811275Seric continue; 51911275Seric } 52011275Seric 5217753Seric do 5227124Seric { 5237753Seric /* find the end of the line */ 5247753Seric p = index(l, '\n'); 5257753Seric if (p == NULL) 5267753Seric p = &l[strlen(l)]; 5277124Seric 5287753Seric /* check for line overflow */ 52911275Seric while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags)) 5307753Seric { 5317753Seric register char *q = &l[SMTPLINELIM - 1]; 5327124Seric 5337753Seric svchar = *q; 5347753Seric *q = '\0'; 53510685Seric if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 53623105Seric (void) putc('.', fp); 5377753Seric fputs(l, fp); 53823105Seric (void) putc('!', fp); 53910326Seric fputs(m->m_eol, fp); 5407753Seric *q = svchar; 5417753Seric l = q; 5427753Seric } 5437124Seric 5447753Seric /* output last part */ 5457753Seric svchar = *p; 5467753Seric *p = '\0'; 54710685Seric if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 54823105Seric (void) putc('.', fp); 5497124Seric fputs(l, fp); 55010326Seric fputs(m->m_eol, fp); 5517753Seric *p = svchar; 5527753Seric l = p; 5537753Seric if (*l == '\n') 5547753Seric l++; 5557753Seric } while (l[0] != '\0'); 5567124Seric } 5577676Seric /* 5587676Seric ** XUNLINK -- unlink a file, doing logging as appropriate. 5597676Seric ** 5607676Seric ** Parameters: 5617676Seric ** f -- name of file to unlink. 5627676Seric ** 5637676Seric ** Returns: 5647676Seric ** none. 5657676Seric ** 5667676Seric ** Side Effects: 5677676Seric ** f is unlinked. 5687676Seric */ 5697676Seric 5707676Seric xunlink(f) 5717676Seric char *f; 5727676Seric { 5737676Seric register int i; 5747676Seric 5757676Seric # ifdef LOG 5767676Seric if (LogLevel > 20) 5777812Seric syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f); 5787676Seric # endif LOG 5797676Seric 5807676Seric i = unlink(f); 5817676Seric # ifdef LOG 5827676Seric if (i < 0 && LogLevel > 21) 5837942Seric syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 5847676Seric # endif LOG 5857676Seric } 5867685Seric /* 58714885Seric ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 5887685Seric ** 5897685Seric ** Parameters: 5907685Seric ** buf -- place to put the input line. 5917685Seric ** siz -- size of buf. 5927685Seric ** fp -- file to read from. 5937685Seric ** 5947685Seric ** Returns: 59515533Seric ** NULL on error (including timeout). This will also leave 59615533Seric ** buf containing a null string. 5977685Seric ** buf otherwise. 5987685Seric ** 5997685Seric ** Side Effects: 6007685Seric ** none. 6017685Seric */ 6027685Seric 60314885Seric static jmp_buf CtxReadTimeout; 6047685Seric 60516138Seric #ifndef ETIMEDOUT 60616138Seric #define ETIMEDOUT EINTR 60716138Seric #endif 60816138Seric 6097685Seric char * 6107685Seric sfgets(buf, siz, fp) 6117685Seric char *buf; 6127685Seric int siz; 6137685Seric FILE *fp; 6147685Seric { 6157942Seric register EVENT *ev = NULL; 6167685Seric register char *p; 6177685Seric extern readtimeout(); 6187685Seric 61914885Seric /* set the timeout */ 6207942Seric if (ReadTimeout != 0) 62114885Seric { 62214885Seric if (setjmp(CtxReadTimeout) != 0) 62314885Seric { 62416138Seric errno = ETIMEDOUT; 62525050Seric syserr("net timeout"); 62619037Seric buf[0] = '\0'; 62714885Seric return (NULL); 62814885Seric } 62916138Seric ev = setevent((time_t) ReadTimeout, readtimeout, 0); 63014885Seric } 63114885Seric 63214885Seric /* try to read */ 63315533Seric p = NULL; 63415533Seric while (p == NULL && !feof(fp) && !ferror(fp)) 6357942Seric { 6367942Seric errno = 0; 6377942Seric p = fgets(buf, siz, fp); 63815533Seric if (errno == EINTR) 63915533Seric clearerr(fp); 64015533Seric } 64114885Seric 64214885Seric /* clear the event if it has not sprung */ 6437685Seric clrevent(ev); 64414885Seric 64514885Seric /* clean up the books and exit */ 6468055Seric LineNumber++; 64715533Seric if (p == NULL) 64816880Seric { 64915533Seric buf[0] = '\0'; 65016880Seric return (NULL); 65116880Seric } 65216880Seric for (p = buf; *p != '\0'; p++) 65316880Seric *p &= ~0200; 65416880Seric return (buf); 6557685Seric } 6567685Seric 6577685Seric static 6587685Seric readtimeout() 6597685Seric { 66014885Seric longjmp(CtxReadTimeout, 1); 6617685Seric } 6627786Seric /* 6637786Seric ** FGETFOLDED -- like fgets, but know about folded lines. 6647786Seric ** 6657786Seric ** Parameters: 6667786Seric ** buf -- place to put result. 6677786Seric ** n -- bytes available. 6687786Seric ** f -- file to read from. 6697786Seric ** 6707786Seric ** Returns: 6717786Seric ** buf on success, NULL on error or EOF. 6727786Seric ** 6737786Seric ** Side Effects: 6747786Seric ** buf gets lines from f, with continuation lines (lines 6757786Seric ** with leading white space) appended. CRLF's are mapped 6767786Seric ** into single newlines. Any trailing NL is stripped. 6777786Seric */ 6787786Seric 6797786Seric char * 6807786Seric fgetfolded(buf, n, f) 6817786Seric char *buf; 6827786Seric register int n; 6837786Seric FILE *f; 6847786Seric { 6857786Seric register char *p = buf; 6867786Seric register int i; 6877786Seric 6887786Seric n--; 68917350Seric while ((i = getc(f)) != EOF) 6907786Seric { 69117350Seric if (i == '\r') 69217350Seric { 69317350Seric i = getc(f); 69417350Seric if (i != '\n') 69517350Seric { 69617350Seric if (i != EOF) 69723105Seric (void) ungetc(i, f); 69817350Seric i = '\r'; 69917350Seric } 70017350Seric } 70117350Seric if (--n > 0) 70217350Seric *p++ = i; 70317350Seric if (i == '\n') 70417350Seric { 70517350Seric LineNumber++; 70617350Seric i = getc(f); 70717350Seric if (i != EOF) 70823105Seric (void) ungetc(i, f); 70917350Seric if (i != ' ' && i != '\t') 71017350Seric { 71117350Seric *--p = '\0'; 71217350Seric return (buf); 71317350Seric } 71417350Seric } 7157786Seric } 7167786Seric return (NULL); 7177786Seric } 7187860Seric /* 7197886Seric ** CURTIME -- return current time. 7207886Seric ** 7217886Seric ** Parameters: 7227886Seric ** none. 7237886Seric ** 7247886Seric ** Returns: 7257886Seric ** the current time. 7267886Seric ** 7277886Seric ** Side Effects: 7287886Seric ** none. 7297886Seric */ 7307886Seric 7317886Seric time_t 7327886Seric curtime() 7337886Seric { 7347886Seric auto time_t t; 7357886Seric 7367886Seric (void) time(&t); 7377886Seric return (t); 7387886Seric } 7398264Seric /* 7408264Seric ** ATOBOOL -- convert a string representation to boolean. 7418264Seric ** 7428264Seric ** Defaults to "TRUE" 7438264Seric ** 7448264Seric ** Parameters: 7458264Seric ** s -- string to convert. Takes "tTyY" as true, 7468264Seric ** others as false. 7478264Seric ** 7488264Seric ** Returns: 7498264Seric ** A boolean representation of the string. 7508264Seric ** 7518264Seric ** Side Effects: 7528264Seric ** none. 7538264Seric */ 7548264Seric 7558264Seric bool 7568264Seric atobool(s) 7578264Seric register char *s; 7588264Seric { 7598264Seric if (*s == '\0' || index("tTyY", *s) != NULL) 7608264Seric return (TRUE); 7618264Seric return (FALSE); 7628264Seric } 7639048Seric /* 7649048Seric ** ATOOCT -- convert a string representation to octal. 7659048Seric ** 7669048Seric ** Parameters: 7679048Seric ** s -- string to convert. 7689048Seric ** 7699048Seric ** Returns: 7709048Seric ** An integer representing the string interpreted as an 7719048Seric ** octal number. 7729048Seric ** 7739048Seric ** Side Effects: 7749048Seric ** none. 7759048Seric */ 7769048Seric 7779048Seric atooct(s) 7789048Seric register char *s; 7799048Seric { 7809048Seric register int i = 0; 7819048Seric 7829048Seric while (*s >= '0' && *s <= '7') 7839048Seric i = (i << 3) | (*s++ - '0'); 7849048Seric return (i); 7859048Seric } 7869376Seric /* 7879376Seric ** WAITFOR -- wait for a particular process id. 7889376Seric ** 7899376Seric ** Parameters: 7909376Seric ** pid -- process id to wait for. 7919376Seric ** 7929376Seric ** Returns: 7939376Seric ** status of pid. 7949376Seric ** -1 if pid never shows up. 7959376Seric ** 7969376Seric ** Side Effects: 7979376Seric ** none. 7989376Seric */ 7999376Seric 8009376Seric waitfor(pid) 8019376Seric int pid; 8029376Seric { 8039376Seric auto int st; 8049376Seric int i; 8059376Seric 8069376Seric do 8079376Seric { 8089376Seric errno = 0; 8099376Seric i = wait(&st); 8109376Seric } while ((i >= 0 || errno == EINTR) && i != pid); 8119376Seric if (i < 0) 8129376Seric st = -1; 8139376Seric return (st); 8149376Seric } 8159376Seric /* 81610685Seric ** BITINTERSECT -- tell if two bitmaps intersect 81710685Seric ** 81810685Seric ** Parameters: 81910685Seric ** a, b -- the bitmaps in question 82010685Seric ** 82110685Seric ** Returns: 82210685Seric ** TRUE if they have a non-null intersection 82310685Seric ** FALSE otherwise 82410685Seric ** 82510685Seric ** Side Effects: 82610685Seric ** none. 82710685Seric */ 82810685Seric 82910685Seric bool 83010685Seric bitintersect(a, b) 83110685Seric BITMAP a; 83210685Seric BITMAP b; 83310685Seric { 83410685Seric int i; 83510685Seric 83610685Seric for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 83710685Seric if ((a[i] & b[i]) != 0) 83810685Seric return (TRUE); 83910685Seric return (FALSE); 84010685Seric } 84110685Seric /* 84210685Seric ** BITZEROP -- tell if a bitmap is all zero 84310685Seric ** 84410685Seric ** Parameters: 84510685Seric ** map -- the bit map to check 84610685Seric ** 84710685Seric ** Returns: 84810685Seric ** TRUE if map is all zero. 84910685Seric ** FALSE if there are any bits set in map. 85010685Seric ** 85110685Seric ** Side Effects: 85210685Seric ** none. 85310685Seric */ 85410685Seric 85510685Seric bool 85610685Seric bitzerop(map) 85710685Seric BITMAP map; 85810685Seric { 85910685Seric int i; 86010685Seric 86110685Seric for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 86210685Seric if (map[i] != 0) 86310685Seric return (FALSE); 86410685Seric return (TRUE); 86510685Seric } 866