diff --git a/Cargo.lock b/Cargo.lock index f007c41b2c..e16f7f2693 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -486,7 +486,7 @@ version = "0.1.0" dependencies = [ "libredox 0.1.3", "redox-daemon", - "redox-scheme 0.2.4", + "redox-scheme 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.5.11", ] diff --git a/logd/Cargo.toml b/logd/Cargo.toml index ab9f15e31a..7b60a42f96 100644 --- a/logd/Cargo.toml +++ b/logd/Cargo.toml @@ -8,4 +8,4 @@ edition = "2021" redox_syscall = "0.5" redox-daemon = "0.1.2" libredox = "0.1.3" -redox-scheme = "0.2.1" +redox-scheme = "0.5" diff --git a/logd/src/main.rs b/logd/src/main.rs index 11b04c8d41..5b6e23243c 100644 --- a/logd/src/main.rs +++ b/logd/src/main.rs @@ -1,4 +1,4 @@ -use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; +use redox_scheme::{RequestKind, SignalBehavior, Socket}; use std::env; use std::fs::OpenOptions; use std::process; @@ -17,9 +17,7 @@ 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"); + let socket = Socket::create("log").expect("logd: failed to create log scheme"); eprintln!("logd: ready for logging on log:"); @@ -31,13 +29,16 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .next_request(SignalBehavior::Restart) .expect("logd: failed to read events from log scheme") { - scheme.current_pid = request.context_id(); - - let RequestKind::Call(request) = request.kind() else { - continue; + let request = match request.kind() { + RequestKind::Call(call) => call, + RequestKind::OnClose { id } => { + scheme.on_close(id); + continue; + } + _ => continue, }; - let response = request.handle_scheme_mut(&mut scheme); + let response = request.handle_sync(&mut scheme); socket .write_responses(&[response], SignalBehavior::Restart) .expect("logd: failed to write responses to log scheme"); diff --git a/logd/src/scheme.rs b/logd/src/scheme.rs index 921fe08c5f..d0bd430b4c 100644 --- a/logd/src/scheme.rs +++ b/logd/src/scheme.rs @@ -1,33 +1,56 @@ 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::SchemeMut; +use redox_scheme::scheme::SchemeSync; +use redox_scheme::{CallerCtx, OpenResult}; use syscall::error::*; +use syscall::schemev2::NewFdFlags; -pub struct LogHandle { - context: Box, - bufs: BTreeMap>, +pub enum LogHandle { + Log { + context: Box, + bufs: BTreeMap>, + }, + AddSink, } pub struct LogScheme { next_id: usize, - output_tx: Sender>, + output_tx: Sender, handles: BTreeMap, - pub current_pid: usize, +} + +enum OutputCmd { + Log(Vec), + AddSink(PathBuf), } impl LogScheme { pub fn new(mut files: Vec) -> Self { - let (output_tx, output_rx) = mpsc::channel::>(); + let (output_tx, output_rx) = mpsc::channel::(); 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) => { + // FIXME backfill log messages that were sent to other log sinks + match OpenOptions::new().write(true).open(&sink_path) { + Ok(file) => files.push(file), + Err(err) => { + eprintln!("logd: failed to open {:?}: {:?}", sink_path, err) + } + } + } } } }); @@ -36,28 +59,41 @@ impl LogScheme { next_id: 0, output_tx, handles: BTreeMap::new(), - current_pid: 0, } } } -impl SchemeMut for LogScheme { - fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> Result { +impl SchemeSync for LogScheme { + fn open(&mut self, path: &str, _flags: usize, _ctx: &CallerCtx) -> Result { 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(id) + Ok(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::empty(), + }) } - fn read(&mut self, id: usize, _buf: &mut [u8], _offset: u64, _flags: u32) -> Result { + fn read( + &mut self, + id: usize, + _buf: &mut [u8], + _offset: u64, + _flags: u32, + _ctx: &CallerCtx, + ) -> Result { let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; // TODO @@ -65,27 +101,46 @@ impl SchemeMut for LogScheme { Ok(0) } - fn write(&mut self, id: usize, buf: &[u8], _offset: u64, _flags: u32) -> Result { - let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + fn write( + &mut self, + id: usize, + buf: &[u8], + _offset: u64, + _flags: u32, + ctx: &CallerCtx, + ) -> Result { + 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(self.current_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; @@ -94,16 +149,16 @@ impl SchemeMut for LogScheme { Ok(i) } - fn fcntl(&mut self, id: usize, _cmd: usize, _arg: usize) -> Result { + fn fcntl(&mut self, id: usize, _cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result { let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; Ok(0) } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { 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() { @@ -111,10 +166,13 @@ impl SchemeMut 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; } @@ -122,19 +180,17 @@ impl SchemeMut for LogScheme { Ok(i) } - fn fsync(&mut self, id: usize) -> Result { + fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> { let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; //TODO: flush remaining data? - Ok(0) - } - - fn close(&mut self, id: usize) -> Result { - self.handles.remove(&id).ok_or(Error::new(EBADF))?; - - //TODO: flush remaining data? - - Ok(0) + Ok(()) + } +} + +impl LogScheme { + pub fn on_close(&mut self, id: usize) { + self.handles.remove(&id); } }