fs-monitor.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright 2021, Collabora Ltd.
  4. */
  5. #define _GNU_SOURCE
  6. #include <errno.h>
  7. #include <err.h>
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <fcntl.h>
  11. #include <sys/fanotify.h>
  12. #include <sys/types.h>
  13. #include <unistd.h>
  14. #ifndef __GLIBC__
  15. #include <asm-generic/int-ll64.h>
  16. #endif
  17. #ifndef FAN_FS_ERROR
  18. #define FAN_FS_ERROR 0x00008000
  19. #define FAN_EVENT_INFO_TYPE_ERROR 5
  20. struct fanotify_event_info_error {
  21. struct fanotify_event_info_header hdr;
  22. __s32 error;
  23. __u32 error_count;
  24. };
  25. #endif
  26. #ifndef FILEID_INO32_GEN
  27. #define FILEID_INO32_GEN 1
  28. #endif
  29. #ifndef FILEID_INVALID
  30. #define FILEID_INVALID 0xff
  31. #endif
  32. static void print_fh(struct file_handle *fh)
  33. {
  34. int i;
  35. uint32_t *h = (uint32_t *) fh->f_handle;
  36. printf("\tfh: ");
  37. for (i = 0; i < fh->handle_bytes; i++)
  38. printf("%hhx", fh->f_handle[i]);
  39. printf("\n");
  40. printf("\tdecoded fh: ");
  41. if (fh->handle_type == FILEID_INO32_GEN)
  42. printf("inode=%u gen=%u\n", h[0], h[1]);
  43. else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes)
  44. printf("Type %d (Superblock error)\n", fh->handle_type);
  45. else
  46. printf("Type %d (Unknown)\n", fh->handle_type);
  47. }
  48. static void handle_notifications(char *buffer, int len)
  49. {
  50. struct fanotify_event_metadata *event =
  51. (struct fanotify_event_metadata *) buffer;
  52. struct fanotify_event_info_header *info;
  53. struct fanotify_event_info_error *err;
  54. struct fanotify_event_info_fid *fid;
  55. int off;
  56. for (; FAN_EVENT_OK(event, len); event = FAN_EVENT_NEXT(event, len)) {
  57. if (event->mask != FAN_FS_ERROR) {
  58. printf("unexpected FAN MARK: %llx\n",
  59. (unsigned long long)event->mask);
  60. goto next_event;
  61. }
  62. if (event->fd != FAN_NOFD) {
  63. printf("Unexpected fd (!= FAN_NOFD)\n");
  64. goto next_event;
  65. }
  66. printf("FAN_FS_ERROR (len=%d)\n", event->event_len);
  67. for (off = sizeof(*event) ; off < event->event_len;
  68. off += info->len) {
  69. info = (struct fanotify_event_info_header *)
  70. ((char *) event + off);
  71. switch (info->info_type) {
  72. case FAN_EVENT_INFO_TYPE_ERROR:
  73. err = (struct fanotify_event_info_error *) info;
  74. printf("\tGeneric Error Record: len=%d\n",
  75. err->hdr.len);
  76. printf("\terror: %d\n", err->error);
  77. printf("\terror_count: %d\n", err->error_count);
  78. break;
  79. case FAN_EVENT_INFO_TYPE_FID:
  80. fid = (struct fanotify_event_info_fid *) info;
  81. printf("\tfsid: %x%x\n",
  82. #if defined(__GLIBC__)
  83. fid->fsid.val[0], fid->fsid.val[1]);
  84. #else
  85. fid->fsid.__val[0], fid->fsid.__val[1]);
  86. #endif
  87. print_fh((struct file_handle *) &fid->handle);
  88. break;
  89. default:
  90. printf("\tUnknown info type=%d len=%d:\n",
  91. info->info_type, info->len);
  92. }
  93. }
  94. next_event:
  95. printf("---\n\n");
  96. }
  97. }
  98. int main(int argc, char **argv)
  99. {
  100. int fd;
  101. char buffer[BUFSIZ];
  102. if (argc < 2) {
  103. printf("Missing path argument\n");
  104. return 1;
  105. }
  106. fd = fanotify_init(FAN_CLASS_NOTIF|FAN_REPORT_FID, O_RDONLY);
  107. if (fd < 0)
  108. errx(1, "fanotify_init");
  109. if (fanotify_mark(fd, FAN_MARK_ADD|FAN_MARK_FILESYSTEM,
  110. FAN_FS_ERROR, AT_FDCWD, argv[1])) {
  111. errx(1, "fanotify_mark");
  112. }
  113. while (1) {
  114. int n = read(fd, buffer, BUFSIZ);
  115. if (n < 0)
  116. errx(1, "read");
  117. handle_notifications(buffer, n);
  118. }
  119. return 0;
  120. }