home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / boot / i386 / root / usr / share / YaST2 / include / checkmedia / ui.ycp
Text File  |  2006-11-29  |  13KB  |  540 lines

  1. /**
  2.  * File:
  3.  *   include/checkmedia/ui.ycp
  4.  *
  5.  * Summary:
  6.  *   User interface functions for checking media integrity
  7.  *
  8.  * Authors:
  9.  *   Ladislav Slezak <lslezak@suse.cz>
  10.  *
  11.  * $Id: ui.ycp 33383 2006-10-13 09:12:02Z lslezak $
  12.  *
  13.  * All user interface functions.
  14.  *
  15.  */
  16.  
  17. {
  18.  
  19. textdomain "packager";
  20.  
  21. import "Wizard";
  22. import "CheckMedia";
  23.  
  24. import "Popup";
  25. import "Label";
  26. import "Sequencer";
  27. import "String";
  28. import "Stage";
  29.  
  30. define list<term> CDdevices(string preferred) {
  31.     list<map> cds = (list<map>)SCR::Read(.probe.cdrom);
  32.     list<term> ret = [];
  33.  
  34.     if (cds != nil)
  35.     {
  36.     foreach(map cd, cds, {
  37.         string dev = cd["dev_name"]:"";
  38.         string model = cd["model"]:"";
  39.         boolean deflt = (preferred == dev);
  40.  
  41.         if (dev != nil && dev != "" && model != nil)
  42.         {
  43.             ret = add(ret, `item(`id(dev), model + sformat(" (%1)", dev), deflt));
  44.         }
  45.         }
  46.     );
  47.     }
  48.  
  49.     return ret;
  50. }
  51.  
  52. define void SetButtonState(boolean running) {
  53.     UI::ChangeWidget(`id(`stop), `Enabled, running);
  54.     UI::ChangeWidget(`id(`progress), `Enabled, running);
  55.     UI::ChangeWidget(`id(`next), `Enabled, !running);
  56.     UI::ChangeWidget(`id(`start), `Enabled, !running);
  57.     UI::ChangeWidget(`id(`back), `Enabled, !running);
  58. }
  59.  
  60. define list<string> TranslateInfo(list<string> info) {
  61.     list<string> ret = [];
  62.  
  63.     if (info != nil)
  64.     {
  65.     foreach(string i, info, {
  66.         list<string> parts = splitstring(i, ":");
  67.  
  68.         string key = String::CutBlanks(parts[0]:"");
  69.         string val = String::CutBlanks(parts[1]:"");
  70.  
  71.         map<string,string> trasmap = $[
  72.             // rich text message, %1 = CD identification
  73.             "app" : ("<BIG><B>%1</B></BIG>"),
  74.             // rich text message, %1 medium number, e.g. CD1,CD2...
  75.             "media" : _("<UL><LI>Medium: %1</LI></UL>"),
  76.             // rich text message, %1 = size of the medium
  77.             "size" : _("<UL><LI>Size: %1</LI></UL>"),
  78.             // rich text message, %1 = result of the check
  79.             "check" : _("<UL><LI>Result: %1</LI></UL>"),
  80.             // rich text -  error message
  81.             "not an iso" : _("The drive does not contain a medium or the ISO file system is broken.")
  82.         ];
  83.  
  84.         if (key == "check")
  85.         {
  86.             // try to translate result string
  87.             // correct MD5
  88.             if (val == "md5sum ok")
  89.             {
  90.             // result of the check - success
  91.             val = _("<B>OK</B>");
  92.             }
  93.             else if (val == "md5sum wrong")
  94.             {
  95.             // wrong MD5
  96.             val = _("<B>Error</B> -- MD5 sum does not match<BR>The medium should not be used.");
  97.             }
  98.             else if (val == "md5sum not checked")
  99.             {
  100.             // the correct MD5 is unknown
  101.             val = _("<B>Unknown</B> -- The correct MD5 sum of the medium is unknown.");
  102.             }
  103.             // progress output
  104.             else if (issubstring(val, "%\b\b\b\b"))
  105.             {
  106.             key = "";
  107.             y2milestone("Ignoring progress output: %1", mergestring(splitstring(val, "\b"), "\\b"));
  108.             }
  109.         }
  110.         // don't print MD5 sum (it doesn't help user)
  111.         else if (key == "md5")
  112.         {
  113.             y2milestone("Expected MD5 of the medium: %1", val);
  114.             key = "";
  115.         }
  116.  
  117.         string newstr = trasmap[key]:"";
  118.  
  119.         if (newstr != nil && newstr != "")
  120.         {
  121.             newstr = sformat(newstr, val);
  122.  
  123.             ret = add(ret, newstr);
  124.         }
  125.         }
  126.     );
  127.     }
  128.  
  129.     y2milestone("Translated info: %1", ret);
  130.  
  131.     return ret;
  132. }
  133.  
  134. /**
  135.  * Unmount CD drives in the first installation stage
  136.  * @return map map with unmounted drives (key: device name, value: mount point)
  137.  */
  138. define map<string,string> UnmountCD() {
  139.     // key: device, value: mountpoint
  140.     map<string,string> unmounted = $[];
  141.  
  142.     if (Stage::initial())
  143.     {
  144.     list<map> cddevices = CheckMedia::DetectedCDDevices();
  145.     y2milestone("Detected CD devices: %1", cddevices);
  146.  
  147.     if (cddevices != nil)
  148.     {
  149.         // reload /proc/mounts file
  150.         SCR::UnmountAgent(.proc.mounts);
  151.  
  152.         list<map> mounts = (list<map>)SCR::Read(.proc.mounts);
  153.         list<string> cddevs = maplist(map cdd, cddevices, {return cdd["dev_name"]:"";});
  154.  
  155.         // check which CD drive is mounted
  156.         foreach(map mnt, mounts, {
  157.             string mpoint = mnt["file"]:"";
  158.             string device = mnt["spec"]:"";
  159.  
  160.             if (mpoint != nil && device != nil && contains(cddevs, device))
  161.             {
  162.             boolean succ = (boolean) SCR::Execute(.target.umount, mpoint);
  163.             if (succ == true)
  164.             {
  165.                 unmounted = add(unmounted, device, mpoint);
  166.                 y2milestone("Unmounted device: %1 (%2)", device, mpoint);
  167.             }
  168.             else
  169.             {
  170.                 y2warning("Could not unmount device %1 (%2)", device, mpoint);
  171.             }
  172.             }
  173.         }
  174.         );
  175.     }
  176.     }
  177.  
  178.     y2milestone("unmounted: %1", unmounted);
  179.  
  180.     return unmounted;
  181. }
  182.  
  183. define boolean MountCD(map<string,string> mountedCDs) {
  184.     y2milestone("mountedCDs: %1", mountedCDs);
  185.     boolean ret = true;
  186.  
  187.     if (Stage::initial() && size(mountedCDs) > 0)
  188.     {
  189.     // remount all unmounted devices back
  190.     foreach(string device, string mpoint, mountedCDs, {
  191.         boolean succ = (boolean)SCR::Execute(.target.mount, [device, mpoint], "-o ro");
  192.         if (succ)
  193.         {
  194.             y2milestone("Remounted device %1 (%2)", device, mpoint);
  195.         }
  196.         else
  197.         {
  198.             y2error("Mount failed: %1 (%2)", device, mpoint);
  199.             ret = false;
  200.         }
  201.         }
  202.     );
  203.     }
  204.  
  205.     return ret;
  206. }
  207.  
  208. // mount CD drive and check whether there is directory 'media.1' (the first medium) and 'boot' (bootable product CD)
  209. define boolean InsertedCD1() {
  210.     boolean ret = true;
  211.     string instmode = (string)SCR::Read(.etc.install_inf.InstMode);
  212.  
  213.     if (instmode == "cd" || instmode == "dvd")
  214.     {
  215.     // get CD device name
  216.     string bootcd = "/dev/" + (string)SCR::Read(.etc.install_inf.Cdrom);
  217.  
  218.     // is the device mounted?
  219.     list<map> mounts = (list<map>)SCR::Read(.proc.mounts);
  220.     map<string,string> mnt = listmap(map m, mounts, {return $[m["spec"]:"" : m["file"]:""];});
  221.  
  222.     string dir = "";
  223.     boolean mounted = false;
  224.  
  225.     if (haskey(mnt, bootcd))
  226.     {
  227.         dir = mnt[bootcd]:"";
  228.     }
  229.     else
  230.     {
  231.         dir = (string)SCR::Read(.target.tmpdir) + "/YaST.mnt";
  232.         SCR::Execute(.target.mkdir, dir);
  233.         mounted = (boolean)SCR::Execute(.target.mount, [bootcd, dir], "-o ro");
  234.     }
  235.  
  236.     // check for the first medium
  237.     integer succ = (integer)SCR::Execute(.target.bash, sformat("test -d %1/media.1 && test -d %1/boot", dir));
  238.  
  239.     ret = (succ == 0);
  240.  
  241.     // reset to the previous state
  242.     if (mounted)
  243.     {
  244.         // unmount back
  245.         boolean umnt = (boolean)SCR::Execute(.target.umount, dir);
  246.         y2milestone("unmounted %1: %2", dir, umnt);
  247.     }
  248.     }
  249.  
  250.     return ret;
  251. }
  252.  
  253. define void RequireFirstMedium() {
  254.     while (!InsertedCD1())
  255.     {
  256.     // warning popup - the CD/DVD drive doesn't contain the first medium (CD1/DVD1)
  257.     if (Popup::AnyQuestion(Popup::NoHeadline(), _("Insert the first installation medium."),
  258.         Label::OKButton(), Label::CancelButton(), `focus_yes) == false)
  259.     {
  260.         break;
  261.     }
  262.     }
  263. }
  264.  
  265. string log_content = "";
  266.  
  267. void LogLine(string line)
  268. {
  269.     log_content = log_content + line;
  270.     UI::ChangeWidget(`id(`log), `Value, log_content);
  271.     y2debug("content: %1", log_content);
  272. }
  273.  
  274. /**
  275.  * Main dialog
  276.  * @return symbol Result from UserInput()
  277.  */
  278. define symbol MainDialog () {
  279.  
  280.     // set wizard buttons at first
  281.     if (!CheckMedia::forced_start)
  282.     {
  283.     Wizard::SetNextButton(`next, Label::CloseButton());
  284.     }
  285.  
  286.     // set buttons according to mode
  287.     if (!Stage::initial())
  288.     {
  289.     // remove Back button - workflow has only one dialog
  290.     Wizard::HideBackButton();
  291.     // remove Abort button - it's useless
  292.     Wizard::HideAbortButton();
  293.     }
  294.  
  295.     // umount CD drives (only in the first stage)
  296.     map<string,string> unmountedCD = UnmountCD();
  297.  
  298.     // dialog header
  299.     string caption = _("Media Check");
  300.  
  301.     // help text - media check (header) 1/7
  302.     string help = _("<P><B>Media Check</B></P>") +
  303.     // help text - media check 2/7
  304. _("<P>When you have a problem with
  305. installation and are using a CD or DVD installation medium, you should check
  306. whether the medium could be broken.</P>
  307. ") +
  308.  
  309.     // help text - media check 3/7
  310. _("<P>Select a drive, insert a medium into the drive, and press <B>Start Check</B>
  311. to perform the check. The check can take several minutes depending on
  312. speed of the drive and size of the medium. The check verifies the MD5 checksum.</P>
  313. ") +
  314.  
  315.     // help text - media check 4/7
  316. _("<P>If the check of the medium fails, you should not continue the installation.
  317. It may fail or you may lose your data. You should replace the broken
  318. medium.</P>
  319. ") +
  320.  
  321.     // help text - media check 5/7
  322. _("After the check you can insert the next medium and start the procedure again.
  323. The order of the media is irrelevant.") +
  324.  
  325.     // help text - media check 6/7
  326. _("<P><B>Note:</B> You cannot change the medium if it is used by the system. If
  327. it happens during installation, start manual installation and select the media
  328. verification item in the menu.</P> 
  329. ") +
  330.  
  331.     // help text - media check 7/6
  332. _("<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>
  333. ");
  334.  
  335. // advice check of the media
  336. string label = _("It is recommended to check all installation media to avoid installation problems.");
  337.  
  338.     term contents = `VBox(
  339.     // combobox label
  340.     CheckMedia::forced_start ? `VBox(`Left(`Label(label)), `VSpacing(0.6)) : `Empty(),
  341.     // combo box
  342.     `Left(`ComboBox(`id(`cddevices), _("&CD or DVD Drive"), CDdevices(CheckMedia::preferred_drive))),
  343.     `VSpacing(0.4),
  344.     // widget label
  345.     `Left(`Label(_("Status Information"))),
  346.     `RichText(`id(`log), `opt(`autoScrollDown), ""),
  347.     `VSpacing(0.4),
  348.     // progress bar label
  349.     `ProgressBar(`id(`progress), _("Progress")),
  350.     `VSpacing(1),
  351.     `HBox(
  352.         // push button label
  353.         `PushButton(`id(`start), _("&Start Check")),
  354.         `HSpacing(2),
  355.         // push button label
  356.         `PushButton(`id(`stop), Label::CancelButton())
  357.     )//,
  358. //    `VSpacing(1)
  359.     );
  360.  
  361.     Wizard::SetContents(caption,
  362.     contents,
  363.     help,
  364.     true, true
  365.     );
  366.  
  367.     symbol ret = nil;
  368.     while (true)
  369.     {
  370.     // update state of the buttons (enabled/disabled)
  371.     SetButtonState(false);
  372.  
  373.     ret = (symbol)UI::UserInput();
  374.  
  375.     y2milestone("ui: %1", ret);
  376.  
  377.     if (ret == `next || ret == `back)
  378.     {
  379.         // avoid reproposing of the installation -  always return `back in
  380.         // the initial mode when the module start wasn't forced (after
  381.         // language selection)
  382.         if (Stage::initial() && !CheckMedia::forced_start)
  383.         {
  384.         ret = `back;
  385.         }
  386.         break;
  387.     }
  388.     else if (ret == `cancel)
  389.     {
  390.         ret = `abort;
  391.         break;
  392.     }
  393.     else if (ret == `abort)
  394.     {
  395.         if (Popup::ConfirmAbort(`painless))
  396.         {
  397.         ret = `abort;
  398.         break;
  399.         }
  400.     }
  401.     else if (ret == `start)
  402.     {
  403.         string selecteddrive = (string)UI::QueryWidget(`id(`cddevices), `Value);
  404.  
  405.         if (selecteddrive != nil && selecteddrive != "")
  406.         {
  407.         SetButtonState(true);
  408.  
  409.         y2milestone("starting media check at drive %1", selecteddrive);
  410.         // progress message, %1 is CD device name (e.g. /dev/hdc)
  411.         //UI::ChangeWidget(`id(`log), `LastLine, sformat(_("Check started (%1)...\n"), selecteddrive));
  412.  
  413.         //LogLine(sformat(_("Check started (%1)...\n"), selecteddrive));
  414.  
  415.         // try to read one byte from the medium
  416.         integer res = (integer)SCR::Execute(.target.bash, sformat("/usr/bin/head -c 1 %1 > /dev/null", selecteddrive));
  417.         if (res != 0)
  418.         {
  419.             // error message: the medium cannot be read or no medium in the drive; %1 = drive, e.g. /dev/hdc
  420.             LogLine(sformat(_("Cannot read medium in the drive %1."), selecteddrive));
  421.         }
  422.         else
  423.         {
  424.             CheckMedia::Start(selecteddrive);
  425.  
  426.             boolean loop = true;
  427.             boolean aborted = false;
  428.             while(loop)
  429.             {
  430.             CheckMedia::Process();
  431.  
  432.             integer progress = CheckMedia::Progress();
  433.             list<string> data = CheckMedia::Info();
  434.  
  435.             if (data != nil && size(data) > 0)
  436.             {
  437.                 data = TranslateInfo(data);
  438.  
  439.                 // add new output to the log view
  440.                 string info = mergestring(data, "");
  441.                 LogLine(info);
  442.             }
  443.  
  444.             if (progress > 0)
  445.             {
  446.                 UI::ChangeWidget(`id(`progress), `Value, progress);
  447.             }
  448.  
  449.             symbol ui = (symbol)UI::PollInput();
  450.  
  451.             loop = CheckMedia::Running();
  452.  
  453.             if (ui == `stop || ui == `cancel)
  454.             {
  455.                 CheckMedia::Stop();
  456.                 loop = false;
  457.                 aborted = true;
  458.             }
  459.             else if (ui == `abort)
  460.             {
  461.                 if (Popup::ConfirmAbort(`painless))
  462.                 {
  463.                 CheckMedia::Stop();
  464.  
  465.                 // remount umounted CD drives back
  466.                 MountCD(unmountedCD);
  467.  
  468.                 return `abort;
  469.                 }
  470.             }
  471.  
  472.             // sleep for a while
  473.             sleep(200);
  474.             }
  475.  
  476.             SetButtonState(false);
  477.  
  478.             if (aborted)
  479.             {
  480.             // the check has been canceled
  481.             LogLine(sformat(_("<UL><LI>Result: %1</LI></UL>"), _("<B>Canceled</B>")));
  482.             }
  483.         }
  484.  
  485.         // add empty lines between checks
  486.         LogLine("<BR><BR>");
  487.         // set zero progress
  488.         UI::ChangeWidget(`id(`progress), `Value, 0);
  489.         }
  490.     }
  491.     else
  492.     {
  493.         y2warning("unknown UserInput: %1", ret);
  494.     }
  495.     };
  496.  
  497.     if (Stage::initial())
  498.     {
  499.     // is the first medium in drive?
  500.     RequireFirstMedium();
  501.     }
  502.  
  503.     // remount umounted CD drives back
  504.     MountCD(unmountedCD);
  505.  
  506.     return ret;
  507. }
  508.  
  509.  
  510. /**
  511.  * Main workflow of the idedma configuration
  512.  * @return any Result from WizardSequencer() function
  513.  */
  514. define any MainSequence () ``{
  515.     map aliases =
  516.     $[
  517.         "checkmedia" : ``(MainDialog()),
  518.     ];
  519.  
  520.     map sequence = $[
  521.     "ws_start" : "checkmedia",
  522.     "checkmedia" :
  523.     $[
  524.         `abort    : `abort,
  525.         `next    : `next
  526.     ]
  527.     ];
  528.  
  529.     Wizard::CreateDialog();
  530.     Wizard::SetDesktopIcon("checkmedia");
  531.  
  532.     any ret = Sequencer::Run(aliases, sequence);
  533.  
  534.     UI::CloseDialog();
  535.     return ret;
  536. }
  537.  
  538.  
  539. }
  540.