6 # Copyright (c) 2003 Intel Corporation
9 # Copyright (c) 2004-2006 The Trustees of Princeton University
10 # All rights reserved.
11 # expected /proc/partitions format
14 #----------------------------------------------------
15 #major minor #blocks name
22 #----------------------------------------------------
33 from Exceptions import *
36 a utility class for finding and returning information about
37 block devices, memory, and other hardware on the system
40 PROC_MEMINFO_PATH= "/proc/meminfo"
41 PROC_PARTITIONS_PATH= "/proc/partitions"
43 # set when the sfdisk -l <dev> trick has been done to make
45 DEVICES_SCANNED_FLAG= "/tmp/devices_scanned"
47 # a /proc/partitions block is 1024 bytes
48 # a GB to a HDD manufacturer is 10^9 bytes
49 BLOCKS_PER_GB = pow(10, 9) / 1024.0;
52 MODULE_CLASS_NETWORK= "network"
53 MODULE_CLASS_SCSI= "scsi"
55 #PCI_* is now defined in the pypci modules
56 #PCI_BASE_CLASS_NETWORK=0x02L
57 #PCI_BASE_CLASS_STORAGE=0x01L
59 def get_total_phsyical_mem(vars = {}, log = sys.stderr):
61 return the total physical memory of the machine, in kilobytes.
63 Return None if /proc/meminfo not readable.
67 meminfo_file= file(PROC_MEMINFO_PATH,"r")
73 for line in meminfo_file:
76 (fieldname,value)= string.split(line,":")
78 # this will happen for lines that don't have two values
79 # (like the first line on 2.4 kernels)
82 fieldname= string.strip(fieldname)
83 value= string.strip(value)
85 if fieldname == "MemTotal":
87 (total_memory,units)= string.split(value)
91 if total_memory == "" or total_memory == None or \
92 units == "" or units == None:
95 if string.lower(units) != "kb":
99 total_memory= int(total_memory)
100 except ValueError, e:
108 def get_block_device_list(vars = {}, log = sys.stderr):
110 get a list of block devices from this system.
111 return an associative array, where the device name
112 (full /dev/device path) is the key, and the value
113 is a tuple of (major,minor,numblocks,gb_size,readonly)
116 # make sure we can access to the files/directories in /proc
117 if not os.access(PROC_PARTITIONS_PATH, os.F_OK):
120 # table with valid scsi/sata/ide/raid block device names
122 # add in valid sd and hd block device names
123 for blk_prefix in ('sd','hd'):
124 for blk_num in map ( \
125 lambda x: chr(x), range(ord('a'),ord('z')+1)):
126 devicename="%s%c" % (blk_prefix, blk_num)
127 valid_blk_names[devicename]=None
129 # add in valid scsi raid block device names
130 for M in range(0,1+1):
131 for N in range(0,7+1):
132 devicename = "cciss/c%dd%d" % (M,N)
133 valid_blk_names[devicename]=None
135 for devicename in valid_blk_names.keys():
136 # devfs under 2.4 (old boot cds) used to list partitions
137 # in a format such as scsi/host0/bus0/target0/lun0/disc
138 # and /dev/sda, etc. were just symlinks
140 devfsname= os.readlink( "/dev/%s" % devicename )
141 valid_blk_names[devfsname]=None
145 # only do this once every system boot
146 if not os.access(DEVICES_SCANNED_FLAG, os.R_OK):
148 # this is ugly. under devfs, device
149 # entries in /dev/scsi/.. and /dev/ide/...
150 # don't show up until you attempt to read
151 # from the associated device at /dev (/dev/sda).
152 # so, lets run sfdisk -l (list partitions) against
153 # most possible block devices, that way they show
154 # up when it comes time to do the install.
155 devicenames = valid_blk_names.keys()
157 for devicename in devicenames:
158 os.system( "sfdisk -l /dev/%s > /dev/null 2>&1" % devicename )
161 fb = open(DEVICES_SCANNED_FLAG,"w")
166 partitions_file= file(PROC_PARTITIONS_PATH,"r")
168 for line in partitions_file:
169 line_count= line_count + 1
171 # skip the first two lines always
175 parts= string.split(line)
182 # skip and ignore any partitions
183 if not valid_blk_names.has_key(device):
189 blocks= int(parts[2])
190 except ValueError, err:
193 gb_size= blocks/BLOCKS_PER_GB
195 # check to see if the blk device is readonly
197 # can we write to it?
198 dev_name= "/dev/%s" % device
199 fb = open(dev_name,"w")
203 # check if EROFS errno
204 if errno.errorcode.get(e.errno,None) == 'EROFS':
207 # got some other errno, pretend device is readonly
210 devicelist[dev_name]= (major,minor,blocks,gb_size,readonly)
215 def get_system_modules( vars = {}, log = sys.stderr):
217 Return a list of kernel modules that this system requires.
218 This requires access to the installed system's root
219 directory, as the following file must exist and is used:
220 <install_root>/lib/modules/(first entry if kernel_version unspecified)/modules.pcimap
222 If there are more than one kernels installed, and the kernel
223 version is not specified, then only the first one in
224 /lib/modules is used.
226 Returns a dictionary, keys being the type of module:
227 - scsi MODULE_CLASS_SCSI
228 - network MODULE_CLASS_NETWORK
229 The value being the kernel module name to load.
231 Some sata devices show up under an IDE device class,
232 hence the reason for checking for ide devices as well.
233 If there actually is a match in the pci -> module lookup
234 table, and its an ide device, its most likely sata,
235 as ide modules are built in to the kernel.
238 if not vars.has_key("SYSIMG_PATH"):
239 vars["SYSIMG_PATH"]="/"
240 SYSIMG_PATH=vars["SYSIMG_PATH"]
242 if not vars.has_key("NODE_MODEL_OPTIONS"):
243 vars["NODE_MODEL_OPTIONS"] = 0;
245 initrd, kernel_version = getKernelVersion(vars, log)
247 # get the kernel version we are assuming
248 if kernel_version is None:
250 kernel_version= os.listdir( "%s/lib/modules/" % SYSIMG_PATH )
254 if len(kernel_version) == 0:
257 if len(kernel_version) > 1:
258 print( "WARNING: We may be returning modules for the wrong kernel." )
260 kernel_version= kernel_version[0]
262 print( "Using kernel version %s" % kernel_version )
264 # test to make sure the file we need is present
265 modules_pcimap_path = "%s/lib/modules/%s/modules.pcimap" % \
266 (SYSIMG_PATH,kernel_version)
267 if not os.access(modules_pcimap_path,os.R_OK):
268 print( "WARNING: Unable to read %s" % modules_pcimap_path )
271 pcimap = pypcimap.PCIMap(modules_pcimap_path)
273 # this is the actual data structure we return
276 # these are the lists that will be in system_mods
280 # XXX: this is really similar to what BootCD/conf_files/pl_hwinit does. merge?
281 pcidevs = get_devices()
283 devlist=pcidevs.keys()
287 base = (dev[4] & 0xff0000) >> 16
288 modules = pcimap.get(dev)
289 if base not in (PCI_BASE_CLASS_STORAGE,
290 PCI_BASE_CLASS_NETWORK):
291 # special exception for forcedeth NICs whose base id
292 # claims to be a Bridge, even though it is clearly a
294 if "forcedeth" in modules:
295 base=PCI_BASE_CLASS_NETWORK
300 if base == PCI_BASE_CLASS_NETWORK:
301 network_mods += modules
302 elif base == PCI_BASE_CLASS_STORAGE:
305 system_mods[MODULE_CLASS_SCSI]= scsi_mods
306 system_mods[MODULE_CLASS_NETWORK]= network_mods
311 def getKernelVersion( vars = {} , log = sys.stderr):
312 # make sure we have the variables we need
314 SYSIMG_PATH= vars["SYSIMG_PATH"]
315 if SYSIMG_PATH == "":
316 raise ValueError, "SYSIMG_PATH"
318 NODE_MODEL_OPTIONS=vars["NODE_MODEL_OPTIONS"]
319 except KeyError, var:
320 raise BootManagerException, "Missing variable in vars: %s\n" % var
321 except ValueError, var:
322 raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
325 if NODE_MODEL_OPTIONS & ModelOptions.SMP:
328 os.stat("%s/boot/kernel-boot%s" % (SYSIMG_PATH,option))
329 os.stat("%s/boot/initrd-boot%s" % (SYSIMG_PATH,option))
331 # smp kernel is not there; remove option from modeloptions
332 # such that the rest of the code base thinks we are just
333 # using the base kernel.
334 NODE_MODEL_OPTIONS = NODE_MODEL_OPTIONS & ~ModelOptions.SMP
335 vars["NODE_MODEL_OPTIONS"] = NODE_MODEL_OPTIONS
336 log.write( "WARNING: Couldn't locate smp kernel.\n")
339 initrd= os.readlink( "%s/boot/initrd-boot%s" % (SYSIMG_PATH,option) )
340 kernel_version= initrd.replace("initrd-", "").replace(".img", "")
343 kernel_version = None
345 return (initrd, kernel_version)
348 if __name__ == "__main__":
349 devices= get_block_device_list()
350 print "block devices detected:"
352 print "no devices found!"
354 for dev in devices.keys():
355 print "%s %s" % (dev, repr(devices[dev]))
359 memory= get_total_phsyical_mem()
361 print "unable to read /proc/meminfo for memory"
363 print "total physical memory: %d kb" % memory
368 kernel_version = None
369 if len(sys.argv) > 2:
370 kernel_version = sys.argv[1]
372 modules= get_system_modules()
374 print "unable to list system modules"
376 for module_class in (MODULE_CLASS_SCSI,MODULE_CLASS_NETWORK):
377 if len(modules[module_class]) > 0:
379 for a_mod in modules[module_class]:
380 module_list = module_list + "%s " % a_mod
381 print "all %s modules: %s" % (module_class, module_list)