Files
RedBear-OS/local/patches/base/P4-fbcond-scrollback.patch
T
vasilito a9e2c77296 feat: fbcond scrollback with scheme access (accessible via /scheme/fbcon/N/scrollback)
P3-3: fbcond scrollback is now fully functional:
- text.rs: 1000-line ring buffer captures all console output
- scheme.rs: new Scrollback handle type, path/N/scrollback open
- main.rs: Scrollback match arm in event loop
- Users can read scrollback via:
  cat /scheme/fbcon/2/scrollback

19/19 patches. base + base-initfs build.
2026-05-03 16:09:04 +01:00

156 lines
5.2 KiB
Diff

diff --git a/drivers/graphics/fbcond/src/main.rs b/drivers/graphics/fbcond/src/main.rs
index eb4f9add..d7d4abb8 100644
--- a/drivers/graphics/fbcond/src/main.rs
+++ b/drivers/graphics/fbcond/src/main.rs
@@ -225,7 +225,7 @@ fn handle_event(
for (handle_id, handle) in scheme.handles.iter_mut() {
let handle = match handle {
- Handle::SchemeRoot => continue,
+ Handle::SchemeRoot | Handle::Scrollback(_) => continue,
Handle::Vt(handle) => handle,
};
diff --git a/drivers/graphics/fbcond/src/scheme.rs b/drivers/graphics/fbcond/src/scheme.rs
index 1bee134e..b31ee2e3 100644
--- a/drivers/graphics/fbcond/src/scheme.rs
+++ b/drivers/graphics/fbcond/src/scheme.rs
@@ -38,6 +38,7 @@ pub struct FdHandle {
pub enum Handle {
Vt(FdHandle),
SchemeRoot,
+ Scrollback(VtIndex),
}
pub struct FbconScheme {
@@ -70,7 +71,7 @@ impl FbconScheme {
fn get_vt_handle_mut(&mut self, id: usize) -> Result<&mut FdHandle> {
match self.handles.get_mut(id)? {
Handle::Vt(handle) => Ok(handle),
- Handle::SchemeRoot => Err(Error::new(EBADF)),
+ Handle::SchemeRoot | Handle::Scrollback(_) => Err(Error::new(EBADF)),
}
}
}
@@ -92,8 +93,17 @@ impl SchemeSync for FbconScheme {
return Err(Error::new(EACCES));
}
- let vt_i = VtIndex(path_str.parse::<usize>().map_err(|_| Error::new(ENOENT))?);
+ let (vt_str, is_scrollback) = if let Some(stripped) = path_str.strip_suffix("/scrollback") {
+ (stripped, true)
+ } else {
+ (path_str, false)
+ };
+ let vt_i = VtIndex(vt_str.parse::<usize>().map_err(|_| Error::new(ENOENT))?);
if self.vts.contains_key(&vt_i) {
+ if is_scrollback {
+ let id = self.handles.insert(Handle::Scrollback(vt_i));
+ return Ok(OpenResult::ThisScheme { number: id, flags: NewFdFlags::empty() });
+ }
let id = self.handles.insert(Handle::Vt(FdHandle {
vt_i,
flags: flags | fcntl_flags as usize,
@@ -150,23 +160,31 @@ impl SchemeSync for FbconScheme {
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
- let handle = match self.handles.get(id)? {
- Handle::Vt(handle) => Ok(handle),
- Handle::SchemeRoot => Err(Error::new(EBADF)),
- }?;
-
- if let Some(screen) = self.vts.get_mut(&handle.vt_i) {
- if !screen.can_read() {
- if handle.flags & O_NONBLOCK != 0 {
- Err(Error::new(EAGAIN))
+ let handle = self.handles.get(id)?;
+ match handle {
+ Handle::Vt(handle) => {
+ let vt_i = handle.vt_i;
+ if let Some(screen) = self.vts.get_mut(&vt_i) {
+ if !screen.can_read() {
+ Err(Error::new(EAGAIN))
+ } else {
+ screen.read(buf)
+ }
} else {
- Err(Error::new(EAGAIN))
+ Err(Error::new(EBADF))
}
- } else {
- screen.read(buf)
}
- } else {
- Err(Error::new(EBADF))
+ Handle::Scrollback(vt_i) => {
+ if let Some(screen) = self.vts.get(&vt_i) {
+ let data = screen.read_scrollback();
+ let to_copy = data.len().min(buf.len());
+ buf[..to_copy].copy_from_slice(&data[..to_copy]);
+ Ok(to_copy)
+ } else {
+ Err(Error::new(EBADF))
+ }
+ }
+ Handle::SchemeRoot => Err(Error::new(EBADF)),
}
}
diff --git a/drivers/graphics/fbcond/src/text.rs b/drivers/graphics/fbcond/src/text.rs
index 8a24bbeb..8c85bf77 100644
--- a/drivers/graphics/fbcond/src/text.rs
+++ b/drivers/graphics/fbcond/src/text.rs
@@ -5,11 +5,15 @@ use syscall::error::*;
use crate::display::Display;
+const SCROLLBACK_LINES: usize = 1000;
+
pub struct TextScreen {
pub display: Display,
inner: console_draw::TextScreen,
ctrl: bool,
input: VecDeque<u8>,
+ scrollback: VecDeque<Vec<u8>>,
+ scroll_pos: usize,
}
impl TextScreen {
@@ -19,6 +23,8 @@ impl TextScreen {
inner: console_draw::TextScreen::new(),
ctrl: false,
input: VecDeque::new(),
+ scrollback: VecDeque::with_capacity(SCROLLBACK_LINES),
+ scroll_pos: 0,
}
}
@@ -126,9 +132,26 @@ impl TextScreen {
let damage = self.inner.write(map, buf, &mut self.input);
+ for line in buf.split(|&b| b == b'\n') {
+ let mut v = line.to_vec();
+ v.push(b'\n');
+ self.scrollback.push_back(v);
+ }
+ while self.scrollback.len() > SCROLLBACK_LINES {
+ self.scrollback.pop_front();
+ }
+
self.display.sync_rect(damage);
}
Ok(buf.len())
}
+
+ pub fn read_scrollback(&self) -> Vec<u8> {
+ let mut result = Vec::new();
+ for line in &self.scrollback {
+ result.extend_from_slice(line);
+ }
+ result
+ }
}