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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
use std::env;
use std::ffi::{CString, OsString};
use std::os::unix::ffi::OsStringExt;
use std::ptr;
use errno;
use libc;
fn osstring2cstring(s: OsString) -> CString {
unsafe { CString::from_vec_unchecked(s.into_vec()) }
}
fn split_string(s: &OsString) -> Vec<OsString> {
match s.clone().into_string() {
Ok(cmd) => cmd.split_whitespace().map(OsString::from).collect(),
Err(cmd) => vec![cmd],
}
}
// Helper wrappers around libc::* API
pub fn fork() -> libc::pid_t {
unsafe { libc::fork() }
}
pub fn execvp(cmd: &OsString) {
let cstrings = split_string(cmd)
.into_iter()
.map(osstring2cstring)
.collect::<Vec<_>>();
let mut args = cstrings.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();
args.push(ptr::null());
errno::set_errno(errno::Errno(0));
unsafe { libc::execvp(args[0], args.as_ptr()) };
}
pub fn dup2(fd1: i32, fd2: i32) {
assert!(unsafe { libc::dup2(fd1, fd2) } > -1);
}
pub fn close(fd: i32) {
assert_eq!(unsafe { libc::close(fd) }, 0);
}
pub fn pipe() -> (i32, i32) {
let mut fds = [0; 2];
assert_eq!(unsafe { libc::pipe(fds.as_mut_ptr()) }, 0);
(fds[0], fds[1])
}
fn which(exec: &str) -> Option<OsString> {
if let Some(path) = env::var_os("PATH") {
let paths = env::split_paths(&path);
for path in paths {
let candidate = path.join(exec);
if path.join(exec).exists() {
return Some(candidate.into_os_string());
}
}
}
None
}
pub fn find_pager(env: &str) -> Option<OsString> {
if env::var_os("NOPAGER").is_some() {
return None;
}
let default_pager = || which("more");
env::var_os(env).or_else(default_pager)
}
pub fn isatty(fd: i32) -> bool {
let isatty = unsafe { libc::isatty(fd) };
isatty != 0
}
#[cfg(test)]
mod tests {
use super::*;
const MORE: &str = "/bin/more";
fn assert_ends_with_bin_more(more: OsString) {
let good = more.to_str().map(|m| m.ends_with(MORE)).unwrap_or(false);
assert!(good, "{:?} doesn't end with {}", more, MORE);
}
#[test]
fn more_found_in_path() {
assert!(which("more").is_some())
}
#[test]
fn erom_not_found_in_path() {
assert!(which("erom").is_none())
}
#[test]
fn which_more() {
which("more").map(assert_ends_with_bin_more);
}
#[test]
fn usr_bin_more_default_pager() {
find_pager("__RANDOM_NAME").map(assert_ends_with_bin_more);
}
#[test]
fn nopager() {
env::set_var("NOPAGER", "");
assert!(find_pager("more").is_none());
env::remove_var("NOPAGER");
}
}
|