syd 3.58.0

rock-solid application kernel
Documentation
//
// Syd: rock-solid application kernel
// src/utils/syd-env.rs: Run a command with the environment of the process with the given PID.
//
// Copyright (c) 2024, 2025, 2026 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: GPL-3.0

use std::{
    collections::VecDeque,
    os::unix::process::CommandExt,
    process::{Command, ExitCode, Stdio},
};

use nix::{
    errno::Errno,
    fcntl::{open, OFlag},
    libc::pid_t,
    sys::stat::Mode,
    unistd::Pid,
};
use syd::{
    eprintfln, path::XPathBuf, printf, printfln, proc::util::proc_environ_read, syslog::LogLevel,
};

// Set global allocator to GrapheneOS allocator.
#[cfg(all(
    not(target_os = "android"),
    not(target_arch = "loongarch64"),
    not(target_arch = "riscv64"),
    target_page_size_4k,
    target_pointer_width = "64"
))]
#[global_allocator]
static GLOBAL: hardened_malloc::HardenedMalloc = hardened_malloc::HardenedMalloc;

syd::main! {
    syd::set_sigpipe_dfl()?;

    // Initialize logging.
    syd::log::log_init_simple(LogLevel::Warn)?;

    let mut args: VecDeque<_> = std::env::args().skip(1).collect();
    let pid  = match args.pop_front().as_deref() {
        None | Some("-h") => {
            help()?;
            return Ok(ExitCode::SUCCESS);
        }
        Some("-e") => {
            let _var = if let Some(var) = args.pop_front() {
                var
            } else {
                eprintfln!("Error: -e requires an argument!")?;
                return Ok(ExitCode::FAILURE);
            };

            #[cfg(target_os = "android")]
            {
                eprintfln!("Error: -e is not supported on Android!")?;
                return Ok(ExitCode::FAILURE);
            }

            #[cfg(not(target_os = "android"))]
            match syd::wordexp::WordExp::expand(&_var, true, dur::Duration::from_secs(3)) {
                Ok(val) => {
                    printf!("{val}")?;
                    return Ok(ExitCode::SUCCESS);
                }
                Err(err) => {
                    eprintfln!("Error: {err}")?;
                    std::process::exit(err.into());
                }
            };
        }
        Some(pid) => match pid.parse::<pid_t>().map(Pid::from_raw) {
            Ok(pid) => pid,
            Err(error) => {
                eprintfln!("Invalid PID: {error}")?;
                return Ok(ExitCode::FAILURE);
            }
        },
    };

    let mut pfd = XPathBuf::try_from("/proc")?;
    pfd.try_push_pid(pid)?;
    pfd.try_push(b"environ")?;
    #[expect(clippy::disallowed_methods)]
    let pfd = open(&pfd, OFlag::O_RDONLY, Mode::empty())?.into();

    let environ = match proc_environ_read(pfd) {
        Ok(environ) => environ,
        Err(error) => {
            eprintfln!("syd-env: {error}")?;
            return Ok(ExitCode::FAILURE);
        }
    };

    let error = Command::new("env")
        .args(args)
        .env_clear()
        .envs(&environ)
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .exec();
    eprintfln!("syd-env: {error}")?;
    Ok(ExitCode::FAILURE)
}

fn help() -> Result<(), Errno> {
    printfln!("Usage: syd-env pid [-i] [name=value]... {{command [arg...]}}")?;
    printfln!("Run a command with the environment of the process with the given PID.")?;
    Ok(())
}