wasm-bpf/examples/opensnoop/opensnoop.c

175 lines
4.3 KiB
C

// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
// Copyright (c) 2019 Facebook
// Copyright (c) 2020 Netflix
//
// Based on opensnoop(8) from BCC by Brendan Gregg and others.
// 14-Feb-2020 Brendan Gregg Created this.
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include "libbpf-wasm.h"
#include "opensnoop.h"
#include "opensnoop.skel.h"
#include "trace_helpers.h"
#include <inttypes.h>
#include <sys/types.h>
typedef uint32_t __u32;
typedef uint64_t __u64;
/* Tune the buffer size and wakeup rate. These settings cope with roughly
* 50k opens/sec.
*/
#define PERF_BUFFER_PAGES 64
#define PERF_BUFFER_TIME_MS 10
/* Set the poll timeout when no events occur. This can affect -d accuracy. */
#define PERF_POLL_TIMEOUT_MS 100
#define NSEC_PER_SEC 1000000000ULL
// static volatile sig_atomic_t exiting = 0;
static struct env {
pid_t pid;
pid_t tid;
uid_t uid;
int duration;
bool verbose;
bool timestamp;
bool print_uid;
bool extended;
bool failed;
char* name;
} env = {.uid = INVALID_UID};
static int handle_event(void* ctx, void* data, size_t data_sz) {
const struct event* e = data;
struct tm* tm;
int sps_cnt;
char ts[32];
time_t t;
int fd, err;
/* name filtering is currently done in user space */
if (env.name && strstr(e->comm, env.name) == NULL)
return 0;
/* prepare fields */
time(&t);
tm = localtime(&t);
strftime(ts, sizeof(ts), "%H:%M:%S", tm);
if (e->ret >= 0) {
fd = e->ret;
err = 0;
} else {
fd = -1;
err = -e->ret;
}
/* print output */
sps_cnt = 0;
if (env.timestamp) {
printf("%-8s ", ts);
sps_cnt += 9;
}
if (env.print_uid) {
printf("%-7d ", e->uid);
sps_cnt += 8;
}
printf("%-6d %-16s %3d %3d ", e->pid, e->comm, fd, err);
sps_cnt += 7 + 17 + 4 + 4;
if (env.extended) {
printf("%08o ", e->flags);
sps_cnt += 9;
}
printf("%s\n", e->fname);
return 0;
}
int main(int argc, char** argv) {
struct opensnoop_bpf* obj;
__u64 time_end = 0;
int err;
obj = opensnoop_bpf__open();
if (!obj) {
fprintf(stdout, "failed to open BPF object\n");
return 1;
}
/* initialize global data (filtering options) */
obj->rodata->targ_tgid = env.pid;
obj->rodata->targ_pid = env.tid;
obj->rodata->targ_uid = env.uid;
obj->rodata->targ_failed = env.failed;
/* aarch64 and riscv64 don't have open syscall */
if (!tracepoint_exists("syscalls", "sys_enter_open")) {
bpf_program__set_autoload(
obj->progs.tracepoint__syscalls__sys_enter_open, false);
bpf_program__set_autoload(
obj->progs.tracepoint__syscalls__sys_exit_open, false);
}
err = opensnoop_bpf__load(obj);
if (err) {
fprintf(stdout, "failed to load BPF object: %d\n", err);
goto cleanup;
}
err = opensnoop_bpf__attach(obj);
if (err) {
fprintf(stdout, "failed to attach BPF programs\n");
goto cleanup;
}
printf("attach ok\n");
/* print headers */
if (env.timestamp)
printf("%-8s ", "TIME");
if (env.print_uid)
printf("%-7s ", "UID");
printf("%-6s %-16s %3s %3s ", "PID", "COMM", "FD", "ERR");
if (env.extended)
printf("%-8s ", "FLAGS");
printf("%s", "PATH");
printf("\n");
/* setup event callbacks */
struct bpf_buffer* buf =
bpf_buffer__open(obj->maps.events, handle_event, NULL);
if (!buf) {
err = -errno;
fprintf(stdout, "failed to open perf buffer: %d\n", err);
goto cleanup;
}
/* setup duration */
if (env.duration)
time_end = get_ktime_ns() + env.duration * NSEC_PER_SEC;
/* main: poll */
while (true) {
err = bpf_buffer__poll(buf, PERF_POLL_TIMEOUT_MS);
if (err < 0 && err != -EINTR) {
fprintf(stdout, "error polling perf buffer: %s\n", strerror(-err));
goto cleanup;
}
if (env.duration && get_ktime_ns() > time_end)
goto cleanup;
/* reset err to return 0 if exiting */
err = 0;
}
cleanup:
bpf_buffer__free(buf);
opensnoop_bpf__destroy(obj);
return err != 0;
}