platform_info/platform/
unix.rs1#![warn(unused_results)] use std::ffi::{OsStr, OsString};
23use std::fmt;
24use std::fmt::{Debug, Formatter};
25
26use crate::{PlatformInfoAPI, PlatformInfoError, UNameAPI};
27
28use unix_safe::{oss_from_cstr, utsname};
29
30#[derive(Clone, Debug, PartialEq, Eq)]
33pub struct PlatformInfo {
34 pub utsname: UTSName, sysname: OsString,
39 nodename: OsString,
40 release: OsString,
41 version: OsString,
42 machine: OsString,
43 osname: OsString,
44}
45
46impl PlatformInfoAPI for PlatformInfo {
47 fn new() -> Result<Self, PlatformInfoError> {
49 let utsname = UTSName(utsname()?);
50 Ok(Self {
51 utsname,
52 sysname: oss_from_cstr(&utsname.0.sysname),
53 nodename: oss_from_cstr(&utsname.0.nodename),
54 release: oss_from_cstr(&utsname.0.release),
55 version: oss_from_cstr(&utsname.0.version),
56 machine: oss_from_cstr(&utsname.0.machine),
57 osname: OsString::from(crate::lib_impl::HOST_OS_NAME),
58 })
59 }
60}
61
62impl UNameAPI for PlatformInfo {
63 fn sysname(&self) -> &OsStr {
64 &self.sysname
65 }
66
67 fn nodename(&self) -> &OsStr {
68 &self.nodename
69 }
70
71 fn release(&self) -> &OsStr {
72 &self.release
73 }
74
75 fn version(&self) -> &OsStr {
76 &self.version
77 }
78
79 fn machine(&self) -> &OsStr {
80 &self.machine
81 }
82
83 fn osname(&self) -> &OsStr {
84 &self.osname
85 }
86}
87
88#[derive(Clone, Copy )]
107pub struct UTSName(libc::utsname);
108
109impl Debug for UTSName {
110 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
111 let mut debug_struct = &mut f.debug_struct("UTSName");
112 debug_struct = debug_struct
113 .field("sysname", &oss_from_cstr(&self.0.sysname))
114 .field("nodename", &oss_from_cstr(&self.0.nodename))
115 .field("release", &oss_from_cstr(&self.0.release))
116 .field("version", &oss_from_cstr(&self.0.version))
117 .field("machine", &oss_from_cstr(&self.0.machine));
118 #[cfg(not(any(
121 target_os = "aix",
122 target_os = "illumos",
123 target_os = "solaris",
124 target_os = "macos",
125 target_os = "dragonfly",
126 target_os = "freebsd",
127 target_os = "openbsd",
128 target_os = "netbsd",
129 target_os = "haiku"
130 )))]
131 {
132 debug_struct = debug_struct.field("domainname", &oss_from_cstr(&self.0.domainname));
133 }
134 debug_struct.finish()
135 }
136}
137
138impl PartialEq for UTSName {
139 fn eq(&self, other: &Self) -> bool {
140 let mut equal = true; equal = equal
142 && (
143 self.0.sysname,
144 self.0.nodename,
145 self.0.release,
146 self.0.version,
147 self.0.machine,
148 ) == (
149 other.0.sysname,
150 other.0.nodename,
151 other.0.release,
152 other.0.version,
153 other.0.machine,
154 );
155 #[cfg(not(any(
158 target_os = "aix",
159 target_os = "illumos",
160 target_os = "solaris",
161 target_os = "macos",
162 target_os = "dragonfly",
163 target_os = "freebsd",
164 target_os = "openbsd",
165 target_os = "netbsd",
166 target_os = "haiku"
167 )))]
168 {
169 equal = equal && (self.0.domainname == other.0.domainname);
170 }
171 equal
172 }
173}
174
175impl Eq for UTSName {}
176
177mod unix_safe {
181 use std::convert::TryFrom;
182 use std::ffi::{CStr, OsStr, OsString};
183 use std::io;
184 use std::mem::MaybeUninit;
185 use std::os::unix::ffi::OsStrExt;
186
187 pub fn oss_from_cstr(slice: &[libc::c_char]) -> OsString {
190 assert!(slice.len() < usize::try_from(isize::MAX).unwrap());
191 assert!(slice.iter().position(|&c| c == 0 ).unwrap() < slice.len());
192 OsString::from(OsStr::from_bytes(
193 unsafe { CStr::from_ptr(slice.as_ptr()) }.to_bytes(),
194 ))
195 }
196
197 pub fn utsname() -> Result<libc::utsname, std::io::Error> {
200 let mut uts = MaybeUninit::<libc::utsname>::uninit();
203 let result = unsafe { libc::uname(uts.as_mut_ptr()) };
204 if result != -1 {
205 Ok(unsafe { uts.assume_init() })
207 } else {
208 Err(io::Error::last_os_error())
209 }
210 }
211}
212#[test]
217fn test_osname() {
218 let info = PlatformInfo::new().unwrap();
219 let osname = info.osname().to_string_lossy();
220 assert!(osname.starts_with(crate::lib_impl::HOST_OS_NAME));
221}
222
223#[test]
224fn structure_clone() {
225 let info = PlatformInfo::new().unwrap();
226 println!("{info:?}");
227 #[allow(clippy::redundant_clone)] let info_copy = info.clone();
229 assert_eq!(info_copy, info);
230}