ACC SHELL
/**
* File:
* modules/Bootloader.ycp
*
* Module:
* Bootloader installation and configuration
*
* Summary:
* Bootloader installation and configuration base module
*
* Authors:
* Jiri Srain <jsrain@suse.cz>
* Olaf Dabrunz <od@suse.de>
*
* $Id: Bootloader.ycp 61621 2010-04-08 14:45:52Z juhliarik $
*
*/
{
module "Bootloader";
textdomain "bootloader";
import "Arch";
import "BootCommon";
import "BootStorage";
import "Installation";
import "Initrd";
import "Kernel";
import "Mode";
import "Progress";
import "Stage";
import "Storage";
import "Directory";
import "BootELILO";
import "BootLILO";
import "BootGRUB";
import "BootPOWERLILO"; // The ppc-LILO File
//fate 303395
import "ProductFeatures";
// interface for clients
global define map Export ();
global define boolean Import (map settings);
global define void Propose ();
global define boolean Read ();
global define void Reset ();
global define boolean Write ();
global define boolean FlagOnetimeBoot (string section);
// additional interfaces, mostly for other modules
global define void ReadOrProposeIfNeeded ();
global define string getDefaultSection ();
global define string getKernelParam (string section, string key);
global define boolean setKernelParam (string section, string key, string value);
global define string getLoaderType ();
global define string getProposedDefaultSection ();
global define boolean UpdateGfxMenu ();
global define void DelDuplicatedSections();
global define void ResolveSymlinksInSections();
void createSELinuxDir ();
void handleSELinuxPAM ();
void enableSELinuxPAM ();
void disableSELinuxPAM ();
/**
* Write is repeating again
* Because of progress bar during inst_finish
*/
global boolean repeating_write = false;
// installation proposal help variables
/**
* Configuration was changed during inst. proposal if true
*/
global boolean proposed_cfg_changed = false;
/**
* Cache for the installation proposal
*/
global map cached_proposal = nil;
global map cached_settings = $[];
// old vga value handling function
/**
* old value of vga parameter of default bootloader section
*/
string old_vga = nil;
// UI helping variables
include "bootloader/routines/switcher.ycp";
include "bootloader/routines/popups.ycp";
// general functions
global boolean() test_abort = nil;
/**
* Check whether abort was pressed
* @return boolean true if abort was pressed
*/
boolean testAbort () {
if (test_abort == nil)
return false;
return test_abort ();
}
/** bnc #419197 yast2-bootloader does not correctly initialise libstorage
* Function try initialize yast2-storage
* if other module used it then don't continue with initialize
* @return boolean true on success
*/
boolean checkUsedStorage ()
{
if ((!Storage::InitLibstorage(true)) && (Mode::normal()))
return false;
else
return true;
}
/**
* Constructor
*/
global define void Bootloader () {
return;
}
/**
* Export bootloader settings to a map
* @return bootloader settings
*/
global define map Export () {
ReadOrProposeIfNeeded ();
map out = $[
"loader_type" : getLoaderType (),
"initrd" : Initrd::Export (),
"specific" : blExport (),
"write_settings" : BootCommon::write_settings,
];
string loader_type = (string) (out["loader_type"]:nil);
if ( ! ( loader_type == "grub" ) ) {
// export loader_device and selected_location only for bootloaders
// that have not phased them out yet
out["loader_device"] = BootCommon::loader_device;
out["loader_location"] = BootCommon::selected_location;
}
y2milestone ("Exporting settings: %1", out);
return out;
}
/**
* Import settings from a map
* @param settings map of bootloader settings
* @return boolean true on success
*/
global define boolean Import (map settings) {
y2milestone ("Importing settings: %1", settings);
Reset ();
BootCommon::was_read = true;
BootCommon::was_proposed = true;
BootCommon::changed = true;
BootCommon::location_changed = true;
if (settings["loader_type"]:nil == "")
settings["loader_type"] = nil;
string loader_type = (string) (settings["loader_type"]:nil);
BootCommon::setLoaderType (loader_type);
BootCommon::getLoaderType (false);
if ( ! ( loader_type == "grub" ) ) {
// import loader_device and selected_location only for bootloaders
// that have not phased them out yet
BootCommon::loader_device = settings["loader_device"]:"";
BootCommon::selected_location = settings["loader_location"]:"custom";
// FIXME: obsolete for grub (but inactive through the outer "if" now anyway):
// for lilo and grub, always correct the bootloader device according to
// selected_location (or fall back to value of loader_device)
// Why only for lilo and grub?
if (loader_type == "lilo" || loader_type == "grub"
|| Arch::i386 () || Arch::x86_64 ())
{
BootCommon::loader_device = BootCommon::GetBootloaderDevice ();
}
}
if (settings["initrd"]:$[] != nil)
Initrd::Import (settings["initrd"]:$[]);
boolean ret = blImport (settings["specific"]:$[]);
BootCommon::write_settings = settings["write_settings"]:$[];
return ret;
}
/**
* Read settings from disk
* @return boolean true on success
*/
global define boolean Read () {
y2milestone ("Reading configuration");
// run Progress bar
list<string> stages = [
// progress stage, text in dialog (short, infinitiv)
_("Check boot loader"),
// progress stage, text in dialog (short, infinitiv)
_("Read partitioning"),
// progress stage, text in dialog (short, infinitiv)
_("Load boot loader settings"),
];
list<string> titles = [
// progress step, text in dialog (short)
_("Checking boot loader..."),
// progress step, text in dialog (short)
_("Reading partitioning..."),
// progress step, text in dialog (short)
_("Loading boot loader settings..."),
];
// dialog header
Progress::New (_("Initializing Boot Loader Configuration"),
" ", 3, stages, titles, "");
Progress::NextStage ();
if (testAbort ())
return false;
Progress::NextStage ();
if (!checkUsedStorage ())
return false;
Bootloader::getLoaderType ();
BootCommon::DetectDisks ();
Progress::NextStage ();
if (testAbort ())
return false;
boolean ret = blRead (true, false);
BootCommon::was_read = true;
old_vga = getKernelParam (getDefaultSection (), "vgamode");
Progress::Finish ();
if (testAbort ())
return false;
y2debug ("Read settings: %1", Export ());
return ret;
}
/**
* Reset bootloader settings
* @param init boolean true if basic initialization of system-dependent
* settings should be done
*/
global define void ResetEx (boolean init) {
if (Mode::autoinst ())
return;
y2milestone ("Reseting configuration");
BootCommon::was_proposed = false;
BootCommon::was_read = false;
BootCommon::loader_device = "";
// BootCommon::setLoaderType (nil);
BootCommon::changed = false;
BootCommon::location_changed = false;
// BootCommon::other_bl = $[];
BootCommon::files_edited = false;
BootCommon::write_settings = $[];
blReset (init);
}
/**
* Reset bootloader settings
*/
global define void Reset () {
return ResetEx (true);
}
/**
* Propose bootloader settings
*/
global define void Propose () {
y2milestone ("Proposing configuration");
// always have a current target map available in the log
y2milestone ("unfiltered target map: %1", (map<string,map>)Storage::GetTargetMap());
BootCommon::UpdateInstallationKernelParameters ();
blPropose ();
BootCommon::was_proposed = true;
BootCommon::changed = true;
BootCommon::location_changed = true;
BootCommon::partitioning_last_change = Storage::GetTargetChangeTime();
BootCommon::backup_mbr = true;
y2milestone ("Proposed settings: %1", Export ());
}
/**
* Display bootloader summary
* @return a list of summary lines
*/
global define list<string> Summary () {
list<string> ret =[];
// F#300779 - Install diskless client (NFS-root)
// kokso: additional warning that root partition is nfs type -> bootloader will not be installed
string device = BootCommon::getBootDisk();
if (device == "/dev/nfs")
{
ret = add (ret, _("The boot partition is of type NFS. Bootloader cannot be installed."));
y2milestone("Bootloader::Summary() -> Boot partition is nfs type, bootloader will not be installed.");
return ret;
}
// F#300779 - end
ret = blSummary ();
// check if default section was changed or not
string main_section = getProposedDefaultSection ();
if (main_section == nil)
return ret;
if (getLoaderType () == "none")
return ret;
integer sectnum = BootCommon::Section2Index(main_section);
if (sectnum == -1)
return ret;
if (BootCommon::sections[sectnum, "__changed"]:false)
return ret;
string filtered_cmdline = filterchars (Kernel::GetCmdLine (),
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
if (size (filtered_cmdline) > 0)
{
ret = add (ret, sformat (
// part of summary, %1 is a part of kernel command line
_("Added Kernel Parameters: %1"),
Kernel::GetCmdLine ()));
}
return ret;
}
/**
* Update read settings to new version of configuration files
*/
global define void UpdateConfiguration () {
// first run bootloader-specific update function
blUpdate ();
// remove no more needed modules from MODULES_LOADED_ON_BOOT
string mlob = (string)
SCR::Read (.sysconfig.kernel.MODULES_LOADED_ON_BOOT);
list<string> mod_list = splitstring (mlob, " ");
mod_list = filter (string s, mod_list, ``(
s != "" && s != "cdrom" && s != "ide-cd" && s != "ide-scsi"
));
mlob = mergestring (mod_list, " ");
SCR::Write (.sysconfig.kernel.MODULES_LOADED_ON_BOOT, mlob);
SCR::Write (.sysconfig.kernel, nil);
}
/**
* Update the whole configuration
* @param iv a map representing the installed (original) version
* @param uv a map representing the version the system is upgraded to
* @return boolean true on success
*/
global boolean Update (map<string,any> iv, map<string,any> uv) {
BootCommon::installed_version = iv;
BootCommon::update_version = uv;
return Write (); // write also reads the configuration and updates it
}
/**
* Process update actions needed before packages update starts
*/
global define void PreUpdate () {
y2milestone ("Running bootloader pre-update stuff");
}
/**
* Write bootloader settings to disk
* @return boolean true on success
*/
global define boolean Write () {
boolean ret = true;
// proposing anything is irrelevant during update, this forces reading
// if settings weren't read before
if (Mode::update ())
{
BootCommon::was_proposed = false;
BootCommon::changed = true;
BootCommon::location_changed = true;
BootCommon::getLoaderType (! repeating_write);
}
if (repeating_write)
BootCommon::was_read = true;
else
ReadOrProposeIfNeeded ();
if (BootCommon::write_settings["save_all"]:false)
BootCommon::save_all = true;
if (BootCommon::save_all)
{ // force saving everything
BootCommon::changed = true;
BootCommon::location_changed = true;
Initrd::changed = true;
}
y2milestone ("Writing bootloader configuration");
// run Progress bar
list<string> stages = [
// progress stage, text in dialog (short)
_("Create initrd"),
// progress stage, text in dialog (short)
_("Save boot loader configuration files"),
// progress stage, text in dialog (short)
_("Install boot loader"),
];
list<string> titles = [
// progress step, text in dialog (short)
_("Creating initrd..."),
// progress step, text in dialog (short)
_("Saving boot loader configuration files..."),
// progress step, text in dialog (short)
_("Installing boot loader..."),
];
// progress bar caption
if (Mode::normal ())
{
// progress line
Progress::New (_("Saving Boot Loader Configuration"),
" ", 2, stages, titles, "");
Progress::NextStage ();
}
else
{
Progress::Title (titles[0]:"");
}
map<string,any> params_to_save = $[];
string new_vga = getKernelParam (getDefaultSection (), "vgamode");
if (new_vga != old_vga && new_vga != "false" && new_vga != "" && new_vga !="ask")
{
Initrd::setSplash (new_vga);
if (Stage::initial ())
params_to_save["vgamode"] = new_vga;
}
// Initialize device mapper and LVM in target system
if (Stage::initial () || Mode::update ())
{
// FIXME: should be handled by partitioner
map out = (map)SCR::Execute (.target.bash_output,
"test -f /sbin/devmap_mknod.sh && /sbin/devmap_mknod.sh;" +
"test -f /sbin/vgscan && /sbin/vgscan --mknodes"
);
if (out["exit"]:0 != 0)
{
y2error ("Failed to initialize device mapper");
}
y2milestone ("Device mapper and LVM initialization output: %1", out);
}
// save initrd
if ((Initrd::changed || ! Mode::normal ())
&& ! (BootCommon::write_settings["forbid_save_initrd"]:false))
{
string vga = getKernelParam (getDefaultSection (), "vgamode");
if (vga != "false" && vga != "" && vga !="ask")
{
Initrd::setSplash (vga);
if (Stage::initial ())
params_to_save["vgamode"] = new_vga;
}
ret = Initrd::Write ();
BootCommon::changed = true;
}
if (! ret)
y2error ("Error occurred while creating initrd");
if (Mode::commandline ())
BootCommon::changed = true;
if (! (BootCommon::changed
|| BootCommon::write_settings["initrd_changed_externally"]:false))
{
y2milestone ("No bootloader cfg. file saving needed, exiting");
// return true;
}
if (Mode::normal ())
Progress::NextStage ();
else
{
if (! repeating_write)
Progress::NextStep ();
Progress::Title (titles[1]:"");
}
// Write settings to /etc/sysconfig/bootloader
y2milestone ("Saving configuration files");
string lt = getLoaderType ();
SCR::Write (.sysconfig.bootloader.LOADER_TYPE, lt);
SCR::Write (.sysconfig.bootloader, nil);
params_to_save["additional_failsafe_params"]
= BootCommon::GetAdditionalFailsafeParams ();
params_to_save["installation_kernel_params"] = Kernel::GetCmdLine ();
if (Stage::initial ())
{
SCR::Write (.target.ycp, "/var/lib/YaST2/bootloader.ycp",
params_to_save);
}
if (getLoaderType () == "none")
{
return ret;
}
//F#300779 - Install diskless client (NFS-root)
//kokso: bootloader will not be installed
string device = BootCommon::getBootDisk();
if (device == "/dev/nfs")
{
y2milestone("Bootloader::Write() -> Boot partition is nfs type, bootloader will not be installed.");
return ret;
}
//F#300779 -end
// update graphics menu where possible
UpdateGfxMenu ();
// save bootloader settings
boolean reinit = ! (Mode::update () || Mode::normal ());
y2milestone ("Reinitialize bootloader library before saving: %1",
reinit);
ret = blSave (true, reinit, true) && ret;
if (! ret)
y2error ("Error before configuration files saving finished");
if (Mode::normal ())
Progress::NextStage ();
else
{
if (! repeating_write)
Progress::NextStep ();
Progress::Title (titles[2]:"");
}
// call bootloader executable
y2milestone ("Calling bootloader executable");
ret = ret && blWrite ();
// FATE#305557: Enable SELinux for 11.2
createSELinuxDir ();
handleSELinuxPAM ();
if (! ret)
{
y2error ("Installing bootloader failed");
if (writeErrorPopup ())
{
repeating_write = true;
map res = (map)WFM::call( "bootloader_proposal", ["AskUser",
$[ "has_next": false]]);
if (res["workflow_sequence"]:nil == `next)
{
return Write ();
}
}
}
else
{
if (BootCommon::InstallingToFloppy ())
{
BootCommon::updateTimeoutPopupForFloppy
(BootCommon::getLoaderName (getLoaderType (), `summary));
}
}
return ret;
}
/**
* Write bootloader settings during installation
* @return boolean true on success
*/
global define boolean WriteInstallation ()
{
y2milestone ("Writing bootloader configuration during installation");
boolean ret = true;
if (! Mode::live_installation())
{
// bnc#449785 - Installing of GRUB fails when using live installer from a USB stick
// read current settings...
ret = blRead (true, false);
// delete duplicated sections
DelDuplicatedSections();
} else {
// resolve sim links for image and initrd
// bnc #393030 - live-CD kernel install/remove leaves broken system
ResolveSymlinksInSections();
}
if (BootCommon::write_settings["save_all"]:false)
BootCommon::save_all = true;
if (BootCommon::save_all)
{ // force saving everything
BootCommon::changed = true;
BootCommon::location_changed = true;
Initrd::changed = true;
}
map<string,any> params_to_save = $[];
string new_vga = getKernelParam (getDefaultSection (), "vgamode");
if (new_vga != old_vga && new_vga != "false" && new_vga != "")
{
Initrd::setSplash (new_vga);
if (Stage::initial ())
params_to_save["vgamode"] = new_vga;
}
// save initrd
if ((Initrd::changed || ! Mode::normal ())
&& ! (BootCommon::write_settings["forbid_save_initrd"]:false))
{
string vga = getKernelParam (getDefaultSection (), "vgamode");
if (vga != "false" && vga != "")
{
Initrd::setSplash (vga);
if (Stage::initial ())
params_to_save["vgamode"] = new_vga;
}
ret = Initrd::Write ();
BootCommon::changed = true;
}
if (! ret)
y2error ("Error occurred while creating initrd");
params_to_save["additional_failsafe_params"] = BootCommon::GetAdditionalFailsafeParams ();
params_to_save["installation_kernel_params"] = Kernel::GetCmdLine ();
if (Stage::initial ())
{
SCR::Write (.target.ycp, "/var/lib/YaST2/bootloader.ycp",params_to_save);
}
if (getLoaderType () == "none")
{
return ret;
}
// F#300779 - Install diskless client (NFS-root)
// kokso: bootloader will not be installed
string device = BootCommon::getBootDisk();
if (device == "/dev/nfs")
{
y2milestone("Bootloader::Write() -> Boot partition is nfs type, bootloader will not be installed.");
return ret;
}
// F#300779 -end
// update graphics menu where possible
UpdateGfxMenu ();
// save bootloader settings
boolean reinit = ! (Mode::update () || Mode::normal ());
y2milestone ("Reinitialize bootloader library before saving: %1",reinit);
ret = blSave (true, reinit, true) && ret;
if (! ret)
y2error ("Error before configuration files saving finished");
// call bootloader executable
y2milestone ("Calling bootloader executable");
ret = ret && blWrite ();
// FATE#305557: Enable SELinux for 11.2
createSELinuxDir ();
handleSELinuxPAM ();
if (! ret)
{
y2error ("Installing bootloader failed");
if (writeErrorPopup ())
{
repeating_write = true;
map res = (map)WFM::call( "bootloader_proposal", ["AskUser",$[ "has_next": false]]);
if (res["workflow_sequence"]:nil == `next)
return Write ();
}
}
else
{
if (BootCommon::InstallingToFloppy ())
BootCommon::updateTimeoutPopupForFloppy(BootCommon::getLoaderName (getLoaderType (), `summary));
}
return ret;
}
/**
* Function find and select any boot section like defaul
* if default boot section doesn't exist
*
* @param map<string,any> defualt linux section
* @return boolean true if section was found or was selected
*/
boolean FindAndSelectDefault(map<string,any> default_sec)
{
boolean ret = false;
boolean set_candidate = false;
string default_name = BootCommon::globals["default"]:"";
string default_candidate = "";
foreach(map<string,any> section, BootCommon::sections,
{
if (section["name"]:nil == default_name)
{
y2milestone("Default section was found.");
ret = true;
break;
} else {
if ((section["root"]:"" == default_sec["root"]:"")
&& (section["type"]:"" == "image")
&& (section["original_name"]:"" == "linux"))
{
default_candidate = section["name"]:"";
y2milestone("Candidate for default section is: %1", section);
set_candidate = true;
}
}
});
if (!ret)
{
if ((set_candidate) && (default_candidate!=""))
{
y2milestone("Default section will be update to: %1", default_candidate);
BootCommon::globals["default"] = default_candidate;
ret = true;
} else {
y2error("Default section was not found");
}
}
return ret;
}
/** bnc #450153 YaST bootloader doesn't handle kernel from add-on products in installation
* Remove all section with empty keys "image" and "initrd"
*
*/
void removeDummySections ()
{
BootCommon::sections=filter(map<string,any> section, BootCommon::sections,
{
if ((section["original_name"]:"" == "linux")
|| (section["original_name"]:"" == "failsafe"))
{
if ((search(section["image"]:"", "dummy_image") != nil) &&
(search(section["initrd"]:"", "dummy_initrd") != nil))
{
y2milestone("Removed dummy boot section: %1", section);
return false;
} else
return true;
}
return true;
});
}
/** bnc #450153 YaST bootloader doesn't handle kernel from add-on products in installation
* Function check if client kernel_bl_proposal exist
*
* @return boolean true on success
*/
boolean CheckClientForSLERT()
{
if (WFM::ClientExists("kernel_bl_proposal"))
return true;
else
return false;
}
/**
* Find "same" boot sections and return numbers of sections
* from BootCommon::sections
* @param map<string,any> section
* @return integer number of "same" sactions
*/
define integer CountSection(map<string,any> find_section)
{
y2milestone("Finding same boot sections");
integer num_sections = 0;
foreach(map<string,any> section, BootCommon::sections,
{
if ((section["root"]:nil == find_section["root"]:nil)
&&
(section["original_name"]:nil == find_section["original_name"]:nil))
{
num_sections = num_sections +1;
}
});
y2milestone("Number of similar section is %2 with %1",find_section, num_sections);
return num_sections;
}
/**
* Delete duplicated boot sections from
* BootCommon::sections
*/
global define void DelDuplicatedSections()
{
if (CheckClientForSLERT())
{
removeDummySections ();
return;
}
y2milestone("Deleting duplicated boot sections");
map<string,any> linux_default = $[];
map<string,any> linux_failsafe = $[];
map<string,any> linux_xen = $[];
if (Arch::ppc())
{
linux_default = BootPOWERLILO::CreateImageSection("linux");
} else {
linux_default = BootCommon::CreateLinuxSection ("linux");
linux_failsafe = BootCommon::CreateLinuxSection ("failsafe");
linux_xen = BootCommon::CreateLinuxSection ("xen");
}
y2milestone("Proposed section for linux_default: %1", linux_default);
y2milestone("Proposed section for linux_failsafe: %1", linux_failsafe);
y2milestone("Proposed section for linux_xen: %1", linux_xen);
y2milestone("Boot sections BEFORE deleting: %1", BootCommon::sections);
// obtain number of relative same boot sections for linux_default
integer num_linux_default = CountSection(linux_default);
// obtain number of relative same boot sections for linux_failsafe
integer num_linux_failsafe = CountSection(linux_failsafe);
// obtain number of relative same boot sections for linux_failsafe
integer num_linux_xen = CountSection(linux_xen);
BootCommon::sections=filter(map<string,any> section, BootCommon::sections,
{
if ((((section["name"]:nil == linux_default["name"]:nil)
||(section["description"]:"" == linux_default["name"]:nil))
&& (num_linux_default > 1))
||(((section["name"]:nil == linux_failsafe["name"]:nil)
||(section["description"]:"" ==linux_failsafe["name"]:nil))
&& (num_linux_failsafe > 1))
||(((section["name"]:nil == linux_xen["name"]:nil)
||(section["description"]:"" == linux_xen["name"]:nil))
&& (num_linux_xen > 1)))
{
if (((section["root"]:nil == linux_default["root"]:nil)
||(section["root"]:nil == linux_failsafe["root"]:nil)
||(section["root"]:nil == linux_xen["root"]:nil)))
{
if (section["original_name"]:"" == "failsafe")
num_linux_failsafe = num_linux_failsafe -1;
if (section["original_name"]:"" == "linux")
num_linux_default = num_linux_default -1;
if (section["original_name"]:"" == "xen")
num_linux_xen = num_linux_xen -1;
y2milestone("deleted boot section: %1", section);
return false;
} else {
return true;
}
} else {
return true;
};
return true;
});
ResolveSymlinksInSections();
FindAndSelectDefault(linux_default);
y2milestone("Boot sections AFTER deleting: %1", BootCommon::sections);
}
// write mode settings function
/**
* Set settings how to write bootloader
* @param settings map of settings
*/
global define void SetWriteMode (map<string,any> settings) {
y2milestone ("Setting mode for writing: %1", settings);
foreach (string k, any v, settings, {
BootCommon::write_settings[k] = v;
});
}
// sections handling functions
/**
* Resolve a single symlink in key image_key in section map s
* @param section map map of section to change
* @param image_key string key in section that contains the link
* @return section map of the changed section
*/
global define map<string,any> ResolveSymlink(map<string,any> section, string key) {
// The "-m" is needed in case the link is an absolute link, so that it does
// not fail to resolve when the root partition is mounted in
// Installation::destdir.
string readlink_cmd = "/usr/bin/readlink -n -m " + Installation::destdir;
map out = $[];
string newval = "";
// FIXME: find out why we need WFM::Execute() here (as olh used it above)
out = (map) WFM::Execute (.local.bash_output, readlink_cmd + section[key]:"");
if ( out["exit"]:0 == 0 && out["stdout"]:"" != "" ) {
newval = substring(out["stdout"]:"", size(Installation::destdir));
y2milestone("section %1: converting old %2 parameter from %3 to %4",
section["name"]:"", key, section[key]:"", newval);
section[key] = newval;
} else {
y2error ("section %1: failed to remap %2 parameter",
section["name"]:"", key);
}
return section;
}
/**
* Resolve symlinks in kernel and initrd paths, for existing linux, xen and
* failsafe sections
*/
// FIXME: this is the plan B solution, try to solve plan A in
// BootCommon.ycp:CreateLinuxSection() (line 435)
global define void ResolveSymlinksInSections() {
y2milestone("sections before remapping: %1", BootCommon::sections);
// change only linux, failsafe and xen sections
BootCommon::sections = maplist (map<string,any> s, BootCommon::sections, {
// skip sections that are not linux, xen or failsafe,
// or that are not of type "image" (or "xen" <- needed?)
if ( !contains ( ["linux", "xen", "failsafe"] , s["original_name"]:"") ||
!contains ( ["image", "xen"] , s["type"]:"") ) {
y2milestone("section %1: not linux, xen or failsafe, skipping kernel and initrd remapping",
s["name"]:"");
return s;
}
// first, resolve kernel link name
if ( haskey (s, "image") ) {
// also skip sections that start with a grub device name
// "(hd0,7)/boot/vmlinuz", and are not on the default (currently
// mounted) boot partition
if ( !regexpmatch(s["image"]:"", "^\(hd.*\)") ) {
s = ResolveSymlink(s, "image");
} else {
y2milestone("section %1: skipping remapping kernel symlink on other partition: %2",
s["name"]:"", s["image"]:"");
}
}
// resolve initrd link name, but skip if it is on a non-default boot
// partition (see above)
if ( haskey (s, "initrd") ) {
if ( !regexpmatch(s["initrd"]:"", "^\(hd.*\)") ) {
s = ResolveSymlink(s, "initrd");
} else {
y2milestone("section %1: skipping remapping initrd symlink on other partition: %2",
s["name"]:"", s["initrd"]:"");
}
}
return s;
});
y2milestone("sections after remapping: %1", BootCommon::sections);
}
/** bnc #364904
* Function parse zipl list names if default section is menu
*
* @param string (string) list of names
* @param string position of default name in list
* @return string name of default section from list
*/
string parseListDefault(string names, string position)
{
string ret = "";
y2milestone("section names (string) list: %1 and default name position in list: %2", names, position);
if ((names == "") || (position == ""))
return ret;
if (search(names, ",") != nil)
{
string tmp_names = deletechars(names, " ");
list <string> list_names = splitstring(tmp_names, ",");
ret = list_names[(tointeger(position)-1)]:"";
} else {
ret = names;
}
return ret;
}
/** bnc #364904
* Function check if default section is menu
* if yes it tries to find default section in
* list of names from menu section
*
* @param string name of default BootCommon::globals["default"]:""
* @return string name of default section
*/
string checkZiplDefault(string def)
{
string def_section_name = def;
if (getLoaderType () == "zipl")
{
foreach(map<string,any> section, BootCommon::sections,
{
if (section["name"]:"" == def_section_name)
{
if (section["type"]:"" == "menu")
{
string def_position = section["default"]:"";
def_section_name = parseListDefault(section["list"]:"", def_position);
} else {
break;
}
}
});
}
y2milestone("name of default section: %1", def_section_name);
return def_section_name;
}
/**
* return default section label
* @return string default section label
*/
global define string getDefaultSection () {
ReadOrProposeIfNeeded ();
string default_name = checkZiplDefault(BootCommon::globals["default"]:"");
return default_name;
}
/**
* Get default section as proposed during installation
* @return section that was proposed as default during installation,
* if not known, return current default section if it is of type "image",
* if not found return first linux section, if no present, return empty
* string
*/
global define string getProposedDefaultSection () {
ReadOrProposeIfNeeded ();
string defaultv = "";
string first_image = "";
string default_image = "";
foreach (map<string,any> s, BootCommon::sections, {
string title = s["name"]:"";
if (s["image"]:nil != nil)
{
if (first_image == "")
first_image = title;
if (title == getDefaultSection ())
default_image = title;
}
if (defaultv == "" && s["original_name"]:"" == "linux")
defaultv = title;
});
if (defaultv != "")
return defaultv;
if (default_image != "")
return default_image;
if (first_image != "")
return first_image;
return "";
}
/**
* get kernel parameters from bootloader configuration file
* @param section string section title, use DEFAULT for default section
* @param key string
* @return string value, "false" if not present,
* "true" if present key without value
*/
global define string getKernelParam (string section, string key) {
ReadOrProposeIfNeeded ();
if (section == "DEFAULT")
section = getDefaultSection ();
else if (section == "LINUX_DEFAULT")
section = getProposedDefaultSection ();
if (section == nil)
return "";
map params = (map)BootCommon::getAnyTypeAttrib("kernel_params",$[]);
integer sectnum = -1;
integer index = -1;
foreach (map<string,any> s, BootCommon::sections, {
index = index + 1;
if (s["name"]:"" == section)
sectnum = index;
});
if (sectnum == -1)
return "";
string line = "";
if (contains (["root", "vgamode"], key))
return BootCommon::sections[sectnum, key]:"false";
else
{
line = BootCommon::sections[sectnum, "append"]:"";
return BootCommon::getKernelParamFromLine (line, key);
}
}
/**
* set kernel parameter to menu.lst
* @param section string section title, use DEFAULT for default section
* @param key string parameter key
* @param value string value, "false" to remove key,
* "true" to add key without value
* @return boolean true on success
*/
global define boolean setKernelParam
(string section, string key, string value)
{
if ((! Mode::config ()) && key == "vga" && (
Arch::s390 () || Arch::ppc ()
))
{
y2warning ("Kernel of this architecture does not support the vga parameter");
return true;
}
ReadOrProposeIfNeeded ();
if (section == "DEFAULT")
section = getDefaultSection ();
else if (section == "LINUX_DEFAULT")
section = getProposedDefaultSection ();
if (section == nil)
return false;
integer sectnum = -1;
integer index = -1;
foreach (map<string,any> s, BootCommon::sections, {
index = index + 1;
if (s["name"]:"" == section)
sectnum = index;
});
if (sectnum == -1)
return false;
string slabel = "";
if ((key == "vga" || key == "root") && (value == "true"))
return false;
if (contains (["root", "vga"], key))
{
if (value != "false")
{
if (key == "vga")
BootCommon::sections[sectnum, "vgamode"] = value;
else
BootCommon::sections[sectnum, key] = value;
// added flag that section was modified bnc #432651
BootCommon::sections[sectnum, "__changed"] = true;
}
else
{
if (key == "vga")
BootCommon::sections[sectnum] = remove (BootCommon::sections[sectnum]:$[], "vgamode");
else
BootCommon::sections[sectnum] = remove (BootCommon::sections[sectnum]:$[], key);
}
}
else
{
string line = BootCommon::sections [sectnum, "append"]:"";
line = BootCommon::setKernelParamToLine (line, key, value);
BootCommon::sections [sectnum, "append"] = line;
// added flag that section was modified bnc #432651
BootCommon::sections[sectnum, "__changed"] = true;
}
BootCommon::changed = true;
boolean ret = true;
return ret;
}
/**
* Get currently used bootloader, detect if not set yet
* @return string botloader type
*/
global define string getLoaderType () {
return BootCommon::getLoaderType (false);
}
/**
* Set type of bootloader
* Just a wrapper to BootCommon::setLoaderType
* @param bootloader string type of bootloader
*/
global define void setLoaderType (string bootloader) {
BootCommon::setLoaderType (bootloader);
}
/**
* Get root fs device
* @return string root device
*/
global define string getRootDevice () {
ReadOrProposeIfNeeded ();
return BootStorage::RootPartitionDevice;
}
/**
* Set root fs device
* @param device string root device
*/
global define void setRootDevice (string device) {
ReadOrProposeIfNeeded ();
BootStorage::RootPartitionDevice = device;
}
/**
* Get device containing /boot directory
* @return string boot device
*/
global define string getBootDevice () {
ReadOrProposeIfNeeded ();
return BootStorage::BootPartitionDevice;
}
/**
* Set device containing /boot directory
* @param device string boot device
*/
global define void setBootDevice (string device) {
ReadOrProposeIfNeeded ();
BootStorage::BootPartitionDevice = device;
}
/**
* Set section to boot on next reboot
* @param section string section to boot
* @return boolean true on success
*/
global define void RunDelayedUpdates()
{
// perl-BL delayed section removal
BootCommon::RunDelayedUpdates ();
return;
}
/**
* Set section to boot on next reboot
* @param section string section to boot
* @return boolean true on success
*/
global define boolean FlagOnetimeBoot(string section)
{
return blFlagOnetimeBoot (section);
}
/**
* Check whether settings were read or proposed, if not, decide
* what to do and read or propose settings
*/
global define void ReadOrProposeIfNeeded () {
if (! (BootCommon::was_read || BootCommon::was_proposed))
{
y2milestone ("Stage::initial (): %1, update: %2, config: %3",
Stage::initial (), Mode::update (), Mode::config ());
if (Mode::config ())
{
y2milestone ("Not reading settings in Mode::config ()");
BootCommon::was_read = true;
BootCommon::was_proposed = true;
}
else if (Arch::ia64 () && Mode::update ()
)// FIXME && BootELILO::efi_layout_changed)
{ // recreate config on IPF from scratch - request by rw
y2milestone ("Reproposing new configuration - IPF, EFI layout has changed");
Propose ();
}
else if (Stage::initial () && ! Mode::update ())
{
Propose ();
}
else
{
boolean progress_orig = Progress::set (false);
Read ();
Progress::set (progress_orig);
if (Mode::update ())
{
UpdateConfiguration ();
ResolveSymlinksInSections();
BootCommon::changed = true;
BootCommon::location_changed = true;
}
}
}
}
/**
* Update the language of GFX menu according to currently selected language
* @return boolean true on success
*/
global define boolean UpdateGfxMenu () {
if (getLoaderType () != "lilo" && getLoaderType () != "grub")
return true;
boolean ret = BootCommon::UpdateGfxMenuContents ();
if (! Mode::normal ())
return true;
if (getLoaderType () == "lilo")
{
/*
* This is extreme boolshit, Bootloader::Library has to be called
*/
string bl_command = "/sbin/lilo >> /var/log/YaST2/y2log_bootloader 2>&1";
boolean command_ret = 0 == SCR::Execute (.target.bash, bl_command);
if (! command_ret)
{
y2error ("Execution of installation command failed");
return false;
}
}
return ret;
}
/**
* Function update append -> add console to append
*
* @param map<string,any> boot section
* @return map<string,any> updated boot section
*/
map<string,any> updateAppend(map<string,any> section)
{
map<string,any> ret = section;
if ((section["append"]:"" != "") && (section["console"]:"" != ""))
{
string updated_append = BootCommon::UpdateSerialConsole(section["append"]:"", section["console"]:"");
if (updated_append != nil)
{
ret["append"]=updated_append;
}
}
return ret;
}
/**
* Copy initrd and kernel on the end of instalation
* (1st stage)
* @return boolean on success
*/
// fate #303395 Use kexec to avoid booting between first and second stage
// copy kernel and initrd to /var/lib/YaST
// run kernel via kexec instead of reboot
// if not success then reboot...
global define boolean CopyKernelInird()
{
y2milestone("CopyKernelInird: start copy kernel and inird");
if (Mode::live_installation())
{
y2milestone("Running live_installation without using kexec");
return true;
}
if (ProductFeatures::GetBooleanFeature ("globals", "kexec_reboot") != true)
{
y2milestone("Option kexec_reboot is false. kexec will not be used.");
return true;
}
// check architecture for using kexec instead of reboot
if (Arch::ppc() || Arch::ia64() || Arch::s390())
{
y2milestone("Skip using of kexec on this architecture");
return true;
}
// checking if installation run on VirtualBox
string cmd = sformat("hwinfo --bios |grep Product");
y2milestone("Checking if installation run on VirtualBox command: %1", cmd);
map out = (map)WFM::Execute(.local.bash_output, cmd);
if (search(out["stdout"]:"", "VirtualBox") != nil)
{
y2milestone ("Installation run on VirtualBox, skip kexec loading: %1", out);
return false;
}
// create defualt sections
map<string,any> linux_default = BootCommon::CreateLinuxSection ("linux");
y2milestone("linux_default: %1", linux_default);
map<string,any> default_section = $[];
string name = getDefaultSection ();
// find default section in BootCommon::sections
foreach(map<string,any> section, BootCommon::sections,
{
if ((search(tostring(section["name"]:""),name) != nil)
&& (section["root"]:nil == linux_default["root"]:nil)
&& (section["original_name"]:"" != "failsafe"))
{
y2milestone("default section: %1", section);
default_section = section;
};
});
// create directory /var/lib/YaST2
WFM::Execute(.local.mkdir, "/var/lib/YaST2");
// build command for copy kernel and initrd to /var/lib/YaST during instalation
cmd = nil;
default_section = updateAppend(default_section);
cmd = sformat("/bin/cp %1%2 %1%3 %4", Installation::destdir, tostring(default_section["image"]:""),
tostring(default_section["initrd"]:""), Directory::vardir);
y2milestone("Command for copy: %1", cmd);
out = (map) WFM::Execute (.local.bash_output, cmd);
if (out["exit"]:nil != 0)
{
y2error ("Copy kernel and initrd failed, output: %1", out);
return false;
}
if (default_section["root"]:"" == "")
{
y2milestone("root is not defined in default section.");
return false;
}
if (default_section["vgamode"]:"" == "")
{
y2milestone("vgamode is not defined in default section.");
return false;
}
// flush kernel options into /var/lib/YaST/kernel_params
cmd = sformat("echo \"root=%1 %2 vga=%3\" > %4/kernel_params",
tostring(default_section["root"]:""), tostring(default_section["append"]:""),
tostring(default_section["vgamode"]:""), Directory::vardir);
y2milestone("Command for flushing kernel args: %1", cmd);
out = (map) WFM::Execute (.local.bash_output, cmd);
if (out["exit"]:nil != 0)
{
y2error ("Flushing kernel params failed, output: %1", out);
return false;
}
return true;
}
/** Fate #305557: Enable SELinux for 11.2
* Function cerate /selinux directory
* if SELinux is enabled
*/
void createSELinuxDir ()
{
string path_file = "/selinux";
string cmd = "ls -d /selinux 2>/dev/null";
if (BootCommon::enable_selinux)
{
if (Mode::normal() || Mode::installation())
{
map out = (map)SCR::Execute(.target.bash_output, cmd);
y2milestone("runnning command: \"%1\" and return: %2", cmd, out);
if (out["stdout"]:"" != "/selinux\n")
SCR::Execute(.target.mkdir, path_file);
else
y2milestone("Directory /selinux already exist");
} else {
y2milestone("Skip creating /selinux directory -> wrong mode");
}
} else {
y2milestone("Skip creating /selinux directory");
}
}
/** Fate #309275 SELinux: enable pam_selinux when switching on SELinux in yast2_bootloader
* Function take care about enable/disable SELinuc
*
*/
void handleSELinuxPAM ()
{
y2milestone("handleSELinuxPAM called");
if (Mode::normal() || Mode::installation())
{
if (BootCommon::enable_selinux)
{
y2milestone("call enableSELinuxPAM");
enableSELinuxPAM ();
} else {
y2milestone("call disableSELinuxPAM");
disableSELinuxPAM ();
}
} else {
y2milestone("Skip changing SELinux/AppArmor PAM config -> wrong mode");
}
}
/** Fate #309275 SELinux: enable pam_selinux when switching on SELinux in yast2_bootloader
* Function enable SELinux
*
*/
void enableSELinuxPAM ()
{
string cmd_enable_se = "pam-config -a --selinux 2>/dev/null";
string cmd_disable_aa = "pam-config -d --apparmor 2>/dev/null";
map out = (map) SCR::Execute (.target.bash, cmd_disable_aa);
y2debug("result of disabling the AppArmor PAM module is %1", out);
out = (map) SCR::Execute (.target.bash, cmd_enable_se);
y2debug("result of enabling the SELinux PAM module is %1", out);
}
/** Fate #309275 SELinux: enable pam_selinux when switching on SELinux in yast2_bootloader
* Function disable SELinux
*
*/
void disableSELinuxPAM ()
{
string cmd_disable_se = "pam-config -d --selinux 2>/dev/null";
string cmd_enable_aa = "pam-config -a --apparmor 2>/dev/null";
map out = (map) SCR::Execute (.target.bash, cmd_disable_se);
y2debug("result of disabling the SELinux PAM module is %1", out);
out = (map) SCR::Execute (.target.bash, cmd_enable_aa);
y2debug("result of enabling the AppArmor PAM module is %1", out);
}
}
ACC SHELL 2018