ACC SHELL

Path : /usr/share/YaST2/include/bootloader/routines/
File Upload :
Current File : //usr/share/YaST2/include/bootloader/routines/misc.ycp

/**
 * File:
 *      include/bootloader/routines/misc-common.ycp
 *
 * Module:
 *      Bootloader installation and configuration
 *
 * Summary:
 *      Miscelaneous functions for bootloader configuration and installation
 *
 * Authors:
 *      Jiri Srain <jsrain@suse.cz>
 *      Olaf Dabrunz <od@suse.de>
 *
 * $Id: misc.ycp 61035 2010-02-26 09:20:36Z juhliarik $
 *
 * WARNING:
 *      To be included to BootCommon.ycp only, requires function
 *      getLoaderType to avoid include-import cycle
 *      Use import "BootCommon" instead.
 */



{

    textdomain "bootloader";
    import "Mode";
    import "Stage";

    import "Storage";
    import "StorageDevices";
    import "Report";
    import "Kernel";
    import "Misc";
    import "ProductFeatures";
    import "Directory";
    import "Installation";
    import "FileUtils";
    import "String";
    import "FileUtils";

// bootloader attributes handling functions

    global map<string, integer> Md2Partitions (string md_device);
    global void DetectDisks ();
    global string getBootPartition();
    

    /**
      * return printable name of bootloader
      * @param bootloader string bootloader type internal string
      * @param mode symbol `combo or `summary (because of capitalization)
      * @return string printable bootloader name
      */
    global define string getLoaderName (string bootloader, symbol mode) ``{
	if (bootloader == "none")
	{
	    return mode == `summary
		// summary string
		? _("Do not install any boot loader")
		// combo box item
		: _("Do Not Install Any Boot Loader");
	}
	if (bootloader == "default")
	{
	    return mode == `summary
		// summary string
		? _("Install the default boot loader")
		// combo box item
		: _("Install Default Boot Loader");
	}
	string fallback_name = mode == `summary
	    // summary string
	    ? _("Boot loader")
	    // combo box item
	    : _("Boot Loader");
	// fallback bootloader name, keep short
	return bootloader_attribs[bootloader, "loader_name"]:fallback_name;
    }

    /**
      * Get value of specified boolean bootloader attribute
      * @param attrib string attribute name
      * @return boolean value of attribute
      */
    global define boolean getBooleanAttrib (string attrib) ``{
	return current_bootloader_attribs[attrib]:false;
    }

    /**
      * Get value of specified bootloader attribute
      * @param attrib string attribute name
      * @param defaultv any default value of the attribute (if not found)
      * @return any value of attribute
      */
    global define any getAnyTypeAttrib (string attrib, any defaultv) ``{
        return current_bootloader_attribs[attrib]:defaultv;
    }

// other misc functions



    /**
      * Update the text of countdown widget
      * @param bootloader string printable name of used bootloader
      */
    global define void updateTimeoutPopupForFloppy (string bootloader) ``{
	if (Mode::normal ())
	    return;

        string confirm_boot_msg = Misc::boot_msg;
        // data saved to floppy disk
        string msg = sformat (
            // popup, %1 is bootloader name
            _("The %1 boot sector has been written to the floppy disk."),
            bootloader);
        msg = msg + "\n";
	// always hard boot
        // If LILO was written on floppy disk and we need
        // to do a hard reboot (because a different kernel
        // was installed), tell the user to leave the floppy
        // inserted.
        msg = msg
            // popup - continuing
            + _("Leave the floppy disk in the drive.");

        if ( size (confirm_boot_msg) > 0 )
        {
            msg = msg + "\n" + confirm_boot_msg;
        }
        Misc::boot_msg = msg;
    }


/**
 * Function remap globals settings "boot_custom" device name (/dev/sda) 
 * or to label (ufo_partition)
 * @param map<string,string> globals
 * @return map<string,string> globals
 */

global map<string,string> remapGlobals(map<string,string> globals_set)
{	
	symbol by_mount = nil;
	if (Arch::ppc())
	    by_mount = `id;
        else
	    by_mount = Storage::GetDefaultMountBy();

	//by_mount = `id;
	if (by_mount == `label)
		return globals_set;

	if (haskey(globals_set, "boot_custom"))
	{
		globals_set["boot_custom"] = BootStorage::MountByDev2Dev(globals_set["boot_custom"]:"");
	}

	if (haskey(globals_set, "boot_chrp_custom"))
	{
		globals_set["boot_chrp_custom"] = BootStorage::MountByDev2Dev(globals_set["boot_chrp_custom"]:"");
	}

	if (haskey(globals_set, "boot_pmac_custom"))
	{
		globals_set["boot_pmac_custom"] = BootStorage::MountByDev2Dev(globals_set["boot_pmac_custom"]:"");
	}
	
	if (haskey(globals_set, "boot_iseries_custom"))
	{
		globals_set["boot_iseries_custom"] = BootStorage::MountByDev2Dev(globals_set["boot_iseries_custom"]:"");
	}

	if (haskey(globals_set, "boot_prep_custom"))
	{
		globals_set["boot_prep_custom"] = BootStorage::MountByDev2Dev(globals_set["boot_prep_custom"]:"");
	}
	return globals_set;
}

/**
 * Function remap "resume" from section (append) to device name (/dev/sda) 
 * or to label (ufo_partition)
 *
 * @param map<string,any> sections
 * @param boolean true if convert resume to persistent device name
 * @return map<string,any> sections
 */

define string remapResume(string append, boolean to_persistent)
{
	if ((search(append, "resume")!=nil) && (search(append, "noresume") == nil))
	{
		y2milestone("append before remapping resume: %1", append);
		list <string> list_append = splitstring (append, " ");
		y2debug("split append to list list_append: %1", list_append);
		list <string> new_append = [];

		foreach(string key, list_append,
		{
			if (search(key,"resume") != nil)
			{
				y2debug("arg resume from append: %1",key);
				list <string> resume_arg = splitstring(key, "=");
				string dev = resume_arg[1]:"";
				y2debug("value of resume: %1",resume_arg[1]:"");
				if (dev != "")
				{
					string resume ="";
					// bnc#533782 - after changing filesystem label system doesn't boot 
					if (to_persistent)
						resume = "resume="+BootStorage::Dev2MountByDev(dev);
					else
						resume = "resume="+BootStorage::MountByDev2Dev(dev);
					y2debug("remap resume: %1",resume);
					new_append = add(new_append, resume);
				} else {
					y2debug("adding key to new append_list: %1", key);
					new_append = add(new_append, key);
				}
			} else {
				y2debug("adding key to new append_list: %1", key);
				new_append = add(new_append, key);
			}
		});

		y2debug("NEW append list: %1", new_append);
		string ret = mergestring(new_append, " ");
		y2milestone("Append after remaping: %1", ret);
		return ret;

	} else {
		y2milestone("Section hasn't resume...");
		return append;
	}
}

/**
 * Function remap section "root" and "resume" to device name (/dev/sda) 
 * or to label (ufo_partition)
 * it also prepared measured files for export
 * @param list<map<string,any> > list of sections
 * @return list<map<string,any> > list of sections
 */

global list<map<string,any> > remapSections(list<map<string,any> >sec)
{	
	symbol by_mount = nil;
	if (Arch::ppc())
	    by_mount = `id;
        else
	    by_mount = Storage::GetDefaultMountBy();

	//by_mount = `id;
	if (by_mount == `label)
		return sec;

	list<map<string,any> >temp_sec = [];
	
	// convert root and resume device names in sections to kernel device names
	temp_sec = maplist (map<string,any> s, sections, 
	{
		
		if (s["root"]:"" != "")
		{
			string rdev = s["root"]:"";
			s["root"] = BootStorage::MountByDev2Dev(rdev);

			if (s["append"]:"" != "")
				s["append"] = remapResume(s["append"]:"", false);
		
			y2debug("remapping root: %1 from section to: %2 ",rdev ,s["root"]:"");
		}

		if (s["chainloader"]:"" != "")
			s["chainloader"] = BootStorage::MountByDev2Dev(s["chainloader"]:"");

		return s;
	});

	return temp_sec;
}



    /**
      * returns true if char is blank (newline, tab or space)
      * @param s single char string
      * @return boolean blank/non blank
      */
    global define boolean isBlank(string s) ``{
	if (s == "\n" || s == "\t" || s == " ")
	{
	    return true;
	}
	return false;
    }

    /**
      * returns list difference A \ B (items that are in A and are not in B)
      * @param a list A
      * @param b list B
      * @return list see above
      */
    list difflist(list a, list b) ``{
	return filter(any e, a, ``(!contains(b, e)));
    }

    /**
      * translate filename path (eg. /boot/kernel) to list of device
      *  and relative path
      * @param fullpth string fileststem path (eg. /boot/vmlinuz)
      * @return a list containing device and relative path,
      *  eg. ["/dev/hda1", "/vmlinuz"]
      */
    global define list<string> splitPath (string fullpth) ``{
// UGHLY HACK because of testsuites
	map<string,list> mountpoints = $[];
	if (Mode::test ())
	    mountpoints = $["/" : ["/dev/hda2"], "/boot" : ["/dev/hda1"]];
	else
	    mountpoints = (map<string,list>)Storage::GetMountPoints();
	string dev = "";
	string mp = "";
	integer max = 0;
	//
	// FIXME: this is broken code, implement a proper prefix match!! see below
	foreach (string k, list v, mountpoints, ``{
	    if (k != "swap" && issubstring (fullpth, k) && size (k) > max)
	    {
	        max = size (k);
	        dev = v[0]:"";
	        mp = k;
	    }
	});
	if (mp == "")
	    return [];

	// FIXME: pth will be wrong for fullpth=='(hd0,1)/boot/vmlinux' !!
	string pth = substring (fullpth, size (mp));
	if (substring (pth, 0, 1) != "/")
	    pth = "/" + pth;
	return [dev, pth];
    }

    /**
      * Get bootloader device for specified location
      * FIXME: this function is being phased out. Keeping it around until
      * selected_location and loader_device can be dropped for all bootloader
      * types.
      * @return string device name
      */
    global define string GetBootloaderDevice () ``{
        if (BootCommon::selected_location == "mbr")
            return BootCommon::mbrDisk;
        if (BootCommon::selected_location == "boot")
	    return BootStorage::BootPartitionDevice;
        if (BootCommon::selected_location == "root")
	    return  BootStorage::RootPartitionDevice;
        if (BootCommon::selected_location == "floppy")
            return StorageDevices::FloppyDevice();
        if (BootCommon::selected_location == "mbr_md")
	    return "mbr_md";
	if (BootCommon::selected_location == "none")
	    return "/dev/null";
        return BootCommon::loader_device;
    }

    /**
      * Get list of bootloader device names for all selected or specified
      * locations
      * @return list device names
      */
    global define list<string> GetBootloaderDevices () ``{
	list<string> ret = [];
	if (BootCommon::globals["boot_boot"]:"false" == "true") {
	    ret = add(ret, BootStorage::BootPartitionDevice);
	}
	if (BootCommon::globals["boot_root"]:"false" == "true") {
	    ret = add(ret, BootStorage::RootPartitionDevice);
	}
	if (BootCommon::globals["boot_mbr"]:"false" == "true") {
	    ret = add(ret, BootCommon::mbrDisk);
	}
	if ( haskey(BootCommon::globals, "boot_extended") &&
	    BootCommon::globals["boot_extended"]:"false" == "true" ) {
	    ret = add(ret, BootStorage::ExtendedPartitionDevice);
	}
	// FIXME: floppy support is probably obsolete
	if ( haskey(BootCommon::globals, "boot_floppy") &&
	    BootCommon::globals["boot_floppy"]:"false" == "true" ) {
	    ret = add(ret, StorageDevices::FloppyDevice());
	}
	if ( haskey(BootCommon::globals, "boot_custom") ) {
	    ret = add(ret, BootCommon::globals["boot_custom"]:"");
	}
	if ( size(ret) > 0 )
	    return ret;
	// FIXME: find out what the best value is here: nil, [] or ["/dev/null"]
	return ["/dev/null"];
    }

/**
 * Check if the PBR of the given partition seems to contain a known boot block
 * @param device string partition device to check
 * @return true if the PBR seems to contain a known boot block
 */
global boolean IsPartitionBootable (string device) {
  //FIXME this is only for grub and should go to BootGRUB
    // use examineMBR to analyze PBR (partition boot record):
    // examineMBR returns "* stage1" when it finds the signature
    // of some stage1 bootloader
    string result = examineMBR(device);
    if ((result == "grub") || (result == "lilo"))
    	return true;
    else
	return false;
}


/**
 * Check if installation to floppy is performed
 * @return true if installing bootloader to floppy
 */
global boolean InstallingToFloppy () {
    boolean ret = false;
    // Bug 539774 - bootloader module wants to write to floppy disk although there is none
    if ((loader_device == nil) || (loader_device == ""))
	return ret; // bug #333459 - boot loader editor: propose new configuration 
		    // -- BLE tries to write something on the floppy disk
    // bnc #180784 don't install to bootloader to floppy if ppc
    if (getLoaderType (false) == "ppc")
	ret = false;
    else if (loader_device == StorageDevices::FloppyDevice())
	ret = true;
    else if (contains (BootStorage::getFloppyDevices (), loader_device))
	ret = true;
    y2milestone ("Installing to floppy: %1", ret);
    return ret;
}


/**
 * Get the list of particular kernel parameters
 * @param line string the whole kernel command line
 * @return a list of the kernel parameters split each separaterlly
 */
list<string> ListKernelParamsInLine (string line) {
// FIXME this function is really similar to code in Kernel.ycp
    list<string> cmdlist = [];
    integer parse_index = 0;
    boolean in_quotes = false;
    boolean after_backslash = false;
    string current_param = "";
    while (parse_index < size (line))
    {
	string current_char = substring (line, parse_index, 1);
	if (current_char == "\"" && ! after_backslash)
	    in_quotes = ! in_quotes;
	if (current_char == " " && ! in_quotes)
	{
	    cmdlist = add (cmdlist, current_param);
	    current_param = "";
	}
	else
	    current_param = current_param + current_char;
	if (current_char == "\\")
	    after_backslash = true;
	else
	    after_backslash = false;
	parse_index = parse_index + 1;
    }
    cmdlist = add (cmdlist, current_param);
    cmdlist = maplist (string c, cmdlist, {
	if (regexpmatch (c, "^[^=]+="))
	    c = regexpsub (c, "^([^=]+)=", "\\1");
	return c;
    });
    return cmdlist;

}

    /**
      * get kernel parameter from kernel command line
      * @param line string original line
      * @param key string parameter key
      * @return string value, "false" if not present,
      *   "true" if present key without value
      */
    global define string getKernelParamFromLine (string line, string key) ``{
	// FIXME this doesn't work with quotes and spaces
	string res = "false";
	list<string> params = splitstring (line, " ");
	params = filter (string p, params, ``(p != ""));
	foreach (string p, params, ``{
	    list<string> l = (list<string>) filter (string e, splitstring (p, "="), ``(e != " " && e != ""));
	    if (l[0]:"" == key)
	        res = l[1]:"true";
	});
	return res;
    }

    /**
      * set kernel parameter to GRUB command line
      * @param line string original line
      * @param key string parameter key
      * @param value string value, "false" to remove key,
      *   "true" to add key without value
      * @return string new kernel command line
      */
    global define string setKernelParamToLine
	(string line, string key, string value)
    ``{
	// FIXME this doesn't work with quotes and spaces
	list<string> params = splitstring (line, " ");
	params = filter (string p, params, ``(p != ""));
	boolean done = false;
	// count occurences of every parameter
	map<string,integer> occurences = $[];
	foreach (string p, params, ``{
	    list<string> l = filter (string e, splitstring (p, "="), ``(e != " " && e != ""));
	    string k = l[0]:"";
	    occurences[k] = occurences[k]:0 + 1;
	});
	params = maplist (string p, params, ``{
	    list<string> l = filter (string e, splitstring (p, "="), ``(e != " " && e != ""));
	    string k = l[0]:"";
	    if (k == key)
	    {
		if (value == "false")
		{
		    return "";
		}
		else if (occurences[k]:0 <= 1)
		{
	            done = true;
		    if (value == "true")
		    {
			return key;
		    }
		    else if (value != "false")
		    {
			return sformat ("%1=%2", key, value);
		    }
		}
		else
		{
		    occurences[k] = occurences[k]:0 - 1;
		    return "";
		}
	    }
	    return p;
	});
	if (! done)
	{
	    if (value == "true")
	    {
	        params = add (params, key);
	    }
	    else if (value != "false")
	    {
	        params = add (params, sformat ("%1=%2", key, value));
	    }
	}
	params = filter (string p, params, ``(p != ""));
	line = mergestring (params, " ");
	return line;
    }


    /*
     *  convert any value to an integer and return 0 for nonsense
     */
    global integer myToInteger(any num_any) {
	if (num_any == nil)
	    return 0;
	if (is (num_any, integer))
	    return (integer)num_any;
	if (is (num_any, string))
	    return (num_any == "") ? 0 :
		(tointeger((string)num_any) == nil ? 0 : tointeger((string)num_any));
	return 0;
    }

    /**
      * Get partition which should be activated if doing it during bl inst.
      * @param boot_partition string the partition holding /boot subtree
      * @param loader_device string the device to install bootloader to
      * @return a map $[ "dev" : string, "mbr": string, "num": any]
      *  containing device (eg. "/dev/hda4"), disk (eg. "/dev/hda") and
      *  partition number (eg. 4)
      */
    map<string,any> getPartitionToActivate (string boot_partition,
	string loader_device)
    {
	map p_dev = Storage::GetDiskPartition (loader_device);
	integer num = myToInteger( p_dev["nr"]:nil );
	string mbr_dev = p_dev["disk"]:"";

	// if bootloader is installed to /dev/md*
	// FIXME: use ::storage to detect md devices, not by name!
	if (substring (loader_device, 0, 7) == "/dev/md")
	{
	    map<string,integer> md = Md2Partitions (BootCommon::loader_device);
	    integer min = 256; // max. is 255; 256 means "no bios_id found"
	    string device = "";
	    foreach (string d, integer id, md, {
		if (id < min)
		{
		    min = id;
		    device = d;
		}
	    });
	    if (device != "")
	    {
		map p_dev = Storage::GetDiskPartition (device);
		num = myToInteger( p_dev["nr"]:nil );
		mbr_dev = p_dev["disk"]:"";
	    }
	}
	// if bootloader in MBR, activate /boot partition
	// (partiall fix of #20637)
	else if (num == 0)
	{
	    p_dev = Storage::GetDiskPartition (boot_partition);
	    num = myToInteger( p_dev["nr"]:nil );
	    mbr_dev = p_dev["disk"]:"";

	    if (size (Md2Partitions (boot_partition)) > 1)
	    {
		foreach (string k, integer v, Md2Partitions (boot_partition),{
		    if (search (k, loader_device) == 0)
		    {
			p_dev = Storage::GetDiskPartition (k);
			num = myToInteger( p_dev["nr"]:nil );
			mbr_dev = p_dev["disk"]:"";
		    }
		});
	    }
	}
	if (num != 0)
	{
	    if (num > 4)
	    {
		y2milestone ("Bootloader partition type is logical");
		map tm = Storage::GetTargetMap ();
		list<map> partitions = tm[mbr_dev, "partitions"]:[];
		foreach (map p, partitions, ``{
		    if (p["type"]:nil == `extended)
		    {
			num = p["nr"]:num;
			y2milestone ("Using extended partition %1 instead",
			num);
		    }
		});
	    }
	}
	map<string,any> ret = $[
	    "num" : num,
	    "mbr" : mbr_dev,
	    "dev" : Storage::GetDeviceName (mbr_dev, num),
	];
	return ret;
    }

    /**
     * Get a list of partitions to activate if user wants to activate
     * boot partition
     * @return a list of partitions to activate
     */
    list<map<string, any> > getPartitionsToActivate () {
	map<string,integer> md = $[];
	if (BootCommon::loader_device == "mbr_md")
	{
	    md =  Md2Partitions (BootStorage::BootPartitionDevice);
	}
	else
	{
	    md =  Md2Partitions (BootCommon::loader_device);
	}
	list<string> partitions = maplist (string k, integer v, md, ``(k));
	if (size (partitions) == 0)
	{
	    partitions = [BootCommon::loader_device];
	}
	list<map<string,any> > ret = maplist (string partition, partitions, {
	    return getPartitionToActivate (
		BootStorage::BootPartitionDevice,
		partition);
	});
	return toset (ret);
    }

    /**
     * Get the list of MBR disks that should be rewritten by generic code
     * if user wants to do so
     * @return a list of device names to be rewritten
     */
    list<string> getMbrsToRewrite () {
	list<string> ret = [BootCommon::mbrDisk];
	map<string,integer> md = $[];
	if (BootCommon::loader_device == "mbr_md")
	{
	    md =  Md2Partitions (BootStorage::BootPartitionDevice);
	}
	else
	{
	    md = Md2Partitions (BootCommon::loader_device);
	}
	list<string> mbrs = maplist (string d, integer b, md, {
	    d = getPartitionToActivate (
		BootStorage::BootPartitionDevice, d
	    )["mbr"]:mbrDisk;
	    return d;
	});
	if (contains (mbrs, BootCommon::mbrDisk))
	{
	    ret = (list<string>)merge (ret, mbrs);
	}
	return toset (ret);
    }

    /**
      * Get last change time of file
      * @param filename string name of file
      * @return string last change date as YYYY-MM-DD-HH-MM-SS
      */
     string getFileChangeDate (string filename) {
	map stat = (map) SCR::Read (.target.stat, filename);
	integer ctime = stat["ctime"]:0;
	string command = sformat (
	  "date --date='1970-01-01 00:00:00 %1 seconds' +\"%%Y-%%m-%%d-%%H-%%M-%%S\"",
	  ctime);
	map out = (map) SCR::Execute (.target.bash_output, command);
	string c_time = out["stdout"]:"";
	y2debug ("File %1: last change %2", filename, c_time);
	return c_time;
    }

    /**
      * Save current MBR to /boot/backup_mbr
      * Also save to /var/lib/YaST2/backup_boot_sectors/%device, if some
      * existing, rename it
      * @param device string name of device
      */
    void saveMBR (string device) {
	string device_file = mergestring (splitstring (device, "/"), "_");
	string device_file_path = "/var/lib/YaST2/backup_boot_sectors/"
	    + device_file;
	string device_file_path_to_logs = "/var/log/YaST2/"
	    + device_file;
	SCR::Execute (.target.bash,
	    "test -d /var/lib/YaST2/backup_boot_sectors || mkdir /var/lib/YaST2/backup_boot_sectors");
	if (SCR::Read (.target.size, device_file_path) > 0)
	{
	    list<string> contents = (list<string>) SCR::Read (.target.dir, "/var/lib/YaST2/backup_boot_sectors");
	    contents = filter (string c, contents, ``(regexpmatch (c, sformat (
		"%1-.*-.*-.*-.*-.*-.*", device_file))));
	    contents = sort (contents);
	    integer index = 0;
	    integer siz = size (contents);
	    while (index + 10 < siz)
	    {
		SCR::Execute (.target.remove,
		    sformat ("/var/lib/YaST2/backup_boot_sectors/%1", contents[index]:""));
		index = index + 1;
	    }
	    string change_date = getFileChangeDate (device_file_path);
	    SCR::Execute (.target.bash, sformat (
		"/bin/mv %1 %1-%2",
		device_file_path, change_date));
	}
	SCR::Execute (.target.bash, sformat (
	    "/bin/dd if=%1 of=%2 bs=512 count=1 2>&1",
	    device, device_file_path));
        // save MBR to yast2 log directory
	SCR::Execute (.target.bash, sformat (
	    "/bin/dd if=%1 of=%2 bs=512 count=1 2>&1",
	    device, device_file_path_to_logs));
	if (device == mbrDisk)
	{
	    SCR::Execute (.target.bash, sformat (
		"/bin/dd if=%1 of=%2 bs=512 count=1 2>&1",
		device, "/boot/backup_mbr"));

    	    // save thinkpad MBR 
	    if (BootCommon::ThinkPadMBR(device))
	    {
	       string device_file_path_thinkpad = device_file_path + "thinkpadMBR";
	       y2milestone("Backup thinkpad MBR");
	       SCR::Execute(.target.bash, sformat (
	       "cp %1 %2 2>&1", device_file_path, device_file_path_thinkpad));
	    }

	}
    }

    /**
      * Update contents of MBR (active partition and booting code)
      * FIXME move tis function to lilolike.ycp
      * @return boolean true on success
      */
    global define boolean updateMBR () ``{
      	// FIXME: do the real thing in perl_Bootloader
      	if (getLoaderType (false) == "grub") {  
      	    activate = ( globals["activate"]:"false" == "true" );
      	    repl_mbr = ( globals["generic_mbr"]:"false" == "true" );
      	}

	y2milestone ("Updating disk system area, activate partition: %1, replace MBR: %2", activate, repl_mbr);
	if (backup_mbr)
	{
	    y2milestone ("Doing MBR backup: MBR Disk: %1, loader device: %2",
		BootCommon::mbrDisk, BootCommon::loader_device);
	    list<string> disks_to_rewrite = (list<string>)toset (merge (
		getMbrsToRewrite (),
		[BootCommon::mbrDisk, BootCommon::loader_device]));
	    y2milestone ("Creating backup of boot sectors of %1",
		disks_to_rewrite);
	    foreach (string d, disks_to_rewrite, {
		saveMBR (d);
	    });
	}
	boolean ret = true;
	// if the bootloader stage 1 is not installed in the MBR, but
	// ConfigureLocation() asked us to replace some problematic existing
	// MBR, then overwrite the boot code (only, not the partition list!) in
	// the MBR with a generic (currently DOS?) bootloader
	if (repl_mbr && BootCommon::loader_device != mbrDisk)
	{
	    if (! Stage::initial ())
	    {
		PackageSystem::Install ("master-boot-code");
	    }
	    y2milestone("Updating code in MBR: MBR Disk: %1, loader device: %2",
		BootCommon::mbrDisk, BootCommon::loader_device);
	    list<string> disks_to_rewrite = getMbrsToRewrite ();
	    foreach (string d, disks_to_rewrite, {
		y2milestone ("Copying generic MBR code to %1", d);
		// added fix 446 -> 440 Vista booting problem bnc # 396444
		string command = sformat (
		    "/bin/dd bs=440 count=1 if=%1 of=%2",
		    "/usr/lib/boot/master-boot-code",
		    d);
		y2milestone ("Running command %1", command);
		map out = (map)SCR::Execute (.target.bash_output, command);
		integer exit = out["exit"]:0;
		y2milestone ("Command output: %1", out);
		ret = ret && (0 == exit);
	    });
	}

	if (activate)
	{
	  foreach (map m_activate, getPartitionsToActivate (), {
	    any num = m_activate["num"]:0;
	    string mbr_dev = m_activate["mbr"]:"";
	    if (num != 0 && mbr_dev != "")
	    {
		// if primary partition
		if ((! is (num, integer)) || num <= 4)
		{
		    y2milestone ("Activating partition %1 on %2", num, mbr_dev);
		    // FIXME: this is the most rotten code since molded sliced bread
		    // move to bootloader/Core/GRUB.pm or similar
		    // TESTME: make sure that parted does not destroy BSD
		    // slices (#suse24740): cf. section 5.1 of "info parted":
		    //   Parted only supports the BSD disk label system.
		    //   Parted is unlikely to support the partition slice
		    //   system in the future because the semantics are rather
		    //   strange, and don't work like "normal" partition tables
		    //   do.
//		    string command = sformat
//			("/usr/sbin/parted -s %1 set %2 boot on", mbr_dev, num);
		    // As a workaround for #167602, moved back to
		    // /sbin/activate, because it does not cause the kernel to
		    // forget about an activated extended partition (it changes
		    // the data on disk without using any ioctl).
		    // FIXME: investigate proper handling of the activate flag
		    // (kernel ioctls in parted etc.) and fix parted
		    string command = sformat
			("/usr/sbin/parted -s %1 set %2 boot on", mbr_dev, num);
		    y2milestone ("Running command %1", command);
		    map out = (map)SCR::Execute (.target.bash_output, command);
		    integer exit = out["exit"]:0;
		    y2milestone ("Command output: %1", out);
		    ret = ret && (0 == exit);
		}
	    }
	    else
	    {
		y2error ("Cannot activate %1", m_activate);
	    }
	  });
	}
	return ret;
    }

    /**
      * Rewrite current MBR with /var/lib/YaST2/backup_boot_sectors/%device
      * Warning!!! don't use for bootsectors, 440 bytes of sector are written
      * @param device string device to rewrite MBR to
      * @return boolean true on success
      */
    global define boolean restoreMBR (string device) ``{
	string device_file = mergestring (splitstring (device, "/"), "_");
	if (SCR::Read (.target.size, sformat ("/var/lib/YaST2/backup_boot_sectors/%1", device_file))
	    <= 0)
	{
	    Report::Error ("Can't restore MBR. No saved MBR found");
	    return false;
	}
        // added fix 446 -> 440 for Vista booting problem bnc #396444
	integer ret = (integer) SCR::Execute (.target.bash, sformat (
	    "/bin/dd of=%1 if=/var/lib/YaST2/backup_boot_sectors/%2 bs=440 count=1",
	    device, device_file));
	return (ret == 0);
    }

    /**
      * Update kernel parameters if some were added in Kernel module
      * @param orig original kernel parameters or kernel command line
      * @return kernel command line or parameters with added new parameters
      */
    global define string UpdateKernelParams (string orig) ``{
	list<string> new = splitstring (Kernel::GetCmdLine (), " ");
	list<string> old = splitstring (orig, " ");
	list<string> added = (list<string>)difflist (new,
	     splitstring (BootCommon::kernelCmdLine, " "));
	added = (list<string>)difflist (added, old);
	old = (list<string>) merge (old, added);
	if (Stage::initial ())
	{// move showopts apic to the end
	    boolean showopts = false;
	    boolean apic = false;
	    if (contains (old, "showopts"))
		showopts = true;
	    if (contains (old, "apic"))
		apic = true;
	    old = filter (string o, old, ``(o != "apic" && o != "showopts"));
	    if (showopts)
		old = add (old, "showopts");
	    if (apic)
		old = add (old, "apic");
	}
	return mergestring (old, " ");
    }


    /**
      * Get map of swap partitions
      * @return a map where key is partition name and value its size
      */
    global define map<string, integer> getSwapPartitions () ``{
        //FIXME use cache of storage map
	map<string, map> tm = (map<string,map>)Storage::GetTargetMap ();
	boolean installation = Mode::installation ();
	map<string, integer> ret = $[];
	foreach (string k, map v, tm, ``{
	    integer cyl_size = v["cyl_size"]:0;
	    list<map<string,any> > partitions = v["partitions"]:[];
	    partitions = filter(map<string,any> p, partitions, {
		return p["mount"]:"" == "swap" && ! p["delete"]:false;
	    });
	    foreach (map<string, any> s, partitions, ``{
		// bnc#577127 - Encrypted swap is not properly set up as resume device
		string dev = "";
		if ((s["crypt_device"]:"" != nil) && (s["crypt_device"]:"" != ""))
		    dev = (string)(s["crypt_device"]:"");
		else
		    dev = (string)(s["device"]:"");
		ret[dev] = (integer)(s["region", 1]:0) * cyl_size;
	    });
	});
	y2milestone ("Available swap partitions: %1", ret);
	return ret;
    }

    

    /**
      * Create translated name of a section
      * @param orig string original section name
      * @return translated section name
      */
    global define string translateSectionTitle (string orig) ``{
	return GfxMenu::translateSectionTitle(orig,
					      getLoaderType(false));
    }

    /**
      * Check if device is MBR of a disk
      * @param device string device to check
      * @return boolean true if is MBR
      */
    define boolean IsMbr (string device) ``{
	if (regexpmatch (device, "^\/dev\/[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]+$"))
	    return true;
	if (regexpmatch (device, "^\/dev\/[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]+\/.*d[0-9]+$"))
	    return true;
	return false;
    }

    /**
      * Add '(MBR)' to the disk description if it is a MBR of some partition
      * @param descr string disk description
      * @param device string disk device
      * @return string updated description
      */
    define string AddMbrToDescription (string descr, string device) ``{
	return IsMbr (device)
	    ? sformat ("%1 (MBR)", descr)
	    : descr;
    }

    /**
     * Update the Kernel::vgaType value to the saved one if not defined
     */
    global define void UpdateInstallationKernelParameters () ``{
	map<string,any> saved_params = $[];
	if (! Stage::initial ())
	{
	    saved_params = (map<string,any>)SCR::Read (
		.target.ycp, "/var/lib/YaST2/bootloader.ycp");
	}
	if (Kernel::GetVgaType () == "")
	{
	    string vgaType = (string)(saved_params["vgamode"]:"");
	    if (vgaType != nil && vgaType != "")
		Kernel::SetVgaType (vgaType);
	}
	if (! Stage::initial ())
	{
	    Kernel::SetCmdLine (saved_params["installation_kernel_params"]:"");
	}
	else
	{
	    if (SCR::Read (.etc.install_inf.NoPCMCIA) == "1")
	    {
		Kernel::SetCmdLine (Kernel::GetCmdLine () + " NOPCMCIA");
	    }
	}
    }

    /**
     * Get additional kernel parameters
     * @return additional kernel parameters
     */
    global define string GetAdditionalFailsafeParams () ``{
	if (Stage::initial ())
	{
	    additional_failsafe_params =
		SCR::Read (.etc.install_inf.NoPCMCIA) == "1"
		    ? " NOPCMCIA "
		    : "";
	}
	else
	{
	    map<string,any> saved_params = (map<string,any>)SCR::Read (
		.target.ycp, "/var/lib/YaST2/bootloader.ycp");
	    additional_failsafe_params
		= saved_params["additional_failsafe_params"]:"";
	}
	return additional_failsafe_params;
    }

