Skip to content

Instantly share code, notes, and snippets.

@TrinityCoder
Last active July 20, 2022 17:40
Show Gist options
  • Save TrinityCoder/793c097b5a4ab25b8fabf5cd67e92f05 to your computer and use it in GitHub Desktop.
Save TrinityCoder/793c097b5a4ab25b8fabf5cd67e92f05 to your computer and use it in GitHub Desktop.
Rust: Converting Vec<String> into a C-style 'char**' array to be used in libc library calls, such as in libc::execvp()
# Build by running `cargo make`
# or `cargo build`.
#
# Run by `cargo run`.
[package]
name = "experiment"
version = "0.1.0"
edition = "2018"
[dependencies]
libc = "0.2.55"
[[bin]]
name = "main"
path = "main.rs"
mod utils {
use libc::c_char;
use std::ffi::CString;
/// Consumes a `Vec<String>` and saves some helper data, so it can provide
/// the `*const *const c_char` (`argv`) and `*const c_char` (`argv[0]`)
/// when the user needs them i. e. for [`libc::execvp()`] library call.
pub struct Argv {
argv: Vec<CString>,
argv_ptr: Vec<*const c_char>,
}
impl Argv {
/// Creates a new `Argv` structure.
pub fn new(args: Vec<String>) -> Self {
let argv: Vec<_> = args
.iter()
.map(|arg| CString::new(arg.as_str()).unwrap())
.collect();
let mut argv_ptr: Vec<_> = argv.iter().map(|arg| arg.as_ptr()).collect();
argv_ptr.push(std::ptr::null());
Self { argv, argv_ptr }
}
/// Returns the C language's `argv` (`*const *const c_char`).
pub fn get_argv(&self) -> *const *const c_char { self.argv_ptr.as_ptr() }
/// Returns the C language's `argv[0]` (`*const c_char`).
pub fn get_argv0(&self) -> *const c_char { self.argv_ptr[0] }
/// Gets total length of the `argv` array (including the last null pointer).
pub fn get_len(&self) -> usize { self.argv_ptr.len() }
}
}
fn main() {
let args = vec!["ls".to_string(), "-l".to_string(), "-h".to_string()];
let argv = utils::Argv::new(args.clone());
unsafe {
libc::execvp(argv.get_argv0(), argv.get_argv());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment