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 }