Merge pull request #177 from kreijack/correct-dmesg
dmesg: fix a non working support of /dev/kmesg
This commit is contained in:
commit
f832e8b883
@ -9,15 +9,23 @@ use regex::Regex;
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
fs::File,
|
fs::File,
|
||||||
|
fs::OpenOptions,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
io::{BufRead, BufReader},
|
io::{BufRead, BufReader, ErrorKind},
|
||||||
sync::OnceLock,
|
sync::OnceLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
use std::{os::fd::AsRawFd, os::unix::fs::OpenOptionsExt};
|
||||||
|
|
||||||
use uucore::{
|
use uucore::{
|
||||||
error::{FromIo, UError, UResult, USimpleError},
|
error::{FromIo, UError, UIoError, UResult, USimpleError},
|
||||||
format_usage, help_about, help_usage,
|
format_usage, help_about, help_usage,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
use uucore::libc;
|
||||||
|
|
||||||
mod json;
|
mod json;
|
||||||
mod time_formatter;
|
mod time_formatter;
|
||||||
|
|
||||||
@ -28,9 +36,6 @@ const USAGE: &str = help_usage!("dmesg.md");
|
|||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let mut dmesg = Dmesg::new();
|
let mut dmesg = Dmesg::new();
|
||||||
let matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?;
|
let matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?;
|
||||||
if let Some(kmsg_file) = matches.get_one::<String>(options::KMSG_FILE) {
|
|
||||||
dmesg.kmsg_file = kmsg_file;
|
|
||||||
}
|
|
||||||
if matches.get_flag(options::JSON) {
|
if matches.get_flag(options::JSON) {
|
||||||
dmesg.output_format = OutputFormat::Json;
|
dmesg.output_format = OutputFormat::Json;
|
||||||
}
|
}
|
||||||
@ -112,6 +117,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||||||
if let Some(until) = matches.get_one::<String>(options::UNTIL) {
|
if let Some(until) = matches.get_one::<String>(options::UNTIL) {
|
||||||
dmesg.until_filter = Some(time_formatter::parse_datetime(until)?);
|
dmesg.until_filter = Some(time_formatter::parse_datetime(until)?);
|
||||||
}
|
}
|
||||||
|
if let Some(kmsg_file) = matches.get_one::<String>(options::KMSG_FILE) {
|
||||||
|
dmesg.kmsg_file = kmsg_file;
|
||||||
|
dmesg.kmsg_record_separator = 0;
|
||||||
|
} else if cfg!(target_os = "windows") {
|
||||||
|
return Err(USimpleError::new(1, "Windows requires the use of '-K'"));
|
||||||
|
}
|
||||||
dmesg.print()?;
|
dmesg.print()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -184,6 +195,7 @@ mod options {
|
|||||||
|
|
||||||
struct Dmesg<'a> {
|
struct Dmesg<'a> {
|
||||||
kmsg_file: &'a str,
|
kmsg_file: &'a str,
|
||||||
|
kmsg_record_separator: u8,
|
||||||
output_format: OutputFormat,
|
output_format: OutputFormat,
|
||||||
time_format: TimeFormat,
|
time_format: TimeFormat,
|
||||||
facility_filters: Option<HashSet<Facility>>,
|
facility_filters: Option<HashSet<Facility>>,
|
||||||
@ -196,6 +208,7 @@ impl Dmesg<'_> {
|
|||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Dmesg {
|
Dmesg {
|
||||||
kmsg_file: "/dev/kmsg",
|
kmsg_file: "/dev/kmsg",
|
||||||
|
kmsg_record_separator: b'\n',
|
||||||
output_format: OutputFormat::Normal,
|
output_format: OutputFormat::Normal,
|
||||||
time_format: TimeFormat::Raw,
|
time_format: TimeFormat::Raw,
|
||||||
facility_filters: None,
|
facility_filters: None,
|
||||||
@ -256,10 +269,27 @@ impl Dmesg<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn try_iter(&self) -> UResult<RecordIterator> {
|
fn try_iter(&self) -> UResult<RecordIterator> {
|
||||||
let file = File::open(self.kmsg_file)
|
let mut open_option = OpenOptions::new();
|
||||||
|
open_option.read(true);
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
open_option.custom_flags(libc::O_NONBLOCK);
|
||||||
|
|
||||||
|
let file = open_option
|
||||||
|
.open(self.kmsg_file)
|
||||||
.map_err_context(|| format!("cannot open {}", self.kmsg_file))?;
|
.map_err_context(|| format!("cannot open {}", self.kmsg_file))?;
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
{
|
||||||
|
let fd = file.as_raw_fd();
|
||||||
|
unsafe { libc::lseek(fd, 0, libc::SEEK_DATA) };
|
||||||
|
}
|
||||||
|
|
||||||
let file_reader = BufReader::new(file);
|
let file_reader = BufReader::new(file);
|
||||||
Ok(RecordIterator { file_reader })
|
Ok(RecordIterator {
|
||||||
|
file_reader,
|
||||||
|
kmsg_record_separator: self.kmsg_record_separator,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_record_in_set<T>(
|
fn is_record_in_set<T>(
|
||||||
@ -359,6 +389,7 @@ enum Level {
|
|||||||
|
|
||||||
struct RecordIterator {
|
struct RecordIterator {
|
||||||
file_reader: BufReader<File>,
|
file_reader: BufReader<File>,
|
||||||
|
kmsg_record_separator: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for RecordIterator {
|
impl Iterator for RecordIterator {
|
||||||
@ -379,10 +410,20 @@ impl Iterator for RecordIterator {
|
|||||||
impl RecordIterator {
|
impl RecordIterator {
|
||||||
fn read_record_line(&mut self) -> UResult<Option<String>> {
|
fn read_record_line(&mut self) -> UResult<Option<String>> {
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
let num_bytes = self.file_reader.read_until(0, &mut buf)?;
|
match self
|
||||||
match num_bytes {
|
.file_reader
|
||||||
0 => Ok(None),
|
.read_until(self.kmsg_record_separator, &mut buf)
|
||||||
_ => Ok(Some(String::from_utf8_lossy(&buf).to_string())),
|
{
|
||||||
|
/*
|
||||||
|
* - a read(2) from /dev/kmsg returns WouldBlock if there aren't
|
||||||
|
* any new record
|
||||||
|
* - a read(2) from a file returns 0 if the we reached the end
|
||||||
|
* In these cases return Ok(None)
|
||||||
|
*/
|
||||||
|
Ok(0) => Ok(None),
|
||||||
|
Ok(_) => Ok(Some(String::from_utf8_lossy(&buf).to_string())),
|
||||||
|
Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(None),
|
||||||
|
Err(e) => Err(Box::new(UIoError::from(e))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user