From 0cfbdc909e7e04138881eee714eaeea762e4a5c5 Mon Sep 17 00:00:00 2001 From: Ian Manske Date: Wed, 15 May 2024 07:40:04 +0000 Subject: [PATCH] Fix `sys` panic (#12846) # Description This should fix #10155 where the `sys` command can panic due to date math in certain cases / on certain systems. # User-Facing Changes The `boot_time` column now has a date value instead of a formatted date string. This is technically a breaking change. --- crates/nu-command/src/system/sys/mod.rs | 34 +++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/crates/nu-command/src/system/sys/mod.rs b/crates/nu-command/src/system/sys/mod.rs index 5e0467c251..fcb40fd37d 100644 --- a/crates/nu-command/src/system/sys/mod.rs +++ b/crates/nu-command/src/system/sys/mod.rs @@ -16,9 +16,8 @@ pub use sys_::Sys; pub use temp::SysTemp; pub use users::SysUsers; -use chrono::{DateTime, Local}; +use chrono::{DateTime, FixedOffset, Local}; use nu_protocol::{record, Record, Span, Value}; -use std::time::{Duration, UNIX_EPOCH}; use sysinfo::{ Components, CpuRefreshKind, Disks, Networks, System, Users, MINIMUM_CPU_UPDATE_INTERVAL, }; @@ -171,22 +170,31 @@ pub fn host(span: Span) -> Record { record.push("hostname", Value::string(trim_cstyle_null(hostname), span)); } - record.push( - "uptime", - Value::duration(1000000000 * System::uptime() as i64, span), - ); + let uptime = System::uptime() + .saturating_mul(1_000_000_000) + .try_into() + .unwrap_or(i64::MAX); - // Creates a new SystemTime from the specified number of whole seconds - let d = UNIX_EPOCH + Duration::from_secs(System::boot_time()); - // Create DateTime from SystemTime - let datetime = DateTime::::from(d); - // Convert to local time and then rfc3339 - let timestamp_str = datetime.with_timezone(datetime.offset()).to_rfc3339(); - record.push("boot_time", Value::string(timestamp_str, span)); + record.push("uptime", Value::duration(uptime, span)); + + let boot_time = boot_time() + .map(|time| Value::date(time, span)) + .unwrap_or(Value::nothing(span)); + + record.push("boot_time", boot_time); record } +fn boot_time() -> Option> { + // Broken systems can apparently return really high values. + // See: https://github.com/nushell/nushell/issues/10155 + // First, try to convert u64 to i64, and then try to create a `DateTime`. + let secs = System::boot_time().try_into().ok()?; + let time = DateTime::from_timestamp(secs, 0)?; + Some(time.with_timezone(&Local).fixed_offset()) +} + pub fn temp(span: Span) -> Value { let components = Components::new_with_refreshed_list() .iter()