This uses the cached copy of LISTEN_FDNAMES to find the first file
descriptorlabel with a matching label.

Note that if two file descriptors are given the same label this will
ignore all but the first.

This is another step toward addressing
https://gitlab.com/qemu-project/qemu/-/issues/3011

Signed-off-by: Daniel Kahn Gillmor <d...@fifthhorseman.net>
---
 include/qemu/systemd.h | 15 +++++++++++++++
 util/systemd.c         | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/include/qemu/systemd.h b/include/qemu/systemd.h
index f0ea1266d5..6b3f9a97ff 100644
--- a/include/qemu/systemd.h
+++ b/include/qemu/systemd.h
@@ -23,4 +23,19 @@
  */
 unsigned int check_socket_activation(void);
 
+
+/*
+ * Check if socket activation indicates named file descriptor based on
+ * the colon-delimited LISTEN_FDNAMES.  The "label" must not be NULL,
+ * and should be a simple text string that does not contain a colon,
+ * matching the FileDescriptorName= directive in systemd.socket(5)
+ *
+ * It is acceptable to ask for the empty string as a label.
+ *
+ * Returns -1 if no socket activation is in use, or if the label does
+ * not match any file descriptor.  Otherwise, returns the lowest
+ * numeric value for a file descriptor matching the label exactly.
+ */
+int socket_activated_fd_by_label(const char *label);
+
 #endif
diff --git a/util/systemd.c b/util/systemd.c
index 1eca2bd69f..7bf4a847b2 100644
--- a/util/systemd.c
+++ b/util/systemd.c
@@ -97,9 +97,44 @@ unsigned int check_socket_activation(void)
     return nr_fds;
 }
 
+int socket_activated_fd_by_label(const char *label)
+{
+    int nr_fds = check_socket_activation();
+    if (!nr_fds) {
+        return -1;
+    }
+    int curfd;
+    const char *nameend;
+    const char *nameptr;
+    size_t labellen, namelen;
+
+    labellen = strlen(label);
+    curfd = 0;
+    nameptr = fdnames;
+    do {
+        nameend = strchr(nameptr, ':');
+        if (nameend) {
+            namelen = nameend - nameptr;
+            nameend++;
+        } else {
+            namelen = strlen(nameptr);
+        }
+        if (labellen == namelen && memcmp(nameptr, label, namelen) == 0) {
+            return curfd + FIRST_SOCKET_ACTIVATION_FD;
+        }
+        curfd++;
+        nameptr = nameend;
+    } while (nameptr && curfd < nr_fds);
+    return -1;
+}
+
 #else /* !_WIN32 */
 unsigned int check_socket_activation(void)
 {
     return 0;
 }
+unsigned int socket_activated_fd_by_label(const char *label)
+{
+    return 0;
+}
 #endif
-- 
2.47.2


Reply via email to