From: Miroslav Lichvar Date: Wed, 5 Feb 2025 08:30:46 +0000 (+0100) Subject: main: add support for systemd notification X-Git-Tag: 4.7-pre1~49 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cb1118456b9fb1cbd3c953dbf970aa40d9dc1d29;p=thirdparty%2Fchrony.git main: add support for systemd notification On Linux, if the NOTIFY_SOCKET variable is set, send a "READY=1" and "STOPPING=1" message to the Unix domain socket after initialization and before finalization respectively. This is used with the systemd "notify" service type as documented in the sd_notity(3) man page. It's a recommended alternative to the "forking" service type, which does not need the PID file to determine the main process. Support pathname Unix sockets only. Abstract sockets don't seem to be used by systemd for notifications since version 212. Switch the example services to the notify type, but keep the PID file. It's still useful to prevent start of other chronyd instances. systemd doesn't seem to care about the content of the file and should just remove it in case chronyd didn't terminate cleanly. Suggested-by: Luca Boccassi --- diff --git a/doc/chronyd.adoc b/doc/chronyd.adoc index 887be485..dfabd3e0 100644 --- a/doc/chronyd.adoc +++ b/doc/chronyd.adoc @@ -217,6 +217,14 @@ client requests until the service is able to handle them. The service manager sets the LISTEN_FDS environment variable to the number of passed file descriptors. +*NOTIFY_SOCKET*:: +The systemd service manager sets this variable for services of the *notify* +type. *chronyd* sends a message to this socket when it it is fully initialised +and ready to accept commands (e.g. from *chronyc*), with the clock already set +if using the *-s* option or *initstepslew* directive. It is an alternative to +the *forking* service type, which does not need the PID file. *chronyd* needs +to be started with the *-n* or *-d* option to not fork. + == FILES _@SYSCONFDIR@/chrony.conf_ diff --git a/examples/chronyd-restricted.service b/examples/chronyd-restricted.service index 30ba7d9f..18946210 100644 --- a/examples/chronyd-restricted.service +++ b/examples/chronyd-restricted.service @@ -12,10 +12,10 @@ Conflicts=chronyd.service ntpd.service systemd-timesyncd.service ConditionCapability=CAP_SYS_TIME [Service] -Type=forking +Type=notify PIDFile=/run/chrony/chronyd.pid EnvironmentFile=-/etc/sysconfig/chronyd -ExecStart=/usr/sbin/chronyd -U $OPTIONS +ExecStart=/usr/sbin/chronyd -n -U $OPTIONS User=chrony LogsDirectory=chrony diff --git a/examples/chronyd.service b/examples/chronyd.service index a42eb92a..e3224543 100644 --- a/examples/chronyd.service +++ b/examples/chronyd.service @@ -6,10 +6,10 @@ Conflicts=ntpd.service systemd-timesyncd.service ConditionCapability=CAP_SYS_TIME [Service] -Type=forking +Type=notify PIDFile=/run/chrony/chronyd.pid EnvironmentFile=-/etc/sysconfig/chronyd -ExecStart=/usr/sbin/chronyd $OPTIONS +ExecStart=/usr/sbin/chronyd -n $OPTIONS CapabilityBoundingSet=~CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE CapabilityBoundingSet=~CAP_BLOCK_SUSPEND CAP_KILL CAP_LEASE CAP_LINUX_IMMUTABLE diff --git a/main.c b/main.c index 864dec2d..bf9c66bf 100644 --- a/main.c +++ b/main.c @@ -107,11 +107,40 @@ delete_pidfile(void) /* ================================================== */ +static void +notify_system_manager(int start) +{ +#ifdef LINUX + /* The systemd protocol is documented in the sd_notify(3) man page */ + const char *message, *path = getenv("NOTIFY_SOCKET"); + int sock_fd; + + if (!path) + return; + + if (path[0] != '/') + LOG_FATAL("Unsupported notification socket"); + + message = start ? "READY=1" : "STOPPING=1"; + + sock_fd = SCK_OpenUnixDatagramSocket(path, NULL, 0); + + if (sock_fd < 0 || SCK_Send(sock_fd, message, strlen(message), 0) != strlen(message)) + LOG_FATAL("Could not send notification"); + + SCK_CloseSocket(sock_fd); +#endif +} + +/* ================================================== */ + void MAI_CleanupAndExit(void) { if (!initialised) exit(exit_status); + notify_system_manager(0); + LCL_CancelOffsetCorrection(); SRC_DumpSources(); @@ -215,6 +244,8 @@ post_init_ntp_hook(void *anything) REF_SetMode(ref_mode); } + notify_system_manager(1); + /* Send an empty message to the foreground process so it can exit. If that fails, indicating the process was killed, exit too. */ if (!LOG_NotifyParent(""))