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
/
RootPart.ycp
< prev
next >
Wrap
Text File
|
2006-11-29
|
35KB
|
1,277 lines
/**
* Module: RootPart.ycp
*
* Authors: Arvin Schnell <arvin@suse.de>
*
* Purpose: Responsible for searching of root partitions and
* mounting of target partitions.
*
* $Id: RootPart.ycp 33392 2006-10-13 11:39:53Z locilka $
*/
{
module "RootPart";
textdomain "update";
import "Directory";
import "Mode";
import "Keyboard";
import "Linuxrc";
import "Storage";
import "Popup";
import "ModuleLoading";
import "FileSystems";
import "Update";
import "SuSERelease";
import "FileUtils";
include "partitioning/partition_defines.ycp";
include "partitioning/custom_part_helptexts.ycp";
include "partitioning/custom_part_dialogs.ycp";
// all supported filesystems
global list possible_root_fs = [ `ext2, `ext3, `reiser, `xfs, `jfs ];
// Selected root partition for the update or boot.
global string selectedRootPartition = "";
// Map of all root partitions (key) and information map (value).
// The information map contains the keys `valid, `name and `arch.
global map<string,map> rootPartitions = $[];
// Number of valid root partitions.
global integer numberOfValidRootPartitions = 0;
// Show all partitions (not only root partitions) in the dialog.
global boolean showAllPartitions = false;
// Did we search for root partitions
global boolean didSearchForRootPartitions = false;
// We successfully mounted the target partitions
global boolean targetOk = false;
// Did we try to mount the target partitions?
global boolean did_try_mount_partitions = false;
list <string> already_checked_jfs_partitions = [];
/**
* List of mounted partitions, activated swap partitions and loop devices.
* Amongst other things used for reversing action if mode is changed from
* update to new installation or if root partition for update is changed.
* The order of the list if of paramount importance.
*
* Each item is list [string value, string type [, string device]] where:
*
* Keys/values are:
*
* `type The type, one of "mount", "swap" or "loop".
*
* `device The device.
*
* `mntpt The mount point, only for `type = "mount". Does not
* include Installation::destdir.
*/
list <map <symbol, string> > activated = [];
global boolean Mounted () {
return size (activated) > 0;
}
/**
* Link to SDB article concerning renaming of devices.
*/
string sdb = sformat (_("See the SBD article at %1 for details
about how to solve this problem."),
"http://support.novell.com/techcenter/sdb/en/2003/03/fhassel_update_not_possible.html");
/**
* Get the key what of the selected root partition.
*/
global define string GetInfoOfSelected (symbol what)
{
map i = rootPartitions[selectedRootPartition]:$[];
if (what == `name) {
// Name is known
if (i[what]:"" != "") {
return i[what]:"";
// Linux partition, but no root FS found
} else if (contains (possible_root_fs, i[`fs]:`nil)) {
// label - name of sustem to update
return _("Unknown Linux System");
// Non-Linux
} else {
// label - name of sustem to update
return _("Non-Linux System");
}
} else {
// label - name of sustem to update
return i[what]:_("Unknown");
}
}
/**
* Set the selected root partition to some valid one. Only
* make sense if the number of valid root partition is one.
*/
global define void SetSelectedToValid ()
{
selectedRootPartition = "";
foreach (string p, map i, rootPartitions, {
if (i[`valid]:false && selectedRootPartition == "")
selectedRootPartition = p;
});
}
/**
*
*/
define void AddToTargetMap ()
{
map <string, map> target_map = (map <string, map>) Storage::GetOndiskTarget ();
y2milestone ("On disk target map: %1", target_map);
list <map> tmp = filter (map e, activated, ``(e[`type]:"" == "mount"));
foreach (map e, tmp, {
y2milestone ("Setting partition data: Device: %1, MountPoint: %2",
e[`device]:"", e[`mntpt]:"");
target_map = Storage::SetPartitionData (target_map, e[`device]:"",
"mount", e[`mntpt]:"");
});
tmp = filter (map e, activated, ``(e[`type]:"" == "swap"));
foreach (map e, tmp, {
y2milestone ("Setting swap partition data: Device: %1",
e[`device]:"");
target_map = Storage::SetPartitionData (target_map, e[`device]:"",
"mount", "swap");
});
y2milestone ("Setting target map: %1", target_map);
Storage::SetTargetMap (target_map);
}
/**
*
*/
define void RemoveFromTargetMap ()
{
map <string, map> target_map = Storage::GetTargetMap ();
list <map> tmp = filter (map e, activated, ``(e[`type]:"" == "mount"));
foreach (map e, tmp, {
target_map = Storage::SetPartitionData (target_map, e[`device]:"",
"mount", "");
});
Storage::SetTargetMap (target_map);
}
/**
* Unmount all mounted partitions, deactivate swaps, detach loopback
* devices. Uses list activated to make actions in reverse order.
* @param keeep_in_target Do not remove mounts from targetmap
* @return void
*/
global define void UnmountPartitions (boolean keep_in_target)
{
y2milestone ("UnmountPartitions: %1", keep_in_target);
did_try_mount_partitions = false;
foreach (map info, activated, {
y2milestone ("Unmounting %1", info);
string type = info[`type]:"";
if (type != "")
{
if (type == "mount")
{
string file = Installation::destdir + info[`mntpt]:"";
if (! (boolean)SCR::Execute (.target.umount, file))
{
// error report, %1 is device (eg. /dev/hda1)
Report::Error (sformat (_("Cannot unmount partition %1.
It is currently in use. If the partition stays mounted,
the data may be lost. Unmount the partition manually
or restart your computer.
"), file));
}
}
else if (type == "swap")
{
string device = info[`device]:"";
// FIXME? is it safe?
if (SCR::Execute (.target.bash, "/sbin/swapoff " + device) != 0)
{
y2error("Cannot deactivate swap %1", device);
}
}
else if (type == "loop")
{
string device = info[`device]:"";
// FIXME? is it safe?
if (WFM::Execute(.local.bash, "losetup -d " + device) != 0)
{
y2error("Cannot deactivate loopback device %1", device);
}
}
}
});
// now remove the mount points of the mounted partitions
// in the target map of the storage module
if (!keep_in_target)
RemoveFromTargetMap ();
// clear activated list
activated = [];
}
/**
* Add information about mounted partition to internal list.
* @param partinfo partinfo has to be list with exactly two strings,
* see description of list "activated"
* @return void
*/
define void AddMountedPartition (map <symbol, string> partinfo)
{
activated = prepend (activated, partinfo);
y2debug ("adding %1 yields %2", partinfo, activated);
}
/**
* Check the filesystem of a partition.
*/
define void FSCKPartition (string partition)
{
if (!Mode::test ())
{
symbol detected_fs = Storage::DetectFs (partition);
if (detected_fs == `ext2)
{
// label, %1 is partition
string out = sformat (_("Checking partition %1"), partition);
UI::OpenDialog (`opt(`decorated ), `Label(out));
y2milestone ("command: /sbin/e2fsck -y %1", partition);
SCR::Execute (.target.bash, "/sbin/e2fsck -y " + partition);
UI::CloseDialog ();
}
}
}
/**
* Function checks the device and returns whether it is OK or not.
* The read-only FS check is performed for jfs only and only one for
* one device.
*
* @param string mount_type "jfs", "ext2" or "reiser"
* @param string device, such as /dev/hda3 or /dev/sda8
* @param string error_message (a reference to string)
* @return boolean if successfull or if user forces it
*/
define boolean RunFSCKonJFS (string mount_type, string device, string & error_message) {
// #176292, run fsck before jfs is mounted
if (mount_type == "jfs" && device != "") {
if (contains (already_checked_jfs_partitions, device)) {
y2milestone ("Device %1 has been already checked...", device);
return true;
}
UI::OpenDialog (`Label (sformat (_("Checking file system on %1..."), device)));
y2milestone ("Running fsck on %1", device);
// -n == Check read only, make no changes to the file system.
map cmd = (map) SCR::Execute (.target.bash_output, sformat ("fsck.jfs -n %1", device));
UI::CloseDialog();
// failed
if (cmd["exit"]:nil != 0) {
y2error ("Result: %1", cmd);
error_message = tostring(cmd["stderr"]:nil);
return Popup::ContinueCancel (sformat (
// popup question (continue/cancel dialog)
// %1 is a device name such as /dev/hda5
_("The file system check of device %1 has failed.
Would you like to continue in mounting the device?"),
device
));
// succeeded
} else {
// add device into the list of already checked partitions (with exit status 0);
already_checked_jfs_partitions = add (already_checked_jfs_partitions, device);
y2milestone ("Result: %1", cmd);
return true;
}
}
return true;
}
/**
* Mount partition on specified mount point
* @param mount_point string mount point to monut the partition at
* @param device string device to mount
* @param mount_type string filesystem type to be specified while mounting
* @return string nil on success, error description on fail
*/
define string MountPartition (string mount_point, string device,
string mount_type)
{
if (mount_type == "")
// e.g. -> "reiserfs"
mount_type = FileSystems::GetMountString (
Storage::DetectFs (device), "");
list <string> non_modular_fs = [ "proc", "sysfs" ];
// #211916, sysfs, proc are not modular
if (! contains (non_modular_fs, mount_type)) {
// #167976, was broken with "-t ", modprobe before adding it
y2milestone("Calling 'modprobe %1'", mount_type);
SCR::Execute(.target.modprobe, mount_type, "" );
} else {
y2milestone("FS type %1 is not modular, skipping modprobe...", mount_type);
}
string error_message = nil;
if (! RunFSCKonJFS (mount_type, device, error_message)) {
return error_message;
}
if (mount_type != "")
mount_type = "-t " + mount_type;
boolean ret = (boolean) SCR::Execute (.target.mount,
[device, Installation::destdir + mount_point, Installation::mountlog],
mount_type );
if (ret)
return nil;
else
return (string)SCR::Read (.target.string, Installation::mountlog);
}
/**
* Check filesystem on a partition and mount the partition on specified mount
* point
* @param mount_point string mount point to monut the partition at
* @param device string device to mount
* @param mount_type string filesystem type to be specified while mounting
* @return string nil on success, error description on fail
*/
define string FsckAndMount (string mount_point, string device,
string mount_type)
{
FSCKPartition (device);
string ret = MountPartition (mount_point, device, mount_type);
if (ret == nil)
AddMountedPartition($[`type : "mount", `device : device, `mntpt : mount_point]);
y2milestone ("mounting (%1, %2, %3) yield %4", Installation::destdir +
mount_point, device, mount_type, ret);
return ret;
}
/**
* Check that the root filesystem in fstab has the correct device.
*/
define boolean check_root_device (string partition, list <map> fstab,
string& found_partition)
{
list <map> tmp = filter (map entry, fstab, ``(entry["file"]:"" == "/"));
if (size (tmp) != 1)
{
y2error ("not exactly one root partition found in fstab");
found_partition = "none";
return false;
}
map root = tmp[0]:$[];
if (!Storage::DeviceRealDisk (root["spec"]:""))
{
// There's nothing I can check. Anyway, it's not mounted per device
// name so it can't be wrong, in theory.
return true;
}
if (root["spec"]:"" != partition)
{
y2error ("root partition in fstab has wrong device");
found_partition = root["spec"]:"";
return false;
}
return true;
}
/**
* Find a monut poing in fstab
* @param fstab a list of fstab entries
* @param mountpoint string a mount point to find
* @return string the found partition
*/
define string FindPartitionInFstab (list<map> fstab, string mountpoint) {
if (substring (mountpoint, size (mountpoint) - 1, 1) == "/")
mountpoint = substring (mountpoint, 0, size (mountpoint) - 1);
list <map> tmp = filter (map entry, fstab, {
return entry["file"]:"" == mountpoint
|| entry["file"]:"" == mountpoint + "/";
});
if (size (tmp) == 0)
return nil;
return tmp[0,"spec"]:"";
}
/**
*
*/
define list <map> TranslateFSTab (list <map> fstab)
{
list <string> old_names = [];
foreach (map m, fstab, {
old_names = add (old_names, m["spec"]:"");
});
list <string> new_names = Storage::GetTranslatedDevices (
Update::installedVersion, Update::updateVersion,
old_names);
integer i = 0;
while (i < size (fstab))
{
string spec = fstab[i,"spec"]:"";
fstab[i,"spec"] = new_names[i]:spec;
i = i + 1;
};
return fstab;
}
/**
* Register a new fstab agent and read the configuration
* from Installation::destdir
*/
void readFsTab (list <map> & fstab) {
string fstab_file = Installation::destdir + "/etc/fstab";
if (FileUtils::Exists (fstab_file)) {
SCR::RegisterAgent (.target.etc.fstab, `ag_anyagent(
`Description (
(`File(fstab_file)),
"#\n", // Comment
false, // read-only
(`List (
`Tuple (
`spec (`String("^\t ")),
`Separator ("\t "),
`file (`String("^\t ")),
`Separator ("\t "),
`vfstype (`String("^\t ")),
`Separator ("\t "),
`mntops (`String("^ \t\n")),
`Optional(`Whitespace()),
`Optional(`freq (`Number())),
`Optional(`Whitespace()),
`Optional(`passno (`Number()))
),
"\n"
))
)
));
fstab = (list<map>) SCR::Read (.target.etc.fstab);
SCR::UnregisterAgent (.target.etc.fstab);
} else {
y2error ("No such file %1. Not using fstab.", fstab_file);
}
}
/**
* Register a new cryptotab agent and read the configuration
* from Installation::destdir
*/
void readCryptoTab (list <map> & crtab) {
string crtab_file = Installation::destdir + "/etc/cryptotab";
if (FileUtils::Exists (crtab_file)) {
SCR::RegisterAgent (.target.etc.cryptotab, `ag_anyagent(
`Description (
(`File(crtab_file)),
"#\n", // Comment
false, // read-only
(`List (
`Tuple (
`loop (`String("^\t ")),
`Separator ("\t "),
`file (`String("^\t ")),
`Separator ("\t "),
`mount (`String("^\t ")),
`Separator ("\t "),
`vfstype (`String("^\t ")),
`Separator ("\t "),
`opt1 (`String("^\t ")),
`Separator ("\t "),
`opt2 (`String("^ \t\n"))
),
"\n"
))
)
));
crtab = (list<map>) SCR::Read (.target.etc.cryptotab);
SCR::UnregisterAgent (.target.etc.cryptotab);
} else {
y2warning ("No such file %1. Not using cryptotab.", crtab_file);
}
}
/**
*
*/
define boolean read_fstab_and_cryptotab (list <map>& fstab, list <map>& crtab)
{
integer default_scr = WFM::SCRGetDefault ();
integer new_scr = nil;
if (Stage::initial ())
{
readFsTab (fstab);
readCryptoTab (crtab);
}
else
{
fstab = (list<map>) SCR::Read (.etc.fstab);
crtab = (list<map>) SCR::Read (.etc.cryptotab);
}
return true;
}
/**
*
*/
define boolean PrepareCryptoTab (list <map> crtab, list <map>& fstab)
{
integer crypt_nb = 0;
foreach (map mounts, crtab, {
string vfstype = mounts["vfstype"]:"";
string mntops = mounts["opt2"]:"";
string loop = mounts["loop"]:"";
string fspath = mounts["mount"]:"";
string device = mounts["file"]:"";
y2milestone ("vfstype:%1 mntops:%2 loop:%3 fspath:%4 device:%5",
vfstype, mntops, loop, fspath, device);
if (!issubstring (mntops, "noauto"))
{
boolean again = true;
while (again)
{
boolean crypt_ok = true;
string crypt_passwd = DlgUpdateCryptFs( device, fspath );
if (crypt_passwd == nil || crypt_passwd == "")
{
crypt_ok = false;
again = false;
}
y2milestone ("crypt pwd ok:%1", crypt_ok);
if (crypt_ok)
{
map setloop = $[ "encryption" : "twofish",
"passwd" : crypt_passwd,
"loop_dev" : loop,
"partitionName" : device ];
crypt_ok = Storage::PerformLosetup( setloop, false );
y2milestone ("crypt ok: %1", crypt_ok);
if( crypt_ok )
loop = setloop["loop_dev"]:"";
else
{
// yes-no popup
again = Popup::YesNo (_("Incorrect password. Try again?"));
}
}
if (crypt_ok)
{
map add_fs = $[ "file" : fspath,
"mntops" : mntops,
"spec" : loop,
"freq" : 0,
"passno" : 0,
"vfstype": vfstype ];
fstab = prepend (fstab, add_fs);
AddMountedPartition ($[`type : "loop", `device : device]);
again = false;
}
}
}
});
return true;
}
/**
* Check if specified mount point is mounted
* @param mountpoint the mount point to be checked
* @return boolean true if it is mounted
*/
define boolean IsMounted (string mountpoint) {
if (substring (mountpoint, size (mountpoint) - 1, 1) == "/")
mountpoint = substring (mountpoint, 0, size (mountpoint) - 1);
boolean ret = true;
foreach (map e, activated, {
if (e[`type]:"" == "mount"
&& (e[`mntpt]:"" == mountpoint
|| e[`mntpt]:"" == mountpoint + "/"))
{
ret = true;
}
});
return ret;
}
/**
*
*/
define boolean MountFSTab (list <map> fstab, string& message)
{
list allowed_fs = [ "ext", "ext2", "ext3", "minix", "reiserfs", "jfs",
"xfs", "xiafs", "hpfs", "vfat", "auto", "proc" ];
// mount sysfs first
string ret = MountPartition ("/sys", "sysfs", "sysfs");
if (ret == nil)
AddMountedPartition($[`type : "mount", `device : "sysfs", `mntpt : "/sys"]);
boolean success = true;
boolean raidMounted = false;
foreach (map mounts, fstab, {
string vfstype = mounts["vfstype"]:"";
string mntops = mounts["mntops"]:"";
string spec = mounts["spec"]:"";
string fspath = mounts["file"]:"";
if (contains (allowed_fs, vfstype)
&& fspath != "/" && (fspath != "/var" || ! IsMounted("/var"))
&& !issubstring (mntops,"noauto"))
{
y2milestone ("mounting %1 to %2", spec, fspath);
if ( !Mode::test () )
{
string mount_type = "";
if (vfstype == "proc")
{
mount_type = vfstype;
}
string mount_err = "";
while (mount_err != nil)
{
mount_err = FsckAndMount (fspath, spec, mount_type);
if (mount_err != nil)
{
y2error("mounting %1 (type %2) on %3 failed", spec,
mount_type, Installation::destdir + fspath);
UI::OpenDialog (`VBox (
`Label (sformat (
// label in a popup, %1 is device (eg. /dev/hda1), %2 is output of the 'mount' command
_("The partition %1 could not be mounted.
%2
If you are sure that the partition is not necessary for the
update (it is not any system partition), click Continue.
To check or fix the mount options, click Specify Mount Options.
To abort update, click Cancel."),
spec, mount_err)
),
`VSpacing (1),
`HBox (
`PushButton (`id (`cont), Label::ContinueButton ()),
// push button
`PushButton (`id (`cmd), _("&Specify Mount Options")),
`PushButton (`id (`cancel), Label::CancelButton ())
)
));
symbol act = (symbol)UI::UserInput ();
UI::CloseDialog ();
if (act == `cancel)
{
mount_err = nil;
success = false;
}
else if (act == `cont)
{
mount_err = nil;
}
else if (act == `cmd)
{
UI::OpenDialog (`VBox (
// popup heading
`Heading (_("Mount Options")),
`VSpacing (0.6),
// text entry label
`TextEntry (`id (`mp), _("&Mount Point"), fspath),
`VSpacing (0.4),
// tex entry label
`TextEntry (`id (`device), _("&Device"), spec),
`VSpacing (0.4),
// text entry label
`TextEntry (`id (`fs), _("&File System\n(empty for autodetection)"), mount_type),
`VSpacing (1),
`HBox (
`PushButton (`id (`ok), Label::OKButton ()),
`PushButton (`id (`cancel), Label::CancelButton ())
)
));
act = (symbol)UI::UserInput ();
if (act == `ok)
{
fspath = (string)UI::QueryWidget (`id (`mp), `Value);
spec = (string)UI::QueryWidget (`id (`device), `Value);
mount_type = (string)UI::QueryWidget (`id (`fs), `Value);
}
UI::CloseDialog ();
}
/*
message = sformat (_("The partition %1 could not be mounted.\n
Check the log file %2.
"), spec, Directory::logdir + "/y2log");
success = false;
ret_bool = true;*/
}
}
}
} // allowed_fs
else if (vfstype == "swap" && fspath == "swap" )
{
y2milestone("mounting %1 to %2", spec, fspath);
if ( !Mode::test () )
{
string command = "/sbin/swapon ";
if ( spec != "" )
{
// swap-partition
command = command + spec;
// run /sbin/swapon
integer ret_from_shell = (integer) SCR::Execute (.target.bash, command);
if ( ret_from_shell != 0 )
{
y2error("swapon failed: %1", command );
}
else
{
AddMountedPartition ($[`type : "swap", `device : spec]);
}
}
}
}
});
return success;
}
/**
* Mount /var partition
* @param device string device holding the /var subtree
* @return string nil on success, error description on fail
*/
string MountVarPartition (string device) {
string mount_err = FsckAndMount ("/var", device, "");
string err_message = nil;
if (mount_err != nil)
{
y2error ("failed to mount /var");
err_message = sformat (
// error message
_("The /var partition %1 could not be mounted.\n"),
device) + "\n" + mount_err + "\n\n" + sdb;
}
return err_message;
}
/**
* Check if /var partition is needed, mount it if it is
* @param fstab a list of fstab entries
* @param root_device_current string current root device
* @return string nil on success, error description on fail
*/
define string MountVarIfRequired (list <map> fstab, string root_device_current)
{
string var_device_fstab = FindPartitionInFstab (fstab, "/var");
if (var_device_fstab == nil)
return nil;
if (!Storage::DeviceRealDisk (var_device_fstab))
return MountVarPartition (var_device_fstab);
list <map> tmp1 = filter (map entry, fstab, ``(entry["file"]:"" == "/"));
string root_device_fstab = tmp1[0,"spec"]:"";
if (!Storage::DeviceRealDisk (root_device_fstab))
return MountVarPartition (var_device_fstab);
map root_info = Storage::GetDiskPartition (root_device_fstab);
map var_info = Storage::GetDiskPartition (var_device_fstab);
if (root_info["disk"]:"" == var_info["disk"]:"")
{
map tmp2 = Storage::GetDiskPartition (root_device_current);
string var_partition_current = Storage::GetDeviceName (tmp2["disk"]:"", var_info["nr"]:0);
return MountVarPartition (var_partition_current);
}
list <string> realdisks = [];
foreach (string s, map m, (map <string, map>) Storage::GetOndiskTarget (), {
if (Storage::DeviceRealDisk (s))
realdisks = add (realdisks, s);
});
if (size (realdisks) != 2)
{
y2error ("don't know how to handle more than two disks at this point");
// error message
return _("Unable to mount /var partition with this disk configuration.\n") + sdb;
}
string other_disk = realdisks[ realdisks[0]:"" == root_info["disk"]:"" ? 1 : 0 ]:"";
string var_partition_current = Storage::GetDeviceName (other_disk, var_info["nr"]:0);
return MountVarPartition (var_partition_current);
}
/**
* Mounting root-partition; reading fstab and mounting read partitions
*/
global define boolean MountPartitions (string root_device_current)
{
y2milestone ("mount partitions: %1", root_device_current);
if (did_try_mount_partitions)
return true;
did_try_mount_partitions = true;
boolean success = true;
// popup message, %1 will be replace with the name of the logfile
string message = sformat (_("Partitions could not be mounted.\n
Check the log file %1."), Directory::logdir + "/y2log");
y2milestone ("selected partition: %1", root_device_current);
boolean ret_bool = true;
list <map> fstab = [];
list <map> crtab = [];
// Mount selected root partition to Installation::destdir
if ( !Mode::test () )
{
ret_bool = nil == FsckAndMount ("/", root_device_current, "");
}
if ( ret_bool )
{
// read the keyboard settings now, so that it used when
// typing passwords for encrypted partitions
Keyboard::CheckKeyboardDuringUpdate (Installation::destdir);
Update::GetProductName ();
read_fstab_and_cryptotab (fstab, crtab);
y2milestone ("fstab: %1", fstab);
y2milestone ("crtab: %1", crtab);
fstab = TranslateFSTab (fstab);
crtab = TranslateFSTab (crtab);
y2milestone ("fstab: %1", fstab);
y2milestone ("crtab: %1", crtab);
if (size (fstab) == 0)
{
y2error ("no or empty fstab found!");
// error message
message = _("No fstab found.");
success = false;
}
else
{
string tmp_msg = MountVarIfRequired (fstab, root_device_current);
if (tmp_msg != nil)
{
y2error ("failed to mount /var!");
message = tmp_msg;
success = false;
}
else
{
/* Removed, as fstab and crtab have been translated above
fstab = TranslateFSTab (fstab);
crtab = TranslateFSTab (crtab);
y2milestone ("fstab: %1", fstab);
y2milestone ("crtab: %1", crtab);
*/
string tmp = "";
if (!check_root_device (root_device_current, fstab, tmp))
{
y2error ("fstab has wrong root device!");
// message part 1
message = _("The root partition in /etc/fstab has an invalid root device.\n") +
// message part 2
sformat (_("It is currently mounted as %1 but listed as %2.\n"),
root_device_current, tmp) + sdb;
success = false;
}
else
{
y2milestone ("cryptotab %1", crtab);
PrepareCryptoTab (crtab, fstab);
y2milestone ("fstab %1", fstab);
if (!MountFSTab (fstab, message))
success = false;
}
}
}
}
else
{
y2error("Could not mount root '%1' to '%2'", root_device_current,
Installation::destdir);
success = false;
}
y2milestone ("MountPartition (%1) = %2", root_device_current, success);
y2milestone ("activated %1", activated);
if (!success)
{
Popup::Message(message);
// some mount failed, unmount all mounted fs
UnmountPartitions(false);
did_try_mount_partitions = true;
}
else
{
// enter the mount points of the newly mounted partitions
// in the target map of the storage module
AddToTargetMap ();
}
return success;
}
global define boolean SetFormatPartitions (list<map> fstabpart)
{
// All storage devices
map <string, map> target_map = Storage::GetTargetMap ();
// all activated
list <map> tmp = filter (map e, activated, {
return e[`type]:"" == "mount";
});
foreach (map e, tmp, {
string mntpt = e[`mntpt]:"";
string part = e[`device]:"";
map p = $[];
foreach (map pp, fstabpart, {
// mountpoint matches
if (pp["mount"]:"" == mntpt) {
p = pp;
break;
}
});
boolean format_partition = false;
if (p["format"]:nil != nil) {
format_partition = p["format"]:false;
}
target_map = Storage::SetPartitionData (target_map, part, "mount", mntpt );
target_map = Storage::SetPartitionData (target_map, part, "format", format_partition);
target_map = Storage::SetPartitionData (target_map, part, "delete", false);
target_map = Storage::SetPartitionData (target_map, part, "create", false);
});
Storage::SetTargetMap (target_map);
return true;
}
/**
* Get architecture of an elf file.
*/
define string GetArchOfELF (string filename)
{
map bash_out = (map) SCR::Execute (.target.bash_output, Directory::ybindir +
"/elf-arch " + filename);
if (bash_out["exit"]:1 != 0)
return "unknown";
return deletechars (bash_out["stdout"]:"unknown", "\n");
}
/**
* Check a root partition and return map with infomations (see
* variable rootPartitions).
*/
define map CheckPartition (map partition)
{
map freshman = $[
`valid : false,
`name : "unknown",
`arch : "unknown",
`label: partition["label"]:"",
`fs : partition["detected_fs"]:`unknown,
`fstype : partition["fstype"]:"unknown",
];
string p_dev = partition["device"]:"error";
integer p_fsid = partition["fsid"]:0;
symbol p_type = partition["type"]:`primary;
symbol p_detect_fs = partition["detected_fs"]:`unknown;
if ((p_fsid == 131 || p_type == `lvm || p_type == `sw_raid) &&
// possible root FS
contains (possible_root_fs, p_detect_fs))
{
map<symbol,string> mt_map = $[
`ext2: "ext2",
`ext3: "ext3",
`reiser: "reiserfs",
`xfs: "xfs",
`jfs: "jfs",
];
string mount_type = mt_map[p_detect_fs]:"";
string error_message = nil;
if (! RunFSCKonJFS (mount_type, p_dev, error_message)) {
freshman[`valid] = false;
// popup error, %1 is a device name /dev/hda5
Report::Error (sformat (_("File system check of the device %1 has failed."), p_dev));
return freshman;
}
if (mount_type != "")
SCR::Execute(.target.modprobe, mount_type, "" );
// mount (read-only) partition to Installation::destdir
if ((boolean) SCR::Execute (.target.mount, [p_dev, Installation::destdir,
Installation::mountlog], "-o ro"))
{
// Is this a root partition, does /etc/fstab exists?
if (SCR::Read (.target.size, Installation::destdir + "/etc/fstab") > 0)
{
y2milestone ("found fstab on %1", partition);
// Get installed release name
string release = SuSERelease::ReleaseInformation
(Installation::destdir);
y2debug("release: %1", release );
if (release == "?") {
// label for an unknown installed system
release = _("Unknown");
}
freshman[`name] = release;
// Right architecture?
freshman[`arch] = GetArchOfELF (Installation::destdir + "/bin/bash");
if (freshman[`arch]:"unknown" == GetArchOfELF ("/bin/bash"))
{
freshman[`valid] = true;
}
else
{
y2milestone ("Architecture for partition %1 is %2, upgrading %3", p_dev, freshman[`arch]:"unknown", GetArchOfELF ("/bin/bash"));
}
}
// unmount partition
SCR::Execute (.target.umount, Installation::destdir);
}
}
y2milestone ("%1 %2", partition, freshman);
return freshman;
}
/**
* Find all valid root partitions and place the result in rootPartitions.
* The partitions are mounted and unmounted again (to Installation::destdir).
* Loads a bunch of kernel modules.
* @return void
*/
global define void FindRootPartitions ()
{
if (didSearchForRootPartitions)
return;
ModuleLoading::Load ("reiserfs", "", "Linux", "Reiser FS", Linuxrc::manual (), true);
ModuleLoading::Load ("jfs", "", "Linux", "JFS", Linuxrc::manual (), true);
ModuleLoading::Load ("xfs", "", "Linux", "XFS", Linuxrc::manual (), true);
ModuleLoading::Load ("ext3", "", "Linux", "Ext3", Linuxrc::manual (), true);
ModuleLoading::Load ("raid0", "", "Linux", "Raid 0", Linuxrc::manual (), true);
ModuleLoading::Load ("raid1", "", "Linux", "Raid 1", Linuxrc::manual (), true);
ModuleLoading::Load ("raid5", "", "Linux", "Raid 5", Linuxrc::manual (), true);
ModuleLoading::Load ("multipath", "", "Linux", "Multipath", Linuxrc::manual (), true);
ModuleLoading::Load ("dm-mod", "", "Linux", "DM", Linuxrc::manual (), true);
SCR::Execute (.target.bash, "/sbin/devmap_mknod.sh");
ModuleLoading::Load ("dm-snapshot", "", "Linux", "DM", Linuxrc::manual (), true);
if (Mode::test ())
{
Storage::SetTargetMap ((map<string,map>) SCR::Read (.target.yast2, "test_target_map.ycp"));
}
map <string, map> target_map = (map <string, map>) Storage::GetOndiskTarget ();
y2milestone ("target_map: %1", target_map);
// target_map = (map <string, map>) Storage::GetTargetMap ();
// y2milestone ("target_map: %1", target_map);
rootPartitions = $[];
numberOfValidRootPartitions = 0;
foreach (string device, map description, target_map, {
foreach (map partition, description["partitions"]:[], {
// some partitions don't make sense at all
if (partition["detected_fs"]:`unknown != `swap &&
partition["type"]:`primary != `extended)
{
map freshman = $[];
if (Mode::test ())
freshman = $[`valid : true, `name : "SuSE Linux 4.2", `arch : "i286", `label: "Label" ];
else
freshman = CheckPartition (partition);
rootPartitions = add (rootPartitions, partition["device"]:"error", freshman);
if (freshman[`valid]:false)
numberOfValidRootPartitions = numberOfValidRootPartitions + 1;
}
});
});
didSearchForRootPartitions = true;
y2milestone ("rootPartitions: %1", rootPartitions);
}
global string GetDistroArch () {
return GetArchOfELF ("/bin/bash");
}
global boolean mount_target ()
{
UI::OpenDialog (`opt(`decorated ),
// intermediate popup while mounting partitions
`Label(_("Mounting partitions. One moment please...")));
boolean tmp = RootPart::MountPartitions (RootPart::selectedRootPartition);
sleep (500);
UI::CloseDialog ();
return tmp;
}
global void Detect () {
if (!didSearchForRootPartitions)
{
UI::OpenDialog (`opt(`decorated ),
// label
`Label(_("Evaluating root partition. One moment please...")));
FindRootPartitions ();
UI::CloseDialog ();
selectedRootPartition = "";
y2milestone ("Detected root partitions: %1", rootPartitions);
}
}
global void Propose (boolean force_reset) {
y2milestone ("Proposing root partition");
Detect ();
if (force_reset)
{
selectedRootPartition = "";
}
if (numberOfValidRootPartitions == 0
&& selectedRootPartition == "")
{
targetOk = false;
}
else
{
if (selectedRootPartition == "")
{
SetSelectedToValid ();
}
}
}
}