/**
 * Get additional kernel parameters from control file
 * @return string additional kernel parameters
 */
global string GetAdditionalKernelParams () {
    return ProductFeatures::GetStringFeature (
		"globals",
		"additional_kernel_parameters");
}

/**
 * Get additional kernel parameters splitted to a list
 * @return a list of additional kernel parameters
 */
global list<string> ListAdditionalKernelParams () {
    return ListKernelParamsInLine (GetAdditionalKernelParams ());
}

/**
 * Update graphical bootloader to contain help text of current language
 * And make the selected installation language default
 * @return boolean true on success
 */
global define boolean UpdateGfxMenuContents () {
    return GfxMenu::UpdateGfxMenuContents(getLoaderType(false));
}


/**
 * Update device name according to changes in kernel (eg. SATA)
 * @param device string the original device name
 * @return string updated device
 */
global string UpdateDevice (string device) {
    if (Mode::test ())
    {
	map mapping = $[
	    "/dev/hda" : "/dev/sda",
	    "/dev/hdb" : "/dev/sdb",
	];

	map d = Storage::GetDiskPartition( device );
	if( haskey( mapping, d["disk"]:"" ))
	{
	    if (d["nr"]:nil == nil || d["nr"]:nil == 0)
	    {
		device = mapping[d["disk"]:""]:"";
	    }
	    else
	    {
		device = Storage::GetDeviceName(
		    mapping[d["disk"]:""]:"",
		    d["nr"]:nil);
	    }
	}
    }
    else
    {
	list<string> devices = Storage::GetTranslatedDevices (
	    installed_version,
	    update_version,
	    [ device ]);
	device = devices[0]:device;
    }
    return device;
}

/**
 * Check if memtest86 is present
 * @return boolean true if memtest86 section is to be proposed
 */
global boolean MemtestPresent () {
    return (! contains (removed_sections, "memtest"))
	&& (Mode::test ()
	    || (Mode::normal () && Pkg::IsProvided ("memtest86+"))
	    || (! Mode::normal () && Pkg::IsSelected ("memtest86+")));

}


/**
 * Check if the bootloader can be installed at all with current configuration
 * @return boolean true if it can
 */
global boolean BootloaderInstallable () {
    if (Mode::config ())
	return true;
    if (Arch::i386 () || Arch::x86_64 ())
    // the only relevant is the partition holding the /boot filesystem
    {
	DetectDisks ();
	y2milestone ("Boot partition device: %1",
	    BootStorage::BootPartitionDevice);
	map dev = Storage::GetDiskPartition( BootStorage::BootPartitionDevice);
	y2milestone ("Disk info: %1", dev);
	// MD, but not mirroring is OK
	// FIXME: type detection by name deprecated
	if (dev["disk"]:"" == "/dev/md")
	{
	    map tm = Storage::GetTargetMap ();
	    map md = tm["/dev/md"]:$[];
	    list<map> parts = md["partitions"]:[];
	    map info = $[];
	    foreach (map p, parts, {
		if (p["device"]:"" == BootStorage::BootPartitionDevice)
		    info = p;
	    });
	    if (tolower (info["raid_type"]:"") != "raid1")
	    {
		y2milestone ("Cannot install bootloader on RAID (not mirror)");
		return false;
	    }

	    // (bnc 357897) - lilo reports inconsistent raid version when trying to install on raid1
	    if (getLoaderType (false) == "lilo")
	    {
		string raid_ver = info["sb_ver"]:"";    //"00.90.03"
		if (substring(raid_ver,0,2) == "01")
		{
		    y2milestone ("Cannot install bootloader on RAID (lilo doesn't support raid version %1)", info["sb_ver"]:"");
		    return false;
		}
	    }
	}
	// EVMS
	// FIXME: type detection by name deprecated
	else if (search (getBootPartition(), "/dev/evms/") == 0)
	{
	    y2milestone ("Cannot install bootloader on EVMS");
	    return false;
	}
	// LVM
	else if (! is( dev["nr"]:(any)0, integer ))
	{
	    y2milestone ("Cannot install bootloader on LVM");
	    return false;
	}

	return true;
    }
    else
    {
	return true;
    }
}

/**
 * Function return absolute value of arg
 *
 * @param integer value
 * @return integer absolute value
 */

integer abs(integer value)
{
	if (value < 0)
		return (value * (-1));
	else
		return value;
}

/** bnc #440125 - default boot section with failsafe args
 * Compare append from default linux section with append from 
 * BootCommon::sections
 *
 * @return boolean true if appends are similar
 */
boolean compareAppends(string default_append, string section_append)
{
	integer deuce = 0;
	// delete white space on the beginning of string
	default_append = String::CutBlanks(default_append);
	section_append = String::CutBlanks(section_append);
	// check valid append for section
        //FIXME JR I think this is not true, append is valid even if it contain only one letter '3' which mean go to runlevel 3
	if (size(section_append) < 3)
		return false;

	// check size of default append with section append
	// if the size is same return true (same appends)
	y2milestone("Size of default append: \"%1\" and compared section append: \"%2\"", 
			size(default_append), size(section_append));
	if (size(default_append) == size(section_append))
		return true;

	list <string> default_list = splitstring(default_append, " ");
	list <string> section_list = splitstring(section_append, " ");

	integer size_default_list = size(default_list);
	integer size_section_list = size(section_list);

	integer relative_deuce = abs(size_section_list - size_default_list);

	// check number of append args
	// if different between number of args is more than 3 args return false

	y2milestone("No. default args: %1 no. compared section args: %2", size_default_list, size_section_list);
	if (relative_deuce >= 3)
		return false;

	// check args by keywords from section append to default append

	y2milestone("default_append: %1", default_append);
	y2milestone("section_list: %1", section_list);
	foreach(string key, section_list,
	{		
		if (search(key, "resume=") != nil)
		{
			list <string> tmp = splitstring(key,"=");
			key = BootStorage::Dev2MountByDev(tmp[1]:"");
		}
		if (search(default_append, key) != nil)
			deuce = deuce +1;
		else
			deuce = deuce -1;
	});

	// if there exist more than 3 different args return false
	// else append seem to be similar -> true
	y2milestone("No. deuces of default append with compared append: %1", deuce);
	if (abs(size_default_list - deuce) >= 3)
		return false;
	else
		return true;
}



/** bnc #440125 - default boot section with failsafe args
 * Try to find potencional default linux section
 * It can solve problem in function WriteToSysconf() with saving
 * wrong (failsafe) args for default
 *
 * @return string name of default boot section
 */

global string findRelativeDefaultLinux ()
{
	string default_linux = "";
	
	// create defualt sections
	map<string,any> linux_default = BootCommon::CreateLinuxSection("linux");

	foreach(map<string,any>s, BootCommon::sections,
	{
		if ((s["root"]:"" == linux_default["root"]:nil) &&
		    (s["original_name"]:"" == "linux"))
		{
                        //FIXME Check for root and original name should be enought, as failsafe allways has failsafe orig name
			if (compareAppends(linux_default["append"]:"", s["append"]:""))
				default_linux = s["name"]:"";
		}
	});

	y2milestone("Relative default boot section is: \"%1\"", default_linux);
	return default_linux;
} 



/** bnc #440125 - default boot section with failsafe args
 * Check if default boot name is linux
 * 
 * @param string default boot name
 * @return boolean true if boot name is linux
 */
global boolean isDefaultBootSectioLinux(string default_boot)
{
	boolean ret = false;
	foreach(map<string,any>s, BootCommon::sections,
	{
		if (s["name"]:"" == default_boot)
		{
			if (s["original_name"]:"" == "linux")
				ret = true;
			break;
		}
	});
	if (ret)
		y2milestone("Boot section: \"%1\" is linux", default_boot);
	else
		y2warning("Boot section: \"%1\" is NOT linux", default_boot);
	return ret;
}

