0001
0002
0003
0004
0005
0006 #define _GNU_SOURCE
0007 #include <errno.h>
0008 #include <err.h>
0009 #include <stdlib.h>
0010 #include <stdio.h>
0011 #include <fcntl.h>
0012 #include <sys/fanotify.h>
0013 #include <sys/types.h>
0014 #include <unistd.h>
0015
0016 #ifndef FAN_FS_ERROR
0017 #define FAN_FS_ERROR 0x00008000
0018 #define FAN_EVENT_INFO_TYPE_ERROR 5
0019
0020 struct fanotify_event_info_error {
0021 struct fanotify_event_info_header hdr;
0022 __s32 error;
0023 __u32 error_count;
0024 };
0025 #endif
0026
0027 #ifndef FILEID_INO32_GEN
0028 #define FILEID_INO32_GEN 1
0029 #endif
0030
0031 #ifndef FILEID_INVALID
0032 #define FILEID_INVALID 0xff
0033 #endif
0034
0035 static void print_fh(struct file_handle *fh)
0036 {
0037 int i;
0038 uint32_t *h = (uint32_t *) fh->f_handle;
0039
0040 printf("\tfh: ");
0041 for (i = 0; i < fh->handle_bytes; i++)
0042 printf("%hhx", fh->f_handle[i]);
0043 printf("\n");
0044
0045 printf("\tdecoded fh: ");
0046 if (fh->handle_type == FILEID_INO32_GEN)
0047 printf("inode=%u gen=%u\n", h[0], h[1]);
0048 else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes)
0049 printf("Type %d (Superblock error)\n", fh->handle_type);
0050 else
0051 printf("Type %d (Unknown)\n", fh->handle_type);
0052
0053 }
0054
0055 static void handle_notifications(char *buffer, int len)
0056 {
0057 struct fanotify_event_metadata *event =
0058 (struct fanotify_event_metadata *) buffer;
0059 struct fanotify_event_info_header *info;
0060 struct fanotify_event_info_error *err;
0061 struct fanotify_event_info_fid *fid;
0062 int off;
0063
0064 for (; FAN_EVENT_OK(event, len); event = FAN_EVENT_NEXT(event, len)) {
0065
0066 if (event->mask != FAN_FS_ERROR) {
0067 printf("unexpected FAN MARK: %llx\n",
0068 (unsigned long long)event->mask);
0069 goto next_event;
0070 }
0071
0072 if (event->fd != FAN_NOFD) {
0073 printf("Unexpected fd (!= FAN_NOFD)\n");
0074 goto next_event;
0075 }
0076
0077 printf("FAN_FS_ERROR (len=%d)\n", event->event_len);
0078
0079 for (off = sizeof(*event) ; off < event->event_len;
0080 off += info->len) {
0081 info = (struct fanotify_event_info_header *)
0082 ((char *) event + off);
0083
0084 switch (info->info_type) {
0085 case FAN_EVENT_INFO_TYPE_ERROR:
0086 err = (struct fanotify_event_info_error *) info;
0087
0088 printf("\tGeneric Error Record: len=%d\n",
0089 err->hdr.len);
0090 printf("\terror: %d\n", err->error);
0091 printf("\terror_count: %d\n", err->error_count);
0092 break;
0093
0094 case FAN_EVENT_INFO_TYPE_FID:
0095 fid = (struct fanotify_event_info_fid *) info;
0096
0097 printf("\tfsid: %x%x\n",
0098 fid->fsid.val[0], fid->fsid.val[1]);
0099 print_fh((struct file_handle *) &fid->handle);
0100 break;
0101
0102 default:
0103 printf("\tUnknown info type=%d len=%d:\n",
0104 info->info_type, info->len);
0105 }
0106 }
0107 next_event:
0108 printf("---\n\n");
0109 }
0110 }
0111
0112 int main(int argc, char **argv)
0113 {
0114 int fd;
0115
0116 char buffer[BUFSIZ];
0117
0118 if (argc < 2) {
0119 printf("Missing path argument\n");
0120 return 1;
0121 }
0122
0123 fd = fanotify_init(FAN_CLASS_NOTIF|FAN_REPORT_FID, O_RDONLY);
0124 if (fd < 0)
0125 errx(1, "fanotify_init");
0126
0127 if (fanotify_mark(fd, FAN_MARK_ADD|FAN_MARK_FILESYSTEM,
0128 FAN_FS_ERROR, AT_FDCWD, argv[1])) {
0129 errx(1, "fanotify_mark");
0130 }
0131
0132 while (1) {
0133 int n = read(fd, buffer, BUFSIZ);
0134
0135 if (n < 0)
0136 errx(1, "read");
0137
0138 handle_notifications(buffer, n);
0139 }
0140
0141 return 0;
0142 }