fork download
  1. #define _GNU_SOURCE
  2. #include <errno.h>
  3. #include <fcntl.h>
  4. #include <limits.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <sys/fanotify.h>
  10. #include <unistd.h>
  11.  
  12. #define BUF_SIZE 65536
  13.  
  14. int
  15. main(int argc, char **argv)
  16. {
  17. int fd, ret, event_fd;
  18. ssize_t len, path_len;
  19. char path[PATH_MAX];
  20. char procfd_path[PATH_MAX];
  21. char events_buf[BUF_SIZE];
  22. struct file_handle *file_handle;
  23. struct fanotify_event_metadata *metadata;
  24. struct fanotify_event_info_fid *fid;
  25.  
  26. if (argc != 2) {
  27. fprintf(stderr, "Invalid number of command line arguments.\n");
  28. exit(EXIT_FAILURE);
  29. }
  30.  
  31. /* Create an fanotify file descriptor with FAN_REPORT_FID as a flag
  32.   so that program can receive fid events. */
  33.  
  34. fd = fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_FID, 0);
  35. if (fd == -1) {
  36. perror("fanotify_init");
  37. exit(EXIT_FAILURE);
  38. }
  39.  
  40. /* Place a mark on the filesystem object supplied in argv[1]. */
  41.  
  42. ret = fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_FILESYSTEM,
  43. ( FAN_CREATE | FAN_DELETE | FAN_MODIFY | FAN_MOVE | FAN_ONDIR | FAN_EVENT_ON_CHILD),
  44. AT_FDCWD, argv[1]);
  45. if (ret == -1) {
  46. perror("fanotify_mark");
  47. exit(EXIT_FAILURE);
  48. }
  49.  
  50. printf("Listening for events.\n");
  51.  
  52. /* Read events from the event queue into a buffer */
  53.  
  54. len = read(fd, (void *) &events_buf, sizeof(events_buf));
  55. if (len == -1 && errno != EAGAIN) {
  56. perror("read");
  57. exit(EXIT_FAILURE);
  58. }
  59.  
  60. /* Process all events within the buffer */
  61.  
  62. for (metadata = (struct fanotify_event_metadata *) events_buf;
  63. FAN_EVENT_OK(metadata, len);
  64. metadata = FAN_EVENT_NEXT(metadata, len)) {
  65. fid = (struct fanotify_event_info_fid *) (metadata + 1);
  66. file_handle = (struct file_handle *) fid->handle;
  67.  
  68. if (metadata->mask & FAN_CREATE) {
  69. printf ("\tFAN_CREATE\n");
  70. }
  71. if (metadata->mask & FAN_DELETE) {
  72. printf ("\tFAN_DELETE\n");
  73. }
  74. if (metadata->mask & FAN_MODIFY) {
  75. printf ("\tFAN_MODIFY\n");
  76. }
  77. if (metadata->mask & FAN_MOVE) {
  78. printf ("\tFAN_MOVE\n");
  79. }
  80. if (metadata->mask & FAN_ONDIR) {
  81. printf ("\tFAN_ONDIR\n");
  82. }
  83. if (metadata->mask & FAN_EVENT_ON_CHILD) {
  84. printf ("\tFAN_EVENT_ON_CHILD\n");
  85. }
  86.  
  87.  
  88. /* Ensure that the event info is of the correct type */
  89.  
  90. if (fid->hdr.info_type != FAN_EVENT_INFO_TYPE_FID) {
  91. fprintf(stderr, "Received unexpected event info type.\n");
  92. // exit(EXIT_FAILURE);
  93. }
  94. printf("event len %u, FAN_EVENT_METADATA_LEN: %ld\n", metadata->event_len, FAN_EVENT_METADATA_LEN);
  95. printf("header len %d\n", fid->hdr.len);
  96. printf("enent metadata %p\n", metadata);
  97. printf("fid %p\n", fid);
  98. printf("file handle %p\n", file_handle);
  99.  
  100. // if (metadata->mask == FAN_CREATE)
  101. // printf("FAN_CREATE (file created):");
  102.  
  103. // if (metadata->mask == FAN_CREATE | FAN_ONDIR)
  104. // printf("FAN_CREATE | FAN_ONDIR (subdirectory created):");
  105.  
  106. /* metadata->fd is set to FAN_NOFD when FAN_REPORT_FID is enabled.
  107.   To obtain a file descriptor for the file object corresponding to
  108.   an event you can use the struct file_handle that's provided
  109.   within the fanotify_event_info_fid in conjunction with the
  110.   open_by_handle_at(2) system call. A check for ESTALE is done
  111.   to accommodate for the situation where the file handle for the
  112.   object was deleted prior to this system call. */
  113.  
  114. event_fd = open_by_handle_at(AT_FDCWD, file_handle, O_RDONLY);
  115. if (event_fd == -1) {
  116. if (errno == ESTALE) {
  117. printf("File handle is no longer valid. "
  118. "File has been deleted\n");
  119. continue;
  120. } else {
  121. perror("open_by_handle_at");
  122. exit(EXIT_FAILURE);
  123. }
  124. }
  125.  
  126. snprintf(procfd_path, sizeof(procfd_path), "/proc/self/fd/%d",
  127. event_fd);
  128.  
  129. /* Retrieve and print the path of the modified dentry */
  130.  
  131. path_len = readlink(procfd_path, path, sizeof(path) - 1);
  132. if (path_len == -1) {
  133. perror("readlink");
  134. exit(EXIT_FAILURE);
  135. }
  136.  
  137. path[path_len] = '\0';
  138. printf("\tDirectory '%s' has been modified.\n", path);
  139.  
  140. /* Close associated file descriptor for this event */
  141.  
  142. close(event_fd);
  143. }
  144.  
  145. printf("All events processed successfully. Program exiting.\n");
  146. exit(EXIT_SUCCESS);
  147. }
