Skip to content

Commit 3b07168

Browse files
committed
Auto merge of #455 - posborne:gethostname-sethostname-updates, r=kamalmarhubi
Gethostname sethostname updates These changes have been previously discussed some with #452 but we decided it made sense to separate things out a bit more. r? @kamalmarhubi @fiveop
2 parents 1fbf1fe + 2c02ee9 commit 3b07168

File tree

2 files changed

+46
-9
lines changed

2 files changed

+46
-9
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
6464
- `SigFlags` in `::nix::sys::signal` has be renamed to `SigmaskHow` and its type
6565
has changed from `bitflags` to `enum` in order to conform to our conventions.
6666
([#460](https://github.com/nix-rust/nix/pull/460))
67+
- `sethostname` now takes a `&str` instead of a `&[u8]` as this provides an API
68+
that makes more sense in normal, correct usage of the API.
69+
- `gethostname` previously did not expose the actual length of the hostname
70+
written from the underlying system call at all. This has been updated to
71+
return a `&CStr` within the provided buffer that is always properly
72+
NUL-terminated (this is not guaranteed by the call with all platforms/libc
73+
implementations).
6774

6875
### Fixed
6976
- Fixed multiple issues with Unix domain sockets on non-Linux OSes

src/unistd.rs

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use fcntl::{fcntl, OFlag, O_CLOEXEC, FD_CLOEXEC};
55
use fcntl::FcntlArg::F_SETFD;
66
use libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t, mode_t};
77
use std::mem;
8-
use std::ffi::{CString, CStr, OsString};
9-
use std::os::unix::ffi::{OsStringExt};
8+
use std::ffi::{CString, CStr, OsString, OsStr};
9+
use std::os::unix::ffi::{OsStringExt, OsStrExt};
1010
use std::os::unix::io::RawFd;
1111
use std::path::{PathBuf};
1212
use void::Void;
@@ -480,7 +480,14 @@ pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
480480
Errno::result(res).map(drop)
481481
}
482482

483-
pub fn sethostname(name: &[u8]) -> Result<()> {
483+
/// Set the system host name (see
484+
/// [gethostname(2)](http://man7.org/linux/man-pages/man2/gethostname.2.html)).
485+
///
486+
/// Given a name, attempt to update the system host name to the given string.
487+
/// On some systems, the host name is limited to as few as 64 bytes. An error
488+
/// will be return if the name is not valid or the current process does not have
489+
/// permissions to update the host name.
490+
pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> {
484491
// Handle some differences in type of the len arg across platforms.
485492
cfg_if! {
486493
if #[cfg(any(target_os = "dragonfly",
@@ -492,19 +499,42 @@ pub fn sethostname(name: &[u8]) -> Result<()> {
492499
type sethostname_len_t = size_t;
493500
}
494501
}
495-
let ptr = name.as_ptr() as *const c_char;
496-
let len = name.len() as sethostname_len_t;
502+
let ptr = name.as_ref().as_bytes().as_ptr() as *const c_char;
503+
let len = name.as_ref().len() as sethostname_len_t;
497504

498505
let res = unsafe { libc::sethostname(ptr, len) };
499506
Errno::result(res).map(drop)
500507
}
501508

502-
pub fn gethostname(name: &mut [u8]) -> Result<()> {
503-
let ptr = name.as_mut_ptr() as *mut c_char;
504-
let len = name.len() as size_t;
509+
/// Get the host name and store it in the provided buffer, returning a pointer
510+
/// the CStr in that buffer on success (see
511+
/// [gethostname(2)](http://man7.org/linux/man-pages/man2/gethostname.2.html)).
512+
///
513+
/// This function call attempts to get the host name for the running system and
514+
/// store it in a provided buffer. The buffer will be populated with bytes up
515+
/// to the length of the provided slice including a NUL terminating byte. If
516+
/// the hostname is longer than the length provided, no error will be provided.
517+
/// The posix specification does not specify whether implementations will
518+
/// null-terminate in this case, but the nix implementation will ensure that the
519+
/// buffer is null terminated in this case.
520+
///
521+
/// ```no_run
522+
/// use nix::unistd;
523+
///
524+
/// let mut buf = [0u8; 64];
525+
/// let hostname_cstr = unistd::gethostname(&mut buf).expect("Failed getting hostname");
526+
/// let hostname = hostname_cstr.to_str().expect("Hostname wasn't valid UTF-8");
527+
/// println!("Hostname: {}", hostname);
528+
/// ```
529+
pub fn gethostname<'a>(buffer: &'a mut [u8]) -> Result<&'a CStr> {
530+
let ptr = buffer.as_mut_ptr() as *mut c_char;
531+
let len = buffer.len() as size_t;
505532

506533
let res = unsafe { libc::gethostname(ptr, len) };
507-
Errno::result(res).map(drop)
534+
Errno::result(res).map(|_| {
535+
buffer[len - 1] = 0; // ensure always null-terminated
536+
unsafe { CStr::from_ptr(buffer.as_ptr() as *const c_char) }
537+
})
508538
}
509539

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

0 commit comments

Comments
 (0)