-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathutil.rs
159 lines (139 loc) · 4.67 KB
/
util.rs
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
use nix::{dir::Dir, fcntl::OFlag, sys::stat::Mode};
use std::env::consts::ARCH;
use std::io::Read;
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
use std::process::{Child, Output};
/// Wait for a process to exit and store it's output without
/// moving the object
pub fn wait_with_output(process: &mut Child) -> Result<Output, std::io::Error> {
let status = process.wait()?;
let mut stdout = Vec::new();
let mut stderr = Vec::new();
process
.stdout
.take()
.expect("failed to take stdout")
.read_to_end(&mut stdout)?;
process
.stderr
.take()
.expect("failed to take stdin")
.read_to_end(&mut stderr)?;
Ok(Output {
status,
stdout,
stderr,
})
}
/// Wrap nix::unistd::pipe to reutrn OwnedFd's rather than
/// RawFd's as RawFd doesn't clean itself up on being dropped
pub fn pipe_ownedfd() -> nix::Result<(OwnedFd, OwnedFd)> {
let (p1, p2) = nix::unistd::pipe()?;
unsafe { Ok((OwnedFd::from_raw_fd(p1), OwnedFd::from_raw_fd(p2))) }
}
/// Close all FDs apart from stdin, stdout and stderr
pub fn close_fds() -> Result<(), std::io::Error> {
let dir = Dir::open("/proc/self/fd", OFlag::O_DIRECTORY, Mode::empty())?;
let dir_fd = dir.as_raw_fd();
for entry in dir.into_iter() {
match entry?.file_name().to_str() {
Ok(entry) => {
if entry == "." || entry == ".." {
continue;
}
match entry.parse::<i32>() {
// Retain std{in, out, err}
Ok(0) => log::info!("Not closing stdin"),
Ok(1) => log::info!("Not closing stdout"),
Ok(2) => log::info!("Not closing stderr"),
Ok(fd) => {
if fd == dir_fd {
log::info!("Not closing dir fd {dir_fd}")
} else {
log::info!("Closing FD {fd}");
nix::unistd::close(fd)?;
}
}
Err(err) => {
log::warn!("Got invalid FD '{entry}': {err}");
}
}
}
Err(err) => {
log::warn!("Got invalid UTF8 in FD, ignoring: {err}");
}
}
}
Ok(())
}
/// Clear all the existing env vars
pub fn clear_env() {
// We must collect the vars first to avoid modifying the stsructure
// during iteration
std::env::vars()
.collect::<Vec<_>>()
.iter()
.for_each(|key_value| {
let key = &key_value.0;
log::info!("Clearing variable: {key}");
std::env::remove_var(key);
});
}
/// Sets the environment variables, reading a slice of strings in the
/// 'KEY=VAL' format
/// XXX is there a more idiomatic way such that we can take slices over
/// both String and &str?
pub fn set_env(env: &[String]) {
for var in env {
let mut split = var.split('=');
if let Some(key) = split.next() {
if let Some(val) = split.next() {
log::info!("Setting variable '{key}' to '{val}'");
std::env::set_var(key, val);
continue;
}
}
panic!("Didn't find valid key value pair in '{var}'!");
}
}
pub fn is_compatible_arch(image_arch: &str) -> bool {
// Normalize the architecture names to match up with
// https://doc.rust-lang.org/std/env/consts/constant.ARCH.html
let normalized = match image_arch {
"386" => "x86",
"amd64" => "x86_64",
// Doesn't account for v7, v8, etc.
"arm" => "arm",
"arm64" => "aarch64",
"ppc64le" => "powerpc64",
"s390x" => "s390x",
_ => {
log::warn!("No mapping for arch: {image_arch}");
return false;
}
};
normalized == ARCH
}
pub fn get_base_path() -> &'static str {
static BASE_DIR: &str = "/tmp/dabba";
BASE_DIR
}
/// Parse the JSON object or return an std::io::Error instance
pub fn serde_deserialize_or_err<T: serde::de::DeserializeOwned>(json: &str) -> std::io::Result<T> {
match serde_json::from_str(json) {
Ok(parsed) => Ok(parsed),
Err(err) => Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Failed to read JSON: {err}"),
)),
}
}
pub fn serde_result_to_ureq<T>(result: serde_json::Result<T>) -> std::io::Result<T> {
match result {
Ok(result) => Ok(result),
Err(err) => Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Failed to parse: {err}"),
)),
}
}