Class: Bootloader::Stage1

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Yast::Logger
Defined in:
src/lib/bootloader/stage1.rb

Overview

Represents where is bootloader stage1 installed. Allows also proposing its location.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeStage1

Returns a new instance of Stage1.


27
28
29
# File 'src/lib/bootloader/stage1.rb', line 27

def initialize
  @model = CFA::Grub2::InstallDevice.new
end

Instance Attribute Details

#modelObject (readonly)

Returns the value of attribute model.


22
23
24
# File 'src/lib/bootloader/stage1.rb', line 22

def model
  @model
end

Instance Method Details

#add_udev_device(dev) ⇒ Object

Adds to devices udev variant for given device.

Parameters:

  • dev (String)

    device to add. Can be also logical device that is translated to physical one. If specific string should be added as it is then use #add_device


57
58
59
60
61
# File 'src/lib/bootloader/stage1.rb', line 57

def add_udev_device(dev)
  real_devices = Yast::BootStorage.stage1_devices_for_name(dev)
  udev_devices = real_devices.map { |d| Bootloader::UdevMapping.to_mountby_device(d.name) }
  udev_devices.each { |d| @model.add_device(d) }
end

#available_locationsObject

List of symbolic links of available locations to install. Possible values are :mbr for disks and :boot for partitions.


65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'src/lib/bootloader/stage1.rb', line 65

def available_locations
  case Yast::Arch.architecture
  when "i386", "x86_64"
    res = [:mbr]
    return res unless can_use_boot?

    if logical_boot?
      res << :logical << :extended
    else
      res << :boot
    end
  else
    log.info "no available non-custom location for arch #{Yast::Arch.architecture}"

    []
  end
end

#boot_disk_namesObject


111
112
113
114
115
# File 'src/lib/bootloader/stage1.rb', line 111

def boot_disk_names
  detect_devices

  @mbr_devices
end

#boot_partition?Boolean

Returns:

  • (Boolean)

117
118
119
120
121
122
# File 'src/lib/bootloader/stage1.rb', line 117

def boot_partition?
  names = boot_partition_names
  return false if names.empty?

  include_real_devs?(names)
end

#boot_partition_namesArray<String>

partition names where stage1 can be placed and where /boot lives

Returns:

  • (Array<String>)

105
106
107
108
109
# File 'src/lib/bootloader/stage1.rb', line 105

def boot_partition_names
  detect_devices

  @boot_devices
end

#can_use_boot?Boolean

Returns:

  • (Boolean)

185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'src/lib/bootloader/stage1.rb', line 185

def can_use_boot?
  fs = Yast::BootStorage.boot_filesystem

  # no boot assigned
  return false unless fs

  return false unless fs.is?(:blk_filesystem)

  # cannot install stage one to xfs as it doesn't have reserved space (bnc#884255)
  return false if fs.type == ::Y2Storage::Filesystems::Type::XFS

  parts = fs.blk_devices

  subgraph = parts.each_with_object([]) do |part, result|
    result.concat([part] + part.descendants + part.ancestors)
  end

  return false if subgraph.any? do |dev|
    # LVM partition does not have reserved space for stage one
    next true if dev.is?(:lvm_pv)
    # MD Raid does not have reserved space for stage one (bsc#1063957)
    next true if dev.is?(:md)
    # encrypted partition does not have reserved space and it is bad idea in general
    # (bsc#1056862)
    next true if dev.is?(:encryption)

    false
  end

  true
end

#clear_devicesObject

Removes all stage1 placements


97
98
99
100
101
# File 'src/lib/bootloader/stage1.rb', line 97

def clear_devices
  devices.each do |dev|
    @model.remove_device(dev)
  end
end

#custom_devicesObject


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'src/lib/bootloader/stage1.rb', line 156

def custom_devices
  known_devices = boot_disk_names + boot_partition_names + extended_boot_partitions_names
  log.info "known devices #{known_devices.inspect}"

  devices.reject do |dev|
    dev_path = DevicePath.new(dev)

    # in installation do not care of uuids - not know at this time
    kernel_dev = if dev_path.uuid?
      dev
    else
      Bootloader::UdevMapping.to_kernel_device(dev)
    end

    log.info "stage1 devices for #{dev} is #{kernel_dev.inspect}"
    known_devices.include?(kernel_dev)
  end
