Current systemd versions have a NotifyAccess key for services, which
defaults to "main", meaning systemd checks the credentials of the process
that writes to the socket and rejects if it's not the PID it spawned. Since
sdnotify-wrapper runs as a (grand)child of daemon, this means its READY=1
message gets rejected, and the service gets stuck as "activating...".
This inverts the parent-child relationship so users don't have to tweak
this option to "all" (meaning daemon + whatever is running in the same
Unitâ„¢) manually. The MAINPID half of the message tells it to look after the
real daemon.
If only there was an easy, portable way of ensuring only a process, its
descendants, or trusted local services had access to the communication
channel for readiness notification, without a central registry of
everything running in the system...
diff --git a/sdnotify-wrapper.c b/sdnotify-wrapper.c
index 71e588d..3e30827 100644
--- a/sdnotify-wrapper.c
+++ b/sdnotify-wrapper.c
@@ -32,17 +32,12 @@
Options:
-d fd: the daemon will write its notification on descriptor fd.
Default is 1.
- -f: do not doublefork. Use if the daemon waits for children it does
- not know it has (for instance, superservers do this). When in doubt,
- do not use that option, or you may have a zombie hanging around.
-t timeout: if the daemon has not sent a notification after timeout
milliseconds, give up and exit; systemd will not be notified.
- -k: keep the NOTIFY_SOCKET environment variable when execing into the
- daemon. By default, the variable is unset: the daemon should not need it.
+ -k: keep the NOTIFY_SOCKET environment variable when spawning the daemon.
+ By default, the variable is unset: the daemon should not need it.
Notes:
- sdnotify-wrapper does not change the daemon's pid. It runs as a
- (grand)child of the daemon.
If the NOTIFY_SOCKET environment variable is not set, sdnotify-wrapper
does nothing - it only execs into the daemon.
sdnotify-wrapper is more liberal than sd_notify(). It will accept
@@ -70,7 +65,7 @@
#include <skalibs/socket.h>
#include <skalibs/exec.h>
-#define USAGE "sdnotify-wrapper [ -d fd ] [ -f ] [ -t timeout ] [ -k ] prog..."
+#define USAGE "sdnotify-wrapper [ -d fd ] [ -t timeout ] [ -k ] prog..."
#define dieusage() strerr_dieusage(100, USAGE)
#define VAR "NOTIFY_SOCKET"
@@ -100,7 +95,7 @@ static inline void notify_systemd (pid_t pid, char const *socketpath)
close(fd) ;
}
-static inline int run_child (int fd, unsigned int timeout, pid_t pid, char const *s)
+static inline int run_parent (int fd, unsigned int timeout, pid_t pid, char const *s)
{
char dummy[4096] ;
iopause_fd x = { .fd = fd, .events = IOPAUSE_READ } ;
@@ -130,18 +125,17 @@ int main (int argc, char const *const *argv)
char const *s = getenv(VAR) ;
unsigned int fd = 1 ;
unsigned int timeout = 0 ;
- int df = 1, keep = 0 ;
+ int keep = 0 ;
PROG = "sdnotify-wrapper" ;
{
subgetopt l = SUBGETOPT_ZERO ;
for (;;)
{
- int opt = subgetopt_r(argc, argv, "d:ft:k", &l) ;
+ int opt = subgetopt_r(argc, argv, "d:t:k", &l) ;
if (opt == -1) break ;
switch (opt)
{
case 'd' : if (!uint0_scan(l.arg, &fd)) dieusage() ; break ;
- case 'f' : df = 0 ; break ;
case 't' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ;
case 'k' : keep = 1 ; break ;
default : dieusage() ;
@@ -154,17 +148,15 @@ int main (int argc, char const *const *argv)
if (!s) xexec(argv) ;
else
{
- pid_t parent = getpid() ;
pid_t child ;
int p[2] ;
if (pipe(p) < 0) strerr_diefu1sys(111, "pipe") ;
- child = df ? doublefork() : fork() ;
- if (child < 0) strerr_diefu1sys(111, df ? "doublefork" : "fork") ;
- else if (!child)
+ child = fork() ;
+ if (child < 0) strerr_diefu1sys(111, "fork") ;
+ else if (child)
{
- PROG = "sdnotify-wrapper (child)" ;
close(p[1]) ;
- return run_child(p[0], timeout, parent, s) ;
+ return run_parent(p[0], timeout, child, s) ;
}
close(p[0]) ;
if (fd_move((int)fd, p[1]) < 0) strerr_diefu1sys(111, "move descriptor") ;