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:
409096f739
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)
This commit is contained in:
parent
d47783eff8
commit
4b63e46a4e
|
@ -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,
|
||||
|
|
|
@ -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,30 +964,34 @@ void GParted_Core::read_mountpoints_from_file(
|
|||
node = fs_info .get_path_by_label( label ) ;
|
||||
|
||||
if ( ! node .empty() )
|
||||
{
|
||||
Glib::ustring mountpoint = p->mnt_dir ;
|
||||
|
||||
//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
|
||||
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 ) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
add_node_and_mountpoint( map, node, mountpoint ) ;
|
||||
}
|
||||
|
||||
endmntent( fp ) ;
|
||||
}
|
||||
|
||||
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 ) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GParted_Core::read_mountpoints_from_file_swaps(
|
||||
const Glib::ustring & filename,
|
||||
std::map< Glib::ustring, std::vector<Glib::ustring> > & map )
|
||||
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue