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 / autoinstall / autopart.ycp < prev    next >
Text File  |  2006-11-29  |  65KB  |  1,573 lines

  1. /*
  2.  
  3.  
  4. $Id: autopart.ycp 33409 2006-10-13 14:22:46Z ug $
  5. */
  6. {
  7.     textdomain "autoinst";
  8.  
  9.     import "FileSystems";
  10.  
  11.     include "partitioning/partition_defines.ycp";
  12.  
  13.  
  14.  
  15.     map get_gap_info( map disk, map pd, boolean add_exist_linux );
  16.     map add_cylinder_info( map conf, map gap );
  17.     map get_perfect_list( list ps, map g );
  18.     map process_partition_data( string dev, map solution );
  19.     map find_matching_disk( list<string> disks, map target, map conf );
  20.     map try_resize_windows( map disk );
  21.     map remove_possible_partitions( map disk, map conf );
  22.     map distribute_space( integer rest, list weights, list added, list ps );
  23.     void add_part_recursive( list ps, map g );
  24.     map normalize_gaps( list ps, map g );
  25.     integer do_weighting( list ps, map g );
  26.  
  27.     symbol cur_mode = `free;
  28.     integer cur_weight = -10000;
  29.     map cur_gap = $[];
  30.  
  31.  
  32.     list GetNoneLinuxPartitions(string device) {
  33.         list ret = [];
  34.         foreach ( string dev, map disk, Storage::GetTargetMap(), ``{
  35.                 if( Storage::IsRealDisk( disk )  && dev == device)
  36.                 {
  37.                 list<map> l = (list<map>) filter( map p, disk["partitions"]:[],
  38.                     ``(!p["delete"]:false &&
  39.                         !p["format"]:false &&
  40.                         !Partitions::IsLinuxPartition(p["fsid"]:0)) );
  41.  
  42.                 l = filter(map p, l, ``(!contains( [`xfs, `ext2, `ext3, `jfs, `reiser],
  43.                             p["used_fs"]:`unknown)));
  44.                 l = filter(map p, l,
  45.                     ``(!FileSystems::IsSystemMp( p["mount"]:"", false )));
  46.                 if( size(l)>0 )
  47.                 {
  48.                     list<integer> ln =  maplist( map p, l, ``(p["nr"]:0));
  49.                     ret = union( ret, ln );
  50.                 }
  51.                 }
  52.                 });
  53.         y2milestone( "GetNoneLinuxPartitions ret=%1", ret );
  54.         return( ret );
  55.     }
  56.  
  57.  
  58.     list<integer> GetAllPartitions(string device) {
  59.         list<integer> ret = [];
  60.         foreach ( string dev, map disk, Storage::GetTargetMap(), ``{
  61.                 if( Storage::IsRealDisk( disk )  && dev == device)
  62.                 {
  63.                 list<integer> l = maplist( map p, disk["partitions"]:[],
  64.                     ``(p["nr"]:0));
  65.  
  66.                 ret = (list<integer>)union( ret, l );
  67.                 }
  68.                 });
  69.         y2milestone( "All Partitions ret=%1", ret );
  70.         return( ret );
  71.     }
  72.  
  73.     /**
  74.      * Read partition data from XML control file
  75.      * @return map flexible propsal map
  76.      */
  77.     define list<map> preprocess_partition_config(list<map> xmlflex) {
  78.         
  79.         y2debug("xml input: %1", xmlflex );
  80.         map<string,any> tm = Storage::GetTargetMap();
  81.         list<map>partitioning = maplist(map d, xmlflex, ``{
  82.             
  83.             foreach( string key, [ "keep_partition_id", "keep_partition_num"], ``{
  84.                 list num = [];
  85.                 list<string> nlist = splitstring(d[key]:"", ",");
  86.                 foreach( string n, nlist, ``{ num = union( num, [tointeger(n)] );});
  87.                 d[key] = num;
  88.             });
  89.  
  90.             list fsys = [];
  91.             list<string> nlist = splitstring( d["keep_partition_fsys"]:"" , "," );
  92.             foreach( string n, nlist,
  93.                      ``{
  94.                 symbol fs = FileSystems::FsToSymbol(n);
  95.                 if( fs != `none )
  96.                 {
  97.                     fsys = union( fsys, [ fs ] );
  98.                 }
  99.             });
  100.             d["keep_partition_fsys"] = fsys;
  101.  
  102.  
  103.             list<map> user_partitions = d["partitions"]:[];
  104.             if (size(user_partitions) == 0)
  105.             {
  106.                 y2milestone("no partitions specified, creating default scheme");
  107.                 map root = $[];
  108.                 root["mount"] = "/";
  109.                 root["size"] = "max";
  110.                 map swap = $[];
  111.                 swap["mount"] = "swap";
  112.                 swap["size"] = "auto";
  113.                 user_partitions=add(user_partitions, swap);
  114.                 user_partitions=add(user_partitions, root);
  115.                 
  116.             }
  117.             
  118.             list partitions = [];
  119.             foreach(map partition, user_partitions,
  120.                     ``{
  121.                 if (haskey(partition, "maxsize"))
  122.                 {
  123.                     partition["max"] = kmgt_str_to_byte(partition["maxsize"]:"");
  124.                 } 
  125.                     
  126.                 if (partition["size"]:"" != "")
  127.                 {
  128.                     string s = partition["size"]:"";
  129.                     if( tolower(s) == "auto" )
  130.                     {
  131.                         partition["size"] = -1;
  132.                     }
  133.                     else if( tolower(s) == "max" )
  134.                     {
  135.                         partition["size"] = 0;
  136.                     }
  137.                     else
  138.                     {
  139.                         partition["size"] = kmgt_str_to_byte( s );
  140.                     }
  141.                 }
  142.                     
  143.                 if( partition["size"]:0 == -1 && partition["mount"]:"" == "swap" )
  144.                 {
  145.                     partition["size"] = 1024*1024*Partitions::SwapSizeMb(0);
  146.                 }
  147.             
  148.                 if( partition["mount"]:"" == Partitions::BootMount() )
  149.                 {
  150.                     if( partition["size"]:0 == -1 )
  151.                         partition["size"] = Partitions::MinimalNeededBootsize();
  152.  
  153.                     if( partition["filesystem"]:`none == `none )
  154.                         partition["filesystem"] = Partitions::DefaultBootFs();
  155.  
  156.                     if( partition["filesystem_id"]:0 == 0 )
  157.                         partition["filesystem_id"] = Partitions::FsidBoot();
  158.  
  159.                     //partition["max_cyl"] = Partitions::BootCyl();
  160.                 }
  161.                 
  162.                 if( partition["size"]:0 == -1 )
  163.                     partition["size"] = 0;
  164.  
  165.                 if (partition["used_by_type"]:`UB_NONE==`UB_LVM)
  166.                         partition["filesystem_id"] =  Partitions::fsid_lvm;
  167.                 else if (partition["used_by_type"]:`UB_NONE==`UB_EVMS)
  168.                     partition["filesystem_id"] =  Partitions::fsid_lvm;
  169.                 else if (partition["used_by_type"]:`UB_NONE==`UB_MD)
  170.                     partition["filesystem_id"] =  Partitions::fsid_raid;
  171.  
  172.                 partition["fsid"] = partition["filesystem_id"]:Partitions::fsid_native;
  173.                 
  174.                 y2debug("partition: %1", partition);
  175.                 partitions = add( partitions, partition );
  176.             });
  177.         
  178.             if (d["type"]:`CT_UNKNONW!=`CT_LVM && d["type"]:`CT_UNKNONW!=`CT_EVMS) {
  179.                 d["partitions"] = partitions;
  180.             }
  181.             return (d);
  182.         });
  183.         
  184.         y2milestone( "conf: %1", partitioning );
  185.         return( partitioning );
  186.     }
  187.  
  188.     define map try_add_boot( map conf, map disk ) {
  189.         boolean boot = 
  190.             size(filter( map e, conf["partitions"]:[], 
  191.                          ``(e["mount"]:""==Partitions::BootMount() || (e["partition_id"]:0 == Partitions::FsidBoot() && Partitions::FsidBoot() != 131 ) ))) > 0;
  192.         boolean root = size(filter( map e, conf["partitions"]:[], 
  193.                                     ``(e["mount"]:""=="/"))) > 0;
  194.         map tc = (map) eval(conf);
  195.         if( !boot && root &&
  196.             (disk["cyl_count"]:0 > Partitions::BootCyl() ||
  197.              Arch::ia64 () || Arch::ppc () || Arch::sparc ()) )
  198.         {
  199.             map pb = $[];
  200.             if( ! Arch::ppc () ) {
  201.                 pb["mount"] = Partitions::BootMount();
  202.                 pb["fsys"] = Partitions::DefaultBootFs();
  203.             }
  204.             pb["size"] = Partitions::MinimalNeededBootsize();
  205.             pb["filesystem"] = Partitions::DefaultBootFs();
  206.             pb["fsid"] = Partitions::FsidBoot(); // FIXME: might be useless
  207.             pb["filesystem_id"] = Partitions::FsidBoot();
  208.             pb["id"] = Partitions::FsidBoot(); // FIXME: might be useless
  209.             pb["auto_added"] = true;
  210.             pb["type"] = `primary; // FIXME: might be useless
  211.             pb["partition_type"] = "primary";
  212.             pb["nr"] = 1;
  213.             //pb["max_cyl"] = Partitions::BootCyl();
  214.             //tc["partitions"] = add( tc["partitions"]:[], pb );
  215.             tc["partitions"] = merge( [ pb ], tc["partitions"]:[] );
  216.             y2milestone( "boot added automagically pb %1", pb );
  217.         }
  218.         return( tc );
  219.     }
  220.  
  221.  
  222.     /**
  223.      * Find matching disk
  224.      */
  225.     define map find_matching_disk( list<string> disks, map target, map conf )
  226.         ``{
  227.         map<string,map> solutions = $[];
  228.  
  229.         cur_weight = -100000;
  230.         cur_gap = $[];
  231.         foreach( string k, disks,
  232.                  ``{
  233.             map e = target[k]:$[];
  234.             map pd = conf;
  235.             y2milestone( "processing disk %1", k );
  236.             y2milestone( "parts %1", conf["partitions"]:[] );
  237.             map tc = try_add_boot( conf, e );
  238.             cur_mode = `free;
  239.             if( !tc["prefer_remove"]:false )
  240.             {
  241.                 map gap = get_gap_info( e, pd , false );
  242.                 tc = add_cylinder_info( tc, gap );
  243.                 map l = get_perfect_list( tc["partitions"]:[], gap );
  244.                 if( size(l)>0 )
  245.                 {
  246.                     solutions[k] = eval(l);
  247.                     solutions[k,"disk"] = eval(e);
  248.                 }
  249.                 cur_mode = `reuse;
  250.                 map egap = get_gap_info( e, pd, true );
  251.                 if( size(egap["gap"]:[]) > size(gap["gap"]:[]) )
  252.                 {
  253.                     tc = add_cylinder_info( tc, egap );
  254.                     l = get_perfect_list( tc["partitions"]:[], egap );
  255.                     if( size(l)>0 && 
  256.                         (!haskey(solutions,k) || 
  257.                          (haskey( l, "weight" ) && 
  258.                           l["weigth"]:0 > solutions[k,"weigth"]:0 )))
  259.                     {
  260.                         y2milestone( "solution reuse existing" );
  261.                         solutions[k] = eval(l);
  262.                         solutions[k,"disk"] = eval(e);
  263.                     }
  264.                 }
  265.                 cur_mode = `resize;
  266.                 map rw = try_resize_windows( e );
  267.                 if( size( filter( map p, rw["partitions"]:[],
  268.                                   ``(haskey(p, "winfo")) ))>0 )
  269.                 {
  270.                     egap = get_gap_info( rw, pd, true );
  271.                     tc = add_cylinder_info( tc, egap );
  272.                     l = get_perfect_list( tc["partitions"]:[], egap );
  273.                     if( size(l)>0 && 
  274.                         (!haskey(solutions,k) ||
  275.                          (haskey( l, "weight" ) && 
  276.                           l["weigth"]:0 > solutions[k,"weigth"]:0 )))
  277.                     {
  278.                         y2milestone( "solution resizing windows" );
  279.                         solutions[k] = eval(l);
  280.                         solutions[k,"disk"] = eval(rw);
  281.                     }
  282.                 }
  283.             }
  284.             else
  285.             {
  286.                 cur_mode = `free;
  287.                 map rp = remove_possible_partitions( e, tc );
  288.                 map gap = get_gap_info( rp, pd, false );
  289.                 tc = add_cylinder_info( tc, gap );
  290.                 map l = get_perfect_list( tc["partitions"]:[], gap );
  291.                 if( size(l)>0 )
  292.                 {
  293.                     solutions[k] = eval(l);
  294.                     solutions[k,"disk"] = eval(rp);
  295.                 }
  296.             }
  297.         });
  298.         map ret = $[];
  299.         if( size(solutions)>0 )
  300.         {
  301.             foreach( string k, map e, solutions,
  302.                      ``{
  303.                 y2milestone( "disk %1 weight %2", k, e["weight"]:0 );
  304.             });
  305.             list<string> disks = maplist( string k, map e, solutions, ``(k) );
  306.             disks = sort( string a, string b, disks, 
  307.                           ``(solutions[a,"weight"]:0>solutions[b,"weight"]:0));
  308.             y2milestone( "sorted disks %1", disks );
  309.             ret = solutions[disks[0]:""]:$[];
  310.             ret["device"] = disks[0]:"";
  311.         }
  312.         return( ret );
  313.     }
  314.  
  315.  
  316.     
  317.     /**
  318.      * Process partition data
  319.      */
  320.     define map process_partition_data( string dev, map solution )
  321.         ``{
  322.         map disk = solution["disk"]:$[];
  323.         list<map> partitions = [];
  324.         string value = "";
  325.         map mapvalue = $[];
  326.         boolean remove_boot = false;
  327.         if( size( filter( map e, solution["partitions"]:[], 
  328.                           ``(e["mount"]:""==Partitions::BootMount() && 
  329.                              e["auto_added"]:false)))>0 )
  330.         {
  331.             foreach( map e, solution["solution","gap"]:[],
  332.                      ``{
  333.                 foreach( list a, e["added"]:[],
  334.                          ``{
  335.                     integer pindex = a[0]:0;
  336.                     if( solution["partitions",pindex,"mount"]:"" == "/" &&
  337.                         disk["cyl_count"]:0 > Partitions::BootCyl() &&
  338.                         e["end"]:0 <= Partitions::BootCyl() )
  339.                     {
  340.                         remove_boot = true;
  341.                     }
  342.                 });
  343.             });
  344.         }
  345.         integer index = 0;
  346.         if( remove_boot )
  347.         {
  348.             foreach( map e, solution["solution","gap"]:[],
  349.                      ``{
  350.                 list nlist = [];
  351.                 foreach( list a, e["added"]:[],
  352.                          ``{
  353.                     integer pindex = a[0]:0;
  354.                     if( solution["partitions",pindex,"mount"]:"" == 
  355.                         Partitions::BootMount() )
  356.                     {
  357.                         integer rest = a[2]:0;
  358.                         y2milestone( "remove unneeded %3 %1 cyl %2", 
  359.                                      e["added"]:[], rest, Partitions::BootMount() );
  360.                         list<list> nlist = filter( list l, e["added"]:[], ``(l[0]:0!=pindex));
  361.                         if( size(nlist)>0 && !e["exists"]:false )
  362.                         {
  363.                             list weight = maplist( list l, nlist, ``(l[2]:0) );
  364.                             map r = $[];
  365.                             r = distribute_space( rest, weight, nlist, 
  366.                                                   solution["partitions"]:[] );
  367.                             nlist = eval(r["added"]:[]);
  368.                             solution["solution","gap",index,"cylinders"] = 
  369.                                 e["cylinders"]:0 - r["diff"]:0;
  370.                         }
  371.                         solution["solution","gap",index,"added"] = eval(nlist);
  372.                         y2milestone( "remove unneeded %2 %1", e["added"]:[],
  373.                                      Partitions::BootMount() );
  374.                     }
  375.                     pindex = pindex+1;
  376.                 });
  377.                 index = index + 1;
  378.             });
  379.         }
  380.         index = 0;
  381.         foreach( map e, solution["solution","gap"]:[],
  382.                  ``{
  383.             if( !e["exists"]:false && e["cylinders"]:0>0 )
  384.             {
  385.                 integer increase = 0;
  386.                 list<integer> weight = 
  387.                     maplist( list l, e["added"]:[], 
  388.                              ``(solution["partitions",l[0]:0,"grow"]:false ? 1 : 0) );
  389.                 if( find( integer l, weight, ``(l>0) ) != nil ) 
  390.                 {
  391.                     map r = $[];
  392.                     r = distribute_space( e["cylinders"]:0, weight, e["added"]:[], 
  393.                                           solution["partitions"]:[] );
  394.                     solution["solution","gap",index,"added"] = eval(r["added"]:[]);
  395.                     solution["solution","gap",index,"cylinders"] = 
  396.                         e["cylinders"]:0 - r["diff"]:0;
  397.                     y2milestone( "increase increasable p %1 cyl %2", 
  398.                                  solution["solution","gap",index,"added"]:[],
  399.                                  solution["solution","gap",index,"cylinders"]:0 );
  400.                 }
  401.             }
  402.             index = index + 1;
  403.         });
  404.         foreach( map e, solution["solution","gap"]:[],
  405.                  ``{
  406.             if( e["exists"]:false )
  407.             {
  408.                 integer index = 0;
  409.                 integer pindex = e["added",0,0]:0;
  410.                 string mount = solution["partitions",pindex,"mount"]:"";
  411.                 integer fsid = Partitions::fsid_native;
  412.                 if( mount == "swap" )
  413.                 {
  414.                     fsid = Partitions::fsid_swap;
  415.                 }
  416.                 if( solution["partitions",pindex,"id"]:0 != 0 )
  417.                 {
  418.                     fsid = solution["partitions",pindex,"id"]:0;
  419.                 }
  420.                 foreach( map p, disk["partitions"]:[],
  421.                          ``{
  422.                     if( !p["delete"]:false && p["nr"]:0 == e["added",0,1]:0 )
  423.                     {
  424.                         p["format"] = solution["partitions",pindex,"format"]:true;
  425.                         if( solution["partitions",pindex,"resize"]:false == true ) {
  426.                             p["resize"] = true;
  427.                             p["region"] = solution["partitions",pindex,"region"]:[];
  428.                         }
  429.                         p["mount"] = mount;
  430.                         if (e["reuse"]:false)                
  431.                             p["used_fs"] = solution["partitions",pindex,"filesystem"]:p["detected_fs"]:`reiser;
  432.                         else
  433.                             p["used_fs"] = solution["partitions",pindex,"filesystem"]:`reiser;
  434.                         
  435.                         value = solution["partitions",pindex,"fstopt"]:"";
  436.                         if( size(value)>0 )
  437.                         {
  438.                             p["fstopt"] = value;
  439.                         }
  440.                         else
  441.                         {
  442.                             p["fstopt"] = FileSystems::DefaultFstabOptions( p );
  443.                         }
  444.                         mapvalue = solution["partitions",pindex,"fs_options"]:$[];
  445.                         if( size(mapvalue)>0 )
  446.                         {
  447.                             p["fs_options"] = mapvalue;
  448.                         }
  449.                         value = solution["partitions",pindex,"label"]:"";
  450.                         if( size(value)>0 )
  451.                         {
  452.                             symbol mb = solution["partitions",pindex,"mountby"]:`no_mb;
  453.                             if( mb != `no_mb ) {
  454.                                     p["mountby"] = mb;
  455.                             }
  456.                             p["label"] = value;
  457.                         }
  458.                 
  459.                         
  460.                         if (solution["partitions",pindex,"loop_fs"]:false
  461.                             || solution["partitions",pindex,"crypt_fs"]:false)
  462.                         {
  463.                             //p["loop_fs"]  =    solution["partitions",pindex,"crypt_fs"]:false;
  464.                             p["enc_type"] = solution["partitions",pindex,"enc_type"]:`twofish;
  465.                             Storage::UpdateClassified( p["device"]:"",
  466.                                                   solution["partitions",pindex,"crypt_key"]:"" );
  467.                             //p["crypt"] =    solution["partitions",pindex,"crypt"]:"twofish256";
  468.                         }
  469.                         
  470.                         if( p["fsid"]:0 != fsid )
  471.                         {
  472.                             p["change_fsid"] = true;
  473.                             p["ori_fsid"] = p["fsid"]:0;
  474.                             p["fsid"] = fsid;
  475.                         }
  476.                         if (solution["partitions",pindex,"lvm_group"]:"" != "")
  477.                         {
  478.                             p["used_fs"]    =  `unknown;
  479.                             p["fsid"]        =  Partitions::fsid_lvm;
  480.                             p["format"]        =  false;
  481.                             p["lvm_group"]    =  solution["partitions",pindex,"lvm_group"]:"";
  482.                             p["mount"]        =  "";
  483.                             p["fstype"]        =  "Linux LVM";
  484.                         } 
  485.                         else if (solution["partitions",pindex,"evms_group"]:"" != "") {
  486.                             p["used_fs"]    =  `unknown;
  487.                             p["fsid"]        =  Partitions::fsid_lvm;
  488.                             p["format"]        =  false;
  489.                             string lvm          = (solution["partitions",pindex,"evms_group"]:true)?("lvm2"):("lvm");
  490.                             p["evms_group"]    =  "evms/"+lvm+"/"+solution["partitions",pindex,"evms_group"]:"";
  491.                             p["mount"]        =  "";
  492.                             p["fstype"]        =  "EVMS";
  493.                         }
  494.                         else if (solution["partitions",pindex,"raid_name"]:"" != "")
  495.                         {               
  496.                             p["used_fs"]    = `unknown;
  497.                             p["fsid"]    = Partitions::fsid_raid;
  498.                             p["format"]    = false;
  499.                             p["raid_name"]    = solution["partitions",pindex,"raid_name"]:"";
  500.                             p["raid_type"]   = solution["partitions",pindex,"raid_type"]:"raid";
  501.                             p["mount"]    = "";
  502.                             p["fstype"]    = "Linux RAID";
  503.                         }
  504.                         
  505.                         disk["partitions",index] = p;
  506.                         y2milestone( "reuse auto partition %1", p );
  507.                     }
  508.                     index = index + 1;
  509.                 });
  510.             }
  511.             else
  512.             {
  513.                 list region = [ e["start"]:0, e["end"]:0-e["start"]:0+1 ];
  514.                 map part = $[];
  515.         
  516.                 if( e["extended"]:false && e["created"]:0 > 0 && size(e["created_primary"]:[]) == 0)
  517.                 {
  518.                     part["create"] = true;
  519.                     part["nr"] = e["created"]:0;
  520.                     part["device"] = Storage::GetDeviceName( dev, part["nr"]:-1 );
  521.                     part["region"] = eval(region);
  522.                     part["type"] = `extended;
  523.                     part["fsid"] = Partitions::fsid_extended_win;
  524.                     part["fstype"] = Partitions::FsIdToString( part["fsid"]:0 );
  525.                     y2milestone( "extended auto partition %1", part );
  526.                     partitions = add( partitions, eval(part));
  527.                 }
  528.                 foreach( list a, e["added"]:[],
  529.                          ``{
  530.                     part = $[];
  531.                     integer pindex = a[0]:0;
  532.                     string mount = solution["partitions",pindex,"mount"]:"";
  533.                     integer fsid = Partitions::fsid_native;
  534.                     part["format"] =  solution["partitions",pindex,"format"]:true;
  535.                     if( mount == "swap" )
  536.                     {
  537.                         fsid = Partitions::fsid_swap;
  538.                     }
  539.                     if( solution["partitions",pindex,"filesystem_id"]:0 != 0 )
  540.                     {
  541.                         fsid = solution["partitions",pindex,"filesystem_id"]:0;
  542.                         if( !haskey( solution["partitions",pindex]:$[], "filesystem" ))
  543.                         {
  544.                             part["format"] = false;
  545.                         }
  546.                         y2milestone( "partition id %1 format %2 part %3", fsid, 
  547.                                      part["format"]:false, 
  548.                                      solution["partitions",pindex]:$[] );
  549.                     }
  550.                     part["create"] = true;
  551.                     part["nr"] = a[1]:0;
  552.                     part["device"] = Storage::GetDeviceName( dev, part["nr"]:0 );
  553.                     region[1] = a[2]:0;
  554.                     part["region"] = eval(region);
  555.                     region[0] = region[0]:0 + region[1]:0;
  556.                     part["type"] = `primary;
  557.                     if( e["extended"]:false )
  558.                     {
  559.                         part["type"] = `logical;
  560.                     }
  561.                     
  562.                     if(contains(e["created_primary"]:[],  a[1]:0 ))
  563.                     {
  564.                         part["type"] = `primary;
  565.                     }
  566.                          
  567.                     part["mount"] = mount;
  568.                     symbol mb = solution["partitions",pindex,"mountby"]:`no_mb;
  569.                     if( mb != `no_mb ) {
  570.                             part["mountby"] = mb;
  571.                     }
  572.                     part["used_fs"] = 
  573.                         solution["partitions",pindex,"filesystem"]:((mount == "swap")?(`swap):(`reiser));
  574.                     value = solution["partitions",pindex,"fstopt"]:"";
  575.                     if( size(value)>0 )
  576.                     {
  577.                         part["fstopt"] = value;
  578.                     }
  579.                     else
  580.                     {
  581.                         part["fstopt"] = FileSystems::DefaultFstabOptions( part );
  582.                     }
  583.                     
  584.                     mapvalue = solution["partitions",pindex,"fs_options"]:$[];
  585.                     if( size(mapvalue)>0 )
  586.                     {
  587.                         part["fs_options"] = mapvalue;
  588.                     }
  589.                     
  590.                     if (solution["partitions",pindex,"loop_fs"]:false
  591.                         || solution["partitions",pindex,"crypt_fs"]:false)
  592.                     {
  593.                         //part["loop_fs"]  =    solution["partitions",pindex,"crypt_fs"]:false;
  594.             part["enc_type"] = solution["partitions",pindex,"enc_type"]:`twofish;
  595.                         Storage::UpdateClassified( part["device"]:"",
  596.                                               solution["partitions",pindex,"crypt_key"]:"" );
  597.                         //part["crypt"] =    solution["partitions",pindex,"crypt"]:"twofish256";
  598.                     }
  599.                     
  600.                     value = solution["partitions",pindex,"label"]:"";
  601.                     if( size(value)>0 )
  602.                     {
  603.                         part["label"] = value;
  604.                     }
  605.                     part["fsid"] = fsid;
  606.                     part["fstype"] = Partitions::FsIdToString( fsid );
  607.                     if (solution["partitions",pindex,"lvm_group"]:"" != "")
  608.                     {
  609.                         part["used_fs"]    =  `unknown;
  610.                         part["fsid"]        =  Partitions::fsid_lvm;
  611.                         part["format"]        =  false;
  612.                         part["lvm_group"]    =  solution["partitions",pindex,"lvm_group"]:"";
  613.                         part["mount"]        =  "";
  614.                         part["fstype"]        =  "Linux LVM";
  615.                     }
  616.                     else if (solution["partitions",pindex,"evms_group"]:"" != "") {
  617.                         part["used_fs"]    =  `unknown;
  618.                         part["fsid"]        =  Partitions::fsid_lvm;
  619.                         part["format"]        =  false;
  620.                         part["evms_group"]    =  solution["partitions",pindex,"evms_group"]:"";
  621.                         part["mount"]        =  "";
  622.                         part["fstype"]        =  "EVMS";
  623.                     }
  624.                     else if (solution["partitions",pindex,"raid_name"]:"" != "")
  625.                     {               
  626.                         part["used_fs"]    = `unknown;
  627.                         part["fsid"]    = Partitions::fsid_raid;
  628.                         part["format"]    = false;
  629.                         part["raid_name"]    = solution["partitions",pindex,"raid_name"]:"";
  630.                         part["raid_type"]   = solution["partitions",pindex,"raid_type"]:"raid";
  631.                         part["mount"]    = "";
  632.                         part["fstype"]    = "Linux RAID";
  633.                     }
  634.                     
  635.                     y2milestone( "auto partition %1", part );
  636.                     partitions = add( partitions, eval(part));
  637.  
  638.                     if (a[1]:0 + 1 == e["created"]:0 &&  e["extended"]:false )
  639.                     {
  640.                         part = $[];
  641.                         list ext_region = [ region[0]:0, e["end"]:0-region[0]:0+1 ];
  642.                         part["create"] = true;
  643.                         part["nr"] = e["created"]:0;
  644.                         part["device"] = Storage::GetDeviceName( dev, part["nr"]:-1 );
  645.                         part["region"] = ext_region;
  646.                         part["type"] = `extended;
  647.                         part["fsid"] = Partitions::fsid_extended_win;
  648.                         part["fstype"] = Partitions::FsIdToString( part["fsid"]:0 );
  649.                         y2milestone( "extended auto partition %1", part );
  650.                         partitions = add( partitions, eval(part));                    
  651.                     }
  652.                 });
  653.                 partitions = sort( map a, map b, partitions, ``(a["nr"]:0<b["nr"]:0));
  654.             }
  655.         });
  656.         disk["partitions"] = union( disk["partitions"]:[], partitions );
  657.         y2milestone( "disk %1", disk );
  658.         return( disk );
  659.     }
  660.  
  661.     define map find_matching_partition_size(map gap, integer nr)
  662.         {
  663.             list mg = filter(map g, gap["gap"]:[], ``(g["nr"]:-1 == nr && g["reuse"]:false));
  664.             y2milestone("usepart partition: %1", mg[0]:$[]);
  665.             return mg[0]:$[];
  666.         }
  667.  
  668.     /**
  669.      * Add Cylinder Information
  670.      */
  671.     define map add_cylinder_info( map conf, map gap )
  672.         ``{
  673.         integer big_cyl = 4 * 1024 * 1024 * 1024; 
  674.         integer cyl_size = gap["cyl_size"]:1;
  675.         /*
  676.           // FIXME: Why is sorting needed here?
  677.         conf["partitions"] = 
  678.             sort( map a, map b, conf["partitions"]:[],
  679.                   ``({
  680.                       if( a["max_cyl"]:big_cyl != b["max_cyl"]:big_cyl )
  681.                           return( a["max_cyl"]:big_cyl < b["max_cyl"]:big_cyl );
  682.                       else
  683.                           return( a["size"]:0 > b["size"]:0 );
  684.                   }));
  685.         */
  686.         y2milestone( "parts %1", conf["partitions"]:[] );
  687.         integer sum = 0;
  688.         conf["partitions"] = maplist( map p, conf["partitions"]:[],
  689.                                       ``{
  690.                                           sum = sum + p["pct"]:0;
  691.                                           p["cylinders"] = (p["size"]:0+cyl_size-1)/cyl_size;
  692.                                           
  693.                                           // p["cylinders"] = (p["size"]:0)/cyl_size;
  694.  
  695.                                           map mg = find_matching_partition_size(gap,p["usepart"]:0);
  696.                                           if (mg != $[])
  697.                                           {
  698.                                               p["cylinders"] = mg["cylinders"]:0;
  699.                                               p["size"] = mg["size"]:0;
  700.                                               if (p["usepart"]:0< gap["max_primary"]:0)
  701.                                               {
  702.                                                   p["partition_type"] = "primary";                          
  703.                                               }
  704.                                           }
  705.                                           
  706.                                           if( p["cylinders"]:0 == 0 )
  707.                                           {
  708.                                               p["cylinders"] = 1;
  709.                                           }
  710.                                           return( p );
  711.                                       });
  712.         y2milestone( "sum %1", sum );
  713.         y2milestone( "parts %1", conf["partitions"]:[] );
  714.         if( sum>100 )
  715.         {
  716.             integer rest = sum - 100;
  717.             conf["partitions"] = maplist( map p, conf["partitions"]:[],
  718.                                           ``{
  719.                                               if( haskey( p, "pct" ) )
  720.                                               {
  721.                                                   integer pct = p["pct"]:0;
  722.                                                   integer diff = ((rest * pct) + sum/2) / sum;
  723.                                                   sum = sum - pct;
  724.                                                   rest = rest - diff;
  725.                                                   p["pct"] = pct - diff;
  726.                                               }
  727.                                               return( p );
  728.                                           });
  729.         }    
  730.         conf["partitions"] = maplist( map p, conf["partitions"]:[],
  731.                                       ``{
  732.                                           if( haskey( p, "pct" ) )
  733.                                           {
  734.                                               integer cyl = gap["sum"]:0 / 100 * p["pct"]:0;
  735.                                               cyl = (cyl+cyl_size/2) / cyl_size;
  736.                                               if( cyl == 0 )
  737.                                               {
  738.                                                   cyl = 1;
  739.                                               }
  740.                                               p["want_cyl"] = cyl;
  741.                                           }
  742.                                           if( p["max"]:0 > 0 )
  743.                                           {
  744.                                               integer cyl = (p["max"]:0+cyl_size-1) / cyl_size;
  745.                                               p["size_max_cyl"] = cyl;
  746.                                               if( p["want_cyl"]:0 > cyl )
  747.                                               {
  748.                                                   p["want_cyl"] = cyl;
  749.                                               }
  750.                                           }                      
  751.                                           return( p );
  752.                                       });
  753.         y2milestone( "parts %1", conf["partitions"]:[] );
  754.         return( conf );
  755.     }
  756.  
  757.     
  758.     /**
  759.      * Compute perfect partition list
  760.      * @param ps Partition List from control file
  761.      * @param g Calculated Gaps
  762.      * @return map Best partition list using the gaps
  763.      */
  764.     define map get_perfect_list( list ps, map g ) {
  765.         y2milestone( "requested partitions  %1", ps );
  766.         y2milestone( "calculated gaps %1", g );
  767.  
  768.         /**
  769.           * If gaps are available
  770.           * AND (
  771.           * extended partitions are possible and there are
  772.           * primaries left and number of requested partitions(+1) is less than all available
  773.           * primaries and logical slots
  774.           * OR
  775.           * extended is not possible and number of requested partitions is less than all
  776.           * available primaries and logical slots )
  777.           */
  778.         if( size(g["gap"]:[])>0 &&
  779.             ((g["extended_possible"]:false && 
  780. //            size(g["free_pnr"]:[])>0 &&             // reusing all 4 primaries will fail with this
  781.               size(ps)+1 <= size(g["ext_pnr"]:[])+size(g["free_pnr"]:[])) ||
  782.              (!g["extended_possible"]:false &&
  783.               size(ps) <= size(g["ext_pnr"]:[])+size(g["free_pnr"]:[]))) )
  784.         {
  785.             map lg = (map) eval(g);
  786.  
  787.             // prepare local gap var
  788.             lg["gap"] = maplist( map e, lg["gap"]:[], 
  789.                                  ``{ 
  790.                                      e["orig_cyl"] = e["cylinders"]:0;
  791.                                      e["added"] = [];
  792.                                      return( e );
  793.                                  });
  794.             lg["procpart"] = 0;
  795.             
  796.             list lp = (list) eval(ps);
  797.             
  798.             if( g["extended_possible"]:false &&
  799.                 size(ps)+1>=size(g["free_pnr"]:[]) &&
  800.                 size(filter(map up, (list<map>)ps, ``(
  801.                             up["partition_type"]:"none" == "primary" || 
  802.                             contains(lg["free_pnr"]:[], up["partition_nr"]:0) )))  == 0 
  803.                 )
  804.             {
  805.                 y2milestone( "creating extended" );
  806.                 integer index = 0;
  807.                 foreach( map e, lg["gap"]:[], 
  808.                          ``{
  809.                     if( !e["exists"]:false )
  810.                     {
  811.                         map gap = (map) eval(lg);
  812.                         gap["gap",index,"created"] = gap["free_pnr",0]:1;
  813.                         gap["free_pnr"] = remove( gap["free_pnr"]:[1], 0 );
  814.                         gap["gap",index,"extended"] = true;
  815.                         add_part_recursive( ps, gap );
  816.                     }
  817.                     index = index+1;
  818.                 });
  819.             }
  820.             else
  821.             {
  822.                 y2milestone( "not creating extended now" );        
  823.                 add_part_recursive( ps, lg );
  824.             }
  825.         }
  826.         map ret = $[];
  827.         if( size(cur_gap)>0 )
  828.         {
  829.             ret["weight"] = cur_weight;
  830.             ret["solution"] = eval(cur_gap);
  831.             ret["partitions"] = eval(ps);
  832.         }
  833.         y2milestone( "ret weight %1", ret["weight"]:-1000000 );
  834.         y2milestone( "ret solution %1", ret["solution","gap"]:[] );
  835.         return( ret );
  836.     }
  837.  
  838.  
  839.     
  840.     /**
  841.      * Recursive Adding of partitions
  842.      * @param ps Partition list from control file
  843.      * @param g Calculated gaps
  844.      * @return void
  845.      */
  846.     define void add_part_recursive( list ps, map g )
  847.         ``{
  848.         y2milestone( "partition index %1", g["procpart"]:0 );
  849.         y2milestone( "partitions %1", ps );
  850.         y2milestone( "gap %1", g );
  851.  
  852.     // creation_needed indicates the case, that we do not
  853.     // create a single partition but are reusing some
  854.     boolean creation_needed = false;
  855.     foreach( map p, (list<map>)ps, ``{
  856.         if( p["create"]:true == true ) {
  857.             creation_needed = true;
  858.         }
  859.     });
  860.     y2milestone("creation is needed? %1",creation_needed);
  861.  
  862.  
  863.         map lg = (map) eval(g);
  864.         integer gindex = 0;
  865.         integer pindex = lg["procpart"]:0;
  866.         map part = ps[pindex]:$[];
  867.         lg["procpart"] = pindex + 1;
  868.         y2milestone( "working on partition %1", part );
  869.         foreach( map e, lg["gap"]:[], 
  870.                  ``{
  871.             y2milestone( "start: gap section  %1", e );
  872.             
  873.             if( part["max_cyl"]:0 <= e["end"]:0 &&    
  874.                 part["cylinders"]:0 <= e["cylinders"]:0 &&
  875.                 (!e["extended"]:false && (size(lg["free_pnr"]:[])>0 || ! creation_needed ) ||
  876.                  e["extended"]:false && size(lg["ext_pnr"]:[])>0)
  877.                 )
  878.             {
  879.                 map llg = (map) eval(lg);
  880.  
  881.                 list addl = [ pindex ];
  882.                 
  883.                 // number of needed primaries by user
  884.                 integer sp = size(filter(map up, (list<map>)ps,
  885.                                          ``(up["partition_type"]:"none"  == "primary" ||
  886.                                              contains(llg["free_pnr"]:[], up["partition_nr"]:0))));
  887.  
  888.                 y2milestone("number of primaries requested: %1", sp );
  889.                 integer cp = 0;
  890.                 foreach(map gg, llg["gap"]:[], ``{
  891.                     cp = cp + size(gg["created_primary"]:[]);
  892.                 });
  893.  
  894.                 boolean ex = false;
  895.                 y2milestone("number of created primaries: %1", cp );
  896.         
  897.                 // Extended
  898.                 if( llg["extended_possible"]:false &&
  899.                     !e["extended"]:false &&
  900.                     size(ps)+1>=size(llg["free_pnr"]:[]) && // maybe not needed
  901.                     cp == sp  &&   sp  > 0    )
  902.                 {
  903.                     y2milestone( "creating extended" );
  904.                                       
  905.                     map gap = (map) eval(lg);
  906.                     llg["gap",gindex,"created"] = llg["free_pnr",0]:1;
  907.                     llg["free_pnr"] = remove( llg["free_pnr"]:[1], 0 );
  908.                     llg["gap",gindex,"extended"] = true;
  909.                     // reset
  910.                     llg["procpart"] = pindex ;
  911.                     ex = true;
  912.                 
  913.                 }
  914.                 // Logical
  915.                 else if( e["extended"]:false ) // ||
  916.                     /*
  917.                          ( ps[pindex,"partition_type"]:"none" != "primary" &&
  918.                            ps[pindex,"partition_type"]:"none" != "extended")
  919.                          )
  920.                          */
  921.                 {
  922.                     if (!e["reuse"]:false)
  923.                     {    
  924.                         addl = add( addl, llg["ext_pnr",0]:5 );
  925.                         llg["ext_pnr"] = remove( llg["ext_pnr"]:[0], 0 );
  926.                     } else {
  927.                         addl = add( addl, e["nr"]:0 );
  928.                     }
  929.                 }
  930.                 // Primary
  931.                 else
  932.                 {
  933.                     if (e["exists"]:false)
  934.                     {
  935.                         addl = add( addl, e["nr"]:0 );
  936.                         llg["gap",gindex,"created_primary"] = add(llg["gap",gindex,"created_primary"]:[],
  937.                                                                   e["nr"]:0 );
  938.                     } else {
  939.                         addl = add( addl, llg["free_pnr",0]:1 );
  940.                         llg["gap",gindex,"created_primary"] = add(llg["gap",gindex,"created_primary"]:[],
  941.                                                                   llg["free_pnr",0]:1 );
  942.                         llg["free_pnr"] = remove( llg["free_pnr"]:[0], 0 );
  943.                     }
  944.  
  945.                 }
  946.                 
  947.                 if (!ex)
  948.                 {
  949.                     llg["gap",gindex,"added"] = 
  950.                         add( llg["gap",gindex,"added"]:[], addl );
  951.                 }
  952.  
  953.                 if (!ex) {
  954.                     if( e["exists"]:false )
  955.                     {
  956.                         llg["gap",gindex,"cylinders"] = 0;
  957.                     }
  958.                     else
  959.                     {
  960.                         llg["gap",gindex,"cylinders"] = 
  961.                             llg["gap",gindex,"cylinders"]:0 - part["cylinders"]:0;
  962.                     }
  963.                 }
  964.                 
  965.                 if( pindex+1 < size(ps) || ex )
  966.                 {
  967.                     add_part_recursive( ps, llg );
  968.                 }
  969.                 else
  970.                 {
  971.                     map ng = normalize_gaps(ps, llg);
  972.                     integer val = do_weighting( ps, ng );
  973.                     y2milestone( "val %1 cur_weight %2 size %3", val, cur_weight, size(cur_gap));
  974.                     if( val > cur_weight || size(cur_gap)==0 )
  975.                     {
  976.                         cur_weight = val;
  977.                         cur_gap = (map)eval(ng);
  978.                     }
  979.                 }
  980.             }
  981.             gindex = gindex+1;
  982.         });
  983.         
  984.     };
  985.  
  986.  
  987.  
  988.     /**
  989.      * Normalize Gaps
  990.      */
  991.     define map normalize_gaps( list ps, map g )
  992.         ``{
  993.         y2milestone( "normalize_gaps: gap %1", g );
  994.         integer gindex = 0;
  995.         integer pindex = 0;
  996.         foreach( map e, g["gap"]:[],
  997.                  ``{
  998.             y2milestone( "gap section %1", e );
  999.             if( e["exists"]:false )
  1000.             {
  1001.                 if( size(e["added"]:[])>0 && size(e["added",0]:[])==2 )
  1002.                 {
  1003.                     e["added",0] = add( e["added",0]:[], e["orig_cyl"]:1 );
  1004.                 }
  1005.             }
  1006.             else
  1007.             {
  1008.                 integer rest = e["cylinders"]:0;
  1009.                 integer needed = 0;
  1010.                 integer tidx = 0;
  1011.                 foreach( list p, e["added"]:[],
  1012.                          ``{
  1013.                     tidx = p[0]:0;
  1014.                     if( ps[tidx,"want_cyl"]:0 > ps[tidx,"cylinders"]:0 )
  1015.                     {
  1016.                         needed = needed + ps[tidx,"want_cyl"]:0 -
  1017.                             ps[tidx,"cylinders"]:0;
  1018.                     }
  1019.                 });
  1020.                 y2milestone( "needed %1 rest %2", needed, rest );
  1021.                 if( needed > rest )
  1022.                 {
  1023.                     list tr = [];
  1024.                     list weight = 
  1025.                         maplist( list l, e["added"]:[], 
  1026.                                  ``({
  1027.                                      integer idx = l[0]:0;
  1028.                                      integer d = ps[idx,"want_cyl"]:0 - 
  1029.                                          ps[idx,"cylinders"]:0;
  1030.                                      if( d>0 )
  1031.                                      {
  1032.                                          l = add( l, ps[idx,"cylinders"]:0 );
  1033.                                      }
  1034.                                      tr = add( tr, l );
  1035.                                      return( d>0 ? d : 0 );
  1036.                                  }));
  1037.                     y2milestone( "tr %1", tr );
  1038.                     map r = $[];
  1039.                     r = distribute_space( rest, weight, tr, ps );
  1040.                     g["gap",gindex,"added"] = eval(r["added"]:[]);
  1041.                     g["gap",gindex,"cylinders"] = e["cylinders"]:0 - r["diff"]:0;
  1042.                     y2milestone( "partly satisfy %1 cyl %2", g["gap",gindex,"added"]:[],
  1043.                                  g["gap",gindex,"cylinders"]:0 );
  1044.                 }
  1045.                 else
  1046.                 {
  1047.                     g["gap",gindex,"cylinders"] = e["cylinders"]:0 - needed;
  1048.                 }
  1049.  
  1050.                 pindex = 0;
  1051.                 foreach( list p, g["gap",gindex,"added"]:[], 
  1052.                          ``{
  1053.                     if( size(p)<3 )
  1054.                     {
  1055.                         tidx = p[0]:0;
  1056.                         if( ps[tidx,"want_cyl"]:0 > ps[tidx,"cylinders"]:0 )
  1057.                         {
  1058.                             p = add( p, ps[tidx,"want_cyl"]:0 );
  1059.                         }
  1060.                         else
  1061.                         {
  1062.                             p = add( p, ps[tidx,"cylinders"]:0 );
  1063.                         }
  1064.                         g["gap",gindex,"added",pindex] = p;
  1065.                         y2milestone( "satisfy p %1 cyl %2", p, e["cylinders"]:0 );
  1066.                     }
  1067.                     pindex = pindex+1;
  1068.                 });
  1069.                 y2milestone( "added %1", g["gap",gindex,"added"]:[] );
  1070.             }
  1071.             gindex = gindex + 1;
  1072.         });
  1073.         gindex = 0;
  1074.         foreach( map e, g["gap"]:[],
  1075.                  ``{
  1076.             if( !e["exists"]:false && e["cylinders"]:0>0 )
  1077.             {
  1078.                 list<integer> weight = maplist( list l, e["added"]:[], 
  1079.                                                 ``(ps[l[0]:0,"size"]:0==0 ? 1 : 0) );
  1080.                 if( find( integer l, weight, ``(l>0) ) != nil ) 
  1081.                 {
  1082.                     map r = $[];
  1083.                     r = distribute_space( e["cylinders"]:0, weight, e["added"]:[], 
  1084.                                           ps );
  1085.                     g["gap",gindex,"added"] = eval(r["added"]:[]);
  1086.                     g["gap",gindex,"cylinders"] = e["cylinders"]:0 - r["diff"]:0;
  1087.                     y2milestone( "increase max p %1 cyl %2", g["gap",gindex,"added"]:[], 
  1088.                                  g["gap",gindex,"cylinders"]:0 );
  1089.                 }
  1090.             }
  1091.             gindex = gindex + 1;
  1092.         });
  1093.         gindex = 0;
  1094.         foreach( map e, g["gap"]:[],
  1095.                  ``{
  1096.             if( !e["exists"]:false && e["cylinders"]:0>0 && 
  1097.                 e["cylinders"]:0 < g["disk_cyl"]:0/20 )
  1098.             {
  1099.                 list weight = maplist( list l, e["added"]:[], ``(l[2]:0) );
  1100.                 map r = $[];
  1101.                 r = distribute_space( e["cylinders"]:0, weight, e["added"]:[], ps );
  1102.                 g["gap",gindex,"added"] = eval(r["added"]:[]);
  1103.                 g["gap",gindex,"cylinders"] = e["cylinders"]:0 - r["diff"]:0;
  1104.                 y2milestone( "close small gap p %1 cyl %2", g["gap",gindex,"added"]:[], 
  1105.                              g["gap",gindex,"cylinders"]:0 );
  1106.             }
  1107.             gindex = gindex + 1;
  1108.         });
  1109.         y2milestone( "gap %1", g );
  1110.         return( g );
  1111.     };
  1112.  
  1113.  
  1114.     /**
  1115.      * Distribute Spaces
  1116.      */
  1117.     define map distribute_space( integer rest, list weights, list added, list ps )
  1118.         ``{
  1119.         integer diff_sum = 0;
  1120.         integer sum = 0;
  1121.         integer index = 0;
  1122.         integer pindex = 0;
  1123.         y2milestone( "rest %1 weights %2 added %3", rest, weights, added );
  1124.         foreach( list p, (list<list>)added,
  1125.                  ``{
  1126.             pindex = p[0]:0;
  1127.             if( ps[pindex,"size_max_cyl"]:0==0 || ps[pindex,"grow"]:false ||
  1128.                 ps[pindex,"size_max_cyl"]:0 > p[2]:0 )
  1129.             {
  1130.                 sum = sum + weights[index]:0;
  1131.             }
  1132.             index = index+1;
  1133.         });
  1134.         index = 0;
  1135.         y2milestone( "sum %1 rest %2 added %3", sum, rest, added );
  1136.         foreach( list p, (list<list>)added,
  1137.                  ``{
  1138.             pindex = p[0]:0;
  1139.             if( size(p)==3 && sum>0 &&
  1140.                 (ps[pindex,"size_max_cyl"]:0==0 || ps[pindex,"grow"]:false ||
  1141.                  ps[pindex,"size_max_cyl"]:0 > p[2]:0) )
  1142.             {
  1143.                 integer diff = ((rest*weights[index]:0) + sum/2) / sum;
  1144.                 if( ps[pindex,"size_max_cyl"]:0>0 && 
  1145.                     !ps[pindex,"grow"]:false &&
  1146.                     diff > ps[pindex,"size_max_cyl"]:0-p[2]:0 )
  1147.                 {
  1148.                     diff = ps[pindex,"size_max_cyl"]:0-p[2]:0;
  1149.                 }
  1150.                 sum = sum - weights[index]:0;
  1151.                 rest = rest - diff;
  1152.                 added[index,2] = added[index,2]:0 + diff;
  1153.                 diff_sum = diff_sum + diff;
  1154.                 y2milestone( "sum %1 rest %2 diff %3 added %4", sum, rest, diff, 
  1155.                              added[index]:[] );
  1156.             }
  1157.             index = index+1;
  1158.         });
  1159.         map ret = $[ "added":added, "diff" : diff_sum ];
  1160.         y2milestone( "ret (distribute_space) %1", ret );
  1161.         return( ret );
  1162.     }
  1163.  
  1164.  
  1165.     /**
  1166.      * Calculate plan weights
  1167.      */
  1168.     define integer do_weighting( list ps, map g )
  1169.         ``{
  1170.         y2milestone( "gap %1", g["gap"]:[] );
  1171.         integer ret = 0;
  1172.         integer index = 0;
  1173.         if( cur_mode == `free )
  1174.         {
  1175.             ret = 0;
  1176.         }
  1177.         if( cur_mode == `reuse )
  1178.         {
  1179.             ret = ret - 100;
  1180.         }
  1181.         else if( cur_mode == `resize )
  1182.         {
  1183.             ret = ret - 1000;
  1184.         }
  1185.         else if( cur_mode == `desparate )
  1186.         {
  1187.             ret = ret - 1000000;
  1188.         }
  1189.         y2milestone( "weight after mode ret %1", ret );
  1190.         foreach( map e, g["gap"]:[],
  1191.                  ``{
  1192.             y2milestone( "added %1", e["added"]:[] );
  1193.             if( !e["exists"]:false && e["cylinders"]:0 > 0 )
  1194.             {
  1195.                 ret = ret - 5;
  1196.                 if( e["cylinders"]:0 < g["disk_cyl"]:0/20 )
  1197.                 {
  1198.                     ret = ret - 10;
  1199.                 }
  1200.                 y2milestone("weight (cyl) %1", ret );
  1201.             }
  1202.             y2milestone( "weight after gaps %1", ret );
  1203.             foreach( list p, e["added"]:[], 
  1204.                      ``{
  1205.                 index = p[0]:0;
  1206.                 if( e["exists"]:false && ps[index,"mount"]:""=="swap" && 
  1207.                     e["swap"]:false )
  1208.                 {
  1209.                     ret = ret + 100;
  1210.                     y2milestone( "weight after swap reuse %1", ret );
  1211.                 }
  1212.                 if( ps[index,"want_cyl"]:0>0 )
  1213.                 {
  1214.                     integer diff = ps[index,"want_cyl"]:0 - p[2]:0;
  1215.                     integer normdiff = diff * 100 / p[2]:0;
  1216.                     if( diff < 0 )
  1217.                     {
  1218.                         normdiff = -normdiff;
  1219.                     }
  1220.                     else if( diff > 0 )
  1221.                     {
  1222.                         normdiff = normdiff / 10;
  1223.                     }
  1224.                     ret = ret - normdiff;
  1225.                     ret = ret + ps[index,"want_cyl"]:0*g["cyl_size"]:1 / 
  1226.                         (100 * 1024 * 1024);
  1227.                     y2milestone( "after pct parts %1", ret );
  1228.                 }
  1229.                 if( ps[index,"size"]:0==0 )
  1230.                 {
  1231.                     ret = ret + p[2]:0 * g["cyl_size"]:1 / (50 * 1024 * 1024);
  1232.                     y2milestone( "after maximizes parts %1", ret );
  1233.                 }
  1234.                 if( ps[index,"size_max_cyl"]:0 > 0 && 
  1235.                     ps[index,"size_max_cyl"]:0 < p[2]:0 )
  1236.                 {
  1237.                     integer diff = p[2]:0 - ps[index,"size_max_cyl"]:0;
  1238.                     integer normdiff = diff * 100 / ps[index,"size_max_cyl"]:0;
  1239.                     ret = ret - normdiff;
  1240.                     y2milestone( "after maximal size %1", ret );
  1241.                 }
  1242.             });
  1243.             /*
  1244.             if( e["cylinders"]:0 > 0 )
  1245.             {
  1246.                 y2milestone("ret (before rounding): %1", ret);
  1247.                 ret = ret - (e["cylinders"]:0 * g["cyl_size"]:1) / (1024*1024*1024);
  1248.                 y2milestone("weight (after rounding): %1", ret);
  1249.             }
  1250.             */
  1251.         });
  1252.         y2milestone( "weight:  %1", ret );
  1253.         return( ret );
  1254.     };
  1255.  
  1256.     /**
  1257.      * Remove partitions
  1258.      * @param disk disk data
  1259.      * @param pm partitioning as in the control file.
  1260.      * @return map the new partition map with removed partitions
  1261.      */
  1262.     define map remove_possible_partitions( map disk , map pm)
  1263.     {
  1264.         boolean remove_special_partitions = pm["remove_special_partitions"]:false;
  1265.         list keep_partition_num = pm["keep_partition_num"]:[];
  1266.         list keep_partition_id = pm["keep_partition_id"]:[];
  1267.         list keep_partition_fsys = pm["keep_partition_fsys"]:[];
  1268.  
  1269.         // Special partitions
  1270.         list nodelpart = [ 0x12, 0xde, 257 ];
  1271.  
  1272.         // Handle <usepart> which is analog to create=false and partition_nr>0
  1273.         foreach(map p, pm["partitions"]:[], ``{
  1274.             if (p["usepart"]:0 != 0 )
  1275.                 keep_partition_num=add(keep_partition_num, p["usepart"]:0 );
  1276.         });
  1277.  
  1278.         map ret = (map)disk;
  1279.         ret["partitions"] = maplist( map p, ret["partitions"]:[],
  1280.                 ``{
  1281.                 integer fsid = p["fsid"]:0;
  1282.                 if( (remove_special_partitions ||
  1283.                         !contains( nodelpart, fsid ) ) &&
  1284.                     p["type"]:`primary != `extended &&
  1285.                     !contains( keep_partition_num, p["nr"]:0 ) &&
  1286.                     !contains( keep_partition_id, fsid ) &&
  1287.                     !contains( keep_partition_fsys, p["used_fs"]:`none ))
  1288.                 {
  1289.                     p["delete"] = true;
  1290.                     if (haskey(p, "raid_name")) {
  1291.                         p["old_raid_name"] = p["raid_name"]:"";
  1292.                         p=remove(p, "raid_name");
  1293.                     }
  1294.                 }
  1295.                 return( p );
  1296.                 });
  1297.         integer max_prim = Partitions::MaxPrimary(disk["label"]:"msdos");
  1298.  
  1299.         // delete extended if no logical remain
  1300.         if( size( filter( map p, ret["partitions"]:[],
  1301.                         ``(p["type"]:`primary == `extended)))>0 &&
  1302.                 size( filter( map p, ret["partitions"]:[],
  1303.                         ``(p["nr"]:0>max_prim && !p["delete"]:false) ))==0 )
  1304.         {
  1305.             ret["partitions"] = maplist( map p, ret["partitions"]:[],
  1306.                     ``{
  1307.                     if( p["type"]:`primary == `extended )
  1308.                     {
  1309.                     p["delete"] = true;
  1310.                     }
  1311.                     return( p );
  1312.                     });
  1313.         }
  1314.         y2milestone("after removal: %1", ret);
  1315.         return( ret );
  1316.     }
  1317.  
  1318.  
  1319.     
  1320. /*
  1321.     define map remove_possible_partitions( map disk, map conf )
  1322.         ``{
  1323.         list nodelpart = [ 0x12, 0xde, 257 ];
  1324.         map ret = (map)eval(disk);
  1325.         ret["partitions"] = maplist( map p, ret["partitions"]:[],
  1326.                                      ``{
  1327.                                          integer fsid = p["fsid"]:0;
  1328.                                          if( (conf["remove_special_partitions"]:false ||
  1329.                                               !contains( nodelpart, fsid ) ) &&
  1330.                                              p["type"]:`primary != `extended &&
  1331.                                              !contains( conf["keep_partition_num"]:[], p["nr"]:0 ) &&
  1332.                                              !contains( conf["keep_partition_id"]:[], fsid ) &&
  1333.                                              !contains( conf["keep_partition_fsys"]:[], p["used_fs"]:`none ))
  1334.                                          {
  1335.                                              p["delete"] = true;
  1336.                                          }
  1337.                                          return( p );
  1338.                                      });
  1339.         integer max_prim = Partitions::MaxPrimary(disk["label"]:"msdos");
  1340.         if( size( filter( map p, ret["partitions"]:[], 
  1341.                           ``(p["type"]:`primary == `extended)))>0 &&
  1342.             size( filter( map p, ret["partitions"]:[], 
  1343.                           ``(p["nr"]:0>max_prim && !p["delete"]:false) ))==0 )
  1344.         {
  1345.             ret["partitions"] = maplist( map p, ret["partitions"]:[],
  1346.                                          ``{
  1347.                                              if( p["type"]:`primary == `extended )
  1348.                                              {
  1349.                                                  p["delete"] = true;
  1350.                                              }
  1351.                                              return( p );
  1352.                                          });
  1353.         }
  1354.         return( ret );
  1355.     };
  1356. */
  1357.  
  1358.  
  1359.     /**
  1360.      * Try resizing windows partition
  1361.      *
  1362.      */
  1363.     define map try_resize_windows( map disk )
  1364.         ``{
  1365.         integer cyl_size = disk["cyl_size"]:1;
  1366.         map win = $[];
  1367.         map ret = (map)eval(disk);
  1368.  
  1369.         ret["partitions"] = maplist( map p, ret["partitions"]:[], ``{
  1370.             integer fsid = p["fsid"]:0;
  1371.             if( Partitions::IsDosPartition( fsid ) ) 
  1372.             {
  1373.                 integer psize = (p["region",0]:0 + p["region",1]:1 - 1) * cyl_size;
  1374.                 win = Storage::GetFreeSpace( p["device"]:"", psize, `fat32,
  1375.                                                  false );
  1376.                 y2milestone( "win=%1", win );
  1377.                 if( win != nil && psize > 300*1024*1024 )
  1378.                 {
  1379.                     p["winfo"] = win;
  1380.                     p["region",1] = (win["new_size"]:0 + cyl_size - 1) / cyl_size;
  1381.                     y2milestone( "win part %1", p );
  1382.                 }
  1383.             }
  1384.             return( p );
  1385.         });
  1386.         return( ret );
  1387.     };
  1388.  
  1389.  
  1390.     /**
  1391.      * Collect gap information
  1392.      *
  1393.      */
  1394.     define list<map> get_gaps( integer start, integer end,
  1395.                                map pd,
  1396.                                list<map> part, 
  1397.                                boolean add_exist_linux )
  1398.         ``{
  1399.         y2milestone("partitions: %1", pd["partitions"]:[] );
  1400.         list<integer> usepart_p =  maplist(map pa, pd["partitions"]:[],
  1401.                                                         ``{
  1402.                                                             return pa["usepart"]:0;
  1403.                                                         });
  1404.         list<integer> reuse = filter(integer i, usepart_p, ``(i!=0));
  1405.         
  1406.         y2milestone("reuse: %1", reuse);
  1407.         
  1408.         y2milestone( "start %1 end %2 add_exist %3", start, end, add_exist_linux );
  1409.         list<map> ret = [];
  1410.         map entry = $[];
  1411.         foreach( map p, part, 
  1412.                  ``{                
  1413.             integer s = p["region",0]:0;
  1414.             integer e = s + p["region",1]:1 - 1;
  1415.             entry = $[];
  1416.             y2milestone("Getting gap from part: %1", p );
  1417.             y2milestone("start %1 s %2 e %3", start, s, e );
  1418.             if( start < s )
  1419.             {
  1420.                 entry["start"] = start;
  1421.                 entry["end"] = s-1;
  1422.                 ret = add( ret, eval(entry) );
  1423.             }
  1424.             if( add_exist_linux && 
  1425.                 (p["fsid"]:0==Partitions::fsid_native || 
  1426.                  p["fsid"]:0==Partitions::fsid_swap) )
  1427.             {
  1428.                 entry["swap"] = p["fsid"]:0==Partitions::fsid_swap;
  1429.                 entry["start"] = s;
  1430.                 entry["end"] = e;
  1431.                 entry["exists"] = true;
  1432.                 entry["nr"] = p["nr"]:0;
  1433.                 ret = add( ret, entry );        
  1434.             }
  1435.             
  1436.             if (contains(reuse,  p["nr"]:0))
  1437.             {
  1438.                 // This partition is to be used as specified in the control file
  1439.                 entry["swap"] = p["fsid"]:0==Partitions::fsid_swap;
  1440.                 entry["start"] = s;
  1441.                 entry["end"] = e;
  1442.                 entry["exists"] = true;
  1443.                 entry["reuse"] = true;
  1444.                 entry["nr"] = p["nr"]:0;
  1445.                 ret = add( ret, entry );        
  1446.             }
  1447.             
  1448.             start = e+1;
  1449.         });
  1450.         if( start < end )
  1451.         {
  1452.             entry = $[];
  1453.             entry["start"] = start;
  1454.             entry["end"] = end;
  1455.             ret = add( ret, entry );
  1456.         }
  1457.         y2milestone( "ret %1", ret );
  1458.         return( ret );
  1459.     }
  1460.  
  1461.     
  1462.     /**
  1463.      * Collect gap information
  1464.      * 
  1465.      */
  1466.     define map get_gap_info( map disk, map pd, boolean add_exist_linux )
  1467.         ``{
  1468.         map ret = $[];
  1469.         list<map> gap = [];
  1470.         list<map> plist = filter( map p, disk["partitions"]:[], ``(!p["delete"]:false) );
  1471.         plist = sort( map a, map b, plist, ``(a["region",0]:0<b["region",0]:0) );
  1472.         list exist_pnr = sort( maplist( map e, plist, ``(e["nr"]:0) ));
  1473.         integer max_prim = Partitions::MaxPrimary(disk["label"]:"msdos");
  1474.         boolean has_ext = Partitions::HasExtended( disk["label"]:"msdos" );
  1475.  
  1476.         // check if we support extended partitions
  1477.         if( has_ext )
  1478.         {
  1479.             // see if disk has an extended already
  1480.             map ext = filter( map p, plist,
  1481.                               ``(p["type"]:`primary == `extended))[0]:$[];
  1482.             ret["extended_possible"] = size(ext)==0;
  1483.             if( size(ext)>0 )
  1484.             {
  1485.                 gap = get_gaps( ext["region",0]:0, 
  1486.                                 ext["region",0]:0 + ext["region",1]:1-1,
  1487.                                 pd,
  1488.                                 filter( map p, plist, ``(p["nr"]:0>max_prim)),
  1489.                                 add_exist_linux );
  1490.                 gap = maplist( map e, gap, 
  1491.                                ``{
  1492.                                    e["extended"]=true;
  1493.                                    return e;
  1494.                                });
  1495.                 plist = filter( map p, plist, ``(p["nr"]:0<=max_prim));
  1496.             }
  1497.         }
  1498.         else
  1499.         {
  1500.             ret["extended_possible"] = false;
  1501.         }
  1502.  
  1503.         gap = (list<map>)union( gap, 
  1504.                                 get_gaps( 0, disk["cyl_count"]:1-1, pd, plist, add_exist_linux ));
  1505.         integer av_size = 0;
  1506.         gap = maplist( map e, gap,
  1507.                        ``{
  1508.                            e["cylinders"] = e["end"]:0 - e["start"]:0 + 1;
  1509.                            e["size"] = e["cylinders"]:0 * disk["cyl_size"]:1;
  1510.                            av_size = av_size + e["size"]:0;
  1511.                            return( e );
  1512.                        });
  1513.         gap = maplist( map e, gap,
  1514.                        ``{
  1515.                            e["sizepct"] = (e["size"]:0 * 201 / 2) / av_size;
  1516.                            if( e["sizepct"]:0 == 0 )
  1517.                            {
  1518.                                e["sizepct"] = 1;
  1519.                            }
  1520.                            return( e );
  1521.                        });
  1522.         ret["cyl_size"] = disk["cyl_size"]:1;
  1523.         ret["disk_cyl"] = disk["cyl_count"]:1;
  1524.         ret["max_primary"] = disk["max_primary"]:0;
  1525.         ret["sum"] = av_size;
  1526.         integer max_pnr = max_prim;
  1527.         integer pnr = 1;
  1528.         list free_pnr = [];
  1529.         y2milestone( "exist_pnr %1", exist_pnr );
  1530.         while( pnr<=max_pnr )
  1531.         {
  1532.             if( !contains( exist_pnr, pnr ) )
  1533.             {
  1534.                 free_pnr = add( free_pnr, pnr );
  1535.             }
  1536.             pnr = pnr + 1;
  1537.         }
  1538.         ret["free_pnr"] = free_pnr;
  1539.         list<integer> ext_pnr = [ 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
  1540.                                   25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,
  1541.                                   45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63];
  1542.         integer max_logical = disk["max_logical"]:15;
  1543.         if( max_logical<63 )
  1544.         {
  1545.             ext_pnr = filter( integer i, ext_pnr, ``(i<=max_logical));
  1546.         }
  1547.         if( !ret["extended_possible"]:false )
  1548.         {
  1549.             if( !has_ext )
  1550.             {
  1551.                 ext_pnr = [];
  1552.             }
  1553.             else
  1554.             {
  1555.                 integer maxext = exist_pnr[size(exist_pnr)-1]:4;
  1556.                 pnr = 5;
  1557.                 while( pnr<=maxext )
  1558.                 {
  1559.                     ext_pnr = remove( ext_pnr, 0 );
  1560.                     pnr = pnr+1;
  1561.                 }
  1562.             }
  1563.         }
  1564.         ret["ext_pnr"] = ext_pnr;
  1565.         
  1566.         ret["gap"] = sort(map a, map b, gap, ``(a["start"]:0<b["start"]:0));
  1567.         y2milestone( "ret %1", ret );
  1568.         return( ret );
  1569.     }
  1570.  
  1571. }
  1572.  
  1573.