cloudfox-coreshift-core 2.11.0

Low-level Linux and Android systems primitives for CoreShift (CloudFox)
Documentation
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/

//! Exec argv/env context for spawning.
//!
//! Owns the C-compatible argument-vector and environment storage that is
//! handed to the backend spawners (`posix.rs`, `fork.rs`).

use std::ffi::CString;
use std::ptr;

use crate::CoreError;

/// Owned argument vector storage for spawn internals.
#[derive(Clone)]
pub(super) enum ExecArgv {
    /// Dynamically allocated C-compatible strings.
    Dynamic(Vec<CString>),
}

/// Validated execution context for process spawning.
#[derive(Clone)]
pub(super) struct ExecContext {
    pub(super) argv: ExecArgv,
    envp: Option<Vec<CString>>,
    pub(super) cwd: Option<CString>,
}

impl ExecContext {
    /// Build a validated execution context for process spawn.
    pub(super) fn new(
        argv: Vec<String>,
        env: Option<Vec<String>>,
        cwd: Option<String>,
    ) -> Result<Self, CoreError> {
        if argv.is_empty() {
            return Err(CoreError::sys(libc::EINVAL, "exec argv empty"));
        }

        let c_argv: Vec<CString> = argv
            .into_iter()
            .map(|s| {
                CString::new(s).map_err(|_| CoreError::sys(libc::EINVAL, "exec argv contains nul"))
            })
            .collect::<Result<_, _>>()?;

        let c_envp = match env {
            Some(vars) => Some(
                vars.into_iter()
                    .map(|s| {
                        CString::new(s)
                            .map_err(|_| CoreError::sys(libc::EINVAL, "exec env contains nul"))
                    })
                    .collect::<Result<Vec<_>, _>>()?,
            ),
            None => None,
        };

        let c_cwd = match cwd {
            Some(c) => Some(
                CString::new(c)
                    .map_err(|_| CoreError::sys(libc::EINVAL, "exec cwd contains nul"))?,
            ),
            None => None,
        };

        Ok(Self {
            argv: ExecArgv::Dynamic(c_argv),
            envp: c_envp,
            cwd: c_cwd,
        })
    }

    /// Return a vector of pointers to the argument strings.
    pub(super) fn get_argv_ptrs(&self) -> Vec<*mut libc::c_char> {
        let mut ptrs = Vec::new();
        match &self.argv {
            ExecArgv::Dynamic(v) => {
                for s in v {
                    ptrs.push(s.as_ptr() as *mut libc::c_char);
                }
            }
        }
        ptrs.push(ptr::null_mut());
        ptrs
    }

    /// Return a vector of pointers to the environment strings.
    pub(super) fn get_envp_ptrs(&self) -> Option<Vec<*mut libc::c_char>> {
        self.envp.as_ref().map(|envp| {
            let mut ptrs = Vec::new();
            for s in envp {
                ptrs.push(s.as_ptr() as *mut libc::c_char);
            }
            ptrs.push(ptr::null_mut());
            ptrs
        })
    }
}