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