ACC SHELL

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

/**
 * File:
 *      modules/BootELILO.ycp
 *
 * Module:
 *      Bootloader installation and configuration
 *
 * Summary:
 *      Module containing specific functions for ELILO configuration
 *      and installation
 *
 * Authors:
 *      Joachim Plack <jplack@suse.de>
 *      Jiri Srain <jsrain@suse.cz>
 *      Andreas Schwab <schwab@suse.de>
 *      Olaf Dabrunz <od@suse.de>
 *      Philipp Thomas <pth@suse.de>
 *
 * $Id: BootELILO.ycp 61352 2010-03-16 16:33:37Z juhliarik $
 *
 */

{

// FIXME paths will be probably changed because of bugzilla 21644

module "BootELILO";

textdomain "bootloader";

import "BootArch";
import "BootCommon";
import "BootStorage";
import "Installation";
import "Kernel";
import "Mode";
import "Report";
import "Stage";
import "Storage";
import "String";
import "Arch";

include "bootloader/elilo/helps.ycp";
include "bootloader/routines/popups.ycp";
include "bootloader/elilo/dialogs.ycp";



// private variables

/**
  * Name of EFI entry when read settings
  */
global string old_efi_entry = nil;

/**
  * elilo.conf path
  */
global string elilo_conf_filename = "/boot/efi/SuSE/elilo.conf";

/**
  * True if EFI entry should be recreated
  */
global boolean create_efi_entry = true;

string efi_vendor = "SuSE";

/**
 * bnc #450682 - adding boot entry to EFI
 * true is label was added
 */

global boolean added_label_to_efi = false;

/**
 * Is the /sys/firmware/efi directory available?
 */
boolean efi_available = true;


include "bootloader/elilo/widgets.ycp";

// misc. functions

/**
  * Return mountpoint of partition holding EFI data
  * @return mountpoint if partition holding EFI data
  */
global define string getEfiMountPoint () {
    string mountpoint = "/";
    // FIXME: UGLY HACK because of testsuites
    map mountpoints = $[];
    if (Mode::test ())
        mountpoints = $["/" : ["/dev/hda2"], "/boot" : ["/dev/hda1"]];
    else
        mountpoints = Storage::GetMountPoints();
    if (haskey (mountpoints, "/boot/efi"))
    {
        mountpoint = "/boot/efi";
    }
    else if (haskey (mountpoints, "/boot"))
    {
        mountpoint = "/boot";
    }
    y2milestone ("Mountpoint of EFI: %1", mountpoint);
    return mountpoint;
}


/**
  * Get directory containing elilo.conf relative to EFI partition's root
  * @return directory containing elilo.conf relative to EFI root
  */
global define string getEliloConfSubdir () {
    return sformat ("/efi/%1", efi_vendor);
}


/**
  * Get path of elilo.conf relative to EFI partition's root
  * @return string path of elilo.conf relative to EFI partition's root
  */
global define string getEliloConfSubpath () {
    return sformat ("%1/elilo.conf", getEliloConfSubdir ());
}


/**
  * Return path to elilo.conf file
  * @return string path to elilo.conf
  */
global define string getEliloConfFilename () {
    // FIXME config file name location should be read from Library
    //  and it should not be needed here!!!
    string ret = sformat ("%1/efi/%2/elilo.conf", getEfiMountPoint (),
        efi_vendor);
    y2milestone ("elilo.conf sould be located at %1", ret);
    return ret;
}

// wrapper function to adjust to new grub name sceme
map<string,any> CreateLinuxSection (string title) {
    map<string,any> section =
      BootCommon::CreateLinuxSection (title);

    // don't translate label bnc #151486
    section["description"] = section["name"]:"";
    section["name"] = title;

    return section;
}



/**
 * Propose sections to bootloader menu
 * modifies internal structures
 */
global void CreateSections () {
    map<string,any> linux = CreateLinuxSection ("linux");
    map<string,any> failsafe = CreateLinuxSection ("failsafe");

    // bnc#588609 - Problems writing elilo
    map<string,any> xen = $[];
    if (BootCommon::XenPresent ())
       xen = CreateLinuxSection ("xen");

    // append for default section is in global
    // FIXME do it later
    //    if (haskey (linux, "append"))
    //  	linux = remove (linux, "append");
    if ((xen != nil) && (size(xen) >0))
       BootCommon::sections = [ linux, failsafe, xen ];
    else
       BootCommon::sections = [ linux, failsafe ];
}


/**
 * Propose global options of bootloader
 * modifies internal structures
 */
global void CreateGlobals () {
    BootCommon::globals = $[
    // FIXME do it later
    //	"append" : BootArch::DefaultKernelParams (""),
	"default" : "linux",
	"timeout" : "8",
	"prompt" : "true",
    // bnc #438276 - no 'read-only'
	"relocatable" : "true"
    ];

}


// general functions


/**
  * Export bootloader settings to a map
  * @return bootloader settings
  */
global define map Export () {
    map ret = BootCommon::Export ();
    ret["old_efi_entry"] = old_efi_entry;
    ret["elilo_conf_filename"] = elilo_conf_filename;
    ret["create_efi_entry"] = create_efi_entry;
    return ret;
}


/**
  * Import settings from a map
  * @param settings map of bootloader settings
  */
global define boolean Import (map settings) {
    BootCommon::Import (settings);
    old_efi_entry = (string) (settings["old_efi_entry"]:nil);
    elilo_conf_filename = getEliloConfFilename ();
    create_efi_entry
        = settings["create_efi_entry"]:(settings["location"]:"" != "");
    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 define boolean Read (boolean reread, boolean avoid_reading_device_map) {
	import "Product";
	boolean efi_entry_found = false;
	elilo_conf_filename = getEliloConfFilename ();
	// copy old elilo.conf from /boot/<something> to /etc in case of upgrade
	// (if /etc/elilo.conf doesn't exist)
	if (SCR::Read (.target.size, "/etc/elilo.conf") <= 0
	    && SCR::Read (.target.size, elilo_conf_filename) > 0)
	{
	    SCR::Execute (.target.bash, sformat (
		"/bin/cp %1 /etc/elilo.conf", elilo_conf_filename));
	}
	SCR::Execute (.target.bash, "/bin/touch /etc/elilo.conf");
	BootCommon::DetectDisks ();
	boolean ret = BootCommon::Read (reread, avoid_reading_device_map);

	// check for meaningless EFI entry name in sysconfig
	if ( !haskey(BootCommon::globals,"boot_efilabel")
	    || BootCommon::globals["boot_efilabel"]:"" == "mbr"
	    || BootCommon::globals["boot_efilabel"]:"" == ""
	    || BootCommon::globals["boot_efilabel"]:"" == nil )
	{
	    string efi_path = String::Replace(
		getEliloConfSubpath (), "/", "\\");
	    // Read Firmware setting from NVRam
	    map efi_status = (map)SCR::Execute (.target.bash_output, sformat (
		"/usr/sbin/efibootmgr |grep \"%1\"", efi_path));
	    if (efi_status["exit"]:0 != 0)
	    {
		BootCommon::globals["boot_efilabel"] = Product::name;
	    }
	    else
	    {
		string output = efi_status["stdout"]:"";
		list lines = splitstring (output, "\n");
		output = lines[0]:"";
		if (regexpmatch (output, "Boot.*\* (.*)  HD"))
		{
		    BootCommon::globals["boot_efilabel"]
			= regexpsub (output, "Boot.*\* (.*)  HD", "\\1");
		    efi_entry_found = true;
		}
		else
		{
		    BootCommon::globals["boot_efilabel"] = Product::name;
		}
	    }
	}
	else
	{
	    efi_entry_found = 0 == SCR::Execute (.target.bash, sformat (
		"/usr/sbin/efibootmgr |grep \"%1\"",
		BootCommon::globals["boot_efilabel"]:"")
	    );
	}
	create_efi_entry = !efi_entry_found;
	old_efi_entry = efi_entry_found
	    ? BootCommon::globals["boot_efilabel"]:""
	    : (string)nil;
	return ret;
}


/**
  * Reset bootloader settings
  */
global define void Reset (boolean init) {
    if (Mode::autoinst ())
        return;
    create_efi_entry = true;
    BootCommon::Reset(init);
}


/**
  * Propose bootloader settings
  */
global define void Propose () {
    import "Product";
    if (! BootCommon::was_proposed)
    {
        create_efi_entry = true;
	// make sure the code handling globals below triggers and that
	// boot_efilabel is recreated
	if ( haskey(BootCommon::globals, "boot_efilabel") )
	    BootCommon::globals = remove(BootCommon::globals, "boot_efilabel");
    }
    if (! Stage::initial ())
        create_efi_entry = true;
    if (Mode::update ())
        create_efi_entry = false;
    efi_available = 0 == (integer)SCR::Execute (.target.bash, "test -d /sys/firmware/efi");
    if (! efi_available)
	create_efi_entry = false;
    elilo_conf_filename = getEliloConfFilename ();
    BootCommon::DetectDisks ();
    BootCommon::del_parts = BootStorage::getPartitionList (`deleted, "elilo");

    if (BootCommon::sections == nil || size (BootCommon::sections) == 0)
    {
        CreateSections ();
        BootCommon::kernelCmdLine = Kernel::GetCmdLine ();
    }
    else
    {
        if (Mode::autoinst ())
        {
	    y2debug ("Nothing to do for propose in AI mode");
        }
        else
	BootCommon::FixSections (BootELILO::CreateSections);
    }

    if (BootCommon::globals == nil || size (BootCommon::globals) == 0)
    {
        CreateGlobals ();
    }

    if (BootCommon::globals["boot_efilabel"]:nil == nil ||
	BootCommon::globals["boot_efilabel"]:nil == "")
    {
	BootCommon::globals["boot_efilabel"] = Product::name;
    }

    if (Mode::installation())
	BootCommon::UpdateProposalFromClient();

    y2milestone ("EFI entry name: %1", BootCommon::globals["boot_efilabel"]:"");
    y2milestone ("Proposed sections: %1", BootCommon::sections);
    y2milestone ("Proposed globals: %1", BootCommon::globals);
}


/**
 * Save all bootloader configuration files
 * @return boolean true if success
 */
global boolean Save (boolean clean, boolean init, boolean flush) {
    boolean ret = BootCommon::Save (clean, init, flush);
    return ret;
}


/**
  * Display bootloader summary
  * @return a list of summary lines
  */
global define list<string> Summary () {
    // summary text, %1 is bootloader name (eg. LILO)
    list<string> result = [ sformat (_("Boot loader type: %1"),
        BootCommon::getLoaderName (BootCommon::getLoaderType (false), `summary)) ];

    if (BootCommon::globals["boot_efilabel"]:"" == "" || !create_efi_entry )
    {
        result =
	    // summary text
	    add (result, _("Do Not Create EFI Boot Manager Entry"));
    }
    else
    {
        result = add (result, sformat (
	// summary text, %1 is label of the entry of EFI boot manager
	_("Create EFI Boot Manager Entry %1"),
	BootCommon::globals["boot_efilabel"]:""));
    }
    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>")));
    return result;
}


