68 lines
2.8 KiB
Zig
68 lines
2.8 KiB
Zig
//! system/services/log-flush — a one-shot that copies the kernel's in-memory
|
|
//! diagnostic log to a file on the mounted USB FAT volume, so the boot log
|
|
//! survives to be read on another machine. On a headless or real board there is
|
|
//! no host capturing serial, so without this the log is lost at power-off; this
|
|
//! is the on-disk equivalent of QEMU's `-serial file:`.
|
|
//!
|
|
//! It reads the whole kernel log back through `klog_read` (the RAM sink in
|
|
//! system/kernel/log.zig) and writes it to /mnt/usb/DANOS.LOG. The name is 8.3
|
|
//! (FAT short-name rule: base <= 8, extension <= 3) and lives at the mount root
|
|
//! (there is no mkdir on the FAT path yet). init spawns this once the boot
|
|
//! services are up; init itself repeats the flush at shutdown for a fuller log.
|
|
//!
|
|
//! If no USB volume is mounted — no stick, or the initial-ramdisk sweep that
|
|
//! spawns every bundled binary bare with no VFS — it waits briefly, then exits
|
|
//! silently, deranging no other test's output.
|
|
|
|
const std = @import("std");
|
|
const runtime = @import("runtime");
|
|
const fs = runtime.fs;
|
|
|
|
const log_path = "/mnt/usb/DANOS.LOG";
|
|
|
|
/// Copy the whole kernel log to the open file, looping klog_read -> write until
|
|
/// the log is exhausted. Returns the number of bytes written.
|
|
fn drainKernelLog(file: *fs.File) usize {
|
|
var chunk: [4096]u8 = undefined;
|
|
var offset: usize = 0;
|
|
while (true) {
|
|
const got = runtime.system.klogRead(offset, &chunk);
|
|
if (got == 0) break; // reached the end of the accumulated log
|
|
if (file.writeAll(chunk[0..got]) == null) break; // storage went away
|
|
offset += got;
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
pub fn main() void {
|
|
// Wait for the fat server to mount /mnt/usb (it must bring up the whole USB
|
|
// storage chain first, so it races us at boot). Bounded: if the mount never
|
|
// appears — no volume, or the no-VFS ramdisk sweep — give up silently.
|
|
var ready = false;
|
|
var tries: u32 = 0;
|
|
while (tries < 1400) : (tries += 1) {
|
|
if (fs.openDirectory("/mnt/usb")) |directory| {
|
|
var dir = directory;
|
|
dir.close();
|
|
ready = true;
|
|
break;
|
|
}
|
|
runtime.system.sleep(50);
|
|
}
|
|
if (!ready) return; // /mnt/usb never became available — nothing to persist to
|
|
|
|
// Truncate on open: each flush replaces the file, so a shorter log on a later
|
|
// boot of the same stick leaves no stale tail from a previous, longer one.
|
|
var file = fs.open(log_path, .{ .create = true, .truncate = true }) orelse return;
|
|
const written = drainKernelLog(&file);
|
|
file.close();
|
|
|
|
var line: [96]u8 = undefined;
|
|
_ = runtime.system.write(std.fmt.bufPrint(&line, "log-flush: wrote {d} bytes to {s}\n", .{ written, log_path }) catch return);
|
|
}
|
|
|
|
pub const panic = runtime.panic;
|
|
comptime {
|
|
_ = &runtime.start._start; // pull the runtime entry shim into the image
|
|
}
|