1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright 2021, Collabora Ltd. |
4 | */ |
5 | |
6 | #define _GNU_SOURCE |
7 | #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_ERROR |
17 | #define FAN_FS_ERROR 0x00008000 |
18 | #define FAN_EVENT_INFO_TYPE_ERROR 5 |
19 | |
20 | struct fanotify_event_info_error { |
21 | struct fanotify_event_info_header hdr; |
22 | __s32 error; |
23 | __u32 error_count; |
24 | }; |
25 | #endif |
26 | |
27 | #ifndef FILEID_INO32_GEN |
28 | #define FILEID_INO32_GEN 1 |
29 | #endif |
30 | |
31 | #ifndef FILEID_INVALID |
32 | #define FILEID_INVALID 0xff |
33 | #endif |
34 | |
35 | static void print_fh(struct file_handle *fh) |
36 | { |
37 | int i; |
38 | uint32_t *h = (uint32_t *) fh->f_handle; |
39 | |
40 | printf(format: "\tfh: " ); |
41 | for (i = 0; i < fh->handle_bytes; i++) |
42 | printf(format: "%hhx" , fh->f_handle[i]); |
43 | printf(format: "\n" ); |
44 | |
45 | printf(format: "\tdecoded fh: " ); |
46 | if (fh->handle_type == FILEID_INO32_GEN) |
47 | printf(format: "inode=%u gen=%u\n" , h[0], h[1]); |
48 | else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes) |
49 | printf(format: "Type %d (Superblock error)\n" , fh->handle_type); |
50 | else |
51 | printf(format: "Type %d (Unknown)\n" , fh->handle_type); |
52 | |
53 | } |
54 | |
55 | static 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(format: "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(format: "Unexpected fd (!= FAN_NOFD)\n" ); |
74 | goto next_event; |
75 | } |
76 | |
77 | printf(format: "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(format: "\tGeneric Error Record: len=%d\n" , |
89 | err->hdr.len); |
90 | printf(format: "\terror: %d\n" , err->error); |
91 | printf(format: "\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(format: "\tfsid: %x%x\n" , |
98 | fid->fsid.val[0], fid->fsid.val[1]); |
99 | print_fh(fh: (struct file_handle *) &fid->handle); |
100 | break; |
101 | |
102 | default: |
103 | printf(format: "\tUnknown info type=%d len=%d:\n" , |
104 | info->info_type, info->len); |
105 | } |
106 | } |
107 | next_event: |
108 | printf(format: "---\n\n" ); |
109 | } |
110 | } |
111 | |
112 | int main(int argc, char **argv) |
113 | { |
114 | int fd; |
115 | |
116 | char buffer[BUFSIZ]; |
117 | |
118 | if (argc < 2) { |
119 | printf(format: "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(status: 1, format: "fanotify_init" ); |
126 | |
127 | if (fanotify_mark(fanotify_fd: fd, FAN_MARK_ADD|FAN_MARK_FILESYSTEM, |
128 | FAN_FS_ERROR, AT_FDCWD, pathname: argv[1])) { |
129 | errx(status: 1, format: "fanotify_mark" ); |
130 | } |
131 | |
132 | while (1) { |
133 | int n = read(fd: fd, buf: buffer, BUFSIZ); |
134 | |
135 | if (n < 0) |
136 | errx(status: 1, format: "read" ); |
137 | |
138 | handle_notifications(buffer, len: n); |
139 | } |
140 | |
141 | return 0; |
142 | } |
143 | |