home *** CD-ROM | disk | FTP | other *** search
/ Chip 2000 May / Chip_2000-05_cd2.bin / suse / inst-sys / lib / YaST2 / clients / installation.ycp < prev    next >
Encoding:
Text File  |  2000-03-30  |  20.2 KB  |  641 lines

  1. /**
  2.  * Module:              installation.ycp
  3.  *
  4.  * Authors:             Mathias Kettner (kettner@suse.de)
  5.  *
  6.  * Purpose:             Setup the UI and define macros for the
  7.  *                      installation dialog, general framework, ...
  8.  *                      Describing and calling all submodules, depending on
  9.  *                      the installation should be started or continued.
  10.  *                      
  11.  * user_settings:       add:    continue_mode
  12.  *                      used:   language
  13.  *                      add:    targets
  14.  *                      add:    architecture
  15.  *                      add:    boot_mode
  16.  *                      add:    has_floppy
  17.  *                      add:    mouse_id
  18.  *                      add:    mouse
  19.  *                      used:   automode
  20.  *                      used:   instmode
  21.  *                      used:   keyboard
  22.  *
  23.  */
  24. {
  25.     string default_language = "en";
  26.     string default_architecture = "i386";
  27.  
  28.     /*
  29.      * test command line arguments for test mode and continue mode
  30.      */
  31.     
  32.     integer arg_n = size(Args()) - 1;
  33.     boolean test_mode = false;
  34.     boolean continue_mode = false;
  35.  
  36.     while (arg_n >= 0) {
  37.         if (Args(arg_n) == .test) {
  38.             test_mode = true;
  39.         }
  40.  
  41.         if (Args(arg_n) == .continue) {
  42.             continue_mode = true;
  43.         }
  44.         
  45.         arg_n = arg_n - 1;
  46.     }
  47.             
  48.  
  49.     /*
  50.      * Define macros for use in the submodules.
  51.      */
  52.  
  53.     /*
  54.      * Define a macro that looks up a localized string in a language map
  55.      * of the form $[ "default" : "Defaultstring", "de" : "German....", ...]
  56.      */
  57.  
  58.     define translate(map lmap, string lang) ``{
  59.         string|void t = lookup(lmap, lang, nil);
  60.         if (t == nil && size(lang) > 2) t = lookup(lmap, substring(lang, 0, 2), nil);
  61.         if (t == nil) t = lookup(lmap, "default", nil);
  62.         return t;
  63.     };
  64.  
  65.  
  66.     /*
  67.      * Fallback in case the first parameter is no language map but a string
  68.      */
  69.     
  70.     define translate(string s, string lang) ``{
  71.         return s;
  72.     };
  73.  
  74.  
  75.     integer current_stage = -1;
  76.     
  77.     /*
  78.      * Set the wizard installation stage, i.e. the indicator of how
  79.      * far the installation has progressed yet.
  80.      * Sets the wizard header image accordingly.
  81.      */
  82.  
  83.     define SetWizardStage( integer stage, boolean force ) ``{
  84.     
  85.     if ( stage == current_stage && ! force )    // cache
  86.     {
  87.         y2log( .debug, "installation", 666, sformat("Stage %1 cached - doing nothing", stage ) );
  88.         return;
  89.     }
  90.  
  91.     y2log( .debug, "installation", 666, sformat("Setting stage to %1", stage ) );
  92.     
  93.     // Set the header image according to the stage
  94.     UI( `SetWizardImage( ReadByteblock( sformat( "/lib/YaST2/images/stage%1.png", stage ) ) ) );
  95.  
  96.     // Cache the current stage
  97.     current_stage = stage;
  98.     };
  99.  
  100.   // ==================================================================================
  101.  
  102.   /*
  103.    * Set the X mouse as specified.
  104.    * Uses the 'mset' command (originally from SaX).
  105.    *
  106.    * used by inst_startup and inst_mouse
  107.    */
  108.  
  109.   define SetXMouse( map mouse_params ) ``{
  110.       string emul3 = "off";
  111.       
  112.       if ( lookup ( mouse_params, "emul3", false ) )
  113.       emul3 = "on";
  114.       
  115.       // mset <device> <mousetype> <baudrate> <samplerate> <resolution> <buttons> <emul3> <timeout> <chordmiddle>
  116.       //        [ClearDTR] [ClearRTS] [ReOpen]
  117.       // Example:   mset /dev/psaux PS/2 1200 60 0 3 off 50 off
  118.  
  119.  
  120.       string mset_command = sformat ( "/lib/YaST2/bin/mset %1 %2 1200 60 0 3 %3 50 off",
  121.                       lookup ( mouse_params, "device", "/dev/mouse" ),
  122.                       lookup ( mouse_params, "xf86",   "PS/2" ),
  123.                       emul3 );
  124.  
  125.       if ( test_mode )
  126.       y2log( .milestone, "inst_mouse", 1,
  127.          "Test mode - NOT setting X mouse - would have called:\n" + mset_command );
  128.       else {
  129.       integer result = Shell( mset_command, $["DISPLAY" : ":0.0"] );
  130.       }
  131.   };
  132.  
  133.   // ==================================================================================
  134.   
  135.   
  136.     /*
  137.      * for PPC: convert pdisk output to fdisk output format
  138.      */
  139.  
  140.     define pdisk2target (list pdisk_data) ``{
  141.     list partitions = [];
  142.  
  143.     foreach (`pentry, pdisk_data, ``{
  144.         // make partition entry map, start with dummy fsid entry
  145.         map part = $["fsid":0, "type":`pdisk];
  146.  
  147.          if (lookup (pentry, "type") == nil) continue;
  148.   
  149.          string fstype = lookup (pentry, "type");
  150.  
  151.          if (lookup (pentry, "name") != nil)
  152.          fstype = fstype + " (" + lookup (pentry, "name") + ")";
  153.  
  154.          // fstype
  155.          part = add (part, "fstype", fstype);
  156.          // nr
  157.          part = add (part, "nr", lookup (pentry, "nr"));
  158.   
  159.          part = add (part, "region", [(lookup (pentry, "base") / 64), (lookup (pentry, "length") / 64)]);
  160.   
  161.          partitions = add (partitions, part);
  162.   
  163.      }); // foreach
  164.   
  165.         return partitions;
  166.   
  167.     }; // pdisk2target
  168.  
  169.  
  170.     // ------------------------------------------------------
  171.     // check partitions for given disk (as path, i.e. '.sda')
  172.     // returns list as specified in README.target_partition
  173.     //
  174.     
  175.     define check4partitions (path diskpath, string architecture) ``{
  176.  
  177.     list partitions = SCR(`Read(.disk + diskpath + .partitions));
  178.  
  179.     // fdisk may fail on ppc, check with pdisk in this case
  180.  
  181.     if ((partitions == []) && (architecture == "ppc")) {
  182.         partitions = pdisk2target (SCR(`Read(.pdisk + diskpath)));
  183.     }
  184.  
  185.     if (test_mode) y2log (.milestone, "check4partitions", 1, "partitions " + partitions);
  186.  
  187.     return partitions;
  188.     };
  189.  
  190.   // ==================================================================================
  191.  
  192.   /*
  193.    * Define a macro that transforms information about all partitions ( from
  194.    * user_settings( "targets" ) ) into a list(map) with information about partitions
  195.    * which are available for installation, e.g.:
  196.    *
  197.    * [$["free":1625676, "name":"/boot", "used":0], $["free":2210406, "name":"/", "used":0]]
  198.    * 
  199.    * Please note: in 6.4 there isn't any information about used space, so "used" at begin
  200.    *              of installation is initialized with zero; size "free" in KBytes
  201.    *              
  202.    */
  203.  
  204.   define get_partition_info( map targets, boolean remove_slash ) ``{
  205.       
  206.       list(map) target_partitions = [];
  207.       integer spare_percentage     = 22;    // percentage of free spare space on every partition
  208.       integer min_spare     = 2048; // minimum free space ( 2 MB )
  209.       
  210.       foreach( `disk, `diskinfo, targets, ``{  
  211.  
  212.       list part_info = lookup( diskinfo, "partitions" );
  213.  
  214.       foreach( `part, part_info, ``{
  215.           integer free_size = 0;
  216.           integer spare_size = 0;
  217.           
  218.           if ( lookup( part, "mount", nil ) != nil && substring( lookup( part, "mount"), 0, 1 ) == "/" )
  219.           {
  220.           if ( lookup( part, "create", nil ) == true || lookup( part, "delete", nil ) == false ||
  221.                ( lookup( part, "create", nil) == nil && lookup( part, "delete", nil ) == nil ) )
  222.           {
  223.               _debug( "get_partition_info: adding partition: ", part );
  224.  
  225.               // get free space ("region", second value ) * cyl_size in KBytes
  226.               free_size = select( lookup( part, "region" ), 1 ) * (lookup( diskinfo,"cyl_size")/1024);
  227.  
  228.               spare_size = (free_size*spare_percentage)/100;
  229.  
  230.               if ( spare_size < min_spare )
  231.               {
  232.               spare_size = min_spare;
  233.               }
  234.               free_size = free_size - spare_size; 
  235.  
  236.               y2log( .milestone, "installation", 1, sformat( "available partition: mount: %1, free: %2 KB",
  237.                                  lookup( part, "mount" ), free_size) );
  238.               if ( !remove_slash)
  239.               {
  240.               target_partitions = add ( target_partitions, $["name":lookup( part, "mount" ), "used":0, "free":free_size,
  241.                         "region":lookup( part, "region" ), "used_fs":lookup( part, "used_fs" )  ] );
  242.               }
  243.               else
  244.               {
  245.               string part_name = "";
  246.               string mount_name = lookup( part, "mount");
  247.  
  248.               if ( mount_name != "/" )
  249.               {
  250.                   part_name = substring( mount_name, 1, size(mount_name) );
  251.               }
  252.               else
  253.               {
  254.                   part_name = mount_name;
  255.               }
  256.  
  257.               target_partitions = add ( target_partitions, $["name":part_name, "used":0, "free":free_size,
  258.                                     "region":lookup( part, "region" ), "used_fs":lookup( part, "used_fs" )  ] );
  259.               
  260.               }
  261.  
  262.           }
  263.           }
  264.       } );
  265.       } );
  266.  
  267.       _debug( "get_partition_info: ", target_partitions );
  268.       
  269.       return ( target_partitions );
  270.   };
  271.  
  272.   
  273.   UI(``{
  274.       /**
  275.        * Create a typical installation wizard dialog.
  276.        */
  277.       OpenDialog( `opt(`defaultsize),
  278.                   `VBox(
  279.                         `ReplacePoint( `id(`image ), `Image( `suseheader, "SuSE") ),
  280.                         `HBox(
  281.                               `HWeight( 30, `ReplacePoint( `id(`helpSpace), `RichText(`id(`help), ""))),
  282.                               `HWeight( 70, `VBox(
  283.                                                   `Left(`Heading(`id(`title), _("YaST2\nInitializing ..."))),
  284.                                                   `HVCenter(`ReplacePoint(`id(`contents), `Empty())),
  285.                                                   `HBox(
  286.                                                         // back pushbutton: the user input is ignored and the last dialog is called
  287.                                                         `PushButton(`id(`back), _("&Back")),
  288.                                                         `HStretch(),
  289.                             `ReplacePoint( `id(`rep_next),
  290.                                        // next pushbutton: the user input is checked and the next dialog is called
  291.                                        `PushButton(`id(`next), _("&Next"))
  292.                                        )
  293.                                                         )
  294.                                                   )
  295.                                        )
  296.                               )
  297.                         )
  298.                  );
  299.       
  300.  
  301.       /*
  302.        * Define how the general framework for the installation wizard should
  303.        * look like. This Macro creates and show a dialog.
  304.        */
  305.  
  306.       define SetWizardContents(string title, term contents, string helptext,
  307.                               boolean has_back, boolean has_next) ``{
  308.         ChangeWidget(`id(`back), `Enabled, has_back);
  309.         ChangeWidget(`id(`next), `Enabled, has_next);
  310.         ChangeWidget(`id(`help), `Value, helptext);
  311.         ChangeWidget(`id(`title), `Value, title);
  312.         ReplaceWidget(`id(`contents), contents);
  313.         SetFocus( `id(`next) );
  314.       };
  315.  
  316.  
  317.       /*
  318.        * Change the image at the top of the window.
  319.        */
  320.       define SetWizardImage(byteblock|void imagedata) ``{
  321.           if (imagedata == nil)
  322.       {
  323.           y2log(.warning, "installation", 1, "SetWizardImage(): Invalid image - using fallback" );
  324.               ReplaceWidget( `id(`image), `Image(`suseheader, "SuSE") );
  325.       }
  326.           else  
  327.               ReplaceWidget( `id(`image), `Image(imagedata, "SuSE") );
  328.       };
  329.       
  330.       /*
  331.        * Replace the wizard help subwindow with a custom widget.
  332.        * Call this BEFORE SetWizardContents() to avoid geometry
  333.        * management problems!
  334.        *
  335.        * Remember to restore the help subwindow with
  336.        * RestoreWizardHelp() before any other module is called!
  337.        */
  338.       define ReplaceWizardHelp(term contents) ``{
  339.           ReplaceWidget(`id(`helpSpace), contents);
  340.       };
  341.  
  342.  
  343.       /*
  344.        * Restore the wizard help subwindow after ReplaceWizardHelp().
  345.        */
  346.       define RestoreWizardHelp(string helpText) ``{
  347.           ReplaceWidget(`id(`helpSpace), `RichText(`id(`help), helpText ) );
  348.       };
  349.  
  350.  
  351.       /*
  352.        * Replace the wizard 'next' button with a custom widget.
  353.        */
  354.       define ReplaceWizardNextButton(term contents) ``{
  355.       ReplaceWidget(`id(`rep_next), contents);
  356.       };
  357.  
  358.  
  359.       /*
  360.        * Restore the wizard 'next' button after ReplaceWizardNextButton().
  361.        */
  362.       define RestoreWizardNextButton() ``{
  363.       ReplaceWidget(`id(`rep_next), 
  364.             // next pushbutton: the user input is checked and the next dialog is called
  365.             `PushButton(`id(`next), _("&Next") )
  366.             );
  367.       };
  368.  
  369.       /*
  370.        * Small dialog that has a next, cancel and back button that
  371.        * appears, if one of the submodules does not work. This is
  372.        * useful during development.
  373.        */
  374.       // DEBUG
  375.       define ModuleError(string text) ``{
  376.         OpenDialog(`opt(`decorated),
  377.            `VBox(`Label(text),
  378.                          `HBox(`PushButton(`id(`back), "&Back"),
  379.                                `PushButton(`id(`cancel), "&Cancel"),
  380.                                `PushButton(`id(`again), "&Again"),
  381.                                `PushButton(`id(`next), "&Next"))));
  382.         any r = UserInput();
  383.         CloseDialog();
  384.         return r;
  385.       };
  386.  
  387.       /*
  388.        * Displays a message to the user in a small dialog with an OK
  389.        * button.
  390.        */
  391.  
  392.       define DisplayMessage(string message) ``{
  393.           // ok pushbutton: confirm the dialog
  394.           OpenDialog(`opt(`decorated),
  395.              `VBox(`Label(message),
  396.                `PushButton(`opt(`default), _("&OK"))));
  397.           UserInput();
  398.           CloseDialog();
  399.       };
  400.  
  401.       /**
  402.     * Displays a message with timeout to the user in a small dialog
  403.     * with an OK
  404.     * button.
  405.     */
  406.  
  407.       define DisplayTimedMessage(string message, integer seconds) ``{
  408.           // ok pushbutton: confirm the dialog
  409.           OpenDialog(`opt(`decorated),
  410.              `VBox(`Label(message),
  411.                `HCenter(`Label(`id(`remaining_time), ""+seconds)),
  412.                `HBox(`PushButton(`id(`timed_stop), _("&Stop")),
  413.                  `PushButton(`id(`timed_ok), `opt(`default), _("&OK")))));
  414.       sleep (1000);
  415.       any which_input = `empty;
  416.       while (seconds > 0) {
  417.         which_input = PollInput();
  418.         if (which_input == `timed_ok)
  419.         break;
  420.         if (which_input == `timed_stop) {
  421.         while (which_input == `timed_stop)
  422.             which_input = UserInput();
  423.         break;
  424.         }
  425.         sleep (1000);
  426.         seconds = seconds - 1;
  427.         ChangeWidget (`id(`remaining_time), `Value, ""+seconds);
  428.       }
  429.           CloseDialog();
  430.       };
  431.  
  432.       /*
  433.        * Are your sure?
  434.        */
  435.  
  436.       define YesOrNo(any message, string yes_button_message, string no_button_message) ``{
  437.           OpenDialog(`opt(`decorated),
  438.                      `VBox(`Label(message), 
  439.                            `HBox(
  440.                                  `PushButton(`id(`yes), `opt(`default), yes_button_message),
  441.                                  `HStretch(),
  442.                                  // no pushbutton:  the dialog is not confirmed
  443.                                  `PushButton( no_button_message )
  444.                  )
  445.                )
  446.              );
  447.           any ret = UserInput();
  448.           CloseDialog();
  449.           return (ret == `yes);
  450.       };
  451.       
  452.  
  453.       // Return a pretty description of a byte count, with two fraction digits
  454.       // and using KB, MB or GB as unit as appropriate.
  455.       define size_text (integer bytes) ``{
  456.         float whole = tofloat (bytes) / 1024.0;
  457.         // KiloByte abbreviated
  458.         string unit = _("KB");
  459.         if (whole > 1024.0)
  460.           {
  461.             whole = whole / 1024.0;
  462.             // MegaByte abbreviated
  463.             unit = _("MB");
  464.             if (whole > 1024.0)
  465.               {
  466.                 whole = whole / 1024.0;
  467.                 // GigaByte abbreviated
  468.                 unit = _("GB");
  469.               }
  470.           }
  471.         return tostring (whole, 2) + " " + unit;
  472.       };
  473.  
  474.       /*
  475.        * Small dialog that has a cancel and continue button that
  476.        * appears just befor the video mode is tested.
  477.        */
  478.       define ContinueCancel(string message,
  479.                 string continue_button_message,
  480.                 string cancel_button_message ) ``{
  481.         OpenDialog(`opt(`decorated),
  482.            `VBox(`Label(message),
  483.                          `HBox(
  484.                                `PushButton(`id(`continue), `opt(`default),continue_button_message),
  485.                    `PushButton(`id(`cancel),   cancel_button_message)
  486.                    )
  487.              )
  488.            );
  489.         any r = UserInput();
  490.         CloseDialog();
  491.         return ( r == `continue );
  492.       };
  493.   });
  494.  
  495.   string mountpoint = "/var/adm/mount";
  496.   map user_settings = $["mountpoint":mountpoint];
  497.  
  498.   /*
  499.    * The first argument to this module decides, if the installation
  500.    * should be _started_ or _continued_. If the first argument
  501.    * is given and is .continue, we have a different list of modules
  502.    */
  503.   list modules = [];
  504.   integer m = 0; // current module
  505.  
  506.  
  507.   if (test_mode) {
  508.       user_settings = add(user_settings, "test_mode", true);
  509.       y2log(.warning, "installation", 1, "***** Test mode enabled *****");
  510.   }
  511.   
  512.   if (continue_mode) {
  513.       modules =
  514.       [
  515.        [ `inst_rpmcopy    (false, false), 7 ],
  516.        [ `inst_config_x11    (true, true),   7 ],
  517.        [ `inst_suseconfig    (false, false), 8 ],
  518.        [ `inst_ask_config    (false, true),  8 ]
  519.           ];
  520.  
  521.       // Read the final settings of the first part of the installation.
  522.       user_settings = Read("/var/lib/YaST2/settings.ycp");
  523.       // Add marker for the second pass.
  524.       user_settings = add(user_settings, "continue_mode", true);
  525.       UI(`SetLanguage(lookup (user_settings, "language", default_language)));
  526.       //      UI(`SetKeyboard(lookup (user_settings, "keyboard", "english-us")));
  527.   }
  528.   else {
  529.       /*
  530.        * Try to load user_settings from disk.
  531.        * If none are found, we simply use an empty map.
  532.        */
  533.       Shell("mount /dev/fd0 /floppy -t msdos");
  534.       any r = ReadY2("settings.ycp");
  535.       if (is(r, map)) {
  536.           user_settings = r;
  537.           _debug("Read user settings: ", user_settings);
  538.       }
  539.       Shell("umount /floppy");
  540.  
  541.       modules =
  542.       [
  543.        // module                  back   next  stage
  544.        [ `inst_language          (false, true),  1 ],
  545.        [ `inst_mouse             (true,  true),  1 ],
  546.        [ `inst_environment       (true,  true),  1 ],
  547.        [ `inst_mode              (true,  true),  2 ],
  548.        [ `inst_target_selection  (true,  true),  2 ],
  549.        [ `inst_target_part       (true,  true),  2 ],
  550.        [ `inst_custom_part       (true,  true),  2 ],
  551.        [ `inst_sw_select         (true,  true),  3 ],
  552.        [ `inst_lilo_info         (true,  true),  4 ],
  553.        [ `inst_user              (true,  true),  5 ],
  554.        [ `inst_root              (true,  true),  5 ],
  555.        [ `inst_doit              (true,  true),  6 ],
  556.        [ `inst_prepdisk          (false, false), 6 ],
  557.        [ `inst_rpmcopy         (false, false), 6 ],
  558.        [ `inst_finish         (false, false), 6 ]
  559.  
  560.       ];
  561.       
  562.  
  563.       /*
  564.        * Show warning, if existent.
  565.        */
  566.  
  567.       string warnfile = "/var/adm/mount/suse/setup/descr/common.war";
  568.       string|void warning = ReadString(warnfile);
  569.       if (warning != nil) {
  570.           UI(`DisplayMessage(warning));
  571.       }
  572.  
  573.       // pass targets to user_settings
  574.  
  575.       if ( ! test_mode ) {
  576.       SetWizardStage (1, false);
  577.       CallFunction (`inst_startup ());
  578.       // inst_startup might return `cancel if no disks were found
  579.       // we allow this for now (diskless client installation ?!)
  580.       // if (xxx == `cancel) { return `cancel; // no disks found !! }
  581.       }
  582.  
  583.       if (lookup(user_settings, "automode") == .doit) m = 10;
  584.   }
  585.  
  586.  
  587.   // All settings the user does are saved into a map. The submodules
  588.   // are called as functions and thus have access to this variable.
  589.   // They return `next, `back, `cancel, `again or `auto.
  590.   // A submodule that can't be loaded (syntax error) returns nil.
  591.  
  592.   any former_result = nil;
  593.   
  594.   while ((m >= 0) && (m < size(modules)))
  595.   {
  596.       list    module_info = select( modules, m);
  597.       term    argterm     = select( module_info, 0);
  598.       integer    stage         = select( module_info, 1);
  599.  
  600.       // Tell modules if we were going backwards.
  601.       argterm = add(argterm, former_result == `back);
  602.  
  603.       // Regenerate the text of the buttons in order to make language change active
  604.       UI(`ChangeWidget(`id(`back), `Label, _("&Back")));
  605.       UI(`ChangeWidget(`id(`next), `Label, _("&Next")));
  606.  
  607.       SetWizardStage(stage, false);
  608.       symbol|void result = CallFunction(argterm);
  609.  
  610.       // If the module return nil, something basic went wrong.
  611.       // We show a stub dialog instead.
  612.  
  613.       if (result == nil) {
  614.           any r = nil;
  615.           r = UI(`ModuleError(("The module " + symbolof(argterm)) + " does not work."));
  616.           if      (r == `next)   m = m + 1;
  617.           else if (r == `back)   m = m - 1;
  618.           else if (r != `again)  return nil;
  619.           else                   continue;
  620.       }
  621.  
  622.       if      (result == `next)        m = m + 1;
  623.       else if (result == `back)        m = m - 1;
  624.       else if (result == `cancel)      return `cancel;
  625.       else if (result == `again)       continue; // Show same dialog again
  626.       else if (result == `auto) 
  627.       {
  628.           if (former_result != nil) {
  629.               if      (former_result == `next) m = m + 1;
  630.               else if (former_result == `back) m = m - 1;
  631.           }
  632.           continue;
  633.       }
  634.       former_result = result;
  635.   }
  636.   UI(`CloseDialog());
  637.   y2log( .milestone, "installation", 1, "all done : "+m);
  638.   if (m <= -1) return `back;
  639.   else return `next;
  640. }
  641.