From a44a29534c5cdd5ae18823fe97d09da6d4bd4f24 Mon Sep 17 00:00:00 2001 From: Peter Volkov Date: Sat, 25 Jul 2026 20:47:25 +0300 Subject: [PATCH] sysv-initctl: avoid busy loop without FIFO clients sysv-initctl opened /run/initctl with O_RDONLY | O_NONBLOCK and called read() directly in a loop. Immediately after startup, no client has the FIFO open for writing, so read() returns zero instead of waiting. The daemon treated this as a short request and retried continuously, consuming CPU and flooding syslog with "read: short count". This can be reproduced on a system using openrc-init by starting the compatibility daemon without connecting an initctl client: rc-service sysv-initctl start pid=$(pgrep -x sysv-initctl) strace -p "$pid" -e read top -p "$pid" Before this change, strace repeatedly reports read() returning zero. Open the read end nonblocking during setup, keep a dummy write end open, and then make the reader blocking. This allows the daemon to sleep in read() while no clients are connected. Mark both descriptors close-on-exec. --- src/sysv-initctl/initctl.c | 39 +++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/sysv-initctl/initctl.c b/src/sysv-initctl/initctl.c index 8340a2a08..6b17dd7d8 100644 --- a/src/sysv-initctl/initctl.c +++ b/src/sysv-initctl/initctl.c @@ -14,6 +14,43 @@ static bool init_halt = false; +static int open_fifo(const char *path) +{ + int dummy_writer; + int flags; + int reader; + int saved_errno; + + reader = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (reader == -1) + return -1; + + /* + * Keep the dummy writer open for the lifetime of the process so that the + * reader does not see EOF while no clients are connected. Open the reader + * nonblocking so that open() does not wait for an initial client. Once the + * dummy writer is in place, make reads blocking so that the daemon sleeps + * until data arrives. + */ + dummy_writer = open(path, O_WRONLY | O_NONBLOCK | O_CLOEXEC); + if (dummy_writer == -1) + goto fail; + + flags = fcntl(reader, F_GETFL); + if (flags == -1 || fcntl(reader, F_SETFL, flags & ~O_NONBLOCK) == -1) + goto fail; + + return reader; + +fail: + saved_errno = errno; + if (dummy_writer != -1) + close(dummy_writer); + close(reader); + errno = saved_errno; + return -1; +} + static void sysvinit_runlevel(int runlevel) { const char *cmd; @@ -78,7 +115,7 @@ int main(void) { return 1; } symlink("/run/initctl", "/dev/initctl"); - if ((fifo = open("/run/initctl", O_RDONLY | O_NONBLOCK)) == -1) { + if ((fifo = open_fifo("/run/initctl")) == -1) { syslog(LOG_ERR, "open: %s", strerror(errno)); return 1; }