xref: /csrg-svn/usr.sbin/sendmail/src/util.c (revision 58332)
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*58332Seric static char sccsid[] = "@(#)util.c	6.10 (Berkeley) 03/01/93";
1133731Sbostic #endif /* not lint */
1222717Sdist 
13*58332Seric # include "sendmail.h"
144538Seric # include <sys/stat.h>
15298Seric # include <sysexits.h>
1657135Seric /*
17298Seric **  STRIPQUOTES -- Strip quotes & quote bits from a string.
18298Seric **
19298Seric **	Runs through a string and strips off unquoted quote
20298Seric **	characters and quote bits.  This is done in place.
21298Seric **
22298Seric **	Parameters:
23298Seric **		s -- the string to strip.
24298Seric **
25298Seric **	Returns:
26298Seric **		none.
27298Seric **
28298Seric **	Side Effects:
29298Seric **		none.
30298Seric **
31298Seric **	Called By:
32298Seric **		deliver
33298Seric */
34298Seric 
3554983Seric stripquotes(s)
36298Seric 	char *s;
37298Seric {
38298Seric 	register char *p;
39298Seric 	register char *q;
40298Seric 	register char c;
41298Seric 
424101Seric 	if (s == NULL)
434101Seric 		return;
444101Seric 
4554983Seric 	p = q = s;
4654983Seric 	do
47298Seric 	{
4854983Seric 		c = *p++;
4954983Seric 		if (c == '\\')
5054983Seric 			c = *p++;
5154983Seric 		else if (c == '"')
5254983Seric 			continue;
5354983Seric 		*q++ = c;
5454983Seric 	} while (c != '\0');
55298Seric }
56298Seric /*
572900Seric **  CAPITALIZE -- return a copy of a string, properly capitalized.
582900Seric **
592900Seric **	Parameters:
602900Seric **		s -- the string to capitalize.
612900Seric **
622900Seric **	Returns:
632900Seric **		a pointer to a properly capitalized string.
642900Seric **
652900Seric **	Side Effects:
662900Seric **		none.
672900Seric */
682900Seric 
692900Seric char *
702900Seric capitalize(s)
712900Seric 	register char *s;
722900Seric {
732900Seric 	static char buf[50];
742900Seric 	register char *p;
752900Seric 
762900Seric 	p = buf;
772900Seric 
782900Seric 	for (;;)
792900Seric 	{
8058050Seric 		while (!(isascii(*s) && isalpha(*s)) && *s != '\0')
812900Seric 			*p++ = *s++;
822900Seric 		if (*s == '\0')
832900Seric 			break;
8440999Sbostic 		*p++ = toupper(*s);
8540999Sbostic 		s++;
8658050Seric 		while (isascii(*s) && isalpha(*s))
872900Seric 			*p++ = *s++;
882900Seric 	}
892900Seric 
902900Seric 	*p = '\0';
912900Seric 	return (buf);
922900Seric }
932900Seric /*
94298Seric **  XALLOC -- Allocate memory and bitch wildly on failure.
95298Seric **
96298Seric **	THIS IS A CLUDGE.  This should be made to give a proper
97298Seric **	error -- but after all, what can we do?
98298Seric **
99298Seric **	Parameters:
100298Seric **		sz -- size of area to allocate.
101298Seric **
102298Seric **	Returns:
103298Seric **		pointer to data region.
104298Seric **
105298Seric **	Side Effects:
106298Seric **		Memory is allocated.
107298Seric */
108298Seric 
109298Seric char *
110298Seric xalloc(sz)
1117007Seric 	register int sz;
112298Seric {
113298Seric 	register char *p;
114298Seric 
11523121Seric 	p = malloc((unsigned) sz);
116298Seric 	if (p == NULL)
117298Seric 	{
118298Seric 		syserr("Out of memory!!");
11910685Seric 		abort();
12010685Seric 		/* exit(EX_UNAVAILABLE); */
121298Seric 	}
122298Seric 	return (p);
123298Seric }
124298Seric /*
1253151Seric **  COPYPLIST -- copy list of pointers.
1263151Seric **
1273151Seric **	This routine is the equivalent of newstr for lists of
1283151Seric **	pointers.
1293151Seric **
1303151Seric **	Parameters:
1313151Seric **		list -- list of pointers to copy.
1323151Seric **			Must be NULL terminated.
1333151Seric **		copycont -- if TRUE, copy the contents of the vector
1343151Seric **			(which must be a string) also.
1353151Seric **
1363151Seric **	Returns:
1373151Seric **		a copy of 'list'.
1383151Seric **
1393151Seric **	Side Effects:
1403151Seric **		none.
1413151Seric */
1423151Seric 
1433151Seric char **
1443151Seric copyplist(list, copycont)
1453151Seric 	char **list;
1463151Seric 	bool copycont;
1473151Seric {
1483151Seric 	register char **vp;
1493151Seric 	register char **newvp;
1503151Seric 
1513151Seric 	for (vp = list; *vp != NULL; vp++)
1523151Seric 		continue;
1533151Seric 
1543151Seric 	vp++;
1553151Seric 
15616897Seric 	newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
15716897Seric 	bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
1583151Seric 
1593151Seric 	if (copycont)
1603151Seric 	{
1613151Seric 		for (vp = newvp; *vp != NULL; vp++)
1623151Seric 			*vp = newstr(*vp);
1633151Seric 	}
1643151Seric 
1653151Seric 	return (newvp);
1663151Seric }
1673151Seric /*
16858170Seric **  COPYQUEUE -- copy address queue.
16958170Seric **
17058170Seric **	This routine is the equivalent of newstr for address queues
17158170Seric **	addresses marked with QDONTSEND aren't copied
17258170Seric **
17358170Seric **	Parameters:
17458170Seric **		addr -- list of address structures to copy.
17558170Seric **
17658170Seric **	Returns:
17758170Seric **		a copy of 'addr'.
17858170Seric **
17958170Seric **	Side Effects:
18058170Seric **		none.
18158170Seric */
18258170Seric 
18358170Seric ADDRESS *
18458170Seric copyqueue(addr)
18558170Seric 	ADDRESS *addr;
18658170Seric {
18758170Seric 	register ADDRESS *newaddr;
18858170Seric 	ADDRESS *ret;
18958170Seric 	register ADDRESS **tail = &ret;
19058170Seric 
19158170Seric 	while (addr != NULL)
19258170Seric 	{
19358170Seric 		if (!bitset(QDONTSEND, addr->q_flags))
19458170Seric 		{
19558170Seric 			newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS));
19658170Seric 			STRUCTCOPY(*addr, *newaddr);
19758170Seric 			*tail = newaddr;
19858170Seric 			tail = &newaddr->q_next;
19958170Seric 		}
20058170Seric 		addr = addr->q_next;
20158170Seric 	}
20258170Seric 	*tail = NULL;
20358170Seric 
20458170Seric 	return ret;
20558170Seric }
20658170Seric /*
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 {
24958050Seric 	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 {
26758050Seric 	register int c;
26851781Seric 	register struct metamac *mp;
26951781Seric 	extern struct metamac MetaMacros[];
2703151Seric 
2718055Seric 	if (s == NULL)
2728055Seric 	{
2738055Seric 		printf("<null>");
2748055Seric 		return;
2758055Seric 	}
27658050Seric 	while ((c = (*s++ & 0377)) != '\0')
2773151Seric 	{
2783151Seric 		if (!isascii(c))
2793151Seric 		{
28058050Seric 			if (c == MATCHREPL || c == MACROEXPAND)
28158050Seric 			{
28258050Seric 				putchar('$');
28358050Seric 				continue;
28458050Seric 			}
28558050Seric 			for (mp = MetaMacros; mp->metaname != '\0'; mp++)
28658050Seric 			{
28758050Seric 				if ((mp->metaval & 0377) == c)
28858050Seric 				{
28958050Seric 					printf("$%c", mp->metaname);
29058050Seric 					break;
29158050Seric 				}
29258050Seric 			}
29358050Seric 			if (mp->metaname != '\0')
29458050Seric 				continue;
29523105Seric 			(void) putchar('\\');
2963151Seric 			c &= 0177;
2973151Seric 		}
29857589Seric 		if (isprint(c))
2993151Seric 		{
30057589Seric 			putchar(c);
30157589Seric 			continue;
30257589Seric 		}
30352050Seric 
30457589Seric 		/* wasn't a meta-macro -- find another way to print it */
30557589Seric 		switch (c)
30657589Seric 		{
30757589Seric 		  case '\0':
30857589Seric 			continue;
30952050Seric 
31057589Seric 		  case '\n':
31157589Seric 			c = 'n';
31257589Seric 			break;
31352050Seric 
31457589Seric 		  case '\r':
31557589Seric 			c = 'r';
31657589Seric 			break;
31752637Seric 
31857589Seric 		  case '\t':
31957589Seric 			c = 't';
32057589Seric 			break;
32157589Seric 
32257589Seric 		  default:
32357589Seric 			(void) putchar('^');
32457589Seric 			(void) putchar(c ^ 0100);
32557589Seric 			continue;
3263151Seric 		}
3273151Seric 	}
3284086Seric 	(void) fflush(stdout);
3293151Seric }
3303151Seric /*
3313151Seric **  MAKELOWER -- Translate a line into lower case
3323151Seric **
3333151Seric **	Parameters:
3343151Seric **		p -- the string to translate.  If NULL, return is
3353151Seric **			immediate.
3363151Seric **
3373151Seric **	Returns:
3383151Seric **		none.
3393151Seric **
3403151Seric **	Side Effects:
3413151Seric **		String pointed to by p is translated to lower case.
3423151Seric **
3433151Seric **	Called By:
3443151Seric **		parse
3453151Seric */
3463151Seric 
3473151Seric makelower(p)
3483151Seric 	register char *p;
3493151Seric {
3503151Seric 	register char c;
3513151Seric 
3523151Seric 	if (p == NULL)
3533151Seric 		return;
3543151Seric 	for (; (c = *p) != '\0'; p++)
3553151Seric 		if (isascii(c) && isupper(c))
35633724Sbostic 			*p = tolower(c);
3573151Seric }
3584059Seric /*
3595196Seric **  BUILDFNAME -- build full name from gecos style entry.
3604375Seric **
3615196Seric **	This routine interprets the strange entry that would appear
3625196Seric **	in the GECOS field of the password file.
3635196Seric **
3644375Seric **	Parameters:
3655196Seric **		p -- name to build.
3665196Seric **		login -- the login name of this user (for &).
3675196Seric **		buf -- place to put the result.
3684375Seric **
3694375Seric **	Returns:
3704375Seric **		none.
3714375Seric **
3724375Seric **	Side Effects:
3734375Seric **		none.
3744375Seric */
3754375Seric 
37654984Seric buildfname(gecos, login, buf)
37754984Seric 	register char *gecos;
3785196Seric 	char *login;
3794375Seric 	char *buf;
3804375Seric {
38154984Seric 	register char *p;
3824375Seric 	register char *bp = buf;
38354984Seric 	int l;
3844375Seric 
38554984Seric 	if (*gecos == '*')
38654984Seric 		gecos++;
38754984Seric 
38857123Seric 	/* find length of final string */
38954984Seric 	l = 0;
39054984Seric 	for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
39154984Seric 	{
39254984Seric 		if (*p == '&')
39354984Seric 			l += strlen(login);
39454984Seric 		else
39554984Seric 			l++;
39654984Seric 	}
39754984Seric 
39854984Seric 	/* now fill in buf */
39955193Seric 	for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
4004375Seric 	{
4014375Seric 		if (*p == '&')
4024375Seric 		{
4035196Seric 			(void) strcpy(bp, login);
4044375Seric 			*bp = toupper(*bp);
4054375Seric 			while (*bp != '\0')
4064375Seric 				bp++;
4074375Seric 		}
4084375Seric 		else
40955193Seric 			*bp++ = *p;
4104375Seric 	}
4114375Seric 	*bp = '\0';
4124375Seric }
4134375Seric /*
4144538Seric **  SAFEFILE -- return true if a file exists and is safe for a user.
4154538Seric **
4164538Seric **	Parameters:
4174538Seric **		fn -- filename to check.
4184538Seric **		uid -- uid to compare against.
4194538Seric **		mode -- mode bits that must match.
4204538Seric **
4214538Seric **	Returns:
42258247Seric **		0 if fn exists, is owned by uid, and matches mode.
42358247Seric **		An errno otherwise.  The actual errno is cleared.
4244538Seric **
4254538Seric **	Side Effects:
4264538Seric **		none.
4274538Seric */
4284538Seric 
42958247Seric int
4304538Seric safefile(fn, uid, mode)
4314538Seric 	char *fn;
43255372Seric 	uid_t uid;
4334538Seric 	int mode;
4344538Seric {
4354538Seric 	struct stat stbuf;
4364538Seric 
43758247Seric 	if (stat(fn, &stbuf) < 0)
43858247Seric 	{
43958247Seric 		int ret = errno;
44058247Seric 
44158247Seric 		errno = 0;
44258247Seric 		return ret;
44358247Seric 	}
44458247Seric 	if (stbuf.st_uid == uid && (stbuf.st_mode & mode) == mode)
44558247Seric 		return 0;
44658247Seric 	return EPERM;
4474538Seric }
4484538Seric /*
4494557Seric **  FIXCRLF -- fix <CR><LF> in line.
4504557Seric **
4514557Seric **	Looks for the <CR><LF> combination and turns it into the
4524557Seric **	UNIX canonical <NL> character.  It only takes one line,
4534557Seric **	i.e., it is assumed that the first <NL> found is the end
4544557Seric **	of the line.
4554557Seric **
4564557Seric **	Parameters:
4574557Seric **		line -- the line to fix.
4584557Seric **		stripnl -- if true, strip the newline also.
4594557Seric **
4604557Seric **	Returns:
4614557Seric **		none.
4624557Seric **
4634557Seric **	Side Effects:
4644557Seric **		line is changed in place.
4654557Seric */
4664557Seric 
4674557Seric fixcrlf(line, stripnl)
4684557Seric 	char *line;
4694557Seric 	bool stripnl;
4704557Seric {
4714557Seric 	register char *p;
4724557Seric 
47356795Seric 	p = strchr(line, '\n');
4744557Seric 	if (p == NULL)
4754557Seric 		return;
47636291Sbostic 	if (p > line && p[-1] == '\r')
4774557Seric 		p--;
4784557Seric 	if (!stripnl)
4794557Seric 		*p++ = '\n';
4804557Seric 	*p = '\0';
4814557Seric }
4824557Seric /*
4836890Seric **  DFOPEN -- determined file open
4846890Seric **
4856890Seric **	This routine has the semantics of fopen, except that it will
4866890Seric **	keep trying a few times to make this happen.  The idea is that
4876890Seric **	on very loaded systems, we may run out of resources (inodes,
4886890Seric **	whatever), so this tries to get around it.
4896890Seric */
4906890Seric 
4916890Seric FILE *
4926890Seric dfopen(filename, mode)
4936890Seric 	char *filename;
4946890Seric 	char *mode;
4956890Seric {
4966890Seric 	register int tries;
4976890Seric 	register FILE *fp;
4986890Seric 
4996890Seric 	for (tries = 0; tries < 10; tries++)
5006890Seric 	{
50125618Seric 		sleep((unsigned) (10 * tries));
5026890Seric 		errno = 0;
5036890Seric 		fp = fopen(filename, mode);
5049376Seric 		if (fp != NULL)
5056890Seric 			break;
5069376Seric 		if (errno != ENFILE && errno != EINTR)
5079376Seric 			break;
5086890Seric 	}
50956328Seric 	if (fp != NULL)
51056328Seric 	{
51156328Seric #ifdef FLOCK
51256328Seric 		int locktype;
51356328Seric 
51456328Seric 		/* lock the file to avoid accidental conflicts */
51556328Seric 		if (*mode == 'w' || *mode == 'a')
51656328Seric 			locktype = LOCK_EX;
51756328Seric 		else
51856328Seric 			locktype = LOCK_SH;
51956328Seric 		(void) flock(fileno(fp), locktype);
52056328Seric #endif
52156328Seric 		errno = 0;
52256328Seric 	}
5236890Seric 	return (fp);
5246890Seric }
5257124Seric /*
5267124Seric **  PUTLINE -- put a line like fputs obeying SMTP conventions
5277124Seric **
5287753Seric **	This routine always guarantees outputing a newline (or CRLF,
5297753Seric **	as appropriate) at the end of the string.
5307753Seric **
5317124Seric **	Parameters:
5327124Seric **		l -- line to put.
5337124Seric **		fp -- file to put it onto.
53410172Seric **		m -- the mailer used to control output.
5357124Seric **
5367124Seric **	Returns:
5377124Seric **		none
5387124Seric **
5397124Seric **	Side Effects:
5407124Seric **		output of l to fp.
5417124Seric */
5427124Seric 
54310172Seric putline(l, fp, m)
5447753Seric 	register char *l;
5457124Seric 	FILE *fp;
54610172Seric 	MAILER *m;
5477124Seric {
5487124Seric 	register char *p;
54947157Sbostic 	register char svchar;
5507124Seric 
55111275Seric 	/* strip out 0200 bits -- these can look like TELNET protocol */
55252106Seric 	if (bitnset(M_7BITS, m->m_flags))
55311275Seric 	{
55447157Sbostic 		for (p = l; svchar = *p; ++p)
55547157Sbostic 			if (svchar & 0200)
55647157Sbostic 				*p = svchar &~ 0200;
55711275Seric 	}
55811275Seric 
5597753Seric 	do
5607124Seric 	{
5617753Seric 		/* find the end of the line */
56256795Seric 		p = strchr(l, '\n');
5637753Seric 		if (p == NULL)
5647753Seric 			p = &l[strlen(l)];
5657124Seric 
5667753Seric 		/* check for line overflow */
56752106Seric 		while (m->m_linelimit > 0 && (p - l) > m->m_linelimit)
5687753Seric 		{
56952106Seric 			register char *q = &l[m->m_linelimit - 1];
5707124Seric 
5717753Seric 			svchar = *q;
5727753Seric 			*q = '\0';
57310685Seric 			if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
57423105Seric 				(void) putc('.', fp);
5757753Seric 			fputs(l, fp);
57623105Seric 			(void) putc('!', fp);
57710326Seric 			fputs(m->m_eol, fp);
5787753Seric 			*q = svchar;
5797753Seric 			l = q;
5807753Seric 		}
5817124Seric 
5827753Seric 		/* output last part */
58310685Seric 		if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
58423105Seric 			(void) putc('.', fp);
58547157Sbostic 		for ( ; l < p; ++l)
58647157Sbostic 			(void) putc(*l, fp);
58710326Seric 		fputs(m->m_eol, fp);
5887753Seric 		if (*l == '\n')
58947157Sbostic 			++l;
5907753Seric 	} while (l[0] != '\0');
5917124Seric }
5927676Seric /*
5937676Seric **  XUNLINK -- unlink a file, doing logging as appropriate.
5947676Seric **
5957676Seric **	Parameters:
5967676Seric **		f -- name of file to unlink.
5977676Seric **
5987676Seric **	Returns:
5997676Seric **		none.
6007676Seric **
6017676Seric **	Side Effects:
6027676Seric **		f is unlinked.
6037676Seric */
6047676Seric 
6057676Seric xunlink(f)
6067676Seric 	char *f;
6077676Seric {
6087676Seric 	register int i;
6097676Seric 
6107676Seric # ifdef LOG
61158020Seric 	if (LogLevel > 98)
61258020Seric 		syslog(LOG_DEBUG, "%s: unlink %s", CurEnv->e_id, f);
61356795Seric # endif /* LOG */
6147676Seric 
6157676Seric 	i = unlink(f);
6167676Seric # ifdef LOG
61758020Seric 	if (i < 0 && LogLevel > 97)
6187942Seric 		syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno);
61956795Seric # endif /* LOG */
6207676Seric }
6217685Seric /*
62214885Seric **  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
6237685Seric **
6247685Seric **	Parameters:
6257685Seric **		buf -- place to put the input line.
6267685Seric **		siz -- size of buf.
6277685Seric **		fp -- file to read from.
62857384Seric **		timeout -- the timeout before error occurs.
6297685Seric **
6307685Seric **	Returns:
63115533Seric **		NULL on error (including timeout).  This will also leave
63215533Seric **			buf containing a null string.
6337685Seric **		buf otherwise.
6347685Seric **
6357685Seric **	Side Effects:
6367685Seric **		none.
6377685Seric */
6387685Seric 
63914885Seric static jmp_buf	CtxReadTimeout;
6407685Seric 
6417685Seric char *
64257384Seric sfgets(buf, siz, fp, timeout)
6437685Seric 	char *buf;
6447685Seric 	int siz;
6457685Seric 	FILE *fp;
64657384Seric 	time_t timeout;
6477685Seric {
6487942Seric 	register EVENT *ev = NULL;
6497685Seric 	register char *p;
65046928Sbostic 	static int readtimeout();
6517685Seric 
65214885Seric 	/* set the timeout */
65357384Seric 	if (timeout != 0)
65414885Seric 	{
65514885Seric 		if (setjmp(CtxReadTimeout) != 0)
65614885Seric 		{
65736233Skarels # ifdef LOG
65836230Skarels 			syslog(LOG_NOTICE,
65936230Skarels 			    "timeout waiting for input from %s\n",
66057642Seric 			    CurHostName? CurHostName: "local");
66136233Skarels # endif
66236230Skarels 			errno = 0;
66340964Sbostic 			usrerr("451 timeout waiting for input");
66419037Seric 			buf[0] = '\0';
66514885Seric 			return (NULL);
66614885Seric 		}
66757384Seric 		ev = setevent(timeout, readtimeout, 0);
66814885Seric 	}
66914885Seric 
67014885Seric 	/* try to read */
67115533Seric 	p = NULL;
67215533Seric 	while (p == NULL && !feof(fp) && !ferror(fp))
6737942Seric 	{
6747942Seric 		errno = 0;
6757942Seric 		p = fgets(buf, siz, fp);
67615533Seric 		if (errno == EINTR)
67715533Seric 			clearerr(fp);
67815533Seric 	}
67914885Seric 
68014885Seric 	/* clear the event if it has not sprung */
6817685Seric 	clrevent(ev);
68214885Seric 
68314885Seric 	/* clean up the books and exit */
6848055Seric 	LineNumber++;
68515533Seric 	if (p == NULL)
68616880Seric 	{
68715533Seric 		buf[0] = '\0';
68816880Seric 		return (NULL);
68916880Seric 	}
69052106Seric 	if (!EightBit)
69152106Seric 		for (p = buf; *p != '\0'; p++)
69252106Seric 			*p &= ~0200;
69316880Seric 	return (buf);
6947685Seric }
6957685Seric 
6967685Seric static
6977685Seric readtimeout()
6987685Seric {
69914885Seric 	longjmp(CtxReadTimeout, 1);
7007685Seric }
7017786Seric /*
7027786Seric **  FGETFOLDED -- like fgets, but know about folded lines.
7037786Seric **
7047786Seric **	Parameters:
7057786Seric **		buf -- place to put result.
7067786Seric **		n -- bytes available.
7077786Seric **		f -- file to read from.
7087786Seric **
7097786Seric **	Returns:
71057135Seric **		input line(s) on success, NULL on error or EOF.
71157135Seric **		This will normally be buf -- unless the line is too
71257135Seric **			long, when it will be xalloc()ed.
7137786Seric **
7147786Seric **	Side Effects:
7157786Seric **		buf gets lines from f, with continuation lines (lines
7167786Seric **		with leading white space) appended.  CRLF's are mapped
7177786Seric **		into single newlines.  Any trailing NL is stripped.
7187786Seric */
7197786Seric 
7207786Seric char *
7217786Seric fgetfolded(buf, n, f)
7227786Seric 	char *buf;
7237786Seric 	register int n;
7247786Seric 	FILE *f;
7257786Seric {
7267786Seric 	register char *p = buf;
72757135Seric 	char *bp = buf;
7287786Seric 	register int i;
7297786Seric 
7307786Seric 	n--;
73117350Seric 	while ((i = getc(f)) != EOF)
7327786Seric 	{
73317350Seric 		if (i == '\r')
73417350Seric 		{
73517350Seric 			i = getc(f);
73617350Seric 			if (i != '\n')
73717350Seric 			{
73817350Seric 				if (i != EOF)
73923105Seric 					(void) ungetc(i, f);
74017350Seric 				i = '\r';
74117350Seric 			}
74217350Seric 		}
74357135Seric 		if (--n <= 0)
74457135Seric 		{
74557135Seric 			/* allocate new space */
74657135Seric 			char *nbp;
74757135Seric 			int nn;
74857135Seric 
74957135Seric 			nn = (p - bp);
75057232Seric 			if (nn < MEMCHUNKSIZE)
75157135Seric 				nn *= 2;
75257135Seric 			else
75357232Seric 				nn += MEMCHUNKSIZE;
75457135Seric 			nbp = xalloc(nn);
75557135Seric 			bcopy(bp, nbp, p - bp);
75657135Seric 			p = &nbp[p - bp];
75757135Seric 			if (bp != buf)
75857135Seric 				free(bp);
75957135Seric 			bp = nbp;
76057135Seric 			n = nn - (p - bp);
76157135Seric 		}
76257135Seric 		*p++ = i;
76317350Seric 		if (i == '\n')
76417350Seric 		{
76517350Seric 			LineNumber++;
76617350Seric 			i = getc(f);
76717350Seric 			if (i != EOF)
76823105Seric 				(void) ungetc(i, f);
76917350Seric 			if (i != ' ' && i != '\t')
77052647Seric 				break;
77117350Seric 		}
7727786Seric 	}
77357135Seric 	if (p == bp)
77452647Seric 		return (NULL);
77552647Seric 	*--p = '\0';
77657135Seric 	return (bp);
7777786Seric }
7787860Seric /*
7797886Seric **  CURTIME -- return current time.
7807886Seric **
7817886Seric **	Parameters:
7827886Seric **		none.
7837886Seric **
7847886Seric **	Returns:
7857886Seric **		the current time.
7867886Seric **
7877886Seric **	Side Effects:
7887886Seric **		none.
7897886Seric */
7907886Seric 
7917886Seric time_t
7927886Seric curtime()
7937886Seric {
7947886Seric 	auto time_t t;
7957886Seric 
7967886Seric 	(void) time(&t);
7977886Seric 	return (t);
7987886Seric }
7998264Seric /*
8008264Seric **  ATOBOOL -- convert a string representation to boolean.
8018264Seric **
8028264Seric **	Defaults to "TRUE"
8038264Seric **
8048264Seric **	Parameters:
8058264Seric **		s -- string to convert.  Takes "tTyY" as true,
8068264Seric **			others as false.
8078264Seric **
8088264Seric **	Returns:
8098264Seric **		A boolean representation of the string.
8108264Seric **
8118264Seric **	Side Effects:
8128264Seric **		none.
8138264Seric */
8148264Seric 
8158264Seric bool
8168264Seric atobool(s)
8178264Seric 	register char *s;
8188264Seric {
81956795Seric 	if (*s == '\0' || strchr("tTyY", *s) != NULL)
8208264Seric 		return (TRUE);
8218264Seric 	return (FALSE);
8228264Seric }
8239048Seric /*
8249048Seric **  ATOOCT -- convert a string representation to octal.
8259048Seric **
8269048Seric **	Parameters:
8279048Seric **		s -- string to convert.
8289048Seric **
8299048Seric **	Returns:
8309048Seric **		An integer representing the string interpreted as an
8319048Seric **		octal number.
8329048Seric **
8339048Seric **	Side Effects:
8349048Seric **		none.
8359048Seric */
8369048Seric 
8379048Seric atooct(s)
8389048Seric 	register char *s;
8399048Seric {
8409048Seric 	register int i = 0;
8419048Seric 
8429048Seric 	while (*s >= '0' && *s <= '7')
8439048Seric 		i = (i << 3) | (*s++ - '0');
8449048Seric 	return (i);
8459048Seric }
8469376Seric /*
8479376Seric **  WAITFOR -- wait for a particular process id.
8489376Seric **
8499376Seric **	Parameters:
8509376Seric **		pid -- process id to wait for.
8519376Seric **
8529376Seric **	Returns:
8539376Seric **		status of pid.
8549376Seric **		-1 if pid never shows up.
8559376Seric **
8569376Seric **	Side Effects:
8579376Seric **		none.
8589376Seric */
8599376Seric 
8609376Seric waitfor(pid)
8619376Seric 	int pid;
8629376Seric {
8639376Seric 	auto int st;
8649376Seric 	int i;
8659376Seric 
8669376Seric 	do
8679376Seric 	{
8689376Seric 		errno = 0;
8699376Seric 		i = wait(&st);
8709376Seric 	} while ((i >= 0 || errno == EINTR) && i != pid);
8719376Seric 	if (i < 0)
8729376Seric 		st = -1;
8739376Seric 	return (st);
8749376Seric }
8759376Seric /*
87610685Seric **  BITINTERSECT -- tell if two bitmaps intersect
87710685Seric **
87810685Seric **	Parameters:
87910685Seric **		a, b -- the bitmaps in question
88010685Seric **
88110685Seric **	Returns:
88210685Seric **		TRUE if they have a non-null intersection
88310685Seric **		FALSE otherwise
88410685Seric **
88510685Seric **	Side Effects:
88610685Seric **		none.
88710685Seric */
88810685Seric 
88910685Seric bool
89010685Seric bitintersect(a, b)
89110685Seric 	BITMAP a;
89210685Seric 	BITMAP b;
89310685Seric {
89410685Seric 	int i;
89510685Seric 
89610685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
89710685Seric 		if ((a[i] & b[i]) != 0)
89810685Seric 			return (TRUE);
89910685Seric 	return (FALSE);
90010685Seric }
90110685Seric /*
90210685Seric **  BITZEROP -- tell if a bitmap is all zero
90310685Seric **
90410685Seric **	Parameters:
90510685Seric **		map -- the bit map to check
90610685Seric **
90710685Seric **	Returns:
90810685Seric **		TRUE if map is all zero.
90910685Seric **		FALSE if there are any bits set in map.
91010685Seric **
91110685Seric **	Side Effects:
91210685Seric **		none.
91310685Seric */
91410685Seric 
91510685Seric bool
91610685Seric bitzerop(map)
91710685Seric 	BITMAP map;
91810685Seric {
91910685Seric 	int i;
92010685Seric 
92110685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
92210685Seric 		if (map[i] != 0)
92310685Seric 			return (FALSE);
92410685Seric 	return (TRUE);
92510685Seric }
92658247Seric /*
92758318Seric **  STRCONTAINEDIN -- tell if one string is contained in another
92858318Seric **
92958318Seric **	Parameters:
93058318Seric **		a -- possible substring.
93158318Seric **		b -- possible superstring.
93258318Seric **
93358318Seric **	Returns:
93458318Seric **		TRUE if a is contained in b.
93558318Seric **		FALSE otherwise.
93658318Seric */
93758318Seric 
93858318Seric bool
93958318Seric strcontainedin(a, b)
94058318Seric 	register char *a;
94158318Seric 	register char *b;
94258318Seric {
94358318Seric 	int l;
94458318Seric 
94558318Seric 	l = strlen(a);
94658318Seric 	for (;;)
94758318Seric 	{
94858318Seric 		b = strchr(b, a[0]);
94958318Seric 		if (b == NULL)
95058318Seric 			return FALSE;
95158318Seric 		if (strncmp(a, b, l) == 0)
95258318Seric 			return TRUE;
95358318Seric 		b++;
95458318Seric 	}
95558318Seric }
95658318Seric /*
95758247Seric **  TRANSIENTERROR -- tell if an error code indicates a transient failure
95858247Seric **
95958247Seric **	This looks at an errno value and tells if this is likely to
96058247Seric **	go away if retried later.
96158247Seric **
96258247Seric **	Parameters:
96358247Seric **		err -- the errno code to classify.
96458247Seric **
96558247Seric **	Returns:
96658247Seric **		TRUE if this is probably transient.
96758247Seric **		FALSE otherwise.
96858247Seric */
96958247Seric 
97058247Seric bool
97158247Seric transienterror(err)
97258247Seric 	int err;
97358247Seric {
97458247Seric 	switch (err)
97558247Seric 	{
97658247Seric 	  case EIO:			/* I/O error */
97758247Seric 	  case ENXIO:			/* Device not configured */
97858247Seric 	  case EAGAIN:			/* Resource temporarily unavailable */
97958247Seric 	  case ENOMEM:			/* Cannot allocate memory */
98058247Seric 	  case ENODEV:			/* Operation not supported by device */
98158247Seric 	  case ENFILE:			/* Too many open files in system */
98258247Seric 	  case EMFILE:			/* Too many open files */
98358247Seric 	  case ENOSPC:			/* No space left on device */
98458247Seric #ifdef ETIMEDOUT
98558247Seric 	  case ETIMEDOUT:		/* Connection timed out */
98658247Seric #endif
98758247Seric #ifdef ESTALE
98858247Seric 	  case ESTALE:			/* Stale NFS file handle */
98958247Seric #endif
99058247Seric #ifdef ENETDOWN
99158247Seric 	  case ENETDOWN:		/* Network is down */
99258247Seric #endif
99358247Seric #ifdef ENETUNREACH
99458247Seric 	  case ENETUNREACH:		/* Network is unreachable */
99558247Seric #endif
99658247Seric #ifdef ENETRESET
99758247Seric 	  case ENETRESET:		/* Network dropped connection on reset */
99858247Seric #endif
99958247Seric #ifdef ECONNABORTED
100058247Seric 	  case ECONNABORTED:		/* Software caused connection abort */
100158247Seric #endif
100258247Seric #ifdef ECONNRESET
100358247Seric 	  case ECONNRESET:		/* Connection reset by peer */
100458247Seric #endif
100558247Seric #ifdef ENOBUFS
100658247Seric 	  case ENOBUFS:			/* No buffer space available */
100758247Seric #endif
100858247Seric #ifdef ESHUTDOWN
100958247Seric 	  case ESHUTDOWN:		/* Can't send after socket shutdown */
101058247Seric #endif
101158247Seric #ifdef ECONNREFUSED
101258247Seric 	  case ECONNREFUSED:		/* Connection refused */
101358247Seric #endif
101458247Seric #ifdef EHOSTDOWN
101558247Seric 	  case EHOSTDOWN:		/* Host is down */
101658247Seric #endif
101758247Seric #ifdef EHOSTUNREACH
101858247Seric 	  case EHOSTUNREACH:		/* No route to host */
101958247Seric #endif
102058247Seric #ifdef EDQUOT
102158247Seric 	  case EDQUOT:			/* Disc quota exceeded */
102258247Seric #endif
102358247Seric #ifdef EPROCLIM
102458247Seric 	  case EPROCLIM:		/* Too many processes */
102558247Seric #endif
102658247Seric #ifdef EUSERS
102758247Seric 	  case EUSERS:			/* Too many users */
102858247Seric #endif
102958247Seric #ifdef EDEADLK
103058247Seric 	  case EDEADLK:			/* Resource deadlock avoided */
103158247Seric #endif
103258247Seric 		return TRUE;
103358247Seric 	}
103458247Seric 
103558247Seric 	/* nope, must be permanent */
103658247Seric 	return FALSE;
103758247Seric }
1038