#ifndef lint
#ifdef QUEUE
-static char sccsid[] = "@(#)queue.c 8.1 (Berkeley) 6/7/93 (with queueing)";
+static char sccsid[] = "@(#)queue.c 8.27 (Berkeley) 10/29/93 (with queueing)";
#else
-static char sccsid[] = "@(#)queue.c 8.1 (Berkeley) 6/7/93 (without queueing)";
+static char sccsid[] = "@(#)queue.c 8.27 (Berkeley) 10/29/93 (without queueing)";
#endif
#endif /* not lint */
-# include <signal.h>
# include <errno.h>
# include <pwd.h>
# include <dirent.h>
** Create control file.
*/
- newid = (e->e_id == NULL);
+ 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)
- {
- tfp = e->e_lockfp;
- }
- else
+
+ /* if newid, just write the qf file directly (instead of tf file) */
+ if (!newid)
{
/* get a locked tf file */
- for (i = 100; --i >= 0; )
+ for (i = 0; i < 128; i++)
{
fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode);
if (fd < 0)
{
- if (errno == EEXIST)
- continue;
-notemp:
- syserr("!queueup: cannot create temp file %s", tf);
+ if (errno != EEXIST)
+ break;
+#ifdef LOG
+ if (LogLevel > 0 && (i % 32) == 0)
+ syslog(LOG_ALERT, "queueup: cannot create %s: %s",
+ tf, errstring(errno));
+#endif
+ continue;
}
- if (lockfile(fd, tf, LOCK_EX|LOCK_NB))
+ 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);
- sleep(i);
- }
- if (fd < 0)
- goto notemp;
- tfp = fdopen(fd, "w");
+ 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)
+ syserr("!queueup: cannot create queue temp file %s", tf);
}
if (tTd(40, 1))
- printf("queueing %s\n", e->e_id);
+ 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.
register FILE *dfp;
extern putbody();
- e->e_df = newstr(queuename(e, 'd'));
+ e->e_df = queuename(e, 'd');
+ e->e_df = newstr(e->e_df);
fd = open(e->e_df, O_WRONLY|O_CREAT, FileMode);
- if (fd < 0)
- syserr("!queueup: cannot create %s", e->e_df);
- dfp = fdopen(fd, "w");
+ if (fd < 0 || (dfp = fdopen(fd, "w")) == NULL)
+ syserr("!queueup: cannot create data temp file %s",
+ e->e_df);
(*e->e_putbody)(dfp, FileMailer, e, NULL);
(void) xfclose(dfp, "queueup dfp", e->e_id);
e->e_putbody = putbody;
e->e_to = q->q_paddr;
message("queued");
if (LogLevel > 8)
- logdelivery(NULL, NULL, "queued", e);
+ logdelivery(NULL, NULL, "queued", NULL, e);
e->e_to = NULL;
}
if (tTd(40, 1))
bzero((char *) &nullmailer, sizeof nullmailer);
nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
- nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
+ nullmailer.m_se_rwset = nullmailer.m_sh_rwset = 0;
nullmailer.m_eol = "\n";
define('g', "\201f", e);
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, tfp, oldstyle,
&nullmailer, e);
+
+ TrafficLogFile = savetrace;
}
else
fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);
** Clean up.
*/
- fflush(tfp);
- fsync(fileno(tfp));
- if (ferror(tfp))
+ if (fflush(tfp) < 0 || fsync(fileno(tfp)) < 0 || ferror(tfp))
{
if (newid)
syserr("!552 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", tf, qf, e->e_df);
+
+ /* 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;
}
static uid_t lastuid;
/* initialization */
- if (a == NULL || tfp == NULL)
+ if (a == NULL || a->q_alias == NULL || tfp == NULL)
{
if (lastctladdr != NULL && tfp != NULL)
fprintf(tfp, "C\n");
uid = 0;
else
uid = q->q_uid;
-
- /* if a is an alias, use that for printing */
- if (a->q_alias != NULL)
- a = a->q_alias;
+ a = a->q_alias;
/* check to see if this is the same as last time */
if (lastctladdr != NULL && uid == lastuid &&
#ifndef SIGCHLD
(void) waitfor(pid);
#else /* SIGCHLD */
- (void) signal(SIGCHLD, reapchild);
+ (void) setsignal(SIGCHLD, reapchild);
#endif /* SIGCHLD */
if (QueueIntvl != 0)
(void) setevent(QueueIntvl, runqueue, TRUE);
if (fork() != 0)
exit(EX_OK);
#else /* SIGCHLD */
- (void) signal(SIGCHLD, SIG_DFL);
+ (void) setsignal(SIGCHLD, SIG_DFL);
#endif /* SIGCHLD */
}
clrdaemon();
# endif /* DAEMON */
+ /* force it to run expensive jobs */
+ NoConnect = FALSE;
+
/*
** Create ourselves an envelope
*/
}
else
{
- dowork(w->w_name + 2, ForkQueueRuns, FALSE, e);
+ pid_t pid;
+ extern pid_t dowork();
+
+ pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e);
+ errno = 0;
+ (void) waitfor(pid);
}
free(w->w_name);
free((char *) w);
while ((d = readdir(f)) != NULL)
{
FILE *cf;
+ register char *p;
char lbuf[MAXNAME];
extern bool strcontainedin();
** both old and new type ids.
*/
- i = strlen(d->d_name);
- if (i != 9 && i != 10)
+ p = d->d_name + 2;
+ if (isupper(p[0]) && isupper(p[2]))
+ p += 3;
+ else if (isupper(p[1]))
+ p += 2;
+ else
+ p = d->d_name;
+ for (i = 0; isdigit(*p); p++)
+ i++;
+ if (i < 5 || *p != '\0')
{
if (Verbose)
printf("orderq: bogus qf name %s\n", d->d_name);
** e - the envelope in which to run it.
**
** Returns:
-** none.
+** process id of process that is running the queue job.
**
** Side Effects:
** The work request is satisfied if possible.
*/
+pid_t
dowork(id, forkflag, requeueflag, e)
char *id;
bool forkflag;
bool requeueflag;
register ENVELOPE *e;
{
- register int i;
+ register pid_t pid;
extern bool readqf();
if (tTd(40, 1))
if (forkflag)
{
- i = fork();
- if (i < 0)
+ pid = fork();
+ if (pid < 0)
{
syserr("dowork: cannot fork");
- return;
+ return 0;
}
}
else
{
- i = 0;
+ pid = 0;
}
- if (i == 0)
+ if (pid == 0)
{
/*
** CHILD
/* set basic modes, etc. */
(void) alarm(0);
clearenvelope(e, FALSE);
- e->e_flags |= EF_QUEUERUN;
+ e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
e->e_errormode = EM_MAIL;
e->e_id = id;
+ GrabTo = UseErrorsTo = FALSE;
+ if (forkflag)
+ {
+ disconnect(1, e);
+ OpMode = MD_DELIVER;
+ }
# ifdef LOG
if (LogLevel > 76)
syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id,
e->e_header = NULL;
/* read the queue control file -- return if locked */
- if (!readqf(e))
+ if (!readqf(e, !requeueflag))
{
if (tTd(40, 4))
printf("readqf(%s) failed\n", e->e_id);
else
dropenvelope(e);
}
- else if (!requeueflag)
- {
- /*
- ** Parent -- pick up results.
- */
-
- errno = 0;
- (void) waitfor(i);
- }
+ e->e_id = NULL;
+ return pid;
}
\f/*
** READQF -- read queue file and set up environment.
**
** Parameters:
** e -- the envelope of the job to run.
+** announcefile -- if set, announce the name of the queue
+** file in error messages.
**
** Returns:
** TRUE if it successfully read the queue file.
*/
bool
-readqf(e)
+readqf(e, announcefile)
register ENVELOPE *e;
+ bool announcefile;
{
register FILE *qfp;
ADDRESS *ctladdr;
return FALSE;
}
+ if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
+ {
+ /* being processed by another queuer */
+ if (tTd(40, 8))
+ printf("readqf(%s): locked\n", qf);
+ if (Verbose)
+ printf("%s: locked\n", e->e_id);
+# ifdef LOG
+ if (LogLevel > 19)
+ syslog(LOG_DEBUG, "%s: locked", e->e_id);
+# endif /* LOG */
+ (void) fclose(qfp);
+ return FALSE;
+ }
+
/*
** Check the queue file for plausibility to avoid attacks.
*/
return FALSE;
}
- if (st.st_uid != geteuid() || (st.st_mode & 07777) != FileMode)
+ if (st.st_uid != geteuid())
{
# ifdef LOG
if (LogLevel > 0)
# endif /* LOG */
if (tTd(40, 8))
printf("readqf(%s): bogus file\n", qf);
+ rename(qf, queuename(e, 'Q'));
fclose(qfp);
return FALSE;
}
- if (!lockfile(fileno(qfp), qf, LOCK_EX|LOCK_NB))
+ if (st.st_size == 0)
{
- /* being processed by another queuer */
- if (tTd(40, 8))
- printf("readqf(%s): locked\n", qf);
- if (Verbose)
- printf("%s: locked\n", e->e_id);
-# ifdef LOG
- if (LogLevel > 19)
- syslog(LOG_DEBUG, "%s: locked", e->e_id);
-# endif /* LOG */
- (void) fclose(qfp);
+ /* must be a bogus file -- just remove it */
+ (void) unlink(qf);
+ fclose(qfp);
return FALSE;
}
- if (st.st_size == 0)
+ if (st.st_nlink == 0)
{
- /* must be a bogus file -- just remove it */
- (void) unlink(qf);
+ /*
+ ** Race condition -- we got a file just as it was being
+ ** unlinked. Just assume it is zero length.
+ */
+
fclose(qfp);
return FALSE;
}
- /* save this lock */
+ /* good file -- save this lock */
e->e_lockfp = qfp;
/* do basic system initialization */
initsys(e);
- FileName = qf;
+ if (announcefile)
+ FileName = qf;
LineNumber = 0;
+ e->e_flags |= EF_GLOBALERRS;
+ OpMode = MD_DELIVER;
if (Verbose)
printf("\nRunning %s\n", e->e_id);
ctladdr = NULL;
break;
case 'M': /* message */
- e->e_message = newstr(&bp[1]);
+ /* ignore this; we want a new message next time */
break;
case 'S': /* sender */
default:
syserr("readqf: bad line \"%s\"", e->e_id,
LineNumber, bp);
- break;
+ fclose(qfp);
+ rename(qf, queuename(e, 'Q'));
+ return FALSE;
}
if (bp != buf)
** Check for permission to print the queue
*/
- if (bitset(PRIV_RESTRMAILQ, PrivacyFlags) && getuid() != 0)
+ if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
{
struct stat st;
# ifdef NGROUPS
int n;
- int gidset[NGROUPS];
+ GIDSET_T gidset[NGROUPS];
# endif
if (stat(QueueDir, &st) < 0)
}
if (n < 0)
# else
- if (getgid() != st.st_gid)
+ if (RealGid != st.st_gid)
# endif
{
usrerr("510 You are not permitted to see the queue");
char message[MAXLINE];
char bodytype[MAXNAME];
+ printf("%8s", w->w_name + 2);
f = fopen(w->w_name, "r");
if (f == NULL)
{
+ printf(" (job completed)\n");
errno = 0;
continue;
}
- printf("%8s", w->w_name + 2);
- if (!lockfile(fileno(f), w->w_name, LOCK_SH|LOCK_NB))
+ if (!lockfile(fileno(f), w->w_name, NULL, LOCK_SH|LOCK_NB))
printf("*");
else if (shouldqueue(w->w_pri, w->w_ctime))
printf("X");
{
if (errno == EEXIST)
continue;
- syserr("queuename: Cannot create \"%s\" in \"%s\"",
- qf, QueueDir);
+ syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
+ qf, QueueDir, geteuid());
exit(EX_UNAVAILABLE);
}
- if (lockfile(i, qf, LOCK_EX|LOCK_NB))
+ if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB))
{
e->e_lockfp = fdopen(i, "w");
break;
}
if (c1 >= '~' && c2 >= 'Z')
{
- syserr("queuename: Cannot create \"%s\" in \"%s\"",
- qf, QueueDir);
+ syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
+ qf, QueueDir, geteuid());
exit(EX_OSERR);
}
e->e_id = newstr(&qf[2]);
define('i', e->e_id, e);
if (tTd(7, 1))
printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
+ if (tTd(7, 9))
+ {
+ printf(" lockfd=");
+ dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
+ }
# ifdef LOG
if (LogLevel > 93)
syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
** See if this clears our concept of controlling user.
*/
- if (user == NULL)
- user = "";
+ if (user == NULL || *user == '\0')
+ return NULL;
/*
** Set up addr fields for controlling user.