xref: /csrg-svn/usr.sbin/sendmail/src/util.c (revision 40999)
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*40999Sbostic static char sccsid[] = "@(#)util.c	5.17 (Berkeley) 04/19/90";
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;
122*40999Sbostic 		*p++ = toupper(*s);
123*40999Sbostic 		s++;
1242900Seric 		while (isalpha(*s))
1252900Seric 			*p++ = *s++;
1262900Seric 	}
1272900Seric 
1282900Seric 	*p = '\0';
1292900Seric 	return (buf);
1302900Seric }
1312900Seric /*
132298Seric **  XALLOC -- Allocate memory and bitch wildly on failure.
133298Seric **
134298Seric **	THIS IS A CLUDGE.  This should be made to give a proper
135298Seric **	error -- but after all, what can we do?
136298Seric **
137298Seric **	Parameters:
138298Seric **		sz -- size of area to allocate.
139298Seric **
140298Seric **	Returns:
141298Seric **		pointer to data region.
142298Seric **
143298Seric **	Side Effects:
144298Seric **		Memory is allocated.
145298Seric */
146298Seric 
147298Seric char *
148298Seric xalloc(sz)
1497007Seric 	register int sz;
150298Seric {
151298Seric 	register char *p;
15223121Seric 	extern char *malloc();
153298Seric 
15423121Seric 	p = malloc((unsigned) sz);
155298Seric 	if (p == NULL)
156298Seric 	{
157298Seric 		syserr("Out of memory!!");
15810685Seric 		abort();
15910685Seric 		/* exit(EX_UNAVAILABLE); */
160298Seric 	}
161298Seric 	return (p);
162298Seric }
163298Seric /*
1643151Seric **  COPYPLIST -- copy list of pointers.
1653151Seric **
1663151Seric **	This routine is the equivalent of newstr for lists of
1673151Seric **	pointers.
1683151Seric **
1693151Seric **	Parameters:
1703151Seric **		list -- list of pointers to copy.
1713151Seric **			Must be NULL terminated.
1723151Seric **		copycont -- if TRUE, copy the contents of the vector
1733151Seric **			(which must be a string) also.
1743151Seric **
1753151Seric **	Returns:
1763151Seric **		a copy of 'list'.
1773151Seric **
1783151Seric **	Side Effects:
1793151Seric **		none.
1803151Seric */
1813151Seric 
1823151Seric char **
1833151Seric copyplist(list, copycont)
1843151Seric 	char **list;
1853151Seric 	bool copycont;
1863151Seric {
1873151Seric 	register char **vp;
1883151Seric 	register char **newvp;
1893151Seric 
1903151Seric 	for (vp = list; *vp != NULL; vp++)
1913151Seric 		continue;
1923151Seric 
1933151Seric 	vp++;
1943151Seric 
19516897Seric 	newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
19616897Seric 	bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
1973151Seric 
1983151Seric 	if (copycont)
1993151Seric 	{
2003151Seric 		for (vp = newvp; *vp != NULL; vp++)
2013151Seric 			*vp = newstr(*vp);
2023151Seric 	}
2033151Seric 
2043151Seric 	return (newvp);
2053151Seric }
2063151Seric /*
2073151Seric **  PRINTAV -- print argument vector.
2083151Seric **
2093151Seric **	Parameters:
2103151Seric **		av -- argument vector.
2113151Seric **
2123151Seric **	Returns:
2133151Seric **		none.
2143151Seric **
2153151Seric **	Side Effects:
2163151Seric **		prints av.
2173151Seric */
2183151Seric 
2193151Seric printav(av)
2203151Seric 	register char **av;
2213151Seric {
2223151Seric 	while (*av != NULL)
2233151Seric 	{
2248063Seric 		if (tTd(0, 44))
2258063Seric 			printf("\n\t%08x=", *av);
2268063Seric 		else
22723105Seric 			(void) putchar(' ');
2283151Seric 		xputs(*av++);
2293151Seric 	}
23023105Seric 	(void) putchar('\n');
2313151Seric }
2323151Seric /*
2333151Seric **  LOWER -- turn letter into lower case.
2343151Seric **
2353151Seric **	Parameters:
2363151Seric **		c -- character to turn into lower case.
2373151Seric **
2383151Seric **	Returns:
2393151Seric **		c, in lower case.
2403151Seric **
2413151Seric **	Side Effects:
2423151Seric **		none.
2433151Seric */
2443151Seric 
2453151Seric char
2463151Seric lower(c)
2473151Seric 	register char c;
2483151Seric {
24933724Sbostic 	return(isascii(c) && isupper(c) ? tolower(c) : c);
2503151Seric }
2513151Seric /*
2523151Seric **  XPUTS -- put string doing control escapes.
2533151Seric **
2543151Seric **	Parameters:
2553151Seric **		s -- string to put.
2563151Seric **
2573151Seric **	Returns:
2583151Seric **		none.
2593151Seric **
2603151Seric **	Side Effects:
2613151Seric **		output to stdout
2623151Seric */
2633151Seric 
2643151Seric xputs(s)
2653151Seric 	register char *s;
2663151Seric {
2673151Seric 	register char c;
2683151Seric 
2698055Seric 	if (s == NULL)
2708055Seric 	{
2718055Seric 		printf("<null>");
2728055Seric 		return;
2738055Seric 	}
27423105Seric 	(void) putchar('"');
2753151Seric 	while ((c = *s++) != '\0')
2763151Seric 	{
2773151Seric 		if (!isascii(c))
2783151Seric 		{
27923105Seric 			(void) putchar('\\');
2803151Seric 			c &= 0177;
2813151Seric 		}
28210326Seric 		if (c < 040 || c >= 0177)
2833151Seric 		{
28423105Seric 			(void) putchar('^');
28510326Seric 			c ^= 0100;
2863151Seric 		}
28723105Seric 		(void) putchar(c);
2883151Seric 	}
28923105Seric 	(void) putchar('"');
2904086Seric 	(void) fflush(stdout);
2913151Seric }
2923151Seric /*
2933151Seric **  MAKELOWER -- Translate a line into lower case
2943151Seric **
2953151Seric **	Parameters:
2963151Seric **		p -- the string to translate.  If NULL, return is
2973151Seric **			immediate.
2983151Seric **
2993151Seric **	Returns:
3003151Seric **		none.
3013151Seric **
3023151Seric **	Side Effects:
3033151Seric **		String pointed to by p is translated to lower case.
3043151Seric **
3053151Seric **	Called By:
3063151Seric **		parse
3073151Seric */
3083151Seric 
3093151Seric makelower(p)
3103151Seric 	register char *p;
3113151Seric {
3123151Seric 	register char c;
3133151Seric 
3143151Seric 	if (p == NULL)
3153151Seric 		return;
3163151Seric 	for (; (c = *p) != '\0'; p++)
3173151Seric 		if (isascii(c) && isupper(c))
31833724Sbostic 			*p = tolower(c);
3193151Seric }
3204059Seric /*
3215196Seric **  BUILDFNAME -- build full name from gecos style entry.
3224375Seric **
3235196Seric **	This routine interprets the strange entry that would appear
3245196Seric **	in the GECOS field of the password file.
3255196Seric **
3264375Seric **	Parameters:
3275196Seric **		p -- name to build.
3285196Seric **		login -- the login name of this user (for &).
3295196Seric **		buf -- place to put the result.
3304375Seric **
3314375Seric **	Returns:
3324375Seric **		none.
3334375Seric **
3344375Seric **	Side Effects:
3354375Seric **		none.
3364375Seric */
3374375Seric 
3385196Seric buildfname(p, login, buf)
3395196Seric 	register char *p;
3405196Seric 	char *login;
3414375Seric 	char *buf;
3424375Seric {
3434375Seric 	register char *bp = buf;
3444375Seric 
3454438Seric 	if (*p == '*')
3464438Seric 		p++;
3476278Seric 	while (*p != '\0' && *p != ',' && *p != ';' && *p != '%')
3484375Seric 	{
3494375Seric 		if (*p == '&')
3504375Seric 		{
3515196Seric 			(void) strcpy(bp, login);
3524375Seric 			*bp = toupper(*bp);
3534375Seric 			while (*bp != '\0')
3544375Seric 				bp++;
3554375Seric 			p++;
3564375Seric 		}
3574375Seric 		else
3584375Seric 			*bp++ = *p++;
3594375Seric 	}
3604375Seric 	*bp = '\0';
3614375Seric }
3624375Seric /*
3634538Seric **  SAFEFILE -- return true if a file exists and is safe for a user.
3644538Seric **
3654538Seric **	Parameters:
3664538Seric **		fn -- filename to check.
3674538Seric **		uid -- uid to compare against.
3684538Seric **		mode -- mode bits that must match.
3694538Seric **
3704538Seric **	Returns:
3714538Seric **		TRUE if fn exists, is owned by uid, and matches mode.
3724538Seric **		FALSE otherwise.
3734538Seric **
3744538Seric **	Side Effects:
3754538Seric **		none.
3764538Seric */
3774538Seric 
3784538Seric bool
3794538Seric safefile(fn, uid, mode)
3804538Seric 	char *fn;
3814538Seric 	int uid;
3824538Seric 	int mode;
3834538Seric {
3844538Seric 	struct stat stbuf;
3854538Seric 
3864538Seric 	if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid &&
3874538Seric 	    (stbuf.st_mode & mode) == mode)
3884538Seric 		return (TRUE);
38911936Seric 	errno = 0;
3904538Seric 	return (FALSE);
3914538Seric }
3924538Seric /*
3934557Seric **  FIXCRLF -- fix <CR><LF> in line.
3944557Seric **
3954557Seric **	Looks for the <CR><LF> combination and turns it into the
3964557Seric **	UNIX canonical <NL> character.  It only takes one line,
3974557Seric **	i.e., it is assumed that the first <NL> found is the end
3984557Seric **	of the line.
3994557Seric **
4004557Seric **	Parameters:
4014557Seric **		line -- the line to fix.
4024557Seric **		stripnl -- if true, strip the newline also.
4034557Seric **
4044557Seric **	Returns:
4054557Seric **		none.
4064557Seric **
4074557Seric **	Side Effects:
4084557Seric **		line is changed in place.
4094557Seric */
4104557Seric 
4114557Seric fixcrlf(line, stripnl)
4124557Seric 	char *line;
4134557Seric 	bool stripnl;
4144557Seric {
4154557Seric 	register char *p;
4164557Seric 
4174557Seric 	p = index(line, '\n');
4184557Seric 	if (p == NULL)
4194557Seric 		return;
42036291Sbostic 	if (p > line && p[-1] == '\r')
4214557Seric 		p--;
4224557Seric 	if (!stripnl)
4234557Seric 		*p++ = '\n';
4244557Seric 	*p = '\0';
4254557Seric }
4264557Seric /*
4276890Seric **  DFOPEN -- determined file open
4286890Seric **
4296890Seric **	This routine has the semantics of fopen, except that it will
4306890Seric **	keep trying a few times to make this happen.  The idea is that
4316890Seric **	on very loaded systems, we may run out of resources (inodes,
4326890Seric **	whatever), so this tries to get around it.
4336890Seric */
4346890Seric 
4356890Seric FILE *
4366890Seric dfopen(filename, mode)
4376890Seric 	char *filename;
4386890Seric 	char *mode;
4396890Seric {
4406890Seric 	register int tries;
4416890Seric 	register FILE *fp;
4426890Seric 
4436890Seric 	for (tries = 0; tries < 10; tries++)
4446890Seric 	{
44525618Seric 		sleep((unsigned) (10 * tries));
4466890Seric 		errno = 0;
4476890Seric 		fp = fopen(filename, mode);
4489376Seric 		if (fp != NULL)
4496890Seric 			break;
4509376Seric 		if (errno != ENFILE && errno != EINTR)
4519376Seric 			break;
4526890Seric 	}
45311936Seric 	errno = 0;
4546890Seric 	return (fp);
4556890Seric }
4567124Seric /*
4577124Seric **  PUTLINE -- put a line like fputs obeying SMTP conventions
4587124Seric **
4597753Seric **	This routine always guarantees outputing a newline (or CRLF,
4607753Seric **	as appropriate) at the end of the string.
4617753Seric **
4627124Seric **	Parameters:
4637124Seric **		l -- line to put.
4647124Seric **		fp -- file to put it onto.
46510172Seric **		m -- the mailer used to control output.
4667124Seric **
4677124Seric **	Returns:
4687124Seric **		none
4697124Seric **
4707124Seric **	Side Effects:
4717124Seric **		output of l to fp.
4727124Seric */
4737124Seric 
4747753Seric # define SMTPLINELIM	990	/* maximum line length */
4757124Seric 
47610172Seric putline(l, fp, m)
4777753Seric 	register char *l;
4787124Seric 	FILE *fp;
47910172Seric 	MAILER *m;
4807124Seric {
4817124Seric 	register char *p;
4827753Seric 	char svchar;
4837124Seric 
48411275Seric 	/* strip out 0200 bits -- these can look like TELNET protocol */
48511275Seric 	if (bitnset(M_LIMITS, m->m_flags))
48611275Seric 	{
48711275Seric 		p = l;
48811275Seric 		while ((*p++ &= ~0200) != 0)
48911275Seric 			continue;
49011275Seric 	}
49111275Seric 
4927753Seric 	do
4937124Seric 	{
4947753Seric 		/* find the end of the line */
4957753Seric 		p = index(l, '\n');
4967753Seric 		if (p == NULL)
4977753Seric 			p = &l[strlen(l)];
4987124Seric 
4997753Seric 		/* check for line overflow */
50011275Seric 		while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags))
5017753Seric 		{
5027753Seric 			register char *q = &l[SMTPLINELIM - 1];
5037124Seric 
5047753Seric 			svchar = *q;
5057753Seric 			*q = '\0';
50610685Seric 			if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
50723105Seric 				(void) putc('.', fp);
5087753Seric 			fputs(l, fp);
50923105Seric 			(void) putc('!', fp);
51010326Seric 			fputs(m->m_eol, fp);
5117753Seric 			*q = svchar;
5127753Seric 			l = q;
5137753Seric 		}
5147124Seric 
5157753Seric 		/* output last part */
5167753Seric 		svchar = *p;
5177753Seric 		*p = '\0';
51810685Seric 		if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
51923105Seric 			(void) putc('.', fp);
5207124Seric 		fputs(l, fp);
52110326Seric 		fputs(m->m_eol, fp);
5227753Seric 		*p = svchar;
5237753Seric 		l = p;
5247753Seric 		if (*l == '\n')
5257753Seric 			l++;
5267753Seric 	} while (l[0] != '\0');
5277124Seric }
5287676Seric /*
5297676Seric **  XUNLINK -- unlink a file, doing logging as appropriate.
5307676Seric **
5317676Seric **	Parameters:
5327676Seric **		f -- name of file to unlink.
5337676Seric **
5347676Seric **	Returns:
5357676Seric **		none.
5367676Seric **
5377676Seric **	Side Effects:
5387676Seric **		f is unlinked.
5397676Seric */
5407676Seric 
5417676Seric xunlink(f)
5427676Seric 	char *f;
5437676Seric {
5447676Seric 	register int i;
5457676Seric 
5467676Seric # ifdef LOG
5477676Seric 	if (LogLevel > 20)
5487812Seric 		syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f);
5497676Seric # endif LOG
5507676Seric 
5517676Seric 	i = unlink(f);
5527676Seric # ifdef LOG
5537676Seric 	if (i < 0 && LogLevel > 21)
5547942Seric 		syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno);
5557676Seric # endif LOG
5567676Seric }
5577685Seric /*
55814885Seric **  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
5597685Seric **
5607685Seric **	Parameters:
5617685Seric **		buf -- place to put the input line.
5627685Seric **		siz -- size of buf.
5637685Seric **		fp -- file to read from.
5647685Seric **
5657685Seric **	Returns:
56615533Seric **		NULL on error (including timeout).  This will also leave
56715533Seric **			buf containing a null string.
5687685Seric **		buf otherwise.
5697685Seric **
5707685Seric **	Side Effects:
5717685Seric **		none.
5727685Seric */
5737685Seric 
57414885Seric static jmp_buf	CtxReadTimeout;
5757685Seric 
5767685Seric char *
5777685Seric sfgets(buf, siz, fp)
5787685Seric 	char *buf;
5797685Seric 	int siz;
5807685Seric 	FILE *fp;
5817685Seric {
5827942Seric 	register EVENT *ev = NULL;
5837685Seric 	register char *p;
5847685Seric 	extern readtimeout();
5857685Seric 
58614885Seric 	/* set the timeout */
5877942Seric 	if (ReadTimeout != 0)
58814885Seric 	{
58914885Seric 		if (setjmp(CtxReadTimeout) != 0)
59014885Seric 		{
59136233Skarels # ifdef LOG
59236230Skarels 			syslog(LOG_NOTICE,
59336230Skarels 			    "timeout waiting for input from %s\n",
59440998Sbostic 			    RealHostName? RealHostName: "local");
59536233Skarels # endif
59636230Skarels 			errno = 0;
59740964Sbostic 			usrerr("451 timeout waiting for input");
59819037Seric 			buf[0] = '\0';
59914885Seric 			return (NULL);
60014885Seric 		}
60116138Seric 		ev = setevent((time_t) ReadTimeout, readtimeout, 0);
60214885Seric 	}
60314885Seric 
60414885Seric 	/* try to read */
60515533Seric 	p = NULL;
60615533Seric 	while (p == NULL && !feof(fp) && !ferror(fp))
6077942Seric 	{
6087942Seric 		errno = 0;
6097942Seric 		p = fgets(buf, siz, fp);
61015533Seric 		if (errno == EINTR)
61115533Seric 			clearerr(fp);
61215533Seric 	}
61314885Seric 
61414885Seric 	/* clear the event if it has not sprung */
6157685Seric 	clrevent(ev);
61614885Seric 
61714885Seric 	/* clean up the books and exit */
6188055Seric 	LineNumber++;
61915533Seric 	if (p == NULL)
62016880Seric 	{
62115533Seric 		buf[0] = '\0';
62216880Seric 		return (NULL);
62316880Seric 	}
62416880Seric 	for (p = buf; *p != '\0'; p++)
62516880Seric 		*p &= ~0200;
62616880Seric 	return (buf);
6277685Seric }
6287685Seric 
6297685Seric static
6307685Seric readtimeout()
6317685Seric {
63214885Seric 	longjmp(CtxReadTimeout, 1);
6337685Seric }
6347786Seric /*
6357786Seric **  FGETFOLDED -- like fgets, but know about folded lines.
6367786Seric **
6377786Seric **	Parameters:
6387786Seric **		buf -- place to put result.
6397786Seric **		n -- bytes available.
6407786Seric **		f -- file to read from.
6417786Seric **
6427786Seric **	Returns:
6437786Seric **		buf on success, NULL on error or EOF.
6447786Seric **
6457786Seric **	Side Effects:
6467786Seric **		buf gets lines from f, with continuation lines (lines
6477786Seric **		with leading white space) appended.  CRLF's are mapped
6487786Seric **		into single newlines.  Any trailing NL is stripped.
6497786Seric */
6507786Seric 
6517786Seric char *
6527786Seric fgetfolded(buf, n, f)
6537786Seric 	char *buf;
6547786Seric 	register int n;
6557786Seric 	FILE *f;
6567786Seric {
6577786Seric 	register char *p = buf;
6587786Seric 	register int i;
6597786Seric 
6607786Seric 	n--;
66117350Seric 	while ((i = getc(f)) != EOF)
6627786Seric 	{
66317350Seric 		if (i == '\r')
66417350Seric 		{
66517350Seric 			i = getc(f);
66617350Seric 			if (i != '\n')
66717350Seric 			{
66817350Seric 				if (i != EOF)
66923105Seric 					(void) ungetc(i, f);
67017350Seric 				i = '\r';
67117350Seric 			}
67217350Seric 		}
67317350Seric 		if (--n > 0)
67417350Seric 			*p++ = i;
67517350Seric 		if (i == '\n')
67617350Seric 		{
67717350Seric 			LineNumber++;
67817350Seric 			i = getc(f);
67917350Seric 			if (i != EOF)
68023105Seric 				(void) ungetc(i, f);
68117350Seric 			if (i != ' ' && i != '\t')
68217350Seric 			{
68317350Seric 				*--p = '\0';
68417350Seric 				return (buf);
68517350Seric 			}
68617350Seric 		}
6877786Seric 	}
6887786Seric 	return (NULL);
6897786Seric }
6907860Seric /*
6917886Seric **  CURTIME -- return current time.
6927886Seric **
6937886Seric **	Parameters:
6947886Seric **		none.
6957886Seric **
6967886Seric **	Returns:
6977886Seric **		the current time.
6987886Seric **
6997886Seric **	Side Effects:
7007886Seric **		none.
7017886Seric */
7027886Seric 
7037886Seric time_t
7047886Seric curtime()
7057886Seric {
7067886Seric 	auto time_t t;
7077886Seric 
7087886Seric 	(void) time(&t);
7097886Seric 	return (t);
7107886Seric }
7118264Seric /*
7128264Seric **  ATOBOOL -- convert a string representation to boolean.
7138264Seric **
7148264Seric **	Defaults to "TRUE"
7158264Seric **
7168264Seric **	Parameters:
7178264Seric **		s -- string to convert.  Takes "tTyY" as true,
7188264Seric **			others as false.
7198264Seric **
7208264Seric **	Returns:
7218264Seric **		A boolean representation of the string.
7228264Seric **
7238264Seric **	Side Effects:
7248264Seric **		none.
7258264Seric */
7268264Seric 
7278264Seric bool
7288264Seric atobool(s)
7298264Seric 	register char *s;
7308264Seric {
7318264Seric 	if (*s == '\0' || index("tTyY", *s) != NULL)
7328264Seric 		return (TRUE);
7338264Seric 	return (FALSE);
7348264Seric }
7359048Seric /*
7369048Seric **  ATOOCT -- convert a string representation to octal.
7379048Seric **
7389048Seric **	Parameters:
7399048Seric **		s -- string to convert.
7409048Seric **
7419048Seric **	Returns:
7429048Seric **		An integer representing the string interpreted as an
7439048Seric **		octal number.
7449048Seric **
7459048Seric **	Side Effects:
7469048Seric **		none.
7479048Seric */
7489048Seric 
7499048Seric atooct(s)
7509048Seric 	register char *s;
7519048Seric {
7529048Seric 	register int i = 0;
7539048Seric 
7549048Seric 	while (*s >= '0' && *s <= '7')
7559048Seric 		i = (i << 3) | (*s++ - '0');
7569048Seric 	return (i);
7579048Seric }
7589376Seric /*
7599376Seric **  WAITFOR -- wait for a particular process id.
7609376Seric **
7619376Seric **	Parameters:
7629376Seric **		pid -- process id to wait for.
7639376Seric **
7649376Seric **	Returns:
7659376Seric **		status of pid.
7669376Seric **		-1 if pid never shows up.
7679376Seric **
7689376Seric **	Side Effects:
7699376Seric **		none.
7709376Seric */
7719376Seric 
7729376Seric waitfor(pid)
7739376Seric 	int pid;
7749376Seric {
7759376Seric 	auto int st;
7769376Seric 	int i;
7779376Seric 
7789376Seric 	do
7799376Seric 	{
7809376Seric 		errno = 0;
7819376Seric 		i = wait(&st);
7829376Seric 	} while ((i >= 0 || errno == EINTR) && i != pid);
7839376Seric 	if (i < 0)
7849376Seric 		st = -1;
7859376Seric 	return (st);
7869376Seric }
7879376Seric /*
78810685Seric **  BITINTERSECT -- tell if two bitmaps intersect
78910685Seric **
79010685Seric **	Parameters:
79110685Seric **		a, b -- the bitmaps in question
79210685Seric **
79310685Seric **	Returns:
79410685Seric **		TRUE if they have a non-null intersection
79510685Seric **		FALSE otherwise
79610685Seric **
79710685Seric **	Side Effects:
79810685Seric **		none.
79910685Seric */
80010685Seric 
80110685Seric bool
80210685Seric bitintersect(a, b)
80310685Seric 	BITMAP a;
80410685Seric 	BITMAP b;
80510685Seric {
80610685Seric 	int i;
80710685Seric 
80810685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
80910685Seric 		if ((a[i] & b[i]) != 0)
81010685Seric 			return (TRUE);
81110685Seric 	return (FALSE);
81210685Seric }
81310685Seric /*
81410685Seric **  BITZEROP -- tell if a bitmap is all zero
81510685Seric **
81610685Seric **	Parameters:
81710685Seric **		map -- the bit map to check
81810685Seric **
81910685Seric **	Returns:
82010685Seric **		TRUE if map is all zero.
82110685Seric **		FALSE if there are any bits set in map.
82210685Seric **
82310685Seric **	Side Effects:
82410685Seric **		none.
82510685Seric */
82610685Seric 
82710685Seric bool
82810685Seric bitzerop(map)
82910685Seric 	BITMAP map;
83010685Seric {
83110685Seric 	int i;
83210685Seric 
83310685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
83410685Seric 		if (map[i] != 0)
83510685Seric 			return (FALSE);
83610685Seric 	return (TRUE);
83710685Seric }
838