You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
4.0 KiB

9 months ago
import os
from leapp.exceptions import StopActorExecution
from leapp.libraries.common import mdraid
from leapp.libraries.stdlib import api, CalledProcessError, run
from leapp.utils.deprecation import deprecated
def has_grub(blk_dev):
"""
Check whether GRUB is present on block device
"""
try:
blk = os.open(blk_dev, os.O_RDONLY)
mbr = os.read(blk, 512)
except OSError:
api.current_logger().warning(
'Could not read first sector of {} in order to identify the bootloader'.format(blk_dev)
)
raise StopActorExecution()
os.close(blk)
test = 'GRUB'
if not isinstance(mbr, str):
test = test.encode('utf-8')
return test in mbr
def blk_dev_from_partition(partition):
"""
Find parent device of /boot partition
"""
try:
result = run(['lsblk', '-spnlo', 'name', partition])
except CalledProcessError:
api.current_logger().warning(
'Could not get parent device of {} partition'.format(partition)
)
raise StopActorExecution()
# lsblk "-s" option prints dependencies in inverse order, so the parent device will always
# be the last or the only device.
# Command result example:
# 'result', {'signal': 0, 'pid': 3872, 'exit_code': 0, 'stderr': u'', 'stdout': u'/dev/vda1\n/dev/vda\n'}
return result['stdout'].strip().split()[-1]
def get_boot_partition():
"""
Get /boot partition name.
"""
try:
# call grub2-probe to identify /boot partition
result = run(['grub2-probe', '--target=device', '/boot'])
except CalledProcessError:
api.current_logger().warning(
'Could not get name of underlying /boot partition'
)
raise StopActorExecution()
except OSError:
api.current_logger().warning(
'Could not get name of underlying /boot partition:'
' grub2-probe is missing.'
' Possibly called on system that does not use GRUB2?'
)
raise StopActorExecution()
boot_partition = result['stdout'].strip()
api.current_logger().info('/boot is on {}'.format(boot_partition))
return boot_partition
def get_grub_devices():
"""
Get block devices where GRUB is located. We assume GRUB is on the same device
as /boot partition is. In case that device is an md (Multiple Device) device, all
of the component devices of such a device are considered.
:return: Devices where GRUB is located
:rtype: list
"""
boot_device = get_boot_partition()
devices = []
if mdraid.is_mdraid_dev(boot_device):
component_devs = mdraid.get_component_devices(boot_device)
blk_devs = [blk_dev_from_partition(dev) for dev in component_devs]
# remove duplicates as there might be raid on partitions on the same drive
# even if that's very unusual
devices = sorted(list(set(blk_devs)))
else:
devices.append(blk_dev_from_partition(boot_device))
have_grub = [dev for dev in devices if has_grub(dev)]
api.current_logger().info('GRUB is installed on {}'.format(",".join(have_grub)))
return have_grub
@deprecated(since='2023-06-23', message='This function has been replaced by get_grub_devices')
def get_grub_device():
"""
Get block device where GRUB is located. We assume GRUB is on the same device
as /boot partition is.
"""
boot_partition = get_boot_partition()
grub_dev = blk_dev_from_partition(boot_partition)
api.current_logger().info('GRUB is installed on {}'.format(grub_dev))
# if has_grub(grub_dev):
return grub_dev if has_grub(grub_dev) else None
def is_blscfg_enabled_in_defaultgrub(default_grub_msg):
"""
Check if GRUB_ENABLE_BLSCFG is true in /etc/default/grub file
"""
grub_options_lst = default_grub_msg.default_grub_info
default_grub_options = {
option.name: option.value.strip('"') for option in grub_options_lst
}
return bool(default_grub_options.get('GRUB_ENABLE_BLSCFG', '') == 'true')