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 # -n is numeric ids (no lookup), -m is machine readable
50 LSPCI_CMD= "/sbin/lspci -nm"
52 MODULE_CLASS_NETWORK= "network"
53 MODULE_CLASS_SCSI= "scsi"
55 PCI_BASE_CLASS_NETWORK=0x02L
56 PCI_BASE_CLASS_STORAGE=0x01L
58 def get_total_phsyical_mem(vars = {}, log = sys.stderr):
60 return the total physical memory of the machine, in kilobytes.
62 Return None if /proc/meminfo not readable.
66 meminfo_file= file(PROC_MEMINFO_PATH,"r")
72 for line in meminfo_file:
75 (fieldname,value)= string.split(line,":")
77 # this will happen for lines that don't have two values
78 # (like the first line on 2.4 kernels)
81 fieldname= string.strip(fieldname)
82 value= string.strip(value)
84 if fieldname == "MemTotal":
86 (total_memory,units)= string.split(value)
90 if total_memory == "" or total_memory == None or \
91 units == "" or units == None:
94 if string.lower(units) != "kb":
98 total_memory= int(total_memory)
107 def get_block_device_list(vars = {}, log = sys.stderr):
109 get a list of block devices from this system.
110 return an associative array, where the device name
111 (full /dev/device path) is the key, and the value
112 is a tuple of (major,minor,numblocks,gb_size,readonly)
115 # make sure we can access to the files/directories in /proc
116 if not os.access(PROC_PARTITIONS_PATH, os.F_OK):
119 # table with valid scsi/sata/ide/raid block device names
121 # add in valid sd and hd block device names
122 for blk_prefix in ('sd','hd'):
123 for blk_num in map ( \
124 lambda x: chr(x), range(ord('a'),ord('z')+1)):
125 devicename="%s%c" % (blk_prefix, blk_num)
126 valid_blk_names[devicename]=None
128 # add in valid scsi raid block device names
129 for M in range(0,1+1):
130 for N in range(0,7+1):
131 devicename = "cciss/c%dd%d" % (M,N)
132 valid_blk_names[devicename]=None
134 for devicename in valid_blk_names.keys():
135 # devfs under 2.4 (old boot cds) used to list partitions
136 # in a format such as scsi/host0/bus0/target0/lun0/disc
137 # and /dev/sda, etc. were just symlinks
139 devfsname= os.readlink( "/dev/%s" % devicename )
140 valid_blk_names[devfsname]=None
144 # only do this once every system boot
145 if not os.access(DEVICES_SCANNED_FLAG, os.R_OK):
147 # this is ugly. under devfs, device
148 # entries in /dev/scsi/.. and /dev/ide/...
149 # don't show up until you attempt to read
150 # from the associated device at /dev (/dev/sda).
151 # so, lets run sfdisk -l (list partitions) against
152 # most possible block devices, that way they show
153 # up when it comes time to do the install.
154 devicenames = valid_blk_names.keys()
156 for devicename in devicenames:
157 os.system( "sfdisk -l /dev/%s > /dev/null 2>&1" % devicename )
160 fb = open(DEVICES_SCANNED_FLAG,"w")
165 partitions_file= file(PROC_PARTITIONS_PATH,"r")
167 for line in partitions_file:
168 line_count= line_count + 1
170 # skip the first two lines always
174 parts= string.split(line)
181 # skip and ignore any partitions
182 if not valid_blk_names.has_key(device):
188 blocks= int(parts[2])
189 except ValueError, err:
192 gb_size= blocks/BLOCKS_PER_GB
194 # check to see if the blk device is readonly
196 # can we write to it?
197 dev_name= "/dev/%s" % device
198 fb = open(dev_name,"w")
202 # check if EROFS errno
203 if errno.errorcode.get(e.errno,None) == 'EROFS':
206 # got some other errno, pretend device is readonly
209 devicelist[dev_name]= (major,minor,blocks,gb_size,readonly)
214 def get_system_modules( vars = {}, log = sys.stderr):
216 Return a list of kernel modules that this system requires.
217 This requires access to the installed system's root
218 directory, as the following file must exist and is used:
219 <install_root>/lib/modules/(first entry if kernel_version unspecified)/modules.pcimap
221 If there are more than one kernels installed, and the kernel
222 version is not specified, then only the first one in
223 /lib/modules is used.
225 Returns a dictionary, keys being the type of module:
226 - scsi MODULE_CLASS_SCSI
227 - network MODULE_CLASS_NETWORK
228 The value being the kernel module name to load.
230 Some sata devices show up under an IDE device class,
231 hence the reason for checking for ide devices as well.
232 If there actually is a match in the pci -> module lookup
233 table, and its an ide device, its most likely sata,
234 as ide modules are built in to the kernel.
237 if not vars.has_key("SYSIMG_PATH"):
238 vars["SYSIMG_PATH"]="/"
239 SYSIMG_PATH=vars["SYSIMG_PATH"]
241 if not vars.has_key("NODE_MODEL_OPTIONS"):
242 vars["NODE_MODEL_OPTIONS"] = 0;
244 initrd, kernel_version = getKernelVersion(vars, log)
246 # get the kernel version we are assuming
247 if kernel_version is None:
249 kernel_version= os.listdir( "%s/lib/modules/" % SYSIMG_PATH )
253 if len(kernel_version) == 0:
256 if len(kernel_version) > 1:
257 print( "WARNING: We may be returning modules for the wrong kernel." )
259 kernel_version= kernel_version[0]
261 print( "Using kernel version %s" % kernel_version )
263 # test to make sure the file we need is present
264 modules_pcimap_path = "%s/lib/modules/%s/modules.pcimap" % \
265 (SYSIMG_PATH,kernel_version)
266 if not os.access(modules_pcimap_path,os.R_OK):
267 print( "WARNING: Unable to read %s" % modules_pcimap_path )
270 pcimap = pypcimap.PCIMap(modules_pcimap_path)
272 # this is the actual data structure we return
275 # these are the lists that will be in system_mods
279 # XXX: this is really similar to what BootCD/conf_files/pl_hwinit does. merge?
280 pcidevs = get_devices()
282 for (slot, dev) in pcidevs.iteritems():
283 base = (dev[4] & 0xff0000) >> 16
284 if base not in (PCI_BASE_CLASS_STORAGE,
285 PCI_BASE_CLASS_NETWORK):
288 modules = pcimap.get(dev)
290 if base == PCI_BASE_CLASS_NETWORK:
291 network_mods += modules
292 elif base == PCI_BASE_CLASS_STORAGE:
295 system_mods[MODULE_CLASS_SCSI]= scsi_mods
296 system_mods[MODULE_CLASS_NETWORK]= network_mods
301 def getKernelVersion( vars = {} , log = sys.stderr):
302 # make sure we have the variables we need
304 SYSIMG_PATH= vars["SYSIMG_PATH"]
305 if SYSIMG_PATH == "":
306 raise ValueError, "SYSIMG_PATH"
308 NODE_MODEL_OPTIONS=vars["NODE_MODEL_OPTIONS"]
309 except KeyError, var:
310 raise BootManagerException, "Missing variable in vars: %s\n" % var
311 except ValueError, var:
312 raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
315 if NODE_MODEL_OPTIONS & ModelOptions.SMP:
318 os.stat("%s/boot/kernel-boot%s" % (SYSIMG_PATH,option))
319 os.stat("%s/boot/initrd-boot%s" % (SYSIMG_PATH,option))
321 # smp kernel is not there; remove option from modeloptions
322 # such that the rest of the code base thinks we are just
323 # using the base kernel.
324 NODE_MODEL_OPTIONS = NODE_MODEL_OPTIONS & ~ModelOptions.SMP
325 vars["NODE_MODEL_OPTIONS"] = NODE_MODEL_OPTIONS
326 log.write( "WARNING: Couldn't locate smp kernel.\n")
329 initrd= os.readlink( "%s/boot/initrd-boot%s" % (SYSIMG_PATH,option) )
330 kernel_version= initrd.replace("initrd-", "").replace(".img", "")
333 kernel_version = None
335 return (initrd, kernel_version)
338 if __name__ == "__main__":
339 devices= get_block_device_list()
340 print "block devices detected:"
342 print "no devices found!"
344 for dev in devices.keys():
345 print "%s %s" % (dev, repr(devices[dev]))
349 memory= get_total_phsyical_mem()
351 print "unable to read /proc/meminfo for memory"
353 print "total physical memory: %d kb" % memory
358 kernel_version = None
359 if len(sys.argv) > 2:
360 kernel_version = sys.argv[1]
362 modules= get_system_modules()
364 print "unable to list system modules"
366 for module_class in (MODULE_CLASS_SCSI,MODULE_CLASS_NETWORK):
367 if len(modules[module_class]) > 0:
369 for a_mod in modules[module_class]:
370 module_list = module_list + "%s " % a_mod
371 print "all %s modules: %s" % (module_class, module_list)