gparted/include/FS_Info.h

66 lines
2 KiB
C
Raw Normal View History

/* Copyright (C) 2008, 2009, 2010 Curtis Gedak
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GPARTED_FS_INFO_H
#define GPARTED_FS_INFO_H
#include "BlockSpecial.h"
#include <glibmm/ustring.h>
#include <vector>
namespace GParted
{
struct FS_Entry
{
BlockSpecial path;
Glib::ustring type;
Glib::ustring sec_type;
Glib::ustring uuid;
bool have_label;
Glib::ustring label;
};
class FS_Info
{
public:
static void clear_cache();
Pass device and partition names to blkid (#131) A user reported that GParted would hang at "scanning all devices...", when a fully working disk was named on the command line, but another device on the machine was hung. This can be replicated like this: (on Ubuntu 20.04 LTS for it's NBD support) 1. Export and import NBD: # truncate -s 1G /tmp/disk-1G.img # nbd-server -C /dev/null 9000 /tmp/disk-1G.img # nbd-client localhost 9000 /dev/nbd0 2. Hang the NBD server and therefore /dev/nbd0: # killall -STOP nbd-server 3. Run GParted: $ gparted /dev/sda Tracing GParted shows that execution of blkid never returns. # strace -f -tt -q -bexecve -eexecve ./gpartedbin 2>&1 1> /dev/null | fgrep -v ENOENT ... [pid 37823] 13:56:24.814139 execve("/usr/sbin/mkudffs", ["mkudffs", "--help"], 0x55e2a3f2d230 /* 20 vars */ <detached ...> [pid 37814] 13:56:24.829246 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=37823, si_uid=0, si_status=1, si_utime=0, si_stime=0} --- [pid 37825] 13:56:25.376796 execve("/usr/sbin/blkid", ["blkid", "-v"], 0x55e2a3f2d230 /* 20 vars */ <detached ...> [pid 37824] 13:56:25.380824 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=37825, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- [pid 37826] 13:56:25.402512 execve("/usr/sbin/blkid", ["blkid"], 0x55e2a3f2d230 /* 20 vars */ <detached ...> Tracking of blkid shows that it hangs on either the open of or first read from /dev/nbd0. # strace blkid ... lstat("/dev", {st_mode=S_IFDIR|0755, st_size=4560, ...}) = 0 lstat("/dev/nbd0", {st_mode=S_IFBLK|0660, st_rdev=makedev(0x2b, 0), ...}) = 0 stat("/dev/nbd0", {st_mode=S_IFBLK|0660, st_rdev=makedev(0x2b, 0), ...}) = 0 lstat("/dev", {st_mode=S_IFDIR|0755, st_size=4560, ...}) = 0 lstat("/dev/nbd0", {st_mode=S_IFBLK|0660, st_rdev=makedev(0x2b, 0), ...}) = 0 access("/dev/nbd0", F_OK) = 0 stat("/dev/nbd0", {st_mode=S_IFBLK|0660, st_rdev=makedev(0x2b, 0), ...}) = 0 openat(AT_FDCWD, "/sys/dev/block/43:0", O_RDONLY|O_CLOEXEC) = 4 openat(4, "dm/uuid", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) close(4) = 0 openat(AT_FDCWD, "/dev/nbd0", O_RDONLY|O_CLOEXEC Clean up: 1. Resume NBD server: # killall -CONT nbd-server 2. Delete NBD setup: # nbd-client -d /dev/nbd0 # killall nbd-server # rm /tmp/disk-1G.img Fix this by making GParted specify the whole disk device and partition names that it is interested in to blkid, rather than letting blkid scan and report all block devices. Do this both when GParted determines the devices for itself and when they are named on the command line. Also update example blkid command output being parsed and cache value with this change to how blkid is executed. Closes #131 - GParted hangs when non-named device is hung
2021-01-24 14:33:04 +00:00
static void load_cache_for_paths(const std::vector<Glib::ustring>& paths);
static Glib::ustring get_fs_type( const Glib::ustring & path );
static Glib::ustring get_label( const Glib::ustring & path, bool & found );
static Glib::ustring get_uuid( const Glib::ustring & path );
static Glib::ustring get_path_by_uuid( const Glib::ustring & uuid );
static Glib::ustring get_path_by_label( const Glib::ustring & label );
private:
static bool not_initialised_then_error();
static void set_commands_found();
static const FS_Entry & get_cache_entry_by_path( const Glib::ustring & path );
static void run_blkid_load_cache(const std::vector<Glib::ustring>& paths);
Support /etc/fstab using Unicode labels as mount points (#786502) So far GParted is still loading the default non-reversible encoded labels from blkid in the initial loading of the FS_Info module cache. This encoded label is used to match LABEL=<label> when reading /etc/fstab, via the get_path_by_label() call, so works for ASCII only labels. This prevents GParted enabling the "mount on >" partition menu item when non-ASCII labels are used. To fix this: 1) Stop reading the labels the wrong way. Via the blkid command used to initially load the FS_Info module cache and is subject to default non-reversible encoding of non-printable ASCII bytes. 2) Read all the labels the right way, but only when needed. Only when /etc/fstab file contains LABEL=<label> and get_path_by_label() is called, read all the labels from blkid without encoding them via run_blkid_update_cache_one_label(). 3) Return label from the cache. get_label() returns the cached label, loading it into the cache first if needed with run_blkid_update_cache_one_label(). In the worst case scenario of having a LABEL=<label> in /etc/fstab blkid will be run for every partition containing a recognised file system to read the label. On my desktop with 5 hard drives, 4 SWRaid arrays and 31 recognised file systems running 'blkid -o value -s LABEL ...' 31 times took 0.074 seconds of a total scan time of 9.072 seconds. Less that 1% of the total scanning time. When LABEL=<label> is not used in /etc/fstab individual blkid executions are only used to read labels for file systems where there is no file system specific tool available reducing the impact further. Blkid itself caches the data in it's blkid.tab cache file rather than reading all file systems on each invocation. Also the Linux file system cache will already contain the blkid executable file, needed libraries files and the blkid.tab cache file itself. Hence why repeated execution of blkid is so fast. Further to the updated comment in set_partition_label_and_uuid(). Matching LABEL=<label> from /etc/fstab uses the label obtained from blkid run in the C locale so this kind of assumes it returns the label correctly and it does for my limited testing on Unicode enabled desktops. Just not sure if it would be true for all cases in all locales compared to the FS specific command run in the users default locale. Bug 786502 - Support reading Unicode labels when file system specific tools aren't available
2017-08-28 09:52:44 +00:00
static void update_fs_info_cache_all_labels();
static bool run_blkid_update_cache_one_label( FS_Entry & fs_entry );
static bool fs_info_cache_initialized ;
static bool blkid_found ;
Workaround older blkid not distinguishing between FAT16 and FAT32 (#743181) Older versions of blkid don't correctly distinguish between FAT16 and FAT32 file systems when overwriting one with the other. This effects GParted too with these file systems on whole disk devices where only blkid is used to recognise the contents. See previous fix for why only blkid is used in this case: Avoid whole disk FAT being detected as MSDOS partition table (#743181) Example: # blkid -v blkid from util-linux 2.20.1 (liblkid 2.20.0, 19-Oct-2011) # mkdosfs -F16 -I /dev/md1 # blkid | fgrep md1 /dev/md1: SEC_TYPE="msdos" UUID="7C23-95D9" TYPE="vfat" # mkdosfs -F32 -I /dev/md1 # blkid | fgrep md1 /dev/md1: SEC_TYPE="msdos" UUID="7F93-98F4" TYPE="vfat" So blkid recognised the UUID changed but didn't remove the SEC_TYPE for the FAT32 file system. See FS_Info::get_fs_type() as it uses this to distinguish between FAT16 and FAT32. This is a caching update bug in blkid, because telling blkid not to use the cache gets the right results: # blkid -c /dev/null | fgrep md1 /dev/md1: UUID="7F93-98F4" TYPE="vfat" With testing determined that blkid from util-linux 2.23 and later are not affected and earlier versions are affected. Mostly recently known affected distribution is Ubuntu 14.04 LTS with util-linux 2.20.1. The straight forward fix would be to instruct blkid to not use its cache with 'blkid -c /dev/null'. But using blkid's cache is needed to prevent blkid hanging for minutes when trying to access a non-existent floppy drive when the BIOS is set incorrectly. See commit: 18f863151c82934fe0a980853cc3deb1e439bec2 Fix long scan problem when BIOS floppy setting incorrect Instead, when using an older affected version of blkid and when blkid cache reports a vfat file system, run blkid again bypassing the cache. The device is known to exist and contain a vfat file system, just not whether it is a FAT16 or FAT32 file system, so can't be a non-existent floppy device and won't hang. Bug 743181 - Add unpartitioned drive read-write support
2015-03-08 11:13:20 +00:00
static bool need_blkid_vfat_cache_update_workaround;
static std::vector<FS_Entry> fs_info_cache;
};
}//GParted
#endif /* GPARTED_FS_INFO_H */