still prettifying
[bootmanager.git] / source / systeminfo.py
index 9997342..4536294 100755 (executable)
@@ -1,5 +1,5 @@
-#!/usr/bin/python2
-
+#!/usr/bin/python
+#
 # Copyright (c) 2003 Intel Corporation
 # All rights reserved.
 #
@@ -18,6 +18,7 @@
 #3     4   18804082 hda4
 #----------------------------------------------------
 
+from __future__ import print_function
 
 import string
 import sys
@@ -26,27 +27,7 @@ import popen2
 import re
 import errno
 import ModelOptions
-try:
-    from pypciscan import get_devices
-except:
-    def get_devices():
-        """ This is a replacement to the version in pypciscan library for 3.3 and lower bootcds 
-        that will help maintain backward compatibility.  This version has limitations wrt accuracy
-        that the library does not.  In particular it is limited to the output of
-        lspci and 'forces' all devices to appear on the '0000' domain, rather than
-        where they actually are."""
-
-        ret = {}
-        #pci = os.popen("lspci -nm | sed -e 's/\"//g'", 'r')
-        pci = os.popen("lspci -nm | sed -e 's/\"//g' -e 's/Class //g'", 'r')
-        for line in pci:
-            l = line[:-1]
-            f = l.split(" ")
-            key = "0000:%s" % f[0]
-            ret[key] = (int(f[2],16), int(f[3],16), 0xffff, 0xffff, int(f[1],16) << 8)
-        return ret
-
-import pypcimap
+from pypci import *
 from Exceptions import *
 
 """
@@ -54,28 +35,24 @@ a utility class for finding and returning information about
 block devices, memory, and other hardware on the system
 """
 
-PROC_MEMINFO_PATH= "/proc/meminfo"
-PROC_PARTITIONS_PATH= "/proc/partitions"
+PROC_MEMINFO_PATH = "/proc/meminfo"
+PROC_PARTITIONS_PATH = "/proc/partitions"
 
 # set when the sfdisk -l <dev> trick has been done to make
 # all devices show up
-DEVICES_SCANNED_FLAG= "/tmp/devices_scanned"
+DEVICES_SCANNED_FLAG = "/tmp/devices_scanned"
 
 # a /proc/partitions block is 1024 bytes
 # a GB to a HDD manufacturer is 10^9 bytes
 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_BASE_CLASS_NETWORK=0x02L
-PCI_BASE_CLASS_STORAGE=0x01L
-
-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):
     """
@@ -85,28 +62,28 @@ def get_total_phsyical_mem(vars = {}, log = sys.stderr):
     """
 
     try:
-        meminfo_file= file(PROC_MEMINFO_PATH,"r")
-    except IOError, e:
+        meminfo_file = file(PROC_MEMINFO_PATH, "r")
+    except IOError as e:
         return
 
-    total_memory= None
+    total_memory = None
 
     for line in meminfo_file:
 
         try:
-            (fieldname,value)= string.split(line,":")
-        except ValueError, e:
+            fieldname, value = string.split(line, ":")
+        except ValueError as e:
             # this will happen for lines that don't have two values
             # (like the first line on 2.4 kernels)
             continue
 
-        fieldname= string.strip(fieldname)
-        value= string.strip(value)
+        fieldname = string.strip(fieldname)
+        value = string.strip(value)
         
         if fieldname == "MemTotal":
             try:
-                (total_memory,units)= string.split(value)
-            except ValueError, e:
+                total_memory, units = string.split(value)
+            except ValueError as e:
                 return
 
             if total_memory == "" or total_memory == None or \
@@ -117,8 +94,8 @@ def get_total_phsyical_mem(vars = {}, log = sys.stderr):
                 return
 
             try:
-                total_memory= int(total_memory)
-            except ValueError, e:
+                total_memory = int(total_memory)
+            except ValueError as e:
                 return
 
             break
@@ -131,7 +108,7 @@ def get_block_device_list(vars = {}, log = sys.stderr):
     get a list of block devices from this system.
     return an associative array, where the device name
     (full /dev/device path) is the key, and the value
