home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / boot / i386 / root / usr / share / YaST2 / modules / GfxMenu.ycp < prev    next >
Text File  |  2006-11-29  |  17KB  |  438 lines

  1. /**
  2.  * File:
  3.  *      modules/GfxMenu.ycp
  4.  *
  5.  * Module:
  6.  *      Bootloader installation and configuration
  7.  *
  8.  * Summary:
  9.  *      Routines to maintain translations in the graphical bootloader menu
  10.  *
  11.  * Authors:
  12.  *      Jiri Srain <jsrain@suse.cz>
  13.  *      Olaf Dabrunz <od@suse.de>
  14.  *
  15.  * $Id: GfxMenu.ycp 33445 2006-10-16 22:33:57Z odabrunz $
  16.  *
  17.  */
  18.  
  19. {
  20.     module "GfxMenu";
  21.  
  22.     textdomain "bootloader";
  23.  
  24.     import "Mode";
  25.  
  26.     /**
  27.      * Replace every match of given regular expression in a string with a
  28.      * replacement string
  29.      *
  30.      * e.g. ReplaceRegexMatch( "abcdef12ef34gh000", "[0-9]+", "_A_" ) -> "abcdef_A_ef_A_gh_A_"
  31.      *
  32.      * @param input string that may contain substrings matching regex
  33.      * @param regex regular expression to search for, must not contain brackets
  34.      * @param repl  string that replaces every substring matching the regex
  35.      * @return string that has matches replaced
  36.      */
  37.     global define string ReplaceRegexMatch(string input, string regex, string repl) ``{
  38.     if(input == nil || size(input) < 1) return "";
  39.     string rest = input;
  40.     string output = "";
  41.     if( regexpmatch( rest, regex ) )
  42.         {
  43.         list p = regexppos( rest, regex );
  44.         do
  45.         {
  46.         output = output +
  47.              substring( rest, 0, p[0]:0 ) +
  48.                  repl;
  49.         rest = substring( rest, p[0]:0+p[1]:0 );
  50.         p = regexppos( rest, regex );
  51.         }
  52.         while( size(p)>0 );
  53.         }
  54.     return output + rest;
  55.     }
  56.  
  57.     /**
  58.       * Create translated name of a section
  59.       * @param orig string original section name
  60.       * @param loader string bootloader type
  61.       * @return translated section name
  62.       */
  63.     global define string translateSectionTitle (string orig, string loader)
  64.     ``{
  65.     //
  66.     // FIXME: handling of bootloader-specific restrictions should be done
  67.     // in perl-Bootloader
  68.     //
  69.         map trans = $[
  70.         // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
  71.         // are allowed, otherwise translartion won't be used
  72.         // try to keep short, may be shortened due to bootloader limitations
  73.             "linux" : _("Linux"),
  74.         // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
  75.         // are allowed, otherwise translartion won't be used
  76.         // try to keep short, may be shortened due to bootloader limitations
  77.             "failsafe" : _("Failsafe"),
  78.         // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
  79.         // are allowed, otherwise translartion won't be used
  80.         // try to keep short, may be shortened due to bootloader limitations
  81.             "floppy" : _("Floppy"),
  82.         // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
  83.         // are allowed, otherwise translartion won't be used
  84.         // try to keep short, may be shortened due to bootloader limitations
  85.             "hard disk" : _("Hard Disk"),
  86.         // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
  87.         // are allowed, otherwise translartion won't be used
  88.         // try to keep short, may be shortened due to bootloader limitations
  89.             "memtest86" : _("Memory Test"),
  90.         // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
  91.         // are allowed, otherwise translartion won't be used
  92.         // try to keep short, may be shortened due to bootloader limitations
  93.             "original MBR" : _("MBR before Installation"),
  94.         // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
  95.         // are allowed, otherwise translartion won't be used
  96.         // try to keep short, may be shortened due to bootloader limitations
  97.             "previous" : _("Previous Kernel"),
  98.         // entry of bootloader menu - only a-z, A-Z, 0-9, _ and blank space
  99.         // are allowed, otherwise translartion won't be used
  100.         // try to keep short, may be shortened due to bootloader limitations
  101.             "Vendor diagnostics" : _("Vendor Diagnostics"),
  102.         ];
  103.         map not_trans = $[
  104.             "linux" : "Linux",
  105.             "failsafe" : "Failsafe",
  106.             "floppy" : "Floppy",
  107.             "hard disk" : "Hard Disk",
  108.             "memtest86" : "Memory Test",
  109.             "original MBR" : "MBR before Installation",
  110.             "windows" : "Windows",
  111.         "xen" : "XEN",
  112.         ];
  113.     string translated = trans[orig]:"\n"; // not allowed character
  114.         // not_translated version will be used
  115.     string filtered = filterchars (translated, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 _");
  116.     if (size (filtered) != size (translated))
  117.     {
  118.         y2warning ("Incorrect translation %1 -> %2", orig, translated);
  119.         return not_trans[orig]:orig;
  120.     }
  121.     if (loader != "grub")
  122.     {
  123.         // FIXME / FEATURE: At least for IA64, there is a two level boot
  124.         // hierarchy (efibootmgr, elilo): the first level boot menu can be
  125.         // used to select a partition (i.e. an installation), the second
  126.         // level can be used to select a kernel/commandline set.
  127.         // This may become an alternative setup for grub in the future
  128.         // (requiring a separate menu.lst on an extra partition for the
  129.         // first level, along with the changes in several parts of the
  130.         // BootGRUB code for this).
  131.         // AI: rw/od should discuss this with the grub maintainer and
  132.         // create a feature for this.
  133.         //
  134.         // ATM, this is only available for IA64.
  135.         // Thus, for "elilo", the second level string should remain
  136.         // "linux", the product name already appears in the efi menu.
  137.         if (loader != "elilo" && orig == "linux")
  138.         {
  139.         import "Product";
  140.         string product = Product::short_name;
  141.         string prod_filtered = filterchars (product, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 _.");
  142.         if (product == prod_filtered && product != " ")
  143.         {
  144.             filtered = prod_filtered;
  145.         }
  146.         }
  147.         y2milestone ("adapting section title: %1", filtered);
  148.         // label tag for lilo.conf has a restricted valid character set and
  149.         // limited allowed string length
  150.         string cutoff = "";
  151.  
  152.         // Limit length to 11 characters, but keep it "nice"
  153.         // 1. cut off linux- prefix if found
  154.         if (size(filtered) > 11) {
  155.         cutoff = regexpsub (filtered, "^[Ll][Ii][Nn][Uu][Xx]-", "");
  156.         if (cutoff != nil)
  157.             filtered = cutoff;
  158.         }
  159.  
  160.         while (size(filtered) > 11) {
  161.         // 2. cut off last word, break if no more found
  162.         cutoff = regexpsub (filtered, "^(.*) [^ ]*$", "\\1");
  163.         y2milestone ("cutoff is: %1", cutoff);
  164.         if (cutoff == nil || size(cutoff) == size(filtered))
  165.             break;
  166.         filtered = cutoff;
  167.         }
  168.         y2milestone ("section title without excess words: %1", filtered);
  169.  
  170.         // 3. last resort: cutoff excess characters
  171.         filtered = substring (filtered, 0, 11);
  172.         y2milestone ("section title limited to 11 chars: %1", filtered);
  173.  
  174.         // 4. convert not allowed chars to "_"
  175.         // (NOTE: this converts according to lilo requirements, ATM we do
  176.         // not allow ".-" above already; so ATM this converts only " ")
  177.         filtered = ReplaceRegexMatch (filtered, "[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.-]", "_");
  178.         y2milestone ("section title: filtered unallowed characters: %1", filtered);
  179.     }
  180.     else if (contains (["linux", "failsafe", "previous", "xen"], orig)
  181.         && ! Mode::test ())
  182.     {
  183.         /* for bootloaders that support long section names, like grub: */
  184.         import "Product";
  185.         string product = Product::name;
  186.         string prod_filtered = filterchars (product, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 _.");
  187.         if (product == prod_filtered && product != " ")
  188.         {
  189.         if (orig == "linux")
  190.         {
  191.             filtered = prod_filtered;
  192.         }
  193.         else
  194.         {
  195.             filtered = sformat ("%1 -- %2", filtered, prod_filtered);
  196.         }
  197.         }
  198.     }
  199.     return filtered;
  200.     }
  201.  
  202.     /**
  203.      * Get translated section names, including diacritics
  204.      * @param loader string bootloader type
  205.      * @return a map section names translations
  206.      */
  207.     global define map<string,string> getTranslationsToDiacritics (string loader) ``{
  208.         map<string,string> trans = $[
  209.         // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
  210.         // are allowed. Always remove the leading '_', its just to
  211.         // be able to have translations with and without diacritics
  212.         // please use diacritics here
  213.             "linux" : _("_Linux"),
  214.         // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
  215.         // are allowed. Always remove the leading '_', its just to
  216.         // be able to have translations with and without diacritics
  217.         // please use diacritics here
  218.             "failsafe" : _("_Failsafe"),
  219.         // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
  220.         // are allowed. Always remove the leading '_', its just to
  221.         // be able to have translations with and without diacritics
  222.         // please use diacritics here
  223.             "floppy" : _("_Floppy"),
  224.         // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
  225.         // are allowed. Always remove the leading '_', its just to
  226.         // be able to have translations with and without diacritics
  227.         // please use diacritics here
  228.             "hard disk" : _("_Hard Disk"),
  229.         // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
  230.         // are allowed. Always remove the leading '_', its just to
  231.         // be able to have translations with and without diacritics
  232.         // please use diacritics here
  233.             "memtest86" : _("_Memory Test"),
  234.         // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
  235.         // are allowed. Always remove the leading '_', its just to
  236.         // be able to have translations with and without diacritics
  237.         // please use diacritics here
  238.             "original MBR" : _("_MBR before Installation"),
  239.         // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
  240.         // are allowed. Always remove the leading '_', its just to
  241.         // be able to have translations with and without diacritics
  242.         // please use diacritics here
  243.             "previous" : _("_Previous Kernel"),
  244.         // entry of bootloader menu - only ISO 8859-1, -2 and -15 characters
  245.         // are allowed. Always remove the leading '_', its just to
  246.         // be able to have translations with and without diacritics
  247.         // please use diacritics here
  248.             "Vendor diagnostics" : _("_Vendor Diagnostics"),
  249.         "xen" : "XEN",
  250.         ];
  251. /*    trans = filter (string k, string v, trans, {
  252.         if (substring (v, 0, 1) == "_")
  253.         {
  254.         y2warning ("Translation %1 contains leading underscore", v);
  255.         return false;
  256.         }
  257.         return true;
  258.     });*/
  259.     trans = mapmap (string k, string v, trans, {
  260.         if (substring (v, 0, 1) == "_")
  261.         v = substring (v, 1);
  262.         return $[ k : v ];
  263.     });
  264.     map<string,string> ret = mapmap (string k, string v, trans, {
  265.         string il1 = translateSectionTitle (k, loader);
  266.         if (contains (["linux", "failsafe", "previous", "xen"], k) && ! Mode::test ())
  267.         {
  268.         import "Product";
  269.         string product = Product::name;
  270.         if (product != " ")
  271.         {
  272.             if (k == "linux")
  273.             {
  274.             v = product;
  275.             }
  276.             else
  277.             {
  278.             v = sformat ("%1 (%2)", product, v);
  279.             }
  280.         }
  281.         }
  282.         return $[il1 : v];
  283.     });
  284.     return ret;
  285.     }
  286.  
  287. /**
  288.  * Update graphical bootloader to contain translations for section labels in
  289.  * the currently selected installation language (set in
  290.  * /etc/sysconfig/language, RC_LANG)
  291.  * And make the selected installation language default
  292.  * @param loader string bootloader type
  293.  * @return boolean true on success
  294.  */
  295. global define boolean UpdateGfxMenuContents (string loader) {
  296.     y2milestone ("Updating GFX boot menu");
  297.     // if the boot menu does not exist, return without updating it
  298.     if (SCR::Read (.target.size, "/boot/message") == -1)
  299.     return true;
  300.     if (SCR::Read (.target.size, "/etc/sysconfig/bootsplash") == -1)
  301.     return true;
  302.  
  303.     // get a list containing the system default language and the installed languages
  304.     // get the current language
  305.     string main_lang = (string)SCR::Read (.sysconfig.language.RC_LANG);
  306.     string langs = (string)
  307.     SCR::Read (.sysconfig.language.INSTALLED_LANGUAGES);
  308.     if (langs == nil)
  309.     langs = "";
  310.     list<string> languages = splitstring (langs, ",");
  311.     languages = prepend (languages, main_lang);
  312.     languages = filter (string l, languages, {return l != nil;});
  313.     // if no languages are installed and no main language is defined, we can do
  314.     // nothing: simply return
  315.     if (size (languages) == 0)
  316.     return true;
  317.  
  318.     // if no boot theme is defined, we cannot create the GfxMenu: just leave
  319.     string boot_theme = (string)SCR::Read (.sysconfig.bootsplash.THEME);
  320.     if (boot_theme == nil)
  321.     return true;
  322.  
  323.  
  324.     // in the list of the system default language and the installed languages
  325.     // find the subset that is supported by either a help text or a translation
  326.     // file (for the GUI messages) or both
  327.     // results:
  328.     // selected    -- list of supported languages (both long form (de_DE) and short form (de))
  329.     // lang_params -- string of supported languages (both long form (de_DE) and short form (de))
  330.  
  331.     // get names of available languages
  332.     string data_dir = sformat ("/etc/bootsplash/themes/%1/bootloader",
  333.     boot_theme);
  334.     list<string> files = (list<string>)SCR::Read (.target.dir, data_dir);
  335.     list<string> helps = filter (string f, files, {
  336.     return regexpmatch (f, "\\.hlp$");
  337.     });
  338.     list<string> texts = filter (string f, files, {
  339.     return regexpmatch (f, "\\.tr$");
  340.     });
  341.     helps = maplist (string h, helps, ``(substring (h, 0, 2)));
  342.     texts = maplist (string t, texts, ``(substring (t, 0, 2)));
  343.     y2milestone ("Texts available for %1", sort (texts));
  344.     y2milestone ("Helps available for %1", sort (helps));
  345.  
  346.     string tmpdir = (string)SCR::Read (.target.tmpdir);
  347.     string lang_params = "";
  348.  
  349.     list<string> selected = [];
  350.     foreach (string lang, languages, {
  351.     list<string> l = splitstring (lang, ".");
  352.     lang = l[0]:"";
  353.     y2milestone ("Selected language for booting menu: %1", lang);
  354.     l = splitstring (lang, "_");
  355.     string lang_short = l[0]:"";
  356.     // check if lang is supported by a help text and/or a GUI message
  357.     // translation file
  358.     if (! (contains (helps, lang_short) || contains (texts, lang_short)))
  359.     {
  360.         y2milestone ("Language %1 is not supported by gfxmenu", lang_short);
  361.     }
  362.     else if (! (contains (selected, lang)
  363.             || contains (selected, lang_short)))
  364.     {
  365.         lang_params = sformat ("%1 %2 %3", lang_params, lang, lang_short);
  366.         selected = add (selected, lang);
  367.         selected = add (selected, lang_short);
  368.     }
  369.     });
  370.  
  371.     // create translation map (in temp file) for the currently active language
  372.     // for gettext (AFAICT), i.e. whatever is found in LANG or LC_MESSAGES --
  373.     // this should be RC_LANG
  374.     string trans_file = sformat ("%1/boot_translations", tmpdir);
  375.     map<string,string> trans_map = getTranslationsToDiacritics (loader);
  376.     list<string> trans_list = maplist (string k, string v, trans_map, {
  377.     return sformat ("%1\n%2", k, v);
  378.     });
  379.     string trans_str = mergestring (trans_list, "\n");
  380.     trans_str = trans_str + "\n";
  381.     SCR::Write (.target.string, trans_file, trans_str);
  382.     if (lang_params == "")
  383.     lang_params = "en_EN en";
  384.  
  385.     // update the boot message (/boot/message cpio archive) with menu entry
  386.     // translation file (trans_file) and translation files for help texts and
  387.     // UI texts
  388.     //  - currently (2006/09) update_gfxmenu includes the hlp and tr files only
  389.     //    for the first language (e.g. "de_DE de") from lang_params, the others
  390.     //    are ignored
  391.     //  - tr and hlp files that match the long language name ("de_DE") are
  392.     //    preferred over files that contain only the short language name
  393.     //  - English ("en") is always included in the list of selectable
  394.     //    languages, and the English tr and hlp files are never removed from
  395.     //    the message archive
  396.     string command = sformat (
  397.     "/usr/lib/YaST2/bin/update_gfxmenu %1 %2 %3 %4",
  398.     tmpdir, data_dir, trans_file, lang_params);
  399.  
  400.     y2milestone ("Running command %1", command);
  401.     map ret = (map)SCR::Execute (.target.bash_output, command);
  402.     y2milestone ("GFXMenu update result: %1", ret);
  403.     return ret["exit"]:0 == 0;
  404. }
  405.  
  406. /**
  407.  * Updates GFX menu without requiring any information, reads loader type
  408.  * from sysconfig, calls /sbin/lilo if LILO is being used directly
  409.  * @return boolean true on success
  410.  */
  411. global boolean Update() {
  412.     string loader = (string)SCR::Read (.sysconfig.bootloader.LOADER_TYPE);
  413.     if (! UpdateGfxMenuContents (loader))
  414.     return false;
  415.  
  416.     if (loader == "lilo")
  417.     {
  418.     map out = (map)SCR::Execute (.target.bash_output, "/sbin/lilo");
  419.     if (out["exit"]:0 != 0)
  420.     {
  421.         y2error ("Output of /sbin/lilo: %1", out);
  422.         return false;
  423.     }
  424.     }
  425.     return true;
  426. }
  427.  
  428.  
  429.  
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437. } //end of module
  438.