shell_rs/
uname.rs

1// Copyright (c) 2021 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
2// Use of this source is governed by Apache-2.0 License that can be found
3// in the LICENSE file.
4
5use crate::core::str::cstr_to_str;
6use crate::error::Error;
7
8#[derive(Debug)]
9pub struct Options {
10    /// Print all information.
11    pub all: bool,
12
13    /// Print the kernel name.
14    pub kernel_name: bool,
15
16    /// Print the network node hostname.
17    pub node_name: bool,
18
19    /// Print the kernel release.
20    pub kernel_release: bool,
21
22    /// Print the kernel version.
23    pub kernel_version: bool,
24
25    /// Print the machine hardware name.
26    pub machine: bool,
27
28    /// Print the processor type (non-portable).
29    pub processor: bool,
30
31    /// Print the hardware platform (non-portable).
32    pub hardware_platform: bool,
33
34    /// Print the operating system.
35    pub operating_system: bool,
36}
37
38impl Default for Options {
39    fn default() -> Self {
40        Self {
41            all: false,
42            kernel_name: false,
43            node_name: false,
44            kernel_release: false,
45            kernel_version: false,
46            machine: true,
47            processor: false,
48            hardware_platform: false,
49            operating_system: false,
50        }
51    }
52}
53
54impl Options {
55    pub fn with_all() -> Self {
56        Self {
57            all: true,
58            ..Self::default()
59        }
60    }
61}
62
63#[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "")))]
64const HOST_OS: &str = "GNU/Linux";
65#[cfg(all(target_os = "linux", not(any(target_env = "gnu", target_env = ""))))]
66const HOST_OS: &str = "Linux";
67#[cfg(target_os = "windows")]
68const HOST_OS: &str = "Windows NT";
69#[cfg(target_os = "freebsd")]
70const HOST_OS: &str = "FreeBSD";
71#[cfg(target_os = "netbsd")]
72const HOST_OS: &str = "NetBSD";
73#[cfg(target_os = "openbsd")]
74const HOST_OS: &str = "OpenBSD";
75#[cfg(target_vendor = "apple")]
76const HOST_OS: &str = "Darwin";
77#[cfg(target_os = "fuchsia")]
78const HOST_OS: &str = "Fuchsia";
79#[cfg(target_os = "redox")]
80const HOST_OS: &str = "Redox";
81
82/// Print system info.
83pub fn uname(options: &Options) -> Result<String, Error> {
84    let mut uts = nc::utsname_t::default();
85    let _ = unsafe { nc::uname(&mut uts)? };
86    let mut result = Vec::new();
87
88    if options.all || options.kernel_name {
89        result.push(cstr_to_str(&uts.sysname)?);
90    }
91    if options.all || options.node_name {
92        result.push(cstr_to_str(&uts.nodename)?);
93    }
94    if options.all || options.kernel_release {
95        result.push(cstr_to_str(&uts.release)?);
96    }
97    if options.all || options.kernel_version {
98        result.push(cstr_to_str(&uts.version)?);
99    }
100    if options.all || options.machine {
101        result.push(cstr_to_str(&uts.machine)?);
102    }
103    if options.all || options.processor {
104        // This option is ignored.
105        // See https://stackoverflow.com/posts/394271/revisions
106    }
107    if options.all || options.hardware_platform {
108        let domain_name = cstr_to_str(&uts.domainname)?;
109        if domain_name != "(none)" {
110            result.push(domain_name);
111        }
112    }
113    if options.all || options.operating_system {
114        result.push(HOST_OS);
115    }
116
117    Ok(result.join(" "))
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn test_uname() {
126        assert!(uname(&Options::default()).is_ok());
127        assert!(uname(&Options::with_all()).is_ok());
128    }
129}