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

Merge pull request #7892 from cakebaker/uptime_refactor_uumain

uptime: refactor `uumain`
This commit is contained in:
Sylvestre Ledru 2025-05-09 22:11:44 +02:00 committed by GitHub
commit 45b0c39ed7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 47 additions and 65 deletions

View file

@ -6,7 +6,8 @@
// spell-checker:ignore getloadavg behaviour loadavg uptime upsecs updays upmins uphours boottime nusers utmpxname gettime clockid
use chrono::{Local, TimeZone, Utc};
use clap::ArgMatches;
#[cfg(unix)]
use std::ffi::OsString;
use std::io;
use thiserror::Error;
use uucore::error::{UError, UResult};
@ -44,14 +45,10 @@ pub enum UptimeError {
// io::Error wrapper
#[error("couldn't get boot time: {0}")]
IoErr(#[from] io::Error),
#[error("couldn't get boot time: Is a directory")]
TargetIsDir,
#[error("couldn't get boot time: Illegal seek")]
TargetIsFifo,
#[error("extra operand '{0}'")]
ExtraOperandError(String),
}
impl UError for UptimeError {
@ -64,41 +61,22 @@ impl UError for UptimeError {
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uu_app().try_get_matches_from(args)?;
#[cfg(windows)]
return default_uptime(&matches);
#[cfg(unix)]
{
use std::ffi::OsString;
use uucore::error::set_exit_code;
use uucore::show_error;
let file_path = matches.get_one::<OsString>(options::PATH);
#[cfg(windows)]
let file_path = None;
let argument = matches.get_many::<OsString>(options::PATH);
// Switches to default uptime behaviour if there is no argument
if argument.is_none() {
return default_uptime(&matches);
}
let mut arg_iter = argument.unwrap();
let file_path = arg_iter.next().unwrap();
if let Some(path) = arg_iter.next() {
// Uptime doesn't attempt to calculate boot time if there is extra arguments.
// Its a fatal error
show_error!(
"{}",
UptimeError::ExtraOperandError(path.to_owned().into_string().unwrap())
);
set_exit_code(1);
return Ok(());
}
uptime_with_file(file_path)
if matches.get_flag(options::SINCE) {
uptime_since()
} else if let Some(path) = file_path {
uptime_with_file(path)
} else {
default_uptime()
}
}
pub fn uu_app() -> Command {
Command::new(uucore::util_name())
let cmd = Command::new(uucore::util_name())
.version(uucore::crate_version!())
.about(ABOUT)
.override_usage(format_usage(USAGE))
@ -109,18 +87,20 @@ pub fn uu_app() -> Command {
.long(options::SINCE)
.help("system up since")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(options::PATH)
.help("file to search boot time from")
.action(ArgAction::Append)
.value_parser(ValueParser::os_string())
.value_hint(ValueHint::AnyPath),
)
);
#[cfg(unix)]
cmd.arg(
Arg::new(options::PATH)
.help("file to search boot time from")
.action(ArgAction::Set)
.num_args(0..=1)
.value_parser(ValueParser::os_string())
.value_hint(ValueHint::AnyPath),
)
}
#[cfg(unix)]
fn uptime_with_file(file_path: &std::ffi::OsString) -> UResult<()> {
fn uptime_with_file(file_path: &OsString) -> UResult<()> {
use std::fs;
use std::os::unix::fs::FileTypeExt;
use uucore::error::set_exit_code;
@ -212,27 +192,29 @@ fn uptime_with_file(file_path: &std::ffi::OsString) -> UResult<()> {
Ok(())
}
fn uptime_since() -> UResult<()> {
#[cfg(unix)]
#[cfg(not(target_os = "openbsd"))]
let (boot_time, _) = process_utmpx(None);
#[cfg(target_os = "openbsd")]
let uptime = get_uptime(None)?;
#[cfg(unix)]
#[cfg(not(target_os = "openbsd"))]
let uptime = get_uptime(boot_time)?;
#[cfg(target_os = "windows")]
let uptime = get_uptime(None)?;
let initial_date = Local
.timestamp_opt(Utc::now().timestamp() - uptime, 0)
.unwrap();
println!("{}", initial_date.format("%Y-%m-%d %H:%M:%S"));
Ok(())
}
/// Default uptime behaviour i.e. when no file argument is given.
fn default_uptime(matches: &ArgMatches) -> UResult<()> {
if matches.get_flag(options::SINCE) {
#[cfg(unix)]
#[cfg(not(target_os = "openbsd"))]
let (boot_time, _) = process_utmpx(None);
#[cfg(target_os = "openbsd")]
let uptime = get_uptime(None)?;
#[cfg(unix)]
#[cfg(not(target_os = "openbsd"))]
let uptime = get_uptime(boot_time)?;
#[cfg(target_os = "windows")]
let uptime = get_uptime(None)?;
let initial_date = Local
.timestamp_opt(Utc::now().timestamp() - uptime, 0)
.unwrap();
println!("{}", initial_date.format("%Y-%m-%d %H:%M:%S"));
return Ok(());
}
fn default_uptime() -> UResult<()> {
print_time();
print_uptime(None)?;
print_nusers(None);
@ -251,7 +233,7 @@ fn print_loadavg() {
#[cfg(unix)]
#[cfg(not(target_os = "openbsd"))]
fn process_utmpx(file: Option<&std::ffi::OsString>) -> (Option<time_t>, usize) {
fn process_utmpx(file: Option<&OsString>) -> (Option<time_t>, usize) {
let mut nusers = 0;
let mut boot_time = None;

View file

@ -251,7 +251,7 @@ fn test_uptime_with_extra_argument() {
.arg("a")
.arg("b")
.fails()
.stderr_contains("extra operand 'b'");
.stderr_contains("unexpected value 'b'");
}
/// Checks whether uptime displays the correct stderr msg when its called with a directory
#[test]