Compilation error #stdin compilation error #stdout 0s 0KB
stdin
Standard input is empty
compilation info
prog.c: In function ‘main’:
prog.c:34:41: error: ‘FAN_REPORT_FID’ undeclared (first use in this function); did you mean ‘FAN_REPORT_TID’?
    fd = fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_FID, 0);
                                         ^~~~~~~~~~~~~~
                                         FAN_REPORT_TID
prog.c:34:41: note: each undeclared identifier is reported only once for each function it appears in
prog.c:43:26: error: ‘FAN_CREATE’ undeclared (first use in this function); did you mean ‘DN_CREATE’?
                        ( FAN_CREATE | FAN_DELETE | FAN_MODIFY | FAN_MOVE | FAN_ONDIR | FAN_EVENT_ON_CHILD),
                          ^~~~~~~~~~
                          DN_CREATE
prog.c:43:39: error: ‘FAN_DELETE’ undeclared (first use in this function); did you mean ‘DN_DELETE’?
                        ( FAN_CREATE | FAN_DELETE | FAN_MODIFY | FAN_MOVE | FAN_ONDIR | FAN_EVENT_ON_CHILD),
                                       ^~~~~~~~~~
                                       DN_DELETE
prog.c:43:65: error: ‘FAN_MOVE’ undeclared (first use in this function); did you mean ‘FAN_NOFD’?
                        ( FAN_CREATE | FAN_DELETE | FAN_MODIFY | FAN_MOVE | FAN_ONDIR | FAN_EVENT_ON_CHILD),
                                                                 ^~~~~~~~
                                                                 FAN_NOFD
prog.c:66:48: error: dereferencing pointer to incomplete type ‘struct fanotify_event_info_fid’
        file_handle = (struct file_handle *) fid->handle;
                                                ^~
prog.c:90:34: error: ‘FAN_EVENT_INFO_TYPE_FID’ undeclared (first use in this function); did you mean ‘FAN_EVENT_ON_CHILD’?
        if (fid->hdr.info_type != FAN_EVENT_INFO_TYPE_FID) {
                                  ^~~~~~~~~~~~~~~~~~~~~~~
                                  FAN_EVENT_ON_CHILD
stdout
Standard output is empty