summaryrefslogtreecommitdiff
path: root/src/queue.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/queue.c')
-rw-r--r--src/queue.c256
1 files changed, 166 insertions, 90 deletions
diff --git a/src/queue.c b/src/queue.c
index d48efb1..b02fc08 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -1,44 +1,22 @@
/*
- * Copyright (c) 1983, 1995-1997 Eric P. Allman
+ * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* 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.
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
*
- * 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
#if QUEUE
-static char sccsid[] = "@(#)queue.c 8.175 (Berkeley) 10/4/97 (with queueing)";
+static char sccsid[] = "@(#)queue.c 8.211 (Berkeley) 1/25/1999 (with queueing)";
#else
-static char sccsid[] = "@(#)queue.c 8.175 (Berkeley) 10/4/97 (without queueing)";
+static char sccsid[] = "@(#)queue.c 8.211 (Berkeley) 1/25/1999 (without queueing)";
#endif
#endif /* not lint */
@@ -163,7 +141,7 @@ queueup(e, announce)
newid ? " (new id)" : "");
if (tTd(40, 3))
{
- extern void printenvflags();
+ extern void printenvflags __P((ENVELOPE *));
printf(" e_flags=");
printenvflags(e);
@@ -225,10 +203,10 @@ queueup(e, announce)
fprintf(tfp, "V%d\n", QF_VERSION);
/* output creation time */
- fprintf(tfp, "T%ld\n", e->e_ctime);
+ fprintf(tfp, "T%ld\n", (long) e->e_ctime);
/* output last delivery time */
- fprintf(tfp, "K%ld\n", e->e_dtime);
+ fprintf(tfp, "K%ld\n", (long) e->e_dtime);
/* output number of delivery attempts */
fprintf(tfp, "N%d\n", e->e_ntries);
@@ -239,8 +217,16 @@ queueup(e, announce)
/* output inode number of data file */
/* XXX should probably include device major/minor too */
if (e->e_dfino != -1)
- fprintf(tfp, "I%d/%d/%ld\n",
- major(e->e_dfdev), minor(e->e_dfdev), e->e_dfino);
+ {
+ if (sizeof e->e_dfino > sizeof(long))
+ fprintf(tfp, "I%d/%d/%s\n",
+ major(e->e_dfdev), minor(e->e_dfdev),
+ quad_to_string(e->e_dfino));
+ else
+ fprintf(tfp, "I%d/%d/%lu\n",
+ major(e->e_dfdev), minor(e->e_dfdev),
+ (unsigned long) e->e_dfino);
+ }
/* output body type */
if (e->e_bodytype != NULL)
@@ -360,10 +346,9 @@ queueup(e, announce)
define('g', "\201f", e);
for (h = e->e_header; h != NULL; h = h->h_link)
{
- extern bool bitzerop();
+ extern bool bitzerop __P((BITMAP));
- /* don't output null headers */
- if (h->h_value == NULL || h->h_value[0] == '\0')
+ if (h->h_value == NULL)
continue;
/* don't output resent headers on non-resent messages */
@@ -477,7 +462,7 @@ printctladdr(a, tfp)
register ADDRESS *q;
uid_t uid;
gid_t gid;
- static ADDRESS *lastctladdr;
+ static ADDRESS *lastctladdr = NULL;
static uid_t lastuid;
/* initialization */
@@ -599,12 +584,10 @@ runqueue(forkflag, verbose)
{
pid_t pid;
extern SIGFUNC_DECL intsig __P((int));
-#ifdef SIGCHLD
extern SIGFUNC_DECL reapchild __P((int));
blocksignal(SIGCHLD);
(void) setsignal(SIGCHLD, reapchild);
-#endif
pid = dofork();
if (pid == -1)
@@ -626,31 +609,26 @@ runqueue(forkflag, verbose)
if (pid != 0)
{
/* parent -- pick up intermediate zombie */
-#ifndef SIGCHLD
- (void) waitfor(pid);
-#else
(void) blocksignal(SIGALRM);
- proc_list_add(pid);
+ proc_list_add(pid, "Queue runner");
(void) releasesignal(SIGALRM);
releasesignal(SIGCHLD);
-#endif /* SIGCHLD */
if (QueueIntvl != 0)
(void) setevent(QueueIntvl, runqueueevent, 0);
return TRUE;
}
/* child -- double fork and clean up signals */
+ clrcontrol();
proc_list_clear();
-#ifndef SIGCHLD
- if (fork() != 0)
- exit(EX_OK);
-#else /* SIGCHLD */
+
+ /* Add parent process as first child item */
+ proc_list_add(getpid(), "Queue runner child process");
releasesignal(SIGCHLD);
(void) setsignal(SIGCHLD, SIG_DFL);
-#endif /* SIGCHLD */
(void) setsignal(SIGHUP, intsig);
}
- setproctitle("running queue: %s", QueueDir);
+ sm_setproctitle(TRUE, "running queue: %s", QueueDir);
if (LogLevel > 69)
sm_syslog(LOG_DEBUG, NOQID,
@@ -775,7 +753,6 @@ runqueue(forkflag, verbose)
else
{
pid_t pid;
- extern pid_t dowork();
if (Verbose)
{
@@ -796,7 +773,7 @@ runqueue(forkflag, verbose)
/* exit without the usual cleanup */
e->e_id = NULL;
- finis();
+ finis(TRUE, ExitStat);
/*NOTREACHED*/
return TRUE;
}
@@ -842,20 +819,40 @@ orderq(doall)
{
register struct dirent *d;
register WORK *w;
+ register char *p;
DIR *f;
register int i;
int wn = -1;
int wc;
-
+ QUEUE_CHAR *check;
+
if (tTd(41, 1))
{
printf("orderq:\n");
- if (QueueLimitId != NULL)
- printf("\tQueueLimitId = %s\n", QueueLimitId);
- if (QueueLimitSender != NULL)
- printf("\tQueueLimitSender = %s\n", QueueLimitSender);
- if (QueueLimitRecipient != NULL)
- printf("\tQueueLimitRecipient = %s\n", QueueLimitRecipient);
+
+ check = QueueLimitId;
+ while (check != NULL)
+ {
+ printf("\tQueueLimitId = %s\n",
+ check->queue_match);
+ check = check->queue_next;
+ }
+
+ check = QueueLimitSender;
+ while (check != NULL)
+ {
+ printf("\tQueueLimitSender = %s\n",
+ check->queue_match);
+ check = check->queue_next;
+ }
+
+ check = QueueLimitRecipient;
+ while (check != NULL)
+ {
+ printf("\tQueueLimitRecipient = %s\n",
+ check->queue_match);
+ check = check->queue_next;
+ }
}
/* clear out old WorkQ */
@@ -886,9 +883,9 @@ orderq(doall)
while ((d = readdir(f)) != NULL)
{
FILE *cf;
- register char *p;
+ int qfver = 0;
char lbuf[MAXNAME + 1];
- extern bool strcontainedin();
+ extern bool strcontainedin __P((char *, char *));
if (tTd(41, 50))
printf("orderq: checking %s\n", d->d_name);
@@ -898,10 +895,26 @@ orderq(doall)
continue;
if (strlen(d->d_name) > MAXQFNAME)
+ {
+ if (Verbose)
+ printf("orderq: %s too long, %d max characters\n",
+ d->d_name, MAXQFNAME);
+ if (LogLevel > 0)
+ sm_syslog(LOG_ALERT, NOQID,
+ "orderq: %s too long, %d max characters",
+ d->d_name, MAXQFNAME);
continue;
+ }
- if (QueueLimitId != NULL &&
- !strcontainedin(QueueLimitId, d->d_name))
+ check = QueueLimitId;
+ while (check != NULL)
+ {
+ if (strcontainedin(check->queue_match, d->d_name))
+ break;
+ else
+ check = check->queue_next;
+ }
+ if (QueueLimitId != NULL && check == NULL)
continue;
#ifdef PICKY_QF_NAME_CHECK
@@ -984,10 +997,9 @@ orderq(doall)
i |= NEED_R;
while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
{
- int qfver = 0;
- char *p;
int c;
- extern bool strcontainedin();
+ time_t age;
+ extern bool strcontainedin __P((char *, char *));
p = strchr(lbuf, '\n');
if (p != NULL)
@@ -1032,18 +1044,37 @@ orderq(doall)
}
else
p = &lbuf[1];
- if (strcontainedin(QueueLimitRecipient, p))
+ check = QueueLimitRecipient;
+ while (check != NULL)
+ {
+ if (strcontainedin(check->queue_match,
+ p))
+ break;
+ else
+ check = check->queue_next;
+ }
+ if (check != NULL)
i &= ~NEED_R;
break;
case 'S':
- if (QueueLimitSender != NULL &&
- strcontainedin(QueueLimitSender, &lbuf[1]))
- i &= ~NEED_S;
+ check = QueueLimitSender;
+ while (check != NULL)
+ {
+ if (strcontainedin(check->queue_match,
+ &lbuf[1]))
+ break;
+ else
+ check = check->queue_next;
+ }
+ if (check != NULL)
+ i &= ~NEED_S;
break;
case 'K':
- if ((curtime() - (time_t) atol(&lbuf[1])) < MinQueueAge)
+ age = curtime() - (time_t) atol(&lbuf[1]);
+ if (age >= 0 && MinQueueAge > 0 &&
+ age < MinQueueAge)
w->w_tooyoung = TRUE;
break;
@@ -1076,8 +1107,8 @@ orderq(doall)
if (QueueSortOrder == QS_BYHOST)
{
- extern workcmpf1();
- extern workcmpf2();
+ extern int workcmpf1();
+ extern int workcmpf2();
/*
** Sort the work directory for the first time,
@@ -1102,12 +1133,14 @@ orderq(doall)
w = &WorkList[i];
while (++i < wc)
{
+ extern int sm_strcasecmp __P((char *, char *));
+
if (WorkList[i].w_host == NULL &&
w->w_host == NULL)
WorkList[i].w_lock = TRUE;
else if (WorkList[i].w_host != NULL &&
w->w_host != NULL &&
- strcmp(WorkList[i].w_host, w->w_host) == 0)
+ sm_strcasecmp(WorkList[i].w_host, w->w_host) == 0)
WorkList[i].w_lock = TRUE;
else
break;
@@ -1123,7 +1156,7 @@ orderq(doall)
}
else if (QueueSortOrder == QS_BYTIME)
{
- extern workcmpf3();
+ extern int workcmpf3();
/*
** Simple sort based on submission time only.
@@ -1133,7 +1166,7 @@ orderq(doall)
}
else
{
- extern workcmpf0();
+ extern int workcmpf0();
/*
** Simple sort based on queue priority only.
@@ -1163,6 +1196,7 @@ orderq(doall)
if (WorkList != NULL)
free(WorkList);
WorkList = NULL;
+ WorkListSize = 0;
if (tTd(40, 1))
{
@@ -1279,6 +1313,7 @@ workcmpf1(a, b)
register WORK *b;
{
int i;
+ extern int sm_strcasecmp __P((char *, char *));
/* host name */
if (a->w_host != NULL && b->w_host == NULL)
@@ -1286,7 +1321,7 @@ workcmpf1(a, b)
else if (a->w_host == NULL && b->w_host != NULL)
return -1;
if (a->w_host != NULL && b->w_host != NULL &&
- (i = strcmp(a->w_host, b->w_host)))
+ (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
return i;
/* lock status */
@@ -1320,6 +1355,7 @@ workcmpf2(a, b)
register WORK *b;
{
int i;
+ extern int sm_strcasecmp __P((char *, char *));
/* lock status */
if (a->w_lock != b->w_lock)
@@ -1331,7 +1367,7 @@ workcmpf2(a, b)
else if (a->w_host == NULL && b->w_host != NULL)
return -1;
if (a->w_host != NULL && b->w_host != NULL &&
- (i = strcmp(a->w_host, b->w_host)))
+ (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
return i;
/* job priority */
@@ -1392,7 +1428,7 @@ dowork(id, forkflag, requeueflag, e)
register ENVELOPE *e;
{
register pid_t pid;
- extern bool readqf();
+ extern bool readqf __P((ENVELOPE *));
if (tTd(40, 1))
printf("dowork(%s)\n", id);
@@ -1418,6 +1454,16 @@ dowork(id, forkflag, requeueflag, e)
{
/* child -- error messages to the transcript */
QuickAbort = OnlyOneError = FALSE;
+
+ /*
+ ** Since the delivery may happen in a child and the
+ ** parent does not wait, the parent may close the
+ ** maps thereby removing any shared memory used by
+ ** the map. Therefore, open a copy of the maps for
+ ** the delivery process.
+ */
+
+ initmaps(FALSE, e);
}
}
else
@@ -1449,7 +1495,7 @@ dowork(id, forkflag, requeueflag, e)
disconnect(1, e);
OpMode = MD_DELIVER;
}
- setproctitle("%s: from queue", id);
+ sm_setproctitle(TRUE, "%s: from queue", id);
if (LogLevel > 76)
sm_syslog(LOG_DEBUG, e->e_id,
"dowork, pid=%d",
@@ -1461,11 +1507,11 @@ dowork(id, forkflag, requeueflag, e)
/* read the queue control file -- return if locked */
if (!readqf(e))
{
- if (tTd(40, 4))
+ if (tTd(40, 4) && e->e_id != NULL)
printf("readqf(%s) failed\n", e->e_id);
e->e_id = NULL;
if (forkflag)
- exit(EX_OK);
+ finis(FALSE, EX_OK);
else
return 0;
}
@@ -1481,7 +1527,7 @@ dowork(id, forkflag, requeueflag, e)
/* finish up and exit */
if (forkflag)
- finis();
+ finis(TRUE, ExitStat);
else
dropenvelope(e, TRUE);
}
@@ -1748,10 +1794,10 @@ readqf(e)
/* if this has been tried recently, let it be */
if (e->e_ntries > 0 &&
+ MinQueueAge > 0 && e->e_dtime <= curtime() &&
curtime() < e->e_dtime + MinQueueAge)
{
char *howlong = pintvl(curtime() - e->e_dtime, TRUE);
- extern void unlockqueue();
if (Verbose || tTd(40, 8))
printf("%s: too young (%s)\n",
@@ -1825,7 +1871,7 @@ readqf(e)
default:
syserr("readqf: %s: line %d: bad line \"%s\"",
- qf, LineNumber, shortenstring(bp, 203));
+ qf, LineNumber, shortenstring(bp, MAXSHORTSTR));
fclose(qfp);
loseqfile(e, "unrecognized line");
return FALSE;
@@ -2100,6 +2146,13 @@ printqueue()
** locked, open-for-write file pointer in the envelope.
*/
+#ifndef ENOLCK
+# define ENOLCK -1
+#endif
+#ifndef ENOSPC
+# define ENOSPC -1
+#endif
+
char *
queuename(e, type)
register ENVELOPE *e;
@@ -2133,6 +2186,7 @@ queuename(e, type)
while (c1 < '~' || c2 < 'Z')
{
int i;
+ int attempts = 0;
if (c2 >= 'Z')
{
@@ -2151,12 +2205,34 @@ queuename(e, type)
continue;
syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
qf, QueueDir, geteuid());
- exit(EX_UNAVAILABLE);
+ finis(FALSE, EX_UNAVAILABLE);
}
- if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB))
+ do
{
- e->e_lockfp = fdopen(i, "w");
+ if (attempts > 0)
+ sleep(attempts);
+ e->e_lockfp = 0;
+ if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB))
+ {
+ e->e_lockfp = fdopen(i, "w");
+ break;
+ }
+ } while ((errno == ENOLCK || errno == ENOSPC) &&
+ attempts++ < 4);
+
+ /* Successful lock */
+ if (e->e_lockfp != 0)
break;
+
+#if !HASFLOCK
+ if (errno != EAGAIN && errno != EACCES)
+#else
+ if (errno != EWOULDBLOCK)
+#endif
+ {
+ syserr("queuename: Cannot lock \"%s\" in \"%s\" (euid=%d)",
+ qf, QueueDir, geteuid());
+ finis(FALSE, EX_OSERR);
}
/* a reader got the file; abandon it and try again */
@@ -2166,7 +2242,7 @@ queuename(e, type)
{
syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
qf, QueueDir, geteuid());
- exit(EX_OSERR);
+ finis(FALSE, EX_OSERR);
}
e->e_id = newstr(&qf[2]);
define('i', e->e_id, e);