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 / OSRFstab.ycp < prev    next >
Text File  |  2006-11-29  |  60KB  |  2,291 lines

  1. /**
  2.  *  File:
  3.  *    OSRFstab.ycp
  4.  *
  5.  *  Module:
  6.  *    YaST OS Repair. Automatic error detection & repair tool for Linux.
  7.  *
  8.  *  Summary:
  9.  *    YaST OS Repair. Automatic error detection & repair tool for Linux.
  10.  *
  11.  *  Author:
  12.  *    Johannes Buchhold <jbuch@suse.de>
  13.  *
  14.  *  Use:
  15.  *      OSRFstab::LinuxPartitions ("/dev/hda1", "/dev/hda2", .. ]);
  16.  *      OSRFstab::MountablePartitions( ..);
  17.  *    OSRFstab::ValidRootPartitions( ..);
  18.  *
  19.  *    OSRFstab::ReadFstab("/");
  20.  *    OSRFstab::CheckRootEntry ("/dev/hda1",
  21.  *        ["/dev/hda2"], ["/dev/hda3", "/dev/hda4" ]);
  22.  *    OSRFstab::Repair();
  23.  *
  24.  *    OSRFstab::Check(["/dev/hda2"], ["/dev/hda3", "/dev/hda4" ]);
  25.  *    OSRFstab::Repair();
  26.  *
  27.  *
  28.  * $Id: OSRFstab.ycp 32906 2006-09-15 09:57:06Z jsuchome $
  29.  */
  30. {
  31.   module "OSRFstab";
  32.  
  33.   import "FileSystems";
  34.   import "Storage";
  35.   import "StorageDevices";
  36.   import "Hotplug";
  37.   import "Partitions";
  38.   import "Mode";
  39.   import "Installation";
  40.   import "AsciiFile";
  41.   import "Initrd";
  42.   import "Report";
  43.  
  44.   import "OSRFsck";
  45.   import "OSRLogFile";
  46.   import "OSRSystem";
  47.   import "OSRExecute";
  48.   import "OSRPopup";
  49.  
  50.   import "Label";
  51.   import "Popup";
  52.   import "SuSERelease";
  53.  
  54.  
  55.   textdomain "repair";
  56.  
  57.   string remove_label        = _("Remove");
  58.   string ignore_label        = _("Ignore");
  59.   string replace_label        = _("Replace");
  60.   string create_label        = _("Create");
  61.  
  62.   string device_label        = _("Device");
  63.   string mount_label        = _("Mount Point");
  64.   string create_mp_label    = _("Create Mount Point");
  65.   string state_label        = _("State");
  66.   // fstab is file name
  67.   string fstab_line_label    = _("fstab Line");
  68.  
  69.   // button label
  70.   string b_ignore_label        = _("&Ignore");
  71.   // button label
  72.   string b_create_label        = _("&Create");
  73.   // button label
  74.   string b_remove_label        = _("&Remove");
  75.   // button label
  76.   string b_change_mp_label    = _("Change &Mount Point");
  77.   // button label
  78.   string b_replace_label    = _("R&eplace");
  79.  
  80.   global list<string> system_mount_points =
  81.     [ "/dev", "/lib", "/bin", "/etc", "/sbin" ];
  82.  
  83.   /**
  84.    * The path
  85.    */
  86.   global string fstabpath    = "/etc/fstab";
  87.  
  88.   /**
  89.    * The default fstab entries (as maps) -> set in constructor
  90.    */
  91.   map <string,map> fstab_defaults    = $[];
  92.  
  93.   /**
  94.    * All digits
  95.    */
  96.   string digits          = "0123456789";
  97.  
  98.   /**
  99.    * Line position to sense
  100.    */
  101.   map pos2field = $[ 0: "spec",
  102.              1: "mount",
  103.              2: "vfstype",
  104.              3: "mntops",
  105.              4: "freq",
  106.              5: "passno" ];
  107.  
  108.  
  109.   /**
  110.    * Partitions which are swapable
  111.    */
  112.   list<string> swapable_partition_list   = [];
  113.  
  114.   /**
  115.    * All checked partitions (OSRFsck)
  116.    */
  117.   list<string> checked_partitions    = [];
  118.  
  119.   /**
  120.     @example of map describing /etc/fstab:
  121.  
  122.     $[
  123.     "comment"    : "^[ \t]*#.*",
  124.     "delim"        : " \t",
  125.     "l"        : $[
  126.         1    : $[
  127.         "fields" : ["/dev/hda2", "/", "reiserfs", "defaults", "1", "1"],
  128.         "line"     :"/dev/hda2\t/\treiserfs\tdefaults 1 1"
  129.         ],
  130.         2    : $[
  131.         "fields" : [
  132.             "/dev/hda3", "/local", "reiserfs", "defaults", "1", "2"],
  133.         "line"     : "/dev/hda3\t/local\treiserfs\tdefaults 1 2"
  134.         ],
  135.         3    : $[
  136.         "fields" : [ "/dev/hda1", "swap", "swap", "pri=42", "0", "0"],
  137.         "line"     : "/dev/hda1\tswap\tswap\tpri=42 0 0"
  138.         ],
  139.         4    : $[
  140.         "fields" : [
  141.             "devpts", "/dev/pts", "devpts", "mode=0620,gid=5","0", "0"],
  142.         "line"     : "devpts\t/dev/pts\tdevpts\tmode=0620,gid=5 0 0"
  143.         ],
  144.         ...
  145.         14    : $[
  146.         "fields" : [
  147.             "nfs.suse.cz:/home", "/home", "nfs", "defaults", "0", "0"],
  148.         "line"     : "nfs.suse.cz:/home\t/home\tnfs\tdefaults 0 0"
  149.         ],
  150.         15    : $[
  151.         "comment":true,
  152.         "line":"#blah"
  153.         ]
  154.     ],
  155.     "widths"    : [20, 20, 10, 21, 1, 1]
  156.     ]
  157.   */
  158.   map fstab                = $[];
  159.  
  160.   /**
  161.    * The root mount points e.g.: "/", "/mnt"
  162.    */
  163.   string root_mountpoint        = "";
  164.  
  165.   /**
  166.    * All checked valid lines
  167.    * e.g.: [1,2,3];
  168.    */
  169.   list<integer> valid_lines        = [];
  170.  
  171.   /**
  172.    * Not valid lines, e.g.:
  173.    * $[4: ["dev", false, true, true ,true ,true ,true ]],//spec error in line 4
  174.    */
  175.   map not_valid_lines            = $[];
  176.  
  177.   /**
  178.    * Devices without fstab entry
  179.    * e.g.: ["/dev/hdb7"]
  180.    */
  181.   list<string> missing_devs        = [];
  182.  
  183.   /**
  184.    * Constructor: initialize data structures with default values
  185.    */
  186.   global define void OSRFstab () {
  187.  
  188.     foreach (string type, [
  189.     "pts", "proc", "usb", "swap", "cdrom", "floppy",
  190.     "root", "zip", "dev", "nfs", "sys" ],
  191.     {
  192.     fstab_defaults [type]    = FileSystems::GetFstabDefaultMap (type);
  193.     });
  194.   }
  195.  
  196.   define void ResetSettings() {
  197.       missing_devs    = [];
  198.       valid_lines    = [];
  199.       not_valid_lines   = $[];
  200.   }
  201.  
  202.   global define void Reset() {
  203.       ResetSettings();
  204.       root_mountpoint        = "";
  205.       fstab            = $[];
  206.       swapable_partition_list   = [];
  207.       checked_partitions    = [];
  208.   }
  209.  
  210.   /**
  211.    * @param key        values of which key should be returned
  212.    * @param exists    restrict the returned set only to the types with
  213.    * nonempty values of key 'exists'
  214.    */
  215.   define list<string> fstab_default_exist (string exists, string key)
  216.   {
  217.     map <string,map> existing    = filter (
  218.     string type, map desc, fstab_defaults, ``(desc[exists]:"" != ""));
  219.     return (list<string>) maplist (string type, map d, existing, ``(d[key]:""));
  220.   }
  221.  
  222.  
  223.   /**
  224.    * e.g.: transform a fstab list to a fstab map.
  225.    * list: ["/dev/hda6", "/", "reiserfs", "defaults", "1", "1"]
  226.    * map : $[ "spec":"/dev/hda6", "file":"/" ... ]
  227.    */
  228.   define map fstabline2map (list<string> line)``{
  229.  
  230.     map ret    = $[];
  231.     integer pos    = 0;
  232.     foreach (string e, line, ``{
  233.     ret [pos2field[pos]:""] = e;
  234.     pos = pos +1;
  235.     });
  236.     return ret;
  237.   }
  238.  
  239.   /**
  240.    *  Find the list of all valid linux-partitions in the target-map.
  241.    *  @return list The list of names of valid linux-partitions.
  242.    */
  243.   global define list<string> LinuxPartitions(list checked_partitions) ``{
  244.  
  245.     if (Mode::test ()) return ["/dev/hda1", "/dev/hda2"];
  246.  
  247.     if (size (checked_partitions) == 0) return [];
  248. y2warning ("checked_partitions: %1", checked_partitions);
  249.  
  250.     // e.g.: ["/dev/hda1", "/dev/hdb2"]
  251.     list<string> linux_partition_list        = [];
  252.  
  253.     foreach (string device , map description, Storage::GetTargetMap(), {
  254.  
  255.     foreach (map partition, description["partitions"]:[], ``{
  256.  
  257. y2internal ("partition: %1", partition);
  258.         if ((partition["fsid"]:0 == Partitions::fsid_native ||
  259.          partition["type"]:`primary == `lvm ||
  260.          partition["type"]:`primary == `sw_raid))
  261.         {
  262.         // if the fsck functions have been executed
  263.         if (size (checked_partitions) != 0)
  264.         {
  265.             if (contains (checked_partitions,partition["device"]:""))
  266.             {
  267.             linux_partition_list = add (linux_partition_list,
  268.                                         partition["device"]:"");
  269.             }
  270.         }
  271.         else
  272.         {
  273.             linux_partition_list = add (linux_partition_list,
  274.                         partition["device"]:"");
  275.         }
  276.         }
  277.     });
  278.     });
  279.     if (size ( linux_partition_list) == 0)
  280.     y2error("no linux partition found");
  281.     return linux_partition_list;
  282.   };
  283.  
  284.  
  285.   /**
  286.    * Returns a list of names of all mountable partitions out of
  287.    * the specified list.
  288.    * @param list linux_partition_list A list of valid linux-partitions out of
  289.    *    which the mountable partitions are to be returned.
  290.    * @param m_point the test mountpoint
  291.    * @return list List of partition names successfully mounted to m_point.
  292.    */
  293.   global define list<string> MountablePartitions(
  294.             list<string> linux_partition_list, string m_point) ``{
  295.  
  296.     if (Mode::test () || size (linux_partition_list) == 0)
  297.     return linux_partition_list;
  298.  
  299.     // e.g.: ["/dev/hda1"]
  300.     list<string> mount_possible_list    = [];
  301.  
  302.     integer i = 0;
  303.     foreach (string partition_item, linux_partition_list, ``{
  304.  
  305.     if ((boolean) WFM::Execute (.local.mount,
  306.         [ partition_item, m_point, OSRExecute::OutputFile() ]))
  307.     {
  308.         mount_possible_list = add (mount_possible_list, partition_item);
  309.         if (!(boolean) WFM::Execute(.local.umount, m_point))
  310.         {
  311.         y2error("umounting partition %1 not possible",partition_item);
  312.         }
  313.     }
  314.     else
  315.     {
  316.         y2error("mounting partition %1 is not possible", partition_item);
  317.     }
  318.     i = i + 1;
  319.     });
  320.     return mount_possible_list;
  321.   };
  322.  
  323.  
  324.   /**
  325.    *  Returns a list of names of all mountable partitions that contain
  326.    *  a file /etc/fstab out of the specified list.
  327.    *  @param list linux_partition_list A list of valid linux-partitions
  328.    *    out of which the mountable partitions are to be returned.
  329.    *  @return list The list of partition-names that were successfully mounted
  330.    *    to /mnt and contain a filesystem table.
  331.    */
  332.   global define list<map> ValidRootPartitions (
  333.     list<string> mount_possible_list, string mount_p)
  334.   {
  335.  
  336.     if (Mode::test ())
  337.     return maplist (string p, mount_possible_list, ``($["device": p]));
  338.  
  339.     if (size (mount_possible_list) == 0) return [];
  340.  
  341.     // e.g.: [ "device" : "/dev/hda1", "label" : "SUSE Linux"]
  342.     list<map> valid_root_partitions    = [];
  343.     list<string> fstab_found_partitions    = [];
  344.     list<string> smpoints_found_partitions    = [];
  345.  
  346.     // mapping of device to the product label ($[ "/dev/hda1" : "SUSE Linux"])
  347.     map device2label    = $[];
  348.  
  349.     foreach (string partition_item, mount_possible_list, ``{
  350.  
  351.     if (! (boolean) WFM::Execute(.local.mount,
  352.         [ partition_item, mount_p , OSRExecute::OutputFile() ]))
  353.     {
  354.         y2error("Partition: %1; not possible to mount to /mnt",
  355.         partition_item);
  356.     }
  357.     else
  358.     {
  359.         device2label[partition_item] =
  360.         SuSERelease::ReleaseInformation (mount_p);
  361.         // Check fstab exist
  362.         // use the .local.size agent instead of the .etc.fstab agent
  363.         // because it finds the fstab of currently mounted root partition
  364.         if (WFM::Read (.local.size, mount_p + fstabpath) > 0)
  365.         {
  366.         y2milestone("Partition %1: fstab found", partition_item);
  367.         fstab_found_partitions = add (fstab_found_partitions,
  368.             partition_item);
  369.         }
  370.         else
  371.         {
  372.         y2milestone("Partition: %1; no fstab found", partition_item);
  373.         }
  374.         // Check system mount points
  375.         boolean not_fount = false;
  376.         foreach (string mp,  system_mount_points, ``{
  377.         if (mp != "/")
  378.         {
  379.             string cmd    = sformat ("/usr/bin/test -d %1%2", mount_p,mp);
  380.             y2debug ("command: %1", cmd);
  381.             if (!OSRExecute::Command (.local.bash, cmd))
  382.             {
  383.               not_fount = true;
  384.             }
  385.         }
  386.         });
  387.         if (! not_fount)
  388.         {
  389.         y2milestone("system mount points found");
  390.         smpoints_found_partitions = add (smpoints_found_partitions,
  391.             partition_item);
  392.         }
  393.         else
  394.         y2warning("system mount points not found. Partition %1 could not be a root partition", partition_item);
  395.     }
  396.     // umount the partition
  397.     WFM::Execute(.local.umount, mount_p);
  398.     });
  399.  
  400.     valid_root_partitions = maplist (string part, smpoints_found_partitions, {
  401.     return $[ "device" : part, "label" : device2label[part]:"?" ];
  402.     });
  403.  
  404.     y2milestone("ValidRootPartitions return %1", valid_root_partitions);
  405.     return valid_root_partitions;
  406.   };
  407.  
  408.   /**
  409.    * Read the fstab file.
  410.    */
  411.   global define boolean ReadFstab(string mount_p , boolean strict)``{
  412.  
  413.     root_mountpoint    = mount_p;
  414.     fstab        = Partitions::GetFstab(  mount_p + fstabpath);
  415.  
  416.     if (fstab == nil ||  size (fstab) == 0 || fstab["l"]:$[] == $[])
  417.     {
  418.     y2error("No fstab found !!");
  419.     if (strict) return false;
  420.  
  421.     // yes/no popup headline, fstab is file name
  422.     if (Popup::YesNoHeadline(_("Cannot Read fstab"),
  423.     // yes/no popup text
  424. _("
  425. No existing fstab file found. 
  426. Create a new one?
  427. ")))
  428.     {
  429.         OSRExecute::Command (.local.bash,
  430.         sformat ("/bin/mv %1%2 %1%2.YaSTsave",root_mountpoint,fstabpath));
  431.         OSRExecute::Command (.local.bash,
  432.         sformat ("/bin/touch %1%2", root_mountpoint, fstabpath));
  433.         fstab = Partitions::GetFstab (mount_p + fstabpath);
  434.         return true;
  435.     }
  436.     return false;
  437.     }
  438.     else
  439.     {
  440.     y2milestone ("fstab :%1 ", fstab);
  441.     return true;
  442.     }
  443.   }
  444.  
  445.   /**
  446.    * Removes blanks from a string.
  447.    */
  448.   define string remove_blanks (string c) ``{
  449.       return ( mergestring (splitstring (c ," "), ""));
  450.   }
  451.  
  452.   /**
  453.    * Cat the uuid from a string.
  454.    */
  455.   define string uuid_string(list<string> line) ``{
  456.  
  457.       if (substring (line[0]:"", 0, 4) == "UUID") {
  458.       return substring (line[0]:"", 5);
  459.       }
  460.       return "";
  461.   }
  462.  
  463.   /**
  464.    * Cat the label from a string.
  465.    */
  466.   define string label_string(list<string> line)``{
  467.  
  468.       if (substring (line[0]:"", 0,5) =="LABEL") {
  469.       return substring (line[0]:"",6);
  470.       }
  471.       return "";
  472.   }
  473.  
  474.   /**
  475.    * Check the spec (first) entry in a fstab line.
  476.    */
  477.   define boolean check_fs_spec( list<string> line, map part)``{
  478.  
  479.     string uuidstring    = uuid_string (line);
  480.     string labelstring    = label_string (line);
  481.  
  482.     return (contains (checked_partitions, line[0]:"")    ||
  483.         uuidstring   == part["uuid"]:"!"        ||
  484.         labelstring  == part["label"]:"!"
  485.    );
  486.   }
  487.  
  488.   /**
  489.    * Check the file (second) entry in a fstab line.
  490.    */
  491.   define boolean check_fs_file(list<string> line)``{
  492.  
  493.     if (line[1]:"" == nil || line[1]:"" == "")
  494.     return false;
  495.  
  496.     string dir = line[1]:"";
  497.     if (dir == "" || dir == nil)
  498.     return false;
  499.  
  500.     return (OSRExecute::Command (.local.bash,
  501.     sformat ("/usr/bin/test -d %1%2", root_mountpoint, dir)));
  502.   }
  503.  
  504.   /**
  505.    * Check the filesystem type (third) entry in a fstab line.
  506.    */
  507.   define boolean check_fs_vfstype(list<string> line, map part) ``{
  508.  
  509.     if (line[2]:"" == nil || line[2]:"" == "") return false;
  510.  
  511.     line[2] = remove_blanks (line[2]:"");
  512.  
  513.     if (!(FileSystems::GetMountString (part["detected_fs"]:`unknown, "!")
  514.         == line[2]:""
  515.       || line[2]:"" == "auto" || line[2]:"" == "subfs"))
  516.     {
  517.     return false;
  518.     }
  519.     return true;
  520.   }
  521.  
  522.   /**
  523.    * Check the mount options (fourth) entry in a fstab line.
  524.    */
  525.   define boolean check_fs_mntops(list<string> line) {
  526.  
  527.     if (line[3]:"" == nil || line[3]:"" == "") return false;
  528.  
  529.     map checked = FileSystems::CheckFstabOptions (remove_blanks(line[3]:""));
  530.     if (!checked["all_known"]:true)
  531.     {
  532.     y2error ("unknown mount options: %1",checked["unknown_options"]:"");
  533.     }
  534.     return checked["all_known"]:true;
  535.   }
  536.  
  537.   /**
  538.    * Check the freq (fifth) entry in a fstab line.
  539.    */
  540.   define boolean check_fs_freq(list<string> line, list<string> defaults)``{
  541.       if (line[4]:"" == nil || line[4]:"" == "") return false;
  542.  
  543.       return (( size (filterchars (remove_blanks (line[4]:"0"), digits)) > 0) &&
  544.           ( contains (defaults, remove_blanks (line[4]:"0"))));
  545.   }
  546.  
  547.   /**
  548.    * Check the passno (sixth) entry in a fstab line.
  549.    */
  550.   define boolean check_fs_passno(list<string> line, list<string> defaults)``{
  551.  
  552.     if (line[5]:"" == nil || line[5]:"" == "")
  553.     return false;
  554.  
  555.     if (size (filterchars (remove_blanks (line[5]:"0"), digits))
  556.     == size (remove_blanks (line[5]:"0")))
  557.     {
  558.     if (size (defaults) != 0)
  559.     {
  560.         return contains (defaults, remove_blanks (line[5]:"!"));
  561.     }
  562.     else
  563.     {
  564.         return true;
  565.     }
  566.     }
  567.     return false;
  568.   }
  569.  
  570.   /**
  571.    * Returns the partition map for a device.
  572.    * cdrom, floppy and zip devices are support too.
  573.    */
  574.   define map devname2part(string dev_name)``{
  575.  
  576.       if (substring (dev_name, 0,1) != "/") return $[];
  577.  
  578.       map ret = StorageDevices::GetCdromEntry( dev_name);
  579.       if (ret == $[] || ret == nil) {
  580.  
  581.       ret = find(map e, StorageDevices::cddrives, ``(e["linkname"]:"" == dev_name));
  582.  
  583.       // check link
  584.       if (ret == nil) {
  585.           OSRExecute::CommandOutput(.local.bash, sformat ("/bin/ls -l %1", dev_name));
  586.           list<string> std_dev_list = filter (string s,  splitstring (OSRExecute::stdout, " "), ``( s != " "));
  587.           string link    = std_dev_list[size (std_dev_list)-1]:"";
  588.           list linkl    = splitstring (link , "\n");
  589.           link        = linkl[0]:"";
  590.           y2milestone("link is %1", link);
  591.           if (! issubstring (link , "/dev"))
  592.           {
  593.           link = "/dev/" + link ;
  594.           }
  595.           y2milestone("new link %1", link);
  596.           ret = StorageDevices::GetCdromEntry( link);
  597.           if (ret == $[] || ret == nil)
  598.           {
  599.           //y2milestone(" StorageDevices :: %1 " ,StorageDevices::cddrives);
  600.           ret = find(map e, StorageDevices::cddrives, ``(e["linkname"]:"" == link));
  601.           }
  602.           y2milestone(" ret in check link %1", ret);
  603.       }
  604.       }
  605.  
  606.       if (ret == $[] || ret == nil) {
  607.       ret =  find(map e, StorageDevices::FloppyDrives, ``(e["dev_orig"]:(e["dev_name"]:"") == dev_name));
  608.       if (ret != $[] && ret != nil) ret["found"] = "floppy";
  609.       }
  610.       else {
  611.       ret["found"] = "cdrom";
  612.       }
  613.  
  614.       if (ret == $[] || ret == nil)
  615.       {
  616.     list lret    = maplist (string n, map m,
  617.         filter (string k, map e, (map<string,map>)StorageDevices::ZipDrives,
  618.         ``(e["dev_orig"]:(e["dev_name"]:"") == dev_name)), ``(m));
  619.     ret        = lret[0]:$[];
  620.     if (ret != $[] && ret != nil) ret["found"] = "zip";
  621.       }
  622.  
  623.       if (ret == $[] || ret == nil)
  624.       {
  625.       ret = Storage::GetPartition( Storage::GetTargetMap(), dev_name );
  626.       if (ret != $[] && ret != nil) {
  627.           if (ret["device"]:"" == dev_name)
  628.           {
  629.           ret["dev_name"] = dev_name;
  630.           if (ret["fsid"]:0 == Partitions::fsid_swap) {
  631.               ret["found"] = "swap";
  632.           }
  633.           else {
  634.               ret["found"] ="dev";
  635.           }
  636.           if (ret["mount"]:"" == "/")
  637.           {
  638.               ret["found"] = "root";
  639.           }
  640.           }
  641.           else {
  642.           // Storage return default !!
  643.           ret = $[];
  644.           }
  645.       }
  646.       }
  647.       return ret;
  648.   };
  649.  
  650.   /**
  651.    * Check if an entry for a device exist in the fstab.
  652.    */
  653.   define boolean check_dev_entry(string p)``{
  654.  
  655.     map part  =  devname2part(p);
  656.     map lines =  filter (integer lnr, map line, fstab["l"]:$[], ``(
  657.  
  658.     (line["fields",0]:"!" == p)                ||
  659.     (line["fields",0]:"!" == part["linkname"]:"" &&
  660.      part["found"]:"" == "cdrom")                ||
  661.         (line["fields",0]:"!" == "UUID=" + part["uuid"]:"")    ||
  662.         (line["fields",0]:"!" == "LABEL=" + part["label"]:""))
  663.    );
  664.     if (size (lines) > 0)
  665.     {
  666.     y2milestone("found entry for %1 in the fstab", p);
  667.     return true;
  668.     }
  669.     else
  670.     {
  671.     y2warning ("no entry for %1 found in the fstab",p);
  672.     if (part["used_by"]:"" != "")
  673.     {
  674.         y2warning ("it is a device used by other entity (e.g. LVM, EVMS, MD): ignoring");
  675.         return true;
  676.     }
  677.     missing_devs = add (missing_devs, p);
  678.     missing_devs = toset (missing_devs);
  679.     return false;
  680.     }
  681.   }
  682.  
  683.  
  684.   /**
  685.    * Return the partition map for a special uuid.
  686.    */
  687.   define map uuid2part(string uuidstring) {
  688.       map ret = $[];
  689.       foreach (string dn, checked_partitions, {
  690.       if (ret == $[]) {
  691.           map part = devname2part(dn);
  692.           if (part ["uuid"]:"" == uuidstring)
  693.           {
  694.           ret = devname2part(dn);
  695.           ret["wise"] = "uuid" ;
  696.           }
  697.       }
  698.       });
  699.       return ret;
  700.   }
  701.  
  702.   /**
  703.    * Return the partition map for a special label.
  704.    */
  705.   define map label2part(string labelstring) {
  706.       map ret = $[];
  707.       foreach (string dn, checked_partitions, {
  708.       if (ret == $[]) {
  709.           map part = devname2part(dn);
  710.           if (part ["label"]:"!" == labelstring) {
  711.           ret = devname2part( dn);
  712.           ret["wise"] = "label";
  713.           }
  714.       }
  715.       });
  716.       return ret;
  717.   }
  718.  
  719.   /**
  720.    * Return the partition map for a fstab line.
  721.    */
  722.   define map line2part(list<string> line) ``{
  723.  
  724.       if (contains (fstab_default_exist ("spec", "spec"), line[0]:""))
  725.       return $[];
  726.  
  727.       map ret = devname2part(line[0]:"");
  728.       if (ret == nil || ret == $[])
  729.       {
  730.       string uuidstring    = uuid_string(line);
  731.       if (uuidstring != "")
  732.           ret = uuid2part (uuidstring);
  733.       if (ret == nil || ret == $[])
  734.       {
  735.           string labelstring = label_string(line);
  736.           if (labelstring != "")
  737.           ret = label2part( labelstring);
  738.       }
  739.       }
  740.       else
  741.       {
  742.       ret["wise"] = "dev";
  743.       }
  744.       y2milestone("line2part return: %1", ret);
  745.       return ret;
  746.   }
  747.  
  748.  
  749.   /**
  750.    * Check one fstab line and return false if
  751.    * the line contains errors.
  752.    */
  753.   define boolean check_fstab_line( integer lnr)``{
  754.  
  755.     map linemap        = AsciiFile::GetLine(fstab, lnr);
  756.     list<string> line    = linemap["fields"]:[];
  757.  
  758.     // empty line ?
  759.     if (size (filter (string pos, line, ``( pos != "" && pos != " "))) == 0 ||
  760.     line == [])
  761.     {
  762.     y2milestone(" add empty line to valid_lines ");
  763.     valid_lines  = add (valid_lines , lnr);
  764.     return true;
  765.     }
  766.  
  767.     map part            = line2part(line);
  768.  
  769.     string  type        = "invalid";
  770.     boolean fs_spec        = false;
  771.     boolean fs_file        = false;
  772.     boolean fs_vfstype        = false;
  773.     boolean fs_mntops        = false;
  774.     boolean fs_freq        = false;
  775.     boolean fs_passno        = false;
  776.  
  777.     if (part == nil || part == $[] || size (part)<=0)
  778.     {
  779.     if (line[0]:"" == fstab_defaults["usb","spec"]:"!")
  780.     {
  781.         if (Hotplug::haveUSB)
  782.         {
  783.         type    = "usb";
  784.         fs_spec    = true;
  785.         fs_file    = (line[1]:"" == fstab_defaults[type,"mount"]:"!");
  786.         fs_vfstype = (line[2]:"" == fstab_defaults[type,"vfstype"]:"!");
  787.         fs_mntops  = check_fs_mntops (line);
  788.         }
  789.         else
  790.         {
  791.         y2error("usb line in fstab but no usb found");
  792.         type        = "usb";
  793.         fs_spec        = false;
  794.         fs_file        = true;
  795.         fs_vfstype    = true;
  796.         fs_mntops    = true;
  797.         }
  798.     }
  799.     else if (issubstring (line[0]:"", ":/"))
  800.     {
  801.         // nfs
  802.         type    = "nfs";
  803.         fs_spec    = true; // no check
  804.         fs_file    = check_fs_file (line);
  805.         fs_vfstype    = true; // no check
  806.         fs_mntops    = true; // no check
  807.     }
  808.     else if (line[0]:"" == fstab_defaults["pts","spec"]:"!")
  809.     {
  810.         type    = "pts";
  811.         fs_spec    = true;
  812.         fs_file    = check_fs_file (line);
  813.         fs_vfstype    = ( line[2]:"" == fstab_defaults[type,"vfstype"]:"!");
  814.         fs_mntops    = ( line[3]:"" != nil && line[3]:"" != "");
  815.     }
  816.     else if (line[0]:"" == fstab_defaults["proc","spec"]:"!")
  817.     {
  818.         type    = "proc";
  819.         fs_spec    = true;
  820.         fs_file    = ( line[1]:"" == fstab_defaults[type,"mount"]:"!");
  821.         fs_vfstype    = ( line[2]:"" == fstab_defaults[type,"vfstype"]:"!");
  822.         fs_mntops    = ( line[3]:"" != nil && line[3]:"" != "");
  823.     }
  824.     else if (line[0]:"" == fstab_defaults["sys","spec"]:"!")
  825.     {
  826.         type    = "sys";
  827.         fs_spec    = true;
  828.         fs_file    = ( line[1]:"" == fstab_defaults[type,"mount"]:"!");
  829.         fs_vfstype    = ( line[2]:"" == fstab_defaults[type,"vfstype"]:"!");
  830.         fs_mntops    = ( line[3]:"" != nil && line[3]:"" != "");
  831.     }
  832.     fs_freq        = check_fs_freq (
  833.         line, [ tostring (fstab_defaults [type, "freq"]:0) ]);
  834.     fs_passno    = check_fs_passno (
  835.         line, [ tostring (fstab_defaults [type, "passno"]:0) ]);
  836.     }
  837.     else
  838.     {
  839.     list<string> special_freq    = [];
  840.     list<string> special_passno    = [];
  841.  
  842.     // cdrom floppy zip
  843.     if (part["found"]:"" == "floppy" ||
  844.         part["found"]:"" == "zip"    ||
  845.         part["found"]:"" == "cdrom")
  846.     {
  847.         type    = part["found"]:"";
  848.         fs_spec    = true;
  849.         fs_file    = check_fs_file(line);
  850.         fs_vfstype    = check_fs_vfstype(line, part);
  851.         fs_mntops    = check_fs_mntops( line);
  852.     }
  853.     else if (contains (checked_partitions, part["dev_name"]:"") &&
  854.          part["found"]:"" == "dev")
  855.     {
  856.         // check root first with CheckRootEntry!!
  857.         if (line[1]:"" == "/")
  858.         return true;
  859.         type    = "dev";
  860.         fs_spec    = true;
  861.         fs_file    = check_fs_file(line);
  862.         fs_vfstype    = check_fs_vfstype(line, part);
  863.         fs_mntops    = check_fs_mntops( line);
  864.  
  865.         special_passno    = [ "2" ];
  866.         special_freq    = [ "1" ];
  867.         // add mount point to target_map for later use (OSRBoot)
  868.         part["mount"]    = line[1]:"";
  869.         Storage::ChangeVolumeProperties(part);
  870.     }
  871.     else if (contains (swapable_partition_list, part["dev_name"]:"") &&
  872.          part["found"]:"" == "swap")
  873.     {
  874.         type    = "swap";
  875.         fs_file    = true;
  876.         fs_spec    = (line[1]:"" == "swap");
  877.         fs_vfstype    = ( line[2]:"" == "swap");
  878.         // TODO the default could be checked by
  879.         // FileSystems::GetFstabDefaultMntops ("swap")
  880.         fs_mntops    = check_fs_mntops (line);
  881.     }
  882.     else if (part["found"]:"" == "root")
  883.     {
  884.         fs_spec    = true;
  885.         fs_file    = true;
  886.         fs_vfstype  = true;
  887.         fs_mntops   = true;
  888.         fs_freq     = true;
  889.         fs_passno   = true;
  890.     }
  891.     else
  892.     {
  893.         y2error("not valid fstab entry found");
  894.     }
  895.  
  896.     // not check for root
  897.     if (type != "" &&
  898.         contains (["dev", "swap","floppy", "zip", "cdrom"], type))
  899.     {
  900.         fs_freq    = check_fs_freq (line,
  901.         add (special_freq, tostring (fstab_defaults [type, "freq"]:0)));
  902.         fs_passno  = check_fs_passno (line,
  903.         add (special_passno,tostring(fstab_defaults[type,"passno"]:0)));
  904.     }
  905.     }
  906.     if (! fs_spec)
  907.     {
  908.     y2error("%1 spec not valid", line[0]:"");
  909.     }
  910.     if (! fs_file)
  911.     {
  912.     y2error("%1 file not valid", line[0]:"");
  913.     }
  914.     if (! fs_vfstype)
  915.     {
  916.     y2error("%1 fstype not valid",line[0]:"");
  917.     }
  918.     if (! fs_mntops)
  919.     {
  920.     y2error("%1 mntops not valid",line[0]:"");
  921.     }
  922.     if (! fs_freq)
  923.     {
  924.     y2error("%1 freq not valid",line[0]:"");
  925.     }
  926.     if (! fs_passno)
  927.     {
  928.     y2error("%1 passno not valid",line[0]:"");
  929.     }
  930.  
  931.     if (fs_spec && fs_file && fs_vfstype && fs_mntops && fs_freq && fs_passno)
  932.     {
  933.     valid_lines  = add (valid_lines , lnr);
  934.     y2milestone("fstab line nr %1 entry is valid", lnr);
  935.     }
  936.     else
  937.     {
  938.     y2error("fstab line nr %1 is not valid", lnr);
  939.     not_valid_lines [lnr] =
  940.         [type, fs_spec, fs_file, fs_vfstype, fs_mntops, fs_freq, fs_passno];
  941.     }
  942.     return (fs_spec && fs_file && fs_vfstype && fs_mntops && fs_freq &&
  943.         fs_passno);
  944.   }
  945.  
  946.   /**
  947.    * All device that should be checked.
  948.    */
  949.   define list<string> devices2check()``{
  950.       list<string> dev2check = (list<string>)
  951.     union (
  952.         union (checked_partitions, swapable_partition_list),
  953.         [
  954.         fstab_defaults ["usb", "spec"]:"",
  955.         fstab_defaults ["proc", "spec"]:"",
  956.         fstab_defaults ["pts", "spec"]:""
  957.         ]
  958.     );
  959.       dev2check = (list<string>) union (dev2check,
  960.     maplist (map d, StorageDevices::cddrives,
  961.         ``(d["dev_orig"]:(d["dev_name"]:""))));
  962.  
  963.       dev2check = (list<string>) union (dev2check,
  964.     maplist (map d, StorageDevices::FloppyDrives,
  965.         ``(d["dev_orig"]:(d["dev_name"]:""))));
  966.  
  967.       dev2check = (list<string>) union (dev2check,
  968.     maplist (string k, map d, (map<string,map>) StorageDevices::ZipDrives,
  969.         ``(d["dev_orig"]:(d["dev_name"]:""))));
  970.  
  971.       return dev2check;
  972.   }
  973.  
  974.   /**
  975.    * Check if all entries in the fstab are valid and
  976.    * if all found devices have an entry in the fstab.
  977.    */
  978.   global define boolean Check(list<string> tswapable_partition_list,
  979.                   list<string> tchecked_partitions) ``{
  980.  
  981.       ResetSettings();
  982.       swapable_partition_list = tswapable_partition_list;
  983.       checked_partitions      = tchecked_partitions;
  984.  
  985.       // check all lines in existing fstab file 
  986.       foreach (integer lnr, map line, fstab["l"]:$[], ``{
  987.       y2milestone("----check fstab line %1 ", lnr);
  988.       if (! contains (valid_lines, lnr))
  989.           check_fstab_line(lnr);
  990.       });
  991.       // check all mountable partitions + swap + usb+ proc +...
  992.       foreach (string p, devices2check(), ``{
  993.       y2milestone("-----check partition and usb,proc,pts %1", p);
  994.       check_dev_entry(p);
  995.       });
  996.  
  997.       return ((size (missing_devs) == 0)  && (size (not_valid_lines) == 0));
  998.   }
  999.  
  1000.   /**
  1001.    * Build items for table in missing devices dialog.
  1002.    */
  1003.   define list<term> missing_devs_items( map new_entries)``{
  1004.       list<term> item_list = [];
  1005.       foreach (string k, map<string,any> e, (map<string,map<string,any> >)new_entries, ``{
  1006.       item_list = add (item_list, `item(`id(k), k, e["mount"]:""));
  1007.       });
  1008.       return item_list;
  1009.   }
  1010.  
  1011.   define string find_next_media_file(string type)``{
  1012.       integer num = 0;
  1013.       string  mp  = "/media/" + type;
  1014.       while (true) {
  1015.       if (AsciiFile::FindLineField(fstab, 1,mp) == [])
  1016.           return mp;
  1017.       else {
  1018.           num = num +  1;
  1019.           mp = sformat ("%1%2",mp,num);
  1020.       }
  1021.       }
  1022.   }
  1023.  
  1024.   define list<string> used_mount_points(map fstab)``{
  1025.  
  1026.       list<string> ret = [];
  1027.       foreach (integer lnr, map ldata, fstab["l"]:$[], ``{
  1028.       ret = add (ret , ldata["fields", 1 ]:"");
  1029.       });
  1030.       return ret;
  1031.   }
  1032.  
  1033.   /**
  1034.    * Build fstab entries for all existing devices that are not listed
  1035.    * in the fstab.
  1036.    */
  1037.   define map suggest_missing_entries()``{
  1038.  
  1039.     if (Mode::test ()) return $[ "/dev/hda1" : $[ "mount" : "/hh" ]];
  1040.  
  1041.     integer other_nr = 1;    // count other mounts -> global for wirte_fstab
  1042.     map new_entries = $[];
  1043.  
  1044.     missing_devs = sort (string d1, string d2, missing_devs , ``( d1 < d2));
  1045.  
  1046.     foreach (string dev, missing_devs, {
  1047.  
  1048.     map part      = devname2part(dev);
  1049.     if (part != nil && part != $[] &&
  1050.         contains (["dev", "swap", "root"], part["found"]:"" ))
  1051.     {
  1052.         part["device"] = dev;
  1053.         integer nr = 1;
  1054.         map fstabentry            = Storage::onepartition2fstab(part,nr);
  1055.         list<string> used_mountpoints    = used_mount_points(fstab);
  1056.         string start            = "/data";
  1057.         integer count            = 2;
  1058.  
  1059.         // fstabentry could be empty map for some partitions (e.g.
  1060.         // with LVM group) -> suggest_missing_entries could report error 4
  1061.         while (contains (used_mountpoints , fstabentry["mount"]:""))
  1062.         {
  1063.         // find new mount point
  1064.         fstabentry["mount"] = sformat ("%1%2", start, count);
  1065.         count = count + 1;
  1066.         y2milestone("new mount point %1 ", fstabentry["mount"]:"");
  1067.         }
  1068.         if (size (fstabentry)>0)
  1069.         {
  1070.         new_entries[dev] =  fstabentry;
  1071.         }
  1072.     }
  1073.     else if (contains (fstab_default_exist ("spec", "spec"), dev))
  1074.     {
  1075.         string type    = "";
  1076.         foreach (string key, map descr, fstab_defaults, {
  1077.         if (descr["spec"]:"" == dev)
  1078.             type    = key;
  1079.         });
  1080.         new_entries[dev]    = fstabline2map ((list<string>)
  1081.         FileSystems::GetFstabDefaultList (type));
  1082.     }
  1083.     else if (contains (["zip", "floppy"], part["found"]:""))
  1084.     {
  1085.         map fstline        = fstabline2map ((list<string>)
  1086.         FileSystems::GetFstabDefaultList (part["found"]:""));
  1087.         fstline["spec"]    = part["dev_orig"]:(part["dev_name"]:"");
  1088.         fstline["mount"]    = find_next_media_file (part["found"]:"");
  1089.         new_entries[dev]    = fstline;
  1090.     }
  1091.     else if ("cdrom" == part["found"]:"")
  1092.     {
  1093.         map ret        = Storage::MakeCdromFstabEntry (part);
  1094. //        new_entries[dev]    = ret; // workaround for bug #185575
  1095.     }
  1096.     else {
  1097.         y2error("creating an entry for %1 is not possible (3)", dev);
  1098.     }
  1099.     });
  1100.     if (size (new_entries) == 0) {
  1101.     y2error("creating fstab entries is not possible (4)");
  1102.     }
  1103.     else {
  1104.     y2milestone("Suggested new fstab entries %1", new_entries);
  1105.     }
  1106.     return new_entries;
  1107.   }
  1108.  
  1109.   /**
  1110.    * @param cmp:
  1111.    *      fstab line nr  : mount point
  1112.    * cmp : $[ 1         : "/hhh",
  1113.    *          2         : "/mnt/uuu" ];
  1114.    *
  1115.    * @return create failed for mount points $[ 1        : "/hhh" ];
  1116.    */
  1117.   global define map check_and_create_mount_points(map cmp) ``{
  1118.  
  1119.     map failed = $[];
  1120.     foreach (integer lnr, string missing_dir, (map<integer,string>) cmp, ``{
  1121.         if (substring (missing_dir , 0,1) == "/")
  1122.         {
  1123.         list<string> subdirs = filter (string  sdir, splitstring (missing_dir, "/"), ``( sdir != ""));
  1124.         string mkdir = root_mountpoint + "/";
  1125.         foreach (string sdir, subdirs, ``{
  1126.             mkdir = mkdir + "/"+ sdir;
  1127.             if (! OSRExecute::Command(.local.bash, sformat ("/usr/bin/test -d %1", mkdir)))
  1128.             OSRExecute::Command(.local.bash, sformat ("/bin/mkdir %1", mkdir));
  1129.         });
  1130.         if (! OSRExecute::Command(.local.bash, sformat ("/usr/bin/test -d %1", root_mountpoint + missing_dir)))
  1131.         {
  1132.             failed[lnr] =  missing_dir;
  1133.         }
  1134.         }
  1135.     });
  1136.  
  1137.     if (size (failed) == 0)
  1138.     {
  1139.         // popup message
  1140.         Report::Message(_("
  1141. All missing mount points were
  1142. created successfully.
  1143. "));
  1144.     }
  1145.     else if (size (failed) > 1)
  1146.     {
  1147.         // error popup
  1148.         Report::Error (sformat (_("
  1149. Could not create the
  1150. following mount points:
  1151. %1
  1152. "), mergestring ((list<string>)
  1153.         maplist (integer lnr, string dir, (map<integer,string>) failed,``(dir)), "\n")));
  1154.     }
  1155.     else if (size (failed) == 1)
  1156.     {
  1157.         Report::Error(sformat (_("
  1158. Could not create the 
  1159. mount point:
  1160. %1
  1161. "), mergestring ((list<string>)
  1162.         maplist (integer lnr, string dir,(map<integer,string>) failed, ``(dir)), "\n")));
  1163.     }
  1164.     return failed;
  1165.   }
  1166.  
  1167.   /**
  1168.    * Dialog for existing devices that are not listed in the fstab.
  1169.    */
  1170.   define symbol SuggestMissingEntriesDialog()``{
  1171.  
  1172.       map new_entries   = suggest_missing_entries();
  1173.  
  1174.       if (size (new_entries) == 0) return `error;
  1175.  
  1176.       string help_text = _("
  1177. <P>No valid fstab entry was found
  1178. for the devices listed in the table.
  1179. </P>
  1180. <P>
  1181. Select the devices for which 
  1182. to create a new fstab entry
  1183. and enter a mount point.
  1184. </P>
  1185. <P>After creating mount points for all
  1186. devices, press Repair 
  1187. to continue.
  1188. </P>
  1189. ");
  1190.       help_text = help_text +
  1191.  
  1192.       
  1193.       OSRPopup::build_label_description (device_label, _("The name of the device for which no valid fstab
  1194. entry was found.
  1195. ")) +
  1196.  
  1197.       OSRPopup::build_label_description (mount_label, _("The mount point for the found device. This
  1198. mount point is created in the file system. If you leave the mount point field empty, no fstab entry will be created.
  1199. ")) +
  1200.  
  1201.       OSRPopup::build_label_description (create_mp_label, _("Add a mount point for a device."));
  1202.  
  1203.       OSRPopup::OpenSuggestDialog(_("Add fstab Entries"),
  1204.                   _("
  1205. Select the devices for which to
  1206. create a new fstab entry and enter a mount point.
  1207. "),
  1208.                   help_text,
  1209.                   `VBox(`Left(`Label(_("Devices without Valid fstab Entry"))),
  1210.                     `Table(`id(`table), `header(device_label, mount_label), missing_devs_items(new_entries)),
  1211.                     `Right(`PushButton(`id(`mountpoint), create_mp_label))) ,70 );
  1212.  
  1213.  
  1214.     symbol ret       = `ok;
  1215.     repeat
  1216.     {
  1217.     ret = (symbol) UI::UserInput();
  1218.  
  1219.     if (ret == `mountpoint)
  1220.     {
  1221.         string current = (string)UI::QueryWidget(`id(`table),`CurrentItem);
  1222.         if (current != nil && current != "")
  1223.         {
  1224.         string text = OSRPopup::ChangeFieldDialog (
  1225.             new_entries[current,"mount"]:"",
  1226.             // TextEntry label, %1 is device label
  1227.             sformat (_("
  1228. Mount Point for %1
  1229. "), new_entries[current,"spec"]:""));
  1230.  
  1231.         if (text != nil)
  1232.         {
  1233.             new_entries[current,"mount"] = text;
  1234.             UI::ChangeWidget(`id(`table),
  1235.             `Items, missing_devs_items (new_entries));
  1236.         }
  1237.         }
  1238.     }
  1239.  
  1240.     if (ret == `ok)
  1241.     {
  1242.         integer changed_size = size (
  1243.         filter (string k,map e, (map<string,map<string,any> >)new_entries, ``(
  1244.             e["spec"]:"" != "" && e["mount"]:"" != ""))
  1245.         );
  1246.         if (changed_size == 0)
  1247.         {
  1248.         Report::Warning(_("
  1249. First create mount points
  1250. for the listed devices.
  1251. "));
  1252.         ret = `notok;
  1253.         continue;
  1254.         }
  1255.         else if (changed_size < size (new_entries))
  1256.         {
  1257.         // yes/no popup headline
  1258.         if (!Popup::YesNoHeadline (_("Empty Mount Point"),
  1259.         // yes/no popup text
  1260. _("
  1261. Valid mount points are required to
  1262. create fstab entries for devices.
  1263. You did not enter a mount point
  1264. for all devices. If you continue
  1265. now, fstab entries are only created
  1266. for devices with mount points. 
  1267. Really continue?
  1268. ")))
  1269.         {
  1270.             ret = `notok;
  1271.             continue;
  1272.         }
  1273.         }
  1274.         // create mount point (cmp)
  1275.         map cmp         = $[];
  1276.         integer fack_lnr = 0;
  1277.         foreach (string k, map e, (map<string,map<string,any> >)new_entries, ``{
  1278.         if (e["spec"]:"" != "" && e["mount"]:"" != ""){
  1279.             list<string> fstlist = [ k , e["mount"]:"",
  1280.                          e["vfstype"]:"", e["mntops"]:"",
  1281.                          sformat ("%1",e["freq"]:nil),
  1282.                          sformat ("%1",e["passno"]:nil) ];
  1283.  
  1284.             cmp[fack_lnr] =  e["mount"]:"";
  1285.             fack_lnr      =  fack_lnr + 1;
  1286.             AsciiFile::AppendLine( fstab, fstlist);
  1287.         }
  1288.         });
  1289.  
  1290.         map failed = check_and_create_mount_points(cmp);
  1291.         if (size (failed) > 0) ret =  `error;
  1292.     }
  1293.     } until( ret == `ok || ret == `cancel || ret == `error);
  1294.  
  1295.     UI::CloseDialog();
  1296.     return ret;
  1297.   }
  1298.  
  1299.  
  1300.  
  1301.   /**
  1302.    *
  1303.    */
  1304.   define map suggest_create_mp()``{
  1305.  
  1306.     // found fstab line without valid mount point, e.g. (not_valid_lines):
  1307.     // $[4: ["dev", false, true, true ,true ,true ,true ]], //spec error
  1308.     list<integer> cmpl =  maplist (integer kk, list vv,
  1309.     filter (integer k, list v, (map<integer,list>) not_valid_lines,
  1310.     {
  1311.         return
  1312.         v[1]:true == true    &&
  1313.         v[2]:true == false    &&
  1314.         substring (fstab [4, "fields", 1]:"", 0, 1) == "/"  &&
  1315.         (fstab_defaults[v[0]:"","mount"]:"" == "" || v[0]:"" == "pts");
  1316.     }),
  1317.     ``(kk)
  1318.     );
  1319.  
  1320.     if (Mode::test ()) cmpl = [1,2];
  1321.     return AsciiFile::GetLines (fstab, cmpl);
  1322.   }
  1323.  
  1324.  
  1325.   /**
  1326.    *
  1327.    */
  1328.   define list<term> create_mp_items(map cmp)``{
  1329.       list<term> ret = [];
  1330.       foreach (integer lnr, map v, (map<integer,map<string,any> >)cmp, ``{
  1331.       ret = add (ret,
  1332.         `item (`id(lnr), create_label, v["fields",1]:"", v["fields",0]:""));
  1333.       });
  1334.       return ret;
  1335.   }
  1336.  
  1337.   /**
  1338.    *
  1339.    */
  1340.   define symbol SuggestCreateMp()``{
  1341.       map missing_create_mp = suggest_create_mp();
  1342.  
  1343.       if (size (missing_create_mp) == 0) return `ok;
  1344.  
  1345.       // help text
  1346.       string help_text = _("
  1347. <P>The /etc/fstab file does not contain
  1348. valid mount points for the listed devices.
  1349. </P>") +
  1350.       //%1 is Ignore label and %2 is Create label
  1351.       OSRPopup::build_label_description (state_label, sformat (_("
  1352. The status of a listed line can be switched between
  1353. %1 and %2. Mount points for a partition are only created
  1354. if the the status is %2.
  1355. "), ignore_label, create_label)) +
  1356.  
  1357.  
  1358.       OSRPopup::build_label_description (mount_label, _("
  1359. This field contains the present entry
  1360. of the mount point in fstab.
  1361. Change this field to a valid mount point.
  1362. If you do not want to create the mount point,
  1363. select the corresponding line in the table and change
  1364. the status to ignore.
  1365. ")) +
  1366.       // %1 is Ignore label
  1367.       OSRPopup::build_label_description (b_ignore_label, sformat (_("Change the status of the line to %1.
  1368. "),ignore_label)) +
  1369.  
  1370.       // %1 is Create label
  1371.       OSRPopup::build_label_description (b_create_label, sformat (_("Change the status of the line to %1.
  1372. "), create_label));
  1373.  
  1374.       OSRPopup::OpenSuggestDialog( _("Create Mount Points"),
  1375.                    _("
  1376. Some mount points for fstab entries are missing in
  1377. the file system. Change the status of the
  1378. lines for which to create a mount point.
  1379. "),
  1380.                    help_text,
  1381.                    `VBox(`Left(`Label(_("Missing or Invalid Mount Points"))),
  1382.                      `Table(`id(`table), `header( state_label, mount_label, device_label ),
  1383.                         create_mp_items(missing_create_mp)),
  1384.                       `HBox(`PushButton(`id(`ignore), b_ignore_label),
  1385.                         `PushButton(`id(`create), b_create_label),
  1386.                         `Right(`PushButton(`id(`change),  b_change_mp_label))),
  1387.                      `VSpacing(1)
  1388.                      ), 50);
  1389.  
  1390.     UI::SetFocus(`id(`table));
  1391.     symbol ret       = `ok;
  1392.     map    cmp       = $[];
  1393.     repeat
  1394.     {
  1395.     ret = (symbol) UI::UserInput();
  1396.     integer current_item  = (integer)
  1397.         UI::QueryWidget(`id(`table), `CurrentItem);
  1398.  
  1399.     if (ret == `ignore)
  1400.     {
  1401.         UI::ChangeWidget (`id(`table), `Item(current_item,0), ignore_label);
  1402.     }
  1403.     else if (ret == `create)
  1404.     {
  1405.         UI::ChangeWidget (`id(`table), `Item(current_item,0), create_label);
  1406.     }
  1407.     else if (ret == `change)
  1408.     {
  1409.         integer current = (integer)
  1410.         UI::QueryWidget(`id(`table), `CurrentItem);
  1411.         if (current != nil)
  1412.         {
  1413.         string text = OSRPopup::ChangeFieldDialog (
  1414.             // TextEntry label, %1 is device
  1415.             missing_create_mp [current,"fields",1]:"", sformat (_("
  1416. Mount Point for %1
  1417. "), missing_create_mp[current,"fields",0]:""));
  1418.  
  1419.  
  1420.         if (text != nil)
  1421.         {
  1422.             missing_create_mp[current,"fields",1] = text;
  1423.             UI::ChangeWidget (`id(`table), `Items,
  1424.             create_mp_items (missing_create_mp));
  1425.         }
  1426.         }
  1427.     }
  1428.     else if (ret == `ok)
  1429.     {
  1430.         cmp = $[];
  1431.         foreach (integer e, map lines, (map<integer,map>) missing_create_mp,
  1432.         {
  1433.         term it    = (term) UI::QueryWidget(`id(`table), `Item(e));
  1434.         if (it[1]:"" == create_label)
  1435.         {
  1436.             cmp[e] = lines["fields", 1]:"";
  1437.         }
  1438.         });
  1439.     }
  1440.     } until( ret == `ok || ret == `cancel);
  1441.  
  1442.     UI::CloseDialog();
  1443.  
  1444.     if (ret == `ok)
  1445.     {
  1446.     map failed = check_and_create_mount_points( cmp);
  1447.  
  1448.     if (size (failed) == 0)
  1449.     {
  1450.         foreach (integer lnr, string dir, (map<integer,string>) cmp,``{
  1451.         fstab["l",lnr,"fields",1] = dir;
  1452.         // rebuild the hole entry
  1453.         not_valid_lines[lnr,3] = false;
  1454.         not_valid_lines[lnr,4] = false;
  1455.         not_valid_lines[lnr,5] = false;
  1456.         not_valid_lines[lnr,6] = false;
  1457.         });
  1458.     }
  1459.     else if (size (failed) > 1)
  1460.     {
  1461.         // suggest to remove the line
  1462.         foreach (integer lnr, string dir, (map<integer,string>) failed, ``{
  1463.         not_valid_lines = filter (integer llnr, list<any> v, (map<integer,list<any> >)not_valid_lines,
  1464.             ``( llnr != lnr));
  1465.         });
  1466.         ret = `error;
  1467.     }
  1468.     else if (size (failed) == 1)
  1469.     {
  1470.         // suggest to remove the line
  1471.         foreach (integer lnr, string dir, (map<integer,string>) failed, ``{
  1472.         not_valid_lines = filter (integer llnr, list<any> v, (map<integer,list<any> >)not_valid_lines,
  1473.             ``( llnr != lnr));
  1474.         });
  1475.         ret = `error;
  1476.     }
  1477.     }
  1478.     return ret;
  1479.   }
  1480.  
  1481.   /**
  1482.    * Find all fstab entries (line nr) with not existing devices.
  1483.    */
  1484.   define list<integer> suggest_remove_spec()``{
  1485.     // spec not valid (false) -> remove
  1486.     list<integer> rm = (list<integer>) maplist (integer n, list m,
  1487.     filter (integer k, list<any>v, (map<integer,list<any> >)not_valid_lines, ``( v[1]:true == false)),
  1488.     ``(n));
  1489.     return rm;
  1490.   }
  1491.  
  1492.   /**
  1493.    * Build a item list for all fstab entries with not existing devices.
  1494.    */
  1495.   define list<term> remove_spec_items(list<integer> rm_entries, string ignore_label)
  1496.   {
  1497.  
  1498.     list<term> ret = [];
  1499.     foreach (integer lnr, rm_entries, {
  1500.     map line    = AsciiFile::GetLine (fstab, lnr);
  1501.     ret = add (ret, `item (`id(lnr), ignore_label, line["line"]:""));
  1502.     });
  1503.     return ret;
  1504.   }
  1505.  
  1506.   /**
  1507.    * Dialog for all fstab entries with not existing devices.
  1508.    */
  1509.   define symbol SuggestRemoveSpecDialog()``{
  1510.     list<integer> rm_entries = suggest_remove_spec();
  1511.  
  1512.     if (size (rm_entries) == 0) return `ok;
  1513.  
  1514.     string help_text = OSRPopup::build_label_description (state_label,
  1515.     // help text in fstab dialog, %1 is Ignore label, %2 is Remove label
  1516.     sformat (_("
  1517. The status of a listed line can be switched between
  1518. %1 and %2. fstab entries are only removed if the the status of the
  1519. corresponding line is %2.
  1520. "), ignore_label, remove_label)) +
  1521.  
  1522.     // %1 is Ignore label
  1523.     OSRPopup::build_label_description (b_ignore_label, sformat (_("Change the status of the line to %1.
  1524. "), ignore_label)) +
  1525.  
  1526.     // %1 is Remove label
  1527.     OSRPopup::build_label_description (b_remove_label, sformat (_("Change the status of the line to %1.
  1528. "), remove_label));
  1529.  
  1530.     OSRPopup::OpenSuggestDialog(
  1531.     // dialog caption, fstab is filename
  1532.     _("Remove fstab Entries"),
  1533.     // dialog text
  1534.     _("Could not find existing devices for the following fstab lines.
  1535. To remove the lines from fstab, select them in the table and 
  1536. change the status.
  1537. "),
  1538.     help_text,
  1539.     `VBox(
  1540.         // label (table will follow)
  1541.         `Left(`Label(_("Invalid or Obsolete Lines in fstab"))),
  1542.         `Table(`id(`table),
  1543.         `header(state_label, fstab_line_label),
  1544.         remove_spec_items(rm_entries, ignore_label)),
  1545.         `Left(`HBox(
  1546.         `PushButton(`id(`ignore), b_ignore_label),
  1547.         `PushButton(`id(`remove), b_remove_label)))
  1548.     ), 50);
  1549.  
  1550.     UI::SetFocus(`id(`table));
  1551.  
  1552.     symbol ret = `ok;
  1553.     repeat
  1554.     {
  1555.     ret = (symbol) UI::UserInput();
  1556.     integer current_item =
  1557.         (integer) UI::QueryWidget(`id(`table), `CurrentItem);
  1558.  
  1559.     if (ret == `ignore)
  1560.     {
  1561.         UI::ChangeWidget(`id(`table), `Item(current_item, 0), ignore_label);
  1562.     }
  1563.     else if (ret == `remove)
  1564.     {
  1565.         UI::ChangeWidget(`id(`table), `Item(current_item, 0), remove_label);
  1566.     }
  1567.     else if (ret == `ok)
  1568.     {
  1569.         list<integer> rm_list = [];
  1570.         foreach (integer e, rm_entries, {
  1571.         term it    = (term) UI::QueryWidget(`id(`table), `Item(e));
  1572.         if (it[1]:"" == remove_label)
  1573.         {
  1574.             rm_list = add (rm_list, e);
  1575.         }
  1576.         });
  1577.         y2milestone("lines to remove %1", rm_list);
  1578.         AsciiFile::RemoveLines(fstab, rm_list);
  1579.     }
  1580.     } until( ret == `ok || ret == `cancel);
  1581.  
  1582.     UI::CloseDialog();
  1583.     return ret;
  1584.   };
  1585.  
  1586.   /**
  1587.    * Find all fstab lines with at least one invalid position
  1588.    */
  1589.   define map suggest_modify()``{
  1590.  
  1591.     y2milestone("starting modify suggestion");
  1592. /*
  1593.     map modify_entries = filter (integer k, list<any> v, (map<integer,list<any> >)not_valid_lines,
  1594.     ``( v[1]:false == true));
  1595.     */
  1596.     map modify_entries = filter (integer k, list v,
  1597.     (map<integer,list>) not_valid_lines,``( v[1]:false == true));
  1598.  
  1599.     if (size (modify_entries) == 0) return $[];
  1600.  
  1601.     map nlines  = $[];
  1602.     foreach (integer lnr, list opts,  (map<integer,list>) modify_entries,
  1603.     {
  1604.     map linemap        = AsciiFile::GetLine (fstab, lnr);
  1605.     list<string> line    = linemap ["fields"]:[];
  1606.     list<string> nline    = [line[0]:""];
  1607.     map part        = line2part(line);
  1608.     string type        = opts[0]:"";
  1609.     list default_line    = FileSystems::GetFstabDefaultList (type);
  1610.     if (opts[2]:true == false)
  1611.     {
  1612.         if (fstab_defaults [type,"mount"]:"" != "" && type != "pts")
  1613.         {
  1614.         nline = add (nline, fstab_defaults[type,"mount"]:"");
  1615.         }
  1616.         else
  1617.         {
  1618.         AsciiFile::RemoveLines(fstab, [ lnr ]);
  1619.         return;
  1620.         }
  1621.     }
  1622.     else
  1623.     {
  1624.         nline = add (nline , line[1]:"");
  1625.     }
  1626.     // invalid  vfstype
  1627.     if (opts[3]:true == false)
  1628.     {
  1629.         if (type == "dev" )
  1630.         {
  1631.         string detected_fs = FileSystems::GetMountString (
  1632.             part["detected_fs"]:part["used_fs"]:`unknown, "");
  1633.         if (detected_fs != "")
  1634.         {
  1635.               nline = add (nline, detected_fs);
  1636.         }
  1637.         else
  1638.         {
  1639.             y2error("could not repair the defect fstab line %1", line);
  1640.             return;
  1641.         }
  1642.         }
  1643.         else
  1644.         {
  1645.         // proc, usb, pts
  1646.         string fs = fstab_defaults[type,"vfstype"]:"";
  1647.         if (fs != "")
  1648.             nline = add (nline, fs);
  1649.         else
  1650.         {
  1651.             y2error("invalid type");
  1652.             return;
  1653.         }
  1654.         }
  1655.     }
  1656.     else
  1657.     {
  1658.         nline = add (nline, line[2]:"");
  1659.     }
  1660.     integer i = 4;
  1661.     while (i <= 6)
  1662.     {
  1663.         // invalid ops
  1664.         if (opts[i]:true == false)
  1665.         {
  1666.         string str = default_line[i-1]:"";
  1667.         if (str != "")
  1668.             nline = add (nline, str);
  1669.         else
  1670.         {
  1671.             y2error("not valid %2 for line %1 found", line,
  1672.             pos2field[i-1]:"");
  1673.         }
  1674.         //set following pos to false
  1675.         integer ii = i+1;
  1676.         while (ii <=6)
  1677.         {
  1678.             opts[ii] = false;
  1679.             ii = ii+1;
  1680.         }
  1681.         }
  1682.         else
  1683.         {
  1684.         nline = add (nline, line[i-1]:"");
  1685.         }
  1686.         i = i +1;
  1687.     }
  1688.     nline = filter (string pos, nline, ``( pos != nil && pos != ""));
  1689.     if (size (nline) == 6 && nline != line)
  1690.     {
  1691.         nlines[lnr] = nline;
  1692.     }
  1693.     else if (nline != line)
  1694.     {
  1695.        y2error("the size of the suggested fstab entry is to less");
  1696.     }
  1697.     });
  1698.     return nlines;
  1699.   }
  1700.  
  1701.   /**
  1702.    * Build a item list.
  1703.    */
  1704.   define list<term> modify_items (map nlines, string ignore_label, boolean existing)
  1705.   {
  1706.  
  1707.     list<term> ret = [];
  1708.     foreach (integer lnr, list<string> nline,(map<integer,list<string> >)nlines,
  1709.     {
  1710.     if (existing)
  1711.     {
  1712.         map linemap    = AsciiFile::GetLine(fstab,lnr);
  1713.         nline    = linemap["fields"]:[];
  1714.     }
  1715.     ret = add (ret,`item(`id(lnr), ignore_label, mergestring(nline, ", ")));
  1716.     });
  1717.     return ret;
  1718.   };
  1719.  
  1720.   /**
  1721.    * Dialog for all fstab entries that have at least one invalid entry.
  1722.    */
  1723.   define symbol SuggestModifyDialog()``{
  1724.  
  1725.     map nlines            = suggest_modify();
  1726.  
  1727.     if (size (nlines) == 0)
  1728.     return `ok;
  1729.  
  1730.     //label of table, fstab is filename
  1731.     string existing_label    = _("Existing fstab Lines");
  1732.     //label of table, fstab is filename
  1733.     string suggested_label    = _("Suggested fstab Lines");
  1734.  
  1735.     // help text, %1 is table label for Suggested.  %2 is Replace button label
  1736.     string help_text = sformat (_("
  1737. One or more existing fstab entries seem to
  1738. be invalid. Compare the suggested entry
  1739. with the existing one.
  1740. To replace an existing line with a suggested
  1741. line, select the corresponding line
  1742. in the %1 table and
  1743. press %2.
  1744. "), suggested_label, b_replace_label) +
  1745.  
  1746.     //%1 is Ignore label, %2 is replace label
  1747.     OSRPopup::build_label_description (state_label, sformat (_("
  1748. The status of a listed line can be switched between
  1749. %1 and %2. Lines are only replaced if the status is %2.
  1750. "), ignore_label, replace_label)) +
  1751.  
  1752.     //%1 is Ignore label
  1753.     OSRPopup::build_label_description (b_ignore_label, sformat (_("Change the status of the line to %1.
  1754. "), ignore_label)) +
  1755.  
  1756.     //%1 is Replace label
  1757.     OSRPopup::build_label_description (b_replace_label, sformat (_("Change the status of the line to %1.
  1758. "), replace_label));
  1759.  
  1760.     // dialog headline
  1761.     OSRPopup::OpenSuggestDialog (_("Change Existing fstab Entries"),
  1762.     // dialog description
  1763. _("
  1764. One or more existing fstab entries seem invalid. 
  1765. Compare the suggested entry with the existing one."),
  1766.     help_text,
  1767.     `VBox (
  1768.         `Left(`Label(existing_label)),
  1769.         `Table (`id(`table_e), `opt(`disabled),
  1770.         `header (state_label, fstab_line_label),
  1771.         modify_items (nlines, ignore_label, true)
  1772.         ),
  1773.         `VSpacing(1),
  1774.         `Left(`Label(suggested_label)),
  1775.         `Table(`id(`table_s), `opt(`notify),
  1776.         `header (state_label, fstab_line_label),
  1777.         modify_items(nlines,ignore_label, false)
  1778.         ),
  1779.         `Left (`HBox(
  1780.         `PushButton(`id(`ignore), b_ignore_label),
  1781.         `PushButton(`id(`replace),b_replace_label)
  1782.         ))
  1783.     ),
  1784.     80
  1785.     );
  1786.     UI::SetFocus(`id(`table_s));
  1787.  
  1788.     symbol ret    = `ok;
  1789.     repeat
  1790.     {
  1791.     ret = (symbol) UI::UserInput();
  1792.     integer current_item =
  1793.         (integer) UI::QueryWidget(`id(`table_s), `CurrentItem);
  1794.     UI::ChangeWidget (`id(`table_e), `CurrentItem, current_item);
  1795.  
  1796.     if (ret == `ignore)
  1797.     {
  1798.         UI::ChangeWidget(`id(`table_s), `Item(current_item,0),ignore_label);
  1799.         UI::ChangeWidget(`id(`table_e), `Item(current_item,0),ignore_label);
  1800.     }
  1801.     else if (ret == `replace)
  1802.     {
  1803.         UI::ChangeWidget(`id(`table_s),`Item(current_item,0),replace_label);
  1804.         UI::ChangeWidget(`id(`table_e),`Item(current_item,0),replace_label);
  1805.     }
  1806.     else if (ret == `ok)
  1807.     {
  1808.         integer changed_count = size (
  1809.         filter (integer e, any ld, (map<integer,any>) nlines, {
  1810.             term it    = (term)UI::QueryWidget(`id(`table_s),`Item(e));
  1811.             return (it[1]:"" == replace_label);
  1812.         })
  1813.         );
  1814.         if (changed_count == 0)
  1815.         {
  1816.         Report::Warning(_("
  1817. Set the status of at least one
  1818. table entry to replace.
  1819. "));
  1820.         ret = `notok;
  1821.         continue;
  1822.         }
  1823.         else if (changed_count < size (nlines))
  1824.         {
  1825.         // yes/no popup headline
  1826.         if (! Popup::YesNoHeadline (_("Not All Replaced"),
  1827.         // yes/no popup text
  1828. _("
  1829. Only the fstab lines marked for replacement 
  1830. are replaced. Really replace only the
  1831. selected lines?
  1832. ")))
  1833.         {
  1834.             ret = `notok;
  1835.             continue;
  1836.         }
  1837.         }
  1838.         list<integer> rp_list = [];
  1839.         foreach (integer e, any ld, (map<integer,any>) nlines, {
  1840.         term it    = (term) UI::QueryWidget (`id(`table_s),`Item (e));
  1841.         if (it[1]:"" == replace_label)
  1842.         {
  1843.             rp_list = add (rp_list, e);
  1844.         }
  1845.         });
  1846.  
  1847.         y2milestone("lines to remove %1", rp_list);
  1848.         AsciiFile::RemoveLines(fstab, rp_list);
  1849.  
  1850.         // save and reread before append fstab !!
  1851.         // Remove don't resort list positions!!
  1852.         AsciiFile::RewriteFile (fstab, root_mountpoint + fstabpath);
  1853.         ReadFstab (root_mountpoint, true);
  1854.  
  1855.         foreach (integer rp, rp_list, ``{
  1856.         AsciiFile::AppendLine(fstab, nlines[rp]:[]);
  1857.         });
  1858.     }
  1859.     } until( ret == `ok || ret == `cancel);
  1860.  
  1861.     UI::CloseDialog();
  1862.     return ret;
  1863.   }
  1864.  
  1865.   define symbol ret_worst_symbol(list<symbol> retl)``{
  1866.  
  1867.     map symbol_weight = $[
  1868.                 `ok        : 1,
  1869.                 `cancel    : 2,
  1870.                 `error    : 3,
  1871.                 `abort    : 2
  1872.     ];
  1873.  
  1874.     symbol ret = `ok;
  1875.     foreach (symbol r, retl, ``{
  1876.     if (symbol_weight[ret]:0 < symbol_weight[r]:-1)
  1877.         ret = r;
  1878.     });
  1879.     return ret;
  1880.   }
  1881.  
  1882.   /**
  1883.    * Repair the fstab. Call sub dialogs.
  1884.    */
  1885.   global define symbol Repair () ``{
  1886.  
  1887.     list<symbol> ret = [];
  1888.  
  1889.     if (Mode::test ())
  1890.     {
  1891.     return `ok;
  1892.     }
  1893.  
  1894.     if (size (missing_devs) > 0) {
  1895.     y2milestone ("-------------- missing devices: %1", missing_devs);
  1896.     ret = add (ret, SuggestMissingEntriesDialog());
  1897.     }
  1898.  
  1899.     if (size (not_valid_lines) > 0) {
  1900.     y2milestone ("-------------- not valid lines: %1", not_valid_lines);
  1901.     ret = add (ret, SuggestCreateMp());
  1902.     ret = add (ret, SuggestRemoveSpecDialog());
  1903.     ret = add (ret, SuggestModifyDialog());
  1904.     }
  1905.  
  1906.     y2milestone("ret repair list %1", ret);
  1907.  
  1908.     if ((size (filter (symbol r, ret, ``( r == `ok))) > 0))
  1909.     {
  1910.     AsciiFile::RewriteFile (fstab, root_mountpoint + fstabpath);
  1911.     ResetSettings ();
  1912.     ReadFstab (root_mountpoint, true);
  1913.     }
  1914.     else
  1915.     {
  1916.     y2milestone("new fstab was not written");
  1917.     return `cancel;
  1918.     }
  1919.     return ret_worst_symbol(ret);
  1920.   }
  1921.  
  1922.   /**
  1923.    *
  1924.    */
  1925.   global define boolean CheckRootEntry (string dev_name,
  1926.                     list<string> tswapable_partition_list,
  1927.                     list<string> tchecked_partitions)``{
  1928.  
  1929.     ResetSettings();
  1930.     y2milestone("check root fstab entry");
  1931.     swapable_partition_list    = tswapable_partition_list;
  1932.     checked_partitions        = tchecked_partitions;
  1933.     boolean ret            = false;
  1934.     map root_part        = devname2part (dev_name);
  1935.     list root_l_no        = AsciiFile::FindLineField (fstab, 0, dev_name);
  1936.  
  1937.     root_l_no            = union (root_l_no,
  1938.     AsciiFile::FindLineField (fstab, 0, "UUID=" + root_part["uuid"]:""));
  1939.  
  1940.     root_l_no            = union (root_l_no,
  1941.     AsciiFile::FindLineField (fstab, 0, "LABEL=" + root_part["label"]:""));
  1942.  
  1943.     // root_lines example:
  1944.     // $[ 1 : $["fields":["/dev/hda3", "/", "reiserfs", "defaults", "1", "2"],
  1945.     //        "line":"/dev/hda3\t/\treiserfs\tdefaults 1 2" ]
  1946.     // ]
  1947.     map<integer,map> root_lines        = $[];
  1948.  
  1949.     foreach (integer n, (list<integer>) root_l_no, {
  1950.     root_lines[n] = AsciiFile::GetLine(fstab, n);
  1951.     });
  1952.  
  1953.     root_lines    =
  1954.     filter (integer n, map l, root_lines, ``(l["fields",1]:"" == "/"));
  1955.  
  1956.     if (size (root_lines) != 1)
  1957.     {
  1958.     y2error(" several or non root entries in fstab found");
  1959.     y2error(" root lines %1", root_lines);
  1960.     missing_devs  = add (missing_devs, dev_name);
  1961.     ret =  false;
  1962.     }
  1963.     else
  1964.     {
  1965.     list keys        = maplist (integer k, map v, root_lines,``(k));
  1966.     integer root_line_key    = keys[0]:1;
  1967.     list<string> root_line    = root_lines [root_line_key, "fields"]:[];
  1968.     string type        = "root";
  1969.  
  1970.     boolean fs_vfstype    = check_fs_vfstype (root_line, root_part);
  1971.     boolean fs_mntops    = check_fs_mntops (root_line);
  1972.     boolean fs_freq        = check_fs_freq (root_line,
  1973.         [ tostring (fstab_defaults [type, "freq"]:0) ]);
  1974.     boolean fs_passno    = check_fs_passno (root_line,
  1975.         [ tostring (fstab_defaults [type, "passno"]:0) ]);
  1976.  
  1977.     if (! fs_vfstype)
  1978.     {
  1979.         y2error("root fstype not valid");
  1980.     }
  1981.     if (! fs_mntops)
  1982.     {
  1983.         y2error("root mntops not valid");
  1984.     }
  1985.     if (! fs_freq)
  1986.     {
  1987.         y2error("root freq not valid");
  1988.     }
  1989.     if (! fs_passno)
  1990.     {
  1991.         y2error("root passno not valid");
  1992.     }
  1993.  
  1994.     if (fs_vfstype && fs_mntops && fs_freq && fs_passno)
  1995.     {
  1996.         valid_lines  = add (valid_lines, root_line_key);
  1997.         y2milestone("root fstab line entry is valid");
  1998.     }
  1999.     else
  2000.     {
  2001.         y2error("root fstab line is not valid");
  2002.         not_valid_lines [root_line_key] =
  2003.         [ type, true, true, fs_vfstype, fs_mntops, fs_freq, fs_passno];
  2004.     }
  2005.     ret = (fs_vfstype && fs_mntops && fs_freq && fs_passno);
  2006.     }
  2007.  
  2008.     //for OSRBoot
  2009.     root_part["mount"] = "/";
  2010.     Storage::ChangeVolumeProperties(root_part);
  2011.  
  2012.     //inst_prepdisk for OSRBoot!
  2013.     foreach (string modname, (list<string>)FileSystems::GetNeededModules (
  2014.             root_part["detected_fs"]:(root_part["used_fs"]:`ext2)), ``{
  2015.       Initrd::AddModule (modname, "");
  2016.     });
  2017.  
  2018.     return ret;
  2019.   }
  2020.  
  2021.  
  2022.   /**
  2023.    *
  2024.    */
  2025.   global define string BootDev() ``{
  2026.  
  2027.     map lines    = fstab["l"]:$[];
  2028.     list line   = maplist (integer llineno, map llinedata,
  2029.     filter (integer lineno, map<string,any> linedata, (map<integer,map<string,any> >) lines , ``(
  2030.         linedata["fields", 1]:"" == "/boot")),
  2031.     ``(llinedata)
  2032.     );
  2033.     string ret    = "";
  2034.     if (size (line) == 1)
  2035.     {
  2036.     map part    = line2part(line[0,"fields"]:[]);
  2037.     ret        = part["dev_name"]:part["device"]:"";
  2038.     }
  2039.     else
  2040.     {
  2041.     y2milestone("no /boot device in fstab");
  2042.     }
  2043.     if (ret == nil)
  2044.     ret = "";
  2045.     return ret;
  2046.   }
  2047.  
  2048.  
  2049.   /**
  2050.    * ask user to select the root partition
  2051.    */
  2052.   global define string SelectRoot (list<map> valid_root_partition_list) {
  2053.  
  2054.     if (size (valid_root_partition_list) == 1)
  2055.     return valid_root_partition_list[0,"device"]:"";
  2056.  
  2057.     return OSRPopup::RadioButtonGroupText (
  2058.     // popup headline
  2059.     _("Select a Root Partition"),
  2060.     // popup text (radio buttons wil follow
  2061.     _("There are several valid root partitions in your system.
  2062. Select one item in the list.
  2063. "),
  2064.     (list<list>) maplist (map entry, valid_root_partition_list, ``(
  2065.         [
  2066.         entry["device"]:"",
  2067.         entry["label"]:""
  2068.         ]
  2069.     )),
  2070.     "",
  2071.     "",
  2072.     true
  2073.     );
  2074.   }
  2075.  
  2076.   /**
  2077.    *
  2078.    */
  2079.   global define boolean ReadedSuccessfully() ``{
  2080.       return ( fstab != nil  && fstab != $[]);
  2081.   }
  2082.  
  2083.   /**
  2084.    *
  2085.    */
  2086.   global define list<map> UmountAll (list<map> umount_list) ``{
  2087.  
  2088.     integer counter_error       = 0;
  2089.     list<map> just_umounted     = [];
  2090.     list<map> mnt_list        = [];
  2091.  
  2092.     mnt_list = filter (map s, umount_list, ``(
  2093.     substring (s["file"]:s["mountpoint"]:"", 0, size (root_mountpoint))
  2094.     == root_mountpoint)
  2095.     );
  2096.  
  2097.     mnt_list = sort (map x, map y, mnt_list, ``(
  2098.     size (splitstring (x["file"]:x["mountpoint"]:"", "/")) >
  2099.     size (splitstring (y["file"]:y["mountpoint"]:"" ,"/")))
  2100.     );
  2101.  
  2102.     y2milestone("partitions which should be umounted %1", mnt_list);
  2103.  
  2104.     // umount all partitions from "/mnt" or deeper, as long as there are no
  2105.     // more mounted partitions with mountpoint "/mnt..."
  2106.     foreach (map current, mnt_list, ``{
  2107.  
  2108.     if (OSRExecute::Command (.local.bash,
  2109.         "/bin/umount "+ current["file"]:current["mountpoint"]:""))
  2110.     {
  2111.         just_umounted = add (just_umounted, $[
  2112.         "partition"  : current["spec"]:current["partition"]:"",
  2113.         "mountpoint" : current["file"]:current["mountpoint"]:"" ]
  2114.         );
  2115.     }
  2116.     else
  2117.     {
  2118.         y2error(" %1 could not be umounted",
  2119.         current["file"]:current["mountpoint"]:"");
  2120.         counter_error = counter_error +1;
  2121.     }
  2122.     });
  2123.  
  2124.     if (counter_error == 0)
  2125.     {
  2126.     y2debug("All partitions were successfully umounted from /mnt...");
  2127.     }
  2128.     return just_umounted;
  2129.   }
  2130.  
  2131.   /**
  2132.    *
  2133.    */
  2134.   global define list<map> UmountAllFrom( string root)``{
  2135.  
  2136.     if (root != "" && root != nil)
  2137.     root_mountpoint = root;
  2138.  
  2139.     list<map> just_umounted      = [];
  2140.     list<map> mounted_partitions = Partitions::CurMounted();
  2141.  
  2142.     // filter swap partitions
  2143.     mounted_partitions = filter (map p, mounted_partitions, ``(
  2144.     p["file"]:"" != "swap" && findfirstof (p["spec"]:"", "/") == 0));
  2145.  
  2146.     // filter the list of partitions that are mounted to "/mnt" or deeper
  2147.     if (root_mountpoint != "/")
  2148.     {
  2149.     just_umounted = UmountAll( mounted_partitions);
  2150.     }
  2151.  
  2152.     return just_umounted;
  2153.   }
  2154.  
  2155.  
  2156.   /**
  2157.    *
  2158.    */
  2159.   global define list<map> RootDev(string root)``{
  2160.  
  2161.     if (root != "" && root != nil)
  2162.     root_mountpoint = root;
  2163.  
  2164.     list<map> mounted = [];
  2165.  
  2166.     if (! ReadedSuccessfully())
  2167.     {
  2168.     list<string> checked_partitions        = filter (string s,
  2169.         maplist (map p, OSRFsck::PossiblePartitions(), ``(p["device"]:"")),
  2170.         ``(s !=""));
  2171.     list<string> linux_partition_list    =
  2172.         LinuxPartitions(checked_partitions);
  2173.     list<string> mount_possible_list    =
  2174.         MountablePartitions (linux_partition_list, root_mountpoint);
  2175.     list<map> valid_root_partitions    =
  2176.         ValidRootPartitions (mount_possible_list, root_mountpoint);
  2177.  
  2178.     if (size (valid_root_partitions) == 0)
  2179.     {
  2180.         // error popup: no root partition found
  2181.         Report::Error(_("
  2182. No valid root partition found. 
  2183. Go back and select all scan 
  2184. options. Afterwards, restart 
  2185. scanning.
  2186. "));
  2187.         return nil;
  2188.     }
  2189.     string root_partition    = SelectRoot (valid_root_partitions);
  2190.     y2milestone("selected root_partition %1" ,root_partition);
  2191.  
  2192.     boolean mount        = OSRExecute::Command (.local.bash,
  2193.         sformat ("/bin/mount %1 %2", root_partition, root_mountpoint));
  2194.  
  2195.     mounted = add (mounted, $[
  2196.         "partition" : root_partition,
  2197.         "mountpoint" : root_mountpoint,
  2198.         "status"    : mount ]
  2199.     );
  2200.     if (mount)
  2201.     {
  2202.         OSRSystem::ChangeRoot("/");
  2203.         ReadFstab(root_mountpoint, true);
  2204.     }
  2205.     else
  2206.     {
  2207.         y2error("can not mount root partition");
  2208.     }
  2209.     }
  2210.  
  2211.     y2milestone("RootDev in Fstab %1" ,mounted);
  2212.     return mounted;
  2213.   }
  2214.  
  2215.  
  2216.   /**
  2217.    * Mount all partitions specified in the fstab.
  2218.    * If no fstab was readed try to find root partition
  2219.    * and read fstab. Afterwards mount all partitions.
  2220.    */
  2221.   global define list<map> MountAll(string root)``{
  2222.  
  2223.     list<map> mounted = [];
  2224.  
  2225.     if (root != "" && root != nil)
  2226.     root_mountpoint = root;
  2227.  
  2228.     if (OSRFsck::LoadAllFsModules())
  2229.     {
  2230.     y2milestone("kernel fs modules successful loaded");
  2231.     }
  2232.     else
  2233.     {
  2234.     y2error("loaded kernel modules returned an error");
  2235.     }
  2236.     // if fstab is not readed.
  2237.     // Fstab functions are not called.
  2238.     // user skiped execution of osr_module_partition,
  2239.     // but need a root partition -> find root and
  2240.     // read fstab.
  2241.     list<map> t_mounted = RootDev(root_mountpoint);
  2242.  
  2243.     if (t_mounted != nil && t_mounted != [])
  2244.     mounted = (list<map>) union (mounted, t_mounted);
  2245.  
  2246.     if (! ReadedSuccessfully())
  2247.     {
  2248.     Report::Error(_("
  2249. Cannot read the file /etc/fstab.
  2250. Initialization of the target system
  2251. is not possible. Go back
  2252. and select all scan options.
  2253. "));
  2254.     return nil;
  2255.     }
  2256.  
  2257.     //sort fstab lines /mnt/hh/kk > /mnt/hh
  2258.     list<map> lines = (list<map>) maplist (integer lnr, map linedata,
  2259.     fstab["l"]:$[], ``(linedata));
  2260.  
  2261.     foreach (map linedata, lines, ``{
  2262.  
  2263.     list<string> line    = linedata["fields"]:[];
  2264.     map part        = line2part (line);
  2265.     // not mounted
  2266.     if ((part["found"]:"" == "dev") &&
  2267.         (!contains (["/dev/cdrecorder", "/dev/cdrom", "/dev/dvd",
  2268.              "/media/cdrecorder", "/media/cdrom", "/media/dvd" ],
  2269.         line[1]:"")) &&
  2270.         (Storage::DeviceMounted(line[1]:"") == "")
  2271.         && ( line[1]:"" != "/"))
  2272.     {
  2273.         string mp    = root_mountpoint + line[1]:"";
  2274.         mounted    = add (mounted , $[
  2275.         "partition"    : line[0]:"",
  2276.         "mountpoint"    : mp,
  2277.         "status"    : OSRExecute::Command (.local.bash,
  2278.             sformat ("/bin/mount %1 %2", line[0]:"", mp))
  2279.         ]
  2280.         );
  2281.     }
  2282.       });
  2283.  
  2284.       OSRSystem::ChangeRoot(root_mountpoint);
  2285.       y2milestone(" Mount all return %1", mounted); 
  2286.       return mounted;
  2287.   }
  2288.  
  2289.  
  2290. }//EOF
  2291.