ACC SHELL
/**
* File:
* modules/BootPOWERLILO.ycp
*
* Module:
* Bootloader installation and configuration
*
* Summary:
* Module containing specific functions for POWERLILO configuration
* and installation
*
* Authors:
* Jiri Srain <jsrain@suse.cz>
* Joachim Plack <jplack@suse.de>
* Olaf Dabrunz <od@suse.de>
* Philipp Thomas <pth@suse.de>
*
* $Id: BootPOWERLILO.ycp 59966 2009-12-04 15:16:44Z juhliarik $
*
*/
{
module "BootPOWERLILO";
textdomain "bootloader";
import "Arch";
import "BootArch";
import "BootCommon";
import "BootStorage";
import "Installation";
import "Kernel";
import "Mode";
import "Pkg";
import "Stage";
import "Storage";
/*
* include ppc specific help messages
*/
include "bootloader/ppc/helps.ycp";
/*
* read my dialogs
*/
include "bootloader/routines/popups.ycp"; // define confirmSectionDeletePopup
/*
* This whole code is a big mess. To have a solution at all I included and
* adapted copies of the code from the old BootPPC.ycp, from common code in
* lilolike.ycp and others.
*
* od - February and March 2006
*/
// partition number for the bootloader (either 41PReP boot or Apple_HFS)
// start with disabled value and let the partition scanner find a match.
global string prep_boot_partition = "";
// map available of 41 PReP partitions, used on iSeries and CHRP
global list<string> prep_boot_partitions = [];
// map available HFS partitions, used on PMac
global list<string> pmac_boot_partitions = [];
// PReP boot partitions that were proposed by partitioner to install BL
global list<string> install_prep_boot_partitions = [];
// saved ID of the base installation source
global integer base_source = -1;
// iSeries specific global settings
// current board attribs
global boolean prep_only_active = true;
global boolean prep_only_iseries_vd = true;
global boolean prep_only_primary = true;
global boolean prep_same_disk_as_root = true;
global list table_items = [];
global string boot_device = "";
string board_type = nil;
global define string getBoardType ();
global define void currentBoardInit ();
include "bootloader/ppc/dialogs.ycp";
/**
* Update list of 41 PReP boot partitions
* @return boolean true if list changed, false otherwise
*/
boolean updatePrepBootPartitions () {
y2milestone ("Detecting PReP partitions: prep_only_active: %1, prep_only_iseries_vd: %2, prep_only_primary: %3", prep_only_active, prep_only_iseries_vd, prep_only_primary);
map<string,map> targetMap = (map<string,map>)Storage::GetTargetMap ();
y2milestone ("TargetMap: %1", targetMap);
list old_prep_boot_partitions = prep_boot_partitions;
list old_install_prep_boot_partitions = install_prep_boot_partitions;
prep_boot_partitions = [];
install_prep_boot_partitions = [];
y2milestone("old prep_boot_partitions %1", old_prep_boot_partitions);
foreach (string dname, map ddata, targetMap, ``{
list<map> partitions = ddata["partitions"]:[];
y2milestone ("Partitions: %1", partitions);
partitions = filter (map p, partitions,
``((! p["delete"]:false) && is (p["fsid"]:nil, integer)
// both partition types 0x41 and FAT16 can be handled by PPC lilo
&& (p["fsid"]:nil == 65 || p["fsid"]:nil == 6)
&& !contains( [`lvm, `evms, `sw_raid], p["type"]:`primary )
));
y2milestone ("Filtered existing partitions: %1", partitions);
// prep_only_iseries_vd means: use only partitions on /dev/iseries/vd*
if (prep_only_iseries_vd) {
partitions = filter (map p, partitions, ``(
regexpmatch (p["device"]:"", "\/dev\/iseries\/vd.*")
));
}
if (prep_only_primary) {
partitions = filter (map p, partitions, ``(
p["type"]:`primary == `primary
));
}
y2milestone ("Finally filtered partitions: %1", partitions);
prep_boot_partitions = (list<string>)
merge (prep_boot_partitions,
(list<string>)maplist (map p, partitions, ``(p["device"]:""))
);
partitions = filter (map p, partitions, ``(p["prep_install"]:false));
y2milestone ("Finally filtered recommended partitions: %1",
partitions);
install_prep_boot_partitions = (list<string>)
merge (
install_prep_boot_partitions,
(list<string>) maplist(map p, partitions, ``(p["device"]:""))
);
});
prep_boot_partitions = filter (string p, prep_boot_partitions, ``(p != ""));
prep_boot_partitions = sort (prep_boot_partitions);
y2milestone ("Detected PReP partitions: %1", prep_boot_partitions);
y2milestone ("Proposed PReP partitions: %1",
install_prep_boot_partitions);
if (old_prep_boot_partitions == prep_boot_partitions
&& old_install_prep_boot_partitions == install_prep_boot_partitions)
{
y2milestone ("PReP Partitions unchanged");
return false;
}
else {
y2milestone ("PReP Partitions changed");
return true;
}
}
/**
* Select PReP boot partition to propose
* Changes internal variables.
*/
void choosePrepBootPartition () {
y2milestone ("Resetting selected PReP boot partition");
list<string> root_disks = [];
if (Storage::CheckForLvmRootFs ()) {
map<string,map> tm = Storage::GetTargetMap ();
string vg = "";
foreach (string dev, map info, tm, {
if (info["type"]:`CT_UNKNOWN==`CT_LVM) {
list<map> volumes = info["partitions"]:[];
foreach (map v, volumes, {
if (v["mount"]:"" == "/") {
vg = info["name"]:"";
y2milestone ("Volume group of root FS: %1", vg);
}
});
}
});
foreach (string dev, map info, tm, {
list<map> partitions = info["partitions"]:[];
foreach (map p, partitions, {
if (p["used_by_device"]:"" == "/dev/" + vg) {
root_disks = add (root_disks, dev);
}
});
});
y2milestone ("Disks holding LVM with root fs: %1", root_disks);
}
else {
root_disks = [
Storage::GetDiskPartition(BootStorage::RootPartitionDevice)["disk"]:""
];
}
prep_boot_partition = "";
// First take the partitions that Storage:: hinted us to take, then
// consider the other prep_boot_partitions
prep_boot_partitions = (list<string>)
merge (
install_prep_boot_partitions,
prep_boot_partitions);
// in the combined list, look for "usable" partitions:
// - if we require the boot partition to be on the same disk as
// the root partition ("prep_same_disk_as_root"), select the
// first prep partition from that disk
// - otherwise take the first prep partition in the list
foreach (string partition, prep_boot_partitions, ``{
if (prep_boot_partition == "") {
boolean usable = true;
if (prep_same_disk_as_root) {
map part_split = Storage::GetDiskPartition (partition);
string part_disk = part_split["disk"]:"";
if (! contains (root_disks, part_disk))
usable = false;
}
if (usable)
prep_boot_partition = partition;
}
});
// For CHRP lilo can handle PReP partition on other disks now
// If all above fails, take the first one then ...
if ( (prep_boot_partition == "") && (getBoardType () == "chrp") ) {
prep_boot_partition = prep_boot_partitions[0]:"";
}
y2milestone ("Selected PReP boot partition: %1", prep_boot_partition);
BootCommon::activate = (prep_boot_partition != "");
y2milestone ("Install bootloader: %1", BootCommon::activate);
}
/**
* Initialize attributes of the board type
*/
void PRePInit () {
y2milestone ("Initializing PReP attributes");
prep_only_active = true;
prep_only_iseries_vd = false;
prep_only_primary = true;
prep_same_disk_as_root = false;
table_items = [ "__prep_location" ];
}
/**
* Initialize attributes of the board type
*/
void CHRPInit () {
y2milestone ("Initializing CHRP attributes");
prep_only_active = true;
prep_only_iseries_vd = false;
prep_only_primary = true;
// On CHRP, if there is no bootable partition on the disk containing
// "/", there is CHRP-specific code in choosePrepBootPartition that
// takes the first prep partition in the system.
prep_same_disk_as_root = true;
table_items = [ "__chrp_location", "__set_default_of" ];
}
/**
* Helper function that executes a command with the shell, appending
* stdout and stderr to a logfile. On error, it writes log entries to the
* yast2 log.
* @param command string command to execute
* @param logfile string logfile for the commands output
* @return boolean true on success
*/
boolean iSeriesExecute (string command, string logfile) ``{
command = command + " >>" + logfile + " 2>&1";
integer command_ret = (integer)SCR::Execute (.target.bash, command);
if (command_ret != 0) {
y2error ("Execution of command failed: %1, error code: %2", command, command_ret);
string log = (string)SCR::Read (.target.string, logfile);
y2error ("stderr and stdout of the command: %1", log);
return false;
}
return true;
}
/**
* Install the board-type-specific part of bootloader
* @return boolean true on success
*/
global define boolean iSeriesWrite () {
if (! BootCommon::activate)
return true;
// during installation (fresh or update), always install the ISERIES64
// file into slot A as a "rescue system"
if (Stage::initial ()) {
string command = "";
string my_log = "/var/log/YaST2/y2log_bootloader_iseries_slot_a";
// bnc #409927 VUL-0: yast2: slideshow not checked cryptographically
string src_filename = Pkg::SourceProvideDigestedFile(base_source, 1, "/ISERIES64", false);
if (base_source == -1 || src_filename == nil) {
y2milestone ("Cannot write rescue kernel to slot A, base source not found");
return false;
}
string rescue_bootbinary = (string)SCR::Read (.target.tmpdir)
+ "/rescue_bootbinary";
string tg_rescue_bootbinary
= Installation::destdir + rescue_bootbinary;
y2milestone ("Copying %1 to %2",
src_filename, tg_rescue_bootbinary);
WFM::Execute (.local.bash, sformat ("/bin/cp %1 %2",
src_filename, tg_rescue_bootbinary));
y2milestone("start writing rescue kernel to slot A ...");
command = "time dd if=" + rescue_bootbinary
+ " of=/proc/iSeries/mf/A/vmlinux bs=64k";
if (! iSeriesExecute (command, my_log))
return false;
if (! iSeriesExecute (
"dd if=/dev/zero of=/proc/iSeries/mf/A/cmdline bs=255 count=1",
my_log)
)
return false;
// NOTE: on SLES10, the "root=" parameter is not handled by the
// initrd in the ISERIES64 file. The initrd just boots up to a
// shell.
SCR::Execute (.target.bash,
"echo -en 'start_shell manual=1\\0' > /proc/iSeries/mf/A/cmdline");
y2milestone("done writing rescue kernel to slot A.");
}
return true;
}
/**
* Initialize attributes of the board type
*/
global define void iSeriesInit () {
y2milestone ("Initializing iSeries attributes");
prep_only_active = true;
prep_only_iseries_vd = true;
prep_only_primary = true;
prep_same_disk_as_root = false;
table_items = [ "__iseries_location" ];
}
// misc. functions
global define void initBoardType () {
if (Arch::board_iseries ())
{
board_type = "iseries";
}
else if (Arch::board_prep ())
{
board_type = "prep";
}
else if (Arch::board_chrp ())
{
board_type = "chrp";
}
else if (Arch::board_mac_new ())
{
board_type="pmac";
}
else if (Arch::board_mac_old ())
{
board_type="pmac";
}
else
{
board_type = "unknown";
}
y2milestone ("setting board type to: %1", board_type);
}
global define string getBoardType () {
if (board_type == nil)
initBoardType ();
return board_type;
}
/**
* Initialize the attribute of currently used board type
*/
global define void currentBoardInit () {
if (getBoardType () == "iseries")
{
iSeriesInit ();
}
else if (getBoardType () == "prep")
{
PRePInit ();
}
else if (getBoardType () == "chrp")
{
CHRPInit ();
}
// TODO other boards
}
/**
* Create section for bootable image
* @param title string the section name to create (untranslated)
* @return map describes the section
*/
global map<string,any> CreateImageSection (string title) {
map<string,any> ret = BootCommon::CreateLinuxSection(title);
//Do not use translated names, as we are happy if it work with kernel device
ret["root"] = BootStorage::RootPartitionDevice;
// bnc #217443
ret["optional"] = "true";
//do not use translated name FIXME this should be filtered out
ret["name"] = title;
return ret;
}
/**
* Choose a boot partition on pmac
* type == Apple_HFS|Apple_Bootstrap && size < 20 cyl
* @return string device name of pmac boot partition
*/
string GoodPmacBootPartition() {
y2milestone ("Detecting pmac boot partition");
map<string,map> targetMap = (map<string,map>)Storage::GetTargetMap ();
y2milestone ("TargetMap: %1", targetMap);
list<string> boot_partitions = [];
string selected_boot_partition = "";
foreach (string dname, map ddata, targetMap, ``{
list<map> partitions = ddata["partitions"]:[];
y2milestone ("Partitions: %1", partitions);
// does this device contain the root partition?
boolean hasrootdev = ( find (map p, partitions, ``(
(! p["delete"]:false)
&& p["device"]:"" == BootStorage::RootPartitionDevice
&& !contains( [`lvm, `evms, `sw_raid], p["type"]:`primary )
)) != nil );
// find possible boot partitions
partitions = filter (map p, partitions, ``(
(! p["delete"]:false)
&& is (p["fsid"]:nil, integer)
// both partition types Apple_Bootstrap and Apple_HFS can be
// handled by PPC lilo; yast2-storage maps both to fsid 258
&& (p["fsid"]:nil == 258)
&& !contains( [`lvm, `evms, `sw_raid], p["type"]:`primary )
));
y2milestone ("Filtered existing partitions: %1", partitions);
// bug #459860 - no boot partition found during fresh install
// find the smallest partition
integer max_size = 1000000000;
integer iter = -1;
integer min_position = -1;
foreach (map p, partitions,
{
iter = iter +1;
if (p["size_k"]:0 < max_size)
{
min_position = iter;
max_size = p["size_k"]:0;
}
});
// if any partition was found
if (min_position > -1)
{
list <map> tmp_partitions = [];
map partition = partitions[min_position]:$[];
if (partition["size_k"]:0 < 160650)
y2milestone("Partition smaller than 160650k: %1", partition);
else
y2warning("Partition is not smaller than 160650k: %1", partition);
tmp_partitions = add(tmp_partitions, partition);
partitions = tmp_partitions;
}
y2milestone ("Filtered existing partitions: %1", partitions);
// found a boot partition on the same device as the root partition?
if (hasrootdev && size (partitions) > 0
&& selected_boot_partition == "")
{
y2milestone ("Selected pmac boot partition %1 on device with root partition %2",
partitions[0, "device"]:"", BootStorage::RootPartitionDevice);
selected_boot_partition = partitions[0, "device"]:"";
}
// collect found boot partitions
boot_partitions = (list<string>)merge (boot_partitions,
(list<string>)maplist (map p, partitions, ``(
p["device"]:""
))
);
});
y2milestone ("Detected pmac boot partitions: %1", boot_partitions);
pmac_boot_partitions = boot_partitions;
if (selected_boot_partition == "")
{
selected_boot_partition = boot_partitions[0]:"";
}
y2milestone ("Selected pmac boot partition: %1", selected_boot_partition);
return selected_boot_partition;
}
/**
* Propose the location of the root device on disk and the boot device (if
* any), according to the subarchitecture.
* Results are stored in global variables.
*
*/
global void LocationProposal () {
BootCommon::DetectDisks ();
// del_parts is used by FixSections() in lilolike.ycp (imported by BootCommon.ycp)
BootCommon::del_parts = BootStorage::getPartitionList (`deleted, "ppc");
if (BootCommon::DisksChanged ()) {
y2milestone ("Reconfiguring locations");
BootCommon::DetectDisks ();
}
if (updatePrepBootPartitions () || prep_boot_partition == "")
{
// TODO warning to user
choosePrepBootPartition ();
}
switch (getBoardType()) {
case ("chrp"):
BootStorage::BootPartitionDevice = prep_boot_partition;
break;
case ("prep"):
BootStorage::BootPartitionDevice = prep_boot_partition;
break;
case ("iseries"):
BootStorage::BootPartitionDevice = prep_boot_partition;
break;
case ("pmac") :
BootStorage::BootPartitionDevice = GoodPmacBootPartition();
break;
default:
y2error("Unknown ppc architecture");
}
// These need to be set, for POWERLILO probably only to interface with
// autoyast, others base subsequent decisions on this.
// See ConfigureLocation() in lilolike.ycp.
//
// Mini-discussion: If autoyast is mainly used to clone configs, the
// loader_device and repl_mbr interface is enough, because loader_device
// simply contains the name of the device (partition, disk MBR, RAID
// device) to use for the bootloader.
// But if autoyast some day is used to transport configurations to less
// similar machines and setups, or to specify some sort of generic setup
// with special settings that will work on most machines, it may (or may
// not) be helpful to be able to specify boot_* variables in the autoyast
// file. This may apply better to the boot_* variables in BootGRUB.ycp
// though.
// FIXME: what about loader_location (aka selected_location internally)?
BootCommon::loader_device = BootStorage::BootPartitionDevice;
BootCommon::activate = true;
y2milestone("Boot partition is %1", BootCommon::loader_device);
}
/**
* Propose sections to bootloader menu
* modifies internal sreuctures
*/
global void CreateSections () {
map<string,any> linux = CreateImageSection ("linux");
// FIXME: create an 'other' section for MACs to boot MacOS
BootCommon::sections = [ linux, ];
}
/**
* Propose global options of bootloader
* modifies internal structures
*/
global void CreateGlobals () {
BootCommon::globals = $[
"activate": "true",
"default" : BootCommon::sections[0, "name"]:"",
"timeout" : "8",
];
map<string, string> boot_map = $[];
y2milestone("RootPartDevice is %1",BootStorage::RootPartitionDevice);
switch(getBoardType()){
case ("chrp") :
boot_map = $[
"boot_chrp_custom" : BootStorage::BootPartitionDevice,
];
break;
case ("prep") :
boot_map = $[
"boot_prep_custom" : BootStorage::BootPartitionDevice,
];
break;
case ("pmac") :
boot_map = $[
"boot_pmac_custom" : BootStorage::BootPartitionDevice,
];
break;
case ("iseries") :
boot_map = $[
"boot_slot" : "B",
// FIXME: what file should be used here?
"boot_file" : "/tmp/suse_linux_image",
];
// If we have an empty BootPartitionDevice on iseries, this means:
// do not boot from BootPartitionDevice but from some other place.
// Do not pass down to perl-Bootloader, lilo fails on an empty "boot =" line.
if (BootStorage::BootPartitionDevice != nil &&
BootStorage::BootPartitionDevice != "") {
boot_map["boot_iseries_custom"] = BootStorage::BootPartitionDevice;
}
break;
default:
y2error("Unknown ppc architecture");
}
// Finally merge results into "globals": new values replace old ones
BootCommon::globals = (map<string, string>) union(BootCommon::globals, boot_map);
}
/**
* Save the ID of the base installation source
* modifies internal variable
*/
global void SaveInstSourceId () {
base_source = -1;
// Find the source ID of the base product:
// list all products
list<map<string,any> > products =
Pkg::ResolvableProperties ("", `product, "");
y2internal ("products: %1", products);
// filter products to be installed
products = filter (map<string,any> p, products, {
return p["source"]:-1 != -1;
});
// get base products
list<map<string,any> > base_products =
filter (map<string,any> p, products, {
return p["category"]:"" == "base";
});
if (size (base_products) == 0)
base_products = products; // just to be safe in case of a bug...
list<integer> sources = maplist (map<string,any> p, base_products, {
return p["source"]:-1;
});
y2internal ("remaining products: %1, sources: %2",
products, sources);
sources = sort (sources);
base_source = sources[0]:-1;
y2milestone ("Base source: %1", base_source);
}
/** bnc #439674 Autoyast install of Cell blades fails to install bootloader
* The function update global settings for bootloader
* if there is used autoyast The basic problem is that there is missing
* boot_* , timeout etc.
* If there missing necessary information they will be added
*
*/
void UpdateGlobalsInAutoInst()
{
if (!haskey(BootCommon::globals, "timeout"))
BootCommon::globals["timeout"] = "8";
if (!haskey(BootCommon::globals, "activate"))
BootCommon::globals["activate"] = "true";
// if there missing boot_* -> then propose it
if ((!haskey(BootCommon::globals, "boot_chrp_custom")) &&
(!haskey(BootCommon::globals, "boot_prep_custom")) &&
(!haskey(BootCommon::globals, "boot_pmac_custom")) &&
(!haskey(BootCommon::globals, "boot_iseries_custom")))
{
string arch = getBoardType ();
switch(arch) {
case ("prep"):
BootCommon::globals["boot_prep_custom"] = BootStorage::BootPartitionDevice;
break;
case ("pmac"):
BootCommon::globals["boot_pmac_custom"] = BootStorage::BootPartitionDevice;
break;
case ("iseries"):
BootCommon::globals["boot_slot"] = "B";
BootCommon::globals["boot_file"] = "/tmp/suse_linux_image";
if (BootStorage::BootPartitionDevice != nil &&
BootStorage::BootPartitionDevice != "")
{
BootCommon::globals["boot_iseries_custom"] = BootStorage::BootPartitionDevice;
}
break;
default:
BootCommon::globals["boot_chrp_custom"] = BootStorage::BootPartitionDevice;
break;
}
}
}
// general functions
/**
* Propose bootloader settings
*/
global define void Propose () {
y2debug ("Started propose: Glob: %1, Sec: %2",
BootCommon::globals, BootCommon::sections);
// Need to remember inst source ID now to get the ISERIES64 file from the
// inst source later on (see Bug #165497, Comment #16). This won't work
// later during inst_finish, so we need to do it earlier -- only the
// proposal is a possible place.
SaveInstSourceId();
// FIXME: make modern code out of these conditionals
// - comments
// - simplify
// - check validity
boolean initial_propose = true;
if (BootCommon::was_proposed)
{
// FIXME: autoyast settings are simply Import()ed and was_proposed is
// set to true. The settings for the current board still need to be
// initialized though. We do this every time the bootloader proposal is
// called, because it also does not harm (results for the board
// detection are cached both in Arch.ycp and in our variable
// board_type.) To fix: make the "where does the information come
// from", when, more clear and obvious (in the code and/or in docs).
if (Mode::autoinst ())
{
currentBoardInit ();
}
initial_propose = false;
}
else
{
currentBoardInit ();
}
y2milestone ("board type is: %1", board_type);
// Get root and boot partition (if any)
LocationProposal();
if (BootCommon::sections == nil || size (BootCommon::sections) == 0)
{
CreateSections (); // make an initial proposal for at least one section
BootCommon::kernelCmdLine = Kernel::GetCmdLine ();
}
else
{
if (Mode::autoinst ())
{
y2debug ("Nothing to do in AI mode if sections exist");
// bnc #439674 Autoyast install of Cell blades fails to install bootloader
UpdateGlobalsInAutoInst();
}
else
BootCommon::FixSections (BootPOWERLILO::CreateSections);
}
if (BootCommon::globals == nil ||
// consider globals empty even if lines_cache_id is present
size (filter(string key, any v, BootCommon::globals, {
return key != "lines_cache_id";
})) == 0)
{
CreateGlobals ();
}
else
{
if (Mode::autoinst ())
{
y2debug ("Nothing to do in AI mode if globals are defined");
}
else
BootCommon::FixGlobals ();
}
y2milestone ("Proposed sections: %1", BootCommon::sections);
y2milestone ("Proposed globals: %1", BootCommon::globals);
}
/**
* Export bootloader settings to a map
* @return bootloader settings
*/
global define map Export () {
map exp = $[
"global": BootCommon::remapGlobals(BootCommon::globals),
"sections" : BootCommon::remapSections(BootCommon::sections),
"activate" : BootCommon::activate,
];
return exp;
}
/**
* Import settings from a map
* @param settings map of bootloader settings
* @return boolean true on success
*/
global define boolean Import (map settings) {
BootCommon::globals = settings["global"]:$[];
BootCommon::sections = settings["sections"]:[];
BootCommon::activate = settings["activate"]:false;
return true;
}
/**
* Read settings from disk
* @param reread boolean true to force reread settings from system
* @param avoid_reading_device_map do not read new device map from file, use
* internal data
* @return boolean true on success
*/
global boolean Read (boolean reread, boolean avoid_reading_device_map) {
BootCommon::InitializeLibrary (reread, "ppc");
if (reread) {
BootCommon::ReadFiles (avoid_reading_device_map);
}
boolean ret = BootCommon::Read (false, avoid_reading_device_map);
y2milestone (":: Read globals: %1", BootCommon::globals);
//importMetaData();
return ret;
}
/**
* Reset bootloader settings
*/
global define void Reset (boolean init) {
// Reset global variables to default values
prep_boot_partition = "";
prep_boot_partitions = [];
install_prep_boot_partitions = [];
BootCommon::Reset (init);
}
/**
* Save all bootloader configuration files to the cache of the PlugLib
* PlugLib must be initialized properly !!!
* @param clean boolean true if settings should be cleaned up (checking their
* correctness, supposing all files are on the disk
* @param init boolean true to init the library
* @param flush boolean true to flush settings to the disk
* @return boolean true if success
*/
global boolean Save (boolean clean, boolean init, boolean flush) {
boolean ret = true;
// FIXME: this is currently a copy from BootCommon::Save
if (clean)
{
BootCommon::RemoveUnexistentSections ("", "");
BootCommon::UpdateAppend ();
}
// check if there is selected "none" bootloader
string bl = BootCommon::getLoaderType (false);
if (bl == "none")
{
BootCommon::InitializeLibrary (init, bl);
return true;
}
if (! BootCommon::InitializeLibrary (init, "ppc"))
// send current disk/partition information to perl-Bootloader
BootCommon::SetDiskInfo ();
// convert
map<string,string> my_globals = mapmap (string k , string v, BootCommon::globals, {
if ((k == "stage1_dev") || (regexpmatch(k, "^boot_.*custom$" )))
return $[k : BootStorage::Dev2MountByDev(v)];
else
return $[k : v];
});
// FIXME: remove all mountpoints of type 'boot/boot' through some Storage::<func>
// FIXME: set one mountpoint 'boot/boot' for every boot target means all
// partitions in 'boot_<arch>_custom' and 'clone' (chrp)
// ret = ret && BootCommon::SetDeviceMap (device_mapping);
// bnc #450506 root=kernelname in lilo.conf after upgrade
BootCommon::sections = BootCommon::remapSections(BootCommon::sections);
ret = ret && BootCommon::SetSections (BootCommon::sections);
ret = ret && BootCommon::SetGlobal (my_globals);
if (flush)
ret = ret && BootCommon::CommitSettings ();
//importMetaData();
BootCommon::WriteToSysconf(false);
return ret;
}
/**
* Display bootloader summary
* @return a list of summary lines
*/
global define list<string> Summary () {
list<string> result = [];
// FIXME:
// - evaluate and use the text from iSeriesSummary(), PRePSummary() and
// CHRPSummary()
// - add the cases for mac_old and mac_new (see BootPPC::Summary())
// summary text, %1 is bootloader name
result = add(
result,
sformat(
_("Boot loader type: %1"),
BootCommon::getLoaderName (BootCommon::getLoaderType (false), `summary)
)
);
// summary text for boot loader locations, sum up all locations to one string
string boot_loader_locations =
mergestring(
filter( string bll,
maplist( string key, any value, BootCommon::global_options, {
return (substring(key,0,5) == "boot_")
? BootCommon::globals[key]:"" : "";
}),
{ return bll != ""; }
),
", "
);
result = add (result, sformat (_("Location: %1"), boot_loader_locations));
list<string> sects = [];
foreach (map<string,any> s, BootCommon::sections, {
string title = s["name"]:"";
// section name "suffix" for default section
string def = (title == BootCommon::globals["default"]:"")
? _(" (default)")
: "";
sects = add (sects, String::EscapeTags (sformat ("+ %1%2", title, def)));
});
// summary text. %1 is list of bootloader sections
result = add (result, sformat (_("Sections:<br>%1"),
mergestring (sects, "<br>")));
// FIXME: does the following code make any sense for ppc? (see also #163387)
// It seems not. (We do not do this, cf. jplack.) Keeping the code cadaver
// around until finally ready for removal.
// if (BootCommon::loader_device == "/dev/null")
// // summary text
// result = add (result,
// _("Do not install boot loader; just create configuration files"));
return result;
}
/**
* Update read settings to new version of configuration files
*/
global void Update () {
/**
* Firstly update sections of bootloader configuration and modify internal
* structures as needed. This means right now:
*
* - no change of "resume=" parameter in append entry, not used on ppc yet
* - delete console= parameters as console autodetection now works
*/
// This function has been copied from lilolike.ycp::UpdateSections and
// adapted to conform with the image parameter
// BootPOWERLILO.ycp/perl-Bootloader uses. Some unneeded code has been
// removed.
// FIXME: SLES9 -> SLES10 update: check loader_type = lilo in
// /etc/sysconfig/bootloader
// take current sections as starting point
list<map<string,any> > updated_sections = BootCommon::sections;
boolean linux_resume_added = false;
map<string,any> default_sect = CreateImageSection("linux");
string default_name = default_sect["name"]:"";
// assumption is that all of the following section names ar "good" names
// meaning that we will return a valid section description from
// CreateImageSection for them.
list<string> sections_to_recreate = ["linux"];
updated_sections = maplist (map<string,any> s, updated_sections, {
string name = s["name"]:"";
string oname = s["original_name"]:name;
// if we find a section that looks like it has been initially proposed
// from the installer, replace with the actual "good" proposal
if (contains(sections_to_recreate, oname)) {
sections_to_recreate = filter (string this_name,
sections_to_recreate, ``(this_name != oname)
);
// check for a new global default if oname != name
if ( name == BootCommon::globals["default"]:"" ) {
// we assume that the new name produced by CreateImageSection
// will be oname
BootCommon::globals["default"] = oname;
}
return CreateImageSection(oname);
}
// else adjust the entries of the found section according to some
// fancy rules
foreach (string key, ["image", "initrd"], {
string value = s[key]:"";
// FIXME: check whether this is code for update from SLES8?
// then we would delete it.
if (regexpmatch (value, "^.*\.shipped.*$"))
{
value = regexpsub (value,
"^(.*)\.shipped(.*)$", "\\1\\2");
}
else if (regexpmatch (value, "^.*\.suse.*$"))
{
value = regexpsub (value,
"^(.*)\.suse(.*)$", "\\1\\2");
}
s[key] = value;
});
// update root= entry in selected sections as the device naming
// changes in the linux kernel from time to time ...
if (contains (BootCommon::update_section_types, oname) && haskey(s, "root"))
{
y2milestone ("Updating root device of section %1", name);
s["root"] = BootCommon::UpdateDevice (s["root"]:"");
}
// handle the append line
string append = s["append"]:"";
// FIXME: how should we handle root= entries in append= lines?
// add additional kernel parameters to the end of the append entry
// of special image section 'linux'
//
if (oname == "linux") {
foreach (string o, BootCommon::ListAdditionalKernelParams (), {
append = BootCommon::setKernelParamToLine (append, o, "false");
});
append = append + " " + BootCommon::GetAdditionalKernelParams ();
if (BootCommon::getKernelParamFromLine (append, "splash") == "false")
append = BootCommon::setKernelParamToLine (append, "splash", "silent");
}
// remove console= entries from kernel parameters, console auto
// detection now works. For special sections take what's given on boot
// command line
string console = "false"; // false means delete to 'setKernelParamToLine'
if (contains (BootCommon::update_section_types, oname))
{
console = BootCommon::getKernelParamFromLine (Kernel::GetCmdLine(), "console") ;
}
append = BootCommon::setKernelParamToLine (append, "console", console);
// finally append entry is written back
if (append != "")
s["append"] = append;
else
s = remove(s, "append");
return s;
});
// if there was no original section matching the sections we want to
// recreate, so do prepend or append newly created sections to the list of
// updated sections
foreach (string section_name, sections_to_recreate, {
map<string,any> new_section = CreateImageSection(section_name);
if (section_name == "linux")
updated_sections = prepend (updated_sections, new_section);
else
updated_sections = add (updated_sections, new_section);
});
BootCommon::sections = updated_sections;
y2milestone("finished updating sections: %1", updated_sections);
// End of UpdateSections ();
/**
* Secondly update global settings of bootloader configuration:
*
* - no change of 'activate'
* - no change of 'timeout'
* - no change of default section
* - no change of default initrd
* - update device names that might have changed in as needed
* - delete console= parameters as console autodetection now works
*/
BootCommon::loader_device
= BootCommon::UpdateDevice (BootCommon::loader_device);
// update device naming of default root and boot_* entries
foreach (string key, ["root", "boot_prep_custom", "boot_chrp_custom",
"boot_iseries_custom","boot_pmac_custom", "clone"], {
if (haskey(BootCommon::globals, key)) {
y2milestone ("Updating global %1= setting, currently %2",
key, BootCommon::globals[key]:"");
BootCommon::globals[key] =
BootCommon::UpdateDevice (BootCommon::globals[key]:"");
}
});
// remove console= entries from globals, console auto detection now works
if (haskey (BootCommon::globals, "append")) {
string append = BootCommon::globals["append"]:"";
append = BootCommon::setKernelParamToLine (append, "console", "false");
if (append != "")
BootCommon::globals["append"] = append;
else
BootCommon::globals = remove(BootCommon::globals, "append");
}
}
/**
* Write bootloader settings to disk
* @return boolean true on success
*/
global define boolean Write () {
if (getBoardType () == "iseries")
{
iSeriesWrite ();
}
boolean ret = BootCommon::UpdateBootloader ();
ret = ret && BootCommon::InitializeBootloader ();
if (ret == nil)
ret = false;
return ret;
}
global map<string,symbol()> Dialogs () {
// PPC definitly needs other text modules
return $[
"loader" : PPCDetailsDialog,
];
}
/**
* Set section to boot on next reboot
* @param section string section to boot
* @return boolean true on success
*/
global define boolean FlagOnetimeBoot (string section)
{
map result = (map)SCR::Execute (.target.bash_output,
sformat ("/sbin/lilo -R \"%1\"", section));
y2milestone ("lilo returned %1", result);
return (result["exit"]:-1 == 0);
}
list<string> ppc_section_types(){
if (Arch::board_iseries()){
return ["image","other"];
}
return ["image"];
}
/**
* Return map of provided functions
* @return map map of functions (eg. $["write":BootPOWERLILO::Write])
*/
global map<string, any> GetFunctions () {
return $[
"export" : Export,
"import" : Import,
"read" : Read,
"reset" : Reset,
"propose" : Propose,
"save" : Save,
"summary" : Summary,
"update" : Update,
"write" : Write,
"widgets" : ppcWidgets,
"dialogs" : Dialogs,
"section_types" : ppc_section_types,
"flagonetimeboot" : FlagOnetimeBoot,
];
}
/**
* Initializer of PowerLILO bootloader
*/
global void Initializer () {
y2milestone ("Called PowerLILO initializer");
BootCommon::current_bootloader_attribs = $[
"propose" : true,
"read" : true,
"scratch" : true,
"bootloader_on_disk" : true,
];
BootCommon::InitializeLibrary (false, "ppc");
}
/**
* Constructor
*/
global void BootPOWERLILO () {
BootCommon::bootloader_attribs["ppc"] = $[
"required_packages" : ["lilo"],
"loader_name" : "ppc",
"initializer" : BootPOWERLILO::Initializer,
];
}
}
/*
* Local variables:
* mode: ycp
* mode: font-lock
* mode: auto-fill
* indent-level: 4
* fill-column: 78
* End:
*/
ACC SHELL 2018