1use crate::host::with_host;
8use fusevm::Value;
9use indexmap::IndexMap;
10
11pub const METHODS: &[&str] = &[
12 "platform",
13 "arch",
14 "type",
15 "release",
16 "hostname",
17 "homedir",
18 "tmpdir",
19 "endianness",
20 "cpus",
21 "totalmem",
22 "freemem",
23 "uptime",
24 "loadavg",
25 "userInfo",
26 "networkInterfaces",
27 "version",
28 "machine",
29 "availableParallelism",
30 "getPriority",
31 "setPriority",
32];
33
34pub fn constant(name: &str) -> Option<Value> {
36 match name {
37 "EOL" => Some(with_host(|h| h.new_str("\n"))),
38 "devNull" => Some(with_host(|h| h.new_str("/dev/null"))),
39 "constants" => Some(with_host(|h| {
41 let mut signals = indexmap::IndexMap::new();
42 for (k, v) in [
43 ("SIGHUP", 1),
44 ("SIGINT", 2),
45 ("SIGQUIT", 3),
46 ("SIGILL", 4),
47 ("SIGTRAP", 5),
48 ("SIGABRT", 6),
49 ("SIGBUS", 10),
50 ("SIGFPE", 8),
51 ("SIGKILL", 9),
52 ("SIGUSR1", 30),
53 ("SIGSEGV", 11),
54 ("SIGUSR2", 31),
55 ("SIGPIPE", 13),
56 ("SIGALRM", 14),
57 ("SIGTERM", 15),
58 ("SIGCHLD", 20),
59 ("SIGCONT", 19),
60 ("SIGSTOP", 17),
61 ("SIGTSTP", 18),
62 ("SIGWINCH", 28),
63 ] {
64 signals.insert(k.to_string(), Value::Float(v as f64));
65 }
66 let sig = h.new_object(signals);
67 let mut priority = indexmap::IndexMap::new();
68 for (k, v) in [
69 ("PRIORITY_LOW", 19),
70 ("PRIORITY_BELOW_NORMAL", 10),
71 ("PRIORITY_NORMAL", 0),
72 ("PRIORITY_ABOVE_NORMAL", -7),
73 ("PRIORITY_HIGH", -14),
74 ("PRIORITY_HIGHEST", -20),
75 ] {
76 priority.insert(k.to_string(), Value::Float(v as f64));
77 }
78 let prio = h.new_object(priority);
79 let mut m = indexmap::IndexMap::new();
80 m.insert("signals".to_string(), sig);
81 m.insert("priority".to_string(), prio);
82 h.new_object(m)
83 })),
84 _ => None,
85 }
86}
87
88pub fn platform() -> &'static str {
90 match std::env::consts::OS {
91 "macos" => "darwin",
92 "windows" => "win32",
93 other => other,
94 }
95}
96
97pub fn arch() -> &'static str {
99 match std::env::consts::ARCH {
100 "aarch64" => "arm64",
101 "x86_64" => "x64",
102 other => other,
103 }
104}
105
106pub fn call(method: &str, args: &[Value]) -> Option<Result<Value, String>> {
107 let s = |v: &str| Ok(with_host(|h| h.new_str(v)));
108 Some(match method {
109 "platform" => s(platform()),
110 "arch" => s(arch()),
111 "machine" => s(std::env::consts::ARCH),
112 "type" => s(match std::env::consts::OS {
113 "macos" => "Darwin",
114 "linux" => "Linux",
115 "windows" => "Windows_NT",
116 other => other,
117 }),
118 "release" => s(""),
119 "version" => s(""),
120 "hostname" => s(&hostname()),
121 "homedir" => s(&dirs::home_dir()
122 .map(|p| p.to_string_lossy().into_owned())
123 .unwrap_or_default()),
124 "tmpdir" => s(std::env::temp_dir().to_string_lossy().trim_end_matches('/')),
125 "endianness" => s(if cfg!(target_endian = "big") {
126 "BE"
127 } else {
128 "LE"
129 }),
130 "totalmem" => Ok(Value::Float(0.0)),
131 "freemem" => Ok(Value::Float(0.0)),
132 "uptime" => Ok(Value::Float(0.0)),
133 "cpus" => Ok(with_host(|h| h.new_array(Vec::new()))),
134 "loadavg" => {
136 let mut avg = [0f64; 3];
137 let n = unsafe { libc::getloadavg(avg.as_mut_ptr(), 3) };
139 let items: Vec<Value> = if n == 3 {
140 avg.iter().map(|v| Value::Float(*v)).collect()
141 } else {
142 vec![Value::Float(0.0); 3]
143 };
144 Ok(with_host(|h| h.new_array(items)))
145 }
146 "networkInterfaces" => Ok(with_host(|h| h.new_object(IndexMap::new()))),
147 "userInfo" => Ok(user_info()),
148 "availableParallelism" => {
150 let n = std::thread::available_parallelism()
151 .map(|n| n.get())
152 .unwrap_or(1);
153 Ok(Value::Float(n as f64))
154 }
155 "getPriority" => {
157 let pid = if args.is_empty() {
158 0
159 } else {
160 super::arg_num(args, 0) as i32
161 };
162 let prio = unsafe { libc::getpriority(libc::PRIO_PROCESS as _, pid as _) };
164 Ok(Value::Float(prio as f64))
165 }
166 "setPriority" => {
169 let (pid, prio) = if args.len() >= 2 {
170 (
171 super::arg_num(args, 0) as i32,
172 super::arg_num(args, 1) as i32,
173 )
174 } else {
175 (0, super::arg_num(args, 0) as i32)
176 };
177 unsafe {
179 libc::setpriority(libc::PRIO_PROCESS as _, pid as _, prio as _);
180 }
181 Ok(Value::Undef)
182 }
183 _ => return None,
184 })
185}
186
187fn hostname() -> String {
188 std::process::Command::new("hostname")
189 .output()
190 .ok()
191 .and_then(|o| String::from_utf8(o.stdout).ok())
192 .map(|s| s.trim().to_string())
193 .unwrap_or_default()
194}
195
196fn user_info() -> Value {
197 with_host(|h| {
198 let mut m = IndexMap::new();
199 let user = std::env::var("USER")
200 .or_else(|_| std::env::var("USERNAME"))
201 .unwrap_or_default();
202 let home = dirs::home_dir()
203 .map(|p| p.to_string_lossy().into_owned())
204 .unwrap_or_default();
205 let shell = std::env::var("SHELL").unwrap_or_default();
206 m.insert("username".into(), h.new_str(user));
207 m.insert("homedir".into(), h.new_str(home));
208 m.insert("shell".into(), h.new_str(shell));
209 m.insert("uid".into(), Value::Float(-1.0));
210 m.insert("gid".into(), Value::Float(-1.0));
211 h.new_object(m)
212 })
213}