use bcc::ring_buf::{RingBufBuilder, RingCallback}; use bcc::BccError; use bcc::{Tracepoint, BPF}; use clap::{App, Arg}; use core::sync::atomic::{AtomicBool, Ordering}; use std::os::raw::c_int; use std::sync::Arc; use std::time::Instant; // BPF ring buffer submit example // // Based on: https://github.com/iovisor/bcc/blob/master/examples/ringbuf/ringbuf_submit.py #[repr(C)] struct event_t { filename: [u8; 64], dfd: c_int, flags: c_int, mode: c_int, } fn do_main(runnable: Arc) -> Result<(), BccError> { let matches = App::new("ringbuf submit") .about("Ring buffer submit example") .arg( Arg::with_name("duration") .long("duration") .value_name("Seconds") .help("The total duration to run") .takes_value(true), ) .get_matches(); let duration: Option = matches .value_of("duration") .map(|v| std::time::Duration::new(v.parse().expect("Invalid argument for duration"), 0)); let code = " BPF_RINGBUF_OUTPUT(buffer, 1 << 4); struct event { char filename[64]; int dfd; int flags; int mode; }; int openat_entry(struct tracepoint__syscalls__sys_enter_openat *args) { int zero = 0; struct event *event = buffer.ringbuf_reserve(sizeof(struct event)); if (!event) { return 1; } bpf_probe_read_user_str(event->filename, sizeof(event->filename), args->filename); event->dfd = args->dfd; event->flags = args->flags; event->mode = args->mode; buffer.ringbuf_submit(event, 0); // or, to discard: buffer.ringbuf_discard(event, 0); return 0; } "; // compile the above BPF code! let mut module = BPF::new(code)?; // tracepoints! Tracepoint::new() .handler("openat_entry") .subsystem("syscalls") .tracepoint("sys_enter_openat") .attach(&mut module)?; let cb = RingCallback::new(Box::new(ring_buf_callback)); let table = module.table("buffer")?; let mut ring_buf = RingBufBuilder::new(table, cb).build()?; println!( "{:-64} {:10} {:10} {:10}", "FILENAME", "DIR_FD", "FLAGS", "MODE" ); let start = Instant::now(); while runnable.load(Ordering::SeqCst) { ring_buf.consume(); if let Some(d) = duration { if Instant::now() - start >= d { break; } } std::thread::sleep(std::time::Duration::from_millis(500)); } Ok(()) } fn parse_struct(x: &[u8]) -> event_t { unsafe { std::ptr::read_unaligned(x.as_ptr() as *const event_t) } } fn get_string(x: &[u8]) -> String { match x.iter().position(|&r| r == 0) { Some(zero_pos) => String::from_utf8_lossy(&x[0..zero_pos]).to_string(), None => String::from_utf8_lossy(x).to_string(), } } fn ring_buf_callback(data: &[u8]) { let event = parse_struct(data); println!( "{:-64} {:10} {:10} {:10}", get_string(&event.filename), event.dfd, event.flags, event.mode ); } fn main() { let runnable = Arc::new(AtomicBool::new(true)); let r = runnable.clone(); ctrlc::set_handler(move || { r.store(false, Ordering::SeqCst); }) .expect("Failed to set handler for SIGINT / SIGTERM"); match do_main(runnable) { Err(x) => { eprintln!("Error: {}", x); std::process::exit(1); } _ => {} } }