1use std::ffi::OsString;
9use std::path::Path;
10
11use clap::builder::ValueParser;
12use clap::{Arg, Command};
13use uucore::error::UResult;
14use uucore::format_usage;
15use uucore::translate;
16
17#[cfg(target_os = "openbsd")]
18use utmp_classic::{UtmpEntry, parse_from_path};
19#[cfg(not(target_os = "openbsd"))]
20use uucore::utmpx::{self, Utmpx};
21
22#[cfg(target_os = "openbsd")]
23const OPENBSD_UTMP_FILE: &str = "/var/run/utmp";
24
25static ARG_FILE: &str = "file";
26
27fn get_long_usage() -> String {
28 #[cfg(not(target_os = "openbsd"))]
29 let default_path: &str = utmpx::DEFAULT_FILE;
30 #[cfg(target_os = "openbsd")]
31 let default_path: &str = OPENBSD_UTMP_FILE;
32
33 translate!("users-long-usage", "default_path" => default_path)
34}
35
36#[uucore::main]
37pub fn uumain(args: impl uucore::Args) -> UResult<()> {
38 let matches = uucore::clap_localization::handle_clap_result(uu_app(), args)?;
39
40 let maybe_file: Option<&Path> = matches.get_one::<OsString>(ARG_FILE).map(AsRef::as_ref);
41
42 let mut users: Vec<String>;
43
44 #[cfg(target_os = "openbsd")]
46 {
47 let filename = maybe_file.unwrap_or(Path::new(OPENBSD_UTMP_FILE));
48 let entries = parse_from_path(filename).unwrap_or_default();
49 users = Vec::new();
50 for entry in entries {
51 if let UtmpEntry::UTMP {
52 line: _,
53 user,
54 host: _,
55 time: _,
56 } = entry
57 {
58 if !user.is_empty() {
59 users.push(user);
60 }
61 }
62 }
63 };
64 #[cfg(not(target_os = "openbsd"))]
65 {
66 let filename = maybe_file.unwrap_or(utmpx::DEFAULT_FILE.as_ref());
67
68 users = Utmpx::iter_all_records_from(filename)
69 .filter(|ut| ut.is_user_process())
70 .map(|ut| ut.user())
71 .collect::<Vec<_>>();
72 };
73
74 if !users.is_empty() {
75 users.sort();
76 println!("{}", users.join(" "));
77 }
78
79 Ok(())
80}
81
82pub fn uu_app() -> Command {
83 #[cfg(not(target_env = "musl"))]
84 let about = translate!("users-about");
85 #[cfg(target_env = "musl")]
86 let about = translate!("users-about") + &translate!("users-about-musl-warning");
87
88 Command::new(uucore::util_name())
89 .version(uucore::crate_version!())
90 .help_template(uucore::localized_help_template(uucore::util_name()))
91 .about(about)
92 .override_usage(format_usage(&translate!("users-usage")))
93 .infer_long_args(true)
94 .after_help(get_long_usage())
95 .arg(
96 Arg::new(ARG_FILE)
97 .num_args(1)
98 .value_hint(clap::ValueHint::FilePath)
99 .value_parser(ValueParser::os_string()),
100 )
101}