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
|
mod command;
use command::command_stdout_lossy;
pub fn version() -> String {
// The OS version information is obtained first from the os-release file. If that
// information is incomplete or unavailable, an attempt is made to obtain the
// version information from the lsb_release command. If that fails, any partial
// information from os-release is used if available, or a fallback message if
// reading from the os-release file produced
// no version information.
let version = read_os_release_file().unwrap_or_else(|incomplete_info| {
parse_lsb_release().unwrap_or_else(|| {
incomplete_info.unwrap_or_else(|| String::from("[Failed to detect version]"))
})
});
format!("Linux {version}")
}
pub fn short_version() -> String {
let version = read_os_release_file_short().unwrap_or_else(|| {
parse_lsb_release().unwrap_or_else(|| String::from("[Failed to detect version]"))
});
format!("Linux {version}")
}
fn read_os_release_file_short() -> Option<String> {
let mut os_release_info = rs_release::get_os_release().ok()?;
let os_name = os_release_info.remove("NAME");
let os_version_id = os_release_info.remove("VERSION_ID");
if let Some(os_name) = os_name
&& os_name != "NixOS"
&& let Some(os_version_id) = os_version_id
{
return Some(format!("{os_name} {os_version_id}"));
}
os_release_info.remove("PRETTY_NAME")
}
fn read_os_release_file() -> Result<String, Option<String>> {
let mut os_release_info = rs_release::get_os_release().map_err(|_| None)?;
let os_name = os_release_info.remove("NAME");
let os_version = os_release_info.remove("VERSION");
if os_name.is_some() || os_version.is_some() {
let full_info_available = os_name.is_some() && os_version.is_some();
let gathered_info = format!(
"{} {}",
os_name.unwrap_or_else(|| "[unknown distribution]".to_owned()),
os_version.unwrap_or_else(|| "[unknown version]".to_owned())
);
if full_info_available {
Ok(gathered_info)
} else {
// Partial version information
Err(Some(gathered_info))
}
} else {
// No information was obtained
Err(None)
}
}
fn parse_lsb_release() -> Option<String> {
command_stdout_lossy("lsb_release", &["-ds"])
.ok()
.and_then(|output| {
if output.is_empty() {
None
} else {
Some(output)
}
})
}
pub fn extra_metadata() -> impl Iterator<Item = (String, String)> {
#[cfg(not(feature = "network-manager"))]
let version_cmds = [kernel_version, wg_version, systemd_version];
#[cfg(feature = "network-manager")]
let version_cmds = [kernel_version, nm_version, wg_version, systemd_version];
version_cmds.into_iter().filter_map(|f| f())
}
/// `uname -r` outputs a single line containing only the kernel version:
/// > 5.9.15
fn kernel_version() -> Option<(String, String)> {
let kernel = command_stdout_lossy("uname", &["-r"]).ok()?;
Some(("kernel".to_string(), kernel))
}
/// NetworkManager's version is returned as a numeric version string
/// > 1.26.0
#[cfg(feature = "network-manager")]
fn nm_version() -> Option<(String, String)> {
let nm = talpid_dbus::network_manager::NetworkManager::new().ok()?;
Some(("nm".to_string(), nm.version_string().ok()?))
}
/// `/sys/module/wireguard/version` contains only a numeric version string
/// > 1.0.0
fn wg_version() -> Option<(String, String)> {
let wireguard_version = std::fs::read_to_string("/sys/module/wireguard/version")
.ok()?
.trim()
.to_string();
Some(("wireguard".to_string(), wireguard_version))
}
/// `systemctl --version` usually outputs two lines - one with the version, and another listing
/// features:
/// > systemd 246 (246)
/// > +PAM +AUDIT -SELINUX +IMA +APPARMOR +SMACK -SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT -GNUTLS +ACL
fn systemd_version() -> Option<(String, String)> {
let systemd_version_output = command_stdout_lossy("systemctl", &["--version"]).ok()?;
let version = systemd_version_output.lines().next()?.to_string();
Some(("systemd".to_string(), version))
}
|