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