/**
 * Module: 		Storage.ycp
 *
 * Authors:		Johannes Buchhold (jbuch@suse.de)
 *
 * Purpose: 		These module contains all settings/information which
 * are needed to partitioning the harddisk. Futhermore it contains a interface
 * to * access and modify the partitioning settings.
 *
 * Todo: Translate
 * Diese Modul enthält alle Informationen die für die Partitionierung der
 * Festplatten erforderlich sind. Diese Informationen bestehen aus der
 * Beschreibung, der vor der Partitionierung vorhandenen Platteneinstellungen,
 * und der Art und Weise wie diese verändert werden soll.
 * Alle nötigen Zugriffsfunktionen auf diese Datenstruktur sind ebenfalls in
 * diesem Modul enthalten. Der Zugriff auf die Speicherung der
 * Partitionseinstellungen läuft * also nur über dieses Modul.
 * Der Zufriff und die Rückgabe von Teilen der Partitionsdatenstruktur
 * wurde versucht * "intelligent" zu gestallten und ist im einzelen bei den
 * entspechenden Funktionen * näher erklärt.
 *
 * $Id: Storage.ycp 22850 2005-03-30 09:54:08Z fehr $
 */
{

  module "Storage";
  textdomain "storage";

  import "Arch";
  import "AsciiFile";
  import "Encoding";
  import "Directory";
  import "FileSystems";
  import "Installation";
  import "Label";
  import "Mode";
  import "Partitions";
  import "Popup";
  import "Misc";
  import "StorageDevices";
  import "Stage";

global boolean DoCheckEvmsNonEvms = true;
global boolean DoCheckEvmsLvm = true;
map DiskMapVersion = $[];
map DiskMap = $[];

 /*
  include "storage/routines.ycp";
 */
  /**
   * Get Device Name
   * @param disk Disk
   * @param any partition
   * @return string device name
   */
global define string GetDeviceName( string disk, any partition )
    {
      string ret = disk;

      if( is( partition, integer ) )
	  {
  	  if( find( disk, "/dev/cciss/" )==0 ||
  	      find( disk, "/dev/ida/" )==0 ||
  	      find( disk, "/dev/ataraid/" )==0 ||
  	      find( disk, "/dev/etherd/" )==0 ||
  	      find( disk, "/dev/rd/" )==0 )
  	      {
  	      ret = ret + "p";
  	      }
  	  ret = ret + sformat( "%1", partition );
	  }
      else if( size( (string)partition )>0 )
          {
  	  ret = ret + "/" + (string)partition;
	  }
      return( ret );
  };


    /* Storage = TargetMap + modify_targets + classified_user_settings */
    /* Storage = $[ "targets" 			: $[],
                    "modify_targets" 		: $[],
		    "classified_user_settings" 	: $[],
		    "lvm_view_all_mnt"    	: true,
		    "whole_disk"    		: false,
		    "must_reread_partitions"   	: false,
		    "win_device"   		: false,
		    "raidtab_created"   	: false,
		    "use_lvm"   		: false,
		    "testsuite"   		: false,
		    "do_resize"    		: "",
		    "part_proposal_mode"        : "",
		    "part_proposal_first"       : true,
		    "focus"		       	: key
		    ]
    */

    global boolean immediate_prepdisk = false;
    global boolean ZeroNewPartitions = false;

    map  StorageMap	= $[];
    map<integer,map>  StorageMaps	= $[];

    /* stringkeys for access  to the Storage map */
    string lvm_view_all_mnt_key  	= "lvm_view_all_mnt";
    string targets_key 			= "targets";
    string targets_backup_key 		= "targets_backup";
    string targets_backup_l_key 	= "targets_l_backup";
    string targets_backup_m_key 	= "targets_m_backup";
    string part_mode_key 		= "part_mode";
    string part_disk_key  		= "part_disk";
    string whole_disk_key 		= "whole_disk";
    string raidtab_created_key 		= "raidtab_created";
    string testsuite_key       		= "testsuite";
    string do_resize_key 		= "do_resize";
    string win_device_key	 	= "win_device";
    string custom_display_key	 	= "custom_display";
    string part_proposal_mode_key	= "part_proposal_mode";
    string part_proposal_first_key	= "part_proposal_first";
    string part_proposal_active_key	= "part_proposal_active";
    string modify_targets_key		= "modify_targets";
    string classified_user_settings_key = "classified_user_settings";
    string use_lvm_key			= "use_lvm";

    string storage_map_key		= "storage_map";
    string storage_type_key     	= "storage_type";
    string storage_doc_key		= "storage_doc";
    symbol record_key			= `record;
    symbol custom_key			= `custom;
    boolean lvm_initialized             = false;
    boolean probe_done             	= false;
    symbol  exit_key               	= `next;
    boolean force_disk_probe            = false;

/**
*
*/
global define map GetDiskPartition( string device )
    ``{
    map ret = $[];
    integer dlen = 0;
    boolean as_string = false;

    if( find( device, "/dev/hd" )==0 ||
	find( device, "/dev/sd" )==0 ||
	find( device, "/dev/ed" )==0 ||
	find( device, "/dev/iseries/vd" )==0 )
	{
	dlen = findfirstof( device, "0123456789" );
	if( dlen == nil )
	    {
	    dlen = size(device);
	    }
	}
    else if( find( device, "/dev/md" )==0 )
	{
	dlen = 7;
	}
    else if( find( device, "/dev/loop" )==0 )
	{
	dlen = 9;
	}
    else if( find( device, "/dev/i2o/hd" )==0 )
	{
	dlen = 12;
	}
    else if( find( device, "/dev/rd/" )==0 ||
	     find( device, "/dev/cciss/" )==0 ||
	     find( device, "/dev/ataraid/" )==0 ||
	     find( device, "/dev/etherd/" )==0 ||
	     find( device, "/dev/ida/" )==0 )
	{
	integer pos = findlastof( device, "p" );
	dlen = size(device);
	if( pos!=nil )
	    {
	    dlen = pos;
	    }
	}
    else if( find( device, "/dev/dasd" )==0 )
	{
	dlen = size(device);
	if( findfirstof( device, "0123456789" )>0 )
	    {
	    dlen = dlen-1;
	    }
	}
    else
	{
	as_string = true;
	if( size( splitstring(device, "/"))>3 )
	    {
	    integer pos = findlastof( device, "/" );
	    if( pos!=nil )
		{
		dlen = pos;
		}
	    }
	else
	    {
	    dlen = size(device);
	    }
	}
    ret = add( ret, "disk", substring( device, 0, dlen ) );
    device = substring( device, dlen );
    if( size(device)>0 && findfirstof( device, "/p" )==0 )
	{
	device = substring( device, 1 );
	}
    ret["nr"] = 0;
    if( as_string )
	{
	ret["nr"] = device;
	}
    else
	{
	if( size(device)>0 )
	    {
	    ret["nr"] = tointeger(device);
	    }
	}
    if( size(ret["disk"]:"")>0 && ret["nr"]:(any)1 == 0 )
	{
	ret["nr"] = "";
	}
    return( ret );
    };



/* return partition <device> of map <tg> */
global define map<string,any> GetPartition( map<string,map> tg, string device )
    ``{
    map<string,any> ret = $[];
    map tmp = GetDiskPartition( device );
    string disk = tmp["disk"]:"";
    if( find(device, "/dev/evms")==0 && !haskey( tg, disk ) )
	{
	disk = "/dev/evms";
	}
    y2debug( "device=%1", device );
    list< map<string,any> > part = (list< map<string,any> >)
	filter( map<string, any> pi, tg[disk,"partitions"]:[],
	        ``(pi["device"]:""==device && !pi["delete"]:false));
    if( size(part)>=0 )
        {
	ret = part[0]:$[];
	}
    y2debug( "ret=%1", ret );
    return( ret );
    }


/* set <part>, return changed map <tg> */
global define map<string,map> SetPartition( map<string,map> tg, map part )
    ``{
    y2milestone( "SetPartition part=%1", part );
    map tmp = GetDiskPartition( part["device"]:"" );
    y2milestone( "SetPartition tmp=%1", tmp );
    string disk = tmp["disk"]:"";
    if( find(part["device"]:"", "/dev/evms")==0 && !haskey( tg, disk ) )
	{
	disk = "/dev/evms";
	}
    list r_part = filter(map p, tg[disk,"partitions"]:[],
			  ``(p["device"]:"" != part["device"]:"" ||
			     p["delete"]:false == true));
    r_part = add( r_part, part );
    tg[disk,"partitions"] = r_part;
    return( tg );
    }

/**
 * Find next free loop device.
 * @return string loop_dev ( e.g.: /dev/loop1 )
 */
global define string GetLoopDev( integer start )
    ``{
    if( Mode::test () )
	return "/dev/loop2";

    integer max_loop_dev= 15;
    integer loop_dev_nb = start;
    boolean found_free  = false;
    string  loop_dev    = "";

    while( !found_free && loop_dev_nb <= max_loop_dev )
	{
	loop_dev = sformat("/dev/loop%1", loop_dev_nb );
	loop_dev_nb = loop_dev_nb + 1;

	// Test loop dev
	if( SCR::Execute(.target.bash , "/sbin/losetup 2>/dev/null " + loop_dev ) != 0 )
	    found_free = true;
	}

    if( !found_free )
	{
	loop_dev = "";
	// internal error popup
	Popup::Error( _("Too many loop devices (cryptofs ...)") );
	y2error( "Too many loop devices");
	}

    y2milestone("ret \"%1\"",loop_dev);

    return( loop_dev );
    };

global define map<string,any> InitialLoopMaindev()
    ``{
    return( $[ "name"      : Partitions::loop_name,
	       "cyl_count" : 1,          // not used
	       "cyl_size"  : 1024*1024,  // size in MB
	       "partitions": []
	     ] );
    }

global define map<string,any> InitialLoopEntry()
    ``{
    map<string,any> part = $[ "type"     : `loop,
		  "loop_fs"  : true,
		  "fstype"   : Partitions::loop_name,
		  "fsid"     : Partitions::fsid_native,
		  "region"   : [ 0, 0 ]
		];
    return( part );
    }

 /**
 *
 */
