Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supporting Grub2-BLS #708

Open
wants to merge 45 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
009d051
supporting Grub2-BLS
schubi2 Nov 14, 2024
ee16502
no fallbacks
schubi2 Nov 14, 2024
c639282
fixed testcases
schubi2 Nov 14, 2024
3111016
fixed testcases
schubi2 Nov 14, 2024
953b4c8
evaluate grub2-bls architectures
schubi2 Nov 14, 2024
96d5b8b
evaluate grub2-bls architectures
schubi2 Nov 14, 2024
6fb8f2d
cleanup
schubi2 Nov 15, 2024
6f3a891
cleanup
schubi2 Nov 15, 2024
008cd03
fixed timeout
schubi2 Nov 18, 2024
672aa02
no bls switching
schubi2 Nov 18, 2024
5da518c
set textdomain
schubi2 Nov 19, 2024
74405e7
set textdomain
schubi2 Nov 19, 2024
c3e3c78
switching not allowed
schubi2 Nov 19, 2024
ea93f6a
taking get-* from sdbootutil
schubi2 Nov 26, 2024
011839c
using sdbootutil in systemd-boot
schubi2 Nov 26, 2024
556a3db
timeout to integer
schubi2 Nov 26, 2024
c88b468
not needed CFS::systemdboot
schubi2 Nov 26, 2024
e450381
not needed CFS::systemdboot
schubi2 Nov 26, 2024
c7b49e8
not needed CFS::systemdboot
schubi2 Nov 26, 2024
184d261
fixed testcases
schubi2 Nov 26, 2024
e83fe23
fixed testcase
schubi2 Nov 26, 2024
b631d24
added translation comments
schubi2 Nov 26, 2024
fac9383
cleanup
schubi2 Nov 27, 2024
18cd79d
cleanup
schubi2 Nov 27, 2024
5a2e0a1
cleanup
schubi2 Nov 27, 2024
2b7dce0
cleanup
schubi2 Nov 27, 2024
c148516
cleanup
schubi2 Nov 27, 2024
dec55e0
cleanup
schubi2 Nov 27, 2024
d18e621
cleanup
schubi2 Nov 27, 2024
3511190
fixed Execute.on_target
schubi2 Nov 27, 2024
9a340a9
fixed testcase
schubi2 Nov 27, 2024
369f44f
pmbr for bls
schubi2 Nov 27, 2024
fc00345
pmbr for bls
schubi2 Nov 27, 2024
5789f8d
fixed testcase
schubi2 Nov 28, 2024
054b256
cleanup
schubi2 Nov 28, 2024
bbc87d5
activate pmbr for bls
schubi2 Nov 28, 2024
078bde4
cleanup testcases
schubi2 Nov 28, 2024
8c241ec
merging pmbr
schubi2 Nov 29, 2024
0f8a518
making PMBRWidget general
schubi2 Nov 29, 2024
88e8aeb
making PMBRWidget general
schubi2 Nov 29, 2024
d71a689
add pmbr to systemd-boot
schubi2 Nov 29, 2024
b936d0e
fixed testcase
schubi2 Nov 29, 2024
aad7340
fixed testcase
schubi2 Nov 29, 2024
9dd4b63
fixed proposal
schubi2 Dec 17, 2024
eba3bdf
fixed proposal
schubi2 Dec 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ that holds and also can propose the bootloader implementation. So now let's expl

