whoami/
os.rs

1#![allow(unsafe_code)]
2
3// Daku
4#[cfg_attr(all(target_arch = "wasm32", daku), path = "os/daku.rs")]
5// Redox
6#[cfg_attr(
7    all(target_os = "redox", not(target_arch = "wasm32")),
8    path = "os/redox.rs"
9)]
10// Unix
11#[cfg_attr(
12    all(
13        any(
14            target_os = "linux",
15            target_os = "macos",
16            target_os = "dragonfly",
17            target_os = "freebsd",
18            target_os = "netbsd",
19            target_os = "openbsd",
20            target_os = "illumos",
21            target_os = "hurd",
22        ),
23        not(target_arch = "wasm32")
24    ),
25    path = "os/unix.rs"
26)]
27// Wasi
28#[cfg_attr(
29    all(target_arch = "wasm32", target_os = "wasi"),
30    path = "os/wasi.rs"
31)]
32// Web
33#[cfg_attr(
34    all(
35        target_arch = "wasm32",
36        not(target_os = "wasi"),
37        not(daku),
38        feature = "web",
39    ),
40    path = "os/web.rs"
41)]
42// Windows
43#[cfg_attr(
44    all(target_os = "windows", not(target_arch = "wasm32")),
45    path = "os/windows.rs"
46)]
47mod target;
48
49use std::{
50    env::{self, VarError},
51    ffi::OsString,
52    io::{Error, ErrorKind},
53};
54
55use crate::{Arch, DesktopEnv, Platform, Result};
56
57/// Implement `Target for Os` to add platform support for a target.
58pub(crate) struct Os;
59
60/// Target platform support
61pub(crate) trait Target: Sized {
62    /// Return a semicolon-delimited string of language/COUNTRY codes.
63    fn langs(self) -> Result<String>;
64    /// Return the user's "real" / "full" name.
65    fn realname(self) -> Result<OsString>;
66    /// Return the user's username.
67    fn username(self) -> Result<OsString>;
68    /// Return the computer's "fancy" / "pretty" name.
69    fn devicename(self) -> Result<OsString>;
70    /// Return the computer's hostname.
71    fn hostname(self) -> Result<String>;
72    /// Return the OS distribution's name.
73    fn distro(self) -> Result<String>;
74    /// Return the desktop environment.
75    fn desktop_env(self) -> DesktopEnv;
76    /// Return the target platform.
77    fn platform(self) -> Platform;
78    /// Return the computer's CPU architecture.
79    fn arch(self) -> Result<Arch>;
80
81    /// Return the user's account name (usually just the username, but may
82    /// include an account server hostname).
83    fn account(self) -> Result<OsString> {
84        self.username()
85    }
86}
87
88// This is only used on some platforms
89#[allow(dead_code)]
90fn err_missing_record() -> Error {
91    Error::new(ErrorKind::NotFound, "Missing record")
92}
93
94// This is only used on some platforms
95#[allow(dead_code)]
96fn err_null_record() -> Error {
97    Error::new(ErrorKind::NotFound, "Null record")
98}
99
100// This is only used on some platforms
101#[allow(dead_code)]
102fn err_empty_record() -> Error {
103    Error::new(ErrorKind::NotFound, "Empty record")
104}
105
106// This is only used on some platforms
107#[allow(dead_code)]
108fn unix_lang() -> Result<String> {
109    let check_var = |var| {
110        env::var(var).map_err(|e| {
111            let kind = match e {
112                VarError::NotPresent => ErrorKind::NotFound,
113                VarError::NotUnicode(_) => ErrorKind::InvalidData,
114            };
115            Error::new(kind, e)
116        })
117    };
118
119    // Uses priority defined in
120    // <https://www.gnu.org/software/gettext/manual/html_node/Locale-Environment-Variables.html>
121    let locale = check_var("LC_ALL").or_else(|_| check_var("LANG"));
122
123    // The LANGUAGE environment variable takes precedence if and only if
124    // localization is enabled, i.e., LC_ALL / LANG is not "C".
125    // <https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html>
126    let langs = match &locale {
127        Ok(loc) if loc != "C" => check_var("LANGUAGE").or(locale),
128        _ => locale,
129    }?;
130
131    if langs.is_empty() {
132        return Err(err_empty_record());
133    }
134
135    Ok(langs)
136}