• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yast / yast-bootloader / 8831324946

25 Apr 2024 10:56AM UTC coverage: 87.126% (+0.1%) from 86.999%
8831324946

push

github

schubi2
fixed testcase

3228 of 3705 relevant lines covered (87.13%)

12.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.3
/src/lib/bootloader/systemdboot.rb
1
# frozen_string_literal: true
2

3
require "fileutils"
1✔
4
require "yast"
1✔
5
require "bootloader/sysconfig"
1✔
6
require "bootloader/cpu_mitigations"
1✔
7
require "cfa/systemd_boot"
1✔
8
require "cfa/grub2/default"
1✔
9
require "cfa/matcher"
1✔
10
require "cfa/placer"
1✔
11

12
Yast.import "Report"
1✔
13
Yast.import "Arch"
1✔
14
Yast.import "ProductFeatures"
1✔
15
Yast.import "BootStorage"
1✔
16
Yast.import "Stage"
1✔
17

18
module Bootloader
1✔
19
  # Represents systemd bootloader with efi target
20
  class SystemdBoot < BootloaderBase
1✔
21
    include Yast::Logger
1✔
22
    include Yast::I18n
1✔
23

24
    CMDLINE = "/etc/kernel/cmdline"
1✔
25

26
    # @!attribute menue_timeout
27
    #   @return [Integer] menue timeout
28
    attr_accessor :menue_timeout
1✔
29

30
    # @!attribute secure_boot
31
    #   @return [Boolean] current secure boot setting
32
    attr_accessor :secure_boot
1✔
33

34
    def initialize
1✔
35
      super
44✔
36

37
      textdomain "bootloader"
44✔
38
      # For kernel parameters we are using the same data structure
39
      # like grub2 in order to be compatible with all calls.
40
      @kernel_container = ::CFA::Grub2::Default.new
44✔
41
      @explicit_cpu_mitigations = false
44✔
42
    end
43

44
    def kernel_params
1✔
45
      @kernel_container.kernel_params
7✔
46
    end
47

48
    # rubocop:disable Metrics/AbcSize
49
    def merge(other)
1✔
50
      log.info "merging with system: timeout=#{other.menue_timeout} " \
1✔
51
               "secure_boot=#{other.secure_boot}"
52
      log.info "      kernel_params = #{other.kernel_params.serialize}"
1✔
53
      super
1✔
54
      self.menue_timeout = other.menue_timeout unless other.menue_timeout.nil?
1✔
55
      self.secure_boot = other.secure_boot unless other.secure_boot.nil?
1✔
56
      kernel_serialize = kernel_params.serialize
1✔
57
      # handle specially noresume as it should lead to remove all other resume
58
      kernel_serialize.gsub!(/resume=\S+/, "") if kernel_params.parameter("noresume")
1✔
59

60
      # explicitly set mitigations means overwrite of our
61
      if other.explicit_cpu_mitigations
1✔
62
        log.info "merging cpu_mitigations"
×
63
        self.cpu_mitigations = other.cpu_mitigations
×
64
      end
65

66
      log.info "mitigations after merge #{cpu_mitigations}"
1✔
67
      # prevent double cpu_mitigations params
68
      kernel_serialize.gsub!(/mitigations=\S+/, "") if kernel_params.parameter("mitigations")
1✔
69

70
      new_kernel_params = "#{kernel_serialize} #{other.kernel_params.serialize}"
1✔
71
      # deduplicate identicatel parameter. Keep always the last one ( so reverse is needed ).
72
      new_params = new_kernel_params.split.reverse.uniq.reverse.join(" ")
1✔
73

74
      @kernel_container.kernel_params.replace(new_params)
1✔
75
    end
76
    # rubocop:enable Metrics/AbcSize
77

78
    def cpu_mitigations
1✔
79
      CpuMitigations.from_kernel_params(kernel_params)
1✔
80
    end
81

82
    def explicit_cpu_mitigations
1✔
83
      @explicit_cpu_mitigations ? cpu_mitigations : nil
1✔
84
    end
85

86
    def cpu_mitigations=(value)
1✔
87
      log.info "setting mitigations to #{value}"
×
88
      @explicit_cpu_mitigations = true
×
89
      value.modify_kernel_params(kernel_params)
×
90
    end
91

92
    def read
1✔
93
      super
1✔
94

95
      read_menue_timeout
1✔
96
      self.secure_boot = Systeminfo.secure_boot_active?
1✔
97

98
      lines = ""
1✔
99
      filename = File.join(Yast::Installation.destdir, CMDLINE)
1✔
100
      if File.exist?(filename)
1✔
101
        File.open(filename).each do |line|
×
102
          lines = + line
×
103
        end
104
      end
105
      @kernel_container.kernel_params.replace(lines)
1✔
106
    end
107

108
    # Write bootloader settings to disk
109
    def write(etc_only: false)
1✔
110
      super
1✔
111
      log.info("Writing settings...")
1✔
112
      if Yast::Stage.initial # while new installation only (currently)
1✔
113
        install_bootloader
1✔
114
        create_menue_entries
1✔
115
      end
116
      write_menue_timeout
1✔
117

118
      File.open(File.join(Yast::Installation.destdir, CMDLINE), "w+") do |fw|
1✔
119
        fw.puts(kernel_params.serialize)
1✔
120
      end
121
      true
1✔
122
    end
123

124
    def propose
1✔
125
      super
×
126
      log.info("Propose settings...")
×
127
      if @kernel_container.kernel_params.empty?
×
128
        kernel_line = Yast::BootArch.DefaultKernelParams(propose_resume)
×
129
        @kernel_container.kernel_params.replace(kernel_line)
×
130
      end
131
      self.menue_timeout = Yast::ProductFeatures.GetIntegerFeature("globals", "boot_timeout").to_i
×
132
      self.secure_boot = Systeminfo.secure_boot_supported?
×
133
    end
134

135
    def status_string(status)
1✔
136
      if status
2✔
137
        _("enabled")
×
138
      else
139
        _("disabled")
2✔
140
      end
141
    end
142

143
    # Secure boot setting shown in summary screen.
144
    # sdbootutil intialize secure boot if shim has been installed.
145
    #
146
    # @return [String]
147
    def secure_boot_summary
1✔
148
      link = if secure_boot
2✔
149
        "<a href=\"disable_secure_boot\">(#{_("disable")})</a>"
×
150
      else
151
        "<a href=\"enable_secure_boot\">(#{_("enable")})</a>"
2✔
152
      end
153

154
      "#{_("Secure Boot:")} #{status_string(secure_boot)} #{link}"
2✔
155
    end
156

157
    # Display bootloader summary
158
    # @return a list of summary lines
159
    def summary(*)
1✔
160
      result = [
161
        Yast::Builtins.sformat(
2✔
162
          _("Boot Loader Type: %1"),
163
          "Systemd Boot"
164
        )
165
      ]
166
      result << secure_boot_summary if Systeminfo.secure_boot_available?(name)
2✔
167
      result
2✔
168
    end
169

170
    def name
1✔
171
      "systemd-boot"
11✔
172
    end
173

174
    def packages
1✔
175
      res = super
1✔
176
      res << "sdbootutil" << "systemd-boot"
1✔
177

178
      case Yast::Arch.architecture
1✔
179
      when "x86_64"
180
        res << "shim" if secure_boot
1✔
181
      else
182
        log.warn "Unknown architecture #{Yast::Arch.architecture} for systemdboot"
×
183
      end
184

185
      res
1✔
186
    end
187

188
    def delete
1✔
189
      log.warn("is currently not supported")
12✔
190
    end
191

192
    # overwrite BootloaderBase version to save secure boot
193
    def write_sysconfig(prewrite: false)
1✔
194
      sysconfig = Bootloader::Sysconfig.new(bootloader: name,
×
195
        secure_boot: secure_boot, trusted_boot: false,
196
        update_nvram: false)
197
      prewrite ? sysconfig.pre_write : sysconfig.write
×
198
    end
199

200
  private
1✔
201

202
    SDBOOTUTIL = "/usr/bin/sdbootutil"
1✔
203

204
    def create_menue_entries
1✔
205
      cmdline_file = File.join(Yast::Installation.destdir, CMDLINE)
1✔
206
      if Yast::Stage.initial
1✔
207
        # sdbootutil script needs the "root=<device>" entry in kernel parameters.
208
        # This will be written to CMDLINE which will be used in an
209
        # installed system by the administrator only. So we can use it because
210
        # the system will be installed new. This file will be deleted after
211
        # calling sdbootutil.
212
        File.open(cmdline_file, "w+") do |fw|
1✔
213
          fw.puts("root=#{Yast::BootStorage.root_partitions.first.name}")
1✔
214
        end
215
      end
216
      begin
217
        Yast::Execute.on_target!(SDBOOTUTIL, "--verbose", "add-all-kernels")
1✔
218
      rescue Cheetah::ExecutionFailed => e
219
        Yast::Report.Error(
×
220
          format(_(
221
                   "Cannot create systemd-boot menue entry:\n" \
222
                   "Command `%{command}`.\n" \
223
                   "Error output: %{stderr}"
224
                 ), command: e.commands.inspect, stderr: e.stderr)
225
        )
226
      end
227
      File.delete(cmdline_file) if Yast::Stage.initial # see above
1✔
228
    end
229

230
    def read_menue_timeout
1✔
231
      config = CFA::SystemdBoot.load
1✔
232
      return unless config.menue_timeout
1✔
233

234
      self.menue_timeout = if config.menue_timeout == "menu-force"
×
235
        -1
×
236
      else
237
        config.menue_timeout.to_i
×
238
      end
239
    end
240

241
    def write_menue_timeout
1✔
242
      config = CFA::SystemdBoot.load
1✔
243
      config.menue_timeout = if menue_timeout == -1
1✔
244
        "menu-force"
×
245
      else
246
        menue_timeout.to_s
1✔
247
      end
248
      config.save
1✔
249
    end
250

251
    def install_bootloader
1✔
252
      Yast::Execute.on_target!(SDBOOTUTIL, "--verbose",
1✔
253
        "install")
254
    rescue Cheetah::ExecutionFailed => e
255
      Yast::Report.Error(
×
256
      format(_(
257
               "Cannot install systemd bootloader:\n" \
258
               "Command `%{command}`.\n" \
259
               "Error output: %{stderr}"
260
             ), command: e.commands.inspect, stderr: e.stderr)
261
    )
262
      nil
×
263
    end
264
  end
265
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc