[comp.mail.sendmail] too many open files

fletcher@cs.utexas.edu (Fletcher Mattox) (12/10/90)

My 5.64 runs out of file descriptors when there is lots of mail
queued up for a host which has been unreachable for longer than
three days (my timeout).  It happens to the process running the
queue when it tries to return mail to the sender.  The senders'
addresses all resolve to the same mailer.  After it successfully
returns mail to several of the senders, it is stopped dead in
its tracks with something like this:

Dec  8 19:11:32 cs sendmail[16583]: AE16583: SYSERR: queueup: cannot create temp file tfAE16583: Too many open files

Anyone know the cause of this?

Craig_Everhart@TRANSARC.COM (12/11/90)

About four months ago, I was distributing a sendmail patch that helped
eliminate duplicate messages that would occur when sendmail restarted
its work on a given df*/qf* pair before it had finished the previous run
(e.g. after a crash).  The patch caused sendmail to rewrite the qf* file
after each successful delivery.

Now, this patch worked fine in 5.61-based sendmails.  But in at least
5.64 and beyond, the interface to one of the routines that the patch
used (queueup) changed, so that it opens a new file on each call and
leaves it open, and the unmodified patch can fail because it didn't know
to close any files.  If you think that this is the root of your
problems, I'll track down the fix to the patched version, which a friend
of mine has been running in his configuration with no problems.

Hm: it wasn't hard to find.  Here's the change, if this was your
problem.  Down in sendall() in deliver.c, the guts of the checkpoint
algorithm is an iterated call to queueup() that looks something like:

		{
			int estat;
			if (DoingMore) queueup(e, TRUE, FALSE, TRUE);
			DoingMore = FALSE;
			estat = deliver(e, q);	/* Queueup if any delivered */
			if (estat == EX_OK) DoingMore = TRUE;
		}

I believe that the thing to do is this:

		{
			int estat; FILE *newfile;
			if (DoingMore) {
				newfile = queueup(e, TRUE, FALSE, TRUE);
				if (newfile) {
					(void) fclose(lockfp);
					lockfp = newfile;
				}
			}
			DoingMore = FALSE;
			estat = deliver(e, q);	/* Queueup if any delivered */
			if (estat == EX_OK) DoingMore = TRUE;
		}

This will call queueup() again, but will correctly close the pointer to
the old qf file that it just deleted (replacing it with the
newly-written tf file).

Good luck.

		Craig