ACC SHELL
/**
* 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\"> "
+ _("<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