summaryrefslogtreecommitdiffstats
path: root/rsnix/src/fat.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-02 15:21:34 +0200
committersalmonik <salmonik@tuta.io>2026-08-02 15:21:34 +0200
commitc7d92071e1dd11c45999457b16554b4abaa73b28 (patch)
treeaff7c7f19adcffe1dd91e1c2514af02c77fd524e /rsnix/src/fat.rs
parentv0.5.5: fix real-hardware boot crash — shadow back in heap as first allocation (diff)
downloadrs-dos-c7d92071e1dd11c45999457b16554b4abaa73b28.tar.gz
rs-dos-c7d92071e1dd11c45999457b16554b4abaa73b28.zip
v0.5.5: crash reports go to a dedicated CRASHLOG USB stick
The fault handler now writes crash.log to the volume labeled CRASHLOG (label-selected via fat::crash_vol), falling back to slot 0. On real hardware the boot USB may be unwritable, so a second stick labeled CRASHLOG survives the write; the shell auto-prints the previous crash report from it at next boot (read_crash_log resolves /disk/<uid>/crash.log through the FAT path, since Disk nodes hold no cached children). - fat.rs: volume_label() + crash_vol() (no allocation) - fs.rs: write_crash_log targets crash_vol(); read_crash_log prefers the CRASHLOG disk node; drop now-unused first_disk() - mkdisk.sh: --label option - test-fault.sh: boots with a dedicated CRASHLOG stick (mkfs -F 32 -n CRASHLOG), verifies crash.log lands there and NOT on the ESP
Diffstat (limited to '')
-rw-r--r--rsnix/src/fat.rs31
1 files changed, 30 insertions, 1 deletions
diff --git a/rsnix/src/fat.rs b/rsnix/src/fat.rs
index eda81ed..b7e0da1 100644
--- a/rsnix/src/fat.rs
+++ b/rsnix/src/fat.rs
@@ -71,6 +71,31 @@ pub fn is_mounted(vol: usize) -> bool {
71 vols().get(vol).map(|v| v.mounted).unwrap_or(false) 71 vols().get(vol).map(|v| v.mounted).unwrap_or(false)
72} 72}
73 73
74/// The volume's label — the part of its uid before the serial suffix
75/// (uid is "LABEL-XXXXXXXX", label sanitized to [A-Z0-9_], so the first
76/// '-' always terminates it). No allocation: borrows the uid string.
77pub fn volume_label(vol: usize) -> Option<&'static str> {
78 let uid = &vols().get(vol)?.uid;
79 Some(uid.split_once('-').map(|(l, _)| l).unwrap_or(uid))
80}
81
82/// Index of the crash-log volume: the first volume whose label is
83/// "CRASHLOG" (a dedicated stick survives reboot writes that a boot
84/// device may not accept), else slot 0 (first mounted) as before.
85pub fn crash_vol() -> Option<usize> {
86 let n = volume_count();
87 if n == 0 {
88 return None;
89 }
90 for vol in 0..n {
91 if let Some(label) = volume_label(vol)
92 && label.eq_ignore_ascii_case("CRASHLOG") {
93 return Some(vol);
94 }
95 }
96 Some(0)
97}
98
74/// Re-scan after a disk arrival/removal: unmount volumes whose disk left, 99/// Re-scan after a disk arrival/removal: unmount volumes whose disk left,
75/// mount every disk that has no mounted volume (which also re-tries 100/// mount every disk that has no mounted volume (which also re-tries
76/// mounts that failed at boot). Volume slots are tombstoned, never 101/// mounts that failed at boot). Volume slots are tombstoned, never
@@ -175,7 +200,11 @@ fn v() -> &'static mut Volume {
175 match vols().get_mut(i) { 200 match vols().get_mut(i) {
176 Some(v) => v, 201 Some(v) => v,
177 None => { 202 None => {
178 crate::serial_println!("fat: internal error — no volume at slot {}", i); 203 crate::serial_println!(
204 "fat: internal error — no volume at slot {} (len={})",
205 i,
206 vols().len()
207 );
179 crate::interrupts::halt(); 208 crate::interrupts::halt();
180 } 209 }
181 } 210 }