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 >
Wrap
Text File
|
2006-11-29
|
40KB
|
1,397 lines
/**
* File:
* OSRPtbl.ycp
*
* Module:
* YaST OS Repair. Automatic error detection & repair tool for Linux.
*
* Summary:
* YaST OS Repair. Automatic error detection & repair tool for Linux.
*
* Author:
* Johannes Buchhold <jbuch@suse.de>
*
* $Id: OSRPtbl.ycp 24138 2005-07-18 15:30:14Z jsuchome $
*/
{
module "OSRPtbl";
import "OSRExecute";
import "OSRFloppy";
import "OSRPopup";
import "OSRCommon";
import "Storage";
import "StorageDevices";
import "Mode";
import "Report";
import "Label";
import "Popup";
include "partitioning/partition_defines.ycp";
textdomain "repair";
string s_ignore_label = _("Ignore");
string s_recover_label = _("Recover");
define string floppy_help_text ();
define string gpart_help_text ();
define string original_help_text ();
define symbol restore_from_floppy ();
define symbol restore_original();
define symbol expert_restore_with_gpart ();
global define symbol RestoreWithGpart ();
/**
* All repair methods
*/
map repair_methods = $[
`floppy : $[
"header" : _("&Copy Saved Partition Table from Floppy"),
"help" : floppy_help_text,
"method" : restore_from_floppy
],
`gpart : $[
"header" : _("Have &gpart Suggest Partition Table"),
"help" : gpart_help_text,
"method" : RestoreWithGpart,
"default" : true
],
`gpart_e : $[
"header" : _("Have g&part Suggest Partition Table (Expert Mode)"),
"help" : gpart_help_text,
"method" : expert_restore_with_gpart,
"default" : true
],
`original : $[
"header" : _("&Restore Original Partition Table"),
"help" : original_help_text,
"method" : restore_original,
"enabled" : false
]
];
/**
* The harddisk name. e.g.: /dev/hda
*/
string target = "";
/**
* The path of the harddisk (for fdisk calls). e.g.: .dev.hda.
*/
path target_scrpath = .;
/**
* At the first call of the OSRPtbl module the constructor saves all
* mbr's to the YaST"2.tmp Directory. The names of the randomly
* created mbr files are stored in the map backup_dev_filenames.
*/
map backup_dev_filenames = $[];
/**
* backup_mbr_status is true, if all mbr's are successfully stored
* to the tmp directory.
*/
boolean backup_mbr_status = false;
/**
* Expert options for gpart
*/
string gpart_expert_options = "";
global define void Reset()``{
target = "";
target_scrpath = .;
gpart_expert_options = "";
}
global define void OSRPtbl()``{
if (! StorageDevices::FloppyPresent )
{
// filter floppy repair methode
y2milestone("filter floppy repair methode. No floppy found");
repair_methods = filter (symbol r, map<any,any> d, (map<symbol,map<any,any> >)repair_methods, ``(
r != `floppy ));
}
}
/**
* Help text for the floppy repair method.
*/
define string floppy_help_text() ``{
//%1 is device label, such as /dev/hda
return sformat(_("
<p><h3>No Partition Table Found for Hard Disk %1</h3></BR>
The repair system will search for a valid partition table of disk %1
on the inserted floppy disk. If it cannot find
one, it will start the program gpart to guess the lost
partition table. You can decide if the information gpart
finds is valid for your system.</p>
"),target ) +
_("<p>gpart may be of some help when the primary partition table
has been lost or destroyed, but it can, under no circumstances,
replace proper disk and partition table backups. To save the
master boot record (MBR) including the primary partition
table to the file /tmp/hda.mbr, enter the command
<pre>
dd if=/dev/hda of=/tmp/hda.mbr bs=512 count=1
</pre>
replacing /dev/hda with the block device name of the disk
in question. This should be done for all disks in the system.
To restore the primary partition table without overwriting
the MBR, enter
<pre>
dd if=/tmp/hda.mbr of=/dev/hda bs=1 count=64 skip=446 seek=446
</pre></p>
") +
_("<p>Warning: Make sure that all parameters are entered as shown
and the disk device is correct. Failing to do so may
result in severe corruption of the file system. The saved file
should be stored in a safe place like a floppy disk.</p>
") +
_("<p>From the manual page of gpart:<br>
\"It should be stressed that gpart does a very heuristic
job, never believe its output without any plausability
checks. It can be easily right in its guesswork but it can
also be terribly wrong. You have been warned.\"</p>");
};
/**
* Help for gpart
*/
define string gpart_help_text()``{
//%1 is device label, such as /dev/hda
return sformat(_("
<P><h3>No Partition Table Found for Hard Disk %1</h3><BR>
The repair system will start gpart to guess the primary partition
table of disk %1.</p>
"), target) +
_("<p>gpart may be of some help when the primary partition table
was lost or destroyed, but it can, under no circumstances,
replace proper disk and partition table backups. To save the
master boot record (MBR) including the primary partition
table to the file /tmp/hda.mbr, enter
<pre>
dd if=/dev/hda of=/tmp/hda.mbr bs=512 count=1
</pre>
replacing /dev/hda with the block device name of the disk
in question. This should be done for all disks in the system.
To restore the primary partition table without overwriting
the MBR, enter
<pre>
dd if=/tmp/hda.mbr of=/dev/hda bs=1 count=64 skip=446 seek=446
</pre></p>
") +
_("<p>Warning: Make sure that all parameters are typed as shown
and the disk device is correct. Failing to do so may
result in severe corruption of the file system. The saved file
should be stored in a safe place like a floppy disk.</p>
") +
_("<p>From the manual page of gpart:<br>
\"It should be stressed that gpart does a very heuristic
job, never believe its output without any plausability
checks. It can be easily right in its guesswork but it can
also be terribly wrong. You have been warned.\"</p>");
}
/**
* Help text for restoring orginal mbr's
*/
define string original_help_text()``{
//%1 is device label, such as /dev/hda
return sformat(_("
Before starting any scan or repair sequence,
a backup of the original partition table
of the device %1 is created.
"), target );
}
/**
* Save all mbr's to tmp directory and saves the path names
* in the map backup_dev_filenames.
*/
define void SavePtbl()``{
y2milestone("Saving all mbr's to tmp directory");
// save all current ptbl's to tmp directory
map<string,map> tg = filter( string k, map disk, Storage::GetTargetMap(), ``(Storage::IsRealDisk(disk)));
list<string> devlist = maplist( string k, map disk, tg, ``(k));
if (devlist != nil && devlist != [] ) {
integer ok = 0;
foreach(string dev, devlist, ``{
// build mbr backup string
string randompart = sformat("%1/%2_%3.mbr",
WFM::Read(.local.tmpdir,"" ),
mergestring(splitstring(dev,"/"),"_") ,
random(100000));
if (OSRExecute::Command(.local.bash, sformat("/bin/dd if=%1 of=%2 count=1 bs=512",dev,randompart ))){
ok =ok+1;
backup_dev_filenames[dev] = randompart;
}
});
if (ok == size(devlist)) backup_mbr_status = true;
}
else {
y2error("Emtpy devive list. No harddisk found.");
}
}
/**
* Check reparired mbr.
*/
define boolean CheckRestoredPtbl(string target) ``{
y2milestone("checking restored ptl");
list partition_table = Storage::GetTargetMap()[target,"partitions"]:[];
if ((partition_table != nil) && (partition_table != []))
{
y2milestone("restoring was successful. Reread Storage");
// o.k., partition table successfully reverted.
Storage::ReReadTargetMap();
// popup message
Report::Message(_("
Partition table successfully repaired.
"));
return true;
}
else {
// popup message
Report::Message(_("
Partition table was not successfully repaired.
"));
}
return false;
}
/**
* Build the file name for reading partition list from floppy.
*/
define string build_file_name( string key )``{
return sformat("%2/%1",mergestring(splitstring(key, "/"),"_") , OSRFloppy::mount_point);
}
/**
* Need mounted floppy
*/
define list<map> read_part_list_from_floppy(string target)``{
return (list<map>) WFM::Read(.local.ycp, build_file_name(target)+".ycp");
}
/**
* Show
*/
define list<map> FoundPtblDialog (list<map> partitions, string dev, string repair_tool, boolean whole_mbr )``{
y2milestone("Found partitions for recovering %1", partitions );
string label_status = _("Status");
string label_name = _("Name");
//File System ID
string label_fsid = _("FSID");
string label_start = _("Start");
string label_end = _("End");
string label_size = _("Size");
string label_whole = _("Restore the Entire Master Boot Record");
list<term> items = [];
foreach (map n,partitions, {
if (n["region",1]:0 != 1)
{
map mdev = Storage::GetTargetMap()[dev]:$[];
items = add (items, `item (`id(sformat("%1", n["nr"]:1)),
s_ignore_label,
dev + n["nr"]:1,
n["fsid"]:131,
sformat ("%1", n["region",0]:0),
sformat ("%1", n["region",1]:0 + n["region",0]:0 - 1),
ByteToHumanString (n["size_k"]:0 * 1024)
));
}
});
// help_text first sentence.
string help_text = _("<P>The table in the center of the dialog shows the partitions
that could be recovered.</P>
") +
// %1 is Ignore label
OSRPopup::build_label_description( OSRPopup::ignore_label, sformat(_("Change the status of a partition to %1."), s_ignore_label )) +
// %1 is Recover label
OSRPopup::build_label_description( OSRPopup::recover_label, sformat(_("Change the status of a partition to %1."), s_recover_label)) +
//%1 is Recover label
OSRPopup::build_label_description( OSRPopup::repair_label, sformat(_("If you have changed the status of all partitions for recovering
to %1, press Repair to execute the recovery process.
"), s_recover_label)) +
// help_text description for table column, %1 ignore, %2 recover
OSRPopup::build_label_description( label_status, sformat(_("The status of a listed partition
can be switched between %1 and %2. Only
partitions with the status
%2 are recovered.
"), s_ignore_label, s_recover_label )) +
OSRPopup::build_label_description( label_name, _("Name of the partition that could be
recovered.
")) +
OSRPopup::build_label_description( label_fsid, _("The file system ID of the partition.
For example, 131 is a normal Linux partition and 6, 11, 12, and 14 are fat and fat32 partitions.
")) +
OSRPopup::build_label_description( label_start, _("The start cylinder of the partition.")) +
OSRPopup::build_label_description( label_end, _("The end cylinder of the partition.")) +
OSRPopup::build_label_description( label_size, _("Size of the partition."));
term whole_term = `Empty();
if (whole_mbr )
{
whole_term = `Left(`CheckBox(`id(`whole_mbr), `opt(`notify), label_whole ,false));
OSRPopup::build_label_description( label_whole, _("Select this option to
recover the entire master boot record with all partitions.
"));
}
// dialog caption
OSRPopup::OpenSuggestDialog(_("Recover Lost Partitions"),
// dialog text, %1 is device label
sformat(_("
The following partitions were found on device %1.
To recover a partition, select the entry
in the table and press Recover.
"), dev),
help_text,
`VBox(`Table(`id(`table), `header(label_status, label_name, label_fsid, label_start, label_end, label_size ), items ),
`Left(`HBox(
`PushButton(`id(`ignore), OSRPopup::ignore_label ),
`PushButton(`id(`recover), OSRPopup::recover_label )
)),
whole_term
),
40);
UI::SetFocus(`id(`table));
any ret = `ok;
list<map> recover = [];
repeat
{
ret = UI::UserInput();
string current_item = (string)UI::QueryWidget(`id(`table),`CurrentItem);
term it = (term) UI::QueryWidget (`id(`table), `Item (current_item));
string current_value = it[1]:"";
map current_part = find (map part, partitions, ``(
sformat("%1", part["nr"]:"") == current_item ));
if (current_part == nil || current_part == $[] )
y2error(" partition not found");
if (ret == `ignore )
{
if (current_part["type"]:`unknown == `extended )
{
foreach (map part,
filter (map p, partitions,``(p["type"]:`unknown==`logical)),
``{
UI::ChangeWidget(`id(`table),
`Item(sformat("%1", part["nr"]:""), 0), s_ignore_label);
});
}
UI::ChangeWidget(`id(`table),`Item(current_item, 0),s_ignore_label);
}
if (ret == `recover )
{
if (current_part["type"]:`unknown == `logical )
{
map extended = find (map part, partitions, ``(
part["type"]:`unknown == `extended ));
UI::ChangeWidget(`id(`table),
`Item(sformat("%1", extended["nr"]:""), 0),s_recover_label);
}
UI::ChangeWidget(`id(`table),`Item(current_item,0),s_recover_label);
}
if (ret == `whole_mbr )
{
UI::ChangeWidget(`id(`table), `Enabled,
!(boolean) UI::QueryWidget(`id(`whole_mbr), `Value ));
}
if ( ret == `ok )
{
recover = filter (map n, partitions, {
term it = (term) UI::QueryWidget (
`id(`table), `Item(sformat("%1", n["nr"]:1)));
return (it[1]:"" == s_recover_label);
});
y2milestone( "all selected items %1", recover );
if (whole_mbr )
{
if ((boolean)UI::QueryWidget(`id(`whole_mbr ), `Value ))
recover = [ $["whole_mbr":$[]] ];
}
}
} until( ret == `ok || ret == `cancel );
UI::CloseDialog();
return recover;
}
/**
* Call fdisk
*/
define boolean fdisk_call(string disk_dev, list<map> torecover )``{
UI::OpenDialog(`VBox(`VSpacing(1),
`Label(_("Recovering partition table...")),
`VSpacing(1)));
boolean result = true;
if (! Mode::test () )
{
/////////////////////////////////////////////////////
map<string,map> tg = Storage::GetTargetMap();
tg[disk_dev,"partitions"] = torecover;
Storage::SetTargetMap(tg);
Storage::CommitChanges();
/////////////////////////////////////////////////////
repair_methods[ `original, "enabled"] = true;
Storage::ReReadTargetMap();
}
else {
y2milestone("fdisk call not executed. Mode::test () = true !!!");
}
UI::CloseDialog();
return result;
};
/**
* Restore lost mbr with a backup from floppy.
*/
define symbol restore_from_floppy( )``{
//%1 is device label, such as /dev/hda
string error_message_start = sformat(_("No primary partition table was found on hard disk %1."), target );
//%1 is device label, such as /dev/hda
string error_message = sformat(_("
If you have a floppy with some
up-to-date system information from a former rescue
session, insert it in your drive and press Repair.
Press Skip and repair manually if you have a
backup of the partition table of disk %1.
Press Help to learn how to
make a backup of a partition table manually
and how to restore it.
"), target);
// this can't be repaired without a floppy drive, so the user must not be asked again
// to repair via floppy
if (! OSRCommon::RequireBoolean("has_floppy"))
{
// display that no floppy drive was detected
Report::Message(_("
Cannot detect a floppy drive
in your system. A backup copy of the
primary partition table could not be
read.
"));
return `error;
}
else {
if (! OSRPopup::Repair(_("Error Detected"), error_message_start + error_message, floppy_help_text())) return `cancel;
if (OSRFloppy::Open(true, 2))
{
OSRFloppy::NextStep(_("Searching for partition table..."));
list<map> found_partitions = read_part_list_from_floppy(target);
list to_recover = [];
if (found_partitions != nil && found_partitions != [] ) {
to_recover = FoundPtblDialog(found_partitions, target, "Floppy", true );
boolean revert = false;
if (size(to_recover ) == 0 ) {
Report::Warning(_("
Could not find a valid partition table.
Insert another floppy disk and
try again or have gpart suggest a
partition table.
"));
OSRFloppy::Close();
return `cancel;
}
else if (haskey( to_recover[0]:$[], "whole_mbr")) {
y2milestone("recover the whole mbr");
if (WFM::Read(.local.size, build_file_name(target)+".mbr" ) == 512 )
{
OSRFloppy::NextStep(_("Restoring old partition table..."));
// copy the backup of the primary partition table to the target device
revert = OSRExecute::Command(.local.bash,
sformat("/bin/dd if=%1.mbr of=%2 bs=1 count=512", build_file_name(target ),target ));
// call block device ioctls: reread the partition table (important after having
// changed the partition table!)
OSRExecute::Command(.target.bash, sformat("/sbin/blockdev --rereadpt %1", target));
}
else {
Report::Error(_("
Could not find a valid master boot
record on the floppy disk. Insert
another floppy disk and try again or
have gpart suggest the partition table.
"));
OSRFloppy::Close();
return `error;
}
}
OSRFloppy::Close();
if (! haskey( to_recover[0]:$[], "whole_mbr") ) {
list<map> new_to_recover = [];
foreach(map<string,any> p, (list<map<string,any> >)to_recover, ``{
p["create"] = true;
new_to_recover = add(new_to_recover, p);
});
revert = fdisk_call( target, new_to_recover );
}
if (revert )
{
if (CheckRestoredPtbl(target) ) {
return `ok;
}
}
// error message
Report::Error(_("
Restoring the partition table
was not successful.
Insert another floppy disk
and try again or have gpart
suggest the partition table.
"));
return `error;
}
}
else
{
// error message
Report::Error (_("
Either no floppy disk is inserted in
the drive or the inserted floppy is not
correctly formatted. Insert
another floppy disk and try again or
have gpart suggest the partition table.
"));
}
OSRFloppy::Close();
}
return `cancel;
}
/**
* Cat the fsid from a line.
*/
define integer gpart_cat_fsid(string line)``{
string sub = substring( line, find(line, ":"), find(line,"(")-find(line,":") );
string allow = "0123456789";
sub = filterchars( sub, allow);
return tointeger(sub);
}
/**
* Cat the geometry from a line.
*/
define map gpart_cat_geometry( string line)``{
string allow = "0123456789/";
string sub1 = substring( line, find(line, "d"), size(line));
list<string> split = splitstring(sub1, "-" );
string start = filterchars(split[0]:"", allow);
string end = filterchars(split[1]:"", allow);
list<string> s = splitstring( start, "/");
list<string> e = splitstring( end, "/");
map ret = $[ "start": $[ "c" : tointeger( s[0]:"0"),
"h" : tointeger( s[1]:"0"),
"s" : tointeger( s[2]:"0") ],
"end" : $[ "c" : tointeger( e[0]:"0"),
"h" : tointeger( e[1]:"0"),
"s" : tointeger( e[2]:"0") ]];
y2milestone("retmap gemetry %1", ret);
return ret;
};
/**
* Dialog with expert gpart options.
*/
define symbol expert_restore_with_gpart() {
// checkbox label
string full_label = _("Full Scan");
// button label
string start_label = _("Start Detection");
map maindev = Storage::GetTargetMap()[target]:$[];
integer cyl_count = maindev["cyl_count"]:0;
gpart_expert_options = "";
map symbol_2_option = $[
`extended : "-E",
`skip_errors : "-e",
`full_scan : "-f"
];
// help text label
string help_text = _("<P>
<BIG><B>Help for Expert Mode</B></BIG>
</P>
") +
// help text (restorng partition)
OSRPopup::build_label_description (full_label, _("
<P>When a possible partition is found,
gpart normally skips all sectors this entry seems
to occupy and continues the scan from the end of
the last possible partition. The disk scan can take
quite a while when using this option. Be patient.</P>
"));
UI::OpenDialog( `HBox(
`HWeight(2, `RichText(`id(`help), help_text )),
`HWeight(4,
`HBox(
`HSpacing(2),
`VBox(
// headline label, gpart is command
`Heading(_("Scan Options for gpart")),
`VSpacing(3),
// checkbox label
`Left(`CheckBox(`id(`extended), _("Do Not Try to &Identify Extended Partition Tables"))),
// checkbox label
`Left(`CheckBox(`id(`skip_errors), _("Do Not &Skip Disk Read Errors"))),
`Left(`CheckBox(`id(`full_scan), full_label )),
`VSpacing(4),
`HBox(
`PushButton(`id(`ok), start_label ),
`PushButton(`id(`cancel), Label::CancelButton())
)
),
`HSpacing(2)
)
)
));
UI::SetFocus(`id(`extended));
symbol ret = `ok;
repeat
{
ret = (symbol) UI::UserInput();
if (ret == `ok ) {
//build expert options
foreach (symbol key, string option, (map<symbol,string>)symbol_2_option, ``{
gpart_expert_options = gpart_expert_options +
((boolean)UI::QueryWidget(`id(key), `Value)
? " " + option + " " : "");
});
y2milestone("gpart options %1", gpart_expert_options );
}
} until( ret == `ok || ret == `cancel );
UI::CloseDialog();
if (ret == `ok ) ret = RestoreWithGpart ();
gpart_expert_options = "";
return ret;
}
define map compare_found_with_existing ( list<map> found_partitions,
list<map> existing_partitions,
string target) ``{
map ret = $[];
foreach(map paritition, found_partitions, ``{
map matching = find(map e_part, existing_partitions, ``(e_part["region"]:[] == paritition["region"]:[0]));
if (matching != nil && matching != $[] )
{
ret["match"] = add(ret["match"]:[], paritition );
y2milestone("found paritition %1 matchs with exiting paritition %2", paritition["device"]:"", matching["device"]:"");
}
else
{
integer found_start = paritition["region",0]:0;
integer found_end = paritition["region",0]:0 + paritition["region", 1]:0 -1;
foreach(map e_part, existing_partitions, ``{
integer existing_start = e_part["region", 0]:0;
integer existing_end = e_part["region", 0]:0 + e_part["region", 1]:0 -1;
if ((existing_start >= found_start && existing_start <= found_end) ||
(existing_end >= found_start && existing_end <= found_end) ||
(existing_start >= found_start && existing_end <= found_end) ||
(existing_start <= found_start && existing_end >= found_end)
)
{
paritition["overlap"] = add(paritition["overlap"]:[], e_part );
y2milestone("found paritition %1 overlaps with exiting paritition %2", paritition["device"]:"", e_part["device"]:"");
}
});
if (paritition["overlap"]:[] != [] )
{
ret["overlap"] = add(ret["overlap"]:[], paritition);
}
else
{
ret["free"] = add(ret["free"]:[], paritition );
y2milestone("found free paritition space for %1", paritition["device"]:"");
}
}
});
if (size(ret) > 0 )
{
ret["existing"] = existing_partitions;
}
return ret;
}
/**
* return partition information (to be shown to user)
*/
define string partition_info (map part, string dev) {
map maindev = Storage::GetTargetMap()[target]:$[];
return
// partition info 1/3, %1,%2 are numbers
sformat (_("Cylinders %1-%2, "),
part["region", 0]:0, part["region",0]:0 + part["region",1]:0 -1) +
// partition info 2/3, %1 is partition ID (number)
sformat(_("ID %1, "), part["fsid"]:131) +
// partition info 3/3, %1 is partition size (number)
sformat (_("Size %1"), ByteToHumanString (
part["region",1]:0 * maindev["cyl_size"]:0));
}
/**
* Compare an existing partition table with the gpart output
*/
define list<map> ComparePtblDialog (map compared, string target,
string repair_tool) ``{
term part_items = `VBox();
list<list> part_list = [];
list<map> found_free_parts = compared["free"]:[];
list<map> overlap_parts = compared["overlap"]:[];
//number to text
map number2text = $[
// label: partition number
1 : _("First Partition Found"),
2 : _("Second Partition Found"),
3 : _("Third Partition Found"),
4 : _("Fourth Partition Found")
];
foreach (map free_part, found_free_parts, ``{
integer nr = free_part["nr"]:0;
part_list = add (part_list, [
nr,
`Left (
`CheckBox(`id(free_part["device"]:""),
//%1 is number. %2 is text like "First Partition Found", %3 is partition info
sformat (_("&%1: %2: %3"), nr, number2text[nr]:"",
partition_info (free_part, target)),
true
)
)
]);
});
foreach (map overlap_part, overlap_parts, ``{
integer nr = overlap_part["nr"]:0;
list<string> del_text_parts = maplist (map e_part,
overlap_part["overlap"]:[], ``{
return sformat (
// label: %1 is device name, %2,%3 numbers
_("Partition %1 must be deleted to recover cylinders %2-%3."),
e_part["device"]:"",
overlap_part["region",0]:0,
overlap_part["region",0]:0 + overlap_part["region",1]:0 - 1);
});
part_list = add (part_list, [
nr,
`Left (`VBox (
`Left (
`CheckBox (`id(overlap_part["device"]:""),
//%1 in number, %2 is text like "Second Partition Found", %3 is partition info
sformat(_("&%1: %2: %3"), nr, number2text[nr]:"",
partition_info (overlap_part, target)),
false)
),
`VSpacing(0.5),
`Left (
// heading
`Heading (_("Conflicts with Existing Partitions"))
),
`Left (
`Label (mergestring (del_text_parts, "\n"))
)
))
]);
});
part_list = sort (list l, list q, part_list, ``( l[0]:0 < q[0]:0 ));
foreach (list part, part_list , ``{
part_items = add (part_items, part[1]:`Empty());
part_items = add (part_items, `VSpacing(2));
});
// gpart found only existing partitions.
if (size( found_free_parts ) == 0 && size( overlap_parts ) == 0 )
{
// popup message
Report::Message(_("No lost partition found."));
return [];
}
// help text of partition recovery 1/2
string help_text = _("
<p>
Read the following points carefully
and select only the partition that should
really be recovered.
</P>
") +
// help text of partition recovery 2/2
_("<P><B>Use caution.</B> Sometimes an existing partition must
be deleted to recover another partition.</P>
") +
OSRPopup::build_label_description (OSRPopup::repair_label,
// help text for button
_("Start the recovery process."));
string message = "";
// popup headline
OSRPopup::OpenSuggestDialog (_("Recover Previously Existing Partitions"),
message,
help_text,
`HBox (`HSpacing(1), part_items, `HSpacing(1)),
(size(found_free_parts) + size(overlap_parts)) * 15
);
any ret = `ok;
list<map> recover = [];
repeat
{
ret = UI::UserInput();
if ( ret == `ok )
{
foreach (map free_part, found_free_parts, ``{
if ((boolean)
UI::QueryWidget(`id(free_part["device"]:""), `Value))
{
recover = add (recover, free_part );
}
});
foreach (map overlap_part, overlap_parts, ``{
if ((boolean)
UI::QueryWidget(`id(overlap_part["device"]:""), `Value))
{
// warning popup, %1 is device name, %2 list of partitions
if (Popup::ContinueCancel (sformat(_("
Recovering the selected partition %1 is only
possible by deleting the following partitions:
%2
Press Continue to delete the partitions
and recover %1."),
overlap_part["device"]:"",
mergestring (
maplist (map o_part, overlap_part["overlap"]:[],
``(o_part["device"]:"")),
" "
)
)))
{
foreach (map delpart, overlap_part["overlap"]:[], ``{
delpart["delete"] = true;
delpart = filter (string key, any d,
(map<string,any>) delpart,``(key != "overlap"));
recover = (list<map>) union (recover, [delpart]);
});
overlap_part = filter (string key, any d,
(map<string,any>)overlap_part,``(key != "overlap"));
recover = add (recover, overlap_part );
}
else //popup canceled
{
UI::ChangeWidget (`id(overlap_part["device"]:""),
`Value, false);
recover = [];
ret = `again;
}
}
});
list<map> existing_partitions = compared["existing"]:[];
list used_nrs = maplist (
map ep,existing_partitions,``(ep["nr"]:0));
list delete_nrs = maplist (
map dpp, filter (map dp, recover, ``(dp["delete"]:false)),
``(dpp["nr"]:0)
);
used_nrs = filter (integer nr, (list<integer>) used_nrs, ``(
!contains(delete_nrs, nr)));
list<integer> primary_pos = [1,2,3,4];
list<integer> free_primary = filter (integer nr, primary_pos, ``(
!contains (used_nrs, nr)));
// check partition nr's
foreach(map part, recover , {
if (part["delete"]:false != true && ret != `again )
{
// partition nr is used by a other partition.
if (contains (used_nrs, part["nr"]:0))
{
if (size (free_primary) > 0)
{
y2milestone("move partition nr %1 to a free primary position", part["nr"]:0);
part["nr"] = free_primary[0]:0;
free_primary = remove (free_primary, 0);
}
else
{
y2error("no free primary slot found. locical search not supported");
// error popup, %1 is paritition number, %2 info
Report::Error(sformat(_("
Recovering the partition %1 (%2) is not
possible. The partition number conflicts
with an existing partition. Solving the
conflict is not possible.
"), part["nr"]:0, partition_info (part, target)));
UI::ChangeWidget(`id(part["device"]:""), `Value, false);
ret = `again;
}
}
}
});
}
} until ( ret == `ok || ret == `cancel );
UI::CloseDialog();
return recover;
}
/**
* Restoring a partition tables with gpart.
*/
global define symbol RestoreWithGpart () ``{
/////////////////////////////////////////////////////////////////////////
//
// Repair partition table with gpart
//
/////////////////////////////////////////////////////////////////////////
list<map> found_partitions = [];
string gpart_file = (string) SCR::Read(.target.tmpdir) + "/gpart";
WFM::Execute (.local.bash, sformat("if /usr/bin/test -e %1; then /bin/rm %1; else /bin/echo %1 not exist; fi;", gpart_file));
string gpart_command = "/usr/bin/gpart "+ gpart_expert_options +" "+ target;
term contents = `HBox(`HSpacing(0.5),
`VBox (
`Left (`HBox (
// headline of partition scan popup
`HWeight (30, `Heading(_("Search for Lost Partitions"))),
`HWeight (30, `HSpacing(4))
)),
`VSpacing(1),
// addtional info for partition scan
`Left (`Label (_("This can take a lot of time depending on the
system performance and the hard disk size.")
)),
// label text (device name follows)
`Left (`Label(_("Hard Disk: ") + target)),
`VSpacing(0.5),
`VSpacing(1),
// button label
`HBox (
`PushButton(`id(`start) , _("&Start")),
`PushButton (`id(`cancel), Label::CancelButton())
)
),
`HSpacing(0.5)
);
UI::OpenDialog (contents);
if (UI::UserInput () != `start )
{
UI::CloseDialog();
return `cancel;
}
UI::ChangeWidget(`id(`start), `Enabled, false);
UI::ChangeWidget(`id(`cancel), `Enabled, false);
// FIXME action cannot be cancelled! -> use background or callback
// progress doesn't have sence!
UI::BusyCursor();
if (OSRExecute::CommandProgress (.target.bash_output, gpart_command, gpart_file))
{
string file = (string) WFM::Read(.local.string, gpart_file );
// display the results in a window
string partitions_out = substring (file,
find (file, "\nPrimary partition(1)"),
(size(file) - find (file, "\nPrimary partition(1)"))
);
string partition1 = substring(partitions_out,
find(partitions_out, "\nPrimary partition(1)"),
(find(partitions_out, "\nPrimary partition(2)") -
find(partitions_out, "\nPrimary partition(1)"))
);
string partition2 = substring (partitions_out,
find (partitions_out, "\nPrimary partition(2)"),
(find(partitions_out, "\nPrimary partition(3)") -
find(partitions_out, "\nPrimary partition(2)"))
);
string partition3 = substring (partitions_out,
find(partitions_out, "\nPrimary partition(3)"),
(find(partitions_out, "\nPrimary partition(4)") -
find(partitions_out, "\nPrimary partition(3)"))
);
string partition4 = substring(partitions_out,
find(partitions_out, "\nPrimary partition(4)"),
(size(partitions_out)-find(partitions_out,"\nPrimary partition(4)"))
);
list gpart_partitions = [partition1, partition2, partition3,partition4];
integer index = 0;
while ((index >= 0) && (index < size(gpart_partitions)))
{
map partition = $[];
string p = gpart_partitions[index]:"";
list<string> p_list = splitstring(p, "\n");
foreach (string line, p_list, ``{
if (issubstring(line, "type: "))
{
partition["fsid"] = gpart_cat_fsid(line );
}
else if (issubstring( line, "chs:"))
{
map geometry = gpart_cat_geometry( line );
integer s = geometry["start","c"]:0;
integer l = geometry["end","c"]:0 - s + 1;
partition["region"] = [s,l];
}
partition["nr"] = index +1;
partition["type"] = `primary;
partition["create"] = true;
partition["device"] = Storage::GetDeviceName(target, index + 1);
});
index = index + 1;
if (partition["region",1]:0 != 0 && partition["fsid"]:0 != 0)
{
found_partitions = add(found_partitions, partition );
}
}
}
UI::CloseDialog();
UI::NormalCursor();
if (size (found_partitions) == 0)
{
// error popup, %1 is device
Report::Error(sformat(_("
No valid partitions found for the
partition table of %1. If there were
some partitions on the disk, you can try
to restore them manually. To do
that, enter the cylinder values
in fdisk or the partitioning tool.
"), target));
return `error;
}
else
{
map compared = compare_found_with_existing (
found_partitions,
(list<map>) Storage::GetTargetMap()[target, "partitions"]:[],
target);
list<map> torecover = ComparePtblDialog (compared, target, "Gpart");
if (size (torecover) < 1 || Mode::test ())
return `cancel;
if (fdisk_call (target, torecover))
{
if (CheckRestoredPtbl (target))
{
return `ok;
}
}
else
{
// error popup message
Report::Error(_("Partition table was not successfully repaired."));
return `error;
}
}
return `error;
}
/**
* Restore saved mbr.
*/
define boolean write_original(list<string> to_reset, boolean whole_mbr )``{
if (Mode::test () ) return true;
y2milestone("write orginal master boot record");
integer ok = 0 ;
foreach(string dev, to_reset , ``{
if ( backup_dev_filenames[dev]:"" != "" ) {
string command = sformat("/bin/dd if=%1 of=%2 ", backup_dev_filenames[dev]:"", dev );
if (whole_mbr ) command = command + "count=1 bs=512";
else command = command + "bs=1 count=64 skip=446 seek=446";
if (OSRExecute::Command(.local.bash,command)) {
ok = ok + 1;
Report::Message(sformat(_("Writing the backup of %1 was successful."), dev));
}
else {
Report::Message(sformat(_("Writing the backup of %1 was not successful."), dev));
}
repair_methods[ `original, "enabled"] = true;
}
else {
y2error("No entry in backup map found");
}
});
return ( ok == size(to_reset));
}
/**
* Restore saved mbr.
*/
define symbol restore_original()``{
//%1 is device label, such as /dev/hda
string header = sformat(_("Restore Original Partition Table of %1"), target);
string ok_label = mergestring(splitstring(Label::OKButton(), "&"),"");
//%1 is OK button label, %2 is device like /dev/hda
string message = original_help_text() + sformat(_("
If you press %1, the partition table
of %2 will be replaced with
the backup.
"), ok_label, target );
if (Popup::YesNoHeadline(header, message ))
{
if (! Mode::test () )
{
if (write_original([target], true )) return `ok;
else return `error;
}
else {
return `ok;
}
}
return `cancel;
}
/**
* Write partition info of given disk to floppy (needs mounted floppy)
*/
global define boolean WritePartitionsInfo2Floppy (string key, list parts) {
if (Mode::test () ) return true;
boolean write_error = false;
string file = build_file_name (key);
// set the dd-command
string command = sformat("dd if=%1 of=%2.mbr bs=512 count=1", key, file);
// write mbr to floppy
OSRExecute::Command (.local.bash, command);
// write partition list to floppy
WFM::Write (.local.ycp, file+".ycp", parts);
if (!(WFM::Read(.local.size, file + ".mbr") == 512 &&
WFM::Read(.local.size, file + ".ycp") != 0 ))
{
write_error = true;
}
return (!write_error);
}
/**
* Main Dialog for repairing deleted/not valid partition tables.
*
* @parm t_target the target e.g.: /dev/hda
*
*/
global define symbol MainPtblRepairDialog(string t_target) ``{
//Save all mbr's to tmp directory.
SavePtbl();
target = t_target;
term r_options = `VBox(`Left(`Label(_("Select a repair method or skip repairing."))),`VSpacing(0.5));
foreach(symbol ro, map<string,any> rd, (map<symbol,map<string,any> >)repair_methods, ``{
term r_button = `RadioButton(`id( ro ));
if (! rd["enabled"]:true ) r_button = add( r_button , `opt(`disabled));
r_button = add( r_button , rd["header"]:"");
r_button = add( r_button, rd["default"]:false );
r_options = add( r_options , `Left( r_button ));
});
//%1 is device label, such as /dev/hda
string error_text = sformat(_("
No partition table was found for hard disk %1.
If at least one partition should exist for %1,
select one of the following repair methods. If
no partition ever existed on this hard disk,
skip the repair.
"), target);
//%1 is device label, such as /dev/hda
if (! OSRPopup::OpenMainRepairDialog( sformat(_("Repair Partition Table of %1"),target ), error_text, r_options ))
{
y2error("could not open main dialog");
return `error;
}
symbol ret = `ok;
repeat {
ret = (symbol) UI::UserInput();
symbol selected = (symbol) UI::QueryWidget(`id(`rb), `CurrentButton);
if (ret == `help )
{
string () help_f =
repair_methods[selected,"help"]:OSRCommon::EmptyString;
Popup::LongText (OSRPopup::help_headline,
`RichText ( help_f () ), 50, 20);
}
else if (ret == `ok )
{
UI::CloseDialog();
symbol () f =
repair_methods [selected,"method"]:OSRCommon::SymbolError;
ret = f ();
if (ret != `ok )
{
if (! OSRPopup::OpenMainRepairDialog (
// dialog headline, %1 is device label live /dev/hda
sformat(_("Repair Partition Table of %1"), target ),
error_text, r_options ))
{
y2error("could not open main dialog");
return `error;
}
ret = `again;
}
}
} until( ret == `cancel || ret == `abort || ret == `ok );
if (ret != `ok ) UI::CloseDialog();
return ret;
}
global define void SetTarget(string ttarget)``{
target = ttarget;
}
}//EOF