From 8fc04194435f3a07efa73f21532bdb5d6d1f8670 Mon Sep 17 00:00:00 2001
From: Andrew Borodin <aborodin@vmail.ru>
Date: Sat, 11 Apr 2015 12:12:50 +0300
Subject: [PATCH] Ticket #3441: fix Linux kernel-specific segfault on startup.
Sync with gnulib 3fb6e360363744462ce15c381f0b116c6fc4ce82.
src/filemanager/mountlist.c: remove dependency on libmount.
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.
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
---
m4.include/ls-mntd-fs.m4 | 23 ++------
src/filemanager/mountlist.c | 124 ++++++++++++++++++++++++++++++++++----------
2 files changed, 102 insertions(+), 45 deletions(-)
diff --git a/m4.include/ls-mntd-fs.m4 b/m4.include/ls-mntd-fs.m4
index c29f0aa..7e4aa19 100644
a
|
b
|
|
1 | | # serial 29 |
| 1 | # serial 32 |
2 | 2 | # How to list mounted file systems. |
3 | 3 | |
4 | | # Copyright (C) 1998-2004, 2006, 2009-2011 Free Software Foundation, Inc. |
| 4 | # Copyright (C) 1998-2004, 2006, 2009-2015 Free Software Foundation, Inc. |
5 | 5 | # |
6 | 6 | # This file is free software; the Free Software Foundation |
7 | 7 | # gives unlimited permission to copy and/or distribute it, |
… |
… |
if test -z "$ac_list_mounted_fs"; then |
110 | 110 | AC_DEFINE([MOUNTED_VMOUNT], [1], |
111 | 111 | [Define if there is a function named mntctl that can be used to read |
112 | 112 | the list of mounted file systems, and there is a system header file |
113 | | that declares 'struct vmount.' (AIX)]) |
| 113 | that declares 'struct vmount'. (AIX)]) |
114 | 114 | fi |
115 | 115 | fi |
116 | 116 | |
… |
… |
if test $ac_cv_func_getmntent = yes; then |
120 | 120 | # Determine whether it's the one-argument variant or the two-argument one. |
121 | 121 | |
122 | 122 | if test -z "$ac_list_mounted_fs"; then |
123 | | # 4.3BSD, SunOS, HP-UX, Dynix, Irix |
| 123 | # GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix |
124 | 124 | AC_MSG_CHECKING([for one-argument getmntent function]) |
125 | 125 | AC_CACHE_VAL([fu_cv_sys_mounted_getmntent1], |
126 | 126 | [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ |
… |
… |
if test $ac_cv_func_getmntent = yes; then |
152 | 152 | of mounted file systems, and that function takes a single argument. |
153 | 153 | (4.3BSD, SunOS, HP-UX, Dynix, Irix)]) |
154 | 154 | AC_CHECK_FUNCS([hasmntopt]) |
155 | | |
156 | | # Check for libmount to support /proc/self/mountinfo on Linux |
157 | | AC_CACHE_VAL([ac_cv_lib_libmount_mnt_table_parse_stream], |
158 | | [AC_CHECK_LIB([mount], [mnt_new_table_from_file], |
159 | | ac_cv_lib_mount_mnt_table_parse_stream=yes, |
160 | | ac_cv_lib_mount_mnt_table_parse_stream=no)]) |
161 | | if test $ac_cv_lib_mount_mnt_table_parse_stream = yes; then |
162 | | AC_DEFINE([MOUNTED_PROC_MOUNTINFO], [1], |
163 | | [Define if want to use /proc/self/mountinfo on Linux.]) |
164 | | LIBS="-lmount $LIBS" |
165 | | elif test -f /proc/self/mountinfo; then |
166 | | AC_MSG_WARN([/proc/self/mountinfo present but libmount is missing.]) |
167 | | fi |
168 | 155 | fi |
169 | 156 | fi |
170 | 157 | |
… |
… |
if test -z "$ac_list_mounted_fs"; then |
353 | 340 | ac_list_mounted_fs=found |
354 | 341 | AC_DEFINE([MOUNTED_INTERIX_STATVFS], [1], |
355 | 342 | [Define if we are on interix, and ought to use statvfs plus |
356 | | some special knowledge on where mounted filesystems can be |
| 343 | some special knowledge on where mounted file systems can be |
357 | 344 | found. (Interix)]) |
358 | 345 | fi |
359 | 346 | ;; |
diff --git a/src/filemanager/mountlist.c b/src/filemanager/mountlist.c
index 991ebc3..1bc5b33 100644
a
|
b
|
|
87 | 87 | |
88 | 88 | #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ |
89 | 89 | #include <mntent.h> |
| 90 | #include <sys/types.h> |
90 | 91 | #ifndef MOUNTED |
91 | 92 | #ifdef _PATH_MOUNTED /* GNU libc */ |
92 | 93 | #define MOUNTED _PATH_MOUNTED |
… |
… |
|
157 | 158 | #include <sys/mntent.h> |
158 | 159 | #endif |
159 | 160 | |
160 | | #ifdef MOUNTED_PROC_MOUNTINFO |
161 | | /* Use /proc/self/mountinfo instead of /proc/self/mounts (/etc/mtab) |
162 | | * on Linux, if available */ |
163 | | #include <libmount/libmount.h> |
164 | | #endif |
165 | | |
166 | 161 | #ifndef HAVE_HASMNTOPT |
167 | 162 | #define hasmntopt(mnt, opt) ((char *) 0) |
168 | 163 | #endif |
… |
… |
statfs (char *file, struct statfs *fsb) |
613 | 608 | |
614 | 609 | /* --------------------------------------------------------------------------------------------- */ |
615 | 610 | |
| 611 | #if defined MOUNTED_GETMNTENT1 && defined __linux__ |
| 612 | |
| 613 | /* Unescape the paths in mount tables. |
| 614 | STR is updated in place. */ |
| 615 | static void |
| 616 | unescape_tab (char *str) |
| 617 | { |
| 618 | size_t i, j = 0; |
| 619 | size_t len; |
| 620 | |
| 621 | len = strlen (str) + 1; |
| 622 | |
| 623 | for (i = 0; i < len; i++) |
| 624 | { |
| 625 | if (str[i] == '\\' && (i + 4 < len) |
| 626 | && str[i + 1] >= '0' && str[i + 1] <= '3' |
| 627 | && str[i + 2] >= '0' && str[i + 2] <= '7' && str[i + 3] >= '0' && str[i + 3] <= '7') |
| 628 | { |
| 629 | str[j++] = (str[i + 1] - '0') * 64 + (str[i + 2] - '0') * 8 + (str[i + 3] - '0'); |
| 630 | i += 3; |
| 631 | } |
| 632 | else |
| 633 | str[j++] = str[i]; |
| 634 | } |
| 635 | } |
| 636 | #endif |
| 637 | |
| 638 | /* --------------------------------------------------------------------------------------------- */ |
| 639 | |
616 | 640 | /* Return a list of the currently mounted file systems, or NULL on error. |
617 | 641 | Add each entry to the tail of the list so that they stay in order. |
618 | 642 | If NEED_FS_TYPE is true, ensure that the file system type fields in |
… |
… |
read_file_system_list (int need_fs_type) |
658 | 682 | |
659 | 683 | #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ |
660 | 684 | { |
661 | | #ifdef MOUNTED_PROC_MOUNTINFO |
662 | | struct libmnt_table *fstable = NULL; |
| 685 | FILE *fp; |
663 | 686 | |
664 | | fstable = mnt_new_table_from_file ("/proc/self/mountinfo"); |
| 687 | #ifdef __linux__ |
| 688 | /* Try parsing mountinfo first, as that make device IDs available. |
| 689 | Note we could use libmount routines to simplify this parsing a little |
| 690 | (and that code is in previous versions of this function), however |
| 691 | libmount depends on libselinux which pulls in many dependencies. */ |
| 692 | char const *mountinfo = "/proc/self/mountinfo"; |
665 | 693 | |
666 | | if (fstable != NULL) |
| 694 | fp = fopen (mountinfo, "r"); |
| 695 | if (fp != NULL) |
667 | 696 | { |
668 | | struct libmnt_fs *fs; |
669 | | struct libmnt_iter *iter; |
| 697 | char *line = NULL; |
| 698 | size_t buf_size = 0; |
670 | 699 | |
671 | | iter = mnt_new_iter (MNT_ITER_FORWARD); |
672 | | |
673 | | while (iter && mnt_table_next_fs (fstable, iter, &fs) == 0) |
| 700 | while (getline (&line, &buf_size, fp) != -1) |
674 | 701 | { |
| 702 | unsigned int devmaj, devmin; |
| 703 | int target_s, target_e, type_s, type_e, source_s, source_e; |
| 704 | char test; |
| 705 | char *dash; |
| 706 | int rc; |
| 707 | |
| 708 | rc = sscanf (line, "%*u " /* id - discarded */ |
| 709 | "%*u " /* parent - discarded */ |
| 710 | "%u:%u " /* dev major:minor */ |
| 711 | "%*s " /* mountroot - discarded */ |
| 712 | "%n%*s%n" /* target, start and end */ |
| 713 | "%c", /* more data... */ |
| 714 | &devmaj, &devmin, &target_s, &target_e, &test); |
| 715 | if (rc != 3 && rc != 5) /* 5 if %n included in count. */ |
| 716 | continue; |
| 717 | |
| 718 | /* skip optional fields, terminated by " - " */ |
| 719 | dash = strstr (line + target_e, " - "); |
| 720 | if (dash == NULL) |
| 721 | continue; |
| 722 | |
| 723 | rc = sscanf (dash, " - " /* */ |
| 724 | "%n%*s%n " /* FS type, start and end */ |
| 725 | "%n%*s%n " /* source, start and end */ |
| 726 | "%c", /* more data... */ |
| 727 | &type_s, &type_e, &source_s, &source_e, &test); |
| 728 | if (rc != 1 && rc != 5) /* 5 if %n included in count. */ |
| 729 | continue; |
| 730 | |
| 731 | /* manipulate the sub-strings in place. */ |
| 732 | line[target_e] = '\0'; |
| 733 | dash[type_e] = '\0'; |
| 734 | dash[source_e] = '\0'; |
| 735 | unescape_tab (dash + source_s); |
| 736 | unescape_tab (line + target_s); |
| 737 | |
675 | 738 | me = g_malloc (sizeof *me); |
676 | 739 | |
677 | | me->me_devname = g_strdup (mnt_fs_get_source (fs)); |
678 | | me->me_mountdir = g_strdup (mnt_fs_get_target (fs)); |
679 | | me->me_type = g_strdup (mnt_fs_get_fstype (fs)); |
| 740 | me->me_devname = strdup (dash + source_s); |
| 741 | me->me_mountdir = strdup (line + target_s); |
| 742 | me->me_type = strdup (dash + type_s); |
680 | 743 | me->me_type_malloced = 1; |
681 | | me->me_dev = mnt_fs_get_devno (fs); |
682 | | /* Note we don't use mnt_fs_is_pseudofs() or mnt_fs_is_netfs() here |
683 | | as libmount's classification is non-compatible currently. |
684 | | Also we pass "false" for the "Bind" option as that's only |
| 744 | me->me_dev = makedev (devmaj, devmin); |
| 745 | /* we pass "false" for the "Bind" option as that's only |
685 | 746 | significant when the Fs_type is "none" which will not be |
686 | 747 | the case when parsing "/proc/self/mountinfo", and only |
687 | 748 | applies for static /etc/mtab files. */ |
… |
… |
read_file_system_list (int need_fs_type) |
693 | 754 | mtail = &me->me_next; |
694 | 755 | } |
695 | 756 | |
696 | | mnt_free_iter (iter); |
697 | | mnt_free_table (fstable); |
| 757 | free (line); |
| 758 | |
| 759 | if (ferror (fp) != 0) |
| 760 | { |
| 761 | int saved_errno = errno; |
| 762 | |
| 763 | fclose (fp); |
| 764 | errno = saved_errno; |
| 765 | goto free_then_fail; |
| 766 | } |
698 | 767 | |
| 768 | if (fclose (fp) == EOF) |
| 769 | goto free_then_fail; |
699 | 770 | } |
700 | | else /* fallback to /proc/self/mounts (/etc/mtab) if anything failed */ |
701 | | #endif /* MOUNTED_PROC_MOUNTINFO */ |
| 771 | else /* fallback to /proc/self/mounts (/etc/mtab). */ |
| 772 | #endif /* __linux __ */ |
702 | 773 | { |
703 | | FILE *fp; |
704 | 774 | struct mntent *mnt; |
705 | 775 | const char *table = MOUNTED; |
706 | 776 | |