162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2021, Collabora Ltd. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#define _GNU_SOURCE 762306a36Sopenharmony_ci#include <errno.h> 862306a36Sopenharmony_ci#include <err.h> 962306a36Sopenharmony_ci#include <stdlib.h> 1062306a36Sopenharmony_ci#include <stdio.h> 1162306a36Sopenharmony_ci#include <fcntl.h> 1262306a36Sopenharmony_ci#include <sys/fanotify.h> 1362306a36Sopenharmony_ci#include <sys/types.h> 1462306a36Sopenharmony_ci#include <unistd.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#ifndef FAN_FS_ERROR 1762306a36Sopenharmony_ci#define FAN_FS_ERROR 0x00008000 1862306a36Sopenharmony_ci#define FAN_EVENT_INFO_TYPE_ERROR 5 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct fanotify_event_info_error { 2162306a36Sopenharmony_ci struct fanotify_event_info_header hdr; 2262306a36Sopenharmony_ci __s32 error; 2362306a36Sopenharmony_ci __u32 error_count; 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci#endif 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#ifndef FILEID_INO32_GEN 2862306a36Sopenharmony_ci#define FILEID_INO32_GEN 1 2962306a36Sopenharmony_ci#endif 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#ifndef FILEID_INVALID 3262306a36Sopenharmony_ci#define FILEID_INVALID 0xff 3362306a36Sopenharmony_ci#endif 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic void print_fh(struct file_handle *fh) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci int i; 3862306a36Sopenharmony_ci uint32_t *h = (uint32_t *) fh->f_handle; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci printf("\tfh: "); 4162306a36Sopenharmony_ci for (i = 0; i < fh->handle_bytes; i++) 4262306a36Sopenharmony_ci printf("%hhx", fh->f_handle[i]); 4362306a36Sopenharmony_ci printf("\n"); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci printf("\tdecoded fh: "); 4662306a36Sopenharmony_ci if (fh->handle_type == FILEID_INO32_GEN) 4762306a36Sopenharmony_ci printf("inode=%u gen=%u\n", h[0], h[1]); 4862306a36Sopenharmony_ci else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes) 4962306a36Sopenharmony_ci printf("Type %d (Superblock error)\n", fh->handle_type); 5062306a36Sopenharmony_ci else 5162306a36Sopenharmony_ci printf("Type %d (Unknown)\n", fh->handle_type); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic void handle_notifications(char *buffer, int len) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci struct fanotify_event_metadata *event = 5862306a36Sopenharmony_ci (struct fanotify_event_metadata *) buffer; 5962306a36Sopenharmony_ci struct fanotify_event_info_header *info; 6062306a36Sopenharmony_ci struct fanotify_event_info_error *err; 6162306a36Sopenharmony_ci struct fanotify_event_info_fid *fid; 6262306a36Sopenharmony_ci int off; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci for (; FAN_EVENT_OK(event, len); event = FAN_EVENT_NEXT(event, len)) { 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (event->mask != FAN_FS_ERROR) { 6762306a36Sopenharmony_ci printf("unexpected FAN MARK: %llx\n", 6862306a36Sopenharmony_ci (unsigned long long)event->mask); 6962306a36Sopenharmony_ci goto next_event; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (event->fd != FAN_NOFD) { 7362306a36Sopenharmony_ci printf("Unexpected fd (!= FAN_NOFD)\n"); 7462306a36Sopenharmony_ci goto next_event; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci printf("FAN_FS_ERROR (len=%d)\n", event->event_len); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci for (off = sizeof(*event) ; off < event->event_len; 8062306a36Sopenharmony_ci off += info->len) { 8162306a36Sopenharmony_ci info = (struct fanotify_event_info_header *) 8262306a36Sopenharmony_ci ((char *) event + off); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci switch (info->info_type) { 8562306a36Sopenharmony_ci case FAN_EVENT_INFO_TYPE_ERROR: 8662306a36Sopenharmony_ci err = (struct fanotify_event_info_error *) info; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci printf("\tGeneric Error Record: len=%d\n", 8962306a36Sopenharmony_ci err->hdr.len); 9062306a36Sopenharmony_ci printf("\terror: %d\n", err->error); 9162306a36Sopenharmony_ci printf("\terror_count: %d\n", err->error_count); 9262306a36Sopenharmony_ci break; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci case FAN_EVENT_INFO_TYPE_FID: 9562306a36Sopenharmony_ci fid = (struct fanotify_event_info_fid *) info; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci printf("\tfsid: %x%x\n", 9862306a36Sopenharmony_ci fid->fsid.val[0], fid->fsid.val[1]); 9962306a36Sopenharmony_ci print_fh((struct file_handle *) &fid->handle); 10062306a36Sopenharmony_ci break; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci default: 10362306a36Sopenharmony_ci printf("\tUnknown info type=%d len=%d:\n", 10462306a36Sopenharmony_ci info->info_type, info->len); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_cinext_event: 10862306a36Sopenharmony_ci printf("---\n\n"); 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ciint main(int argc, char **argv) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci int fd; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci char buffer[BUFSIZ]; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (argc < 2) { 11962306a36Sopenharmony_ci printf("Missing path argument\n"); 12062306a36Sopenharmony_ci return 1; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci fd = fanotify_init(FAN_CLASS_NOTIF|FAN_REPORT_FID, O_RDONLY); 12462306a36Sopenharmony_ci if (fd < 0) 12562306a36Sopenharmony_ci errx(1, "fanotify_init"); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (fanotify_mark(fd, FAN_MARK_ADD|FAN_MARK_FILESYSTEM, 12862306a36Sopenharmony_ci FAN_FS_ERROR, AT_FDCWD, argv[1])) { 12962306a36Sopenharmony_ci errx(1, "fanotify_mark"); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci while (1) { 13362306a36Sopenharmony_ci int n = read(fd, buffer, BUFSIZ); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (n < 0) 13662306a36Sopenharmony_ci errx(1, "read"); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci handle_notifications(buffer, n); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci} 143