end

#extended_boot_partition?Boolean

Returns:

  • (Boolean)

148
149
150
151
152
153
154
# File 'src/lib/bootloader/stage1.rb', line 148

def extended_boot_partition?
  names = extended_boot_partitions_names
  return false if names.empty?
  return false if boot_partition_names == names

  include_real_devs?(names)
end

#extended_boot_partitions_namesObject


137
138
139
140
141
142
143
144
145
146
# File 'src/lib/bootloader/stage1.rb', line 137

def extended_boot_partitions_names
  @boot_objects.map do |device|
    dev = if device.is?(:partition) && device.type.is?(:logical)
      Yast::BootStorage.extended_for_logical(device)
    else
      device
    end
    dev.name
  end
end

#include?(dev) ⇒ Boolean

Checks if given device is used as stage1 location

Parameters:

  • dev (String)

    device to check, it can be kernel or udev name, it can also be virtual or real device, method convert it as needed

Returns:

  • (Boolean)

47
48
49
50
51
52
# File 'src/lib/bootloader/stage1.rb', line 47

def include?(dev)
  real_devs = Yast::BootStorage.stage1_devices_for_name(dev)
  real_devs_names = real_devs.map(&:name)

  include_real_devs?(real_devs_names)
end

#inspectObject


31
32
33
34
# File 'src/lib/bootloader/stage1.rb', line 31

def inspect
  "<Bootloader::Stage1 #{object_id} activate: #{activate?} " \
    "generic_mbr: #{generic_mbr?} devices: #{devices.inspect}>"
end

#logical_boot?Boolean

Returns:

  • (Boolean)

131
132
133
134
135
# File 'src/lib/bootloader/stage1.rb', line 131

def logical_boot?
  detect_devices

  @boot_objects.any? { |p| p.is?(:partition) && p.type.is?(:logical) }
end

#mbr?Boolean

Returns:

  • (Boolean)

124
125
126
127
128
129
# File 'src/lib/bootloader/stage1.rb', line 124

def mbr?
  names = boot_disk_names
  return false if names.empty?

  include_real_devs?(names)
end

#merge(other) ⇒ Object


217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'src/lib/bootloader/stage1.rb', line 217

def merge(other)
  # merge here is a bit tricky, as for stage1 does not exist `defined?`
  # because grub_installdevice contain value or not, so it is not
  # possible to recognize if chosen or just not set
  # so logic is following
  # 1) if any flag is set to true, then use it because e.g. autoyast defined flags,
  #    but devices usually not
  # 2) if there is devices specified, then set also flags to value in other
  #    as it mean, that there is enough info to decide
  log.info "stage1 to merge #{other.inspect}"

  if other.devices.empty?
    self.activate    = activate? || other.activate?
    self.generic_mbr = generic_mbr? || other.generic_mbr?
  else
    clear_devices
    other.devices.each { |d| add_device(d) }

    self.activate    = other.activate?
    self.generic_mbr = other.generic_mbr?
  end

  log.info "stage1 after merge #{inspect}"
end

#proposeObject

Propose and set Stage1 location. It sets properly all devices where bootloader stage1 should be written. It also sets if partition should be activated by setting its boot flag. It proposes if generic_mbr will be written into MBR. The proposal is only based on storage information, disregarding any existing values of the output variables (which are respected at other times, in AutoYaST).


181
182
183
# File 'src/lib/bootloader/stage1.rb', line 181

def propose
  Stage1Proposal.propose(self)
end

#readObject


36
37
38
# File 'src/lib/bootloader/stage1.rb', line 36

def read
  @model.load
end

#remove_device(dev) ⇒ Object

Removes device from list of stage 1 placements.

Parameters:

  • dev (String)

    device to remove, have to be always physical device, but can match different udev names.


86
87
88
89
90
91
92
93
94
# File 'src/lib/bootloader/stage1.rb', line 86

def remove_device(dev)
  kernel_dev = Bootloader::UdevMapping.to_kernel_device(dev)

  dev = devices.find do |map_dev|
    kernel_dev == Bootloader::UdevMapping.to_kernel_device(map_dev)
  end

  @model.remove_device(dev)
end

#writeObject


40
41
42
# File 'src/lib/bootloader/stage1.rb', line 40

def write
  @model.save
end