Re: [EXIM] Serializing local delivery to a procmail pipe

Góra strony
Delete this message
Reply to this message
Autor: Ian Jackson
Data:  
Dla: Tabor J. Wells, exim-users
Temat: Re: [EXIM] Serializing local delivery to a procmail pipe
Tabor J. Wells writes ("Re: [EXIM] Serializing local delivery to a
procmail pipe"):
....
> But that's the problem right now. Procmail is creating so many locks that
> they all just thrash the system waiting on release. The volume of bounces
> is such that quickly there are thousands of processes spawned which are
> piped to procmail which create a lock and spin waiting for it to be
> released. Is there any possibility of adding a serialize option for the
> transport in a future version? Or barring that modelling something like
> the smtp_accept_queue_per_connection option?


Surely your real problem is that procmail isn't doing locking properly
(with fcntl F_SETLKW) and instead is polling on a lockfile ?

If so, the following small C program may be of some help. Try
something like
"|with-lock-ex -w /path/to/lockfile program arg arg ..."
in the appropriate Exim aliasfile or wherever.

Better would be to fix (or reconfigure) procmail, of course.

Ian.

/*
 * File locker
 *
 * Usage: with-lock-ex -<mode> <lockfile> <command> <args>...
 *
 * modes are
 *  w    wait for the lock
 *  f    fail if the lock cannot be acquired
 *  q    silently do nothing if the lock cannot be acquired
 *
 * with-lock-ex will open and lock the lockfile for writing and
 * then feed the remainder of its arguments to exec(2); when
 * that process terminates the fd will be closed and the file
 * unlocked automatically by the kernel.
 *
 * If invoked as with-lock, behaves like with-lock-ex -f (for backward
 * compatibility with an earlier version).
 *
 * This file written by me, Ian Jackson, in 1993, 1994, 1995, 1996,
 * 1998, 1999.  I hereby place it in the public domain.
 */


#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>

static const char *cmd;

static void fail(const char *why) __attribute__((noreturn));

static void fail(const char *why) {
fprintf(stderr,"with-lock-ex %s: %s: %s\n",cmd,why,strerror(errno));
exit(255);
}

int main(int argc, char **argv) {
int fd, mode, um;
long cloexec;
struct flock fl;
const char *p;

  if (argc >= 3 && !strcmp((p= strrchr(argv[0],'/')) ? ++p : argv[0], "with-lock")) {
    mode= 'f';
  } else if (argc < 4 || argv[1][0] != '-' || argv[1][2] ||
         ((mode= argv[1][1]) != 'w' && mode != 'q' && mode != 'f')) {
    fputs("usage: with-lock-ex -w|-q|-f <lockfile> <command> <args>...\n"
      "       with-lock             <lockfile> <command> <args>...\n",
      stderr);
    exit(255);
  } else {
    argv++; argc--;
  }
  cmd= argv[2];
  um= umask(0777); if (um==-1) fail("find umask");
  if (umask(um)==-1) fail("reset umask");


fd= open(argv[1],O_RDWR|O_CREAT,0666&~(um|((um&0222)<<1))); if (fd<0) fail(argv[1]);

  for (;;) {
    fl.l_type= F_WRLCK;
    fl.l_whence= SEEK_SET;
    fl.l_start= 0;
    fl.l_len= 1;
    if (fcntl(fd, mode=='w' ? F_SETLKW : F_SETLK, &fl) != -1) break;
    if (mode=='q' && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EBUSY)) exit(0);
    if (errno != EINTR) fail("could not acquire lock");
  }


cloexec= fcntl(fd, F_GETFD); if (cloexec==-1) fail("fcntl F_GETFD");
cloexec &= ~1;
if (fcntl(fd, F_SETFD, cloexec)==-1) fail("fcntl F_SETFD");

execvp(cmd,argv+2);
fail("unable to execute command");
}

--
*** Exim information can be found at http://www.exim.org/ ***