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);
+	}
 }