Skip to content

Commit 99a1726

Browse files
committed
unistd: document and change implementation of gethostname
Previously gethostname just mutated a buffer. We now provide a slightly more usable (but still allocation free) API that ensures that the returned buffer is NUL-terminated. We give back a `&CStr` instead of requiring that the user do all of the conversions from `&[u8]` when we know we are dealing with a `&CStr`. Signed-off-by: Paul Osborne <osbpau@gmail.com>
1 parent e6c1d7f commit 99a1726

File tree

2 files changed

+36
-4
lines changed

2 files changed

+36
-4
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ This project adheres to [Semantic Versioning](http://semver.org/).
3636
([#410](https://github.com/nix-rust/nix/pull/410))
3737
- `sethostname` now takes a `&str` instead of a `&[u8]` as this provides an API
3838
that makes more sense in normal, correct usage of the API.
39+
- `gethostname` previously did not expose the actual length of the hostname
40+
written from the underlying system call at all. This has been updated to
41+
return a `&CStr` within the provided buffer that is always properly
42+
NUL-terminated (this is not guaranteed by the call with all platforms/libc
43+
implementations).
3944

4045
### Fixed
4146
- Fixed using kqueue with `EVFILT_USER` on FreeBSD

src/unistd.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -476,12 +476,39 @@ pub fn sethostname(name: &str) -> Result<()> {
476476
Errno::result(res).map(drop)
477477
}
478478

479-
pub fn gethostname(name: &mut [u8]) -> Result<()> {
480-
let ptr = name.as_mut_ptr() as *mut c_char;
481-
let len = name.len() as size_t;
479+
/// Get the host name and store it int the provided buffer, returning the actual
480+
/// length stored in the buffer (see
481+
/// [gethostname(2)](http://man7.org/linux/man-pages/man2/gethostname.2.html)).
482+
///
483+
/// This function call attempts to get the host name for the running system and
484+
/// store it in a provided buffer. The buffer will be populated with bytes up
485+
/// to the length of the provided slice including a NUL terminating byte. If
486+
/// the hostname is longer than the length provided, no error will be provided.
487+
/// The posix specification does not specify whether implementations will
488+
/// null-terminate in this case, but the nix implementation will ensure that the
489+
/// buffer is null terminated in this case.
490+
///
491+
/// The return size is the number of bytes actually written into the slice
492+
/// including the NULL terminator. Here's an example of how you might actually
493+
/// use this in practice:
494+
///
495+
/// ```no_run
496+
/// use nix::unistd;
497+
///
498+
/// let mut buf = [0u8; 64];
499+
/// let hostname_cstr = unistd::gethostname(&mut buf).expect("Failed getting hostname");
500+
/// let hostname = hostname_cstr.to_str().expect("Hostname wasn't valid UTF-8");
501+
/// println!("Hostname: {}", hostname);
502+
/// ```
503+
pub fn gethostname<'a>(buffer: &'a mut [u8]) -> Result<&'a CStr> {
504+
let ptr = buffer.as_mut_ptr() as *mut c_char;
505+
let len = buffer.len() as size_t;
482506

483507
let res = unsafe { libc::gethostname(ptr, len) };
484-
Errno::result(res).map(drop)
508+
Errno::result(res).map(move |_| {
509+
buffer[len - 1] = 0; // ensure always null-terminated
510+
unsafe { CStr::from_ptr(buffer.as_ptr() as *const c_char) }
511+
})
485512
}
486513

487514
pub fn close(fd: RawFd) -> Result<()> {

0 commit comments

Comments
 (0)