|
1 | 1 | //! Get system identification
|
2 | 2 | use std::mem;
|
3 |
| -use libc::{self, c_char}; |
4 |
| -use std::ffi::CStr; |
5 |
| -use std::str::from_utf8_unchecked; |
| 3 | +use std::os::unix::ffi::OsStrExt; |
| 4 | +use std::ffi::OsStr; |
| 5 | +use libc::c_char; |
| 6 | +use crate::{Errno, Result}; |
6 | 7 |
|
7 | 8 | /// Describes the running system. Return type of [`uname`].
|
8 | 9 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
9 | 10 | #[repr(transparent)]
|
10 | 11 | pub struct UtsName(libc::utsname);
|
11 | 12 |
|
12 | 13 | impl UtsName {
|
13 |
| - /// Name of the operating system implementation |
14 |
| - pub fn sysname(&self) -> &str { |
15 |
| - to_str(&(&self.0.sysname as *const c_char ) as *const *const c_char) |
| 14 | + /// Name of the operating system implementation. |
| 15 | + pub fn sysname(&self) -> &OsStr { |
| 16 | + cast_and_trim(&self.0.sysname) |
16 | 17 | }
|
17 | 18 |
|
18 | 19 | /// Network name of this machine.
|
19 |
| - pub fn nodename(&self) -> &str { |
20 |
| - to_str(&(&self.0.nodename as *const c_char ) as *const *const c_char) |
| 20 | + pub fn nodename(&self) -> &OsStr { |
| 21 | + cast_and_trim(&self.0.nodename) |
21 | 22 | }
|
22 | 23 |
|
23 | 24 | /// Release level of the operating system.
|
24 |
| - pub fn release(&self) -> &str { |
25 |
| - to_str(&(&self.0.release as *const c_char ) as *const *const c_char) |
| 25 | + pub fn release(&self) -> &OsStr { |
| 26 | + cast_and_trim(&self.0.release) |
26 | 27 | }
|
27 | 28 |
|
28 | 29 | /// Version level of the operating system.
|
29 |
| - pub fn version(&self) -> &str { |
30 |
| - to_str(&(&self.0.version as *const c_char ) as *const *const c_char) |
| 30 | + pub fn version(&self) -> &OsStr { |
| 31 | + cast_and_trim(&self.0.version) |
31 | 32 | }
|
32 | 33 |
|
33 | 34 | /// Machine hardware platform.
|
34 |
| - pub fn machine(&self) -> &str { |
35 |
| - to_str(&(&self.0.machine as *const c_char ) as *const *const c_char) |
| 35 | + pub fn machine(&self) -> &OsStr { |
| 36 | + cast_and_trim(&self.0.machine) |
36 | 37 | }
|
37 | 38 | }
|
38 | 39 |
|
39 | 40 | /// Get system identification
|
40 |
| -pub fn uname() -> UtsName { |
| 41 | +pub fn uname() -> Result<UtsName> { |
41 | 42 | unsafe {
|
42 |
| - let mut ret = mem::MaybeUninit::uninit(); |
43 |
| - libc::uname(ret.as_mut_ptr()); |
44 |
| - UtsName(ret.assume_init()) |
| 43 | + let mut ret = mem::MaybeUninit::zeroed(); |
| 44 | + Errno::result(libc::uname(ret.as_mut_ptr()))?; |
| 45 | + Ok(UtsName(ret.assume_init())) |
45 | 46 | }
|
46 | 47 | }
|
47 | 48 |
|
48 |
| -#[inline] |
49 |
| -fn to_str<'a>(s: *const *const c_char) -> &'a str { |
50 |
| - unsafe { |
51 |
| - let res = CStr::from_ptr(*s).to_bytes(); |
52 |
| - from_utf8_unchecked(res) |
53 |
| - } |
| 49 | +fn cast_and_trim(slice: &[c_char]) -> &OsStr { |
| 50 | + let length = slice.iter().position(|&byte| byte == 0).unwrap_or(slice.len()); |
| 51 | + let bytes = unsafe { |
| 52 | + std::slice::from_raw_parts(slice.as_ptr().cast(), length) |
| 53 | + }; |
| 54 | + |
| 55 | + OsStr::from_bytes(bytes) |
54 | 56 | }
|
55 | 57 |
|
56 | 58 | #[cfg(test)]
|
57 | 59 | mod test {
|
58 | 60 | #[cfg(target_os = "linux")]
|
59 | 61 | #[test]
|
60 | 62 | pub fn test_uname_linux() {
|
61 |
| - assert_eq!(super::uname().sysname(), "Linux"); |
| 63 | + assert_eq!(super::uname().unwrap().sysname(), "Linux"); |
62 | 64 | }
|
63 | 65 |
|
64 | 66 | #[cfg(any(target_os = "macos", target_os = "ios"))]
|
65 | 67 | #[test]
|
66 | 68 | pub fn test_uname_darwin() {
|
67 |
| - assert_eq!(super::uname().sysname(), "Darwin"); |
| 69 | + assert_eq!(super::uname().unwrap().sysname(), "Darwin"); |
68 | 70 | }
|
69 | 71 |
|
70 | 72 | #[cfg(target_os = "freebsd")]
|
71 | 73 | #[test]
|
72 | 74 | pub fn test_uname_freebsd() {
|
73 |
| - assert_eq!(super::uname().sysname(), "FreeBSD"); |
| 75 | + assert_eq!(super::uname().unwrap().sysname(), "FreeBSD"); |
74 | 76 | }
|
75 | 77 | }
|
0 commit comments