You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
514 lines
18 KiB
514 lines
18 KiB
6 years ago
|
diff --git a/src/df.c b/src/df.c
|
||
|
index e28a656..fe222d9 100644
|
||
|
--- a/src/df.c
|
||
|
+++ b/src/df.c
|
||
|
@@ -45,12 +45,12 @@
|
||
|
|
||
|
/* Filled with device numbers of examined file systems to avoid
|
||
|
duplicities in output. */
|
||
|
-struct devlist
|
||
|
+static struct devlist
|
||
|
{
|
||
|
dev_t dev_num;
|
||
|
struct mount_entry *me;
|
||
|
struct devlist *next;
|
||
|
-};
|
||
|
+} *device_list;
|
||
|
|
||
|
/* If true, show even file systems with zero size or
|
||
|
uninteresting types. */
|
||
|
@@ -609,13 +609,10 @@ excluded_fstype (const char *fstype)
|
||
|
me_mountdir wins. */
|
||
|
|
||
|
static void
|
||
|
-filter_mount_list (void)
|
||
|
+filter_mount_list (bool devices_only)
|
||
|
{
|
||
|
struct mount_entry *me;
|
||
|
|
||
|
- /* Store of already-processed device numbers. */
|
||
|
- struct devlist *devlist_head = NULL;
|
||
|
-
|
||
|
/* Sort all 'wanted' entries into the list devlist_head. */
|
||
|
for (me = mount_list; me;)
|
||
|
{
|
||
|
@@ -623,41 +620,66 @@ filter_mount_list (void)
|
||
|
struct devlist *devlist;
|
||
|
struct mount_entry *discard_me = NULL;
|
||
|
|
||
|
- if (-1 == stat (me->me_mountdir, &buf))
|
||
|
+ /* Avoid stating remote file systems as that may hang.
|
||
|
+ On Linux we probably have me_dev populated from /proc/self/mountinfo,
|
||
|
+ however we still stat() in case another device was mounted later. */
|
||
|
+ if ((me->me_remote && show_local_fs)
|
||
|
+ || -1 == stat (me->me_mountdir, &buf))
|
||
|
{
|
||
|
- /* Stat failed - add ME to be able to complain about it later. */
|
||
|
+ /* If remote, and showing just local, add ME for filtering later.
|
||
|
+ If stat failed; add ME to be able to complain about it later. */
|
||
|
buf.st_dev = me->me_dev;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
- /* If the device name is a real path name ... */
|
||
|
- if (strchr (me->me_devname, '/'))
|
||
|
- {
|
||
|
- /* ... try to find its device number in the devlist. */
|
||
|
- for (devlist = devlist_head; devlist; devlist = devlist->next)
|
||
|
- if (devlist->dev_num == buf.st_dev)
|
||
|
- break;
|
||
|
+ /* If we've already seen this device... */
|
||
|
+ for (devlist = device_list; devlist; devlist = devlist->next)
|
||
|
+ if (devlist->dev_num == buf.st_dev)
|
||
|
+ break;
|
||
|
|
||
|
- if (devlist)
|
||
|
+ if (devlist)
|
||
|
+ {
|
||
|
+ if (! print_grand_total && me->me_remote && devlist->me->me_remote
|
||
|
+ && ! STREQ (devlist->me->me_devname, me->me_devname))
|
||
|
{
|
||
|
+ /* Don't discard remote entries with different locations,
|
||
|
+ as these are more likely to be explicitly mounted.
|
||
|
+ However avoid this when producing a total to give
|
||
|
+ a more accurate value in that case. */
|
||
|
+ }
|
||
|
+ 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 an entry overmounted on a new device win... */
|
||
|
+ || (! STREQ (devlist->me->me_devname, me->me_devname)
|
||
|
+ /* ... but only when matching an existing mnt point,
|
||
|
+ to avoid problematic replacement when given
|
||
|
+ inaccurate mount lists, seen with some chroot
|
||
|
+ environments for example. */
|
||
|
+ && STREQ (me->me_mountdir,
|
||
|
+ devlist->me->me_mountdir)))
|
||
|
+ {
|
||
|
+ /* Discard mount entry for existing device. */
|
||
|
+ discard_me = devlist->me;
|
||
|
+ devlist->me = me;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ /* Discard mount entry currently being processed. */
|
||
|
discard_me = me;
|
||
|
-
|
||
|
- /* Let the shorter mountdir win. */
|
||
|
- if (! strchr (devlist->me->me_devname, '/')
|
||
|
- || (strlen (devlist->me->me_mountdir)
|
||
|
- > strlen (me->me_mountdir)))
|
||
|
- {
|
||
|
- discard_me = devlist->me;
|
||
|
- devlist->me = me;
|
||
|
- }
|
||
|
}
|
||
|
+
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (discard_me)
|
||
|
{
|
||
|
me = me->me_next;
|
||
|
- free_mount_entry (discard_me);
|
||
|
+ if (! devices_only)
|
||
|
+ free_mount_entry (discard_me);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
@@ -665,28 +687,49 @@ filter_mount_list (void)
|
||
|
devlist = xmalloc (sizeof *devlist);
|
||
|
devlist->me = me;
|
||
|
devlist->dev_num = buf.st_dev;
|
||
|
- devlist->next = devlist_head;
|
||
|
- devlist_head = devlist;
|
||
|
+ devlist->next = device_list;
|
||
|
+ device_list = devlist;
|
||
|
|
||
|
me = me->me_next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Finally rebuild the mount_list from the devlist. */
|
||
|
- mount_list = NULL;
|
||
|
- while (devlist_head)
|
||
|
+ if (! devices_only) {
|
||
|
+ mount_list = NULL;
|
||
|
+ while (device_list)
|
||
|
+ {
|
||
|
+ /* Add the mount entry. */
|
||
|
+ me = device_list->me;
|
||
|
+ me->me_next = mount_list;
|
||
|
+ mount_list = me;
|
||
|
+ /* Free devlist entry and advance. */
|
||
|
+ struct devlist *devlist = device_list->next;
|
||
|
+ free (device_list);
|
||
|
+ device_list = devlist;
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+/* Search a mount entry list for device id DEV.
|
||
|
+ Return the corresponding mount entry if found or NULL if not. */
|
||
|
+
|
||
|
+static struct mount_entry const * _GL_ATTRIBUTE_PURE
|
||
|
+me_for_dev (dev_t dev)
|
||
|
+{
|
||
|
+ struct devlist *dl = device_list;
|
||
|
+
|
||
|
+ while (dl)
|
||
|
{
|
||
|
- /* Add the mount entry. */
|
||
|
- me = devlist_head->me;
|
||
|
- me->me_next = mount_list;
|
||
|
- mount_list = me;
|
||
|
- /* Free devlist entry and advance. */
|
||
|
- struct devlist *devlist = devlist_head->next;
|
||
|
- free (devlist_head);
|
||
|
- devlist_head = devlist;
|
||
|
+ if (dl->dev_num == dev)
|
||
|
+ return dl->me;
|
||
|
+ dl = dl->next;
|
||
|
}
|
||
|
+
|
||
|
+ return NULL;
|
||
|
}
|
||
|
|
||
|
+
|
||
|
/* Return true if N is a known integer value. On many file systems,
|
||
|
UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
|
||
|
represents unknown. Use a rule that works on AIX file systems, and
|
||
|
@@ -856,6 +899,11 @@ get_dev (char const *disk, char const *mount_point, char const* file,
|
||
|
if (!selected_fstype (fstype) || excluded_fstype (fstype))
|
||
|
return;
|
||
|
|
||
|
+ /* Ignore relative MOUNT_POINTs, which are present for example
|
||
|
+ in /proc/mounts on Linux with network namespaces. */
|
||
|
+ if (!force_fsu && mount_point && ! IS_ABSOLUTE_FILE_NAME (mount_point))
|
||
|
+ return;
|
||
|
+
|
||
|
/* If MOUNT_POINT is NULL, then the file system is not mounted, and this
|
||
|
program reports on the file system that the special file is on.
|
||
|
It would be better to report on the unmounted file system,
|
||
|
@@ -868,9 +916,43 @@ get_dev (char const *disk, char const *mount_point, char const* file,
|
||
|
fsu = *force_fsu;
|
||
|
else if (get_fs_usage (stat_file, disk, &fsu))
|
||
|
{
|
||
|
- error (0, errno, "%s", quote (stat_file));
|
||
|
- exit_status = EXIT_FAILURE;
|
||
|
- return;
|
||
|
+ /* If we can't access a system provided entry due
|
||
|
+ to it not being present (now), or due to permissions,
|
||
|
+ just output placeholder values rather than failing. */
|
||
|
+ if (process_all && (errno == EACCES || errno == ENOENT))
|
||
|
+ {
|
||
|
+ if (! show_all_fs)
|
||
|
+ return;
|
||
|
+
|
||
|
+ fstype = "-";
|
||
|
+ fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree =
|
||
|
+ fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ error (0, errno, "%s", quote (stat_file));
|
||
|
+ exit_status = EXIT_FAILURE;
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ else if (process_all && show_all_fs)
|
||
|
+ {
|
||
|
+ /* Ensure we don't output incorrect stats for over-mounted directories.
|
||
|
+ Discard stats when the device name doesn't match. Though don't
|
||
|
+ discard when used and current mount entries are both remote due
|
||
|
+ to the possibility of aliased host names or exports. */
|
||
|
+ struct stat sb;
|
||
|
+ if (stat (stat_file, &sb) == 0)
|
||
|
+ {
|
||
|
+ struct mount_entry const * dev_me = me_for_dev (sb.st_dev);
|
||
|
+ if (dev_me && ! STREQ (dev_me->me_devname, disk)
|
||
|
+ && (! dev_me->me_remote || ! me_remote))
|
||
|
+ {
|
||
|
+ fstype = "-";
|
||
|
+ fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree =
|
||
|
+ fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX;
|
||
|
+ }
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs)
|
||
|
@@ -1275,8 +1357,7 @@ get_all_entries (void)
|
||
|
{
|
||
|
struct mount_entry *me;
|
||
|
|
||
|
- if (!show_all_fs)
|
||
|
- filter_mount_list ();
|
||
|
+ filter_mount_list (show_all_fs);
|
||
|
|
||
|
for (me = mount_list; me; me = me->me_next)
|
||
|
get_dev (me->me_devname, me->me_mountdir, NULL, NULL, me->me_type,
|
||
|
@@ -1325,7 +1406,7 @@ or all file systems by default.\n\
|
||
|
emit_mandatory_arg_note ();
|
||
|
|
||
|
fputs (_("\
|
||
|
- -a, --all include dummy file systems\n\
|
||
|
+ -a, --all include pseudo, duplicate, inaccessible file systems\n\
|
||
|
-B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\
|
||
|
'-BM' prints sizes in units of 1,048,576 bytes;\n\
|
||
|
see SIZE format below\n\
|
||
|
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
|
||
|
index 942d9a1..1df1eac 100644
|
||
|
--- a/doc/coreutils.texi
|
||
|
+++ b/doc/coreutils.texi
|
||
|
@@ -11123,11 +11123,15 @@ The program accepts the following options. Also see @ref{Common options}.
|
||
|
@itemx --all
|
||
|
@opindex -a
|
||
|
@opindex --all
|
||
|
-@cindex automounter file systems
|
||
|
@cindex ignore file systems
|
||
|
-Include in the listing dummy file systems, which
|
||
|
-are omitted by default. Such file systems are typically special-purpose
|
||
|
-pseudo-file-systems, such as automounter entries.
|
||
|
+Include in the listing dummy, duplicate, or inaccessible file systems, which
|
||
|
+are omitted by default. Dummy file systems are typically special purpose
|
||
|
+pseudo file systems such as @samp{/proc}, with no associated storage.
|
||
|
+Duplicate file systems are local or remote file systems that are mounted
|
||
|
+at separate locations in the local file hierarchy, or bind mounted locations.
|
||
|
+Inaccessible file systems are those which are mounted but subsequently
|
||
|
+over-mounted by another file system at that point, or otherwise inaccessible
|
||
|
+due to permissions of the mount point etc.
|
||
|
|
||
|
@item -B @var{size}
|
||
|
@itemx --block-size=@var{size}
|
||
|
diff --git a/tests/df/skip-duplicates.sh b/tests/df/skip-duplicates.sh
|
||
|
index 1e94dc0..4069604 100755
|
||
|
--- a/tests/df/skip-duplicates.sh
|
||
|
+++ b/tests/df/skip-duplicates.sh
|
||
|
@@ -2,7 +2,7 @@
|
||
|
# Test df's behavior when the mount list contains duplicate entries.
|
||
|
# This test is skipped on systems that lack LD_PRELOAD support; that's fine.
|
||
|
|
||
|
-# Copyright (C) 2012-2013 Free Software Foundation, Inc.
|
||
|
+# Copyright (C) 2012-2015 Free Software Foundation, Inc.
|
||
|
|
||
|
# This program is free software: you can redistribute it and/or modify
|
||
|
# it under the terms of the GNU General Public License as published by
|
||
|
@@ -21,19 +21,73 @@
|
||
|
print_ver_ df
|
||
|
require_gcc_shared_
|
||
|
|
||
|
-df || skip_ "df fails"
|
||
|
+# We use --local here so as to not activate
|
||
|
+# potentially very many remote mounts.
|
||
|
+df --local || skip_ 'df fails'
|
||
|
|
||
|
-# Simulate an mtab file with two entries of the same device number.
|
||
|
-# Also add entries with unstatable mount dirs to ensure that's handled.
|
||
|
-cat > k.c <<'EOF' || framework_failure_
|
||
|
+export CU_NONROOT_FS=$(df --local --output=target 2>&1 | grep /. | head -n1)
|
||
|
+export CU_REMOTE_FS=$(df --local --output=target 2>&1 | grep /. |
|
||
|
+ tail -n+2 | head -n1)
|
||
|
+
|
||
|
+unique_entries=1
|
||
|
+test -z "$CU_NONROOT_FS" || unique_entries=$(expr $unique_entries + 1)
|
||
|
+test -z "$CU_REMOTE_FS" || unique_entries=$(expr $unique_entries + 2)
|
||
|
+
|
||
|
+grep '^#define HAVE_MNTENT_H 1' $CONFIG_HEADER > /dev/null \
|
||
|
+ || skip_ "no mntent.h available to confirm the interface"
|
||
|
+
|
||
|
+grep '^#define HAVE_GETMNTENT 1' $CONFIG_HEADER > /dev/null \
|
||
|
+ || skip_ "getmntent is not used on this system"
|
||
|
+
|
||
|
+# Simulate an mtab file to test various cases.
|
||
|
+cat > k.c <<EOF || framework_failure_
|
||
|
+#define _GNU_SOURCE
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
+#include <errno.h>
|
||
|
#include <mntent.h>
|
||
|
+#include <string.h>
|
||
|
+#include <dlfcn.h>
|
||
|
+
|
||
|
+#define STREQ(a, b) (strcmp (a, b) == 0)
|
||
|
+
|
||
|
+FILE* fopen(const char *path, const char *mode)
|
||
|
+{
|
||
|
+ static FILE* (*fopen_func)(char const *, char const *);
|
||
|
+
|
||
|
+ /* get reference to original (libc provided) fopen */
|
||
|
+ if (!fopen_func)
|
||
|
+ {
|
||
|
+ fopen_func = (FILE*(*)(char const *, char const *))
|
||
|
+ dlsym(RTLD_NEXT, "fopen");
|
||
|
+ if (!fopen_func)
|
||
|
+ {
|
||
|
+ fprintf (stderr, "Failed to find fopen()\n");
|
||
|
+ errno = ESRCH;
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Returning ENOENT here will get read_file_system_list()
|
||
|
+ to fall back to using getmntent() below. */
|
||
|
+ if (STREQ (path, "/proc/self/mountinfo"))
|
||
|
+ {
|
||
|
+ errno = ENOENT;
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ return fopen_func(path, mode);
|
||
|
+}
|
||
|
+
|
||
|
+#define STREQ(a, b) (strcmp (a, b) == 0)
|
||
|
|
||
|
struct mntent *getmntent (FILE *fp)
|
||
|
{
|
||
|
+ static char *nonroot_fs;
|
||
|
+ static char *remote_fs;
|
||
|
+ static int done;
|
||
|
+
|
||
|
/* Prove that LD_PRELOAD works. */
|
||
|
- static int done = 0;
|
||
|
if (!done)
|
||
|
{
|
||
|
fclose (fopen ("x", "w"));
|
||
|
@@ -41,50 +95,92 @@ struct mntent *getmntent (FILE *fp)
|
||
|
}
|
||
|
|
||
|
static struct mntent mntents[] = {
|
||
|
- {.mnt_fsname="/short", .mnt_dir="/invalid/mount/dir"},
|
||
|
- {.mnt_fsname="fsname", .mnt_dir="/",},
|
||
|
- {.mnt_fsname="/fsname", .mnt_dir="/root"},
|
||
|
- {.mnt_fsname="/fsname", .mnt_dir="/"},
|
||
|
+ {.mnt_fsname="/short", .mnt_dir="/invalid/mount/dir", .mnt_opts=""},
|
||
|
+ {.mnt_fsname="fsname", .mnt_dir="/", .mnt_opts=""},
|
||
|
+ {.mnt_fsname="/fsname", .mnt_dir="/.", .mnt_opts=""},
|
||
|
+ {.mnt_fsname="/fsname", .mnt_dir="/", .mnt_opts=""},
|
||
|
+ {.mnt_fsname="virtfs", .mnt_dir="/NONROOT", .mnt_type="t1", .mnt_opts=""},
|
||
|
+ {.mnt_fsname="virtfs2", .mnt_dir="/NONROOT", .mnt_type="t2", .mnt_opts=""},
|
||
|
+ {.mnt_fsname="netns", .mnt_dir="net:[1234567]", .mnt_opts=""},
|
||
|
+ {.mnt_fsname="rem:ote1",.mnt_dir="/REMOTE", .mnt_opts=""},
|
||
|
+ {.mnt_fsname="rem:ote1",.mnt_dir="/REMOTE", .mnt_opts=""},
|
||
|
+ {.mnt_fsname="rem:ote2",.mnt_dir="/REMOTE", .mnt_opts=""},
|
||
|
};
|
||
|
|
||
|
- if (!getenv ("CU_TEST_DUPE_INVALID") && done == 1)
|
||
|
+ if (done == 1)
|
||
|
+ {
|
||
|
+ nonroot_fs = getenv ("CU_NONROOT_FS");
|
||
|
+ if (!nonroot_fs || !*nonroot_fs)
|
||
|
+ nonroot_fs = "/"; /* merge into / entries. */
|
||
|
+
|
||
|
+ remote_fs = getenv ("CU_REMOTE_FS");
|
||
|
+ }
|
||
|
+
|
||
|
+ if (done == 1 && !getenv ("CU_TEST_DUPE_INVALID"))
|
||
|
done++; /* skip the first entry. */
|
||
|
|
||
|
- while (done++ <= 4)
|
||
|
+ while (done++ <= 10)
|
||
|
{
|
||
|
- mntents[done-2].mnt_type = "-";
|
||
|
+ if (!mntents[done-2].mnt_type)
|
||
|
+ mntents[done-2].mnt_type = "-";
|
||
|
+ if (!mntents[done-2].mnt_opts)
|
||
|
+ mntents[done-2].mnt_opts = "-";
|
||
|
+ if (STREQ (mntents[done-2].mnt_dir, "/NONROOT"))
|
||
|
+ mntents[done-2].mnt_dir = nonroot_fs;
|
||
|
+ if (STREQ (mntents[done-2].mnt_dir, "/REMOTE"))
|
||
|
+ {
|
||
|
+ if (!remote_fs || !*remote_fs)
|
||
|
+ continue;
|
||
|
+ else
|
||
|
+ mntents[done-2].mnt_dir = remote_fs;
|
||
|
+ }
|
||
|
return &mntents[done-2];
|
||
|
}
|
||
|
+
|
||
|
return NULL;
|
||
|
}
|
||
|
EOF
|
||
|
|
||
|
# Then compile/link it:
|
||
|
-gcc --std=gnu99 -shared -fPIC -ldl -O2 k.c -o k.so \
|
||
|
+gcc_shared_ k.c k.so \
|
||
|
|| framework_failure_ 'failed to build shared library'
|
||
|
|
||
|
# Test if LD_PRELOAD works:
|
||
|
-LD_PRELOAD=./k.so df
|
||
|
+LD_PRELOAD=$LD_PRELOAD:./k.so df
|
||
|
test -f x || skip_ "internal test failure: maybe LD_PRELOAD doesn't work?"
|
||
|
|
||
|
# The fake mtab file should only contain entries
|
||
|
# having the same device number; thus the output should
|
||
|
-# consist of a header and one entry.
|
||
|
-LD_PRELOAD=./k.so df >out || fail=1
|
||
|
-test $(wc -l <out) -eq 2 || { fail=1; cat out; }
|
||
|
+# consist of a header and unique entries.
|
||
|
+LD_PRELOAD=$LD_PRELOAD:./k.so df -T >out || fail=1
|
||
|
+test $(wc -l <out) -eq $(expr 1 + $unique_entries) || { fail=1; cat out; }
|
||
|
|
||
|
-# Ensure we fail when unable to stat invalid entries
|
||
|
-LD_PRELOAD=./k.so CU_TEST_DUPE_INVALID=1 df >out && fail=1
|
||
|
-test $(wc -l <out) -eq 2 || { fail=1; cat out; }
|
||
|
+# With --total we should suppress the duplicate but separate remote file system
|
||
|
+LD_PRELOAD=$LD_PRELOAD:./k.so df --total >out || fail=1
|
||
|
+test "$CU_REMOTE_FS" && elide_remote=1 || elide_remote=0
|
||
|
+test $(wc -l <out) -eq $(expr 2 + $unique_entries - $elide_remote) ||
|
||
|
+ { fail=1; cat out; }
|
||
|
+
|
||
|
+# Ensure we don't fail when unable to stat (currently) unavailable entries
|
||
|
+LD_PRELOAD=$LD_PRELOAD:./k.so CU_TEST_DUPE_INVALID=1 df -T >out || fail=1
|
||
|
+test $(wc -l <out) -eq $(expr 1 + $unique_entries) || { fail=1; cat out; }
|
||
|
|
||
|
# df should also prefer "/fsname" over "fsname"
|
||
|
-test $(grep -c '/fsname' <out) -eq 1 || { fail=1; cat out; }
|
||
|
-# ... and "/fsname" with '/' as Mounted on over '/root'
|
||
|
-test $(grep -c '/root' <out) -eq 0 || { fail=1; cat out; }
|
||
|
+if test "$unique_entries" = 2; then
|
||
|
+ test $(grep -c '/fsname' <out) -eq 1 || { fail=1; cat out; }
|
||
|
+ # ... and "/fsname" with '/' as Mounted on over '/.'
|
||
|
+ test $(grep -cF '/.' <out) -eq 0 || { fail=1; cat out; }
|
||
|
+fi
|
||
|
+
|
||
|
+# df should use the last seen devname (mnt_fsname) and devtype (mnt_type)
|
||
|
+test $(grep -c 'virtfs2.*t2' <out) -eq 1 || { fail=1; cat out; }
|
||
|
|
||
|
# Ensure that filtering duplicates does not affect -a processing.
|
||
|
-LD_PRELOAD=./k.so df -a >out || fail=1
|
||
|
-test $(wc -l <out) -eq 4 || { fail=1; cat out; }
|
||
|
+LD_PRELOAD=$LD_PRELOAD:./k.so df -a >out || fail=1
|
||
|
+total_fs=6; test "$CU_REMOTE_FS" && total_fs=$(expr $total_fs + 3)
|
||
|
+test $(wc -l <out) -eq $total_fs || { fail=1; cat out; }
|
||
|
+# Ensure placeholder "-" values used for the eclipsed "virtfs"
|
||
|
+test $(grep -c 'virtfs *-' <out) -eq 1 || { fail=1; cat out; }
|
||
|
|
||
|
# Ensure that filtering duplicates does not affect
|
||
|
# argument processing (now without the fake getmntent()).
|
||
|
diff --git a/init.cfg b/init.cfg
|
||
|
index 360d4da..16f9813 100644
|
||
|
--- a/init.cfg
|
||
|
+++ b/init.cfg
|
||
|
@@ -472,6 +472,18 @@ require_sparse_support_()
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
+# Compile a shared lib using the GCC options for doing so.
|
||
|
+# Pass input and output file as parameters respectively.
|
||
|
+# Any other optional parmeters are passed to $CC.
|
||
|
+gcc_shared_()
|
||
|
+{
|
||
|
+ local in=$1
|
||
|
+ local out=$2
|
||
|
+ shift 2 || return 1
|
||
|
+
|
||
|
+ $CC -Wall -shared --std=gnu99 -fPIC -O2 $* "$in" -o "$out" -ldl
|
||
|
+}
|
||
|
+
|
||
|
# There are a myriad of ways to build shared libs,
|
||
|
# so we only consider running tests requiring shared libs,
|
||
|
# on platforms that support building them as follows.
|