xref: /linux/samples/fanotify/fs-monitor.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
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