📄 queue.c
字号:
/* * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */# include "sendmail.h"#ifndef lint#ifdef QUEUEstatic char sccsid[] = "@(#)queue.c 8.41 (Berkeley) 4/18/94 (with queueing)";#elsestatic char sccsid[] = "@(#)queue.c 8.41 (Berkeley) 4/18/94 (without queueing)";#endif#endif /* not lint */# include <errno.h># include <pwd.h># include <dirent.h># ifdef QUEUE/*** Work queue.*/struct work{ char *w_name; /* name of control file */ long w_pri; /* priority of message, see below */ time_t w_ctime; /* creation time of message */ struct work *w_next; /* next in queue */};typedef struct work WORK;WORK *WorkQ; /* queue of things to be done *//*** QUEUEUP -- queue a message up for future transmission.**** Parameters:** e -- the envelope to queue up.** queueall -- if TRUE, queue all addresses, rather than** just those with the QQUEUEUP flag set.** announce -- if TRUE, tell when you are queueing up.**** Returns:** none.**** Side Effects:** The current request are saved in a control file.** The queue file is left locked.*/queueup(e, queueall, announce) register ENVELOPE *e; bool queueall; bool announce;{ char *qf; register FILE *tfp; register HDR *h; register ADDRESS *q; int fd; int i; bool newid; register char *p; MAILER nullmailer; MCI mcibuf; char buf[MAXLINE], tf[MAXLINE]; /* ** Create control file. */ newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags); /* if newid, queuename will create a locked qf file in e->lockfp */ strcpy(tf, queuename(e, 't')); tfp = e->e_lockfp; if (tfp == NULL) newid = FALSE; /* if newid, just write the qf file directly (instead of tf file) */ if (!newid) { /* get a locked tf file */ for (i = 0; i < 128; i++) { fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode); if (fd < 0) { if (errno != EEXIST) break;#ifdef LOG if (LogLevel > 0 && (i % 32) == 0) syslog(LOG_ALERT, "queueup: cannot create %s, uid=%d: %s", tf, geteuid(), errstring(errno));#endif } else { if (lockfile(fd, tf, NULL, LOCK_EX|LOCK_NB)) break;#ifdef LOG else if (LogLevel > 0 && (i % 32) == 0) syslog(LOG_ALERT, "queueup: cannot lock %s: %s", tf, errstring(errno));#endif close(fd); } if ((i % 32) == 31) { /* save the old temp file away */ (void) rename(tf, queuename(e, 'T')); } else sleep(i % 32); } if (fd < 0 || (tfp = fdopen(fd, "w")) == NULL) { printopenfds(TRUE); syserr("!queueup: cannot create queue temp file %s, uid=%d", tf, geteuid()); } } if (tTd(40, 1)) printf("\n>>>>> queueing %s%s >>>>>\n", e->e_id, newid ? " (new id)" : ""); if (tTd(40, 9)) { printf(" tfp="); dumpfd(fileno(tfp), TRUE, FALSE); printf(" lockfp="); if (e->e_lockfp == NULL) printf("NULL\n"); else dumpfd(fileno(e->e_lockfp), TRUE, FALSE); } /* ** If there is no data file yet, create one. */ if (e->e_df == NULL) { register FILE *dfp; extern putbody(); e->e_df = queuename(e, 'd'); e->e_df = newstr(e->e_df); fd = open(e->e_df, O_WRONLY|O_CREAT|O_TRUNC, FileMode); if (fd < 0 || (dfp = fdopen(fd, "w")) == NULL) syserr("!queueup: cannot create data temp file %s, uid=%d", e->e_df, geteuid()); bzero(&mcibuf, sizeof mcibuf); mcibuf.mci_out = dfp; mcibuf.mci_mailer = FileMailer; (*e->e_putbody)(&mcibuf, e, NULL); (void) xfclose(dfp, "queueup dfp", e->e_id); e->e_putbody = putbody; } /* ** Output future work requests. ** Priority and creation time should be first, since ** they are required by orderq. */ /* output message priority */ fprintf(tfp, "P%ld\n", e->e_msgpriority); /* output creation time */ fprintf(tfp, "T%ld\n", e->e_ctime); /* output type and name of data file */ if (e->e_bodytype != NULL) fprintf(tfp, "B%s\n", e->e_bodytype); fprintf(tfp, "D%s\n", e->e_df); /* message from envelope, if it exists */ if (e->e_message != NULL) fprintf(tfp, "M%s\n", e->e_message); /* send various flag bits through */ p = buf; if (bitset(EF_WARNING, e->e_flags)) *p++ = 'w'; if (bitset(EF_RESPONSE, e->e_flags)) *p++ = 'r'; *p++ = '\0'; if (buf[0] != '\0') fprintf(tfp, "F%s\n", buf); /* $r and $s and $_ macro values */ if ((p = macvalue('r', e)) != NULL) fprintf(tfp, "$r%s\n", p); if ((p = macvalue('s', e)) != NULL) fprintf(tfp, "$s%s\n", p); if ((p = macvalue('_', e)) != NULL) fprintf(tfp, "$_%s\n", p); /* output name of sender */ fprintf(tfp, "S%s\n", e->e_from.q_paddr); /* output list of error recipients */ printctladdr(NULL, NULL); for (q = e->e_errorqueue; q != NULL; q = q->q_next) { if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) { printctladdr(q, tfp); fprintf(tfp, "E%s\n", q->q_paddr); } } /* output list of recipient addresses */ for (q = e->e_sendqueue; q != NULL; q = q->q_next) { if (bitset(QQUEUEUP, q->q_flags) || (queueall && !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags))) { printctladdr(q, tfp); fprintf(tfp, "R%s\n", q->q_paddr); if (announce) { e->e_to = q->q_paddr; message("queued"); if (LogLevel > 8) logdelivery(NULL, NULL, "queued", NULL, e); e->e_to = NULL; } if (tTd(40, 1)) { printf("queueing "); printaddr(q, FALSE); } } } /* ** Output headers for this message. ** Expand macros completely here. Queue run will deal with ** everything as absolute headers. ** All headers that must be relative to the recipient ** can be cracked later. ** We set up a "null mailer" -- i.e., a mailer that will have ** no effect on the addresses as they are output. */ bzero((char *) &nullmailer, sizeof nullmailer); nullmailer.m_re_rwset = nullmailer.m_rh_rwset = nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1; nullmailer.m_eol = "\n"; bzero(&mcibuf, sizeof mcibuf); mcibuf.mci_mailer = &nullmailer; mcibuf.mci_out = tfp; define('g', "\201f", e); for (h = e->e_header; h != NULL; h = h->h_link) { extern bool bitzerop(); /* don't output null headers */ if (h->h_value == NULL || h->h_value[0] == '\0') continue; /* don't output resent headers on non-resent messages */ if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) continue; /* expand macros; if null, don't output header at all */ if (bitset(H_DEFAULT, h->h_flags)) { (void) expand(h->h_value, buf, &buf[sizeof buf], e); if (buf[0] == '\0') continue; } /* output this header */ fprintf(tfp, "H"); /* if conditional, output the set of conditions */ if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags)) { int j; (void) putc('?', tfp); for (j = '\0'; j <= '\177'; j++) if (bitnset(j, h->h_mflags)) (void) putc(j, tfp); (void) putc('?', tfp); } /* output the header: expand macros, convert addresses */ if (bitset(H_DEFAULT, h->h_flags)) { fprintf(tfp, "%s: %s\n", h->h_field, buf); } else if (bitset(H_FROM|H_RCPT, h->h_flags)) { bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); FILE *savetrace = TrafficLogFile; TrafficLogFile = NULL; if (bitset(H_FROM, h->h_flags)) oldstyle = FALSE; commaize(h, h->h_value, oldstyle, &mcibuf, e); TrafficLogFile = savetrace; } else fprintf(tfp, "%s: %s\n", h->h_field, h->h_value); } /* ** Clean up. */ if (fflush(tfp) < 0 || fsync(fileno(tfp)) < 0 || ferror(tfp)) { if (newid) syserr("!552 Error writing control file %s", tf); else syserr("!452 Error writing control file %s", tf); } if (!newid) { /* rename (locked) tf to be (locked) qf */ qf = queuename(e, 'q'); if (rename(tf, qf) < 0) syserr("cannot rename(%s, %s), df=%s, uid=%d", tf, qf, e->e_df, geteuid()); /* close and unlock old (locked) qf */ if (e->e_lockfp != NULL) (void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id); e->e_lockfp = tfp; } else qf = tf; errno = 0; e->e_flags |= EF_INQUEUE;# ifdef LOG /* save log info */ if (LogLevel > 79) syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df);# endif /* LOG */ if (tTd(40, 1)) printf("<<<<< done queueing %s <<<<<\n\n", e->e_id); return;}printctladdr(a, tfp) register ADDRESS *a; FILE *tfp;{ char *uname; register struct passwd *pw; register ADDRESS *q; uid_t uid; static ADDRESS *lastctladdr; static uid_t lastuid; /* initialization */ if (a == NULL || a->q_alias == NULL || tfp == NULL) { if (lastctladdr != NULL && tfp != NULL) fprintf(tfp, "C\n"); lastctladdr = NULL; lastuid = 0; return; } /* find the active uid */ q = getctladdr(a); if (q == NULL) uid = 0; else uid = q->q_uid; a = a->q_alias; /* check to see if this is the same as last time */ if (lastctladdr != NULL && uid == lastuid && strcmp(lastctladdr->q_paddr, a->q_paddr) == 0) return; lastuid = uid; lastctladdr = a; if (uid == 0 || (pw = getpwuid(uid)) == NULL) uname = ""; else uname = pw->pw_name; fprintf(tfp, "C%s:%s\n", uname, a->q_paddr);}/*** RUNQUEUE -- run the jobs in the queue.**** Gets the stuff out of the queue in some presumably logical** order and processes them.**** Parameters:** forkflag -- TRUE if the queue scanning should be done in** a child process. We double-fork so it is not our** child and we don't have to clean up after it.**** Returns:** none.**** Side Effects:** runs things in the mail queue.*/ENVELOPE QueueEnvelope; /* the queue run envelope */runqueue(forkflag) bool forkflag;{ register ENVELOPE *e; extern ENVELOPE BlankEnvelope; /* ** If no work will ever be selected, don't even bother reading ** the queue. */ CurrentLA = getla(); /* get load average */ if (shouldqueue(0L, curtime())) { if (Verbose) printf("Skipping queue run -- load average too high\n"); if (forkflag && QueueIntvl != 0) (void) setevent(QueueIntvl, runqueue, TRUE); return; } /* ** See if we want to go off and do other useful work. */ if (forkflag) { int pid;#ifdef SIGCHLD extern void reapchild(); (void) setsignal(SIGCHLD, reapchild);#endif pid = dofork(); if (pid != 0) { /* parent -- pick up intermediate zombie */#ifndef SIGCHLD (void) waitfor(pid);#endif /* SIGCHLD */ if (QueueIntvl != 0) (void) setevent(QueueIntvl, runqueue, TRUE); return; } /* child -- double fork */#ifndef SIGCHLD if (fork() != 0) exit(EX_OK);#else /* SIGCHLD */ (void) setsignal(SIGCHLD, SIG_DFL);#endif /* SIGCHLD */ } setproctitle("running queue: %s", QueueDir);# ifdef LOG if (LogLevel > 69) syslog(LOG_DEBUG, "runqueue %s, pid=%d, forkflag=%d", QueueDir, getpid(), forkflag);# endif /* LOG */ /* ** Release any resources used by the daemon code. */# ifdef DAEMON clrdaemon();# endif /* DAEMON */ /* force it to run expensive jobs */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -