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

10 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')