From 0764270c85c7b1d1bfb2020e244182dda73def7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20Sch=C3=A4fer?= Date: Wed, 22 Apr 2026 08:41:01 +0200 Subject: [PATCH] Do not manually edit the grubenv file Make sure to use grub2-editenv for changing content in the grub env blob. This Fixes #2986 --- kiwi/bootloader/config/grub2.py | 37 +++++++++-------------- test/unit/bootloader/config/grub2_test.py | 16 ++++------ 2 files changed, 20 insertions(+), 33 deletions(-) diff --git a/kiwi/bootloader/config/grub2.py b/kiwi/bootloader/config/grub2.py index 841f7acfbb6..4a7010bea00 100644 --- a/kiwi/bootloader/config/grub2.py +++ b/kiwi/bootloader/config/grub2.py @@ -24,6 +24,7 @@ import glob import shutil from collections import OrderedDict +from typing import List # project from kiwi.bootloader.config.base import BootLoaderConfigBase @@ -291,7 +292,9 @@ def setup_disk_image_config( ] ) # Setup/Update loader environment - self._setup_loader_variables() + self._setup_loader_variables( + self.xml_state.get_build_type_bootloader_environment_variables() + ) # Disable os-prober, it takes information from the host it # runs on which is not necessarily matching with the image @@ -1572,16 +1575,7 @@ def _fix_grub_root_device_reference(self, config_file, boot_options): vendor_grubenv_file = \ Defaults.get_vendor_grubenv(self.efi_mount.mountpoint) if vendor_grubenv_file: - with open(vendor_grubenv_file) as vendor_grubenv: - grubenv = vendor_grubenv.read() - grubenv = grubenv.replace( - 'root={0}'.format( - boot_options.get('root_device') - ), - self.root_reference - ) - with open(vendor_grubenv_file, 'w') as vendor_grubenv: - vendor_grubenv.write(grubenv) + self._setup_loader_variables([self.root_reference]) def _fix_grub_loader_entries_boot_cmdline(self): if self.cmdline: @@ -1753,18 +1747,15 @@ def _has_btrfs_relative_path(self) -> bool: return True return False - def _setup_loader_variables(self): + def _setup_loader_variables(self, variable_list: List[str]): """ Run grub2-editenv for writing an updated environment blob """ - if self.root_mount: - variable_list = \ - self.xml_state.get_build_type_bootloader_environment_variables() - if variable_list: - log.info(f'Set grub environment variables: {variable_list}') - Command.run( - [ - 'chroot', self.root_mount.mountpoint, - 'grub2-editenv', '-', 'set' - ] + variable_list - ) + if self.root_mount and variable_list: + log.info(f'Set grub environment variables: {variable_list}') + Command.run( + [ + 'chroot', self.root_mount.mountpoint, + 'grub2-editenv', '-', 'set' + ] + variable_list + ) diff --git a/test/unit/bootloader/config/grub2_test.py b/test/unit/bootloader/config/grub2_test.py index 2741d61f549..2f5b7f139e2 100644 --- a/test/unit/bootloader/config/grub2_test.py +++ b/test/unit/bootloader/config/grub2_test.py @@ -1196,15 +1196,12 @@ def test_setup_disk_image_config( with patch('builtins.open', create=True) as mock_open: mock_open_grub = MagicMock(spec=io.IOBase) mock_open_menu = MagicMock(spec=io.IOBase) - mock_open_grubenv = MagicMock(spec=io.IOBase) def open_file(filename, mode=None): if filename == 'root_mount_point/boot/grub2/grub.cfg': return mock_open_grub.return_value elif filename == 'some_entry.conf': return mock_open_menu.return_value - elif filename == 'grubenv': - return mock_open_grubenv.return_value mock_open.side_effect = open_file @@ -1212,13 +1209,10 @@ def open_file(filename, mode=None): mock_open_grub.return_value.__enter__.return_value file_handle_menu = \ mock_open_menu.return_value.__enter__.return_value - file_handle_grubenv = \ - mock_open_grubenv.return_value.__enter__.return_value file_handle_grub.read.return_value = \ 'root=rootdev nomodeset console=ttyS0 console=tty0\n' \ 'root=PARTUUID=xx' - file_handle_grubenv.read.return_value = 'root=rootdev' file_handle_menu.read.return_value = \ 'options foo\nlinux unexpected/boot/vmlinuz\ninitrd /boot/initrd' self.bootloader.xml_state.\ @@ -1252,6 +1246,12 @@ def open_file(filename, mode=None): 'bash', '-c', 'cd root_mount_point/boot && rm -f boot && ln -s . boot' ], raise_on_error=False + ), + call( + [ + 'chroot', self.bootloader.root_mount.mountpoint, + 'grub2-editenv', '-', 'set', 'root=overlay:UUID=ID' + ] ) ] mock_copy_grub_config_to_efi_path.assert_called_once_with( @@ -1262,9 +1262,6 @@ def open_file(filename, mode=None): '\n' 'root=overlay:UUID=ID' ) - file_handle_grubenv.write.assert_called_once_with( - 'root=overlay:UUID=ID' - ) assert 'options some-cmdline root=UUID=foo' in \ file_handle_menu.write.call_args_list[0][0][0].split(os.linesep) assert 'linux /boot/vmlinuz' in \ @@ -1304,7 +1301,6 @@ def open_file(filename, mode=None): # test read-only device file_handle_grub.write.side_effect = OSError('readonly system') - file_handle_grubenv.write.side_effect = OSError('readonly system') file_handle_menu.write.side_effect = OSError('readonly system') with self._caplog.at_level(logging.INFO):