systemd: add fd-store support
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
2783f062a6
commit
fb1a75d48f
@ -1,5 +1,6 @@
|
||||
use std::ffi::CString;
|
||||
use std::ffi::{c_char, c_void, CStr, CString};
|
||||
use std::io;
|
||||
use std::os::fd::{AsFd, AsRawFd, RawFd};
|
||||
|
||||
use crate::sys;
|
||||
|
||||
@ -41,3 +42,86 @@ impl SystemdNotify {
|
||||
pub fn barrier(timeout: u64) -> Result<(), io::Error> {
|
||||
sys::check_call(unsafe { sys::sd_notify_barrier(0, timeout) }).map(drop)
|
||||
}
|
||||
|
||||
/// Store a set of file descriptors in systemd's file descriptor store for this service.
|
||||
pub fn store_fds(name: &str, fds: &[RawFd]) -> Result<(), io::Error> {
|
||||
validate_name(name)?;
|
||||
|
||||
let message = CString::new(format!("FDSTORE=1\nFDNAME={name}"))?;
|
||||
|
||||
sys::check_call(unsafe {
|
||||
sys::sd_pid_notify_with_fds(0, 0, message.as_ptr(), fds.as_ptr(), fds.len() as _)
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
|
||||
/// Store a file descriptor in systemd's file descriptor store for this service.
|
||||
pub fn store_fd<F: AsFd + ?Sized>(name: &str, fds: &F) -> Result<(), io::Error> {
|
||||
store_fds(name, &[fds.as_fd().as_raw_fd()])
|
||||
}
|
||||
|
||||
/// Validate a name for the `FDNAME=` argument (see `man sd_pid_notify_with_fds`).
|
||||
fn validate_name(name: &str) -> Result<(), io::Error> {
|
||||
for b in name.as_bytes() {
|
||||
if *b == b':' || b.is_ascii_control() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"invalid file descriptor name",
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// An iterator over the file descriptor names in the systemd file descriptor store.
|
||||
pub struct ListenFdNames {
|
||||
ptr: *mut *mut c_char,
|
||||
cur: usize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl ListenFdNames {
|
||||
/// Query the file descriptor names and numbers stored in the systemd file descriptor store.
|
||||
pub fn query() -> Result<Self, io::Error> {
|
||||
let mut names = std::ptr::null_mut();
|
||||
let count = sys::check_call(unsafe { sys::sd_listen_fds_with_names(0, &mut names) })?;
|
||||
Ok(Self {
|
||||
ptr: names,
|
||||
cur: 0,
|
||||
len: count as usize,
|
||||
})
|
||||
}
|
||||
|
||||
fn as_array(&self) -> &[*mut c_char] {
|
||||
if self.ptr.is_null() {
|
||||
&[]
|
||||
} else {
|
||||
unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ListenFdNames {
|
||||
fn drop(&mut self) {
|
||||
for name in self.as_array() {
|
||||
unsafe { libc::free(*name as *mut c_void) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for ListenFdNames {
|
||||
type Item = (RawFd, Result<String, std::string::FromUtf8Error>);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let names = self.as_array();
|
||||
if self.cur >= names.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let ptr = names[self.cur] as *const c_char;
|
||||
let fd_num = (self.cur as RawFd) + sys::LISTEN_FDS_START;
|
||||
self.cur += 1;
|
||||
let name = String::from_utf8(unsafe { CStr::from_ptr(ptr) }.to_bytes().to_vec());
|
||||
Some((fd_num, name))
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
use std::ffi::{c_char, c_int, c_uchar};
|
||||
use std::ffi::{c_char, c_int, c_uchar, c_uint};
|
||||
use std::io;
|
||||
use std::os::fd::RawFd;
|
||||
|
||||
pub const LISTEN_FDS_START: RawFd = 3;
|
||||
|
||||
#[link(name = "systemd")]
|
||||
extern "C" {
|
||||
@ -10,6 +13,17 @@ extern "C" {
|
||||
) -> c_int;
|
||||
pub fn sd_notify(unset_environment: c_int, state: *const c_char) -> c_int;
|
||||
pub fn sd_notify_barrier(unset_environment: c_int, timeout: u64) -> c_int;
|
||||
pub fn sd_pid_notify_with_fds(
|
||||
pid: libc::pid_t,
|
||||
unset_environment: c_int,
|
||||
state: *const c_char,
|
||||
fds: *const c_int,
|
||||
n_fds: c_uint,
|
||||
) -> c_int;
|
||||
pub fn sd_listen_fds_with_names(
|
||||
unset_environment: c_int,
|
||||
names: *mut *mut *mut c_char,
|
||||
) -> c_int;
|
||||
}
|
||||
|
||||
pub fn check_call(ret: c_int) -> Result<c_int, io::Error> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user