Blob Blame History Raw
From e82cfd53cfd127e5877aefa5ea1d50bfe71d1788 Mon Sep 17 00:00:00 2001
From: Fridolin Pokorny <fpokorny@redhat.com>
Date: Wed, 27 Aug 2014 15:25:30 +0200
Subject: [PATCH 1/9] 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.

* lib/mountlist.c (read_file_system_list): Use the libmount routines
from util-linux to parse "/proc/self/mountinfo" or fall back to
standard getmntent() processing.
* m4/ls-mntd-fs.m4: Check for libmount only when 1-argument
getmntent() is used, as is the case on GNU/Linux.
* DEPENDENCIES: Mention the optional util-linux dependency.

Upstream-commit: 3ea43e02541ece750ffc6cd1dfe34195421b4ef3
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/mountlist.c  | 82 ++++++++++++++++++++++++++++++++++++------------
 m4/ls-mntd-fs.m4 | 15 ++++++++-
 2 files changed, 76 insertions(+), 21 deletions(-)

diff --git a/lib/mountlist.c b/lib/mountlist.c
index 17779f6..617fa88 100644
--- a/lib/mountlist.c
+++ b/lib/mountlist.c
@@ -128,6 +128,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
@@ -430,32 +436,68 @@ read_file_system_list (bool need_fs_type)
 
 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
   {
-    struct mntent *mnt;
-    char const *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 = xmalloc (sizeof *me);
-        me->me_devname = xstrdup (mnt->mnt_fsname);
-        me->me_mountdir = xstrdup (mnt->mnt_dir);
-        me->me_type = xstrdup (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;
 
-        /* Add to the linked list. */
-        *mtail = me;
-        mtail = &me->me_next;
+        iter = mnt_new_iter (MNT_ITER_FORWARD);
+
+        while (iter && mnt_table_next_fs (fstable, iter, &fs) == 0)
+          {
+            me = xmalloc (sizeof *me);
+
+            me->me_devname = xstrdup (mnt_fs_get_source (fs));
+            me->me_mountdir = xstrdup (mnt_fs_get_target (fs));
+            me->me_type = xstrdup (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);
       }
+    else /* fallback to /proc/self/mounts (/etc/mtab) if anything failed */
+#endif /* MOUNTED_PROC_MOUNTINFO */
+      {
+        FILE * fp;
+        struct mntent *mnt;
+        char const *table = MOUNTED;
 
-    if (endmntent (fp) == 0)
-      goto free_then_fail;
+        fp = setmntent (table, "r");
+        if (fp == NULL)
+          return NULL;
+
+        while ((mnt = getmntent (fp)))
+          {
+            me = xmalloc (sizeof *me);
+            me->me_devname = xstrdup (mnt->mnt_fsname);
+            me->me_mountdir = xstrdup (mnt->mnt_dir);
+            me->me_type = xstrdup (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. */
 
diff --git a/m4/ls-mntd-fs.m4 b/m4/ls-mntd-fs.m4
index fb116c8..bc5ed82 100644
--- a/m4/ls-mntd-fs.m4
+++ b/m4/ls-mntd-fs.m4
@@ -1,4 +1,4 @@
-# serial 30
+# serial 31
 # How to list mounted file systems.
 
 # Copyright (C) 1998-2004, 2006, 2009-2013 Free Software Foundation, Inc.
@@ -168,6 +168,19 @@ if test $ac_cv_func_getmntent = yes; then
         [Define if there is a function named getmntent for reading the list of
          mounted file systems, and that function takes two arguments.  (SVR4)])
       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
 
-- 
2.17.2


From 7e5e39933b60761dbd5ad1b0e2d8c075d72ef322 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <P@draigBrady.com>
Date: Thu, 30 Oct 2014 04:08:50 +0000
Subject: [PATCH 2/9] mountlist: don't use libmount to decide on dummy/remote

* lib/mountlist.c (read_file_system_list): Don't use the libmount
routines to determine whether a file system is dummy or remote,
as they're not currently compatible.  For example the remoteness
is determined on file system type (for which the list seems incomplete),
rather than simply checking for a ':' in the device name.
Also libmount currently determines that 'tmpfs' is a dummy file system
even though it has associated storage.

Upstream-commit: 2768ceb7994506e2cfba88be3b6bd13ef5440a90
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/mountlist.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/lib/mountlist.c b/lib/mountlist.c
index 617fa88..b01846c 100644
--- a/lib/mountlist.c
+++ b/lib/mountlist.c
@@ -182,10 +182,9 @@
    we grant an exception to any with "bind" in its list of mount options.
    I.e., those are *not* dummy entries.  */
 #ifdef MOUNTED_GETMNTENT1
-# define ME_DUMMY(Fs_name, Fs_type, Fs_ent)	\
+# define ME_DUMMY(Fs_name, Fs_type, Bind)	\
   (ME_DUMMY_0 (Fs_name, Fs_type)		\
-   || (strcmp (Fs_type, "none") == 0		\
-       && !hasmntopt (Fs_ent, "bind")))
+   || (strcmp (Fs_type, "none") == 0 && !Bind))
 #else
 # define ME_DUMMY(Fs_name, Fs_type)		\
   (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
@@ -457,8 +456,14 @@ read_file_system_list (bool need_fs_type)
             me->me_type = xstrdup (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);
+            /* Note we don't use mnt_fs_is_pseudofs() or mnt_fs_is_netfs() here
+               as libmount's classification is non-compatible currently.
+               Also we pass "false" for the "Bind" option as that's only
+               significant when the Fs_type is "none" which will not be
+               the case when parsing "/proc/self/mountinfo", and only
+               applies for static /etc/mtab files.  */
+            me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, false);
+            me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
 
             /* Add to the linked list. */
             *mtail = me;
@@ -481,12 +486,14 @@ read_file_system_list (bool need_fs_type)
 
         while ((mnt = getmntent (fp)))
           {
+            bool bind = hasmntopt (mnt, "bind");
+
             me = xmalloc (sizeof *me);
             me->me_devname = xstrdup (mnt->mnt_fsname);
             me->me_mountdir = xstrdup (mnt->mnt_dir);
             me->me_type = xstrdup (mnt->mnt_type);
             me->me_type_malloced = 1;
-            me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, mnt);
+            me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, bind);
             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
             me->me_dev = dev_from_mount_options (mnt->mnt_opts);
 
-- 
2.17.2


From e51d88d267c5222ed2bd852bc4701dfe87d8360a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <P@draigBrady.com>
Date: Thu, 2 Apr 2015 04:18:02 +0100
Subject: [PATCH 3/9] mountlist: remove dependency on libmount

* lib/mountlist.c (read_file_system_list): Parse /proc/self/mountinfo
directly, rather than depending on libmount, which has many
dependencies due to its dependence on libselinux, as detailed at:
http://lists.gnu.org/archive/html/bug-gnulib/2015-01/msg00063.html
Note we restrict this to __linux__ as that's probably where this
interface will remain.  If ever porting, it would be best
to first pull the makedev() wrapper from coreutils to a gnulib module.
Note also we don't add a getline dependency to the mountlist module,
as all Linux versions are sufficient.

Upstream-commit: 3fb6e360363744462ce15c381f0b116c6fc4ce82
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/mountlist.c  | 128 ++++++++++++++++++++++++++++++++++++-----------
 m4/ls-mntd-fs.m4 |  17 +------
 2 files changed, 102 insertions(+), 43 deletions(-)

diff --git a/lib/mountlist.c b/lib/mountlist.c
index b01846c..2dbb245 100644
--- a/lib/mountlist.c
+++ b/lib/mountlist.c
@@ -58,6 +58,7 @@
 
 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
 # include <mntent.h>
+# include <sys/types.h>
 # if !defined MOUNTED
 #  if defined _PATH_MOUNTED     /* GNU libc  */
 #   define MOUNTED _PATH_MOUNTED
@@ -128,12 +129,6 @@
 # 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
@@ -389,6 +384,34 @@ dev_from_mount_options (char const *mount_options)
 
 #endif
 
+#if defined MOUNTED_GETMNTENT1 && defined __linux__
+
+/* Unescape the paths in mount tables.
+   STR is updated in place.  */
+
+static void
+unescape_tab (char *str)
+{
+  size_t i, j = 0;
+  size_t len = strlen (str) + 1;
+  for (i = 0; i < len; i++)
+    {
+      if (str[i] == '\\' && (i + 4 < len)
+          && str[i + 1] >= '0' && str[i + 1] <= '3'
+          && str[i + 2] >= '0' && str[i + 2] <= '7'
+          && str[i + 3] >= '0' && str[i + 3] <= '7')
+        {
+          str[j++] = (str[i + 1] - '0') * 64 +
+                     (str[i + 2] - '0') * 8 +
+                     (str[i + 3] - '0');
+          i += 3;
+        }
+      else
+        str[j++] = str[i];
+    }
+}
+#endif
+
 /* Return a list of the currently mounted file systems, or NULL on error.
    Add each entry to the tail of the list so that they stay in order.
    If NEED_FS_TYPE is true, ensure that the file system type fields in
@@ -435,30 +458,70 @@ read_file_system_list (bool need_fs_type)
 
 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
   {
-#ifdef MOUNTED_PROC_MOUNTINFO
-    struct libmnt_table *fstable = NULL;
-
-    fstable = mnt_new_table_from_file ("/proc/self/mountinfo");
+    FILE *fp;
 
-    if (fstable != NULL)
+#ifdef __linux__
+    /* Try parsing mountinfo first, as that make device IDs available.
+       Note we could use libmount routines to simplify this parsing a little
+       (and that code is in previous versions of this function), however
+       libmount depends on libselinux which pulls in many dependencies.  */
+    char const *mountinfo = "/proc/self/mountinfo";
+    fp = fopen (mountinfo, "r");
+    if (fp != NULL)
       {
-        struct libmnt_fs *fs;
-        struct libmnt_iter *iter;
+        char *line = NULL;
+        size_t buf_size = 0;
 
-        iter = mnt_new_iter (MNT_ITER_FORWARD);
-
-        while (iter && mnt_table_next_fs (fstable, iter, &fs) == 0)
+        while (getline (&line, &buf_size, fp) != -1)
           {
+            unsigned int devmaj, devmin;
+            int target_s, target_e, type_s, type_e, source_s, source_e;
+            char test;
+            char *dash;
+            int rc;
+
+            rc = sscanf(line, "%*u "        /* id - discarded  */
+                              "%*u "        /* parent - discarded */
+                              "%u:%u "      /* dev major:minor  */
+                              "%*s "        /* mountroot - discarded  */
+                              "%n%*s%n"     /* target, start and end  */
+                              "%c",         /* more data...  */
+                              &devmaj, &devmin,
+                              &target_s, &target_e,
+                              &test);
+            if (rc != 3 && rc != 5)  /* 5 if %n included in count.  */
+              continue;
+
+            /* skip optional fields, terminated by " - "  */
+            dash = strstr (line + target_e, " - ");
+            if (! dash)
+              continue;
+
+            rc = sscanf(dash, " - "
+                              "%n%*s%n "    /* FS type, start and end  */
+                              "%n%*s%n "    /* source, start and end  */
+                              "%c",         /* more data...  */
+                              &type_s, &type_e,
+                              &source_s, &source_e,
+                              &test);
+            if (rc != 1 && rc != 5)  /* 5 if %n included in count.  */
+              continue;
+
+            /* manipulate the sub-strings in place.  */
+            line[target_e] = '\0';
+            dash[type_e] = '\0';
+            dash[source_e] = '\0';
+            unescape_tab (dash + source_s);
+            unescape_tab (line + target_s);
+
             me = xmalloc (sizeof *me);
 
-            me->me_devname = xstrdup (mnt_fs_get_source (fs));
-            me->me_mountdir = xstrdup (mnt_fs_get_target (fs));
-            me->me_type = xstrdup (mnt_fs_get_fstype (fs));
+            me->me_devname = xstrdup (dash + source_s);
+            me->me_mountdir = xstrdup (line + target_s);
+            me->me_type = xstrdup (dash + type_s);
             me->me_type_malloced = 1;
-            me->me_dev = mnt_fs_get_devno (fs);
-            /* Note we don't use mnt_fs_is_pseudofs() or mnt_fs_is_netfs() here
-               as libmount's classification is non-compatible currently.
-               Also we pass "false" for the "Bind" option as that's only
+            me->me_dev = makedev (devmaj, devmin);
+            /* we pass "false" for the "Bind" option as that's only
                significant when the Fs_type is "none" which will not be
                the case when parsing "/proc/self/mountinfo", and only
                applies for static /etc/mtab files.  */
@@ -470,13 +533,22 @@ read_file_system_list (bool need_fs_type)
             mtail = &me->me_next;
           }
 
-        mnt_free_iter (iter);
-        mnt_free_table (fstable);
+        free (line);
+
+        if (ferror (fp))
+          {
+            int saved_errno = errno;
+            fclose (fp);
+            errno = saved_errno;
+            goto free_then_fail;
+          }
+
+        if (fclose (fp) == EOF)
+          goto free_then_fail;
       }
-    else /* fallback to /proc/self/mounts (/etc/mtab) if anything failed */
-#endif /* MOUNTED_PROC_MOUNTINFO */
+    else /* fallback to /proc/self/mounts (/etc/mtab).  */
+#endif /* __linux __ */
       {
-        FILE * fp;
         struct mntent *mnt;
         char const *table = MOUNTED;
 
diff --git a/m4/ls-mntd-fs.m4 b/m4/ls-mntd-fs.m4
index bc5ed82..412fbfc 100644
--- a/m4/ls-mntd-fs.m4
+++ b/m4/ls-mntd-fs.m4
@@ -1,4 +1,4 @@
-# serial 31
+# serial 32
 # How to list mounted file systems.
 
 # Copyright (C) 1998-2004, 2006, 2009-2013 Free Software Foundation, Inc.
@@ -120,7 +120,7 @@ if test $ac_cv_func_getmntent = yes; then
   # Determine whether it's the one-argument variant or the two-argument one.
 
   if test -z "$ac_list_mounted_fs"; then
-    # 4.3BSD, SunOS, HP-UX, Dynix, Irix
+    # GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix
     AC_MSG_CHECKING([for one-argument getmntent function])
     AC_CACHE_VAL([fu_cv_sys_mounted_getmntent1],
                  [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
@@ -168,19 +168,6 @@ if test $ac_cv_func_getmntent = yes; then
         [Define if there is a function named getmntent for reading the list of
          mounted file systems, and that function takes two arguments.  (SVR4)])
       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
 
-- 
2.17.2


From a6a7c39b36699fdbbb57679f2f71fc3ae08e8ba2 Mon Sep 17 00:00:00 2001
From: Dave Chiluk <chiluk@canonical.com>
Date: Mon, 31 Aug 2015 16:07:58 -0500
Subject: [PATCH 4/9] mountlist: add me_mntroot field on Linux machines

* lib/mountlist.c (read_file_system_list): Populate me_mntroot in
mount_entry so Linux machines based on /proc/self/mountinfo can
distinguish between bind mounts and original mounts.  In reality bind
mounts aren't treated differently than mountroot=/ mounts by the
kernel, but the user often wants these bind mounts distinguished.
* lib/mountlist.h (struct mount_entry): Add me_mntroot element.
More details at https://pad.lv/1432871

Upstream-commit: c6148bca89e9465fd6ba3a10d273ec4cb58c2dbe
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/mountlist.c | 25 ++++++++++++++++++++++---
 lib/mountlist.h |  2 ++
 2 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/lib/mountlist.c b/lib/mountlist.c
index 2dbb245..f4d285a 100644
--- a/lib/mountlist.c
+++ b/lib/mountlist.c
@@ -444,6 +444,7 @@ read_file_system_list (bool need_fs_type)
         me = xmalloc (sizeof *me);
         me->me_devname = xstrdup (mnt->mnt_fsname);
         me->me_mountdir = xstrdup (mnt->mnt_dir);
+        me->me_mntroot = NULL;
         me->me_type = xstrdup (mnt->mnt_type);
         me->me_type_malloced = 1;
         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
@@ -475,7 +476,8 @@ read_file_system_list (bool need_fs_type)
         while (getline (&line, &buf_size, fp) != -1)
           {
             unsigned int devmaj, devmin;
-            int target_s, target_e, type_s, type_e, source_s, source_e;
+            int target_s, target_e, type_s, type_e;
+            int source_s, source_e, mntroot_s, mntroot_e;
             char test;
             char *dash;
             int rc;
@@ -483,13 +485,15 @@ read_file_system_list (bool need_fs_type)
             rc = sscanf(line, "%*u "        /* id - discarded  */
                               "%*u "        /* parent - discarded */
                               "%u:%u "      /* dev major:minor  */
-                              "%*s "        /* mountroot - discarded  */
+                              "%n%*s%n "    /* mountroot */
                               "%n%*s%n"     /* target, start and end  */
                               "%c",         /* more data...  */
                               &devmaj, &devmin,
+                              &mntroot_s, &mntroot_e,
                               &target_s, &target_e,
                               &test);
-            if (rc != 3 && rc != 5)  /* 5 if %n included in count.  */
+
+            if (rc != 3 && rc != 7)  /* 7 if %n included in count.  */
               continue;
 
             /* skip optional fields, terminated by " - "  */
@@ -508,16 +512,19 @@ read_file_system_list (bool need_fs_type)
               continue;
 
             /* manipulate the sub-strings in place.  */
+            line[mntroot_e] = '\0';
             line[target_e] = '\0';
             dash[type_e] = '\0';
             dash[source_e] = '\0';
             unescape_tab (dash + source_s);
             unescape_tab (line + target_s);
+            unescape_tab (line + mntroot_s);
 
             me = xmalloc (sizeof *me);
 
             me->me_devname = xstrdup (dash + source_s);
             me->me_mountdir = xstrdup (line + target_s);
+            me->me_mntroot = xstrdup (line + mntroot_s);
             me->me_type = xstrdup (dash + type_s);
             me->me_type_malloced = 1;
             me->me_dev = makedev (devmaj, devmin);
@@ -563,6 +570,7 @@ read_file_system_list (bool need_fs_type)
             me = xmalloc (sizeof *me);
             me->me_devname = xstrdup (mnt->mnt_fsname);
             me->me_mountdir = xstrdup (mnt->mnt_dir);
+            me->me_mntroot = NULL;
             me->me_type = xstrdup (mnt->mnt_type);
             me->me_type_malloced = 1;
             me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, bind);
@@ -595,6 +603,7 @@ read_file_system_list (bool need_fs_type)
         me = xmalloc (sizeof *me);
         me->me_devname = xstrdup (fsp->f_mntfromname);
         me->me_mountdir = xstrdup (fsp->f_mntonname);
+        me->me_mntroot = NULL;
         me->me_type = fs_type;
         me->me_type_malloced = 0;
         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
@@ -621,6 +630,7 @@ read_file_system_list (bool need_fs_type)
         me = xmalloc (sizeof *me);
         me->me_devname = xstrdup (fsp->f_mntfromname);
         me->me_mountdir = xstrdup (fsp->f_mntonname);
+        me->me_mntroot = NULL;
         me->me_type = xstrdup (fsp->f_fstypename);
         me->me_type_malloced = 1;
         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
@@ -647,6 +657,7 @@ read_file_system_list (bool need_fs_type)
         me = xmalloc (sizeof *me);
         me->me_devname = xstrdup (fsd.fd_req.devname);
         me->me_mountdir = xstrdup (fsd.fd_req.path);
+        me->me_mntroot = NULL;
         me->me_type = gt_names[fsd.fd_req.fstype];
         me->me_type_malloced = 0;
         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
@@ -745,6 +756,7 @@ read_file_system_list (bool need_fs_type)
           me->me_devname = xstrdup (fi.device_name[0] != '\0'
                                     ? fi.device_name : fi.fsh_name);
           me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
+          me->me_mntroot = NULL;
           me->me_type = xstrdup (fi.fsh_name);
           me->me_type_malloced = 1;
           me->me_dev = fi.dev;
@@ -794,6 +806,7 @@ read_file_system_list (bool need_fs_type)
         me = xmalloc (sizeof *me);
         me->me_devname = xstrdup (stats[counter].f_mntfromname);
         me->me_mountdir = xstrdup (stats[counter].f_mntonname);
+        me->me_mntroot = NULL;
         me->me_type = xstrdup (FS_TYPE (stats[counter]));
         me->me_type_malloced = 1;
         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
@@ -830,6 +843,7 @@ read_file_system_list (bool need_fs_type)
         strcpy (me->me_devname + 5, mnt.mt_dev);
 # endif
         me->me_mountdir = xstrdup (mnt.mt_filsys);
+        me->me_mntroot = NULL;
         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
         me->me_type = "";
         me->me_type_malloced = 0;
@@ -877,6 +891,7 @@ read_file_system_list (bool need_fs_type)
         me = xmalloc (sizeof *me);
         me->me_devname = xstrdup ((*ent)->mt_resource);
         me->me_mountdir = xstrdup ((*ent)->mt_directory);
+        me->me_mntroot = NULL;
         me->me_type = xstrdup ((*ent)->mt_fstype);
         me->me_type_malloced = 1;
         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
@@ -939,6 +954,7 @@ read_file_system_list (bool need_fs_type)
             me = xmalloc (sizeof *me);
             me->me_devname = xstrdup (mnt.mnt_special);
             me->me_mountdir = xstrdup (mnt.mnt_mountp);
+            me->me_mntroot = NULL;
             me->me_type = xstrdup (mnt.mnt_fstype);
             me->me_type_malloced = 1;
             me->me_dummy = MNT_IGNORE (&mnt) != 0;
@@ -1015,6 +1031,7 @@ read_file_system_list (bool need_fs_type)
                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
           }
         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
+        me->me_mntroot = NULL;
         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
         me->me_type_malloced = 1;
         options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
@@ -1058,6 +1075,7 @@ read_file_system_list (bool need_fs_type)
             me = xmalloc (sizeof *me);
             me->me_devname = xstrdup (dev.f_mntfromname);
             me->me_mountdir = xstrdup (dev.f_mntonname);
+            me->me_mntroot = NULL;
             me->me_type = xstrdup (dev.f_fstypename);
             me->me_type_malloced = 1;
             me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
@@ -1100,6 +1118,7 @@ void free_mount_entry (struct mount_entry *me)
 {
   free (me->me_devname);
   free (me->me_mountdir);
+  free (me->me_mntroot);
   if (me->me_type_malloced)
     free (me->me_type);
   free (me);
diff --git a/lib/mountlist.h b/lib/mountlist.h
index 55877e2..1872b2b 100644
--- a/lib/mountlist.h
+++ b/lib/mountlist.h
@@ -27,6 +27,8 @@ struct mount_entry
 {
   char *me_devname;             /* Device node name, including "/dev/". */
   char *me_mountdir;            /* Mount point directory name. */
+  char *me_mntroot;             /* Directory on filesystem of device used */
+                                /* as root for the (bind) mount. */
   char *me_type;                /* "nfs", "4.2", etc. */
   dev_t me_dev;                 /* Device number of me_mountdir. */
   unsigned int me_dummy : 1;    /* Nonzero for dummy file systems. */
-- 
2.17.2


From 6b301e5f89d4555e33b267e3ea5a709a4b584038 Mon Sep 17 00:00:00 2001
From: Andrew Borodin <aborodin@vmail.ru>
Date: Sun, 27 Sep 2015 11:41:17 +0300
Subject: [PATCH 5/9] mountlist: clean up of variable duplication

* lib/mountlist.c (read_file_system_list) [MOUNTED_LISTMNTENT]:
the 'me' variable is already declared above.  Remove it here.

Upstream-commit: 1eda6d17e93fa496368f82cac6317b8045cc9373
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/mountlist.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/lib/mountlist.c b/lib/mountlist.c
index f4d285a..6f66996 100644
--- a/lib/mountlist.c
+++ b/lib/mountlist.c
@@ -429,7 +429,6 @@ read_file_system_list (bool need_fs_type)
   {
     struct tabmntent *mntlist, *p;
     struct mntent *mnt;
-    struct mount_entry *me;
 
     /* the third and fourth arguments could be used to filter mounts,
        but Crays doesn't seem to have any mounts that we want to
-- 
2.17.2


From b2063df8d13fc279f3fa38d1315e3ff3f66c70e5 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Wed, 14 Sep 2016 19:21:42 -0500
Subject: [PATCH 6/9] mountlist: include sysmacros.h for glibc

On Fedora rawhide (glibc 2.25), './gnulib-tool --test mountlist'
reports:
../../gllib/mountlist.c: In function 'read_file_system_list':
../../gllib/mountlist.c:534:13: warning: '__makedev_from_sys_types' is deprecated:
  In the GNU C Library, `makedev' is defined by <sys/sysmacros.h>.
  For historical compatibility, it is currently defined by
  <sys/types.h> as well, but we plan to remove this soon.
  To use `makedev', include <sys/sysmacros.h> directly.
  If you did not intend to use a system-defined macro `makedev',
  you should #undef it after including <sys/types.h>.
  [-Wdeprecated-declarations]
             me->me_dev = makedev (devmaj, devmin);
             ^~
In file included from /usr/include/features.h:397:0,
                 from /usr/include/sys/types.h:25,
                 from ./sys/types.h:28,
                 from ../../gllib/mountlist.h:23,
                 from ../../gllib/mountlist.c:20:
/usr/include/sys/sysmacros.h:89:1: note: declared here
 __SYSMACROS_DEFINE_MAKEDEV (__SYSMACROS_FST_IMPL_TEMPL)
 ^

Fix it by including the right headers.  We also need a fix to
autoconf's AC_HEADER_MAJOR, but that's a separate patch.

* m4/mountlist.m4 (gl_PREREQ_MOUTLIST_EXTRA): Include
AC_HEADER_MAJOR.
* lib/mountlist.c (includes): Use correct headers.

Signed-off-by: Eric Blake <eblake@redhat.com>

Upstream-commit: 4da63c5881f60f71999a943612da9112232b9161
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/mountlist.c | 6 ++++++
 m4/mountlist.m4 | 3 ++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/lib/mountlist.c b/lib/mountlist.c
index 6f66996..40338ac 100644
--- a/lib/mountlist.c
+++ b/lib/mountlist.c
@@ -37,6 +37,12 @@
 # include <sys/param.h>
 #endif
 
+#if MAJOR_IN_MKDEV
+# include <sys/mkdev.h>
+#elif MAJOR_IN_SYSMACROS
+# include <sys/sysmacros.h>
+#endif
+
 #if defined MOUNTED_GETFSSTAT   /* OSF_1 and Darwin1.3.x */
 # if HAVE_SYS_UCRED_H
 #  include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
diff --git a/m4/mountlist.m4 b/m4/mountlist.m4
index cd137c9..2f47ce2 100644
--- a/m4/mountlist.m4
+++ b/m4/mountlist.m4
@@ -1,4 +1,4 @@
-# serial 11
+# serial 12
 dnl Copyright (C) 2002-2006, 2009-2013 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -15,5 +15,6 @@ AC_DEFUN([gl_PREREQ_MOUNTLIST_EXTRA],
 [
   dnl Note gl_LIST_MOUNTED_FILE_SYSTEMS checks for mntent.h, not sys/mntent.h.
   AC_CHECK_HEADERS([sys/mntent.h])
+  AC_HEADER_MAJOR()dnl for use of makedev ()
   gl_FSTYPENAME
 ])
-- 
2.17.2


From 472ef28870dce7ca7505fa2ca477040da347a567 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <P@draigBrady.com>
Date: Thu, 2 Apr 2015 05:34:07 +0100
Subject: [PATCH 7/9] df: fix use of uninitialized variable reported by
 valgrind

 Conditional jump or move depends on uninitialised value(s)
    at 0x40380C: get_field_values (df.c:840)
    by 0x403E16: get_dev (df.c:994)
    by 0x404D65: get_all_entries (df.c:1364)
    by 0x405926: main (df.c:1714)

* src/df.c (get_dev): Initialize the fsu.fsu_bavail_top_bit_set
member, when adding placeholder entries.
(main): Avoid a "definitely lost" memory leak warning from valgrind,
reported by Bernhard Voelker.

Upstream-commit: bf180f8f5a53eb82054e85e26dcd1ea7c43dbdfe
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 src/df.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/df.c b/src/df.c
index ce11b50..5ffd0a5 100644
--- a/src/df.c
+++ b/src/df.c
@@ -935,6 +935,7 @@ get_dev (char const *disk, char const *mount_point, char const* file,
             return;
 
           fstype = "-";
+          fsu.fsu_bavail_top_bit_set = false;
           fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree =
           fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX;
         }
@@ -959,6 +960,7 @@ get_dev (char const *disk, char const *mount_point, char const* file,
               && (! dev_me->me_remote || ! me_remote))
             {
               fstype = "-";
+              fsu.fsu_bavail_top_bit_set = false;
               fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree =
               fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX;
             }
@@ -1736,6 +1738,8 @@ main (int argc, char **argv)
       for (i = optind; i < argc; ++i)
         if (argv[i])
           get_entry (argv[i], &stats[i - optind]);
+
+      IF_LINT (free (stats));
     }
   else
     get_all_entries ();
-- 
2.17.2


From fc6104cc9d8d2908b3225b035def82d3a95bdfd0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <P@draigBrady.com>
Date: Sun, 5 Apr 2015 18:21:38 +0100
Subject: [PATCH 8/9] df: fix --local hanging with inaccessible remote mounts

* src/df.c (filter_mount_list): With -l, avoid stating remote mounts.
* init.cfg: Avoid test hangs with inaccessible remote mounts.
* tests/df/no-mtab-status.sh: Skip with inaccessible remote mounts.
* tests/df/skip-rootfs.sh: Likewise.
* tests/df/total-verify.sh: Likewise.
* NEWS: Mention the bug fix.
Reported at http://bugzilla.redhat.com/1199679

Upstream-commit: 1b1c40e1d6f8cf30b6c7c9d31bbddbc3d5cc72e6
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 init.cfg                   | 2 +-
 tests/df/no-mtab-status.sh | 3 ++-
 tests/df/skip-rootfs.sh    | 3 ++-
 tests/df/total-verify.sh   | 3 ++-
 4 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/init.cfg b/init.cfg
index 3364a73..d5a80bb 100644
--- a/init.cfg
+++ b/init.cfg
@@ -79,7 +79,7 @@ is_local_dir_()
 require_mount_list_()
 {
   local mount_list_fail='cannot read table of mounted file systems'
-  df 2>&1 | grep -F "$mount_list_fail" >/dev/null &&
+  df --local 2>&1 | grep -F "$mount_list_fail" >/dev/null &&
     skip_ "$mount_list_fail"
 }
 
diff --git a/tests/df/no-mtab-status.sh b/tests/df/no-mtab-status.sh
index 2e6b61b..9b6b9d3 100755
--- a/tests/df/no-mtab-status.sh
+++ b/tests/df/no-mtab-status.sh
@@ -21,7 +21,8 @@
 print_ver_ df
 require_gcc_shared_
 
-df || skip_ "df fails"
+# Protect against inaccessible remote mounts etc.
+timeout 10 df || skip_ "df fails"
 
 # Simulate "mtab" failure.
 cat > k.c <<'EOF' || framework_failure_
diff --git a/tests/df/skip-rootfs.sh b/tests/df/skip-rootfs.sh
index 9c5d0a9..b79751e 100755
--- a/tests/df/skip-rootfs.sh
+++ b/tests/df/skip-rootfs.sh
@@ -19,7 +19,8 @@
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
 print_ver_ df
 
-df || skip_ "df fails"
+# Protect against inaccessible remote mounts etc.
+timeout 10 df || skip_ "df fails"
 
 # Verify that rootfs is in mtab (and shown when the -a option is specified).
 df -a >out || fail=1
diff --git a/tests/df/total-verify.sh b/tests/df/total-verify.sh
index a045ccf..f05a91e 100755
--- a/tests/df/total-verify.sh
+++ b/tests/df/total-verify.sh
@@ -20,7 +20,8 @@
 print_ver_ df
 require_perl_
 
-df || skip_ "df fails"
+# Protect against inaccessible remote mounts etc.
+timeout 10 df || skip_ "df fails"
 
 cat <<\EOF > check-df || framework_failure_
 my ($total, $used, $avail) = (0, 0, 0);
-- 
2.17.2


From 9a52ebdc70071076a1b7263b64b118972d203778 Mon Sep 17 00:00:00 2001
From: Dave Chiluk <chiluk@canonical.com>
Date: Mon, 21 Sep 2015 15:04:11 -0500
Subject: [PATCH 9/9] df: prioritize mounts nearer the device root

In the presence of bind mounts of a device, the 4th "mount root" field
from /proc/self/mountinfo is now considered, so as to prefer mount
points closer to the root of the device.  Note on older systems with
an /etc/mtab file, the source device was listed as the originating
directory, and so this was not an issue.
Details at http://pad.lv/1432871

* src/df.c (filter_mount_list): When deduplicating mount entries,
only prefer sources nearer or at the root of the device, when the
target is nearer the root of the device.
* NEWS: Mention the change in behavior.

Upstream-commit: 3babaf83875ceac896c8dd3a64248e955dfecef9
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 src/df.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/src/df.c b/src/df.c
index 5ffd0a5..c50aa80 100644
--- a/src/df.c
+++ b/src/df.c
@@ -649,6 +649,13 @@ filter_mount_list (bool devices_only)
 
           if (devlist)
             {
+              bool target_nearer_root = strlen (devlist->me->me_mountdir)
+                                        > strlen (me->me_mountdir);
+              /* With bind mounts, prefer items nearer the root of the source */
+              bool source_below_root = devlist->me->me_mntroot != NULL
+                                       && me->me_mntroot != NULL
+                                       && (strlen (devlist->me->me_mntroot)
+                                           < strlen (me->me_mntroot));
               if (! print_grand_total && me->me_remote && devlist->me->me_remote
                   && ! STREQ (devlist->me->me_devname, me->me_devname))
                 {
@@ -660,9 +667,8 @@ filter_mount_list (bool devices_only)
               else if ((strchr (me->me_devname, '/')
                        /* let "real" devices with '/' in the name win.  */
                         && ! strchr (devlist->me->me_devname, '/'))
-                       /* let a shorter mountdir win.  */
-                       || (strlen (devlist->me->me_mountdir)
-                           > strlen (me->me_mountdir))
+                       /* let points towards the root of the device win.  */
+                       || (target_nearer_root && ! source_below_root)
                        /* let an entry overmounted on a new device win...  */
                        || (! STREQ (devlist->me->me_devname, me->me_devname)
                            /* ... but only when matching an existing mnt point,
-- 
2.17.2