Hi,
I'm writing and testing unit files for systemd, the new init for Fedora
16 and later and I stumbled upon race condition when bmc-watchdog and
ipmidetectd does double fork.
Systemd expects that the binary (e.g. bmc-watchdog) exits *after* the
final daemon process is forked, i.e. both forks are finished. FreeIPMI
code calls exit() in the parent right after the first fork, which might
be before the second fork(). Systemd then sometimes marks the service as
failed.
Attached you can find simple patch, fixing both daemons using a pipe for
communication. I tested only ipmidetectd daemon, I'm still looking for
some HW to test bmc-watchdog (we usually don't run Fedora on such HW).
Jan
diff -up freeipmi-1.1.1/bmc-watchdog/bmc-watchdog.c.systemd freeipmi-1.1.1/bmc-watchdog/bmc-watchdog.c
--- freeipmi-1.1.1/bmc-watchdog/bmc-watchdog.c.systemd 2012-01-02 20:26:09.000000000 +0100
+++ freeipmi-1.1.1/bmc-watchdog/bmc-watchdog.c 2012-01-06 16:28:55.966295836 +0100
@@ -1677,6 +1677,10 @@ _daemon_init ()
unsigned int i;
pid_t pid;
FILE *pidfile;
+ int fds[2];
+
+ if ( pipe(fds) < 0 )
+ _err_exit ("pipe: %s", strerror (errno));
if ( (pidfile = fopen(BMC_WATCHDOG_PIDFILE, "w")) == NULL )
_err_exit ("fopen: %s", strerror (errno));
@@ -1684,7 +1688,14 @@ _daemon_init ()
if ((pid = fork ()) < 0)
_err_exit ("fork: %s", strerror (errno));
if (pid)
- exit (0); /* parent terminates */
+ {
+ /* parent terminates */
+ char buf;
+ read(fds[0], &buf, 1);
+ close(fds[1]);
+ close(fds[0]);
+ exit (0);
+ }
setsid ();
@@ -1706,6 +1717,9 @@ _daemon_init ()
umask (0);
+ write(fds[1], "a", 1);
+ close(fds[1]);
+ close(fds[0]);
for (i = 0; i < 64; i++)
close (i);
}
diff -up freeipmi-1.1.1/ipmidetectd/ipmidetectd.c.systemd freeipmi-1.1.1/ipmidetectd/ipmidetectd.c
--- freeipmi-1.1.1/ipmidetectd/ipmidetectd.c.systemd 2012-01-02 20:26:13.000000000 +0100
+++ freeipmi-1.1.1/ipmidetectd/ipmidetectd.c 2012-01-06 16:28:09.309420665 +0100
@@ -58,12 +58,22 @@ _daemon_init (void)
/* Based on code in Unix network programming by R. Stevens */
pid_t pid;
unsigned int i;
+ int fds[2];
+ if (pipe(fds) < 0)
+ IPMIDETECTD_EXIT (("pipe: %s", strerror (errno)));
if ((pid = fork ()) < 0)
IPMIDETECTD_EXIT (("fork: %s", strerror (errno)));
- if (pid != 0) /* Terminate Parent */
- exit (0);
+ if (pid != 0)
+ {
+ /* Terminate Parent */
+ char buf;
+ read(fds[0], &buf, 1);
+ close(fds[1]);
+ close(fds[0]);
+ exit (0);
+ }
setsid ();
@@ -79,6 +89,9 @@ _daemon_init (void)
chdir ("/");
umask (0);
+ write(fds[1], "a", 1);
+ close(fds[1]);
+ close(fds[0]);
for (i = 0; i < 64; i++)
close (i);
_______________________________________________
Freeipmi-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/freeipmi-devel