diff options
| author | glass <glass@NetBSD.org> | 1993-10-30 00:33:33 +0000 |
|---|---|---|
| committer | glass <glass@NetBSD.org> | 1993-10-30 00:33:33 +0000 |
| commit | d498f75b4b0e52e1626687c81da4da55b2ec45b3 (patch) | |
| tree | 091dc67bc1b2ee448992e04aeaf4236a02c73ac0 /usr.sbin/sendmail/src/queue.c | |
| parent | 6d9dd525b6705e31cccff26fdb7c4c843c9ce37a (diff) | |
updated from 8.3 to 8.6.3.
known problems: sendmail/cf/cf required 'obj' directory
Diffstat (limited to 'usr.sbin/sendmail/src/queue.c')
| -rw-r--r-- | usr.sbin/sendmail/src/queue.c | 241 |
1 files changed, 154 insertions, 87 deletions
diff --git a/usr.sbin/sendmail/src/queue.c b/usr.sbin/sendmail/src/queue.c index b47a979df4e..160570114e2 100644 --- a/usr.sbin/sendmail/src/queue.c +++ b/usr.sbin/sendmail/src/queue.c @@ -36,15 +36,12 @@ #ifndef lint #ifdef QUEUE -/*static char sccsid[] = "from: @(#)queue.c 8.3 (Berkeley) 7/13/93 (with queueing)";*/ -static char rcsid[] = "$Id: queue.c,v 1.5 1993/08/01 17:56:27 mycroft Exp $"; +static char sccsid[] = "@(#)queue.c 8.24 (Berkeley) 10/23/93 (with queueing)"; #else -/*static char sccsid[] = "from: @(#)queue.c 8.3 (Berkeley) 7/13/93 (without queueing)";*/ -static char rcsid[] = "$Id: queue.c,v 1.5 1993/08/01 17:56:27 mycroft Exp $"; +static char sccsid[] = "@(#)queue.c 8.24 (Berkeley) 10/23/93 (without queueing)"; #endif #endif /* not lint */ -# include <signal.h> # include <errno.h> # include <pwd.h> # include <dirent.h> @@ -103,43 +100,68 @@ queueup(e, queueall, announce) ** 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. @@ -150,11 +172,12 @@ notemp: 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; @@ -249,7 +272,7 @@ notemp: 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); @@ -321,9 +344,12 @@ notemp: 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; @@ -331,12 +357,16 @@ notemp: 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; } @@ -352,7 +382,7 @@ printctladdr(a, tfp) 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"); @@ -367,10 +397,7 @@ printctladdr(a, tfp) 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 && @@ -446,7 +473,7 @@ runqueue(forkflag) #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); @@ -457,7 +484,7 @@ runqueue(forkflag) if (fork() != 0) exit(EX_OK); #else /* SIGCHLD */ - (void) signal(SIGCHLD, SIG_DFL); + (void) setsignal(SIGCHLD, SIG_DFL); #endif /* SIGCHLD */ } @@ -477,6 +504,9 @@ runqueue(forkflag) clrdaemon(); # endif /* DAEMON */ + /* force it to run expensive jobs */ + NoConnect = FALSE; + /* ** Create ourselves an envelope */ @@ -519,7 +549,12 @@ runqueue(forkflag) } 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); @@ -599,6 +634,7 @@ orderq(doall) while ((d = readdir(f)) != NULL) { FILE *cf; + register char *p; char lbuf[MAXNAME]; extern bool strcontainedin(); @@ -615,8 +651,16 @@ orderq(doall) ** 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); @@ -777,19 +821,20 @@ workcmpf(a, b) ** 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)) @@ -801,19 +846,19 @@ dowork(id, forkflag, requeueflag, e) 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 @@ -826,9 +871,15 @@ dowork(id, forkflag, requeueflag, e) /* 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 = FALSE; + if (forkflag) + { + disconnect(1, e); + OpMode = MD_DELIVER; + } # ifdef LOG if (LogLevel > 76) syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id, @@ -839,7 +890,7 @@ dowork(id, forkflag, requeueflag, e) 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); @@ -864,21 +915,16 @@ dowork(id, forkflag, requeueflag, e) else dropenvelope(e); } - else if (!requeueflag) - { - /* - ** Parent -- pick up results. - */ - - errno = 0; - (void) waitfor(i); - } + e->e_id = NULL; + return pid; } /* ** 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. @@ -889,8 +935,9 @@ dowork(id, forkflag, requeueflag, e) */ bool -readqf(e) +readqf(e, announcefile) register ENVELOPE *e; + bool announcefile; { register FILE *qfp; ADDRESS *ctladdr; @@ -917,6 +964,21 @@ readqf(e) 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. */ @@ -931,7 +993,7 @@ readqf(e) return FALSE; } - if (st.st_uid != geteuid() || (st.st_mode & 07777) != FileMode) + if (st.st_uid != geteuid()) { # ifdef LOG if (LogLevel > 0) @@ -942,42 +1004,41 @@ readqf(e) # endif /* LOG */ if (tTd(40, 8)) printf("readqf(%s): bogus file\n", qf); - fclose(qfp); 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; @@ -1007,7 +1068,7 @@ readqf(e) break; case 'M': /* message */ - e->e_message = newstr(&bp[1]); + /* ignore this; we want a new message next time */ break; case 'S': /* sender */ @@ -1111,12 +1172,12 @@ printqueue() ** Check for permission to print the queue */ - if (bitset(PRIV_RESTRMAILQ, PrivacyFlags) && RealUid != 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) @@ -1177,14 +1238,15 @@ printqueue() 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"); @@ -1346,11 +1408,11 @@ queuename(e, type) { 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; @@ -1361,14 +1423,19 @@ queuename(e, type) } 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); @@ -1447,8 +1514,8 @@ setctluser(user) ** 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. |
