xref: /titanic_50/usr/src/cmd/sendmail/src/mci.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1998-2005 Sendmail, Inc. and its suppliers.
3*7c478bd9Sstevel@tonic-gate  *	All rights reserved.
4*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1995-1997 Eric P. Allman.  All rights reserved.
5*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1988, 1993
6*7c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
7*7c478bd9Sstevel@tonic-gate  *
8*7c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
9*7c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
10*7c478bd9Sstevel@tonic-gate  * the sendmail distribution.
11*7c478bd9Sstevel@tonic-gate  *
12*7c478bd9Sstevel@tonic-gate  */
13*7c478bd9Sstevel@tonic-gate 
14*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
15*7c478bd9Sstevel@tonic-gate 
16*7c478bd9Sstevel@tonic-gate #include <sendmail.h>
17*7c478bd9Sstevel@tonic-gate 
18*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: mci.c,v 8.214 2005/02/04 22:01:45 ca Exp $")
19*7c478bd9Sstevel@tonic-gate 
20*7c478bd9Sstevel@tonic-gate #if NETINET || NETINET6
21*7c478bd9Sstevel@tonic-gate # include <arpa/inet.h>
22*7c478bd9Sstevel@tonic-gate #endif /* NETINET || NETINET6 */
23*7c478bd9Sstevel@tonic-gate 
24*7c478bd9Sstevel@tonic-gate #include <dirent.h>
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate static int	mci_generate_persistent_path __P((const char *, char *,
27*7c478bd9Sstevel@tonic-gate 						  int, bool));
28*7c478bd9Sstevel@tonic-gate static bool	mci_load_persistent __P((MCI *));
29*7c478bd9Sstevel@tonic-gate static void	mci_uncache __P((MCI **, bool));
30*7c478bd9Sstevel@tonic-gate static int	mci_lock_host_statfile __P((MCI *));
31*7c478bd9Sstevel@tonic-gate static int	mci_read_persistent __P((SM_FILE_T *, MCI *));
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate /*
34*7c478bd9Sstevel@tonic-gate **  Mail Connection Information (MCI) Caching Module.
35*7c478bd9Sstevel@tonic-gate **
36*7c478bd9Sstevel@tonic-gate **	There are actually two separate things cached.  The first is
37*7c478bd9Sstevel@tonic-gate **	the set of all open connections -- these are stored in a
38*7c478bd9Sstevel@tonic-gate **	(small) list.  The second is stored in the symbol table; it
39*7c478bd9Sstevel@tonic-gate **	has the overall status for all hosts, whether or not there
40*7c478bd9Sstevel@tonic-gate **	is a connection open currently.
41*7c478bd9Sstevel@tonic-gate **
42*7c478bd9Sstevel@tonic-gate **	There should never be too many connections open (since this
43*7c478bd9Sstevel@tonic-gate **	could flood the socket table), nor should a connection be
44*7c478bd9Sstevel@tonic-gate **	allowed to sit idly for too long.
45*7c478bd9Sstevel@tonic-gate **
46*7c478bd9Sstevel@tonic-gate **	MaxMciCache is the maximum number of open connections that
47*7c478bd9Sstevel@tonic-gate **	will be supported.
48*7c478bd9Sstevel@tonic-gate **
49*7c478bd9Sstevel@tonic-gate **	MciCacheTimeout is the time (in seconds) that a connection
50*7c478bd9Sstevel@tonic-gate **	is permitted to survive without activity.
51*7c478bd9Sstevel@tonic-gate **
52*7c478bd9Sstevel@tonic-gate **	We actually try any cached connections by sending a NOOP
53*7c478bd9Sstevel@tonic-gate **	before we use them; if the NOOP fails we close down the
54*7c478bd9Sstevel@tonic-gate **	connection and reopen it.  Note that this means that a
55*7c478bd9Sstevel@tonic-gate **	server SMTP that doesn't support NOOP will hose the
56*7c478bd9Sstevel@tonic-gate **	algorithm -- but that doesn't seem too likely.
57*7c478bd9Sstevel@tonic-gate **
58*7c478bd9Sstevel@tonic-gate **	The persistent MCI code is donated by Mark Lovell and Paul
59*7c478bd9Sstevel@tonic-gate **	Vixie.  It is based on the long term host status code in KJS
60*7c478bd9Sstevel@tonic-gate **	written by Paul but has been adapted by Mark to fit into the
61*7c478bd9Sstevel@tonic-gate **	MCI structure.
62*7c478bd9Sstevel@tonic-gate */
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate static MCI	**MciCache;		/* the open connection cache */
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate /*
67*7c478bd9Sstevel@tonic-gate **  MCI_CACHE -- enter a connection structure into the open connection cache
68*7c478bd9Sstevel@tonic-gate **
69*7c478bd9Sstevel@tonic-gate **	This may cause something else to be flushed.
70*7c478bd9Sstevel@tonic-gate **
71*7c478bd9Sstevel@tonic-gate **	Parameters:
72*7c478bd9Sstevel@tonic-gate **		mci -- the connection to cache.
73*7c478bd9Sstevel@tonic-gate **
74*7c478bd9Sstevel@tonic-gate **	Returns:
75*7c478bd9Sstevel@tonic-gate **		none.
76*7c478bd9Sstevel@tonic-gate */
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate void
79*7c478bd9Sstevel@tonic-gate mci_cache(mci)
80*7c478bd9Sstevel@tonic-gate 	register MCI *mci;
81*7c478bd9Sstevel@tonic-gate {
82*7c478bd9Sstevel@tonic-gate 	register MCI **mcislot;
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate 	/*
85*7c478bd9Sstevel@tonic-gate 	**  Find the best slot.  This may cause expired connections
86*7c478bd9Sstevel@tonic-gate 	**  to be closed.
87*7c478bd9Sstevel@tonic-gate 	*/
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 	mcislot = mci_scan(mci);
90*7c478bd9Sstevel@tonic-gate 	if (mcislot == NULL)
91*7c478bd9Sstevel@tonic-gate 	{
92*7c478bd9Sstevel@tonic-gate 		/* we don't support caching */
93*7c478bd9Sstevel@tonic-gate 		return;
94*7c478bd9Sstevel@tonic-gate 	}
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	if (mci->mci_host == NULL)
97*7c478bd9Sstevel@tonic-gate 		return;
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	/* if this is already cached, we are done */
100*7c478bd9Sstevel@tonic-gate 	if (bitset(MCIF_CACHED, mci->mci_flags))
101*7c478bd9Sstevel@tonic-gate 		return;
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate 	/* otherwise we may have to clear the slot */
104*7c478bd9Sstevel@tonic-gate 	if (*mcislot != NULL)
105*7c478bd9Sstevel@tonic-gate 		mci_uncache(mcislot, true);
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	if (tTd(42, 5))
108*7c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_cache: caching %p (%s) in slot %d\n",
109*7c478bd9Sstevel@tonic-gate 			   mci, mci->mci_host, (int) (mcislot - MciCache));
110*7c478bd9Sstevel@tonic-gate 	if (tTd(91, 100))
111*7c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_DEBUG, CurEnv->e_id,
112*7c478bd9Sstevel@tonic-gate 			  "mci_cache: caching %lx (%.100s) in slot %d",
113*7c478bd9Sstevel@tonic-gate 			  (unsigned long) mci, mci->mci_host,
114*7c478bd9Sstevel@tonic-gate 			  (int) (mcislot - MciCache));
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	*mcislot = mci;
117*7c478bd9Sstevel@tonic-gate 	mci->mci_flags |= MCIF_CACHED;
118*7c478bd9Sstevel@tonic-gate }
119*7c478bd9Sstevel@tonic-gate /*
120*7c478bd9Sstevel@tonic-gate **  MCI_SCAN -- scan the cache, flush junk, and return best slot
121*7c478bd9Sstevel@tonic-gate **
122*7c478bd9Sstevel@tonic-gate **	Parameters:
123*7c478bd9Sstevel@tonic-gate **		savemci -- never flush this one.  Can be null.
124*7c478bd9Sstevel@tonic-gate **
125*7c478bd9Sstevel@tonic-gate **	Returns:
126*7c478bd9Sstevel@tonic-gate **		The LRU (or empty) slot.
127*7c478bd9Sstevel@tonic-gate */
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate MCI **
130*7c478bd9Sstevel@tonic-gate mci_scan(savemci)
131*7c478bd9Sstevel@tonic-gate 	MCI *savemci;
132*7c478bd9Sstevel@tonic-gate {
133*7c478bd9Sstevel@tonic-gate 	time_t now;
134*7c478bd9Sstevel@tonic-gate 	register MCI **bestmci;
135*7c478bd9Sstevel@tonic-gate 	register MCI *mci;
136*7c478bd9Sstevel@tonic-gate 	register int i;
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	if (MaxMciCache <= 0)
139*7c478bd9Sstevel@tonic-gate 	{
140*7c478bd9Sstevel@tonic-gate 		/* we don't support caching */
141*7c478bd9Sstevel@tonic-gate 		return NULL;
142*7c478bd9Sstevel@tonic-gate 	}
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	if (MciCache == NULL)
145*7c478bd9Sstevel@tonic-gate 	{
146*7c478bd9Sstevel@tonic-gate 		/* first call */
147*7c478bd9Sstevel@tonic-gate 		MciCache = (MCI **) sm_pmalloc_x(MaxMciCache * sizeof *MciCache);
148*7c478bd9Sstevel@tonic-gate 		memset((char *) MciCache, '\0', MaxMciCache * sizeof *MciCache);
149*7c478bd9Sstevel@tonic-gate 		return &MciCache[0];
150*7c478bd9Sstevel@tonic-gate 	}
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	now = curtime();
153*7c478bd9Sstevel@tonic-gate 	bestmci = &MciCache[0];
154*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MaxMciCache; i++)
155*7c478bd9Sstevel@tonic-gate 	{
156*7c478bd9Sstevel@tonic-gate 		mci = MciCache[i];
157*7c478bd9Sstevel@tonic-gate 		if (mci == NULL || mci->mci_state == MCIS_CLOSED)
158*7c478bd9Sstevel@tonic-gate 		{
159*7c478bd9Sstevel@tonic-gate 			bestmci = &MciCache[i];
160*7c478bd9Sstevel@tonic-gate 			continue;
161*7c478bd9Sstevel@tonic-gate 		}
162*7c478bd9Sstevel@tonic-gate 		if ((mci->mci_lastuse + MciCacheTimeout <= now ||
163*7c478bd9Sstevel@tonic-gate 		     (mci->mci_mailer != NULL &&
164*7c478bd9Sstevel@tonic-gate 		      mci->mci_mailer->m_maxdeliveries > 0 &&
165*7c478bd9Sstevel@tonic-gate 		      mci->mci_deliveries + 1 >= mci->mci_mailer->m_maxdeliveries))&&
166*7c478bd9Sstevel@tonic-gate 		    mci != savemci)
167*7c478bd9Sstevel@tonic-gate 		{
168*7c478bd9Sstevel@tonic-gate 			/* connection idle too long or too many deliveries */
169*7c478bd9Sstevel@tonic-gate 			bestmci = &MciCache[i];
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 			/* close it */
172*7c478bd9Sstevel@tonic-gate 			mci_uncache(bestmci, true);
173*7c478bd9Sstevel@tonic-gate 			continue;
174*7c478bd9Sstevel@tonic-gate 		}
175*7c478bd9Sstevel@tonic-gate 		if (*bestmci == NULL)
176*7c478bd9Sstevel@tonic-gate 			continue;
177*7c478bd9Sstevel@tonic-gate 		if (mci->mci_lastuse < (*bestmci)->mci_lastuse)
178*7c478bd9Sstevel@tonic-gate 			bestmci = &MciCache[i];
179*7c478bd9Sstevel@tonic-gate 	}
180*7c478bd9Sstevel@tonic-gate 	return bestmci;
181*7c478bd9Sstevel@tonic-gate }
182*7c478bd9Sstevel@tonic-gate /*
183*7c478bd9Sstevel@tonic-gate **  MCI_UNCACHE -- remove a connection from a slot.
184*7c478bd9Sstevel@tonic-gate **
185*7c478bd9Sstevel@tonic-gate **	May close a connection.
186*7c478bd9Sstevel@tonic-gate **
187*7c478bd9Sstevel@tonic-gate **	Parameters:
188*7c478bd9Sstevel@tonic-gate **		mcislot -- the slot to empty.
189*7c478bd9Sstevel@tonic-gate **		doquit -- if true, send QUIT protocol on this connection.
190*7c478bd9Sstevel@tonic-gate **			  if false, we are assumed to be in a forked child;
191*7c478bd9Sstevel@tonic-gate **				all we want to do is close the file(s).
192*7c478bd9Sstevel@tonic-gate **
193*7c478bd9Sstevel@tonic-gate **	Returns:
194*7c478bd9Sstevel@tonic-gate **		none.
195*7c478bd9Sstevel@tonic-gate */
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate static void
198*7c478bd9Sstevel@tonic-gate mci_uncache(mcislot, doquit)
199*7c478bd9Sstevel@tonic-gate 	register MCI **mcislot;
200*7c478bd9Sstevel@tonic-gate 	bool doquit;
201*7c478bd9Sstevel@tonic-gate {
202*7c478bd9Sstevel@tonic-gate 	register MCI *mci;
203*7c478bd9Sstevel@tonic-gate 	extern ENVELOPE BlankEnvelope;
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 	mci = *mcislot;
206*7c478bd9Sstevel@tonic-gate 	if (mci == NULL)
207*7c478bd9Sstevel@tonic-gate 		return;
208*7c478bd9Sstevel@tonic-gate 	*mcislot = NULL;
209*7c478bd9Sstevel@tonic-gate 	if (mci->mci_host == NULL)
210*7c478bd9Sstevel@tonic-gate 		return;
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	mci_unlock_host(mci);
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 	if (tTd(42, 5))
215*7c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_uncache: uncaching %p (%s) from slot %d (%d)\n",
216*7c478bd9Sstevel@tonic-gate 			   mci, mci->mci_host, (int) (mcislot - MciCache),
217*7c478bd9Sstevel@tonic-gate 			   doquit);
218*7c478bd9Sstevel@tonic-gate 	if (tTd(91, 100))
219*7c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_DEBUG, CurEnv->e_id,
220*7c478bd9Sstevel@tonic-gate 			  "mci_uncache: uncaching %lx (%.100s) from slot %d (%d)",
221*7c478bd9Sstevel@tonic-gate 			  (unsigned long) mci, mci->mci_host,
222*7c478bd9Sstevel@tonic-gate 			  (int) (mcislot - MciCache), doquit);
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	mci->mci_deliveries = 0;
225*7c478bd9Sstevel@tonic-gate 	if (doquit)
226*7c478bd9Sstevel@tonic-gate 	{
227*7c478bd9Sstevel@tonic-gate 		message("Closing connection to %s", mci->mci_host);
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 		mci->mci_flags &= ~MCIF_CACHED;
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 		/* only uses the envelope to flush the transcript file */
232*7c478bd9Sstevel@tonic-gate 		if (mci->mci_state != MCIS_CLOSED)
233*7c478bd9Sstevel@tonic-gate 			smtpquit(mci->mci_mailer, mci, &BlankEnvelope);
234*7c478bd9Sstevel@tonic-gate #if XLA
235*7c478bd9Sstevel@tonic-gate 		xla_host_end(mci->mci_host);
236*7c478bd9Sstevel@tonic-gate #endif /* XLA */
237*7c478bd9Sstevel@tonic-gate 	}
238*7c478bd9Sstevel@tonic-gate 	else
239*7c478bd9Sstevel@tonic-gate 	{
240*7c478bd9Sstevel@tonic-gate 		if (mci->mci_in != NULL)
241*7c478bd9Sstevel@tonic-gate 			(void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT);
242*7c478bd9Sstevel@tonic-gate 		if (mci->mci_out != NULL)
243*7c478bd9Sstevel@tonic-gate 			(void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
244*7c478bd9Sstevel@tonic-gate 		mci->mci_in = mci->mci_out = NULL;
245*7c478bd9Sstevel@tonic-gate 		mci->mci_state = MCIS_CLOSED;
246*7c478bd9Sstevel@tonic-gate 		mci->mci_exitstat = EX_OK;
247*7c478bd9Sstevel@tonic-gate 		mci->mci_errno = 0;
248*7c478bd9Sstevel@tonic-gate 		mci->mci_flags = 0;
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 		mci->mci_retryrcpt = false;
251*7c478bd9Sstevel@tonic-gate 		mci->mci_tolist = NULL;
252*7c478bd9Sstevel@tonic-gate #if PIPELINING
253*7c478bd9Sstevel@tonic-gate 		mci->mci_okrcpts = 0;
254*7c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
255*7c478bd9Sstevel@tonic-gate 	}
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	SM_FREE_CLR(mci->mci_status);
258*7c478bd9Sstevel@tonic-gate 	SM_FREE_CLR(mci->mci_rstatus);
259*7c478bd9Sstevel@tonic-gate 	SM_FREE_CLR(mci->mci_heloname);
260*7c478bd9Sstevel@tonic-gate 	if (mci->mci_rpool != NULL)
261*7c478bd9Sstevel@tonic-gate 	{
262*7c478bd9Sstevel@tonic-gate 		sm_rpool_free(mci->mci_rpool);
263*7c478bd9Sstevel@tonic-gate 		mci->mci_macro.mac_rpool = NULL;
264*7c478bd9Sstevel@tonic-gate 		mci->mci_rpool = NULL;
265*7c478bd9Sstevel@tonic-gate 	}
266*7c478bd9Sstevel@tonic-gate }
267*7c478bd9Sstevel@tonic-gate /*
268*7c478bd9Sstevel@tonic-gate **  MCI_FLUSH -- flush the entire cache
269*7c478bd9Sstevel@tonic-gate **
270*7c478bd9Sstevel@tonic-gate **	Parameters:
271*7c478bd9Sstevel@tonic-gate **		doquit -- if true, send QUIT protocol.
272*7c478bd9Sstevel@tonic-gate **			  if false, just close the connection.
273*7c478bd9Sstevel@tonic-gate **		allbut -- but leave this one open.
274*7c478bd9Sstevel@tonic-gate **
275*7c478bd9Sstevel@tonic-gate **	Returns:
276*7c478bd9Sstevel@tonic-gate **		none.
277*7c478bd9Sstevel@tonic-gate */
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate void
280*7c478bd9Sstevel@tonic-gate mci_flush(doquit, allbut)
281*7c478bd9Sstevel@tonic-gate 	bool doquit;
282*7c478bd9Sstevel@tonic-gate 	MCI *allbut;
283*7c478bd9Sstevel@tonic-gate {
284*7c478bd9Sstevel@tonic-gate 	register int i;
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	if (MciCache == NULL)
287*7c478bd9Sstevel@tonic-gate 		return;
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MaxMciCache; i++)
290*7c478bd9Sstevel@tonic-gate 	{
291*7c478bd9Sstevel@tonic-gate 		if (allbut != MciCache[i])
292*7c478bd9Sstevel@tonic-gate 			mci_uncache(&MciCache[i], doquit);
293*7c478bd9Sstevel@tonic-gate 	}
294*7c478bd9Sstevel@tonic-gate }
295*7c478bd9Sstevel@tonic-gate /*
296*7c478bd9Sstevel@tonic-gate **  MCI_GET -- get information about a particular host
297*7c478bd9Sstevel@tonic-gate **
298*7c478bd9Sstevel@tonic-gate **	Parameters:
299*7c478bd9Sstevel@tonic-gate **		host -- host to look for.
300*7c478bd9Sstevel@tonic-gate **		m -- mailer.
301*7c478bd9Sstevel@tonic-gate **
302*7c478bd9Sstevel@tonic-gate **	Returns:
303*7c478bd9Sstevel@tonic-gate **		mci for this host (might be new).
304*7c478bd9Sstevel@tonic-gate */
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate MCI *
307*7c478bd9Sstevel@tonic-gate mci_get(host, m)
308*7c478bd9Sstevel@tonic-gate 	char *host;
309*7c478bd9Sstevel@tonic-gate 	MAILER *m;
310*7c478bd9Sstevel@tonic-gate {
311*7c478bd9Sstevel@tonic-gate 	register MCI *mci;
312*7c478bd9Sstevel@tonic-gate 	register STAB *s;
313*7c478bd9Sstevel@tonic-gate 	extern SOCKADDR CurHostAddr;
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	/* clear CurHostAddr so we don't get a bogus address with this name */
316*7c478bd9Sstevel@tonic-gate 	memset(&CurHostAddr, '\0', sizeof CurHostAddr);
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	/* clear out any expired connections */
319*7c478bd9Sstevel@tonic-gate 	(void) mci_scan(NULL);
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	if (m->m_mno < 0)
322*7c478bd9Sstevel@tonic-gate 		syserr("!negative mno %d (%s)", m->m_mno, m->m_name);
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 	s = stab(host, ST_MCI + m->m_mno, ST_ENTER);
325*7c478bd9Sstevel@tonic-gate 	mci = &s->s_mci;
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	/* initialize per-message data */
328*7c478bd9Sstevel@tonic-gate 	mci->mci_retryrcpt = false;
329*7c478bd9Sstevel@tonic-gate 	mci->mci_tolist = NULL;
330*7c478bd9Sstevel@tonic-gate #if PIPELINING
331*7c478bd9Sstevel@tonic-gate 	mci->mci_okrcpts = 0;
332*7c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	if (mci->mci_rpool == NULL)
335*7c478bd9Sstevel@tonic-gate 		mci->mci_rpool = sm_rpool_new_x(NULL);
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate 	if (mci->mci_macro.mac_rpool == NULL)
338*7c478bd9Sstevel@tonic-gate 		mci->mci_macro.mac_rpool = mci->mci_rpool;
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 	/*
341*7c478bd9Sstevel@tonic-gate 	**  We don't need to load the persistent data if we have data
342*7c478bd9Sstevel@tonic-gate 	**  already loaded in the cache.
343*7c478bd9Sstevel@tonic-gate 	*/
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	if (mci->mci_host == NULL &&
346*7c478bd9Sstevel@tonic-gate 	    (mci->mci_host = s->s_name) != NULL &&
347*7c478bd9Sstevel@tonic-gate 	    !mci_load_persistent(mci))
348*7c478bd9Sstevel@tonic-gate 	{
349*7c478bd9Sstevel@tonic-gate 		if (tTd(42, 2))
350*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_get(%s %s): lock failed\n",
351*7c478bd9Sstevel@tonic-gate 				host, m->m_name);
352*7c478bd9Sstevel@tonic-gate 		mci->mci_exitstat = EX_TEMPFAIL;
353*7c478bd9Sstevel@tonic-gate 		mci->mci_state = MCIS_CLOSED;
354*7c478bd9Sstevel@tonic-gate 		mci->mci_statfile = NULL;
355*7c478bd9Sstevel@tonic-gate 		return mci;
356*7c478bd9Sstevel@tonic-gate 	}
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 	if (tTd(42, 2))
359*7c478bd9Sstevel@tonic-gate 	{
360*7c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_get(%s %s): mci_state=%d, _flags=%lx, _exitstat=%d, _errno=%d\n",
361*7c478bd9Sstevel@tonic-gate 			host, m->m_name, mci->mci_state, mci->mci_flags,
362*7c478bd9Sstevel@tonic-gate 			mci->mci_exitstat, mci->mci_errno);
363*7c478bd9Sstevel@tonic-gate 	}
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	if (mci->mci_state == MCIS_OPEN)
366*7c478bd9Sstevel@tonic-gate 	{
367*7c478bd9Sstevel@tonic-gate 		/* poke the connection to see if it's still alive */
368*7c478bd9Sstevel@tonic-gate 		(void) smtpprobe(mci);
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 		/* reset the stored state in the event of a timeout */
371*7c478bd9Sstevel@tonic-gate 		if (mci->mci_state != MCIS_OPEN)
372*7c478bd9Sstevel@tonic-gate 		{
373*7c478bd9Sstevel@tonic-gate 			mci->mci_errno = 0;
374*7c478bd9Sstevel@tonic-gate 			mci->mci_exitstat = EX_OK;
375*7c478bd9Sstevel@tonic-gate 			mci->mci_state = MCIS_CLOSED;
376*7c478bd9Sstevel@tonic-gate 		}
377*7c478bd9Sstevel@tonic-gate 		else
378*7c478bd9Sstevel@tonic-gate 		{
379*7c478bd9Sstevel@tonic-gate 			/* get peer host address */
380*7c478bd9Sstevel@tonic-gate 			/* (this should really be in the mci struct) */
381*7c478bd9Sstevel@tonic-gate 			SOCKADDR_LEN_T socklen = sizeof CurHostAddr;
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 			(void) getpeername(sm_io_getinfo(mci->mci_in,
384*7c478bd9Sstevel@tonic-gate 							 SM_IO_WHAT_FD, NULL),
385*7c478bd9Sstevel@tonic-gate 				(struct sockaddr *) &CurHostAddr, &socklen);
386*7c478bd9Sstevel@tonic-gate 		}
387*7c478bd9Sstevel@tonic-gate 	}
388*7c478bd9Sstevel@tonic-gate 	if (mci->mci_state == MCIS_CLOSED)
389*7c478bd9Sstevel@tonic-gate 	{
390*7c478bd9Sstevel@tonic-gate 		time_t now = curtime();
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 		/* if this info is stale, ignore it */
393*7c478bd9Sstevel@tonic-gate 		if (mci->mci_lastuse + MciInfoTimeout <= now)
394*7c478bd9Sstevel@tonic-gate 		{
395*7c478bd9Sstevel@tonic-gate 			mci->mci_lastuse = now;
396*7c478bd9Sstevel@tonic-gate 			mci->mci_errno = 0;
397*7c478bd9Sstevel@tonic-gate 			mci->mci_exitstat = EX_OK;
398*7c478bd9Sstevel@tonic-gate 		}
399*7c478bd9Sstevel@tonic-gate 	}
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 	return mci;
402*7c478bd9Sstevel@tonic-gate }
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate /*
405*7c478bd9Sstevel@tonic-gate **  MCI_CLOSE -- (forcefully) close files used for a connection.
406*7c478bd9Sstevel@tonic-gate **	Note: this is a last resort, usually smtpquit() or endmailer()
407*7c478bd9Sstevel@tonic-gate **		should be used to close a connection.
408*7c478bd9Sstevel@tonic-gate **
409*7c478bd9Sstevel@tonic-gate **	Parameters:
410*7c478bd9Sstevel@tonic-gate **		mci -- the connection to close.
411*7c478bd9Sstevel@tonic-gate **		where -- where has this been called?
412*7c478bd9Sstevel@tonic-gate **
413*7c478bd9Sstevel@tonic-gate **	Returns:
414*7c478bd9Sstevel@tonic-gate **		none.
415*7c478bd9Sstevel@tonic-gate */
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate void
418*7c478bd9Sstevel@tonic-gate mci_close(mci, where)
419*7c478bd9Sstevel@tonic-gate 	MCI *mci;
420*7c478bd9Sstevel@tonic-gate 	char *where;
421*7c478bd9Sstevel@tonic-gate {
422*7c478bd9Sstevel@tonic-gate 	bool dumped;
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	if (mci == NULL)
425*7c478bd9Sstevel@tonic-gate 		return;
426*7c478bd9Sstevel@tonic-gate 	dumped = false;
427*7c478bd9Sstevel@tonic-gate 	if (mci->mci_out != NULL)
428*7c478bd9Sstevel@tonic-gate 	{
429*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
430*7c478bd9Sstevel@tonic-gate 		{
431*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_close: mci_out!=NULL, where=%s\n",
432*7c478bd9Sstevel@tonic-gate 				where);
433*7c478bd9Sstevel@tonic-gate 			mci_dump(sm_debug_file(), mci, false);
434*7c478bd9Sstevel@tonic-gate 			dumped = true;
435*7c478bd9Sstevel@tonic-gate 		}
436*7c478bd9Sstevel@tonic-gate 		(void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
437*7c478bd9Sstevel@tonic-gate 		mci->mci_out = NULL;
438*7c478bd9Sstevel@tonic-gate 	}
439*7c478bd9Sstevel@tonic-gate 	if (mci->mci_in != NULL)
440*7c478bd9Sstevel@tonic-gate 	{
441*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
442*7c478bd9Sstevel@tonic-gate 		{
443*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_close: mci_in!=NULL, where=%s\n",
444*7c478bd9Sstevel@tonic-gate 				where);
445*7c478bd9Sstevel@tonic-gate 			if (!dumped)
446*7c478bd9Sstevel@tonic-gate 				mci_dump(sm_debug_file(), mci, false);
447*7c478bd9Sstevel@tonic-gate 		}
448*7c478bd9Sstevel@tonic-gate 		(void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT);
449*7c478bd9Sstevel@tonic-gate 		mci->mci_in = NULL;
450*7c478bd9Sstevel@tonic-gate 	}
451*7c478bd9Sstevel@tonic-gate 	mci->mci_state = MCIS_CLOSED;
452*7c478bd9Sstevel@tonic-gate }
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate /*
455*7c478bd9Sstevel@tonic-gate **  MCI_NEW -- allocate new MCI structure
456*7c478bd9Sstevel@tonic-gate **
457*7c478bd9Sstevel@tonic-gate **	Parameters:
458*7c478bd9Sstevel@tonic-gate **		rpool -- if non-NULL: allocate from that rpool.
459*7c478bd9Sstevel@tonic-gate **
460*7c478bd9Sstevel@tonic-gate **	Returns:
461*7c478bd9Sstevel@tonic-gate **		mci (new).
462*7c478bd9Sstevel@tonic-gate */
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate MCI *
465*7c478bd9Sstevel@tonic-gate mci_new(rpool)
466*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
467*7c478bd9Sstevel@tonic-gate {
468*7c478bd9Sstevel@tonic-gate 	register MCI *mci;
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	if (rpool == NULL)
471*7c478bd9Sstevel@tonic-gate 		mci = (MCI *) sm_malloc_x(sizeof *mci);
472*7c478bd9Sstevel@tonic-gate 	else
473*7c478bd9Sstevel@tonic-gate 		mci = (MCI *) sm_rpool_malloc_x(rpool, sizeof *mci);
474*7c478bd9Sstevel@tonic-gate 	memset((char *) mci, '\0', sizeof *mci);
475*7c478bd9Sstevel@tonic-gate 	mci->mci_rpool = sm_rpool_new_x(NULL);
476*7c478bd9Sstevel@tonic-gate 	mci->mci_macro.mac_rpool = mci->mci_rpool;
477*7c478bd9Sstevel@tonic-gate 	return mci;
478*7c478bd9Sstevel@tonic-gate }
479*7c478bd9Sstevel@tonic-gate /*
480*7c478bd9Sstevel@tonic-gate **  MCI_MATCH -- check connection cache for a particular host
481*7c478bd9Sstevel@tonic-gate **
482*7c478bd9Sstevel@tonic-gate **	Parameters:
483*7c478bd9Sstevel@tonic-gate **		host -- host to look for.
484*7c478bd9Sstevel@tonic-gate **		m -- mailer.
485*7c478bd9Sstevel@tonic-gate **
486*7c478bd9Sstevel@tonic-gate **	Returns:
487*7c478bd9Sstevel@tonic-gate **		true iff open connection exists.
488*7c478bd9Sstevel@tonic-gate */
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate bool
491*7c478bd9Sstevel@tonic-gate mci_match(host, m)
492*7c478bd9Sstevel@tonic-gate 	char *host;
493*7c478bd9Sstevel@tonic-gate 	MAILER *m;
494*7c478bd9Sstevel@tonic-gate {
495*7c478bd9Sstevel@tonic-gate 	register MCI *mci;
496*7c478bd9Sstevel@tonic-gate 	register STAB *s;
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 	if (m->m_mno < 0 || m->m_mno > MAXMAILERS)
499*7c478bd9Sstevel@tonic-gate 		return false;
500*7c478bd9Sstevel@tonic-gate 	s = stab(host, ST_MCI + m->m_mno, ST_FIND);
501*7c478bd9Sstevel@tonic-gate 	if (s == NULL)
502*7c478bd9Sstevel@tonic-gate 		return false;
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	mci = &s->s_mci;
505*7c478bd9Sstevel@tonic-gate 	return mci->mci_state == MCIS_OPEN;
506*7c478bd9Sstevel@tonic-gate }
507*7c478bd9Sstevel@tonic-gate /*
508*7c478bd9Sstevel@tonic-gate **  MCI_SETSTAT -- set status codes in MCI structure.
509*7c478bd9Sstevel@tonic-gate **
510*7c478bd9Sstevel@tonic-gate **	Parameters:
511*7c478bd9Sstevel@tonic-gate **		mci -- the MCI structure to set.
512*7c478bd9Sstevel@tonic-gate **		xstat -- the exit status code.
513*7c478bd9Sstevel@tonic-gate **		dstat -- the DSN status code.
514*7c478bd9Sstevel@tonic-gate **		rstat -- the SMTP status code.
515*7c478bd9Sstevel@tonic-gate **
516*7c478bd9Sstevel@tonic-gate **	Returns:
517*7c478bd9Sstevel@tonic-gate **		none.
518*7c478bd9Sstevel@tonic-gate */
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate void
521*7c478bd9Sstevel@tonic-gate mci_setstat(mci, xstat, dstat, rstat)
522*7c478bd9Sstevel@tonic-gate 	MCI *mci;
523*7c478bd9Sstevel@tonic-gate 	int xstat;
524*7c478bd9Sstevel@tonic-gate 	char *dstat;
525*7c478bd9Sstevel@tonic-gate 	char *rstat;
526*7c478bd9Sstevel@tonic-gate {
527*7c478bd9Sstevel@tonic-gate 	/* protocol errors should never be interpreted as sticky */
528*7c478bd9Sstevel@tonic-gate 	if (xstat != EX_NOTSTICKY && xstat != EX_PROTOCOL)
529*7c478bd9Sstevel@tonic-gate 		mci->mci_exitstat = xstat;
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 	SM_FREE_CLR(mci->mci_status);
532*7c478bd9Sstevel@tonic-gate 	if (dstat != NULL)
533*7c478bd9Sstevel@tonic-gate 		mci->mci_status = sm_strdup_x(dstat);
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	SM_FREE_CLR(mci->mci_rstatus);
536*7c478bd9Sstevel@tonic-gate 	if (rstat != NULL)
537*7c478bd9Sstevel@tonic-gate 		mci->mci_rstatus = sm_strdup_x(rstat);
538*7c478bd9Sstevel@tonic-gate }
539*7c478bd9Sstevel@tonic-gate /*
540*7c478bd9Sstevel@tonic-gate **  MCI_DUMP -- dump the contents of an MCI structure.
541*7c478bd9Sstevel@tonic-gate **
542*7c478bd9Sstevel@tonic-gate **	Parameters:
543*7c478bd9Sstevel@tonic-gate **		fp -- output file pointer
544*7c478bd9Sstevel@tonic-gate **		mci -- the MCI structure to dump.
545*7c478bd9Sstevel@tonic-gate **
546*7c478bd9Sstevel@tonic-gate **	Returns:
547*7c478bd9Sstevel@tonic-gate **		none.
548*7c478bd9Sstevel@tonic-gate **
549*7c478bd9Sstevel@tonic-gate **	Side Effects:
550*7c478bd9Sstevel@tonic-gate **		none.
551*7c478bd9Sstevel@tonic-gate */
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate struct mcifbits
554*7c478bd9Sstevel@tonic-gate {
555*7c478bd9Sstevel@tonic-gate 	int	mcif_bit;	/* flag bit */
556*7c478bd9Sstevel@tonic-gate 	char	*mcif_name;	/* flag name */
557*7c478bd9Sstevel@tonic-gate };
558*7c478bd9Sstevel@tonic-gate static struct mcifbits	MciFlags[] =
559*7c478bd9Sstevel@tonic-gate {
560*7c478bd9Sstevel@tonic-gate 	{ MCIF_VALID,		"VALID"		},
561*7c478bd9Sstevel@tonic-gate 	{ MCIF_CACHED,		"CACHED"	},
562*7c478bd9Sstevel@tonic-gate 	{ MCIF_ESMTP,		"ESMTP"		},
563*7c478bd9Sstevel@tonic-gate 	{ MCIF_EXPN,		"EXPN"		},
564*7c478bd9Sstevel@tonic-gate 	{ MCIF_SIZE,		"SIZE"		},
565*7c478bd9Sstevel@tonic-gate 	{ MCIF_8BITMIME,	"8BITMIME"	},
566*7c478bd9Sstevel@tonic-gate 	{ MCIF_7BIT,		"7BIT"		},
567*7c478bd9Sstevel@tonic-gate 	{ MCIF_INHEADER,	"INHEADER"	},
568*7c478bd9Sstevel@tonic-gate 	{ MCIF_CVT8TO7,		"CVT8TO7"	},
569*7c478bd9Sstevel@tonic-gate 	{ MCIF_DSN,		"DSN"		},
570*7c478bd9Sstevel@tonic-gate 	{ MCIF_8BITOK,		"8BITOK"	},
571*7c478bd9Sstevel@tonic-gate 	{ MCIF_CVT7TO8,		"CVT7TO8"	},
572*7c478bd9Sstevel@tonic-gate 	{ MCIF_INMIME,		"INMIME"	},
573*7c478bd9Sstevel@tonic-gate 	{ MCIF_AUTH,		"AUTH"		},
574*7c478bd9Sstevel@tonic-gate 	{ MCIF_AUTHACT,		"AUTHACT"	},
575*7c478bd9Sstevel@tonic-gate 	{ MCIF_ENHSTAT,		"ENHSTAT"	},
576*7c478bd9Sstevel@tonic-gate 	{ MCIF_PIPELINED,	"PIPELINED"	},
577*7c478bd9Sstevel@tonic-gate #if STARTTLS
578*7c478bd9Sstevel@tonic-gate 	{ MCIF_TLS,		"TLS"		},
579*7c478bd9Sstevel@tonic-gate 	{ MCIF_TLSACT,		"TLSACT"	},
580*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */
581*7c478bd9Sstevel@tonic-gate 	{ MCIF_DLVR_BY,		"DLVR_BY"	},
582*7c478bd9Sstevel@tonic-gate 	{ 0,			NULL		}
583*7c478bd9Sstevel@tonic-gate };
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate void
586*7c478bd9Sstevel@tonic-gate mci_dump(fp, mci, logit)
587*7c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
588*7c478bd9Sstevel@tonic-gate 	register MCI *mci;
589*7c478bd9Sstevel@tonic-gate 	bool logit;
590*7c478bd9Sstevel@tonic-gate {
591*7c478bd9Sstevel@tonic-gate 	register char *p;
592*7c478bd9Sstevel@tonic-gate 	char *sep;
593*7c478bd9Sstevel@tonic-gate 	char buf[4000];
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 	sep = logit ? " " : "\n\t";
596*7c478bd9Sstevel@tonic-gate 	p = buf;
597*7c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(p, SPACELEFT(buf, p), "MCI@%p: ", mci);
598*7c478bd9Sstevel@tonic-gate 	p += strlen(p);
599*7c478bd9Sstevel@tonic-gate 	if (mci == NULL)
600*7c478bd9Sstevel@tonic-gate 	{
601*7c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(p, SPACELEFT(buf, p), "NULL");
602*7c478bd9Sstevel@tonic-gate 		goto printit;
603*7c478bd9Sstevel@tonic-gate 	}
604*7c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(p, SPACELEFT(buf, p), "flags=%lx", mci->mci_flags);
605*7c478bd9Sstevel@tonic-gate 	p += strlen(p);
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	/*
608*7c478bd9Sstevel@tonic-gate 	**  The following check is just for paranoia.  It protects the
609*7c478bd9Sstevel@tonic-gate 	**  assignment in the if() clause. If there's not some minimum
610*7c478bd9Sstevel@tonic-gate 	**  amount of space we can stop right now. The check will not
611*7c478bd9Sstevel@tonic-gate 	**  trigger as long as sizeof(buf)=4000.
612*7c478bd9Sstevel@tonic-gate 	*/
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 	if (p >= buf + sizeof(buf) - 4)
615*7c478bd9Sstevel@tonic-gate 		goto printit;
616*7c478bd9Sstevel@tonic-gate 	if (mci->mci_flags != 0)
617*7c478bd9Sstevel@tonic-gate 	{
618*7c478bd9Sstevel@tonic-gate 		struct mcifbits *f;
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 		*p++ = '<';	/* protected above */
621*7c478bd9Sstevel@tonic-gate 		for (f = MciFlags; f->mcif_bit != 0; f++)
622*7c478bd9Sstevel@tonic-gate 		{
623*7c478bd9Sstevel@tonic-gate 			if (!bitset(f->mcif_bit, mci->mci_flags))
624*7c478bd9Sstevel@tonic-gate 				continue;
625*7c478bd9Sstevel@tonic-gate 			(void) sm_strlcpyn(p, SPACELEFT(buf, p), 2,
626*7c478bd9Sstevel@tonic-gate 					   f->mcif_name, ",");
627*7c478bd9Sstevel@tonic-gate 			p += strlen(p);
628*7c478bd9Sstevel@tonic-gate 		}
629*7c478bd9Sstevel@tonic-gate 		p[-1] = '>';
630*7c478bd9Sstevel@tonic-gate 	}
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 	/* Note: sm_snprintf() takes care of NULL arguments for %s */
633*7c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(p, SPACELEFT(buf, p),
634*7c478bd9Sstevel@tonic-gate 		",%serrno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s",
635*7c478bd9Sstevel@tonic-gate 		sep, mci->mci_errno, mci->mci_herrno,
636*7c478bd9Sstevel@tonic-gate 		mci->mci_exitstat, mci->mci_state, (int) mci->mci_pid, sep);
637*7c478bd9Sstevel@tonic-gate 	p += strlen(p);
638*7c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(p, SPACELEFT(buf, p),
639*7c478bd9Sstevel@tonic-gate 		"maxsize=%ld, phase=%s, mailer=%s,%s",
640*7c478bd9Sstevel@tonic-gate 		mci->mci_maxsize, mci->mci_phase,
641*7c478bd9Sstevel@tonic-gate 		mci->mci_mailer == NULL ? "NULL" : mci->mci_mailer->m_name,
642*7c478bd9Sstevel@tonic-gate 		sep);
643*7c478bd9Sstevel@tonic-gate 	p += strlen(p);
644*7c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(p, SPACELEFT(buf, p),
645*7c478bd9Sstevel@tonic-gate 		"status=%s, rstatus=%s,%s",
646*7c478bd9Sstevel@tonic-gate 		mci->mci_status, mci->mci_rstatus, sep);
647*7c478bd9Sstevel@tonic-gate 	p += strlen(p);
648*7c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(p, SPACELEFT(buf, p),
649*7c478bd9Sstevel@tonic-gate 		"host=%s, lastuse=%s",
650*7c478bd9Sstevel@tonic-gate 		mci->mci_host, ctime(&mci->mci_lastuse));
651*7c478bd9Sstevel@tonic-gate printit:
652*7c478bd9Sstevel@tonic-gate 	if (logit)
653*7c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_DEBUG, CurEnv->e_id, "%.1000s", buf);
654*7c478bd9Sstevel@tonic-gate 	else
655*7c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s\n", buf);
656*7c478bd9Sstevel@tonic-gate }
657*7c478bd9Sstevel@tonic-gate /*
658*7c478bd9Sstevel@tonic-gate **  MCI_DUMP_ALL -- print the entire MCI cache
659*7c478bd9Sstevel@tonic-gate **
660*7c478bd9Sstevel@tonic-gate **	Parameters:
661*7c478bd9Sstevel@tonic-gate **		fp -- output file pointer
662*7c478bd9Sstevel@tonic-gate **		logit -- if set, log the result instead of printing
663*7c478bd9Sstevel@tonic-gate **			to stdout.
664*7c478bd9Sstevel@tonic-gate **
665*7c478bd9Sstevel@tonic-gate **	Returns:
666*7c478bd9Sstevel@tonic-gate **		none.
667*7c478bd9Sstevel@tonic-gate */
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate void
670*7c478bd9Sstevel@tonic-gate mci_dump_all(fp, logit)
671*7c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
672*7c478bd9Sstevel@tonic-gate 	bool logit;
673*7c478bd9Sstevel@tonic-gate {
674*7c478bd9Sstevel@tonic-gate 	register int i;
675*7c478bd9Sstevel@tonic-gate 
676*7c478bd9Sstevel@tonic-gate 	if (MciCache == NULL)
677*7c478bd9Sstevel@tonic-gate 		return;
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MaxMciCache; i++)
680*7c478bd9Sstevel@tonic-gate 		mci_dump(fp, MciCache[i], logit);
681*7c478bd9Sstevel@tonic-gate }
682*7c478bd9Sstevel@tonic-gate /*
683*7c478bd9Sstevel@tonic-gate **  MCI_LOCK_HOST -- Lock host while sending.
684*7c478bd9Sstevel@tonic-gate **
685*7c478bd9Sstevel@tonic-gate **	If we are contacting a host, we'll need to
686*7c478bd9Sstevel@tonic-gate **	update the status information in the host status
687*7c478bd9Sstevel@tonic-gate **	file, and if we want to do that, we ought to have
688*7c478bd9Sstevel@tonic-gate **	locked it. This has the (according to some)
689*7c478bd9Sstevel@tonic-gate **	desirable effect of serializing connectivity with
690*7c478bd9Sstevel@tonic-gate **	remote hosts -- i.e.: one connection to a given
691*7c478bd9Sstevel@tonic-gate **	host at a time.
692*7c478bd9Sstevel@tonic-gate **
693*7c478bd9Sstevel@tonic-gate **	Parameters:
694*7c478bd9Sstevel@tonic-gate **		mci -- containing the host we want to lock.
695*7c478bd9Sstevel@tonic-gate **
696*7c478bd9Sstevel@tonic-gate **	Returns:
697*7c478bd9Sstevel@tonic-gate **		EX_OK	    -- got the lock.
698*7c478bd9Sstevel@tonic-gate **		EX_TEMPFAIL -- didn't get the lock.
699*7c478bd9Sstevel@tonic-gate */
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate int
702*7c478bd9Sstevel@tonic-gate mci_lock_host(mci)
703*7c478bd9Sstevel@tonic-gate 	MCI *mci;
704*7c478bd9Sstevel@tonic-gate {
705*7c478bd9Sstevel@tonic-gate 	if (mci == NULL)
706*7c478bd9Sstevel@tonic-gate 	{
707*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
708*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_lock_host: NULL mci\n");
709*7c478bd9Sstevel@tonic-gate 		return EX_OK;
710*7c478bd9Sstevel@tonic-gate 	}
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate 	if (!SingleThreadDelivery)
713*7c478bd9Sstevel@tonic-gate 		return EX_OK;
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 	return mci_lock_host_statfile(mci);
716*7c478bd9Sstevel@tonic-gate }
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate static int
719*7c478bd9Sstevel@tonic-gate mci_lock_host_statfile(mci)
720*7c478bd9Sstevel@tonic-gate 	MCI *mci;
721*7c478bd9Sstevel@tonic-gate {
722*7c478bd9Sstevel@tonic-gate 	int save_errno = errno;
723*7c478bd9Sstevel@tonic-gate 	int retVal = EX_OK;
724*7c478bd9Sstevel@tonic-gate 	char fname[MAXPATHLEN];
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 	if (HostStatDir == NULL || mci->mci_host == NULL)
727*7c478bd9Sstevel@tonic-gate 		return EX_OK;
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 	if (tTd(56, 2))
730*7c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_lock_host: attempting to lock %s\n",
731*7c478bd9Sstevel@tonic-gate 			   mci->mci_host);
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 	if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname,
734*7c478bd9Sstevel@tonic-gate 					 true) < 0)
735*7c478bd9Sstevel@tonic-gate 	{
736*7c478bd9Sstevel@tonic-gate 		/* of course this should never happen */
737*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 2))
738*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_lock_host: Failed to generate host path for %s\n",
739*7c478bd9Sstevel@tonic-gate 				   mci->mci_host);
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 		retVal = EX_TEMPFAIL;
742*7c478bd9Sstevel@tonic-gate 		goto cleanup;
743*7c478bd9Sstevel@tonic-gate 	}
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate 	mci->mci_statfile = safefopen(fname, O_RDWR, FileMode,
746*7c478bd9Sstevel@tonic-gate 				      SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH|SFF_CREAT);
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 	if (mci->mci_statfile == NULL)
749*7c478bd9Sstevel@tonic-gate 	{
750*7c478bd9Sstevel@tonic-gate 		syserr("mci_lock_host: cannot create host lock file %s", fname);
751*7c478bd9Sstevel@tonic-gate 		goto cleanup;
752*7c478bd9Sstevel@tonic-gate 	}
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 	if (!lockfile(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL),
755*7c478bd9Sstevel@tonic-gate 		      fname, "", LOCK_EX|LOCK_NB))
756*7c478bd9Sstevel@tonic-gate 	{
757*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 2))
758*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_lock_host: couldn't get lock on %s\n",
759*7c478bd9Sstevel@tonic-gate 				fname);
760*7c478bd9Sstevel@tonic-gate 		(void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT);
761*7c478bd9Sstevel@tonic-gate 		mci->mci_statfile = NULL;
762*7c478bd9Sstevel@tonic-gate 		retVal = EX_TEMPFAIL;
763*7c478bd9Sstevel@tonic-gate 		goto cleanup;
764*7c478bd9Sstevel@tonic-gate 	}
765*7c478bd9Sstevel@tonic-gate 
766*7c478bd9Sstevel@tonic-gate 	if (tTd(56, 12) && mci->mci_statfile != NULL)
767*7c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_lock_host: Sanity check -- lock is good\n");
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate cleanup:
770*7c478bd9Sstevel@tonic-gate 	errno = save_errno;
771*7c478bd9Sstevel@tonic-gate 	return retVal;
772*7c478bd9Sstevel@tonic-gate }
773*7c478bd9Sstevel@tonic-gate /*
774*7c478bd9Sstevel@tonic-gate **  MCI_UNLOCK_HOST -- unlock host
775*7c478bd9Sstevel@tonic-gate **
776*7c478bd9Sstevel@tonic-gate **	Clean up the lock on a host, close the file, let
777*7c478bd9Sstevel@tonic-gate **	someone else use it.
778*7c478bd9Sstevel@tonic-gate **
779*7c478bd9Sstevel@tonic-gate **	Parameters:
780*7c478bd9Sstevel@tonic-gate **		mci -- us.
781*7c478bd9Sstevel@tonic-gate **
782*7c478bd9Sstevel@tonic-gate **	Returns:
783*7c478bd9Sstevel@tonic-gate **		nothing.
784*7c478bd9Sstevel@tonic-gate */
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate void
787*7c478bd9Sstevel@tonic-gate mci_unlock_host(mci)
788*7c478bd9Sstevel@tonic-gate 	MCI *mci;
789*7c478bd9Sstevel@tonic-gate {
790*7c478bd9Sstevel@tonic-gate 	int save_errno = errno;
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	if (mci == NULL)
793*7c478bd9Sstevel@tonic-gate 	{
794*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
795*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_unlock_host: NULL mci\n");
796*7c478bd9Sstevel@tonic-gate 		return;
797*7c478bd9Sstevel@tonic-gate 	}
798*7c478bd9Sstevel@tonic-gate 
799*7c478bd9Sstevel@tonic-gate 	if (HostStatDir == NULL || mci->mci_host == NULL)
800*7c478bd9Sstevel@tonic-gate 		return;
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	if (!SingleThreadDelivery && mci_lock_host_statfile(mci) == EX_TEMPFAIL)
803*7c478bd9Sstevel@tonic-gate 	{
804*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
805*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_unlock_host: stat file already locked\n");
806*7c478bd9Sstevel@tonic-gate 	}
807*7c478bd9Sstevel@tonic-gate 	else
808*7c478bd9Sstevel@tonic-gate 	{
809*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 2))
810*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_unlock_host: store prior to unlock\n");
811*7c478bd9Sstevel@tonic-gate 		mci_store_persistent(mci);
812*7c478bd9Sstevel@tonic-gate 	}
813*7c478bd9Sstevel@tonic-gate 
814*7c478bd9Sstevel@tonic-gate 	if (mci->mci_statfile != NULL)
815*7c478bd9Sstevel@tonic-gate 	{
816*7c478bd9Sstevel@tonic-gate 		(void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT);
817*7c478bd9Sstevel@tonic-gate 		mci->mci_statfile = NULL;
818*7c478bd9Sstevel@tonic-gate 	}
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 	errno = save_errno;
821*7c478bd9Sstevel@tonic-gate }
822*7c478bd9Sstevel@tonic-gate /*
823*7c478bd9Sstevel@tonic-gate **  MCI_LOAD_PERSISTENT -- load persistent host info
824*7c478bd9Sstevel@tonic-gate **
825*7c478bd9Sstevel@tonic-gate **	Load information about host that is kept
826*7c478bd9Sstevel@tonic-gate **	in common for all running sendmails.
827*7c478bd9Sstevel@tonic-gate **
828*7c478bd9Sstevel@tonic-gate **	Parameters:
829*7c478bd9Sstevel@tonic-gate **		mci -- the host/connection to load persistent info for.
830*7c478bd9Sstevel@tonic-gate **
831*7c478bd9Sstevel@tonic-gate **	Returns:
832*7c478bd9Sstevel@tonic-gate **		true -- lock was successful
833*7c478bd9Sstevel@tonic-gate **		false -- lock failed
834*7c478bd9Sstevel@tonic-gate */
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate static bool
837*7c478bd9Sstevel@tonic-gate mci_load_persistent(mci)
838*7c478bd9Sstevel@tonic-gate 	MCI *mci;
839*7c478bd9Sstevel@tonic-gate {
840*7c478bd9Sstevel@tonic-gate 	int save_errno = errno;
841*7c478bd9Sstevel@tonic-gate 	bool locked = true;
842*7c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
843*7c478bd9Sstevel@tonic-gate 	char fname[MAXPATHLEN];
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 	if (mci == NULL)
846*7c478bd9Sstevel@tonic-gate 	{
847*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
848*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_load_persistent: NULL mci\n");
849*7c478bd9Sstevel@tonic-gate 		return true;
850*7c478bd9Sstevel@tonic-gate 	}
851*7c478bd9Sstevel@tonic-gate 
852*7c478bd9Sstevel@tonic-gate 	if (IgnoreHostStatus || HostStatDir == NULL || mci->mci_host == NULL)
853*7c478bd9Sstevel@tonic-gate 		return true;
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 	/* Already have the persistent information in memory */
856*7c478bd9Sstevel@tonic-gate 	if (SingleThreadDelivery && mci->mci_statfile != NULL)
857*7c478bd9Sstevel@tonic-gate 		return true;
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate 	if (tTd(56, 1))
860*7c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_load_persistent: Attempting to load persistent information for %s\n",
861*7c478bd9Sstevel@tonic-gate 			   mci->mci_host);
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 	if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname,
864*7c478bd9Sstevel@tonic-gate 					 false) < 0)
865*7c478bd9Sstevel@tonic-gate 	{
866*7c478bd9Sstevel@tonic-gate 		/* Not much we can do if the file isn't there... */
867*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
868*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_load_persistent: Couldn't generate host path\n");
869*7c478bd9Sstevel@tonic-gate 		goto cleanup;
870*7c478bd9Sstevel@tonic-gate 	}
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate 	fp = safefopen(fname, O_RDONLY, FileMode,
873*7c478bd9Sstevel@tonic-gate 		       SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH);
874*7c478bd9Sstevel@tonic-gate 	if (fp == NULL)
875*7c478bd9Sstevel@tonic-gate 	{
876*7c478bd9Sstevel@tonic-gate 		/* I can't think of any reason this should ever happen */
877*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
878*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_load_persistent: open(%s): %s\n",
879*7c478bd9Sstevel@tonic-gate 				fname, sm_errstring(errno));
880*7c478bd9Sstevel@tonic-gate 		goto cleanup;
881*7c478bd9Sstevel@tonic-gate 	}
882*7c478bd9Sstevel@tonic-gate 
883*7c478bd9Sstevel@tonic-gate 	FileName = fname;
884*7c478bd9Sstevel@tonic-gate 	locked = lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname, "",
885*7c478bd9Sstevel@tonic-gate 			  LOCK_SH|LOCK_NB);
886*7c478bd9Sstevel@tonic-gate 	if (locked)
887*7c478bd9Sstevel@tonic-gate 	{
888*7c478bd9Sstevel@tonic-gate 		(void) mci_read_persistent(fp, mci);
889*7c478bd9Sstevel@tonic-gate 		(void) lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname,
890*7c478bd9Sstevel@tonic-gate 				"", LOCK_UN);
891*7c478bd9Sstevel@tonic-gate 	}
892*7c478bd9Sstevel@tonic-gate 	FileName = NULL;
893*7c478bd9Sstevel@tonic-gate 	(void) sm_io_close(fp, SM_TIME_DEFAULT);
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate cleanup:
896*7c478bd9Sstevel@tonic-gate 	errno = save_errno;
897*7c478bd9Sstevel@tonic-gate 	return locked;
898*7c478bd9Sstevel@tonic-gate }
899*7c478bd9Sstevel@tonic-gate /*
900*7c478bd9Sstevel@tonic-gate **  MCI_READ_PERSISTENT -- read persistent host status file
901*7c478bd9Sstevel@tonic-gate **
902*7c478bd9Sstevel@tonic-gate **	Parameters:
903*7c478bd9Sstevel@tonic-gate **		fp -- the file pointer to read.
904*7c478bd9Sstevel@tonic-gate **		mci -- the pointer to fill in.
905*7c478bd9Sstevel@tonic-gate **
906*7c478bd9Sstevel@tonic-gate **	Returns:
907*7c478bd9Sstevel@tonic-gate **		-1 -- if the file was corrupt.
908*7c478bd9Sstevel@tonic-gate **		0 -- otherwise.
909*7c478bd9Sstevel@tonic-gate **
910*7c478bd9Sstevel@tonic-gate **	Warning:
911*7c478bd9Sstevel@tonic-gate **		This code makes the assumption that this data
912*7c478bd9Sstevel@tonic-gate **		will be read in an atomic fashion, and that the data
913*7c478bd9Sstevel@tonic-gate **		was written in an atomic fashion.  Any other functioning
914*7c478bd9Sstevel@tonic-gate **		may lead to some form of insanity.  This should be
915*7c478bd9Sstevel@tonic-gate **		perfectly safe due to underlying stdio buffering.
916*7c478bd9Sstevel@tonic-gate */
917*7c478bd9Sstevel@tonic-gate 
918*7c478bd9Sstevel@tonic-gate static int
919*7c478bd9Sstevel@tonic-gate mci_read_persistent(fp, mci)
920*7c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
921*7c478bd9Sstevel@tonic-gate 	register MCI *mci;
922*7c478bd9Sstevel@tonic-gate {
923*7c478bd9Sstevel@tonic-gate 	int ver;
924*7c478bd9Sstevel@tonic-gate 	register char *p;
925*7c478bd9Sstevel@tonic-gate 	int saveLineNumber = LineNumber;
926*7c478bd9Sstevel@tonic-gate 	char buf[MAXLINE];
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 	if (fp == NULL)
929*7c478bd9Sstevel@tonic-gate 		syserr("mci_read_persistent: NULL fp");
930*7c478bd9Sstevel@tonic-gate 	if (mci == NULL)
931*7c478bd9Sstevel@tonic-gate 		syserr("mci_read_persistent: NULL mci");
932*7c478bd9Sstevel@tonic-gate 	if (tTd(56, 93))
933*7c478bd9Sstevel@tonic-gate 	{
934*7c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_read_persistent: fp=%lx, mci=",
935*7c478bd9Sstevel@tonic-gate 			   (unsigned long) fp);
936*7c478bd9Sstevel@tonic-gate 	}
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 	SM_FREE_CLR(mci->mci_status);
939*7c478bd9Sstevel@tonic-gate 	SM_FREE_CLR(mci->mci_rstatus);
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate 	sm_io_rewind(fp, SM_TIME_DEFAULT);
942*7c478bd9Sstevel@tonic-gate 	ver = -1;
943*7c478bd9Sstevel@tonic-gate 	LineNumber = 0;
944*7c478bd9Sstevel@tonic-gate 	while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
945*7c478bd9Sstevel@tonic-gate 	{
946*7c478bd9Sstevel@tonic-gate 		LineNumber++;
947*7c478bd9Sstevel@tonic-gate 		p = strchr(buf, '\n');
948*7c478bd9Sstevel@tonic-gate 		if (p != NULL)
949*7c478bd9Sstevel@tonic-gate 			*p = '\0';
950*7c478bd9Sstevel@tonic-gate 		switch (buf[0])
951*7c478bd9Sstevel@tonic-gate 		{
952*7c478bd9Sstevel@tonic-gate 		  case 'V':		/* version stamp */
953*7c478bd9Sstevel@tonic-gate 			ver = atoi(&buf[1]);
954*7c478bd9Sstevel@tonic-gate 			if (ver < 0 || ver > 0)
955*7c478bd9Sstevel@tonic-gate 				syserr("Unknown host status version %d: %d max",
956*7c478bd9Sstevel@tonic-gate 					ver, 0);
957*7c478bd9Sstevel@tonic-gate 			break;
958*7c478bd9Sstevel@tonic-gate 
959*7c478bd9Sstevel@tonic-gate 		  case 'E':		/* UNIX error number */
960*7c478bd9Sstevel@tonic-gate 			mci->mci_errno = atoi(&buf[1]);
961*7c478bd9Sstevel@tonic-gate 			break;
962*7c478bd9Sstevel@tonic-gate 
963*7c478bd9Sstevel@tonic-gate 		  case 'H':		/* DNS error number */
964*7c478bd9Sstevel@tonic-gate 			mci->mci_herrno = atoi(&buf[1]);
965*7c478bd9Sstevel@tonic-gate 			break;
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 		  case 'S':		/* UNIX exit status */
968*7c478bd9Sstevel@tonic-gate 			mci->mci_exitstat = atoi(&buf[1]);
969*7c478bd9Sstevel@tonic-gate 			break;
970*7c478bd9Sstevel@tonic-gate 
971*7c478bd9Sstevel@tonic-gate 		  case 'D':		/* DSN status */
972*7c478bd9Sstevel@tonic-gate 			mci->mci_status = newstr(&buf[1]);
973*7c478bd9Sstevel@tonic-gate 			break;
974*7c478bd9Sstevel@tonic-gate 
975*7c478bd9Sstevel@tonic-gate 		  case 'R':		/* SMTP status */
976*7c478bd9Sstevel@tonic-gate 			mci->mci_rstatus = newstr(&buf[1]);
977*7c478bd9Sstevel@tonic-gate 			break;
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 		  case 'U':		/* last usage time */
980*7c478bd9Sstevel@tonic-gate 			mci->mci_lastuse = atol(&buf[1]);
981*7c478bd9Sstevel@tonic-gate 			break;
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate 		  case '.':		/* end of file */
984*7c478bd9Sstevel@tonic-gate 			if (tTd(56, 93))
985*7c478bd9Sstevel@tonic-gate 				mci_dump(sm_debug_file(), mci, false);
986*7c478bd9Sstevel@tonic-gate 			return 0;
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate 		  default:
989*7c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_CRIT, NOQID,
990*7c478bd9Sstevel@tonic-gate 				  "%s: line %d: Unknown host status line \"%s\"",
991*7c478bd9Sstevel@tonic-gate 				  FileName == NULL ? mci->mci_host : FileName,
992*7c478bd9Sstevel@tonic-gate 				  LineNumber, buf);
993*7c478bd9Sstevel@tonic-gate 			LineNumber = saveLineNumber;
994*7c478bd9Sstevel@tonic-gate 			return -1;
995*7c478bd9Sstevel@tonic-gate 		}
996*7c478bd9Sstevel@tonic-gate 	}
997*7c478bd9Sstevel@tonic-gate 	LineNumber = saveLineNumber;
998*7c478bd9Sstevel@tonic-gate 	if (tTd(56, 93))
999*7c478bd9Sstevel@tonic-gate 		sm_dprintf("incomplete (missing dot for EOF)\n");
1000*7c478bd9Sstevel@tonic-gate 	if (ver < 0)
1001*7c478bd9Sstevel@tonic-gate 		return -1;
1002*7c478bd9Sstevel@tonic-gate 	return 0;
1003*7c478bd9Sstevel@tonic-gate }
1004*7c478bd9Sstevel@tonic-gate /*
1005*7c478bd9Sstevel@tonic-gate **  MCI_STORE_PERSISTENT -- Store persistent MCI information
1006*7c478bd9Sstevel@tonic-gate **
1007*7c478bd9Sstevel@tonic-gate **	Store information about host that is kept
1008*7c478bd9Sstevel@tonic-gate **	in common for all running sendmails.
1009*7c478bd9Sstevel@tonic-gate **
1010*7c478bd9Sstevel@tonic-gate **	Parameters:
1011*7c478bd9Sstevel@tonic-gate **		mci -- the host/connection to store persistent info for.
1012*7c478bd9Sstevel@tonic-gate **
1013*7c478bd9Sstevel@tonic-gate **	Returns:
1014*7c478bd9Sstevel@tonic-gate **		none.
1015*7c478bd9Sstevel@tonic-gate */
1016*7c478bd9Sstevel@tonic-gate 
1017*7c478bd9Sstevel@tonic-gate void
1018*7c478bd9Sstevel@tonic-gate mci_store_persistent(mci)
1019*7c478bd9Sstevel@tonic-gate 	MCI *mci;
1020*7c478bd9Sstevel@tonic-gate {
1021*7c478bd9Sstevel@tonic-gate 	int save_errno = errno;
1022*7c478bd9Sstevel@tonic-gate 
1023*7c478bd9Sstevel@tonic-gate 	if (mci == NULL)
1024*7c478bd9Sstevel@tonic-gate 	{
1025*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
1026*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_store_persistent: NULL mci\n");
1027*7c478bd9Sstevel@tonic-gate 		return;
1028*7c478bd9Sstevel@tonic-gate 	}
1029*7c478bd9Sstevel@tonic-gate 
1030*7c478bd9Sstevel@tonic-gate 	if (HostStatDir == NULL || mci->mci_host == NULL)
1031*7c478bd9Sstevel@tonic-gate 		return;
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate 	if (tTd(56, 1))
1034*7c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_store_persistent: Storing information for %s\n",
1035*7c478bd9Sstevel@tonic-gate 			   mci->mci_host);
1036*7c478bd9Sstevel@tonic-gate 
1037*7c478bd9Sstevel@tonic-gate 	if (mci->mci_statfile == NULL)
1038*7c478bd9Sstevel@tonic-gate 	{
1039*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
1040*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_store_persistent: no statfile\n");
1041*7c478bd9Sstevel@tonic-gate 		return;
1042*7c478bd9Sstevel@tonic-gate 	}
1043*7c478bd9Sstevel@tonic-gate 
1044*7c478bd9Sstevel@tonic-gate 	sm_io_rewind(mci->mci_statfile, SM_TIME_DEFAULT);
1045*7c478bd9Sstevel@tonic-gate #if !NOFTRUNCATE
1046*7c478bd9Sstevel@tonic-gate 	(void) ftruncate(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL),
1047*7c478bd9Sstevel@tonic-gate 			 (off_t) 0);
1048*7c478bd9Sstevel@tonic-gate #endif /* !NOFTRUNCATE */
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate 	(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "V0\n");
1051*7c478bd9Sstevel@tonic-gate 	(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "E%d\n",
1052*7c478bd9Sstevel@tonic-gate 			     mci->mci_errno);
1053*7c478bd9Sstevel@tonic-gate 	(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "H%d\n",
1054*7c478bd9Sstevel@tonic-gate 			     mci->mci_herrno);
1055*7c478bd9Sstevel@tonic-gate 	(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "S%d\n",
1056*7c478bd9Sstevel@tonic-gate 			     mci->mci_exitstat);
1057*7c478bd9Sstevel@tonic-gate 	if (mci->mci_status != NULL)
1058*7c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT,
1059*7c478bd9Sstevel@tonic-gate 				     "D%.80s\n",
1060*7c478bd9Sstevel@tonic-gate 				     denlstring(mci->mci_status, true, false));
1061*7c478bd9Sstevel@tonic-gate 	if (mci->mci_rstatus != NULL)
1062*7c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT,
1063*7c478bd9Sstevel@tonic-gate 				     "R%.80s\n",
1064*7c478bd9Sstevel@tonic-gate 				     denlstring(mci->mci_rstatus, true, false));
1065*7c478bd9Sstevel@tonic-gate 	(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "U%ld\n",
1066*7c478bd9Sstevel@tonic-gate 			     (long)(mci->mci_lastuse));
1067*7c478bd9Sstevel@tonic-gate 	(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, ".\n");
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate 	(void) sm_io_flush(mci->mci_statfile, SM_TIME_DEFAULT);
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 	errno = save_errno;
1072*7c478bd9Sstevel@tonic-gate 	return;
1073*7c478bd9Sstevel@tonic-gate }
1074*7c478bd9Sstevel@tonic-gate /*
1075*7c478bd9Sstevel@tonic-gate **  MCI_TRAVERSE_PERSISTENT -- walk persistent status tree
1076*7c478bd9Sstevel@tonic-gate **
1077*7c478bd9Sstevel@tonic-gate **	Recursively find all the mci host files in `pathname'.  Default to
1078*7c478bd9Sstevel@tonic-gate **		main host status directory if no path is provided.
1079*7c478bd9Sstevel@tonic-gate **	Call (*action)(pathname, host) for each file found.
1080*7c478bd9Sstevel@tonic-gate **
1081*7c478bd9Sstevel@tonic-gate **	Note: all information is collected in a list before it is processed.
1082*7c478bd9Sstevel@tonic-gate **	This may not be the best way to do it, but it seems safest, since
1083*7c478bd9Sstevel@tonic-gate **	the file system would be touched while we are attempting to traverse
1084*7c478bd9Sstevel@tonic-gate **	the directory tree otherwise (during purges).
1085*7c478bd9Sstevel@tonic-gate **
1086*7c478bd9Sstevel@tonic-gate **	Parameters:
1087*7c478bd9Sstevel@tonic-gate **		action -- function to call on each node.  If returns < 0,
1088*7c478bd9Sstevel@tonic-gate **			return immediately.
1089*7c478bd9Sstevel@tonic-gate **		pathname -- root of tree.  If null, use main host status
1090*7c478bd9Sstevel@tonic-gate **			directory.
1091*7c478bd9Sstevel@tonic-gate **
1092*7c478bd9Sstevel@tonic-gate **	Returns:
1093*7c478bd9Sstevel@tonic-gate **		< 0 -- if any action routine returns a negative value, that
1094*7c478bd9Sstevel@tonic-gate **			value is returned.
1095*7c478bd9Sstevel@tonic-gate **		0 -- if we successfully went to completion.
1096*7c478bd9Sstevel@tonic-gate **		> 0 -- return status from action()
1097*7c478bd9Sstevel@tonic-gate */
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate int
1100*7c478bd9Sstevel@tonic-gate mci_traverse_persistent(action, pathname)
1101*7c478bd9Sstevel@tonic-gate 	int (*action)__P((char *, char *));
1102*7c478bd9Sstevel@tonic-gate 	char *pathname;
1103*7c478bd9Sstevel@tonic-gate {
1104*7c478bd9Sstevel@tonic-gate 	struct stat statbuf;
1105*7c478bd9Sstevel@tonic-gate 	DIR *d;
1106*7c478bd9Sstevel@tonic-gate 	int ret;
1107*7c478bd9Sstevel@tonic-gate 
1108*7c478bd9Sstevel@tonic-gate 	if (pathname == NULL)
1109*7c478bd9Sstevel@tonic-gate 		pathname = HostStatDir;
1110*7c478bd9Sstevel@tonic-gate 	if (pathname == NULL)
1111*7c478bd9Sstevel@tonic-gate 		return -1;
1112*7c478bd9Sstevel@tonic-gate 
1113*7c478bd9Sstevel@tonic-gate 	if (tTd(56, 1))
1114*7c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_traverse: pathname is %s\n", pathname);
1115*7c478bd9Sstevel@tonic-gate 
1116*7c478bd9Sstevel@tonic-gate 	ret = stat(pathname, &statbuf);
1117*7c478bd9Sstevel@tonic-gate 	if (ret < 0)
1118*7c478bd9Sstevel@tonic-gate 	{
1119*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 2))
1120*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_traverse: Failed to stat %s: %s\n",
1121*7c478bd9Sstevel@tonic-gate 				pathname, sm_errstring(errno));
1122*7c478bd9Sstevel@tonic-gate 		return ret;
1123*7c478bd9Sstevel@tonic-gate 	}
1124*7c478bd9Sstevel@tonic-gate 	if (S_ISDIR(statbuf.st_mode))
1125*7c478bd9Sstevel@tonic-gate 	{
1126*7c478bd9Sstevel@tonic-gate 		bool leftone, removedone;
1127*7c478bd9Sstevel@tonic-gate 		size_t len;
1128*7c478bd9Sstevel@tonic-gate 		char *newptr;
1129*7c478bd9Sstevel@tonic-gate 		struct dirent *e;
1130*7c478bd9Sstevel@tonic-gate 		char newpath[MAXPATHLEN];
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate 		if ((d = opendir(pathname)) == NULL)
1133*7c478bd9Sstevel@tonic-gate 		{
1134*7c478bd9Sstevel@tonic-gate 			if (tTd(56, 2))
1135*7c478bd9Sstevel@tonic-gate 				sm_dprintf("mci_traverse: opendir %s: %s\n",
1136*7c478bd9Sstevel@tonic-gate 					pathname, sm_errstring(errno));
1137*7c478bd9Sstevel@tonic-gate 			return -1;
1138*7c478bd9Sstevel@tonic-gate 		}
1139*7c478bd9Sstevel@tonic-gate 		len = sizeof(newpath) - MAXNAMLEN - 3;
1140*7c478bd9Sstevel@tonic-gate 		if (sm_strlcpy(newpath, pathname, len) >= len)
1141*7c478bd9Sstevel@tonic-gate 		{
1142*7c478bd9Sstevel@tonic-gate 			if (tTd(56, 2))
1143*7c478bd9Sstevel@tonic-gate 				sm_dprintf("mci_traverse: path \"%s\" too long",
1144*7c478bd9Sstevel@tonic-gate 					pathname);
1145*7c478bd9Sstevel@tonic-gate 			return -1;
1146*7c478bd9Sstevel@tonic-gate 		}
1147*7c478bd9Sstevel@tonic-gate 		newptr = newpath + strlen(newpath);
1148*7c478bd9Sstevel@tonic-gate 		*newptr++ = '/';
1149*7c478bd9Sstevel@tonic-gate 
1150*7c478bd9Sstevel@tonic-gate 		/*
1151*7c478bd9Sstevel@tonic-gate 		**  repeat until no file has been removed
1152*7c478bd9Sstevel@tonic-gate 		**  this may become ugly when several files "expire"
1153*7c478bd9Sstevel@tonic-gate 		**  during these loops, but it's better than doing
1154*7c478bd9Sstevel@tonic-gate 		**  a rewinddir() inside the inner loop
1155*7c478bd9Sstevel@tonic-gate 		*/
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 		do
1158*7c478bd9Sstevel@tonic-gate 		{
1159*7c478bd9Sstevel@tonic-gate 			leftone = removedone = false;
1160*7c478bd9Sstevel@tonic-gate 			while ((e = readdir(d)) != NULL)
1161*7c478bd9Sstevel@tonic-gate 			{
1162*7c478bd9Sstevel@tonic-gate 				if (e->d_name[0] == '.')
1163*7c478bd9Sstevel@tonic-gate 					continue;
1164*7c478bd9Sstevel@tonic-gate 
1165*7c478bd9Sstevel@tonic-gate 				(void) sm_strlcpy(newptr, e->d_name,
1166*7c478bd9Sstevel@tonic-gate 					       sizeof newpath -
1167*7c478bd9Sstevel@tonic-gate 					       (newptr - newpath));
1168*7c478bd9Sstevel@tonic-gate 
1169*7c478bd9Sstevel@tonic-gate 				if (StopRequest)
1170*7c478bd9Sstevel@tonic-gate 					stop_sendmail();
1171*7c478bd9Sstevel@tonic-gate 				ret = mci_traverse_persistent(action, newpath);
1172*7c478bd9Sstevel@tonic-gate 				if (ret < 0)
1173*7c478bd9Sstevel@tonic-gate 					break;
1174*7c478bd9Sstevel@tonic-gate 				if (ret == 1)
1175*7c478bd9Sstevel@tonic-gate 					leftone = true;
1176*7c478bd9Sstevel@tonic-gate 				if (!removedone && ret == 0 &&
1177*7c478bd9Sstevel@tonic-gate 				    action == mci_purge_persistent)
1178*7c478bd9Sstevel@tonic-gate 					removedone = true;
1179*7c478bd9Sstevel@tonic-gate 			}
1180*7c478bd9Sstevel@tonic-gate 			if (ret < 0)
1181*7c478bd9Sstevel@tonic-gate 				break;
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate 			/*
1184*7c478bd9Sstevel@tonic-gate 			**  The following appears to be
1185*7c478bd9Sstevel@tonic-gate 			**  necessary during purges, since
1186*7c478bd9Sstevel@tonic-gate 			**  we modify the directory structure
1187*7c478bd9Sstevel@tonic-gate 			*/
1188*7c478bd9Sstevel@tonic-gate 
1189*7c478bd9Sstevel@tonic-gate 			if (removedone)
1190*7c478bd9Sstevel@tonic-gate 				rewinddir(d);
1191*7c478bd9Sstevel@tonic-gate 			if (tTd(56, 40))
1192*7c478bd9Sstevel@tonic-gate 				sm_dprintf("mci_traverse: path %s: ret %d removed %d left %d\n",
1193*7c478bd9Sstevel@tonic-gate 					pathname, ret, removedone, leftone);
1194*7c478bd9Sstevel@tonic-gate 		} while (removedone);
1195*7c478bd9Sstevel@tonic-gate 
1196*7c478bd9Sstevel@tonic-gate 		/* purge (or whatever) the directory proper */
1197*7c478bd9Sstevel@tonic-gate 		if (!leftone)
1198*7c478bd9Sstevel@tonic-gate 		{
1199*7c478bd9Sstevel@tonic-gate 			*--newptr = '\0';
1200*7c478bd9Sstevel@tonic-gate 			ret = (*action)(newpath, NULL);
1201*7c478bd9Sstevel@tonic-gate 		}
1202*7c478bd9Sstevel@tonic-gate 		(void) closedir(d);
1203*7c478bd9Sstevel@tonic-gate 	}
1204*7c478bd9Sstevel@tonic-gate 	else if (S_ISREG(statbuf.st_mode))
1205*7c478bd9Sstevel@tonic-gate 	{
1206*7c478bd9Sstevel@tonic-gate 		char *end = pathname + strlen(pathname) - 1;
1207*7c478bd9Sstevel@tonic-gate 		char *start;
1208*7c478bd9Sstevel@tonic-gate 		char *scan;
1209*7c478bd9Sstevel@tonic-gate 		char host[MAXHOSTNAMELEN];
1210*7c478bd9Sstevel@tonic-gate 		char *hostptr = host;
1211*7c478bd9Sstevel@tonic-gate 
1212*7c478bd9Sstevel@tonic-gate 		/*
1213*7c478bd9Sstevel@tonic-gate 		**  Reconstruct the host name from the path to the
1214*7c478bd9Sstevel@tonic-gate 		**  persistent information.
1215*7c478bd9Sstevel@tonic-gate 		*/
1216*7c478bd9Sstevel@tonic-gate 
1217*7c478bd9Sstevel@tonic-gate 		do
1218*7c478bd9Sstevel@tonic-gate 		{
1219*7c478bd9Sstevel@tonic-gate 			if (hostptr != host)
1220*7c478bd9Sstevel@tonic-gate 				*(hostptr++) = '.';
1221*7c478bd9Sstevel@tonic-gate 			start = end;
1222*7c478bd9Sstevel@tonic-gate 			while (start > pathname && *(start - 1) != '/')
1223*7c478bd9Sstevel@tonic-gate 				start--;
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate 			if (*end == '.')
1226*7c478bd9Sstevel@tonic-gate 				end--;
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 			for (scan = start; scan <= end; scan++)
1229*7c478bd9Sstevel@tonic-gate 				*(hostptr++) = *scan;
1230*7c478bd9Sstevel@tonic-gate 
1231*7c478bd9Sstevel@tonic-gate 			end = start - 2;
1232*7c478bd9Sstevel@tonic-gate 		} while (end > pathname && *end == '.');
1233*7c478bd9Sstevel@tonic-gate 
1234*7c478bd9Sstevel@tonic-gate 		*hostptr = '\0';
1235*7c478bd9Sstevel@tonic-gate 
1236*7c478bd9Sstevel@tonic-gate 		/*
1237*7c478bd9Sstevel@tonic-gate 		**  Do something with the file containing the persistent
1238*7c478bd9Sstevel@tonic-gate 		**  information.
1239*7c478bd9Sstevel@tonic-gate 		*/
1240*7c478bd9Sstevel@tonic-gate 
1241*7c478bd9Sstevel@tonic-gate 		ret = (*action)(pathname, host);
1242*7c478bd9Sstevel@tonic-gate 	}
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate 	return ret;
1245*7c478bd9Sstevel@tonic-gate }
1246*7c478bd9Sstevel@tonic-gate /*
1247*7c478bd9Sstevel@tonic-gate **  MCI_PRINT_PERSISTENT -- print persistent info
1248*7c478bd9Sstevel@tonic-gate **
1249*7c478bd9Sstevel@tonic-gate **	Dump the persistent information in the file 'pathname'
1250*7c478bd9Sstevel@tonic-gate **
1251*7c478bd9Sstevel@tonic-gate **	Parameters:
1252*7c478bd9Sstevel@tonic-gate **		pathname -- the pathname to the status file.
1253*7c478bd9Sstevel@tonic-gate **		hostname -- the corresponding host name.
1254*7c478bd9Sstevel@tonic-gate **
1255*7c478bd9Sstevel@tonic-gate **	Returns:
1256*7c478bd9Sstevel@tonic-gate **		0
1257*7c478bd9Sstevel@tonic-gate */
1258*7c478bd9Sstevel@tonic-gate 
1259*7c478bd9Sstevel@tonic-gate int
1260*7c478bd9Sstevel@tonic-gate mci_print_persistent(pathname, hostname)
1261*7c478bd9Sstevel@tonic-gate 	char *pathname;
1262*7c478bd9Sstevel@tonic-gate 	char *hostname;
1263*7c478bd9Sstevel@tonic-gate {
1264*7c478bd9Sstevel@tonic-gate 	static bool initflag = false;
1265*7c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
1266*7c478bd9Sstevel@tonic-gate 	int width = Verbose ? 78 : 25;
1267*7c478bd9Sstevel@tonic-gate 	bool locked;
1268*7c478bd9Sstevel@tonic-gate 	MCI mcib;
1269*7c478bd9Sstevel@tonic-gate 
1270*7c478bd9Sstevel@tonic-gate 	/* skip directories */
1271*7c478bd9Sstevel@tonic-gate 	if (hostname == NULL)
1272*7c478bd9Sstevel@tonic-gate 		return 0;
1273*7c478bd9Sstevel@tonic-gate 
1274*7c478bd9Sstevel@tonic-gate 	if (StopRequest)
1275*7c478bd9Sstevel@tonic-gate 		stop_sendmail();
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate 	if (!initflag)
1278*7c478bd9Sstevel@tonic-gate 	{
1279*7c478bd9Sstevel@tonic-gate 		initflag = true;
1280*7c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1281*7c478bd9Sstevel@tonic-gate 				     " -------------- Hostname --------------- How long ago ---------Results---------\n");
1282*7c478bd9Sstevel@tonic-gate 	}
1283*7c478bd9Sstevel@tonic-gate 
1284*7c478bd9Sstevel@tonic-gate 	fp = safefopen(pathname, O_RDONLY, FileMode,
1285*7c478bd9Sstevel@tonic-gate 		       SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH);
1286*7c478bd9Sstevel@tonic-gate 
1287*7c478bd9Sstevel@tonic-gate 	if (fp == NULL)
1288*7c478bd9Sstevel@tonic-gate 	{
1289*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
1290*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_print_persistent: cannot open %s: %s\n",
1291*7c478bd9Sstevel@tonic-gate 				pathname, sm_errstring(errno));
1292*7c478bd9Sstevel@tonic-gate 		return 0;
1293*7c478bd9Sstevel@tonic-gate 	}
1294*7c478bd9Sstevel@tonic-gate 
1295*7c478bd9Sstevel@tonic-gate 	FileName = pathname;
1296*7c478bd9Sstevel@tonic-gate 	memset(&mcib, '\0', sizeof mcib);
1297*7c478bd9Sstevel@tonic-gate 	if (mci_read_persistent(fp, &mcib) < 0)
1298*7c478bd9Sstevel@tonic-gate 	{
1299*7c478bd9Sstevel@tonic-gate 		syserr("%s: could not read status file", pathname);
1300*7c478bd9Sstevel@tonic-gate 		(void) sm_io_close(fp, SM_TIME_DEFAULT);
1301*7c478bd9Sstevel@tonic-gate 		FileName = NULL;
1302*7c478bd9Sstevel@tonic-gate 		return 0;
1303*7c478bd9Sstevel@tonic-gate 	}
1304*7c478bd9Sstevel@tonic-gate 
1305*7c478bd9Sstevel@tonic-gate 	locked = !lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), pathname,
1306*7c478bd9Sstevel@tonic-gate 			   "", LOCK_SH|LOCK_NB);
1307*7c478bd9Sstevel@tonic-gate 	(void) sm_io_close(fp, SM_TIME_DEFAULT);
1308*7c478bd9Sstevel@tonic-gate 	FileName = NULL;
1309*7c478bd9Sstevel@tonic-gate 
1310*7c478bd9Sstevel@tonic-gate 	(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%c%-39s %12s ",
1311*7c478bd9Sstevel@tonic-gate 			     locked ? '*' : ' ', hostname,
1312*7c478bd9Sstevel@tonic-gate 			     pintvl(curtime() - mcib.mci_lastuse, true));
1313*7c478bd9Sstevel@tonic-gate 	if (mcib.mci_rstatus != NULL)
1314*7c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", width,
1315*7c478bd9Sstevel@tonic-gate 				     mcib.mci_rstatus);
1316*7c478bd9Sstevel@tonic-gate 	else if (mcib.mci_exitstat == EX_TEMPFAIL && mcib.mci_errno != 0)
1317*7c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1318*7c478bd9Sstevel@tonic-gate 				     "Deferred: %.*s\n", width - 10,
1319*7c478bd9Sstevel@tonic-gate 				     sm_errstring(mcib.mci_errno));
1320*7c478bd9Sstevel@tonic-gate 	else if (mcib.mci_exitstat != 0)
1321*7c478bd9Sstevel@tonic-gate 	{
1322*7c478bd9Sstevel@tonic-gate 		char *exmsg = sm_sysexmsg(mcib.mci_exitstat);
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 		if (exmsg == NULL)
1325*7c478bd9Sstevel@tonic-gate 		{
1326*7c478bd9Sstevel@tonic-gate 			char buf[80];
1327*7c478bd9Sstevel@tonic-gate 
1328*7c478bd9Sstevel@tonic-gate 			(void) sm_snprintf(buf, sizeof buf,
1329*7c478bd9Sstevel@tonic-gate 				"Unknown mailer error %d",
1330*7c478bd9Sstevel@tonic-gate 				mcib.mci_exitstat);
1331*7c478bd9Sstevel@tonic-gate 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n",
1332*7c478bd9Sstevel@tonic-gate 					     width, buf);
1333*7c478bd9Sstevel@tonic-gate 		}
1334*7c478bd9Sstevel@tonic-gate 		else
1335*7c478bd9Sstevel@tonic-gate 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n",
1336*7c478bd9Sstevel@tonic-gate 					     width, &exmsg[5]);
1337*7c478bd9Sstevel@tonic-gate 	}
1338*7c478bd9Sstevel@tonic-gate 	else if (mcib.mci_errno == 0)
1339*7c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK\n");
1340*7c478bd9Sstevel@tonic-gate 	else
1341*7c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK: %.*s\n",
1342*7c478bd9Sstevel@tonic-gate 				     width - 4, sm_errstring(mcib.mci_errno));
1343*7c478bd9Sstevel@tonic-gate 
1344*7c478bd9Sstevel@tonic-gate 	return 0;
1345*7c478bd9Sstevel@tonic-gate }
1346*7c478bd9Sstevel@tonic-gate /*
1347*7c478bd9Sstevel@tonic-gate **  MCI_PURGE_PERSISTENT -- Remove a persistence status file.
1348*7c478bd9Sstevel@tonic-gate **
1349*7c478bd9Sstevel@tonic-gate **	Parameters:
1350*7c478bd9Sstevel@tonic-gate **		pathname -- path to the status file.
1351*7c478bd9Sstevel@tonic-gate **		hostname -- name of host corresponding to that file.
1352*7c478bd9Sstevel@tonic-gate **			NULL if this is a directory (domain).
1353*7c478bd9Sstevel@tonic-gate **
1354*7c478bd9Sstevel@tonic-gate **	Returns:
1355*7c478bd9Sstevel@tonic-gate **		0 -- ok
1356*7c478bd9Sstevel@tonic-gate **		1 -- file not deleted (too young, incorrect format)
1357*7c478bd9Sstevel@tonic-gate **		< 0 -- some error occurred
1358*7c478bd9Sstevel@tonic-gate */
1359*7c478bd9Sstevel@tonic-gate 
1360*7c478bd9Sstevel@tonic-gate int
1361*7c478bd9Sstevel@tonic-gate mci_purge_persistent(pathname, hostname)
1362*7c478bd9Sstevel@tonic-gate 	char *pathname;
1363*7c478bd9Sstevel@tonic-gate 	char *hostname;
1364*7c478bd9Sstevel@tonic-gate {
1365*7c478bd9Sstevel@tonic-gate 	struct stat statbuf;
1366*7c478bd9Sstevel@tonic-gate 	char *end = pathname + strlen(pathname) - 1;
1367*7c478bd9Sstevel@tonic-gate 	int ret;
1368*7c478bd9Sstevel@tonic-gate 
1369*7c478bd9Sstevel@tonic-gate 	if (tTd(56, 1))
1370*7c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_purge_persistent: purging %s\n", pathname);
1371*7c478bd9Sstevel@tonic-gate 
1372*7c478bd9Sstevel@tonic-gate 	ret = stat(pathname, &statbuf);
1373*7c478bd9Sstevel@tonic-gate 	if (ret < 0)
1374*7c478bd9Sstevel@tonic-gate 	{
1375*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 2))
1376*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_purge_persistent: Failed to stat %s: %s\n",
1377*7c478bd9Sstevel@tonic-gate 				pathname, sm_errstring(errno));
1378*7c478bd9Sstevel@tonic-gate 		return ret;
1379*7c478bd9Sstevel@tonic-gate 	}
1380*7c478bd9Sstevel@tonic-gate 	if (curtime() - statbuf.st_mtime <= MciInfoTimeout)
1381*7c478bd9Sstevel@tonic-gate 		return 1;
1382*7c478bd9Sstevel@tonic-gate 	if (hostname != NULL)
1383*7c478bd9Sstevel@tonic-gate 	{
1384*7c478bd9Sstevel@tonic-gate 		/* remove the file */
1385*7c478bd9Sstevel@tonic-gate 		ret = unlink(pathname);
1386*7c478bd9Sstevel@tonic-gate 		if (ret < 0)
1387*7c478bd9Sstevel@tonic-gate 		{
1388*7c478bd9Sstevel@tonic-gate 			if (LogLevel > 8)
1389*7c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ERR, NOQID,
1390*7c478bd9Sstevel@tonic-gate 					  "mci_purge_persistent: failed to unlink %s: %s",
1391*7c478bd9Sstevel@tonic-gate 					  pathname, sm_errstring(errno));
1392*7c478bd9Sstevel@tonic-gate 			if (tTd(56, 2))
1393*7c478bd9Sstevel@tonic-gate 				sm_dprintf("mci_purge_persistent: failed to unlink %s: %s\n",
1394*7c478bd9Sstevel@tonic-gate 					pathname, sm_errstring(errno));
1395*7c478bd9Sstevel@tonic-gate 			return ret;
1396*7c478bd9Sstevel@tonic-gate 		}
1397*7c478bd9Sstevel@tonic-gate 	}
1398*7c478bd9Sstevel@tonic-gate 	else
1399*7c478bd9Sstevel@tonic-gate 	{
1400*7c478bd9Sstevel@tonic-gate 		/* remove the directory */
1401*7c478bd9Sstevel@tonic-gate 		if (*end != '.')
1402*7c478bd9Sstevel@tonic-gate 			return 1;
1403*7c478bd9Sstevel@tonic-gate 
1404*7c478bd9Sstevel@tonic-gate 		if (tTd(56, 1))
1405*7c478bd9Sstevel@tonic-gate 			sm_dprintf("mci_purge_persistent: dpurge %s\n", pathname);
1406*7c478bd9Sstevel@tonic-gate 
1407*7c478bd9Sstevel@tonic-gate 		ret = rmdir(pathname);
1408*7c478bd9Sstevel@tonic-gate 		if (ret < 0)
1409*7c478bd9Sstevel@tonic-gate 		{
1410*7c478bd9Sstevel@tonic-gate 			if (tTd(56, 2))
1411*7c478bd9Sstevel@tonic-gate 				sm_dprintf("mci_purge_persistent: rmdir %s: %s\n",
1412*7c478bd9Sstevel@tonic-gate 					pathname, sm_errstring(errno));
1413*7c478bd9Sstevel@tonic-gate 			return ret;
1414*7c478bd9Sstevel@tonic-gate 		}
1415*7c478bd9Sstevel@tonic-gate 	}
1416*7c478bd9Sstevel@tonic-gate 
1417*7c478bd9Sstevel@tonic-gate 	return 0;
1418*7c478bd9Sstevel@tonic-gate }
1419*7c478bd9Sstevel@tonic-gate /*
1420*7c478bd9Sstevel@tonic-gate **  MCI_GENERATE_PERSISTENT_PATH -- generate path from hostname
1421*7c478bd9Sstevel@tonic-gate **
1422*7c478bd9Sstevel@tonic-gate **	Given `host', convert from a.b.c to $HostStatDir/c./b./a,
1423*7c478bd9Sstevel@tonic-gate **	putting the result into `path'.  if `createflag' is set, intervening
1424*7c478bd9Sstevel@tonic-gate **	directories will be created as needed.
1425*7c478bd9Sstevel@tonic-gate **
1426*7c478bd9Sstevel@tonic-gate **	Parameters:
1427*7c478bd9Sstevel@tonic-gate **		host -- host name to convert from.
1428*7c478bd9Sstevel@tonic-gate **		path -- place to store result.
1429*7c478bd9Sstevel@tonic-gate **		pathlen -- length of path buffer.
1430*7c478bd9Sstevel@tonic-gate **		createflag -- if set, create intervening directories as
1431*7c478bd9Sstevel@tonic-gate **			needed.
1432*7c478bd9Sstevel@tonic-gate **
1433*7c478bd9Sstevel@tonic-gate **	Returns:
1434*7c478bd9Sstevel@tonic-gate **		0 -- success
1435*7c478bd9Sstevel@tonic-gate **		-1 -- failure
1436*7c478bd9Sstevel@tonic-gate */
1437*7c478bd9Sstevel@tonic-gate 
1438*7c478bd9Sstevel@tonic-gate static int
1439*7c478bd9Sstevel@tonic-gate mci_generate_persistent_path(host, path, pathlen, createflag)
1440*7c478bd9Sstevel@tonic-gate 	const char *host;
1441*7c478bd9Sstevel@tonic-gate 	char *path;
1442*7c478bd9Sstevel@tonic-gate 	int pathlen;
1443*7c478bd9Sstevel@tonic-gate 	bool createflag;
1444*7c478bd9Sstevel@tonic-gate {
1445*7c478bd9Sstevel@tonic-gate 	char *elem, *p, *x, ch;
1446*7c478bd9Sstevel@tonic-gate 	int ret = 0;
1447*7c478bd9Sstevel@tonic-gate 	int len;
1448*7c478bd9Sstevel@tonic-gate 	char t_host[MAXHOSTNAMELEN];
1449*7c478bd9Sstevel@tonic-gate #if NETINET6
1450*7c478bd9Sstevel@tonic-gate 	struct in6_addr in6_addr;
1451*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
1452*7c478bd9Sstevel@tonic-gate 
1453*7c478bd9Sstevel@tonic-gate 	/*
1454*7c478bd9Sstevel@tonic-gate 	**  Rationality check the arguments.
1455*7c478bd9Sstevel@tonic-gate 	*/
1456*7c478bd9Sstevel@tonic-gate 
1457*7c478bd9Sstevel@tonic-gate 	if (host == NULL)
1458*7c478bd9Sstevel@tonic-gate 	{
1459*7c478bd9Sstevel@tonic-gate 		syserr("mci_generate_persistent_path: null host");
1460*7c478bd9Sstevel@tonic-gate 		return -1;
1461*7c478bd9Sstevel@tonic-gate 	}
1462*7c478bd9Sstevel@tonic-gate 	if (path == NULL)
1463*7c478bd9Sstevel@tonic-gate 	{
1464*7c478bd9Sstevel@tonic-gate 		syserr("mci_generate_persistent_path: null path");
1465*7c478bd9Sstevel@tonic-gate 		return -1;
1466*7c478bd9Sstevel@tonic-gate 	}
1467*7c478bd9Sstevel@tonic-gate 
1468*7c478bd9Sstevel@tonic-gate 	if (tTd(56, 80))
1469*7c478bd9Sstevel@tonic-gate 		sm_dprintf("mci_generate_persistent_path(%s): ", host);
1470*7c478bd9Sstevel@tonic-gate 
1471*7c478bd9Sstevel@tonic-gate 	if (*host == '\0' || *host == '.')
1472*7c478bd9Sstevel@tonic-gate 		return -1;
1473*7c478bd9Sstevel@tonic-gate 
1474*7c478bd9Sstevel@tonic-gate 	/* make certain this is not a bracketed host number */
1475*7c478bd9Sstevel@tonic-gate 	if (strlen(host) > sizeof t_host - 1)
1476*7c478bd9Sstevel@tonic-gate 		return -1;
1477*7c478bd9Sstevel@tonic-gate 	if (host[0] == '[')
1478*7c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(t_host, host + 1, sizeof t_host);
1479*7c478bd9Sstevel@tonic-gate 	else
1480*7c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(t_host, host, sizeof t_host);
1481*7c478bd9Sstevel@tonic-gate 
1482*7c478bd9Sstevel@tonic-gate 	/*
1483*7c478bd9Sstevel@tonic-gate 	**  Delete any trailing dots from the hostname.
1484*7c478bd9Sstevel@tonic-gate 	**  Leave 'elem' pointing at the \0.
1485*7c478bd9Sstevel@tonic-gate 	*/
1486*7c478bd9Sstevel@tonic-gate 
1487*7c478bd9Sstevel@tonic-gate 	elem = t_host + strlen(t_host);
1488*7c478bd9Sstevel@tonic-gate 	while (elem > t_host &&
1489*7c478bd9Sstevel@tonic-gate 	       (elem[-1] == '.' || (host[0] == '[' && elem[-1] == ']')))
1490*7c478bd9Sstevel@tonic-gate 		*--elem = '\0';
1491*7c478bd9Sstevel@tonic-gate 
1492*7c478bd9Sstevel@tonic-gate 	/* check for bogus bracketed address */
1493*7c478bd9Sstevel@tonic-gate 	if (host[0] == '[')
1494*7c478bd9Sstevel@tonic-gate 	{
1495*7c478bd9Sstevel@tonic-gate 		bool good = false;
1496*7c478bd9Sstevel@tonic-gate # if NETINET6
1497*7c478bd9Sstevel@tonic-gate 		if (anynet_pton(AF_INET6, t_host, &in6_addr) == 1)
1498*7c478bd9Sstevel@tonic-gate 			good = true;
1499*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
1500*7c478bd9Sstevel@tonic-gate # if NETINET
1501*7c478bd9Sstevel@tonic-gate 		if (inet_addr(t_host) != INADDR_NONE)
1502*7c478bd9Sstevel@tonic-gate 			good = true;
1503*7c478bd9Sstevel@tonic-gate # endif /* NETINET */
1504*7c478bd9Sstevel@tonic-gate 		if (!good)
1505*7c478bd9Sstevel@tonic-gate 			return -1;
1506*7c478bd9Sstevel@tonic-gate 	}
1507*7c478bd9Sstevel@tonic-gate 
1508*7c478bd9Sstevel@tonic-gate 	/* check for what will be the final length of the path */
1509*7c478bd9Sstevel@tonic-gate 	len = strlen(HostStatDir) + 2;
1510*7c478bd9Sstevel@tonic-gate 	for (p = (char *) t_host; *p != '\0'; p++)
1511*7c478bd9Sstevel@tonic-gate 	{
1512*7c478bd9Sstevel@tonic-gate 		if (*p == '.')
1513*7c478bd9Sstevel@tonic-gate 			len++;
1514*7c478bd9Sstevel@tonic-gate 		len++;
1515*7c478bd9Sstevel@tonic-gate 		if (p[0] == '.' && p[1] == '.')
1516*7c478bd9Sstevel@tonic-gate 			return -1;
1517*7c478bd9Sstevel@tonic-gate 	}
1518*7c478bd9Sstevel@tonic-gate 	if (len > pathlen || len < 1)
1519*7c478bd9Sstevel@tonic-gate 		return -1;
1520*7c478bd9Sstevel@tonic-gate 	(void) sm_strlcpy(path, HostStatDir, pathlen);
1521*7c478bd9Sstevel@tonic-gate 	p = path + strlen(path);
1522*7c478bd9Sstevel@tonic-gate 	while (elem > t_host)
1523*7c478bd9Sstevel@tonic-gate 	{
1524*7c478bd9Sstevel@tonic-gate 		if (!path_is_dir(path, createflag))
1525*7c478bd9Sstevel@tonic-gate 		{
1526*7c478bd9Sstevel@tonic-gate 			ret = -1;
1527*7c478bd9Sstevel@tonic-gate 			break;
1528*7c478bd9Sstevel@tonic-gate 		}
1529*7c478bd9Sstevel@tonic-gate 		elem--;
1530*7c478bd9Sstevel@tonic-gate 		while (elem >= t_host && *elem != '.')
1531*7c478bd9Sstevel@tonic-gate 			elem--;
1532*7c478bd9Sstevel@tonic-gate 		*p++ = '/';
1533*7c478bd9Sstevel@tonic-gate 		x = elem + 1;
1534*7c478bd9Sstevel@tonic-gate 		while ((ch = *x++) != '\0' && ch != '.')
1535*7c478bd9Sstevel@tonic-gate 		{
1536*7c478bd9Sstevel@tonic-gate 			if (isascii(ch) && isupper(ch))
1537*7c478bd9Sstevel@tonic-gate 				ch = tolower(ch);
1538*7c478bd9Sstevel@tonic-gate 			if (ch == '/')
1539*7c478bd9Sstevel@tonic-gate 				ch = ':';	/* / -> : */
1540*7c478bd9Sstevel@tonic-gate 			*p++ = ch;
1541*7c478bd9Sstevel@tonic-gate 		}
1542*7c478bd9Sstevel@tonic-gate 		if (elem >= t_host)
1543*7c478bd9Sstevel@tonic-gate 			*p++ = '.';
1544*7c478bd9Sstevel@tonic-gate 		*p = '\0';
1545*7c478bd9Sstevel@tonic-gate 	}
1546*7c478bd9Sstevel@tonic-gate 	if (tTd(56, 80))
1547*7c478bd9Sstevel@tonic-gate 	{
1548*7c478bd9Sstevel@tonic-gate 		if (ret < 0)
1549*7c478bd9Sstevel@tonic-gate 			sm_dprintf("FAILURE %d\n", ret);
1550*7c478bd9Sstevel@tonic-gate 		else
1551*7c478bd9Sstevel@tonic-gate 			sm_dprintf("SUCCESS %s\n", path);
1552*7c478bd9Sstevel@tonic-gate 	}
1553*7c478bd9Sstevel@tonic-gate 	return ret;
1554*7c478bd9Sstevel@tonic-gate }
1555