Skip to main content

gatel_core/
sd_notify.rs

1//! Minimal systemd `sd_notify` implementation.
2//!
3//! Sends state notifications to systemd via the `$NOTIFY_SOCKET` datagram
4//! socket. This is a no-op when `$NOTIFY_SOCKET` is not set (i.e., when not
5//! running under systemd with `Type=notify`).
6
7/// Notify systemd about a service state change.
8///
9/// Common states:
10/// - `"READY=1"` — service startup is complete
11/// - `"RELOADING=1"` — service is reloading its configuration
12/// - `"STOPPING=1"` — service is beginning its shutdown
13/// - `"STATUS=..."` — free-form status string for `systemctl status`
14///
15/// This is a no-op on non-Linux platforms or when `$NOTIFY_SOCKET` is unset.
16#[cfg(target_os = "linux")]
17pub fn sd_notify(state: &str) {
18    use std::os::unix::ffi::OsStrExt;
19    use std::os::unix::net::UnixDatagram;
20
21    let Some(socket_path) = std::env::var_os("NOTIFY_SOCKET") else {
22        return;
23    };
24
25    let Ok(sock) = UnixDatagram::unbound() else {
26        return;
27    };
28
29    let path_bytes = socket_path.as_os_str().as_bytes();
30
31    if path_bytes.starts_with(b"@") {
32        // Abstract socket (Linux-specific): replace leading '@' with '\0'.
33        use std::os::linux::net::SocketAddrExt;
34        use std::os::unix::net::SocketAddr;
35        if let Ok(addr) = SocketAddr::from_abstract_name(&path_bytes[1..]) {
36            let _ = sock.send_to_addr(state.as_bytes(), &addr);
37        }
38    } else {
39        let _ = sock.send_to(state.as_bytes(), &socket_path);
40    }
41}
42
43/// No-op on non-Linux platforms.
44#[cfg(not(target_os = "linux"))]
45pub fn sd_notify(_state: &str) {}