Skip to content

Commit

Permalink
mountlist: remove dependency on libmount
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
pixelb committed Apr 3, 2015
1 parent e2e6669 commit 3fb6e36
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 56 deletions.
13 changes: 13 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
2015-04-02 Pádraig Brady <[email protected]>

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.

2015-04-02 Paul Eggert <[email protected]>

stddef: port to pre-C11 GCC on x86
Expand Down
7 changes: 0 additions & 7 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,3 @@ at any time.
+ Download:
http://ftp.gnu.org/gnu/libtool/
ftp://ftp.gnu.org/gnu/libtool/

* util-linux
+ Optional.
Needed if you want to support /proc/self/mountinfo available on Linux.
This will give an ability to propagate device ID of a mounted file system.
+ Download:
http://www.kernel.org/pub/linux/utils/util-linux/
128 changes: 100 additions & 28 deletions lib/mountlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -392,6 +387,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
Expand Down Expand Up @@ -438,30 +461,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. */
Expand All @@ -473,13 +536,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;

Expand Down
23 changes: 2 additions & 21 deletions m4/ls-mntd-fs.m4
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# serial 31
# serial 32
# How to list mounted file systems.

# Copyright (C) 1998-2004, 2006, 2009-2015 Free Software Foundation, Inc.
Expand Down Expand Up @@ -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([[
Expand Down Expand Up @@ -152,25 +152,6 @@ 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])
AC_ARG_WITH([libmount],
[AS_HELP_STRING([--with-libmount],
[use libmount if available to parse the system mount list.])],
[],
dnl libmount has the advantage of propagating accurate device IDs for
dnl each entry, but the disadvantage of many dependent shared libs
dnl with associated runtime startup overhead and virt mem usage.
[with_libmount=no])
# Check for libmount to support /proc/self/mountinfo on Linux
if test "x$with_libmount" != xno; then
AC_CHECK_LIB([mount], [mnt_new_table_from_file],
[AC_DEFINE([MOUNTED_PROC_MOUNTINFO], [1],
[Define if want to use /proc/self/mountinfo on Linux.])
LIBS="-lmount $LIBS"],
[test -f /proc/self/mountinfo &&
AC_MSG_WARN([/proc/self/mountinfo present but libmount missing.])])
fi
fi
fi
Expand Down

0 comments on commit 3fb6e36

Please sign in to comment.