On Mon, Mar 11, 2024 at 07:32:30PM +0200, Andrey Drobyshev wrote:
On 3/7/24 16:27, Richard W.M. Jones wrote:
> On Thu, Feb 29, 2024 at 05:37:08PM +0200, Andrey Drobyshev wrote:
>> I discovered that when a VM has an ISO attached via CD-ROM, libguestfs
>> fails to read its partition table and therefore fails to perform basic
>> operations on a VM, e.g. listing a directory or editing a file:
>>
>> # virsh domblklist rocky9-vm
>> Target Source
>> ---------------------------------------------------------------------------
>> sda /vz/vmprivate/e827caad-b9e4-4858-b3dc-53ae6b8a5145/harddisk.hdd
>> sdb /vzt/images/Rocky-9.3-x86_64-minimal.iso
>
> [Download the ISO from here:
https://rockylinux.org/download/]
We had a bit of a discussion here about this image, which we think is
a Hybrid ISO generated by either this exact tool or a similar one:
https://wiki.syslinux.org/wiki/index.php?title=Isohybrid
The image contains ISO with MBR + GPT partition table. For some
reason sgdisk cannot seem to read the GPT partition table properly, so
either it's badly formatted or maybe there is a bug in sgdisk:
This hybrid ISO image:
$ file /var/tmp/Rocky-9.3-x86_64-minimal.iso
/var/tmp/Rocky-9.3-x86_64-minimal.iso: ISO 9660 CD-ROM filesystem data (DOS/MBR boot
sector) 'Rocky-9-3-x86_64-dvd' (bootable)
Just some regular ISO:
$ file /mnt/media/software/vmware/VMware-VCSA-all-7.0.0-15952498.iso
/mnt/media/software/vmware/VMware-VCSA-all-7.0.0-15952498.iso: ISO 9660 CD-ROM
filesystem data 'VMware VCSA'
Linux kernel and sfdisk can parse the MBR:
$ virt-rescue --ro -a /var/tmp/Rocky-9.3-x86_64-minimal.iso
<rescue> dmesg | grep sda:
[ 0.520088] sda: sda1
sda2
$ sfdisk -l /var/tmp/Rocky-9.3-x86_64-minimal.iso
Disk /var/tmp/Rocky-9.3-x86_64-minimal.iso: 1.57 GiB, 1686568960 bytes, 3294080 sectors
...
Device Boot Start End Sectors Size Id Type
/var/tmp/Rocky-9.3-x86_64-minimal.iso1 * 0 3293407 3293408 1.6G 0 Empty
/var/tmp/Rocky-9.3-x86_64-minimal.iso2 664 14851 14188 6.9M ef EFI (
But sgdisk cannot:
$ sgdisk /var/tmp/Rocky-9.3-x86_64-minimal.iso -i 1
Invalid partition data!
I just wonder if a better way to do this is to ignore partitions that
appear on a hybrid ISO by actually detecting hybrid ISO as a specific
format (rather than hard coding "iso9660" or "udf").
Your patch tries to modify list_filesystems, but this could also be
done in list_partitions.
Still thinking about this ... Do we have a bug about it?
I think a key issue is why does sgdisk not recognise the
partition table.
Rich.
>> # virt-ls -d rocky9-vm /
>> libguestfs: error: inspect_os: sgdisk: Invalid partition data!
>>
>> # virt-edit -d rocky9-vm /etc/fstab
>> libguestfs: error: inspect_os: sgdisk: Invalid partition data!
>>
>>
>> Even virt-inspector can't give us proper output on an ISO9660 image:
>>
>> # virt-inspector /vzt/images/Rocky-9.3-x86_64-minimal.iso
>> libguestfs: error: inspect_os: sgdisk: Invalid partition data!
>> virt-inspector: no operating system could be detected inside this disk
>> image.
>> ...
>>
>>
>> First I found a 3 years old topic where you suggested that sgdisk itself
>> might be too old:
>>
https://listman.redhat.com/archives/libguestfs/2021-March/025939.html.
>> However this doesn't seem to be it in this case:
>> I've compiled the latest version from
>>
https://sourceforge.net/projects/gptfdisk -- no luck as well. Seems
>> that sgdisk isn't capable of recognizing ISO9660 images.
>>
>> Then I noticed 2 things:
>>
>> 1. libguestfs appliance is being created (with backend=libvirt) with ISO
>> attached as device='disk' (not 'cdrom'):
>>
>>> <disk type='file' device='disk'>
>>> <driver name='qemu' type='qcow2'
cache='unsafe'/>
>>> <source file='/tmp/libguestfsD7IHvF/overlay2.qcow2'
index='2'/>
>>> <backingStore type='file' index='5'>
>>> <format type='raw'/>
>>> <source
file='/vzt/images/Rocky-9.3-x86_64-minimal.iso'/>
>>> <backingStore/>
>>> </backingStore>
>>> <target dev='sdb' bus='scsi'/>
>>> <alias name='scsi0-0-1-0'/>
>>> <address type='drive' controller='0'
bus='0' target='1' unit='0'/>
>>> </disk>
>>
>> That forces this disk to be supplied with "scsi-hd" driver in use,
which
>> in turn leads to the device being visible inside the guest as a regular
>> SCSI hdd /dev/sdb. Shouldn't we, for instance, make sure that for such
>> images device='cdrom' and "scsi-cd" driver are being used? In
this case
>> the guest will see it as /dev/sr0, and I suspect srX devices are being
>> skipped by guestfs_inspect_os.
>
> I think /dev/srX would not be ignored:
>
>
https://github.com/libguestfs/libguestfs/blob/729d6d55ea84494f0398d02450b...
>
> But anyway I don't think that's the problem here. We try to present
> any disk image (even an ISO) as a regular disk to the libguestfs
> appliance. That's because we don't need or care about the special
> features of /dev/srX like the ability to eject a disk.
>
> I think the central problem is why libguestfs cannot inspect the ISO.
>
> $ virt-inspector -a Rocky-9.3-x86_64-minimal.iso
> libguestfs: error: inspect_os: sgdisk: Invalid partition data!
> virt-inspector: no operating system could be detected inside this disk image.
>
> $ guestfish --ro -a Rocky-9.3-x86_64-minimal.iso -i
> libguestfs: error: inspect_os: sgdisk: Invalid partition data!
>
> etc
>
> Adding -vx options shows the problem is with sgdisk:
>
> command: sgdisk returned 2
> command: sgdisk: stderr:
> Invalid partition data!
> ocaml_exn: 'inspect_os' raised 'Failure' exception
> guestfsd: error: sgdisk: Invalid partition data!
> guestfsd: => inspect_os (0x1e0) took 0.13 secs
>
> I believe this comes from:
>
>
https://github.com/libguestfs/libguestfs/blob/729d6d55ea84494f0398d02450b...
>
> I modified the error message in this file to see what it's trying to
> do and it comes from the call to 'part_get_gpt_type'.
>
> I think it's a regression in commit b699111e04.
>
Just to be accurate here: commit b699111e04 ("daemon: list-filesystems:
Filter out MBR extended partitions.") hasn't introduced the call to
Parted.part_get_gpt_type, it was done by the commit 16192ad95 ("daemon:
list-filesystems: Change the way we filter out LDM partitions.") coming
from the same series.
> Do you want to try the attached patch?
>
Thank you, I've tried the patch and ignoring the sgdisk error does help
to overcome the failure when working with domains having an ISO
attached. However I'm not convinced that simply ignoring the error is
the right thing to do: what if there's an error on other than ISO, where
we do indeed want to be aware of it? I think we should rather make an
exception for a CD/DVD images.
AFAIU ISO9660 images', as well as UDF images' structures aren't supposed
to have partition tables. Rather these formats fool tools like sgdisk,
parted etc. into thinking there're actual partition tables. If so, why
don't we just skip listing separate partitions and look at the image as
a whole when listing file systems. What do you think of the attached patch?
> Note this still won't allow the ISO to be inspected, but it avoids the
> "Invalid partition data!" error, and maybe will cure the original
> problem above.
>
You're right, inspection still doesn't work properly (with my patch as
well). Now the commands fail further:
$ guestfish --ro -a /vzt/images/Rocky-9.3-x86_64-minimal.iso -i
guestfish: no operating system was found on this disk
If using guestfish ‘-i’ option, remove this option and instead
use the commands ‘run’ followed by ‘list-filesystems’.
You can then mount filesystems you want by hand using the
‘mount’ or ‘mount-ro’ command.
.....
$ virt-ls -a /vzt/images/Rocky-9.3-x86_64-minimal.iso /
virt-ls: no operating system was found on this disk
If using guestfish ‘-i’ option, remove this option and instead
use the commands ‘run’ followed by ‘list-filesystems’.
You can then mount filesystems you want by hand using the
‘mount’ or ‘mount-ro’ command.
.....
That seems to be because there's no <root> element in the inspection result:
$ virt-inspector -a /vzt/images/Rocky-9.3-x86_64-minimal.iso
<?xml version="1.0"?>
<operatingsystems/>
Shouldn't we tweak inspect_get_roots() (from daemon/inspect.ml) to
recognize ISO9660 as well?
>> 2. When trying to perform the same operation via guestfish, everything
>> appears to be working:
>>
>> # guestfish -a /vzt/images/Rocky-9.3-x86_64-minimal.iso -m /dev/sda ls /
>>> /dev/null && echo $?
>> 0
>
> I think this is just because we're avoiding inspection?
>
>> File edit works as well. From debug output I see that sgdisk isn't
>> being invoked at all. That means there's a code path for the same
>> operations where sgdisk can be omitted. Maybe we should follow that
>> same code path when invoking other tools like virt-ls or virt-edit?
>>
>>
>> Overall, what would be an appropriate fix in your opinion? We should at
>> least make sure that working with domains (with the "-d" option)
works
>> no matter what.
>>
>> Andrey
>
> Rich.
>
From 2a703ca4abb93fce76985afc34052e1372939ba0 Mon Sep 17 00:00:00
2001
From: Andrey Drobyshev <andrey.drobyshev(a)virtuozzo.com>
Date: Mon, 11 Mar 2024 19:13:26 +0200
Subject: [PATCH] daemon: listfs: Ignore partitions when dealing with ISO9660
or UDF
ISO9660 or UDF images (CD/DVD) don't really have partition table,
however tools like sgdisk might think otherwise. Currently when working
with a domain having a cdrom attached, we get:
$ virt-ls -d VM /
guestfsd: error: sgdisk: Invalid partition data!
Let's detect filesystem type of such a block device (with blkid) and
treat it as a whole in case it has type "iso9660" or "udf", e.g.
ignoring what appears to be separate partitions.
Signed-off-by: Andrey Drobyshev <andrey.drobyshev(a)virtuozzo.com>
---
daemon/listfs.ml | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/daemon/listfs.ml b/daemon/listfs.ml
index 3c6e86fa5..15422be78 100644
--- a/daemon/listfs.ml
+++ b/daemon/listfs.ml
@@ -43,8 +43,17 @@ let rec list_filesystems () =
let devices = List.filter is_not_partitioned_device devices in
List.iter (check_with_vfs_type ret) devices;
+ (* CD or DVD devices (ISO9660 or UDF).
+ * We want to treat such devices as a whole, even if it appears
+ * to have a partition table.
+ *)
+ let devices = Devsparts.list_devices () in
+ let devices = List.filter is_device_cd_or_dvd devices in
+ List.iter (check_with_vfs_type ret) devices;
+
(* Partitions. *)
let partitions = Devsparts.list_partitions () in
+ let partitions = List.filter is_not_fake_cd_or_dvd_partition partitions in
let partitions = List.filter is_partition_can_hold_filesystem partitions in
List.iter (check_with_vfs_type ret) partitions;
@@ -138,11 +147,7 @@ and is_mbr_extended parttype device partnum =
and is_mbr_bogus parttype device partnum =
parttype = "msdos" && partnum = 1 && Utils.has_bogus_mbr
device
-(* Use vfs-type to check for a filesystem of some sort of [device].
- * Appends (device, vfs_type) to the ret parameter (there may be
- * multiple devices found in the case of btrfs).
- *)
-and check_with_vfs_type ret device =
+and device_to_mountable_vfstype device =
let mountable = Mountable.of_device device in
let vfs_type =
try Blkid.vfs_type mountable
@@ -151,6 +156,22 @@ and check_with_vfs_type ret device =
eprintf "check_with_vfs_type: %s: %s\n"
device (Printexc.to_string exn);
"" in
+ (mountable, vfs_type)
+
+and is_device_cd_or_dvd device =
+ let mountable, vfs_type = device_to_mountable_vfstype device in
+ vfs_type = "iso9660" || vfs_type = "udf"
+
+and is_not_fake_cd_or_dvd_partition partition =
+ let device = Devsparts.part_to_dev partition in
+ not (is_device_cd_or_dvd device)
+
+(* Use vfs-type to check for a filesystem of some sort of [device].
+ * Appends (device, vfs_type) to the ret parameter (there may be
+ * multiple devices found in the case of btrfs).
+ *)
+and check_with_vfs_type ret device =
+ let mountable, vfs_type = device_to_mountable_vfstype device in
if vfs_type = "" then
List.push_back ret (mountable, "unknown")
--
2.39.3
--
Richard Jones, Virtualization Group, Red Hat
http://people.redhat.com/~rjones
Read my programming and virtualization blog:
http://rwmj.wordpress.com
virt-top is 'top' for virtual machines. Tiny program with many
powerful monitoring features, net stats, disk stats, logging, etc.
http://people.redhat.com/~rjones/virt-top