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 / include / partitioning / evms_lib.ycp < prev    next >
Text File  |  2006-11-29  |  36KB  |  1,322 lines

  1. /**
  2.  * File:
  3.  *   evms_lib.ycp
  4.  *
  5.  * Module: 
  6.  *    utility functions for evms config
  7.  *
  8.  * Summary:
  9.  *
  10.  * Authors:
  11.  *   Thomas Fehr <fehr@suse.de>
  12.  *
  13.  *
  14.  * $Id: evms_lib.ycp 33366 2006-10-12 14:55:19Z fehr $
  15.  *
  16.  */
  17.  
  18.  
  19. {
  20.  
  21. textdomain "storage";
  22.  
  23. import "FileSystems";
  24. import "Storage";
  25. import "Mode";
  26.  
  27. include "partitioning/partition_defines.ycp";
  28.  
  29. //////////////////////////////////////////////////////////////////////
  30. // helptext for evms main dialog 
  31. //////////////////////////////////////////////////////////////////////
  32.  
  33. define string getEvmsHelptext()
  34.     ``{
  35.     string help_text = "";
  36.  
  37.  // helptext EVMS partitioning. 
  38.     help_text =  _("<p>The upper part of this dialog contains the container-related functionality. Here, create, edit, and modify EVMS containers. </p>");
  39.  
  40.     // helptext EVMS partitioning. 
  41.     help_text = help_text + _("<p>
  42. The lower part with the list contains all available EVMS devices.
  43. If at least one EVMS container is available, you can create new 
  44. devices that use the available space of the current container.</p>
  45. ");
  46.  
  47.     return( help_text );
  48.     };
  49.  
  50. //////////////////////////////////////////////////////////////////////
  51. // evms_pesize_check 
  52. // in: <number>[kKmM][bB]
  53. // 
  54. // return 0 if input is invalid
  55. // 
  56. // pesize is valid   8K to 512M in power of 2
  57. // 8 is 8k
  58. // 16K == 16k == 16KB == 16kb
  59.      
  60. define integer evms_pesize_check( string input, string type )
  61.     ``{
  62.     integer num = kmgt_str_to_byte( input );
  63.     if( findfirstnotof( input, "0123456789 " ) == nil )
  64.     num = num*1024;
  65.  
  66.     integer ret = num;
  67.  
  68.     if( ret % 1024 != 0 )
  69.     ret = 0;
  70.     else
  71.     {
  72.     while( num>1 && ret>0 )
  73.         {
  74.         if( num%2 != 0 )
  75.         ret = 0;
  76.         else
  77.         num = num/2;
  78.             }
  79.         }
  80.     y2milestone( "evms_pesize_check ret %1", ret );
  81.     if( ret < 8*1024 || ret > 512*1024*1024*1024 )
  82.         {
  83.         ret = 0;
  84.         }
  85.     y2milestone( "evms_pesize_check ret %1", ret );
  86.     if( ret==0 )
  87.     {
  88.     // error popup text
  89.     Popup::Error(_("The data entered is invalid.
  90. Insert a physical extent size from
  91. 8KB to 512GB in powers of 2, for example, 4M or 512K.
  92. "));
  93.     }
  94.     return( ret );
  95.     };
  96.  
  97. //////////////////////////////////////////////////////////////////////
  98. // checks if name is a valid container name 
  99. define boolean evms_check_name( string name )
  100.     ``{
  101.     if ( size( name ) == 0 ) return( false );
  102.     return( ( findfirstof( name, " ;/`'┬┤!,\"%#" ) == nil ) );
  103.     }
  104.  
  105. define string evms_dev_disk( string dev )
  106.     {
  107.     return( Storage::EvmsDevDisk( dev ));
  108.     }
  109.  
  110. define list<map> filter_deleted_parts( map<string,map> tg, list<map> plist )
  111.     ``{
  112.     list<map> ret = [];
  113.     foreach( map p, plist, 
  114.     ``{
  115.     if( search( p["device"]:"", "/dev/evms/" )==0 )
  116.         {
  117.         map disk = 
  118.         Storage::GetDiskPartition( evms_dev_disk( p["device"]:"" ));
  119.         if( size(filter( map pa, tg[disk["disk"]:"","partitions"]:[],
  120.                  ``(sformat("%1",pa["nr"]:(any)"")==
  121.                     sformat("%1",disk["nr"]:(any)0) &&
  122.                 pa["delete"]:false)))==0)
  123.         {
  124.         ret = add( ret, p );
  125.         }
  126.         }
  127.     else
  128.         {
  129.         ret = add( ret, p );
  130.         }
  131.     });
  132.     if( size(plist)!=size(ret) )
  133.     {
  134.     y2milestone( "filter_deleted_parts plist %1", plist );
  135.     y2milestone( "filter_deleted_parts ret %1", ret );
  136.     }
  137.     return( ret );
  138.     }
  139.  
  140. define list<map> filter_mounted_evms_part( map<string,map> tg, list<map> pa )
  141.     {
  142.     list<map> ret = filter( map p, pa,
  143.     ``{
  144.     boolean ok = p["evms_native"]:false;
  145.     if( !ok )
  146.         {
  147.         string dev = evms_dev_disk( p["device"]:"" );
  148.         map part = Storage::GetPartition( tg, dev );
  149.         ok = size(part["mount"]:"")==0;
  150.         }
  151.     return( ok );
  152.     });
  153.     return( ret );
  154.     }
  155.  
  156. define list<map> filter_used_disk_evms_part( map<string,map> tg, list<map> pa, string name )
  157.     {
  158.     boolean ok = false;
  159.     list<map> ret = filter( map p, pa,
  160.     ``{
  161.     string dev = evms_dev_disk( p["device"]:"" );
  162.     ok = tg[dev,"used_by_type"]:`UB_NONE == `UB_NONE ||
  163.          (tg[dev,"used_by_type"]:`UB_NONE == `UB_EVMS && 
  164.           tg[dev,"used_by"]:"" == name);
  165.     return( ok );
  166.     });
  167.     return( ret );
  168.     }
  169.  
  170. define list<map> get_pvlist( map<string,map> tg, string name )
  171.     ``{
  172.     list<map> pv = [];
  173.     y2milestone( "get_pvlist name %1", name );
  174.     foreach( string k, map e, tg,
  175.     ``{
  176.     if( e["type"]:`CT_UNKNOWN==`CT_EVMS )
  177.         {
  178.         if( !e["is_container"]:false )
  179.         {
  180.         list<map> tmp = filter( map p, e["partitions"]:[],
  181.                         ``(p["used_by_type"]:`UB_NONE==`UB_NONE ||
  182.                            (p["used_by_type"]:`UB_NONE==`UB_EVMS &&
  183.                         p["used_by"]:""==name)));
  184.         tmp = filter( map p, tmp, ``(size(p["mount"]:"")==0));
  185.         tmp = filter_mounted_evms_part( tg, tmp );
  186.         tmp = filter_used_disk_evms_part( tg, tmp, name );
  187.         y2milestone( "key %1 tmp %2", k, tmp );
  188.         pv = (list<map>)merge( pv, tmp );
  189.         }
  190.         }
  191.     else
  192.         {
  193.         y2milestone( "get_pvlist key %1 disk %2", k, e );
  194.         list<map> tmp = filter( map p, e["partitions"]:[],
  195.                     ``(size(name)>0 &&
  196.                        p["used_by_type"]:`UB_NONE==`UB_EVMS &&
  197.                        p["used_by"]:""==name ));
  198.         tmp = (list<map>)merge( tmp,
  199.                     filter( map p, e["partitions"]:[],
  200.                         ``(p["type"]:`primary != `extended &&
  201.                            size(p["mount"]:"")==0 &&
  202.                            p["used_by_type"]:`UB_NONE==`UB_NONE)));
  203.         y2milestone( "get_pvlist tmp %1", tmp );
  204.         y2milestone( "key %1 tmp %2", k, tmp );
  205.         pv = (list<map>)merge( pv, tmp );
  206.         }
  207.     });
  208.     pv = maplist( map p, pv, 
  209.     ``{
  210.     string d = substring( p["device"]:"", 5 );
  211.     if( search( d, "evms/" )==0 )
  212.         {
  213.         d = substring( d, 5 );
  214.         }
  215.     p["device"] = d;
  216.     return( p );
  217.     });
  218.     pv = filter( map p, pv, ``(search(p["device"]:"","md/md")!=0));
  219.     pv = sort( map a, map b, pv, ``(a["device"]:""<b["device"]:""));
  220.     y2milestone( "pv %1", pv );
  221.     string pdev = "";
  222.     pv = filter( map p, pv, 
  223.     ``({
  224.     boolean r = false;
  225.     if( pdev!=p["device"]:"" )
  226.         {
  227.         pdev = p["device"]:"";
  228.         r = true;
  229.         }
  230.     return( r );
  231.     }));
  232.     y2milestone( "unique %1", pv );
  233.     return( pv );
  234.     }
  235.  
  236. define list<term> get_table_entries( list<map> pvlist, string name )
  237.     ``{
  238.     y2milestone( "get_table_entries name %1", name );
  239.     integer count=-1;
  240.     list<term> ret = maplist( map p, pvlist,
  241.     ``{
  242.     count = count+1;
  243.     return( `item( `id(count), p["device"]:"", 
  244.             ByteToHumanStringWithZero(p["size_k"]:0*1024),
  245.             size(p["used_by"]:"")>0?" "+name:"" ));
  246.     });
  247.     y2milestone( "get_table_entries ret %1", ret );
  248.     return( ret );
  249.     }
  250.  
  251. define integer evms_usable_size( integer siz, integer pesize )
  252.     ``{
  253.     integer r = siz - 128*1024;
  254.     r = (r/pesize)*pesize;
  255.     if( r < 0 ) r = 0;
  256.     return( r );
  257.     }
  258.  
  259. define integer get_container_size( map co, list pvlist )
  260.     ``{
  261.     integer ret = co["size_k"]:0 * 1024;
  262.     y2milestone( "get_container_size ret %1", ret );
  263.     return( ret );
  264.     }
  265.  
  266. define void set_container_size( map co, integer new_size )
  267.     ``{
  268.     string s = ByteToHumanStringWithZero( new_size );
  269.     UI::ChangeWidget( `id(`size), `Value, s );
  270.     UI::RecalcLayout();
  271.     }
  272.  
  273. define list get_index_list( list<string> l, list pvlist )
  274.     ``{
  275.     list nl = [];
  276.     foreach( string e, l,
  277.     ``{
  278.     integer i=0;
  279.     while( i<size(pvlist) && pvlist[i,"device"]:""!=e )
  280.         {
  281.         i = i+1;
  282.         }
  283.     if( i<size(pvlist) )
  284.         {
  285.         nl = add( nl, i );
  286.         }
  287.     });
  288.     y2milestone( "get_index_list l %1 ret %2", l, nl );
  289.     return( nl );
  290.     }
  291.  
  292. define void set_table_elements( list<term> entries, integer id )
  293.     ``{
  294.     if( id < 0 )
  295.     {
  296.     id = (integer) UI::QueryWidget( `id(`pv_table), `CurrentItem );
  297.     }
  298.     UI::ChangeWidget( `id(`pv_table), `Items, entries );
  299.     UI::ChangeWidget( `id(`pv_table), `CurrentItem, id );
  300.     }
  301.  
  302. define map dlg_modify_container( map<string,map> tg, map<string,any> co, 
  303.                                  boolean create )
  304.     ``{
  305.     string old_name = co["name"]:"";
  306.     integer old_pesize = co["pesize"]:0;
  307.     // popup header
  308.     string head = _("Modify Existing EVMS Container");
  309.     if( co["create"]:false )
  310.     {
  311.     if( create )
  312.         {
  313.         // popup header
  314.         head = _("Create EVMS Container");
  315.         }
  316.     else
  317.         {
  318.         // popup header
  319.         head = _("Modify EVMS Container");
  320.         }
  321.     }
  322.     string txt =
  323.           // popup description
  324. _("Change the settings for an EVMS container.
  325. Container type, PE size, and container name can only be set when creating
  326. the container.
  327. ");
  328.  
  329.     term dlg = 
  330.     `HBox(
  331.         `HSpacing(2),
  332.         `VBox(
  333.           `Heading(head),
  334.           `Label( txt ),
  335.           // label text
  336.           `HBox(
  337.               `HSpacing(1),
  338.               `ComboBox( `id(`type), `opt(`notify), _("Container Type"),
  339.                               // label text
  340.                      [ `item( `id("lvm"), _("Linux LVM") ),
  341.                               // label text
  342.                    `item( `id("lvm2"), _("Linux LVM2") )] ),
  343.               
  344.               `HSpacing(2),
  345.               // label text
  346.               `TextEntry( `id(`name), `opt(`notify), 
  347.                           _("Container &Name"), co["name"]:"" ),
  348.               `HSpacing(2),
  349.               // label text
  350.               `TextEntry(`id(`pesize), _("&Physical Extent Size"), ""),
  351.               `HSpacing(1)
  352.               ),
  353.           `Left(`HBox( 
  354.               `HSpacing(1),
  355.               `Label( _("Container Size:") ),
  356.               `Label( `id(`size), "" ),
  357.               `HSpacing(1)
  358.                )),
  359.           `VSpacing(1),
  360.           `HBox( 
  361.               `HSpacing(2),
  362.               `VBox(
  363.               `HBox( 
  364.                   `Table(`id(`pv_table), `opt(`notify),
  365.                      // header text
  366.                      `header(_("Device"), `Right(_(" Size")), 
  367.                          // header text
  368.                          _(" Container")),
  369.                      [] ),
  370.                   `VSpacing(10)
  371.                   ),
  372.               `VSpacing(1),
  373.               `HBox(
  374.                   // button text
  375.                   `PushButton(`id(`pv_add), _("&Add Volume")),
  376.                   // button text
  377.                   `PushButton(`id(`pv_remove), _("&Remove Volume"))
  378.                   )
  379.               ),
  380.               `HSpacing(2)
  381.               ),
  382.           `VSpacing(1),
  383.           `HBox(
  384.               // Ok button
  385.               `PushButton(`id(`ok), `opt(`default), Label::OKButton() ),
  386.               // Cancel button
  387.               `PushButton(`id(`cancel), Label::CancelButton() )
  388.                ),
  389.           `VSpacing(0.5)
  390.          ),
  391.         `HSpacing(2)
  392.         );
  393.  
  394.     UI::OpenDialog( `opt(`decorated ), dlg );
  395.  
  396.     string name = co["name"]:"";
  397.     string typename = co["lvm2"]:false?"lvm2":"lvm";
  398.  
  399.     if( search( name, "aix/" )==0 )
  400.     {
  401.     typename = "aix";
  402.     }
  403.  
  404.     UI::ChangeWidget( `id(`name), `Value, Storage::EvmsShortName(name) );
  405.     if( create )
  406.     {
  407.     UI::ChangeWidget( `id(`name), `ValidChars, 
  408.                       FileSystems::nchars + "-._:" );
  409.     }
  410.     else
  411.     {
  412.     UI::ChangeWidget( `id(`name), `Enabled, false );
  413.     }
  414.     UI::ChangeWidget( `id(`pesize), `Enabled, co["create"]:false );
  415.     UI::ChangeWidget( `id(`type), `Enabled, create );
  416.     UI::ChangeWidget( `id(`pesize), `Value, 
  417.                       ByteToHumanStringWithZero(co["pesize"]:0 ));
  418.     UI::ChangeWidget( `id(`type), `Value, typename );
  419.  
  420.     list<map> pvlist = get_pvlist( tg, co["name"]:"" );
  421.     y2milestone( "dlg_modify_container pvlist %1", pvlist );
  422.     y2milestone( "dlg_modify_container co %1", co );
  423.     set_table_elements( get_table_entries( pvlist, co["name"]:"" ), 0 );
  424.     integer cur_size = co["size_k"]:0 * 1024;
  425.     set_container_size( co, cur_size );
  426.     symbol ret = nil;
  427.  
  428.     repeat
  429.     {
  430.     ret = (symbol)UI::UserInput();
  431.  
  432.     y2milestone( "dlg_modify_container ret %1", ret );
  433.  
  434.     if( ret == `type )
  435.         {
  436.         typename  = (string)UI::QueryWidget(`id(`type), `Value );
  437.         name = typename + "/" + Storage::EvmsShortName(name);
  438.         co["name"] = name;
  439.         set_table_elements( get_table_entries( pvlist, name ), -1 );
  440.         }
  441.     else if( ret == `name )
  442.         {
  443.         name = (string)UI::QueryWidget(`id(`name), `Value );
  444.         name = deletechars( name, " \t" );
  445.         y2milestone( "dlg_modify_container new name:%1", name );
  446.         name = typename + "/" + name;
  447.         co["name"] = name;
  448.         set_table_elements( get_table_entries( pvlist, name ), -1 );
  449.         }
  450.     else if( contains( [`pv_add, `pv_remove, `pv_table ], ret ) )
  451.         {
  452.         integer id = (integer)UI::QueryWidget(`id(`pv_table), `CurrentItem);
  453.         if( ret == `pv_table && id != nil )
  454.         {
  455.         ret = size(pvlist[id,"used_by"]:"")>0?`pv_remove:`pv_add;
  456.         }
  457.         if( ret == `pv_add && id != nil && 
  458.             size(pvlist[id,"used_by"]:"")==0 )
  459.         {
  460.         name = co["name"]:"";
  461.         string dev = "/dev/" + pvlist[id,"device"]:"";
  462.         if( size(Storage::GetPartition(tg,dev))==0 )
  463.             dev = "/dev/evms/" + pvlist[id,"device"]:"";
  464.         y2milestone( "dev:%1", dev );
  465.         Storage::SetPartitionMount( dev, "" );
  466.         Storage::SetPartitionFormat( dev, false, `none );
  467.         Storage::ExtendEvmsCo( old_name, pvlist[id,"device"]:"" );
  468.         tg = Storage::GetTargetMap();
  469.         co = (map<string,any>)tg["/dev/evms/"+old_name]:$[];
  470.         co["name"] = name;
  471.         y2milestone( "co: %1", co );
  472.         pvlist = get_pvlist( tg, old_name );
  473.         cur_size = co["size_k"]:0*1024;
  474.         set_container_size( co, cur_size );
  475.         set_table_elements( get_table_entries( pvlist, name ), id );
  476.         }
  477.         else if( ret == `pv_remove && id != nil && 
  478.              size(pvlist[id,"used_by"]:"")>0 )
  479.         {
  480.         name = co["name"]:"";
  481.         boolean changed = 
  482.             Storage::ReduceEvmsCo( old_name, pvlist[id,"device"]:"" );
  483.         if( !changed )
  484.             {
  485.             // message popup
  486.             Popup::Error(
  487. _("If you remove the selected partition from the container,
  488. there will not be enough space for all volumes in this container.
  489. To delete the container completely, remove its volumes first."));
  490.             }
  491.         else
  492.             {
  493.             tg = Storage::GetTargetMap();
  494.             co = (map<string,any>)tg["/dev/evms/"+old_name]:$[];
  495.             co["name"] = name;
  496.             y2milestone( "co: %1", co );
  497.             pvlist = get_pvlist( tg, old_name );
  498.             cur_size = co["size_k"]:0*1024;
  499.             set_container_size( co, cur_size );
  500.             set_table_elements( get_table_entries( pvlist, name ), id );
  501.             }
  502.         }
  503.         }
  504.     else if( ret == `ok )
  505.         {
  506.         co["pesize"] = 
  507.         evms_pesize_check( (string)UI::QueryWidget( `id(`pesize), 
  508.                                                     `Value),
  509.                    typename );
  510.  
  511.         y2milestone( "dlg_modify_container co %1 type %2", co, typename );
  512.  
  513.         if( co["pesize"]:0 == 0 )
  514.             {
  515.         ret = `again;
  516.         }
  517.  
  518.         if( ret==`ok && !evms_check_name(Storage::EvmsShortName(name)) )
  519.         {
  520.         // error popup text
  521.         Popup::Error(_("The data entered is invalid.
  522. Insert a container names like \"system\" or \"test\".
  523. Do not use ;/`, in this name.
  524. "));
  525.         ret = `again;
  526.         }
  527.       
  528.         if( ret==`ok && co["create"]:false && old_name!=co["name"]:"" &&
  529.             (haskey( tg, "/dev/evms/" + co["name"]:"" ) ||
  530.              haskey( tg, "/dev/" + name )) )
  531.         {
  532.         // error popup text
  533.         Popup::Error(sformat(_("The container named \"%1\" already exists.
  534. Choose a different name
  535. or cancel this dialog.
  536. "), name ));
  537.         ret = `again;
  538.         }
  539.  
  540.         if( cur_size <= 0 )
  541.         {
  542.         // error popup text
  543.         Popup::Error(_("The container contains no physical volume.
  544. Every container must consist of at least one physical volume."));
  545.         ret = `again;
  546.         }
  547.         if( old_name!=co["name"]:"" || old_pesize!=co["pesize"]:0 )
  548.         {
  549.         name = co["name"]:"";
  550.         y2milestone( "name old:%1 new:%2 pe old:%3 new:%4",
  551.                      old_name, name, old_pesize, co["pesize"]:0 );
  552.         Storage::ModifyEvmsCo( old_name, Storage::EvmsShortName(name),
  553.                        co["pesize"]:0, 
  554.                        search(name,"lvm2/")==0 );
  555.         }
  556.         }
  557.     } until( ret == `ok || ret == `cancel );
  558.  
  559.     UI::CloseDialog();
  560.  
  561.     map r = $["ok":false];
  562.          
  563.     if (ret == `ok )
  564.     {
  565.     r["ok"] = true;
  566.     r["name"] = co["name"]:"";
  567.     y2milestone( "dlg_modify_container ret co %1", co );
  568.     }
  569.     y2milestone( "dlg_modify_container ret ok %1", r["ok"]:false );
  570.     return( r );
  571.     };
  572.  
  573. define map add_evms_container( map<string,map> tg )
  574.     ``{
  575.     map ret = $[ "ok":false ];
  576.     string name = "";
  577.     list<string> l = maplist( string k, map entry, 
  578.                               filter( string key, map e, tg,
  579.                           ``(e["type"]:`CT_UNKNOWN==`CT_EVMS &&
  580.                          size(e["name"]:"")>0)),
  581.                   ``(entry["name"]:""));
  582.     y2milestone( "add_evms_container l:%1", l );
  583.     if( size(l)==0 )
  584.     name = "lvm2/system";
  585.     else
  586.     {
  587.     integer num = size(l)+1;
  588.     name = sformat( "lvm2/co%1", num );
  589.     while( size(filter( string s, l, 
  590.                         ``{
  591.                 integer ret=search(s,substring(name,4));
  592.                 return( ret!=nil && ret>0 );
  593.                 }
  594.                 ))>0 )
  595.         {
  596.         num = num+1;
  597.         name = sformat( "lvm2/co%1", num );
  598.         }
  599.     }
  600.     map<string,any> co = 
  601.     $[ "size_k" : 0,
  602.        "pesize" : 4 * 1024 * 1024,
  603.        "create" : true,
  604.        "type" : `CT_EVMS,
  605.        "is_container" : true,
  606.        "name" : name,
  607.        "lvm2" : true,
  608.        "partitions" : []
  609.     ];
  610.  
  611.     if( Storage::CreateEvmsCo( co["name"]:"", co["pesize"]:1024, 
  612.                                co["lvm2"]:false ))
  613.     {
  614.     ret = dlg_modify_container( tg, co, true );
  615.     if( !ret["ok"]:false )
  616.         {
  617.         Storage::DeleteEvmsCo( co["name"]:"" );
  618.         }
  619.     }
  620.     y2milestone( "add_evms_container ret:%1", ret );
  621.     return( ret );
  622.     };
  623.  
  624. define map edit_evms_container( map<string,map> tg, string key )
  625.     ``{
  626.     map ret = $[ "ok":false ];
  627.     y2milestone( "edit_evms_container key %1", key );
  628.     map<string,any> co = (map<string,any>)tg["/dev/evms/"+key]:$[];
  629.     co["name"] = key;
  630.     ret = dlg_modify_container( tg, co, false );
  631.     y2milestone( "edit_evms_container ret:%1", ret );
  632.     return( ret );
  633.     };
  634.  
  635. define map remove_evms_container( map<string,map> tg, string key )
  636.     ``{
  637.     y2milestone( "remove_evms_container key %1", key );
  638.     string mkey = "/dev/evms/"+key;
  639.     map ret = $["ok":false];
  640.     map co = tg[mkey]:$[];
  641.     if( size(co["partitions"]:[])>0 )
  642.     {
  643.     // Message popup
  644.     Popup::Message(sformat(
  645. _("The container \"%1\" contains at least one volume.
  646. It cannot be removed. Remove all volumes of this container
  647. before removing the container"), key ));
  648.     }
  649.     else
  650.     {
  651.     // popup text
  652.     if( Popup::ContinueCancel( sformat( _("Really remove container \"%1\"?"), key)))
  653.         {
  654.         Storage::DeleteEvmsCo( co["name"]:"" );
  655.         ret["ok"] = true;
  656.         }
  657.     }
  658.     y2milestone( "remove_evms_container ret:%1", ret );
  659.     return( ret );
  660.     }
  661.  
  662.  
  663. //////////////////////////////////////////////////////////////////////
  664. // show a new list of containers
  665. //////////////////////////////////////////////////////////////////////
  666.  
  667. define void new_co_list( list co_list )
  668.     ``{
  669.     UI::ReplaceWidget(`id(`rcont), `ComboBox(`id(`cont), `opt(`notify),
  670.               // button text
  671.               _("EVMS &Container"), co_list ));
  672.     };
  673.  
  674. define integer get_co_size( map co )
  675.     ``{
  676.     integer sum_byte = co["size_k"]:0 * 1024;
  677.     return( sum_byte );
  678.     }
  679.  
  680. define void new_co_size( map co )
  681.     ``{
  682.     integer total = get_co_size(co);
  683.     integer free = co["pe_free"]:0 * co["pesize"]:0;
  684.     y2milestone( "total %1 free %2", total, free );
  685.     string total_s = ByteToHumanStringWithZero( total );
  686.     string free_s = ByteToHumanStringWithZero( free );
  687.     UI::ChangeWidget( `id(`co_size), `Value, total_s );
  688.     UI::ChangeWidget( `id(`co_free), `Value, free_s );
  689.     if( UI::WidgetExists( `id(`co_graph)) )
  690.     {
  691.     UI::ChangeWidget( `id(`co_graph), `Labels,
  692.                       // e.g. %1 is replaced with a size e.g.. "used 5 GB"
  693.               [ sformat( _("used\n%1"), 
  694.                      ByteToHumanStringWithZero(total-free)),
  695.                       // e.g. %1 is replaced with a size e.g.. "free 1 GB"
  696.                 sformat( _("free\n%1"), free_s ) ] );
  697.     UI::ChangeWidget( `id(`co_graph), `Values, [ (total-free)/1024/1024, 
  698.                                                   free/1024/1024 ] );
  699.     }
  700.     UI::RecalcLayout();
  701.     }
  702.  
  703. define term get_bargraph_if_possible()
  704.     ``{
  705.     term ret = `Empty();
  706.     if( UI::HasSpecialWidget( `BarGraph ))
  707.         {
  708.         ret = `Left(`BarGraph( `id(`co_graph), `opt(`hstretch),
  709.                                [ 0, 10 ], [ "", ""]) );
  710.         }
  711.     y2milestone( "get_bargraph_if_possible ret %1", ret );
  712.     return( ret );
  713.     };
  714.  
  715. define map get_co_map( string current, map tg )
  716.     ``{
  717.     return( tg["/dev/evms/"+current]:$[] );
  718.     }
  719.  
  720. define list get_containers( map<string,map> tg, string none )
  721.     ``{
  722.     list ret = [];
  723.     foreach( string k, map e, tg, 
  724.     ``{
  725.     if( e["is_container"]:false )
  726.         {
  727.         ret = add( ret, substring( k, 10 ));
  728.         }
  729.     });
  730.     if( size(ret)==0 )
  731.     {
  732.     ret = [ none ];
  733.     }
  734.     y2milestone( "get_containers ret %1", ret );
  735.     return( ret );
  736.     }
  737.  
  738. define list get_evms_volumes( map<string,map> tg )
  739.     ``{
  740.     list<string> tmp = [];
  741.     foreach( string k, map e, tg,
  742.     ``{
  743.     if( search( k, "/dev/evms" )==0 && !e["is_container"]:false )
  744.         {
  745.         tmp = add( tmp, k );
  746.         foreach( map p, e["partitions"]:[], ``(y2milestone( "get_evms_volumes p:%1", p )));
  747.         }
  748.     });
  749.     list<string> keys = sort( tmp );
  750.     tmp = [];
  751.     foreach( string k, map e, tg,
  752.     ``{
  753.     if( search( k, "/dev/evms" )==0 && e["is_container"]:false )
  754.         {
  755.         tmp = add( tmp, k );
  756.         foreach( map p, e["partitions"]:[], ``(y2milestone( "p:%1", p )));
  757.         }
  758.     });
  759.     keys = (list<string>)merge( keys, sort(tmp) );
  760.     list<map> parts = [];
  761.     y2milestone( "get_evms_volumes keys %1", keys );
  762.     foreach( string k, keys,
  763.     ``{
  764.     list<map> pa = 
  765.         filter( map p, tg[k,"partitions"]:[], 
  766.             ``(p["used_by_type"]:`UB_NONE==`UB_NONE));
  767.     pa = filter( map p, pa, 
  768.         ``{
  769.         string ndev = evms_dev_disk( p["device"]:"" );
  770.         return( !Storage::IsRealDisk( tg[ndev]:$[] ));
  771.         });
  772.     pa = filter_deleted_parts( tg, pa );
  773.     if( k=="/dev/evms" )
  774.         {
  775.         pa = filter_mounted_evms_part( tg, pa );
  776.         }
  777.     parts = 
  778.         (list<map>)merge( parts, 
  779.                           sort( map x, map y, pa,
  780.                     ``(x["name"]:(any)""<y["name"]:(any)"")));
  781.     });
  782.     y2milestone( "get_evms_volumes parts %1", parts );
  783.     list ret = maplist( map p, parts, 
  784.     ``{
  785.     string fo = "";
  786.     if( p[`enc_type]:`none != `none )
  787.         {
  788.         fo = fo + "C";
  789.         }
  790.     if( p["format"]:false )
  791.         {
  792.         fo = fo + "F";
  793.         }
  794.     return( `item( `id(p["device"]:""), 
  795.                    p["device"]:"", 
  796.                ByteToHumanStringWithZero(p["size_k"]:0*1024), fo,
  797.                p["mount"]:"",
  798.                p["evms_native"]:false?"N":"C"
  799.                ));
  800.     });
  801.     y2milestone( "get_evms_volumes ret %1", ret );
  802.     return( ret );
  803.     }
  804.  
  805. define void volume_handle_max( integer stripe, string max_text )
  806.     ``{
  807.     y2milestone( "volume_handle_max stripe %1", stripe );
  808.     UI::ChangeWidget( `id(`max_size), `Enabled, stripe==1 );
  809.     UI::ChangeWidget( `id(`max_text), `Value, stripe==1?max_text:"" );
  810.     }
  811.  
  812. define map<string,any> dlg_logical_volume( map<string,any> co, 
  813.                                            map<string,any> part, 
  814.                        boolean create, boolean is_cont )
  815.     ``{
  816.     y2milestone( "dlg_logical_volume create:%1 p=%2 container:%3", 
  817.                  create, part, is_cont );
  818.     y2milestone( "dlg_logical_volume co:%1", 
  819.                  filter(string k, any e, co, ``(k!="partitions")) );
  820.  
  821.     integer new_size = part["size_k"]:0 * 1024;
  822.     integer old_size = new_size;
  823.     if( haskey( part, "orig_size_k" ))
  824.     old_size = part["orig_size_k"]:0*1024;
  825.     integer max_size = co["pe_free"]:0 * co["pesize"]:0;
  826.     if( !create )
  827.     {
  828.     max_size = max_size + new_size;
  829.     }
  830.     string  curr_size = ByteToHumanStringWithZero(new_size);
  831.     old_size = kmgt_str_to_byte(curr_size);
  832.     string  vol_name  = part["name"]:"";
  833.     integer stripes   = part["stripes"]:1;
  834.     integer stripesize = part["stripesize"]:64;
  835.     integer pesize = co["pesize"]:1;
  836.     string  mkey = "/dev/evms";
  837.     if( is_cont )
  838.     {
  839.     mkey = mkey + "/" + co["name"]:"";
  840.     }
  841.  
  842.     y2milestone( "dlg_logical_volume mkey %1 vol_name %2", mkey, vol_name );
  843.  
  844.     list stripes_poss = [
  845.               `item(`id(1), "1",  stripes == 1 ),
  846.               `item(`id(2), "2",  stripes == 2 ),
  847.               `item(`id(3), "3",  stripes == 3 ),
  848.               `item(`id(4), "4",  stripes == 4 ),
  849.               `item(`id(5), "5",  stripes == 5 ),
  850.               `item(`id(6), "6",  stripes == 6 ),
  851.               `item(`id(7), "7",  stripes == 7 ),
  852.               `item(`id(8), "8",  stripes == 8 )
  853.             ];
  854.  
  855.     list stripe_size = [
  856.               `item(`id(4),   "4",    stripesize == 4 ),
  857.               `item(`id(8),   "8",    stripesize == 8 ),
  858.               `item(`id(16),  "16",   stripesize == 16 ),
  859.               `item(`id(32),  "32",   stripesize == 32 ),
  860.               `item(`id(64),  "64",   stripesize == 64 ),
  861.               `item(`id(128), "128",  stripesize == 128 ),
  862.               `item(`id(256), "256",  stripesize == 256 ),
  863.               `item(`id(512), "512",  stripesize == 512 ),
  864.                        ];
  865.     
  866.     string  heading = "";
  867.     boolean is_create_mode = false;
  868.     boolean is_resize_mode = false;
  869.     boolean is_mount_mode = false;
  870.     term    ui_vol_name = `Empty();
  871.      
  872.     // header for input field size of volume 
  873.     string size_txt = sformat(_("&Size: (e.g., %1 %2)"), 
  874.                   ByteToHumanStringWithZero(4196*1024*1024),
  875.                   ByteToHumanStringWithZero(210*1024*1024));
  876.     // header for input field maximum allowd size
  877.     string max_text = sformat(_("max = %1 "), 
  878.                   ByteToHumanStringWithZero(max_size));
  879.  
  880.  
  881.     if( create && part["create"]:false )
  882.         {
  883.     // popup heading 
  884.     heading = _("Create Logical Volume");
  885.     is_create_mode = true; 
  886.     }
  887.     else if( !create && part["create"]:false )
  888.         {
  889.     // popup heading 
  890.     heading = _("Edit Logical Volume");
  891.     is_create_mode = false;
  892.     }
  893.     else 
  894.     {
  895.     // popup heading 
  896.     if( is_cont )
  897.         {
  898.         heading = _("Resize Logical Volume");
  899.         }
  900.     else
  901.         {
  902.         heading = _("Edit Logical Volume");
  903.         }
  904.     is_create_mode = false;
  905.     is_resize_mode = is_cont;
  906.     is_mount_mode = !is_resize_mode;
  907.     stripes_poss = [ `item(`id(1), "-", true) ];
  908.     stripe_size = [ `item(`id(1), "-", true) ];
  909.     }
  910.  
  911.     if( is_create_mode )
  912.     {
  913.     ui_vol_name = `VBox( `TextEntry(`id(`vol_name),
  914.                     // label text
  915.                     _("Volume &Name "), vol_name),
  916.                  // label text
  917.                  `Left(`Label(_("(e.g. var, opt)")))
  918.               );
  919.     }
  920.     else 
  921.     {
  922.     // display name of current volume group
  923.     ui_vol_name = `VBox( `Label(""),
  924.                  // label text
  925.                  `HBox(`Label( _("Volume Name: ")),
  926.                    `Heading(`opt(`outputField), vol_name ),
  927.                    `HStretch()
  928.                  ));
  929.     }
  930.  
  931.     term evms_specials = `Empty();
  932.  
  933.     if( !is_mount_mode )
  934.     {
  935.     evms_specials = `VBox(
  936.         `Top(`Left(ui_vol_name)),
  937.         `Top(`VBox( 
  938.         `TextEntry(`id(`size), size_txt, curr_size),
  939.         `HBox(
  940.             // set size to maxsize
  941.             `Left(`Label( `id(`max_text), max_text )),
  942.             // button text
  943.             `PushButton( `id(`max_size), _("ma&x")))
  944.         )),
  945.         `VStretch(),
  946.         `Left(`ComboBox( `id(`stripes), `opt(`hstretch,`notify),
  947.                  // button text
  948.                  _("Stri&pes"), stripes_poss )),
  949.         `VStretch(),
  950.         `Left(`ComboBox( `id(`stripesize), `opt(`hstretch,`notify),
  951.                  // button text
  952.                  _("Stripe &Size"), stripe_size )),
  953.         `VStretch());
  954.     }
  955.     else
  956.     {
  957.                   // label text %1 is prelaced by e.g. 4 GB
  958.     string txt = sformat( _("Size %1"), curr_size );
  959.         evms_specials = `VBox( `Right( `Label( txt ) ) );
  960.     }
  961.  
  962.     y2milestone( "dlg_logical_volume is_create_mode %1 is_resize_mode %2 is_mount_mode %3", 
  963.                  is_create_mode, is_resize_mode, is_mount_mode );
  964.  
  965.     map<symbol,map> fs = FileSystems::GetAllFileSystems(true, true);
  966.  
  967.     UI::OpenDialog(
  968.     `opt(`decorated ),
  969.     `HBox(`HWeight(30, 
  970.         `HBox(
  971.         `HSpacing(1),
  972.         `HStretch(),
  973.         `VBox(
  974.             `Heading(heading),
  975.             `VStretch(),
  976.             `VSpacing(1),
  977.             `HBox(
  978.              `HWeight( 40, FormatDlg( part, fs )),
  979.              `HStretch(),
  980.              `HSpacing(0.5),
  981.              `HWeight( 40, `VBox(
  982.                  `Top(evms_specials),
  983.                  `VSpacing(1),
  984.                  `ReplacePoint( `id(`mount_dlg_rp), 
  985.                         MountDlg(part, []))
  986.                  ))
  987.              ),
  988.             `VStretch(),  
  989.             `VSpacing(1),
  990.             `HBox(
  991.             // Ok button
  992.             `PushButton( `id(`ok), `opt(`default), 
  993.                          Label::OKButton()  ),
  994.             // Cancel button
  995.             `PushButton( `id(`cancel), Label::CancelButton() )
  996.             )
  997.             ),
  998.           `HStretch(),
  999.           `HSpacing(1)
  1000.           )
  1001.          )));
  1002.  
  1003.  
  1004.       // configure main dialog for the first call
  1005.       if( is_create_mode )
  1006.       {
  1007.       UI::ChangeWidget( `id(`vol_name), `ValidChars, 
  1008.                 FileSystems::nchars + "-._:" );
  1009.       }
  1010.       if( !is_mount_mode )
  1011.       {
  1012.       UI::ChangeWidget( `id(`stripes), `Enabled, !is_resize_mode );
  1013.       UI::ChangeWidget( `id(`stripesize), `Enabled, 
  1014.                 !is_resize_mode && stripes>1 );
  1015.       volume_handle_max( stripes, max_text );
  1016.       }
  1017.   
  1018.       ////////////////////////////////////////////////////////////////////
  1019.       // User mainloop for dialog
  1020.       ////////////////////////////////////////////////////////////////////
  1021.       
  1022.       boolean input_is_ok = true;
  1023.       map<string,any> retval = part;
  1024.  
  1025.       retval = HandlePartWidgetChanges( true, `ok, fs, part, retval );
  1026.  
  1027.       any ret = `cancel;
  1028.  
  1029.       repeat
  1030.       {
  1031.       input_is_ok  = true;
  1032.         
  1033.       ret = UI::UserInput();
  1034.       y2milestone( "dlg_logical_volume ret %1", ret );
  1035.  
  1036.       /////////////////////////////////////////////////////////
  1037.       if( ret == `stripes)
  1038.           {
  1039.           stripes = (integer)UI::QueryWidget( `id(`stripes), `Value);
  1040.           UI::ChangeWidget( `id(`stripesize), `Enabled, 
  1041.                 !is_resize_mode && stripes>1 );
  1042.           volume_handle_max( stripes, max_text );
  1043.           continue;
  1044.           }
  1045.  
  1046.       if( ret == `max_size)
  1047.           {
  1048.           UI::ChangeWidget( `id(`size), `Value, 
  1049.                             ByteToHumanStringWithZero(max_size));
  1050.           continue;
  1051.           }
  1052.  
  1053.       if( ret != `cancel )
  1054.           {
  1055.           retval = HandlePartWidgetChanges( false, ret, fs, part, retval );
  1056.           }
  1057.         
  1058.       if( is_create_mode ) 
  1059.           {
  1060.           vol_name = (string)UI::QueryWidget( `id(`vol_name), `Value );
  1061.           vol_name = deletechars( vol_name, " \t" );
  1062.           }
  1063.  
  1064.       if( UI::WidgetExists( `id(`stripes) ))
  1065.           {
  1066.           stripes = (integer)UI::QueryWidget(`id(`stripes), `Value);
  1067.           stripesize = (integer)UI::QueryWidget(`id(`stripesize), `Value);
  1068.           }
  1069.  
  1070.       if( ret==`ok )
  1071.           {
  1072.           if( UI::WidgetExists( `id(`size) ))
  1073.           {
  1074.           new_size = 
  1075.               kmgt_str_to_byte( (string)UI::QueryWidget(`id(`size),
  1076.                                                 `Value));
  1077.  
  1078.           if( !check_max_size(new_size, max_size) )
  1079.               {
  1080.               input_is_ok = false;
  1081.               continue;
  1082.               }
  1083.           if( !check_ok_fssize(new_size, retval) )
  1084.               {
  1085.               input_is_ok = false;
  1086.               continue;
  1087.               }
  1088.           y2milestone( "dlg_logical_volume new_size %1 old_size %2", 
  1089.                        new_size, old_size );
  1090.           }
  1091.  
  1092.           if( is_resize_mode && !retval["format"]:false && 
  1093.           new_size!=old_size )
  1094.           {
  1095.           string mp = retval["inactive"]:false ? "" : retval["mount"]:"";
  1096.           if( !CheckResizePossible( true, true, new_size-old_size,
  1097.                   retval["used_fs"]:`unknown, mp ))
  1098.               {
  1099.               UI::ChangeWidget(`id(`size), `Value, curr_size );
  1100.               continue;
  1101.               }
  1102.           }
  1103.  
  1104.           if( is_create_mode )
  1105.           {
  1106.           if( !evms_check_name(vol_name) )
  1107.               {
  1108.               input_is_ok = false;
  1109.               // error popup text
  1110.               // xgettext:no-c-format
  1111.               Popup::Error(_("Check your volume name. 
  1112. Use names like \"opt\" or \"var\" ...
  1113. Do not use ;/\`',!\"%#"));
  1114.               UI::SetFocus(`id(vol_name));
  1115.               continue;
  1116.               }
  1117.           else 
  1118.               {
  1119.               list names = maplist( map p, co["partitions"]:[],
  1120.                                     ``(p["name"]:""));
  1121.               if( contains( names, vol_name ) )
  1122.               {
  1123.               input_is_ok = false;
  1124.               // error popup text
  1125.               Popup::Error(sformat(_("A volume named \"%1\" already exists
  1126. in container \"%2\". Choose another name
  1127. or cancel this dialog.
  1128. "), vol_name, co["name"]:"" ));
  1129.               UI::SetFocus(`id(vol_name));
  1130.               continue;
  1131.               }
  1132.               }   
  1133.           }
  1134.  
  1135.           map ret_mp = CheckOkMount( mkey+"/"+vol_name, part, retval );
  1136.           retval = ret_mp["map"]:$[];
  1137.           if( !ret_mp["ok"]:false )
  1138.           {
  1139.           if( ret_mp["field"]:`none != `none )
  1140.               UI::SetFocus(`id( ret_mp["field"]:`none ));
  1141.           input_is_ok = false;
  1142.           continue;
  1143.           }
  1144.  
  1145.           y2milestone( "dlg_logical_volume retval %1 Doit:%2", 
  1146.                        retval["mount"]:"", Storage::DoCheckEvmsNonEvms );
  1147.  
  1148.           if( size(retval["mount"]:"")>0 && Storage::DoCheckEvmsNonEvms )
  1149.           {
  1150.           map<string,map> tg = Storage::GetTargetMap();
  1151.           list<string> ud = Storage::GetUsedRealDisksNew( tg, true );
  1152.           list<string> dl = Storage::GetEvmsRealDisk( tg, part );
  1153.           list isc = filter( string d, dl, ``(contains( ud, d )));
  1154.           if( size(isc)>0 )
  1155.               {
  1156.               if( !Popup::YesNo( evms_texts_evms_nonevms() ))
  1157.               {
  1158.               input_is_ok = false;
  1159.               continue;
  1160.               }
  1161.               else
  1162.               {
  1163.               Storage::DoCheckEvmsNonEvms = false;
  1164.               }
  1165.               }
  1166.           }
  1167.  
  1168.           ret_mp = CheckDeviceFinalOk( retval );
  1169.           if( !ret_mp["ok"]:false )
  1170.           input_is_ok = false;
  1171.           else
  1172.           retval = ret_mp["map"]:$[];
  1173.           }
  1174.  
  1175.       /////////////////////////////////////////////////////////
  1176.       retval["stripes"] = stripes;
  1177.       if( stripes>1 )
  1178.           {
  1179.           retval["stripesize"] = stripesize;
  1180.           }
  1181.       if( !is_mount_mode )
  1182.           {
  1183.           retval["name"] = vol_name;
  1184.           retval["device"] = mkey + "/" + vol_name;
  1185.           if( new_size != old_size )
  1186.           retval["size_k"] = (((new_size+pesize-1)/pesize)*pesize)/1024;
  1187.           y2milestone( "dlg_logical_volume size_k %1 new_size %2 old %3", 
  1188.                        retval["size_k"]:-1, new_size, old_size );
  1189.           }
  1190.       } 
  1191.       until ( (ret==`ok&&input_is_ok) || ret == `cancel );
  1192.  
  1193.       UI::CloseDialog();
  1194.       
  1195.       if( ret == `cancel || !input_is_ok )
  1196.       {
  1197.       retval = $[];
  1198.       }
  1199.       y2milestone( "dlg_logical_volume retval=%1", retval );
  1200.       return( retval );
  1201.       };
  1202.  
  1203. define map add_evms_volume( string co_name, map<string,map> tg )
  1204.     ``{
  1205.     y2milestone( "add_evms_volume co_name %1", co_name );
  1206.     map ret = $[ "ok" : false ];
  1207.     map<string,any> part = 
  1208.     $[ "create" : true,
  1209.        "used_fs" : Partitions::DefaultFs(),
  1210.        "stripes" : 1,
  1211.        "format" : true,
  1212.        "type" : `evms,
  1213.        "fstype" : "EVMS",
  1214.        "mount" : GetMountPointProposal( tg, [ Partitions::BootMount() ] )
  1215.     ];
  1216.     map<string,any> co = (map<string,any>)tg["/dev/evms/"+co_name]:$[];
  1217.     if( co["pe_free"]:0==0 )
  1218.     {
  1219.     // popup text %1 is replaced by a container name
  1220.     Popup::Message(sformat(_("There is no available space in the current container %1."), co_name ));
  1221.     }
  1222.     else
  1223.     {
  1224.     co["name"] = co_name;
  1225.     part["size_k"] = co["pe_free"]:0/4 * co["pesize"]:0 / 1024;
  1226.     part = dlg_logical_volume( co, part, true, true );
  1227.     if( size(part)>0 )
  1228.         {
  1229.         ret["ok"] = Storage::CreateEvmsVolume( co_name, part["name"]:"",
  1230.                                                part["size_k"]:0, 
  1231.                            part["stripes"]:1 );
  1232.         if( !ret["ok"]:false )
  1233.         {
  1234.         string txt = _("A volume with the requested size 
  1235. could not be created. 
  1236. ");
  1237.         if( part["stripes"]:1 > 1 )
  1238.             txt = txt + _("Try reducing the stripe count of the volume.");
  1239.         Popup::Error( txt );
  1240.         }
  1241.         else
  1242.         {
  1243.         ret["ok"] = Storage::ChangeVolumeProperties( part );
  1244.         if( ret["ok"]:false && part["stripes"]:1>1 && 
  1245.             part["stripesize"]:0>0 )
  1246.             ret["ok"] = Storage::ChangeEvmsStripeSize( co_name, 
  1247.                                    part["name"]:"",
  1248.                                    part["stripesize"]:0 );
  1249.         }
  1250.         }
  1251.     }
  1252.     y2milestone( "add_evms_volume ret=%1", ret );
  1253.     return( ret );
  1254.     };
  1255.  
  1256. define map edit_evms_volume( string device, map<string,map> tg )
  1257.     ``{
  1258.     y2milestone( "edit_evms_volume device %1", device );
  1259.     map ret = $[ "ok" : false ];
  1260.  
  1261.     map d = Storage::GetDiskPartition( device );
  1262.     y2milestone( "edit_evms_volume d %1", d );
  1263.  
  1264.     string key = d["disk"]:"";
  1265.     if( !haskey( tg, key ) )
  1266.     {
  1267.     key = "/dev/evms";
  1268.     }
  1269.     y2milestone( "edit_evms_volume key %1", key );
  1270.  
  1271.     map<string,any> part = Storage::GetPartition( tg, device );
  1272.     y2milestone( "edit_evms_volume part %1", part );
  1273.  
  1274.     integer last_size = part["size_k"]:0*1024;
  1275.     part = dlg_logical_volume( (map<string,any>)tg[key]:$[], part, false, 
  1276.                    tg[key,"is_container"]:false );
  1277.     if( size(part)>0 )
  1278.     {
  1279.     ret["ok"] = Storage::ChangeVolumeProperties( part );
  1280.     if( ret["ok"]:false && last_size != part["size_k"]:0*1024 )
  1281.         ret["ok"] = Storage::ResizeVolume( part["device"]:"", key,
  1282.                            part["size_k"]:0 );
  1283.     }
  1284.     return( ret );
  1285.     };
  1286.  
  1287. define map delete_evms_volume( string device, map<string,map> tg )
  1288.     ``{
  1289.     y2milestone( "delete_evms_volume device %1", device );
  1290.     map ret = $[ "ok" : false ];
  1291.  
  1292.     map d = Storage::GetDiskPartition( device );
  1293.  
  1294.     string key = d["disk"]:"";
  1295.     if( !haskey( tg, key ) )
  1296.     {
  1297.     key = "/dev/evms";
  1298.     }
  1299.  
  1300.     map<string,any> part = Storage::GetPartition( tg, device );
  1301.     y2milestone( "delete_evms_volume part %1", part );
  1302.  
  1303.     if( !tg[key,"is_container"]:false )
  1304.     {
  1305.     // popup text %1 is replaced by a container name
  1306.     Popup::Message(sformat(_("You can only delete logical volumes in a container.
  1307. %1 is not a logical volume produced by a container.
  1308. "), device ));
  1309.     }
  1310.     else if( check_device_delete( part, false, Mode::installation() ))
  1311.     {
  1312.     string txt = sformat( _("Really delete %1?"), part["device"]:"" );
  1313.     if( Popup::YesNo( txt ) )
  1314.         {
  1315.         ret["ok"] = Storage::DeleteDevice( key, part["device"]:"" );
  1316.         }
  1317.     }
  1318.     return( ret );
  1319.     };
  1320.  
  1321. }
  1322.