ACC SHELL
/**
* File:
* include/bootloader/routines/misc-common.ycp
*
* Module:
* Bootloader installation and configuration
*
* Summary:
* Miscelaneous functions for bootloader configuration and installation
*
* Authors:
* Jiri Srain <jsrain@suse.cz>
* Olaf Dabrunz <od@suse.de>
*
* $Id: misc.ycp 61035 2010-02-26 09:20:36Z juhliarik $
*
* WARNING:
* To be included to BootCommon.ycp only, requires function
* getLoaderType to avoid include-import cycle
* Use import "BootCommon" instead.
*/
{
textdomain "bootloader";
import "Mode";
import "Stage";
import "Storage";
import "StorageDevices";
import "Report";
import "Kernel";
import "Misc";
import "ProductFeatures";
import "Directory";
import "Installation";
import "FileUtils";
import "String";
import "FileUtils";
// bootloader attributes handling functions
global map<string, integer> Md2Partitions (string md_device);
global void DetectDisks ();
global string getBootPartition();
/**
* return printable name of bootloader
* @param bootloader string bootloader type internal string
* @param mode symbol `combo or `summary (because of capitalization)
* @return string printable bootloader name
*/
global define string getLoaderName (string bootloader, symbol mode) ``{
if (bootloader == "none")
{
return mode == `summary
// summary string
? _("Do not install any boot loader")
// combo box item
: _("Do Not Install Any Boot Loader");
}
if (bootloader == "default")
{
return mode == `summary
// summary string
? _("Install the default boot loader")
// combo box item
: _("Install Default Boot Loader");
}
string fallback_name = mode == `summary
// summary string
? _("Boot loader")
// combo box item
: _("Boot Loader");
// fallback bootloader name, keep short
return bootloader_attribs[bootloader, "loader_name"]:fallback_name;
}
/**
* Get value of specified boolean bootloader attribute
* @param attrib string attribute name
* @return boolean value of attribute
*/
global define boolean getBooleanAttrib (string attrib) ``{
return current_bootloader_attribs[attrib]:false;
}
/**
* Get value of specified bootloader attribute
* @param attrib string attribute name
* @param defaultv any default value of the attribute (if not found)
* @return any value of attribute
*/
global define any getAnyTypeAttrib (string attrib, any defaultv) ``{
return current_bootloader_attribs[attrib]:defaultv;
}
// other misc functions
/**
* Update the text of countdown widget
* @param bootloader string printable name of used bootloader
*/
global define void updateTimeoutPopupForFloppy (string bootloader) ``{
if (Mode::normal ())
return;
string confirm_boot_msg = Misc::boot_msg;
// data saved to floppy disk
string msg = sformat (
// popup, %1 is bootloader name
_("The %1 boot sector has been written to the floppy disk."),
bootloader);
msg = msg + "\n";
// always hard boot
// If LILO was written on floppy disk and we need
// to do a hard reboot (because a different kernel
// was installed), tell the user to leave the floppy
// inserted.
msg = msg
// popup - continuing
+ _("Leave the floppy disk in the drive.");
if ( size (confirm_boot_msg) > 0 )
{
msg = msg + "\n" + confirm_boot_msg;
}
Misc::boot_msg = msg;
}
/**
* Function remap globals settings "boot_custom" device name (/dev/sda)
* or to label (ufo_partition)
* @param map<string,string> globals
* @return map<string,string> globals
*/
global map<string,string> remapGlobals(map<string,string> globals_set)
{
symbol by_mount = nil;
if (Arch::ppc())
by_mount = `id;
else
by_mount = Storage::GetDefaultMountBy();
//by_mount = `id;
if (by_mount == `label)
return globals_set;
if (haskey(globals_set, "boot_custom"))
{
globals_set["boot_custom"] = BootStorage::MountByDev2Dev(globals_set["boot_custom"]:"");
}
if (haskey(globals_set, "boot_chrp_custom"))
{
globals_set["boot_chrp_custom"] = BootStorage::MountByDev2Dev(globals_set["boot_chrp_custom"]:"");
}
if (haskey(globals_set, "boot_pmac_custom"))
{
globals_set["boot_pmac_custom"] = BootStorage::MountByDev2Dev(globals_set["boot_pmac_custom"]:"");
}
if (haskey(globals_set, "boot_iseries_custom"))
{
globals_set["boot_iseries_custom"] = BootStorage::MountByDev2Dev(globals_set["boot_iseries_custom"]:"");
}
if (haskey(globals_set, "boot_prep_custom"))
{
globals_set["boot_prep_custom"] = BootStorage::MountByDev2Dev(globals_set["boot_prep_custom"]:"");
}
return globals_set;
}
/**
* Function remap "resume" from section (append) to device name (/dev/sda)
* or to label (ufo_partition)
*
* @param map<string,any> sections
* @param boolean true if convert resume to persistent device name
* @return map<string,any> sections
*/
define string remapResume(string append, boolean to_persistent)
{
if ((search(append, "resume")!=nil) && (search(append, "noresume") == nil))
{
y2milestone("append before remapping resume: %1", append);
list <string> list_append = splitstring (append, " ");
y2debug("split append to list list_append: %1", list_append);
list <string> new_append = [];
foreach(string key, list_append,
{
if (search(key,"resume") != nil)
{
y2debug("arg resume from append: %1",key);
list <string> resume_arg = splitstring(key, "=");
string dev = resume_arg[1]:"";
y2debug("value of resume: %1",resume_arg[1]:"");
if (dev != "")
{
string resume ="";
// bnc#533782 - after changing filesystem label system doesn't boot
if (to_persistent)
resume = "resume="+BootStorage::Dev2MountByDev(dev);
else
resume = "resume="+BootStorage::MountByDev2Dev(dev);
y2debug("remap resume: %1",resume);
new_append = add(new_append, resume);
} else {
y2debug("adding key to new append_list: %1", key);
new_append = add(new_append, key);
}
} else {
y2debug("adding key to new append_list: %1", key);
new_append = add(new_append, key);
}
});
y2debug("NEW append list: %1", new_append);
string ret = mergestring(new_append, " ");
y2milestone("Append after remaping: %1", ret);
return ret;
} else {
y2milestone("Section hasn't resume...");
return append;
}
}
/**
* Function remap section "root" and "resume" to device name (/dev/sda)
* or to label (ufo_partition)
* it also prepared measured files for export
* @param list<map<string,any> > list of sections
* @return list<map<string,any> > list of sections
*/
global list<map<string,any> > remapSections(list<map<string,any> >sec)
{
symbol by_mount = nil;
if (Arch::ppc())
by_mount = `id;
else
by_mount = Storage::GetDefaultMountBy();
//by_mount = `id;
if (by_mount == `label)
return sec;
list<map<string,any> >temp_sec = [];
// convert root and resume device names in sections to kernel device names
temp_sec = maplist (map<string,any> s, sections,
{
if (s["root"]:"" != "")
{
string rdev = s["root"]:"";
s["root"] = BootStorage::MountByDev2Dev(rdev);
if (s["append"]:"" != "")
s["append"] = remapResume(s["append"]:"", false);
y2debug("remapping root: %1 from section to: %2 ",rdev ,s["root"]:"");
}
if (s["chainloader"]:"" != "")
s["chainloader"] = BootStorage::MountByDev2Dev(s["chainloader"]:"");
return s;
});
return temp_sec;
}
/**
* returns true if char is blank (newline, tab or space)
* @param s single char string
* @return boolean blank/non blank
*/
global define boolean isBlank(string s) ``{
if (s == "\n" || s == "\t" || s == " ")
{
return true;
}
return false;
}
/**
* returns list difference A \ B (items that are in A and are not in B)
* @param a list A
* @param b list B
* @return list see above
*/
list difflist(list a, list b) ``{
return filter(any e, a, ``(!contains(b, e)));
}
/**
* translate filename path (eg. /boot/kernel) to list of device
* and relative path
* @param fullpth string fileststem path (eg. /boot/vmlinuz)
* @return a list containing device and relative path,
* eg. ["/dev/hda1", "/vmlinuz"]
*/
global define list<string> splitPath (string fullpth) ``{
// UGHLY HACK because of testsuites
map<string,list> mountpoints = $[];
if (Mode::test ())
mountpoints = $["/" : ["/dev/hda2"], "/boot" : ["/dev/hda1"]];
else
mountpoints = (map<string,list>)Storage::GetMountPoints();
string dev = "";
string mp = "";
integer max = 0;
//
// FIXME: this is broken code, implement a proper prefix match!! see below
foreach (string k, list v, mountpoints, ``{
if (k != "swap" && issubstring (fullpth, k) && size (k) > max)
{
max = size (k);
dev = v[0]:"";
mp = k;
}
});
if (mp == "")
return [];
// FIXME: pth will be wrong for fullpth=='(hd0,1)/boot/vmlinux' !!
string pth = substring (fullpth, size (mp));
if (substring (pth, 0, 1) != "/")
pth = "/" + pth;
return [dev, pth];
}
/**
* Get bootloader device for specified location
* FIXME: this function is being phased out. Keeping it around until
* selected_location and loader_device can be dropped for all bootloader
* types.
* @return string device name
*/
global define string GetBootloaderDevice () ``{
if (BootCommon::selected_location == "mbr")
return BootCommon::mbrDisk;
if (BootCommon::selected_location == "boot")
return BootStorage::BootPartitionDevice;
if (BootCommon::selected_location == "root")
return BootStorage::RootPartitionDevice;
if (BootCommon::selected_location == "floppy")
return StorageDevices::FloppyDevice();
if (BootCommon::selected_location == "mbr_md")
return "mbr_md";
if (BootCommon::selected_location == "none")
return "/dev/null";
return BootCommon::loader_device;
}
/**
* Get list of bootloader device names for all selected or specified
* locations
* @return list device names
*/
global define list<string> GetBootloaderDevices () ``{
list<string> ret = [];
if (BootCommon::globals["boot_boot"]:"false" == "true") {
ret = add(ret, BootStorage::BootPartitionDevice);
}
if (BootCommon::globals["boot_root"]:"false" == "true") {
ret = add(ret, BootStorage::RootPartitionDevice);
}
if (BootCommon::globals["boot_mbr"]:"false" == "true") {
ret = add(ret, BootCommon::mbrDisk);
}
if ( haskey(BootCommon::globals, "boot_extended") &&
BootCommon::globals["boot_extended"]:"false" == "true" ) {
ret = add(ret, BootStorage::ExtendedPartitionDevice);
}
// FIXME: floppy support is probably obsolete
if ( haskey(BootCommon::globals, "boot_floppy") &&
BootCommon::globals["boot_floppy"]:"false" == "true" ) {
ret = add(ret, StorageDevices::FloppyDevice());
}
if ( haskey(BootCommon::globals, "boot_custom") ) {
ret = add(ret, BootCommon::globals["boot_custom"]:"");
}
if ( size(ret) > 0 )
return ret;
// FIXME: find out what the best value is here: nil, [] or ["/dev/null"]
return ["/dev/null"];
}
/**
* Check if the PBR of the given partition seems to contain a known boot block
* @param device string partition device to check
* @return true if the PBR seems to contain a known boot block
*/
global boolean IsPartitionBootable (string device) {
//FIXME this is only for grub and should go to BootGRUB
// use examineMBR to analyze PBR (partition boot record):
// examineMBR returns "* stage1" when it finds the signature
// of some stage1 bootloader
string result = examineMBR(device);
if ((result == "grub") || (result == "lilo"))
return true;
else
return false;
}
/**
* Check if installation to floppy is performed
* @return true if installing bootloader to floppy
*/
global boolean InstallingToFloppy () {
boolean ret = false;
// Bug 539774 - bootloader module wants to write to floppy disk although there is none
if ((loader_device == nil) || (loader_device == ""))
return ret; // bug #333459 - boot loader editor: propose new configuration
// -- BLE tries to write something on the floppy disk
// bnc #180784 don't install to bootloader to floppy if ppc
if (getLoaderType (false) == "ppc")
ret = false;
else if (loader_device == StorageDevices::FloppyDevice())
ret = true;
else if (contains (BootStorage::getFloppyDevices (), loader_device))
ret = true;
y2milestone ("Installing to floppy: %1", ret);
return ret;
}
/**
* Get the list of particular kernel parameters
* @param line string the whole kernel command line
* @return a list of the kernel parameters split each separaterlly
*/
list<string> ListKernelParamsInLine (string line) {
// FIXME this function is really similar to code in Kernel.ycp
list<string> cmdlist = [];
integer parse_index = 0;
boolean in_quotes = false;
boolean after_backslash = false;
string current_param = "";
while (parse_index < size (line))
{
string current_char = substring (line, parse_index, 1);
if (current_char == "\"" && ! after_backslash)
in_quotes = ! in_quotes;
if (current_char == " " && ! in_quotes)
{
cmdlist = add (cmdlist, current_param);
current_param = "";
}
else
current_param = current_param + current_char;
if (current_char == "\\")
after_backslash = true;
else
after_backslash = false;
parse_index = parse_index + 1;
}
cmdlist = add (cmdlist, current_param);
cmdlist = maplist (string c, cmdlist, {
if (regexpmatch (c, "^[^=]+="))
c = regexpsub (c, "^([^=]+)=", "\\1");
return c;
});
return cmdlist;
}
/**
* get kernel parameter from kernel command line
* @param line string original line
* @param key string parameter key
* @return string value, "false" if not present,
* "true" if present key without value
*/
global define string getKernelParamFromLine (string line, string key) ``{
// FIXME this doesn't work with quotes and spaces
string res = "false";
list<string> params = splitstring (line, " ");
params = filter (string p, params, ``(p != ""));
foreach (string p, params, ``{
list<string> l = (list<string>) filter (string e, splitstring (p, "="), ``(e != " " && e != ""));
if (l[0]:"" == key)
res = l[1]:"true";
});
return res;
}
/**
* set kernel parameter to GRUB command line
* @param line string original line
* @param key string parameter key
* @param value string value, "false" to remove key,
* "true" to add key without value
* @return string new kernel command line
*/
global define string setKernelParamToLine
(string line, string key, string value)
``{
// FIXME this doesn't work with quotes and spaces
list<string> params = splitstring (line, " ");
params = filter (string p, params, ``(p != ""));
boolean done = false;
// count occurences of every parameter
map<string,integer> occurences = $[];
foreach (string p, params, ``{
list<string> l = filter (string e, splitstring (p, "="), ``(e != " " && e != ""));
string k = l[0]:"";
occurences[k] = occurences[k]:0 + 1;
});
params = maplist (string p, params, ``{
list<string> l = filter (string e, splitstring (p, "="), ``(e != " " && e != ""));
string k = l[0]:"";
if (k == key)
{
if (value == "false")
{
return "";
}
else if (occurences[k]:0 <= 1)
{
done = true;
if (value == "true")
{
return key;
}
else if (value != "false")
{
return sformat ("%1=%2", key, value);
}
}
else
{
occurences[k] = occurences[k]:0 - 1;
return "";
}
}
return p;
});
if (! done)
{
if (value == "true")
{
params = add (params, key);
}
else if (value != "false")
{
params = add (params, sformat ("%1=%2", key, value));
}
}
params = filter (string p, params, ``(p != ""));
line = mergestring (params, " ");
return line;
}
/*
* convert any value to an integer and return 0 for nonsense
*/
global integer myToInteger(any num_any) {
if (num_any == nil)
return 0;
if (is (num_any, integer))
return (integer)num_any;
if (is (num_any, string))
return (num_any == "") ? 0 :
(tointeger((string)num_any) == nil ? 0 : tointeger((string)num_any));
return 0;
}
/**
* Get partition which should be activated if doing it during bl inst.
* @param boot_partition string the partition holding /boot subtree
* @param loader_device string the device to install bootloader to
* @return a map $[ "dev" : string, "mbr": string, "num": any]
* containing device (eg. "/dev/hda4"), disk (eg. "/dev/hda") and
* partition number (eg. 4)
*/
map<string,any> getPartitionToActivate (string boot_partition,
string loader_device)
{
map p_dev = Storage::GetDiskPartition (loader_device);
integer num = myToInteger( p_dev["nr"]:nil );
string mbr_dev = p_dev["disk"]:"";
// if bootloader is installed to /dev/md*
// FIXME: use ::storage to detect md devices, not by name!
if (substring (loader_device, 0, 7) == "/dev/md")
{
map<string,integer> md = Md2Partitions (BootCommon::loader_device);
integer min = 256; // max. is 255; 256 means "no bios_id found"
string device = "";
foreach (string d, integer id, md, {
if (id < min)
{
min = id;
device = d;
}
});
if (device != "")
{
map p_dev = Storage::GetDiskPartition (device);
num = myToInteger( p_dev["nr"]:nil );
mbr_dev = p_dev["disk"]:"";
}
}
// if bootloader in MBR, activate /boot partition
// (partiall fix of #20637)
else if (num == 0)
{
p_dev = Storage::GetDiskPartition (boot_partition);
num = myToInteger( p_dev["nr"]:nil );
mbr_dev = p_dev["disk"]:"";
if (size (Md2Partitions (boot_partition)) > 1)
{
foreach (string k, integer v, Md2Partitions (boot_partition),{
if (search (k, loader_device) == 0)
{
p_dev = Storage::GetDiskPartition (k);
num = myToInteger( p_dev["nr"]:nil );
mbr_dev = p_dev["disk"]:"";
}
});
}
}
if (num != 0)
{
if (num > 4)
{
y2milestone ("Bootloader partition type is logical");
map tm = Storage::GetTargetMap ();
list<map> partitions = tm[mbr_dev, "partitions"]:[];
foreach (map p, partitions, ``{
if (p["type"]:nil == `extended)
{
num = p["nr"]:num;
y2milestone ("Using extended partition %1 instead",
num);
}
});
}
}
map<string,any> ret = $[
"num" : num,
"mbr" : mbr_dev,
"dev" : Storage::GetDeviceName (mbr_dev, num),
];
return ret;
}
/**
* Get a list of partitions to activate if user wants to activate
* boot partition
* @return a list of partitions to activate
*/
list<map<string, any> > getPartitionsToActivate () {
map<string,integer> md = $[];
if (BootCommon::loader_device == "mbr_md")
{
md = Md2Partitions (BootStorage::BootPartitionDevice);
}
else
{
md = Md2Partitions (BootCommon::loader_device);
}
list<string> partitions = maplist (string k, integer v, md, ``(k));
if (size (partitions) == 0)
{
partitions = [BootCommon::loader_device];
}
list<map<string,any> > ret = maplist (string partition, partitions, {
return getPartitionToActivate (
BootStorage::BootPartitionDevice,
partition);
});
return toset (ret);
}
/**
* Get the list of MBR disks that should be rewritten by generic code
* if user wants to do so
* @return a list of device names to be rewritten
*/
list<string> getMbrsToRewrite () {
list<string> ret = [BootCommon::mbrDisk];
map<string,integer> md = $[];
if (BootCommon::loader_device == "mbr_md")
{
md = Md2Partitions (BootStorage::BootPartitionDevice);
}
else
{
md = Md2Partitions (BootCommon::loader_device);
}
list<string> mbrs = maplist (string d, integer b, md, {
d = getPartitionToActivate (
BootStorage::BootPartitionDevice, d
)["mbr"]:mbrDisk;
return d;
});
if (contains (mbrs, BootCommon::mbrDisk))
{
ret = (list<string>)merge (ret, mbrs);
}
return toset (ret);
}
/**
* Get last change time of file
* @param filename string name of file
* @return string last change date as YYYY-MM-DD-HH-MM-SS
*/
string getFileChangeDate (string filename) {
map stat = (map) SCR::Read (.target.stat, filename);
integer ctime = stat["ctime"]:0;
string command = sformat (
"date --date='1970-01-01 00:00:00 %1 seconds' +\"%%Y-%%m-%%d-%%H-%%M-%%S\"",
ctime);
map out = (map) SCR::Execute (.target.bash_output, command);
string c_time = out["stdout"]:"";
y2debug ("File %1: last change %2", filename, c_time);
return c_time;
}
/**
* Save current MBR to /boot/backup_mbr
* Also save to /var/lib/YaST2/backup_boot_sectors/%device, if some
* existing, rename it
* @param device string name of device
*/
void saveMBR (string device) {
string device_file = mergestring (splitstring (device, "/"), "_");
string device_file_path = "/var/lib/YaST2/backup_boot_sectors/"
+ device_file;
string device_file_path_to_logs = "/var/log/YaST2/"
+ device_file;
SCR::Execute (.target.bash,
"test -d /var/lib/YaST2/backup_boot_sectors || mkdir /var/lib/YaST2/backup_boot_sectors");
if (SCR::Read (.target.size, device_file_path) > 0)
{
list<string> contents = (list<string>) SCR::Read (.target.dir, "/var/lib/YaST2/backup_boot_sectors");
contents = filter (string c, contents, ``(regexpmatch (c, sformat (
"%1-.*-.*-.*-.*-.*-.*", device_file))));
contents = sort (contents);
integer index = 0;
integer siz = size (contents);
while (index + 10 < siz)
{
SCR::Execute (.target.remove,
sformat ("/var/lib/YaST2/backup_boot_sectors/%1", contents[index]:""));
index = index + 1;
}
string change_date = getFileChangeDate (device_file_path);
SCR::Execute (.target.bash, sformat (
"/bin/mv %1 %1-%2",
device_file_path, change_date));
}
SCR::Execute (.target.bash, sformat (
"/bin/dd if=%1 of=%2 bs=512 count=1 2>&1",
device, device_file_path));
// save MBR to yast2 log directory
SCR::Execute (.target.bash, sformat (
"/bin/dd if=%1 of=%2 bs=512 count=1 2>&1",
device, device_file_path_to_logs));
if (device == mbrDisk)
{
SCR::Execute (.target.bash, sformat (
"/bin/dd if=%1 of=%2 bs=512 count=1 2>&1",
device, "/boot/backup_mbr"));
// save thinkpad MBR
if (BootCommon::ThinkPadMBR(device))
{
string device_file_path_thinkpad = device_file_path + "thinkpadMBR";
y2milestone("Backup thinkpad MBR");
SCR::Execute(.target.bash, sformat (
"cp %1 %2 2>&1", device_file_path, device_file_path_thinkpad));
}
}
}
/**
* Update contents of MBR (active partition and booting code)
* FIXME move tis function to lilolike.ycp
* @return boolean true on success
*/
global define boolean updateMBR () ``{
// FIXME: do the real thing in perl_Bootloader
if (getLoaderType (false) == "grub") {
activate = ( globals["activate"]:"false" == "true" );
repl_mbr = ( globals["generic_mbr"]:"false" == "true" );
}
y2milestone ("Updating disk system area, activate partition: %1, replace MBR: %2", activate, repl_mbr);
if (backup_mbr)
{
y2milestone ("Doing MBR backup: MBR Disk: %1, loader device: %2",
BootCommon::mbrDisk, BootCommon::loader_device);
list<string> disks_to_rewrite = (list<string>)toset (merge (
getMbrsToRewrite (),
[BootCommon::mbrDisk, BootCommon::loader_device]));
y2milestone ("Creating backup of boot sectors of %1",
disks_to_rewrite);
foreach (string d, disks_to_rewrite, {
saveMBR (d);
});
}
boolean 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 a generic (currently DOS?) bootloader
if (repl_mbr && BootCommon::loader_device != mbrDisk)
{
if (! Stage::initial ())
{
PackageSystem::Install ("master-boot-code");
}
y2milestone("Updating code in MBR: MBR Disk: %1, loader device: %2",
BootCommon::mbrDisk, BootCommon::loader_device);
list<string> disks_to_rewrite = getMbrsToRewrite ();
foreach (string d, disks_to_rewrite, {
y2milestone ("Copying generic MBR code to %1", d);
// added fix 446 -> 440 Vista booting problem bnc # 396444
string command = sformat (
"/bin/dd bs=440 count=1 if=%1 of=%2",
"/usr/lib/boot/master-boot-code",
d);
y2milestone ("Running command %1", command);
map out = (map)SCR::Execute (.target.bash_output, command);
integer exit = out["exit"]:0;
y2milestone ("Command output: %1", out);
ret = ret && (0 == exit);
});
}
if (activate)
{
foreach (map m_activate, getPartitionsToActivate (), {
any num = m_activate["num"]:0;
string mbr_dev = m_activate["mbr"]:"";
if (num != 0 && mbr_dev != "")
{
// if primary partition
if ((! is (num, integer)) || num <= 4)
{
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.
// string command = sformat
// ("/usr/sbin/parted -s %1 set %2 boot on", mbr_dev, num);
// As a workaround for #167602, moved back to
// /sbin/activate, because it does not cause the kernel to
// forget about an activated extended partition (it changes
// the data on disk without using any ioctl).
// FIXME: investigate proper handling of the activate flag
// (kernel ioctls in parted etc.) and fix parted
string command = sformat
("/usr/sbin/parted -s %1 set %2 boot on", mbr_dev, num);
y2milestone ("Running command %1", command);
map out = (map)SCR::Execute (.target.bash_output, command);
integer exit = out["exit"]:0;
y2milestone ("Command output: %1", out);
ret = ret && (0 == exit);
}
}
else
{
y2error ("Cannot activate %1", m_activate);
}
});
}
return ret;
}
/**
* Rewrite current MBR with /var/lib/YaST2/backup_boot_sectors/%device
* Warning!!! don't use for bootsectors, 440 bytes of sector are written
* @param device string device to rewrite MBR to
* @return boolean true on success
*/
global define boolean restoreMBR (string device) ``{
string device_file = mergestring (splitstring (device, "/"), "_");
if (SCR::Read (.target.size, sformat ("/var/lib/YaST2/backup_boot_sectors/%1", device_file))
<= 0)
{
Report::Error ("Can't restore MBR. No saved MBR found");
return false;
}
// added fix 446 -> 440 for Vista booting problem bnc #396444
integer ret = (integer) SCR::Execute (.target.bash, sformat (
"/bin/dd of=%1 if=/var/lib/YaST2/backup_boot_sectors/%2 bs=440 count=1",
device, device_file));
return (ret == 0);
}
/**
* Update kernel parameters if some were added in Kernel module
* @param orig original kernel parameters or kernel command line
* @return kernel command line or parameters with added new parameters
*/
global define string UpdateKernelParams (string orig) ``{
list<string> new = splitstring (Kernel::GetCmdLine (), " ");
list<string> old = splitstring (orig, " ");
list<string> added = (list<string>)difflist (new,
splitstring (BootCommon::kernelCmdLine, " "));
added = (list<string>)difflist (added, old);
old = (list<string>) merge (old, added);
if (Stage::initial ())
{// move showopts apic to the end
boolean showopts = false;
boolean apic = false;
if (contains (old, "showopts"))
showopts = true;
if (contains (old, "apic"))
apic = true;
old = filter (string o, old, ``(o != "apic" && o != "showopts"));
if (showopts)
old = add (old, "showopts");
if (apic)
old = add (old, "apic");
}
return mergestring (old, " ");
}
/**
* Get map of swap partitions
* @return a map where key is partition name and value its size
*/
global define map<string, integer> getSwapPartitions () ``{
//FIXME use cache of storage map
map<string, map> tm = (map<string,map>)Storage::GetTargetMap ();
boolean installation = Mode::installation ();
map<string, integer> ret = $[];
foreach (string k, map v, tm, ``{
integer cyl_size = v["cyl_size"]:0;
list<map<string,any> > partitions = v["partitions"]:[];
partitions = filter(map<string,any> p, partitions, {
return p["mount"]:"" == "swap" && ! p["delete"]:false;
});
foreach (map<string, any> s, partitions, ``{
// bnc#577127 - Encrypted swap is not properly set up as resume device
string dev = "";
if ((s["crypt_device"]:"" != nil) && (s["crypt_device"]:"" != ""))
dev = (string)(s["crypt_device"]:"");
else
dev = (string)(s["device"]:"");
ret[dev] = (integer)(s["region", 1]:0) * cyl_size;
});
});
y2milestone ("Available swap partitions: %1", ret);
return ret;
}
/**
* Create translated name of a section
* @param orig string original section name
* @return translated section name
*/
global define string translateSectionTitle (string orig) ``{
return GfxMenu::translateSectionTitle(orig,
getLoaderType(false));
}
/**
* Check if device is MBR of a disk
* @param device string device to check
* @return boolean true if is MBR
*/
define boolean IsMbr (string device) ``{
if (regexpmatch (device, "^\/dev\/[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]+$"))
return true;
if (regexpmatch (device, "^\/dev\/[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]+\/.*d[0-9]+$"))
return true;
return false;
}
/**
* Add '(MBR)' to the disk description if it is a MBR of some partition
* @param descr string disk description
* @param device string disk device
* @return string updated description
*/
define string AddMbrToDescription (string descr, string device) ``{
return IsMbr (device)
? sformat ("%1 (MBR)", descr)
: descr;
}
/**
* Update the Kernel::vgaType value to the saved one if not defined
*/
global define void UpdateInstallationKernelParameters () ``{
map<string,any> saved_params = $[];
if (! Stage::initial ())
{
saved_params = (map<string,any>)SCR::Read (
.target.ycp, "/var/lib/YaST2/bootloader.ycp");
}
if (Kernel::GetVgaType () == "")
{
string vgaType = (string)(saved_params["vgamode"]:"");
if (vgaType != nil && vgaType != "")
Kernel::SetVgaType (vgaType);
}
if (! Stage::initial ())
{
Kernel::SetCmdLine (saved_params["installation_kernel_params"]:"");
}
else
{
if (SCR::Read (.etc.install_inf.NoPCMCIA) == "1")
{
Kernel::SetCmdLine (Kernel::GetCmdLine () + " NOPCMCIA");
}
}
}
/**
* Get additional kernel parameters
* @return additional kernel parameters
*/
global define string GetAdditionalFailsafeParams () ``{
if (Stage::initial ())
{
additional_failsafe_params =
SCR::Read (.etc.install_inf.NoPCMCIA) == "1"
? " NOPCMCIA "
: "";
}
else
{
map<string,any> saved_params = (map<string,any>)SCR::Read (
.target.ycp, "/var/lib/YaST2/bootloader.ycp");
additional_failsafe_params
= saved_params["additional_failsafe_params"]:"";
}
return additional_failsafe_params;
}
/**
* Get additional kernel parameters from control file
* @return string additional kernel parameters
*/
global string GetAdditionalKernelParams () {
return ProductFeatures::GetStringFeature (
"globals",
"additional_kernel_parameters");
}
/**
* Get additional kernel parameters splitted to a list
* @return a list of additional kernel parameters
*/
global list<string> ListAdditionalKernelParams () {
return ListKernelParamsInLine (GetAdditionalKernelParams ());
}
/**
* Update graphical bootloader to contain help text of current language
* And make the selected installation language default
* @return boolean true on success
*/
global define boolean UpdateGfxMenuContents () {
return GfxMenu::UpdateGfxMenuContents(getLoaderType(false));
}
/**
* Update device name according to changes in kernel (eg. SATA)
* @param device string the original device name
* @return string updated device
*/
global string UpdateDevice (string device) {
if (Mode::test ())
{
map mapping = $[
"/dev/hda" : "/dev/sda",
"/dev/hdb" : "/dev/sdb",
];
map d = Storage::GetDiskPartition( device );
if( haskey( mapping, d["disk"]:"" ))
{
if (d["nr"]:nil == nil || d["nr"]:nil == 0)
{
device = mapping[d["disk"]:""]:"";
}
else
{
device = Storage::GetDeviceName(
mapping[d["disk"]:""]:"",
d["nr"]:nil);
}
}
}
else
{
list<string> devices = Storage::GetTranslatedDevices (
installed_version,
update_version,
[ device ]);
device = devices[0]:device;
}
return device;
}
/**
* Check if memtest86 is present
* @return boolean true if memtest86 section is to be proposed
*/
global boolean MemtestPresent () {
return (! contains (removed_sections, "memtest"))
&& (Mode::test ()
|| (Mode::normal () && Pkg::IsProvided ("memtest86+"))
|| (! Mode::normal () && Pkg::IsSelected ("memtest86+")));
}
/**
* Check if the bootloader can be installed at all with current configuration
* @return boolean true if it can
*/
global boolean BootloaderInstallable () {
if (Mode::config ())
return true;
if (Arch::i386 () || Arch::x86_64 ())
// the only relevant is the partition holding the /boot filesystem
{
DetectDisks ();
y2milestone ("Boot partition device: %1",
BootStorage::BootPartitionDevice);
map dev = Storage::GetDiskPartition( BootStorage::BootPartitionDevice);
y2milestone ("Disk info: %1", dev);
// MD, but not mirroring is OK
// FIXME: type detection by name deprecated
if (dev["disk"]:"" == "/dev/md")
{
map tm = Storage::GetTargetMap ();
map md = tm["/dev/md"]:$[];
list<map> parts = md["partitions"]:[];
map info = $[];
foreach (map p, parts, {
if (p["device"]:"" == BootStorage::BootPartitionDevice)
info = p;
});
if (tolower (info["raid_type"]:"") != "raid1")
{
y2milestone ("Cannot install bootloader on RAID (not mirror)");
return false;
}
// (bnc 357897) - lilo reports inconsistent raid version when trying to install on raid1
if (getLoaderType (false) == "lilo")
{
string raid_ver = info["sb_ver"]:""; //"00.90.03"
if (substring(raid_ver,0,2) == "01")
{
y2milestone ("Cannot install bootloader on RAID (lilo doesn't support raid version %1)", info["sb_ver"]:"");
return false;
}
}
}
// EVMS
// FIXME: type detection by name deprecated
else if (search (getBootPartition(), "/dev/evms/") == 0)
{
y2milestone ("Cannot install bootloader on EVMS");
return false;
}
// LVM
else if (! is( dev["nr"]:(any)0, integer ))
{
y2milestone ("Cannot install bootloader on LVM");
return false;
}
return true;
}
else
{
return true;
}
}
/**
* Function return absolute value of arg
*
* @param integer value
* @return integer absolute value
*/
integer abs(integer value)
{
if (value < 0)
return (value * (-1));
else
return value;
}
/** bnc #440125 - default boot section with failsafe args
* Compare append from default linux section with append from
* BootCommon::sections
*
* @return boolean true if appends are similar
*/
boolean compareAppends(string default_append, string section_append)
{
integer deuce = 0;
// delete white space on the beginning of string
default_append = String::CutBlanks(default_append);
section_append = String::CutBlanks(section_append);
// check valid append for section
//FIXME JR I think this is not true, append is valid even if it contain only one letter '3' which mean go to runlevel 3
if (size(section_append) < 3)
return false;
// check size of default append with section append
// if the size is same return true (same appends)
y2milestone("Size of default append: \"%1\" and compared section append: \"%2\"",
size(default_append), size(section_append));
if (size(default_append) == size(section_append))
return true;
list <string> default_list = splitstring(default_append, " ");
list <string> section_list = splitstring(section_append, " ");
integer size_default_list = size(default_list);
integer size_section_list = size(section_list);
integer relative_deuce = abs(size_section_list - size_default_list);
// check number of append args
// if different between number of args is more than 3 args return false
y2milestone("No. default args: %1 no. compared section args: %2", size_default_list, size_section_list);
if (relative_deuce >= 3)
return false;
// check args by keywords from section append to default append
y2milestone("default_append: %1", default_append);
y2milestone("section_list: %1", section_list);
foreach(string key, section_list,
{
if (search(key, "resume=") != nil)
{
list <string> tmp = splitstring(key,"=");
key = BootStorage::Dev2MountByDev(tmp[1]:"");
}
if (search(default_append, key) != nil)
deuce = deuce +1;
else
deuce = deuce -1;
});
// if there exist more than 3 different args return false
// else append seem to be similar -> true
y2milestone("No. deuces of default append with compared append: %1", deuce);
if (abs(size_default_list - deuce) >= 3)
return false;
else
return true;
}
/** bnc #440125 - default boot section with failsafe args
* Try to find potencional default linux section
* It can solve problem in function WriteToSysconf() with saving
* wrong (failsafe) args for default
*
* @return string name of default boot section
*/
global string findRelativeDefaultLinux ()
{
string default_linux = "";
// create defualt sections
map<string,any> linux_default = BootCommon::CreateLinuxSection("linux");
foreach(map<string,any>s, BootCommon::sections,
{
if ((s["root"]:"" == linux_default["root"]:nil) &&
(s["original_name"]:"" == "linux"))
{
//FIXME Check for root and original name should be enought, as failsafe allways has failsafe orig name
if (compareAppends(linux_default["append"]:"", s["append"]:""))
default_linux = s["name"]:"";
}
});
y2milestone("Relative default boot section is: \"%1\"", default_linux);
return default_linux;
}
/** bnc #440125 - default boot section with failsafe args
* Check if default boot name is linux
*
* @param string default boot name
* @return boolean true if boot name is linux
*/
global boolean isDefaultBootSectioLinux(string default_boot)
{
boolean ret = false;
foreach(map<string,any>s, BootCommon::sections,
{
if (s["name"]:"" == default_boot)
{
if (s["original_name"]:"" == "linux")
ret = true;
break;
}
});
if (ret)
y2milestone("Boot section: \"%1\" is linux", default_boot);
else
y2warning("Boot section: \"%1\" is NOT linux", default_boot);
return ret;
}
/** bnc#511319 Add information about /etc/sysconfig/bootloader to configuration file.
* Write option with value and comment to
* sysconfig file
*
* @param boolean true if called from client inst_bootloader
* @param path to config file (.sysconfig.bootloader)
* @param path option (.DEFAULT_APPEND)
* @param string value of otion
* @param string comment of option
* @return true on success
*/
define boolean WriteOptionToSysconfig(boolean inst, path file_path, path option, string value, string comment)
{
boolean ret = false;
if ((!inst) &&(!FileUtils::Exists("/etc/sysconfig/bootloader")))
{
y2milestone("Skip writting configuration to /etc/sysconfig/bootloader -> file missing");
return ret;
}
path file_path_option = add (file_path, option);
boolean comment_exist = SCR::Read(add(file_path_option, .comment)) == nil;
// write value of option
ret = SCR::Write(file_path_option, value);
// write comment of option if it is necessary
if (!comment_exist )
{
ret = ret && SCR::Write(add(file_path_option, .comment), comment);
}
SCR::Write(file_path, nil);
return ret;
}
/** bnc#511319 Add information about /etc/sysconfig/bootloader to configuration file.
* Create /etc/sysconfig/bootloader it is configuration
* file for bootloader
*
* @param boolean true if it is called from client inst_bootlaoder
* @return boolean true on success
*/
define boolean CreateBLSysconfigFile(boolean inst)
{
if (inst)
{
if (!FileUtils::Exists(Installation::destdir +"/etc/sysconfig"))
{
WFM::Execute(.local.mkdir, Installation::destdir + "/etc/sysconfig");
WFM::Execute(.local.bash, sformat ("touch %1/etc/sysconfig/bootloader", Installation::destdir));
}
//string target_sysconfig_path = Installation::destdir + "/etc/sysconfig/bootloader";
return true;
}
return true;
}
/** bnc #578545 - kdump misconfigures crashkernel parameter for Xen
* Check if default_append includes crashkernel arg
*
* @param string defaul_append
* @return string defaul_append without crashkernel
*/
define string deleteCrashkernelFromAppend (string append)
{
y2milestone("Original append: %1",append);
list<string> list_append = splitstring(append, " ");
if (size(list_append)>0)
{
list_append = filter(string key, list_append,
{
if (search(key, "crashkernel") == nil)
return true;
else
return false;
});
}
string ret = mergestring(list_append, " ");
y2milestone("Filtered append: %1",ret);
return ret;
}
/** FATE #302245 save kernel args etc to /etc/sysconfig/bootloader
* Function write/update info in /etc/sysconfig/bootloader
* @param booloean true if it called from inst_bootloader.ycp
*/
global define void WriteToSysconf(boolean inst_bootloader)
{
string lt = BootCommon::getLoaderType (false);
y2milestone ("Saving /etc/sysconfig/bootloader for %1", lt);
string default_boot_section_name = "";
// fix for bnc #440125 - default boot section with failsafe args
// it is not possible create exact algoritmus but I hope it helps in
// mostly cases.
if (isDefaultBootSectioLinux(BootCommon::globals["default"]:""))
default_boot_section_name = BootCommon::globals["default"]:"";
else
default_boot_section_name = findRelativeDefaultLinux ();
// get the default and failsafe append + vga parameters; if section with
// appropriate original name not found, just use any Linux section
// doing so during update may be questionable, however, the variables need to
// be initialized in any case
string default_vga = "";
string default_append = "";
boolean default_set = false;
string failsafe_vga = "";
string failsafe_append = "";
boolean failsafe_set = false;
string xen_vga = "";
string xen_append = "";
string xen_kernel_append = "";
string addon_name = "";
string addon_append = "";
string addon_vga = "";
boolean xen_set = false;
// default boot section is not found
if (default_boot_section_name == "")
{
// create defualt sections
map<string,any> linux_default = BootCommon::CreateLinuxSection("linux");
default_set = true;
default_vga = linux_default["vgamode"]:"";
default_append = linux_default["append"]:"";
}
foreach (map<string,any>s, BootCommon::sections,
{
if ((search(s["original_name"]:"","linux") != nil) &&
(s["name"]:"" == default_boot_section_name))
{
default_set = true;
default_vga = s["vgamode"]:"";
default_append = s["append"]:"";
}
if (search(s["original_name"]:"","xen") != nil)
{
xen_set = true;
xen_vga = s["vgamode"]:"";
xen_append = s["xen_append"]:"";
xen_kernel_append = s["append"]:"";
}
else if (search(s["original_name"]:"","failsafe") != nil)
{
failsafe_set = true;
failsafe_vga = s["vgamode"]:"";
failsafe_append = s["append"]:"";
}
if (s["type"]:"" == "image" && ! default_set)
{
default_vga = s["vgamode"]:"";
default_append = s["append"]:"";
}
if (s["type"]:"" == "image" && ! failsafe_set)
{
failsafe_vga = s["vgamode"]:"";
failsafe_append = s["append"]:"";
}
if (s["__rt_kernel"]:"" == "true")
{
addon_name = s["name"]:"";
addon_append = s["append"]:"";
addon_vga = s["vgamode"]:"";
}
});
if (! xen_set)
{
xen_kernel_append = deleteCrashkernelFromAppend(default_append);
xen_append = "";
xen_vga = default_vga;
}
// save some sysconfig variables
// register new agent pointing into the mounted filesystem
path sys_agent = .sysconfig.bootloader;
if (inst_bootloader)
{
sys_agent = add(.target, sys_agent);
string target_sysconfig_path = Installation::destdir + "/etc/sysconfig/bootloader";
SCR::RegisterAgent (sys_agent, `ag_ini(
`SysConfigFile(target_sysconfig_path)));
}
CreateBLSysconfigFile(inst_bootloader);
string comment = "";
comment= "\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tlist(grub,lilo,none)
## Default:\tgrub
#
# Type of bootloader in use.
# For making the change effect run bootloader configuration tool
# and configure newly selected bootloader
#
#\n";
if (!Arch::i386() && !Arch::x86_64())
{
comment= "\n ## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# Type of bootloader in use.
# For making the change effect run bootloader configuration tool
# and configure newly selected bootloader
#
#\n";
}
WriteOptionToSysconfig(inst_bootloader, sys_agent, .LOADER_TYPE, lt, comment);
comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\t\"splash=silent quiet showotps\"
#
# Arguments for kernel which is used like default boot section.
# If the options is commented perl-Bootloader uses his default arguments
# for kernel.
#\n";
if (!Arch::i386() && !Arch::x86_64())
{
comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# Arguments for kernel which is used like default boot section.
# If the options is commented perl-Bootloader uses his default arguments
# for kernel.
#\n";
}
WriteOptionToSysconfig(inst_bootloader, sys_agent, .DEFAULT_APPEND, default_append, comment);
comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# VGA option for kernel which is used like default boot section.
# If the options is commented or empty perl-Bootloader doesn't use it.
# Empty option could be cause of broken size of fonts etc.
#\n";
if (Arch::i386 () || Arch::x86_64 () || Arch::ia64 ())
WriteOptionToSysconfig(inst_bootloader, sys_agent, .DEFAULT_VGA, default_vga, comment);
comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\t\"showopts apm=off noresume nosmp maxcpus=0 edd=off powersaved=off nohz=off highres=off processor.max_cstate=1 nomodeset x11failsafe\"
#
# Arguments for kernel which is used like failsafe boot section
# If the options is commented perl-Bootloader uses his default arguments
# for kernel.
#\n";
if (Arch::x86_64())
{
comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\t\"showopts apm=off noresume edd=off powersaved=off nohz=off highres=off processor.max_cstate=1 nomodeset x11failsafe\"
#
# Arguments for kernel which is used like failsafe boot section
# If the options is commented perl-Bootloader uses his default arguments
# for kernel.
#\n";
}
if (Arch::ia64())
{
comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\t\"nohalt noresume powersaved=off x11failsafe\"
#
# Arguments for kernel which is used like failsafe boot section
# If the options is commented perl-Bootloader uses his default arguments
# for kernel.
#\n";
}
if (Arch::s390())
{
comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# Arguments for kernel which is used like failsafe boot section
# If the options is commented perl-Bootloader uses his default arguments
# for kernel.
#\n";
}
WriteOptionToSysconfig(inst_bootloader, sys_agent, .FAILSAFE_APPEND, failsafe_append, comment);
comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# VGA option for kernel which is used like failsafe boot section.
# If the options is commented or empty perl-Bootloader doesn't use it.
# Empty option could be cause of broken size of fonts etc.
#\n";
if (Arch::i386 () || Arch::x86_64 () || Arch::ia64 ())
WriteOptionToSysconfig(inst_bootloader, sys_agent, .FAILSAFE_VGA, failsafe_vga, comment);
comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\t\"splash=silent quiet showotps\"
#
# Arguments for XEN kernel in Dom0.
# If the options is commented perl-Bootloader uses his default arguments
# for XEN kernel.
#\n";
if (Arch::ia64 ())
{
comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\t\"splash=silent quiet\"
#
# Arguments for XEN kernel in Dom0.
# If the options is commented perl-Bootloader uses his default arguments
# for XEN kernel.
#\n";
}
if (Arch::i386 () || Arch::x86_64 () || Arch::ia64 ())
WriteOptionToSysconfig(inst_bootloader, sys_agent, .XEN_KERNEL_APPEND, xen_kernel_append, comment);
comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# Arguments for XEN hypervisor
# Usually it is empty or includes arguments like crashkernel for kdump etc.
#\n";
if (Arch::i386 () || Arch::x86_64 () || Arch::ia64 ())
WriteOptionToSysconfig(inst_bootloader, sys_agent, .XEN_APPEND, xen_append, comment);
comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# VGA option for XEN kernel.
# If the options is commented or empty perl-Bootloader doesn't use it.
# Empty option could be cause of broken size of fonts etc.
#\n";
if (Arch::i386 () || Arch::x86_64 () || Arch::ia64 ())
WriteOptionToSysconfig(inst_bootloader, sys_agent, .XEN_VGA, xen_vga, comment);
comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# Title of RealTime kernel in bootloader configuration file.
#\n";
if (addon_name != "")
WriteOptionToSysconfig(inst_bootloader, sys_agent, .RT_NAME, addon_name, comment);
comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# VGA option for RealTime kernel.
# If the options is commented or empty perl-Bootloader doesn't use it.
# Empty option could be cause of broken size of fonts etc.
#\n";
if (addon_vga != "")
WriteOptionToSysconfig(inst_bootloader, sys_agent, .RT_VGA, addon_vga, comment);
comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# Arguments for RealTime kernel.
# If the options is commented perl-Bootloader uses his default arguments
# for kernel.
#\n";
if (addon_append != "")
WriteOptionToSysconfig(inst_bootloader, sys_agent, .RT_APPEND, addon_append, comment);
}
/**
* Function return boot device it means
* return boot partition or root partition if boot partition deosn't exist
* function return "" if boot partition or root partition is not defined (autoyast)
* @return string name of boot device (partition)
*/
global string getBootPartition()
{
string boot_device = "";
if (BootStorage::BootPartitionDevice != "")
boot_device = BootStorage::BootPartitionDevice;
else if (BootStorage::RootPartitionDevice != "")
boot_device = BootStorage::RootPartitionDevice;
return boot_device;
}
/** FATE #303548 - Grub: limit device.map to devices detected by BIOS Int 13
* Function select boot device - disk
*
* @return string name of boot device - disk
*/
global string getBootDisk()
{
string boot_device = getBootPartition();
if (boot_device == "")
{
y2milestone("BootPartitionDevice and RootPartitionDevice are empty");
return boot_device;
}
map p_dev = Storage::GetDiskPartition (boot_device);
string boot_disk_device = p_dev["disk"]:"";
if ((boot_disk_device != "") && (boot_disk_device != nil))
{
y2milestone("Boot device - disk: %1", boot_disk_device);
return boot_disk_device;
}
y2milestone("Finding boot disk failed!");
return "";
}
/** FATE #303548 - Grub: limit device.map to devices detected by BIOS Int 13
* Function select boot device - disk
*
* @return string name of boot device - disk
*/
/** FATE #110038: Serial console
* Function build value for console from:
* @param string unit no of console
* @param string speed
* @param string parity (n,o,e)
* @param string word (8)
* @return string value of console for kernel append
*/
define string buildConsoleValue (string unit, string speed, string parity, string word)
{
string ret = "";
if ((unit != "") && (speed != ""))
{
// add number of serial console
ret = "ttyS" + unit;
// add speed
ret = ret + "," + speed;
if (parity != "")
{
// add parity
switch (parity)
{
case ("no"):
ret = ret + "n";
break;
case ("odd"):
ret = ret +"o";
break;
case ("even"):
ret = ret + "e";
break;
default:
ret = ret + "n";
break;
}
// add word
if (word != "")
ret = ret + word;
}
y2milestone("console value for kernel: %1", ret);
} else {
y2error("Wrong values unit: %1 , speed: %2 , parity: %3 , word: %4",
unit, speed, parity, word);
}
return ret;
}
/** FATE #110038: Serial console
* Function parse string key (e.g. --speed=9600)
* and return value of key
* @param string key e.g. --unit=0
* @return string value of key
*/
define string getKeyValue(string key)
{
string ret = "";
list <string> value = [];
if (key != "")
{
value = splitstring (key, "=");
if (value[1]:"" != "")
ret = value[1]:"";
}
y2debug("parse: %1 and return value: %2", key, ret);
return ret;
}
/** FATE #110038: Serial console
* Function check value from globals (serial and terminal)
* after that build value of console append for kernel if it is possible
* @return string value of console for kernel append
*/
define string getConsoleValue()
{
string ret = "";
if ((globals["serial"]:"" != "") && (globals["terminal"]:"" != ""))
{
list <string> list_serial = splitstring (globals["serial"]:"", " ");
y2milestone("list of serial args: %1", list_serial);
string unit = "";
string speed = "";
string parity = "";
string word = "";
foreach(string key, list_serial,
{
if (search(key, "--unit") != nil)
unit = getKeyValue(key);
if (search(key, "--speed") != nil)
speed = getKeyValue(key);
if (search(key, "--parity") != nil)
parity = getKeyValue(key);
if (search(key, "--word") != nil)
word = getKeyValue(key);
});
// build value
ret = buildConsoleValue (unit, speed, parity, word);
}
return ret;
}
/** FATE #110038: Serial console
* Add console arg for kernel if there is defined serial console
* - add key console with value to section type image and xen
*/
global define void HandleConsole()
{
string console_value = getConsoleValue();
// list of idexes from sections where is image or xen
list < integer > list_index =[];
// counter
integer index = -1;
foreach(map<string,any> section, sections,
{
index = index +1;
if ((section["type"]:"" == "image") || (search(section["type"]:"", "xen") != nil))
list_index = add(list_index, index);
});
// add key console with value
if (size(list_index) > 0)
{
foreach (integer idx, list_index,
{
sections[idx, "__changed"] = true;
if (sections[idx, "append"]:nil != nil)
{
string updated_append = "";
if ((console_value != "") || (console_value != nil))
updated_append = BootCommon::UpdateSerialConsole(sections[idx,"append"]:"",
console_value);
else
updated_append = BootCommon::UpdateSerialConsole(sections[idx,"append"]:"", "");
if (updated_append != nil)
{
sections[idx,"append"]=updated_append;
}
}
y2debug("Added/Removed console for section: %1", sections[idx]:$[]);
});
}
}
/** bnc #450153 - support for installation kernel from add-on
* fucntion call client from add-on and update proposal for
* yast2-bootloader. -> availabe edit kernel args for kernel
* from add-on
*
* @return boolean - true on success
*/
global boolean UpdateProposalFromClient ()
{
boolean ret = true;
string client_file = "kernel_bl_proposal";
if ((!Arch::i386()) && (!Arch::x86_64()))
{
y2milestone("Unsuported architecture... for adding SLERT addon");
return ret;
}
if (WFM::ClientExists(client_file))
{
y2milestone("Client: %1 was found", client_file);
WFM::CallFunction (client_file, []);
} else {
y2milestone("File %1 doesn't exist - proposal will not be updated", client_file);
}
return ret;
}
} //end of include
ACC SHELL 2018