From 3f79ddf06375c3b34569c8b9ce91a607bbd0f052 Mon Sep 17 00:00:00 2001 From: Profpatsch Date: Sun, 28 Jun 2020 15:14:04 +0200 Subject: pkgs/profpatsch/execline: add el_exec and el_substitute el_exec: wraps the various execve wrappers in skalib that are useful for writing execline-like utils. currently only `xpathexec0` is supported, which execs into the argv you give it or errors with the right error if file not found. el_substitute: execline argv substitution! Wraps the execline function, so it will behave exactly the same as the existing execline utils, like `importas`. --- pkgs/profpatsch/execline/el_substitute.rs | 190 ++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 pkgs/profpatsch/execline/el_substitute.rs (limited to 'pkgs/profpatsch/execline/el_substitute.rs') diff --git a/pkgs/profpatsch/execline/el_substitute.rs b/pkgs/profpatsch/execline/el_substitute.rs new file mode 100644 index 00000000..b7e98cde --- /dev/null +++ b/pkgs/profpatsch/execline/el_substitute.rs @@ -0,0 +1,190 @@ +extern crate errno; +extern crate libc; + +use std::ffi::{CStr, CString}; + +#[repr(C)] +pub struct Stralloc_C { + s: *mut libc::c_char, + len: libc::size_t, + a: libc::size_t +} + +fn stralloc_zero() -> Stralloc_C { + Stralloc_C { + s: std::ptr::null_mut(), + len: 0, + a: 0 + } +} + +#[link(name = "skarnet")] +extern "C" { + fn stralloc_free(sa: *mut Stralloc_C); + fn stralloc_ready_tuned( + sa: *mut Stralloc_C, + n: libc::size_t, + base: libc::size_t, + a: libc::size_t, + b: libc::size_t, + ) -> libc::c_int; + + fn stralloc_copyb( + sa: *mut Stralloc_C, + s: *const libc::c_char, + len: libc::size_t + ) -> libc::c_int; +} + +fn stralloc_ready(sa: *mut Stralloc_C, n: libc::size_t) { + unsafe { + if (stralloc_ready_tuned(sa, n, 8, 1, 8) == 0) { + panic!("{}", errno::errno()); + } + } +} + +struct Stralloc(Stralloc_C); + +impl Stralloc { + fn new() -> Self { + let mut sa = stralloc_zero(); + unsafe { + stralloc_ready(&mut sa, 0); + } + Stralloc(sa) + } +} + +impl AsMut for Stralloc { + fn as_mut(&mut self) -> &mut Stralloc_C { + match self { + Stralloc(s) => s + } + } +} + +impl AsRef for Stralloc { + fn as_ref(&self) -> &Stralloc_C { + match self { + Stralloc(s) => s + } + } +} + +impl<'a> From<&mut [u8]> for Stralloc { + fn from(s: &mut [u8]) -> Self { + let mut sa = stralloc_zero(); + let ptr = s.as_mut_ptr() as *mut libc::c_char; + unsafe { + if stralloc_copyb(&mut sa, ptr, s.len()) == 0 { + panic!("{}", errno::errno()); + } + } + Stralloc(sa) + } +} + +// TODO not sure if stralloc will always be a contiguous block? +// that’s the precondition for from_raw_parts +impl AsRef<[u8]> for Stralloc_C { + fn as_ref(&self) -> &[u8] { + let ptr = self.s as *const u8; + unsafe { + std::slice::from_raw_parts(ptr, self.len) + } + } +} + +impl Drop for Stralloc { + fn drop(&mut self) { + match self { + Stralloc(inner) => { + unsafe { + stralloc_free(inner); + } + } + } + } +} + + +#[repr(C)] +#[derive(Debug)] +pub struct Elsubst_C +{ + var: libc::size_t, + value: libc::size_t, + // values are \0-separated strings, + // and n is the amount of elements in one such string + n: libc::c_uint +} + +#[link(name = "execline")] +extern "C" { + fn el_substitute( + dst: *mut Stralloc_C, + src: *const libc::c_char, + len: libc::size_t, + // length is given by nsubst + vars: *const libc::c_char, + // length is given by nsubst + values: *const libc::c_char, + + substs: *const Elsubst_C, + nsubst: libc::size_t + ) -> libc::c_int; +} + +pub struct Subst<'a> { + pub var: &'a CStr, + pub value: &'a CStr, +} + +fn simple_substitute<'a, 'b>(subst: &[Subst<'a>], src: &CStr) -> CString { + let len = src.to_bytes_with_nul().len() as libc::size_t; + let src = src.as_ptr() as *const libc::c_char; + let mut vars : Vec = Vec::new(); + let mut values : Vec = Vec::new(); + let mut substs : Vec = Vec::new(); + let mut var_i = 0; + let mut value_i = 0; + for s in subst { + let var = s.var.to_bytes_with_nul(); + let value = s.value.to_bytes_with_nul(); + vars.extend_from_slice(var); + values.extend_from_slice(value); + substs.push(Elsubst_C { + // these index into the vars/values arrays given to el_substitute + var: var_i, + value: value_i, + // we don’t deal with split values here + n: 1 + }); + var_i += var.len(); + value_i += value.len(); + } + let nsubst = subst.len(); + let mut dst = stralloc_zero(); + unsafe { + if el_substitute( + &mut dst, + src, + len, + vars.as_ptr() as *const libc::c_char, + values.as_ptr() as *const libc::c_char, + substs.as_ptr() as *const Elsubst_C, + nsubst + ) == -1 { + panic!("{}", errno::errno()); + } + // el_substitute returns a \0-delim C string + CStr::from_bytes_with_nul_unchecked(dst.as_ref()).to_owned() + } +} + +pub fn simple_substitute_argv<'a, 'b, S: AsRef>(subst: &[Subst<'a>], argv: &'b [S]) -> Vec { + argv.into_iter() + .map(|arg| simple_substitute(subst, arg.as_ref())) + .collect::>() +} -- cgit 1.4.1