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