-    is a tuple of (major,minor,numblocks,gb_size,readonly)
+    is a tuple of (major, minor, numblocks, gb_size, readonly)
     """
 
     # make sure we can access to the files/directories in /proc
@@ -141,25 +118,25 @@ 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'):
-        for blk_num in map ( \
-            lambda x: chr(x), range(ord('a'),ord('z')+1)):
-            devicename="%s%c" % (blk_prefix, blk_num)
-            valid_blk_names[devicename]=None
+    # also check for vd (virtio devices used with kvm)
+    for blk_prefix in ('sd', 'hd', 'vd'):
+        for blk_num in string.ascii_lowercase:
+            devicename = "{}{}".format(blk_prefix, blk_num)
+            valid_blk_names[devicename] = None
 
     # add in valid scsi raid block device names
-    for M in range(0,1+1):
-        for N in range(0,7+1):
-            devicename = "cciss/c%dd%d" % (M,N)
-            valid_blk_names[devicename]=None
+    for M in range(0, 1+1):
+        for N in range(0, 7+1):
+            devicename = "cciss/c{}d{}".format(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
+            devfsname = os.readlink("/dev/{}".format(devicename))
+            valid_blk_names[devfsname] = None
         except OSError:
             pass
 
@@ -173,67 +150,71 @@ 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/{} > /dev/null 2>&1".format(devicename))
 
         # touch file
-        fb = open(DEVICES_SCANNED_FLAG,"w")
+        fb = open(DEVICES_SCANNED_FLAG, "w")
         fb.close()
 
-    devicelist= {}
+    devicelist = {}
 
-    partitions_file= file(PROC_PARTITIONS_PATH,"r")
-    line_count= 0
+    partitions_file = file(PROC_PARTITIONS_PATH, "r")
+    line_count = 0
     for line in partitions_file:
-        line_count= line_count + 1
+        line_count = line_count + 1
 
         # skip the first two lines always
         if line_count < 2:
             continue
 
-        parts= string.split(line)
+        parts = string.split(line)
 
         if len(parts) < 4:
             continue
 
-        device= parts[3]
+        device = parts[3]
 
         # skip and ignore any partitions
         if not valid_blk_names.has_key(device):
             continue
 
         try:
-            major= int(parts[0])
-            minor= int(parts[1])
-            blocks= int(parts[2])
-        except ValueError, err:
+            major = int(parts[0])
+            minor = int(parts[1])
+            blocks = int(parts[2])
+        except ValueError as err:
             continue
 
-        gb_size= blocks/BLOCKS_PER_GB
+        gb_size = blocks/BLOCKS_PER_GB
 
         # check to see if the blk device is readonly
         try:
             # can we write to it?
-            dev_name= "/dev/%s" % device
-            fb = open(dev_name,"w")
+            dev_name = "/dev/{}".format(device)
+            fb = open(dev_name, "w")
             fb.close()
-            readonly=False
-        except IOError, e:
+            readonly = False
+        except IOError as e:
             # check if EROFS errno
-            if errno.errorcode.get(e.errno,None) == 'EROFS':
-                readonly=True
+            if errno.errorcode.get(e.errno, None) == 'EROFS':
+                readonly = True
             else:
                 # got some other errno, pretend device is readonly
-                readonly=True
+                readonly = True
 
-        devicelist[dev_name]= (major,minor,blocks,gb_size,readonly)
+        devicelist[dev_name] = (major, minor, blocks, gb_size, readonly)
 
     return devicelist
 
 
-def get_system_modules( vars = {}, log = sys.stderr):
+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
@@ -257,8 +238,8 @@ def get_system_modules( vars = {}, log = sys.stderr):
     """
 
     if not vars.has_key("SYSIMG_PATH"):
-        vars["SYSIMG_PATH"]="/"
-    SYSIMG_PATH=vars["SYSIMG_PATH"]
+        vars["SYSIMG_PATH"] = "/"
+    SYSIMG_PATH = vars["SYSIMG_PATH"]
 
     if not vars.has_key("NODE_MODEL_OPTIONS"):
         vars["NODE_MODEL_OPTIONS"] = 0;
@@ -268,89 +249,98 @@ def get_system_modules( vars = {}, log = sys.stderr):
     # get the kernel version we are assuming
     if kernel_version is None:
         try:
-            kernel_version= os.listdir( "%s/lib/modules/" % SYSIMG_PATH )
-        except OSError, e:
+            kernel_version = os.listdir("{}/lib/modules/".format(SYSIMG_PATH))
+        except OSError as e:
             return
 
         if len(kernel_version) == 0:
             return
 
         if len(kernel_version) > 1:
-            print( "WARNING: We may be returning modules for the wrong kernel." )
+            print("WARNING: We may be returning modules for the wrong kernel.")
 
-        kernel_version= kernel_version[0]
+        kernel_version = kernel_version[0]
 
-    print( "Using kernel version %s" % kernel_version )
+    print("Using kernel version {}".format(kernel_version))
 
     # test to make sure the file we need is present