/** bnc#511319 Add information about /etc/sysconfig/bootloader to configuration file.
 * Write option with value and comment to
 * sysconfig file
 *
 * @param boolean true if called from client inst_bootloader
 * @param path to config file (.sysconfig.bootloader)
 * @param path option (.DEFAULT_APPEND)
 * @param string value of otion
 * @param string comment of option
 * @return true on success
 */

define boolean WriteOptionToSysconfig(boolean inst, path file_path, path option, string value, string comment)
{
    boolean ret = false;

    if ((!inst) &&(!FileUtils::Exists("/etc/sysconfig/bootloader")))
    {
	y2milestone("Skip writting configuration to /etc/sysconfig/bootloader -> file missing");
	return ret;
    }
    path file_path_option = add (file_path, option);
    boolean comment_exist = SCR::Read(add(file_path_option, .comment)) == nil;

    // write value of option
    ret = SCR::Write(file_path_option, value);

    // write comment of option if it is necessary
    if (!comment_exist )
    {
	ret = ret && SCR::Write(add(file_path_option, .comment), comment);
    }
    SCR::Write(file_path, nil);
    return ret;
}

/** bnc#511319 Add information about /etc/sysconfig/bootloader to configuration file.
 * Create /etc/sysconfig/bootloader it is configuration
 * file for bootloader
 *
 * @param boolean true if it is called from client inst_bootlaoder
 * @return boolean true on success
 */

define boolean CreateBLSysconfigFile(boolean inst)
{
    if (inst)
    {
	if (!FileUtils::Exists(Installation::destdir +"/etc/sysconfig"))
	{
	    WFM::Execute(.local.mkdir, Installation::destdir + "/etc/sysconfig");
	    WFM::Execute(.local.bash, sformat ("touch %1/etc/sysconfig/bootloader", Installation::destdir));
	}
	//string target_sysconfig_path = Installation::destdir + "/etc/sysconfig/bootloader";
	return true;
    }
    return true;
}
/** bnc #578545 - kdump misconfigures crashkernel parameter for Xen
 * Check if default_append includes crashkernel arg
 * 
 * @param string defaul_append
 * @return string defaul_append without crashkernel
 */

define string deleteCrashkernelFromAppend (string append)
{
	y2milestone("Original append: %1",append);
	list<string> list_append = splitstring(append, " ");

	if (size(list_append)>0)
	{
	   list_append = filter(string key, list_append,
	   {
		if (search(key, "crashkernel") == nil)
		    return true;
		else
		    return false;
           });
	}
	string ret = mergestring(list_append, " ");
	y2milestone("Filtered append: %1",ret);
	return ret;
}


