Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | // SPDX-License-Identifier: GPL-2.0 /* * Copyright 2021, Collabora Ltd. */ #define _GNU_SOURCE #include <errno.h> #include <err.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <sys/fanotify.h> #include <sys/types.h> #include <unistd.h> #ifndef FAN_FS_ERROR #define FAN_FS_ERROR 0x00008000 #define FAN_EVENT_INFO_TYPE_ERROR 5 struct fanotify_event_info_error { struct fanotify_event_info_header hdr; __s32 error; __u32 error_count; }; #endif #ifndef FILEID_INO32_GEN #define FILEID_INO32_GEN 1 #endif #ifndef FILEID_INVALID #define FILEID_INVALID 0xff #endif static void print_fh(struct file_handle *fh) { int i; uint32_t *h = (uint32_t *) fh->f_handle; printf("\tfh: "); for (i = 0; i < fh->handle_bytes; i++) printf("%hhx", fh->f_handle[i]); printf("\n"); printf("\tdecoded fh: "); if (fh->handle_type == FILEID_INO32_GEN) printf("inode=%u gen=%u\n", h[0], h[1]); else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes) printf("Type %d (Superblock error)\n", fh->handle_type); else printf("Type %d (Unknown)\n", fh->handle_type); } static void handle_notifications(char *buffer, int len) { struct fanotify_event_metadata *event = (struct fanotify_event_metadata *) buffer; struct fanotify_event_info_header *info; struct fanotify_event_info_error *err; struct fanotify_event_info_fid *fid; int off; for (; FAN_EVENT_OK(event, len); event = FAN_EVENT_NEXT(event, len)) { if (event->mask != FAN_FS_ERROR) { printf("unexpected FAN MARK: %llx\n", (unsigned long long)event->mask); goto next_event; } if (event->fd != FAN_NOFD) { printf("Unexpected fd (!= FAN_NOFD)\n"); goto next_event; } printf("FAN_FS_ERROR (len=%d)\n", event->event_len); for (off = sizeof(*event) ; off < event->event_len; off += info->len) { info = (struct fanotify_event_info_header *) ((char *) event + off); switch (info->info_type) { case FAN_EVENT_INFO_TYPE_ERROR: err = (struct fanotify_event_info_error *) info; printf("\tGeneric Error Record: len=%d\n", err->hdr.len); printf("\terror: %d\n", err->error); printf("\terror_count: %d\n", err->error_count); break; case FAN_EVENT_INFO_TYPE_FID: fid = (struct fanotify_event_info_fid *) info; printf("\tfsid: %x%x\n", fid->fsid.val[0], fid->fsid.val[1]); print_fh((struct file_handle *) &fid->handle); break; default: printf("\tUnknown info type=%d len=%d:\n", info->info_type, info->len); } } next_event: printf("---\n\n"); } } int main(int argc, char **argv) { int fd; char buffer[BUFSIZ]; if (argc < 2) { printf("Missing path argument\n"); return 1; } fd = fanotify_init(FAN_CLASS_NOTIF|FAN_REPORT_FID, O_RDONLY); if (fd < 0) errx(1, "fanotify_init"); if (fanotify_mark(fd, FAN_MARK_ADD|FAN_MARK_FILESYSTEM, FAN_FS_ERROR, AT_FDCWD, argv[1])) { errx(1, "fanotify_mark"); } while (1) { int n = read(fd, buffer, BUFSIZ); if (n < 0) errx(1, "read"); handle_notifications(buffer, n); } return 0; } |