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