/** FATE #302245 save kernel args etc to /etc/sysconfig/bootloader
 * Function write/update info in /etc/sysconfig/bootloader
 * @param booloean true if it called from inst_bootloader.ycp 
 */

global define void WriteToSysconf(boolean inst_bootloader)
{
    string lt = BootCommon::getLoaderType (false);
    y2milestone ("Saving /etc/sysconfig/bootloader for %1", lt);

    string default_boot_section_name = "";
    // fix for bnc #440125 - default boot section with failsafe args
    // it is not possible create exact algoritmus but I hope it helps in
    // mostly cases.
    if (isDefaultBootSectioLinux(BootCommon::globals["default"]:""))
    	default_boot_section_name = BootCommon::globals["default"]:"";
    else
	default_boot_section_name = findRelativeDefaultLinux ();

    // get the default and failsafe append + vga parameters; if section with
    // appropriate original name not found, just use any Linux section
    // doing so during update may be questionable, however, the variables need to
    // be initialized in any case
    string default_vga = "";
    string default_append = "";
    boolean default_set = false;
    string failsafe_vga = "";
    string failsafe_append = "";
    boolean failsafe_set = false;
    string xen_vga = "";
    string xen_append = "";
    string xen_kernel_append = "";
    string addon_name = "";
    string addon_append = "";
    string addon_vga = "";
    boolean xen_set = false;

    // default boot section is not found
    if (default_boot_section_name == "")
    {
	// create defualt sections
	map<string,any> linux_default = BootCommon::CreateLinuxSection("linux");
	default_set = true;
	default_vga = linux_default["vgamode"]:"";
	default_append = linux_default["append"]:"";
    }

    foreach (map<string,any>s, BootCommon::sections, 
    {
	if ((search(s["original_name"]:"","linux") != nil) && 
	   (s["name"]:"" == default_boot_section_name))
	{
	   default_set = true;
	   default_vga = s["vgamode"]:"";
	   default_append = s["append"]:"";
	}
	if (search(s["original_name"]:"","xen") != nil)
	{
	   xen_set = true;
	   xen_vga = s["vgamode"]:"";
	   xen_append = s["xen_append"]:"";
	   xen_kernel_append = s["append"]:"";
	}
	else if (search(s["original_name"]:"","failsafe") != nil)
	{
	   failsafe_set = true;
	   failsafe_vga = s["vgamode"]:"";
	   failsafe_append = s["append"]:"";
	}
	if (s["type"]:"" == "image" && ! default_set)
	{
	   default_vga = s["vgamode"]:"";
	   default_append = s["append"]:"";
	}
	if (s["type"]:"" == "image" && ! failsafe_set)
        {
	   failsafe_vga = s["vgamode"]:"";
	   failsafe_append = s["append"]:"";
	}

	if (s["__rt_kernel"]:"" == "true")
	{
	   addon_name = s["name"]:"";
	   addon_append = s["append"]:"";
	   addon_vga = s["vgamode"]:"";
	}

    });

    if (! xen_set)
    {
       xen_kernel_append = deleteCrashkernelFromAppend(default_append);
       xen_append = "";
       xen_vga = default_vga;
    }

    // save some sysconfig variables
    // register new agent pointing into the mounted filesystem
    path sys_agent = .sysconfig.bootloader;

    if (inst_bootloader)
    {
	sys_agent = add(.target, sys_agent);
	string target_sysconfig_path = Installation::destdir + "/etc/sysconfig/bootloader";
	SCR::RegisterAgent (sys_agent, `ag_ini(
  	     `SysConfigFile(target_sysconfig_path)));

    } 
    CreateBLSysconfigFile(inst_bootloader);

    string comment = "";
    comment= "\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tlist(grub,lilo,none)
## Default:\tgrub
#
# Type of bootloader in use.
# For making the change effect run bootloader configuration tool
# and configure newly selected bootloader
#
#\n";
    if (!Arch::i386() && !Arch::x86_64())
    {
	comment= "\n ## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# Type of bootloader in use.
# For making the change effect run bootloader configuration tool
# and configure newly selected bootloader
#
#\n";
    }

    WriteOptionToSysconfig(inst_bootloader, sys_agent, .LOADER_TYPE, lt, comment);

    comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\t\"splash=silent quiet showotps\"
#
# Arguments for kernel which is used like default boot section.
# If the options is commented perl-Bootloader uses his default arguments
# for kernel.
#\n";

    if (!Arch::i386() && !Arch::x86_64())
    {
	comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# Arguments for kernel which is used like default boot section.
# If the options is commented perl-Bootloader uses his default arguments
# for kernel.
#\n";

    }
    WriteOptionToSysconfig(inst_bootloader, sys_agent, .DEFAULT_APPEND, default_append, comment);

    comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# VGA option for kernel which is used like default boot section.
# If the options is commented or empty perl-Bootloader doesn't use it.
# Empty option could be cause of broken size of fonts etc.
#\n";

    if (Arch::i386 () || Arch::x86_64 () || Arch::ia64 ())
	WriteOptionToSysconfig(inst_bootloader, sys_agent, .DEFAULT_VGA, default_vga, comment);

    comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\t\"showopts apm=off noresume nosmp maxcpus=0 edd=off powersaved=off nohz=off highres=off processor.max_cstate=1 nomodeset x11failsafe\"
#
# Arguments for kernel which is used like failsafe boot section
# If the options is commented perl-Bootloader uses his default arguments
# for kernel.
#\n";

    if (Arch::x86_64())
    {
    comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\t\"showopts apm=off noresume edd=off powersaved=off nohz=off highres=off processor.max_cstate=1 nomodeset x11failsafe\"
#
# Arguments for kernel which is used like failsafe boot section
# If the options is commented perl-Bootloader uses his default arguments
# for kernel.
#\n";

    }
    if (Arch::ia64())
    {
    comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\t\"nohalt noresume powersaved=off x11failsafe\"
#
# Arguments for kernel which is used like failsafe boot section
# If the options is commented perl-Bootloader uses his default arguments
# for kernel.
#\n";

    }

    if (Arch::s390())
    {
    comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# Arguments for kernel which is used like failsafe boot section
# If the options is commented perl-Bootloader uses his default arguments
# for kernel.
#\n";

    }
  
    WriteOptionToSysconfig(inst_bootloader, sys_agent, .FAILSAFE_APPEND, failsafe_append, comment);

    comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# VGA option for kernel which is used like failsafe boot section.
# If the options is commented or empty perl-Bootloader doesn't use it.
# Empty option could be cause of broken size of fonts etc.
#\n";

    if (Arch::i386 () || Arch::x86_64 () || Arch::ia64 ())
	WriteOptionToSysconfig(inst_bootloader, sys_agent, .FAILSAFE_VGA, failsafe_vga, comment);

   comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\t\"splash=silent quiet showotps\"
#
# Arguments for XEN kernel in Dom0.
# If the options is commented perl-Bootloader uses his default arguments
# for XEN kernel.
#\n";

    if (Arch::ia64 ())
    {
	comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\t\"splash=silent quiet\"
#
# Arguments for XEN kernel in Dom0.
# If the options is commented perl-Bootloader uses his default arguments
# for XEN kernel.
#\n";

    }

    if (Arch::i386 () || Arch::x86_64 () || Arch::ia64 ())
	WriteOptionToSysconfig(inst_bootloader, sys_agent, .XEN_KERNEL_APPEND, xen_kernel_append, comment);

   comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# Arguments for XEN hypervisor
