ACC SHELL
/**
* File:
* include/bootloader/routines/lilolike.ycp
*
* Module:
* Bootloader installation and configuration
*
* Summary:
* Functions common for lilo-like bootloaders only
*
* Authors:
* Jiri Srain <jsrain@suse.cz>
* Olaf Dabrunz <od@suse.de>
*
* $Id: lilolike.ycp 62030 2010-05-19 07:58:43Z juhliarik $
*
*/
{
textdomain "bootloader";
import "Arch";
import "Mode";
import "Storage";
import "StorageDevices";
import "BootArch";
import "Map";
global string DiskOrderSummary ();
global void DetectDisks ();
global boolean DisksChanged ();
include "bootloader/routines/i386.ycp";
/**
* Check whether disk settings were changed since last checking
* @return boolean true if needs to recheck
*/
global boolean DisksChanged () {
if (Mode::config ())
return false;
map mp = Storage::GetMountPoints();
string actual_root = mp["/", 0]:"";
string actual_boot = mp["/boot", 0]:actual_root;
// don't change configuration if '/' and '/boot' were not changed
// and location is "floppy", "mbr" or "boot"
if (actual_boot == BootStorage::BootPartitionDevice
&& actual_root == BootStorage::RootPartitionDevice
&& selected_location != "custom"
&& selected_location != ""
&& selected_location != nil)
{
return false;
}
list all_partitions = BootStorage::getPartitionList(`boot, getLoaderType(false));
if (!contains(all_partitions, BootCommon::loader_device))
{
y2milestone ("Location should be set again");
return true;
}
return false;
}
/**
* FindMbrDisk()
* try to find the system's mbr device
* @return string mbr device
*/
global string FindMBRDisk() {
// check the disks order, first has MBR
list<string> order = BootStorage::DisksOrder ();
if (size (order) > 0)
{
string ret = order[0]:"";
y2milestone ("First disk in the order: %1, using for MBR", ret);
return ret;
}
// OK, order empty, use the disk with boot partition
map mp = Storage::GetMountPoints();
string boot_disk = mp["/boot",2]:(mp["/",2]:"");
y2milestone ("Disk with boot partition: %1, using for MBR", boot_disk);
return boot_disk;
}
/**
* 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
* @param list<map> list of partitions
* @return string device for analyse MBR
*/
define string soft_MDraid_boot_disk(list<map> partitions)
{
string result = "";
string boot_device = "";
if ((BootStorage::BootPartitionDevice != nil) && (BootStorage::BootPartitionDevice != ""))
boot_device = BootStorage::BootPartitionDevice;
else
boot_device = BootStorage::RootPartitionDevice;
foreach(map p, partitions, {
if (p["device"]:"" == boot_device)
{
if ((p["type"]:nil == `sw_raid) && (p["fstype"]:"" == "MD Raid"))
{
string device_1 = p["devices",0]:"";
y2debug("device_1: %1", device_1);
map dp = Storage::GetDiskPartition (device_1);
y2debug("dp: %1", dp);
result = dp["disk"]:"";
}
}
});
y2milestone("Device for analyse MBR from soft-raid (MD-Raid only): %1", result);
return result;
}
/**
* ConfigureLocation()
* Where to install the bootloader.
* Returns the type of device where to install: one of "boot", "root", "mbr", "mbr_md"
* Also sets internal global variable selected_location to this.
*
*
* @return string type of location proposed to bootloader
*/
// FIXME: replace with grub_ConfigureLocation() when lilo et al. have
// changed to stop using selected_location and loader_device.
string ConfigureLocation() {
selected_location = "mbr"; // default to mbr
loader_device = BootCommon::mbrDisk;
// check whether the /boot partition
// - is primary: is_logical -> false
// - is on the first disk (with the MBR): disk_is_mbr -> true
map<string,any> tm = Storage::GetTargetMap ();
map dp = Storage::GetDiskPartition (BootStorage::BootPartitionDevice);
string disk = dp["disk"]:"";
boolean disk_is_mbr = disk == mbrDisk;
map dm = tm[disk]:$[];
list<map> partitions = dm["partitions"]:[];
boolean is_logical = false;
string extended = nil;
list<string> needed_devices = [ BootStorage::BootPartitionDevice ];
map<string,integer> md_info = Md2Partitions (BootStorage::BootPartitionDevice);
if (md_info != nil && size (md_info) > 0)
{
disk_is_mbr = false;
needed_devices = maplist (string d, integer b, md_info, {
map pdp = Storage::GetDiskPartition (d);
string p_disk = pdp["disk"]:"";
if (p_disk == mbrDisk)
disk_is_mbr = true;
return d;
});
}
y2milestone ("Boot partition devices: %1", needed_devices);
foreach (map p, partitions, {
if (p["type"]:nil == `extended)
{
extended = (string)p["device"]:nil;
}
else if (contains (needed_devices, p["device"]:"")
&& p["type"]:nil == `logical)
{
is_logical = true;
}
});
y2milestone ("/boot is on 1st disk: %1", disk_is_mbr);
y2milestone ("/boot is in logical partition: %1", is_logical);
y2milestone ("The extended partition: %1", extended);
// keep_mbr, if the MBR contains special code that needs to be kept,
// like Thinkpad boot code (and ATM only Thinkpad boot code
// is recognized)
boolean keep_mbr = KeepMBR (loader_device);
integer exit = 0;
// if is primary, store bootloader there
if (disk_is_mbr && ! is_logical)
{
selected_location = "boot";
loader_device = BootStorage::BootPartitionDevice;
activate = true;
activate_changed = true;
// check if there is raid and if it soft-raid select correct device for analyse MBR
// bnc #398356
if (size (needed_devices) > 1)
disk = soft_MDraid_boot_disk(partitions);
if (disk == "")
disk = dp["disk"]:"";
string out = examineMBR(disk);
repl_mbr = (out != "vista") && (! keep_mbr);
}
else if (size (needed_devices) > 1)
{
loader_device = "mbr_md";
selected_location = "mbr_md";
}
if (keep_mbr)
{
if (is_logical && extended != nil)
loader_device = extended;
else
loader_device = BootStorage::BootPartitionDevice;
selected_location = "boot";
}
if (! contains (BootStorage::getPartitionList (`boot, getLoaderType(false)), loader_device))
{
selected_location = "mbr"; // default to mbr
loader_device = BootCommon::mbrDisk;
}
y2milestone ("ConfigureLocation (%1 on %2)",
selected_location, loader_device);
// set active flag
if (selected_location == "mbr")
{
// we are installing into MBR:
// if there is an active partition, then we do not need to activate
// one (otherwise we do)
activate = size (Storage::GetBootPartition (mbrDisk)) == 0;
}
else
{
// if not installing to MBR, always activate
activate = true;
}
return selected_location;
}
/**
* Detect /boot and / (root) partition devices
* If loader_device is empty or the device is not available as a boot
* partition, also calls ConfigureLocation to configure loader_device, set
* selected_location and set the activate flag if needed
* all these settings are stored in internal variables
*/
global void DetectDisks () {
// #151501: AutoYaST needs to know the activate flag and the
// loader_device; jsrain also said this code is probably a bug:
// commenting out, 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;
map mp = Storage::GetMountPoints();
list mountdata_boot = mp["/boot"]:(mp["/"]:[]);
list mountdata_root = mp["/"]:[];
y2milestone( "mountPoints %1", mp );
y2milestone( "mountdata_boot %1", mountdata_boot );
BootStorage::RootPartitionDevice = mp["/", 0]:"";
if (BootStorage::RootPartitionDevice == "")
{
y2error ("No mountpoint for / !!");
}
// if /boot changed, re-configure location
BootStorage::BootPartitionDevice
= mountdata_boot[0]:BootStorage::RootPartitionDevice;
if (BootCommon::mbrDisk == "" || BootCommon::mbrDisk == nil)
{
// mbr detection.
BootCommon::mbrDisk = FindMBRDisk();
}
if (loader_device == nil || loader_device == ""
|| ! contains (BootStorage::getPartitionList (`boot, getLoaderType(false)), loader_device))
ConfigureLocation ();
}
/**
* Converts the md device to the list of devices building it
* @param md_device string md device
* @return a map of devices (from device name to BIOS ID or nil if
* not detected) building the md device
*/
global define map<string, integer> Md2Partitions (string md_device) {
map<string,integer> ret = $[];
map<string,any> tm = (map<string,map>)Storage::GetTargetMap();
foreach (string disk, any descr_a, tm, ``{
map<string,any> descr = (map<string,any>)descr_a;
string bios_id_str = descr["bios_id"]:"";
integer bios_id = 256; // maximum + 1 (means: no bios_id found)
if (bios_id_str != "")
bios_id = tointeger (bios_id);
list<map<string,any> > partitions = (list<map<string,any> >)
descr["partitions"]:[];
foreach (map<string,any> partition, partitions, ``{
if (partition["used_by_device"]:"" == md_device)
{
string d = (string)(partition["device"]:"");
ret[d] = bios_id;
}
});
});
y2milestone ("Partitions building %1: %2", md_device, ret);
return ret;
}
/**
* Converts the md device to the first of its members
* @param md_device string md device
* @return string one of devices building the md array
*/
global define string Md2Partition (string md_device) {
map<string,integer> devices = Md2Partitions (md_device);
if (size (devices) == 0)
return md_device;
integer minimal = 129; // maximum + 2
string found = "";
foreach (string k, integer v, devices, {
if (v < minimal)
{
found = k;
minimal = v;
}
});
return found;
}
/**
* Run delayed updates
*
* This is used by perl-Bootloader when it cannot remove sections from the
* bootloader configuration from the postuninstall-script of the kernel. It
* writes a command to a delayed update script that is then called here to
* remove these sections.
*
* The script is deleted after execution.
*/
global void RunDelayedUpdates () {
string scriptname = "/boot/perl-BL_delayed_exec";
string cmd = sformat("test -x %1 && { cat %1 ; %1 ; }", scriptname);
y2milestone ("running delayed update command: %1", cmd);
map out = (map)SCR::Execute (.target.bash_output, cmd);
y2milestone ("command returned %1", out);
cmd = sformat("rm -f %1", scriptname);
out = (map)SCR::Execute (.target.bash_output, cmd);
}
/**
* fallback list for kernel flavors (adapted from Kernel.ycp), used if we have
* no better information
* order is from special to general, but prefer "default" in favor of "xen"
*/
// FIXME: handle "rt" and "vanilla"?
// bnc #400526 there is not xenpae anymore...
list<string> generic_fallback_flavors = [
"s390", "iseries64", "ppc64", "bigsmp", "default", "xen",
];
/**
* Fix global section of lilo-like bootloader
*
* This currently only tries to fix the "default" key if necessary. It is when
* the referenced section does not exist anymore or during a system update when
* a special comment in the bootloader configuration tells us that we have to
* update the "default" key. An empty "default" value is not changed, because
* this means that no default is wanted.
*
* If we need to fix the "default" key we take the following steps:
*
* - If we are fixing the configuration at the end of an update and the
* special key "former_default_image_flavor" exists, try to set the default
* to the first "linux.*" section with an image of this flavor (preferring
* "linux" entries over possibly older "linux-.*" entries).
*
* - Otherwise go through a list of fallback kernel flavours and use the first
* "linux.*" section that contains a matching image (preferring "linux"
* entries over possibly older "linux-.*" entries).
*
* - Otherwise, simply use the first section as the default section.
*/
global void FixGlobals () {
string defaultv = globals["default"]:"";
string first = "";
y2milestone ("fixing default section");
// nothing to do if default is empty
if (defaultv == "")
return;
// does default section exist?
boolean exists = false;
foreach (map<string,any> s, sections, {
string label = s["name"]:"";
if (label == defaultv)
exists = true;
if (first == "")
first = label;
});
if (exists &&
(! Mode::update() || globals["former_default_image_flavor"]:nil == nil))
return;
// need to fix "default"
boolean old_entry_found = false;
string found_name = "";
list<string> fallback_flavors = generic_fallback_flavors;
if (Mode::update() && globals["former_default_image_flavor"]:nil != nil) {
fallback_flavors = prepend(fallback_flavors, globals["former_default_image_flavor"]:"");
// former_default_image_flavor is removed at the end of the update
globals = remove (globals, "former_default_image_flavor");
}
y2milestone ("looking for image flavors %1", fallback_flavors);
foreach (string flavor, fallback_flavors, {
if (found_name != "")
return;
foreach (map<string,any> s, sections, {
string label = s["name"]:"";
if (regexpmatch (s["original_name"]:"", "^linux(-.*)?$") ||
regexpmatch (s["image"]:"", "^.*-" + flavor + "$")) {
// found, if we have not yet found a match, or the previously
// found one was for an "old" entry and we now found a "new"
// one
if (found_name == "" ||
(old_entry_found && regexpmatch (s["original_name"]:"", "^linux$"))) {
found_name = label;
if (regexpmatch (s["original_name"]:"", "^linux-.*$"))
old_entry_found = true;
else
old_entry_found = false;
}
}
});
});
if (found_name != "")
globals["default"] = found_name;
else
globals["default"] = first;
y2milestone ("setting new default section to: %1", globals["default"]:nil);
}
string getLargestSwapPartition () {
map<string, integer> swap_sizes = getSwapPartitions ();
list<string> swap_parts = (list<string>)
maplist (string name, integer size, swap_sizes, ``(name));
swap_parts = sort (string a, string b, swap_parts,
``(swap_sizes[a]:0 > swap_sizes[b]:0)
);
return swap_parts[0]:"";
}
/**
* Fix section of lilo-like bootloader
*/
global void FixSections (void() create_sections) {
list<string> parts = BootStorage::getPartitionList(`parts_old, getLoaderType(false));
if (partitioning_last_change
!= Storage::GetTargetChangeTime()
&& BootCommon::files_edited)
{
displayFilesEditedPopup ();
files_edited_warned = true;
return;
}
// save old sections and propose new ones in global "sections"
// (the updated list of old sections will become the new section list in
// the end)
list<map<string,any> > old_sect_list = sections;
create_sections ();
// new_sect is a map with elements containing: "type" -> section
map<string,map<string,any> > new_sect = listmap (map<string,any> s,
sections,
{
string label = s["name"]:"";
string type = s["original_name"]:label;
return $[type: s];
});
// remember a list with all the section "types" in the old section list
// (needed later in this function to find newly created sections)
list<string> old_section_types = maplist (map<string,any> s, old_sect_list,
{
return s["original_name"]:"";
});
// in the old list of sections:
// - only keep sections that the user created (no "__auto", or false) or
// changed ("__changed") in the UI
// - replace unchanged sections with ones we proposed just now (if
// available)
// - also notify user when devices for a "changed by user" section are
// unavailable or would now be proposed differently (and mark section as
// "created by user")
old_sect_list = maplist (map<string,any> s, old_sect_list, {
string label = s["name"]:"";
string type = s["original_name"]:label;
if (! s["__auto"]:false)
{
y2milestone ("Leaving section %1", label);
return s;
}
else if (! s["__changed"]:false)
{
y2milestone ("Recreating section %1, new is %2",
label, new_sect[type]:$[]);
return new_sect[type]:$[];
}
else
{
// section was created by us, then changed by the user:
// - keep it, except if no newly created section of same type can
// be found (which probably means we have a bug, because
// "__auto" says we created the old section as well)
// - maybe notify user to check it (and then mark it as a "user
// defined section")
y2milestone ("Warning on section %1", label);
boolean cont = true;
// if "non-standard" section name and a used device is not
// available anymore, notify user
if (type != "linux" && type != "failsafe"
&& type != "memtest86")
{
foreach (string n, s["__devs"]:[], {
if (! contains (parts, n))
{
cont = false;
}
});
}
// find section of same type in newly created sections;
// if not found (which should not happen, since according to the
// "__auto" key we created it) delete this section
map<string,any> new_this_section = new_sect[type]:$[];
if (new_this_section == $[]) {
y2warning("Warning, could not find freshly proposed section" +
"corresponding to section %1, deleting it",
s["name"]:"");
return $[];
}
// if the devices for this section and the freshly created one of
// the same type are different, notify user
list new_devs = toset(new_this_section["__devs"]:[]);
list old_devs = toset(s["__devs"]:[]);
if (size (new_devs) != size (old_devs))
cont = false;
else
{
foreach (any d, old_devs, ``{
if (! contains (new_devs, d))
cont = false;
});
}
// display info popup for this section;
// also, next time we come through this function, consider this
// section as a section created by the user (and leave it as it is)
if (! cont)
{
s["__auto"] = false;
displayDiskChangePopup (label);
}
return s;
}
});
// in newly created sections, fix "resume" parameter in append line if
// necessary
y2milestone ("Checking for sections using the resume parameter");
sections = maplist (map<string,any> s, BootCommon::sections, ``{
string append = s["append"]:"";
string resume = getKernelParamFromLine (append, "resume");
if (resume != "" && resume != nil
&& ! haskey (getSwapPartitions (), resume))
// points to unexistent swap partition
{
// bnc# 335526 - Installing memtest with lilo screws up installation
if (search(s["original_name"]:"", "memtest") == nil)
{
append = setKernelParamToLine (append, "resume", BootStorage::Dev2MountByDev(getLargestSwapPartition ()));
s["append"] = append;
}
}
return s;
});
// now add sections from newly created ones that were unknown before in the
// old section list, if not already removed by the user (#170469)
foreach (map<string,any> s, sections, {
string label = s["name"]:"";
string type = s["original_name"]:label;
if (! contains (old_section_types, type) &&
! contains (removed_sections, type))
{
y2milestone ("Adding new section \"%1\": %2",
label, s);
old_sect_list = add(old_sect_list, s);
return s;
}
});
// Strange (I must have misread the code here):
// if a newly created section uses one or more deleted devices, and a
// section of that type does not exist anymore in the old section list, add
// it to the old section list
y2milestone ("Checking for sections needing some of %1", del_parts);
list<string> to_remove = [];
foreach (map<string,any> s, sections, {
list<string> devs = s["__devs"]:[];
string label = s["name"]:"";
y2milestone ("Section %1 needs %2", label, devs);
boolean to_add = false;
foreach (string d, devs, {
if (contains (del_parts, d))
{
to_add = true;
}
});
if (to_add)
{
map old_sect = listmap (map<string,any> os, old_sect_list, {
return $[label: os];
});
if (label != "" && ! haskey(old_sect, label))
{
y2milestone ("Adding %1", s);
to_remove = add (to_remove, label);
old_sect_list = add (old_sect_list, s);
}
}
});
// FIXME: BUG: looks like a bug to remove a list of labels from the list of
// deleted devices
del_parts = (list<string>)difflist (del_parts, to_remove);
// cleanup: throw away empty sections
old_sect_list = filter (map<string,any> s, old_sect_list, {
return s != $[];
});
// save old, updated section list as proposed section list
sections = old_sect_list;
}
/**
* Update in section old devices to new kernel format
* @param section section to modify
*/
void UpdateDeviceForSection(map<string,any> section){
if (section["type"]:"" == "image" || section["type"]:"" == "xen")
{
//check if we update correct image and if update is needed
if (BootCommon::UpdateDevice(section["root"]:"nonexisted")
== BootStorage::RootPartitionDevice
&& section["root"]:""!=(BootCommon::UpdateDevice(section["root"]:"")))
{
y2milestone ("Updating device of section %1", section["name"]:"name");
section["root"]= BootCommon::UpdateDevice(section["root"]:"");
string resume
= BootCommon::getKernelParamFromLine (
section["append"]:"", "resume");
if (resume != "false")
{
y2milestone ("Updating resume device of section %1", section["name"]:"name");
resume = BootCommon::UpdateDevice (resume);
section["append"] = BootCommon::setKernelParamToLine (
section["append"]:"", "resume", BootStorage::Dev2MountByDev(resume));
}
section["__modified"] = "1";
}
}
}
/**
* Update sections of bootloader menu (removes obsolete thinks and
* place for ugly hacks (but doesn't efect zypper dup))
* modifies internal structures
* label update is done in perl-Bootloader during updating kernel
* Purpose is don't break anything, but expect that previous state is
* working
*/
global void UpdateSections ()
{
foreach (map<string,any> section, BootCommon::sections,{
//remap device names from hd* to sd*
UpdateDeviceForSection(section);
});
}
/*global void UpdateSections (boolean replace,
map<string,any>(string) create_linux_section)
{
list<map<string,any> > out = BootCommon::sections;
list<string> recreated = [];
boolean linux_resume_added = false;
map<string,any> default_sect = create_linux_section ("linux");
string default_kernel = default_sect["image"]:"";
string default_initrd = default_sect["initrd"]:"";
string default_name = default_sect["name"]:"";
list<string> sections_to_recreate = ["linux", "failsafe", "memtest86"];
if (getLoaderType (false) == "grub")
{
sections_to_recreate = add (sections_to_recreate, "xen");
}
// if replace == true, replace all sections that have a type in
// sections_to_recreate with a newly created version
// if replace == false, only adjust "append" line of "linux" section
//
// at the end of the loop, if one of the sections_to_recreate does not
// exist, create it
foreach (string t, sections_to_recreate, {
map<string,any> m = create_linux_section (t);
boolean f_changed = false;
out = maplist (map<string,any> s, out, {
string label = s["name"]:"";
string sect_type = s["original_name"]:"";
if (sect_type == "")
sect_type = label;
if (sect_type == t)
{
f_changed = true;
if (replace && m != $[])
{
y2milestone ("Recreated section %1: %2", label, m);
recreated = add (recreated, label);
return m;
}
else if (t == "linux")
{
string append = s["append"]:"";
string resume = BootCommon::getKernelParamFromLine (
append, "resume");
if (! haskey (BootCommon::getSwapPartitions (), resume))
{
append = setKernelParamToLine (append,
"resume", BootStorage::Dev2MountByDev(getLargestSwapPartition ()));
s["append"] = append;
linux_resume_added = true;
}
return s;
}
else
return s;
}
else
{
return s;
}
});
// if we did NOT change or replace the old section (meaning: there was
// none), but create_linux_section() gave us a new section, then
// prepend or append the section created by create_linux_section()
if (! f_changed && m != $[])
{
y2milestone ("Recreated section: %1", m);
recreated = add (recreated, m["name"]:"");
if (t == "linux")
out = prepend (out, m);
else
out = add (out, m);
}
});
y2milestone ("All recreated sections: %1", recreated);
// for grub and replace-mode only:
// convert sections that boot "other" installations (another Linux, Windows
// etc.) to chainloader and configfile sections
//
// ! contains (sections_to_recreate, original_name) AND
// original_name == name (e.g. "openSUSE 10.3 (/dev/sdb1)") AND
// haskey("image") AND
// haskey("initrd")
//
// => if bootable, convert to "chainloader"
// otherwise, convert to "configfile" and hope for the best
//
if (getLoaderType (false) == "grub" && replace)
{
y2milestone ("Converting sections for other installation to use chainloader/configfile entries...");
out = maplist (map<string,any> s, out, {
string label = s["name"]:"";
string sect_type = s["original_name"]:"";
y2milestone ("label: %1, sect_type: %2", label, sect_type);
if (!contains(sections_to_recreate, sect_type) &&
sect_type == label &&
haskey(s, "image") &&
haskey(s, "initrd"))
{
string dev = (string) s["root"]:nil;
// create new entry
s = $[
"name": label,
"original_name": sect_type,
"root": BootStorage::Dev2MountByDev(dev)
];
if (dev != nil && IsPartitionBootable(dev))
{
// bootable => chainloader
s["noverifyroot"] = "true";
s["chainloader"] = BootStorage::Dev2MountByDev(dev);
s["blockoffset"] = "1";
s["type"] = "other";
y2milestone ("Updating section \"%1\" booting other installation to use chainloader entry", s["name"]:"");
}
else
{
// not bootable => configfile
// let's hope the config file can be found (should work at
// least for all SUSE installations using grub)
s["configfile"] = "/boot/grub/menu.lst";
s["type"] = "menu";
y2milestone ("Updating section \"%1\" booting other installation to use configfile entry", s["name"]:"");
}
return s;
}
else
return s;
});
}
// now adjust these keys in sections that need it:
// - kernel
// - initrd
// - name
// - device (e.g. for SATA: /dev/hda -> /dev/sda)
// - append
out = maplist (map<string,any> s, out, {
string label = s["name"]:"";
string type = s["original_name"]:label;
// FIXME: do we still need to remove strings from kernel or initrd names?
// if yes: add "image"
// if no: remove loop
// probably need to do this depending on the version of the old
// installation
foreach (string key, ["image", "initrd"], {
string value = s[key]:"";
if (regexpmatch (value, "^.*\.shipped.*$"))
{
value = regexpsub (value,
"^(.*)\.shipped(.*)$", "\\1\\2");
}
else if (regexpmatch (value, "^.*\.suse.*$"))
{
value = regexpsub (value,
"^(.*)\.suse(.*)$", "\\1\\2");
}
// This was broken (was: s["key"] = value;)
s[key] = value;
});
// If we did not replace the sections anyway, adjust the section titles:
// Does this section
// - use the default kernel of a linux section \ i.e. it uses the updated kernel
// - use the default initrd of a linux section /
// - contain the name of the first "linux" section read from disk in
// its name
// then, update the section name
if (!replace
&& s["image"]:"" == default_kernel
&& s["initrd"]:"" == default_initrd
&& issubstring (s["name"]:"", read_default_section_name)
&& read_default_section_name != ""
&& read_default_section_name != default_name)
{
// idea of this:
// orig_name == "linux": "Linux" -> "<new name>"
// orig_name == "failsafe": "Failsafe -- Linux" -> "Failsafe -- <new name>"
y2milestone ("Updating label of section %1...", s["name"]:"");
string old_name = s["name"]:"";
integer i1 = search (old_name, read_default_section_name);
integer i2 = i1 + size (read_default_section_name);
s["name"] = substring (old_name, 0, i1) + default_name
+ substring (old_name, i2);
y2milestone ("... to %1", s["name"]:"");
}
// Update device names in sections for certain section types, if the
// section has not been recreated anyway
// FIXME: never update device names twice!
foreach (string key, ["root", "chainloader"], {
// FIXME: for some reason, this used to update "linux" and
// "failsafe" even if they have been recreated; but "other"
// sections were never updated -- since there are no calls to
// UpdateSections() with replace == false, ATM we disable updating
// "linux" and "failsafe", and add "other", seed
// BootCommon::update_section_types
if ((contains (update_section_types, type)
&& ! contains (recreated, label))
|| key == "chainloader")
{
string device = (string) s[key]:nil;
y2milestone ("Checking for update: device %1 of key %2, section %3", device, key, label);
if (device != nil)
{
y2milestone ("Updating root/other device of section %1",
label);
device = BootCommon::UpdateDevice (device);
s[key] = device;
}
}
});
if (type == "linux" && haskey (s, "append"))
{
string option = s["append"]:"";
foreach (string o, ListAdditionalKernelParams (), {
option = setKernelParamToLine (option, o, "false");
});
option = option + " " + GetAdditionalKernelParams ();
if (getKernelParamFromLine (option, "splash") == "false")
option = setKernelParamToLine
(option, "splash", "silent");
s["append"] = option;
}
else if (haskey (s, "append")
&& contains (BootCommon::update_section_types, type)
&& ! contains (recreated, label))
{
string option = s["append"]:"";
if (type != "linux" || ! linux_resume_added)
{
string resume
= BootCommon::getKernelParamFromLine (
option, "resume");
if (resume != "false")
{
y2milestone ("Updating resume device of section %1", label);
resume = BootCommon::UpdateDevice (resume);
option = BootCommon::setKernelParamToLine (
option, "resume", BootStorage::Dev2MountByDev(resume));
}
}
s["append"] = option;
}
return s;
});
sections = out;
}*/
/**
* Update global options of bootloader
* modifies internal sreuctures
*/
global void UpdateGlobals () {
if (BootCommon::globals["timeout"]:"" == "")
BootCommon::globals["timeout"] = "8";
list<string> s1_devs
= splitstring (BootCommon::globals["stage1_dev"]:"", ",");
s1_devs = maplist (string d, s1_devs, {
return UpdateDevice (d);
});
BootCommon::globals["stage1_dev"] = mergestring (s1_devs, ",");
// bnc #380509 if autoyast profile includes gfxmenu == none
// it will be deleted
if (BootCommon::globals["gfxmenu"]:"" != "none")
BootCommon::globals["gfxmenu"] = "/boot/message";
// now that the label for the "linux" section is not "linux" anymore, but
// some product dependent string that can change with an update ("SLES_10"
// -> "SLES_10_SP1"), we need to update the label in the "default" line for
// LILO and GRUB (although the latter only needs it to correctly transform
// back to the section number)
// FIXME: is this needed/wanted for ELILO as well?
if ( contains (["lilo", "grub"], getLoaderType (false)))
FixGlobals ();
}
/**
* Update the device map according to changed device names
* Read device map and store it in internal structures
*/
global void UpdateDeviceMap () {
BootStorage::device_mapping = mapmap (string unix, string fw, BootStorage::device_mapping, {
y2milestone ("Updating device in devmap entry %1 -> %2",
unix, fw);
unix = BootCommon::UpdateDevice (unix);
return $[ unix : fw ];
});
y2milestone ("Updated device map: %1", BootStorage::device_mapping);
}
/**
* Filter sections, remove those pointing to unexistent image
* @param path_prefix string prefix to be added to kernel path
* @param relative_path_prefix prefix to be added to relative kernel
* paths (without leading slash)
*/
global void RemoveUnexistentSections (string path_prefix,
string relative_path_prefix)
{
string defaultv = globals["default"]:"";
string first = nil;
BootCommon::sections = filter (map<string,any> s, BootCommon::sections, {
string label = s["name"]:"";
string type = s["original_name"]:"";
if (label == "")
{
y2warning ("Removing section with empty title");
if (label == defaultv)
defaultv = nil;
return false;
}
// FIXME the following check makes sense for all sections`
if (! contains (["linux", "failsafe", "memtest86", "xen"], type))
{
if (first == nil)
first = label;
return true;
}
string kernel = s["image"]:"";
if (kernel == "")
{
if (first == nil)
first = label;
return true;
}
if (substring (kernel, 0, 1) == "/")
{
kernel = path_prefix + kernel;
}
else
{
if (relative_path_prefix == "")
return true;
kernel = relative_path_prefix + kernel;
}
if (SCR::Read (.target.size, kernel) == -1)
{
y2warning ("Removing section %1 with unexistent kernel %2",
label, kernel);
if (label == defaultv)
defaultv = nil;
return false;
}
if (first == nil)
first = label;
return true;
});
if (defaultv == nil)
defaultv = first;
globals["default"] = defaultv;
}
/**
* Update append option if some parameters were changed
*/
global void UpdateAppend () {
sections = maplist (map<string,any> s, sections, {
string type = s["original_name"]:"";
if ((type == "linux" || type == "global")
&& s["append"]:nil != nil
&& Stage::initial ())
{
s["append"] = UpdateKernelParams (s["append"]:"");
}
return s;
});
if (haskey (globals, "append"))
{
globals["append"] = UpdateKernelParams (globals["append"]:"");
}
}
/**
* Update the gfxboot/message/... line if exists
*/
global void UpdateGfxMenu () {
string message = globals["gfxmenu"]:"";
if ((message != "") && (search(message, "(") == nil))
{
if (-1 == SCR::Read (.target.size, message))
{
globals = remove (globals, "gfxmenu");
}
}
}
/**
* Get the summary of disks order for the proposal
* @return string a line for the summary (or nil if not intended to be shown)
*/
global string DiskOrderSummary () {
list<string> order = BootStorage::DisksOrder ();
string ret = nil;
if (size (order) > 1)
{
ret = sformat (
// part of summary, %1 is a list of hard disks device names
_("Order of Hard Disks: %1"),
mergestring (order, ", "));
}
return ret;
}
/**
* Convert XEN boot section to normal linux section
* if intalling in domU (bnc #436899)
*
* @return boolean true if XEN section is converted to linux section
*/
boolean ConvertXENinDomU ()
{
boolean ret = false;
if (!Arch::is_xenU())
{
y2milestone("Don't convert XEN section - it is not running in domU");
return ret;
}
// tmp sections
list<map<string,any> > tmp_sections = [];
foreach(map<string,any> sec, BootCommon::sections,
{
// bnc#604401 Xen para-virtualized guest boots native kernel
// set XEN boot section to default
if (sec["type"]:"" == "xen" || sec["type"]:"" == "image")
{
if (search(tolower(sec["image"]:""), "xen") != nil)
{
y2milestone("Set \"xen\" image: %1 to default", sec["name"]:"");
BootCommon::globals["default"] = sec["name"]:"";
}
}
if (sec["type"]:"" != "xen")
{
tmp_sections = add(tmp_sections, sec);
} else {
// convert XEN section to linux section
y2milestone("Converting XEN section in domU: %1", sec);
sec["type"] = "image";
sec["original_name"] = "linux";
if (haskey(sec,"xen"))
sec = remove(sec, "xen");
if (haskey(sec,"xen_append"))
sec = remove(sec, "xen_append");
if (haskey(sec,"lines_cache_id"))
sec = remove(sec, "lines_cache_id");
y2milestone("Converted XEN section in domU: %1", sec);
tmp_sections = add(tmp_sections, sec);
ret = true;
}
});
BootCommon::sections = tmp_sections;
return ret;
}
} // EOF
/*
* Local variables:
* mode: ycp
* mode: font-lock
* mode: auto-fill
* indent-level: 4
* fill-column: 78
* End:
*/
ACC SHELL 2018