patches and low-level development discussion
 help / color / mirror / code / Atom feed
From: Demi Marie Obenour <demiobenour@gmail.com>
To: Spectrum OS Development <devel@spectrum-os.org>
Cc: Demi Marie Obenour <demiobenour@gmail.com>, Alyssa Ross <hi@alyssa.is>
Subject: [PATCH v6 1/2] tools: Add adapter tool for services using sd_notify
Date: Mon, 03 Nov 2025 03:29:21 -0500	[thread overview]
Message-ID: <20251103-udev-v6-1-704649b85d6d@gmail.com> (raw)
In-Reply-To: <20251103-udev-v6-0-704649b85d6d@gmail.com>

This adapts programs using sd_notify for use with s6 readiness
notification.  stdin and stdout are hard-coded for simplicity.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
---
systemd readiness notification has two
strict advantages over the s6 version:

1. It allows reliable reloading.
2. It allows providing a status message that the service manager
   can show in status output.

s6 would actually benefit from both of these features.
---
Changes since v4:
- Use CC0 for the trivial Meson file.
- Use -D_GNU_SOURCE instead of #define _GNU_SOURCE 1.
- Use a global variable for the iovec.
- Use ISC license for the C code in case s6 wants to use it.
- Remove unneeded MSG_DONTWAIT.
- Remove unneeded check for EAGAIN and EWOULDBLOCK when poll() has
  already indicated that the file descriptor is ready.

Changes since v1:

- Hard-code file descriptors.
- Run wrapper as background process.
- Massively reduce code size.
- Use // instead of /* */ for comments.
- Check that the notification FD is a pipe and that the listening socket
  is a socket.
- Rely on s6-ipc-socketbinder to create the listening socket.
- Do not unlink the listening socket.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
---
 tools/default.nix                           |   1 +
 tools/meson.build                           |   1 +
 tools/sd-notify-adapter/meson.build         |   4 ++
 tools/sd-notify-adapter/sd-notify-adapter.c | 107 ++++++++++++++++++++++++++++
 4 files changed, 113 insertions(+)

diff --git a/tools/default.nix b/tools/default.nix
index 398f57038d3f9fdec47b72850755e289f225f339..36a9a8c84de9f83e31981d3d47fab27e98f6ae5a 100644
--- a/tools/default.nix
+++ b/tools/default.nix
@@ -76,6 +76,7 @@ stdenv.mkDerivation (finalAttrs: {
       ./lsvm
       ./start-vmm
       ./subprojects
+      ./sd-notify-adapter
     ] ++ lib.optionals driverSupport [
       ./xdp-forwarder
     ]));
diff --git a/tools/meson.build b/tools/meson.build
index 186008dbc9dd2b63adbce7475c375fb0de5c2c6a..5d0ae81042fd3d77646594500f32cb1d48a6af0c 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -27,6 +27,7 @@ if get_option('host')
 
   subdir('lsvm')
   subdir('start-vmm')
+  subdir('sd-notify-adapter')
 endif
 
 if get_option('app')
