On Tue, 20 Oct 2026, Andrea Venturoli wrote:

Hello.

I've got:
_ FreeBSD 14.4;
_ a mail jail;
_ cyrus-imapd312 installed inside the jail;
_ a file "/usr/local/etc/rc.conf.d/cyrus_imapd" (inside the jai), with cyrus_imapd_enable="YES" as content.

With this setup Cyrus IMAP has always started at boot (or when restarting the jail).
Upgrade to 15.1 and it doesn't anymore.

However, "service imapd start" does its job.
All the other daemons (mimedefang, rbldnsd, saslauthd, opendkim, etc...), set up in the same way, work.

How do I get around this?
Or, at least, I do I debug this?

I just ran into this after upgrading from 14.5-STABLE to 15.1-STABLE. I have not yet found out why it happens as I have other things needing fixing, but it appears from running a test program that dup(0) is returning 4 instead of 3 when imapd starts, which causes this to fail in master/master.c:

      /* we reserve fds for children to communicate with us, so they
         better be available. */
      for (fd = STATUS_FD; fd <= LISTEN_FD; fd++) {
          close(fd);
          if (dup(0) != fd) fatalf(2, "couldn't dup fd 0: %m");
      }

As you noticed, that is only happening during the jail startup and not when the service is started manually. In my case, I am using the base jail command and not ezjail.

I am attaching a simple workaround for the startup script, but it is not the solution. The workaround is duplicating stdin to file descriptor 3, which placates that test because 3 can be closed and returned in the dup(0) call.

Sean
--
[email protected]
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

int main(void)
{
    int fd, flags, n;

    for (fd = 3; fd <= 5; fd++)
    {
        errno = 0;
        flags = fcntl(fd, F_GETFD);
        printf("before close(%d): flags=%d errno=%d (%s)\n", fd, flags, errno,
               strerror(errno));
        if (close(fd) == -1 && errno != EBADF)
        {
            printf("close: %s\n", strerror(errno));

            return (1);
        }

        errno = 0;
        n = dup(0);
        printf("expected=%d, dup(0)=%d, errno=%d (%s)\n", fd, n, errno,
               strerror(errno));
        if (n != fd)
        {
            printf("Mismatch at fd %d\n", fd);

            return (1);
        }
    }

    return (0);
}
diff --git a/mail/cyrus-imapd38/files/imapd.in 
b/mail/cyrus-imapd38/files/imapd.in
index 89e6c2ce8ea1..443eb947cae2 100644
--- a/mail/cyrus-imapd38/files/imapd.in
+++ b/mail/cyrus-imapd38/files/imapd.in
@@ -25,9 +25,14 @@ rcvar=cyrus_imapd_enable
 command="%%PREFIX%%/cyrus/libexec/master"
 pidfile="/var/run/cyrus-master.pid"
 required_files="%%PREFIX%%/etc/cyrus.conf %%PREFIX%%/etc/imapd.conf"
+start_cmd="cyrus_imapd_start"
 stop_postcmd="cyrus_imapd_poststop"
 extra_commands="reload"
 
+cyrus_imapd_start() {
+       limits -C daemon ${command} ${cyrus_imapd_flags} 3<&0
+}
+
 cyrus_imapd_poststop() {
        /bin/rm -f ${pidfile}
 }

Reply via email to