17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * Copyright (c) 1998-2005 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate * All rights reserved.
47c478bd9Sstevel@tonic-gate * Copyright (c) 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*d4660949Sjbeck SM_RCSID("@(#)$Id: mci.c,v 8.221 2007/11/13 23:44:25 gshapiro Exp $")
197c478bd9Sstevel@tonic-gate
207c478bd9Sstevel@tonic-gate #if NETINET || NETINET6
217c478bd9Sstevel@tonic-gate # include <arpa/inet.h>
227c478bd9Sstevel@tonic-gate #endif /* NETINET || NETINET6 */
237c478bd9Sstevel@tonic-gate
247c478bd9Sstevel@tonic-gate #include <dirent.h>
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate static int mci_generate_persistent_path __P((const char *, char *,
277c478bd9Sstevel@tonic-gate int, bool));
287c478bd9Sstevel@tonic-gate static bool mci_load_persistent __P((MCI *));
297c478bd9Sstevel@tonic-gate static void mci_uncache __P((MCI **, bool));
307c478bd9Sstevel@tonic-gate static int mci_lock_host_statfile __P((MCI *));
317c478bd9Sstevel@tonic-gate static int mci_read_persistent __P((SM_FILE_T *, MCI *));
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate ** Mail Connection Information (MCI) Caching Module.
357c478bd9Sstevel@tonic-gate **
367c478bd9Sstevel@tonic-gate ** There are actually two separate things cached. The first is
377c478bd9Sstevel@tonic-gate ** the set of all open connections -- these are stored in a
387c478bd9Sstevel@tonic-gate ** (small) list. The second is stored in the symbol table; it
397c478bd9Sstevel@tonic-gate ** has the overall status for all hosts, whether or not there
407c478bd9Sstevel@tonic-gate ** is a connection open currently.
417c478bd9Sstevel@tonic-gate **
427c478bd9Sstevel@tonic-gate ** There should never be too many connections open (since this
437c478bd9Sstevel@tonic-gate ** could flood the socket table), nor should a connection be
447c478bd9Sstevel@tonic-gate ** allowed to sit idly for too long.
457c478bd9Sstevel@tonic-gate **
467c478bd9Sstevel@tonic-gate ** MaxMciCache is the maximum number of open connections that
477c478bd9Sstevel@tonic-gate ** will be supported.
487c478bd9Sstevel@tonic-gate **
497c478bd9Sstevel@tonic-gate ** MciCacheTimeout is the time (in seconds) that a connection
507c478bd9Sstevel@tonic-gate ** is permitted to survive without activity.
517c478bd9Sstevel@tonic-gate **
5249218d4fSjbeck ** We actually try any cached connections by sending a RSET
5349218d4fSjbeck ** before we use them; if the RSET fails we close down the
5449218d4fSjbeck ** connection and reopen it (see smtpprobe()).
557c478bd9Sstevel@tonic-gate **
567c478bd9Sstevel@tonic-gate ** The persistent MCI code is donated by Mark Lovell and Paul
577c478bd9Sstevel@tonic-gate ** Vixie. It is based on the long term host status code in KJS
587c478bd9Sstevel@tonic-gate ** written by Paul but has been adapted by Mark to fit into the
597c478bd9Sstevel@tonic-gate ** MCI structure.
607c478bd9Sstevel@tonic-gate */
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate static MCI **MciCache; /* the open connection cache */
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate ** MCI_CACHE -- enter a connection structure into the open connection cache
667c478bd9Sstevel@tonic-gate **
677c478bd9Sstevel@tonic-gate ** This may cause something else to be flushed.
687c478bd9Sstevel@tonic-gate **
697c478bd9Sstevel@tonic-gate ** Parameters:
707c478bd9Sstevel@tonic-gate ** mci -- the connection to cache.
717c478bd9Sstevel@tonic-gate **
727c478bd9Sstevel@tonic-gate ** Returns:
737c478bd9Sstevel@tonic-gate ** none.
747c478bd9Sstevel@tonic-gate */
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate void
mci_cache(mci)777c478bd9Sstevel@tonic-gate mci_cache(mci)
787c478bd9Sstevel@tonic-gate register MCI *mci;
797c478bd9Sstevel@tonic-gate {
807c478bd9Sstevel@tonic-gate register MCI **mcislot;
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate /*
837c478bd9Sstevel@tonic-gate ** Find the best slot. This may cause expired connections
847c478bd9Sstevel@tonic-gate ** to be closed.
857c478bd9Sstevel@tonic-gate */
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate mcislot = mci_scan(mci);
887c478bd9Sstevel@tonic-gate if (mcislot == NULL)
897c478bd9Sstevel@tonic-gate {
907c478bd9Sstevel@tonic-gate /* we don't support caching */
917c478bd9Sstevel@tonic-gate return;
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate if (mci->mci_host == NULL)
957c478bd9Sstevel@tonic-gate return;
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate /* if this is already cached, we are done */
987c478bd9Sstevel@tonic-gate if (bitset(MCIF_CACHED, mci->mci_flags))
997c478bd9Sstevel@tonic-gate return;
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate /* otherwise we may have to clear the slot */
1027c478bd9Sstevel@tonic-gate if (*mcislot != NULL)
1037c478bd9Sstevel@tonic-gate mci_uncache(mcislot, true);
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate if (tTd(42, 5))
1067c478bd9Sstevel@tonic-gate sm_dprintf("mci_cache: caching %p (%s) in slot %d\n",
1077c478bd9Sstevel@tonic-gate mci, mci->mci_host, (int) (mcislot - MciCache));
1087c478bd9Sstevel@tonic-gate if (tTd(91, 100))
1097c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id,
1107c478bd9Sstevel@tonic-gate "mci_cache: caching %lx (%.100s) in slot %d",
1117c478bd9Sstevel@tonic-gate (unsigned long) mci, mci->mci_host,
1127c478bd9Sstevel@tonic-gate (int) (mcislot - MciCache));
1137c478bd9Sstevel@tonic-gate
1147c478bd9Sstevel@tonic-gate *mcislot = mci;
1157c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_CACHED;
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate /*
1187c478bd9Sstevel@tonic-gate ** MCI_SCAN -- scan the cache, flush junk, and return best slot
1197c478bd9Sstevel@tonic-gate **
1207c478bd9Sstevel@tonic-gate ** Parameters:
1217c478bd9Sstevel@tonic-gate ** savemci -- never flush this one. Can be null.
1227c478bd9Sstevel@tonic-gate **
1237c478bd9Sstevel@tonic-gate ** Returns:
1247c478bd9Sstevel@tonic-gate ** The LRU (or empty) slot.
1257c478bd9Sstevel@tonic-gate */
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate MCI **
mci_scan(savemci)1287c478bd9Sstevel@tonic-gate mci_scan(savemci)
1297c478bd9Sstevel@tonic-gate MCI *savemci;
1307c478bd9Sstevel@tonic-gate {
1317c478bd9Sstevel@tonic-gate time_t now;
1327c478bd9Sstevel@tonic-gate register MCI **bestmci;
1337c478bd9Sstevel@tonic-gate register MCI *mci;
1347c478bd9Sstevel@tonic-gate register int i;
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate if (MaxMciCache <= 0)
1377c478bd9Sstevel@tonic-gate {
1387c478bd9Sstevel@tonic-gate /* we don't support caching */
1397c478bd9Sstevel@tonic-gate return NULL;
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate if (MciCache == NULL)
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate /* first call */
145058561cbSjbeck MciCache = (MCI **) sm_pmalloc_x(MaxMciCache * sizeof(*MciCache));
146058561cbSjbeck memset((char *) MciCache, '\0', MaxMciCache * sizeof(*MciCache));
1477c478bd9Sstevel@tonic-gate return &MciCache[0];
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate
1507c478bd9Sstevel@tonic-gate now = curtime();
1517c478bd9Sstevel@tonic-gate bestmci = &MciCache[0];
1527c478bd9Sstevel@tonic-gate for (i = 0; i < MaxMciCache; i++)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate mci = MciCache[i];
1557c478bd9Sstevel@tonic-gate if (mci == NULL || mci->mci_state == MCIS_CLOSED)
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate bestmci = &MciCache[i];
1587c478bd9Sstevel@tonic-gate continue;
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate if ((mci->mci_lastuse + MciCacheTimeout <= now ||
1617c478bd9Sstevel@tonic-gate (mci->mci_mailer != NULL &&
1627c478bd9Sstevel@tonic-gate mci->mci_mailer->m_maxdeliveries > 0 &&
1637c478bd9Sstevel@tonic-gate mci->mci_deliveries + 1 >= mci->mci_mailer->m_maxdeliveries))&&
1647c478bd9Sstevel@tonic-gate mci != savemci)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate /* connection idle too long or too many deliveries */
1677c478bd9Sstevel@tonic-gate bestmci = &MciCache[i];
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate /* close it */
1707c478bd9Sstevel@tonic-gate mci_uncache(bestmci, true);
1717c478bd9Sstevel@tonic-gate continue;
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate if (*bestmci == NULL)
1747c478bd9Sstevel@tonic-gate continue;
1757c478bd9Sstevel@tonic-gate if (mci->mci_lastuse < (*bestmci)->mci_lastuse)
1767c478bd9Sstevel@tonic-gate bestmci = &MciCache[i];
1777c478bd9Sstevel@tonic-gate }
1787c478bd9Sstevel@tonic-gate return bestmci;
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate /*
1817c478bd9Sstevel@tonic-gate ** MCI_UNCACHE -- remove a connection from a slot.
1827c478bd9Sstevel@tonic-gate **
1837c478bd9Sstevel@tonic-gate ** May close a connection.
1847c478bd9Sstevel@tonic-gate **
1857c478bd9Sstevel@tonic-gate ** Parameters:
1867c478bd9Sstevel@tonic-gate ** mcislot -- the slot to empty.
1877c478bd9Sstevel@tonic-gate ** doquit -- if true, send QUIT protocol on this connection.
1887c478bd9Sstevel@tonic-gate ** if false, we are assumed to be in a forked child;
1897c478bd9Sstevel@tonic-gate ** all we want to do is close the file(s).
1907c478bd9Sstevel@tonic-gate **
1917c478bd9Sstevel@tonic-gate ** Returns:
1927c478bd9Sstevel@tonic-gate ** none.
1937c478bd9Sstevel@tonic-gate */
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate static void
mci_uncache(mcislot,doquit)1967c478bd9Sstevel@tonic-gate mci_uncache(mcislot, doquit)
1977c478bd9Sstevel@tonic-gate register MCI **mcislot;
1987c478bd9Sstevel@tonic-gate bool doquit;
1997c478bd9Sstevel@tonic-gate {
2007c478bd9Sstevel@tonic-gate register MCI *mci;
2017c478bd9Sstevel@tonic-gate extern ENVELOPE BlankEnvelope;
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate mci = *mcislot;
2047c478bd9Sstevel@tonic-gate if (mci == NULL)
2057c478bd9Sstevel@tonic-gate return;
2067c478bd9Sstevel@tonic-gate *mcislot = NULL;
2077c478bd9Sstevel@tonic-gate if (mci->mci_host == NULL)
2087c478bd9Sstevel@tonic-gate return;
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate mci_unlock_host(mci);
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate if (tTd(42, 5))
2137c478bd9Sstevel@tonic-gate sm_dprintf("mci_uncache: uncaching %p (%s) from slot %d (%d)\n",
2147c478bd9Sstevel@tonic-gate mci, mci->mci_host, (int) (mcislot - MciCache),
2157c478bd9Sstevel@tonic-gate doquit);
2167c478bd9Sstevel@tonic-gate if (tTd(91, 100))
2177c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id,
2187c478bd9Sstevel@tonic-gate "mci_uncache: uncaching %lx (%.100s) from slot %d (%d)",
2197c478bd9Sstevel@tonic-gate (unsigned long) mci, mci->mci_host,
2207c478bd9Sstevel@tonic-gate (int) (mcislot - MciCache), doquit);
2217c478bd9Sstevel@tonic-gate
2227c478bd9Sstevel@tonic-gate mci->mci_deliveries = 0;
2237c478bd9Sstevel@tonic-gate if (doquit)
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate message("Closing connection to %s", mci->mci_host);
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_CACHED;
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate /* only uses the envelope to flush the transcript file */
2307c478bd9Sstevel@tonic-gate if (mci->mci_state != MCIS_CLOSED)
2317c478bd9Sstevel@tonic-gate smtpquit(mci->mci_mailer, mci, &BlankEnvelope);
2327c478bd9Sstevel@tonic-gate #if XLA
2337c478bd9Sstevel@tonic-gate xla_host_end(mci->mci_host);
2347c478bd9Sstevel@tonic-gate #endif /* XLA */
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate else
2377c478bd9Sstevel@tonic-gate {
2387c478bd9Sstevel@tonic-gate if (mci->mci_in != NULL)
2397c478bd9Sstevel@tonic-gate (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT);
2407c478bd9Sstevel@tonic-gate if (mci->mci_out != NULL)
2417c478bd9Sstevel@tonic-gate (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
2427c478bd9Sstevel@tonic-gate mci->mci_in = mci->mci_out = NULL;
2437c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_CLOSED;
2447c478bd9Sstevel@tonic-gate mci->mci_exitstat = EX_OK;
2457c478bd9Sstevel@tonic-gate mci->mci_errno = 0;
2467c478bd9Sstevel@tonic-gate mci->mci_flags = 0;
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate mci->mci_retryrcpt = false;
2497c478bd9Sstevel@tonic-gate mci->mci_tolist = NULL;
2507c478bd9Sstevel@tonic-gate #if PIPELINING
2517c478bd9Sstevel@tonic-gate mci->mci_okrcpts = 0;
2527c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate SM_FREE_CLR(mci->mci_status);
2567c478bd9Sstevel@tonic-gate SM_FREE_CLR(mci->mci_rstatus);
2577c478bd9Sstevel@tonic-gate SM_FREE_CLR(mci->mci_heloname);
2587c478bd9Sstevel@tonic-gate if (mci->mci_rpool != NULL)
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate sm_rpool_free(mci->mci_rpool);
2617c478bd9Sstevel@tonic-gate mci->mci_macro.mac_rpool = NULL;
2627c478bd9Sstevel@tonic-gate mci->mci_rpool = NULL;
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate /*
2667c478bd9Sstevel@tonic-gate ** MCI_FLUSH -- flush the entire cache
2677c478bd9Sstevel@tonic-gate **
2687c478bd9Sstevel@tonic-gate ** Parameters:
2697c478bd9Sstevel@tonic-gate ** doquit -- if true, send QUIT protocol.
2707c478bd9Sstevel@tonic-gate ** if false, just close the connection.
2717c478bd9Sstevel@tonic-gate ** allbut -- but leave this one open.
2727c478bd9Sstevel@tonic-gate **
2737c478bd9Sstevel@tonic-gate ** Returns:
2747c478bd9Sstevel@tonic-gate ** none.
2757c478bd9Sstevel@tonic-gate */
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate void
mci_flush(doquit,allbut)2787c478bd9Sstevel@tonic-gate mci_flush(doquit, allbut)
2797c478bd9Sstevel@tonic-gate bool doquit;
2807c478bd9Sstevel@tonic-gate MCI *allbut;
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate register int i;
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate if (MciCache == NULL)
2857c478bd9Sstevel@tonic-gate return;
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate for (i = 0; i < MaxMciCache; i++)
2887c478bd9Sstevel@tonic-gate {
2897c478bd9Sstevel@tonic-gate if (allbut != MciCache[i])
2907c478bd9Sstevel@tonic-gate mci_uncache(&MciCache[i], doquit);
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate /*
2947c478bd9Sstevel@tonic-gate ** MCI_GET -- get information about a particular host
2957c478bd9Sstevel@tonic-gate **
2967c478bd9Sstevel@tonic-gate ** Parameters:
2977c478bd9Sstevel@tonic-gate ** host -- host to look for.
2987c478bd9Sstevel@tonic-gate ** m -- mailer.
2997c478bd9Sstevel@tonic-gate **
3007c478bd9Sstevel@tonic-gate ** Returns:
3017c478bd9Sstevel@tonic-gate ** mci for this host (might be new).
3027c478bd9Sstevel@tonic-gate */
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate MCI *
mci_get(host,m)3057c478bd9Sstevel@tonic-gate mci_get(host, m)
3067c478bd9Sstevel@tonic-gate char *host;
3077c478bd9Sstevel@tonic-gate MAILER *m;
3087c478bd9Sstevel@tonic-gate {
3097c478bd9Sstevel@tonic-gate register MCI *mci;
3107c478bd9Sstevel@tonic-gate register STAB *s;
3117c478bd9Sstevel@tonic-gate extern SOCKADDR CurHostAddr;
3127c478bd9Sstevel@tonic-gate
3137c478bd9Sstevel@tonic-gate /* clear CurHostAddr so we don't get a bogus address with this name */
314058561cbSjbeck memset(&CurHostAddr, '\0', sizeof(CurHostAddr));
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate /* clear out any expired connections */
3177c478bd9Sstevel@tonic-gate (void) mci_scan(NULL);
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate if (m->m_mno < 0)
3207c478bd9Sstevel@tonic-gate syserr("!negative mno %d (%s)", m->m_mno, m->m_name);
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate s = stab(host, ST_MCI + m->m_mno, ST_ENTER);
3237c478bd9Sstevel@tonic-gate mci = &s->s_mci;
3247c478bd9Sstevel@tonic-gate
3257c478bd9Sstevel@tonic-gate /* initialize per-message data */
3267c478bd9Sstevel@tonic-gate mci->mci_retryrcpt = false;
3277c478bd9Sstevel@tonic-gate mci->mci_tolist = NULL;
3287c478bd9Sstevel@tonic-gate #if PIPELINING
3297c478bd9Sstevel@tonic-gate mci->mci_okrcpts = 0;
3307c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
3317c478bd9Sstevel@tonic-gate
3327c478bd9Sstevel@tonic-gate if (mci->mci_rpool == NULL)
3337c478bd9Sstevel@tonic-gate mci->mci_rpool = sm_rpool_new_x(NULL);
3347c478bd9Sstevel@tonic-gate
3357c478bd9Sstevel@tonic-gate if (mci->mci_macro.mac_rpool == NULL)
3367c478bd9Sstevel@tonic-gate mci->mci_macro.mac_rpool = mci->mci_rpool;
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate /*
3397c478bd9Sstevel@tonic-gate ** We don't need to load the persistent data if we have data
3407c478bd9Sstevel@tonic-gate ** already loaded in the cache.
3417c478bd9Sstevel@tonic-gate */
3427c478bd9Sstevel@tonic-gate
3437c478bd9Sstevel@tonic-gate if (mci->mci_host == NULL &&
3447c478bd9Sstevel@tonic-gate (mci->mci_host = s->s_name) != NULL &&
3457c478bd9Sstevel@tonic-gate !mci_load_persistent(mci))
3467c478bd9Sstevel@tonic-gate {
3477c478bd9Sstevel@tonic-gate if (tTd(42, 2))
3487c478bd9Sstevel@tonic-gate sm_dprintf("mci_get(%s %s): lock failed\n",
3497c478bd9Sstevel@tonic-gate host, m->m_name);
3507c478bd9Sstevel@tonic-gate mci->mci_exitstat = EX_TEMPFAIL;
3517c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_CLOSED;
3527c478bd9Sstevel@tonic-gate mci->mci_statfile = NULL;
3537c478bd9Sstevel@tonic-gate return mci;
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate if (tTd(42, 2))
3577c478bd9Sstevel@tonic-gate {
3587c478bd9Sstevel@tonic-gate sm_dprintf("mci_get(%s %s): mci_state=%d, _flags=%lx, _exitstat=%d, _errno=%d\n",
3597c478bd9Sstevel@tonic-gate host, m->m_name, mci->mci_state, mci->mci_flags,
3607c478bd9Sstevel@tonic-gate mci->mci_exitstat, mci->mci_errno);
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate if (mci->mci_state == MCIS_OPEN)
3647c478bd9Sstevel@tonic-gate {
3657c478bd9Sstevel@tonic-gate /* poke the connection to see if it's still alive */
3667c478bd9Sstevel@tonic-gate (void) smtpprobe(mci);
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate /* reset the stored state in the event of a timeout */
3697c478bd9Sstevel@tonic-gate if (mci->mci_state != MCIS_OPEN)
3707c478bd9Sstevel@tonic-gate {
3717c478bd9Sstevel@tonic-gate mci->mci_errno = 0;
3727c478bd9Sstevel@tonic-gate mci->mci_exitstat = EX_OK;
3737c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_CLOSED;
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate else
3767c478bd9Sstevel@tonic-gate {
3777c478bd9Sstevel@tonic-gate /* get peer host address */
3787c478bd9Sstevel@tonic-gate /* (this should really be in the mci struct) */
379058561cbSjbeck SOCKADDR_LEN_T socklen = sizeof(CurHostAddr);
3807c478bd9Sstevel@tonic-gate
3817c478bd9Sstevel@tonic-gate (void) getpeername(sm_io_getinfo(mci->mci_in,
3827c478bd9Sstevel@tonic-gate SM_IO_WHAT_FD, NULL),
3837c478bd9Sstevel@tonic-gate (struct sockaddr *) &CurHostAddr, &socklen);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate if (mci->mci_state == MCIS_CLOSED)
3877c478bd9Sstevel@tonic-gate {
3887c478bd9Sstevel@tonic-gate time_t now = curtime();
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate /* if this info is stale, ignore it */
3917c478bd9Sstevel@tonic-gate if (mci->mci_lastuse + MciInfoTimeout <= now)
3927c478bd9Sstevel@tonic-gate {
3937c478bd9Sstevel@tonic-gate mci->mci_lastuse = now;
3947c478bd9Sstevel@tonic-gate mci->mci_errno = 0;
3957c478bd9Sstevel@tonic-gate mci->mci_exitstat = EX_OK;
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate return mci;
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate
4027c478bd9Sstevel@tonic-gate /*
4037c478bd9Sstevel@tonic-gate ** MCI_CLOSE -- (forcefully) close files used for a connection.
4047c478bd9Sstevel@tonic-gate ** Note: this is a last resort, usually smtpquit() or endmailer()
4057c478bd9Sstevel@tonic-gate ** should be used to close a connection.
4067c478bd9Sstevel@tonic-gate **
4077c478bd9Sstevel@tonic-gate ** Parameters:
4087c478bd9Sstevel@tonic-gate ** mci -- the connection to close.
4097c478bd9Sstevel@tonic-gate ** where -- where has this been called?
4107c478bd9Sstevel@tonic-gate **
4117c478bd9Sstevel@tonic-gate ** Returns:
4127c478bd9Sstevel@tonic-gate ** none.
4137c478bd9Sstevel@tonic-gate */
4147c478bd9Sstevel@tonic-gate
4157c478bd9Sstevel@tonic-gate void
mci_close(mci,where)4167c478bd9Sstevel@tonic-gate mci_close(mci, where)
4177c478bd9Sstevel@tonic-gate MCI *mci;
4187c478bd9Sstevel@tonic-gate char *where;
4197c478bd9Sstevel@tonic-gate {
4207c478bd9Sstevel@tonic-gate bool dumped;
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate if (mci == NULL)
4237c478bd9Sstevel@tonic-gate return;
4247c478bd9Sstevel@tonic-gate dumped = false;
4257c478bd9Sstevel@tonic-gate if (mci->mci_out != NULL)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate if (tTd(56, 1))
4287c478bd9Sstevel@tonic-gate {
4297c478bd9Sstevel@tonic-gate sm_dprintf("mci_close: mci_out!=NULL, where=%s\n",
4307c478bd9Sstevel@tonic-gate where);
4317c478bd9Sstevel@tonic-gate mci_dump(sm_debug_file(), mci, false);
4327c478bd9Sstevel@tonic-gate dumped = true;
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
4357c478bd9Sstevel@tonic-gate mci->mci_out = NULL;
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate if (mci->mci_in != NULL)
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate if (tTd(56, 1))
4407c478bd9Sstevel@tonic-gate {
4417c478bd9Sstevel@tonic-gate sm_dprintf("mci_close: mci_in!=NULL, where=%s\n",
4427c478bd9Sstevel@tonic-gate where);
4437c478bd9Sstevel@tonic-gate if (!dumped)
4447c478bd9Sstevel@tonic-gate mci_dump(sm_debug_file(), mci, false);
4457c478bd9Sstevel@tonic-gate }
4467c478bd9Sstevel@tonic-gate (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT);
4477c478bd9Sstevel@tonic-gate mci->mci_in = NULL;
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_CLOSED;
4507c478bd9Sstevel@tonic-gate }
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate /*
4537c478bd9Sstevel@tonic-gate ** MCI_NEW -- allocate new MCI structure
4547c478bd9Sstevel@tonic-gate **
4557c478bd9Sstevel@tonic-gate ** Parameters:
4567c478bd9Sstevel@tonic-gate ** rpool -- if non-NULL: allocate from that rpool.
4577c478bd9Sstevel@tonic-gate **
4587c478bd9Sstevel@tonic-gate ** Returns:
4597c478bd9Sstevel@tonic-gate ** mci (new).
4607c478bd9Sstevel@tonic-gate */
4617c478bd9Sstevel@tonic-gate
4627c478bd9Sstevel@tonic-gate MCI *
mci_new(rpool)4637c478bd9Sstevel@tonic-gate mci_new(rpool)
4647c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool;
4657c478bd9Sstevel@tonic-gate {
4667c478bd9Sstevel@tonic-gate register MCI *mci;
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate if (rpool == NULL)
469058561cbSjbeck mci = (MCI *) sm_malloc_x(sizeof(*mci));
4707c478bd9Sstevel@tonic-gate else
471058561cbSjbeck mci = (MCI *) sm_rpool_malloc_x(rpool, sizeof(*mci));
472058561cbSjbeck memset((char *) mci, '\0', sizeof(*mci));
4737c478bd9Sstevel@tonic-gate mci->mci_rpool = sm_rpool_new_x(NULL);
4747c478bd9Sstevel@tonic-gate mci->mci_macro.mac_rpool = mci->mci_rpool;
4757c478bd9Sstevel@tonic-gate return mci;
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate /*
4787c478bd9Sstevel@tonic-gate ** MCI_MATCH -- check connection cache for a particular host
4797c478bd9Sstevel@tonic-gate **
4807c478bd9Sstevel@tonic-gate ** Parameters:
4817c478bd9Sstevel@tonic-gate ** host -- host to look for.
4827c478bd9Sstevel@tonic-gate ** m -- mailer.
4837c478bd9Sstevel@tonic-gate **
4847c478bd9Sstevel@tonic-gate ** Returns:
4857c478bd9Sstevel@tonic-gate ** true iff open connection exists.
4867c478bd9Sstevel@tonic-gate */
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate bool
mci_match(host,m)4897c478bd9Sstevel@tonic-gate mci_match(host, m)
4907c478bd9Sstevel@tonic-gate char *host;
4917c478bd9Sstevel@tonic-gate MAILER *m;
4927c478bd9Sstevel@tonic-gate {
4937c478bd9Sstevel@tonic-gate register MCI *mci;
4947c478bd9Sstevel@tonic-gate register STAB *s;
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate if (m->m_mno < 0 || m->m_mno > MAXMAILERS)
4977c478bd9Sstevel@tonic-gate return false;
4987c478bd9Sstevel@tonic-gate s = stab(host, ST_MCI + m->m_mno, ST_FIND);
4997c478bd9Sstevel@tonic-gate if (s == NULL)
5007c478bd9Sstevel@tonic-gate return false;
5017c478bd9Sstevel@tonic-gate
5027c478bd9Sstevel@tonic-gate mci = &s->s_mci;
5037c478bd9Sstevel@tonic-gate return mci->mci_state == MCIS_OPEN;
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate /*
5067c478bd9Sstevel@tonic-gate ** MCI_SETSTAT -- set status codes in MCI structure.
5077c478bd9Sstevel@tonic-gate **
5087c478bd9Sstevel@tonic-gate ** Parameters:
5097c478bd9Sstevel@tonic-gate ** mci -- the MCI structure to set.
5107c478bd9Sstevel@tonic-gate ** xstat -- the exit status code.
5117c478bd9Sstevel@tonic-gate ** dstat -- the DSN status code.
5127c478bd9Sstevel@tonic-gate ** rstat -- the SMTP status code.
5137c478bd9Sstevel@tonic-gate **
5147c478bd9Sstevel@tonic-gate ** Returns:
5157c478bd9Sstevel@tonic-gate ** none.
5167c478bd9Sstevel@tonic-gate */
5177c478bd9Sstevel@tonic-gate
5187c478bd9Sstevel@tonic-gate void
mci_setstat(mci,xstat,dstat,rstat)5197c478bd9Sstevel@tonic-gate mci_setstat(mci, xstat, dstat, rstat)
5207c478bd9Sstevel@tonic-gate MCI *mci;
5217c478bd9Sstevel@tonic-gate int xstat;
5227c478bd9Sstevel@tonic-gate char *dstat;
5237c478bd9Sstevel@tonic-gate char *rstat;
5247c478bd9Sstevel@tonic-gate {
5257c478bd9Sstevel@tonic-gate /* protocol errors should never be interpreted as sticky */
5267c478bd9Sstevel@tonic-gate if (xstat != EX_NOTSTICKY && xstat != EX_PROTOCOL)
5277c478bd9Sstevel@tonic-gate mci->mci_exitstat = xstat;
5287c478bd9Sstevel@tonic-gate
5297c478bd9Sstevel@tonic-gate SM_FREE_CLR(mci->mci_status);
5307c478bd9Sstevel@tonic-gate if (dstat != NULL)
5317c478bd9Sstevel@tonic-gate mci->mci_status = sm_strdup_x(dstat);
5327c478bd9Sstevel@tonic-gate
5337c478bd9Sstevel@tonic-gate SM_FREE_CLR(mci->mci_rstatus);
5347c478bd9Sstevel@tonic-gate if (rstat != NULL)
5357c478bd9Sstevel@tonic-gate mci->mci_rstatus = sm_strdup_x(rstat);
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate /*
5387c478bd9Sstevel@tonic-gate ** MCI_DUMP -- dump the contents of an MCI structure.
5397c478bd9Sstevel@tonic-gate **
5407c478bd9Sstevel@tonic-gate ** Parameters:
5417c478bd9Sstevel@tonic-gate ** fp -- output file pointer
5427c478bd9Sstevel@tonic-gate ** mci -- the MCI structure to dump.
5437c478bd9Sstevel@tonic-gate **
5447c478bd9Sstevel@tonic-gate ** Returns:
5457c478bd9Sstevel@tonic-gate ** none.
5467c478bd9Sstevel@tonic-gate **
5477c478bd9Sstevel@tonic-gate ** Side Effects:
5487c478bd9Sstevel@tonic-gate ** none.
5497c478bd9Sstevel@tonic-gate */
5507c478bd9Sstevel@tonic-gate
5517c478bd9Sstevel@tonic-gate struct mcifbits
5527c478bd9Sstevel@tonic-gate {
5537c478bd9Sstevel@tonic-gate int mcif_bit; /* flag bit */
5547c478bd9Sstevel@tonic-gate char *mcif_name; /* flag name */
5557c478bd9Sstevel@tonic-gate };
5567c478bd9Sstevel@tonic-gate static struct mcifbits MciFlags[] =
5577c478bd9Sstevel@tonic-gate {
5587c478bd9Sstevel@tonic-gate { MCIF_VALID, "VALID" },
5597c478bd9Sstevel@tonic-gate { MCIF_CACHED, "CACHED" },
5607c478bd9Sstevel@tonic-gate { MCIF_ESMTP, "ESMTP" },
5617c478bd9Sstevel@tonic-gate { MCIF_EXPN, "EXPN" },
5627c478bd9Sstevel@tonic-gate { MCIF_SIZE, "SIZE" },
5637c478bd9Sstevel@tonic-gate { MCIF_8BITMIME, "8BITMIME" },
5647c478bd9Sstevel@tonic-gate { MCIF_7BIT, "7BIT" },
5657c478bd9Sstevel@tonic-gate { MCIF_INHEADER, "INHEADER" },
5667c478bd9Sstevel@tonic-gate { MCIF_CVT8TO7, "CVT8TO7" },
5677c478bd9Sstevel@tonic-gate { MCIF_DSN, "DSN" },
5687c478bd9Sstevel@tonic-gate { MCIF_8BITOK, "8BITOK" },
5697c478bd9Sstevel@tonic-gate { MCIF_CVT7TO8, "CVT7TO8" },
5707c478bd9Sstevel@tonic-gate { MCIF_INMIME, "INMIME" },
5717c478bd9Sstevel@tonic-gate { MCIF_AUTH, "AUTH" },
5727c478bd9Sstevel@tonic-gate { MCIF_AUTHACT, "AUTHACT" },
5737c478bd9Sstevel@tonic-gate { MCIF_ENHSTAT, "ENHSTAT" },
5747c478bd9Sstevel@tonic-gate { MCIF_PIPELINED, "PIPELINED" },
5757c478bd9Sstevel@tonic-gate #if STARTTLS
5767c478bd9Sstevel@tonic-gate { MCIF_TLS, "TLS" },
5777c478bd9Sstevel@tonic-gate { MCIF_TLSACT, "TLSACT" },
5787c478bd9Sstevel@tonic-gate #endif /* STARTTLS */
5797c478bd9Sstevel@tonic-gate { MCIF_DLVR_BY, "DLVR_BY" },
5807c478bd9Sstevel@tonic-gate { 0, NULL }
5817c478bd9Sstevel@tonic-gate };
5827c478bd9Sstevel@tonic-gate
5837c478bd9Sstevel@tonic-gate void
mci_dump(fp,mci,logit)5847c478bd9Sstevel@tonic-gate mci_dump(fp, mci, logit)
5857c478bd9Sstevel@tonic-gate SM_FILE_T *fp;
5867c478bd9Sstevel@tonic-gate register MCI *mci;
5877c478bd9Sstevel@tonic-gate bool logit;
5887c478bd9Sstevel@tonic-gate {
5897c478bd9Sstevel@tonic-gate register char *p;
5907c478bd9Sstevel@tonic-gate char *sep;
5917c478bd9Sstevel@tonic-gate char buf[4000];
5927c478bd9Sstevel@tonic-gate
5937c478bd9Sstevel@tonic-gate sep = logit ? " " : "\n\t";
5947c478bd9Sstevel@tonic-gate p = buf;
5957c478bd9Sstevel@tonic-gate (void) sm_snprintf(p, SPACELEFT(buf, p), "MCI@%p: ", mci);
5967c478bd9Sstevel@tonic-gate p += strlen(p);
5977c478bd9Sstevel@tonic-gate if (mci == NULL)
5987c478bd9Sstevel@tonic-gate {
5997c478bd9Sstevel@tonic-gate (void) sm_snprintf(p, SPACELEFT(buf, p), "NULL");
6007c478bd9Sstevel@tonic-gate goto printit;
6017c478bd9Sstevel@tonic-gate }
6027c478bd9Sstevel@tonic-gate (void) sm_snprintf(p, SPACELEFT(buf, p), "flags=%lx", mci->mci_flags);
6037c478bd9Sstevel@tonic-gate p += strlen(p);
6047c478bd9Sstevel@tonic-gate
6057c478bd9Sstevel@tonic-gate /*
6067c478bd9Sstevel@tonic-gate ** The following check is just for paranoia. It protects the
6077c478bd9Sstevel@tonic-gate ** assignment in the if() clause. If there's not some minimum
6087c478bd9Sstevel@tonic-gate ** amount of space we can stop right now. The check will not
6097c478bd9Sstevel@tonic-gate ** trigger as long as sizeof(buf)=4000.
6107c478bd9Sstevel@tonic-gate */
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate if (p >= buf + sizeof(buf) - 4)
6137c478bd9Sstevel@tonic-gate goto printit;
6147c478bd9Sstevel@tonic-gate if (mci->mci_flags != 0)
6157c478bd9Sstevel@tonic-gate {
6167c478bd9Sstevel@tonic-gate struct mcifbits *f;
6177c478bd9Sstevel@tonic-gate
6187c478bd9Sstevel@tonic-gate *p++ = '<'; /* protected above */
6197c478bd9Sstevel@tonic-gate for (f = MciFlags; f->mcif_bit != 0; f++)
6207c478bd9Sstevel@tonic-gate {
6217c478bd9Sstevel@tonic-gate if (!bitset(f->mcif_bit, mci->mci_flags))
6227c478bd9Sstevel@tonic-gate continue;
6237c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(p, SPACELEFT(buf, p), 2,
6247c478bd9Sstevel@tonic-gate f->mcif_name, ",");
6257c478bd9Sstevel@tonic-gate p += strlen(p);
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate p[-1] = '>';
6287c478bd9Sstevel@tonic-gate }
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate /* Note: sm_snprintf() takes care of NULL arguments for %s */
6317c478bd9Sstevel@tonic-gate (void) sm_snprintf(p, SPACELEFT(buf, p),
6327c478bd9Sstevel@tonic-gate ",%serrno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s",
6337c478bd9Sstevel@tonic-gate sep, mci->mci_errno, mci->mci_herrno,
6347c478bd9Sstevel@tonic-gate mci->mci_exitstat, mci->mci_state, (int) mci->mci_pid, sep);
6357c478bd9Sstevel@tonic-gate p += strlen(p);
6367c478bd9Sstevel@tonic-gate (void) sm_snprintf(p, SPACELEFT(buf, p),
6377c478bd9Sstevel@tonic-gate "maxsize=%ld, phase=%s, mailer=%s,%s",
6387c478bd9Sstevel@tonic-gate mci->mci_maxsize, mci->mci_phase,
6397c478bd9Sstevel@tonic-gate mci->mci_mailer == NULL ? "NULL" : mci->mci_mailer->m_name,
6407c478bd9Sstevel@tonic-gate sep);
6417c478bd9Sstevel@tonic-gate p += strlen(p);
6427c478bd9Sstevel@tonic-gate (void) sm_snprintf(p, SPACELEFT(buf, p),
6437c478bd9Sstevel@tonic-gate "status=%s, rstatus=%s,%s",
6447c478bd9Sstevel@tonic-gate mci->mci_status, mci->mci_rstatus, sep);
6457c478bd9Sstevel@tonic-gate p += strlen(p);
6467c478bd9Sstevel@tonic-gate (void) sm_snprintf(p, SPACELEFT(buf, p),
6477c478bd9Sstevel@tonic-gate "host=%s, lastuse=%s",
6487c478bd9Sstevel@tonic-gate mci->mci_host, ctime(&mci->mci_lastuse));
6497c478bd9Sstevel@tonic-gate printit:
6507c478bd9Sstevel@tonic-gate if (logit)
6517c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "%.1000s", buf);
6527c478bd9Sstevel@tonic-gate else
6537c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s\n", buf);
6547c478bd9Sstevel@tonic-gate }
6557c478bd9Sstevel@tonic-gate /*
6567c478bd9Sstevel@tonic-gate ** MCI_DUMP_ALL -- print the entire MCI cache
6577c478bd9Sstevel@tonic-gate **
6587c478bd9Sstevel@tonic-gate ** Parameters:
6597c478bd9Sstevel@tonic-gate ** fp -- output file pointer
6607c478bd9Sstevel@tonic-gate ** logit -- if set, log the result instead of printing
6617c478bd9Sstevel@tonic-gate ** to stdout.
6627c478bd9Sstevel@tonic-gate **
6637c478bd9Sstevel@tonic-gate ** Returns:
6647c478bd9Sstevel@tonic-gate ** none.
6657c478bd9Sstevel@tonic-gate */
6667c478bd9Sstevel@tonic-gate
6677c478bd9Sstevel@tonic-gate void
mci_dump_all(fp,logit)6687c478bd9Sstevel@tonic-gate mci_dump_all(fp, logit)
6697c478bd9Sstevel@tonic-gate SM_FILE_T *fp;
6707c478bd9Sstevel@tonic-gate bool logit;
6717c478bd9Sstevel@tonic-gate {
6727c478bd9Sstevel@tonic-gate register int i;
6737c478bd9Sstevel@tonic-gate
6747c478bd9Sstevel@tonic-gate if (MciCache == NULL)
6757c478bd9Sstevel@tonic-gate return;
6767c478bd9Sstevel@tonic-gate
6777c478bd9Sstevel@tonic-gate for (i = 0; i < MaxMciCache; i++)
6787c478bd9Sstevel@tonic-gate mci_dump(fp, MciCache[i], logit);
6797c478bd9Sstevel@tonic-gate }
6807c478bd9Sstevel@tonic-gate /*
6817c478bd9Sstevel@tonic-gate ** MCI_LOCK_HOST -- Lock host while sending.
6827c478bd9Sstevel@tonic-gate **
6837c478bd9Sstevel@tonic-gate ** If we are contacting a host, we'll need to
6847c478bd9Sstevel@tonic-gate ** update the status information in the host status
6857c478bd9Sstevel@tonic-gate ** file, and if we want to do that, we ought to have
6867c478bd9Sstevel@tonic-gate ** locked it. This has the (according to some)
6877c478bd9Sstevel@tonic-gate ** desirable effect of serializing connectivity with
6887c478bd9Sstevel@tonic-gate ** remote hosts -- i.e.: one connection to a given
6897c478bd9Sstevel@tonic-gate ** host at a time.
6907c478bd9Sstevel@tonic-gate **
6917c478bd9Sstevel@tonic-gate ** Parameters:
6927c478bd9Sstevel@tonic-gate ** mci -- containing the host we want to lock.
6937c478bd9Sstevel@tonic-gate **
6947c478bd9Sstevel@tonic-gate ** Returns:
6957c478bd9Sstevel@tonic-gate ** EX_OK -- got the lock.
6967c478bd9Sstevel@tonic-gate ** EX_TEMPFAIL -- didn't get the lock.
6977c478bd9Sstevel@tonic-gate */
6987c478bd9Sstevel@tonic-gate
6997c478bd9Sstevel@tonic-gate int
mci_lock_host(mci)7007c478bd9Sstevel@tonic-gate mci_lock_host(mci)
7017c478bd9Sstevel@tonic-gate MCI *mci;
7027c478bd9Sstevel@tonic-gate {
7037c478bd9Sstevel@tonic-gate if (mci == NULL)
7047c478bd9Sstevel@tonic-gate {
7057c478bd9Sstevel@tonic-gate if (tTd(56, 1))
7067c478bd9Sstevel@tonic-gate sm_dprintf("mci_lock_host: NULL mci\n");
7077c478bd9Sstevel@tonic-gate return EX_OK;
7087c478bd9Sstevel@tonic-gate }
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate if (!SingleThreadDelivery)
7117c478bd9Sstevel@tonic-gate return EX_OK;
7127c478bd9Sstevel@tonic-gate
7137c478bd9Sstevel@tonic-gate return mci_lock_host_statfile(mci);
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate
7167c478bd9Sstevel@tonic-gate static int
mci_lock_host_statfile(mci)7177c478bd9Sstevel@tonic-gate mci_lock_host_statfile(mci)
7187c478bd9Sstevel@tonic-gate MCI *mci;
7197c478bd9Sstevel@tonic-gate {
7207c478bd9Sstevel@tonic-gate int save_errno = errno;
7217c478bd9Sstevel@tonic-gate int retVal = EX_OK;
7227c478bd9Sstevel@tonic-gate char fname[MAXPATHLEN];
7237c478bd9Sstevel@tonic-gate
7247c478bd9Sstevel@tonic-gate if (HostStatDir == NULL || mci->mci_host == NULL)
7257c478bd9Sstevel@tonic-gate return EX_OK;
7267c478bd9Sstevel@tonic-gate
7277c478bd9Sstevel@tonic-gate if (tTd(56, 2))
7287c478bd9Sstevel@tonic-gate sm_dprintf("mci_lock_host: attempting to lock %s\n",
7297c478bd9Sstevel@tonic-gate mci->mci_host);
7307c478bd9Sstevel@tonic-gate
731058561cbSjbeck if (mci_generate_persistent_path(mci->mci_host, fname, sizeof(fname),
7327c478bd9Sstevel@tonic-gate true) < 0)
7337c478bd9Sstevel@tonic-gate {
7347c478bd9Sstevel@tonic-gate /* of course this should never happen */
7357c478bd9Sstevel@tonic-gate if (tTd(56, 2))
7367c478bd9Sstevel@tonic-gate sm_dprintf("mci_lock_host: Failed to generate host path for %s\n",
7377c478bd9Sstevel@tonic-gate mci->mci_host);
7387c478bd9Sstevel@tonic-gate
7397c478bd9Sstevel@tonic-gate retVal = EX_TEMPFAIL;
7407c478bd9Sstevel@tonic-gate goto cleanup;
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate mci->mci_statfile = safefopen(fname, O_RDWR, FileMode,
7447c478bd9Sstevel@tonic-gate SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH|SFF_CREAT);
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate if (mci->mci_statfile == NULL)
7477c478bd9Sstevel@tonic-gate {
7487c478bd9Sstevel@tonic-gate syserr("mci_lock_host: cannot create host lock file %s", fname);
7497c478bd9Sstevel@tonic-gate goto cleanup;
7507c478bd9Sstevel@tonic-gate }
7517c478bd9Sstevel@tonic-gate
7527c478bd9Sstevel@tonic-gate if (!lockfile(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL),
7537c478bd9Sstevel@tonic-gate fname, "", LOCK_EX|LOCK_NB))
7547c478bd9Sstevel@tonic-gate {
7557c478bd9Sstevel@tonic-gate if (tTd(56, 2))
7567c478bd9Sstevel@tonic-gate sm_dprintf("mci_lock_host: couldn't get lock on %s\n",
7577c478bd9Sstevel@tonic-gate fname);
7587c478bd9Sstevel@tonic-gate (void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT);
7597c478bd9Sstevel@tonic-gate mci->mci_statfile = NULL;
7607c478bd9Sstevel@tonic-gate retVal = EX_TEMPFAIL;
7617c478bd9Sstevel@tonic-gate goto cleanup;
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate
7647c478bd9Sstevel@tonic-gate if (tTd(56, 12) && mci->mci_statfile != NULL)
7657c478bd9Sstevel@tonic-gate sm_dprintf("mci_lock_host: Sanity check -- lock is good\n");
7667c478bd9Sstevel@tonic-gate
7677c478bd9Sstevel@tonic-gate cleanup:
7687c478bd9Sstevel@tonic-gate errno = save_errno;
7697c478bd9Sstevel@tonic-gate return retVal;
7707c478bd9Sstevel@tonic-gate }
7717c478bd9Sstevel@tonic-gate /*
7727c478bd9Sstevel@tonic-gate ** MCI_UNLOCK_HOST -- unlock host
7737c478bd9Sstevel@tonic-gate **
7747c478bd9Sstevel@tonic-gate ** Clean up the lock on a host, close the file, let
7757c478bd9Sstevel@tonic-gate ** someone else use it.
7767c478bd9Sstevel@tonic-gate **
7777c478bd9Sstevel@tonic-gate ** Parameters:
7787c478bd9Sstevel@tonic-gate ** mci -- us.
7797c478bd9Sstevel@tonic-gate **
7807c478bd9Sstevel@tonic-gate ** Returns:
7817c478bd9Sstevel@tonic-gate ** nothing.
7827c478bd9Sstevel@tonic-gate */
7837c478bd9Sstevel@tonic-gate
7847c478bd9Sstevel@tonic-gate void
mci_unlock_host(mci)7857c478bd9Sstevel@tonic-gate mci_unlock_host(mci)
7867c478bd9Sstevel@tonic-gate MCI *mci;
7877c478bd9Sstevel@tonic-gate {
7887c478bd9Sstevel@tonic-gate int save_errno = errno;
7897c478bd9Sstevel@tonic-gate
7907c478bd9Sstevel@tonic-gate if (mci == NULL)
7917c478bd9Sstevel@tonic-gate {
7927c478bd9Sstevel@tonic-gate if (tTd(56, 1))
7937c478bd9Sstevel@tonic-gate sm_dprintf("mci_unlock_host: NULL mci\n");
7947c478bd9Sstevel@tonic-gate return;
7957c478bd9Sstevel@tonic-gate }
7967c478bd9Sstevel@tonic-gate
7977c478bd9Sstevel@tonic-gate if (HostStatDir == NULL || mci->mci_host == NULL)
7987c478bd9Sstevel@tonic-gate return;
7997c478bd9Sstevel@tonic-gate
8007c478bd9Sstevel@tonic-gate if (!SingleThreadDelivery && mci_lock_host_statfile(mci) == EX_TEMPFAIL)
8017c478bd9Sstevel@tonic-gate {
8027c478bd9Sstevel@tonic-gate if (tTd(56, 1))
8037c478bd9Sstevel@tonic-gate sm_dprintf("mci_unlock_host: stat file already locked\n");
8047c478bd9Sstevel@tonic-gate }
8057c478bd9Sstevel@tonic-gate else
8067c478bd9Sstevel@tonic-gate {
8077c478bd9Sstevel@tonic-gate if (tTd(56, 2))
8087c478bd9Sstevel@tonic-gate sm_dprintf("mci_unlock_host: store prior to unlock\n");
8097c478bd9Sstevel@tonic-gate mci_store_persistent(mci);
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate
8127c478bd9Sstevel@tonic-gate if (mci->mci_statfile != NULL)
8137c478bd9Sstevel@tonic-gate {
8147c478bd9Sstevel@tonic-gate (void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT);
8157c478bd9Sstevel@tonic-gate mci->mci_statfile = NULL;
8167c478bd9Sstevel@tonic-gate }
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate errno = save_errno;
8197c478bd9Sstevel@tonic-gate }
8207c478bd9Sstevel@tonic-gate /*
8217c478bd9Sstevel@tonic-gate ** MCI_LOAD_PERSISTENT -- load persistent host info
8227c478bd9Sstevel@tonic-gate **
8237c478bd9Sstevel@tonic-gate ** Load information about host that is kept
8247c478bd9Sstevel@tonic-gate ** in common for all running sendmails.
8257c478bd9Sstevel@tonic-gate **
8267c478bd9Sstevel@tonic-gate ** Parameters:
8277c478bd9Sstevel@tonic-gate ** mci -- the host/connection to load persistent info for.
8287c478bd9Sstevel@tonic-gate **
8297c478bd9Sstevel@tonic-gate ** Returns:
8307c478bd9Sstevel@tonic-gate ** true -- lock was successful
8317c478bd9Sstevel@tonic-gate ** false -- lock failed
8327c478bd9Sstevel@tonic-gate */
8337c478bd9Sstevel@tonic-gate
8347c478bd9Sstevel@tonic-gate static bool
mci_load_persistent(mci)8357c478bd9Sstevel@tonic-gate mci_load_persistent(mci)
8367c478bd9Sstevel@tonic-gate MCI *mci;
8377c478bd9Sstevel@tonic-gate {
8387c478bd9Sstevel@tonic-gate int save_errno = errno;
8397c478bd9Sstevel@tonic-gate bool locked = true;
8407c478bd9Sstevel@tonic-gate SM_FILE_T *fp;
8417c478bd9Sstevel@tonic-gate char fname[MAXPATHLEN];
8427c478bd9Sstevel@tonic-gate
8437c478bd9Sstevel@tonic-gate if (mci == NULL)
8447c478bd9Sstevel@tonic-gate {
8457c478bd9Sstevel@tonic-gate if (tTd(56, 1))
8467c478bd9Sstevel@tonic-gate sm_dprintf("mci_load_persistent: NULL mci\n");
8477c478bd9Sstevel@tonic-gate return true;
8487c478bd9Sstevel@tonic-gate }
8497c478bd9Sstevel@tonic-gate
8507c478bd9Sstevel@tonic-gate if (IgnoreHostStatus || HostStatDir == NULL || mci->mci_host == NULL)
8517c478bd9Sstevel@tonic-gate return true;
8527c478bd9Sstevel@tonic-gate
8537c478bd9Sstevel@tonic-gate /* Already have the persistent information in memory */
8547c478bd9Sstevel@tonic-gate if (SingleThreadDelivery && mci->mci_statfile != NULL)
8557c478bd9Sstevel@tonic-gate return true;
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate if (tTd(56, 1))
8587c478bd9Sstevel@tonic-gate sm_dprintf("mci_load_persistent: Attempting to load persistent information for %s\n",
8597c478bd9Sstevel@tonic-gate mci->mci_host);
8607c478bd9Sstevel@tonic-gate
861058561cbSjbeck if (mci_generate_persistent_path(mci->mci_host, fname, sizeof(fname),
8627c478bd9Sstevel@tonic-gate false) < 0)
8637c478bd9Sstevel@tonic-gate {
8647c478bd9Sstevel@tonic-gate /* Not much we can do if the file isn't there... */
8657c478bd9Sstevel@tonic-gate if (tTd(56, 1))
8667c478bd9Sstevel@tonic-gate sm_dprintf("mci_load_persistent: Couldn't generate host path\n");
8677c478bd9Sstevel@tonic-gate goto cleanup;
8687c478bd9Sstevel@tonic-gate }
8697c478bd9Sstevel@tonic-gate
8707c478bd9Sstevel@tonic-gate fp = safefopen(fname, O_RDONLY, FileMode,
8717c478bd9Sstevel@tonic-gate SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH);
8727c478bd9Sstevel@tonic-gate if (fp == NULL)
8737c478bd9Sstevel@tonic-gate {
8747c478bd9Sstevel@tonic-gate /* I can't think of any reason this should ever happen */
8757c478bd9Sstevel@tonic-gate if (tTd(56, 1))
8767c478bd9Sstevel@tonic-gate sm_dprintf("mci_load_persistent: open(%s): %s\n",
8777c478bd9Sstevel@tonic-gate fname, sm_errstring(errno));
8787c478bd9Sstevel@tonic-gate goto cleanup;
8797c478bd9Sstevel@tonic-gate }
8807c478bd9Sstevel@tonic-gate
8817c478bd9Sstevel@tonic-gate FileName = fname;
8827c478bd9Sstevel@tonic-gate locked = lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname, "",
8837c478bd9Sstevel@tonic-gate LOCK_SH|LOCK_NB);
8847c478bd9Sstevel@tonic-gate if (locked)
8857c478bd9Sstevel@tonic-gate {
8867c478bd9Sstevel@tonic-gate (void) mci_read_persistent(fp, mci);
8877c478bd9Sstevel@tonic-gate (void) lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname,
8887c478bd9Sstevel@tonic-gate "", LOCK_UN);
8897c478bd9Sstevel@tonic-gate }
8907c478bd9Sstevel@tonic-gate FileName = NULL;
8917c478bd9Sstevel@tonic-gate (void) sm_io_close(fp, SM_TIME_DEFAULT);
8927c478bd9Sstevel@tonic-gate
8937c478bd9Sstevel@tonic-gate cleanup:
8947c478bd9Sstevel@tonic-gate errno = save_errno;
8957c478bd9Sstevel@tonic-gate return locked;
8967c478bd9Sstevel@tonic-gate }
8977c478bd9Sstevel@tonic-gate /*
8987c478bd9Sstevel@tonic-gate ** MCI_READ_PERSISTENT -- read persistent host status file
8997c478bd9Sstevel@tonic-gate **
9007c478bd9Sstevel@tonic-gate ** Parameters:
9017c478bd9Sstevel@tonic-gate ** fp -- the file pointer to read.
9027c478bd9Sstevel@tonic-gate ** mci -- the pointer to fill in.
9037c478bd9Sstevel@tonic-gate **
9047c478bd9Sstevel@tonic-gate ** Returns:
9057c478bd9Sstevel@tonic-gate ** -1 -- if the file was corrupt.
9067c478bd9Sstevel@tonic-gate ** 0 -- otherwise.
9077c478bd9Sstevel@tonic-gate **
9087c478bd9Sstevel@tonic-gate ** Warning:
9097c478bd9Sstevel@tonic-gate ** This code makes the assumption that this data
9107c478bd9Sstevel@tonic-gate ** will be read in an atomic fashion, and that the data
9117c478bd9Sstevel@tonic-gate ** was written in an atomic fashion. Any other functioning
9127c478bd9Sstevel@tonic-gate ** may lead to some form of insanity. This should be
9137c478bd9Sstevel@tonic-gate ** perfectly safe due to underlying stdio buffering.
9147c478bd9Sstevel@tonic-gate */
9157c478bd9Sstevel@tonic-gate
9167c478bd9Sstevel@tonic-gate static int
mci_read_persistent(fp,mci)9177c478bd9Sstevel@tonic-gate mci_read_persistent(fp, mci)
9187c478bd9Sstevel@tonic-gate SM_FILE_T *fp;
9197c478bd9Sstevel@tonic-gate register MCI *mci;
9207c478bd9Sstevel@tonic-gate {
9217c478bd9Sstevel@tonic-gate int ver;
9227c478bd9Sstevel@tonic-gate register char *p;
9237c478bd9Sstevel@tonic-gate int saveLineNumber = LineNumber;
9247c478bd9Sstevel@tonic-gate char buf[MAXLINE];
9257c478bd9Sstevel@tonic-gate
9267c478bd9Sstevel@tonic-gate if (fp == NULL)
9273ee0e492Sjbeck {
9287c478bd9Sstevel@tonic-gate syserr("mci_read_persistent: NULL fp");
9293ee0e492Sjbeck /* NOTREACHED */
9303ee0e492Sjbeck return -1;
9313ee0e492Sjbeck }
9327c478bd9Sstevel@tonic-gate if (mci == NULL)
9333ee0e492Sjbeck {
9347c478bd9Sstevel@tonic-gate syserr("mci_read_persistent: NULL mci");
9353ee0e492Sjbeck /* NOTREACHED */
9363ee0e492Sjbeck return -1;
9373ee0e492Sjbeck }
9387c478bd9Sstevel@tonic-gate if (tTd(56, 93))
9397c478bd9Sstevel@tonic-gate {
9407c478bd9Sstevel@tonic-gate sm_dprintf("mci_read_persistent: fp=%lx, mci=",
9417c478bd9Sstevel@tonic-gate (unsigned long) fp);
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate
9447c478bd9Sstevel@tonic-gate SM_FREE_CLR(mci->mci_status);
9457c478bd9Sstevel@tonic-gate SM_FREE_CLR(mci->mci_rstatus);
9467c478bd9Sstevel@tonic-gate
9477c478bd9Sstevel@tonic-gate sm_io_rewind(fp, SM_TIME_DEFAULT);
9487c478bd9Sstevel@tonic-gate ver = -1;
9497c478bd9Sstevel@tonic-gate LineNumber = 0;
950058561cbSjbeck while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
9517c478bd9Sstevel@tonic-gate {
9527c478bd9Sstevel@tonic-gate LineNumber++;
9537c478bd9Sstevel@tonic-gate p = strchr(buf, '\n');
9547c478bd9Sstevel@tonic-gate if (p != NULL)
9557c478bd9Sstevel@tonic-gate *p = '\0';
9567c478bd9Sstevel@tonic-gate switch (buf[0])
9577c478bd9Sstevel@tonic-gate {
9587c478bd9Sstevel@tonic-gate case 'V': /* version stamp */
9597c478bd9Sstevel@tonic-gate ver = atoi(&buf[1]);
9607c478bd9Sstevel@tonic-gate if (ver < 0 || ver > 0)
9617c478bd9Sstevel@tonic-gate syserr("Unknown host status version %d: %d max",
9627c478bd9Sstevel@tonic-gate ver, 0);
9637c478bd9Sstevel@tonic-gate break;
9647c478bd9Sstevel@tonic-gate
9657c478bd9Sstevel@tonic-gate case 'E': /* UNIX error number */
9667c478bd9Sstevel@tonic-gate mci->mci_errno = atoi(&buf[1]);
9677c478bd9Sstevel@tonic-gate break;
9687c478bd9Sstevel@tonic-gate
9697c478bd9Sstevel@tonic-gate case 'H': /* DNS error number */
9707c478bd9Sstevel@tonic-gate mci->mci_herrno = atoi(&buf[1]);
9717c478bd9Sstevel@tonic-gate break;
9727c478bd9Sstevel@tonic-gate
9737c478bd9Sstevel@tonic-gate case 'S': /* UNIX exit status */
9747c478bd9Sstevel@tonic-gate mci->mci_exitstat = atoi(&buf[1]);
9757c478bd9Sstevel@tonic-gate break;
9767c478bd9Sstevel@tonic-gate
9777c478bd9Sstevel@tonic-gate case 'D': /* DSN status */
9787c478bd9Sstevel@tonic-gate mci->mci_status = newstr(&buf[1]);
9797c478bd9Sstevel@tonic-gate break;
9807c478bd9Sstevel@tonic-gate
9817c478bd9Sstevel@tonic-gate case 'R': /* SMTP status */
9827c478bd9Sstevel@tonic-gate mci->mci_rstatus = newstr(&buf[1]);
9837c478bd9Sstevel@tonic-gate break;
9847c478bd9Sstevel@tonic-gate
9857c478bd9Sstevel@tonic-gate case 'U': /* last usage time */
9867c478bd9Sstevel@tonic-gate mci->mci_lastuse = atol(&buf[1]);
9877c478bd9Sstevel@tonic-gate break;
9887c478bd9Sstevel@tonic-gate
9897c478bd9Sstevel@tonic-gate case '.': /* end of file */
9907c478bd9Sstevel@tonic-gate if (tTd(56, 93))
9917c478bd9Sstevel@tonic-gate mci_dump(sm_debug_file(), mci, false);
9927c478bd9Sstevel@tonic-gate return 0;
9937c478bd9Sstevel@tonic-gate
9947c478bd9Sstevel@tonic-gate default:
9957c478bd9Sstevel@tonic-gate sm_syslog(LOG_CRIT, NOQID,
9967c478bd9Sstevel@tonic-gate "%s: line %d: Unknown host status line \"%s\"",
9977c478bd9Sstevel@tonic-gate FileName == NULL ? mci->mci_host : FileName,
9987c478bd9Sstevel@tonic-gate LineNumber, buf);
9997c478bd9Sstevel@tonic-gate LineNumber = saveLineNumber;
10007c478bd9Sstevel@tonic-gate return -1;
10017c478bd9Sstevel@tonic-gate }
10027c478bd9Sstevel@tonic-gate }
10037c478bd9Sstevel@tonic-gate LineNumber = saveLineNumber;
10047c478bd9Sstevel@tonic-gate if (tTd(56, 93))
10057c478bd9Sstevel@tonic-gate sm_dprintf("incomplete (missing dot for EOF)\n");
10067c478bd9Sstevel@tonic-gate if (ver < 0)
10077c478bd9Sstevel@tonic-gate return -1;
10087c478bd9Sstevel@tonic-gate return 0;
10097c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate /*
10117c478bd9Sstevel@tonic-gate ** MCI_STORE_PERSISTENT -- Store persistent MCI information
10127c478bd9Sstevel@tonic-gate **
10137c478bd9Sstevel@tonic-gate ** Store information about host that is kept
10147c478bd9Sstevel@tonic-gate ** in common for all running sendmails.
10157c478bd9Sstevel@tonic-gate **
10167c478bd9Sstevel@tonic-gate ** Parameters:
10177c478bd9Sstevel@tonic-gate ** mci -- the host/connection to store persistent info for.
10187c478bd9Sstevel@tonic-gate **
10197c478bd9Sstevel@tonic-gate ** Returns:
10207c478bd9Sstevel@tonic-gate ** none.
10217c478bd9Sstevel@tonic-gate */
10227c478bd9Sstevel@tonic-gate
10237c478bd9Sstevel@tonic-gate void
mci_store_persistent(mci)10247c478bd9Sstevel@tonic-gate mci_store_persistent(mci)
10257c478bd9Sstevel@tonic-gate MCI *mci;
10267c478bd9Sstevel@tonic-gate {
10277c478bd9Sstevel@tonic-gate int save_errno = errno;
10287c478bd9Sstevel@tonic-gate
10297c478bd9Sstevel@tonic-gate if (mci == NULL)
10307c478bd9Sstevel@tonic-gate {
10317c478bd9Sstevel@tonic-gate if (tTd(56, 1))
10327c478bd9Sstevel@tonic-gate sm_dprintf("mci_store_persistent: NULL mci\n");
10337c478bd9Sstevel@tonic-gate return;
10347c478bd9Sstevel@tonic-gate }
10357c478bd9Sstevel@tonic-gate
10367c478bd9Sstevel@tonic-gate if (HostStatDir == NULL || mci->mci_host == NULL)
10377c478bd9Sstevel@tonic-gate return;
10387c478bd9Sstevel@tonic-gate
10397c478bd9Sstevel@tonic-gate if (tTd(56, 1))
10407c478bd9Sstevel@tonic-gate sm_dprintf("mci_store_persistent: Storing information for %s\n",
10417c478bd9Sstevel@tonic-gate mci->mci_host);
10427c478bd9Sstevel@tonic-gate
10437c478bd9Sstevel@tonic-gate if (mci->mci_statfile == NULL)
10447c478bd9Sstevel@tonic-gate {
10457c478bd9Sstevel@tonic-gate if (tTd(56, 1))
10467c478bd9Sstevel@tonic-gate sm_dprintf("mci_store_persistent: no statfile\n");
10477c478bd9Sstevel@tonic-gate return;
10487c478bd9Sstevel@tonic-gate }
10497c478bd9Sstevel@tonic-gate
10507c478bd9Sstevel@tonic-gate sm_io_rewind(mci->mci_statfile, SM_TIME_DEFAULT);
10517c478bd9Sstevel@tonic-gate #if !NOFTRUNCATE
10527c478bd9Sstevel@tonic-gate (void) ftruncate(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL),
10537c478bd9Sstevel@tonic-gate (off_t) 0);
10547c478bd9Sstevel@tonic-gate #endif /* !NOFTRUNCATE */
10557c478bd9Sstevel@tonic-gate
10567c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "V0\n");
10577c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "E%d\n",
10587c478bd9Sstevel@tonic-gate mci->mci_errno);
10597c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "H%d\n",
10607c478bd9Sstevel@tonic-gate mci->mci_herrno);
10617c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "S%d\n",
10627c478bd9Sstevel@tonic-gate mci->mci_exitstat);
10637c478bd9Sstevel@tonic-gate if (mci->mci_status != NULL)
10647c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT,
10657c478bd9Sstevel@tonic-gate "D%.80s\n",
10667c478bd9Sstevel@tonic-gate denlstring(mci->mci_status, true, false));
10677c478bd9Sstevel@tonic-gate if (mci->mci_rstatus != NULL)
10687c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT,
10697c478bd9Sstevel@tonic-gate "R%.80s\n",
10707c478bd9Sstevel@tonic-gate denlstring(mci->mci_rstatus, true, false));
10717c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "U%ld\n",
10727c478bd9Sstevel@tonic-gate (long)(mci->mci_lastuse));
10737c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, ".\n");
10747c478bd9Sstevel@tonic-gate
10757c478bd9Sstevel@tonic-gate (void) sm_io_flush(mci->mci_statfile, SM_TIME_DEFAULT);
10767c478bd9Sstevel@tonic-gate
10777c478bd9Sstevel@tonic-gate errno = save_errno;
10787c478bd9Sstevel@tonic-gate return;
10797c478bd9Sstevel@tonic-gate }
10807c478bd9Sstevel@tonic-gate /*
10817c478bd9Sstevel@tonic-gate ** MCI_TRAVERSE_PERSISTENT -- walk persistent status tree
10827c478bd9Sstevel@tonic-gate **
10837c478bd9Sstevel@tonic-gate ** Recursively find all the mci host files in `pathname'. Default to
10847c478bd9Sstevel@tonic-gate ** main host status directory if no path is provided.
10857c478bd9Sstevel@tonic-gate ** Call (*action)(pathname, host) for each file found.
10867c478bd9Sstevel@tonic-gate **
10877c478bd9Sstevel@tonic-gate ** Note: all information is collected in a list before it is processed.
10887c478bd9Sstevel@tonic-gate ** This may not be the best way to do it, but it seems safest, since
10897c478bd9Sstevel@tonic-gate ** the file system would be touched while we are attempting to traverse
10907c478bd9Sstevel@tonic-gate ** the directory tree otherwise (during purges).
10917c478bd9Sstevel@tonic-gate **
10927c478bd9Sstevel@tonic-gate ** Parameters:
10937c478bd9Sstevel@tonic-gate ** action -- function to call on each node. If returns < 0,
10947c478bd9Sstevel@tonic-gate ** return immediately.
10957c478bd9Sstevel@tonic-gate ** pathname -- root of tree. If null, use main host status
10967c478bd9Sstevel@tonic-gate ** directory.
10977c478bd9Sstevel@tonic-gate **
10987c478bd9Sstevel@tonic-gate ** Returns:
10997c478bd9Sstevel@tonic-gate ** < 0 -- if any action routine returns a negative value, that
11007c478bd9Sstevel@tonic-gate ** value is returned.
11017c478bd9Sstevel@tonic-gate ** 0 -- if we successfully went to completion.
11027c478bd9Sstevel@tonic-gate ** > 0 -- return status from action()
11037c478bd9Sstevel@tonic-gate */
11047c478bd9Sstevel@tonic-gate
11057c478bd9Sstevel@tonic-gate int
11067c478bd9Sstevel@tonic-gate mci_traverse_persistent(action, pathname)
11077c478bd9Sstevel@tonic-gate int (*action)__P((char *, char *));
11087c478bd9Sstevel@tonic-gate char *pathname;
11097c478bd9Sstevel@tonic-gate {
11107c478bd9Sstevel@tonic-gate struct stat statbuf;
11117c478bd9Sstevel@tonic-gate DIR *d;
11127c478bd9Sstevel@tonic-gate int ret;
11137c478bd9Sstevel@tonic-gate
11147c478bd9Sstevel@tonic-gate if (pathname == NULL)
11157c478bd9Sstevel@tonic-gate pathname = HostStatDir;
11167c478bd9Sstevel@tonic-gate if (pathname == NULL)
11177c478bd9Sstevel@tonic-gate return -1;
11187c478bd9Sstevel@tonic-gate
11197c478bd9Sstevel@tonic-gate if (tTd(56, 1))
11207c478bd9Sstevel@tonic-gate sm_dprintf("mci_traverse: pathname is %s\n", pathname);
11217c478bd9Sstevel@tonic-gate
11227c478bd9Sstevel@tonic-gate ret = stat(pathname, &statbuf);
11237c478bd9Sstevel@tonic-gate if (ret < 0)
11247c478bd9Sstevel@tonic-gate {
11257c478bd9Sstevel@tonic-gate if (tTd(56, 2))
11267c478bd9Sstevel@tonic-gate sm_dprintf("mci_traverse: Failed to stat %s: %s\n",
11277c478bd9Sstevel@tonic-gate pathname, sm_errstring(errno));
11287c478bd9Sstevel@tonic-gate return ret;
11297c478bd9Sstevel@tonic-gate }
11307c478bd9Sstevel@tonic-gate if (S_ISDIR(statbuf.st_mode))
11317c478bd9Sstevel@tonic-gate {
11327c478bd9Sstevel@tonic-gate bool leftone, removedone;
11337c478bd9Sstevel@tonic-gate size_t len;
11347c478bd9Sstevel@tonic-gate char *newptr;
11357c478bd9Sstevel@tonic-gate struct dirent *e;
11367c478bd9Sstevel@tonic-gate char newpath[MAXPATHLEN];
113749218d4fSjbeck #if MAXPATHLEN <= MAXNAMLEN - 3
113849218d4fSjbeck ERROR "MAXPATHLEN <= MAXNAMLEN - 3"
113949218d4fSjbeck #endif /* MAXPATHLEN <= MAXNAMLEN - 3 */
11407c478bd9Sstevel@tonic-gate
11417c478bd9Sstevel@tonic-gate if ((d = opendir(pathname)) == NULL)
11427c478bd9Sstevel@tonic-gate {
11437c478bd9Sstevel@tonic-gate if (tTd(56, 2))
11447c478bd9Sstevel@tonic-gate sm_dprintf("mci_traverse: opendir %s: %s\n",
11457c478bd9Sstevel@tonic-gate pathname, sm_errstring(errno));
11467c478bd9Sstevel@tonic-gate return -1;
11477c478bd9Sstevel@tonic-gate }
1148*d4660949Sjbeck
1149*d4660949Sjbeck /*
1150*d4660949Sjbeck ** Reserve space for trailing '/', at least one
1151*d4660949Sjbeck ** character, and '\0'
1152*d4660949Sjbeck */
1153*d4660949Sjbeck
1154*d4660949Sjbeck len = sizeof(newpath) - 3;
11557c478bd9Sstevel@tonic-gate if (sm_strlcpy(newpath, pathname, len) >= len)
11567c478bd9Sstevel@tonic-gate {
1157*d4660949Sjbeck int save_errno = errno;
1158*d4660949Sjbeck
11597c478bd9Sstevel@tonic-gate if (tTd(56, 2))
11607c478bd9Sstevel@tonic-gate sm_dprintf("mci_traverse: path \"%s\" too long",
11617c478bd9Sstevel@tonic-gate pathname);
1162*d4660949Sjbeck (void) closedir(d);
1163*d4660949Sjbeck errno = save_errno;
11647c478bd9Sstevel@tonic-gate return -1;
11657c478bd9Sstevel@tonic-gate }
11667c478bd9Sstevel@tonic-gate newptr = newpath + strlen(newpath);
11677c478bd9Sstevel@tonic-gate *newptr++ = '/';
1168*d4660949Sjbeck len = sizeof(newpath) - (newptr - newpath);
11697c478bd9Sstevel@tonic-gate
11707c478bd9Sstevel@tonic-gate /*
11717c478bd9Sstevel@tonic-gate ** repeat until no file has been removed
11727c478bd9Sstevel@tonic-gate ** this may become ugly when several files "expire"
11737c478bd9Sstevel@tonic-gate ** during these loops, but it's better than doing
11747c478bd9Sstevel@tonic-gate ** a rewinddir() inside the inner loop
11757c478bd9Sstevel@tonic-gate */
11767c478bd9Sstevel@tonic-gate
11777c478bd9Sstevel@tonic-gate do
11787c478bd9Sstevel@tonic-gate {
11797c478bd9Sstevel@tonic-gate leftone = removedone = false;
11807c478bd9Sstevel@tonic-gate while ((e = readdir(d)) != NULL)
11817c478bd9Sstevel@tonic-gate {
11827c478bd9Sstevel@tonic-gate if (e->d_name[0] == '.')
11837c478bd9Sstevel@tonic-gate continue;
11847c478bd9Sstevel@tonic-gate
1185*d4660949Sjbeck if (sm_strlcpy(newptr, e->d_name, len) >= len)
1186*d4660949Sjbeck {
1187*d4660949Sjbeck /* Skip truncated copies */
1188*d4660949Sjbeck if (tTd(56, 4))
1189*d4660949Sjbeck {
1190*d4660949Sjbeck *newptr = '\0';
1191*d4660949Sjbeck sm_dprintf("mci_traverse: path \"%s%s\" too long",
1192*d4660949Sjbeck newpath, e->d_name);
1193*d4660949Sjbeck }
1194*d4660949Sjbeck continue;
1195*d4660949Sjbeck }
11967c478bd9Sstevel@tonic-gate
11977c478bd9Sstevel@tonic-gate if (StopRequest)
11987c478bd9Sstevel@tonic-gate stop_sendmail();
11997c478bd9Sstevel@tonic-gate ret = mci_traverse_persistent(action, newpath);
12007c478bd9Sstevel@tonic-gate if (ret < 0)
12017c478bd9Sstevel@tonic-gate break;
12027c478bd9Sstevel@tonic-gate if (ret == 1)
12037c478bd9Sstevel@tonic-gate leftone = true;
12047c478bd9Sstevel@tonic-gate if (!removedone && ret == 0 &&
12057c478bd9Sstevel@tonic-gate action == mci_purge_persistent)
12067c478bd9Sstevel@tonic-gate removedone = true;
12077c478bd9Sstevel@tonic-gate }
12087c478bd9Sstevel@tonic-gate if (ret < 0)
12097c478bd9Sstevel@tonic-gate break;
12107c478bd9Sstevel@tonic-gate
12117c478bd9Sstevel@tonic-gate /*
12127c478bd9Sstevel@tonic-gate ** The following appears to be
12137c478bd9Sstevel@tonic-gate ** necessary during purges, since
12147c478bd9Sstevel@tonic-gate ** we modify the directory structure
12157c478bd9Sstevel@tonic-gate */
12167c478bd9Sstevel@tonic-gate
12177c478bd9Sstevel@tonic-gate if (removedone)
12187c478bd9Sstevel@tonic-gate rewinddir(d);
12197c478bd9Sstevel@tonic-gate if (tTd(56, 40))
12207c478bd9Sstevel@tonic-gate sm_dprintf("mci_traverse: path %s: ret %d removed %d left %d\n",
12217c478bd9Sstevel@tonic-gate pathname, ret, removedone, leftone);
12227c478bd9Sstevel@tonic-gate } while (removedone);
12237c478bd9Sstevel@tonic-gate
12247c478bd9Sstevel@tonic-gate /* purge (or whatever) the directory proper */
12257c478bd9Sstevel@tonic-gate if (!leftone)
12267c478bd9Sstevel@tonic-gate {
12277c478bd9Sstevel@tonic-gate *--newptr = '\0';
12287c478bd9Sstevel@tonic-gate ret = (*action)(newpath, NULL);
12297c478bd9Sstevel@tonic-gate }
12307c478bd9Sstevel@tonic-gate (void) closedir(d);
12317c478bd9Sstevel@tonic-gate }
12327c478bd9Sstevel@tonic-gate else if (S_ISREG(statbuf.st_mode))
12337c478bd9Sstevel@tonic-gate {
12347c478bd9Sstevel@tonic-gate char *end = pathname + strlen(pathname) - 1;
12357c478bd9Sstevel@tonic-gate char *start;
12367c478bd9Sstevel@tonic-gate char *scan;
12377c478bd9Sstevel@tonic-gate char host[MAXHOSTNAMELEN];
12387c478bd9Sstevel@tonic-gate char *hostptr = host;
12397c478bd9Sstevel@tonic-gate
12407c478bd9Sstevel@tonic-gate /*
12417c478bd9Sstevel@tonic-gate ** Reconstruct the host name from the path to the
12427c478bd9Sstevel@tonic-gate ** persistent information.
12437c478bd9Sstevel@tonic-gate */
12447c478bd9Sstevel@tonic-gate
12457c478bd9Sstevel@tonic-gate do
12467c478bd9Sstevel@tonic-gate {
12477c478bd9Sstevel@tonic-gate if (hostptr != host)
12487c478bd9Sstevel@tonic-gate *(hostptr++) = '.';
12497c478bd9Sstevel@tonic-gate start = end;
12507c478bd9Sstevel@tonic-gate while (start > pathname && *(start - 1) != '/')
12517c478bd9Sstevel@tonic-gate start--;
12527c478bd9Sstevel@tonic-gate
12537c478bd9Sstevel@tonic-gate if (*end == '.')
12547c478bd9Sstevel@tonic-gate end--;
12557c478bd9Sstevel@tonic-gate
12567c478bd9Sstevel@tonic-gate for (scan = start; scan <= end; scan++)
12577c478bd9Sstevel@tonic-gate *(hostptr++) = *scan;
12587c478bd9Sstevel@tonic-gate
12597c478bd9Sstevel@tonic-gate end = start - 2;
12607c478bd9Sstevel@tonic-gate } while (end > pathname && *end == '.');
12617c478bd9Sstevel@tonic-gate
12627c478bd9Sstevel@tonic-gate *hostptr = '\0';
12637c478bd9Sstevel@tonic-gate
12647c478bd9Sstevel@tonic-gate /*
12657c478bd9Sstevel@tonic-gate ** Do something with the file containing the persistent
12667c478bd9Sstevel@tonic-gate ** information.
12677c478bd9Sstevel@tonic-gate */
12687c478bd9Sstevel@tonic-gate
12697c478bd9Sstevel@tonic-gate ret = (*action)(pathname, host);
12707c478bd9Sstevel@tonic-gate }
12717c478bd9Sstevel@tonic-gate
12727c478bd9Sstevel@tonic-gate return ret;
12737c478bd9Sstevel@tonic-gate }
12747c478bd9Sstevel@tonic-gate /*
12757c478bd9Sstevel@tonic-gate ** MCI_PRINT_PERSISTENT -- print persistent info
12767c478bd9Sstevel@tonic-gate **
12777c478bd9Sstevel@tonic-gate ** Dump the persistent information in the file 'pathname'
12787c478bd9Sstevel@tonic-gate **
12797c478bd9Sstevel@tonic-gate ** Parameters:
12807c478bd9Sstevel@tonic-gate ** pathname -- the pathname to the status file.
12817c478bd9Sstevel@tonic-gate ** hostname -- the corresponding host name.
12827c478bd9Sstevel@tonic-gate **
12837c478bd9Sstevel@tonic-gate ** Returns:
12847c478bd9Sstevel@tonic-gate ** 0
12857c478bd9Sstevel@tonic-gate */
12867c478bd9Sstevel@tonic-gate
12877c478bd9Sstevel@tonic-gate int
mci_print_persistent(pathname,hostname)12887c478bd9Sstevel@tonic-gate mci_print_persistent(pathname, hostname)
12897c478bd9Sstevel@tonic-gate char *pathname;
12907c478bd9Sstevel@tonic-gate char *hostname;
12917c478bd9Sstevel@tonic-gate {
12927c478bd9Sstevel@tonic-gate static bool initflag = false;
12937c478bd9Sstevel@tonic-gate SM_FILE_T *fp;
12947c478bd9Sstevel@tonic-gate int width = Verbose ? 78 : 25;
12957c478bd9Sstevel@tonic-gate bool locked;
12967c478bd9Sstevel@tonic-gate MCI mcib;
12977c478bd9Sstevel@tonic-gate
12987c478bd9Sstevel@tonic-gate /* skip directories */
12997c478bd9Sstevel@tonic-gate if (hostname == NULL)
13007c478bd9Sstevel@tonic-gate return 0;
13017c478bd9Sstevel@tonic-gate
13027c478bd9Sstevel@tonic-gate if (StopRequest)
13037c478bd9Sstevel@tonic-gate stop_sendmail();
13047c478bd9Sstevel@tonic-gate
13057c478bd9Sstevel@tonic-gate if (!initflag)
13067c478bd9Sstevel@tonic-gate {
13077c478bd9Sstevel@tonic-gate initflag = true;
13087c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
13097c478bd9Sstevel@tonic-gate " -------------- Hostname --------------- How long ago ---------Results---------\n");
13107c478bd9Sstevel@tonic-gate }
13117c478bd9Sstevel@tonic-gate
13127c478bd9Sstevel@tonic-gate fp = safefopen(pathname, O_RDONLY, FileMode,
13137c478bd9Sstevel@tonic-gate SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH);
13147c478bd9Sstevel@tonic-gate
13157c478bd9Sstevel@tonic-gate if (fp == NULL)
13167c478bd9Sstevel@tonic-gate {
13177c478bd9Sstevel@tonic-gate if (tTd(56, 1))
13187c478bd9Sstevel@tonic-gate sm_dprintf("mci_print_persistent: cannot open %s: %s\n",
13197c478bd9Sstevel@tonic-gate pathname, sm_errstring(errno));
13207c478bd9Sstevel@tonic-gate return 0;
13217c478bd9Sstevel@tonic-gate }
13227c478bd9Sstevel@tonic-gate
13237c478bd9Sstevel@tonic-gate FileName = pathname;
1324058561cbSjbeck memset(&mcib, '\0', sizeof(mcib));
13257c478bd9Sstevel@tonic-gate if (mci_read_persistent(fp, &mcib) < 0)
13267c478bd9Sstevel@tonic-gate {
13277c478bd9Sstevel@tonic-gate syserr("%s: could not read status file", pathname);
13287c478bd9Sstevel@tonic-gate (void) sm_io_close(fp, SM_TIME_DEFAULT);
13297c478bd9Sstevel@tonic-gate FileName = NULL;
13307c478bd9Sstevel@tonic-gate return 0;
13317c478bd9Sstevel@tonic-gate }
13327c478bd9Sstevel@tonic-gate
13337c478bd9Sstevel@tonic-gate locked = !lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), pathname,
13347c478bd9Sstevel@tonic-gate "", LOCK_SH|LOCK_NB);
13357c478bd9Sstevel@tonic-gate (void) sm_io_close(fp, SM_TIME_DEFAULT);
13367c478bd9Sstevel@tonic-gate FileName = NULL;
13377c478bd9Sstevel@tonic-gate
13387c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%c%-39s %12s ",
13397c478bd9Sstevel@tonic-gate locked ? '*' : ' ', hostname,
13407c478bd9Sstevel@tonic-gate pintvl(curtime() - mcib.mci_lastuse, true));
13417c478bd9Sstevel@tonic-gate if (mcib.mci_rstatus != NULL)
13427c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", width,
13437c478bd9Sstevel@tonic-gate mcib.mci_rstatus);
13447c478bd9Sstevel@tonic-gate else if (mcib.mci_exitstat == EX_TEMPFAIL && mcib.mci_errno != 0)
13457c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
13467c478bd9Sstevel@tonic-gate "Deferred: %.*s\n", width - 10,
13477c478bd9Sstevel@tonic-gate sm_errstring(mcib.mci_errno));
13487c478bd9Sstevel@tonic-gate else if (mcib.mci_exitstat != 0)
13497c478bd9Sstevel@tonic-gate {
13507c478bd9Sstevel@tonic-gate char *exmsg = sm_sysexmsg(mcib.mci_exitstat);
13517c478bd9Sstevel@tonic-gate
13527c478bd9Sstevel@tonic-gate if (exmsg == NULL)
13537c478bd9Sstevel@tonic-gate {
13547c478bd9Sstevel@tonic-gate char buf[80];
13557c478bd9Sstevel@tonic-gate
1356058561cbSjbeck (void) sm_snprintf(buf, sizeof(buf),
13577c478bd9Sstevel@tonic-gate "Unknown mailer error %d",
13587c478bd9Sstevel@tonic-gate mcib.mci_exitstat);
13597c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n",
13607c478bd9Sstevel@tonic-gate width, buf);
13617c478bd9Sstevel@tonic-gate }
13627c478bd9Sstevel@tonic-gate else
13637c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n",
13647c478bd9Sstevel@tonic-gate width, &exmsg[5]);
13657c478bd9Sstevel@tonic-gate }
13667c478bd9Sstevel@tonic-gate else if (mcib.mci_errno == 0)
13677c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK\n");
13687c478bd9Sstevel@tonic-gate else
13697c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK: %.*s\n",
13707c478bd9Sstevel@tonic-gate width - 4, sm_errstring(mcib.mci_errno));
13717c478bd9Sstevel@tonic-gate
13727c478bd9Sstevel@tonic-gate return 0;
13737c478bd9Sstevel@tonic-gate }
13747c478bd9Sstevel@tonic-gate /*
13757c478bd9Sstevel@tonic-gate ** MCI_PURGE_PERSISTENT -- Remove a persistence status file.
13767c478bd9Sstevel@tonic-gate **
13777c478bd9Sstevel@tonic-gate ** Parameters:
13787c478bd9Sstevel@tonic-gate ** pathname -- path to the status file.
13797c478bd9Sstevel@tonic-gate ** hostname -- name of host corresponding to that file.
13807c478bd9Sstevel@tonic-gate ** NULL if this is a directory (domain).
13817c478bd9Sstevel@tonic-gate **
13827c478bd9Sstevel@tonic-gate ** Returns:
13837c478bd9Sstevel@tonic-gate ** 0 -- ok
13847c478bd9Sstevel@tonic-gate ** 1 -- file not deleted (too young, incorrect format)
13857c478bd9Sstevel@tonic-gate ** < 0 -- some error occurred
13867c478bd9Sstevel@tonic-gate */
13877c478bd9Sstevel@tonic-gate
13887c478bd9Sstevel@tonic-gate int
mci_purge_persistent(pathname,hostname)13897c478bd9Sstevel@tonic-gate mci_purge_persistent(pathname, hostname)
13907c478bd9Sstevel@tonic-gate char *pathname;
13917c478bd9Sstevel@tonic-gate char *hostname;
13927c478bd9Sstevel@tonic-gate {
13937c478bd9Sstevel@tonic-gate struct stat statbuf;
13947c478bd9Sstevel@tonic-gate char *end = pathname + strlen(pathname) - 1;
13957c478bd9Sstevel@tonic-gate int ret;
13967c478bd9Sstevel@tonic-gate
13977c478bd9Sstevel@tonic-gate if (tTd(56, 1))
13987c478bd9Sstevel@tonic-gate sm_dprintf("mci_purge_persistent: purging %s\n", pathname);
13997c478bd9Sstevel@tonic-gate
14007c478bd9Sstevel@tonic-gate ret = stat(pathname, &statbuf);
14017c478bd9Sstevel@tonic-gate if (ret < 0)
14027c478bd9Sstevel@tonic-gate {
14037c478bd9Sstevel@tonic-gate if (tTd(56, 2))
14047c478bd9Sstevel@tonic-gate sm_dprintf("mci_purge_persistent: Failed to stat %s: %s\n",
14057c478bd9Sstevel@tonic-gate pathname, sm_errstring(errno));
14067c478bd9Sstevel@tonic-gate return ret;
14077c478bd9Sstevel@tonic-gate }
14087c478bd9Sstevel@tonic-gate if (curtime() - statbuf.st_mtime <= MciInfoTimeout)
14097c478bd9Sstevel@tonic-gate return 1;
14107c478bd9Sstevel@tonic-gate if (hostname != NULL)
14117c478bd9Sstevel@tonic-gate {
14127c478bd9Sstevel@tonic-gate /* remove the file */
14137c478bd9Sstevel@tonic-gate ret = unlink(pathname);
14147c478bd9Sstevel@tonic-gate if (ret < 0)
14157c478bd9Sstevel@tonic-gate {
14167c478bd9Sstevel@tonic-gate if (LogLevel > 8)
14177c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID,
14187c478bd9Sstevel@tonic-gate "mci_purge_persistent: failed to unlink %s: %s",
14197c478bd9Sstevel@tonic-gate pathname, sm_errstring(errno));
14207c478bd9Sstevel@tonic-gate if (tTd(56, 2))
14217c478bd9Sstevel@tonic-gate sm_dprintf("mci_purge_persistent: failed to unlink %s: %s\n",
14227c478bd9Sstevel@tonic-gate pathname, sm_errstring(errno));
14237c478bd9Sstevel@tonic-gate return ret;
14247c478bd9Sstevel@tonic-gate }
14257c478bd9Sstevel@tonic-gate }
14267c478bd9Sstevel@tonic-gate else
14277c478bd9Sstevel@tonic-gate {
14287c478bd9Sstevel@tonic-gate /* remove the directory */
14297c478bd9Sstevel@tonic-gate if (*end != '.')
14307c478bd9Sstevel@tonic-gate return 1;
14317c478bd9Sstevel@tonic-gate
14327c478bd9Sstevel@tonic-gate if (tTd(56, 1))
14337c478bd9Sstevel@tonic-gate sm_dprintf("mci_purge_persistent: dpurge %s\n", pathname);
14347c478bd9Sstevel@tonic-gate
14357c478bd9Sstevel@tonic-gate ret = rmdir(pathname);
14367c478bd9Sstevel@tonic-gate if (ret < 0)
14377c478bd9Sstevel@tonic-gate {
14387c478bd9Sstevel@tonic-gate if (tTd(56, 2))
14397c478bd9Sstevel@tonic-gate sm_dprintf("mci_purge_persistent: rmdir %s: %s\n",
14407c478bd9Sstevel@tonic-gate pathname, sm_errstring(errno));
14417c478bd9Sstevel@tonic-gate return ret;
14427c478bd9Sstevel@tonic-gate }
14437c478bd9Sstevel@tonic-gate }
14447c478bd9Sstevel@tonic-gate
14457c478bd9Sstevel@tonic-gate return 0;
14467c478bd9Sstevel@tonic-gate }
14477c478bd9Sstevel@tonic-gate /*
14487c478bd9Sstevel@tonic-gate ** MCI_GENERATE_PERSISTENT_PATH -- generate path from hostname
14497c478bd9Sstevel@tonic-gate **
14507c478bd9Sstevel@tonic-gate ** Given `host', convert from a.b.c to $HostStatDir/c./b./a,
14517c478bd9Sstevel@tonic-gate ** putting the result into `path'. if `createflag' is set, intervening
14527c478bd9Sstevel@tonic-gate ** directories will be created as needed.
14537c478bd9Sstevel@tonic-gate **
14547c478bd9Sstevel@tonic-gate ** Parameters:
14557c478bd9Sstevel@tonic-gate ** host -- host name to convert from.
14567c478bd9Sstevel@tonic-gate ** path -- place to store result.
14577c478bd9Sstevel@tonic-gate ** pathlen -- length of path buffer.
14587c478bd9Sstevel@tonic-gate ** createflag -- if set, create intervening directories as
14597c478bd9Sstevel@tonic-gate ** needed.
14607c478bd9Sstevel@tonic-gate **
14617c478bd9Sstevel@tonic-gate ** Returns:
14627c478bd9Sstevel@tonic-gate ** 0 -- success
14637c478bd9Sstevel@tonic-gate ** -1 -- failure
14647c478bd9Sstevel@tonic-gate */
14657c478bd9Sstevel@tonic-gate
14667c478bd9Sstevel@tonic-gate static int
mci_generate_persistent_path(host,path,pathlen,createflag)14677c478bd9Sstevel@tonic-gate mci_generate_persistent_path(host, path, pathlen, createflag)
14687c478bd9Sstevel@tonic-gate const char *host;
14697c478bd9Sstevel@tonic-gate char *path;
14707c478bd9Sstevel@tonic-gate int pathlen;
14717c478bd9Sstevel@tonic-gate bool createflag;
14727c478bd9Sstevel@tonic-gate {
14737c478bd9Sstevel@tonic-gate char *elem, *p, *x, ch;
14747c478bd9Sstevel@tonic-gate int ret = 0;
14757c478bd9Sstevel@tonic-gate int len;
14767c478bd9Sstevel@tonic-gate char t_host[MAXHOSTNAMELEN];
14777c478bd9Sstevel@tonic-gate #if NETINET6
14787c478bd9Sstevel@tonic-gate struct in6_addr in6_addr;
14797c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
14807c478bd9Sstevel@tonic-gate
14817c478bd9Sstevel@tonic-gate /*
14827c478bd9Sstevel@tonic-gate ** Rationality check the arguments.
14837c478bd9Sstevel@tonic-gate */
14847c478bd9Sstevel@tonic-gate
14857c478bd9Sstevel@tonic-gate if (host == NULL)
14867c478bd9Sstevel@tonic-gate {
14877c478bd9Sstevel@tonic-gate syserr("mci_generate_persistent_path: null host");
14887c478bd9Sstevel@tonic-gate return -1;
14897c478bd9Sstevel@tonic-gate }
14907c478bd9Sstevel@tonic-gate if (path == NULL)
14917c478bd9Sstevel@tonic-gate {
14927c478bd9Sstevel@tonic-gate syserr("mci_generate_persistent_path: null path");
14937c478bd9Sstevel@tonic-gate return -1;
14947c478bd9Sstevel@tonic-gate }
14957c478bd9Sstevel@tonic-gate
14967c478bd9Sstevel@tonic-gate if (tTd(56, 80))
14977c478bd9Sstevel@tonic-gate sm_dprintf("mci_generate_persistent_path(%s): ", host);
14987c478bd9Sstevel@tonic-gate
14997c478bd9Sstevel@tonic-gate if (*host == '\0' || *host == '.')
15007c478bd9Sstevel@tonic-gate return -1;
15017c478bd9Sstevel@tonic-gate
15027c478bd9Sstevel@tonic-gate /* make certain this is not a bracketed host number */
1503058561cbSjbeck if (strlen(host) > sizeof(t_host) - 1)
15047c478bd9Sstevel@tonic-gate return -1;
15057c478bd9Sstevel@tonic-gate if (host[0] == '[')
1506058561cbSjbeck (void) sm_strlcpy(t_host, host + 1, sizeof(t_host));
15077c478bd9Sstevel@tonic-gate else
1508058561cbSjbeck (void) sm_strlcpy(t_host, host, sizeof(t_host));
15097c478bd9Sstevel@tonic-gate
15107c478bd9Sstevel@tonic-gate /*
15117c478bd9Sstevel@tonic-gate ** Delete any trailing dots from the hostname.
15127c478bd9Sstevel@tonic-gate ** Leave 'elem' pointing at the \0.
15137c478bd9Sstevel@tonic-gate */
15147c478bd9Sstevel@tonic-gate
15157c478bd9Sstevel@tonic-gate elem = t_host + strlen(t_host);
15167c478bd9Sstevel@tonic-gate while (elem > t_host &&
15177c478bd9Sstevel@tonic-gate (elem[-1] == '.' || (host[0] == '[' && elem[-1] == ']')))
15187c478bd9Sstevel@tonic-gate *--elem = '\0';
15197c478bd9Sstevel@tonic-gate
15207c478bd9Sstevel@tonic-gate /* check for bogus bracketed address */
15217c478bd9Sstevel@tonic-gate if (host[0] == '[')
15227c478bd9Sstevel@tonic-gate {
15237c478bd9Sstevel@tonic-gate bool good = false;
15247c478bd9Sstevel@tonic-gate # if NETINET6
15257c478bd9Sstevel@tonic-gate if (anynet_pton(AF_INET6, t_host, &in6_addr) == 1)
15267c478bd9Sstevel@tonic-gate good = true;
15277c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
15287c478bd9Sstevel@tonic-gate # if NETINET
15297c478bd9Sstevel@tonic-gate if (inet_addr(t_host) != INADDR_NONE)
15307c478bd9Sstevel@tonic-gate good = true;
15317c478bd9Sstevel@tonic-gate # endif /* NETINET */
15327c478bd9Sstevel@tonic-gate if (!good)
15337c478bd9Sstevel@tonic-gate return -1;
15347c478bd9Sstevel@tonic-gate }
15357c478bd9Sstevel@tonic-gate
15367c478bd9Sstevel@tonic-gate /* check for what will be the final length of the path */
15377c478bd9Sstevel@tonic-gate len = strlen(HostStatDir) + 2;
15387c478bd9Sstevel@tonic-gate for (p = (char *) t_host; *p != '\0'; p++)
15397c478bd9Sstevel@tonic-gate {
15407c478bd9Sstevel@tonic-gate if (*p == '.')
15417c478bd9Sstevel@tonic-gate len++;
15427c478bd9Sstevel@tonic-gate len++;
15437c478bd9Sstevel@tonic-gate if (p[0] == '.' && p[1] == '.')
15447c478bd9Sstevel@tonic-gate return -1;
15457c478bd9Sstevel@tonic-gate }
15467c478bd9Sstevel@tonic-gate if (len > pathlen || len < 1)
15477c478bd9Sstevel@tonic-gate return -1;
15487c478bd9Sstevel@tonic-gate (void) sm_strlcpy(path, HostStatDir, pathlen);
15497c478bd9Sstevel@tonic-gate p = path + strlen(path);
15507c478bd9Sstevel@tonic-gate while (elem > t_host)
15517c478bd9Sstevel@tonic-gate {
15527c478bd9Sstevel@tonic-gate if (!path_is_dir(path, createflag))
15537c478bd9Sstevel@tonic-gate {
15547c478bd9Sstevel@tonic-gate ret = -1;
15557c478bd9Sstevel@tonic-gate break;
15567c478bd9Sstevel@tonic-gate }
15577c478bd9Sstevel@tonic-gate elem--;
15587c478bd9Sstevel@tonic-gate while (elem >= t_host && *elem != '.')
15597c478bd9Sstevel@tonic-gate elem--;
15607c478bd9Sstevel@tonic-gate *p++ = '/';
15617c478bd9Sstevel@tonic-gate x = elem + 1;
15627c478bd9Sstevel@tonic-gate while ((ch = *x++) != '\0' && ch != '.')
15637c478bd9Sstevel@tonic-gate {
15647c478bd9Sstevel@tonic-gate if (isascii(ch) && isupper(ch))
15657c478bd9Sstevel@tonic-gate ch = tolower(ch);
15667c478bd9Sstevel@tonic-gate if (ch == '/')
15677c478bd9Sstevel@tonic-gate ch = ':'; /* / -> : */
15687c478bd9Sstevel@tonic-gate *p++ = ch;
15697c478bd9Sstevel@tonic-gate }
15707c478bd9Sstevel@tonic-gate if (elem >= t_host)
15717c478bd9Sstevel@tonic-gate *p++ = '.';
15727c478bd9Sstevel@tonic-gate *p = '\0';
15737c478bd9Sstevel@tonic-gate }
15747c478bd9Sstevel@tonic-gate if (tTd(56, 80))
15757c478bd9Sstevel@tonic-gate {
15767c478bd9Sstevel@tonic-gate if (ret < 0)
15777c478bd9Sstevel@tonic-gate sm_dprintf("FAILURE %d\n", ret);
15787c478bd9Sstevel@tonic-gate else
15797c478bd9Sstevel@tonic-gate sm_dprintf("SUCCESS %s\n", path);
15807c478bd9Sstevel@tonic-gate }
15817c478bd9Sstevel@tonic-gate return ret;
15827c478bd9Sstevel@tonic-gate }
1583