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 >
Text File  |  2006-11-29  |  35KB  |  1,277 lines

  1. /**
  2.  * Module:    RootPart.ycp
  3.  *
  4.  * Authors:    Arvin Schnell <arvin@suse.de>
  5.  *
  6.  * Purpose:    Responsible for searching of root partitions and
  7.  *        mounting of target partitions.
  8.  *
  9.  * $Id: RootPart.ycp 33392 2006-10-13 11:39:53Z locilka $
  10.  */
  11. {
  12.     module "RootPart";
  13.  
  14.     textdomain "update";
  15.  
  16.     import "Directory";
  17.     import "Mode";
  18.     import "Keyboard";
  19.     import "Linuxrc";
  20.     import "Storage";
  21.     import "Popup";
  22.     import "ModuleLoading";
  23.     import "FileSystems";
  24.     import "Update";
  25.     import "SuSERelease";
  26.     import "FileUtils";
  27.  
  28.     include "partitioning/partition_defines.ycp";
  29.     include "partitioning/custom_part_helptexts.ycp";
  30.     include "partitioning/custom_part_dialogs.ycp";
  31.  
  32.     // all supported filesystems
  33.     global list possible_root_fs = [ `ext2, `ext3, `reiser, `xfs, `jfs ];
  34.  
  35.     // Selected root partition for the update or boot.
  36.     global string selectedRootPartition = "";
  37.  
  38.     // Map of all root partitions (key) and information map (value).
  39.     // The information map contains the keys `valid, `name and `arch.
  40.     global map<string,map> rootPartitions = $[];
  41.  
  42.     // Number of valid root partitions.
  43.     global integer numberOfValidRootPartitions = 0;
  44.  
  45.     // Show all partitions (not only root partitions) in the dialog.
  46.     global boolean showAllPartitions = false;
  47.  
  48.     // Did we search for root partitions
  49.     global boolean didSearchForRootPartitions = false;
  50.  
  51.     // We successfully mounted the target partitions
  52.     global boolean targetOk = false;
  53.  
  54.     // Did we try to mount the target partitions?
  55.     global boolean did_try_mount_partitions = false;
  56.     
  57.     list <string> already_checked_jfs_partitions = [];
  58.  
  59.  
  60.     /**
  61.      * List of mounted partitions, activated swap partitions and loop devices.
  62.      * Amongst other things used for reversing action if mode is changed from
  63.      * update to new installation or if root partition for update is changed.
  64.      * The order of the list if of paramount importance.
  65.      *
  66.      * Each item is list [string value, string type [, string device]] where:
  67.      *
  68.      * Keys/values are:
  69.      *
  70.      *   `type     The type, one of "mount", "swap" or "loop".
  71.      *
  72.      *   `device   The device.
  73.      *
  74.      *   `mntpt    The mount point, only for `type = "mount".  Does not
  75.      *             include Installation::destdir.
  76.      */
  77.     list <map <symbol, string> > activated = [];
  78.  
  79.     global boolean Mounted () {
  80.     return size (activated) > 0;
  81.     }
  82.  
  83.  
  84.     /**
  85.      *  Link to SDB article concerning renaming of devices.
  86.      */
  87.     string sdb = sformat (_("See the SBD article at %1 for details
  88. about how to solve this problem."),
  89. "http://support.novell.com/techcenter/sdb/en/2003/03/fhassel_update_not_possible.html");
  90.  
  91.  
  92.     /**
  93.      * Get the key what of the selected root partition.
  94.      */
  95.     global define string GetInfoOfSelected (symbol what)
  96.     {
  97.     map i = rootPartitions[selectedRootPartition]:$[];
  98.  
  99.     if (what == `name) {
  100.         // Name is known
  101.         if (i[what]:"" != "") {
  102.         return i[what]:"";
  103.  
  104.         // Linux partition, but no root FS found
  105.         } else if (contains (possible_root_fs, i[`fs]:`nil)) {
  106.         // label - name of sustem to update
  107.         return _("Unknown Linux System");
  108.  
  109.         // Non-Linux
  110.         } else {
  111.         // label - name of sustem to update
  112.         return _("Non-Linux System");
  113.         }
  114.     } else {
  115.         // label - name of sustem to update
  116.         return i[what]:_("Unknown");
  117.     }
  118.     }
  119.  
  120.  
  121.     /**
  122.      * Set the selected root partition to some valid one. Only
  123.      * make sense if the number of valid root partition is one.
  124.      */
  125.     global define void SetSelectedToValid ()
  126.     {
  127.     selectedRootPartition = "";
  128.     foreach (string p, map i, rootPartitions, {
  129.         if (i[`valid]:false && selectedRootPartition == "")
  130.         selectedRootPartition = p;
  131.     });
  132.     }
  133.  
  134.  
  135.     /**
  136.      *
  137.      */
  138.     define void AddToTargetMap ()
  139.     {
  140.     map <string, map> target_map = (map <string, map>) Storage::GetOndiskTarget ();
  141.     y2milestone ("On disk target map: %1", target_map);
  142.     list <map> tmp = filter (map e, activated, ``(e[`type]:"" == "mount"));
  143.     foreach (map e, tmp, {
  144.         y2milestone ("Setting partition data: Device: %1, MountPoint: %2",
  145.         e[`device]:"", e[`mntpt]:"");
  146.         target_map = Storage::SetPartitionData (target_map, e[`device]:"",
  147.                             "mount", e[`mntpt]:"");
  148.     });
  149.     tmp = filter (map e, activated, ``(e[`type]:"" == "swap"));
  150.     foreach (map e, tmp, {
  151.         y2milestone ("Setting swap partition data: Device: %1",
  152.         e[`device]:"");
  153.         target_map = Storage::SetPartitionData (target_map, e[`device]:"",
  154.                             "mount", "swap");
  155.     });
  156.     y2milestone ("Setting target map: %1", target_map);
  157.     Storage::SetTargetMap (target_map);
  158.     }
  159.  
  160.  
  161.     /**
  162.      *
  163.      */
  164.     define void RemoveFromTargetMap ()
  165.     {
  166.     map <string, map> target_map = Storage::GetTargetMap ();
  167.     list <map> tmp = filter (map e, activated, ``(e[`type]:"" == "mount"));
  168.     foreach (map e, tmp, {
  169.         target_map = Storage::SetPartitionData (target_map, e[`device]:"",
  170.                             "mount", "");
  171.     });
  172.     Storage::SetTargetMap (target_map);
  173.     }
  174.  
  175.     /**
  176.      * Unmount all mounted partitions, deactivate swaps, detach loopback
  177.      * devices. Uses list activated to make actions in reverse order.
  178.      * @param keeep_in_target Do not remove mounts from targetmap
  179.      * @return void
  180.      */
  181.     global define void UnmountPartitions (boolean keep_in_target)
  182.     {
  183.     y2milestone ("UnmountPartitions: %1", keep_in_target);
  184.  
  185.     did_try_mount_partitions = false;
  186.  
  187.     foreach (map info, activated, {
  188.         y2milestone ("Unmounting %1", info);
  189.         string type = info[`type]:"";
  190.  
  191.         if (type != "")
  192.         {
  193.         if (type == "mount")
  194.         {
  195.             string file = Installation::destdir + info[`mntpt]:"";
  196.             if (! (boolean)SCR::Execute (.target.umount, file))
  197.             {
  198.             // error report, %1 is device (eg. /dev/hda1)
  199.             Report::Error (sformat (_("Cannot unmount partition %1.
  200.  
  201. It is currently in use. If the partition stays mounted,
  202. the data may be lost. Unmount the partition manually
  203. or restart your computer.
  204. "), file));
  205.             }
  206.         }
  207.         else if (type == "swap")
  208.         {
  209.             string device = info[`device]:"";
  210.             // FIXME? is it safe?
  211.             if (SCR::Execute (.target.bash, "/sbin/swapoff " + device) != 0)
  212.             {
  213.             y2error("Cannot deactivate swap %1", device);
  214.             }
  215.         }
  216.         else if (type == "loop")
  217.         {
  218.             string device = info[`device]:"";
  219.             // FIXME? is it safe?
  220.             if (WFM::Execute(.local.bash, "losetup -d " + device) != 0)
  221.             {
  222.             y2error("Cannot deactivate loopback device %1", device);
  223.             }
  224.         }
  225.         }
  226.     });
  227.  
  228.     // now remove the mount points of the mounted partitions
  229.     // in the target map of the storage module
  230.         if (!keep_in_target)
  231.         RemoveFromTargetMap ();
  232.  
  233.  
  234.     // clear activated list
  235.     activated = [];
  236.     }
  237.  
  238.  
  239.     /**
  240.      * Add information about mounted partition to internal list.
  241.      * @param partinfo partinfo has to be list with exactly two strings,
  242.      * see description of list "activated"
  243.      * @return void
  244.      */
  245.     define void AddMountedPartition (map <symbol, string> partinfo)
  246.     {
  247.     activated = prepend (activated, partinfo);
  248.     y2debug ("adding %1 yields %2", partinfo, activated);
  249.     }
  250.  
  251.  
  252.     /**
  253.      * Check the filesystem of a partition.
  254.      */
  255.     define void FSCKPartition (string partition)
  256.     {
  257.     if (!Mode::test ())
  258.     {
  259.         symbol detected_fs = Storage::DetectFs (partition);
  260.         if (detected_fs == `ext2)
  261.         {
  262.         // label, %1 is partition
  263.         string out = sformat (_("Checking partition %1"), partition);
  264.         UI::OpenDialog (`opt(`decorated ), `Label(out));
  265.  
  266.         y2milestone ("command: /sbin/e2fsck -y %1", partition);
  267.         SCR::Execute (.target.bash, "/sbin/e2fsck -y " + partition);
  268.  
  269.         UI::CloseDialog ();
  270.         }
  271.     }
  272.     }
  273.  
  274. /**
  275.  * Function checks the device and returns whether it is OK or not.
  276.  * The read-only FS check is performed for jfs only and only one for
  277.  * one device.
  278.  *
  279.  * @param string mount_type "jfs", "ext2" or "reiser"
  280.  * @param string device, such as /dev/hda3 or /dev/sda8
  281.  * @param string error_message (a reference to string)
  282.  * @return boolean if successfull or if user forces it
  283.  */
  284. define boolean RunFSCKonJFS (string mount_type, string device, string & error_message) {
  285.     // #176292, run fsck before jfs is mounted
  286.     if (mount_type == "jfs" && device != "") {
  287.  
  288.     if (contains (already_checked_jfs_partitions, device)) {
  289.         y2milestone ("Device %1 has been already checked...", device);
  290.         return true;
  291.     }
  292.  
  293.     UI::OpenDialog (`Label (sformat (_("Checking file system on %1..."), device)));
  294.  
  295.     y2milestone ("Running fsck on %1", device);
  296.     // -n == Check read only, make no changes to the file system.
  297.     map cmd = (map) SCR::Execute (.target.bash_output, sformat ("fsck.jfs -n %1", device));
  298.     
  299.     UI::CloseDialog();
  300.     
  301.     // failed
  302.     if (cmd["exit"]:nil != 0) {
  303.         y2error ("Result: %1", cmd);
  304.         error_message = tostring(cmd["stderr"]:nil);
  305.  
  306.         return Popup::ContinueCancel (sformat (
  307.         // popup question (continue/cancel dialog)
  308.         // %1 is a device name such as /dev/hda5
  309.         _("The file system check of device %1 has failed.
  310.  
  311. Would you like to continue in mounting the device?"),
  312.         device
  313.         ));
  314.     // succeeded
  315.     } else {
  316.         // add device into the list of already checked partitions (with exit status 0);
  317.         already_checked_jfs_partitions = add (already_checked_jfs_partitions, device);
  318.         y2milestone ("Result: %1", cmd);
  319.         return true;
  320.     }
  321.     }
  322.     
  323.     return true;
  324. }
  325.  
  326. /**
  327.  * Mount partition on specified mount point
  328.  * @param mount_point string mount point to monut the partition at
  329.  * @param device string device to mount
  330.  * @param mount_type string filesystem type to be specified while mounting
  331.  * @return string nil on success, error description on fail
  332.  */
  333. define string MountPartition (string mount_point, string device,
  334.     string mount_type)
  335. {
  336.     if (mount_type == "")
  337.     // e.g. -> "reiserfs"
  338.     mount_type = FileSystems::GetMountString (
  339.         Storage::DetectFs (device), "");
  340.  
  341.     list <string> non_modular_fs = [ "proc", "sysfs" ];
  342.  
  343.     // #211916, sysfs, proc are not modular
  344.     if (! contains (non_modular_fs, mount_type)) {
  345.     // #167976, was broken with "-t ", modprobe before adding it
  346.     y2milestone("Calling 'modprobe %1'", mount_type);
  347.     SCR::Execute(.target.modprobe, mount_type, "" );
  348.     } else {
  349.     y2milestone("FS type %1 is not modular, skipping modprobe...", mount_type);
  350.     }
  351.  
  352.     string error_message = nil;
  353.     if (! RunFSCKonJFS (mount_type, device, error_message)) {
  354.     return error_message;
  355.     }
  356.  
  357.     if (mount_type != "")
  358.     mount_type = "-t " + mount_type;
  359.  
  360.     boolean ret = (boolean) SCR::Execute (.target.mount,
  361.     [device, Installation::destdir + mount_point, Installation::mountlog],
  362.     mount_type );
  363.     if (ret)
  364.     return nil;
  365.     else
  366.     return (string)SCR::Read (.target.string, Installation::mountlog);
  367. }
  368.  
  369.  
  370.  
  371. /**
  372.  * Check filesystem on a partition and mount the partition on specified mount
  373.  *  point
  374.  * @param mount_point string mount point to monut the partition at
  375.  * @param device string device to mount
  376.  * @param mount_type string filesystem type to be specified while mounting
  377.  * @return string nil on success, error description on fail
  378.  */
  379. define string FsckAndMount (string mount_point, string device,
  380.     string mount_type)
  381. {
  382.     FSCKPartition (device);
  383.  
  384.     string ret = MountPartition (mount_point, device, mount_type);
  385.  
  386.     if (ret == nil)
  387.     AddMountedPartition($[`type : "mount", `device : device, `mntpt : mount_point]);
  388.  
  389.     y2milestone ("mounting (%1, %2, %3) yield %4", Installation::destdir +
  390.     mount_point, device, mount_type, ret);
  391.  
  392.     return ret;
  393. }
  394.  
  395.  
  396.     /**
  397.      *  Check that the root filesystem in fstab has the correct device.
  398.      */
  399.     define boolean check_root_device (string partition, list <map> fstab,
  400.                       string& found_partition)
  401.     {
  402.     list <map> tmp = filter (map entry, fstab, ``(entry["file"]:"" == "/"));
  403.  
  404.     if (size (tmp) != 1)
  405.     {
  406.         y2error ("not exactly one root partition found in fstab");
  407.         found_partition = "none";
  408.         return false;
  409.     }
  410.  
  411.     map root = tmp[0]:$[];
  412.  
  413.     if (!Storage::DeviceRealDisk (root["spec"]:""))
  414.     {
  415.         // There's nothing I can check.  Anyway, it's not mounted per device
  416.         // name so it can't be wrong, in theory.
  417.         return true;
  418.     }
  419.  
  420.     if (root["spec"]:"" != partition)
  421.     {
  422.         y2error ("root partition in fstab has wrong device");
  423.         found_partition = root["spec"]:"";
  424.         return false;
  425.     }
  426.  
  427.     return true;
  428.     }
  429.  
  430. /**
  431.  * Find a monut poing in fstab
  432.  * @param fstab a list of fstab entries
  433.  * @param mountpoint string a mount point to find
  434.  * @return string the found partition
  435.  */
  436. define string FindPartitionInFstab (list<map> fstab, string mountpoint) {
  437.     if (substring (mountpoint, size (mountpoint) - 1, 1) == "/")
  438.     mountpoint = substring (mountpoint, 0, size (mountpoint) - 1);
  439.  
  440.     list <map> tmp = filter (map entry, fstab, {
  441.     return entry["file"]:"" == mountpoint
  442.         || entry["file"]:"" == mountpoint + "/";
  443.     });
  444.  
  445.     if (size (tmp) == 0)
  446.     return nil;
  447.  
  448.     return tmp[0,"spec"]:"";
  449. }
  450.  
  451.     /**
  452.      *
  453.      */
  454.     define list <map> TranslateFSTab (list <map> fstab)
  455.     {
  456.     list <string> old_names = [];
  457.     foreach (map m, fstab, {
  458.         old_names = add (old_names, m["spec"]:"");
  459.     });
  460.  
  461.     list <string> new_names = Storage::GetTranslatedDevices (
  462.         Update::installedVersion, Update::updateVersion,
  463.         old_names);
  464.  
  465.     integer i = 0;
  466.     while (i < size (fstab))
  467.     {
  468.         string spec = fstab[i,"spec"]:"";
  469.         fstab[i,"spec"] = new_names[i]:spec;
  470.         i = i + 1;
  471.     };
  472.  
  473.     return fstab;
  474.     }
  475.  
  476.     /**
  477.      * Register a new fstab agent and read the configuration
  478.      * from Installation::destdir
  479.      */
  480.     void readFsTab (list <map> & fstab) {
  481.         string fstab_file = Installation::destdir + "/etc/fstab";
  482.  
  483.         if (FileUtils::Exists (fstab_file)) {
  484.         SCR::RegisterAgent (.target.etc.fstab, `ag_anyagent(
  485.           `Description (
  486.               (`File(fstab_file)),
  487.               "#\n",                    // Comment
  488.               false,                    // read-only
  489.               (`List (
  490.                 `Tuple (
  491.                   `spec (`String("^\t ")),
  492.                   `Separator ("\t "),
  493.                   `file (`String("^\t ")),
  494.                   `Separator ("\t "),
  495.                   `vfstype (`String("^\t ")),
  496.                   `Separator ("\t "),
  497.                   `mntops (`String("^ \t\n")),
  498.                   `Optional(`Whitespace()),
  499.                   `Optional(`freq (`Number())),
  500.                   `Optional(`Whitespace()),
  501.                   `Optional(`passno (`Number()))
  502.                 ),
  503.                 "\n"
  504.               ))
  505.             )
  506.         ));
  507.  
  508.         fstab = (list<map>) SCR::Read (.target.etc.fstab);
  509.         
  510.         SCR::UnregisterAgent (.target.etc.fstab);
  511.         } else {
  512.         y2error ("No such file %1. Not using fstab.", fstab_file);
  513.         }
  514.     }
  515.     
  516.     /**
  517.      * Register a new cryptotab agent and read the configuration
  518.      * from Installation::destdir
  519.      */
  520.     void readCryptoTab (list <map> & crtab) {
  521.         string crtab_file = Installation::destdir + "/etc/cryptotab";
  522.  
  523.         if (FileUtils::Exists (crtab_file)) {
  524.         SCR::RegisterAgent (.target.etc.cryptotab, `ag_anyagent(
  525.           `Description (
  526.               (`File(crtab_file)),
  527.               "#\n",            // Comment
  528.               false,            // read-only
  529.               (`List (
  530.             `Tuple (
  531.               `loop (`String("^\t ")),
  532.               `Separator ("\t "),
  533.               `file (`String("^\t ")),
  534.               `Separator ("\t "),
  535.               `mount (`String("^\t ")),
  536.                   `Separator ("\t "),
  537.               `vfstype (`String("^\t ")),
  538.               `Separator ("\t "),
  539.               `opt1 (`String("^\t ")),
  540.               `Separator ("\t "),
  541.               `opt2 (`String("^ \t\n"))
  542.             ),
  543.             "\n"
  544.               ))
  545.             )
  546.         ));
  547.         
  548.         crtab = (list<map>) SCR::Read (.target.etc.cryptotab);
  549.         
  550.         SCR::UnregisterAgent (.target.etc.cryptotab);
  551.         } else {
  552.         y2warning ("No such file %1. Not using cryptotab.", crtab_file);
  553.         }
  554.     }
  555.  
  556.     /**
  557.      *
  558.      */
  559.     define boolean read_fstab_and_cryptotab (list <map>& fstab, list <map>& crtab)
  560.     {
  561.     integer default_scr = WFM::SCRGetDefault ();
  562.     integer new_scr = nil;
  563.     if (Stage::initial ())
  564.     {
  565.         readFsTab (fstab);
  566.         readCryptoTab (crtab);
  567.     }
  568.     else
  569.     {
  570.         fstab = (list<map>) SCR::Read (.etc.fstab);
  571.         crtab = (list<map>) SCR::Read (.etc.cryptotab);
  572.     }
  573.  
  574.     return true;
  575.     }
  576.  
  577.  
  578.     /**
  579.      *
  580.      */
  581.     define boolean PrepareCryptoTab (list <map> crtab, list <map>& fstab)
  582.     {
  583.     integer crypt_nb = 0;
  584.  
  585.     foreach (map mounts, crtab, {
  586.  
  587.         string vfstype = mounts["vfstype"]:"";
  588.         string mntops  = mounts["opt2"]:"";
  589.         string loop    = mounts["loop"]:"";
  590.         string fspath  = mounts["mount"]:"";
  591.         string device  = mounts["file"]:"";
  592.  
  593.         y2milestone ("vfstype:%1 mntops:%2 loop:%3 fspath:%4 device:%5",
  594.              vfstype, mntops, loop, fspath, device);
  595.  
  596.         if (!issubstring (mntops, "noauto"))
  597.         {
  598.           boolean again = true;
  599.           while (again)
  600.           {
  601.         boolean crypt_ok = true;
  602.         string crypt_passwd = DlgUpdateCryptFs( device, fspath );
  603.  
  604.         if (crypt_passwd == nil || crypt_passwd == "")
  605.         {
  606.             crypt_ok = false;
  607.             again = false;
  608.         }
  609.  
  610.         y2milestone ("crypt pwd ok:%1", crypt_ok);
  611.  
  612.         if (crypt_ok)
  613.         {
  614.             map setloop = $[ "encryption"    : "twofish",
  615.                      "passwd"        : crypt_passwd,
  616.                      "loop_dev"      : loop,
  617.                      "partitionName" : device ];
  618.  
  619.             crypt_ok = Storage::PerformLosetup( setloop, false );
  620.             y2milestone ("crypt ok: %1", crypt_ok);
  621.             if( crypt_ok )
  622.             loop = setloop["loop_dev"]:"";
  623.             else
  624.             {
  625.             // yes-no popup
  626.             again = Popup::YesNo (_("Incorrect password. Try again?"));
  627.             }
  628.         }
  629.  
  630.         if (crypt_ok)
  631.         {
  632.             map add_fs = $[ "file" : fspath,
  633.                     "mntops" : mntops,
  634.                     "spec" : loop,
  635.                     "freq" : 0,
  636.                     "passno" : 0,
  637.                     "vfstype": vfstype ];
  638.             fstab = prepend (fstab, add_fs);
  639.             AddMountedPartition ($[`type : "loop", `device : device]);
  640.             again = false;
  641.         }
  642.           }
  643.         }
  644.  
  645.     });
  646.  
  647.     return true;
  648.     }
  649.  
  650.  
  651. /**
  652.  * Check if specified mount point is mounted
  653.  * @param mountpoint the mount point to be checked
  654.  * @return boolean true if it is mounted
  655.  */
  656. define boolean IsMounted (string mountpoint) {
  657.     if (substring (mountpoint, size (mountpoint) - 1, 1) == "/")
  658.     mountpoint = substring (mountpoint, 0, size (mountpoint) - 1);
  659.  
  660.     boolean ret = true;
  661.     foreach (map e, activated, {
  662.     if (e[`type]:"" == "mount"
  663.         && (e[`mntpt]:"" == mountpoint
  664.         || e[`mntpt]:"" == mountpoint + "/"))
  665.     {
  666.         ret = true;
  667.     }
  668.     });
  669.     return ret;
  670. }
  671.  
  672.     /**
  673.      *
  674.      */
  675.     define boolean MountFSTab (list <map> fstab, string& message)
  676.     {
  677.     list allowed_fs = [ "ext", "ext2", "ext3", "minix", "reiserfs", "jfs",
  678.                 "xfs", "xiafs", "hpfs", "vfat", "auto", "proc" ];
  679.  
  680.     // mount sysfs first
  681.     string ret = MountPartition ("/sys", "sysfs", "sysfs");
  682.  
  683.     if (ret == nil)
  684.         AddMountedPartition($[`type : "mount", `device : "sysfs", `mntpt : "/sys"]);
  685.  
  686.  
  687.     boolean success = true;
  688.  
  689.     boolean raidMounted = false;
  690.  
  691.     foreach (map mounts, fstab, {
  692.  
  693.         string vfstype = mounts["vfstype"]:"";
  694.         string mntops  = mounts["mntops"]:"";
  695.         string spec    = mounts["spec"]:"";
  696.         string fspath  = mounts["file"]:"";
  697.  
  698.         if (contains (allowed_fs, vfstype)
  699.         && fspath != "/" && (fspath != "/var" || ! IsMounted("/var"))
  700.         && !issubstring (mntops,"noauto"))
  701.         {
  702.         y2milestone ("mounting %1 to %2", spec, fspath);
  703.  
  704.         if ( !Mode::test () )
  705.         {
  706.             string mount_type = "";
  707.             if (vfstype == "proc")
  708.             {
  709.             mount_type = vfstype;
  710.             }
  711.  
  712.             string mount_err = "";
  713.             while (mount_err != nil)
  714.             {
  715.             mount_err = FsckAndMount (fspath, spec, mount_type);
  716.             if (mount_err != nil)
  717.             {
  718.                 y2error("mounting %1 (type %2) on %3 failed", spec,
  719.                 mount_type, Installation::destdir + fspath);
  720.                 UI::OpenDialog (`VBox (
  721.                 `Label (sformat (
  722.                     // label in a popup, %1 is device (eg. /dev/hda1), %2 is output of the 'mount' command
  723.                     _("The partition %1 could not be mounted.
  724.  
  725. %2
  726.  
  727. If you are sure that the partition is not necessary for the
  728. update (it is not any system partition), click Continue.
  729. To check or fix the mount options, click Specify Mount Options.
  730. To abort update, click Cancel."),
  731.                     spec, mount_err)
  732.                 ),
  733.                 `VSpacing (1),
  734.                 `HBox (
  735.                     `PushButton (`id (`cont), Label::ContinueButton ()),
  736.                     // push button
  737.                     `PushButton (`id (`cmd), _("&Specify Mount Options")),
  738.                     `PushButton (`id (`cancel), Label::CancelButton ())
  739.                 )
  740.                 ));
  741.                 symbol act = (symbol)UI::UserInput ();
  742.                 UI::CloseDialog ();
  743.                 if (act == `cancel)
  744.                 {
  745.                 mount_err = nil;
  746.                 success = false;
  747.                 }
  748.                 else if (act == `cont)
  749.                 {
  750.                 mount_err = nil;
  751.                 }
  752.                 else if (act == `cmd)
  753.                 {
  754.                 UI::OpenDialog (`VBox (
  755.                     // popup heading
  756.                     `Heading (_("Mount Options")),
  757.                     `VSpacing (0.6),
  758.                     // text entry label
  759.                     `TextEntry (`id (`mp), _("&Mount Point"), fspath),
  760.                     `VSpacing (0.4),
  761.                     // tex entry label
  762.                     `TextEntry (`id (`device), _("&Device"), spec),
  763.                     `VSpacing (0.4),
  764.                     // text entry label
  765.                     `TextEntry (`id (`fs), _("&File System\n(empty for autodetection)"), mount_type),
  766.                     `VSpacing (1),
  767.                     `HBox (
  768.  
  769.                     `PushButton (`id (`ok), Label::OKButton ()),
  770.                     `PushButton (`id (`cancel), Label::CancelButton ())
  771.                     )
  772.                 ));
  773.                 act = (symbol)UI::UserInput ();
  774.                 if (act == `ok)
  775.                 {
  776.                     fspath = (string)UI::QueryWidget (`id (`mp), `Value);
  777.                     spec = (string)UI::QueryWidget (`id (`device), `Value);
  778.                     mount_type = (string)UI::QueryWidget (`id (`fs), `Value);
  779.                 }
  780.                 UI::CloseDialog ();
  781.                 }
  782. /*
  783.                 message = sformat (_("The partition %1 could not be mounted.\n
  784. Check the log file %2.
  785. "), spec, Directory::logdir + "/y2log");
  786.                 success = false;
  787.                 ret_bool = true;*/
  788.             }
  789.             }
  790.         }
  791.         }  // allowed_fs
  792.         else if (vfstype == "swap" && fspath == "swap" )
  793.         {
  794.         y2milestone("mounting %1 to %2", spec, fspath);
  795.  
  796.         if ( !Mode::test () )
  797.         {
  798.             string command = "/sbin/swapon ";
  799.             if ( spec != "" )
  800.             {
  801.             // swap-partition
  802.             command = command + spec;
  803.  
  804.             // run /sbin/swapon
  805.             integer ret_from_shell = (integer) SCR::Execute (.target.bash, command);
  806.             if ( ret_from_shell != 0 )
  807.             {
  808.                 y2error("swapon failed: %1", command );
  809.             }
  810.             else
  811.             {
  812.                 AddMountedPartition ($[`type : "swap", `device : spec]);
  813.             }
  814.             }
  815.         }
  816.         }
  817.     });
  818.  
  819.     return success;
  820.     }
  821.  
  822. /**
  823.  * Mount /var partition
  824.  * @param device string device holding the /var subtree
  825.  * @return string nil on success, error description on fail
  826.  */
  827. string MountVarPartition (string device) {
  828.     string mount_err = FsckAndMount ("/var", device, "");
  829.     string err_message = nil;
  830.     if (mount_err != nil)
  831.     {
  832.     y2error ("failed to mount /var");
  833.     err_message = sformat (
  834.         // error message
  835.         _("The /var partition %1 could not be mounted.\n"),
  836.         device) + "\n" + mount_err + "\n\n" + sdb;
  837.     }
  838.     return err_message;
  839. }
  840.  
  841. /**
  842.  * Check if /var partition is needed, mount it if it is
  843.  * @param fstab a list of fstab entries
  844.  * @param root_device_current string current root device
  845.  * @return string nil on success, error description on fail
  846.  */
  847. define string MountVarIfRequired (list <map> fstab, string root_device_current)
  848. {
  849.     string var_device_fstab = FindPartitionInFstab (fstab, "/var");
  850.     if (var_device_fstab == nil)
  851.         return nil;
  852.  
  853.     if (!Storage::DeviceRealDisk (var_device_fstab))
  854.         return MountVarPartition (var_device_fstab);
  855.  
  856.     list <map> tmp1 = filter (map entry, fstab, ``(entry["file"]:"" == "/"));
  857.     string root_device_fstab = tmp1[0,"spec"]:"";
  858.     if (!Storage::DeviceRealDisk (root_device_fstab))
  859.         return MountVarPartition (var_device_fstab);
  860.  
  861.     map root_info = Storage::GetDiskPartition (root_device_fstab);
  862.     map var_info = Storage::GetDiskPartition (var_device_fstab);
  863.  
  864.     if (root_info["disk"]:"" == var_info["disk"]:"")
  865.     {
  866.         map tmp2 = Storage::GetDiskPartition (root_device_current);
  867.         string var_partition_current = Storage::GetDeviceName (tmp2["disk"]:"", var_info["nr"]:0);
  868.  
  869.         return MountVarPartition (var_partition_current);
  870.     }
  871.  
  872.     list <string> realdisks = [];
  873.     foreach (string s, map m, (map <string, map>) Storage::GetOndiskTarget (), {
  874.         if (Storage::DeviceRealDisk (s))
  875.         realdisks = add (realdisks, s);
  876.     });
  877.  
  878.     if (size (realdisks) != 2)
  879.     {
  880.         y2error ("don't know how to handle more than two disks at this point");
  881.         // error message
  882.         return _("Unable to mount /var partition with this disk configuration.\n") + sdb;
  883.     }
  884.  
  885.     string other_disk = realdisks[ realdisks[0]:"" == root_info["disk"]:"" ? 1 : 0 ]:"";
  886.     string var_partition_current = Storage::GetDeviceName (other_disk, var_info["nr"]:0);
  887.  
  888.     return MountVarPartition (var_partition_current);
  889. }
  890.  
  891.  
  892.     /**
  893.      * Mounting root-partition; reading fstab and mounting read partitions
  894.      */
  895.     global define boolean MountPartitions (string root_device_current)
  896.     {
  897.     y2milestone ("mount partitions: %1", root_device_current);
  898.  
  899.     if (did_try_mount_partitions)
  900.         return true;
  901.  
  902.     did_try_mount_partitions = true;
  903.  
  904.     boolean success = true;
  905.  
  906.     // popup message, %1 will be replace with the name of the logfile
  907.     string message =  sformat (_("Partitions could not be mounted.\n
  908. Check the log file %1."), Directory::logdir + "/y2log");
  909.     y2milestone ("selected partition: %1", root_device_current);
  910.  
  911.     boolean ret_bool = true;
  912.  
  913.     list <map> fstab = [];
  914.     list <map> crtab = [];
  915.  
  916.     // Mount selected root partition to Installation::destdir
  917.     if ( !Mode::test () )
  918.     {
  919.         ret_bool = nil == FsckAndMount ("/", root_device_current, "");
  920.     }
  921.  
  922.     if ( ret_bool )
  923.     {
  924.         // read the keyboard settings now, so that it used when
  925.         // typing passwords for encrypted partitions
  926.         Keyboard::CheckKeyboardDuringUpdate (Installation::destdir);
  927.  
  928.         Update::GetProductName ();
  929.  
  930.         read_fstab_and_cryptotab (fstab, crtab);
  931.  
  932.         y2milestone ("fstab: %1", fstab);
  933.         y2milestone ("crtab: %1", crtab);
  934.  
  935.         fstab = TranslateFSTab (fstab);
  936.         crtab = TranslateFSTab (crtab);
  937.  
  938.         y2milestone ("fstab: %1", fstab);
  939.         y2milestone ("crtab: %1", crtab);
  940.  
  941.         if (size (fstab) == 0)
  942.         {
  943.         y2error ("no or empty fstab found!");
  944.         // error message
  945.         message = _("No fstab found.");
  946.         success = false;
  947.         }
  948.         else
  949.         {
  950.         string tmp_msg = MountVarIfRequired (fstab, root_device_current);
  951.         if (tmp_msg != nil)
  952.         {
  953.             y2error ("failed to mount /var!");
  954.             message = tmp_msg;
  955.             success = false;
  956.         }
  957.         else
  958.         {
  959. /* Removed, as fstab and crtab have been translated above
  960.             fstab = TranslateFSTab (fstab);
  961.             crtab = TranslateFSTab (crtab);
  962.  
  963.             y2milestone ("fstab: %1", fstab);
  964.             y2milestone ("crtab: %1", crtab);
  965. */
  966.             string tmp = "";
  967.  
  968.             if (!check_root_device (root_device_current, fstab, tmp))
  969.             {
  970.             y2error ("fstab has wrong root device!");
  971.             // message part 1
  972.             message = _("The root partition in /etc/fstab has an invalid root device.\n") +
  973.             // message part 2
  974.                 sformat (_("It is currently mounted as %1 but listed as %2.\n"),
  975.                      root_device_current, tmp) + sdb;
  976.             success = false;
  977.             }
  978.             else
  979.             {
  980.             y2milestone ("cryptotab %1", crtab);
  981.  
  982.             PrepareCryptoTab (crtab, fstab);
  983.  
  984.             y2milestone ("fstab %1", fstab);
  985.  
  986.             if (!MountFSTab (fstab, message))
  987.                 success = false;
  988.             }
  989.         }
  990.         }
  991.     }
  992.     else
  993.     {
  994.         y2error("Could not mount root '%1' to '%2'", root_device_current,
  995.             Installation::destdir);
  996.         success = false;
  997.     }
  998.  
  999.     y2milestone ("MountPartition (%1) = %2", root_device_current, success);
  1000.     y2milestone ("activated %1", activated);
  1001.  
  1002.     if (!success)
  1003.     {
  1004.         Popup::Message(message);
  1005.  
  1006.         // some mount failed, unmount all mounted fs
  1007.         UnmountPartitions(false);
  1008.         did_try_mount_partitions = true;
  1009.     }
  1010.     else
  1011.     {
  1012.         // enter the mount points of the newly mounted partitions
  1013.         // in the target map of the storage module
  1014.         AddToTargetMap ();
  1015.     }
  1016.  
  1017.     return success;
  1018.     }
  1019.  
  1020.  
  1021.     global define boolean SetFormatPartitions (list<map> fstabpart)
  1022.     {
  1023.     // All storage devices
  1024.         map <string, map> target_map = Storage::GetTargetMap ();
  1025.  
  1026.     // all activated
  1027.     list <map> tmp = filter (map e, activated, {
  1028.         return e[`type]:"" == "mount";
  1029.     });
  1030.  
  1031.     foreach (map e, tmp, {
  1032.         string mntpt = e[`mntpt]:"";
  1033.         string part  = e[`device]:"";
  1034.  
  1035.         map p = $[];
  1036.         foreach (map pp, fstabpart, {
  1037.         // mountpoint matches
  1038.         if (pp["mount"]:"" == mntpt) {
  1039.             p = pp;
  1040.             break;
  1041.         }
  1042.         });
  1043.  
  1044.         boolean format_partition = false;
  1045.         if (p["format"]:nil != nil) {
  1046.         format_partition = p["format"]:false;
  1047.         }
  1048.         target_map = Storage::SetPartitionData (target_map, part, "mount", mntpt );
  1049.         target_map = Storage::SetPartitionData (target_map, part, "format", format_partition);
  1050.         target_map = Storage::SetPartitionData (target_map, part, "delete", false);
  1051.         target_map = Storage::SetPartitionData (target_map, part, "create", false);
  1052.     });
  1053.  
  1054.         Storage::SetTargetMap (target_map);
  1055.         return true;
  1056.     }
  1057.  
  1058.  
  1059.     /**
  1060.      * Get architecture of an elf file.
  1061.      */
  1062.     define string GetArchOfELF (string filename)
  1063.     {
  1064.     map bash_out = (map) SCR::Execute (.target.bash_output, Directory::ybindir +
  1065.                        "/elf-arch " + filename);
  1066.     if (bash_out["exit"]:1 != 0)
  1067.         return "unknown";
  1068.     return deletechars (bash_out["stdout"]:"unknown", "\n");
  1069.     }
  1070.  
  1071.  
  1072.     /**
  1073.      * Check a root partition and return map with infomations (see
  1074.      * variable rootPartitions).
  1075.      */
  1076.     define map CheckPartition (map partition)
  1077.     {
  1078.     map freshman = $[
  1079.         `valid : false,
  1080.         `name : "unknown",
  1081.         `arch : "unknown",
  1082.         `label: partition["label"]:"",
  1083.         `fs : partition["detected_fs"]:`unknown,
  1084.         `fstype : partition["fstype"]:"unknown",
  1085.     ];
  1086.  
  1087.     string p_dev = partition["device"]:"error";
  1088.     integer p_fsid = partition["fsid"]:0;
  1089.     symbol p_type = partition["type"]:`primary;
  1090.     symbol p_detect_fs = partition["detected_fs"]:`unknown;
  1091.  
  1092.     if ((p_fsid == 131 || p_type == `lvm || p_type == `sw_raid) &&
  1093.         // possible root FS
  1094.         contains (possible_root_fs, p_detect_fs))
  1095.     {
  1096.         map<symbol,string> mt_map = $[
  1097.         `ext2: "ext2",
  1098.         `ext3: "ext3",
  1099.         `reiser: "reiserfs",
  1100.         `xfs: "xfs",
  1101.         `jfs: "jfs",
  1102.         ];
  1103.         string mount_type = mt_map[p_detect_fs]:"";
  1104.  
  1105.         string error_message = nil;
  1106.         if (! RunFSCKonJFS (mount_type, p_dev, error_message)) {
  1107.         freshman[`valid] = false;
  1108.         // popup error, %1 is a device name /dev/hda5
  1109.         Report::Error (sformat (_("File system check of the device %1 has failed."), p_dev));
  1110.         return freshman;
  1111.         }
  1112.  
  1113.         if (mount_type != "")
  1114.         SCR::Execute(.target.modprobe, mount_type, "" );
  1115.         // mount (read-only) partition to Installation::destdir
  1116.         if ((boolean) SCR::Execute (.target.mount, [p_dev, Installation::destdir,
  1117.                             Installation::mountlog], "-o ro"))
  1118.         {
  1119.         // Is this a root partition, does /etc/fstab exists?
  1120.         if (SCR::Read (.target.size, Installation::destdir + "/etc/fstab") > 0)
  1121.         {
  1122.             y2milestone ("found fstab on %1", partition);
  1123.  
  1124.             // Get installed release name
  1125.             string release = SuSERelease::ReleaseInformation
  1126.             (Installation::destdir);
  1127.                     y2debug("release: %1", release );
  1128.             if (release == "?") {
  1129.             // label for an unknown installed system
  1130.             release = _("Unknown");
  1131.             }
  1132.             freshman[`name] = release;
  1133.  
  1134.             // Right architecture?
  1135.             freshman[`arch] = GetArchOfELF (Installation::destdir + "/bin/bash");
  1136.             if (freshman[`arch]:"unknown" == GetArchOfELF ("/bin/bash"))
  1137.             {
  1138.             freshman[`valid] = true;
  1139.             }
  1140.             else
  1141.             {
  1142.             y2milestone ("Architecture for partition %1 is %2, upgrading %3", p_dev, freshman[`arch]:"unknown", GetArchOfELF ("/bin/bash"));
  1143.             }
  1144.         }
  1145.  
  1146.         // unmount partition
  1147.         SCR::Execute (.target.umount, Installation::destdir);
  1148.         }
  1149.     }
  1150.  
  1151.     y2milestone ("%1 %2", partition, freshman);
  1152.  
  1153.     return freshman;
  1154.     }
  1155.  
  1156.  
  1157.     /**
  1158.      * Find all valid root partitions and place the result in rootPartitions.
  1159.      * The partitions are mounted and unmounted again (to Installation::destdir).
  1160.      * Loads a bunch of kernel modules.
  1161.      * @return void
  1162.      */
  1163.     global define void FindRootPartitions ()
  1164.     {
  1165.     if (didSearchForRootPartitions)
  1166.         return;
  1167.  
  1168.     ModuleLoading::Load ("reiserfs", "", "Linux", "Reiser FS", Linuxrc::manual (), true);
  1169.     ModuleLoading::Load ("jfs", "", "Linux", "JFS", Linuxrc::manual (), true);
  1170.     ModuleLoading::Load ("xfs", "", "Linux", "XFS", Linuxrc::manual (), true);
  1171.     ModuleLoading::Load ("ext3", "", "Linux", "Ext3", Linuxrc::manual (), true);
  1172.     ModuleLoading::Load ("raid0", "", "Linux", "Raid 0", Linuxrc::manual (), true);
  1173.     ModuleLoading::Load ("raid1", "", "Linux", "Raid 1", Linuxrc::manual (), true);
  1174.     ModuleLoading::Load ("raid5", "", "Linux", "Raid 5", Linuxrc::manual (), true);
  1175.     ModuleLoading::Load ("multipath", "", "Linux", "Multipath", Linuxrc::manual (), true);
  1176.     ModuleLoading::Load ("dm-mod", "", "Linux", "DM", Linuxrc::manual (), true);
  1177.     SCR::Execute (.target.bash, "/sbin/devmap_mknod.sh");
  1178.     ModuleLoading::Load ("dm-snapshot", "", "Linux", "DM", Linuxrc::manual (), true);
  1179.  
  1180.     if (Mode::test ())
  1181.     {
  1182.         Storage::SetTargetMap ((map<string,map>) SCR::Read (.target.yast2, "test_target_map.ycp"));
  1183.     }
  1184.  
  1185.     map <string, map> target_map = (map <string, map>) Storage::GetOndiskTarget ();
  1186.     y2milestone ("target_map: %1", target_map);
  1187. //    target_map = (map <string, map>) Storage::GetTargetMap ();
  1188. //    y2milestone ("target_map: %1", target_map);
  1189.  
  1190.     rootPartitions = $[];
  1191.     numberOfValidRootPartitions = 0;
  1192.  
  1193.     foreach (string device, map description, target_map, {
  1194.         foreach (map partition, description["partitions"]:[], {
  1195.  
  1196.         // some partitions don't make sense at all
  1197.         if (partition["detected_fs"]:`unknown != `swap &&
  1198.             partition["type"]:`primary != `extended)
  1199.         {
  1200.             map freshman = $[];
  1201.  
  1202.             if (Mode::test ())
  1203.             freshman = $[`valid : true, `name : "SuSE Linux 4.2", `arch : "i286", `label: "Label" ];
  1204.             else
  1205.             freshman = CheckPartition (partition);
  1206.  
  1207.             rootPartitions = add (rootPartitions, partition["device"]:"error", freshman);
  1208.  
  1209.             if (freshman[`valid]:false)
  1210.             numberOfValidRootPartitions = numberOfValidRootPartitions + 1;
  1211.         }
  1212.         });
  1213.     });
  1214.  
  1215.     didSearchForRootPartitions = true;
  1216.  
  1217.     y2milestone ("rootPartitions: %1", rootPartitions);
  1218.     }
  1219.  
  1220. global string GetDistroArch () {
  1221.     return GetArchOfELF ("/bin/bash");
  1222. }
  1223.  
  1224.     global boolean mount_target ()
  1225.     {
  1226.         UI::OpenDialog (`opt(`decorated ),
  1227.                         // intermediate popup while mounting partitions
  1228.                         `Label(_("Mounting partitions. One moment please...")));
  1229.  
  1230.         boolean tmp = RootPart::MountPartitions (RootPart::selectedRootPartition);
  1231.         sleep (500);
  1232.  
  1233.         UI::CloseDialog ();
  1234.  
  1235.         return tmp;
  1236.     }
  1237.  
  1238. global void Detect () {
  1239.     if (!didSearchForRootPartitions)
  1240.     {
  1241.         UI::OpenDialog (`opt(`decorated ),
  1242.                         // label
  1243.                         `Label(_("Evaluating root partition. One moment please...")));
  1244.  
  1245.         FindRootPartitions ();
  1246.  
  1247.         UI::CloseDialog ();
  1248.  
  1249.         selectedRootPartition = "";
  1250.     y2milestone ("Detected root partitions: %1", rootPartitions);
  1251.     }
  1252. }
  1253.  
  1254. global void Propose (boolean force_reset) {
  1255.     y2milestone ("Proposing root partition");
  1256.     Detect ();
  1257.     if (force_reset)
  1258.     {
  1259.         selectedRootPartition = "";
  1260.     }
  1261.  
  1262.     if (numberOfValidRootPartitions == 0
  1263.         && selectedRootPartition == "")
  1264.     {
  1265.         targetOk = false;
  1266.     }
  1267.     else
  1268.     {
  1269.         if (selectedRootPartition == "")
  1270.         {
  1271.             SetSelectedToValid ();
  1272.         }
  1273.     }
  1274. }
  1275.  
  1276. }
  1277.