xref: /illumos-gate/usr/src/cmd/sendmail/src/util.c (revision 445f2479)
17c478bd9Sstevel@tonic-gate /*
2*445f2479Sjbeck  * Copyright (c) 1998-2006 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate  *	All rights reserved.
47c478bd9Sstevel@tonic-gate  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
57c478bd9Sstevel@tonic-gate  * Copyright (c) 1988, 1993
67c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
97c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
107c478bd9Sstevel@tonic-gate  * the sendmail distribution.
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  */
137c478bd9Sstevel@tonic-gate 
147c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
157c478bd9Sstevel@tonic-gate 
167c478bd9Sstevel@tonic-gate #include <sendmail.h>
177c478bd9Sstevel@tonic-gate 
18*445f2479Sjbeck SM_RCSID("@(#)$Id: util.c,v 8.392 2006/03/09 19:49:35 ca Exp $")
197c478bd9Sstevel@tonic-gate 
207c478bd9Sstevel@tonic-gate #include <sysexits.h>
217c478bd9Sstevel@tonic-gate #include <sm/xtrap.h>
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate /*
247c478bd9Sstevel@tonic-gate **  NEWSTR -- Create a copy of a C string
257c478bd9Sstevel@tonic-gate **
267c478bd9Sstevel@tonic-gate **	Parameters:
277c478bd9Sstevel@tonic-gate **		s -- the string to copy.
287c478bd9Sstevel@tonic-gate **
297c478bd9Sstevel@tonic-gate **	Returns:
307c478bd9Sstevel@tonic-gate **		pointer to newly allocated string.
317c478bd9Sstevel@tonic-gate */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate char *
347c478bd9Sstevel@tonic-gate newstr(s)
357c478bd9Sstevel@tonic-gate 	const char *s;
367c478bd9Sstevel@tonic-gate {
377c478bd9Sstevel@tonic-gate 	size_t l;
387c478bd9Sstevel@tonic-gate 	char *n;
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate 	l = strlen(s);
417c478bd9Sstevel@tonic-gate 	SM_ASSERT(l + 1 > l);
427c478bd9Sstevel@tonic-gate 	n = xalloc(l + 1);
437c478bd9Sstevel@tonic-gate 	sm_strlcpy(n, s, l + 1);
447c478bd9Sstevel@tonic-gate 	return n;
457c478bd9Sstevel@tonic-gate }
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /*
487c478bd9Sstevel@tonic-gate **  ADDQUOTES -- Adds quotes & quote bits to a string.
497c478bd9Sstevel@tonic-gate **
507c478bd9Sstevel@tonic-gate **	Runs through a string and adds backslashes and quote bits.
517c478bd9Sstevel@tonic-gate **
527c478bd9Sstevel@tonic-gate **	Parameters:
537c478bd9Sstevel@tonic-gate **		s -- the string to modify.
547c478bd9Sstevel@tonic-gate **		rpool -- resource pool from which to allocate result
557c478bd9Sstevel@tonic-gate **
567c478bd9Sstevel@tonic-gate **	Returns:
577c478bd9Sstevel@tonic-gate **		pointer to quoted string.
587c478bd9Sstevel@tonic-gate */
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate char *
617c478bd9Sstevel@tonic-gate addquotes(s, rpool)
627c478bd9Sstevel@tonic-gate 	char *s;
637c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
647c478bd9Sstevel@tonic-gate {
657c478bd9Sstevel@tonic-gate 	int len = 0;
667c478bd9Sstevel@tonic-gate 	char c;
677c478bd9Sstevel@tonic-gate 	char *p = s, *q, *r;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	if (s == NULL)
707c478bd9Sstevel@tonic-gate 		return NULL;
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	/* Find length of quoted string */
737c478bd9Sstevel@tonic-gate 	while ((c = *p++) != '\0')
747c478bd9Sstevel@tonic-gate 	{
757c478bd9Sstevel@tonic-gate 		len++;
767c478bd9Sstevel@tonic-gate 		if (c == '\\' || c == '"')
777c478bd9Sstevel@tonic-gate 			len++;
787c478bd9Sstevel@tonic-gate 	}
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	q = r = sm_rpool_malloc_x(rpool, len + 3);
817c478bd9Sstevel@tonic-gate 	p = s;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	/* add leading quote */
847c478bd9Sstevel@tonic-gate 	*q++ = '"';
857c478bd9Sstevel@tonic-gate 	while ((c = *p++) != '\0')
867c478bd9Sstevel@tonic-gate 	{
877c478bd9Sstevel@tonic-gate 		/* quote \ or " */
887c478bd9Sstevel@tonic-gate 		if (c == '\\' || c == '"')
897c478bd9Sstevel@tonic-gate 			*q++ = '\\';
907c478bd9Sstevel@tonic-gate 		*q++ = c;
917c478bd9Sstevel@tonic-gate 	}
927c478bd9Sstevel@tonic-gate 	*q++ = '"';
937c478bd9Sstevel@tonic-gate 	*q = '\0';
947c478bd9Sstevel@tonic-gate 	return r;
957c478bd9Sstevel@tonic-gate }
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate **  STRIPBACKSLASH -- Strip all leading backslashes from a string, provided
997c478bd9Sstevel@tonic-gate **	the following character is alpha-numerical.
1007c478bd9Sstevel@tonic-gate **
1017c478bd9Sstevel@tonic-gate **	This is done in place.
1027c478bd9Sstevel@tonic-gate **
1037c478bd9Sstevel@tonic-gate **	Parameters:
1047c478bd9Sstevel@tonic-gate **		s -- the string to strip.
1057c478bd9Sstevel@tonic-gate **
1067c478bd9Sstevel@tonic-gate **	Returns:
1077c478bd9Sstevel@tonic-gate **		none.
1087c478bd9Sstevel@tonic-gate */
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate void
1117c478bd9Sstevel@tonic-gate stripbackslash(s)
1127c478bd9Sstevel@tonic-gate 	char *s;
1137c478bd9Sstevel@tonic-gate {
1147c478bd9Sstevel@tonic-gate 	char *p, *q, c;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	if (s == NULL || *s == '\0')
1177c478bd9Sstevel@tonic-gate 		return;
1187c478bd9Sstevel@tonic-gate 	p = q = s;
1197c478bd9Sstevel@tonic-gate 	while (*p == '\\' && (p[1] == '\\' || (isascii(p[1]) && isalnum(p[1]))))
1207c478bd9Sstevel@tonic-gate 		p++;
1217c478bd9Sstevel@tonic-gate 	do
1227c478bd9Sstevel@tonic-gate 	{
1237c478bd9Sstevel@tonic-gate 		c = *q++ = *p++;
1247c478bd9Sstevel@tonic-gate 	} while (c != '\0');
1257c478bd9Sstevel@tonic-gate }
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate **  RFC822_STRING -- Checks string for proper RFC822 string quoting.
1297c478bd9Sstevel@tonic-gate **
1307c478bd9Sstevel@tonic-gate **	Runs through a string and verifies RFC822 special characters
1317c478bd9Sstevel@tonic-gate **	are only found inside comments, quoted strings, or backslash
1327c478bd9Sstevel@tonic-gate **	escaped.  Also verified balanced quotes and parenthesis.
1337c478bd9Sstevel@tonic-gate **
1347c478bd9Sstevel@tonic-gate **	Parameters:
1357c478bd9Sstevel@tonic-gate **		s -- the string to modify.
1367c478bd9Sstevel@tonic-gate **
1377c478bd9Sstevel@tonic-gate **	Returns:
1387c478bd9Sstevel@tonic-gate **		true iff the string is RFC822 compliant, false otherwise.
1397c478bd9Sstevel@tonic-gate */
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate bool
1427c478bd9Sstevel@tonic-gate rfc822_string(s)
1437c478bd9Sstevel@tonic-gate 	char *s;
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate 	bool quoted = false;
1467c478bd9Sstevel@tonic-gate 	int commentlev = 0;
1477c478bd9Sstevel@tonic-gate 	char *c = s;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	if (s == NULL)
1507c478bd9Sstevel@tonic-gate 		return false;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	while (*c != '\0')
1537c478bd9Sstevel@tonic-gate 	{
1547c478bd9Sstevel@tonic-gate 		/* escaped character */
1557c478bd9Sstevel@tonic-gate 		if (*c == '\\')
1567c478bd9Sstevel@tonic-gate 		{
1577c478bd9Sstevel@tonic-gate 			c++;
1587c478bd9Sstevel@tonic-gate 			if (*c == '\0')
1597c478bd9Sstevel@tonic-gate 				return false;
1607c478bd9Sstevel@tonic-gate 		}
1617c478bd9Sstevel@tonic-gate 		else if (commentlev == 0 && *c == '"')
1627c478bd9Sstevel@tonic-gate 			quoted = !quoted;
1637c478bd9Sstevel@tonic-gate 		else if (!quoted)
1647c478bd9Sstevel@tonic-gate 		{
1657c478bd9Sstevel@tonic-gate 			if (*c == ')')
1667c478bd9Sstevel@tonic-gate 			{
1677c478bd9Sstevel@tonic-gate 				/* unbalanced ')' */
1687c478bd9Sstevel@tonic-gate 				if (commentlev == 0)
1697c478bd9Sstevel@tonic-gate 					return false;
1707c478bd9Sstevel@tonic-gate 				else
1717c478bd9Sstevel@tonic-gate 					commentlev--;
1727c478bd9Sstevel@tonic-gate 			}
1737c478bd9Sstevel@tonic-gate 			else if (*c == '(')
1747c478bd9Sstevel@tonic-gate 				commentlev++;
1757c478bd9Sstevel@tonic-gate 			else if (commentlev == 0 &&
1767c478bd9Sstevel@tonic-gate 				 strchr(MustQuoteChars, *c) != NULL)
1777c478bd9Sstevel@tonic-gate 				return false;
1787c478bd9Sstevel@tonic-gate 		}
1797c478bd9Sstevel@tonic-gate 		c++;
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/* unbalanced '"' or '(' */
1837c478bd9Sstevel@tonic-gate 	return !quoted && commentlev == 0;
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate /*
1867c478bd9Sstevel@tonic-gate **  SHORTEN_RFC822_STRING -- Truncate and rebalance an RFC822 string
1877c478bd9Sstevel@tonic-gate **
1887c478bd9Sstevel@tonic-gate **	Arbitrarily shorten (in place) an RFC822 string and rebalance
1897c478bd9Sstevel@tonic-gate **	comments and quotes.
1907c478bd9Sstevel@tonic-gate **
1917c478bd9Sstevel@tonic-gate **	Parameters:
1927c478bd9Sstevel@tonic-gate **		string -- the string to shorten
1937c478bd9Sstevel@tonic-gate **		length -- the maximum size, 0 if no maximum
1947c478bd9Sstevel@tonic-gate **
1957c478bd9Sstevel@tonic-gate **	Returns:
1967c478bd9Sstevel@tonic-gate **		true if string is changed, false otherwise
1977c478bd9Sstevel@tonic-gate **
1987c478bd9Sstevel@tonic-gate **	Side Effects:
1997c478bd9Sstevel@tonic-gate **		Changes string in place, possibly resulting
2007c478bd9Sstevel@tonic-gate **		in a shorter string.
2017c478bd9Sstevel@tonic-gate */
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate bool
2047c478bd9Sstevel@tonic-gate shorten_rfc822_string(string, length)
2057c478bd9Sstevel@tonic-gate 	char *string;
2067c478bd9Sstevel@tonic-gate 	size_t length;
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	bool backslash = false;
2097c478bd9Sstevel@tonic-gate 	bool modified = false;
2107c478bd9Sstevel@tonic-gate 	bool quoted = false;
2117c478bd9Sstevel@tonic-gate 	size_t slen;
2127c478bd9Sstevel@tonic-gate 	int parencount = 0;
2137c478bd9Sstevel@tonic-gate 	char *ptr = string;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	/*
2167c478bd9Sstevel@tonic-gate 	**  If have to rebalance an already short enough string,
2177c478bd9Sstevel@tonic-gate 	**  need to do it within allocated space.
2187c478bd9Sstevel@tonic-gate 	*/
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	slen = strlen(string);
2217c478bd9Sstevel@tonic-gate 	if (length == 0 || slen < length)
2227c478bd9Sstevel@tonic-gate 		length = slen;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	while (*ptr != '\0')
2257c478bd9Sstevel@tonic-gate 	{
2267c478bd9Sstevel@tonic-gate 		if (backslash)
2277c478bd9Sstevel@tonic-gate 		{
2287c478bd9Sstevel@tonic-gate 			backslash = false;
2297c478bd9Sstevel@tonic-gate 			goto increment;
2307c478bd9Sstevel@tonic-gate 		}
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 		if (*ptr == '\\')
2337c478bd9Sstevel@tonic-gate 			backslash = true;
2347c478bd9Sstevel@tonic-gate 		else if (*ptr == '(')
2357c478bd9Sstevel@tonic-gate 		{
2367c478bd9Sstevel@tonic-gate 			if (!quoted)
2377c478bd9Sstevel@tonic-gate 				parencount++;
2387c478bd9Sstevel@tonic-gate 		}
2397c478bd9Sstevel@tonic-gate 		else if (*ptr == ')')
2407c478bd9Sstevel@tonic-gate 		{
2417c478bd9Sstevel@tonic-gate 			if (--parencount < 0)
2427c478bd9Sstevel@tonic-gate 				parencount = 0;
2437c478bd9Sstevel@tonic-gate 		}
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 		/* Inside a comment, quotes don't matter */
2467c478bd9Sstevel@tonic-gate 		if (parencount <= 0 && *ptr == '"')
2477c478bd9Sstevel@tonic-gate 			quoted = !quoted;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate increment:
2507c478bd9Sstevel@tonic-gate 		/* Check for sufficient space for next character */
2517c478bd9Sstevel@tonic-gate 		if (length - (ptr - string) <= (size_t) ((backslash ? 1 : 0) +
2527c478bd9Sstevel@tonic-gate 						parencount +
2537c478bd9Sstevel@tonic-gate 						(quoted ? 1 : 0)))
2547c478bd9Sstevel@tonic-gate 		{
2557c478bd9Sstevel@tonic-gate 			/* Not enough, backtrack */
2567c478bd9Sstevel@tonic-gate 			if (*ptr == '\\')
2577c478bd9Sstevel@tonic-gate 				backslash = false;
2587c478bd9Sstevel@tonic-gate 			else if (*ptr == '(' && !quoted)
2597c478bd9Sstevel@tonic-gate 				parencount--;
2607c478bd9Sstevel@tonic-gate 			else if (*ptr == '"' && parencount == 0)
2617c478bd9Sstevel@tonic-gate 				quoted = false;
2627c478bd9Sstevel@tonic-gate 			break;
2637c478bd9Sstevel@tonic-gate 		}
2647c478bd9Sstevel@tonic-gate 		ptr++;
2657c478bd9Sstevel@tonic-gate 	}
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	/* Rebalance */
2687c478bd9Sstevel@tonic-gate 	while (parencount-- > 0)
2697c478bd9Sstevel@tonic-gate 	{
2707c478bd9Sstevel@tonic-gate 		if (*ptr != ')')
2717c478bd9Sstevel@tonic-gate 		{
2727c478bd9Sstevel@tonic-gate 			modified = true;
2737c478bd9Sstevel@tonic-gate 			*ptr = ')';
2747c478bd9Sstevel@tonic-gate 		}
2757c478bd9Sstevel@tonic-gate 		ptr++;
2767c478bd9Sstevel@tonic-gate 	}
2777c478bd9Sstevel@tonic-gate 	if (quoted)
2787c478bd9Sstevel@tonic-gate 	{
2797c478bd9Sstevel@tonic-gate 		if (*ptr != '"')
2807c478bd9Sstevel@tonic-gate 		{
2817c478bd9Sstevel@tonic-gate 			modified = true;
2827c478bd9Sstevel@tonic-gate 			*ptr = '"';
2837c478bd9Sstevel@tonic-gate 		}
2847c478bd9Sstevel@tonic-gate 		ptr++;
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 	if (*ptr != '\0')
2877c478bd9Sstevel@tonic-gate 	{
2887c478bd9Sstevel@tonic-gate 		modified = true;
2897c478bd9Sstevel@tonic-gate 		*ptr = '\0';
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate 	return modified;
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate /*
2947c478bd9Sstevel@tonic-gate **  FIND_CHARACTER -- find an unquoted character in an RFC822 string
2957c478bd9Sstevel@tonic-gate **
2967c478bd9Sstevel@tonic-gate **	Find an unquoted, non-commented character in an RFC822
2977c478bd9Sstevel@tonic-gate **	string and return a pointer to its location in the
2987c478bd9Sstevel@tonic-gate **	string.
2997c478bd9Sstevel@tonic-gate **
3007c478bd9Sstevel@tonic-gate **	Parameters:
3017c478bd9Sstevel@tonic-gate **		string -- the string to search
3027c478bd9Sstevel@tonic-gate **		character -- the character to find
3037c478bd9Sstevel@tonic-gate **
3047c478bd9Sstevel@tonic-gate **	Returns:
3057c478bd9Sstevel@tonic-gate **		pointer to the character, or
3067c478bd9Sstevel@tonic-gate **		a pointer to the end of the line if character is not found
3077c478bd9Sstevel@tonic-gate */
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate char *
3107c478bd9Sstevel@tonic-gate find_character(string, character)
3117c478bd9Sstevel@tonic-gate 	char *string;
3127c478bd9Sstevel@tonic-gate 	int character;
3137c478bd9Sstevel@tonic-gate {
3147c478bd9Sstevel@tonic-gate 	bool backslash = false;
3157c478bd9Sstevel@tonic-gate 	bool quoted = false;
3167c478bd9Sstevel@tonic-gate 	int parencount = 0;
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	while (string != NULL && *string != '\0')
3197c478bd9Sstevel@tonic-gate 	{
3207c478bd9Sstevel@tonic-gate 		if (backslash)
3217c478bd9Sstevel@tonic-gate 		{
3227c478bd9Sstevel@tonic-gate 			backslash = false;
3237c478bd9Sstevel@tonic-gate 			if (!quoted && character == '\\' && *string == '\\')
3247c478bd9Sstevel@tonic-gate 				break;
3257c478bd9Sstevel@tonic-gate 			string++;
3267c478bd9Sstevel@tonic-gate 			continue;
3277c478bd9Sstevel@tonic-gate 		}
3287c478bd9Sstevel@tonic-gate 		switch (*string)
3297c478bd9Sstevel@tonic-gate 		{
3307c478bd9Sstevel@tonic-gate 		  case '\\':
3317c478bd9Sstevel@tonic-gate 			backslash = true;
3327c478bd9Sstevel@tonic-gate 			break;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 		  case '(':
3357c478bd9Sstevel@tonic-gate 			if (!quoted)
3367c478bd9Sstevel@tonic-gate 				parencount++;
3377c478bd9Sstevel@tonic-gate 			break;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 		  case ')':
3407c478bd9Sstevel@tonic-gate 			if (--parencount < 0)
3417c478bd9Sstevel@tonic-gate 				parencount = 0;
3427c478bd9Sstevel@tonic-gate 			break;
3437c478bd9Sstevel@tonic-gate 		}
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 		/* Inside a comment, nothing matters */
3467c478bd9Sstevel@tonic-gate 		if (parencount > 0)
3477c478bd9Sstevel@tonic-gate 		{
3487c478bd9Sstevel@tonic-gate 			string++;
3497c478bd9Sstevel@tonic-gate 			continue;
3507c478bd9Sstevel@tonic-gate 		}
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 		if (*string == '"')
3537c478bd9Sstevel@tonic-gate 			quoted = !quoted;
3547c478bd9Sstevel@tonic-gate 		else if (*string == character && !quoted)
3557c478bd9Sstevel@tonic-gate 			break;
3567c478bd9Sstevel@tonic-gate 		string++;
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	/* Return pointer to the character */
3607c478bd9Sstevel@tonic-gate 	return string;
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate /*
3647c478bd9Sstevel@tonic-gate **  CHECK_BODYTYPE -- check bodytype parameter
3657c478bd9Sstevel@tonic-gate **
3667c478bd9Sstevel@tonic-gate **	Parameters:
3677c478bd9Sstevel@tonic-gate **		bodytype -- bodytype parameter
3687c478bd9Sstevel@tonic-gate **
3697c478bd9Sstevel@tonic-gate **	Returns:
3707c478bd9Sstevel@tonic-gate **		BODYTYPE_* according to parameter
3717c478bd9Sstevel@tonic-gate **
3727c478bd9Sstevel@tonic-gate */
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate int
3757c478bd9Sstevel@tonic-gate check_bodytype(bodytype)
3767c478bd9Sstevel@tonic-gate 	char *bodytype;
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate 	/* check body type for legality */
3797c478bd9Sstevel@tonic-gate 	if (bodytype == NULL)
3807c478bd9Sstevel@tonic-gate 		return BODYTYPE_NONE;
3817c478bd9Sstevel@tonic-gate 	if (sm_strcasecmp(bodytype, "7BIT") == 0)
3827c478bd9Sstevel@tonic-gate 		return BODYTYPE_7BIT;
3837c478bd9Sstevel@tonic-gate 	if (sm_strcasecmp(bodytype, "8BITMIME") == 0)
3847c478bd9Sstevel@tonic-gate 		return BODYTYPE_8BITMIME;
3857c478bd9Sstevel@tonic-gate 	return BODYTYPE_ILLEGAL;
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate #if _FFR_BESTMX_BETTER_TRUNCATION || _FFR_DNSMAP_MULTI
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate **  TRUNCATE_AT_DELIM -- truncate string at a delimiter and append "..."
3917c478bd9Sstevel@tonic-gate **
3927c478bd9Sstevel@tonic-gate **	Parameters:
3937c478bd9Sstevel@tonic-gate **		str -- string to truncate
3947c478bd9Sstevel@tonic-gate **		len -- maximum length (including '\0') (0 for unlimited)
3957c478bd9Sstevel@tonic-gate **		delim -- delimiter character
3967c478bd9Sstevel@tonic-gate **
3977c478bd9Sstevel@tonic-gate **	Returns:
3987c478bd9Sstevel@tonic-gate **		None.
3997c478bd9Sstevel@tonic-gate */
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate void
4027c478bd9Sstevel@tonic-gate truncate_at_delim(str, len, delim)
4037c478bd9Sstevel@tonic-gate 	char *str;
4047c478bd9Sstevel@tonic-gate 	size_t len;
4057c478bd9Sstevel@tonic-gate 	int delim;
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate 	char *p;
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	if (str == NULL || len == 0 || strlen(str) < len)
4107c478bd9Sstevel@tonic-gate 		return;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	*(str + len - 1) = '\0';
4137c478bd9Sstevel@tonic-gate 	while ((p = strrchr(str, delim)) != NULL)
4147c478bd9Sstevel@tonic-gate 	{
4157c478bd9Sstevel@tonic-gate 		*p = '\0';
4167c478bd9Sstevel@tonic-gate 		if (p - str + 4 < len)
4177c478bd9Sstevel@tonic-gate 		{
4187c478bd9Sstevel@tonic-gate 			*p++ = (char) delim;
4197c478bd9Sstevel@tonic-gate 			*p = '\0';
4207c478bd9Sstevel@tonic-gate 			(void) sm_strlcat(str, "...", len);
4217c478bd9Sstevel@tonic-gate 			return;
4227c478bd9Sstevel@tonic-gate 		}
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	/* Couldn't find a place to append "..." */
4267c478bd9Sstevel@tonic-gate 	if (len > 3)
4277c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(str, "...", len);
4287c478bd9Sstevel@tonic-gate 	else
4297c478bd9Sstevel@tonic-gate 		str[0] = '\0';
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate #endif /* _FFR_BESTMX_BETTER_TRUNCATION || _FFR_DNSMAP_MULTI */
4327c478bd9Sstevel@tonic-gate /*
4337c478bd9Sstevel@tonic-gate **  XALLOC -- Allocate memory, raise an exception on error
4347c478bd9Sstevel@tonic-gate **
4357c478bd9Sstevel@tonic-gate **	Parameters:
4367c478bd9Sstevel@tonic-gate **		sz -- size of area to allocate.
4377c478bd9Sstevel@tonic-gate **
4387c478bd9Sstevel@tonic-gate **	Returns:
4397c478bd9Sstevel@tonic-gate **		pointer to data region.
4407c478bd9Sstevel@tonic-gate **
4417c478bd9Sstevel@tonic-gate **	Exceptions:
4427c478bd9Sstevel@tonic-gate **		SmHeapOutOfMemory (F:sm.heap) -- cannot allocate memory
4437c478bd9Sstevel@tonic-gate **
4447c478bd9Sstevel@tonic-gate **	Side Effects:
4457c478bd9Sstevel@tonic-gate **		Memory is allocated.
4467c478bd9Sstevel@tonic-gate */
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate char *
4497c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK
4507c478bd9Sstevel@tonic-gate xalloc_tagged(sz, file, line)
4517c478bd9Sstevel@tonic-gate 	register int sz;
4527c478bd9Sstevel@tonic-gate 	char *file;
4537c478bd9Sstevel@tonic-gate 	int line;
4547c478bd9Sstevel@tonic-gate #else /* SM_HEAP_CHECK */
4557c478bd9Sstevel@tonic-gate xalloc(sz)
4567c478bd9Sstevel@tonic-gate 	register int sz;
4577c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */
4587c478bd9Sstevel@tonic-gate {
4597c478bd9Sstevel@tonic-gate 	register char *p;
4607c478bd9Sstevel@tonic-gate 
461*445f2479Sjbeck 	SM_REQUIRE(sz >= 0);
462*445f2479Sjbeck 
4637c478bd9Sstevel@tonic-gate 	/* some systems can't handle size zero mallocs */
4647c478bd9Sstevel@tonic-gate 	if (sz <= 0)
4657c478bd9Sstevel@tonic-gate 		sz = 1;
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	/* scaffolding for testing error handling code */
4687c478bd9Sstevel@tonic-gate 	sm_xtrap_raise_x(&SmHeapOutOfMemory);
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	p = sm_malloc_tagged((unsigned) sz, file, line, sm_heap_group());
4717c478bd9Sstevel@tonic-gate 	if (p == NULL)
4727c478bd9Sstevel@tonic-gate 	{
4737c478bd9Sstevel@tonic-gate 		sm_exc_raise_x(&SmHeapOutOfMemory);
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 	return p;
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate /*
4787c478bd9Sstevel@tonic-gate **  COPYPLIST -- copy list of pointers.
4797c478bd9Sstevel@tonic-gate **
4807c478bd9Sstevel@tonic-gate **	This routine is the equivalent of strdup for lists of
4817c478bd9Sstevel@tonic-gate **	pointers.
4827c478bd9Sstevel@tonic-gate **
4837c478bd9Sstevel@tonic-gate **	Parameters:
4847c478bd9Sstevel@tonic-gate **		list -- list of pointers to copy.
4857c478bd9Sstevel@tonic-gate **			Must be NULL terminated.
4867c478bd9Sstevel@tonic-gate **		copycont -- if true, copy the contents of the vector
4877c478bd9Sstevel@tonic-gate **			(which must be a string) also.
4887c478bd9Sstevel@tonic-gate **		rpool -- resource pool from which to allocate storage,
4897c478bd9Sstevel@tonic-gate **			or NULL
4907c478bd9Sstevel@tonic-gate **
4917c478bd9Sstevel@tonic-gate **	Returns:
4927c478bd9Sstevel@tonic-gate **		a copy of 'list'.
4937c478bd9Sstevel@tonic-gate */
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate char **
4967c478bd9Sstevel@tonic-gate copyplist(list, copycont, rpool)
4977c478bd9Sstevel@tonic-gate 	char **list;
4987c478bd9Sstevel@tonic-gate 	bool copycont;
4997c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
5007c478bd9Sstevel@tonic-gate {
5017c478bd9Sstevel@tonic-gate 	register char **vp;
5027c478bd9Sstevel@tonic-gate 	register char **newvp;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	for (vp = list; *vp != NULL; vp++)
5057c478bd9Sstevel@tonic-gate 		continue;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	vp++;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	newvp = (char **) sm_rpool_malloc_x(rpool, (vp - list) * sizeof *vp);
5107c478bd9Sstevel@tonic-gate 	memmove((char *) newvp, (char *) list, (int) (vp - list) * sizeof *vp);
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	if (copycont)
5137c478bd9Sstevel@tonic-gate 	{
5147c478bd9Sstevel@tonic-gate 		for (vp = newvp; *vp != NULL; vp++)
5157c478bd9Sstevel@tonic-gate 			*vp = sm_rpool_strdup_x(rpool, *vp);
5167c478bd9Sstevel@tonic-gate 	}
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	return newvp;
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate /*
5217c478bd9Sstevel@tonic-gate **  COPYQUEUE -- copy address queue.
5227c478bd9Sstevel@tonic-gate **
5237c478bd9Sstevel@tonic-gate **	This routine is the equivalent of strdup for address queues;
5247c478bd9Sstevel@tonic-gate **	addresses marked as QS_IS_DEAD() aren't copied
5257c478bd9Sstevel@tonic-gate **
5267c478bd9Sstevel@tonic-gate **	Parameters:
5277c478bd9Sstevel@tonic-gate **		addr -- list of address structures to copy.
5287c478bd9Sstevel@tonic-gate **		rpool -- resource pool from which to allocate storage
5297c478bd9Sstevel@tonic-gate **
5307c478bd9Sstevel@tonic-gate **	Returns:
5317c478bd9Sstevel@tonic-gate **		a copy of 'addr'.
5327c478bd9Sstevel@tonic-gate */
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate ADDRESS *
5357c478bd9Sstevel@tonic-gate copyqueue(addr, rpool)
5367c478bd9Sstevel@tonic-gate 	ADDRESS *addr;
5377c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
5387c478bd9Sstevel@tonic-gate {
5397c478bd9Sstevel@tonic-gate 	register ADDRESS *newaddr;
5407c478bd9Sstevel@tonic-gate 	ADDRESS *ret;
5417c478bd9Sstevel@tonic-gate 	register ADDRESS **tail = &ret;
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	while (addr != NULL)
5447c478bd9Sstevel@tonic-gate 	{
5457c478bd9Sstevel@tonic-gate 		if (!QS_IS_DEAD(addr->q_state))
5467c478bd9Sstevel@tonic-gate 		{
5477c478bd9Sstevel@tonic-gate 			newaddr = (ADDRESS *) sm_rpool_malloc_x(rpool,
5487c478bd9Sstevel@tonic-gate 							sizeof *newaddr);
5497c478bd9Sstevel@tonic-gate 			STRUCTCOPY(*addr, *newaddr);
5507c478bd9Sstevel@tonic-gate 			*tail = newaddr;
5517c478bd9Sstevel@tonic-gate 			tail = &newaddr->q_next;
5527c478bd9Sstevel@tonic-gate 		}
5537c478bd9Sstevel@tonic-gate 		addr = addr->q_next;
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 	*tail = NULL;
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	return ret;
5587c478bd9Sstevel@tonic-gate }
5597c478bd9Sstevel@tonic-gate /*
5607c478bd9Sstevel@tonic-gate **  LOG_SENDMAIL_PID -- record sendmail pid and command line.
5617c478bd9Sstevel@tonic-gate **
5627c478bd9Sstevel@tonic-gate **	Parameters:
5637c478bd9Sstevel@tonic-gate **		e -- the current envelope.
5647c478bd9Sstevel@tonic-gate **
5657c478bd9Sstevel@tonic-gate **	Returns:
5667c478bd9Sstevel@tonic-gate **		none.
5677c478bd9Sstevel@tonic-gate **
5687c478bd9Sstevel@tonic-gate **	Side Effects:
5697c478bd9Sstevel@tonic-gate **		writes pidfile, logs command line.
5707c478bd9Sstevel@tonic-gate **		keeps file open and locked to prevent overwrite of active file
5717c478bd9Sstevel@tonic-gate */
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate static SM_FILE_T	*Pidf = NULL;
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate void
5767c478bd9Sstevel@tonic-gate log_sendmail_pid(e)
5777c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
5787c478bd9Sstevel@tonic-gate {
5797c478bd9Sstevel@tonic-gate 	long sff;
5807c478bd9Sstevel@tonic-gate 	char pidpath[MAXPATHLEN];
5817c478bd9Sstevel@tonic-gate 	extern char *CommandLineArgs;
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	/* write the pid to the log file for posterity */
5847c478bd9Sstevel@tonic-gate 	sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT|SFF_NBLOCK;
5857c478bd9Sstevel@tonic-gate 	if (TrustedUid != 0 && RealUid == TrustedUid)
5867c478bd9Sstevel@tonic-gate 		sff |= SFF_OPENASROOT;
5877c478bd9Sstevel@tonic-gate 	expand(PidFile, pidpath, sizeof pidpath, e);
5887c478bd9Sstevel@tonic-gate 	Pidf = safefopen(pidpath, O_WRONLY|O_TRUNC, FileMode, sff);
5897c478bd9Sstevel@tonic-gate 	if (Pidf == NULL)
5907c478bd9Sstevel@tonic-gate 	{
5917c478bd9Sstevel@tonic-gate 		if (errno == EWOULDBLOCK)
5927c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, NOQID,
5937c478bd9Sstevel@tonic-gate 				  "unable to write pid to %s: file in use by another process",
5947c478bd9Sstevel@tonic-gate 				  pidpath);
5957c478bd9Sstevel@tonic-gate 		else
5967c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, NOQID,
5977c478bd9Sstevel@tonic-gate 				  "unable to write pid to %s: %s",
5987c478bd9Sstevel@tonic-gate 				  pidpath, sm_errstring(errno));
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 	else
6017c478bd9Sstevel@tonic-gate 	{
6027c478bd9Sstevel@tonic-gate 		PidFilePid = getpid();
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 		/* write the process id on line 1 */
6057c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(Pidf, SM_TIME_DEFAULT, "%ld\n",
6067c478bd9Sstevel@tonic-gate 				     (long) PidFilePid);
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 		/* line 2 contains all command line flags */
6097c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(Pidf, SM_TIME_DEFAULT, "%s\n",
6107c478bd9Sstevel@tonic-gate 				     CommandLineArgs);
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 		/* flush */
6137c478bd9Sstevel@tonic-gate 		(void) sm_io_flush(Pidf, SM_TIME_DEFAULT);
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 		/*
6167c478bd9Sstevel@tonic-gate 		**  Leave pid file open until process ends
6177c478bd9Sstevel@tonic-gate 		**  so it's not overwritten by another
6187c478bd9Sstevel@tonic-gate 		**  process.
6197c478bd9Sstevel@tonic-gate 		*/
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate 	if (LogLevel > 9)
6227c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, NOQID, "started as: %s", CommandLineArgs);
6237c478bd9Sstevel@tonic-gate }
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate /*
6267c478bd9Sstevel@tonic-gate **  CLOSE_SENDMAIL_PID -- close sendmail pid file
6277c478bd9Sstevel@tonic-gate **
6287c478bd9Sstevel@tonic-gate **	Parameters:
6297c478bd9Sstevel@tonic-gate **		none.
6307c478bd9Sstevel@tonic-gate **
6317c478bd9Sstevel@tonic-gate **	Returns:
6327c478bd9Sstevel@tonic-gate **		none.
6337c478bd9Sstevel@tonic-gate */
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate void
6367c478bd9Sstevel@tonic-gate close_sendmail_pid()
6377c478bd9Sstevel@tonic-gate {
6387c478bd9Sstevel@tonic-gate 	if (Pidf == NULL)
6397c478bd9Sstevel@tonic-gate 		return;
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	(void) sm_io_close(Pidf, SM_TIME_DEFAULT);
6427c478bd9Sstevel@tonic-gate 	Pidf = NULL;
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate /*
6467c478bd9Sstevel@tonic-gate **  SET_DELIVERY_MODE -- set and record the delivery mode
6477c478bd9Sstevel@tonic-gate **
6487c478bd9Sstevel@tonic-gate **	Parameters:
6497c478bd9Sstevel@tonic-gate **		mode -- delivery mode
6507c478bd9Sstevel@tonic-gate **		e -- the current envelope.
6517c478bd9Sstevel@tonic-gate **
6527c478bd9Sstevel@tonic-gate **	Returns:
6537c478bd9Sstevel@tonic-gate **		none.
6547c478bd9Sstevel@tonic-gate **
6557c478bd9Sstevel@tonic-gate **	Side Effects:
6567c478bd9Sstevel@tonic-gate **		sets {deliveryMode} macro
6577c478bd9Sstevel@tonic-gate */
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate void
6607c478bd9Sstevel@tonic-gate set_delivery_mode(mode, e)
6617c478bd9Sstevel@tonic-gate 	int mode;
6627c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
6637c478bd9Sstevel@tonic-gate {
6647c478bd9Sstevel@tonic-gate 	char buf[2];
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	e->e_sendmode = (char) mode;
6677c478bd9Sstevel@tonic-gate 	buf[0] = (char) mode;
6687c478bd9Sstevel@tonic-gate 	buf[1] = '\0';
6697c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_TEMP, macid("{deliveryMode}"), buf);
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate /*
6727c478bd9Sstevel@tonic-gate **  SET_OP_MODE -- set and record the op mode
6737c478bd9Sstevel@tonic-gate **
6747c478bd9Sstevel@tonic-gate **	Parameters:
6757c478bd9Sstevel@tonic-gate **		mode -- op mode
6767c478bd9Sstevel@tonic-gate **		e -- the current envelope.
6777c478bd9Sstevel@tonic-gate **
6787c478bd9Sstevel@tonic-gate **	Returns:
6797c478bd9Sstevel@tonic-gate **		none.
6807c478bd9Sstevel@tonic-gate **
6817c478bd9Sstevel@tonic-gate **	Side Effects:
6827c478bd9Sstevel@tonic-gate **		sets {opMode} macro
6837c478bd9Sstevel@tonic-gate */
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate void
6867c478bd9Sstevel@tonic-gate set_op_mode(mode)
6877c478bd9Sstevel@tonic-gate 	int mode;
6887c478bd9Sstevel@tonic-gate {
6897c478bd9Sstevel@tonic-gate 	char buf[2];
6907c478bd9Sstevel@tonic-gate 	extern ENVELOPE BlankEnvelope;
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	OpMode = (char) mode;
6937c478bd9Sstevel@tonic-gate 	buf[0] = (char) mode;
6947c478bd9Sstevel@tonic-gate 	buf[1] = '\0';
6957c478bd9Sstevel@tonic-gate 	macdefine(&BlankEnvelope.e_macro, A_TEMP, MID_OPMODE, buf);
6967c478bd9Sstevel@tonic-gate }
6977c478bd9Sstevel@tonic-gate /*
6987c478bd9Sstevel@tonic-gate **  PRINTAV -- print argument vector.
6997c478bd9Sstevel@tonic-gate **
7007c478bd9Sstevel@tonic-gate **	Parameters:
7017c478bd9Sstevel@tonic-gate **		fp -- output file pointer.
7027c478bd9Sstevel@tonic-gate **		av -- argument vector.
7037c478bd9Sstevel@tonic-gate **
7047c478bd9Sstevel@tonic-gate **	Returns:
7057c478bd9Sstevel@tonic-gate **		none.
7067c478bd9Sstevel@tonic-gate **
7077c478bd9Sstevel@tonic-gate **	Side Effects:
7087c478bd9Sstevel@tonic-gate **		prints av.
7097c478bd9Sstevel@tonic-gate */
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate void
7127c478bd9Sstevel@tonic-gate printav(fp, av)
7137c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
7147c478bd9Sstevel@tonic-gate 	register char **av;
7157c478bd9Sstevel@tonic-gate {
7167c478bd9Sstevel@tonic-gate 	while (*av != NULL)
7177c478bd9Sstevel@tonic-gate 	{
7187c478bd9Sstevel@tonic-gate 		if (tTd(0, 44))
7197c478bd9Sstevel@tonic-gate 			sm_dprintf("\n\t%08lx=", (unsigned long) *av);
7207c478bd9Sstevel@tonic-gate 		else
7217c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(fp, SM_TIME_DEFAULT, ' ');
7227c478bd9Sstevel@tonic-gate 		xputs(fp, *av++);
7237c478bd9Sstevel@tonic-gate 	}
7247c478bd9Sstevel@tonic-gate 	(void) sm_io_putc(fp, SM_TIME_DEFAULT, '\n');
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate /*
7277c478bd9Sstevel@tonic-gate **  XPUTS -- put string doing control escapes.
7287c478bd9Sstevel@tonic-gate **
7297c478bd9Sstevel@tonic-gate **	Parameters:
7307c478bd9Sstevel@tonic-gate **		fp -- output file pointer.
7317c478bd9Sstevel@tonic-gate **		s -- string to put.
7327c478bd9Sstevel@tonic-gate **
7337c478bd9Sstevel@tonic-gate **	Returns:
7347c478bd9Sstevel@tonic-gate **		none.
7357c478bd9Sstevel@tonic-gate **
7367c478bd9Sstevel@tonic-gate **	Side Effects:
7377c478bd9Sstevel@tonic-gate **		output to stdout
7387c478bd9Sstevel@tonic-gate */
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate void
7417c478bd9Sstevel@tonic-gate xputs(fp, s)
7427c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
7437c478bd9Sstevel@tonic-gate 	register const char *s;
7447c478bd9Sstevel@tonic-gate {
7457c478bd9Sstevel@tonic-gate 	register int c;
7467c478bd9Sstevel@tonic-gate 	register struct metamac *mp;
7477c478bd9Sstevel@tonic-gate 	bool shiftout = false;
7487c478bd9Sstevel@tonic-gate 	extern struct metamac MetaMacros[];
7497c478bd9Sstevel@tonic-gate 	static SM_DEBUG_T DebugANSI = SM_DEBUG_INITIALIZER("ANSI",
7507c478bd9Sstevel@tonic-gate 		"@(#)$Debug: ANSI - enable reverse video in debug output $");
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	/*
7537c478bd9Sstevel@tonic-gate 	**  TermEscape is set here, rather than in main(),
7547c478bd9Sstevel@tonic-gate 	**  because ANSI mode can be turned on or off at any time
7557c478bd9Sstevel@tonic-gate 	**  if we are in -bt rule testing mode.
7567c478bd9Sstevel@tonic-gate 	*/
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	if (sm_debug_unknown(&DebugANSI))
7597c478bd9Sstevel@tonic-gate 	{
7607c478bd9Sstevel@tonic-gate 		if (sm_debug_active(&DebugANSI, 1))
7617c478bd9Sstevel@tonic-gate 		{
7627c478bd9Sstevel@tonic-gate 			TermEscape.te_rv_on = "\033[7m";
7637c478bd9Sstevel@tonic-gate 			TermEscape.te_rv_off = "\033[0m";
7647c478bd9Sstevel@tonic-gate 		}
7657c478bd9Sstevel@tonic-gate 		else
7667c478bd9Sstevel@tonic-gate 		{
7677c478bd9Sstevel@tonic-gate 			TermEscape.te_rv_on = "";
7687c478bd9Sstevel@tonic-gate 			TermEscape.te_rv_off = "";
7697c478bd9Sstevel@tonic-gate 		}
7707c478bd9Sstevel@tonic-gate 	}
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	if (s == NULL)
7737c478bd9Sstevel@tonic-gate 	{
7747c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s<null>%s",
7757c478bd9Sstevel@tonic-gate 				     TermEscape.te_rv_on, TermEscape.te_rv_off);
7767c478bd9Sstevel@tonic-gate 		return;
7777c478bd9Sstevel@tonic-gate 	}
7787c478bd9Sstevel@tonic-gate 	while ((c = (*s++ & 0377)) != '\0')
7797c478bd9Sstevel@tonic-gate 	{
7807c478bd9Sstevel@tonic-gate 		if (shiftout)
7817c478bd9Sstevel@tonic-gate 		{
7827c478bd9Sstevel@tonic-gate 			(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s",
7837c478bd9Sstevel@tonic-gate 					     TermEscape.te_rv_off);
7847c478bd9Sstevel@tonic-gate 			shiftout = false;
7857c478bd9Sstevel@tonic-gate 		}
7867c478bd9Sstevel@tonic-gate 		if (!isascii(c))
7877c478bd9Sstevel@tonic-gate 		{
7887c478bd9Sstevel@tonic-gate 			if (c == MATCHREPL)
7897c478bd9Sstevel@tonic-gate 			{
7907c478bd9Sstevel@tonic-gate 				(void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
7917c478bd9Sstevel@tonic-gate 						     "%s$",
7927c478bd9Sstevel@tonic-gate 						     TermEscape.te_rv_on);
7937c478bd9Sstevel@tonic-gate 				shiftout = true;
7947c478bd9Sstevel@tonic-gate 				if (*s == '\0')
7957c478bd9Sstevel@tonic-gate 					continue;
7967c478bd9Sstevel@tonic-gate 				c = *s++ & 0377;
7977c478bd9Sstevel@tonic-gate 				goto printchar;
7987c478bd9Sstevel@tonic-gate 			}
7997c478bd9Sstevel@tonic-gate 			if (c == MACROEXPAND || c == MACRODEXPAND)
8007c478bd9Sstevel@tonic-gate 			{
8017c478bd9Sstevel@tonic-gate 				(void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
8027c478bd9Sstevel@tonic-gate 						     "%s$",
8037c478bd9Sstevel@tonic-gate 						     TermEscape.te_rv_on);
8047c478bd9Sstevel@tonic-gate 				if (c == MACRODEXPAND)
8057c478bd9Sstevel@tonic-gate 					(void) sm_io_putc(fp,
8067c478bd9Sstevel@tonic-gate 							  SM_TIME_DEFAULT, '&');
8077c478bd9Sstevel@tonic-gate 				shiftout = true;
8087c478bd9Sstevel@tonic-gate 				if (*s == '\0')
8097c478bd9Sstevel@tonic-gate 					continue;
8107c478bd9Sstevel@tonic-gate 				if (strchr("=~&?", *s) != NULL)
8117c478bd9Sstevel@tonic-gate 					(void) sm_io_putc(fp,
8127c478bd9Sstevel@tonic-gate 							  SM_TIME_DEFAULT,
8137c478bd9Sstevel@tonic-gate 							  *s++);
8147c478bd9Sstevel@tonic-gate 				if (bitset(0200, *s))
8157c478bd9Sstevel@tonic-gate 					(void) sm_io_fprintf(fp,
8167c478bd9Sstevel@tonic-gate 							     SM_TIME_DEFAULT,
8177c478bd9Sstevel@tonic-gate 							     "{%s}",
8187c478bd9Sstevel@tonic-gate 							     macname(bitidx(*s++)));
8197c478bd9Sstevel@tonic-gate 				else
8207c478bd9Sstevel@tonic-gate 					(void) sm_io_fprintf(fp,
8217c478bd9Sstevel@tonic-gate 							     SM_TIME_DEFAULT,
8227c478bd9Sstevel@tonic-gate 							     "%c",
8237c478bd9Sstevel@tonic-gate 							     *s++);
8247c478bd9Sstevel@tonic-gate 				continue;
8257c478bd9Sstevel@tonic-gate 			}
8267c478bd9Sstevel@tonic-gate 			for (mp = MetaMacros; mp->metaname != '\0'; mp++)
8277c478bd9Sstevel@tonic-gate 			{
8287c478bd9Sstevel@tonic-gate 				if (bitidx(mp->metaval) == c)
8297c478bd9Sstevel@tonic-gate 				{
8307c478bd9Sstevel@tonic-gate 					(void) sm_io_fprintf(fp,
8317c478bd9Sstevel@tonic-gate 							     SM_TIME_DEFAULT,
8327c478bd9Sstevel@tonic-gate 							     "%s$%c",
8337c478bd9Sstevel@tonic-gate 							     TermEscape.te_rv_on,
8347c478bd9Sstevel@tonic-gate 							     mp->metaname);
8357c478bd9Sstevel@tonic-gate 					shiftout = true;
8367c478bd9Sstevel@tonic-gate 					break;
8377c478bd9Sstevel@tonic-gate 				}
8387c478bd9Sstevel@tonic-gate 			}
8397c478bd9Sstevel@tonic-gate 			if (c == MATCHCLASS || c == MATCHNCLASS)
8407c478bd9Sstevel@tonic-gate 			{
8417c478bd9Sstevel@tonic-gate 				if (bitset(0200, *s))
8427c478bd9Sstevel@tonic-gate 					(void) sm_io_fprintf(fp,
8437c478bd9Sstevel@tonic-gate 							     SM_TIME_DEFAULT,
8447c478bd9Sstevel@tonic-gate 							     "{%s}",
8457c478bd9Sstevel@tonic-gate 							     macname(bitidx(*s++)));
8467c478bd9Sstevel@tonic-gate 				else if (*s != '\0')
8477c478bd9Sstevel@tonic-gate 					(void) sm_io_fprintf(fp,
8487c478bd9Sstevel@tonic-gate 							     SM_TIME_DEFAULT,
8497c478bd9Sstevel@tonic-gate 							     "%c",
8507c478bd9Sstevel@tonic-gate 							     *s++);
8517c478bd9Sstevel@tonic-gate 			}
8527c478bd9Sstevel@tonic-gate 			if (mp->metaname != '\0')
8537c478bd9Sstevel@tonic-gate 				continue;
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 			/* unrecognized meta character */
8567c478bd9Sstevel@tonic-gate 			(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%sM-",
8577c478bd9Sstevel@tonic-gate 					     TermEscape.te_rv_on);
8587c478bd9Sstevel@tonic-gate 			shiftout = true;
8597c478bd9Sstevel@tonic-gate 			c &= 0177;
8607c478bd9Sstevel@tonic-gate 		}
8617c478bd9Sstevel@tonic-gate   printchar:
8627c478bd9Sstevel@tonic-gate 		if (isprint(c))
8637c478bd9Sstevel@tonic-gate 		{
8647c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(fp, SM_TIME_DEFAULT, c);
8657c478bd9Sstevel@tonic-gate 			continue;
8667c478bd9Sstevel@tonic-gate 		}
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 		/* wasn't a meta-macro -- find another way to print it */
8697c478bd9Sstevel@tonic-gate 		switch (c)
8707c478bd9Sstevel@tonic-gate 		{
8717c478bd9Sstevel@tonic-gate 		  case '\n':
8727c478bd9Sstevel@tonic-gate 			c = 'n';
8737c478bd9Sstevel@tonic-gate 			break;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 		  case '\r':
8767c478bd9Sstevel@tonic-gate 			c = 'r';
8777c478bd9Sstevel@tonic-gate 			break;
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 		  case '\t':
8807c478bd9Sstevel@tonic-gate 			c = 't';
8817c478bd9Sstevel@tonic-gate 			break;
8827c478bd9Sstevel@tonic-gate 		}
8837c478bd9Sstevel@tonic-gate 		if (!shiftout)
8847c478bd9Sstevel@tonic-gate 		{
8857c478bd9Sstevel@tonic-gate 			(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s",
8867c478bd9Sstevel@tonic-gate 					     TermEscape.te_rv_on);
8877c478bd9Sstevel@tonic-gate 			shiftout = true;
8887c478bd9Sstevel@tonic-gate 		}
8897c478bd9Sstevel@tonic-gate 		if (isprint(c))
8907c478bd9Sstevel@tonic-gate 		{
8917c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(fp, SM_TIME_DEFAULT, '\\');
8927c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(fp, SM_TIME_DEFAULT, c);
8937c478bd9Sstevel@tonic-gate 		}
8947c478bd9Sstevel@tonic-gate 		else
8957c478bd9Sstevel@tonic-gate 		{
8967c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(fp, SM_TIME_DEFAULT, '^');
8977c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(fp, SM_TIME_DEFAULT, c ^ 0100);
8987c478bd9Sstevel@tonic-gate 		}
8997c478bd9Sstevel@tonic-gate 	}
9007c478bd9Sstevel@tonic-gate 	if (shiftout)
9017c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s",
9027c478bd9Sstevel@tonic-gate 				     TermEscape.te_rv_off);
9037c478bd9Sstevel@tonic-gate 	(void) sm_io_flush(fp, SM_TIME_DEFAULT);
9047c478bd9Sstevel@tonic-gate }
9057c478bd9Sstevel@tonic-gate /*
9067c478bd9Sstevel@tonic-gate **  MAKELOWER -- Translate a line into lower case
9077c478bd9Sstevel@tonic-gate **
9087c478bd9Sstevel@tonic-gate **	Parameters:
9097c478bd9Sstevel@tonic-gate **		p -- the string to translate.  If NULL, return is
9107c478bd9Sstevel@tonic-gate **			immediate.
9117c478bd9Sstevel@tonic-gate **
9127c478bd9Sstevel@tonic-gate **	Returns:
9137c478bd9Sstevel@tonic-gate **		none.
9147c478bd9Sstevel@tonic-gate **
9157c478bd9Sstevel@tonic-gate **	Side Effects:
9167c478bd9Sstevel@tonic-gate **		String pointed to by p is translated to lower case.
9177c478bd9Sstevel@tonic-gate */
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate void
9207c478bd9Sstevel@tonic-gate makelower(p)
9217c478bd9Sstevel@tonic-gate 	register char *p;
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate 	register char c;
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	if (p == NULL)
9267c478bd9Sstevel@tonic-gate 		return;
9277c478bd9Sstevel@tonic-gate 	for (; (c = *p) != '\0'; p++)
9287c478bd9Sstevel@tonic-gate 		if (isascii(c) && isupper(c))
9297c478bd9Sstevel@tonic-gate 			*p = tolower(c);
9307c478bd9Sstevel@tonic-gate }
9317c478bd9Sstevel@tonic-gate /*
9327c478bd9Sstevel@tonic-gate **  FIXCRLF -- fix <CR><LF> in line.
9337c478bd9Sstevel@tonic-gate **
9347c478bd9Sstevel@tonic-gate **	Looks for the <CR><LF> combination and turns it into the
9357c478bd9Sstevel@tonic-gate **	UNIX canonical <NL> character.  It only takes one line,
9367c478bd9Sstevel@tonic-gate **	i.e., it is assumed that the first <NL> found is the end
9377c478bd9Sstevel@tonic-gate **	of the line.
9387c478bd9Sstevel@tonic-gate **
9397c478bd9Sstevel@tonic-gate **	Parameters:
9407c478bd9Sstevel@tonic-gate **		line -- the line to fix.
9417c478bd9Sstevel@tonic-gate **		stripnl -- if true, strip the newline also.
9427c478bd9Sstevel@tonic-gate **
9437c478bd9Sstevel@tonic-gate **	Returns:
9447c478bd9Sstevel@tonic-gate **		none.
9457c478bd9Sstevel@tonic-gate **
9467c478bd9Sstevel@tonic-gate **	Side Effects:
9477c478bd9Sstevel@tonic-gate **		line is changed in place.
9487c478bd9Sstevel@tonic-gate */
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate void
9517c478bd9Sstevel@tonic-gate fixcrlf(line, stripnl)
9527c478bd9Sstevel@tonic-gate 	char *line;
9537c478bd9Sstevel@tonic-gate 	bool stripnl;
9547c478bd9Sstevel@tonic-gate {
9557c478bd9Sstevel@tonic-gate 	register char *p;
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	p = strchr(line, '\n');
9587c478bd9Sstevel@tonic-gate 	if (p == NULL)
9597c478bd9Sstevel@tonic-gate 		return;
9607c478bd9Sstevel@tonic-gate 	if (p > line && p[-1] == '\r')
9617c478bd9Sstevel@tonic-gate 		p--;
9627c478bd9Sstevel@tonic-gate 	if (!stripnl)
9637c478bd9Sstevel@tonic-gate 		*p++ = '\n';
9647c478bd9Sstevel@tonic-gate 	*p = '\0';
9657c478bd9Sstevel@tonic-gate }
9667c478bd9Sstevel@tonic-gate /*
9677c478bd9Sstevel@tonic-gate **  PUTLINE -- put a line like fputs obeying SMTP conventions
9687c478bd9Sstevel@tonic-gate **
9697c478bd9Sstevel@tonic-gate **	This routine always guarantees outputing a newline (or CRLF,
9707c478bd9Sstevel@tonic-gate **	as appropriate) at the end of the string.
9717c478bd9Sstevel@tonic-gate **
9727c478bd9Sstevel@tonic-gate **	Parameters:
9737c478bd9Sstevel@tonic-gate **		l -- line to put.
9747c478bd9Sstevel@tonic-gate **		mci -- the mailer connection information.
9757c478bd9Sstevel@tonic-gate **
9767c478bd9Sstevel@tonic-gate **	Returns:
977*445f2479Sjbeck **		true iff line was written successfully
9787c478bd9Sstevel@tonic-gate **
9797c478bd9Sstevel@tonic-gate **	Side Effects:
9807c478bd9Sstevel@tonic-gate **		output of l to mci->mci_out.
9817c478bd9Sstevel@tonic-gate */
9827c478bd9Sstevel@tonic-gate 
983*445f2479Sjbeck bool
9847c478bd9Sstevel@tonic-gate putline(l, mci)
9857c478bd9Sstevel@tonic-gate 	register char *l;
9867c478bd9Sstevel@tonic-gate 	register MCI *mci;
9877c478bd9Sstevel@tonic-gate {
988*445f2479Sjbeck 	return putxline(l, strlen(l), mci, PXLF_MAPFROM);
9897c478bd9Sstevel@tonic-gate }
9907c478bd9Sstevel@tonic-gate /*
9917c478bd9Sstevel@tonic-gate **  PUTXLINE -- putline with flags bits.
9927c478bd9Sstevel@tonic-gate **
9937c478bd9Sstevel@tonic-gate **	This routine always guarantees outputing a newline (or CRLF,
9947c478bd9Sstevel@tonic-gate **	as appropriate) at the end of the string.
9957c478bd9Sstevel@tonic-gate **
9967c478bd9Sstevel@tonic-gate **	Parameters:
9977c478bd9Sstevel@tonic-gate **		l -- line to put.
9987c478bd9Sstevel@tonic-gate **		len -- the length of the line.
9997c478bd9Sstevel@tonic-gate **		mci -- the mailer connection information.
10007c478bd9Sstevel@tonic-gate **		pxflags -- flag bits:
10017c478bd9Sstevel@tonic-gate **		    PXLF_MAPFROM -- map From_ to >From_.
10027c478bd9Sstevel@tonic-gate **		    PXLF_STRIP8BIT -- strip 8th bit.
10037c478bd9Sstevel@tonic-gate **		    PXLF_HEADER -- map bare newline in header to newline space.
10047c478bd9Sstevel@tonic-gate **		    PXLF_NOADDEOL -- don't add an EOL if one wasn't present.
10057c478bd9Sstevel@tonic-gate **
10067c478bd9Sstevel@tonic-gate **	Returns:
1007*445f2479Sjbeck **		true iff line was written successfully
10087c478bd9Sstevel@tonic-gate **
10097c478bd9Sstevel@tonic-gate **	Side Effects:
10107c478bd9Sstevel@tonic-gate **		output of l to mci->mci_out.
10117c478bd9Sstevel@tonic-gate */
10127c478bd9Sstevel@tonic-gate 
1013*445f2479Sjbeck bool
10147c478bd9Sstevel@tonic-gate putxline(l, len, mci, pxflags)
10157c478bd9Sstevel@tonic-gate 	register char *l;
10167c478bd9Sstevel@tonic-gate 	size_t len;
10177c478bd9Sstevel@tonic-gate 	register MCI *mci;
10187c478bd9Sstevel@tonic-gate 	int pxflags;
10197c478bd9Sstevel@tonic-gate {
10207c478bd9Sstevel@tonic-gate 	bool dead = false;
10217c478bd9Sstevel@tonic-gate 	register char *p, *end;
10227c478bd9Sstevel@tonic-gate 	int slop = 0;
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	/* strip out 0200 bits -- these can look like TELNET protocol */
10257c478bd9Sstevel@tonic-gate 	if (bitset(MCIF_7BIT, mci->mci_flags) ||
10267c478bd9Sstevel@tonic-gate 	    bitset(PXLF_STRIP8BIT, pxflags))
10277c478bd9Sstevel@tonic-gate 	{
10287c478bd9Sstevel@tonic-gate 		register char svchar;
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 		for (p = l; (svchar = *p) != '\0'; ++p)
10317c478bd9Sstevel@tonic-gate 			if (bitset(0200, svchar))
10327c478bd9Sstevel@tonic-gate 				*p = svchar &~ 0200;
10337c478bd9Sstevel@tonic-gate 	}
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	end = l + len;
10367c478bd9Sstevel@tonic-gate 	do
10377c478bd9Sstevel@tonic-gate 	{
10387c478bd9Sstevel@tonic-gate 		bool noeol = false;
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 		/* find the end of the line */
10417c478bd9Sstevel@tonic-gate 		p = memchr(l, '\n', end - l);
10427c478bd9Sstevel@tonic-gate 		if (p == NULL)
10437c478bd9Sstevel@tonic-gate 		{
10447c478bd9Sstevel@tonic-gate 			p = end;
10457c478bd9Sstevel@tonic-gate 			noeol = true;
10467c478bd9Sstevel@tonic-gate 		}
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 		if (TrafficLogFile != NULL)
10497c478bd9Sstevel@tonic-gate 			(void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
10507c478bd9Sstevel@tonic-gate 					     "%05d >>> ", (int) CurrentPid);
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 		/* check for line overflow */
10537c478bd9Sstevel@tonic-gate 		while (mci->mci_mailer->m_linelimit > 0 &&
10547c478bd9Sstevel@tonic-gate 		       (p - l + slop) > mci->mci_mailer->m_linelimit)
10557c478bd9Sstevel@tonic-gate 		{
10567c478bd9Sstevel@tonic-gate 			char *l_base = l;
10577c478bd9Sstevel@tonic-gate 			register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1];
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 			if (l[0] == '.' && slop == 0 &&
10607c478bd9Sstevel@tonic-gate 			    bitnset(M_XDOT, mci->mci_mailer->m_flags))
10617c478bd9Sstevel@tonic-gate 			{
10627c478bd9Sstevel@tonic-gate 				if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
10637c478bd9Sstevel@tonic-gate 					       '.') == SM_IO_EOF)
10647c478bd9Sstevel@tonic-gate 					dead = true;
10657c478bd9Sstevel@tonic-gate 				if (TrafficLogFile != NULL)
10667c478bd9Sstevel@tonic-gate 					(void) sm_io_putc(TrafficLogFile,
10677c478bd9Sstevel@tonic-gate 							  SM_TIME_DEFAULT, '.');
10687c478bd9Sstevel@tonic-gate 			}
10697c478bd9Sstevel@tonic-gate 			else if (l[0] == 'F' && slop == 0 &&
10707c478bd9Sstevel@tonic-gate 				 bitset(PXLF_MAPFROM, pxflags) &&
10717c478bd9Sstevel@tonic-gate 				 strncmp(l, "From ", 5) == 0 &&
10727c478bd9Sstevel@tonic-gate 				 bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
10737c478bd9Sstevel@tonic-gate 			{
10747c478bd9Sstevel@tonic-gate 				if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
10757c478bd9Sstevel@tonic-gate 					       '>') == SM_IO_EOF)
10767c478bd9Sstevel@tonic-gate 					dead = true;
10777c478bd9Sstevel@tonic-gate 				if (TrafficLogFile != NULL)
10787c478bd9Sstevel@tonic-gate 					(void) sm_io_putc(TrafficLogFile,
10797c478bd9Sstevel@tonic-gate 							  SM_TIME_DEFAULT,
10807c478bd9Sstevel@tonic-gate 							  '>');
10817c478bd9Sstevel@tonic-gate 			}
10827c478bd9Sstevel@tonic-gate 			if (dead)
10837c478bd9Sstevel@tonic-gate 				break;
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 			while (l < q)
10867c478bd9Sstevel@tonic-gate 			{
10877c478bd9Sstevel@tonic-gate 				if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
1088*445f2479Sjbeck 				       (unsigned char) *l++) == SM_IO_EOF)
10897c478bd9Sstevel@tonic-gate 				{
10907c478bd9Sstevel@tonic-gate 					dead = true;
10917c478bd9Sstevel@tonic-gate 					break;
10927c478bd9Sstevel@tonic-gate 				}
10937c478bd9Sstevel@tonic-gate 			}
10947c478bd9Sstevel@tonic-gate 			if (dead)
10957c478bd9Sstevel@tonic-gate 				break;
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 			if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, '!') ==
10987c478bd9Sstevel@tonic-gate 			    SM_IO_EOF ||
10997c478bd9Sstevel@tonic-gate 			    sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT,
11007c478bd9Sstevel@tonic-gate 					mci->mci_mailer->m_eol) ==
11017c478bd9Sstevel@tonic-gate 			    SM_IO_EOF ||
11027c478bd9Sstevel@tonic-gate 			    sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, ' ') ==
11037c478bd9Sstevel@tonic-gate 			    SM_IO_EOF)
11047c478bd9Sstevel@tonic-gate 			{
11057c478bd9Sstevel@tonic-gate 				dead = true;
11067c478bd9Sstevel@tonic-gate 				break;
11077c478bd9Sstevel@tonic-gate 			}
11087c478bd9Sstevel@tonic-gate 			if (TrafficLogFile != NULL)
11097c478bd9Sstevel@tonic-gate 			{
11107c478bd9Sstevel@tonic-gate 				for (l = l_base; l < q; l++)
11117c478bd9Sstevel@tonic-gate 					(void) sm_io_putc(TrafficLogFile,
11127c478bd9Sstevel@tonic-gate 							  SM_TIME_DEFAULT,
11137c478bd9Sstevel@tonic-gate 							  (unsigned char)*l);
11147c478bd9Sstevel@tonic-gate 				(void) sm_io_fprintf(TrafficLogFile,
11157c478bd9Sstevel@tonic-gate 						     SM_TIME_DEFAULT,
11167c478bd9Sstevel@tonic-gate 						     "!\n%05d >>>  ",
11177c478bd9Sstevel@tonic-gate 						     (int) CurrentPid);
11187c478bd9Sstevel@tonic-gate 			}
11197c478bd9Sstevel@tonic-gate 			slop = 1;
11207c478bd9Sstevel@tonic-gate 		}
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate 		if (dead)
11237c478bd9Sstevel@tonic-gate 			break;
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 		/* output last part */
11267c478bd9Sstevel@tonic-gate 		if (l[0] == '.' && slop == 0 &&
11277c478bd9Sstevel@tonic-gate 		    bitnset(M_XDOT, mci->mci_mailer->m_flags))
11287c478bd9Sstevel@tonic-gate 		{
11297c478bd9Sstevel@tonic-gate 			if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, '.') ==
11307c478bd9Sstevel@tonic-gate 			    SM_IO_EOF)
11317c478bd9Sstevel@tonic-gate 			{
1132*445f2479Sjbeck 				dead = true;
1133*445f2479Sjbeck 				break;
11347c478bd9Sstevel@tonic-gate 			}
11357c478bd9Sstevel@tonic-gate 			if (TrafficLogFile != NULL)
11367c478bd9Sstevel@tonic-gate 				(void) sm_io_putc(TrafficLogFile,
11377c478bd9Sstevel@tonic-gate 						  SM_TIME_DEFAULT, '.');
11387c478bd9Sstevel@tonic-gate 		}
11397c478bd9Sstevel@tonic-gate 		else if (l[0] == 'F' && slop == 0 &&
11407c478bd9Sstevel@tonic-gate 			 bitset(PXLF_MAPFROM, pxflags) &&
11417c478bd9Sstevel@tonic-gate 			 strncmp(l, "From ", 5) == 0 &&
11427c478bd9Sstevel@tonic-gate 			 bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
11437c478bd9Sstevel@tonic-gate 		{
11447c478bd9Sstevel@tonic-gate 			if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, '>') ==
11457c478bd9Sstevel@tonic-gate 			    SM_IO_EOF)
11467c478bd9Sstevel@tonic-gate 			{
1147*445f2479Sjbeck 				dead = true;
1148*445f2479Sjbeck 				break;
11497c478bd9Sstevel@tonic-gate 			}
11507c478bd9Sstevel@tonic-gate 			if (TrafficLogFile != NULL)
11517c478bd9Sstevel@tonic-gate 				(void) sm_io_putc(TrafficLogFile,
11527c478bd9Sstevel@tonic-gate 						  SM_TIME_DEFAULT, '>');
11537c478bd9Sstevel@tonic-gate 		}
11547c478bd9Sstevel@tonic-gate 		for ( ; l < p; ++l)
11557c478bd9Sstevel@tonic-gate 		{
11567c478bd9Sstevel@tonic-gate 			if (TrafficLogFile != NULL)
11577c478bd9Sstevel@tonic-gate 				(void) sm_io_putc(TrafficLogFile,
11587c478bd9Sstevel@tonic-gate 						  SM_TIME_DEFAULT,
11597c478bd9Sstevel@tonic-gate 						  (unsigned char)*l);
11607c478bd9Sstevel@tonic-gate 			if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
11617c478bd9Sstevel@tonic-gate 				       (unsigned char) *l) == SM_IO_EOF)
11627c478bd9Sstevel@tonic-gate 			{
11637c478bd9Sstevel@tonic-gate 				dead = true;
11647c478bd9Sstevel@tonic-gate 				break;
11657c478bd9Sstevel@tonic-gate 			}
11667c478bd9Sstevel@tonic-gate 		}
11677c478bd9Sstevel@tonic-gate 		if (dead)
11687c478bd9Sstevel@tonic-gate 			break;
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 		if (TrafficLogFile != NULL)
11717c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(TrafficLogFile, SM_TIME_DEFAULT,
11727c478bd9Sstevel@tonic-gate 					  '\n');
11737c478bd9Sstevel@tonic-gate 		if ((!bitset(PXLF_NOADDEOL, pxflags) || !noeol) &&
11747c478bd9Sstevel@tonic-gate 		    sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT,
11757c478bd9Sstevel@tonic-gate 				mci->mci_mailer->m_eol) == SM_IO_EOF)
11767c478bd9Sstevel@tonic-gate 		{
1177*445f2479Sjbeck 			dead = true;
1178*445f2479Sjbeck 			break;
11797c478bd9Sstevel@tonic-gate 		}
11807c478bd9Sstevel@tonic-gate 		if (l < end && *l == '\n')
11817c478bd9Sstevel@tonic-gate 		{
11827c478bd9Sstevel@tonic-gate 			if (*++l != ' ' && *l != '\t' && *l != '\0' &&
11837c478bd9Sstevel@tonic-gate 			    bitset(PXLF_HEADER, pxflags))
11847c478bd9Sstevel@tonic-gate 			{
11857c478bd9Sstevel@tonic-gate 				if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
11867c478bd9Sstevel@tonic-gate 					       ' ') == SM_IO_EOF)
11877c478bd9Sstevel@tonic-gate 				{
1188*445f2479Sjbeck 					dead = true;
1189*445f2479Sjbeck 					break;
11907c478bd9Sstevel@tonic-gate 				}
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 				if (TrafficLogFile != NULL)
11937c478bd9Sstevel@tonic-gate 					(void) sm_io_putc(TrafficLogFile,
11947c478bd9Sstevel@tonic-gate 							  SM_TIME_DEFAULT, ' ');
11957c478bd9Sstevel@tonic-gate 			}
11967c478bd9Sstevel@tonic-gate 		}
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 	} while (l < end);
1199*445f2479Sjbeck 	return !dead;
12007c478bd9Sstevel@tonic-gate }
1201*445f2479Sjbeck 
12027c478bd9Sstevel@tonic-gate /*
12037c478bd9Sstevel@tonic-gate **  XUNLINK -- unlink a file, doing logging as appropriate.
12047c478bd9Sstevel@tonic-gate **
12057c478bd9Sstevel@tonic-gate **	Parameters:
12067c478bd9Sstevel@tonic-gate **		f -- name of file to unlink.
12077c478bd9Sstevel@tonic-gate **
12087c478bd9Sstevel@tonic-gate **	Returns:
12097c478bd9Sstevel@tonic-gate **		return value of unlink()
12107c478bd9Sstevel@tonic-gate **
12117c478bd9Sstevel@tonic-gate **	Side Effects:
12127c478bd9Sstevel@tonic-gate **		f is unlinked.
12137c478bd9Sstevel@tonic-gate */
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate int
12167c478bd9Sstevel@tonic-gate xunlink(f)
12177c478bd9Sstevel@tonic-gate 	char *f;
12187c478bd9Sstevel@tonic-gate {
12197c478bd9Sstevel@tonic-gate 	register int i;
12207c478bd9Sstevel@tonic-gate 	int save_errno;
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	if (LogLevel > 98)
12237c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_DEBUG, CurEnv->e_id, "unlink %s", f);
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 	i = unlink(f);
12267c478bd9Sstevel@tonic-gate 	save_errno = errno;
12277c478bd9Sstevel@tonic-gate 	if (i < 0 && LogLevel > 97)
12287c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s: unlink-fail %d",
12297c478bd9Sstevel@tonic-gate 			  f, errno);
12307c478bd9Sstevel@tonic-gate 	if (i >= 0)
12317c478bd9Sstevel@tonic-gate 		SYNC_DIR(f, false);
12327c478bd9Sstevel@tonic-gate 	errno = save_errno;
12337c478bd9Sstevel@tonic-gate 	return i;
12347c478bd9Sstevel@tonic-gate }
12357c478bd9Sstevel@tonic-gate /*
12367c478bd9Sstevel@tonic-gate **  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
12377c478bd9Sstevel@tonic-gate **
12387c478bd9Sstevel@tonic-gate **	Parameters:
12397c478bd9Sstevel@tonic-gate **		buf -- place to put the input line.
12407c478bd9Sstevel@tonic-gate **		siz -- size of buf.
12417c478bd9Sstevel@tonic-gate **		fp -- file to read from.
12427c478bd9Sstevel@tonic-gate **		timeout -- the timeout before error occurs.
12437c478bd9Sstevel@tonic-gate **		during -- what we are trying to read (for error messages).
12447c478bd9Sstevel@tonic-gate **
12457c478bd9Sstevel@tonic-gate **	Returns:
12467c478bd9Sstevel@tonic-gate **		NULL on error (including timeout).  This may also leave
12477c478bd9Sstevel@tonic-gate **			buf containing a null string.
12487c478bd9Sstevel@tonic-gate **		buf otherwise.
12497c478bd9Sstevel@tonic-gate */
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate char *
12537c478bd9Sstevel@tonic-gate sfgets(buf, siz, fp, timeout, during)
12547c478bd9Sstevel@tonic-gate 	char *buf;
12557c478bd9Sstevel@tonic-gate 	int siz;
12567c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
12577c478bd9Sstevel@tonic-gate 	time_t timeout;
12587c478bd9Sstevel@tonic-gate 	char *during;
12597c478bd9Sstevel@tonic-gate {
12607c478bd9Sstevel@tonic-gate 	register char *p;
12617c478bd9Sstevel@tonic-gate 	int save_errno;
12627c478bd9Sstevel@tonic-gate 	int io_timeout;
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 	SM_REQUIRE(siz > 0);
12657c478bd9Sstevel@tonic-gate 	SM_REQUIRE(buf != NULL);
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	if (fp == NULL)
12687c478bd9Sstevel@tonic-gate 	{
12697c478bd9Sstevel@tonic-gate 		buf[0] = '\0';
12707c478bd9Sstevel@tonic-gate 		errno = EBADF;
12717c478bd9Sstevel@tonic-gate 		return NULL;
12727c478bd9Sstevel@tonic-gate 	}
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	/* try to read */
12757c478bd9Sstevel@tonic-gate 	p = NULL;
12767c478bd9Sstevel@tonic-gate 	errno = 0;
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 	/* convert the timeout to sm_io notation */
12797c478bd9Sstevel@tonic-gate 	io_timeout = (timeout <= 0) ? SM_TIME_DEFAULT : timeout * 1000;
12807c478bd9Sstevel@tonic-gate 	while (!sm_io_eof(fp) && !sm_io_error(fp))
12817c478bd9Sstevel@tonic-gate 	{
12827c478bd9Sstevel@tonic-gate 		errno = 0;
12837c478bd9Sstevel@tonic-gate 		p = sm_io_fgets(fp, io_timeout, buf, siz);
12847c478bd9Sstevel@tonic-gate 		if (p == NULL && errno == EAGAIN)
12857c478bd9Sstevel@tonic-gate 		{
12867c478bd9Sstevel@tonic-gate 			/* The sm_io_fgets() call timedout */
12877c478bd9Sstevel@tonic-gate 			if (LogLevel > 1)
12887c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_NOTICE, CurEnv->e_id,
12897c478bd9Sstevel@tonic-gate 					  "timeout waiting for input from %.100s during %s",
12907c478bd9Sstevel@tonic-gate 					  CURHOSTNAME,
12917c478bd9Sstevel@tonic-gate 					  during);
12927c478bd9Sstevel@tonic-gate 			buf[0] = '\0';
12937c478bd9Sstevel@tonic-gate #if XDEBUG
12947c478bd9Sstevel@tonic-gate 			checkfd012(during);
12957c478bd9Sstevel@tonic-gate #endif /* XDEBUG */
12967c478bd9Sstevel@tonic-gate 			if (TrafficLogFile != NULL)
12977c478bd9Sstevel@tonic-gate 				(void) sm_io_fprintf(TrafficLogFile,
12987c478bd9Sstevel@tonic-gate 						     SM_TIME_DEFAULT,
12997c478bd9Sstevel@tonic-gate 						     "%05d <<< [TIMEOUT]\n",
13007c478bd9Sstevel@tonic-gate 						     (int) CurrentPid);
13017c478bd9Sstevel@tonic-gate 			errno = ETIMEDOUT;
13027c478bd9Sstevel@tonic-gate 			return NULL;
13037c478bd9Sstevel@tonic-gate 		}
13047c478bd9Sstevel@tonic-gate 		if (p != NULL || errno != EINTR)
13057c478bd9Sstevel@tonic-gate 			break;
13067c478bd9Sstevel@tonic-gate 		(void) sm_io_clearerr(fp);
13077c478bd9Sstevel@tonic-gate 	}
13087c478bd9Sstevel@tonic-gate 	save_errno = errno;
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 	/* clean up the books and exit */
13117c478bd9Sstevel@tonic-gate 	LineNumber++;
13127c478bd9Sstevel@tonic-gate 	if (p == NULL)
13137c478bd9Sstevel@tonic-gate 	{
13147c478bd9Sstevel@tonic-gate 		buf[0] = '\0';
13157c478bd9Sstevel@tonic-gate 		if (TrafficLogFile != NULL)
13167c478bd9Sstevel@tonic-gate 			(void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
13177c478bd9Sstevel@tonic-gate 					     "%05d <<< [EOF]\n",
13187c478bd9Sstevel@tonic-gate 					     (int) CurrentPid);
13197c478bd9Sstevel@tonic-gate 		errno = save_errno;
13207c478bd9Sstevel@tonic-gate 		return NULL;
13217c478bd9Sstevel@tonic-gate 	}
13227c478bd9Sstevel@tonic-gate 	if (TrafficLogFile != NULL)
13237c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
13247c478bd9Sstevel@tonic-gate 				     "%05d <<< %s", (int) CurrentPid, buf);
13257c478bd9Sstevel@tonic-gate 	if (SevenBitInput)
13267c478bd9Sstevel@tonic-gate 	{
13277c478bd9Sstevel@tonic-gate 		for (p = buf; *p != '\0'; p++)
13287c478bd9Sstevel@tonic-gate 			*p &= ~0200;
13297c478bd9Sstevel@tonic-gate 	}
13307c478bd9Sstevel@tonic-gate 	else if (!HasEightBits)
13317c478bd9Sstevel@tonic-gate 	{
13327c478bd9Sstevel@tonic-gate 		for (p = buf; *p != '\0'; p++)
13337c478bd9Sstevel@tonic-gate 		{
13347c478bd9Sstevel@tonic-gate 			if (bitset(0200, *p))
13357c478bd9Sstevel@tonic-gate 			{
13367c478bd9Sstevel@tonic-gate 				HasEightBits = true;
13377c478bd9Sstevel@tonic-gate 				break;
13387c478bd9Sstevel@tonic-gate 			}
13397c478bd9Sstevel@tonic-gate 		}
13407c478bd9Sstevel@tonic-gate 	}
13417c478bd9Sstevel@tonic-gate 	return buf;
13427c478bd9Sstevel@tonic-gate }
13437c478bd9Sstevel@tonic-gate /*
13447c478bd9Sstevel@tonic-gate **  FGETFOLDED -- like fgets, but knows about folded lines.
13457c478bd9Sstevel@tonic-gate **
13467c478bd9Sstevel@tonic-gate **	Parameters:
13477c478bd9Sstevel@tonic-gate **		buf -- place to put result.
13487c478bd9Sstevel@tonic-gate **		n -- bytes available.
13497c478bd9Sstevel@tonic-gate **		f -- file to read from.
13507c478bd9Sstevel@tonic-gate **
13517c478bd9Sstevel@tonic-gate **	Returns:
13527c478bd9Sstevel@tonic-gate **		input line(s) on success, NULL on error or SM_IO_EOF.
13537c478bd9Sstevel@tonic-gate **		This will normally be buf -- unless the line is too
13547c478bd9Sstevel@tonic-gate **			long, when it will be sm_malloc_x()ed.
13557c478bd9Sstevel@tonic-gate **
13567c478bd9Sstevel@tonic-gate **	Side Effects:
13577c478bd9Sstevel@tonic-gate **		buf gets lines from f, with continuation lines (lines
13587c478bd9Sstevel@tonic-gate **		with leading white space) appended.  CRLF's are mapped
13597c478bd9Sstevel@tonic-gate **		into single newlines.  Any trailing NL is stripped.
13607c478bd9Sstevel@tonic-gate */
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate char *
13637c478bd9Sstevel@tonic-gate fgetfolded(buf, n, f)
13647c478bd9Sstevel@tonic-gate 	char *buf;
13657c478bd9Sstevel@tonic-gate 	register int n;
13667c478bd9Sstevel@tonic-gate 	SM_FILE_T *f;
13677c478bd9Sstevel@tonic-gate {
13687c478bd9Sstevel@tonic-gate 	register char *p = buf;
13697c478bd9Sstevel@tonic-gate 	char *bp = buf;
13707c478bd9Sstevel@tonic-gate 	register int i;
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 	SM_REQUIRE(n > 0);
13737c478bd9Sstevel@tonic-gate 	SM_REQUIRE(buf != NULL);
13747c478bd9Sstevel@tonic-gate 	if (f == NULL)
13757c478bd9Sstevel@tonic-gate 	{
13767c478bd9Sstevel@tonic-gate 		buf[0] = '\0';
13777c478bd9Sstevel@tonic-gate 		errno = EBADF;
13787c478bd9Sstevel@tonic-gate 		return NULL;
13797c478bd9Sstevel@tonic-gate 	}
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	n--;
13827c478bd9Sstevel@tonic-gate 	while ((i = sm_io_getc(f, SM_TIME_DEFAULT)) != SM_IO_EOF)
13837c478bd9Sstevel@tonic-gate 	{
13847c478bd9Sstevel@tonic-gate 		if (i == '\r')
13857c478bd9Sstevel@tonic-gate 		{
13867c478bd9Sstevel@tonic-gate 			i = sm_io_getc(f, SM_TIME_DEFAULT);
13877c478bd9Sstevel@tonic-gate 			if (i != '\n')
13887c478bd9Sstevel@tonic-gate 			{
13897c478bd9Sstevel@tonic-gate 				if (i != SM_IO_EOF)
13907c478bd9Sstevel@tonic-gate 					(void) sm_io_ungetc(f, SM_TIME_DEFAULT,
13917c478bd9Sstevel@tonic-gate 							    i);
13927c478bd9Sstevel@tonic-gate 				i = '\r';
13937c478bd9Sstevel@tonic-gate 			}
13947c478bd9Sstevel@tonic-gate 		}
13957c478bd9Sstevel@tonic-gate 		if (--n <= 0)
13967c478bd9Sstevel@tonic-gate 		{
13977c478bd9Sstevel@tonic-gate 			/* allocate new space */
13987c478bd9Sstevel@tonic-gate 			char *nbp;
13997c478bd9Sstevel@tonic-gate 			int nn;
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 			nn = (p - bp);
14027c478bd9Sstevel@tonic-gate 			if (nn < MEMCHUNKSIZE)
14037c478bd9Sstevel@tonic-gate 				nn *= 2;
14047c478bd9Sstevel@tonic-gate 			else
14057c478bd9Sstevel@tonic-gate 				nn += MEMCHUNKSIZE;
14067c478bd9Sstevel@tonic-gate 			nbp = sm_malloc_x(nn);
14077c478bd9Sstevel@tonic-gate 			memmove(nbp, bp, p - bp);
14087c478bd9Sstevel@tonic-gate 			p = &nbp[p - bp];
14097c478bd9Sstevel@tonic-gate 			if (bp != buf)
14107c478bd9Sstevel@tonic-gate 				sm_free(bp);
14117c478bd9Sstevel@tonic-gate 			bp = nbp;
14127c478bd9Sstevel@tonic-gate 			n = nn - (p - bp);
14137c478bd9Sstevel@tonic-gate 		}
14147c478bd9Sstevel@tonic-gate 		*p++ = i;
14157c478bd9Sstevel@tonic-gate 		if (i == '\n')
14167c478bd9Sstevel@tonic-gate 		{
14177c478bd9Sstevel@tonic-gate 			LineNumber++;
14187c478bd9Sstevel@tonic-gate 			i = sm_io_getc(f, SM_TIME_DEFAULT);
14197c478bd9Sstevel@tonic-gate 			if (i != SM_IO_EOF)
14207c478bd9Sstevel@tonic-gate 				(void) sm_io_ungetc(f, SM_TIME_DEFAULT, i);
14217c478bd9Sstevel@tonic-gate 			if (i != ' ' && i != '\t')
14227c478bd9Sstevel@tonic-gate 				break;
14237c478bd9Sstevel@tonic-gate 		}
14247c478bd9Sstevel@tonic-gate 	}
14257c478bd9Sstevel@tonic-gate 	if (p == bp)
14267c478bd9Sstevel@tonic-gate 		return NULL;
14277c478bd9Sstevel@tonic-gate 	if (p[-1] == '\n')
14287c478bd9Sstevel@tonic-gate 		p--;
14297c478bd9Sstevel@tonic-gate 	*p = '\0';
14307c478bd9Sstevel@tonic-gate 	return bp;
14317c478bd9Sstevel@tonic-gate }
14327c478bd9Sstevel@tonic-gate /*
14337c478bd9Sstevel@tonic-gate **  CURTIME -- return current time.
14347c478bd9Sstevel@tonic-gate **
14357c478bd9Sstevel@tonic-gate **	Parameters:
14367c478bd9Sstevel@tonic-gate **		none.
14377c478bd9Sstevel@tonic-gate **
14387c478bd9Sstevel@tonic-gate **	Returns:
14397c478bd9Sstevel@tonic-gate **		the current time.
14407c478bd9Sstevel@tonic-gate */
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate time_t
14437c478bd9Sstevel@tonic-gate curtime()
14447c478bd9Sstevel@tonic-gate {
14457c478bd9Sstevel@tonic-gate 	auto time_t t;
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	(void) time(&t);
14487c478bd9Sstevel@tonic-gate 	return t;
14497c478bd9Sstevel@tonic-gate }
14507c478bd9Sstevel@tonic-gate /*
14517c478bd9Sstevel@tonic-gate **  ATOBOOL -- convert a string representation to boolean.
14527c478bd9Sstevel@tonic-gate **
14537c478bd9Sstevel@tonic-gate **	Defaults to false
14547c478bd9Sstevel@tonic-gate **
14557c478bd9Sstevel@tonic-gate **	Parameters:
14567c478bd9Sstevel@tonic-gate **		s -- string to convert.  Takes "tTyY", empty, and NULL as true,
14577c478bd9Sstevel@tonic-gate **			others as false.
14587c478bd9Sstevel@tonic-gate **
14597c478bd9Sstevel@tonic-gate **	Returns:
14607c478bd9Sstevel@tonic-gate **		A boolean representation of the string.
14617c478bd9Sstevel@tonic-gate */
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate bool
14647c478bd9Sstevel@tonic-gate atobool(s)
14657c478bd9Sstevel@tonic-gate 	register char *s;
14667c478bd9Sstevel@tonic-gate {
14677c478bd9Sstevel@tonic-gate 	if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL)
14687c478bd9Sstevel@tonic-gate 		return true;
14697c478bd9Sstevel@tonic-gate 	return false;
14707c478bd9Sstevel@tonic-gate }
14717c478bd9Sstevel@tonic-gate /*
14727c478bd9Sstevel@tonic-gate **  ATOOCT -- convert a string representation to octal.
14737c478bd9Sstevel@tonic-gate **
14747c478bd9Sstevel@tonic-gate **	Parameters:
14757c478bd9Sstevel@tonic-gate **		s -- string to convert.
14767c478bd9Sstevel@tonic-gate **
14777c478bd9Sstevel@tonic-gate **	Returns:
14787c478bd9Sstevel@tonic-gate **		An integer representing the string interpreted as an
14797c478bd9Sstevel@tonic-gate **		octal number.
14807c478bd9Sstevel@tonic-gate */
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate int
14837c478bd9Sstevel@tonic-gate atooct(s)
14847c478bd9Sstevel@tonic-gate 	register char *s;
14857c478bd9Sstevel@tonic-gate {
14867c478bd9Sstevel@tonic-gate 	register int i = 0;
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 	while (*s >= '0' && *s <= '7')
14897c478bd9Sstevel@tonic-gate 		i = (i << 3) | (*s++ - '0');
14907c478bd9Sstevel@tonic-gate 	return i;
14917c478bd9Sstevel@tonic-gate }
14927c478bd9Sstevel@tonic-gate /*
14937c478bd9Sstevel@tonic-gate **  BITINTERSECT -- tell if two bitmaps intersect
14947c478bd9Sstevel@tonic-gate **
14957c478bd9Sstevel@tonic-gate **	Parameters:
14967c478bd9Sstevel@tonic-gate **		a, b -- the bitmaps in question
14977c478bd9Sstevel@tonic-gate **
14987c478bd9Sstevel@tonic-gate **	Returns:
14997c478bd9Sstevel@tonic-gate **		true if they have a non-null intersection
15007c478bd9Sstevel@tonic-gate **		false otherwise
15017c478bd9Sstevel@tonic-gate */
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate bool
15047c478bd9Sstevel@tonic-gate bitintersect(a, b)
15057c478bd9Sstevel@tonic-gate 	BITMAP256 a;
15067c478bd9Sstevel@tonic-gate 	BITMAP256 b;
15077c478bd9Sstevel@tonic-gate {
15087c478bd9Sstevel@tonic-gate 	int i;
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
15117c478bd9Sstevel@tonic-gate 	{
15127c478bd9Sstevel@tonic-gate 		if ((a[i] & b[i]) != 0)
15137c478bd9Sstevel@tonic-gate 			return true;
15147c478bd9Sstevel@tonic-gate 	}
15157c478bd9Sstevel@tonic-gate 	return false;
15167c478bd9Sstevel@tonic-gate }
15177c478bd9Sstevel@tonic-gate /*
15187c478bd9Sstevel@tonic-gate **  BITZEROP -- tell if a bitmap is all zero
15197c478bd9Sstevel@tonic-gate **
15207c478bd9Sstevel@tonic-gate **	Parameters:
15217c478bd9Sstevel@tonic-gate **		map -- the bit map to check
15227c478bd9Sstevel@tonic-gate **
15237c478bd9Sstevel@tonic-gate **	Returns:
15247c478bd9Sstevel@tonic-gate **		true if map is all zero.
15257c478bd9Sstevel@tonic-gate **		false if there are any bits set in map.
15267c478bd9Sstevel@tonic-gate */
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate bool
15297c478bd9Sstevel@tonic-gate bitzerop(map)
15307c478bd9Sstevel@tonic-gate 	BITMAP256 map;
15317c478bd9Sstevel@tonic-gate {
15327c478bd9Sstevel@tonic-gate 	int i;
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
15357c478bd9Sstevel@tonic-gate 	{
15367c478bd9Sstevel@tonic-gate 		if (map[i] != 0)
15377c478bd9Sstevel@tonic-gate 			return false;
15387c478bd9Sstevel@tonic-gate 	}
15397c478bd9Sstevel@tonic-gate 	return true;
15407c478bd9Sstevel@tonic-gate }
15417c478bd9Sstevel@tonic-gate /*
15427c478bd9Sstevel@tonic-gate **  STRCONTAINEDIN -- tell if one string is contained in another
15437c478bd9Sstevel@tonic-gate **
15447c478bd9Sstevel@tonic-gate **	Parameters:
15457c478bd9Sstevel@tonic-gate **		icase -- ignore case?
15467c478bd9Sstevel@tonic-gate **		a -- possible substring.
15477c478bd9Sstevel@tonic-gate **		b -- possible superstring.
15487c478bd9Sstevel@tonic-gate **
15497c478bd9Sstevel@tonic-gate **	Returns:
15507c478bd9Sstevel@tonic-gate **		true if a is contained in b (case insensitive).
15517c478bd9Sstevel@tonic-gate **		false otherwise.
15527c478bd9Sstevel@tonic-gate */
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate bool
15557c478bd9Sstevel@tonic-gate strcontainedin(icase, a, b)
15567c478bd9Sstevel@tonic-gate 	bool icase;
15577c478bd9Sstevel@tonic-gate 	register char *a;
15587c478bd9Sstevel@tonic-gate 	register char *b;
15597c478bd9Sstevel@tonic-gate {
15607c478bd9Sstevel@tonic-gate 	int la;
15617c478bd9Sstevel@tonic-gate 	int lb;
15627c478bd9Sstevel@tonic-gate 	int c;
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate 	la = strlen(a);
15657c478bd9Sstevel@tonic-gate 	lb = strlen(b);
15667c478bd9Sstevel@tonic-gate 	c = *a;
15677c478bd9Sstevel@tonic-gate 	if (icase && isascii(c) && isupper(c))
15687c478bd9Sstevel@tonic-gate 		c = tolower(c);
15697c478bd9Sstevel@tonic-gate 	for (; lb-- >= la; b++)
15707c478bd9Sstevel@tonic-gate 	{
15717c478bd9Sstevel@tonic-gate 		if (icase)
15727c478bd9Sstevel@tonic-gate 		{
15737c478bd9Sstevel@tonic-gate 			if (*b != c &&
15747c478bd9Sstevel@tonic-gate 			    isascii(*b) && isupper(*b) && tolower(*b) != c)
15757c478bd9Sstevel@tonic-gate 				continue;
15767c478bd9Sstevel@tonic-gate 			if (sm_strncasecmp(a, b, la) == 0)
15777c478bd9Sstevel@tonic-gate 				return true;
15787c478bd9Sstevel@tonic-gate 		}
15797c478bd9Sstevel@tonic-gate 		else
15807c478bd9Sstevel@tonic-gate 		{
15817c478bd9Sstevel@tonic-gate 			if (*b != c)
15827c478bd9Sstevel@tonic-gate 				continue;
15837c478bd9Sstevel@tonic-gate 			if (strncmp(a, b, la) == 0)
15847c478bd9Sstevel@tonic-gate 				return true;
15857c478bd9Sstevel@tonic-gate 		}
15867c478bd9Sstevel@tonic-gate 	}
15877c478bd9Sstevel@tonic-gate 	return false;
15887c478bd9Sstevel@tonic-gate }
15897c478bd9Sstevel@tonic-gate /*
15907c478bd9Sstevel@tonic-gate **  CHECKFD012 -- check low numbered file descriptors
15917c478bd9Sstevel@tonic-gate **
15927c478bd9Sstevel@tonic-gate **	File descriptors 0, 1, and 2 should be open at all times.
15937c478bd9Sstevel@tonic-gate **	This routine verifies that, and fixes it if not true.
15947c478bd9Sstevel@tonic-gate **
15957c478bd9Sstevel@tonic-gate **	Parameters:
15967c478bd9Sstevel@tonic-gate **		where -- a tag printed if the assertion failed
15977c478bd9Sstevel@tonic-gate **
15987c478bd9Sstevel@tonic-gate **	Returns:
15997c478bd9Sstevel@tonic-gate **		none
16007c478bd9Sstevel@tonic-gate */
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate void
16037c478bd9Sstevel@tonic-gate checkfd012(where)
16047c478bd9Sstevel@tonic-gate 	char *where;
16057c478bd9Sstevel@tonic-gate {
16067c478bd9Sstevel@tonic-gate #if XDEBUG
16077c478bd9Sstevel@tonic-gate 	register int i;
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 	for (i = 0; i < 3; i++)
16107c478bd9Sstevel@tonic-gate 		fill_fd(i, where);
16117c478bd9Sstevel@tonic-gate #endif /* XDEBUG */
16127c478bd9Sstevel@tonic-gate }
16137c478bd9Sstevel@tonic-gate /*
16147c478bd9Sstevel@tonic-gate **  CHECKFDOPEN -- make sure file descriptor is open -- for extended debugging
16157c478bd9Sstevel@tonic-gate **
16167c478bd9Sstevel@tonic-gate **	Parameters:
16177c478bd9Sstevel@tonic-gate **		fd -- file descriptor to check.
16187c478bd9Sstevel@tonic-gate **		where -- tag to print on failure.
16197c478bd9Sstevel@tonic-gate **
16207c478bd9Sstevel@tonic-gate **	Returns:
16217c478bd9Sstevel@tonic-gate **		none.
16227c478bd9Sstevel@tonic-gate */
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate void
16257c478bd9Sstevel@tonic-gate checkfdopen(fd, where)
16267c478bd9Sstevel@tonic-gate 	int fd;
16277c478bd9Sstevel@tonic-gate 	char *where;
16287c478bd9Sstevel@tonic-gate {
16297c478bd9Sstevel@tonic-gate #if XDEBUG
16307c478bd9Sstevel@tonic-gate 	struct stat st;
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate 	if (fstat(fd, &st) < 0 && errno == EBADF)
16337c478bd9Sstevel@tonic-gate 	{
16347c478bd9Sstevel@tonic-gate 		syserr("checkfdopen(%d): %s not open as expected!", fd, where);
16357c478bd9Sstevel@tonic-gate 		printopenfds(true);
16367c478bd9Sstevel@tonic-gate 	}
16377c478bd9Sstevel@tonic-gate #endif /* XDEBUG */
16387c478bd9Sstevel@tonic-gate }
16397c478bd9Sstevel@tonic-gate /*
16407c478bd9Sstevel@tonic-gate **  CHECKFDS -- check for new or missing file descriptors
16417c478bd9Sstevel@tonic-gate **
16427c478bd9Sstevel@tonic-gate **	Parameters:
16437c478bd9Sstevel@tonic-gate **		where -- tag for printing.  If null, take a base line.
16447c478bd9Sstevel@tonic-gate **
16457c478bd9Sstevel@tonic-gate **	Returns:
16467c478bd9Sstevel@tonic-gate **		none
16477c478bd9Sstevel@tonic-gate **
16487c478bd9Sstevel@tonic-gate **	Side Effects:
16497c478bd9Sstevel@tonic-gate **		If where is set, shows changes since the last call.
16507c478bd9Sstevel@tonic-gate */
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate void
16537c478bd9Sstevel@tonic-gate checkfds(where)
16547c478bd9Sstevel@tonic-gate 	char *where;
16557c478bd9Sstevel@tonic-gate {
16567c478bd9Sstevel@tonic-gate 	int maxfd;
16577c478bd9Sstevel@tonic-gate 	register int fd;
16587c478bd9Sstevel@tonic-gate 	bool printhdr = true;
16597c478bd9Sstevel@tonic-gate 	int save_errno = errno;
16607c478bd9Sstevel@tonic-gate 	static BITMAP256 baseline;
16617c478bd9Sstevel@tonic-gate 	extern int DtableSize;
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 	if (DtableSize > BITMAPBITS)
16647c478bd9Sstevel@tonic-gate 		maxfd = BITMAPBITS;
16657c478bd9Sstevel@tonic-gate 	else
16667c478bd9Sstevel@tonic-gate 		maxfd = DtableSize;
16677c478bd9Sstevel@tonic-gate 	if (where == NULL)
16687c478bd9Sstevel@tonic-gate 		clrbitmap(baseline);
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	for (fd = 0; fd < maxfd; fd++)
16717c478bd9Sstevel@tonic-gate 	{
16727c478bd9Sstevel@tonic-gate 		struct stat stbuf;
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 		if (fstat(fd, &stbuf) < 0 && errno != EOPNOTSUPP)
16757c478bd9Sstevel@tonic-gate 		{
16767c478bd9Sstevel@tonic-gate 			if (!bitnset(fd, baseline))
16777c478bd9Sstevel@tonic-gate 				continue;
16787c478bd9Sstevel@tonic-gate 			clrbitn(fd, baseline);
16797c478bd9Sstevel@tonic-gate 		}
16807c478bd9Sstevel@tonic-gate 		else if (!bitnset(fd, baseline))
16817c478bd9Sstevel@tonic-gate 			setbitn(fd, baseline);
16827c478bd9Sstevel@tonic-gate 		else
16837c478bd9Sstevel@tonic-gate 			continue;
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 		/* file state has changed */
16867c478bd9Sstevel@tonic-gate 		if (where == NULL)
16877c478bd9Sstevel@tonic-gate 			continue;
16887c478bd9Sstevel@tonic-gate 		if (printhdr)
16897c478bd9Sstevel@tonic-gate 		{
16907c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_DEBUG, CurEnv->e_id,
16917c478bd9Sstevel@tonic-gate 				  "%s: changed fds:",
16927c478bd9Sstevel@tonic-gate 				  where);
16937c478bd9Sstevel@tonic-gate 			printhdr = false;
16947c478bd9Sstevel@tonic-gate 		}
16957c478bd9Sstevel@tonic-gate 		dumpfd(fd, true, true);
16967c478bd9Sstevel@tonic-gate 	}
16977c478bd9Sstevel@tonic-gate 	errno = save_errno;
16987c478bd9Sstevel@tonic-gate }
16997c478bd9Sstevel@tonic-gate /*
17007c478bd9Sstevel@tonic-gate **  PRINTOPENFDS -- print the open file descriptors (for debugging)
17017c478bd9Sstevel@tonic-gate **
17027c478bd9Sstevel@tonic-gate **	Parameters:
17037c478bd9Sstevel@tonic-gate **		logit -- if set, send output to syslog; otherwise
17047c478bd9Sstevel@tonic-gate **			print for debugging.
17057c478bd9Sstevel@tonic-gate **
17067c478bd9Sstevel@tonic-gate **	Returns:
17077c478bd9Sstevel@tonic-gate **		none.
17087c478bd9Sstevel@tonic-gate */
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate #if NETINET || NETINET6
17117c478bd9Sstevel@tonic-gate # include <arpa/inet.h>
17127c478bd9Sstevel@tonic-gate #endif /* NETINET || NETINET6 */
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate void
17157c478bd9Sstevel@tonic-gate printopenfds(logit)
17167c478bd9Sstevel@tonic-gate 	bool logit;
17177c478bd9Sstevel@tonic-gate {
17187c478bd9Sstevel@tonic-gate 	register int fd;
17197c478bd9Sstevel@tonic-gate 	extern int DtableSize;
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 	for (fd = 0; fd < DtableSize; fd++)
17227c478bd9Sstevel@tonic-gate 		dumpfd(fd, false, logit);
17237c478bd9Sstevel@tonic-gate }
17247c478bd9Sstevel@tonic-gate /*
17257c478bd9Sstevel@tonic-gate **  DUMPFD -- dump a file descriptor
17267c478bd9Sstevel@tonic-gate **
17277c478bd9Sstevel@tonic-gate **	Parameters:
17287c478bd9Sstevel@tonic-gate **		fd -- the file descriptor to dump.
17297c478bd9Sstevel@tonic-gate **		printclosed -- if set, print a notification even if
17307c478bd9Sstevel@tonic-gate **			it is closed; otherwise print nothing.
17317c478bd9Sstevel@tonic-gate **		logit -- if set, use sm_syslog instead of sm_dprintf()
17327c478bd9Sstevel@tonic-gate **
17337c478bd9Sstevel@tonic-gate **	Returns:
17347c478bd9Sstevel@tonic-gate **		none.
17357c478bd9Sstevel@tonic-gate */
17367c478bd9Sstevel@tonic-gate 
17377c478bd9Sstevel@tonic-gate void
17387c478bd9Sstevel@tonic-gate dumpfd(fd, printclosed, logit)
17397c478bd9Sstevel@tonic-gate 	int fd;
17407c478bd9Sstevel@tonic-gate 	bool printclosed;
17417c478bd9Sstevel@tonic-gate 	bool logit;
17427c478bd9Sstevel@tonic-gate {
17437c478bd9Sstevel@tonic-gate 	register char *p;
17447c478bd9Sstevel@tonic-gate 	char *hp;
17457c478bd9Sstevel@tonic-gate #ifdef S_IFSOCK
17467c478bd9Sstevel@tonic-gate 	SOCKADDR sa;
17477c478bd9Sstevel@tonic-gate #endif /* S_IFSOCK */
17487c478bd9Sstevel@tonic-gate 	auto SOCKADDR_LEN_T slen;
17497c478bd9Sstevel@tonic-gate 	int i;
17507c478bd9Sstevel@tonic-gate #if STAT64 > 0
17517c478bd9Sstevel@tonic-gate 	struct stat64 st;
17527c478bd9Sstevel@tonic-gate #else /* STAT64 > 0 */
17537c478bd9Sstevel@tonic-gate 	struct stat st;
17547c478bd9Sstevel@tonic-gate #endif /* STAT64 > 0 */
17557c478bd9Sstevel@tonic-gate 	char buf[200];
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 	p = buf;
17587c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(p, SPACELEFT(buf, p), "%3d: ", fd);
17597c478bd9Sstevel@tonic-gate 	p += strlen(p);
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate 	if (
17627c478bd9Sstevel@tonic-gate #if STAT64 > 0
17637c478bd9Sstevel@tonic-gate 	    fstat64(fd, &st)
17647c478bd9Sstevel@tonic-gate #else /* STAT64 > 0 */
17657c478bd9Sstevel@tonic-gate 	    fstat(fd, &st)
17667c478bd9Sstevel@tonic-gate #endif /* STAT64 > 0 */
17677c478bd9Sstevel@tonic-gate 	    < 0)
17687c478bd9Sstevel@tonic-gate 	{
17697c478bd9Sstevel@tonic-gate 		if (errno != EBADF)
17707c478bd9Sstevel@tonic-gate 		{
17717c478bd9Sstevel@tonic-gate 			(void) sm_snprintf(p, SPACELEFT(buf, p),
17727c478bd9Sstevel@tonic-gate 				"CANNOT STAT (%s)",
17737c478bd9Sstevel@tonic-gate 				sm_errstring(errno));
17747c478bd9Sstevel@tonic-gate 			goto printit;
17757c478bd9Sstevel@tonic-gate 		}
17767c478bd9Sstevel@tonic-gate 		else if (printclosed)
17777c478bd9Sstevel@tonic-gate 		{
17787c478bd9Sstevel@tonic-gate 			(void) sm_snprintf(p, SPACELEFT(buf, p), "CLOSED");
17797c478bd9Sstevel@tonic-gate 			goto printit;
17807c478bd9Sstevel@tonic-gate 		}
17817c478bd9Sstevel@tonic-gate 		return;
17827c478bd9Sstevel@tonic-gate 	}
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 	i = fcntl(fd, F_GETFL, 0);
17857c478bd9Sstevel@tonic-gate 	if (i != -1)
17867c478bd9Sstevel@tonic-gate 	{
17877c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(p, SPACELEFT(buf, p), "fl=0x%x, ", i);
17887c478bd9Sstevel@tonic-gate 		p += strlen(p);
17897c478bd9Sstevel@tonic-gate 	}
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(p, SPACELEFT(buf, p), "mode=%o: ",
17927c478bd9Sstevel@tonic-gate 			(int) st.st_mode);
17937c478bd9Sstevel@tonic-gate 	p += strlen(p);
17947c478bd9Sstevel@tonic-gate 	switch (st.st_mode & S_IFMT)
17957c478bd9Sstevel@tonic-gate 	{
17967c478bd9Sstevel@tonic-gate #ifdef S_IFSOCK
17977c478bd9Sstevel@tonic-gate 	  case S_IFSOCK:
17987c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(p, SPACELEFT(buf, p), "SOCK ");
17997c478bd9Sstevel@tonic-gate 		p += strlen(p);
18007c478bd9Sstevel@tonic-gate 		memset(&sa, '\0', sizeof sa);
18017c478bd9Sstevel@tonic-gate 		slen = sizeof sa;
18027c478bd9Sstevel@tonic-gate 		if (getsockname(fd, &sa.sa, &slen) < 0)
18037c478bd9Sstevel@tonic-gate 			(void) sm_snprintf(p, SPACELEFT(buf, p), "(%s)",
18047c478bd9Sstevel@tonic-gate 				 sm_errstring(errno));
18057c478bd9Sstevel@tonic-gate 		else
18067c478bd9Sstevel@tonic-gate 		{
18077c478bd9Sstevel@tonic-gate 			hp = hostnamebyanyaddr(&sa);
18087c478bd9Sstevel@tonic-gate 			if (hp == NULL)
18097c478bd9Sstevel@tonic-gate 			{
18107c478bd9Sstevel@tonic-gate 				/* EMPTY */
18117c478bd9Sstevel@tonic-gate 				/* do nothing */
18127c478bd9Sstevel@tonic-gate 			}
18137c478bd9Sstevel@tonic-gate # if NETINET
18147c478bd9Sstevel@tonic-gate 			else if (sa.sa.sa_family == AF_INET)
18157c478bd9Sstevel@tonic-gate 				(void) sm_snprintf(p, SPACELEFT(buf, p),
18167c478bd9Sstevel@tonic-gate 					"%s/%d", hp, ntohs(sa.sin.sin_port));
18177c478bd9Sstevel@tonic-gate # endif /* NETINET */
18187c478bd9Sstevel@tonic-gate # if NETINET6
18197c478bd9Sstevel@tonic-gate 			else if (sa.sa.sa_family == AF_INET6)
18207c478bd9Sstevel@tonic-gate 				(void) sm_snprintf(p, SPACELEFT(buf, p),
18217c478bd9Sstevel@tonic-gate 					"%s/%d", hp, ntohs(sa.sin6.sin6_port));
18227c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
18237c478bd9Sstevel@tonic-gate 			else
18247c478bd9Sstevel@tonic-gate 				(void) sm_snprintf(p, SPACELEFT(buf, p),
18257c478bd9Sstevel@tonic-gate 					"%s", hp);
18267c478bd9Sstevel@tonic-gate 		}
18277c478bd9Sstevel@tonic-gate 		p += strlen(p);
18287c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(p, SPACELEFT(buf, p), "->");
18297c478bd9Sstevel@tonic-gate 		p += strlen(p);
18307c478bd9Sstevel@tonic-gate 		slen = sizeof sa;
18317c478bd9Sstevel@tonic-gate 		if (getpeername(fd, &sa.sa, &slen) < 0)
18327c478bd9Sstevel@tonic-gate 			(void) sm_snprintf(p, SPACELEFT(buf, p), "(%s)",
18337c478bd9Sstevel@tonic-gate 					sm_errstring(errno));
18347c478bd9Sstevel@tonic-gate 		else
18357c478bd9Sstevel@tonic-gate 		{
18367c478bd9Sstevel@tonic-gate 			hp = hostnamebyanyaddr(&sa);
18377c478bd9Sstevel@tonic-gate 			if (hp == NULL)
18387c478bd9Sstevel@tonic-gate 			{
18397c478bd9Sstevel@tonic-gate 				/* EMPTY */
18407c478bd9Sstevel@tonic-gate 				/* do nothing */
18417c478bd9Sstevel@tonic-gate 			}
18427c478bd9Sstevel@tonic-gate # if NETINET
18437c478bd9Sstevel@tonic-gate 			else if (sa.sa.sa_family == AF_INET)
18447c478bd9Sstevel@tonic-gate 				(void) sm_snprintf(p, SPACELEFT(buf, p),
18457c478bd9Sstevel@tonic-gate 					"%s/%d", hp, ntohs(sa.sin.sin_port));
18467c478bd9Sstevel@tonic-gate # endif /* NETINET */
18477c478bd9Sstevel@tonic-gate # if NETINET6
18487c478bd9Sstevel@tonic-gate 			else if (sa.sa.sa_family == AF_INET6)
18497c478bd9Sstevel@tonic-gate 				(void) sm_snprintf(p, SPACELEFT(buf, p),
18507c478bd9Sstevel@tonic-gate 					"%s/%d", hp, ntohs(sa.sin6.sin6_port));
18517c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
18527c478bd9Sstevel@tonic-gate 			else
18537c478bd9Sstevel@tonic-gate 				(void) sm_snprintf(p, SPACELEFT(buf, p),
18547c478bd9Sstevel@tonic-gate 					"%s", hp);
18557c478bd9Sstevel@tonic-gate 		}
18567c478bd9Sstevel@tonic-gate 		break;
18577c478bd9Sstevel@tonic-gate #endif /* S_IFSOCK */
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate 	  case S_IFCHR:
18607c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(p, SPACELEFT(buf, p), "CHR: ");
18617c478bd9Sstevel@tonic-gate 		p += strlen(p);
18627c478bd9Sstevel@tonic-gate 		goto defprint;
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate #ifdef S_IFBLK
18657c478bd9Sstevel@tonic-gate 	  case S_IFBLK:
18667c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(p, SPACELEFT(buf, p), "BLK: ");
18677c478bd9Sstevel@tonic-gate 		p += strlen(p);
18687c478bd9Sstevel@tonic-gate 		goto defprint;
18697c478bd9Sstevel@tonic-gate #endif /* S_IFBLK */
18707c478bd9Sstevel@tonic-gate 
18717c478bd9Sstevel@tonic-gate #if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK)
18727c478bd9Sstevel@tonic-gate 	  case S_IFIFO:
18737c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(p, SPACELEFT(buf, p), "FIFO: ");
18747c478bd9Sstevel@tonic-gate 		p += strlen(p);
18757c478bd9Sstevel@tonic-gate 		goto defprint;
18767c478bd9Sstevel@tonic-gate #endif /* defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) */
18777c478bd9Sstevel@tonic-gate 
18787c478bd9Sstevel@tonic-gate #ifdef S_IFDIR
18797c478bd9Sstevel@tonic-gate 	  case S_IFDIR:
18807c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(p, SPACELEFT(buf, p), "DIR: ");
18817c478bd9Sstevel@tonic-gate 		p += strlen(p);
18827c478bd9Sstevel@tonic-gate 		goto defprint;
18837c478bd9Sstevel@tonic-gate #endif /* S_IFDIR */
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate #ifdef S_IFLNK
18867c478bd9Sstevel@tonic-gate 	  case S_IFLNK:
18877c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(p, SPACELEFT(buf, p), "LNK: ");
18887c478bd9Sstevel@tonic-gate 		p += strlen(p);
18897c478bd9Sstevel@tonic-gate 		goto defprint;
18907c478bd9Sstevel@tonic-gate #endif /* S_IFLNK */
18917c478bd9Sstevel@tonic-gate 
18927c478bd9Sstevel@tonic-gate 	  default:
18937c478bd9Sstevel@tonic-gate defprint:
18947c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(p, SPACELEFT(buf, p),
18957c478bd9Sstevel@tonic-gate 			 "dev=%d/%d, ino=%llu, nlink=%d, u/gid=%d/%d, ",
18967c478bd9Sstevel@tonic-gate 			 major(st.st_dev), minor(st.st_dev),
18977c478bd9Sstevel@tonic-gate 			 (ULONGLONG_T) st.st_ino,
18987c478bd9Sstevel@tonic-gate 			 (int) st.st_nlink, (int) st.st_uid,
18997c478bd9Sstevel@tonic-gate 			 (int) st.st_gid);
19007c478bd9Sstevel@tonic-gate 		p += strlen(p);
19017c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(p, SPACELEFT(buf, p), "size=%llu",
19027c478bd9Sstevel@tonic-gate 			 (ULONGLONG_T) st.st_size);
19037c478bd9Sstevel@tonic-gate 		break;
19047c478bd9Sstevel@tonic-gate 	}
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate printit:
19077c478bd9Sstevel@tonic-gate 	if (logit)
19087c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_DEBUG, CurEnv ? CurEnv->e_id : NULL,
19097c478bd9Sstevel@tonic-gate 			  "%.800s", buf);
19107c478bd9Sstevel@tonic-gate 	else
19117c478bd9Sstevel@tonic-gate 		sm_dprintf("%s\n", buf);
19127c478bd9Sstevel@tonic-gate }
19137c478bd9Sstevel@tonic-gate /*
19147c478bd9Sstevel@tonic-gate **  SHORTEN_HOSTNAME -- strip local domain information off of hostname.
19157c478bd9Sstevel@tonic-gate **
19167c478bd9Sstevel@tonic-gate **	Parameters:
19177c478bd9Sstevel@tonic-gate **		host -- the host to shorten (stripped in place).
19187c478bd9Sstevel@tonic-gate **
19197c478bd9Sstevel@tonic-gate **	Returns:
19207c478bd9Sstevel@tonic-gate **		place where string was truncated, NULL if not truncated.
19217c478bd9Sstevel@tonic-gate */
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate char *
19247c478bd9Sstevel@tonic-gate shorten_hostname(host)
19257c478bd9Sstevel@tonic-gate 	char host[];
19267c478bd9Sstevel@tonic-gate {
19277c478bd9Sstevel@tonic-gate 	register char *p;
19287c478bd9Sstevel@tonic-gate 	char *mydom;
19297c478bd9Sstevel@tonic-gate 	int i;
19307c478bd9Sstevel@tonic-gate 	bool canon = false;
19317c478bd9Sstevel@tonic-gate 
19327c478bd9Sstevel@tonic-gate 	/* strip off final dot */
19337c478bd9Sstevel@tonic-gate 	i = strlen(host);
19347c478bd9Sstevel@tonic-gate 	p = &host[(i == 0) ? 0 : i - 1];
19357c478bd9Sstevel@tonic-gate 	if (*p == '.')
19367c478bd9Sstevel@tonic-gate 	{
19377c478bd9Sstevel@tonic-gate 		*p = '\0';
19387c478bd9Sstevel@tonic-gate 		canon = true;
19397c478bd9Sstevel@tonic-gate 	}
19407c478bd9Sstevel@tonic-gate 
19417c478bd9Sstevel@tonic-gate 	/* see if there is any domain at all -- if not, we are done */
19427c478bd9Sstevel@tonic-gate 	p = strchr(host, '.');
19437c478bd9Sstevel@tonic-gate 	if (p == NULL)
19447c478bd9Sstevel@tonic-gate 		return NULL;
19457c478bd9Sstevel@tonic-gate 
19467c478bd9Sstevel@tonic-gate 	/* yes, we have a domain -- see if it looks like us */
19477c478bd9Sstevel@tonic-gate 	mydom = macvalue('m', CurEnv);
19487c478bd9Sstevel@tonic-gate 	if (mydom == NULL)
19497c478bd9Sstevel@tonic-gate 		mydom = "";
19507c478bd9Sstevel@tonic-gate 	i = strlen(++p);
19517c478bd9Sstevel@tonic-gate 	if ((canon ? sm_strcasecmp(p, mydom)
19527c478bd9Sstevel@tonic-gate 		   : sm_strncasecmp(p, mydom, i)) == 0 &&
19537c478bd9Sstevel@tonic-gate 			(mydom[i] == '.' || mydom[i] == '\0'))
19547c478bd9Sstevel@tonic-gate 	{
19557c478bd9Sstevel@tonic-gate 		*--p = '\0';
19567c478bd9Sstevel@tonic-gate 		return p;
19577c478bd9Sstevel@tonic-gate 	}
19587c478bd9Sstevel@tonic-gate 	return NULL;
19597c478bd9Sstevel@tonic-gate }
19607c478bd9Sstevel@tonic-gate /*
19617c478bd9Sstevel@tonic-gate **  PROG_OPEN -- open a program for reading
19627c478bd9Sstevel@tonic-gate **
19637c478bd9Sstevel@tonic-gate **	Parameters:
19647c478bd9Sstevel@tonic-gate **		argv -- the argument list.
19657c478bd9Sstevel@tonic-gate **		pfd -- pointer to a place to store the file descriptor.
19667c478bd9Sstevel@tonic-gate **		e -- the current envelope.
19677c478bd9Sstevel@tonic-gate **
19687c478bd9Sstevel@tonic-gate **	Returns:
19697c478bd9Sstevel@tonic-gate **		pid of the process -- -1 if it failed.
19707c478bd9Sstevel@tonic-gate */
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate pid_t
19737c478bd9Sstevel@tonic-gate prog_open(argv, pfd, e)
19747c478bd9Sstevel@tonic-gate 	char **argv;
19757c478bd9Sstevel@tonic-gate 	int *pfd;
19767c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
19777c478bd9Sstevel@tonic-gate {
19787c478bd9Sstevel@tonic-gate 	pid_t pid;
19797c478bd9Sstevel@tonic-gate 	int save_errno;
19807c478bd9Sstevel@tonic-gate 	int sff;
19817c478bd9Sstevel@tonic-gate 	int ret;
19827c478bd9Sstevel@tonic-gate 	int fdv[2];
19837c478bd9Sstevel@tonic-gate 	char *p, *q;
19847c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
19857c478bd9Sstevel@tonic-gate 	extern int DtableSize;
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate 	if (pipe(fdv) < 0)
19887c478bd9Sstevel@tonic-gate 	{
19897c478bd9Sstevel@tonic-gate 		syserr("%s: cannot create pipe for stdout", argv[0]);
19907c478bd9Sstevel@tonic-gate 		return -1;
19917c478bd9Sstevel@tonic-gate 	}
19927c478bd9Sstevel@tonic-gate 	pid = fork();
19937c478bd9Sstevel@tonic-gate 	if (pid < 0)
19947c478bd9Sstevel@tonic-gate 	{
19957c478bd9Sstevel@tonic-gate 		syserr("%s: cannot fork", argv[0]);
19967c478bd9Sstevel@tonic-gate 		(void) close(fdv[0]);
19977c478bd9Sstevel@tonic-gate 		(void) close(fdv[1]);
19987c478bd9Sstevel@tonic-gate 		return -1;
19997c478bd9Sstevel@tonic-gate 	}
20007c478bd9Sstevel@tonic-gate 	if (pid > 0)
20017c478bd9Sstevel@tonic-gate 	{
20027c478bd9Sstevel@tonic-gate 		/* parent */
20037c478bd9Sstevel@tonic-gate 		(void) close(fdv[1]);
20047c478bd9Sstevel@tonic-gate 		*pfd = fdv[0];
20057c478bd9Sstevel@tonic-gate 		return pid;
20067c478bd9Sstevel@tonic-gate 	}
20077c478bd9Sstevel@tonic-gate 
20087c478bd9Sstevel@tonic-gate 	/* Reset global flags */
20097c478bd9Sstevel@tonic-gate 	RestartRequest = NULL;
20107c478bd9Sstevel@tonic-gate 	RestartWorkGroup = false;
20117c478bd9Sstevel@tonic-gate 	ShutdownRequest = NULL;
20127c478bd9Sstevel@tonic-gate 	PendingSignal = 0;
20137c478bd9Sstevel@tonic-gate 	CurrentPid = getpid();
20147c478bd9Sstevel@tonic-gate 
20157c478bd9Sstevel@tonic-gate 	/*
20167c478bd9Sstevel@tonic-gate 	**  Initialize exception stack and default exception
20177c478bd9Sstevel@tonic-gate 	**  handler for child process.
20187c478bd9Sstevel@tonic-gate 	*/
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate 	sm_exc_newthread(fatal_error);
20217c478bd9Sstevel@tonic-gate 
20227c478bd9Sstevel@tonic-gate 	/* child -- close stdin */
20237c478bd9Sstevel@tonic-gate 	(void) close(0);
20247c478bd9Sstevel@tonic-gate 
20257c478bd9Sstevel@tonic-gate 	/* stdout goes back to parent */
20267c478bd9Sstevel@tonic-gate 	(void) close(fdv[0]);
20277c478bd9Sstevel@tonic-gate 	if (dup2(fdv[1], 1) < 0)
20287c478bd9Sstevel@tonic-gate 	{
20297c478bd9Sstevel@tonic-gate 		syserr("%s: cannot dup2 for stdout", argv[0]);
20307c478bd9Sstevel@tonic-gate 		_exit(EX_OSERR);
20317c478bd9Sstevel@tonic-gate 	}
20327c478bd9Sstevel@tonic-gate 	(void) close(fdv[1]);
20337c478bd9Sstevel@tonic-gate 
20347c478bd9Sstevel@tonic-gate 	/* stderr goes to transcript if available */
20357c478bd9Sstevel@tonic-gate 	if (e->e_xfp != NULL)
20367c478bd9Sstevel@tonic-gate 	{
20377c478bd9Sstevel@tonic-gate 		int xfd;
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate 		xfd = sm_io_getinfo(e->e_xfp, SM_IO_WHAT_FD, NULL);
20407c478bd9Sstevel@tonic-gate 		if (xfd >= 0 && dup2(xfd, 2) < 0)
20417c478bd9Sstevel@tonic-gate 		{
20427c478bd9Sstevel@tonic-gate 			syserr("%s: cannot dup2 for stderr", argv[0]);
20437c478bd9Sstevel@tonic-gate 			_exit(EX_OSERR);
20447c478bd9Sstevel@tonic-gate 		}
20457c478bd9Sstevel@tonic-gate 	}
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate 	/* this process has no right to the queue file */
20487c478bd9Sstevel@tonic-gate 	if (e->e_lockfp != NULL)
20497c478bd9Sstevel@tonic-gate 		(void) close(sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL));
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 	/* chroot to the program mailer directory, if defined */
20527c478bd9Sstevel@tonic-gate 	if (ProgMailer != NULL && ProgMailer->m_rootdir != NULL)
20537c478bd9Sstevel@tonic-gate 	{
20547c478bd9Sstevel@tonic-gate 		expand(ProgMailer->m_rootdir, buf, sizeof buf, e);
20557c478bd9Sstevel@tonic-gate 		if (chroot(buf) < 0)
20567c478bd9Sstevel@tonic-gate 		{
20577c478bd9Sstevel@tonic-gate 			syserr("prog_open: cannot chroot(%s)", buf);
20587c478bd9Sstevel@tonic-gate 			exit(EX_TEMPFAIL);
20597c478bd9Sstevel@tonic-gate 		}
20607c478bd9Sstevel@tonic-gate 		if (chdir("/") < 0)
20617c478bd9Sstevel@tonic-gate 		{
20627c478bd9Sstevel@tonic-gate 			syserr("prog_open: cannot chdir(/)");
20637c478bd9Sstevel@tonic-gate 			exit(EX_TEMPFAIL);
20647c478bd9Sstevel@tonic-gate 		}
20657c478bd9Sstevel@tonic-gate 	}
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 	/* run as default user */
20687c478bd9Sstevel@tonic-gate 	endpwent();
20697c478bd9Sstevel@tonic-gate 	sm_mbdb_terminate();
2070*445f2479Sjbeck #if _FFR_MEMSTAT
2071*445f2479Sjbeck 	(void) sm_memstat_close();
2072*445f2479Sjbeck #endif /* _FFR_MEMSTAT */
20737c478bd9Sstevel@tonic-gate 	if (setgid(DefGid) < 0 && geteuid() == 0)
20747c478bd9Sstevel@tonic-gate 	{
20757c478bd9Sstevel@tonic-gate 		syserr("prog_open: setgid(%ld) failed", (long) DefGid);
20767c478bd9Sstevel@tonic-gate 		exit(EX_TEMPFAIL);
20777c478bd9Sstevel@tonic-gate 	}
20787c478bd9Sstevel@tonic-gate 	if (setuid(DefUid) < 0 && geteuid() == 0)
20797c478bd9Sstevel@tonic-gate 	{
20807c478bd9Sstevel@tonic-gate 		syserr("prog_open: setuid(%ld) failed", (long) DefUid);
20817c478bd9Sstevel@tonic-gate 		exit(EX_TEMPFAIL);
20827c478bd9Sstevel@tonic-gate 	}
20837c478bd9Sstevel@tonic-gate 
20847c478bd9Sstevel@tonic-gate 	/* run in some directory */
20857c478bd9Sstevel@tonic-gate 	if (ProgMailer != NULL)
20867c478bd9Sstevel@tonic-gate 		p = ProgMailer->m_execdir;
20877c478bd9Sstevel@tonic-gate 	else
20887c478bd9Sstevel@tonic-gate 		p = NULL;
20897c478bd9Sstevel@tonic-gate 	for (; p != NULL; p = q)
20907c478bd9Sstevel@tonic-gate 	{
20917c478bd9Sstevel@tonic-gate 		q = strchr(p, ':');
20927c478bd9Sstevel@tonic-gate 		if (q != NULL)
20937c478bd9Sstevel@tonic-gate 			*q = '\0';
20947c478bd9Sstevel@tonic-gate 		expand(p, buf, sizeof buf, e);
20957c478bd9Sstevel@tonic-gate 		if (q != NULL)
20967c478bd9Sstevel@tonic-gate 			*q++ = ':';
20977c478bd9Sstevel@tonic-gate 		if (buf[0] != '\0' && chdir(buf) >= 0)
20987c478bd9Sstevel@tonic-gate 			break;
20997c478bd9Sstevel@tonic-gate 	}
21007c478bd9Sstevel@tonic-gate 	if (p == NULL)
21017c478bd9Sstevel@tonic-gate 	{
21027c478bd9Sstevel@tonic-gate 		/* backup directories */
21037c478bd9Sstevel@tonic-gate 		if (chdir("/tmp") < 0)
21047c478bd9Sstevel@tonic-gate 			(void) chdir("/");
21057c478bd9Sstevel@tonic-gate 	}
21067c478bd9Sstevel@tonic-gate 
21077c478bd9Sstevel@tonic-gate 	/* Check safety of program to be run */
21087c478bd9Sstevel@tonic-gate 	sff = SFF_ROOTOK|SFF_EXECOK;
21097c478bd9Sstevel@tonic-gate 	if (!bitnset(DBS_RUNWRITABLEPROGRAM, DontBlameSendmail))
21107c478bd9Sstevel@tonic-gate 		sff |= SFF_NOGWFILES|SFF_NOWWFILES;
21117c478bd9Sstevel@tonic-gate 	if (bitnset(DBS_RUNPROGRAMINUNSAFEDIRPATH, DontBlameSendmail))
21127c478bd9Sstevel@tonic-gate 		sff |= SFF_NOPATHCHECK;
21137c478bd9Sstevel@tonic-gate 	else
21147c478bd9Sstevel@tonic-gate 		sff |= SFF_SAFEDIRPATH;
21157c478bd9Sstevel@tonic-gate 	ret = safefile(argv[0], DefUid, DefGid, DefUser, sff, 0, NULL);
21167c478bd9Sstevel@tonic-gate 	if (ret != 0)
21177c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id,
21187c478bd9Sstevel@tonic-gate 			  "Warning: prog_open: program %s unsafe: %s",
21197c478bd9Sstevel@tonic-gate 			  argv[0], sm_errstring(ret));
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate 	/* arrange for all the files to be closed */
21227c478bd9Sstevel@tonic-gate 	sm_close_on_exec(STDERR_FILENO + 1, DtableSize);
21237c478bd9Sstevel@tonic-gate 
21247c478bd9Sstevel@tonic-gate 	/* now exec the process */
21257c478bd9Sstevel@tonic-gate 	(void) execve(argv[0], (ARGV_T) argv, (ARGV_T) UserEnviron);
21267c478bd9Sstevel@tonic-gate 
21277c478bd9Sstevel@tonic-gate 	/* woops!  failed */
21287c478bd9Sstevel@tonic-gate 	save_errno = errno;
21297c478bd9Sstevel@tonic-gate 	syserr("%s: cannot exec", argv[0]);
21307c478bd9Sstevel@tonic-gate 	if (transienterror(save_errno))
21317c478bd9Sstevel@tonic-gate 		_exit(EX_OSERR);
21327c478bd9Sstevel@tonic-gate 	_exit(EX_CONFIG);
21337c478bd9Sstevel@tonic-gate 	return -1;	/* avoid compiler warning on IRIX */
21347c478bd9Sstevel@tonic-gate }
21357c478bd9Sstevel@tonic-gate /*
21367c478bd9Sstevel@tonic-gate **  GET_COLUMN -- look up a Column in a line buffer
21377c478bd9Sstevel@tonic-gate **
21387c478bd9Sstevel@tonic-gate **	Parameters:
21397c478bd9Sstevel@tonic-gate **		line -- the raw text line to search.
21407c478bd9Sstevel@tonic-gate **		col -- the column number to fetch.
21417c478bd9Sstevel@tonic-gate **		delim -- the delimiter between columns.  If null,
21427c478bd9Sstevel@tonic-gate **			use white space.
21437c478bd9Sstevel@tonic-gate **		buf -- the output buffer.
21447c478bd9Sstevel@tonic-gate **		buflen -- the length of buf.
21457c478bd9Sstevel@tonic-gate **
21467c478bd9Sstevel@tonic-gate **	Returns:
21477c478bd9Sstevel@tonic-gate **		buf if successful.
21487c478bd9Sstevel@tonic-gate **		NULL otherwise.
21497c478bd9Sstevel@tonic-gate */
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate char *
21527c478bd9Sstevel@tonic-gate get_column(line, col, delim, buf, buflen)
21537c478bd9Sstevel@tonic-gate 	char line[];
21547c478bd9Sstevel@tonic-gate 	int col;
21557c478bd9Sstevel@tonic-gate 	int delim;
21567c478bd9Sstevel@tonic-gate 	char buf[];
21577c478bd9Sstevel@tonic-gate 	int buflen;
21587c478bd9Sstevel@tonic-gate {
21597c478bd9Sstevel@tonic-gate 	char *p;
21607c478bd9Sstevel@tonic-gate 	char *begin, *end;
21617c478bd9Sstevel@tonic-gate 	int i;
21627c478bd9Sstevel@tonic-gate 	char delimbuf[4];
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate 	if ((char) delim == '\0')
21657c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(delimbuf, "\n\t ", sizeof delimbuf);
21667c478bd9Sstevel@tonic-gate 	else
21677c478bd9Sstevel@tonic-gate 	{
21687c478bd9Sstevel@tonic-gate 		delimbuf[0] = (char) delim;
21697c478bd9Sstevel@tonic-gate 		delimbuf[1] = '\0';
21707c478bd9Sstevel@tonic-gate 	}
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate 	p = line;
21737c478bd9Sstevel@tonic-gate 	if (*p == '\0')
21747c478bd9Sstevel@tonic-gate 		return NULL;			/* line empty */
21757c478bd9Sstevel@tonic-gate 	if (*p == (char) delim && col == 0)
21767c478bd9Sstevel@tonic-gate 		return NULL;			/* first column empty */
21777c478bd9Sstevel@tonic-gate 
21787c478bd9Sstevel@tonic-gate 	begin = line;
21797c478bd9Sstevel@tonic-gate 
21807c478bd9Sstevel@tonic-gate 	if (col == 0 && (char) delim == '\0')
21817c478bd9Sstevel@tonic-gate 	{
21827c478bd9Sstevel@tonic-gate 		while (*begin != '\0' && isascii(*begin) && isspace(*begin))
21837c478bd9Sstevel@tonic-gate 			begin++;
21847c478bd9Sstevel@tonic-gate 	}
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 	for (i = 0; i < col; i++)
21877c478bd9Sstevel@tonic-gate 	{
21887c478bd9Sstevel@tonic-gate 		if ((begin = strpbrk(begin, delimbuf)) == NULL)
21897c478bd9Sstevel@tonic-gate 			return NULL;		/* no such column */
21907c478bd9Sstevel@tonic-gate 		begin++;
21917c478bd9Sstevel@tonic-gate 		if ((char) delim == '\0')
21927c478bd9Sstevel@tonic-gate 		{
21937c478bd9Sstevel@tonic-gate 			while (*begin != '\0' && isascii(*begin) && isspace(*begin))
21947c478bd9Sstevel@tonic-gate 				begin++;
21957c478bd9Sstevel@tonic-gate 		}
21967c478bd9Sstevel@tonic-gate 	}
21977c478bd9Sstevel@tonic-gate 
21987c478bd9Sstevel@tonic-gate 	end = strpbrk(begin, delimbuf);
21997c478bd9Sstevel@tonic-gate 	if (end == NULL)
22007c478bd9Sstevel@tonic-gate 		i = strlen(begin);
22017c478bd9Sstevel@tonic-gate 	else
22027c478bd9Sstevel@tonic-gate 		i = end - begin;
22037c478bd9Sstevel@tonic-gate 	if (i >= buflen)
22047c478bd9Sstevel@tonic-gate 		i = buflen - 1;
22057c478bd9Sstevel@tonic-gate 	(void) sm_strlcpy(buf, begin, i + 1);
22067c478bd9Sstevel@tonic-gate 	return buf;
22077c478bd9Sstevel@tonic-gate }
22087c478bd9Sstevel@tonic-gate /*
22097c478bd9Sstevel@tonic-gate **  CLEANSTRCPY -- copy string keeping out bogus characters
22107c478bd9Sstevel@tonic-gate **
22117c478bd9Sstevel@tonic-gate **	Parameters:
22127c478bd9Sstevel@tonic-gate **		t -- "to" string.
22137c478bd9Sstevel@tonic-gate **		f -- "from" string.
22147c478bd9Sstevel@tonic-gate **		l -- length of space available in "to" string.
22157c478bd9Sstevel@tonic-gate **
22167c478bd9Sstevel@tonic-gate **	Returns:
22177c478bd9Sstevel@tonic-gate **		none.
22187c478bd9Sstevel@tonic-gate */
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate void
22217c478bd9Sstevel@tonic-gate cleanstrcpy(t, f, l)
22227c478bd9Sstevel@tonic-gate 	register char *t;
22237c478bd9Sstevel@tonic-gate 	register char *f;
22247c478bd9Sstevel@tonic-gate 	int l;
22257c478bd9Sstevel@tonic-gate {
22267c478bd9Sstevel@tonic-gate 	/* check for newlines and log if necessary */
22277c478bd9Sstevel@tonic-gate 	(void) denlstring(f, true, true);
22287c478bd9Sstevel@tonic-gate 
22297c478bd9Sstevel@tonic-gate 	if (l <= 0)
22307c478bd9Sstevel@tonic-gate 		syserr("!cleanstrcpy: length == 0");
22317c478bd9Sstevel@tonic-gate 
22327c478bd9Sstevel@tonic-gate 	l--;
22337c478bd9Sstevel@tonic-gate 	while (l > 0 && *f != '\0')
22347c478bd9Sstevel@tonic-gate 	{
22357c478bd9Sstevel@tonic-gate 		if (isascii(*f) &&
22367c478bd9Sstevel@tonic-gate 		    (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL))
22377c478bd9Sstevel@tonic-gate 		{
22387c478bd9Sstevel@tonic-gate 			l--;
22397c478bd9Sstevel@tonic-gate 			*t++ = *f;
22407c478bd9Sstevel@tonic-gate 		}
22417c478bd9Sstevel@tonic-gate 		f++;
22427c478bd9Sstevel@tonic-gate 	}
22437c478bd9Sstevel@tonic-gate 	*t = '\0';
22447c478bd9Sstevel@tonic-gate }
22457c478bd9Sstevel@tonic-gate /*
22467c478bd9Sstevel@tonic-gate **  DENLSTRING -- convert newlines in a string to spaces
22477c478bd9Sstevel@tonic-gate **
22487c478bd9Sstevel@tonic-gate **	Parameters:
22497c478bd9Sstevel@tonic-gate **		s -- the input string
22507c478bd9Sstevel@tonic-gate **		strict -- if set, don't permit continuation lines.
22517c478bd9Sstevel@tonic-gate **		logattacks -- if set, log attempted attacks.
22527c478bd9Sstevel@tonic-gate **
22537c478bd9Sstevel@tonic-gate **	Returns:
22547c478bd9Sstevel@tonic-gate **		A pointer to a version of the string with newlines
22557c478bd9Sstevel@tonic-gate **		mapped to spaces.  This should be copied.
22567c478bd9Sstevel@tonic-gate */
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate char *
22597c478bd9Sstevel@tonic-gate denlstring(s, strict, logattacks)
22607c478bd9Sstevel@tonic-gate 	char *s;
22617c478bd9Sstevel@tonic-gate 	bool strict;
22627c478bd9Sstevel@tonic-gate 	bool logattacks;
22637c478bd9Sstevel@tonic-gate {
22647c478bd9Sstevel@tonic-gate 	register char *p;
22657c478bd9Sstevel@tonic-gate 	int l;
22667c478bd9Sstevel@tonic-gate 	static char *bp = NULL;
22677c478bd9Sstevel@tonic-gate 	static int bl = 0;
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate 	p = s;
22707c478bd9Sstevel@tonic-gate 	while ((p = strchr(p, '\n')) != NULL)
22717c478bd9Sstevel@tonic-gate 		if (strict || (*++p != ' ' && *p != '\t'))
22727c478bd9Sstevel@tonic-gate 			break;
22737c478bd9Sstevel@tonic-gate 	if (p == NULL)
22747c478bd9Sstevel@tonic-gate 		return s;
22757c478bd9Sstevel@tonic-gate 
22767c478bd9Sstevel@tonic-gate 	l = strlen(s) + 1;
22777c478bd9Sstevel@tonic-gate 	if (bl < l)
22787c478bd9Sstevel@tonic-gate 	{
22797c478bd9Sstevel@tonic-gate 		/* allocate more space */
22807c478bd9Sstevel@tonic-gate 		char *nbp = sm_pmalloc_x(l);
22817c478bd9Sstevel@tonic-gate 
22827c478bd9Sstevel@tonic-gate 		if (bp != NULL)
22837c478bd9Sstevel@tonic-gate 			sm_free(bp);
22847c478bd9Sstevel@tonic-gate 		bp = nbp;
22857c478bd9Sstevel@tonic-gate 		bl = l;
22867c478bd9Sstevel@tonic-gate 	}
22877c478bd9Sstevel@tonic-gate 	(void) sm_strlcpy(bp, s, l);
22887c478bd9Sstevel@tonic-gate 	for (p = bp; (p = strchr(p, '\n')) != NULL; )
22897c478bd9Sstevel@tonic-gate 		*p++ = ' ';
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate 	if (logattacks)
22927c478bd9Sstevel@tonic-gate 	{
22937c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_NOTICE, CurEnv->e_id,
22947c478bd9Sstevel@tonic-gate 			  "POSSIBLE ATTACK from %.100s: newline in string \"%s\"",
22957c478bd9Sstevel@tonic-gate 			  RealHostName == NULL ? "[UNKNOWN]" : RealHostName,
22967c478bd9Sstevel@tonic-gate 			  shortenstring(bp, MAXSHORTSTR));
22977c478bd9Sstevel@tonic-gate 	}
22987c478bd9Sstevel@tonic-gate 
22997c478bd9Sstevel@tonic-gate 	return bp;
23007c478bd9Sstevel@tonic-gate }
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate /*
23037c478bd9Sstevel@tonic-gate **  STRREPLNONPRT -- replace "unprintable" characters in a string with subst
23047c478bd9Sstevel@tonic-gate **
23057c478bd9Sstevel@tonic-gate **	Parameters:
23067c478bd9Sstevel@tonic-gate **		s -- string to manipulate (in place)
23077c478bd9Sstevel@tonic-gate **		subst -- character to use as replacement
23087c478bd9Sstevel@tonic-gate **
23097c478bd9Sstevel@tonic-gate **	Returns:
23107c478bd9Sstevel@tonic-gate **		true iff string did not contain "unprintable" characters
23117c478bd9Sstevel@tonic-gate */
23127c478bd9Sstevel@tonic-gate 
23137c478bd9Sstevel@tonic-gate bool
23147c478bd9Sstevel@tonic-gate strreplnonprt(s, c)
23157c478bd9Sstevel@tonic-gate 	char *s;
23167c478bd9Sstevel@tonic-gate 	int c;
23177c478bd9Sstevel@tonic-gate {
23187c478bd9Sstevel@tonic-gate 	bool ok;
23197c478bd9Sstevel@tonic-gate 
23207c478bd9Sstevel@tonic-gate 	ok = true;
23217c478bd9Sstevel@tonic-gate 	if (s == NULL)
23227c478bd9Sstevel@tonic-gate 		return ok;
23237c478bd9Sstevel@tonic-gate 	while (*s != '\0')
23247c478bd9Sstevel@tonic-gate 	{
23257c478bd9Sstevel@tonic-gate 		if (!(isascii(*s) && isprint(*s)))
23267c478bd9Sstevel@tonic-gate 		{
23277c478bd9Sstevel@tonic-gate 			*s = c;
23287c478bd9Sstevel@tonic-gate 			ok = false;
23297c478bd9Sstevel@tonic-gate 		}
23307c478bd9Sstevel@tonic-gate 		++s;
23317c478bd9Sstevel@tonic-gate 	}
23327c478bd9Sstevel@tonic-gate 	return ok;
23337c478bd9Sstevel@tonic-gate }
23347c478bd9Sstevel@tonic-gate 
23357c478bd9Sstevel@tonic-gate /*
23367c478bd9Sstevel@tonic-gate **  STR2PRT -- convert "unprintable" characters in a string to \oct
23377c478bd9Sstevel@tonic-gate **
23387c478bd9Sstevel@tonic-gate **	Parameters:
23397c478bd9Sstevel@tonic-gate **		s -- string to convert
23407c478bd9Sstevel@tonic-gate **
23417c478bd9Sstevel@tonic-gate **	Returns:
23427c478bd9Sstevel@tonic-gate **		converted string.
23437c478bd9Sstevel@tonic-gate **		This is a static local buffer, string must be copied
23447c478bd9Sstevel@tonic-gate **		before this function is called again!
23457c478bd9Sstevel@tonic-gate */
23467c478bd9Sstevel@tonic-gate 
23477c478bd9Sstevel@tonic-gate char *
23487c478bd9Sstevel@tonic-gate str2prt(s)
23497c478bd9Sstevel@tonic-gate 	char *s;
23507c478bd9Sstevel@tonic-gate {
23517c478bd9Sstevel@tonic-gate 	int l;
23527c478bd9Sstevel@tonic-gate 	char c, *h;
23537c478bd9Sstevel@tonic-gate 	bool ok;
23547c478bd9Sstevel@tonic-gate 	static int len = 0;
23557c478bd9Sstevel@tonic-gate 	static char *buf = NULL;
23567c478bd9Sstevel@tonic-gate 
23577c478bd9Sstevel@tonic-gate 	if (s == NULL)
23587c478bd9Sstevel@tonic-gate 		return NULL;
23597c478bd9Sstevel@tonic-gate 	ok = true;
23607c478bd9Sstevel@tonic-gate 	for (h = s, l = 1; *h != '\0'; h++, l++)
23617c478bd9Sstevel@tonic-gate 	{
23627c478bd9Sstevel@tonic-gate 		if (*h == '\\')
23637c478bd9Sstevel@tonic-gate 		{
23647c478bd9Sstevel@tonic-gate 			++l;
23657c478bd9Sstevel@tonic-gate 			ok = false;
23667c478bd9Sstevel@tonic-gate 		}
23677c478bd9Sstevel@tonic-gate 		else if (!(isascii(*h) && isprint(*h)))
23687c478bd9Sstevel@tonic-gate 		{
23697c478bd9Sstevel@tonic-gate 			l += 3;
23707c478bd9Sstevel@tonic-gate 			ok = false;
23717c478bd9Sstevel@tonic-gate 		}
23727c478bd9Sstevel@tonic-gate 	}
23737c478bd9Sstevel@tonic-gate 	if (ok)
23747c478bd9Sstevel@tonic-gate 		return s;
23757c478bd9Sstevel@tonic-gate 	if (l > len)
23767c478bd9Sstevel@tonic-gate 	{
23777c478bd9Sstevel@tonic-gate 		char *nbuf = sm_pmalloc_x(l);
23787c478bd9Sstevel@tonic-gate 
23797c478bd9Sstevel@tonic-gate 		if (buf != NULL)
23807c478bd9Sstevel@tonic-gate 			sm_free(buf);
23817c478bd9Sstevel@tonic-gate 		len = l;
23827c478bd9Sstevel@tonic-gate 		buf = nbuf;
23837c478bd9Sstevel@tonic-gate 	}
23847c478bd9Sstevel@tonic-gate 	for (h = buf; *s != '\0' && l > 0; s++, l--)
23857c478bd9Sstevel@tonic-gate 	{
23867c478bd9Sstevel@tonic-gate 		c = *s;
23877c478bd9Sstevel@tonic-gate 		if (isascii(c) && isprint(c) && c != '\\')
23887c478bd9Sstevel@tonic-gate 		{
23897c478bd9Sstevel@tonic-gate 			*h++ = c;
23907c478bd9Sstevel@tonic-gate 		}
23917c478bd9Sstevel@tonic-gate 		else
23927c478bd9Sstevel@tonic-gate 		{
23937c478bd9Sstevel@tonic-gate 			*h++ = '\\';
23947c478bd9Sstevel@tonic-gate 			--l;
23957c478bd9Sstevel@tonic-gate 			switch (c)
23967c478bd9Sstevel@tonic-gate 			{
23977c478bd9Sstevel@tonic-gate 			  case '\\':
23987c478bd9Sstevel@tonic-gate 				*h++ = '\\';
23997c478bd9Sstevel@tonic-gate 				break;
24007c478bd9Sstevel@tonic-gate 			  case '\t':
24017c478bd9Sstevel@tonic-gate 				*h++ = 't';
24027c478bd9Sstevel@tonic-gate 				break;
24037c478bd9Sstevel@tonic-gate 			  case '\n':
24047c478bd9Sstevel@tonic-gate 				*h++ = 'n';
24057c478bd9Sstevel@tonic-gate 				break;
24067c478bd9Sstevel@tonic-gate 			  case '\r':
24077c478bd9Sstevel@tonic-gate 				*h++ = 'r';
24087c478bd9Sstevel@tonic-gate 				break;
24097c478bd9Sstevel@tonic-gate 			  default:
2410*445f2479Sjbeck 				SM_ASSERT(l >= 2);
24117c478bd9Sstevel@tonic-gate 				(void) sm_snprintf(h, l, "%03o",
24127c478bd9Sstevel@tonic-gate 					(unsigned int)((unsigned char) c));
24137c478bd9Sstevel@tonic-gate 
24147c478bd9Sstevel@tonic-gate 				/*
24157c478bd9Sstevel@tonic-gate 				**  XXX since l is unsigned this may
24167c478bd9Sstevel@tonic-gate 				**  wrap around if the calculation is screwed
24177c478bd9Sstevel@tonic-gate 				**  up...
24187c478bd9Sstevel@tonic-gate 				*/
24197c478bd9Sstevel@tonic-gate 
24207c478bd9Sstevel@tonic-gate 				l -= 2;
24217c478bd9Sstevel@tonic-gate 				h += 3;
24227c478bd9Sstevel@tonic-gate 				break;
24237c478bd9Sstevel@tonic-gate 			}
24247c478bd9Sstevel@tonic-gate 		}
24257c478bd9Sstevel@tonic-gate 	}
24267c478bd9Sstevel@tonic-gate 	*h = '\0';
24277c478bd9Sstevel@tonic-gate 	buf[len - 1] = '\0';
24287c478bd9Sstevel@tonic-gate 	return buf;
24297c478bd9Sstevel@tonic-gate }
24307c478bd9Sstevel@tonic-gate /*
24317c478bd9Sstevel@tonic-gate **  PATH_IS_DIR -- check to see if file exists and is a directory.
24327c478bd9Sstevel@tonic-gate **
24337c478bd9Sstevel@tonic-gate **	There are some additional checks for security violations in
24347c478bd9Sstevel@tonic-gate **	here.  This routine is intended to be used for the host status
24357c478bd9Sstevel@tonic-gate **	support.
24367c478bd9Sstevel@tonic-gate **
24377c478bd9Sstevel@tonic-gate **	Parameters:
24387c478bd9Sstevel@tonic-gate **		pathname -- pathname to check for directory-ness.
24397c478bd9Sstevel@tonic-gate **		createflag -- if set, create directory if needed.
24407c478bd9Sstevel@tonic-gate **
24417c478bd9Sstevel@tonic-gate **	Returns:
24427c478bd9Sstevel@tonic-gate **		true -- if the indicated pathname is a directory
24437c478bd9Sstevel@tonic-gate **		false -- otherwise
24447c478bd9Sstevel@tonic-gate */
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate bool
24477c478bd9Sstevel@tonic-gate path_is_dir(pathname, createflag)
24487c478bd9Sstevel@tonic-gate 	char *pathname;
24497c478bd9Sstevel@tonic-gate 	bool createflag;
24507c478bd9Sstevel@tonic-gate {
24517c478bd9Sstevel@tonic-gate 	struct stat statbuf;
24527c478bd9Sstevel@tonic-gate 
24537c478bd9Sstevel@tonic-gate #if HASLSTAT
24547c478bd9Sstevel@tonic-gate 	if (lstat(pathname, &statbuf) < 0)
24557c478bd9Sstevel@tonic-gate #else /* HASLSTAT */
24567c478bd9Sstevel@tonic-gate 	if (stat(pathname, &statbuf) < 0)
24577c478bd9Sstevel@tonic-gate #endif /* HASLSTAT */
24587c478bd9Sstevel@tonic-gate 	{
24597c478bd9Sstevel@tonic-gate 		if (errno != ENOENT || !createflag)
24607c478bd9Sstevel@tonic-gate 			return false;
24617c478bd9Sstevel@tonic-gate 		if (mkdir(pathname, 0755) < 0)
24627c478bd9Sstevel@tonic-gate 			return false;
24637c478bd9Sstevel@tonic-gate 		return true;
24647c478bd9Sstevel@tonic-gate 	}
24657c478bd9Sstevel@tonic-gate 	if (!S_ISDIR(statbuf.st_mode))
24667c478bd9Sstevel@tonic-gate 	{
24677c478bd9Sstevel@tonic-gate 		errno = ENOTDIR;
24687c478bd9Sstevel@tonic-gate 		return false;
24697c478bd9Sstevel@tonic-gate 	}
24707c478bd9Sstevel@tonic-gate 
24717c478bd9Sstevel@tonic-gate 	/* security: don't allow writable directories */
24727c478bd9Sstevel@tonic-gate 	if (bitset(S_IWGRP|S_IWOTH, statbuf.st_mode))
24737c478bd9Sstevel@tonic-gate 	{
24747c478bd9Sstevel@tonic-gate 		errno = EACCES;
24757c478bd9Sstevel@tonic-gate 		return false;
24767c478bd9Sstevel@tonic-gate 	}
24777c478bd9Sstevel@tonic-gate 	return true;
24787c478bd9Sstevel@tonic-gate }
24797c478bd9Sstevel@tonic-gate /*
24807c478bd9Sstevel@tonic-gate **  PROC_LIST_ADD -- add process id to list of our children
24817c478bd9Sstevel@tonic-gate **
24827c478bd9Sstevel@tonic-gate **	Parameters:
24837c478bd9Sstevel@tonic-gate **		pid -- pid to add to list.
24847c478bd9Sstevel@tonic-gate **		task -- task of pid.
24857c478bd9Sstevel@tonic-gate **		type -- type of process.
24867c478bd9Sstevel@tonic-gate **		count -- number of processes.
24877c478bd9Sstevel@tonic-gate **		other -- other information for this type.
24887c478bd9Sstevel@tonic-gate **
24897c478bd9Sstevel@tonic-gate **	Returns:
24907c478bd9Sstevel@tonic-gate **		none
24917c478bd9Sstevel@tonic-gate **
24927c478bd9Sstevel@tonic-gate **	Side Effects:
24937c478bd9Sstevel@tonic-gate **		May increase CurChildren. May grow ProcList.
24947c478bd9Sstevel@tonic-gate */
24957c478bd9Sstevel@tonic-gate 
24967c478bd9Sstevel@tonic-gate typedef struct procs	PROCS_T;
24977c478bd9Sstevel@tonic-gate 
24987c478bd9Sstevel@tonic-gate struct procs
24997c478bd9Sstevel@tonic-gate {
25007c478bd9Sstevel@tonic-gate 	pid_t		proc_pid;
25017c478bd9Sstevel@tonic-gate 	char		*proc_task;
25027c478bd9Sstevel@tonic-gate 	int		proc_type;
25037c478bd9Sstevel@tonic-gate 	int		proc_count;
25047c478bd9Sstevel@tonic-gate 	int		proc_other;
25057c478bd9Sstevel@tonic-gate 	SOCKADDR	proc_hostaddr;
25067c478bd9Sstevel@tonic-gate };
25077c478bd9Sstevel@tonic-gate 
25087c478bd9Sstevel@tonic-gate static PROCS_T	*volatile ProcListVec = NULL;
25097c478bd9Sstevel@tonic-gate static int	ProcListSize = 0;
25107c478bd9Sstevel@tonic-gate 
25117c478bd9Sstevel@tonic-gate void
25127c478bd9Sstevel@tonic-gate proc_list_add(pid, task, type, count, other, hostaddr)
25137c478bd9Sstevel@tonic-gate 	pid_t pid;
25147c478bd9Sstevel@tonic-gate 	char *task;
25157c478bd9Sstevel@tonic-gate 	int type;
25167c478bd9Sstevel@tonic-gate 	int count;
25177c478bd9Sstevel@tonic-gate 	int other;
25187c478bd9Sstevel@tonic-gate 	SOCKADDR *hostaddr;
25197c478bd9Sstevel@tonic-gate {
25207c478bd9Sstevel@tonic-gate 	int i;
25217c478bd9Sstevel@tonic-gate 
25227c478bd9Sstevel@tonic-gate 	for (i = 0; i < ProcListSize; i++)
25237c478bd9Sstevel@tonic-gate 	{
25247c478bd9Sstevel@tonic-gate 		if (ProcListVec[i].proc_pid == NO_PID)
25257c478bd9Sstevel@tonic-gate 			break;
25267c478bd9Sstevel@tonic-gate 	}
25277c478bd9Sstevel@tonic-gate 	if (i >= ProcListSize)
25287c478bd9Sstevel@tonic-gate 	{
25297c478bd9Sstevel@tonic-gate 		/* probe the existing vector to avoid growing infinitely */
25307c478bd9Sstevel@tonic-gate 		proc_list_probe();
25317c478bd9Sstevel@tonic-gate 
25327c478bd9Sstevel@tonic-gate 		/* now scan again */
25337c478bd9Sstevel@tonic-gate 		for (i = 0; i < ProcListSize; i++)
25347c478bd9Sstevel@tonic-gate 		{
25357c478bd9Sstevel@tonic-gate 			if (ProcListVec[i].proc_pid == NO_PID)
25367c478bd9Sstevel@tonic-gate 				break;
25377c478bd9Sstevel@tonic-gate 		}
25387c478bd9Sstevel@tonic-gate 	}
25397c478bd9Sstevel@tonic-gate 	if (i >= ProcListSize)
25407c478bd9Sstevel@tonic-gate 	{
25417c478bd9Sstevel@tonic-gate 		/* grow process list */
25427c478bd9Sstevel@tonic-gate 		PROCS_T *npv;
25437c478bd9Sstevel@tonic-gate 
25447c478bd9Sstevel@tonic-gate 		SM_ASSERT(ProcListSize < INT_MAX - PROC_LIST_SEG);
25457c478bd9Sstevel@tonic-gate 		npv = (PROCS_T *) sm_pmalloc_x((sizeof *npv) *
25467c478bd9Sstevel@tonic-gate 					       (ProcListSize + PROC_LIST_SEG));
25477c478bd9Sstevel@tonic-gate 		if (ProcListSize > 0)
25487c478bd9Sstevel@tonic-gate 		{
25497c478bd9Sstevel@tonic-gate 			memmove(npv, ProcListVec,
25507c478bd9Sstevel@tonic-gate 				ProcListSize * sizeof (PROCS_T));
25517c478bd9Sstevel@tonic-gate 			sm_free(ProcListVec);
25527c478bd9Sstevel@tonic-gate 		}
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate 		/* XXX just use memset() to initialize this part? */
25557c478bd9Sstevel@tonic-gate 		for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++)
25567c478bd9Sstevel@tonic-gate 		{
25577c478bd9Sstevel@tonic-gate 			npv[i].proc_pid = NO_PID;
25587c478bd9Sstevel@tonic-gate 			npv[i].proc_task = NULL;
25597c478bd9Sstevel@tonic-gate 			npv[i].proc_type = PROC_NONE;
25607c478bd9Sstevel@tonic-gate 		}
25617c478bd9Sstevel@tonic-gate 		i = ProcListSize;
25627c478bd9Sstevel@tonic-gate 		ProcListSize += PROC_LIST_SEG;
25637c478bd9Sstevel@tonic-gate 		ProcListVec = npv;
25647c478bd9Sstevel@tonic-gate 	}
25657c478bd9Sstevel@tonic-gate 	ProcListVec[i].proc_pid = pid;
25667c478bd9Sstevel@tonic-gate 	PSTRSET(ProcListVec[i].proc_task, task);
25677c478bd9Sstevel@tonic-gate 	ProcListVec[i].proc_type = type;
25687c478bd9Sstevel@tonic-gate 	ProcListVec[i].proc_count = count;
25697c478bd9Sstevel@tonic-gate 	ProcListVec[i].proc_other = other;
25707c478bd9Sstevel@tonic-gate 	if (hostaddr != NULL)
25717c478bd9Sstevel@tonic-gate 		ProcListVec[i].proc_hostaddr = *hostaddr;
25727c478bd9Sstevel@tonic-gate 	else
25737c478bd9Sstevel@tonic-gate 		memset(&ProcListVec[i].proc_hostaddr, 0,
25747c478bd9Sstevel@tonic-gate 			sizeof(ProcListVec[i].proc_hostaddr));
25757c478bd9Sstevel@tonic-gate 
25767c478bd9Sstevel@tonic-gate 	/* if process adding itself, it's not a child */
25777c478bd9Sstevel@tonic-gate 	if (pid != CurrentPid)
25787c478bd9Sstevel@tonic-gate 	{
25797c478bd9Sstevel@tonic-gate 		SM_ASSERT(CurChildren < INT_MAX);
25807c478bd9Sstevel@tonic-gate 		CurChildren++;
25817c478bd9Sstevel@tonic-gate 	}
25827c478bd9Sstevel@tonic-gate }
25837c478bd9Sstevel@tonic-gate /*
25847c478bd9Sstevel@tonic-gate **  PROC_LIST_SET -- set pid task in process list
25857c478bd9Sstevel@tonic-gate **
25867c478bd9Sstevel@tonic-gate **	Parameters:
25877c478bd9Sstevel@tonic-gate **		pid -- pid to set
25887c478bd9Sstevel@tonic-gate **		task -- task of pid
25897c478bd9Sstevel@tonic-gate **
25907c478bd9Sstevel@tonic-gate **	Returns:
25917c478bd9Sstevel@tonic-gate **		none.
25927c478bd9Sstevel@tonic-gate */
25937c478bd9Sstevel@tonic-gate 
25947c478bd9Sstevel@tonic-gate void
25957c478bd9Sstevel@tonic-gate proc_list_set(pid, task)
25967c478bd9Sstevel@tonic-gate 	pid_t pid;
25977c478bd9Sstevel@tonic-gate 	char *task;
25987c478bd9Sstevel@tonic-gate {
25997c478bd9Sstevel@tonic-gate 	int i;
26007c478bd9Sstevel@tonic-gate 
26017c478bd9Sstevel@tonic-gate 	for (i = 0; i < ProcListSize; i++)
26027c478bd9Sstevel@tonic-gate 	{
26037c478bd9Sstevel@tonic-gate 		if (ProcListVec[i].proc_pid == pid)
26047c478bd9Sstevel@tonic-gate 		{
26057c478bd9Sstevel@tonic-gate 			PSTRSET(ProcListVec[i].proc_task, task);
26067c478bd9Sstevel@tonic-gate 			break;
26077c478bd9Sstevel@tonic-gate 		}
26087c478bd9Sstevel@tonic-gate 	}
26097c478bd9Sstevel@tonic-gate }
26107c478bd9Sstevel@tonic-gate /*
26117c478bd9Sstevel@tonic-gate **  PROC_LIST_DROP -- drop pid from process list
26127c478bd9Sstevel@tonic-gate **
26137c478bd9Sstevel@tonic-gate **	Parameters:
26147c478bd9Sstevel@tonic-gate **		pid -- pid to drop
26157c478bd9Sstevel@tonic-gate **		st -- process status
26167c478bd9Sstevel@tonic-gate **		other -- storage for proc_other (return).
26177c478bd9Sstevel@tonic-gate **
26187c478bd9Sstevel@tonic-gate **	Returns:
26197c478bd9Sstevel@tonic-gate **		none.
26207c478bd9Sstevel@tonic-gate **
26217c478bd9Sstevel@tonic-gate **	Side Effects:
26227c478bd9Sstevel@tonic-gate **		May decrease CurChildren, CurRunners, or
26237c478bd9Sstevel@tonic-gate **		set RestartRequest or ShutdownRequest.
26247c478bd9Sstevel@tonic-gate **
26257c478bd9Sstevel@tonic-gate **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
26267c478bd9Sstevel@tonic-gate **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
26277c478bd9Sstevel@tonic-gate **		DOING.
26287c478bd9Sstevel@tonic-gate */
26297c478bd9Sstevel@tonic-gate 
26307c478bd9Sstevel@tonic-gate void
26317c478bd9Sstevel@tonic-gate proc_list_drop(pid, st, other)
26327c478bd9Sstevel@tonic-gate 	pid_t pid;
26337c478bd9Sstevel@tonic-gate 	int st;
26347c478bd9Sstevel@tonic-gate 	int *other;
26357c478bd9Sstevel@tonic-gate {
26367c478bd9Sstevel@tonic-gate 	int i;
26377c478bd9Sstevel@tonic-gate 	int type = PROC_NONE;
26387c478bd9Sstevel@tonic-gate 
26397c478bd9Sstevel@tonic-gate 	for (i = 0; i < ProcListSize; i++)
26407c478bd9Sstevel@tonic-gate 	{
26417c478bd9Sstevel@tonic-gate 		if (ProcListVec[i].proc_pid == pid)
26427c478bd9Sstevel@tonic-gate 		{
26437c478bd9Sstevel@tonic-gate 			ProcListVec[i].proc_pid = NO_PID;
26447c478bd9Sstevel@tonic-gate 			type = ProcListVec[i].proc_type;
26457c478bd9Sstevel@tonic-gate 			if (other != NULL)
26467c478bd9Sstevel@tonic-gate 				*other = ProcListVec[i].proc_other;
2647*445f2479Sjbeck 			if (CurChildren > 0)
2648*445f2479Sjbeck 				CurChildren--;
26497c478bd9Sstevel@tonic-gate 			break;
26507c478bd9Sstevel@tonic-gate 		}
26517c478bd9Sstevel@tonic-gate 	}
26527c478bd9Sstevel@tonic-gate 
26537c478bd9Sstevel@tonic-gate 
26547c478bd9Sstevel@tonic-gate 	if (type == PROC_CONTROL && WIFEXITED(st))
26557c478bd9Sstevel@tonic-gate 	{
26567c478bd9Sstevel@tonic-gate 		/* if so, see if we need to restart or shutdown */
26577c478bd9Sstevel@tonic-gate 		if (WEXITSTATUS(st) == EX_RESTART)
26587c478bd9Sstevel@tonic-gate 			RestartRequest = "control socket";
26597c478bd9Sstevel@tonic-gate 		else if (WEXITSTATUS(st) == EX_SHUTDOWN)
26607c478bd9Sstevel@tonic-gate 			ShutdownRequest = "control socket";
26617c478bd9Sstevel@tonic-gate 	}
26627c478bd9Sstevel@tonic-gate 	else if (type == PROC_QUEUE_CHILD && !WIFSTOPPED(st) &&
26637c478bd9Sstevel@tonic-gate 		 ProcListVec[i].proc_other > -1)
26647c478bd9Sstevel@tonic-gate 	{
26657c478bd9Sstevel@tonic-gate 		/* restart this persistent runner */
26667c478bd9Sstevel@tonic-gate 		mark_work_group_restart(ProcListVec[i].proc_other, st);
26677c478bd9Sstevel@tonic-gate 	}
26687c478bd9Sstevel@tonic-gate 	else if (type == PROC_QUEUE)
26697c478bd9Sstevel@tonic-gate 		CurRunners -= ProcListVec[i].proc_count;
26707c478bd9Sstevel@tonic-gate }
26717c478bd9Sstevel@tonic-gate /*
26727c478bd9Sstevel@tonic-gate **  PROC_LIST_CLEAR -- clear the process list
26737c478bd9Sstevel@tonic-gate **
26747c478bd9Sstevel@tonic-gate **	Parameters:
26757c478bd9Sstevel@tonic-gate **		none.
26767c478bd9Sstevel@tonic-gate **
26777c478bd9Sstevel@tonic-gate **	Returns:
26787c478bd9Sstevel@tonic-gate **		none.
26797c478bd9Sstevel@tonic-gate **
26807c478bd9Sstevel@tonic-gate **	Side Effects:
26817c478bd9Sstevel@tonic-gate **		Sets CurChildren to zero.
26827c478bd9Sstevel@tonic-gate */
26837c478bd9Sstevel@tonic-gate 
26847c478bd9Sstevel@tonic-gate void
26857c478bd9Sstevel@tonic-gate proc_list_clear()
26867c478bd9Sstevel@tonic-gate {
26877c478bd9Sstevel@tonic-gate 	int i;
26887c478bd9Sstevel@tonic-gate 
26897c478bd9Sstevel@tonic-gate 	/* start from 1 since 0 is the daemon itself */
26907c478bd9Sstevel@tonic-gate 	for (i = 1; i < ProcListSize; i++)
26917c478bd9Sstevel@tonic-gate 		ProcListVec[i].proc_pid = NO_PID;
26927c478bd9Sstevel@tonic-gate 	CurChildren = 0;
26937c478bd9Sstevel@tonic-gate }
26947c478bd9Sstevel@tonic-gate /*
26957c478bd9Sstevel@tonic-gate **  PROC_LIST_PROBE -- probe processes in the list to see if they still exist
26967c478bd9Sstevel@tonic-gate **
26977c478bd9Sstevel@tonic-gate **	Parameters:
26987c478bd9Sstevel@tonic-gate **		none
26997c478bd9Sstevel@tonic-gate **
27007c478bd9Sstevel@tonic-gate **	Returns:
27017c478bd9Sstevel@tonic-gate **		none
27027c478bd9Sstevel@tonic-gate **
27037c478bd9Sstevel@tonic-gate **	Side Effects:
27047c478bd9Sstevel@tonic-gate **		May decrease CurChildren.
27057c478bd9Sstevel@tonic-gate */
27067c478bd9Sstevel@tonic-gate 
27077c478bd9Sstevel@tonic-gate void
27087c478bd9Sstevel@tonic-gate proc_list_probe()
27097c478bd9Sstevel@tonic-gate {
2710*445f2479Sjbeck 	int i, children;
2711*445f2479Sjbeck 	int chldwasblocked;
2712*445f2479Sjbeck 	pid_t pid;
2713*445f2479Sjbeck 
2714*445f2479Sjbeck 	children = 0;
2715*445f2479Sjbeck 	chldwasblocked = sm_blocksignal(SIGCHLD);
27167c478bd9Sstevel@tonic-gate 
27177c478bd9Sstevel@tonic-gate 	/* start from 1 since 0 is the daemon itself */
27187c478bd9Sstevel@tonic-gate 	for (i = 1; i < ProcListSize; i++)
27197c478bd9Sstevel@tonic-gate 	{
2720*445f2479Sjbeck 		pid = ProcListVec[i].proc_pid;
2721*445f2479Sjbeck 		if (pid == NO_PID || pid == CurrentPid)
27227c478bd9Sstevel@tonic-gate 			continue;
2723*445f2479Sjbeck 		if (kill(pid, 0) < 0)
27247c478bd9Sstevel@tonic-gate 		{
27257c478bd9Sstevel@tonic-gate 			if (LogLevel > 3)
27267c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_DEBUG, CurEnv->e_id,
27277c478bd9Sstevel@tonic-gate 					  "proc_list_probe: lost pid %d",
27287c478bd9Sstevel@tonic-gate 					  (int) ProcListVec[i].proc_pid);
27297c478bd9Sstevel@tonic-gate 			ProcListVec[i].proc_pid = NO_PID;
27307c478bd9Sstevel@tonic-gate 			SM_FREE_CLR(ProcListVec[i].proc_task);
27317c478bd9Sstevel@tonic-gate 			CurChildren--;
27327c478bd9Sstevel@tonic-gate 		}
2733*445f2479Sjbeck 		else
2734*445f2479Sjbeck 		{
2735*445f2479Sjbeck 			++children;
2736*445f2479Sjbeck 		}
27377c478bd9Sstevel@tonic-gate 	}
27387c478bd9Sstevel@tonic-gate 	if (CurChildren < 0)
27397c478bd9Sstevel@tonic-gate 		CurChildren = 0;
2740*445f2479Sjbeck 	if (chldwasblocked == 0)
2741*445f2479Sjbeck 		(void) sm_releasesignal(SIGCHLD);
2742*445f2479Sjbeck 	if (LogLevel > 10 && children != CurChildren)
2743*445f2479Sjbeck 	{
2744*445f2479Sjbeck 		sm_syslog(LOG_ERR, NOQID,
2745*445f2479Sjbeck 			  "proc_list_probe: found %d children, expected %d",
2746*445f2479Sjbeck 			  children, CurChildren);
2747*445f2479Sjbeck 	}
27487c478bd9Sstevel@tonic-gate }
27497c478bd9Sstevel@tonic-gate 
27507c478bd9Sstevel@tonic-gate /*
27517c478bd9Sstevel@tonic-gate **  PROC_LIST_DISPLAY -- display the process list
27527c478bd9Sstevel@tonic-gate **
27537c478bd9Sstevel@tonic-gate **	Parameters:
27547c478bd9Sstevel@tonic-gate **		out -- output file pointer
27557c478bd9Sstevel@tonic-gate **		prefix -- string to output in front of each line.
27567c478bd9Sstevel@tonic-gate **
27577c478bd9Sstevel@tonic-gate **	Returns:
27587c478bd9Sstevel@tonic-gate **		none.
27597c478bd9Sstevel@tonic-gate */
27607c478bd9Sstevel@tonic-gate 
27617c478bd9Sstevel@tonic-gate void
27627c478bd9Sstevel@tonic-gate proc_list_display(out, prefix)
27637c478bd9Sstevel@tonic-gate 	SM_FILE_T *out;
27647c478bd9Sstevel@tonic-gate 	char *prefix;
27657c478bd9Sstevel@tonic-gate {
27667c478bd9Sstevel@tonic-gate 	int i;
27677c478bd9Sstevel@tonic-gate 
27687c478bd9Sstevel@tonic-gate 	for (i = 0; i < ProcListSize; i++)
27697c478bd9Sstevel@tonic-gate 	{
27707c478bd9Sstevel@tonic-gate 		if (ProcListVec[i].proc_pid == NO_PID)
27717c478bd9Sstevel@tonic-gate 			continue;
27727c478bd9Sstevel@tonic-gate 
27737c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(out, SM_TIME_DEFAULT, "%s%d %s%s\n",
27747c478bd9Sstevel@tonic-gate 				     prefix,
27757c478bd9Sstevel@tonic-gate 				     (int) ProcListVec[i].proc_pid,
27767c478bd9Sstevel@tonic-gate 				     ProcListVec[i].proc_task != NULL ?
27777c478bd9Sstevel@tonic-gate 				     ProcListVec[i].proc_task : "(unknown)",
27787c478bd9Sstevel@tonic-gate 				     (OpMode == MD_SMTP ||
27797c478bd9Sstevel@tonic-gate 				      OpMode == MD_DAEMON ||
27807c478bd9Sstevel@tonic-gate 				      OpMode == MD_ARPAFTP) ? "\r" : "");
27817c478bd9Sstevel@tonic-gate 	}
27827c478bd9Sstevel@tonic-gate }
27837c478bd9Sstevel@tonic-gate 
27847c478bd9Sstevel@tonic-gate /*
27857c478bd9Sstevel@tonic-gate **  PROC_LIST_SIGNAL -- send a signal to a type of process in the list
27867c478bd9Sstevel@tonic-gate **
27877c478bd9Sstevel@tonic-gate **	Parameters:
27887c478bd9Sstevel@tonic-gate **		type -- type of process to signal
27897c478bd9Sstevel@tonic-gate **		signal -- the type of signal to send
27907c478bd9Sstevel@tonic-gate **
27917c478bd9Sstevel@tonic-gate **	Results:
27927c478bd9Sstevel@tonic-gate **		none.
27937c478bd9Sstevel@tonic-gate **
27947c478bd9Sstevel@tonic-gate **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
27957c478bd9Sstevel@tonic-gate **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
27967c478bd9Sstevel@tonic-gate **		DOING.
27977c478bd9Sstevel@tonic-gate */
27987c478bd9Sstevel@tonic-gate 
27997c478bd9Sstevel@tonic-gate void
28007c478bd9Sstevel@tonic-gate proc_list_signal(type, signal)
28017c478bd9Sstevel@tonic-gate 	int type;
28027c478bd9Sstevel@tonic-gate 	int signal;
28037c478bd9Sstevel@tonic-gate {
28047c478bd9Sstevel@tonic-gate 	int chldwasblocked;
28057c478bd9Sstevel@tonic-gate 	int alrmwasblocked;
28067c478bd9Sstevel@tonic-gate 	int i;
28077c478bd9Sstevel@tonic-gate 	pid_t mypid = getpid();
28087c478bd9Sstevel@tonic-gate 
28097c478bd9Sstevel@tonic-gate 	/* block these signals so that we may signal cleanly */
28107c478bd9Sstevel@tonic-gate 	chldwasblocked = sm_blocksignal(SIGCHLD);
28117c478bd9Sstevel@tonic-gate 	alrmwasblocked = sm_blocksignal(SIGALRM);
28127c478bd9Sstevel@tonic-gate 
28137c478bd9Sstevel@tonic-gate 	/* Find all processes of type and send signal */
28147c478bd9Sstevel@tonic-gate 	for (i = 0; i < ProcListSize; i++)
28157c478bd9Sstevel@tonic-gate 	{
28167c478bd9Sstevel@tonic-gate 		if (ProcListVec[i].proc_pid == NO_PID ||
28177c478bd9Sstevel@tonic-gate 		    ProcListVec[i].proc_pid == mypid)
28187c478bd9Sstevel@tonic-gate 			continue;
28197c478bd9Sstevel@tonic-gate 		if (ProcListVec[i].proc_type != type)
28207c478bd9Sstevel@tonic-gate 			continue;
28217c478bd9Sstevel@tonic-gate 		(void) kill(ProcListVec[i].proc_pid, signal);
28227c478bd9Sstevel@tonic-gate 	}
28237c478bd9Sstevel@tonic-gate 
28247c478bd9Sstevel@tonic-gate 	/* restore the signals */
28257c478bd9Sstevel@tonic-gate 	if (alrmwasblocked == 0)
28267c478bd9Sstevel@tonic-gate 		(void) sm_releasesignal(SIGALRM);
28277c478bd9Sstevel@tonic-gate 	if (chldwasblocked == 0)
28287c478bd9Sstevel@tonic-gate 		(void) sm_releasesignal(SIGCHLD);
28297c478bd9Sstevel@tonic-gate }
28307c478bd9Sstevel@tonic-gate 
28317c478bd9Sstevel@tonic-gate /*
28327c478bd9Sstevel@tonic-gate **  COUNT_OPEN_CONNECTIONS
28337c478bd9Sstevel@tonic-gate **
28347c478bd9Sstevel@tonic-gate **	Parameters:
28357c478bd9Sstevel@tonic-gate **		hostaddr - ClientAddress
28367c478bd9Sstevel@tonic-gate **
28377c478bd9Sstevel@tonic-gate **	Returns:
28387c478bd9Sstevel@tonic-gate **		the number of open connections for this client
28397c478bd9Sstevel@tonic-gate **
28407c478bd9Sstevel@tonic-gate */
28417c478bd9Sstevel@tonic-gate 
28427c478bd9Sstevel@tonic-gate int
28437c478bd9Sstevel@tonic-gate count_open_connections(hostaddr)
28447c478bd9Sstevel@tonic-gate 	SOCKADDR *hostaddr;
28457c478bd9Sstevel@tonic-gate {
28467c478bd9Sstevel@tonic-gate 	int i, n;
28477c478bd9Sstevel@tonic-gate 
28487c478bd9Sstevel@tonic-gate 	if (hostaddr == NULL)
28497c478bd9Sstevel@tonic-gate 		return 0;
28507c478bd9Sstevel@tonic-gate 	n = 0;
28517c478bd9Sstevel@tonic-gate 	for (i = 0; i < ProcListSize; i++)
28527c478bd9Sstevel@tonic-gate 	{
28537c478bd9Sstevel@tonic-gate 		if (ProcListVec[i].proc_pid == NO_PID)
28547c478bd9Sstevel@tonic-gate 			continue;
28557c478bd9Sstevel@tonic-gate 		if (hostaddr->sa.sa_family !=
28567c478bd9Sstevel@tonic-gate 		    ProcListVec[i].proc_hostaddr.sa.sa_family)
28577c478bd9Sstevel@tonic-gate 			continue;
28587c478bd9Sstevel@tonic-gate #if NETINET
28597c478bd9Sstevel@tonic-gate 		if (hostaddr->sa.sa_family == AF_INET &&
28607c478bd9Sstevel@tonic-gate 		    (hostaddr->sin.sin_addr.s_addr ==
28617c478bd9Sstevel@tonic-gate 		     ProcListVec[i].proc_hostaddr.sin.sin_addr.s_addr))
28627c478bd9Sstevel@tonic-gate 			n++;
28637c478bd9Sstevel@tonic-gate #endif /* NETINET */
28647c478bd9Sstevel@tonic-gate #if NETINET6
28657c478bd9Sstevel@tonic-gate 		if (hostaddr->sa.sa_family == AF_INET6 &&
28667c478bd9Sstevel@tonic-gate 		    IN6_ARE_ADDR_EQUAL(&(hostaddr->sin6.sin6_addr),
28677c478bd9Sstevel@tonic-gate 				       &(ProcListVec[i].proc_hostaddr.sin6.sin6_addr)))
28687c478bd9Sstevel@tonic-gate 			n++;
28697c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
28707c478bd9Sstevel@tonic-gate 	}
28717c478bd9Sstevel@tonic-gate 	return n;
28727c478bd9Sstevel@tonic-gate }
2873