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*058561cbSjbeck SM_RCSID("@(#)$Id: mci.c,v 8.218 2006/08/15 23:24:57 ca 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 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 ** 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 */ 145*058561cbSjbeck MciCache = (MCI **) sm_pmalloc_x(MaxMciCache * sizeof(*MciCache)); 146*058561cbSjbeck 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 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 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 * 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 */ 314*058561cbSjbeck 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) */ 379*058561cbSjbeck 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 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 * 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) 469*058561cbSjbeck mci = (MCI *) sm_malloc_x(sizeof(*mci)); 4707c478bd9Sstevel@tonic-gate else 471*058561cbSjbeck mci = (MCI *) sm_rpool_malloc_x(rpool, sizeof(*mci)); 472*058561cbSjbeck 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 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 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 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 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 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 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 731*058561cbSjbeck 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 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 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 861*058561cbSjbeck 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 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; 950*058561cbSjbeck 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 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 } 11487c478bd9Sstevel@tonic-gate len = sizeof(newpath) - MAXNAMLEN - 3; 11497c478bd9Sstevel@tonic-gate if (sm_strlcpy(newpath, pathname, len) >= len) 11507c478bd9Sstevel@tonic-gate { 11517c478bd9Sstevel@tonic-gate if (tTd(56, 2)) 11527c478bd9Sstevel@tonic-gate sm_dprintf("mci_traverse: path \"%s\" too long", 11537c478bd9Sstevel@tonic-gate pathname); 11547c478bd9Sstevel@tonic-gate return -1; 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate newptr = newpath + strlen(newpath); 11577c478bd9Sstevel@tonic-gate *newptr++ = '/'; 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate /* 11607c478bd9Sstevel@tonic-gate ** repeat until no file has been removed 11617c478bd9Sstevel@tonic-gate ** this may become ugly when several files "expire" 11627c478bd9Sstevel@tonic-gate ** during these loops, but it's better than doing 11637c478bd9Sstevel@tonic-gate ** a rewinddir() inside the inner loop 11647c478bd9Sstevel@tonic-gate */ 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate do 11677c478bd9Sstevel@tonic-gate { 11687c478bd9Sstevel@tonic-gate leftone = removedone = false; 11697c478bd9Sstevel@tonic-gate while ((e = readdir(d)) != NULL) 11707c478bd9Sstevel@tonic-gate { 11717c478bd9Sstevel@tonic-gate if (e->d_name[0] == '.') 11727c478bd9Sstevel@tonic-gate continue; 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate (void) sm_strlcpy(newptr, e->d_name, 1175*058561cbSjbeck sizeof(newpath) - 11767c478bd9Sstevel@tonic-gate (newptr - newpath)); 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate if (StopRequest) 11797c478bd9Sstevel@tonic-gate stop_sendmail(); 11807c478bd9Sstevel@tonic-gate ret = mci_traverse_persistent(action, newpath); 11817c478bd9Sstevel@tonic-gate if (ret < 0) 11827c478bd9Sstevel@tonic-gate break; 11837c478bd9Sstevel@tonic-gate if (ret == 1) 11847c478bd9Sstevel@tonic-gate leftone = true; 11857c478bd9Sstevel@tonic-gate if (!removedone && ret == 0 && 11867c478bd9Sstevel@tonic-gate action == mci_purge_persistent) 11877c478bd9Sstevel@tonic-gate removedone = true; 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate if (ret < 0) 11907c478bd9Sstevel@tonic-gate break; 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate /* 11937c478bd9Sstevel@tonic-gate ** The following appears to be 11947c478bd9Sstevel@tonic-gate ** necessary during purges, since 11957c478bd9Sstevel@tonic-gate ** we modify the directory structure 11967c478bd9Sstevel@tonic-gate */ 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate if (removedone) 11997c478bd9Sstevel@tonic-gate rewinddir(d); 12007c478bd9Sstevel@tonic-gate if (tTd(56, 40)) 12017c478bd9Sstevel@tonic-gate sm_dprintf("mci_traverse: path %s: ret %d removed %d left %d\n", 12027c478bd9Sstevel@tonic-gate pathname, ret, removedone, leftone); 12037c478bd9Sstevel@tonic-gate } while (removedone); 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate /* purge (or whatever) the directory proper */ 12067c478bd9Sstevel@tonic-gate if (!leftone) 12077c478bd9Sstevel@tonic-gate { 12087c478bd9Sstevel@tonic-gate *--newptr = '\0'; 12097c478bd9Sstevel@tonic-gate ret = (*action)(newpath, NULL); 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate (void) closedir(d); 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate else if (S_ISREG(statbuf.st_mode)) 12147c478bd9Sstevel@tonic-gate { 12157c478bd9Sstevel@tonic-gate char *end = pathname + strlen(pathname) - 1; 12167c478bd9Sstevel@tonic-gate char *start; 12177c478bd9Sstevel@tonic-gate char *scan; 12187c478bd9Sstevel@tonic-gate char host[MAXHOSTNAMELEN]; 12197c478bd9Sstevel@tonic-gate char *hostptr = host; 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate /* 12227c478bd9Sstevel@tonic-gate ** Reconstruct the host name from the path to the 12237c478bd9Sstevel@tonic-gate ** persistent information. 12247c478bd9Sstevel@tonic-gate */ 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate do 12277c478bd9Sstevel@tonic-gate { 12287c478bd9Sstevel@tonic-gate if (hostptr != host) 12297c478bd9Sstevel@tonic-gate *(hostptr++) = '.'; 12307c478bd9Sstevel@tonic-gate start = end; 12317c478bd9Sstevel@tonic-gate while (start > pathname && *(start - 1) != '/') 12327c478bd9Sstevel@tonic-gate start--; 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate if (*end == '.') 12357c478bd9Sstevel@tonic-gate end--; 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate for (scan = start; scan <= end; scan++) 12387c478bd9Sstevel@tonic-gate *(hostptr++) = *scan; 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate end = start - 2; 12417c478bd9Sstevel@tonic-gate } while (end > pathname && *end == '.'); 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate *hostptr = '\0'; 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate /* 12467c478bd9Sstevel@tonic-gate ** Do something with the file containing the persistent 12477c478bd9Sstevel@tonic-gate ** information. 12487c478bd9Sstevel@tonic-gate */ 12497c478bd9Sstevel@tonic-gate 12507c478bd9Sstevel@tonic-gate ret = (*action)(pathname, host); 12517c478bd9Sstevel@tonic-gate } 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate return ret; 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate /* 12567c478bd9Sstevel@tonic-gate ** MCI_PRINT_PERSISTENT -- print persistent info 12577c478bd9Sstevel@tonic-gate ** 12587c478bd9Sstevel@tonic-gate ** Dump the persistent information in the file 'pathname' 12597c478bd9Sstevel@tonic-gate ** 12607c478bd9Sstevel@tonic-gate ** Parameters: 12617c478bd9Sstevel@tonic-gate ** pathname -- the pathname to the status file. 12627c478bd9Sstevel@tonic-gate ** hostname -- the corresponding host name. 12637c478bd9Sstevel@tonic-gate ** 12647c478bd9Sstevel@tonic-gate ** Returns: 12657c478bd9Sstevel@tonic-gate ** 0 12667c478bd9Sstevel@tonic-gate */ 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate int 12697c478bd9Sstevel@tonic-gate mci_print_persistent(pathname, hostname) 12707c478bd9Sstevel@tonic-gate char *pathname; 12717c478bd9Sstevel@tonic-gate char *hostname; 12727c478bd9Sstevel@tonic-gate { 12737c478bd9Sstevel@tonic-gate static bool initflag = false; 12747c478bd9Sstevel@tonic-gate SM_FILE_T *fp; 12757c478bd9Sstevel@tonic-gate int width = Verbose ? 78 : 25; 12767c478bd9Sstevel@tonic-gate bool locked; 12777c478bd9Sstevel@tonic-gate MCI mcib; 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate /* skip directories */ 12807c478bd9Sstevel@tonic-gate if (hostname == NULL) 12817c478bd9Sstevel@tonic-gate return 0; 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate if (StopRequest) 12847c478bd9Sstevel@tonic-gate stop_sendmail(); 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate if (!initflag) 12877c478bd9Sstevel@tonic-gate { 12887c478bd9Sstevel@tonic-gate initflag = true; 12897c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 12907c478bd9Sstevel@tonic-gate " -------------- Hostname --------------- How long ago ---------Results---------\n"); 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate fp = safefopen(pathname, O_RDONLY, FileMode, 12947c478bd9Sstevel@tonic-gate SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH); 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate if (fp == NULL) 12977c478bd9Sstevel@tonic-gate { 12987c478bd9Sstevel@tonic-gate if (tTd(56, 1)) 12997c478bd9Sstevel@tonic-gate sm_dprintf("mci_print_persistent: cannot open %s: %s\n", 13007c478bd9Sstevel@tonic-gate pathname, sm_errstring(errno)); 13017c478bd9Sstevel@tonic-gate return 0; 13027c478bd9Sstevel@tonic-gate } 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate FileName = pathname; 1305*058561cbSjbeck memset(&mcib, '\0', sizeof(mcib)); 13067c478bd9Sstevel@tonic-gate if (mci_read_persistent(fp, &mcib) < 0) 13077c478bd9Sstevel@tonic-gate { 13087c478bd9Sstevel@tonic-gate syserr("%s: could not read status file", pathname); 13097c478bd9Sstevel@tonic-gate (void) sm_io_close(fp, SM_TIME_DEFAULT); 13107c478bd9Sstevel@tonic-gate FileName = NULL; 13117c478bd9Sstevel@tonic-gate return 0; 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate locked = !lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), pathname, 13157c478bd9Sstevel@tonic-gate "", LOCK_SH|LOCK_NB); 13167c478bd9Sstevel@tonic-gate (void) sm_io_close(fp, SM_TIME_DEFAULT); 13177c478bd9Sstevel@tonic-gate FileName = NULL; 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%c%-39s %12s ", 13207c478bd9Sstevel@tonic-gate locked ? '*' : ' ', hostname, 13217c478bd9Sstevel@tonic-gate pintvl(curtime() - mcib.mci_lastuse, true)); 13227c478bd9Sstevel@tonic-gate if (mcib.mci_rstatus != NULL) 13237c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", width, 13247c478bd9Sstevel@tonic-gate mcib.mci_rstatus); 13257c478bd9Sstevel@tonic-gate else if (mcib.mci_exitstat == EX_TEMPFAIL && mcib.mci_errno != 0) 13267c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 13277c478bd9Sstevel@tonic-gate "Deferred: %.*s\n", width - 10, 13287c478bd9Sstevel@tonic-gate sm_errstring(mcib.mci_errno)); 13297c478bd9Sstevel@tonic-gate else if (mcib.mci_exitstat != 0) 13307c478bd9Sstevel@tonic-gate { 13317c478bd9Sstevel@tonic-gate char *exmsg = sm_sysexmsg(mcib.mci_exitstat); 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate if (exmsg == NULL) 13347c478bd9Sstevel@tonic-gate { 13357c478bd9Sstevel@tonic-gate char buf[80]; 13367c478bd9Sstevel@tonic-gate 1337*058561cbSjbeck (void) sm_snprintf(buf, sizeof(buf), 13387c478bd9Sstevel@tonic-gate "Unknown mailer error %d", 13397c478bd9Sstevel@tonic-gate mcib.mci_exitstat); 13407c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", 13417c478bd9Sstevel@tonic-gate width, buf); 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate else 13447c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", 13457c478bd9Sstevel@tonic-gate width, &exmsg[5]); 13467c478bd9Sstevel@tonic-gate } 13477c478bd9Sstevel@tonic-gate else if (mcib.mci_errno == 0) 13487c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK\n"); 13497c478bd9Sstevel@tonic-gate else 13507c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK: %.*s\n", 13517c478bd9Sstevel@tonic-gate width - 4, sm_errstring(mcib.mci_errno)); 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate return 0; 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate /* 13567c478bd9Sstevel@tonic-gate ** MCI_PURGE_PERSISTENT -- Remove a persistence status file. 13577c478bd9Sstevel@tonic-gate ** 13587c478bd9Sstevel@tonic-gate ** Parameters: 13597c478bd9Sstevel@tonic-gate ** pathname -- path to the status file. 13607c478bd9Sstevel@tonic-gate ** hostname -- name of host corresponding to that file. 13617c478bd9Sstevel@tonic-gate ** NULL if this is a directory (domain). 13627c478bd9Sstevel@tonic-gate ** 13637c478bd9Sstevel@tonic-gate ** Returns: 13647c478bd9Sstevel@tonic-gate ** 0 -- ok 13657c478bd9Sstevel@tonic-gate ** 1 -- file not deleted (too young, incorrect format) 13667c478bd9Sstevel@tonic-gate ** < 0 -- some error occurred 13677c478bd9Sstevel@tonic-gate */ 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate int 13707c478bd9Sstevel@tonic-gate mci_purge_persistent(pathname, hostname) 13717c478bd9Sstevel@tonic-gate char *pathname; 13727c478bd9Sstevel@tonic-gate char *hostname; 13737c478bd9Sstevel@tonic-gate { 13747c478bd9Sstevel@tonic-gate struct stat statbuf; 13757c478bd9Sstevel@tonic-gate char *end = pathname + strlen(pathname) - 1; 13767c478bd9Sstevel@tonic-gate int ret; 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate if (tTd(56, 1)) 13797c478bd9Sstevel@tonic-gate sm_dprintf("mci_purge_persistent: purging %s\n", pathname); 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate ret = stat(pathname, &statbuf); 13827c478bd9Sstevel@tonic-gate if (ret < 0) 13837c478bd9Sstevel@tonic-gate { 13847c478bd9Sstevel@tonic-gate if (tTd(56, 2)) 13857c478bd9Sstevel@tonic-gate sm_dprintf("mci_purge_persistent: Failed to stat %s: %s\n", 13867c478bd9Sstevel@tonic-gate pathname, sm_errstring(errno)); 13877c478bd9Sstevel@tonic-gate return ret; 13887c478bd9Sstevel@tonic-gate } 13897c478bd9Sstevel@tonic-gate if (curtime() - statbuf.st_mtime <= MciInfoTimeout) 13907c478bd9Sstevel@tonic-gate return 1; 13917c478bd9Sstevel@tonic-gate if (hostname != NULL) 13927c478bd9Sstevel@tonic-gate { 13937c478bd9Sstevel@tonic-gate /* remove the file */ 13947c478bd9Sstevel@tonic-gate ret = unlink(pathname); 13957c478bd9Sstevel@tonic-gate if (ret < 0) 13967c478bd9Sstevel@tonic-gate { 13977c478bd9Sstevel@tonic-gate if (LogLevel > 8) 13987c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 13997c478bd9Sstevel@tonic-gate "mci_purge_persistent: failed to unlink %s: %s", 14007c478bd9Sstevel@tonic-gate pathname, sm_errstring(errno)); 14017c478bd9Sstevel@tonic-gate if (tTd(56, 2)) 14027c478bd9Sstevel@tonic-gate sm_dprintf("mci_purge_persistent: failed to unlink %s: %s\n", 14037c478bd9Sstevel@tonic-gate pathname, sm_errstring(errno)); 14047c478bd9Sstevel@tonic-gate return ret; 14057c478bd9Sstevel@tonic-gate } 14067c478bd9Sstevel@tonic-gate } 14077c478bd9Sstevel@tonic-gate else 14087c478bd9Sstevel@tonic-gate { 14097c478bd9Sstevel@tonic-gate /* remove the directory */ 14107c478bd9Sstevel@tonic-gate if (*end != '.') 14117c478bd9Sstevel@tonic-gate return 1; 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate if (tTd(56, 1)) 14147c478bd9Sstevel@tonic-gate sm_dprintf("mci_purge_persistent: dpurge %s\n", pathname); 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate ret = rmdir(pathname); 14177c478bd9Sstevel@tonic-gate if (ret < 0) 14187c478bd9Sstevel@tonic-gate { 14197c478bd9Sstevel@tonic-gate if (tTd(56, 2)) 14207c478bd9Sstevel@tonic-gate sm_dprintf("mci_purge_persistent: rmdir %s: %s\n", 14217c478bd9Sstevel@tonic-gate pathname, sm_errstring(errno)); 14227c478bd9Sstevel@tonic-gate return ret; 14237c478bd9Sstevel@tonic-gate } 14247c478bd9Sstevel@tonic-gate } 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate return 0; 14277c478bd9Sstevel@tonic-gate } 14287c478bd9Sstevel@tonic-gate /* 14297c478bd9Sstevel@tonic-gate ** MCI_GENERATE_PERSISTENT_PATH -- generate path from hostname 14307c478bd9Sstevel@tonic-gate ** 14317c478bd9Sstevel@tonic-gate ** Given `host', convert from a.b.c to $HostStatDir/c./b./a, 14327c478bd9Sstevel@tonic-gate ** putting the result into `path'. if `createflag' is set, intervening 14337c478bd9Sstevel@tonic-gate ** directories will be created as needed. 14347c478bd9Sstevel@tonic-gate ** 14357c478bd9Sstevel@tonic-gate ** Parameters: 14367c478bd9Sstevel@tonic-gate ** host -- host name to convert from. 14377c478bd9Sstevel@tonic-gate ** path -- place to store result. 14387c478bd9Sstevel@tonic-gate ** pathlen -- length of path buffer. 14397c478bd9Sstevel@tonic-gate ** createflag -- if set, create intervening directories as 14407c478bd9Sstevel@tonic-gate ** needed. 14417c478bd9Sstevel@tonic-gate ** 14427c478bd9Sstevel@tonic-gate ** Returns: 14437c478bd9Sstevel@tonic-gate ** 0 -- success 14447c478bd9Sstevel@tonic-gate ** -1 -- failure 14457c478bd9Sstevel@tonic-gate */ 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate static int 14487c478bd9Sstevel@tonic-gate mci_generate_persistent_path(host, path, pathlen, createflag) 14497c478bd9Sstevel@tonic-gate const char *host; 14507c478bd9Sstevel@tonic-gate char *path; 14517c478bd9Sstevel@tonic-gate int pathlen; 14527c478bd9Sstevel@tonic-gate bool createflag; 14537c478bd9Sstevel@tonic-gate { 14547c478bd9Sstevel@tonic-gate char *elem, *p, *x, ch; 14557c478bd9Sstevel@tonic-gate int ret = 0; 14567c478bd9Sstevel@tonic-gate int len; 14577c478bd9Sstevel@tonic-gate char t_host[MAXHOSTNAMELEN]; 14587c478bd9Sstevel@tonic-gate #if NETINET6 14597c478bd9Sstevel@tonic-gate struct in6_addr in6_addr; 14607c478bd9Sstevel@tonic-gate #endif /* NETINET6 */ 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate /* 14637c478bd9Sstevel@tonic-gate ** Rationality check the arguments. 14647c478bd9Sstevel@tonic-gate */ 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate if (host == NULL) 14677c478bd9Sstevel@tonic-gate { 14687c478bd9Sstevel@tonic-gate syserr("mci_generate_persistent_path: null host"); 14697c478bd9Sstevel@tonic-gate return -1; 14707c478bd9Sstevel@tonic-gate } 14717c478bd9Sstevel@tonic-gate if (path == NULL) 14727c478bd9Sstevel@tonic-gate { 14737c478bd9Sstevel@tonic-gate syserr("mci_generate_persistent_path: null path"); 14747c478bd9Sstevel@tonic-gate return -1; 14757c478bd9Sstevel@tonic-gate } 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate if (tTd(56, 80)) 14787c478bd9Sstevel@tonic-gate sm_dprintf("mci_generate_persistent_path(%s): ", host); 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate if (*host == '\0' || *host == '.') 14817c478bd9Sstevel@tonic-gate return -1; 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate /* make certain this is not a bracketed host number */ 1484*058561cbSjbeck if (strlen(host) > sizeof(t_host) - 1) 14857c478bd9Sstevel@tonic-gate return -1; 14867c478bd9Sstevel@tonic-gate if (host[0] == '[') 1487*058561cbSjbeck (void) sm_strlcpy(t_host, host + 1, sizeof(t_host)); 14887c478bd9Sstevel@tonic-gate else 1489*058561cbSjbeck (void) sm_strlcpy(t_host, host, sizeof(t_host)); 14907c478bd9Sstevel@tonic-gate 14917c478bd9Sstevel@tonic-gate /* 14927c478bd9Sstevel@tonic-gate ** Delete any trailing dots from the hostname. 14937c478bd9Sstevel@tonic-gate ** Leave 'elem' pointing at the \0. 14947c478bd9Sstevel@tonic-gate */ 14957c478bd9Sstevel@tonic-gate 14967c478bd9Sstevel@tonic-gate elem = t_host + strlen(t_host); 14977c478bd9Sstevel@tonic-gate while (elem > t_host && 14987c478bd9Sstevel@tonic-gate (elem[-1] == '.' || (host[0] == '[' && elem[-1] == ']'))) 14997c478bd9Sstevel@tonic-gate *--elem = '\0'; 15007c478bd9Sstevel@tonic-gate 15017c478bd9Sstevel@tonic-gate /* check for bogus bracketed address */ 15027c478bd9Sstevel@tonic-gate if (host[0] == '[') 15037c478bd9Sstevel@tonic-gate { 15047c478bd9Sstevel@tonic-gate bool good = false; 15057c478bd9Sstevel@tonic-gate # if NETINET6 15067c478bd9Sstevel@tonic-gate if (anynet_pton(AF_INET6, t_host, &in6_addr) == 1) 15077c478bd9Sstevel@tonic-gate good = true; 15087c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 15097c478bd9Sstevel@tonic-gate # if NETINET 15107c478bd9Sstevel@tonic-gate if (inet_addr(t_host) != INADDR_NONE) 15117c478bd9Sstevel@tonic-gate good = true; 15127c478bd9Sstevel@tonic-gate # endif /* NETINET */ 15137c478bd9Sstevel@tonic-gate if (!good) 15147c478bd9Sstevel@tonic-gate return -1; 15157c478bd9Sstevel@tonic-gate } 15167c478bd9Sstevel@tonic-gate 15177c478bd9Sstevel@tonic-gate /* check for what will be the final length of the path */ 15187c478bd9Sstevel@tonic-gate len = strlen(HostStatDir) + 2; 15197c478bd9Sstevel@tonic-gate for (p = (char *) t_host; *p != '\0'; p++) 15207c478bd9Sstevel@tonic-gate { 15217c478bd9Sstevel@tonic-gate if (*p == '.') 15227c478bd9Sstevel@tonic-gate len++; 15237c478bd9Sstevel@tonic-gate len++; 15247c478bd9Sstevel@tonic-gate if (p[0] == '.' && p[1] == '.') 15257c478bd9Sstevel@tonic-gate return -1; 15267c478bd9Sstevel@tonic-gate } 15277c478bd9Sstevel@tonic-gate if (len > pathlen || len < 1) 15287c478bd9Sstevel@tonic-gate return -1; 15297c478bd9Sstevel@tonic-gate (void) sm_strlcpy(path, HostStatDir, pathlen); 15307c478bd9Sstevel@tonic-gate p = path + strlen(path); 15317c478bd9Sstevel@tonic-gate while (elem > t_host) 15327c478bd9Sstevel@tonic-gate { 15337c478bd9Sstevel@tonic-gate if (!path_is_dir(path, createflag)) 15347c478bd9Sstevel@tonic-gate { 15357c478bd9Sstevel@tonic-gate ret = -1; 15367c478bd9Sstevel@tonic-gate break; 15377c478bd9Sstevel@tonic-gate } 15387c478bd9Sstevel@tonic-gate elem--; 15397c478bd9Sstevel@tonic-gate while (elem >= t_host && *elem != '.') 15407c478bd9Sstevel@tonic-gate elem--; 15417c478bd9Sstevel@tonic-gate *p++ = '/'; 15427c478bd9Sstevel@tonic-gate x = elem + 1; 15437c478bd9Sstevel@tonic-gate while ((ch = *x++) != '\0' && ch != '.') 15447c478bd9Sstevel@tonic-gate { 15457c478bd9Sstevel@tonic-gate if (isascii(ch) && isupper(ch)) 15467c478bd9Sstevel@tonic-gate ch = tolower(ch); 15477c478bd9Sstevel@tonic-gate if (ch == '/') 15487c478bd9Sstevel@tonic-gate ch = ':'; /* / -> : */ 15497c478bd9Sstevel@tonic-gate *p++ = ch; 15507c478bd9Sstevel@tonic-gate } 15517c478bd9Sstevel@tonic-gate if (elem >= t_host) 15527c478bd9Sstevel@tonic-gate *p++ = '.'; 15537c478bd9Sstevel@tonic-gate *p = '\0'; 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate if (tTd(56, 80)) 15567c478bd9Sstevel@tonic-gate { 15577c478bd9Sstevel@tonic-gate if (ret < 0) 15587c478bd9Sstevel@tonic-gate sm_dprintf("FAILURE %d\n", ret); 15597c478bd9Sstevel@tonic-gate else 15607c478bd9Sstevel@tonic-gate sm_dprintf("SUCCESS %s\n", path); 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate return ret; 15637c478bd9Sstevel@tonic-gate } 1564