1#[cfg(feature = "set")]
2use std::ffi::OsStr;
3use std::ffi::OsString;
4use std::io;
5#[cfg(feature = "set")]
6use std::os::unix::ffi::OsStrExt;
7use std::os::unix::ffi::OsStringExt;
8
9const _POSIX_HOST_NAME_MAX: libc::c_long = 255;
10
11pub fn get() -> io::Result<OsString> {
12 let limit = unsafe { libc::sysconf(libc::_SC_HOST_NAME_MAX) };
17 let size = libc::c_long::max(limit, _POSIX_HOST_NAME_MAX) as usize;
18
19 let mut buffer = vec![0u8; size + 1];
21
22 #[allow(trivial_casts)]
23 let result = unsafe { libc::gethostname(buffer.as_mut_ptr() as *mut libc::c_char, size) };
24
25 if result != 0 {
26 return Err(io::Error::last_os_error());
27 }
28
29 Ok(wrap_buffer(buffer))
30}
31
32fn wrap_buffer(mut bytes: Vec<u8>) -> OsString {
33 let end = bytes
37 .iter()
38 .position(|&byte| byte == 0x00)
39 .unwrap_or(bytes.len());
40 bytes.resize(end, 0x00);
41
42 OsString::from_vec(bytes)
43}
44
45#[cfg(feature = "set")]
46pub fn set(hostname: &OsStr) -> io::Result<()> {
47 #[cfg(not(any(
48 target_os = "dragonfly",
49 target_os = "freebsd",
50 target_os = "ios",
51 target_os = "macos",
52 target_os = "solaris",
53 target_os = "illumos"
54 )))]
55 #[allow(non_camel_case_types)]
56 type hostname_len_t = libc::size_t;
57
58 #[cfg(any(
59 target_os = "dragonfly",
60 target_os = "freebsd",
61 target_os = "ios",
62 target_os = "macos",
63 target_os = "solaris",
64 target_os = "illumos"
65 ))]
66 #[allow(non_camel_case_types)]
67 type hostname_len_t = libc::c_int;
68
69 #[allow(clippy::unnecessary_cast)]
70 if hostname.len() > hostname_len_t::MAX as usize {
72 return Err(io::Error::other("hostname too long"));
73 }
74
75 let size = hostname.len() as hostname_len_t;
76
77 #[allow(trivial_casts)]
78 let result =
79 unsafe { libc::sethostname(hostname.as_bytes().as_ptr() as *const libc::c_char, size) };
80
81 if result != 0 {
82 Err(io::Error::last_os_error())
83 } else {
84 Ok(())
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use std::ffi::OsStr;
91
92 use super::wrap_buffer;
93
94 #[test]
97 fn test_non_overflowed_buffer() {
98 let buf = b"potato\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0".to_vec();
99
100 assert_eq!(wrap_buffer(buf), OsStr::new("potato"));
101 }
102
103 #[test]
104 fn test_empty_buffer() {
105 let buf = b"".to_vec();
106
107 assert_eq!(wrap_buffer(buf), OsStr::new(""));
108 }
109
110 #[test]
111 fn test_filled_with_null_buffer() {
112 let buf = b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0".to_vec();
113
114 assert_eq!(wrap_buffer(buf), OsStr::new(""));
115 }
116
117 #[test]
122 fn test_overflowed_buffer() {
123 let buf = b"potat".to_vec();
124
125 assert_eq!(wrap_buffer(buf), OsStr::new("potat"));
126 }
127}