From 1cc260d4146b29dc404301ab34015776dca57da9 Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Sun, 24 Nov 2024 22:56:45 +0700 Subject: [PATCH 01/20] tests/dmesg: add time-format option test & fixtures. --- tests/by-util/test_dmesg.rs | 16 ++++++++++++++++ tests/fixtures/dmesg/kmsg.input.1 | Bin 0 -> 172 bytes .../dmesg/test_kmsg_time_format_ctime.expected | 5 +++++ .../dmesg/test_kmsg_time_format_delta.expected | 5 +++++ .../dmesg/test_kmsg_time_format_iso.expected | 5 +++++ .../dmesg/test_kmsg_time_format_notime.expected | 5 +++++ .../dmesg/test_kmsg_time_format_raw.expected | 5 +++++ .../test_kmsg_time_format_reltime.expected | 5 +++++ 8 files changed, 46 insertions(+) create mode 100644 tests/fixtures/dmesg/kmsg.input.1 create mode 100644 tests/fixtures/dmesg/test_kmsg_time_format_ctime.expected create mode 100644 tests/fixtures/dmesg/test_kmsg_time_format_delta.expected create mode 100644 tests/fixtures/dmesg/test_kmsg_time_format_iso.expected create mode 100644 tests/fixtures/dmesg/test_kmsg_time_format_notime.expected create mode 100644 tests/fixtures/dmesg/test_kmsg_time_format_raw.expected create mode 100644 tests/fixtures/dmesg/test_kmsg_time_format_reltime.expected diff --git a/tests/by-util/test_dmesg.rs b/tests/by-util/test_dmesg.rs index 08e398a..c174518 100644 --- a/tests/by-util/test_dmesg.rs +++ b/tests/by-util/test_dmesg.rs @@ -30,3 +30,19 @@ fn test_kmsg_json() { .no_stderr() .stdout_is_templated_fixture("test_kmsg_json.expected", &[("\r\n", "\n")]); } + +#[test] +fn test_kmsg_time_format() { + let time_formats = ["delta", "reltime", "ctime", "notime", "iso", "raw"]; + for format in time_formats { + let time_format_arg = format!("--time-format={format}"); + let expected_output = format!("test_kmsg_time_format_{format}.expected"); + new_ucmd!() + .arg("--kmsg-file") + .arg("kmsg.input.1") + .arg(time_format_arg) + .succeeds() + .no_stderr() + .stdout_is_fixture(expected_output); + } +} diff --git a/tests/fixtures/dmesg/kmsg.input.1 b/tests/fixtures/dmesg/kmsg.input.1 new file mode 100644 index 0000000000000000000000000000000000000000..8c2a5cbd83419599e8dd133b9bb3662049ad743d GIT binary patch literal 172 zcmXpu(lO96(9yN_@pq4R^>qz$R{*gbLqj~c7%U8Q40TKmKmeE(UWW9U~oM sFu+jd9OUoE#b9KjW2|EcGR6SYDi=prUyvdT3mp?36AK)w+(H7l0L^SE2mk;8 literal 0 HcmV?d00001 diff --git a/tests/fixtures/dmesg/test_kmsg_time_format_ctime.expected b/tests/fixtures/dmesg/test_kmsg_time_format_ctime.expected new file mode 100644 index 0000000..559346d --- /dev/null +++ b/tests/fixtures/dmesg/test_kmsg_time_format_ctime.expected @@ -0,0 +1,5 @@ +[Mon Nov 18 19:34:12 2024] LOG_EMERG LOG_AUTH +[Mon Nov 18 19:34:13 2024] LOG_EMERG LOG_AUTHPRIV +[Mon Nov 18 19:34:13 2024] LOG_EMERG LOG_CRON +[Mon Nov 18 19:34:13 2024] LOG_EMERG LOG_DAEMON +[Mon Nov 18 19:35:00 2024] LOG_EMERG LOG_FTP diff --git a/tests/fixtures/dmesg/test_kmsg_time_format_delta.expected b/tests/fixtures/dmesg/test_kmsg_time_format_delta.expected new file mode 100644 index 0000000..81b8aad --- /dev/null +++ b/tests/fixtures/dmesg/test_kmsg_time_format_delta.expected @@ -0,0 +1,5 @@ +[< 0.000000>] LOG_EMERG LOG_AUTH +[< 0.000000>] LOG_EMERG LOG_AUTHPRIV +[< -0.166667>] LOG_EMERG LOG_CRON +[< 0.666667>] LOG_EMERG LOG_DAEMON +[< 47.000000>] LOG_EMERG LOG_FTP diff --git a/tests/fixtures/dmesg/test_kmsg_time_format_iso.expected b/tests/fixtures/dmesg/test_kmsg_time_format_iso.expected new file mode 100644 index 0000000..199ef99 --- /dev/null +++ b/tests/fixtures/dmesg/test_kmsg_time_format_iso.expected @@ -0,0 +1,5 @@ +2024-11-18T19:34:12,866807+07:00 LOG_EMERG LOG_AUTH +2024-11-18T19:34:13,366807+07:00 LOG_EMERG LOG_AUTHPRIV +2024-11-18T19:34:13,200140+07:00 LOG_EMERG LOG_CRON +2024-11-18T19:34:13,866807+07:00 LOG_EMERG LOG_DAEMON +2024-11-18T19:35:00,866807+07:00 LOG_EMERG LOG_FTP diff --git a/tests/fixtures/dmesg/test_kmsg_time_format_notime.expected b/tests/fixtures/dmesg/test_kmsg_time_format_notime.expected new file mode 100644 index 0000000..e16d233 --- /dev/null +++ b/tests/fixtures/dmesg/test_kmsg_time_format_notime.expected @@ -0,0 +1,5 @@ +LOG_EMERG LOG_AUTH +LOG_EMERG LOG_AUTHPRIV +LOG_EMERG LOG_CRON +LOG_EMERG LOG_DAEMON +LOG_EMERG LOG_FTP diff --git a/tests/fixtures/dmesg/test_kmsg_time_format_raw.expected b/tests/fixtures/dmesg/test_kmsg_time_format_raw.expected new file mode 100644 index 0000000..df70bd8 --- /dev/null +++ b/tests/fixtures/dmesg/test_kmsg_time_format_raw.expected @@ -0,0 +1,5 @@ +[ 0.000000] LOG_EMERG LOG_AUTH +[ 0.500000] LOG_EMERG LOG_AUTHPRIV +[ 0.333333] LOG_EMERG LOG_CRON +[ 1.000000] LOG_EMERG LOG_DAEMON +[ 48.000000] LOG_EMERG LOG_FTP diff --git a/tests/fixtures/dmesg/test_kmsg_time_format_reltime.expected b/tests/fixtures/dmesg/test_kmsg_time_format_reltime.expected new file mode 100644 index 0000000..6cebd19 --- /dev/null +++ b/tests/fixtures/dmesg/test_kmsg_time_format_reltime.expected @@ -0,0 +1,5 @@ +[Nov18 19:34] LOG_EMERG LOG_AUTH +[ +0.000000] LOG_EMERG LOG_AUTHPRIV +[ -0.166667] LOG_EMERG LOG_CRON +[ +0.666667] LOG_EMERG LOG_DAEMON +[Nov18 19:35] LOG_EMERG LOG_FTP From 4c7d8f8253f74994ca7314944ae4a24548d40294 Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Sun, 24 Nov 2024 23:12:26 +0700 Subject: [PATCH 02/20] tests/dmesg: add invalid time-format test. --- tests/by-util/test_dmesg.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/by-util/test_dmesg.rs b/tests/by-util/test_dmesg.rs index c174518..f8c6df5 100644 --- a/tests/by-util/test_dmesg.rs +++ b/tests/by-util/test_dmesg.rs @@ -46,3 +46,13 @@ fn test_kmsg_time_format() { .stdout_is_fixture(expected_output); } } + +#[test] +fn test_invalid_time_format() { + new_ucmd!() + .arg("--time-format=definitely-invalid") + .fails() + .code_is(1) + .no_stdout() + .stderr_is("dmesg: unknown time format: definitely-invalid"); +} From 7dc792491570e223118b51b087e8725f6cbc45cd Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Sun, 24 Nov 2024 23:13:51 +0700 Subject: [PATCH 03/20] dmesg: add time-format command arg. --- src/uu/dmesg/src/dmesg.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/uu/dmesg/src/dmesg.rs b/src/uu/dmesg/src/dmesg.rs index 8fb64f7..0e590cc 100644 --- a/src/uu/dmesg/src/dmesg.rs +++ b/src/uu/dmesg/src/dmesg.rs @@ -49,11 +49,21 @@ pub fn uu_app() -> Command { .help("use JSON output format") .action(ArgAction::SetTrue), ) + .arg( + Arg::new(options::TIME_FORMAT) + .long("time-format") + .help( + "show timestamp using the given format:\n".to_string() + + " [delta|reltime|ctime|notime|iso|raw]", + ) + .action(ArgAction::Set), + ) } mod options { pub const KMSG_FILE: &str = "kmsg-file"; pub const JSON: &str = "json"; + pub const TIME_FORMAT: &str = "time-format"; } struct Dmesg<'a> { From c893226fe8e8763675f9d57ee2bc8678f05445a6 Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Mon, 25 Nov 2024 13:03:54 +0700 Subject: [PATCH 04/20] dmesg: support normal print with raw time format. --- src/uu/dmesg/src/dmesg.rs | 27 ++++++++++++++++++++++++++- src/uu/dmesg/src/time_formatter.rs | 5 +++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/uu/dmesg/src/time_formatter.rs diff --git a/src/uu/dmesg/src/dmesg.rs b/src/uu/dmesg/src/dmesg.rs index 0e590cc..58c4d57 100644 --- a/src/uu/dmesg/src/dmesg.rs +++ b/src/uu/dmesg/src/dmesg.rs @@ -12,6 +12,7 @@ use uucore::{ }; mod json; +mod time_formatter; const ABOUT: &str = help_about!("dmesg.md"); const USAGE: &str = help_usage!("dmesg.md"); @@ -69,6 +70,7 @@ mod options { struct Dmesg<'a> { kmsg_file: &'a str, output_format: OutputFormat, + time_format: TimeFormat, records: Option>, } @@ -77,6 +79,7 @@ impl Dmesg<'_> { Dmesg { kmsg_file: "/dev/kmsg", output_format: OutputFormat::Normal, + time_format: TimeFormat::Raw, records: None, } } @@ -122,7 +125,7 @@ impl Dmesg<'_> { fn print(&self) { match self.output_format { OutputFormat::Json => self.print_json(), - OutputFormat::Normal => unimplemented!(), + OutputFormat::Normal => self.print_normal(), } } @@ -131,6 +134,20 @@ impl Dmesg<'_> { println!("{}", json::serialize_records(records)); } } + + fn print_normal(&self) { + if let Some(records) = &self.records { + for record in records { + match self.time_format { + TimeFormat::Raw => { + print!("[{}] ", time_formatter::raw(record.timestamp_us)) + } + _ => unimplemented!(), + } + println!("{}", record.message); + } + } + } } enum OutputFormat { @@ -138,6 +155,14 @@ enum OutputFormat { Json, } +enum TimeFormat { + Delta, + Reltime, + Ctime, + Iso, + Raw, +} + struct Record { priority_facility: u32, _sequence: u64, diff --git a/src/uu/dmesg/src/time_formatter.rs b/src/uu/dmesg/src/time_formatter.rs new file mode 100644 index 0000000..24c31bb --- /dev/null +++ b/src/uu/dmesg/src/time_formatter.rs @@ -0,0 +1,5 @@ +pub fn raw(timestamp_us: u64) -> String { + let seconds = timestamp_us / 1000000; + let sub_seconds = timestamp_us % 1000000; + format!("{:>5}.{:0>6}", seconds, sub_seconds) +} From 49bd8ead505e938346110cc17b6f859d04dfca13 Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Mon, 25 Nov 2024 13:26:35 +0700 Subject: [PATCH 05/20] dmesg: parse time-format command line argument. --- src/uu/dmesg/src/dmesg.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/uu/dmesg/src/dmesg.rs b/src/uu/dmesg/src/dmesg.rs index 58c4d57..5392e67 100644 --- a/src/uu/dmesg/src/dmesg.rs +++ b/src/uu/dmesg/src/dmesg.rs @@ -27,6 +27,22 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if matches.get_flag(options::JSON) { dmesg.output_format = OutputFormat::Json; } + if let Some(time_format) = matches.get_one::(options::TIME_FORMAT) { + match &time_format[..] { + "delta" => dmesg.time_format = TimeFormat::Delta, + "reltime" => dmesg.time_format = TimeFormat::Reltime, + "ctime" => dmesg.time_format = TimeFormat::Ctime, + "notime" => dmesg.time_format = TimeFormat::Notime, + "iso" => dmesg.time_format = TimeFormat::Iso, + "raw" => dmesg.time_format = TimeFormat::Raw, + _ => { + return Err(USimpleError::new( + 1, + format!("unknown time format: {time_format}"), + )) + } + } + } dmesg.parse()?.print(); Ok(()) } @@ -159,6 +175,7 @@ enum TimeFormat { Delta, Reltime, Ctime, + Notime, Iso, Raw, } From f6826b82492dbe3641a1974d5963bdf233f8d5a2 Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Mon, 25 Nov 2024 13:28:00 +0700 Subject: [PATCH 06/20] tests/dmesg: add new line to expected error message. --- tests/by-util/test_dmesg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/by-util/test_dmesg.rs b/tests/by-util/test_dmesg.rs index f8c6df5..82a0078 100644 --- a/tests/by-util/test_dmesg.rs +++ b/tests/by-util/test_dmesg.rs @@ -54,5 +54,5 @@ fn test_invalid_time_format() { .fails() .code_is(1) .no_stdout() - .stderr_is("dmesg: unknown time format: definitely-invalid"); + .stderr_is("dmesg: unknown time format: definitely-invalid\n"); } From 4c1812f128049781442ff0f130994af43436ffaa Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Mon, 25 Nov 2024 13:53:12 +0700 Subject: [PATCH 07/20] tests/dmesg: separate time format tests. --- tests/by-util/test_dmesg.rs | 52 +++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/tests/by-util/test_dmesg.rs b/tests/by-util/test_dmesg.rs index 82a0078..51642e6 100644 --- a/tests/by-util/test_dmesg.rs +++ b/tests/by-util/test_dmesg.rs @@ -32,19 +32,45 @@ fn test_kmsg_json() { } #[test] -fn test_kmsg_time_format() { - let time_formats = ["delta", "reltime", "ctime", "notime", "iso", "raw"]; - for format in time_formats { - let time_format_arg = format!("--time-format={format}"); - let expected_output = format!("test_kmsg_time_format_{format}.expected"); - new_ucmd!() - .arg("--kmsg-file") - .arg("kmsg.input.1") - .arg(time_format_arg) - .succeeds() - .no_stderr() - .stdout_is_fixture(expected_output); - } +fn test_kmsg_time_format_delta() { + test_kmsg_time_format("delta"); +} + +#[test] +fn test_kmsg_time_format_reltime() { + test_kmsg_time_format("reltime"); +} + +#[test] +fn test_kmsg_time_format_ctime() { + test_kmsg_time_format("ctime"); +} + +#[test] +fn test_kmsg_time_format_notime() { + test_kmsg_time_format("notime"); +} + +#[test] +fn test_kmsg_time_format_iso() { + test_kmsg_time_format("iso"); +} + +#[test] +fn test_kmsg_time_format_raw() { + test_kmsg_time_format("raw"); +} + +fn test_kmsg_time_format(format: &str) { + let time_format_arg = format!("--time-format={format}"); + let expected_output = format!("test_kmsg_time_format_{format}.expected"); + new_ucmd!() + .arg("--kmsg-file") + .arg("kmsg.input.1") + .arg(time_format_arg) + .succeeds() + .no_stderr() + .stdout_is_fixture(expected_output); } #[test] From a99abce42522b0aade3451bbe0065db43a4d179e Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Mon, 25 Nov 2024 19:54:33 +0700 Subject: [PATCH 08/20] dmesg: support ctime & notime time-format. --- Cargo.lock | 208 ++++++++++++++++++++++++++++- Cargo.toml | 2 + src/uu/dmesg/Cargo.toml | 5 + src/uu/dmesg/src/dmesg.rs | 4 + src/uu/dmesg/src/time_formatter.rs | 35 +++++ 5 files changed, 253 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index da6a312..59992db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "aho-corasick" version = "1.1.3" @@ -11,6 +17,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.15" @@ -60,6 +81,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + [[package]] name = "bitflags" version = "1.3.2" @@ -72,6 +99,12 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "bytecount" version = "0.6.8" @@ -84,6 +117,15 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "cc" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +dependencies = [ + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -96,6 +138,20 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.6", +] + [[package]] name = "clap" version = "4.5.21" @@ -155,6 +211,15 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -229,6 +294,16 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +[[package]] +name = "flate2" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -270,6 +345,29 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core 0.52.0", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "io-lifetimes" version = "1.0.11" @@ -293,6 +391,15 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.164" @@ -311,12 +418,27 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "nix" version = "0.29.0" @@ -344,6 +466,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "num_threads" version = "0.1.7" @@ -488,6 +619,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" dependencies = [ "bitflags 2.6.0", + "chrono", + "flate2", "hex", "procfs-core", "rustix 0.38.39", @@ -500,6 +633,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" dependencies = [ "bitflags 2.6.0", + "chrono", "hex", ] @@ -671,6 +805,12 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "siphasher" version = "0.3.11" @@ -903,7 +1043,9 @@ dependencies = [ name = "uu_dmesg" version = "0.0.1" dependencies = [ + "chrono", "clap", + "procfs", "regex", "serde", "serde_json", @@ -1013,6 +1155,61 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.82", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.82", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + [[package]] name = "wild" version = "2.2.1" @@ -1050,7 +1247,16 @@ version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" dependencies = [ - "windows-core", + "windows-core 0.57.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ "windows-targets 0.52.6", ] diff --git a/Cargo.toml b/Cargo.toml index 88c5e32..6d61165 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,6 +82,8 @@ tempfile = { workspace = true } libc = { workspace = true } rand = { workspace = true } uucore = { workspace = true, features = ["entries", "process", "signals"] } +# dmesg test require fixed-boot-time feature turned on. +dmesg = { version = "0.0.1", package = "uu_dmesg", path = "src/uu/dmesg", features = ["fixed-boot-time"] } [target.'cfg(unix)'.dev-dependencies] xattr = { workspace = true } diff --git a/src/uu/dmesg/Cargo.toml b/src/uu/dmesg/Cargo.toml index 96df1cc..5b95a2c 100644 --- a/src/uu/dmesg/Cargo.toml +++ b/src/uu/dmesg/Cargo.toml @@ -16,3 +16,8 @@ uucore = { workspace = true } regex = { workspace = true } serde_json = { workspace = true } serde = { workspace = true } +chrono = "0.4.38" +procfs = "0.17" + +[features] +fixed-boot-time = [] diff --git a/src/uu/dmesg/src/dmesg.rs b/src/uu/dmesg/src/dmesg.rs index 5392e67..0e33c36 100644 --- a/src/uu/dmesg/src/dmesg.rs +++ b/src/uu/dmesg/src/dmesg.rs @@ -155,9 +155,13 @@ impl Dmesg<'_> { if let Some(records) = &self.records { for record in records { match self.time_format { + TimeFormat::Ctime => { + print!("[{}] ", time_formatter::ctime(record.timestamp_us)) + } TimeFormat::Raw => { print!("[{}] ", time_formatter::raw(record.timestamp_us)) } + TimeFormat::Notime => (), _ => unimplemented!(), } println!("{}", record.message); diff --git a/src/uu/dmesg/src/time_formatter.rs b/src/uu/dmesg/src/time_formatter.rs index 24c31bb..92155c6 100644 --- a/src/uu/dmesg/src/time_formatter.rs +++ b/src/uu/dmesg/src/time_formatter.rs @@ -1,5 +1,40 @@ +use chrono::{DateTime, FixedOffset, TimeDelta, Timelike}; +#[cfg(feature = "fixed-boot-time")] +use chrono::{NaiveDate, NaiveTime}; +use std::sync::OnceLock; + pub fn raw(timestamp_us: u64) -> String { let seconds = timestamp_us / 1000000; let sub_seconds = timestamp_us % 1000000; format!("{:>5}.{:0>6}", seconds, sub_seconds) } + +pub fn ctime(timestamp_us: u64) -> String { + let mut date_time = boot_time() + .checked_add_signed(TimeDelta::microseconds(timestamp_us as i64)) + .unwrap(); + // dmesg always round up sub seconds. + if date_time.time().nanosecond() > 0 { + date_time = date_time.checked_add_signed(TimeDelta::seconds(1)).unwrap(); + } + date_time.format("%a %b %d %H:%M:%S %Y").to_string() +} + +static BOOT_TIME: OnceLock> = OnceLock::new(); + +#[cfg(feature = "fixed-boot-time")] +fn boot_time() -> DateTime { + *BOOT_TIME.get_or_init(|| { + let date = NaiveDate::from_ymd_opt(2024, 11, 18).unwrap(); + let time = NaiveTime::from_hms_opt(19, 34, 12).unwrap(); + let tz = FixedOffset::east_opt(7 * 3600).unwrap(); + chrono::NaiveDateTime::new(date, time) + .and_local_timezone(tz) + .unwrap() + }) +} + +#[cfg(not(feature = "fixed-boot-time"))] +fn boot_time() -> DateTime { + *BOOT_TIME.get_or_init(|| procfs::boot_time().unwrap().into()) +} From 9f665333cfab32a2eeab28eeebf271aed9e6f3e1 Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Tue, 26 Nov 2024 10:56:52 +0700 Subject: [PATCH 09/20] dmesg: corrected fixed boot time value. --- src/uu/dmesg/src/time_formatter.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/uu/dmesg/src/time_formatter.rs b/src/uu/dmesg/src/time_formatter.rs index 92155c6..59cd867 100644 --- a/src/uu/dmesg/src/time_formatter.rs +++ b/src/uu/dmesg/src/time_formatter.rs @@ -1,4 +1,4 @@ -use chrono::{DateTime, FixedOffset, TimeDelta, Timelike}; +use chrono::{DateTime, FixedOffset, TimeDelta}; #[cfg(feature = "fixed-boot-time")] use chrono::{NaiveDate, NaiveTime}; use std::sync::OnceLock; @@ -10,13 +10,9 @@ pub fn raw(timestamp_us: u64) -> String { } pub fn ctime(timestamp_us: u64) -> String { - let mut date_time = boot_time() + let date_time = boot_time() .checked_add_signed(TimeDelta::microseconds(timestamp_us as i64)) .unwrap(); - // dmesg always round up sub seconds. - if date_time.time().nanosecond() > 0 { - date_time = date_time.checked_add_signed(TimeDelta::seconds(1)).unwrap(); - } date_time.format("%a %b %d %H:%M:%S %Y").to_string() } @@ -26,7 +22,7 @@ static BOOT_TIME: OnceLock> = OnceLock::new(); fn boot_time() -> DateTime { *BOOT_TIME.get_or_init(|| { let date = NaiveDate::from_ymd_opt(2024, 11, 18).unwrap(); - let time = NaiveTime::from_hms_opt(19, 34, 12).unwrap(); + let time = NaiveTime::from_hms_micro_opt(19, 34, 12, 866807).unwrap(); let tz = FixedOffset::east_opt(7 * 3600).unwrap(); chrono::NaiveDateTime::new(date, time) .and_local_timezone(tz) From c13e2f7b5afccb89066ead63b36efc817a3ecc5d Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Tue, 26 Nov 2024 10:57:45 +0700 Subject: [PATCH 10/20] dmesg: support iso time-format. --- src/uu/dmesg/src/dmesg.rs | 3 +++ src/uu/dmesg/src/time_formatter.rs | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/uu/dmesg/src/dmesg.rs b/src/uu/dmesg/src/dmesg.rs index 0e33c36..51153d5 100644 --- a/src/uu/dmesg/src/dmesg.rs +++ b/src/uu/dmesg/src/dmesg.rs @@ -158,6 +158,9 @@ impl Dmesg<'_> { TimeFormat::Ctime => { print!("[{}] ", time_formatter::ctime(record.timestamp_us)) } + TimeFormat::Iso => { + print!("{} ", time_formatter::iso(record.timestamp_us)) + } TimeFormat::Raw => { print!("[{}] ", time_formatter::raw(record.timestamp_us)) } diff --git a/src/uu/dmesg/src/time_formatter.rs b/src/uu/dmesg/src/time_formatter.rs index 59cd867..23e0bbe 100644 --- a/src/uu/dmesg/src/time_formatter.rs +++ b/src/uu/dmesg/src/time_formatter.rs @@ -16,6 +16,13 @@ pub fn ctime(timestamp_us: u64) -> String { date_time.format("%a %b %d %H:%M:%S %Y").to_string() } +pub fn iso(timestamp_us: u64) -> String { + let date_time = boot_time() + .checked_add_signed(TimeDelta::microseconds(timestamp_us as i64)) + .unwrap(); + date_time.format("%Y-%m-%dT%H:%M:%S,%6f%:z").to_string() +} + static BOOT_TIME: OnceLock> = OnceLock::new(); #[cfg(feature = "fixed-boot-time")] From 2669aaae4003a7b1d365122d1942249ca7c4f0d7 Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Tue, 26 Nov 2024 22:43:07 +0700 Subject: [PATCH 11/20] dmesg: support reltime time-format. --- src/uu/dmesg/src/dmesg.rs | 7 ++++ src/uu/dmesg/src/time_formatter.rs | 54 ++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/uu/dmesg/src/dmesg.rs b/src/uu/dmesg/src/dmesg.rs index 51153d5..1298d09 100644 --- a/src/uu/dmesg/src/dmesg.rs +++ b/src/uu/dmesg/src/dmesg.rs @@ -153,8 +153,15 @@ impl Dmesg<'_> { fn print_normal(&self) { if let Some(records) = &self.records { + let mut reltime_formatter = time_formatter::ReltimeFormatter::new(); for record in records { match self.time_format { + TimeFormat::Reltime => { + print!( + "[{}] ", + reltime_formatter.format(record.timestamp_us as i64) + ) + } TimeFormat::Ctime => { print!("[{}] ", time_formatter::ctime(record.timestamp_us)) } diff --git a/src/uu/dmesg/src/time_formatter.rs b/src/uu/dmesg/src/time_formatter.rs index 23e0bbe..26b4833 100644 --- a/src/uu/dmesg/src/time_formatter.rs +++ b/src/uu/dmesg/src/time_formatter.rs @@ -23,6 +23,60 @@ pub fn iso(timestamp_us: u64) -> String { date_time.format("%Y-%m-%dT%H:%M:%S,%6f%:z").to_string() } +pub struct ReltimeFormatter { + state: State, + prev_timestamp_us: i64, + previous_unix_timestamp: i64, +} + +pub enum State { + Initial, + AfterBoot, + Delta, +} + +impl ReltimeFormatter { + pub fn new() -> Self { + ReltimeFormatter { + state: State::Initial, + prev_timestamp_us: 0, + previous_unix_timestamp: 0, + } + } + + pub fn format(&mut self, timestamp_us: i64) -> String { + let date_time = boot_time() + .checked_add_signed(TimeDelta::microseconds(timestamp_us)) + .unwrap(); + let unix_timestamp = date_time.timestamp(); + let minute_changes = (unix_timestamp / 60) != (self.previous_unix_timestamp / 60); + let format_res = match self.state { + State::Initial => date_time.format("%b%d %H:%M").to_string(), + _ if minute_changes => date_time.format("%b%d %H:%M").to_string(), + State::AfterBoot => Self::delta(0), + State::Delta => Self::delta(timestamp_us - self.prev_timestamp_us), + }; + self.prev_timestamp_us = timestamp_us; + self.previous_unix_timestamp = unix_timestamp; + self.state = match self.state { + State::Initial if timestamp_us == 0 => State::AfterBoot, + _ => State::Delta, + }; + format_res + } + + fn delta(delta_us: i64) -> String { + let seconds = i64::abs(delta_us / 1000000); + let sub_seconds = i64::abs(delta_us % 1000000); + let sign = if delta_us >= 0 { 1.0 } else { -1.0 }; + format!( + "{:>+4.0}.{:0>6}", + sign * f64::from(seconds as i32), + sub_seconds + ) + } +} + static BOOT_TIME: OnceLock> = OnceLock::new(); #[cfg(feature = "fixed-boot-time")] From 8efc8a01c27da2a8efb233a1dac27fb92ded894f Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Tue, 26 Nov 2024 23:34:18 +0700 Subject: [PATCH 12/20] dmesg: support delta time-format. --- src/uu/dmesg/src/dmesg.rs | 5 +++- src/uu/dmesg/src/time_formatter.rs | 38 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/uu/dmesg/src/dmesg.rs b/src/uu/dmesg/src/dmesg.rs index 1298d09..1343bbc 100644 --- a/src/uu/dmesg/src/dmesg.rs +++ b/src/uu/dmesg/src/dmesg.rs @@ -154,8 +154,12 @@ impl Dmesg<'_> { fn print_normal(&self) { if let Some(records) = &self.records { let mut reltime_formatter = time_formatter::ReltimeFormatter::new(); + let mut delta_formatter = time_formatter::DeltaFormatter::new(); for record in records { match self.time_format { + TimeFormat::Delta => { + print!("[{}] ", delta_formatter.format(record.timestamp_us as i64)) + } TimeFormat::Reltime => { print!( "[{}] ", @@ -172,7 +176,6 @@ impl Dmesg<'_> { print!("[{}] ", time_formatter::raw(record.timestamp_us)) } TimeFormat::Notime => (), - _ => unimplemented!(), } println!("{}", record.message); } diff --git a/src/uu/dmesg/src/time_formatter.rs b/src/uu/dmesg/src/time_formatter.rs index 26b4833..4f21ab5 100644 --- a/src/uu/dmesg/src/time_formatter.rs +++ b/src/uu/dmesg/src/time_formatter.rs @@ -29,6 +29,11 @@ pub struct ReltimeFormatter { previous_unix_timestamp: i64, } +pub struct DeltaFormatter { + state: State, + prev_timestamp_us: i64, +} + pub enum State { Initial, AfterBoot, @@ -77,6 +82,39 @@ impl ReltimeFormatter { } } +impl DeltaFormatter { + pub fn new() -> Self { + DeltaFormatter { + state: State::Initial, + prev_timestamp_us: 0, + } + } + + pub fn format(&mut self, timestamp_us: i64) -> String { + let format_res = match self.state { + State::Delta => Self::delta(timestamp_us - self.prev_timestamp_us), + _ => Self::delta(0), + }; + self.prev_timestamp_us = timestamp_us; + self.state = match self.state { + State::Initial if timestamp_us == 0 => State::AfterBoot, + _ => State::Delta, + }; + format_res + } + + fn delta(delta_us: i64) -> String { + let seconds = i64::abs(delta_us / 1000000); + let sub_seconds = i64::abs(delta_us % 1000000); + let sign = if delta_us >= 0 { 1.0 } else { -1.0 }; + format!( + "<{:>5.0}.{:0>6}>", + sign * f64::from(seconds as i32), + sub_seconds + ) + } +} + static BOOT_TIME: OnceLock> = OnceLock::new(); #[cfg(feature = "fixed-boot-time")] From f621687dd6ac6659ed640d8253c5c85fed443d31 Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Wed, 27 Nov 2024 00:45:13 +0700 Subject: [PATCH 13/20] dmesg: use utmpx to get boot time. --- Cargo.lock | 38 ------------------------------ src/uu/dmesg/Cargo.toml | 1 - src/uu/dmesg/src/time_formatter.rs | 36 +++++++++++++++++++++++++++- 3 files changed, 35 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59992db..e4ee481 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - [[package]] name = "aho-corasick" version = "1.1.3" @@ -211,15 +205,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -294,16 +279,6 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" -[[package]] -name = "flate2" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "fnv" version = "1.0.7" @@ -430,15 +405,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "miniz_oxide" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" -dependencies = [ - "adler2", -] - [[package]] name = "nix" version = "0.29.0" @@ -619,8 +585,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" dependencies = [ "bitflags 2.6.0", - "chrono", - "flate2", "hex", "procfs-core", "rustix 0.38.39", @@ -633,7 +597,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" dependencies = [ "bitflags 2.6.0", - "chrono", "hex", ] @@ -1045,7 +1008,6 @@ version = "0.0.1" dependencies = [ "chrono", "clap", - "procfs", "regex", "serde", "serde_json", diff --git a/src/uu/dmesg/Cargo.toml b/src/uu/dmesg/Cargo.toml index 5b95a2c..c6a8870 100644 --- a/src/uu/dmesg/Cargo.toml +++ b/src/uu/dmesg/Cargo.toml @@ -17,7 +17,6 @@ regex = { workspace = true } serde_json = { workspace = true } serde = { workspace = true } chrono = "0.4.38" -procfs = "0.17" [features] fixed-boot-time = [] diff --git a/src/uu/dmesg/src/time_formatter.rs b/src/uu/dmesg/src/time_formatter.rs index 4f21ab5..8c09907 100644 --- a/src/uu/dmesg/src/time_formatter.rs +++ b/src/uu/dmesg/src/time_formatter.rs @@ -130,6 +130,40 @@ fn boot_time() -> DateTime { } #[cfg(not(feature = "fixed-boot-time"))] +#[cfg(unix)] +#[cfg(not(target_os = "openbsd"))] fn boot_time() -> DateTime { - *BOOT_TIME.get_or_init(|| procfs::boot_time().unwrap().into()) + *BOOT_TIME.get_or_init(|| boot_time_from_utmpx().unwrap()) +} + +#[cfg(not(feature = "fixed-boot-time"))] +#[cfg(windows)] +fn boot_time() -> DateTime { + // TODO: get windows boot time + *BOOT_TIME.get_or_init(|| chrono::DateTime::from_timestamp(0, 0).unwrap().into()) +} + +#[cfg(not(feature = "fixed-boot-time"))] +#[cfg(target_os = "openbsd")] +fn boot_time() -> DateTime { + // TODO: get openbsd boot time + *BOOT_TIME.get_or_init(|| chrono::DateTime::from_timestamp(0, 0).unwrap().into()) +} + +#[cfg(not(feature = "fixed-boot-time"))] +#[cfg(unix)] +#[cfg(not(target_os = "openbsd"))] +fn boot_time_from_utmpx() -> Option> { + for record in uucore::utmpx::Utmpx::iter_all_records() { + if record.record_type() == uucore::utmpx::BOOT_TIME { + let t = record.login_time(); + return Some( + chrono::DateTime::from_timestamp(t.unix_timestamp(), t.nanosecond()) + .unwrap() + .with_timezone(&chrono::Local) + .into(), + ); + } + } + None } From a56b75f7be15672abcd0f9166392de74982cf9a2 Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Wed, 27 Nov 2024 00:53:44 +0700 Subject: [PATCH 14/20] tests/dmesg: handle added carriage return when fixture is checked out on Windows. --- tests/by-util/test_dmesg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/by-util/test_dmesg.rs b/tests/by-util/test_dmesg.rs index 51642e6..87c977e 100644 --- a/tests/by-util/test_dmesg.rs +++ b/tests/by-util/test_dmesg.rs @@ -70,7 +70,7 @@ fn test_kmsg_time_format(format: &str) { .arg(time_format_arg) .succeeds() .no_stderr() - .stdout_is_fixture(expected_output); + .stdout_is_templated_fixture(expected_output, &[("\r\n", "\n")]); } #[test] From c4944f4c857a08b0f5d2cf607967051551bcab81 Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Wed, 27 Nov 2024 15:59:03 +0700 Subject: [PATCH 15/20] dmesg: remove int to float conversion for adding sign. --- src/uu/dmesg/src/time_formatter.rs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/uu/dmesg/src/time_formatter.rs b/src/uu/dmesg/src/time_formatter.rs index 8c09907..d2d7287 100644 --- a/src/uu/dmesg/src/time_formatter.rs +++ b/src/uu/dmesg/src/time_formatter.rs @@ -73,12 +73,10 @@ impl ReltimeFormatter { fn delta(delta_us: i64) -> String { let seconds = i64::abs(delta_us / 1000000); let sub_seconds = i64::abs(delta_us % 1000000); - let sign = if delta_us >= 0 { 1.0 } else { -1.0 }; - format!( - "{:>+4.0}.{:0>6}", - sign * f64::from(seconds as i32), - sub_seconds - ) + let sign = if delta_us >= 0 { '+' } else { '-' }; + let mut res = format!("{}.{:0>6}", seconds, sub_seconds); + res.insert(0, sign); + format!("{:>11}", res) } } @@ -106,12 +104,11 @@ impl DeltaFormatter { fn delta(delta_us: i64) -> String { let seconds = i64::abs(delta_us / 1000000); let sub_seconds = i64::abs(delta_us % 1000000); - let sign = if delta_us >= 0 { 1.0 } else { -1.0 }; - format!( - "<{:>5.0}.{:0>6}>", - sign * f64::from(seconds as i32), - sub_seconds - ) + let mut res = format!("{}.{:0>6}", seconds, sub_seconds); + if delta_us < 0 { + res.insert(0, '-'); + } + format!("<{:>12}>", res) } } From dff0a8ea0b930ff989a7291902ec14c42b91ffb2 Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Wed, 27 Nov 2024 16:05:31 +0700 Subject: [PATCH 16/20] dmesg: change Record timestamp_us data type to i64. --- src/uu/dmesg/src/dmesg.rs | 9 +++------ src/uu/dmesg/src/json.rs | 6 +++--- src/uu/dmesg/src/time_formatter.rs | 10 +++++----- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/uu/dmesg/src/dmesg.rs b/src/uu/dmesg/src/dmesg.rs index 1343bbc..cf3f8d3 100644 --- a/src/uu/dmesg/src/dmesg.rs +++ b/src/uu/dmesg/src/dmesg.rs @@ -158,13 +158,10 @@ impl Dmesg<'_> { for record in records { match self.time_format { TimeFormat::Delta => { - print!("[{}] ", delta_formatter.format(record.timestamp_us as i64)) + print!("[{}] ", delta_formatter.format(record.timestamp_us)) } TimeFormat::Reltime => { - print!( - "[{}] ", - reltime_formatter.format(record.timestamp_us as i64) - ) + print!("[{}] ", reltime_formatter.format(record.timestamp_us)) } TimeFormat::Ctime => { print!("[{}] ", time_formatter::ctime(record.timestamp_us)) @@ -200,7 +197,7 @@ enum TimeFormat { struct Record { priority_facility: u32, _sequence: u64, - timestamp_us: u64, + timestamp_us: i64, message: String, } diff --git a/src/uu/dmesg/src/json.rs b/src/uu/dmesg/src/json.rs index 672d515..7549328 100644 --- a/src/uu/dmesg/src/json.rs +++ b/src/uu/dmesg/src/json.rs @@ -23,7 +23,7 @@ struct Dmesg<'a> { #[derive(serde::Serialize)] struct Record<'a> { pri: u32, - time: u64, + time: i64, msg: &'a str, } @@ -129,11 +129,11 @@ impl serde_json::ser::Formatter for DmesgFormatter { } } - fn write_u64(&mut self, writer: &mut W, value: u64) -> io::Result<()> + fn write_i64(&mut self, writer: &mut W, value: i64) -> io::Result<()> where W: ?Sized + io::Write, { - // The only u64 field in Dmesg is time, which requires a specific format + // The only i64 field in Dmesg is time, which requires a specific format let seconds = value / 1000000; let sub_seconds = value % 1000000; let repr = format!("{:>5}.{:0>6}", seconds, sub_seconds); diff --git a/src/uu/dmesg/src/time_formatter.rs b/src/uu/dmesg/src/time_formatter.rs index d2d7287..c7c0e0e 100644 --- a/src/uu/dmesg/src/time_formatter.rs +++ b/src/uu/dmesg/src/time_formatter.rs @@ -3,22 +3,22 @@ use chrono::{DateTime, FixedOffset, TimeDelta}; use chrono::{NaiveDate, NaiveTime}; use std::sync::OnceLock; -pub fn raw(timestamp_us: u64) -> String { +pub fn raw(timestamp_us: i64) -> String { let seconds = timestamp_us / 1000000; let sub_seconds = timestamp_us % 1000000; format!("{:>5}.{:0>6}", seconds, sub_seconds) } -pub fn ctime(timestamp_us: u64) -> String { +pub fn ctime(timestamp_us: i64) -> String { let date_time = boot_time() - .checked_add_signed(TimeDelta::microseconds(timestamp_us as i64)) + .checked_add_signed(TimeDelta::microseconds(timestamp_us)) .unwrap(); date_time.format("%a %b %d %H:%M:%S %Y").to_string() } -pub fn iso(timestamp_us: u64) -> String { +pub fn iso(timestamp_us: i64) -> String { let date_time = boot_time() - .checked_add_signed(TimeDelta::microseconds(timestamp_us as i64)) + .checked_add_signed(TimeDelta::microseconds(timestamp_us)) .unwrap(); date_time.format("%Y-%m-%dT%H:%M:%S,%6f%:z").to_string() } From 887e65d0ab3727e4cf8625b784010153a509e873 Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Fri, 29 Nov 2024 23:28:56 +0700 Subject: [PATCH 17/20] tests/dmesg: use stderr_only. Co-authored-by: Daniel Hofstetter --- tests/by-util/test_dmesg.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/by-util/test_dmesg.rs b/tests/by-util/test_dmesg.rs index 87c977e..b811584 100644 --- a/tests/by-util/test_dmesg.rs +++ b/tests/by-util/test_dmesg.rs @@ -79,6 +79,5 @@ fn test_invalid_time_format() { .arg("--time-format=definitely-invalid") .fails() .code_is(1) - .no_stdout() - .stderr_is("dmesg: unknown time format: definitely-invalid\n"); + .stderr_only("dmesg: unknown time format: definitely-invalid\n"); } From c3c80c4bcdcf1945086c50bfa0eb7f211a83eae4 Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Sat, 30 Nov 2024 22:03:03 +0700 Subject: [PATCH 18/20] dmesg: refactor to avoid duplicate code. Co-authored-by: Daniel Hofstetter --- src/uu/dmesg/src/dmesg.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/uu/dmesg/src/dmesg.rs b/src/uu/dmesg/src/dmesg.rs index cf3f8d3..75bfe8f 100644 --- a/src/uu/dmesg/src/dmesg.rs +++ b/src/uu/dmesg/src/dmesg.rs @@ -28,20 +28,20 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { dmesg.output_format = OutputFormat::Json; } if let Some(time_format) = matches.get_one::(options::TIME_FORMAT) { - match &time_format[..] { - "delta" => dmesg.time_format = TimeFormat::Delta, - "reltime" => dmesg.time_format = TimeFormat::Reltime, - "ctime" => dmesg.time_format = TimeFormat::Ctime, - "notime" => dmesg.time_format = TimeFormat::Notime, - "iso" => dmesg.time_format = TimeFormat::Iso, - "raw" => dmesg.time_format = TimeFormat::Raw, + dmesg.time_format = match &time_format[..] { + "delta" => TimeFormat::Delta, + "reltime" => TimeFormat::Reltime, + "ctime" => TimeFormat::Ctime, + "notime" => TimeFormat::Notime, + "iso" => TimeFormat::Iso, + "raw" => TimeFormat::Raw, _ => { return Err(USimpleError::new( 1, format!("unknown time format: {time_format}"), )) } - } + }; } dmesg.parse()?.print(); Ok(()) From f3de668f7f5a1adb5fccdf9e3e59af382b362ade Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Sat, 30 Nov 2024 22:07:32 +0700 Subject: [PATCH 19/20] dmesg: add file header. --- src/uu/dmesg/src/time_formatter.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/uu/dmesg/src/time_formatter.rs b/src/uu/dmesg/src/time_formatter.rs index c7c0e0e..ba6aabe 100644 --- a/src/uu/dmesg/src/time_formatter.rs +++ b/src/uu/dmesg/src/time_formatter.rs @@ -1,3 +1,8 @@ +// This file is part of the uutils util-linux package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + use chrono::{DateTime, FixedOffset, TimeDelta}; #[cfg(feature = "fixed-boot-time")] use chrono::{NaiveDate, NaiveTime}; From e965074bafc56e75033490e210bed58309429827 Mon Sep 17 00:00:00 2001 From: Fuad Ismail Date: Sat, 30 Nov 2024 22:15:38 +0700 Subject: [PATCH 20/20] dmesg: avoid using insert for better readability. --- src/uu/dmesg/src/time_formatter.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/uu/dmesg/src/time_formatter.rs b/src/uu/dmesg/src/time_formatter.rs index ba6aabe..198431f 100644 --- a/src/uu/dmesg/src/time_formatter.rs +++ b/src/uu/dmesg/src/time_formatter.rs @@ -79,8 +79,7 @@ impl ReltimeFormatter { let seconds = i64::abs(delta_us / 1000000); let sub_seconds = i64::abs(delta_us % 1000000); let sign = if delta_us >= 0 { '+' } else { '-' }; - let mut res = format!("{}.{:0>6}", seconds, sub_seconds); - res.insert(0, sign); + let res = format!("{}{}.{:0>6}", sign, seconds, sub_seconds); format!("{:>11}", res) } }