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 / OSRBoot.ycp < prev    next >
Text File  |  2006-11-29  |  38KB  |  1,393 lines

  1. /**
  2.  * File:    OSRBoot.ycp
  3.  * Module:    repair
  4.  * Summary:    Bootloader checks
  5.  * Authors:    Johannes Buchhold <jbuch@suse.de>
  6.  *
  7.  * $Id: OSRBoot.ycp 25045 2005-08-18 12:06:28Z jsuchome $
  8.  *
  9.  * Provide osr mode information.
  10.  */
  11.  
  12. {
  13.  
  14.     module "OSRBoot";
  15.  
  16.     import "Storage";
  17.     import "StorageDevices";
  18.     import "Report";
  19.     import "Installation";
  20.     import "Mode";
  21.     import "Popup";
  22.     import "Wizard";
  23.  
  24.     import "Bootloader";
  25.     import "BootCommon";
  26.     import "Initrd";
  27.     import "Kernel";
  28.  
  29.     import "OSRSystem";
  30.     import "OSRLogFile";
  31.     import "OSRExecute";
  32.     import "OSRPkg";
  33.     import "OSRPopup";
  34.     import "OSRCommon";
  35.  
  36.     textdomain "repair";
  37.  
  38.     include "repair/bootloader_routines.ycp";
  39.  
  40.     /**
  41.      * Configuration files needed by every boot loader
  42.      */
  43.     global map needed_config_files = $[
  44.         "modules"        : "/etc/modprobe.conf",
  45.         "initrd"        : "/etc/sysconfig/kernel",
  46.         "bootleader"    : "/etc/sysconfig/bootloader"
  47.     ];
  48.  
  49.     /**
  50.      * Boot loader package name and required version
  51.      */
  52.     map bootloader_packages = $[
  53.         "lilo"    : [
  54.         $[
  55.             "pkgname"        : "lilo",
  56.             "pkgversion"    : "22.3.2-32"
  57.         ],
  58.         $[
  59.             "pkgname"        : "gfxboot",
  60.             "pkgversion"    : "1.9-34"
  61.         ]
  62.         ],
  63.         "grub"    : [
  64.         $[
  65.             "pkgname"        : "grub",
  66.             "pkgversion"    : "0.92-69"
  67.         ]
  68.         ],
  69.         "silo"    : [], //"SILO",
  70.         "milo"    : [], //"MILO",
  71.         "aboot"    : [], //"aboot",^
  72.         "elilo"    : [], //"ELILO",
  73.         "mips"    : [], //"dvh",
  74.         "s390"    : [], //"zipl",
  75.         "ppc"    : []  //"boot loader"
  76.     ];
  77.  
  78.     // function prototypes
  79.     define boolean check_lilo_config();
  80.     define boolean check_grub_config();
  81.     global define symbol repair_grub_config();
  82.  
  83.     /**
  84.      * Check and repair define for every support boot loader
  85.      */
  86.     map bootloader_config_check = $[
  87.         "lilo"    : $[
  88.         "config_check"    : check_lilo_config,
  89.         "config_repair"    : repair_grub_config,
  90.         "config_file"    : "/etc/lilo.conf"
  91.         ],
  92.         "grub"    : $[
  93.         "config_check"    : check_grub_config,
  94.         "config_repair"    : repair_grub_config,
  95.         "config_file"    : "/etc/grub.conf",
  96.         "device_map"    : "/boot/grub/device.map",
  97.         "stage1"    : "/boot/grub/stage1",
  98.         "stage2"    : "/boot/grub/stage2",
  99.         "menu"        : "/boot/grub/menu.lst"
  100.         ],
  101.         "silo"    : $[], //"SILO",
  102.         "milo"    : $[], //"MILO",
  103.         "aboot"    : $[], //"aboot",
  104.         "elilo"    : $[], //"ELILO",
  105.         "mips"    : $[], //"dvh",
  106.         "s390"    : $[], //"zipl",
  107.         "ppc"    : $[]  //"boot loader"
  108.     ];
  109.  
  110.     list valid_grub_menu_enties = [];
  111.  
  112.     list grub_generally = [
  113.                "bootp"    ,
  114.                "color"    ,
  115.                "device"    ,
  116.                "dhcp"    ,
  117.                "hide"    ,
  118.                "ifconfig"    ,
  119.                "pager"    ,
  120.                "partnew"    ,
  121.                "parttype"    ,
  122.                "password"    ,
  123.                "rarp"    ,
  124.                "serial"    ,
  125.                "setkey"    ,
  126.                "terminal"    ,
  127.                "tftpserver"    ,
  128.                "unhide"    ,
  129.                "gfxmenu"    ,
  130.     ];
  131.  
  132.     list grub_menu_only = [
  133.               "default"    ,
  134.               "fallback"    ,
  135.               "hiddenmenu"    ,
  136.               "timeout"        ,
  137.               "title"
  138.               ];
  139.  
  140.     list grub_menu = [
  141.               "blocklist"    ,
  142.               "boot"        ,
  143.               "cat"        ,
  144.               "chainloader"    ,
  145.               "cmp"        ,
  146.               "configfile"    ,
  147.               "debug"        ,
  148.               "displayapm"    ,
  149.               "displaymem"    ,
  150.               "embed"        ,
  151.               "find"        ,
  152.               "fstest"        ,
  153.               "geometry"    ,
  154.               "halt"        ,
  155.               "help"        ,
  156.               "impsprobe"    ,
  157.               "initrd"        ,
  158.               "install"        ,
  159.               "ioprobe"        ,
  160.               "kernel"        ,
  161.               "lock"        ,
  162.               "makeactive"    ,
  163.               "map"        ,
  164.               "md5crypt"    ,
  165.               "module"        ,
  166.               "modulenounzip"    ,
  167.               "pause"        ,
  168.               "quit"        ,
  169.               "reboot"        ,
  170.               "read"        ,
  171.               "root"        ,
  172.               "rootnoverify"    ,
  173.               "savedefault"    ,
  174.               "setup"        ,
  175.               "testload"    ,
  176.               "testvbe"        ,
  177.               "uppermem"    ,
  178.               "vbeprobe"
  179.     ];
  180.  
  181.     /**
  182.      * Default settings for /etc/grub.conf
  183.      */
  184.     map grub_conf_defaults = $[ "discswitch"    : "d",
  185.                 "addr"        : "0x8000"];
  186.  
  187.     /**
  188.      * File for backup bootloader settings
  189.      */
  190.     string config_backup_path        = "/bootloader";
  191.     boolean backup_created        = false;
  192.  
  193.     /**
  194.      * Error message if the check defines found an error
  195.      */
  196.     string error_message         = "";
  197.  
  198.     /**
  199.      * Help text if the check defines found an error
  200.      */
  201.     string help_text             = "";
  202.  
  203.     /**
  204.      * The name of the boot loader
  205.      */
  206.     string  bootloader              = "";
  207.  
  208.     /**
  209.      * A list with all invalid configuration files.
  210.      */
  211.     list<string> invalid_config_files     = [];
  212.  
  213.     /**
  214.      * A list of all not installed boot loader packages
  215.      */
  216.     global list<string> missing_packages = [];
  217.  
  218.     /**
  219.      * The root mount point.
  220.      */
  221.     global string  root_mountpoint     = Installation::destdir;
  222.  
  223.     /**
  224.      * The root device e.g.: /dev/hda2
  225.      */
  226.     global string  root_device        = "";
  227.  
  228.     /**
  229.      * The boot device e.g.: /dev/hda1
  230.      */
  231.     global string  boot_device        = "";
  232.  
  233.     global boolean bootloader_error_found = false;
  234.  
  235.     global list<string> not_valid_files = [];
  236.  
  237.     global list current_initrd_modules = [];
  238.  
  239.  
  240.  
  241.     /**
  242.      * Reset module settings.
  243.      **/
  244.     global define void Reset()``{
  245.     not_valid_files     = [];
  246.     bootloader_error_found     = false;
  247.     invalid_config_files     = [];
  248.     boot_device         = "";
  249.     root_device         = "";
  250.     bootloader         = "";
  251.     missing_packages     = [];
  252.     help_text         = "";
  253.     error_message         = "";
  254.     current_initrd_modules  = [];
  255.     //not backup_created
  256.     }
  257.  
  258.     ////////////////////////////////////////////////////////////////////////////
  259.     // Package data access functions
  260.     ////////////////////////////////////////////////////////////////////////////
  261.  
  262.     /**
  263.      * The minimal package version of a package.
  264.      */
  265.     define string RequiredPackageVersion(string bootloader, string package )``{
  266.     map package_data = (map)
  267.         find (map pkgdata, bootloader_packages[bootloader]:[],
  268.         ``( pkgdata["pkgname"]:"" == package));
  269.  
  270.     if (package_data == nil || package_data == $[])
  271.     {
  272.         y2error("package version not found");
  273.         return "";
  274.     }
  275.     else
  276.     {
  277.         return package_data["pkgversion"]:"";
  278.     }
  279.     }
  280.  
  281.     /**
  282.      * Return a list of strings with all required boot loader packages with the current
  283.      * and the required version.
  284.      */
  285.     global define list<string> PackageVersionStrings(string bootloader, list<string> packages )``{
  286.     list<string> ret = [];
  287.     foreach(string package, packages, ``{
  288.         string package_version = package;
  289.         if (!Mode::test ())
  290.         {
  291.         package_version = package_version + " current version: " +
  292.             Pkg::PkgVersion(package) + " required version: " +
  293.             RequiredPackageVersion(bootloader, package);
  294.         }
  295.         ret = add(ret, package_version );
  296.     });
  297.     return ret;
  298.     }
  299.  
  300.     /**
  301.      * Return all needed packages of a boot loader.
  302.      */
  303.     global define list<string> BootloaderPackages(string bootloader )``{
  304.     return maplist(map pkgdata, bootloader_packages[bootloader]:[], ``( pkgdata["pkgname"]:"" ));
  305.     }
  306.  
  307.     /**
  308.      *  Compares the two specified version numbers. Each version number has to be a string
  309.      *  of the form "21.6-34", "34.4.3", ...
  310.      *
  311.      *  API function.
  312.      *  See the testsuite.
  313.      *
  314.      *  @param string version_1 The first version-number as string.
  315.      *  @param string version_2 The second version-number as string.
  316.      *  @return boolean True if the first version number is newer than the second one.
  317.      *  @example if (!OSRVersionIsHigherOrEqual("21.6", "22.3")) y2error("Something's wrong here.")
  318.      */
  319.     global define boolean VersionIsHigherOrEqual( string version_1, string version_2  ) ``{
  320.  
  321.       list<string>    v_1   = [];
  322.       list<string>    v_2   = [];
  323.       integer n_1   = 0;
  324.       integer n_2   = 0;
  325.       integer index = 0;
  326.       integer max   = 0;
  327.  
  328.       // split the version-strings at the dots- and minus-characters "24.5.6" -> ["24", "5", "6"]
  329.       v_1 = splitstring(version_1, ".-");
  330.       v_2 = splitstring(version_2, ".-");
  331.  
  332.       // select the smaller one of the two numbers
  333.       if (size(v_1) < size(v_2))
  334.       {
  335.       max = size(v_1);
  336.       }
  337.       else
  338.       {
  339.       max = size(v_2);
  340.       }
  341.  
  342.       // iterate the splitted version-numbers
  343.       while(index < max)
  344.       {
  345.       n_1 = tointeger (v_1[index]:"0");
  346.       n_2 = tointeger (v_2[index]:"0");
  347.  
  348.       if (n_1 > n_2)
  349.       {
  350.           return true;
  351.       }
  352.       else if (n_1 < n_2)
  353.       {
  354.           return false;
  355.       }
  356.       index = index + 1;
  357.       }
  358.  
  359.       // if the splitted numbers were all equal, look if the first version-number
  360.       // consits of more parts than the second one
  361.       return (size(v_1) >= size(v_2));
  362.   };
  363.  
  364.  
  365.     /**
  366.      * build the help text with the package summary
  367.      * for all specified packages
  368.      */
  369.     define string build_packages_help(list<string> missing_packages )``{
  370.     string help_text = "";
  371.     foreach(string package, missing_packages,``{
  372.         help_text = help_text +sformat("<b>%1</b><br>%2<br>",package, Pkg::PkgSummary(package));
  373.     });
  374.     return help_text;
  375.     }
  376.  
  377.  
  378.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  379.     // Checking sysconfig fils and boot loader packages
  380.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  381.  
  382.     /**
  383.      * Check the main config file for boot loader and kernel initrd
  384.      */
  385.     global define boolean CheckSysconfigFiles(string root)``{
  386.  
  387.     if( root != "" ) root_mountpoint = root;
  388.  
  389.     // TODO check if one module is needed at least
  390.     string r1 = (string) SCR::Read (.sysconfig.kernel.INITRD_MODULES);
  391.     if( r1 == nil ) not_valid_files = add(not_valid_files, needed_config_files["initrd"]:"");
  392.  
  393.     r1 = (string) SCR::Read (.sysconfig.bootloader.LOADER_TYPE);
  394.     if( r1 == nil || r1 == "" ) not_valid_files = add(not_valid_files, needed_config_files["bootloader"]:"");
  395.  
  396.     integer r2 = Mode::test () ? 0 : (integer) WFM::Execute(.local.bash,
  397.         sformat("/usr/bin/test -f %1%2",
  398.         root_mountpoint, needed_config_files["modules"]:""));
  399.     if (r2 != 0)
  400.     {
  401.         not_valid_files = add (not_valid_files,
  402.         needed_config_files["modules"]:"");
  403.     }
  404.  
  405.     if( size( not_valid_files ) > 0 )
  406.     {
  407.         bootloader_error_found = true;
  408.         y2error("checking the sysconfig file found error");
  409.     }
  410.     return size( not_valid_files ) == 0;
  411.     }
  412.  
  413.  
  414.     /**
  415.      * Check boot loader packages.
  416.      * @param what = "installed" if all packages are installed
  417.      *          what = "version"   if all packages have the required version
  418.      *        what = "verify"    if all packages are not damaged
  419.      */
  420.     global define boolean CheckLoaderPackages(string loader, string root, string what )``{
  421.  
  422.     if( loader     != "") bootloader     = loader;
  423.     if( root     != "") root_mountpoint    = root;
  424.  
  425.     missing_packages = [];
  426.  
  427.     OSRPkg::OpenPkg( root_mountpoint );
  428.  
  429.     // check all needed packages
  430.     foreach(string package, BootloaderPackages( bootloader ), ``{
  431.  
  432.         if( what == "installed" )
  433.         {
  434.         if(!Mode::test () && ! Pkg::IsProvided ( package ) ) {
  435.             missing_packages = add(missing_packages, package);
  436.         }
  437.         else {
  438.             y2milestone("installed package %1", package );
  439.         }
  440.         // TODO check dependencies
  441.         }
  442.         else if ( what == "verify" )
  443.         {
  444.         //Pkg::XXX not support
  445.         string command = sformat("/bin/rpm -V -r\"%1\" %2", root_mountpoint, package);
  446.  
  447.         if ( ! OSRExecute::CommandOutput(.local.bash_output, command)) {
  448.             missing_packages = add(missing_packages, package);
  449.         }
  450.         else {
  451.             y2milestone("package %1 verified", package);
  452.         }
  453.         }
  454.         else if ( what == "version" )
  455.         {
  456.         if (!Mode::test () &&
  457.             !VersionIsHigherOrEqual (Pkg::PkgVersion (package),
  458.             RequiredPackageVersion(bootloader, package)))
  459.         {
  460.             missing_packages = add(missing_packages, package );
  461.         }
  462.         else {
  463.             y2milestone("package %1 version is ok.", package);
  464.         }
  465.         }
  466.         else {
  467.         y2error("CheckLoaderPackages what is not valid");
  468.         }
  469.  
  470.     });
  471.  
  472.     if ( size(missing_packages) > 0 )
  473.     {
  474.         bootloader_error_found = true;
  475.         y2error(" package check found error");
  476.     }
  477.     return size(missing_packages) == 0;
  478.     }
  479.  
  480.  
  481.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  482.     // Install missing or damaged boot loader packages
  483.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  484.  
  485.     /**
  486.      * Install all missing package if the user accept.
  487.      */
  488.     global define symbol InstallLoaderPackage(string loader, string root, string install_reason )``{
  489.  
  490.     if( loader     != "" ) bootloader     = loader;
  491.     if( root     != "" ) root_mountpoint    = root;
  492.  
  493.     string help_text     = build_packages_help( missing_packages );
  494.     // error message: %1 is explanation, %2 is list of packages
  495.     string error_message      = sformat(_("
  496. %1
  497.  
  498. %2
  499.  
  500. Press Repair to install these packages.
  501. "),install_reason, mergestring( missing_packages, "\n" ));
  502.  
  503.  
  504.     if( OSRPopup::Repair(_("Boot Loader Package Missing"), error_message, help_text)) {
  505.  
  506.         OSRPkg::root_mountpoint  = root;
  507.         OSRPkg::missing_packages = missing_packages;
  508.         return OSRPkg::InstallMissing(false);
  509.     }
  510.     else
  511.     {
  512.         y2milestone(" installing missing loader packages was canceled");
  513.         return `cancel;
  514.     }
  515.     }
  516.  
  517.     ///////////////////////////////////////////////////////////////////////////
  518.     // Check initrd modules
  519.     ///////////////////////////////////////////////////////////////////////////
  520.  
  521.     /**
  522.      * Check the specified initrd modules.
  523.      */
  524.     global define boolean CheckInitrdModules(string root )``{
  525.     if( root != "") root_mountpoint = root;
  526.  
  527.     string crs = (string) SCR::Read (.sysconfig.kernel.INITRD_MODULES);
  528.     current_initrd_modules = splitstring(crs, " ");
  529.     y2milestone("current initrd_modules %1", current_initrd_modules);
  530.  
  531.     list storage_initrd = Storage::GetRootInitrdModules();
  532.     y2milestone(" found initrd modules %1",storage_initrd );
  533.  
  534.     //add found modules to Boot::initrdModules
  535.     foreach(string m, (list<string>) storage_initrd, ``{
  536.         Initrd::AddModule (m, "");
  537.     });
  538.  
  539.     list<string> listed_modules = Initrd::ListModules();
  540.     y2milestone("needed initrd_modules in Boot %1", listed_modules );
  541.     list<string> missing = (list<string>) filter(string s, listed_modules,
  542.         ``( !contains(current_initrd_modules, s)));
  543.  
  544. //    if( Mode::test () ) missing = add(missing, "reiserfs");
  545.  
  546.     if (size( missing ) > 0)
  547.     {
  548.         help_text = _("
  549. The variable INITRD_MODULES contains the list of modules
  550. to add to the initial RAM disk by calling the script mkinitrd.
  551. Examples are drivers for SCSI controllers, LVM, reiserfs.
  552. ");
  553.         //%1 is file name, %2 is list of kernel modules
  554.         error_message = sformat(_("
  555. The file %1 contains a list
  556. of modules to add to the initial
  557. RAM disk by calling the script mkinitrd.
  558. YaST is missing the following modules:
  559.  
  560. %2
  561.  
  562. Press Repair to add the missing
  563. modules to the initial RAM disk.
  564. "), needed_config_files["initrd"]:"", mergestring( missing , "\n" ));
  565.  
  566.  
  567.         return false;
  568.     }
  569.     return true;
  570.     }
  571.  
  572.  
  573.     /**
  574.      * Wirte initrd modules and call mkinitrd
  575.      */
  576.     global define symbol RepairInitrdModules()``{
  577.     // initrd is case-sensitive
  578.     if ( ! OSRPopup::Repair(_("initrd Modules Missing"), error_message, help_text) ) {
  579.         return `cancel;
  580.     }
  581.     boolean ret           = true;
  582.     string  kernel_initrd = mergestring
  583.         ((list<string>)Initrd::ListModules(), " ");
  584.  
  585.     if ( ! Mode::test () )
  586.     {
  587.         // write INITRD_MODULES - Initrd::Write() could be used?
  588.         SCR::Write (.sysconfig.kernel.INITRD_MODULES, kernel_initrd);
  589.         SCR::Write (.sysconfig.kernel, nil);
  590.  
  591.         string destproc = "/proc";
  592.         SCR::Execute (.target.mkdir, destproc, 0755);
  593.         SCR::Execute (.target.mount, ["proc", destproc], "-t proc");
  594.         ret = (0 == SCR::Execute(.target.bash, "/sbin/mkinitrd >> /var/log/YaST2/y2logmkinitrd 2>> /var/log/YaST2/y2logmkinitrd"));
  595.         SCR::Execute (.target.umount, destproc );
  596.     }
  597.  
  598.     if (! ret)
  599.         {
  600.         // question in a popup box
  601.             if ( Popup::YesNo( _("Calling mkinitrd failed.
  602. Display the log file?
  603. ")))
  604.             {
  605.                 Popup::ShowFile( _("The Output of the Script mkinitrd"), "/var/log/YaST2/y2logmkinitrd" );
  606.             }
  607.         }
  608.     if( ret ) return `ok;
  609.     else return `error;
  610.     }
  611.  
  612. ////////////////////////////////////////////////////////////////////////////
  613. // Check the boot loader configuration files
  614. ////////////////////////////////////////////////////////////////////////////
  615.  
  616.     /**
  617.      * Check if the boot loader conf file exists.
  618.      */
  619.     global define boolean ExistsConf(string loader, string root  )``{
  620.     if ( loader != "" ) bootloader         = loader;
  621.     if ( root   != "" ) root_mountpoint    = root;
  622.  
  623.     // look if the file lilo.conf exists an has a positive size
  624.     if ( ! (SCR::Read(.target.size,  bootloader_config_check[bootloader, "config_file"]:"") > 0 ))
  625.     {
  626.         //No conf file found
  627.         help_text = sformat(_("
  628. <p>The file %1 was not found.</p>"), bootloader_config_check[bootloader, "config_file"]:"") +
  629.  
  630. _("<p>The boot loader configuration file contains
  631. defective data. Depending on the boot loader
  632. type, the syntax of the configuration file
  633. differs. </p>
  634. ");
  635.  
  636.         error_message = _("
  637. The main configuration file of the boot loader was
  638. not found.
  639.  
  640. If you changed the boot loader configuration
  641. manually and the system starts correctly,
  642. skip this dialog and continue the detection
  643. sequence.
  644. If you never changed anything affecting
  645. the boot loader, press Repair
  646. to create a new configuration file.
  647. ");
  648.  
  649.         invalid_config_files = add(invalid_config_files,  bootloader_config_check[bootloader, "config_file"]:"");
  650.         bootloader_error_found = true;
  651.         y2error("can't find boot loader conf file");
  652.         return false;
  653.     }
  654.     return true;
  655.     }
  656.  
  657.  
  658.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  659.     // Check the lilo configuration file
  660.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  661.  
  662.  
  663.     /**
  664.      * Check the lilo conf file.
  665.      */
  666.     define boolean check_lilo_config()``{
  667.  
  668.     // Be careful: use the mountpoint of the root partition for execution of this command!
  669.     string command = sformat("%1/sbin/lilo -r %1 -t -v", root_mountpoint );
  670.  
  671.     if(  OSRExecute::Command(.local.bash, command ))
  672.     {
  673.         return true;
  674.     }
  675.     else {
  676.  
  677.         y2error("lilo config file %1 is not valid", bootloader_config_check[bootloader, "config_file" ]:"");
  678.  
  679.         // help text 1/2
  680.         help_text = _("
  681. <p>The command /sbin/lilo -t checks the syntax
  682. of the LILO boot loader configuration file.</p>
  683. ") +
  684.  
  685. // help text 2/2
  686. _("<p>This command returned an error. This normally means
  687. your system is not bootable.
  688.  
  689. It is recommended to create a new configuration
  690. file.</P>
  691. ");
  692.  
  693.         // error message
  694.         error_message = _("
  695. The syntax of the boot loader configuration
  696. file is not valid.
  697. The configuration file contains defective
  698. data needed for booting the Linux system.
  699.  
  700. Press Repair to generate a new
  701. configuration file automatically.
  702.  
  703. If you are sure your configuration file
  704. contains no errors, press Skip.
  705. ");
  706.         return false;
  707.     }
  708.  
  709.     }
  710.  
  711.  
  712.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  713.     // Device check.
  714.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  715.  
  716.     /**
  717.      * Returns false if the specified device can not
  718.      * found in the target_map (Storage module)
  719.      */
  720.     define boolean exists_device(string dev_name )``{
  721.  
  722.     if(dev_name == "" ) return true;
  723.  
  724.     // if device is a floppy
  725.     if( StorageDevices::FloppyDrives == [] || StorageDevices::FloppyDrives == nil ) StorageDevices::Probe(false);
  726.     y2milestone("FloppyDrives %1", StorageDevices::FloppyDrives );
  727.     map ret =  find(map e, StorageDevices::FloppyDrives, ``(e["dev_orig"]:(e["dev_name"]:"") == dev_name));
  728.     if ( ret != nil && size( ret ) > 0 ) return true;
  729.  
  730.     // if device is a hard disk
  731.     map<string,map> tg = Storage::GetTargetMap();
  732.     ret     = tg[dev_name]:$[];
  733.     if ( ret != nil && size( ret ) > 0 ) return true;
  734.  
  735.     // if device is a partition
  736.     ret = Storage::GetPartition( tg, dev_name );
  737.     if ( ret != nil && size( ret ) > 0 ) return true;
  738.  
  739.     // fix grub bug
  740.     if ( substring( dev_name, 0, 7) == "/dev/fd" )
  741.     {
  742.         return true;
  743.     }
  744.  
  745.     // device does not exists
  746.     y2error("device with name %1 not found", dev_name);
  747.     return false;
  748.     }
  749.  
  750.     /**
  751.      * Convert a grub device (hd0) to a lilo device name (/dev/hda1)
  752.      * grub2Lilo can't convert floppy device.
  753.      */
  754.     define string grubDev2LiloDev(string grub_device )``{
  755.  
  756.     if ( grub_device == "")
  757.         return "";
  758.  
  759.     string ret = "";
  760.     if ( !regexpmatch(grub_device, ".fd.*"))
  761.     {
  762.         ret = grubDev2unixDev (grub_device);
  763.     }
  764.     else
  765.     {
  766.         ret = "/dev/" + substring(grub_device, 1, 3);
  767.     }
  768.     y2milestone("grubDev2unixDev converts %1 to %2", grub_device, ret );
  769.     return ret;
  770.     }
  771.  
  772.     /**
  773.      * Check if a device (grub syntax) exist.
  774.      */
  775.     define boolean exists_grub_device(string grub_device )``{
  776.  
  777.     //"device":"(hd0)"
  778.     if( exists_device(grubDev2LiloDev( grub_device )))
  779.     {
  780.         y2milestone(" device %1 exists", grub_device);
  781.         return true;
  782.     }
  783.     else
  784.     {
  785.         y2error(" device %1 not found", grub_device);
  786.         return false;
  787.     }
  788.     }
  789.  
  790.  
  791.  
  792.     //////////////////////////////////////////////////////////////////
  793.     // grub conf file checks
  794.     //////////////////////////////////////////////////////////////////
  795.  
  796.     /**
  797.      * Check a grub device entry.
  798.      */
  799.     define boolean check_grub_device(string grub_device )``{
  800.     y2milestone("check grub device: %1", grub_device);
  801.     if ( grub_device == "") return true;
  802.     return exists_grub_device(grub_device);
  803.     }
  804.  
  805.     /**
  806.      * Check if the root entry exists and is the expected
  807.      */
  808.     define boolean check_grub_root(string root ) {
  809.  
  810.     y2milestone("check grub root: %1", root);
  811.  
  812.     if (root == "") return true;
  813.  
  814.     if (! exists_grub_device(root)) return false;
  815.  
  816.     string check_dev = root_device;
  817.  
  818.     if( boot_device != root_device )
  819.     {
  820.         check_dev = boot_device;
  821.     }
  822.  
  823.     if( check_dev == grubDev2LiloDev(root)) return true;
  824.     else return false;
  825.     }
  826.  
  827.     /**
  828.      * Check the addr entry of a grub conf file.
  829.      */
  830.     define boolean check_grub_addr( string addr  )``{
  831.     if( addr == "" )
  832.     {
  833.         addr = grub_conf_defaults["addr"]:"";
  834.         y2milestone("adrr not set - use default addr");
  835.     }
  836.  
  837.     if( addr != grub_conf_defaults["addr"]:""){
  838.         y2error("grub addr (%1) changed not default %2", addr, grub_conf_defaults["addr"]:"");
  839.         // TODO is it a problem, that addr is different from default?
  840.     }
  841.     return true;
  842.     }
  843.  
  844.     /**
  845.      *
  846.      */
  847.     define boolean check_grub_discswitch (string discswitch)``{
  848.  
  849.     if (discswitch != "")
  850.     {
  851.         if (discswitch != grub_conf_defaults["discswitch"]:"")
  852.         {
  853.         y2error("grub discswitch (%1) changed not default %2",
  854.             discswitch,  grub_conf_defaults["discswitch"]:"");
  855.         }
  856.     }
  857.     return true;
  858.     }
  859.  
  860.     /**
  861.      * Test if stage1 exist.
  862.      */
  863.     define boolean check_grub_stage1( string stage1 )``{
  864.     if ( stage1 == "" )
  865.     {
  866.         stage1 = bootloader_config_check[bootloader, "stage1"]:"";
  867.     }
  868.     return OSRExecute::Command(.local.bash, sformat(
  869.         "/usr/bin/test -f %1%2 -o -f %1/boot%2", root_mountpoint, stage1));
  870.     }
  871.  
  872.     /**
  873.      * Test if stage2 exist.
  874.      */
  875.     define boolean check_grub_stage2(string stage2)``{
  876.     return OSRExecute::Command(.local.bash, sformat(
  877.         "/usr/bin/test -f %1%2 -o -f %1/boot%2", root_mountpoint, stage2 ));
  878.     }
  879.  
  880.     ///////////////////////////////////////////////////////////////////////////
  881.     // grub menu file checks
  882.     ///////////////////////////////////////////////////////////////////////////
  883.  
  884.     /**
  885.      * Checks the keys of one map.
  886.      */
  887.     define boolean check_grub_menu_entry_map(map entries)``{
  888.     boolean error_found = false;
  889.     foreach(string key, string value, (map<string,string>)entries ,``{
  890.         if( ! contains(valid_grub_menu_enties, key ))
  891.         {
  892.         y2error("key -%1- not found - no valid key", key);
  893.         error_found = true;
  894.         }
  895.     });
  896.     return ! error_found;
  897.     }
  898.  
  899.     /**
  900.      * Check the keys of the specified map.
  901.      * @param entries = $["color":"white/blue black/light-gray",
  902.      *                    "default":"0", "gfxmenu":"(hd0,2)/boot/message",
  903.      *                    "timeout":"8"]
  904.      * @return true if all keys are valid
  905.      */
  906.     define boolean check_grub_global_options(map  entries )``{
  907.     valid_grub_menu_enties =  union( grub_generally, grub_menu_only );
  908.     return check_grub_menu_entry_map(entries);
  909.     }
  910.  
  911.     /**
  912.      * Checks all maps of the specified list.
  913.      * @param entries = [$["initrd":"(hd0,2)/boot/initrd",
  914.      *                   "kernel":"(hd0,2)/boot/vmlinuz root=/dev/hda3   vga=791", "title":"linux"],
  915.      *        error    ->$["asd":"", "chainloader":"+1", "makeactive":"true", "root":"(hd1,0)", "title":"windows"],
  916.      *                   $["chainloader":"+1", "root":"(fd0)", "title":"floppy"],
  917.      *                   $["initrd":"(hd0,2)/boot/initrd.shipped", "kernel":"(hd0,2)/boot/vmlinuz.shipped root=/dev/hda3
  918.      *                      ide=nodma apm=off acpi=off vga=normal nosmp maxcpus=0 disableapic 3", "title":"failsafe"]]
  919.      */
  920.     define boolean check_grub_menu_entries(list entries )``{
  921.     valid_grub_menu_enties = union( grub_menu, grub_menu_only);
  922.     boolean error_found = false;
  923.     foreach(map menu, (list<map<any,any> >)entries, ``{
  924.         error_found = ! (check_grub_menu_entry_map(menu) == false ) ? false : !error_found;
  925.     });
  926.     return ! error_found;
  927.     }
  928.  
  929.    /**
  930.      * reads specified section and returns values as list [$[option:$[value:..., comment:...]]]
  931.      * @param type string sections / ""
  932.      * @param section string
  933.      * @return map map as described above
  934.      */
  935.     global define map sectOptions2Map(string loader ,string type, string section) ``{
  936.     path p = .;
  937.  
  938.     if (type == "")
  939.     {
  940.         p = topath (loader);
  941.     }
  942.     else
  943.     {
  944.         p = add( add (topath (loader), "sections"), section);
  945.     }
  946.  
  947.     list optlist = SCR::Dir(p);
  948.  
  949.     if (type == "")
  950.     {
  951.         optlist = filter(string e, (list<string>) optlist, ``(e != "sections"));
  952.     }
  953.  
  954.     any value   = "";
  955.     map retval  = $[ ];
  956.  
  957.     foreach (string e, (list<string>) optlist, ``{
  958.         value = BootCommon::mod2ui (SCR::Read(add(p, e)));
  959.         if (isSpecial(e))
  960.         {
  961.         retval = add (retval,
  962.             e, mergestring ((list<string>)SCR::Read(add(p, e)), ","));
  963.         }
  964.         else
  965.         {
  966.         retval = add(retval, e, sformat("%1", value));
  967.         }
  968.     });
  969.     return retval;
  970.     }
  971.  
  972.  
  973.     /**
  974.      * Check the grub menu and the grub menu entries.
  975.      */
  976.     define boolean check_grub_menu( string menu )``{
  977.  
  978.     string menu_dev  = "";
  979.     string menu_path = "";
  980.  
  981.     if( menu == "" )
  982.     {
  983.         menu_path = bootloader_config_check["grub", "menu"]:"";
  984.     }
  985.     else {
  986.         menu_dev  = substring(menu, 0, findfirstof(menu, ")") +1 );
  987.         menu_path = substring(menu, findfirstof(menu, ")") +1 );
  988.     }
  989.     y2milestone("menu_path %1, menu_dev %2, menu: %3",menu_path,menu_dev,menu);
  990.  
  991.     if( menu_dev != "" && ! exists_grub_device(menu_dev ) )
  992.     {
  993.         invalid_config_files = add(invalid_config_files, menu_path );
  994.         y2error("grub menu device not found %1", menu);
  995.         return false;
  996.     }
  997.     // TODO: get the real mountpoint for boot partition
  998.     if(!OSRExecute::Command(.local.bash, sformat(
  999.         "/usr/bin/test -f %1%2 -o -f %1/boot%2", root_mountpoint, menu_path)))
  1000.     {
  1001.         invalid_config_files = add(invalid_config_files, menu_path );
  1002.         y2error("grub menu file not found: %1",menu_path);
  1003.         return false;
  1004.     }
  1005.     else
  1006.     {
  1007.         // read grub menu file
  1008.         map global_options = sectOptions2Map("grub" , "", "");
  1009.         list sects         = SCR::Dir(.grub.sections);
  1010.         list sections      = [];
  1011.  
  1012.         foreach(string e, (list<string>) sects, ``{ sections = add(sections, sectOptions2Map("grub", "sections", e)); });
  1013.  
  1014.         // debug grub menu file
  1015.         y2milestone("options  : %1", global_options );
  1016.         y2milestone("sections : %1", sections       );
  1017.  
  1018.         // check keys in the grub menu file
  1019.         boolean ret = check_grub_global_options(global_options) && check_grub_menu_entries(sections);
  1020.  
  1021.         if( ! ret )
  1022.         {
  1023.         y2error("the grub menu file is not valid");
  1024.         invalid_config_files = add(invalid_config_files, menu_path );
  1025.         }
  1026.         return ret;
  1027.     }
  1028.     }
  1029.  
  1030.  
  1031.     /**
  1032.      * Check the grub device map.
  1033.      */
  1034.     define boolean check_grub_device_map()``{
  1035.  
  1036.     // TODO: get the real mountpoint for boot partition
  1037.     string grub_dir = root_mountpoint +  "/boot/grub";
  1038.     if (! OSRExecute::Command(.local.bash, sformat("/usr/bin/test -d %1",grub_dir)))
  1039.     {
  1040.         y2error("grub directory does not exist");
  1041.         invalid_config_files = add(invalid_config_files, bootloader_config_check[bootloader, "device_map"]:"" );
  1042.         return false;
  1043.     }
  1044.  
  1045.     string dev_map = (string) SCR::Read(.target.string,
  1046.         bootloader_config_check[bootloader, "device_map"]:"" );
  1047.  
  1048.     if( dev_map == "" || dev_map == nil )
  1049.     {
  1050.         y2error("reading device map was not successful");
  1051.         invalid_config_files = add(invalid_config_files, bootloader_config_check[bootloader, "device_map"]:"" );
  1052.         return false;
  1053.     }
  1054.  
  1055.     list maps = filter (string e, splitstring (dev_map, "\n"), ``(e != ""));
  1056.     maps      = maplist (string e, (list<string>) maps, ``{
  1057.         return filter (string f, splitstring (e, " \t"), ``(f != ""));
  1058.     });
  1059.  
  1060.     boolean error_found = false;
  1061.     foreach (list e, (list<list<any> >)maps, ``{
  1062.         if ( ! error_found )
  1063.         {
  1064.         error_found = ! exists_grub_device( e[0]:"");
  1065.         if( error_found )
  1066.             y2error("grub device map: device not found %1", e[0]:"");
  1067.         }
  1068.         if ( ! error_found )
  1069.         {
  1070.         error_found = ! exists_device (e[1]:"");
  1071.         if ( error_found )
  1072.             y2error("grub device map: device not found %1", e[0]:"");
  1073.         }
  1074.     });
  1075.  
  1076.     if ( error_found == nil || error_found  )
  1077.     {
  1078.         invalid_config_files = add(invalid_config_files,  bootloader_config_check[bootloader, "device_map"]:"" );
  1079.  
  1080.         return false;
  1081.     }
  1082.     return true;
  1083.     }
  1084.  
  1085.     /**
  1086.      * Check the sysntax of grub configuration files:
  1087.      * /boot/grub/device.map
  1088.      * /boot/grub/menu.lst
  1089.      * /etc/grub.conf
  1090.      */
  1091.     define boolean check_grub_config() {
  1092.  
  1093.     // check /boot/grub/device.map
  1094.     // (fd0)   /dev/fd0
  1095.     // (hd0)   /dev/hda
  1096.     // (hd1)   /dev/hdb
  1097.     boolean grub_device_map = check_grub_device_map();
  1098.     if (!grub_device_map)
  1099.     {
  1100.         y2error("grub devide map contains errors");
  1101.     }
  1102.  
  1103.     /* systax of grub_conf:
  1104.       $[
  1105.         "addr"        : "0x8000",
  1106.         "device"        : "(hd0)",
  1107.         "discswitch"    : true,
  1108.         "menu"        : "(hd0,2)/boot/grub/menu.lst",
  1109.         "root"        : "(hd0,2)",
  1110.         "s2prefix"        : "--stage2=/boot/grub/stage2",
  1111.         "stage1"        : "/boot/grub/stage1",
  1112.         "stage2"        : "/boot/grub/stage2"]
  1113.     */
  1114.     string conf_file_contens = (string) SCR::Read(.target.string,
  1115.         bootloader_config_check[bootloader, "config_file"]:"");
  1116.  
  1117.     map grub_conf = parseGrubConf (conf_file_contens);
  1118.         y2internal ("grub_conf: %1", grub_conf);
  1119.  
  1120.     boolean embedding    = false;
  1121.     if (grub_conf["command"]:"" == "setup")
  1122.     {
  1123.         embedding        = true;
  1124.         y2milestone ("embedding stage 1.5 -> reduced checking");
  1125.     }
  1126.  
  1127.     readDeviceMap ();
  1128.  
  1129.     boolean grub_device    = check_grub_device (grub_conf["device"]:"" );
  1130.     boolean grub_root       = check_grub_root (grub_conf["root"]:"" );
  1131.     boolean grub_addr    = embedding ||
  1132.                 check_grub_addr (grub_conf["addr"]:"" );
  1133.     boolean grub_discheck    = embedding ||
  1134.                 check_grub_discswitch (grub_conf["discswitch"]:"");
  1135.     boolean grub_stage1    = embedding ||
  1136.                 check_grub_stage1 (grub_conf["stage1"]:"");
  1137.     boolean grub_stage2    = embedding ||
  1138.                 check_grub_stage2 (grub_conf["stage2"]:"");
  1139.     boolean grub_menu    = embedding ||
  1140.                 check_grub_menu (grub_conf["menu"]:"" );
  1141.  
  1142.     if ( ! grub_device )
  1143.         y2error("grub conf device entry is invalid");
  1144.     if ( ! grub_root   )
  1145.         y2error("grub conf root entry is invalid");
  1146.     if ( ! grub_addr   )
  1147.         y2error("grub conf addr entry is invalid");
  1148.     if ( ! grub_discheck)
  1149.         y2error("grub conf discswitch entry is invalid");
  1150.     if ( ! grub_stage1 )
  1151.         y2error("grub conf state1 is invalid");
  1152.     if ( ! grub_stage2 )
  1153.         y2error("grub conf state2 is invalid");
  1154.  
  1155.     if ( grub_menu == nil ) {
  1156.         y2error("grub menu is invalid");
  1157.         grub_menu = false;
  1158.     }
  1159.     if (grub_device && grub_root && grub_addr && grub_menu &&
  1160.         grub_discheck && grub_stage1 && grub_stage2 && grub_device_map)
  1161.     {
  1162.         return true;
  1163.     }
  1164.     else
  1165.     {
  1166.         string menu_path = grub_conf["menu"]:"";
  1167.         if (menu_path == "" || menu_path == nil)
  1168.         {
  1169.         menu_path = bootloader_config_check[bootloader, "menu"]:"";
  1170.         }
  1171.         else
  1172.         {
  1173.         menu_path = substring(menu_path , findfirstof(menu_path, ")") +1 );
  1174.         }
  1175.  
  1176.         // help text 1/4
  1177.         help_text = _("
  1178. <p>A default GRUB installation needs three
  1179. configuration files:</p>
  1180. ") +
  1181.  
  1182.         sformat("<p>%1</p>", mergestring ([
  1183.         bootloader_config_check [bootloader, "device_map"]:"",
  1184.         bootloader_config_check [bootloader, "config_file"]:"",
  1185.         menu_path
  1186.         ],"<br>")) +
  1187.  
  1188. // help text 2/4
  1189. _("<P>The following files
  1190. are not valid:</p>
  1191. ") +
  1192.  
  1193.         sformat ("<p>%1</p>", mergestring (invalid_config_files, "<br>")) +
  1194.  
  1195. // help text 3/4
  1196. _("<p>This generally means that your system is not
  1197. bootable.</p>
  1198. ") +
  1199.  
  1200. // help text 4/4
  1201. _("<p>Creating a new boot loader
  1202. configuration is recommended.</p>
  1203. ");
  1204.  
  1205.         // error text
  1206.         error_message = _("
  1207. The configuration of the boot loader
  1208. contains errors.
  1209.  
  1210. Press Repair to generate a new
  1211. configuration automatically.
  1212.  
  1213. If you are sure your configuration
  1214. contains no errors and your system
  1215. is bootable, press Skip.
  1216. ");
  1217.  
  1218.         return false;
  1219.     }
  1220.     }
  1221.  
  1222.     /**
  1223.      * Check the boot loader configuration.
  1224.      */
  1225.     global define boolean CheckConfig(string loader , string root, string root_dev, string boot_dev )``{
  1226.  
  1227.     if ( loader   != "" )  bootloader     = loader;
  1228.     if ( root     != "" )  root_mountpoint    = root;
  1229.     if ( root_dev != "" )  root_device    = root_dev;
  1230.     if ( boot_dev != "" )  boot_device     = boot_dev;
  1231.  
  1232.     // reset settings
  1233.     error_message         = "";
  1234.     help_text         = "";
  1235.     invalid_config_files     = [];
  1236.  
  1237.     if (!haskey (bootloader_config_check [bootloader]:$[], "config_check"))
  1238.     {
  1239.         y2error("boot loader config check not supported");
  1240.         bootloader_error_found = true;
  1241.         return false;
  1242.     }
  1243.     boolean () check_f =
  1244.         bootloader_config_check[bootloader,"config_check"]:OSRCommon::False;
  1245.     if (!Mode::test () && !check_f ())
  1246.     {
  1247.         bootloader_error_found = true;
  1248.         y2error("boot loader config check returned an error");
  1249.         return false;
  1250.     }
  1251.     return true;
  1252.     }
  1253.  
  1254.  
  1255.     /**
  1256.      * Repair a damaged grub configuration.
  1257.      */
  1258.     global define symbol repair_grub_config()``{
  1259.  
  1260.     // change root for boot loader module call - why??
  1261.     Bootloader::setLoaderType (nil);
  1262.     Bootloader::Reset();
  1263.     Bootloader::Propose(); // does not read current configuration...
  1264.     map retmap = (map)
  1265.         WFM::CallFunction ("bootloader_proposal",["AskUser", $[]]);
  1266.     symbol ret = retmap["workflow_sequence"]:`next;
  1267.  
  1268.     if( ret == `next )
  1269.     {
  1270.         Wizard::CreateDialog ();
  1271.  
  1272.         // prepare environment for saving boot loader settings
  1273.         string destproc = "/proc";
  1274.         SCR::Execute (.target.mkdir, destproc, 0755);
  1275.         SCR::Execute (.target.mount, ["proc", destproc], "-t proc");
  1276.         SCR::Execute (.target.bash, "/sbin/SuSEconfig --module bootsplash");
  1277.  
  1278.         boolean g_ret = Bootloader::Write();
  1279.         Wizard::CloseDialog();
  1280.  
  1281.         if ( g_ret )
  1282.         // message popup
  1283.           Report::Message(_("The boot loader was installed successfully."));
  1284.  
  1285.         SCR::Execute (.target.umount, "/proc");
  1286.         WFM::Execute(.local.umount, root_mountpoint + "/proc" );
  1287.     }
  1288.     return ret;
  1289.     }
  1290.  
  1291.  
  1292.     /**
  1293.      * Repair a damaged boot loader configuration.
  1294.      */
  1295.     global define symbol RepairConfig(string loader, boolean show_message )``{
  1296.     if ( loader != "" ) bootloader = loader;
  1297.     if ( show_message  )
  1298.     {
  1299.         // popup headline
  1300.         if ( !OSRPopup::Repair (_("Boot Loader Error Detected"),
  1301.             error_message, help_text))
  1302.         {
  1303.         return `cancel;
  1304.         }
  1305.     }
  1306.  
  1307.     // set needed value Boot::initrdModules
  1308.     CheckInitrdModules( root_mountpoint );
  1309.     if (!haskey (bootloader_config_check [bootloader]:$[], "config_repair"))
  1310.     {
  1311.         y2error("boot loader config repair not supported");
  1312.         return `error;
  1313.     }
  1314.     symbol () repair_f = bootloader_config_check [bootloader, "config_repair"]:OSRCommon::SymbolError;
  1315.     return repair_f ();
  1316.     }
  1317.  
  1318.     /**
  1319.      * Install a new boot loader
  1320.      */
  1321.     global define symbol InstallNewLoader()``{
  1322.  
  1323.     error_message = _("
  1324. No valid boot loader installation
  1325. can be found. Installing
  1326. a new boot loader is recommended.
  1327.  
  1328. If you are sure your system boots
  1329. correctly, it is not necessary to
  1330. reinstall the boot loader.
  1331.  
  1332. Otherwise, press Repair
  1333. to install a new boot loader.
  1334. ");
  1335.  
  1336.     help_text = _("
  1337. <P>The boot loader is the first thing
  1338. you should see after you turn
  1339. on a computer with a Linux installation.
  1340. Starting a Linux system without
  1341. a boot loader is not possible.</P>
  1342. ") +
  1343.  
  1344. _("<P>If you have installed more than
  1345. one operating system on a computer,
  1346. the boot loader allows you to select
  1347. which system to start.</P>
  1348. ");
  1349.     bootloader = "";
  1350.     return RepairConfig("",true);
  1351.     }
  1352.  
  1353.  
  1354.     /**
  1355.      * Repairing configuration files.
  1356.      */
  1357.     global define symbol RepairSysconfigFiles()``{
  1358.  
  1359.     // repairing not possible
  1360.     if( contains ( not_valid_files, needed_config_files["modules"]:"") )
  1361.     {
  1362.         y2error("repairing %1 is not possible", needed_config_files["modules"]:"");
  1363.         Report::Error(sformat (_("
  1364. The file %1 was not found.
  1365. It cannot be recovered.
  1366. "), needed_config_files["modules"]:""));
  1367.         return `error;
  1368.     }
  1369.  
  1370.     list<string> t_not_valid_file = filter(string file, not_valid_files, ``( file != needed_config_files["modules"]:"" ));
  1371.  
  1372.     error_message = sformat(_("
  1373. The following configuration 
  1374. files cannot be found:
  1375.  
  1376. %1
  1377.  
  1378. Installing a new
  1379. boot loader is recommended.
  1380.  
  1381. If you are sure your system boots
  1382. correctly, it is not necessary to
  1383. reinstall the boot loader.
  1384.  
  1385. Otherwise, press Repair
  1386. to install a new boot loader.
  1387. "), mergestring(maplist(string file, not_valid_files, ``(file)), "\n"));
  1388.  
  1389.  
  1390.     return RepairConfig(bootloader,true);
  1391.     }
  1392. }//EOF
  1393.