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
60 def get_total_phsyical_mem(vars = {}, log = sys.stderr):
62 return the total physical memory of the machine, in kilobytes.
64 Return None if /proc/meminfo not readable.
68 meminfo_file= file(PROC_MEMINFO_PATH,"r")
74 for line in meminfo_file:
77 (fieldname,value)= string.split(line,":")
79 # this will happen for lines that don't have two values
80 # (like the first line on 2.4 kernels)
83 fieldname= string.strip(fieldname)
84 value= string.strip(value)
86 if fieldname == "MemTotal":
88 (total_memory,units)= string.split(value)
92 if total_memory == "" or total_memory == None or \
93 units == "" or units == None:
96 if string.lower(units) != "kb":
100 total_memory= int(total_memory)
101 except ValueError, e:
109 def get_block_device_list(vars = {}, log = sys.stderr):
111 get a list of block devices from this system.
112 return an associative array, where the device name
113 (full /dev/device path) is the key, and the value
114 is a tuple of (major,minor,numblocks,gb_size,readonly)
117 # make sure we can access to the files/directories in /proc
118 if not os.access(PROC_PARTITIONS_PATH, os.F_OK):
121 # table with valid scsi/sata/ide/raid block device names
123 # add in valid sd and hd block device names
124 for blk_prefix in ('sd','hd'):
125 for blk_num in map ( \
126 lambda x: chr(x), range(ord('a'),ord('z')+1)):
127 devicename="%s%c" % (blk_prefix, blk_num)
128 valid_blk_names[devicename]=None
130 # add in valid scsi raid block device names
131 for M in range(0,1+1):
132 for N in range(0,7+1):
133 devicename = "cciss/c%dd%d" % (M,N)
134 valid_blk_names[devicename]=None
136 for devicename in valid_blk_names.keys():
137 # devfs under 2.4 (old boot cds) used to list partitions
138 # in a format such as scsi/host0/bus0/target0/lun0/disc
139 # and /dev/sda, etc. were just symlinks
141 devfsname= os.readlink( "/dev/%s" % devicename )
142 valid_blk_names[devfsname]=None
146 # only do this once every system boot
147 if not os.access(DEVICES_SCANNED_FLAG, os.R_OK):
149 # this is ugly. under devfs, device
150 # entries in /dev/scsi/.. and /dev/ide/...
151 # don't show up until you attempt to read
152 # from the associated device at /dev (/dev/sda).
153 # so, lets run sfdisk -l (list partitions) against
154 # most possible block devices, that way they show
155 # up when it comes time to do the install.
156 devicenames = valid_blk_names.keys()
158 for devicename in devicenames:
159 os.system( "sfdisk -l /dev/%s > /dev/null 2>&1" % devicename )
162 fb = open(DEVICES_SCANNED_FLAG,"w")
167 partitions_file= file(PROC_PARTITIONS_PATH,"r")
169 for line in partitions_file:
170 line_count= line_count + 1
172 # skip the first two lines always
176 parts= string.split(line)
183 # skip and ignore any partitions
184 if not valid_blk_names.has_key(device):
190 blocks= int(parts[2])
191 except ValueError, err:
194 gb_size= blocks/BLOCKS_PER_GB
196 # check to see if the blk device is readonly
198 # can we write to it?
199 dev_name= "/dev/%s" % device
200 fb = open(dev_name,"w")
204 # check if EROFS errno
205 if errno.errorcode.get(e.errno,None) == 'EROFS':
208 # got some other errno, pretend device is readonly
211 devicelist[dev_name]= (major,minor,blocks,gb_size,readonly)
216 def get_system_modules( vars = {}, log = sys.stderr):
218 Return a list of kernel modules that this system requires.
219 This requires access to the installed system's root
220 directory, as the following file must exist and is used:
221 <install_root>/lib/modules/(first entry if kernel_version unspecified)/modules.pcimap
223 If there are more than one kernels installed, and the kernel
224 version is not specified, then only the first one in
225 /lib/modules is used.
227 Returns a dictionary, keys being the type of module:
228 - scsi MODULE_CLASS_SCSI
229 - network MODULE_CLASS_NETWORK
230 The value being the kernel module name to load.
232 Some sata devices show up under an IDE device class,
233 hence the reason for checking for ide devices as well.
234 If there actually is a match in the pci -> module lookup
235 table, and its an ide device, its most likely sata,
236 as ide modules are built in to the kernel.
239 if not vars.has_key("SYSIMG_PATH"):
240 vars["SYSIMG_PATH"]="/"
241 SYSIMG_PATH=vars["SYSIMG_PATH"]
243 if not vars.has_key("NODE_MODEL_OPTIONS"):
244 vars["NODE_MODEL_OPTIONS"] = 0;
246 initrd, kernel_version = getKernelVersion(vars, log)
248 # get the kernel version we are assuming
249 if kernel_version is None:
251 kernel_version= os.listdir( "%s/lib/modules/" % SYSIMG_PATH )
255 if len(kernel_version) == 0:
258 if len(kernel_version) > 1:
259 print( "WARNING: We may be returning modules for the wrong kernel." )
261 kernel_version= kernel_version[0]
263 print( "Using kernel version %s" % kernel_version )
265 # test to make sure the file we need is present
266 modules_pcimap_path = "%s/lib/modules/%s/modules.pcimap" % \
267 (SYSIMG_PATH,kernel_version)
268 if not os.access(modules_pcimap_path,os.R_OK):
269 print( "Unable to read %s" % path )
272 pcimap = pypcimap.PCIMap(modules_pcimap_path)
274 # this is the actual data structure we return
277 # these are the lists that will be in system_mods
281 # XXX: this is really similar to what BootCD/conf_files/pl_hwinit does. merge?
282 pcidevs = get_devices()
284 for (slot, dev) in pcidevs.iteritems():
285 base = (dev[4] & 0xff0000) >> 16
286 if base not in (PCI_BASE_CLASS_STORAGE,
287 PCI_BASE_CLASS_NETWORK):
290 modules = pcimap.get(dev)
292 if base == PCI_BASE_CLASS_NETWORK:
293 network_mods += modules
294 elif base == PCI_BASE_CLASS_STORAGE:
297 system_mods[MODULE_CLASS_SCSI]= scsi_mods
298 system_mods[MODULE_CLASS_NETWORK]= network_mods
303 def getKernelVersion( vars = {} , log = sys.stderr):
304 # make sure we have the variables we need
306 SYSIMG_PATH= vars["SYSIMG_PATH"]
307 if SYSIMG_PATH == "":
308 raise ValueError, "SYSIMG_PATH"
310 NODE_MODEL_OPTIONS=vars["NODE_MODEL_OPTIONS"]
311 except KeyError, var:
312 raise BootManagerException, "Missing variable in vars: %s\n" % var
313 except ValueError, var:
314 raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
317 if NODE_MODEL_OPTIONS & ModelOptions.SMP:
320 os.stat("%s/boot/kernel-boot%s" % (SYSIMG_PATH,option))
321 os.stat("%s/boot/initrd-boot%s" % (SYSIMG_PATH,option))
323 # smp kernel is not there; remove option from modeloptions
324 # such that the rest of the code base thinks we are just
325 # using the base kernel.
326 NODE_MODEL_OPTIONS = NODE_MODEL_OPTIONS & ~ModelOptions.SMP
327 vars["NODE_MODEL_OPTIONS"] = NODE_MODEL_OPTIONS
328 log.write( "WARNING: Couldn't locate smp kernel.\n")
331 initrd= os.readlink( "%s/boot/initrd-boot%s" % (SYSIMG_PATH,option) )
332 kernel_version= initrd.replace("initrd-", "").replace(".img", "")
335 kernel_version = None
337 return (initrd, kernel_version)
340 if __name__ == "__main__":
341 devices= get_block_device_list()
342 print "block devices detected:"
344 print "no devices found!"
346 for dev in devices.keys():
347 print "%s %s" % (dev, repr(devices[dev]))
351 memory= get_total_phsyical_mem()
353 print "unable to read /proc/meminfo for memory"
355 print "total physical memory: %d kb" % memory
360 kernel_version = None
361 if len(sys.argv) > 2:
362 kernel_version = sys.argv[1]
364 modules= get_system_modules()
366 print "unable to list system modules"
369 if type == MODULE_CLASS_SCSI:
370 print( "all scsi modules:" )
371 for a_mod in modules[type]:
373 elif type == MODULE_CLASS_NETWORK:
374 print( "all network modules:" )
375 for a_mod in modules[type]: