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

yast / yast-bootloader / 12048550996

27 Nov 2024 10:37AM UTC coverage: 87.484% (+0.1%) from 87.378%
12048550996

Pull #708

github

schubi2
cleanup
Pull Request #708: Supporting Grub2-BLS

210 of 240 new or added lines in 13 files covered. (87.5%)

88 existing lines in 7 files now uncovered.

3362 of 3843 relevant lines covered (87.48%)

13.0 hits per line

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

90.78
/src/lib/bootloader/grub2.rb
1
# frozen_string_literal: true
2

3
require "yast"
1✔
4
require "y2storage"
1✔
5
require "bootloader/grub2base"
1✔
6
require "bootloader/mbr_update"
1✔
7
require "bootloader/device_map"
1✔
8
require "bootloader/stage1"
1✔
9
require "bootloader/grub_install"
1✔
10
require "bootloader/systeminfo"
1✔
11

12
Yast.import "Arch"
1✔
13
Yast.import "BootStorage"
1✔
14
Yast.import "HTML"
1✔
15

16
module Bootloader
1✔
17
  # Represents non-EFI variant of GRUB2
18
  class Grub2 < Grub2Base
1✔
19
    attr_reader :device_map
1✔
20

21
    def initialize
1✔
22
      super
236✔
23

24
      textdomain "bootloader"
236✔
25
      @stage1 = Stage1.new
236✔
26
      @grub_install = GrubInstall.new(efi: false)
236✔
27
      @device_map = DeviceMap.new
236✔
28
    end
29

30
    # Read settings from disk, overwritting already set values
31
    def read
1✔
32
      super
2✔
33

34
      begin
35
        stage1.read
2✔
36
      rescue Errno::ENOENT
37
        # grub_installdevice is not part of grub2 rpm, so it doesn't need to exist.
38
        # In such case ignore exception and use empty @stage1
UNCOV
39
        log.info "grub_installdevice does not exist. Using empty one."
×
40
        @stage1 = Stage1.new
×
41
      end
42

43
      begin
44
        # device map is needed only for legacy boot on intel
45
        device_map.read if Yast::Arch.x86_64 || Yast::Arch.i386
2✔
46
      rescue Errno::ENOENT
47
        # device map is only optional part of grub2, so it doesn't need to exist.
48
        # In such case ignore exception and use empty device map
UNCOV
49
        log.info "grub2/device.map does not exist. Using empty one."
×
50
        @device_map = DeviceMap.new
×
51
      end
52
    end
53

54
    # Write bootloader settings to disk
55
    # @return [Boolean] true on success
56
    def write(etc_only: false)
1✔
57
      # super have to called as first as grub install require some config writen in ancestor
58
      super
7✔
59

60
      device_map.write if (Yast::Arch.x86_64 || Yast::Arch.i386) && !etc_only
7✔
61

62
      # TODO: own class handling PBMR
63
      # set it only for gpt disk bsc#1008092
64
      pmbr_setup(*::Yast::BootStorage.gpt_disks(stage1.devices))
7✔
65

66
      # powernv must not call grub2-install (bnc#970582)
67
      if !Yast::Arch.board_powernv
7✔
68
        if !etc_only
7✔
69
          failed = @grub_install.execute(
5✔
70
            devices: stage1.devices, secure_boot: secure_boot, trusted_boot: trusted_boot,
71
            update_nvram: update_nvram
72
          )
73
          failed.each { |f| stage1.remove_device(f) }
5✔
74
        end
75
        # write stage1 location
76
        stage1.write
7✔
77
      end
78
      # Do some mbr activations ( s390 do not have mbr nor boot flag on its disks )
79
      # powernv do not have prep partition, so we do not have any partition to activate (bnc#970582)
80
      MBRUpdate.new.run(stage1) if !Yast::Arch.s390 && !Yast::Arch.board_powernv && !etc_only
7✔
81
    end
82

83
    def propose
1✔
84
      super
7✔
85

86
      stage1.propose
7✔
87
      # for GPT add protective MBR flag otherwise some systems won't
88
      # boot, safer option for legacy booting (bnc#872054)
89
      self.pmbr_action = :add
7✔
90
      log.info "proposed pmbr_action #{pmbr_action}."
7✔
91
      device_map.propose if Yast::Arch.x86_64 || Yast::Arch.i386
7✔
92
    end
93

94
    def merge(other)
1✔
95
      super
14✔
96

97
      @device_map = other.device_map if !other.device_map.empty?
14✔
98

99
      stage1.merge(other.stage1)
14✔
100
    end
101

102
    # Display bootloader summary
103
    # @return a list of summary lines
104
    def summary(simple_mode: false)
1✔
105
      result = [
106
        Yast::Builtins.sformat(
4✔
107
          _("Boot Loader Type: %1"),
108
          "GRUB2"
109
        )
110
      ]
111

112
      result.concat(boot_flags_summary)
4✔
113

114
      locations_val = locations
4✔
115
      if !locations_val.empty?
4✔
116
        result << format(
4✔
117
          _("Write Boot Code To: %s"),
118
          locations_val.join(", ")
119
        )
120
      end
121

122
      # it is necessary different summary for autoyast and installation
123
      # other mode than autoyast on running system
124
      # both ppc and s390 have special devices for stage1 so it do not make sense
125
      # allow change of location to MBR or boot partition (bnc#879107)
126
      no_location = simple_mode || Yast::Arch.ppc || Yast::Arch.s390 || Yast::Mode.config
4✔
127
      result << url_location_summary unless no_location
4✔
128

129
      order_sum = disk_order_summary
4✔
130
      result << order_sum unless order_sum.empty?
4✔
131

132
      result
4✔
133
    end
134

135
    def name
1✔
136
      "grub2"
141✔
137
    end
138

139
    def packages
1✔
140
      res = super
45✔
141
      res << "grub2"
45✔
142
      res << "syslinux" if include_syslinux_package?
45✔
143
      res << "trustedgrub2" << "trustedgrub2-i386-pc" if include_trustedgrub2_packages?
45✔
144
      res
45✔
145
    end
146

147
    # FIXME: refactor with injection like super(prewrite: prewrite, sysconfig = ...)
148
    # overwrite BootloaderBase version to save trusted boot
149
    def write_sysconfig(prewrite: false)
1✔
150
      sysconfig = Bootloader::Sysconfig.new(
3✔
151
        bootloader: name, secure_boot: secure_boot, trusted_boot: trusted_boot,
152
        update_nvram: update_nvram
153
      )
154
      prewrite ? sysconfig.pre_write : sysconfig.write
3✔
155
    end
156

157
  private
1✔
158

159
    # Checks if syslinux package should be included
160
    #
161
    # Needed for generic_mbr binary files, but it must not be required in inst-sys as inst-sys have
162
    # it itself (bsc#1004229).
163
    #
164
    # @return [Boolean] true if syslinux package should be included; false otherwise
165
    def include_syslinux_package?
1✔
166
      return false if Yast::Stage.initial
45✔
167

168
      stage1.generic_mbr?
34✔
169
    end
170

171
    # @return [Boolean] true when trustedgrub2 packages should be included; false otherwise
172
    def include_trustedgrub2_packages?
1✔
173
      return false unless trusted_boot
45✔
174

175
      Yast::Arch.x86_64 || Yast::Arch.i386
4✔
176
    end
177

178
    def devicegraph
1✔
179
      Y2Storage::StorageManager.instance.staging
×
180
    end
181

182
    def disk_order_summary
1✔
183
      return "" if Yast::Arch.s390
4✔
184

185
      return "" if device_map.size < 2
3✔
186

187
      Yast::Builtins.sformat(
1✔
188
        # part of summary, %1 is a list of hard disks device names
189
        _("Order of Hard Disks: %1"),
190
        device_map.disks_order.join(", ")
191
      )
192
    end
193

194
    # Gets all locations where stage1 will be written
195
    def locations
1✔
196
      locations = []
4✔
197

198
      partition_location = Yast::BootStorage.boot_partitions.map(&:name).join(", ")
4✔
199
      locations << partition_location if stage1.boot_partition?
4✔
200
      if stage1.extended_boot_partition?
4✔
201
        partitions = Yast::BootStorage.boot_partitions.map do |partition|
4✔
202
          Yast::BootStorage.extended_for_logical(partition).name
4✔
203
        end
204
        locations << partitions.join(", ")
4✔
205
      end
206
      locations << Yast::BootStorage.boot_disks.map(&:name).join(", ") if stage1.mbr?
4✔
207
      locations << stage1.custom_devices if !stage1.custom_devices.empty?
4✔
208

209
      locations
4✔
210
    end
211

212
    def mbr_line
1✔
213
      # TRANSLATORS: summary line where %s is disk specified, can be more disks, separated by comma
214
      res = if stage1.mbr?
3✔
215
        _(
3✔
216
          "Write it into MBR of %s (<a href=\"disable_boot_mbr\">do not write</a>)"
217
        )
218
      # TRANSLATORS: summary line where %s is disk specified, can be more disks, separated by comma
219
      else
220
        _(
×
221
          "Do not write it into MBR of %s (<a href=\"enable_boot_mbr\">write</a>)"
222
        )
223
      end
224

225
      format(res, Yast::BootStorage.boot_disks.map(&:name).join(", "))
3✔
226
    end
227

228
    def partition_line
1✔
229
      # TRANSLATORS: summary line where %s is partition specified, can be more disks,
230
      # separated by comma
231
      res = if stage1.boot_partition?
×
232
        _(
×
233
          "Write it into partition with /boot - %s " \
234
          "(<a href=\"disable_boot_boot\">do not write</a>)"
235
        )
236
      # TRANSLATORS: summary line where %s is partition specified, can be more disks,
237
      # separated by comma
238
      else
239
        _(
×
240
          "Do not write it into partition with /boot - %s " \
241
          "(<a href=\"enable_boot_boot\">write</a>)"
242
        )
243
      end
244
      format(res, Yast::BootStorage.boot_partitions.map(&:name).join(", "))
×
245
    end
246

247
    def logical_partition_line
1✔
248
      # TRANSLATORS: summary line where %s is partition specified, can be more disks,
249
      # separated by comma
250
      res = if stage1.boot_partition?
3✔
251
        _(
3✔
252
          "Write it into logical partition with /boot - %s " \
253
          "(<a href=\"disable_boot_boot\">do not write</a>)"
254
        )
255
      # TRANSLATORS: summary line where %s is partition specified, can be more disks,
256
      # separated by comma
257
      else
258
        _(
×
259
          "Do not write it into logical partition with /boot - %s " \
260
          "(<a href=\"enable_boot_boot\">write</a>)"
261
        )
262
      end
263
      format(res, Yast::BootStorage.boot_partitions.map(&:name).join(", "))
3✔
264
    end
265

266
    def extended_partition_line
1✔
267
      # TRANSLATORS: summary line where %s is partition specified, can be more disks,
268
      # separated by comma
269
      res = if stage1.extended_boot_partition?
3✔
270
        _(
3✔
271
          "Write it into extended partition with /boot - %s " \
272
          "(<a href=\"disable_boot_extended\">do not write</a>)"
273
        )
274
      # TRANSLATORS: summary line where %s is partition specified, can be more disks,
275
      # separated by comma
276
      else
277
        _(
×
278
          "Do not write it into extended partition with /boot - %s " \
279
          "(<a href=\"enable_boot_extended\">write</a>)"
280
        )
281
      end
282

283
      partitions = Yast::BootStorage.boot_partitions.map do |partition|
3✔
284
        Yast::BootStorage.extended_for_logical(partition).name
3✔
285
      end
286
      format(res, partitions.join(", "))
3✔
287
    end
288

289
    # FATE#303643 Enable one-click changes in bootloader proposal
290
    #
291
    #
292
    def url_location_summary
1✔
293
      log.info "Prepare url summary for GRUB2"
3✔
294
      line = +"<ul><li>"
3✔
295
      line << mbr_line
3✔
296
      line << "</li>\n"
3✔
297

298
      # do not allow to switch on boot from partition that do not support it
299
      if stage1.can_use_boot?
3✔
300
        line << "<li>"
3✔
301
        if stage1.logical_boot?
3✔
302
          line << extended_partition_line
3✔
303
          line << "</li>"
3✔
304
          line << "<li>"
3✔
305
          line << logical_partition_line
3✔
306
        else
307
          line << partition_line
×
308
        end
309
        line << "</li>"
3✔
310
      end
311

312
      if stage1.devices.empty?
3✔
313
        # no location chosen, so warn user that it is problem unless he is sure
314
        msg = _("Warning: No location for boot code selected." \
3✔
315
                "Unless you know what you are doing please select above location.")
316
        line << "<li>" << Yast::HTML.Colorize(msg, "red") << "</li>"
3✔
317
      end
318

319
      line << "</ul>"
3✔
320

321
      # TRANSLATORS: title for list of location proposals
322
      _("Boot Code: %s") % line
3✔
323
    end
324

325
    # summary for various boot flags
326
    def boot_flags_summary
1✔
327
      result = []
4✔
328
      result << secure_boot_summary if Systeminfo.secure_boot_available?(name)
4✔
329
      result << trusted_boot_summary if Systeminfo.trusted_boot_available?(name)
4✔
330
      result << update_nvram_summary if Systeminfo.nvram_available?(name)
4✔
331

332
      result
4✔
333
    end
334
  end
335
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

© 2025 Coveralls, Inc