global define map<string,map> GetLvmMdSystemInfo( map<string,map> targetMap )
    ``{
    map<string,map> md = (map<string,map>) SCR::Read (.md.config);
    y2debug( "md %1", md );
    if( size(md)>0 )
	{
	string key = "/dev/md";
	integer total_size = 0;
	map entry = $[];
	list partitions = [];
	entry["name"] = Partitions::raid_name;
	entry["cyl_size"] = 1024 * 1024;
	foreach (string pk, map pv, md, ``{
	    map part = $[];
	    integer lsize = 0;
	    y2debug ("key=%1 map=%2", pk, pv );
	    part["fsid"] = Partitions::fsid_native;
	    part["fstype"] = Partitions::raid_name;
	    lsize = pv["blocks"]:0 / 1024;
	    total_size = total_size + lsize;
	    list region = [0, lsize];
	    part["region"] = [0, lsize];
	    part["nr"] = tointeger(substring (pk, 7));
	    part["device"] = Storage::GetDeviceName( key, part["nr"]:(any)0 );
	    part["size_byte"] = pv["blocks"]:0 * 1024;
	    part = FileSystems::GetFsysInfos( part );
	    if( pv["chunk"]:0 >0 )
		{
		part["chunk_size"] = sformat("%1",pv["chunk"]:0);
		}
	    if( size(pv["parity_algorithm"]:"")>0 )
		{
		part["parity_algorithm"] = pv["parity_algorithm"]:"";
		}
	    part["persistent_superblock"] = pv["persistent_superblock"]:false;
	    part["raid_type"] = pv["raid_type"]:"";
	    part["type"] = `sw_raid;
	    y2debug ("key=%2 part=%1", part, pk);
	    partitions = add (partitions, part);
	    });
	entry["cyl_count"] = total_size;
	entry["partitions"] = partitions;
	targetMap[key] = entry;
	}
    foreach (string k, map v, md,
	``{
	integer dcnt = 0;
	list<string> devices = v["devices"]:[];
	integer spare = size(devices) - v["used_disks"]:size(devices);
	foreach(string e, devices,
	    ``{
	    map p = Storage::GetPartition( targetMap, e );
	    p["raid_name"] = k;
	    p["fsid"] = Partitions::fsid_raid;
	    p["fstype"] = Partitions::FsIdToString( p["fsid"]:0 );
	    targetMap = Storage::SetPartition( targetMap, p );
	    y2debug ("changed partition=%1", p);
	    });
	});
    map<string,map> lvm_vg = (map<string,map>) SCR::Read (.lvm.vg);
    y2debug( "lvm vg %1", lvm_vg );
    foreach (string k, map v, lvm_vg,
	``{
	string key = "/dev/" + k;
	map entry = $[];
	integer pesize = v["pesize"]:4096;
	list partitions = [];
	entry["is_lvm_vg"] = true;
	entry["name"] = k;
	entry["cyl_size"] = pesize * 1024;
	entry["cyl_count"] = v["blocks"]:0 / pesize;
	entry["lvm2"] = v["lvm2"]:false;
	y2debug ("key=%1 pesize=%2 map=%3", key, pesize, entry);
	foreach (string pk, map pv, v["lv"]:$[],
	    ``{
	    map part = $[];
	    part["fsid"] = Partitions::fsid_lvm;
	    part["fstype"] = "LV";
	    string name = substring (pk, (findlastof (pk, "/") + 1));
	    list region = [0, pv["blocks"]:0 / pesize];
	    part["region"] = region;
	    part["nr"] = name;
	    part["device"] = Storage::GetDeviceName( key, name );
	    part = FileSystems::GetFsysInfos( part );
	    part["type"] = `lvm;
	    y2debug ("key=%2 part=%1", part, pk);
	    partitions = add (partitions, part);
	    });
	entry["partitions"] = partitions;
	targetMap[key] = entry;
	});
    map<string,map> lvm_pv = filter(string k, map v, (map<string,map>) SCR::Read(.lvm.pv),
                         ``(size(v["vgname"]:"") > 0));
    y2debug( "lvm pv %1", lvm_pv );
    foreach(string k, map v, lvm_pv,
	``{
	map p = Storage::GetPartition( targetMap, k );
	p["lvm_group"] = v["vgname"]:"";
	p["lvm_mp_pv"] = v["multipath"]:false;
	p["lvm_size_bytes"] = (v["blocks"]:0) * 1024;
	p["fsid"] = Partitions::fsid_lvm;
	p["fstype"] = Partitions::FsIdToString( p["fsid"]:0 );
	targetMap = Storage::SetPartition( targetMap, p );
	});
    string evms_ag = "/usr/lib/YaST2/plugin/libpy2ag_evms.so.2";
    string evms64_ag = "/usr/lib64/YaST2/plugin/libpy2ag_evms.so.2";
    if( SCR::Read( .target.size, evms_ag )>=0 ||
        SCR::Read( .target.size, evms64_ag )>=0 )
	{
	list<map> cont = (list<map>) SCR::Read (.evms.container);
	foreach( map e, cont, 
	    ``{
	    string key = "/dev/evms/" + e["name"]:"";
	    map entry = $[];
	    integer pesize = e["pesize"]:4096/1024;
	    entry["is_evms"] = true;
	    entry["is_evms_container"] = true;
	    entry["name"] = e["name"]:"";
	    entry["cyl_size"] = pesize*1024;
	    entry["cyl_count"] = e["size"]:0 / pesize;
	    entry["cyl_free"] = e["free"]:0 / pesize;
	    entry["manager"] = e["type"]:"LvmRegMgr";
	    entry["consumes"] = e["consumes"]:[];
	    entry["partitions"] = [];
	    targetMap[key] = entry;
	    y2milestone ("GetLvmMdSystemInfo e=%1 key:%2 map=%3", e, key, entry);
	    });
	list<map> vol = (list<map>) SCR::Read (.evms.volume);
	foreach( map e, vol, 
	    ``{
	    integer pos = findlastof( e["device"]:"", "/" );
	    string key = substring( e["device"]:"", 0, pos );
	    y2milestone ("GetLvmMdSystemInfo key:%1", key );
	    if( !haskey( targetMap, key ) )
		{
		map entry = $[];
		entry["is_evms"] = true;
		entry["cyl_size"] = 1024*1024;
		entry["cyl_count"] = 0;
		entry["partitions"] = [];
		y2milestone ("GetLvmMdSystemInfo add entry key:%1", entry );
		targetMap[key] = entry;
		}
	    map part = $[];
	    part["fstype"] = "EVMS";
	    part["type"] = `evms;
	    part["device"] = e["device"]:"";
	    part["nr"] = substring (e["device"]:"", size(key)+1);
	    part["id"] = e["evms_id"]:-1;
	    if( e["native"]:false )
		{
		part["evms_native"] = true;
		}
	    list region = [0, e["size"]:0 / (targetMap[key,"cyl_size"]:1/1024)];
	    part["region"] = region;
	    part = FileSystems::GetFsysInfos( part );
	    y2milestone ("GetLvmMdSystemInfo part=%1", part);
	    if( part["evms_native"]:false || !regexpmatch( part["nr"]:"", "loop[0-9]*" ))
		{
		targetMap[key,"partitions"] = add( targetMap[key,"partitions"]:[], 
						   part );
		}
	    else
		{
		y2milestone( "skip %1", part["device"]:"" );
		}
	    });
	foreach( map e, vol, 
	    ``{
	    string cons = e["consumes",0]:"";
	    y2milestone( "GetLvmMdSystemInfo %1 consumes %2", e,  cons );
	    if( "/dev/evms/" + cons != e["device"]:"" )
		{
		string name = substring( e["device"]:"", 
					 findlastof( e["device"]:"", "/" )+1 );
		if( find( cons, "lvm/" ) == 0 )
		    cons = substring( cons, 4 );
		else if( find( cons, "aix/" ) == 0 )
		    cons = substring( cons, 4 );
		string dev = "/dev/" + cons;
		y2milestone( "GetLvmMdSystemInfo dev %1", dev );
		map p = Storage::GetPartition( targetMap, dev );
		if( size(p)>0 )
		    {
		    p["evms_vol"] = name;
		    targetMap = Storage::SetPartition( targetMap, p );
		    }
		dev = "/dev/evms/" + cons;
		p = Storage::GetPartition( targetMap, dev );
		if( size(p)>0 )
		    {
		    p["evms_vol"] = name;
		    targetMap = Storage::SetPartition( targetMap, p );
		    }
		}
	    });
	foreach( map e, cont, 
	    ``{
	    foreach( string dev, e["consumes"]:[],
		``{
		string name = e["name"]:""; 
		dev = "/dev/" + dev;
		map p = Storage::GetPartition( targetMap, dev );
		if( size(p)>0 )
		    {
		    p["evms_vol"] = name;
		    targetMap = Storage::SetPartition( targetMap, p );
		    }
		dev = "/dev/evms/" + dev;
		p = Storage::GetPartition( targetMap, dev );
		if( size(p)>0 )
		    {
		    p["evms_vol"] = name;
		    targetMap = Storage::SetPartition( targetMap, p );
		    }
		});
	    });
	}
    if( Mode::normal () )
	{
	SCR::UnmountAgent (.proc.mounts);
	list<map> mounts = (list<map>) SCR::Read(.proc.mounts);
	list<map> loop = [];
	list<map> tab = [];
	SCR::UnmountAgent (.etc.cryptotab);
	if( SCR::Read( .target.size, "/etc/cryptotab" ) > 0 )
	    tab = (list<map>) SCR::Read( .etc.cryptotab );
	foreach (map e, tab,
	    ``{
	    map v = $[];
	    v["device"] = e["file"]:"";
	    v["loop"] = e["loop"]:"";
	    v["used_fs"] = e["vfstype"]:"";
	    v["mount"] = e["mount"]:"";
	    v["crypt"] = e["opt1"]:"twofish";
	    loop = add( loop, v );
	    });
	y2milestone( "loop %1", loop );
	tab = [];
	SCR::UnmountAgent (.etc.fstab);
	if( SCR::Read( .target.size, "/etc/fstab" ) > 0 )
	    tab = (list<map>) SCR::Read( .etc.fstab );
	foreach (map e, tab,
	    ``{
	    map v = $[];
	    v["device"] = e["spec"]:"";
	    v["mount"] = e["file"]:"";
	    v["used_fs"] = e["vfstype"]:"";
	    list<string> opts = splitstring( e["mntops"]:"", "," );
	    boolean noauto = size(filter(string s, opts, ``(s=="noauto"))) > 0;
	    string lopt = filter(string s, opts, ``(find(s,"loop")==0) )[0]:"";
	    string algo = filter(string s, opts, ``(find(s,"encryption")==0))[0]:"";
	    y2milestone( "noauto:%1 lopt:%2 algo:%3", noauto, lopt, algo );
	    if( size(lopt)>0 )
		{
		list tm = splitstring( lopt, "=" );
		v["loop"] = tm[1]:"";
		if( size(v["loop"]:"")==0 )
		    {
		    map t = filter(map w, mounts,
				   ``(w["file"]:""==v["mount"]:""))[0]:$[];
		    v["loop"] = t["spec"]:"";
		    if( size(v["loop"]:"")==0 )
			{
			v["loop"] = GetLoopDev(0);
			}
		    }
		tm = splitstring( algo, "=" );
		v["crypt"] = tm[1]:"none";
		v["noauto"] = noauto;
		loop = add( loop, v );
		}
	    else if( noauto )
		{
		map p = Storage::GetPartition( targetMap, v["device"]:"" );
		if( size(p)>0 )
		    {
		    p["noauto"] = true;
		    targetMap = Storage::SetPartition( targetMap, p );
		    }
		}
	    });
	y2milestone( "loop %1", loop );
	foreach (map e, loop,
	    ``{
	    map stat = (map) SCR::Read( .target.stat, e["device"]:"" );
	    map p = $[];
	    y2milestone( "stat %1", stat );
	    y2milestone( "loop %1", e );
	    if( stat["isblock"]:false )
		{
		p = Storage::GetPartition( targetMap, e["device"]:"" );
		}
	    else if( stat["isreg"]:false )
		{
		if( size(targetMap["/dev/loop"]:$[])==0 )
		    {
		    targetMap["/dev/loop"] = InitialLoopMaindev();
		    }
		p = InitialLoopEntry();
		map tmp = GetDiskPartition( e["loop"]:"" );
		p["nr"] = tmp["nr"]:(any)0;
		p["device"] = e["loop"]:"";
		p["fpath"] = e["device"]:"";
		p["region",1] = (integer) SCR::Read( .target.size, e["device"]:"" ) /
				targetMap["/dev/loop","cyl_size"]:1;
		}
	    if( size(p)>0 )
		{
		p["loop_fs"] = true;
		p["crypt"] = e["crypt"]:"none";
		p["mount"] = e["mount"]:"";
		p["used_fs"] = FileSystems::FsToSymbol( e["used_fs"]:"" );
		if( e["noauto"]:false )
		    {
		    p["noauto"] = true;
		    }
		string loop = e["loop"]:"";
		if( size(loop)>0 )
		    {
		    p["loop_dev"] = loop;
		    p = FileSystems::GetFsysInfos( p );
		    }
		y2milestone( "p %1", p );
		targetMap = Storage::SetPartition( targetMap, p );
		}
	    });
	}
    return targetMap;
    };


global define void SetMdOn( boolean on )
    ``{
    y2milestone( "SetMdOn on %1", on );
    if( on )
	{
	SCR::Write( .md.activate, "" );
	SCR::Write( .lvm.activate, "" );
	}
    else
	{
	SCR::Write( .lvm.deactivate, "" );
	SCR::Write( .md.deactivate, "" );
	}
    y2milestone( "return" );
    }

/**
 * Reads LVM (vgscan ...) and MD data (/proc)
 */
global define map<string,map> ReadLvmMd( map<string,map> targetMap )
    ``{
    SCR::UnmountAgent(.md);
    targetMap = GetLvmMdSystemInfo( targetMap );
    if( Stage::initial ()  && !Mode::repair () )
	{
	SetMdOn( false );
	}
    return( targetMap );
    };

    /* GetFsysType()
     * detect type of filesystems with partition id 0x83
     *
     */
global define map<string,map> GetFsysType( map<string,map> target)
    ``{
    foreach( string device, map disk, target,
	``{
	list<map> partitions = disk["partitions"]:[];
	list p_new = [];
	foreach (map partition, partitions,
	    ``{
	    if( partition["used_fs"]:`none == `none )
		{
		partition = FileSystems::GetFsysInfos( partition );
		if( !contains( Partitions::no_windows, partition["fsid"]:0 ) &&
		    partition["used_fs"]:`unknown == `fat32 )
		    {
		    partition["fsid"] = Partitions::fsid_fat32;
		    partition["fstype"] =
			Partitions::FsIdToString( Partitions::fsid_fat32 );
		    }
		if( partition["used_fs"]:`none == `swap && Stage::initial () )
		    {
		    string cmd = sformat( "file -s %1", partition["device"]:"/dev/null" );
		    cmd = cmd + "| grep -q \"new style\"";
		    integer ret = (integer)SCR::Execute(.target.bash, cmd );
		    y2milestone( "cmd %1 ret %2", cmd, ret );
		    if( ret!=0 )
			{
			partition["old_swap"] = true;
			}
		    y2milestone( "partition %1", partition );
		    }
		}
	    p_new = add( p_new, partition );
	    });
	target[device,"partitions"] = p_new;
	});
    return target;
    }


/** 
 * Get List of swap partitions
 * @return list List of swap partitions
 */
global define list SwappingPartitions()``{
    list ret = [];
    SCR::UnmountAgent (.proc.swaps);
    list<map> swaps = filter(map e, (list<map>) SCR::Read( .proc.swaps ),
                         ``(e["type"]:""=="partition"));
    ret = maplist(map e, swaps, ``(e["file"]:"") );
    y2milestone( "SwappingPartitions %1", ret );
    return( ret );
    }

/**
 *
 * mark swap-partitions with pseudo Mountpoint swap in targetMap
 * @param target Disk map
 * @return map<string,map> modified target
 */
global define map<string,map> AddSwapMp( map<string,map> target )
    ``{
    list swaps = [];
    if( !Stage::initial () )
	swaps = SwappingPartitions();
    y2milestone( "AddSwapMp swaps %1", swaps );
    foreach(string diskdev, map disk, target,
	``{
	 disk["partitions"] = maplist(map part, disk["partitions"]:[],
				 ``{
				 if( (Stage::initial () &&
				      !disk["delete"]:false &&
				      !Partitions::IsDosWinNtPartition(part["fsid"]:0) &&
				      part["detected_fs"]:`unknown==`swap &&
				      !part["old_swap"]:false &&
				      find( diskdev, "/dev/evms" )!=0 ) ||
				     (!Stage::initial () &&
				      contains( swaps, part["device"]:"" )))
				     {
				     part["mount"] = "swap";
				     y2milestone( "AddSwapMp %1", part );
				     }
				 return( part );
				 });
	target[diskdev] = disk;
	});
    return( target );
    }

global define list GetDestroyedLvmVgs( map<string,map> target )
    ``{
    list vgs = [];
    foreach(string diskdev, map disk, target,
	``{
	foreach( map p, disk["partitions"]:[],
	    ``{
	    if( size(p["lvm_group"]:"")>0 &&
	        (p["delete"]:false || p["format"]:false) )
		{
		vgs = union( vgs, [ p["lvm_group"]:"" ] );
		}
	    });
	});
    vgs = sort( vgs );
    y2milestone( "GetDestroyedLvmVgs %1", vgs );
    return( vgs );
    }

global define map<string,map> DeleteDestroyedLvmVgs( map<string,map> target )
    ``{
    list<string> vgs = maplist( string s, (list<string>)GetDestroyedLvmVgs( target ), 
				``("/dev/"+s));
    y2milestone( "DeleteDestroyedLvmVgs %1", vgs );
    foreach( string dev, vgs,
	``{
	if( haskey( target, dev ))
	    target[dev,"delete"] = true;
	target[dev,"partitions"] = maplist( map p, target[dev,"partitions"]:[],
					    ``{ 
					    if( haskey( p, "mount" ))
						p = remove( p, "mount" ); 
					    return( p );
					    });
	y2milestone( "DeleteDestroyedLvmVgs %1: %2", dev, target[dev]:$[] );
	});
    return( target );
    }

global define map<string,map> AddWinInfo( map<string,map> targets )
    ``{
    y2milestone( "AddWinInfo called" );
    foreach(string disk, map data, targets,
	``{
	targets[disk,"partitions"] = 
	    maplist(map p, data["partitions"]:[],
		``{
		if( Partitions::IsDosWinNtPartition(p["fsid"]:0) &&
		    contains( [`fat32, `fat16, `ntfs ], p["used_fs"]:`none ))
		    {
		    symbol used_fs = `fat32;
		    if( p["used_fs"]:`none == `ntfs )
			{
			used_fs = `ntfs;
			}
		    p["winfo"] = FileSystems::GetFreeSpace( p["device"]:"", 0,
		                                            used_fs, false );
		    }
		return( p );
		});
	});
    return( targets );
    };

global define string SaveDumpPath( string name )``{
    string ret = Directory::tmpdir + "/" + name;
    y2debug( "name=%1 path=%2", name, ret );
    return ret;
    }

map lenc = $[ "el" : "iso8859-7",
              "hu" : "iso8859-2",
              "cs" : "iso8859-2",
              "hr" : "iso8859-2",
              "sl" : "iso8859-2",
              "sk" : "iso8859-2",
              "en" : "iso8859-1",
              "tr" : "iso8859-9",
	      "lt" : "iso8859-13",
	      "bg" : "iso8859-5",
	      "ru" : "iso8859-5"];

global define string LangTypicalEncoding()
    ``{
    string lang = Encoding::GetEncLang();
    string enc = "utf8";
    if( !Encoding::GetUtf8Lang() )
	{
	enc = "iso8859-15";
	lang = substring(lang, 0, 2);
	lang = tolower(lang);
	if( haskey( lenc, lang ) )
	    {
	    enc = lenc[lang]:"";
	    }
	}
    y2milestone( "LangTypicalEncoding lang %1 ret %2", lang, enc );
    return( enc );
    }

/**
 * Search in the list partitions for windows partitions and add the key
 * "mount" to the found windows partitions.
 * @parm partitions the partitions list
 * @parm primary handle primary or logical partitions
 * @return list new partitions with windows mountpoints
 */
global define list AddMountPointsForWinParts( list<map> partitions, boolean primary, integer& foreign_nr )
    ``{
    if( !Arch::i386 () && !Arch::ia64 () && !Arch::x86_64 () )
	return partitions;

    string foreign_ids = "CDEFGHIJKLMNOPQRSTUVW";

    list<map> new_partitions = [];

    foreach(map partition, partitions,
	``{
	map new_partition = partition;
	integer fsid      = partition["fsid"]:Partitions::fsid_native;
	integer partnum = 0;
	if( haskey( partition, "nr") && is( partition["nr"]:(any)0, integer ) )
	    {
	    partnum = partition["nr"]:0;
	    }

	if( !haskey( partition, "mount") && !partition["delete"]:false &&
	    ((partnum<5)==primary) &&
	    Partitions::IsDosWinNtPartition(fsid) &&
	    contains( [`fat32, `fat16, `ntfs], partition["used_fs"]:`none ))
	    {
	    string mntops = "users,gid=users,umask=0002";
	    string enc = LangTypicalEncoding();
	    string code = Encoding::GetCodePage(enc);
	    if( size(enc)>0 )
		{
		if( partition["used_fs"]:`none != `ntfs )
		    {
		    if( enc=="utf8" )
			mntops = mntops + ",utf8=true";
		    else
			mntops = mntops + ",iocharset=" + enc;
		    }
		else
		    mntops = mntops + ",nls=" + enc;
		}
	    if( size(code)>0 && code != "437" &&
	        partition["used_fs"]:`none!=`ntfs )
		{
		mntops = mntops + ",codepage=" + code;
		}
	    if( partition["used_fs"]:`none == `ntfs )
		{
		mntops = "ro," + mntops;
		}
	    new_partition["fstopt"] = mntops;
	    if( contains( Partitions::fsid_dostypes, fsid ))
		{
		new_partition["mount"] =
		    "/dos/" + substring (foreign_ids, foreign_nr, 1);
		foreign_nr = foreign_nr + 1;
		}
	    else
		{
		new_partition["mount"] =
		    "/windows/" + substring (foreign_ids, foreign_nr, 1);
		foreign_nr = foreign_nr + 1;
		}
	    y2milestone( "win part %1", new_partition );
	    }

	new_partitions = add ( new_partitions , new_partition );
	});
    return new_partitions;
    };

global define map<string,map> AddMountPointsForWin( map<string,map> targets )
    ``{
    y2milestone( "AddMountPointsForWin called" );
    integer foreign_nr = 0;

    foreach(string disk, map data, targets,
	``{
	targets[disk,"partitions"] =
	    AddMountPointsForWinParts( data["partitions"]:[], true, 
	                               foreign_nr );
	});
    foreach(string disk, map data, targets,
	``{
	targets[disk,"partitions"] =
	    AddMountPointsForWinParts( data["partitions"]:[], false, 
	                               foreign_nr );
	});
    return( targets );
    }

//  add mount point for all mounted partitions
global define map<string,map> AddMountPointInfo( map<string,map> target )
    ``{
    list<map> mounts = Partitions::CurMounted();
    foreach(string diskdev, map disk, target,
	``{
	// variable renamed due to some interpreter problems
	list<map> tmp2 = disk["partitions"]:[];
	tmp2 = maplist(map part, tmp2,
	    ``{
	    map mt = find(map mp, mounts, ``(mp["spec"]:" "==part["device"]:"" ||
					   mp["loop_on"]:" "==part["device"]:""));
	    if( mt != nil )
		{
		part["mount"] = mt["file"]:"";
		if( part["noauto"]:false )
		    {
		    part["active"] = true;
		    }
		}
	    return( part );
	    });
	disk["partitions"] = tmp2;
	target[diskdev] = disk;
	});
    return( target );
    }

global define list FindFstabLines( map fstab, string mount, string device,
                                   string uuid, string label )
    ``{
    list<integer> lines = [];
    if( size(mount)>0 && mount != "swap" )
	{
	lines = AsciiFile::FindLineField( fstab, 1, mount );
	}
    if( size(lines)==0 )
	{
	lines = AsciiFile::FindLineField( fstab, 0, device );
	}
    if( size(lines)>1 )
	{
	uuid = "UUID=" + uuid;
	label = "LABEL=" + label;
	map<integer,map> tlines = AsciiFile::GetLines( fstab, lines );
	map<integer,map> nlist = filter(integer num, map line, tlines,
			    ``( line["fields",0]:"" == device ||
				line["fields",0]:"" == uuid ||
				line["fields",0]:"" == label ));
	if( size(nlist)>0 )
	    {
	    lines = maplist( integer num, map line, nlist, ``(num));
	    }
	}
    y2milestone( "lines %1", lines );
    return( lines );
    };

//  add info gotten from /etc/fstab to targetMap
global define map<string,map> AddFstabInfo( map<string,map> target, boolean lineno )
    ``{
    y2milestone( "lineno=%1", lineno );
    map fstab = Partitions::GetFstab( "/etc/fstab" );
    map crtab = Partitions::GetCrypto( "/etc/cryptotab" );
    foreach(string diskdev, map disk, target,
	``{
	list new_part = [];
	foreach(map part, disk["partitions"]:[],
	    ``{
	    list<string> rem = [];
	    if( lineno )
		{
		rem = [ "fstabline", "crtabline" ];
		}
	    else
		{
		rem = [ "mountby", "fstopt" ];
		}
	    part = (map<string,any>)filter(string key, any val, (map<string,any>)part, ``(!contains( rem, key )));
	    string mp = part["mount"]:"";
	    if( size(part["ori_mount"]:"")>0 )
		{
		mp = part["ori_mount"]:"";
		}
	    list lines = [];
	    lines = FindFstabLines( fstab, mp, part["device"]:"",
	                            part["uuid"]:"", part["label"]:"" );
	    if( size(lines)>0 )
		{
		if( lineno )
		    {
		    part["fstabline"] = lines[0]:-1;
		    }
		else
		    {
		    map entry = AsciiFile::GetLine( fstab, lines[0]:-1 );
		    if( entry["fields",3]:"defaults" != "defaults" )
			{
			part["fstopt"] = entry["fields",3]:"";
			}
		    if( find(entry["fields",0]:"", "UUID=") > -1 )
			{
			part["mountby"] = `uuid;
			}
		    else if( find(entry["fields",0]:"", "LABEL=") > -1 )
			{
			part["mountby"] = `label;
			}
		    }
		}
	    lines = AsciiFile::FindLineField( crtab, 2, mp );
	    if( size(lines)==0 && diskdev!="/dev/loop" )
		{
		lines = AsciiFile::FindLineField( crtab, 1, part["device"]:"" );
		}
	    if( size(lines)==0 && diskdev=="/dev/loop" )
		{
		lines = AsciiFile::FindLineField( crtab, 0, part["device"]:"" );
		}
	    if( size(lines)>0 )
		{
		if( lineno )
		    {
		    part["crtabline"] = lines[0]:-1;
		    }
		else
		    {
		    map entry = AsciiFile::GetLine( crtab, lines[0]:-1 );
		    if( entry["fields",5]:"defaults" != "defaults" )
			{
			part["fstopt"] = entry["fields",5]:"";
			}
		    }
		}
	    y2milestone( "part=%1", part );
	    new_part = add( new_part, part );
	    });
	target[diskdev] = disk;
	target[diskdev,"partitions"] = new_part;
	});
    return( target );
    }

    /*
     */
global define map<string,map> GetTargetMap()
    ``{
    map<string,map> tmp = $[];
    boolean changed = false;
    if( !probe_done && !Mode::config () )
	{
	y2milestone ("probing StorageDevices" );
	tmp = (map<string,map>)StorageDevices::Probe(force_disk_probe);
	force_disk_probe = false;
	y2milestone ("probing done" );
	if( size(tmp)>0 )
	    {
	    tmp = (map<string,map>)ReadLvmMd( tmp );
	    y2milestone ("lvm init done" );
	    StorageMap[targets_key] = tmp;
	    probe_done = true;
	    lvm_initialized = true;
	    changed = true;
	    }
	}
    if( changed )
	{
	tmp = StorageMap[targets_key]:$[];
	y2milestone ("getting fsys type" );
	tmp = GetFsysType( tmp );
	y2milestone ("AddSwapMp" );
	tmp = AddSwapMp( tmp );
	if( Stage::initial () )
	    {
	    y2milestone( "AddWinInfo" );
	    tmp = AddWinInfo( tmp );
	    }
	SCR::Write(.target.ycp, Storage::SaveDumpPath("targetMap_i"), tmp );
	StorageMap[targets_backup_key,"initial"] = eval(tmp);
	StorageMap[targets_backup_l_key,"initial"] = true;
	StorageMap[targets_backup_m_key,"initial"] = $[];
	if( Stage::initial () || Mode::repair () )
	    {
	    y2milestone( "AddMountPointsForWin" );
	    tmp = AddMountPointsForWin( tmp );
	    }
	if( Mode::normal () )
	    {
	    y2milestone ("AddMountPointInfo" );
	    tmp = AddMountPointInfo( tmp );
	    y2milestone ("AddFstabInfo" );
	    tmp = AddFstabInfo( tmp, false );
	    }
	StorageMap[targets_key] = tmp;
	y2milestone ("changed done" );
	}
    return StorageMap[targets_key]:$[];
    };

global define void SaveExitKey( symbol key )
    ``{
    if( key == `next || key == `back )
	{
	exit_key = key;
	y2milestone( "Exit Key %1", exit_key );
	}
    };

global define symbol GetExitKey()
	``{
    return( exit_key );
    };

global define map FindFstabEntry( map fstab, string mount, string device,
			          string uuid, string label )
		``{
    map ret = $[];
    list lines = [];
    lines = FindFstabLines( fstab, mount, device, uuid, label );
    y2milestone( "mount=%1 device=%2 uuid=%3 label=%4", mount, device, uuid,
                 label );
    if( size(lines)>0 )
			{
	map entry = AsciiFile::GetLine( fstab, lines[0]:-1 );
	ret = $[ "spec" : entry["fields",0]:"",
	         "file" : entry["fields",1]:"",
	         "vfstype" : entry["fields",2]:"",
	         "mntops" : entry["fields",3]:"",
	         "freq" : entry["fields",4]:0,
	         "passno" : entry["fields",5]:0 ];
			}
    y2milestone( "ret %1", ret );
    return( ret );
		    }

global define map GetOndiskTarget()
    ``{
    map ret = $[];
    if( size(StorageMap[targets_backup_key,"initial"]:$[])>0 )
	{
	ret = (map)eval( StorageMap[targets_backup_key,"initial"]:$[] );
	}
    return( ret );
    };


global define void ResetOndiskTarget()
    ``{
    if( size(StorageMap[targets_backup_key,"initial"]:$[])>0 )
	{
	y2milestone( "resetting to on disk TargetMap" );
	StorageMap[targets_key] = eval(StorageMap[targets_backup_key,"initial"]:$[]);
	lvm_initialized = StorageMap[targets_backup_l_key,"initial"]:false;
	StorageMap[modify_targets_key] = eval(StorageMap[targets_backup_m_key,"initial"]:$[]);
	}
    }

    global define void CreateTargetBackup(string who)``{
	if( size(StorageMap[targets_backup_key,who]:$[])==0 )
	    {
	    y2milestone( "creating backup of TargetMap who=%1", who );
	    StorageMap[targets_backup_key,who] = eval(StorageMap[targets_key]:$[]);
	    StorageMap[targets_backup_l_key,who] = lvm_initialized;
	    StorageMap[targets_backup_m_key,who] = eval(StorageMap[modify_targets_key]:$[]);
	    }
	}

    global define void DisposeTargetBackup(string who)``{
	y2milestone( "dispose backup of TargetMap who=%1", who );
	StorageMap[targets_backup_key,who] = $[];
	StorageMap[targets_backup_m_key,who] = $[];
	}

    global define map GetTargetBackup(string who)``{
	return( StorageMap[targets_backup_key,who]:$[] );
	}

    global define void RestoreTargetBackup(string who)``{
	if( size(StorageMap[targets_backup_key,who]:$[])>0 )
	    {
	    y2milestone( "restoring backup of TargetMap who=%1", who );
	    StorageMap[targets_key] = eval(StorageMap[targets_backup_key,who]:$[]);
	    lvm_initialized = StorageMap[targets_backup_l_key,who]:false;
	    StorageMap[modify_targets_key] = eval(StorageMap[targets_backup_m_key,who]:$[]);
	    StorageMap[targets_backup_key,who] = $[];
	    StorageMap[targets_backup_m_key,who] = $[];
	    }
	else
	    y2error( "no existing backup of TargetMap" );
	}

global define void SetModifyTargets( map modify_targets )``{
    y2debug( "SetModifyTargets map:%1", modify_targets );
    StorageMap = add( StorageMap, modify_targets_key, modify_targets );
};

global define map<string,map> ReReadTargetMap()
    ``{
    y2milestone("start reread");
    probe_done = false;
    lvm_initialized = false;
    SCR::Write( .md.init, "" );
    SCR::Write( .lvm.init, "" );
    SCR::Write( .evms.init, "" );
    SetModifyTargets( $[] );
    force_disk_probe = true;
    return GetTargetMap();
    };

global define void SetTargetMap( map targets )
    ``{
    if( StorageMap["targets"]:$[] != targets )
	{
	integer change_time = time();
	y2milestone( "SetTargetMap changed time %1", change_time );
	StorageMap["targets"] = targets;
	StorageMap["targets_time"] = change_time;
	}
    else
	{
	y2milestone( "SetTargetMap unchanged" );
	}
    };

    global define integer GetTargetChangeTime() ``{
	return( StorageMap["targets_time"]:0 );
    }



    global define boolean GetPartProposalActive()``{
	return StorageMap[part_proposal_active_key]:true;
    };

    global define void SetPartProposalActive( boolean value )``{
	StorageMap[part_proposal_active_key] = value;
    };

    global define string GetPartMode()``{
	y2milestone( "GetPartMode %1", StorageMap[part_mode_key]:"" );
	return StorageMap[part_mode_key]:"";
    };

    global define void SetPartMode( string value )``{
	y2milestone( "SetPartMode %1", value );
	StorageMap[part_mode_key] = value;
    };

    global define boolean GetCustomDisplay()``{
	return StorageMap[custom_display_key]:false;
    };

    global define void SetCustomDisplay( boolean value )``{
	StorageMap[custom_display_key] = value;
    };

    global define string GetPartDisk()``{
	return StorageMap[part_disk_key]:"";
    };

    global define void SetPartDisk( string value )``{
	StorageMap[part_disk_key] = value;
	if( find(value,"/dev/") == 0 )
	  {
	  SetModifyTargets( $[] );
	  }
    };

    global define map<integer,map> GetModifyTargets()``{
	return StorageMap[modify_targets_key]:$[];
    };

    /* SubDev defines  ------------------------------------------------------------------ */
    define list<map> FilterDelete( list<map> partitions ) ``{
	return filter(map c_part, partitions ,
			      ``( c_part["delete"]:false != true));
    }



    /* GetMountPoints()
     * collect mountpoint:device as map to get a sorted list
     * @returns: map of lists, the map key is the mount point,
     *		usually starting with a "/". Exception is "swap"
     *	For directory mount points (key starting with /) the value
     *  is a list [partitionName, fsid, targetdevice, raid_type]
     *  For swap mount points, the value is a list of lists:
     *  [[partitionName, fsid, targetdevice, raid_type], ...]
     *
     */
global define map GetMountPoints()
    ``{
    map mountPoints = $[];
    list swapPoints = [];
    map<string,map> tg = GetTargetMap();
    foreach ( string targetdevice, map target, tg,
	``{
	list<map> partitions = FilterDelete( target["partitions"]:[] );
	foreach (map partition, partitions,
	    ``{
	    string partitionName =
		GetDeviceName( targetdevice, partition["nr"]:(any)0);
	    string mountPoint = partition["mount"]:"";
	    integer fsid = partition["fsid"]:0;
	    if (mountPoint != "")
		{
		string raid_type = "";
		if( partition["type"]:`undefined == `sw_raid )
		    {
		    raid_type = partition["raid_type"]:"";
		    }
		// partition has a mount point
		if (mountPoint == "swap")
		    {
		    swapPoints = add( swapPoints,
				      [partitionName, fsid, targetdevice, raid_type]);
		    }
		else
		    {
		    mountPoints = add( mountPoints, mountPoint,
		                       [partitionName, fsid, targetdevice, raid_type]);
		    }
		}
	    });
	});
    if (size (swapPoints) > 0)
	mountPoints = add (mountPoints, "swap", swapPoints);
    if( !Stage::initial () )
	{
	list<map> cm = filter(map e, Partitions::CurMounted(),
	                  ``(find(e["spec"]:"","/dev/")==0));
	foreach(map e, cm,
	    ``{
	    if( !haskey( mountPoints, e["file"]:"" ) )
		{
		map p = GetPartition( tg, e["spec"]:"" );
		if( size(p)>0 )
		    {
		    string raid_type = "";
		    if( p["type"]:`undefined == `sw_raid )
			{
			raid_type = p["raid_type"]:"";
			}
		    map d = GetDiskPartition( e["spec"]:"" );
		    mountPoints[e["file"]:""] =
			[ p["device"]:"", p["fsid"]:0, d["disk"]:"",
			  raid_type ];
		    }
		}
	    });
	}
    y2milestone( "ret %1", mountPoints );
    return mountPoints;
    }



    global define map GetClassifiedUserSettings()``{
	return StorageMap[classified_user_settings_key]:$[];
    }

    global define void SetClassifiedUserSettings(map classified_user_settings )``{
	StorageMap = add( StorageMap, classified_user_settings_key, classified_user_settings );
    }

    global define void SetLvmUse(boolean value )``{
	StorageMap = add( StorageMap, use_lvm_key, value );
    }


  global define boolean GetTestsuite()``{
      return StorageMap[testsuite_key]:false;
  }

  global define void SetTestsuite( boolean value ) ``{
      StorageMap = add( StorageMap, testsuite_key, value );
  }

  global define boolean GetLvmViewAllMnt()``{
      return StorageMap[lvm_view_all_mnt_key]:true;
  }

  global define void SetLvmViewAllMnt( boolean value ) ``{
      StorageMap = add( StorageMap, lvm_view_all_mnt_key, value );
  }

  global define boolean GetRaidtabCreated()``{
      return StorageMap[raidtab_created_key]:false;
  }

  global define void SetRaidtabCreated( boolean value ) ``{
      StorageMap = add( StorageMap, raidtab_created_key, value );
  }

  global define string GetDoResize()``{
      return StorageMap[do_resize_key]:"NO";
  }

  global define void SetDoResize( string value ) ``{
      StorageMap = add( StorageMap, do_resize_key, value );
  }

  global define string GetPartProposalMode()``{
      return StorageMap[part_proposal_mode_key]:"accept";
  }

  global define void SetPartProposalMode( string value ) ``{
      StorageMap = add( StorageMap, part_proposal_mode_key, value );
  }

  global define boolean GetWholeDisk()``{
      return StorageMap[whole_disk_key]:false;
  }

  global define void SetWholeDisk( boolean value ) ``{
      StorageMap = add( StorageMap, whole_disk_key, value );
  }

  global define boolean GetPartProposalFirst()``{
      return StorageMap[part_proposal_first_key]:true;
  }

  global define void SetPartProposalFirst( boolean value ) ``{
      StorageMap = add( StorageMap, part_proposal_first_key, value );
  }

  global define boolean GetWinDevice()``{
      return StorageMap[win_device_key]:false;
  }

  global define void SetWinDevice( boolean value ) ``{
      StorageMap = add( StorageMap, win_device_key, value );
    }

    /**
     * Return a map that contains the maindev for maindevkey.
     * @param maindevkey
     * @return map
     */
    global define map<string, any> GetMainDev(string maindevkey )``{
	map<string, any> maindev = (map<string, any>)GetTargetMap()[maindevkey]:$[];

	if( maindev == $[] )
	    {
	    y2milestone("GetMainDev return empty map $[] (default value)");
	    y2milestone("No maindev with key %1 in Storage found.", maindevkey );
	    }

	return maindev;

	}


    map default_main_dev_param = $[
				   "partitions" : [],
				   "bus"	: "",
				   "name"	: "",
				   "module"	: "",
				   "whole"	: false, // or nil ?
				   "whole_disk" : false, // or nil ?
				   "cyl_count"  : -1,
				   "cyl_size"	: -1,
				   "vendor"	: "",
				   "raid"	: false, // or nil ?
				   "is_lvm_vg"	: false  // or nil ?
    ];


  /**
   *
     *
   */
global define any GetMainDevParam( string maindevkey, string paramkey, 
                                   any default )
    ``{
    any param =  GetMainDev( maindevkey )[paramkey]:default;

    return param;
    }

global define list GetSubDevFilterList( string maindevkey, string what, 
                                        string how )
    ``{
    list<map> partitions		= [];

    if( maindevkey == "all" )
	{
	foreach( string maindevkey_inner, map maindev, GetTargetMap(),``{
	        list part = maindev["partitions"]:[];
		partitions = (list<map>)union( partitions, part );
		});
        }
    else
	{
	partitions = (list<map>) GetMainDevParam( maindevkey, "partitions", [] );
        }
    y2milestone("GetSubDevFilterList partitions %1", partitions );

    list<map> filterPartitions 	= [];

    if( what == "all" )
	{
	filterPartitions = partitions;
	}
    else if ( what == "no_delete" )
	{
	filterPartitions = FilterDelete( partitions );
	}
    else
	{
	return nil;
	}

    if( how == "all" )
	{
	return filterPartitions;
	}
    else
	{
	return nil;
	}

    /* TODO TODO */
    }


    global define map GetEntryForMountpoint( string mp ) ``{
	list<map> all_partitions = (list<map>)GetSubDevFilterList("all", "no_delete", "all" );
        map partition = find(map part, all_partitions,
	                     ``( part["mount"]:"" == mp ));
        if( partition==nil || partition["mount"]:"" != mp )
	  {
	    partition = $[];
	  }
        return partition;
      }



  /**
   * CheckForLvmRootFs
   *---------------------------------------------------------------------
   * check if the root filesystem is a lvm logical volume
   *
   **/
  global define boolean CheckForLvmRootFs()
    ``{
      map dev = $[ "nr" : 0 ];
	map part = GetEntryForMountpoint( "/" );
	if( size(part)>0 )
	    {
	    dev = GetDiskPartition( part["device"]:"" );
	    }
      y2milestone( "CheckForLvmRootFs root=%1 dev=%2", part, dev );
      boolean ret = !is( dev["nr"]:(any)0, integer ) && 
                    find( part["device"]:"", "/dev/evms" )!=0;
      y2milestone( "CheckForLvmRootFs ret=%1", ret );
      return ret;
    };

  /**
   * CheckForEvmsRootFs
   *---------------------------------------------------------------------
   * check if the root filesystem is a evms volume
   *
   **/
global define boolean CheckForEvmsRootFs()
    ``{
    map part = GetEntryForMountpoint( "/" );
    boolean ret = find( part["device"]:"", "/dev/evms/" )==0;
    y2milestone( "CheckForEvmsRootFs ret=%1", ret );
    return ret;
    };



  /*---------------------------------------------------------------------
   * checkForMdRootFs
   *---------------------------------------------------------------------
   * check if the root filesystem is a md device
   *---------------------------------------------------------------------
   */
    global define boolean CheckForMdRootFs()
    ``{
      boolean ret = false;
	map part = GetEntryForMountpoint( "/" );
	map dev = $[ "nr" : 0 ];
	if( size(part)>0 )
	    {
	    dev = GetDiskPartition( part["device"]:"" );
	    }
	y2milestone( "CheckForMdRootFs root=%1 dev=%2", part, dev );
	ret = dev["disk"]:"" == "/dev/md";
      y2milestone( "CheckForMdRootFs ret=%1", ret );
      return ret;
    };






    /* StorageMaps =  [
       1: $[  storage_map_key		: 	$[ Storage_01],
              storage_type_key		:	`record,
	      ],
       2, $[ storage_map_key		: 	$[ Storage_02],
             storage_type_key		: 	`custom,
             storage_doc_key 		:	"create partition /dev/hda2"
	     ],
       3: $[ storage_map_key		:       $[ Storage_03 ],
             storage_type_key		:	`custom,
	     storage_doc_key		:	"delete partition /dev/hda1"
	     ],
       4: $[ storage_map_key		: 	$[ Storage_04 ],
             storage_type_key		: 	`record
	     ]
	];
    */



    /* Record - Rollback - Commit */
    /* update focus and Storage - StorageStack */

    /* Find the next free position in the map StorageMaps
     * @return integer
     */
    define integer NextStorageMapsPos() ``{
	return (size( StorageMaps) + 1);
    }


    define integer FindLastRecordEntry() ``{
	map<integer,any> all_record_entries = (map<integer,any>)filter (integer key, map entry , StorageMaps, ``( entry[storage_type_key]:custom_key == record_key ));
	list<integer> all_record_keys   = (list<integer>) maplist(integer key, any entry , all_record_entries,  ``(  key ));

	if( size( all_record_entries ) > 0 )
	    return sort(integer x, integer y, all_record_keys , ``(y < x))[0]:1;
	else return 0;
    }


    define void Rollback2Pos(integer pos ) ``{
	StorageMap = StorageMaps[pos,storage_map_key]:$[];
	StorageMaps = filter(integer key, map entry, StorageMaps, ``( key < pos ));
    }


    define void AddEntry2StorageMaps(symbol type_key, string doc )``{
	map storage_maps_entry = $[];

	storage_maps_entry = add(storage_maps_entry, storage_map_key  , StorageMap    );
	storage_maps_entry = add(storage_maps_entry, storage_type_key , type_key   );

	if( doc != "" )
	    storage_maps_entry = add(storage_maps_entry, storage_type_key , doc    );

	StorageMaps = add( StorageMaps, NextStorageMapsPos(), storage_maps_entry );
    }


    /**
     *
     * @return boolean
     */
    global define void Record()``{
	AddEntry2StorageMaps( record_key, "");
    }

    /**
     *
     * @return boolean
     */
    global define boolean Rollback()``{
	integer last_record_entry =  FindLastRecordEntry();
	if( last_record_entry != 0 )
	{
	    Rollback2Pos( last_record_entry );
	    return true;
	}
	else
	{
	    return false;
	}
    }

    /**
     *
     *	@return boolean
     */
    global define boolean Commit()``{
	integer last_record_entry = FindLastRecordEntry();
	if( last_record_entry != 0 )
	{
	    StorageMaps = filter( integer key, map entry, StorageMaps,
	                          ``( key < last_record_entry ));
	    return true;
	}
	else
	{
	    return false;
	}

    }


    /**
     *
     * @return boolean
     */
    global define void Save( string doc )``{
	AddEntry2StorageMaps( custom_key, doc );
    }

    /*
     *
     * @return boolean
     */
    global define void Undo( integer key )``{
	Rollback2Pos( key );
    }



    /* Konstuktor */
    /* partition_defines ->  ReReadTargetMap */

    /* Storage call ReRead */
    global define void Storage()``{
	StorageMap[targets_backup_key] = $[];
	StorageMap[targets_backup_l_key] = $[];
	StorageMap[targets_backup_m_key] = $[];
	SetClassifiedUserSettings( $[ "crypt_nb":0 ]  );
	SetModifyTargets($[]);
	SetTargetMap( $[] );
	if( Mode::normal () )
	    {
	    Storage::SetPartMode( "CUSTOM" );
	    Storage::SetPartProposalActive( false  );
	    }
	SetLvmUse( false );
	lvm_initialized = false;
    };

    /* Dev definitions

       dev     = maindev  | subdev
       maindev = "disk"   | "vg"	| "md" (raiddev)
       subdev  = "part"   | "lv" 	| "raid"

       e.g.: 	"disk" = "/dev/hda"	| "dev/sda"	| "/dev/hdd"  | ...
                "vg"   = "/dev/system" 	| "dev/group"   | ...
		"md"   = "/dev/md"  (only)
		"part" = "1//dev/hda"	| "2//dev/sda"	| ..
		"lv"   = "usr//dev/system" | "home//dev/system"
    */


    /* Key definitions

       key = maindevkey | subdevkey + maindevkey

       maindevkey	= key( disk | vg | md   )
       subdevkey	= key( part | lv | raid )
       subdevkey        = maindevkey + subdevindex | "all"

       subdevindex 	= 1 | 2 | "home" | "usr" | ..

       e.g.:
       maindevkey	= "/dev/hda"	| "/dev/md"	| "/dev/system"		| "all"
       subdevkey	= "1//dev/hda"	| "1//dev/md"	| "home//dev/system" 	| "all"


   */



    /*
     * @param key maindevkey or subdevkey e.g.:  "/dev/hda" or  "1//dev/hda"
     * @return boolean
     */
    global define boolean IsKeyMainDevKey(string key )``{
	if(  substring( key, 0, 1) == "/" )
	    return true;
	return false;

	/* TODO regexpmatch dont't work at the moment */
	//return regexpmatch( key, "/dev/.*" );
    }

    /* key - maindevkey - subdevkey defines */

    /*
     * Build a subdevkey with a maindevkey and a subdevindex.
     * subdevkey = subdevkey + "/" + maindevkey
     * @param maindevkey e.g.: /dev/hda
     * @param subdevkey e.g.: 1, "usr" ..
     * @return string "1//dev/hda" or "usr//dev/system" or "" by error
     */
    global define string GetSubDevKey(string maindevkey, any subdevindex )``{
	if( ! IsKeyMainDevKey( maindevkey ) )
	{
	    return "";
	}

	return sformat("%1/%2",subdevindex, maindevkey);
    }


    /*
     * Find a subdevkey in a key and return the subdevkey is one found else return nil.
     * @param key e.g.: "1//dev/hda" or "usr//dev/system" ..
     * @return string e.g.: "1" or "usr" ..
     */
    global define string GetSubDevIndex( string key )``{

	integer column = findfirstof( key, "/" );

	if ( column != nil )
	{
	    return( substring( key, 0, column));
	}
	else
	{
	    return( nil );
	}
    }


    /*
     * @param key maindevkey or subdevkey e.g.:  "/dev/hda" or  "1//dev/hda"
     * @return string maindev e.g.: "/dev/hda" or "/dev/system"
     */
    global define string GetMainDevKey( string key )``{

	if( IsKeyMainDevKey( key ) )
	    return key;

	integer column = findfirstof( key, "/" );

	if ( column != nil )
	{
	    return( substring( key, column+1));
	}
	else
	{
	    return( nil );
	}
    }





    /*
     * @param key maindevkey or subdevkey e.g.:  "/dev/hda" or  "1//dev/hda"
     * @return boolean
     */
    global define boolean IsKeySubDevKey(string key)``{

	if(  substring( key, 0, 1) != "/" )
	    return true;
	return false;

	/* TODO regexpmatch don't work at the moment */
	//return regexpmatch( key, ".*//dev/.*"  );
    }


    /*
     * @param key maindevkey or subdevkey e.g.:  "/dev/hda" or  "1//dev/hda"
     * @return boolean
     */
    global define boolean IsKeyKey(string key )``{
	if( key == nil || key == "" )
	    return false;

	if( IsKeyMainDevKey( key ) )
	    return true;
	if( IsKeySubDevKey( key ))
	    return true;
	return false;
    }



/* partition_defines -> getIdMap
   if no subdev with the key subdevkey exists return $[]
 */
global define map<string,any> GetSubDev( string subdevkey )
    ``{

    list<map> partitions = (list<map>) GetMainDevParam( GetMainDevKey(subdevkey), "partitions", [] );

    map<string,any> part = (map<string,any>)find(map c_part, partitions,
		     ``(sformat("%1",c_part["nr"]:(any)0) ==
			    GetSubDevIndex( subdevkey ) &&
			!c_part["delete"]:false ));

    if ( part == nil )
	{
	y2milestone("No subdev with key %1 in Storage found. Return empty map.", subdevkey);
	part = $[];
	}
    return part;
    }

    /*
     * @param subdevkey  e.g.:  "1//dev/hda" or "usr//dev/hda"
     * @return boolean
     */
    global define boolean IsSubDev(string subdevkey )``{
	if ( GetSubDev( subdevkey ) != $[] )
	{
	    return true;
	}
	else {
	    return false;
	}
    }


    /*
     * @param maindevkey  e.g.:  "/dev/hda" or "/dev/systen"
     * @return boolean
     */
    global define boolean IsMainDev(string maindevkey )``{
	if( GetMainDev( maindevkey ) != $[] )
	{
	    return true;
	}
	else {
	    return false;
	}
    }

    /*
     * @param key maindevkey or subdevkey e.g.:  "/dev/hda" or  "1//dev/hda"
     * @return boolean
     */
   global define boolean IsDev(string key )``{
	if( IsMainDev( key ) )
	    return true;
	if( IsSubDev( key ))
	    return true;
	return false;
    }



    /* MainDev defines ------------------------------------------------------------------
    /* partition_defines -> isDisk */
    /* partition_defines -> isRaid */
    /* partition_defines -> isLVM  */
    symbol sw_raid_type_key = `sw_raid;
    symbol lvm_type_key	    = `lvm;
    symbol extended_type_key= `extended;



    /**
     * Return true if Storage contains a maindev with the key "maindevkey".
     * @return boolean
     * @param maindevkey
     *
     */
    global define boolean ExistsMainDevKeyEntry( string maindevkey )``{

	if( GetMainDev( maindevkey) != $[] )
	    return true;
	return false;
    }




     /**
     * Return true if Storage contains a /dev/md entry with the key "key".
     * @param maindevkey
     * @return boolean
     */
    global define boolean IsMainDevMd(string maindevkey )``{
	if( issubstring( maindevkey, "/dev/md" ) && ExistsMainDevKeyEntry( maindevkey ) )
	    return true;
	return false;
    }


    /**
     * Return true if Storage contains a volume group with the key "key".
     * @return boolean
     * @param maindevkey
     *
     */
    global define boolean IsMainDevVg(string maindevkey )``{
	if( (boolean) GetMainDevParam( maindevkey , "is_lvm_vg", false ))
	    return true;
	return false;
    }


    /**
     *
     *
     */
    global define boolean IsMainDevDisk(string maindevkey )``{
	if ( IsMainDev( maindevkey) )
	{

	    if( ( ! IsMainDevMd( maindevkey )) && ( ! IsMainDevVg( maindevkey )) )
		return true;
	}
	return false;
    }



    global define boolean DelMainDev(string maindevkey )``{

	return false;
    }


    /**
     * Add a maindev to Storage.
     * @param maindevkey key for the new maindev
     * @param newmaindev map with the new maindev
     * @return boolean
     */
    global define boolean AddMainDev(string maindevkey, map<string, any> newmaindev )``{
	if (! ExistsMainDevKeyEntry( maindevkey ) )
	{
	    SetTargetMap( add(GetTargetMap(), maindevkey, newmaindev ));
	    return true;
	}
	else
	{
	    return false;
	}
    }


    /**
     * Modify a maindev in Storage.
     * @param maindevkey describe the maindev
     * @param newmaindev map with modified maindev
     * @return boolean
     */
    global define boolean SetMainDev(string maindevkey, map<string, any> newmaindev )``{

	if( ! ExistsMainDevKeyEntry( maindevkey ))
	{
	    return false;
	}
	else
	{
	    map new_targetMap =  add(GetTargetMap(), maindevkey, newmaindev );
	    SetTargetMap(new_targetMap );
	    return true;
	}
    }



    /**
     *
     * @param  what "all" |  "only_md" | "only_vg" | "only_disk" |  "add_subdev_possible"
     * @param  how  "all" |  "key_list"
     * @return map | list
    */

    global define any GetMainDevFilter(string what , string how )``{

	map filterTargetMap	 = $[];

	if ( what == "all" )
	{
	    filterTargetMap = GetTargetMap();
	}
	else if ( what == "only_md" )
	{
	    filterTargetMap = filter(string key, any value, GetTargetMap(), ``( IsMainDevMd( key ) ) );
	}
	else if ( what == "only_vg" )
	{
	    filterTargetMap = filter(string key, any value, GetTargetMap(), ``( IsMainDevVg( key ) ) );
	}
	else if ( what == "only_disk" )
	{
	    filterTargetMap = filter(string key, any value, GetTargetMap(), ``( IsMainDevDisk( key )));
	}
	else
	{
	    return nil;
	}



	if ( how == "all" )
	{
	    return filterTargetMap;
	}
	else if ( how == "key_list" )
	{
	    return  maplist( any key, any entry , filterTargetMap,  ``( key ));
	}
	else
	{
	    return nil;
	}

    }


    global define boolean DelMainDevParam(string maindevkey, string paramkey )``{
	map<string,any> maindev = (map<string, any>)GetMainDev( maindevkey );

	if( maindev == $[] )
	    return false;

	maindev     = (map<string,any>)filter( string key, any value, maindev, ``( key != paramkey ));
	return SetMainDev( maindevkey, maindev );
    }


    global define boolean AddMainDevParam(string maindevkey, string paramkey, any newparam )``{
	map<string, any> maindev = GetMainDev( maindevkey );

	if( maindev == $[] )
	    return false;

	maindev     = add( maindev, paramkey, newparam );
	return SetMainDev( maindevkey, maindev );
    }


    global define boolean SetMainDevParam(string maindevkey, string paramkey, any newparam )``{
	map<string, any> maindev = GetMainDev( maindevkey);

	if( maindev == $[] )
	    return false;

	maindev     = add( maindev, paramkey, newparam );
	return SetMainDev( maindevkey, maindev );
    }






global define map<string,map> RemoveAllPartEntry( map<string,map> tg, string skey, string value )
    ``{
    map<string,map> new_tg = tg;

    foreach(string dev, map disk, tg,
	``{
	boolean changed = false;
	list new_partitions = [];
	foreach (map partition, disk["partitions"]:[],
	    ``{
	    if( partition[skey]:"" == value )
		{
		partition = filter(string key, any value_inner, (map<string,any>)partition, ``( key != skey));
		changed = true;
		}
	    new_partitions = add( new_partitions , partition);
	    });

	if( changed )
	    {
	    disk["partitions"] = new_partitions;
	    new_tg[dev] = disk;
	    }
	});
    return( new_tg );
    };

global define list<map> RenumberS390Partitions( string dname,
                                                list<map> partitions )
    ``{
    integer cnt = 1;
    partitions = sort( map a, map b, partitions, 
                       ``(a["region",0]:0<b["region",0]:0));
    partitions = maplist( map p, partitions,
	``{
	if( !p["delete"]:false )
	    {
	    if( p["nr"]:0 != cnt )
		{
		if( !haskey( p, "ori_nr" ) )
		    {
		    p["ori_nr"] = p["nr"]:0;
		    }
		p["nr"] = cnt;
		p["device"] = GetDeviceName( dname, cnt );
		}
	    cnt = cnt+1;
	    }
	return( p );
	});
    y2milestone( "RenumberS390Partions %1", partitions ); 
    return( partitions );
    }

global define map<string, map> 
RenameTgDevices( map<string, map> tg, map<string, string> ren )
    ``{
    y2milestone( "RenameTgDevices ren:%1", ren );
    foreach( string dev, map co, tg,
	``{
	if( find( dev, "/dev/evms/" ) == 0 )
	    {
	    y2milestone( "RenameTgDevices before added:%1 removed:%2",
	                 co["added"]:[], co["removed"]:[] );
	    if( size(co["added"]:[])>0 )
		{
		co["added"] = 
		    maplist( string d, co["added"]:[], 
			     ``(haskey( ren, d )?(ren[d]:""):d));
		}
	    if( size(co["removed"]:[])>0 )
		{
		co["removed"] = 
		    maplist( string d, co["removed"]:[], 
			     ``(haskey( ren, d )?(ren[d]:""):d));
		}
	    y2milestone( "RenameTgDevices after added:%1 removed:%2",
	                 co["added"]:[], co["removed"]:[] );
	    tg[dev] = co;
	    }
	});
    return( tg );
    }

global define map<integer, map> 
RenameMtDevices( map<integer, map> mt, map<string, string> ren )
    ``{
    y2milestone( "RenameMtDevices ren:%1", ren );
    foreach( integer num, map entry, mt,
	``{
	if( entry["type"]:""=="create_vg" && size(entry["devices"]:[])>0 )
	    {
	    y2milestone( "RenameMtDevices before entry:%1", entry );
	    entry["devices"] = 
		maplist( string d, entry["devices"]:[], 
			 ``(haskey( ren, d )?(ren[d]:""):d));
	    y2milestone( "RenameMtDevices after entry:%1", entry );
	    mt[num] = entry;
	    }
	if( (entry["type"]:""=="create_pv" || entry["type"]:""=="remove_pv") &&
	    haskey( ren, entry["device"]:"" ))
	    {
	    y2milestone( "RenameMtDevices before entry:%1", entry );
	    entry["device"] = ren[entry["device"]:""]:"";
	    y2milestone( "RenameMtDevices after entry:%1", entry );
	    mt[num] = entry;
	    }
	});
    return( mt );
    }


    /*
      Do not use DelSubDev for LVM !!!!!!!!!!!!!!!!!!
      ToDo Fix
     */
global define boolean DelSubDev( string subdevkey )
    ``{
    if ( ! IsKeySubDevKey( subdevkey ) ) return false;


    string  maindevkey         = GetMainDevKey( subdevkey  );
    string  subdevindex        = GetSubDevIndex( subdevkey );
    integer number             = tointeger( subdevindex );

    list<map> curr_partitions  = (list<map>) GetMainDevParam( maindevkey, 
                                                              "partitions", []);
    map<string, string> renamed_parts = $[];
    map<string, any> curr_part = GetSubDev(subdevkey);
    map<string, any> curr_disk = GetMainDev( maindevkey );

    // if it is an extended partition -> delete all logical!
    // -----------
    // remove all partition with a "nr" >= 5  i.e. all logical
    // we dont need to mark already existing part. with delete,
    // because fdisk deletes the logical automaticly
    // also, when a deleted extended is newly created cause the delete operation
    // is done!

    if( IsMainDevMd( maindevkey ))
	{
	map<string, map> tg = (map <string, map>)GetTargetMap();
	tg = RemoveAllPartEntry( tg, "raid_name", maindevkey+subdevindex );
	SetTargetMap(tg);
	}

    if ( curr_part["type"]:`unknown == `extended )
	{
	curr_partitions = filter( map parti, curr_partitions, 
	                          ``(parti["nr"]:(any)0<5));
	}

    map part_created = (map) find(map parti, curr_partitions,
                             ``( parti["nr"]:(any)0 == number &&
                                 parti["create"]:false ));

    if (part_created == nil)
	{
	// No newly created found...
	// Mark already existant with "delete"
	curr_partitions =  maplist(map parti, curr_partitions,
	    ``({
	    if( parti["nr"]:(any)0 == number )
		{
		parti["delete"] = true;
		if( haskey( parti, "ori_nr" ) )
		    {
		    parti["nr"] = parti["ori_nr"]:(any)0;
		    }
		}
	    return( parti );
	    }));
	}
    else
	{
	// delete newly created partition
	curr_partitions =
	    filter(map parti, curr_partitions,
		    ``( !(parti["nr"]:(any)0 == number && parti["create"]:false )));
	list<map> create_next = (list<map>)
	    filter(map p, curr_partitions,
		    ``( p["nr"]:(any)0 > number && p["create"]:false &&
		        curr_part["type"]:`unknown != `logical ));
	create_next = sort( map a, map b, create_next, 
	                    ``( a["nr"]:(any)0 < b["nr"]:(any)0 ));
	y2milestone("curr_partitions %1", curr_partitions );
	y2milestone("create_next %1", create_next );
	integer del_num = number;
	foreach(map p, create_next,
	    ``{
	    integer old = p["nr"]:0;
	    map part = (map)eval(p);
	    part["nr"] = del_num;
	    string new = GetDeviceName( maindevkey, del_num );
	    renamed_parts[part["device"]:""] = new;
	    part["device"] = new;
	    del_num = old;
	    curr_partitions = filter(map t, curr_partitions,
				      ``( !(t["nr"]:(any)0 == old &&
				            t["create"]:false )));
	    curr_partitions = add( curr_partitions, part );
	    });
	y2milestone("curr_partitions %1", curr_partitions );
	}

    ///////////////////////////////////////////////
    // If you delete a logical partition you must decrease the number of
    // every logical partition, that has a higher number than the deleted
    // start: sda1 sda2 sda5 sda6 sda7 sda8 sda9 sda10
    // delete sda7
    // you must sda8 -> sda7   sda9 -> sda8     sda10 -> sda9
    // end with: sda1 sda2 sda5 sda6 sda7 sda8 sda9

    if( curr_part["type"]:`unknown == `logical )
	{
	curr_partitions = maplist(map parti, curr_partitions,
	    ``({
	    // only the valid ones
	    if( !parti["delete"]:false && parti["nr"]:(any)0 > number )
		{
		if( !haskey( parti, "ori_nr" ))
		    {
		    parti["ori_nr"] = parti["nr"]:(any)0;
		    }
		parti["nr"] = parti["nr"]:0 - 1;
		string new = GetDeviceName( maindevkey, parti["nr"]:(any)0 );
		renamed_parts[parti["device"]:""] = new;
		parti["device"] = new;
		}
	    return( parti );
	    }));
	}

    if( curr_disk["label"]:"msdos" == "dasd" )
	{
	curr_partitions = RenumberS390Partitions( maindevkey, curr_partitions );
	}
    curr_disk["partitions"] = curr_partitions;

    SetMainDev( maindevkey, curr_disk );
    if( size(renamed_parts)>0 )
	{
	map<string, map> tg = GetTargetMap();
	tg = RenameTgDevices( tg, renamed_parts );
	SetTargetMap(tg);
	map<integer,map> mt = GetModifyTargets();
	mt = RenameMtDevices( mt, renamed_parts );
	SetModifyTargets(mt);
	}
    return true;
    }

global define string
GetIdSmaller( string disk, integer delim )
    ``{
    string ret = disk;
    map<string,map> tg = GetTargetMap();
    list<map> ps = filter( map p, tg[disk,"partitions"]:[], ``(p["nr"]:0<delim));
    ps = sort( map a, map b, ps, ``(a["nr"]:(any)0>b["nr"]:(any)0));
    if( size(ps)>0 )
	ret = GetSubDevKey( disk, ps[0,"nr"]:(any)0 );
    y2milestone( "GetIdSmaller disk:%1 delim:%2 ret:%3",
                 disk, delim, ret );
    return( ret );
    }


global define void AddSubDev( string subdevkey, map newsubdev )
    ``{
    string maindevkey = GetMainDevKey( subdevkey );
    list<map> partitions = (list<map>) GetMainDevParam( maindevkey, 
                                                        "partitions", [] );

    partitions        = add( partitions, newsubdev );

    string label = (string) GetMainDevParam( maindevkey, "label", "msdos" );
    if( label == "dasd" )
	{
	partitions = RenumberS390Partitions( maindevkey, partitions );
	}
    SetMainDevParam( maindevkey, "partitions", partitions);
    }

/* set <key> in partition <device> to the given <value> and return changed map <tg> */
global define map<string,map> SetPartitionData( map<string,map> tg, 
                                                string device, string key, 
						any value )
    ``{
    y2milestone( "SetPartitionData device=%1 key=%2 value=%3", device, key, 
                 value );
    map tmp = GetDiskPartition( device );
    string disk = tmp["disk"]:"";
    list r_part = filter(map part, tg[disk,"partitions"]:[],
			  ``(part["device"]:"" != device ||
			     part["delete"]:false == true));
    if( size(r_part)!=size(tg[disk,"partitions"]:[]) )
	{
	map p = filter( map part, tg[disk,"partitions"]:[],
		        ``(part["device"]:"" == device &&
			   part["delete"]:false == false))[0]:$[];
	if( size(p)>0 )
	    {
	    p[key] = value;
	    r_part    = add( r_part, p );
	    tg[disk,"partitions"] = r_part;
	    }
	}
    return( tg );
    }

/* remove <key> in partition <device> and return changed map <tg> */
global define map<string,map> DelPartitionData( map<string,map> tg, 
                                                string device, string key)
    ``{
    y2debug( "device=%1, key=%2", device, key );
    map tmp = GetDiskPartition( device );
    string disk = tmp["disk"]:"";
    list r_part = filter(map part, tg[disk,"partitions"]:[],
			  ``(part["device"]:"" != device ||
			     part["delete"]:false == true));
    if( size(r_part)!=size(tg[disk,"partitions"]:[]) )
	{
	map p = filter( map part, tg[disk,"partitions"]:[],
			``(part["device"]:"" == device &&
			   part["delete"]:false == false))[0]:$[];
	if( size(p)>0 )
	    {
	    p = filter(string k, any e, (map<string,any>)p, ``(k != key) );
	    r_part    = add( r_part, p );
	    tg[disk,"partitions"] = r_part;
	    }
	}
    return( tg );
    }


/* replace SubDev entry with newsubdev */
global define boolean SetSubDev( string subdevkey, map newsubdev )
    ``{
    string maindevkey = GetMainDevKey( subdevkey );
    list<map> partitions = (list<map>) GetMainDevParam( maindevkey, "partitions", [] );

    // and now delete the old partition number in curr_disk to replace it in the next step
    list r_part =
	filter(map c_part, partitions ,
		``(sformat("%1", c_part["nr"]:(any)0) != GetSubDevIndex( subdevkey) ||
		   c_part["delete"]:false));

    // netxt step: insert changed partition
    r_part    = add( r_part,   newsubdev );


    return SetMainDevParam( maindevkey, "partitions", r_part );
	}




    /* maindevkey = all | maindevkey
       what = "all"		|
              "assigned_raid"	| "assigned_vg"  | "not_assigned" | "assigned"
	      "delete" | "no_delete"
	      "edit_possible"	| "delete_possible" |
	      "display_possible" |
	      "assign_raid_possible" | "assign_vg_possible"
	      "no_virtal" 	| "virtual"
      how = "all"	| "key_list"  | "index_list" (   raid_lib -> get_possible_rds  )
    */


    map default_sub_dev_param = $[
				   "delete"	:	false,
				   "fsid"	:	Partitions::fsid_native,
				   "fstype"	:	"Linux native",
				   "nr"		:	1,
				   "region"	: 	[0,1],
				   "type"	:	`primary,
				   "used_fs"	:	`ext2
				 ];


    global define any GetSubDevParam(string subdevkey, string paramkey )``{

	any param = GetSubDev(subdevkey )[paramkey]:nil;

	if( param == nil )
	{

	    y2milestone(" GetSubDevParam try to return default subdev parameter.");
	    param = default_sub_dev_param[paramkey]:nil;
	}
	if( param == nil )
	{
	    y2error(" GetSubDevParam return nil - parameter not found.");
	}

	return param;
    }


    global define boolean DelSubDevParam(string subdevkey, string paramkey )``{
	map<string,any> subdev = GetSubDev( subdevkey );

	if( subdev == $[] )
	    return false;

	subdev     = filter(string key, any value, subdev, ``( key != paramkey ));

	return SetSubDev( subdevkey, subdev );
    };


    global define boolean AddSubDevParam(string subdevkey, string paramkey, any newparam )``{
	map subdev = GetSubDev( subdevkey );

	if( subdev == $[] )
	    return false;

	subdev = add( subdev, paramkey, newparam );
	return SetSubDev( subdevkey, subdev );
    };


    global define boolean SetSubDevParam(string subdevkey, string paramkey, any newparam )``{
	return AddSubDevParam( subdevkey,  paramkey, newparam );
    };




    /* For IsSubDev... defines use GetSubDevList( .. , .. , .. )``{}; */

    global define boolean IsSubDevVirtual(string subdevkey )``{
	return GetSubDev( subdevkey )["create"]:false;
    };


    /* raid_lib->isItemRd ?? */
    /* raid_lib -> isCurrentRaid */
    global define boolean IsSubDevRaid(string subdevkey )``{
	if( GetSubDevParam( subdevkey, "type" ) == sw_raid_type_key )
	    return true;
	else return false;

    };
    global define boolean IsSubDevLv(string subdevkey )``{
	if( GetSubDevParam( subdevkey, "type" ) == lvm_type_key )
	    return true;
	else return false;

    };
    global define boolean IsSubDevPart(string subdevkey )``{
	/* ?? */
	if( ! IsSubDevLv( subdevkey ) && ! IsSubDevRaid( subdevkey ) )
	    return true;
	else return false;

    };



    /**
     * I386:
     * Check if the patition-id is an extended -id
     *
     * @return boolean
     *
     */
    global define boolean IsSubDevExtended(string subdevkey )``{

	any number = GetSubDevParam(subdevkey, "fsid" );

	if( GetSubDevParam( subdevkey, "type" ) == extended_type_key )
	    return true;

	// old code
	// Standrd-Erw         Linux-Erweiterte    Win95-Erweitert
	if ( (number == 5) || (number == 133) || (number == 15) )
	{
	    y2debug( "IS__EXTENDE YES");
	    return(true);
	}
	else
	{
	    y2debug( "IS__EXTENDE NO");
	    return(false);
	}
    };


/**
  * Insert Raid size info to Storage
 **/
global define void AddRaidSizeInfo()
    ``{
    map<string,map> targetMap = GetTargetMap();

    targetMap = mapmap(string dev, map devmap, targetMap,
	``{
	integer cyl_size = devmap["cyl_size"]:1000000;

	list partitions = maplist(map part, devmap["partitions"]:[],
	    ``{
	    integer nb_cyl = part["region",1]:0;

	    integer bytes_of_part =  ( nb_cyl ) * cyl_size;
	    part["size_byte"] = bytes_of_part;
	    return( part );
	    });

	return( $[ dev: add( devmap, "partitions", partitions)] );
	});

    SetTargetMap( targetMap );
    };



global define list GetRootInitrdModules()
    ``{
    map partition = GetEntryForMountpoint( "/" );
    y2milestone("root partition in GetInitrdModules %1", partition );

    list initrdmodules =
	FileSystems::GetNeededModules( partition["used_fs"]:`ext2 );

    if (partition["raid_type"]:"" == "raid0" )
	{
	if (!contains (initrdmodules, "raid0"))
	    {
	    initrdmodules = add (initrdmodules, "raid0");
	    }
	}
    if (partition["raid_type"]:"" == "raid1" )
	{
	if (!contains (initrdmodules, "raid1"))
	    {
	    initrdmodules = add (initrdmodules, "raid1");
	    }
	}
    if (partition["raid_type"]:"" == "multipath" )
	{
	if (!contains (initrdmodules, "multipath"))
	    {
	    initrdmodules = add (initrdmodules, "multipath");
	    }
	}
    if (partition["raid_type"]:"" == "raid5" )
	{
	if (!contains (initrdmodules, "raid5"))
	    {
	    initrdmodules = add (initrdmodules, "raid5");
	    }
	}
    if (partition["raid_type"]:"" == "raid6" )
	{
	if (!contains (initrdmodules, "raid6"))
	    {
	    initrdmodules = add (initrdmodules, "raid6");
	    }
	}
    if( partition["type"]:`unknown == `lvm )
	{
	string vgname = substring( partition["device"]:"", 5 );
	vgname = substring( vgname, 0, findfirstof( vgname, "/" ));
	map tg = GetTargetMap();
	list<string> mod = (list<string>) maplist(map k, filter(map e, tg["/dev/md","partitions"]:[],
	                                ``(e["lvm_group"]:""==vgname) ),
			    ``(k["raid_type"]:""));
	y2milestone( "mod %1", mod );
	foreach(string e, mod,
	    ``{
	    if( size(e)>0 && !contains( initrdmodules, e ) )
		{
		initrdmodules = add( initrdmodules, e );
		}
	    });
	if( !contains( initrdmodules, "dm_mod" ) )
	    {
	    initrdmodules = add( initrdmodules, "dm_mod" );
	    }
	}
    y2milestone ("initrdmodules %1", initrdmodules);
    return initrdmodules;
    };




/* Contain the current key ( subdevkey ) for all wizards */
string WizardKey = "";

global define string GetWizardKey()
    ``{
	y2debug( " Return wizard key %1", WizardKey);
	return WizardKey;
    };

global define void SetWizardKey( string key )
    ``{
	if( IsKeyKey(key))
	{
	    y2debug(" Set WizardKey %1", WizardKey);
	    WizardKey = key;
	}
    };


















  /*
   * partition_defines -> addTargetModification
   * Add a new entry into the execution stack "modify_targets" in Storage.
   *
   */
  global define void AddModify(map new_create_pv )``{
      map modify_targets = GetModifyTargets();
      integer max = size( modify_targets );

      SetModifyTargets( add( modify_targets, max+1, new_create_pv ));
  };

  /*
   * partition_defines -> removeTargetModification
   * Remove an entry from the execution stack "modify_targets" in Storage.
   * Renumber the rest of the entries.
   *
   */
  global define void DelModify(integer number )``{

      map<integer,any> modify_targets = GetModifyTargets();

      // delete entry
      modify_targets = filter(integer k, any v, modify_targets, ``(k != number ) );
	// renumber 1 2 4 5 -> 1 2 3 4
      modify_targets = mapmap(integer k, any v, modify_targets, ``{
	  if ( k > number )
	  {
	      return($[k-1: v]);
	  }
	  else
	  {
	      return($[k: v]);
	  }
      });

      return SetModifyTargets( modify_targets );
  };

  global define string AddCryptToClassified( string fs_passwd ) ``{

    map classified = GetClassifiedUserSettings();

    integer crypt_nb  = classified["crypt_nb"]:0;
    string  crypt_key = sformat( "loop_crypt_pw%1", crypt_nb );

    classified["crypt_nb"] = crypt_nb+1;
    classified[crypt_key] = fs_passwd;

    SetClassifiedUserSettings(classified);
    return crypt_key;
    }

  global define integer NumLoopDevices() ``{
    return( GetClassifiedUserSettings()["crypt_nb"]:0 );
    }

  global define map IdFromTarget( map tg, string id )
    ``{
    map part = $[];
    if( id != nil )
	{
	string maindev = GetMainDevKey(id);  // i.e. /dev/hda for /dev/hda1
	string subdev  = GetSubDevIndex(id); // i.e. 1        for /dev/hda1

	part = filter( map part, tg[maindev,"partitions"]:[],
		       ``( sformat("%1", part["nr"]:(any)"") == subdev &&
			   part["delete"]:false == false) )[0]:$[];
	}
    y2debug( "IdFromTarget id:%1 map:%2", id, part );
    return( part );
    }


    /* Functions for testing */

    global define void DebugStorage()``{

	y2milestone("StorageMaps: %1",StorageMaps);
	y2milestone("Storage:%1",StorageMap);
    }



global define boolean DiskAgentCall( map curr_map )
    ``{
    boolean ok  = false;
    integer pos = 0;
    string disk = curr_map["disk"]:"";
    string pt   = "";

    y2milestone( "DiskAgentCall map=%1", curr_map );
    disk = substring( disk, 5 );
    pos = findfirstof( disk, "/" );
    while( pos != nil && pos > 0 )
	{
	pt = pt + "." + substring( disk, 0, pos );
	disk = substring( disk, pos+1 );
	pos = findfirstof( disk, "/" );
	}

    boolean parted = Partitions::UseParted();
    if( curr_map["type"]:"" == "resize" )
	{
	parted = true;
	}

    pt = pt + "." + disk;
    if( size(pt)>0 )
	{
	pt = ".disk" + pt + ".command";
	y2debug( "pt=%1", pt );
	ok = SCR::Write(topath(pt), curr_map, parted );
	}
    return( ok );
    }


/**
 * Delete the partition table and disk label of device
 * @param string the device to be deleted
 * @return integer
 */
global define integer ZeroDevice(string del_device)
    ``{
    y2milestone( "ZeroDevice %1", del_device );
    map tg = GetTargetMap();
    map init_disk = $[ "disk" : del_device, "type" : "init", 
                       "label" : tg[del_device,"label"]:"msdos" ];

    boolean ok = Storage::DiskAgentCall( init_disk );
    if( !ok )
	{
	// popup text
	Popup::Message( sformat(_("Initialization of disk %1 failed."), del_device ));
	}
    integer ret = ok ? 0 : 1;
    y2milestone( "ZeroDevice ret %1", ret );
    return(ret);
    }


/**
 * Check if a disk is a real disk and not RAID or LVM
 * @return boolean true if real disk
 */
global define boolean IsRealDisk( string disk, map entry )
    ``{
    return( disk != "/dev/md" && disk != "/dev/loop" &&
            !entry["is_lvm_vg"]:false && find( disk, "/dev/evms")!=0 );
    }

global define boolean DeviceRealDisk( string device )
    ``{
    boolean ret = false;
    
    if( find( device, "LABEL" )!=0 && find( device, "UUID" )!=0 )
	{
	map dev = $[];
	dev = GetDiskPartition( device );
	ret = dev["disk"]:"" != "/dev/md" && dev["disk"]:"" != "/dev/loop" &&
	      find( dev["disk"]:"", "/dev/evms")!=0 &&
	      is( dev["nr"]:(any)0, integer );
	if( !ret )
	    {
	    map st = (map)SCR::Read( .target.stat, dev["disk"]:"" );
	    ret = !st["isdir"]:false;
	    }
	}
    y2milestone( "DeviceRealDisk %1 ret %2", device, ret );
    return ret;
    }

/**
  * Determine if there is any Linux partition on this system.
  *
  * If there is none, we don't need to ask if the user wants to update or
  * boot an installed system - he can only do a new installation anyway.
  * No time-consuming or dangerous operations should be performed here,
  * only simple checks for existence of a Linux (type 83) partition.
  *
  * @return boolean true if there is anything that might be a Linux partition
  **/
global define boolean HaveLinuxPartitions() ``{
    boolean ret = false;
    foreach ( string dev, map disk, GetTargetMap(), ``{
        if( !ret )
	    {
	    if( IsRealDisk( dev, disk ) )
		{
		foreach( map e, disk["partitions"]:[], ``{
		    ret = ret ||
			  Partitions::IsLinuxPartition( e["fsid"]:Partitions::fsid_native );
		    });
		}
	    }
	});
    y2milestone( "HaveLinuxPartitions ret=%1", ret );
    return( ret );
    };

/**
 * Get list of all Partitions on all real disks
 * @return list Partition list
 */
global define list GetPartitionList()``{
    list ret = [];
    foreach ( string dev, map disk, GetTargetMap(), ``{
        if( IsRealDisk( dev, disk ) )
	    {
	    list<map> l = filter( map p, disk["partitions"]:[],
	                     ``(p["delete"]:false==false) );
	    ret = union( ret, maplist( map p, l,
				       ``(GetDeviceName(dev,p["nr"]:(any)0))));
	    }
	});
    ret = sort( ret );
    y2debug( "GetPartitionList ret=%1", ret );
    return( ret );
    }

/**
 * Get list of all Linux Partitions on all real disks
 * @return list Partition list
 */
global define list GetOtherLinuxPartitions()``{
    list ret = [];
    foreach ( string dev, map disk, GetTargetMap(), ``{
        if( IsRealDisk( dev, disk ) )
	    {
	    list<map> l = (list<map>) filter( map p, disk["partitions"]:[],
	                     ``(!p["delete"]:false &&
	                        !p["format"]:false &&
			        Partitions::IsLinuxPartition(p["fsid"]:0)) );
	    l = filter(map p, l, ``(contains( [`xfs, `ext2, `ext3, `jfs, `reiser],
	                                    p["used_fs"]:`unknown)));
	    l = filter(map p, l,
			``(!FileSystems::IsSystemMp( p["mount"]:"", false )));
	    if( size(l)>0 )
		{
		ret = union( ret, l );
		}
	    }
	});
    y2milestone( "GetOtherLinuxPartitions ret=%1", ret );
    return( ret );
    }

/**
 * Check if swap paritition is availbe on a disk
 * @param disk Disk to be checked
 * @return boolean true if swap available.
 */
global define boolean CheckSwapOn( string disk )``{
    boolean ret = false;
    list swaps = SwappingPartitions();
    while( size(swaps)>0 && !ret )
	{
	if( find( swaps[0]:"", disk )==0)
	    {
	    ret = true;
	    }
	swaps = remove( swaps, 0 );
	}
    y2milestone( "CheckSwapOn %1 ret %2", disk, ret );
    return( ret );
    }

global define string CheckSwapConflicts()``{
    string ret = "";
    list swaps = SwappingPartitions();
    if( size(swaps)>0 )
	{
	list plist = [];
	foreach ( string dev, map disk, GetTargetMap(), ``{
	    if( IsRealDisk( dev, disk ) )
		{
		list<map> l = filter(map p, disk["partitions"]:[],
				``(p["delete"]:false==false) );
		l = filter(map p, l, ``(p["mount"]:"" != "" ||
				      p["raid_name"]:"" != "" ||
				      p["evms_vol"]:"" != "" ||
				      p["lvm_group"]:"" != "") );
		l = filter(map p, l, ``(p["mount"]:"" != "swap") );
		list l1 = maplist(map p, l, ``(GetDeviceName(dev,p["nr"]:(any)0)));
		plist = union( plist, l1 );
		}
	    });
	y2milestone( "CheckSwapConflicts used %1", plist );
	while( size(swaps)>0 && size(ret)==0 )
	    {
	    if( contains( plist, swaps[0]:"" ) )
		{
		ret = swaps[0]:"";
		}
	    swaps = remove( swaps, 0 );
	    }
	}
    y2milestone( "CheckSwapConflicts ret %1", ret );
    return( ret );
    }

global define list GetWinPrimPartitions( map<string,map> targets )
    ``{
    list<map> ret = [];
    map entry = $[];
    string text = "";
    integer num_dos = 0;
    integer num_win = 0;
    integer num_os2 = 0;
    integer num_linux = 0;
    string linux_text = "Linux other";
    string dos_text = "dos";
    string win_text = "windows";
    string os2_text = "OS/2 Boot Manager";

    foreach(string disk, map data, targets,
	``{
	foreach(map part, data["partitions"]:[],
	    ``{
	    string device = GetDeviceName( disk, part["nr"]:(any)0 );
	    if( part["type"]:`unknown == `primary &&
		part["delete"]:false==false &&
	        SCR::Execute (.target.bash,
		              "/usr/lib/YaST2/bin/check.boot "+device) == 0)
		{
		text = "";
	        if( Partitions::IsDosWinNtPartition( part["fsid"]:0 ) &&
		    part["winfo","win_disk"]:false )
		    {
		    if( contains( Partitions::fsid_dostypes, part["fsid"]:0 ) )
			{
			num_dos = num_dos+1;
			text = dos_text;
			}
		    else
			{
			num_win = num_win+1;
			text = win_text;
			}
		    }
		else if( part["fsid"]:0 == 0x12 )
		    {
		    text = "Vendor diagnostic";
		    }
		else if( part["fsid"]:0 == 0x0a )
		    {
		    text = os2_text;
		    num_os2 = num_os2+1;
		    }
		else if( part["fsid"]:0 == Partitions::fsid_native &&
		         size(part["mount"]:"")==0 )
		    {
		    text = linux_text;
		    num_linux = num_linux+1;
		    }
		if( size(text)>0 )
		    {
		    entry["device"] = device;
		    entry["string"] = text;
		    ret = add( ret, eval(entry) );
		    y2milestone( "new entry %1", entry );
		    }
		}
	    });
	});
    y2milestone( "GetWinPrimPartitions num_linux %1 num_win %2 num_dos %3 num_os2 %4",
                 num_linux, num_win, num_dos, num_os2 );
    integer num = 1;
    if( num_linux>1 )
	{
	ret = maplist( map entry, ret, 
	    ``{
	    if( entry["string"]:""==linux_text )
		{
		entry["string"] = linux_text + sformat( " %1", num );
		num = num+1;
		}
	    return( entry );
	    });
	}
    num = 1;
    if( num_dos>1 )
	{
	ret = maplist( map entry, ret, 
	    ``{
	    if( entry["string"]:""==dos_text )
		{
		entry["string"] = dos_text + sformat( " %1", num );
		num = num+1;
		}
	    return( entry );
	    });
	}
    num = 1;
    if( num_win>1 )
	{
	ret = maplist( map entry, ret, 
	    ``{
	    if( entry["string"]:""==win_text )
		{
		entry["string"] = win_text + sformat( " %1", num );
		num = num+1;
		}
	    return( entry );
	    });
	}
    num = 1;
    if( num_os2>1 )
	{
	ret = maplist( map entry, ret, 
	    ``{
	    if( entry["string"]:""==os2_text )
		{
		entry["string"] = os2_text + sformat( " %1", num );
		num = num+1;
		}
	    return( entry );
	    });
	}
    y2milestone( "GetWinPrimPartitions ret %1", ret );
    return( ret );
    }

global define list<string> AddPackageList()
    ``{
    list<string> pl = [];
    boolean mount_lvm = false;
    boolean need_evms = false;
    map<string,map> tg = GetTargetMap();
    map<string,map> tt = filter( string k, map e, tg, ``(e["is_lvm_vg"]:false &&
					     !e["delete"]:false));
    boolean have_lvm = size(tt)>0;
    if( have_lvm )
	{
	list<map> part = [];
	foreach( string k, map e, tt,
		 ``{
		 part = (list<map>)merge( part, e["partitions"]:[]);
		 });
	mount_lvm = size(filter( map p, part, ``(size(p["mount"]:"")>0)))>0; 
	}
    tt = filter( string k, map e, tg, ``(find(k, "/dev/evms/")==0));
    if( size(filter( string k, map e, tg, ``(e["is_evms_container"]:false &&
					     find(e["name"]:"","lvm/")!=0)))>0)
	{
	y2milestone( "non lvm evms container" );
	need_evms = true;
	}
    if( !need_evms )
	{
	list<map> part = [];
	foreach( string k, map e, tt,
		 ``{
		 part = (list<map>)merge( part, e["partitions"]:[]);
		 });
	need_evms = size(filter( map p, part, ``(size(p["mount"]:"")>0)))>0; 
	}
    y2milestone( "AddPackageList have_lvm %1 mount_lvm %2 need_evms %3", 
                  have_lvm, mount_lvm, need_evms );
    if( have_lvm && (mount_lvm||!need_evms))
	{
	pl = add( pl, "lvm2" );
	}
    if( need_evms )
	{
	pl = add( pl, "evms" );
	}
    y2milestone( "AddPackageList ret %1", pl );
    return( pl );
    }

global define list GetForeignPrimary()
    ``{
    list ret = [];
    if( Arch::i386 () || Arch::ia64 () || Arch::x86_64 () )
	{
	map<string,map> tg = filter(string k, map e, GetTargetMap(), ``(IsRealDisk(k,e)));
	list<map> wd = (list<map>) flatten( (list<list>) maplist(string k, map e, tg, ``(e["partitions"]:[])));
	wd = filter(map e, wd, ``(size(e["winfo"]:$[])>0));
	y2milestone( "wd %1", wd );
	if( !Stage::initial () && size(wd)==0 )
	    {
	    tg = GetTargetMap();
	    y2milestone( "AddWinInfo" );
	    tg = AddWinInfo( tg );
	    SetTargetMap( tg );
	    }
	foreach(map e, (list<map>)GetWinPrimPartitions( tg ),
	    ``{
	    ret = add( ret, sformat( "%1 %2", e["device"]:"", e["string"]:"" ));
	    });
	}
    y2milestone( "ret=%1", ret );
    return( ret );
    }

global define map IsResizable( map part )
    ``{
    map ret = FileSystems::IsResizable(`unknown);
    if( !Arch::s390 () &&
        (part["type"]:`none==`lvm || Partitions::IsResizable( part["fsid"]:0 )))
	{
	if( part["fsid"]:0==Partitions::fsid_swap )
		{
	    ret = FileSystems::IsResizable(`swap);
		}
	else
		{
	    ret = FileSystems::IsResizable(part["used_fs"]:`unknown);
		}
	}
    y2milestone( "IsResizable part:%1 ret:%2", part, ret );
    return( ret );
    }

global define integer FreeCylAfter( map disk, map partition )
	``{
    integer ret = 0;
    integer next_used_cyl = disk["cyl_count"]:0;
    integer cylinder = partition["region",0]:0;
    if( haskey( partition, "ori_length" ))
	{
        cylinder = cylinder + partition["ori_length"]:0;
        }
    else
	{
        cylinder = cylinder + partition["region",1]:0;
        }
    if( partition["type"]:`primary == `logical )
	{
	map ext = filter( map part, disk["partitions"]:[],
			  ``( part["type"]:`primary==`extended ))[0]:$[];
	next_used_cyl = ext["region",0]:0+ext["region",1]:0;
	}
    if( cylinder < next_used_cyl )
	{
	foreach(map part, disk["partitions"]:[], ``{
	    if( !part["delete"]:false )
		{
		integer start = part["region",0]:0;
		if( start >= cylinder && start < next_used_cyl )
		    {
		    next_used_cyl = start;
		    }
		}
	    });
	}
    if( next_used_cyl >= cylinder )
	ret = next_used_cyl-cylinder;
    y2milestone( "FreeCylAfter cyl:%1 ret:%2", cylinder, ret );
    return( ret );
    }

global define boolean CheckNextCreated( map disk, list region )
    ``{
    boolean ret = false;
    integer cylinder = region[0]:0 + region[1]:0;
    foreach(map part, disk["partitions"]:[], ``{
	if( part["region",0]:0 == cylinder && part["create"]:false )
	    {
	    ret = true;
	    }
	});
    y2milestone( "CheckNextCreated region:%1 ret:%2", region, ret );
    return( ret );
    }

global define void AdaptResize( string maindev, list region, integer schange )
    ``{
    list<map> partitions = (list<map>) GetMainDevParam( maindev, "partitions", [] );
    integer cylinder = region[0]:0 + region[1]:0;
    boolean found = false;
    integer index = -1;
    integer e_idx = -1;
    list<integer> idx_list = [];
    map part = (map) find(map p, partitions,
                          ``(p["delete"]:false==false &&
			     p["region",0]:0 == cylinder &&
			     p["create"]:false) );
    y2milestone( "AdaptResize %1 reg %2 change %3", maindev, region, schange );
    if( part != nil )
	{
	found = false;
	index = 0;
	foreach(map p, partitions,
	    ``{
	    if( !p["delete"]:false && p["region",0]:0 == cylinder &&
		p["create"]:false )
		{
		found = true;
		}
	    else if( !found )
		{
		index = index + 1;
		}
	    });
	if( partitions[index,"type"]:`primary == `extended )
	    {
	    e_idx = index;
	    found = false;
	    index = 0;
	    foreach(map p, partitions,
		``{
		if( !p["delete"]:false && p["region",0]:0 == cylinder &&
		    p["create"]:false && p["type"]:`primary != `extended )
		    {
		    found = true;
		    part = (map)eval(p);
		    }
		else if( !found )
		    {
		    index = index + 1;
		    }
		});
	    }
	cylinder = part["region",0]:0 + part["region",1]:0;
	y2milestone( "AdaptResize part:%1", part );
	y2milestone( "AdaptResize index:%1 e_idx:%2 cylinder:%3", index, e_idx,
	             cylinder );
	map pnew = (map) find(map p, partitions, ``(!p["delete"]:false &&
					    p["region",0]:0 == cylinder &&
					    p["create"]:false ));
	y2milestone( "AdaptResize pnew:%1", pnew );
	while( pnew != nil &&
	       (part["mount"]:"" == Partitions::BootMount() ||
	        part["fsid"]:0==Partitions::fsid_swap ||
	        part["region",1]:0 < (schange<0?(-1*schange):schange)) )
	    {
	    y2milestone( "AdaptResize pnew:%1", pnew );
	    part = (map)eval(pnew);
	    idx_list = add( idx_list, index );
	    found = false;
	    index = 0;
	    foreach(map p, partitions, ``{
	        y2milestone( "found:%1 index:%2 p=%3", found, index, p );
		if( p["delete"]:false == false &&
		    p["nr"]:(any)0 == pnew["nr"]:(any)0 )
		    {
		    found = true;
		    }
		else if( !found )
		    {
		    index = index + 1;
		    }
		});
	    cylinder = part["region",0]:0 + part["region",1]:0;
	    pnew = (map) find(map p, partitions, ``(p["delete"]:false==false &&
					    p["region",0]:0 == cylinder &&
					    p["create"]:false ));
	    }
	y2milestone( "AdaptResize idx:%1 list:%2", index, idx_list );
	partitions[index,"region",0] = partitions[index,"region",0]:0 - schange;
	partitions[index,"region",1] = partitions[index,"region",1]:0 + schange;
	if( partitions[index,"region",1]:0 <= 0 )
	    {
	    partitions[index,"region",1] = 1;
	    }
	if( e_idx>=0 )
	    {
	    partitions[e_idx,"region",0] = partitions[e_idx,"region",0]:0 - schange;
	    partitions[e_idx,"region",1] = partitions[e_idx,"region",1]:0 + schange;
	    if( partitions[e_idx,"region",1]:0 <= 0 )
		{
		partitions[e_idx,"region",1] = 1;
		}
	    }

	foreach(integer num, idx_list, ``{
	    partitions[num,"region",0] = partitions[num,"region",0]:0 - schange;
	    });
	}
    else
	{
	y2error( "AdaptResize this should not happen %1", partitions );
	}
    SetMainDevParam( maindev, "partitions", partitions );
    y2milestone( "AdaptResize maindev:%1 region:%2 change:%3", maindev,
                 region, schange );
    }


global define string PathToDestdir( string pt )
    ``{
    if( Installation::scr_destdir != "/" )
	{
	pt = Installation::scr_destdir + pt;
	}
    return( pt );
    }

//-----------------------------------------------------
//
// change an entry in /etc/fstab
//
global define void ChangeLineFstab( map entry )
    ``{
    string tabpath = PathToDestdir( "/etc/fstab" );
    if( Installation::scr_destdir != "/" )
	{
	if( SCR::Read( .target.size, tabpath )>= 0 )
	    SCR::Execute( .target.remove, tabpath );
	}
    map fstab = Partitions::GetFstab( tabpath );
    list lines = Storage::FindFstabLines( fstab, entry["mount"]:"",
                                          entry["spec"]:"", "x", "x" );
    list fstlist = [ entry["spec"]:"", entry["mount"]:"",
		     entry["vfstype"]:"", entry["mntops"]:"",
		     sformat("%1",entry["freq"]:0),
		     sformat("%1",entry["passno"]:0) ];
    y2milestone( "lines %1", lines );
    if( size(lines)==0 )
	{
	AsciiFile::AppendLine( fstab, fstlist );
	}
    else
	{
	integer field = 0;
	while( field<4 )
	    {
	    AsciiFile::ChangeLineField( fstab, lines[0]:-1, field,
					fstlist[field]:"" );
	    field = field+1;
	    }
	}
    string dir = entry["mount"]:"";
    if( substring( dir, 0, 1 )== "/" )
	{
	dir = PathToDestdir( dir );
	if( SCR::Read( .target.size, dir )<=0 )
	    {
	    SCR::Execute( .target.mkdir, dir );
	    }
	}
    AsciiFile::RewriteFile( fstab, tabpath );
    };

global define map MakeCdromFstabEntry( map cd )
    ``{
    map entry = FileSystems::GetFstabDefaultMap( "cdrom" );
    string cdmount = cd["linkname"]:"";
    entry["spec"] = cdmount;
    entry["mount"] = "/media/"+substring(cdmount,5);
    string enc = Storage::LangTypicalEncoding();
    if( !contains( [ "iso8859-1", "iso8859-15", "" ], enc ))
	{
	entry["mntops"] = entry["mntops"]:"" + ",iocharset=" + enc;
	}
    y2milestone( "ret %1", entry );
    return( entry );
    };

define void HandleModulesOnBoot( map<string,map> targetMap )
    ``{
    list<string> ml = filter( string e, 
                              (list<string>) splitstring( Misc::SysconfigRead( .sysconfig.kernel.MODULES_LOADED_ON_BOOT, "" ), " \t"), 
			      ``(size(e)>0));
    y2milestone( "HandleModulesOnBoot ml %1", ml );
    boolean need_cryptoloop = false;
    boolean need_fish2 = false;
    foreach( string disk, map e, targetMap,
	``{
	foreach( map p, e["partitions"]:[],
	    ``{
	    if( p["noauto"]:false && p["loop_fs"]:false )
		{
		if( p["crypt"]:"none" == "twofish256" )
		    need_cryptoloop = true;
		else if( find( p["crypt"]:"none", "twofish")==0 )
		    need_fish2 = true;
		}
	    });
	});
    y2milestone( "HandleModulesOnBoot need_fish2 %1 need_cryptoloop %2", need_fish2,
                 need_cryptoloop );
    if( need_fish2 && find( string e, ml, ``(e=="loop_fish2"))==nil )
	{
	ml = add( ml, "loop_fish2" );
	SCR::Write( .sysconfig.kernel.MODULES_LOADED_ON_BOOT,
		    mergestring( ml, " " ) );

	}
    if( need_cryptoloop && find( string e, ml, ``(e=="cryptoloop"))==nil )
	{
	ml = add( ml, "cryptoloop" );
	SCR::Write( .sysconfig.kernel.MODULES_LOADED_ON_BOOT,
		    mergestring( ml, " " ) );
	}
    if( need_cryptoloop && find( string e, ml, ``(e=="twofish"))==nil )
	{
	ml = add( ml, "twofish" );
	SCR::Write( .sysconfig.kernel.MODULES_LOADED_ON_BOOT,
		    mergestring( ml, " " ) );

	}
    }

global define void WriteFstab( map<string,map> targetMap )
    ``{
    y2milestone( "WriteFstab called" );

    include "partitioning/write_fstab.ycp";

    map<string,map> tg = eval(targetMap);
    if( Stage::initial () )
	{
	StorageDevices::MakeCDLinks();
	}
    write_fstab( tg, StorageDevices::ZipDrives, StorageDevices::cddrives );
    HandleModulesOnBoot( targetMap );
    }

global define map GetS390DeviceMap( map<string,map> targetMap )
    ``{
    integer num = 0;
    string alph = "abcdefghijklmnopqrstuvwxyz";
    string newdev = "";
    string param = "";
    map ret =  $[];
    list<map> dasd = (list<map>) SCR::Read(.proc.dasddev);

    foreach( string key, map value, targetMap, ``{
        list<map> part = value["partitions"]:[];
	if( find( map p, part, ``( p["loop_fs"]:false ||
				size(p["lvm_group"]:"")>0 ||
				size(p["raid_name"]:"")>0 ||
				size(p["mount"]:"")>0)) != nil )
	    {
	    newdev = "/dev/dasd";
	    if( num < 26 )
		{
		newdev = newdev + substring( alph, num, 1 );
		}
	    else
		{
		newdev = newdev + substring( alph, (num/26)-1, 1 ) +
		         substring( alph, num%26, 1 );
		}
	    ret[key] = newdev;
	    map ddev = find( map p, dasd,
	                     ``( p["name"]:"" == substring( key, 5 )));
	    if( ddev != nil )
		{
		param = param + ddev["address"]:"";
		param = param + ",";
		}
	    num = num + 1;
	    }
	if( size(param)>0 && substring(param, size(param)-1, 1)=="," )
	    {
	    param = substring( param, 0, size(param)-1 );
	    }
	ret["param"] = param;
	});

    return(ret);
    };

global define string MapS390Device( string device, map device_map )
    ``{
    string ret = device;
    if( find( device, "/dev/dasd" ) == 0 )
	{
	map dev = Storage::GetDiskPartition( device );
	string disk = dev["disk"]:"";
	if( disk != "" && device_map[disk]:"" !="" )
	    {
	    ret = Storage::GetDeviceName( device_map[disk]:"", dev["nr"]:(any)0 );
	    }
	}
    return( ret );
    };

global define map<string,map> SpecialBootHandling( map<string,map> tg )
    ``{
    boolean have_ppc_boot = false;
    foreach( string dev, map disk, tg,
	``{
	foreach(map part, disk["partitions"]:[],
	    ``{
	    if( !part["delete"]:false && !have_ppc_boot &&
	        part["fsid"]:0 == Partitions::fsid_prep_chrp_boot &&
		size(part["mount"]:"")==0 && part["create"]:false )
		{
		have_ppc_boot = true;
		}
	    });
	});
    y2milestone( "SpecialBootHandling: have_ppc_boot:%1", have_ppc_boot );
    foreach( string dev, map disk, tg,
	``{
	list new_part = [];
	foreach(map part, disk["partitions"]:[],
	    ``{
	    // convert a mount point of /boot to a 41 PReP boot partition
	    if( Partitions::PrepBoot() && !part["delete"]:false &&
		part["mount"]:"" == Partitions::BootMount() && !have_ppc_boot )
		{
		integer id = Partitions::fsid_prep_chrp_boot;
		part["format"] = false;
		part["mount"] = "";
		part["fstype"] = Partitions::FsIdToString( id );
		part["prep_install"] = true;
		if( !part["create"]:false && part["fsid"]:0 != id )
		    {
		    part["ori_fsid"] = part["fsid"]:0;
		    part["change_fsid"] = true;
		    }
		part["fsid"] = id;
		y2milestone( "modified Prep part=%1", part );
		}
	    if( Arch::board_mac () && !part["delete"]:false &&
		part["mount"]:"" == Partitions::BootMount() )
		{
		integer id = Partitions::fsid_mac_hfs;
		part["mount"] = "";
		part["fstype"] = Partitions::FsIdToString( id );
		part["fsid"] = id;
		part["used_fs"] = `hfs;
		part["detected_fs"] = `hfs;
		y2milestone( "modified hfs part=%1", part );
		}
	    if( Arch::ia64 () && !part["delete"]:false &&
		part["mount"]:"" == Partitions::BootMount() )
		{
		integer id = Partitions::fsid_gpt_boot;
		part["fsid"] = id;
		part["fstype"] = Partitions::FsIdToString( id );
		if( !part["create"]:false &&
		    contains( [`fat32, `fat16, `vfat], part["detected_fs"]:`none ))
		    {
		    part["format"] = false;
		    }
		y2milestone( "modified GPT boot part=%1", part );
		}
	    new_part = add( new_part, part );
	    });
	tg[dev,"partitions"] = new_part;
	});
    return( tg );
    }

global define list<list<string> > AutodetectMultipathRaid( map<string,map> tg )
    ``{
    list<list<string> > ret = [];
    map<string, list> disks = (map<string, list>) $[];
    foreach(string dev, map disk, tg,
	``{
	string id = disk["unique"]:"";
	integer pos = find( id, "." );
	if( pos >= 0 )
	    {
	    id = substring( id, pos+1 );
	    if( haskey( disks, id ) )
		{
		disks[id] = add( disks[id]:[], dev );
		}
	    else
		{
		disks[id] = [ dev ];
		}
	    }
	});
    disks = (map<string, list>) filter(string key, list entry, disks, ``(size(entry)>=2) );
    y2milestone( "disks %1", disks );
    foreach( string key, list entry, disks,
	``{
	foreach(map p, tg[entry[0]:"","partitions"]:[],
	    ``{
	    boolean ok = true;
	    list<string> dl = [];
	    foreach(string disk, (list<string>)entry,
		``{
		string dev = GetDeviceName( disk, p["nr"]:(any)0 );
		map p1 = GetPartition( tg, dev );
		if( p1["type"]:`primary == `extended ||
		    size(p1["raid_name"]:"")>0 ||
		    size(p1["mount"]:"")>0 ||
		    size(p1["vg_name"]:"")>0 )
		    {
		    ok = false;
		    }
		dl = add( dl, dev );
		});
	    if( ok )
		{
		ret = add( ret, dl );
		}
	    });
	});
    y2milestone( "ret %1", ret );
    return( ret );
    }

global define boolean PerformLosetup( map& loop, boolean format )
    ``{
    boolean crypt_ok = false;
    string pwd = loop["passwd"]:"";
    loop = (map)filter( string k, any val, (map<string,any>)loop, ``(k!="passwd"));
    y2milestone( "PerformLosetup format %1 loop %2", format, loop );

    string tmpf = SaveDumpPath( "tmpf" );
    y2milestone( "PerformLosetup tmpf %1", tmpf );
    SCR::Write( .target.string, tmpf, pwd );

    string cmd = FileSystems::GetLosetupCmd( loop, tmpf );
    map r = (map)SCR::Execute( .target.bash_output, cmd );
    y2milestone( "PerformLosetup r %1", r );
    crypt_ok = r["exit"]:1 == 0;
    if( crypt_ok && !format && find( loop["encryption"]:"", "twofish")==0 )
	{
	string enc = FileSystems::DetectLoopEncryption( loop, tmpf );
	y2milestone( "PerformLosetup enc %1", enc );
	if( size(enc)>0 )
	    {
	    loop["encryption"] = enc;
	    crypt_ok = true;
	    }
	}
    SCR::Execute( .target.remove, tmpf );
    y2milestone( "PerformLosetup ret %1", crypt_ok );
    return( crypt_ok );
    }

global define boolean SetCryptLoop( map& part )
    ``{
    string crypt_passwd = GetClassifiedUserSettings()[part["crypt_key"]:""]:"";
    string loop_dev = part["loop_dev"]:"";

    boolean crypt_ok = size(loop_dev)>0;

    y2milestone( "SetCryptLoop crypt %1 %2", crypt_ok, loop_dev );

    SCR::UnmountAgent (.proc.modules);
    map loaded_modules = (map) SCR::Read(.proc.modules);
    if( part["loop_fs"]:false )
	{
	if( part["crypt"]:"" == "twofish" )
	    {
	    if( !haskey( loaded_modules, "loop_fish2" ) )
		{
		crypt_ok = (boolean) SCR::Execute( .target.modprobe, 
		                                  "loop_fish2", "");
		}
	    }
       else if( part["crypt"]:"" == "twofishSL92" )
            {
            if( !haskey( loaded_modules, "loop_fish2" ) )
                {
                crypt_ok = (boolean) SCR::Execute( .target.modprobe,
                                                  "loop_fish2", "");
                }
            }
	else if( find(part["crypt"]:"","twofish")==0 )
	    {
	    if( !haskey( loaded_modules, "cryptoloop" ) )
		{
		crypt_ok = (boolean) SCR::Execute( .target.modprobe, 
		                                   "cryptoloop", "");
		}
	    if( crypt_ok && !haskey( loaded_modules, "twofish" ) )
		{
		crypt_ok = (boolean) SCR::Execute( .target.modprobe, 
		                                   "twofish", "");
		}
	    }
	}
    y2milestone( "SetCryptLoop crypt mp: %1", crypt_ok);

    boolean retry = false;

    do
	{
	if( crypt_ok )
	    {
	    map setloop =
		$[ "encryption"    : part["crypt"]:"twofish",
		   "passwd"        : crypt_passwd,
		   "loop_dev"      : loop_dev,
		   "partitionName" : part["device"]:"" ];
	    if( size(part["itercountk"]:"")>0 )
		{
		setloop["itercountk"] = part["itercountk"]:"";
		}
	    if( size(part["phash"]:"")>0 )
		{
		setloop["phash"] = part["phash"]:"";
		}
	    if( part["type"]:`none == `loop )
		{
		setloop["partitionName"] = PathToDestdir( part["fpath"]:"" );
		}
	    crypt_ok = PerformLosetup( setloop, part["format"]:false );
	    y2milestone( "after  PerformLosetup loop:%1", setloop );
	    if( setloop["encryption"]:"" != part["crypt"]:"twofish" )
		{
		y2milestone( "setting new encryption to %1", 
		             setloop["encryption"]:"" );
		part["crypt"] = setloop["encryption"]:"";
		}
	    }
	if( !crypt_ok )
	    {
	    retry = false;
	    symbol ret=`yes;
	    ret = Popup::AnyQuestion3( Popup::NoHeadline(),
		    // popup text %1 is replaced by partition name e.g. /dev/hda1
		    sformat(_("Error crypting the file system %1."),
			    part["device"]:""),
		    Label::ContinueButton(), Label::AbortButton(),
		    Label::RetryButton(), `focus_yes);
	    if (ret == `retry)
		{
		retry=true;
		}
	    else if( ret != `no )
		{
		//set to ok, to suppress popup about formatting error
		crypt_ok = true;
		}
	    }
	}
    while( !crypt_ok || retry );
    if( !crypt_ok && size(loop_dev)>0 )
	{
	SCR::Execute( .target.bash, "/sbin/losetup -d "+loop_dev );
	}

    y2milestone( "ret %1", crypt_ok);
    return( crypt_ok );
    }

global define boolean DiskmapNeeded()
    ``{
    boolean ret = false;
    map<string,map> real_disks = filter( string k, map e, GetTargetMap(), ``(IsRealDisk( k, e )) );
    list<string> disks = (list<string>) maplist( string k, map e, real_disks, ``(k));
    y2milestone( "disks %1", disks );
    boolean scsi_disk = false;
    boolean ide_disk = false;
    foreach( string k, disks,
	``{
	if( find( k, "/dev/sd" )==0 )
	    {
	    scsi_disk = true;
	    }
	else if( find( k, "/dev/hd" )==0 )
	    {
	    ide_disk = true;
	    }
	else
	    {
	    ret = true;
	    }
	});
    ret = ret || (scsi_disk && ide_disk);
    if( !ret && ide_disk )
	{
	string abc = "abcdefghijklmnopqrstuvwxyz";
	integer idx = 0;
	foreach( string k, disks,
	    ``{
	    y2milestone( "dev %1 abc %2", substring(k, 7, 1),
	                 substring(abc, idx, 1));
	    if( substring(k, 7, 1) != substring(abc, idx, 1) )
		{
		ret = true;
		}
	    idx = idx+1;
	    });
	}
    y2milestone( "ret %1 disks %2 ide %3 scsi %4", ret, size(disks), ide_disk,
                 scsi_disk );
    return( ret );
    };

global define boolean UseLilo()
    ``{
    boolean ret = false;
    y2milestone( "ret %1", ret );
    return( ret );
    }

global define void DestroyLvmOnAllDisks()
    ``{
    y2milestone( "DestroyLvmOnAllDisks called" );
    map<string,map> tg = GetTargetMap();
    SCR::Write( .lvm.deactivate, "" );
    foreach( any disk, map data, tg,
	``{
	foreach( map p, data["partitions"]:[],
	    ``{
	    if( p["fsid"]:0==Partitions::fsid_lvm && !data["is_lvm_vg"]:false )
		{
		string cmd = sformat( "echo y | pvcreate -ff %1",
		                      p["device"]:"" );
		y2milestone( "cmd %1", cmd );
		SCR::Execute(.target.bash, cmd );
		}
	    });
	data["partitions"] =
	    maplist( map p, data["partitions"]:[],
		``{
		p = filter( string k, any e, (map<string,any>)p,
		            ``(k!="lvm_group" && k!="lvm_mp_pv" &&
			       k!="lvm_size_bytes"));
		return( p );
		});
	});
    tg = filter( string k, map e, tg, ``( !e["is_lvm_vg"]:false ));
    SetTargetMap( tg );
    SCR::Write( .lvm.activate, "" );
    };

global define void DestroyMdOnAllDisks()
    ``{
    y2milestone( "DestroyMdOnAllDisks called" );
    map<string,map> tg = GetTargetMap();
    list raid_names = [];
    SCR::Write( .md.deactivate, "" );
    foreach( string disk, map data, tg,
	``{
	if( IsRealDisk( disk, data ) )
	    {
	    foreach( map p, data["partitions"]:[],
		``{
		if( p["fsid"]:0==Partitions::fsid_raid )
		    {
		    raid_names = add( raid_names, p["device"]:"" );
		    }
		});
	    data["partitions"] =
		maplist( map p, data["partitions"]:[],
		    ``{
		    p = filter( string k, any e, (map<string,any>)p, ``(k!="raid_name"));
		    return( p );
		    });
	    }
	});
    if( size(raid_names)>0 )
	{
	string cmd = sformat( "/sbin/mdadm --zero-superblock %1",
	                      mergestring( (list<string>)raid_names, " " ));
	y2milestone( "executing cmd %1", cmd );
	SCR::Execute(.target.bash, cmd );
	}
    tg = filter( string k, map e, tg, ``( k != "/dev/md" ));
    SetTargetMap( tg );
    SCR::Write( .md.activate, "" );
    };

global define list<string> GetDirPatterns( string dir, list patterns )
    ``{
    list<string> ret = [];
    string cmd = sformat( "cd %1 && (ls %2 2>/dev/null)", dir,
                          mergestring( (list<string>)patterns, " "));
    map out = (map) SCR::Execute( .target.bash_output, cmd );
    ret = splitstring( out["stdout"]:"", "\n" );
    ret = filter( string e, ret, ``(size(e)>0) );
    ret = maplist( string e, ret, ``(dir+"/"+e));
    y2milestone( "dir %1 pat %2", dir, patterns );
    y2milestone( "ret %1", ret );
    return( ret );
    }

global define map GetBootPartition( string disk )
    ``{
    map ret = $[];
    map tg = GetTargetMap();
    ret = filter( map p, tg[disk,"partitions"]:[], 
                  ``(p["boot"]:false&&!p["delete"]:false))[0]:$[];
    y2milestone( "disk:%1 ret:%2", disk, ret );
    return( ret );
    }

global define void UpdateFstabSubfs()
    ``{
    y2milestone( "updating subfs for cdrom and floppy" );
    string tabpath = PathToDestdir( "/etc/fstab" );
    map fstab = Partitions::GetFstab( tabpath );
    integer line = 0;
    while( line<=AsciiFile::NumLines( fstab ) )
	{
	map l = AsciiFile::GetLine( fstab, line );
	if( find( l["fields",1]:"", "/media/floppy" )==0 )
	    {
	    AsciiFile::ChangeLineField( fstab, line, 2, "subfs" );
	    AsciiFile::ChangeLineField( fstab, line, 3, FileSystems::GetFstabDefaultMntops("floppy") );
	    }
	else if( find( l["fields",1]:"", "/media/cdrom" )==0 ||
		 find( l["fields",1]:"", "/media/dvd" )==0 ||
		 find( l["fields",1]:"", "/media/cdrecorder" )==0 ||
		 find( l["fields",1]:"", "/media/dvdrecorder" )==0 ||
		 find( l["fields",1]:"", "/cdrom" )==0 ||
		 find( l["fields",1]:"", "/dvd" )==0 ||
		 find( l["fields",1]:"", "/cdrecorder" )==0 ||
		 find( l["fields",1]:"", "/dvdrecorder" )==0 ) 
	    {
	    AsciiFile::ChangeLineField( fstab, line, 2, "subfs" );
	    list<string> opts = splitstring( l["fields",3]:"", "," );
	    opts = filter( string e, opts, ``(size(e)>0 ));
	    y2milestone( "old opts %1", opts );
	    opts = filter( string e, opts, 
			   ``(!contains( ["noauto","ro","user","exec"], e )));
	    y2milestone( "old opts %1", opts );
	    string nopts = FileSystems::GetFstabDefaultMntops("cdrom");
	    if( size(opts)>0 )
		nopts = nopts + "," + mergestring( opts, "," );
	    y2milestone( "new opts %1", opts );
	    AsciiFile::ChangeLineField( fstab, line, 3, nopts );
	    }
	line = line+1;
	}
    AsciiFile::RewriteFile( fstab, tabpath );
    }

global string HdToIseries( string input )
    ``{
    string ret = input;
    string regex = "/dev/hd[a-z][0-9]*";
    if( regexpmatch( input, regex ))
	{
	ret = "/dev/iseries/vd" + substring( ret, 7 );
	}
    y2milestone( "HdToIseries input:%1 ret:%2", input, ret );
    return( ret );
    }

global string HdDiskMap( string input, map diskmap )
    ``{
    string ret = input;
    map d = GetDiskPartition( input );
    if( haskey( diskmap, d["disk"]:"" ))
	{
	ret = GetDeviceName( diskmap[d["disk"]:""]:"", d["nr"]:(any)0 );
	}
    y2milestone( "HdDiskMap input:%1 ret:%2", input, ret );
    return( ret );
    }

global define void UpdateFstabIseriesVd()
    ``{
    y2milestone( "UpdateFstabIseriesVd updating hdx to iseries/vdx" );
    string tabpath = PathToDestdir( "/etc/fstab" );
    map fstab = Partitions::GetFstab( tabpath );
    integer line = 0;
    string n = "";
    while( line<=AsciiFile::NumLines( fstab ) )
	{
	map l = AsciiFile::GetLine( fstab, line );
	n = HdToIseries( l["fields",0]:"" );
	if( n != l["fields",0]:"" )
	    {
	    AsciiFile::ChangeLineField( fstab, line, 0, n );
	    }
	line = line+1;
	}
    AsciiFile::RewriteFile( fstab, tabpath );
    tabpath = PathToDestdir( "/etc/cryptotab" );
    map crtab = Partitions::GetCrypto( tabpath );
    line = 0;
    while( line<=AsciiFile::NumLines( crtab ) )
	{
	map l = AsciiFile::GetLine( crtab, line );
	n = HdToIseries( l["fields",1]:"" );
	if( n != l["fields",1]:"" )
	    {
	    AsciiFile::ChangeLineField( crtab, line, 1, n );
	    }
	line = line+1;
	}
    AsciiFile::RewriteFile( crtab, tabpath );
    }

global define void UpdateCdromLinks( map diskmap )
    ``{
    y2milestone( "UpdateCdromLinks map %1", diskmap );
    foreach( string link, StorageDevices::TypeNames,
	``{
	string dev = "/dev/" + link;
	string cont = (string)SCR::Read( .target.symlink, dev );
	if( cont!=nil && find( cont, "/dev/") != 0 )
	    cont = "/dev/" + cont;
	y2milestone( "UpdateCdromLinks dev %1 cont %2", dev, cont );
	if( cont!=nil && haskey( diskmap, cont ) && size(diskmap[cont]:"")>0 )
	    {
	    y2milestone( "Change symlink %1 from %2 -> %3", dev, cont,
	                 diskmap[cont]:"" );
	    SCR::Execute( .target.remove, dev );
	    SCR::Execute( .target.symlink, substring(diskmap[cont]:"",5), dev );
	    }
	});
    }

global define void UpdateFstabDiskmap( map diskmap )
    ``{
    y2milestone( "UpdateFstabdiskmap map %1", diskmap );
    string tabpath = PathToDestdir( "/etc/fstab" );
    map fstab = Partitions::GetFstab( tabpath );
    integer line = 0;
    string n = "";
    while( line<=AsciiFile::NumLines( fstab ) )
	{
	map l = AsciiFile::GetLine( fstab, line );
	n = HdDiskMap( l["fields",0]:"", diskmap );
	if( n != l["fields",0]:"" )
	    {
	    AsciiFile::ChangeLineField( fstab, line, 0, n );
	    }
	line = line+1;
	}
    AsciiFile::RewriteFile( fstab, tabpath );
    tabpath = PathToDestdir( "/etc/cryptotab" );
    map crtab = Partitions::GetCrypto( tabpath );
    line = 0;
    while( line<=AsciiFile::NumLines( crtab ) )
	{
	map l = AsciiFile::GetLine( crtab, line );
	n = HdDiskMap( l["fields",1]:"", diskmap );
	if( n != l["fields",1]:"" )
	    {
	    AsciiFile::ChangeLineField( crtab, line, 1, n );
	    }
	line = line+1;
	}
    AsciiFile::RewriteFile( crtab, tabpath );
    }

global define void UpdateCryptoType()
    ``{
    y2milestone( "UpdateCryptoType" );
    string tabpath = PathToDestdir( "/etc/fstab" );
    map fstab = Partitions::GetFstab( tabpath );
    integer line = 0;
    integer pos = 0;
    string search = "encryption=twofish256";
    while( line<=AsciiFile::NumLines( fstab ) )
	{
	map l = AsciiFile::GetLine( fstab, line );
	pos = find( l["fields",3]:"", search );
	if( pos >= 0 )
	    {
	    string new = substring( l["fields",3]:"", 0, pos );
	    new = new + "encryption=twofishSL92";
	    new = new + substring( l["fields",3]:"", pos+size(search) );
	    y2milestone( "new options line in %1 is %2", l, new );
	    AsciiFile::ChangeLineField( fstab, line, 3, new );
	    }
	line = line+1;
	}
    AsciiFile::RewriteFile( fstab, tabpath );
    tabpath = PathToDestdir( "/etc/cryptotab" );
    map crtab = Partitions::GetCrypto( tabpath );
    line = 0;
    while( line<=AsciiFile::NumLines( crtab ) )
	{
	map l = AsciiFile::GetLine( crtab, line );
	if( l["fields",4]:"" == "twofish256" )
	    {
	    y2milestone( "set twofishSL92 in line %1", l );
	    AsciiFile::ChangeLineField( crtab, line, 4, "twofishSL92" );
	    }
	line = line+1;
	}
    AsciiFile::RewriteFile( crtab, tabpath );
    }

global define void UpdateFstabUsbdevfs()
    ``{
    y2milestone( "UpdateFstabUsbdevfs updating usbdevfs to usbfs" );
    boolean changed = false;
    string tabpath = PathToDestdir( "/etc/fstab" );
    map fstab = Partitions::GetFstab( tabpath );
    integer line = 0;
    while( line<=AsciiFile::NumLines( fstab ) )
	{
	map l = AsciiFile::GetLine( fstab, line );
	if( l["fields",2]:"" == "usbdevfs" )
	    {
	    AsciiFile::ChangeLineField( fstab, line, 2, "usbfs" );
	    changed = true;
	    }
	line = line+1;
	}
    if( changed )
	{
	y2milestone( "UpdateFstabUsbdevfs changed" );
	AsciiFile::RewriteFile( fstab, tabpath );
	}
    }


define map BuildDiskmap( map oldv )
    ``{
    map d = (map)SCR::Read( .target.stat, 
                            Installation::destdir + "/var/lib/hardware" );
    if( d["isdir"]:false && oldv != DiskMapVersion )
    if( oldv != DiskMapVersion )
	{
	DiskMap = $[];
	string cmd = "cd /var/lib/hardware/unique-keys && ";
	cmd = cmd + " ln -s " + Installation::destdir + "/var/lib/hardware/* ";
	cmd = cmd + Installation::destdir + "/var/lib/hardware/unique-keys/* .";
	y2milestone( "BuildDiskmap cmd %1", cmd );
	map bo = (map)SCR::Execute (.target.bash_output, cmd );
	y2milestone( "BuildDiskmap bo %1", bo );
	cmd = "hwinfo --map";
	y2milestone( "BuildDiskmap cmd %1", cmd );
	bo = (map)SCR::Execute (.target.bash_output, cmd );
	y2milestone( "BuildDiskmap bo %1", bo );
	if( bo["exit"]:1==0 && size(bo["stdout"]:"")>0 )
	    {
	    list<string> lines = splitstring( bo["stdout"]:"", "\n" );
	    foreach( string line, lines,
		``{
		list<string> disks = filter( string d, 
		                             splitstring( line, " \t" ),
					     ``(size(d)>0));
		if( size(disks)>1 )
		    {
		    integer index = 1;
		    while( index<size(disks) )
			{
			DiskMap[disks[index]:""] = disks[0]:"";
			index = index+1;
			}
		    }
		});
	    }
	if( bo["exit"]:1==0 )
	    DiskMapVersion = oldv;
	else
	    DiskMapVersion = $[];
	cmd = "find /var/lib/hardware -type l | xargs rm";
	y2milestone( "BuildDiskmap cmd %1", cmd );
	bo = (map)SCR::Execute (.target.bash_output, cmd );
	y2milestone( "BuildDiskmap bo %1", bo );
	y2milestone( "BuildDiskmap DiskMap %1", DiskMap );
	y2milestone( "BuildDiskmap DiskMapVersion %1", DiskMapVersion );
	}
    return( DiskMap );
    }

global define void ExecuteHwcfgDisk()
    ``{
    string cmd = "/usr/sbin/gen-hwcfg-disk.sh";
    y2milestone( "ExecuteHwcfgDisk cmd %1", cmd );
    map bo = (map)SCR::Execute (.target.bash_output, cmd );
    y2milestone( "ExecuteHwcfgDisk bo %1", bo );
    };

global define void Update( map oldv, map newv )
    ``{
    y2milestone( "Update old:%1 new:%2", oldv, newv );
    if( oldv["major"]:0<9 )
	{
	UpdateFstabUsbdevfs();
	}
    map dm = BuildDiskmap( oldv );
    if( size(dm)>0 )
	{
	UpdateFstabDiskmap( dm );
	}
    if( oldv["major"]:0<9 || (oldv["major"]:0==9 && oldv["minor"]:0<=2))
	{
	StorageDevices::MakeCDLinks();
	Storage::UpdateCryptoType();
	}
    if( oldv["major"]:0<9 || (oldv["major"]:0==9 && oldv["minor"]:0==0))
	{
	UpdateFstabSubfs();
	if( Arch::board_iseries () )
	    {
	    UpdateFstabIseriesVd();
	    }
	string cmd = "cd / && /sbin/insserv -r /etc/init.d/boot.evms";
	y2milestone( "Update cmd %1", cmd );
	map bo = (map)SCR::Execute (.target.bash_output, cmd );
	y2milestone( "Update bo %1", bo );
	}
    ExecuteHwcfgDisk();
    }

global define list<string> GetTranslatedDevices( map oldv, map newv, 
						 list<string> names )
    {
    y2milestone( "GetTranslatedDevices old:%1 new:%2", oldv, newv );
    y2milestone( "GetTranslatedDevices names %1", names );
    list<string> ret = names;
    map dm = BuildDiskmap( oldv );
    if( size(dm)>0 )
	{
	ret = maplist( string n, names, ``(HdDiskMap( n, dm )));
	}
    if( (oldv["major"]:0<9 || (oldv["major"]:0==9 && oldv["minor"]:0==0)) &&
        Arch::board_iseries () )
	{
	ret = maplist( string n, names, ``(HdToIseries( n )));
	}
    y2milestone( "GetTranslatedDevices ret %1", ret );
    return( ret );
    }

global define list GetUsedLvmGroups( map<string,map> tg )
    ``{
    list groups = [];
    foreach( string disk, map data, tg,
	``{
	if( data["is_lvm_vg"]:false && !data["delete"]:false &&
	    size( filter( map p, data["partitions"]:[], 
	                  ``(size(p["mount"]:"")>0 ) )) > 0 )
	    {
	    y2milestone( "GetUsedLvmGroups %1", 
	                 filter( map p, data["partitions"]:[],
				 ``(size(p["mount"]:"")>0 ) ) );
	    groups = add( groups, substring( disk, 5 ) );
	    }
	});
    y2milestone( "GetUsedLvmGroups ret %1", groups );
    return( groups );
    };

/**
 * Get used real disks
 * @param tg Target map
 * @return disks List of disks
 */
global define list<string> GetUsedRealDisks( map<string,map> tg )
    ``{
    list<string> disks = [];
    list lvmgr = GetUsedLvmGroups( tg );
    list mdlist = [];
    foreach( map p, tg["/dev/md","partitions"]:[],
	``{
	if( size(p["mount"]:"")>0  ||
	    contains( lvmgr, p["lvm_group"]:"" ) )
	    {
	    mdlist = add( mdlist, p["device"]:"" );
	    }
	});
    foreach( string disk, map data, tg,
	``{
	if( IsRealDisk( disk, data ) && 
	    size( filter( map p, data["partitions"]:[], 
	                  ``(size(p["mount"]:"")>0 ||
			     contains( mdlist, p["raid_name"]:"" )  ||
			     contains( lvmgr, p["lvm_group"]:"" ) ) )) > 0 )
	    {
	    disks = add( disks, disk );
	    }
	});
    y2milestone( "GetUsedRealDisks ret %1", disks );
    return( disks );
    };

global define list<string> GetEvmsRealDisk( map<string,map> tg, map p )
    ``{
    list<string> rdisk = [];
    string name = "";
    if( size(p["device"]:"")>10 )
	name = substring( p["device"]:"", 10 );
    if( find( name, "lvm/" ) == 0 )
	{
	name = substring( name, 0, findlastof( name, "/" ));
	}
    y2milestone( "GetEvmsRealDisk name is %1", name );
    foreach( string disk, map data, tg,
	``{
	if( size(name)>0 && 
	    (IsRealDisk( disk, data ) || disk=="/dev/md") &&
	    size( filter( map p, data["partitions"]:[], 
	                  ``(p["evms_vol"]:"" == name)))>0 )
	    {
	    rdisk = (list<string>)union( rdisk, [ disk ] );
	    }
	});
    if( size(rdisk)==0 && !p["evms_native"]:false )
	{
	map d = GetDiskPartition( "/dev/" + name );
	if( haskey( tg, d["disk"]:"" ))
	    {
	    rdisk = [ d["disk"]:"" ];
	    }
	}
    y2milestone( "GetEvmsRealDisk %1 is %2", p["device"]:"", rdisk );
    return( rdisk );
    }

global define list<string> GetUsedEvmsDisks( map<string,map> tg )
    ``{
    list<string> disks = [];
    list mdlist = [];
    foreach( string disk, map data, tg,
	``{
	if( find( disk, "/dev/evms" )==0 )
	    {
	    foreach( map p, data["partitions"]:[],
		``{
		if( size(p["mount"]:"")>0 )
		    {
		    list<string> dl = GetEvmsRealDisk( tg, p );
		    foreach( string d, dl,
			``{
			if( find( d, "/dev/md" ) == 0 )
			    {
			    list<string> ndl = [];
			    foreach( string dd, map pp, tg,
				``{
				if( pp["raid_name"]:"" == d )
				    {
				    ndl = add( ndl, dd );
				    }
				});
			    disks = (list<string>)union( disks, ndl );
			    }
			else
			    {
			    disks = (list<string>)add( disks, d );
			    }
			});
		    }
		});
	    }
	});
    disks = sort( disks );
    y2milestone( "GetUsedEvmsDisks ret %1", disks );
    return( disks );
    };

global define boolean CheckEvmsNonEvms()
    ``{
    boolean ret = true;
    if( DoCheckEvmsNonEvms )
	{
	map<string,map> tg = GetTargetMap();
	list<string> evms = GetUsedEvmsDisks( tg );
	list<string> nonevms = GetUsedRealDisks( tg );
	evms = filter( string d, evms, ``(contains( nonevms, d )));
	y2milestone( "CheckEvmsNonEvms intersec %1", evms );
	ret = size(evms)==0;
	}
    y2milestone( "CheckEvmsNonEvms ret %1", ret );
    return( ret );
    };

global define boolean CheckEvmsLvm()
    ``{
    boolean ret = true;
    if( DoCheckEvmsLvm )
	{
	map<string,map> tg = GetTargetMap();
	list evms = GetUsedEvmsDisks( tg );
	list lvms = GetUsedLvmGroups( tg );
	ret = size(evms)==0 || size(lvms)==0;
	}
    y2milestone( "CheckEvmsLvm ret %1", ret );
    return( ret );
    };

global define void FinishInstall()
    ``{
    map<string,map> tg = GetTargetMap();
    HandleModulesOnBoot( tg );
    list evms = GetUsedEvmsDisks( tg );
    y2milestone( "FinishInstall evms %1", evms );
    if( size(evms)>0 )
	{
	string cmd = "cd / && /sbin/insserv /etc/init.d/boot.evms";
	y2milestone( "FinishInstall cmd %1", cmd );
	map bo = (map)SCR::Execute (.target.bash_output, cmd );
	y2milestone( "FinishInstall bo %1", bo );
	list<string> nonevms = GetUsedRealDisks( tg );
	nonevms = filter( string d, nonevms, ``(!contains( evms, d )));
	if( size(nonevms)>0 && SCR::Read( .target.size, "/etc/evms.conf" )>=0 )
	    {
	    map evmsconf = $[];
	    AsciiFile::ReadFile( evmsconf, "/etc/evms.conf" );
	    boolean found = false;
	    integer i = 1;
	    string regex = "^[ \t]*exclude[ \t]*=";
	    while( i<=AsciiFile::NumLines(evmsconf) && !found )
		{
		map l = AsciiFile::GetLine( evmsconf, i );
		if( regexpmatch( l["line"]:"", regex ))
		    {
		    found = true;
		    string li = "\texclude = [ " + mergestring( nonevms, " " ) +
		                " ]";
		    y2milestone( "FinishInstall li = %1", li );
		    evmsconf["l",i,"line"] = li;
		    evmsconf["l",i,"buildline"] = false;
		    AsciiFile::RewriteFile( evmsconf, "/etc/evms.conf" );
		    }
		i = i+1;
		}
	    }
	}
    ExecuteHwcfgDisk();
    y2milestone( "FinishInstall" );
    }

}


