ACC SHELL

Path : /usr/share/YaST2/modules/
File Upload :
Current File : //usr/share/YaST2/modules/GfxMenu.ycp

/**
 * File:
 *      modules/GfxMenu.ycp
 *
 * Module:
 *      Bootloader installation and configuration
 *
 * Summary:
 *      Routines to maintain translations in the graphical bootloader menu
 *
 * Authors:
 *      Jiri Srain <jsrain@suse.cz>
 *      Olaf Dabrunz <od@suse.de>
 *
 * $Id: GfxMenu.ycp 58175 2009-07-27 14:52:21Z juhliarik $
 *
 */

{
    module "GfxMenu";

    textdomain "bootloader";

    import "Mode";

    /** FATE#305403: Bootloader beep configuration
     * enable/disable sounds signal during boot
     */
     global boolean enable_sound_signals = false;

    /**
     * Replace every match of given regular expression in a string with a
     * replacement string
     *
     * e.g. ReplaceRegexMatch( "abcdef12ef34gh000", "[0-9]+", "_A_" ) -> "abcdef_A_ef_A_gh_A_"
     *
     * @param input string that may contain substrings matching regex
     * @param regex regular expression to search for, must not contain brackets
     * @param repl  string that replaces every substring matching the regex
     * @return string that has matches replaced
     */
    global define string ReplaceRegexMatch(string input, string regex, string repl) ``{
	if(input == nil || size(input) < 1) return "";
	string rest = input;
	string output = "";
	if( regexpmatch( rest, regex ) )
	    {
	    list p = regexppos( rest, regex );
	    do
		{
		output = output +
			 substring( rest, 0, p[0]:0 ) +
		         repl;
		rest = substring( rest, p[0]:0+p[1]:0 );
		p = regexppos( rest, regex );
		}
	    while( size(p)>0 );
	    }
	return output + rest;
    }

    /**
      * Create translated name of a section
      * @param orig string original section name
      * @param loader string bootloader type
      * @return translated section name
      */
    global define string translateSectionTitle (string orig, string loader)
    ``{
	//
	// FIXME: handling of bootloader-specific restrictions should be done
	// in perl-Bootloader
	//
        map trans = $[
	    // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
	    // are allowed, otherwise translartion won't be used
	    // try to keep short, may be shortened due to bootloader limitations
            "linux" : _("Linux"),
	    // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
	    // are allowed, otherwise translartion won't be used
	    // try to keep short, may be shortened due to bootloader limitations
            "failsafe" : _("Failsafe"),
	    // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
	    // are allowed, otherwise translartion won't be used
	    // try to keep short, may be shortened due to bootloader limitations
            "floppy" : _("Floppy"),
	    // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
	    // are allowed, otherwise translartion won't be used
	    // try to keep short, may be shortened due to bootloader limitations
            "hard disk" : _("Hard Disk"),
	    // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
	    // are allowed, otherwise translartion won't be used
	    // try to keep short, may be shortened due to bootloader limitations
            "memtest86" : _("Memory Test"),
	    // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
	    // are allowed, otherwise translartion won't be used
	    // try to keep short, may be shortened due to bootloader limitations
            "original MBR" : _("MBR before Installation"),
	    // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
	    // are allowed, otherwise translartion won't be used
	    // try to keep short, may be shortened due to bootloader limitations
            "previous" : _("Previous Kernel"),
	    // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
	    // are allowed, otherwise translartion won't be used
	    // try to keep short, may be shortened due to bootloader limitations
            "Vendor diagnostics" : _("Vendor Diagnostics"),
        ];
        map not_trans = $[
            "linux" : "Linux",
            "failsafe" : "Failsafe",
            "floppy" : "Floppy",
            "hard disk" : "Hard Disk",
            "memtest86" : "Memory Test",
            "original MBR" : "MBR before Installation",
            "windows" : "Windows",
	    "xen" : "XEN",
        ];
	string translated = trans[orig]:"\n"; // not allowed character
		// not_translated version will be used
	string filtered = filterchars (translated, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 _");
	if (size (filtered) != size (translated))
	{
	    y2warning ("Incorrect translation %1 -> %2", orig, translated);
	    return not_trans[orig]:orig;
	}
	if (loader != "grub")
	{
	    // FIXME / FEATURE: At least for IA64, there is a two level boot
	    // hierarchy (efibootmgr, elilo): the first level boot menu can be
	    // used to select a partition (i.e. an installation), the second
	    // level can be used to select a kernel/commandline set.
	    // This may become an alternative setup for grub in the future
	    // (requiring a separate menu.lst on an extra partition for the
	    // first level, along with the changes in several parts of the
	    // BootGRUB code for this).
	    // AI: rw/od should discuss this with the grub maintainer and
	    // create a feature for this.
	    //
	    // ATM, this is only available for IA64.
	    // Thus, for "elilo", the second level string should remain
	    // "linux", the product name already appears in the efi menu.
	    if (loader != "elilo" && orig == "linux")
	    {
		import "Product";
		string product = Product::short_name;
		string prod_filtered = filterchars (product, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 _.");
		if (product == prod_filtered && product != " ")
		{
		    filtered = prod_filtered;
		}
	    }
	    y2milestone ("adapting section title: %1", filtered);
	    // label tag for lilo.conf has a restricted valid character set and
	    // limited allowed string length
	    string cutoff = "";

	    // Limit length to 11 characters, but keep it "nice"
	    // 1. cut off linux- prefix if found
	    if (size(filtered) > 11) {
		cutoff = regexpsub (filtered, "^[Ll][Ii][Nn][Uu][Xx]-", "");
		if (cutoff != nil)
		    filtered = cutoff;
	    }

	    while (size(filtered) > 11) {
		// 2. cut off last word, break if no more found
		cutoff = regexpsub (filtered, "^(.*) [^ ]*$", "\\1");
		y2milestone ("cutoff is: %1", cutoff);
		if (cutoff == nil || size(cutoff) == size(filtered))
		    break;
		filtered = cutoff;
	    }
	    y2milestone ("section title without excess words: %1", filtered);

	    // 3. last resort: cutoff excess characters
	    filtered = substring (filtered, 0, 11);
	    y2milestone ("section title limited to 11 chars: %1", filtered);

	    // 4. convert not allowed chars to "_"
	    // (NOTE: this converts according to lilo requirements, ATM we do
	    // not allow ".-" above already; so ATM this converts only " ")
	    filtered = ReplaceRegexMatch (filtered, "[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.-]", "_");
	    y2milestone ("section title: filtered unallowed characters: %1", filtered);
	}
	else if (contains (["linux", "failsafe", "previous", "xen"], orig)
	    && ! Mode::test ())
	{
	    /* for bootloaders that support long section names, like grub: */
	    import "Product";
	    string product = Product::name;
	    string prod_filtered = filterchars (product, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 _.");
	    if (product != nil && product == prod_filtered && product != " " && product != "")
	    {
		if (orig == "linux")
		{
		    filtered = prod_filtered;
		}
		else
		{
		    filtered = sformat ("%1 -- %2", filtered, prod_filtered);
		}
	    }
	}
	return filtered;
    }

    /**
     * Get translated section names, including diacritics
     * @param loader string bootloader type
     * @return a map section names translations
     */
    global define map<string,string> getTranslationsToDiacritics (string loader) ``{
        map<string,string> trans = $[
	    // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
	    // are allowed. Always remove the leading '_', its just to
	    // be able to have translations with and without diacritics
	    // please use diacritics here
            "linux" : _("_Linux"),
	    // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
	    // are allowed. Always remove the leading '_', its just to
	    // be able to have translations with and without diacritics
	    // please use diacritics here
            "failsafe" : _("_Failsafe"),
	    // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
	    // are allowed. Always remove the leading '_', its just to
	    // be able to have translations with and without diacritics
	    // please use diacritics here
            "floppy" : _("_Floppy"),
	    // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
	    // are allowed. Always remove the leading '_', its just to
	    // be able to have translations with and without diacritics
	    // please use diacritics here
            "hard disk" : _("_Hard Disk"),
	    // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
	    // are allowed. Always remove the leading '_', its just to
	    // be able to have translations with and without diacritics
	    // please use diacritics here
            "memtest86" : _("_Memory Test"),
	    // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
	    // are allowed. Always remove the leading '_', its just to
	    // be able to have translations with and without diacritics
	    // please use diacritics here
            "original MBR" : _("_MBR before Installation"),
	    // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
	    // are allowed. Always remove the leading '_', its just to
	    // be able to have translations with and without diacritics
	    // please use diacritics here
            "previous" : _("_Previous Kernel"),
	    // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
	    // are allowed. Always remove the leading '_', its just to
	    // be able to have translations with and without diacritics
	    // please use diacritics here
            "Vendor diagnostics" : _("_Vendor Diagnostics"),
	    "xen" : "XEN",
        ];
/*	trans = filter (string k, string v, trans, {
	    if (substring (v, 0, 1) == "_")
	    {
		y2warning ("Translation %1 contains leading underscore", v);
		return false;
	    }
	    return true;
	});*/
	trans = mapmap (string k, string v, trans, {
	    if (substring (v, 0, 1) == "_")
		v = substring (v, 1);
	    return $[ k : v ];
	});
	map<string,string> ret = mapmap (string k, string v, trans, {
	    string il1 = translateSectionTitle (k, loader);
	    if (contains (["linux", "failsafe", "previous", "xen"], k) && ! Mode::test ())
	    {
		import "Product";
		string product = Product::name;
		if (product != " " && product != "" && product != nil)
		{
		    if (k == "linux")
		    {
			v = product;
		    }
		    else
		    {
			v = sformat ("%1 (%2)", product, v);
		    }
		}
	    }
	    return $[il1 : v];
	});
	return ret;
    }

/** FATE#305403: Bootloader beep configuration
 * Read status of acoustic signals
 * set global variable enable_sound_signals
 *
 */

global void ReadStatusAcousticSignal ()
{
    integer ret = -1; // off

    string command = "gfxboot --show-config | grep beep=";
    map out = (map)SCR::Execute (.target.bash_output, command);

    y2milestone("Comand: %1 return: %2",command, out);
    if (out["exit"]:-1 == 0)
    {
	string result = out["stdout"]:"";
	list <string> l_result = splitstring(result, "\n");
	if (l_result[1]:"" == "beep=1")
	    ret = 1;
	else
	    ret = 0;

    } else {
	y2error("Calling command: %1 failed", command);
    }
    if (ret == 1)
	enable_sound_signals = true;
    else
	enable_sound_signals = false;

    y2milestone("Status of acoustic signals is (on==true/off==false): %1", enable_sound_signals);
}


/** FATE#305403: Bootloader beep configuration
 * Write settings for acoustic signals
 *
 * @param boolean true -> enable acoustic signals or disable
 */
void WriteAcousticSignal(boolean enable)
{
    string command = "gfxboot --change-config boot::beep=0";
    if (enable)
    {
	y2milestone("Enable acoustic signals for boot menu");
	command = "gfxboot --change-config boot::beep=1";
    } else {
	y2milestone("Disable acoustic signals for boot menu");
    }
    map ret = (map)SCR::Execute (.target.bash_output, command);
    y2milestone ("Result of command: %1 result: %2",command, ret);
}


/**
 * Update graphical bootloader to contain translations for section labels in
 * the currently selected installation language (set in
 * /etc/sysconfig/language, RC_LANG)
 * And make the selected installation language default
 * @param loader string bootloader type
 * @return boolean true on success
 */
global define boolean UpdateGfxMenuContents (string loader) {
    y2milestone ("Updating GFX boot menu");

    // FATE#305403: Bootloader beep configuration
    WriteAcousticSignal(enable_sound_signals);
    // if the boot menu does not exist, return without updating it
    if (SCR::Read (.target.size, "/boot/message") == -1)
	return true;
    if (SCR::Read (.target.size, "/etc/sysconfig/bootsplash") == -1)
	return true;

    // get a list containing the system default language and the installed languages
    // get the current language
    string main_lang = (string)SCR::Read (.sysconfig.language.RC_LANG);
    string langs = (string)
	SCR::Read (.sysconfig.language.INSTALLED_LANGUAGES);
    if (langs == nil)
	langs = "";
    list<string> languages = splitstring (langs, ",");
    languages = prepend (languages, main_lang);
    languages = filter (string l, languages, {return l != nil;});
    // if no languages are installed and no main language is defined, we can do
    // nothing: simply return
    if (size (languages) == 0)
	return true;

    // if no boot theme is defined, we cannot create the GfxMenu: just leave
    string boot_theme = (string)SCR::Read (.sysconfig.bootsplash.THEME);
    if (boot_theme == nil)
	return true;


    // in the list of the system default language and the installed languages
    // find the subset that is supported by either a help text or a translation
    // file (for the GUI messages) or both
    // results:
    // selected    -- list of supported languages (both long form (de_DE) and short form (de))
    // lang_params -- string of supported languages (both long form (de_DE) and short form (de))

    // get names of available languages
    string data_dir = sformat ("/etc/bootsplash/themes/%1/bootloader",
	boot_theme);
    list<string> files = (list<string>)SCR::Read (.target.dir, data_dir);
    list<string> helps = filter (string f, files, {
	return regexpmatch (f, "\\.hlp$");
    });
    list<string> texts = filter (string f, files, {
	return regexpmatch (f, "\\.tr$");
    });
    helps = maplist (string h, helps, ``(substring (h, 0, 2)));
    texts = maplist (string t, texts, ``(substring (t, 0, 2)));
    y2milestone ("Texts available for %1", sort (texts));
    y2milestone ("Helps available for %1", sort (helps));

    string tmpdir = (string)SCR::Read (.target.tmpdir);
    string lang_params = "";
    boolean lang_supported = true;

    list<string> selected = [];
    foreach (string lang, languages, {
	list<string> l = splitstring (lang, ".");
	lang = l[0]:"";
	y2milestone ("Selected language for booting menu: %1", lang);
	l = splitstring (lang, "_");
	string lang_short = l[0]:"";
	// check if lang is supported by a help text and/or a GUI message
	// translation file
	if (! (contains (helps, lang_short) || contains (texts, lang_short)))
	{
	    y2milestone ("Language %1 is not supported by gfxmenu", lang_short);
	    // rather avoid all translations; non-supported characters don't show
	    // in the future, the menu should be translated into selected language,
	    // not only into the system language
	    lang_supported = false;
	}
	else if (! (contains (selected, lang)
		    || contains (selected, lang_short)))
	{
	    lang_params = sformat ("%1 %2 %3", lang_params, lang, lang_short);
	    selected = add (selected, lang);
	    selected = add (selected, lang_short);
	}
    });

    // create translation map (in temp file) for the currently active language
    // for gettext (AFAICT), i.e. whatever is found in LANG or LC_MESSAGES --
    // this should be RC_LANG
    string trans_file = sformat ("%1/boot_translations", tmpdir);
    map<string,string> trans_map = getTranslationsToDiacritics (loader);
    list<string> trans_list = maplist (string k, string v, trans_map, {
	return sformat ("%1\n%2", k, v);
    });
    string trans_str = mergestring (trans_list, "\n");
    trans_str = trans_str + "\n";
    if (! lang_supported)
    {
	y2milestone ("Avoiding providing bootloader menu translations");
	trans_str = "";
    }
    SCR::Write (.target.string, trans_file, trans_str);
    if (lang_params == "")
	lang_params = "en_EN en";

    // update the boot message (/boot/message cpio archive) with menu entry
    // translation file (trans_file) and translation files for help texts and
    // UI texts
    //  - currently (2006/09) update_gfxmenu includes the hlp and tr files only
    //    for the first language (e.g. "de_DE de") from lang_params, the others
    //    are ignored
    //  - tr and hlp files that match the long language name ("de_DE") are
    //    preferred over files that contain only the short language name
    //  - English ("en") is always included in the list of selectable
    //    languages, and the English tr and hlp files are never removed from
    //    the message archive
    string command = sformat (
	"/usr/lib/YaST2/bin/update_gfxmenu %1 %2 %3 %4",
	tmpdir, data_dir, trans_file, lang_params);

    y2milestone ("Running command %1", command);
    map ret = (map)SCR::Execute (.target.bash_output, command);
    y2milestone ("GFXMenu update result: %1", ret);
    return ret["exit"]:0 == 0;
}

/**
 * Updates GFX menu without requiring any information, reads loader type
 * from sysconfig, calls /sbin/lilo if LILO is being used directly
 * @return boolean true on success
 */
global boolean Update() {
    string loader = (string)SCR::Read (.sysconfig.bootloader.LOADER_TYPE);
    if (! UpdateGfxMenuContents (loader))
	return false;

    if (loader == "lilo")
    {
	map out = (map)SCR::Execute (.target.bash_output, "/sbin/lilo");
	if (out["exit"]:0 != 0)
	{
	    y2error ("Output of /sbin/lilo: %1", out);
	    return false;
	}
    }
    return true;
}










} //end of module

ACC SHELL 2018