xref: /csrg-svn/usr.sbin/sendmail/src/util.c (revision 40964)
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*40964Sbostic static char sccsid[] = "@(#)util.c	5.15 (Berkeley) 04/18/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;
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;
41936291Sbostic 	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;
596*40964Sbostic 			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 	}
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