Module: Yast::BootloaderGrub2MiscInclude

Defined in:
src/include/bootloader/grub2/misc.rb

Instance Method Summary (collapse)

Instance Method Details

- (Boolean) gpt_boot_disk?

Returns:

  • (Boolean)


643
644
645
646
647
# File 'src/include/bootloader/grub2/misc.rb', line 643

def gpt_boot_disk?
  targets = BootCommon.GetBootloaderDevices
  boot_discs = targets.map {|d| Storage.GetDisk(Storage.GetTargetMap, d)}
  boot_discs.any? {|d| d["label"] == "gpt" }
end

- (String) grub_ConfigureLocation

grub_ConfigureLocation() Where to install the bootloader. Returns the type of device where to install: one of bootroot mbrextended `mbr_md Also sets the boot_* keys in the internal global variable globals accordingly.

Returns:

  • (String)

    type of location proposed to bootloader



456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
# File 'src/include/bootloader/grub2/misc.rb', line 456

def grub_ConfigureLocation
  # NOTE: selected_location is a temporary local variable now; the global
  # variable is not used for grub anymore
  selected_location = :mbr # default to mbr

  vista_mbr = false
  # check whether the /boot partition
  #  - is primary:				is_logical  -> false
  #  - is on the first disk (with the MBR):  boot_partition_is_on_mbr_disk -> true

  tm = Storage.GetTargetMap
  dp = Storage.GetDiskPartition(BootStorage.BootPartitionDevice)
  boot_partition_disk = Ops.get_string(dp, "disk", "")
  boot_partition_is_on_mbr_disk = boot_partition_disk == BootCommon.mbrDisk

  dm = Ops.get_map(tm, boot_partition_disk, {})
  partitions_on_boot_partition_disk = Ops.get_list(dm, "partitions", [])
  is_logical = false
  is_logical_and_btrfs = false
  extended = nil

  # determine the underlying devices for the "/boot" partition (either the
  # BootPartitionDevice, or the devices from which the soft-RAID device for
  # "/boot" is built)
  underlying_boot_partition_devices = [BootStorage.BootPartitionDevice]
  md_info = BootCommon.Md2Partitions(BootStorage.BootPartitionDevice)
  if md_info != nil && Ops.greater_than(Builtins.size(md_info), 0)
    boot_partition_is_on_mbr_disk = false
    underlying_boot_partition_devices = Builtins.maplist(md_info) do |dev, bios_id|
      pdp = Storage.GetDiskPartition(dev)
      p_disk = Ops.get_string(pdp, "disk", "")
      boot_partition_is_on_mbr_disk = true if p_disk == BootCommon.mbrDisk
      dev
    end
  end
  Builtins.y2milestone(
    "Boot partition devices: %1",
    underlying_boot_partition_devices
  )

  Builtins.foreach(partitions_on_boot_partition_disk) do |p|
    if Ops.get(p, "type") == :extended
      extended = Ops.get_string(p, "device")
    elsif Builtins.contains(
        underlying_boot_partition_devices,
        Ops.get_string(p, "device", "")
      ) &&
        Ops.get(p, "type") == :logical
      # If any of the underlying_boot_partition_devices can be found on
      # the boot_partition_disk AND is a logical partition, set
      # is_logical to true.
      # For soft-RAID this will not match anyway ("/dev/[hs]da*" does not
      # match "/dev/md*").
      is_logical = true
      is_logical_and_btrfs = true if Ops.get(p, "used_fs") == :btrfs
    end
  end
  Builtins.y2milestone(
    "/boot is on 1st disk: %1",
    boot_partition_is_on_mbr_disk
  )
  Builtins.y2milestone("/boot is in logical partition: %1", is_logical)
  Builtins.y2milestone(
    "/boot is in logical partition and use btrfs: %1",
    is_logical_and_btrfs
  )
  Builtins.y2milestone("The extended partition: %1", extended)

  # if is primary, store bootloader there

  exit = 0
  # there was check if boot device is on logical partition
  # IMO it is good idea check MBR also in this case
  # see bug #279837 comment #53
  if boot_partition_is_on_mbr_disk
    selected_location = BootStorage.BootPartitionDevice !=
      BootStorage.RootPartitionDevice ? :boot : :root
    Ops.set(BootCommon.globals, "activate", "true")
    BootCommon.activate_changed = true

    # check if there is raid and if it soft-raid select correct device for analyse MBR
    # bnc #398356
    if Ops.greater_than(Builtins.size(underlying_boot_partition_devices), 1)
      boot_partition_disk = soft_MDraid_boot_disk(
        partitions_on_boot_partition_disk
      )
    end
    if boot_partition_disk == ""
      boot_partition_disk = Ops.get_string(dp, "disk", "")
    end
    # bnc #483797 cannot read 512 bytes from...
    out = ""
    if boot_partition_disk != ""
      out = BootCommon.examineMBR(boot_partition_disk)
    else
      Builtins.y2error("Boot partition disk not found")
    end
    Ops.set(
      BootCommon.globals,
      "generic_mbr",
      out != "vista" ? "true" : "false"
    )
    if out == "vista"
      Builtins.y2milestone("Vista MBR...")
      vista_mbr = true
    end
  elsif Ops.greater_than(
      Builtins.size(underlying_boot_partition_devices),
      1
    )
    # FIXME: `mbr_md is probably unneeded; AFA we can see, this decision is
    # automatic anyway and perl-Bootloader should be able to make it without help
    # from the user or the proposal.
    # In one or two places yast2-bootloader needs to find out all underlying MBR
    # devices, if we install stage 1 to a soft-RAID. These places need to find out
    # themselves if we have MBRs on a soft-RAID or not.
    # selected_location = `mbr_md;
    selected_location = :mbr
  end

  if is_logical_and_btrfs
    Builtins.y2milestone(
      "/boot is on logical parititon and uses btrfs, mbr is favored in this situration"
    )
    selected_location = :mbr
  end

  if !BootStorage.can_boot_from_partition
    Builtins.y2milestone("/boot cannot be used to install stage1")
    selected_location = :mbr
  end

  SetBootloaderDevice(selected_location)
  if !Builtins.contains(
      BootStorage.getPartitionList(:boot, "grub"),
      Ops.get(BootCommon.GetBootloaderDevices, 0)
    )
    selected_location = :mbr # default to mbr
    SetBootloaderDevice(selected_location)
  end

  Builtins.y2milestone(
    "grub_ConfigureLocation (%1 on %2)",
    selected_location,
    BootCommon.GetBootloaderDevices
  )

  # set active flag, if needed
  if selected_location == :mbr &&
      Ops.less_or_equal(Builtins.size(underlying_boot_partition_devices), 1)
    # We are installing into MBR:
    # If there is an active partition, then we do not need to activate
    # one (otherwise we do).
    # Reason: if we use our own MBR code, we do not rely on the activate
    # flag in the partition table to boot Linux. Thus, the activated
    # partition can remain activated, which causes less problems with
    # other installed OSes like Windows (older versions assign the C:
    # drive letter to the activated partition).
    Ops.set(
      BootCommon.globals,
      "activate",
      Builtins.size(Storage.GetBootPartition(BootCommon.mbrDisk)) == 0 ? "true" : "false"
    )
  else
    # if not installing to MBR, always activate (so the generic MBR will
    # boot Linux)

    # kokso: fix the problem with proposing installation generic boot code to "/" or "/boot"
    # kokso: if boot device is on logical partition
    if is_logical && extended != nil &&
        (Ops.get(BootCommon.globals, "generic_mbr", "") == "true" || vista_mbr)
      selected_location = :extended
    end
    Ops.set(BootCommon.globals, "activate", "true")
    SetBootloaderDevice(selected_location)
  end

  # for GPT remove protective MBR flag otherwise some systems won't boot
  if gpt_boot_disk?
    BootCommon.pmbr_action = :remove
  end

  Builtins.y2milestone("location configured. Resulting globals #{BootCommon.globals}")

  selected_location
end

- (Object) grub_DetectDisks

Detect “/boot”, “/” (root), extended partition device and MBR disk device

If no bootloader device has been set up yet (globals), or the first (FIXME(!)) device is not available as a boot partition, also call grub_ConfigureLocation to configure globals and set the globals and globals flags if needed all these settings are stored in internal variables



685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
# File 'src/include/bootloader/grub2/misc.rb', line 685

def grub_DetectDisks
  # #151501: AutoYaST also needs to know the activate flag and the
  # "boot_*" settings (formerly the loader_device); jsrain also said
  # that skipping setting these variables is probably a bug:
  # commenting out the skip code, but this may need to be changed and made dependent
  # on a "clone" flag (i.e. make the choice to provide minimal (i.e. let
  # YaST do partial proposals on the target system) or maximal (i.e.
  # stay as closely as possible to this system) info in the AutoYaST XML
  # file)
  # if (Mode::config ())
  #    return;
  mp = Storage.GetMountPoints

  mountdata_boot = Ops.get_list(mp, "/boot", Ops.get_list(mp, "/", []))
  mountdata_root = Ops.get_list(mp, "/", [])

  Builtins.y2milestone("mountPoints %1", mp)
  Builtins.y2milestone("mountdata_boot %1", mountdata_boot)

  BootStorage.RootPartitionDevice = Ops.get_string(mp, ["/", 0], "")

  if BootStorage.RootPartitionDevice == ""
    Builtins.y2error("No mountpoint for / !!")
  end

  # if /boot changed, re-configure location
  BootStorage.BootPartitionDevice = Ops.get_string(
    mountdata_boot,
    0,
    BootStorage.RootPartitionDevice
  )

  # get extended partition device (if exists)
  BootStorage.ExtendedPartitionDevice = grub_GetExtendedPartitionDev

  if BootCommon.mbrDisk == "" || BootCommon.mbrDisk == nil
    # mbr detection.
    BootCommon.mbrDisk = BootCommon.FindMBRDisk
  end

  # if no bootloader devices have been set up, or any of the set up
  # bootloader devices have become unavailable, then re-propose the
  # bootloader location.
  all_boot_partitions = BootStorage.getPartitionList(:boot, "grub")
  bldevs = BootCommon.GetBootloaderDevices
  need_location_reconfigure = false

  if bldevs == nil || bldevs == ["/dev/null"]
    need_location_reconfigure = true
  else
    Builtins.foreach(bldevs) do |dev|
      if !Builtins.contains(all_boot_partitions, dev)
        need_location_reconfigure = true
      end
    end
  end

  grub_ConfigureLocation if need_location_reconfigure

  nil
end

- (Hash) grub_DisksChanged

Check whether any disk settings for the disks we currently use were changed since last checking

Returns:

  • (Hash)

    map containing boolean “changed” and string “reason”



750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
# File 'src/include/bootloader/grub2/misc.rb', line 750

def grub_DisksChanged
  ret = { "changed" => false, "reason" => "" }

  return deep_copy(ret) if Mode.config

  mp = Storage.GetMountPoints
  actual_root = Ops.get_string(mp, ["/", 0], "")
  actual_boot = Ops.get_string(mp, ["/boot", 0], actual_root)
  actual_extended = grub_GetExtendedPartitionDev

  if Ops.get(BootCommon.globals, "boot_boot", "false") == "true" &&
      actual_boot != BootStorage.BootPartitionDevice
    ret = {
      "changed" => true,
      "reason"  => Ops.add(
        Ops.add(
          Ops.add(
            Ops.get_string(ret, "reason", ""),
            "Selected bootloader location \"/boot\" is not on "
          ),
          BootStorage.BootPartitionDevice
        ),
        " any more.\n"
      )
    }
  end

  if Ops.get(BootCommon.globals, "boot_root", "false") == "true" &&
      actual_root != BootStorage.RootPartitionDevice
    ret = {
      "changed" => true,
      "reason"  => Ops.add(
        Ops.add(
          Ops.add(
            Ops.get_string(ret, "reason", ""),
            "Selected bootloader location \"/\" is not on "
          ),
          BootStorage.RootPartitionDevice
        ),
        " any more.\n"
      )
    }
  end

  if Ops.get(BootCommon.globals, "boot_mbr", "false") == "true"
    actual_mbr = BootCommon.FindMBRDisk

    if actual_mbr != BootCommon.mbrDisk
      ret = {
        "changed" => true,
        "reason"  => Ops.add(
          Ops.add(
            Ops.add(
              Ops.get_string(ret, "reason", ""),
              "Selected bootloader location MBR is not on "
            ),
            BootCommon.mbrDisk
          ),
          " any more.\n"
        )
      }
    end
  end

  if Ops.get(BootCommon.globals, "boot_extended", "false") == "true" &&
      actual_extended != BootStorage.ExtendedPartitionDevice
    ret = {
      "changed" => true,
      "reason"  => Ops.add(
        Ops.add(
          Ops.add(
            Ops.get_string(ret, "reason", ""),
            "Selected bootloader location \"extended partition\" is not on "
          ),
          BootStorage.ExtendedPartitionDevice
        ),
        " any more.\n"
      )
    }
  end


  if Ops.get(BootCommon.globals, "boot_custom") != nil &&
      Ops.get(BootCommon.globals, "boot_custom") != ""
    all_boot_partitions = BootStorage.getPartitionList(:boot, "grub")

    if !Builtins.contains(
        all_boot_partitions,
        Ops.get(BootCommon.globals, "boot_custom")
      )
      ret = {
        "changed" => true,
        "reason"  => Ops.add(
          Ops.add(
            Ops.add(
              Ops.get_string(ret, "reason", ""),
              "Selected custom bootloader partition "
            ),
            Ops.get(BootCommon.globals, "boot_custom")
          ),
          " is not available any more.\n"
        )
      }
    end
  end

  if Ops.get_boolean(ret, "changed", false)
    Builtins.y2milestone("Location should be set again")
  end

  deep_copy(ret)
end

- (String) grub_GetExtendedPartitionDev

Find extended partition device (if it exists) on the same device where the BootPartitionDevice is located

BootPartitionDevice must be set

Returns:

  • (String)

    device name of extended partition, or nil if none found



655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
# File 'src/include/bootloader/grub2/misc.rb', line 655

def grub_GetExtendedPartitionDev
  ret = nil

  tm = Storage.GetTargetMap

  device = ""
  if BootStorage.BootPartitionDevice != ""
    device = BootStorage.BootPartitionDevice
  else
    device = BootStorage.RootPartitionDevice
  end

  dp = Storage.GetDiskPartition(device)
  disk = Ops.get_string(dp, "disk", "")
  dm = Ops.get_map(tm, disk, {})
  partitions = Ops.get_list(dm, "partitions", [])
  Builtins.foreach(partitions) do |p|
    ret = Ops.get_string(p, "device") if Ops.get(p, "type") == :extended
  end

  ret
end

- (Object) grub_getMbrsToRewrite

Get the list of MBR disks that should be rewritten by generic code if user wants to do so

Returns:

  • a list of device names to be rewritten



174
175
176
177
178
179
180
181
182
183
184
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
216
217
218
219
220
221
222
223
224
225
226
227
# File 'src/include/bootloader/grub2/misc.rb', line 174

def grub_getMbrsToRewrite
  ret = [BootCommon.mbrDisk]
  md = {}
  underlying_devs = []
  devs = []
  boot_devices = []

  # bnc#494630 - add also boot partitions from soft-raids
  boot_device = BootCommon.getBootPartition
  if Builtins.substring(boot_device, 0, 7) == "/dev/md"
    boot_devices = Builtins.add(boot_devices, boot_device)
    Builtins.foreach(BootCommon.GetBootloaderDevices) do |dev|
      boot_devices = Builtins.add(boot_devices, dev)
    end
  else
    boot_devices = BootCommon.GetBootloaderDevices
  end

  # get a list of all bootloader devices or their underlying soft-RAID
  # devices, if necessary
  underlying_devs = Builtins.maplist(boot_devices) do |dev|
    md = BootCommon.Md2Partitions(dev)
    if Ops.greater_than(Builtins.size(md), 0)
      devs = Builtins.maplist(md) { |k, v| k }
      next deep_copy(devs)
    end
    [dev]
  end
  bootloader_base_devices = Builtins.flatten(underlying_devs)

  # find the MBRs on the same disks as the devices underlying the boot
  # devices; if for any of the "underlying" or "base" devices no device
  # for acessing the MBR can be determined, include mbrDisk in the list
  mbrs = Builtins.maplist(bootloader_base_devices) do |dev|
    dev = Ops.get_string(
      grub_getPartitionToActivate(dev),
      "mbr",
      BootCommon.mbrDisk
    )
    dev
  end
  # FIXME: the exact semantics of this check is unclear; but it seems OK
  # to keep this as a sanity check and a check for an empty list;
  # mbrDisk _should_ be included in mbrs; the exact cases for this need
  # to be found and documented though
  if Builtins.contains(mbrs, BootCommon.mbrDisk)
    ret = Convert.convert(
      Builtins.merge(ret, mbrs),
      :from => "list",
      :to   => "list <string>"
    )
  end
  Builtins.toset(ret)
end

- (Object) grub_getPartitionsToActivate

Get a list of partitions to activate if user wants to activate boot partition

Returns:

  • a list of partitions to activate



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'src/include/bootloader/grub2/misc.rb', line 130

def grub_getPartitionsToActivate
  md = {}
  underlying_devs = []
  devs = []

  boot_devices = []

  # bnc#494630 - add also boot partitions from soft-raids
  boot_device = BootCommon.getBootPartition
  if Builtins.substring(boot_device, 0, 7) == "/dev/md"
    boot_devices = Builtins.add(boot_devices, boot_device)
    Builtins.foreach(BootCommon.GetBootloaderDevices) do |dev|
      boot_devices = Builtins.add(boot_devices, dev)
    end
  else
    boot_devices = BootCommon.GetBootloaderDevices
  end

  # get a list of all bootloader devices or their underlying soft-RAID
  # devices, if necessary
  underlying_devs = Builtins.maplist(boot_devices) do |dev|
    md = BootCommon.Md2Partitions(dev)
    if Ops.greater_than(Builtins.size(md), 0)
      devs = Builtins.maplist(md) { |k, v| k }
      next deep_copy(devs)
    end
    [dev]
  end
  bootloader_base_devices = Builtins.flatten(underlying_devs)

  if Builtins.size(bootloader_base_devices) == 0
    bootloader_base_devices = BootCommon.GetBootloaderDevices
  end
  ret = Builtins.maplist(bootloader_base_devices) do |partition|
    grub_getPartitionToActivate(partition)
  end
  ret.delete({})

  Builtins.toset(ret)
end

- (Object) grub_getPartitionToActivate(loader_device)

