xref: /csrg-svn/usr.sbin/sendmail/src/util.c (revision 8063)
13151Seric # include <stdio.h>
24538Seric # include <sys/types.h>
34538Seric # include <sys/stat.h>
4298Seric # include <sysexits.h>
56890Seric # include <errno.h>
62900Seric # include <ctype.h>
76890Seric # include "sendmail.h"
8298Seric 
9*8063Seric SCCSID(@(#)util.c	3.31		09/05/82);
10409Seric 
11298Seric /*
12298Seric **  STRIPQUOTES -- Strip quotes & quote bits from a string.
13298Seric **
14298Seric **	Runs through a string and strips off unquoted quote
15298Seric **	characters and quote bits.  This is done in place.
16298Seric **
17298Seric **	Parameters:
18298Seric **		s -- the string to strip.
194101Seric **		qf -- if set, remove actual `` " '' characters
204101Seric **			as well as the quote bits.
21298Seric **
22298Seric **	Returns:
23298Seric **		none.
24298Seric **
25298Seric **	Side Effects:
26298Seric **		none.
27298Seric **
28298Seric **	Called By:
29298Seric **		deliver
30298Seric */
31298Seric 
324101Seric stripquotes(s, qf)
33298Seric 	char *s;
344101Seric 	bool qf;
35298Seric {
36298Seric 	register char *p;
37298Seric 	register char *q;
38298Seric 	register char c;
39298Seric 
404101Seric 	if (s == NULL)
414101Seric 		return;
424101Seric 
43298Seric 	for (p = q = s; (c = *p++) != '\0'; )
44298Seric 	{
454101Seric 		if (c != '"' || !qf)
46298Seric 			*q++ = c & 0177;
47298Seric 	}
48298Seric 	*q = '\0';
49298Seric }
50298Seric /*
512900Seric **  CAPITALIZE -- return a copy of a string, properly capitalized.
522900Seric **
532900Seric **	Parameters:
542900Seric **		s -- the string to capitalize.
552900Seric **
562900Seric **	Returns:
572900Seric **		a pointer to a properly capitalized string.
582900Seric **
592900Seric **	Side Effects:
602900Seric **		none.
612900Seric */
622900Seric 
632900Seric char *
642900Seric capitalize(s)
652900Seric 	register char *s;
662900Seric {
672900Seric 	static char buf[50];
682900Seric 	register char *p;
692900Seric 
702900Seric 	p = buf;
712900Seric 
722900Seric 	for (;;)
732900Seric 	{
742900Seric 		while (!isalpha(*s) && *s != '\0')
752900Seric 			*p++ = *s++;
762900Seric 		if (*s == '\0')
772900Seric 			break;
782900Seric 		*p++ = toupper(*s++);
792900Seric 		while (isalpha(*s))
802900Seric 			*p++ = *s++;
812900Seric 	}
822900Seric 
832900Seric 	*p = '\0';
842900Seric 	return (buf);
852900Seric }
862900Seric /*
87298Seric **  XALLOC -- Allocate memory and bitch wildly on failure.
88298Seric **
89298Seric **	THIS IS A CLUDGE.  This should be made to give a proper
90298Seric **	error -- but after all, what can we do?
91298Seric **
92298Seric **	Parameters:
93298Seric **		sz -- size of area to allocate.
94298Seric **
95298Seric **	Returns:
96298Seric **		pointer to data region.
97298Seric **
98298Seric **	Side Effects:
99298Seric **		Memory is allocated.
100298Seric */
101298Seric 
102298Seric char *
103298Seric xalloc(sz)
1047007Seric 	register int sz;
105298Seric {
106298Seric 	register char *p;
107298Seric 
108298Seric 	p = malloc(sz);
109298Seric 	if (p == NULL)
110298Seric 	{
111298Seric 		syserr("Out of memory!!");
1121598Seric 		exit(EX_UNAVAILABLE);
113298Seric 	}
114298Seric 	return (p);
115298Seric }
116298Seric /*
1172900Seric **  NEWSTR -- make copy of string.
1182900Seric **
1192900Seric **	Space is allocated for it using xalloc.
1202900Seric **
1212900Seric **	Parameters:
1222900Seric **		string to copy.
1232900Seric **
1242900Seric **	Returns:
1252900Seric **		pointer to new string.
1262900Seric **
1272900Seric **	Side Effects:
1282900Seric **		none.
1292900Seric */
1302900Seric 
1312900Seric char *
1322900Seric newstr(s)
1332900Seric 	register char *s;
1342900Seric {
1352900Seric 	register char *p;
1362900Seric 
1377007Seric 	p = xalloc(strlen(s) + 1);
1387007Seric 	(void) strcpy(p, s);
1392900Seric 	return (p);
1402900Seric }
1413151Seric /*
1423151Seric **  COPYPLIST -- copy list of pointers.
1433151Seric **
1443151Seric **	This routine is the equivalent of newstr for lists of
1453151Seric **	pointers.
1463151Seric **
1473151Seric **	Parameters:
1483151Seric **		list -- list of pointers to copy.
1493151Seric **			Must be NULL terminated.
1503151Seric **		copycont -- if TRUE, copy the contents of the vector
1513151Seric **			(which must be a string) also.
1523151Seric **
1533151Seric **	Returns:
1543151Seric **		a copy of 'list'.
1553151Seric **
1563151Seric **	Side Effects:
1573151Seric **		none.
1583151Seric */
1593151Seric 
1603151Seric char **
1613151Seric copyplist(list, copycont)
1623151Seric 	char **list;
1633151Seric 	bool copycont;
1643151Seric {
1653151Seric 	register char **vp;
1663151Seric 	register char **newvp;
1673151Seric 
1683151Seric 	for (vp = list; *vp != NULL; vp++)
1693151Seric 		continue;
1703151Seric 
1713151Seric 	vp++;
1723151Seric 
1737007Seric 	newvp = (char **) xalloc((vp - list) * sizeof *vp);
1744086Seric 	bmove((char *) list, (char *) newvp, (vp - list) * sizeof *vp);
1753151Seric 
1763151Seric 	if (copycont)
1773151Seric 	{
1783151Seric 		for (vp = newvp; *vp != NULL; vp++)
1793151Seric 			*vp = newstr(*vp);
1803151Seric 	}
1813151Seric 
1823151Seric 	return (newvp);
1833151Seric }
1843151Seric /*
1853151Seric **  PRINTAV -- print argument vector.
1863151Seric **
1873151Seric **	Parameters:
1883151Seric **		av -- argument vector.
1893151Seric **
1903151Seric **	Returns:
1913151Seric **		none.
1923151Seric **
1933151Seric **	Side Effects:
1943151Seric **		prints av.
1953151Seric */
1963151Seric 
1973151Seric # ifdef DEBUG
1983151Seric printav(av)
1993151Seric 	register char **av;
2003151Seric {
2013151Seric 	while (*av != NULL)
2023151Seric 	{
203*8063Seric 		if (tTd(0, 44))
204*8063Seric 			printf("\n\t%08x=", *av);
205*8063Seric 		else
206*8063Seric 			putchar(' ');
2073151Seric 		xputs(*av++);
2083151Seric 	}
209*8063Seric 	putchar('\n');
2103151Seric }
2113151Seric # endif DEBUG
2123151Seric /*
2133151Seric **  LOWER -- turn letter into lower case.
2143151Seric **
2153151Seric **	Parameters:
2163151Seric **		c -- character to turn into lower case.
2173151Seric **
2183151Seric **	Returns:
2193151Seric **		c, in lower case.
2203151Seric **
2213151Seric **	Side Effects:
2223151Seric **		none.
2233151Seric */
2243151Seric 
2253151Seric char
2263151Seric lower(c)
2273151Seric 	register char c;
2283151Seric {
2293151Seric 	if (isascii(c) && isupper(c))
2303151Seric 		c = c - 'A' + 'a';
2313151Seric 	return (c);
2323151Seric }
2333151Seric /*
2343151Seric **  XPUTS -- put string doing control escapes.
2353151Seric **
2363151Seric **	Parameters:
2373151Seric **		s -- string to put.
2383151Seric **
2393151Seric **	Returns:
2403151Seric **		none.
2413151Seric **
2423151Seric **	Side Effects:
2433151Seric **		output to stdout
2443151Seric */
2453151Seric 
2463151Seric # ifdef DEBUG
2473151Seric xputs(s)
2483151Seric 	register char *s;
2493151Seric {
2503151Seric 	register char c;
2513151Seric 
2528055Seric 	if (s == NULL)
2538055Seric 	{
2548055Seric 		printf("<null>");
2558055Seric 		return;
2568055Seric 	}
257*8063Seric 	putchar('"');
2583151Seric 	while ((c = *s++) != '\0')
2593151Seric 	{
2603151Seric 		if (!isascii(c))
2613151Seric 		{
2623151Seric 			putchar('\\');
2633151Seric 			c &= 0177;
2643151Seric 		}
2653151Seric 		if (iscntrl(c))
2663151Seric 		{
2673151Seric 			putchar('^');
2683151Seric 			c |= 0100;
2693151Seric 		}
2703151Seric 		putchar(c);
2713151Seric 	}
272*8063Seric 	putchar('"');
2734086Seric 	(void) fflush(stdout);
2743151Seric }
2753151Seric # endif DEBUG
2763151Seric /*
2773151Seric **  MAKELOWER -- Translate a line into lower case
2783151Seric **
2793151Seric **	Parameters:
2803151Seric **		p -- the string to translate.  If NULL, return is
2813151Seric **			immediate.
2823151Seric **
2833151Seric **	Returns:
2843151Seric **		none.
2853151Seric **
2863151Seric **	Side Effects:
2873151Seric **		String pointed to by p is translated to lower case.
2883151Seric **
2893151Seric **	Called By:
2903151Seric **		parse
2913151Seric */
2923151Seric 
2933151Seric makelower(p)
2943151Seric 	register char *p;
2953151Seric {
2963151Seric 	register char c;
2973151Seric 
2983151Seric 	if (p == NULL)
2993151Seric 		return;
3003151Seric 	for (; (c = *p) != '\0'; p++)
3013151Seric 		if (isascii(c) && isupper(c))
3023151Seric 			*p = c - 'A' + 'a';
3033151Seric }
3044059Seric /*
3054059Seric **  SAMEWORD -- return TRUE if the words are the same
3064059Seric **
3074059Seric **	Ignores case.
3084059Seric **
3094059Seric **	Parameters:
3104059Seric **		a, b -- the words to compare.
3114059Seric **
3124059Seric **	Returns:
3134059Seric **		TRUE if a & b match exactly (modulo case)
3144059Seric **		FALSE otherwise.
3154059Seric **
3164059Seric **	Side Effects:
3174059Seric **		none.
3184059Seric */
3194059Seric 
3204059Seric bool
3214059Seric sameword(a, b)
3224059Seric 	register char *a, *b;
3234059Seric {
3244059Seric 	while (lower(*a) == lower(*b))
3254059Seric 	{
3264059Seric 		if (*a == '\0')
3274059Seric 			return (TRUE);
3284059Seric 		a++;
3294059Seric 		b++;
3304059Seric 	}
3314059Seric 	return (FALSE);
3324059Seric }
3334086Seric /*
3344101Seric **  CLEAR -- clear a block of memory
3354101Seric **
3364101Seric **	Parameters:
3374101Seric **		p -- location to clear.
3384101Seric **		l -- number of bytes to clear.
3394101Seric **
3404101Seric **	Returns:
3414101Seric **		none.
3424101Seric **
3434101Seric **	Side Effects:
3444101Seric **		none.
3454101Seric */
3464101Seric 
3474101Seric clear(p, l)
3484101Seric 	register char *p;
3494101Seric 	register int l;
3504101Seric {
3514101Seric 	while (l-- > 0)
3524101Seric 		*p++ = 0;
3534101Seric }
3544101Seric /*
3555196Seric **  BUILDFNAME -- build full name from gecos style entry.
3564375Seric **
3575196Seric **	This routine interprets the strange entry that would appear
3585196Seric **	in the GECOS field of the password file.
3595196Seric **
3604375Seric **	Parameters:
3615196Seric **		p -- name to build.
3625196Seric **		login -- the login name of this user (for &).
3635196Seric **		buf -- place to put the result.
3644375Seric **
3654375Seric **	Returns:
3664375Seric **		none.
3674375Seric **
3684375Seric **	Side Effects:
3694375Seric **		none.
3704375Seric */
3714375Seric 
3725196Seric buildfname(p, login, buf)
3735196Seric 	register char *p;
3745196Seric 	char *login;
3754375Seric 	char *buf;
3764375Seric {
3774375Seric 	register char *bp = buf;
3784375Seric 
3794438Seric 	if (*p == '*')
3804438Seric 		p++;
3816278Seric 	while (*p != '\0' && *p != ',' && *p != ';' && *p != '%')
3824375Seric 	{
3834375Seric 		if (*p == '&')
3844375Seric 		{
3855196Seric 			(void) strcpy(bp, login);
3864375Seric 			*bp = toupper(*bp);
3874375Seric 			while (*bp != '\0')
3884375Seric 				bp++;
3894375Seric 			p++;
3904375Seric 		}
3914375Seric 		else
3924375Seric 			*bp++ = *p++;
3934375Seric 	}
3944375Seric 	*bp = '\0';
3954375Seric }
3964375Seric /*
3974538Seric **  SAFEFILE -- return true if a file exists and is safe for a user.
3984538Seric **
3994538Seric **	Parameters:
4004538Seric **		fn -- filename to check.
4014538Seric **		uid -- uid to compare against.
4024538Seric **		mode -- mode bits that must match.
4034538Seric **
4044538Seric **	Returns:
4054538Seric **		TRUE if fn exists, is owned by uid, and matches mode.
4064538Seric **		FALSE otherwise.
4074538Seric **
4084538Seric **	Side Effects:
4094538Seric **		none.
4104538Seric */
4114538Seric 
4124538Seric bool
4134538Seric safefile(fn, uid, mode)
4144538Seric 	char *fn;
4154538Seric 	int uid;
4164538Seric 	int mode;
4174538Seric {
4184538Seric 	struct stat stbuf;
4194538Seric 
4204538Seric 	if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid &&
4214538Seric 	    (stbuf.st_mode & mode) == mode)
4224538Seric 		return (TRUE);
4234538Seric 	return (FALSE);
4244538Seric }
4254538Seric /*
4264557Seric **  FIXCRLF -- fix <CR><LF> in line.
4274557Seric **
4284557Seric **	Looks for the <CR><LF> combination and turns it into the
4294557Seric **	UNIX canonical <NL> character.  It only takes one line,
4304557Seric **	i.e., it is assumed that the first <NL> found is the end
4314557Seric **	of the line.
4324557Seric **
4334557Seric **	Parameters:
4344557Seric **		line -- the line to fix.
4354557Seric **		stripnl -- if true, strip the newline also.
4364557Seric **
4374557Seric **	Returns:
4384557Seric **		none.
4394557Seric **
4404557Seric **	Side Effects:
4414557Seric **		line is changed in place.
4424557Seric */
4434557Seric 
4444557Seric fixcrlf(line, stripnl)
4454557Seric 	char *line;
4464557Seric 	bool stripnl;
4474557Seric {
4484557Seric 	register char *p;
4494557Seric 
4504557Seric 	p = index(line, '\n');
4514557Seric 	if (p == NULL)
4524557Seric 		return;
4534794Seric 	if (p[-1] == '\r')
4544557Seric 		p--;
4554557Seric 	if (!stripnl)
4564557Seric 		*p++ = '\n';
4574557Seric 	*p = '\0';
4584557Seric }
4594557Seric /*
4604086Seric **  SYSLOG -- fake entry to fool lint
4614086Seric */
4624086Seric 
4634086Seric # ifdef LOG
4644086Seric # ifdef lint
4654086Seric 
4664086Seric /*VARARGS2*/
4674086Seric syslog(pri, fmt, args)
4684086Seric 	int pri;
4694086Seric 	char *fmt;
4704086Seric {
4714086Seric 	pri = *fmt;
4724086Seric 	args = pri;
4734086Seric 	pri = args;
4744086Seric }
4754086Seric 
4764086Seric # endif lint
4774086Seric # endif LOG
4786890Seric /*
4796890Seric **  DFOPEN -- determined file open
4806890Seric **
4816890Seric **	This routine has the semantics of fopen, except that it will
4826890Seric **	keep trying a few times to make this happen.  The idea is that
4836890Seric **	on very loaded systems, we may run out of resources (inodes,
4846890Seric **	whatever), so this tries to get around it.
4856890Seric */
4866890Seric 
4876890Seric FILE *
4886890Seric dfopen(filename, mode)
4896890Seric 	char *filename;
4906890Seric 	char *mode;
4916890Seric {
4926890Seric 	register int tries;
4936890Seric 	register FILE *fp;
4946890Seric 	extern int errno;
4956890Seric 
4966890Seric 	for (tries = 0; tries < 10; tries++)
4976890Seric 	{
4986890Seric 		sleep(10 * tries);
4996890Seric 		errno = 0;
5006890Seric 		fp = fopen(filename, mode);
5016890Seric 		if (fp != NULL || errno != ENFILE)
5026890Seric 			break;
5036890Seric 	}
5046890Seric 	return (fp);
5056890Seric }
5067124Seric /*
5077124Seric **  PUTLINE -- put a line like fputs obeying SMTP conventions
5087124Seric **
5097753Seric **	This routine always guarantees outputing a newline (or CRLF,
5107753Seric **	as appropriate) at the end of the string.
5117753Seric **
5127124Seric **	Parameters:
5137124Seric **		l -- line to put.
5147124Seric **		fp -- file to put it onto.
5157124Seric **		fullsmtp -- if set, obey strictest SMTP conventions.
5167124Seric **
5177124Seric **	Returns:
5187124Seric **		none
5197124Seric **
5207124Seric **	Side Effects:
5217124Seric **		output of l to fp.
5227124Seric */
5237124Seric 
5247753Seric # define SMTPLINELIM	990	/* maximum line length */
5257124Seric 
5267124Seric putline(l, fp, fullsmtp)
5277753Seric 	register char *l;
5287124Seric 	FILE *fp;
5297124Seric 	bool fullsmtp;
5307124Seric {
5317124Seric 	register char *p;
5327753Seric 	char svchar;
5337124Seric 
5347753Seric 	do
5357124Seric 	{
5367753Seric 		/* find the end of the line */
5377753Seric 		p = index(l, '\n');
5387753Seric 		if (p == NULL)
5397753Seric 			p = &l[strlen(l)];
5407124Seric 
5417753Seric 		/* check for line overflow */
5427753Seric 		while (fullsmtp && (p - l) > SMTPLINELIM)
5437753Seric 		{
5447753Seric 			register char *q = &l[SMTPLINELIM - 1];
5457124Seric 
5467753Seric 			svchar = *q;
5477753Seric 			*q = '\0';
5487753Seric 			fputs(l, fp);
5497753Seric 			fputs("!\r\n", fp);
5507753Seric 			*q = svchar;
5517753Seric 			l = q;
5527753Seric 		}
5537124Seric 
5547753Seric 		/* output last part */
5557753Seric 		svchar = *p;
5567753Seric 		*p = '\0';
5577124Seric 		fputs(l, fp);
5587753Seric 		if (fullsmtp)
5597753Seric 			fputc('\r', fp);
5607753Seric 		fputc('\n', fp);
5617753Seric 		*p = svchar;
5627753Seric 		l = p;
5637753Seric 		if (*l == '\n')
5647753Seric 			l++;
5657753Seric 	} while (l[0] != '\0');
5667124Seric }
5677676Seric /*
5687676Seric **  XUNLINK -- unlink a file, doing logging as appropriate.
5697676Seric **
5707676Seric **	Parameters:
5717676Seric **		f -- name of file to unlink.
5727676Seric **
5737676Seric **	Returns:
5747676Seric **		none.
5757676Seric **
5767676Seric **	Side Effects:
5777676Seric **		f is unlinked.
5787676Seric */
5797676Seric 
5807676Seric xunlink(f)
5817676Seric 	char *f;
5827676Seric {
5837676Seric 	register int i;
5847676Seric 
5857676Seric # ifdef LOG
5867676Seric 	if (LogLevel > 20)
5877812Seric 		syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f);
5887676Seric # endif LOG
5897676Seric 
5907676Seric 	i = unlink(f);
5917676Seric # ifdef LOG
5927676Seric 	if (i < 0 && LogLevel > 21)
5937942Seric 		syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno);
5947676Seric # endif LOG
5957676Seric }
5967685Seric /*
5977685Seric **  SFGETS -- "safe" fgets -- times out.
5987685Seric **
5997685Seric **	Parameters:
6007685Seric **		buf -- place to put the input line.
6017685Seric **		siz -- size of buf.
6027685Seric **		fp -- file to read from.
6037685Seric **
6047685Seric **	Returns:
6057685Seric **		NULL on error (including timeout).
6067685Seric **		buf otherwise.
6077685Seric **
6087685Seric **	Side Effects:
6097685Seric **		none.
6107685Seric */
6117685Seric 
6127942Seric static bool	TimeoutFlag;
6137685Seric 
6147685Seric char *
6157685Seric sfgets(buf, siz, fp)
6167685Seric 	char *buf;
6177685Seric 	int siz;
6187685Seric 	FILE *fp;
6197685Seric {
6207942Seric 	register EVENT *ev = NULL;
6217685Seric 	register char *p;
6227685Seric 	extern readtimeout();
6237685Seric 
6247942Seric 	if (ReadTimeout != 0)
6257942Seric 		ev = setevent(ReadTimeout, readtimeout, 0);
6267942Seric 	TimeoutFlag = FALSE;
6277942Seric 	do
6287942Seric 	{
6297942Seric 		errno = 0;
6307942Seric 		p = fgets(buf, siz, fp);
6317942Seric 	} while (!(p != NULL || TimeoutFlag || errno != EINTR));
6327685Seric 	clrevent(ev);
6338055Seric 	LineNumber++;
6347685Seric 	return (p);
6357685Seric }
6367685Seric 
6377685Seric static
6387685Seric readtimeout()
6397685Seric {
6407942Seric 	TimeoutFlag = TRUE;
6417685Seric }
6427786Seric /*
6437786Seric **  FGETFOLDED -- like fgets, but know about folded lines.
6447786Seric **
6457786Seric **	Parameters:
6467786Seric **		buf -- place to put result.
6477786Seric **		n -- bytes available.
6487786Seric **		f -- file to read from.
6497786Seric **
6507786Seric **	Returns:
6517786Seric **		buf on success, NULL on error or EOF.
6527786Seric **
6537786Seric **	Side Effects:
6547786Seric **		buf gets lines from f, with continuation lines (lines
6557786Seric **		with leading white space) appended.  CRLF's are mapped
6567786Seric **		into single newlines.  Any trailing NL is stripped.
6577786Seric */
6587786Seric 
6597786Seric char *
6607786Seric fgetfolded(buf, n, f)
6617786Seric 	char *buf;
6627786Seric 	register int n;
6637786Seric 	FILE *f;
6647786Seric {
6657786Seric 	register char *p = buf;
6667786Seric 	register int i;
6677786Seric 
6687786Seric 	n--;
6698055Seric 	while (sfgets(p, n, f) != NULL)
6707786Seric 	{
6717786Seric 		fixcrlf(p, TRUE);
6727786Seric 		i = fgetc(f);
6737786Seric 		if (i != EOF)
6747786Seric 			ungetc(i, f);
6757786Seric 		if (i != ' ' && i != '\t')
6767786Seric 			return (buf);
6777786Seric 		i = strlen(p);
6787786Seric 		p += i;
6797786Seric 		*p++ = '\n';
6807786Seric 		n -= i + 1;
6817786Seric 	}
6827786Seric 	return (NULL);
6837786Seric }
6847860Seric /*
6857860Seric **  PINTVL -- produce printable version of a time interval
6867860Seric **
6877860Seric **	Parameters:
6887860Seric **		intvl -- the interval to be converted
6897860Seric **		brief -- if TRUE, print this in an extremely compact form
6907860Seric **			(basically used for logging).
6917860Seric **
6927860Seric **	Returns:
6937860Seric **		A pointer to a string version of intvl suitable for
6947860Seric **			printing or framing.
6957860Seric **
6967860Seric **	Side Effects:
6977860Seric **		none.
6987860Seric **
6997860Seric **	Warning:
7007860Seric **		The string returned is in a static buffer.
7017860Seric */
7027860Seric 
7037860Seric # define PLURAL(n)	((n) == 1 ? "" : "s")
7047860Seric 
7057860Seric char *
7067860Seric pintvl(intvl, brief)
7077860Seric 	time_t intvl;
7087860Seric 	bool brief;
7097860Seric {
7107860Seric 	static char buf[MAXNAME];
7117860Seric 	register char *p;
7127860Seric 	int wk, dy, hr, mi, se;
7137860Seric 
7147860Seric 	if (intvl == 0 && !brief)
7157860Seric 		return ("zero seconds");
7167860Seric 
7177860Seric 	/* decode the interval into weeks, days, hours, minutes, seconds */
7187860Seric 	se = intvl % 60;
7197860Seric 	intvl /= 60;
7207860Seric 	mi = intvl % 60;
7217860Seric 	intvl /= 60;
7227860Seric 	hr = intvl % 24;
7237860Seric 	intvl /= 24;
7247860Seric 	if (brief)
7257860Seric 		dy = intvl;
7267860Seric 	else
7277860Seric 	{
7287860Seric 		dy = intvl % 7;
7297860Seric 		intvl /= 7;
7307860Seric 		wk = intvl;
7317860Seric 	}
7327860Seric 
7337860Seric 	/* now turn it into a sexy form */
7347860Seric 	p = buf;
7357860Seric 	if (brief)
7367860Seric 	{
7377860Seric 		if (dy > 0)
7387860Seric 		{
7397860Seric 			(void) sprintf(p, "%d+", dy);
7407860Seric 			p += strlen(p);
7417860Seric 		}
7427860Seric 		(void) sprintf(p, "%02d:%02d:%02d", hr, mi, se);
7437860Seric 		return (buf);
7447860Seric 	}
7457860Seric 
7467860Seric 	/* use the verbose form */
7477860Seric 	if (wk > 0)
7487860Seric 	{
7497860Seric 		(void) sprintf(p, ", %d week%s", wk, PLURAL(wk));
7507860Seric 		p += strlen(p);
7517860Seric 	}
7527860Seric 	if (dy > 0)
7537860Seric 	{
7547860Seric 		(void) sprintf(p, ", %d day%s", dy, PLURAL(dy));
7557860Seric 		p += strlen(p);
7567860Seric 	}
7577860Seric 	if (hr > 0)
7587860Seric 	{
7597860Seric 		(void) sprintf(p, ", %d hour%s", hr, PLURAL(hr));
7607860Seric 		p += strlen(p);
7617860Seric 	}
7627860Seric 	if (mi > 0)
7637860Seric 	{
7647860Seric 		(void) sprintf(p, ", %d minute%s", mi, PLURAL(mi));
7657860Seric 		p += strlen(p);
7667860Seric 	}
7677860Seric 	if (se > 0)
7687860Seric 	{
7697860Seric 		(void) sprintf(p, ", %d second%s", se, PLURAL(se));
7707860Seric 		p += strlen(p);
7717860Seric 	}
7727860Seric 
7737860Seric 	return (buf + 2);
7747860Seric }
7757886Seric /*
7767886Seric **  CURTIME -- return current time.
7777886Seric **
7787886Seric **	Parameters:
7797886Seric **		none.
7807886Seric **
7817886Seric **	Returns:
7827886Seric **		the current time.
7837886Seric **
7847886Seric **	Side Effects:
7857886Seric **		none.
7867886Seric */
7877886Seric 
7887886Seric time_t
7897886Seric curtime()
7907886Seric {
7917886Seric 	auto time_t t;
7927886Seric 
7937886Seric 	(void) time(&t);
7947886Seric 	return (t);
7957886Seric }
796