/**
 * Module:		inst_prepdisk.ycp
 *
 * Authors:		Mathias Kettner (kettner@suse.de) (initial)
 *			Stefan Schubert (schubi@suse.de)
 *			Klaus Kaempf (kkaempf@suse.de)
 *
 * Purpose:
 * Displays a progress bar showing progress of disk preparation.
 * The user has the opportunity to cancel the installation. The
 * disks are partitioned. Swap is created and used. File systems
 * are created for the new partitions. Mount points are created
 * and mounted for the targets / and /boot.
 *
 *
 * SCR:	Write(.disk + scrpath + .partitions, targetpartitions)
 *	Execute (.target.mkdir, [ <mountpoint>, 0755] )
 *	Execute (.target.mount, [<device>, <mountpoint>] )
 *
 *
 * possible return values: `back, `abort `next

 *
 * $Id: inst_prepdisk.ycp 22507 2005-03-14 13:25:27Z fehr $
 */

 // TODO: - check for errors on non i386
 //       - lvm?

{
  textdomain "storage";
  import "Arch";
  import "Initrd";
  import "Installation";
  import "Mode";
  import "Wizard";
  import "Popup";
  import "Storage";
  import "FileSystems";
  import "Hotplug";
  import "Partitions";
  import "StorageClients";
  import "Report";
  import "Label";
  import "Linuxrc";

  if (Mode::update ())
    return `auto;

  include "partitioning/partition_defines.ycp";
  include "partitioning/target_modify.ycp";
  include "partitioning/raid_lib.ycp";
  include "partitioning/lvm_pv_lib.ycp";
  include "partitioning/lvm_lib.ycp";

  //integer loop_dev_nb	   = 0;
  boolean crypt_ok         = true;
  boolean reboot_necessary = false;
  boolean reboot           = false;

  map<integer,map>     modify_targets        = (map<integer,map>)Storage::GetModifyTargets();
  boolean test_mode		= Mode::test ();
  boolean immediate_prepdisk    = Storage::immediate_prepdisk;
  boolean this_is_for_real	= ! test_mode;

  SCR::Write( .target.ycp, Storage::SaveDumpPath("targetMap_ps"), 
              Storage::GetTargetMap() );

  // differ between installation and running system
  boolean installation		= Stage::initial ();
  list    remountPartitions     = [];

  // we need to deactivate these in case of error
  list<string> activatedswaps = [];
  list<string> activatedLoopDevices = [];


    //switch swap off
define void doswapoff(list<string> activatedswaps)
    ``{
    foreach (string swapdev, activatedswaps,
	``{
        if( 0 != (integer)SCR::Execute (.target.bash, "/sbin/swapoff "+swapdev))
	    {
	    Report::Error(sformat(
		  // popup text, %1 is replaced by partition name e.g. /dev/hda1
		  _("Deactivating swap device %1 failed. You may have to reboot."),
		  swapdev));
	    }
	});
	return;
    };

//detach loop devices
define void losetup_d(list<string> activatedLoopDevices)
    ``{
    foreach( string loopdev, activatedLoopDevices,
    ``{
       y2debug("detaching loop device %1",loopdev);
       if (0 != (integer)SCR::Execute (.target.bash, "/sbin/losetup -d "+loopdev))
       {
	 y2warning("detaching loop device %1 failed",loopdev);
	 Report::Warning (sformat(
	      // popup text, %1 is replaced by loop name e.g. /dev/loop0
	      _("Detaching loop device %1 failed. Nothing serious, but you may run out of loop devices."),
	      loopdev));
       }
     });
     return;
    };

    //backup target map, reread it from harddisk and restore mountpoints etc.
define void restoretargetmap()
    ``{
    //bakup information a new map
    map baktargets=$[];
    foreach ( string tdevice, map target, Storage::GetTargetMap(),
	``{
	list<map> partitions = target["partitions"]:[];
	//map for partitions, referenced by number
	map bakpartitionmap=$[];
	foreach( map pentry, partitions,
	    ``{
	    //no backup for partitions marked for delete
	    if (pentry["delete"]:false)
		return;

	    integer fsid	= pentry["fsid"]:0;
	    string  mount	= pentry["mount"]:"";
	    boolean crypt_fs	= pentry["loop_fs"]:false;
	    string  crypt_key   = pentry["crypt_key"]:"";
	    string  cypher      = pentry["crypt"]:"";
	    symbol  used_fs 	= pentry["used_fs"]:`unknown;
	    boolean format	= pentry["format"]:false;
	    list region	= pentry["region"]:[];
	    map bakpentry=$[
		"fsid" :fsid,
		"mount" :mount,
		"loop_fs" : crypt_fs,
		"crypt_key": crypt_key,
		"used_fs": used_fs,
		"crypt":cypher,
		"format":format,
		"region":region,
	    ];
	    bakpartitionmap[pentry["nr"]:nil] = bakpentry;
	    });
	baktargets[ tdevice ] = $["partitions":bakpartitionmap];
	});
    map<string,map> targets = Storage::ReReadTargetMap();

    //see if theres info available in backupmap
    foreach (string tdevice, map target, targets,
	``{
	map bakpartitionmap = baktargets[tdevice, "partitions"]:$[];
	list<map> partitions = target["partitions"]:[];

	list<map> newpartitions = [];
	boolean usebackup=true;
	foreach( map pentry, partitions,
	    ``{
	    usebackup = true;
	    integer nr = pentry["nr"]:0;

	    //do we have data for that partition?
	    map bakpentry=bakpartitionmap[nr]:$[];

	    // partition is (no longer) available
	    if( bakpentry == $[])
		usebackup=false;

	    integer fsid = pentry["fsid"]:0;
	    integer bakfsid = bakpentry["fsid"]:0;

	    //file system id has changed, better leave it
	    if( usebackup && fsid!=bakfsid)
		{
		y2warning("fsid changed, no bakup for %1%2",tdevice,nr);
		usebackup=false;
		}

	    list region = pentry["region"]:[];
	    list bakregion = bakpentry["region"]:[];

	    // different region is dangerous
	    if( usebackup && region != bakregion )
		{
		y2warning("region changed, no bakup for %1%2",tdevice,nr);
		usebackup=false;
		}

	    string  mount	= pentry["mount"]:"";
	    boolean crypt_fs	= pentry["loop_fs"]:false;
	    string  crypt_key   = pentry["crypt_key"]:"";
	    string  cypher      = pentry["crypt"]:"";
	    symbol  used_fs	= pentry["used_fs"]:`unknown;
	    boolean format	= pentry["format"]:false;

	    if( usebackup==true)
		{
		string  bakmount     = bakpentry["mount"]:"";
		boolean bakcrypt_fs  = bakpentry["loop_fs"]:false;
		string  bakcrypt_key = bakpentry["crypt_key"]:"";
		string  bakcypher    = bakpentry["crypt"]:"";
		symbol  bakused_fs   = bakpentry["used_fs"]:`unknown;
		boolean bakformat    = bakpentry["format"]:false;

		if (mount=="" && bakmount !="" )
		    pentry["mount"] = bakmount;
		if (crypt_fs==false && bakcrypt_fs !=false )
		    pentry["loop_fs"] = bakcrypt_fs;
		if (crypt_key=="" && bakcrypt_key !="" )
		    pentry ["crypt_key"] = bakcrypt_key;
		if (cypher=="" && bakcypher !="" )
		    pentry ["crypt"] = bakcypher;
		if (used_fs==`unknown && bakused_fs !=`unknown )
		    pentry ["used_fs"] = bakused_fs;
		if (format==false && bakformat !=false )
		    pentry ["format"] = bakformat;
		}

	    newpartitions = add (newpartitions, pentry);
	    });
	targets[tdevice] = target;
	targets[tdevice,"partitions"] = newpartitions;
	});
    Storage::SetTargetMap( targets );
    };

