run parted with the --script option to prevent from hanging
[bootmanager.git] / source / systeminfo.py
index 966c149..921ede6 100755 (executable)
@@ -1,5 +1,5 @@
-#!/usr/bin/python2
-
+#!/usr/bin/python
+#
 # Copyright (c) 2003 Intel Corporation
 # All rights reserved.
 #
@@ -23,13 +23,12 @@ import string
 import sys
 import os
 import popen2
-import merge_hw_tables
 import re
 import errno
 import ModelOptions
+from pypci import *
 from Exceptions import *
 
-hwdatapath = "usr/share/hwdata"
 """
 a utility class for finding and returning information about
 block devices, memory, and other hardware on the system
@@ -47,21 +46,12 @@ DEVICES_SCANNED_FLAG= "/tmp/devices_scanned"
 BLOCKS_PER_GB = pow(10, 9) / 1024.0;
 
 
-# -n is numeric ids (no lookup), -m is machine readable
-LSPCI_CMD= "/sbin/lspci -nm"
-
 MODULE_CLASS_NETWORK= "network"
 MODULE_CLASS_SCSI= "scsi"
 
-PCI_CLASS_NETWORK_ETHERNET=0x0200L
-PCI_CLASS_STORAGE_SCSI=0x0100L
-PCI_CLASS_STORAGE_IDE=0x0101L
-PCI_CLASS_STORAGE_FLOPPY=0x0102L
-PCI_CLASS_STORAGE_IPI=0x0103L
-PCI_CLASS_STORAGE_RAID=0x0104L
-PCI_CLASS_STORAGE_OTHER=0x0180L
-
-PCI_ANY=0xffffffffL
+#PCI_* is now defined in the pypci modules
+#PCI_BASE_CLASS_NETWORK=0x02L
+#PCI_BASE_CLASS_STORAGE=0x01L
 
 def get_total_phsyical_mem(vars = {}, log = sys.stderr):
     """
@@ -127,7 +117,8 @@ def get_block_device_list(vars = {}, log = sys.stderr):
     # table with valid scsi/sata/ide/raid block device names
     valid_blk_names = {}
     # add in valid sd and hd block device names
-    for blk_prefix in ('sd','hd'):
+    # also check for vd (virtio devices used with kvm)
+    for blk_prefix in ('sd','hd','vd'):
         for blk_num in map ( \
             lambda x: chr(x), range(ord('a'),ord('z')+1)):
             devicename="%s%c" % (blk_prefix, blk_num)
@@ -139,6 +130,16 @@ def get_block_device_list(vars = {}, log = sys.stderr):
             devicename = "cciss/c%dd%d" % (M,N)
             valid_blk_names[devicename]=None
 
+    for devicename in valid_blk_names.keys():
+        # devfs under 2.4 (old boot cds) used to list partitions
+        # in a format such as scsi/host0/bus0/target0/lun0/disc
+        # and /dev/sda, etc. were just symlinks
+        try:
+            devfsname= os.readlink( "/dev/%s" % devicename )
+            valid_blk_names[devfsname]=None
+        except OSError:
+            pass
+
     # only do this once every system boot
     if not os.access(DEVICES_SCANNED_FLAG, os.R_OK):
 
@@ -149,10 +150,14 @@ def get_block_device_list(vars = {}, log = sys.stderr):
         # so, lets run sfdisk -l (list partitions) against
         # most possible block devices, that way they show
         # up when it comes time to do the install.
+
+        # 27.6.2012 - Using parted instead of sfdisk, assuming
+        # that doing so respects the behavior mentioned above.
+
         devicenames = valid_blk_names.keys()
         devicenames.sort()
         for devicename in devicenames:
-            os.system( "sfdisk -l /dev/%s > /dev/null 2>&1" % devicename )
+            os.system( "parted --script --list /dev/%s > /dev/null 2>&1" % devicename )
 
         # touch file
         fb = open(DEVICES_SCANNED_FLAG,"w")
