/**
 * File:
 *   osr_module_partition.ycp
 *
 * Module:
 *   Partition and filesystems checking module.
 *
 * Summary:
 *   YaST2 OS Repair. Automatic error detection & repair tool for Linux.
 *
 * Author:
 *   Johannes Buchhold <jbuch@suse.de>
 *
 * $Id: osr_module_partition.ycp 22045 2005-03-01 10:13:50Z jsuchome $
 */

{
  import "FileSystems";
  import "Label";
  import "Mode";
  import "OSR";
  import "OSRCommon";
  import "OSRProgress";
  import "OSRSummary";
  import "OSRSystem";
  import "OSRStatus";
  import "OSRExecute";
  import "OSRPtbl";
  import "OSRSwap";
  import "OSRFsck";
  import "OSRFstab";
  import "OSRPopup";
  import "OSRModuleLoading";
  import "Partitions";
  import "Popup";
  import "Report";
  import "Stage";
  import "Storage";

  textdomain "repair";

  include "partitioning/custom_part_dialogs.ycp";

  //////////////////////////////////////////////////////////////////////
  //
  //  DETECTION METHODS
  //
  //////////////////////////////////////////////////////////////////////


  /**
   * Check if at least one harddisk exist.
   */
  define boolean OSRPartitionCheckDiskCount()``{

      /////////////////////////////////////////////////////////////////////////
      //
      //  Check all disks for entries in their map
      //
      /////////////////////////////////////////////////////////////////////////
      Storage::ReReadTargetMap();

      // get the names of detected harddisks and put them in the list -> ["/dev/hda", "/dev/sda"]
      list<string> disk_list = (list<string>)
	Storage::GetMainDevFilter("all", "key_list" );

      if ((size(disk_list) == 0) || (disk_list == nil))
      {
        // if no harddisk was found, exit the rescue system
        OSRStatus::ErrorSeverityBlocking();
        // summary text
        OSRSummary::DetectError( "", _("No hard disks were detected."));
        // error popup
        Report::Message(_("
YaST could not detect any hard disks
in your system. You probably need to load
the correct kernel modules.

YaST halts now.
"));

        OSR::SetReboot();
        return false;
      }
      else if (size(disk_list) == 1)
      {
        OSRSummary::DetectOK("",
            // summary text: %1 will be replaced with a string like "/dev/hda"
            sformat(_("One hard disk detected: %1"), disk_list[0]:""));
      }
      else if (size(disk_list) > 1)
      {
        OSRSummary::DetectOK("",
            // summary text: %1 is string like "/dev/hda, /dev/hdb, /dev/sda"
            sformat(_("Several hard disks detected: %1"), mergestring(disk_list, ", ")));
      }
      OSRCommon::ProvideBoolean("valid_target",true);
      return true;
  }


  /**
   *  Checks the mbr's of all harddisks.
   *  @return boolean
   */
  define boolean OSRPartitionCheckDisks() ``{

      /////////////////////////////////////////////////////////////////////////
      //
      //  Iterate all harddisks, check for partitions
      //
      /////////////////////////////////////////////////////////////////////////

      map           target_map      = Storage::GetTargetMap();
      list<string>  valid_target_list   = [];

      // check all targets (all disks) for partition entries
      foreach(string target, map values, (map<string,map>) target_map, ``{

      list<map> target_partitions = values["partitions"]:[];
      path      target_scrpath    = values["scrpath"]:.;

      if ( size(target_partitions) == 0 )
      {
          OSRSummary::DetectError("",
            // summary text
            sformat(_("No partition table was found for hard disk %1"),target));

          /////////////////////////////////////////////////////////////////////
          //
          //  Repair partition table with backup from floppy or with proposal
          //  from gpart
          //
          /////////////////////////////////////////////////////////////////////
          OSRSummary::SetRepairSummary( OSRPtbl::MainPtblRepairDialog(target , target_scrpath ),
                // summary header
                sformat(_("Repairing partition table of hard disk %1"), target),
                // summary text
                _("Successfully repaired the partition table."),
                // summary text
                _("Partition table was not repaired."),
                // summary text
                _("Repair was not successful."));
      }
      else
      {
          // add the name of the current harddisk to the list of valid targets
          valid_target_list = add(valid_target_list, target);
      }
      });

      /////////////////////////////////////////////////////////////////////////
      //
      //  Check if at least one harddisk with a valid partition table exists
      //
      /////////////////////////////////////////////////////////////////////////

      if (size(valid_target_list) == 0)
      {
        OSRStatus::ErrorSeverityBlocking();

        OSRSummary::DetectError("",
            // summary text
            _("No hard disk was found with a valid primary partition table."));

        // error popup
        Report::Message(_("
YaST could not detect any hard disks that
contain a valid primary partition table.

YaST halts now.
"));

        OSR::SetReboot();
        return false;
      }
      else if (size(valid_target_list) == 1)
      {
        // at least one valid target found
        OSRSummary::DetectOK("",
            // summary text (%1 is disk)
            sformat(_("Partition tables found for disk %1"),
                valid_target_list[0]:""));
      }
      else if (size(valid_target_list) > 0)
      {
        // at least one valid target found
        OSRSummary::DetectOK( "",
            // summary text
            sformat(_("Partition tables found for the disks %1"),
                mergestring(valid_target_list, ", ")));
      }
      OSRCommon::ProvideList("valid_target_list", valid_target_list);
      return true;
  };

  /**
   *
   */
  define boolean OSRPartitionCheckSwap()``{
      /////////////////////////////////////////////////////////////////
      //
      // search for valid swap partitions
      //
      /////////////////////////////////////////////////////////////////
      list<string> swap_partition_list = OSRSwap::Partitions();
      if ( size( swap_partition_list ) <= 0 )
      {
        // summary text
        OSRSummary::NotFound("", _("No valid partition types were found."));
      }
      else
      {
        OSRSummary::DetectOK("",
            // summary text (%1 are partitions)
            sformat(_("Valid swap partitions were found:<br>%1"),
                mergestring(swap_partition_list, ", ")));
        OSRCommon::ProvideList("swap_partition_list", swap_partition_list );
      }
      return true;
  }


  define boolean OSRPartitionCheckSwapAble()``{

      /////////////////////////////////////////////////////////////////
      //
      // search for "swap-able" partitions
      //
      /////////////////////////////////////////////////////////////////
      list<string> swap_partition_list     = (list<string>)
	OSRCommon::RequireList("swap_partition_list"); // ["/dev/hda1", "/dev/hdb2"]
      list<string> swapable_partition_list = OSRSwap::ValidPartitions(swap_partition_list); // ["/dev/hdb2"]
      list<string> swapon_notpossible_list = filter(string p, swap_partition_list, ``( ! contains( swapable_partition_list, p )));

      if (size( swapable_partition_list ) <= 0 )
      {
        // summary text
        OSRSummary::NotFound("", _("No swappable partitions were found."));
      }
      else
      {
        OSRSummary::DetectOK("",
            // summary text (%1 are partitions)
            sformat(_("Swappable partitions were found:<br>%1"),
                mergestring(swapable_partition_list, ", ")));
      }

      OSRCommon::ProvideList("swapable_partitions", swapable_partition_list);

      /////////////////////////////////////////////////////////////////
      //
      // include all swap partitions
      //
      /////////////////////////////////////////////////////////////////
      foreach(string swap, swapable_partition_list, ``{

      // Check if the specified swap-partition is already "swapped", if true don't swapon.
      // summary header (%1 is partition)
      string summary_header = sformat(_("Adding partition %1 to swap"), swap);

      if ( Storage::CheckSwapOn(swap))
      {
        OSRSummary::DetectOK( summary_header,
            // summary text (%1 is partition)
            sformat(_("Partition %1 was already added to swap"), swap));
      }
      else
      {
        // popup label (%1 is partition)
        if( ! Popup::YesNoHeadline(sformat(_("Activate Swap Partition %1"), swap),
            // popup text
            sformat(_("
The partition %1 has the file system ID 130 and
contains a valid swap area. Activating this swap
partition increases the performance of the repair tool.
Press \"Yes\" to activate the swap
partition.
"),swap ) ))
          {
            return;
          }

          // run /sbin/swapon
          if ( OSRExecute::Command(.local.bash, sformat("/sbin/swapon %1", swap)))
          {
            OSRSummary::DetectOK( summary_header,
                // summary text
                _("Swap activation was successful."));

            // add spap partition to list swap_aktivated for swapoff
            OSRCommon::ProvideList("swap_aktivated", add (
                OSRCommon::RequireList("swap_aktivated"), swap ));
          }
          else
          {
            // should never happen - GetSwapablePartitions(swap_partition_list) test swapon !!
            OSRSummary::DetectError( summary_header,
                // summary text
                _("Swap activation was not successful."));
          }
      }
      });

      if ( size ( swapon_notpossible_list ) != 0 ) {
      foreach(string part, swapon_notpossible_list, ``{
          OSRSummary::DetectError(
                      // summary header
                      sformat(_("Adding partition %1 to swap"), part),
                      // summary text
                      sformat(_("No valid swap area was found on
partition %1"), part)
                      );

          OSRSummary::SetRepairSummary(OSRSwap::Repair( part ),
                      // summary header
                      sformat(_("Creating swap area on partition %1..."), part),
                      // summary text
                      sformat(_("mkswap %1 was successful."), part ),
                      // summary text
                      _("Repair skipped."),
                      // summary text
                      sformat(_("mkswap %1 not successful."), part ));
      });
      }
      return true;
  }


  /**
   * Load all kernel fs modules
   */
  define boolean OSRPartitionLoadAllFsModules()``{

      /////////////////////////////////////////////////////////
      //
      // install available kernel modules for the filesystems
      //
      /////////////////////////////////////////////////////////
      if (! OSRFsck::LoadAllFsModules())
      {
        OSRSummary::DetectProblem("",
            // summary text (%1 are kernel modules)
            sformat(_("Loading failed for kernel modules:<br> %1"),
                mergestring(OSRFsck::not_installed_modules, "<br>")));
        return false;
      }
      else {
        OSRSummary::DetectOK("",
            // summary text (%1 are kernel modules)
            sformat(_("Kernel modules successfully installed:<br> %1"),
                mergestring(OSRFsck::fs_kernel_modules, "<br>")));
        OSRCommon::ProvideBoolean("fs_module_loaded", true);
        return true;
      }
  }

  /**
   *
   */
  define boolean OSRPartitionCurrentlyMountedPartitions()``{

      /////////////////////////////////////////////////////////
      //
      // Umount all partitions from "/mnt" or from deeper directories
      // (e.g. "/mnt/usr", "/mnt/usr/local", ...)
      // before mounting anything to "/mnt".
      //
      /////////////////////////////////////////////////////////
      //string  root_mountpoint    = OSRCommon::RequireString("root_mountpoint");
      OSRSystem::SetOrgRoot();
      OSRCommon::ProvideList("just_umounted", OSRFstab::UmountAllFrom( OSRSystem::TargetRoot()));

      list<map> mounted_partitions = Partitions::CurMounted();
      // filter swap partitions
      mounted_partitions = filter(map p, mounted_partitions,
        ``(p["file"]:"" != "swap" && findfirstof( p["spec"]:"", "/") == 0 ));

      /////////////////////////////////////////////////////////
      //
      // search for currently mounted partitions
      //
      /////////////////////////////////////////////////////////
      if ( size( mounted_partitions) <= 0)
      {
        // no mounted partitions: not implicitly an error!
        // summary text
        OSRSummary::DetectOK("", _("No mounted partitions were found."));
      }
      else
      {
        // create a mount-like output
        list<string> mounted_output = maplist(map entry, mounted_partitions,
                    // %1 is device, %2 mount point, %3 is fs type, %4 options
                    // example: "/dev/hda3 on /local type  rw" (=empty type)
                    ``(sformat (_("%1 on %2 type %3 %4"),
                        entry["spec"]:"", entry["file"]:"",
                        entry["fstype"]:"", entry["mntops"]:"")));
        OSRSummary::DetectOK("",
            // summary text
            sformat(_("Mounted partitions were found:<br>%1"),
                mergestring(mounted_output, "<br>")));
      }
      OSRCommon::ProvideList("mounted_partitions", mounted_partitions);
      return true;
  }

  /**
   *
   */
  define boolean OSRPartition2CheckPartitions()``{

      /////////////////////////////////////////////////////////
      //
      // search for fsck possible partitions
      //
      /////////////////////////////////////////////////////////

      list<map> fs_check_parts = OSRFsck::PossiblePartitions();

      if( size( fs_check_parts ) == 0 || fs_check_parts == nil) {
        // summary text
        OSRSummary::DetectError("",_("No partitions found."));
      }
      else {
        list<string> key_list = maplist(map p, fs_check_parts,
            ``( Storage::GetDeviceName(p["maindev"]:"", p["nr"]:nil)));
        OSRSummary::DetectOK("", sformat(_("%1"), mergestring(key_list, " " )));
      }
      OSRCommon::ProvideList("fsck_partitions", fs_check_parts );
  }


  /**
   *
   */
  define boolean OSRPartitionFSCheck()``{

      /////////////////////////////////////////////////////////
      //
      // fsck for all possible partitions
      //
      /////////////////////////////////////////////////////////
      list<map> fsck_partitions		= (list<map>)
	OSRCommon::RequireList("fsck_partitions");
      list<map> mounted_partitions	= (list<map>)
	OSRCommon::RequireList("mounted_partitions");
      list<string> checked_partitions = [];

      foreach(map p, fsck_partitions, ``{

      string  dev_name   = Storage::GetDeviceName(p["maindev"]:"", p["nr"]:nil);
      // summary header
      string summary_header  = sformat(_("Executing file system check for partition %1..."),  dev_name  );

      if( size( filter(map p, mounted_partitions, ``(p["spec"]:""  == dev_name ))) != 0 )
      {
        // summary text
        OSRSummary::DetectOK(summary_header, _("The partition is mounted. The file system check is not possible."));
        checked_partitions = add(checked_partitions, dev_name );
      }
      else
      {
          boolean fs_ok    = OSRFsck::Check( p );
          symbol used_fs  = (symbol) Storage::GetSubDevParam (
	    Storage::GetSubDevKey (p["maindev"]:"", p["nr"]:nil),"detected_fs");

          if ( fs_ok == true )
          {
            OSRSummary::DetectOK(summary_header,
                // summary text, %1 is device, %2 file system type
                sformat(_("%1 contains valid %2 file system"),
                    dev_name, FileSystems::GetName( used_fs, "unknown") ));
            checked_partitions = add(checked_partitions, dev_name );
          }
          else
          {
	    string fsname = FileSystems::GetName( used_fs, "unknown");
            // summary text, %1 is device, %2 file system type
	    string summary = sformat (_("%1 contains no valid %2 file system"),
                dev_name, fsname );
	    if (fsname == "unknown")
		// summary text, %1 is device
		summary = sformat(_("%1 contains unknown file system"),dev_name);

            OSRSummary::DetectError (summary_header, summary);
            if( fs_ok != nil )
            {
              symbol ret = OSRFsck::Repair(dev_name, used_fs );
              // start repairing !!x
              OSRSummary::SetRepairSummary( ret ,
                           summary_header,
                           // summary text
                           _("Repair was successful."),
                           // summary text
                           _("Repair was skipped."),
                           // summary text
                           _("Repair was not successful."));
              if ( ret == `ok )
              {
                checked_partitions = add(checked_partitions, dev_name );
              }
            }
          }
      }
      });
      OSRCommon::ProvideList( "checked_partitions", checked_partitions );
      return true;
  }

    /**
     * //////////////////////////////////////////////////
     * // search for valid Linux partitions
     * //////////////////////////////////////////////////
     */
    define boolean OSRPartitionLinuxPartitions()``{

      // Raid and LVM not supported at the moment!!
      list<string> checked_partitions	= (list<string>)
	OSRCommon::RequireList("checked_partitions");
      list<string> linux_partition_list =
	OSRFstab::LinuxPartitions(checked_partitions);

      if (size(linux_partition_list) <= 0 )
      {
        // summary text
        OSRSummary::DetectError("", _("No valid partition types were found."));
        // popup label
        if( Popup::AnyQuestion(_("No valid Linux partitions were found"),
            // popup text
            _("YaST could not detect any valid Linux partitions
in your system. There probably is no valid
Linux system on this computer. If you are
sure you installed a Linux system,
press \"Retry Scanning\". Otherwise
skip scanning the system and start a new
installation.
"),
            // button label
            _("&Retry Scanning"),
            Label::CancelButton(),
            `focus_yes) )
        {
            OSRStatus::RestartScan("find_harddisks");
            return true;
        }
        else
        {
            OSRStatus::ErrorSeverityBlocking();
            if (Stage::initial ())
            {
                OSR::SetReboot();
                y2milestone ( "Make a hard reboot" );
            }
            return false;
        }
      }
      else
      {
        OSRSummary::DetectOK("",
            // summary text
            sformat(_("Valid Linux partitions were found:<br>%1"),
                mergestring(linux_partition_list, ", ")));
      }
      OSRCommon::ProvideList("linux_partition_list", linux_partition_list);
      return true;
  }


  /**
   *
   */
  define boolean OSRPartitionMountableLinuxPartitions()``{

      /////////////////////////////////////////////////////////
      //
      // search for mountable partitions
      //
      /////////////////////////////////////////////////////////
      list<string> linux_partition_list	= (list<string>)
	OSRCommon::RequireList("linux_partition_list");
      list<string> mount_possible_list  = OSRFstab::MountablePartitions(linux_partition_list, OSRSystem::TargetRoot());

      if ( size(mount_possible_list) > 0 )
      {
        OSRSummary::DetectOK("",
            // summary text
            sformat(_("Mountable partitions were found:<br>%1"),
                mergestring(mount_possible_list, ", ")));

        OSRCommon::ProvideList("mount_possible_list", mount_possible_list);
        return true;
      }
      else
      {
        // summary text
        OSRSummary::DetectError("", _("No mountable partitions were found"));
        // popup label
        if( Popup::AnyQuestion(_("No mountable partitions were found"),
            // popup text
            _("
YaST could not detect any mountable partitions
in your system. Probably there is no valid
Linux system on this computer. If you are sure
you installed a Linux system, press 
\"Retry Scanning\". Otherwise skip scanning
the system and start a new installation.
"),
            // button label
            _("&Retry Scanning"),
            Label::CancelButton(),
            `focus_yes ) )
        {
            OSRStatus::RestartScan("find_harddisks");
            return true;
        }
        else
        {
            OSRStatus::ErrorSeverityBlocking();
            if (Stage::initial ())
            {
                OSR::SetReboot();
                y2milestone ( "Make a hard reboot" );
            }
            return false;
        }
      }

      list<string> not_mountable_linux  = filter(string p, linux_partition_list, ``( ! contains( mount_possible_list, p)));
      if ( size( not_mountable_linux ) != 0 ) {

      // summary text
      OSRSummary::DetectProblem(_("Unmountable Linux partitions"),
        mergestring(not_mountable_linux, " " ));
      }

      return true;
  }


  /**
   *  Checks the detected partitions for valid filesystems, mounts them and
   *  searches for filesystem tables (/etc/fstab) on the partitions.
   *
   *  @return map The result_map.
   */
  define boolean OSRPartitionFindRootPartitions() ``{

      /////////////////////////////////////////////////////////////////
      //
      // search for valid root partitions with a filesystem table
      //
      /////////////////////////////////////////////////////////////////

      list<string> valid_root_partition_list = OSRFstab::ValidRootPartitions (
        (list<string>) OSRCommon::RequireList("mount_possible_list"),
	OSRSystem::TargetRoot());
      string  root_partition         = "";

      if (size(valid_root_partition_list) == 1)
      {
        root_partition = valid_root_partition_list[0]:"";
        // summary text (%1 is root partition)
        OSRSummary::DetectOK("", sformat(_("One valid partition was found: %1"),
            root_partition));
      }
      else if ( size(valid_root_partition_list) > 1 )
      {
        // several valid root partitions found
        OSRSummary::DetectOK("",
            // summary text (%1 are root partitions)
            sformat(_("Several valid root partitions were found:<br>%1"),
                mergestring(valid_root_partition_list, ", ")));

      if( ! Stage::initial () )
      {
          // choose root partitions only if booted from cd.
          // problem with SCR agent. and /mnt (root_mountpoint)
          map root_map = Storage::GetEntryForMountpoint("/");
          root_partition = root_map["device"]:"";
      }
      if( Stage::initial () || root_partition == "" )
      {
          // launch a popup with a RadioButtonGroup
          // - one button for each item in the list -
          // and let the user select the root partition
          root_partition = OSRFstab::SelectRoot( valid_root_partition_list);
      }
      }

      if (size(valid_root_partition_list) <= 0  || root_partition == "" )
      {
        // summary text
        OSRSummary::DetectError("", _("No valid root partition was found"));
        // popup label
        if( Popup::AnyQuestion(_("No valid root partition was found"),
            // popup text
            _("
YaST could not detect any valid root partition
in your system. Probably there is no valid
Linux system on this computer. If you are
sure you installed a Linux system, try 
to restart scanning. Otherwise skip scanning and
start a new installation.
"),
            // button label
            _("&Retry Scanning"),
            Label::CancelButton(),
            `focus_yes ) )
        {
          OSRStatus::RestartScan("find_harddisks");
          return true;
        }
        else {
         OSRStatus::ErrorSeverityBlocking();
         if (Stage::initial ())
         {
         OSR::SetReboot();
         y2milestone ( "Make a hard reboot" );
         }
         return false;
     }
      }

      OSRCommon::ProvideString("root_partition", root_partition);
      OSRCommon::ProvideList("valid_root_partitions", valid_root_partition_list );
      return true;
  };



  define boolean OSRPartitionMountRoot()``{

    /////////////////////////////////////////////////////////////////////////
    //
    //  mount the root partition to /mnt
    //
    /////////////////////////////////////////////////////////////////////////
    string root_partition	= OSRCommon::RequireString ("root_partition");

    list<map> just_mounted	= [];

    // summary header, %1 is root partition, %2 target
    string  summary_header	= sformat(_("Mounting root partition %1 to %2"),
	root_partition, OSRSystem::TargetRoot());

    // check if the specified partition is already mounted to "/mnt",
    // mount only if it is not already done.
    if ( OSRSystem::TargetRoot() !=
	 Partitions::MountedOn (root_partition, Partitions::CurMounted()))
    {
	// Mount selected partition to /mnt
        if ((boolean) WFM::Execute (.local.mount,
	    [root_partition, OSRSystem::TargetRoot(),OSRExecute::OutputFile()]))
        {
	    // add the mounted partition to the list, this has to be known for
	    // being able to umount all partitions that were mounted
	    // by the rescue system
	    just_mounted = add (just_mounted, $[
		"partition"	: root_partition,
		"mountpoint"	: OSRSystem::TargetRoot()
	    ]);
	    OSRSummary::DetectOK (summary_header,
		// summary text
		_("Root partition was successfully mounted"));
	}
	else
	{
	    OSRSummary::DetectError (summary_header,
		// summary text, %1 is mount point
		sformat(_("Root partition was not successfully mounted to %1"),
		    OSRSystem::TargetRoot() ));

	    if (size (OSRCommon::RequireList("valid_root_partitions")) > 1)
	    {

		if (Popup::AnyQuestion (sformat (
		    // popup label, %1 is mount point
		    _("Root partition was not successfully mounted to %1"),
			OSRSystem::TargetRoot()),
		    // popup text, %1 is root partition
		    sformat (_("
YaST could not mount the root partition %1.
Restart the scanning and choose a another
root partition or cancel scanning the system.
"), root_partition),
		    // button label
		    _("&Restart Scanning"), Label::CancelButton(), `focus_yes)
		)
		{
		    OSRStatus::RestartScan ("find_valid_root_partitions");
		    return true;
		}
	    }
	    OSRStatus::ErrorSeverityModuleBlocking();
	    return false;
	}
    }
    else
    {
	OSRSummary::DetectOK(
	    // summary header (%1 is partition, %2 mount point)
            sformat(_("Mount Root Partition %1 to %2"),
                root_partition, OSRSystem::TargetRoot()),
            // summary text (%1 is mount point)
            sformat(_("Root partition is already mounted to %1"),
                OSRSystem::TargetRoot()  ));
    }

    OSRCommon::ProvideList("just_mounted", just_mounted );
    OSRCommon::ProvideBoolean("root_mounted", true );
    return true;
  }

  /**
   *  Mount the root partition and all reachable, local and valid partitions
   *  from the detected filesystem table "/etc/fstab".
   *
   *  Requires: list valid_root_partitions,
   *            string root_partition
   *  Provides: list just_mounted,
   *            string root_mountpoint
   *
   *  @return map The result_map.
   */
  define boolean OSRPartitionReadFstab() ``{

      /////////////////////////////////////////////////////////////////////////
      //
      //  get the fstab
      //
      /////////////////////////////////////////////////////////////////////////

      // summary header
      string summary_header   = sformat(_("Reading fstab of root partition %1..."),  OSRCommon::RequireString("root_partition"));

      if ( ! OSRFstab::ReadFstab(OSRSystem::TargetRoot(), false))
      {
        // summary text
        OSRSummary::DetectError( summary_header, _("fstab could not be read."));

        if( size( OSRCommon::RequireList("valid_root_partitions")) > 1 ) {
            // popup label
            if( Popup::AnyQuestion(_("fstab was not successfully read."),
                // popup text
                _("
YaST could not read fstab.
Restart the scan and choose another
root partition or cancel scanning the system.
"),
                // button label
                _("&Restart Scanning"),
                Label::CancelButton(),
                `focus_yes ))
          {
              OSRStatus::RestartScan("find_valid_root_partitions");
              return true;
          }
      }
      OSRStatus::ErrorSeverityModuleBlocking();
      return false;
      }
      else
      {
        // summary text
        OSRSummary::DetectOK( summary_header, _("fstab read."));
      }

      OSRCommon::ProvideBoolean("fstab_readed", true);
      return true;
  }


  /**
   * Check the root entry in the fstab.
   */
  define boolean OSRPartitionCheckFstabRoot()``{

      if (OSRFstab::CheckRootEntry (OSRCommon::RequireString("root_partition"),
	    (list<string>) OSRCommon::RequireList("swapable_partitions"),
            (list<string>) OSRCommon::RequireList("checked_partitions")) ||
	  Mode::test ())
      {
        // summary text
        OSRSummary::DetectOK("", _("The root entry of fstab is valid."));
      }
      else {

        // summary text
        OSRSummary::DetectError("", _("The root entry of fstab is not valid."));

        OSRSummary::SetRepairSummary(OSRFstab::Repair(),
                       "",
                       // summary text
                       _("Repairing the root entry was successful."),
                       // summary text
                       _("Repair was skipped."),
                       // summary text
                       _("Repair was not successful."));
      }
      OSRCommon::ProvideBoolean("fstab_root_checked",true);
      return true;
  }

  /**
   * Check all entris (without root) in the fstab.
   */
  define boolean OSRPartitionCheckFstab()``{

      string root_partition    = OSRCommon::RequireString("root_partition");

      if ( OSRFstab::Check (
		(list<string>)OSRCommon::RequireList("swapable_partitions"),
		(list<string>)OSRCommon::RequireList("checked_partitions")))
      {
        // summary text
        OSRSummary::DetectOK("", _("fstab entries valid."));
      }
      else
      {
        // summary text
        OSRSummary::DetectError("",_("At least one fstab entry is not valid."));

        OSRSummary::SetRepairSummary(OSRFstab::Repair(),
                       "",
                       // summary text
                       _("The fstab entry was successfully repaired."),
                       // summary text
                       _("Repair was skipped."),
                       // summary text
                       _("Repair was not successful."));
      }
      OSRCommon::ProvideBoolean( "fstab_checked", true);
      return true;
  };


  /**
   * Reset temporary settings.
   */
  define boolean OSRPartitionReset()``{

      // umount just_mount!!
      list<map> just_mounted    = (list<map>) OSRCommon::RequireList("just_mounted");
      just_mounted      = sort(map x, map y, just_mounted,
        ``(size(splitstring(x["mountpoint"]:"", "/")) >
           size(splitstring( y["mountpoint"]:"" ,"/"))));
      y2milestone(" just_mounted %1", just_mounted );

      // mount just_umounted!!
      list<map> just_umounted   = (list<map>) OSRCommon::RequireList("just_umounted");
      just_umounted		= sort(map x, map y, just_umounted,
        ``(size(splitstring(x["mountpoint"]:"", "/")) <
           size(splitstring(y["mountpoint"]:"" ,"/"))));

      just_mounted = (list<map>) union ( [
            $[  "partition" : "usbfs",
                "mountpoint" : OSRSystem::TargetRoot() + "/proc/bus/usb" ],
            $[  "partition" : "proc",
                "mountpoint" : OSRSystem::TargetRoot() + "/proc" ]
            ], just_mounted );

      // build todo map
      list<map> todo = [];

      foreach(map mp, just_mounted, ``{
        todo = add( todo, add( mp, "path", .local.umount ));
      });
      foreach(map mp, just_umounted, ``{
        todo = add( todo, add( mp, "path", .local.mount ));
      });

      y2milestone(" reset map %1" , todo);
      // execute todo
      foreach( map mp , todo , ``{
      if( (mp["path"]:.local.umount == .local.mount )
	  ? (boolean) WFM::Execute(mp["path"]:.local.mount,
	    [ mp["partition"]:"", mp["mountpoint"]:""])
          : (boolean) WFM::Execute(mp["path"]:.local.umount,
	    mp["mountpoint"]:"" ))
      {
          y2milestone(" %1 %2 succeeded", mp["path"]:.local.umount,mp["mountpoint"]:"" );
      }
      else {
          y2error(" %1 %2 failed",  mp["path"]:.local.umount,mp["mountpoint"]:"" );
      }
      });

      OSRModuleLoading::UnloadAll();

      OSRPtbl::Reset();
      OSRFsck::Reset();
      OSRFstab::Reset();

      return true;
  }

  /**
   * Direct partitioning with the custom part tool.
   */
  define symbol OSRDirectCustomPart()``{

      y2milestone("Direct start Custom Part");

      // remove all mount points
      map target_map = Storage::GetTargetMap();
      foreach(string dev, map parts, (map<string,map>) target_map, ``{
	integer counter = 0;
	foreach (map part, parts["partitions"]:[], ``{
	    if ( part["mount"]:"" != "" )
		target_map[dev, "partitions", counter,"mount"] = "";
	    counter = counter  +1;
	});
      });
      Storage::SetTargetMap(target_map);
      Storage::SetPartMode("CUSTOM");
      Storage::SetPartProposalActive(false);

      symbol ret = `next ;
      UI::NormalCursor();
      repeat {
      Storage::immediate_prepdisk = true;

      ret = (symbol) WFM::CallFunction ("inst_disk", [true, true] );
      Storage::immediate_prepdisk = false;

      if ( ret == `next  )
      {
	  // TODO: ReallyInstPrepdisk should be part of some module...
	  // (now included from "partitioning/custom_part_dialogs.ycp")
          ret = ReallyInstPrepdisk ();
          if ( ret == `back ) ret = `again;

          if ( ret == `apply  )
          {
	    ret = (symbol) WFM::CallFunction ("inst_prepdisk", [false, false]);
	    ret = `again;
          }
          if ( ret == `finish )
          {
	    ret = (symbol) WFM::CallFunction ("inst_prepdisk", [false, false]);
          }
      }
      } until ( ret ==  `back || ret == `next || ret == `ok || ret == `cancel || ret == `abort);
      return ret;
  }

  /**
   * Direct recover a lost partition table.
   */
  define symbol OSRDirectPartitionTable()``{

      y2milestone("Direct start repairing partition table");

      symbol ret             = `next;
      list<string> disk_list = (list<string>)
	Storage::GetMainDevFilter("all", "key_list" );
      string repair_dev      = disk_list[0]:"";

      UI::NormalCursor();
      // select the root partition
      if( size( disk_list ) > 1)
      {
        // RadioButtonGroup label
        repair_dev =  OSRPopup::RadioButtonGroup(_("Select a hard disk"),
            // RadioButtonGroup text
            _("
There are several hard disk in your system.
Select the hard disk for which YaST
should try to recover lost partitions.
"),
            disk_list,
            "cancel",
            true
            );
      }
      else if( repair_dev == "" )
      {
        // error popup
        Report::Error("
YaST can not found any valid hard
disk at your system. Recovering a
lost partitions is not possible.
");
        ret = `error;
      }

      if( repair_dev != "cancel" && repair_dev != "" )
      {
        map maindev = Storage::GetMainDev( repair_dev );

        OSRPtbl::SetTarget( repair_dev, maindev["scrpath"]:.);

        ret = OSRPtbl::RestoreWithGpart ();
      }

      OSRPtbl::Reset();
      return ret;
  }


  /**
   * Direct repair a damaged file system.
   */
  define symbol OSRDirectFilesystem()``{

      y2milestone("Direct start repairing a file system ");

      list<map> parts_data = (list<map>)
	Storage::GetSubDevFilterList("all", "no_delete" ,"all" );

      parts_data = filter(map p, parts_data,
        ``(  ( contains ( OSRFsck::fsck_fsid, p["fsid"]:0 )) &&
               contains ( OSRFsck::fsck_type, p["type"]:`unknown )));

      list<string> partitions = maplist(map p, parts_data, ``(p["device"]:""));
      string scan_dev         = "";

      UI::NormalCursor();
      if( size(partitions) == 0  )
      {
        // error popup
        Report::Error("
YaST can not found any valid partitions
at your system. Executing a file system
check is not possible.");
        return `error;
      }
      else if( size( partitions ) > 0 )
      {
        // RadioButtonGroup label
        scan_dev =  OSRPopup::RadioButtonGroup(_("Select partition"),
            // RadioButtonGroup text
            _("
Where should YaST execute a file system check?
"),
            partitions,
            partitions[0]:"",
            false
            );
      }
      if( scan_dev != "" )
      {
      import "OSRLogFile";

      map subdevkeys    = Storage::GetDiskPartition( scan_dev );
      map p = find(map part, parts_data, ``( scan_dev == part["device"]:"" )); //Storage::GetSubDev( subdevkey );
      p["maindev"]      = subdevkeys["disk"]:"";

      if( p["mount"]:"" != "" )
      {
          if( contains( OSRFstab::system_mount_points,  p["mount"]:""))
          {
            // error popup
            Report::Error( sformat(_("
The selected partition %1 is
currently mounted on the system mount point %2.
YaST cannot unmount this partition.
Start the YaST rescue tool from CD-ROM and
try executing the file system check again.
"), scan_dev, p["mount"]:""));
            return `error;

          }
          else
          {
            // popup label
            if (! Popup::YesNoHeadline(_("Partition mounted"),
                // popup text
                sformat(_("
The selected partition %1 is 
currently mounted. Should YaST try to
unmount the partition then try to execute
a file system check?
"), scan_dev )))
          {
              return `error;
          }
          else {
              WFM::Execute(.local.umount,  p["mount"]:""   );

              if( Partitions::MountedOn( scan_dev , Partitions::CurMounted()) != "" )
              {
                // error popup
                Report::Error(sformat(_("
Unmounting the partition %1 is
not possible. File system check
cannot be executed.
"), scan_dev ));
                return `error;
              }
          }
          }
      }

      symbol ret = `next;
      string direct_name = OSRCommon::current_direct_name;

      term progress = OSRProgress::Create(`fsck_progress,
                          _("Progress:"),
                          0,true);
      term contents = `HBox(
	`HSpacing(1),
        `VBox(
            `VSpacing(1),
	    // label
            `HBox(`HWeight(30,`Left(`Heading(_("Checking file system...")))),
            `HWeight(30, `HSpacing(10))),
            `VSpacing(1),
            `Left(`Label(_("Partition: ") + scan_dev )),
            `VSpacing(1),
            progress,
            `VSpacing(1)
        ),
	`HSpacing(1)
      );
      UI::OpenDialog( contents );

      OSRProgress::DeleteFile( OSRLogFile::GetTmpDir() + "/"+ direct_name );
      OSRProgress::SetFile(`fsck_progress, OSRLogFile::GetTmpDir() + "/"+ direct_name );
      boolean fs_ok     = OSRFsck::Check( p );
      OSRProgress::Fill(`fsck_progress);
      UI::CloseDialog();

      if( fs_ok == nil )
      {
          // error popup
          Report::Error(sformat(_("

YaST cannot detect the file system type
of the partition %1. Executing a file
system check is not possible.
"), scan_dev ));
          ret = `error;
      }
      else
      {
          symbol used_fs = (symbol) Storage::GetSubDevParam (
	    Storage::GetSubDevKey (p["maindev"]:"", p["nr"]:nil),"detected_fs");

          if (fs_ok)
	  {
	    if (OSRFsck::IsNonLinuxFileSystem (used_fs))
		// message popup %1 is partition, %2 filesystem type name
		Report::Message(sformat(_("
The partition %1 contains
the non-Linux file system \"%2\".
No partitions checks were done.
"),scan_dev, FileSystems::GetName( used_fs, "unknown") ));
	    else
		// message popup %1 is partition, %2 filesystem type name
		Report::Message(sformat(_("
The partition %1 contains
a valid %2 file system.
"),scan_dev, FileSystems::GetName( used_fs, "unknown") ));
          }
          else
	  {
	    if( OSRFsck::Repair(scan_dev, used_fs ) != `ok )
	    {
		ret =  `error;
	    }
          }
      }
      OSRFsck::Reset();
      return ret;
      }
      return `cancel;
  }

  /**
   * Save disk partition info to floppy
   */
  define symbol OSRDirectSave2Floppy()``{

      import "OSRFloppy";
      import "StorageDevices";


      UI::NormalCursor();
      if (!StorageDevices::FloppyPresent)
      {
	// message popup (no floppy drive was detected)
	Report::Message(_("
YaST could not detect a floppy drive in your
system. Saving system information is not
possible.
"));
	return `error;
      }
      // popup text
      if (! Popup::ContinueCancel(_("
Insert a formatted disk
in your floppy drive and press
Continue.
")))
      {
	return `cancel;
      }

      map target_map = Storage::GetTargetMap();
      boolean error  = false;

      if (OSRFloppy::Open (true, size(target_map)))
      {
          foreach (string key, map v, (map<string,map>) target_map, {
	    OSRFloppy::NextStep (
		// progress label
		sformat (_("Saving partition table of disk %1..."), key));
	    if (!error &&
		!OSRPtbl::WritePartitionsInfo2Floppy (key, v["partitions"]:[]))
	    {
              // eroro popup
              Report::Error(sformat(_("
The primary partition table of disk %1
was not written correctly to floppy disk.
"), key));
                error = true;
	    }
          });
      }
      OSRFloppy::Close();

      if ( error )
      {
          // eroro popup
          Report::Error(_("
Writing the system information was
not successful. Try again.
"));
          return `error;
      }
      else {
          // message popup
          Report::Message(_("\nWriting the system information was successful.
"));

      }
      return `ok;
  }

  //////////////////////////////////////////////////////////////////////
  //
  //  METHODS
  //
  //////////////////////////////////////////////////////////////////////

  /**
   *  Initialization of the module map that contains all important information
   *  for this module.
   *
   *  @return map The map that contains all information about the module
   *  osr_module_partition.
   */

  define map OSRPartitionInit() ``{
      return $[
           // has to be the name of the file
           "name"              :  "osr_module_partition",
                                  // module headline
           "headline"          :  _("Partitions and File Systems"),
           "global_entries"    : $[
                       "mbr_check" : $[
                                      // module action label
                          "text"    : _("Check Partition Tables"),
                                      // helptext
                          "help"    : _("
<P><B>What is a partition table?</B><BR>
The partition table is the part of
a hard disk where the information about
the size and the position of the
partitions of a hard disk are stored.
Every hard disk has its own partition
table.</P>
") +
_("<P>Without such a partition table,
Linux cannot find a partition on a hard
disk.</P>
") +

_("<P><B>Check Partition Tables</B><BR>
If you delete a partition by mistake,
it is sometimes possible to recover the
lost partition. YaST can analyze
the hard disk and try to find such a
partition.
The partition table can also be lost 
or damaged due to a system crash or a virus.
Even in these cases, YaST can sometimes
recover a partition table.</P>
")
                       ],
                       "swap_check" :
                       $[
                                  // module action label
                         "text" : _("Check Swap Areas"),
                                  // helptext
                         "help" : _("
<P><B>What is a swap area?</B><BR>
The swap area is the virtual memory of a
Linux system. Linux swap areas can be a
special partition or in a file.</P>
") +

_("<P><B>Check Swap Areas</B><BR>
YaST checks all found swap areas.
If a swap area is damaged, the
repair system proposes creating
a new swap area.
</P>
")
                       ],
                       "fs_check" :
                       $[
                                  // module action label
                         "text" : _("Check File Systems"),
                                  // helptext
                         "help" : _("
<P><B>What is a file system?</B><BR>
Formatting a partition means a
file system will be created in a partition.
After that, you can mount the partition and
save files and other data to the partition.
Linux can normally use only partitions with
a valid file system for saving data and
programs. </p>
") +

_("<P><B>Check File System</B><BR>
An inconsistent file system occurs when
a partition is not correctly unmounted.
For example, this happens when the system
crashes.</p>
") +

_("<p>There is a repair method for each file
system. For example, if the file system
of the damaged partition is ext2 or
ext3, use fsck.ext2 (e2fsck) with the
corresponding options to repair the
file system.</P>
") +
_("<P>YaST checks the file system of all
found partitions and suggests 
repairing it if an error was found.</P>
")
                         ],

                       "fstab_check" :
                       $[
                                  // module action label
                         "text" : _("Check fstab Entries"),
                                  // helptext
                         "help" : _("
<P><B>What is fstab?</B><BR>
fstab is a configuration file that
contains entries for all devices that should
be mounted during the boot process. 
If you have deleted a partiton without
removing the corresponding fstab entry, you
get a warning during the boot process.</P>
")+

_("<P><B>Check fstab Entries</B><BR>
YaST checks all entries listed in the
fstab and reports missing, obsolete, and
erroneous entries.</P>
"),
                         "requires" : ["fs_check", "swap_check"]
                       ]
           ],

           "static_provides"    : $[
                        //"root_mountpoint"     : "/mnt"

           ],
           "reset_methods"      : [
                                      // module reset label
                       $["summary"  : _("Reset Module Settings"),
                         "method"   : OSRPartitionReset,
                         "provides" : 10 ]
           ],
           // the sequence of the detection methods of this module
           "detect_methods"    :  [
                       $[ "name"      : "find_harddisks",
                                        // module method progress label
                           "summary"  : _("Searching for hard disks..."),
                           "method"   : OSRPartitionCheckDiskCount,
                           "requires" :  ["repair_target"],
                           "provides" :  ["valid_target"],
                           "group"    : "mbr_check",
                           "progress" : 10
                          ],
                       $[ "name"     : "check_harddisks",
                                        // module method progress label
                          "summary"  : _("Checking partition tables..."),
                          "method"   : OSRPartitionCheckDisks,
                          "requires" :  [ "has_floppy", "valid_target"],
                          "provides" :  [ "valid_target_list"],
                          "group"    : "mbr_check",
                          "progress" :  100
                          ],
                       $["name"   : "find_swap",
                                        // module method progress label
                          "summary"   : _("Searching for valid swap partitions..."),
                          "method"    : OSRPartitionCheckSwap,
                           "requires" :  [ "valid_target_list"   ],
                          "provides"  :  [ "swap_partition_list" ],
                         "group"      : "swap_check",
                          "progress"  : 20
                          ],
                       $[ "name"     : "find_swapable",
                                        // module method progress label
                          "summary"  : _("Searching for swappable partitions..."),
                          "method"   : OSRPartitionCheckSwapAble,
                          "requires" :  [ "swap_partition_list" ],
                          "provides" :  [ "swapable_partitions" ],
                          "group"    :  "swap_check",
                          "progress" : 20
                          ],
                       $[ "name"     : "load_modules",
                                        // module method progress label
                          "summary"  : _("Installing kernel modules for file system support..."),
                          "method"   : OSRPartitionLoadAllFsModules,
                          "requires" : [],
                          "group"    : "fs_check",
                          "provides" :  ["fs_module_loaded"],
                          "progress" : 20
                          ],
                       $[ "name"     : "find_mounted",
                                        // module method progress label
                          "summary"  : _("Searching for currently mounted partitions..."),
                          "method"   : OSRPartitionCurrentlyMountedPartitions,
                          "requires" :  ["valid_target_list", "fs_module_loaded" ],
                          "provides" :  ["mounted_partitions"],
                          "group"    : "fs_check",
                          "progress" :  20
                       ],
                       $["name"  : "find_fscheck",
                                        // module method progress label
                          "summary"  : _("Found partitions for file system check"),
                          "method"   : OSRPartition2CheckPartitions,
                          "requires" :  [ "mounted_partitions" ],
                          "provides" :  [ "fsck_partitions"],
                          "group"    : "fs_check",
                          "progress" :  20
                       ],
                       $[ "name"     : "fsck",
                          "summary"  : "",
                          "method"   : OSRPartitionFSCheck,
                          "requires" :  [ "fsck_partitions" ],
                          "provides" :  [ "checked_partitions" ],
                          "group"    : "fs_check",
                          "progress" :  200
                       ],
                       $[ "name"     : "find_linux_partitions",
                                        // module method progress label
                          "summary"  : _("Searching for valid Linux partitions..."),
                          "method"   : OSRPartitionLinuxPartitions,
                          "requires" :  ["checked_partitions" ],
                          "provides" :  ["linux_partition_list"],
                          "group"    :  "fstab_check",
                          "progress" : 20
                           ],
                       $[ "name"     : "find_mountable_linux_partitions",
                                        // module method progress label
                          "summary"  : _("Searching for mountable partitions..."),
                          "method"   : OSRPartitionMountableLinuxPartitions,
                          "requires" :  ["linux_partition_list"],
                          "provides" :  ["mount_possible_list" ],
                          "group"    :  "fstab_check",
                          "progress" : 20
                          ],
                       $[ "name"     : "find_valid_root_partitions",
                                        // module method progress label
                          "summary"  : _("Searching for valid root partitions..."),
                          "method"   : OSRPartitionFindRootPartitions,
                          "requires" :  ["mount_possible_list"],
                          "provides" :  ["root_partition", "valid_root_partitions" ],
                          "group"    : "fstab_check",
                          "progress" : 20
                          ],
                       $[ "name"     : "mount_root",
                          "summary"  : "",
                          "method"   : OSRPartitionMountRoot,
                          "requires" :  [ "root_partition"],
                          "provides" :  ["root_mounted"   ],
                          "group"    : "fstab_check",
                          "progress" : 20
                          ],
                       $[ "name"     : "read_fstab",
                          "summary"  : "",
                          "method"   : OSRPartitionReadFstab,
                          "requires" :  [ "root_mounted"      ],
                          "provides" :  [ "fstab_readed"      ],
                          "group"    : "fstab_check",
                          "progress" : 20
                       ],
                       $[ "name"     : "check_root_entry",
                                        // module method progress label
                          "summary"  : _("Checking root file system entry of fstab"),
                          "method"   : OSRPartitionCheckFstabRoot,
                          "requires" :  [ "fstab_readed"        ],
                          "provides" :  [ "fstab_root_checked"      ],
                          "group"    : "fstab_check",
                          "progress" : 20
                        ],
                       $[ "name"     : "check_entries",
                                        // module method progress label
                          "summary"  : _("Checking fstab entries"),
                          "method"   : OSRPartitionCheckFstab,
                          "requires" :  [ "fstab_root_checked"      ],
                          "provides" :  [ "fstab_checked"       ],
                          "group"    : "fstab_check",
                          "progress" : 20
                       ]
           ],
           "direct_methods" : [
                   $[

                     "name"     : "direct_methods_custom_part",
                                      // module method action label
                     "button_text"  : _("Start Partitioning Tool"),
                                      // module method description
                     "description"  : _("
To resize, delete, or create a partition,
press this button
to start the YaST partitioning tool.
"),
                     "method"       : OSRDirectCustomPart,
                     "initial_only"     : true,
                     "visible"      : false,
                   ],
                     $[

                       "name"       : "direct_methods_recover_partition",
                                          // module method action label
                       "button_text"    : _("Recover Lost Partitions"),
                                          // module method description
                       "description"    : _("
If you have deleted or lost one or all
partitions of a hard disk accidentally,
press this button to attempt
recovery.
"),
                       "method"     : OSRDirectPartitionTable,
                       "initial_only"   : false,
                       "visible"    : true,
                     ],
                     $[

                       "name"       : "direct_methods_filesystem",
                                          // module method action label
                       "button_text"    : _("Repair File System"),
                                          // module method description
                       "description"    : _("
If the system crashed and you have a
corrupted file system afterward press
this button to scan and repair the file
system.
"),
                       "method"     : OSRDirectFilesystem,
                       "initial_only"   : false,
                       "visible"    : true
                     ],
                     $[
                       "name"       : "direct_methods_save",
                                          // module method action label
                       "button_text"    : _("Save System Settings to Floppy"),
                                          // module method description
                       "description"    : _("This can be helpful for later system checks. For example, it is possible to recover a lost partition
table with the stored system information.
"),
                       "method"     : OSRDirectSave2Floppy,
                       "initial_only"   : false,
                       "visible"    : true
                     ]
           ]
      ];


  };

}//EOF
