[systemd-devel] [RFC] link against util-linux for fstab parsing

Dave Reisner d at falconindy.com
Fri Feb 17 13:47:51 PST 2012


Based on the premise that we shouldn't develop a case of NIH, link
against a library whose sole purpose in life is parsing tab files.
---
Curious if something like this is wanted -- it's 90% complete, but there's no
sense in finishing it up if it's not interesting. I'd like to be able to get
rid of the fstab_node_to_udev_node() function but that would likely require
linking against libblkid in cryptsetup-generator.

Worth noting:
* in mount_fix_timeouts(), i've removed the possibility of using
  'comment=systemd.device-timeout'. This option is undocumented in
  systemd.mount(5), and util-linux will not parse out the value properly.
* is that this won't compile without util-linux from git or one of
  the recent RCs as it depends on mnt_fs_is_swaparea().

 Makefile.am  |    6 ++-
 configure.ac |    1 +
 src/mount.c  |  157 +++++++++++++++++++++++++++++-----------------------------
 3 files changed, 83 insertions(+), 81 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 10c85a4..2559cde 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -493,7 +493,8 @@ libsystemd_core_la_CFLAGS = \
 	$(LIBWRAP_CFLAGS) \
 	$(PAM_CFLAGS) \
 	$(AUDIT_CFLAGS) \
-	$(KMOD_CFLAGS)
+	$(KMOD_CFLAGS) \
+	$(MOUNT_CFLAGS)
 
 libsystemd_core_la_LIBADD = \
 	libsystemd-basic.la \
@@ -503,7 +504,8 @@ libsystemd_core_la_LIBADD = \
 	$(PAM_LIBS) \
 	$(AUDIT_LIBS) \
 	$(CAP_LIBS) \
-	$(KMOD_LIBS)
+	$(KMOD_LIBS) \
+	$(MOUNT_LIBS)
 
 # This is needed because automake is buggy in how it generates the
 # rules for C programs, but not Vala programs.	We therefore can't
