[gparted] Fallback to reading mount command output instead of /etc/mtab (#723842)
- From: Curtis Gedak <gedakc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gparted] Fallback to reading mount command output instead of /etc/mtab (#723842)
- Date: Wed, 30 Jul 2014 17:35:08 +0000 (UTC)
commit 4b63e46a4ed7655a876875fc7d9bea01b3e91871
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date: Mon Apr 14 15:21:55 2014 +0100
Fallback to reading mount command output instead of /etc/mtab (#723842)
With linux 3.5 and later, the device used to mount a btrfs file system
is updated in /proc/mounts when the previous mounting device is removed
from the file system. Most recent distributions make /etc/mtab a
symbolic link to /proc/mounts. However some still have /etc/mtab as a
plain file only updated by mount and umount, thus showing the old device
name which is no longer part of the file system.
On Ubuntu 13.10, which has /etc/mtab as a plain file managed by mount
and umount:
# mkfs.btrfs /dev/sdb1
# mount /dev/sdb1 /mnt/1
# btrfs device add /dev/sdb2 /mnt/1
# btrfs device delete /dev/sdb1 /mnt/1
# sync
# btrfs filesystem show /dev/sdb1
# btrfs filesystem show /dev/sdb2
Label: none uuid: e47775a6-e5ad-4fb4-9ea4-1570aa5b4009
Total devices 2 FS bytes used 28.00KB
devid 2 size 2.00GB used 272.00MB path /dev/sdb2
# fgrep btrfs /proc/mounts
/dev/sdb2 /mnt/1 btrfs rw,relatime,space_cache 0 0
# ls -l /etc/mtab
-rw-r--r-- 1 root root 842 Apr 15 19:41 /etc/mtab
# fgrep btrfs /etc/mtab
/dev/sdb1 /mnt/1 btrfs rw 0 0
This causes GParted to report /dev/sdb1 as busy and mounted at /mnt/1
when it is no longer mounted. This effects recent releases of Ubuntu,
13.04, 13.10 and 14.04.
Either /etc/mtab is a symlink and is identical to /proc/mounts or
/etc/mtab is a plain file with wrong information. Fix by not reading
mounted file systems from /etc/mtab.
However old distributions only contain 'rootfs' and '/dev/root' device
names for the / (root) file system with '/dev/root' being a block device
rather than a symlink to the true device. For example from CentOS 5.x:
# fgrep ' / ' /proc/mounts
rootfs / rootfs rw 0 0
/dev/root / ext3 rw,data=ordered 0 0
# ls -l /dev/root
brw------- 1 root root 8, 3 Jun 4 2013 /dev/root
This prevents identification, and therefore busy detection, of the
device containing the / (root) file system. Used to read /etc/mtab to
get the root file system device name.
# fgrep ' / ' /etc/mtab
/dev/sda3 / ext3 rw 0 0
# ls -l /dev/sda3
brw-r----- 1 root disk 8, 3 Jun 4 2013 /dev/sda3
As per commit:
409096f739118af95e3bff4484fdedb7885c97a2
improved scanning for root mountpoint (/) ...
but, as discussed above, this contains an out of date device name after
the mounting device has been dynamically removed from a multi-device
btrfs, thus identifying the wrong device as busy. Instead fall back to
reading mounted file systems from the output of the mount command, but
only when required.
# mount | fgrep ' / '
/dev/sda3 on / type ext3 (rw)
Bug #723842 - GParted resizes the wrong filesystem (does not pass the
devid to btrfs filesystem resize)
include/GParted_Core.h | 11 ++++--
src/GParted_Core.cc | 92 ++++++++++++++++++++++++++++++++++++++----------
2 files changed, 80 insertions(+), 23 deletions(-)
---
diff --git a/include/GParted_Core.h b/include/GParted_Core.h
index ded7835..b51271b 100644
--- a/include/GParted_Core.h
+++ b/include/GParted_Core.h
@@ -70,11 +70,14 @@ private:
static void init_maps() ;
void set_thread_status_message( Glib::ustring msg ) ;
static void read_mountpoints_from_file( const Glib::ustring & filename,
- std::map< Glib::ustring,
- std::vector<Glib::ustring> > & map ) ;
+ std::map< Glib::ustring, std::vector<Glib::ustring> > & map )
;
+ static void add_node_and_mountpoint( std::map< Glib::ustring, std::vector<Glib::ustring> > & map,
+ Glib::ustring & node,
+ Glib::ustring & mountpoint ) ;
static void read_mountpoints_from_file_swaps( const Glib::ustring & filename,
- std::map< Glib::ustring,
- std::vector<Glib::ustring> > & map ) ;
+ std::map< Glib::ustring, std::vector<Glib::ustring> > &
map ) ;
+ static bool have_rootfs_dev( std::map< Glib::ustring, std::vector<Glib::ustring> > & map ) ;
+ static void read_mountpoints_from_mount_command( std::map< Glib::ustring, std::vector<Glib::ustring>
& map ) ;
Glib::ustring get_partition_path( PedPartition * lp_partition ) ;
void set_device_partitions( Device & device, PedDevice* lp_device, PedDisk* lp_disk ) ;
GParted::FILESYSTEM get_filesystem( PedDevice* lp_device, PedPartition* lp_partition,
diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc
index 755e9ba..16839c0 100644
--- a/src/GParted_Core.cc
+++ b/src/GParted_Core.cc
@@ -909,7 +909,20 @@ void GParted_Core::init_maps()
read_mountpoints_from_file( "/proc/mounts", mount_info ) ;
read_mountpoints_from_file_swaps( "/proc/swaps", mount_info ) ;
- read_mountpoints_from_file( "/etc/mtab", mount_info ) ;
+
+ if ( ! have_rootfs_dev( mount_info ) )
+ //Old distributions only contain 'rootfs' and '/dev/root' device names for
+ // the / (root) file system in /proc/mounts with '/dev/root' being a
+ // block device rather than a symlink to the true device. This prevents
+ // identification, and therefore busy detection, of the device containing
+ // the / (root) file system. Used to read /etc/mtab to get the root file
+ // system device name, but this contains an out of date device name after
+ // the mounting device has been dynamically removed from a multi-device
+ // btrfs, thus identifying the wrong device as busy. Instead fall back
+ // to reading mounted file systems from the output of the mount command,
+ // but only when required.
+ read_mountpoints_from_mount_command( mount_info ) ;
+
read_mountpoints_from_file( "/etc/fstab", fstab_info ) ;
//sort the mount points and remove duplicates.. (no need to do this for fstab_info)
@@ -940,6 +953,7 @@ void GParted_Core::read_mountpoints_from_file(
while ( (p = getmntent(fp)) != NULL )
{
Glib::ustring node = p->mnt_fsname ;
+ Glib::ustring mountpoint = p->mnt_dir ;
Glib::ustring uuid = Utils::regexp_label( node, "^UUID=(.*)" ) ;
if ( ! uuid .empty() )
@@ -950,28 +964,32 @@ void GParted_Core::read_mountpoints_from_file(
node = fs_info .get_path_by_label( label ) ;
if ( ! node .empty() )
- {
- Glib::ustring mountpoint = p->mnt_dir ;
+ add_node_and_mountpoint( map, node, mountpoint ) ;
+ }
- //Only add node path(s) if mount point exists
- if ( file_test( mountpoint, Glib::FILE_TEST_EXISTS ) )
- {
- map[ node ] .push_back( mountpoint ) ;
+ endmntent( fp ) ;
+}
- //If node is a symbolic link (e.g., /dev/root)
- // then find real path and add entry
- if ( file_test( node, Glib::FILE_TEST_IS_SYMLINK ) )
- {
- char c_str[4096+1] ;
- //FIXME: it seems realpath is very unsafe to use (manpage)...
- if ( realpath( node .c_str(), c_str ) != NULL )
- map[ c_str ] .push_back( mountpoint ) ;
- }
- }
+void GParted_Core::add_node_and_mountpoint(
+ std::map< Glib::ustring, std::vector<Glib::ustring> > & map,
+ Glib::ustring & node,
+ Glib::ustring & mountpoint )
+{
+ //Only add node path(s) if mount point exists
+ if ( file_test( mountpoint, Glib::FILE_TEST_EXISTS ) )
+ {
+ map[ node ] .push_back( mountpoint ) ;
+
+ //If node is a symbolic link (e.g., /dev/root)
+ // then find real path and add entry too
+ if ( file_test( node, Glib::FILE_TEST_IS_SYMLINK ) )
+ {
+ char c_str[4096+1] ;
+ //FIXME: it seems realpath is very unsafe to use (manpage)...
+ if ( realpath( node .c_str(), c_str ) != NULL )
+ map[ c_str ] .push_back( mountpoint ) ;
}
}
-
- endmntent( fp ) ;
}
void GParted_Core::read_mountpoints_from_file_swaps(
@@ -994,6 +1012,42 @@ void GParted_Core::read_mountpoints_from_file_swaps(
}
}
+//Return true only if the map contains a device name for the / (root) file system other
+// than 'rootfs' and '/dev/root'
+bool GParted_Core::have_rootfs_dev( std::map< Glib::ustring, std::vector<Glib::ustring> > & map )
+{
+ std::map< Glib::ustring, std::vector<Glib::ustring> >::iterator iter_mp ;
+ for ( iter_mp = mount_info .begin() ; iter_mp != mount_info .end() ; iter_mp ++ )
+ {
+ if ( ! iter_mp ->second .empty() && iter_mp ->second[ 0 ] == "/" )
+ {
+ if ( iter_mp ->first != "rootfs" && iter_mp ->first != "/dev/root" )
+ return true ;
+ }
+ }
+ return false ;
+}
+
+void GParted_Core::read_mountpoints_from_mount_command(
+ std::map< Glib::ustring, std::vector<Glib::ustring> > & map )
+{
+ Glib::ustring output ;
+ Glib::ustring error ;
+ if ( ! Utils::execute_command( "mount", output, error, true ) )
+ {
+ std::vector<Glib::ustring> lines ;
+ Utils::split( output, lines, "\n") ;
+ for ( unsigned int i = 0 ; i < lines .size() ; i ++ )
+ {
+ //Process line like "/dev/sda3 on / type ext4 (rw)"
+ Glib::ustring node = Utils::regexp_label( lines[ i ], "^([^[:blank:]]+) on " ) ;
+ Glib::ustring mountpoint = Utils::regexp_label( lines[ i ], "^[^[:blank:]]+ on
([^[:blank:]]+) " ) ;
+ if ( ! node .empty() )
+ add_node_and_mountpoint( map, node, mountpoint ) ;
+ }
+ }
+}
+
Glib::ustring GParted_Core::get_partition_path( PedPartition * lp_partition )
{
char * lp_path; //we have to free the result of ped_partition_get_path()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]