154510930SGabriel Krisman Bertazi // SPDX-License-Identifier: GPL-2.0
254510930SGabriel Krisman Bertazi /*
354510930SGabriel Krisman Bertazi * Copyright 2021, Collabora Ltd.
454510930SGabriel Krisman Bertazi */
554510930SGabriel Krisman Bertazi
654510930SGabriel Krisman Bertazi #define _GNU_SOURCE
754510930SGabriel Krisman Bertazi #include <errno.h>
854510930SGabriel Krisman Bertazi #include <err.h>
954510930SGabriel Krisman Bertazi #include <stdlib.h>
1054510930SGabriel Krisman Bertazi #include <stdio.h>
1154510930SGabriel Krisman Bertazi #include <fcntl.h>
1254510930SGabriel Krisman Bertazi #include <sys/fanotify.h>
1354510930SGabriel Krisman Bertazi #include <sys/types.h>
1454510930SGabriel Krisman Bertazi #include <unistd.h>
1554510930SGabriel Krisman Bertazi
1654510930SGabriel Krisman Bertazi #ifndef FAN_FS_ERROR
1754510930SGabriel Krisman Bertazi #define FAN_FS_ERROR 0x00008000
1854510930SGabriel Krisman Bertazi #define FAN_EVENT_INFO_TYPE_ERROR 5
1954510930SGabriel Krisman Bertazi
2054510930SGabriel Krisman Bertazi struct fanotify_event_info_error {
2154510930SGabriel Krisman Bertazi struct fanotify_event_info_header hdr;
2254510930SGabriel Krisman Bertazi __s32 error;
2354510930SGabriel Krisman Bertazi __u32 error_count;
2454510930SGabriel Krisman Bertazi };
2554510930SGabriel Krisman Bertazi #endif
2654510930SGabriel Krisman Bertazi
2754510930SGabriel Krisman Bertazi #ifndef FILEID_INO32_GEN
2854510930SGabriel Krisman Bertazi #define FILEID_INO32_GEN 1
2954510930SGabriel Krisman Bertazi #endif
3054510930SGabriel Krisman Bertazi
3154510930SGabriel Krisman Bertazi #ifndef FILEID_INVALID
3254510930SGabriel Krisman Bertazi #define FILEID_INVALID 0xff
3354510930SGabriel Krisman Bertazi #endif
3454510930SGabriel Krisman Bertazi
print_fh(struct file_handle * fh)3554510930SGabriel Krisman Bertazi static void print_fh(struct file_handle *fh)
3654510930SGabriel Krisman Bertazi {
3754510930SGabriel Krisman Bertazi int i;
3854510930SGabriel Krisman Bertazi uint32_t *h = (uint32_t *) fh->f_handle;
3954510930SGabriel Krisman Bertazi
4054510930SGabriel Krisman Bertazi printf("\tfh: ");
4154510930SGabriel Krisman Bertazi for (i = 0; i < fh->handle_bytes; i++)
4254510930SGabriel Krisman Bertazi printf("%hhx", fh->f_handle[i]);
4354510930SGabriel Krisman Bertazi printf("\n");
4454510930SGabriel Krisman Bertazi
4554510930SGabriel Krisman Bertazi printf("\tdecoded fh: ");
4654510930SGabriel Krisman Bertazi if (fh->handle_type == FILEID_INO32_GEN)
4754510930SGabriel Krisman Bertazi printf("inode=%u gen=%u\n", h[0], h[1]);
4854510930SGabriel Krisman Bertazi else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes)
4954510930SGabriel Krisman Bertazi printf("Type %d (Superblock error)\n", fh->handle_type);
5054510930SGabriel Krisman Bertazi else
5154510930SGabriel Krisman Bertazi printf("Type %d (Unknown)\n", fh->handle_type);
5254510930SGabriel Krisman Bertazi
5354510930SGabriel Krisman Bertazi }
5454510930SGabriel Krisman Bertazi
handle_notifications(char * buffer,int len)5554510930SGabriel Krisman Bertazi static void handle_notifications(char *buffer, int len)
5654510930SGabriel Krisman Bertazi {
5754510930SGabriel Krisman Bertazi struct fanotify_event_metadata *event =
5854510930SGabriel Krisman Bertazi (struct fanotify_event_metadata *) buffer;
5954510930SGabriel Krisman Bertazi struct fanotify_event_info_header *info;
6054510930SGabriel Krisman Bertazi struct fanotify_event_info_error *err;
6154510930SGabriel Krisman Bertazi struct fanotify_event_info_fid *fid;
6254510930SGabriel Krisman Bertazi int off;
6354510930SGabriel Krisman Bertazi
6454510930SGabriel Krisman Bertazi for (; FAN_EVENT_OK(event, len); event = FAN_EVENT_NEXT(event, len)) {
6554510930SGabriel Krisman Bertazi
6654510930SGabriel Krisman Bertazi if (event->mask != FAN_FS_ERROR) {
67*b7eccf75SJan Kara printf("unexpected FAN MARK: %llx\n",
68*b7eccf75SJan Kara (unsigned long long)event->mask);
6954510930SGabriel Krisman Bertazi goto next_event;
7054510930SGabriel Krisman Bertazi }
7154510930SGabriel Krisman Bertazi
7254510930SGabriel Krisman Bertazi if (event->fd != FAN_NOFD) {
7354510930SGabriel Krisman Bertazi printf("Unexpected fd (!= FAN_NOFD)\n");
7454510930SGabriel Krisman Bertazi goto next_event;
7554510930SGabriel Krisman Bertazi }
7654510930SGabriel Krisman Bertazi
7754510930SGabriel Krisman Bertazi printf("FAN_FS_ERROR (len=%d)\n", event->event_len);
7854510930SGabriel Krisman Bertazi
7954510930SGabriel Krisman Bertazi for (off = sizeof(*event) ; off < event->event_len;
8054510930SGabriel Krisman Bertazi off += info->len) {
8154510930SGabriel Krisman Bertazi info = (struct fanotify_event_info_header *)
8254510930SGabriel Krisman Bertazi ((char *) event + off);
8354510930SGabriel Krisman Bertazi
8454510930SGabriel Krisman Bertazi switch (info->info_type) {
8554510930SGabriel Krisman Bertazi case FAN_EVENT_INFO_TYPE_ERROR:
8654510930SGabriel Krisman Bertazi err = (struct fanotify_event_info_error *) info;
8754510930SGabriel Krisman Bertazi
8854510930SGabriel Krisman Bertazi printf("\tGeneric Error Record: len=%d\n",
8954510930SGabriel Krisman Bertazi err->hdr.len);
9054510930SGabriel Krisman Bertazi printf("\terror: %d\n", err->error);
9154510930SGabriel Krisman Bertazi printf("\terror_count: %d\n", err->error_count);
9254510930SGabriel Krisman Bertazi break;
9354510930SGabriel Krisman Bertazi
9454510930SGabriel Krisman Bertazi case FAN_EVENT_INFO_TYPE_FID:
9554510930SGabriel Krisman Bertazi fid = (struct fanotify_event_info_fid *) info;
9654510930SGabriel Krisman Bertazi
9754510930SGabriel Krisman Bertazi printf("\tfsid: %x%x\n",
9854510930SGabriel Krisman Bertazi fid->fsid.val[0], fid->fsid.val[1]);
9954510930SGabriel Krisman Bertazi print_fh((struct file_handle *) &fid->handle);
10054510930SGabriel Krisman Bertazi break;
10154510930SGabriel Krisman Bertazi
10254510930SGabriel Krisman Bertazi default:
10354510930SGabriel Krisman Bertazi printf("\tUnknown info type=%d len=%d:\n",
10454510930SGabriel Krisman Bertazi info->info_type, info->len);
10554510930SGabriel Krisman Bertazi }
10654510930SGabriel Krisman Bertazi }
10754510930SGabriel Krisman Bertazi next_event:
10854510930SGabriel Krisman Bertazi printf("---\n\n");
10954510930SGabriel Krisman Bertazi }
11054510930SGabriel Krisman Bertazi }
11154510930SGabriel Krisman Bertazi
main(int argc,char ** argv)11254510930SGabriel Krisman Bertazi int main(int argc, char **argv)
11354510930SGabriel Krisman Bertazi {
11454510930SGabriel Krisman Bertazi int fd;
11554510930SGabriel Krisman Bertazi
11654510930SGabriel Krisman Bertazi char buffer[BUFSIZ];
11754510930SGabriel Krisman Bertazi
11854510930SGabriel Krisman Bertazi if (argc < 2) {
11954510930SGabriel Krisman Bertazi printf("Missing path argument\n");
12054510930SGabriel Krisman Bertazi return 1;
12154510930SGabriel Krisman Bertazi }
12254510930SGabriel Krisman Bertazi
12354510930SGabriel Krisman Bertazi fd = fanotify_init(FAN_CLASS_NOTIF|FAN_REPORT_FID, O_RDONLY);
12454510930SGabriel Krisman Bertazi if (fd < 0)
12554510930SGabriel Krisman Bertazi errx(1, "fanotify_init");
12654510930SGabriel Krisman Bertazi
12754510930SGabriel Krisman Bertazi if (fanotify_mark(fd, FAN_MARK_ADD|FAN_MARK_FILESYSTEM,
12854510930SGabriel Krisman Bertazi FAN_FS_ERROR, AT_FDCWD, argv[1])) {
12954510930SGabriel Krisman Bertazi errx(1, "fanotify_mark");
13054510930SGabriel Krisman Bertazi }
13154510930SGabriel Krisman Bertazi
13254510930SGabriel Krisman Bertazi while (1) {
13354510930SGabriel Krisman Bertazi int n = read(fd, buffer, BUFSIZ);
13454510930SGabriel Krisman Bertazi
13554510930SGabriel Krisman Bertazi if (n < 0)
13654510930SGabriel Krisman Bertazi errx(1, "read");
13754510930SGabriel Krisman Bertazi
13854510930SGabriel Krisman Bertazi handle_notifications(buffer, n);
13954510930SGabriel Krisman Bertazi }
14054510930SGabriel Krisman Bertazi
14154510930SGabriel Krisman Bertazi return 0;
14254510930SGabriel Krisman Bertazi }
143