-    modules_pcimap_path = "%s/lib/modules/%s/modules.pcimap" % \
-                          (SYSIMG_PATH,kernel_version)
-    if not os.access(modules_pcimap_path,os.R_OK):
-        print( "Unable to read %s" % path )
+    modules_pcimap_path = "{}/lib/modules/{}/modules.pcimap"\
+        .format(SYSIMG_PATH, kernel_version)
+    if not os.access(modules_pcimap_path, os.R_OK):
+        print("WARNING: Unable to read {}".format(modules_pcimap_path))
         return
 
     pcimap = pypcimap.PCIMap(modules_pcimap_path)
 
     # this is the actual data structure we return
-    system_mods= {}
+    system_mods = {}
 
     # these are the lists that will be in system_mods
-    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()
 
-    for (slot, dev) in pcidevs.iteritems():
+    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):
-            continue
+            # 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
 
-        modules = pcimap.get(dev)
         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
 
     return system_mods
 
 
-def getKernelVersion( vars = {} , log = sys.stderr):
+def getKernelVersion(vars = {}, log = sys.stderr):
     # make sure we have the variables we need
     try:
-        SYSIMG_PATH= vars["SYSIMG_PATH"]
+        SYSIMG_PATH = vars["SYSIMG_PATH"]
         if SYSIMG_PATH == "":
-            raise ValueError, "SYSIMG_PATH"
+            raise ValueError("SYSIMG_PATH")
 
-        NODE_MODEL_OPTIONS=vars["NODE_MODEL_OPTIONS"]
-    except KeyError, var:
-        raise BootManagerException, "Missing variable in vars: %s\n" % var
-    except ValueError, var:
-        raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+        NODE_MODEL_OPTIONS = vars["NODE_MODEL_OPTIONS"]
+    except KeyError as var:
+        raise BootManagerException("Missing variable in vars: {}\n".format(var))
+    except ValueError as var:
+        raise BootManagerException("Variable in vars, shouldn't be: {}\n".format(var))
 
     option = ''
     if NODE_MODEL_OPTIONS & ModelOptions.SMP:
         option = 'smp'
         try:
-            os.stat("%s/boot/kernel-boot%s" % (SYSIMG_PATH,option))
-            os.stat("%s/boot/initrd-boot%s" % (SYSIMG_PATH,option))
-        except OSError, e:
+            os.stat("{}/boot/kernel-boot{}".format(SYSIMG_PATH, option))
+            os.stat("{}/boot/initrd-boot{}".format(SYSIMG_PATH, option))
+        except OSError as e:
             # smp kernel is not there; remove option from modeloptions
             # such that the rest of the code base thinks we are just
             # using the base kernel.
             NODE_MODEL_OPTIONS = NODE_MODEL_OPTIONS & ~ModelOptions.SMP
             vars["NODE_MODEL_OPTIONS"] = NODE_MODEL_OPTIONS
-            log.write( "WARNING: Couldn't locate smp kernel.\n")
+            log.write("WARNING: Couldn't locate smp kernel.\n")
             option = ''
     try:
-        initrd= os.readlink( "%s/boot/initrd-boot%s" % (SYSIMG_PATH,option) )
-        kernel_version= initrd.replace("initrd-", "").replace(".img", "")    
-    except OSError, e:
+        initrd = os.readlink("{}/boot/initrd-boot{}".format(SYSIMG_PATH, option))
+        kernel_version = initrd.replace("initrd-", "").replace(".img", "")    
+    except OSError as e:
         initrd = None
         kernel_version = None
         
@@ -358,40 +348,37 @@ def getKernelVersion( vars = {} , log = sys.stderr):
 
 
 if __name__ == "__main__":
-    devices= get_block_device_list()
-    print "block devices detected:"
+    devices = get_block_device_list()
+    print("block devices detected:")
     if not devices:
-        print "no devices found!"
+        print("no devices found!")
     else:
         for dev in devices.keys():
-            print "%s %s" % (dev, repr(devices[dev]))
+            print("{} {}".format(dev, repr(devices[dev])))
             
 
-    print ""
-    memory= get_total_phsyical_mem()
+    print("")
+    memory = get_total_phsyical_mem()
     if not memory:
-        print "unable to read /proc/meminfo for memory"
+        print("unable to read /proc/meminfo for memory")
     else:
-        print "total physical memory: %d kb" % memory
+        print("total physical memory: {} kb".format(memory))
         
 
-    print ""
+    print("")
 
     kernel_version = None
     if len(sys.argv) > 2:
         kernel_version = sys.argv[1]
         
-    modules= get_system_modules()
+    modules = get_system_modules()
     if not modules:
-        print "unable to list system 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 + "{} ".format(a_mod)
+                print("all {} modules: {}".format(module_class, module_list))