ACC SHELL

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

/**
 * File:
 *      autoinstall.ycp
 *
 * Module:
 *      Bootloader installation and configuration
 *
 * Summary:
 *      Bootloader autoinstallation preparation
 *
 * Authors:
 *      Jiri Srain <jsrain@suse.cz>
 *      Olaf Dabrunz <od@suse.de>
 *
 * $Id: autoinstall.ycp 57000 2009-04-27 15:10:59Z juhliarik $
 *
 */
{

// Example autoyast configuration file snippets:
//
// -------------------------------------------------
// SLES9:
//
// <bootloader>
//   <activate config:type="boolean">true</activate>
//   <board_type>chrp</board_type>
//   <default>linux</default>
//   <global config:type="list">
//     <global_entry>
//       <key>default</key>
//       <value>linux</value>
//     </global_entry>
//     <global_entry>
//       <key>timeout</key>
//       <value config:type="integer">100</value>
//     </global_entry>
//     <global_entry>
//     [...]
// </global>
// <initrd_modules config:type="list">
//   <initrd_module>
//     <module>sym53c8xx</module>
//   </initrd_module>
//   <initrd_module>
//     <module>loop</module>
//   </initrd_module>
// </initrd_modules>
// <loader_device>/dev/sda1</loader_device>
// <loader_type>ppc</loader_type>
// <location>boot</location>
// <of_defaultdevice config:type="boolean">true</of_defaultdevice>
// <prep_boot_partition>/dev/sda1</prep_boot_partition>
// <sections config:type="list">
//   <section config:type="list">
//     <section_entry>
//       <key>image</key>
//       <value>/boot/vmlinux</value>
//     </section_entry>
//     <section_entry>
//       <key>label</key>
//       <value>linux</value>
//     </section_entry>
//     [...]
// -------------------------------------------------
// openSUSE 10.3 Alpha5:
//
// <bootloader>
//   <global>
//     <activate>true</activate>
//     <boot_chrp_custom>/dev/sda1</boot_chrp_custom>
//     <default>linux</default>
//     <lines_cache_id>1</lines_cache_id>
//     <timeout config:type="integer">80</timeout>
//   </global>
//   <initrd_modules config:type="list">
//     <initrd_module>
//       <module>ipr</module>
//     </initrd_module>
//     <initrd_module>
//       <module>pata_pdc2027x</module>
//     </initrd_module>
//     <initrd_module>
//       <module>dm_mod</module>
//     </initrd_module>
//   </initrd_modules>
//   <loader_type>ppc</loader_type>
//   <sections config:type="list">
//     <section>
//       <append> xmon=on sysrq=1</append>
//       <image>/boot/vmlinux-2.6.22-rc4-git3-2-ppc64</image>
//       <initial>1</initial>
//       <initrd>/boot/initrd-2.6.22-rc4-git3-2-ppc64</initrd>
//       <kernel>/boot/vmlinux</kernel>
//       <lines_cache_id>0</lines_cache_id>
//       <name>linux</name>
//       <original_name>linux</original_name>
//       <root>/dev/system/root2</root>
//       <type>image</type>
//     </section>
//   </sections>
// </bootloader>
// -------------------------------------------------

    import "Bootloader";
    import "BootStorage";
    import "BootCommon";
    import "Initrd";
    import "Kernel";
    import "Mode";

/**
 * Add missing data (eg. root filesystem) to sections imported from profile
 * @param sect a list of all sections
 * @return a lit of all updated sections
 */
list<map<string,any> > UpdateImportedSections (list<map<string,any> > sect) {
    sect = maplist (map<string,any> s, sect, {
	y2milestone ("Updating imported section %1", s);
	string orig_name = s["original_name"]:s["name"]:"linux";
	string type = s["type"]:"image";
	if (type != "image")
	    return s;
	s = (map<string,any>)union (
	    BootCommon::CreateLinuxSection (orig_name),
	    s);

	// convert "kernel" to "image", if not already defined in the section
	if ( haskey(s, "kernel") ) {
	    if ( ! haskey(s, "image") ) {
		s["image"] = s["kernel"]:"";
	    }
	    s = remove (s, "kernel");
	}
	// convert "vga" to "vgamode", if not already defined in the section
	if ( haskey(s, "vga") ) {
	    if ( ! haskey(s, "vgamode") ) {
		s["vgamode"] = s["vga"]:"";
	    }
	    s = remove (s, "vga");
	}

	return s;
    });
    return sect;
}

    /**
      * Translate the autoinstallation map to the Export map
      * @param ai a map the autoinstallation map
      * @return a map the export map
      */
    define map<string,any> AI2Export (map<string,any> ai) ``{
	if (Mode::autoinst ())
	{
	    BootCommon::DetectDisks ();
	}
	// prepare settings for default bootloader if not specified in the
	// profile
	if (Mode::autoinst () && (
	    ai["loader_type"]:"default" == "default"
	    || ai["loader_type"]:"default" == ""
	    )
	) {
	    ai["loader_type"] = Bootloader::getLoaderType ();
	}
	y2milestone ("Bootloader settings from profile: %1", ai);

	// bootloader type and location stuff
	map<string,any> exp = $[
	    "loader_type" : ai["loader_type"]:"",
	    "specific" : $[],
	];

	// define "global" sub-map to make sure we can add to the globals at
	// any time
	exp["specific", "global"] = (map<string,any>) $[];

/* FIXME
	// global PPC stuff
	if (ai["loader_type"]:"" == "ppc")
	{
	    exp["specific", "activate"] = true;
	    foreach (string k, ["iseries_streamfile", "iseries_write_slot_a",
		"iseries_write_slot_b", "iseries_write_streamfile",
		"iseries_write_prepboot", "prep_boot_partition",
		"of_defaultdevice", "board_type", "activate"],
	    {
		if (haskey (ai, k))
		{
		    exp["specific", k] = ai[k]:nil;
		}
	    });
	}
	// global ELILO stuff
	if (ai["loader_type"]:"" == "elilo")
	{
	    string def_label = "";
	    if (! Mode::test ())
	    {
	    import "Product";
		if (Mode::autoinst ())
		{
		    def_label = Product::name;
		}
	    }
	    // if EFI label not specified, use default label
	    exp["location"] = ai["efi_entry_label"]:ai["location"]:def_label;
	    exp["specific", "create_efi_entry"]
		= ai["create_efi_entry"]:(exp["location"]:"" != "");
	}
*/
	// LILO and GRUB stuff

	map<string,string> old_key_to_new_global_key = $[
	    "repl_mbr" :    "generic_mbr",
	    "activate" :    "activate"
	];

	if (ai["loader_type"]:"" == "lilo" || ai["loader_type"]:"" == "grub")
	{
	    foreach (string k, ["repl_mbr", "activate", ],
            {
		if (haskey (ai, k))
		{
		    if (ai["loader_type"]:"" == "grub") {
			// NOTE: repl_mbr and activate have an effect for lilo,
			// for grub they are only accepted for backwards
			// compatibility (we use globals["generic_mbr"] and
			// globals["activate"] there); anyhow, an existing
			// new-style key in the global map from autoyast has
			// precedence over the old-style key (and will
			// overwrite this later when we import it from the ai
			// map)
			exp["specific", "global", old_key_to_new_global_key[k]:nil] =
			    (ai[k]:false) ? "true" : "false";
			y2milestone("converted old key %1 to key %2 in globals: %3",
			    k, old_key_to_new_global_key[k]:nil, exp["specific", "global"]:nil);
		    } else {
			exp["specific", k] = ai[k]:nil;
		    }

		}
            });
	    // loader_location needs other default and key
	    //
	    // NOTE: loader_device and loader_location (aka selected_location
	    // internally) have an effect for lilo, for grub loader_location is
	    // only accepted for backwards compatibility, but loader_device is
	    // ignored (FIXME: can we map this to the boot_* variables, or is
	    // the target map not yet available?)
	    // (we use globals["boot_*"] for these functions now)
	    // anyhow, an existing new-style boot_* key in the global map from
	    // autoyast has precedence over the settings from the old-style key
	    // (and it will be overwritten later when we import the boot_* keys
	    // from the ai map)
	    if ( ai["loader_type"]:"" == "grub" && haskey(ai, "location") ) {
		if ( ai["location"]:nil == "extended" )
		    exp["specific", "global", "boot_extended"] = "true";
		else if ( ai["location"]:nil == "boot" )
		    exp["specific", "global", "boot_boot"] = "true";
		else if ( ai["location"]:nil == "root" )
		    exp["specific", "global", "boot_root"] = "true";
		else if ( ai["location"]:nil == "mbr" )
		    exp["specific", "global", "boot_mbr"] = "true";
		else if ( ai["location"]:nil == "mbr_md" )
		    exp["specific", "global", "boot_mbr"] = "true";
	    } else {
		exp["loader_location"] = ai["location"]:"custom";
	    }

	    foreach (string k, [/*"loader_location",*/ "loader_device"], {
		if (haskey (ai, k))
		{
		    exp[k] = ai[k]:nil;
		}
	    });
	} // LILO and GRUB stuff

	// device map stuff
	if (size (ai["device_map"]:[]) > 0)
	{
	    list<map<string,string> > dm = ai["device_map"]:[];
	    if (dm != nil && size (dm) > 0)
	    {
		map<string,string> device_map = listmap (
		    map<string,string> entry, dm,
		{
		    string firmware = deletechars(entry["firmware"]:"", "()");

		    return $[ entry["linux"]:"" : firmware ];
		});
		exp["specific", "device_map"] = device_map;
	    }
	}

	// initrd stuff
	list<string> modlist = [];
	map<string,any> modsett = $[];
	foreach(map mod, ai["initrd_modules"]:[], ``{
	    modlist = add(modlist, mod["module"]:"");
	    modsett = add(modsett, mod["module"]:"", mod["module_args"]:$[]);
	});
        if (Mode::autoinst ())
        {
	    map current = Initrd::Export();
            y2milestone("Automatically detected initrd modules: %1", current);
	    list<string> modules = current["list"]:[];
	    map<string,any> modules_settings = current["settings"]:$[];
	    foreach (string m, modules, {
		if (! contains (modlist, m))
		{
		    // add only if it isn't present
		    modlist = add (modlist, m);
		}
		if (! haskey (modsett, m) && haskey (modules_settings, m))
		{
		    // if the argument is in profile, prefer it
		    modsett[m] = modules_settings[m]:nil;
		}
	    });
            string parameters = ai["kernel_parameters"]:"";
            if ( size(parameters) > 0)
            {
                foreach ( string parameter, splitstring(parameters, " "), {
		    list param_value_list = splitstring (parameter, "=");
		    if (size (param_value_list) > 0)
		    {
			Kernel::AddCmdLine (
			    param_value_list[0]:"",
			    param_value_list[1]:"");
		    }
		});
            }
	}

	if (size(modlist) > 0 )
	    exp["initrd"] = $[ "list": modlist, "settings" : modsett ];

	boolean old_format = false;

	// section stuff
	list<string> section_names = [];
	if (size (ai["sections"]:[]) > 0)
	{
	    foreach (any s, ai["sections"]:[], {
		if (! is (s, map<string,any>))
		    old_format = true;
	    });
	    if (! old_format)
	    {
		list<map<string,any> > sect = (list<map<string,any> >)
		    ai["sections"]:[];
		sect = UpdateImportedSections (sect);
		exp["specific", "sections"] = sect;
		section_names = maplist (map<string,any> s, sect, {
		    return s["name"]:"";
		});
	    }
	}

	// global stuff
	if ((! haskey (ai, "global")) || is (ai["global"]:nil, map))
	{
	    exp["specific", "global"] = mapmap (string k, any v,
		ai["global"]:$[],
	    {
		return $[ k : sformat ("%1", v) ];
	    });
	}
	else // old format
	{
	    old_format = true;
	}
	y2milestone ("SLES9 format detected: %1", old_format);
	if (old_format)
	{
	    // In SLES9, there were no specific tags defined for the bootloader
	    // configuration items in the <global> and <sections> scopes. All
	    // configuration lines there were put into <key> and <value> pairs,
	    // and each of these pairs were put into <(global|section)_entry>
	    // tags (see example config snippets above).
	    // Converting key/value pairs to file contents first, then setting
	    // as file contents and re-exporting the parsed file contents.

	    list<list<map> > sections = ai["sections"]:[];
	    list<map> globals = ai["global"]:[];
	    sections = prepend (sections, globals);
	    list<map> flat = flatten (sections);
	    string loader = ai["loader_type"]:"";
	    string separator = loader == "grub" ? " " : " = ";
	    list<string> lines = maplist (map f, flat, {
		return sformat ("%1%2%3",
		    f["key"]:"", separator,
		    f["value"]:nil == nil ? "" : f["value"]:nil);
	    });
	    string file = mergestring (lines, "\n");
	    BootCommon::InitializeLibrary (true, loader);
	    BootCommon::SetDeviceMap (BootStorage::device_mapping);
	    BootCommon::SetSections ([]);
	    BootCommon::SetGlobal ($[]);
	    map<string,string> files = BootCommon::GetFilesContents ();
	    map<string,string> bl2file = $[
		"grub" : "/boot/grub/menu.lst",
		"lilo" : "/etc/lilo.conf",
		// TODO the other bootloaders
	    ];
	    files[bl2file[loader]:""] = file;
	    BootCommon::SetFilesContents (files);
	    exp["specific", "global"] = BootCommon::GetGlobal ();
	    list<map<string,any> > sect = BootCommon::GetSections ();
	    sect = UpdateImportedSections (sect);
	    exp["specific", "sections"] = sect;
	    section_names = maplist (map<string,any> s, sect, {
		return s["name"]:"";
	    });
	}

	if (haskey (exp["specific", "global"]:$[], "default")
	    && ! contains (section_names,
		exp["specific", "global", "default"]:""))
	{
	    exp["specific", "global"]
		= remove (exp["specific", "global"]:$[], "default");
	}

	return exp;
    }

    /**
      * Translate the Export map to the autoinstallation map
      * @param exp a map the export map
      * @return a map the autoinstallation map
      */
    define map<string,any> Export2AI (map<string,any> exp) ``{
	// bootloader type and location stuff
	map<string,any> ai = $[
	    "loader_type" : exp["loader_type"]:"default",
	];
	map<string,string> glob = filter (string k, string v,
	    exp["specific", "global"]:$[],
	{
	    return substring (k, 0, 2) != "__";
	});
	// global options stuff
	if (size (glob) > 0)
	{
	    ai["global"] = mapmap (string k, string v, glob, {
		if (k == "timeout")
		    return (map<string,any>)$[ k : tointeger (v) ];
		else if (k == "embed_stage1.5")
		    return (map<string,any>)
			$[ k : (v == "0" || v == "") ? false : true ];
		return (map<string,any>)$[ k : v ];
	    });
	}
	// sections stuff
	ai["sections"] = maplist (map<string,any> s,
	    exp["specific", "sections"]:[],
	{
	    s = filter (string k, any v, s, {
		return substring (k, 0, 2) != "__";
	    });
	    return s;
	});
/*
	// global PPC stuff
	if (ai["loader_type"]:"" == "ppc")
	{
	    foreach (string k, ["iseries_streamfile", "iseries_write_slot_a",
		"iseries_write_slot_b", "iseries_write_streamfile",
		"iseries_write_prepboot", "prep_boot_partition",
		"of_defaultdevice", "board_type", "activate", ],
	    {
		if (haskey (exp["specific"]:$[], k))
		{
		    ai[k] = exp["specific", k]:nil;
		}
	    });
	}

	// global ELILO stuff
	if (ai["loader_type"]:"" == "elilo")
	{
	    // discards location and loader device, it is correct.
	    ai = $[
		"loader_type" : exp["loader_type"]:"",
		"efi_entry_label" : exp["location"]:"",
		"create_efi_entry" : exp["specific", "create_efi_entry"]:false,
	    ];
	}
*/
	// LILO and GRUB stuff
	if (ai["loader_type"]:"" == "lilo" || ai["loader_type"]:"" == "grub")
	{
	    // FIXME: repl_mbr and activate are obsolete for GRUB, no need to
	    // look for them in the export map any more (but does not really do
	    // any harm)
	    foreach (string k, ["repl_mbr", "activate", ],
            {
                if (haskey (exp["specific"]:$[], k))
                {
                    ai[k] = exp["specific", k]:nil;
                }
            });
	    // FIXME: loader_device and loader_location (aka selected_location
	    // internally) are obsolete for GRUB, no need to look for them in
	    // the export map any more (but does not really do any harm)
	    if (haskey (exp, "loader_location"))
		ai["location"] = exp["loader_location"]:"";
	    foreach (string k, ["loader_device"], {
		if (haskey (exp, k))
		{
		    ai[k] = exp[k]:nil;
		}
	    });
	}

	// device map stuff
	if (size (exp["specific", "device_map"]:$[]) > 0)
	{
	    map<string,string> device_map = exp["specific", "device_map"]:$[];
	    y2error ("DM: %1", device_map);
	    if (device_map != nil && size (device_map) > 0)
	    {
		list<map<string,string> > dm = maplist (
		    string linux,
		    string firmware,
		    device_map,
		{
		    return $[
			"linux" : linux,
			"firmware" : firmware,
		    ];
		});
		ai["device_map"] = dm;
	    }
	}

	// initrd stuff
	list<map> ayinitrd = maplist(string m, exp["initrd", "list"]:[], ``{
	    map tmp = $[];
	    tmp["module"] = m;
	    if (exp["initrd", "settings", m]:$[] != $[])
		tmp["module_args"] = exp["initrd", "settings", m]:$[];
	    return (tmp);
	});
	if (size(ayinitrd) > 0 )
	    ai["initrd_modules"] = ayinitrd;

	return ai;
    }

}

ACC SHELL 2018