ACC SHELL

Path : /usr/share/YaST2/include/partitioning/
File Upload :
Current File : //usr/share/YaST2/include/partitioning/ep-dialogs.ycp

/**
 * File:	ep-dialogs.ycp
 * Package:	yast2-storage
 * Summary:	Expert Partitioner
 * Authors:	Arvin Schnell <aschnell@suse.de>
 *
 * This file must only be included in other Expert Partitioner files ("ep-*.ycp").
 */
{
    textdomain "storage";


    include "partitioning/custom_part_lib.ycp";


    string MiniWorkflowStepFormatMountHelptext()
    {
	// helptext
	string helptext = _("<p>First, choose whether the partition should be
formatted and the desired file system type.</p>");

	// helptext
	helptext = helptext + _("<p>Changing the encryption on an existing
volume will delete all data on it.</p>");

	// helptext
	helptext = helptext + _("<p>Then, choose whether the partition should
be mounted and enter the mount point (/, /boot, /usr, /var, etc.).</p>");

	return helptext;
    }


    symbol MiniWorkflowStepFormatMount(map<string, any> &orig_data)
    {
	map<string, any> data = orig_data;
	y2milestone("MiniWorkflowStepFormatMount data:%1", data);

        //retrieve all filesystems
	map<symbol, map<symbol, any> > all_filesystems = FileSystems::GetAllFileSystems(true, true);

	void ChangeWidgetIfExists( symbol wid, symbol property, any value)
	{
	    if ( UI::WidgetExists(`id(wid)) )
		UI::ChangeWidget(`id(wid), property, value);
	}

	list <string> ProposeMountpoints( symbol used_fs, string current_mp )
	{
	    map <symbol, any> fs_data = all_filesystems[used_fs]: $[];

	   //not much choice for swap partitions :)
	   if( used_fs == `swap )
	   {
		return fs_data[ `mountpoints ]:[];
	   }
	   //otherwise, ask notUsedMountPoint, it will filter out
	   //mountpoint already in use + add current mountpoint
	   else
	   {
		list <string> not_used = notUsedMountpoints( Storage::GetTargetMap(), fs_data[ `mountpoints]:[]);
		return ( list <string> ) union( [current_mp], not_used );
	   }
	}

	// disable Options p.b. if no fs options can be set
	// disable Encrypt box if fs doesn't support encryption
	void EnableDisableFsOpts( symbol used_fs )
	{
	    map <symbol, any> fs_data = all_filesystems[used_fs]: $[];
	    UI::ChangeWidget(`id(`fs_options), `Enabled, fs_data[`options]:[] != []);
	    ChangeWidgetIfExists(`crypt_fs, `Enabled, fs_data[`crypt]:true);
	}

	boolean do_format = data["format"]:false;
	symbol used_fs = data["used_fs"]:`unknown;
	symbol default_crypt_fs = data["type"]:`unknown == `loop ? `luks : `none;
	boolean crypt_fs = data["enc_type"]:default_crypt_fs != `none;
	boolean orig_crypt_fs = crypt_fs;
	string mount = data["mount"]:"";
	boolean do_mount = mount != "";


	boolean AskPassword()
	{
	    y2milestone( "AskPassword data:%1", data );
	    boolean ret = crypt_fs;
	    if( ret )
		ret = do_format || orig_crypt_fs!=crypt_fs || do_mount;
	    if( ret && !do_format )
		{
		string key = (data["type"]:`unknown != `loop) ? (data["device"]:"error") : (data["fpath"]:"error");
		ret = Storage::NeedCryptPwd(key);
		}
	    return( ret );
	}

	/* MiniWorkflowStepPartitionSize data:
		$["create":true,
		  "cyl_size":8225280,
		   "device":"/dev/sda1",
		   "disk_device":"/dev/sda",
		   "new":true,
		   "slots":$[`primary:[1, 65]],
		   "type":`primary]
	*/

	//Supply some reasonable defaults for newly created partitions
	//and mark it for formatting, too
	if (data["new"]:false && !data["formatmount_proposed"]:false)
	{
	    data["formatmount_proposed"] = true;

	    //propose new mountpoint and filesystem
	    string mount_point_proposal = SingleMountPointProposal( );
	    used_fs = Partitions::DefaultFs();

	    //special case for boot partition
	    if (mount_point_proposal == Partitions::BootMount())
		used_fs = Partitions::DefaultBootFs();

	    data["format"] = true;
	    data["fsid"] = Partitions::fsid_native;
	    data["ori_fsid"] = Partitions::fsid_native;
	    data["used_fs"] = used_fs;

	    //set globals
	    do_format = true;
	    mount = mount_point_proposal;
	    do_mount = mount != "";

	    if (data["type"]:`unknown == `loop)
		do_mount = true;
	}


	term tmp1 = `Empty();
	if (contains([`primary, `extended, `logical], data["type"]:`none))
	{
	    tmp1 = `VBox(`id(`do_not_format_attachment),
			 FsidComboBox(data, FileSystems::GetAllFileSystems(true, true))
		    );
	}

	list mountpoints = ProposeMountpoints( used_fs, mount );

	term contents = `HVSquash(`VStackFrames(
				      `FrameWithMarginBox(_("Formatting Options"),
					     `RadioButtonGroup(`id(`format),
							       `VBox(
								   `LeftRadioButtonWithAttachment(`id(`do_format), `opt(`notify),
												  _("Format partition"),
												  `VBox(`id(`do_format_attachment),
												      FileSystemsComboBox(data, all_filesystems)
												      )),
								   `VSpacing(0.45),
								   `LeftRadioButtonWithAttachment(`id(`do_not_format), `opt(`notify),
												  _("Do not format partition"),
												  tmp1),
								   `VSpacing(0.45),
								   CryptButton(data)
								   )
							)
					  ),
				      `FrameWithMarginBox(_("Mounting Options"),
					     `RadioButtonGroup(`id(`mount),
							       `VBox(
								   `LeftRadioButtonWithAttachment(`id(`do_mount), `opt(`notify),
												  _("Mount partition"),
												  `VBox(
												      `id(`do_mount_attachment),
												      `ComboBox(`id(`mount_point), `opt(`editable, `hstretch, `notify),
														_("Mount Point"), mountpoints),
												      `PushButton(`id(`fstab_options), `opt(`hstretch),
														  // button text
														  _("Fs&tab Options..."))
												      )),
								   `VSpacing(0.45),
								   `LeftRadioButton(`id(`do_not_mount), `opt(`notify),
										    _("Do not mount partition"))
								   )
						 )
					  )
				      )
	    );

	MiniWorkflow::SetContents(Greasemonkey::Transform(contents), MiniWorkflowStepFormatMountHelptext());

	MiniWorkflow::SetLastStep(!AskPassword());

	UI::ChangeWidget(`id(`format), `Value, do_format ? `do_format : `do_not_format);
	UI::ChangeWidget(`id(`do_format_attachment), `Enabled, do_format);
	//not there in RAID/LVM/loop configuration (#483789)
	ChangeWidgetIfExists( `do_not_format_attachment, `Enabled, !do_format );

	if( do_format)
	   EnableDisableFsOpts(used_fs);

	//not there on s390s
	ChangeWidgetIfExists( `crypt_fs, `Value, crypt_fs );

	UI::ChangeWidget(`id(`mount), `Value, do_mount ? `do_mount : `do_not_mount);
	UI::ChangeWidget(`id(`do_mount_attachment), `Enabled, do_mount);
	UI::ChangeWidget(`id(`mount_point), `Value, mount);

	symbol widget = nil;

	data = HandlePartWidgetChanges(true, widget, all_filesystems, orig_data, data);

	repeat
	{
	    widget = MiniWorkflow::UserInput();

	    if (widget != `back && widget != `abort)
	    {
		data = HandlePartWidgetChanges(false, widget, all_filesystems, orig_data, data);
	    }

	    switch (widget)
	    {
		//user has chosen different filesystem
		case `fs:
		{
		    used_fs = (symbol) UI::QueryWidget(`id(`fs), `Value);

		    //retrieve info about fs user has selected
		    map used_fs_data = all_filesystems[used_fs]:$[];
		    y2milestone("Selected filesystem details %1", used_fs_data);

		    if (used_fs != data["used_fs"]:`none)
		    {
			//set file system type
			data["used_fs"] = used_fs;
			data = filter(string key, any value, data, { return key != "fs_options"; });

			//set file system ID (and update the File System ID widget
			//that is - FsidComboBox)
			data["fsid"] = used_fs_data[`fsid]: Partitions::fsid_native;
			UI::ChangeWidget( `id(`fsid_point), `Value, used_fs_data[`fsid_item]:"");

			//suggest some nice mountpoints if user wants to mount this partition
			if (do_mount)
			{
			    UI::ChangeWidget(`id(`mount_point), `Items, ProposeMountpoints( used_fs, mount ));
			}
		    }
		    break;
		}

		case `crypt_fs:
		    crypt_fs = (boolean) UI::QueryWidget(`id(`crypt_fs), `Value);
		    MiniWorkflow::SetLastStep(!AskPassword());
		    break;

		    /* already done in HandlePartWidgetChanges
		case `fs_options:
		    map fs_options = FileSystems::DefaultFormatOptions(data);
		    if (size(fs_options) > 0 && !haskey(data, "fs_options"))
			data["fs_options"] = FileSystems::DefaultFormatOptions(data);

		    map filesystems = FileSystems::GetAllFileSystems(true, true);
		    data["fs_options"] = FileSystemOptions(data["fs_options"]:$[], filesystems[data["used_fs"]:`unknown]:$[]);
		    break;
		    */

		    /* already done in HandlePartWidgetChanges
		case `fstab_options:
		    string fstopt = FileSystems::DefaultFstabOptions(data);
		    if (size(fstopt) > 0 && !haskey(data, "fstopt"))
			data["fstopt"] = fstopt;

		    data = FstabOptions(data, data);
		    break;
		    */

		case `do_format:
		    do_format = (boolean) UI::QueryWidget(`id(`do_format), `Value);
		    data["used_fs"] = (symbol) UI::QueryWidget(`id(`fs), `Value);

		    UI::ChangeWidget(`id(`do_format_attachment), `Enabled, true);
		    ChangeWidgetIfExists(`do_not_format_attachment, `Enabled, false);
		    EnableDisableFsOpts( data["used_fs"]:`none);
		    UI::SetFocus(`id(`fs));
		    MiniWorkflow::SetLastStep(!AskPassword());
		    break;

		case `do_not_format:
		    do_format = (boolean) UI::QueryWidget(`id(`do_format), `Value);
		    UI::ChangeWidget(`id(`do_format_attachment), `Enabled, false);
		    ChangeWidgetIfExists(`do_not_format_attachment, `Enabled, true);
		    MiniWorkflow::SetLastStep(!AskPassword());
		    break;

		case `fsid_point:
		    // TODO
		    break;

		case `do_mount:
		    do_mount = true;
		    UI::ChangeWidget(`id(`do_mount_attachment), `Enabled, true);
		    UI::SetFocus(`id(`mount_point));
		    //propose mountpoints
		    //UI::ChangeWidget(`id(`mount_point), `Items, ProposeMountpoints( used_fs, mount ));
		    MiniWorkflow::SetLastStep(!AskPassword());
		    break;

		case `do_not_mount:
		    do_mount = false;
		    UI::ChangeWidget(`id(`do_mount_attachment), `Enabled, false);
		    MiniWorkflow::SetLastStep(!AskPassword());
		    break;

		case `next:
		    do_format = (boolean) UI::QueryWidget(`id(`do_format), `Value);
		    crypt_fs = (boolean) UI::QueryWidget(`id(`crypt_fs), `Value);
		    do_mount = (boolean) UI::QueryWidget(`id(`do_mount), `Value);
		    mount = (string) UI::QueryWidget(`id(`mount_point), `Value);

		    // TODO: checks
		    //crypt-file specific checks
		    if (data["type"]:`unknown == `loop)
		    {
			//is encrypt fs checked?
			if (!crypt_fs)
			{
			    // error popup
			    Popup::Error(_("Crypt files must be encrypted."));
			    UI::ChangeWidget(`id(`crypt_fs), `Value, true);
			    UI::SetFocus(`id(`crypt_fs));
			    widget = `again;
			    continue;
			}

			//enforce formatting the crypt-file
			if (data["create_file"]:false && !do_format)
			{
			    // error popup
			    Popup::Error(_("You chose to create the crypt file, but did not specify
that it should be formatted. This does not make sense.

Also check the format option.
"));
			    UI::ChangeWidget(`id(`do_format), `Value, true);
			    UI::ChangeWidget(`id(`do_format_attachment), `Enabled, true);
			    UI::SetFocus(`id(`fs));
			    widget = `again;
			    continue;
			}
			//enforce specifying mountpoint
			if (!do_mount)
			{
			    // error popup
			    Popup::Error(_("Crypt files require a mount point."));
			    UI::ChangeWidget(`id(`do_mount), `Value, true);
			    UI::ChangeWidget(`id(`do_mount_attachment), `Enabled, true);
			    UI::SetFocus(`id(`mount_point));
			    widget = `again;
			    continue;
			}
		    }

		    if (do_mount)
		    {
			map ret_mp = CheckOkMount(data["device"]:"error", orig_data, data);
			if (!ret_mp["ok"]:false)
			{
			    if (ret_mp["field"]:`none != `none)
				UI::SetFocus(`id(ret_mp["field"]:`none));
			    widget = `again;
			    continue;
			}
		    }

		    if (do_format)
		    {
			if (!check_ok_fssize(data["size_k"]:0, data))
			{
			    widget = `again;
			    continue;
			}
		    }

		    break;
	    }
	}
	until (widget == `abort || widget == `back || widget == `next);

	if (widget == `next)
	{
	    if( crypt_fs )
		data["enc_type"] = data["format"]:false ? `luks : `twofish;
	    else
		data["enc_type"] = `none;

	    data["format"] = do_format;
	    data["mount"] = do_mount ? mount : "";

	    if (!data["format"]:false)
		data = filter(string key, any value, data, { return key != "fs_options"; });

	    if (contains([`primary, `extended, `logical], data["type"]:`unknown))
		if (data["fsid"]:0 != orig_data["fsid"]:0)
		    data["change_fsid"] = true;

	    if (!AskPassword())
		widget = `finish;

	    orig_data = data;
	}

	y2milestone("MiniWorkflowStepFormatMount data:%1 ret:%2", data, widget);

	return widget;
    }


    string MiniWorkflowStepPasswordHelptext(map<string, any> data)
    {
	integer min_pw_len = data["format"]:false ? 8 : 1;
	boolean empty_pw_allowed = EmptyCryptPwdAllowed(data);

	// helptext
	string helptext = _("<p>
Keep in mind that this file system is only protected when it is not
mounted. Once it is mounted, it is as secure as every other
Linux file system.
</p>");

	if (empty_pw_allowed)
	{
	    if (data["used_fs"]:`unknown == `swap)
		// helptext
                helptext = helptext + _("<p>
The file system used for this volume is swap. You may leave the crypt password
empty but then the swap device cannot be used for hibernating (suspend to
disk).
</p>
");
	    else
		// helptext
		helptext = helptext + _("<p>
This mount point corresponds to a temporary filesystem like /tmp or /var/tmp.
You may leave the crypt password empty. If you do this, the system will create
a random password at system startup for you. This means, you will lose all
data on these filesystems at system shutdown.
</p>
");
	}

        // helptext
        helptext = helptext + _("<p>
If you forget your password, you will lose access to the data on your file system.
Choose your password carefully. A combination of letters and numbers
is recommended. To ensure the password was entered correctly,
enter it twice.
</p>
");

        // helptext, %1 is replaced by integer
        helptext = helptext + sformat(_("<p>
You must distinguish between uppercase and lowercase. A password should have at
least %1 characters and, as a rule, not contain any special characters
(e.g., letters with accents or umlauts).
</p>
"), min_pw_len);

	// helptext
	helptext = helptext + _("<p>
Do not forget this password!
</p>");

	return helptext;
    }


    symbol MiniWorkflowStepPassword(map<string, any> &data)
    {
	y2milestone("MiniWorkflowStepPassword data:%1", data);

	integer min_pw_len = data["format"]:false ? 8 : 1;
	boolean empty_pw_allowed = EmptyCryptPwdAllowed(data);
	boolean two_pw = data["format"]:false || isempty(data["mount"]:"");

	string label = "";

	if( two_pw )
	    {
	    label = _("All data previously present on the volume will be lost!");
	    label = label + "\n";
	    label = label + _("Don't forget what you enter here!");
	    label = label + "\n";
	    }
	if (empty_pw_allowed)
	    label = label + _("Empty password allowed.");

	term ad = `Empty();
	if( two_pw )
	    ad = `Password( `id(`pw2), `opt(`hstretch),
	                    // Label: get same password again for verification
			    // Please use newline if label is longer than 40 characters
			    _("Reenter the password for &verification:"), "");


	term contents = `HVSquash(`FrameWithMarginBox(_("Password"),
					 `VBox(
					     `Password(`id(`pw1), `opt(`hstretch),
						       // Label: get password for user root
						       // Please use newline if label is longer than 40 characters
						       _("&Enter a password for your file system:"), ""),
					     ad,
					     `VSpacing(0.5),
					     `Left(`Label(label))
					     )
				      )
	    );

	MiniWorkflow::SetContents(Greasemonkey::Transform(contents), MiniWorkflowStepPasswordHelptext(data));
	MiniWorkflow::SetLastStep(true);

	string password = "";
	symbol widget = nil;

	//don't put those inside the loop - they'd be reset after each unsuccesful try
	UI::ChangeWidget(`id(`pw1), `Value, "");
	if (two_pw)
	    UI::ChangeWidget(`id(`pw2), `Value, "");

	string dev = (data["type"]:`unknown != `loop) ? data["device"]:"" 
						      : data["fpath"]:"";
	repeat
	{
	    widget = MiniWorkflow::UserInput();

	    if (widget == `next)
	    {
		password = (string) UI::QueryWidget(`id(`pw1), `Value);

		string tmp = password;
		if (two_pw)
		    tmp = (string) UI::QueryWidget(`id(`pw2), `Value);

		boolean need_verify = !data["format"]:false && !isempty(data["mount"]:"");

		if (!Storage::CheckEncryptionPasswords(password, tmp, min_pw_len, empty_pw_allowed) ||
		    (need_verify && !Storage::CheckCryptOk(dev, password, false, false)) )
		{
		    UI::SetFocus(`id(`pw1) );
		    widget = `again;
		}
	    }
	}
	until (widget == `abort || widget == `back || widget == `next);

	if (widget == `next)
	{
	    Storage::SetCryptPwd(dev, password);
	    widget = `finish;
	}

	y2milestone("MiniWorkflowStepPassword data:%1 ret:%2", data, widget);

	return widget;
    }


    boolean DlgResize(map <string, any> &data, map <string, any> disk)
    {
	/*
	 * This resize dialog is simple but avoids several problems faced
	 * before:
	 *
	 * - Stripped digits in a bargraph (bnc #445590)
	 *
	 * - Impossible to resize to maximal size (bnc #373744, #442318,
	 *   #456816)
	 *
	 * - Changing dialog size (bnc #460382)
	 *
	 * If somebody wants fancy stuff like slider or bargraph it's a
	 * feature request.
	 */


	map<string, map> target_map = Storage::GetTargetMap();


	map possible = Storage::IsResizable(data);
	if (!data["format"]:false && !possible["shrink"]:false && !possible["extend"]:false)
	{
	    // popup text
	    Popup::Message(_("
You cannot resize the selected partition because the file system
on this partition does not support resizing.
"));
	    return false;
	}


	integer cyl_size = 0;
	integer free_cyl_after = 0;

	string device = data["device"]:"error";
	symbol used_fs = data["used_fs"]:`none;


	integer used_k = FileSystems::MinFsSizeK(used_fs);
	if (!data["format"]:false)
	{
	    if (used_fs != `swap)
	    {
		map free_data = Storage::GetFreeSpace(device, used_fs, true);
		if (isempty(free_data) || !free_data["ok"]:false)
		{
		    y2error("Failed to retrieve FreeSpace %1, filesystem %2", device, data["used_fs"]:`none);
		    //FIXME: Really?
		    Popup::Error(sformat(_("Partition %1 cannot be resized\nbecause the filesystem seems to be inconsistent"), device));
		    return false;
		}

		used_k = Integer::Max([ used_k, free_data["used"]:0 / 1024 ]);
	    }
	}

	integer min_free_k = 10*1024;
	integer size_k = data["size_k"]:0;

	// minimal and maximal size for volume
	integer min_size_k = Integer::Min([ used_k + min_free_k, size_k ]);
	integer max_size_k = 0;

	string heading = "";

	switch (data["type"]:`unknown)
	{
	    case `primary:
	    case `logical:
	    {
		// Heading for dialog
		heading = sformat(_("Resize Partition %1"), device);

		cyl_size = disk["cyl_size"]:1;
		integer free_cyl_before = 0;
		Storage::FreeCylindersAroundPartition(device, free_cyl_before, free_cyl_after);

		min_size_k = Integer::Max([ min_size_k, cyl_size / 1024 ]);
		max_size_k = size_k + (cyl_size * free_cyl_after) / 1024;
	    }
	    break;

	    case `lvm:
	    {
		// Heading for dialog
		heading = sformat(_("Resize Logical Volume %1"), device);

		min_size_k = Integer::Max([ min_size_k, disk["pesize"]:0 / 1024 ]);
		max_size_k = size_k + (disk["pe_free"]:0 * disk["pesize"]:0) / 1024;
	    }
	    break;
	}

	// size_k + min_size_k could be > max_size_k
	min_size_k = Integer::Min([ min_size_k, max_size_k ]);

	y2milestone("used_k:%1 size_k:%2", used_k, size_k);
	y2milestone("min_size_k:%1 max_size_k:%2", min_size_k, max_size_k);


	term infos = `VBox(`Left(`Label(sformat(_("Current size: %1"), Storage::KByteToHumanString(size_k)))));
	if (used_fs != `swap && !data["format"]:false)
	    infos = add(infos, `Left(`Label(sformat(_("Currently used: %1"), Storage::KByteToHumanString(used_k)))));


	term contents = `HVSquash(
	    // frame heading
	    `FrameWithMarginBox(_("Size"),
				`RadioButtonGroup(`id(`size),
						  `VBox(
						      `LeftRadioButton(`id(`max_size), `opt(`notify),
								       // radio button text, %1 is replaced by size
								       sformat(_("Maximum Size (%1)"), Storage::KByteToHumanString(max_size_k))),
						      `LeftRadioButton(`id(`min_size), `opt(`notify),
								         // radio button text, %1 is replaced by size
								       sformat(_("Minimum Size (%1)"), Storage::KByteToHumanString(min_size_k))),
						      // radio button text
						      `LeftRadioButtonWithAttachment(`id(`custom_size), `opt(`notify), _("Custom Size"),
										     `VBox(`id(`custom_size_attachment),
											   `MinWidth(15, `InputField(`id(`custom_size_input),
														     `opt(`shrinkable), _("Size")))
											 )),
						      `VSpacing(1),
						      infos
						      )
				)
		));

        UI::OpenDialog(
	    `VBox(
	        `Left(`Heading(heading)),
		Greasemonkey::Transform(contents),
		`VSpacing(1.0),
		`ButtonBox(
		    `PushButton(`id(`help), `opt(`helpButton), Label::HelpButton()),
		    `PushButton(`id(`cancel), `opt(`cancelButton), Label::CancelButton()),
		    `PushButton(`id(`ok), `opt(`default, `okButton), Label::OKButton())
		)
	    )
	);

	// help text
	string help_text = _("<p>Choose new size.</p>");

	UI::ChangeWidget(`help, `HelpText, help_text);

	UI::ChangeWidget(`id(`size), `Value, `max_size);
	UI::ChangeWidget(`id(`custom_size_attachment), `Enabled, false);

	symbol widget = nil;

	integer old_size_k = size_k;

	do {

	    widget = (symbol) UI::UserInput();

	    switch (widget)
	    {
	        case `max_size:
	        {
		    UI::ChangeWidget(`id(`custom_size_attachment), `Enabled, false);
		    break;
		}

		case `min_size:
	        {
		    UI::ChangeWidget(`id(`custom_size_attachment), `Enabled, false);
		    break;
		}

		case `custom_size:
	        {
		    UI::ChangeWidget(`id(`custom_size_attachment), `Enabled, true);
		    UI::SetFocus(`id(`custom_size_input));
		    break;
	        }

	        case `ok:
	        {
		    switch ((symbol) UI::QueryWidget(`id(`size), `Value))
		    {
			case `max_size:
			{
			    size_k = max_size_k;
			    break;
			}

			case `min_size:
			{
			    size_k = min_size_k;
			    break;
			}

			case `custom_size:
			{
			    string tmp = (string) UI::QueryWidget(`id(`custom_size_input), `Value);
			    if (!Storage::HumanStringToKByteWithRangeCheck(tmp, size_k, min_size_k, max_size_k))
			    {
				// error popup, %1 and %2 are replaced by sizes
				Popup::Error(sformat(_("The size entered is invalid. Enter a size between %1 and %2."),
						     Storage::KByteToHumanString(min_size_k),
						     Storage::KByteToHumanString(max_size_k)));
				widget = `again;
				continue;
			    }
			    break;
			}
		    }

		    if (size_k != old_size_k)
		    {
			string mountpoint = data["inactive"]:false ? "" : data["mount"]:"";
			boolean lvm = data["type"]:`unknown == `lvm;

			//1 - ask & be interactive, 2 - we are on lvm, 3 - cyl.diff, 4 - filesystem, 5 - mountpoint
			if (!CheckResizePossible(false, lvm, size_k - old_size_k, used_fs, mountpoint))
			{
			    //FIXME: To check whether the part. can be resized only
			    //after user tries to do that is stupid - in some cases
			    //we can tell beforehand, thus user should never get to this
			    //point (e.g. when the partition is mounted)
			    y2error("Resizing the partition is not possible");
			    widget = `again;
			    continue;
			}

			switch (data["type"]:`unknown)
			{
			    case `primary:
			    case `logical:
				integer num_cyl = tointeger(1024.0 * size_k / cyl_size + 0.5);
				num_cyl = Integer::Clamp(num_cyl, 1, data["region", 1]:0 + free_cyl_after);
				data["region", 1] = num_cyl;
				break;

			    case `lvm:
				data["size_k"] = size_k;
				break;
			}
		    }
		    break;
	        }

		case `cancel:
		    break;
	    }

	} while (widget != `cancel && widget != `ok);

	UI::CloseDialog();

	return widget == `ok;
    }


    void DisplayCommandOutput(string command)
    {
	// TODO: maybe use LogView.ycp, but here we want to wait until the command has finished
	// TODO: better error handling

	UI::OpenDialog(`VBox(
			   // label for log view
			   `MinWidth(60, `LogView(`id(`log), sformat(_("Output of %1"), command), 15, 0)),
			   `PushButton(`opt(`default), Label::CloseButton())
			   ));

	map tmp = (map) SCR::Execute(.target.bash_output, command);

	string lines = tmp["stderr"]:"" != "" ? tmp["stderr"]:"" : tmp["stdout"]:"";
	UI::ChangeWidget(`id(`log), `Value, lines);

	UI::UserInput();
	UI::CloseDialog();
    }


    void RescanDisks()
    {
	UI::OpenDialog(`opt(`decorated),
		       // popup text
		       `MarginBox(2, 1, `Label(_("Rescanning disks..."))));

	Storage::ReReadTargetMap();

	UI::CloseDialog();
    }


    boolean ConfirmRecursiveDelete(string device, list<string> devices, string headline, string text_before,
				   string text_after)
    {
	term button_box = `ButtonBox (
		`PushButton(`id(`yes), `opt(`okButton), Label::DeleteButton() ),
		`PushButton(`id(`no_button), `opt(`default, `cancelButton), Label::CancelButton())
	);

	map display_info = UI::GetDisplayInfo();
	boolean has_image_support = display_info["HasImageSupport"]:false;

	term layout =
	`VBox (
	    `VSpacing (0.4),
	    `HBox (
		has_image_support ? `Top (`Image(Icon::IconPath ("question"))) : `Empty(),
		`HSpacing (1),
		`VBox (
		    `Left (`Heading (headline)),
		    `VSpacing (0.2),
		    `Left( `Label( text_before ) ),
		    `VSpacing (0.2),
		    `Left(`RichText(HTML::List(sort(devices)))),
		    `VSpacing (0.2),
		    `Left(`Label( text_after)),
		    button_box
		)
	    )
	);

	UI::OpenDialog(layout);
	symbol ret = (symbol) UI::UserInput();
	UI::CloseDialog();

	return ret == `yes;
    }
}

ACC SHELL 2018