about summary refs log tree commit diff
path: root/pkgs/profpatsch/execline/el_exec.rs
blob: 0e4e11b7bec1747d1d2b8c67f58adb7fa3fb19d0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
use std::ffi::CStr;
extern crate libc;

fn to_c_argv<S: AsRef<CStr>>(s: &[S]) -> (&[S], Vec<*const libc::c_char>) {
    let mut c_ptr_args = s.iter()
        .map(|s| s.as_ref().as_ptr())
        .collect::<Vec<*const libc::c_char>>();
    c_ptr_args.push(std::ptr::null());
    (s, c_ptr_args)
}

/// Exec into argv, or exit 0 if it’s empty.
/// Will throw 127 if the executable is not found (ENOENT)
/// and 126 for any other exec error.
pub fn xmexec0<'a, S: AsRef<CStr>>(argv: &'a [S]) {
    let (c_strings, c_argv) = to_c_argv(argv);

    unsafe {
        let env = C::environ;
        C::xmexec0_af(
            c_argv[0] as *const libc::c_char,
            c_argv.as_ptr() as *const *const libc::c_char,
            env,
            C::env_len(env)
        )
    }
}

mod C {
    #[link(name = "skarnet")]
    extern "C" {
        pub fn xmexec0_af(
            file: *const libc::c_char,
            argv: *const *const libc::c_char,
            envp: *const *const libc::c_char,
            envlen: libc::size_t
        );
        pub static environ: *const *const libc::c_char;
        pub fn env_len(
            e: *const *const libc::c_char
        ) -> libc::size_t;
    }
}