Browse Source

Sync with gnulib 3ea43e02541ece750ffc6cd1dfe34195421b4ef3.

mountlist: use /proc/self/mountinfo when available

Use libmount to propagate device IDs provided by Linux in
/proc/self/mountinfo.  This will give more accurate output when using df
in chroot'ed environments as the device IDs are not determined by stat()
which may be inaccurate within the chroot.

Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
Andrew Borodin 10 years ago
parent
commit
12fac096ed
2 changed files with 76 additions and 20 deletions
  1. 13 0
      m4.include/ls-mntd-fs.m4
  2. 63 20
      src/filemanager/mountlist.c

+ 13 - 0
m4.include/ls-mntd-fs.m4

@@ -152,6 +152,19 @@ if test $ac_cv_func_getmntent = yes; then
          of mounted file systems, and that function takes a single argument.
          (4.3BSD, SunOS, HP-UX, Dynix, Irix)])
       AC_CHECK_FUNCS([hasmntopt])
+
+      # Check for libmount to support /proc/self/mountinfo on Linux
+      AC_CACHE_VAL([ac_cv_lib_libmount_mnt_table_parse_stream],
+        [AC_CHECK_LIB([mount], [mnt_new_table_from_file],
+          ac_cv_lib_mount_mnt_table_parse_stream=yes,
+          ac_cv_lib_mount_mnt_table_parse_stream=no)])
+      if test $ac_cv_lib_mount_mnt_table_parse_stream = yes; then
+         AC_DEFINE([MOUNTED_PROC_MOUNTINFO], [1],
+           [Define if want to use /proc/self/mountinfo on Linux.])
+         LIBS="-lmount $LIBS"
+      elif test -f /proc/self/mountinfo; then
+         AC_MSG_WARN([/proc/self/mountinfo present but libmount is missing.])
+      fi
     fi
   fi
 

+ 63 - 20
src/filemanager/mountlist.c

@@ -157,6 +157,12 @@
 #include <sys/mntent.h>
 #endif
 
+#ifdef MOUNTED_PROC_MOUNTINFO
+/* Use /proc/self/mountinfo instead of /proc/self/mounts (/etc/mtab)
+ * on Linux, if available */
+#include <libmount/libmount.h>
+#endif
+
 #ifndef HAVE_HASMNTOPT
 #define hasmntopt(mnt, opt) ((char *) 0)
 #endif
@@ -653,32 +659,69 @@ read_file_system_list (int need_fs_type)
 
 #ifdef MOUNTED_GETMNTENT1       /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
     {
-        struct mntent *mnt;
-        const char *table = MOUNTED;
-        FILE *fp;
+#ifdef MOUNTED_PROC_MOUNTINFO
+        struct libmnt_table *fstable = NULL;
 
-        fp = setmntent (table, "r");
-        if (fp == NULL)
-            return NULL;
+        fstable = mnt_new_table_from_file ("/proc/self/mountinfo");
 
-        while ((mnt = getmntent (fp)))
+        if (fstable != NULL)
         {
-            me = g_malloc (sizeof (*me));
-            me->me_devname = g_strdup (mnt->mnt_fsname);
-            me->me_mountdir = g_strdup (mnt->mnt_dir);
-            me->me_type = g_strdup (mnt->mnt_type);
-            me->me_type_malloced = 1;
-            me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, mnt);
-            me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
-            me->me_dev = dev_from_mount_options (mnt->mnt_opts);
+            struct libmnt_fs *fs;
+            struct libmnt_iter *iter;
+
+            iter = mnt_new_iter (MNT_ITER_FORWARD);
+
+            while (iter && mnt_table_next_fs (fstable, iter, &fs) == 0)
+            {
+                me = g_malloc (sizeof *me);
+
+                me->me_devname = g_strdup (mnt_fs_get_source (fs));
+                me->me_mountdir = g_strdup (mnt_fs_get_target (fs));
+                me->me_type = g_strdup (mnt_fs_get_fstype (fs));
+                me->me_type_malloced = 1;
+                me->me_dev = mnt_fs_get_devno (fs);
+                me->me_dummy = mnt_fs_is_pseudofs (fs);
+                me->me_remote = mnt_fs_is_netfs (fs);
+
+                /* Add to the linked list. */
+                *mtail = me;
+                mtail = &me->me_next;
+            }
+
+            mnt_free_iter (iter);
+            mnt_free_table (fstable);
 
-            /* Add to the linked list. */
-            *mtail = me;
-            mtail = &me->me_next;
         }
+        else                    /* fallback to /proc/self/mounts (/etc/mtab) if anything failed */
+#endif /* MOUNTED_PROC_MOUNTINFO */
+        {
+            FILE *fp;
+            struct mntent *mnt;
+            const char *table = MOUNTED;
 
-        if (endmntent (fp) == 0)
-            goto free_then_fail;
+            fp = setmntent (table, "r");
+            if (fp == NULL)
+                return NULL;
+
+            while ((mnt = getmntent (fp)))
+            {
+                me = g_malloc (sizeof (*me));
+                me->me_devname = g_strdup (mnt->mnt_fsname);
+                me->me_mountdir = g_strdup (mnt->mnt_dir);
+                me->me_type = g_strdup (mnt->mnt_type);
+                me->me_type_malloced = 1;
+                me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, mnt);
+                me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
+                me->me_dev = dev_from_mount_options (mnt->mnt_opts);
+
+                /* Add to the linked list. */
+                *mtail = me;
+                mtail = &me->me_next;
+            }
+
+            if (endmntent (fp) == 0)
+                goto free_then_fail;
+        }
     }
 #endif /* MOUNTED_GETMNTENT1. */