Skip to content

Commit

Permalink
Move fallbacks to lib.rs
Browse files Browse the repository at this point in the history
  • Loading branch information
AldaronLau committed Nov 14, 2023
1 parent a93a9fc commit c191aa8
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 116 deletions.
2 changes: 1 addition & 1 deletion WASM.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ web-sys, and will instead return these mock values:
- `devicename()`: "Unknown"
- `hostname()`: "localhost"
- `platform()`: "Unknown"
- `distro()`: "Unknown Unknown"
- `distro()`: "Emulated"
- `desktop_env()`: "Unknown WebAssembly"
- `arch()`: "wasm32"

Expand Down
16 changes: 11 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
)]

const DEFAULT_USERNAME: &str = "Unknown";
const DEFAULT_HOSTNAME: &str = "localhost";
const DEFAULT_HOSTNAME: &str = "Localhost";

pub mod fallible;

Expand Down Expand Up @@ -412,13 +412,16 @@ pub fn username_os() -> OsString {
/// Get the user's real (full) name.
#[inline(always)]
pub fn realname() -> String {
fallible::realname().unwrap_or_else(|_| DEFAULT_USERNAME.to_owned())
fallible::realname()
.or_else(|_| fallible::username())
.unwrap_or_else(|_| DEFAULT_USERNAME.to_owned())
}

/// Get the user's real (full) name.
#[inline(always)]
pub fn realname_os() -> OsString {
fallible::realname_os()
.or_else(|_| fallible::username_os())
.unwrap_or_else(|_| DEFAULT_USERNAME.to_owned().into())
}

Expand All @@ -427,7 +430,9 @@ pub fn realname_os() -> OsString {
/// Often used to identify device for bluetooth pairing.
#[inline(always)]
pub fn devicename() -> String {
fallible::devicename().unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string())
fallible::devicename()
.or_else(|_| fallible::hostname())
.unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string())
}

/// Get the device name (also known as "Pretty Name").
Expand All @@ -436,6 +441,7 @@ pub fn devicename() -> String {
#[inline(always)]
pub fn devicename_os() -> OsString {
fallible::devicename_os()
.or_else(|_| fallible::hostname_os())
.unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string().into())
}

Expand All @@ -447,7 +453,7 @@ pub fn devicename_os() -> OsString {
/// [`devicename()`]).
#[inline(always)]
pub fn hostname() -> String {
fallible::hostname().unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string())
fallible::hostname().unwrap_or_else(|_| DEFAULT_HOSTNAME.to_lowercase())
}

/// Get the host device's hostname.
Expand All @@ -459,7 +465,7 @@ pub fn hostname() -> String {
#[inline(always)]
pub fn hostname_os() -> OsString {
fallible::hostname_os()
.unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string().into())
.unwrap_or_else(|_| DEFAULT_HOSTNAME.to_lowercase().into())
}

/// Get the name of the operating system distribution and (possibly) version.
Expand Down
127 changes: 44 additions & 83 deletions src/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,37 +128,44 @@ fn string_from_os(string: OsString) -> String {
}
}

