ACC SHELL

Path : /usr/share/YaST2/include/checkmedia/
File Upload :
Current File : //usr/share/YaST2/include/checkmedia/ui.ycp

/**
 * File:
 *   include/checkmedia/ui.ycp
 *
 * Summary:
 *   User interface functions for checking media integrity
 *
 * Authors:
 *   Ladislav Slezak <lslezak@suse.cz>
 *
 * $Id: ui.ycp 54734 2009-01-16 19:03:38Z lslezak $
 *
 * All user interface functions.
 *
 */

{

textdomain "packager";

import "Wizard";
import "CheckMedia";

import "Popup";
import "Label";
import "Sequencer";
import "String";
import "Stage";
import "PackageSystem";
import "GetInstArgs";
import "Directory";

// selected input file (used when checking a file instead of physical CD/DVD medium)
string iso_filename = "";

// checking file (ISO image) instead of a medium is in progress
boolean checking_file = false;

define list<term> CDdevices(string preferred) {
    list<map> cds = (list<map>)SCR::Read(.probe.cdrom);
    list<term> ret = [];

    if (cds != nil)
    {
	foreach(map cd, cds, {
		string dev = cd["dev_name"]:"";
		string model = cd["model"]:"";
		boolean deflt = (preferred == dev);

		if (dev != nil && dev != "" && model != nil)
		{
		    ret = add(ret, `item(`id(dev), model + sformat(" (%1)", dev), deflt));
		}
	    }
	);
    }

    return ret;
}

