diff --git a/init/src/main.rs b/init/src/main.rs index 275275e64b..f660673d0f 100644 --- a/init/src/main.rs +++ b/init/src/main.rs @@ -130,16 +130,6 @@ fn main() { scheduler .schedule_start_and_report_errors(&mut unit_store, UnitId("00_logd.service".to_owned())); scheduler.step(&mut unit_store, &mut init_config); - // NOTE: init/daemon stdio is deliberately kept on the kernel console - // rather than being redirected into /scheme/log. Redirecting made the boot - // "go dark" after logd on text/recovery ISOs (bare/mini): the graphical - // bootlog (fbbootlogd, VT1) does not reliably surface /scheme/log to the - // framebuffer, and logd's console mirror is racy, so the console showed - // nothing between logd and the login VT — indistinguishable from a hang. - // Keeping stdio on the console makes the full boot observable on - // `-serial` and the framebuffer. (A quiet/splash mode for the graphical - // full ISO can re-enable the redirect once fbbootlogd rendering is fixed.) - let _ = switch_stdio; let runtime_target = UnitId("00_runtime.target".to_owned()); scheduler.schedule_start_and_report_errors(&mut unit_store, runtime_target.clone()); @@ -155,6 +145,29 @@ fn main() { Path::new("/usr"), Path::new("/etc"), ); + + // Pin init/daemon stdio to the dedicated boot-log VT (fbcon/1) before the + // /usr units run. Rationale: stdio otherwise stays on the kernel console + // (/scheme/debug), which fbcond renders onto the *active* VT. Once the + // `29_activate_console` unit switches the active VT to 2 for the getty + // login, any daemon that logs afterwards — late async driver attach + // (i2c-hidd, evdevd, dw-acpi-i2cd) or smolnetd's bounded NIC wait — paints + // its output on top of the login banner/prompt, so the prompt is never the + // last thing on screen. Pinning daemon output to VT1 (a fixed VT, not the + // active one) keeps the boot log fully visible — VT1 is the active console + // during boot, and fbcond still mirrors it to the serial line — while + // leaving VT2 clean for a login prompt that lands last. + // + // This is deliberately NOT the old `/scheme/log` redirect that made boot + // "go dark": that depended on fbbootlogd surfacing /scheme/log to the + // framebuffer (racy/unreliable). A real VT renders directly, so full-boot + // observability is preserved. Best-effort: if fbcon/1 cannot be opened + // (e.g. fbcond absent on a headless/serial-only boot), stdio stays on the + // kernel console and the boot remains observable exactly as before. + if let Err(err) = switch_stdio("/scheme/fbcon/1") { + eprintln!("INIT: keeping stdio on kernel console (fbcon/1 unavailable: {err})"); + } + { // FIXME introduce multi-user.target unit and replace the config dir iteration // scheduler.schedule_start_and_report_errors(&mut unit_store, UnitId("multi-user.target".to_owned()));