logd: Add api to add new sink sources at runtime

This will allow logd to be started before fbbootlogd.
This commit is contained in:
bjorn3
2025-04-06 19:33:49 +02:00
parent d20dd30ccf
commit 034d76ffd5
2 changed files with 69 additions and 28 deletions
-2
View File
@@ -19,8 +19,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
let socket = Socket::create("log").expect("logd: failed to create log scheme");
libredox::call::setrens(0, 0).expect("logd: failed to enter null namespace");
eprintln!("logd: ready for logging on log:");
daemon.ready().expect("logd: failed to notify parent");
+69 -26
View File
@@ -1,7 +1,8 @@
use std::collections::BTreeMap;
use std::fs::File;
use std::fs::{File, OpenOptions};
use std::io::Write;
use std::mem;
use std::path::PathBuf;
use std::sync::mpsc::{self, Sender};
use redox_scheme::scheme::SchemeSync;
@@ -9,26 +10,46 @@ use redox_scheme::{CallerCtx, OpenResult};
use syscall::error::*;
use syscall::schemev2::NewFdFlags;
pub struct LogHandle {
context: Box<str>,
bufs: BTreeMap<usize, Vec<u8>>,
pub enum LogHandle {
Log {
context: Box<str>,
bufs: BTreeMap<usize, Vec<u8>>,
},
AddSink,
}
pub struct LogScheme {
next_id: usize,
output_tx: Sender<Vec<u8>>,
output_tx: Sender<OutputCmd>,
handles: BTreeMap<usize, LogHandle>,
}
enum OutputCmd {
Log(Vec<u8>),
AddSink(PathBuf),
}
impl LogScheme {
pub fn new(mut files: Vec<File>) -> Self {
let (output_tx, output_rx) = mpsc::channel::<Vec<u8>>();
let (output_tx, output_rx) = mpsc::channel::<OutputCmd>();
std::thread::spawn(move || {
for line in output_rx {
for file in &mut files {
let _ = file.write(&line);
let _ = file.flush();
for cmd in output_rx {
match cmd {
OutputCmd::Log(line) => {
for file in &mut files {
let _ = file.write(&line);
let _ = file.flush();
}
}
OutputCmd::AddSink(sink_path) => {
match OpenOptions::new().write(true).open(&sink_path) {
Ok(file) => files.push(file),
Err(err) => {
eprintln!("logd: failed to open {:?}: {:?}", sink_path, err)
}
}
}
}
}
});
@@ -46,13 +67,17 @@ impl SchemeSync for LogScheme {
let id = self.next_id;
self.next_id += 1;
self.handles.insert(
id,
LogHandle {
context: path.to_string().into_boxed_str(),
bufs: BTreeMap::new(),
},
);
if path == "add_sink" {
self.handles.insert(id, LogHandle::AddSink);
} else {
self.handles.insert(
id,
LogHandle::Log {
context: path.to_string().into_boxed_str(),
bufs: BTreeMap::new(),
},
);
}
Ok(OpenResult::ThisScheme {
number: id,
@@ -83,23 +108,38 @@ impl SchemeSync for LogScheme {
_flags: u32,
ctx: &CallerCtx,
) -> Result<usize> {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let (context, bufs) = match self.handles.get_mut(&id).ok_or(Error::new(EBADF))? {
LogHandle::Log { context, bufs } => (context, bufs),
LogHandle::AddSink => {
// FIXME maybe check if root
let handle_buf = handle.bufs.entry(ctx.pid).or_insert_with(|| Vec::new());
let sink_path = PathBuf::from(
String::from_utf8(buf.to_owned()).map_err(|_| Error::new(EINVAL))?,
);
self.output_tx.send(OutputCmd::AddSink(sink_path)).unwrap();
return Ok(buf.len());
}
};
let handle_buf = bufs.entry(ctx.pid).or_insert_with(|| Vec::new());
let mut i = 0;
while i < buf.len() {
let b = buf[i];
if handle_buf.is_empty() && !handle.context.is_empty() {
handle_buf.extend_from_slice(handle.context.as_bytes());
if handle_buf.is_empty() && !context.is_empty() {
handle_buf.extend_from_slice(context.as_bytes());
handle_buf.extend_from_slice(b": ");
}
handle_buf.push(b);
if b == b'\n' {
self.output_tx.send(mem::take(handle_buf)).unwrap();
self.output_tx
.send(OutputCmd::Log(mem::take(handle_buf)))
.unwrap();
}
i += 1;
@@ -117,7 +157,7 @@ impl SchemeSync for LogScheme {
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let scheme_path = b"log:";
let scheme_path = b"/scheme/log/";
let mut i = 0;
while i < buf.len() && i < scheme_path.len() {
@@ -125,10 +165,13 @@ impl SchemeSync for LogScheme {
i += 1;
}
let path_bytes = match handle {
LogHandle::Log { context, .. } => context.as_bytes(),
LogHandle::AddSink => b"add_sink",
};
let mut j = 0;
let context_bytes = handle.context.as_bytes();
while i < buf.len() && j < context_bytes.len() {
buf[i] = context_bytes[j];
while i < buf.len() && j < path_bytes.len() {
buf[i] = path_bytes[j];
i += 1;
j += 1;
}