pub mod paths {
use std::path::PathBuf;
pub const HOME_ENV: &str = "HOME";
pub fn home_dir() -> Option<PathBuf> {
std::env::var_os(HOME_ENV).map(PathBuf::from)
}
}
pub mod control {
use std::io;
use std::path::Path;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Probe {
Live,
Dead,
Indeterminate,
}
pub type Stream = std::os::unix::net::UnixStream;
pub struct Listener(std::os::unix::net::UnixListener);
impl Listener {
pub fn accept(&self) -> io::Result<Stream> {
self.0.accept().map(|(stream, _)| stream)
}
pub fn incoming(&self) -> impl Iterator<Item = io::Result<Stream>> + '_ {
std::iter::from_fn(move || Some(self.accept()))
}
}
pub fn connect(addr: impl AsRef<Path>) -> io::Result<Stream> {
Stream::connect(addr.as_ref())
}
pub fn bind(addr: impl AsRef<Path>) -> io::Result<Listener> {
std::os::unix::net::UnixListener::bind(addr.as_ref()).map(Listener)
}
pub fn probe(addr: impl AsRef<Path>) -> Probe {
match Stream::connect(addr.as_ref()) {
Ok(_) => Probe::Live,
Err(e)
if matches!(
e.kind(),
io::ErrorKind::NotFound | io::ErrorKind::ConnectionRefused
) =>
{
Probe::Dead
}
Err(_) => Probe::Indeterminate,
}
}
}
pub mod tty {
pub fn sanitize() {
unsafe {
if libc::isatty(libc::STDOUT_FILENO) != 1 {
return;
}
let mut t: libc::termios = std::mem::zeroed();
if libc::tcgetattr(libc::STDOUT_FILENO, &mut t) == 0 {
t.c_oflag |= libc::OPOST | libc::ONLCR;
t.c_lflag |= libc::ICANON | libc::ECHO | libc::ECHOE | libc::ISIG;
t.c_iflag |= libc::ICRNL;
let _ = libc::tcsetattr(libc::STDOUT_FILENO, libc::TCSANOW, &t);
}
}
}
pub fn is_stdin_tty() -> bool {
unsafe { libc::isatty(libc::STDIN_FILENO) == 1 }
}
}
pub mod daemon {
use std::process::Command;
pub fn detach(cmd: &mut Command) {
use std::os::unix::process::CommandExt;
unsafe {
cmd.pre_exec(|| {
libc::setsid();
Ok(())
});
}
}
}
pub mod proc {
pub fn uid_tag() -> String {
unsafe { libc::getuid() }.to_string()
}
#[cfg(feature = "ssh")]
pub fn hostname() -> Option<String> {
let mut buf = [0u8; 256];
if unsafe { libc::gethostname(buf.as_mut_ptr().cast::<libc::c_char>(), buf.len()) } != 0 {
return None;
}
let end = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
let name = String::from_utf8_lossy(&buf[..end]).trim().to_string();
(!name.is_empty()).then_some(name)
}
pub fn kill_matching(needle: &str) {
let _ = std::process::Command::new("pkill")
.arg("-f")
.arg(needle)
.status();
}
pub fn kill_all_mars() {
for needle in ["mars --server", "mars keyd"] {
kill_matching(needle);
}
}
}
pub mod fsperm {
use std::io;
use std::path::Path;
pub fn restrict_dir(path: &Path) -> io::Result<()> {
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o700))
}
#[cfg(feature = "ssh")]
pub fn restrict_file(path: &Path) -> io::Result<()> {
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o600))
}
}
pub mod shell {
pub fn default_shell() -> String {
std::env::var("SHELL").unwrap_or_else(|_| "/bin/bash".to_string())
}
}