- [GRUB2](https://www.rubydoc.info/github/yast/yast-bootloader/master/Bootloader/Grub2) for legacy booting or emulated grub2 boot like s390x.
- [GRUB2-EFI](https://www.rubydoc.info/github/yast/yast-bootloader/master/Bootloader/Grub2EFI) for EFI variant of GRUB2 bootloader
- [GRUB2-BLS](https://www.rubydoc.info/github/yast/yast-bootloader/master/Bootloader/Grub2Bls) bootloader based on Boot Loader Specification(BLS) (for EFI only)
- [systemd-boot](https://www.rubydoc.info/github/yast/yast-bootloader/master/Bootloader/SystemdBoot) systemd bootloader (for EFI only)
- [None](https://www.rubydoc.info/github/yast/yast-bootloader/master/Bootloader/NoneBootloader) when YaST does not manage booting
- [GRUB2 base](https://www.rubydoc.info/github/yast/yast-bootloader/master/Bootloader/Grub2Base) is the shared functionality for both GRUB2 implementations
Expand Down
1,490 changes: 446 additions & 1,044 deletions doc/bootloader_backend.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions package/yast2-bootloader.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
-------------------------------------------------------------------
Wed Nov 13 16:28:04 UTC 2024 - Stefan Schubert <[email protected]>

- Added grub2-bls support (jsc#PED-10703).
- 5.0.13

-------------------------------------------------------------------
Tue Nov 5 09:57:58 UTC 2024 - Josef Reidinger <[email protected]>

Expand Down
2 changes: 1 addition & 1 deletion package/yast2-bootloader.spec
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@


Name: yast2-bootloader
Version: 5.0.12
Version: 5.0.13
Release: 0
Summary: YaST2 - Bootloader Configuration
License: GPL-2.0-or-later
Expand Down
26 changes: 14 additions & 12 deletions src/lib/bootloader/autoyast_converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,18 @@ def import(data)
return bootloader if bootloader.name == "none"

case bootloader.name
when "grub2", "grub2-efi"
import_grub2(data, bootloader)
import_grub2efi(data, bootloader)
import_stage1(data, bootloader)
when "grub2", "grub2-efi", "grub2-bls"
if ["grub2", "grub2-efi"].include?(bootloader.name)
import_grub2(data, bootloader)
import_grub2efi(data, bootloader)
import_stage1(data, bootloader)
import_device_map(data, bootloader)
import_password(data, bootloader)
# always nil pmbr as autoyast does not support it yet,
# so use nil to always use proposed value (bsc#1081967)
bootloader.pmbr_action = nil
end
import_default(data, bootloader.grub_default)
import_device_map(data, bootloader)
import_password(data, bootloader)
# always nil pmbr as autoyast does not support it yet,
# so use nil to always use proposed value (bsc#1081967)
bootloader.pmbr_action = nil
cpu_mitigations = data.global.cpu_mitigations
if cpu_mitigations
bootloader.cpu_mitigations = CpuMitigations.from_string(cpu_mitigations)
Expand Down Expand Up @@ -72,18 +74,18 @@ def export(config)
res["global"] = {}

case config.name
when "grub2", "grub2-efi"
when "grub2", "grub2-efi", "grub2-bls"
global = res["global"]
export_grub2(global, config) if config.name == "grub2"
export_grub2efi(global, config) if config.name == "grub2-efi"
export_password(global, config.password) if ["grub2", "grub2-efi"].include?(config.name)
export_default(global, config.grub_default)
export_password(global, config.password)
res["global"]["cpu_mitigations"] = config.cpu_mitigations.value.to_s
when "systemd-boot"
res["global"]["timeout"] = config.menu_timeout
res["global"]["secure_boot"] = config.secure_boot
else
raise UnsupportedBootloader, bootloader.name
raise UnsupportedBootloader, config.name
end
# Do not export device map as device name are very unpredictable and is used only as
# work-around when automatic ones do not work for what-ever reasons ( it can really safe
Expand Down
69 changes: 69 additions & 0 deletions src/lib/bootloader/bls.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# frozen_string_literal: true

require "fileutils"
require "yast"
require "bootloader/sysconfig"
require "bootloader/cpu_mitigations"
require "cfa/grub2/default"

Yast.import "Report"

module Bootloader
# Represents bls compatile system calls which can be used
# e.g. by grub2-bls and systemd-boot
class Bls
include Yast::Logger
include Yast::I18n

SDBOOTUTIL = "/usr/bin/sdbootutil"

def self.create_menu_entries
Yast::Execute.on_target!(SDBOOTUTIL, "--verbose", "add-all-kernels")
rescue Cheetah::ExecutionFailed => e
Yast::Report.Error(
format(_(
"Cannot create boot menu entry:\n" \
"Command `%{command}`.\n" \
"Error output: %{stderr}"
), command: e.commands.inspect, stderr: e.stderr)
)
end

def self.install_bootloader
Yast::Execute.on_target!(SDBOOTUTIL, "--verbose",
"install")
rescue Cheetah::ExecutionFailed => e
Yast::Report.Error(
format(_(
"Cannot install bootloader:\n" \
"Command `%{command}`.\n" \
"Error output: %{stderr}"
), command: e.commands.inspect, stderr: e.stderr)
)
end

def self.write_menu_timeout(timeout)
Yast::Execute.on_target(SDBOOTUTIL, "set-timeout", timeout)
schubi2 marked this conversation as resolved.
Show resolved Hide resolved
rescue Cheetah::ExecutionFailed => e
Yast::Report.Error(
format(_(
"Cannot write boot menu timeout:\n" \
"Command `%{command}`.\n" \
"Error output: %{stderr}"
), command: e.commands.inspect, stderr: e.stderr)
)
end

def self.write_default_menu(default)
Yast::Execute.on_target(SDBOOTUTIL, "set-default", default)
rescue Cheetah::ExecutionFailed => e
Yast::Report.Error(
format(_(
"Cannot write default boot menu entry:\n" \
"Command `%{command}`.\n" \
"Error output: %{stderr}"
), command: e.commands.inspect, stderr: e.stderr)
)
end
end
end
83 changes: 83 additions & 0 deletions src/lib/bootloader/bls_sections.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# frozen_string_literal: true

require "json"
require "yast"
require "yast2/execute"
require "bootloader/bls"

Yast.import "Misc"

module Bootloader
# Represents available sections and handling of default BLS boot entry
class BlsSections
include Yast::Logger

# @return [Array<String>] list of all available boot titles
# or an empty array
attr_reader :all

# @return [String] title of default boot section.
attr_reader :default

def initialize
@all = []
@default = ""
end

# Sets default section internally.
# @param [String] value of new boot title to boot
# @note to write it to system use #write later
def default=(value)
log.info "set new default to '#{value.inspect}'"

# empty value mean no default specified
if !all.empty? && !all.include?(value) && !value.empty?
log.warn "Invalid value #{value} trying to set as default. Fallback to default"
value = ""
end

@default = value
end

# writes default to system making it persistent
def write
return if @default.empty?

Bls.write_default_menu(@default)
end

def read
@data = read_entries
@all = @data.map { |e| e["title"] }
@default = read_default
end

private

OS_RELEASE_PATH = "/etc/os-release"

def grubenv_path
str = Yast::Misc.CustomSysconfigRead("ID_LIKE", "openSUSE",
OS_RELEASE_PATH)
os = str.split.first
File.join("/boot/efi/EFI/", os, "/grubenv")
end

# @return [String] return default boot as string or "" if not set
# or something goes wrong
def read_default
Yast::Misc.CustomSysconfigRead("default", "",
grubenv_path)
end

# @return [Array] return array of entries or []
def read_entries
output = Yast::Execute.on_target(
"/usr/bin/bootctl", "--json=short", "list", stdout: :capture
schubi2 marked this conversation as resolved.
Show resolved Hide resolved
)
return [] if output.nil?

JSON.parse(output)
end
end
end
12 changes: 12 additions & 0 deletions src/lib/bootloader/bootloader_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
module Bootloader
# Represents base for all kinds of bootloaders
class BootloaderBase
include Yast::I18n

def initialize
textdomain "bootloader"

@read = false
@proposed = false
@initial_sysconfig = Sysconfig.from_system
Expand Down Expand Up @@ -113,5 +117,13 @@ def include_kexec_tools_package?
def restore_initial_sysconfig
@initial_sysconfig.write
end

def status_string(status)
if status
_("enabled")
else
_("disabled")
end
end
end
end
10 changes: 10 additions & 0 deletions src/lib/bootloader/bootloader_factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require "bootloader/none_bootloader"
require "bootloader/grub2"
require "bootloader/grub2efi"
require "bootloader/grub2bls"
require "bootloader/systemdboot"
require "bootloader/exceptions"

Expand All @@ -24,6 +25,7 @@ class BootloaderFactory
# Keyword used in autoyast for default bootloader used for given system.
DEFAULT_KEYWORD = "default"
SYSTEMDBOOT = "systemd-boot"
GRUB2BLS = "grub2-bls"
schubi2 marked this conversation as resolved.
Show resolved Hide resolved

class << self
include Yast::Logger
Expand Down Expand Up @@ -57,6 +59,7 @@ def supported_names
if Yast::Mode.config
# default means bootloader use what it think is the best
result = BootloaderFactory::SUPPORTED_BOOTLOADERS.clone
result << GRUB2BLS if use_grub2_bls?
result << SYSTEMDBOOT if use_systemd_boot?
result << DEFAULT_KEYWORD
return result
Expand All @@ -72,6 +75,7 @@ def supported_names
# grub2 everywhere except aarch64 or riscv64
ret << "grub2" unless Systeminfo.efi_mandatory?
ret << "grub2-efi" if Systeminfo.efi_supported?
ret << GRUB2BLS if use_grub2_bls?
ret << SYSTEMDBOOT if use_systemd_boot?
ret << "none"
# avoid double entry for selected one
Expand All @@ -89,6 +93,8 @@ def bootloader_by_name(name)
@cached_bootloaders["grub2-efi"] ||= Grub2EFI.new
when "systemd-boot"
@cached_bootloaders["systemd-boot"] ||= SystemdBoot.new
when "grub2-bls"
@cached_bootloaders["grub2-bls"] ||= Grub2Bls.new
when "none"
@cached_bootloaders["none"] ||= NoneBootloader.new
when String
Expand All @@ -108,6 +114,10 @@ def use_systemd_boot?
(Yast::Arch.x86_64 || Yast::Arch.aarch64) # only these architectures are supported.
end

def use_grub2_bls?
(Yast::Arch.x86_64 || Yast::Arch.aarch64) # only these architectures are supported.
schubi2 marked this conversation as resolved.
Show resolved Hide resolved
end

def grub2_efi_installable?
Systeminfo.efi_mandatory? ||
((Yast::Arch.x86_64 || Yast::Arch.i386) && Systeminfo.efi?)
Expand Down
2 changes: 1 addition & 1 deletion src/lib/bootloader/config_dialog.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def contents
boot_code_tab = ::Bootloader::SystemdBootWidget::BootCodeTab.new
kernel_tab = ::Bootloader::SystemdBootWidget::KernelTab.new
bootloader_tab = ::Bootloader::SystemdBootWidget::BootloaderTab.new
else
else # grub2, grub2-efi, grub2-bls
boot_code_tab = ::Bootloader::Grub2Widget::BootCodeTab.new
kernel_tab = ::Bootloader::Grub2Widget::KernelTab.new
bootloader_tab = ::Bootloader::Grub2Widget::BootloaderTab.new
Expand Down
18 changes: 1 addition & 17 deletions src/lib/bootloader/generic_widgets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def localized_names(name)
names = {
"grub2" => _("GRUB2"),
"grub2-efi" => _("GRUB2 for EFI"),
"grub2-bls" => _("GRUB2 with BLS"),
schubi2 marked this conversation as resolved.
Show resolved Hide resolved
# Translators: option in combo box when bootloader is not managed by yast2
"systemd-boot" => _("Systemd Boot"),
"none" => _("Not Managed"),
Expand All @@ -52,8 +53,6 @@ def localized_names(name)
names[name] or raise "Unknown supported bootloader '#{name}'"
end

# rubocop:disable Metrics/MethodLength
# It will be reduced again if systemd-boot is not anymore in beta phase.
def handle
old_bl = BootloaderFactory.current.name
new_bl = value
Expand All @@ -73,20 +72,6 @@ def handle
return :redraw if !Yast::Popup.ContinueCancel(popup_msg)
end

if new_bl == "systemd-boot"
# popup - Continue/Cancel
popup_msg = _(
"\n" \
"Systemd-boot support is currently work in progress and\n" \
schubi2 marked this conversation as resolved.
Show resolved Hide resolved
"may not work as expected. Use at your own risk.\n" \
"\n" \
"Currently we do not provide official maintenance or support.\n" \
"Proceed?\n"
)

return :redraw if !Yast::Popup.ContinueCancel(popup_msg)
end

if !Yast::Stage.initial && (old_bl == "systemd-boot")
Yast::Popup.Warning(_(
"Switching from systemd-boot to another bootloader\n" \
Expand All @@ -101,7 +86,6 @@ def handle
:redraw
end

# rubocop:enable Metrics/MethodLength
def help
_(
"<p><b>Boot Loader</b>\n" \
Expand Down
Loading
Loading