Skip to content

Commit cd055e7

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 <[email protected]>
1 parent d324991 commit cd055e7

File tree

2 files changed

+32
-4
lines changed

2 files changed

+32
-4
lines changed

CHANGELOG.md

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

4247
### Fixed
4348
- Fixed using kqueue with `EVFILT_USER` on FreeBSD

src/unistd.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -473,12 +473,35 @@ pub fn sethostname(name: &str) -> Result<()> {
473473
Errno::result(res).map(drop)
474474
}
475475

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

480500
let res = unsafe { libc::gethostname(ptr, len) };
481-
Errno::result(res).map(drop)
501+
Errno::result(res).map(|_| {
502+
buffer[len - 1] = 0; // ensure always null-terminated
503+
unsafe { CStr::from_ptr(buffer.as_ptr() as *const c_char) }
504+
})
482505
}
483506

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

0 commit comments

Comments
 (0)