/**
 * Update read settings to new version of configuration files
 */
global define void Update () {
    /*
     * Update global options of bootloader
     * modifies internal structures
     */
    if (BootCommon::globals["timeout"]:"" == "")
        BootCommon::globals["timeout"] = "8";
    BootCommon::globals["append"] = BootArch::DefaultKernelParams ("");

    BootCommon::UpdateSections ();
    // FIXME EFI entry name
}


/**
  * Install the bootloader, display a popup with log if something
  *  goes wrong
  * @param command string command to install the bootloader
  * @param logfile string filename of file used to write bootloader log
  * @return boolean true on success
  */
// FIXME get rid of this function
define boolean installBootLoader (string command, string logfile) {
    y2milestone ("Running command %1", command);
    map exit = (map)SCR::Execute (.target.bash_output, command);
    boolean ret = 0 == exit["exit"]:1;
    if (! ret)
    {
        y2milestone ("Exit code of %1: %2", command, exit["exit"]:-1);
        string log = (string)SCR::Read (.target.string, logfile);
        log = log + exit["stdout"]:"" + exit["stderr"]:"";
        if (exit["exit"]:1 == 139)
        {
            // means: process received signal SIGSEGV
            // please, use some usual translation
            // proofreaders: don't change this text
            log = log + _("Segmentation fault");
        }

        errorWithLogPopup (sformat (
            // error popup - label, %1 is bootloader name
            _("Error Occurred while Installing %1"),
            BootCommon::getLoaderName (BootCommon::getLoaderType (false), `summary)), log);
    } else {
	added_label_to_efi = true;
	y2milestone("Adding label to EFI finish successful");
    }
    return ret;
}

/** bnc #438215 - YaST creates efibootloader entry twice
 * Function convert number of partition to hexa
 * 
 * @param any number of boot partition (10 or "10")
 * @return string number boot partition in hexa ("a") - without "0x"
 */
string tomyhexa(any boot_part)
{
        string ret = "1000";

        integer int_boot_part = tointeger(boot_part);
        if (int_boot_part != nil)
        {
                string hexa = tohexstring(int_boot_part);
                if (search(hexa, "x")!= nil)
                {
                        list <string> hexa_without_0x = splitstring(hexa, "x");
                        if (size(hexa_without_0x)>1)
                                ret = hexa_without_0x[1]:"1000";
                }
        }
        return ret;
}


/** bnc #269198 change efi-label
 * Function check if there exist same efi-label or different for
 * same partition if efi-label is different delete it and create new one
 * if it is same nothing to do it.
 */

boolean updateEFILabel()
{
	boolean ret = true;
	string cmd = "";
	map mp = Storage::GetMountPoints();
	string boot_dev = mp[getEfiMountPoint (), 0]:"/boot/efi";
	map splited = Storage::GetDiskPartition (boot_dev);
	any boot_part = splited["nr"]:0;
	any boot_disk = splited["disk"]:"";
	
	
	// command for checking same boot entry in efi bnc #438215 (YaST creates efibootloader entry twice)
	cmd = sformat("/usr/sbin/efibootmgr -v | grep -c \"%1.*HD(%2.*File(.\\efi.\\SuSE.\\elilo.efi)\"",
		BootCommon::globals["boot_efilabel"]:"", tomyhexa(boot_part));

	// check how many entries with same label and partition is actually in efi
	y2milestone("run command %1", cmd);
	map out = (map)SCR::Execute (.target.bash_output, cmd);
	y2milestone("output of command %1", out);

	// check number of same boot entries in efi
	// if boot entry is added -> don't add it again
	if (deletechars(out["stdout"]:"","\n") != "0")
	{
		if (out["exit"]:0 == 0)
			y2milestone("Skip adding new boot entry - EFI Label exist");
		else
			y2error("Calling command %1 faild", cmd);
		return ret;

	} else {

		cmd = sformat("/usr/sbin/efibootmgr -v | grep -c \"HD(%1.*File(.\\efi.\\SuSE.\\elilo.efi)\"", tomyhexa(boot_part));
		// check how many entries with same label and partition is actually in efi
		y2milestone("run command %1", cmd);
		map out = (map)SCR::Execute (.target.bash_output, cmd);
		y2milestone("output of command %1", out);

		// check how many boot entries have same number of partitions
		if (deletechars(out["stdout"]:"","\n") != "0")
		{
			// delete old boot entry

			cmd = sformat("efibootmgr -v |grep \"HD(%1.*File(.\\efi.\\SuSE.\\elilo.efi)\" | cut -d \" \" -f 1",
				tomyhexa(boot_part));
			y2milestone("run command %1", cmd);
           		out = (map)SCR::Execute (.target.bash_output, cmd);
			y2milestone("output of command %1", out);

           		string boot_entries = out["stdout"]:"";
           		y2milestone("EFI boot entries with \"same\" boot partition %1",boot_entries);

           		list<string> list_boot_entries = splitstring(boot_entries, "\n");

           		y2milestone("list_boot_entries=%1",list_boot_entries);

			foreach(string entry, list_boot_entries,
			{
				if ((deletechars(entry, "\n*") != "") && (deletechars(entry, "\n*") != nil))
				{
					cmd = sformat("/usr/sbin/efibootmgr --delete-bootnum --bootnum %1 -q;", 
						substring (deletechars(entry, "\n*"),4, 4));
					y2milestone("run command %1", cmd);
           				out = (map)SCR::Execute (.target.bash_output, cmd);
					y2milestone("output of command %1", out);
				}
			});
			
		}
		// add new boot entry
		string bl_logfile = "/var/log/YaST2/y2log_bootloader";
	    	string bl_command = sformat ( "/usr/sbin/efibootmgr -v --create --label \"%1\" " +
			"--disk %2 --part %3 " +
			"--loader '\\efi\\SuSE\\elilo.efi' --write-signature >> %4 2>&1",
			BootCommon::globals["boot_efilabel"]:"", boot_disk, boot_part, bl_logfile
		);
		ret = ret && installBootLoader (bl_command, bl_logfile);
	}
	return ret;
}

/** FIXME: efibootmgr doesn't provide info about disk!
 * bnc #450682 - adding boot entry to EFI
 * function delete all existing boot entry with same name and partition number
 * @param string name of label
 * @param string number of partition
 */

void deleteSameEFIBootEntry(string name, any part_no)
{

    boolean still_exist = true;

    string cmd = sformat("efibootmgr -v |grep \"%1.*HD(%2.*File(.\\efi.\\SuSE.\\elilo.efi)\" | cut -d \" \" -f 1",
		name, tomyhexa(part_no));
    y2milestone("run command %1", cmd);
    map out = (map)SCR::Execute (.target.bash_output, cmd);
    y2milestone("output of command %1", out);

    string boot_entries = out["stdout"]:"";
    y2milestone("EFI boot entries with \"same\" boot partition %1",boot_entries);

    list<string> list_boot_entries = splitstring(boot_entries, "\n");

    y2milestone("list_boot_entries=%1",list_boot_entries);

    foreach(string entry, list_boot_entries,
    {
	if ((deletechars(entry, "\n*") != "") && (deletechars(entry, "\n*") != nil))
	{
	cmd = sformat("/usr/sbin/efibootmgr --delete-bootnum --bootnum %1 -q;", 
		substring (deletechars(entry, "\n*"),4, 4));
		y2milestone("run command %1", cmd);
      		out = (map)SCR::Execute (.target.bash_output, cmd);
		y2milestone("output of command %1", out);
	}
    });
}

/**
  * Write bootloader settings to disk
  * @return boolean true on success
  */
global define boolean Write () {

    y2milestone("run Write function from BootELILO");
    //	SCR::Execute (.target.bash, "/sbin/elilo");
    boolean ret = BootCommon::UpdateBootloader ();
    if (ret == nil)
	ret = false;

// FIXME find a better way to report status
    if (ret && ! efi_available) {
	Popup::TimedMessage(
_("System was not booted via EFI firmware. To boot your
computer, you need to load ELILO via the EFI shell."), 10);
    }

    if (Mode::normal())
	updateEFILabel();

    if (BootCommon::location_changed || create_efi_entry)
    {
	map mp = Storage::GetMountPoints();
	string boot_dev = mp[getEfiMountPoint (), 0]:"/boot/efi";
	map splited = Storage::GetDiskPartition (boot_dev);
	any boot_part = splited["nr"]:0;
	any boot_disk = splited["disk"]:"";
	y2milestone ("Disk: %1, Part: %2", boot_disk, boot_part);

	/*
	 * Create new EFI Bootmgr Label if specified
	 */
	if (BootCommon::globals["boot_efilabel"]:"" != "")
	{
	    string bl_logfile = "/var/log/YaST2/y2log_bootloader";
	    string bl_command = sformat (
		"/usr/sbin/efibootmgr -v --create --label \"%1\" " +
		"--disk %2 --part %3 " +
		"--loader '\\efi\\SuSE\\elilo.efi' --write-signature >> %4 2>&1",
		BootCommon::globals["boot_efilabel"]:"", boot_disk, boot_part, bl_logfile
	    );

	    // command for checking same boot entry in efi bnc #438215 (YaST creates efibootloader entry twice)
	    string cmd = sformat("/usr/sbin/efibootmgr -v | grep -c \"%1.*HD(%2.*File(.\\efi.\\SuSE.\\elilo.efi)\"",
		BootCommon::globals["boot_efilabel"]:"", tomyhexa(boot_part));
	    y2milestone("Command for checking same boot entry: %1", cmd);

	    // check how many entries with same label and partition is actually in efi
	    map out = (map)SCR::Execute (.target.bash_output, cmd);

	    // check number of same boot entries in efi
	    // if boot entry is added -> don't add it again
	    if (deletechars(out["stdout"]:"","\n") == "0")
	    {
	    	ret = ret && installBootLoader (bl_command, bl_logfile);
	    } else {

		if (added_label_to_efi)
		{
		    y2milestone("Skip adding boot entry: %1 to EFI. There already exist and was added: %2 with 
				same label and partition.", BootCommon::globals["boot_efilabel"]:"",
				deletechars(out["stdout"]:"","\n"));
		} else {
		    // delete efi entry with same label name and partition
		    deleteSameEFIBootEntry(BootCommon::globals["boot_efilabel"]:"", boot_part);
		    // add new efi boot entry
		    ret = ret && installBootLoader (bl_command, bl_logfile);
		}
		
	    }
	}


	/*
         * Remove existing old, obsolete menu entries
	 *
	 * FIXME should be handled completly through the library
	 */

	// Detect the current default boot entry (e.g. "0007")
	map default_entry_map = (map)SCR::Execute (.target.bash_output,
	    "/usr/sbin/efibootmgr |grep ^BootOrder: | " +
	    "cut -d ' ' -f 2 | cut -d ',' -f 1"
	);
	string new_entry = default_entry_map["stdout"]:"";

	// Check for validity -- returned default_entry has to be 4 chars long
	// and be composed of numbers and characters only
	if (size (new_entry) != 4
	    && regexpmatch (new_entry, "[0-9A-F]") == false)
	{
	    y2error ("BootELILO: Found default boot entry %1 isn't valid",
		    new_entry);
	}
	else
	{
	    // Remove newlines and carriage returns in string
	    new_entry = deletechars (new_entry, "\n\r");

	    // Attach prefix "Boot" for proper matching
	    new_entry = "Boot" + new_entry;

	    // Prepare command for fetching string "HD(...)"
	    // from efibootmgr output
	    string command = sformat (
		"set -o pipefail; /usr/sbin/efibootmgr -v | " +
		"grep '%1' |sed 's/%1.*\\(HD(.*)File(.*)\\).*/\\1/'",
		String::Quote (new_entry)
	    );

	    map hd_descr_map = (map)SCR::Execute (.target.bash_output, command);
	    y2milestone ("BootELILO: hd_descr_map = %1", hd_descr_map);

	    // Remove newlines and carriage returns in string
	    string hd_descr = deletechars (hd_descr_map["stdout"]:"", "\n\r");

	    // Prepare command for fetching boot entry number corresponding
	    // to "HD(...)" string from efibootmgr output
	    command = sformat (
		"set -o pipefail; /usr/sbin/efibootmgr -v |" +
		"grep '%1' |awk '{print $1}'",
		String::Quote (hd_descr)
	    );

	    map entries2remove_map = (map)SCR::Execute (.target.bash_output, command);
	    y2milestone ("BootELILO: entries2remove_map = %1", entries2remove_map);
	    string entries2remove_string = entries2remove_map["stdout"]:"";

	    // Convert the string containing the entries to be removed to a list
	    list<string> entries2remove_list = splitstring (entries2remove_string, "\n");

	    // Check if there are entries to remove, thus if listsize is greater than 0
	    integer listsize = size (entries2remove_list);
	    if (listsize > 0)
	    {
		// Rermove the last entry of the list (because it's an empty one)
		integer lastentry = listsize - 1;
		entries2remove_list = remove (entries2remove_list, lastentry);
		y2milestone ("BootELILO: entries2remove_list = %1", entries2remove_list);

		// Filter the bootnumbers from strings for further usage
		entries2remove_list = maplist (string entry2remove, entries2remove_list, {
		    if (issubstring (entry2remove, new_entry) == false)
		    {
			entry2remove = substring (entry2remove, 4, 4);
			return entry2remove;
		    }
		});

		// Delete obsolete bootentries by bootnumbers
		foreach (string entry2remove, entries2remove_list, {
		    string command = sformat (
			"/usr/sbin/efibootmgr --delete-bootnum --bootnum %1 -q;",
			entry2remove
		    );

		    y2milestone ("Running command %1", command);
		    map ret_map = (map)SCR::Execute (.target.bash_output, command);
		    y2milestone ("BootELILO: ret_map = %1", ret_map);
		    ret = (ret_map["exit"]:1 == 0);
		});
	    }
	    else
	    {
		y2milestone ("BootELILO: No obsolete entry to remove");
	    }
	}
    }
    return ret;
}


global map<string,symbol()> Dialogs () {
    return $[
	"loader"	: EliloLoaderDetailsDialog,
    ];
}

/**
  * Set section to boot on next reboot.
  * @param section string section to boot
  * @return boolean true on success
  */
global define boolean FlagBootDefaultOnce (string section) {
	/* For now a dummy */
	return true;
}

list <string> elilo_section_types()
{
	return ["image", "xen"];
}

/**
  * Return map of provided functions
  * @return a map of functions (eg. $["write"::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"		: Widgets,
        "dialogs"		: Dialogs,
        "section_types"		: elilo_section_types,
	"flagbootdefaultonce"	: FlagBootDefaultOnce,
    ];
}

/**
 * Initializer of ELILO bootloader
 */
global void Initializer () {
    y2milestone ("Called ELILO initializer");
    BootCommon::current_bootloader_attribs = $[
        "propose" : true,
        "read" : true,
        "scratch" : true,
        "restore_mbr" : true,
        "bootloader_on_disk" : true,
    ];

    BootCommon::InitializeLibrary (false, "elilo");
}

/**
 * Constructor
 */
global define void BootELILO () {
    BootCommon::bootloader_attribs["elilo"] = $[
	"required_packages" : ["elilo", "efibootmgr"],
	"loader_name" : "ELILO",
	"initializer" : BootELILO::Initializer,
    ];
}

} // EOF

/*
 * Local variables:
 *     mode: ycp
 *     mode: font-lock
 *     mode: auto-fill
 *     indent-level: 4
 *     fill-column: 78
 * End:
 */

ACC SHELL 2018