]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: split monitor initialization
authorKarel Zak <kzak@redhat.com>
Mon, 15 Dec 2014 13:13:25 +0000 (14:13 +0100)
committerKarel Zak <kzak@redhat.com>
Tue, 6 Jan 2015 15:19:02 +0000 (16:19 +0100)
The patch introduces mnt_monitor_enable_*() functions (now for
userspace only) to make the API easy to use for high-level purpose.

Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/docs/libmount-sections.txt
libmount/src/libmount.h.in
libmount/src/libmount.sym
libmount/src/monitor.c

index 626f211086cff55e9cd05df55a79208b16441af7..3474fab583f05765ad09cb5b9e6bb2882eb67704 100644 (file)
@@ -389,8 +389,8 @@ libmnt_monitor
 mnt_new_monitor
 mnt_ref_monitor
 mnt_unref_monitor
+mnt_monitor_enable_userspace
 mnt_monitor_userspace_get_fd
-mnt_monitor_get_events
 mnt_monitor_get_filename
 mnt_monitor_is_changed
 </SECTION>
index b6e3dd308698298ec64b8f46ebae991a7c8e3ca8..db9b2542d9cb140208a667d800fb675b1badff39 100644 (file)
@@ -541,11 +541,10 @@ extern struct libmnt_monitor *mnt_new_monitor(void);
 extern void mnt_ref_monitor(struct libmnt_monitor *mn);
 extern void mnt_unref_monitor(struct libmnt_monitor *mn);
 
-extern int mnt_monitor_userspace_get_fd(struct libmnt_monitor *mn, const char *filename);
-extern int mnt_monitor_get_events(struct libmnt_monitor *mn, int fd, unsigned int *event);
-extern const char *mnt_monitor_get_filename(struct libmnt_monitor *mn, int fd);
-extern int mnt_monitor_is_changed(struct libmnt_monitor *mn, int fd);
+extern int mnt_monitor_enable_userspace(struct libmnt_monitor *mn,
+                               int enable, const char *filename);
 
+extern int mnt_monitor_userspace_get_fd(struct libmnt_monitor *mn);
 
 /* context.c */
 
