122717Sdist /* 233731Sbostic * Copyright (c) 1988 Regents of the University of California. 333731Sbostic * All rights reserved. 433731Sbostic * 533731Sbostic * Redistribution and use in source and binary forms are permitted 633731Sbostic * provided that this notice is preserved and that due credit is given 733731Sbostic * to the University of California at Berkeley. The name of the University 833731Sbostic * may not be used to endorse or promote products derived from this 933731Sbostic * software without specific prior written permission. This software 1033731Sbostic * is provided ``as is'' without express or implied warranty. 1133731Sbostic * 1233731Sbostic * Sendmail 1333731Sbostic * Copyright (c) 1983 Eric P. Allman 1433731Sbostic * Berkeley, California 1533731Sbostic */ 1622717Sdist 1722717Sdist #ifndef lint 18*36291Sbostic static char sccsid[] = "@(#)util.c 5.14 (Berkeley) 12/05/88"; 1933731Sbostic #endif /* not lint */ 2022717Sdist 213151Seric # include <stdio.h> 224538Seric # include <sys/types.h> 234538Seric # include <sys/stat.h> 24298Seric # include <sysexits.h> 256890Seric # include <errno.h> 266890Seric # include "sendmail.h" 27298Seric 28298Seric /* 29298Seric ** STRIPQUOTES -- Strip quotes & quote bits from a string. 30298Seric ** 31298Seric ** Runs through a string and strips off unquoted quote 32298Seric ** characters and quote bits. This is done in place. 33298Seric ** 34298Seric ** Parameters: 35298Seric ** s -- the string to strip. 364101Seric ** qf -- if set, remove actual `` " '' characters 374101Seric ** as well as the quote bits. 38298Seric ** 39298Seric ** Returns: 40298Seric ** none. 41298Seric ** 42298Seric ** Side Effects: 43298Seric ** none. 44298Seric ** 45298Seric ** Called By: 46298Seric ** deliver 47298Seric */ 48298Seric 494101Seric stripquotes(s, qf) 50298Seric char *s; 514101Seric bool qf; 52298Seric { 53298Seric register char *p; 54298Seric register char *q; 55298Seric register char c; 56298Seric 574101Seric if (s == NULL) 584101Seric return; 594101Seric 60298Seric for (p = q = s; (c = *p++) != '\0'; ) 61298Seric { 624101Seric if (c != '"' || !qf) 63298Seric *q++ = c & 0177; 64298Seric } 65298Seric *q = '\0'; 66298Seric } 67298Seric /* 689043Seric ** QSTRLEN -- give me the string length assuming 0200 bits add a char 699043Seric ** 709043Seric ** Parameters: 719043Seric ** s -- the string to measure. 729043Seric ** 739043Seric ** Reurns: 749043Seric ** The length of s, including space for backslash escapes. 759043Seric ** 769043Seric ** Side Effects: 779043Seric ** none. 789043Seric */ 799043Seric 809043Seric qstrlen(s) 819043Seric register char *s; 829043Seric { 839043Seric register int l = 0; 849043Seric register char c; 859043Seric 869043Seric while ((c = *s++) != '\0') 879043Seric { 889043Seric if (bitset(0200, c)) 899043Seric l++; 909043Seric l++; 919043Seric } 929043Seric return (l); 939043Seric } 949043Seric /* 952900Seric ** CAPITALIZE -- return a copy of a string, properly capitalized. 962900Seric ** 972900Seric ** Parameters: 982900Seric ** s -- the string to capitalize. 992900Seric ** 1002900Seric ** Returns: 1012900Seric ** a pointer to a properly capitalized string. 1022900Seric ** 1032900Seric ** Side Effects: 1042900Seric ** none. 1052900Seric */ 1062900Seric 1072900Seric char * 1082900Seric capitalize(s) 1092900Seric register char *s; 1102900Seric { 1112900Seric static char buf[50]; 1122900Seric register char *p; 1132900Seric 1142900Seric p = buf; 1152900Seric 1162900Seric for (;;) 1172900Seric { 1182900Seric while (!isalpha(*s) && *s != '\0') 1192900Seric *p++ = *s++; 1202900Seric if (*s == '\0') 1212900Seric break; 1222900Seric *p++ = toupper(*s++); 1232900Seric while (isalpha(*s)) 1242900Seric *p++ = *s++; 1252900Seric } 1262900Seric 1272900Seric *p = '\0'; 1282900Seric return (buf); 1292900Seric } 1302900Seric /* 131298Seric ** XALLOC -- Allocate memory and bitch wildly on failure. 132298Seric ** 133298Seric ** THIS IS A CLUDGE. This should be made to give a proper 134298Seric ** error -- but after all, what can we do? 135298Seric ** 136298Seric ** Parameters: 137298Seric ** sz -- size of area to allocate. 138298Seric ** 139298Seric ** Returns: 140298Seric ** pointer to data region. 141298Seric ** 142298Seric ** Side Effects: 143298Seric ** Memory is allocated. 144298Seric */ 145298Seric 146298Seric char * 147298Seric xalloc(sz) 1487007Seric register int sz; 149298Seric { 150298Seric register char *p; 15123121Seric extern char *malloc(); 152298Seric 15323121Seric p = malloc((unsigned) sz); 154298Seric if (p == NULL) 155298Seric { 156298Seric syserr("Out of memory!!"); 15710685Seric abort(); 15810685Seric /* exit(EX_UNAVAILABLE); */ 159298Seric } 160298Seric return (p); 161298Seric } 162298Seric /* 1633151Seric ** COPYPLIST -- copy list of pointers. 1643151Seric ** 1653151Seric ** This routine is the equivalent of newstr for lists of 1663151Seric ** pointers. 1673151Seric ** 1683151Seric ** Parameters: 1693151Seric ** list -- list of pointers to copy. 1703151Seric ** Must be NULL terminated. 1713151Seric ** copycont -- if TRUE, copy the contents of the vector 1723151Seric ** (which must be a string) also. 1733151Seric ** 1743151Seric ** Returns: 1753151Seric ** a copy of 'list'. 1763151Seric ** 1773151Seric ** Side Effects: 1783151Seric ** none. 1793151Seric */ 1803151Seric 1813151Seric char ** 1823151Seric copyplist(list, copycont) 1833151Seric char **list; 1843151Seric bool copycont; 1853151Seric { 1863151Seric register char **vp; 1873151Seric register char **newvp; 1883151Seric 1893151Seric for (vp = list; *vp != NULL; vp++) 1903151Seric continue; 1913151Seric 1923151Seric vp++; 1933151Seric 19416897Seric newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); 19516897Seric bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); 1963151Seric 1973151Seric if (copycont) 1983151Seric { 1993151Seric for (vp = newvp; *vp != NULL; vp++) 2003151Seric *vp = newstr(*vp); 2013151Seric } 2023151Seric 2033151Seric return (newvp); 2043151Seric } 2053151Seric /* 2063151Seric ** PRINTAV -- print argument vector. 2073151Seric ** 2083151Seric ** Parameters: 2093151Seric ** av -- argument vector. 2103151Seric ** 2113151Seric ** Returns: 2123151Seric ** none. 2133151Seric ** 2143151Seric ** Side Effects: 2153151Seric ** prints av. 2163151Seric */ 2173151Seric 2183151Seric printav(av) 2193151Seric register char **av; 2203151Seric { 2213151Seric while (*av != NULL) 2223151Seric { 2238063Seric if (tTd(0, 44)) 2248063Seric printf("\n\t%08x=", *av); 2258063Seric else 22623105Seric (void) putchar(' '); 2273151Seric xputs(*av++); 2283151Seric } 22923105Seric (void) putchar('\n'); 2303151Seric } 2313151Seric /* 2323151Seric ** LOWER -- turn letter into lower case. 2333151Seric ** 2343151Seric ** Parameters: 2353151Seric ** c -- character to turn into lower case. 2363151Seric ** 2373151Seric ** Returns: 2383151Seric ** c, in lower case. 2393151Seric ** 2403151Seric ** Side Effects: 2413151Seric ** none. 2423151Seric */ 2433151Seric 2443151Seric char 2453151Seric lower(c) 2463151Seric register char c; 2473151Seric { 24833724Sbostic return(isascii(c) && isupper(c) ? tolower(c) : c); 2493151Seric } 2503151Seric /* 2513151Seric ** XPUTS -- put string doing control escapes. 2523151Seric ** 2533151Seric ** Parameters: 2543151Seric ** s -- string to put. 2553151Seric ** 2563151Seric ** Returns: 2573151Seric ** none. 2583151Seric ** 2593151Seric ** Side Effects: 2603151Seric ** output to stdout 2613151Seric */ 2623151Seric 2633151Seric xputs(s) 2643151Seric register char *s; 2653151Seric { 2663151Seric register char c; 2673151Seric 2688055Seric if (s == NULL) 2698055Seric { 2708055Seric printf("<null>"); 2718055Seric return; 2728055Seric } 27323105Seric (void) putchar('"'); 2743151Seric while ((c = *s++) != '\0') 2753151Seric { 2763151Seric if (!isascii(c)) 2773151Seric { 27823105Seric (void) putchar('\\'); 2793151Seric c &= 0177; 2803151Seric } 28110326Seric if (c < 040 || c >= 0177) 2823151Seric { 28323105Seric (void) putchar('^'); 28410326Seric c ^= 0100; 2853151Seric } 28623105Seric (void) putchar(c); 2873151Seric } 28823105Seric (void) putchar('"'); 2894086Seric (void) fflush(stdout); 2903151Seric } 2913151Seric /* 2923151Seric ** MAKELOWER -- Translate a line into lower case 2933151Seric ** 2943151Seric ** Parameters: 2953151Seric ** p -- the string to translate. If NULL, return is 2963151Seric ** immediate. 2973151Seric ** 2983151Seric ** Returns: 2993151Seric ** none. 3003151Seric ** 3013151Seric ** Side Effects: 3023151Seric ** String pointed to by p is translated to lower case. 3033151Seric ** 3043151Seric ** Called By: 3053151Seric ** parse 3063151Seric */ 3073151Seric 3083151Seric makelower(p) 3093151Seric register char *p; 3103151Seric { 3113151Seric register char c; 3123151Seric 3133151Seric if (p == NULL) 3143151Seric return; 3153151Seric for (; (c = *p) != '\0'; p++) 3163151Seric if (isascii(c) && isupper(c)) 31733724Sbostic *p = tolower(c); 3183151Seric } 3194059Seric /* 3205196Seric ** BUILDFNAME -- build full name from gecos style entry. 3214375Seric ** 3225196Seric ** This routine interprets the strange entry that would appear 3235196Seric ** in the GECOS field of the password file. 3245196Seric ** 3254375Seric ** Parameters: 3265196Seric ** p -- name to build. 3275196Seric ** login -- the login name of this user (for &). 3285196Seric ** buf -- place to put the result. 3294375Seric ** 3304375Seric ** Returns: 3314375Seric ** none. 3324375Seric ** 3334375Seric ** Side Effects: 3344375Seric ** none. 3354375Seric */ 3364375Seric 3375196Seric buildfname(p, login, buf) 3385196Seric register char *p; 3395196Seric char *login; 3404375Seric char *buf; 3414375Seric { 3424375Seric register char *bp = buf; 3434375Seric 3444438Seric if (*p == '*') 3454438Seric p++; 3466278Seric while (*p != '\0' && *p != ',' && *p != ';' && *p != '%') 3474375Seric { 3484375Seric if (*p == '&') 3494375Seric { 3505196Seric (void) strcpy(bp, login); 3514375Seric *bp = toupper(*bp); 3524375Seric while (*bp != '\0') 3534375Seric bp++; 3544375Seric p++; 3554375Seric } 3564375Seric else 3574375Seric *bp++ = *p++; 3584375Seric } 3594375Seric *bp = '\0'; 3604375Seric } 3614375Seric /* 3624538Seric ** SAFEFILE -- return true if a file exists and is safe for a user. 3634538Seric ** 3644538Seric ** Parameters: 3654538Seric ** fn -- filename to check. 3664538Seric ** uid -- uid to compare against. 3674538Seric ** mode -- mode bits that must match. 3684538Seric ** 3694538Seric ** Returns: 3704538Seric ** TRUE if fn exists, is owned by uid, and matches mode. 3714538Seric ** FALSE otherwise. 3724538Seric ** 3734538Seric ** Side Effects: 3744538Seric ** none. 3754538Seric */ 3764538Seric 3774538Seric bool 3784538Seric safefile(fn, uid, mode) 3794538Seric char *fn; 3804538Seric int uid; 3814538Seric int mode; 3824538Seric { 3834538Seric struct stat stbuf; 3844538Seric 3854538Seric if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && 3864538Seric (stbuf.st_mode & mode) == mode) 3874538Seric return (TRUE); 38811936Seric errno = 0; 3894538Seric return (FALSE); 3904538Seric } 3914538Seric /* 3924557Seric ** FIXCRLF -- fix <CR><LF> in line. 3934557Seric ** 3944557Seric ** Looks for the <CR><LF> combination and turns it into the 3954557Seric ** UNIX canonical <NL> character. It only takes one line, 3964557Seric ** i.e., it is assumed that the first <NL> found is the end 3974557Seric ** of the line. 3984557Seric ** 3994557Seric ** Parameters: 4004557Seric ** line -- the line to fix. 4014557Seric ** stripnl -- if true, strip the newline also. 4024557Seric ** 4034557Seric ** Returns: 4044557Seric ** none. 4054557Seric ** 4064557Seric ** Side Effects: 4074557Seric ** line is changed in place. 4084557Seric */ 4094557Seric 4104557Seric fixcrlf(line, stripnl) 4114557Seric char *line; 4124557Seric bool stripnl; 4134557Seric { 4144557Seric register char *p; 4154557Seric 4164557Seric p = index(line, '\n'); 4174557Seric if (p == NULL) 4184557Seric return; 419*36291Sbostic if (p > line && p[-1] == '\r') 4204557Seric p--; 4214557Seric if (!stripnl) 4224557Seric *p++ = '\n'; 4234557Seric *p = '\0'; 4244557Seric } 4254557Seric /* 4266890Seric ** DFOPEN -- determined file open 4276890Seric ** 4286890Seric ** This routine has the semantics of fopen, except that it will 4296890Seric ** keep trying a few times to make this happen. The idea is that 4306890Seric ** on very loaded systems, we may run out of resources (inodes, 4316890Seric ** whatever), so this tries to get around it. 4326890Seric */ 4336890Seric 4346890Seric FILE * 4356890Seric dfopen(filename, mode) 4366890Seric char *filename; 4376890Seric char *mode; 4386890Seric { 4396890Seric register int tries; 4406890Seric register FILE *fp; 4416890Seric 4426890Seric for (tries = 0; tries < 10; tries++) 4436890Seric { 44425618Seric sleep((unsigned) (10 * tries)); 4456890Seric errno = 0; 4466890Seric fp = fopen(filename, mode); 4479376Seric if (fp != NULL) 4486890Seric break; 4499376Seric if (errno != ENFILE && errno != EINTR) 4509376Seric break; 4516890Seric } 45211936Seric errno = 0; 4536890Seric return (fp); 4546890Seric } 4557124Seric /* 4567124Seric ** PUTLINE -- put a line like fputs obeying SMTP conventions 4577124Seric ** 4587753Seric ** This routine always guarantees outputing a newline (or CRLF, 4597753Seric ** as appropriate) at the end of the string. 4607753Seric ** 4617124Seric ** Parameters: 4627124Seric ** l -- line to put. 4637124Seric ** fp -- file to put it onto. 46410172Seric ** m -- the mailer used to control output. 4657124Seric ** 4667124Seric ** Returns: 4677124Seric ** none 4687124Seric ** 4697124Seric ** Side Effects: 4707124Seric ** output of l to fp. 4717124Seric */ 4727124Seric 4737753Seric # define SMTPLINELIM 990 /* maximum line length */ 4747124Seric 47510172Seric putline(l, fp, m) 4767753Seric register char *l; 4777124Seric FILE *fp; 47810172Seric MAILER *m; 4797124Seric { 4807124Seric register char *p; 4817753Seric char svchar; 4827124Seric 48311275Seric /* strip out 0200 bits -- these can look like TELNET protocol */ 48411275Seric if (bitnset(M_LIMITS, m->m_flags)) 48511275Seric { 48611275Seric p = l; 48711275Seric while ((*p++ &= ~0200) != 0) 48811275Seric continue; 48911275Seric } 49011275Seric 4917753Seric do 4927124Seric { 4937753Seric /* find the end of the line */ 4947753Seric p = index(l, '\n'); 4957753Seric if (p == NULL) 4967753Seric p = &l[strlen(l)]; 4977124Seric 4987753Seric /* check for line overflow */ 49911275Seric while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags)) 5007753Seric { 5017753Seric register char *q = &l[SMTPLINELIM - 1]; 5027124Seric 5037753Seric svchar = *q; 5047753Seric *q = '\0'; 50510685Seric if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 50623105Seric (void) putc('.', fp); 5077753Seric fputs(l, fp); 50823105Seric (void) putc('!', fp); 50910326Seric fputs(m->m_eol, fp); 5107753Seric *q = svchar; 5117753Seric l = q; 5127753Seric } 5137124Seric 5147753Seric /* output last part */ 5157753Seric svchar = *p; 5167753Seric *p = '\0'; 51710685Seric if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 51823105Seric (void) putc('.', fp); 5197124Seric fputs(l, fp); 52010326Seric fputs(m->m_eol, fp); 5217753Seric *p = svchar; 5227753Seric l = p; 5237753Seric if (*l == '\n') 5247753Seric l++; 5257753Seric } while (l[0] != '\0'); 5267124Seric } 5277676Seric /* 5287676Seric ** XUNLINK -- unlink a file, doing logging as appropriate. 5297676Seric ** 5307676Seric ** Parameters: 5317676Seric ** f -- name of file to unlink. 5327676Seric ** 5337676Seric ** Returns: 5347676Seric ** none. 5357676Seric ** 5367676Seric ** Side Effects: 5377676Seric ** f is unlinked. 5387676Seric */ 5397676Seric 5407676Seric xunlink(f) 5417676Seric char *f; 5427676Seric { 5437676Seric register int i; 5447676Seric 5457676Seric # ifdef LOG 5467676Seric if (LogLevel > 20) 5477812Seric syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f); 5487676Seric # endif LOG 5497676Seric 5507676Seric i = unlink(f); 5517676Seric # ifdef LOG 5527676Seric if (i < 0 && LogLevel > 21) 5537942Seric syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 5547676Seric # endif LOG 5557676Seric } 5567685Seric /* 55714885Seric ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 5587685Seric ** 5597685Seric ** Parameters: 5607685Seric ** buf -- place to put the input line. 5617685Seric ** siz -- size of buf. 5627685Seric ** fp -- file to read from. 5637685Seric ** 5647685Seric ** Returns: 56515533Seric ** NULL on error (including timeout). This will also leave 56615533Seric ** buf containing a null string. 5677685Seric ** buf otherwise. 5687685Seric ** 5697685Seric ** Side Effects: 5707685Seric ** none. 5717685Seric */ 5727685Seric 57314885Seric static jmp_buf CtxReadTimeout; 5747685Seric 5757685Seric char * 5767685Seric sfgets(buf, siz, fp) 5777685Seric char *buf; 5787685Seric int siz; 5797685Seric FILE *fp; 5807685Seric { 5817942Seric register EVENT *ev = NULL; 5827685Seric register char *p; 5837685Seric extern readtimeout(); 5847685Seric 58514885Seric /* set the timeout */ 5867942Seric if (ReadTimeout != 0) 58714885Seric { 58814885Seric if (setjmp(CtxReadTimeout) != 0) 58914885Seric { 59036233Skarels # ifdef LOG 59136230Skarels syslog(LOG_NOTICE, 59236230Skarels "timeout waiting for input from %s\n", 59336230Skarels RealHostName); 59436233Skarels # endif 59536230Skarels errno = 0; 59636230Skarels usrerr("timeout waiting for input"); 59719037Seric buf[0] = '\0'; 59814885Seric return (NULL); 59914885Seric } 60016138Seric ev = setevent((time_t) ReadTimeout, readtimeout, 0); 60114885Seric } 60214885Seric 60314885Seric /* try to read */ 60415533Seric p = NULL; 60515533Seric while (p == NULL && !feof(fp) && !ferror(fp)) 6067942Seric { 6077942Seric errno = 0; 6087942Seric p = fgets(buf, siz, fp); 60915533Seric if (errno == EINTR) 61015533Seric clearerr(fp); 61115533Seric } 61214885Seric 61314885Seric /* clear the event if it has not sprung */ 6147685Seric clrevent(ev); 61514885Seric 61614885Seric /* clean up the books and exit */ 6178055Seric LineNumber++; 61815533Seric if (p == NULL) 61916880Seric { 62015533Seric buf[0] = '\0'; 62116880Seric return (NULL); 62216880Seric } 62316880Seric for (p = buf; *p != '\0'; p++) 62416880Seric *p &= ~0200; 62516880Seric return (buf); 6267685Seric } 6277685Seric 6287685Seric static 6297685Seric readtimeout() 6307685Seric { 63114885Seric longjmp(CtxReadTimeout, 1); 6327685Seric } 6337786Seric /* 6347786Seric ** FGETFOLDED -- like fgets, but know about folded lines. 6357786Seric ** 6367786Seric ** Parameters: 6377786Seric ** buf -- place to put result. 6387786Seric ** n -- bytes available. 6397786Seric ** f -- file to read from. 6407786Seric ** 6417786Seric ** Returns: 6427786Seric ** buf on success, NULL on error or EOF. 6437786Seric ** 6447786Seric ** Side Effects: 6457786Seric ** buf gets lines from f, with continuation lines (lines 6467786Seric ** with leading white space) appended. CRLF's are mapped 6477786Seric ** into single newlines. Any trailing NL is stripped. 6487786Seric */ 6497786Seric 6507786Seric char * 6517786Seric fgetfolded(buf, n, f) 6527786Seric char *buf; 6537786Seric register int n; 6547786Seric FILE *f; 6557786Seric { 6567786Seric register char *p = buf; 6577786Seric register int i; 6587786Seric 6597786Seric n--; 66017350Seric while ((i = getc(f)) != EOF) 6617786Seric { 66217350Seric if (i == '\r') 66317350Seric { 66417350Seric i = getc(f); 66517350Seric if (i != '\n') 66617350Seric { 66717350Seric if (i != EOF) 66823105Seric (void) ungetc(i, f); 66917350Seric i = '\r'; 67017350Seric } 67117350Seric } 67217350Seric if (--n > 0) 67317350Seric *p++ = i; 67417350Seric if (i == '\n') 67517350Seric { 67617350Seric LineNumber++; 67717350Seric i = getc(f); 67817350Seric if (i != EOF) 67923105Seric (void) ungetc(i, f); 68017350Seric if (i != ' ' && i != '\t') 68117350Seric { 68217350Seric *--p = '\0'; 68317350Seric return (buf); 68417350Seric } 68517350Seric } 6867786Seric } 6877786Seric return (NULL); 6887786Seric } 6897860Seric /* 6907886Seric ** CURTIME -- return current time. 6917886Seric ** 6927886Seric ** Parameters: 6937886Seric ** none. 6947886Seric ** 6957886Seric ** Returns: 6967886Seric ** the current time. 6977886Seric ** 6987886Seric ** Side Effects: 6997886Seric ** none. 7007886Seric */ 7017886Seric 7027886Seric time_t 7037886Seric curtime() 7047886Seric { 7057886Seric auto time_t t; 7067886Seric 7077886Seric (void) time(&t); 7087886Seric return (t); 7097886Seric } 7108264Seric /* 7118264Seric ** ATOBOOL -- convert a string representation to boolean. 7128264Seric ** 7138264Seric ** Defaults to "TRUE" 7148264Seric ** 7158264Seric ** Parameters: 7168264Seric ** s -- string to convert. Takes "tTyY" as true, 7178264Seric ** others as false. 7188264Seric ** 7198264Seric ** Returns: 7208264Seric ** A boolean representation of the string. 7218264Seric ** 7228264Seric ** Side Effects: 7238264Seric ** none. 7248264Seric */ 7258264Seric 7268264Seric bool 7278264Seric atobool(s) 7288264Seric register char *s; 7298264Seric { 7308264Seric if (*s == '\0' || index("tTyY", *s) != NULL) 7318264Seric return (TRUE); 7328264Seric return (FALSE); 7338264Seric } 7349048Seric /* 7359048Seric ** ATOOCT -- convert a string representation to octal. 7369048Seric ** 7379048Seric ** Parameters: 7389048Seric ** s -- string to convert. 7399048Seric ** 7409048Seric ** Returns: 7419048Seric ** An integer representing the string interpreted as an 7429048Seric ** octal number. 7439048Seric ** 7449048Seric ** Side Effects: 7459048Seric ** none. 7469048Seric */ 7479048Seric 7489048Seric atooct(s) 7499048Seric register char *s; 7509048Seric { 7519048Seric register int i = 0; 7529048Seric 7539048Seric while (*s >= '0' && *s <= '7') 7549048Seric i = (i << 3) | (*s++ - '0'); 7559048Seric return (i); 7569048Seric } 7579376Seric /* 7589376Seric ** WAITFOR -- wait for a particular process id. 7599376Seric ** 7609376Seric ** Parameters: 7619376Seric ** pid -- process id to wait for. 7629376Seric ** 7639376Seric ** Returns: 7649376Seric ** status of pid. 7659376Seric ** -1 if pid never shows up. 7669376Seric ** 7679376Seric ** Side Effects: 7689376Seric ** none. 7699376Seric */ 7709376Seric 7719376Seric waitfor(pid) 7729376Seric int pid; 7739376Seric { 7749376Seric auto int st; 7759376Seric int i; 7769376Seric 7779376Seric do 7789376Seric { 7799376Seric errno = 0; 7809376Seric i = wait(&st); 7819376Seric } while ((i >= 0 || errno == EINTR) && i != pid); 7829376Seric if (i < 0) 7839376Seric st = -1; 7849376Seric return (st); 7859376Seric } 7869376Seric /* 78710685Seric ** BITINTERSECT -- tell if two bitmaps intersect 78810685Seric ** 78910685Seric ** Parameters: 79010685Seric ** a, b -- the bitmaps in question 79110685Seric ** 79210685Seric ** Returns: 79310685Seric ** TRUE if they have a non-null intersection 79410685Seric ** FALSE otherwise 79510685Seric ** 79610685Seric ** Side Effects: 79710685Seric ** none. 79810685Seric */ 79910685Seric 80010685Seric bool 80110685Seric bitintersect(a, b) 80210685Seric BITMAP a; 80310685Seric BITMAP b; 80410685Seric { 80510685Seric int i; 80610685Seric 80710685Seric for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 80810685Seric if ((a[i] & b[i]) != 0) 80910685Seric return (TRUE); 81010685Seric return (FALSE); 81110685Seric } 81210685Seric /* 81310685Seric ** BITZEROP -- tell if a bitmap is all zero 81410685Seric ** 81510685Seric ** Parameters: 81610685Seric ** map -- the bit map to check 81710685Seric ** 81810685Seric ** Returns: 81910685Seric ** TRUE if map is all zero. 82010685Seric ** FALSE if there are any bits set in map. 82110685Seric ** 82210685Seric ** Side Effects: 82310685Seric ** none. 82410685Seric */ 82510685Seric 82610685Seric bool 82710685Seric bitzerop(map) 82810685Seric BITMAP map; 82910685Seric { 83010685Seric int i; 83110685Seric 83210685Seric for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 83310685Seric if (map[i] != 0) 83410685Seric return (FALSE); 83510685Seric return (TRUE); 83610685Seric } 837