qmail timestamp in human readable form

Convert qmail tag to timestamp

tail /var/log/qmail1/smtpd/current | tai64nlocal

Add debugging symbols to qmail build

The build of qmail is a little different that the build process of most applications. That makes adding debugging information a little bit tricky. At first, I simply removed the O2 flag from the conf-cc file. I was surprised to find that the compiler still didn’t include the debugging information.

After looking at the code for a little while, it occured to me that the .o file contained the debugging information, but the final binary did not. It turned out that the conf-ld file contained a ‘-s’ flag which stripped debugging inforamtion from the object files during linking. Ug! Removing the ‘-s’ flag fixed the problem.

echo "cc -g" > conf-cc
echo "cc" > conf-ld
make setup check

What is conf-split

conf-split is used by qmail to store queued messages in a set of subdirectories. The larger the conf-split file, the more subdirectories. The reason it is important is because operating systems typically have difficulty storing large numbers of files in a single directory. Conf-split can reduce the number of messages stored in any individual directory, and that can increase performance on larger systems. Due to qmail’s hashing algorithm, the number for conf-split should always be prime.

According to Charles Cazabon, “It does — a large series of random numbers, modulo some number I, will result in an even distribution of results if and only if I is prime. If I isn’t prime, the results are skewed noticeably towards the low end.”

qmail-local Hangs Under RHEL with Maildir++ and NFS Mounted Maildir directories

I’m not sure if the problem is caused by a bug in glibc or a bug in maildir++. The problem occurs when qmail-local attempts to read a broken maildirsize file (removed by another process after being opened) in maildir++’s read5120 function.

static int read5120(char* fn, char* buf, int *len)
        int fd;
        int r;

        if ( ( fd = open(fn, O_RDWR | O_NDELAY | O_APPEND,
                                        0600) ) == -1 ) {
                if ( errno == error_noent ) return -1;

        *len = 0;
        for (;;) {
                r = read(fd, buf, 5120 - *len);
                if (r == -1) if (errno == error_intr) continue;
                if (*len >= 5120) { /* file to big */
                        return -1;
                if (r == 0) return fd; /* no more data */
                *len += r;
                buf += r;

Apparently, when the maildirsize file disappears in one thread (or server when NFS mounted), read returns a -1 but fails to set errno. Since read5120 requires that errno is set before it considers the returned -1 an error, it treats the -1 as ‘the number of bytes read.’ This forces qmail-local into an almost infinite loop (until ‘r’ overflows).

As of this date, the most recent RHEL glibc does not set errno so updating glibc on RedHat systems doesn’t help at all.

My guess, though I have yet to implment it, is that I could simply remove the ‘errmo == errno_intr’ comparison to fix the bug. If anybody has any suggestiosn, I would be more that happy to post them here.