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*33724Sbostic static char SccsId[] = "@(#)util.c 5.10 (Berkeley) 03/13/88"; 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> 206890Seric # include "sendmail.h" 21298Seric 22298Seric /* 23298Seric ** STRIPQUOTES -- Strip quotes & quote bits from a string. 24298Seric ** 25298Seric ** Runs through a string and strips off unquoted quote 26298Seric ** characters and quote bits. This is done in place. 27298Seric ** 28298Seric ** Parameters: 29298Seric ** s -- the string to strip. 304101Seric ** qf -- if set, remove actual `` " '' characters 314101Seric ** as well as the quote bits. 32298Seric ** 33298Seric ** Returns: 34298Seric ** none. 35298Seric ** 36298Seric ** Side Effects: 37298Seric ** none. 38298Seric ** 39298Seric ** Called By: 40298Seric ** deliver 41298Seric */ 42298Seric 434101Seric stripquotes(s, qf) 44298Seric char *s; 454101Seric bool qf; 46298Seric { 47298Seric register char *p; 48298Seric register char *q; 49298Seric register char c; 50298Seric 514101Seric if (s == NULL) 524101Seric return; 534101Seric 54298Seric for (p = q = s; (c = *p++) != '\0'; ) 55298Seric { 564101Seric if (c != '"' || !qf) 57298Seric *q++ = c & 0177; 58298Seric } 59298Seric *q = '\0'; 60298Seric } 61298Seric /* 629043Seric ** QSTRLEN -- give me the string length assuming 0200 bits add a char 639043Seric ** 649043Seric ** Parameters: 659043Seric ** s -- the string to measure. 669043Seric ** 679043Seric ** Reurns: 689043Seric ** The length of s, including space for backslash escapes. 699043Seric ** 709043Seric ** Side Effects: 719043Seric ** none. 729043Seric */ 739043Seric 749043Seric qstrlen(s) 759043Seric register char *s; 769043Seric { 779043Seric register int l = 0; 789043Seric register char c; 799043Seric 809043Seric while ((c = *s++) != '\0') 819043Seric { 829043Seric if (bitset(0200, c)) 839043Seric l++; 849043Seric l++; 859043Seric } 869043Seric return (l); 879043Seric } 889043Seric /* 892900Seric ** CAPITALIZE -- return a copy of a string, properly capitalized. 902900Seric ** 912900Seric ** Parameters: 922900Seric ** s -- the string to capitalize. 932900Seric ** 942900Seric ** Returns: 952900Seric ** a pointer to a properly capitalized string. 962900Seric ** 972900Seric ** Side Effects: 982900Seric ** none. 992900Seric */ 1002900Seric 1012900Seric char * 1022900Seric capitalize(s) 1032900Seric register char *s; 1042900Seric { 1052900Seric static char buf[50]; 1062900Seric register char *p; 1072900Seric 1082900Seric p = buf; 1092900Seric 1102900Seric for (;;) 1112900Seric { 1122900Seric while (!isalpha(*s) && *s != '\0') 1132900Seric *p++ = *s++; 1142900Seric if (*s == '\0') 1152900Seric break; 1162900Seric *p++ = toupper(*s++); 1172900Seric while (isalpha(*s)) 1182900Seric *p++ = *s++; 1192900Seric } 1202900Seric 1212900Seric *p = '\0'; 1222900Seric return (buf); 1232900Seric } 1242900Seric /* 125298Seric ** XALLOC -- Allocate memory and bitch wildly on failure. 126298Seric ** 127298Seric ** THIS IS A CLUDGE. This should be made to give a proper 128298Seric ** error -- but after all, what can we do? 129298Seric ** 130298Seric ** Parameters: 131298Seric ** sz -- size of area to allocate. 132298Seric ** 133298Seric ** Returns: 134298Seric ** pointer to data region. 135298Seric ** 136298Seric ** Side Effects: 137298Seric ** Memory is allocated. 138298Seric */ 139298Seric 140298Seric char * 141298Seric xalloc(sz) 1427007Seric register int sz; 143298Seric { 144298Seric register char *p; 14523121Seric extern char *malloc(); 146298Seric 14723121Seric p = malloc((unsigned) 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 22023105Seric (void) putchar(' '); 2213151Seric xputs(*av++); 2223151Seric } 22323105Seric (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 { 242*33724Sbostic return(isascii(c) && isupper(c) ? tolower(c) : c); 2433151Seric } 2443151Seric /* 2453151Seric ** XPUTS -- put string doing control escapes. 2463151Seric ** 2473151Seric ** Parameters: 2483151Seric ** s -- string to put. 2493151Seric ** 2503151Seric ** Returns: 2513151Seric ** none. 2523151Seric ** 2533151Seric ** Side Effects: 2543151Seric ** output to stdout 2553151Seric */ 2563151Seric 2573151Seric xputs(s) 2583151Seric register char *s; 2593151Seric { 2603151Seric register char c; 2613151Seric 2628055Seric if (s == NULL) 2638055Seric { 2648055Seric printf("<null>"); 2658055Seric return; 2668055Seric } 26723105Seric (void) putchar('"'); 2683151Seric while ((c = *s++) != '\0') 2693151Seric { 2703151Seric if (!isascii(c)) 2713151Seric { 27223105Seric (void) putchar('\\'); 2733151Seric c &= 0177; 2743151Seric } 27510326Seric if (c < 040 || c >= 0177) 2763151Seric { 27723105Seric (void) putchar('^'); 27810326Seric c ^= 0100; 2793151Seric } 28023105Seric (void) putchar(c); 2813151Seric } 28223105Seric (void) putchar('"'); 2834086Seric (void) fflush(stdout); 2843151Seric } 2853151Seric /* 2863151Seric ** MAKELOWER -- Translate a line into lower case 2873151Seric ** 2883151Seric ** Parameters: 2893151Seric ** p -- the string to translate. If NULL, return is 2903151Seric ** immediate. 2913151Seric ** 2923151Seric ** Returns: 2933151Seric ** none. 2943151Seric ** 2953151Seric ** Side Effects: 2963151Seric ** String pointed to by p is translated to lower case. 2973151Seric ** 2983151Seric ** Called By: 2993151Seric ** parse 3003151Seric */ 3013151Seric 3023151Seric makelower(p) 3033151Seric register char *p; 3043151Seric { 3053151Seric register char c; 3063151Seric 3073151Seric if (p == NULL) 3083151Seric return; 3093151Seric for (; (c = *p) != '\0'; p++) 3103151Seric if (isascii(c) && isupper(c)) 311*33724Sbostic *p = tolower(c); 3123151Seric } 3134059Seric /* 3145196Seric ** BUILDFNAME -- build full name from gecos style entry. 3154375Seric ** 3165196Seric ** This routine interprets the strange entry that would appear 3175196Seric ** in the GECOS field of the password file. 3185196Seric ** 3194375Seric ** Parameters: 3205196Seric ** p -- name to build. 3215196Seric ** login -- the login name of this user (for &). 3225196Seric ** buf -- place to put the result. 3234375Seric ** 3244375Seric ** Returns: 3254375Seric ** none. 3264375Seric ** 3274375Seric ** Side Effects: 3284375Seric ** none. 3294375Seric */ 3304375Seric 3315196Seric buildfname(p, login, buf) 3325196Seric register char *p; 3335196Seric char *login; 3344375Seric char *buf; 3354375Seric { 3364375Seric register char *bp = buf; 3374375Seric 3384438Seric if (*p == '*') 3394438Seric p++; 3406278Seric while (*p != '\0' && *p != ',' && *p != ';' && *p != '%') 3414375Seric { 3424375Seric if (*p == '&') 3434375Seric { 3445196Seric (void) strcpy(bp, login); 3454375Seric *bp = toupper(*bp); 3464375Seric while (*bp != '\0') 3474375Seric bp++; 3484375Seric p++; 3494375Seric } 3504375Seric else 3514375Seric *bp++ = *p++; 3524375Seric } 3534375Seric *bp = '\0'; 3544375Seric } 3554375Seric /* 3564538Seric ** SAFEFILE -- return true if a file exists and is safe for a user. 3574538Seric ** 3584538Seric ** Parameters: 3594538Seric ** fn -- filename to check. 3604538Seric ** uid -- uid to compare against. 3614538Seric ** mode -- mode bits that must match. 3624538Seric ** 3634538Seric ** Returns: 3644538Seric ** TRUE if fn exists, is owned by uid, and matches mode. 3654538Seric ** FALSE otherwise. 3664538Seric ** 3674538Seric ** Side Effects: 3684538Seric ** none. 3694538Seric */ 3704538Seric 3714538Seric bool 3724538Seric safefile(fn, uid, mode) 3734538Seric char *fn; 3744538Seric int uid; 3754538Seric int mode; 3764538Seric { 3774538Seric struct stat stbuf; 3784538Seric 3794538Seric if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && 3804538Seric (stbuf.st_mode & mode) == mode) 3814538Seric return (TRUE); 38211936Seric errno = 0; 3834538Seric return (FALSE); 3844538Seric } 3854538Seric /* 3864557Seric ** FIXCRLF -- fix <CR><LF> in line. 3874557Seric ** 3884557Seric ** Looks for the <CR><LF> combination and turns it into the 3894557Seric ** UNIX canonical <NL> character. It only takes one line, 3904557Seric ** i.e., it is assumed that the first <NL> found is the end 3914557Seric ** of the line. 3924557Seric ** 3934557Seric ** Parameters: 3944557Seric ** line -- the line to fix. 3954557Seric ** stripnl -- if true, strip the newline also. 3964557Seric ** 3974557Seric ** Returns: 3984557Seric ** none. 3994557Seric ** 4004557Seric ** Side Effects: 4014557Seric ** line is changed in place. 4024557Seric */ 4034557Seric 4044557Seric fixcrlf(line, stripnl) 4054557Seric char *line; 4064557Seric bool stripnl; 4074557Seric { 4084557Seric register char *p; 4094557Seric 4104557Seric p = index(line, '\n'); 4114557Seric if (p == NULL) 4124557Seric return; 4134794Seric if (p[-1] == '\r') 4144557Seric p--; 4154557Seric if (!stripnl) 4164557Seric *p++ = '\n'; 4174557Seric *p = '\0'; 4184557Seric } 4194557Seric /* 4206890Seric ** DFOPEN -- determined file open 4216890Seric ** 4226890Seric ** This routine has the semantics of fopen, except that it will 4236890Seric ** keep trying a few times to make this happen. The idea is that 4246890Seric ** on very loaded systems, we may run out of resources (inodes, 4256890Seric ** whatever), so this tries to get around it. 4266890Seric */ 4276890Seric 4286890Seric FILE * 4296890Seric dfopen(filename, mode) 4306890Seric char *filename; 4316890Seric char *mode; 4326890Seric { 4336890Seric register int tries; 4346890Seric register FILE *fp; 4356890Seric 4366890Seric for (tries = 0; tries < 10; tries++) 4376890Seric { 43825618Seric sleep((unsigned) (10 * tries)); 4396890Seric errno = 0; 4406890Seric fp = fopen(filename, mode); 4419376Seric if (fp != NULL) 4426890Seric break; 4439376Seric if (errno != ENFILE && errno != EINTR) 4449376Seric break; 4456890Seric } 44611936Seric errno = 0; 4476890Seric return (fp); 4486890Seric } 4497124Seric /* 4507124Seric ** PUTLINE -- put a line like fputs obeying SMTP conventions 4517124Seric ** 4527753Seric ** This routine always guarantees outputing a newline (or CRLF, 4537753Seric ** as appropriate) at the end of the string. 4547753Seric ** 4557124Seric ** Parameters: 4567124Seric ** l -- line to put. 4577124Seric ** fp -- file to put it onto. 45810172Seric ** m -- the mailer used to control output. 4597124Seric ** 4607124Seric ** Returns: 4617124Seric ** none 4627124Seric ** 4637124Seric ** Side Effects: 4647124Seric ** output of l to fp. 4657124Seric */ 4667124Seric 4677753Seric # define SMTPLINELIM 990 /* maximum line length */ 4687124Seric 46910172Seric putline(l, fp, m) 4707753Seric register char *l; 4717124Seric FILE *fp; 47210172Seric MAILER *m; 4737124Seric { 4747124Seric register char *p; 4757753Seric char svchar; 4767124Seric 47711275Seric /* strip out 0200 bits -- these can look like TELNET protocol */ 47811275Seric if (bitnset(M_LIMITS, m->m_flags)) 47911275Seric { 48011275Seric p = l; 48111275Seric while ((*p++ &= ~0200) != 0) 48211275Seric continue; 48311275Seric } 48411275Seric 4857753Seric do 4867124Seric { 4877753Seric /* find the end of the line */ 4887753Seric p = index(l, '\n'); 4897753Seric if (p == NULL) 4907753Seric p = &l[strlen(l)]; 4917124Seric 4927753Seric /* check for line overflow */ 49311275Seric while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags)) 4947753Seric { 4957753Seric register char *q = &l[SMTPLINELIM - 1]; 4967124Seric 4977753Seric svchar = *q; 4987753Seric *q = '\0'; 49910685Seric if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 50023105Seric (void) putc('.', fp); 5017753Seric fputs(l, fp); 50223105Seric (void) putc('!', fp); 50310326Seric fputs(m->m_eol, fp); 5047753Seric *q = svchar; 5057753Seric l = q; 5067753Seric } 5077124Seric 5087753Seric /* output last part */ 5097753Seric svchar = *p; 5107753Seric *p = '\0'; 51110685Seric if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 51223105Seric (void) putc('.', fp); 5137124Seric fputs(l, fp); 51410326Seric fputs(m->m_eol, fp); 5157753Seric *p = svchar; 5167753Seric l = p; 5177753Seric if (*l == '\n') 5187753Seric l++; 5197753Seric } while (l[0] != '\0'); 5207124Seric } 5217676Seric /* 5227676Seric ** XUNLINK -- unlink a file, doing logging as appropriate. 5237676Seric ** 5247676Seric ** Parameters: 5257676Seric ** f -- name of file to unlink. 5267676Seric ** 5277676Seric ** Returns: 5287676Seric ** none. 5297676Seric ** 5307676Seric ** Side Effects: 5317676Seric ** f is unlinked. 5327676Seric */ 5337676Seric 5347676Seric xunlink(f) 5357676Seric char *f; 5367676Seric { 5377676Seric register int i; 5387676Seric 5397676Seric # ifdef LOG 5407676Seric if (LogLevel > 20) 5417812Seric syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f); 5427676Seric # endif LOG 5437676Seric 5447676Seric i = unlink(f); 5457676Seric # ifdef LOG 5467676Seric if (i < 0 && LogLevel > 21) 5477942Seric syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 5487676Seric # endif LOG 5497676Seric } 5507685Seric /* 55114885Seric ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 5527685Seric ** 5537685Seric ** Parameters: 5547685Seric ** buf -- place to put the input line. 5557685Seric ** siz -- size of buf. 5567685Seric ** fp -- file to read from. 5577685Seric ** 5587685Seric ** Returns: 55915533Seric ** NULL on error (including timeout). This will also leave 56015533Seric ** buf containing a null string. 5617685Seric ** buf otherwise. 5627685Seric ** 5637685Seric ** Side Effects: 5647685Seric ** none. 5657685Seric */ 5667685Seric 56714885Seric static jmp_buf CtxReadTimeout; 5687685Seric 56916138Seric #ifndef ETIMEDOUT 57016138Seric #define ETIMEDOUT EINTR 57116138Seric #endif 57216138Seric 5737685Seric char * 5747685Seric sfgets(buf, siz, fp) 5757685Seric char *buf; 5767685Seric int siz; 5777685Seric FILE *fp; 5787685Seric { 5797942Seric register EVENT *ev = NULL; 5807685Seric register char *p; 5817685Seric extern readtimeout(); 5827685Seric 58314885Seric /* set the timeout */ 5847942Seric if (ReadTimeout != 0) 58514885Seric { 58614885Seric if (setjmp(CtxReadTimeout) != 0) 58714885Seric { 58816138Seric errno = ETIMEDOUT; 58925050Seric syserr("net timeout"); 59019037Seric buf[0] = '\0'; 59114885Seric return (NULL); 59214885Seric } 59316138Seric ev = setevent((time_t) ReadTimeout, readtimeout, 0); 59414885Seric } 59514885Seric 59614885Seric /* try to read */ 59715533Seric p = NULL; 59815533Seric while (p == NULL && !feof(fp) && !ferror(fp)) 5997942Seric { 6007942Seric errno = 0; 6017942Seric p = fgets(buf, siz, fp); 60215533Seric if (errno == EINTR) 60315533Seric clearerr(fp); 60415533Seric } 60514885Seric 60614885Seric /* clear the event if it has not sprung */ 6077685Seric clrevent(ev); 60814885Seric 60914885Seric /* clean up the books and exit */ 6108055Seric LineNumber++; 61115533Seric if (p == NULL) 61216880Seric { 61315533Seric buf[0] = '\0'; 61416880Seric return (NULL); 61516880Seric } 61616880Seric for (p = buf; *p != '\0'; p++) 61716880Seric *p &= ~0200; 61816880Seric return (buf); 6197685Seric } 6207685Seric 6217685Seric static 6227685Seric readtimeout() 6237685Seric { 62414885Seric longjmp(CtxReadTimeout, 1); 6257685Seric } 6267786Seric /* 6277786Seric ** FGETFOLDED -- like fgets, but know about folded lines. 6287786Seric ** 6297786Seric ** Parameters: 6307786Seric ** buf -- place to put result. 6317786Seric ** n -- bytes available. 6327786Seric ** f -- file to read from. 6337786Seric ** 6347786Seric ** Returns: 6357786Seric ** buf on success, NULL on error or EOF. 6367786Seric ** 6377786Seric ** Side Effects: 6387786Seric ** buf gets lines from f, with continuation lines (lines 6397786Seric ** with leading white space) appended. CRLF's are mapped 6407786Seric ** into single newlines. Any trailing NL is stripped. 6417786Seric */ 6427786Seric 6437786Seric char * 6447786Seric fgetfolded(buf, n, f) 6457786Seric char *buf; 6467786Seric register int n; 6477786Seric FILE *f; 6487786Seric { 6497786Seric register char *p = buf; 6507786Seric register int i; 6517786Seric 6527786Seric n--; 65317350Seric while ((i = getc(f)) != EOF) 6547786Seric { 65517350Seric if (i == '\r') 65617350Seric { 65717350Seric i = getc(f); 65817350Seric if (i != '\n') 65917350Seric { 66017350Seric if (i != EOF) 66123105Seric (void) ungetc(i, f); 66217350Seric i = '\r'; 66317350Seric } 66417350Seric } 66517350Seric if (--n > 0) 66617350Seric *p++ = i; 66717350Seric if (i == '\n') 66817350Seric { 66917350Seric LineNumber++; 67017350Seric i = getc(f); 67117350Seric if (i != EOF) 67223105Seric (void) ungetc(i, f); 67317350Seric if (i != ' ' && i != '\t') 67417350Seric { 67517350Seric *--p = '\0'; 67617350Seric return (buf); 67717350Seric } 67817350Seric } 6797786Seric } 6807786Seric return (NULL); 6817786Seric } 6827860Seric /* 6837886Seric ** CURTIME -- return current time. 6847886Seric ** 6857886Seric ** Parameters: 6867886Seric ** none. 6877886Seric ** 6887886Seric ** Returns: 6897886Seric ** the current time. 6907886Seric ** 6917886Seric ** Side Effects: 6927886Seric ** none. 6937886Seric */ 6947886Seric 6957886Seric time_t 6967886Seric curtime() 6977886Seric { 6987886Seric auto time_t t; 6997886Seric 7007886Seric (void) time(&t); 7017886Seric return (t); 7027886Seric } 7038264Seric /* 7048264Seric ** ATOBOOL -- convert a string representation to boolean. 7058264Seric ** 7068264Seric ** Defaults to "TRUE" 7078264Seric ** 7088264Seric ** Parameters: 7098264Seric ** s -- string to convert. Takes "tTyY" as true, 7108264Seric ** others as false. 7118264Seric ** 7128264Seric ** Returns: 7138264Seric ** A boolean representation of the string. 7148264Seric ** 7158264Seric ** Side Effects: 7168264Seric ** none. 7178264Seric */ 7188264Seric 7198264Seric bool 7208264Seric atobool(s) 7218264Seric register char *s; 7228264Seric { 7238264Seric if (*s == '\0' || index("tTyY", *s) != NULL) 7248264Seric return (TRUE); 7258264Seric return (FALSE); 7268264Seric } 7279048Seric /* 7289048Seric ** ATOOCT -- convert a string representation to octal. 7299048Seric ** 7309048Seric ** Parameters: 7319048Seric ** s -- string to convert. 7329048Seric ** 7339048Seric ** Returns: 7349048Seric ** An integer representing the string interpreted as an 7359048Seric ** octal number. 7369048Seric ** 7379048Seric ** Side Effects: 7389048Seric ** none. 7399048Seric */ 7409048Seric 7419048Seric atooct(s) 7429048Seric register char *s; 7439048Seric { 7449048Seric register int i = 0; 7459048Seric 7469048Seric while (*s >= '0' && *s <= '7') 7479048Seric i = (i << 3) | (*s++ - '0'); 7489048Seric return (i); 7499048Seric } 7509376Seric /* 7519376Seric ** WAITFOR -- wait for a particular process id. 7529376Seric ** 7539376Seric ** Parameters: 7549376Seric ** pid -- process id to wait for. 7559376Seric ** 7569376Seric ** Returns: 7579376Seric ** status of pid. 7589376Seric ** -1 if pid never shows up. 7599376Seric ** 7609376Seric ** Side Effects: 7619376Seric ** none. 7629376Seric */ 7639376Seric 7649376Seric waitfor(pid) 7659376Seric int pid; 7669376Seric { 7679376Seric auto int st; 7689376Seric int i; 7699376Seric 7709376Seric do 7719376Seric { 7729376Seric errno = 0; 7739376Seric i = wait(&st); 7749376Seric } while ((i >= 0 || errno == EINTR) && i != pid); 7759376Seric if (i < 0) 7769376Seric st = -1; 7779376Seric return (st); 7789376Seric } 7799376Seric /* 78010685Seric ** BITINTERSECT -- tell if two bitmaps intersect 78110685Seric ** 78210685Seric ** Parameters: 78310685Seric ** a, b -- the bitmaps in question 78410685Seric ** 78510685Seric ** Returns: 78610685Seric ** TRUE if they have a non-null intersection 78710685Seric ** FALSE otherwise 78810685Seric ** 78910685Seric ** Side Effects: 79010685Seric ** none. 79110685Seric */ 79210685Seric 79310685Seric bool 79410685Seric bitintersect(a, b) 79510685Seric BITMAP a; 79610685Seric BITMAP b; 79710685Seric { 79810685Seric int i; 79910685Seric 80010685Seric for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 80110685Seric if ((a[i] & b[i]) != 0) 80210685Seric return (TRUE); 80310685Seric return (FALSE); 80410685Seric } 80510685Seric /* 80610685Seric ** BITZEROP -- tell if a bitmap is all zero 80710685Seric ** 80810685Seric ** Parameters: 80910685Seric ** map -- the bit map to check 81010685Seric ** 81110685Seric ** Returns: 81210685Seric ** TRUE if map is all zero. 81310685Seric ** FALSE if there are any bits set in map. 81410685Seric ** 81510685Seric ** Side Effects: 81610685Seric ** none. 81710685Seric */ 81810685Seric 81910685Seric bool 82010685Seric bitzerop(map) 82110685Seric BITMAP map; 82210685Seric { 82310685Seric int i; 82410685Seric 82510685Seric for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 82610685Seric if (map[i] != 0) 82710685Seric return (FALSE); 82810685Seric return (TRUE); 82910685Seric } 830