gem5img.py revision 8265
18265Sgblack@eecs.umich.edu#!/usr/bin/python 28265Sgblack@eecs.umich.edu# 38265Sgblack@eecs.umich.edu# gem5img.py 48265Sgblack@eecs.umich.edu# Script for managing a gem5 disk image. 58265Sgblack@eecs.umich.edu# 68265Sgblack@eecs.umich.edu 78265Sgblack@eecs.umich.edufrom optparse import OptionParser 88265Sgblack@eecs.umich.eduimport os 98265Sgblack@eecs.umich.edufrom os import environ as env 108265Sgblack@eecs.umich.eduimport string 118265Sgblack@eecs.umich.edufrom subprocess import CalledProcessError, Popen, PIPE, STDOUT 128265Sgblack@eecs.umich.edufrom sys import exit, argv 138265Sgblack@eecs.umich.edu 148265Sgblack@eecs.umich.edu 158265Sgblack@eecs.umich.edu# Some constants. 168265Sgblack@eecs.umich.eduMaxLBACylinders = 16383 178265Sgblack@eecs.umich.eduMaxLBAHeads = 16 188265Sgblack@eecs.umich.eduMaxLBASectors = 63 198265Sgblack@eecs.umich.eduMaxLBABlocks = MaxLBACylinders * MaxLBAHeads * MaxLBASectors 208265Sgblack@eecs.umich.edu 218265Sgblack@eecs.umich.eduBlockSize = 512 228265Sgblack@eecs.umich.eduMB = 1024 * 1024 238265Sgblack@eecs.umich.edu 248265Sgblack@eecs.umich.edu# Setup PATH to look in the sbins. 258265Sgblack@eecs.umich.eduenv['PATH'] += ':/sbin:/usr/sbin' 268265Sgblack@eecs.umich.edu 278265Sgblack@eecs.umich.edu# Whether to print debug output. 288265Sgblack@eecs.umich.edudebug = False 298265Sgblack@eecs.umich.edu 308265Sgblack@eecs.umich.edu# Figure out cylinders, heads and sectors from a size in blocks. 318265Sgblack@eecs.umich.edudef chsFromSize(sizeInBlocks): 328265Sgblack@eecs.umich.edu if sizeInBlocks >= MaxLBABlocks: 338265Sgblack@eecs.umich.edu sizeInMBs = (sizeInBlocks * BlockSize) / MB 348265Sgblack@eecs.umich.edu print '%d MB is too big for LBA, truncating file.' % sizeInMBs 358265Sgblack@eecs.umich.edu return (MaxLBACylinders, MaxLBAHeads, MaxLBASectors) 368265Sgblack@eecs.umich.edu 378265Sgblack@eecs.umich.edu sectors = sizeInBlocks 388265Sgblack@eecs.umich.edu if sizeInBlocks > 63: 398265Sgblack@eecs.umich.edu sectors = 63 408265Sgblack@eecs.umich.edu 418265Sgblack@eecs.umich.edu headSize = sizeInBlocks / sectors 428265Sgblack@eecs.umich.edu heads = 16 438265Sgblack@eecs.umich.edu if headSize < 16: 448265Sgblack@eecs.umich.edu heads = sizeInBlocks 458265Sgblack@eecs.umich.edu 468265Sgblack@eecs.umich.edu cylinders = sizeInBlocks / (sectors * heads) 478265Sgblack@eecs.umich.edu 488265Sgblack@eecs.umich.edu return (cylinders, heads, sectors) 498265Sgblack@eecs.umich.edu 508265Sgblack@eecs.umich.edu 518265Sgblack@eecs.umich.edu# Figure out if we should use sudo. 528265Sgblack@eecs.umich.edudef needSudo(): 538265Sgblack@eecs.umich.edu if not hasattr(needSudo, 'notRoot'): 548265Sgblack@eecs.umich.edu needSudo.notRoot = (os.geteuid() != 0) 558265Sgblack@eecs.umich.edu if needSudo.notRoot: 568265Sgblack@eecs.umich.edu print 'You are not root. Using sudo.' 578265Sgblack@eecs.umich.edu return needSudo.notRoot 588265Sgblack@eecs.umich.edu 598265Sgblack@eecs.umich.edu# Run an external command. 608265Sgblack@eecs.umich.edudef runCommand(command, inputVal=''): 618265Sgblack@eecs.umich.edu print "%>", ' '.join(command) 628265Sgblack@eecs.umich.edu proc = Popen(command, stdin=PIPE) 638265Sgblack@eecs.umich.edu proc.communicate(inputVal) 648265Sgblack@eecs.umich.edu return proc.returncode 658265Sgblack@eecs.umich.edu 668265Sgblack@eecs.umich.edu# Run an external command and capture its output. This is intended to be 678265Sgblack@eecs.umich.edu# used with non-interactive commands where the output is for internal use. 688265Sgblack@eecs.umich.edudef getOutput(command, inputVal=''): 698265Sgblack@eecs.umich.edu global debug 708265Sgblack@eecs.umich.edu if debug: 718265Sgblack@eecs.umich.edu print "%>", ' '.join(command) 728265Sgblack@eecs.umich.edu proc = Popen(command, stderr=STDOUT, 738265Sgblack@eecs.umich.edu stdin=PIPE, stdout=PIPE) 748265Sgblack@eecs.umich.edu (out, err) = proc.communicate(inputVal) 758265Sgblack@eecs.umich.edu return (out, proc.returncode) 768265Sgblack@eecs.umich.edu 778265Sgblack@eecs.umich.edu# Run a command as root, using sudo if necessary. 788265Sgblack@eecs.umich.edudef runPriv(command, inputVal=''): 798265Sgblack@eecs.umich.edu realCommand = command 808265Sgblack@eecs.umich.edu if needSudo(): 818265Sgblack@eecs.umich.edu realCommand = [findProg('sudo')] + command 828265Sgblack@eecs.umich.edu return runCommand(realCommand, inputVal) 838265Sgblack@eecs.umich.edu 848265Sgblack@eecs.umich.edudef privOutput(command, inputVal=''): 858265Sgblack@eecs.umich.edu realCommand = command 868265Sgblack@eecs.umich.edu if needSudo(): 878265Sgblack@eecs.umich.edu realCommand = [findProg('sudo')] + command 888265Sgblack@eecs.umich.edu return getOutput(realCommand, inputVal) 898265Sgblack@eecs.umich.edu 908265Sgblack@eecs.umich.edu# Find the path to a program. 918265Sgblack@eecs.umich.edudef findProg(program, cleanupDev=None): 928265Sgblack@eecs.umich.edu (out, returncode) = getOutput(['which', program]) 938265Sgblack@eecs.umich.edu if returncode != 0: 948265Sgblack@eecs.umich.edu if cleanupDev: 958265Sgblack@eecs.umich.edu cleanupDev.destroy() 968265Sgblack@eecs.umich.edu exit("Unable to find program %s, check your PATH variable." % program) 978265Sgblack@eecs.umich.edu return string.strip(out) 988265Sgblack@eecs.umich.edu 998265Sgblack@eecs.umich.educlass LoopbackDevice(object): 1008265Sgblack@eecs.umich.edu def __init__(self, devFile=None): 1018265Sgblack@eecs.umich.edu self.devFile = devFile 1028265Sgblack@eecs.umich.edu def __str__(self): 1038265Sgblack@eecs.umich.edu return str(self.devFile) 1048265Sgblack@eecs.umich.edu 1058265Sgblack@eecs.umich.edu def setup(self, fileName, offset=False): 1068265Sgblack@eecs.umich.edu assert not self.devFile 1078265Sgblack@eecs.umich.edu (out, returncode) = privOutput([findProg('losetup'), '-f']) 1088265Sgblack@eecs.umich.edu if returncode != 0: 1098265Sgblack@eecs.umich.edu print out 1108265Sgblack@eecs.umich.edu return returncode 1118265Sgblack@eecs.umich.edu self.devFile = string.strip(out) 1128265Sgblack@eecs.umich.edu command = [findProg('losetup'), self.devFile, fileName] 1138265Sgblack@eecs.umich.edu if offset: 1148265Sgblack@eecs.umich.edu off = findPartOffset(self.devFile, fileName, 0) 1158265Sgblack@eecs.umich.edu command = command[:1] + \ 1168265Sgblack@eecs.umich.edu ["-o", "%d" % off] + \ 1178265Sgblack@eecs.umich.edu command[1:] 1188265Sgblack@eecs.umich.edu return runPriv(command) 1198265Sgblack@eecs.umich.edu 1208265Sgblack@eecs.umich.edu def destroy(self): 1218265Sgblack@eecs.umich.edu assert self.devFile 1228265Sgblack@eecs.umich.edu returncode = runPriv([findProg('losetup'), '-d', self.devFile]) 1238265Sgblack@eecs.umich.edu self.devFile = None 1248265Sgblack@eecs.umich.edu return returncode 1258265Sgblack@eecs.umich.edu 1268265Sgblack@eecs.umich.edudef findPartOffset(devFile, fileName, partition): 1278265Sgblack@eecs.umich.edu # Attach a loopback device to the file so we can use sfdisk on it. 1288265Sgblack@eecs.umich.edu dev = LoopbackDevice() 1298265Sgblack@eecs.umich.edu dev.setup(fileName) 1308265Sgblack@eecs.umich.edu # Dump the partition information. 1318265Sgblack@eecs.umich.edu command = [findProg('sfdisk'), '-d', dev.devFile] 1328265Sgblack@eecs.umich.edu (out, returncode) = privOutput(command) 1338265Sgblack@eecs.umich.edu if returncode != 0: 1348265Sgblack@eecs.umich.edu print out 1358265Sgblack@eecs.umich.edu exit(returncode) 1368265Sgblack@eecs.umich.edu lines = out.splitlines() 1378265Sgblack@eecs.umich.edu # Make sure the first few lines of the output look like what we expect. 1388265Sgblack@eecs.umich.edu assert(lines[0][0] == '#') 1398265Sgblack@eecs.umich.edu assert(lines[1] == 'unit: sectors') 1408265Sgblack@eecs.umich.edu assert(lines[2] == '') 1418265Sgblack@eecs.umich.edu # This line has information about the first partition. 1428265Sgblack@eecs.umich.edu chunks = lines[3].split() 1438265Sgblack@eecs.umich.edu # The fourth chunk is the offset of the partition in sectors followed by 1448265Sgblack@eecs.umich.edu # a comma. We drop the comma and convert that to an integer. 1458265Sgblack@eecs.umich.edu sectors = string.atoi(chunks[3][:-1]) 1468265Sgblack@eecs.umich.edu # Free the loopback device and return an answer. 1478265Sgblack@eecs.umich.edu dev.destroy() 1488265Sgblack@eecs.umich.edu return sectors * BlockSize 1498265Sgblack@eecs.umich.edu 1508265Sgblack@eecs.umich.edudef mountPointToDev(mountPoint): 1518265Sgblack@eecs.umich.edu (mountTable, returncode) = getOutput([findProg('mount')]) 1528265Sgblack@eecs.umich.edu if returncode != 0: 1538265Sgblack@eecs.umich.edu print mountTable 1548265Sgblack@eecs.umich.edu exit(returncode) 1558265Sgblack@eecs.umich.edu mountTable = mountTable.splitlines() 1568265Sgblack@eecs.umich.edu for line in mountTable: 1578265Sgblack@eecs.umich.edu chunks = line.split() 1588265Sgblack@eecs.umich.edu if os.path.samefile(chunks[2], mountPoint): 1598265Sgblack@eecs.umich.edu return LoopbackDevice(chunks[0]) 1608265Sgblack@eecs.umich.edu return None 1618265Sgblack@eecs.umich.edu 1628265Sgblack@eecs.umich.edu 1638265Sgblack@eecs.umich.edu# Commands for the gem5img.py script 1648265Sgblack@eecs.umich.educommands = {} 1658265Sgblack@eecs.umich.educommandOrder = [] 1668265Sgblack@eecs.umich.edu 1678265Sgblack@eecs.umich.educlass Command(object): 1688265Sgblack@eecs.umich.edu def addOption(self, *args, **kargs): 1698265Sgblack@eecs.umich.edu self.parser.add_option(*args, **kargs) 1708265Sgblack@eecs.umich.edu 1718265Sgblack@eecs.umich.edu def __init__(self, name, description, posArgs): 1728265Sgblack@eecs.umich.edu self.name = name 1738265Sgblack@eecs.umich.edu self.description = description 1748265Sgblack@eecs.umich.edu self.func = None 1758265Sgblack@eecs.umich.edu self.posArgs = posArgs 1768265Sgblack@eecs.umich.edu commands[self.name] = self 1778265Sgblack@eecs.umich.edu commandOrder.append(self.name) 1788265Sgblack@eecs.umich.edu usage = 'usage: %prog [options]' 1798265Sgblack@eecs.umich.edu posUsage = '' 1808265Sgblack@eecs.umich.edu for posArg in posArgs: 1818265Sgblack@eecs.umich.edu (argName, argDesc) = posArg 1828265Sgblack@eecs.umich.edu usage += ' %s' % argName 1838265Sgblack@eecs.umich.edu posUsage += '\n %s: %s' % posArg 1848265Sgblack@eecs.umich.edu usage += posUsage 1858265Sgblack@eecs.umich.edu self.parser = OptionParser(usage=usage, description=description) 1868265Sgblack@eecs.umich.edu self.addOption('-d', '--debug', dest='debug', action='store_true', 1878265Sgblack@eecs.umich.edu help='Verbose output.') 1888265Sgblack@eecs.umich.edu 1898265Sgblack@eecs.umich.edu def parseArgs(self, argv): 1908265Sgblack@eecs.umich.edu (self.options, self.args) = self.parser.parse_args(argv[2:]) 1918265Sgblack@eecs.umich.edu if len(self.args) != len(self.posArgs): 1928265Sgblack@eecs.umich.edu self.parser.error('Incorrect number of arguments') 1938265Sgblack@eecs.umich.edu global debug 1948265Sgblack@eecs.umich.edu if self.options.debug: 1958265Sgblack@eecs.umich.edu debug = True 1968265Sgblack@eecs.umich.edu 1978265Sgblack@eecs.umich.edu def runCom(self): 1988265Sgblack@eecs.umich.edu if not self.func: 1998265Sgblack@eecs.umich.edu exit('Unimplemented command %s!' % self.name) 2008265Sgblack@eecs.umich.edu self.func(self.options, self.args) 2018265Sgblack@eecs.umich.edu 2028265Sgblack@eecs.umich.edu 2038265Sgblack@eecs.umich.edu# A command which prepares an image with an partition table and an empty file 2048265Sgblack@eecs.umich.edu# system. 2058265Sgblack@eecs.umich.eduinitCom = Command('init', 'Create an image with an empty file system.', 2068265Sgblack@eecs.umich.edu [('file', 'Name of the image file.'), 2078265Sgblack@eecs.umich.edu ('mb', 'Size of the file in MB.')]) 2088265Sgblack@eecs.umich.eduinitCom.addOption('-t', '--type', dest='fstype', action='store', 2098265Sgblack@eecs.umich.edu default='ext2', 2108265Sgblack@eecs.umich.edu help='Type of file system to use. Appended to mkfs.') 2118265Sgblack@eecs.umich.edu 2128265Sgblack@eecs.umich.edu# A command to mount the first partition in the image. 2138265Sgblack@eecs.umich.edumountCom = Command('mount', 'Mount the first partition in the disk image.', 2148265Sgblack@eecs.umich.edu [('file', 'Name of the image file.'), 2158265Sgblack@eecs.umich.edu ('mount point', 'Where to mount the image.')]) 2168265Sgblack@eecs.umich.edu 2178265Sgblack@eecs.umich.edudef mountComFunc(options, args): 2188265Sgblack@eecs.umich.edu (path, mountPoint) = args 2198265Sgblack@eecs.umich.edu if not os.path.isdir(mountPoint): 2208265Sgblack@eecs.umich.edu print "Mount point %s is not a directory." % mountPoint 2218265Sgblack@eecs.umich.edu 2228265Sgblack@eecs.umich.edu dev = LoopbackDevice() 2238265Sgblack@eecs.umich.edu if dev.setup(path, offset=True) != 0: 2248265Sgblack@eecs.umich.edu exit(1) 2258265Sgblack@eecs.umich.edu 2268265Sgblack@eecs.umich.edu if runPriv([findProg('mount'), str(dev), mountPoint]) != 0: 2278265Sgblack@eecs.umich.edu dev.destroy() 2288265Sgblack@eecs.umich.edu exit(1) 2298265Sgblack@eecs.umich.edu 2308265Sgblack@eecs.umich.edumountCom.func = mountComFunc 2318265Sgblack@eecs.umich.edu 2328265Sgblack@eecs.umich.edu# A command to unmount the first partition in the image. 2338265Sgblack@eecs.umich.eduumountCom = Command('umount', 'Unmount the first partition in the disk image.', 2348265Sgblack@eecs.umich.edu [('mount point', 'What mount point to unmount.')]) 2358265Sgblack@eecs.umich.edu 2368265Sgblack@eecs.umich.edudef umountComFunc(options, args): 2378265Sgblack@eecs.umich.edu (mountPoint,) = args 2388265Sgblack@eecs.umich.edu if not os.path.isdir(mountPoint): 2398265Sgblack@eecs.umich.edu print "Mount point %s is not a directory." % mountPoint 2408265Sgblack@eecs.umich.edu exit(1) 2418265Sgblack@eecs.umich.edu 2428265Sgblack@eecs.umich.edu dev = mountPointToDev(mountPoint) 2438265Sgblack@eecs.umich.edu if not dev: 2448265Sgblack@eecs.umich.edu print "Unable to find mount information for %s." % mountPoint 2458265Sgblack@eecs.umich.edu 2468265Sgblack@eecs.umich.edu # Unmount the loopback device. 2478265Sgblack@eecs.umich.edu if runPriv([findProg('umount'), mountPoint]) != 0: 2488265Sgblack@eecs.umich.edu exit(1) 2498265Sgblack@eecs.umich.edu 2508265Sgblack@eecs.umich.edu # Destroy the loopback device. 2518265Sgblack@eecs.umich.edu dev.destroy() 2528265Sgblack@eecs.umich.edu 2538265Sgblack@eecs.umich.eduumountCom.func = umountComFunc 2548265Sgblack@eecs.umich.edu 2558265Sgblack@eecs.umich.edu 2568265Sgblack@eecs.umich.edu# A command to create an empty file to hold the image. 2578265Sgblack@eecs.umich.edunewCom = Command('new', 'File creation part of "init".', 2588265Sgblack@eecs.umich.edu [('file', 'Name of the image file.'), 2598265Sgblack@eecs.umich.edu ('mb', 'Size of the file in MB.')]) 2608265Sgblack@eecs.umich.edu 2618265Sgblack@eecs.umich.edudef newImage(file, mb): 2628265Sgblack@eecs.umich.edu (cylinders, heads, sectors) = chsFromSize((mb * MB) / BlockSize) 2638265Sgblack@eecs.umich.edu size = cylinders * heads * sectors * BlockSize 2648265Sgblack@eecs.umich.edu 2658265Sgblack@eecs.umich.edu # We lseek to the end of the file and only write one byte there. This 2668265Sgblack@eecs.umich.edu # leaves a "hole" which many file systems are smart enough not to actually 2678265Sgblack@eecs.umich.edu # store to disk and which is defined to read as zero. 2688265Sgblack@eecs.umich.edu fd = os.open(file, os.O_WRONLY | os.O_CREAT) 2698265Sgblack@eecs.umich.edu os.lseek(fd, size - 1, os.SEEK_SET) 2708265Sgblack@eecs.umich.edu os.write(fd, '\0') 2718265Sgblack@eecs.umich.edu 2728265Sgblack@eecs.umich.edudef newComFunc(options, args): 2738265Sgblack@eecs.umich.edu (file, mb) = args 2748265Sgblack@eecs.umich.edu mb = string.atoi(mb) 2758265Sgblack@eecs.umich.edu newImage(file, mb) 2768265Sgblack@eecs.umich.edu 2778265Sgblack@eecs.umich.edu 2788265Sgblack@eecs.umich.edunewCom.func = newComFunc 2798265Sgblack@eecs.umich.edu 2808265Sgblack@eecs.umich.edu# A command to partition the image file like a raw disk device. 2818265Sgblack@eecs.umich.edupartitionCom = Command('partition', 'Partition part of "init".', 2828265Sgblack@eecs.umich.edu [('file', 'Name of the image file.')]) 2838265Sgblack@eecs.umich.edu 2848265Sgblack@eecs.umich.edudef partition(dev, cylinders, heads, sectors): 2858265Sgblack@eecs.umich.edu # Use fdisk to partition the device 2868265Sgblack@eecs.umich.edu comStr = '0,\n;\n;\n;\n' 2878265Sgblack@eecs.umich.edu return runPriv([findProg('sfdisk'), '--no-reread', '-D', \ 2888265Sgblack@eecs.umich.edu '-C', "%d" % cylinders, \ 2898265Sgblack@eecs.umich.edu '-H', "%d" % heads, \ 2908265Sgblack@eecs.umich.edu '-S', "%d" % sectors, \ 2918265Sgblack@eecs.umich.edu str(dev)], inputVal=comStr) 2928265Sgblack@eecs.umich.edu 2938265Sgblack@eecs.umich.edudef partitionComFunc(options, args): 2948265Sgblack@eecs.umich.edu (path,) = args 2958265Sgblack@eecs.umich.edu 2968265Sgblack@eecs.umich.edu dev = LoopbackDevice() 2978265Sgblack@eecs.umich.edu if dev.setup(path) != 0: 2988265Sgblack@eecs.umich.edu exit(1) 2998265Sgblack@eecs.umich.edu 3008265Sgblack@eecs.umich.edu # Figure out the dimensions of the file. 3018265Sgblack@eecs.umich.edu size = os.path.getsize(path) 3028265Sgblack@eecs.umich.edu if partition(dev, *chsFromSize(size / BlockSize)) != 0: 3038265Sgblack@eecs.umich.edu dev.destroy() 3048265Sgblack@eecs.umich.edu exit(1) 3058265Sgblack@eecs.umich.edu 3068265Sgblack@eecs.umich.edu dev.destroy() 3078265Sgblack@eecs.umich.edu 3088265Sgblack@eecs.umich.edupartitionCom.func = partitionComFunc 3098265Sgblack@eecs.umich.edu 3108265Sgblack@eecs.umich.edu# A command to format the first partition in the image. 3118265Sgblack@eecs.umich.eduformatCom = Command('format', 'Formatting part of "init".', 3128265Sgblack@eecs.umich.edu [('file', 'Name of the image file.')]) 3138265Sgblack@eecs.umich.eduformatCom.addOption('-t', '--type', dest='fstype', action='store', 3148265Sgblack@eecs.umich.edu default='ext2', 3158265Sgblack@eecs.umich.edu help='Type of file system to use. Appended to mkfs.') 3168265Sgblack@eecs.umich.edu 3178265Sgblack@eecs.umich.edudef formatImage(dev, fsType): 3188265Sgblack@eecs.umich.edu return runPriv([findProg('mkfs.%s' % fsType, dev), str(dev)]) 3198265Sgblack@eecs.umich.edu 3208265Sgblack@eecs.umich.edudef formatComFunc(options, args): 3218265Sgblack@eecs.umich.edu (path,) = args 3228265Sgblack@eecs.umich.edu 3238265Sgblack@eecs.umich.edu dev = LoopbackDevice() 3248265Sgblack@eecs.umich.edu if dev.setup(path, offset=True) != 0: 3258265Sgblack@eecs.umich.edu exit(1) 3268265Sgblack@eecs.umich.edu 3278265Sgblack@eecs.umich.edu # Format the device. 3288265Sgblack@eecs.umich.edu if formatImage(dev, options.fstype) != 0: 3298265Sgblack@eecs.umich.edu dev.destroy() 3308265Sgblack@eecs.umich.edu exit(1) 3318265Sgblack@eecs.umich.edu 3328265Sgblack@eecs.umich.edu dev.destroy() 3338265Sgblack@eecs.umich.edu 3348265Sgblack@eecs.umich.eduformatCom.func = formatComFunc 3358265Sgblack@eecs.umich.edu 3368265Sgblack@eecs.umich.edudef initComFunc(options, args): 3378265Sgblack@eecs.umich.edu (path, mb) = args 3388265Sgblack@eecs.umich.edu mb = string.atoi(mb) 3398265Sgblack@eecs.umich.edu newImage(path, mb) 3408265Sgblack@eecs.umich.edu dev = LoopbackDevice() 3418265Sgblack@eecs.umich.edu if dev.setup(path) != 0: 3428265Sgblack@eecs.umich.edu exit(1) 3438265Sgblack@eecs.umich.edu size = os.path.getsize(path) 3448265Sgblack@eecs.umich.edu if partition(dev, *chsFromSize((mb * MB) / BlockSize)) != 0: 3458265Sgblack@eecs.umich.edu dev.destroy() 3468265Sgblack@eecs.umich.edu exit(1) 3478265Sgblack@eecs.umich.edu dev.destroy() 3488265Sgblack@eecs.umich.edu if dev.setup(path, offset=True) != 0: 3498265Sgblack@eecs.umich.edu exit(1) 3508265Sgblack@eecs.umich.edu if formatImage(dev, options.fstype) != 0: 3518265Sgblack@eecs.umich.edu dev.destroy() 3528265Sgblack@eecs.umich.edu exit(1) 3538265Sgblack@eecs.umich.edu dev.destroy() 3548265Sgblack@eecs.umich.edu 3558265Sgblack@eecs.umich.eduinitCom.func = initComFunc 3568265Sgblack@eecs.umich.edu 3578265Sgblack@eecs.umich.edu 3588265Sgblack@eecs.umich.edu# Figure out what command was requested and execute it. 3598265Sgblack@eecs.umich.eduif len(argv) < 2 or argv[1] not in commands: 3608265Sgblack@eecs.umich.edu print 'Usage: %s [command] <command arguments>' 3618265Sgblack@eecs.umich.edu print 'where [command] is one of ' 3628265Sgblack@eecs.umich.edu for name in commandOrder: 3638265Sgblack@eecs.umich.edu command = commands[name] 3648265Sgblack@eecs.umich.edu print ' %s: %s' % (command.name, command.description) 3658265Sgblack@eecs.umich.edu print 'Watch for orphaned loopback devices and delete them with' 3668265Sgblack@eecs.umich.edu print 'losetup -d. Mounted images will belong to root, so you may need' 3678265Sgblack@eecs.umich.edu print 'to use sudo to modify their contents.' 3688265Sgblack@eecs.umich.edu exit(1) 3698265Sgblack@eecs.umich.edu 3708265Sgblack@eecs.umich.educommand = commands[argv[1]] 3718265Sgblack@eecs.umich.educommand.parseArgs(argv) 3728265Sgblack@eecs.umich.educommand.runCom() 373