logd: Add api to add new sink sources at runtime
This will allow logd to be started before fbbootlogd.
This commit is contained in:
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user