Skip to main content

khive_runtime/
events_split_socket_path.rs

1//! Socket pathname admission for the events split.
2
3use std::os::unix::ffi::OsStrExt;
4use std::path::Path;
5
6use super::absolutize;
7use crate::config::RuntimeConfig;
8use crate::error::{RuntimeError, RuntimeResult};
9
10/// Refuse an events socket pathname that cannot fit the platform address field.
11/// The daemon anchors relative paths before binding, so preflight counts that
12/// same absolute spelling, including the terminating NUL.
13pub fn validate_events_socket_path(socket_path: &Path) -> RuntimeResult<()> {
14    let socket_path = absolutize(socket_path);
15    // SAFETY: sockaddr_un contains only integer fields and a character array;
16    // all-zero is valid. No syscall uses this value; only the field size is read.
17    let address: libc::sockaddr_un = unsafe { std::mem::zeroed() };
18    let limit = address.sun_path.len();
19    let path_bytes = socket_path.as_os_str().as_bytes().len();
20    let required_bytes = path_bytes.saturating_add(1);
21    if required_bytes > limit {
22        return Err(RuntimeError::InvalidInput(format!(
23            "events socket path {socket_path:?} uses {path_bytes} path bytes \
24             ({required_bytes} including NUL), exceeding the platform sun_path limit of {limit} bytes"
25        )));
26    }
27    Ok(())
28}
29
30/// Validate the configured forwarding socket of a file-backed runtime before
31/// its backend is opened. An in-memory runtime never forwards, so its socket
32/// is not checked.
33pub(crate) fn validate_configured_events_socket(config: &RuntimeConfig) -> RuntimeResult<()> {
34    if config.db_path.is_none() {
35        return Ok(());
36    }
37    match config
38        .events_split
39        .as_ref()
40        .and_then(|split| split.socket_path.as_deref())
41    {
42        Some(socket) => validate_events_socket_path(socket),
43        None => Ok(()),
44    }
45}