From 2d4c44a62c636abec3e8ec871c007bbcb1337c4a 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 7682ee3196..2861dc64b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,11 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#410](https://github.com/nix-rust/nix/pull/410)) - `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 using kqueue with `EVFILT_USER` on FreeBSD diff --git a/src/unistd.rs b/src/unistd.rs index f395595fb6..95f92f9a04 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -473,12 +473,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<()> {