| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- // 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 __GLIBC__
- #include <asm-generic/int-ll64.h>
- #endif
- #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",
- #if defined(__GLIBC__)
- fid->fsid.val[0], fid->fsid.val[1]);
- #else
- fid->fsid.__val[0], fid->fsid.__val[1]);
- #endif
- 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;
- }
|