diff --git a/tools/sd-notify-adapter/meson.build b/tools/sd-notify-adapter/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..906fbde673105fd65436b34802f1bcc74e9f823e
--- /dev/null
+++ b/tools/sd-notify-adapter/meson.build
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com>
+
+executable('sd-notify-adapter', 'sd-notify-adapter.c', c_args : ['-D_GNU_SOURCE'], install: true)
diff --git a/tools/sd-notify-adapter/sd-notify-adapter.c b/tools/sd-notify-adapter/sd-notify-adapter.c
new file mode 100644
index 0000000000000000000000000000000000000000..734f018da605e4359d3fa6422a01effbd9e878ea
--- /dev/null
+++ b/tools/sd-notify-adapter/sd-notify-adapter.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: ISC
+// SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#define ARRAY_SIZE(s) (sizeof(s)/sizeof(s[0]))
+
+enum {
+	socket_fd,
+	notification_fd,
+};
+
+struct iovec msg;
+
+#define READY "READY=1"
+#define READY_SIZE (sizeof(READY) - 1)
+
+static void process_notification(void)
+{
+	ssize_t first_recv_size = recv(socket_fd, msg.iov_base, msg.iov_len,
+	                               MSG_TRUNC | MSG_PEEK);
+	if (first_recv_size == -1) {
+		if (errno == EINTR)
+			return; // signal caught
+		err(EXIT_FAILURE, "recv from notification socket");
+	}
+	size_t size = (size_t)first_recv_size;
+	if (size == 0)
+		return; // avoid arithmetic on NULL pointer
+	if (size > msg.iov_len) {
+		msg.iov_base = realloc(msg.iov_base, size);
+		if (msg.iov_base == NULL)
+			err(EXIT_FAILURE, "allocation failure");
+		msg.iov_len = size;
+	}
+	ssize_t second_recv_size = recv(socket_fd, msg.iov_base, msg.iov_len,
+	                                MSG_CMSG_CLOEXEC | MSG_TRUNC);
+	if (second_recv_size == -1) {
+		if (errno == EINTR)
+			return;
+		err(EXIT_FAILURE, "recv from notification socket");
+	}
+	assert(first_recv_size == second_recv_size);
+	for (char *next, *cursor = msg.iov_base, *end = cursor + size;
+	     cursor != NULL; cursor = (next == NULL ? NULL : next + 1)) {
+		next = memchr(cursor, '\n', (size_t)(end - cursor));
+		size_t message_size = (size_t)((next == NULL ? end : next) - cursor);
+		if (message_size == READY_SIZE &&
+		    memcmp(cursor, READY, READY_SIZE) == 0) {
+			ssize_t write_size = write(notification_fd, "\n", 1);
+			if (write_size != 1)
+				err(EXIT_FAILURE, "writing to notification descriptor");
+			exit(0);
+		}
+	}
+}
+
+int main(int argc, char **)
+{
+	if (argc != 1)
+		errx(EXIT_FAILURE, "stdin is listening socket, stdout is notification pipe");
+	for (;;) {
+		struct pollfd p[] = {
+			{
+				.fd = socket_fd,
+				.events = POLLIN,
+				.revents = 0,
+			},
+			{
+				.fd = notification_fd,
+				.events = 0,
+				.revents = 0,
+			},
+		};
+		int r = poll(p, ARRAY_SIZE(p), -1);
+		if (r < 0) {
+			if (errno == EINTR)
+				continue;
+			err(EXIT_FAILURE, "poll");
+		}
+		if (p[0].revents) {
+			if (p[0].revents & POLLERR)
+				errx(EXIT_FAILURE, "unexpected POLLERR");
+			if (p[0].revents & POLLIN)
+				process_notification();
+		}
+		if (p[1].revents)
+			errx(EXIT_FAILURE, "s6 closed its pipe before the child was ready");
+	}
+}

-- 
2.51.2


  reply	other threads:[~2025-11-03  8:30 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-11-03  8:29 [PATCH v6 0/2] Switch from mdevd to systemd-udevd in root filesystem Demi Marie Obenour
2025-11-03  8:29 ` Demi Marie Obenour [this message]
2025-11-03  8:33   ` [PATCH v6 1/2] tools: Add adapter tool for services using sd_notify Demi Marie Obenour
2025-11-06  9:41     ` Alyssa Ross
2025-11-06  9:49   ` Alyssa Ross
2025-11-03  8:29 ` [PATCH v6 2/2] host/rootfs: Switch to systemd-udevd Demi Marie Obenour
2025-11-06  9:55   ` Alyssa Ross
  -- strict thread matches above, loose matches on Subject: below --
2025-11-07 19:00 [PATCH v6 0/2] Switch from mdevd to systemd-udevd in root filesystem Demi Marie Obenour
2025-11-07 19:00 ` [PATCH v6 1/2] tools: Add adapter tool for services using sd_notify Demi Marie Obenour
2025-11-09 13:58   ` Alyssa Ross

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251103-udev-v6-1-704649b85d6d@gmail.com \
    --to=demiobenour@gmail.com \
    --cc=devel@spectrum-os.org \
    --cc=hi@alyssa.is \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://spectrum-os.org/git/crosvm
	https://spectrum-os.org/git/doc
	https://spectrum-os.org/git/mktuntap
	https://spectrum-os.org/git/nixpkgs
	https://spectrum-os.org/git/spectrum
	https://spectrum-os.org/git/ucspi-vsock
	https://spectrum-os.org/git/www

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).