// Define macro that creates a dialog with progressbar
define void MakefsDialog()
    ``{
    // html-format
    // advise the user to wait for completion
    // part 1 of 2
    string helptext = _("<p>
Please wait while your hard disk is prepared for installation...
<br></p>");
    if( !Stage::initial () )
	{
	helptext = _("<p>
Please wait while your hard disk is prepared...
<br></p>");
	}
    // rich-text format help text part 2 of 2
    helptext = helptext + _("\
<p>
Depending on the size of your hard disk and your processor speed, this action
might take some time.  5 minutes are not unusual for disks larger than 4 GB.
Often, the progress meter doesn't show a linear progress; even if it looks
slow near the end (\"95 %\"), please be patient: the formatting tool has to
perform various checks. <br></p>");

    // The Wizard module sets a special protection mode for "Accept"
    // buttons to prevent sloppy calls to Wizard::SetContents()
    // from disabling it. This doesn't apply here, however -
    // switching protection mode off.
    UI::WizardCommand(`ProtectNextButton( false ) );
    
    // hard disk will be made ready for installing Linux
    Wizard::SetContents(_("Preparing Your Hard Disk"),
			`ProgressBar(`id(`progress), " ", 100),
			helptext, false, false);
    };

define void DumpPartitionStart( string device, boolean crypt_fs )
    ``{
    string dd_sblocks = "";
    string idev = crypt_fs ? "/dev/urandom" : "/dev/zero";
    dd_sblocks = sformat( "/bin/dd if=%1 of=%2 bs=1024 count=50 2>&1", idev, 
                          device );
    if( !Arch::sparc () || crypt_fs )
	{
	y2milestone( "dd_sblocks=%1", dd_sblocks );
	y2milestone( "%1", SCR::Execute (.target.bash_output, dd_sblocks ));
	}
    }

define boolean CheckExistDevice( string device )
    ``{
    map st = (map)SCR::Read( .target.stat, device );
    y2milestone( "CheckExistDevice stat %1", st );
    boolean ret = size(st)>0 && st["isblock"]:false;
    y2milestone( "CheckExistDevice %1 ret %2", device, ret );
    return( ret );
    }

define boolean HandleFormatPartition( map partition )
    ``{
    boolean format = partition["format"]:false;
    boolean crypt_fs = partition["loop_fs"]:false &&
                       partition["crypt"]:""!="none";
    string mount = partition["mount"]:"";
    string device = "";
    boolean retry = false;
    boolean cancel = false;

    //retry loop
    do
	{
	device = partition["device"]:"";
	retry = false;

	y2milestone( "HandleFormatPartition dev:%1 crypt %2 loop_dev %3", 
	             device, crypt_fs, partition["loop_dev"]:"" );

	boolean loop_match = false;

	if( size(partition["loop_dev"]:"")>0 )
	    {
	    map r = Partitions::GetLoopOn( partition["loop_dev"]:"" );
	    loop_match = r["file"]:"" == partition["device"]:"";
	    if( !loop_match )
		SCR::Execute( .target.bash, 
			      "/sbin/losetup -d " + partition["loop_dev"]:"" );
	    }
	y2milestone( "HandleFormatPartition loop_match %1", loop_match );
	///////////////////////////////
	// CRYPT ?
	if( !loop_match && (crypt_fs || partition["type"]:`none==`loop) )
	    {
	    if( size(partition["loop_dev"]:"")==0 )
		{
		partition["loop_dev"] = Storage::GetLoopDev(0);
		}
	    cancel = !Storage::SetCryptLoop( partition );
	    if( !cancel )
		{
		if( !format && !partition["delete"]:false )
		    {
		    partition = FileSystems::GetFsysInfos( partition );
		    y2milestone( "loop part info %1", partition );
		    }
		map<string,map> tg = Storage::GetTargetMap();
		tg = Storage::SetPartition( tg, partition );
		Storage::SetTargetMap( tg );
		if( haskey( partition, "loop_dev" ))
		    {
		    device = partition["loop_dev"]:"";
		    activatedLoopDevices = add(activatedLoopDevices, device);
		    }
		}
	    }
	// announce partition to be formatted
	if( !cancel && format && mount != "swap")
	    {
	    string tmp = device;
	    if( partition["type"]:`none==`loop )
		{
		tmp = partition["fpath"]:"";
		}
	    string label = "";
	    if( size(mount)>0 )
		{
		// label text, example: "Formatting /dev/hda1 for /usr"
		label = sformat(_("Formatting %1 as %2"), tmp, mount);
		}
	    else
		{
		// label text, example: "Formatting /dev/hda1"
		label = sformat(_("Formatting %1"), tmp );
		}

	    UI::ChangeWidget(`id(`progress), `Label, label );
	    symbol ret = `ok;

	    if( this_is_for_real )
		{
		// Format partitions

		symbol used_fs = partition["used_fs"]:`unknown;

		y2milestone( "mkfs: used %1, crypt %2 ", used_fs, crypt_fs);

		list options = [];
		if( size(partition["format_opt"]:"")>0 )
		    {
		    list<string> t = splitstring( partition["format_opt"]:"", " " );
		    options = merge( options, 
		                     filter( string e, t, ``(size(e)>0)));
		    }
		if( partition["format"]:false && 
		    partition["fs_options"]:$[] != $[] )
		    {
		    options = convertFsOptionMapInList( partition );
		    }

		if( used_fs == `ext3 )
		    {
		    // add -j to options
		    options = add( options , "-j" );
		    }
		y2milestone( "Format options %1", options );


		string makefs_type = 
		    FileSystems::GetMakeFsType( used_fs, "ext2");

		if( !CheckExistDevice( device ))
		    {
		    ret = `not_ok;
		    }

		if( ret == `ok )
		    {
		    DumpPartitionStart( device, crypt_fs );
		    if( used_fs != `hfs )
			{
			list tmp = [ "StorageClients::MkfsProgressBar", 
				     makefs_type,  device, options ];
			ret = (symbol)WFM::CallFunction( "makefs", tmp );
			y2milestone( "format ret = %1", ret );
			}
		    else
			{
			string cmd = sformat( "/usr/bin/hformat %1", device );
			y2milestone( "cmd %1", cmd );
			SCR::Execute (.target.bash, cmd );
			ret = `ok;
			}
		    }
		if( ret == `ok )
		    {
		    FileSystems::DoChangedFsDefaults( partition );
		    map info = FileSystems::GetUuidVolume( device, used_fs );
		    map<string,map> tg = Storage::GetTargetMap();
		    if( size(info["uuid"]:"")>0 )
			{
			tg = Storage::SetPartitionData( tg, 
							partition["device"]:"",
							"uuid", 
							info["uuid"]:"" );
			}
		    tg = Storage::SetPartitionData( tg, partition["device"]:"",
						    "detected_fs", used_fs );
		    tg = Storage::DelPartitionData( tg, partition["device"]:"",
						    "create" );
		    Storage::SetTargetMap( tg );
		    }
		}
	    else
		{
		// Fake formatting
		integer progress = 0;

		while ( progress < 100 )
		    {
		    StorageClients::MkfsProgressBar( progress );
		    sleep ( 300 ); // millisec
		    progress = progress + 3;
		    }
		}

	    if( ret == `cancel )
		{
		cancel = true;
		}
	    else if( ret != `ok )
		{
		// report any formatting errors
		ret = Popup::AnyQuestion3(Popup::NoHeadline(),
			// popup text, %1 replaced by partition name e.g. /dev/hda1
			sformat(_("Could not format partition %1.
You can continue if you know what you are doing, but, to prevent damage to
your file systems, it is safer to cancel and reboot."),
			    device ),
			Label::ContinueButton(), Label::AbortButton(), 
			Label::RetryButton(), `focus_no);
		if (ret == `no)
		    {
		    cancel=true;
		    }
		else if (ret==`retry)
		    {
		    retry=true;
		    }
		}
	    }
	} 
    while( retry );
    string label = partition["label"]:"";
    if( !cancel && 
        ((size(label)>0 && (format || 
			   (haskey(partition,"ori_label") && 
			    partition["ori_label"]:""!=label)))||
	 (size(label)==0 && !format && size(partition["ori_label"]:"")>0)))
	{
	y2milestone( "set volume label %1", label );
	if( !FileSystems::SetVolumeLabel( device, partition ))
	    {
	    Popup::Error(
		// popup text, %1 replaced by arbitrary name
		// %2 replaced by partition name e.g. /dev/hda1
		sformat(_("Error setting the volume label on device %2 to %1"),
			partition["label"]:"", device ));
	    }
	else
	    {
	    map<string,map> tg = Storage::GetTargetMap();
	    tg = Storage::DelPartitionData( tg, device, "ori_label" );
	    Storage::SetTargetMap( tg );
	    }
	}
    // free loop device again of "noauto" is set, "noauto" means mounting
    // only be explicit user demand 
    if( !cancel && size(partition["loop_dev"]:"")>0 &&
	partition["noauto"]:false )
	{
	SCR::Execute( .target.bash, 
		      "/sbin/losetup -d " + partition["loop_dev"]:"" );
	}
    y2milestone( "device %1 ret %2", partition["device"]:"", cancel );
    return( !cancel );
    };

boolean HandlePartitionDisk( string device, map disk )
    ``{
    boolean retry = false;
    list<map> partitions = disk["partitions"]:[];
    path scrpath = disk["scrpath"]:topath("."+substring(device, 5));
    y2milestone( "HandlePartitionDisk partitions %1\n", partitions );
    if( find( device, "/dev/dasd" )!=0 )
	{
	y2milestone( "HandlePartitionDisk path %1\n", 
		     .disk + scrpath + .partitions );
	if( Arch::ia64 () )
	    {
	    partitions = 
		maplist( map p, partitions,
			 ``{
			 if( p["mount"]:"" == Partitions::BootMount() )
			     p["fsid"] = Partitions::fsid_gpt_boot;
			 return( p );
			 });
	    }
	y2milestone( "HandlePartitionDisk write partitions %1", partitions );
	do
	    {
	    retry = false;
	    UI::ChangeWidget(`id(`progress), `Label,
			     // label text, %1 is replaced by disk name e.g. /dev/hda
			     sformat(_("partitioning disk %1"), device ));

	    map args = $[ "parted" : Partitions::UseParted(),
			  "label"  : disk["label"]:"msdos" ];
	    y2milestone( "HandlePartitionDisk args %1", args );

	    /////////////////////////////////////////////////////
	    boolean result = SCR::Write(.disk + scrpath + .partitions,
					partitions, args );
	    /////////////////////////////////////////////////////

	    if( !result )
		{
		y2error("Oops, partitioning failed for device %1", device);

		symbol ret=`yes;
		// continue/cancel/retry during installation
		if( Stage::initial () )
		    {
		    if( Storage::CheckSwapOn( device ) )
			{
			reboot_necessary = true;
			}
		    else
			{
			ret = Popup::AnyQuestion3(
			    // heading text
			    _("Partitioning Failed"),
			    sformat (
				// popup text
				_("Partitioning failed for unknown reason.
Repartition disk %1."),
				   device),
			    Label::ContinueButton(),
			    Label::AbortButton(),
			    Label::RetryButton(), `focus_no);

			if( ret == `retry )
			    {
			    retry = true;
			    }
			else if ( ret == `no )
			    {
			    return( false );
			    }
			}
		    }
		// offer reboot in running system
		else
		    {
		    // heading text
		    ret = Popup::AnyQuestion3(_("parted failed."),
			  // popup text
			  _("It is strongly advised to reboot now to prevent damage to your file systems."),
			  // button text
			  Label::ContinueButton(), Label::AbortButton(), 
			  _("Reboot"), `focus_retry);

		    if( ret == `retry )
			{
			SCR::Execute (.target.bash,"/sbin/shutdown -r now");
			reboot = true;
		        return( false );
			}
		    else if (ret == `no )
			{
		        return( false );
			}
		    }
		}
	    }
	while ( retry );
	}
    else
	{
	string cmd = sformat( "/sbin/fdasd -p %1 | grep '^[ ]*/dev/dasd' | tr -s ' '", 
	                      device );
	if( disk["dasdfmt"]:false )
	    {
	    partitions = filter( map p, partitions, ``(!p["delete"]:false));
	    y2milestone( "HandlePartitionDisk partitions %1", partitions );
	    }
	map bo = (map)SCR::Execute( .target.bash_output, cmd );
	list<string> lines = filter( string l,
	                             splitstring( bo["stdout"]:"", "\n" ),
				     ``(size(l)>0));
	y2milestone( "HandlePartitionDisk lines %1", lines );
	list<map> fp = maplist( string s, lines, 
	    ``{
	    map p = $[];
	    list <string> fl = filter( string f, splitstring( s, " " ), 
	                               ``(size(f)>0));
	    p["name"] = fl[0]:"";
	    p["start"] = tointeger(fl[1]:"0");
	    p["end"] = tointeger(fl[2]:"0");
	    p["nr"] = tointeger(fl[4]:"0");
	    return( p );
	    });
	y2milestone( "HandlePartitionDisk fp %1", fp );
	foreach( map p, partitions,
	    ``{
	    if( p["delete"]:false )
		{
		fp = filter( map f, fp, ``(f["nr"]:0!=p["nr"]:0));
		}
	    });
	y2milestone( "HandlePartitionDisk fp %1", fp );
	foreach( map p, partitions,
	    ``{
	    if( p["create"]:false )
		{
		map new = $[ "new" : true ];
		new["nr"] = p["nr"]:0;
		new["start"] = p["region",0]:0 * disk["tracks"]:1;
		new["end"] = (p["region",0]:0+p["region",1]:0) * 
		             disk["tracks"]:1 - 1;
		fp = add( fp, new );
		}
	    });
	fp = sort( map a, map b, fp, ``(a["start"]:0<b["start"]:0));
	y2milestone( "HandlePartitionDisk fp %1", fp );
	boolean map_ok = true;
	integer cnt = 1;
	foreach( map p, fp, 
	    ``{
	    if( cnt<size(fp) )
		{
		if( p["end"]:0 - fp[cnt,"start"]:0 > disk["tracks"]:1 )
		    {
		    map_ok = false;
		    }
		}
	    cnt = cnt+1;
	    });
	if( !map_ok )
	    {
	    y2error( "This should not happen" );
	    y2error( "impossible partition list %1", fp );
	    return( false );
	    }
	else
	    {
	    integer diff = 0;
	    cnt = 1;
	    fp = maplist( map p, fp,
		``{
		if( cnt<size(p) )
		    {
		    diff = p["end"]:0 - fp[cnt,"start"]:0;
		    if( diff<0 )
			diff = -diff;
		    if( diff <=disk["tracks"]:1 )
			{
			p["end"] = fp[cnt,"start"]:1-1;
			}
		    }
		return( p );
		});
	    y2milestone( "HandlePartitionDisk fp %1", fp );
	    if( size(fp)>0 )
		{
		if( fp[0,"start"]:0 <= disk["tracks"]:1 )
		    {
		    fp[0,"start"] = "first";
		    }
		diff = disk["tracks"]:1*disk["cyl_count"]:0 - 
		       fp[size(fp)-1,"end"]:0;
		if( diff <= disk["tracks"]:1 )
		    {
		    fp[size(fp)-1,"end"] = "last";
		    }
		}
	    y2milestone( "HandlePartitionDisk fp %1", fp );
	    string conf = "";
	    foreach( map p, fp,
		``{
		conf = conf + sformat( "[%1,%2]\n", p["start"]:nil, 
		                       p["end"]:nil );
		});
	    y2milestone( "HandlePartitionDisk conf %1", conf );
	    string tmpf = Storage::SaveDumpPath( "tmpf" );
	    y2milestone( "HandlePartitionDisk tmpf %1", tmpf );
	    SCR::Write( .target.string, tmpf, conf );
	    string cmd = sformat( "/sbin/fdasd -c %1 %2", tmpf, device );
	    do
		{
		retry = false;
		UI::ChangeWidget(`id(`progress), `Label,
				 // label text, %1 is replaced by disk name e.g. /dev/hda
				 sformat(_("partitioning disk %1"), device ));
		y2milestone( "HandlePartitionDisk Executing cmd = %1", cmd );
		map bo = (map)SCR::Execute( .target.bash_output, cmd );
		boolean result = bo["exit"]:1 == 0;
		y2milestone( "HandlePartitionDisk bo = %1", bo );
		if( !result )
		    {
		    y2error("Oops, fdasd failed for device %1", device);

		    symbol ret=`yes;
		    // continue/cancel/retry during installation
		    ret = Popup::AnyQuestion3(
			// heading text
			_("fdasd Failed"),
			sformat (
			    // popup text
			    _("Partitioning failed for unknown reason.
Repartition disk %1."),
			       device),
			Label::ContinueButton(), Label::AbortButton(),
			Label::RetryButton(), `focus_no);

		    if( ret == `retry )
			{
			retry = true;
			}
		    else if ( ret == `no )
			{
			return( false );
			}
		    }
		}
	    while ( retry );
	    //SCR::Execute( .target.remove, tmpf );
	    }
	}
    return( true );
    }

define list CreateAndActivateSwap( list<list> swd )
    ``{
    list ret = [];
    y2milestone( "CreateAndActivateSwap swd %1", swd );
    foreach (list swaplist, swd,
	``{
	y2milestone( "CreateAndActivateSwap swap %1", swaplist );
	string swapdev = swaplist[0]:"/dev/null";

	if( !contains( Storage::SwappingPartitions(), swapdev ) )
	    {
	    boolean format_swap = swaplist[1]:false;
	    string label = "";
	    if( format_swap )
		{
		// label text %1 replaced by partition name e.g. /dev/hda1
		label = sformat(_("Formatting %1 as swap"), swapdev );
		}
	    else
		{
		// label text %1 replaced by partition name e.g. /dev/hda1
		label = sformat(_("Activating %1 for swap"), swapdev );
		}
	    UI::ChangeWidget(`id(`progress), `Label, label );

	    if( swaplist[1]:false && CheckExistDevice(swapdev))
	       {
	       DumpPartitionStart( swapdev, false );
	       if( SCR::Execute (.target.bash, "/sbin/mkswap "+ swapdev) != 0 )
		  {
		  // popup text %1 replaced by partition name e.g. /dev/hda1
		  Report::Error(sformat(_("Could not set up swap partition %1"), swapdev));
		  }
	       else
		  {
		  map<string,map> tg = Storage::GetTargetMap();
		  tg = Storage::DelPartitionData( tg, swapdev, "create" );
		  Storage::SetTargetMap(tg);
		  }
	       }
	    if (0 != SCR::Execute (.target.bash, "/sbin/swapon "+swapdev))
	       {
	       // popup text %1 replaced by partition name e.g. /dev/hda1
	       Report::Error(sformat(_("Could not set up swap partition %1"), swapdev));
	       }
	    else
	       {
	       ret = add (ret, swapdev);
	       }
	    }
	});
    y2milestone( "CreateAndActivateSwap ret %1", ret );
    return( ret );
    }


define map DetermineMountPoints(string disk, map target, map mp )
    ``{
    y2milestone( "DetermineMountPoints disk %1 tg %2", disk, target );
    y2milestone( "DetermineMountPoints installation %1", installation );
    foreach ( map part, target["partitions"]:[],
	``{
	y2milestone( "DetermineMountPoints part %1", part );
	string device = part["device"]:"";
	string mount = part["mount"]:"";
	boolean running_system_create_part = 
	    !installation && part["create"]:false;
	boolean running_system_remount_part = 
	    !installation && contains( remountPartitions, device );

	if( installation || running_system_create_part || 
	    running_system_remount_part )
	    {
	    if( mount != "" && mount != "swap" && !part["delete"]:false &&
	        !part["noauto"]:false &&
		(!installation||!contains(Partitions::fsid_ntfstypes, part["fsid"]:0))) // ntfs is read-only anyway.
		{
		symbol used_fs = part["used_fs"]:`unknown;
		if( used_fs == `unknown )
		    {
		    used_fs = part["detected_fs"]:`unknown;
		    }
		if( part["loop_fs"]:false && size(part["loop_dev"]:"")>0 )
		    device = part["loop_dev"]:"";
		mp[mount] = [device, used_fs, disk];
		}
	    }
	});  // foreach (partition)
    y2milestone( "DetermineMountPoints disk %1 mp %2", disk, mp );
    return( mp );
    };

define boolean DoMountList( map<string,list> mp )
    ``{
    boolean retry = false;
    boolean cancel = false;
    string source_partition = (string)SCR::Read (.etc.install_inf.Partition);
    if (source_partition == nil) source_partition = "";

    y2milestone( "DoMountList mp %1", mp );
    foreach( string mount, list mountData, mp,
	``{
	if (cancel)
	    {
	    return;
	    }
	symbol used_fs = mountData[1]:`ext2;

	/////////////////////////////////////////////
	// load filesystem modules
	FileSystems::LoadModule( used_fs );

	if( mount == "/" )
	    {
	    foreach( string modname, FileSystems::GetNeededModules(used_fs),
		``{
		Initrd::AddModule (modname, "");
		});
	    }

	// eg /mnt + /usr
	if( Installation::scr_destdir != "/" )
	    {
	    mount = Installation::scr_destdir + mount;
	    }

	do
	    {
	    retry = false;

	    // partition has a mount point
	    y2milestone("mkdir %1", mount );
	    SCR::Execute( .target.mkdir, mount, 0755 );
	    string device = mountData[0]:"/dev/null";

	    y2milestone( "mountcmd: %1 target:%2 [-t <%3>]", device, mount, 
	                 used_fs );

	    string mount_type = FileSystems::GetMountString( used_fs, "");

	    if (mount_type != "")
		{
		mount_type = "-t " + mount_type;
		}

	    if( device == sformat("/dev/%1", source_partition) )
		break;

	    if( !(boolean)SCR::Execute( .target.mount, [device, mount], mount_type ) )
		{
		symbol ret=`yes;
		// /bin/mount failed, report this to the user
		ret = Popup::AnyQuestion3(Popup::NoHeadline(),
			// popup text, %2 replaced by directory name e.g. /usr
			// %1 replaced by partition name e.g. /dev/hda1
			sformat(_("Could not mount partition %1 to %2.
You can continue if you know what you are doing, but, to prevent damage to
your file systems, it is safer to cancel and reboot."),
			    device, mount ),
			Label::ContinueButton(), Label::AbortButton(), 
			Label::RetryButton(), `focus_yes);
		if (ret == `retry)
		    {
		    retry=true;
		    }
		else if (ret == `no)
		    {
		    cancel=true;
		    }
		}
	    } while (retry==true);
	});
    y2milestone( "ret %1", !cancel );
    return( !cancel );
    };

define void DoUmountAndReset( list mounts )
    ``{
    y2milestone( "mounts %1", mounts );
    if( installation )
	{
	mounts = add( mounts, "/sys" );
	mounts = add( mounts, "/proc" );
	mounts = add( mounts, "/proc/bus/usb" );
	}
    integer num = size(mounts)-1;
    while( num>=0 )
	{
	y2milestone( "umount: %1", Storage::PathToDestdir( mounts[num]:"" ) );
	SCR::Execute( .target.umount, Storage::PathToDestdir( mounts[num]:"" ) );
	num = num-1;
	}
    doswapoff(activatedswaps);
    losetup_d(activatedLoopDevices);
    restoretargetmap();
    };

  y2milestone( "BEGINNING of inst_prepdisk" );

  if ( Mode::autoinst () )
  {
      import "AutoinstStorage";
      AutoinstStorage::Initialize();
  }
  
  changeExtendedIdTo15();
  // check for ppc-PReP/CHRP system, they need a special boot partition
  // todo -> put this in a lib, we need it also in inst_custom_part ...

  MakefsDialog();

  // Begin with the actual work
  // 0.5 unmount all deleted or changed partitions ( only in running system )
  if( !installation )
      {
      list<map> mounts = Partitions::CurMounted();
      list<map> umounts = [];
      list<map> targetMounts = [];

      foreach( map mounted_partition, mounts, 
	  ``{
	  y2debug( "mounted partition map : %1", mounted_partition );

	  map<string,map> all_target_of_mounted_part = filter( string key, map target, Storage::GetTargetMap(), 
	                                           ``( issubstring( mounted_partition["spec"]:"", key ) ||
						       issubstring( mounted_partition["loop_on"]:"", key )));
	  y2debug( "all_target_of_mounted_part: %1 ", mounted_partition );

	  if( size( all_target_of_mounted_part ) > 0 )
	      {
	      map target_of_mounted_part = (map)
		  maplist(any k, any v, all_target_of_mounted_part, ``(v) )[0]:$[];

	      y2debug( "target_of_mounted_part %1", maplist(any k, any v, all_target_of_mounted_part, ``(k) )[0]:"");
	      list<map> all_partitions = filter( map part,
					    target_of_mounted_part["partitions"]:[],
					    ``( issubstring( mounted_partition["spec"]:"", sformat( "%1", part["nr"]:(any)0 ) ) ||
					        issubstring( mounted_partition["loop_on"]:"", sformat( "%1", part["nr"]:(any)0 ) )));

	      y2debug( " all partitions %1" , all_partitions );

	      boolean delete_found        = false;
	      boolean mount_changed_found = false;
	      boolean format_found	  = false;
	      boolean change_fsid         = false;


	      // mounted partition should be delete
	      delete_found =  size( filter( map part, all_partitions,
	                                    ``( part["delete"]:false &&
					        !part["create"]:false ))) > 0;

	      // mount point of mounted partition should be changed
	      mount_changed_found =
		  size( filter( map part, all_partitions,
	                       ``( !part["delete"]:false &&
				   (haskey(part,"ori_mount") &&
				    part["ori_mount"]:""!=part["mount"]:"") ||
				   (haskey(part,"ori_fstopt") &&
				    part["ori_fstopt"]:""!=part["fstopt"]:"") ||
				   (haskey(part,"ori_label") &&
				    !FileSystems::ChangeLabelMounted( part["used_fs"]:`unkown ) &&
				    part["ori_label"]:""!=part["label"]:""))))>0;

	      // mounted partition should formated
	      format_found = size( filter(map part, all_partitions, 
	                                  ``( !part["delete"]:false &&
					       part["format"]:false ))) > 0;

	      // change fsid of  mounted  partition
	      change_fsid = size( filter(map part, all_partitions, 
	                                 ``( !part["delete"]:false &&
					      part["change_fsid"]:false ))) > 0;

	      if( mount_changed_found || delete_found || format_found ||
	          change_fsid )
		  {
		  umounts = add( umounts, mounted_partition );
		  }

	      if( mount_changed_found || format_found || change_fsid )
		  {
		  remountPartitions = add( remountPartitions,
		                           mounted_partition["spec"]:"");
		  }
	      y2debug( "%5 delete:%1 changed:%2 format:%3 chfsid:%4",
	               delete_found, mount_changed_found,
	               format_found, change_fsid, 
		       mounted_partition["spec"]:"" );
	      }
	  });
      y2milestone( "remountPartitions=%1", remountPartitions );
      y2milestone( "umounts=%1", umounts );

      foreach( string key, map val, Storage::GetTargetMap(), 
	  ``{
          list<map> new = filter( map v, val["partitions"]:[], ``(v["mount"]:""!=""));
	  y2milestone( "new:%1", new );
	  targetMounts = (list<map>)union( targetMounts, new );
	  });

      foreach( map val, targetMounts,
	  ``{
          string dev = val["device"]:"";
	  if( size( filter( map v, mounts, 
	                    ``(v["spec"]:""==dev||v["loop_on"]:""==dev) ))==0 )
	      {
	      remountPartitions = add( remountPartitions, dev );
	      y2milestone( "remadd:%1 rem:%2", dev, remountPartitions );
	      }
	  });

      y2milestone( "remountPartitions=%1", remountPartitions );

      if( !this_is_for_real )
	  {
	  y2milestone( "All unmounted mount points : %1", 
		       maplist(map umount, umounts, ``(umount["file"]:"")));
	  }
      else
	  {
	  foreach( map umount, umounts,
	      ``{
	      string mount_point = umount["file"]:"";
	      if( mount_point != "swap")
		  SCR::Execute( .target.umount, mount_point );
	      else
		  SCR::Execute( .target.bash, 
		                "/sbin/swapoff " + umount["spec"]:"");
	      });
	  }
      }


  // 0. Prepare modify_target map
  // move first pv to vg_create

    map procMod = processModifyTargets( modify_targets, Storage::GetTargetMap() );
    Storage::SetTargetMap( procMod["targets"]:$[] );
    modify_targets  = procMod["modify_targets"]:$[];

    boolean cancel = false;
    boolean retry = false;
    map<string,map> tg = Storage::GetTargetMap();
    integer num_lvm_vg = size (filter (string dev, map disk, tg,
                                       ``(disk["is_lvm_vg"]:false&&
				          !disk["delete"]:false)));
    boolean md_active = size(tg["/dev/md","partitions"]:[])>0;
    integer num_evms = 0;

    foreach( string dev, map disk, tg,
	``{
	if( find( dev, "/dev/evms" )==0 )
	    {
	    num_evms = num_evms + size(filter( map p, disk["partitions"]:[],
					       ``(size(p["mount"]:"")>0)));
	    }
	});
    y2milestone( "num_evms %1 num_lvm_vg %2 md_active %3", num_evms, num_lvm_vg,
                 md_active );

    modify_targets = HandleDeletedVgs( tg, modify_targets );

  // 0b. Do any necessary lvm preparation

    if( size(modify_targets) > 0 )
	{
        // activate lvm
	Storage::SetMdOn( true );
	do
	  {
	  retry=false;

	  integer n = 0;
	  boolean mod_ok = true;
	  map<integer,map> mod = filter( integer num, map p, modify_targets,
	                    ``(p["type"]:""=="remove_lv") );
	  if( size(mod)>0 )
	    {
	    mod = mapmap( integer num, map p, mod, ``{ n=n+1; return( $[n: p] ); } );
	    y2milestone( "mod=%1", mod );
	    mod_ok = target_modify( mod, installation );
	    }
	  if( mod_ok )
	    {
	    mod = filter( integer num, map p, modify_targets,
			  ``(p["type"]:""=="resize_lv") );
	    if( size(mod)>0 )
	      {
	      n = 0;
	      mod = mapmap( integer num, map p, mod, ``{ n=n+1; return( $[n: p] ); } );
	      y2milestone( "mod=%1", mod );
	      mod_ok = HandleResizeLvm( Storage::GetTargetMap(), mod, true );
	      }
	    }
	  if( mod_ok )
	    {
	    mod = filter( integer num, map p, modify_targets,
			  ``(p["type"]:""=="remove_pv" ||
			     p["type"]:""=="remove_vg") );
	    if( size(mod)>0 )
	      {
	      n = 0;
	      mod = mapmap( integer num, map p, mod, ``{ n=n+1; return( $[n: p] ); } );
	      y2milestone( "mod=%1", mod );
	      mod_ok = target_modify( mod, installation );
	      }
	    }
	  y2milestone( "mod_ok=%1", mod_ok );

	  if ( !mod_ok )
	    {
	    symbol ret = `yes;
 
 	    // heading text
	    ret = Popup::AnyQuestion3(_("LVM setup 0 failed."),
		  // popup text
		  _("You can continue if you know what you are doing, but, to prevent
damage to your file systems, it is safer to cancel and reboot.
"),
		  Label::ContinueButton(), Label::AbortButton(), Label::RetryButton(), `focus_no);

	    if (ret == `retry)
	      {
	      retry = true;
	      }
	    else if (ret == `no)
	      {
	      return `back;
	      }
	    }
	  } while(retry);
        // deactivate lvm
	Storage::SetMdOn( false );
        }

    HandleEvmsChanges( tg, true, true );
    SCR::UnmountAgent(.evms);

    if( md_active )
	{
	list<any> mr_list = [];
	if( !Stage::initial () )
	    {
	    mr_list = filter( map e, tg["/dev/md","partitions"]:[],
	                           ``(size(e["mount"]:"")>0));
	    mr_list = maplist( map e, (list<map>)mr_list, ``(e["device"]:"") );
	    }
	y2milestone( "mr_list %1", mr_list );
	SCR::Write( .md.deactivate, mr_list );
	}

    y2milestone( "dmsetup %1", 
                 SCR::Execute( .target.bash_output, "/sbin/dmsetup ls" ));

  // 1. Partitioning all disks

    // remember special devices for LILO
    string boot_device = "";
    list<list>   swap_devices = [];
    string root_device = "";


    map running_swap = (map)SCR::Read(.run.swapon_s);

    y2milestone("running_swap: %1", running_swap);

    string swap_conflicts = Storage::CheckSwapConflicts();
    if( size(swap_conflicts)>0 )
	{

        // popup text %1 replaced by partition name e.g. /dev/hda1
	Report::Message (sformat(_("The swap partition %1 used during installation conflicts with the partitions needed for the system to be installed.\n
Please repeat the installation with another swap partition selected
"), swap_conflicts));
	Linuxrc::WriteYaSTInf($["Root" : "reboot", "RebootMsg" : "0"]);
	return `abort;
	}

    if( Arch::s390 () )
	{
        map<string,map> tg = filter( string d, map disk, 
	                             Storage::GetTargetMap(),
				     ``(disk["dasdfmt"]:false));
	list<string> ddf = maplist( string d, map disk, tg, ``{return(d);});
	if( size(ddf)>0 )
	    {
	    boolean ok = true;
	    retry = false;
	    string txt = "";
	    if( size(ddf)>1 )
		{
		// label text, %1 is replaced by multiple disk names
		txt = sformat(_("dasdfmt Disks %1"), mergestring( ddf, " " ) );
		}
	    else
		{
		// label text, %1 is replaced by disk name
		txt = sformat(_("dasdfmt disk %1"), ddf[0]:"" );
		}
	    UI::ChangeWidget(`id(`progress), `Label, txt );
	    string cmd = "dasdfmt -y -F -Y -b 4096 -P 4 -d cdl";
	    cmd = cmd + mergestring( maplist( string d, ddf, 
	                             ``{return( " -f "+d);}), "" );
	    do
		{
		y2milestone( "Executing cmd = %1", cmd );
		ok = SCR::Execute( .target.bash, cmd ) == 0; 	
		if( !ok )
		    {
		    // heading text
		    symbol ret = Popup::AnyQuestion3( _("dasdfmt Failed"),
			_("dasdfmt failed."),
			Label::ContinueButton(),
			Label::AbortButton(),
			Label::RetryButton(), `focus_no);

		    if( ret == `retry )
			{
			retry = true;
			}
		    else if ( ret == `no )
			{
			cancel = true;
			}
		    }
		}
	    while( !ok && retry && !cancel );
	    }
	}

    foreach (string tdevice, map target, Storage::GetTargetMap(),
	``{
	if (cancel)
	    {
	    return;
	    };

	// every disk
	list<map> partitions = target["partitions"]:[];

	y2debug("Target: %1", tdevice );

	// Partitioning with disk agent  
	if( this_is_for_real && Storage::IsRealDisk( tdevice, target ))
	    {
	    map bo = (map)SCR::Execute( .target.bash_output, 
				        "echo YAST_IS_RUNNING=$YAST_IS_RUNNING" );
	    y2milestone( "y2env %1", bo["stdout"]:"" );

            // handle all partitions resizings that decrease partition size
	    cancel = !HandleResizePartitions( tdevice, target, true );

	    boolean need_part = size( filter( map p, target["partitions"]:[],
	                                      ``( p["resize"]:false ||
	                                          p["create"]:false ||
	                                          p["delete"]:false ))) > 0;
	    y2milestone( "disk:%1 need_part:%2", tdevice, need_part );

	    if( !cancel && need_part )
		{
		cancel = !HandlePartitionDisk( tdevice, target );
		}
	    if( !cancel && need_part && Storage::ZeroNewPartitions )
		{
		foreach( map p, filter( map e, partitions, 
		                        ``(e["create"]:false && 
					   CheckExistDevice(e["device"]:""))),
		    ``{
		    string dd_sblocks =
			sformat( "/bin/dd if=/dev/zero of=%1 bs=1024 count=200 2>&1",
				 p["device"]:"" );
		    y2milestone( "ZeroPartitions %1", dd_sblocks );
		    y2milestone( "%1", SCR::Execute( .target.bash_output, 
		                                     dd_sblocks ));
		    });
		}
	    if( !cancel )
		{
		foreach( map pentry, partitions,
		    ``{
		    /////////////////////////////////////////////////////
		    // look if we have to change an partition id

		    boolean change_fsid = pentry["change_fsid"]:false;
		    symbol type = pentry["type" ]:`unknown;

		    if( change_fsid )
			{
			integer ori_fsid = pentry["ori_fsid"]:0;
			integer fsid     = pentry["fsid"]:0;
			integer nr       = pentry["nr"]:0;

			y2milestone( "change_fsid disk:%1 readonly:%2", tdevice,
				     target["readonly"]:false );

			if( fsid!=ori_fsid && !target["readonly"]:false )
			    {
			    disk_change_id( tdevice, nr, fsid );
			    }
			}
		    });
		}

	    if( !cancel )
		cancel = !HandleResizePartitions( tdevice, target, false );
	    }  // partitioning

	if( !immediate_prepdisk )
	    {
	    // check all partitions and initialize
	    // boot_device, root_device, and swap_devices

	    foreach (map pentry, partitions,
		``{
		string device = pentry["device"]:"";
		string mountpoint = pentry["mount"]:"";
		boolean do_format = pentry["format"]:false;

		y2milestone( "device %1, mount %2, format %3", device, 
		             mountpoint, do_format );

		if( !pentry["delete"]:false)
		    {		// only those which aren't deleted
		    if( mountpoint == Partitions::BootMount() )
			{
			boot_device = device;
			}
			// only swaps which aren't running 
			// (yast2 did enable any swap yet!!)
		    else if( mountpoint=="swap" && 
			     (running_swap[substring(device, 4, size(device))]:"" == ""))
			{
			swap_devices = add( swap_devices, [device, do_format] );
			}
		    else if (mountpoint == "/")
			{
			root_device = device;
			}
		    }
		y2debug("Partition: %1",pentry );
		});
	    }

	if ( boot_device == "" )
	    boot_device = root_device;
	});	// foreach target

    y2milestone( "root:%1 boot:%2 swap:%3", root_device, boot_device, 
                 swap_devices );

    //partitioning failed

    if( reboot )
	{
	return `abort;
	}
    if( cancel )
	{
	y2debug("partitioning failed");
	restoretargetmap();
	return `back;
	}

    if( reboot_necessary || immediate_prepdisk )
	{

        // popup text
	Report::Message (_("Because swap needed to be activated while partitioning, rebooting
is required. After that, restart the installation.
"));
	Linuxrc::WriteYaSTInf($["Root" : "reboot", "RebootMsg" : "0"]);
	return `abort;
	}

    //------------------------------------------------------------------
    // partitioner isn't needed any more

    SCR::UnmountAgent (.disk);

    if( md_active )
	{
	SCR::Write( .md.activate, "" );
	}

    // 2a. Do any necessary RAID preparation
    if( this_is_for_real && md_active )
	{
        map<string,map> tg = Storage::GetTargetMap();
	y2milestone( "rd %1", tg["/dev/md","partitions"]:[] );
	list<map> rem_l = filter( map p, tg["/dev/md","partitions"]:[],
	                     ``( p["delete"]:false && !p["create"]:false ));
	list<map> add_l = filter( map p, tg["/dev/md","partitions"]:[],
	                     ``( !p["delete"]:false && p["create"]:false ));
	y2milestone( "rem %1", rem_l ); 
	y2milestone( "add %1", add_l );
	foreach( map p, rem_l,
	    ``{
	    y2milestone( "p %1", p );
	    string cmd = "/sbin/raidstop -c /dev/null " + p["device"]:"";
	    y2milestone( "cmd %1", cmd );
	    SCR::Execute( .target.bash, cmd );
	    });
	if( size( add_l )>0 || size( rem_l )>0)
	    {
	    y2milestone( "prepare raid" );
	    do
		{
		boolean raidtab_created = prepare_raid( tg, installation );
		retry = false;

		y2milestone ("raidtab_created: %1", raidtab_created);
		y2milestone ("raids %1", 
		    filter( map p, tg["/dev/md","partitions"]:[],
			        ``(!p["delete"]:false)));


		if (raidtab_created)
		    {
		    // remember to copy /etc/raidtab to target in inst_finish
		    Storage::SetRaidtabCreated( true );
		    }
		// prepare failed, ask user what to do
		else if( size( filter( map p, tg["/dev/md","partitions"]:[],
				       ``(!p["delete"]:false)))>0 )
		    {
		    symbol ret=`yes;
		    ret = Popup::AnyQuestion3(Popup::NoHeadline(),
						// popup text 
						_("Preparing the RAID system failed"),
						Label::ContinueButton(), Label::AbortButton(), Label::RetryButton(),`focus_no);


		    if (ret == `retry)
		    {
			retry=true;
		    }
		    else if (ret == `no)
		    {
			doswapoff(activatedswaps);
			losetup_d(activatedLoopDevices);
			restoretargetmap();
			return `back;
		    }
		    }
		} while(retry);
	    }
	}

    
    // 2b. Do any necessary lvm preparation
    // activate lvm, cause if I only use a existing LV, I need to activate it 
    // here
    if ( num_lvm_vg > 0 )
	{
	SCR::Write( .lvm.init, "" );
	Storage::SetMdOn( true );
	}
    y2milestone( "dmsetup %1", 
		 SCR::Execute( .target.bash_output, "/sbin/dmsetup ls" ));
    do
	{
	retry=false;
	integer n = 0;
	map<integer,map> mod = filter( integer num, map p, modify_targets,
	                  ``(p["type"]:""!="remove_pv" &&
			     p["type"]:""!="remove_lv" &&
			     p["type"]:""!="remove_vg") );
	y2milestone( "mod=%1", mod );

	map<integer,map> mod1 = filter( integer num, map p, mod,
					``(p["type"]:""=="create_vg" ||
					   p["type"]:""=="create_pv"));
        mod1 = mapmap( integer num, map p, mod1, 
	               ``{ n=n+1; return( $[n: p] ); } );
	y2milestone( "mod1=%1", mod1 );

	boolean ret = target_modify( mod1, installation );
	if( ret )
	    {
	    mod1 = filter( integer num, map p, mod,
			   ``(p["type"]:""!="create_vg" &&
			      p["type"]:""!="create_pv"));
	    n = 0;
	    mod1 = mapmap( integer num, map p, mod1, 
			   ``{ n=n+1; return( $[n: p] ); } );
	    y2milestone( "mod1=%1", mod );
	    ret = target_modify( mod1, installation );
	    }
	if( ret )
	    {
	    mod = filter( integer num, map p, modify_targets,
			  ``(p["type"]:""=="resize_lv") );
	    if( size(mod)>0 )
	      {
	      n = 0;
	      mod = mapmap( integer num, map p, mod, 
	                    ``{ n=n+1; return( $[n: p] ); } );
	      y2milestone( "mod=%1", mod );
	      ret = HandleResizeLvm( Storage::GetTargetMap(), mod, false );
	      }
	    }

	if (ret == false)
	    {
	    symbol ret = `yes;

	    // heading text 
	    ret = Popup::AnyQuestion3(_("LVM setup 1 failed."),
		  // popup text 
		  _("You can continue if you know what you are doing, but, to prevent
damage to your file systems, it is safer to cancel and reboot.
"),
		  Label::ContinueButton(), Label::AbortButton(), Label::RetryButton(), `focus_no);

	    if( ret == `retry)
		{
	        retry = true;
		}
	    else if (ret == `no)
		{
	        doswapoff (activatedswaps);
	        losetup_d (activatedLoopDevices);
	        restoretargetmap();
	        return `back;
	        }
	    }
	} while(retry);

    if( Storage::CheckForLvmRootFs() && num_lvm_vg>1 )
	{
	map part = Storage::GetEntryForMountpoint( "/" );
	map tmp = Storage::GetDiskPartition( part["device"]:"" );
	string vg_root = substring( tmp["disk"]:"", 5 );
	if( size(vg_root)>0 )
	    {
	    SCR::Write( .lvm.deactivate, "" );
	    SCR::Write( .lvm.activate, vg_root );
	    SCR::Write( .lvm.activate, "" );
	    }
	}

    y2milestone( "dmsetup %1", 
		 SCR::Execute( .target.bash_output, "/sbin/dmsetup ls" ));
    y2milestone( "ls %1", 
		 SCR::Execute( .target.bash_output, "/bin/ls -l /dev/mapper /dev/system" ));

    // 3. Create and use swap devices
    if( this_is_for_real )
	{
	list<list> swd = filter( list e, swap_devices, ``(find(e[0]:"","/dev/evms/")!=0));
	list sw = CreateAndActivateSwap( swd );
        activatedswaps = (list<string>)union(activatedswaps, sw);
	}

    // 4. Create filesystems
    cancel = false;
    retry = false;

    foreach( string tdevice, map target, 
             filter( string k, map e, Storage::GetTargetMap(), 
	             ``(k!="/dev/loop" && find(k,"/dev/evms")!=0 )),
	``{
	// every disk
	list<map> partitions = target["partitions"]:[];
	y2milestone( "tdevice %1", tdevice );
	foreach(map partition, filter( map p, partitions, ``(!p["delete"]:false)),
	    ``{
	    if( !cancel && 
	        (size(partition["mount"]:"")>0 ||
	         size(partition["label"]:"")>0 || 
	         partition["format"]:false))
		{
		cancel = !HandleFormatPartition( partition );
		y2milestone( "after HandleFormatPartition cancel %1", cancel );
		}
	    });
	});

    // some mkfs failed, go back
    if( cancel )
	{
	doswapoff(activatedswaps);
	losetup_d(activatedLoopDevices);
	restoretargetmap();
	return `back;
	}


    // 5. Mount all targets with mountpoints

    // now select all native non-EVMS partitions with a mountpoint
    // and put them in a map. This ensures lexical ordering.
    map<string,list> mountPoints = $[];
    tg = Storage::GetTargetMap();

    foreach( string tdevice, map target, 
             filter( string k, map e, tg, 
	             ``(k!="/dev/loop" && find(k,"/dev/evms")!=0 )),
	``{
	mountPoints = (map<string,list>)DetermineMountPoints( tdevice, target, mountPoints );
	}); // foreach (tdevice)

    y2milestone("non EVMS-MountPoints: %1",mountPoints);

    y2milestone( "Enable automatic module loading for mount");
    if( installation )
	SCR::Execute( .target.bash, 
	              "/bin/echo /sbin/modprobe >/proc/sys/kernel/modprobe");

    if( this_is_for_real )
	{
	cancel = !DoMountList( mountPoints );

	// some mount failed, try to umount all already mounted partitions
	if( cancel )
	    {
	    list<string> mlist = maplist( string k, any e, mountPoints, ``(k) );
	    mlist = sort( string a, string b, mlist, ``(size(a)<size(b)) );
	    DoUmountAndReset( mlist );
	    return `back;
	    }
	}

    if( num_evms>0 || HandleEvmsChanges( tg, false, false ) )
	{
	SCR::Write( .evms.init, "" );
	y2milestone( "dmsetup %1", 
		     SCR::Execute( .target.bash_output, "/sbin/dmsetup ls" ));
	HandleEvmsChanges( tg, false, true );
	RemoveUsedNonEvmsDm( tg );

	// Create and use swap devices
	list<list> swd = filter( list e, swap_devices, 
	                         ``(find(e[0]:"","/dev/evms/")==0));
	list sw = CreateAndActivateSwap( swd );
        activatedswaps = (list<string>)union(activatedswaps, sw);

	// Create filesystems
	cancel = false;
	retry = false;

	foreach( string tdevice, map target, 
		 filter( string k, map e, Storage::GetTargetMap(), 
			 ``(find(k,"/dev/evms")==0 )),
	    ``{
	    // every disk
	    list<map> partitions = target["partitions"]:[];
	    y2milestone( "tdevice %1", tdevice );
	    foreach(map partition, filter( map p, partitions, ``(!p["delete"]:false)),
		``{
		if( !cancel && 
		    (size(partition["mount"]:"")>0 ||
		     size(partition["label"]:"")>0 || 
		     partition["format"]:false))
		    {
		    cancel = !HandleFormatPartition( partition );
		    y2milestone( "after HandleFormatPartition cancel %1", cancel );
		    }
		});
	    });

	// some mkfs failed, go back
	if( cancel )
	    {
	    doswapoff(activatedswaps);
	    losetup_d(activatedLoopDevices);
	    restoretargetmap();
	    return `back;
	    }

	tg = Storage::GetTargetMap();
	list<string> mlist = maplist( string k, any e, mountPoints, ``(k) );
	mlist = sort( string a, string b, mlist, ``(size(a)>size(b)) );
	 y2milestone( "umount list %1", mlist );
	foreach( string m, mlist, 
	    ``{
	    y2milestone( "umount %1", Storage::PathToDestdir( m ) );
	    SCR::Execute( .target.umount, Storage::PathToDestdir( m ) );
	    });
	foreach( string tdevice, map target, 
		 filter( string k, map e, tg, ``(find(k,"/dev/evms")==0 )),
	    ``{
	    mountPoints = (map<string,list>)DetermineMountPoints( tdevice, target, mountPoints );
	    }); // foreach (tdevice)

	y2milestone("added EVMS-MountPoints: %1",mountPoints);

	if( installation )
	    SCR::Execute( .target.bash, 
			  "/bin/echo /sbin/modprobe >/proc/sys/kernel/modprobe");

	if( this_is_for_real )
	    {
	    cancel = !DoMountList( mountPoints );

	    // some mount failed, try to umount all already mounted partitions
	    if( cancel )
		{
		list<string> mlist = maplist( string k, any e, mountPoints, ``(k) );
		mlist = sort( string a, string b, mlist, ``(size(a)<size(b)) );
		DoUmountAndReset( mlist );
		return `back;
		}
	    }
	}

    y2milestone( "dmsetup %1", 
                 SCR::Execute( .target.bash_output, "/sbin/dmsetup ls" ));

    if( size( tg["/dev/loop","partitions"]:[] )>0 && this_is_for_real )
	{
	map loop = tg["/dev/loop"]:$[];
	list mlist = maplist( any k, any e, mountPoints, ``(k) );
	foreach( map p, loop["partitions"]:[],
	    ``{
	    string fpath = Storage::PathToDestdir( p["fpath"]:"" );
	    if( !cancel && p["create"]:false )
		{
		integer size_k = loop["cyl_size"]:0 * p["region",1]:0 / 1024;
		integer max_ur = 10*1024;
		if( size_k<max_ur )
		    {
		    max_ur = size_k;
		    }
		string cmd = 
		    sformat( "dd if=/dev/urandom of=%1 bs=1k count=%2 2>&1", 
		             fpath, max_ur );
		size_k = size_k-max_ur;
		if( size_k>0 )
		    {
		    cmd = cmd + "; dd if=/dev/zero ";
		    cmd = cmd + sformat( "of=%1 bs=1k count=%2 seek=%3 2>&1",
				         fpath, size_k, max_ur );
		    cmd = cmd + " conv=notrunc";
		    }
		if( SCR::Read( .target.size, fpath )>=0 )
		    {
		    SCR::Execute( .target.remove, fpath  );
		    }
		fpath = substring( fpath, 0, findlastof( fpath, "/" ));
		y2milestone( "dir %1", fpath );
		if( SCR::Read( .target.size, fpath )<=0 )
		    {
		    SCR::Execute( .target.mkdir, fpath  );
		    }
		y2milestone( "cmd %1", cmd );
		UI::ChangeWidget( `id(`progress), `Value, 0 );
		UI::ChangeWidget( `id(`progress), `Label, 
				  // label text %1 replaced by pathname 
				  sformat( _("Creating crypt file %1"), 
					   p["fpath"]:"" ));
		map bo = (map)SCR::Execute (.target.bash_output, cmd );
		if( bo["exit"]:1 != 0 )
		    {
		    // popup text %1 replaced by pathname 
		    Report::Error(sformat(_("Could not create crypt file %1"), p["fpath"]:"" ));
		    cancel = true;
		    }
		}
	    if( !cancel && p["delete"]:false )
		{
		if( size(p["loop_dev"]:"")>0 )
		    {
		    SCR::Execute( .target.bash, 
				  "/sbin/losetup -d " + p["loop_dev"]:"" );
		    }
		if( size(p["fpath"]:"")>0 && p["fpath_remove"]:false )
		    {
		    if( SCR::Read( .target.size, fpath )>=0 )
			{
			SCR::Execute( .target.remove, fpath  );
			}
		    }
		}
	    if( !cancel && !p["delete"]:false )
		{
		cancel = !HandleFormatPartition( p );
		}
	    });
	tg = Storage::GetTargetMap();
	loop = tg["/dev/loop"]:$[];
	if( !cancel )
	    {
	    map<string,list> loop_mp = (map<string,list>)DetermineMountPoints( "/dev/loop", loop, $[] );
	    cancel = !DoMountList( loop_mp );
	    if( cancel )
		{
		mlist = union( mlist, maplist( any k, any e, loop_mp, ``(k) ));
		}
	    }
	if( cancel )
	    {
	    DoUmountAndReset( mlist );
	    return `back;
	    }
	}

    y2milestone( "installation=%1", installation );

    if( this_is_for_real )
	{
	//mount proc and usbfs during installation
	if (installation)
	    {
	    string destproc = Installation::scr_destdir+"/proc";
	    SCR::Execute (.target.mkdir, destproc, 0755);
	    SCR::Execute (.target.mount, ["proc", destproc], "-t proc");
	    if (Hotplug::haveUSB)
		{
		SCR::Execute( .target.mount, ["usbfs", destproc +"/bus/usb"],
			      "-t usbfs" );
		}
	    destproc = Installation::scr_destdir+"/sys";
	    SCR::Execute (.target.mkdir, destproc, 0755);
	    SCR::Execute (.target.mount, ["sysfs", destproc], "-t sysfs");
	    }
	Storage::WriteFstab( Storage::GetTargetMap() );
	if( Stage::initial () && Storage::CheckForEvmsRootFs() )
	    {
	    string cmd = "/bin/cp -av /dev/evms " + 
	                 Storage::PathToDestdir("/dev");
	    y2milestone( "cmd %1", cmd );
	    map m = (map) SCR::Execute(.target.bash_output, cmd );
	    y2milestone( "ret %1", m );
	    }
	}

    y2milestone( "Disable automatic module loading");
    if( installation )
	SCR::Execute( .target.bash, 
	              "/bin/echo /etc/nothing >/proc/sys/kernel/modprobe");

    // remove all possibly remaining occurences of entries causing changes
    // in targetmap 
    tg = Storage::GetTargetMap();
    foreach( string device, map disk, tg,
	``{
	list remove_keys = [ "format", "ori_mount", "ori_label", "ori_fstopt", 
	                     "ori_mountby", "create", "resize", "ori_fsid", 
			     "ori_nr", "change_fsid", "ori_length", 
			     "ori_fstype" ];
	list new = [];
	foreach( map part, disk["partitions"]:[],
	    ``{
	    if( !part["delete"]:false )
		{
		part = filter( string k, any v, (map<string,any>)part, ``(!contains( remove_keys, k )));
		new = add( new, part );
		}
	    });
	tg[device,"partitions"] = new;
	});
    tg = filter( string device, map disk, tg, ``(!disk["delete"]:false));
    Storage::SetTargetMap( tg );

    SCR::Write( .target.ycp, Storage::SaveDumpPath("targetMap_pe"), 
                Storage::GetTargetMap() );

    Storage::SetModifyTargets( $[] );

    y2milestone("END of inst_prepdisk.ycp");

//XXX
  //Popup::Message("finish");
//  return `back;

    return `next;
}
