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 # also check for vd (virtio devices used with kvm)
121 for blk_prefix in ('sd','hd','vd'):
122 for blk_num in map ( \
123 lambda x: chr(x), range(ord('a'),ord('z')+1)):
124 devicename="%s%c" % (blk_prefix, blk_num)
125 valid_blk_names[devicename]=None
127 # add in valid scsi raid block device names
128 for M in range(0,1+1):
129 for N in range(0,7+1):
130 devicename = "cciss/c%dd%d" % (M,N)
131 valid_blk_names[devicename]=None
133 for devicename in valid_blk_names.keys():
134 # devfs under 2.4 (old boot cds) used to list partitions
135 # in a format such as scsi/host0/bus0/target0/lun0/disc
136 # and /dev/sda, etc. were just symlinks
138 devfsname= os.readlink( "/dev/%s" % devicename )
139 valid_blk_names[devfsname]=None
143 # only do this once every system boot
144 if not os.access(DEVICES_SCANNED_FLAG, os.R_OK):
146 # this is ugly. under devfs, device
147 # entries in /dev/scsi/.. and /dev/ide/...
148 # don't show up until you attempt to read
149 # from the associated device at /dev (/dev/sda).
150 # so, lets run sfdisk -l (list partitions) against
151 # most possible block devices, that way they show
152 # up when it comes time to do the install.
153 devicenames = valid_blk_names.keys()
155 for devicename in devicenames:
156 os.system( "sfdisk -l /dev/%s > /dev/null 2>&1" % devicename )
159 fb = open(DEVICES_SCANNED_FLAG,"w")
164 partitions_file= file(PROC_PARTITIONS_PATH,"r")
166 for line in partitions_file:
167 line_count= line_count + 1
169 # skip the first two lines always
173 parts= string.split(line)
180 # skip and ignore any partitions
181 if not valid_blk_names.has_key(device):
187 blocks= int(parts[2])
188 except ValueError, err:
191 gb_size= blocks/BLOCKS_PER_GB
193 # check to see if the blk device is readonly
195 # can we write to it?
196 dev_name= "/dev/%s" % device
197 fb = open(dev_name,"w")
201 # check if EROFS errno
202 if errno.errorcode.get(e.errno,None) == 'EROFS':
205 # got some other errno, pretend device is readonly
208 devicelist[dev_name]= (major,minor,blocks,gb_size,readonly)
213 def get_system_modules( vars = {}, log = sys.stderr):
215 Return a list of kernel modules that this system requires.
216 This requires access to the installed system's root
217 directory, as the following file must exist and is used:
218 <install_root>/lib/modules/(first entry if kernel_version unspecified)/modules.pcimap
220 If there are more than one kernels installed, and the kernel
221 version is not specified, then only the first one in
222 /lib/modules is used.
224 Returns a dictionary, keys being the type of module:
225 - scsi MODULE_CLASS_SCSI
226 - network MODULE_CLASS_NETWORK
227 The value being the kernel module name to load.
229 Some sata devices show up under an IDE device class,
230 hence the reason for checking for ide devices as well.
231 If there actually is a match in the pci -> module lookup
232 table, and its an ide device, its most likely sata,
233 as ide modules are built in to the kernel.
236 if not vars.has_key("SYSIMG_PATH"):
237 vars["SYSIMG_PATH"]="/"
238 SYSIMG_PATH=vars["SYSIMG_PATH"]
240 if not vars.has_key("NODE_MODEL_OPTIONS"):
241 vars["NODE_MODEL_OPTIONS"] = 0;
243 initrd, kernel_version = getKernelVersion(vars, log)
245 # get the kernel version we are assuming
246 if kernel_version is None:
248 kernel_version= os.listdir( "%s/lib/modules/" % SYSIMG_PATH )
252 if len(kernel_version) == 0:
255 if len(kernel_version) > 1:
256 print( "WARNING: We may be returning modules for the wrong kernel." )
258 kernel_version= kernel_version[0]
260 print( "Using kernel version %s" % kernel_version )
262 # test to make sure the file we need is present
263 modules_pcimap_path = "%s/lib/modules/%s/modules.pcimap" % \
264 (SYSIMG_PATH,kernel_version)
265 if not os.access(modules_pcimap_path,os.R_OK):
266 print( "WARNING: Unable to read %s" % modules_pcimap_path )
269 pcimap = pypcimap.PCIMap(modules_pcimap_path)
271 # this is the actual data structure we return
274 # these are the lists that will be in system_mods
278 # XXX: this is really similar to what BootCD/conf_files/pl_hwinit does. merge?
279 pcidevs = get_devices()
281 devlist=pcidevs.keys()
285 base = (dev[4] & 0xff0000) >> 16
286 modules = pcimap.get(dev)
287 if base not in (PCI_BASE_CLASS_STORAGE,
288 PCI_BASE_CLASS_NETWORK):
289 # special exception for forcedeth NICs whose base id
290 # claims to be a Bridge, even though it is clearly a
292 if "forcedeth" in modules:
293 base=PCI_BASE_CLASS_NETWORK
298 if base == PCI_BASE_CLASS_NETWORK:
299 network_mods += modules
300 elif base == PCI_BASE_CLASS_STORAGE:
303 system_mods[MODULE_CLASS_SCSI]= scsi_mods
304 system_mods[MODULE_CLASS_NETWORK]= network_mods
309 def getKernelVersion( vars = {} , log = sys.stderr):
310 # make sure we have the variables we need
312 SYSIMG_PATH= vars["SYSIMG_PATH"]
313 if SYSIMG_PATH == "":
314 raise ValueError, "SYSIMG_PATH"
316 NODE_MODEL_OPTIONS=vars["NODE_MODEL_OPTIONS"]
317 except KeyError, var:
318 raise BootManagerException, "Missing variable in vars: %s\n" % var
319 except ValueError, var:
320 raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
323 if NODE_MODEL_OPTIONS & ModelOptions.SMP:
326 os.stat("%s/boot/kernel-boot%s" % (SYSIMG_PATH,option))
327 os.stat("%s/boot/initrd-boot%s" % (SYSIMG_PATH,option))
329 # smp kernel is not there; remove option from modeloptions
330 # such that the rest of the code base thinks we are just
331 # using the base kernel.
332 NODE_MODEL_OPTIONS = NODE_MODEL_OPTIONS & ~ModelOptions.SMP
333 vars["NODE_MODEL_OPTIONS"] = NODE_MODEL_OPTIONS
334 log.write( "WARNING: Couldn't locate smp kernel.\n")
337 initrd= os.readlink( "%s/boot/initrd-boot%s" % (SYSIMG_PATH,option) )
338 kernel_version= initrd.replace("initrd-", "").replace(".img", "")
341 kernel_version = None
343 return (initrd, kernel_version)
346 if __name__ == "__main__":
347 devices= get_block_device_list()
348 print "block devices detected:"
350 print "no devices found!"
352 for dev in devices.keys():
353 print "%s %s" % (dev, repr(devices[dev]))
357 memory= get_total_phsyical_mem()
359 print "unable to read /proc/meminfo for memory"
361 print "total physical memory: %d kb" % memory
366 kernel_version = None
367 if len(sys.argv) > 2:
368 kernel_version = sys.argv[1]
370 modules= get_system_modules()
372 print "unable to list system modules"
374 for module_class in (MODULE_CLASS_SCSI,MODULE_CLASS_NETWORK):
375 if len(modules[module_class]) > 0:
377 for a_mod in modules[module_class]:
378 module_list = module_list + "%s " % a_mod
379 print "all %s modules: %s" % (module_class, module_list)