home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2007 January, February, March & April
/
Chip-Cover-CD-2007-02.iso
/
boot
/
i386
/
root
/
usr
/
share
/
YaST2
/
include
/
bootloader
/
routines
/
lilolike.ycp
< prev
next >
Wrap
Text File
|
2006-11-29
|
37KB
|
1,234 lines
/**
* 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>
*
* $Id: lilolike.ycp 34590 2006-11-24 18:33:17Z aosthof $
*
*/
{
textdomain "bootloader";
import "Arch";
import "Mode";
import "Storage";
import "StorageDevices";
import "BootArch";
global string DiskOrderSummary ();
global list<string> DisksOrder ();
global define void DetectDisks ();
global define boolean RefreshDisks();
global void ProposeDeviceMap ();
include "bootloader/routines/i386.ycp";
/**
* Is embedding 1.5 stage of bootloader to dedicated partition area possible?
* @return true if it is possible
*/
global boolean allowEmbed15 () {
// allow only for /boot or /root device selected
if (! (BootCommon::loader_device == BootCommon::BootPartitionDevice
|| BootCommon::loader_device == BootCommon::RootPartitionDevice
|| BootCommon::loader_device == BootCommon::mbrDisk
))
{
return false;
}
// check filesystem on /boot for Reiserfs and JFS
map mp = Storage::GetMountPoints ();
list bp_info
= mp["/boot"]:mp["/"]:[];
list<map> partitions
= Storage::GetTargetMap ()[bp_info[2]:"", "partitions"]:[];
boolean ret = false;
foreach (map p, partitions, {
if (p["device"]:"" == BootCommon::BootPartitionDevice)
{
symbol fs = (symbol)p["used_fs"]:nil;
if (fs == `reiser || fs == `jfs)
ret = true;
}
});
return ret;
}
/**
* 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 == BootCommon::BootPartitionDevice
&& actual_root == BootCommon::RootPartitionDevice
&& selected_location != "custom"
&& selected_location != ""
&& selected_location != nil)
{
return false;
}
list all_partitions = BootCommon::getPartitionList(`boot);
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 = 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;
}
/**
* 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.
*
* Sets internal global variables:
* - selected_location to the type of bootloader device (currently one of: "boot", "root", "mbr", "mbr_md")
* - loader_device to the actual device name to install the bootloader to (e.g. "/dev/hda1") or to "mbr_md"
* - activate to true if the loader_device needs to be activated in the MBR
* - activate_changed leave untouched, except when
* - booting from a primary /boot partition on the first disk (the one with the MBR seen by the BIOS), then set to true
* (FIXME: why only then?)
* - repl_mbr leave untouched, except when
* - booting from a primary /boot partition on the first disk, then set to true when
* - the examination of the code in the MBR
* - by examine_mbr.pl shows that it
* - DOES look like a LILO or GRUB MBR (always replace them with new versions) AND
* - DOES NOT look like a "generic MBR" (= DOS MBR) (OK as stage 1 to boot primary part. on 1st disk) AND
* - DOES NOT look like a valid "stage 1" at all (not enough entropy to contain valid code) AND
* - DOES look like some "stage 1" code (has enough entropy, but no known signature) AND
* - by KeepMBR() -> ThinkPadMBR() shows that it
* - DOES NOT look like a Thinkpad MBR (begins with specific code sequence from that one)
* otherwise set to false
*
* @return string type of location proposed to bootloader
*/
global define 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 (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 = [ BootPartitionDevice ];
map<string,integer> md_info = Md2Partitions (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);
// if is primary, store bootloader there
if (disk_is_mbr && ! is_logical)
{
selected_location = "boot";
loader_device = BootPartitionDevice;
activate = true;
activate_changed = true;
// examine_mbr.pl returns
// - 0 for a "Generic MBR" (DOS MBR)
// - 0 for an unknown MBR
// - 1 for a GRUB or lilo "stage 1"
// - 1 for an "invalid MBR", i.e. without enough entropy to
// contain boot code
map out = (map)SCR::Execute (.target.bash_output, sformat (
"/usr/lib/YaST2/bin/examine_mbr.pl %1", disk));
y2milestone ("MBR examining script returned %1", out);
integer exit = out["exit"]:0;
repl_mbr = (exit != 0) && (! 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 = BootPartitionDevice;
selected_location = "boot";
}
if (! contains (getPartitionList (`boot), 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 define void DetectDisks () ``{
/* map tm = Storage::GetTargetMap ();
list partitions = [];
foreach ( string dev, map disk, tm, ``{
if( Storage::IsRealDisk( disk ) )
{
list l = filter( map p, disk["partitions"]:[],
``(p["delete"]:false==false) );
partitions = merge (partitions, l);
}
});*/
// #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 );
BootCommon::RootPartitionDevice = mp["/", 0]:"";
if (BootCommon::RootPartitionDevice == "")
{
y2error ("No mountpoint for / !!");
}
// if /boot changed, re-configure location
BootCommon::BootPartitionDevice
= mountdata_boot[0]:BootCommon::RootPartitionDevice;
if (BootCommon::mbrDisk == "" || BootCommon::mbrDisk == nil)
{
// mbr detection.
BootCommon::mbrDisk = FindMBRDisk();
}
if (loader_device == nil || loader_device == ""
|| ! contains (getPartitionList (`boot), loader_device))
ConfigureLocation ();
/* if (mountdata_boot[3]:"" == "raid1")
{
list md_list = filter (`e, partitions,
``(e["used_by"]:"" == substring(mountdata_boot[0]:"",5)));
list dev_list = maplist (`e, md_list, ``(e["device"]:""));
dev_list = filter (`d, dev_list, ``(d != ""));
if (size (dev_list) > 0)
{
dev_list = sort (dev_list);
BootCommon::BootPartitionDevice = dev_list[0]:"";
}
}
if (mountdata_root[3]:"" == "raid1")
{
list md_list = filter (`e, partitions,
``(e["used_by"]:"" == substring(mountdata_root[0]:"",5)));
list dev_list = maplist (`e, md_list, ``(e["device"]:""));
dev_list = filter (`d, dev_list, ``(d != ""));
if (size (dev_list) > 0)
{
dev_list = sort (dev_list);
BootCommon::RootPartitionDevice = dev_list[0]:"";
}
}*/
}
/**
* 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 = 128; // maximum + 1
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"]:"" == substring(md_device,5))
{
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;
// devices = (list<string>)sort (devices);
// return devices[0]:"";
}
/**
* Get the md device a partition belongs to (or the partition itself if
* it doesn't exist
* @param device string a partition
* @return string the md device
*/
global define string Partition2Md (string device) {
string ret = device;
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;
list<map<string,any> > partitions = (list<map<string,any> >)
descr["partitions"]:[];
foreach (map<string,any> partition, partitions, ``{
if (partition["device"]:"" == device)
{
ret = (string)(partition["used_by"]:device);
if( search( ret, "/dev/" )!=0 )
ret = "/dev/"+ret;
}
});
});
y2milestone ("Partition %1 builds %2", device, ret);
return ret;
}
/**
* Refresh disk locations
* @return boolean true if bootloader location should be set again
*/
global define boolean RefreshDisks() ``{
boolean ret = true;
if (! DisksChanged ())
ret = false;
y2milestone ("Reconfiguring locations");
DetectDisks ();
return ret;
}
/**
* Answer whether LBA is supported
* @return boolean true if supported
*/
global boolean LbaSupport() {
if (Arch::i386 ())
{
list internal_bios = (list<map>)SCR::Read (.probe.bios);
return internal_bios[0, "lba_support"]:false;
}
else
return true;
}
/**
* IsBootAccessible()
* @return boolean true if accessible
*/
global define boolean IsBootAccessible() ``{
if (Mode::config ())
return true;
boolean boot_partition_accessible = true;
if (!LbaSupport())
{
string boot_mount_point = "";
// check, if no /boot partition exists
if (Storage::GetMountPoints()["/boot"]:"" == "")
{
boot_mount_point = "/";
}
else
{
boot_mount_point = "/boot";
}
// check if boot mount point is below cyl 1024
foreach (string dname, map ddata, (map<string,map>)Storage::GetTargetMap(),
``{
list<map> partitions = ddata["partitions"]:[];
if (partitions != [])
{
foreach (map pentry, partitions, ``{
if (pentry["mount"]:"" == boot_mount_point)
{
boot_partition_accessible =
(1024 > pentry["region",0]:0);
}
});
}
});
}
if (boot_partition_accessible)
y2milestone("Boot partition accessible");
else
y2milestone("Boot partition unaccessible");
return (boot_partition_accessible);
}
/**
* Should backup copy of bootloader bootsector be created?
* @return boolean true if yes.
*/
global define boolean createBackupBS () ``{
if (! Stage::initial ())
return false;
map mp = Storage::GetMountPoints ();
list data = mp["/boot"]:(mp["/"]:[]);
string bpd = data[0]:"";
// ???? FIXME ???? how about LVM/MD ????
return bpd == BootPartitionDevice;
}
/**
* Fix global section of lilo-like bootloader
* This currently only changes the "default" key to point to the first section,
* in case the referenced section does not exist anymore. An empty "default"
* value is not changed.
*/
global void FixGlobals () {
string defaultv = globals["default"]:"";
string first = "";
if (defaultv != "")
{
boolean exists = false;
foreach (map<string,any> s, sections, {
string label = s["name"]:"";
if (label == defaultv)
exists = true;
if (first == "")
first = label;
});
if (! exists)
globals["default"] = first;
}
}
/**
* Fix section of lilo-like bootloader
*/
global void FixSections (void() create_sections) {
list<string> parts = getPartitionList(`parts_old);
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
// - 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" && type != "wildcard")
{
foreach (string n, s["__devs"]:[], {
if (! contains (parts, n))
{
cont = false;
}
});
}
// if the devices for this section and the freshly created one of
// the same type are different, notify user
map<string,any> new_this_section = new_sect[type]:$[];
if (new_this_section == $[])
return $[];
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 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
{
append = setKernelParamToLine (append,
"resume", 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 sections of bootloader menu
* modifies internal structures
* @param replace boolean true if old sectinos shall be replaced
* @param create_linux_section a reference to a function to create linux
* section anew
*/
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["kernel"]:"";
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 != $[])
{
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", 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 != $[])
{
recreated = add (recreated, m["name"]:"");
if (t == "linux")
out = prepend (out, m);
else
out = add (out, m);
}
});
// 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;
foreach (string key, ["kernel", "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");
}
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["kernel"]:"" == 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"]:"");
}
foreach (string key, ["root", "chainloader"], {
if ((contains (update_section_types, type)
&& ! contains (recreated, label))
|| key == "chainloader")
{
string device = s["key"]:"";
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", resume);
}
}
s["append"] = option;
}
return s;
});
sections = out;
}
/**
* Update global options of bootloader
* modifies internal sreuctures
*/
global void UpdateGlobals () {
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, ",");
BootCommon::globals["gfxmenu"] = "/boot/message";
}
/**
* Update the device map according to changed device names
* Read device map and store it in internal structures
*/
global void UpdateDeviceMap () {
device_mapping = mapmap (string unix, string fw, device_mapping, {
y2milestone ("Updating device in devmap entry %1 -> %2",
unix, fw);
unix = BootCommon::UpdateDevice (unix);
return $[ unix : fw ];
});
y2milestone ("Updated device map: %1", 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"]:"";
// do not touch the wildcard section
if (regexpmatch (s["kernel"]:"", ".+\\-\\*"))
{
if (first == nil)
first = label;
return true;
}
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["kernel"]:"";
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;
}
/**
* Remove or add initrd option if needed, update append option if some
* parameters were changed
*/
global void UpdateInitrdLine () {
sections = maplist (map<string,any> s, sections, {
string initrd = s["initrd"]:"";
string title = s["name"]:"";
string type = s["original_name"]:"";
// do not touch the wildcard section
if (regexpmatch (s["initrd"]:"", ".+\\-\\*"))
{
return s;
}
if ((type == "linux" || type == "failsafe")
&& write_settings["insert_initrd"]:false)
{
s["initrd"] = BootArch::InitrdImage ();
}
else if (type == "xen" && write_settings["insert_initrd"]:false)
{
if (BootCommon::UsingXenPae())
s["initrd"] = "/boot/initrd-xenpae";
else
s["initrd"] = "/boot/initrd-xen";
}
if (initrd != "")
{
// check for initrd in GRUB format, keep them
// FIXME change the check for leading slash
if (getLoaderType (false) == "grub"
&& substring (initrd, 0, 1) == "(")
{
return s;
}
if (-1 == SCR::Read (.target.size, initrd) && haskey (s, "initrd"))
s = remove (s, "initrd");
}
return s;
});
}
/**
* 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 == "wildcard" || 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 != "")
{
if (-1 == SCR::Read (.target.size, message))
{
globals = remove (globals, "gfxmenu");
}
}
}
/**
* Generate device map proposal, store it in internal variables
*/
// FIXME: move that funbction out here, as it is grub only
global void ProposeDeviceMap () {
device_mapping = $[];
map<string,map> targetMap = $[];
if (Mode::config ())
y2milestone ("Skipping device map proposing in Config mode");
else
targetMap = (map<string,map>)Storage::GetTargetMap();
//FIXME: This is not the final solution, we must be able to handle both,
//FakeRAIDs _and_ single disks.
// Search in complete target map for "CT_DMRAID" types
map <string, map> DMTargetMap = filter (string k, map v, targetMap, {
return v["type"]:`CT_UNKNOWN==`CT_DMRAID;
});
// If no dmraids are present, search in complete target map for "CT_DISK"
// types. This should be the "normal" case.
if ( size(DMTargetMap) == 0 ) {
targetMap = filter (string k, map v, targetMap, {
return v["type"]:`CT_UNKNOWN==`CT_DISK;
});
} else {
// If dmraid(s) are found, only use them
// Get all available dmraids in the proper BIOS order
map out = (map) SCR::Execute (.target.bash_output, "dmraid -s -c");
if ( out["exit"]:0 == 0 && out["stdout"]:"" != "" ) {
list<string> DMRaid_devices_in_BIOS_order =
splitstring (out["stdout"]:"", "\n");
// Remove last list entry (because it is empty)
integer index_empty = size(DMRaid_devices_in_BIOS_order) - 1;
DMRaid_devices_in_BIOS_order =
remove(DMRaid_devices_in_BIOS_order, index_empty);
integer DMRaidBiosID = 128;
// FIXME: This code only work when YaST2-Storage either assigns
// BIOS-IDs to all available DMRaid devices or to none of them.
// Probably it's best to throw this code away once YaST2-Storage
// assigns BIOS-IDs to all available DMRaid devices.
// Assign BIOS-IDs to DMRaid devices in the Target Map in BIOS
// order
DMTargetMap = listmap (string DMRaidDevice, DMRaid_devices_in_BIOS_order, {
DMRaidDevice = "/dev/mapper/" + DMRaidDevice;
if (haskey(DMTargetMap, DMRaidDevice)) {
if ( !haskey(DMTargetMap[DMRaidDevice]:$[], "bios_id") ) {
DMTargetMap[DMRaidDevice, "bios_id"] = tohexstring(DMRaidBiosID);
DMRaidBiosID = DMRaidBiosID + 1;
}
return $[ DMRaidDevice : DMTargetMap[DMRaidDevice]:$[] ];
}
});
y2milestone("sorted (according to BIOS) DMTargetMap: %1", DMTargetMap);
} else {
y2error ("Command: \"dmraid -s -c\" failed, no sorting of DMTargetMap.");
}
targetMap = DMTargetMap;
}
y2milestone ("Target map: %1", targetMap);
// add devices with known bios_id
// collect BIOS IDs which are used
map ids = $[];
foreach (string target_dev, map target, targetMap, {
string bios_id = target["bios_id"]:"";
if (bios_id != "")
{
integer index = tointeger (bios_id) - tointeger ("0x80");
string grub_dev = sformat ("hd%1", index);
device_mapping[target_dev] = grub_dev;
ids[index] = true;
}
});
// and guess other devices
// don't use already used BIOS IDs
foreach (string target_dev, map target, targetMap, {
string bios_id = target["bios_id"]:"";
if (bios_id == "")
{
integer index = 0;
while (ids[index]:false)
index = index + 1;
string grub_dev = sformat ("hd%1", index);
device_mapping[target_dev] = grub_dev;
ids[index] = true;
}
});
if (StorageDevices::FloppyPresent)
device_mapping[StorageDevices::FloppyDevice] = "fd0";
y2milestone ("Detected device mapping: %1", device_mapping);
}
/**
* Get the order of disks according to BIOS mapping
* @return a list of all disks in the order BIOS sees them
*/
global list<string> DisksOrder () {
if (device_mapping == nil || size (device_mapping) == 0)
{
ProposeDeviceMap ();
}
map<string,string> devmap_rev = mapmap (string k, string v,
BootCommon::device_mapping,
{
return $[ v : k ];
});
devmap_rev = filter (string k, string v, devmap_rev, {
return substring (k, 0, 2) == "hd";
});
list<string> order = maplist (string k, string v, devmap_rev, {
return v;
});
return order;
}
/**
* 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 = 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;
}
} // EOF
/*
* Local variables:
* mode: ycp
* mode: font-lock
* mode: auto-fill
* indent-level: 4
* fill-column: 78
* End:
*/