define void SetButtonState(boolean running) {
    UI::ChangeWidget(`id(`stop), `Enabled, running);
    UI::ChangeWidget(`id(`progress), `Enabled, running);
    UI::ChangeWidget(`id(`next), `Enabled, !running);
    UI::ChangeWidget(`id(`start), `Enabled, !running);
    UI::ChangeWidget(`id(`back), `Enabled, !running);
}

define list<string> TranslateInfo(list<string> info) {
    list<string> ret = [];

    if (info != nil)
    {
	foreach(string i, info, {
		list<string> parts = splitstring(i, ":");

		string key = String::CutBlanks(parts[0]:"");
		string val = String::CutBlanks(parts[1]:"");

		map<string,string> trasmap = $[
		    // rich text message, %1 = CD identification
		    "app" : "<P><IMG SRC=\"" + Directory::icondir + "/22x22/apps/yast-checkmedia.png\">&nbsp;&nbsp;&nbsp;"
			+ _("<BIG><B>%1</B></BIG>") + (checking_file ? sformat("  (%1)", iso_filename) : ""),
		    // rich text message, %1 medium number, e.g. CD1,CD2...
		    "media" : _("<UL><LI>Medium: %1</LI></UL>"),
		    // rich text message, %1 = size of the medium
		    "size" : _("<UL><LI>Size: %1</LI></UL>"),
		    // rich text message, %1 = result of the check
		    "check" : _("<UL><LI>Result: %1</LI></UL>"),
		    // rich text -  error message
		    "not an iso" : "<FONT COLOR=red>" + _("The drive does not contain a medium or the ISO file system is broken.") + "</FONT>"
		];

		if (key == "check")
		{
		    // try to translate result string
		    // correct MD5
		    if (val == "md5sum ok")
		    {
			// result of the check - success
			val = "<FONT COLOR=\"darkGreen\">" + _("<B>OK</B> -- The medium has been successfully verified.") + "</FONT>";
		    }
		    else if (val == "md5sum wrong")
		    {
			// wrong MD5
			val = "<FONT COLOR=red>" + _("<B>Error</B> -- MD5 sum does not match<BR>This medium should not be used.") + "</FONT>";
		    }
		    else if (val == "md5sum not checked")
		    {
			// the correct MD5 is unknown
			val = _("<B>Unknown</B> -- The correct MD5 sum of the medium is unknown.");
		    }
		    // progress output
		    else if (issubstring(val, "%\b\b\b\b"))
		    {
			key = "";
			y2milestone("Ignoring progress output: %1", mergestring(splitstring(val, "\b"), "\\b"));
		    }
		}
		// don't print MD5 sum (it doesn't help user)
		else if (key == "md5")
		{
		    y2milestone("Expected MD5 of the medium: %1", val);
		    key = "";
		}

		string newstr = trasmap[key]:"";

		if (newstr != nil && newstr != "")
		{
		    newstr = sformat(newstr, val);

		    ret = add(ret, newstr);
		}
	    }
	);
    }

    y2milestone("Translated info: %1", ret);

    return ret;
}

// does the medium contain MD5 checksum in the application area?
boolean md5sumTagPresent(string input)
{
    string command = sformat("dd if=%1 bs=1 skip=33651 count=512", input);

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

    if (res["exit"]:-1 != 0)
    {
	y2warning("command failed: %1", command);
	return nil;
    }

    y2milestone("Read application area: %1", res["stdout"]:"");

    return regexpmatch(res["stdout"]:"", "md5sum=");
}

// mount CD drive and check whether there is directory 'media.1' (the first medium) and 'boot' (bootable product CD)
define boolean InsertedCD1() {
    boolean ret = true;
    string instmode = (string)SCR::Read(.etc.install_inf.InstMode);

    if (instmode == "cd" || instmode == "dvd")
    {
	string cdrom_device = (string) SCR::Read(.etc.install_inf.Cdrom);

	// bugzilla #305495
	if (cdrom_device == nil || cdrom_device == "") {
	    y2error ("No Cdrom present in install.inf");
	    // try to recover
	    return true;
	}

	// get CD device name
	string bootcd = "/dev/" + cdrom_device;

	// is the device mounted?
	list<map> mounts = (list<map>)SCR::Read(.proc.mounts);
	map<string,string> mnt = listmap(map m, mounts, {return $[m["spec"]:"" : m["file"]:""];});

	string dir = "";
	boolean mounted = false;

	if (haskey(mnt, bootcd))
	{
	    dir = mnt[bootcd]:"";
	}
	else
	{
	    dir = (string)SCR::Read(.target.tmpdir) + "/YaST.mnt";
	    SCR::Execute(.target.mkdir, dir);
	    mounted = (boolean)SCR::Execute(.target.mount, [bootcd, dir], "-o ro");
	}

	// check for the first medium
	integer succ = (integer)SCR::Execute(.target.bash, sformat("test -d %1/media.1 && test -d %1/boot", dir));

	ret = (succ == 0);

	// reset to the previous state
	if (mounted)
	{
	    // unmount back
	    boolean umnt = (boolean)SCR::Execute(.target.umount, dir);
	    y2milestone("unmounted %1: %2", dir, umnt);
	}
    }

    return ret;
}

define void RequireFirstMedium() {
    while (!InsertedCD1())
    {
	// warning popup - the CD/DVD drive doesn't contain the first medium (CD1/DVD1)
	if (Popup::AnyQuestion(Popup::NoHeadline(), _("Insert the first installation medium."),
	    Label::OKButton(), Label::CancelButton(), `focus_yes) == false)
	{
	    break;
	}
    }
}

string log_content = "";

void LogLine(string line)
{
    log_content = log_content + line;
    UI::ChangeWidget(`id(`log), `Value, log_content);
    y2debug("content: %1", log_content);
}

/**
 * Main dialog
 * @return symbol Result from UserInput()
 */
define symbol MainDialog () {

    string req_package = "checkmedia";

    if (SCR::Read(.target.size, CheckMedia::checkmedia) < 0 &&
	!PackageSystem::CheckAndInstallPackagesInteractive([req_package]))
    {
	return `abort;
    }

    // set wizard buttons at first
    if (!CheckMedia::forced_start)
    {
	Wizard::SetNextButton(`next, Label::CloseButton());
    }

    // set buttons according to mode
    if (!Stage::initial())
    {
	// remove Back button - workflow has only one dialog
	Wizard::HideBackButton();
	// remove Abort button - it's useless
	Wizard::HideAbortButton();
    }

    // umount CD drives (release all sources)
    if (Stage::initial())
    {
	// release all media
	Pkg::SourceReleaseAll();
    }

    // dialog header
    string caption = _("Media Check");

    // help text - media check (header) 1/8
    string help = _("<P><B>Media Check</B></P>") +
    // help text - media check 2/8
_("<P>When you have a problem with
the installation and you are using a CD or DVD installation medium, you should check
whether the medium is broken.</P>
") +

    // help text - media check 3/8
_("<P>Select a drive, insert a medium into the drive and press <B>Start Check</B>
or use <B>Check ISO File</B> and select an ISO file.
The check can take several minutes depending on speed of the
drive and size of the medium. The check verifies the MD5 checksum.</P> ") +

    // help text - media check 4/8
_("<P>If the check of the medium fails, you should not continue the installation.
It may fail or you may lose your data. You should replace the broken
medium.</P>
") +

    // help text - media check 5/8
_("After the check you can insert the next medium and start the procedure again.
The order of the media is irrelevant.") +

    // help text - media check 6/8
_("<P><B>Note:</B> You cannot change the medium while it is used by the system.</P>") +

    // help text - media check 7/8
_("<P>To check media before starting installation use the media check item in the boot menu.</P>") +

    // help text - media check 8/8
_("<P>If you burn the media yourself, use the <B>pad</B> option in your recording software. It avoids read errors at the end of media during the check.</P>
");

// advice check of the media
// for translators: split the message to more lines if needed, use max. 50 characters per line
string label = _("It is recommended to check all installation media\nto avoid installation problems. To skip this step press 'Next'");

    term contents = `VBox(
	// combobox label
	CheckMedia::forced_start ? `VBox(`Left(`Label(label)), `VSpacing(0.6)) : `Empty(),
	// combo box
	`HBox(
	    `ComboBox(`id(`cddevices), _("&CD or DVD Drive"), CDdevices(CheckMedia::preferred_drive)),
	    `VBox(
		// empty label for aligning the widgets
		`Label(""),
		`HBox(
		    // push button label
		    `PushButton(`id(`start), _("&Start Check")),
		    `PushButton(`id(`eject), _("&Eject"))
		)
	    ),
	    `HStretch()
	),
	// push button label
	`Left(`PushButton(`id(`iso_file), _("Check ISO File..."))),
	`VSpacing(0.4),
	// widget label
	`Left(`Label(_("Status Information"))),
	`RichText(`id(`log), `opt(`autoScrollDown), ""),
	`VSpacing(0.4),
	// progress bar label
	`ProgressBar(`id(`progress), _("Progress")),
	`VSpacing(0.4),
	// push button label
	`PushButton(`id(`stop), Label::CancelButton())
    );

    Wizard::SetContents(caption,
	contents,
	help,
	GetInstArgs::enable_back(), GetInstArgs::enable_next()
    );

    symbol ret = nil;
    while (true)
    {
	// update state of the buttons (enabled/disabled)
	SetButtonState(false);

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

	y2milestone("ui: %1", ret);

	if (ret == `next || ret == `back)
	{
	    // avoid reproposing of the installation -  always return `back in
	    // the initial mode when the module start wasn't forced (after
	    // language selection)
	    if (Stage::initial() && !CheckMedia::forced_start)
	    {
		ret = `back;
	    }
	    break;
	}
	else if (ret == `cancel)
	{
	    ret = `abort;
	    break;
	}
	else if (ret == `abort)
	{
	    if (Popup::ConfirmAbort(`painless))
	    {
		ret = `abort;
		break;
	    }
	}
	else if (ret == `start || ret == `iso_file)
	{
	    string selecteddrive = "";

	    checking_file = (ret == `iso_file);

	    if (checking_file)
	    {
		// window title - open file dialog
		selecteddrive = UI::AskForExistingFile(iso_filename, "*.iso", _("Select an ISO File to Check"));

		// remember for the next run
		if (selecteddrive != nil)
		{
		    iso_filename = selecteddrive;
		}
	    }
	    else
	    {
		selecteddrive = (string)UI::QueryWidget(`id(`cddevices), `Value);
	    }

	    if (selecteddrive != nil && selecteddrive != "")
	    {
		SetButtonState(true);

		y2milestone("starting media check at drive %1", selecteddrive);
		// progress message, %1 is CD device name (e.g. /dev/hdc)
		//UI::ChangeWidget(`id(`log), `LastLine, sformat(_("Check started (%1)...\n"), selecteddrive));

		//LogLine(sformat(_("Check started (%1)...\n"), selecteddrive));

		// try to read one byte from the medium
		integer res = (integer)SCR::Execute(.target.bash, sformat("/usr/bin/head -c 1 %1 > /dev/null", selecteddrive));
		if (res != 0)
		{
		    // error message: the medium cannot be read or no medium in the drive; %1 = drive, e.g. /dev/hdc
		    LogLine("<FONT COLOR=red>" + sformat(_("Cannot read medium in the drive %1."), selecteddrive) + "</FONT>");
		}
		else
		{
		    if (md5sumTagPresent(selecteddrive) == false)
		    {
			if (!Popup::ContinueCancel(_("The medium does not contain a MD5 checksum.
The content of the medium cannot be verified.

Only readability of the medium will be checked.
")))
			{
			    continue;
			}
		    }

		    CheckMedia::Start(selecteddrive);

		    boolean loop = true;
		    boolean aborted = false;
		    while(loop)
		    {
			loop = CheckMedia::Running();
			CheckMedia::Process();

			integer progress = CheckMedia::Progress();
			list<string> data = CheckMedia::Info();

			if (data != nil && size(data) > 0)
			{
			    data = TranslateInfo(data);

			    // add new output to the log view
			    string info = mergestring(data, "");
			    LogLine(info);
			}

			if (progress > 0)
			{
			    UI::ChangeWidget(`id(`progress), `Value, progress);
			}

			symbol ui = (symbol)UI::PollInput();

			if (ui == `stop || ui == `cancel)
			{
			    CheckMedia::Stop();
			    loop = false;
			    aborted = true;
			}
			else if (ui == `abort)
			{
			    if (Popup::ConfirmAbort(`painless))
			    {
				CheckMedia::Stop();

				return `abort;
			    }
			}

			// sleep for a while
			sleep(200);
		    }

		    SetButtonState(false);

		    if (aborted)
		    {
			// the check has been canceled
			LogLine(sformat(_("<UL><LI>Result: %1</LI></UL>"), _("<B>Canceled</B>")));
		    }
		}

		// process remaining output
		CheckMedia::Process();
		list<string> data = CheckMedia::Info();

		if (data != nil && size(data) > 0)
		{
		    data = TranslateInfo(data);

		    // add new output to the log view
		    string info = mergestring(data, "");
		    LogLine(info);
		}

		CheckMedia::Release();

		// finish the paragraph
		LogLine("<BR></P>");
		// set zero progress
		UI::ChangeWidget(`id(`progress), `Value, 0);
	    }
	}
	else if (ret == `eject)
	{
	    string selecteddrive = (string)UI::QueryWidget(`id(`cddevices), `Value);
	    string command = "/bin/eject " + selecteddrive;

	    y2milestone("Executing '%1'", command);

	    map res = (map)SCR::Execute(.target.bash_output, command);
	    y2milestone("Result: %1", res);
	}
	else
	{
	    y2warning("unknown UserInput: %1", ret);
	}
    };

    if (Stage::initial())
    {
	// is the first medium in drive?
	RequireFirstMedium();
    }

    return ret;
}


/**
 * Main workflow of the idedma configuration
 * @return any Result from WizardSequencer() function
 */
define any MainSequence () ``{
    map aliases =
	$[
	    "checkmedia" : ``(MainDialog()),
	];

    map sequence = $[
	"ws_start" : "checkmedia",
	"checkmedia" :
	$[
	    `abort	: `abort,
	    `next	: `next
	]
    ];

    Wizard::CreateDialog();
    Wizard::SetDesktopIcon("checkmedia");

    any ret = Sequencer::Run(aliases, sequence);

    UI::CloseDialog();
    return ret;
}


}

ACC SHELL 2018