Guest User

Untitled

a guest
Jan 16th, 2018
308
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.56 KB | None | 0 0
  1. /*
  2. * File: fanotify-example.c
  3. * Date: Fri Nov 15 14:55:49 2013
  4. * Author: Aleksander Morgado <aleksander@lanedo.com>
  5. *
  6. * A simple tester of fanotify in the Linux kernel.
  7. *
  8. * This program is released in the Public Domain.
  9. *
  10. * Compile with:
  11. * $> gcc -o fanotify-example fanotify-example.c
  12. *
  13. * Run as:
  14. * $> ./fanotify-example /path/to/monitor /another/path/to/monitor ...
  15. */
  16.  
  17. /* Define _GNU_SOURCE, Otherwise we don't get O_LARGEFILE */
  18. #define _GNU_SOURCE
  19.  
  20. #include <stdio.h>
  21. #include <signal.h>
  22. #include <string.h>
  23. #include <unistd.h>
  24. #include <stdlib.h>
  25. #include <poll.h>
  26. #include <errno.h>
  27. #include <limits.h>
  28. #include <sys/stat.h>
  29. #include <sys/signalfd.h>
  30. #include <fcntl.h>
  31.  
  32. #include <linux/fanotify.h>
  33.  
  34. /* Structure to keep track of monitored directories */
  35. typedef struct {
  36. /* Path of the directory */
  37. char *path;
  38. } monitored_t;
  39.  
  40. /* Size of buffer to use when reading fanotify events */
  41. #define FANOTIFY_BUFFER_SIZE 8192
  42.  
  43. /* Enumerate list of FDs to poll */
  44. enum {
  45. FD_POLL_SIGNAL = 0,
  46. FD_POLL_FANOTIFY,
  47. FD_POLL_MAX
  48. };
  49.  
  50. /* Setup fanotify notifications (FAN) mask. All these defined in fanotify.h. */
  51. static uint64_t event_mask =
  52. (FAN_ACCESS | /* File accessed */
  53. FAN_MODIFY | /* File modified */
  54. FAN_CLOSE_WRITE | /* Writtable file closed */
  55. FAN_CLOSE_NOWRITE | /* Unwrittable file closed */
  56. FAN_OPEN | /* File was opened */
  57. FAN_ONDIR | /* We want to be reported of events in the directory */
  58. FAN_EVENT_ON_CHILD); /* We want to be reported of events in files of the directory */
  59.  
  60. /* Array of directories being monitored */
  61. static monitored_t *monitors;
  62. static int n_monitors;
  63.  
  64. static char *
  65. get_program_name_from_pid (int pid,
  66. char *buffer,
  67. size_t buffer_size)
  68. {
  69. int fd;
  70. ssize_t len;
  71. char *aux;
  72.  
  73. /* Try to get program stat */
  74. sprintf (buffer, "/proc/%d/stat", pid);
  75. if ((fd = open (buffer, O_RDONLY)) < 0)
  76. return NULL;
  77.  
  78. /* Read file contents into buffer */
  79. if ((len = read (fd, buffer, buffer_size - 1)) <= 0)
  80. {
  81. close (fd);
  82. return NULL;
  83. }
  84. close (fd);
  85.  
  86. buffer[len] = '\0';
  87. aux = strstr (buffer, "^@");
  88. if (aux)
  89. *aux = '\0';
  90.  
  91. return buffer;
  92. }
  93.  
  94. static char *
  95. get_file_path_from_fd (int fd,
  96. char *buffer,
  97. size_t buffer_size)
  98. {
  99. ssize_t len;
  100.  
  101. if (fd <= 0)
  102. return NULL;
  103.  
  104. sprintf (buffer, "/proc/self/fd/%d", fd);
  105. if ((len = readlink (buffer, buffer, buffer_size - 1)) < 0)
  106. return NULL;
  107.  
  108. buffer[len] = '\0';
  109. return buffer;
  110. }
  111.  
  112. static void
  113. event_process (struct fanotify_event_metadata *event)
  114. {
  115. char path[PATH_MAX];
  116.  
  117. printf ("Received event in path '%s'",
  118. get_file_path_from_fd (event->fd,
  119. path,
  120. PATH_MAX) ?
  121. path : "unknown");
  122. printf (" pid=%d (%s): \n",
  123. event->pid,
  124. (get_program_name_from_pid (event->pid,
  125. path,
  126. PATH_MAX) ?
  127. path : "unknown"));
  128.  
  129. if (event->mask & FAN_OPEN)
  130. printf ("\tFAN_OPEN\n");
  131. if (event->mask & FAN_ACCESS)
  132. printf ("\tFAN_ACCESS\n");
  133. if (event->mask & FAN_MODIFY)
  134. printf ("\tFAN_MODIFY\n");
  135. if (event->mask & FAN_CLOSE_WRITE)
  136. printf ("\tFAN_CLOSE_WRITE\n");
  137. if (event->mask & FAN_CLOSE_NOWRITE)
  138. printf ("\tFAN_CLOSE_NOWRITE\n");
  139. fflush (stdout);
  140.  
  141. close (event->fd);
  142. }
  143.  
  144. static void
  145. shutdown_fanotify (int fanotify_fd)
  146. {
  147. int i;
  148.  
  149. for (i = 0; i < n_monitors; ++i)
  150. {
  151. /* Remove the mark, using same event mask as when creating it */
  152. fanotify_mark (fanotify_fd,
  153. FAN_MARK_REMOVE,
  154. event_mask,
  155. AT_FDCWD,
  156. monitors[i].path);
  157. free (monitors[i].path);
  158. }
  159. free (monitors);
  160. close (fanotify_fd);
  161. }
  162.  
  163. static int
  164. initialize_fanotify (int argc,
  165. const char **argv)
  166. {
  167. int i;
  168. int fanotify_fd;
  169.  
  170. /* Create new fanotify device */
  171. if ((fanotify_fd = fanotify_init (FAN_CLOEXEC,
  172. O_RDONLY | O_CLOEXEC | O_LARGEFILE)) < 0)
  173. {
  174. fprintf (stderr,
  175. "Couldn't setup new fanotify device: %s\n",
  176. strerror (errno));
  177. return -1;
  178. }
  179.  
  180. /* Allocate array of monitor setups */
  181. n_monitors = argc - 1;
  182. monitors = malloc (n_monitors * sizeof (monitored_t));
  183.  
  184. /* Loop all input directories, setting up marks */
  185. for (i = 0; i < n_monitors; ++i)
  186. {
  187. monitors[i].path = strdup (argv[i + 1]);
  188. /* Add new fanotify mark */
  189. if (fanotify_mark (fanotify_fd,
  190. FAN_MARK_ADD,
  191. event_mask,
  192. AT_FDCWD,
  193. monitors[i].path) < 0)
  194. {
  195. fprintf (stderr,
  196. "Couldn't add monitor in directory '%s': '%s'\n",
  197. monitors[i].path,
  198. strerror (errno));
  199. return -1;
  200. }
  201.  
  202. printf ("Started monitoring directory '%s'...\n",
  203. monitors[i].path);
  204. }
  205.  
  206. return fanotify_fd;
  207. }
  208.  
  209. static void
  210. shutdown_signals (int signal_fd)
  211. {
  212. close (signal_fd);
  213. }
  214.  
  215. static int
  216. initialize_signals (void)
  217. {
  218. int signal_fd;
  219. sigset_t sigmask;
  220.  
  221. /* We want to handle SIGINT and SIGTERM in the signal_fd, so we block them. */
  222. sigemptyset (&sigmask);
  223. sigaddset (&sigmask, SIGINT);
  224. sigaddset (&sigmask, SIGTERM);
  225.  
  226. if (sigprocmask (SIG_BLOCK, &sigmask, NULL) < 0)
  227. {
  228. fprintf (stderr,
  229. "Couldn't block signals: '%s'\n",
  230. strerror (errno));
  231. return -1;
  232. }
  233.  
  234. /* Get new FD to read signals from it */
  235. if ((signal_fd = signalfd (-1, &sigmask, 0)) < 0)
  236. {
  237. fprintf (stderr,
  238. "Couldn't setup signal FD: '%s'\n",
  239. strerror (errno));
  240. return -1;
  241. }
  242.  
  243. return signal_fd;
  244. }
  245.  
  246. int
  247. main (int argc,
  248. const char **argv)
  249. {
  250. int signal_fd;
  251. int fanotify_fd;
  252. struct pollfd fds[FD_POLL_MAX];
  253.  
  254. /* Input arguments... */
  255. if (argc < 2)
  256. {
  257. fprintf (stderr, "Usage: %s directory1 [directory2 ...]\n", argv[0]);
  258. exit (EXIT_FAILURE);
  259. }
  260.  
  261. /* Initialize signals FD */
  262. if ((signal_fd = initialize_signals ()) < 0)
  263. {
  264. fprintf (stderr, "Couldn't initialize signals\n");
  265. exit (EXIT_FAILURE);
  266. }
  267.  
  268. /* Initialize fanotify FD and the marks */
  269. if ((fanotify_fd = initialize_fanotify (argc, argv)) < 0)
  270. {
  271. fprintf (stderr, "Couldn't initialize fanotify\n");
  272. exit (EXIT_FAILURE);
  273. }
  274.  
  275. /* Setup polling */
  276. fds[FD_POLL_SIGNAL].fd = signal_fd;
  277. fds[FD_POLL_SIGNAL].events = POLLIN;
  278. fds[FD_POLL_FANOTIFY].fd = fanotify_fd;
  279. fds[FD_POLL_FANOTIFY].events = POLLIN;
  280.  
  281. /* Now loop */
  282. for (;;)
  283. {
  284. /* Block until there is something to be read */
  285. if (poll (fds, FD_POLL_MAX, -1) < 0)
  286. {
  287. fprintf (stderr,
  288. "Couldn't poll(): '%s'\n",
  289. strerror (errno));
  290. exit (EXIT_FAILURE);
  291. }
  292.  
  293. /* Signal received? */
  294. if (fds[FD_POLL_SIGNAL].revents & POLLIN)
  295. {
  296. struct signalfd_siginfo fdsi;
  297.  
  298. if (read (fds[FD_POLL_SIGNAL].fd,
  299. &fdsi,
  300. sizeof (fdsi)) != sizeof (fdsi))
  301. {
  302. fprintf (stderr,
  303. "Couldn't read signal, wrong size read\n");
  304. exit (EXIT_FAILURE);
  305. }
  306.  
  307. /* Break loop if we got the expected signal */
  308. if (fdsi.ssi_signo == SIGINT ||
  309. fdsi.ssi_signo == SIGTERM)
  310. {
  311. break;
  312. }
  313.  
  314. fprintf (stderr,
  315. "Received unexpected signal\n");
  316. }
  317.  
  318. /* fanotify event received? */
  319. if (fds[FD_POLL_FANOTIFY].revents & POLLIN)
  320. {
  321. char buffer[FANOTIFY_BUFFER_SIZE];
  322. ssize_t length;
  323.  
  324. /* Read from the FD. It will read all events available up to
  325. * the given buffer size. */
  326. if ((length = read (fds[FD_POLL_FANOTIFY].fd,
  327. buffer,
  328. FANOTIFY_BUFFER_SIZE)) > 0)
  329. {
  330. struct fanotify_event_metadata *metadata;
  331.  
  332. metadata = (struct fanotify_event_metadata *)buffer;
  333. while (FAN_EVENT_OK (metadata, length))
  334. {
  335. event_process (metadata);
  336. if (metadata->fd > 0)
  337. close (metadata->fd);
  338. metadata = FAN_EVENT_NEXT (metadata, length);
  339. }
  340. }
  341. }
  342. }
  343.  
  344. /* Clean exit */
  345. shutdown_fanotify (fanotify_fd);
  346. shutdown_signals (signal_fd);
  347.  
  348. printf ("Exiting fanotify example...\n");
  349.  
  350. return EXIT_SUCCESS;
  351. }
Add Comment
Please, Sign In to add comment