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 #----------------------------------------------------
31 from Exceptions import *
34 a utility class for finding and returning information about
35 block devices, memory, and other hardware on the system
38 PROC_MEMINFO_PATH= "/proc/meminfo"
39 PROC_PARTITIONS_PATH= "/proc/partitions"
41 # set when the sfdisk -l <dev> trick has been done to make
43 DEVICES_SCANNED_FLAG= "/tmp/devices_scanned"
45 # a /proc/partitions block is 1024 bytes
46 # a GB to a HDD manufacturer is 10^9 bytes
47 BLOCKS_PER_GB = pow(10, 9) / 1024.0;
50 # -n is numeric ids (no lookup), -m is machine readable
51 LSPCI_CMD= "/sbin/lspci -nm"
53 MODULE_CLASS_NETWORK= "network"
54 MODULE_CLASS_SCSI= "scsi"
56 PCI_BASE_CLASS_NETWORK=0x02L
57 PCI_BASE_CLASS_STORAGE=0x01L
61 def get_total_phsyical_mem(vars = {}, log = sys.stderr):
63 return the total physical memory of the machine, in kilobytes.
65 Return None if /proc/meminfo not readable.
69 meminfo_file= file(PROC_MEMINFO_PATH,"r")
75 for line in meminfo_file:
78 (fieldname,value)= string.split(line,":")
80 # this will happen for lines that don't have two values
81 # (like the first line on 2.4 kernels)
84 fieldname= string.strip(fieldname)
85 value= string.strip(value)
87 if fieldname == "MemTotal":
89 (total_memory,units)= string.split(value)
93 if total_memory == "" or total_memory == None or \
94 units == "" or units == None:
97 if string.lower(units) != "kb":
101 total_memory= int(total_memory)
102 except ValueError, e:
110 def get_block_device_list(vars = {}, log = sys.stderr):
112 get a list of block devices from this system.
113 return an associative array, where the device name
114 (full /dev/device path) is the key, and the value
115 is a tuple of (major,minor,numblocks,gb_size,readonly)
118 # make sure we can access to the files/directories in /proc
119 if not os.access(PROC_PARTITIONS_PATH, os.F_OK):
122 # table with valid scsi/sata/ide/raid block device names
124 # add in valid sd and hd block device names
125 for blk_prefix in ('sd','hd'):
126 for blk_num in map ( \
127 lambda x: chr(x), range(ord('a'),ord('z')+1)):
128 devicename="%s%c" % (blk_prefix, blk_num)
129 valid_blk_names[devicename]=None
131 # add in valid scsi raid block device names
132 for M in range(0,1+1):
133 for N in range(0,7+1):
134 devicename = "cciss/c%dd%d" % (M,N)
135 valid_blk_names[devicename]=None
137 for devicename in valid_blk_names.keys():
138 # devfs under 2.4 (old boot cds) used to list partitions
139 # in a format such as scsi/host0/bus0/target0/lun0/disc
140 # and /dev/sda, etc. were just symlinks
142 devfsname= os.readlink( "/dev/%s" % devicename )
143 valid_blk_names[devfsname]=None
147 # only do this once every system boot
148 if not os.access(DEVICES_SCANNED_FLAG, os.R_OK):
150 # this is ugly. under devfs, device
151 # entries in /dev/scsi/.. and /dev/ide/...
152 # don't show up until you attempt to read
153 # from the associated device at /dev (/dev/sda).
154 # so, lets run sfdisk -l (list partitions) against
155 # most possible block devices, that way they show
156 # up when it comes time to do the install.
157 devicenames = valid_blk_names.keys()
159 for devicename in devicenames:
160 os.system( "sfdisk -l /dev/%s > /dev/null 2>&1" % devicename )
163 fb = open(DEVICES_SCANNED_FLAG,"w")
168 partitions_file= file(PROC_PARTITIONS_PATH,"r")
170 for line in partitions_file:
171 line_count= line_count + 1
173 # skip the first two lines always
177 parts= string.split(line)
184 # skip and ignore any partitions
185 if not valid_blk_names.has_key(device):
191 blocks= int(parts[2])
192 except ValueError, err:
195 gb_size= blocks/BLOCKS_PER_GB
197 # check to see if the blk device is readonly
199 # can we write to it?
200 dev_name= "/dev/%s" % device
201 fb = open(dev_name,"w")
205 # check if EROFS errno
206 if errno.errorcode.get(e.errno,None) == 'EROFS':
209 # got some other errno, pretend device is readonly
212 devicelist[dev_name]= (major,minor,blocks,gb_size,readonly)
217 def get_system_modules( vars = {}, log = sys.stderr):
219 Return a list of kernel modules that this system requires.
220 This requires access to the installed system's root
221 directory, as the following file must exist and is used:
222 <install_root>/lib/modules/(first entry if kernel_version unspecified)/modules.pcimap
224 If there are more than one kernels installed, and the kernel
225 version is not specified, then only the first one in
226 /lib/modules is used.
228 Returns a dictionary, keys being the type of module:
229 - scsi MODULE_CLASS_SCSI
230 - network MODULE_CLASS_NETWORK
231 The value being the kernel module name to load.
233 Some sata devices show up under an IDE device class,
234 hence the reason for checking for ide devices as well.
235 If there actually is a match in the pci -> module lookup
236 table, and its an ide device, its most likely sata,
237 as ide modules are built in to the kernel.
240 if not vars.has_key("SYSIMG_PATH"):
241 vars["SYSIMG_PATH"]="/"
242 SYSIMG_PATH=vars["SYSIMG_PATH"]
244 if not vars.has_key("NODE_MODEL_OPTIONS"):
245 vars["NODE_MODEL_OPTIONS"] = 0;
247 initrd, kernel_version = getKernelVersion(vars, log)
249 # get the kernel version we are assuming
250 if kernel_version is None:
252 kernel_version= os.listdir( "%s/lib/modules/" % SYSIMG_PATH )
256 if len(kernel_version) == 0:
259 if len(kernel_version) > 1:
260 print( "WARNING: We may be returning modules for the wrong kernel." )
262 kernel_version= kernel_version[0]
264 print( "Using kernel version %s" % kernel_version )
266 # test to make sure the file we need is present
267 modules_pcimap_path = "%s/lib/modules/%s/modules.pcimap" % \
268 (SYSIMG_PATH,kernel_version)
269 if not os.access(modules_pcimap_path,os.R_OK):
270 print( "Unable to read %s" % path )
273 pcimap = pypcimap.PCIMap(modules_pcimap_path)
275 # this is the actual data structure we return
278 # these are the lists that will be in system_mods
282 # XXX: this is really similar to what BootCD/conf_files/pl_hwinit does. merge?
283 pcidevs = pypciscan.get_devices()
285 for (slot, dev) in pcidevs.iteritems():
286 base = (dev[4] & 0xff0000) >> 16
287 if base not in (PCI_BASE_CLASS_STORAGE,
288 PCI_BASE_CLASS_NETWORK):
291 modules = pcimap.get(dev)
293 if base == PCI_BASE_CLASS_NETWORK:
294 network_mods.append(modules[0])
295 elif base == PCI_BASE_CLASS_STORAGE:
296 scsi_mods.append(modules[0])
298 # XXX ata_piix and ahci both claim 8086:2652 and 8086:2653,
299 # and it is usually a non-visible BIOS option that decides
300 # which is appropriate. Just load both.
301 if dev[0] == 0x8086 and (dev[1] == 0x2652 or dev[1] == 0x2653):
302 if modules[0] == "ahci":
303 scsi_mods.append("ata_piix")
304 elif modules[0] == "ata_piix":
305 scsi_mods.append("ahci")
307 system_mods[MODULE_CLASS_SCSI]= scsi_mods
308 system_mods[MODULE_CLASS_NETWORK]= network_mods
313 def getKernelVersion( vars = {} , log = sys.stderr):
314 # make sure we have the variables we need
316 SYSIMG_PATH= vars["SYSIMG_PATH"]
317 if SYSIMG_PATH == "":
318 raise ValueError, "SYSIMG_PATH"
320 NODE_MODEL_OPTIONS=vars["NODE_MODEL_OPTIONS"]
321 except KeyError, var:
322 raise BootManagerException, "Missing variable in vars: %s\n" % var
323 except ValueError, var:
324 raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
327 if NODE_MODEL_OPTIONS & ModelOptions.SMP:
330 os.stat("%s/boot/kernel-boot%s" % (SYSIMG_PATH,option))
331 os.stat("%s/boot/initrd-boot%s" % (SYSIMG_PATH,option))
333 # smp kernel is not there; remove option from modeloptions
334 # such that the rest of the code base thinks we are just
335 # using the base kernel.
336 NODE_MODEL_OPTIONS = NODE_MODEL_OPTIONS & ~ModelOptions.SMP
337 vars["NODE_MODEL_OPTIONS"] = NODE_MODEL_OPTIONS
338 log.write( "WARNING: Couldn't locate smp kernel.\n")
341 initrd= os.readlink( "%s/boot/initrd-boot%s" % (SYSIMG_PATH,option) )
342 kernel_version= initrd.replace("initrd-", "").replace(".img", "")
345 kernel_version = None
347 return (initrd, kernel_version)
350 if __name__ == "__main__":
351 devices= get_block_device_list()
352 print "block devices detected:"
354 print "no devices found!"
356 for dev in devices.keys():
357 print "%s %s" % (dev, repr(devices[dev]))
361 memory= get_total_phsyical_mem()
363 print "unable to read /proc/meminfo for memory"
365 print "total physical memory: %d kb" % memory
370 kernel_version = None
371 if len(sys.argv) > 2:
372 kernel_version = sys.argv[1]
374 modules= get_system_modules()
376 print "unable to list system modules"
379 if type == MODULE_CLASS_SCSI:
380 print( "all scsi modules:" )
381 for a_mod in modules[type]:
383 elif type == MODULE_CLASS_NETWORK:
384 print( "all network modules:" )
385 for a_mod in modules[type]: