Skip to content

Commit

Permalink
Add System::distribution_id_like()
Browse files Browse the repository at this point in the history
This is similar to System::distribution_id() but for ID_LIKE.
See
<https://www.freedesktop.org/software/systemd/man/latest/os-release.html#ID_LIKE=>.
  • Loading branch information
legeana committed Jan 26, 2025
1 parent 35a52d1 commit a5f8b02
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 0 deletions.
27 changes: 27 additions & 0 deletions src/common/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,33 @@ impl System {
SystemInner::distribution_id()
}

/// Returns the distribution ids of operating systems that are closely
/// related to the local operating system in regards to packaging and
/// programming interfaces, for example listing one or more OS identifiers
/// the local OS is a derivative from.
///
/// See also
/// - <https://www.freedesktop.org/software/systemd/man/latest/os-release.html#ID_LIKE=>
///
/// | example platform | value of `System::distribution_id_like()` |
/// |---|---|
/// | android phone | [] |
/// | archlinux laptop | [] |
/// | centos server | ["rhel", "fedora"] |
/// | ubuntu laptop | ["debian"] |
/// | windows laptop | [] |
///
/// **Important**: this information is computed every time this function is called.
///
/// ```no_run
/// use sysinfo::System;
///
/// println!("Distribution ID_LIKE: {:?}", System::distribution_id_like());
/// ```
pub fn distribution_id_like() -> Vec<String> {
SystemInner::distribution_id_like()
}

/// Returns the system hostname based off DNS.
///
/// **Important**: this information is computed every time this function is called.
Expand Down
4 changes: 4 additions & 0 deletions src/unix/apple/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,10 @@ impl SystemInner {
std::env::consts::OS.to_owned()
}

pub(crate) fn distribution_id_like() -> Vec<String> {
Vec::new()
}

pub(crate) fn cpu_arch() -> Option<String> {
let mut arch_str: [u8; 32] = [0; 32];
let mut mib = [libc::CTL_HW as _, libc::HW_MACHINE as _];
Expand Down
4 changes: 4 additions & 0 deletions src/unix/freebsd/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,10 @@ impl SystemInner {
std::env::consts::OS.to_owned()
}

pub(crate) fn distribution_id_like() -> Vec<String> {
Vec::new()
}

pub(crate) fn cpu_arch() -> Option<String> {
let mut arch_str: [u8; 32] = [0; 32];
let mib = [libc::CTL_HW as _, libc::HW_MACHINE as _];
Expand Down
66 changes: 66 additions & 0 deletions src/unix/linux/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,23 @@ impl SystemInner {
.unwrap_or_else(|| std::env::consts::OS.to_owned())
}

#[cfg(not(target_os = "android"))]
pub(crate) fn distribution_id_like() -> Vec<String> {
system_info_as_list(get_system_info_linux(
InfoType::DistributionIDLike,
Path::new("/etc/os-release"),
Path::new(""),
))
}

#[cfg(target_os = "android")]
pub(crate) fn distribution_id_like() -> Vec<String> {
// Currently get_system_info_android doesn't support InfoType::DistributionIDLike and always
// returns None. This call is done anyway for consistency with non-Android implementation
// and to suppress dead-code warning for DistributionIDLike on Android.
system_info_as_list(get_system_info_android(InfoType::DistributionIDLike))
}

pub(crate) fn cpu_arch() -> Option<String> {
let mut raw = std::mem::MaybeUninit::<libc::utsname>::uninit();

Expand Down Expand Up @@ -633,6 +650,9 @@ enum InfoType {
/// Machine-parseable ID of a distribution, see
/// https://www.freedesktop.org/software/systemd/man/os-release.html#ID=
DistributionID,
/// Machine-parseable ID_LIKE of related distributions, see
/// <https://www.freedesktop.org/software/systemd/man/latest/os-release.html#ID_LIKE=>
DistributionIDLike,
}

#[cfg(not(target_os = "android"))]
Expand All @@ -646,6 +666,7 @@ fn get_system_info_linux(info: InfoType, path: &Path, fallback_path: &Path) -> O
InfoType::Name => "NAME=",
InfoType::OsVersion => "VERSION_ID=",
InfoType::DistributionID => "ID=",
InfoType::DistributionIDLike => "ID_LIKE=",
};

for line in buf.lines() {
Expand Down Expand Up @@ -674,6 +695,10 @@ fn get_system_info_linux(info: InfoType, path: &Path, fallback_path: &Path) -> O
// lsb-release is inconsistent with os-release and unsupported.
return None;
}
InfoType::DistributionIDLike => {
// lsb-release doesn't support ID_LIKE.
return None;
}
};
for line in buf.lines() {
if let Some(stripped) = line.strip_prefix(info_str) {
Expand All @@ -683,6 +708,16 @@ fn get_system_info_linux(info: InfoType, path: &Path, fallback_path: &Path) -> O
None
}

/// Returns a system info value as a list of strings.
/// Absence of a value is treated as an empty list.
fn system_info_as_list(sysinfo: Option<String>) -> Vec<String> {
match sysinfo {
Some(value) => value.split_ascii_whitespace().map(String::from).collect(),
// For list fields absence of a field is equivalent to an empty list.
None => Vec::new(),
}
}

#[cfg(target_os = "android")]
fn get_system_info_android(info: InfoType) -> Option<String> {
// https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/os/Build.java#58
Expand All @@ -693,6 +728,10 @@ fn get_system_info_android(info: InfoType) -> Option<String> {
// Not supported.
return None;
}
InfoType::DistributionIDLike => {
// Not supported.
return None;
}
};

let mut value_buffer = vec![0u8; libc::PROP_VALUE_MAX as usize];
Expand Down Expand Up @@ -721,6 +760,7 @@ mod test {
use super::get_system_info_linux;
use super::read_table;
use super::read_table_key;
use super::system_info_as_list;
use super::InfoType;
use std::collections::HashMap;
use std::io::Write;
Expand Down Expand Up @@ -823,6 +863,7 @@ mod test {
assert!(get_system_info_android(InfoType::OsVersion).is_some());
assert!(get_system_info_android(InfoType::Name).is_some());
assert!(get_system_info_android(InfoType::DistributionID).is_none());
assert!(get_system_info_android(InfoType::DistributionIDLike).is_none());
}

#[test]
Expand Down Expand Up @@ -873,6 +914,10 @@ DISTRIB_DESCRIPTION="Ubuntu 20.10"
get_system_info_linux(InfoType::DistributionID, &tmp1, Path::new("")),
Some("ubuntu".to_owned())
);
assert_eq!(
get_system_info_linux(InfoType::DistributionIDLike, &tmp1, Path::new("")),
Some("debian".to_owned())
);

// Check for the "fallback" path: "/etc/lsb-release"
assert_eq!(
Expand All @@ -887,5 +932,26 @@ DISTRIB_DESCRIPTION="Ubuntu 20.10"
get_system_info_linux(InfoType::DistributionID, Path::new(""), &tmp2),
None
);
assert_eq!(
get_system_info_linux(InfoType::DistributionIDLike, Path::new(""), &tmp2),
None
);
}

#[test]
fn test_system_info_as_list() {
assert_eq!(system_info_as_list(None), Vec::<String>::new());
assert_eq!(
system_info_as_list(Some("".to_string())),
Vec::<String>::new(),
);
assert_eq!(
system_info_as_list(Some("debian".to_string())),
vec!["debian".to_string()],
);
assert_eq!(
system_info_as_list(Some("rhel fedora".to_string())),
vec!["rhel".to_string(), "fedora".to_string()],
);
}
}
4 changes: 4 additions & 0 deletions src/unknown/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ impl SystemInner {
std::env::consts::OS.to_owned()
}

pub(crate) fn distribution_id_like() -> Vec<String> {
Vec::new()
}

pub(crate) fn host_name() -> Option<String> {
None
}
Expand Down

0 comments on commit a5f8b02

Please sign in to comment.