daemontools and 64 bit dev_t
This is about a fix for a small issue with Dan Bernstein’s daemontools package.
Since daemontools was written, some systems have started using 64 bit inode and
device numbers in struct stat
.
Unfortunately, svscan.c
assumes these values are unsigned long
:
struct {
unsigned long dev;
unsigned long ino;
int flagactive;
int flaglog;
int pid; /* 0 if not running */
int pidlog; /* 0 if not running */
int pi[2]; /* defined if flaglog */
} x[SERVICES];
In the case of recent-ish FreeBSD this can cause problems on 32 bit hardware.
On these machines, device and inode numbers are 64 bit, but unsigned long
is only 32 bit.
I discovered this while building a FreeBSD 12 jail in a FreeBSD 13 ZFS system on an old 32 bit machine. (I’m sure this is a very common setup.)
Symptoms
When I started svscan
the normal way, readproctitle
showed errors about
not being able to get locks.
Running svscan in the forground shows this:
# svscan /service
supervise: fatal: unable to acquire qmail-smtpsub/supervise/lock: temporary failure
supervise: fatal: unable to acquire log/supervise/lock: temporary failure
. . .
svscan.c
scans the /service
directory every 5 seconds looking for new
services to start, and to reap any exited child processes.
It maintains a table matching each service directory with its
corresponding supervise
processes.
Whenever a service directory is considered for startup, svscan.c
calls
stat()
on the directory and looks for a match in the table.
If there is a match, nothing more happens; the service is already running.
But if the device and inode numbers returned by stat()
don’t match anything
in the table, new instances of supervise
are started.
When unsigned long
isn’t enough to capture device and inode numbers, no
match is found, even when supervise is already running fine.
So new instances of supervise
are started, and they find they cannot get
the locks, and then exit with the ‘unable to acquire lock’ messages.
Fix
The fix is to change the types of .dev
and .ino
to the standard POSIX
types dev_t
and ino_t
:
struct {
dev_t dev;
ino_t ino;
int flagactive;
int flaglog;
int pid; /* 0 if not running */
int pidlog; /* 0 if not running */
int pi[2]; /* defined if flaglog */
} x[SERVICES];