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 def get_total_phsyical_mem(vars = {}, log = sys.stderr):
57 return the total physical memory of the machine, in kilobytes.
59 Return None if /proc/meminfo not readable.
63 meminfo_file= file(PROC_MEMINFO_PATH,"r")
69 for line in meminfo_file:
72 (fieldname,value)= string.split(line,":")
74 # this will happen for lines that don't have two values
75 # (like the first line on 2.4 kernels)
78 fieldname= string.strip(fieldname)
79 value= string.strip(value)
81 if fieldname == "MemTotal":
83 (total_memory,units)= string.split(value)
87 if total_memory == "" or total_memory == None or \
88 units == "" or units == None:
91 if string.lower(units) != "kb":
95 total_memory= int(total_memory)
104 def get_block_device_list(vars = {}, log = sys.stderr):
106 get a list of block devices from this system.
107 return an associative array, where the device name
108 (full /dev/device path) is the key, and the value
109 is a tuple of (major,minor,numblocks,gb_size,readonly)
112 # make sure we can access to the files/directories in /proc
113 if not os.access(PROC_PARTITIONS_PATH, os.F_OK):
116 # table with valid scsi/sata/ide/raid block device names
118 # add in valid sd and hd block device names
119 for blk_prefix in ('sd','hd'):
120 for blk_num in map ( \
121 lambda x: chr(x), range(ord('a'),ord('z')+1)):
122 devicename="%s%c" % (blk_prefix, blk_num)
123 valid_blk_names[devicename]=None
125 # add in valid scsi raid block device names
126 for M in range(0,1+1):
127 for N in range(0,7+1):
128 devicename = "cciss/c%dd%d" % (M,N)
129 valid_blk_names[devicename]=None
131 for devicename in valid_blk_names.keys():
132 # devfs under 2.4 (old boot cds) used to list partitions
133 # in a format such as scsi/host0/bus0/target0/lun0/disc
134 # and /dev/sda, etc. were just symlinks
136 devfsname= os.readlink( "/dev/%s" % devicename )
137 valid_blk_names[devfsname]=None
141 # only do this once every system boot
142 if not os.access(DEVICES_SCANNED_FLAG, os.R_OK):
144 # this is ugly. under devfs, device
145 # entries in /dev/scsi/.. and /dev/ide/...
146 # don't show up until you attempt to read
147 # from the associated device at /dev (/dev/sda).
148 # so, lets run sfdisk -l (list partitions) against
149 # most possible block devices, that way they show
150 # up when it comes time to do the install.
151 devicenames = valid_blk_names.keys()
153 for devicename in devicenames:
154 os.system( "sfdisk -l /dev/%s > /dev/null 2>&1" % devicename )
157 fb = open(DEVICES_SCANNED_FLAG,"w")
162 partitions_file= file(PROC_PARTITIONS_PATH,"r")
164 for line in partitions_file:
165 line_count= line_count + 1
167 # skip the first two lines always
171 parts= string.split(line)
178 # skip and ignore any partitions
179 if not valid_blk_names.has_key(device):
185 blocks= int(parts[2])
186 except ValueError, err:
189 gb_size= blocks/BLOCKS_PER_GB
191 # check to see if the blk device is readonly
193 # can we write to it?
194 dev_name= "/dev/%s" % device
195 fb = open(dev_name,"w")
199 # check if EROFS errno
200 if errno.errorcode.get(e.errno,None) == 'EROFS':
203 # got some other errno, pretend device is readonly
206 devicelist[dev_name]= (major,minor,blocks,gb_size,readonly)
211 def get_system_modules( vars = {}, log = sys.stderr):
213 Return a list of kernel modules that this system requires.
214 This requires access to the installed system's root
215 directory, as the following file must exist and is used:
216 <install_root>/lib/modules/(first entry if kernel_version unspecified)/modules.pcimap
218 If there are more than one kernels installed, and the kernel
219 version is not specified, then only the first one in
220 /lib/modules is used.
222 Returns a dictionary, keys being the type of module:
223 - scsi MODULE_CLASS_SCSI
224 - network MODULE_CLASS_NETWORK
225 The value being the kernel module name to load.
227 Some sata devices show up under an IDE device class,
228 hence the reason for checking for ide devices as well.
229 If there actually is a match in the pci -> module lookup
230 table, and its an ide device, its most likely sata,
231 as ide modules are built in to the kernel.
234 if not vars.has_key("SYSIMG_PATH"):
235 vars["SYSIMG_PATH"]="/"
236 SYSIMG_PATH=vars["SYSIMG_PATH"]
238 if not vars.has_key("NODE_MODEL_OPTIONS"):
239 vars["NODE_MODEL_OPTIONS"] = 0;
241 initrd, kernel_version = getKernelVersion(vars, log)
243 # get the kernel version we are assuming
244 if kernel_version is None:
246 kernel_version= os.listdir( "%s/lib/modules/" % SYSIMG_PATH )
250 if len(kernel_version) == 0:
253 if len(kernel_version) > 1:
254 print( "WARNING: We may be returning modules for the wrong kernel." )
256 kernel_version= kernel_version[0]
258 print( "Using kernel version %s" % kernel_version )
260 # test to make sure the file we need is present
261 modules_pcimap_path = "%s/lib/modules/%s/modules.pcimap" % \
262 (SYSIMG_PATH,kernel_version)
263 if not os.access(modules_pcimap_path,os.R_OK):
264 print( "WARNING: Unable to read %s" % modules_pcimap_path )
267 pcimap = pypcimap.PCIMap(modules_pcimap_path)
269 # this is the actual data structure we return
272 # these are the lists that will be in system_mods
276 # XXX: this is really similar to what BootCD/conf_files/pl_hwinit does. merge?
277 pcidevs = get_devices()
279 for (slot, dev) in pcidevs.iteritems():
280 base = (dev[4] & 0xff0000) >> 16
281 if base not in (PCI_BASE_CLASS_STORAGE,
282 PCI_BASE_CLASS_NETWORK):
285 modules = pcimap.get(dev)
287 if base == PCI_BASE_CLASS_NETWORK:
288 network_mods += modules
289 elif base == PCI_BASE_CLASS_STORAGE:
292 system_mods[MODULE_CLASS_SCSI]= scsi_mods
293 system_mods[MODULE_CLASS_NETWORK]= network_mods
298 def getKernelVersion( vars = {} , log = sys.stderr):
299 # make sure we have the variables we need
301 SYSIMG_PATH= vars["SYSIMG_PATH"]
302 if SYSIMG_PATH == "":
303 raise ValueError, "SYSIMG_PATH"
305 NODE_MODEL_OPTIONS=vars["NODE_MODEL_OPTIONS"]
306 except KeyError, var:
307 raise BootManagerException, "Missing variable in vars: %s\n" % var
308 except ValueError, var:
309 raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
312 if NODE_MODEL_OPTIONS & ModelOptions.SMP:
315 os.stat("%s/boot/kernel-boot%s" % (SYSIMG_PATH,option))
316 os.stat("%s/boot/initrd-boot%s" % (SYSIMG_PATH,option))
318 # smp kernel is not there; remove option from modeloptions
319 # such that the rest of the code base thinks we are just
320 # using the base kernel.
321 NODE_MODEL_OPTIONS = NODE_MODEL_OPTIONS & ~ModelOptions.SMP
322 vars["NODE_MODEL_OPTIONS"] = NODE_MODEL_OPTIONS
323 log.write( "WARNING: Couldn't locate smp kernel.\n")
326 initrd= os.readlink( "%s/boot/initrd-boot%s" % (SYSIMG_PATH,option) )
327 kernel_version= initrd.replace("initrd-", "").replace(".img", "")
330 kernel_version = None
332 return (initrd, kernel_version)
335 if __name__ == "__main__":
336 devices= get_block_device_list()
337 print "block devices detected:"
339 print "no devices found!"
341 for dev in devices.keys():
342 print "%s %s" % (dev, repr(devices[dev]))
346 memory= get_total_phsyical_mem()
348 print "unable to read /proc/meminfo for memory"
350 print "total physical memory: %d kb" % memory
355 kernel_version = None
356 if len(sys.argv) > 2:
357 kernel_version = sys.argv[1]
359 modules= get_system_modules()
361 print "unable to list system modules"
363 for module_class in (MODULE_CLASS_SCSI,MODULE_CLASS_NETWORK):
364 if len(modules[module_class]) > 0:
366 for a_mod in modules[module_class]:
367 module_list = module_list + "%s " % a_mod
368 print "all %s modules: %s" % (module_class, module_list)