ACC SHELL

Path : /proc/self/root/usr/share/YaST2/modules/
File Upload :
Current File : //proc/self/root/usr/share/YaST2/modules/Bootloader.ycp

/**
 * 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