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 pypciscan import get_devices
33 """ This is a replacement to the version in pypciscan library for 3.3 and lower bootcds
34 that will help maintain backward compatibility. This version has limitations wrt accuracy
35 that the library does not. In particular it is limited to the output of
36 lspci and 'forces' all devices to appear on the '0000' domain, rather than
37 where they actually are."""
40 #pci = os.popen("lspci -nm | sed -e 's/\"//g'", 'r')
41 pci = os.popen("lspci -nm | sed -e 's/\"//g' -e 's/Class //g'", 'r')
45 key = "0000:%s" % f[0]
46 ret[key] = (int(f[2],16), int(f[3],16), 0xffff, 0xffff, int(f[1],16) << 8)
50 from Exceptions import *
53 a utility class for finding and returning information about
54 block devices, memory, and other hardware on the system
57 PROC_MEMINFO_PATH= "/proc/meminfo"
58 PROC_PARTITIONS_PATH= "/proc/partitions"
60 # set when the sfdisk -l <dev> trick has been done to make
62 DEVICES_SCANNED_FLAG= "/tmp/devices_scanned"
64 # a /proc/partitions block is 1024 bytes
65 # a GB to a HDD manufacturer is 10^9 bytes
66 BLOCKS_PER_GB = pow(10, 9) / 1024.0;
69 # -n is numeric ids (no lookup), -m is machine readable
70 LSPCI_CMD= "/sbin/lspci -nm"
72 MODULE_CLASS_NETWORK= "network"
73 MODULE_CLASS_SCSI= "scsi"
75 PCI_BASE_CLASS_NETWORK=0x02L
76 PCI_BASE_CLASS_STORAGE=0x01L
80 def get_total_phsyical_mem(vars = {}, log = sys.stderr):
82 return the total physical memory of the machine, in kilobytes.
84 Return None if /proc/meminfo not readable.
88 meminfo_file= file(PROC_MEMINFO_PATH,"r")
94 for line in meminfo_file:
97 (fieldname,value)= string.split(line,":")
99 # this will happen for lines that don't have two values
100 # (like the first line on 2.4 kernels)
103 fieldname= string.strip(fieldname)
104 value= string.strip(value)
106 if fieldname == "MemTotal":
108 (total_memory,units)= string.split(value)
109 except ValueError, e:
112 if total_memory == "" or total_memory == None or \
113 units == "" or units == None:
116 if string.lower(units) != "kb":
120 total_memory= int(total_memory)
121 except ValueError, e:
129 def get_block_device_list(vars = {}, log = sys.stderr):
131 get a list of block devices from this system.
132 return an associative array, where the device name
133 (full /dev/device path) is the key, and the value
134 is a tuple of (major,minor,numblocks,gb_size,readonly)
137 # make sure we can access to the files/directories in /proc
138 if not os.access(PROC_PARTITIONS_PATH, os.F_OK):
141 # table with valid scsi/sata/ide/raid block device names
143 # add in valid sd and hd block device names
144 for blk_prefix in ('sd','hd'):
145 for blk_num in map ( \
146 lambda x: chr(x), range(ord('a'),ord('z')+1)):
147 devicename="%s%c" % (blk_prefix, blk_num)
148 valid_blk_names[devicename]=None
150 # add in valid scsi raid block device names
151 for M in range(0,1+1):
152 for N in range(0,7+1):
153 devicename = "cciss/c%dd%d" % (M,N)
154 valid_blk_names[devicename]=None
156 for devicename in valid_blk_names.keys():
157 # devfs under 2.4 (old boot cds) used to list partitions
158 # in a format such as scsi/host0/bus0/target0/lun0/disc
159 # and /dev/sda, etc. were just symlinks
161 devfsname= os.readlink( "/dev/%s" % devicename )
162 valid_blk_names[devfsname]=None
166 # only do this once every system boot
167 if not os.access(DEVICES_SCANNED_FLAG, os.R_OK):
169 # this is ugly. under devfs, device
170 # entries in /dev/scsi/.. and /dev/ide/...
171 # don't show up until you attempt to read
172 # from the associated device at /dev (/dev/sda).
173 # so, lets run sfdisk -l (list partitions) against
174 # most possible block devices, that way they show
175 # up when it comes time to do the install.
176 devicenames = valid_blk_names.keys()
178 for devicename in devicenames:
179 os.system( "sfdisk -l /dev/%s > /dev/null 2>&1" % devicename )
182 fb = open(DEVICES_SCANNED_FLAG,"w")
187 partitions_file= file(PROC_PARTITIONS_PATH,"r")
189 for line in partitions_file:
190 line_count= line_count + 1
192 # skip the first two lines always
196 parts= string.split(line)
203 # skip and ignore any partitions
204 if not valid_blk_names.has_key(device):
210 blocks= int(parts[2])
211 except ValueError, err:
214 gb_size= blocks/BLOCKS_PER_GB
216 # check to see if the blk device is readonly
218 # can we write to it?
219 dev_name= "/dev/%s" % device
220 fb = open(dev_name,"w")
224 # check if EROFS errno
225 if errno.errorcode.get(e.errno,None) == 'EROFS':
228 # got some other errno, pretend device is readonly
231 devicelist[dev_name]= (major,minor,blocks,gb_size,readonly)
236 def get_system_modules( vars = {}, log = sys.stderr):
238 Return a list of kernel modules that this system requires.
239 This requires access to the installed system's root
240 directory, as the following file must exist and is used:
241 <install_root>/lib/modules/(first entry if kernel_version unspecified)/modules.pcimap
243 If there are more than one kernels installed, and the kernel
244 version is not specified, then only the first one in
245 /lib/modules is used.
247 Returns a dictionary, keys being the type of module:
248 - scsi MODULE_CLASS_SCSI
249 - network MODULE_CLASS_NETWORK
250 The value being the kernel module name to load.
252 Some sata devices show up under an IDE device class,
253 hence the reason for checking for ide devices as well.
254 If there actually is a match in the pci -> module lookup
255 table, and its an ide device, its most likely sata,
256 as ide modules are built in to the kernel.
259 if not vars.has_key("SYSIMG_PATH"):
260 vars["SYSIMG_PATH"]="/"
261 SYSIMG_PATH=vars["SYSIMG_PATH"]
263 if not vars.has_key("NODE_MODEL_OPTIONS"):
264 vars["NODE_MODEL_OPTIONS"] = 0;
266 initrd, kernel_version = getKernelVersion(vars, log)
268 # get the kernel version we are assuming
269 if kernel_version is None:
271 kernel_version= os.listdir( "%s/lib/modules/" % SYSIMG_PATH )
275 if len(kernel_version) == 0:
278 if len(kernel_version) > 1:
279 print( "WARNING: We may be returning modules for the wrong kernel." )
281 kernel_version= kernel_version[0]
283 print( "Using kernel version %s" % kernel_version )
285 # test to make sure the file we need is present
286 modules_pcimap_path = "%s/lib/modules/%s/modules.pcimap" % \
287 (SYSIMG_PATH,kernel_version)
288 if not os.access(modules_pcimap_path,os.R_OK):
289 print( "Unable to read %s" % path )
292 pcimap = pypcimap.PCIMap(modules_pcimap_path)
294 # this is the actual data structure we return
297 # these are the lists that will be in system_mods
301 # XXX: this is really similar to what BootCD/conf_files/pl_hwinit does. merge?
302 pcidevs = get_devices()
304 for (slot, dev) in pcidevs.iteritems():
305 base = (dev[4] & 0xff0000) >> 16
306 if base not in (PCI_BASE_CLASS_STORAGE,
307 PCI_BASE_CLASS_NETWORK):
310 modules = pcimap.get(dev)
312 if base == PCI_BASE_CLASS_NETWORK:
313 network_mods += modules
314 elif base == PCI_BASE_CLASS_STORAGE:
317 system_mods[MODULE_CLASS_SCSI]= scsi_mods
318 system_mods[MODULE_CLASS_NETWORK]= network_mods
323 def getKernelVersion( vars = {} , log = sys.stderr):
324 # make sure we have the variables we need
326 SYSIMG_PATH= vars["SYSIMG_PATH"]
327 if SYSIMG_PATH == "":
328 raise ValueError, "SYSIMG_PATH"
330 NODE_MODEL_OPTIONS=vars["NODE_MODEL_OPTIONS"]
331 except KeyError, var:
332 raise BootManagerException, "Missing variable in vars: %s\n" % var
333 except ValueError, var:
334 raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
337 if NODE_MODEL_OPTIONS & ModelOptions.SMP:
340 os.stat("%s/boot/kernel-boot%s" % (SYSIMG_PATH,option))
341 os.stat("%s/boot/initrd-boot%s" % (SYSIMG_PATH,option))
343 # smp kernel is not there; remove option from modeloptions
344 # such that the rest of the code base thinks we are just
345 # using the base kernel.
346 NODE_MODEL_OPTIONS = NODE_MODEL_OPTIONS & ~ModelOptions.SMP
347 vars["NODE_MODEL_OPTIONS"] = NODE_MODEL_OPTIONS
348 log.write( "WARNING: Couldn't locate smp kernel.\n")
351 initrd= os.readlink( "%s/boot/initrd-boot%s" % (SYSIMG_PATH,option) )
352 kernel_version= initrd.replace("initrd-", "").replace(".img", "")
355 kernel_version = None
357 return (initrd, kernel_version)
360 if __name__ == "__main__":
361 devices= get_block_device_list()
362 print "block devices detected:"
364 print "no devices found!"
366 for dev in devices.keys():
367 print "%s %s" % (dev, repr(devices[dev]))
371 memory= get_total_phsyical_mem()
373 print "unable to read /proc/meminfo for memory"
375 print "total physical memory: %d kb" % memory
380 kernel_version = None
381 if len(sys.argv) > 2:
382 kernel_version = sys.argv[1]
384 modules= get_system_modules()
386 print "unable to list system modules"
389 if type == MODULE_CLASS_SCSI:
390 print( "all scsi modules:" )
391 for a_mod in modules[type]:
393 elif type == MODULE_CLASS_NETWORK:
394 print( "all network modules:" )
395 for a_mod in modules[type]: