From 0b70b151b87d74965cd718fde6f902a85f8f23e9 Mon Sep 17 00:00:00 2001 From: Alex Lyon Date: Wed, 7 Mar 2018 03:04:13 -0800 Subject: [PATCH] hostname: refactor a bit --- Cargo.lock | 1 + src/hostname/Cargo.toml | 1 + src/hostname/hostname.rs | 151 +++++++++++++++++++++++---------------- 3 files changed, 90 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03d338051..4d1b5b1c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -541,6 +541,7 @@ dependencies = [ name = "hostname" version = "0.0.1" dependencies = [ + "getopts 0.2.17 (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", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/hostname/Cargo.toml b/src/hostname/Cargo.toml index 4acec7fda..d40cfc865 100644 --- a/src/hostname/Cargo.toml +++ b/src/hostname/Cargo.toml @@ -11,6 +11,7 @@ path = "hostname.rs" [dependencies] libc = "0.2.26" winapi = { version = "0.3", features = ["sysinfoapi", "winsock2"] } +getopts = "0.2" uucore = { path="../uucore" } [[bin]] diff --git a/src/hostname/hostname.rs b/src/hostname/hostname.rs index 2b8d8a5a3..898e3c8b0 100644 --- a/src/hostname/hostname.rs +++ b/src/hostname/hostname.rs @@ -12,6 +12,7 @@ extern crate libc; #[cfg(windows)] extern crate winapi; +extern crate getopts; #[macro_use] extern crate uucore; @@ -21,6 +22,7 @@ use std::iter::repeat; use std::io; use std::str; use std::net::ToSocketAddrs; +use getopts::Matches; #[cfg(windows)] use winapi::um::winsock2::{GetHostNameW, WSAStartup, WSACleanup}; @@ -36,9 +38,9 @@ use libc::gethostname; #[cfg(not(windows))] use libc::sethostname; -static SYNTAX: &'static str = "[OPTION]... [HOSTNAME]"; -static SUMMARY: &'static str = "Print or set the system's host name."; -static LONG_HELP: &'static str = ""; +const SYNTAX: &'static str = "[OPTION]... [HOSTNAME]"; +const SUMMARY: &'static str = "Print or set the system's host name."; +const LONG_HELP: &'static str = ""; pub fn uumain(args: Vec) -> i32 { #[cfg(windows)] @@ -66,68 +68,83 @@ fn execute(args: Vec) -> i32 { .parse(args); match matches.free.len() { - 0 => { - let hostname = return_if_err!(1, xgethostname()); - - if matches.opt_present("i") { - // XXX: to_socket_addrs needs hostname:port so append a dummy port and remove it later. - // This should use std::net::lookup_host, but that is still marked unstable. - let hostname = hostname + ":1"; - match hostname.to_socket_addrs() { - Ok(addresses) => { - let mut hashset = HashSet::new(); - let mut output = String::new(); - for addr in addresses { - // XXX: not sure why this is necessary... - if !hashset.contains(&addr) { - let mut ip = format!("{}", addr); - if ip.ends_with(":1") { - ip = ip[..ip.len()-2].to_owned(); - } - output.push_str(&ip); - output.push_str(" "); - hashset.insert(addr.clone()); - } - } - let len = output.len(); - if len > 0 { - println!("{}", &output[0 .. len - 1]); - } - } - Err(f) => { - show_error!("{}", f); - return 1; - } - } + 0 => display_hostname(matches), + 1 => { + if let Err(err) = xsethostname(matches.free.last().unwrap()) { + show_error!("{}", err); + 1 } else { - if matches.opt_present("s") { - let mut it = hostname.char_indices().filter(|&ci| ci.1 == '.'); - let ci = it.next(); - if ci.is_some() { - println!("{}", &hostname[0 .. ci.unwrap().0]); - return 0; - } - } else if matches.opt_present("d") { - let mut it = hostname.char_indices().filter(|&ci| ci.1 == '.'); - let ci = it.next(); - if ci.is_some() { - println!("{}", &hostname[ci.unwrap().0 + 1 .. ]); - return 0; - } - } - - println!("{}", hostname); + 0 } } - 1 => xsethostname(matches.free.last().unwrap()), - _ => crash!(1, "{}", msg_wrong_number_of_arguments!(0, 1)) - }; + _ => { + show_error!("{}", msg_wrong_number_of_arguments!(0, 1)); + 1 + } + } +} - 0 +fn display_hostname(matches: Matches) -> i32 { + let hostname = return_if_err!(1, xgethostname()); + + if matches.opt_present("i") { + // XXX: to_socket_addrs needs hostname:port so append a dummy port and remove it later. + // This was originally supposed to use std::net::lookup_host, but that seems to be + // deprecated. Perhaps we should use the dns-lookup crate? + let hostname = hostname + ":1"; + match hostname.to_socket_addrs() { + Ok(addresses) => { + let mut hashset = HashSet::new(); + let mut output = String::new(); + for addr in addresses { + // XXX: not sure why this is necessary... + if !hashset.contains(&addr) { + let mut ip = format!("{}", addr); + if ip.ends_with(":1") { + let len = ip.len(); + ip.truncate(len - 2); + } + output.push_str(&ip); + output.push_str(" "); + hashset.insert(addr); + } + } + let len = output.len(); + if len > 0 { + println!("{}", &output[0..len - 1]); + } + + 0 + } + Err(f) => { + show_error!("{}", f); + + 1 + } + } + } else { + if matches.opt_present("s") || matches.opt_present("d") { + let mut it = hostname.char_indices().filter(|&ci| ci.1 == '.'); + if let Some(ci) = it.next() { + if matches.opt_present("s") { + println!("{}", &hostname[0..ci.0]); + } else { + println!("{}", &hostname[ci.0 + 1..]); + } + return 0; + } + } + + println!("{}", hostname); + + 0 + } } #[cfg(not(windows))] fn xgethostname() -> io::Result { + use std::ffi::CStr; + let namelen = 256; let mut name: Vec = repeat(0).take(namelen).collect(); let err = unsafe { @@ -135,9 +152,13 @@ fn xgethostname() -> io::Result { }; if err == 0 { - let last_char = name.iter().position(|byte| *byte == 0).unwrap_or(namelen); + let mut last_char = name.iter().position(|byte| *byte == 0).unwrap_or(namelen); + if last_char == name.len() { + name.push(0); + last_char += 1; + } - Ok(str::from_utf8(&name[..last_char]).unwrap().to_owned()) + Ok(CStr::from_bytes_with_nul(&name[..last_char]).unwrap().to_string_lossy().into_owned()) } else { Err(io::Error::last_os_error()) } @@ -159,7 +180,7 @@ fn xgethostname() -> io::Result { } #[cfg(not(windows))] -fn xsethostname(name: &str) { +fn xsethostname(name: &str) -> io::Result<()> { let vec_name: Vec = name.bytes().map(|c| c as libc::c_char).collect(); let err = unsafe { @@ -167,12 +188,14 @@ fn xsethostname(name: &str) { }; if err != 0 { - eprintln!("Cannot set hostname to {}", name); + Err(io::Error::last_os_error()) + } else { + Ok(()) } } #[cfg(windows)] -fn xsethostname(name: &str) { +fn xsethostname(name: &str) -> io::Result<()> { use std::ffi::OsStr; let wide_name = OsStr::new(name).to_wide_null(); @@ -183,6 +206,8 @@ fn xsethostname(name: &str) { if err == 0 { // NOTE: the above is correct, failure is when the function returns 0 apparently - eprintln!("Cannot set hostname to {}", name); + Err(io::Error::last_os_error()) + } else { + Ok(()) } }