3 # Copyright (c) 2003 Intel Corporation
6 # Copyright (c) 2004-2006 The Trustees of Princeton University
8 # expected /proc/partitions format
11 #----------------------------------------------------
12 #major minor #blocks name
19 #----------------------------------------------------
30 from Exceptions import *
33 a utility class for finding and returning information about
34 block devices, memory, and other hardware on the system
37 PROC_MEMINFO_PATH= "/proc/meminfo"
38 PROC_PARTITIONS_PATH= "/proc/partitions"
40 # set when the sfdisk -l <dev> trick has been done to make
42 DEVICES_SCANNED_FLAG= "/tmp/devices_scanned"
44 # a /proc/partitions block is 1024 bytes
45 # a GB to a HDD manufacturer is 10^9 bytes
46 BLOCKS_PER_GB = pow(10, 9) / 1024.0;
49 MODULE_CLASS_NETWORK= "network"
50 MODULE_CLASS_SCSI= "scsi"
52 #PCI_* is now defined in the pypci modules
53 #PCI_BASE_CLASS_NETWORK=0x02L
54 #PCI_BASE_CLASS_STORAGE=0x01L
56 def get_total_phsyical_mem(vars = {}, log = sys.stderr):
58 return the total physical memory of the machine, in kilobytes.
60 Return None if /proc/meminfo not readable.
64 meminfo_file= file(PROC_MEMINFO_PATH,"r")
70 for line in meminfo_file:
73 (fieldname,value)= string.split(line,":")
75 # this will happen for lines that don't have two values
76 # (like the first line on 2.4 kernels)
79 fieldname= string.strip(fieldname)
80 value= string.strip(value)
82 if fieldname == "MemTotal":
84 (total_memory,units)= string.split(value)
88 if total_memory == "" or total_memory == None or \
89 units == "" or units == None:
92 if string.lower(units) != "kb":
96 total_memory= int(total_memory)
105 def get_block_device_list(vars = {}, log = sys.stderr):
107 get a list of block devices from this system.
108 return an associative array, where the device name
109 (full /dev/device path) is the key, and the value
110 is a tuple of (major,minor,numblocks,gb_size,readonly)
113 # make sure we can access to the files/directories in /proc
114 if not os.access(PROC_PARTITIONS_PATH, os.F_OK):
117 # table with valid scsi/sata/ide/raid block device names
119 # add in valid sd and hd block device names
120 for blk_prefix in ('sd','hd'):
121 for blk_num in map ( \
122 lambda x: chr(x), range(ord('a'),ord('z')+1)):
123 devicename="%s%c" % (blk_prefix, blk_num)
124 valid_blk_names[devicename]=None
126 # add in valid scsi raid block device names
127 for M in range(0,1+1):
128 for N in range(0,7+1):
129 devicename = "cciss/c%dd%d" % (M,N)
130 valid_blk_names[devicename]=None
132 for devicename in valid_blk_names.keys():
133 # devfs under 2.4 (old boot cds) used to list partitions
134 # in a format such as scsi/host0/bus0/target0/lun0/disc
135 # and /dev/sda, etc. were just symlinks
137 devfsname= os.readlink( "/dev/%s" % devicename )
138 valid_blk_names[devfsname]=None
142 # only do this once every system boot
143 if not os.access(DEVICES_SCANNED_FLAG, os.R_OK):
145 # this is ugly. under devfs, device
146 # entries in /dev/scsi/.. and /dev/ide/...
147 # don't show up until you attempt to read
148 # from the associated device at /dev (/dev/sda).
149 # so, lets run sfdisk -l (list partitions) against
150 # most possible block devices, that way they show
151 # up when it comes time to do the install.
152 devicenames = valid_blk_names.keys()
154 for devicename in devicenames:
155 os.system( "sfdisk -l /dev/%s > /dev/null 2>&1" % devicename )
158 fb = open(DEVICES_SCANNED_FLAG,"w")
163 partitions_file= file(PROC_PARTITIONS_PATH,"r")
165 for line in partitions_file:
166 line_count= line_count + 1
168 # skip the first two lines always
172 parts= string.split(line)
179 # skip and ignore any partitions
180 if not valid_blk_names.has_key(device):
186 blocks= int(parts[2])
187 except ValueError, err:
190 gb_size= blocks/BLOCKS_PER_GB
192 # check to see if the blk device is readonly
194 # can we write to it?
195 dev_name= "/dev/%s" % device
196 fb = open(dev_name,"w")
200 # check if EROFS errno
201 if errno.errorcode.get(e.errno,None) == 'EROFS':
204 # got some other errno, pretend device is readonly
207 devicelist[dev_name]= (major,minor,blocks,gb_size,readonly)
212 def get_system_modules( vars = {}, log = sys.stderr):
214 Return a list of kernel modules that this system requires.
215 This requires access to the installed system's root
216 directory, as the following file must exist and is used:
217 <install_root>/lib/modules/(first entry if kernel_version unspecified)/modules.pcimap
219 If there are more than one kernels installed, and the kernel
220 version is not specified, then only the first one in
221 /lib/modules is used.
223 Returns a dictionary, keys being the type of module:
224 - scsi MODULE_CLASS_SCSI
225 - network MODULE_CLASS_NETWORK
226 The value being the kernel module name to load.
228 Some sata devices show up under an IDE device class,
229 hence the reason for checking for ide devices as well.
230 If there actually is a match in the pci -> module lookup
231 table, and its an ide device, its most likely sata,
232 as ide modules are built in to the kernel.
235 if not vars.has_key("SYSIMG_PATH"):
236 vars["SYSIMG_PATH"]="/"
237 SYSIMG_PATH=vars["SYSIMG_PATH"]
239 if not vars.has_key("NODE_MODEL_OPTIONS"):
240 vars["NODE_MODEL_OPTIONS"] = 0;
242 initrd, kernel_version = getKernelVersion(vars, log)
244 # get the kernel version we are assuming
245 if kernel_version is None:
247 kernel_version= os.listdir( "%s/lib/modules/" % SYSIMG_PATH )
251 if len(kernel_version) == 0:
254 if len(kernel_version) > 1:
255 print( "WARNING: We may be returning modules for the wrong kernel." )
257 kernel_version= kernel_version[0]
259 print( "Using kernel version %s" % kernel_version )
261 # test to make sure the file we need is present
262 modules_pcimap_path = "%s/lib/modules/%s/modules.pcimap" % \
263 (SYSIMG_PATH,kernel_version)
264 if not os.access(modules_pcimap_path,os.R_OK):
265 print( "WARNING: Unable to read %s" % modules_pcimap_path )
268 pcimap = pypcimap.PCIMap(modules_pcimap_path)
270 # this is the actual data structure we return
273 # these are the lists that will be in system_mods
277 # XXX: this is really similar to what BootCD/conf_files/pl_hwinit does. merge?
278 pcidevs = get_devices()
280 for slot in sorted(pcidevs.keys()):
282 base = (dev[4] & 0xff0000) >> 16
283 if base not in (PCI_BASE_CLASS_STORAGE,
284 PCI_BASE_CLASS_NETWORK):
287 modules = pcimap.get(dev)
289 if base == PCI_BASE_CLASS_NETWORK:
290 network_mods += modules
291 elif base == PCI_BASE_CLASS_STORAGE:
294 system_mods[MODULE_CLASS_SCSI]= scsi_mods
295 system_mods[MODULE_CLASS_NETWORK]= network_mods
300 def getKernelVersion( vars = {} , log = sys.stderr):
301 # make sure we have the variables we need
303 SYSIMG_PATH= vars["SYSIMG_PATH"]
304 if SYSIMG_PATH == "":
305 raise ValueError, "SYSIMG_PATH"
307 NODE_MODEL_OPTIONS=vars["NODE_MODEL_OPTIONS"]
308 except KeyError, var:
309 raise BootManagerException, "Missing variable in vars: %s\n" % var
310 except ValueError, var:
311 raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
314 if NODE_MODEL_OPTIONS & ModelOptions.SMP:
317 os.stat("%s/boot/kernel-boot%s" % (SYSIMG_PATH,option))
318 os.stat("%s/boot/initrd-boot%s" % (SYSIMG_PATH,option))
320 # smp kernel is not there; remove option from modeloptions
321 # such that the rest of the code base thinks we are just
322 # using the base kernel.
323 NODE_MODEL_OPTIONS = NODE_MODEL_OPTIONS & ~ModelOptions.SMP
324 vars["NODE_MODEL_OPTIONS"] = NODE_MODEL_OPTIONS
325 log.write( "WARNING: Couldn't locate smp kernel.\n")
328 initrd= os.readlink( "%s/boot/initrd-boot%s" % (SYSIMG_PATH,option) )
329 kernel_version= initrd.replace("initrd-", "").replace(".img", "")
332 kernel_version = None
334 return (initrd, kernel_version)
337 if __name__ == "__main__":
338 devices= get_block_device_list()
339 print "block devices detected:"
341 print "no devices found!"
343 for dev in devices.keys():
344 print "%s %s" % (dev, repr(devices[dev]))
348 memory= get_total_phsyical_mem()
350 print "unable to read /proc/meminfo for memory"
352 print "total physical memory: %d kb" % memory
357 kernel_version = None
358 if len(sys.argv) > 2:
359 kernel_version = sys.argv[1]
361 modules= get_system_modules()
363 print "unable to list system modules"
365 for module_class in (MODULE_CLASS_SCSI,MODULE_CLASS_NETWORK):
366 if len(modules[module_class]) > 0:
368 for a_mod in modules[module_class]:
369 module_list = module_list + "%s " % a_mod
370 print "all %s modules: %s" % (module_class, module_list)