kanit

Toy init system
Log | Files | Refs | README | LICENSE

bsod.rs (2806B)


      1 // we all love to see a bsod
      2 
      3 use std::backtrace::Backtrace;
      4 use std::io::{Write, stdin, stdout};
      5 use std::os::fd::RawFd;
      6 use std::os::unix::process::CommandExt;
      7 use std::panic::PanicHookInfo;
      8 use std::process::Command;
      9 
     10 use nix::fcntl::{OFlag, open};
     11 use nix::ioctl_write_int_bad;
     12 use nix::sys::reboot::{RebootMode, reboot};
     13 use nix::sys::stat::Mode;
     14 use nix::unistd::isatty;
     15 
     16 const BLUE_BG: &str = "\x1b]P0000080";
     17 const WHITE_TEXT: &str = "\x1b]P7FFFFFF";
     18 
     19 const CLEAR_SCREEN: &str = "\x1b[1;1H\x1b[2J";
     20 
     21 const VT_ACTIVATE: i32 = 0x5606;
     22 const VT_WAIT_ACTIVE: i32 = 0x5607;
     23 
     24 ioctl_write_int_bad!(vt_activate, VT_ACTIVATE);
     25 ioctl_write_int_bad!(vt_wait_activate, VT_WAIT_ACTIVE);
     26 
     27 fn print_info(info: &PanicHookInfo, tty: bool) {
     28     let mut stdout = stdout();
     29 
     30     if tty {
     31         let _ = write!(&mut stdout, "{BLUE_BG}{WHITE_TEXT}{CLEAR_SCREEN}");
     32     }
     33 
     34     let _ = writeln!(
     35         &mut stdout,
     36         "Kanit Panic\n===========\nKanit experienced an unrecoverable error and cannot continue."
     37     );
     38     let _ = writeln!(
     39         &mut stdout,
     40         "Consider checking the system journal or the following backtrace.\n"
     41     );
     42 
     43     if let Some(s) = info.payload().downcast_ref::<&str>() {
     44         let _ = writeln!(&mut stdout, "Message: {s}");
     45     }
     46 
     47     if let Some(loc) = info.location() {
     48         let _ = writeln!(
     49             &mut stdout,
     50             "File: {}:{}:{}",
     51             loc.file(),
     52             loc.line(),
     53             loc.column()
     54         );
     55     }
     56 
     57     let mut junk = String::new();
     58 
     59     if tty {
     60         let _ = writeln!(&mut stdout, "Press enter to view backtrace...");
     61 
     62         let _ = stdout.flush();
     63 
     64         let _ = stdin().read_line(&mut junk);
     65     }
     66 
     67     let backtrace = Backtrace::force_capture();
     68 
     69     let _ = writeln!(&mut stdout, "-- backtrace --\n{backtrace}");
     70 
     71     if tty {
     72         let _ = writeln!(
     73             &mut stdout,
     74             "Init is now considered unstable, press enter to enter into emergency shell..."
     75         );
     76 
     77         let _ = stdout.flush();
     78         let _ = stdin().read_line(&mut junk);
     79     }
     80 
     81     let _ = Command::new("sh").exec();
     82 
     83     if tty {
     84         let _ = writeln!(
     85             &mut stdout,
     86             "failed to enter emergency shell, press enter to restart..."
     87         );
     88 
     89         let _ = stdout.flush();
     90         let _ = stdin().read_line(&mut junk);
     91     }
     92 
     93     let _ = reboot(RebootMode::RB_AUTOBOOT);
     94 }
     95 
     96 pub fn bsod(info: &PanicHookInfo) {
     97     if !isatty(RawFd::from(1)).unwrap_or(false) {
     98         return print_info(info, false);
     99     }
    100 
    101     // change virtual terminal
    102     if let Ok(fd) = open("/dev/console", OFlag::O_RDONLY, Mode::empty()) {
    103         // SAFETY: we ensure `fd` is valid
    104         unsafe {
    105             let _ = vt_activate(fd, 1);
    106             let _ = vt_wait_activate(fd, 1);
    107         }
    108     }
    109 
    110     print_info(info, false);
    111 }