1use std::io;
2#[cfg(feature = "set")]
3use std::ffi::OsStr;
4use std::ffi::OsString;
5#[cfg(feature = "set")]
6use std::os::unix::ffi::OsStrExt;
7use std::os::unix::ffi::OsStringExt;
8
9use libc;
10
11pub fn get() -> io::Result<OsString> {
12 let size =
17 unsafe { libc::sysconf(libc::_SC_HOST_NAME_MAX) as libc::size_t };
18
19 let mut buffer = vec![0u8; size];
20
21 let result = unsafe {
22 libc::gethostname(buffer.as_mut_ptr() as *mut libc::c_char, size)
23 };
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_else(|| 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(target_os = "dragonfly",
48 target_os = "freebsd",
49 target_os = "ios",
50 target_os = "macos")))]
51 #[allow(non_camel_case_types)]
52 type hostname_len_t = libc::size_t;
53
54 #[cfg(any(target_os = "dragonfly",
55 target_os = "freebsd",
56 target_os = "ios",
57 target_os = "macos"))]
58 #[allow(non_camel_case_types)]
59 type hostname_len_t = libc::c_int;
60
61 let size = hostname.len() as hostname_len_t;
62
63 let result = unsafe {
64 libc::sethostname(
65 hostname.as_bytes().as_ptr() as *const libc::c_char,
66 size,
67 )
68 };
69
70 if result != 0 {
71 Err(io::Error::last_os_error())
72 } else {
73 Ok(())
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use std::ffi::OsStr;
80
81 use super::wrap_buffer;
82
83 #[test]
86 fn test_non_overflowed_buffer() {
87 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();
88
89 assert_eq!(wrap_buffer(buf), OsStr::new("potato"));
90 }
91
92 #[test]
93 fn test_empty_buffer() {
94 let buf = b"".to_vec();
95
96 assert_eq!(wrap_buffer(buf), OsStr::new(""));
97 }
98
99 #[test]
100 fn test_filled_with_null_buffer() {
101 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();
102
103 assert_eq!(wrap_buffer(buf), OsStr::new(""));
104 }
105
106 #[test]
111 fn test_overflowed_buffer() {
112 let buf = b"potat".to_vec();
113
114 assert_eq!(wrap_buffer(buf), OsStr::new("potat"));
115 }
116}