diff --git a/man/rules/meson.build b/man/rules/meson.build
index ca3b471281..13d2bd9b58 100644
--- a/man/rules/meson.build
+++ b/man/rules/meson.build
@@ -808,7 +808,8 @@ manpages = [
'sd_notifyf',
'sd_pid_notify',
'sd_pid_notify_with_fds',
- 'sd_pid_notifyf'],
+ 'sd_pid_notifyf',
+ 'sd_pid_notifyf_with_fds'],
''],
['sd_path_lookup', '3', ['sd_path_lookup_strv'], ''],
['sd_pid_get_owner_uid',
diff --git a/man/sd_notify.xml b/man/sd_notify.xml
index f93542e329..b82d145860 100644
--- a/man/sd_notify.xml
+++ b/man/sd_notify.xml
@@ -22,6 +22,7 @@
sd_pid_notifysd_pid_notifyfsd_pid_notify_with_fds
+ sd_pid_notifyf_with_fdssd_notify_barrierNotify service manager about start-up completion and other service status changes
@@ -67,6 +68,16 @@
unsigned n_fds
+
+ int sd_pid_notifyf_with_fds
+ pid_t pid
+ int unset_environment
+ const int *fds
+ size_t n_fds
+ const char *format
+ …
+
+
int sd_notify_barrierint unset_environment
@@ -326,12 +337,12 @@
able to properly attribute the message to the unit, and thus will ignore it, even if
NotifyAccess= is set for it.
- Hence, to eliminate all race conditions involving lookup of the client's unit and attribution of notifications
- to units correctly, sd_notify_barrier() may be used. This call acts as a synchronization point
- and ensures all notifications sent before this call have been picked up by the service manager when it returns
- successfully. Use of sd_notify_barrier() is needed for clients which are not invoked by the
- service manager, otherwise this synchronization mechanism is unnecessary for attribution of notifications to the
- unit.
+ Hence, to eliminate all race conditions involving lookup of the client's unit and attribution of
+ notifications to units correctly, sd_notify_barrier() may be used. This call acts as
+ a synchronization point and ensures all notifications sent before this call have been picked up by the
+ service manager when it returns successfully. Use of sd_notify_barrier() is needed
+ for clients which are not invoked by the service manager, otherwise this synchronization mechanism is
+ unnecessary for attribution of notifications to the unit.sd_notifyf() is similar to sd_notify() but takes a
printf()-like format string plus arguments.
@@ -352,6 +363,11 @@
that file descriptors sent to the service manager on a message without FDSTORE=1 are
immediately closed on reception.
+ sd_pid_notifyf_with_fds() is a combination of
+ sd_pid_notify_with_fds() and sd_notifyf(), i.e. it accepts both
+ a PID and a set of file descriptors as input, and processes a format string to generate the state
+ string.
+
sd_notify_barrier() allows the caller to synchronize against reception of
previously sent notification messages and uses the BARRIER=1 command. It takes a
relative timeout value in microseconds which is passed to
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index 53db234a0c..76fa1e0e32 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -818,4 +818,5 @@ global:
sd_session_get_username;
sd_session_get_start_time;
sd_uid_get_login_time;
+ sd_pid_notifyf_with_fds;
} LIBSYSTEMD_253;
diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c
index f2f295d6e4..eec6fb64ef 100644
--- a/src/libsystemd/sd-daemon/sd-daemon.c
+++ b/src/libsystemd/sd-daemon/sd-daemon.c
@@ -667,6 +667,36 @@ _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
return sd_pid_notify(0, unset_environment, p);
}
+int sd_pid_notifyf_with_fds(
+ pid_t pid,
+ int unset_environment,
+ const int *fds, size_t n_fds,
+ const char *format, ...) {
+
+ _cleanup_free_ char *p = NULL;
+ int r;
+
+ /* Paranoia check: we traditionally used 'unsigned' as array size, but we nowadays more correctly use
+ * 'size_t'. sd_pid_notifyf_with_fds() and sd_pid_notify_with_fds() are from different eras, hence
+ * differ in this. Let's catch resulting incompatibilites early, even though they are pretty much
+ * theoretic only */
+ if (n_fds > UINT_MAX)
+ return -E2BIG;
+
+ if (format) {
+ va_list ap;
+
+ va_start(ap, format);
+ r = vasprintf(&p, format, ap);
+ va_end(ap);
+
+ if (r < 0 || !p)
+ return -ENOMEM;
+ }
+
+ return sd_pid_notify_with_fds(pid, unset_environment, p, fds, n_fds);
+}
+
_public_ int sd_booted(void) {
/* We test whether the runtime unit file directory has been
* created. This takes place in mount-setup.c, so is
diff --git a/src/systemd/sd-daemon.h b/src/systemd/sd-daemon.h
index 6f88cf02fa..a8b40ff1f8 100644
--- a/src/systemd/sd-daemon.h
+++ b/src/systemd/sd-daemon.h
@@ -290,6 +290,11 @@ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) _s
*/
int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds);
+/*
+ Combination of sd_pid_notifyf() and sd_pid_notify_with_fds()
+*/
+int sd_pid_notifyf_with_fds(pid_t pid, int unset_environment, const int *fds, size_t n_fds, const char *format, ...) _sd_printf_(5,6);
+
/*
Returns > 0 if synchronization with systemd succeeded. Returns < 0
on error. Returns 0 if $NOTIFY_SOCKET was not set. Note that the