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) {}