1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /*
3 * This file is part of libmount from util-linux project.
4 *
5 * Copyright (C) 2014-2018 Karel Zak <kzak@redhat.com>
6 *
7 * libmount is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 */
12
13 /**
14 * SECTION: monitor
15 * @title: Monitor
16 * @short_description: interface to monitor mount tables
17 *
18 * For example monitor VFS (/proc/self/mountinfo) for changes:
19 *
20 * <informalexample>
21 * <programlisting>
22 * const char *filename;
23 * struct libmount_monitor *mn = mnt_new_monitor();
24 *
25 * mnt_monitor_enable_kernel(mn, TRUE));
26 *
27 * printf("waiting for changes...\n");
28 * while (mnt_monitor_wait(mn, -1) > 0) {
29 * while (mnt_monitor_next_change(mn, &filename, NULL) == 0)
30 * printf(" %s: change detected\n", filename);
31 * }
32 * mnt_unref_monitor(mn);
33 * </programlisting>
34 * </informalexample>
35 *
36 */
37
38 #include "fileutils.h"
39 #include "mountP.h"
40 #include "pathnames.h"
41
42 #include <sys/inotify.h>
43 #include <sys/epoll.h>
44
45
46 struct monitor_opers;
47
48 struct monitor_entry {
49 int fd; /* private entry file descriptor */
50 char *path; /* path to the monitored file */
51 int type; /* MNT_MONITOR_TYPE_* */
52 uint32_t events; /* wanted epoll events */
53
54 const struct monitor_opers *opers;
55
56 unsigned int enable : 1,
57 changed : 1;
58
59 struct list_head ents;
60 };
61
62 struct libmnt_monitor {
63 int refcount;
64 int fd; /* public monitor file descriptor */
65
66 struct list_head ents;
67 };
68
69 struct monitor_opers {
70 int (*op_get_fd)(struct libmnt_monitor *, struct monitor_entry *);
71 int (*op_close_fd)(struct libmnt_monitor *, struct monitor_entry *);
72 int (*op_event_verify)(struct libmnt_monitor *, struct monitor_entry *);
73 };
74
75 static int monitor_modify_epoll(struct libmnt_monitor *mn,
76 struct monitor_entry *me, int enable);
77
78 /**
79 * mnt_new_monitor:
80 *
81 * The initial refcount is 1, and needs to be decremented to
82 * release the resources of the filesystem.
83 *
84 * Returns: newly allocated struct libmnt_monitor.
85 */
86 struct libmnt_monitor *mnt_new_monitor(void)
87 {
88 struct libmnt_monitor *mn = calloc(1, sizeof(*mn));
89 if (!mn)
90 return NULL;
91
92 mn->refcount = 1;
93 mn->fd = -1;
94 INIT_LIST_HEAD(&mn->ents);
95
96 DBG(MONITOR, ul_debugobj(mn, "alloc"));
97 return mn;
98 }
99
100 /**
101 * mnt_ref_monitor:
102 * @mn: monitor pointer
103 *
104 * Increments reference counter.
105 */
106 void mnt_ref_monitor(struct libmnt_monitor *mn)
107 {
108 if (mn)
109 mn->refcount++;
110 }
111
112 static void free_monitor_entry(struct monitor_entry *me)
113 {
114 if (!me)
115 return;
116 list_del(&me->ents);
117 if (me->fd >= 0)
118 close(me->fd);
119 free(me->path);
120 free(me);
121 }
122
123 /**
124 * mnt_unref_monitor:
125 * @mn: monitor pointer
126 *
127 * Decrements the reference counter, on zero the @mn is automatically
128 * deallocated.
129 */
130 void mnt_unref_monitor(struct libmnt_monitor *mn)
131 {
132 if (!mn)
133 return;
134
135 mn->refcount--;
136 if (mn->refcount <= 0) {
137 mnt_monitor_close_fd(mn); /* destroys all file descriptors */
138
139 while (!list_empty(&mn->ents)) {
140 struct monitor_entry *me = list_entry(mn->ents.next,
141 struct monitor_entry, ents);
142 free_monitor_entry(me);
143 }
144
145 free(mn);
146 }
147 }
148
149 static struct monitor_entry *monitor_new_entry(struct libmnt_monitor *mn)
150 {
151 struct monitor_entry *me;
152
153 assert(mn);
154
155 me = calloc(1, sizeof(*me));
156 if (!me)
157 return NULL;
158 INIT_LIST_HEAD(&me->ents);
159 list_add_tail(&me->ents, &mn->ents);
160
161 me->fd = -1;
162
163 return me;
164 }
165
166 static int monitor_next_entry(struct libmnt_monitor *mn,
167 struct libmnt_iter *itr,
168 struct monitor_entry **me)
169 {
170 int rc = 1;
171
172 assert(mn);
173 assert(itr);
174
175 if (me)
176 *me = NULL;
177
178 if (!itr->head)
179 MNT_ITER_INIT(itr, &mn->ents);
180 if (itr->p != itr->head) {
181 if (me)
182 *me = MNT_ITER_GET_ENTRY(itr, struct monitor_entry, ents);
183 MNT_ITER_ITERATE(itr);
184 rc = 0;
185 }
186
187 return rc;
188 }
189
190 /* returns entry by type */
191 static struct monitor_entry *monitor_get_entry(struct libmnt_monitor *mn, int type)
192 {
193 struct libmnt_iter itr;
194 struct monitor_entry *me;
195
196 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
197 while (monitor_next_entry(mn, &itr, &me) == 0) {
198 if (me->type == type)
199 return me;
200 }
201 return NULL;
202 }
203
204
205 /*
206 * Userspace monitor
207 */
208
209 static int userspace_monitor_close_fd(struct libmnt_monitor *mn __attribute__((__unused__)),
210 struct monitor_entry *me)
211 {
212 assert(me);
213
214 if (me->fd >= 0)
215 close(me->fd);
216 me->fd = -1;
217 return 0;
218 }
219
220 static int userspace_add_watch(struct monitor_entry *me, int *final, int *fd)
221 {
222 char *filename = NULL;
223 int wd, rc = -EINVAL;
224
225 assert(me);
226 assert(me->path);
227
228 /*
229 * libmount uses rename(2) to atomically update utab, monitor
230 * rename changes is too tricky. It seems better to monitor utab
231 * lockfile close.
232 */
233 if (asprintf(&filename, "%s.lock", me->path) <= 0) {
234 rc = -errno;
235 goto done;
236 }
237
238 /* try lock file if already exists */
239 errno = 0;
240 wd = inotify_add_watch(me->fd, filename, IN_CLOSE_NOWRITE);
241 if (wd >= 0) {
242 DBG(MONITOR, ul_debug(" added inotify watch for %s [fd=%d]", filename, wd));
243 rc = 0;
244 if (final)
245 *final = 1;
246 if (fd)
247 *fd = wd;
248 goto done;
249 } else if (errno != ENOENT) {
250 rc = -errno;
251 goto done;
252 }
253
254 while (strchr(filename, '/')) {
255 stripoff_last_component(filename);
256 if (!*filename)
257 break;
258
259 /* try directory where is the lock file */
260 errno = 0;
261 wd = inotify_add_watch(me->fd, filename, IN_CREATE|IN_ISDIR);
262 if (wd >= 0) {
263 DBG(MONITOR, ul_debug(" added inotify watch for %s [fd=%d]", filename, wd));
264 rc = 0;
265 if (fd)
266 *fd = wd;
267 break;
268 }
269
270 if (errno != ENOENT) {
271 rc = -errno;
272 break;
273 }
274 }
275 done:
276 free(filename);
277 return rc;
278 }
279
280 static int userspace_monitor_get_fd(struct libmnt_monitor *mn,
281 struct monitor_entry *me)
282 {
283 int rc;
284
285 if (!me || me->enable == 0) /* not-initialized or disabled */
286 return -EINVAL;
287 if (me->fd >= 0)
288 return me->fd; /* already initialized */
289
290 assert(me->path);
291 DBG(MONITOR, ul_debugobj(mn, " open userspace monitor for %s", me->path));
292
293 me->fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
294 if (me->fd < 0)
295 goto err;
296
297 if (userspace_add_watch(me, NULL, NULL) < 0)
298 goto err;
299
300 return me->fd;
301 err:
302 rc = -errno;
303 if (me->fd >= 0)
304 close(me->fd);
305 me->fd = -1;
306 DBG(MONITOR, ul_debugobj(mn, "failed to create userspace monitor [rc=%d]", rc));
307 return rc;
308 }
309
310 /*
311 * verify and drain inotify buffer
312 */
313 static int userspace_event_verify(struct libmnt_monitor *mn,
314 struct monitor_entry *me)
315 {
316 char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
317 int status = 0;
318
319 if (!me || me->fd < 0)
320 return 0;
321
322 DBG(MONITOR, ul_debugobj(mn, "drain and verify userspace monitor inotify"));
323
324 /* the me->fd is non-blocking */
325 do {
326 ssize_t len;
327 char *p;
328 const struct inotify_event *e;
329
330 len = read(me->fd, buf, sizeof(buf));
331 if (len < 0)
332 break;
333
334 for (p = buf; p < buf + len;
335 p += sizeof(struct inotify_event) + e->len) {
336
337 int fd = -1;
338
339 e = (const struct inotify_event *) p;
340 DBG(MONITOR, ul_debugobj(mn, " inotify event 0x%x [%s]\n", e->mask, e->len ? e->name : ""));
341
342 if (e->mask & IN_CLOSE_NOWRITE)
343 status = 1;
344 else {
345 /* event on lock file */
346 userspace_add_watch(me, &status, &fd);
347
348 if (fd != e->wd) {
349 DBG(MONITOR, ul_debugobj(mn, " removing watch [fd=%d]", e->wd));
350 inotify_rm_watch(me->fd, e->wd);
351 }
352 }
353 }
354 } while (1);
355
356 DBG(MONITOR, ul_debugobj(mn, "%s", status == 1 ? " success" : " nothing"));
357 return status;
358 }
359
360 /*
361 * userspace monitor operations
362 */
363 static const struct monitor_opers userspace_opers = {
364 .op_get_fd = userspace_monitor_get_fd,
365 .op_close_fd = userspace_monitor_close_fd,
366 .op_event_verify = userspace_event_verify
367 };
368
369 /**
370 * mnt_monitor_enable_userspace:
371 * @mn: monitor
372 * @enable: 0 or 1
373 * @filename: overwrites default
374 *
375 * Enables or disables userspace monitoring. If the userspace monitor does not
376 * exist and enable=1 then allocates new resources necessary for the monitor.
377 *
378 * If the top-level monitor has been already created (by mnt_monitor_get_fd()
379 * or mnt_monitor_wait()) then it's updated according to @enable.
380 *
381 * The @filename is used only the first time when you enable the monitor. It's
382 * impossible to have more than one userspace monitor. The recommended is to
383 * use NULL as filename.
384 *
385 * The userspace monitor is unsupported for systems with classic regular
386 * /etc/mtab file.
387 *
388 * Return: 0 on success and <0 on error
389 */
390 int mnt_monitor_enable_userspace(struct libmnt_monitor *mn, int enable, const char *filename)
391 {
392 struct monitor_entry *me;
393 int rc = 0;
394
395 if (!mn)
396 return -EINVAL;
397
398 me = monitor_get_entry(mn, MNT_MONITOR_TYPE_USERSPACE);
399 if (me) {
400 rc = monitor_modify_epoll(mn, me, enable);
401 if (!enable)
402 userspace_monitor_close_fd(mn, me);
403 return rc;
404 }
405 if (!enable)
406 return 0;
407
408 DBG(MONITOR, ul_debugobj(mn, "allocate new userspace monitor"));
409
410 if (!filename)
411 filename = mnt_get_utab_path(); /* /run/mount/utab */
412 if (!filename) {
413 DBG(MONITOR, ul_debugobj(mn, "failed to get userspace mount table path"));
414 return -EINVAL;
415 }
416
417 me = monitor_new_entry(mn);
418 if (!me)
419 goto err;
420
421 me->type = MNT_MONITOR_TYPE_USERSPACE;
422 me->opers = &userspace_opers;
423 me->events = EPOLLIN;
424 me->path = strdup(filename);
425 if (!me->path)
426 goto err;
427
428 return monitor_modify_epoll(mn, me, TRUE);
429 err:
430 rc = -errno;
431 free_monitor_entry(me);
432 DBG(MONITOR, ul_debugobj(mn, "failed to allocate userspace monitor [rc=%d]", rc));
433 return rc;
434 }
435
436
437 /*
438 * Kernel monitor
439 */
440
441 static int kernel_monitor_close_fd(struct libmnt_monitor *mn __attribute__((__unused__)),
442 struct monitor_entry *me)
443 {
444 assert(me);
445
446 if (me->fd >= 0)
447 close(me->fd);
448 me->fd = -1;
449 return 0;
450 }
451
452 static int kernel_monitor_get_fd(struct libmnt_monitor *mn,
453 struct monitor_entry *me)
454 {
455 int rc;
456
457 if (!me || me->enable == 0) /* not-initialized or disabled */
458 return -EINVAL;
459 if (me->fd >= 0)
460 return me->fd; /* already initialized */
461
462 assert(me->path);
463 DBG(MONITOR, ul_debugobj(mn, " open kernel monitor for %s", me->path));
464
465 me->fd = open(me->path, O_RDONLY|O_CLOEXEC);
466 if (me->fd < 0)
467 goto err;
468
469 return me->fd;
470 err:
471 rc = -errno;
472 DBG(MONITOR, ul_debugobj(mn, "failed to create kernel monitor [rc=%d]", rc));
473 return rc;
474 }
475
476 /*
477 * kernel monitor operations
478 */
479 static const struct monitor_opers kernel_opers = {
480 .op_get_fd = kernel_monitor_get_fd,
481 .op_close_fd = kernel_monitor_close_fd,
482 };
483
484 /**
485 * mnt_monitor_enable_kernel:
486 * @mn: monitor
487 * @enable: 0 or 1
488 *
489 * Enables or disables kernel VFS monitoring. If the monitor does not exist and
490 * enable=1 then allocates new resources necessary for the monitor.
491 *
492 * If the top-level monitor has been already created (by mnt_monitor_get_fd()
493 * or mnt_monitor_wait()) then it's updated according to @enable.
494 *
495 * Return: 0 on success and <0 on error
496 */
497 int mnt_monitor_enable_kernel(struct libmnt_monitor *mn, int enable)
498 {
499 struct monitor_entry *me;
500 int rc = 0;
501
502 if (!mn)
503 return -EINVAL;
504
505 me = monitor_get_entry(mn, MNT_MONITOR_TYPE_KERNEL);
506 if (me) {
507 rc = monitor_modify_epoll(mn, me, enable);
508 if (!enable)
509 kernel_monitor_close_fd(mn, me);
510 return rc;
511 }
512 if (!enable)
513 return 0;
514
515 DBG(MONITOR, ul_debugobj(mn, "allocate new kernel monitor"));
516
517 /* create a new entry */
518 me = monitor_new_entry(mn);
519 if (!me)
520 goto err;
521
522 /* If you want to use epoll FD in another epoll then top level
523 * epoll_wait() will drain all events from low-level FD if the
524 * low-level FD is not added with EPOLLIN. It means without EPOLLIN it
525 * it's impossible to detect which low-level FD has been active.
526 *
527 * Unfortunately, use EPOLLIN for mountinfo is tricky because in this
528 * case kernel returns events all time (we don't read from the FD).
529 * The solution is to use also edge-triggered (EPOLLET) flag, then
530 * kernel generate events on mountinfo changes only. The disadvantage is
531 * that we have to drain initial event generated by EPOLLIN after
532 * epoll_ctl(ADD). See monitor_modify_epoll().
533 */
534 me->events = EPOLLIN | EPOLLET;
535
536 me->type = MNT_MONITOR_TYPE_KERNEL;
537 me->opers = &kernel_opers;
538 me->path = strdup(_PATH_PROC_MOUNTINFO);
539 if (!me->path)
540 goto err;
541
542 return monitor_modify_epoll(mn, me, TRUE);
543 err:
544 rc = -errno;
545 free_monitor_entry(me);
546 DBG(MONITOR, ul_debugobj(mn, "failed to allocate kernel monitor [rc=%d]", rc));
547 return rc;
548 }
549
550 /*
551 * Add/Remove monitor entry to/from monitor epoll.
552 */
553 static int monitor_modify_epoll(struct libmnt_monitor *mn,
554 struct monitor_entry *me, int enable)
555 {
556 assert(mn);
557 assert(me);
558
559 me->enable = enable ? 1 : 0;
560 me->changed = 0;
561
562 if (mn->fd < 0)
563 return 0; /* no epoll, ignore request */
564
565 if (enable) {
566 struct epoll_event ev = { .events = me->events };
567 int fd = me->opers->op_get_fd(mn, me);
568
569 if (fd < 0)
570 goto err;
571
572 DBG(MONITOR, ul_debugobj(mn, " add fd=%d (for %s)", fd, me->path));
573
574 ev.data.ptr = (void *) me;
575
576 if (epoll_ctl(mn->fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
577 if (errno != EEXIST)
578 goto err;
579 }
580 if (me->events & (EPOLLIN | EPOLLET)) {
581 /* Drain initial events generated for /proc/self/mountinfo */
582 struct epoll_event events[1];
583 while (epoll_wait(mn->fd, events, 1, 0) > 0);
584 }
585 } else if (me->fd) {
586 DBG(MONITOR, ul_debugobj(mn, " remove fd=%d (for %s)", me->fd, me->path));
587 if (epoll_ctl(mn->fd, EPOLL_CTL_DEL, me->fd, NULL) < 0) {
588 if (errno != ENOENT)
589 goto err;
590 }
591 }
592
593 return 0;
594 err:
595 return -errno;
596 }
597
598 /**
599 * mnt_monitor_close_fd:
600 * @mn: monitor
601 *
602 * Close monitor file descriptor. This is usually unnecessary, because
603 * mnt_unref_monitor() cleanups all.
604 *
605 * The function is necessary only if you want to reset monitor setting. The
606 * next mnt_monitor_get_fd() or mnt_monitor_wait() will use newly initialized
607 * monitor. This restart is unnecessary for mnt_monitor_enable_*() functions.
608 *
609 * Returns: 0 on success, <0 on error.
610 */
611 int mnt_monitor_close_fd(struct libmnt_monitor *mn)
612 {
613 struct libmnt_iter itr;
614 struct monitor_entry *me;
615
616 if (!mn)
617 return -EINVAL;
618
619 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
620
621 /* disable all monitor entries */
622 while (monitor_next_entry(mn, &itr, &me) == 0) {
623
624 /* remove entry from epoll */
625 if (mn->fd >= 0)
626 monitor_modify_epoll(mn, me, FALSE);
627
628 /* close entry FD */
629 me->opers->op_close_fd(mn, me);
630 }
631
632 if (mn->fd >= 0) {
633 DBG(MONITOR, ul_debugobj(mn, "closing top-level monitor fd"));
634 close(mn->fd);
635 }
636 mn->fd = -1;
637 return 0;
638 }
639
640 /**
641 * mnt_monitor_get_fd:
642 * @mn: monitor
643 *
644 * The file descriptor is associated with all monitored files and it's usable
645 * for example for epoll. You have to call mnt_monitor_event_cleanup() or
646 * mnt_monitor_next_change() after each event.
647 *
648 * Returns: >=0 (fd) on success, <0 on error
649 */
650 int mnt_monitor_get_fd(struct libmnt_monitor *mn)
651 {
652 struct libmnt_iter itr;
653 struct monitor_entry *me;
654 int rc = 0;
655
656 if (!mn)
657 return -EINVAL;
658 if (mn->fd >= 0)
659 return mn->fd;
660
661 DBG(MONITOR, ul_debugobj(mn, "create top-level monitor fd"));
662 mn->fd = epoll_create1(EPOLL_CLOEXEC);
663 if (mn->fd < 0)
664 return -errno;
665
666 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
667
668 DBG(MONITOR, ul_debugobj(mn, "adding monitor entries to epoll (fd=%d)", mn->fd));
669 while (monitor_next_entry(mn, &itr, &me) == 0) {
670 if (!me->enable)
671 continue;
672 rc = monitor_modify_epoll(mn, me, TRUE);
673 if (rc)
674 goto err;
675 }
676
677 DBG(MONITOR, ul_debugobj(mn, "successfully created monitor"));
678 return mn->fd;
679 err:
680 rc = errno ? -errno : -EINVAL;
681 close(mn->fd);
682 mn->fd = -1;
683 DBG(MONITOR, ul_debugobj(mn, "failed to create monitor [rc=%d]", rc));
684 return rc;
685 }
686
687 /**
688 * mnt_monitor_wait:
689 * @mn: monitor
690 * @timeout: number of milliseconds, -1 block indefinitely, 0 return immediately
691 *
692 * Waits for the next change, after the event it's recommended to use
693 * mnt_monitor_next_change() to get more details about the change and to
694 * avoid false positive events.
695 *
696 * Returns: 1 success (something changed), 0 timeout, <0 error.
697 */
698 int mnt_monitor_wait(struct libmnt_monitor *mn, int timeout)
699 {
700 int rc;
701 struct monitor_entry *me;
702 struct epoll_event events[1];
703
704 if (!mn)
705 return -EINVAL;
706
707 if (mn->fd < 0) {
708 rc = mnt_monitor_get_fd(mn);
709 if (rc < 0)
710 return rc;
711 }
712
713 do {
714 DBG(MONITOR, ul_debugobj(mn, "calling epoll_wait(), timeout=%d", timeout));
715 rc = epoll_wait(mn->fd, events, 1, timeout);
716 if (rc < 0)
717 return -errno; /* error */
718 if (rc == 0)
719 return 0; /* timeout */
720
721 me = (struct monitor_entry *) events[0].data.ptr;
722 if (!me)
723 return -EINVAL;
724
725 if (me->opers->op_event_verify == NULL ||
726 me->opers->op_event_verify(mn, me) == 1) {
727 me->changed = 1;
728 break;
729 }
730 } while (1);
731
732 return 1; /* success */
733 }
734
735
736 static struct monitor_entry *get_changed(struct libmnt_monitor *mn)
737 {
738 struct libmnt_iter itr;
739 struct monitor_entry *me;
740
741 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
742 while (monitor_next_entry(mn, &itr, &me) == 0) {
743 if (me->changed)
744 return me;
745 }
746 return NULL;
747 }
748
749 /**
750 * mnt_monitor_next_change:
751 * @mn: monitor
752 * @filename: returns changed file (optional argument)
753 * @type: returns MNT_MONITOR_TYPE_* (optional argument)
754 *
755 * The function does not wait and it's designed to provide details about changes.
756 * It's always recommended to use this function to avoid false positives.
757 *
758 * Returns: 0 on success, 1 no change, <0 on error
759 */
760 int mnt_monitor_next_change(struct libmnt_monitor *mn,
761 const char **filename,
762 int *type)
763 {
764 int rc;
765 struct monitor_entry *me;
766
767 if (!mn || mn->fd < 0)
768 return -EINVAL;
769
770 /*
771 * if we previously called epoll_wait() (e.g. mnt_monitor_wait()) then
772 * info about unread change is already stored in monitor_entry.
773 *
774 * If we get nothing, then ask kernel.
775 */
776 me = get_changed(mn);
777 while (!me) {
778 struct epoll_event events[1];
779
780 DBG(MONITOR, ul_debugobj(mn, "asking for next changed"));
781
782 rc = epoll_wait(mn->fd, events, 1, 0); /* no timeout! */
783 if (rc < 0) {
784 DBG(MONITOR, ul_debugobj(mn, " *** error"));
785 return -errno;
786 }
787 if (rc == 0) {
788 DBG(MONITOR, ul_debugobj(mn, " *** nothing"));
789 return 1;
790 }
791
792 me = (struct monitor_entry *) events[0].data.ptr;
793 if (!me)
794 return -EINVAL;
795
796 if (me->opers->op_event_verify != NULL &&
797 me->opers->op_event_verify(mn, me) != 1)
798 me = NULL;
799 }
800
801 me->changed = 0;
802
803 if (filename)
804 *filename = me->path;
805 if (type)
806 *type = me->type;
807
808 DBG(MONITOR, ul_debugobj(mn, " *** success [changed: %s]", me->path));
809 return 0;
810 }
811
812 /**
813 * mnt_monitor_event_cleanup:
814 * @mn: monitor
815 *
816 * This function cleanups (drain) internal buffers. It's necessary to call
817 * this function after event if you do not call mnt_monitor_next_change().
818 *
819 * Returns: 0 on success, <0 on error
820 */
821 int mnt_monitor_event_cleanup(struct libmnt_monitor *mn)
822 {
823 int rc;
824
825 if (!mn || mn->fd < 0)
826 return -EINVAL;
827
828 while ((rc = mnt_monitor_next_change(mn, NULL, NULL)) == 0);
829 return rc < 0 ? rc : 0;
830 }
831
832 #ifdef TEST_PROGRAM
833
834 static struct libmnt_monitor *create_test_monitor(int argc, char *argv[])
835 {
836 struct libmnt_monitor *mn;
837 int i;
838
839 mn = mnt_new_monitor();
840 if (!mn) {
841 warn("failed to allocate monitor");
842 goto err;
843 }
844
845 for (i = 1; i < argc; i++) {
846 if (strcmp(argv[i], "userspace") == 0) {
847 if (mnt_monitor_enable_userspace(mn, TRUE, NULL)) {
848 warn("failed to initialize userspace monitor");
849 goto err;
850 }
851
852 } else if (strcmp(argv[i], "kernel") == 0) {
853 if (mnt_monitor_enable_kernel(mn, TRUE)) {
854 warn("failed to initialize kernel monitor");
855 goto err;
856 }
857 }
858 }
859 if (i == 1) {
860 warnx("No monitor type specified");
861 goto err;
862 }
863
864 return mn;
865 err:
866 mnt_unref_monitor(mn);
867 return NULL;
868 }
869
870 /*
871 * create a monitor and add the monitor fd to epoll
872 */
873 static int __test_epoll(struct libmnt_test *ts, int argc, char *argv[], int cleanup)
874 {
875 int fd, efd = -1, rc = -1;
876 struct epoll_event ev;
877 struct libmnt_monitor *mn = create_test_monitor(argc, argv);
878
879 if (!mn)
880 return -1;
881
882 fd = mnt_monitor_get_fd(mn);
883 if (fd < 0) {
884 warn("failed to initialize monitor fd");
885 goto done;
886 }
887
888 efd = epoll_create1(EPOLL_CLOEXEC);
889 if (efd < 0) {
890 warn("failed to create epoll");
891 goto done;
892 }
893
894 ev.events = EPOLLIN;
895 ev.data.fd = fd;
896
897 rc = epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ev);
898 if (rc < 0) {
899 warn("failed to add fd to epoll");
900 goto done;
901 }
902
903 printf("waiting for changes...\n");
904 do {
905 const char *filename = NULL;
906 struct epoll_event events[1];
907 int n = epoll_wait(efd, events, 1, -1);
908
909 if (n < 0) {
910 rc = -errno;
911 warn("polling error");
912 goto done;
913 }
914 if (n == 0 || events[0].data.fd != fd)
915 continue;
916
917 printf(" top-level FD active\n");
918 if (cleanup)
919 mnt_monitor_event_cleanup(mn);
920 else {
921 while (mnt_monitor_next_change(mn, &filename, NULL) == 0)
922 printf(" %s: change detected\n", filename);
923 }
924 } while (1);
925
926 rc = 0;
927 done:
928 if (efd >= 0)
929 close(efd);
930 mnt_unref_monitor(mn);
931 return rc;
932 }
933
934 /*
935 * create a monitor and add the monitor fd to epoll
936 */
937 static int test_epoll(struct libmnt_test *ts, int argc, char *argv[])
938 {
939 return __test_epoll(ts, argc, argv, 0);
940 }
941
942 static int test_epoll_cleanup(struct libmnt_test *ts, int argc, char *argv[])
943 {
944 return __test_epoll(ts, argc, argv, 1);
945 }
946
947 /*
948 * create a monitor and wait for a change
949 */
950 static int test_wait(struct libmnt_test *ts, int argc, char *argv[])
951 {
952 const char *filename;
953 struct libmnt_monitor *mn = create_test_monitor(argc, argv);
954
955 if (!mn)
956 return -1;
957
958 printf("waiting for changes...\n");
959 while (mnt_monitor_wait(mn, -1) > 0) {
960 printf("notification detected\n");
961
962 while (mnt_monitor_next_change(mn, &filename, NULL) == 0)
963 printf(" %s: change detected\n", filename);
964
965 }
966 mnt_unref_monitor(mn);
967 return 0;
968 }
969
970 int main(int argc, char *argv[])
971 {
972 struct libmnt_test tss[] = {
973 { "--epoll", test_epoll, "<userspace kernel ...> monitor in epoll" },
974 { "--epoll-clean", test_epoll_cleanup, "<userspace kernel ...> monitor in epoll and clean events" },
975 { "--wait", test_wait, "<userspace kernel ...> monitor wait function" },
976 { NULL }
977 };
978
979 return mnt_run_test(tss, argc, argv);
980 }
981
982 #endif /* TEST_PROGRAM */