1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 03:27:44 +00:00

hostname: add support for Windows (and maybe other systems too)

This commit is contained in:
Alex Lyon 2018-03-06 16:40:08 -08:00
parent 15aaa8215e
commit 6330474b4f
5 changed files with 76 additions and 39 deletions

1
.gitignore vendored
View file

@ -4,6 +4,7 @@ target/
/tmp/ /tmp/
/busybox/ /busybox/
/.vscode/ /.vscode/
/.vs/
*~ *~
.*.swp .*.swp
.*.swo .*.swo

1
Cargo.lock generated
View file

@ -543,6 +543,7 @@ version = "0.0.1"
dependencies = [ dependencies = [
"libc 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)",
"uucore 0.0.1", "uucore 0.0.1",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]

View file

@ -13,7 +13,6 @@ unix = [
"du", "du",
"groups", "groups",
"hostid", "hostid",
"hostname",
"id", "id",
"install", "install",
"kill", "kill",
@ -68,6 +67,7 @@ generic = [
"arch", "arch",
"cat", "cat",
"hashsum", "hashsum",
"hostname",
"join", "join",
"more", "more",
"ln", "ln",

View file

@ -10,6 +10,7 @@ path = "hostname.rs"
[dependencies] [dependencies]
libc = "0.2.26" libc = "0.2.26"
winapi = { version = "0.3", features = ["sysinfoapi", "winsock2"] }
uucore = { path="../uucore" } uucore = { path="../uucore" }
[[bin]] [[bin]]

View file

@ -7,41 +7,57 @@
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*
* Synced with:
*
* https://www.opensource.apple.com/source/shell_cmds/shell_cmds-170/hostname/hostname.c?txt
*/ */
extern crate libc; extern crate libc;
#[cfg(windows)]
extern crate winapi;
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use std::collections::hash_set::HashSet; use std::collections::hash_set::HashSet;
use std::iter::repeat; use std::iter::repeat;
use std::io;
use std::str; use std::str;
use std::net::ToSocketAddrs; use std::net::ToSocketAddrs;
#[cfg(windows)]
use winapi::um::winsock2::{GetHostNameW, WSAStartup, WSACleanup};
#[cfg(windows)]
use winapi::um::sysinfoapi::{ComputerNamePhysicalDnsHostname, SetComputerNameExW};
#[cfg(windows)]
use winapi::shared::minwindef::MAKEWORD;
#[cfg(windows)]
use uucore::wide::*;
#[cfg(not(windows))]
use libc::gethostname;
#[cfg(not(windows))]
use libc::sethostname;
static SYNTAX: &'static str = "[OPTION]... [HOSTNAME]"; static SYNTAX: &'static str = "[OPTION]... [HOSTNAME]";
static SUMMARY: &'static str = "Print or set the system's host name."; static SUMMARY: &'static str = "Print or set the system's host name.";
static LONG_HELP: &'static str = ""; static LONG_HELP: &'static str = "";
extern {
fn gethostname(name: *mut libc::c_char, namelen: libc::size_t) -> libc::c_int;
}
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
extern {
fn sethostname(name: *const libc::c_char, namelen: libc::c_int) -> libc::c_int;
}
#[cfg(target_os = "linux")]
extern {
fn sethostname(name: *const libc::c_char, namelen: libc::size_t) -> libc::c_int;
}
pub fn uumain(args: Vec<String>) -> i32 { pub fn uumain(args: Vec<String>) -> i32 {
#[cfg(windows)]
unsafe {
let mut data = std::mem::uninitialized();
if WSAStartup(MAKEWORD(2, 2), &mut data as *mut _) != 0 {
eprintln!("Failed to start Winsock 2.2");
return 1;
}
}
let result = execute(args);
#[cfg(windows)]
unsafe {
WSACleanup();
}
result
}
fn execute(args: Vec<String>) -> i32 {
let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP) let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP)
.optflag("d", "domain", "Display the name of the DNS domain if possible") .optflag("d", "domain", "Display the name of the DNS domain if possible")
.optflag("i", "ip-address", "Display the network address(es) of the host") .optflag("i", "ip-address", "Display the network address(es) of the host")
@ -51,7 +67,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
match matches.free.len() { match matches.free.len() {
0 => { 0 => {
let hostname = xgethostname(); let hostname = return_if_err!(1, xgethostname());
if matches.opt_present("i") { if matches.opt_present("i") {
// XXX: to_socket_addrs needs hostname:port so append a dummy port and remove it later. // XXX: to_socket_addrs needs hostname:port so append a dummy port and remove it later.
@ -110,45 +126,63 @@ pub fn uumain(args: Vec<String>) -> i32 {
0 0
} }
fn xgethostname() -> String { #[cfg(not(windows))]
let namelen = 256usize; fn xgethostname() -> io::Result<String> {
let mut name : Vec<u8> = repeat(0).take(namelen).collect(); let namelen = 256;
let mut name: Vec<u8> = repeat(0).take(namelen).collect();
let err = unsafe { let err = unsafe {
gethostname (name.as_mut_ptr() as *mut libc::c_char, gethostname(name.as_mut_ptr() as *mut libc::c_char, namelen as libc::size_t)
namelen as libc::size_t)
}; };
if err != 0 { if err == 0 {
panic!("Cannot determine hostname"); let last_char = name.iter().position(|byte| *byte == 0).unwrap_or(namelen);
Ok(str::from_utf8(&name[..last_char]).unwrap().to_owned())
} else {
Err(io::Error::last_os_error())
} }
let last_char = name.iter().position(|byte| *byte == 0).unwrap_or(namelen);
str::from_utf8(&name[..last_char]).unwrap().to_owned()
} }
#[cfg(any(target_os = "macos", target_os = "freebsd"))] #[cfg(windows)]
fn xgethostname() -> io::Result<String> {
let namelen = 256;
let mut name: Vec<u16> = repeat(0).take(namelen).collect();
let err = unsafe {
GetHostNameW(name.as_mut_ptr(), namelen as libc::c_int)
};
if err == 0 {
Ok(String::from_wide_null(&name))
} else {
Err(io::Error::last_os_error())
}
}
#[cfg(not(windows))]
fn xsethostname(name: &str) { fn xsethostname(name: &str) {
let vec_name: Vec<libc::c_char> = name.bytes().map(|c| c as libc::c_char).collect(); let vec_name: Vec<libc::c_char> = name.bytes().map(|c| c as libc::c_char).collect();
let err = unsafe { let err = unsafe {
sethostname (vec_name.as_ptr(), vec_name.len() as libc::c_int) sethostname(vec_name.as_ptr(), vec_name.len() as _)
}; };
if err != 0 { if err != 0 {
println!("Cannot set hostname to {}", name); eprintln!("Cannot set hostname to {}", name);
} }
} }
#[cfg(target_os = "linux")] #[cfg(windows)]
fn xsethostname(name: &str) { fn xsethostname(name: &str) {
let vec_name: Vec<libc::c_char> = name.bytes().map(|c| c as libc::c_char).collect(); use std::ffi::OsStr;
let wide_name = OsStr::new(name).to_wide_null();
let err = unsafe { let err = unsafe {
sethostname (vec_name.as_ptr(), vec_name.len() as libc::size_t) SetComputerNameExW(ComputerNamePhysicalDnsHostname, wide_name.as_ptr())
}; };
if err != 0 { if err == 0 {
println!("Cannot set hostname to {}", name); // NOTE: the above is correct, failure is when the function returns 0 apparently
eprintln!("Cannot set hostname to {}", name);
} }
} }