index d5c4643e48122431affa1c2ee745e8d50fe10d3d..039475aaee511f4bee229bb3e67484793f9618d0 100644 (file)
@@ -299,7 +299,7 @@ MOUNT_2.25 {
 } MOUNT_2.24;
 
 MOUNT_2.26 {
-       mnt_monitor_get_events;
+       mnt_monitor_enable_userspace;
        mnt_monitor_get_filename;
        mnt_monitor_is_changed;
        mnt_monitor_userspace_get_fd;
index c043adfd04809151ddf35ce379abafce0637b098..4a0cbc53ce92d30044ced251ec41190a82c0b43c 100644 (file)
@@ -27,9 +27,10 @@ enum {
 struct monitor_entry {
        int                     fd;             /* public file descriptor */
        char                    *path;          /* path to the monitored file */
-       unsigned int            events;         /* epoll events or zero */
        int                     type;           /* MNT_MONITOR_TYPE_* */
 
+       unsigned int            enable : 1;
+
        struct list_head        ents;
 };
 
@@ -39,6 +40,9 @@ struct libmnt_monitor {
        struct list_head        ents;
 };
 
+static int monitor_enable_entry(struct libmnt_monitor *mn,
+                               struct monitor_entry *me, int enable);
+
 /**
  * mnt_new_monitor:
  *
@@ -121,56 +125,98 @@ static struct monitor_entry *monitor_new_entry(struct libmnt_monitor *mn)
         INIT_LIST_HEAD(&me->ents);
        list_add_tail(&me->ents, &mn->ents);
 
+       me->fd = -1;
+
        return me;
 }
 
+static struct monitor_entry *monitor_get_entry(struct libmnt_monitor *mn, int type)
+{
+       struct list_head *p;
+
+       assert(mn);
+       assert(type);
+
+       list_for_each(p, &mn->ents) {
+               struct monitor_entry *me;
+
+               me = list_entry(p, struct monitor_entry, ents);
+               if (me->type == type)
+                       return me;
+       }
+
+       return NULL;
+}
+
+static struct monitor_entry *monitor_get_entry_by_fd(struct libmnt_monitor *mn, int fd)
+{
+       struct list_head *p;
+
+       assert(mn);
+
+       if (fd < 0)
+               return NULL;
+
+       list_for_each(p, &mn->ents) {
+               struct monitor_entry *me;
+
+               me = list_entry(p, struct monitor_entry, ents);
+               if (me->fd == fd)
+                       return me;
+       }
+
+       DBG(MONITOR, ul_debugobj(mn, "failed to get entry for fd=%d", fd));
+       return NULL;
+}
+
+
+
 /**
- * mnt_monitor_userspace_get_fd:
- * @mn: monitor pointer
+ * mnt_monitor_enable_userspace:
+ * @mn: monitor
+ * @enable: 0 or 1
  * @filename: overwrites default
  *
- * The kernel mount tables (/proc/mounts and /proc/self/mountinfo) are possible
- * to monitor by [e]poll(). This function provides the same for userspace mount
- * table.
- *
- * The userspace mount table is originaly /etc/mtab or on systems without mtab
- * it's private libmount utab file.
+ * Enables or disables userspace monitor. If the monitor does not exist and
+ * enable=1 then allocates new resources necessary for the monitor.
  *
- * The userspace mount tables are updated by rename(2), this requires that all
- * dictionary with the mount table is monitored. Be careful on systems with
- * regular /etc (see mnt_has_regular_mtab()).
+ * If high-level monitor has been already initialized (by mnt_monitor_get_fd()
+ * or mnt_wait_monitor()) then it's updated according to @enable.
  *
- * Use mnt_monitor_userspace_get_events() to get epoll events mask (e.g
- * EPOLLIN, ...).
- * 
- * Use mnt_monitor_is_changed() to verify that events on the @fd are really
- * relevant for userspace moutn table.
+ * The @filename is used only first time when you enable the monitor. It's
+ * impossible to have more than one userspace monitor.
  *
- * If the change is detected then you can use mnt_table_parse_mtab() to parse
- * the file and mnt_diff_tables() to compare old and new version of the file.
+ * Note that the current implementation of the userspace monitor is based on
+ * inotify. On systems (libc) without inotify_init1() the function return
+ * -ENOSYS. The dependence on inotify is implemenation specific and may be
+ * changed later.
  *
- * Returns: <0 on error or file descriptor.
+ * Return: 0 on success and <0 on error
  */
-#ifdef HAVE_INOTIFY_INIT1
-int mnt_monitor_userspace_get_fd(struct libmnt_monitor *mn, const char *filename)
+int mnt_monitor_enable_userspace(struct libmnt_monitor *mn, int enable, const char *filename)
 {
        struct monitor_entry *me;
-       int rc = 0, wd;
-       char *dirname, *sep;
+       int rc = 0;
 
-       assert(mn);
+       if (!mn)
+               return -EINVAL;
+
+       me = monitor_get_entry(mn, MNT_MONITOR_TYPE_USERSPACE);
+       if (me)
+               return monitor_enable_entry(mn, me, enable);
+       if (!enable)
+               return 0;
 
+       DBG(MONITOR, ul_debugobj(mn, "allocate new userspace monitor"));
+
+       /* create a new entry */
+       if (!mnt_has_regular_mtab(&filename, NULL))     /* /etc/mtab */
+               filename = mnt_get_utab_path();         /* /run/mount/utab */
        if (!filename) {
-               if (!mnt_has_regular_mtab(&filename, NULL))     /* /etc/mtab */
-                       filename = mnt_get_utab_path();         /* /run/mount/utab */
-               if (!filename) {
-                       DBG(MONITOR, ul_debugobj(mn, "failed to get userspace mount table path"));
-                       return -EINVAL;
-               }
+               DBG(MONITOR, ul_debugobj(mn, "failed to get userspace mount table path"));
+               return -EINVAL;
        }
 
-       DBG(MONITOR, ul_debugobj(mn, "new userspace monitor for %s requested", filename));
-
        me = monitor_new_entry(mn);
        if (!me)
                goto err;
@@ -180,6 +226,39 @@ int mnt_monitor_userspace_get_fd(struct libmnt_monitor *mn, const char *filename
        if (!me->path)
                goto err;
 
+       DBG(MONITOR, ul_debugobj(mn, "allocate new userspace monitor: OK"));
+       return monitor_enable_entry(mn, me, 1);
+err:
+       rc = -errno;
+       free_monitor_entry(me);
+       return rc;
+}
+
+/**
+ * mnt_monitor_userspace_get_fd:
+ * @mn: monitor pointer
+ *
+ * Returns: file descriptor to previously enabled userspace monitor or <0 on error.
+ */
+#ifdef HAVE_INOTIFY_INIT1
+int mnt_monitor_userspace_get_fd(struct libmnt_monitor *mn)
+{
+       struct monitor_entry *me;
+       int wd, rc;
+       char *dirname, *sep;
+
+       assert(mn);
+
+       me = monitor_get_entry(mn, MNT_MONITOR_TYPE_USERSPACE);
+       if (!me || me->enable == 0)     /* not-initialized or disabled */
+               return -EINVAL;
+
+       if (me->fd >= 0)
+               return me->fd;          /* already initialized */
+
+       assert(me->path);
+       DBG(MONITOR, ul_debugobj(mn, "open userspace monitor for %s", me->path));
+
        dirname = me->path;
        sep = stripoff_last_component(dirname); /* add \0 between dir/filename */
 
@@ -206,59 +285,74 @@ int mnt_monitor_userspace_get_fd(struct libmnt_monitor *mn, const char *filename
        if (sep && sep > dirname)
                *(sep - 1) = '/';               /* set '/' back to the path */
 
-       me->events = EPOLLIN | EPOLLPRI;
-
        DBG(MONITOR, ul_debugobj(mn, "new fd=%d", me->fd));
        return me->fd;
 err:
-       rc = -errno;
-       free_monitor_entry(me);
-       return rc;
-}
-#else /* HAVE_INOTIFY_INIT1 */
-int mnt_monitor_userspace_get_fd(struct libmnt_monitor *mn __attribute__((unused)),
-                               const char *filename  __attribute__((unused)))
-{
-       return -ENOSYS;
+       return -errno;
 }
-#endif
 
-static struct monitor_entry *get_monitor_entry(struct libmnt_monitor *mn, int fd)
+static int monitor_userspace_is_changed(struct libmnt_monitor *mn,
+                                       struct monitor_entry *me)
 {
-       struct list_head *p;
+       char wanted[NAME_MAX + 1];
+       char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
+       struct inotify_event *event;
+       char *p;
+       ssize_t r;
+       int rc = 0;
 
-       assert(mn);
+       DBG(MONITOR, ul_debugobj(mn, "checking fd=%d for userspace changes", me->fd));
 
-       if (fd < 0)
-               return NULL;
+       p = strrchr(me->path, '/');
+       if (!p)
+               p = me->path;
+       else
+               p++;
+       strncpy(wanted, p, sizeof(wanted) - 1);
+       wanted[sizeof(wanted) - 1] = '\0';
+       rc = 0;
 
-       list_for_each(p, &mn->ents) {
-               struct monitor_entry *me;
+       DBG(MONITOR, ul_debugobj(mn, "wanted file: '%s'", wanted));
 
-               me = list_entry(p, struct monitor_entry, ents);
-               if (me->fd == fd)
-                       return me;
+       while ((r = read(me->fd, buf, sizeof(buf))) > 0) {
+               for (p = buf; p < buf + r; ) {
+                       event = (struct inotify_event *) p;
+
+                       if (strcmp(event->name, wanted) == 0)
+                               rc = 1;
+                       p += sizeof(struct inotify_event) + event->len;
+               }
+               if (rc)
+                       break;
        }
 
-       DBG(MONITOR, ul_debugobj(mn, "failed to get entry for fd=%d", fd));
-       return NULL;
+       return rc;
 }
 
-/**
- * mnt_monitor_get_events:
- * @mn: monitor
- * @fd: event file descriptor
- * @event: returns epoll event mask
- *
- * Returns: on on success, <0 on error.
- */
-int mnt_monitor_get_events(struct libmnt_monitor *mn, int fd, unsigned int *event)
+#else /* HAVE_INOTIFY_INIT1 */
+int mnt_monitor_enable_userspace(
+               struct libmnt_monitor *mn  __attribute__((unused)),
+               int enable  __attribute__((unused)),
+               const char *filename  __attribute__((unused)))
+{
+       return -ENOSYS;
+}
+int mnt_monitor_userspace_get_fd(
+               struct libmnt_monitor *mn __attribute__((unused)))
+{
+       return -ENOSYS;
+}
+#endif
+
+static int monitor_enable_entry(struct libmnt_monitor *mn,
+                               struct monitor_entry *me, int enable)
 {
-       struct monitor_entry *me = get_monitor_entry(mn, fd);
+       assert(mn);
+       assert(me);
 
-       if (!me || !event)
-               return -EINVAL;
-       *event = me->events;
+       me->enable = enable ? 1 : 0;
+
+       /* TODO : remove / add me->fd to high-level*/
        return 0;
 }
 
@@ -271,7 +365,7 @@ int mnt_monitor_get_events(struct libmnt_monitor *mn, int fd, unsigned int *even
  */
 const char *mnt_monitor_get_filename(struct libmnt_monitor *mn, int fd)
 {
-       struct monitor_entry *me = get_monitor_entry(mn, fd);
+       struct monitor_entry *me = monitor_get_entry_by_fd(mn, fd);
 
        if (!me)
                return NULL;
@@ -287,50 +381,16 @@ const char *mnt_monitor_get_filename(struct libmnt_monitor *mn, int fd)
  */
 int mnt_monitor_is_changed(struct libmnt_monitor *mn, int fd)
 {
-       struct monitor_entry *me = get_monitor_entry(mn, fd);
+       struct monitor_entry *me = monitor_get_entry_by_fd(mn, fd);
        int rc = 0;
 
        if (!me)
                return 0;
 
-
        switch (me->type) {
-#ifdef HAVE_INOTIFY_INIT1
        case MNT_MONITOR_TYPE_USERSPACE:
-       {
-               char wanted[NAME_MAX + 1];
-               char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
-               struct inotify_event *event;
-                char *p;
-               ssize_t r;
-
-               DBG(MONITOR, ul_debugobj(mn, "checking fd=%d for userspace changes", me->fd));
-
-               p = strrchr(me->path, '/');
-               if (!p)
-                       p = me->path;
-               else
-                       p++;
-               strncpy(wanted, p, sizeof(wanted) - 1);
-               wanted[sizeof(wanted) - 1] = '\0';
-               rc = 0;
-
-               DBG(MONITOR, ul_debugobj(mn, "wanted file: '%s'", wanted));
-
-                while ((r = read(me->fd, buf, sizeof(buf))) > 0) {
-                       for (p = buf; p < buf + r; ) {
-                               event = (struct inotify_event *) p;
-
-                               if (strcmp(event->name, wanted) == 0)
-                                       rc = 1;
-                               p += sizeof(struct inotify_event) + event->len;
-                        }
-                       if (rc)
-                               break;
-                }
+               rc = monitor_userspace_is_changed(mn, me);
                break;
-       }
-#endif
        default:
                return 0;
        }
@@ -354,10 +414,14 @@ int test_monitor(struct libmnt_test *ts, int argc, char *argv[])
                goto done;
        }
 
-       /* monitor userspace mount table changes */
-       fd = mnt_monitor_userspace_get_fd(mn, NULL);
+       if (mnt_monitor_enable_userspace(mn, TRUE, NULL)) {
+               warn("failed to initialize userspace monitor");
+               goto done;
+       }
+
+       fd = mnt_monitor_userspace_get_fd(mn);
        if (fd < 0) {
-               warn("failed to initialize userspace mount table fd");
+               warn("failed to initialize userspace monitor fd");
                goto done;
        }
 
@@ -367,7 +431,7 @@ int test_monitor(struct libmnt_test *ts, int argc, char *argv[])
                goto done;
        }
 
-       mnt_monitor_get_events(mn, fd, &ev.events);
+       ev.events = EPOLLPRI | EPOLLIN;
 
        /* set data is necessary only if you want to use epoll for more file
         * descriptors, then epoll_wait() returns data associated with the file
@@ -411,7 +475,7 @@ done:
 int main(int argc, char *argv[])
 {
        struct libmnt_test tss[] = {
-               { "--monitor", test_monitor, "print change" },
+               { "--low-userspace", test_monitor, "tests low-level userspace monitor" },
                { NULL }
        };