13151Seric # include <stdio.h> 24538Seric # include <sys/types.h> 34538Seric # include <sys/stat.h> 4298Seric # include <sysexits.h> 56890Seric # include <errno.h> 62900Seric # include <ctype.h> 76890Seric # include "sendmail.h" 8298Seric 9*10326Seric SCCSID(@(#)util.c 3.41 01/16/83); 10409Seric 11298Seric /* 12298Seric ** STRIPQUOTES -- Strip quotes & quote bits from a string. 13298Seric ** 14298Seric ** Runs through a string and strips off unquoted quote 15298Seric ** characters and quote bits. This is done in place. 16298Seric ** 17298Seric ** Parameters: 18298Seric ** s -- the string to strip. 194101Seric ** qf -- if set, remove actual `` " '' characters 204101Seric ** as well as the quote bits. 21298Seric ** 22298Seric ** Returns: 23298Seric ** none. 24298Seric ** 25298Seric ** Side Effects: 26298Seric ** none. 27298Seric ** 28298Seric ** Called By: 29298Seric ** deliver 30298Seric */ 31298Seric 324101Seric stripquotes(s, qf) 33298Seric char *s; 344101Seric bool qf; 35298Seric { 36298Seric register char *p; 37298Seric register char *q; 38298Seric register char c; 39298Seric 404101Seric if (s == NULL) 414101Seric return; 424101Seric 43298Seric for (p = q = s; (c = *p++) != '\0'; ) 44298Seric { 454101Seric if (c != '"' || !qf) 46298Seric *q++ = c & 0177; 47298Seric } 48298Seric *q = '\0'; 49298Seric } 50298Seric /* 519043Seric ** QSTRLEN -- give me the string length assuming 0200 bits add a char 529043Seric ** 539043Seric ** Parameters: 549043Seric ** s -- the string to measure. 559043Seric ** 569043Seric ** Reurns: 579043Seric ** The length of s, including space for backslash escapes. 589043Seric ** 599043Seric ** Side Effects: 609043Seric ** none. 619043Seric */ 629043Seric 639043Seric qstrlen(s) 649043Seric register char *s; 659043Seric { 669043Seric register int l = 0; 679043Seric register char c; 689043Seric 699043Seric while ((c = *s++) != '\0') 709043Seric { 719043Seric if (bitset(0200, c)) 729043Seric l++; 739043Seric l++; 749043Seric } 759043Seric return (l); 769043Seric } 779043Seric /* 782900Seric ** CAPITALIZE -- return a copy of a string, properly capitalized. 792900Seric ** 802900Seric ** Parameters: 812900Seric ** s -- the string to capitalize. 822900Seric ** 832900Seric ** Returns: 842900Seric ** a pointer to a properly capitalized string. 852900Seric ** 862900Seric ** Side Effects: 872900Seric ** none. 882900Seric */ 892900Seric 902900Seric char * 912900Seric capitalize(s) 922900Seric register char *s; 932900Seric { 942900Seric static char buf[50]; 952900Seric register char *p; 962900Seric 972900Seric p = buf; 982900Seric 992900Seric for (;;) 1002900Seric { 1012900Seric while (!isalpha(*s) && *s != '\0') 1022900Seric *p++ = *s++; 1032900Seric if (*s == '\0') 1042900Seric break; 1052900Seric *p++ = toupper(*s++); 1062900Seric while (isalpha(*s)) 1072900Seric *p++ = *s++; 1082900Seric } 1092900Seric 1102900Seric *p = '\0'; 1112900Seric return (buf); 1122900Seric } 1132900Seric /* 114298Seric ** XALLOC -- Allocate memory and bitch wildly on failure. 115298Seric ** 116298Seric ** THIS IS A CLUDGE. This should be made to give a proper 117298Seric ** error -- but after all, what can we do? 118298Seric ** 119298Seric ** Parameters: 120298Seric ** sz -- size of area to allocate. 121298Seric ** 122298Seric ** Returns: 123298Seric ** pointer to data region. 124298Seric ** 125298Seric ** Side Effects: 126298Seric ** Memory is allocated. 127298Seric */ 128298Seric 129298Seric char * 130298Seric xalloc(sz) 1317007Seric register int sz; 132298Seric { 133298Seric register char *p; 134298Seric 135298Seric p = malloc(sz); 136298Seric if (p == NULL) 137298Seric { 138298Seric syserr("Out of memory!!"); 1391598Seric exit(EX_UNAVAILABLE); 140298Seric } 141298Seric return (p); 142298Seric } 143298Seric /* 1443151Seric ** COPYPLIST -- copy list of pointers. 1453151Seric ** 1463151Seric ** This routine is the equivalent of newstr for lists of 1473151Seric ** pointers. 1483151Seric ** 1493151Seric ** Parameters: 1503151Seric ** list -- list of pointers to copy. 1513151Seric ** Must be NULL terminated. 1523151Seric ** copycont -- if TRUE, copy the contents of the vector 1533151Seric ** (which must be a string) also. 1543151Seric ** 1553151Seric ** Returns: 1563151Seric ** a copy of 'list'. 1573151Seric ** 1583151Seric ** Side Effects: 1593151Seric ** none. 1603151Seric */ 1613151Seric 1623151Seric char ** 1633151Seric copyplist(list, copycont) 1643151Seric char **list; 1653151Seric bool copycont; 1663151Seric { 1673151Seric register char **vp; 1683151Seric register char **newvp; 1693151Seric 1703151Seric for (vp = list; *vp != NULL; vp++) 1713151Seric continue; 1723151Seric 1733151Seric vp++; 1743151Seric 1757007Seric newvp = (char **) xalloc((vp - list) * sizeof *vp); 1764086Seric bmove((char *) list, (char *) newvp, (vp - list) * sizeof *vp); 1773151Seric 1783151Seric if (copycont) 1793151Seric { 1803151Seric for (vp = newvp; *vp != NULL; vp++) 1813151Seric *vp = newstr(*vp); 1823151Seric } 1833151Seric 1843151Seric return (newvp); 1853151Seric } 1863151Seric /* 1873151Seric ** PRINTAV -- print argument vector. 1883151Seric ** 1893151Seric ** Parameters: 1903151Seric ** av -- argument vector. 1913151Seric ** 1923151Seric ** Returns: 1933151Seric ** none. 1943151Seric ** 1953151Seric ** Side Effects: 1963151Seric ** prints av. 1973151Seric */ 1983151Seric 1993151Seric # ifdef DEBUG 2003151Seric printav(av) 2013151Seric register char **av; 2023151Seric { 2033151Seric while (*av != NULL) 2043151Seric { 2058063Seric if (tTd(0, 44)) 2068063Seric printf("\n\t%08x=", *av); 2078063Seric else 2088063Seric putchar(' '); 2093151Seric xputs(*av++); 2103151Seric } 2118063Seric putchar('\n'); 2123151Seric } 2133151Seric # endif DEBUG 2143151Seric /* 2153151Seric ** LOWER -- turn letter into lower case. 2163151Seric ** 2173151Seric ** Parameters: 2183151Seric ** c -- character to turn into lower case. 2193151Seric ** 2203151Seric ** Returns: 2213151Seric ** c, in lower case. 2223151Seric ** 2233151Seric ** Side Effects: 2243151Seric ** none. 2253151Seric */ 2263151Seric 2273151Seric char 2283151Seric lower(c) 2293151Seric register char c; 2303151Seric { 2313151Seric if (isascii(c) && isupper(c)) 2323151Seric c = c - 'A' + 'a'; 2333151Seric return (c); 2343151Seric } 2353151Seric /* 2363151Seric ** XPUTS -- put string doing control escapes. 2373151Seric ** 2383151Seric ** Parameters: 2393151Seric ** s -- string to put. 2403151Seric ** 2413151Seric ** Returns: 2423151Seric ** none. 2433151Seric ** 2443151Seric ** Side Effects: 2453151Seric ** output to stdout 2463151Seric */ 2473151Seric 2483151Seric # ifdef DEBUG 2493151Seric xputs(s) 2503151Seric register char *s; 2513151Seric { 2523151Seric register char c; 2533151Seric 2548055Seric if (s == NULL) 2558055Seric { 2568055Seric printf("<null>"); 2578055Seric return; 2588055Seric } 2598063Seric putchar('"'); 2603151Seric while ((c = *s++) != '\0') 2613151Seric { 2623151Seric if (!isascii(c)) 2633151Seric { 2643151Seric putchar('\\'); 2653151Seric c &= 0177; 2663151Seric } 267*10326Seric if (c < 040 || c >= 0177) 2683151Seric { 2693151Seric putchar('^'); 270*10326Seric c ^= 0100; 2713151Seric } 2723151Seric putchar(c); 2733151Seric } 2748063Seric putchar('"'); 2754086Seric (void) fflush(stdout); 2763151Seric } 2773151Seric # endif DEBUG 2783151Seric /* 2793151Seric ** MAKELOWER -- Translate a line into lower case 2803151Seric ** 2813151Seric ** Parameters: 2823151Seric ** p -- the string to translate. If NULL, return is 2833151Seric ** immediate. 2843151Seric ** 2853151Seric ** Returns: 2863151Seric ** none. 2873151Seric ** 2883151Seric ** Side Effects: 2893151Seric ** String pointed to by p is translated to lower case. 2903151Seric ** 2913151Seric ** Called By: 2923151Seric ** parse 2933151Seric */ 2943151Seric 2953151Seric makelower(p) 2963151Seric register char *p; 2973151Seric { 2983151Seric register char c; 2993151Seric 3003151Seric if (p == NULL) 3013151Seric return; 3023151Seric for (; (c = *p) != '\0'; p++) 3033151Seric if (isascii(c) && isupper(c)) 3043151Seric *p = c - 'A' + 'a'; 3053151Seric } 3064059Seric /* 3074059Seric ** SAMEWORD -- return TRUE if the words are the same 3084059Seric ** 3094059Seric ** Ignores case. 3104059Seric ** 3114059Seric ** Parameters: 3124059Seric ** a, b -- the words to compare. 3134059Seric ** 3144059Seric ** Returns: 3154059Seric ** TRUE if a & b match exactly (modulo case) 3164059Seric ** FALSE otherwise. 3174059Seric ** 3184059Seric ** Side Effects: 3194059Seric ** none. 3204059Seric */ 3214059Seric 3224059Seric bool 3234059Seric sameword(a, b) 3244059Seric register char *a, *b; 3254059Seric { 3264059Seric while (lower(*a) == lower(*b)) 3274059Seric { 3284059Seric if (*a == '\0') 3294059Seric return (TRUE); 3304059Seric a++; 3314059Seric b++; 3324059Seric } 3334059Seric return (FALSE); 3344059Seric } 3354086Seric /* 3364101Seric ** CLEAR -- clear a block of memory 3374101Seric ** 3384101Seric ** Parameters: 3394101Seric ** p -- location to clear. 3404101Seric ** l -- number of bytes to clear. 3414101Seric ** 3424101Seric ** Returns: 3434101Seric ** none. 3444101Seric ** 3454101Seric ** Side Effects: 3464101Seric ** none. 3474101Seric */ 3484101Seric 3494101Seric clear(p, l) 3504101Seric register char *p; 3514101Seric register int l; 3524101Seric { 3534101Seric while (l-- > 0) 3544101Seric *p++ = 0; 3554101Seric } 3564101Seric /* 3575196Seric ** BUILDFNAME -- build full name from gecos style entry. 3584375Seric ** 3595196Seric ** This routine interprets the strange entry that would appear 3605196Seric ** in the GECOS field of the password file. 3615196Seric ** 3624375Seric ** Parameters: 3635196Seric ** p -- name to build. 3645196Seric ** login -- the login name of this user (for &). 3655196Seric ** buf -- place to put the result. 3664375Seric ** 3674375Seric ** Returns: 3684375Seric ** none. 3694375Seric ** 3704375Seric ** Side Effects: 3714375Seric ** none. 3724375Seric */ 3734375Seric 3745196Seric buildfname(p, login, buf) 3755196Seric register char *p; 3765196Seric char *login; 3774375Seric char *buf; 3784375Seric { 3794375Seric register char *bp = buf; 3804375Seric 3814438Seric if (*p == '*') 3824438Seric p++; 3836278Seric while (*p != '\0' && *p != ',' && *p != ';' && *p != '%') 3844375Seric { 3854375Seric if (*p == '&') 3864375Seric { 3875196Seric (void) strcpy(bp, login); 3884375Seric *bp = toupper(*bp); 3894375Seric while (*bp != '\0') 3904375Seric bp++; 3914375Seric p++; 3924375Seric } 3934375Seric else 3944375Seric *bp++ = *p++; 3954375Seric } 3964375Seric *bp = '\0'; 3974375Seric } 3984375Seric /* 3994538Seric ** SAFEFILE -- return true if a file exists and is safe for a user. 4004538Seric ** 4014538Seric ** Parameters: 4024538Seric ** fn -- filename to check. 4034538Seric ** uid -- uid to compare against. 4044538Seric ** mode -- mode bits that must match. 4054538Seric ** 4064538Seric ** Returns: 4074538Seric ** TRUE if fn exists, is owned by uid, and matches mode. 4084538Seric ** FALSE otherwise. 4094538Seric ** 4104538Seric ** Side Effects: 4114538Seric ** none. 4124538Seric */ 4134538Seric 4144538Seric bool 4154538Seric safefile(fn, uid, mode) 4164538Seric char *fn; 4174538Seric int uid; 4184538Seric int mode; 4194538Seric { 4204538Seric struct stat stbuf; 4214538Seric 4224538Seric if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && 4234538Seric (stbuf.st_mode & mode) == mode) 4244538Seric return (TRUE); 4254538Seric return (FALSE); 4264538Seric } 4274538Seric /* 4284557Seric ** FIXCRLF -- fix <CR><LF> in line. 4294557Seric ** 4304557Seric ** Looks for the <CR><LF> combination and turns it into the 4314557Seric ** UNIX canonical <NL> character. It only takes one line, 4324557Seric ** i.e., it is assumed that the first <NL> found is the end 4334557Seric ** of the line. 4344557Seric ** 4354557Seric ** Parameters: 4364557Seric ** line -- the line to fix. 4374557Seric ** stripnl -- if true, strip the newline also. 4384557Seric ** 4394557Seric ** Returns: 4404557Seric ** none. 4414557Seric ** 4424557Seric ** Side Effects: 4434557Seric ** line is changed in place. 4444557Seric */ 4454557Seric 4464557Seric fixcrlf(line, stripnl) 4474557Seric char *line; 4484557Seric bool stripnl; 4494557Seric { 4504557Seric register char *p; 4514557Seric 4524557Seric p = index(line, '\n'); 4534557Seric if (p == NULL) 4544557Seric return; 4554794Seric if (p[-1] == '\r') 4564557Seric p--; 4574557Seric if (!stripnl) 4584557Seric *p++ = '\n'; 4594557Seric *p = '\0'; 4604557Seric } 4614557Seric /* 4624086Seric ** SYSLOG -- fake entry to fool lint 4634086Seric */ 4644086Seric 4654086Seric # ifdef LOG 4664086Seric # ifdef lint 4674086Seric 4684086Seric /*VARARGS2*/ 4694086Seric syslog(pri, fmt, args) 4704086Seric int pri; 4714086Seric char *fmt; 4724086Seric { 4734086Seric pri = *fmt; 4744086Seric args = pri; 4754086Seric pri = args; 4764086Seric } 4774086Seric 4784086Seric # endif lint 4794086Seric # endif LOG 4806890Seric /* 4816890Seric ** DFOPEN -- determined file open 4826890Seric ** 4836890Seric ** This routine has the semantics of fopen, except that it will 4846890Seric ** keep trying a few times to make this happen. The idea is that 4856890Seric ** on very loaded systems, we may run out of resources (inodes, 4866890Seric ** whatever), so this tries to get around it. 4876890Seric */ 4886890Seric 4896890Seric FILE * 4906890Seric dfopen(filename, mode) 4916890Seric char *filename; 4926890Seric char *mode; 4936890Seric { 4946890Seric register int tries; 4956890Seric register FILE *fp; 4966890Seric 4976890Seric for (tries = 0; tries < 10; tries++) 4986890Seric { 4996890Seric sleep(10 * tries); 5006890Seric errno = 0; 5016890Seric fp = fopen(filename, mode); 5029376Seric if (fp != NULL) 5036890Seric break; 5049376Seric if (errno != ENFILE && errno != EINTR) 5059376Seric break; 5066890Seric } 5076890Seric return (fp); 5086890Seric } 5097124Seric /* 5107124Seric ** PUTLINE -- put a line like fputs obeying SMTP conventions 5117124Seric ** 5127753Seric ** This routine always guarantees outputing a newline (or CRLF, 5137753Seric ** as appropriate) at the end of the string. 5147753Seric ** 5157124Seric ** Parameters: 5167124Seric ** l -- line to put. 5177124Seric ** fp -- file to put it onto. 51810172Seric ** m -- the mailer used to control output. 5197124Seric ** 5207124Seric ** Returns: 5217124Seric ** none 5227124Seric ** 5237124Seric ** Side Effects: 5247124Seric ** output of l to fp. 5257124Seric */ 5267124Seric 5277753Seric # define SMTPLINELIM 990 /* maximum line length */ 5287124Seric 52910172Seric putline(l, fp, m) 5307753Seric register char *l; 5317124Seric FILE *fp; 53210172Seric MAILER *m; 5337124Seric { 5347124Seric register char *p; 5357753Seric char svchar; 5367124Seric 5377753Seric do 5387124Seric { 5397753Seric /* find the end of the line */ 5407753Seric p = index(l, '\n'); 5417753Seric if (p == NULL) 5427753Seric p = &l[strlen(l)]; 5437124Seric 5447753Seric /* check for line overflow */ 54510172Seric while (bitset(M_LIMITS, m->m_flags) && (p - l) > SMTPLINELIM) 5467753Seric { 5477753Seric register char *q = &l[SMTPLINELIM - 1]; 5487124Seric 5497753Seric svchar = *q; 5507753Seric *q = '\0'; 55110172Seric if (l[0] == '.' && bitset(M_XDOT, m->m_flags)) 55210172Seric fputc('.', fp); 5537753Seric fputs(l, fp); 55410066Seric fputc('!', fp); 555*10326Seric fputs(m->m_eol, fp); 5567753Seric *q = svchar; 5577753Seric l = q; 5587753Seric } 5597124Seric 5607753Seric /* output last part */ 5617753Seric svchar = *p; 5627753Seric *p = '\0'; 56310172Seric if (l[0] == '.' && bitset(M_XDOT, m->m_flags)) 56410172Seric fputc('.', fp); 5657124Seric fputs(l, fp); 566*10326Seric fputs(m->m_eol, fp); 5677753Seric *p = svchar; 5687753Seric l = p; 5697753Seric if (*l == '\n') 5707753Seric l++; 5717753Seric } while (l[0] != '\0'); 5727124Seric } 5737676Seric /* 5747676Seric ** XUNLINK -- unlink a file, doing logging as appropriate. 5757676Seric ** 5767676Seric ** Parameters: 5777676Seric ** f -- name of file to unlink. 5787676Seric ** 5797676Seric ** Returns: 5807676Seric ** none. 5817676Seric ** 5827676Seric ** Side Effects: 5837676Seric ** f is unlinked. 5847676Seric */ 5857676Seric 5867676Seric xunlink(f) 5877676Seric char *f; 5887676Seric { 5897676Seric register int i; 5907676Seric 5917676Seric # ifdef LOG 5927676Seric if (LogLevel > 20) 5937812Seric syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f); 5947676Seric # endif LOG 5957676Seric 5967676Seric i = unlink(f); 5977676Seric # ifdef LOG 5987676Seric if (i < 0 && LogLevel > 21) 5997942Seric syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 6007676Seric # endif LOG 6017676Seric } 6027685Seric /* 6037685Seric ** SFGETS -- "safe" fgets -- times out. 6047685Seric ** 6057685Seric ** Parameters: 6067685Seric ** buf -- place to put the input line. 6077685Seric ** siz -- size of buf. 6087685Seric ** fp -- file to read from. 6097685Seric ** 6107685Seric ** Returns: 6117685Seric ** NULL on error (including timeout). 6127685Seric ** buf otherwise. 6137685Seric ** 6147685Seric ** Side Effects: 6157685Seric ** none. 6167685Seric */ 6177685Seric 6187942Seric static bool TimeoutFlag; 6197685Seric 6207685Seric char * 6217685Seric sfgets(buf, siz, fp) 6227685Seric char *buf; 6237685Seric int siz; 6247685Seric FILE *fp; 6257685Seric { 6267942Seric register EVENT *ev = NULL; 6277685Seric register char *p; 6287685Seric extern readtimeout(); 6297685Seric 6307942Seric if (ReadTimeout != 0) 6317942Seric ev = setevent(ReadTimeout, readtimeout, 0); 6327942Seric TimeoutFlag = FALSE; 6337942Seric do 6347942Seric { 6357942Seric errno = 0; 6367942Seric p = fgets(buf, siz, fp); 6377942Seric } while (!(p != NULL || TimeoutFlag || errno != EINTR)); 6387685Seric clrevent(ev); 6398055Seric LineNumber++; 6409581Seric if (TimeoutFlag) 6419581Seric syserr("sfgets: timeout on read (mailer may be hung)"); 6427685Seric return (p); 6437685Seric } 6447685Seric 6457685Seric static 6467685Seric readtimeout() 6477685Seric { 6487942Seric TimeoutFlag = TRUE; 6497685Seric } 6507786Seric /* 6517786Seric ** FGETFOLDED -- like fgets, but know about folded lines. 6527786Seric ** 6537786Seric ** Parameters: 6547786Seric ** buf -- place to put result. 6557786Seric ** n -- bytes available. 6567786Seric ** f -- file to read from. 6577786Seric ** 6587786Seric ** Returns: 6597786Seric ** buf on success, NULL on error or EOF. 6607786Seric ** 6617786Seric ** Side Effects: 6627786Seric ** buf gets lines from f, with continuation lines (lines 6637786Seric ** with leading white space) appended. CRLF's are mapped 6647786Seric ** into single newlines. Any trailing NL is stripped. 6657786Seric */ 6667786Seric 6677786Seric char * 6687786Seric fgetfolded(buf, n, f) 6697786Seric char *buf; 6707786Seric register int n; 6717786Seric FILE *f; 6727786Seric { 6737786Seric register char *p = buf; 6747786Seric register int i; 6757786Seric 6767786Seric n--; 67710030Seric while (fgets(p, n, f) != NULL) 6787786Seric { 67910030Seric LineNumber++; 6807786Seric fixcrlf(p, TRUE); 6817786Seric i = fgetc(f); 6827786Seric if (i != EOF) 6837786Seric ungetc(i, f); 6847786Seric if (i != ' ' && i != '\t') 6857786Seric return (buf); 6867786Seric i = strlen(p); 6877786Seric p += i; 6887786Seric *p++ = '\n'; 6897786Seric n -= i + 1; 6907786Seric } 6917786Seric return (NULL); 6927786Seric } 6937860Seric /* 6947886Seric ** CURTIME -- return current time. 6957886Seric ** 6967886Seric ** Parameters: 6977886Seric ** none. 6987886Seric ** 6997886Seric ** Returns: 7007886Seric ** the current time. 7017886Seric ** 7027886Seric ** Side Effects: 7037886Seric ** none. 7047886Seric */ 7057886Seric 7067886Seric time_t 7077886Seric curtime() 7087886Seric { 7097886Seric auto time_t t; 7107886Seric 7117886Seric (void) time(&t); 7127886Seric return (t); 7137886Seric } 7148264Seric /* 7158264Seric ** ATOBOOL -- convert a string representation to boolean. 7168264Seric ** 7178264Seric ** Defaults to "TRUE" 7188264Seric ** 7198264Seric ** Parameters: 7208264Seric ** s -- string to convert. Takes "tTyY" as true, 7218264Seric ** others as false. 7228264Seric ** 7238264Seric ** Returns: 7248264Seric ** A boolean representation of the string. 7258264Seric ** 7268264Seric ** Side Effects: 7278264Seric ** none. 7288264Seric */ 7298264Seric 7308264Seric bool 7318264Seric atobool(s) 7328264Seric register char *s; 7338264Seric { 7348264Seric if (*s == '\0' || index("tTyY", *s) != NULL) 7358264Seric return (TRUE); 7368264Seric return (FALSE); 7378264Seric } 7389048Seric /* 7399048Seric ** ATOOCT -- convert a string representation to octal. 7409048Seric ** 7419048Seric ** Parameters: 7429048Seric ** s -- string to convert. 7439048Seric ** 7449048Seric ** Returns: 7459048Seric ** An integer representing the string interpreted as an 7469048Seric ** octal number. 7479048Seric ** 7489048Seric ** Side Effects: 7499048Seric ** none. 7509048Seric */ 7519048Seric 7529048Seric atooct(s) 7539048Seric register char *s; 7549048Seric { 7559048Seric register int i = 0; 7569048Seric 7579048Seric while (*s >= '0' && *s <= '7') 7589048Seric i = (i << 3) | (*s++ - '0'); 7599048Seric return (i); 7609048Seric } 7619376Seric /* 7629376Seric ** WAITFOR -- wait for a particular process id. 7639376Seric ** 7649376Seric ** Parameters: 7659376Seric ** pid -- process id to wait for. 7669376Seric ** 7679376Seric ** Returns: 7689376Seric ** status of pid. 7699376Seric ** -1 if pid never shows up. 7709376Seric ** 7719376Seric ** Side Effects: 7729376Seric ** none. 7739376Seric */ 7749376Seric 7759376Seric waitfor(pid) 7769376Seric int pid; 7779376Seric { 7789376Seric auto int st; 7799376Seric int i; 7809376Seric 7819376Seric do 7829376Seric { 7839376Seric errno = 0; 7849376Seric i = wait(&st); 7859376Seric } while ((i >= 0 || errno == EINTR) && i != pid); 7869376Seric if (i < 0) 7879376Seric st = -1; 7889376Seric return (st); 7899376Seric } 7909376Seric /* 7919376Seric ** CLOSEALL -- close all extraneous file descriptors 7929376Seric ** 7939376Seric ** Parameters: 7949376Seric ** none. 7959376Seric ** 7969376Seric ** Returns: 7979376Seric ** none. 7989376Seric ** 7999376Seric ** Side Effects: 8009376Seric ** Closes all file descriptors except zero, one, and two. 8019376Seric */ 8029376Seric 8039376Seric closeall() 8049376Seric { 8059376Seric int i; 8069376Seric 8079376Seric for (i = 3; i < 50; i++) 8089376Seric (void) close(i); 8099376Seric } 810