clawshell 0.1.0-alpha.1

A security privileged process for the OpenClaw ecosystem.
use std::path::PathBuf;
use std::process::{Command, ExitStatus};

#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "macos")]
mod macos;

#[cfg(target_os = "linux")]
pub use self::linux::*;
#[cfg(target_os = "macos")]
pub use self::macos::*;

#[cfg(not(any(target_os = "linux", target_os = "macos")))]
compile_error!("unsupported target OS: ClawShell currently supports only Linux and macOS");

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("{command} failed to execute: {source}")]
    CommandIo {
        command: &'static str,
        #[source]
        source: std::io::Error,
    },
    #[error("failed to {operation} '{path}': {source}")]
    FileIo {
        operation: &'static str,
        path: PathBuf,
        #[source]
        source: std::io::Error,
    },
    #[error("{command} failed with exit status {status}; stdout: {stdout}; stderr: {stderr}")]
    CommandFailed {
        command: &'static str,
        status: ExitStatus,
        stdout: String,
        stderr: String,
    },
    #[cfg(target_os = "macos")]
    #[error("no available system UID in 400-499 range")]
    NoAvailableSystemUid,
}

fn command_output(
    command: &mut Command,
    command_name: &'static str,
) -> Result<std::process::Output, Error> {
    command.output().map_err(|source| Error::CommandIo {
        command: command_name,
        source,
    })
}

fn command_status(command: &mut Command, command_name: &'static str) -> Result<(), Error> {
    let output = command_output(command, command_name)?;
    if output.status.success() {
        Ok(())
    } else {
        Err(Error::CommandFailed {
            command: command_name,
            status: output.status,
            stdout: String::from_utf8_lossy(&output.stdout).to_string(),
            stderr: String::from_utf8_lossy(&output.stderr).to_string(),
        })
    }
}

fn format_octal_mode(mode_bits: u32) -> String {
    format!("{:04o}", mode_bits)
}