ACC SHELL

Path : /usr/share/YaST2/modules/
File Upload :
Current File : //usr/share/YaST2/modules/StorageFields.ycp

/**
 * File:	StorageFields.ycp
 * Package:	yast2-storage
 * Summary:	Expert Partitioner
 * Authors:	Arvin Schnell <aschnell@suse.de>
 */
{
    module "StorageFields";


    textdomain "storage";


    import "Storage";
    import "StorageIcons";
    import "FileSystems";
    import "Partitions";
    import "Directory";
    import "Mode";
    import "HTML";
    import "Integer";
    import "String";
    import "Region";


    /**
     * Call callback for every disk of target_map in a well defined sorted order.
     */
    global void IterateTargetMap(map<string, map> target_map, void(map<string, map>, map) callback)
    {
	const map disk_order = $[ `CT_DMRAID : 0, `CT_DMMULTIPATH : 1, `CT_MDPART : 2, `CT_DISK : 3,
				  `CT_MD : 4, `CT_LOOP : 5, `CT_LVM : 6, `CT_DM : 7, `CT_NFS : 8 ];

	list<string> keys = maplist(string dev, map disk, target_map, { return dev; });
	keys = sort(string a, string b, keys, {
	    integer oa = disk_order[target_map[a, "type"]:`CT_UNKNOWN]:9;
	    integer ob = disk_order[target_map[b, "type"]:`CT_UNKNOWN]:9;
	    return (oa==ob) ? (a<b) : (oa<ob);
	});

	foreach(string dev, keys, {
	    map disk = target_map[dev]:$[];
	    callback(target_map, disk);
	});
    };


    string BooleanToHumanString(boolean value)
    {
	if (value)
	    // human text for Boolean value
	    return _("Yes");
	else
	    // human text for Boolean value
	    return _("No");
    }


    string UsedByString(map<string, any> used_by)
    {
	symbol type = used_by["type"]:`UB_NONE;
	string device = used_by["device"]:"";

	switch (type)
	{
	    case `UB_LVM:
		return "LVM " + device;
	    case `UB_DM:
		return "DM " + device;
	    case `UB_DMRAID:
		return "DM RAID " + device;
	    case `UB_DMMULTIPATH:
		return "DM Multipath " + device;
	    case `UB_MD:
	    case `UB_MDPART:
		return "MD RAID " + device;
	    default:
		return device;
	}
    }


    global term TableHeader(list<symbol> fields)
    {
	term header = `header();

	foreach(symbol field, fields, {

	    switch (field)
	    {
		case `device:
		    // Column header
		    header = add(header, _("Device"));
		    break;

		case `size:
		    // Column header
		    header = add(header, `Right(_("Size")));
		    break;

		case `type:
		    // Column header
		    header = add(header, _("Type"));
		    break;

		case `format:
		    // Column header, abbreviation for "format" (to format a partition)
		    header = add(header, `Center(_("F")));
		    break;

		case `encrypted:
		    // Column header, , abbreviation for "encrypted" (an encrypted device)
		    header = add(header, `Center(_("Enc")));
		    break;

		case `fs_type:
		    // Column header, abbreviation for "Filesystem Type"
		    header = add(header, _("FS Type"));
		    break;

		case `mount_point:
		    // Column header
		    header = add(header, _("Mount Point"));
		    break;

		case `mount_by:
		    // Column header
		    header = add(header, _("Mount By"));
		    break;

		case `used_by:
		    // Column header
		    header = add(header, _("Used By"));
		    break;

		case `start_cyl:
		    // Column header
		    header = add(header, `Right(_("Start")));
		    break;

		case `end_cyl:
		    // Column header
		    header = add(header, `Right(_("End")));
		    break;

		case `fs_id:
		    // Column header
		    header = add(header, `Right(_("FS Id")));
		    break;

		case `uuid:
		    // Column header
		    header = add(header, _("UUID"));
		    break;

		case `label:
		    // Column header
		    header = add(header, _("Label"));
		    break;

		case `udev_path:
		    // Column header
		    header = add(header, _("Device Path"));
		    break;

		case `udev_id:
		    // Column header
		    header = add(header, _("Device ID"));
		    break;

		case `bios_id:
		    // Column header
		    header = add(header, _("BIOS ID"));
		    break;

		case `disk_label:
		    // Column header
		    header = add(header, _("Disk Label"));
		    break;

		case `lvm_metadata:
		    // Column header
		    header = add(header, _("Metadata"));
		    break;

		case `pe_size:
		    // Column header, abbreviation for "Physical Extent"
		    header = add(header, _("PE Size"));
		    break;

		case `stripes:
		    // Column header
		    header = add(header, _("Stripes"));
		    break;

		case `raid_version:
		    // Column header
		    header = add(header, _("RAID Version"));
		    break;

		case `raid_type:
		    // Column header
		    header = add(header, _("RAID Type"));
		    break;

		case `chunk_size:
		    // Column header
		    header = add(header, _("Chunk Size"));
		    break;

		case `parity_algorithm:
		    // Column header
		    header = add(header, _("Parity Algorithm"));
		    break;

		default:
		    y2error("unknown field %1", field);
		    header = add(header, "error");
		    break;
	    }

	});

	return header;
    }


    string Helptext(symbol field, symbol style)
    {
	string ret = "<p>";

	switch (field)
	{
	    case `bios_id:
		// helptext for table column and overview entry
		ret = ret + _("<b>BIOS ID</b> shows the BIOS ID of the hard
disk. This field can be empty.");
		break;

	    case `bus:
		// helptext for table column and overview entry
		ret = ret + _("<b>Bus</b> shows how the device is connected to
the system. This field can be empty, e.g. for multipath disks.");
		break;

	    case `chunk_size:
		// helptext for table column and overview entry
		ret = ret + _("<b>Chunk Size</b> shows the chunk size for RAID
devices.");
		break;

	    case `cyl_size:
		// helptext for table column and overview entry
		ret = ret + _("<b>Cylinder Size</b> shows the size of the
cylinders of the hard disk.");
		break;

	    case `sector_size:
		// helptext for table column and overview entry
		ret = ret + _("<b>Sector Size</b> shows the size of the
sectors of the hard disk.");
		break;

	    case `device:
		// helptext for table column and overview entry
		ret = ret + _("<b>Device</b> shows the kernel name of the
device.");
		break;

	    case `disk_label:
		// helptext for table column and overview entry
		ret = ret + _("<b>Disk Label</b> shows the partition table
type of the disk, e.g <tt>MSDOS</tt> or <tt>GPT</tt>.");
		break;

	    case `encrypted:
		// helptext for table column and overview entry
		ret = ret + _("<b>Encrypted</b> shows whether the device is
encrypted.");
		break;

	    case `end_cyl:
		// helptext for table column and overview entry
		ret = ret + _("<b>End Cylinder</b> shows the end cylinder of
the partition.");
		break;

	    case `fc_fcp_lun:
		// helptext for table column and overview entry
		ret = ret + _("<b>LUN</b> shows the Logical Unit Number for
Fibre Channel disks.");
		break;

	    case `fc_port_id:
		// helptext for table column and overview entry
		ret = ret + _("<b>Port ID</b> shows the port id for Fibre
Channel disks.");
		break;

	    case `fc_wwpn:
		// helptext for table column and overview entry
		ret = ret + _("<b>WWPN</b> shows the World Wide Port Name for
Fibre Channel disks.");
		break;

	    case `file_path:
		// helptext for table column and overview entry
		ret = ret + _("<b>File Path</b> shows the path of the file for
an encrypted loop device.");
		break;

	    case `format:
		// helptext for table column and overview entry
		ret = ret + _("<b>Format</b> shows some flags: <tt>F</tt>
means the device is selected to be formatted.");
		break;

	    case `fs_id:
		// helptext for table column and overview entry
		ret = ret + _("<b>FS Id</b> shows the file system id.");
		break;

	    case `fs_type:
		// helptext for table column and overview entry
		ret = ret + _("<b>FS Type</b> shows the file system type.");
		break;

	    case `label:
		// helptext for table column and overview entry
		ret = ret + _("<b>Label</b> shows the label of the file
system.");
		break;

	    case `lvm_metadata:
		// helptext for table column and overview entry
		ret = ret + _("<b>Metadata</b> shows the LVM metadata type for
volume groups.");
		break;

	    case `model:
		// helptext for table column and overview entry
		ret = ret + _("<b>Model</b> shows the device model.");
		break;

	    case `mount_by:
		// helptext for table column and overview entry
		ret = ret + _("<b>Mount By</b> indicates how the file system
is mounted: (Kernel) by Kernel Name, (Label) by File System Label, (UUID) by
File System UUID, (ID) by Device ID, and (Path) by Device Path.");
		if (Mode::normal())
		    // helptext for table column and overview entry
		    ret = ret + " " + _("A question mark (?) indicates that
the file system is not listed in <tt>/etc/fstab</tt>. It is either mounted
manually or by some automount system. When changing setting of this volume
YaST will not update <tt>/etc/fstab</tt>.");
		break;

	    case `mount_point:
		// helptext for table column and overview entry
		ret = ret + _("<b>Mount Point</b> shows where the file system
is mounted.");
		if (Mode::normal())
		    // helptext for table column and overview entry
		    ret = ret + " " + _("An asterisk (*) after the mount point
indicates a file system that is currently not mounted (for example, because it
has the <tt>noauto</tt> option set in <tt>/etc/fstab</tt>).");
		break;

	    case `num_cyl:
		// helptext for table column and overview entry
		ret = ret + _("<b>Number of Cylinders</b> shows how many
cylinders the hard disk has.");
		break;

	    case `parity_algorithm:
		// helptext for table column and overview entry
		ret = ret + _("<b>Parity Algorithm</b> shows the parity
algorithm for RAID devices with RAID type 5.");
		break;

	    case `pe_size:
		// helptext for table column and overview entry
		ret = ret + _("<b>PE Size</b> shows the physical extent size
for LVM volume groups.");
		break;

	    case `raid_version:
		// helptext for table column and overview entry
		ret = ret + _("<b>RAID Version</b> shows the RAID version.");
		break;

	    case `raid_type:
		// helptext for table column and overview entry
		ret = ret + _("<b>RAID Type</b> shows the RAID type, also
called RAID level, for RAID devices.");
		break;

	    case `size:
		// helptext for table column and overview entry
		ret = ret + _("<b>Size</b> shows the size of the device.");
		break;

	    case `start_cyl:
		// helptext for table column and overview entry
		ret = ret + _("<b>Start Cylinder</b> shows the start cylinder
of the partition.");
		break;

	    case `stripes:
		// helptext for table column and overview entry
		ret = ret + _("<b>Stripes</b> shows the stripe number for LVM
logical volumes and, if greater than one, in parenthesise the stripe size.");
		break;

	    case `type:
		// helptext for table column and overview entry
		ret = ret + _("<b>Type</b> gives a general overview about the
device type.");
		break;

	    case `udev_id:
		// helptext for table column and overview entry
		ret = ret + _("<b>Device Id</b> shows the persistent device
ids. This field can be empty.");
		break;

	    case `udev_path:
		// helptext for table column and overview entry
		ret = ret + _("<b>Device Path</b> shows the persistent device
path. This field can be empty.");
		break;

	    case `used_by:
		// helptext for table column and overview entry
		ret = ret + _("<b>Used By</b> shows if a device is used by
e.g. RAID or LVM. If you do not use such things, it is perfectly normal for
this column to be empty.");
		break;

	    case `uuid:
		// helptext for table column and overview entry
		ret = ret + _("<b>UUID</b> shows the Universally Unique
Identifier of the file system.");
		break;

	    case `vendor:
		// helptext for table column and overview entry
		ret = ret + _("<b>Vendor</b> shows the device vendor.");
		break;

	    default:
		y2error("unknown field %1", field);
		ret = ret + "error";
		break;
	}

	ret = ret + "</p>";

	return ret;
    }


    any MakeSubInfo(map disk, map part, symbol field, symbol style)
    {
	map data = (part == nil ? disk : part);
	symbol type = ( part == nil ? disk["type"]:`primary : part["type"]:`CT_DISK );

	string device = data["device"]:"";

	switch (field)
	{
	    case `device:
	    {
		string value = device;
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by device name
		    return sformat(_("Device: %1"), String::EscapeTags(value));
	    }

	    case `size:
	    {
		string value = Storage::KByteToHumanString(data["size_k"]:0);
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by size
		    return sformat(_("Size: %1"), value);
	    }

	    case `type:
	    {
		string value = "";

		if (part == nil)
		{
		    string disk_device = disk["device"]:"";
		    string vendor = disk["vendor"]:"";
		    string model = disk["model"]:"";

		    if ((model != "") && (vendor != ""))
			value = vendor + "-" + model;
		    else
			value = vendor + model;

		    if (value == "")
		    {
			if (disk["bus"]:"" == "RAID")
			{
			    value = "RAID " + disk_device;
			}
			else if (disk["type"]:`CT_UNKNOWN == `CT_LVM)
			{
			    value = "LVM" + (disk["lvm2"]:false ? "2 " : " ") + disk["name"]:"";
			}
			else if (disk["type"]:`CT_UNKNOWN == `CT_DMRAID)
			{
			    value = "DM RAID " + disk["name"]:"";
			}
			else if (disk["type"]:`CT_UNKNOWN == `CT_DMMULTIPATH)
			{
			    value = "DM Multipath " + disk["name"]:"";
			}
			else if (disk["type"]:`CT_UNKNOWN == `CT_MDPART)
			{
			    value = "MD RAID " + disk["name"]:"";
			}
			else
			{
			    // label text
			    vendor = sformat(_("DISK %1"), substring(disk_device, 5));
			}
		    }
		}
		else
		{
		    value = part["fstype"]:"";
		}
		if (style == `table)
		    return `cell(`icon(Directory::icondir + "22x22/apps/" + StorageIcons::IconMap(type)), value);
		else
		    // row label
		    return sformat(_("Type: %1"), String::EscapeTags(value));
	    }

	    case `format:
	    {
		string value = "";
		if (part == nil) {
		    if (disk["dasdfmt"]:false)
			value = value + "X";
		} else {
		    if (part["format"]:false)
			value = value + "F";
		}
		if (style == `table)
		    return value;
		else
		    // row label
		    return sformat(_("Format: %1"), value);
	    }

	    case `encrypted:
	    {
		boolean value = data["enc_type"]:`none != `none;
		if (style == `table)
		{
		    if (value)
		    {
			if (UI::GetDisplayInfo()["HasIconSupport"]:false)
			    return `cell(`icon(Directory::icondir + "22x22/apps/" + StorageIcons::encrypted_icon), "");
			else
			    return "E";
		    }
		    else
			return "";
		}
		else
		{
		    // row label, %1 is replace by "Yes" or "No"
		    return sformat(_("Encrypted: %1"), BooleanToHumanString(value));
		}
	    }

	    case `fs_type:
	    {
		string value = FileSystems::GetName(data["used_fs"]:`unknown, "");
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by file system name e.g. "Ext3"
		    return sformat(_("File System: %1"), value);
	    }

	    case `mount_point:
	    {
		string value = data["mount"]:"";

		if (Mode::normal())
		{
		    if (data["inactive"]:false )
			value = value + " *";
		}

		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by mount point e.g. "/mnt"
		    return sformat(_("Mount Point: %1"), String::EscapeTags(value));
	    }

	    case `mount_by:
	    {
		string value = "";

		if (data["mount"]:"" != "") {
		    map tmp = $[ `device : "Kernel", `uuid : "UUID", `label : "Label", `id : "ID", `path : "Path" ];
		    symbol mount_by = data["mountby"]:`device;
		    value = tmp[mount_by]:"";
		}

		if (Mode::normal())
		{
		    boolean tmp = false;
		    if (Storage::GetIgnoreFstab(device, tmp) && tmp)
			value = "?";
		}

		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by mount by method
		    return sformat(_("Mount By: %1"), value);
	    }

	    case `used_by:
	    {
		if (style == `table)
		    return UsedByString(data["used_by", 0]:$[]);
		else
		{
		    integer n = size(data["used_by"]:[]);
		    return mergestring(maplist(integer i, Integer::Range(n == 0 ? 1 : n), {
			// row label, %1 is replaced by number, %2 is replace by device name e.g. /dev/system
			return sformat(_("Used By %1: %2"), i+1, String::EscapeTags(UsedByString(data["used_by", i]:$[])));
		    }), HTML::Newline());
		}
	    }

	    case `uuid:
	    {
		string value = data["uuid"]:"";
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by file system uuid
		    return sformat(_("UUID: %1"), value);
	    }

	    case `label:
	    {
		string value = (part == nil) ? "" : data["label"]:"";
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by file system label
		    return sformat(_("Label: %1"), String::EscapeTags(value));
	    }

	    case `udev_path:
	    {
		string value = data["udev_path"]:"";
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by udev device path
		    return sformat(_("Device Path: %1"), value);
	    }

	    case `udev_id:
	    {
		if (style == `table) {
		    return data["udev_id", 0]:"";
		} else {
		    integer n = size(data["udev_id"]:[]);
		    return mergestring(maplist(integer i, Integer::Range(n == 0 ? 1 : n), {
			// row label, %1 is replaced by number, %2 is replace by udef device id
			return sformat(_("Device ID %1: %2"), i+1, data["udev_id", i]:"");
		    }), HTML::Newline());
		}
	    }

	    case `bios_id:
	    {
		string value = data["bios_id"]:"";
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by bios id
		    return sformat(_("BIOS ID: %1"), value);
	    }

	    case `disk_label:
	    {
		string value = (part == nil) ? toupper(data["label"]:"") : "";
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by disk label e.g. "MSDOS" or "GPT"
		    return sformat(_("Disk Label: %1"), value);
	    }

	    case `vendor:
	    {
		string value = data["vendor"]:"";
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by vendor name
		    return sformat(_("Vendor: %1"), String::EscapeTags(value));
	    }

	    case `model:
	    {
		string value = data["model"]:"";
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by model string
		    return sformat(_("Model: %1"), String::EscapeTags(value));
	    }

	    case `bus:
	    {
		string value = data["bus"]:"";
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by bus name e.g. "SCSI"
		    return sformat(_("Bus: %1"), value);
	    }

	    case `lvm_metadata:
	    {
		string value = "";
		if (disk["type"]:`CT_UNKNOWN == `CT_LVM && part == nil)
		    value = disk["lvm2"]:true ? "LVM2" : "LVM1";
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by metadata version string
		    return sformat(_("Metadata: %1"), value);
	    }

	    case `pe_size:
	    {
		string value = "";
		if (disk["type"]:`CT_UNKNOWN == `CT_LVM && part == nil)
		    value = Storage::ByteToHumanStringOmitZeroes(disk["pesize"]:0);
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by size
		    return sformat(_("PE Size: %1"), value);
	    }

	    case `stripes:
	    {
		string value = "";
		if (disk["type"]:`CT_UNKNOWN == `CT_LVM && part != nil)
		{
		    integer stripes = data["stripes"]:1;
		    integer stripesize = data["stripesize"]:0;
		    if (stripes == 1)
			value = sformat("%1", stripes);
		    else
			value = sformat("%1 (%2)", stripes, Storage::KByteToHumanStringOmitZeroes(stripesize));
		}
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by integer
		    return sformat(_("Stripes: %1"), value);
	    }

	    case `raid_version:
	    {
		string value = data["sb_ver"]:"";
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by raid version e.g. "1.00"
		    return sformat(_("RAID Version: %1"), value);
	    }

	    case `raid_type:
	    {
		string value = toupper(data["raid_type"]:"");
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by raid type e.g. "RAID1"
		    return sformat(_("RAID Type: %1"), value);
	    }

	    case `chunk_size:
	    {
		string value = "";
		if (contains(["raid0", "raid5"], data["raid_type"]:"")) {
		    integer chunksize = data["chunk_size"]:0;
		    value = Storage::KByteToHumanStringOmitZeroes(chunksize);
		}
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by size
		    return sformat(_("Chunk Size: %1"), value);
	    }

	    case `parity_algorithm:
	    {
		string value = "";
		if (contains(["raid5"], data["raid_type"]:"")) {
		    value = data["parity_algorithm"]:"";
		    value = mergestring(splitstring(value, "_"), "-");
		}
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by algorithm name
		    return sformat(_("Parity Algorithm: %1"), value);
	    }

	    case `num_cyl:
	    {
		string value = "";
		if (part == nil && Storage::IsPartitionable(disk))
		    value = tostring(disk["cyl_count"]:0);
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by integer
		    return sformat(_("Number of Cylinders: %1"), value);
	    }

	    case `cyl_size:
	    {
		string value = "";
		if (part == nil && Storage::IsPartitionable(disk))
		    value = Storage::ByteToHumanString(disk["cyl_size"]:0);
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by size
		    return sformat(_("Cylinder Size: %1"), value);
	    }

	    case `start_cyl:
	    {
		string value = "";
		if (Storage::IsPartitionable(disk)) {
		    if (part == nil)
			value = tostring(0);
		    else
			value = tostring(Region::Start(part["region"]:[]));
		}
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by integer
		    return sformat(_("Start Cylinder: %1"), value);
	    }

	    case `end_cyl:
	    {
		string value = "";
		if (Storage::IsPartitionable(disk)) {
		    if (part == nil)
			value = tostring(disk["cyl_count"]:0 - 1);
		    else
			value = tostring(Region::End(part["region"]:[]));
		}
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by integer
		    return sformat(_("End Cylinder: %1"), value);
	    }

	    case `sector_size:
	    {
		string value = "";
		if (part == nil && Storage::IsPartitionable(disk))
		    value = Storage::ByteToHumanStringOmitZeroes(disk["sector_size"]:0);
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by size
		    return sformat(_("Sector Size: %1"), value);
	    }

	    case `fs_id:
	    {
		integer fs_id = data["fsid"]:0;
		string value = Partitions::ToHexString(fs_id) + " " + Partitions::FsIdToString(fs_id);
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by file system id
		    return sformat(_("FS Id: %1"), value);
	    }

	    case `file_path:
	    {
		string value = data["fpath"]:"";
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by file path e.g. "/data/secret"
		    return sformat(_("File Path: %1"), String::EscapeTags(value));
	    }

	    case `fc_wwpn:
	    {
		string value = "";
		if (haskey(data["fc"]:$[], "wwpn"))
		    value = "0x" + toupper(substring(tohexstring(data["fc", "wwpn"]:0, 16), 2));
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by wwpn
		    return sformat(_("WWPN: %1"), value);
	    }

	    case `fc_fcp_lun:
	    {
		string value = "";
		if (haskey(data["fc"]:$[], "fcp_lun"))
		    value = tostring(data["fc", "fcp_lun"]:0);
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by lun
		    return sformat(_("LUN: %1"), value);
	    }

	    case `fc_port_id:
	    {
		string value = "";
		if (haskey(data["fc"]:$[], "port_id"))
		    value = "0x" + toupper(substring(tohexstring(data["fc", "port_id"]:0, 6), 2));
		if (style == `table)
		    return value;
		else
		    // row label, %1 is replace by port id
		    return sformat(_("Port ID: %1"), value);
	    }

	    default:
	    {
		y2error("unknown field %1", field);
		return "error";
	    }
	}
    }


    term TableRow(list<symbol> fields, map disk, map part)
    {
	string device = (part == nil) ? disk["device"]:"" : part["device"]:"";

	term row = list::reduce(term tmp, symbol field, `item(`id(device)), fields, {
	    return add(tmp, MakeSubInfo(disk, part, field, `table));
	});

	return row;
    }


    global boolean AlwaysHideDisk(map<string, map> target_map, map disk)
    {
	boolean real_disk = Storage::IsPartitionable(disk);
	symbol type = disk["type"]:`CT_UNKNOWN;

	if (type == `CT_DISK && !real_disk)
	    return true;

	if (!contains([ `CT_DISK, `CT_DMRAID, `CT_DMMULTIPATH, `CT_MDPART, `CT_LVM ], type))
	    return true;

	return false;
    }


    global boolean AlwaysHidePartition(map<string, map> target_map, map disk, map partition)
    {
	if (partition["fsid"]:0 == Partitions::fsid_mac_hidden)
	    return true;

	return false;
    }


    /**
     * Predicate function for Table and TableContents.
     */
    global symbol PredicateAll(map disk, map partition)
    {
	return `showandfollow;
    }


    /**
     * Predicate function for Table and TableContents.
     */
    global symbol PredicateDiskType(map disk, map partition, list<symbol> disk_types)
    {
	if (partition == nil)
	{
	    if (contains(disk_types, disk["type"]:`CT_UNKNOWN))
		return `showandfollow;
	    else
		return `ignore;
	}
	else
	{
	    return `show;
	}
    }


    /**
     * Predicate function for Table and TableContents.
     */
    global symbol PredicateDiskDevice(map disk, map partition, list<string> disk_devices)
    {
	if (partition == nil)
	{
	    if (contains(disk_devices, disk["device"]:""))
		return `follow;
	    else
		return `ignore;
	}
	else
	{
	    return `show;
	}
    }


    /**
     * Predicate function for Table and TableContents.
     */
    global symbol PredicateDevice(map disk, map partition, list<string> devices)
    {
	if (partition == nil)
	{
	    if (contains(devices, disk["device"]:""))
		return `showandfollow;
	    else
		return `follow;
	}
	else
	{
	    if (contains(devices, partition["device"]:""))
		return `show;
	    else
		return `ignore;
	}
    }


    /**
     * Predicate function for Table and TableContents.
     */
    global symbol PredicateUsedByDevice(map disk, map partition, list<string> devices)
    {
	if (partition == nil)
	{
	    if (find(map used_by, disk["used_by"]:[], { return contains(devices, used_by["device"]:""); }) != nil)
		return `showandfollow;
	    else
		return `follow;
	}
	else
	{
	    if (find(map used_by, partition["used_by"]:[], { return contains(devices, used_by["device"]:""); }) != nil)
		return `show;
	    else
		return `ignore;
	}
    }


    /**
     * Predicate function for Table and TableContents.
     */
    global symbol PredicateMountpoint(map disk, map partition)
    {
	if (partition == nil)
	{
	    if (!isempty(disk["mount"]:""))
		return `showandfollow;
	    else
		return `follow;
	}
	else
	{
	    if (!isempty(partition["mount"]:""))
		return `show;
	    else
		return `ignore;
	}
    }


    /**
     * The predicate function determines whether the disk/partition is
     * included. The predicate function takes two arguments, disk and
     * partition. For disks predicate is called with the partitions set to
     * nil.
     *
     * Possible return values for predicate:
     * `show, `follow, `showandfollow, `ignore
     */
    global list<term> TableContents(list<symbol> fields, map<string, map> target_map,
				    symbol(map, map) predicate)
    {
	list<term> contents = [];

	void callback(map<string, map> target_map, map disk)
	{
	    symbol disk_predicate = predicate(disk, nil);

	    if (!AlwaysHideDisk(target_map, disk) &&
		contains([`show, `showandfollow], disk_predicate))
	    {
		term row = StorageFields::TableRow(fields, disk, nil);
		contents = add(contents, row);
	    }

	    if (contains([`follow, `showandfollow], disk_predicate))
	    {
		list<map> partitions = disk["partitions"]:[];

		foreach(map partition, partitions, {

		    symbol part_predicate = predicate(disk, partition);

		    if (!AlwaysHidePartition(target_map, disk, partition) &&
			contains([`show, `showandfollow], part_predicate))
		    {
			term row = StorageFields::TableRow(fields, disk, partition);
			contents = add(contents, row);
		    }
		});
	    }
	}

	IterateTargetMap(target_map, callback);

	return contents;
    }


    global term Table(list<symbol> fields, map<string, map> target_map,
		      symbol(map, map) predicate)
    {
	term header = TableHeader(fields);
	list<term> content = TableContents(fields, target_map, predicate);

	return `Table(`opt(`keepSorting), header, content);
    }


    global string TableHelptext(list<symbol> fields)
    {
	fields = filter(symbol field, fields, { return substring(tostring(field), 0, 8) != "`heading"; });

	string initial = _("<p>The table contains:</p>");

	string helptext = list::reduce(string tmp, symbol field, initial, fields, {
	    return tmp + Helptext(field, `table);
	});

	return helptext;
    }


    /**
     * The device must be the device entry in the target-map, e.g. "/dev/sda1",
     * not something like "LABEL=test".
     */
    global string OverviewContents(list<symbol> fields, map<string, map> target_map, string device)
    {
	map disk = target_map[device]:nil;
	map part = nil;

	if (disk == nil)
	{
	    foreach(string s, map d, target_map, {
		part = find(map p, d["partitions"]:[], { return p["device"]:"" == device; });
		if (part != nil) {
		    disk = d;
		    break;
		}
	    });
	}

	list< list<symbol> > splitfields(list<symbol> fields)
	{
	    list< list<symbol> > ret = [];

	    list<symbol> tmp = [];
	    foreach(symbol field, fields, {
		if (substring(tostring(field), 0, 8) == "`heading") {
		    if (size(tmp) > 1)
			ret = add(ret, tmp);
		    tmp = [ field ];
		} else {
		    tmp = add(tmp, field);
		}
	    });
	    if (size(tmp) > 1)
		ret = add(ret, tmp);

	    return ret;
	}

	string Heading(symbol field)
	{
	    switch (field) {
		case `heading_device:
		    // heading
		    return _("Device:");
		case `heading_filesystem:
		    // heading
		    return _("File System:");
		case `heading_hd:
		    // heading
		    return _("Hard Disk:");
		case `heading_fc:
		    // heading
		    return _("Fibre Channel:");
		case `heading_lvm:
		    // heading
		    return _("LVM:");
		case `heading_md:
		    // heading
		    return _("RAID:");
		default:
		    y2error("unknown field %1", field);
		    return "error";
	    }
	}

	list<string> List(list<symbol> fields)
	{
	    return maplist(symbol field, fields, {
		// cast to string - overviews expect textual summary
		return ( string ) MakeSubInfo(disk, part, field, `overview);
	    });
	};

	string content = mergestring(maplist(list<symbol> subfields, splitfields(fields), {
	    return HTML::Heading(Heading(subfields[0]:`none)) + HTML::List(List(sublist(subfields, 1)));
	}), "");

	return content;
    }


    global term Overview(list<symbol> fields, map<string, map> target_map, string device)
    {
	string contents = OverviewContents(fields, target_map, device);

	return `RichText(`id(`text), `opt(`hstretch, `vstretch), contents);
    }


    global string OverviewHelptext(list<symbol> fields)
    {
	fields = filter(symbol field, fields, { return substring(tostring(field), 0, 8) != "`heading"; });

	string initial = _("<p>The overview contains:</p>");

	string helptext = list::reduce(string tmp, symbol field, initial, fields, {
	    return tmp + Helptext(field, `overview);
	});

	return helptext;
    }
}

ACC SHELL 2018