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 / clients / inst_custom_part.ycp < prev    next >
Text File  |  2006-11-29  |  106KB  |  3,573 lines

  1. /*
  2.  *************************************************************
  3.  *
  4.  *     YaST2      SuSE Labs                        -o)
  5.  *     --------------------                        /\\
  6.  *                                                _\_v
  7.  *           www.suse.de / www.suse.com
  8.  * ----------------------------------------------------------
  9.  *
  10.  * Author:        Michael Hager <mike@suse.de>
  11.  *
  12.  * Description:   Partitioner for experts.
  13.  *
  14.  *
  15.  * Purpose:
  16.  *                      -Determing possible partitions.
  17.  *                      -Ask the user which partition to use.
  18.  *                      -Check the input and return error-messages.
  19.  *                      -Writing user_settings with the selected partitions.
  20.  *
  21.  * user_settings:       used:   targets
  22.  *
  23.  * external function:   get_partition_info: get a list of current partitions
  24.  *                      check4partitions:   read the disk-information
  25.  *
  26.  *
  27.  *************************************************************
  28.  
  29.  $Id: inst_custom_part.ycp 33991 2006-11-02 16:14:26Z fehr $
  30.  
  31. */
  32. {
  33.   textdomain "storage";
  34.  
  35.   import "Arch";
  36.   /* FIXME import "Bootloader";*/
  37.   import "Installation";
  38.   import "Mode";
  39.   import "Wizard";
  40.   import "Storage";
  41.   import "FileSystems";
  42.   import "Partitions";
  43.   import "Package";
  44.  
  45.   import "Label";
  46.   import "Popup";
  47.   import "String";
  48.   import "Storage";
  49.   import "StorageDevices";
  50.   import "ProductFeatures";
  51.  
  52.   list    hitlist = [];
  53.   boolean hiterror = false;
  54.  
  55.   include "partitioning/partition_defines.ycp";
  56.   include "partitioning/loop.ycp";
  57.   include "partitioning/lvm_ui_dialogs.ycp";
  58.   include "partitioning/lvm_pv_lib.ycp";
  59.   include "partitioning/raid_lib.ycp";
  60.   include "partitioning/raid_ui.ycp";
  61.   include "partitioning/custom_part_lib.ycp";
  62.   include "partitioning/custom_part_dialogs.ycp";
  63.   include "partitioning/custom_part_check_generated.ycp";
  64.   include "partitioning/evms_lib.ycp";
  65.  
  66.  
  67.   // Which columns show the main window have
  68.   boolean showT_dev           = true;      // show /dev/hda1
  69.   boolean showT_id           = false;     // s390 show FD01
  70.   boolean showT_cyl           = true;      // show start and endcyl
  71.   boolean showT_size           = true;      // show size of partition
  72.   boolean showT_format           = true;      // show format flag
  73.   boolean showT_fs           = true;      // show filesystem
  74.   boolean showT_mount           = true;      // show mountpoint
  75.   boolean showT_mby               = true;      // show mount by
  76.   boolean showT_Used          = true;      // show using entity
  77.   boolean showT_Label             = true;      // show assigned label
  78.   boolean showT_udev_id          = true;      // show persistent id
  79.   boolean showT_udev_path         = true;      // show persistent path
  80.  
  81.   // hide some details in the table by default
  82.   boolean show_T_details = Storage::GetExpertDetail();
  83.  
  84.   boolean show_disk               = true;
  85.   boolean edit_cylinder           = true;
  86.   boolean bsd_label               = false;
  87.  
  88.  
  89.   boolean button_resize       = true;    // Should the "Resize Partition"-Button be shown in main window
  90.   boolean button_create       = true;    // Should the "Create Partition"-Button be shown in main window
  91.   boolean button_delete       = true;    // Should the "Delete Partition"-Button be shown in main window
  92.   boolean button_edit             = true;    // Should the "Edit   Partition"-Button be shown in main window
  93.   boolean button_reread           = true;    // Should the "Reread Partition"-Button be shown in Expert menu
  94.   boolean button_raid               = true;    // Should the "RAID"  -Button be shown in main window
  95.   boolean button_loop               = true;    // Should the "LOOP"  -Button be shown in main window
  96.   boolean button_lvm              = true;    // Should the "LVM"   -Button be shown in main window
  97.                                              // Should the "EVMS"  -Button be shown in main window
  98.   boolean button_evms             = ProductFeatures::GetBooleanFeature ("partitioning", "evms_config");
  99.   boolean button_expert           = true;    // Should the "EXPERT"-Button be shown in main window
  100.   boolean button_delete_parttable = true;    // Should the "Delete partition table and disk label"
  101.                                              // -Button be shown in Expert menu
  102.   boolean button_adapt_mp      = false;   // Should the "Adapt mount points from
  103.                                              // existing /etc/fstab" -Button be shown in Expert menu
  104.  
  105.    if( button_evms && Mode::normal() && 
  106.        SCR::Read( .target.size, "/usr/share/YaST2/clients/inst_evms.ycp" )<=0 )
  107.        button_evms = false;
  108.    y2milestone( "EVMS:%1", button_evms );
  109.    boolean test_mode          = Mode::test ();
  110.    string  boot_mode          =    "fritz";
  111.    /* FIXME string  boot_mode          =    Bootloader::getLoaderType ();*/
  112.    string  focusline          = "";
  113.  
  114.    string last_sel_disk = "";
  115.  
  116.  
  117.  
  118.  
  119.    ////////////////////////////////////////////////
  120.    // Testmode, should be commented in release
  121.    // test_mode   = true;
  122.    // test_mode   = false;
  123.    // Arch::architecture () = "ppc";
  124.    // Arch::architecture () = "axp";
  125.    ////////////////////////////////////////////////
  126.  
  127.    if( Arch::ppc () )
  128.        {
  129.        showT_cyl     = false;
  130.        bsd_label         = false;
  131.        }
  132.  
  133.    if( Arch::s390 () )
  134.        {
  135.        showT_id = true;
  136.        button_resize = false;
  137.        button_loop = false;
  138.        }
  139.  
  140.    if( Arch::alpha () )
  141.        {
  142.        bsd_label = (boot_mode == "aboot");
  143.        }
  144.  
  145.    if( Arch::sparc () )
  146.        {
  147.        bsd_label = true;
  148.        }
  149.  
  150.    if( Stage::initial () )
  151.        {
  152.        button_adapt_mp = true;
  153.        }
  154.    if( Mode::repair () )
  155.       {
  156.       button_adapt_mp      = false;
  157.       }
  158.  
  159.  
  160.    y2debug( "ARCHIT %1", Arch::architecture () );
  161.  
  162.  
  163.    ////////////////////////////////////////////////////////////////////////
  164.    //                          DEFINES                                   //
  165.    ////////////////////////////////////////////////////////////////////////
  166.  
  167.  
  168.  
  169.     /*---------------------------------------------------------------------
  170.      * Check if the numer is in the format <number>
  171.      *
  172.      * Returns true or false
  173.      *----------------------------------------------------------------------
  174.      */
  175.  
  176. define boolean IsNumber( string input )
  177.     ``{
  178.     integer n = 0;
  179.     while (n < size(input))
  180.     {
  181.         string erg = filterchars(substring(input, n,1), "0123456789.");
  182.  
  183.         if (size(erg) != 1)
  184.         {
  185.         return(false);
  186.         }
  187.         n = n + 1;
  188.         }
  189.     return(true);
  190.     };
  191.  
  192.     /*---------------------------------------------------------------------
  193.      * Check if the number is in the format [+]<number>[kKmMgGtT][bBoO]
  194.      *
  195.      * Returns true or false
  196.      *----------------------------------------------------------------------
  197.      */
  198. define boolean IsCylNumber( string input )
  199.     ``{
  200.     if( substring( input, 0, 1) == "+")
  201.         {
  202.     input = substring( input, 1);
  203.         }
  204.  
  205.     if( !IsNumber(input))
  206.     {
  207.     // check whether the last char is in "gGtTkKmM" or "bBoO"
  208.     string last_char = substring( input, size(input)-1, 1);
  209.  
  210.     if( last_char == "b" || last_char == "B"  ||
  211.         last_char == "o" || last_char == "O" )
  212.         {
  213.         input = substring( input, 0, size(input)-1);
  214.         // check whether the last char is in "gGtTkKmM"
  215.         last_char = substring( input, size(input)-1, 1);
  216.         }
  217.  
  218.         string erg = filterchars(last_char, "kKmMgGtT");
  219.  
  220.         if( size(erg) != 1)
  221.         {
  222.         // the last isn't in "kKmMgGtT"
  223.         return( false );
  224.         }
  225.     else
  226.         {
  227.         // the last is in "kKmMgGtT" check whether the rest is a number
  228.         return( IsNumber( substring(input, 0, size(input)-1)));
  229.         }
  230.     }
  231.     else
  232.     {
  233.     return( true );
  234.     }
  235.     };
  236.  
  237.  
  238.      /*---------------------------------------------------------------------
  239.      * Parse the end_partition String
  240.      * Input:
  241.      *  - start_cylinder,
  242.      *  - end of partition in
  243.      *    valid is [+]<number>[kKmMgGtT][bBoO]
  244.      *    insert a valid string! consistency must be already checked
  245.      * - size of a cylinder in byte
  246.      *
  247.      * Returns (endcylinder -startcylinder +1) as integer
  248.      *----------------------------------------------------------------------
  249.      */
  250.  
  251. define integer ToEndRegion( string start_cyl, string end_part,
  252.                 integer cyl_size )
  253.     ``{
  254.     boolean is_add = false;
  255.     string input = end_part;
  256.  
  257.     if( substring( input, 0, 1) == "+")
  258.     {
  259.     input = substring( input, 1);
  260.     is_add = true;
  261.     }
  262.  
  263.     if ( !IsNumber(input))
  264.     {
  265.     is_add = true;  //  44k is the same as +44k
  266.  
  267.     // take last char
  268.     string last_char = substring( input, size(input)-1, 1);
  269.  
  270.     // accept also +4kb or 7GB
  271.     if( last_char == "b" || last_char == "B" ||
  272.         last_char == "o" || last_char == "O" )
  273.         {
  274.         input     = substring( input, 0, size(input)-1);
  275.         last_char = substring( input, size(input)-1, 1);
  276.         }
  277.  
  278.     //integer base     = tointeger(substring( input, 0, size(input)-1 ));
  279.     float base     = tofloat(substring( input, 0, size(input)-1 ));
  280.  
  281.     if( last_char == "k" || last_char == "K" )
  282.         {
  283.         return( tointeger((base*1024.0)/tofloat(cyl_size) +1.0 ));
  284.         }
  285.     if( last_char == "m" || last_char == "M" )
  286.         {
  287.         return( tointeger((base*1048576.0)/tofloat(cyl_size) +1.0 ));
  288.         }
  289.     if( last_char == "g" || last_char == "G" )
  290.         {
  291.         return( tointeger((base*1073741824.0)/tofloat(cyl_size) +1.0 ));
  292.         }
  293.     if( last_char == "t" || last_char == "T" )
  294.         {
  295.         return( tointeger((base*1099511627776.0)/tofloat(cyl_size) +1.0 ));
  296.         }
  297.  
  298.     y2error("Error in parsing end_cylinder" );
  299.     return( tointeger(base) );
  300.     }
  301.     else
  302.     {
  303.     if (is_add)
  304.         {
  305.         return( tointeger(tofloat(input)) );
  306.         }
  307.     else
  308.         {
  309.         return( tointeger(tofloat(input))-tointeger(start_cyl)+1 );
  310.         }
  311.     }
  312.     };
  313.  
  314.  
  315.     /*---------------------------------------------------------------------
  316.      * tests which Partition types on a disk can be created
  317.      * for Intel-I386!
  318.      *
  319.      * Input: map disk    // (the map out of the targets map)
  320.      *        string dev  // /dev/hda
  321.      *
  322.      *  Return value: [ <primary_poss>, <extended_poss>, <logical_poss> ]
  323.      *  boolean primary_poss;   // Is a primary partition possible
  324.      *  boolean extended_poss;  // Is a extended partition possible
  325.      *  boolean logical_poss;   // Is a logical partition possible
  326.      *----------------------------------------------------------------------
  327.      * DESCRIPTION
  328.      *
  329.      * primary_part_is_possible  = false; // can I create a primary part ?
  330.      * extended_part_is_possible = false; // can I create a extended part ?
  331.      * logial_part_is_possible  = false; // ...
  332.      *
  333.      *
  334.      *   if (one of the partitions <disk>1 <disk>2 <disk>3 <disk>4
  335.      *       is not used )
  336.      *   {
  337.      *      primary_part_is_possible = true;
  338.      *   }
  339.      *
  340.      *   if  primary_part_is_possible && (no extended partition exists)
  341.      *   {
  342.      *     extended_part_is_possible = true;
  343.      *   }
  344.      *
  345.      *   if (extended partition already exists) && (extended partition has
  346.      *                                       space left)
  347.      *      && (not more than 15 logical parts already exist)
  348.      *   {
  349.      *     logial_part_is_possible = true;
  350.      *   }
  351.      *
  352.      *
  353.      *   At the same time is not possible, that both "logial_part_is_possible"
  354.      *   and "extended_part_is_possible" are true
  355.      *   so we have 6 possible situations
  356.      *
  357.      *   to show this we use
  358.      *   "P" for primary_part_is_possible
  359.      *   "E" for extended_part_is_possible
  360.      *   "L" for logial_part_is_possible
  361.      *
  362.      *   "p" for primary_part_is_possible  == false
  363.      *   "e" for extended_part_is_possible == false
  364.      *   "l" for logial_part_is_possible  == false
  365.      *
  366.      *
  367.      *   PE  : I can create a primary or exended part.
  368.      *   PL  : Extended part. exist. I can create a primary or a logical
  369.      *   Pel : only a priary is possible, when the extended part. has no space left
  370.      *
  371.      *   pE  : Not possible, if "E" is possible always "P" is possible too.
  372.      *   pL  : only a logical is possible, if together 4 primary and extended
  373.      *  partitions are already created
  374.      *   pel : no partitions are possible
  375.      *
  376.      *----------------------------------------------------------------------
  377.      */
  378.  
  379. define list CheckCreatePossibilities( string dev, map disk )
  380.     ``{
  381.     string type = substring(dev, 5, 2);
  382.  
  383.     boolean extended_exists      = false;
  384.  
  385.     symbol no_logical_cause     = `no_ext;
  386.     symbol no_primary_cause     = `dev_full;
  387.     symbol no_extended_cause    = `dev_full;
  388.  
  389.     boolean     primary_is_possible  = false;
  390.     boolean     extended_is_possible = false;
  391.     boolean     logical_is_possible  = false;
  392.  
  393.     list<map> primary_list =
  394.     filter( map part, disk["partitions"]:[],
  395.         ``( part["type"]:`unknown == `primary ));
  396.     list<map> extended_list =
  397.     filter( map part, disk["partitions"]:[],
  398.         ``( part["type"]:`unknown == `extended));
  399.     list<map> logical_list =
  400.     filter( map part, disk["partitions"]:[],
  401.         ``( part["type"]:`unknown == `logical));
  402.  
  403.     if( (size(extended_list) + size(primary_list)) < disk["max_primary"]:4 )
  404.     {
  405.     primary_is_possible = true;
  406.     }
  407.  
  408.     if( primary_is_possible && (size(extended_list) == 0) &&
  409.         Partitions::HasExtended( disk["label"]:"") )
  410.     {
  411.     extended_is_possible = true;
  412.     }
  413.  
  414.     if( size(extended_list) > 0 )
  415.     {
  416.     no_extended_cause = `already;
  417.     extended_exists = true;
  418.     }
  419.  
  420.     if( disk["max_primary"]:4 > 4 )
  421.     {
  422.     logical_is_possible = false;
  423.     extended_is_possible = false;
  424.     no_logical_cause = `impossible;
  425.     no_extended_cause = `impossible;
  426.     }
  427.  
  428.     if( extended_exists )
  429.     {
  430.     no_logical_cause = `no_extsp;
  431.  
  432.     // test if extended partition has space left == a slot exists
  433.     boolean slot_exist = false;
  434.  
  435.     // Start-End of the extended partition
  436.  
  437.     integer start_ext_cyl = extended_list[0,"region",0]:0;
  438.     integer end_ext_cyl   = extended_list[0,"region",1]:1 + start_ext_cyl-1;
  439.  
  440.  
  441.     // logical_cyl_list = [ <start_cyl.firstLogPart> , <end_cyl.firstLogPart> , <start.nextLogPart> ,....., <end.lastLogPart>]
  442.     //
  443.     // example:  input: hda5:region [255,100] hda6:region[355,100] hda7[455,100]
  444.     //           is al list generatated: logical_cyl_list = [255,354,355,454,455,555]
  445.     //
  446.     list logical_cyl_list =
  447.         sort(flatten(maplist( map part, logical_list,
  448.                   ``([part["region",0]:0,
  449.                       part["region",0]:0 + part["region",1]:1-1 ]))));
  450.  
  451.     // Look for a slot in the list of cylinders
  452.     integer  n          = 0;
  453.  
  454.     if (size(logical_cyl_list) == 0 )
  455.         {
  456.         // no logical partitions exist
  457.         slot_exist = true;
  458.         }
  459.     else
  460.         {
  461.         repeat
  462.         {
  463.         if( n == 0 )
  464.             {
  465.             // first
  466.             if( logical_cyl_list[0]:0 != start_ext_cyl )
  467.             slot_exist = true;
  468.             }
  469.         else if( n == (size(logical_cyl_list)/2))
  470.             {
  471.             // last
  472.             if( logical_cyl_list[size(logical_cyl_list)-1]:0 !=
  473.                 end_ext_cyl )
  474.             slot_exist = true;
  475.             }
  476.         else
  477.             {
  478.             //check if between logical partition n-1 and n is a slot
  479.             if( (logical_cyl_list[2*n-1]:0 + 1) != (logical_cyl_list[2*n]:0 ))
  480.             slot_exist = true;
  481.             }
  482.  
  483.         n = n+1;
  484.         } until ( n == ( (size(logical_cyl_list)/2 +1)) || slot_exist );
  485.         }
  486.  
  487.     if( slot_exist)
  488.         {
  489.         no_logical_cause     = `to_many;
  490.  
  491.         y2debug( "Logical: %1 %2", type, logical_cyl_list);
  492.  
  493.         if( type == "hd" )      // EIDE supports 63 partitions
  494.         {
  495.         if (size(logical_cyl_list)/2 < 59 ) logical_is_possible = true;
  496.         }
  497.         if( type == "sd" )     // SCSI supports 15 partitions
  498.         {
  499.         if (size(logical_cyl_list)/2 < 11 ) logical_is_possible = true;
  500.         }
  501.         else
  502.         {
  503.         logical_is_possible = true;
  504.         }
  505.         }
  506.     }
  507.  
  508.     return( [primary_is_possible, extended_is_possible, logical_is_possible,
  509.          no_primary_cause, no_extended_cause, no_logical_cause ]);
  510.     };
  511.  
  512.  
  513.     /*---------------------------------------------------------------------
  514.      * Find bigest slot
  515.      * return [start, end] or nil
  516.      *---------------------------------------------------------------------
  517.      */
  518.  
  519. define list GetSlot( string dev, map disk )
  520.     ``{
  521.     string type = substring(dev, 5, 2);
  522.     list<map> global_list = filter( map part, disk["partitions"]:[],
  523.                     ``( part["type"]:`unknown != `logical ));
  524.  
  525.     if( bsd_label )
  526.     {
  527.     global_list  = filter( map part, global_list, ``( part["nr"]:0 != 3 ));
  528.     }
  529.  
  530.  
  531.     list global_cyl_list =
  532.     sort(flatten(maplist( map part, global_list,
  533.                   ``([part["region",0]:0,
  534.                   part["region",0]:0 + part["region",1]:1-1 ]))));
  535.  
  536.     // Look for a slot in the list of cylinders
  537.     integer  n          = 0;
  538.     integer start_cyl   = 0;
  539.     integer end_cyl     = disk["cyl_count"]:1 - 1;
  540.  
  541.     integer sl_start   = 0;
  542.     integer sl_end     = 0;
  543.     integer curr_start = 0;
  544.     integer curr_end   = 0;
  545.  
  546.     boolean slot_exist = false;
  547.  
  548.     y2milestone( "global_cyl_list %1", global_cyl_list );
  549.  
  550.     if( size(global_cyl_list) == 0 )
  551.     {
  552.     // no partition exist
  553.     return( [start_cyl, end_cyl]);
  554.     }
  555.     else
  556.     {
  557.     repeat
  558.         {
  559.         if( n == 0 )
  560.         {
  561.         // first
  562.         curr_start  =  start_cyl-1;
  563.         curr_end    =  global_cyl_list[0]:0;
  564.         }
  565.         else if ( n == (size(global_cyl_list)/2))
  566.         {
  567.         // last
  568.         curr_start = global_cyl_list[size(global_cyl_list)-1]:0;
  569.         curr_end   = end_cyl+1;
  570.         }
  571.         else
  572.         {
  573.         //check if between global partition n-1 and n is a slot
  574.         curr_start = global_cyl_list[2*n-1]:0;
  575.         curr_end   = global_cyl_list[2*n]:0;
  576.         }
  577.  
  578.         y2milestone( "n curr_start %1 curr_end %2", curr_start, curr_end );
  579.         if( curr_start+1 < curr_end )
  580.         {
  581.         slot_exist = true;
  582.  
  583.         y2debug( "A Slot at: %1 %2",  curr_start, curr_end );
  584.  
  585.         if( (curr_end-curr_start-2) >= (sl_end - sl_start) )
  586.             {
  587.             sl_start = curr_start+1;
  588.             sl_end   = curr_end-1;
  589.             }
  590.         }
  591.         y2debug("SLOT- %1 %2 %3 %4", slot_exist, curr_start, curr_end, n );
  592.  
  593.         n = n+1;
  594.         } until ( n == ( (size(global_cyl_list)/2 +1)));
  595.     }
  596.  
  597.     if( slot_exist)
  598.         {
  599.     return( [sl_start, sl_end] );
  600.         }
  601.     else
  602.     {
  603.     return(nil);
  604.     }
  605.     };
  606.  
  607.     /*---------------------------------------------------------------------
  608.      * test primary and extended slot
  609.      * return [start, end] or nil
  610.      * Input: start_cyl of the tested slot, /dev/hda1,  diskmap
  611.      * return [max-end_cyl] or "nil" if its no valid start_cyl
  612.      * todo: GetSlo TestSlot should be one function
  613.      *---------------------------------------------------------------------
  614.      */
  615.  
  616. define integer TestSlot( integer slot_start_cyl, string dev, map disk,
  617.              boolean bsd_label )
  618.     ``{
  619.     string type = substring(dev, 5, 2);
  620.     list<map> global_list  = filter( map part, disk["partitions"]:[],
  621.                      ``( part["type"]:`unknown != `logical ));
  622.  
  623.     if( bsd_label )
  624.     {
  625.     global_list  = filter( map part, global_list, ``( part["nr"]:0 != 3 ) );
  626.     }
  627.  
  628.     list global_cyl_list =
  629.     sort(flatten(maplist( map part, global_list,
  630.                   ``([part["region",0]:0,
  631.                   part["region",0]:0 + part["region",1]:1-1 ]))));
  632.  
  633.     // Look for a slot in the list of cylinders
  634.     integer  n          = 0;
  635.     integer start_cyl   = 0;
  636.     integer end_cyl     = disk["cyl_count"]:1 - 1;
  637.  
  638.     integer sl_start   = 0;
  639.     integer sl_end     = 0;
  640.     integer curr_start = 0;
  641.     integer curr_end   = 0;
  642.  
  643.     boolean slot_exist = false;
  644.  
  645.  
  646.     if( size(global_cyl_list) == 0 )
  647.     {
  648.     y2debug( "Testing Slot : disk empty");
  649.     if( start_cyl <= slot_start_cyl && slot_start_cyl <= end_cyl )
  650.         return( end_cyl );
  651.     }
  652.     else
  653.     {
  654.     repeat
  655.         {
  656.         if( n == 0 )
  657.         {
  658.         // first
  659.         curr_start  =  start_cyl-1;
  660.         curr_end    =  global_cyl_list[0]:0;
  661.         }
  662.         else if ( n == (size(global_cyl_list)/2))
  663.         {
  664.         // last
  665.         curr_start = global_cyl_list[size(global_cyl_list)-1]:0;
  666.         curr_end   = end_cyl+1;
  667.         }
  668.         else
  669.         {
  670.         //check if between global partition n-1 and n is a slot
  671.         curr_start = global_cyl_list[2*n-1]:0;
  672.         curr_end   = global_cyl_list[2*n]:0;
  673.         }
  674.  
  675.         y2debug( "Testing Slot %1 < x < %2", curr_start, curr_end );
  676.         if( curr_start < slot_start_cyl && slot_start_cyl < curr_end )
  677.         {
  678.         // If the slot was found ...
  679.         y2debug( "X Slot at: %1 %2 ",  curr_start, curr_end );
  680.         //////////////////
  681.         return( curr_end-1 );
  682.         //////////////////
  683.         }
  684.         y2debug("SLOT- %1 %2 %3 %4", slot_exist, curr_start, curr_end, n );
  685.  
  686.         n = n+1;
  687.         } until ( n == ( (size(global_cyl_list)/2 +1)));
  688.     }
  689.     return(nil);
  690.     };
  691.  
  692.  
  693.  
  694.     /*---------------------------------------------------------------------
  695.      * Find bigest slot for logical
  696.      * return [start, end] or nil
  697.     /*---------------------------------------------------------------------
  698.      */
  699.  
  700. define list GetLogicalSlot( string dev, map disk )
  701.     ``{
  702.     string type = substring(dev, 5, 2);
  703.  
  704.     list<map> global_list  = filter( map part, disk["partitions"]:[],
  705.                      ``( part["type"]:`unknown == `logical ));
  706.     map    extended = (map)find( map part, disk["partitions"]:[],
  707.                   ``( part["type"]:`unknown == `extended ));
  708.  
  709.     //////////////////////////////////
  710.     if (extended == nil)
  711.     {
  712.     return(nil);
  713.     }
  714.     //////////////////////////////////
  715.  
  716.     list global_cyl_list =
  717.     sort(flatten(maplist( map part, global_list,
  718.                           ``([part["region",0]:0,
  719.                   part["region",0]:0 + part["region",1]:1-1 ]))));
  720.  
  721.     // Look for a slot in the list of cylinders
  722.     integer  n          = 0;
  723.     integer start_cyl   = tointeger( extended["region",0]:0 );
  724.     integer end_cyl     = start_cyl + tointeger(extended["region",1]:1)-1;
  725.  
  726.     integer sl_start   = 0;
  727.     integer sl_end     = 0;
  728.     integer curr_start = 0;
  729.     integer curr_end   = 0;
  730.  
  731.     boolean slot_exist = false;
  732.  
  733.  
  734.     if (size(global_cyl_list) == 0 )
  735.         {
  736.         // no partition exist
  737.         return( [start_cyl, end_cyl]);
  738.         }
  739.     else
  740.         {
  741.         repeat
  742.         {
  743.         if( n == 0 )
  744.         {
  745.         // first
  746.         curr_start  =  start_cyl-1;
  747.         curr_end    =  global_cyl_list[0]:0;
  748.         }
  749.         else if ( n == (size(global_cyl_list)/2))
  750.         {
  751.         // last
  752.         curr_start = global_cyl_list[size(global_cyl_list)-1]:0;
  753.         curr_end   = end_cyl+1;
  754.         }
  755.         else
  756.         {
  757.         //check if between global partition n-1 and n is a slot
  758.         curr_start = global_cyl_list[2*n-1]:0;
  759.         curr_end   = global_cyl_list[2*n]:0;
  760.         }
  761.  
  762.         if( curr_start+1 < curr_end )
  763.         {
  764.         slot_exist = true;
  765.  
  766.         y2debug( "A Slot at: %1 %2  ",  curr_start, curr_end );
  767.  
  768.         if( (curr_end - curr_start -2) >= (sl_end - sl_start) )
  769.             {
  770.             sl_start = curr_start+1;
  771.             sl_end   = curr_end-1;
  772.             }
  773.         }
  774.         y2debug("SLOT- %1 %2 %3 %4  ", slot_exist, curr_start, curr_end, n );
  775.  
  776.         n = n+1;
  777.         } until ( n == ( (size(global_cyl_list)/2 +1)));
  778.     }
  779.  
  780.     if (slot_exist)
  781.         {
  782.         return( [sl_start, sl_end] );
  783.         }
  784.     else
  785.         {
  786.         return(nil);
  787.         }
  788.     };
  789.  
  790.  
  791.     /*---------------------------------------------------------------------
  792.      * Check slot for logical partition
  793.      * Input: start_cyl of the tested slot, /dev/hda5,  diskmap, in edit_mode or create_mode
  794.      *
  795.      * return [max-end_cyl] or nil if its no valisd start_cyl
  796.      *
  797.      * todo: GetLogicalSlot TestLogicalSlot should be one function
  798.      *---------------------------------------------------------------------
  799.      */
  800.  
  801. define integer TestLogicalSlot( integer slot_start_cyl, string dev, map disk)
  802.     ``{
  803.     string type = substring(dev, 5, 2);
  804.  
  805.     list<map> global_list = filter( map part, disk["partitions"]:[],
  806.                                ``( part["type"]:`unknown == `logical ));
  807.     map extended = (map)find( map part, disk["partitions"]:[],
  808.                               ``( part["type"]:`unknown == `extended ));
  809.  
  810.     list global_cyl_list =
  811.     sort(flatten(maplist( map part, global_list,
  812.                           ``([part["region",0]:0,
  813.                   part["region",0]:0 + part["region",1]:1-1 ]))));
  814.  
  815.     // Look for the slot in the list of cylinders
  816.     integer  n          = 0;
  817.     integer start_cyl   = tointeger( extended["region",0]:0 );
  818.     integer end_cyl     = start_cyl + tointeger( extended["region",1]:1-1 );
  819.  
  820.     integer sl_start   = 0;
  821.     integer sl_end     = 0;
  822.     integer curr_start = 0;
  823.     integer curr_end   = 0;
  824.  
  825.     boolean slot_exist = false;
  826.  
  827.  
  828.     if (size(global_cyl_list) == 0 )
  829.         {
  830.         if( start_cyl <= slot_start_cyl  && slot_start_cyl <= end_cyl )
  831.       return( end_cyl );
  832.         }
  833.     else
  834.         {
  835.         repeat
  836.         {
  837.         if( n == 0 )
  838.         {
  839.         // first
  840.         curr_start  =  start_cyl-1;
  841.         curr_end    =  global_cyl_list[0]:0;
  842.         }
  843.         else if ( n == (size(global_cyl_list)/2))
  844.         {
  845.         // last
  846.         curr_start = global_cyl_list[size(global_cyl_list)-1]:0;
  847.         curr_end   = end_cyl+1;
  848.         }
  849.         else
  850.         {
  851.         //check if between global partition n-1 and n is a slot
  852.         curr_start = global_cyl_list[2*n-1]:0;
  853.         curr_end   = global_cyl_list[2*n]:0;
  854.         }
  855.  
  856.         y2debug( "Testing Slot %1  < x < %2  ", curr_start, curr_end );
  857.  
  858.         if( curr_start < slot_start_cyl && slot_start_cyl < curr_end )
  859.         {
  860.         // If the slot was found ...
  861.         y2debug( "X Slot at:  %1 %2 ",  curr_start, curr_end );
  862.         //////////////////
  863.         return( curr_end -1);
  864.         //////////////////
  865.         }
  866.         y2debug("SLOT- %1 %2 %3 %4", slot_exist, curr_start, curr_end, n );
  867.  
  868.         n = n+1;
  869.         } until ( n == ( (size(global_cyl_list)/2 +1)));
  870.         }
  871.     return(nil);
  872.     };
  873.  
  874.  
  875.     /*---------------------------------------------------------------------
  876.      * returns for nonnegative numbers a string with a minimum of 4 characters:
  877.      * 1      -> "   1"
  878.      * 22     -> "  22"
  879.      * 145    -> " 145"
  880.      * 2134   -> "2134"
  881.      * 34111 -> "34111"
  882.      *----------------------------------------------------------------------
  883.      */
  884. define string to4string( integer nb )
  885.     ``{
  886.     if ( nb < 10 )   return( sformat( "   %1", nb ));
  887.     if ( nb < 100 )  return( sformat( "  %1",  nb ));
  888.     if ( nb < 1000 ) return( sformat( " %1",   nb ));
  889.     return( sformat( "%1", nb ));
  890.     };
  891.  
  892. define string usedByString( symbol ub_type, string used_by )
  893.     {
  894.     string ret = "";
  895.     if( ub_type == `UB_LVM )
  896.     ret = "LVM " + used_by;
  897.     else if( ub_type == `UB_EVMS )
  898.     ret = "EVMS " + used_by;
  899.     else if( ub_type == `UB_DM )
  900.     ret = "DM " + used_by;
  901.     else if( ub_type == `UB_DMRAID )
  902.     ret = "RAID " + used_by;
  903.     else if( ub_type != `UN_NONE )
  904.     ret = used_by;
  905.     return( ret );
  906.     }
  907.  
  908.     /*---------------------------------------------------------------------
  909.      * Fill the selection box with ID 'selbox_id' inside widget tree
  910.      * 'widget' with disk and partition info from 'all_disks'.
  911.      *
  912.      *  Return value:
  913.      * term contents = `VBox(`Label("Partitions"),
  914.      *                        `Table(`header("Device", "Start", "End", "Size", "F", "Type", "Mount", "RAID" , "LVM" ),
  915.      *                               [
  916.      *                                `item(`id("/dev/hda"),    "/dev/hda",      "8.5 GB",   " ", "Seagate ST 48012", " ",      "1",  "1115"    ,"",    ""),
  917.      *                                `item(`id("1//dev/hda"), "  /dev/hda1",   "509.8 MB", " ", "FAT16",            " ",      "1",  "65"    ,"",    ""),
  918.      *                                `item(`id("2//dev/hda"), "  /dev/hda2",   "666.7 MB", " ", "NTFS",             " ",      "66", "150"    ,"",    ""),
  919.      *                                `item(`id("3//dev/hda"), "  /dev/hda3",   "5.5 GB",   " ", "Extended",         " ",      "301","1024"    ,"",    ""),
  920.      *                                `item(`id("4//dev/hda"), "  /dev/hda5",   "7.8 MB",   "F", "Linux ",           "/boot",      "301","302"    ,"",    ""),
  921.      *                       `item(`id("5//dev/hda"), "  /dev/hda6",   "7.8 MB",   "", "Linux LVM ",         "",         "303","304"    ,"",    "system"),
  922.      *                      `item(`id("6//dev/hda"), "  /dev/hda7",   "7.8 MB",   "", "Linux RAID ",        "",         "305","307"    ,"/dev/md1",    ""),
  923.      *                               ] )) ;
  924.      *
  925.      *  PPC: without Start End
  926.      *
  927.      *----------------------------------------------------------------------
  928.      */
  929.  
  930. define list FillPartitionList(map<string,map> targets)
  931.     ``{
  932.      list<term> table_input     = [];
  933.      boolean log_mode = false;
  934.  
  935.     // order should be md, then loop, then LVM, then EVMS
  936.     map disk_order = $[ `CT_DMRAID : 0, `CT_DISK : 1, `CT_MD : 2, `CT_LOOP : 3,
  937.                         `CT_LVM : 4, `CT_EVMS : 5, `CT_DM : 6 ];
  938.     list<string> keys = maplist( string dev, map disk, targets,
  939.                  ``{return(dev);} );
  940.     keys = sort( string a, string b, keys,
  941.     ``{
  942.     integer oa = disk_order[targets[a,"type"]:`CT_UNKNOWN]:6;
  943.     integer ob = disk_order[targets[b,"type"]:`CT_UNKNOWN]:6;
  944.     return( (oa==ob) ? (a<b) : (oa<ob) );
  945.     });
  946.  
  947.     SCR::Write(.target.ycp,Storage::SaveDumpPath("targetMap_c"), targets );
  948.     foreach( string dev, keys,
  949.     ``{
  950.     map disk = targets[dev]:$[];
  951.     boolean real_disk = Storage::IsPartitionable( disk );
  952.     integer cyl_count     = disk["cyl_count"]:0;
  953.     integer cyl_size      = disk["cyl_size"]:1000000;
  954.     string  vendor        = disk["vendor"]:"";
  955.     string  model         = disk["model"]:"";
  956.     string  dev_size      = ByteToHumanString(disk["size_k"]:0*1024);
  957.     string  dev_start_cyl = to4string(0);
  958.     string  dev_nb_cyl    = to4string(cyl_count==0?cyl_count:(cyl_count-1));
  959.     string  udev_id       = mergestring( disk["udev_id"]:[], " ");
  960.     string  udev_path     = disk["udev_path"]:"";
  961.  
  962.     if ( (model != "") && (vendor != "") )
  963.         vendor = vendor + "-" + model;
  964.     else
  965.         vendor = vendor +       model;
  966.  
  967.     // entry in column "Type" for a unknown disk
  968.     if( vendor == "" )
  969.         {
  970.         if (disk["bus"]:"" == "RAID")
  971.         {
  972.         vendor = "RAID "+dev;
  973.         }
  974.         else if( disk["type"]:`CT_UNKNOWN==`CT_LVM )
  975.         {
  976.         vendor = "LVM" + (disk["lvm2"]:false ? "2 " : " ") +
  977.              disk["name"]:"";
  978.         }
  979.         else if( disk["type"]:`CT_UNKNOWN==`CT_EVMS )
  980.         {
  981.         vendor = "EVMS " + disk["name"]:"";
  982.         }
  983.         else if( disk["type"]:`CT_UNKNOWN==`CT_DMRAID )
  984.         {
  985.         vendor = "BIOS RAID " + disk["name"]:"";
  986.         }
  987.         else
  988.         // label text
  989.         vendor = sformat( _("DISK %1"), substring( dev, 5 ));
  990.         }
  991.  
  992.     boolean id_sw_raid_dev = (dev == "/dev/md");
  993.  
  994.     /////////////////////////////////////////////////////////////
  995.     // Insert line for the entire disk into selection box widget
  996.     // Look, if for the architecture disk, and Cylinder are shown
  997.  
  998.     if( !real_disk )
  999.         {
  1000.         dev_nb_cyl    = " -- ";
  1001.         dev_start_cyl = " -- ";
  1002.         }
  1003.  
  1004.     if( show_disk && 
  1005.         !(disk["type"]:`CT_UNKNOWN==`CT_DISK && !real_disk) &&
  1006.         (disk["type"]:`CT_UNKNOWN==`CT_DISK ||
  1007.          disk["type"]:`CT_UNKNOWN==`CT_DMRAID ||
  1008.          disk["type"]:`CT_UNKNOWN==`CT_LVM ||
  1009.          (disk["type"]:`CT_UNKNOWN==`CT_EVMS && size(disk["name"]:"")>0 &&
  1010.           (!haskey( targets, "/dev/"+substring( disk["name"]:"", search( disk["name"]:"", "/")+1 ))||
  1011.            disk["create"]:false))))
  1012.         {
  1013.         y2milestone( "disk:%1", disk );
  1014.         term a = `item(`id(dev));
  1015.  
  1016.         if( showT_dev )    a = add(a, dev );
  1017.         if( showT_id )     a = add(a, sformat( " (%1)",
  1018.                            disk["bios_id"]:"" ) );
  1019.         if( showT_size )   a = add(a, dev_size );
  1020.         if( showT_format ) a = add(a, (disk["dasdfmt"]:false)?"X":" " );
  1021.         if( showT_fs )     a = add(a, vendor);
  1022.         if( showT_mount )  a = add(a, "" );
  1023.         if( show_T_details && showT_mby ) a = add(a, "");
  1024.         if( show_T_details && showT_cyl ) a = add(a, dev_start_cyl );
  1025.         if( show_T_details && showT_cyl ) a = add(a, dev_nb_cyl );
  1026.         if( showT_Used )   a = add(a, usedByString( disk["used_by_type"]:`UB_NONE,
  1027.                             disk["used_by"]:"" ));
  1028.         if( showT_Label )  a = add(a, "");
  1029.         if( show_T_details && showT_udev_id )   a = add(a, udev_id);
  1030.         if( show_T_details && showT_udev_path ) a = add(a, udev_path);
  1031.  
  1032.         table_input = add( table_input, a );
  1033.         }
  1034.  
  1035.     /////////////////////////////////////////////////////////////
  1036.     // Now we come to the partitions ...
  1037.  
  1038.     list<map> partitions = disk["partitions"]:[];
  1039.  
  1040.     foreach( map partition, partitions,
  1041.         ``{
  1042.         // dont show "system partitions"
  1043.         string fstype = partition["fstype"]:"";
  1044.         boolean hide = partition["fsid"]:0 == Partitions::fsid_mac_hidden ||
  1045.                        disk["used_by_type"]:`UB_NONE==`UB_DMRAID;
  1046.         if( !hide && search( partition["device"]:"", "/dev/evms/" )==0 )
  1047.         {
  1048.         y2milestone( "evms p: %1", partition );
  1049.         string d1 = evms_dev_disk( partition["device"]:"" );
  1050.         y2milestone( "evms d1:%1", d1 );
  1051.         integer val = search( d1, "/lvm/" );
  1052.         if( val!=nil && val>0 )
  1053.             {
  1054.             d1 = "/dev/" + substring( d1, 9 );
  1055.             }
  1056.         else
  1057.             {
  1058.             val = search( d1, "/lvm2/" );
  1059.             if( val!=nil && val>0 )
  1060.             {
  1061.             d1 = "/dev/" + substring( d1, 10 );
  1062.             }
  1063.             }
  1064.         hide = size(partition["mount"]:"")==0;
  1065.         if( hide )
  1066.             {
  1067.             y2milestone( "evms p: %1", Storage::GetPartition( targets, d1 ));
  1068.             hide = (size(Storage::GetPartition( targets, d1 ))>0||
  1069.                     Storage::IsPartType(targets[d1,"type"]:`CT_UNKNOWN)) &&
  1070.                !partition["evms_native"]:false;
  1071.             }
  1072.         y2milestone( "evms d1:%1 hide:%2", d1, hide );
  1073.         }
  1074.         if( !hide || log_mode )
  1075.         {
  1076.         string   part_id         = "";
  1077.  
  1078.         string part_dev_name = partition["device"]:"";
  1079.         string id = part_dev_name;
  1080.  
  1081.         ////////////////////////////////////////////////////////////
  1082.         // Format other Colums:
  1083.  
  1084.         integer  start_cyl       = partition["region",0]:0;
  1085.         integer  nb_cyl          = partition["region",1]:0;
  1086.         symbol   type            = partition["type"]:`unknown;
  1087.         boolean  format          = partition["format"]:false;
  1088.         boolean  crypt_fs        = partition["enc_type"]:`none != `none;
  1089.         symbol   used_fs         = partition["used_fs"]:`unknown;
  1090.         string   mount_point     = partition["mount"]:"";
  1091.         symbol   mount_by        = partition["mountby"]:`device;
  1092.         string   filesystem_name = "";
  1093.         string   label           = partition["label"]:"";
  1094.         string   udev_id         = mergestring( partition["udev_id"]:[], " ");
  1095.         string   udev_path       = partition["udev_path"]:"";
  1096.  
  1097.         string used_by = 
  1098.             usedByString( partition["used_by_type"]:`UB_NONE,
  1099.                   partition["used_by"]:"" );
  1100.  
  1101.         filesystem_name = partition["fstype"]:"";
  1102.  
  1103.         if( format && partition["fsid"]:0 == Partitions::fsid_native)
  1104.             {
  1105.             string fs_name =  FileSystems::GetName( used_fs, "Ext2" );
  1106.             filesystem_name = filesystem_name + " (" + fs_name + ") ";
  1107.             }
  1108.  
  1109.         string format_flag      = "";
  1110.         if ( format ) format_flag = "F";
  1111.         if ( crypt_fs ) format_flag = "C" + format_flag;
  1112.  
  1113.         string bytes_of_part =
  1114.             ByteToHumanString( partition["size_k"]:0*1024 );
  1115.  
  1116.         /////////////////////////////////////////////////////
  1117.         // Insert line for this partition into selection box widget
  1118.         //
  1119.         // Start- and EndCly are shown (intel) or not (ppc) ...
  1120.  
  1121.         term a = `item(`id(id));
  1122.  
  1123.         if( showT_dev )    a = add(a, part_dev_name );
  1124.         if( showT_id )     a = add(a, part_id );
  1125.         if( showT_size )   a = add(a, bytes_of_part);
  1126.         if( showT_format ) a = add(a, format_flag);
  1127.         if( showT_fs )     a = add(a, filesystem_name);
  1128.         if( showT_mount )
  1129.             {
  1130.             string tmp = mount_point;
  1131.             if( Mode::normal() && partition["inactive"]:false )
  1132.             {
  1133.             tmp = tmp + " *";
  1134.             }
  1135.             a = add(a, tmp );
  1136.             }
  1137.         if( show_T_details && showT_mby )
  1138.             {
  1139.             if (size (mount_point) > 0)
  1140.             {
  1141.             map tmp = $[ `device : "K", `uuid : "U", `label : "L",
  1142.                      `id : "I", `path : "P" ];
  1143.             a = add(a, tmp[mount_by]:"");
  1144.             }
  1145.             else
  1146.             a = add(a, "");
  1147.             }
  1148.         if( show_T_details && showT_cyl )
  1149.             {
  1150.             if( real_disk )
  1151.             {
  1152.             a = add(a, to4string(start_cyl));
  1153.             integer num = start_cyl + nb_cyl - 1;
  1154.             if( num<0 )
  1155.                 num=0;
  1156.             a = add(a, to4string(num));
  1157.             }
  1158.             else
  1159.             {
  1160.             a = add(a, " -- ");
  1161.             a = add(a, " -- ");
  1162.             }
  1163.             }
  1164.         if( showT_Used )   a = add(a, used_by);
  1165.         if( showT_Label )  a = add(a, label);
  1166.         
  1167.         if( show_T_details && showT_udev_id ) a = add(a, udev_id);
  1168.         if( show_T_details && showT_udev_path ) a = add(a, udev_path);
  1169.  
  1170.         table_input = add( table_input, a );
  1171.         }
  1172.         else
  1173.            {
  1174.            // as deleted marked
  1175.            // y2debug( "ddddddddddddd----");
  1176.            }
  1177.         });
  1178.     });
  1179.  
  1180.     return( table_input );
  1181.     };
  1182.  
  1183. /*-------------------------------------------------------------------
  1184.  *
  1185.  *    Now check start an end cylinder
  1186.  *    caution: there is no differenc in edit and create cause the partition, which is to edited,
  1187.  *    is not in the disk map!
  1188.  *
  1189.  *    Check:
  1190.  *    A. Is start_cyl ist a number?  no-> try again
  1191.  *    B. is start_cyl valid ( can the partition start there?) no -> try again
  1192.  *          (when this is tested, the maximal possible end cylinder is computed, too)
  1193.  *    C.    Now we check the syntax of the endCylinder
  1194.  *    D.    If the syntax is valid, the requested end cylinder is checked
  1195.  *    E.  If it is not valid, the user gets a popup and the maximal possible end cylinder is set
  1196.  *
  1197.  *    returns  [<symbol>, <value>]
  1198.  *
  1199.  *             [`ok,  <effektive end cyl>]
  1200.  *             [`max, <max-value as str> ]   // case E
  1201.  *             [`error, 0]
  1202.  *-------------------------------------------------------------------
  1203.  */
  1204.  
  1205. define list TestStartEndCyl( string str_start_cyl, string str_end_part,
  1206.                  string dev, map disk, symbol type,
  1207.                  integer cyl_size, boolean bsd_label )
  1208.     ``{
  1209.     integer    max_end_cyl   = 0;
  1210.     string    max_end_str   = "";
  1211.     symbol    input         = `ok;
  1212.     integer   int_start_cyl = tointeger(str_start_cyl);
  1213.     integer   int_end_cyl   = 0;
  1214.     y2milestone( "TestStartEndCyl start_cyl:%1 end_cyl:%2", str_start_cyl,
  1215.                  str_end_part );
  1216.  
  1217.     ////////////////////////////////// STEP A /////////////////////
  1218.     if (!IsNumber( str_start_cyl ))
  1219.     {
  1220.     input = `error;
  1221.     // error popup text
  1222.     Popup::Error(_("Invalid input for the start of the partition.
  1223. Enter the start cylinder, for example, 77.
  1224. "));
  1225.     }
  1226.     else
  1227.     {
  1228.     ////////////////////////////// STEP B /////////////////////
  1229.  
  1230.     integer      int_start_cyl = tointeger(str_start_cyl);
  1231.  
  1232.     if ( type == `logical )
  1233.         max_end_cyl = TestLogicalSlot( int_start_cyl, dev, disk );
  1234.     else
  1235.         max_end_cyl = TestSlot( int_start_cyl, dev, disk, bsd_label );  // primary && extended
  1236.     if (max_end_cyl == nil)
  1237.         {
  1238.         // error popup text
  1239.         Popup::Error(_("The value entered is invalid. Try again."));
  1240.         input = `error;
  1241.         }
  1242.  
  1243.     if ( input == `ok )
  1244.         {
  1245.         ////////////////////////// STEP C /////////////////////
  1246.         if (!IsCylNumber(str_end_part))
  1247.         {
  1248.         input = `error;
  1249.         // error popup text
  1250.         Popup::Error(_("The value for the partition end is invalid.
  1251.  
  1252. Enter the end cylinder number (such as 77), an offset (like +122),
  1253. or the size of the partition (for example, +100M or 1.8GB )
  1254. "));
  1255.         }
  1256.         else
  1257.         {
  1258.         ////////////////////// STEP D /////////////////////
  1259.  
  1260.         int_end_cyl = int_start_cyl +
  1261.                   ToEndRegion( str_start_cyl, str_end_part,
  1262.                        cyl_size ) - 1;
  1263.  
  1264.         if( int_end_cyl > max_end_cyl || int_end_cyl < int_start_cyl)
  1265.             {
  1266.             ////////////////// STEP E /////////////////////
  1267.  
  1268.             // error popup text, %1, %2, %3 is replaced by numeric value
  1269.             string text = sformat( _("
  1270. The value of the end cylinder %1 was not valid.
  1271. The value must be between %2 and %3.
  1272.  
  1273. Use the maximum allowed value
  1274. or select No and enter a correct value yourself.
  1275.  
  1276. Use the maximum allowed value?
  1277. "),
  1278.                                           int_end_cyl, int_start_cyl,
  1279.                       max_end_cyl );
  1280.             boolean ans = Popup::YesNo( text );
  1281.  
  1282.             if( ans )
  1283.                 {
  1284.             max_end_str = sformat("%1", max_end_cyl);
  1285.             input = `max;
  1286.             }
  1287.             else
  1288.                 {
  1289.             input = `error;
  1290.             }
  1291.             }
  1292.         }
  1293.         }
  1294.     }
  1295.     // END Check
  1296.  
  1297.     if ( input == `ok )  return( [`ok,  int_end_cyl ]);
  1298.     if ( input == `max ) return( [`max, max_end_str ]);
  1299.  
  1300.     // if  ( input == `error )
  1301.     return( [`error, 0]);
  1302.     };
  1303.  
  1304.  
  1305.  
  1306. /*---------------------------------------------------------------------
  1307.  * Checks if the mountpoint is valid
  1308.  * - /proc /mnt /lost+found contain Installation::sourcedir are not allowd
  1309.  * - double entries are not allowed ( mountpoints with no / and "" are always allowed )
  1310.  *
  1311.  *----------------------------------------------------------------------
  1312.  
  1313. /**
  1314.  * Dialog: "Create a partition Dialog"
  1315.  * @parm new_val map that contains a partition
  1316.  * @parm file_systems filesystem definitions
  1317.  * @parm tilte    title string
  1318.  * @parm dev device string for the new/edit partition
  1319.  * @parm disk a map with the disk data  CAUTION: in Edit-Mode, the edited partition, must not be in this map!!
  1320.  * @parm bsd_label
  1321.  * @parm edit_size flag
  1322.  * @parm cyl_size
  1323.  * @return map modified partition or nil by cancel
  1324.  */
  1325.  
  1326. define map<string,any> EditOrCreatePartDlg( map<string,any> cur_val,
  1327.                                             map<symbol,map> file_systems,
  1328.                         string title, map disk,
  1329.                         boolean bsd_label,
  1330.                         boolean edit_size,
  1331.                         integer cyl_size,
  1332.                         boolean installation )
  1333.  
  1334.     ``{
  1335.     boolean create = cur_val["create"]:false;
  1336.     string dev = cur_val["device"]:"";
  1337.     boolean is_disk = cur_val["type"]:`primary == `primary ||
  1338.                       cur_val["type"]:`primary == `logical;
  1339.     y2milestone( "EditOrCreatePartDlg cur_val:%1", cur_val );
  1340.     y2milestone( "EditOrCreatePartDlg is_disk:%1", is_disk );
  1341.  
  1342.     string helptextCR = getEditOrCreateHelptext( cur_val, !create );
  1343.  
  1344.     //////////////////////////////////////////////////////////////////////
  1345.     // Now create "main" dialog with all elements needed
  1346.     //////////////////////////////////////////////////////////////////////
  1347.  
  1348.     //////////////////////////////////////////////////////////////////////
  1349.     // right side of the main dialog
  1350.     term field_dlg_right =
  1351.     `VBox(
  1352.          `Top( SizeDlg( cur_val, cyl_size, edit_size, is_disk )),
  1353.          `VSpacing(1),
  1354.          `ReplacePoint( `id(`mount_dlg_rp), MountDlg( cur_val, [] ))
  1355.          );
  1356.  
  1357.  
  1358.  
  1359.     ////////////////////////////////////////////////////////////////////
  1360.     // left side of the main dialog
  1361.     term field_dlg_left =
  1362.     `Top( `ReplacePoint( `id( `format_dlg_rp),
  1363.                  FormatDlg( cur_val, file_systems) ));
  1364.  
  1365.     ////////////////////////////////////////////////////////////////////
  1366.     // Open main dialog for editing and creation of partitions
  1367.     ////////////////////////////////////////////////////////////////////
  1368.     UI::OpenDialog( `opt(`decorated  ),
  1369.             `HBox(
  1370.             `HWeight(30, `RichText( helptextCR )),
  1371.             `HStretch(),
  1372.             `HSpacing(1),
  1373.             `HWeight(70,`VBox(
  1374.                        `Heading( title),
  1375.                        `VSpacing(1),
  1376.                        `VStretch(),
  1377.                        `HBox(
  1378.                          field_dlg_left,
  1379.                          `HSpacing(2),
  1380.                          field_dlg_right
  1381.                          ),
  1382.                        `VSpacing(1),
  1383.                        `VStretch(),
  1384.                        `HBox(
  1385.                          `PushButton(`id(`ok), `opt(`default),  Label::OKButton() ),
  1386.                          `PushButton(`id(`cancel),  Label::CancelButton() )
  1387.                          )
  1388.                        )
  1389.                 ),
  1390.             `HSpacing(1),
  1391.             `HStretch()
  1392.             )
  1393.         );
  1394.  
  1395.     map<string,any> retval = cur_val;
  1396.     symbol ret = `ok;
  1397.  
  1398.     retval = HandlePartWidgetChanges( true, ret, file_systems, cur_val,
  1399.                       retval );
  1400.  
  1401.     repeat
  1402.        {
  1403.        ////////////////////////////////////////////////////////////
  1404.        // Check the User input
  1405.        ret = (symbol)UI::UserInput();
  1406.        y2milestone( "EditOrCreatePartDlg UserInput ret:%1", ret );
  1407.  
  1408.        if ( ret != `cancel )
  1409.       {
  1410.       retval = HandlePartWidgetChanges( false, ret, file_systems, cur_val,
  1411.                         retval );
  1412.       }
  1413.  
  1414.        ////////////////////////////////////////////////////////////
  1415.        // if the user has pushed the button ok
  1416.        if ( ret == `ok )
  1417.       {
  1418.       /////////////////////////////////////////////////////////
  1419.       // save mountpoint
  1420.      retval["mount"] = String::CutBlanks( (string)UI::QueryWidget(`id(`mount_point),
  1421.                                       `Value));
  1422.  
  1423.       /////////////////////////////////////////////////////////
  1424.       // add fstype to retval
  1425.  
  1426.       integer fs_id = retval["fsid"]:0;
  1427.  
  1428.       if( fs_id<256 )
  1429.           {
  1430.           retval["fstype"] = "";
  1431.           foreach( symbol file_system_name, map file_system_map, file_systems, ``{
  1432.            if( file_system_map[`fsid]:Partitions::fsid_native ==
  1433.                fs_id )
  1434.                retval["fstype"] = file_system_map[`fstype]:"";
  1435.            });
  1436.  
  1437.            if( retval["fstype"]:"" == "")
  1438.            retval["fstype"] = Partitions::FsIdToString( fs_id );
  1439.            }
  1440.  
  1441.        if( create && edit_size )
  1442.            {
  1443.            ////////////////////////////////////////////////////
  1444.            // Get start and end cyl and check if the user input
  1445.            // for start und end cyl are valid
  1446.            list re = [];
  1447.            string start_cyl = (string)UI::QueryWidget(`id(`start_cyl), `Value);
  1448.            string end_part  = (string)UI::QueryWidget(`id(`end_part), `Value);
  1449.  
  1450.            re = TestStartEndCyl( start_cyl, end_part, dev, disk,
  1451.                      retval["type"]:`primary, cyl_size,
  1452.                      bsd_label );
  1453.  
  1454.            if( re[0]:`error == `error )
  1455.            {
  1456.            UI::SetFocus(`id(`end_part));
  1457.            ret = `again;
  1458.            continue;
  1459.            }
  1460.            if( re[0]:`error == `max )
  1461.            {
  1462.            end_part =  re[1]:"";
  1463.            }
  1464.  
  1465.            ////////////////////////////////////////////////////
  1466.            // add start_cyl and end_part to region and add region
  1467.            // to retval
  1468.            list region = [ tointeger( start_cyl ),
  1469.                    ToEndRegion( start_cyl, end_part, cyl_size )];
  1470.  
  1471.            retval["region"] = region;
  1472.            }
  1473.  
  1474.       integer check_size = retval["size_k"]:0 * 1024;
  1475.       if( is_disk )
  1476.           check_size = retval["region",1]:0 * cyl_size;
  1477.           
  1478.       if( !check_ok_fssize( check_size, retval ))
  1479.           {
  1480.           UI::SetFocus(`id(`end_part));
  1481.           ret = `again;
  1482.           continue;
  1483.           }
  1484.  
  1485.        map ret_mp = CheckOkMount( dev, cur_val, retval );
  1486.        retval = ret_mp["map"]:$[];
  1487.        if( !ret_mp["ok"]:false )
  1488.            {
  1489.            if( ret_mp["field"]:`none != `none )
  1490.            UI::SetFocus(`id(ret_mp["field"]:`none));
  1491.            ret = `again;
  1492.            continue;
  1493.            }
  1494.  
  1495.        //////////////////////////////////////////////////////////////
  1496.        //  user changed fsid of existing partition
  1497.        symbol par_type = cur_val["type"]:`empty;
  1498.        y2milestone( "EditOrCreatePartDlg par_type %1", par_type );
  1499.        y2milestone( "EditOrCreatePartDlg retval %1", cur_val );
  1500.        y2milestone( "EditOrCreatePartDlg cur_val %1", retval );
  1501.        if( retval["fsid"]:0 != cur_val["fsid"]:0 &&
  1502.            (par_type==`primary||par_type==`logical||par_type==`extended)&&
  1503.            !haskey( cur_val, "change_fsid") && !disk["readonly"]:false &&
  1504.            !retval["create"]:false && disk["label"]:"msdos"!="gpt" )
  1505.            {
  1506.            // popup text
  1507.            boolean ok = Popup::ContinueCancel(_("
  1508. You have changed the FSID of an existing partition.
  1509. In some cases, this could have serious consequences, especially
  1510. if you change the FSID of a partition belonging to a different
  1511. operating system. Only proceed if you know exactly
  1512. what you are doing.
  1513. "));
  1514.  
  1515.            if (! ok )
  1516.            {
  1517.            UI::ReplaceWidget(`id(`fsid_dlg_rp),
  1518.                       FsidComboBox( cur_val, file_systems ));
  1519.            UI::ChangeWidget(`id(`format), `CurrentButton,
  1520.                     `format_false );
  1521.            ret = `again;
  1522.            continue;
  1523.            }
  1524.  
  1525.            if( !haskey( cur_val, "change_fsid"))
  1526.            {
  1527.            retval["change_fsid"] = true;
  1528.            retval["ori_fsid" ] = cur_val["fsid"]:0;
  1529.            }
  1530.            }
  1531.  
  1532.  
  1533.        map ret_cr = CheckCryptOk( retval );
  1534.        if( !ret_cr["ok"]:false )
  1535.            {
  1536.            ret = `retry;
  1537.            }
  1538.        else
  1539.            {
  1540.            retval = ret_cr["map"]:$[];
  1541.            }
  1542.  
  1543.  
  1544.        ////////////////////////////////////////////////////////
  1545.        // modified partition and partition is mounted
  1546.  
  1547.        if( !installation && !arePartitionsEqual( cur_val, retval ) &&
  1548.            !create )
  1549.            {
  1550.            string mounts = Storage::DeviceMounted( dev );
  1551.            if( mounts != "" )
  1552.            {
  1553.            if( !UseChangedPartitionContinueCancelPopup() )
  1554.                {
  1555.                ret = `cancel;
  1556.                }
  1557.            }
  1558.            }
  1559.        }
  1560.        } until (  ret == `ok  || ret == `cancel );
  1561.  
  1562.     y2milestone( "EditOrCreatePartDlg ret:%1 retval=%2", ret, retval );
  1563.  
  1564.     UI::CloseDialog();
  1565.  
  1566.     if ( ret == `cancel )
  1567.     {
  1568.     return( nil );
  1569.     }
  1570.     else
  1571.     {
  1572.     return( retval );
  1573.     }
  1574.     }
  1575.  
  1576.  
  1577.      /**
  1578.       * Dialog: "Resize a partition Dialog"
  1579.       * @parm cur_val  map that contains a partition
  1580.       * @parm device   device name of the resized partition
  1581.       * @parm cyl_size size of a cylinder on the disk
  1582.       * @return map modified partition or nil by cancel
  1583.       */
  1584. define map ResizePartDlg( map cur_val, string device, map disk, map possible )
  1585.     ``{
  1586.     integer cyl_size = disk["cyl_size"]:0;
  1587.     boolean test_simple_ui = false;
  1588.     boolean win = Partitions::IsDosWinNtPartition( cur_val["fsid"]:0 );
  1589.     boolean swap = !win && cur_val["fsid"]:0==Partitions::fsid_swap;
  1590.     boolean simple_ui = false;
  1591.     integer cyl_after = 0;
  1592.     if( possible["extend"]:false )
  1593.     {
  1594.     cyl_after = Storage::FreeCylAfter( disk, cur_val );
  1595.     }
  1596.     integer av_space = cyl_after*cyl_size;
  1597.  
  1598.     y2milestone( "ResizePartDlg dev:%1 cyl:%2 map:%3 win:%4 swap:%5",
  1599.          device, cyl_size, cur_val, win, swap );
  1600.     y2milestone( "ResizePartDlg cyl_after:%1 av_space:%2",
  1601.          cyl_after, av_space );
  1602.  
  1603.     integer min_free = 0;
  1604.     integer new_size = 0;
  1605.     integer shrink_size = 0;
  1606.     integer new_min = 0;
  1607.  
  1608.     map df = $[];
  1609.  
  1610.     if( !swap && !cur_val["format"]:false )
  1611.     {
  1612.     df = Storage::GetFreeSpace( device, 0, cur_val["used_fs"]:`none, true );
  1613.     if( size(df)==0 || !df["ok"]:false )
  1614.         {
  1615.         y2error( "failed GetFreeSpace %1 fs:%2", device,
  1616.              cur_val["used_fs"]:`none );
  1617.         string tmp = sformat(
  1618. _("Partition %1 cannot be resized
  1619. because the file system seems to be inconsistent.
  1620. "), device );
  1621.         Popup::Error( tmp );
  1622.         return( nil );
  1623.         }
  1624.     }
  1625.     else
  1626.     {
  1627.     df["used"] = 0;
  1628.     if( haskey( cur_val, "orig_size_k" ) && cur_val["resize"]:false )
  1629.         {
  1630.         df["df_free"] = cur_val["orig_size_k"]:0 * 1024;
  1631.         }
  1632.     else
  1633.         {
  1634.         df["df_free"] = cur_val["region",1]:0 * cyl_size;
  1635.         }
  1636.     df["free"] = df["df_free"]:0;
  1637.     }
  1638.  
  1639.     // label text
  1640.     string  unit = _("MB");
  1641.     integer factor = 1024*1024;
  1642.  
  1643.     if( df["df_free"]:0 > 15*1024*factor )
  1644.     {
  1645.     factor = factor * 1024;
  1646.     unit = _("GB");
  1647.     }
  1648.     y2milestone( "ResizePartDlg factor:%1", factor );
  1649.  
  1650.     if( haskey( cur_val, "win_max_length" ) && cur_val["resize"]:false )
  1651.     {
  1652.     new_min = cur_val["orig_size_k"]:0*1024/cyl_size - cur_val["win_max_length"]:0;
  1653.     new_min = new_min*cyl_size / factor;
  1654.     }
  1655.  
  1656.     y2milestone( "ResizePartDlg min_lin:%1 df:%2", new_min, df );
  1657.  
  1658.     integer used = df["used"]:0 / factor;
  1659.     integer free = df["df_free"]:0 / factor;
  1660.     integer not_shrink_free = 0;
  1661.  
  1662.     // Labels for bar graph. "%1" will be replace with a numeric value.
  1663.     string bargraph_label_used  = "";
  1664.     string bargraph_label_free  = "";
  1665.     string bargraph_label_new   = "";
  1666.     if( win )
  1667.     {
  1668.     // label text %1 is replaced by a number
  1669.     bargraph_label_used  = _("Windows\nUsed\n%1 ") + unit;
  1670.     // label text %1 is replaced by a number
  1671.     bargraph_label_free  = _("Windows\nFree\n%1 ") + unit;
  1672.     // label text %1 is replaced by a number
  1673.     bargraph_label_new   = _("Linux\nSize\n%1 ") + unit;
  1674.     }
  1675.     else
  1676.     {
  1677.     // label text %1 is replaced by a number
  1678.     bargraph_label_used  = _("Space\nUsed\n%1 ") + unit;
  1679.     if( swap )
  1680.         {
  1681.         // label text %1 is replaced by a number
  1682.         bargraph_label_free  = _("Swap\nSpace\n%1 ") + unit;
  1683.         }
  1684.     else
  1685.         {
  1686.         // label text %1 is replaced by a number
  1687.         bargraph_label_free  = _("Space\nFree\n%1 ") + unit;
  1688.         }
  1689.     // label text, %1 is replaced by a number
  1690.     bargraph_label_new   = _("Unused\nDisk\n%1 ") + unit;
  1691.     }
  1692.  
  1693.     // Labels for input fields. "%1" will be replaced with the current unit (MB)
  1694.     string field_label_free = "";
  1695.     string field_label_new  = "";
  1696.     if( win )
  1697.     {
  1698.     // label text, %1 is replaced by a unit value ("MB")
  1699.     field_label_free = sformat( _("Windows Free (%1)"), unit);
  1700.     // label text, %1 is replaced by a unit value ("MB")
  1701.     field_label_new  = sformat( _("Linux Size (%1)"), unit);
  1702.     }
  1703.     else
  1704.     {
  1705.     // label text, %1 is replaced by a unit value ("MB")
  1706.     field_label_new  = sformat( _("Unused Disk (%1)"), unit);
  1707.     if( swap )
  1708.         {
  1709.         // label text, %1 is replaced by a unit value ("MB")
  1710.         field_label_free = sformat( _("Swap Space (%1) "), unit);
  1711.         }
  1712.     else
  1713.         {
  1714.         // label text, %1 is replaced by a unit value ("MB")
  1715.         field_label_free = sformat( _("Space Free (%1)"), unit);
  1716.         }
  1717.     }
  1718.  
  1719.     if( win )
  1720.     {
  1721.     min_free = free / 10;
  1722.     if( df["df_free"]:0 != df["free"]:0 )
  1723.         {
  1724.         not_shrink_free = df["df_free"]:0 - df["free"]:0;
  1725.         not_shrink_free = (not_shrink_free + factor - 1) / factor;
  1726.         if( not_shrink_free > min_free )
  1727.         {
  1728.         min_free = not_shrink_free;
  1729.         }
  1730.         }
  1731.     }
  1732.     else
  1733.     {
  1734.     min_free = (factor==1024*1024)?5:1;
  1735.     }
  1736.  
  1737.     if( cur_val["used_fs"]:`none == `ntfs &&
  1738.         not_shrink_free > df["free"]:0/factor/5 )
  1739.         {
  1740.         //Message text.  %1 and %2 are numbers. %3 is the unit.
  1741.     string ptext = sformat( _("Your NTFS file system has %1 %3 free space available. Due to limitations in
  1742. the NTFS resizer, the file system can only be shrunk by up to %2 %3.
  1743. To be able to shrink the file system more, boot your Windows
  1744. system and run a disk defragmentation program under Windows to move
  1745. the used blocks of the file system towards the start of the partition.
  1746. "),
  1747.                                 free, df["free"]:0/factor, unit );
  1748.         Popup::Message( ptext );
  1749.     }
  1750.     if( haskey( cur_val, "orig_size_k" ) && cur_val["resize"]:false )
  1751.     {
  1752.     shrink_size = (df["used"]:0+df["df_free"]:0)/factor -
  1753.               cur_val["region",1]:0*cyl_size/factor;
  1754.     y2milestone( "ResizePartDlg new_size_k:%1 shrink_size:%2",
  1755.                  cur_val["region,1"]:0*cyl_size/factor, shrink_size );
  1756.     if( shrink_size>df["free"]:0/factor )
  1757.         {
  1758.         shrink_size = df["free"]:0/factor;
  1759.         }
  1760.     y2milestone( "ResizePartDlg shrink_size:%1", shrink_size );
  1761.     }
  1762.     av_space = av_space/factor;
  1763.  
  1764.     y2milestone( "ResizePartDlg min_free:%1 free:%2 used:%3 shrink_size:%4 unit:%5",
  1765.                  min_free, free, used, shrink_size, unit );
  1766.  
  1767.     string windows = "";
  1768.     if( win )
  1769.     {
  1770.     // label text
  1771.     windows = _("Windows");
  1772.     }
  1773.  
  1774.     // Help text for partition resizing -
  1775.     // common part for both graphical mode (with bar graphs)
  1776.     // and non-graphical mode (text only).
  1777.     // %1 is OS label, such as Windows
  1778.     string helptext = sformat( _("<p>
  1779. Choose the new size for your %1 partition.
  1780. </p>"), windows );
  1781.  
  1782.     // help text (common to both modes), continued
  1783.     // %1 is OS label, such as Windows
  1784.     helptext = helptext + sformat( _("
  1785. <p>
  1786. The actual resizing is performed only after you confirm all your
  1787. settings in the last installation dialog. Until then, your %1
  1788. partition will remain untouched.
  1789. </p>"), windows );
  1790.  
  1791.     // help text (common to both modes), continued
  1792.     helptext = helptext + _("
  1793. <p>
  1794. If you decide not to resize your partition, press
  1795. <b>Do Not Resize</b>. This resets the values to the original
  1796. size of the partition.
  1797. </p>
  1798. ");
  1799.  
  1800.     if( UI::HasSpecialWidget(`Slider   ) &&
  1801.     UI::HasSpecialWidget(`BarGraph ) && !test_simple_ui )
  1802.     {
  1803.     // help text, continued - graphical mode only
  1804.     // this text will be appended to the help text common to both modes.
  1805.     helptext = helptext + _("
  1806. <p>
  1807. The upper bar graph displays the current situation.
  1808. The lower bar graph displays the situation after the installation (after
  1809. the partition resize).
  1810. </p>");
  1811.     // help text (graphical mode), continued
  1812.     helptext = helptext + _("
  1813. <p>
  1814. Drag the slider or enter a numeric value in either
  1815. input field to adjust the suggested value.
  1816. </p>");
  1817.  
  1818.     ////////////////////////////////////////////////////////////////////////////////////////////
  1819.     // Open main dialog for resizing of partitions
  1820.     ////////////////////////////////////////////////////////////////////////////////////////////
  1821.     term graph = nil;
  1822.     if( win || cyl_after==0 )
  1823.         {
  1824.         graph = `BarGraph( [ used, free ],
  1825.                    [ bargraph_label_used, bargraph_label_free ] );
  1826.         }
  1827.     else
  1828.         {
  1829.         graph = `BarGraph( [ used, free, av_space ],
  1830.                    [ bargraph_label_used, bargraph_label_free,
  1831.                  bargraph_label_new ] );
  1832.         }
  1833.     y2milestone( "ResizePartDlg graph=%1", graph );
  1834.  
  1835.     UI::OpenDialog( `opt(`decorated  ),
  1836.             `HBox(
  1837.               `HWeight(30, `RichText( helptext )),
  1838.               `HStretch(),
  1839.               `HSpacing(1),
  1840.               `HWeight(70,`VBox(
  1841.                   `HSpacing(50),
  1842.                   `VStretch(),
  1843.                   `VSpacing(1),
  1844.                   // Headline above bar graph that displays current partition size
  1845.                   `Left( `Label( _("Now")) ),
  1846.                   graph,
  1847.                   `VSpacing(1),
  1848.                   `VStretch(),
  1849.                   // Headline above bar graph that displays future partitions
  1850.                   `Left( `Label( _("After Installation") ) ),
  1851.                   `PartitionSplitter( `id(`linux_size),
  1852.                           used, free+av_space,
  1853.                           shrink_size+av_space, new_min, min_free,
  1854.                           bargraph_label_used,
  1855.                           bargraph_label_free,
  1856.                           bargraph_label_new,
  1857.                           field_label_free,
  1858.                           field_label_new ),
  1859.                   // Button text
  1860.                   `HBox( `PushButton(`id(`rem_resize), _("&Do Not Resize") )),
  1861.                   `VSpacing(1),
  1862.                   `HBox(
  1863.                    `PushButton(`id(`ok), `opt(`default),  Label::OKButton()   ),
  1864.                    `PushButton(`id(`cancel),  Label::CancelButton() ))
  1865.                   ))));
  1866.     }
  1867.     else
  1868.     {
  1869.     simple_ui = true;
  1870.     // help text, continued - non-graphical mode only
  1871.     // this help text will be appended to the help text common to both modes.
  1872.     //%1 is OS label, such as Windows
  1873.     helptext = helptext + sformat( _("
  1874. <p>Enter a value for the size to which to shrink the %1 partition.
  1875. </p>"), windows );
  1876.  
  1877.     string used_label = "";
  1878.     if( win )
  1879.         {
  1880.         // Label text
  1881.         used_label = _("Windows Used");
  1882.         }
  1883.     else
  1884.         {
  1885.         // Label text
  1886.         used_label = _("Used");
  1887.         }
  1888.     // help text (non-graphical mode), continued
  1889.     //%1 is label text, such as Used. %2 is OS, such as Windows.
  1890.     helptext = helptext + sformat(_("
  1891. <p>
  1892. <b>%1<b> is the size of the used part of your %2 partition.
  1893. </p>"), used_label, windows );
  1894.  
  1895.     // help text (non-graphical mode), continued
  1896.     helptext = helptext + _("
  1897. <p><b>Free</b> indicates the current free space (before shrinking)
  1898. of the partition.
  1899. </p>");
  1900.  
  1901.     UI::OpenDialog( `opt(`decorated  ),
  1902.             `HBox(
  1903.             `HWeight(30, `RichText( helptext )),
  1904.             `HStretch(),
  1905.             `HSpacing(1),
  1906.             `HWeight(70,
  1907.               `VBox(
  1908.                 `HBox(
  1909.                 // Label for used part of the partition in non-graphical mode
  1910.                 `HWeight(3, `Right(`Label(used_label))),
  1911.                 `HWeight(2, `Label(`opt(`outputField), sformat("%1", used ))),
  1912.                 `HWeight(3, `Left(`Label( unit )))),
  1913.                 `VSpacing(0.5),
  1914.                 `HBox(
  1915.                 // Label for free part of the partition in non-graphical mode
  1916.                 `HWeight(3, `Right(`Label(_("Free")))),
  1917.                 `HWeight(2, `Label(`opt(`outputField), sformat("%1", free ))),
  1918.                 `HWeight(3, `Left(`Label( unit )))),
  1919.                 `VSpacing(0.5),
  1920.                 `HBox(
  1921.                  // Edit field label for linux partition size in non-graphical mode
  1922.                 `HWeight(3, `Right(`Bottom(`Label(_("New Size"))))),
  1923.                 `HWeight(2, `IntField( `id(`linux_size), "",
  1924.                                used+min_free, used+free+av_space,
  1925.                                used+free-shrink_size)),
  1926.                 `HWeight(3, `Left(`Bottom(`Label( unit ))))),
  1927.                 // Button text
  1928.                 `HBox( `PushButton( `id(`rem_resize),
  1929.                                     _("&Do Not Resize") )),
  1930.                 `VSpacing(1),
  1931.                 `HBox(
  1932.                  `PushButton( `id(`ok), `opt(`default),
  1933.                               Label::OKButton() ),
  1934.                  `PushButton( `id(`cancel),
  1935.                               Label::CancelButton() ))
  1936.                ))));
  1937.     }
  1938.  
  1939.     map retval = cur_val;
  1940.     any ret = `ok;
  1941.  
  1942.     repeat
  1943.     {
  1944.     /////////////////////////////////////////////////////////////
  1945.     // Check the User input
  1946.     ret = UI::UserInput();
  1947.  
  1948.     y2milestone( "ResizePartDlg ret=%1", ret );
  1949.  
  1950.     if( ret == `rem_resize )
  1951.         {
  1952.         if( simple_ui )
  1953.         UI::ChangeWidget( `id(`linux_size), `Value,  used+free );
  1954.         else
  1955.         UI::ChangeWidget( `id(`linux_size), `Value,  av_space );
  1956.         }
  1957.  
  1958.     if( ret == `ok )
  1959.         {
  1960.         // Get the value the user adjusted. If s/he entered a value
  1961.         // too big or too small this is automatically adjusted to the
  1962.         // biggest/smallest value possible (by Qt).
  1963.         shrink_size = (integer)UI::QueryWidget(`id(`linux_size), `Value);
  1964.         y2milestone( "ResizePartDlg shrink_size %1", shrink_size );
  1965.         if( simple_ui )
  1966.         {
  1967.         new_size = shrink_size;
  1968.         }
  1969.         else
  1970.         {
  1971.         new_size = used + free + av_space - shrink_size;
  1972.         }
  1973.         y2milestone( "ResizePartDlg Value:%1 New size:%2", shrink_size, new_size);
  1974.         }
  1975.         if( ret == `ok )
  1976.         {
  1977.         if( (!simple_ui && shrink_size != av_space) ||
  1978.             (simple_ui && shrink_size != used+free) )
  1979.         {
  1980.         retval["resize"] = true;
  1981.         list new_reg = [ retval["region",0]:0,
  1982.                  PartedSizeToCly( (tofloat(new_size*factor)), cyl_size ) ];
  1983.         retval["region"] = new_reg;
  1984.         }
  1985.         else
  1986.         {
  1987.         retval["resize"] = false;
  1988.         }
  1989.         }
  1990.     if( ret == `ok && !cur_val["format"]:false && retval["resize"]:false )
  1991.         {
  1992.         integer diff = 0;
  1993.         if( haskey( retval, "orig_size_k" ))
  1994.         diff = retval["region",1]:0 - retval["orig_size_k"]:0*1024/cyl_size;
  1995.         else
  1996.         diff = retval["region",1]:0 - cur_val["region",1]:0;
  1997.         string mp = cur_val["inactive"]:false ? "" : cur_val["mount"]:"";
  1998.         y2milestone( "ResizePartDlg diff %1 mp %2", diff, mp );
  1999.         if( !CheckResizePossible( false, false, diff,
  2000.                       cur_val["used_fs"]:`unknown, mp ))
  2001.         {
  2002.         ret = `again;
  2003.         }
  2004.         }
  2005.     y2milestone("ResizePartDlg ret = %1", retval );
  2006.     }
  2007.     until( ret == `ok || ret == `cancel );
  2008.  
  2009.     UI::CloseDialog();
  2010.  
  2011.     if( ret == `cancel )
  2012.     {
  2013.     return( nil );
  2014.     }
  2015.     else
  2016.     {
  2017.     return( retval );
  2018.     }
  2019.     }
  2020.  
  2021.  
  2022.  
  2023.     /*---------------------------------------------------------------------
  2024.      * Display "Create a extended partition Dialog"
  2025.      *
  2026.      * return: nil bei cancel
  2027.      *         [fsid,format,mount,start_cyl,end_cyl] bei ok
  2028.      *
  2029.      *----------------------------------------------------------------------
  2030.      */
  2031. define map CreateEditExtendedPartDlg( map new_val, string title, string dev,
  2032.                                       map disk, integer cyl_size, boolean edit,
  2033.                       boolean bsd_label )
  2034.     ``{
  2035.     string helptextCR = getCreateEditExtendedHelptext();
  2036.  
  2037.     /////////////////////////////////////////////////////////////////////////////////////////
  2038.     // title of the dialog
  2039.     term header = `Heading(title);
  2040.  
  2041.     UI::OpenDialog( `opt(`decorated ),
  2042.             `VBox(
  2043.              //`Heading(title),
  2044.              header,
  2045.              `VSpacing(0.5),
  2046.              `HBox(
  2047.                    /// left side
  2048.                    `HWeight(50,`RichText( helptextCR )),
  2049.                    /// right side
  2050.                    // popup create partition: frame description Start/End Cylinder
  2051.                    `HWeight( 40, SizeDlg( new_val, cyl_size, true, true) )
  2052.                    ),
  2053.              `VSpacing(0.5),
  2054.              `HBox(
  2055.                    // popup create partition:
  2056.                    `PushButton(`id(`ok), `opt(`default),  Label::OKButton()   ),
  2057.                    // popup create partition:
  2058.                    `PushButton(`id(`cancel), Label::CancelButton())
  2059.                    )
  2060.              )
  2061.               );
  2062.  
  2063.     UI::SetFocus(`id(`start_cyl));
  2064.  
  2065.     map     return_value    = $[];
  2066.     symbol  doit            = `cancel;
  2067.     repeat
  2068.         {
  2069.     //-------------------------------
  2070.     // Check the User input
  2071.     //-------------------------------
  2072.     doit = (symbol)UI::UserInput();
  2073.  
  2074.     if( doit != `cancel )
  2075.         {
  2076.         return_value = new_val;
  2077.  
  2078.         list ret = [];
  2079.         string start_cyl =  (string)UI::QueryWidget( `id(`start_cyl), `Value);
  2080.         string end_part  =  (string)UI::QueryWidget( `id(`end_part), `Value);
  2081.  
  2082.         ret = TestStartEndCyl( start_cyl, end_part, dev, disk,
  2083.                    return_value["type"]:`primary,
  2084.                    cyl_size, bsd_label );
  2085.  
  2086.         if (ret[0]:`error == `error )
  2087.         {
  2088.         doit = `again;
  2089.         continue;
  2090.         }
  2091.         if (ret[0]:`error == `max )
  2092.         {
  2093.         end_part =  ret[1]:"";
  2094.         }
  2095.  
  2096.         //////////////////////////////////////////////////////////////
  2097.         // add start_cyl and end_part to region and add region to return_value
  2098.         list region = [ tointeger( start_cyl ),
  2099.                 ToEndRegion( start_cyl, end_part, cyl_size )];
  2100.  
  2101.         return_value["region"] = region;
  2102.         }
  2103.  
  2104.         } until( doit == `cancel || doit == `ok );
  2105.  
  2106.  
  2107.     //------------------------------------------------------------------------------------
  2108.     // Check if the start end cylinder are changed: PopUp // todo change logical cylinders
  2109.     //------------------------------------------------------------------------------------
  2110.     if( doit != `cancel && edit &&
  2111.     return_value["region",0]:0 > new_val["region",0]:0 ||
  2112.     return_value["region",1]:0 != new_val["region",1]:0 )
  2113.     {
  2114.     // warning popup text
  2115.         Popup::Warning(_("You have changed the start or end cylinders.
  2116. Make sure that all logical partitions
  2117. fit into this new extended partition.
  2118. "));
  2119.     }
  2120.  
  2121.     UI::CloseDialog();
  2122.  
  2123.     if( doit == `cancel )
  2124.     {
  2125.         return( nil );
  2126.     }
  2127.     else
  2128.     {
  2129.         return( return_value );
  2130.     }
  2131.     };
  2132.  
  2133.  
  2134.     /*---------------------------------------------------------------------
  2135.      * Dialog choose disk
  2136.      * return /dev/xxx  or nil if cancel
  2137.      * what -> `create or `delete
  2138.      *---------------------------------------------------------------------
  2139.      */
  2140.  
  2141. boolean SelDisk( symbol what, map disk )
  2142.     {
  2143.     return( (what==`delete||!disk["readonly"]:false) &&
  2144.             Storage::IsPartitionable( disk ) &&
  2145.         disk["used_by_type"]:`UB_NONE==`UB_NONE );
  2146.     }
  2147.  
  2148. define string ChooseDisk( map<string,map> targetMap, string heading, symbol what )
  2149.     ``{
  2150.     // Header Choose disk dialog
  2151.     term diskgroup  = `VBox();
  2152.     list<string> disks      = [];
  2153.     integer n = 0;
  2154.     string txt = "";
  2155.  
  2156.     y2milestone( "ChooseDisk last_sel_disk:%1 what:%2", last_sel_disk, what );
  2157.  
  2158.     disks = maplist( string dv, map ds, 
  2159.                      filter( string dev, map disk, targetMap, 
  2160.                     ``(SelDisk(what,disk))),
  2161.             ``(dv));
  2162.     y2milestone( "ChooseDisk disks:%1", disks );
  2163.     disks = (list<string>)
  2164.             merge( filter( string d, disks, ``(search(d,"/dev/mapper/")==0)),
  2165.                    filter( string d, disks, ``(search(d,"/dev/mapper/")!=0)) );
  2166.     y2milestone( "ChooseDisk disks:%1", disks );
  2167.     foreach( string dev, disks,
  2168.     ``{
  2169.       txt = sformat( "&%1: %2", n+1, dev );
  2170.       diskgroup = add( diskgroup, `Left( `RadioButton( `id(dev), txt,
  2171.                                          dev==last_sel_disk )));
  2172.       n = n + 1;
  2173.     });
  2174.     if( size(disks)>10 )
  2175.     {
  2176.     diskgroup = `VBox( `SelectionBox( `id(`disklist), _("Available &Disks"),
  2177.                       disks ));
  2178.     }
  2179.     else
  2180.     {
  2181.     diskgroup = `RadioButtonGroup( `id(`choosedisk), diskgroup );
  2182.     }
  2183.  
  2184.     if( size(disks) > 1 )
  2185.     {
  2186.     UI::OpenDialog( `opt(`decorated), `VBox(`Heading( heading ),
  2187.             `VSpacing(0.5),
  2188.             diskgroup,
  2189.             `VSpacing(0.5),
  2190.             `HBox(
  2191.                   // popup edit existing partition: OK
  2192.                   `PushButton(`id(`ok), `opt(`default), Label::OKButton() ),
  2193.                   // popup edit existing partition: Cancel
  2194.                   `PushButton(`id(`cancel), Label::CancelButton() )
  2195.                   )
  2196.             )
  2197.               );
  2198.     if( UI::WidgetExists( `id(`disklist) ))
  2199.         {
  2200.         UI::ChangeWidget( `id(`disklist), `CurrentItem, last_sel_disk );
  2201.         }
  2202.     symbol ret = (symbol)UI::UserInput();
  2203.  
  2204.     if( ret == `cancel)
  2205.         {
  2206.         UI::CloseDialog();
  2207.         return( nil );
  2208.         }
  2209.     else
  2210.         {
  2211.         string r = "";
  2212.         y2milestone( "ChooseDisk exits %1", UI::WidgetExists( `id(`disklist)) );
  2213.         if( !UI::WidgetExists( `id(`disklist) ))
  2214.         {
  2215.         r = (string)UI::QueryWidget(`id(`choosedisk), `CurrentButton);
  2216.         }
  2217.         else
  2218.         {
  2219.         r = (string)UI::QueryWidget(`id(`disklist), `CurrentItem);
  2220.         }
  2221.         y2milestone( "ChooseDisk r %1", r );
  2222.         UI::CloseDialog();
  2223.         n=0;
  2224.         if( what==`create && targetMap[r,"readonly"]:false )
  2225.         {
  2226.         Popup::Error( Partitions::RdonlyText( r, true ));
  2227.         return( nil );
  2228.         }
  2229.         last_sel_disk = r;
  2230.         y2milestone( "ChooseDisk last_sel_disk:%1", last_sel_disk );
  2231.         return(r);
  2232.         }
  2233.     }
  2234.     else if( size(disks) == 1 )
  2235.     {
  2236.     // if there is only one disk: no
  2237.     return( disks[0]:"" );
  2238.     }
  2239.     else if( size(disks) == 0 )
  2240.     {
  2241.     string txt = _("There are no partitionable Disks available.");
  2242.     if( Arch::s390() )
  2243.         {
  2244.         txt = txt + "\n" + _("You may use dasdfmt in Expert-Button to low level format disks.");
  2245.         }
  2246.     Popup::Error( txt );
  2247.     return( "" );
  2248.     }
  2249.     };
  2250.  
  2251. define term RaidButton( integer num )
  2252.     ``{
  2253.     list item_list = [];
  2254.     item_list = add( item_list,
  2255.              // menue entry text
  2256.              `item( `id(`raid_wizard), _("&Create RAID...") ));
  2257.     if( num>0 )
  2258.     item_list = add( item_list,
  2259.               // menu entry text
  2260.              `item( `id(`raid_settings), _("&Edit RAID")));
  2261.     // button text
  2262.     return( `MenuButton( _("&RAID...") , item_list  ));
  2263.     };
  2264.  
  2265. define term LoopButton( integer num )
  2266.     ``{
  2267.     list item_list = [];
  2268.     item_list = add( item_list,
  2269.               // menue entry text
  2270.              `item( `id(`loop_create), _("&Create Crypt File") ));
  2271.     if( num>0 )
  2272.     item_list = add( item_list,
  2273.              // menue entry text
  2274.              `item( `id(`loop_edit), _("&Edit Crypt File")));
  2275.     // button text
  2276.     return( `MenuButton( _("Cr&ypt File...") , item_list  ));
  2277.     };
  2278.  
  2279.  
  2280.  
  2281.     /*---------------------------------------------------------------------
  2282.      * Dialog choose primary extended or logical Partition
  2283.      * Input "PL", "PE" or "PEL"
  2284.      * return `primary or `logical or `extended or `none
  2285.      *---------------------------------------------------------------------
  2286.      */
  2287.  
  2288. define symbol ChoosePart( string usage )
  2289.       ``{
  2290.       term PL = `VBox(
  2291.           // button text
  2292.           `Left( `RadioButton( `id(`primary ), _("&Primary Partition"), true )),
  2293.           // button text
  2294.           `Left( `RadioButton( `id(`logical ), _("&Logical Partition"), false ))
  2295.              );
  2296.       term PE = `VBox(
  2297.           // button text
  2298.           `Left( `RadioButton( `id(`primary ), _("&Primary Partition"), true )),
  2299.           // button text
  2300.           `Left( `RadioButton( `id(`extended ), _("&Extended Partition"), false ))
  2301.              );
  2302.       term PEL = `VBox(
  2303.           // button text
  2304.           `Left( `RadioButton( `id(`primary ), _("&Primary Partition"), true )),
  2305.           // button text
  2306.           `Left( `RadioButton( `id(`logical ), _("&Logical Partition"), false )),
  2307.           // button text
  2308.           `Left( `RadioButton( `id(`extended ), _("&Extended Partition"), false ))
  2309.               );
  2310.  
  2311.       term                 current = PEL;        // default
  2312.       if ( usage == "PL" ) current = PL;
  2313.       if ( usage == "PE" ) current = PE;
  2314.  
  2315.       UI::OpenDialog( `opt(`decorated ),
  2316.               // heading in a popup dialog
  2317.                       `VBox(`Heading(_("Partition Type") ),
  2318.                     `VSpacing(0.5),
  2319.                 `RadioButtonGroup( `id(`choosePL), current ),
  2320.                 `VSpacing(0.5),
  2321.                 `HBox(
  2322.                   // popup edit existing partition: OK
  2323.                   `PushButton(`id(`ok),  `opt(`default), Label::OKButton() ),
  2324.                   // popup edit existing partition: Cancel
  2325.                   `PushButton(`id(`cancel), Label::CancelButton()   )
  2326.                   )
  2327.                 )
  2328.             );
  2329.       symbol ret = (symbol)UI::UserInput();
  2330.  
  2331.       if (ret == `cancel)
  2332.       {
  2333.       UI::CloseDialog();
  2334.       return(`none);
  2335.       }
  2336.       else
  2337.       {
  2338.       ret = (symbol)UI::QueryWidget(`id(`choosePL), `CurrentButton);
  2339.       UI::CloseDialog();
  2340.       return(ret);
  2341.       }
  2342.     };
  2343.  
  2344.  
  2345.     /*---------------------------------------------------------------------
  2346.      * Make a output string for "you can not create a partition, because: "
  2347.      *---------------------------------------------------------------------
  2348.      */
  2349.  
  2350.  
  2351. define string FormatCauseLine( symbol cause )
  2352.     ``{
  2353.     if( cause == `no_ext )
  2354.     // complete sentence, appended after other complete sentences.
  2355.     return( _("No extended partition exists."));
  2356.     if( cause == `dev_full )
  2357.     // complete sentence, appended after other complete sentences.
  2358.     return( _("There are already four primary and extended partitions."));
  2359.     if( cause == `no_extsp )
  2360.     // complete sentence, appended after other complete sentences.
  2361.     return( _("No space is left in the extended partition."));
  2362.     if( cause == `to_many )
  2363.     // complete sentence, appended after other complete sentences.
  2364.     return( _("Too many logical drives already exist."));
  2365.     if ( cause == `no_space )
  2366.     // complete sentence, appended after other complete sentences.
  2367.     return( _("No space remains."));
  2368.     if ( cause == `already )
  2369.     // complete sentence, appended after other complete sentences.
  2370.     return( _("An extended partition already exists."));
  2371.     return( "---" );
  2372.     };
  2373.  
  2374. define term GetTableHeader () {
  2375.     term header = `header();
  2376.  
  2377.     // Column header
  2378.     if ( showT_dev )    header = add( header, _("Device"));
  2379.  
  2380.     // Column header
  2381.     if ( showT_id )     header = add( header, _("ID"));
  2382.  
  2383.     // Column header: centered / minimum = 11 characters /
  2384.     // fill with space if needed
  2385.     if ( showT_size )   header = add( header, `Right(_("    Size    ")));
  2386.  
  2387.     // Column header: centered / minimum = 3 characters /
  2388.     // fill with space if needed
  2389.     if ( showT_format ) header = add( header, `Right(_(" F ")));
  2390.  
  2391.     // Column header
  2392.     if ( showT_fs )     header = add( header,  _("Type"));
  2393.  
  2394.     // Column header: centered / minimum = 7 characters /
  2395.     // fill with space if needed
  2396.     if ( showT_mount )  header = add( header, _(" Mount "));
  2397.  
  2398.     // Column header
  2399.     if ( show_T_details && showT_mby )    header = add( header, _("Mount By"));
  2400.  
  2401.     // Column header: minimum = 5 characters   fill with space if needed
  2402.     if ( show_T_details && showT_cyl )    header = add( header, `Right(_("Start")));
  2403.  
  2404.     // Column header: minimum = 4 characters   fill with space if needed
  2405.     if ( show_T_details && showT_cyl )    header = add( header, `Right(_("End ")));
  2406.  
  2407.     // Column header
  2408.     if ( showT_Used )   header = add( header, `Left(_("Used By")));
  2409.  
  2410.     // Column header
  2411.     if ( showT_Label )  header = add( header, `Left(_("Label")));
  2412.  
  2413.     // Column header
  2414.     if ( show_T_details && showT_udev_id )   header = add( header, `Left(_("Device ID")));
  2415.  
  2416.     // Column header
  2417.     if ( show_T_details && showT_udev_path ) header = add( header, `Left(_("Device Path")));
  2418.     
  2419.     return header;
  2420. }
  2421.  
  2422.     /*---------------------------------------------------------------------
  2423.      * Make a output string for "you can not create a partition, because: "
  2424.      *---------------------------------------------------------------------
  2425.      */
  2426.  
  2427. define string FormatYouCannotCause( boolean primary_is_possible,
  2428.                     boolean extended_is_possible,
  2429.                     boolean logical_is_possible,
  2430.                     symbol  no_primary_cause,
  2431.                     symbol  no_extended_cause,
  2432.                     symbol  no_logical_cause )
  2433.     ``{
  2434.     string pri_line = "";
  2435.     string ext_line = "";
  2436.     string log_line = "";
  2437.  
  2438.     y2milestone( "prim:%1 ext:%2 log:%3 (%4 %5 %6)", primary_is_possible,
  2439.                  extended_is_possible, logical_is_possible, no_primary_cause,
  2440.          no_extended_cause, no_logical_cause );
  2441.  
  2442.     if( primary_is_possible )
  2443.     // complete sentence. gets combined with other sentences.
  2444.     pri_line = _("A primary partition can be created.\n");
  2445.     else
  2446.     // complete sentence. gets combined with other sentences.
  2447.     pri_line = _("A primary partition cannot be created.") + " " +
  2448.                FormatCauseLine( no_primary_cause ) + "\n";
  2449.  
  2450.     if( logical_is_possible )
  2451.     // complete sentence. gets combined with other sentences.
  2452.     log_line = _("A logical partition can be created.\n");
  2453.     else
  2454.     if( no_logical_cause != `impossible )
  2455.         // complete sentence. gets combined with other sentences.
  2456.         log_line = _("A logical partition cannot be created.") + " " +
  2457.                FormatCauseLine( no_logical_cause ) +"\n" ;
  2458.  
  2459.     if ( extended_is_possible )
  2460.     // complete sentence. gets combined with other sentences.
  2461.     ext_line = _("An extended partition can be created.\n");
  2462.     else
  2463.     if( no_logical_cause != `impossible )
  2464.         // complete sentence. gets combined with other sentences.
  2465.         ext_line = _("An extended partition cannot be created.") + " " +
  2466.                FormatCauseLine( no_extended_cause ) +"\n";
  2467.  
  2468.     return ( pri_line + ext_line + log_line );
  2469.     };
  2470.  
  2471.  
  2472.     /////////////////////////////////////////////////////////////////
  2473.     // MAIN:
  2474.     /////////////////////////////////////////////////////////////////
  2475.  
  2476.     symbol ret = nil;
  2477.  
  2478.     y2milestone( "Custom partitioner started" );
  2479.     Storage::SetWizardKey("");
  2480.  
  2481.     SCR::Write(.target.ycp, Storage::SaveDumpPath("targetMap_s"),
  2482.                Storage::GetTargetMap() );
  2483.  
  2484.     map<string,map> tg = Storage::GetTargetMap();
  2485.     list table_list = FillPartitionList(tg);
  2486.  
  2487.     if( !Storage::CheckBackupState("custom_part") )
  2488.     {
  2489.     Storage::CreateTargetBackup("custom_part");
  2490.     }
  2491.  
  2492.     /////////////////////////////////////////////////////////////////
  2493.     ///              MAIN DIALOG
  2494.  
  2495.  
  2496.  
  2497.     /////////////////////////////////////////////////////////////////
  2498.     //    MAIN LAYOUT
  2499.     // ---------------------------
  2500.  
  2501.     term buttonline_a = `HBox();
  2502.  
  2503.     // main dialog: Button Create partition
  2504.     if( button_create )
  2505.     buttonline_a = add( buttonline_a,
  2506.                         `PushButton(`id(`create), _("&Create")) );
  2507.  
  2508.     // main dialog: Button Edit partition
  2509.     if( button_edit )
  2510.     buttonline_a = add( buttonline_a, `PushButton(`id(`edit), _("&Edit")));
  2511.  
  2512.     // main dialog: Button Delete partition
  2513.     if( button_delete )
  2514.     buttonline_a = add( buttonline_a,
  2515.                         `PushButton(`id(`delete), _("&Delete")) );
  2516.  
  2517.     // main dialog: Button Resize partition
  2518.     if( button_resize )
  2519.     buttonline_a = add( buttonline_a,
  2520.                         `PushButton(`id(`resize), _("Re&size")) );
  2521.  
  2522.  
  2523.  
  2524.     list expert_item_list =[];
  2525.     if( button_reread )
  2526.     expert_item_list =
  2527.         add( expert_item_list ,
  2528.              // menu entry text
  2529.          `item( `id (`reread),  _("&Reread Partition Table")));
  2530.     if( button_adapt_mp )
  2531.     expert_item_list =
  2532.         add( expert_item_list,
  2533.          `item( `id (`adapt_mp),
  2534.             // menu entry text
  2535.                 _("&Import Mount Points from Existing /etc/fstab")));
  2536.     if ( button_delete_parttable )
  2537.     expert_item_list =
  2538.         add( expert_item_list,
  2539.          `item( `id (`delete_parttable),
  2540.             // menu entry text
  2541.                 _("Delete Partition &Table and Disk Label")));
  2542.     if( Arch::s390 () )
  2543.     {
  2544.     expert_item_list =
  2545.         add( expert_item_list,
  2546.          `item( `id(`dasdfmt),
  2547.             // menu entry text
  2548.                 _("Execute dasd&fmt on the DASD Device")));
  2549.     buttonline_a = add( buttonline_a, `PushButton(`id(`dasdfmt),
  2550.                               //button text using case-senstive command name.  dasdfmt should not normally be translated.
  2551.                         _("dasd&fmt")) );
  2552.     }
  2553.  
  2554.  
  2555.     term buttonline_b = `HBox();
  2556.  
  2557.     if( button_lvm )
  2558.     // main dialog: Button LVM
  2559.     buttonline_b = add( buttonline_b, `PushButton(`id(`lvm), _("&LVM...")));
  2560.  
  2561.     if( button_evms )
  2562.     // main dialog: Button EVMS
  2563.     buttonline_b = add( buttonline_b, `PushButton(`id(`evms), _("E&VMS...")));
  2564.  
  2565.     // main dialog: Button RAID
  2566.     if( button_raid )
  2567.     buttonline_b =
  2568.         add( buttonline_b,
  2569.          `ReplacePoint( `id(`raid_button),
  2570.                     RaidButton(size(tg["/dev/md","partitions"]:[]))));
  2571.  
  2572.     // main dialog: Button LOOP
  2573.     if( button_loop )
  2574.     buttonline_b =
  2575.         add( buttonline_b,
  2576.          `ReplacePoint( `id(`loop_button),
  2577.                     LoopButton(size(tg["/dev/loop","partitions"]:[]))));
  2578.  
  2579.     if( button_expert) buttonline_b =
  2580.     // main dialog: Menu-Button for Expert options
  2581.     add( buttonline_b, `MenuButton ( _("E&xpert.."), expert_item_list ));
  2582.  
  2583.  
  2584.     // check box
  2585.     term details_checkbox = `Left (
  2586.     `CheckBox (`id(`show_table_details), `opt(`notify), _("&Show Details"), show_T_details)
  2587.     );
  2588.  
  2589.     term contents = `VBox( `VSpacing(0.5),
  2590.                `ReplacePoint(
  2591.                  `id(`table_rp),
  2592.                              `Table( `id(`table), `opt(`notify,`keepSorting),
  2593.                    GetTableHeader(), table_list )
  2594.                    ),
  2595.                details_checkbox,
  2596.                buttonline_a,
  2597.                buttonline_b ) ;
  2598.  
  2599.     string help_text = "";
  2600.     if( Arch::s390 () )
  2601.     {
  2602.     help_text = getMainHelptextS390();
  2603.     }
  2604.     else
  2605.     {
  2606.     help_text = getMainHelptext(Stage::initial());
  2607.     }
  2608.  
  2609.     // Main dialog: Header
  2610.  
  2611.     string back_label = "";
  2612.     string next_label = "";
  2613.     if( Stage::initial () )
  2614.     {
  2615.     back_label = Label::BackButton();
  2616.     next_label = Label::AcceptButton();
  2617.     }
  2618.     else
  2619.     {
  2620.     back_label = Label::QuitButton();
  2621.     // button text
  2622.     next_label =  _("&Apply");
  2623.     Wizard::HideAbortButton();
  2624.     }
  2625.  
  2626.     // heading text
  2627.     Wizard::SetContentsButtons(_("Expert Partitioner"), contents, help_text,
  2628.                                back_label, next_label );
  2629.  
  2630.  
  2631.    //////////////////////////////////////////////////////////////////
  2632.    ////  Loop for User Input ....
  2633.    //////////////////////////////////////////////////////////////////
  2634.  
  2635.     repeat
  2636.         {
  2637.     map<string,map> tg =  Storage::GetTargetMap();
  2638.         table_list = FillPartitionList(tg);
  2639.         UI::ChangeWidget(`id(`table), `Items, table_list);
  2640.  
  2641.     ///////////////////////////////////////////////////////
  2642.     // Now set the focus
  2643.     // (only for "show_disk" cause I use the disk line)
  2644.  
  2645.     if( show_disk )
  2646.         {
  2647.         UI::SetFocus( `id(`table));
  2648.         focusline = Storage::GetLastUsed();
  2649.         y2milestone( "focusline %1", focusline );
  2650.         if( size(focusline)>0 )
  2651.             {
  2652.             UI::ChangeWidget(`id(`table), `CurrentItem, focusline);
  2653.             }
  2654.         }
  2655.  
  2656.         ret = (symbol)Wizard::UserInput();
  2657.  
  2658.     y2milestone( "USERINPUT: %1", ret);
  2659.  
  2660.     if( ret==`show_table_details ) 
  2661.         {
  2662.         show_T_details = (boolean) UI::QueryWidget(`id(`show_table_details), `Value);
  2663.         UI::ReplaceWidget( `id(`table_rp),
  2664.                    `Table( `id(`table), `opt(`notify,`keepSorting),
  2665.                        GetTableHeader(), [] ));
  2666.         continue;
  2667.         }
  2668.     
  2669.  
  2670.         /////////////////////////////////////////////////////////////
  2671.         ////  CREATE
  2672.         /////////////////////////////////////////////////////////////
  2673.         else if( ret == `create)
  2674.         {
  2675.             string ddev = ChooseDisk( tg,
  2676.                       // popup text
  2677.                       _("Disk to Partition"),
  2678.                       `create );
  2679.  
  2680.         if( ddev == nil || size(ddev)==0 )
  2681.         {
  2682.         ret = `again;
  2683.         continue;
  2684.         }
  2685.  
  2686.         symbol create_type = `none;
  2687.         map disk = tg[ddev]:$[];
  2688.  
  2689.         list possibilities = CheckCreatePossibilities( ddev, disk );
  2690.         y2milestone( "possibilities %1", possibilities );
  2691.  
  2692.         boolean primary_is_possible  = possibilities[0]:false;
  2693.         boolean extended_is_possible = possibilities[1]:false;
  2694.         boolean logical_is_possible  = possibilities[2]:false;
  2695.  
  2696.         symbol  no_primary_cause     = possibilities[3]:`no_space;
  2697.         symbol  no_extended_cause    = possibilities[4]:`no_space;
  2698.         symbol  no_logical_cause     = possibilities[5]:`no_space;
  2699.  
  2700.         list log_slot = [];
  2701.         list p_e_slot = [];
  2702.  
  2703.         //////////////////////////////////////////////////////////
  2704.         // Test if there is space left on the device
  2705.         log_slot = GetLogicalSlot(ddev, disk);
  2706.         y2milestone( "log_slot %1", log_slot );
  2707.         p_e_slot = GetSlot(ddev, disk);
  2708.         y2milestone( "p_e_slot %1", p_e_slot );
  2709.  
  2710.         if ((log_slot == nil) && logical_is_possible )
  2711.         no_logical_cause  = `no_space;
  2712.         if ((p_e_slot == nil) && primary_is_possible )
  2713.         no_primary_cause  = `no_space;
  2714.         if ((p_e_slot == nil) && extended_is_possible)
  2715.         no_extended_cause = `no_space;
  2716.  
  2717.         if (log_slot == nil)
  2718.         logical_is_possible  = false;
  2719.         if (p_e_slot == nil)
  2720.             primary_is_possible  = false;
  2721.         if (p_e_slot == nil)
  2722.             extended_is_possible = false;
  2723.  
  2724.  
  2725.  
  2726.         /*----------------------------------------------------------------------
  2727.         *   Intel/Fdisk  PPC/Fdisk
  2728.         *
  2729.         *   At the same time is not possible, that both "logial_part_is_possible"
  2730.         *   and "extended_part_is_possible" are true
  2731.         *   so we have 6 possible situations
  2732.         *
  2733.         *   to show this we use
  2734.         *   "P" for primary_part_is_possible
  2735.         *   "E" for extended_part_is_possible
  2736.         *   "L" for logial_part_is_possible
  2737.         *
  2738.         *   "p" for primary_part_is_possible  == false
  2739.         *   "e" for extended_part_is_possible == false
  2740.         *   "l" for logial_part_is_possible  == false
  2741.         *
  2742.         *
  2743.         *   PE  : I can create a primary or exended part.
  2744.         *   PL  : Extended part. exist. I can create a primary or a logical
  2745.         *   Pel : only a priary is possible, when the extended part. has no space left
  2746.         *
  2747.         *   pE  : Not possible, if "E" is possible always "P" is possible too.
  2748.         *   pL  : only a logical is possible, if together 4 primary and extended
  2749.         *          partitions are already created
  2750.         *   pel : no partitions are possible
  2751.         *
  2752.         *   --------------------------------------------------------------------
  2753.         *
  2754.         *   BSD-Labeling:
  2755.         *   "Pel" for primary_part_is_possible
  2756.         *   "pel" for primary_part_is_possible  == false
  2757.         *
  2758.         *--------------------------------------------------------------------------*/
  2759.  
  2760.         if( !primary_is_possible  && !extended_is_possible &&
  2761.             !logical_is_possible )
  2762.         {
  2763.         // ------pel--------
  2764.         string text = "";
  2765.  
  2766.         if( disk["label"]:"msdos" != "msdos" )
  2767.             {
  2768.             // popup text , %1 is replaced by a disk name e.g. /dev/hda
  2769.             text = sformat( _("It is not possible to create a partition on %1."), ddev);
  2770.             }
  2771.         else
  2772.             {
  2773.             // popup text , %1 is replaced by a disk name e.g. /dev/hda
  2774.             // %2 is replaced by an explanation
  2775.             text = sformat( _("It is not possible to create a partition on %1.
  2776.  
  2777. %2
  2778. "), ddev,
  2779.                     FormatYouCannotCause( primary_is_possible,
  2780.                                           extended_is_possible,
  2781.                               logical_is_possible,
  2782.                               no_primary_cause,
  2783.                               no_extended_cause,
  2784.                               no_logical_cause ));
  2785.             }
  2786.         Popup::Warning(text);
  2787.         }
  2788.         else if( !primary_is_possible && logical_is_possible )
  2789.         {
  2790.         //------pL----------
  2791.         create_type = `logical;
  2792.         }
  2793.         else if( !primary_is_possible && extended_is_possible )
  2794.         {
  2795.         //------pE----------
  2796.         create_type = `extended;
  2797.         }
  2798.         else if( primary_is_possible && !extended_is_possible &&
  2799.                  !logical_is_possible )
  2800.         {
  2801.         //------Pel----------
  2802.         create_type = `primary;
  2803.         }
  2804.         else if ( primary_is_possible  && extended_is_possible )
  2805.         {
  2806.         //------PE----------
  2807.         create_type = ChoosePart("PE");   // ddev
  2808.         }
  2809.         else if ( primary_is_possible  && logical_is_possible )
  2810.         {
  2811.         //------PL----------
  2812.         create_type = ChoosePart("PL");     // popup
  2813.         }
  2814.         else
  2815.         {
  2816.         y2error("Error during partition check" );
  2817.         create_type = ChoosePart("PEL");   // popup
  2818.         }
  2819.  
  2820.         if( create_type != `none )
  2821.         {
  2822.         list slot = (create_type!=`logical)?p_e_slot:log_slot;
  2823.         y2milestone( "slot:%1", slot );
  2824.         map r = Storage::NextPartition( disk["device"]:"",
  2825.                                         create_type );
  2826.         integer curr_nr = r["nr"]:0;
  2827.  
  2828.         //---------------------------------------------------
  2829.         // Present the Create-Popups ...
  2830.         //---------------------------------------------------
  2831.  
  2832.         string titleC = "";
  2833.         // Popup Create Partition: Description of partition %1 is for example "/dev/hda"
  2834.         if ( create_type == `primary )  titleC = sformat( _(" Create a Primary Partition on %1 "), ddev );
  2835.         // Popup Create Partition: Description of partition %1 is for example "/dev/hda"
  2836.         if ( create_type == `extended ) titleC = sformat( _(" Create an Extended Partition on %1 "), ddev );
  2837.         // Popup Create Partition: Description of partition %1 is for example "/dev/hda"
  2838.         if ( create_type == `logical )  titleC = sformat( _(" Create a Logical Partition on %1 "), ddev );
  2839.  
  2840.         map<string,any> new_val =
  2841.             $[
  2842.             "create" : true,
  2843.             "region" : [ slot[0]:0, slot[1]:0 - slot[0]:0+1 ],
  2844.             "type"   : create_type,
  2845.             "nr"     : curr_nr,
  2846.             "device" : r["device"]:""
  2847.             ];
  2848.  
  2849.  
  2850.         if( create_type == `extended )
  2851.             {
  2852.             new_val = (map<string,any>)union( new_val ,
  2853.             $[
  2854.             "fsid"    : Partitions::fsid_extended_win,
  2855.             "used_fs" : `unknown,
  2856.              ]);
  2857.  
  2858.             new_val =
  2859.             (map<string,any>)CreateEditExtendedPartDlg( new_val,
  2860.                                     titleC,
  2861.                                     ddev,
  2862.                                     disk,
  2863.                                     disk["cyl_size"]:1000000,
  2864.                                     false,
  2865.                                     bsd_label );
  2866.             }
  2867.         else
  2868.             {
  2869.             string mount_point_proposal =
  2870.             GetMountPointProposal( Storage::GetTargetMap(), [] );
  2871.             symbol used_fs = Partitions::DefaultFs();
  2872.             if( mount_point_proposal == Partitions::BootMount() )
  2873.             {
  2874.             used_fs = Partitions::DefaultBootFs();
  2875.             }
  2876.             new_val =
  2877.             (map<string,any>)union( new_val,
  2878.                 $[
  2879.                 "format" : true,
  2880.                 "fsid"   : Partitions::fsid_native,
  2881.                 "mount"  : mount_point_proposal,
  2882.                 "used_fs": used_fs,
  2883.                  ]);
  2884.  
  2885.             if( Mode::repair() )
  2886.             {
  2887.             new_val["format"] = false;
  2888.             new_val["mount" ] = "";
  2889.             }
  2890.  
  2891.             new_val = EditOrCreatePartDlg( new_val,
  2892.                            FileSystems::GetAllFileSystems(true, true ),
  2893.                            titleC, disk,
  2894.                            bsd_label, edit_cylinder,
  2895.                            disk["cyl_size"]:1000000,
  2896.                            Stage::initial() );
  2897.             }
  2898.  
  2899.         if (new_val != nil)
  2900.             {
  2901.             // set focus to new partition
  2902.             focusline = new_val["device"]:"";
  2903.             Storage::CreatePartition( disk["device"]:"",
  2904.                           new_val["device"]:"",
  2905.                                       new_val["type"]:`primary,
  2906.                                       new_val["fsid"]:Partitions::fsid_native,
  2907.                           new_val["region",0]:0,
  2908.                           new_val["region",1]:0 );
  2909.             Storage::ChangeVolumeProperties( new_val );
  2910.             }
  2911.         }
  2912.         }
  2913.  
  2914.       ///////////////////////////////////////////////////////////////
  2915.       ////  EDIT
  2916.       ///////////////////////////////////////////////////////////////
  2917.  
  2918.         if( ret == `edit || ret == `table )
  2919.         {
  2920.         map<string,any> part = $[];
  2921.         string id = "";
  2922.         id = (string)UI::QueryWidget(`id(`table), `CurrentItem);
  2923.  
  2924.         // notify a line is selected
  2925.             if( id != nil )
  2926.         {
  2927.         focusline = id;
  2928.         if( !haskey( tg, id ) )
  2929.             part = Storage::GetPartition( tg, id );
  2930.  
  2931.         y2milestone( "current partition %1", part );
  2932.  
  2933.         if( size(part)==0 )
  2934.             {
  2935.             if( tg[id,"type"]:`CT_UNKNOWN == `CT_LVM )
  2936.             {
  2937.             ret = `lvm;
  2938.             }
  2939.             else
  2940.             {
  2941.             TargetAllocationDlg(tg[id]:$[], id );
  2942.             }
  2943.             }
  2944.         else if( part["type"]:`unknown == `lvm )
  2945.             {
  2946.             HandleEditLv( tg, id );
  2947.             }
  2948.         else if( part["type"]:`unknown == `sw_raid )
  2949.             {
  2950.             RaidExpertDlg( `settings, id, part,
  2951.                    FileSystems::GetAllFileSystems(true,true),
  2952.                    false, tg );
  2953.             }
  2954.         else if( part["type"]:`unknown == `evms )
  2955.             {
  2956.             map ad = edit_evms_volume( id, tg );
  2957.             // has the user cancelled the dialog?
  2958.             if( ad["ok"]:false && size( ad["targets"]:$[] )>0 )
  2959.             {
  2960.             Storage::SetTargetMap( ad["targets"]:$[] );
  2961.             }
  2962.             }
  2963.         else if( part["type"]:`unknown == `loop )
  2964.             {
  2965.             ret = `loop_edit;
  2966.             }
  2967.         else
  2968.             {
  2969.             map new_val = $[];
  2970.             map<string,any> disk = Storage::GetDisk( tg, id );
  2971.             /////////////////////////////////////////////////////
  2972.             // check if the partition can be deleted
  2973.  
  2974.             if( !check_device_edit( part, bsd_label))
  2975.             {
  2976.             ret = `again;
  2977.             continue;
  2978.             }
  2979.  
  2980.             list<map> partitions_without_current =
  2981.             filter( map p, disk["partitions"]:[],
  2982.                 ``(p["nr"]:(any)0!=part["nr"]:(any)0 ));
  2983.  
  2984.             map<string,any> disk_without_current =
  2985.             add( disk, "partitions", partitions_without_current);
  2986.             //////////////////////////////////////
  2987.             // There are three different Editors:
  2988.             // - "normal"
  2989.             // - extended
  2990.             // - already existing
  2991.  
  2992.             if( part["type"]:`primary == `extended )
  2993.             {
  2994.             if( part["create"]:false )
  2995.                 {
  2996.                 // header of the dialog edit a partition
  2997.                 string title = _("Edit an Extended Partition") +
  2998.                                " " + part["device"]:"";
  2999.                 new_val = CreateEditExtendedPartDlg( part,
  3000.                                  title,
  3001.                                  part["device"]:"",
  3002.                                  disk_without_current,
  3003.                                  disk["cyl_size"]:1000000,
  3004.                                  true,
  3005.                                  bsd_label
  3006.                                    );
  3007.                 }
  3008.             else
  3009.                 {
  3010.                 // error popup text
  3011.                 Popup::Error( _("An already-existing extended partition cannot be changed.
  3012. Delete this partition then create a new one using
  3013. the new parameters.
  3014. All data on this partition will be lost if you delete it."));
  3015.                 new_val = nil;
  3016.                 }
  3017.             }
  3018.             else
  3019.             {
  3020.             string title = "";
  3021.             if( !part["create"]:false )
  3022.                 {
  3023.                 // header of the dialog to edit a partition %1 is replaced by device name (e.g. /dev/hda1)
  3024.                 title = sformat( _("Edit Existing Partition %1"),
  3025.                                  part["device"]:"" );
  3026.                 if( part["type"]:`primary != `primary &&  
  3027.                     part["type"]:`primary != `logical )
  3028.                 title = sformat( _("Edit Existing Device %1"),
  3029.                          part["device"]:"" );
  3030.                 }
  3031.             else
  3032.                 {
  3033.                 // header of the dialog to edit a partition %1 is replaced by device name (e.g. /dev/hda1)
  3034.  
  3035.                 title = sformat( _("Edit Partition %1"),
  3036.                                  part["device"]:"" );
  3037.                 }
  3038.  
  3039.             new_val =
  3040.                 EditOrCreatePartDlg( part,
  3041.                          FileSystems::GetAllFileSystems(true, true) ,
  3042.                          title,
  3043.                          disk_without_current,
  3044.                          bsd_label, edit_cylinder,
  3045.                          disk["cyl_size"]:1000000,
  3046.                          Stage::initial() );
  3047.             }
  3048.             if( new_val != nil && size(new_val)>0 )   // not canceld
  3049.             {
  3050.             if( new_val["create"]:false )
  3051.                 Storage::UpdatePartition( new_val["device"]:"",
  3052.                               new_val["region",0]:0,
  3053.                               new_val["region",1]:0 );
  3054.             if( !disk["readonly"]:false )
  3055.                 Storage::SetPartitionId( new_val["device"]:"",
  3056.                              new_val["fsid"]:Partitions::fsid_native );
  3057.             Storage::ChangeVolumeProperties( new_val );
  3058.             }
  3059.             }
  3060.             }
  3061.         else
  3062.             {
  3063.                 // popup text
  3064.                 Popup::Message(_("Select the partition to edit in the main dialog.") );
  3065.             }
  3066.         }
  3067.  
  3068.         /////////////////////////////////////////////////////////////
  3069.         // DELETE
  3070.         /////////////////////////////////////////////////////////////
  3071.         if (ret == `delete)
  3072.         {
  3073.         map<string,any> part = $[];
  3074.         string id = (string)UI::QueryWidget( `id(`table), `CurrentItem);
  3075.         map<string,any> disk = Storage::GetDisk( tg, id );
  3076.  
  3077.         if( !haskey( tg, id ) )
  3078.         part = Storage::GetPartition( tg, id );
  3079.         y2milestone( "id:%1 part:%2", id, part );
  3080.         if( !haskey( tg, id ) && size(part)==0 )
  3081.         {
  3082.         ret = `again;
  3083.         continue;
  3084.         }
  3085.  
  3086.         if( disk["readonly"]:false )
  3087.         {
  3088.         Popup::Error( Partitions::RdonlyText( disk["device"]:"", true ));
  3089.         ret = `again;
  3090.         continue;
  3091.         }
  3092.  
  3093.         if( haskey( tg, id ) )
  3094.         {
  3095.         if( tg[id,"type"]:`CT_UNKNOWN == `CT_MD )
  3096.             {
  3097.             ret = `again;
  3098.             continue;
  3099.             }
  3100.         else if( tg[id,"type"]:`CT_UNKNOWN == `CT_LVM )
  3101.             {
  3102.             string current_vg = substring( tg[id,"device"]:"", 5 );
  3103.             HandleRemoveVg( tg, current_vg );
  3104.             }
  3105.         else if( tg[id,"type"]:`CT_UNKNOWN == `CT_DMRAID )
  3106.             {
  3107.             if( Popup::YesNo( sformat(_("Really delete BIOS RAID %1?"), id )))
  3108.             {
  3109.             if( deleteAllDevPartitions( disk, Stage::initial(), bsd_label ))
  3110.                 Storage::DeleteDmraid( id );
  3111.             }
  3112.             }
  3113.                 // YesNo popup text %1 is replaced by a disk name e.g. /dev/hda
  3114.         else if( Popup::YesNo( sformat(_("Really delete all partitions on %1?"), id )))
  3115.             {
  3116.             focusline = id;
  3117.             deleteAllDevPartitions( disk, Stage::initial(), bsd_label );
  3118.             }
  3119.         }
  3120.         else if( part["type"]:`unknown==`lvm )
  3121.         {
  3122.         if( !check_device_delete( part, false, Stage::initial()))
  3123.             {
  3124.             ret = `again;
  3125.             continue;
  3126.             }
  3127.         else
  3128.             HandleRemoveLv( tg, id );
  3129.         }
  3130.             else
  3131.         {
  3132.                 /////////////////////////////////////////////////////
  3133.                 // delete algorithm:
  3134.                 // if you find newly created (but until now not realy
  3135.         // written) partition (sign: "create = true"): delete it
  3136.                 // else there must be already existing partition: mark it
  3137.         // with "delete = true"
  3138.  
  3139.         focusline = id;
  3140.  
  3141.         y2milestone( "delete part %1", part );
  3142.         /////////////////////////////////////////////////////
  3143.         // check if the partition can be deleted
  3144.  
  3145.         if( part["type"]:`primary == `extended &&
  3146.             !check_extended_delete( disk, Stage::initial() ))
  3147.             {
  3148.             ret = `again;
  3149.             continue;
  3150.             }
  3151.         if( part["type"]:`primary != `extended &&
  3152.             !check_device_delete( part, bsd_label, Stage::initial()))
  3153.             {
  3154.             ret = `again;
  3155.             continue;
  3156.             }
  3157.  
  3158.         /////////////////////////////////////////////////////
  3159.         // now delete partition!!
  3160.  
  3161.                 // YesNo popup text, %1 is replaced by a device name e.g. /dev/hda1
  3162.         if( Popup::YesNo( sformat(_("Really delete %1?"),
  3163.                                     part["device"]:"" )))
  3164.             {
  3165.             if( search( id, "/dev/loop")==0 && size(part["fpath"]:"")>0 &&
  3166.             Mode::normal() &&
  3167.             // YesNo popup.  %1 is path to a file
  3168.             Popup::YesNo( sformat(_("\nShould the loop file %1 also be removed?
  3169. "), part["fpath"]:"" )))
  3170.             {
  3171.             Storage::DeleteLoop( disk["device"]:"",
  3172.                                  part["fpath"]:"", true );
  3173.             }
  3174.             else
  3175.             {
  3176.             Storage::DeleteDevice( disk["device"]:"",
  3177.                            part["device"]:"" );
  3178.             }
  3179.             focusline = Storage::GetIdSmaller( disk["device"]:"",
  3180.                                                part["nr"]:0 );
  3181.             }
  3182.         if( search( id, "/dev/md" )==0  )
  3183.             {
  3184.             map raid = Storage::GetDisk( Storage::GetTargetMap(), "/dev/md" );
  3185.             UI::ReplaceWidget( `id(`raid_button),
  3186.                        RaidButton(size(raid["partitions"]:[])) );
  3187.             }
  3188.         else if( search( id, "/dev/loop" )==0  )
  3189.             {
  3190.             map dev = Storage::GetDisk( Storage::GetTargetMap(), "/dev/loop" );
  3191.             UI::ReplaceWidget( `id(`loop_button),
  3192.                        LoopButton(size(dev["partitions"]:[])) );
  3193.             }
  3194.         }
  3195.         }
  3196.  
  3197.  
  3198.         /////////////////////////////////////////////////////////////
  3199.         // RESIZE
  3200.         /////////////////////////////////////////////////////////////
  3201.         if (ret == `resize)
  3202.         {
  3203.         string id = (string)UI::QueryWidget(`id(`table), `CurrentItem);
  3204.         focusline = id;
  3205.         map part = $[];
  3206.         map disk = Storage::GetDisk( tg, id );
  3207.         if( !haskey( tg, id ) )
  3208.         part = Storage::GetPartition( tg, id );
  3209.  
  3210.         if( disk["readonly"]:false )
  3211.         {
  3212.         Popup::Error( Partitions::RdonlyText( disk["device"]:"", true ));
  3213.         ret = `again;
  3214.         continue;
  3215.         }
  3216.  
  3217.         y2milestone( "disk=%1", disk );
  3218.         y2milestone( "RESIZE id=%1 part=%2", id, part );
  3219.         map possible = Storage::IsResizable( part );
  3220.         if( size(part)==0 ||
  3221.         part["used_by_type"]:`UB_NONE == `UB_LVM ||
  3222.         part["used_by_type"]:`UB_NONE == `UB_MD ||
  3223.             part["type"]:`unknown == `sw_raid ||
  3224.             part["type"]:`unknown == `loop ||
  3225.             part["type"]:`unknown == `dm )
  3226.         {
  3227.                 // popup text
  3228.         Popup::Message(_("
  3229. You cannot resize a disk device, LVM volume group, LVM physical volume,
  3230. or MD device.
  3231. "));
  3232.         }
  3233.         else if( !part["format"]:false &&
  3234.             !possible["extend"]:false && !possible["shrink"]:false )
  3235.         {
  3236.                 // popup text
  3237.         Popup::Message(_("
  3238. You cannot resize the selected partition because the file system
  3239. on this partition does not support resizing.
  3240. "));
  3241.                 }
  3242.         else if( part["type"]:`unknown == `lvm )
  3243.         {
  3244.         HandleEditLv( tg, id );
  3245.         }
  3246.         else
  3247.         {
  3248.         map new_val = part;
  3249.         if( Mode::normal() && new_val["used_fs"]:`none == `ntfs )
  3250.             {
  3251.             Package::InstallAll( ["ntfsprogs"] );
  3252.             }
  3253.         string dev = new_val["device"]:"";
  3254.         if( new_val["ori_nr"]:0 > 0 &&
  3255.             new_val["ori_nr"]:0 != new_val["nr"]:0 )
  3256.             {
  3257.             dev = Storage::GetDeviceName( disk["device"]:"", new_val["ori_nr"]:0 );
  3258.             }
  3259.         new_val = ResizePartDlg( new_val, dev, disk, possible );
  3260.         if( new_val != nil )
  3261.             {
  3262.             integer size_change = part["region",1]:0 -
  3263.                               new_val["region",1]:0;
  3264.             y2milestone( "region old=%1 new:%2", part["region"]:[],
  3265.                          new_val["region"]:[] );
  3266.             y2milestone( "size_change=%1", size_change );
  3267.             tg = Storage::SetPartition( tg, new_val );
  3268.             Storage::SetTargetMap(tg);
  3269.             if( size_change != 0 &&
  3270.                 Storage::CheckNextCreated( disk,
  3271.                                        part["region"]:[0,0] ))
  3272.             {
  3273.             if( size_change < 0 )
  3274.                 {
  3275.                 // popup text
  3276.                 Popup::Message( _("
  3277. You decreased the size available for Linux partitions.
  3278. Linux partition sizes have been adapted accordingly.
  3279. Check the new sizes in the partition list.
  3280. "));
  3281.                             Storage::AdaptResize( disk["device"]:"",
  3282.                                       part["region"]:[0,0],
  3283.                           size_change );
  3284.                 }
  3285.             // popup text
  3286.             else if( Popup::YesNo( _("
  3287. You decreased a partition that is followed by a newly-created partition.
  3288. Should the newly-created partition be automatically increased to use the
  3289. freed disk space?
  3290. ")) )
  3291.                 {
  3292.                             Storage::AdaptResize( disk["device"]:"",
  3293.                                       part["region"]:[0,0],
  3294.                           size_change );
  3295.                 }
  3296.             }
  3297.             }
  3298.         }
  3299.         }
  3300.  
  3301.     boolean ask_reread = true;
  3302.  
  3303.         /////////////////////////////////////////////////////////////
  3304.         // Delete partition table and disk label
  3305.         /////////////////////////////////////////////////////////////
  3306.  
  3307.         if( ret == `delete_parttable )
  3308.         {
  3309.         string ddev = ChooseDisk( tg,
  3310.                       // heading text
  3311.                                   _("Delete Partition Table"), `delete );
  3312.         // not cancel
  3313.         if( ddev != nil )
  3314.         {
  3315.         DDZeroPartitionTable(ddev);
  3316.         }
  3317.         }
  3318.  
  3319.     if( Arch::s390 () && ret==`dasdfmt )
  3320.         {
  3321.         string id = (string)UI::QueryWidget(`id(`table), `CurrentItem);
  3322.         map disk = tg[id]:$[];
  3323.  
  3324.         y2milestone( "dasdfmt disk:%1", id );
  3325.  
  3326.         if( haskey( tg, id ) && search( id, "/dev/dasd")==0 )
  3327.         {
  3328.         if( !disk["dasdfmt"]:false)
  3329.             {
  3330.             // popup text %1 is replaced by a dasd name e.g. /dev/dasda
  3331.             boolean yn = Popup::YesNo(sformat(
  3332. _("Running dasdfmt deletes all data on the disk.
  3333. Really execute dasdfmt on disk %1?
  3334. "),id));
  3335.             y2milestone( "yn=%1", yn );
  3336.             if( yn )
  3337.             {
  3338.             Storage::InitializeDisk( id, true );
  3339.             }
  3340.             }
  3341.         else
  3342.             {
  3343.             Popup::Message( _("The disk is no longer marked for dasdfmt.
  3344.  
  3345. Partitions currently present on this disk are again
  3346. displayed.
  3347. ") );
  3348.             Storage::InitializeDisk( id, false );
  3349.             }
  3350.         }
  3351.         else
  3352.         {
  3353.         // popup text
  3354.         Popup::Error( _("No DASD disk selected.
  3355. Select the DASD disk on which dasdfmt should be executed."));
  3356.         }
  3357.         }
  3358.  
  3359.  
  3360.         /////////////////////////////////////////////////////////////
  3361.         // REREAD
  3362.         /////////////////////////////////////////////////////////////
  3363.  
  3364.         if (ret == `reread)
  3365.         {
  3366.         boolean ret2 = true;
  3367.  
  3368.         if( ask_reread )
  3369.         // popup text
  3370.         ret2 = Popup::YesNo(_("Rereading the partition table cancels all current changes. Really reread the partition table?"));
  3371.  
  3372.         if( ret2 )
  3373.         {
  3374.         Storage::ReReadTargetMap();
  3375.         }
  3376.         }
  3377.  
  3378.  
  3379.     /////////////////////////////////////////////////////////////
  3380.         // Raid
  3381.         /////////////////////////////////////////////////////////////
  3382.  
  3383.         if( ret == `raid_wizard )
  3384.         {
  3385.         if( !check_raid_possible( tg ))
  3386.             {
  3387.         ret = `again;
  3388.         continue;
  3389.         }
  3390.         }
  3391.  
  3392.     if( ret == `loop_edit || ret == `loop_create )
  3393.         {
  3394.         string id = (string)UI::QueryWidget( `id(`table), `CurrentItem );
  3395.         Storage::SetWizardKey( id );
  3396.         if( ret == `loop_edit )
  3397.         {
  3398.         if( search( id, "/dev/loop" )!=0 )
  3399.             {
  3400.             // popup text
  3401.             Popup::Message( _("Select a loop device entry.") );
  3402.             ret = `again;
  3403.             continue;
  3404.             }
  3405.         }
  3406.         LoopSetup( ret==`loop_edit );
  3407.         if( ret==`loop_create )
  3408.         {
  3409.         map dev = Storage::GetDisk( Storage::GetTargetMap(), "/dev/loop" );
  3410.         UI::ReplaceWidget( `id(`loop_button),
  3411.                    LoopButton(size(dev["partitions"]:[])) );
  3412.         }
  3413.         }
  3414.  
  3415.     /////////////////////////////////////////////////////////////
  3416.         // LVM
  3417.         /////////////////////////////////////////////////////////////
  3418.  
  3419.         if (ret == `lvm)
  3420.         {
  3421.         if( !check_lvm_possible( tg ) )
  3422.         {
  3423.         ret = `again;
  3424.         continue;
  3425.         }
  3426.         else if( Mode::normal () )
  3427.         {
  3428.         Package::InstallAll( ["lvm2"] );
  3429.         }
  3430.         }
  3431.  
  3432.     /////////////////////////////////////////////////////////////
  3433.         // Adapt mount points from existing /etc/fstab
  3434.         /////////////////////////////////////////////////////////////
  3435.  
  3436.         if (ret == `adapt_mp && Stage::initial() )
  3437.         {
  3438.         map<string,map> od = (map<string,map>)Storage::GetOndiskTarget();
  3439.         list<list> fstab = scanAndReadExistingFstab( od );
  3440.         y2milestone( "adapt_mp fstab %1", fstab );
  3441.         list ti = maplist( list e, fstab,
  3442.                            ``(AddFstabToData( od, (list<map>)e)[1]:$[]));
  3443.         y2milestone( "adapt_mp ti %1", ti );
  3444.  
  3445.         integer idx = FstabAddDialog( ti );
  3446.         if( idx>=0 )
  3447.         {
  3448.         od = (map<string,map>)Storage::GetOndiskTarget();
  3449.         y2milestone( "adapt_mp use fstab idx %1", idx );
  3450.         ti = AddFstabToData( od, (list<map>)fstab[idx]:[] );
  3451.         Storage::ResetOndiskTarget();
  3452.         foreach( string d, map disk, ti[0]:$[],
  3453.             ``{
  3454.             foreach( map p, disk["partitions"]:[],
  3455.             ``{
  3456.             if( size(p["mount"]:"")>0 && p["enc_type"]:`none!=`none )
  3457.                 {
  3458.                 string pwd = DlgCreateCryptFs( p["device"]:"", 5, false );
  3459.                 if( pwd != nil && size(pwd)>0 )
  3460.                 Storage::SetCryptPwd( p["device"]:"", pwd );
  3461.                 }
  3462.             });
  3463.             });
  3464.         Storage::SetTargetMap( ti[0]:$[] );
  3465.         }
  3466.         }
  3467.  
  3468.         /////////////////////////////////////////////////////////////
  3469.         // End of Actions, Now check the returncode
  3470.         /////////////////////////////////////////////////////////////
  3471.  
  3472.         if (ret == `next || ret == `back || ret == `raid || ret == `lvm ||
  3473.         ret == `raid_settings || ret == `raid_wizard || ret == `evms )
  3474.         {
  3475.             symbol doagain = `next;
  3476.  
  3477.         if( ret == `raid_wizard || ret == `raid_settings )
  3478.         {
  3479.         if( Storage::CheckBackupState("raid"))
  3480.             Storage::DisposeTargetBackup("raid");
  3481.         }
  3482.  
  3483.         if( ret == `back &&
  3484.         !Storage::EqualBackupStates( "custom_part", "", true ))
  3485.         {
  3486.         // popup text %1 will be replaces with button text
  3487.         string txt = sformat( _("You have changed the partitioning.
  3488. These changes are lost if you exit the main dialog with %1.
  3489. Really quit the main dialog?
  3490. "),
  3491.                       deletechars(back_label,"&") );
  3492.         if( !Popup::YesNo( txt ))
  3493.             {
  3494.             doagain = `again;
  3495.             }
  3496.         }
  3497.         if( ret == `next )
  3498.         {
  3499.         boolean changed =
  3500.             !Storage::EqualBackupStates( "custom_part", "", true );
  3501.         y2milestone( "CheckNext ret=%1 changed=%2", ret, changed );
  3502.         if( changed )
  3503.             {
  3504.             Storage::SetPartMode( "CUSTOM" );
  3505.             }
  3506.         }
  3507.         if ( ret == `next )
  3508.         {
  3509.         list retval = check_created_partition_table( Storage::GetTargetMap(), true,
  3510.                                  Stage::initial()&&!Mode::repair() );
  3511.         Storage::SetTargetMap( retval[0]:$[] );
  3512.             doagain = retval[1]:`next;
  3513.         }
  3514.  
  3515.         if( (ret==`abort || ret==`back || ret==`next) && doagain!=`again )
  3516.         {
  3517.         Storage::DisposeTargetBackup("custom_part");
  3518.         }
  3519.  
  3520.         if( doagain == `again ) ret = `again;
  3521.  
  3522.             if( ret != `back )
  3523.         {
  3524.                 if (ret == `apply) return `again;
  3525.         }
  3526.         if( (ret == `back||ret==`abort) && Storage::GetPartMode()=="NORMAL" )
  3527.         {
  3528.         Storage::SetPartMode( "CUSTOM" );
  3529.         }
  3530.         }
  3531.  
  3532.     Storage::SetLastUsed( focusline );
  3533.  
  3534.     y2milestone( "end main loop ret %1 focusline %2", ret, focusline );
  3535.         } until (ret == `next || ret == `back || ret == `cancel ||
  3536.              ret == `raid_wizard || ret == `raid_settings ||
  3537.              ret == `evms ||
  3538.          ret == `lvm || ret == `lvmlv || ret == `abort );
  3539.  
  3540.   Wizard::RestoreNextButton();
  3541.   if( (ret == `lvm || ret == `raid_wizard || ret == `raid_settings ||
  3542.        ret == `evms) &&
  3543.       !Stage::initial () )
  3544.       {
  3545.       Wizard::RestoreBackButton();
  3546.       }
  3547.  
  3548.   Storage::SetExpertDetail( show_T_details );
  3549.   Storage::SaveExpertDetail();
  3550.  
  3551.  
  3552.   Wizard::RestoreHelp( help_text );
  3553.   SCR::Write(.target.ycp, Storage::SaveDumpPath("targetMap_e"),
  3554.              Storage::GetTargetMap() );
  3555.  
  3556.   //next by installation
  3557.   if( Stage::initial () && ret == `next )
  3558.       ret = `instnext;
  3559.  
  3560.   //next in existing system
  3561.   if( !Stage::initial () && ret == `next )
  3562.       ret = `sysnext;
  3563.  
  3564.   if( ret == `back )
  3565.       ret = `backtoi;
  3566.  
  3567.   if( ret == `raid_settings || ret == `raid_wizard )
  3568.       Storage::Record();
  3569.  
  3570.   return ret;
  3571.  
  3572. }
  3573.