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 / BootGRUB.ycp < prev    next >
Text File  |  2006-11-29  |  26KB  |  866 lines

  1. /**
  2.  * File:
  3.  *      modules/BootGRUB.ycp
  4.  *
  5.  * Module:
  6.  *      Bootloader installation and configuration
  7.  *
  8.  * Summary:
  9.  *      Module containing specific functions for GRUB configuration
  10.  *      and installation
  11.  *
  12.  * Authors:
  13.  *      Jiri Srain <jsrain@suse.cz>
  14.  *      Joachim Plack <jplack@suse.de>
  15.  *
  16.  * $Id: BootGRUB.ycp 34514 2006-11-21 09:17:32Z jplack $
  17.  *
  18.  */
  19.  
  20. {
  21. module "BootGRUB";
  22.  
  23. textdomain "bootloader";
  24.  
  25. import "Arch";
  26. import "BootCommon";
  27. import "Kernel";
  28. import "Mode";
  29. import "Stage";
  30. import "Storage";
  31. import "StorageDevices";
  32. import "Pkg";
  33. import "HTML";
  34.  
  35. // private variables
  36.  
  37. /**
  38.   * Shall proposal merge menus?
  39.   */
  40. global symbol merge_level = `main;
  41. /**
  42.   * Insert saved MBR to bootloader menu?
  43.   */
  44. global boolean insert_saved_mbr = false;
  45.  
  46. // variables for temporary data
  47.  
  48. /**
  49.   * Disks order for ordering widget purproses
  50.   */
  51. global list<string> disks_order = nil;
  52.  
  53. // function prototypes
  54.  
  55. global boolean backup_to_bootsector = true;
  56.  
  57. // includes
  58.  
  59. include "bootloader/grub/misc.ycp";
  60. include "bootloader/routines/popups.ycp";
  61. include "bootloader/grub/helps.ycp";
  62. include "bootloader/generic/dialogs.ycp";
  63.  
  64.  
  65. // end of mandatory functions
  66. //----------------------------------------------------------------------------
  67.  
  68.  
  69. // wrapper function to adjuct to new grub name sceme
  70. global map<string,any> CreateLinuxSection (string title) {
  71.     map<string,any> section =
  72.       BootCommon::CreateLinuxSection (title);
  73.  
  74.     // replace "kernel" by "image"
  75.     if (haskey(section, "kernel")) {
  76.       section["image"] = section["kernel"]:"";
  77.       section = remove(section, "kernel");
  78.     }
  79.     // replace "vga" by "vgamode"
  80.     if (haskey(section, "vga")) {
  81.       section["vgamode"] = section["vga"]:"";
  82.       section = remove(section, "vga");
  83.     }
  84.  
  85.     return section;
  86. }
  87.  
  88.  
  89.  
  90. /**
  91.   * Propose sections to bootloader menu
  92.   * modifies internal structures
  93.   */
  94. global define void CreateSections () ``{
  95.     y2debug ("Creating GRUB sections from scratch");
  96.     list<map<string,any> > out = [
  97.     CreateLinuxSection ("linux"),
  98.     ];
  99.     if (BootCommon::XenPresent ())
  100.         out = add (out, CreateLinuxSection ("xen"));
  101.     list<string> others_ignore = [];
  102.     list<string> others = (list<string>)Storage::GetForeignPrimary();
  103.     y2debug ("Other primaries: %1", others);
  104.     list<map> other_l = (list<map>)Storage::GetOtherLinuxPartitions();
  105.     y2debug ("Other linux parts: %1", other_l);
  106.     list<string> destroyed_partitions
  107.         = BootCommon::getPartitionList (`destroyed);
  108.  
  109.     string tmpdir = (string)SCR::Read (.target.tmpdir) + "/bldetect/";
  110.  
  111.     if (merge_level != `none && other_l != nil && size (other_l) > 0
  112.     && 0 == SCR::Execute (.target.bash,
  113.        sformat ("test -d %1 || /bin/mkdir %1", tmpdir))
  114.     )
  115.     {
  116.         y2milestone ("Detecting other Linux parts");
  117.     list filesystems = maplist (map p, other_l,
  118.                     ``(p["used_fs"]:(any)""));
  119.     filesystems = toset (filter (any f, filesystems, ``(f != "")));
  120.     filesystems = filter (any f, filesystems, ``(f != `ext2));
  121.     y2debug ("Have to modprobe %1", filesystems);
  122.     foreach (any f, filesystems, {
  123.         map fsmods = $[
  124.         `ext2 : "",
  125.         `ext3 : "ext3",
  126.         `reiser : "reiserfs",
  127.         `xfs : "xfs",
  128.         `jfs : "jfs"
  129.         ];
  130.         string modname = fsmods[f]:"";
  131.         y2debug ("Module name is %1", modname);
  132.         if (modname != "")
  133.         {
  134.         integer r = (integer)SCR::Execute (.target.bash,
  135.             sformat ("/sbin/modprobe %1", modname));
  136.         y2debug ("result of loading %1 is %2", modname, r);
  137.         }
  138.     });
  139.     BootCommon::InitializeLibrary (true, "grub");
  140.     foreach (map o, other_l, {
  141.         string dev = o["device"]:"";
  142.         if (dev != "" && 0 == SCR::Execute (.target.bash,
  143.             sformat ("/bin/mount %1 %2", dev, tmpdir))
  144.         )
  145.         {
  146.             y2milestone ("Mounted %1", dev);
  147.         list<string> filenames = [];
  148.         foreach (string fn, [
  149. // not needed since there is a symlink in /boot directory
  150. // named boot pointing to the /boot directory
  151. // this caused bug #23346 - the file was found twice
  152. //            tmpdir + "grub/menu.lst",
  153.             tmpdir + "boot/grub/menu.lst"
  154.             ], {
  155.             if (-1 != (integer)SCR::Read (.target.size, fn))
  156.                 filenames = add (filenames, fn);
  157.         });
  158.         y2milestone ("Found files %1", filenames);
  159.         integer count = 0;
  160.         foreach (string f, filenames, {
  161.             y2debug ("Checking file %1", f);
  162.             string fc = (string)SCR::Read (.target.string, f);
  163.             string dm = (string)SCR::Read (.target.string,
  164.             regexpsub (f, "(.*)menu.lst$",
  165.                    "\\1device.map"));
  166.             y2debug ("Device map file name: %1",
  167.                  regexpsub (f, "(.*)menu.lst$",
  168.                     "\\1device.map"));
  169.             y2debug ("Device map contents: %1", dm);
  170.             map<string,string> files = $[
  171.                          "/boot/grub/menu.lst" : fc,
  172.                          ];
  173.             if (dm == nil)
  174.                 return;
  175.  
  176.             files["/boot/grub/device.map"] = dm;
  177.             BootCommon::InitializeLibrary (false, "grub");
  178.             BootCommon::SetFilesContents (files);
  179.             list<map<string,string> > sects
  180.                 = BootCommon::GetSections ();
  181.             y2debug ("Found sections %1", sects);
  182.             if (merge_level == `main)
  183.             {
  184.                 sects = filter (map<string,string> s, sects, {
  185.                 return s["initial"]:nil != nil;
  186.             });
  187.             }
  188.             count = count + size (sects);
  189.             foreach (map<string,any> s, sects, ``{
  190.                 s = (map<string,any>)union (s, $[
  191.                 "__changed" : false,
  192.                 "__auto" : true,
  193.                 "__converted" : true,
  194.             ]);
  195.             // no need to translate here...
  196.             s["name"] = sformat ("%2 (%1)",
  197.                 dev, s["name"]:"");
  198.             s["original_name"] = s["name"]:"";
  199.             list<string> devs = [dev];
  200.             list<string> _dp = [];
  201.  
  202.             string _d = s["root"]:"";
  203.             if (_d != nil && _d != "")
  204.                 devs = add (devs, _d);
  205.             devs = (list<string>)filter (string d, devs,
  206.                 ``(d != ""
  207.                    && d != nil
  208.                    && d != "/dev/null" && d != "false"));
  209.             devs = toset (devs);
  210.             devs = maplist (string d, devs, {
  211.                 return BootCommon::UpdateDevice (d);
  212.             });
  213.             boolean _add = true;
  214.             foreach (string _d, devs, {
  215.                 if (contains (destroyed_partitions, _d))
  216.                     _add = false;
  217.             });
  218.             if (_add)
  219.             {
  220.                 s["__devs"] = devs;
  221.                 out = add (out, s);
  222.             }
  223.             });
  224.         });
  225.         if (count > 0)
  226.             others_ignore = add (others_ignore, dev);
  227.  
  228.         SCR::Execute (.target.bash, sformat (
  229.             "/bin/umount %1", dev));
  230.         }
  231.     });
  232.     SCR::Execute (.target.bash, sformat ("/bin/rmdir %1", tmpdir));
  233.     }
  234.  
  235.     if (others != nil && (size (others) > 0)) {
  236.     foreach (string o, others, {
  237.         list parts = splitstring (o, " ");
  238.         while (parts[0]:" " == "")
  239.           parts = remove (parts, 0);
  240.         string dev = parts[0]:"";
  241.         y2milestone ("Checking other partition %1", dev);
  242.         if (! contains (others_ignore, dev)) {
  243.             parts = remove (parts, 0);
  244.         string label = mergestring ((list<string>)parts, " ");
  245.  
  246.         // don't add rewritten location (#19990)
  247.         if (dev != "" && label != ""
  248.             && dev != BootCommon::loader_device
  249.             && (
  250.             BootCommon::AddFirmwareToBootloader (
  251.                                  BootCommon::mbrDisk)
  252.             || (label != "Vendor diagnostics"
  253.                 && label != "Vendor diagnostic")
  254.             )
  255.             )
  256.         {
  257.             map<string,any> m = $[
  258.             "name" : BootCommon::translateSectionTitle (label),
  259.             "type" : "other",
  260.             "original_name" : label,
  261.             "chainloader" : dev,
  262.             "__changed" : false,
  263.             "__auto" : true,
  264.             "__devs" : [dev],
  265.             ];
  266.             out = add (out, m);
  267.         }
  268.         }
  269.     });
  270.     }
  271.     if (BootCommon::InstallingToFloppy ())
  272.     {
  273.         out = add (out, $[
  274.         "name" : BootCommon::translateSectionTitle("hard disk"),
  275.         "original_name" : "hard_disk",
  276.         "type" : "other",
  277.         "chainloader" : BootCommon::mbrDisk,
  278.         "__changed" : false,
  279.         "__auto" : true,
  280.         "__devs" : [],
  281.         ]);
  282.     }
  283.     else if (StorageDevices::FloppyPresent)
  284.     {
  285.         out = add (out, $[
  286.         "name" : BootCommon::translateSectionTitle("floppy"),
  287.         "original_name" : "floppy",
  288.         "type" : "other",
  289.         "chainloader" : "/dev/fd0",
  290.         "__changed" : false,
  291.         "__auto" : true,
  292.         "__devs" : [],
  293.         ]);
  294.     }
  295.     out = add (out, CreateLinuxSection ("failsafe"));
  296.     out = add (out, CreateLinuxSection ("memtest86"));
  297.  
  298.     if (Mode::normal ())
  299.     {
  300.         foreach (map<string,string> additional,
  301.          BootCommon::CheckAdditionalKernels (),
  302.     {
  303.         string type = additional["version"]:"";
  304.         type = sformat ("%1", type);
  305.         map<string,any> s = CreateLinuxSection (type);
  306.         s["image"] = additional["image"]:"";
  307.         if (haskey (additional, "initrd"))
  308.             s["initrd"] = additional["initrd"]:"";
  309.         out = add (out, s);
  310.     });
  311.     }
  312.     out = filter (map<string,any> s, out, {return s != $[] && s != nil;});
  313.     BootCommon::sections = out;
  314. }
  315.  
  316. /**
  317.  * Propose global options of bootloader
  318.  */
  319. global map<string,string> StandardGlobals () {
  320.     return $[
  321.     "activate": "true",
  322.     "default" : BootCommon::sections[0, "name"]:"",
  323.     "timeout" : "8",
  324.     "gfxmenu" : "/boot/message",
  325.     ];
  326. }
  327.  
  328.  
  329. // general functions
  330.  
  331. /**
  332.  * Read settings from disk
  333.  * @param reread boolean true to force reread settings from system
  334.  * @return boolean true on success
  335.  */
  336. global boolean Read (boolean reread) {
  337.     BootCommon::InitializeLibrary (reread, "grub");
  338.     if (reread)
  339.     {
  340.     BootCommon::ReadFiles ();
  341.     }
  342.     BootCommon::DetectDisks ();
  343.     boolean ret = BootCommon::Read (false);
  344.     // refresh device map if not read
  345.     if (BootCommon::device_mapping == nil
  346.     || size (BootCommon::device_mapping) == 0)
  347.     {
  348.     BootCommon::ProposeDeviceMap ();
  349.     }
  350.  
  351.     list<string> loader_devices = splitstring (
  352.     BootCommon::globals["stage1_dev"]:"",
  353.     ",");
  354.  
  355.     if (size (loader_devices) > 1)
  356.     {
  357.     // check if members of a MD are present
  358.     map<string,map> tm = Storage::GetTargetMap ();
  359.     list<string> md = maplist (map m, tm["/dev/md", "partitions"]:[], {
  360.         return m["device"]:"";
  361.     });
  362.     if (Mode::test ())
  363.         md = ["/dev/md0"];
  364.     boolean md_found = false;
  365.     // try collapse all MD disks
  366.     foreach (string md_disk, md, {
  367.         list<string> md_members = sort (maplist (
  368.         string s,
  369.         integer id,
  370.         BootCommon::Md2Partitions (md_disk),
  371.         {
  372.         return s;
  373.         }));
  374.         if (Mode::test ())
  375.         md_members = ["/dev/hda1", "/dev/hdb1"];
  376.  
  377.         boolean reduce = true;
  378.         foreach (string member, md_members, {
  379.         if (! contains (loader_devices, member))
  380.             reduce = false;
  381.         });
  382.         if (reduce)
  383.         {
  384.         loader_devices = filter (string d, loader_devices, {
  385.             return ! contains (md_members, d);
  386.         });
  387.         loader_devices = add (loader_devices, md_disk);
  388.         }
  389.     });
  390.     // check MBRs of all disks holding /boot partition
  391.     map<string,integer> boot_md
  392.         = BootCommon::Md2Partitions (
  393.         BootCommon::BootPartitionDevice);
  394.     if (Mode::test ())
  395.         boot_md = $["/dev/hda1" : 128, "/dev/hdb1" : 129];
  396.     list<string> md_disks = maplist (string d, integer b, boot_md,
  397.     {
  398.         map p_dev = Storage::GetDiskPartition (d);
  399.         return p_dev["disk"]:"";
  400.     });
  401.     boolean reduce = true;
  402.     foreach (string d, md_disks, {
  403.         if (! contains (loader_devices, d))
  404.         reduce = false;
  405.     });
  406.     if (reduce)
  407.     {
  408.         loader_devices = filter (string d, loader_devices, {
  409.         return ! contains (md_disks, d);
  410.         });
  411.         loader_devices = add (loader_devices, "mbr_md");
  412.     }
  413.     if (contains (loader_devices, BootCommon::BootPartitionDevice))
  414.     {
  415.         loader_devices = filter (string d, loader_devices, {
  416.         return d != BootCommon::BootPartitionDevice;
  417.         });
  418.         backup_to_bootsector = true;
  419.         if (size (loader_devices) > 0)
  420.         {
  421.         loader_devices = sort (loader_devices);
  422.         BootCommon::loader_device = loader_devices[0]:"";
  423.         }
  424.         else
  425.         {
  426.         BootCommon::loader_device = BootCommon::BootPartitionDevice;
  427.         }
  428.     }
  429.     }
  430.     else if (size (loader_devices) == 1)
  431.     {
  432.     BootCommon::loader_device = loader_devices[0]:"";
  433.     }
  434.  
  435.     importMetaData();
  436.  
  437.     return ret;
  438. }
  439.  
  440.  
  441.     /**
  442.       * Reset bootloader settings
  443.       * @param init boolean true to repropose also device map
  444.       */
  445.     global define void Reset (boolean init) ``{
  446.     if (Mode::autoinst ())
  447.         return;
  448.     BootCommon::Reset (init);
  449.     }
  450.     /**
  451.       * Propose bootloader settings
  452.       */
  453.     global define void Propose () ``{
  454.     y2debug ("Started propose: Glob: %1, Sec: %2",
  455.         BootCommon::globals, BootCommon::sections);
  456.  
  457.     string old_loader_device = BootCommon::loader_device;
  458.     // if NOT was_proposed (i.e. blPropose() has not been called yet), then
  459.     // - set up BootPartitionDevice, RootPartitionDevice
  460.     // - if empty, set up mbrDisk
  461.     // - if loader_device is empty or the device is not a boot device, go
  462.     //   to ConfigureLocation() and
  463.     //    - propose
  464.     //        - loader_device
  465.     //        - selected_location (according to loader_device)
  466.     //        - activate (when needed, but try to be nice to Windows)
  467.     //    - do not touch these, except when /boot partition is selected_location:
  468.     //        - activate_changed (set to true)
  469.     //        - repl_mbr (set to true when we need to update existing GRUB, lilo MBRs,
  470.     //            or when it looks like there is no code in the MBR at all,
  471.     //            but NOT if this is a "Generic" (DOS) MBR, some unknown code
  472.     //            or a Thinkpad MBR)
  473.     //
  474.     // always propose:
  475.     //  - device_mapping (from "bios_id"s delivered by Storage, then let
  476.     //                    devices with unknown "bios_id"s drop into the
  477.     //                    gaps of this mapping or append at the end)
  478.     //
  479.     // if '/' and '/boot' were changed and selected_location is set and not
  480.     // "custom", ask user with popup whether it is OK to change the
  481.     // location and change it (with DetectDisks() and ConfigureLocation()
  482.     // (see above))
  483.     BootCommon::i386LocationProposal ();
  484.  
  485.     // The Propose() function is called every time before Summary() is
  486.     // called. We have to take the current state of the boot_* and activate
  487.     // keys from the globals variable (where the new generic widgets put
  488.     // the current settings and/or a previous proposal left them there, see
  489.     // below) and put this information in the loader_device and activate
  490.     // variables for the internal routines to use.
  491.     // FIXME: This should probably be put in a function of its own. ATM,
  492.     // this code looks still too specific to put it in a function, though.
  493.     // But I may be wrong here.
  494.  
  495.     if ( old_loader_device == BootCommon::loader_device ) {
  496.         // if we did not re-propose, use user-supplied settings (if any)
  497.         if ( haskey(BootCommon::globals, "boot_boot") && BootCommon::globals["boot_boot"]:"false" == "true" ) {
  498.         BootCommon::loader_device = BootCommon::BootPartitionDevice;
  499.         } else if ( haskey(BootCommon::globals, "boot_root") && BootCommon::globals["boot_root"]:"false" == "true" ) {
  500.         BootCommon::loader_device = BootCommon::RootPartitionDevice;
  501.         } else if ( haskey(BootCommon::globals, "boot_mbr") && BootCommon::globals["boot_mbr"]:"false" == "true" ) {
  502.         BootCommon::loader_device = BootCommon::mbrDisk;
  503.         } else if ( haskey(BootCommon::globals, "boot_custom") ) {
  504.         BootCommon::loader_device = BootCommon::globals["boot_custom"]:"";
  505.         }
  506.  
  507.         if ( haskey(BootCommon::globals, "activate") ) {
  508.         if ( BootCommon::globals["activate"]:"false" == "true" ) {
  509.             BootCommon::activate = true;
  510.         } else {
  511.             BootCommon::activate = false;
  512.         }
  513.         }
  514.     }
  515.     else {
  516.           BootCommon::globals["activate"] =
  517.             BootCommon::activate ? "true" : "false";
  518.         BootCommon::globals["generic_mbr"] =
  519.             BootCommon::repl_mbr ? "true" : "false";
  520.     }
  521.  
  522.     if (BootCommon::sections == nil || size (BootCommon::sections) == 0)
  523.     {
  524.         CreateSections ();
  525.         BootCommon::kernelCmdLine = Kernel::GetCmdLine ();
  526.     }
  527.     else
  528.     {
  529.         if (Mode::autoinst ())
  530.         {
  531.         // TODO whatever will be needed
  532.         y2debug ("nothing to do in AI mode if sections exist");
  533.         }
  534.         else
  535.         BootCommon::FixSections (BootGRUB::CreateSections);
  536.     }
  537.     if (BootCommon::globals == nil || size (BootCommon::globals) == 0)
  538.     {
  539.         BootCommon::globals = StandardGlobals();
  540.     }
  541.     else
  542.     {
  543.             if (Mode::autoinst ())
  544.             {
  545.                 // TODO whatever will be needed
  546.         y2debug ("nothing to to in AI mode if globals are defined");
  547.             }
  548.             else {
  549.         // Merge default globals where not yet set
  550.             BootCommon::globals = (map<string, string>) union(
  551.             StandardGlobals(),
  552.             BootCommon::globals
  553.         );
  554.         }
  555.         // this currently does nothing more than fixing the "default" key,
  556.         // if that points to a section that does not exist anymore
  557.         BootCommon::FixGlobals ();
  558.     }
  559.  
  560. //         if (! BootCommon::was_proposed)
  561. //     {
  562. //         BootCommon::globals["embed_stage1.5"] = allowEmbed15 () ? "1" : "0";
  563. //     }
  564.  
  565.     // FIXME: The setting of the boot_* and activate keys in globals for
  566.     // the new perl-Bootloader interface should probably be put in a
  567.     // function of its own. ATM, this code looks still too specific to put
  568.     // it in a function, though. But I may be wrong here.
  569.     // Pass down proposal to the variables of the new perl-Bootloader code
  570.     // first, default to all off:
  571.     BootCommon::globals["boot_boot"] = sformat("%1", false);
  572.     BootCommon::globals["boot_root"] = sformat("%1", false);
  573.     BootCommon::globals["boot_mbr"] =  sformat("%1", false);
  574.     // need to remove the boot_custom key to switch this value off
  575.     if (haskey (BootCommon::globals, "boot_custom")) {
  576.         BootCommon::globals = remove (BootCommon::globals, "boot_custom");
  577.     }
  578.     BootCommon::change_widget_default_value("boot_custom", "");    // FIXME: kludge, maybe obsolete
  579.  
  580.     if ( BootCommon::loader_device == BootCommon::RootPartitionDevice ) {
  581.         BootCommon::globals["boot_root"] = sformat("%1", true);
  582.     } else if ( BootCommon::loader_device == BootCommon::BootPartitionDevice ) {
  583.         BootCommon::globals["boot_boot"] = sformat("%1", true);
  584.     } else if ( BootCommon::loader_device == BootCommon::mbrDisk ) {
  585.         BootCommon::globals["boot_mbr"] = sformat("%1", true);
  586.     } else {
  587.         BootCommon::globals["boot_custom"] = BootCommon::loader_device;
  588.         BootCommon::change_widget_default_value("boot_custom", BootCommon::loader_device);    // FIXME: kludge, maybe obsolete
  589.     }
  590.  
  591.     BootCommon::globals["activate"] = sformat("%1", BootCommon::activate);
  592.  
  593.     y2milestone ("Proposed sections: %1", BootCommon::sections);
  594.     y2milestone ("Proposed globals: %1", BootCommon::globals);
  595.     }
  596.  
  597. /**
  598.  * Save all bootloader configuration files to the cache of the PlugLib
  599.  * PlugLib must be initialized properly !!!
  600.  * @param clean boolean true if settings should be cleaned up (checking their
  601.  *  correctness, supposing all files are on the disk
  602.  * @param init boolean true to init the library
  603.  * @param flush boolean true to flush settings to the disk
  604.  * @return boolean true if success
  605.  */
  606. global boolean Save (boolean clean, boolean init, boolean flush) {
  607.     // update list of devices
  608. //     list<string> loader_devices = [BootCommon::loader_device];
  609. //     if (backup_to_bootsector && contains (BootCommon::getPartitionList(`boot),
  610. //     BootCommon::BootPartitionDevice))
  611. //     {
  612. //     if (loader_devices[0]:"" != nil && loader_devices[0]:"" != "/dev/null"
  613. //         && loader_devices[0]:"" != "")
  614. //     {
  615. //         loader_devices[1] = BootCommon::BootPartitionDevice;
  616. //     }
  617. //     else
  618. //     {
  619. //         loader_devices = [ BootCommon::BootPartitionDevice ];
  620. //     }
  621. //     }
  622.  
  623.     // get the list of device names to install the boot loader stage 1 into:
  624.     //   - for non-md devices, use just the device name
  625.     //   - for installation to md arrays: get the list of device names from
  626.     //     name of md array, either
  627.     //         - just the container-partitions (according to yast2-storage) or
  628.     //         ("/dev/md0" -> ["/dev/hda1", ...])
  629.     //       - the (cut off) name of the corresponding disk devices
  630.     //         ("/dev/md0" -> ["/dev/hda1", ...] -> ["/dev/hda", ...])
  631. //     list<list<string> > dev_lists = maplist (string d, loader_devices, {
  632. //     if (substring (d, 0, 7) == "/dev/md")
  633. //     {
  634. //         map<string,integer> md = BootCommon::Md2Partitions (d);
  635. //         if (Mode::test ())
  636. //         md = $["/dev/hda1" : 128, "/dev/hdb1" : 129];
  637. //         return maplist (string d, integer b, md, {
  638. //         return d;
  639. //         });
  640. //     }
  641. //     if (d == "mbr_md")
  642. //     {
  643. //         map<string,integer> md = BootCommon::Md2Partitions
  644. //         (BootCommon::BootPartitionDevice);
  645. //         if (Mode::test ())
  646. //         md = $["/dev/hda1" : 128, "/dev/hdb1" : 129];
  647. //         return maplist (string d, integer b, md, {
  648. //         // get disk device name for this partition or disk device name
  649. //         map p_dev = Storage::GetDiskPartition (d);
  650. //         return p_dev["disk"]:"";
  651. //         });
  652. //     }
  653. //     return [d];
  654. //     });
  655. //     loader_devices = flatten (dev_lists);
  656. //     BootCommon::globals["stage1_dev"] = mergestring (loader_devices, ",");
  657.  
  658.     // now really save the settings
  659.     boolean ret = BootCommon::Save (clean, init, flush);
  660.     return ret;
  661.     }
  662.  
  663.  
  664. /**
  665.  * Display bootloader summary
  666.  * @return a list of summary lines
  667.  */
  668. global define list<string> Summary () {
  669.     list<string> ret = [];
  670.     string lt = BootCommon::getLoaderType (false);
  671.     string ln = BootCommon::getLoaderName (lt, `summary);
  672.  
  673.     if (lt == "none") {
  674.         ret = [ HTML::Colorize (ln, "red") ];
  675.     }
  676.  
  677.     // summary text, %1 is bootloader name (eg. LILO)
  678.     ret = add (ret, sformat (_("Boot Loader Type: %1"), ln));
  679.  
  680.     // summary text, location is location description (eg. /dev/hda)
  681.     list<string> locations = [];
  682.  
  683.     if (BootCommon::globals["boot_boot"]:"" == "true")
  684.         locations = add(locations, BootCommon::BootPartitionDevice);
  685.     if (BootCommon::globals["boot_root"]:"" == "true")
  686.         locations = add(locations, BootCommon::RootPartitionDevice);
  687.     if (BootCommon::globals["boot_mbr"]:"" == "true")
  688.         locations = add(locations, BootCommon::mbrDisk);
  689.     if (haskey (BootCommon::globals, "boot_custom"))
  690.         locations = add(locations, BootCommon::globals["boot_custom"]:"");
  691.  
  692.     if (size(locations) > 0) {
  693.         // FIXME: should we translate all devices to names and add MBR suffixes?
  694.         ret = add (ret, sformat (_("Location: %1"),
  695.                  mergestring (locations, ", "))
  696.            );
  697.     }
  698.  
  699.     // summary text. %1 is list of bootloader sections
  700.     list<string> sects = [];
  701.     foreach (map<string,any> s, BootCommon::sections, {
  702.         string title = s["name"]:"";
  703.     // section name "suffix" for default section
  704.     string def = title == BootCommon::globals["default"]:"" ? _(" (default)") : "";
  705.     sects = add (sects, sformat ("%1%2", title, def));
  706.     });
  707.  
  708.     ret = add (ret, sformat (_("Sections: %1"),
  709.            String::EscapeTags (mergestring (sects, ", "))));
  710.  
  711.     if (size(locations) == 0) {
  712.         // summary text
  713.         ret = add (ret, _("Do not install boot loader; just create configuration files"));
  714.     }
  715.  
  716.     string order_sum = BootCommon::DiskOrderSummary ();
  717.     if (order_sum != nil)
  718.     ret = add (ret, order_sum);
  719.     return ret;
  720. }
  721.  
  722.  
  723.     /**
  724.       * Update read settings to new version of configuration files
  725.       */
  726. global define void Update () {
  727.     BootCommon::UpdateDeviceMap ();
  728.     BootCommon::UpdateSections (true, CreateLinuxSection);
  729.     BootCommon::UpdateGlobals ();
  730.     // BootCommon::loader_device
  731.     //  = BootCommon::UpdateDevice (BootCommon::loader_device);
  732.     }
  733.     /**
  734.       * Write bootloader settings to disk
  735.       * @return boolean true on success
  736.       */
  737.     global define boolean Write () ``{
  738.     BootCommon::updateMBR ();
  739.     boolean ret = BootCommon::UpdateBootloader ();
  740.     if (BootCommon::location_changed || BootCommon::InstallingToFloppy ())
  741.     {
  742.         if (BootCommon::InstallingToFloppy ())
  743.         {
  744.         if (! saveToFLoppyPopup ())
  745.         {
  746.             y2error ("Preparing floppy disk failed.");
  747.             ret = false;
  748.         }
  749.         }
  750.  
  751.         boolean grub_ret = BootCommon::InitializeBootloader ();
  752.         y2milestone ("GRUB return value: %1", grub_ret);
  753.         if (BootCommon::InstallingToFloppy ())
  754.         {
  755.         BootCommon::updateTimeoutPopupForFloppy
  756.             (BootCommon::getLoaderName ("grub", `summary));
  757.         }
  758.         ret = ret && grub_ret;
  759.         ret = ret && BootCommon::PostUpdateMBR ();
  760.     }
  761.     return ret;
  762.     }
  763.  
  764.  
  765. global symbol WizardSequenzer() {
  766.     y2milestone("Call generic WizardSequenzer");
  767.     return `generic_new;
  768. }
  769.  
  770.  
  771. global map<string,symbol()> Dialogs () {
  772.    
  773.     return $[
  774.     "loader"    : genericBootLoaderOptionsDialog,
  775.     // do we really need the following dialog?
  776. //    "installation"    : genericInstallDetailsDialog,
  777.     ];
  778. }
  779.  
  780.  
  781.   
  782.  
  783.     /**
  784.       * Return map of provided functions
  785.       * @return a map of functions (eg. $["write"::Write])
  786.       */
  787.     global map<string, any> GetFunctions () ``{
  788.     return $[
  789.          //"export"       : Export,
  790.          //"import"       : Import,
  791.             "read"        : Read,
  792.             "reset"        : Reset,
  793.             "propose"        : Propose,
  794.             "save"        : Save,
  795.         "summary"        : Summary,
  796.             "update"        : Update,
  797.             "write"        : Write,
  798.         "widgets"        : genericWidgets,
  799.         "wizard_sequencer"    : WizardSequenzer,
  800.         "dialogs"        : Dialogs,
  801.         "section_types"    : section_types,
  802.     ];
  803.     }
  804.  
  805.     /**
  806.       * Initializer of GRUB bootloader
  807.       */
  808.     global define void Initializer () ``{
  809.     y2milestone ("Called GRUB initializer");
  810.     BootCommon::current_bootloader_attribs = $[
  811.         "alias_keys" : [],
  812.         "update_passwd" : BootGRUB::updatePasswdBeforeSave,
  813.         "propose" : true,
  814.         "read" : true,
  815.         "scratch" : true,
  816.         "additional_entries" : [`item (`id (`propose_deep),
  817.         // menubutton item, keep as short as possible
  818.         _("Propose and &Merge with Existing GRUB Menus"))],
  819.         "restore_mbr" : true,
  820.         "key_only_once" : false,
  821.         "bootloader_on_disk" : true,
  822.     ];
  823.  
  824.     BootCommon::help_messages = (map<string,string>)
  825.       union(BootCommon::help_messages,
  826.         mapmap(string key, string val, grub_help_messages,
  827.             { return $[ "grub_" + key : val ]; }
  828.                )
  829.         );
  830.     y2debug("Initialized help_messages to %1", BootCommon::help_messages);
  831.     BootCommon::descriptions = (map<string,string>)
  832.       union(BootCommon::descriptions,
  833.         mapmap(string key, string val, grub_descriptions,
  834.             { return $[ "grub_" + key : val ]; }
  835.                )
  836.         );
  837.     y2debug("Initialized help_messages to %1", BootCommon::help_messages);
  838.     
  839.     BootCommon::InitializeLibrary (false, "grub");
  840.     importMetaData();
  841.     }
  842.  
  843.     /**
  844.       * Constructor
  845.       */
  846.     global define void BootGRUB () ``{
  847.     BootCommon::bootloader_attribs["grub"] = $[
  848.         "required_packages" : ["grub"],
  849.         "loader_name" : "GRUB",
  850.         "initializer" : BootGRUB::Initializer,
  851.     ];
  852.     }
  853.  
  854.  
  855. }
  856.  
  857. /*
  858.  * Local variables:
  859.  *     mode: ycp
  860.  *     mode: font-lock
  861.  *     mode: auto-fill
  862.  *     indent-level: 4
  863.  *     fill-column: 78
  864.  * End:
  865.  */
  866.