in src/main.rs [138:228]
fn main() -> Result<()> {
let _ = Bpftop::parse();
if !nix::unistd::Uid::current().is_root() {
return Err(anyhow!("This program must be run as root"));
}
// Initialize the journald layer or ignore if not available
let journald_layer = match tracing_journald::layer() {
Ok(layer) => Some(layer),
Err(_) => None,
};
// Initialize the tracing subscriber with the journald layer
let registry = tracing_subscriber::registry()
.with(journald_layer)
.with(tracing_subscriber::filter::LevelFilter::INFO);
// Try to set this subscriber as the global default
registry.try_init()?;
let kernel_version = KernelVersion::current()?;
let _owned_fd: OwnedFd;
let mut stats_enabled_via_procfs = false;
let mut iter_link = None;
info!("Starting bpftop...");
info!("Kernel: {:?}", kernel_version);
// enable BPF stats via syscall if kernel version >= 5.8
if kernel_version >= KernelVersion::new(5, 8, 0) {
let fd = unsafe { bpf_enable_stats(libbpf_sys::BPF_STATS_RUN_TIME) };
if fd < 0 {
return Err(anyhow!("Failed to enable BPF stats via syscall"));
}
_owned_fd = unsafe { OwnedFd::from_raw_fd(fd) };
info!("Enabled BPF stats via syscall");
// load and attach pid_iter BPF program to get process information
let skel_builder = PidIterSkelBuilder::default();
let mut open_object = MaybeUninit::uninit();
let open_skel = skel_builder.open(&mut open_object)?;
let mut skel = open_skel.load()?;
skel.attach()?;
iter_link = skel.links.bpftop_iter;
} else {
// otherwise, enable via procfs
// but first check if procfs bpf stats were already enabled
if procfs_bpf_stats_is_enabled()? {
info!("BPF stats already enabled via procfs");
} else {
fs::write(PROCFS_BPF_STATS_ENABLED, b"1").context(format!(
"Failed to enable BPF stats via {}",
PROCFS_BPF_STATS_ENABLED
))?;
stats_enabled_via_procfs = true;
info!("Enabled BPF stats via procfs");
}
}
// capture panic to disable BPF stats via procfs
let previous_hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| {
if stats_enabled_via_procfs {
if let Err(err) = procs_bfs_stats_disable() {
eprintln!("Failed to disable BPF stats via procfs: {:?}", err);
}
}
previous_hook(panic_info);
}));
// setup terminal
let mut terminal_manager = TerminalManager::new()?;
// create app and run the draw loop
let app = App::new();
app.start_background_thread(iter_link);
let res = run_draw_loop(&mut terminal_manager.terminal, app);
// disable BPF stats via procfs if needed
if stats_enabled_via_procfs {
procs_bfs_stats_disable()?;
}
#[allow(clippy::question_mark)]
if res.is_err() {
return res;
}
Ok(())
}