fn os_from_cstring_gecos(string: *const c_void) -> Option<OsString> {
fn os_from_cstring_gecos(string: *const c_void) -> Result<OsString> {
if string.is_null() {
return None;
return Err(Error::new(ErrorKind::NotFound, "Null record"));
}

// Get a byte slice of the c string.
let slice = unsafe {
let length = strlen_gecos(string);

if length == 0 {
return None;
return Err(Error::new(ErrorKind::InvalidData, "Empty record"));
}
std::slice::from_raw_parts(string as *const u8, length)

std::slice::from_raw_parts(string.cast(), length)
};

// Turn byte slice into Rust String.
Some(OsString::from_vec(slice.to_vec()))
Ok(OsString::from_vec(slice.to_vec()))
}

fn os_from_cstring(string: *const c_void) -> OsString {
fn os_from_cstring(string: *const c_void) -> Result<OsString> {
if string.is_null() {
return "".to_string().into();
return Err(Error::new(ErrorKind::NotFound, "Null record"));
}

// Get a byte slice of the c string.
let slice = unsafe {
let length = strlen(string);
std::slice::from_raw_parts(string as *const u8, length)

if length == 0 {
return Err(Error::new(ErrorKind::InvalidData, "Empty record"));
}

std::slice::from_raw_parts(string.cast(), length)
};

// Turn byte slice into Rust String.
OsString::from_vec(slice.to_vec())
Ok(OsString::from_vec(slice.to_vec()))
}

#[cfg(target_os = "macos")]
Expand Down Expand Up @@ -216,24 +223,18 @@ fn getpwuid(real: bool) -> Result<OsString> {
let _passwd = _passwd.assume_init();

if _passwd.is_null() {
return Err(Error::new(ErrorKind::NotFound, "Missing record"));
return Err(Error::new(ErrorKind::NotFound, "Null record"));
}

passwd.assume_init()
};

// Extract names.
Ok(if real {
let string = os_from_cstring_gecos(passwd.pw_gecos);
let result = if let Some(string) = string {
Ok(string)
} else {
Err(os_from_cstring(passwd.pw_name))
};
fancy_fallback_os(result)
if real {
os_from_cstring_gecos(passwd.pw_gecos)
} else {
os_from_cstring(passwd.pw_name)
})
}
}

pub(crate) fn username() -> Result<String> {
Expand All @@ -244,48 +245,6 @@ pub(crate) fn username_os() -> Result<OsString> {
getpwuid(false)
}

fn fancy_fallback(result: Result<&str, String>) -> String {
let mut cap = true;
let iter = match result {
Ok(a) => a.chars(),
Err(ref b) => b.chars(),
};
let mut new = String::new();
for c in iter {
match c {
'.' | '-' | '_' => {
new.push(' ');
cap = true;
}
a => {
if cap {
cap = false;
for i in a.to_uppercase() {
new.push(i);
}
} else {
new.push(a);
}
}
}
}
new
}

fn fancy_fallback_os(result: Result<OsString, OsString>) -> OsString {
match result {
Ok(success) => success,
Err(fallback) => {
let cs = match fallback.to_str() {
Some(a) => Ok(a),
None => Err(fallback.to_string_lossy().to_string()),
};

fancy_fallback(cs).into()
}
}
}

pub(crate) fn realname() -> Result<String> {
Ok(string_from_os(realname_os()?))
}
Expand All @@ -301,21 +260,21 @@ pub(crate) fn devicename_os() -> Result<OsString> {

#[cfg(not(any(target_os = "macos", target_os = "illumos")))]
pub(crate) fn devicename() -> Result<String> {
if let Ok(machine_info) = std::fs::read("/etc/machine-info") {
let machine_info = String::from_utf8_lossy(&machine_info);
let machine_info = std::fs::read("/etc/machine-info")?;
let machine_info = String::from_utf8_lossy(&machine_info);

for i in machine_info.split('\n') {
let mut j = i.split('=');
for i in machine_info.split('\n') {
let mut j = i.split('=');

if j.next() == Some("PRETTY_HOSTNAME") {
if let Some(value) = j.next() {
return Ok(value.trim_matches('"').to_string());
}
if j.next() == Some("PRETTY_HOSTNAME") {
if let Some(value) = j.next() {
// FIXME: Can " be escaped in pretty name?
return Ok(value.trim_matches('"').to_string());
}
}
}

Ok(fancy_fallback(Err(hostname()?)))
Err(Error::new(ErrorKind::NotFound, "Missing record"))
}

#[cfg(target_os = "macos")]
Expand All @@ -328,27 +287,26 @@ pub(crate) fn devicename_os() -> Result<OsString> {
let out = os_from_cfstring(unsafe {
SCDynamicStoreCopyComputerName(null_mut(), null_mut())
});
let computer = if out.as_bytes().is_empty() {
Err(hostname_os()?)
} else {
Ok(out)
};

Ok(fancy_fallback_os(computer))
if out.as_bytes().is_empty() {
return Err(Error::new(ErrorKind::InvalidData, "Empty record"));
}

Ok(out)
}

#[cfg(target_os = "illumos")]
pub(crate) fn devicename() -> Result<String> {
if let Ok(program) = std::fs::read("/etc/nodename") {
let mut nodename = String::from_utf8_lossy(&program).to_string();
let program = std::fs::read("/etc/nodename")?;
let mut nodename = String::from_utf8_lossy(&program).to_string();
// Remove the trailing newline
let _ = nodename.pop();

// Remove the trailing newline
nodename.pop();

return Ok(nodename);
if nodename.is_empty() {
return Err(Error::new(ErrorKind::InvalidData, "Empty record"));
}

Ok(fancy_fallback(Err(hostname()?)))
return Ok(nodename);
}

pub(crate) fn hostname() -> Result<String> {
Expand All @@ -374,12 +332,15 @@ fn hostname_os() -> Result<OsString> {
fn distro_xml(data: String) -> Result<String> {
let mut product_name = None;
let mut user_visible_version = None;

if let Some(start) = data.find("<dict>") {
if let Some(end) = data.find("</dict>") {
let mut set_product_name = false;
let mut set_user_visible_version = false;

for line in data[start + "<dict>".len()..end].lines() {
let line = line.trim();

if line.starts_with("<key>") {
match line["<key>".len()..].trim_end_matches("</key>") {
"ProductName" => set_product_name = true,
Expand Down
Loading

0 comments on commit c191aa8

Please sign in to comment.