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