Skip to content

Commit

Permalink
Writes kernel log to file (#1216)
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon authored Dec 30, 2024
1 parent 9bb2080 commit 9334072
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 19 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions gui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ name = "obliteration"
path = "src/main.rs"

[dependencies]
anstyle-parse = "0.2.6"
async-net = "2.0.0"
bitfield-struct = "0.9.2"
bytes = "1.9.0"
Expand Down
13 changes: 11 additions & 2 deletions gui/src/data/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ mod part;
mod prof;

/// Manages all files and directories that stored in the data root.
///
/// This does not manage file content. Its job is to organize filesystem hierarchy.
pub struct DataMgr {
part: Part,
prof: Prof,
logs: PathBuf,
}

impl DataMgr {
Expand All @@ -20,6 +23,7 @@ impl DataMgr {
let root: PathBuf = root.into();
let part = root.join("part");
let prof = root.join("prof");
let logs = root.join("kernel.txt");

// Create top-level directories.
Self::create_dir(&part)?;
Expand All @@ -28,17 +32,22 @@ impl DataMgr {
Ok(Self {
part: Part::new(part),
prof: Prof::new(prof),
logs,
})
}

pub fn part(&self) -> &Part {
pub fn partitions(&self) -> &Part {
&self.part
}

pub fn prof(&self) -> &Prof {
pub fn profiles(&self) -> &Prof {
&self.prof
}

pub fn logs(&self) -> &Path {
&self.logs
}

fn create_dir(path: &Path) -> Result<(), DataError> {
if let Err(e) = std::fs::create_dir(path) {
if e.kind() != ErrorKind::AlreadyExists {
Expand Down
33 changes: 33 additions & 0 deletions gui/src/log/file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use anstyle_parse::Perform;
use std::fs::File;
use std::io::{BufWriter, Write};

/// Implementation of [`Perform`] for [`File`].
pub struct LogFile(BufWriter<File>);

impl LogFile {
pub fn new(file: File) -> Self {
Self(BufWriter::new(file))
}
}

impl Perform for LogFile {
fn print(&mut self, c: char) {
self.0
.write_all(c.encode_utf8(&mut [0; 4]).as_bytes())
.unwrap();
}

fn execute(&mut self, byte: u8) {
match byte {
b'\n' => {
#[cfg(unix)]
self.0.write_all(b"\n").unwrap();
#[cfg(windows)]
self.0.write_all(b"\r\n").unwrap();
self.0.flush().unwrap();
}
_ => (),
}
}
}
40 changes: 40 additions & 0 deletions gui/src/log/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use self::file::LogFile;
use anstyle_parse::Parser;
use obconf::ConsoleType;
use std::fs::File;
use std::io::{stderr, stdout, Write};
use std::path::Path;

mod file;

/// Provides method to write kernel logs.
pub struct LogWriter {
file: LogFile,
parser: Parser,
}

impl LogWriter {
pub fn new(file: &Path) -> Result<Self, std::io::Error> {
let file = File::create(file)?;

Ok(Self {
file: LogFile::new(file),
parser: Parser::default(),
})
}

pub fn write(&mut self, ty: ConsoleType, msg: String) {
// Write console.
let msg = msg.as_bytes();

match ty {
ConsoleType::Info => stdout().write_all(msg).unwrap(),
ConsoleType::Warn | ConsoleType::Error => stderr().write_all(msg).unwrap(),
}

// Write file.
for &b in msg {
self.parser.advance(&mut self.file, b);
}
}
}
25 changes: 12 additions & 13 deletions gui/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use self::data::{DataError, DataMgr};
use self::graphics::{EngineBuilder, GraphicsError, PhysicalDevice};
use self::log::LogWriter;
use self::profile::{DisplayResolution, Profile};
use self::setup::{run_setup, SetupError};
use self::ui::{
Expand All @@ -13,11 +14,9 @@ use async_net::{TcpListener, TcpStream};
use clap::{Parser, ValueEnum};
use erdp::ErrorDisplay;
use futures::{select_biased, AsyncReadExt, FutureExt};
use obconf::ConsoleType;
use slint::{ComponentHandle, ModelRc, SharedString, ToSharedString, VecModel, WindowHandle};
use std::cell::Cell;
use std::future::Future;
use std::io::{stderr, stdout, Write};
use std::net::SocketAddrV4;
use std::path::PathBuf;
use std::pin::pin;
Expand All @@ -34,6 +33,7 @@ mod dialogs;
mod gdb;
mod graphics;
mod hv;
mod log;
mod panic;
mod profile;
mod rt;
Expand Down Expand Up @@ -178,7 +178,7 @@ async fn run(args: ProgramArgs, exe: PathBuf) -> Result<(), ProgramError> {
// Load profiles.
let mut profiles = Vec::new();

for l in data.prof().list().map_err(ProgramError::ListProfile)? {
for l in data.profiles().list().map_err(ProgramError::ListProfile)? {
let l = l.map_err(ProgramError::ListProfile)?;
let p = Profile::load(&l).map_err(ProgramError::LoadProfile)?;

Expand All @@ -189,7 +189,7 @@ async fn run(args: ProgramArgs, exe: PathBuf) -> Result<(), ProgramError> {
if profiles.is_empty() {
// Create directory.
let p = Profile::default();
let l = data.prof().data(p.id());
let l = data.profiles().data(p.id());

if let Err(e) = std::fs::create_dir(&l) {
return Err(ProgramError::CreateDirectory(l, e));
Expand Down Expand Up @@ -241,6 +241,9 @@ async fn run(args: ProgramArgs, exe: PathBuf) -> Result<(), ProgramError> {
.with_title("Obliteration");

// Prepare to launch VMM.
let logs = data.logs();
let mut logs =
LogWriter::new(logs).map_err(|e| ProgramError::CreateKernelLog(logs.into(), e))?;
let shutdown = Arc::default();
let graphics = graphics
.build(&profile, attrs, &shutdown)
Expand Down Expand Up @@ -279,14 +282,7 @@ async fn run(args: ProgramArgs, exe: PathBuf) -> Result<(), ProgramError> {
if let Some(vmm) = vmm {
match vmm {
VmmEvent::Exit(_, _) => todo!(),
VmmEvent::Log(t, m) => {
let m = m.as_bytes();

match t {
ConsoleType::Info => stdout().write_all(m).unwrap(),
ConsoleType::Warn | ConsoleType::Error => stderr().write_all(m).unwrap(),
}
}
VmmEvent::Log(t, m) => logs.write(t, m),
}
}

Expand Down Expand Up @@ -332,7 +328,7 @@ async fn run_launcher(
let win = win.unwrap();
let row = win.get_selected_profile();
let pro = profiles.update(row, &win);
let loc = data.prof().data(pro.id());
let loc = data.profiles().data(pro.id());

// TODO: Display error instead of panic.
pro.save(loc).unwrap();
Expand Down Expand Up @@ -527,6 +523,9 @@ enum ProgramError {
#[error("couldn't show main window")]
ShowMainWindow(#[source] slint::PlatformError),

#[error("couldn't create {0}")]
CreateKernelLog(PathBuf, #[source] std::io::Error),

#[error("couldn't build graphics engine")]
BuildGraphicsEngine(#[source] GraphicsError),

Expand Down
8 changes: 4 additions & 4 deletions gui/src/setup/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub async fn run_setup() -> Result<Option<DataMgr>, SetupError> {
// Check if root partition exists.
let mgr = DataMgr::new(p).map_err(|e| SetupError::DataManager(p.to_owned(), e))?;

if mgr.part().meta("md0").is_file() {
if mgr.partitions().meta("md0").is_file() {
return Ok(Some(mgr));
}
}
Expand Down Expand Up @@ -178,7 +178,7 @@ fn set_data_root(win: SetupWizard) {
return;
}

win.invoke_set_data_root_ok(mgr.part().meta("md0").is_file());
win.invoke_set_data_root_ok(mgr.partitions().meta("md0").is_file());
}

async fn browse_firmware(win: SetupWizard) {
Expand Down Expand Up @@ -352,7 +352,7 @@ fn extract_partition(
};

// Create database file for file/directory metadata.
let mp = dmgr.part().meta(dev);
let mp = dmgr.partitions().meta(dev);
let meta = match File::create_new(&mp) {
Ok(v) => v,
Err(e) => return Err(PartitionError::CreateFile(mp, e)),
Expand Down Expand Up @@ -383,7 +383,7 @@ fn extract_partition(
drop(tab);

// Extract items.
let root = dmgr.part().data(dev);
let root = dmgr.partitions().data(dev);

loop {
// Get next item.
Expand Down

0 comments on commit 9334072

Please sign in to comment.