ACC SHELL

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

/**
 * File:	ep-lvm-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";


    boolean CheckVgName(string name)
    {
	boolean ret = true;
	string allowed_chars = "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
	    "abcdefghijklmnopqrstuvwxyz" + "._-+";

	if (size(name) == 0)
	{
	    // error popup text
	    Popup::Error(_("Enter a name for the volume group."));
	    ret = false;
	}

	else if (size(name) > 128)
	{
	    // error popup text
	    Popup::Error(_("The name for the volume group is longer than 128 characters."));
	    ret = false;
	}

	else if (substring(name, 0, 1) == "-")
	{
	    // error popup text
	    Popup::Error(_("The name for the volume group must not start with a \"-\"."));
	    ret = false;
	}

	else if (findfirstnotof(name, allowed_chars) != nil)
	{
	    // error popup text
	    Popup::Error(_("The name for the volume group contains illegal characters. Allowed
are alphanumeric characters, \".\", \"_\", \"-\" and \"+\"."));
	    ret = false;
	}
	if (!ret)
	    UI::SetFocus(`id(`vgname));

	return ret;
    }


    boolean CheckVgNameConflict(string name, list<string> vgs)
    {
	boolean ret = true;
	if (contains(vgs, name))
	{
	    // error popup text
	    Popup::Error(sformat(_("The volume group \"%1\" already exists."), name ));
	    ret = false;
	}

	if (!check_vgname_dev(name))
	{
	    // error popup text
	    Popup::Error(sformat(_("The volume group name \"%1\" conflicts
with another entry in the /dev directory.\n"), name));
	    ret = false;
	}

	if (!ret)
	    UI::SetFocus(`id(`vgname));

	return ret;
    }


    boolean ConfirmVgDelete( string vgname, list <string> log_volumes )
    {
	return ConfirmRecursiveDelete( vgname, log_volumes,
	    //pop-up dialog title
	    _("Confirm Deleting of Volume Group"),
	    //pop-up dialog message part 1: %1 is vol.group name
	    sformat( _("The volume group \"%1\" contains at least one logical volume.
If you proceed, the following volumes will be unmounted (if mounted)
and deleted:"), vgname),
	    //pop-up dialog message part 2: %1 is vol.group name
	    sformat( _("Really delete volume group \"%1\" and all related logical volumes?"), vgname)
	);

    }


    boolean CheckPeSize(integer pe_size)
    {
	if (!Integer::IsPowerOfTwo(pe_size) || pe_size < 1024)
	{
	    // error popup, %1, %2 and %3 are replaced by sizes
	    Popup::Error(sformat(_("The data entered is invalid. Insert a physical extent size larger than %1
in powers of 2, for example, \"%2\" or \"%3\""),
			  Storage::KByteToHumanStringOmitZeroes(1),
			  Storage::KByteToHumanStringOmitZeroes(4),
			  Storage::KByteToHumanStringOmitZeroes(4*1024)));
	    UI::SetFocus(`id(`pesize));
	    return false;
	}
	else
	{
	    return true;
	}
    }


    boolean CheckNumberOfDevicesForVg(integer num)
    {
	if (num < 1)
	{
	    // error popup
	    Popup::Error(sformat(_("Select at least one device.")));
	    UI::SetFocus(`id(`unselected));
	    return false;
	}
	else
	{
	    return true;
	}
    }


    boolean CheckLvName(string lv_name)
    {
	boolean ret = true;
	string allowed_chars = "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
	    "abcdefghijklmnopqrstuvwxyz" + "._-+";

	if (size(lv_name) == 0)
	{
	    // error popup text
	    Popup::Error(_("Enter a name for the logical volume."));
	    ret = false;
	}

	else if (size(lv_name) > 128)
	{
	    // error popup text
	    Popup::Error(_("The name for the logical volume is longer than 128 characters."));
	    ret = false;
	}

	else if (findfirstnotof(lv_name, allowed_chars) != nil)
	{
	    // error popup text
	    Popup::Error(_("The name for the logical volume contains illegal characters. Allowed
are alphanumeric characters, \".\", \"_\", \"-\" and \"+\"."));
	    ret = false;
	}

	if(!ret)
	   UI::SetFocus(`id(`lvname));

	return ret;
    }


    boolean CheckLvNameConflict(string lv_name, string vg_name, list<string> lvs)
    {
	if (contains(lvs, lv_name))
	{
	    // error popup text
	    Popup::Error(sformat(_("A logical volume named \"%1\" already exists
in volume group \"%2\"."),
				 lv_name, vg_name));
	    UI::SetFocus(`id(`lvname));
	    return false;
	}

	return true;
    }


    string MiniWorkflowStepVgHelptext()
    {
	// helptext
	string helptext = _("<p>Enter the name and physical extent size of the new volume group.</p>");

	// helptext
	helptext = helptext + _("<p>Select the physical volumes the volume group should contain.</p>");

	return helptext;
    }


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

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

	list<string> vgs = get_vgs(target_map);

	string vgname = size(vgs) == 0 ? "system" : "";
	integer pesize = 4*1024*1024;
	list<string> pvs = [];

	list<symbol> fields = StorageSettings::FilterTable([ `device, `udev_path, `udev_id, `size, `encrypted, `type ]);

	list<map> unused_pvs = filter(map pv, get_possible_pvs(target_map), { return isempty(pv["used_by_device"]:""); });

	term contents = `VBox();

	list<term> pesizes_list = maplist(integer i, Integer::RangeFrom(19, 26), {
	    return `item(`id(2 << i), Storage::ByteToHumanStringOmitZeroes(2 << i));
	});

	// label for input field
	contents = add(contents, `Left(`InputField(`id(`vgname), _("Volume Group Name"))));
	contents = add(contents, `Left(`ComboBoxSelected(`id(`pesize), `opt(`editable),
							 // label for combo box
							 _("&Physical Extent Size"), pesizes_list, `id(pesize))));

	contents = add(contents, DevicesSelectionBox::Create(unused_pvs, [], fields, nil,
							     // label for selection box
							     _("Available Physical Volumes:"),
							     // label for selection box
							     _("Selected Physical Volumes:")));

	MiniWorkflow::SetContents(Greasemonkey::Transform(contents), MiniWorkflowStepVgHelptext());
	MiniWorkflow::SetLastStep(true);
	UI::SetFocus(`id(`vgname));

	symbol widget = nil;

	repeat
	{
	    widget = MiniWorkflow::UserInput();
	    DevicesSelectionBox::Handle(widget);

	    switch (widget)
	    {
		case `next:
		{
		    vgname = (string) UI::QueryWidget(`id(`vgname), `Value);

		    any tmp = UI::QueryWidget(`id(`pesize), `Value);
		    if (is(tmp, integer))
			pesize = (integer) tmp;
		    else if (!Storage::HumanStringToByte((string) tmp, pesize))
			pesize = 0; // will trigger error below

		    pvs = maplist(map pv, DevicesSelectionBox::GetSelectedDevices(), {
			return pv["device"]:"";
		    });

		    if (!CheckVgName(vgname) || !CheckVgNameConflict(vgname, vgs) ||
			!CheckPeSize(pesize) || !CheckNumberOfDevicesForVg(size(pvs)))
			widget = `again;
		}
		break;
	    }
	}
	until (widget == `abort || widget == `back || widget == `next);

	if (widget == `next)
	{
	    data["name"] = vgname;
	    data["pesize"] = pesize;
	    data["devices"] = pvs;

	    widget = `finish;
	}

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

	return widget;
    }


    string MiniWorkflowStepResizeVgHelptext()
    {
	// helptext
	string helptext = _("<p>Change the devices that are used for the volume group.</p>");

	return helptext;
    }


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

	string vgname = data["name"]:"error";
	list<string> pvs_new = [];

	list<symbol> fields = StorageSettings::FilterTable([ `device, `udev_path, `udev_id, `size, `encrypted, `type ]);

	map<string, map> target_map = Storage::GetTargetMap();
	list<map> unused_pvs = filter(map pv, get_possible_pvs(target_map), { return pv["used_by_device"]:"" == ""; });
	list<map> used_pvs = filter(map pv, get_possible_pvs(target_map), { return pv["used_by_device"]:"" == "/dev/" + vgname; });

	term contents = `VBox();

	contents = add(contents, DevicesSelectionBox::Create(unused_pvs, used_pvs, fields, nil,
							    _("Available Physical Volumes:"),
							    _("Selected Physical Volumes:")));

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

	symbol widget = nil;

	repeat
	{
	    widget = MiniWorkflow::UserInput();
	    DevicesSelectionBox::Handle(widget);

	    switch (widget)
	    {
		case `next:
		{
		    pvs_new = maplist(map pv, DevicesSelectionBox::GetSelectedDevices(), {
			return pv["device"]:"";
		    });

		    if (!CheckNumberOfDevicesForVg(size(pvs_new)))
			widget = `again;

		    // TODO: overall size check
		}
		break;
	    }
	}
	until (widget == `abort || widget == `back || widget == `next);

	if (widget == `next)
	{
	    data["devices_new"] = pvs_new;

	    widget = `finish;
	}

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

	return widget;
    }


    boolean DlgCreateVolumeGroupNew(map<string, any> &data)
    {
	map<string, any> aliases = $[
	    "TheOne" : ``(MiniWorkflowStepVg(data))
	];

	map<string, any> sequence = $[
	    "TheOne" : $[ `finish : `finish ]
	];

	// dialog title
	string title = _("Add Volume Group");

	symbol widget = MiniWorkflow::Run(title, StorageIcons::lvm_icon, aliases, sequence, "TheOne");

	return widget == `finish;
    }


    string MiniWorkflowStepLvSizeHelptext()
    {
	// helptext
	string helptext = _("<p>Enter the size as well as the number and size
of stripes for the new logical volume. The number of stripes cannot be higher
than the number of physical volumes of the volume group.</p>");

	return helptext;
    }


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

	integer min_size_k = data["pesize"]:0 / 1024;
	integer max_size_k = data["max_size_k"]:0;
	integer size_k = data["size_k"]:max_size_k;

	symbol what = (size_k == max_size_k) ? `max_size : `manual_size;
	string name = data["name"]:"";

	integer max_stripes = data["max_stripes"]:1;
	integer stripes = data["stripes"]:1;
	integer stripe_size = data["stripesize"]:64*1024;

	term frames = `VStackFrames();

	frames = add(frames,
		     `FrameWithMarginBox(_("Size"),
			    `RadioButtonGroup(`id(`size),
					      `VBox(
						  `LeftRadioButton(`id(`max_size), `opt(`notify),
								   sformat(_("Maximum Size (%1)"), Storage::KByteToHumanString(max_size_k))),
						  `LeftRadioButtonWithAttachment(`id(`manual_size), `opt(`notify), _("Custom Size"),
										 `VBox(`id(`manual_size_attachment),
										       `MinWidth(15, `InputField(`id(`size_input),
														 `opt(`shrinkable), _("Size")))
										     )
						      )
						  )
				)));

	list<term> stripes_list = maplist(integer i, Integer::RangeFrom(1, max_stripes + 1), {
	    return `item(`id(i), tostring(i));
	});

	list<term> stripe_sizes_list = maplist(integer i, Integer::RangeFrom(11, 20), {
	    return `item(`id(2 << i), Storage::ByteToHumanStringOmitZeroes(2 << i));
	});

	// heading for frame
	frames = add(frames, `FrameWithMarginBox(_("Stripes"),
				    `HBox(
					// combo box label
					`Left(`ComboBoxSelected(`id(`stripes), `opt(`notify), _("Number"), stripes_list, `id(stripes))),
					// combo box label
					`Left(`ComboBoxSelected(`id(`stripe_size), _("Size"), stripe_sizes_list, `id(stripe_size))),
					`HStretch())
			 )
	    );

	term contents = `HVSquash(frames);

	//A dialog title - %1 is a logical volume name, %2 is a volume group.
	MiniWorkflow::SetTitle(sformat(_("Add Logical volume %1 on %2"), name, "/dev/" + data["vg_name"]:"error"));
	MiniWorkflow::SetContents(Greasemonkey::Transform(contents), MiniWorkflowStepLvSizeHelptext());
	MiniWorkflow::SetLastStep(false);

	UI::ChangeWidget(`id(`size), `Value, what);
	UI::ChangeWidget(`id(`manual_size_attachment), `Enabled, what == `manual_size);
	UI::ChangeWidget(`id(`size_input), `Value, Storage::KByteToHumanString(size_k));
	UI::ChangeWidget(`id(`stripe_size), `Enabled, stripes > 1);

	symbol widget = nil;

	repeat
	{
	    widget = MiniWorkflow::UserInput();

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

		case `manual_size:
		    UI::ChangeWidget(`id(`manual_size_attachment), `Enabled, true);
		    UI::SetFocus(`id(`size_input));
		    break;

		case `stripes:
		    stripes = (integer) UI::QueryWidget(`id(`stripes), `Value);
		    UI::ChangeWidget(`id(`stripe_size), `Enabled, stripes > 1);
		    break;

		case `next:
		    what = (symbol) UI::QueryWidget(`id(`size), `Value);

		    if (what == `manual_size)
		    {
			string tmp = (string) UI::QueryWidget(`id(`size_input), `Value);
			if (!Storage::HumanStringToKByteWithRangeCheck(tmp, size_k, min_size_k, max_size_k))
			{
			    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;
			}
		    }

		    stripes = (integer) UI::QueryWidget(`id(`stripes), `Value);
		    stripe_size = (integer) UI::QueryWidget(`id(`stripe_size), `Value);
		    break;
	    }
	}
	until (widget == `abort || widget == `back || widget == `next);

	if (widget == `next)
	{
	    switch (what)
	    {
		case `max_size:
		    data["size_k"] = max_size_k;
		    break;

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

	    data["stripes"] = stripes;
	    data["stripesize"] = stripe_size/1024;
	}

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

	return widget;
    }


    boolean DlgResizeVolumeGroup(map<string, any> &data, symbol() Commit)
    {
	map<string, any> aliases = $[
	    "TheOne" : ``(MiniWorkflowStepResizeVg(data)),
	    "Commit" : ``(Commit())
	];

	map<string, any> sequence = $[
	    "TheOne" : $[ `finish : "Commit" ],
	    "Commit" : $[ `finish : `finish ]
	];

	// dialog title
	string title = sformat(_("Resize Volume Group %1"), data["device"]:"error");

	symbol widget = MiniWorkflow::Run(title, StorageIcons::lvm_icon, aliases, sequence, "TheOne");

	return widget == `finish;
    }


    string MiniWorkflowStepLvNameHelptext()
    {
	// helptext
	string helptext = _("<p>Enter the name of the new logical volume.</p>");

	return helptext;
    }


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

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

	string vg_name = data["vg_name"]:"error";

	list<string> lvs = get_lv_names(target_map, vg_name);

	string lv_name = data["name"]:"";

	term contents = `HVSquash(`FrameWithMarginBox(_("Name"),
				`VBox(
				    `Left(`InputField(`id(`lvname), _("Logical Volume"), lv_name)))
				      )
	    );

	MiniWorkflow::SetContents(Greasemonkey::Transform(contents), MiniWorkflowStepLvNameHelptext());
	MiniWorkflow::SetLastStep(false);
	UI::SetFocus(`id(`lvname));

	symbol widget = nil;

	repeat
	{
	    widget = MiniWorkflow::UserInput();

	    switch (widget)
	    {
		case `next:
		    lv_name = (string) UI::QueryWidget(`id(`lvname), `Value);

		    if (!CheckLvName(lv_name) || !CheckLvNameConflict(lv_name, vg_name, lvs))
			widget = `again;

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

	if (widget == `next)
	{
	    data["name"] = lv_name;

	    // ChangeVolumeProperties and thus addLogicalVolume need the device
	    data["device"] = "/dev/" + vg_name + "/" + data["name"]:"";
	}

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

	return widget;
    }


    boolean DlgCreateLogicalVolume(map<string, any> &data, symbol() Commit)
    {
	map<string, any> aliases = $[
	    "Name"        : ``(MiniWorkflowStepLvName(data)),
	    "Size"        : ``(MiniWorkflowStepLvSize(data)),
	    "FormatMount" : ``(MiniWorkflowStepFormatMount(data)),
	    "Password"	  : ``(MiniWorkflowStepPassword(data)),
	    "Commit"      : ``(Commit())
	];

	map<string, any> sequence = $[
	    "Name"        : $[ `next : "Size" ],
	    "Size"        : $[ `next : "FormatMount",
			       `finish : "Commit" ],
	    "FormatMount" : $[ `next : "Password",
			       `finish : "Commit" ],
	    "Password"    : $[ `finish : "Commit" ],
	    "Commit"      : $[ `finish : `finish ]
	];

	// dialog title, %1 is a volume group
	string title = sformat(_("Add Logical Volume on %1"), "/dev/" + data["vg_name"]:"error");

	symbol widget = MiniWorkflow::Run(title, StorageIcons::lvm_lv_icon, aliases, sequence, "Name");

	return widget == `finish;
    }


    boolean DlgEditLogicalVolume(map<string, any> &data)
    {
	string device = data["device"]:"error";

	map<string, any> aliases = $[
	    "FormatMount" : ``(MiniWorkflowStepFormatMount(data)),
	    "Password"	  : ``(MiniWorkflowStepPassword(data))
	];

	map<string, any> sequence = $[
	    "FormatMount" : $[ `next : "Password",
			       `finish : `finish ],
	    "Password"    : $[ `finish : `finish ]
	];

	// dialog title - %1 is a logical volume name, %2 is a volume group
	string title = sformat(_("Edit Logical Volume %1 on %2"), data["name"]:"", regexpsub( device, "^(.*)/[^/]*$", "\\1" ) );

	symbol widget = MiniWorkflow::Run(title, StorageIcons::lvm_lv_icon, aliases, sequence, "FormatMount");

	return widget == `finish;
    }


    boolean DlgResizeLogicalVolumeNew(map <string, any> &lv_data, map <string, any> vg_data)
    {
	return DlgResize(lv_data, vg_data);
    }
}

ACC SHELL 2018