diff --git a/configure.ac b/configure.ac
index 62e8cdf..c8a8440 100644
--- a/configure.ac
+++ b/configure.ac
@@ -126,6 +126,7 @@ m4_pattern_forbid([^_?PKG_[A-Z_]+$],[*** pkg.m4 missing, please install pkg-conf
 PKG_CHECK_MODULES(UDEV, [ libudev >= 172 ])
 PKG_CHECK_MODULES(DBUS, [ dbus-1 >= 1.3.2 ])
 PKG_CHECK_MODULES(KMOD, [ libkmod >= 5 ])
+PKG_CHECK_MODULES(MOUNT, [ mount ])
 
 have_selinux=no
 AC_ARG_ENABLE(selinux, AS_HELP_STRING([--disable-selinux], [Disable optional SELINUX support]))
diff --git a/src/mount.c b/src/mount.c
index 5e52a54..cc675d4 100644
--- a/src/mount.c
+++ b/src/mount.c
@@ -25,6 +25,8 @@
 #include <sys/epoll.h>
 #include <signal.h>
 
+#include <libmount/libmount.h>
+
 #include "unit.h"
 #include "mount.h"
 #include "load-fragment.h"
@@ -262,27 +264,10 @@ static int mount_add_socket_links(Mount *m) {
         return 0;
 }
 
-static char* mount_test_option(const char *haystack, const char *needle) {
-        struct mntent me;
-
-        assert(needle);
-
-        /* Like glibc's hasmntopt(), but works on a string, not a
-         * struct mntent */
-
-        if (!haystack)
-                return false;
-
-        zero(me);
-        me.mnt_opts = (char*) haystack;
-
-        return hasmntopt(&me, needle);
-}
-
 static bool mount_is_network(MountParameters *p) {
         assert(p);
 
-        if (mount_test_option(p->options, "_netdev"))
+        if (mnt_match_options(p->options, "_netdev"))
                 return true;
 
         if (p->fstype && fstype_is_network(p->fstype))
@@ -294,7 +279,7 @@ static bool mount_is_network(MountParameters *p) {
 static bool mount_is_bind(MountParameters *p) {
         assert(p);
 
-        if (mount_test_option(p->options, "bind"))
+        if (mnt_match_options(p->options, "bind"))
                 return true;
 
         if (p->fstype && streq(p->fstype, "bind"))
@@ -312,11 +297,11 @@ static bool needs_quota(MountParameters *p) {
         if (mount_is_bind(p))
                 return false;
 
-        return mount_test_option(p->options, "usrquota") ||
-                mount_test_option(p->options, "grpquota") ||
-                mount_test_option(p->options, "quota") ||
-                mount_test_option(p->options, "usrjquota") ||
-                mount_test_option(p->options, "grpjquota");
+        return mnt_match_options(p->options, "usrquota") ||
+               mnt_match_options(p->options, "grpquota") ||
+               mnt_match_options(p->options, "quota") ||
+               mnt_match_options(p->options, "usrjquota") ||
+               mnt_match_options(p->options, "grpjquota");
 }
 
 static int mount_add_fstab_links(Mount *m) {
@@ -337,15 +322,15 @@ static int mount_add_fstab_links(Mount *m) {
         if (p != &m->parameters_etc_fstab)
                 return 0;
 
-        noauto = !!mount_test_option(p->options, "noauto");
-        nofail = !!mount_test_option(p->options, "nofail");
+        noauto = mnt_match_options(p->options, "+noauto");
+        nofail = mnt_match_options(p->options, "+nofail");
         automount =
-                mount_test_option(p->options, "comment=systemd.automount") ||
-                mount_test_option(p->options, "x-systemd-automount");
+                mnt_match_options(p->options, "comment=systemd.automount") ||
+                mnt_match_options(p->options, "x-systemd-automount");
         handle =
                 automount ||
-                mount_test_option(p->options, "comment=systemd.mount") ||
-                mount_test_option(p->options, "x-systemd-mount") ||
+                mnt_match_options(p->options, "comment=systemd.mount") ||
+                mnt_match_options(p->options, "x-systemd-mount") ||
                 UNIT(m)->manager->mount_auto;
 
         if (mount_is_network(p)) {
@@ -421,8 +406,8 @@ static int mount_add_device_links(Mount *m) {
             p == &m->parameters_etc_fstab) {
                 bool nofail, noauto;
 
-                noauto = !!mount_test_option(p->options, "noauto");
-                nofail = !!mount_test_option(p->options, "nofail");
+                noauto = mnt_match_options(p->options, "+noauto");
+                nofail = mnt_match_options(p->options, "+nofail");
 
                 if ((r = unit_add_node_link(UNIT(m), p->what,
                                             !noauto && nofail &&
@@ -485,6 +470,8 @@ static int mount_add_default_dependencies(Mount *m) {
 static int mount_fix_timeouts(Mount *m) {
         MountParameters *p;
         const char *timeout = NULL;
+        char *opt;
+        size_t optsz;
         Unit *other;
         Iterator i;
         usec_t u;
@@ -501,14 +488,10 @@ static int mount_fix_timeouts(Mount *m) {
          * endless device timeouts for devices that show up only after
          * user input, like crypto devices. */
 
-        if ((timeout = mount_test_option(p->options, "comment=systemd.device-timeout")))
-                timeout += 31;
-        else if ((timeout = mount_test_option(p->options, "x-systemd-device-timeout")))
-                timeout += 25;
-        else
+        if (mnt_optstr_get_option(p->options, "x-systemd-device-timeout", &opt, &optsz) != 0)
                 return 0;
 
-        t = strndup(timeout, strcspn(timeout, ",;" WHITESPACE));
+        t = strndup(timeout, optsz);
         if (!t)
                 return -ENOMEM;
 
@@ -1505,86 +1488,102 @@ fail:
         return r;
 }
 
-static int mount_find_pri(char *options) {
-        char *end, *pri;
+static int mount_find_pri(const char *options) {
+        char *opt, *end;
+        char buf[32];
+        size_t optsz;
         unsigned long r;
 
-        if (!(pri = mount_test_option(options, "pri")))
+        if (mnt_optstr_get_option(options, "pri", &opt, &optsz) != 0)
                 return 0;
 
-        pri += 4;
+        if (optsz + 1 > sizeof(buf))
+                optsz = sizeof(buf);
+
+        snprintf(buf, optsz + 1, "%s", opt);
 
         errno = 0;
-        r = strtoul(pri, &end, 10);
+        r = strtoul(buf, &end, 10);
 
         if (errno != 0)
                 return -errno;
 
-        if (end == pri || (*end != ',' && *end != 0))
+        if (end == buf || (*end != '\0'))
                 return -EINVAL;
 
         return (int) r;
 }
 
 static int mount_load_etc_fstab(Manager *m) {
-        FILE *f;
+        struct libmnt_table *tb = NULL;
+        struct libmnt_cache *mnt_cache = NULL;
+        struct libmnt_iter *itr = NULL;
+        struct libmnt_fs *fs = NULL;
         int r = 0;
-        struct mntent* me;
-
-        assert(m);
 
-        errno = 0;
-        if (!(f = setmntent("/etc/fstab", "r")))
-                return -errno;
+        tb = mnt_new_table();
+        if (!tb) {
+                return -ENOMEM;
+        }
 
-        while ((me = getmntent(f))) {
-                char *where, *what;
-                int k;
+        mnt_cache = mnt_new_cache();
+        if (!mnt_cache) {
+                r = -ENOMEM;
+                goto finish;
+        }
 
-                if (!(what = fstab_node_to_udev_node(me->mnt_fsname))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
+        mnt_table_set_cache(tb, mnt_cache);
 
-                if (!(where = strdup(me->mnt_dir))) {
-                        free(what);
-                        r = -ENOMEM;
-                        goto finish;
-                }
+        r = mnt_table_parse_fstab(tb, "/etc/fstab");
+        if (r != 0)
+                goto finish;
 
-                if (what[0] == '/')
-                        path_kill_slashes(what);
+        itr = mnt_new_iter(MNT_ITER_FORWARD);
+        if (!itr) {
+                r = -ENOMEM;
+                goto finish;
+        }
 
-                if (where[0] == '/')
-                        path_kill_slashes(where);
+        while (mnt_table_next_fs(tb, itr, &fs) == 0) {
+                int k;
+                const char *opts = mnt_fs_get_options(fs);
 
-                if (streq(me->mnt_type, "swap")) {
-                        int pri;
+                if (mnt_fs_is_swaparea(fs)) {
+                        int pri = mount_find_pri(opts);
 
-                        if ((pri = mount_find_pri(me->mnt_opts)) < 0)
+                        if (pri < 0)
                                 k = pri;
                         else
                                 k = swap_add_one(m,
-                                                 what,
+                                                 mnt_fs_get_source(fs),
                                                  NULL,
                                                  pri,
-                                                 !!mount_test_option(me->mnt_opts, "noauto"),
-                                                 !!mount_test_option(me->mnt_opts, "nofail"),
-                                                 !!mount_test_option(me->mnt_opts, "comment=systemd.swapon"),
+                                                 mnt_fs_match_options(fs, "+noauto"),
+                                                 mnt_fs_match_options(fs, "+nofail"),
+                                                 mnt_fs_match_options(fs, "comment=systemd.swapon"),
                                                  false);
                 } else
-                        k = mount_add_one(m, what, where, me->mnt_opts, me->mnt_type, me->mnt_passno, false, false);
-
-                free(what);
-                free(where);
+                        k = mount_add_one(m,
+                                          mnt_fs_get_source(fs),
+                                          mnt_fs_get_target(fs),
+                                          opts,
+                                          mnt_fs_get_fstype(fs),
+                                          mnt_fs_get_passno(fs),
+                                          false,
+                                          false);
 
                 if (k < 0)
                         r = k;
         }
 
+        mnt_free_iter(itr);
+
 finish:
+        if (tb)
+                mnt_free_table(tb);
+        if (mnt_cache)
+                mnt_free_cache(mnt_cache);
 
-        endmntent(f);
         return r;
 }
 
-- 
1.7.9.1



More information about the systemd-devel mailing list