# Usually it is empty or includes arguments like crashkernel for kdump etc.
#\n";

    if (Arch::i386 () || Arch::x86_64 () || Arch::ia64 ())
	WriteOptionToSysconfig(inst_bootloader, sys_agent, .XEN_APPEND, xen_append, comment);

   comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# VGA option for XEN kernel.
# If the options is commented or empty perl-Bootloader doesn't use it.
# Empty option could be cause of broken size of fonts etc.
#\n";
    if (Arch::i386 () || Arch::x86_64 () || Arch::ia64 ())
	WriteOptionToSysconfig(inst_bootloader, sys_agent, .XEN_VGA, xen_vga, comment);
 
   comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# Title of RealTime kernel in bootloader configuration file.
#\n";
    if (addon_name != "")
	WriteOptionToSysconfig(inst_bootloader, sys_agent, .RT_NAME, addon_name, comment);

   comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# VGA option for RealTime kernel.
# If the options is commented or empty perl-Bootloader doesn't use it.
# Empty option could be cause of broken size of fonts etc.
#\n";
   if (addon_vga != "")
	WriteOptionToSysconfig(inst_bootloader, sys_agent, .RT_VGA, addon_vga, comment);

    comment="\n## Path:\tSystem/Bootloader
## Description:\tBootloader configuration
## Type:\tstring
## Default:\tnone
#
# Arguments for RealTime kernel.
# If the options is commented perl-Bootloader uses his default arguments
# for kernel.
#\n";
    if (addon_append != "")
	WriteOptionToSysconfig(inst_bootloader, sys_agent, .RT_APPEND, addon_append, comment);

}

/**
 * Function return boot device it means
 * return boot partition or root partition if boot partition deosn't exist
 * function return "" if boot partition or root partition is not defined (autoyast)
 * @return string name of boot device (partition)
 */

global string getBootPartition()
{
	string boot_device = "";
	if (BootStorage::BootPartitionDevice != "")
		boot_device = BootStorage::BootPartitionDevice;
	else if (BootStorage::RootPartitionDevice != "")
		boot_device = BootStorage::RootPartitionDevice;

	return boot_device;
}

/** FATE #303548 - Grub: limit device.map to devices detected by BIOS Int 13
 * Function select boot device - disk
 *
 * @return string name of boot device - disk
 */

global string getBootDisk()
{
	string boot_device = getBootPartition();

	if (boot_device == "")
	{
		y2milestone("BootPartitionDevice and RootPartitionDevice are empty");
		return boot_device;
	}
	map p_dev = Storage::GetDiskPartition (boot_device);

	string boot_disk_device = p_dev["disk"]:"";

	if ((boot_disk_device != "") && (boot_disk_device != nil))
	{
		y2milestone("Boot device - disk: %1", boot_disk_device);
		return boot_disk_device;
	}

	y2milestone("Finding boot disk failed!");
	return "";
}

/** FATE #303548 - Grub: limit device.map to devices detected by BIOS Int 13
 * Function select boot device - disk
 *
 * @return string name of boot device - disk
 */


/** FATE #110038: Serial console
 * Function build value for console from:
 * @param string unit no of console 
 * @param string speed
 * @param string parity (n,o,e)
 * @param string word (8)
 * @return string value of console for kernel append
 */
define string buildConsoleValue (string unit, string speed, string parity, string word)
{
	string ret = "";
	if ((unit != "") && (speed != ""))
	{
		// add number of serial console
		ret = "ttyS" + unit;
		// add speed
		ret = ret + "," + speed;
		if (parity != "")
		{
			// add parity
			switch (parity)
			{
				case ("no"):
					ret = ret + "n";
					break;
				case ("odd"):
					ret = ret +"o";
					break;
				case ("even"):
					ret = ret + "e";
					break;
				default:
					ret = ret + "n";
					break;
			}

			// add word
			if (word != "")
				ret = ret + word;
		}
		y2milestone("console value for kernel: %1", ret);
	} else {
		y2error("Wrong values unit: %1 , speed: %2 , parity: %3 , word: %4",
			unit, speed, parity, word);
	}
	return ret;
}


/** FATE #110038: Serial console
 * Function parse string key (e.g. --speed=9600)
 * and return value of key
 * @param string key e.g. --unit=0
 * @return string value of key
 */


define string getKeyValue(string key)
{
	string ret = "";
		list <string> value = [];
		if (key != "")
		{
			value = splitstring (key, "=");
			if (value[1]:"" != "")
				ret = value[1]:"";
		}
	
	y2debug("parse: %1 and return value: %2", key, ret);
	return ret;
}


/** FATE #110038: Serial console
 * Function check value from globals (serial and terminal)
 * after that build value of console append for kernel if it is possible
 * @return string value of console for kernel append
 */

define string getConsoleValue()
{
	string ret = "";
	if ((globals["serial"]:"" != "") && (globals["terminal"]:"" != ""))
	{
		list <string>  list_serial = splitstring (globals["serial"]:"", " ");
		y2milestone("list of serial args: %1", list_serial);
		string unit = "";
		string speed = "";
		string parity = "";
		string word = "";
		foreach(string key, list_serial,
		{
			if (search(key, "--unit") != nil)
				unit = getKeyValue(key);
			
			if (search(key, "--speed") != nil)
				speed = getKeyValue(key);

			if (search(key, "--parity") != nil)
				parity = getKeyValue(key);

			if (search(key, "--word") != nil)
				word = getKeyValue(key);	

		});
		// build value
		ret = buildConsoleValue (unit, speed, parity, word);
	}

	return ret;
}

/** FATE #110038: Serial console
 * Add console arg for kernel if there is defined serial console
 * - add key console with value to section type image and xen
 */

global define void HandleConsole()
{
	string console_value = getConsoleValue();

	// list of idexes from sections where is image or xen
	list < integer > list_index =[];
	// counter 
	integer index = -1;
	foreach(map<string,any> section, sections,
	{
		index = index +1;
		if ((section["type"]:"" == "image") || (search(section["type"]:"", "xen") != nil))
			list_index = add(list_index, index);
	});

	// add key console with value
	if (size(list_index) > 0)
	{
		foreach (integer idx, list_index,
		{
			sections[idx, "__changed"] = true;
			if (sections[idx, "append"]:nil != nil)
			{
				string updated_append = "";
				if ((console_value != "") || (console_value != nil))
					updated_append = BootCommon::UpdateSerialConsole(sections[idx,"append"]:"",
						 console_value);
				else
					updated_append = BootCommon::UpdateSerialConsole(sections[idx,"append"]:"", "");
				if (updated_append != nil)
				{
					sections[idx,"append"]=updated_append;
				}
			}
			y2debug("Added/Removed console for section: %1", sections[idx]:$[]);
		});
	}
}



/** bnc #450153 - support for installation kernel from add-on
 * fucntion call client from add-on and update proposal for 
 * yast2-bootloader. -> availabe edit kernel args for kernel
 * from add-on
 *
 * @return boolean - true on success
 */
global boolean UpdateProposalFromClient ()
{
	boolean ret = true;
	string client_file = "kernel_bl_proposal";
	if ((!Arch::i386()) && (!Arch::x86_64()))
	{
		y2milestone("Unsuported architecture... for adding SLERT addon");
		return ret;
	}

	if (WFM::ClientExists(client_file))
	{
		y2milestone("Client: %1 was found", client_file);
		WFM::CallFunction (client_file, []);

	} else {
		y2milestone("File %1 doesn't exist - proposal will not be updated", client_file);
	}

	return ret;
}


} //end of include

ACC SHELL 2018