getargv_sys/
lib.rs

1/*-
2 * Copyright: see LICENSE file
3 */
4
5#![doc(html_logo_url = "https://getargv.narzt.cam/images/logo.svg")]
6#![deny(rustdoc::bare_urls)]
7#![deny(rustdoc::missing_crate_level_docs)]
8#![deny(rustdoc::invalid_rust_codeblocks)]
9#![deny(rustdoc::broken_intra_doc_links)]
10#![allow(non_camel_case_types)]
11#![allow(non_upper_case_globals)]
12#![allow(non_snake_case)]
13
14//! Unsafe Rust bindings for the [getargv library](https://getargv.narzt.cam/).
15//!
16//! This crate provides unsafe FFI bindings for [libgetargv](https://getargv.narzt.cam/),
17//! there is a safe wrapper in the
18//! [getargv](https://docs.rs/getargv/latest/getargv/) crate.
19//!
20//! You almost certainly do not want to use this crate directly.
21//!
22//! You must have [libgetargv](https://getargv.narzt.cam/) installed for
23//! this crate to link to, it will not build/install it for you. If
24//! `libgetargv.dylib` is not located in one of `clang`'s default search
25//! paths, you must set the`LIBGETARGV_LIB_DIR` env var to tell `rustc`
26//! where to find it, and you will either need to set the
27//! `DYLD_FALLBACK_LIBRARY_PATH` env var at runtime to tell dyld where
28//! to load it from, or you will need to use `install_name_tool` on your
29//! binary to fixup the library load path.
30
31use std::mem;
32
33include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
34
35impl Default for ArgvResult {
36    fn default() -> Self{
37        let result: Self = unsafe { mem::zeroed() };
38        result
39    }
40}
41impl Default for ArgvArgcResult {
42    fn default() -> Self{
43        let result: Self = unsafe { mem::zeroed() };
44        result
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51    use std::env;
52    use std::mem::forget;
53    use std::os::raw::c_char;
54    use std::process;
55    use std::ffi::OsStr;
56    use std::os::unix::ffi::OsStrExt;
57    use std::ffi::CStr;
58
59    #[test]
60    fn get_argv_of_pid_works() {
61        unsafe {
62            let mut result: ArgvResult = mem::zeroed();
63            let options: GetArgvOptions = GetArgvOptions {pid: process::id() as pid_t, skip: 0, nuls: false};
64            let success = get_argv_of_pid(&options, &mut result);
65            assert!(success);
66            let result_char: c_char = *result.end_pointer;
67            assert_eq!(result_char, b'\0' as i8);
68            let expected = env::args_os().collect::<Vec<_>>().join(OsStr::from_bytes(&[b' ']));
69            let actual = CStr::from_ptr(result.start_pointer);
70            assert_eq!(expected.to_str().unwrap(), actual.to_str().unwrap());
71            free_ArgvResult(&mut result);
72        }
73    }
74
75    #[test]
76    fn get_argv_and_argc_of_pid_works() {
77        unsafe {
78            let mut result: ArgvArgcResult = mem::zeroed();
79            assert!(get_argv_and_argc_of_pid(process::id() as pid_t, &mut result));
80            assert_eq!(result.argc as usize, env::args_os().len());
81            let v = Vec::from_raw_parts(result.argv,result.argc as usize,result.argc as usize);
82            for (a,e) in env::args_os().zip(v.iter()) {
83                assert_eq!(CStr::from_ptr(*e).to_str().unwrap(), a.to_str().unwrap());
84            }
85            free_ArgvArgcResult(&mut result);
86            forget(v);//would otherwise try to free argv in result
87        }
88    }
89
90    #[test]
91    fn print_argv_of_pid_works() {
92        unsafe {
93            let mut result: ArgvResult = mem::zeroed();
94            let options: GetArgvOptions = GetArgvOptions {pid: process::id() as pid_t, skip: 0, nuls: false};
95            assert!(get_argv_of_pid(&options, &mut result));
96            assert!(print_argv_of_pid(
97                result.start_pointer,
98                result.end_pointer
99            ));
100            free_ArgvResult(&mut result);
101        }
102    }
103
104    #[test]
105    fn argv_result_default_trait_sanity_test() {
106        let zeroed: ArgvResult = unsafe { mem::zeroed() };
107        let result: ArgvResult = Default::default();
108        assert_eq!(result.buffer, zeroed.buffer);
109    }
110
111    #[test]
112    fn argv_argc_result_default_trait_sanity_test() {
113        let zeroed: ArgvArgcResult = unsafe { mem::zeroed() };
114        let result: ArgvArgcResult = Default::default();
115        assert_eq!(result.buffer, zeroed.buffer);
116    }
117}