diff --git a/src/task-find-magic b/src/task-find-magic index f3d77e6d0fa85596ba2afc692412cb6052cd1ebf..48ebbebb66dc47b799d7cc1230c32a0c8a3163db 100755 --- a/src/task-find-magic +++ b/src/task-find-magic @@ -6,4 +6,4 @@ args=${@:2} src_dir=$(dirname "$(command -v $0)") -find "${path}" | ${src_dir}/task_filter_magic ${args} +find "${path}" -type f | ${src_dir}/task_filter_magic ${args} diff --git a/src/task_filter_magic.c b/src/task_filter_magic.c index 4194008b50a63552cb9dd492963e122024fe2e86..8a32d5b5b9dab855dcbc6320fa12970b643aab52 100644 --- a/src/task_filter_magic.c +++ b/src/task_filter_magic.c @@ -144,46 +144,9 @@ static void plog(const unsigned int level, const char *fmt, ...) { va_end(args); } -static int search_buf_bpf(const char *buf, size_t f_len, const char *file_full_path, - const char *magic) { - struct NAME_BPF *skel; - int err; - - /* Set up libbpf errors and debug info callback */ - libbpf_set_print(libbpf_print_fn); - - /* Bump RLIMIT_MEMLOCK to allow BPF sub-system to do anything */ - bump_memlock_rlimit(); - - /* Open BPF application */ - skel = BPF_OPEN(); - if (!skel) { - fprintf(stderr, "Failed to open BPF skeleton\n"); - return EXIT_FAILURE; - } - - /* Load & verify BPF programs */ - err = BPF_LOAD(skel); - if (err) { - fprintf(stderr, "Failed to load and verify BPF skeleton\n"); - goto destroy; - } - - int prog_fd = bpf_program__fd(skel->progs.entry); - - /* TODO: Pass buf, f_len and litral to bpf. */ - long ret = syscall(SYS_bpftask, prog_fd, buf); - - printf("%d = %d\n", ret, (long) *buf); - -destroy: - BPF_DESTROY(skel); - return EXIT_SUCCESS; -} - #define MAX_PATHLEN 512 -static int filter_magic(size_t offset, const char *magic) { +static int filter_magic_user_fp(size_t offset, const char *magic) { int err; size_t magic_size = strlen(magic) + 1; char buf[magic_size]; @@ -204,7 +167,12 @@ static int filter_magic(size_t offset, const char *magic) { } /* Line must end with a newline. */ - pathbuf[strlen(pathbuf)-1] = '\0'; + if (pathbuf[strlen(pathbuf)-1] == '\n') { + pathbuf[strlen(pathbuf)-1] = '\0'; + } else { + log_err("line without newline"); + return EXIT_FAILURE; + } log_debug("pathbuf = %s", pathbuf); FILE *fp = fopen(pathbuf, "r"); @@ -257,23 +225,282 @@ static int filter_magic(size_t offset, const char *magic) { } } +static int filter_magic_user(size_t offset, const char *magic) { + int err; + size_t magic_size = strlen(magic) + 1; + char buf[magic_size]; + buf[magic_size-1] = '\0'; + + while (true) { + char pathbuf[MAX_PATHLEN]; + /* TODO: What if line too long? */ + char *ptr = fgets(pathbuf, MAX_PATHLEN, stdin); + if (ptr == NULL) { + if (ferror(stdin)) { + log_err("fgets(stdin) failed"); + return EXIT_FAILURE; + } else { + log_debug("EOF reached"); + return EXIT_SUCCESS; + } + } + + /* Line must end with a newline. */ + if (pathbuf[strlen(pathbuf)-1] == '\n') { + pathbuf[strlen(pathbuf)-1] = '\0'; + } else { + log_err("line without newline"); + return EXIT_FAILURE; + } + log_debug("pathbuf = %s", pathbuf); + + int fd = open(pathbuf, O_RDONLY); + if (fd == -1) { + perror(pathbuf); + return EXIT_FAILURE; + } + + struct stat statbuf; + err = fstat(fd, &statbuf); + if (err != 0) { + log_debug("Skipping %s: Error fstat()ing file.", pathbuf); + goto close; + } + + // handling only regular files and FIFOs + if (!S_ISREG(statbuf.st_mode) && !S_ISFIFO(statbuf.st_mode)) { + log_debug("Skipping %s: Mode %u is not a file.", pathbuf, statbuf.st_mode); + goto close; + } + + if (statbuf.st_size < offset + magic_size-1) { + goto close; + } + + if (offset) { + off_t o = lseek(fd, offset, SEEK_SET); + if (o == -1) { + perror("lseek"); + return EXIT_FAILURE; + } + } + + ssize_t nread = read(fd, buf, magic_size-1); + if (nread == -1) { + perror("read"); + return EXIT_FAILURE; + } + if (nread < magic_size-1) { + log_warn("read(%s) returned short item count", pathbuf); + return EXIT_FAILURE; + } + + if (strcmp(magic, buf) == 0) { + printf("%s\n", pathbuf); + } + + close: + err = close(fd); + if (err) { + perror("close"); + return EXIT_FAILURE; + } + } +} + +static int filter_magic_user_burst(size_t offset, const char *magic, size_t max_burst_size, bool skip) { + int err; + + size_t magic_size = strlen(magic) + 1; + char buf[magic_size]; + buf[magic_size-1] = '\0'; + + bool eof = false; + while (!eof) { + size_t burst_size; + char pathbufs[max_burst_size][MAX_PATHLEN]; + + for (burst_size = 0; burst_size < max_burst_size; burst_size++) { + char *pathbuf = pathbufs[burst_size]; + char *ptr = fgets(pathbuf, MAX_PATHLEN, stdin); + if (ptr == NULL) { + if (ferror(stdin)) { + log_err("fgets(stdin) failed"); + return EXIT_FAILURE; + } else { + log_debug("EOF reached"); + eof = true; + break; + } + } + + /* Line must end with a newline. */ + if (pathbuf[strlen(pathbuf)-1] == '\n') { + pathbuf[strlen(pathbuf)-1] = '\0'; + } else { + log_err("line too long / no newline"); + return EXIT_FAILURE; + } + } + + if (skip) continue; + + for (size_t i = 0; i < burst_size; i++) { + char *pathbuf = pathbufs[i]; + log_debug("pathbuf = %s", pathbuf); + + int fd = open(pathbuf, O_RDONLY); + if (fd == -1) { + perror(pathbuf); + return EXIT_FAILURE; + } + + struct stat statbuf; + err = fstat(fd, &statbuf); + if (err != 0) { + log_debug("Skipping %s: Error fstat()ing file.", pathbuf); + goto close; + } + + // handling only regular files and FIFOs + if (!S_ISREG(statbuf.st_mode) && !S_ISFIFO(statbuf.st_mode)) { + log_debug("Skipping %s: Mode %u is not a file.", pathbuf, statbuf.st_mode); + goto close; + } + + if (statbuf.st_size < offset + magic_size-1) { + goto close; + } + + if (offset) { + off_t o = lseek(fd, offset, SEEK_SET); + if (o == -1) { + perror("lseek"); + return EXIT_FAILURE; + } + } + + ssize_t nread = read(fd, buf, magic_size-1); + if (nread == -1) { + perror("read"); + return EXIT_FAILURE; + } + if (nread < magic_size-1) { + log_warn("read(%s) returned short item count", pathbuf); + return EXIT_FAILURE; + } + + if (strcmp(magic, buf) == 0) { + printf("%s\n", pathbuf); + } + + close: + err = close(fd); + if (err) { + perror("close"); + return EXIT_FAILURE; + } + } + } +} + +static int filter_magic_bpf(size_t offset, const char *magic, size_t max_burst_size) { + int err; + int ret = EXIT_SUCCESS; + + struct NAME_BPF *skel; + + /* Set up libbpf errors and debug info callback */ + libbpf_set_print(libbpf_print_fn); + + /* Bump RLIMIT_MEMLOCK to allow BPF sub-system to do anything */ + bump_memlock_rlimit(); + + /* Open BPF application */ + skel = BPF_OPEN(); + if (!skel) { + fprintf(stderr, "Failed to open BPF skeleton\n"); + return EXIT_FAILURE; + } + + + size_t magic_size = strlen(magic) + 1; + char buf[magic_size]; + buf[magic_size-1] = '\0'; + char pathbufs[max_burst_size][MAX_PATHLEN]; + /* TODO: Write pathbufs, buf, offset and magic into program. */ + + /* Load & verify BPF programs */ + err = BPF_LOAD(skel); + if (err) { + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); + goto destroy; + } + + int prog_fd = bpf_program__fd(skel->progs.entry); + + bool eof = false; + while (!eof) { + size_t burst_size; + for (burst_size = 0; burst_size < max_burst_size; burst_size++) { + char *pathbuf = pathbufs[burst_size]; + char *ptr = fgets(pathbuf, MAX_PATHLEN, stdin); + if (ptr == NULL) { + if (ferror(stdin)) { + log_err("fgets(stdin) failed"); + return EXIT_FAILURE; + } else { + log_debug("EOF reached"); + eof = true; + break; + } + } + + /* Line must end with a newline. */ + if (pathbuf[strlen(pathbuf)-1] == '\n') { + pathbuf[strlen(pathbuf)-1] = '\0'; + } else { + log_err("line too long / no newline"); + ret = EXIT_FAILURE; + goto destroy; + } + } + + /* TODO: pass burst_size to bpf */ + err = syscall(SYS_bpftask, prog_fd, NULL); + if (err) { + log_err("sys_bpftaks = %d", err); + ret = EXIT_FAILURE; + goto destroy; + } + } + +destroy: + BPF_DESTROY(skel); + return ret; +} + int main(int argc, char **argv) { bool debug = false; - bool variant_bpf = true; + char *variant; + size_t max_burst_size = 1024; /* 32k l1d, 256k l2, 4096k l3 */ size_t offset = 0; char *magic; int c; opterr = 0; - while ((c = getopt(argc, argv, "v:" "D" "o:" "m:")) != -1) { + while ((c = getopt(argc, argv, "D" "v:" "b:" "o:" "m:")) != -1) { switch (c) { - case 'v': - variant_bpf = strcmp("bpf", optarg) == 0; - break; case 'D': debug = true; break; + case 'v': + variant = optarg; + break; + case 'b': + max_burst_size = atoi(optarg); + break; case 'o': offset = atoi(optarg); break; @@ -301,10 +528,20 @@ int main(int argc, char **argv) if (debug) { set_log_level(LOG_LEVEL_DEBUG); - fprintf(stderr, "%s: variant_bpf=%d, debug=%d, magic='%s', offset='%llu'\n", - argv[0], variant_bpf, debug, magic, offset); + fprintf(stderr, "%s: variant=%s, debug=%d, magic='%s', offset='%llu'\n", + argv[0], variant, debug, magic, offset); } - filter_magic(offset, magic); + if (strcmp(variant, "user_fp") == 0) { + return filter_magic_user_fp(offset, magic); + } else if (strcmp(variant, "user") == 0) { + return filter_magic_user(offset, magic); + } else if (strcmp(variant, "user_burst") == 0) { + return filter_magic_user_burst(offset, magic, max_burst_size, false); + } else if (strcmp(variant, "user_burst_skip") == 0) { + return filter_magic_user_burst(offset, magic, max_burst_size, true); + } else if (strcmp(variant, "bpf") == 0) { + return filter_magic_bpf(offset, magic, max_burst_size); + } }