image-info: remove base loop device before analysing partitions
Instead of keeping the loop device of the base image and then opening each partition as a loop device, remove the original loop device of the base image and then create a loop device for each partition from the file itself using the partition offsets. The open_image() function is renamed to convert_image() and now only handles converting qcow2 files to raw files if necessary. The loop_open() context is done in analyse_image() instead, so that the base loop device can be closed without removing the converted image. This fixes the following issue with LVM partitions: When the same lvm partition UUID is on two devices (e.g., /dev/loop0p4 and /dev/loop1), the 'vgchange -ay' command fails with the following error: Cannot activate LVs in VG rootvg while PVs appear on duplicate devices. This happens when we open the LVM partition as a separate loop device, which we do for all partitions that we want to inspect. NB: It's possible to restrict the vgchange command to a specific device with --devices, but this isn't available in older versions of lvm2 (it was introduced in 2.03.11).
This commit is contained in:
parent
81e11c7946
commit
6dafa36fc7
1 changed files with 17 additions and 17 deletions
|
|
@ -70,7 +70,7 @@ def loop_open(ctl, image, *, offset=None, size=None):
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def open_image(ctl, image, fmt):
|
||||
def convert_image(ctl, image, fmt):
|
||||
with tempfile.TemporaryDirectory(dir="/var/tmp") as tmp:
|
||||
if fmt["type"] != "raw":
|
||||
target = os.path.join(tmp, "image.raw")
|
||||
|
|
@ -93,10 +93,7 @@ def open_image(ctl, image, fmt):
|
|||
else:
|
||||
target = image
|
||||
|
||||
size = os.stat(target).st_size
|
||||
|
||||
with loop_open(ctl, target, offset=0, size=size) as dev:
|
||||
yield target, dev
|
||||
yield target
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
|
|
@ -2556,7 +2553,7 @@ def partition_is_lvm(part: Dict) -> bool:
|
|||
return part["type"].upper() in ["E6D6D379-F507-44C2-A23C-238F2A3DF928", "8E"]
|
||||
|
||||
|
||||
def append_partitions(report, device, loctl):
|
||||
def append_partitions(report, image, loctl):
|
||||
partitions = report["partitions"]
|
||||
|
||||
with contextlib.ExitStack() as cm:
|
||||
|
|
@ -2564,7 +2561,7 @@ def append_partitions(report, device, loctl):
|
|||
filesystems = {}
|
||||
for part in partitions:
|
||||
start, size = part["start"], part["size"]
|
||||
dev = cm.enter_context(loop_open(loctl, device, offset=start, size=size))
|
||||
dev = cm.enter_context(loop_open(loctl, image, offset=start, size=size))
|
||||
read_partition(dev, part)
|
||||
if partition_is_lvm(part):
|
||||
lvm = cm.enter_context(discover_lvm(dev))
|
||||
|
|
@ -2630,17 +2627,20 @@ def analyse_image(image):
|
|||
imgfmt = read_image_format(image)
|
||||
report = {"image-format": imgfmt}
|
||||
|
||||
with open_image(loctl, image, imgfmt) as (_, device):
|
||||
report["bootloader"] = read_bootloader_type(device)
|
||||
report.update(read_partition_table(device))
|
||||
with convert_image(loctl, image, imgfmt) as target:
|
||||
size = os.stat(target).st_size
|
||||
with loop_open(loctl, target, offset=0, size=size) as device:
|
||||
report["bootloader"] = read_bootloader_type(device)
|
||||
report.update(read_partition_table(device))
|
||||
if not report["partition-table"]:
|
||||
# no partition table: mount device and treat it as a partition
|
||||
with mount(device) as tree:
|
||||
append_filesystem(report, tree)
|
||||
return report
|
||||
|
||||
if report["partition-table"]:
|
||||
append_partitions(report, device, loctl)
|
||||
else:
|
||||
with mount(device) as tree:
|
||||
append_filesystem(report, tree)
|
||||
|
||||
return report
|
||||
# close loop device and descend into partitions on image file
|
||||
append_partitions(report, target, loctl)
|
||||
return report
|
||||
|
||||
|
||||
def append_directory(report, tree):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue