📄 mci.c
字号:
void
mci_dump(mci, logit)
register MCI *mci;
bool logit;
{
register char *p;
char *sep;
char buf[4000];
sep = logit ? " " : "\n\t";
p = buf;
snprintf(p, SPACELEFT(buf, p), "MCI@%lx: ", (u_long) mci);
p += strlen(p);
if (mci == NULL)
{
snprintf(p, SPACELEFT(buf, p), "NULL");
goto printit;
}
snprintf(p, SPACELEFT(buf, p), "flags=%lx", mci->mci_flags);
p += strlen(p);
if (mci->mci_flags != 0)
{
struct mcifbits *f;
*p++ = '<';
for (f = MciFlags; f->mcif_bit != 0; f++)
{
if (!bitset(f->mcif_bit, mci->mci_flags))
continue;
snprintf(p, SPACELEFT(buf, p), "%s,", f->mcif_name);
p += strlen(p);
}
p[-1] = '>';
}
snprintf(p, SPACELEFT(buf, p),
",%serrno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s",
sep, mci->mci_errno, mci->mci_herrno,
mci->mci_exitstat, mci->mci_state, (int) mci->mci_pid, sep);
p += strlen(p);
snprintf(p, SPACELEFT(buf, p),
"maxsize=%ld, phase=%s, mailer=%s,%s",
mci->mci_maxsize,
mci->mci_phase == NULL ? "NULL" : mci->mci_phase,
mci->mci_mailer == NULL ? "NULL" : mci->mci_mailer->m_name,
sep);
p += strlen(p);
snprintf(p, SPACELEFT(buf, p),
"status=%s, rstatus=%s,%s",
mci->mci_status == NULL ? "NULL" : mci->mci_status,
mci->mci_rstatus == NULL ? "NULL" : mci->mci_rstatus,
sep);
p += strlen(p);
snprintf(p, SPACELEFT(buf, p),
"host=%s, lastuse=%s",
mci->mci_host == NULL ? "NULL" : mci->mci_host,
ctime(&mci->mci_lastuse));
printit:
if (logit)
sm_syslog(LOG_DEBUG, CurEnv->e_id, "%.1000s", buf);
else
printf("%s\n", buf);
}
/*
** MCI_DUMP_ALL -- print the entire MCI cache
**
** Parameters:
** logit -- if set, log the result instead of printing
** to stdout.
**
** Returns:
** none.
*/
void
mci_dump_all(logit)
bool logit;
{
register int i;
if (MciCache == NULL)
return;
for (i = 0; i < MaxMciCache; i++)
mci_dump(MciCache[i], logit);
}
/*
** MCI_LOCK_HOST -- Lock host while sending.
**
** If we are contacting a host, we'll need to
** update the status information in the host status
** file, and if we want to do that, we ought to have
** locked it. This has the (according to some)
** desirable effect of serializing connectivity with
** remote hosts -- i.e.: one connection to a give
** host at a time.
**
** Parameters:
** mci -- containing the host we want to lock.
**
** Returns:
** EX_OK -- got the lock.
** EX_TEMPFAIL -- didn't get the lock.
*/
int
mci_lock_host(mci)
MCI *mci;
{
if (mci == NULL)
{
if (tTd(56, 1))
dprintf("mci_lock_host: NULL mci\n");
return EX_OK;
}
if (!SingleThreadDelivery)
return EX_OK;
return mci_lock_host_statfile(mci);
}
static int
mci_lock_host_statfile(mci)
MCI *mci;
{
int save_errno = errno;
int retVal = EX_OK;
char fname[MAXPATHLEN + 1];
if (HostStatDir == NULL || mci->mci_host == NULL)
return EX_OK;
if (tTd(56, 2))
dprintf("mci_lock_host: attempting to lock %s\n",
mci->mci_host);
if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname, TRUE) < 0)
{
/* of course this should never happen */
if (tTd(56, 2))
dprintf("mci_lock_host: Failed to generate host path for %s\n",
mci->mci_host);
retVal = EX_TEMPFAIL;
goto cleanup;
}
mci->mci_statfile = safefopen(fname, O_RDWR, FileMode,
SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH|SFF_CREAT);
if (mci->mci_statfile == NULL)
{
syserr("mci_lock_host: cannot create host lock file %s",
fname);
goto cleanup;
}
if (!lockfile(fileno(mci->mci_statfile), fname, "", LOCK_EX|LOCK_NB))
{
if (tTd(56, 2))
dprintf("mci_lock_host: couldn't get lock on %s\n",
fname);
(void) fclose(mci->mci_statfile);
mci->mci_statfile = NULL;
retVal = EX_TEMPFAIL;
goto cleanup;
}
if (tTd(56, 12) && mci->mci_statfile != NULL)
dprintf("mci_lock_host: Sanity check -- lock is good\n");
cleanup:
errno = save_errno;
return retVal;
}
/*
** MCI_UNLOCK_HOST -- unlock host
**
** Clean up the lock on a host, close the file, let
** someone else use it.
**
** Parameters:
** mci -- us.
**
** Returns:
** nothing.
*/
void
mci_unlock_host(mci)
MCI *mci;
{
int save_errno = errno;
if (mci == NULL)
{
if (tTd(56, 1))
dprintf("mci_unlock_host: NULL mci\n");
return;
}
if (HostStatDir == NULL || mci->mci_host == NULL)
return;
if (!SingleThreadDelivery && mci_lock_host_statfile(mci) == EX_TEMPFAIL)
{
if (tTd(56, 1))
dprintf("mci_unlock_host: stat file already locked\n");
}
else
{
if (tTd(56, 2))
dprintf("mci_unlock_host: store prior to unlock\n");
mci_store_persistent(mci);
}
if (mci->mci_statfile != NULL)
{
(void) fclose(mci->mci_statfile);
mci->mci_statfile = NULL;
}
errno = save_errno;
}
/*
** MCI_LOAD_PERSISTENT -- load persistent host info
**
** Load information about host that is kept
** in common for all running sendmails.
**
** Parameters:
** mci -- the host/connection to load persistent info
** for.
**
** Returns:
** TRUE -- lock was successful
** FALSE -- lock failed
*/
static bool
mci_load_persistent(mci)
MCI *mci;
{
int save_errno = errno;
bool locked = TRUE;
FILE *fp;
char fname[MAXPATHLEN + 1];
if (mci == NULL)
{
if (tTd(56, 1))
dprintf("mci_load_persistent: NULL mci\n");
return TRUE;
}
if (IgnoreHostStatus || HostStatDir == NULL || mci->mci_host == NULL)
return TRUE;
/* Already have the persistent information in memory */
if (SingleThreadDelivery && mci->mci_statfile != NULL)
return TRUE;
if (tTd(56, 1))
dprintf("mci_load_persistent: Attempting to load persistent information for %s\n",
mci->mci_host);
if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname, FALSE) < 0)
{
/* Not much we can do if the file isn't there... */
if (tTd(56, 1))
dprintf("mci_load_persistent: Couldn't generate host path\n");
goto cleanup;
}
fp = safefopen(fname, O_RDONLY, FileMode,
SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH);
if (fp == NULL)
{
/* I can't think of any reason this should ever happen */
if (tTd(56, 1))
dprintf("mci_load_persistent: open(%s): %s\n",
fname, errstring(errno));
goto cleanup;
}
FileName = fname;
locked = lockfile(fileno(fp), fname, "", LOCK_SH|LOCK_NB);
if (locked)
{
(void) mci_read_persistent(fp, mci);
(void) lockfile(fileno(fp), fname, "", LOCK_UN);
}
FileName = NULL;
(void) fclose(fp);
cleanup:
errno = save_errno;
return locked;
}
/*
** MCI_READ_PERSISTENT -- read persistent host status file
**
** Parameters:
** fp -- the file pointer to read.
** mci -- the pointer to fill in.
**
** Returns:
** -1 -- if the file was corrupt.
** 0 -- otherwise.
**
** Warning:
** This code makes the assumption that this data
** will be read in an atomic fashion, and that the data
** was written in an atomic fashion. Any other functioning
** may lead to some form of insanity. This should be
** perfectly safe due to underlying stdio buffering.
*/
static int
mci_read_persistent(fp, mci)
FILE *fp;
register MCI *mci;
{
int ver;
register char *p;
int saveLineNumber = LineNumber;
char buf[MAXLINE];
if (fp == NULL)
syserr("mci_read_persistent: NULL fp");
if (mci == NULL)
syserr("mci_read_persistent: NULL mci");
if (tTd(56, 93))
{
dprintf("mci_read_persistent: fp=%lx, mci=", (u_long) fp);
mci_dump(mci, FALSE);
}
mci->mci_status = NULL;
if (mci->mci_rstatus != NULL)
free(mci->mci_rstatus);
mci->mci_rstatus = NULL;
rewind(fp);
ver = -1;
LineNumber = 0;
while (fgets(buf, sizeof buf, fp) != NULL)
{
LineNumber++;
p = strchr(buf, '\n');
if (p != NULL)
*p = '\0';
switch (buf[0])
{
case 'V': /* version stamp */
ver = atoi(&buf[1]);
if (ver < 0 || ver > 0)
syserr("Unknown host status version %d: %d max",
ver, 0);
break;
case 'E': /* UNIX error number */
mci->mci_errno = atoi(&buf[1]);
break;
case 'H': /* DNS error number */
mci->mci_herrno = atoi(&buf[1]);
break;
case 'S': /* UNIX exit status */
mci->mci_exitstat = atoi(&buf[1]);
break;
case 'D': /* DSN status */
mci->mci_status = newstr(&buf[1]);
break;
case 'R': /* SMTP status */
mci->mci_rstatus = newstr(&buf[1]);
break;
case 'U': /* last usage time */
mci->mci_lastuse = atol(&buf[1]);
break;
case '.': /* end of file */
return 0;
default:
sm_syslog(LOG_CRIT, NOQID,
"%s: line %d: Unknown host status line \"%s\"",
FileName == NULL ? mci->mci_host : FileName,
LineNumber, buf);
LineNumber = saveLineNumber;
return -1;
}
}
LineNumber = saveLineNumber;
if (ver < 0)
return -1;
return 0;
}
/*
** MCI_STORE_PERSISTENT -- Store persistent MCI information
**
** Store information about host that is kept
** in common for all running sendmails.
**
** Parameters:
** mci -- the host/connection to store persistent info for.
**
** Returns:
** none.
*/
void
mci_store_persistent(mci)
MCI *mci;
{
int save_errno = errno;
if (mci == NULL)
{
if (tTd(56, 1))
dprintf("mci_store_persistent: NULL mci\n");
return;
}
if (HostStatDir == NULL || mci->mci_host == NULL)
return;
if (tTd(56, 1))
dprintf("mci_store_persistent: Storing information for %s\n",
mci->mci_host);
if (mci->mci_statfile == NULL)
{
if (tTd(56, 1))
dprintf("mci_store_persistent: no statfile\n");
return;
}
rewind(mci->mci_statfile);
#if !NOFTRUNCATE
(void) ftruncate(fileno(mci->mci_statfile), (off_t) 0);
#endif /* !NOFTRUNCATE */
fprintf(mci->mci_statfile, "V0\n");
fprintf(mci->mci_statfile, "E%d\n", mci->mci_errno);
fprintf(mci->mci_statfile, "H%d\n", mci->mci_herrno);
fprintf(mci->mci_statfile, "S%d\n", mci->mci_exitstat);
if (mci->mci_status != NULL)
fprintf(mci->mci_statfile, "D%.80s\n",
denlstring(mci->mci_status, TRUE, FALSE));
if (mci->mci_rstatus != NULL)
fprintf(mci->mci_statfile, "R%.80s\n",
denlstring(mci->mci_rstatus, TRUE, FALSE));
fprintf(mci->mci_statfile, "U%ld\n", (long)(mci->mci_lastuse));
fprintf(mci->mci_statfile, ".\n");
(void) fflush(mci->mci_statfile);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -