xref: /csrg-svn/usr.sbin/sendmail/src/util.c (revision 54983)
122717Sdist /*
242833Sbostic  * Copyright (c) 1983 Eric P. Allman
333731Sbostic  * Copyright (c) 1988 Regents of the University of California.
433731Sbostic  * All rights reserved.
533731Sbostic  *
642833Sbostic  * %sccs.include.redist.c%
733731Sbostic  */
822717Sdist 
922717Sdist #ifndef lint
10*54983Seric static char sccsid[] = "@(#)util.c	5.26 (Berkeley) 07/12/92";
1133731Sbostic #endif /* not lint */
1222717Sdist 
133151Seric # include <stdio.h>
144538Seric # include <sys/types.h>
154538Seric # include <sys/stat.h>
16298Seric # include <sysexits.h>
176890Seric # include <errno.h>
186890Seric # include "sendmail.h"
19298Seric 
20298Seric /*
21298Seric **  STRIPQUOTES -- Strip quotes & quote bits from a string.
22298Seric **
23298Seric **	Runs through a string and strips off unquoted quote
24298Seric **	characters and quote bits.  This is done in place.
25298Seric **
26298Seric **	Parameters:
27298Seric **		s -- the string to strip.
28298Seric **
29298Seric **	Returns:
30298Seric **		none.
31298Seric **
32298Seric **	Side Effects:
33298Seric **		none.
34298Seric **
35298Seric **	Called By:
36298Seric **		deliver
37298Seric */
38298Seric 
39*54983Seric stripquotes(s)
40298Seric 	char *s;
41298Seric {
42298Seric 	register char *p;
43298Seric 	register char *q;
44298Seric 	register char c;
45298Seric 
464101Seric 	if (s == NULL)
474101Seric 		return;
484101Seric 
49*54983Seric 	p = q = s;
50*54983Seric 	do
51298Seric 	{
52*54983Seric 		c = *p++;
53*54983Seric 		if (c == '\\')
54*54983Seric 			c = *p++;
55*54983Seric 		else if (c == '"')
56*54983Seric 			continue;
57*54983Seric 		*q++ = c;
58*54983Seric 	} while (c != '\0');
59298Seric }
60298Seric /*
612900Seric **  CAPITALIZE -- return a copy of a string, properly capitalized.
622900Seric **
632900Seric **	Parameters:
642900Seric **		s -- the string to capitalize.
652900Seric **
662900Seric **	Returns:
672900Seric **		a pointer to a properly capitalized string.
682900Seric **
692900Seric **	Side Effects:
702900Seric **		none.
712900Seric */
722900Seric 
732900Seric char *
742900Seric capitalize(s)
752900Seric 	register char *s;
762900Seric {
772900Seric 	static char buf[50];
782900Seric 	register char *p;
792900Seric 
802900Seric 	p = buf;
812900Seric 
822900Seric 	for (;;)
832900Seric 	{
842900Seric 		while (!isalpha(*s) && *s != '\0')
852900Seric 			*p++ = *s++;
862900Seric 		if (*s == '\0')
872900Seric 			break;
8840999Sbostic 		*p++ = toupper(*s);
8940999Sbostic 		s++;
902900Seric 		while (isalpha(*s))
912900Seric 			*p++ = *s++;
922900Seric 	}
932900Seric 
942900Seric 	*p = '\0';
952900Seric 	return (buf);
962900Seric }
972900Seric /*
98298Seric **  XALLOC -- Allocate memory and bitch wildly on failure.
99298Seric **
100298Seric **	THIS IS A CLUDGE.  This should be made to give a proper
101298Seric **	error -- but after all, what can we do?
102298Seric **
103298Seric **	Parameters:
104298Seric **		sz -- size of area to allocate.
105298Seric **
106298Seric **	Returns:
107298Seric **		pointer to data region.
108298Seric **
109298Seric **	Side Effects:
110298Seric **		Memory is allocated.
111298Seric */
112298Seric 
113298Seric char *
114298Seric xalloc(sz)
1157007Seric 	register int sz;
116298Seric {
117298Seric 	register char *p;
11823121Seric 	extern char *malloc();
119298Seric 
12023121Seric 	p = malloc((unsigned) sz);
121298Seric 	if (p == NULL)
122298Seric 	{
123298Seric 		syserr("Out of memory!!");
12410685Seric 		abort();
12510685Seric 		/* exit(EX_UNAVAILABLE); */
126298Seric 	}
127298Seric 	return (p);
128298Seric }
129298Seric /*
1303151Seric **  COPYPLIST -- copy list of pointers.
1313151Seric **
1323151Seric **	This routine is the equivalent of newstr for lists of
1333151Seric **	pointers.
1343151Seric **
1353151Seric **	Parameters:
1363151Seric **		list -- list of pointers to copy.
1373151Seric **			Must be NULL terminated.
1383151Seric **		copycont -- if TRUE, copy the contents of the vector
1393151Seric **			(which must be a string) also.
1403151Seric **
1413151Seric **	Returns:
1423151Seric **		a copy of 'list'.
1433151Seric **
1443151Seric **	Side Effects:
1453151Seric **		none.
1463151Seric */
1473151Seric 
1483151Seric char **
1493151Seric copyplist(list, copycont)
1503151Seric 	char **list;
1513151Seric 	bool copycont;
1523151Seric {
1533151Seric 	register char **vp;
1543151Seric 	register char **newvp;
1553151Seric 
1563151Seric 	for (vp = list; *vp != NULL; vp++)
1573151Seric 		continue;
1583151Seric 
1593151Seric 	vp++;
1603151Seric 
16116897Seric 	newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
16216897Seric 	bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
1633151Seric 
1643151Seric 	if (copycont)
1653151Seric 	{
1663151Seric 		for (vp = newvp; *vp != NULL; vp++)
1673151Seric 			*vp = newstr(*vp);
1683151Seric 	}
1693151Seric 
1703151Seric 	return (newvp);
1713151Seric }
1723151Seric /*
1733151Seric **  PRINTAV -- print argument vector.
1743151Seric **
1753151Seric **	Parameters:
1763151Seric **		av -- argument vector.
1773151Seric **
1783151Seric **	Returns:
1793151Seric **		none.
1803151Seric **
1813151Seric **	Side Effects:
1823151Seric **		prints av.
1833151Seric */
1843151Seric 
1853151Seric printav(av)
1863151Seric 	register char **av;
1873151Seric {
1883151Seric 	while (*av != NULL)
1893151Seric 	{
1908063Seric 		if (tTd(0, 44))
1918063Seric 			printf("\n\t%08x=", *av);
1928063Seric 		else
19323105Seric 			(void) putchar(' ');
1943151Seric 		xputs(*av++);
1953151Seric 	}
19623105Seric 	(void) putchar('\n');
1973151Seric }
1983151Seric /*
1993151Seric **  LOWER -- turn letter into lower case.
2003151Seric **
2013151Seric **	Parameters:
2023151Seric **		c -- character to turn into lower case.
2033151Seric **
2043151Seric **	Returns:
2053151Seric **		c, in lower case.
2063151Seric **
2073151Seric **	Side Effects:
2083151Seric **		none.
2093151Seric */
2103151Seric 
2113151Seric char
2123151Seric lower(c)
2133151Seric 	register char c;
2143151Seric {
21533724Sbostic 	return(isascii(c) && isupper(c) ? tolower(c) : c);
2163151Seric }
2173151Seric /*
2183151Seric **  XPUTS -- put string doing control escapes.
2193151Seric **
2203151Seric **	Parameters:
2213151Seric **		s -- string to put.
2223151Seric **
2233151Seric **	Returns:
2243151Seric **		none.
2253151Seric **
2263151Seric **	Side Effects:
2273151Seric **		output to stdout
2283151Seric */
2293151Seric 
2303151Seric xputs(s)
2313151Seric 	register char *s;
2323151Seric {
2333151Seric 	register char c;
23451781Seric 	register struct metamac *mp;
23551781Seric 	extern struct metamac MetaMacros[];
2363151Seric 
2378055Seric 	if (s == NULL)
2388055Seric 	{
2398055Seric 		printf("<null>");
2408055Seric 		return;
2418055Seric 	}
24251781Seric 	c = *s;
24351781Seric 	if (c == MATCHREPL && isdigit(s[1]) && s[2] == '\0')
24451781Seric 	{
24551781Seric 		printf("$%c", s[1]);
24651781Seric 		return;
24751781Seric 	}
24851781Seric 	for (mp = MetaMacros; mp->metaname != NULL; mp++)
24951781Seric 	{
25051781Seric 		if (mp->metaval == c)
25151781Seric 		{
25251781Seric 			printf("$%c%s", mp->metaname, ++s);
25351781Seric 			return;
25451781Seric 		}
25551781Seric 	}
25623105Seric 	(void) putchar('"');
2573151Seric 	while ((c = *s++) != '\0')
2583151Seric 	{
2593151Seric 		if (!isascii(c))
2603151Seric 		{
26123105Seric 			(void) putchar('\\');
2623151Seric 			c &= 0177;
2633151Seric 		}
26410326Seric 		if (c < 040 || c >= 0177)
2653151Seric 		{
26652050Seric 			switch (c)
26752050Seric 			{
26852050Seric 			  case '\n':
26952050Seric 				c = 'n';
27052050Seric 				break;
27152050Seric 
27252050Seric 			  case '\r':
27352050Seric 				c = 'r';
27452050Seric 				break;
27552050Seric 
27652050Seric 			  case '\t':
27752050Seric 				c = 't';
27852050Seric 				break;
27952050Seric 
28052637Seric 			  case '\001':
28152637Seric 				(void) putchar('$');
28252637Seric 				continue;
28352637Seric 
28452050Seric 			  default:
28552050Seric 				(void) putchar('^');
28652050Seric 				(void) putchar(c ^ 0100);
28752050Seric 				continue;
28852050Seric 			}
28952050Seric 			(void) putchar('\\');
2903151Seric 		}
29123105Seric 		(void) putchar(c);
2923151Seric 	}
29323105Seric 	(void) putchar('"');
2944086Seric 	(void) fflush(stdout);
2953151Seric }
2963151Seric /*
2973151Seric **  MAKELOWER -- Translate a line into lower case
2983151Seric **
2993151Seric **	Parameters:
3003151Seric **		p -- the string to translate.  If NULL, return is
3013151Seric **			immediate.
3023151Seric **
3033151Seric **	Returns:
3043151Seric **		none.
3053151Seric **
3063151Seric **	Side Effects:
3073151Seric **		String pointed to by p is translated to lower case.
3083151Seric **
3093151Seric **	Called By:
3103151Seric **		parse
3113151Seric */
3123151Seric 
3133151Seric makelower(p)
3143151Seric 	register char *p;
3153151Seric {
3163151Seric 	register char c;
3173151Seric 
3183151Seric 	if (p == NULL)
3193151Seric 		return;
3203151Seric 	for (; (c = *p) != '\0'; p++)
3213151Seric 		if (isascii(c) && isupper(c))
32233724Sbostic 			*p = tolower(c);
3233151Seric }
3244059Seric /*
3255196Seric **  BUILDFNAME -- build full name from gecos style entry.
3264375Seric **
3275196Seric **	This routine interprets the strange entry that would appear
3285196Seric **	in the GECOS field of the password file.
3295196Seric **
3304375Seric **	Parameters:
3315196Seric **		p -- name to build.
3325196Seric **		login -- the login name of this user (for &).
3335196Seric **		buf -- place to put the result.
3344375Seric **
3354375Seric **	Returns:
3364375Seric **		none.
3374375Seric **
3384375Seric **	Side Effects:
3394375Seric **		none.
3404375Seric */
3414375Seric 
3425196Seric buildfname(p, login, buf)
3435196Seric 	register char *p;
3445196Seric 	char *login;
3454375Seric 	char *buf;
3464375Seric {
3474375Seric 	register char *bp = buf;
3484375Seric 
3494438Seric 	if (*p == '*')
3504438Seric 		p++;
3516278Seric 	while (*p != '\0' && *p != ',' && *p != ';' && *p != '%')
3524375Seric 	{
3534375Seric 		if (*p == '&')
3544375Seric 		{
3555196Seric 			(void) strcpy(bp, login);
3564375Seric 			*bp = toupper(*bp);
3574375Seric 			while (*bp != '\0')
3584375Seric 				bp++;
3594375Seric 			p++;
3604375Seric 		}
3614375Seric 		else
3624375Seric 			*bp++ = *p++;
3634375Seric 	}
3644375Seric 	*bp = '\0';
3654375Seric }
3664375Seric /*
3674538Seric **  SAFEFILE -- return true if a file exists and is safe for a user.
3684538Seric **
3694538Seric **	Parameters:
3704538Seric **		fn -- filename to check.
3714538Seric **		uid -- uid to compare against.
3724538Seric **		mode -- mode bits that must match.
3734538Seric **
3744538Seric **	Returns:
3754538Seric **		TRUE if fn exists, is owned by uid, and matches mode.
3764538Seric **		FALSE otherwise.
3774538Seric **
3784538Seric **	Side Effects:
3794538Seric **		none.
3804538Seric */
3814538Seric 
3824538Seric bool
3834538Seric safefile(fn, uid, mode)
3844538Seric 	char *fn;
3854538Seric 	int uid;
3864538Seric 	int mode;
3874538Seric {
3884538Seric 	struct stat stbuf;
3894538Seric 
3904538Seric 	if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid &&
3914538Seric 	    (stbuf.st_mode & mode) == mode)
3924538Seric 		return (TRUE);
39311936Seric 	errno = 0;
3944538Seric 	return (FALSE);
3954538Seric }
3964538Seric /*
3974557Seric **  FIXCRLF -- fix <CR><LF> in line.
3984557Seric **
3994557Seric **	Looks for the <CR><LF> combination and turns it into the
4004557Seric **	UNIX canonical <NL> character.  It only takes one line,
4014557Seric **	i.e., it is assumed that the first <NL> found is the end
4024557Seric **	of the line.
4034557Seric **
4044557Seric **	Parameters:
4054557Seric **		line -- the line to fix.
4064557Seric **		stripnl -- if true, strip the newline also.
4074557Seric **
4084557Seric **	Returns:
4094557Seric **		none.
4104557Seric **
4114557Seric **	Side Effects:
4124557Seric **		line is changed in place.
4134557Seric */
4144557Seric 
4154557Seric fixcrlf(line, stripnl)
4164557Seric 	char *line;
4174557Seric 	bool stripnl;
4184557Seric {
4194557Seric 	register char *p;
4204557Seric 
4214557Seric 	p = index(line, '\n');
4224557Seric 	if (p == NULL)
4234557Seric 		return;
42436291Sbostic 	if (p > line && p[-1] == '\r')
4254557Seric 		p--;
4264557Seric 	if (!stripnl)
4274557Seric 		*p++ = '\n';
4284557Seric 	*p = '\0';
4294557Seric }
4304557Seric /*
4316890Seric **  DFOPEN -- determined file open
4326890Seric **
4336890Seric **	This routine has the semantics of fopen, except that it will
4346890Seric **	keep trying a few times to make this happen.  The idea is that
4356890Seric **	on very loaded systems, we may run out of resources (inodes,
4366890Seric **	whatever), so this tries to get around it.
4376890Seric */
4386890Seric 
4396890Seric FILE *
4406890Seric dfopen(filename, mode)
4416890Seric 	char *filename;
4426890Seric 	char *mode;
4436890Seric {
4446890Seric 	register int tries;
4456890Seric 	register FILE *fp;
4466890Seric 
4476890Seric 	for (tries = 0; tries < 10; tries++)
4486890Seric 	{
44925618Seric 		sleep((unsigned) (10 * tries));
4506890Seric 		errno = 0;
4516890Seric 		fp = fopen(filename, mode);
4529376Seric 		if (fp != NULL)
4536890Seric 			break;
4549376Seric 		if (errno != ENFILE && errno != EINTR)
4559376Seric 			break;
4566890Seric 	}
45711936Seric 	errno = 0;
4586890Seric 	return (fp);
4596890Seric }
4607124Seric /*
4617124Seric **  PUTLINE -- put a line like fputs obeying SMTP conventions
4627124Seric **
4637753Seric **	This routine always guarantees outputing a newline (or CRLF,
4647753Seric **	as appropriate) at the end of the string.
4657753Seric **
4667124Seric **	Parameters:
4677124Seric **		l -- line to put.
4687124Seric **		fp -- file to put it onto.
46910172Seric **		m -- the mailer used to control output.
4707124Seric **
4717124Seric **	Returns:
4727124Seric **		none
4737124Seric **
4747124Seric **	Side Effects:
4757124Seric **		output of l to fp.
4767124Seric */
4777124Seric 
47810172Seric putline(l, fp, m)
4797753Seric 	register char *l;
4807124Seric 	FILE *fp;
48110172Seric 	MAILER *m;
4827124Seric {
4837124Seric 	register char *p;
48447157Sbostic 	register char svchar;
4857124Seric 
48611275Seric 	/* strip out 0200 bits -- these can look like TELNET protocol */
48752106Seric 	if (bitnset(M_7BITS, m->m_flags))
48811275Seric 	{
48947157Sbostic 		for (p = l; svchar = *p; ++p)
49047157Sbostic 			if (svchar & 0200)
49147157Sbostic 				*p = svchar &~ 0200;
49211275Seric 	}
49311275Seric 
4947753Seric 	do
4957124Seric 	{
4967753Seric 		/* find the end of the line */
4977753Seric 		p = index(l, '\n');
4987753Seric 		if (p == NULL)
4997753Seric 			p = &l[strlen(l)];
5007124Seric 
5017753Seric 		/* check for line overflow */
50252106Seric 		while (m->m_linelimit > 0 && (p - l) > m->m_linelimit)
5037753Seric 		{
50452106Seric 			register char *q = &l[m->m_linelimit - 1];
5057124Seric 
5067753Seric 			svchar = *q;
5077753Seric 			*q = '\0';
50810685Seric 			if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
50923105Seric 				(void) putc('.', fp);
5107753Seric 			fputs(l, fp);
51123105Seric 			(void) putc('!', fp);
51210326Seric 			fputs(m->m_eol, fp);
5137753Seric 			*q = svchar;
5147753Seric 			l = q;
5157753Seric 		}
5167124Seric 
5177753Seric 		/* output last part */
51810685Seric 		if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
51923105Seric 			(void) putc('.', fp);
52047157Sbostic 		for ( ; l < p; ++l)
52147157Sbostic 			(void) putc(*l, fp);
52210326Seric 		fputs(m->m_eol, fp);
5237753Seric 		if (*l == '\n')
52447157Sbostic 			++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;
58346928Sbostic 	static int 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",
59340998Sbostic 			    RealHostName? RealHostName: "local");
59436233Skarels # endif
59536230Skarels 			errno = 0;
59640964Sbostic 			usrerr("451 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 	}
62352106Seric 	if (!EightBit)
62452106Seric 		for (p = buf; *p != '\0'; p++)
62552106Seric 			*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;
67552647Seric 		else if (n == 0)
67652647Seric 			nmessage(Arpa_Info, "warning: line truncated");
67717350Seric 		if (i == '\n')
67817350Seric 		{
67917350Seric 			LineNumber++;
68017350Seric 			i = getc(f);
68117350Seric 			if (i != EOF)
68223105Seric 				(void) ungetc(i, f);
68317350Seric 			if (i != ' ' && i != '\t')
68452647Seric 				break;
68517350Seric 		}
6867786Seric 	}
68752647Seric 	if (p == buf)
68852647Seric 		return (NULL);
68952647Seric 	*--p = '\0';
69052647Seric 	return (buf);
6917786Seric }
6927860Seric /*
6937886Seric **  CURTIME -- return current time.
6947886Seric **
6957886Seric **	Parameters:
6967886Seric **		none.
6977886Seric **
6987886Seric **	Returns:
6997886Seric **		the current time.
7007886Seric **
7017886Seric **	Side Effects:
7027886Seric **		none.
7037886Seric */
7047886Seric 
7057886Seric time_t
7067886Seric curtime()
7077886Seric {
7087886Seric 	auto time_t t;
7097886Seric 
7107886Seric 	(void) time(&t);
7117886Seric 	return (t);
7127886Seric }
7138264Seric /*
7148264Seric **  ATOBOOL -- convert a string representation to boolean.
7158264Seric **
7168264Seric **	Defaults to "TRUE"
7178264Seric **
7188264Seric **	Parameters:
7198264Seric **		s -- string to convert.  Takes "tTyY" as true,
7208264Seric **			others as false.
7218264Seric **
7228264Seric **	Returns:
7238264Seric **		A boolean representation of the string.
7248264Seric **
7258264Seric **	Side Effects:
7268264Seric **		none.
7278264Seric */
7288264Seric 
7298264Seric bool
7308264Seric atobool(s)
7318264Seric 	register char *s;
7328264Seric {
7338264Seric 	if (*s == '\0' || index("tTyY", *s) != NULL)
7348264Seric 		return (TRUE);
7358264Seric 	return (FALSE);
7368264Seric }
7379048Seric /*
7389048Seric **  ATOOCT -- convert a string representation to octal.
7399048Seric **
7409048Seric **	Parameters:
7419048Seric **		s -- string to convert.
7429048Seric **
7439048Seric **	Returns:
7449048Seric **		An integer representing the string interpreted as an
7459048Seric **		octal number.
7469048Seric **
7479048Seric **	Side Effects:
7489048Seric **		none.
7499048Seric */
7509048Seric 
7519048Seric atooct(s)
7529048Seric 	register char *s;
7539048Seric {
7549048Seric 	register int i = 0;
7559048Seric 
7569048Seric 	while (*s >= '0' && *s <= '7')
7579048Seric 		i = (i << 3) | (*s++ - '0');
7589048Seric 	return (i);
7599048Seric }
7609376Seric /*
7619376Seric **  WAITFOR -- wait for a particular process id.
7629376Seric **
7639376Seric **	Parameters:
7649376Seric **		pid -- process id to wait for.
7659376Seric **
7669376Seric **	Returns:
7679376Seric **		status of pid.
7689376Seric **		-1 if pid never shows up.
7699376Seric **
7709376Seric **	Side Effects:
7719376Seric **		none.
7729376Seric */
7739376Seric 
7749376Seric waitfor(pid)
7759376Seric 	int pid;
7769376Seric {
7779376Seric 	auto int st;
7789376Seric 	int i;
7799376Seric 
7809376Seric 	do
7819376Seric 	{
7829376Seric 		errno = 0;
7839376Seric 		i = wait(&st);
7849376Seric 	} while ((i >= 0 || errno == EINTR) && i != pid);
7859376Seric 	if (i < 0)
7869376Seric 		st = -1;
7879376Seric 	return (st);
7889376Seric }
7899376Seric /*
79010685Seric **  BITINTERSECT -- tell if two bitmaps intersect
79110685Seric **
79210685Seric **	Parameters:
79310685Seric **		a, b -- the bitmaps in question
79410685Seric **
79510685Seric **	Returns:
79610685Seric **		TRUE if they have a non-null intersection
79710685Seric **		FALSE otherwise
79810685Seric **
79910685Seric **	Side Effects:
80010685Seric **		none.
80110685Seric */
80210685Seric 
80310685Seric bool
80410685Seric bitintersect(a, b)
80510685Seric 	BITMAP a;
80610685Seric 	BITMAP b;
80710685Seric {
80810685Seric 	int i;
80910685Seric 
81010685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
81110685Seric 		if ((a[i] & b[i]) != 0)
81210685Seric 			return (TRUE);
81310685Seric 	return (FALSE);
81410685Seric }
81510685Seric /*
81610685Seric **  BITZEROP -- tell if a bitmap is all zero
81710685Seric **
81810685Seric **	Parameters:
81910685Seric **		map -- the bit map to check
82010685Seric **
82110685Seric **	Returns:
82210685Seric **		TRUE if map is all zero.
82310685Seric **		FALSE if there are any bits set in map.
82410685Seric **
82510685Seric **	Side Effects:
82610685Seric **		none.
82710685Seric */
82810685Seric 
82910685Seric bool
83010685Seric bitzerop(map)
83110685Seric 	BITMAP map;
83210685Seric {
83310685Seric 	int i;
83410685Seric 
83510685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
83610685Seric 		if (map[i] != 0)
83710685Seric 			return (FALSE);
83810685Seric 	return (TRUE);
83910685Seric }
840