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 / modules / OSRPtbl.ycp < prev    next >
Text File  |  2006-11-29  |  40KB  |  1,397 lines

  1. /**
  2.  *  File:
  3.  *    OSRPtbl.ycp
  4.  *
  5.  *  Module:
  6.  *    YaST OS Repair. Automatic error detection & repair tool for Linux.
  7.  *
  8.  *  Summary:
  9.  *    YaST OS Repair. Automatic error detection & repair tool for Linux.
  10.  *
  11.  *  Author:
  12.  *    Johannes Buchhold <jbuch@suse.de>
  13.  *
  14.  * $Id: OSRPtbl.ycp 24138 2005-07-18 15:30:14Z jsuchome $
  15.  */
  16. {
  17.   module "OSRPtbl";
  18.  
  19.   import "OSRExecute";
  20.   import "OSRFloppy";
  21.   import "OSRPopup";
  22.   import "OSRCommon";
  23.  
  24.   import "Storage";
  25.   import "StorageDevices";
  26.   import "Mode";
  27.   import "Report";
  28.  
  29.   import "Label";
  30.   import "Popup";
  31.  
  32.   include "partitioning/partition_defines.ycp";
  33.  
  34.   textdomain "repair";
  35.  
  36.  
  37.   string s_ignore_label        = _("Ignore");
  38.   string s_recover_label    = _("Recover");
  39.  
  40.  
  41.   define string floppy_help_text ();
  42.   define string gpart_help_text ();
  43.   define string original_help_text ();
  44.  
  45.   define symbol restore_from_floppy ();
  46.   define symbol restore_original();
  47.   define symbol expert_restore_with_gpart ();
  48.   global define symbol RestoreWithGpart ();
  49.  
  50.   /**
  51.    * All repair methods
  52.    */
  53.   map repair_methods = $[
  54.      `floppy : $[
  55.         "header" : _("&Copy Saved Partition Table from Floppy"),
  56.         "help"   : floppy_help_text,
  57.         "method" : restore_from_floppy
  58.      ],
  59.      `gpart : $[
  60.         "header"  : _("Have &gpart Suggest Partition Table"),
  61.         "help"    : gpart_help_text,
  62.         "method"  : RestoreWithGpart,
  63.         "default" : true
  64.      ],
  65.      `gpart_e : $[
  66.         "header"  : _("Have g&part Suggest Partition Table (Expert Mode)"),
  67.         "help"    : gpart_help_text,
  68.         "method"  : expert_restore_with_gpart,
  69.         "default" : true
  70.      ],
  71.      `original : $[
  72.         "header" :  _("&Restore Original Partition Table"),
  73.         "help"   : original_help_text,
  74.         "method" : restore_original,
  75.         "enabled" : false
  76.      ]
  77.   ];
  78.  
  79.   /**
  80.    * The harddisk name. e.g.: /dev/hda
  81.    */
  82.   string target = "";
  83.  
  84.   /**
  85.    * The path of the harddisk (for fdisk calls). e.g.: .dev.hda.
  86.    */
  87.   path     target_scrpath = .;
  88.  
  89.  
  90.   /**
  91.    * At the first call of the OSRPtbl module the constructor saves all
  92.    * mbr's to the YaST"2.tmp Directory. The names of the randomly
  93.    * created mbr files are stored in the map backup_dev_filenames.
  94.    */
  95.   map backup_dev_filenames  = $[];
  96.  
  97.  
  98.   /**
  99.    * backup_mbr_status is true, if all mbr's are successfully stored
  100.    * to the tmp directory.
  101.    */
  102.   boolean backup_mbr_status = false;
  103.  
  104.  
  105.   /**
  106.    * Expert options for gpart
  107.    */
  108.   string gpart_expert_options = "";
  109.   
  110.  
  111.   global define    void Reset()``{
  112.       target             = "";
  113.       target_scrpath         = .;
  114.       gpart_expert_options     = "";
  115.   }
  116.  
  117.   global define void OSRPtbl()``{
  118.  
  119.     if (! StorageDevices::FloppyPresent )
  120.     {
  121.     // filter floppy repair methode
  122.     y2milestone("filter floppy repair methode. No floppy found");
  123.     repair_methods = filter (symbol r, map<any,any> d, (map<symbol,map<any,any> >)repair_methods, ``(
  124.         r != `floppy ));
  125.     }
  126.   }
  127.  
  128.   /**
  129.    * Help text for the floppy repair method.
  130.    */
  131.   define string floppy_help_text() ``{
  132.       //%1 is device label, such as /dev/hda
  133.       return sformat(_("
  134. <p><h3>No Partition Table Found for Hard Disk %1</h3></BR>
  135.  
  136. The repair system will search for a valid partition table of disk %1
  137. on the inserted floppy disk. If it cannot find
  138. one, it will start the program gpart to guess the lost
  139. partition table. You can decide if the information gpart
  140. finds is valid for your system.</p>
  141. "),target ) +
  142.  
  143. _("<p>gpart may be of some help when the primary partition table
  144. has been lost or destroyed, but it can, under no circumstances,
  145. replace proper disk and partition table backups. To save the
  146. master boot record (MBR) including the primary partition
  147. table to the file /tmp/hda.mbr, enter the command
  148.  
  149. <pre>
  150. dd if=/dev/hda of=/tmp/hda.mbr bs=512 count=1
  151. </pre>
  152.  
  153. replacing /dev/hda with the block device name of the disk
  154. in question. This should be done for all disks in the system.
  155. To restore the primary partition table without overwriting
  156. the MBR, enter
  157.  
  158. <pre>
  159. dd if=/tmp/hda.mbr of=/dev/hda bs=1 count=64 skip=446 seek=446
  160. </pre></p>
  161. ") +
  162.  
  163. _("<p>Warning: Make sure that all parameters are entered as shown
  164. and the disk device is correct. Failing to do so may
  165. result in severe corruption of the file system. The saved file
  166. should be stored in a safe place like a floppy disk.</p>
  167. ") +
  168.  
  169. _("<p>From the manual page of gpart:<br>
  170. \"It should be stressed that gpart does a very heuristic
  171. job, never believe its output without any plausability
  172. checks. It can be easily right in its guesswork but it can
  173. also be terribly wrong. You have been warned.\"</p>");
  174.  
  175.   };
  176.  
  177.   /**
  178.    * Help for gpart
  179.    */
  180.   define string gpart_help_text()``{
  181.       //%1 is device label, such as /dev/hda
  182.       return sformat(_("
  183. <P><h3>No Partition Table Found for Hard Disk %1</h3><BR>
  184.  
  185. The repair system will start gpart to guess the primary partition
  186. table of disk %1.</p>
  187. "),  target) +
  188.  
  189. _("<p>gpart may be of some help when the primary partition table
  190. was lost or destroyed, but it can, under no circumstances,
  191. replace proper disk and partition table backups. To save the
  192. master boot record (MBR) including the primary partition
  193. table to the file /tmp/hda.mbr, enter
  194.  
  195. <pre>
  196. dd if=/dev/hda of=/tmp/hda.mbr bs=512 count=1
  197. </pre>
  198.  
  199. replacing /dev/hda with the block device name of the disk
  200. in question. This should be done for all disks in the system.
  201. To restore the primary partition table without overwriting
  202. the MBR, enter
  203.  
  204. <pre>
  205. dd if=/tmp/hda.mbr of=/dev/hda bs=1 count=64 skip=446 seek=446
  206. </pre></p>
  207. ") +
  208.  
  209. _("<p>Warning: Make sure that all parameters are typed as shown
  210. and the disk device is correct. Failing to do so may
  211. result in severe corruption of the file system. The saved file
  212. should be stored in a safe place like a floppy disk.</p>
  213. ") +
  214.  
  215. _("<p>From the manual page of gpart:<br>
  216. \"It should be stressed that gpart does a very heuristic
  217. job, never believe its output without any plausability
  218. checks. It can be easily right in its guesswork but it can
  219. also be terribly wrong. You have been warned.\"</p>");  
  220.  
  221.   }
  222.  
  223.  
  224.   /**
  225.    * Help text for restoring orginal mbr's
  226.    */
  227.   define string original_help_text()``{
  228.       //%1 is device label, such as /dev/hda
  229.       return sformat(_("
  230. Before starting any scan or repair sequence,
  231. a backup of the original partition table 
  232. of the device %1 is created.
  233. "), target );
  234.     
  235.   }
  236.  
  237.   /**
  238.    * Save all mbr's to tmp directory and saves the path names
  239.    * in the map backup_dev_filenames.
  240.    */
  241.   define void SavePtbl()``{
  242.     y2milestone("Saving all mbr's to tmp directory");
  243.  
  244.     // save all current ptbl's to tmp directory
  245.     map<string,map> tg = filter( string k, map disk, Storage::GetTargetMap(), ``(Storage::IsRealDisk(disk)));
  246.     list<string> devlist = maplist( string k, map disk, tg, ``(k));
  247.  
  248.     if (devlist != nil && devlist != [] ) {
  249.       integer ok = 0;
  250.       foreach(string dev, devlist, ``{
  251.  
  252.         // build mbr backup string
  253.         string randompart = sformat("%1/%2_%3.mbr",
  254.         WFM::Read(.local.tmpdir,"" ),
  255.         mergestring(splitstring(dev,"/"),"_") ,
  256.         random(100000));
  257.  
  258.           if (OSRExecute::Command(.local.bash, sformat("/bin/dd if=%1 of=%2 count=1 bs=512",dev,randompart ))){
  259.           ok =ok+1;
  260.           backup_dev_filenames[dev] = randompart;
  261.           }
  262.       });
  263.  
  264.       if (ok == size(devlist))  backup_mbr_status = true;
  265.       }
  266.       else {
  267.       y2error("Emtpy devive list. No harddisk found.");
  268.       }
  269.   }
  270.  
  271.   /**
  272.    * Check reparired mbr.
  273.    */
  274.   define boolean CheckRestoredPtbl(string target) ``{
  275.       y2milestone("checking restored ptl");
  276.  
  277.       list partition_table = Storage::GetTargetMap()[target,"partitions"]:[];
  278.  
  279.       if ((partition_table != nil) && (partition_table != []))
  280.       {
  281.       y2milestone("restoring was successful. Reread Storage");
  282.       // o.k., partition table successfully reverted.
  283.       Storage::ReReadTargetMap();
  284.       // popup message
  285.       Report::Message(_("
  286. Partition table successfully repaired.
  287. "));
  288.       return true;
  289.       }
  290.       else {
  291.       // popup message
  292.       Report::Message(_("
  293. Partition table was not successfully repaired.
  294. "));
  295.       }
  296.       return false;
  297.   }
  298.  
  299.   /**
  300.    * Build the file name for reading partition list from floppy.
  301.    */
  302.   define string build_file_name( string key )``{
  303.       return sformat("%2/%1",mergestring(splitstring(key, "/"),"_") , OSRFloppy::mount_point);
  304.   }
  305.  
  306.   /**
  307.    * Need mounted floppy
  308.    */
  309.   define list<map> read_part_list_from_floppy(string target)``{
  310.     return (list<map>) WFM::Read(.local.ycp, build_file_name(target)+".ycp");
  311.   }
  312.  
  313.   /**
  314.    * Show
  315.    */
  316.   define list<map> FoundPtblDialog (list<map> partitions, string dev, string repair_tool, boolean whole_mbr )``{
  317.  
  318.      y2milestone("Found partitions for recovering %1", partitions );
  319.  
  320.       string label_status = _("Status");
  321.       string label_name   = _("Name");
  322.       //File System ID
  323.       string label_fsid   = _("FSID");
  324.       string label_start  = _("Start");
  325.       string label_end    = _("End");
  326.       string label_size   = _("Size");
  327.       string label_whole  = _("Restore the Entire Master Boot Record");
  328.  
  329.       list<term> items = [];
  330.       foreach (map n,partitions, {
  331.  
  332.     if (n["region",1]:0 != 1)
  333.     {
  334.         map mdev    = Storage::GetTargetMap()[dev]:$[];
  335.         items = add (items, `item (`id(sformat("%1", n["nr"]:1)),
  336.             s_ignore_label,
  337.             dev + n["nr"]:1,
  338.             n["fsid"]:131,
  339.             sformat ("%1", n["region",0]:0),
  340.             sformat ("%1", n["region",1]:0 + n["region",0]:0 - 1),
  341.             ByteToHumanString (n["size_k"]:0 * 1024)
  342.         ));
  343.     }
  344.       });
  345.  
  346.       // help_text  first sentence.
  347.       string help_text = _("<P>The table in the center of the dialog shows the partitions
  348. that could be recovered.</P>
  349. ") +
  350.  
  351.       // %1 is Ignore label
  352.       OSRPopup::build_label_description( OSRPopup::ignore_label,  sformat(_("Change the status of a partition to %1."), s_ignore_label )) +
  353.       // %1 is Recover label
  354.       OSRPopup::build_label_description( OSRPopup::recover_label, sformat(_("Change the status of a partition to %1."), s_recover_label)) +
  355.  
  356.       //%1 is Recover label
  357.       OSRPopup::build_label_description( OSRPopup::repair_label, sformat(_("If you have changed the status of all partitions for recovering
  358. to %1, press Repair to execute the recovery process.
  359. "), s_recover_label)) +
  360.  
  361.       // help_text description for table column, %1 ignore, %2 recover
  362.       OSRPopup::build_label_description( label_status, sformat(_("The status of a listed partition
  363. can be switched between %1 and %2. Only
  364. partitions with the status
  365. %2 are recovered.
  366. "), s_ignore_label, s_recover_label )) +
  367.  
  368.       OSRPopup::build_label_description( label_name, _("Name of the partition that could be
  369. recovered.
  370. ")) +
  371.  
  372.       OSRPopup::build_label_description( label_fsid, _("The file system ID of the partition.
  373. For example, 131 is a normal Linux partition and 6, 11, 12, and 14 are fat and fat32 partitions.
  374. ")) +
  375.  
  376.       OSRPopup::build_label_description( label_start, _("The start cylinder of the partition.")) +
  377.  
  378.       OSRPopup::build_label_description( label_end,   _("The end cylinder of the partition.")) +
  379.  
  380.       OSRPopup::build_label_description( label_size,  _("Size of the partition."));
  381.  
  382.       term whole_term = `Empty();
  383.       if (whole_mbr )
  384.       {
  385.       whole_term = `Left(`CheckBox(`id(`whole_mbr), `opt(`notify), label_whole ,false));
  386.       OSRPopup::build_label_description( label_whole, _("Select this option to
  387. recover the entire master boot record with all partitions.
  388. "));
  389.       }
  390.  
  391.  
  392.       // dialog caption
  393.       OSRPopup::OpenSuggestDialog(_("Recover Lost Partitions"),
  394.                   // dialog text, %1 is device label
  395.                   sformat(_("
  396. The following partitions were found on device %1.
  397. To recover a partition, select the entry
  398. in the table and press Recover.
  399. "), dev),
  400.                   help_text,
  401.                   `VBox(`Table(`id(`table), `header(label_status, label_name, label_fsid, label_start, label_end, label_size ), items ),
  402.                     `Left(`HBox(
  403.                             `PushButton(`id(`ignore),  OSRPopup::ignore_label  ),
  404.                             `PushButton(`id(`recover), OSRPopup::recover_label )
  405.                             )),
  406.                     whole_term
  407.                     ),
  408.                   40);
  409.     UI::SetFocus(`id(`table));
  410.  
  411.     any ret          = `ok;
  412.     list<map>   recover = [];
  413.     repeat
  414.     {
  415.     ret = UI::UserInput();
  416.  
  417.     string current_item = (string)UI::QueryWidget(`id(`table),`CurrentItem);
  418.     term it = (term) UI::QueryWidget (`id(`table), `Item (current_item));
  419.     string current_value = it[1]:"";
  420.  
  421.     map current_part = find (map part, partitions, ``(
  422.         sformat("%1", part["nr"]:"") == current_item ));
  423.  
  424.     if (current_part == nil || current_part == $[] )
  425.         y2error(" partition not found");
  426.  
  427.     if (ret == `ignore )
  428.     {
  429.         if (current_part["type"]:`unknown == `extended )
  430.         {
  431.         foreach (map part,
  432.             filter (map p, partitions,``(p["type"]:`unknown==`logical)),
  433.         ``{
  434.             UI::ChangeWidget(`id(`table),
  435.             `Item(sformat("%1", part["nr"]:""), 0), s_ignore_label);
  436.         });
  437.         }
  438.         UI::ChangeWidget(`id(`table),`Item(current_item, 0),s_ignore_label);
  439.     }
  440.     if (ret == `recover )
  441.     {
  442.         if (current_part["type"]:`unknown == `logical )
  443.         {
  444.         map extended = find (map part, partitions, ``(
  445.             part["type"]:`unknown == `extended ));
  446.         UI::ChangeWidget(`id(`table),
  447.             `Item(sformat("%1", extended["nr"]:""), 0),s_recover_label);
  448.         }
  449.         UI::ChangeWidget(`id(`table),`Item(current_item,0),s_recover_label);
  450.     }
  451.     if (ret == `whole_mbr )
  452.     {
  453.         UI::ChangeWidget(`id(`table), `Enabled,
  454.         !(boolean) UI::QueryWidget(`id(`whole_mbr), `Value ));
  455.     }
  456.  
  457.     if ( ret == `ok )
  458.     {
  459.         recover = filter (map n, partitions, {
  460.         term it    = (term) UI::QueryWidget (
  461.             `id(`table), `Item(sformat("%1", n["nr"]:1)));
  462.         return (it[1]:"" == s_recover_label);
  463.         });
  464.  
  465.         y2milestone( "all selected items %1", recover );
  466.  
  467.         if (whole_mbr )
  468.         {
  469.         if ((boolean)UI::QueryWidget(`id(`whole_mbr ), `Value ))
  470.             recover = [ $["whole_mbr":$[]] ];
  471.         }
  472.     }
  473.     } until( ret == `ok || ret == `cancel );
  474.  
  475.     UI::CloseDialog();
  476.     return recover;
  477.   }
  478.  
  479.  
  480.   /**
  481.    * Call fdisk
  482.    */
  483.   define boolean fdisk_call(string disk_dev, list<map> torecover )``{
  484.  
  485.       UI::OpenDialog(`VBox(`VSpacing(1),
  486.                `Label(_("Recovering partition table...")),
  487.                `VSpacing(1)));
  488.  
  489.       boolean result = true;
  490.  
  491.       if (! Mode::test () )
  492.       {
  493.       /////////////////////////////////////////////////////
  494.       map<string,map> tg = Storage::GetTargetMap();
  495.       tg[disk_dev,"partitions"] = torecover;
  496.       Storage::SetTargetMap(tg);
  497.       Storage::CommitChanges();
  498.       /////////////////////////////////////////////////////
  499.       repair_methods[ `original,  "enabled"] = true;
  500.  
  501.       Storage::ReReadTargetMap();
  502.       }
  503.       else {
  504.       y2milestone("fdisk call not executed. Mode::test () = true !!!");
  505.       }
  506.  
  507.       UI::CloseDialog();
  508.  
  509.       return result;
  510.   };
  511.  
  512.  
  513.  
  514.   
  515.   /**
  516.    * Restore lost mbr with a backup from floppy.
  517.    */
  518.   define symbol restore_from_floppy( )``{
  519.  
  520.       //%1 is device label, such as /dev/hda
  521.       string error_message_start = sformat(_("No primary partition table was found on hard disk %1."), target );
  522.       //%1 is device label, such as /dev/hda
  523.       string error_message       = sformat(_("
  524.  
  525. If you have a floppy with some
  526. up-to-date system information from a former rescue
  527. session, insert it in your drive and press Repair.
  528.  
  529. Press Skip and repair manually if you have a
  530. backup of the partition table of disk %1.
  531.  
  532. Press Help to learn how to
  533. make a backup of a partition table manually
  534. and how to restore it.
  535. "), target);
  536.  
  537.    
  538.       // this can't be repaired without a floppy drive, so the user must not be asked again
  539.       // to repair via floppy
  540.       if (! OSRCommon::RequireBoolean("has_floppy"))
  541.       {
  542.       // display that no floppy drive was detected
  543.       Report::Message(_("
  544. Cannot detect a floppy drive
  545. in your system. A backup copy of the
  546. primary partition table could not be
  547. read.
  548. "));
  549.       return `error;
  550.       }    
  551.       else {
  552.       if (! OSRPopup::Repair(_("Error Detected"), error_message_start + error_message, floppy_help_text())) return `cancel;
  553.       
  554.       if (OSRFloppy::Open(true, 2))
  555.       {
  556.           OSRFloppy::NextStep(_("Searching for partition table..."));
  557.           list<map> found_partitions = read_part_list_from_floppy(target);
  558.           list   to_recover          = [];
  559.           
  560.           if (found_partitions != nil && found_partitions != [] ) {
  561.           to_recover = FoundPtblDialog(found_partitions, target, "Floppy", true );
  562.           
  563.           boolean revert = false;
  564.           
  565.           if (size(to_recover ) == 0 ) {
  566.               Report::Warning(_("
  567. Could not find a valid partition table.
  568. Insert another floppy disk and
  569. try again or have gpart suggest a
  570. partition table.
  571. "));
  572.               OSRFloppy::Close();
  573.               return `cancel;
  574.           }
  575.           else if (haskey( to_recover[0]:$[], "whole_mbr")) {
  576.  
  577.               y2milestone("recover the whole mbr");
  578.  
  579.               if (WFM::Read(.local.size, build_file_name(target)+".mbr" ) == 512 )
  580.               {        
  581.               OSRFloppy::NextStep(_("Restoring old partition table..."));              
  582.               
  583.               // copy the backup of the primary partition table to the target device
  584.               revert = OSRExecute::Command(.local.bash,
  585.                                sformat("/bin/dd if=%1.mbr of=%2 bs=1 count=512", build_file_name(target ),target ));
  586.               
  587.               // call block device ioctls: reread the partition table (important after having
  588.               // changed the partition table!)
  589.               OSRExecute::Command(.target.bash, sformat("/sbin/blockdev --rereadpt %1", target));
  590.               }
  591.               else {
  592.               Report::Error(_("
  593. Could not find a valid master boot
  594. record on the floppy disk. Insert
  595. another floppy disk and try again or
  596. have gpart suggest the partition table.
  597. "));
  598.               OSRFloppy::Close();
  599.               return `error;
  600.               }
  601.           }
  602.  
  603.           OSRFloppy::Close();
  604.  
  605.           if (! haskey( to_recover[0]:$[], "whole_mbr") ) {
  606.               list<map> new_to_recover = [];
  607.               foreach(map<string,any> p, (list<map<string,any> >)to_recover, ``{
  608.               p["create"] = true;
  609.               new_to_recover = add(new_to_recover, p);
  610.               });
  611.               revert = fdisk_call( target, new_to_recover );
  612.           }
  613.           
  614.           if (revert )
  615.           {
  616.               if (CheckRestoredPtbl(target) ) {
  617.               return `ok; 
  618.               }
  619.           }
  620.  
  621.           // error message
  622.           Report::Error(_("
  623. Restoring the partition table
  624. was not successful.
  625. Insert another floppy disk
  626. and try again or have gpart
  627. suggest the partition table.
  628. "));
  629.           return `error;
  630.           }
  631.       }
  632.       else
  633.       {
  634.           // error message
  635.           Report::Error (_("
  636. Either no floppy disk is inserted in
  637. the drive or the inserted floppy is not
  638. correctly formatted. Insert
  639. another floppy disk and try again or
  640. have gpart suggest the partition table.
  641. "));
  642.       }
  643.  
  644.       OSRFloppy::Close();
  645.       }
  646.       return `cancel;
  647.   }
  648.  
  649.   /**
  650.    * Cat the fsid from a line.
  651.    */
  652.   define integer gpart_cat_fsid(string line)``{
  653.     string sub = substring( line, find(line, ":"), find(line,"(")-find(line,":") );
  654.     string allow =  "0123456789";
  655.     sub = filterchars( sub, allow);
  656.     return tointeger(sub);  
  657.   }
  658.  
  659.   /**
  660.    * Cat the geometry from a line.
  661.    */
  662.   define map gpart_cat_geometry( string line)``{
  663.     string allow = "0123456789/";
  664.  
  665.     string sub1  = substring( line, find(line, "d"), size(line));
  666.     list<string> split   = splitstring(sub1, "-" );
  667.     string start = filterchars(split[0]:"",  allow);
  668.     string end   = filterchars(split[1]:"", allow);
  669.     list<string> s = splitstring( start, "/");
  670.     list<string> e = splitstring( end, "/");
  671.  
  672.     map ret = $[ "start": $[ "c" : tointeger( s[0]:"0"),
  673.               "h" : tointeger( s[1]:"0"),
  674.               "s" : tointeger( s[2]:"0") ],
  675.          "end"  : $[ "c" : tointeger( e[0]:"0"),
  676.                  "h" : tointeger(    e[1]:"0"),
  677.                 "s" : tointeger(    e[2]:"0") ]];
  678.  
  679.     y2milestone("retmap gemetry %1", ret);
  680.     return ret;
  681. };
  682.  
  683.  
  684.   /**
  685.    * Dialog with expert gpart options.
  686.    */
  687.   define symbol expert_restore_with_gpart() {
  688.  
  689.  
  690.     // checkbox label
  691.     string full_label        = _("Full Scan");
  692.     // button label
  693.     string start_label        = _("Start Detection");
  694.  
  695.  
  696.     map maindev            = Storage::GetTargetMap()[target]:$[];
  697.     integer cyl_count        = maindev["cyl_count"]:0;
  698.     gpart_expert_options    = "";
  699.  
  700.     map symbol_2_option = $[
  701.     `extended        : "-E",
  702.     `skip_errors        : "-e",
  703.     `full_scan        : "-f"
  704.     ];
  705.  
  706.     // help text label
  707.     string help_text = _("<P>
  708. <BIG><B>Help for Expert Mode</B></BIG>
  709. </P>
  710. ") +
  711.     // help text (restorng partition)
  712.     OSRPopup::build_label_description (full_label, _("
  713. <P>When a possible partition is found,
  714. gpart normally skips all sectors this entry seems
  715. to occupy and continues the scan from the end of
  716. the last possible partition. The disk scan can take
  717. quite a while when using this option. Be patient.</P>
  718. "));
  719.  
  720.       UI::OpenDialog( `HBox(
  721.                 `HWeight(2, `RichText(`id(`help),  help_text )),
  722.                 `HWeight(4,
  723.                      `HBox(
  724.                         `HSpacing(2),
  725.                         `VBox(
  726.                             // headline label, gpart is command
  727.                           `Heading(_("Scan Options for gpart")),
  728.                           `VSpacing(3),
  729.                           // checkbox label
  730.                           `Left(`CheckBox(`id(`extended),    _("Do Not Try to &Identify Extended Partition Tables"))),
  731.                           // checkbox label
  732.                           `Left(`CheckBox(`id(`skip_errors), _("Do Not &Skip Disk Read Errors"))),
  733.                           `Left(`CheckBox(`id(`full_scan),  full_label  )),
  734.                           `VSpacing(4),
  735.                           `HBox(
  736.                             `PushButton(`id(`ok), start_label ),
  737.                             `PushButton(`id(`cancel), Label::CancelButton())
  738.                             )
  739.                           ),
  740.                         `HSpacing(2)
  741.                         )
  742.                      )
  743.               ));
  744.  
  745.     UI::SetFocus(`id(`extended));
  746.  
  747.     symbol ret     = `ok;
  748.     repeat
  749.     {
  750.     ret = (symbol) UI::UserInput();
  751.  
  752.     if (ret == `ok ) {
  753.  
  754.         //build expert options
  755.         foreach (symbol key, string option, (map<symbol,string>)symbol_2_option, ``{
  756.         gpart_expert_options = gpart_expert_options +
  757.             ((boolean)UI::QueryWidget(`id(key), `Value)
  758.             ? " " + option + " " : "");
  759.         });
  760.  
  761.         y2milestone("gpart options %1", gpart_expert_options );
  762.     }
  763.     } until( ret == `ok || ret == `cancel );
  764.     UI::CloseDialog();
  765.  
  766.     if (ret == `ok ) ret = RestoreWithGpart ();
  767.  
  768.     gpart_expert_options = "";
  769.     return  ret;
  770.   }
  771.  
  772.  
  773.   define map compare_found_with_existing (  list<map> found_partitions,
  774.                         list<map> existing_partitions,
  775.                         string target) ``{
  776.       map ret            = $[];
  777.  
  778.       foreach(map paritition, found_partitions, ``{
  779.  
  780.       map matching = find(map e_part, existing_partitions, ``(e_part["region"]:[] == paritition["region"]:[0]));
  781.  
  782.       if (matching != nil && matching != $[] )
  783.       {
  784.           ret["match"] = add(ret["match"]:[], paritition );
  785.           y2milestone("found paritition %1 matchs with exiting paritition %2", paritition["device"]:"", matching["device"]:"");
  786.       }
  787.       else
  788.       {
  789.           integer found_start = paritition["region",0]:0;
  790.           integer found_end   = paritition["region",0]:0 + paritition["region", 1]:0  -1;
  791.           foreach(map e_part,  existing_partitions, ``{
  792.           integer existing_start = e_part["region", 0]:0;
  793.           integer existing_end   = e_part["region", 0]:0 + e_part["region", 1]:0 -1;
  794.  
  795.           if ((existing_start >= found_start && existing_start <= found_end) ||
  796.                (existing_end   >= found_start && existing_end   <= found_end) ||
  797.                (existing_start >= found_start && existing_end   <= found_end) ||
  798.                (existing_start <= found_start && existing_end   >= found_end)
  799.                )
  800.           {
  801.               paritition["overlap"] = add(paritition["overlap"]:[], e_part );
  802.               y2milestone("found paritition %1 overlaps with exiting paritition %2", paritition["device"]:"", e_part["device"]:"");
  803.           }  
  804.           });
  805.           if (paritition["overlap"]:[] != [] )
  806.           {
  807.           ret["overlap"] = add(ret["overlap"]:[], paritition);
  808.  
  809.           }
  810.           else
  811.           {
  812.           ret["free"]    = add(ret["free"]:[], paritition );
  813.           y2milestone("found free paritition space for %1", paritition["device"]:"");
  814.           }
  815.       }
  816.       });
  817.       if (size(ret) > 0 )
  818.       {
  819.       ret["existing"] = existing_partitions;
  820.       }
  821.       return ret;
  822.   }
  823.  
  824.   /**
  825.    * return partition information (to be shown to user)
  826.    */
  827.   define string partition_info (map part, string dev) {
  828.  
  829.       map maindev    = Storage::GetTargetMap()[target]:$[];
  830.       return
  831.     // partition info 1/3, %1,%2 are numbers
  832.     sformat (_("Cylinders %1-%2, "),
  833.         part["region", 0]:0, part["region",0]:0 + part["region",1]:0 -1) +
  834.     // partition info 2/3, %1 is partition ID (number)
  835.     sformat(_("ID %1, "),  part["fsid"]:131) +
  836.     // partition info 3/3, %1 is partition size (number)
  837.     sformat (_("Size %1"), ByteToHumanString (
  838.         part["region",1]:0 * maindev["cyl_size"]:0));
  839.     }
  840.  
  841.   /**
  842.    * Compare an existing partition table with the gpart output
  843.    */
  844.   define list<map> ComparePtblDialog (map compared, string target,
  845.                       string repair_tool) ``{
  846.  
  847.     term part_items        = `VBox();
  848.     list<list> part_list    = [];
  849.     list<map> found_free_parts    = compared["free"]:[];
  850.     list<map> overlap_parts    = compared["overlap"]:[];
  851.  
  852.     //number to text
  853.     map number2text = $[
  854.     // label: partition number
  855.     1 : _("First Partition Found"),
  856.     2 : _("Second Partition Found"),
  857.     3 : _("Third Partition Found"),
  858.     4 : _("Fourth Partition Found")
  859.     ];
  860.  
  861.     foreach (map free_part, found_free_parts, ``{
  862.     integer nr    = free_part["nr"]:0;
  863.     part_list    = add (part_list, [
  864.         nr,
  865.         `Left (
  866.         `CheckBox(`id(free_part["device"]:""),
  867.               //%1 is number.  %2 is text like "First Partition Found", %3 is partition info
  868.             sformat (_("&%1: %2: %3"), nr, number2text[nr]:"",
  869.             partition_info (free_part, target)),
  870.             true
  871.         )
  872.         )
  873.     ]);
  874.     });
  875.  
  876.     foreach (map overlap_part, overlap_parts, ``{
  877.     integer nr = overlap_part["nr"]:0;
  878.     list<string> del_text_parts = maplist (map e_part,
  879.         overlap_part["overlap"]:[], ``{
  880.         return sformat (
  881.         // label: %1 is device name, %2,%3 numbers
  882.         _("Partition %1 must be deleted to recover cylinders %2-%3."),
  883.         e_part["device"]:"",
  884.         overlap_part["region",0]:0,
  885.         overlap_part["region",0]:0 + overlap_part["region",1]:0 - 1);
  886.     });
  887.  
  888.     part_list = add (part_list, [
  889.         nr,
  890.         `Left (`VBox (
  891.         `Left (
  892.             `CheckBox (`id(overlap_part["device"]:""),
  893.                    //%1 in number, %2 is text like "Second Partition Found", %3 is partition info
  894.             sformat(_("&%1: %2: %3"), nr, number2text[nr]:"",
  895.                 partition_info (overlap_part, target)),
  896.             false)
  897.         ),
  898.         `VSpacing(0.5),
  899.         `Left (
  900.             // heading
  901.             `Heading (_("Conflicts with Existing Partitions"))
  902.         ),
  903.         `Left (
  904.             `Label (mergestring (del_text_parts, "\n"))
  905.         )
  906.         ))
  907.     ]);
  908.     });
  909.  
  910.     part_list = sort (list l, list q, part_list, ``( l[0]:0 < q[0]:0 ));
  911.     foreach (list part, part_list , ``{
  912.     part_items = add (part_items, part[1]:`Empty());
  913.     part_items = add (part_items, `VSpacing(2));
  914.     });
  915.  
  916.     // gpart found only existing partitions.
  917.     if (size( found_free_parts ) == 0 && size( overlap_parts ) == 0 )
  918.     {
  919.     // popup message
  920.     Report::Message(_("No lost partition found."));
  921.     return [];
  922.     }
  923.  
  924.     // help text of partition recovery 1/2
  925.     string help_text = _("
  926. <p>
  927. Read the following points carefully
  928. and select only the partition that should
  929. really be recovered.
  930. </P>
  931. ") +
  932.  
  933.     // help text of partition recovery 2/2
  934.     _("<P><B>Use caution.</B> Sometimes an existing partition must
  935. be deleted to recover another partition.</P>
  936. ") +
  937.  
  938.     OSRPopup::build_label_description (OSRPopup::repair_label,
  939.     // help text for button
  940.     _("Start the recovery process."));
  941.  
  942.     string message = "";
  943.     // popup headline
  944.     OSRPopup::OpenSuggestDialog (_("Recover Previously Existing Partitions"),
  945.     message,
  946.     help_text,
  947.     `HBox (`HSpacing(1), part_items, `HSpacing(1)),
  948.     (size(found_free_parts) + size(overlap_parts)) * 15
  949.     );
  950.  
  951.     any ret          = `ok;
  952.     list<map>   recover = [];
  953.     repeat
  954.     {
  955.     ret = UI::UserInput();
  956.  
  957.     if ( ret == `ok )
  958.     {
  959.         foreach (map free_part, found_free_parts, ``{
  960.         if ((boolean)
  961.             UI::QueryWidget(`id(free_part["device"]:""), `Value))
  962.         {
  963.             recover = add (recover, free_part );
  964.         }
  965.         });
  966.         foreach (map overlap_part, overlap_parts, ``{
  967.         if ((boolean)
  968.             UI::QueryWidget(`id(overlap_part["device"]:""), `Value))
  969.         {
  970.             // warning popup, %1 is device name, %2 list of partitions
  971.             if (Popup::ContinueCancel (sformat(_("
  972. Recovering the selected partition %1 is only
  973. possible by deleting the following partitions:
  974. %2
  975. Press Continue to delete the partitions
  976. and recover %1."),
  977.             overlap_part["device"]:"",
  978.             mergestring (
  979.                 maplist (map o_part, overlap_part["overlap"]:[],
  980.                 ``(o_part["device"]:"")),
  981.                 " "
  982.             )
  983.             )))
  984.             {
  985.             foreach (map delpart, overlap_part["overlap"]:[], ``{
  986.                 delpart["delete"] = true;
  987.                 delpart = filter (string key, any d,
  988.                 (map<string,any>) delpart,``(key != "overlap"));
  989.                 recover = (list<map>) union (recover, [delpart]);
  990.             });
  991.             overlap_part = filter (string key, any d,
  992.                 (map<string,any>)overlap_part,``(key != "overlap"));
  993.             recover = add (recover, overlap_part );
  994.             }
  995.             else //popup canceled
  996.             {
  997.             UI::ChangeWidget (`id(overlap_part["device"]:""),
  998.                 `Value, false);
  999.             recover = [];
  1000.             ret = `again;
  1001.             }
  1002.         }
  1003.         });
  1004.         list<map> existing_partitions    = compared["existing"]:[];
  1005.         list used_nrs            = maplist (
  1006.         map ep,existing_partitions,``(ep["nr"]:0));
  1007.         list delete_nrs            = maplist (
  1008.         map dpp, filter (map dp, recover, ``(dp["delete"]:false)),
  1009.             ``(dpp["nr"]:0)
  1010.         );
  1011.  
  1012.         used_nrs    = filter (integer nr, (list<integer>) used_nrs, ``(
  1013.                 !contains(delete_nrs, nr)));
  1014.  
  1015.         list<integer> primary_pos  = [1,2,3,4];
  1016.         list<integer> free_primary = filter (integer nr, primary_pos, ``(
  1017.         !contains (used_nrs, nr)));
  1018.  
  1019.         // check partition nr's
  1020.         foreach(map part, recover , {
  1021.         if (part["delete"]:false != true && ret != `again )
  1022.         {
  1023.             // partition nr is used by a other partition.
  1024.             if (contains (used_nrs, part["nr"]:0))
  1025.             {
  1026.             if (size (free_primary) > 0)
  1027.             {
  1028.                 y2milestone("move partition nr %1 to a free primary position", part["nr"]:0);
  1029.                 part["nr"] = free_primary[0]:0;
  1030.                 free_primary = remove (free_primary, 0);
  1031.             }
  1032.             else
  1033.             {
  1034.                 y2error("no free primary slot found. locical search not supported");
  1035.                 // error popup, %1 is paritition number, %2 info
  1036.                 Report::Error(sformat(_("
  1037. Recovering the partition %1 (%2) is not
  1038. possible. The partition number conflicts
  1039. with an existing partition. Solving the
  1040. conflict is not possible.
  1041. "), part["nr"]:0, partition_info (part, target)));
  1042.  
  1043.                 UI::ChangeWidget(`id(part["device"]:""), `Value, false);
  1044.                 ret = `again;
  1045.             }
  1046.             }
  1047.         }
  1048.         });
  1049.     }
  1050.     } until ( ret == `ok || ret == `cancel );
  1051.  
  1052.     UI::CloseDialog();
  1053.     return recover;
  1054.   }
  1055.  
  1056.  
  1057.   /**
  1058.    * Restoring a partition tables with gpart.
  1059.    */
  1060.   global define symbol RestoreWithGpart () ``{
  1061.  
  1062.     /////////////////////////////////////////////////////////////////////////
  1063.     //
  1064.     //  Repair partition table with gpart
  1065.     //
  1066.     /////////////////////////////////////////////////////////////////////////
  1067.     list<map> found_partitions    = [];
  1068.     string gpart_file           = (string) SCR::Read(.target.tmpdir) + "/gpart";
  1069.     WFM::Execute (.local.bash, sformat("if /usr/bin/test -e %1; then /bin/rm %1; else /bin/echo %1 not exist; fi;", gpart_file));
  1070.  
  1071.     string gpart_command = "/usr/bin/gpart "+ gpart_expert_options +" "+ target;
  1072.  
  1073.     term contents  = `HBox(`HSpacing(0.5),
  1074.     `VBox (
  1075.         `Left (`HBox (
  1076.         // headline of partition scan popup
  1077.         `HWeight (30, `Heading(_("Search for Lost Partitions"))),
  1078.         `HWeight (30, `HSpacing(4))
  1079.         )),
  1080.         `VSpacing(1),
  1081.         // addtional info for partition scan
  1082.         `Left (`Label (_("This can take a lot of time depending on the
  1083. system performance and the hard disk size.")
  1084.         )),
  1085.         // label text (device name follows)
  1086.         `Left (`Label(_("Hard Disk: ") + target)),
  1087.         `VSpacing(0.5),
  1088.         `VSpacing(1),
  1089.         // button label
  1090.         `HBox (
  1091.         `PushButton(`id(`start) , _("&Start")),
  1092.         `PushButton (`id(`cancel), Label::CancelButton())
  1093.         )
  1094.     ),
  1095.     `HSpacing(0.5)
  1096.     );
  1097.  
  1098.     UI::OpenDialog (contents);
  1099.  
  1100.     if (UI::UserInput () != `start )
  1101.     {
  1102.     UI::CloseDialog();
  1103.         return `cancel;
  1104.     }
  1105.  
  1106.     UI::ChangeWidget(`id(`start), `Enabled, false);
  1107.     UI::ChangeWidget(`id(`cancel), `Enabled, false);
  1108.     // FIXME action cannot be cancelled! -> use background or callback
  1109.     // progress doesn't have sence!
  1110.  
  1111.     UI::BusyCursor();
  1112.     if (OSRExecute::CommandProgress (.target.bash_output, gpart_command, gpart_file))
  1113.     {
  1114.     string file = (string) WFM::Read(.local.string, gpart_file );
  1115.     // display the results in a window
  1116.     string partitions_out = substring (file,
  1117.         find (file, "\nPrimary partition(1)"),
  1118.         (size(file) - find (file, "\nPrimary partition(1)"))
  1119.     );
  1120.     string partition1 = substring(partitions_out,
  1121.         find(partitions_out, "\nPrimary partition(1)"),
  1122.         (find(partitions_out, "\nPrimary partition(2)") -
  1123.          find(partitions_out, "\nPrimary partition(1)"))
  1124.     );
  1125.  
  1126.     string partition2 = substring (partitions_out,
  1127.         find (partitions_out, "\nPrimary partition(2)"),
  1128.         (find(partitions_out, "\nPrimary partition(3)") -
  1129.          find(partitions_out, "\nPrimary partition(2)"))
  1130.     );
  1131.  
  1132.     string partition3 = substring (partitions_out,
  1133.         find(partitions_out, "\nPrimary partition(3)"),
  1134.         (find(partitions_out, "\nPrimary partition(4)") -
  1135.          find(partitions_out, "\nPrimary partition(3)"))
  1136.     );
  1137.  
  1138.     string partition4 = substring(partitions_out,
  1139.         find(partitions_out, "\nPrimary partition(4)"),
  1140.         (size(partitions_out)-find(partitions_out,"\nPrimary partition(4)"))
  1141.     );
  1142.  
  1143.     list gpart_partitions = [partition1, partition2, partition3,partition4];
  1144.  
  1145.     integer index  = 0;
  1146.     while ((index >= 0) && (index < size(gpart_partitions)))
  1147.     {
  1148.         map partition    = $[];
  1149.         string p        = gpart_partitions[index]:"";
  1150.         list<string> p_list = splitstring(p, "\n");
  1151.  
  1152.         foreach (string line, p_list, ``{
  1153.             if (issubstring(line, "type: "))
  1154.             {
  1155.                 partition["fsid"] = gpart_cat_fsid(line );
  1156.             }
  1157.             else if (issubstring( line, "chs:"))
  1158.             {
  1159.             map geometry = gpart_cat_geometry( line );
  1160.                 integer s    = geometry["start","c"]:0;
  1161.                 integer l    = geometry["end","c"]:0 - s + 1;
  1162.                 partition["region"] = [s,l];
  1163.         }
  1164.             partition["nr"]        = index +1;
  1165.             partition["type"]    = `primary;
  1166.             partition["create"]    = true;
  1167.             partition["device"] = Storage::GetDeviceName(target, index + 1);
  1168.         });
  1169.  
  1170.         index = index + 1;
  1171.  
  1172.         if (partition["region",1]:0 != 0 && partition["fsid"]:0 != 0)
  1173.         {
  1174.         found_partitions = add(found_partitions, partition );
  1175.         }
  1176.     }
  1177.     }
  1178.  
  1179.     UI::CloseDialog();
  1180.     UI::NormalCursor();
  1181.  
  1182.     if (size (found_partitions) == 0)
  1183.     {
  1184.     // error popup, %1 is device
  1185.     Report::Error(sformat(_("
  1186. No valid partitions found for the 
  1187. partition table of %1. If there were
  1188. some partitions on the disk, you can try
  1189. to restore them manually. To do
  1190. that, enter the cylinder values
  1191. in fdisk or the partitioning tool.
  1192. "), target));
  1193.     return `error;
  1194.     }
  1195.     else
  1196.     {
  1197.     map compared        =  compare_found_with_existing (
  1198.         found_partitions,
  1199.         (list<map>) Storage::GetTargetMap()[target, "partitions"]:[],
  1200.         target);
  1201.     list<map> torecover    = ComparePtblDialog (compared, target, "Gpart");
  1202.  
  1203.     if (size (torecover) < 1 || Mode::test ())
  1204.         return `cancel;
  1205.  
  1206.     if (fdisk_call (target, torecover))
  1207.     {
  1208.         if (CheckRestoredPtbl (target))
  1209.         {
  1210.         return `ok;
  1211.         }
  1212.     }
  1213.     else
  1214.     {
  1215.         // error popup message
  1216.         Report::Error(_("Partition table was not successfully repaired."));
  1217.         return `error;
  1218.     }
  1219.     }
  1220.     return `error;
  1221.   }
  1222.  
  1223.   /**
  1224.    * Restore saved mbr.
  1225.    */
  1226.   define boolean write_original(list<string> to_reset, boolean whole_mbr )``{
  1227.       if (Mode::test () ) return true;
  1228.  
  1229.       y2milestone("write orginal master boot record");
  1230.  
  1231.       integer ok = 0 ;      
  1232.       foreach(string dev, to_reset , ``{
  1233.  
  1234.       if ( backup_dev_filenames[dev]:"" != "" ) {
  1235.           string command = sformat("/bin/dd if=%1 of=%2 ", backup_dev_filenames[dev]:"", dev );
  1236.  
  1237.           if (whole_mbr ) command = command + "count=1 bs=512";
  1238.           else command = command + "bs=1 count=64 skip=446 seek=446";
  1239.  
  1240.           if (OSRExecute::Command(.local.bash,command)) {
  1241.           ok = ok + 1;
  1242.           Report::Message(sformat(_("Writing the backup of %1 was successful."), dev));
  1243.           }
  1244.           else {
  1245.           Report::Message(sformat(_("Writing the backup of %1 was not successful."), dev));
  1246.           }
  1247.           repair_methods[ `original,  "enabled"] = true;
  1248.       }
  1249.       else {
  1250.           y2error("No entry in backup map found");
  1251.       }
  1252.       
  1253.       });
  1254.       return ( ok ==  size(to_reset));
  1255.   }
  1256.   
  1257.  
  1258.   /**
  1259.    * Restore saved mbr.
  1260.    */
  1261.   define symbol restore_original()``{
  1262.       
  1263.       //%1 is device label, such as /dev/hda
  1264.       string header   = sformat(_("Restore Original Partition Table of %1"), target);
  1265.       string ok_label = mergestring(splitstring(Label::OKButton(), "&"),"");
  1266.  
  1267.       //%1 is OK button label, %2 is device like /dev/hda
  1268.       string message  = original_help_text() +  sformat(_("
  1269. If you press %1, the partition table 
  1270. of %2 will be replaced with 
  1271. the backup.
  1272. "), ok_label, target );
  1273.       
  1274.       if (Popup::YesNoHeadline(header, message ))
  1275.       {   
  1276.       if (! Mode::test () )
  1277.       {
  1278.           if (write_original([target], true )) return `ok;
  1279.           else return `error;
  1280.       }
  1281.       else {
  1282.           return `ok;
  1283.       }
  1284.       }
  1285.       return `cancel;
  1286.   }
  1287.  
  1288.   /**
  1289.    * Write partition info of given disk to floppy (needs mounted floppy)
  1290.    */
  1291.   global define boolean WritePartitionsInfo2Floppy (string key, list parts) {
  1292.  
  1293.       if (Mode::test () ) return true;
  1294.  
  1295.       boolean write_error    = false;
  1296.       string file        = build_file_name (key);
  1297.  
  1298.       // set the dd-command
  1299.       string command = sformat("dd if=%1 of=%2.mbr bs=512 count=1", key, file);
  1300.  
  1301.       // write mbr to floppy
  1302.       OSRExecute::Command (.local.bash, command);
  1303.  
  1304.       // write partition list to floppy
  1305.       WFM::Write (.local.ycp, file+".ycp", parts);
  1306.  
  1307.       if (!(WFM::Read(.local.size, file + ".mbr") == 512  &&
  1308.         WFM::Read(.local.size, file + ".ycp") != 0 ))
  1309.       {
  1310.       write_error = true;
  1311.       }
  1312.  
  1313.       return (!write_error);
  1314.   }
  1315.  
  1316.   
  1317.   /**
  1318.    * Main Dialog for repairing deleted/not valid partition tables.
  1319.    *
  1320.    * @parm t_target the target e.g.: /dev/hda
  1321.    * 
  1322.    */
  1323.   global define symbol MainPtblRepairDialog(string t_target) ``{
  1324.  
  1325.       //Save all mbr's to tmp directory.
  1326.       SavePtbl();
  1327.       
  1328.       target          = t_target;
  1329.       
  1330.       term r_options = `VBox(`Left(`Label(_("Select a repair method or skip repairing."))),`VSpacing(0.5));
  1331.       
  1332.       foreach(symbol ro, map<string,any> rd, (map<symbol,map<string,any> >)repair_methods, ``{
  1333.       term r_button = `RadioButton(`id( ro ));
  1334.       if (! rd["enabled"]:true ) r_button = add( r_button , `opt(`disabled));
  1335.       r_button      = add( r_button ,   rd["header"]:"");
  1336.       r_button      = add( r_button,    rd["default"]:false );
  1337.       r_options = add( r_options , `Left( r_button ));
  1338.       });
  1339.       //%1 is device label, such as /dev/hda
  1340.       string error_text = sformat(_("
  1341. No partition table was found for hard disk %1.
  1342. If at least one partition should exist for %1,
  1343. select one of the following repair methods.  If
  1344. no partition ever existed on this hard disk,
  1345. skip the repair.
  1346.  
  1347. "), target);
  1348.  
  1349.       //%1 is device label, such as /dev/hda
  1350.       if (! OSRPopup::OpenMainRepairDialog( sformat(_("Repair Partition Table of %1"),target ), error_text, r_options ))
  1351.       {
  1352.       y2error("could not open main dialog");
  1353.       return `error;
  1354.       }
  1355.       symbol ret     = `ok;
  1356.       repeat {
  1357.     ret             = (symbol) UI::UserInput();
  1358.     symbol selected = (symbol) UI::QueryWidget(`id(`rb), `CurrentButton);
  1359.  
  1360.     if (ret == `help )
  1361.     {
  1362.         string () help_f =
  1363.         repair_methods[selected,"help"]:OSRCommon::EmptyString;
  1364.         Popup::LongText (OSRPopup::help_headline,
  1365.         `RichText ( help_f () ), 50, 20);
  1366.     }
  1367.     else if (ret == `ok )
  1368.     {
  1369.         UI::CloseDialog();
  1370.         symbol () f =
  1371.         repair_methods [selected,"method"]:OSRCommon::SymbolError;
  1372.         ret = f ();
  1373.  
  1374.         if (ret != `ok )
  1375.         {
  1376.         if (! OSRPopup::OpenMainRepairDialog (
  1377.             // dialog headline, %1 is device label live /dev/hda
  1378.             sformat(_("Repair Partition Table of %1"), target ),
  1379.             error_text, r_options ))
  1380.         {
  1381.             y2error("could not open main dialog");
  1382.             return `error;
  1383.         }
  1384.         ret = `again;
  1385.         }
  1386.     }
  1387.       } until( ret == `cancel || ret == `abort || ret == `ok );
  1388.       if (ret != `ok )  UI::CloseDialog();
  1389.       return ret;
  1390.   }
  1391.  
  1392.   global define void SetTarget(string ttarget)``{
  1393.       target = ttarget;
  1394.   }
  1395.  
  1396. }//EOF
  1397.