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.
 #
 # Copyright (c) 2003 Intel Corporation
 # All rights reserved.
 #
@@ -23,13 +23,12 @@ import string
 import sys
 import os
 import popen2
 import sys
 import os
 import popen2
-import merge_hw_tables
 import re
 import errno
 import ModelOptions
 import re
 import errno
 import ModelOptions
+from pypci import *
 from Exceptions 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
 """
 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;
 
 
 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"
 
 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):
     """
 
 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
     # 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)
         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
 
             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):
 
     # 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.
         # 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:
         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")
 
         # 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
     """
     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.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
 
     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 )
 
 
     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_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
 
         return
 
+    pcimap = pypcimap.PCIMap(modules_pcimap_path)
+
     # this is the actual data structure we return
     system_mods= {}
 
     # 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= []
 
     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
 
     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:
     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)