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