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 / do_proposal_flexible.ycp < prev    next >
Text File  |  2006-11-29  |  109KB  |  3,712 lines

  1. /*
  2.  *************************************************************
  3.  *
  4.  *     YaST2      SuSE Labs                        -o)
  5.  *     --------------------                        /\\
  6.  *                                                _\_v
  7.  *           www.suse.de / www.suse.com
  8.  * ----------------------------------------------------------
  9.  *
  10.  * Author:        Thomas Fehr <fehr@suse.de>
  11.  *
  12.  * Description:   Make a proposal for partitioning
  13.  *
  14.  *
  15.  *************************************************************
  16.  
  17.  $Id: do_proposal_flexible.ycp 33906 2006-10-30 18:01:58Z fehr $
  18. */
  19. {
  20.  
  21. textdomain "storage";
  22.  
  23. import "FileSystems";
  24. import "Partitions";
  25. import "Storage";
  26. import "ProductFeatures";
  27.  
  28. include "partitioning/partition_defines.ycp";
  29.  
  30. map read_partition_config( string fpath );
  31. map read_partition_xml_config();
  32. map get_gap_info( map disk, boolean add_exist_linux );
  33. map add_cylinder_info( map conf, map gap );
  34. map get_perfect_list( list ps, map g );
  35. map process_partition_data( string dev, map solution, string vgname );
  36. map find_matching_disk( list<string> disks, map target, map conf );
  37. map try_resize_windows( map disk );
  38. map remove_possible_partitions( map disk, map conf );
  39. map distribute_space( integer rest, list weights, list added, list ps );
  40. void add_part_recursive( list ps, map g );
  41. map normalize_gaps( list ps, map g );
  42. integer do_weighting( list ps, map g );
  43.  
  44. symbol cur_mode = `free;
  45. integer cur_weight = -10000;
  46. map cur_gap = $[];
  47. integer big_cyl = 4 * 1024 * 1024 * 1024;
  48.  
  49. define boolean ignore_disk( string dev, map entry, boolean soft )
  50.     ``{
  51.     boolean ret = !Storage::IsPartitionable( entry ) || 
  52.                   entry["readonly"]:false || Arch::s390();
  53.     if( !ret && Arch::ia64() && entry["label"]:"gpt"!="gpt" )
  54.     {
  55.     ret = true;
  56.     }
  57.     if( !ret && soft && Arch::board_iseries () && search( dev, "/dev/sd" )==0 )
  58.     {
  59.     ret = true;
  60.     }
  61.     if( !ret && soft && (entry["softraiddisk"]:false||entry["hotpluggable"]:false) )
  62.     {
  63.     ret = true;
  64.     }
  65.     if( !ret && soft && contains( Storage::NoProposeDisks(), dev ))
  66.     {
  67.     ret = true;
  68.     }
  69.     if( !ret && soft )
  70.     ret = entry["used_by_type"]:`UB_NONE != `UB_NONE;
  71.     if( ret )
  72.     {
  73.     y2milestone( "ignoring disk %1 soft %2", dev, soft );
  74.     }
  75.     return( ret );
  76.     };
  77.   
  78. define string pinfo_name()
  79.     ``{
  80.     return( "/part.info" );
  81.     }
  82.  
  83. define boolean has_flex_proposal()
  84.     ``{
  85.     boolean ret = (integer)SCR::Read( .target.size, pinfo_name() )>0;
  86.     return( ret );
  87.     }
  88.  
  89. boolean need_boot( map disk )
  90.     {
  91.     return( Partitions::NeedBoot() ||
  92.         disk["type"]:`CT_UNKNOWN == `CT_DMRAID );
  93.     }
  94.  
  95. define map try_add_boot( map conf, map disk, boolean force )
  96.     ``{
  97.     boolean boot = 
  98.     size(filter( map e, conf["partitions"]:[], 
  99.              ``(e["mount"]:""==Partitions::BootMount()))) > 0;
  100.     boolean root = size(filter( map e, conf["partitions"]:[], 
  101.                 ``(e["mount"]:""=="/"))) > 0;
  102.     map tc = conf;
  103.     y2milestone( "try_add_boot conf %1", conf );
  104.     y2milestone( "try_add_boot boot %1 root %2 force %3", boot, root, force );
  105.     if( !boot && (root||force) && 
  106.         (disk["cyl_count"]:0>Partitions::BootCyl() || need_boot(disk)) )
  107.     {
  108.     map pb = $[];
  109.     pb["mount"] = Partitions::BootMount();
  110.     pb["size"] = Partitions::MinimalNeededBootsize();
  111.     pb["fsys"] = Partitions::DefaultBootFs();
  112.     pb["id"] = Partitions::FsidBoot();
  113.     pb["auto_added"] = true;
  114.     pb["max_cyl"] = Partitions::BootCyl();
  115.     pb["primary"] = Partitions::BootPrimary();
  116.     pb["maxsize"] = 500*1024*1024;
  117.     tc["partitions"] = add( tc["partitions"]:[], pb );
  118.     y2milestone( "try_add_boot disk_cyl %1 boot_cyl %2 need_boot %3 typ %4",
  119.                  disk["cyl_count"]:0, Partitions::BootCyl(), 
  120.              Partitions::NeedBoot(), disk["type"]:`CT_UNKNOWN );
  121.     y2milestone( "try_add_boot boot added automagically pb %1", pb );
  122.     }
  123.     return( tc );
  124.     }
  125.  
  126. define map do_flexible_disk( map disk )
  127.     ``{
  128.     string dev = disk["device"]:"";
  129.     y2milestone( "do_flexible_disk dev %1", dev );
  130.     y2milestone( "do_flexible_disk parts %1", disk["partitions"]:[] );
  131.     map ret = $[];
  132.     ret["ok"] = false;
  133.     map conf = read_partition_config( pinfo_name() );
  134.     map solutions = $[];
  135.  
  136.     if( size(conf)>0 && Storage::IsPartitionable( disk ))
  137.     {
  138.     y2milestone( "do_flexible_disk processing disk %1", dev );
  139.     map tc = try_add_boot( conf, disk, false );
  140.     cur_mode = `free;
  141.     cur_gap = $[];
  142.     map gap = get_gap_info( disk, false );
  143.     tc = add_cylinder_info( tc, gap );
  144.     map sol = get_perfect_list( tc["partitions"]:[], gap );
  145.     if( size(sol)>0 )
  146.         {
  147.         sol["disk"] = eval(disk);
  148.         ret["ok"] = true;
  149.         ret["disk"] = process_partition_data( dev, sol, "" );
  150.         ret["weight"] = sol["weight"]:-1;
  151.         }
  152.     }
  153.     y2milestone( "do_flexible_disk ret %1", ret["ok"]:false );
  154.     if( ret["ok"]:false )
  155.     {
  156.     y2milestone( "do_flexible_disk weight %1", ret["weight"]:-2 );
  157.     y2milestone( "do_flexible_disk disk %1", ret["disk"]:$[] );
  158.     }
  159.     return( ret );
  160.     }
  161.  
  162. define map do_flexible_disk_conf( map disk, map co, boolean ignore_boot,
  163.                                   boolean reuse )
  164.     ``{
  165.     string dev = disk["device"]:"";
  166.     y2milestone( "do_flexible_disk_conf dev %1 ignore_boot %2 reuse %3", 
  167.                  dev, ignore_boot, reuse );
  168.     map conf = co;
  169.     if( !ignore_boot )
  170.     conf = try_add_boot( conf, disk, true );
  171.     y2milestone( "do_flexible_disk_conf parts %1", disk["partitions"]:[] );
  172.     y2milestone( "do_flexible_disk_conf conf %1", conf );
  173.     map ret = $[];
  174.     ret["ok"] = false;
  175.     map solutions = $[];
  176.  
  177.     if( size(conf)>0 && size(conf["partitions"]:[])>0 && 
  178.         Storage::IsPartitionable( disk ))
  179.     {
  180.     y2milestone( "do_flexible_disk_conf processing disk %1", dev );
  181.     cur_mode = reuse?`reuse:`free;
  182.     cur_gap = $[];
  183.     map gap = get_gap_info( disk, reuse );
  184.     map tc = add_cylinder_info( conf, gap );
  185.     map sol = get_perfect_list( tc["partitions"]:[], gap );
  186.     if( size(sol)>0 )
  187.         {
  188.         sol["disk"] = eval(disk);
  189.         ret["ok"] = true;
  190.         ret["disk"] = process_partition_data( dev, sol, "" );
  191.         ret["weight"] = sol["weight"]:-1;
  192.         }
  193.     }
  194.     else if( Storage::IsPartitionable( disk ) )
  195.     {
  196.     ret["ok"] = true;
  197.     ret["disk"] = disk;
  198.     }
  199.     y2milestone( "do_flexible_disk_conf ret %1", ret["ok"]:false );
  200.     if( ret["ok"]:false && size(conf)>0 )
  201.     {
  202.     y2milestone( "do_flexible_disk_conf weight %1", ret["weight"]:-2 );
  203.     y2milestone( "do_flexible_disk_conf parts %1", ret["disk","partitions"]:[] );
  204.     }
  205.     return( ret );
  206.     }
  207.  
  208. define map do_vm_disk_conf( map disk, map boot, string vmkey, string key )
  209.     ``{
  210.     string dev = disk["device"]:"";
  211.     y2milestone( "do_vm_disk_conf dev %1 vmkey %2 key %3 boot %4", 
  212.                  dev, vmkey, key, boot );
  213.     y2milestone( "do_vm_disk_conf parts %1", disk["partitions"]:[] );
  214.     map conf = $[ "partitions" : [ $[ "id" : 0x8E ] ] ];
  215.     if( size(boot)>0 )
  216.     conf["partitions"] = add( conf["partitions"]:[], boot );
  217.     map ret = $[];
  218.     ret["ok"] = false;
  219.  
  220.     integer fsid = conf["partitions",0,"id"]:0;
  221.     if( Storage::IsPartitionable( disk ))
  222.     {
  223.     y2milestone( "do_vm_disk_conf processing disk %1", dev );
  224.     cur_mode = `free;
  225.     cur_gap = $[];
  226.     map gap = get_gap_info( disk, true );
  227.     y2milestone( "do_vm_disk_conf gap %1", gap );
  228.     y2milestone( "do_vm_disk_conf conf %1", conf );
  229.     map tc = add_cylinder_info( conf, gap );
  230.     y2milestone( "do_vm_disk_conf tc %1", tc );
  231.     y2milestone( "do_vm_disk_conf gap %1", gap["gap"]:[] );
  232.     if( size(gap["gap"]:[])>1 )
  233.         {
  234.         gap["gap"] = sort( map a, map b, gap["gap"]:[],
  235.         ``{
  236.         if( a["extended"]:false==b["extended"]:false )
  237.             return( a["start"]:0<b["start"]:0 );
  238.         else
  239.             return( !a["extended"]:false );
  240.         });
  241.         y2milestone( "do_vm_disk_conf gap %1", gap["gap"]:[] );
  242.         }
  243.     boolean ok = size(boot)==0;
  244.     if( !ok )
  245.         {
  246.         integer gstart = -1;
  247.         map bo = find( map p, (list<map>)tc["partitions"]:[], 
  248.                        ``(p["mount"]:""==boot["mount"]:"") );
  249.         y2milestone( "do_vm_disk_conf boot %1", bo );
  250.         integer cyl_num = bo["cylinders"]:1;
  251.         y2milestone( "do_vm_disk_conf boot cyl %1", cyl_num );
  252.         gap["gap"] = maplist( map g, gap["gap"]:[],
  253.         ``{
  254.         if( !g["exists"]:false && !ok && g["cylinders"]:0>=cyl_num &&
  255.             ((g["extended"]:false && size(gap["ext_pnr"]:[])>1)||
  256.              (!g["extended"]:false && size(gap["free_pnr"]:[])>1)))
  257.             {
  258.             ok = true;
  259.             gstart = g["start"]:-1;
  260.             string key = g["extended"]:false ? "ext_pnr" : "free_pnr";
  261.             g["added"] = [ [ 1, gap[key,0]:0, cyl_num ] ];
  262.             g["cylinders"] = g["cylinders"]:0-cyl_num;
  263.             gap[key] = remove( gap[key]:[], 0 );
  264.             if( g["cylinders"]:0 > 0 )
  265.             {
  266.             g["added"] = add( g["added"]:[], 
  267.                               [ 0, gap[key,0]:0, g["cylinders"]:0 ] );
  268.             g["cylinders"] = 0;
  269.             gap[key] = remove( gap[key]:[], 0 );
  270.             }
  271.             }
  272.         return( g );
  273.         });
  274.         if( !ok )
  275.         {
  276.         gap["gap"] = maplist( map g, gap["gap"]:[],
  277.             ``{
  278.             if( !g["exists"]:false && !ok && g["cylinders"]:0>=cyl_num &&
  279.             ((g["extended"]:false && size(gap["ext_pnr"]:[])>0)||
  280.              (!g["extended"]:false && size(gap["free_pnr"]:[])>0)))
  281.             {
  282.             ok = true;
  283.             gstart = g["start"]:-1;
  284.             string key = g["extended"]:false ? "ext_pnr" : "free_pnr";
  285.             g["added"] = [ [ 1, gap[key,0]:0, cyl_num ] ];
  286.             g["cylinders"] = g["cylinders"]:0-cyl_num;
  287.             gap[key] = remove( gap[key]:[], 0 );
  288.             }
  289.             return( g );
  290.             });
  291.         }
  292.         if( ok && size(vmkey)>0 )
  293.         {
  294.         gap["gap"] = filter( map g, gap["gap"]:[], 
  295.                              ``(g["start"]:0==gstart));
  296.         }
  297.         y2milestone( "do_vm_disk_conf gap %1", gap["gap"]:[] );
  298.         }
  299.     else if( size(vmkey)>0 )
  300.         gap = $[];
  301.     map sol = $[];
  302.     sol["solution"] = gap;
  303.     sol["partitions"] = conf["partitions"]:[];
  304.     sol["disk"] = disk;
  305.     ret["ok"] = ok;
  306.     ret["weight"] = 0;
  307.     if( ok && size(vmkey)==0 )
  308.         {
  309.         if( size(gap["ext_reg"]:[])>0 )
  310.         {
  311.         integer ext_end = gap["ext_reg",0]:0 + gap["ext_reg",1]:0 - 1;
  312.         map aext = find( map g, gap["gap"]:[], 
  313.                          ``(size(g["added"]:[])==0 &&
  314.                     !g["exists"]:false &&
  315.                     g["start"]:0>=ext_end &&
  316.                     g["start"]:0-ext_end<=1));
  317.         y2milestone( "do_vm_disk_conf ee:%1 ae:%2", ext_end, aext );
  318.         if( aext!=nil )
  319.             {
  320.             gap["resize_ext"] = aext["end"]:0;
  321.             gap["gap"] = filter( map g, gap["gap"]:[],
  322.                                  ``(g["start"]:0!=aext["start"]:0));
  323.             aext = find( map g, gap["gap"]:[],
  324.                  ``(!g["exists"]:false && g["extended"]:false &&
  325.                     g["end"]:0==ext_end));
  326.             y2milestone( "do_vm_disk_conf aext %1", aext );
  327.             if( aext != nil )
  328.             {
  329.             gap["gap"] = maplist( map g, gap["gap"]:[],
  330.                 ``{
  331.                 if( g["end"]:0==aext["end"]:0 )
  332.                 {
  333.                 g["cylinders"] = g["cylinders"]:0 + 
  334.                                  gap["resize_ext"]:0 -
  335.                          g["end"]:0;
  336.                 g["end"] = gap["resize_ext"]:0;
  337.                 }
  338.                 return( g );
  339.                 });
  340.             }
  341.             else
  342.             {
  343.             map a = $[ "extended" : true,
  344.                    "start" : gap["ext_reg",0]:0+gap["ext_reg",1]:0,
  345.                        "end" : gap["resize_ext"]:0 ];
  346.             a["cylinders"] = a["end"]:0 - a["start"]:0 + 1;
  347.                 y2milestone("do_vm_disk_conf add gap %1", a ); 
  348.                 y2milestone("do_vm_disk_conf add gap %1", gap["gap"]:[] ); 
  349.             gap["gap"] = add( gap["gap"]:[], a );
  350.                 y2milestone("do_vm_disk_conf add gap %1", gap["gap"]:[] ); 
  351.             }
  352.             }
  353.         y2milestone( "do_vm_disk_conf aext gap %1", gap );
  354.         }
  355.         gap["gap"] = maplist( map g, gap["gap"]:[],
  356.         ``{
  357.         if( g["exists"]:false )
  358.             {
  359.             map acur = find( map gg, gap["gap"]:[],
  360.                      ``(size(gg["added"]:[])==0 &&
  361.                     !gg["exists"]:false &&
  362.                         gg["extended"]:false==g["extended"]:false &&
  363.                         gg["start"]:0>=g["end"]:0 && 
  364.                         gg["start"]:0-g["end"]:0<=1));
  365.             y2milestone( "do_vm_disk_conf ee:%1 ae:%2", 
  366.                          g["end"]:0, acur );
  367.             if( acur!=nil )
  368.             {
  369.             g["resize"] = acur["end"]:0;
  370.             g["fsid"] = fsid;
  371.             }
  372.             }
  373.         return( g );
  374.         });
  375.         list<integer> sl = maplist( map g, gap["gap"]:[], 
  376.                                     ``(g["resize"]:-1));
  377.         y2milestone( "do_vm_disk_conf sl %1", sl );
  378.         gap["gap"] = filter( map g, gap["gap"]:[],
  379.                  ``(!contains(sl,g["end"]:0)));
  380.         gap["gap"] = sort( map a, map b, gap["gap"]:[],
  381.         ``{
  382.         return( a["cylinders"]:0>b["cylinders"]:0 );
  383.         });
  384.         y2milestone( "do_vm_disk_conf sorted gap %1", gap["gap"]:[] );
  385.         gap["gap"] = maplist( map g, gap["gap"]:[],
  386.         ``{
  387.         if( !g["exists"]:false && g["cylinders"]:0>0 &&
  388.             ((g["extended"]:false && size(gap["ext_pnr"]:[])>0)||
  389.              (!g["extended"]:false && size(gap["free_pnr"]:[])>0)))
  390.             {
  391.             string key = g["extended"]:false ? "ext_pnr" : "free_pnr";
  392.             g["added"] = add( g["added"]:[], 
  393.                               [ 0, gap[key,0]:0, g["cylinders"]:0 ]);
  394.             g["cylinders"] = 0;
  395.             gap[key] = remove( gap[key]:[], 0 );
  396.             }
  397.         return( g );
  398.         });
  399.         gap["gap"] = maplist( map g, gap["gap"]:[],
  400.         ``{
  401.         if( g["exists"]:false && fsid!=0 && g["fsid"]:0!=fsid )
  402.             {
  403.             g["fsid"] = fsid;
  404.             }
  405.         return( g );
  406.         });
  407.         y2milestone( "do_vm_disk_conf end gap %1", gap["gap"]:[] );
  408.         sol["solution"] = gap;
  409.         }
  410.     ret["disk"] = process_partition_data( dev, sol, key );
  411.     }
  412.     y2milestone( "do_vm_disk_conf ret %1", ret["ok"]:false );
  413.     if( ret["ok"]:false )
  414.     {
  415.     y2milestone( "do_vm_disk_conf weight %1", ret["weight"]:-2 );
  416.     y2milestone( "do_vm_disk_conf parts %1", ret["disk","partitions"]:[] );
  417.     }
  418.     return( ret );
  419.     }
  420.  
  421. define list<string> restrict_disk_names( list<string> disks )
  422.     {
  423.     list<string> ddev = disks;
  424.     list<string> d1 = filter( string s, ddev, ``(search(s,"/dev/hd")==0));
  425.     ddev = filter( string s, ddev, ``(search(s,"/dev/hd")!=0));
  426.     if( size(d1)>2 )
  427.     {
  428.     integer count=1;
  429.     d1 = maplist( string s, d1, 
  430.         ``{
  431.         return( (count<=2)?s:"" );
  432.         count=count+1;
  433.         });
  434.     d1 = filter( string s, d1, ``(size(s)>0));
  435.     }
  436.     d1 = (list<string>)merge( d1, filter( string s, ddev, 
  437.                                           ``(search(s,"/dev/sd")==0)));
  438.     ddev = filter( string s, ddev, ``(search(s,"/dev/sd")!=0));
  439.     ddev = (list<string>)merge( d1, ddev );
  440.     if( size(ddev)>4 )
  441.     {
  442.     integer count=1;
  443.     ddev = maplist( string s, ddev, 
  444.         ``{
  445.         return( (count<=4)?s:"" );
  446.         count=count+1;
  447.         });
  448.     ddev = filter( string s, ddev, ``(size(s)>0));
  449.     }
  450.     y2milestone( "restrict_disk_names: ret %1", ddev );
  451.     return( ddev );
  452.     }
  453.  
  454. define map do_pflex( map<string,map> target, map conf )
  455.     {
  456.     map ret = $[];
  457.     ret["ok"] = false;
  458.     list<map> solutions = [];
  459.     cur_mode = `free;
  460.     if( size(conf)>0 )
  461.     {
  462.     list<string> ddev = maplist( string k, map e, 
  463.                          filter( string l, map f, target, 
  464.                          ``(!ignore_disk(l,f,false))), ``(k));
  465.     ddev = sort( ddev );
  466.     y2milestone( "do_pflex ddev %1", ddev );
  467.     map tc = $[];
  468.     map<integer,any> dtmp = $[];
  469.     foreach( map p, conf["partitions"]:[], 
  470.         ``{
  471.         integer dprio = p["disk"]:0;
  472.         if( haskey( dtmp, dprio ))
  473.         {
  474.         dtmp[dprio] = add( dtmp[dprio]:[], p );
  475.         }
  476.         else
  477.         {
  478.         dtmp[dprio] = [ p ];
  479.         }
  480.         });
  481.     y2milestone( "do_pflex dlist %1", dtmp );
  482.     list dlist = maplist( integer k, any e, dtmp, ``(e) );
  483.     y2milestone( "do_pflex dlist %1", dlist );
  484.     if( size(dlist)>size(ddev) )
  485.         {
  486.         integer idx = size(ddev);
  487.         while( idx<size(dlist) )
  488.         {
  489.         dlist[size(ddev)-1] = union( dlist[size(ddev)-1]:[], 
  490.                                      dlist[idx]:[] );
  491.         idx = idx+1;
  492.         }
  493.         while( size(dlist)>size(ddev) )
  494.         {
  495.         dlist = remove( dlist, size(ddev) );
  496.         }
  497.         y2milestone( "do_pflex dlist %1", dlist );
  498.         }
  499.     list save_dlist = (list) eval(dlist);
  500.     repeat
  501.         {
  502.         integer count = 0;
  503.         repeat
  504.         {
  505.         list<string> td = eval(ddev);
  506.         integer idx = 0;
  507.         y2milestone( "do_pflex start while count %1", count );
  508.         while( idx<size(dlist) && count<size(dlist) )
  509.             {
  510.             y2milestone( "do_pflex in while idx %1", idx );
  511.             tc = (map) eval(conf);
  512.             tc["partitions"] = eval( dlist[idx]:[] );
  513.             map md = find_matching_disk( td, target, tc );
  514.             y2milestone( "do_pflex size(md) %1", size(md) );
  515.             if( size(md)>0 )
  516.             {
  517.             solutions = add( solutions, md );
  518.             td = filter( string e, td, ``(e!=md["device"]:""));
  519.             y2milestone( "do_pflex new td %1", td );
  520.             idx = idx+1;
  521.             }
  522.             else
  523.             {
  524.             y2milestone( "do_pflex no solution" );
  525.             idx = size(dlist);
  526.             td = eval(ddev);
  527.             solutions = [];
  528.             count = count + 1;
  529.             if( size(dlist)>1 )
  530.                 {
  531.                 list tfi = dlist[0]:[];
  532.                 dlist = remove( dlist, 0 );
  533.                 dlist = add( dlist, tfi );
  534.                 y2milestone( "do_pflex new rot dlist %1", dlist );
  535.                 }
  536.             }
  537.             }
  538.         }
  539.         until( size(solutions)>0 || count>=size(dlist) );
  540.         if( size(solutions)==0 && size(dlist)>1 )
  541.         {
  542.         dlist = (list) eval(save_dlist);
  543.         dlist[size(dlist)-2] = union( dlist[size(dlist)-2]:[],
  544.                           dlist[size(dlist)-1]:[] );
  545.         dlist = remove( dlist, size(dlist)-1 );
  546.         y2milestone( "do_pflex new truncated dlist %1",
  547.                      dlist );
  548.         save_dlist = (list)eval(dlist);
  549.         }
  550.         }
  551.     until( size(solutions)>0 || size(dlist)<=1 );
  552.     if( size(solutions)==0 &&
  553.         (size(conf["keep_partition_fsys"]:[])>0 ||
  554.          size(conf["keep_partition_id"]:[])>0 ||
  555.          size(conf["keep_partition_num"]:[])>0 ||
  556.          !conf["prefer_remove"]:false))
  557.         {
  558.         y2milestone( "do_pflex desperate mode" );
  559.         tc = (map) eval(conf);
  560.         cur_mode = `desparate;
  561.         tc["keep_partition_fsys"] = [];
  562.         tc["keep_partition_id"] = [];
  563.         tc["keep_partition_num"] = [];
  564.         tc["prefer_remove"] = true;
  565.         map md = find_matching_disk( ddev, target, tc );
  566.         if( size(md)>0 )
  567.         {
  568.         solutions = add( solutions, md );
  569.         }
  570.         }
  571.     if( size(solutions)>0 )
  572.         {
  573.         foreach( map e, solutions,
  574.         ``{
  575.         string disk = e["device"]:"";
  576.         target[disk] = process_partition_data( disk, e, "" );
  577.         y2milestone( "do_pflex solution disk %1 %2", 
  578.                      disk, target[disk]:$[] );
  579.         });
  580.         ret["ok"] = true;
  581.         target = Storage::SpecialBootHandling( target );
  582.         ret["target"] = Storage::DeleteDestroyedLvmVgs( target );
  583.         }
  584.     }
  585.     return( ret );
  586.     }
  587.  
  588.  
  589. define map do_proposal_flexible( map<string,map> target )
  590.     ``{
  591.     map conf = $[];
  592.     if( ProductFeatures::GetBooleanFeature( "partitioning", 
  593.                                             "use_flexible_partitioning"))
  594.         conf = read_partition_xml_config();
  595.     else
  596.         conf = read_partition_config( pinfo_name() );
  597.  
  598.     return( do_pflex( target, conf ) );
  599.     }
  600.  
  601. define map find_matching_disk( list<string> disks, map target, map conf )
  602.     ``{
  603.     map<string,map> solutions = $[];
  604.  
  605.     cur_weight = -100000;
  606.     cur_gap = $[];
  607.     foreach( string k, disks,
  608.     ``{
  609.     map e = target[k]:$[];
  610.     y2milestone( "find_matching_disk processing disk %1", k );
  611.     y2milestone( "find_matching_disk parts %1", conf["partitions"]:[] );
  612.     map tc = try_add_boot( conf, e, false );
  613.     if( cur_mode != `desparate )
  614.         cur_mode = `free;
  615.     if( !tc["prefer_remove"]:false )
  616.         {
  617.         map gap = get_gap_info( e, false );
  618.         tc = add_cylinder_info( tc, gap );
  619.         map l = get_perfect_list( tc["partitions"]:[], gap );
  620.         if( size(l)>0 )
  621.         {
  622.         solutions[k] = eval(l);
  623.         solutions[k,"disk"] = eval(e);
  624.         }
  625.         cur_mode = `reuse;
  626.         map egap = get_gap_info( e, true );
  627.         if( size(egap["gap"]:[]) > size(gap["gap"]:[]) )
  628.         {
  629.         tc = add_cylinder_info( tc, egap );
  630.         l = get_perfect_list( tc["partitions"]:[], egap );
  631.         if( size(l)>0 && 
  632.             (!haskey(solutions,k) || 
  633.              (haskey( l, "weight" ) && 
  634.               l["weigth"]:0 > solutions[k,"weigth"]:0 )))
  635.             {
  636.             y2milestone( "find_matching_disk solution reuse existing" );
  637.             solutions[k] = eval(l);
  638.             solutions[k,"disk"] = eval(e);
  639.             }
  640.         }
  641.         cur_mode = `resize;
  642.         map rw = try_resize_windows( e );
  643.         if( find( map p, rw["partitions"]:[], ``(p["resize"]:false))!=nil )
  644.         {
  645.         egap = get_gap_info( rw, true );
  646.         tc = add_cylinder_info( tc, egap );
  647.         l = get_perfect_list( tc["partitions"]:[], egap );
  648.         if( size(l)>0 && 
  649.             (!haskey(solutions,k) ||
  650.              (haskey( l, "weight" ) && 
  651.               l["weigth"]:0 > solutions[k,"weigth"]:0 )))
  652.             {
  653.             y2milestone( "find_matching_disk solution resizing windows" );
  654.             solutions[k] = eval(l);
  655.             solutions[k,"disk"] = eval(rw);
  656.             }
  657.         }
  658.         }
  659.     else
  660.         {
  661.         map rp = remove_possible_partitions( e, tc );
  662.         map gap = get_gap_info( rp, false );
  663.         tc = add_cylinder_info( tc, gap );
  664.         map l = get_perfect_list( tc["partitions"]:[], gap );
  665.         if( size(l)>0 )
  666.         {
  667.         solutions[k] = eval(l);
  668.         solutions[k,"disk"] = eval(rp);
  669.         }
  670.         }
  671.     });
  672.     map ret = $[];
  673.     if( size(solutions)>0 )
  674.     {
  675.     foreach( string k, map e, solutions,
  676.         ``{
  677.         y2milestone( "find_matching_disk disk %1 weight %2", 
  678.                      k, e["weight"]:0 );
  679.         });
  680.     list<string> disks = maplist( string k, map e, solutions, ``(k) );
  681.     disks = sort( string a, string b, disks, 
  682.               ``(solutions[a,"weight"]:0>solutions[b,"weight"]:0));
  683.     y2milestone( "find_matching_disk sorted disks %1", disks );
  684.     ret = solutions[disks[0]:""]:$[];
  685.     ret["device"] = disks[0]:"";
  686.     }
  687.     return( ret );
  688.     }
  689.  
  690. define map process_partition_data( string dev, map solution, string vgname )
  691.     ``{
  692.     map disk = solution["disk"]:$[];
  693.     list<map> partitions = [];
  694.     string value = "";
  695.     boolean remove_boot = false;
  696.     if( size( filter( map e, solution["partitions"]:[], 
  697.               ``(e["mount"]:""==Partitions::BootMount() && 
  698.              e["auto_added"]:false)))>0 )
  699.     {
  700.     foreach( map e, solution["solution","gap"]:[],
  701.         ``{
  702.         foreach( list a, e["added"]:[],
  703.         ``{
  704.         integer pindex = a[0]:0;
  705.         if( solution["partitions",pindex,"mount"]:"" == "/" &&
  706.             disk["cyl_count"]:0 > Partitions::BootCyl() &&
  707.             e["end"]:0 <= Partitions::BootCyl() && !need_boot(disk) )
  708.             {
  709.             remove_boot = true;
  710.             }
  711.         });
  712.         });
  713.     }
  714.     integer index = 0;
  715.     if( remove_boot )
  716.     {
  717.     foreach( map e, solution["solution","gap"]:[],
  718.         ``{
  719.         list nlist = [];
  720.         foreach( list a, e["added"]:[],
  721.         ``{
  722.         integer pindex = a[0]:0;
  723.         if( solution["partitions",pindex,"mount"]:"" == 
  724.             Partitions::BootMount() )
  725.             {
  726.             integer rest = a[2]:0;
  727.             y2milestone( "process_partition_data remove unneeded %3 %1 cyl %2", 
  728.                          e["added"]:[], rest, Partitions::BootMount() );
  729.             list<list> nlist = filter( list l, e["added"]:[], ``(l[0]:0!=pindex));
  730.             if( size(nlist)>0 && !e["exists"]:false )
  731.             {
  732.             list weight = maplist( list l, nlist, ``(l[2]:0) );
  733.             map r = $[];
  734.             r = distribute_space( rest, weight, nlist, 
  735.                                   solution["partitions"]:[] );
  736.             nlist = eval(r["added"]:[]);
  737.             solution["solution","gap",index,"cylinders"] = 
  738.                 e["cylinders"]:0 - r["diff"]:0;
  739.             }
  740.             solution["solution","gap",index,"added"] = eval(nlist);
  741.             }
  742.         pindex = pindex+1;
  743.         });
  744.         index = index + 1;
  745.         });
  746.     }
  747.     if( solution["solution","resize_ext"]:0>0 )
  748.     {
  749.     disk["partitions"] = maplist( map p, disk["partitions"]:[],
  750.         ``{
  751.         if( p["type"]:`unknown==`extended )
  752.             {
  753.             p["resize"] = true;
  754.             p["ignore_fs"] = true;
  755.             p["region",1] = solution["solution","resize_ext"]:0 -
  756.                     p["region",0]:0 + 1;
  757.             p["size_k"] = p["region",1]:0 * disk["cyl_size"]:0 / 1024;
  758.             y2milestone( "process_partition_data resize ext %1", p );
  759.             }
  760.         return( p );
  761.         });
  762.     }
  763.     foreach( map e, solution["solution","gap"]:[],
  764.     ``{
  765.     y2milestone( "process_partition_data e %1", e );
  766.     if( e["exists"]:false )
  767.         {
  768.         integer index = 0;
  769.         integer pindex = e["added",0,0]:0;
  770.         string mount = solution["partitions",pindex,"mount"]:"";
  771.         integer fsid = Partitions::fsid_native;
  772.         if( mount == "swap" )
  773.         {
  774.         fsid = Partitions::fsid_swap;
  775.         }
  776.         if( solution["partitions",pindex,"id"]:0 != 0 )
  777.         {
  778.         fsid = solution["partitions",pindex,"id"]:0;
  779.         }
  780.         foreach( map p, disk["partitions"]:[],
  781.         ``{
  782.         if( p["nr"]:0 == e["added",0,1]:0 )
  783.             {
  784.             y2milestone( "process_partition_data reuse part %1", p );
  785.             p["format"] = true;
  786.             p["mount"] = mount;
  787.             p["used_fs"] = 
  788.             solution["partitions",pindex,"fsys"]:Partitions::DefaultFs();
  789.             value = solution["partitions",pindex,"fstopt"]:"";
  790.             if( size(value)>0 )
  791.             {
  792.             p["fstopt"] = value;
  793.             }
  794.             else
  795.             {
  796.             p["fstopt"] = FileSystems::DefaultFstabOptions( p );
  797.             }
  798.             p["fs_options"] = FileSystems::DefaultFormatOptions( p );
  799.             value = solution["partitions",pindex,"fopt"]:"";
  800.             if( size(value)>0 )
  801.             {
  802.             p["format_opt"] = value;
  803.             }
  804.             value = solution["partitions",pindex,"label"]:"";
  805.             if( size(value)>0 )
  806.             {
  807.             p["label"] = value;
  808.             }
  809.             if( p["fsid"]:0 != fsid )
  810.             {
  811.             p["change_fsid"] = true;
  812.             p["ori_fsid"] = p["fsid"]:0;
  813.             p["fsid"] = fsid;
  814.             }
  815.             if( size(mount)==0 && size(vgname)>0 &&
  816.                 p["type"]:`unknown!=`extended )
  817.             p["vg"] = vgname;
  818.             disk["partitions",index] = p;
  819.             y2milestone( "process_partition_data reuse auto part %1", p );
  820.             }
  821.         else if( (size(vgname)>0||e["resize"]:0>0) && 
  822.                   p["nr"]:0 == e["nr"]:0 )
  823.             {
  824.             if( e["fsid"]:0!=0 && e["fsid"]:0!=p["fsid"]:0 )
  825.             {
  826.             p["change_fsid"] = true;
  827.             p["ori_fsid"] = p["fsid"]:0;
  828.             p["fsid"] = e["fsid"]:0;
  829.             }
  830.             if( e["resize"]:0>0 )
  831.             {
  832.             p["resize"] = true;
  833.             p["ignore_fs"] = true;
  834.             p["region",1] = e["resize"]:0 - p["region",0]:0 + 1;
  835.             p["size_k"] = p["region",1]:0 * 
  836.                           disk["cyl_size"]:0 / 1024;
  837.             }
  838.             if( size(vgname)>0 )
  839.             p["vg"] = vgname;
  840.             disk["partitions",index] = p;
  841.             y2milestone( "process_partition_data resize part %1", p );
  842.             }
  843.         index = index + 1;
  844.         });
  845.         }
  846.     else
  847.         {
  848.         list region = [ e["start"]:0, e["end"]:0-e["start"]:0+1 ];
  849.         map part = $[];
  850.         if( e["extended"]:false && e["created"]:0 > 0 )
  851.         {
  852.         while( e["added",0,1]:(disk["max_primary"]:4+1) <= 
  853.             disk["max_primary"]:4 )
  854.             {
  855.             integer pindex = e["added",0,0]:0;
  856.             string mount = solution["partitions",pindex,"mount"]:"";
  857.             integer fsid = Partitions::fsid_native;
  858.             part["format"] = true;
  859.             if( mount == "swap" )
  860.             {
  861.             fsid = Partitions::fsid_swap;
  862.             }
  863.             part["create"] = true;
  864.             part["nr"] = e["created"]:0;
  865.             part["device"] = Storage::GetDeviceName( dev, part["nr"]:-1 );
  866.             part["region"] = region;
  867.             part["region",1] = e["added",0,2]:0;
  868.             region[0] = region[0]:0 + part["region",1]:0;
  869.             region[1] = region[1]:0 - part["region",1]:0;
  870.             part["type"] = `primary;
  871.             if( solution["partitions",pindex,"id"]:0 != 0 )
  872.             {
  873.             fsid = solution["partitions",pindex,"id"]:0;
  874.             if( !haskey( solution["partitions",pindex]:$[], "fsys" ))
  875.                 {
  876.                 part["format"] = false;
  877.                 }
  878.             }
  879.             part["size_k"] = part["region",1]:0 * disk["cyl_size"]:0 / 1024;
  880.             part["mount"] = mount;
  881.             part["used_fs"] = 
  882.             solution["partitions",pindex,"fsys"]:Partitions::DefaultFs();
  883.             value = solution["partitions",pindex,"fstopt"]:"";
  884.             if( size(value)>0 )
  885.             {
  886.             part["fstopt"] = value;
  887.             }
  888.             else
  889.             {
  890.             part["fstopt"] = FileSystems::DefaultFstabOptions( part );
  891.             }
  892.             part["fs_options"] = FileSystems::DefaultFormatOptions( part );
  893.             value = solution["partitions",pindex,"fopt"]:"";
  894.             if( size(value)>0 )
  895.             {
  896.             part["format_opt"] = value;
  897.             }
  898.             value = solution["partitions",pindex,"label"]:"";
  899.             if( size(value)>0 )
  900.             {
  901.             part["label"] = value;
  902.             }
  903.             part["fsid"] = fsid;
  904.             part["fstype"] = Partitions::FsIdToString( fsid );
  905.             if( size(mount)==0 && size(vgname)>0 )
  906.             part["vg"] = vgname;
  907.             y2milestone( "process_partition_data auto partition %1", part );
  908.             partitions = add( partitions, part );
  909.             e["created"] = e["added",0,1]:0;
  910.             e["added"] = remove( e["added"]:[], 0 );
  911.             part = $[];
  912.             }
  913.         part["create"] = true;
  914.         part["nr"] = e["created"]:0;
  915.         part["device"] = Storage::GetDeviceName( dev, part["nr"]:-1 );
  916.         part["region"] = eval(region);
  917.         part["type"] = `extended;
  918.         part["fsid"] = Partitions::fsid_extended_win;
  919.         part["fstype"] = Partitions::FsIdToString( part["fsid"]:0 );
  920.         part["size_k"] = region[1]:0 * disk["cyl_size"]:0 / 1024;
  921.         y2milestone( "process_partition_data extended auto partition %1", part );
  922.         partitions = add( partitions, eval(part));
  923.         }
  924.         foreach( list a, e["added"]:[],
  925.         ``{
  926.         part = $[];
  927.         integer pindex = a[0]:0;
  928.         string mount = solution["partitions",pindex,"mount"]:"";
  929.         integer fsid = Partitions::fsid_native;
  930.         part["format"] = true;
  931.         if( mount == "swap" )
  932.             {
  933.             fsid = Partitions::fsid_swap;
  934.             }
  935.         if( solution["partitions",pindex,"id"]:0 != 0 )
  936.             {
  937.             fsid = solution["partitions",pindex,"id"]:0;
  938.             if( !haskey( solution["partitions",pindex]:$[], "fsys" ))
  939.             {
  940.             part["format"] = false;
  941.             }
  942.             y2milestone( "process_partition_data partition id %1 format %2 part %3", 
  943.                          fsid, part["format"]:false, 
  944.                  solution["partitions",pindex]:$[] );
  945.             }
  946.         part["create"] = true;
  947.         part["nr"] = a[1]:0;
  948.         part["device"] = Storage::GetDeviceName( dev, part["nr"]:0 );
  949.         region[1] = a[2]:0;
  950.         part["region"] = eval(region);
  951.         region[0] = region[0]:0 + region[1]:0;
  952.         part["size_k"] = region[1]:0 * disk["cyl_size"]:0 / 1024;
  953.         part["type"] = `primary;
  954.         if( e["extended"]:false )
  955.             {
  956.             part["type"] = `logical;
  957.             }
  958.         part["mount"] = mount;
  959.         part["used_fs"] = 
  960.             solution["partitions",pindex,"fsys"]:Partitions::DefaultFs();
  961.         value = solution["partitions",pindex,"fstopt"]:"";
  962.         if( size(value)>0 )
  963.             {
  964.             part["fstopt"] = value;
  965.             }
  966.         else
  967.             {
  968.             part["fstopt"] = FileSystems::DefaultFstabOptions( part );
  969.             }
  970.         part["fs_options"] = FileSystems::DefaultFormatOptions( part );
  971.         value = solution["partitions",pindex,"fopt"]:"";
  972.         if( size(value)>0 )
  973.             {
  974.             part["format_opt"] = value;
  975.             }
  976.         value = solution["partitions",pindex,"label"]:"";
  977.         if( size(value)>0 )
  978.             {
  979.             part["label"] = value;
  980.             }
  981.         part["fsid"] = fsid;
  982.         part["fstype"] = Partitions::FsIdToString( fsid );
  983.         if( size(mount)==0 && size(vgname)>0 )
  984.             part["vg"] = vgname;
  985.         y2milestone( "process_partition_data auto partition %1", part );
  986.         partitions = add( partitions, eval(part));
  987.         });
  988.         partitions = sort( map a, map b, partitions, ``(a["nr"]:0<b["nr"]:0));
  989.         }
  990.     });
  991.     disk["partitions"] = union( disk["partitions"]:[], partitions );
  992.     y2milestone( "process_partition_data disk %1", disk );
  993.     return( disk );
  994.     }
  995.  
  996. define map add_cylinder_info( map conf, map gap )
  997.     ``{
  998.     integer cyl_size = gap["cyl_size"]:1;
  999.     conf["partitions"] = 
  1000.     sort( map a, map b, conf["partitions"]:[],
  1001.           ``({
  1002.           if( a["primary"]:false != b["primary"]:false )
  1003.           return( true );
  1004.           else if( a["max_cyl"]:big_cyl != b["max_cyl"]:big_cyl )
  1005.           return( a["max_cyl"]:big_cyl < b["max_cyl"]:big_cyl );
  1006.           else
  1007.           return( a["size"]:0 < b["size"]:0 );
  1008.           }));
  1009.     y2milestone( "add_cylinder_info parts %1", conf["partitions"]:[] );
  1010.     integer sum = 0;
  1011.     conf["partitions"] = maplist( map p, conf["partitions"]:[],
  1012.     ``{
  1013.     sum = sum + p["pct"]:0;
  1014.     p["cylinders"] = (p["size"]:0+cyl_size-1)/cyl_size;
  1015.     if( p["cylinders"]:0 == 0 )
  1016.         {
  1017.         p["cylinders"] = 1;
  1018.         }
  1019.     return( p );
  1020.     });
  1021.     y2milestone( "add_cylinder_info sum %1", sum );
  1022.     y2milestone( "add_cylinder_info parts %1", conf["partitions"]:[] );
  1023.     if( sum>100 )
  1024.     {
  1025.     integer rest = sum - 100;
  1026.     conf["partitions"] = maplist( map p, conf["partitions"]:[],
  1027.         ``{
  1028.         if( haskey( p, "pct" ) )
  1029.         {
  1030.         integer pct = p["pct"]:0;
  1031.         integer diff = ((rest * pct) + sum/2) / sum;
  1032.         sum = sum - pct;
  1033.         rest = rest - diff;
  1034.         p["pct"] = pct - diff;
  1035.         }
  1036.         return( p );
  1037.         });
  1038.     }
  1039.     conf["partitions"] = maplist( map p, conf["partitions"]:[],
  1040.     ``{
  1041.     if( haskey( p, "pct" ) )
  1042.         {
  1043.         integer cyl = gap["sum"]:0 / 100 * p["pct"]:0;
  1044.         cyl = (cyl+cyl_size/2) / cyl_size;
  1045.         if( cyl == 0 )
  1046.         {
  1047.         cyl = 1;
  1048.         }
  1049.         p["want_cyl"] = cyl;
  1050.         }
  1051.     if( p["maxsize"]:0 > 0 )
  1052.         {
  1053.         integer cyl = (p["maxsize"]:0+cyl_size-1) / cyl_size;
  1054.         p["size_max_cyl"] = cyl;
  1055.         if( p["want_cyl"]:0 > cyl )
  1056.         {
  1057.         p["want_cyl"] = cyl;
  1058.         }
  1059.         }
  1060.     return( p );
  1061.     });
  1062.     y2milestone( "add_cylinder_info parts %1", conf["partitions"]:[] );
  1063.     return( conf );
  1064.     }
  1065.  
  1066. define map get_perfect_list( list ps, map g )
  1067.     ``{
  1068.     y2milestone( "get_perfect_list ps %1", ps );
  1069.     y2milestone( "get_perfect_list gap %1", g );
  1070.     if( size(g["gap"]:[])>0 &&
  1071.         ((g["extended_possible"]:false && 
  1072.         size(g["free_pnr"]:[])>0 &&
  1073.         size(ps)+1 <= size(g["ext_pnr"]:[])+size(g["free_pnr"]:[])) ||
  1074.      (!g["extended_possible"]:false &&
  1075.         size(ps) <= size(g["ext_pnr"]:[])+size(g["free_pnr"]:[]))) )
  1076.     {
  1077.     map lg = (map) eval(g);
  1078.     lg["gap"] = maplist( map e, lg["gap"]:[], 
  1079.         ``{ 
  1080.         e["orig_cyl"] = e["cylinders"]:0;
  1081.         e["added"] = [];
  1082.         return( e );
  1083.         });
  1084.     lg["procpart"] = 0;
  1085.     list lp = (list) eval(ps);
  1086.     if( g["extended_possible"]:false && size(ps)+1>size(g["free_pnr"]:[]))
  1087.         {
  1088.         y2milestone( "get_perfect_list creating extended" );
  1089.         integer index = 0;
  1090.         foreach( map e, lg["gap"]:[], 
  1091.         ``{
  1092.         if( !e["exists"]:false )
  1093.             {
  1094.             map gap = (map) eval(lg);
  1095.             gap["gap",index,"created"] = gap["free_pnr",0]:1;
  1096.             gap["free_pnr"] = remove( gap["free_pnr"]:[1], 0 );
  1097.             gap["gap",index,"extended"] = true;
  1098.             add_part_recursive( ps, gap );
  1099.             }
  1100.         index = index+1;
  1101.         });
  1102.         }
  1103.     else
  1104.         {
  1105.         y2milestone( "get_perfect_list not creating extended" );
  1106.         add_part_recursive( ps, lg );
  1107.         }
  1108.     }
  1109.     map ret = $[];
  1110.     if( size(cur_gap)>0 )
  1111.     {
  1112.     ret["weight"] = cur_weight;
  1113.     ret["solution"] = eval(cur_gap);
  1114.     ret["partitions"] = eval(ps);
  1115.     }
  1116.     y2milestone( "get_perfect_list ret weight %1", ret["weight"]:-1000000 );
  1117.     y2milestone( "get_perfect_list ret solution %1", ret["solution","gap"]:[] );
  1118.     return( ret );
  1119.     }
  1120.  
  1121. define void add_part_recursive( list ps, map g )
  1122.     ``{
  1123.     y2milestone( "add_part_recursive pindex %1", g["procpart"]:0 );
  1124.     y2milestone( "add_part_recursive ps %1", ps );
  1125.     y2milestone( "add_part_recursive gap %1", g );
  1126.     map lg = (map) eval(g);
  1127.     integer gindex = 0;
  1128.     integer pindex = lg["procpart"]:0;
  1129.     map part = ps[pindex]:$[];
  1130.     lg["procpart"] = pindex + 1;
  1131.     y2milestone( "add_part_recursive p %1", part );
  1132.     foreach( map e, lg["gap"]:[], 
  1133.     ``{
  1134.     y2milestone( "add_part_recursive e %1", e );
  1135.     boolean max_cyl_ok = !haskey( part, "max_cyl" ) ||
  1136.                          part["max_cyl"]:0 >= e["end"]:0;
  1137.     if( !max_cyl_ok )
  1138.         {
  1139.         integer cyl = 0;
  1140.         foreach( list a, lg["gap",gindex,"added"]:[],
  1141.         ``{
  1142.         cyl = cyl + ps[a[0]:0,"cylinders"]:0;
  1143.         });
  1144.         cyl = cyl + part["cylinders"]:0;
  1145.         y2milestone( "max_cyl_ok cyl %1", cyl );
  1146.         max_cyl_ok = e["start"]:0 + cyl <= part["max_cyl"]:0;
  1147.         }
  1148.     y2milestone( "add_part_recursive max_cyl_ok %1", max_cyl_ok );
  1149.     if( max_cyl_ok && part["cylinders"]:0 <= e["cylinders"]:0 &&
  1150.         ((!e["extended"]:false && size(lg["free_pnr"]:[])>0) ||
  1151.          (part["primary"]:false && e["created"]:false && e["extended"]:false && size(lg["free_pnr"]:[])>0) || 
  1152.          (!part["primary"]:false && e["extended"]:false && size(lg["ext_pnr"]:[])>0)))
  1153.         {
  1154.         map llg = (map) eval(lg);
  1155.         if( e["exists"]:false )
  1156.         {
  1157.         llg["gap",gindex,"cylinders"] = 0;
  1158.         }
  1159.         else
  1160.         {
  1161.         llg["gap",gindex,"cylinders"] = 
  1162.             llg["gap",gindex,"cylinders"]:0 - part["cylinders"]:0;
  1163.         }
  1164.         list addl = [ pindex ];
  1165.         if( e["extended"]:false && !part["primary"]:false )
  1166.         {
  1167.         addl = add( addl, llg["ext_pnr",0]:5 );
  1168.         llg["ext_pnr"] = remove( llg["ext_pnr"]:[0], 0 );
  1169.         }
  1170.         else
  1171.         {
  1172.         addl = add( addl, llg["free_pnr",0]:1 );
  1173.         llg["free_pnr"] = remove( llg["free_pnr"]:[0], 0 );
  1174.         }
  1175.         llg["gap",gindex,"added"] = 
  1176.         add( llg["gap",gindex,"added"]:[], addl );
  1177.         if( pindex+1 < size(ps) )
  1178.         {
  1179.         add_part_recursive( ps, llg );
  1180.         }
  1181.         else
  1182.         {
  1183.         map ng = normalize_gaps(ps, llg);
  1184.         integer val = do_weighting( ps, ng );
  1185.         y2milestone( "add_part_recursive val %1 cur_weight %2 size %3", 
  1186.                      val, cur_weight, size(cur_gap));
  1187.         if( val > cur_weight || size(cur_gap)==0 )
  1188.             {
  1189.             cur_weight = val;
  1190.             cur_gap = (map)eval(ng);
  1191.             }
  1192.         }
  1193.         }
  1194.     gindex = gindex+1;
  1195.     });
  1196.     };
  1197.  
  1198. define map normalize_gaps( list ps, map g )
  1199.     ``{
  1200.     y2milestone( "normalize_gaps gap %1", g );
  1201.     integer gindex = 0;
  1202.     integer pindex = 0;
  1203.     foreach( map e, g["gap"]:[],
  1204.     ``{
  1205.     y2milestone( "normalize_gaps e %1", e );
  1206.     if( e["exists"]:false )
  1207.         {
  1208.         if( size(e["added"]:[])>0 && size(e["added",0]:[])==2 )
  1209.         {
  1210.         g["gap",gindex,"added",0] = 
  1211.             add( e["added",0]:[], e["orig_cyl"]:1 );
  1212.         }
  1213.         }
  1214.     else
  1215.         {
  1216.         integer rest = e["cylinders"]:0;
  1217.         integer needed = 0;
  1218.         integer tidx = 0;
  1219.         foreach( list p, e["added"]:[],
  1220.         ``{
  1221.         tidx = p[0]:0;
  1222.         if( ps[tidx,"want_cyl"]:0 > ps[tidx,"cylinders"]:0 )
  1223.             {
  1224.             needed = needed + ps[tidx,"want_cyl"]:0 -
  1225.                      ps[tidx,"cylinders"]:0;
  1226.             }
  1227.         });
  1228.         y2milestone( "normalize_gaps needed %1 rest %2", needed, rest );
  1229.         if( needed > rest )
  1230.         {
  1231.                 list tr = [];
  1232.         list weight = 
  1233.             maplist( list l, e["added"]:[], 
  1234.                  ``({
  1235.                  integer idx = l[0]:0;
  1236.                  integer d = ps[idx,"want_cyl"]:0 - 
  1237.                              ps[idx,"cylinders"]:0;
  1238.                              if( d>0 )
  1239.                  {
  1240.                  l = add( l, ps[idx,"cylinders"]:0 );
  1241.                  }
  1242.                  tr = add( tr, l );
  1243.                  return( d>0 ? d : 0 );
  1244.                  }));
  1245.             y2milestone( "normalize_gaps tr %1", tr );
  1246.         map r = $[];
  1247.         r = distribute_space( rest, weight, tr, ps );
  1248.         g["gap",gindex,"added"] = eval(r["added"]:[]);
  1249.         g["gap",gindex,"cylinders"] = e["cylinders"]:0 - r["diff"]:0;
  1250.         y2milestone( "normalize_gaps partly satisfy %1 cyl %2", 
  1251.                      g["gap",gindex,"added"]:[],
  1252.                  g["gap",gindex,"cylinders"]:0 );
  1253.         }
  1254.         else
  1255.         {
  1256.         g["gap",gindex,"cylinders"] = e["cylinders"]:0 - needed;
  1257.         }
  1258.  
  1259.         pindex = 0;
  1260.         foreach( list p, g["gap",gindex,"added"]:[], 
  1261.         ``{
  1262.         if( size(p)<3 )
  1263.             {
  1264.             tidx = p[0]:0;
  1265.             if( ps[tidx,"want_cyl"]:0 > ps[tidx,"cylinders"]:0 )
  1266.             {
  1267.             p = add( p, ps[tidx,"want_cyl"]:0 );
  1268.             }
  1269.             else
  1270.             {
  1271.             p = add( p, ps[tidx,"cylinders"]:0 );
  1272.             }
  1273.             g["gap",gindex,"added",pindex] = p;
  1274.             y2milestone( "normalize_gaps satisfy p %1 cyl %2", p, 
  1275.                          e["cylinders"]:0 );
  1276.             }
  1277.         pindex = pindex+1;
  1278.         });
  1279.         y2milestone( "normalize_gaps added %1", 
  1280.                      g["gap",gindex,"added"]:[] );
  1281.         }
  1282.     gindex = gindex + 1;
  1283.     });
  1284.     gindex = 0;
  1285.     foreach( map e, g["gap"]:[],
  1286.     ``{
  1287.     if( !e["exists"]:false && e["cylinders"]:0>0 )
  1288.         {
  1289.         list<integer> weight = maplist( list l, e["added"]:[], 
  1290.                                ``(ps[l[0]:0,"size"]:0==0 ? 1 : 0) );
  1291.         if( find( integer l, weight, ``(l>0) ) != nil ) 
  1292.         {
  1293.         map r = $[];
  1294.         r = distribute_space( e["cylinders"]:0, weight, e["added"]:[], 
  1295.                               ps );
  1296.         g["gap",gindex,"added"] = eval(r["added"]:[]);
  1297.         g["gap",gindex,"cylinders"] = e["cylinders"]:0 - r["diff"]:0;
  1298.         y2milestone( "normalize_gaps increase max p %1 cyl %2", 
  1299.                      g["gap",gindex,"added"]:[], 
  1300.                      g["gap",gindex,"cylinders"]:0 );
  1301.         }
  1302.         }
  1303.     gindex = gindex + 1;
  1304.     });
  1305.     gindex = 0;
  1306.     foreach( map e, g["gap"]:[],
  1307.     ``{
  1308.     if( !e["exists"]:false && e["cylinders"]:0>0 && 
  1309.         e["cylinders"]:0 < g["disk_cyl"]:0/20 )
  1310.         {
  1311.         list weight = maplist( list l, e["added"]:[], ``(l[2]:0) );
  1312.         map r = $[];
  1313.         r = distribute_space( e["cylinders"]:0, weight, e["added"]:[], ps );
  1314.         g["gap",gindex,"added"] = eval(r["added"]:[]);
  1315.         g["gap",gindex,"cylinders"] = e["cylinders"]:0 - r["diff"]:0;
  1316.         y2milestone( "normalize_gaps close small gap p %1 cyl %2", 
  1317.                      g["gap",gindex,"added"]:[], 
  1318.                      g["gap",gindex,"cylinders"]:0 );
  1319.         }
  1320.     gindex = gindex + 1;
  1321.     });
  1322.     gindex = 0;
  1323.     foreach( map e, g["gap"]:[],
  1324.     ``{
  1325.     if( !e["exists"]:false && e["cylinders"]:0>0 )
  1326.         {
  1327.         list<integer> weight = [];
  1328.         weight =
  1329.         maplist( list l, e["added"]:[], 
  1330.              ``((ps[l[0]:0,"increasable"]:false) ? 1 : 0));
  1331.         y2milestone( "normalize_gaps w %1", weight );
  1332.         if( find( integer l, weight, ``(l>0) ) != nil ) 
  1333.         {
  1334.         map r = $[];
  1335.         r = distribute_space( e["cylinders"]:0, weight, e["added"]:[], 
  1336.                       ps );
  1337.         g["gap",gindex,"added"] = eval(r["added"]:[]);
  1338.         g["gap",gindex,"cylinders"] = e["cylinders"]:0 - r["diff"]:0;
  1339.         e["cylinders"] = g["gap",gindex,"cylinders"]:0;
  1340.         y2milestone( "normalize_gaps increase increasable p %1 cyl %2", 
  1341.                  g["gap",gindex,"added"]:[],
  1342.                  g["gap",gindex,"cylinders"]:0 );
  1343.         }
  1344.         }
  1345.         gindex = gindex + 1;
  1346.     });
  1347.     gindex = 0;
  1348.     foreach( map e, g["gap"]:[],
  1349.     ``{
  1350.     if( !e["exists"]:false && e["extended"]:false && e["created"]:0 > 0 &&
  1351.         size(e["added"]:[])==1 && e["cylinders"]:0==0 )
  1352.         {
  1353.         g["gap",gindex,"extended"] = false;
  1354.         g["gap",gindex,"added",0,1] = e["created"]:0;
  1355.         y2milestone( "normalize_gaps changed extended %1", 
  1356.                      g["gap",gindex]:$[] );
  1357.         }
  1358.     gindex = gindex + 1;
  1359.     });
  1360.     gindex = 0;
  1361.     map sort_map = $[ "/boot" : 0, "/boot/efi" : 0, "swap" : 1, 
  1362.                       "/" : 5, "/home" :6 ];
  1363.     foreach( map e, g["gap"]:[],
  1364.     ``{
  1365.     if( !e["exists"]:false && size(e["added"]:[])>1 )
  1366.         {
  1367.         y2milestone( "normalize_gaps old  added %1", e["added"]:[] );
  1368.         list nums = maplist( list l, e["added"]:[], ``(l[1]:-1));
  1369.         y2milestone( "normalize_gaps old nums %1", nums );
  1370.         list sdd = sort( list a, list b, e["added"]:[],
  1371.                  ``({
  1372.                  integer ai = a[0]:0;
  1373.                  integer bi = b[0]:0;
  1374.                  if( ps[ai,"primary"]:false != ps[bi,"primary"]:false )
  1375.                  return( ps[ai,"primary"]:false );
  1376.                  else if( ps[ai,"max_cyl"]:big_cyl != ps[bi,"max_cyl"]:big_cyl )
  1377.                  return( ps[ai,"max_cyl"]:big_cyl < ps[bi,"max_cyl"]:big_cyl );
  1378.                  else
  1379.                  return( sort_map[ps[ai,"mount"]:""]:3 < sort_map[ps[bi,"mount"]:""]:3);
  1380.                  }));
  1381.         integer idx = 0;
  1382.         foreach( list e, (list<list>)sdd, 
  1383.         ``{
  1384.         sdd[idx,1] = nums[idx]:0;
  1385.         idx = idx+1;
  1386.         });
  1387.         g["gap",gindex,"added"] = sdd;
  1388.         y2milestone( "normalize_gaps sort added %1", 
  1389.                      g["gap",gindex,"added"]:[] );
  1390.         }
  1391.     gindex = gindex + 1;
  1392.     });
  1393.     y2milestone( "normalize_gaps gap %1", g );
  1394.     return( g );
  1395.     };
  1396.  
  1397. define map distribute_space( integer rest, list weights, list added, list ps )
  1398.     ``{
  1399.     integer diff_sum = 0;
  1400.     integer sum = 0;
  1401.     integer index = 0;
  1402.     integer pindex = 0;
  1403.     integer scount = 0;
  1404.     y2milestone( "distribute_space rest %1 weights %2 added %3", rest, 
  1405.                  weights, added );
  1406.     integer loopcount=0;
  1407.     do
  1408.     {
  1409.     loopcount = loopcount+1;
  1410.     index = 0;
  1411.     sum = 0;
  1412.     scount = 0;
  1413.     foreach( list p, (list<list>)added,
  1414.         ``{
  1415.         pindex = p[0]:0;
  1416.         if( ps[pindex,"size_max_cyl"]:0==0 || 
  1417.             ps[pindex,"size_max_cyl"]:0 > p[2]:0)
  1418.         {
  1419.         sum = sum + weights[index]:0;
  1420.         y2milestone( "sum %1 weight %2 pindex %3", sum, 
  1421.                      weights[index]:0, pindex );
  1422.         scount = scount+1;
  1423.         }
  1424.         index = index+1;
  1425.         });
  1426.     index = 0;
  1427.     y2milestone( "distribute_space sum %1 rest %2 scount %3 added %4 lc %5",
  1428.                  sum, rest, scount, added, loopcount );
  1429.     foreach( list p, (list<list>)added,
  1430.         ``{
  1431.         pindex = p[0]:0;
  1432.         if( size(p)==3 && sum>0 &&
  1433.         (ps[pindex,"size_max_cyl"]:0==0 ||
  1434.          ps[pindex,"size_max_cyl"]:0 > p[2]:0) )
  1435.         {
  1436.         integer diff = ((rest*weights[index]:0) + sum/2) / sum;
  1437.         if( ps[pindex,"size_max_cyl"]:0>0 && 
  1438.             diff > ps[pindex,"size_max_cyl"]:0-p[2]:0 )
  1439.             {
  1440.             diff = ps[pindex,"size_max_cyl"]:0-p[2]:0;
  1441.             }
  1442.         sum = sum - weights[index]:0;
  1443.         rest = rest - diff;
  1444.         added[index,2] = added[index,2]:0 + diff;
  1445.         diff_sum = diff_sum + diff;
  1446.         y2milestone( "distribute_space sum %1 rest %2 diff %3 added %4", 
  1447.                  sum, rest, diff, added[index]:[] );
  1448.         }
  1449.         index = index+1;
  1450.         });
  1451.     }
  1452.     while( rest>0 && scount>0 && loopcount<3 );
  1453.     map ret = $[ "added":added, "diff" : diff_sum ];
  1454.     y2milestone( "distribute_space ret %1", ret );
  1455.     return( ret );
  1456.     }
  1457.  
  1458. define integer do_weighting( list ps, map g )
  1459.     ``{
  1460.     y2milestone( "do_weighting gap %1", g["gap"]:[] );
  1461.     integer ret = 0;
  1462.     integer index = 0;
  1463.     integer diff = 0;
  1464.     if( cur_mode == `reuse )
  1465.     {
  1466.     ret = ret - 100;
  1467.     }
  1468.     else if( cur_mode == `resize )
  1469.     {
  1470.     ret = ret - 1000;
  1471.     }
  1472.     else if( cur_mode == `desparate )
  1473.     {
  1474.     ret = ret - 1000000;
  1475.     }
  1476.     y2milestone( "do_weighting after mode ret %1", ret );
  1477.     foreach( map e, g["gap"]:[],
  1478.     ``{
  1479.     y2milestone( "do_weighting e %1", e );
  1480.     if( !e["exists"]:false && e["cylinders"]:0 > 0 )
  1481.         {
  1482.         diff = -5;
  1483.         if( e["cylinders"]:0 < g["disk_cyl"]:0/20 )
  1484.         {
  1485.         diff = diff - 10;
  1486.         }
  1487.         ret = ret + diff;
  1488.         y2milestone( "do_weighting after gaps diff %1 ret %2", diff, ret );
  1489.         }
  1490.     foreach( list p, e["added"]:[], 
  1491.         ``{
  1492.         index = p[0]:0;
  1493.         if( e["exists"]:false && ps[index,"mount"]:""=="swap" && 
  1494.             e["swap"]:false )
  1495.         {
  1496.         diff = 100;
  1497.         ret = ret + diff;
  1498.         y2milestone( "do_weighting after swap reuse diff %1 ret %2", 
  1499.                      diff, ret );
  1500.         }
  1501.         if( ps[index,"want_cyl"]:0>0 )
  1502.         {
  1503.         diff = ps[index,"want_cyl"]:0 - p[2]:0;
  1504.         integer normdiff = diff * 100 / p[2]:0;
  1505.         if( diff < 0 )
  1506.             {
  1507.             normdiff = -normdiff;
  1508.             }
  1509.         else if( diff > 0 )
  1510.             {
  1511.             normdiff = normdiff / 10;
  1512.             }
  1513.         diff = ps[index,"want_cyl"]:0*g["cyl_size"]:1 / (100*1024*1024) -
  1514.                normdiff;
  1515.         ret = ret + diff;
  1516.         y2milestone( "do_weighting after pct parts diff %1 ret %2", 
  1517.                      diff, ret );
  1518.         }
  1519.         if( ps[index,"size"]:0==0 )
  1520.         {
  1521.         diff = p[2]:0 * g["cyl_size"]:1 / (50 * 1024 * 1024);
  1522.         ret = ret + diff;
  1523.         y2milestone( "do_weighting after maximizes parts diff %1 ret %2", 
  1524.                      diff, ret );
  1525.         }
  1526.         if( ps[index,"size_max_cyl"]:0 > 0 && 
  1527.         ps[index,"size_max_cyl"]:0 < p[2]:0 )
  1528.         {
  1529.         diff = p[2]:0 - ps[index,"size_max_cyl"]:0;
  1530.         integer normdiff = diff * 100 / ps[index,"size_max_cyl"]:0;
  1531.         ret = ret - normdiff;
  1532.         y2milestone( "do_weighting after maximal size diff %1 ret %2", 
  1533.                      -normdiff, ret );
  1534.         }
  1535.         });
  1536.     if( size(e["added"]:[])>0 && e["cylinders"]:0 > 0 )
  1537.         {
  1538.         integer diff = (e["cylinders"]:0 * g["cyl_size"]:1) / (1024*1024*1024);
  1539.         ret = ret - diff;
  1540.         y2milestone( "do_weighting after gap size diff %1 ret %2", -diff, ret );
  1541.         }
  1542.     if( e["extended"]:false )
  1543.         ret = ret-1;
  1544.     y2milestone( "do_weighting %1", ret );
  1545.     });
  1546.     y2milestone( "do_weighting ret %1", ret );
  1547.     return( ret );
  1548.     };
  1549.  
  1550. define list<map> try_remove_sole_extended( list<map> parts )
  1551.     {
  1552.     list<map> ret = parts;
  1553.     if( find( map p, ret,
  1554.           ``(p["type"]:`unknown==`extended &&
  1555.          !p["delete"]:false))!=nil &&
  1556.     find( map p, ret,
  1557.           ``(p["type"]:`unknown==`logical &&
  1558.          !p["delete"]:false))==nil )
  1559.     {
  1560.     ret = maplist( map p, ret,
  1561.         ``{
  1562.         if( p["type"]:`unknown == `extended )
  1563.         p["delete"] = true;
  1564.         return( p );
  1565.         });
  1566.     y2milestone( "try_remove_sole_extended delete extended p:%1", ret );
  1567.     }
  1568.     return( ret );
  1569.     }
  1570.  
  1571. define map remove_possible_partitions( map disk, map conf )
  1572.     ``{
  1573.     map ret = (map)eval(disk);
  1574.     ret["partitions"] = maplist( map p, ret["partitions"]:[],
  1575.     ``{
  1576.     integer fsid = p["fsid"]:0;
  1577.     if( (conf["remove_special_partitions"]:false ||
  1578.         !contains( Partitions::do_not_delete, fsid ) ) &&
  1579.         p["type"]:`primary != `extended &&
  1580.         !contains( conf["keep_partition_num"]:[], p["nr"]:0 ) &&
  1581.         !contains( conf["keep_partition_id"]:[], fsid ) &&
  1582.         !contains( conf["keep_partition_fsys"]:[], p["used_fs"]:`none ))
  1583.         {
  1584.         p["delete"] = true;
  1585.         }
  1586.     return( p );
  1587.     });
  1588.     ret["partitions"] = try_remove_sole_extended( ret["partitions"]:[] );
  1589.     return( ret );
  1590.     };
  1591.  
  1592. define map try_resize_windows( map disk )
  1593.     ``{
  1594.     integer cyl_size = disk["cyl_size"]:1;
  1595.     map win = $[];
  1596.     map ret = (map)eval(disk);
  1597.  
  1598.     ret["partitions"] = maplist( map p, ret["partitions"]:[],
  1599.     ``{
  1600.     integer fsid = p["fsid"]:0;
  1601.     if( Partitions::IsDosWinNtPartition( fsid ) ) 
  1602.         {
  1603.         win = p["winfo"]:$[];
  1604.         y2milestone( "try_resize_windows win=%1", win );
  1605.         if( win != nil && win["ok"]:false && p["size_k"]:0 > 1024*1024 )
  1606.         {
  1607.         p["winfo"] = win;
  1608.         p["resize"] = true;
  1609.         p["region",1] = (win["new_size"]:0 + cyl_size - 1) / cyl_size;
  1610.         p["win_max_length"] = 
  1611.             (win["max_win_size"]:0 + cyl_size - 1) / cyl_size;
  1612.         y2milestone( "try_resize_windows win part %1", p );
  1613.         }
  1614.         }
  1615.     return( p );
  1616.     });
  1617.     return( ret );
  1618.     };
  1619.  
  1620. define list<map> get_gaps( integer start, integer end, list<map> part, 
  1621.                boolean add_exist_linux )
  1622.     ``{
  1623.     y2milestone( "get_gaps start %1 end %2 add_exist %3", start, end, 
  1624.                  add_exist_linux );
  1625.     list<map> ret = [];
  1626.     map entry = $[];
  1627.     foreach( map p, part, 
  1628.     ``{
  1629.     integer s = p["region",0]:0;
  1630.     integer e = s + p["region",1]:1 - 1;
  1631.     entry = $[];
  1632.     if( start < s )
  1633.         {
  1634.         entry["start"] = start;
  1635.         entry["end"] = s-1;
  1636.         ret = add( ret, eval(entry) );
  1637.         }
  1638.     if( add_exist_linux && size(p["mount"]:"")==0 &&
  1639.         (p["fsid"]:0==Partitions::fsid_native || 
  1640.          p["fsid"]:0==Partitions::fsid_swap) )
  1641.         {
  1642.         entry["swap"] = p["fsid"]:0==Partitions::fsid_swap;
  1643.         entry["start"] = s;
  1644.         entry["end"] = e;
  1645.         entry["exists"] = true;
  1646.         entry["nr"] = p["nr"]:0;
  1647.         ret = add( ret, entry );
  1648.         }
  1649.     start = e+1;
  1650.     });
  1651.     if( start < end )
  1652.     {
  1653.     entry = $[];
  1654.     entry["start"] = start;
  1655.     entry["end"] = end;
  1656.     ret = add( ret, entry );
  1657.     }
  1658.     y2milestone( "get_gaps ret %1", ret );
  1659.     return( ret );
  1660.     }
  1661.  
  1662.  
  1663. define map get_gap_info( map disk, boolean add_exist_linux )
  1664.     ``{
  1665.     map ret = $[];
  1666.     list<map> gap = [];
  1667.     list<map> plist = filter( map p, disk["partitions"]:[], 
  1668.                               ``(!p["delete"]:false) );
  1669.     plist = sort( map a, map b, plist, ``(a["region",0]:0<b["region",0]:0) );
  1670.     list<integer> exist_pnr = sort( maplist( map e, plist, ``(e["nr"]:0) ));
  1671.     if( disk["label"]:""=="mac" && !contains( exist_pnr, 1 ) )
  1672.     {
  1673.     exist_pnr = add( exist_pnr, 1 );
  1674.     }
  1675.     integer max_prim = Partitions::MaxPrimary(disk["label"]:"msdos");
  1676.     boolean has_ext = Partitions::HasExtended( disk["label"]:"msdos" );
  1677.     if( has_ext )
  1678.     {
  1679.     map ext = filter( map p, plist,
  1680.               ``(p["type"]:`primary == `extended))[0]:$[];
  1681.     ret["extended_possible"] = size(ext)==0;
  1682.     ret["ext_reg"] = ext["region"]:[];
  1683.     if( size(ext)>0 )
  1684.         {
  1685.         gap = get_gaps( ext["region",0]:0, 
  1686.                 ext["region",0]:0 + ext["region",1]:1-1, 
  1687.                 filter( map p, plist, ``(p["nr"]:0>max_prim)),
  1688.                 add_exist_linux );
  1689.         gap = maplist( map e, gap, 
  1690.         ``{
  1691.         e["extended"]=true;
  1692.         return e;
  1693.         });
  1694.         plist = filter( map p, plist, ``(p["nr"]:0<=max_prim));
  1695.         }
  1696.     }
  1697.     else
  1698.     {
  1699.     ret["extended_possible"] = false;
  1700.     }
  1701.     gap = (list<map>)union( gap, 
  1702.          get_gaps( 0, disk["cyl_count"]:1-1, plist, add_exist_linux ));
  1703.     integer av_size = 0;
  1704.     gap = maplist( map e, gap,
  1705.     ``{
  1706.     e["cylinders"] = e["end"]:0 - e["start"]:0 + 1;
  1707.     e["size"] = e["cylinders"]:0 * disk["cyl_size"]:1;
  1708.     av_size = av_size + e["size"]:0;
  1709.     return( e );
  1710.     });
  1711.     gap = maplist( map e, gap,
  1712.     ``{
  1713.     e["sizepct"] = (e["size"]:0 * 201 / 2) / av_size;
  1714.     if( e["sizepct"]:0 == 0 )
  1715.         {
  1716.         e["sizepct"] = 1;
  1717.         }
  1718.     return( e );
  1719.     });
  1720.     ret["cyl_size"] = disk["cyl_size"]:1;
  1721.     ret["disk_cyl"] = disk["cyl_count"]:1;
  1722.     ret["sum"] = av_size;
  1723.     integer max_pnr = max_prim;
  1724.     integer pnr = 1;
  1725.     list free_pnr = [];
  1726.     y2milestone( "get_gap_info exist_pnr %1", exist_pnr );
  1727.     while( pnr<=max_pnr )
  1728.     {
  1729.     if( !contains( exist_pnr, pnr ) )
  1730.         {
  1731.         free_pnr = add( free_pnr, pnr );
  1732.         }
  1733.     pnr = pnr + 1;
  1734.     }
  1735.     ret["free_pnr"] = free_pnr;
  1736.     list<integer> ext_pnr = [ 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
  1737.             25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,
  1738.             45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63];
  1739.     integer max_logical = disk["max_logical"]:15;
  1740.     if( max_logical<63 )
  1741.     {
  1742.     ext_pnr = filter( integer i, ext_pnr, ``(i<=max_logical));
  1743.     }
  1744.     if( !has_ext )
  1745.     {
  1746.     ext_pnr = [];
  1747.     }
  1748.     else
  1749.     {
  1750.     integer maxlog = size(filter( integer i, exist_pnr, ``(i>max_pnr))) + 4;
  1751.     ext_pnr = filter( integer i, ext_pnr, ``(i>maxlog));
  1752.     }
  1753.     ret["ext_pnr"] = ext_pnr;
  1754.     ret["gap"] = gap;
  1755.     y2milestone( "get_gap_info ret %1", ret );
  1756.     return( ret );
  1757.     }
  1758.  
  1759. /**
  1760.  * Read partition data from XML control file
  1761.  * @return map flexible propsal map
  1762.  */
  1763. define map read_partition_xml_config()
  1764.     ``{
  1765.  
  1766.     map xmlflex = (map)ProductFeatures::GetFeature ("partitioning", "flexible_partitioning");
  1767.     y2debug("xml input: %1", xmlflex );
  1768.  
  1769.     map conf = $[];
  1770.     conf["prefer_remove"] = xmlflex["prefer_remove"]:true;
  1771.     conf["remove_special_partitions"] =
  1772.     xmlflex["remove_special_partitions"]:false;
  1773.     conf["keep_partition_id"] = [];
  1774.     conf["keep_partition_num"] = [];
  1775.     conf["keep_partition_fsys"] = [];
  1776.  
  1777.     foreach( string key, [ "keep_partition_id", "keep_partition_num"], ``{
  1778.     list num = [];
  1779.     list<string> nlist = splitstring(xmlflex[key]:"", ",");
  1780.     foreach( string n, nlist, ``{ num = union( num, [tointeger(n)] );});
  1781.     conf[key] = num;
  1782.     });
  1783.  
  1784.     list fsys = [];
  1785.     list<string> nlist = splitstring( xmlflex["keep_partition_fsys"]:"" , "," );
  1786.     foreach( string n, nlist,
  1787.          ``{
  1788.     symbol fs = FileSystems::FsToSymbol(n);
  1789.     if( fs != `none )
  1790.     {
  1791.         fsys = union( fsys, [ fs ] );
  1792.     }
  1793.     });
  1794.     conf["keep_partition_fsys"] = fsys;
  1795.     list partitions = [];
  1796.     foreach(map p, xmlflex["partitions"]:[],
  1797.         ``{
  1798.     map partition = $[];
  1799.  
  1800.     if (p["disk"]:0 != 0)
  1801.     {
  1802.         partition["disk"] = p["disk"]:0;
  1803.     }
  1804.     if (p["id"]:0 != 0)
  1805.     {
  1806.         partition["id"] = p["id"]:0;
  1807.     }
  1808.  
  1809.     if (p["fstopt"]:"" != "")
  1810.     {
  1811.         partition["fstopt"] = p["fstopt"]:"";
  1812.     }
  1813.  
  1814.     if (p["formatopt"]:"" != "")
  1815.     {
  1816.         partition["fopt"] = p["formatopt"]:"";
  1817.     }
  1818.  
  1819.     partition["increasable"] = p["increasable"]:false;
  1820.  
  1821.     if (p["mount"]:"" != "")
  1822.     {
  1823.         partition["mount"] = p["mount"]:"";
  1824.     }
  1825.  
  1826.     if (p["percent"]:-1 != -1)
  1827.     {
  1828.         partition["pct"] = p["percent"]:100;
  1829.     }
  1830.  
  1831.     if (p["label"]:"" != "")
  1832.     {
  1833.         partition["label"] = p["label"]:"";
  1834.     }
  1835.  
  1836.     if (p["maxsize"]:"" != "")
  1837.     {
  1838.         partition["maxsize"] = kmgt_str_to_byte(p["maxsize"]:"");
  1839.     }
  1840.  
  1841.     if (p["fsys"]:"" != "")
  1842.     {
  1843.         symbol fs = FileSystems::FsToSymbol(p["fsys"]:"");
  1844.         if( fs != `none )
  1845.         {
  1846.         partition["fsys"] = fs;
  1847.         }
  1848.     }
  1849.  
  1850.     if (p["size"]:"" != "")
  1851.     {
  1852.         string s = p["size"]:"";
  1853.         if( tolower(s) == "auto" )
  1854.         {
  1855.         partition["size"] = -1;
  1856.         }
  1857.         else if( tolower(s) == "max" )
  1858.         {
  1859.         partition["size"] = 0;
  1860.         }
  1861.         else
  1862.         {
  1863.         partition["size"] = kmgt_str_to_byte( s );
  1864.         }
  1865.  
  1866.     }
  1867.  
  1868.     if( partition["size"]:0 == -1 && partition["mount"]:"" == "swap" )
  1869.     {
  1870.         partition["size"] = 1024*1024*Partitions::SwapSizeMb(0);
  1871.     }
  1872.     if( partition["mount"]:"" == Partitions::BootMount() )
  1873.     {
  1874.         if( partition["size"]:0 == -1 )
  1875.         {
  1876.         partition["size"] = Partitions::MinimalNeededBootsize();
  1877.         }
  1878.         if( partition["fsys"]:`none == `none )
  1879.         {
  1880.         partition["fsys"] = Partitions::DefaultBootFs();
  1881.         }
  1882.         if( partition["id"]:0 == 0 )
  1883.         {
  1884.         partition["id"] = Partitions::FsidBoot();
  1885.         }
  1886.         partition["max_cyl"] = Partitions::BootCyl();
  1887.     }
  1888.     if( partition["size"]:0 == -1 )
  1889.     {
  1890.         partition["size"] = 0;
  1891.     }
  1892.  
  1893.     y2debug("partition: %1", partition);
  1894.     if( size(partition["mount"]:"")>0 || partition["id"]:0 > 0 )
  1895.     {
  1896.         partitions = add( partitions, partition );
  1897.     }
  1898.  
  1899.  
  1900.     });
  1901.     conf["partitions"] = partitions;
  1902.     if( size(partitions)==0 )
  1903.     {
  1904.     conf = $[];
  1905.     }
  1906.     else
  1907.     {
  1908.     conf["partitions"] = partitions;
  1909.     }
  1910.     y2milestone( "conf %1", conf );
  1911.     return( conf );
  1912.  
  1913.  
  1914.  
  1915. }
  1916.  
  1917.  
  1918. define map read_partition_config( string fpath )
  1919.     ``{
  1920.     integer pos = 0;
  1921.     string line = "";
  1922.     string rex = "";
  1923.     map conf = $[];
  1924.  
  1925.     conf["prefer_remove"] = true;
  1926.     conf["remove_special_partitions"] = false;
  1927.     conf["keep_partition_id"] = [];
  1928.     conf["keep_partition_num"] = [];
  1929.     conf["keep_partition_fsys"] = [];
  1930.  
  1931.     string cstring = (string) SCR::Read( .target.string, fpath );
  1932.     list<string> lines = filter( string e, splitstring( cstring, "\n" ), ``(size(e)>0) );
  1933.     rex = "[ \t]*#.*";
  1934.     y2milestone( "lines %1", lines );
  1935.     lines = filter( string e, lines, ``(!regexpmatch( e, "[ \t]*#.*" )));
  1936.     y2milestone( "lines %1", lines );
  1937.     list fnd = [];
  1938.     foreach( string key, [ "PREFER_REMOVE", "REMOVE_SPECIAL_PARTITIONS" ],
  1939.     ``{
  1940.     rex = "[ \t]*" + key + "[ \t]*=";
  1941.     fnd = filter( string e, lines, ``(regexpmatch( e, rex )));
  1942.     y2milestone( "rex %1 fnd %2", rex, fnd );
  1943.     if( size(fnd)>0 )
  1944.         {
  1945.         line = deletechars( fnd[size(fnd)-1]:"", "\t " );
  1946.         pos = findlastof( line, "=" );
  1947.         if( pos > 0 )
  1948.         {
  1949.         conf[tolower(key)] = tointeger( substring( line, pos+1 ))>0;
  1950.         }
  1951.         }
  1952.     });
  1953.     foreach( string key, [ "KEEP_PARTITION_ID", "KEEP_PARTITION_NUM" ],
  1954.     ``{
  1955.     rex = "[ \t]*" + key + "[ \t]*=";
  1956.     y2milestone( "rex %1", rex );
  1957.     foreach( string l, filter( string e, lines, ``(regexpmatch( e, rex ))),
  1958.         ``{
  1959.         y2milestone( "line %1", l );
  1960.         line = deletechars( l, "\t " );
  1961.         pos = findlastof( line, "=" );
  1962.         if( pos > 0 )
  1963.         {
  1964.         list num = [];
  1965.         list<string> nlist = splitstring( substring( line, pos+1 ), "," );
  1966.         foreach( string n, nlist, ``{ num = union( num, [tointeger(n)] );});
  1967.         conf[tolower(key)] = union( conf[tolower(key)]:[], num );
  1968.         }
  1969.         });
  1970.     });
  1971.     list fsys = [];
  1972.     rex = "[ \t]*" + "KEEP_PARTITION_FSYS" + "[ \t]*=";
  1973.     foreach( string l, filter( string e, lines, ``(regexpmatch( e, rex ))),
  1974.     ``{
  1975.     y2milestone( "line %1", l );
  1976.     line = deletechars( l, "\t " );
  1977.     pos = findlastof( line, "=" );
  1978.     if( pos > 0 )
  1979.         {
  1980.         list<string> nlist = splitstring( substring( line, pos+1 ), "," );
  1981.         foreach( string n, nlist, 
  1982.         ``{ 
  1983.         symbol fs = FileSystems::FsToSymbol(n);
  1984.         if( fs != `none )
  1985.             {
  1986.             fsys = union( fsys, [ fs ] );
  1987.             }
  1988.         });
  1989.         }
  1990.     });
  1991.     conf["keep_partition_fsys"] = fsys;
  1992.     list partitions = [];
  1993.     map part = $[];
  1994.     rex = "[ \t]*" + "PARTITION" + "[ \t][ \t]*";
  1995.     foreach( string l, filter( string e, lines, ``(regexpmatch( e, rex ))),
  1996.     ``{
  1997.     y2milestone( "line %1", l );
  1998.     string par = "";
  1999.     string key = "";
  2000.     integer pos = search( l, "PARTITION" );
  2001.     line = substring( l, pos+10 );
  2002.     y2milestone( "line %1", line );
  2003.     pos = search( line, "=" );
  2004.     part = $[];
  2005.     while( pos!=nil )
  2006.         {
  2007.         key = deletechars( substring( line, 0, pos ), " \t" );
  2008.         line = substring( line, pos+1 );
  2009.         if( substring( line, 0, 1 ) == "\"" )
  2010.         {
  2011.         line = substring( line, 1 );
  2012.         pos = search( line, "\"" );
  2013.         par = substring( line, 0, pos );
  2014.         line = substring( line, pos+1 );
  2015.         }
  2016.         else
  2017.         {
  2018.         pos = findfirstof( line, " \t" );
  2019.         if( pos==nil )
  2020.             {
  2021.             par = line;
  2022.             }
  2023.         else
  2024.             {
  2025.             par = substring( line, 0, pos );
  2026.             line = substring( line, pos+1 );
  2027.             }
  2028.         }
  2029.         y2debug( "key %1 par \"%2\"", key, par );
  2030.         if( key == "id" )
  2031.         {
  2032.         part[key] = tointeger(par);
  2033.         }
  2034.         else if( key == "mount" )
  2035.         {
  2036.         part[key] = par;
  2037.         }
  2038.         else if( key == "increasable" )
  2039.         {
  2040.         part["increasable"] = tointeger(par)>0 ? true : false;
  2041.         }
  2042.         else if( key == "size" )
  2043.         {
  2044.         if( tolower(par) == "auto" )
  2045.             {
  2046.             part["size"] = -1;
  2047.             }
  2048.         else if( tolower(par) == "max" )
  2049.             {
  2050.             part["size"] = 0;
  2051.             }
  2052.         else
  2053.             {
  2054.             part["size"] = kmgt_str_to_byte( par );
  2055.             }
  2056.         }
  2057.         else if( key == "label" )
  2058.         {
  2059.         part[key] = par;
  2060.         }
  2061.         else if( key == "maxsize" )
  2062.         {
  2063.         part[key] = kmgt_str_to_byte( par );
  2064.         }
  2065.         else if( key == "sizepct" )
  2066.         {
  2067.         part["pct"] = tointeger(par);
  2068.         }
  2069.         else if( key == "disk" )
  2070.         {
  2071.         part[key] = tointeger(par);
  2072.         }
  2073.         else if( key == "fsys" )
  2074.         {
  2075.         symbol fs = FileSystems::FsToSymbol(par);
  2076.         if( fs != `none )
  2077.             {
  2078.             part[key] = fs;
  2079.             }
  2080.         }
  2081.         else if( key == "fstopt" )
  2082.         {
  2083.         part[key] = par;
  2084.         }
  2085.         else if( key == "formatopt" )
  2086.         {
  2087.         part["fopt"] = par;
  2088.         }
  2089.         pos = search( line, "=" );
  2090.         }
  2091.     y2milestone( "part %1", part );
  2092.     if( part["size"]:0 == -1 && part["mount"]:"" == "swap" )
  2093.         {
  2094.         part["size"] = 1024*1024*Partitions::SwapSizeMb(0);
  2095.         }
  2096.     if( part["mount"]:"" == Partitions::BootMount() )
  2097.         {
  2098.         if( part["size"]:0 == -1 )
  2099.         {
  2100.         part["size"] = Partitions::MinimalNeededBootsize();
  2101.         }
  2102.         if( part["fsys"]:`none == `none )
  2103.         {
  2104.         part["fsys"] = Partitions::DefaultBootFs();
  2105.         }
  2106.         if( part["id"]:0 == 0 )
  2107.         {
  2108.         part["id"] = Partitions::FsidBoot();
  2109.         }
  2110.         part["max_cyl"] = Partitions::BootCyl();
  2111.         }
  2112.     if( part["size"]:0 == -1 )
  2113.         {
  2114.         part["size"] = 0;
  2115.         }
  2116.     if( size(part["mount"]:"")>0 || part["id"]:0 > 0 )
  2117.         {
  2118.         partitions = add( partitions, part );
  2119.         }
  2120.     });
  2121.     conf["partitions"] = partitions;
  2122.     if( size(partitions)==0 )
  2123.     {
  2124.     conf = $[];
  2125.     }
  2126.     else
  2127.     {
  2128.     conf["partitions"] = partitions;
  2129.     }
  2130.     y2milestone( "conf %1", conf );
  2131.     return( conf );
  2132.     }
  2133.  
  2134. map can_swap_reuse( string disk, list<map> partitions, map<string,map> tgmap )
  2135.     {
  2136.     map ret = $[];
  2137.     y2milestone( "can_swap_reuse disk %1 partitions %2", disk, partitions );
  2138.     list<map> swaps = filter( map p, partitions,
  2139.                   ``(p["type"]:`unknown!=`free &&
  2140.                  !p["delete"]:false &&
  2141.                  p["detected_fs"]:`unknown==`swap));
  2142.     swaps = filter( map p, swaps, ``(Storage::CheckSwapable(p["device"]:"")));
  2143.     swaps = sort( map a, map b, swaps, ``(a["size_k"]:0>b["size_k"]:0));
  2144.     y2milestone( "can_swap_reuse swaps %1", swaps );
  2145.     if( swaps[0,"size_k"]:0 >= 128*1024 )
  2146.     {
  2147.     ret["partitions"] = 
  2148.         maplist( map p, partitions,
  2149.              ``{
  2150.              if( !p["delete"]:false &&
  2151.              p["device"]:""==swaps[0,"device"]:"" )
  2152.              {
  2153.              p["mount"] = "swap";
  2154.              if( haskey( p, "vg" ))
  2155.                  {
  2156.                  p = remove( p, "vg" );
  2157.                  if( p["change_fsid"]:false )
  2158.                  p["fsid"] = p["ori_fsid"]:Partitions::fsid_swap;
  2159.                  }
  2160.              }
  2161.              return( p );
  2162.              });
  2163.     }
  2164.     else 
  2165.     {
  2166.     swaps = [];
  2167.     map<string,map> tg = filter( string k, map d, tgmap,
  2168.                      ``(Storage::IsPartitionable(d)));
  2169.     if( haskey( tg, disk ))
  2170.         tg = remove( tg, disk );
  2171.     y2milestone( "can_swap_reuse tg wo %1", tg );
  2172.     foreach( string dev, map disk, tg,
  2173.         ``{
  2174.         list sw = filter( map p, disk["partitions"]:[],
  2175.                   ``(p["type"]:`unknown!=`extended &&
  2176.                  !p["delete"]:false &&
  2177.                  p["detected_fs"]:`unknown==`swap));
  2178.         y2milestone( "can_swap_reuse disk %1 sw %2", dev, sw );
  2179.         swaps = (list<map>)union( swaps, sw );
  2180.         });
  2181.     swaps = sort( map a, map b, swaps, ``(a["size_k"]:0>b["size_k"]:0));
  2182.     y2milestone( "can_swap_reuse swaps %1", swaps );
  2183.     if( swaps[0,"size_k"]:0 >= 256*1024 )
  2184.         {
  2185.         ret["targets"] = Storage::SetPartitionData( tgmap, 
  2186.                                                     swaps[0,"device"]:"",
  2187.                                 "mount", "swap" );
  2188.         ret["targets"] = Storage::DelPartitionData( ret["targets"]:$[], 
  2189.                                                     swaps[0,"device"]:"",
  2190.                                 "vg" );
  2191.         }
  2192.     }
  2193.     y2milestone( "can_swap_reuse ret %1", ret );
  2194.     return( ret );
  2195.     }
  2196.  
  2197. list<map> can_boot_reuse( string disk, string label, boolean boot,
  2198.                           integer max_prim, list<map> partitions )
  2199.     {
  2200.     list<map> ret = [];
  2201.     y2milestone( "can_boot_reuse boot %1", boot );
  2202.     if( boot && !Partitions::PrepBoot() )
  2203.     {
  2204.     y2milestone( "can_boot_reuse disk %1 max_prim %2 label %3 part %4", 
  2205.                  disk, max_prim, label, partitions );
  2206.     list<map> pl = [];
  2207.     pl = filter( map p, partitions, 
  2208.              ``(!p["delete"]:false &&
  2209.             p["size_k"]:0*1024 >= 
  2210.                 Partitions::MinimalRequiredBootsize()));
  2211.     map boot = find( map p, pl,
  2212.              ``((p["fsid"]:0 == Partitions::fsid_gpt_boot) ||
  2213.                 (p["fsid"]:0 == Partitions::FsidBoot() && 
  2214.                  p["size_k"]:0<500*1024)||
  2215.                 (p["detected_fs"]:`unknown==`hfs && 
  2216.                  p["boot"]:false && label=="mac") ||
  2217.                 (p["fsid"]:0 == Partitions::fsid_prep_chrp_boot &&
  2218.                  p["nr"]:0 <= max_prim &&
  2219.                  Partitions::PrepBoot())));
  2220.     if( boot != nil )
  2221.         {
  2222.         ret = maplist( map p, partitions,
  2223.                ``{
  2224.                if( !p["delete"]:false &&
  2225.                    p["device"]:""==boot["device"]:"" )
  2226.                    {
  2227.                    p["mount"] = Partitions::BootMount();
  2228.                    p["used_fs"] = Partitions::DefaultBootFs();
  2229.                    p["format"] = true;
  2230.                    p["fstopt"] = 
  2231.                    FileSystems::DefaultFstabOptions( p );
  2232.                    p["fs_options"] = 
  2233.                    FileSystems::DefaultFormatOptions( p );
  2234.                    }
  2235.                return( p );
  2236.                });
  2237.         }
  2238.     y2milestone( "can_boot_reuse ret %1", ret );
  2239.     }
  2240.     return( ret );
  2241.     }
  2242.  
  2243. list<map> can_mp_reuse( string mp, integer min, integer max,
  2244.                         list<map> partitions )
  2245.     {
  2246.     list<map> ret = [];
  2247.     y2milestone( "can_mp_reuse mp %1 min %2 max %3", mp, min, max );
  2248.     list<map> pl = [];
  2249.     pl = filter( map p, partitions, 
  2250.          ``(!p["delete"]:false &&
  2251.             p["fsid"]:Partitions::fsid_native == 
  2252.                 Partitions::fsid_native &&
  2253.             p["used_by_type"]:`UB_NONE == `UB_NONE &&
  2254.             size(p["mount"]:"")==0 &&
  2255.             p["size_k"]:0/1024 >= min &&
  2256.             (max==0 || p["size_k"]:0/1024 <= max)));
  2257.     y2milestone( "can_mp_reuse normal %1", pl );
  2258.     if( size(pl)>0 )
  2259.     {
  2260.     pl = sort( map a, map b, pl, ``(a["size_k"]:0>b["size_k"]:0));
  2261.     y2milestone( "can_mp_reuse sorted %1", pl );
  2262.     ret = maplist( map p, partitions,
  2263.                ``{
  2264.                if( !p["delete"]:false &&
  2265.                p["device"]:""==pl[0,"device"]:"" )
  2266.                {
  2267.                p["mount"] = mp;
  2268.                p["used_fs"] = Partitions::DefaultFs();
  2269.                p["format"] = true;
  2270.                p["fstopt"] = FileSystems::DefaultFstabOptions( p );
  2271.                p["fs_options"] = 
  2272.                    FileSystems::DefaultFormatOptions( p );
  2273.                }
  2274.                return( p );
  2275.                });
  2276.     }
  2277.     y2milestone( "can_mp_reuse ret %1", ret );
  2278.     return( ret );
  2279.     }
  2280.  
  2281. integer get_avail_size_mb( list<map> parts )
  2282.     {
  2283.     integer ret = 0;
  2284.     foreach( map pp, filter( map p, parts, ``(p["delete"]:false &&
  2285.                           p["type"]:`unknown!=`extended)),
  2286.          ``{
  2287.          ret = ret + pp["size_k"]:0/1024;
  2288.          });
  2289.     y2milestone( "get_avail_size_mb ret %1", ret );
  2290.     return( ret );
  2291.     }
  2292.  
  2293. list get_swap_sizes( integer space )
  2294.     {
  2295.     list l = [ Partitions::SwapSizeMb(0), Partitions::SwapSizeMb(space) ];
  2296.     y2milestone( "get_swap_sizes space %1 ret %2", space, l );
  2297.     return( l );
  2298.     }
  2299.  
  2300. list<map> get_proposal( boolean have_swap, map disk )
  2301.     {
  2302.     list<map> ret = [];
  2303.     y2milestone( "get_proposal have_swap:%1 disk %2", have_swap, disk );
  2304.     map root = $[ "mount" : "/", "increasable" : true,
  2305.                   "fsys" : Partitions::DefaultFs(), "size" : 0 ];
  2306.     map opts = Storage::GetControlCfg();
  2307.     map conf = $[ "partitions" : [] ];
  2308.     list swap_sizes = [];
  2309.     integer avail_size = get_avail_size_mb(disk["partitions"]:[]);
  2310.     if( !have_swap )
  2311.     {
  2312.     swap_sizes = get_swap_sizes( avail_size );
  2313.     map swap = $[ "mount" : "swap", "increasable" : true, "fsys" : `swap,
  2314.               "maxsize" : 2*1024*1024*1024,
  2315.               "size"  : swap_sizes[0]:256*1024*1024 ];
  2316.     conf["partitions"] = add( conf["partitions"]:[], swap );
  2317.     }
  2318.     conf["partitions"] = add( conf["partitions"]:[], root );
  2319.     map old_root = $[];
  2320.     if( Storage::ProposalHome() && opts["home_limit"]:0 < avail_size )
  2321.     {
  2322.     map home = $[ "mount" : "/home", "increasable" : true, 
  2323.                   "fsys" : Partitions::DefaultFs(), "size" : 512*1024*1024, 
  2324.               "pct" : 100-opts["root_percent"]:40 ];
  2325.     conf["partitions"] = maplist( map p, conf["partitions"]:[],
  2326.                       ``{
  2327.                       if( p["mount"]:""=="/" )
  2328.                       {
  2329.                       old_root = p;
  2330.                       p["pct"] = opts["root_percent"]:40;
  2331.                       p["maxsize"] = opts["root_max"]:0*1024*1024;
  2332.                       p["size"] = opts["root_base"]:0*1024*1024;
  2333.                       }
  2334.                       return( p );
  2335.                       });
  2336.     conf["partitions"] = add( conf["partitions"]:[], home );
  2337.     }
  2338.     map ps1 = do_flexible_disk_conf( disk, conf, false, false );
  2339.     if( size(old_root)>0 && !ps1["ok"]:false )
  2340.     {
  2341.     conf["partitions"] = 
  2342.         filter( map p, conf["partitions"]:[],
  2343.             ``(p["mount"]:""!="/home" && p["mount"]:""!="/"));
  2344.     conf["partitions"] = add( conf["partitions"]:[], old_root );
  2345.     ps1 = do_flexible_disk_conf( disk, conf, false, false );
  2346.     }
  2347.     if( !have_swap )
  2348.     {
  2349.     integer diff = swap_sizes[0]:256 - swap_sizes[1]:256;
  2350.     if( diff<0 )
  2351.         diff = -diff;
  2352.     y2milestone( "get_proposal diff:%1 ps1 ok:%2", diff, ps1["ok"]:false );
  2353.     if( (!ps1["ok"]:false && diff>0) || diff>100 )
  2354.         {
  2355.         conf["partitions",0,"size"] = swap_sizes[1]:256*1024*1024;
  2356.         map ps2 = do_flexible_disk_conf( disk, conf, false, false );
  2357.         y2milestone( "get_proposal ps2 ok:%1", ps2["ok"]:false );
  2358.         if( ps2["ok"]:false )
  2359.         {
  2360.         map rp1 = find( map p, ps1["disk","partitions"]:[], 
  2361.                 ``(!p["delete"]:false && p["mount"]:""=="/"));
  2362.         map rp2 = find( map p, ps2["disk","partitions"]:[], 
  2363.                 ``(!p["delete"]:false && p["mount"]:""=="/"));
  2364.         y2milestone( "get_proposal rp1:%1", rp1 );
  2365.         y2milestone( "get_proposal rp2:%1", rp2 );
  2366.         if( rp1==nil || (rp2!=nil && rp2["size_k"]:0>rp1["size_k"]:0 ))
  2367.             ps1 = ps2;
  2368.         }
  2369.         }
  2370.     }
  2371.     if( ps1["ok"]:false )
  2372.     ret = ps1["disk","partitions"]:[];
  2373.     y2milestone( "get_proposal ret:%1", ret );
  2374.     return( ret );
  2375.     }
  2376.  
  2377. integer get_usable_size_mb( map disk, boolean reuse_linux )
  2378.     {
  2379.     integer ret = 0;
  2380.     integer cyl_size = disk["cyl_size"]:0;
  2381.     integer disk_cyl = disk["cyl_count"]:0;
  2382.     list<map> partitions = filter( map p, disk["partitions"]:[], 
  2383.                    ``(!p["create"]:false));
  2384.     partitions = sort( map p1, map p2, partitions,
  2385.                            ``(p1["region",0]:0 < p2["region",0]:0));
  2386.     integer last_end = 0;
  2387.     foreach( map p, partitions,
  2388.     ``{
  2389.     if( p["region",0]:0>last_end )
  2390.         ret = ret + (p["region",0]:0-last_end) * cyl_size;
  2391.     if( p["type"]:`unknown!=`extended && 
  2392.         (p["delete"]:false || (reuse_linux && p["linux"]:false)))
  2393.         ret = ret + p["size_k"]:0 * 1024;
  2394.     last_end = p["region",0]:0;
  2395.     if( p["type"]:`unknown != `extended )
  2396.         last_end = last_end + p["region",1]:0;
  2397.     });
  2398.     if( last_end < disk_cyl )
  2399.     ret = ret + (disk_cyl-last_end) * cyl_size;
  2400.     ret = ret / (1024*1024);
  2401.     return( ret );
  2402.     }
  2403.  
  2404. integer get_mb_sol( map sol, string mp )
  2405.     {
  2406.     map pa = find( map p, sol["disk","partitions"]:[], ``(p["mount"]:""==mp));
  2407.     y2milestone( "get_mb_sol pa %1", pa );
  2408.     integer ret = pa!=nil ? pa["size_k"]:0/1024 : 0;
  2409.     y2milestone( "get_mb_sol ret %1", ret );
  2410.     return( ret );
  2411.     }
  2412.  
  2413. integer get_vm_sol( map sol )
  2414.     {
  2415.     integer ret = 0;
  2416.     foreach( map p, sol["disk","partitions"]:[],
  2417.     ``{
  2418.     if( !p["delete"]:false && (size(p["mount"]:"")>0 || size(p["vg"]:"")>0))
  2419.         ret = ret + p["size_k"]:0/1024;
  2420.     });
  2421.     y2milestone( "get_vm_sol ret %1", ret );
  2422.     return( ret );
  2423.     }
  2424.  
  2425. list<map> special_boot_proposal_prepare( list<map> partitions )
  2426.     {
  2427.     list<map> ret = partitions;
  2428.     if( Partitions::PrepBoot() )
  2429.     {
  2430.     ret = maplist( map p, partitions,
  2431.                ``{
  2432.                if( size(p["mount"]:"")==0 &&
  2433.                    (p["fsid"]:0 == 0x06 || p["fsid"]:0 == 0x41) )
  2434.                p["delete"] = true;
  2435.                return( p );
  2436.                });
  2437.     y2milestone( "special_boot_proposal_prepare part:%1", partitions );
  2438.     y2milestone( "special_boot_proposal_prepare  ret:%1", ret );
  2439.     }
  2440.     return( ret );
  2441.     }
  2442.  
  2443. map<string,map> prepare_part_lists( list<string> ddev, map<string,map> tg )
  2444.     {
  2445.     list linux_pid = [ Partitions::fsid_native, Partitions::fsid_swap,
  2446.                        Partitions::fsid_lvm, Partitions::fsid_raid ];
  2447.     foreach( string s, ddev,
  2448.     ``{
  2449.     tg[s,"partitions"] = 
  2450.         maplist( map p, tg[s,"partitions"]:[],
  2451.         ``{
  2452.         if( contains( linux_pid, p["fsid"]:0 ) ||
  2453.             (p["fsid"]:0 == Partitions::fsid_gpt_boot) ||
  2454.             (p["fsid"]:0 == Partitions::FsidBoot() && 
  2455.              p["size_k"]:0<500*1024)||
  2456.             (Partitions::PrepBoot() && 
  2457.              (p["fsid"]:0 == Partitions::fsid_prep_chrp_boot||
  2458.               p["fsid"]:0 == 0x06)))
  2459.             p["linux"] = true;
  2460.         else
  2461.             p["linux"] = false;
  2462.         return( p );
  2463.         });
  2464.     });
  2465.     return( tg );
  2466.     }
  2467.  
  2468. list<string> get_disk_try_list( map<string,map> tg, boolean soft )
  2469.     {
  2470.     list<string> ret = [];
  2471.     ret = maplist( string k, map e, 
  2472.            filter( string l, map f, tg, 
  2473.                ``(!ignore_disk(l,f,soft))), ``(k));
  2474.     ret = sort( ret );
  2475.     if( size(ret)>4 )
  2476.     {
  2477.     ret = restrict_disk_names( ret );
  2478.     }
  2479.     y2milestone( "get_disk_try_list soft:%1 ret:%2", soft, ret );
  2480.     return( ret );
  2481.     }
  2482.  
  2483. boolean usable_for_win_resize( map p, boolean assert_cons_fs )
  2484.     {
  2485.     boolean ret = Partitions::IsDosWinNtPartition( p["fsid"]:0 ) &&
  2486.           p["size_k"]:0 > 1024*1024 && 
  2487.           !p["resize"]:false && !p["delete"]:false;
  2488.     if( ret )
  2489.     {
  2490.     if( assert_cons_fs )
  2491.         ret = p["winfo","ok"]:false;
  2492.     else
  2493.         ret = size(p["winfo"]:$[])>0;
  2494.     }
  2495.     return( ret );
  2496.     }
  2497.  
  2498. list<map> remove_p_settings( list<map> parts, list<string> mp )
  2499.     {
  2500.     list<string> rems = [ "resize", "used_fs", "win_max_length", "mount",
  2501.                           "format", "ignore_fs", "vg" ];
  2502.     parts = 
  2503.     maplist( map p, parts,
  2504.         ``{
  2505.         if( size(mp)==0 || contains( mp, p["mount"]:"") )
  2506.         {
  2507.         foreach( string s, rems,
  2508.             ``{
  2509.             if( haskey( p, s ))
  2510.             p = remove( p, s );
  2511.             });
  2512.         }
  2513.         return( p );
  2514.         });
  2515.     return( parts );
  2516.     }
  2517.  
  2518. list<map> remove_one_partition( list<map> partitions )
  2519.     {
  2520.     list<map> pl = filter( map p, partitions,
  2521.                ``( p["linux"]:false && size(p["mount"]:"")==0 &&
  2522.                    !p["delete"]:false ));
  2523.     if( size(pl)>0 )
  2524.     {
  2525.     pl = sort( map a, map b, pl, 
  2526.            ``(a["size_k"]:0>b["size_k"]:0));
  2527.     pl = (list<map>) union( 
  2528.         filter( map p, pl, ``(p["used_by_type"]:`UB_NONE==`UB_NONE) ),
  2529.         filter( map p, pl, ``(p["used_by_type"]:`UB_NONE!=`UB_NONE) ));
  2530.  
  2531.     partitions = 
  2532.         maplist( map p, partitions,
  2533.         ``{
  2534.         if( p["linux"]:false && !p["delete"]:false &&
  2535.             size(p["mount"]:"")==0 &&
  2536.             p["device"]:""==pl[0,"device"]:"" )
  2537.             {
  2538.             p["delete"] = true;
  2539.             y2milestone( "remove_one_partition p %1", p );
  2540.             }
  2541.         return( p );
  2542.         });
  2543.     partitions = try_remove_sole_extended( partitions );
  2544.     }
  2545.     return( partitions );
  2546.     }
  2547.  
  2548. list<map> remove_one_partition_vm( map disk )
  2549.     {
  2550.     list<map> partitions = disk["partitions"]:[];
  2551.     list<map> pl = filter( map p, partitions,
  2552.                ``( p["linux"]:false && size(p["mount"]:"")==0 &&
  2553.                    !p["delete"]:false ));
  2554.     if( size(pl)>0 )
  2555.     {
  2556.     pl = sort( map a, map b, pl, 
  2557.            ``(a["size_k"]:0<b["size_k"]:0));
  2558.     pl = (list<map>) union( 
  2559.         filter( map p, pl, ``(p["type"]:`primary==`logical) ),
  2560.         filter( map p, pl, ``(p["type"]:`primary!=`logical) ));
  2561.     pl = (list<map>) union( 
  2562.         filter( map p, pl, ``(p["used_by_type"]:`UB_NONE==`UB_NONE) ),
  2563.         filter( map p, pl, ``(p["used_by_type"]:`UB_NONE!=`UB_NONE) ));
  2564.     y2milestone( "remove_one_partition_vm pl %1", pl );
  2565.  
  2566.     integer nr = 0;
  2567.  
  2568.     partitions = 
  2569.         maplist( map p, partitions,
  2570.         ``{
  2571.         if( p["linux"]:false && !p["delete"]:false &&
  2572.             size(p["mount"]:"")==0 &&
  2573.             p["device"]:""==pl[0,"device"]:"" )
  2574.             {
  2575.             p["delete"] = true;
  2576.             nr = p["nr"]:0;
  2577.             y2milestone( "remove_one_partition_vm p %1", p );
  2578.             }
  2579.         return( p );
  2580.         });
  2581.     if( nr>disk["max_primary"]:4 )
  2582.         {
  2583.         partitions = 
  2584.         maplist( map p, partitions,
  2585.             ``{
  2586.             if( !p["delete"]:false && p["nr"]:0>nr )
  2587.             {
  2588.             p["nr"] = p["nr"]:0-1;
  2589.             p["device"] = Storage::GetDeviceName( disk["device"]:"",
  2590.                                                   p["nr"]:0 );
  2591.             y2milestone( "remove_one_partition_vm ren %1", p );
  2592.             }
  2593.             return( p );
  2594.             });
  2595.         }
  2596.     partitions = try_remove_sole_extended( partitions );
  2597.     }
  2598.     return( partitions );
  2599.     }
  2600.  
  2601. map remove_used_by( map tg, string disk )
  2602.     {
  2603.     string uby = tg[disk,"used_by"]:"";
  2604.     y2milestone( "remove_used_by disk %1 uby %2", disk, uby );
  2605.     if( size(uby)>0 )
  2606.     {
  2607.     string k = "/dev/"+uby;
  2608.     if( haskey( tg, k ))
  2609.         {
  2610.         tg[k,"delete"] = true;
  2611.         y2milestone( "remove_used_by uby %1", tg[k]:$[] );
  2612.         }
  2613.     }
  2614.     return( tg );
  2615.     }
  2616.  
  2617. map get_inst_proposal( map<string,map> target )
  2618.     {
  2619.     y2milestone( "get_inst_proposal start" );
  2620.     map ret = $[];
  2621.     target = Storage::AddWinInfo(target);
  2622.     ret["target"] = target;
  2623.     map root = $[ "mount" : "/", "increasable" : true,
  2624.                   "fsys" : Partitions::DefaultFs(), "size" : 0 ];
  2625.     map opts = Storage::GetControlCfg();
  2626.     list<string> ddev = get_disk_try_list( target, true );
  2627.     string sol_disk = "";
  2628.     list modes = [ `free, `reuse, `remove, `resize, `desparate ];
  2629.     map<string,boolean> valid = $[];
  2630.     map<string,list> size_mb = listmap( string s, ddev, ``($[s:[]]));
  2631.     map solution = listmap( string s, ddev, ``($[s:[]]));
  2632.     target = prepare_part_lists( ddev, target );
  2633.     symbol mode = `free;
  2634.     while( mode != `end && size(sol_disk)==0 )
  2635.     {
  2636.     if( mode == `free || mode == `desparate )
  2637.         {
  2638.         valid = listmap( string s, ddev, ``($[s:true]));
  2639.         if( mode == `desparate )
  2640.         {
  2641.         ddev = get_disk_try_list( target, false );
  2642.         valid = listmap( string s, ddev, ``($[s:true]));
  2643.         target = prepare_part_lists( ddev, target );
  2644.         foreach( string s, ddev,
  2645.             ``{
  2646.             target[s,"partitions"] = 
  2647.             remove_p_settings( target[s,"partitions"]:[], [] );
  2648.             target[s,"partitions"] = 
  2649.             maplist( map p, target[s,"partitions"]:[],
  2650.                 ``{
  2651.                 if( !contains( Partitions::do_not_delete, 
  2652.                        p["fsid"]:0 ))
  2653.                 {
  2654.                 if( usable_for_win_resize(p,false) )
  2655.                     p["dtxt"] = _("Resize impossible due to inconsistent fs. Try checking fs under Windows.");
  2656.                 p["delete"] = true;
  2657.                 }
  2658.                 return( p );
  2659.                 });
  2660.             });
  2661.         }
  2662.         }
  2663.     else if( mode == `reuse || mode == `remove )
  2664.         {
  2665.         valid = listmap( string s, ddev, 
  2666.         ``{
  2667.         if( find( map p, target[s,"partitions"]:[], 
  2668.                   ``(p["linux"]:false && size(p["mount"]:"")==0 &&
  2669.                  !p["delete"]:false)) != nil )
  2670.             return( $[s:true] );
  2671.         else
  2672.             return( $[s:false] );
  2673.         });
  2674.         if( mode == `remove )
  2675.         {
  2676.         foreach( string s, ddev,
  2677.             ``{
  2678.             target[s,"partitions"] = 
  2679.             remove_p_settings( target[s,"partitions"]:[], 
  2680.                                ["/", "/home"] );
  2681.             });
  2682.         foreach( string s, filter( string d, ddev, ``(valid[d]:false)),
  2683.             ``{
  2684.             target[s,"partitions"] = 
  2685.             remove_one_partition( target[s,"partitions"]:[] );
  2686.             });
  2687.         }
  2688.         }
  2689.     else if( mode == `resize )
  2690.         {
  2691.         valid = listmap( string s, ddev, 
  2692.         ``{
  2693.         if( find( map p, target[s,"partitions"]:[], 
  2694.                   ``(usable_for_win_resize(p,true))) != nil )
  2695.             return( $[s:true] );
  2696.         else
  2697.             return( $[s:false] );
  2698.         });
  2699.         foreach( string s, filter( string d, ddev, ``(valid[d]:false)),
  2700.         ``{
  2701.         list<map> pl = filter( map p, target[s,"partitions"]:[],
  2702.                        ``(usable_for_win_resize(p,true)));
  2703.         if( size(pl)>0 )
  2704.             {
  2705.             pl = sort( map a, map b, pl, 
  2706.                    ``(a["size_k"]:0>b["size_k"]:0));
  2707.             target[s,"partitions"] = 
  2708.             maplist( map p, target[s,"partitions"]:[],
  2709.                 ``{
  2710.                 if( usable_for_win_resize(p,true) &&
  2711.                 p["device"]:""==pl[0,"device"]:"" )
  2712.                 {
  2713.                 integer cs = target[s,"cyl_size"]:1;
  2714.                 p["resize"] = true;
  2715.                 p["region",1] = 
  2716.                     (p["winfo","new_size"]:0+cs-1) / cs;
  2717.                 p["win_max_length"] =
  2718.                     (p["winfo","max_win_size"]:0+cs-1) / cs;
  2719.                 }
  2720.                 return( p );
  2721.                 });
  2722.             y2milestone( "get_inst_proposal res parts %1", 
  2723.                          target[s,"partitions"]:[] );
  2724.             }
  2725.         });
  2726.         }
  2727.     y2milestone( "get_inst_proposal mode %1 valid %2", mode, valid );
  2728.     foreach( string s, filter( string d, ddev, ``(valid[d]:false)),
  2729.         ``{
  2730.         map conf = $[ "partitions" : [] ];
  2731.         map disk = target[s]:$[];
  2732.         list<map> p = can_boot_reuse( s, disk["label"]:"msdos",
  2733.                                       need_boot(disk),
  2734.                       disk["max_primary"]:4,
  2735.                       disk["partitions"]:[] );
  2736.         disk["partitions"] = 
  2737.         special_boot_proposal_prepare( disk["partitions"]:[] );
  2738.         boolean have_home = false;
  2739.         boolean have_root = false;
  2740.         boolean have_boot = (!Arch::ia64()||mode!=`free) && size(p)>0;
  2741.         if( have_boot )
  2742.             disk["partitions"] = p;
  2743.         map r = can_swap_reuse( s, disk["partitions"]:[], target );
  2744.         boolean have_swap = size(r)>0;
  2745.         if( haskey( r, "partitions" ))
  2746.         disk["partitions"] =  r["partitions"]:[];
  2747.         else if( haskey( r, "targets" ))
  2748.         target = r["targets"]:$[];
  2749.         list swap_sizes = [];
  2750.         integer avail_size = get_usable_size_mb(disk,mode==`reuse);
  2751.         y2milestone( "get_inst_proposal disk %1 mode %2 avail %3", 
  2752.                      s, mode, avail_size );
  2753.         if( avail_size>0 )
  2754.         {
  2755.         if( mode == `reuse )
  2756.             {
  2757.             list<map> parts = disk["partitions"]:[];
  2758.             if( Storage::ProposalHome() )
  2759.             {
  2760.             if( avail_size > opts["home_limit"]:0 )
  2761.                 parts = can_mp_reuse( "/home", 4*1024, 0, parts );
  2762.             else
  2763.                 parts = can_mp_reuse( "/", opts["root_base"]:0, 0, 
  2764.                                       parts );
  2765.             }
  2766.             if( size(parts)>0 && avail_size > opts["home_limit"]:0 )
  2767.             {
  2768.             integer mx = 0;
  2769.             if( Storage::ProposalHome() )
  2770.                 mx = opts["root_max"]:0;
  2771.             parts = can_mp_reuse( "/", opts["root_base"]:0, 
  2772.                           mx, parts );
  2773.             }
  2774.             if( size(parts)>0 )
  2775.             {
  2776.             have_home = avail_size > opts["home_limit"]:0;
  2777.             have_root = true;
  2778.             disk["partitions"] = parts;
  2779.             }
  2780.             y2milestone( "get_inst_proposal reuse have_home %1 have_root %2",
  2781.                          have_home, have_root );
  2782.             if( have_home && have_root )
  2783.             y2milestone( "get_inst_proposal reuse parts %1",
  2784.                          disk["partitions"]:[] );
  2785.             }
  2786.         if( !have_swap )
  2787.             {
  2788.             swap_sizes = get_swap_sizes( avail_size );
  2789.             map swap = $[ "mount" : "swap", "increasable" : true, 
  2790.                   "fsys" : `swap, "maxsize" : 2*1024*1024*1024,
  2791.                   "size"  : swap_sizes[0]:256*1024*1024 ];
  2792.             conf["partitions"] = add( conf["partitions"]:[], swap );
  2793.             }
  2794.         if( !have_root )
  2795.             conf["partitions"] = add( conf["partitions"]:[], root );
  2796.         map old_root = $[];
  2797.         if( !have_home && Storage::ProposalHome() &&
  2798.             opts["home_limit"]:0 < avail_size )
  2799.             {
  2800.             map home = $[ "mount" : "/home", "increasable" : true, 
  2801.                   "fsys" : Partitions::DefaultFs(), 
  2802.                   "size" : 512*1024*1024, 
  2803.                   "pct" : 100-opts["root_percent"]:40 ];
  2804.             conf["partitions"] = 
  2805.             maplist( map p, conf["partitions"]:[],
  2806.                 ``{
  2807.                 if( p["mount"]:""=="/" )
  2808.                 {
  2809.                 old_root = p;
  2810.                 p["pct"] = opts["root_percent"]:40;
  2811.                 p["maxsize"] = opts["root_max"]:0*1024*1024;
  2812.                 p["size"] = opts["root_base"]:0*1024*1024;
  2813.                 }
  2814.                 return( p );
  2815.                 });
  2816.             conf["partitions"] = add( conf["partitions"]:[], home );
  2817.             }
  2818.         map ps1 = do_flexible_disk_conf( disk, conf, have_boot, 
  2819.                          mode==`reuse );
  2820.         if( size(old_root)>0 && !ps1["ok"]:false )
  2821.             {
  2822.             conf["partitions"] = 
  2823.             filter( map p, conf["partitions"]:[],
  2824.                 ``(p["mount"]:""!="/home" && 
  2825.                    p["mount"]:""!="/"));
  2826.             conf["partitions"] = add( conf["partitions"]:[], old_root );
  2827.             ps1 = do_flexible_disk_conf( disk, conf, have_boot, 
  2828.                          mode==`reuse );
  2829.             }
  2830.         if( !have_swap )
  2831.             {
  2832.             integer diff = swap_sizes[0]:256 - swap_sizes[1]:256;
  2833.             if( diff<0 )
  2834.             diff = -diff;
  2835.             y2milestone( "get_inst_proposal diff:%1 ps1 ok:%2", 
  2836.                  diff, ps1["ok"]:false );
  2837.             if( (!ps1["ok"]:false && diff>0) || diff>100 )
  2838.             {
  2839.             conf["partitions",0,"size"] = 
  2840.                 swap_sizes[1]:256*1024*1024;
  2841.             map ps2 = do_flexible_disk_conf( disk, conf, have_boot, 
  2842.                              mode==`reuse );
  2843.             y2milestone( "get_inst_proposal ps2 ok:%1", 
  2844.                      ps2["ok"]:false );
  2845.             if( ps2["ok"]:false )
  2846.                 {
  2847.                 map rp1 = find( map p, ps1["disk","partitions"]:[], 
  2848.                         ``(!p["delete"]:false && 
  2849.                            p["mount"]:""=="/"));
  2850.                 map rp2 = find( map p, ps2["disk","partitions"]:[], 
  2851.                         ``(!p["delete"]:false && 
  2852.                            p["mount"]:""=="/"));
  2853.                 y2milestone( "get_inst_proposal rp1:%1", rp1 );
  2854.                 y2milestone( "get_inst_proposal rp2:%1", rp2 );
  2855.                 if( rp1==nil || 
  2856.                 (rp2!=nil && rp2["size_k"]:0>rp1["size_k"]:0 ))
  2857.                 ps1 = ps2;
  2858.                 }
  2859.             }
  2860.             }
  2861.         if( ps1["ok"]:false )
  2862.             {
  2863.             list mb = [ get_mb_sol( ps1, "/" )];
  2864.             if( Storage::ProposalHome() )
  2865.             mb = add( mb, get_mb_sol( ps1, "/home" ));
  2866.             if( mb[0]:0+mb[1]:0 > size_mb[s,0]:0 + size_mb[s,1]:0 )
  2867.             {
  2868.             solution[s] = ps1["disk"]:$[];
  2869.             size_mb[s] = mb;
  2870.             y2milestone( "get_inst_proposal sol %1 mb %2", 
  2871.                          s, size_mb[s]:[] );
  2872.             }
  2873.             }
  2874.         }
  2875.         });
  2876.     integer max_mb = 0;
  2877.     string max_disk = "";
  2878.     foreach( string s, list mb, size_mb,
  2879.         ``{
  2880.         if( (!Storage::ProposalHome() || mb[1]:0>0 || mode==`resize ) && 
  2881.             mb[1]:0+mb[0]:0 > max_mb )
  2882.         {
  2883.         max_mb = mb[1]:0+mb[0]:0;
  2884.         max_disk = s;
  2885.         }
  2886.         });
  2887.     y2milestone( "max_mb %1 size_mb %2", max_mb, size_mb );
  2888.     if( max_mb>0 && size_mb[max_disk,0]:0 > 2*1024 && 
  2889.         ( !Storage::ProposalHome() || size_mb[max_disk,1]:0 > 1*1024 ))
  2890.         {
  2891.         sol_disk = max_disk;
  2892.         }
  2893.     y2milestone( "get_inst_proposal mode %1 size_mb %2", mode, size_mb );
  2894.     if( size(sol_disk)==0 )
  2895.         {
  2896.         list<boolean> lb = maplist(string s, boolean e, valid, ``(e));
  2897.         if( mode == `free )
  2898.         mode = `reuse;
  2899.         else if( mode == `reuse )
  2900.         mode = `remove;
  2901.         else if( mode == `remove && find( boolean v, lb, ``(v)) == nil )
  2902.         mode = `resize;
  2903.         else if( mode == `resize && find( boolean v, lb, ``(v)) == nil )
  2904.         mode = `desparate;
  2905.         else if( mode == `desparate )
  2906.         mode = `end;
  2907.         if( mode == `desparate && size(sol_disk)==0 )
  2908.         {
  2909.         max_mb = 0;
  2910.         foreach( string s, list mb, size_mb,
  2911.             ``{
  2912.             if( mb[1]:0+mb[0]:0 > max_mb && 
  2913.                 size_mb[max_disk,0]:0 > 2*1024 )
  2914.             {
  2915.             max_mb = mb[1]:0+mb[0]:0;
  2916.             sol_disk = s;
  2917.             }
  2918.             });
  2919.         y2milestone( "get_inst_proposal mode %1 sol_disk %2",
  2920.                      mode, sol_disk );
  2921.         }
  2922.         }
  2923.     }
  2924.     y2milestone( "get_inst_proposal sol_disk %1", sol_disk );
  2925.     if( size(sol_disk)==0 )
  2926.     {
  2927.     integer max_mb = 0;
  2928.     foreach( string s, list mb, size_mb,
  2929.         ``{
  2930.         if( mb[1]:0+mb[0]:0>max_mb )
  2931.         {
  2932.         max_mb = mb[1]:0+mb[0]:0;
  2933.         sol_disk = s;
  2934.         }
  2935.         });
  2936.     y2milestone( "get_inst_proposal sol_disk %1", sol_disk );
  2937.     }
  2938.     ret["ok"] = size(sol_disk)>0;
  2939.     if( ret["ok"]:false )
  2940.     {
  2941.     ret["target"] = remove_used_by( ret["target"]:$[], sol_disk );
  2942.     ret["target",sol_disk] = solution[sol_disk]:$[];
  2943.     ret["target"] = Storage::SpecialBootHandling( ret["target"]:$[] );
  2944.     y2milestone( "get_inst_proposal sol:%1", ret["target",sol_disk]:$[] );
  2945.     }
  2946.     y2milestone( "get_inst_proposal ret[ok]:%1", ret["ok"]:false );
  2947.     return( ret );
  2948.     }
  2949.  
  2950. list<map> remove_keys( list<map> pl, list<string> keys )
  2951.     {
  2952.     pl = maplist( map p, pl,
  2953.     ``{
  2954.     foreach( string k, keys,
  2955.         ``{
  2956.         if( haskey(p,k) )
  2957.         p = remove( p, k );
  2958.         });
  2959.     return( p );
  2960.     });
  2961.     return( pl );
  2962.     }
  2963.  
  2964. map<string,map> remove_mount_points( map<string,map> target )
  2965.     {
  2966.     foreach( string s, map disk, target,
  2967.     ``{
  2968.     target[s,"partitions"] = remove_keys( target[s,"partitions"]:[],
  2969.                                           [ "mount" ] );
  2970.     });
  2971.     return( target );
  2972.     }
  2973.  
  2974. map<string,map> remove_vm( map<string,map> tg, string ky )
  2975.     {
  2976.     y2milestone( "remove_vm key:%1", ky );
  2977.     string key = "/dev/" + ky;
  2978.     if( haskey( tg, key ))
  2979.     {
  2980.     tg[key,"delete"] = true;
  2981.     tg[key,"partitions"] = 
  2982.         maplist( map p, tg[key,"partitions"]:[],
  2983.              ``{
  2984.              p["delete"] = true;
  2985.              return(p);
  2986.              });
  2987.     y2milestone( "remove_vm removed:%1", tg[key]:$[] );
  2988.     list<string> dl = tg[key,"devices"]:[];
  2989.     foreach( string d, dl,
  2990.         ``{
  2991.         tg = Storage::DelPartitionData( tg, d, "used_by" );
  2992.         tg = Storage::DelPartitionData( tg, d, "used_by_type" );
  2993.         });
  2994.     }
  2995.     if( haskey( tg, "/dev/evms/lvm/"+ky ) || haskey( tg, "/dev/evms/lvm2/"+ky ))
  2996.     {
  2997.     if( haskey( tg, "/dev/evms/lvm/"+ky ) && tg[key,"lvm2"]:false )
  2998.         {
  2999.         key = "/dev/evms/lvm/"+ky;
  3000.         tg[key,"delete"] = true;
  3001.         tg[key,"partitions"] = 
  3002.         maplist( map p, tg[key,"partitions"]:[],
  3003.              ``{
  3004.              p["delete"] = true;
  3005.              return(p);
  3006.              });
  3007.         y2milestone( "remove_vm removed:%1", tg[key]:$[] );
  3008.         list<string> dl = tg[key,"devices"]:[];
  3009.         foreach( string d, dl,
  3010.         ``{
  3011.         tg = Storage::DelPartitionData( tg, d, "used_by" );
  3012.         tg = Storage::DelPartitionData( tg, d, "used_by_type" );
  3013.         });
  3014.         }
  3015.     if( haskey( tg, "/dev/evms/lvm2/"+ky ) && !tg[key,"lvm2"]:false )
  3016.         {
  3017.         key = "/dev/evms/lvm2/"+ky;
  3018.         tg[key,"delete"] = true;
  3019.         tg[key,"partitions"] = 
  3020.         maplist( map p, tg[key,"partitions"]:[],
  3021.              ``{
  3022.              p["delete"] = true;
  3023.              return(p);
  3024.              });
  3025.         y2milestone( "remove_vm removed:%1", tg[key]:$[] );
  3026.         list<string> dl = tg[key,"devices"]:[];
  3027.         foreach( string d, dl,
  3028.         ``{
  3029.         tg = Storage::DelPartitionData( tg, d, "used_by" );
  3030.         tg = Storage::DelPartitionData( tg, d, "used_by_type" );
  3031.         });
  3032.         }
  3033.     }
  3034.     return( tg );
  3035.     }
  3036.  
  3037. string find_vm( map<string,map> target, string ky, integer min_size )
  3038.     {
  3039.     string ret = "";
  3040.     string key = "/dev/" + ky;
  3041.     string key2 = "/dev/evms/lvm2/" + ky;
  3042.     if( Storage::ProposalLvm() && target[key,"lvm2"]:false && 
  3043.         target[key,"size_k"]:0 >= min_size )
  3044.     ret = key;
  3045.     else if( Storage::ProposalEvms() && haskey( target, key2 ) && 
  3046.              target[key2,"size_k"]:0 >= min_size )
  3047.     ret = key2;
  3048.     y2milestone( "find_vm key:%1 min_size:%2 ret:%3", ky, min_size, ret );
  3049.     return( ret );
  3050.     }
  3051.  
  3052. boolean did_remove_vg( list<map> partitions, string vg )
  3053.     {
  3054.     boolean ret=false;
  3055.     list<string> ele = [ vg, "lvm/"+vg, "lvm2/"+vg ];
  3056.     foreach( map p, partitions, 
  3057.     ``{
  3058.     if( !ret && p["delete"]:false && contains( ele, p["used_by"]:"" ))
  3059.         ret = true;
  3060.     });
  3061.     y2milestone( "did_remove_vg vg:%1 ret:%2", vg, ret );
  3062.     return( ret );
  3063.     }
  3064.  
  3065. integer sizek_to_pe( integer pek, integer pebyte, boolean pvcreate )
  3066.     {
  3067.     integer ret = (pek-(pvcreate?500:0)) / (pebyte/1024);
  3068.     y2milestone( "sizek_to_pe pek %1 pebyte %2 pvcreate %3 ret %4", 
  3069.                  pek, pebyte, pvcreate, ret );
  3070.     return( ret );
  3071.     }
  3072.  
  3073. integer pe_to_sizek( integer pe, integer pebyte )
  3074.     {
  3075.     integer ret = pe * (pebyte/1024);
  3076.     y2milestone( "pe_to_sizek pe %1 pebyte %2 ret %3", pe, pebyte, ret );
  3077.     return( ret );
  3078.     }
  3079.  
  3080. map extend_vm( map vg, string key, map disk )
  3081.     {
  3082.     y2milestone( "extend_vm key %1 vg %2", key, vg );
  3083.     y2milestone( "extend_vm disk %1", disk );
  3084.     list devs = [];
  3085.     integer num_pe = vg["pe_free"]:0;
  3086.     foreach( map p, disk["partitions"]:[],
  3087.     ``{
  3088.     if( p["vg"]:""==key )
  3089.         {
  3090.         devs = add( devs, p["device"]:"" );
  3091.         num_pe = num_pe + 
  3092.                  sizek_to_pe( p["size_k"]:0, vg["pesize"]:1024, true );
  3093.         };
  3094.     });
  3095.     y2milestone( "extend_vm num_pe %1 devs %2", num_pe, devs );
  3096.     vg["devices_add"] = devs;
  3097.     vg["pe_free"] = num_pe;
  3098.     vg["size_k"] = pe_to_sizek( num_pe, vg["pesize"]:0 );
  3099.     y2milestone( "extend_vm ret %1", vg );
  3100.     return( vg );
  3101.     }
  3102.  
  3103. map create_vm( boolean evms, string key, map disk )
  3104.     {
  3105.     y2milestone( "create_vm evms %1 key %2 disk %3", evms, key, disk );
  3106.     map ret = $[ "type" : evms?`CT_EVMS:`CT_LVM,
  3107.                  "name" : evms?"lvm2/"+key:key,
  3108.          "device" : "/dev/"+(evms?"evms/lvm2/":"")+key,
  3109.                  "lvm2" : true,
  3110.          "create" : true,
  3111.          "partitions" : [],
  3112.          "pesize" : 4*1024*1024 ];
  3113.     list devs = [];
  3114.     integer num_pe = 0;
  3115.     foreach( map p, disk["partitions"]:[],
  3116.     ``{
  3117.     if( p["vg"]:""==key && !p["delete"]:false )
  3118.         {
  3119.         devs = add( devs, p["device"]:"" );
  3120.         num_pe = num_pe + 
  3121.                  sizek_to_pe( p["size_k"]:0, ret["pesize"]:1024, true );
  3122.         };
  3123.     });
  3124.     y2milestone( "create_vm num_pe %1 devs %2", num_pe, devs );
  3125.     ret["devices_add"] = devs;
  3126.     ret["pe_free"] = num_pe;
  3127.     ret["size_k"] = pe_to_sizek( num_pe, ret["pesize"]:0 );
  3128.     y2milestone( "create_vm ret %1", ret );
  3129.     return( ret );
  3130.     }
  3131.  
  3132. integer round_mb_pe( integer mb, integer pebyte )
  3133.     {
  3134.     integer pek = pebyte/1024;
  3135.     if( pek<1 )
  3136.         pek = 1;
  3137.     integer ret = (mb*1024 + pek-1) / pek * pek;
  3138.     if( ret==0 )
  3139.     ret=1;
  3140.     y2milestone( "round_mb_pe mb %1 pebyte %2 ret %3", mb, pebyte, ret );
  3141.     return( ret );
  3142.     }
  3143.  
  3144. map modify_vm( map vm, map opts, boolean need_swap )
  3145.     {
  3146.     y2milestone( "modify_vm swap %1 start %2", need_swap, vm );
  3147.     y2milestone( "modify_vm opts %1", opts );
  3148.     map ret = vm;
  3149.     integer free = ret["pe_free"]:0;
  3150.     integer pe = ret["pesize"]:1024;
  3151.     integer swsize = 0;
  3152.     list swlist = [];
  3153.     if( need_swap )
  3154.     {
  3155.     swlist = get_swap_sizes( free );
  3156.     swsize = (swlist[1]:0>swlist[0]:0) ? swlist[1]:0 : swlist[0]:0;
  3157.     }
  3158.     y2milestone( "modify_vm swsize %1", swsize );
  3159.     map swap = find( map p, ret["partitions"]:[], ``(p["name"]:""=="swap"));
  3160.     map root = find( map p, ret["partitions"]:[], ``(p["name"]:""=="root"));
  3161.     map home = find( map p, ret["partitions"]:[], ``(p["name"]:""=="home"));
  3162.     y2milestone( "modify_vm swap %1 root %2 home %3", swap, root, home );
  3163.     if( root!=nil && root["size_k"]:0<1024*1024 )
  3164.     {
  3165.     ret["partitions"] = maplist( map p, ret["partitions"]:[],
  3166.         ``{
  3167.         if( p["name"]:"" == "root" )
  3168.         {
  3169.         p["delete"] = true;
  3170.         free = free + sizek_to_pe( p["size_k"]:0, pe, false );
  3171.         y2milestone( "modify_vm remove root %1", p );
  3172.         }
  3173.         return(p);
  3174.         });
  3175.     y2milestone( "modify_vm pe free %1", free );
  3176.     root = nil;
  3177.     }
  3178.     ret["partitions"] = sort( map a, map b, ret["partitions"]:[], 
  3179.                               ``(a["size_k"]:0>b["size_k"]:0));
  3180.     list keep = [ "root", "home", "swap" ];
  3181.     integer root_pe = sizek_to_pe( opts["root_base"]:0*1024, pe, false );
  3182.     y2milestone( "modify_vm pe free %1 root %2", free, root_pe );
  3183.     map m = find( map p, ret["partitions"]:[],
  3184.           ``(!p["delete"]:false && !contains(keep,p["name"]:"")));
  3185.     while( root==nil && free<root_pe && m!=nil )
  3186.     {
  3187.     ret["partitions"] = maplist( map p, ret["partitions"]:[],
  3188.         ``{
  3189.         if( p["name"]:"" == m["name"]:"" )
  3190.         {
  3191.         p["delete"] = true;
  3192.         free = free + sizek_to_pe( p["size_k"]:0, pe, false );
  3193.         }
  3194.         return(p);
  3195.         });
  3196.     y2milestone( "modify_vm pe free %1 root %2 del %3", free, root_pe, m );
  3197.     m = find( map p, ret["partitions"]:[],
  3198.           ``(!p["delete"]:false && !contains(keep,p["name"]:"")));
  3199.     }
  3200.     if( root==nil && free<root_pe && swap!=nil && swsize==0 )
  3201.     {
  3202.     ret["partitions"] = maplist( map p, ret["partitions"]:[],
  3203.         ``{
  3204.         if( p["name"]:"" == "swap" )
  3205.         {
  3206.         p["delete"] = true;
  3207.         free = free + sizek_to_pe( p["size_k"]:0, pe, false );
  3208.         }
  3209.         return(p);
  3210.         });
  3211.     swap = nil;
  3212.     y2milestone( "modify_vm pe free %1 root %2", free, root_pe );
  3213.     }
  3214.     if( root==nil && free<root_pe && swsize>0 )
  3215.     {
  3216.     swsize = (swlist[1]:0<swlist[0]:0) ? swlist[1]:0 : swlist[0]:0;
  3217.     y2milestone( "modify_vm new swsize %1", swsize );
  3218.     }
  3219.     if( root==nil && free<root_pe && swap!=nil && swsize<swap["size_k"]:0/1024 )
  3220.     {
  3221.     ret["partitions"] = maplist( map p, ret["partitions"]:[],
  3222.         ``{
  3223.         if( p["name"]:"" == "swap" )
  3224.         {
  3225.         p["delete"] = true;
  3226.         free = free + sizek_to_pe( p["size_k"]:0, pe, false );
  3227.         }
  3228.         return(p);
  3229.         });
  3230.     swap = nil;
  3231.     y2milestone( "modify_vm pe free %1 root %2", free, root_pe );
  3232.     }
  3233.     integer swap_pe = 0;
  3234.     integer home_pe = 0;
  3235.     if( swap==nil && swsize>0 )
  3236.     swap_pe = sizek_to_pe( swsize*1024, pe, false );
  3237.     if( free<root_pe+swap_pe )
  3238.     {
  3239.     y2milestone( "modify_vm pe free %1 root %2 swap %3", 
  3240.                  free, root_pe, swap_pe );
  3241.     if( root==nil && swap_pe>free )
  3242.         {
  3243.         swap_pe = free;
  3244.         free = 0;
  3245.         }
  3246.     else if( swap_pe==0 )
  3247.         {
  3248.         root_pe = free;
  3249.         free = 0;
  3250.         }
  3251.     else
  3252.         {
  3253.         swap_pe = swap_pe*free/(root_pe+swap_pe);
  3254.         root_pe = free-swap_pe;
  3255.         free = 0;
  3256.         }
  3257.     y2milestone( "modify_vm pe free %1 root %2 swap %3", 
  3258.                  free, root_pe, swap_pe );
  3259.     }
  3260.     else
  3261.     {
  3262.     free = free-swap_pe;
  3263.     y2milestone( "modify_vm pe free %1 root %2 swap %3", 
  3264.                  free, root_pe, swap_pe );
  3265.     if( home==nil && Storage::ProposalHome() &&
  3266.         free>sizek_to_pe( opts["home_limit"]:0*1024, pe, false ) )
  3267.         {
  3268.         integer tmp = free * opts["root_percent"]:40 / 100;
  3269.         if( tmp>root_pe )
  3270.         root_pe=tmp;
  3271.         tmp = sizek_to_pe( opts["root_max"]:0*1024, pe, false );
  3272.         if( root_pe>tmp )
  3273.         root_pe=tmp;
  3274.         free = free-root_pe;
  3275.         home_pe = free;
  3276.         tmp = sizek_to_pe( opts["home_max"]:0*1024, pe, false );
  3277.         if( home_pe>tmp )
  3278.         home_pe = tmp;
  3279.         free = free-home_pe;
  3280.         y2milestone( "modify_vm pe free %1 root %2 home %3", 
  3281.              free, root_pe, home_pe );
  3282.         }
  3283.     else 
  3284.         {
  3285.         integer tmp = sizek_to_pe( opts["root_max"]:0*1024, pe, false );
  3286.         root_pe = free;
  3287.         if( root_pe>tmp )
  3288.         root_pe=tmp;
  3289.         free = free-root_pe;
  3290.         }
  3291.     }
  3292.     y2milestone( "modify_vm pe free %1 root %2 swap %3 home %4", 
  3293.          free, root_pe, swap_pe, home_pe );
  3294.     if( root==nil && root_pe>0 )
  3295.     {
  3296.     map p = $[ "create":true, "name" : "root", 
  3297.                "format":true, "used_fs" : Partitions::DefaultFs(),
  3298.            "device" : ret["device"]:"" + "/root",
  3299.            "mount" : "/",
  3300.                "size_k" : pe_to_sizek(root_pe,pe) ];
  3301.         p["fstopt"] = FileSystems::DefaultFstabOptions( p );
  3302.         p["fs_options"] = FileSystems::DefaultFormatOptions( p );
  3303.     y2milestone( "modify_vm created %1", p );
  3304.     ret["partitions"] = add( ret["partitions"]:[], p );
  3305.     }
  3306.     else if( root!=nil )
  3307.     {
  3308.     ret["partitions"] = maplist( map p, ret["partitions"]:[],
  3309.         ``{
  3310.         if( p["name"]:"" == "root" )
  3311.         {
  3312.         p["mount"] = "/";
  3313.         p["format"] = true;
  3314.         if( p["detected_fs"]:`unknown==`unknown )
  3315.             {
  3316.             p["used_fs"] = Partitions::DefaultFs();
  3317.             }
  3318.         p["fstopt"] = FileSystems::DefaultFstabOptions( p );
  3319.         p["fs_options"] = FileSystems::DefaultFormatOptions( p );
  3320.         y2milestone( "modify_vm reuse %1", p );
  3321.         }
  3322.         return(p);
  3323.         });
  3324.     }
  3325.     if( swap==nil && swap_pe>0 )
  3326.     {
  3327.     map p = $[ "create":true, "name" : "swap", 
  3328.                "format":true, "used_fs" : `swap,
  3329.            "device" : ret["device"]:"" + "/swap",
  3330.            "mount" : "swap",
  3331.                "size_k" : pe_to_sizek(swap_pe,pe) ];
  3332.         p["fstopt"] = FileSystems::DefaultFstabOptions( p );
  3333.     p["fs_options"] = FileSystems::DefaultFormatOptions( p );
  3334.     y2milestone( "modify_vm created %1", p );
  3335.     ret["partitions"] = add( ret["partitions"]:[], p );
  3336.     }
  3337.     else if( swap!=nil )
  3338.     {
  3339.     ret["partitions"] = maplist( map p, ret["partitions"]:[],
  3340.         ``{
  3341.         if( p["name"]:"" == "swap" )
  3342.         {
  3343.         p["mount"] = "swap";
  3344.         if( p["detected_fs"]:`unknown!=`swap )
  3345.             {
  3346.             p["format"] = true;
  3347.             p["used_fs"] = `swap;
  3348.             p["fs_options"] = FileSystems::DefaultFormatOptions( p );
  3349.             }
  3350.         p["fstopt"] = FileSystems::DefaultFstabOptions( p );
  3351.         y2milestone( "modify_vm reuse %1", p );
  3352.         }
  3353.         return(p);
  3354.         });
  3355.     }
  3356.     if( home==nil && home_pe>0 )
  3357.     {
  3358.     map p = $[ "create":true, "name" : "home", 
  3359.                "format":true, "used_fs" : Partitions::DefaultFs(),
  3360.            "device" : ret["device"]:"" + "/home",
  3361.            "mount" : "/home",
  3362.                "size_k" : pe_to_sizek(home_pe,pe) ];
  3363.         p["fstopt"] = FileSystems::DefaultFstabOptions( p );
  3364.     p["fs_options"] = FileSystems::DefaultFormatOptions( p );
  3365.     y2milestone( "modify_vm created %1", p );
  3366.     ret["partitions"] = add( ret["partitions"]:[], p );
  3367.     }
  3368.     else if( home!=nil )
  3369.     {
  3370.     ret["partitions"] = maplist( map p, ret["partitions"]:[],
  3371.         ``{
  3372.         if( p["name"]:"" == "home" )
  3373.         {
  3374.         p["mount"] = "/home";
  3375.         if( p["detected_fs"]:`unknown==`unknown )
  3376.             {
  3377.             p["format"] = true;
  3378.             p["used_fs"] = Partitions::DefaultFs();
  3379.             p["fs_options"] = FileSystems::DefaultFormatOptions( p );
  3380.             }
  3381.         p["fstopt"] = FileSystems::DefaultFstabOptions( p );
  3382.         y2milestone( "modify_vm reuse %1", p );
  3383.         }
  3384.         return(p);
  3385.         });
  3386.     }
  3387.     y2milestone( "modify_vm ret %1", ret );
  3388.     return( ret );
  3389.     }
  3390.  
  3391. map get_inst_prop_vm( map<string,map> target, string key )
  3392.     {
  3393.     y2milestone( "get_inst_prop_vm start key %1", key );
  3394.     map ret = $[];
  3395.     map opts = Storage::GetControlCfg();
  3396.     string vg_key = find_vm( target, key, opts["root_base"]:0*1024 );
  3397.     target = remove_mount_points(target);
  3398.     if( size(vg_key)==0 )
  3399.     target = remove_vm(target,key);
  3400.     target = Storage::AddWinInfo(target);
  3401.     ret["target"] = target;
  3402.     map boot = $[ "mount" : Partitions::BootMount(), 
  3403.                   "size" : Partitions::MinimalNeededBootsize(),
  3404.                   "fsys" : Partitions::DefaultBootFs(),
  3405.           "id" : Partitions::FsidBoot(),
  3406.           "max_cyl" : Partitions::BootCyl() ];
  3407.     if( Partitions::BootPrimary() )
  3408.     {
  3409.     boot["primary"] = true;
  3410.     }
  3411.     list<string> ddev = get_disk_try_list( target, true );
  3412.     string sol_disk = "";
  3413.     list modes = [ `free, `remove, `resize, `desparate ];
  3414.     map<string,boolean> valid = $[];
  3415.     map<string,integer> size_mb = listmap( string s, ddev, ``($[s:0]));
  3416.     map<string,boolean> keep_vg = $[];
  3417.     map solution = listmap( string s, ddev, ``($[s:[]]));
  3418.     target = prepare_part_lists( ddev, target );
  3419.     symbol mode = `free;
  3420.     while( mode != `end && size(sol_disk)==0 )
  3421.     {
  3422.     if( mode == `free || mode == `desparate )
  3423.         {
  3424.         valid = listmap( string s, ddev, ``($[s:true]));
  3425.         if( mode == `desparate )
  3426.         {
  3427.         ddev = get_disk_try_list( target, false );
  3428.         valid = listmap( string s, ddev, ``($[s:true]));
  3429.         target = prepare_part_lists( ddev, target );
  3430.         foreach( string s, ddev,
  3431.             ``{
  3432.             target[s,"partitions"] = 
  3433.             remove_p_settings( target[s,"partitions"]:[], [] );
  3434.             target[s,"partitions"] = 
  3435.             maplist( map p, target[s,"partitions"]:[],
  3436.                 ``{
  3437.                 if( !contains( Partitions::do_not_delete, 
  3438.                        p["fsid"]:0 ))
  3439.                 {
  3440.                 if( usable_for_win_resize(p,false) )
  3441.                     p["dtxt"] = _("Resize impossible due to inconsistent fs. Try checking fs under Windows.");
  3442.                 p["delete"] = true;
  3443.                 }
  3444.                 return( p );
  3445.                 });
  3446.             });
  3447.         }
  3448.         }
  3449.     else if( mode == `remove )
  3450.         {
  3451.         valid = listmap( string s, ddev, 
  3452.         ``{
  3453.         if( find( map p, target[s,"partitions"]:[], 
  3454.                   ``(p["linux"]:false && size(p["mount"]:"")==0 &&
  3455.                  !p["delete"]:false)) != nil )
  3456.             return( $[s:true] );
  3457.         else
  3458.             return( $[s:false] );
  3459.         });
  3460.         foreach( string s, filter( string d, ddev, ``(valid[d]:false)),
  3461.         ``{
  3462.         target[s,"partitions"] = 
  3463.             remove_one_partition_vm( target[s]:$[] );
  3464.         });
  3465.         }
  3466.     else if( mode == `resize )
  3467.         {
  3468.         valid = listmap( string s, ddev, 
  3469.         ``{
  3470.         if( find( map p, target[s,"partitions"]:[], 
  3471.             ``(usable_for_win_resize(p,true))) != nil )
  3472.             return( $[s:true] );
  3473.         else
  3474.             return( $[s:false] );
  3475.         });
  3476.         foreach( string s, filter( string d, ddev, ``(valid[d]:false)),
  3477.         ``{
  3478.         list<map> pl = filter( map p, target[s,"partitions"]:[],
  3479.                        ``(usable_for_win_resize(p,true)));
  3480.         if( size(pl)>0 )
  3481.             {
  3482.             pl = sort( map a, map b, pl, 
  3483.                    ``(a["size_k"]:0>b["size_k"]:0));
  3484.             target[s,"partitions"] = 
  3485.             maplist( map p, target[s,"partitions"]:[],
  3486.                 ``{
  3487.                 if( usable_for_win_resize(p,true) &&
  3488.                 p["device"]:""==pl[0,"device"]:"" )
  3489.                 {
  3490.                 integer cs = target[s,"cyl_size"]:1;
  3491.                 p["resize"] = true;
  3492.                 p["region",1] = 
  3493.                     (p["winfo","new_size"]:0+cs-1) / cs;
  3494.                 p["win_max_length"] =
  3495.                     (p["winfo","max_win_size"]:0+cs-1) / cs;
  3496.                 }
  3497.                 return( p );
  3498.                 });
  3499.             y2milestone( "get_inst_prop_vm res parts %1", 
  3500.                          target[s,"partitions"]:[] );
  3501.             }
  3502.         });
  3503.         }
  3504.     y2milestone( "get_inst_prop_vm mode %1 valid %2", mode, valid );
  3505.     foreach( string s, filter( string d, ddev, ``(valid[d]:false)),
  3506.         ``{
  3507.         map disk = target[s]:$[];
  3508.         map conf = $[ "partitions" : [] ];
  3509.         list<map> p = can_boot_reuse( s, disk["label"]:"msdos", true,
  3510.                       disk["max_primary"]:4,
  3511.                       disk["partitions"]:[] );
  3512.         disk["partitions"] = 
  3513.         special_boot_proposal_prepare( disk["partitions"]:[] );
  3514.         boolean have_boot = size(p)>0;
  3515.         if( have_boot )
  3516.             disk["partitions"] = p;
  3517.         string vg = vg_key;
  3518.         if( size(vg)>0 && did_remove_vg( disk["partitions"]:[], key ))
  3519.         vg = "";
  3520.         map ps = do_vm_disk_conf( disk, have_boot?($[]):boot, vg, key );
  3521.         if( ps["ok"]:false )
  3522.         {
  3523.         integer mb = get_vm_sol( ps );
  3524.         if( mb-size_mb[s]:0>size_mb[s]:0/40 )
  3525.             {
  3526.             y2milestone( "get_inst_prop_vm new sol %1 old %2 new %3",
  3527.                          s, size_mb[s]:0, mb );
  3528.             solution[s] = ps["disk"]:$[];
  3529.             size_mb[s] = mb;
  3530.             }
  3531.         if( size(vg)>0 && !keep_vg[s]:false )
  3532.             keep_vg[s] = true;
  3533.         }
  3534.         });
  3535.     y2milestone( "get_inst_prop_vm size_mb %1 keep_vg %2", 
  3536.                  size_mb, keep_vg );
  3537.     integer max_mb = 0;
  3538.     string max_disk = "";
  3539.     string keep_disk = "";
  3540.     foreach( string s, integer mb, size_mb,
  3541.         ``{
  3542.         if( mb > max_mb )
  3543.         {
  3544.         max_mb = mb;
  3545.         max_disk = s;
  3546.         }
  3547.         });
  3548.     foreach( string s, boolean keep, keep_vg,
  3549.         ``{
  3550.         if( size(keep_disk)==0 && keep )
  3551.         {
  3552.         keep_disk = s;
  3553.         }
  3554.         });
  3555.     if( size(keep_disk)>0 )
  3556.         {
  3557.         sol_disk = keep_disk;
  3558.         }
  3559.     else if( max_mb>0 && size_mb[max_disk]:0 > opts["vm_want"]:(20*1024) )
  3560.         {
  3561.         sol_disk = max_disk;
  3562.         vg_key = "";
  3563.         }
  3564.     y2milestone( "get_inst_prop_vm mode %1 sol_disk %2", mode, sol_disk );
  3565.     if( size(sol_disk)==0 )
  3566.         {
  3567.         list<boolean> lb = maplist(string s, boolean e, valid, ``(e));
  3568.         if( mode == `free )
  3569.         mode = `remove;
  3570.         else if( mode == `remove && find( boolean v, lb, ``(v)) == nil )
  3571.         mode = `resize;
  3572.         else if( mode == `resize && find( boolean v, lb, ``(v)) == nil )
  3573.         mode = `desparate;
  3574.         else if( mode == `desparate )
  3575.         mode = `end;
  3576.         }
  3577.     }
  3578.     y2milestone( "get_inst_prop_vm sol_disk %1", sol_disk );
  3579.     if( size(sol_disk)==0 )
  3580.     {
  3581.     integer max_mb = 0;
  3582.     foreach( string s, integer mb, size_mb,
  3583.         ``{
  3584.         if( mb>max_mb )
  3585.         {
  3586.         max_mb = mb;
  3587.         sol_disk = s;
  3588.         }
  3589.         });
  3590.     y2milestone( "get_inst_prop_vm sol_disk %1", sol_disk );
  3591.     }
  3592.     ret["ok"] = size(sol_disk)>0;
  3593.     if( ret["ok"]:false )
  3594.     {
  3595.     map r = can_swap_reuse( sol_disk, solution[sol_disk,"partitions"]:[], 
  3596.                             ret["target"]:$[] );
  3597.     if( haskey( r, "partitions" ))
  3598.         solution[sol_disk,"partitions"] = r["partitions"]:[];
  3599.     else if( haskey( r, "targets" ))
  3600.         ret["target"] = r["targets"]:$[];
  3601.     ret["target"] = remove_used_by( ret["target"]:$[], sol_disk );
  3602.     if( size(vg_key)==0 )
  3603.         {
  3604.         vg_key = (Storage::ProposalEvms()?"/dev/evms/lvm2/":"/dev/")+key;
  3605.         map vg = ret["target",vg_key]:$[];
  3606.         vg = union( vg, create_vm( Storage::ProposalEvms(), key,
  3607.                        solution[sol_disk]:$[] ));
  3608.         if( size(vg["devices"]:[])>0 )
  3609.         {
  3610.         vg = remove( vg, "devices" );
  3611.         }
  3612.         y2milestone( "get_inst_prop_vm vkey %1", vg );
  3613.         ret["target",vg_key] = vg;
  3614.         }
  3615.     else
  3616.         {
  3617.         map vg = ret["target",vg_key]:$[];
  3618.         vg = extend_vm( vg, key, solution[sol_disk]:$[] );
  3619.         ret["target",vg_key] = vg;
  3620.         }
  3621.     ret["target",vg_key] = modify_vm( ret["target",vg_key]:$[], opts,
  3622.                                       size(r)==0 );
  3623.     ret["target",sol_disk] = solution[sol_disk]:$[];
  3624.     ret["target"] = Storage::SpecialBootHandling( ret["target"]:$[] );
  3625.     y2milestone( "get_inst_prop_vm sol:%1", ret["target",sol_disk]:$[] );
  3626.     }
  3627.     y2milestone( "get_inst_prop_vm ret[ok]:%1", ret["ok"]:false );
  3628.     return( ret );
  3629.     }
  3630.  
  3631. map get_proposal_vm( map<string,map> target, string key, map disk )
  3632.     {
  3633.     string ddev = disk["device"]:"";
  3634.     y2milestone( "get_proposal_vm ddev:%1 vg:%2 evms:%3 lvm:%4 home:%5", ddev,
  3635.                  key, Storage::ProposalEvms(), Storage::ProposalLvm(),
  3636.          Storage::ProposalHome() );
  3637.     map ret = $[];
  3638.     map opts = Storage::GetControlCfg();
  3639.     target = remove_mount_points(target);
  3640.     target = remove_vm(target,key);
  3641.     ret["target"] = target;
  3642.     map boot = $[ "mount" : Partitions::BootMount(), 
  3643.                   "size" : Partitions::MinimalNeededBootsize(),
  3644.                   "fsys" : Partitions::DefaultBootFs(),
  3645.           "id" : Partitions::FsidBoot(),
  3646.           "max_cyl" : Partitions::BootCyl() ];
  3647.     if( Partitions::BootPrimary() )
  3648.     {
  3649.     boot["primary"] = true;
  3650.     }
  3651.     map conf = $[ "partitions" : [] ];
  3652.     list<map> p = can_boot_reuse( ddev, disk["label"]:"msdos", true,
  3653.                   disk["max_primary"]:4,
  3654.                   disk["partitions"]:[] );
  3655.     disk["partitions"] = special_boot_proposal_prepare( disk["partitions"]:[] );
  3656.     boolean have_boot = size(p)>0;
  3657.     if( have_boot )
  3658.     disk["partitions"] = p;
  3659.     map ps = do_vm_disk_conf( disk, have_boot?($[]):boot, "", key );
  3660.     ret["ok"] = ps["ok"]:false;
  3661.     if( ret["ok"]:false )
  3662.     {
  3663.     disk = ps["disk"]:$[];
  3664.     map r = can_swap_reuse( ddev, disk["partitions"]:[], 
  3665.                             ret["target"]:$[] );
  3666.     if( haskey( r, "partitions" ))
  3667.         disk["partitions"] = r["partitions"]:[];
  3668.     else if( haskey( r, "targets" ))
  3669.         ret["target"] = r["targets"]:$[];
  3670.     ret["target"] = remove_used_by( ret["target"]:$[], ddev );
  3671.     string vg_key = (Storage::ProposalEvms()?"/dev/evms/lvm2/":"/dev/")+key;
  3672.     map vg = ret["target",vg_key]:$[];
  3673.     vg = union( vg, create_vm( Storage::ProposalEvms(), key, disk ));
  3674.     if( size(vg["devices"]:[])>0 )
  3675.         {
  3676.         vg = remove( vg, "devices" );
  3677.         }
  3678.     y2milestone( "get_proposal_vm vkey %1", vg );
  3679.     ret["target",vg_key] = modify_vm( vg, opts, size(r)==0 );
  3680.     ret["target",ddev] = disk;
  3681.     ret["target"] = Storage::SpecialBootHandling( ret["target"]:$[] );
  3682.     y2milestone( "get_proposal_vm sol:%1", disk );
  3683.     }
  3684.     y2milestone( "get_proposal_vm ret[ok]:%1", ret["ok"]:false );
  3685.     return( ret );
  3686.     }
  3687.  
  3688. map get_inst_prop( map<string,map> target )
  3689.     {
  3690.     map ret = $[];
  3691.     string vg = Storage::ProposalVM();
  3692.     y2milestone( "get_inst_prop vg:%1 evms:%2 lvm:%3 home:%4", vg, 
  3693.                  Storage::ProposalEvms(), Storage::ProposalLvm(),
  3694.          Storage::ProposalHome() );
  3695.     if( size(vg)==0 )
  3696.     ret = get_inst_proposal( target );
  3697.     else
  3698.     {
  3699.     if( Storage::ProposalEvms() && 
  3700.         size(target["/dev/evms","partitions"]:[])==0 )
  3701.         {
  3702.         Storage::ActivateEvms();
  3703.         target = Storage::GetTargetMap();
  3704.         }
  3705.     ret = get_inst_prop_vm( target, vg );
  3706.     }
  3707.     return( ret );
  3708.     }
  3709.  
  3710. }
  3711.  
  3712.