From b2a4fab21c56028dfad31f4ca081e3a5da3c9809 Mon Sep 17 00:00:00 2001 From: Luis Gerhorst <privat@luisgerhorst.de> Date: Tue, 13 Jul 2021 14:35:53 +0200 Subject: [PATCH] task_find: Add sys variant --- src/task_find.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 4 deletions(-) diff --git a/src/task_find.c b/src/task_find.c index 110894a..f930b45 100644 --- a/src/task_find.c +++ b/src/task_find.c @@ -21,6 +21,12 @@ /* isprint */ #include <ctype.h> +#include <sys/syscall.h> // SYS_getdents64 +#include <fcntl.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <inttypes.h> + #include <sys/resource.h> #include <bpf/libbpf.h> #include "task_find.skel.h" @@ -214,6 +220,82 @@ destroy: return ret; } +typedef uint64_t ino64_t; +typedef uint64_t off64_t; + +struct linux_dirent64 { + ino64_t d_ino; /* 64-bit inode number */ + off64_t d_off; /* 64-bit offset to next structure */ + unsigned short d_reclen; /* Size of this dirent */ + unsigned char d_type; /* File type */ + char d_name[]; /* Filename (null-terminated) */ +}; + +/* Same as in GNU find. */ +#define BUF_SIZE (32*1024) + +static int do_user_find(unsigned char d_type, int parent_dfd, const char *name, + const char *search_name, int search_type, bool debug) { + int err = 0; + size_t namelen = strlen(name); + + if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { + return 0; + } + + bool match = + search_type != -1 && d_type == search_type + || search_name != NULL && strcmp(search_name, name) == 0; + if (match) { + write(STDOUT_FILENO, name, namelen); + write(STDOUT_FILENO, "\n", 1); + } + + if (d_type != DT_DIR) { + return 0; + } + int dfd = openat(parent_dfd, name, O_RDONLY | O_DIRECTORY); + if (dfd == -1) { + perror("openat"); + fprintf(stderr, "Warning: openat(%d, %s, ...) failed, is someone modifying the tree?\n", parent_dfd, name); + return 0; + } + + write(STDOUT_FILENO, name, namelen); + write(STDOUT_FILENO, "/\n", 2); + + while (true) { + char buf[BUF_SIZE]; + int nread = syscall(SYS_getdents64, dfd, buf, BUF_SIZE); + if (nread == -1) { + perror("getdents64"); + exit(EXIT_FAILURE); + } + if (nread == 0) { + break; + } + + for (int bpos = 0; bpos < nread;) { + struct linux_dirent64 *d = (struct linux_dirent64 *) (buf + bpos); + err = do_user_find(d->d_type, dfd, d->d_name, search_name, search_type, debug); + if (err) { + goto close; + } + bpos += d->d_reclen; + } + } + +close: + write(STDOUT_FILENO, "..\n", 3); + close(dfd); + return err; +} + +static int user_find(const char *path, const char *search_name, + bool debug, int search_type) { + return do_user_find(DT_DIR, AT_FDCWD, path, search_name, search_type, debug); +} + int main(int argc, char **argv) { bool debug = false; @@ -295,12 +377,12 @@ int main(int argc, char **argv) argv[0], variant_bpf, debug, name, path); } + int ret; if (variant_bpf) { - return bpf_find(path, name, debug, type); + ret = bpf_find(path, name, debug, type); } else { - fprintf(stderr, "Only bpf variant supported.\n"); - return EXIT_FAILURE; + ret = user_find(path, name, debug, type); } - return EXIT_SUCCESS; + return ret; } -- GitLab