Given a device name to which we install the bootloader (loader_device), get the name of the partition which should be activated. Also return the device file name of the disk device that corresponds to loader_device (i.e. where the corresponding MBR can be found). string loader_device)

Parameters:

  • loader_device (String)

    string the device to install bootloader to

Returns:

  • a map $[ “dev” : string, “mbr”: string, “num”: any] containing device (eg. “/dev/hda4”), disk (eg. “/dev/hda”) and partition number (eg. 4) * @param boot_partition string the partition holding /boot subtree map<string,any> getPartitionToActivate (string boot_partition,



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'src/include/bootloader/grub2/misc.rb', line 54

def grub_getPartitionToActivate(loader_device)
  p_dev = Storage.GetDiskPartition(loader_device)
  num = BootCommon.myToInteger(Ops.get(p_dev, "nr"))
  mbr_dev = Ops.get_string(p_dev, "disk", "")

  # If loader_device is /dev/md* (which means bootloader is installed to
  # /dev/md*), return the info map for the first device in BIOS ID order
  # that underlies the soft-RAID and that has a BIOS ID (devices without
  # BIOS ID are excluded).
  # If no device is found in this way, return the info map for the
  # soft-RAID device ("/dev/md", "/dev/md[0-9]*").
  # FIXME: use ::storage to detect md devices, not by name!
  # FIXME: return info for ALL underlying soft-RAID devices here, so
  # that all MBRs can be backed-up and all partitions that need to be
  # activated can be activated. This requires a map<map<...>> return
  # value, and code on the caller side that evaluates this.
  if Builtins.substring(loader_device, 0, 7) == "/dev/md"
    md = BootCommon.Md2Partitions(loader_device)
    # max. is 255; 256 means "no bios_id found", so to have at least one
    # underlaying device use higher
    min = 257
    device = ""
    Builtins.foreach(md) do |d, id|
      if Ops.less_than(id, min)
        min = id
        device = d
      end
    end
    if device != ""
      p_dev2 = Storage.GetDiskPartition(device)
      num = BootCommon.myToInteger(Ops.get(p_dev2, "nr"))
      mbr_dev = Ops.get_string(p_dev2, "disk", "")
    end
  end

  tm = Storage.GetTargetMap
  partitions = Ops.get_list(tm, [mbr_dev, "partitions"], [])
  # do not select swap and do not select BIOS grub partition
  # as it clear its special flags (bnc#894040)
  partitions.select! { |p| p["used_fs"] != :swap && p["fsid"] != Partitions.fsid_bios_grub }
  # (bnc # 337742) - Unable to boot the openSUSE (32 and 64 bits) after installation
  # if loader_device is disk Choose any partition which is not swap to
  # satisfy such bios (bnc#893449)
  if num == 0
    # strange, no partitions on our mbr device, we probably won't boot
    if partitions.empty?
      Builtins.y2warning("no non-swap partitions for mbr device #{mbr_dev}")
      return {}
    end
    num = partitions.first["nr"]
    Builtins.y2milestone("loader_device is disk device, so use its #{num} partition")
  end

  if Ops.greater_than(num, 4)
    Builtins.y2milestone("Bootloader partition type can be logical")
    Builtins.foreach(partitions) do |p|
      if Ops.get(p, "type") == :extended
        num = Ops.get_integer(p, "nr", num)
        Builtins.y2milestone("Using extended partition %1 instead", num)
      end
    end
  end

  ret = {
    "num" => num,
    "mbr" => mbr_dev,
    "dev" => Storage.GetDeviceName(mbr_dev, num)
  }

  Builtins.y2milestone("Partition for activating: %1", ret)
  deep_copy(ret)
end

- (Object) grub_LocationProposal

Propose the boot loader location for grub - if no proposal has been made, collects the devices for “/”, “/boot”, MBR and makes a new proposal - if no device mapping exists, creates a device mapping - if the devices that were somehow (proposal, user interface) selected for bootloader installation do not match the current partitioning any more (e.g. “/boot” partition was selected but is not available anymore (and “/” did not move there), “/” was selected but has moved, etc.), then also re-collect the devices for “/”, “/boot”, MBR and make a new proposal



872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
# File 'src/include/bootloader/grub2/misc.rb', line 872

def grub_LocationProposal
  Builtins.y2milestone("globals: %1", BootCommon.globals)
  Builtins.y2milestone("Mode::autoinst: %1", Mode.autoinst)
  Builtins.y2milestone("Mode::autoupg: %1", Mode.autoupgrade)
  Builtins.y2milestone(
    "haskey( BootCommon::globals, boot_boot ): %1",
    Builtins.haskey(BootCommon.globals, "boot_boot")
  )
  md_mbr = ""
  if !BootCommon.was_proposed ||
      # During autoinstall, the autoyast profile must contain a bootloader
      # device specification (we currently really only support system
      # *cloning* with autoyast...). But as a convenience, and because
      # this kind of magic is available for empty globals and sections, we
      # propose a bootloader location if none was specified.
      # Note that "no bootloader device" can be specified by explicitly
      # setting this up, e.g. by setting one or all boot_* flags to
      # "false".
      # FIXME: add to LILO, ELILO; POWERLILO already should have this
      # (check again)
      (Mode.autoinst || Mode.autoupgrade) && !Builtins.haskey(BootCommon.globals, "boot_boot") &&
        !Builtins.haskey(BootCommon.globals, "boot_root") &&
        !Builtins.haskey(BootCommon.globals, "boot_mbr") &&
        !Builtins.haskey(BootCommon.globals, "boot_extended") &&
        !#	    ! haskey( BootCommon::globals, "boot_mbr_md" ) &&
        Builtins.haskey(BootCommon.globals, "boot_custom")
    grub_DetectDisks
    # check whether edd is loaded; if not: load it
    lsmod_command = "lsmod | grep edd"
    Builtins.y2milestone("Running command %1", lsmod_command)
    lsmod_out = Convert.to_map(
      SCR.Execute(path(".target.bash_output"), lsmod_command)
    )
    Builtins.y2milestone("Command output: %1", lsmod_out)
    edd_loaded = Ops.get_integer(lsmod_out, "exit", 0) == 0
    if !edd_loaded
      command = "/sbin/modprobe edd"
      Builtins.y2milestone("Loading EDD module, running %1", command)
      out = Convert.to_map(
        SCR.Execute(path(".target.bash_output"), command)
      )
      Builtins.y2milestone("Command output: %1", out)
    end
    md_mbr = BootStorage.addMDSettingsToGlobals
    Ops.set(BootCommon.globals, "boot_md_mbr", md_mbr) if md_mbr != ""
  end
  Builtins.y2milestone("(2) globals: %1", BootCommon.globals)

  # refresh device map
  if BootStorage.device_mapping == nil ||
      Builtins.size(BootStorage.device_mapping) == 0 ||
      BootCommon.cached_settings_base_data_change_time !=
        Storage.GetTargetChangeTime &&
        # bnc#585824 - Bootloader doesn't use defined device map from autoyast
        !((Mode.autoinst || Mode.autoupgrade) &&
          BootCommon.cached_settings_base_data_change_time == nil)
    BootStorage.ProposeDeviceMap
    md_mbr = BootStorage.addMDSettingsToGlobals
    Ops.set(BootCommon.globals, "boot_md_mbr", md_mbr) if md_mbr != ""
    BootCommon.InitializeLibrary(true, "grub2")
  end

  if !Mode.autoinst && !Mode.autoupgrade
    changed = grub_DisksChanged
    if Ops.get_boolean(changed, "changed", false)
      if BootCommon.askLocationResetPopup(
          Ops.get_string(changed, "reason", "Disk configuration changed.\n")
        )
        SetBootloaderDevice(:none)
        Builtins.y2milestone("Reconfiguring locations")
        grub_DetectDisks
      end
    end
  end

  nil
end

- (Boolean) grub_updateMBR

Update contents of MBR (active partition and booting code) FIXME move tis function to lilolike.ycp

Returns:

  • (Boolean)

    true on success



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
# File 'src/include/bootloader/grub2/misc.rb', line 232

def grub_updateMBR
  # FIXME: do the real thing in perl_Bootloader
  activate = Ops.get(BootCommon.globals, "activate", "false") == "true"
  generic_mbr = Ops.get(BootCommon.globals, "generic_mbr", "false") == "true"

  Builtins.y2milestone(
    "Updating disk system area, activate partition: %1, " +
      "install generic boot code in MBR: %2",
    activate,
    generic_mbr
  )

  # After a proposal is done, Bootloader::Propose() always sets
  # backup_mbr to true. The default is false. No other parts of the code
  # currently change this flag.
  if BootCommon.backup_mbr
    Builtins.y2milestone(
      "Doing MBR backup: MBR Disk: %1, loader devices: %2",
      BootCommon.mbrDisk,
      BootCommon.GetBootloaderDevices
    )
    disks_to_rewrite = Convert.convert(
      Builtins.toset(
        Builtins.merge(
          grub_getMbrsToRewrite,
          Builtins.merge(
            [BootCommon.mbrDisk],
            BootCommon.GetBootloaderDevices
          )
        )
      ),
      :from => "list",
      :to   => "list <string>"
    )
    Builtins.y2milestone(
      "Creating backup of boot sectors of %1",
      disks_to_rewrite
    )
    backups = disks_to_rewrite.map do |d|
      ::Bootloader::BootRecordBackup.new(d)
    end
    backups.each(&:write)
  end
  ret = true
  # if the bootloader stage 1 is not installed in the MBR, but
  # ConfigureLocation() asked us to replace some problematic existing
  # MBR, then overwrite the boot code (only, not the partition list!) in
  # the MBR with generic (currently DOS?) bootloader stage1 code
  if generic_mbr &&
      !Builtins.contains(
        BootCommon.GetBootloaderDevices,
        BootCommon.mbrDisk
      )
    PackageSystem.Install("syslinux") if !Stage.initial
    Builtins.y2milestone(
      "Updating code in MBR: MBR Disk: %1, loader devices: %2",
      BootCommon.mbrDisk,
      BootCommon.GetBootloaderDevices
    )
    mbr_type = Ops.get_string(
      Ops.get(Storage.GetTargetMap, BootCommon.mbrDisk, {}),
      "label",
      ""
    )
    Builtins.y2milestone("mbr type = %1", mbr_type)
    mbr_file = mbr_type == "gpt" ?
      "/usr/share/syslinux/gptmbr.bin" :
      "/usr/share/syslinux/mbr.bin"

    disks_to_rewrite = grub_getMbrsToRewrite
    Builtins.foreach(disks_to_rewrite) do |d|
      Builtins.y2milestone("Copying generic MBR code to %1", d)
      # added fix 446 -> 440 for Vista booting problem bnc #396444
      command = Builtins.sformat(
        "/bin/dd bs=440 count=1 if=%1 of=%2",
        mbr_file,
        d
      )
      Builtins.y2milestone("Running command %1", command)
      out = Convert.to_map(
        SCR.Execute(path(".target.bash_output"), command)
      )
      exit = Ops.get_integer(out, "exit", 0)
      Builtins.y2milestone("Command output: %1", out)
      ret = ret && 0 == exit
    end
  end

  Builtins.foreach(grub_getPartitionsToActivate) do |m_activate|
    num = Ops.get_integer(m_activate, "num", 0)
    mbr_dev = Ops.get_string(m_activate, "mbr", "")
    raise "INTERNAL ERROR: Data for partition to activate is invalid." if num == 0 || mbr_dev.empty?

    gpt_disk = Storage.GetDisk(Storage.GetTargetMap, BootCommon.mbrDisk)["label"] == "gpt"
    # if primary partition on old DOS MBR table, GPT do not have such limit

    if !(Arch.ppc && gpt_disk) && (gpt_disk || num <= 4)
      Builtins.y2milestone("Activating partition %1 on %2", num, mbr_dev)
      # FIXME: this is the most rotten code since molded sliced bread
      # move to bootloader/Core/GRUB.pm or similar
      # TESTME: make sure that parted does not destroy BSD
      # slices (#suse24740): cf. section 5.1 of "info parted":
      #   Parted only supports the BSD disk label system.
      #   Parted is unlikely to support the partition slice
      #   system in the future because the semantics are rather
      #   strange, and don't work like "normal" partition tables
      #   do.
      # FIXED: investigate proper handling of the activate flag
      # (kernel ioctls in parted etc.) and fix parted

      # this is needed only on gpt disks but we run it always
      # anyway; parted just fails, then
      command = Builtins.sformat(
        "/usr/sbin/parted -s %1 set %2 legacy_boot on",
        mbr_dev,
        num
      )
      Builtins.y2milestone("Running command %1", command)
      out = Convert.to_map(
        WFM.Execute(path(".local.bash_output"), command)
      )
      Builtins.y2milestone("Command output: %1", out)

      command = Builtins.sformat(
        "/usr/sbin/parted -s %1 set %2 boot on",
        mbr_dev,
        num
      )
      Builtins.y2milestone("Running command %1", command)
      out = Convert.to_map(
        WFM.Execute(path(".local.bash_output"), command)
      )
      exit = Ops.get_integer(out, "exit", 0)
      Builtins.y2milestone("Command output: %1", out)
      ret = ret && 0 == exit
    end
  end if activate
  ret
end

- (Object) initialize_bootloader_grub2_misc(include_target)



26
27
28
29
30
31
32
33
34
35
36
37
# File 'src/include/bootloader/grub2/misc.rb', line 26

def initialize_bootloader_grub2_misc(include_target)
  textdomain "bootloader"
  Yast.import "Arch"
  Yast.import "BootCommon"
  Yast.import "BootStorage"
  Yast.import "Map"
  Yast.import "Mode"
  Yast.import "PackageSystem"
  Yast.import "Partitions"
  Yast.import "Storage"
  Yast.import "StorageDevices"
end

- (Boolean) ReduceDeviceMapTo8

FATE #303548 - Grub: limit device.map to devices detected by BIOS Int 13 The function reduces records (devices) in device.map Grub doesn't support more than 8 devices in device.map

Returns:

  • (Boolean)

    true if device map was reduced



958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
# File 'src/include/bootloader/grub2/misc.rb', line 958

def ReduceDeviceMapTo8
  result = false

  if Ops.greater_than(Builtins.size(BootStorage.device_mapping), 8)
    result = true
    bios_order = Convert.convert(
      Map.Values(BootStorage.device_mapping),
      :from => "list",
      :to   => "list <string>"
    )
    #delete all grub devices with order more than 9
    bios_order = Builtins.filter(bios_order) do |key|
      Ops.less_than(Builtins.size(key), 4)
    end
    bios_order = Builtins.lsort(bios_order)
    Builtins.y2debug("ordered values (grub devices): %1", bios_order)
    inverse_device_map = {}
    new_device_map = {}
    Builtins.y2milestone(
      "Device map before reducing: %1",
      BootStorage.device_mapping
    )
    Builtins.foreach(BootStorage.device_mapping) do |key, value|
      Ops.set(inverse_device_map, value, key)
    end

    Builtins.y2debug("inverse_device_map: %1", inverse_device_map)
    index = 0

    Builtins.foreach(bios_order) do |key|
      device_name = Ops.get(inverse_device_map, key, "")
      if Ops.less_than(index, 8)
        Builtins.y2debug(
          "adding device: %1 with key: %2 and index is: %3",
          device_name,
          key,
          index
        )
        Ops.set(new_device_map, device_name, key)
        index = Ops.add(index, 1)
      else
        raise Break
      end
    end
    BootStorage.device_mapping = deep_copy(new_device_map)
    Builtins.y2milestone(
      "Device map after reducing: %1",
      BootStorage.device_mapping
    )
  else
    Builtins.y2milestone(
      "Device map includes less than 9 devices. It is not reduced. device_map: %1",
      BootStorage.device_mapping
    )
  end
  result
end

- (Object) SetBootloaderDevice(selected_location)

SetBootloaderDevice() Set “boot_*” flags in the globals map according to the boot device selected with parameter selected_location. Only a single boot device can be selected with this function. The function cannot be used to set a custom boot device. It will always be deleted.

FIXME: `mbr_md is probably unneeded; AFA we can see, this decision is automatic anyway and perl-Bootloader should be able to make it without help from the user or the proposal.

Parameters:

  • selected_location (Symbol)

    symbol one of bootroot mbrextended mbr_mdnone



389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
# File 'src/include/bootloader/grub2/misc.rb', line 389

def SetBootloaderDevice(selected_location)
  # first, default to all off:
  Builtins.foreach(["boot_boot", "boot_root", "boot_mbr", "boot_extended"]) do |flag|
    Ops.set(BootCommon.globals, flag, "false")
  end
  # need to remove the boot_custom key to switch this value off
  if Builtins.haskey(BootCommon.globals, "boot_custom")
    BootCommon.globals = Builtins.remove(BootCommon.globals, "boot_custom")
  end

  if selected_location == :root
    Ops.set(BootCommon.globals, "boot_root", "true")
  elsif selected_location == :boot
    Ops.set(BootCommon.globals, "boot_boot", "true")
  elsif selected_location == :mbr
    Ops.set(BootCommon.globals, "boot_mbr", "true")
    # Disable generic MBR as we want grub2 there
    Ops.set(BootCommon.globals, "generic_mbr", "false")
  elsif selected_location == :extended
    Ops.set(BootCommon.globals, "boot_extended", "true")
  end

  nil
end

- (String) soft_MDraid_boot_disk(partitions)

function check all partitions and it tries to find /boot partition if it is MD Raid and soft-riad return correct device for analyse MBR

Parameters:

  • list (map)

    list of partitions

Returns:

  • (String)

    device for analyse MBR



418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
# File 'src/include/bootloader/grub2/misc.rb', line 418

def soft_MDraid_boot_disk(partitions)
  partitions = deep_copy(partitions)
  result = ""
  boot_device = ""
  if BootStorage.BootPartitionDevice != nil &&
      BootStorage.BootPartitionDevice != ""
    boot_device = BootStorage.BootPartitionDevice
  else
    boot_device = BootStorage.RootPartitionDevice
  end

  Builtins.foreach(partitions) do |p|
    if Ops.get_string(p, "device", "") == boot_device
      if Ops.get(p, "type") == :sw_raid &&
          Builtins.tolower(Ops.get_string(p, "fstype", "")) == "md raid"
        device_1 = Ops.get_string(p, ["devices", 0], "")
        Builtins.y2debug("device_1: %1", device_1)
        dp = Storage.GetDiskPartition(device_1)
        Builtins.y2debug("dp: %1", dp)
        result = Ops.get_string(dp, "disk", "")
      end
    end
  end
  Builtins.y2milestone(
    "Device for analyse MBR from soft-raid (MD-Raid only): %1",
    result
  )
  result
end