From 34912343a0997830a7bc49522abeb3b6c551a8dc Mon Sep 17 00:00:00 2001 From: Paul Osborne Date: Sat, 29 Oct 2016 17:19:39 -0500 Subject: [PATCH] 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 --- CHANGELOG.md | 5 +++++ src/unistd.rs | 31 +++++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bd38311f0..02b078997d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,11 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#460](https://github.com/nix-rust/nix/pull/460)) - `sethostname` now takes a `&str` instead of a `&[u8]` as this provides an API that makes more sense in normal, correct usage of the API. +- `gethostname` previously did not expose the actual length of the hostname + written from the underlying system call at all. This has been updated to + return a `&CStr` within the provided buffer that is always properly + NUL-terminated (this is not guaranteed by the call with all platforms/libc + implementations). ### Fixed - Fixed multiple issues with Unix domain sockets on non-Linux OSes diff --git a/src/unistd.rs b/src/unistd.rs index 301801089f..69366eeab7 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -506,12 +506,35 @@ pub fn sethostname(name: &str) -> Result<()> { Errno::result(res).map(drop) } -pub fn gethostname(name: &mut [u8]) -> Result<()> { - let ptr = name.as_mut_ptr() as *mut c_char; - let len = name.len() as size_t; +/// Get the host name and store it in the provided buffer, returning a pointer +/// the CStr in that buffer on success (see +/// [gethostname(2)](http://man7.org/linux/man-pages/man2/gethostname.2.html)). +/// +/// This function call attempts to get the host name for the running system and +/// store it in a provided buffer. The buffer will be populated with bytes up +/// to the length of the provided slice including a NUL terminating byte. If +/// the hostname is longer than the length provided, no error will be provided. +/// The posix specification does not specify whether implementations will +/// null-terminate in this case, but the nix implementation will ensure that the +/// buffer is null terminated in this case. +/// +/// ```no_run +/// use nix::unistd; +/// +/// let mut buf = [0u8; 64]; +/// let hostname_cstr = unistd::gethostname(&mut buf).expect("Failed getting hostname"); +/// let hostname = hostname_cstr.to_str().expect("Hostname wasn't valid UTF-8"); +/// println!("Hostname: {}", hostname); +/// ``` +pub fn gethostname<'a>(buffer: &'a mut [u8]) -> Result<&'a CStr> { + let ptr = buffer.as_mut_ptr() as *mut c_char; + let len = buffer.len() as size_t; let res = unsafe { libc::gethostname(ptr, len) }; - Errno::result(res).map(drop) + Errno::result(res).map(|_| { + buffer[len - 1] = 0; // ensure always null-terminated + unsafe { CStr::from_ptr(buffer.as_ptr() as *const c_char) } + }) } pub fn close(fd: RawFd) -> Result<()> {