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 >
Wrap
Text File
|
2006-11-29
|
109KB
|
3,712 lines
/*
*************************************************************
*
* YaST2 SuSE Labs -o)
* -------------------- /\\
* _\_v
* www.suse.de / www.suse.com
* ----------------------------------------------------------
*
* Author: Thomas Fehr <fehr@suse.de>
*
* Description: Make a proposal for partitioning
*
*
*************************************************************
$Id: do_proposal_flexible.ycp 33906 2006-10-30 18:01:58Z fehr $
*/
{
textdomain "storage";
import "FileSystems";
import "Partitions";
import "Storage";
import "ProductFeatures";
include "partitioning/partition_defines.ycp";
map read_partition_config( string fpath );
map read_partition_xml_config();
map get_gap_info( map disk, boolean add_exist_linux );
map add_cylinder_info( map conf, map gap );
map get_perfect_list( list ps, map g );
map process_partition_data( string dev, map solution, string vgname );
map find_matching_disk( list<string> disks, map target, map conf );
map try_resize_windows( map disk );
map remove_possible_partitions( map disk, map conf );
map distribute_space( integer rest, list weights, list added, list ps );
void add_part_recursive( list ps, map g );
map normalize_gaps( list ps, map g );
integer do_weighting( list ps, map g );
symbol cur_mode = `free;
integer cur_weight = -10000;
map cur_gap = $[];
integer big_cyl = 4 * 1024 * 1024 * 1024;
define boolean ignore_disk( string dev, map entry, boolean soft )
``{
boolean ret = !Storage::IsPartitionable( entry ) ||
entry["readonly"]:false || Arch::s390();
if( !ret && Arch::ia64() && entry["label"]:"gpt"!="gpt" )
{
ret = true;
}
if( !ret && soft && Arch::board_iseries () && search( dev, "/dev/sd" )==0 )
{
ret = true;
}
if( !ret && soft && (entry["softraiddisk"]:false||entry["hotpluggable"]:false) )
{
ret = true;
}
if( !ret && soft && contains( Storage::NoProposeDisks(), dev ))
{
ret = true;
}
if( !ret && soft )
ret = entry["used_by_type"]:`UB_NONE != `UB_NONE;
if( ret )
{
y2milestone( "ignoring disk %1 soft %2", dev, soft );
}
return( ret );
};
define string pinfo_name()
``{
return( "/part.info" );
}
define boolean has_flex_proposal()
``{
boolean ret = (integer)SCR::Read( .target.size, pinfo_name() )>0;
return( ret );
}
boolean need_boot( map disk )
{
return( Partitions::NeedBoot() ||
disk["type"]:`CT_UNKNOWN == `CT_DMRAID );
}
define map try_add_boot( map conf, map disk, boolean force )
``{
boolean boot =
size(filter( map e, conf["partitions"]:[],
``(e["mount"]:""==Partitions::BootMount()))) > 0;
boolean root = size(filter( map e, conf["partitions"]:[],
``(e["mount"]:""=="/"))) > 0;
map tc = conf;
y2milestone( "try_add_boot conf %1", conf );
y2milestone( "try_add_boot boot %1 root %2 force %3", boot, root, force );
if( !boot && (root||force) &&
(disk["cyl_count"]:0>Partitions::BootCyl() || need_boot(disk)) )
{
map pb = $[];
pb["mount"] = Partitions::BootMount();
pb["size"] = Partitions::MinimalNeededBootsize();
pb["fsys"] = Partitions::DefaultBootFs();
pb["id"] = Partitions::FsidBoot();
pb["auto_added"] = true;
pb["max_cyl"] = Partitions::BootCyl();
pb["primary"] = Partitions::BootPrimary();
pb["maxsize"] = 500*1024*1024;
tc["partitions"] = add( tc["partitions"]:[], pb );
y2milestone( "try_add_boot disk_cyl %1 boot_cyl %2 need_boot %3 typ %4",
disk["cyl_count"]:0, Partitions::BootCyl(),
Partitions::NeedBoot(), disk["type"]:`CT_UNKNOWN );
y2milestone( "try_add_boot boot added automagically pb %1", pb );
}
return( tc );
}
define map do_flexible_disk( map disk )
``{
string dev = disk["device"]:"";
y2milestone( "do_flexible_disk dev %1", dev );
y2milestone( "do_flexible_disk parts %1", disk["partitions"]:[] );
map ret = $[];
ret["ok"] = false;
map conf = read_partition_config( pinfo_name() );
map solutions = $[];
if( size(conf)>0 && Storage::IsPartitionable( disk ))
{
y2milestone( "do_flexible_disk processing disk %1", dev );
map tc = try_add_boot( conf, disk, false );
cur_mode = `free;
cur_gap = $[];
map gap = get_gap_info( disk, false );
tc = add_cylinder_info( tc, gap );
map sol = get_perfect_list( tc["partitions"]:[], gap );
if( size(sol)>0 )
{
sol["disk"] = eval(disk);
ret["ok"] = true;
ret["disk"] = process_partition_data( dev, sol, "" );
ret["weight"] = sol["weight"]:-1;
}
}
y2milestone( "do_flexible_disk ret %1", ret["ok"]:false );
if( ret["ok"]:false )
{
y2milestone( "do_flexible_disk weight %1", ret["weight"]:-2 );
y2milestone( "do_flexible_disk disk %1", ret["disk"]:$[] );
}
return( ret );
}
define map do_flexible_disk_conf( map disk, map co, boolean ignore_boot,
boolean reuse )
``{
string dev = disk["device"]:"";
y2milestone( "do_flexible_disk_conf dev %1 ignore_boot %2 reuse %3",
dev, ignore_boot, reuse );
map conf = co;
if( !ignore_boot )
conf = try_add_boot( conf, disk, true );
y2milestone( "do_flexible_disk_conf parts %1", disk["partitions"]:[] );
y2milestone( "do_flexible_disk_conf conf %1", conf );
map ret = $[];
ret["ok"] = false;
map solutions = $[];
if( size(conf)>0 && size(conf["partitions"]:[])>0 &&
Storage::IsPartitionable( disk ))
{
y2milestone( "do_flexible_disk_conf processing disk %1", dev );
cur_mode = reuse?`reuse:`free;
cur_gap = $[];
map gap = get_gap_info( disk, reuse );
map tc = add_cylinder_info( conf, gap );
map sol = get_perfect_list( tc["partitions"]:[], gap );
if( size(sol)>0 )
{
sol["disk"] = eval(disk);
ret["ok"] = true;
ret["disk"] = process_partition_data( dev, sol, "" );
ret["weight"] = sol["weight"]:-1;
}
}
else if( Storage::IsPartitionable( disk ) )
{
ret["ok"] = true;
ret["disk"] = disk;
}
y2milestone( "do_flexible_disk_conf ret %1", ret["ok"]:false );
if( ret["ok"]:false && size(conf)>0 )
{
y2milestone( "do_flexible_disk_conf weight %1", ret["weight"]:-2 );
y2milestone( "do_flexible_disk_conf parts %1", ret["disk","partitions"]:[] );
}
return( ret );
}
define map do_vm_disk_conf( map disk, map boot, string vmkey, string key )
``{
string dev = disk["device"]:"";
y2milestone( "do_vm_disk_conf dev %1 vmkey %2 key %3 boot %4",
dev, vmkey, key, boot );
y2milestone( "do_vm_disk_conf parts %1", disk["partitions"]:[] );
map conf = $[ "partitions" : [ $[ "id" : 0x8E ] ] ];
if( size(boot)>0 )
conf["partitions"] = add( conf["partitions"]:[], boot );
map ret = $[];
ret["ok"] = false;
integer fsid = conf["partitions",0,"id"]:0;
if( Storage::IsPartitionable( disk ))
{
y2milestone( "do_vm_disk_conf processing disk %1", dev );
cur_mode = `free;
cur_gap = $[];
map gap = get_gap_info( disk, true );
y2milestone( "do_vm_disk_conf gap %1", gap );
y2milestone( "do_vm_disk_conf conf %1", conf );
map tc = add_cylinder_info( conf, gap );
y2milestone( "do_vm_disk_conf tc %1", tc );
y2milestone( "do_vm_disk_conf gap %1", gap["gap"]:[] );
if( size(gap["gap"]:[])>1 )
{
gap["gap"] = sort( map a, map b, gap["gap"]:[],
``{
if( a["extended"]:false==b["extended"]:false )
return( a["start"]:0<b["start"]:0 );
else
return( !a["extended"]:false );
});
y2milestone( "do_vm_disk_conf gap %1", gap["gap"]:[] );
}
boolean ok = size(boot)==0;
if( !ok )
{
integer gstart = -1;
map bo = find( map p, (list<map>)tc["partitions"]:[],
``(p["mount"]:""==boot["mount"]:"") );
y2milestone( "do_vm_disk_conf boot %1", bo );
integer cyl_num = bo["cylinders"]:1;
y2milestone( "do_vm_disk_conf boot cyl %1", cyl_num );
gap["gap"] = maplist( map g, gap["gap"]:[],
``{
if( !g["exists"]:false && !ok && g["cylinders"]:0>=cyl_num &&
((g["extended"]:false && size(gap["ext_pnr"]:[])>1)||
(!g["extended"]:false && size(gap["free_pnr"]:[])>1)))
{
ok = true;
gstart = g["start"]:-1;
string key = g["extended"]:false ? "ext_pnr" : "free_pnr";
g["added"] = [ [ 1, gap[key,0]:0, cyl_num ] ];
g["cylinders"] = g["cylinders"]:0-cyl_num;
gap[key] = remove( gap[key]:[], 0 );
if( g["cylinders"]:0 > 0 )
{
g["added"] = add( g["added"]:[],
[ 0, gap[key,0]:0, g["cylinders"]:0 ] );
g["cylinders"] = 0;
gap[key] = remove( gap[key]:[], 0 );
}
}
return( g );
});
if( !ok )
{
gap["gap"] = maplist( map g, gap["gap"]:[],
``{
if( !g["exists"]:false && !ok && g["cylinders"]:0>=cyl_num &&
((g["extended"]:false && size(gap["ext_pnr"]:[])>0)||
(!g["extended"]:false && size(gap["free_pnr"]:[])>0)))
{
ok = true;
gstart = g["start"]:-1;
string key = g["extended"]:false ? "ext_pnr" : "free_pnr";
g["added"] = [ [ 1, gap[key,0]:0, cyl_num ] ];
g["cylinders"] = g["cylinders"]:0-cyl_num;
gap[key] = remove( gap[key]:[], 0 );
}
return( g );
});
}
if( ok && size(vmkey)>0 )
{
gap["gap"] = filter( map g, gap["gap"]:[],
``(g["start"]:0==gstart));
}
y2milestone( "do_vm_disk_conf gap %1", gap["gap"]:[] );
}
else if( size(vmkey)>0 )
gap = $[];
map sol = $[];
sol["solution"] = gap;
sol["partitions"] = conf["partitions"]:[];
sol["disk"] = disk;
ret["ok"] = ok;
ret["weight"] = 0;
if( ok && size(vmkey)==0 )
{
if( size(gap["ext_reg"]:[])>0 )
{
integer ext_end = gap["ext_reg",0]:0 + gap["ext_reg",1]:0 - 1;
map aext = find( map g, gap["gap"]:[],
``(size(g["added"]:[])==0 &&
!g["exists"]:false &&
g["start"]:0>=ext_end &&
g["start"]:0-ext_end<=1));
y2milestone( "do_vm_disk_conf ee:%1 ae:%2", ext_end, aext );
if( aext!=nil )
{
gap["resize_ext"] = aext["end"]:0;
gap["gap"] = filter( map g, gap["gap"]:[],
``(g["start"]:0!=aext["start"]:0));
aext = find( map g, gap["gap"]:[],
``(!g["exists"]:false && g["extended"]:false &&
g["end"]:0==ext_end));
y2milestone( "do_vm_disk_conf aext %1", aext );
if( aext != nil )
{
gap["gap"] = maplist( map g, gap["gap"]:[],
``{
if( g["end"]:0==aext["end"]:0 )
{
g["cylinders"] = g["cylinders"]:0 +
gap["resize_ext"]:0 -
g["end"]:0;
g["end"] = gap["resize_ext"]:0;
}
return( g );
});
}
else
{
map a = $[ "extended" : true,
"start" : gap["ext_reg",0]:0+gap["ext_reg",1]:0,
"end" : gap["resize_ext"]:0 ];
a["cylinders"] = a["end"]:0 - a["start"]:0 + 1;
y2milestone("do_vm_disk_conf add gap %1", a );
y2milestone("do_vm_disk_conf add gap %1", gap["gap"]:[] );
gap["gap"] = add( gap["gap"]:[], a );
y2milestone("do_vm_disk_conf add gap %1", gap["gap"]:[] );
}
}
y2milestone( "do_vm_disk_conf aext gap %1", gap );
}
gap["gap"] = maplist( map g, gap["gap"]:[],
``{
if( g["exists"]:false )
{
map acur = find( map gg, gap["gap"]:[],
``(size(gg["added"]:[])==0 &&
!gg["exists"]:false &&
gg["extended"]:false==g["extended"]:false &&
gg["start"]:0>=g["end"]:0 &&
gg["start"]:0-g["end"]:0<=1));
y2milestone( "do_vm_disk_conf ee:%1 ae:%2",
g["end"]:0, acur );
if( acur!=nil )
{
g["resize"] = acur["end"]:0;
g["fsid"] = fsid;
}
}
return( g );
});
list<integer> sl = maplist( map g, gap["gap"]:[],
``(g["resize"]:-1));
y2milestone( "do_vm_disk_conf sl %1", sl );
gap["gap"] = filter( map g, gap["gap"]:[],
``(!contains(sl,g["end"]:0)));
gap["gap"] = sort( map a, map b, gap["gap"]:[],
``{
return( a["cylinders"]:0>b["cylinders"]:0 );
});
y2milestone( "do_vm_disk_conf sorted gap %1", gap["gap"]:[] );
gap["gap"] = maplist( map g, gap["gap"]:[],
``{
if( !g["exists"]:false && g["cylinders"]:0>0 &&
((g["extended"]:false && size(gap["ext_pnr"]:[])>0)||
(!g["extended"]:false && size(gap["free_pnr"]:[])>0)))
{
string key = g["extended"]:false ? "ext_pnr" : "free_pnr";
g["added"] = add( g["added"]:[],
[ 0, gap[key,0]:0, g["cylinders"]:0 ]);
g["cylinders"] = 0;
gap[key] = remove( gap[key]:[], 0 );
}
return( g );
});
gap["gap"] = maplist( map g, gap["gap"]:[],
``{
if( g["exists"]:false && fsid!=0 && g["fsid"]:0!=fsid )
{
g["fsid"] = fsid;
}
return( g );
});
y2milestone( "do_vm_disk_conf end gap %1", gap["gap"]:[] );
sol["solution"] = gap;
}
ret["disk"] = process_partition_data( dev, sol, key );
}
y2milestone( "do_vm_disk_conf ret %1", ret["ok"]:false );
if( ret["ok"]:false )
{
y2milestone( "do_vm_disk_conf weight %1", ret["weight"]:-2 );
y2milestone( "do_vm_disk_conf parts %1", ret["disk","partitions"]:[] );
}
return( ret );
}
define list<string> restrict_disk_names( list<string> disks )
{
list<string> ddev = disks;
list<string> d1 = filter( string s, ddev, ``(search(s,"/dev/hd")==0));
ddev = filter( string s, ddev, ``(search(s,"/dev/hd")!=0));
if( size(d1)>2 )
{
integer count=1;
d1 = maplist( string s, d1,
``{
return( (count<=2)?s:"" );
count=count+1;
});
d1 = filter( string s, d1, ``(size(s)>0));
}
d1 = (list<string>)merge( d1, filter( string s, ddev,
``(search(s,"/dev/sd")==0)));
ddev = filter( string s, ddev, ``(search(s,"/dev/sd")!=0));
ddev = (list<string>)merge( d1, ddev );
if( size(ddev)>4 )
{
integer count=1;
ddev = maplist( string s, ddev,
``{
return( (count<=4)?s:"" );
count=count+1;
});
ddev = filter( string s, ddev, ``(size(s)>0));
}
y2milestone( "restrict_disk_names: ret %1", ddev );
return( ddev );
}
define map do_pflex( map<string,map> target, map conf )
{
map ret = $[];
ret["ok"] = false;
list<map> solutions = [];
cur_mode = `free;
if( size(conf)>0 )
{
list<string> ddev = maplist( string k, map e,
filter( string l, map f, target,
``(!ignore_disk(l,f,false))), ``(k));
ddev = sort( ddev );
y2milestone( "do_pflex ddev %1", ddev );
map tc = $[];
map<integer,any> dtmp = $[];
foreach( map p, conf["partitions"]:[],
``{
integer dprio = p["disk"]:0;
if( haskey( dtmp, dprio ))
{
dtmp[dprio] = add( dtmp[dprio]:[], p );
}
else
{
dtmp[dprio] = [ p ];
}
});
y2milestone( "do_pflex dlist %1", dtmp );
list dlist = maplist( integer k, any e, dtmp, ``(e) );
y2milestone( "do_pflex dlist %1", dlist );
if( size(dlist)>size(ddev) )
{
integer idx = size(ddev);
while( idx<size(dlist) )
{
dlist[size(ddev)-1] = union( dlist[size(ddev)-1]:[],
dlist[idx]:[] );
idx = idx+1;
}
while( size(dlist)>size(ddev) )
{
dlist = remove( dlist, size(ddev) );
}
y2milestone( "do_pflex dlist %1", dlist );
}
list save_dlist = (list) eval(dlist);
repeat
{
integer count = 0;
repeat
{
list<string> td = eval(ddev);
integer idx = 0;
y2milestone( "do_pflex start while count %1", count );
while( idx<size(dlist) && count<size(dlist) )
{
y2milestone( "do_pflex in while idx %1", idx );
tc = (map) eval(conf);
tc["partitions"] = eval( dlist[idx]:[] );
map md = find_matching_disk( td, target, tc );
y2milestone( "do_pflex size(md) %1", size(md) );
if( size(md)>0 )
{
solutions = add( solutions, md );
td = filter( string e, td, ``(e!=md["device"]:""));
y2milestone( "do_pflex new td %1", td );
idx = idx+1;
}
else
{
y2milestone( "do_pflex no solution" );
idx = size(dlist);
td = eval(ddev);
solutions = [];
count = count + 1;
if( size(dlist)>1 )
{
list tfi = dlist[0]:[];
dlist = remove( dlist, 0 );
dlist = add( dlist, tfi );
y2milestone( "do_pflex new rot dlist %1", dlist );
}
}
}
}
until( size(solutions)>0 || count>=size(dlist) );
if( size(solutions)==0 && size(dlist)>1 )
{
dlist = (list) eval(save_dlist);
dlist[size(dlist)-2] = union( dlist[size(dlist)-2]:[],
dlist[size(dlist)-1]:[] );
dlist = remove( dlist, size(dlist)-1 );
y2milestone( "do_pflex new truncated dlist %1",
dlist );
save_dlist = (list)eval(dlist);
}
}
until( size(solutions)>0 || size(dlist)<=1 );
if( size(solutions)==0 &&
(size(conf["keep_partition_fsys"]:[])>0 ||
size(conf["keep_partition_id"]:[])>0 ||
size(conf["keep_partition_num"]:[])>0 ||
!conf["prefer_remove"]:false))
{
y2milestone( "do_pflex desperate mode" );
tc = (map) eval(conf);
cur_mode = `desparate;
tc["keep_partition_fsys"] = [];
tc["keep_partition_id"] = [];
tc["keep_partition_num"] = [];
tc["prefer_remove"] = true;
map md = find_matching_disk( ddev, target, tc );
if( size(md)>0 )
{
solutions = add( solutions, md );
}
}
if( size(solutions)>0 )
{
foreach( map e, solutions,
``{
string disk = e["device"]:"";
target[disk] = process_partition_data( disk, e, "" );
y2milestone( "do_pflex solution disk %1 %2",
disk, target[disk]:$[] );
});
ret["ok"] = true;
target = Storage::SpecialBootHandling( target );
ret["target"] = Storage::DeleteDestroyedLvmVgs( target );
}
}
return( ret );
}
define map do_proposal_flexible( map<string,map> target )
``{
map conf = $[];
if( ProductFeatures::GetBooleanFeature( "partitioning",
"use_flexible_partitioning"))
conf = read_partition_xml_config();
else
conf = read_partition_config( pinfo_name() );
return( do_pflex( target, conf ) );
}
define map find_matching_disk( list<string> disks, map target, map conf )
``{
map<string,map> solutions = $[];
cur_weight = -100000;
cur_gap = $[];
foreach( string k, disks,
``{
map e = target[k]:$[];
y2milestone( "find_matching_disk processing disk %1", k );
y2milestone( "find_matching_disk parts %1", conf["partitions"]:[] );
map tc = try_add_boot( conf, e, false );
if( cur_mode != `desparate )
cur_mode = `free;
if( !tc["prefer_remove"]:false )
{
map gap = get_gap_info( e, false );
tc = add_cylinder_info( tc, gap );
map l = get_perfect_list( tc["partitions"]:[], gap );
if( size(l)>0 )
{
solutions[k] = eval(l);
solutions[k,"disk"] = eval(e);
}
cur_mode = `reuse;
map egap = get_gap_info( e, true );
if( size(egap["gap"]:[]) > size(gap["gap"]:[]) )
{
tc = add_cylinder_info( tc, egap );
l = get_perfect_list( tc["partitions"]:[], egap );
if( size(l)>0 &&
(!haskey(solutions,k) ||
(haskey( l, "weight" ) &&
l["weigth"]:0 > solutions[k,"weigth"]:0 )))
{
y2milestone( "find_matching_disk solution reuse existing" );
solutions[k] = eval(l);
solutions[k,"disk"] = eval(e);
}
}
cur_mode = `resize;
map rw = try_resize_windows( e );
if( find( map p, rw["partitions"]:[], ``(p["resize"]:false))!=nil )
{
egap = get_gap_info( rw, true );
tc = add_cylinder_info( tc, egap );
l = get_perfect_list( tc["partitions"]:[], egap );
if( size(l)>0 &&
(!haskey(solutions,k) ||
(haskey( l, "weight" ) &&
l["weigth"]:0 > solutions[k,"weigth"]:0 )))
{
y2milestone( "find_matching_disk solution resizing windows" );
solutions[k] = eval(l);
solutions[k,"disk"] = eval(rw);
}
}
}
else
{
map rp = remove_possible_partitions( e, tc );
map gap = get_gap_info( rp, false );
tc = add_cylinder_info( tc, gap );
map l = get_perfect_list( tc["partitions"]:[], gap );
if( size(l)>0 )
{
solutions[k] = eval(l);
solutions[k,"disk"] = eval(rp);
}
}
});
map ret = $[];
if( size(solutions)>0 )
{
foreach( string k, map e, solutions,
``{
y2milestone( "find_matching_disk disk %1 weight %2",
k, e["weight"]:0 );
});
list<string> disks = maplist( string k, map e, solutions, ``(k) );
disks = sort( string a, string b, disks,
``(solutions[a,"weight"]:0>solutions[b,"weight"]:0));
y2milestone( "find_matching_disk sorted disks %1", disks );
ret = solutions[disks[0]:""]:$[];
ret["device"] = disks[0]:"";
}
return( ret );
}
define map process_partition_data( string dev, map solution, string vgname )
``{
map disk = solution["disk"]:$[];
list<map> partitions = [];
string value = "";
boolean remove_boot = false;
if( size( filter( map e, solution["partitions"]:[],
``(e["mount"]:""==Partitions::BootMount() &&
e["auto_added"]:false)))>0 )
{
foreach( map e, solution["solution","gap"]:[],
``{
foreach( list a, e["added"]:[],
``{
integer pindex = a[0]:0;
if( solution["partitions",pindex,"mount"]:"" == "/" &&
disk["cyl_count"]:0 > Partitions::BootCyl() &&
e["end"]:0 <= Partitions::BootCyl() && !need_boot(disk) )
{
remove_boot = true;
}
});
});
}
integer index = 0;
if( remove_boot )
{
foreach( map e, solution["solution","gap"]:[],
``{
list nlist = [];
foreach( list a, e["added"]:[],
``{
integer pindex = a[0]:0;
if( solution["partitions",pindex,"mount"]:"" ==
Partitions::BootMount() )
{
integer rest = a[2]:0;
y2milestone( "process_partition_data remove unneeded %3 %1 cyl %2",
e["added"]:[], rest, Partitions::BootMount() );
list<list> nlist = filter( list l, e["added"]:[], ``(l[0]:0!=pindex));
if( size(nlist)>0 && !e["exists"]:false )
{
list weight = maplist( list l, nlist, ``(l[2]:0) );
map r = $[];
r = distribute_space( rest, weight, nlist,
solution["partitions"]:[] );
nlist = eval(r["added"]:[]);
solution["solution","gap",index,"cylinders"] =
e["cylinders"]:0 - r["diff"]:0;
}
solution["solution","gap",index,"added"] = eval(nlist);
}
pindex = pindex+1;
});
index = index + 1;
});
}
if( solution["solution","resize_ext"]:0>0 )
{
disk["partitions"] = maplist( map p, disk["partitions"]:[],
``{
if( p["type"]:`unknown==`extended )
{
p["resize"] = true;
p["ignore_fs"] = true;
p["region",1] = solution["solution","resize_ext"]:0 -
p["region",0]:0 + 1;
p["size_k"] = p["region",1]:0 * disk["cyl_size"]:0 / 1024;
y2milestone( "process_partition_data resize ext %1", p );
}
return( p );
});
}
foreach( map e, solution["solution","gap"]:[],
``{
y2milestone( "process_partition_data e %1", e );
if( e["exists"]:false )
{
integer index = 0;
integer pindex = e["added",0,0]:0;
string mount = solution["partitions",pindex,"mount"]:"";
integer fsid = Partitions::fsid_native;
if( mount == "swap" )
{
fsid = Partitions::fsid_swap;
}
if( solution["partitions",pindex,"id"]:0 != 0 )
{
fsid = solution["partitions",pindex,"id"]:0;
}
foreach( map p, disk["partitions"]:[],
``{
if( p["nr"]:0 == e["added",0,1]:0 )
{
y2milestone( "process_partition_data reuse part %1", p );
p["format"] = true;
p["mount"] = mount;
p["used_fs"] =
solution["partitions",pindex,"fsys"]:Partitions::DefaultFs();
value = solution["partitions",pindex,"fstopt"]:"";
if( size(value)>0 )
{
p["fstopt"] = value;
}
else
{
p["fstopt"] = FileSystems::DefaultFstabOptions( p );
}
p["fs_options"] = FileSystems::DefaultFormatOptions( p );
value = solution["partitions",pindex,"fopt"]:"";
if( size(value)>0 )
{
p["format_opt"] = value;
}
value = solution["partitions",pindex,"label"]:"";
if( size(value)>0 )
{
p["label"] = value;
}
if( p["fsid"]:0 != fsid )
{
p["change_fsid"] = true;
p["ori_fsid"] = p["fsid"]:0;
p["fsid"] = fsid;
}
if( size(mount)==0 && size(vgname)>0 &&
p["type"]:`unknown!=`extended )
p["vg"] = vgname;
disk["partitions",index] = p;
y2milestone( "process_partition_data reuse auto part %1", p );
}
else if( (size(vgname)>0||e["resize"]:0>0) &&
p["nr"]:0 == e["nr"]:0 )
{
if( e["fsid"]:0!=0 && e["fsid"]:0!=p["fsid"]:0 )
{
p["change_fsid"] = true;
p["ori_fsid"] = p["fsid"]:0;
p["fsid"] = e["fsid"]:0;
}
if( e["resize"]:0>0 )
{
p["resize"] = true;
p["ignore_fs"] = true;
p["region",1] = e["resize"]:0 - p["region",0]:0 + 1;
p["size_k"] = p["region",1]:0 *
disk["cyl_size"]:0 / 1024;
}
if( size(vgname)>0 )
p["vg"] = vgname;
disk["partitions",index] = p;
y2milestone( "process_partition_data resize part %1", p );
}
index = index + 1;
});
}
else
{
list region = [ e["start"]:0, e["end"]:0-e["start"]:0+1 ];
map part = $[];
if( e["extended"]:false && e["created"]:0 > 0 )
{
while( e["added",0,1]:(disk["max_primary"]:4+1) <=
disk["max_primary"]:4 )
{
integer pindex = e["added",0,0]:0;
string mount = solution["partitions",pindex,"mount"]:"";
integer fsid = Partitions::fsid_native;
part["format"] = true;
if( mount == "swap" )
{
fsid = Partitions::fsid_swap;
}
part["create"] = true;
part["nr"] = e["created"]:0;
part["device"] = Storage::GetDeviceName( dev, part["nr"]:-1 );
part["region"] = region;
part["region",1] = e["added",0,2]:0;
region[0] = region[0]:0 + part["region",1]:0;
region[1] = region[1]:0 - part["region",1]:0;
part["type"] = `primary;
if( solution["partitions",pindex,"id"]:0 != 0 )
{
fsid = solution["partitions",pindex,"id"]:0;
if( !haskey( solution["partitions",pindex]:$[], "fsys" ))
{
part["format"] = false;
}
}
part["size_k"] = part["region",1]:0 * disk["cyl_size"]:0 / 1024;
part["mount"] = mount;
part["used_fs"] =
solution["partitions",pindex,"fsys"]:Partitions::DefaultFs();
value = solution["partitions",pindex,"fstopt"]:"";
if( size(value)>0 )
{
part["fstopt"] = value;
}
else
{
part["fstopt"] = FileSystems::DefaultFstabOptions( part );
}
part["fs_options"] = FileSystems::DefaultFormatOptions( part );
value = solution["partitions",pindex,"fopt"]:"";
if( size(value)>0 )
{
part["format_opt"] = value;
}
value = solution["partitions",pindex,"label"]:"";
if( size(value)>0 )
{
part["label"] = value;
}
part["fsid"] = fsid;
part["fstype"] = Partitions::FsIdToString( fsid );
if( size(mount)==0 && size(vgname)>0 )
part["vg"] = vgname;
y2milestone( "process_partition_data auto partition %1", part );
partitions = add( partitions, part );
e["created"] = e["added",0,1]:0;
e["added"] = remove( e["added"]:[], 0 );
part = $[];
}
part["create"] = true;
part["nr"] = e["created"]:0;
part["device"] = Storage::GetDeviceName( dev, part["nr"]:-1 );
part["region"] = eval(region);
part["type"] = `extended;
part["fsid"] = Partitions::fsid_extended_win;
part["fstype"] = Partitions::FsIdToString( part["fsid"]:0 );
part["size_k"] = region[1]:0 * disk["cyl_size"]:0 / 1024;
y2milestone( "process_partition_data extended auto partition %1", part );
partitions = add( partitions, eval(part));
}
foreach( list a, e["added"]:[],
``{
part = $[];
integer pindex = a[0]:0;
string mount = solution["partitions",pindex,"mount"]:"";
integer fsid = Partitions::fsid_native;
part["format"] = true;
if( mount == "swap" )
{
fsid = Partitions::fsid_swap;
}
if( solution["partitions",pindex,"id"]:0 != 0 )
{
fsid = solution["partitions",pindex,"id"]:0;
if( !haskey( solution["partitions",pindex]:$[], "fsys" ))
{
part["format"] = false;
}
y2milestone( "process_partition_data partition id %1 format %2 part %3",
fsid, part["format"]:false,
solution["partitions",pindex]:$[] );
}
part["create"] = true;
part["nr"] = a[1]:0;
part["device"] = Storage::GetDeviceName( dev, part["nr"]:0 );
region[1] = a[2]:0;
part["region"] = eval(region);
region[0] = region[0]:0 + region[1]:0;
part["size_k"] = region[1]:0 * disk["cyl_size"]:0 / 1024;
part["type"] = `primary;
if( e["extended"]:false )
{
part["type"] = `logical;
}
part["mount"] = mount;
part["used_fs"] =
solution["partitions",pindex,"fsys"]:Partitions::DefaultFs();
value = solution["partitions",pindex,"fstopt"]:"";
if( size(value)>0 )
{
part["fstopt"] = value;
}
else
{
part["fstopt"] = FileSystems::DefaultFstabOptions( part );
}
part["fs_options"] = FileSystems::DefaultFormatOptions( part );
value = solution["partitions",pindex,"fopt"]:"";
if( size(value)>0 )
{
part["format_opt"] = value;
}
value = solution["partitions",pindex,"label"]:"";
if( size(value)>0 )
{
part["label"] = value;
}
part["fsid"] = fsid;
part["fstype"] = Partitions::FsIdToString( fsid );
if( size(mount)==0 && size(vgname)>0 )
part["vg"] = vgname;
y2milestone( "process_partition_data auto partition %1", part );
partitions = add( partitions, eval(part));
});
partitions = sort( map a, map b, partitions, ``(a["nr"]:0<b["nr"]:0));
}
});
disk["partitions"] = union( disk["partitions"]:[], partitions );
y2milestone( "process_partition_data disk %1", disk );
return( disk );
}
define map add_cylinder_info( map conf, map gap )
``{
integer cyl_size = gap["cyl_size"]:1;
conf["partitions"] =
sort( map a, map b, conf["partitions"]:[],
``({
if( a["primary"]:false != b["primary"]:false )
return( true );
else if( a["max_cyl"]:big_cyl != b["max_cyl"]:big_cyl )
return( a["max_cyl"]:big_cyl < b["max_cyl"]:big_cyl );
else
return( a["size"]:0 < b["size"]:0 );
}));
y2milestone( "add_cylinder_info parts %1", conf["partitions"]:[] );
integer sum = 0;
conf["partitions"] = maplist( map p, conf["partitions"]:[],
``{
sum = sum + p["pct"]:0;
p["cylinders"] = (p["size"]:0+cyl_size-1)/cyl_size;
if( p["cylinders"]:0 == 0 )
{
p["cylinders"] = 1;
}
return( p );
});
y2milestone( "add_cylinder_info sum %1", sum );
y2milestone( "add_cylinder_info parts %1", conf["partitions"]:[] );
if( sum>100 )
{
integer rest = sum - 100;
conf["partitions"] = maplist( map p, conf["partitions"]:[],
``{
if( haskey( p, "pct" ) )
{
integer pct = p["pct"]:0;
integer diff = ((rest * pct) + sum/2) / sum;
sum = sum - pct;
rest = rest - diff;
p["pct"] = pct - diff;
}
return( p );
});
}
conf["partitions"] = maplist( map p, conf["partitions"]:[],
``{
if( haskey( p, "pct" ) )
{
integer cyl = gap["sum"]:0 / 100 * p["pct"]:0;
cyl = (cyl+cyl_size/2) / cyl_size;
if( cyl == 0 )
{
cyl = 1;
}
p["want_cyl"] = cyl;
}
if( p["maxsize"]:0 > 0 )
{
integer cyl = (p["maxsize"]:0+cyl_size-1) / cyl_size;
p["size_max_cyl"] = cyl;
if( p["want_cyl"]:0 > cyl )
{
p["want_cyl"] = cyl;
}
}
return( p );
});
y2milestone( "add_cylinder_info parts %1", conf["partitions"]:[] );
return( conf );
}
define map get_perfect_list( list ps, map g )
``{
y2milestone( "get_perfect_list ps %1", ps );
y2milestone( "get_perfect_list gap %1", g );
if( size(g["gap"]:[])>0 &&
((g["extended_possible"]:false &&
size(g["free_pnr"]:[])>0 &&
size(ps)+1 <= size(g["ext_pnr"]:[])+size(g["free_pnr"]:[])) ||
(!g["extended_possible"]:false &&
size(ps) <= size(g["ext_pnr"]:[])+size(g["free_pnr"]:[]))) )
{
map lg = (map) eval(g);
lg["gap"] = maplist( map e, lg["gap"]:[],
``{
e["orig_cyl"] = e["cylinders"]:0;
e["added"] = [];
return( e );
});
lg["procpart"] = 0;
list lp = (list) eval(ps);
if( g["extended_possible"]:false && size(ps)+1>size(g["free_pnr"]:[]))
{
y2milestone( "get_perfect_list creating extended" );
integer index = 0;
foreach( map e, lg["gap"]:[],
``{
if( !e["exists"]:false )
{
map gap = (map) eval(lg);
gap["gap",index,"created"] = gap["free_pnr",0]:1;
gap["free_pnr"] = remove( gap["free_pnr"]:[1], 0 );
gap["gap",index,"extended"] = true;
add_part_recursive( ps, gap );
}
index = index+1;
});
}
else
{
y2milestone( "get_perfect_list not creating extended" );
add_part_recursive( ps, lg );
}
}
map ret = $[];
if( size(cur_gap)>0 )
{
ret["weight"] = cur_weight;
ret["solution"] = eval(cur_gap);
ret["partitions"] = eval(ps);
}
y2milestone( "get_perfect_list ret weight %1", ret["weight"]:-1000000 );
y2milestone( "get_perfect_list ret solution %1", ret["solution","gap"]:[] );
return( ret );
}
define void add_part_recursive( list ps, map g )
``{
y2milestone( "add_part_recursive pindex %1", g["procpart"]:0 );
y2milestone( "add_part_recursive ps %1", ps );
y2milestone( "add_part_recursive gap %1", g );
map lg = (map) eval(g);
integer gindex = 0;
integer pindex = lg["procpart"]:0;
map part = ps[pindex]:$[];
lg["procpart"] = pindex + 1;
y2milestone( "add_part_recursive p %1", part );
foreach( map e, lg["gap"]:[],
``{
y2milestone( "add_part_recursive e %1", e );
boolean max_cyl_ok = !haskey( part, "max_cyl" ) ||
part["max_cyl"]:0 >= e["end"]:0;
if( !max_cyl_ok )
{
integer cyl = 0;
foreach( list a, lg["gap",gindex,"added"]:[],
``{
cyl = cyl + ps[a[0]:0,"cylinders"]:0;
});
cyl = cyl + part["cylinders"]:0;
y2milestone( "max_cyl_ok cyl %1", cyl );
max_cyl_ok = e["start"]:0 + cyl <= part["max_cyl"]:0;
}
y2milestone( "add_part_recursive max_cyl_ok %1", max_cyl_ok );
if( max_cyl_ok && part["cylinders"]:0 <= e["cylinders"]:0 &&
((!e["extended"]:false && size(lg["free_pnr"]:[])>0) ||
(part["primary"]:false && e["created"]:false && e["extended"]:false && size(lg["free_pnr"]:[])>0) ||
(!part["primary"]:false && e["extended"]:false && size(lg["ext_pnr"]:[])>0)))
{
map llg = (map) eval(lg);
if( e["exists"]:false )
{
llg["gap",gindex,"cylinders"] = 0;
}
else
{
llg["gap",gindex,"cylinders"] =
llg["gap",gindex,"cylinders"]:0 - part["cylinders"]:0;
}
list addl = [ pindex ];
if( e["extended"]:false && !part["primary"]:false )
{
addl = add( addl, llg["ext_pnr",0]:5 );
llg["ext_pnr"] = remove( llg["ext_pnr"]:[0], 0 );
}
else
{
addl = add( addl, llg["free_pnr",0]:1 );
llg["free_pnr"] = remove( llg["free_pnr"]:[0], 0 );
}
llg["gap",gindex,"added"] =
add( llg["gap",gindex,"added"]:[], addl );
if( pindex+1 < size(ps) )
{
add_part_recursive( ps, llg );
}
else
{
map ng = normalize_gaps(ps, llg);
integer val = do_weighting( ps, ng );
y2milestone( "add_part_recursive val %1 cur_weight %2 size %3",
val, cur_weight, size(cur_gap));
if( val > cur_weight || size(cur_gap)==0 )
{
cur_weight = val;
cur_gap = (map)eval(ng);
}
}
}
gindex = gindex+1;
});
};
define map normalize_gaps( list ps, map g )
``{
y2milestone( "normalize_gaps gap %1", g );
integer gindex = 0;
integer pindex = 0;
foreach( map e, g["gap"]:[],
``{
y2milestone( "normalize_gaps e %1", e );
if( e["exists"]:false )
{
if( size(e["added"]:[])>0 && size(e["added",0]:[])==2 )
{
g["gap",gindex,"added",0] =
add( e["added",0]:[], e["orig_cyl"]:1 );
}
}
else
{
integer rest = e["cylinders"]:0;
integer needed = 0;
integer tidx = 0;
foreach( list p, e["added"]:[],
``{
tidx = p[0]:0;
if( ps[tidx,"want_cyl"]:0 > ps[tidx,"cylinders"]:0 )
{
needed = needed + ps[tidx,"want_cyl"]:0 -
ps[tidx,"cylinders"]:0;
}
});
y2milestone( "normalize_gaps needed %1 rest %2", needed, rest );
if( needed > rest )
{
list tr = [];
list weight =
maplist( list l, e["added"]:[],
``({
integer idx = l[0]:0;
integer d = ps[idx,"want_cyl"]:0 -
ps[idx,"cylinders"]:0;
if( d>0 )
{
l = add( l, ps[idx,"cylinders"]:0 );
}
tr = add( tr, l );
return( d>0 ? d : 0 );
}));
y2milestone( "normalize_gaps tr %1", tr );
map r = $[];
r = distribute_space( rest, weight, tr, ps );
g["gap",gindex,"added"] = eval(r["added"]:[]);
g["gap",gindex,"cylinders"] = e["cylinders"]:0 - r["diff"]:0;
y2milestone( "normalize_gaps partly satisfy %1 cyl %2",
g["gap",gindex,"added"]:[],
g["gap",gindex,"cylinders"]:0 );
}
else
{
g["gap",gindex,"cylinders"] = e["cylinders"]:0 - needed;
}
pindex = 0;
foreach( list p, g["gap",gindex,"added"]:[],
``{
if( size(p)<3 )
{
tidx = p[0]:0;
if( ps[tidx,"want_cyl"]:0 > ps[tidx,"cylinders"]:0 )
{
p = add( p, ps[tidx,"want_cyl"]:0 );
}
else
{
p = add( p, ps[tidx,"cylinders"]:0 );
}
g["gap",gindex,"added",pindex] = p;
y2milestone( "normalize_gaps satisfy p %1 cyl %2", p,
e["cylinders"]:0 );
}
pindex = pindex+1;
});
y2milestone( "normalize_gaps added %1",
g["gap",gindex,"added"]:[] );
}
gindex = gindex + 1;
});
gindex = 0;
foreach( map e, g["gap"]:[],
``{
if( !e["exists"]:false && e["cylinders"]:0>0 )
{
list<integer> weight = maplist( list l, e["added"]:[],
``(ps[l[0]:0,"size"]:0==0 ? 1 : 0) );
if( find( integer l, weight, ``(l>0) ) != nil )
{
map r = $[];
r = distribute_space( e["cylinders"]:0, weight, e["added"]:[],
ps );
g["gap",gindex,"added"] = eval(r["added"]:[]);
g["gap",gindex,"cylinders"] = e["cylinders"]:0 - r["diff"]:0;
y2milestone( "normalize_gaps increase max p %1 cyl %2",
g["gap",gindex,"added"]:[],
g["gap",gindex,"cylinders"]:0 );
}
}
gindex = gindex + 1;
});
gindex = 0;
foreach( map e, g["gap"]:[],
``{
if( !e["exists"]:false && e["cylinders"]:0>0 &&
e["cylinders"]:0 < g["disk_cyl"]:0/20 )
{
list weight = maplist( list l, e["added"]:[], ``(l[2]:0) );
map r = $[];
r = distribute_space( e["cylinders"]:0, weight, e["added"]:[], ps );
g["gap",gindex,"added"] = eval(r["added"]:[]);
g["gap",gindex,"cylinders"] = e["cylinders"]:0 - r["diff"]:0;
y2milestone( "normalize_gaps close small gap p %1 cyl %2",
g["gap",gindex,"added"]:[],
g["gap",gindex,"cylinders"]:0 );
}
gindex = gindex + 1;
});
gindex = 0;
foreach( map e, g["gap"]:[],
``{
if( !e["exists"]:false && e["cylinders"]:0>0 )
{
list<integer> weight = [];
weight =
maplist( list l, e["added"]:[],
``((ps[l[0]:0,"increasable"]:false) ? 1 : 0));
y2milestone( "normalize_gaps w %1", weight );
if( find( integer l, weight, ``(l>0) ) != nil )
{
map r = $[];
r = distribute_space( e["cylinders"]:0, weight, e["added"]:[],
ps );
g["gap",gindex,"added"] = eval(r["added"]:[]);
g["gap",gindex,"cylinders"] = e["cylinders"]:0 - r["diff"]:0;
e["cylinders"] = g["gap",gindex,"cylinders"]:0;
y2milestone( "normalize_gaps increase increasable p %1 cyl %2",
g["gap",gindex,"added"]:[],
g["gap",gindex,"cylinders"]:0 );
}
}
gindex = gindex + 1;
});
gindex = 0;
foreach( map e, g["gap"]:[],
``{
if( !e["exists"]:false && e["extended"]:false && e["created"]:0 > 0 &&
size(e["added"]:[])==1 && e["cylinders"]:0==0 )
{
g["gap",gindex,"extended"] = false;
g["gap",gindex,"added",0,1] = e["created"]:0;
y2milestone( "normalize_gaps changed extended %1",
g["gap",gindex]:$[] );
}
gindex = gindex + 1;
});
gindex = 0;
map sort_map = $[ "/boot" : 0, "/boot/efi" : 0, "swap" : 1,
"/" : 5, "/home" :6 ];
foreach( map e, g["gap"]:[],
``{
if( !e["exists"]:false && size(e["added"]:[])>1 )
{
y2milestone( "normalize_gaps old added %1", e["added"]:[] );
list nums = maplist( list l, e["added"]:[], ``(l[1]:-1));
y2milestone( "normalize_gaps old nums %1", nums );
list sdd = sort( list a, list b, e["added"]:[],
``({
integer ai = a[0]:0;
integer bi = b[0]:0;
if( ps[ai,"primary"]:false != ps[bi,"primary"]:false )
return( ps[ai,"primary"]:false );
else if( ps[ai,"max_cyl"]:big_cyl != ps[bi,"max_cyl"]:big_cyl )
return( ps[ai,"max_cyl"]:big_cyl < ps[bi,"max_cyl"]:big_cyl );
else
return( sort_map[ps[ai,"mount"]:""]:3 < sort_map[ps[bi,"mount"]:""]:3);
}));
integer idx = 0;
foreach( list e, (list<list>)sdd,
``{
sdd[idx,1] = nums[idx]:0;
idx = idx+1;
});
g["gap",gindex,"added"] = sdd;
y2milestone( "normalize_gaps sort added %1",
g["gap",gindex,"added"]:[] );
}
gindex = gindex + 1;
});
y2milestone( "normalize_gaps gap %1", g );
return( g );
};
define map distribute_space( integer rest, list weights, list added, list ps )
``{
integer diff_sum = 0;
integer sum = 0;
integer index = 0;
integer pindex = 0;
integer scount = 0;
y2milestone( "distribute_space rest %1 weights %2 added %3", rest,
weights, added );
integer loopcount=0;
do
{
loopcount = loopcount+1;
index = 0;
sum = 0;
scount = 0;
foreach( list p, (list<list>)added,
``{
pindex = p[0]:0;
if( ps[pindex,"size_max_cyl"]:0==0 ||
ps[pindex,"size_max_cyl"]:0 > p[2]:0)
{
sum = sum + weights[index]:0;
y2milestone( "sum %1 weight %2 pindex %3", sum,
weights[index]:0, pindex );
scount = scount+1;
}
index = index+1;
});
index = 0;
y2milestone( "distribute_space sum %1 rest %2 scount %3 added %4 lc %5",
sum, rest, scount, added, loopcount );
foreach( list p, (list<list>)added,
``{
pindex = p[0]:0;
if( size(p)==3 && sum>0 &&
(ps[pindex,"size_max_cyl"]:0==0 ||
ps[pindex,"size_max_cyl"]:0 > p[2]:0) )
{
integer diff = ((rest*weights[index]:0) + sum/2) / sum;
if( ps[pindex,"size_max_cyl"]:0>0 &&
diff > ps[pindex,"size_max_cyl"]:0-p[2]:0 )
{
diff = ps[pindex,"size_max_cyl"]:0-p[2]:0;
}
sum = sum - weights[index]:0;
rest = rest - diff;
added[index,2] = added[index,2]:0 + diff;
diff_sum = diff_sum + diff;
y2milestone( "distribute_space sum %1 rest %2 diff %3 added %4",
sum, rest, diff, added[index]:[] );
}
index = index+1;
});
}
while( rest>0 && scount>0 && loopcount<3 );
map ret = $[ "added":added, "diff" : diff_sum ];
y2milestone( "distribute_space ret %1", ret );
return( ret );
}
define integer do_weighting( list ps, map g )
``{
y2milestone( "do_weighting gap %1", g["gap"]:[] );
integer ret = 0;
integer index = 0;
integer diff = 0;
if( cur_mode == `reuse )
{
ret = ret - 100;
}
else if( cur_mode == `resize )
{
ret = ret - 1000;
}
else if( cur_mode == `desparate )
{
ret = ret - 1000000;
}
y2milestone( "do_weighting after mode ret %1", ret );
foreach( map e, g["gap"]:[],
``{
y2milestone( "do_weighting e %1", e );
if( !e["exists"]:false && e["cylinders"]:0 > 0 )
{
diff = -5;
if( e["cylinders"]:0 < g["disk_cyl"]:0/20 )
{
diff = diff - 10;
}
ret = ret + diff;
y2milestone( "do_weighting after gaps diff %1 ret %2", diff, ret );
}
foreach( list p, e["added"]:[],
``{
index = p[0]:0;
if( e["exists"]:false && ps[index,"mount"]:""=="swap" &&
e["swap"]:false )
{
diff = 100;
ret = ret + diff;
y2milestone( "do_weighting after swap reuse diff %1 ret %2",
diff, ret );
}
if( ps[index,"want_cyl"]:0>0 )
{
diff = ps[index,"want_cyl"]:0 - p[2]:0;
integer normdiff = diff * 100 / p[2]:0;
if( diff < 0 )
{
normdiff = -normdiff;
}
else if( diff > 0 )
{
normdiff = normdiff / 10;
}
diff = ps[index,"want_cyl"]:0*g["cyl_size"]:1 / (100*1024*1024) -
normdiff;
ret = ret + diff;
y2milestone( "do_weighting after pct parts diff %1 ret %2",
diff, ret );
}
if( ps[index,"size"]:0==0 )
{
diff = p[2]:0 * g["cyl_size"]:1 / (50 * 1024 * 1024);
ret = ret + diff;
y2milestone( "do_weighting after maximizes parts diff %1 ret %2",
diff, ret );
}
if( ps[index,"size_max_cyl"]:0 > 0 &&
ps[index,"size_max_cyl"]:0 < p[2]:0 )
{
diff = p[2]:0 - ps[index,"size_max_cyl"]:0;
integer normdiff = diff * 100 / ps[index,"size_max_cyl"]:0;
ret = ret - normdiff;
y2milestone( "do_weighting after maximal size diff %1 ret %2",
-normdiff, ret );
}
});
if( size(e["added"]:[])>0 && e["cylinders"]:0 > 0 )
{
integer diff = (e["cylinders"]:0 * g["cyl_size"]:1) / (1024*1024*1024);
ret = ret - diff;
y2milestone( "do_weighting after gap size diff %1 ret %2", -diff, ret );
}
if( e["extended"]:false )
ret = ret-1;
y2milestone( "do_weighting %1", ret );
});
y2milestone( "do_weighting ret %1", ret );
return( ret );
};
define list<map> try_remove_sole_extended( list<map> parts )
{
list<map> ret = parts;
if( find( map p, ret,
``(p["type"]:`unknown==`extended &&
!p["delete"]:false))!=nil &&
find( map p, ret,
``(p["type"]:`unknown==`logical &&
!p["delete"]:false))==nil )
{
ret = maplist( map p, ret,
``{
if( p["type"]:`unknown == `extended )
p["delete"] = true;
return( p );
});
y2milestone( "try_remove_sole_extended delete extended p:%1", ret );
}
return( ret );
}
define map remove_possible_partitions( map disk, map conf )
``{
map ret = (map)eval(disk);
ret["partitions"] = maplist( map p, ret["partitions"]:[],
``{
integer fsid = p["fsid"]:0;
if( (conf["remove_special_partitions"]:false ||
!contains( Partitions::do_not_delete, fsid ) ) &&
p["type"]:`primary != `extended &&
!contains( conf["keep_partition_num"]:[], p["nr"]:0 ) &&
!contains( conf["keep_partition_id"]:[], fsid ) &&
!contains( conf["keep_partition_fsys"]:[], p["used_fs"]:`none ))
{
p["delete"] = true;
}
return( p );
});
ret["partitions"] = try_remove_sole_extended( ret["partitions"]:[] );
return( ret );
};
define map try_resize_windows( map disk )
``{
integer cyl_size = disk["cyl_size"]:1;
map win = $[];
map ret = (map)eval(disk);
ret["partitions"] = maplist( map p, ret["partitions"]:[],
``{
integer fsid = p["fsid"]:0;
if( Partitions::IsDosWinNtPartition( fsid ) )
{
win = p["winfo"]:$[];
y2milestone( "try_resize_windows win=%1", win );
if( win != nil && win["ok"]:false && p["size_k"]:0 > 1024*1024 )
{
p["winfo"] = win;
p["resize"] = true;
p["region",1] = (win["new_size"]:0 + cyl_size - 1) / cyl_size;
p["win_max_length"] =
(win["max_win_size"]:0 + cyl_size - 1) / cyl_size;
y2milestone( "try_resize_windows win part %1", p );
}
}
return( p );
});
return( ret );
};
define list<map> get_gaps( integer start, integer end, list<map> part,
boolean add_exist_linux )
``{
y2milestone( "get_gaps start %1 end %2 add_exist %3", start, end,
add_exist_linux );
list<map> ret = [];
map entry = $[];
foreach( map p, part,
``{
integer s = p["region",0]:0;
integer e = s + p["region",1]:1 - 1;
entry = $[];
if( start < s )
{
entry["start"] = start;
entry["end"] = s-1;
ret = add( ret, eval(entry) );
}
if( add_exist_linux && size(p["mount"]:"")==0 &&
(p["fsid"]:0==Partitions::fsid_native ||
p["fsid"]:0==Partitions::fsid_swap) )
{
entry["swap"] = p["fsid"]:0==Partitions::fsid_swap;
entry["start"] = s;
entry["end"] = e;
entry["exists"] = true;
entry["nr"] = p["nr"]:0;
ret = add( ret, entry );
}
start = e+1;
});
if( start < end )
{
entry = $[];
entry["start"] = start;
entry["end"] = end;
ret = add( ret, entry );
}
y2milestone( "get_gaps ret %1", ret );
return( ret );
}
define map get_gap_info( map disk, boolean add_exist_linux )
``{
map ret = $[];
list<map> gap = [];
list<map> plist = filter( map p, disk["partitions"]:[],
``(!p["delete"]:false) );
plist = sort( map a, map b, plist, ``(a["region",0]:0<b["region",0]:0) );
list<integer> exist_pnr = sort( maplist( map e, plist, ``(e["nr"]:0) ));
if( disk["label"]:""=="mac" && !contains( exist_pnr, 1 ) )
{
exist_pnr = add( exist_pnr, 1 );
}
integer max_prim = Partitions::MaxPrimary(disk["label"]:"msdos");
boolean has_ext = Partitions::HasExtended( disk["label"]:"msdos" );
if( has_ext )
{
map ext = filter( map p, plist,
``(p["type"]:`primary == `extended))[0]:$[];
ret["extended_possible"] = size(ext)==0;
ret["ext_reg"] = ext["region"]:[];
if( size(ext)>0 )
{
gap = get_gaps( ext["region",0]:0,
ext["region",0]:0 + ext["region",1]:1-1,
filter( map p, plist, ``(p["nr"]:0>max_prim)),
add_exist_linux );
gap = maplist( map e, gap,
``{
e["extended"]=true;
return e;
});
plist = filter( map p, plist, ``(p["nr"]:0<=max_prim));
}
}
else
{
ret["extended_possible"] = false;
}
gap = (list<map>)union( gap,
get_gaps( 0, disk["cyl_count"]:1-1, plist, add_exist_linux ));
integer av_size = 0;
gap = maplist( map e, gap,
``{
e["cylinders"] = e["end"]:0 - e["start"]:0 + 1;
e["size"] = e["cylinders"]:0 * disk["cyl_size"]:1;
av_size = av_size + e["size"]:0;
return( e );
});
gap = maplist( map e, gap,
``{
e["sizepct"] = (e["size"]:0 * 201 / 2) / av_size;
if( e["sizepct"]:0 == 0 )
{
e["sizepct"] = 1;
}
return( e );
});
ret["cyl_size"] = disk["cyl_size"]:1;
ret["disk_cyl"] = disk["cyl_count"]:1;
ret["sum"] = av_size;
integer max_pnr = max_prim;
integer pnr = 1;
list free_pnr = [];
y2milestone( "get_gap_info exist_pnr %1", exist_pnr );
while( pnr<=max_pnr )
{
if( !contains( exist_pnr, pnr ) )
{
free_pnr = add( free_pnr, pnr );
}
pnr = pnr + 1;
}
ret["free_pnr"] = free_pnr;
list<integer> ext_pnr = [ 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,
45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63];
integer max_logical = disk["max_logical"]:15;
if( max_logical<63 )
{
ext_pnr = filter( integer i, ext_pnr, ``(i<=max_logical));
}
if( !has_ext )
{
ext_pnr = [];
}
else
{
integer maxlog = size(filter( integer i, exist_pnr, ``(i>max_pnr))) + 4;
ext_pnr = filter( integer i, ext_pnr, ``(i>maxlog));
}
ret["ext_pnr"] = ext_pnr;
ret["gap"] = gap;
y2milestone( "get_gap_info ret %1", ret );
return( ret );
}
/**
* Read partition data from XML control file
* @return map flexible propsal map
*/
define map read_partition_xml_config()
``{
map xmlflex = (map)ProductFeatures::GetFeature ("partitioning", "flexible_partitioning");
y2debug("xml input: %1", xmlflex );
map conf = $[];
conf["prefer_remove"] = xmlflex["prefer_remove"]:true;
conf["remove_special_partitions"] =
xmlflex["remove_special_partitions"]:false;
conf["keep_partition_id"] = [];
conf["keep_partition_num"] = [];
conf["keep_partition_fsys"] = [];
foreach( string key, [ "keep_partition_id", "keep_partition_num"], ``{
list num = [];
list<string> nlist = splitstring(xmlflex[key]:"", ",");
foreach( string n, nlist, ``{ num = union( num, [tointeger(n)] );});
conf[key] = num;
});
list fsys = [];
list<string> nlist = splitstring( xmlflex["keep_partition_fsys"]:"" , "," );
foreach( string n, nlist,
``{
symbol fs = FileSystems::FsToSymbol(n);
if( fs != `none )
{
fsys = union( fsys, [ fs ] );
}
});
conf["keep_partition_fsys"] = fsys;
list partitions = [];
foreach(map p, xmlflex["partitions"]:[],
``{
map partition = $[];
if (p["disk"]:0 != 0)
{
partition["disk"] = p["disk"]:0;
}
if (p["id"]:0 != 0)
{
partition["id"] = p["id"]:0;
}
if (p["fstopt"]:"" != "")
{
partition["fstopt"] = p["fstopt"]:"";
}
if (p["formatopt"]:"" != "")
{
partition["fopt"] = p["formatopt"]:"";
}
partition["increasable"] = p["increasable"]:false;
if (p["mount"]:"" != "")
{
partition["mount"] = p["mount"]:"";
}
if (p["percent"]:-1 != -1)
{
partition["pct"] = p["percent"]:100;
}
if (p["label"]:"" != "")
{
partition["label"] = p["label"]:"";
}
if (p["maxsize"]:"" != "")
{
partition["maxsize"] = kmgt_str_to_byte(p["maxsize"]:"");
}
if (p["fsys"]:"" != "")
{
symbol fs = FileSystems::FsToSymbol(p["fsys"]:"");
if( fs != `none )
{
partition["fsys"] = fs;
}
}
if (p["size"]:"" != "")
{
string s = p["size"]:"";
if( tolower(s) == "auto" )
{
partition["size"] = -1;
}
else if( tolower(s) == "max" )
{
partition["size"] = 0;
}
else
{
partition["size"] = kmgt_str_to_byte( s );
}
}
if( partition["size"]:0 == -1 && partition["mount"]:"" == "swap" )
{
partition["size"] = 1024*1024*Partitions::SwapSizeMb(0);
}
if( partition["mount"]:"" == Partitions::BootMount() )
{
if( partition["size"]:0 == -1 )
{
partition["size"] = Partitions::MinimalNeededBootsize();
}
if( partition["fsys"]:`none == `none )
{
partition["fsys"] = Partitions::DefaultBootFs();
}
if( partition["id"]:0 == 0 )
{
partition["id"] = Partitions::FsidBoot();
}
partition["max_cyl"] = Partitions::BootCyl();
}
if( partition["size"]:0 == -1 )
{
partition["size"] = 0;
}
y2debug("partition: %1", partition);
if( size(partition["mount"]:"")>0 || partition["id"]:0 > 0 )
{
partitions = add( partitions, partition );
}
});
conf["partitions"] = partitions;
if( size(partitions)==0 )
{
conf = $[];
}
else
{
conf["partitions"] = partitions;
}
y2milestone( "conf %1", conf );
return( conf );
}
define map read_partition_config( string fpath )
``{
integer pos = 0;
string line = "";
string rex = "";
map conf = $[];
conf["prefer_remove"] = true;
conf["remove_special_partitions"] = false;
conf["keep_partition_id"] = [];
conf["keep_partition_num"] = [];
conf["keep_partition_fsys"] = [];
string cstring = (string) SCR::Read( .target.string, fpath );
list<string> lines = filter( string e, splitstring( cstring, "\n" ), ``(size(e)>0) );
rex = "[ \t]*#.*";
y2milestone( "lines %1", lines );
lines = filter( string e, lines, ``(!regexpmatch( e, "[ \t]*#.*" )));
y2milestone( "lines %1", lines );
list fnd = [];
foreach( string key, [ "PREFER_REMOVE", "REMOVE_SPECIAL_PARTITIONS" ],
``{
rex = "[ \t]*" + key + "[ \t]*=";
fnd = filter( string e, lines, ``(regexpmatch( e, rex )));
y2milestone( "rex %1 fnd %2", rex, fnd );
if( size(fnd)>0 )
{
line = deletechars( fnd[size(fnd)-1]:"", "\t " );
pos = findlastof( line, "=" );
if( pos > 0 )
{
conf[tolower(key)] = tointeger( substring( line, pos+1 ))>0;
}
}
});
foreach( string key, [ "KEEP_PARTITION_ID", "KEEP_PARTITION_NUM" ],
``{
rex = "[ \t]*" + key + "[ \t]*=";
y2milestone( "rex %1", rex );
foreach( string l, filter( string e, lines, ``(regexpmatch( e, rex ))),
``{
y2milestone( "line %1", l );
line = deletechars( l, "\t " );
pos = findlastof( line, "=" );
if( pos > 0 )
{
list num = [];
list<string> nlist = splitstring( substring( line, pos+1 ), "," );
foreach( string n, nlist, ``{ num = union( num, [tointeger(n)] );});
conf[tolower(key)] = union( conf[tolower(key)]:[], num );
}
});
});
list fsys = [];
rex = "[ \t]*" + "KEEP_PARTITION_FSYS" + "[ \t]*=";
foreach( string l, filter( string e, lines, ``(regexpmatch( e, rex ))),
``{
y2milestone( "line %1", l );
line = deletechars( l, "\t " );
pos = findlastof( line, "=" );
if( pos > 0 )
{
list<string> nlist = splitstring( substring( line, pos+1 ), "," );
foreach( string n, nlist,
``{
symbol fs = FileSystems::FsToSymbol(n);
if( fs != `none )
{
fsys = union( fsys, [ fs ] );
}
});
}
});
conf["keep_partition_fsys"] = fsys;
list partitions = [];
map part = $[];
rex = "[ \t]*" + "PARTITION" + "[ \t][ \t]*";
foreach( string l, filter( string e, lines, ``(regexpmatch( e, rex ))),
``{
y2milestone( "line %1", l );
string par = "";
string key = "";
integer pos = search( l, "PARTITION" );
line = substring( l, pos+10 );
y2milestone( "line %1", line );
pos = search( line, "=" );
part = $[];
while( pos!=nil )
{
key = deletechars( substring( line, 0, pos ), " \t" );
line = substring( line, pos+1 );
if( substring( line, 0, 1 ) == "\"" )
{
line = substring( line, 1 );
pos = search( line, "\"" );
par = substring( line, 0, pos );
line = substring( line, pos+1 );
}
else
{
pos = findfirstof( line, " \t" );
if( pos==nil )
{
par = line;
}
else
{
par = substring( line, 0, pos );
line = substring( line, pos+1 );
}
}
y2debug( "key %1 par \"%2\"", key, par );
if( key == "id" )
{
part[key] = tointeger(par);
}
else if( key == "mount" )
{
part[key] = par;
}
else if( key == "increasable" )
{
part["increasable"] = tointeger(par)>0 ? true : false;
}
else if( key == "size" )
{
if( tolower(par) == "auto" )
{
part["size"] = -1;
}
else if( tolower(par) == "max" )
{
part["size"] = 0;
}
else
{
part["size"] = kmgt_str_to_byte( par );
}
}
else if( key == "label" )
{
part[key] = par;
}
else if( key == "maxsize" )
{
part[key] = kmgt_str_to_byte( par );
}
else if( key == "sizepct" )
{
part["pct"] = tointeger(par);
}
else if( key == "disk" )
{
part[key] = tointeger(par);
}
else if( key == "fsys" )
{
symbol fs = FileSystems::FsToSymbol(par);
if( fs != `none )
{
part[key] = fs;
}
}
else if( key == "fstopt" )
{
part[key] = par;
}
else if( key == "formatopt" )
{
part["fopt"] = par;
}
pos = search( line, "=" );
}
y2milestone( "part %1", part );
if( part["size"]:0 == -1 && part["mount"]:"" == "swap" )
{
part["size"] = 1024*1024*Partitions::SwapSizeMb(0);
}
if( part["mount"]:"" == Partitions::BootMount() )
{
if( part["size"]:0 == -1 )
{
part["size"] = Partitions::MinimalNeededBootsize();
}
if( part["fsys"]:`none == `none )
{
part["fsys"] = Partitions::DefaultBootFs();
}
if( part["id"]:0 == 0 )
{
part["id"] = Partitions::FsidBoot();
}
part["max_cyl"] = Partitions::BootCyl();
}
if( part["size"]:0 == -1 )
{
part["size"] = 0;
}
if( size(part["mount"]:"")>0 || part["id"]:0 > 0 )
{
partitions = add( partitions, part );
}
});
conf["partitions"] = partitions;
if( size(partitions)==0 )
{
conf = $[];
}
else
{
conf["partitions"] = partitions;
}
y2milestone( "conf %1", conf );
return( conf );
}
map can_swap_reuse( string disk, list<map> partitions, map<string,map> tgmap )
{
map ret = $[];
y2milestone( "can_swap_reuse disk %1 partitions %2", disk, partitions );
list<map> swaps = filter( map p, partitions,
``(p["type"]:`unknown!=`free &&
!p["delete"]:false &&
p["detected_fs"]:`unknown==`swap));
swaps = filter( map p, swaps, ``(Storage::CheckSwapable(p["device"]:"")));
swaps = sort( map a, map b, swaps, ``(a["size_k"]:0>b["size_k"]:0));
y2milestone( "can_swap_reuse swaps %1", swaps );
if( swaps[0,"size_k"]:0 >= 128*1024 )
{
ret["partitions"] =
maplist( map p, partitions,
``{
if( !p["delete"]:false &&
p["device"]:""==swaps[0,"device"]:"" )
{
p["mount"] = "swap";
if( haskey( p, "vg" ))
{
p = remove( p, "vg" );
if( p["change_fsid"]:false )
p["fsid"] = p["ori_fsid"]:Partitions::fsid_swap;
}
}
return( p );
});
}
else
{
swaps = [];
map<string,map> tg = filter( string k, map d, tgmap,
``(Storage::IsPartitionable(d)));
if( haskey( tg, disk ))
tg = remove( tg, disk );
y2milestone( "can_swap_reuse tg wo %1", tg );
foreach( string dev, map disk, tg,
``{
list sw = filter( map p, disk["partitions"]:[],
``(p["type"]:`unknown!=`extended &&
!p["delete"]:false &&
p["detected_fs"]:`unknown==`swap));
y2milestone( "can_swap_reuse disk %1 sw %2", dev, sw );
swaps = (list<map>)union( swaps, sw );
});
swaps = sort( map a, map b, swaps, ``(a["size_k"]:0>b["size_k"]:0));
y2milestone( "can_swap_reuse swaps %1", swaps );
if( swaps[0,"size_k"]:0 >= 256*1024 )
{
ret["targets"] = Storage::SetPartitionData( tgmap,
swaps[0,"device"]:"",
"mount", "swap" );
ret["targets"] = Storage::DelPartitionData( ret["targets"]:$[],
swaps[0,"device"]:"",
"vg" );
}
}
y2milestone( "can_swap_reuse ret %1", ret );
return( ret );
}
list<map> can_boot_reuse( string disk, string label, boolean boot,
integer max_prim, list<map> partitions )
{
list<map> ret = [];
y2milestone( "can_boot_reuse boot %1", boot );
if( boot && !Partitions::PrepBoot() )
{
y2milestone( "can_boot_reuse disk %1 max_prim %2 label %3 part %4",
disk, max_prim, label, partitions );
list<map> pl = [];
pl = filter( map p, partitions,
``(!p["delete"]:false &&
p["size_k"]:0*1024 >=
Partitions::MinimalRequiredBootsize()));
map boot = find( map p, pl,
``((p["fsid"]:0 == Partitions::fsid_gpt_boot) ||
(p["fsid"]:0 == Partitions::FsidBoot() &&
p["size_k"]:0<500*1024)||
(p["detected_fs"]:`unknown==`hfs &&
p["boot"]:false && label=="mac") ||
(p["fsid"]:0 == Partitions::fsid_prep_chrp_boot &&
p["nr"]:0 <= max_prim &&
Partitions::PrepBoot())));
if( boot != nil )
{
ret = maplist( map p, partitions,
``{
if( !p["delete"]:false &&
p["device"]:""==boot["device"]:"" )
{
p["mount"] = Partitions::BootMount();
p["used_fs"] = Partitions::DefaultBootFs();
p["format"] = true;
p["fstopt"] =
FileSystems::DefaultFstabOptions( p );
p["fs_options"] =
FileSystems::DefaultFormatOptions( p );
}
return( p );
});
}
y2milestone( "can_boot_reuse ret %1", ret );
}
return( ret );
}
list<map> can_mp_reuse( string mp, integer min, integer max,
list<map> partitions )
{
list<map> ret = [];
y2milestone( "can_mp_reuse mp %1 min %2 max %3", mp, min, max );
list<map> pl = [];
pl = filter( map p, partitions,
``(!p["delete"]:false &&
p["fsid"]:Partitions::fsid_native ==
Partitions::fsid_native &&
p["used_by_type"]:`UB_NONE == `UB_NONE &&
size(p["mount"]:"")==0 &&
p["size_k"]:0/1024 >= min &&
(max==0 || p["size_k"]:0/1024 <= max)));
y2milestone( "can_mp_reuse normal %1", pl );
if( size(pl)>0 )
{
pl = sort( map a, map b, pl, ``(a["size_k"]:0>b["size_k"]:0));
y2milestone( "can_mp_reuse sorted %1", pl );
ret = maplist( map p, partitions,
``{
if( !p["delete"]:false &&
p["device"]:""==pl[0,"device"]:"" )
{
p["mount"] = mp;
p["used_fs"] = Partitions::DefaultFs();
p["format"] = true;
p["fstopt"] = FileSystems::DefaultFstabOptions( p );
p["fs_options"] =
FileSystems::DefaultFormatOptions( p );
}
return( p );
});
}
y2milestone( "can_mp_reuse ret %1", ret );
return( ret );
}
integer get_avail_size_mb( list<map> parts )
{
integer ret = 0;
foreach( map pp, filter( map p, parts, ``(p["delete"]:false &&
p["type"]:`unknown!=`extended)),
``{
ret = ret + pp["size_k"]:0/1024;
});
y2milestone( "get_avail_size_mb ret %1", ret );
return( ret );
}
list get_swap_sizes( integer space )
{
list l = [ Partitions::SwapSizeMb(0), Partitions::SwapSizeMb(space) ];
y2milestone( "get_swap_sizes space %1 ret %2", space, l );
return( l );
}
list<map> get_proposal( boolean have_swap, map disk )
{
list<map> ret = [];
y2milestone( "get_proposal have_swap:%1 disk %2", have_swap, disk );
map root = $[ "mount" : "/", "increasable" : true,
"fsys" : Partitions::DefaultFs(), "size" : 0 ];
map opts = Storage::GetControlCfg();
map conf = $[ "partitions" : [] ];
list swap_sizes = [];
integer avail_size = get_avail_size_mb(disk["partitions"]:[]);
if( !have_swap )
{
swap_sizes = get_swap_sizes( avail_size );
map swap = $[ "mount" : "swap", "increasable" : true, "fsys" : `swap,
"maxsize" : 2*1024*1024*1024,
"size" : swap_sizes[0]:256*1024*1024 ];
conf["partitions"] = add( conf["partitions"]:[], swap );
}
conf["partitions"] = add( conf["partitions"]:[], root );
map old_root = $[];
if( Storage::ProposalHome() && opts["home_limit"]:0 < avail_size )
{
map home = $[ "mount" : "/home", "increasable" : true,
"fsys" : Partitions::DefaultFs(), "size" : 512*1024*1024,
"pct" : 100-opts["root_percent"]:40 ];
conf["partitions"] = maplist( map p, conf["partitions"]:[],
``{
if( p["mount"]:""=="/" )
{
old_root = p;
p["pct"] = opts["root_percent"]:40;
p["maxsize"] = opts["root_max"]:0*1024*1024;
p["size"] = opts["root_base"]:0*1024*1024;
}
return( p );
});
conf["partitions"] = add( conf["partitions"]:[], home );
}
map ps1 = do_flexible_disk_conf( disk, conf, false, false );
if( size(old_root)>0 && !ps1["ok"]:false )
{
conf["partitions"] =
filter( map p, conf["partitions"]:[],
``(p["mount"]:""!="/home" && p["mount"]:""!="/"));
conf["partitions"] = add( conf["partitions"]:[], old_root );
ps1 = do_flexible_disk_conf( disk, conf, false, false );
}
if( !have_swap )
{
integer diff = swap_sizes[0]:256 - swap_sizes[1]:256;
if( diff<0 )
diff = -diff;
y2milestone( "get_proposal diff:%1 ps1 ok:%2", diff, ps1["ok"]:false );
if( (!ps1["ok"]:false && diff>0) || diff>100 )
{
conf["partitions",0,"size"] = swap_sizes[1]:256*1024*1024;
map ps2 = do_flexible_disk_conf( disk, conf, false, false );
y2milestone( "get_proposal ps2 ok:%1", ps2["ok"]:false );
if( ps2["ok"]:false )
{
map rp1 = find( map p, ps1["disk","partitions"]:[],
``(!p["delete"]:false && p["mount"]:""=="/"));
map rp2 = find( map p, ps2["disk","partitions"]:[],
``(!p["delete"]:false && p["mount"]:""=="/"));
y2milestone( "get_proposal rp1:%1", rp1 );
y2milestone( "get_proposal rp2:%1", rp2 );
if( rp1==nil || (rp2!=nil && rp2["size_k"]:0>rp1["size_k"]:0 ))
ps1 = ps2;
}
}
}
if( ps1["ok"]:false )
ret = ps1["disk","partitions"]:[];
y2milestone( "get_proposal ret:%1", ret );
return( ret );
}
integer get_usable_size_mb( map disk, boolean reuse_linux )
{
integer ret = 0;
integer cyl_size = disk["cyl_size"]:0;
integer disk_cyl = disk["cyl_count"]:0;
list<map> partitions = filter( map p, disk["partitions"]:[],
``(!p["create"]:false));
partitions = sort( map p1, map p2, partitions,
``(p1["region",0]:0 < p2["region",0]:0));
integer last_end = 0;
foreach( map p, partitions,
``{
if( p["region",0]:0>last_end )
ret = ret + (p["region",0]:0-last_end) * cyl_size;
if( p["type"]:`unknown!=`extended &&
(p["delete"]:false || (reuse_linux && p["linux"]:false)))
ret = ret + p["size_k"]:0 * 1024;
last_end = p["region",0]:0;
if( p["type"]:`unknown != `extended )
last_end = last_end + p["region",1]:0;
});
if( last_end < disk_cyl )
ret = ret + (disk_cyl-last_end) * cyl_size;
ret = ret / (1024*1024);
return( ret );
}
integer get_mb_sol( map sol, string mp )
{
map pa = find( map p, sol["disk","partitions"]:[], ``(p["mount"]:""==mp));
y2milestone( "get_mb_sol pa %1", pa );
integer ret = pa!=nil ? pa["size_k"]:0/1024 : 0;
y2milestone( "get_mb_sol ret %1", ret );
return( ret );
}
integer get_vm_sol( map sol )
{
integer ret = 0;
foreach( map p, sol["disk","partitions"]:[],
``{
if( !p["delete"]:false && (size(p["mount"]:"")>0 || size(p["vg"]:"")>0))
ret = ret + p["size_k"]:0/1024;
});
y2milestone( "get_vm_sol ret %1", ret );
return( ret );
}
list<map> special_boot_proposal_prepare( list<map> partitions )
{
list<map> ret = partitions;
if( Partitions::PrepBoot() )
{
ret = maplist( map p, partitions,
``{
if( size(p["mount"]:"")==0 &&
(p["fsid"]:0 == 0x06 || p["fsid"]:0 == 0x41) )
p["delete"] = true;
return( p );
});
y2milestone( "special_boot_proposal_prepare part:%1", partitions );
y2milestone( "special_boot_proposal_prepare ret:%1", ret );
}
return( ret );
}
map<string,map> prepare_part_lists( list<string> ddev, map<string,map> tg )
{
list linux_pid = [ Partitions::fsid_native, Partitions::fsid_swap,
Partitions::fsid_lvm, Partitions::fsid_raid ];
foreach( string s, ddev,
``{
tg[s,"partitions"] =
maplist( map p, tg[s,"partitions"]:[],
``{
if( contains( linux_pid, p["fsid"]:0 ) ||
(p["fsid"]:0 == Partitions::fsid_gpt_boot) ||
(p["fsid"]:0 == Partitions::FsidBoot() &&
p["size_k"]:0<500*1024)||
(Partitions::PrepBoot() &&
(p["fsid"]:0 == Partitions::fsid_prep_chrp_boot||
p["fsid"]:0 == 0x06)))
p["linux"] = true;
else
p["linux"] = false;
return( p );
});
});
return( tg );
}
list<string> get_disk_try_list( map<string,map> tg, boolean soft )
{
list<string> ret = [];
ret = maplist( string k, map e,
filter( string l, map f, tg,
``(!ignore_disk(l,f,soft))), ``(k));
ret = sort( ret );
if( size(ret)>4 )
{
ret = restrict_disk_names( ret );
}
y2milestone( "get_disk_try_list soft:%1 ret:%2", soft, ret );
return( ret );
}
boolean usable_for_win_resize( map p, boolean assert_cons_fs )
{
boolean ret = Partitions::IsDosWinNtPartition( p["fsid"]:0 ) &&
p["size_k"]:0 > 1024*1024 &&
!p["resize"]:false && !p["delete"]:false;
if( ret )
{
if( assert_cons_fs )
ret = p["winfo","ok"]:false;
else
ret = size(p["winfo"]:$[])>0;
}
return( ret );
}
list<map> remove_p_settings( list<map> parts, list<string> mp )
{
list<string> rems = [ "resize", "used_fs", "win_max_length", "mount",
"format", "ignore_fs", "vg" ];
parts =
maplist( map p, parts,
``{
if( size(mp)==0 || contains( mp, p["mount"]:"") )
{
foreach( string s, rems,
``{
if( haskey( p, s ))
p = remove( p, s );
});
}
return( p );
});
return( parts );
}
list<map> remove_one_partition( list<map> partitions )
{
list<map> pl = filter( map p, partitions,
``( p["linux"]:false && size(p["mount"]:"")==0 &&
!p["delete"]:false ));
if( size(pl)>0 )
{
pl = sort( map a, map b, pl,
``(a["size_k"]:0>b["size_k"]:0));
pl = (list<map>) union(
filter( map p, pl, ``(p["used_by_type"]:`UB_NONE==`UB_NONE) ),
filter( map p, pl, ``(p["used_by_type"]:`UB_NONE!=`UB_NONE) ));
partitions =
maplist( map p, partitions,
``{
if( p["linux"]:false && !p["delete"]:false &&
size(p["mount"]:"")==0 &&
p["device"]:""==pl[0,"device"]:"" )
{
p["delete"] = true;
y2milestone( "remove_one_partition p %1", p );
}
return( p );
});
partitions = try_remove_sole_extended( partitions );
}
return( partitions );
}
list<map> remove_one_partition_vm( map disk )
{
list<map> partitions = disk["partitions"]:[];
list<map> pl = filter( map p, partitions,
``( p["linux"]:false && size(p["mount"]:"")==0 &&
!p["delete"]:false ));
if( size(pl)>0 )
{
pl = sort( map a, map b, pl,
``(a["size_k"]:0<b["size_k"]:0));
pl = (list<map>) union(
filter( map p, pl, ``(p["type"]:`primary==`logical) ),
filter( map p, pl, ``(p["type"]:`primary!=`logical) ));
pl = (list<map>) union(
filter( map p, pl, ``(p["used_by_type"]:`UB_NONE==`UB_NONE) ),
filter( map p, pl, ``(p["used_by_type"]:`UB_NONE!=`UB_NONE) ));
y2milestone( "remove_one_partition_vm pl %1", pl );
integer nr = 0;
partitions =
maplist( map p, partitions,
``{
if( p["linux"]:false && !p["delete"]:false &&
size(p["mount"]:"")==0 &&
p["device"]:""==pl[0,"device"]:"" )
{
p["delete"] = true;
nr = p["nr"]:0;
y2milestone( "remove_one_partition_vm p %1", p );
}
return( p );
});
if( nr>disk["max_primary"]:4 )
{
partitions =
maplist( map p, partitions,
``{
if( !p["delete"]:false && p["nr"]:0>nr )
{
p["nr"] = p["nr"]:0-1;
p["device"] = Storage::GetDeviceName( disk["device"]:"",
p["nr"]:0 );
y2milestone( "remove_one_partition_vm ren %1", p );
}
return( p );
});
}
partitions = try_remove_sole_extended( partitions );
}
return( partitions );
}
map remove_used_by( map tg, string disk )
{
string uby = tg[disk,"used_by"]:"";
y2milestone( "remove_used_by disk %1 uby %2", disk, uby );
if( size(uby)>0 )
{
string k = "/dev/"+uby;
if( haskey( tg, k ))
{
tg[k,"delete"] = true;
y2milestone( "remove_used_by uby %1", tg[k]:$[] );
}
}
return( tg );
}
map get_inst_proposal( map<string,map> target )
{
y2milestone( "get_inst_proposal start" );
map ret = $[];
target = Storage::AddWinInfo(target);
ret["target"] = target;
map root = $[ "mount" : "/", "increasable" : true,
"fsys" : Partitions::DefaultFs(), "size" : 0 ];
map opts = Storage::GetControlCfg();
list<string> ddev = get_disk_try_list( target, true );
string sol_disk = "";
list modes = [ `free, `reuse, `remove, `resize, `desparate ];
map<string,boolean> valid = $[];
map<string,list> size_mb = listmap( string s, ddev, ``($[s:[]]));
map solution = listmap( string s, ddev, ``($[s:[]]));
target = prepare_part_lists( ddev, target );
symbol mode = `free;
while( mode != `end && size(sol_disk)==0 )
{
if( mode == `free || mode == `desparate )
{
valid = listmap( string s, ddev, ``($[s:true]));
if( mode == `desparate )
{
ddev = get_disk_try_list( target, false );
valid = listmap( string s, ddev, ``($[s:true]));
target = prepare_part_lists( ddev, target );
foreach( string s, ddev,
``{
target[s,"partitions"] =
remove_p_settings( target[s,"partitions"]:[], [] );
target[s,"partitions"] =
maplist( map p, target[s,"partitions"]:[],
``{
if( !contains( Partitions::do_not_delete,
p["fsid"]:0 ))
{
if( usable_for_win_resize(p,false) )
p["dtxt"] = _("Resize impossible due to inconsistent fs. Try checking fs under Windows.");
p["delete"] = true;
}
return( p );
});
});
}
}
else if( mode == `reuse || mode == `remove )
{
valid = listmap( string s, ddev,
``{
if( find( map p, target[s,"partitions"]:[],
``(p["linux"]:false && size(p["mount"]:"")==0 &&
!p["delete"]:false)) != nil )
return( $[s:true] );
else
return( $[s:false] );
});
if( mode == `remove )
{
foreach( string s, ddev,
``{
target[s,"partitions"] =
remove_p_settings( target[s,"partitions"]:[],
["/", "/home"] );
});
foreach( string s, filter( string d, ddev, ``(valid[d]:false)),
``{
target[s,"partitions"] =
remove_one_partition( target[s,"partitions"]:[] );
});
}
}
else if( mode == `resize )
{
valid = listmap( string s, ddev,
``{
if( find( map p, target[s,"partitions"]:[],
``(usable_for_win_resize(p,true))) != nil )
return( $[s:true] );
else
return( $[s:false] );
});
foreach( string s, filter( string d, ddev, ``(valid[d]:false)),
``{
list<map> pl = filter( map p, target[s,"partitions"]:[],
``(usable_for_win_resize(p,true)));
if( size(pl)>0 )
{
pl = sort( map a, map b, pl,
``(a["size_k"]:0>b["size_k"]:0));
target[s,"partitions"] =
maplist( map p, target[s,"partitions"]:[],
``{
if( usable_for_win_resize(p,true) &&
p["device"]:""==pl[0,"device"]:"" )
{
integer cs = target[s,"cyl_size"]:1;
p["resize"] = true;
p["region",1] =
(p["winfo","new_size"]:0+cs-1) / cs;
p["win_max_length"] =
(p["winfo","max_win_size"]:0+cs-1) / cs;
}
return( p );
});
y2milestone( "get_inst_proposal res parts %1",
target[s,"partitions"]:[] );
}
});
}
y2milestone( "get_inst_proposal mode %1 valid %2", mode, valid );
foreach( string s, filter( string d, ddev, ``(valid[d]:false)),
``{
map conf = $[ "partitions" : [] ];
map disk = target[s]:$[];
list<map> p = can_boot_reuse( s, disk["label"]:"msdos",
need_boot(disk),
disk["max_primary"]:4,
disk["partitions"]:[] );
disk["partitions"] =
special_boot_proposal_prepare( disk["partitions"]:[] );
boolean have_home = false;
boolean have_root = false;
boolean have_boot = (!Arch::ia64()||mode!=`free) && size(p)>0;
if( have_boot )
disk["partitions"] = p;
map r = can_swap_reuse( s, disk["partitions"]:[], target );
boolean have_swap = size(r)>0;
if( haskey( r, "partitions" ))
disk["partitions"] = r["partitions"]:[];
else if( haskey( r, "targets" ))
target = r["targets"]:$[];
list swap_sizes = [];
integer avail_size = get_usable_size_mb(disk,mode==`reuse);
y2milestone( "get_inst_proposal disk %1 mode %2 avail %3",
s, mode, avail_size );
if( avail_size>0 )
{
if( mode == `reuse )
{
list<map> parts = disk["partitions"]:[];
if( Storage::ProposalHome() )
{
if( avail_size > opts["home_limit"]:0 )
parts = can_mp_reuse( "/home", 4*1024, 0, parts );
else
parts = can_mp_reuse( "/", opts["root_base"]:0, 0,
parts );
}
if( size(parts)>0 && avail_size > opts["home_limit"]:0 )
{
integer mx = 0;
if( Storage::ProposalHome() )
mx = opts["root_max"]:0;
parts = can_mp_reuse( "/", opts["root_base"]:0,
mx, parts );
}
if( size(parts)>0 )
{
have_home = avail_size > opts["home_limit"]:0;
have_root = true;
disk["partitions"] = parts;
}
y2milestone( "get_inst_proposal reuse have_home %1 have_root %2",
have_home, have_root );
if( have_home && have_root )
y2milestone( "get_inst_proposal reuse parts %1",
disk["partitions"]:[] );
}
if( !have_swap )
{
swap_sizes = get_swap_sizes( avail_size );
map swap = $[ "mount" : "swap", "increasable" : true,
"fsys" : `swap, "maxsize" : 2*1024*1024*1024,
"size" : swap_sizes[0]:256*1024*1024 ];
conf["partitions"] = add( conf["partitions"]:[], swap );
}
if( !have_root )
conf["partitions"] = add( conf["partitions"]:[], root );
map old_root = $[];
if( !have_home && Storage::ProposalHome() &&
opts["home_limit"]:0 < avail_size )
{
map home = $[ "mount" : "/home", "increasable" : true,
"fsys" : Partitions::DefaultFs(),
"size" : 512*1024*1024,
"pct" : 100-opts["root_percent"]:40 ];
conf["partitions"] =
maplist( map p, conf["partitions"]:[],
``{
if( p["mount"]:""=="/" )
{
old_root = p;
p["pct"] = opts["root_percent"]:40;
p["maxsize"] = opts["root_max"]:0*1024*1024;
p["size"] = opts["root_base"]:0*1024*1024;
}
return( p );
});
conf["partitions"] = add( conf["partitions"]:[], home );
}
map ps1 = do_flexible_disk_conf( disk, conf, have_boot,
mode==`reuse );
if( size(old_root)>0 && !ps1["ok"]:false )
{
conf["partitions"] =
filter( map p, conf["partitions"]:[],
``(p["mount"]:""!="/home" &&
p["mount"]:""!="/"));
conf["partitions"] = add( conf["partitions"]:[], old_root );
ps1 = do_flexible_disk_conf( disk, conf, have_boot,
mode==`reuse );
}
if( !have_swap )
{
integer diff = swap_sizes[0]:256 - swap_sizes[1]:256;
if( diff<0 )
diff = -diff;
y2milestone( "get_inst_proposal diff:%1 ps1 ok:%2",
diff, ps1["ok"]:false );
if( (!ps1["ok"]:false && diff>0) || diff>100 )
{
conf["partitions",0,"size"] =
swap_sizes[1]:256*1024*1024;
map ps2 = do_flexible_disk_conf( disk, conf, have_boot,
mode==`reuse );
y2milestone( "get_inst_proposal ps2 ok:%1",
ps2["ok"]:false );
if( ps2["ok"]:false )
{
map rp1 = find( map p, ps1["disk","partitions"]:[],
``(!p["delete"]:false &&
p["mount"]:""=="/"));
map rp2 = find( map p, ps2["disk","partitions"]:[],
``(!p["delete"]:false &&
p["mount"]:""=="/"));
y2milestone( "get_inst_proposal rp1:%1", rp1 );
y2milestone( "get_inst_proposal rp2:%1", rp2 );
if( rp1==nil ||
(rp2!=nil && rp2["size_k"]:0>rp1["size_k"]:0 ))
ps1 = ps2;
}
}
}
if( ps1["ok"]:false )
{
list mb = [ get_mb_sol( ps1, "/" )];
if( Storage::ProposalHome() )
mb = add( mb, get_mb_sol( ps1, "/home" ));
if( mb[0]:0+mb[1]:0 > size_mb[s,0]:0 + size_mb[s,1]:0 )
{
solution[s] = ps1["disk"]:$[];
size_mb[s] = mb;
y2milestone( "get_inst_proposal sol %1 mb %2",
s, size_mb[s]:[] );
}
}
}
});
integer max_mb = 0;
string max_disk = "";
foreach( string s, list mb, size_mb,
``{
if( (!Storage::ProposalHome() || mb[1]:0>0 || mode==`resize ) &&
mb[1]:0+mb[0]:0 > max_mb )
{
max_mb = mb[1]:0+mb[0]:0;
max_disk = s;
}
});
y2milestone( "max_mb %1 size_mb %2", max_mb, size_mb );
if( max_mb>0 && size_mb[max_disk,0]:0 > 2*1024 &&
( !Storage::ProposalHome() || size_mb[max_disk,1]:0 > 1*1024 ))
{
sol_disk = max_disk;
}
y2milestone( "get_inst_proposal mode %1 size_mb %2", mode, size_mb );
if( size(sol_disk)==0 )
{
list<boolean> lb = maplist(string s, boolean e, valid, ``(e));
if( mode == `free )
mode = `reuse;
else if( mode == `reuse )
mode = `remove;
else if( mode == `remove && find( boolean v, lb, ``(v)) == nil )
mode = `resize;
else if( mode == `resize && find( boolean v, lb, ``(v)) == nil )
mode = `desparate;
else if( mode == `desparate )
mode = `end;
if( mode == `desparate && size(sol_disk)==0 )
{
max_mb = 0;
foreach( string s, list mb, size_mb,
``{
if( mb[1]:0+mb[0]:0 > max_mb &&
size_mb[max_disk,0]:0 > 2*1024 )
{
max_mb = mb[1]:0+mb[0]:0;
sol_disk = s;
}
});
y2milestone( "get_inst_proposal mode %1 sol_disk %2",
mode, sol_disk );
}
}
}
y2milestone( "get_inst_proposal sol_disk %1", sol_disk );
if( size(sol_disk)==0 )
{
integer max_mb = 0;
foreach( string s, list mb, size_mb,
``{
if( mb[1]:0+mb[0]:0>max_mb )
{
max_mb = mb[1]:0+mb[0]:0;
sol_disk = s;
}
});
y2milestone( "get_inst_proposal sol_disk %1", sol_disk );
}
ret["ok"] = size(sol_disk)>0;
if( ret["ok"]:false )
{
ret["target"] = remove_used_by( ret["target"]:$[], sol_disk );
ret["target",sol_disk] = solution[sol_disk]:$[];
ret["target"] = Storage::SpecialBootHandling( ret["target"]:$[] );
y2milestone( "get_inst_proposal sol:%1", ret["target",sol_disk]:$[] );
}
y2milestone( "get_inst_proposal ret[ok]:%1", ret["ok"]:false );
return( ret );
}
list<map> remove_keys( list<map> pl, list<string> keys )
{
pl = maplist( map p, pl,
``{
foreach( string k, keys,
``{
if( haskey(p,k) )
p = remove( p, k );
});
return( p );
});
return( pl );
}
map<string,map> remove_mount_points( map<string,map> target )
{
foreach( string s, map disk, target,
``{
target[s,"partitions"] = remove_keys( target[s,"partitions"]:[],
[ "mount" ] );
});
return( target );
}
map<string,map> remove_vm( map<string,map> tg, string ky )
{
y2milestone( "remove_vm key:%1", ky );
string key = "/dev/" + ky;
if( haskey( tg, key ))
{
tg[key,"delete"] = true;
tg[key,"partitions"] =
maplist( map p, tg[key,"partitions"]:[],
``{
p["delete"] = true;
return(p);
});
y2milestone( "remove_vm removed:%1", tg[key]:$[] );
list<string> dl = tg[key,"devices"]:[];
foreach( string d, dl,
``{
tg = Storage::DelPartitionData( tg, d, "used_by" );
tg = Storage::DelPartitionData( tg, d, "used_by_type" );
});
}
if( haskey( tg, "/dev/evms/lvm/"+ky ) || haskey( tg, "/dev/evms/lvm2/"+ky ))
{
if( haskey( tg, "/dev/evms/lvm/"+ky ) && tg[key,"lvm2"]:false )
{
key = "/dev/evms/lvm/"+ky;
tg[key,"delete"] = true;
tg[key,"partitions"] =
maplist( map p, tg[key,"partitions"]:[],
``{
p["delete"] = true;
return(p);
});
y2milestone( "remove_vm removed:%1", tg[key]:$[] );
list<string> dl = tg[key,"devices"]:[];
foreach( string d, dl,
``{
tg = Storage::DelPartitionData( tg, d, "used_by" );
tg = Storage::DelPartitionData( tg, d, "used_by_type" );
});
}
if( haskey( tg, "/dev/evms/lvm2/"+ky ) && !tg[key,"lvm2"]:false )
{
key = "/dev/evms/lvm2/"+ky;
tg[key,"delete"] = true;
tg[key,"partitions"] =
maplist( map p, tg[key,"partitions"]:[],
``{
p["delete"] = true;
return(p);
});
y2milestone( "remove_vm removed:%1", tg[key]:$[] );
list<string> dl = tg[key,"devices"]:[];
foreach( string d, dl,
``{
tg = Storage::DelPartitionData( tg, d, "used_by" );
tg = Storage::DelPartitionData( tg, d, "used_by_type" );
});
}
}
return( tg );
}
string find_vm( map<string,map> target, string ky, integer min_size )
{
string ret = "";
string key = "/dev/" + ky;
string key2 = "/dev/evms/lvm2/" + ky;
if( Storage::ProposalLvm() && target[key,"lvm2"]:false &&
target[key,"size_k"]:0 >= min_size )
ret = key;
else if( Storage::ProposalEvms() && haskey( target, key2 ) &&
target[key2,"size_k"]:0 >= min_size )
ret = key2;
y2milestone( "find_vm key:%1 min_size:%2 ret:%3", ky, min_size, ret );
return( ret );
}
boolean did_remove_vg( list<map> partitions, string vg )
{
boolean ret=false;
list<string> ele = [ vg, "lvm/"+vg, "lvm2/"+vg ];
foreach( map p, partitions,
``{
if( !ret && p["delete"]:false && contains( ele, p["used_by"]:"" ))
ret = true;
});
y2milestone( "did_remove_vg vg:%1 ret:%2", vg, ret );
return( ret );
}
integer sizek_to_pe( integer pek, integer pebyte, boolean pvcreate )
{
integer ret = (pek-(pvcreate?500:0)) / (pebyte/1024);
y2milestone( "sizek_to_pe pek %1 pebyte %2 pvcreate %3 ret %4",
pek, pebyte, pvcreate, ret );
return( ret );
}
integer pe_to_sizek( integer pe, integer pebyte )
{
integer ret = pe * (pebyte/1024);
y2milestone( "pe_to_sizek pe %1 pebyte %2 ret %3", pe, pebyte, ret );
return( ret );
}
map extend_vm( map vg, string key, map disk )
{
y2milestone( "extend_vm key %1 vg %2", key, vg );
y2milestone( "extend_vm disk %1", disk );
list devs = [];
integer num_pe = vg["pe_free"]:0;
foreach( map p, disk["partitions"]:[],
``{
if( p["vg"]:""==key )
{
devs = add( devs, p["device"]:"" );
num_pe = num_pe +
sizek_to_pe( p["size_k"]:0, vg["pesize"]:1024, true );
};
});
y2milestone( "extend_vm num_pe %1 devs %2", num_pe, devs );
vg["devices_add"] = devs;
vg["pe_free"] = num_pe;
vg["size_k"] = pe_to_sizek( num_pe, vg["pesize"]:0 );
y2milestone( "extend_vm ret %1", vg );
return( vg );
}
map create_vm( boolean evms, string key, map disk )
{
y2milestone( "create_vm evms %1 key %2 disk %3", evms, key, disk );
map ret = $[ "type" : evms?`CT_EVMS:`CT_LVM,
"name" : evms?"lvm2/"+key:key,
"device" : "/dev/"+(evms?"evms/lvm2/":"")+key,
"lvm2" : true,
"create" : true,
"partitions" : [],
"pesize" : 4*1024*1024 ];
list devs = [];
integer num_pe = 0;
foreach( map p, disk["partitions"]:[],
``{
if( p["vg"]:""==key && !p["delete"]:false )
{
devs = add( devs, p["device"]:"" );
num_pe = num_pe +
sizek_to_pe( p["size_k"]:0, ret["pesize"]:1024, true );
};
});
y2milestone( "create_vm num_pe %1 devs %2", num_pe, devs );
ret["devices_add"] = devs;
ret["pe_free"] = num_pe;
ret["size_k"] = pe_to_sizek( num_pe, ret["pesize"]:0 );
y2milestone( "create_vm ret %1", ret );
return( ret );
}
integer round_mb_pe( integer mb, integer pebyte )
{
integer pek = pebyte/1024;
if( pek<1 )
pek = 1;
integer ret = (mb*1024 + pek-1) / pek * pek;
if( ret==0 )
ret=1;
y2milestone( "round_mb_pe mb %1 pebyte %2 ret %3", mb, pebyte, ret );
return( ret );
}
map modify_vm( map vm, map opts, boolean need_swap )
{
y2milestone( "modify_vm swap %1 start %2", need_swap, vm );
y2milestone( "modify_vm opts %1", opts );
map ret = vm;
integer free = ret["pe_free"]:0;
integer pe = ret["pesize"]:1024;
integer swsize = 0;
list swlist = [];
if( need_swap )
{
swlist = get_swap_sizes( free );
swsize = (swlist[1]:0>swlist[0]:0) ? swlist[1]:0 : swlist[0]:0;
}
y2milestone( "modify_vm swsize %1", swsize );
map swap = find( map p, ret["partitions"]:[], ``(p["name"]:""=="swap"));
map root = find( map p, ret["partitions"]:[], ``(p["name"]:""=="root"));
map home = find( map p, ret["partitions"]:[], ``(p["name"]:""=="home"));
y2milestone( "modify_vm swap %1 root %2 home %3", swap, root, home );
if( root!=nil && root["size_k"]:0<1024*1024 )
{
ret["partitions"] = maplist( map p, ret["partitions"]:[],
``{
if( p["name"]:"" == "root" )
{
p["delete"] = true;
free = free + sizek_to_pe( p["size_k"]:0, pe, false );
y2milestone( "modify_vm remove root %1", p );
}
return(p);
});
y2milestone( "modify_vm pe free %1", free );
root = nil;
}
ret["partitions"] = sort( map a, map b, ret["partitions"]:[],
``(a["size_k"]:0>b["size_k"]:0));
list keep = [ "root", "home", "swap" ];
integer root_pe = sizek_to_pe( opts["root_base"]:0*1024, pe, false );
y2milestone( "modify_vm pe free %1 root %2", free, root_pe );
map m = find( map p, ret["partitions"]:[],
``(!p["delete"]:false && !contains(keep,p["name"]:"")));
while( root==nil && free<root_pe && m!=nil )
{
ret["partitions"] = maplist( map p, ret["partitions"]:[],
``{
if( p["name"]:"" == m["name"]:"" )
{
p["delete"] = true;
free = free + sizek_to_pe( p["size_k"]:0, pe, false );
}
return(p);
});
y2milestone( "modify_vm pe free %1 root %2 del %3", free, root_pe, m );
m = find( map p, ret["partitions"]:[],
``(!p["delete"]:false && !contains(keep,p["name"]:"")));
}
if( root==nil && free<root_pe && swap!=nil && swsize==0 )
{
ret["partitions"] = maplist( map p, ret["partitions"]:[],
``{
if( p["name"]:"" == "swap" )
{
p["delete"] = true;
free = free + sizek_to_pe( p["size_k"]:0, pe, false );
}
return(p);
});
swap = nil;
y2milestone( "modify_vm pe free %1 root %2", free, root_pe );
}
if( root==nil && free<root_pe && swsize>0 )
{
swsize = (swlist[1]:0<swlist[0]:0) ? swlist[1]:0 : swlist[0]:0;
y2milestone( "modify_vm new swsize %1", swsize );
}
if( root==nil && free<root_pe && swap!=nil && swsize<swap["size_k"]:0/1024 )
{
ret["partitions"] = maplist( map p, ret["partitions"]:[],
``{
if( p["name"]:"" == "swap" )
{
p["delete"] = true;
free = free + sizek_to_pe( p["size_k"]:0, pe, false );
}
return(p);
});
swap = nil;
y2milestone( "modify_vm pe free %1 root %2", free, root_pe );
}
integer swap_pe = 0;
integer home_pe = 0;
if( swap==nil && swsize>0 )
swap_pe = sizek_to_pe( swsize*1024, pe, false );
if( free<root_pe+swap_pe )
{
y2milestone( "modify_vm pe free %1 root %2 swap %3",
free, root_pe, swap_pe );
if( root==nil && swap_pe>free )
{
swap_pe = free;
free = 0;
}
else if( swap_pe==0 )
{
root_pe = free;
free = 0;
}
else
{
swap_pe = swap_pe*free/(root_pe+swap_pe);
root_pe = free-swap_pe;
free = 0;
}
y2milestone( "modify_vm pe free %1 root %2 swap %3",
free, root_pe, swap_pe );
}
else
{
free = free-swap_pe;
y2milestone( "modify_vm pe free %1 root %2 swap %3",
free, root_pe, swap_pe );
if( home==nil && Storage::ProposalHome() &&
free>sizek_to_pe( opts["home_limit"]:0*1024, pe, false ) )
{
integer tmp = free * opts["root_percent"]:40 / 100;
if( tmp>root_pe )
root_pe=tmp;
tmp = sizek_to_pe( opts["root_max"]:0*1024, pe, false );
if( root_pe>tmp )
root_pe=tmp;
free = free-root_pe;
home_pe = free;
tmp = sizek_to_pe( opts["home_max"]:0*1024, pe, false );
if( home_pe>tmp )
home_pe = tmp;
free = free-home_pe;
y2milestone( "modify_vm pe free %1 root %2 home %3",
free, root_pe, home_pe );
}
else
{
integer tmp = sizek_to_pe( opts["root_max"]:0*1024, pe, false );
root_pe = free;
if( root_pe>tmp )
root_pe=tmp;
free = free-root_pe;
}
}
y2milestone( "modify_vm pe free %1 root %2 swap %3 home %4",
free, root_pe, swap_pe, home_pe );
if( root==nil && root_pe>0 )
{
map p = $[ "create":true, "name" : "root",
"format":true, "used_fs" : Partitions::DefaultFs(),
"device" : ret["device"]:"" + "/root",
"mount" : "/",
"size_k" : pe_to_sizek(root_pe,pe) ];
p["fstopt"] = FileSystems::DefaultFstabOptions( p );
p["fs_options"] = FileSystems::DefaultFormatOptions( p );
y2milestone( "modify_vm created %1", p );
ret["partitions"] = add( ret["partitions"]:[], p );
}
else if( root!=nil )
{
ret["partitions"] = maplist( map p, ret["partitions"]:[],
``{
if( p["name"]:"" == "root" )
{
p["mount"] = "/";
p["format"] = true;
if( p["detected_fs"]:`unknown==`unknown )
{
p["used_fs"] = Partitions::DefaultFs();
}
p["fstopt"] = FileSystems::DefaultFstabOptions( p );
p["fs_options"] = FileSystems::DefaultFormatOptions( p );
y2milestone( "modify_vm reuse %1", p );
}
return(p);
});
}
if( swap==nil && swap_pe>0 )
{
map p = $[ "create":true, "name" : "swap",
"format":true, "used_fs" : `swap,
"device" : ret["device"]:"" + "/swap",
"mount" : "swap",
"size_k" : pe_to_sizek(swap_pe,pe) ];
p["fstopt"] = FileSystems::DefaultFstabOptions( p );
p["fs_options"] = FileSystems::DefaultFormatOptions( p );
y2milestone( "modify_vm created %1", p );
ret["partitions"] = add( ret["partitions"]:[], p );
}
else if( swap!=nil )
{
ret["partitions"] = maplist( map p, ret["partitions"]:[],
``{
if( p["name"]:"" == "swap" )
{
p["mount"] = "swap";
if( p["detected_fs"]:`unknown!=`swap )
{
p["format"] = true;
p["used_fs"] = `swap;
p["fs_options"] = FileSystems::DefaultFormatOptions( p );
}
p["fstopt"] = FileSystems::DefaultFstabOptions( p );
y2milestone( "modify_vm reuse %1", p );
}
return(p);
});
}
if( home==nil && home_pe>0 )
{
map p = $[ "create":true, "name" : "home",
"format":true, "used_fs" : Partitions::DefaultFs(),
"device" : ret["device"]:"" + "/home",
"mount" : "/home",
"size_k" : pe_to_sizek(home_pe,pe) ];
p["fstopt"] = FileSystems::DefaultFstabOptions( p );
p["fs_options"] = FileSystems::DefaultFormatOptions( p );
y2milestone( "modify_vm created %1", p );
ret["partitions"] = add( ret["partitions"]:[], p );
}
else if( home!=nil )
{
ret["partitions"] = maplist( map p, ret["partitions"]:[],
``{
if( p["name"]:"" == "home" )
{
p["mount"] = "/home";
if( p["detected_fs"]:`unknown==`unknown )
{
p["format"] = true;
p["used_fs"] = Partitions::DefaultFs();
p["fs_options"] = FileSystems::DefaultFormatOptions( p );
}
p["fstopt"] = FileSystems::DefaultFstabOptions( p );
y2milestone( "modify_vm reuse %1", p );
}
return(p);
});
}
y2milestone( "modify_vm ret %1", ret );
return( ret );
}
map get_inst_prop_vm( map<string,map> target, string key )
{
y2milestone( "get_inst_prop_vm start key %1", key );
map ret = $[];
map opts = Storage::GetControlCfg();
string vg_key = find_vm( target, key, opts["root_base"]:0*1024 );
target = remove_mount_points(target);
if( size(vg_key)==0 )
target = remove_vm(target,key);
target = Storage::AddWinInfo(target);
ret["target"] = target;
map boot = $[ "mount" : Partitions::BootMount(),
"size" : Partitions::MinimalNeededBootsize(),
"fsys" : Partitions::DefaultBootFs(),
"id" : Partitions::FsidBoot(),
"max_cyl" : Partitions::BootCyl() ];
if( Partitions::BootPrimary() )
{
boot["primary"] = true;
}
list<string> ddev = get_disk_try_list( target, true );
string sol_disk = "";
list modes = [ `free, `remove, `resize, `desparate ];
map<string,boolean> valid = $[];
map<string,integer> size_mb = listmap( string s, ddev, ``($[s:0]));
map<string,boolean> keep_vg = $[];
map solution = listmap( string s, ddev, ``($[s:[]]));
target = prepare_part_lists( ddev, target );
symbol mode = `free;
while( mode != `end && size(sol_disk)==0 )
{
if( mode == `free || mode == `desparate )
{
valid = listmap( string s, ddev, ``($[s:true]));
if( mode == `desparate )
{
ddev = get_disk_try_list( target, false );
valid = listmap( string s, ddev, ``($[s:true]));
target = prepare_part_lists( ddev, target );
foreach( string s, ddev,
``{
target[s,"partitions"] =
remove_p_settings( target[s,"partitions"]:[], [] );
target[s,"partitions"] =
maplist( map p, target[s,"partitions"]:[],
``{
if( !contains( Partitions::do_not_delete,
p["fsid"]:0 ))
{
if( usable_for_win_resize(p,false) )
p["dtxt"] = _("Resize impossible due to inconsistent fs. Try checking fs under Windows.");
p["delete"] = true;
}
return( p );
});
});
}
}
else if( mode == `remove )
{
valid = listmap( string s, ddev,
``{
if( find( map p, target[s,"partitions"]:[],
``(p["linux"]:false && size(p["mount"]:"")==0 &&
!p["delete"]:false)) != nil )
return( $[s:true] );
else
return( $[s:false] );
});
foreach( string s, filter( string d, ddev, ``(valid[d]:false)),
``{
target[s,"partitions"] =
remove_one_partition_vm( target[s]:$[] );
});
}
else if( mode == `resize )
{
valid = listmap( string s, ddev,
``{
if( find( map p, target[s,"partitions"]:[],
``(usable_for_win_resize(p,true))) != nil )
return( $[s:true] );
else
return( $[s:false] );
});
foreach( string s, filter( string d, ddev, ``(valid[d]:false)),
``{
list<map> pl = filter( map p, target[s,"partitions"]:[],
``(usable_for_win_resize(p,true)));
if( size(pl)>0 )
{
pl = sort( map a, map b, pl,
``(a["size_k"]:0>b["size_k"]:0));
target[s,"partitions"] =
maplist( map p, target[s,"partitions"]:[],
``{
if( usable_for_win_resize(p,true) &&
p["device"]:""==pl[0,"device"]:"" )
{
integer cs = target[s,"cyl_size"]:1;
p["resize"] = true;
p["region",1] =
(p["winfo","new_size"]:0+cs-1) / cs;
p["win_max_length"] =
(p["winfo","max_win_size"]:0+cs-1) / cs;
}
return( p );
});
y2milestone( "get_inst_prop_vm res parts %1",
target[s,"partitions"]:[] );
}
});
}
y2milestone( "get_inst_prop_vm mode %1 valid %2", mode, valid );
foreach( string s, filter( string d, ddev, ``(valid[d]:false)),
``{
map disk = target[s]:$[];
map conf = $[ "partitions" : [] ];
list<map> p = can_boot_reuse( s, disk["label"]:"msdos", true,
disk["max_primary"]:4,
disk["partitions"]:[] );
disk["partitions"] =
special_boot_proposal_prepare( disk["partitions"]:[] );
boolean have_boot = size(p)>0;
if( have_boot )
disk["partitions"] = p;
string vg = vg_key;
if( size(vg)>0 && did_remove_vg( disk["partitions"]:[], key ))
vg = "";
map ps = do_vm_disk_conf( disk, have_boot?($[]):boot, vg, key );
if( ps["ok"]:false )
{
integer mb = get_vm_sol( ps );
if( mb-size_mb[s]:0>size_mb[s]:0/40 )
{
y2milestone( "get_inst_prop_vm new sol %1 old %2 new %3",
s, size_mb[s]:0, mb );
solution[s] = ps["disk"]:$[];
size_mb[s] = mb;
}
if( size(vg)>0 && !keep_vg[s]:false )
keep_vg[s] = true;
}
});
y2milestone( "get_inst_prop_vm size_mb %1 keep_vg %2",
size_mb, keep_vg );
integer max_mb = 0;
string max_disk = "";
string keep_disk = "";
foreach( string s, integer mb, size_mb,
``{
if( mb > max_mb )
{
max_mb = mb;
max_disk = s;
}
});
foreach( string s, boolean keep, keep_vg,
``{
if( size(keep_disk)==0 && keep )
{
keep_disk = s;
}
});
if( size(keep_disk)>0 )
{
sol_disk = keep_disk;
}
else if( max_mb>0 && size_mb[max_disk]:0 > opts["vm_want"]:(20*1024) )
{
sol_disk = max_disk;
vg_key = "";
}
y2milestone( "get_inst_prop_vm mode %1 sol_disk %2", mode, sol_disk );
if( size(sol_disk)==0 )
{
list<boolean> lb = maplist(string s, boolean e, valid, ``(e));
if( mode == `free )
mode = `remove;
else if( mode == `remove && find( boolean v, lb, ``(v)) == nil )
mode = `resize;
else if( mode == `resize && find( boolean v, lb, ``(v)) == nil )
mode = `desparate;
else if( mode == `desparate )
mode = `end;
}
}
y2milestone( "get_inst_prop_vm sol_disk %1", sol_disk );
if( size(sol_disk)==0 )
{
integer max_mb = 0;
foreach( string s, integer mb, size_mb,
``{
if( mb>max_mb )
{
max_mb = mb;
sol_disk = s;
}
});
y2milestone( "get_inst_prop_vm sol_disk %1", sol_disk );
}
ret["ok"] = size(sol_disk)>0;
if( ret["ok"]:false )
{
map r = can_swap_reuse( sol_disk, solution[sol_disk,"partitions"]:[],
ret["target"]:$[] );
if( haskey( r, "partitions" ))
solution[sol_disk,"partitions"] = r["partitions"]:[];
else if( haskey( r, "targets" ))
ret["target"] = r["targets"]:$[];
ret["target"] = remove_used_by( ret["target"]:$[], sol_disk );
if( size(vg_key)==0 )
{
vg_key = (Storage::ProposalEvms()?"/dev/evms/lvm2/":"/dev/")+key;
map vg = ret["target",vg_key]:$[];
vg = union( vg, create_vm( Storage::ProposalEvms(), key,
solution[sol_disk]:$[] ));
if( size(vg["devices"]:[])>0 )
{
vg = remove( vg, "devices" );
}
y2milestone( "get_inst_prop_vm vkey %1", vg );
ret["target",vg_key] = vg;
}
else
{
map vg = ret["target",vg_key]:$[];
vg = extend_vm( vg, key, solution[sol_disk]:$[] );
ret["target",vg_key] = vg;
}
ret["target",vg_key] = modify_vm( ret["target",vg_key]:$[], opts,
size(r)==0 );
ret["target",sol_disk] = solution[sol_disk]:$[];
ret["target"] = Storage::SpecialBootHandling( ret["target"]:$[] );
y2milestone( "get_inst_prop_vm sol:%1", ret["target",sol_disk]:$[] );
}
y2milestone( "get_inst_prop_vm ret[ok]:%1", ret["ok"]:false );
return( ret );
}
map get_proposal_vm( map<string,map> target, string key, map disk )
{
string ddev = disk["device"]:"";
y2milestone( "get_proposal_vm ddev:%1 vg:%2 evms:%3 lvm:%4 home:%5", ddev,
key, Storage::ProposalEvms(), Storage::ProposalLvm(),
Storage::ProposalHome() );
map ret = $[];
map opts = Storage::GetControlCfg();
target = remove_mount_points(target);
target = remove_vm(target,key);
ret["target"] = target;
map boot = $[ "mount" : Partitions::BootMount(),
"size" : Partitions::MinimalNeededBootsize(),
"fsys" : Partitions::DefaultBootFs(),
"id" : Partitions::FsidBoot(),
"max_cyl" : Partitions::BootCyl() ];
if( Partitions::BootPrimary() )
{
boot["primary"] = true;
}
map conf = $[ "partitions" : [] ];
list<map> p = can_boot_reuse( ddev, disk["label"]:"msdos", true,
disk["max_primary"]:4,
disk["partitions"]:[] );
disk["partitions"] = special_boot_proposal_prepare( disk["partitions"]:[] );
boolean have_boot = size(p)>0;
if( have_boot )
disk["partitions"] = p;
map ps = do_vm_disk_conf( disk, have_boot?($[]):boot, "", key );
ret["ok"] = ps["ok"]:false;
if( ret["ok"]:false )
{
disk = ps["disk"]:$[];
map r = can_swap_reuse( ddev, disk["partitions"]:[],
ret["target"]:$[] );
if( haskey( r, "partitions" ))
disk["partitions"] = r["partitions"]:[];
else if( haskey( r, "targets" ))
ret["target"] = r["targets"]:$[];
ret["target"] = remove_used_by( ret["target"]:$[], ddev );
string vg_key = (Storage::ProposalEvms()?"/dev/evms/lvm2/":"/dev/")+key;
map vg = ret["target",vg_key]:$[];
vg = union( vg, create_vm( Storage::ProposalEvms(), key, disk ));
if( size(vg["devices"]:[])>0 )
{
vg = remove( vg, "devices" );
}
y2milestone( "get_proposal_vm vkey %1", vg );
ret["target",vg_key] = modify_vm( vg, opts, size(r)==0 );
ret["target",ddev] = disk;
ret["target"] = Storage::SpecialBootHandling( ret["target"]:$[] );
y2milestone( "get_proposal_vm sol:%1", disk );
}
y2milestone( "get_proposal_vm ret[ok]:%1", ret["ok"]:false );
return( ret );
}
map get_inst_prop( map<string,map> target )
{
map ret = $[];
string vg = Storage::ProposalVM();
y2milestone( "get_inst_prop vg:%1 evms:%2 lvm:%3 home:%4", vg,
Storage::ProposalEvms(), Storage::ProposalLvm(),
Storage::ProposalHome() );
if( size(vg)==0 )
ret = get_inst_proposal( target );
else
{
if( Storage::ProposalEvms() &&
size(target["/dev/evms","partitions"]:[])==0 )
{
Storage::ActivateEvms();
target = Storage::GetTargetMap();
}
ret = get_inst_prop_vm( target, vg );
}
return( ret );
}
}