diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f54d5c0..74666ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,3 +48,4 @@ jobs: - run: cargo fmt --check if: matrix.rust == 'stable' - run: cargo doc + if: "!contains(matrix.os, 'windows')" diff --git a/CHANGELOG.md b/CHANGELOG.md index e096578..15bbff3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,21 +1,34 @@ # Changelog + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +and this project adheres to +[Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Changed + +- On Unix, use `rustix` to provide a simple implementation of `gethostname` + without `unsafe` (see [GH-10] and [GH-17]). + +[GH-10]: https://github.com/swsnr/gethostname.rs/pull/10 +[GH-17]: https://github.com/swsnr/gethostname.rs/pull/17 + ## [0.4.3] – 2023-05-13 ### Changed -- Removed the `windows` dependency in favor of using embedded bindings, see [GH-11]. + +- Removed the `windows` dependency in favor of using embedded bindings, see + [GH-11]. [GH-11]: https://github.com/swsnr/gethostname.rs/pull/11 ## [0.4.2] – 2023-04-13 ### Changed + - Update dependencies. ## [0.4.1] – 2022-12-01 @@ -27,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.4.0] – 2022-10-28 ### Changed + - Replace `winapi` with windows-rs, see [GH-7]. - Bump MSRV to 1.64 as required by windows-rs, see [GH-7]. @@ -35,30 +49,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.3.0] – 2022-10-09 ### Changed + - Bump MSRV to 1.56. ## [0.2.3] – 2022-03-12 ### Changed -- Limit `gethostname()` to `cfg(unix)` and `cfg(windows)` to provide more useful build failures on other platforms. + +- Limit `gethostname()` to `cfg(unix)` and `cfg(windows)` to provide more useful + build failures on other platforms. ## [0.2.2] – 2022-01-14 ## [0.2.1] – 2019-12-18 + ### Changed + - Consolidate documetation. - Update crates.io metadata. ## [0.2.0] – 2019-01-22 + ### Added + - Add Windows implementation (see [GH-1]). [GH-1]: https://github.com/swsnr/gethostname.rs/pull/1 ### Changed + - Pin supported Rust version to 1.31 ## 0.1.0 – 2019-01-20 + Initial release. ### Added diff --git a/Cargo.lock b/Cargo.lock index b8dcd76..13eb1c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,11 +2,27 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "gethostname" version = "0.4.3" dependencies = [ - "libc", + "rustix", "windows-targets", ] @@ -16,6 +32,34 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" version = "0.52.5" diff --git a/Cargo.toml b/Cargo.toml index c26e58c..292d0a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,9 @@ categories = ["os", "api-bindings"] rust-version = "1.64" [target.'cfg(not(windows))'.dependencies] -libc = "0.2.141" +rustix = { version = "0.38.34", default-features = false, features = [ + "system", +] } [target.'cfg(windows)'.dependencies] windows-targets = "0.52.4" diff --git a/src/lib.rs b/src/lib.rs index dd1bd97..603a3d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,66 +28,35 @@ use std::ffi::OsString; /// Get the standard host name for the current machine. /// -/// On Unix simply wrap POSIX [gethostname] in a safe interface. On Windows -/// return the DNS host name of the local computer, as returned by -/// [GetComputerNameExW] with `ComputerNamePhysicalDnsHostname` as `NameType`. -/// -/// This function panics if the buffer allocated for the hostname result of the -/// operating system is too small; however we take great care to allocate a -/// buffer of sufficient size: +/// On Unix call [`rustix::system::uname`] to obtain the node name, see +/// [`rustix::system::Uname::nodename`]. /// -/// * On Unix we allocate the buffer using the maximum permitted hostname size, -/// as returned by [sysconf] via `sysconf(_SC_HOST_NAME_MAX)`, plus an extra -/// byte for the trailing NUL byte. A hostname cannot exceed this limit, so -/// this function can't realistically panic. -/// * On Windows we call `GetComputerNameExW` with a NULL buffer first, which -/// makes it return the length of the current host name. We then use this -/// length to allocate a buffer for the actual result; this leaves a tiny -/// tiny race condition in case the hostname changes to a longer name right -/// in between those two calls but that's a risk we don't consider of any -/// practical relevance. +/// On Windows return the DNS host name of the local computer, as returned by +/// [GetComputerNameExW] with `ComputerNamePhysicalDnsHostname` as `NameType`. +/// We call this function twice to obtain the appropriate buffer size; there is +/// a race condition window between these two calls where a change to the node +/// name would result in a wrong buffer size which could cause this function to +/// panic. /// -/// Hence _if_ this function does panic please [report an issue][new]. +/// Note that this host name does not have a well-defined meaning in terms of +/// network name resolution. Specifically, it's not guaranteed that the +/// returned name can be resolved in any particular way, e.g. DNS. /// -/// [gethostname]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html -/// [sysconf]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html /// [GetComputerNameExW]: https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getcomputernameexw -/// [new]: https://github.com/swsnr/gethostname.rs/issues/new pub fn gethostname() -> OsString { - gethostname_impl() -} - -#[cfg(unix)] -#[inline] -fn gethostname_impl() -> OsString { - use libc::{c_char, sysconf, _SC_HOST_NAME_MAX}; - use std::os::unix::ffi::OsStringExt; - // Get the maximum size of host names on this system, and account for the - // trailing NUL byte. - let hostname_max = unsafe { sysconf(_SC_HOST_NAME_MAX) }; - let mut buffer = vec![0; (hostname_max as usize) + 1]; - let returncode = unsafe { libc::gethostname(buffer.as_mut_ptr() as *mut c_char, buffer.len()) }; - if returncode != 0 { - // There are no reasonable failures, so lets panic - panic!( - "gethostname failed: {} - Please report an issue to !", - std::io::Error::last_os_error() - ); + #[cfg(unix)] + { + use std::os::unix::ffi::OsStringExt; + OsString::from_vec(rustix::system::uname().nodename().to_bytes().to_vec()) + } + #[cfg(windows)] + { + get_computer_physical_dns_hostname() } - // We explicitly search for the trailing NUL byte and cap at the buffer - // length: If the buffer's too small (which shouldn't happen since we - // explicitly use the max hostname size above but just in case) POSIX - // doesn't specify whether there's a NUL byte at the end, so if we didn't - // check we might read from memory that's not ours. - let end = buffer.iter().position(|&b| b == 0).unwrap_or(buffer.len()); - buffer.truncate(end); - OsString::from_vec(buffer) } #[cfg(windows)] -#[inline] -fn gethostname_impl() -> OsString { +fn get_computer_physical_dns_hostname() -> OsString { use std::os::windows::ffi::OsStringExt; // The DNS host name of the local computer. If the local computer is a node