Files
boxmaker/crates/memoryd/src/socket.rs
T
kyle b84b9af540 memoryd: the crate, memoryd.toml, and listening on a socket
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-25 16:41:44 -07:00

61 lines
2.4 KiB
Rust

//! Listening on a Unix socket: the directory at 0700, a stale socket removed, the socket at 0600
//! (M5a spec, section 7). The same steps as `brokerd`'s; no crate depends on another role's.
use std::fs::{DirBuilder, Permissions};
use std::io;
use std::os::unix::fs::{DirBuilderExt, PermissionsExt};
use std::os::unix::net::UnixListener;
use std::path::Path;
/// Bind one socket: prepare its directory at 0700, make it private, remove any stale socket,
/// bind, then make the socket itself private at 0600. The error names the path.
pub fn listen(socket: &Path) -> Result<UnixListener, String> {
// A socket needs a directory of its own: step 2 makes that directory 0700, which must never
// be `/` or a shared directory reached through a symbolic link.
let dir = match socket.parent() {
Some(parent) if parent.parent().is_some() && !parent.as_os_str().is_empty() => {
parent.to_path_buf()
}
_ => {
return Err(format!(
"{}: a socket needs a directory of its own, not / or none",
socket.display()
));
}
};
// 1. The directory, at 0700.
DirBuilder::new()
.recursive(true)
.mode(0o700)
.create(&dir)
.map_err(|e| format!("{}: {e}", dir.display()))?;
// `set_permissions` follows a symbolic link, so a link would make the directory it points to
// private instead: refuse it.
let kind = std::fs::symlink_metadata(&dir)
.map_err(|e| format!("{}: {e}", dir.display()))?
.file_type();
if !kind.is_dir() {
return Err(format!(
"{}: is a symbolic link or not a directory; memoryd will not change its mode",
dir.display()
));
}
// 2. Make it private, always, even when it was already there at 0755.
std::fs::set_permissions(&dir, Permissions::from_mode(0o700))
.map_err(|e| format!("{}: {e}", dir.display()))?;
// 3. A stale socket is removed; a missing one is fine.
match std::fs::remove_file(socket) {
Ok(()) => {}
Err(e) if e.kind() == io::ErrorKind::NotFound => {}
Err(e) => return Err(format!("{}: {e}", socket.display())),
}
// 4. Bind, then 5. make the socket private.
let listener = UnixListener::bind(socket).map_err(|e| format!("{}: {e}", socket.display()))?;
std::fs::set_permissions(socket, Permissions::from_mode(0o600))
.map_err(|e| format!("{}: {e}", socket.display()))?;
Ok(listener)
}