@@ -213,10 +218,8 @@ def get_system_modules( vars = {}, log = sys.stderr):
     """
     Return a list of kernel modules that this system requires.
     This requires access to the installed system's root
-    directory, as the following files must exist and are used:
-    <install_root>/usr/share/hwdata/pcitable
+    directory, as the following file must exist and is used:
     <install_root>/lib/modules/(first entry if kernel_version unspecified)/modules.pcimap
-    <install_root>/lib/modules/(first entry if kernel version unspecified)/modules.dep
 
     If there are more than one kernels installed, and the kernel
     version is not specified, then only the first one in
@@ -260,27 +263,15 @@ def get_system_modules( vars = {}, log = sys.stderr):
 
     print( "Using kernel version %s" % kernel_version )
 
-    # test to make sure the three files we need are present
-    pcitable_path = "%s/%s/pcitable" % (SYSIMG_PATH,hwdatapath)
+    # test to make sure the file we need is present
     modules_pcimap_path = "%s/lib/modules/%s/modules.pcimap" % \
                           (SYSIMG_PATH,kernel_version)
-    modules_dep_path = "%s/lib/modules/%s/modules.dep" % \
-                       (SYSIMG_PATH,kernel_version)
-
-    for path in (pcitable_path,modules_pcimap_path,modules_dep_path):
-        if not os.access(path,os.R_OK):
-            print( "Unable to read %s" % path )
-            return
-
-    # now, with those three files, merge them all into one easy to
-    # use lookup table
-    (all_pci_ids, all_modules) = merge_hw_tables.merge_files( modules_dep_path,
-                                                              modules_pcimap_path,
-                                                              pcitable_path )
-    if all_modules is None:
-        print( "Unable to merge pci id tables." )
+    if not os.access(modules_pcimap_path,os.R_OK):
+        print( "WARNING: Unable to read %s" % modules_pcimap_path )
         return
 
+    pcimap = pypcimap.PCIMap(modules_pcimap_path)
+
     # this is the actual data structure we return
     system_mods= {}
 
@@ -288,85 +279,30 @@ def get_system_modules( vars = {}, log = sys.stderr):
     network_mods= []
     scsi_mods= []
 
+    # XXX: this is really similar to what BootCD/conf_files/pl_hwinit does. merge?
+    pcidevs = get_devices()
+
+    devlist=pcidevs.keys()
+    devlist.sort()
+    for slot in devlist:
+        dev = pcidevs[slot]
+        base = (dev[4] & 0xff0000) >> 16
+        modules = pcimap.get(dev)
+        if base not in (PCI_BASE_CLASS_STORAGE,
+                        PCI_BASE_CLASS_NETWORK):
+            # special exception for forcedeth NICs whose base id
+            # claims to be a Bridge, even though it is clearly a
+            # network device
+            if "forcedeth" in modules: 
+                base=PCI_BASE_CLASS_NETWORK
+            else:
+                continue
 
-    # get all the system devices from lspci
-    lspci_prog= popen2.Popen3( LSPCI_CMD, 1 )
-    if lspci_prog is None:
-        print( "Unable to run %s with popen2.Popen3" % LSPCI_CMD )
-        return
-
-    returncode= lspci_prog.wait()
-    if returncode != 0:
-        print( "Running %s failed" % LSPCI_CMD )
-        return
-    else:
-        print( "Successfully ran %s" % LSPCI_CMD )
-
-    # for every lspci line, parse in the four tuple PCI id and the
-    # search for the corresponding driver from the dictionary
-    # generated by merge_hw_tables
-    for line in lspci_prog.fromchild:
-        # A sample line:
-        #
-        # 00:1f.1 "Class 0101" "8086" "2411" -r02 -p80 "8086" "2411"
-        #
-        # Remove '"', 'Class ', and anything beginning with '-'
-        # (usually revisions and prog-if flags) so that we can
-        # split on whitespace:
-        #
-        # 00:1f.1 0101 8086 2411 8086 2411
-        #
-        line = line.strip()
-        line = line.replace('"', '')
-        line = line.replace('Class ', '')
-        line = re.sub('-[^ ]*', '', line)
-
-        parts = line.split()
-        try:
-            if len(parts) < 4:
-                raise
-            classid = long(parts[1], 16)
-            vendorid = long(parts[2], 16)
-            deviceid = long(parts[3], 16)
-        except:
-            print "Invalid line:", line
-            continue
-
-        if classid not in (PCI_CLASS_NETWORK_ETHERNET,
-                           PCI_CLASS_STORAGE_SCSI,
-                           PCI_CLASS_STORAGE_RAID,
-                           PCI_CLASS_STORAGE_OTHER,
-                           PCI_CLASS_STORAGE_IDE):
-            continue
-
-        # Device may have a subvendorid and subdeviceid
-        try:
-            subvendorid = long(parts[4], 16)
-            subdeviceid = long(parts[5], 16)
-        except:
-            subvendorid = PCI_ANY
-            subdeviceid = PCI_ANY
-
-        # search for driver that most closely matches the full_id
-        # to drivers that can handle any subvendor/subdevice
-        # version of the hardware.
-        full_ids = ((vendorid,deviceid,subvendorid,subdeviceid),
-                    (vendorid,deviceid,subvendorid,PCI_ANY),
-                    (vendorid,deviceid,PCI_ANY,PCI_ANY))
-
-        for full_id in full_ids:
-            module = all_pci_ids.get(full_id, None)
-            if module is not None:
-                if classid == PCI_CLASS_NETWORK_ETHERNET:
-                    network_mods.append(module[0])
-                elif classid in (PCI_CLASS_STORAGE_SCSI,
-                                 PCI_CLASS_STORAGE_RAID,
-                                 PCI_CLASS_STORAGE_OTHER,
-                                 PCI_CLASS_STORAGE_IDE):
-                    scsi_mods.append(module[0])
-                else:
-                    print "not network or scsi: 0x%x" % classid
-                break
+        if len(modules) > 0:
+            if base == PCI_BASE_CLASS_NETWORK:
+                network_mods += modules
+            elif base == PCI_BASE_CLASS_STORAGE:
+                scsi_mods += modules
 
     system_mods[MODULE_CLASS_SCSI]= scsi_mods
     system_mods[MODULE_CLASS_NETWORK]= network_mods
@@ -439,13 +375,10 @@ if __name__ == "__main__":
     if not modules:
         print "unable to list system modules"
     else:
-        for type in modules:
-            if type == MODULE_CLASS_SCSI:
-                print( "all scsi modules:" )
-                for a_mod in modules[type]:
-                    print a_mod
-            elif type == MODULE_CLASS_NETWORK:
-                print( "all network modules:" )
-                for a_mod in modules[type]:
-                    print a_mod
+        for module_class in (MODULE_CLASS_SCSI,MODULE_CLASS_NETWORK):
+            if len(modules[module_class]) > 0:
+                module_list = ""
+                for a_mod in modules[module_class]:
+                    module_list = module_list + "%s " % a_mod
+                print "all %s modules: %s" % (module_class, module_list)