diff options
Diffstat (limited to 'src/VBox/Frontends/VBoxShell/vboxshell.py')
-rw-r--r--[-rwxr-xr-x] | src/VBox/Frontends/VBoxShell/vboxshell.py | 208 |
1 files changed, 158 insertions, 50 deletions
diff --git a/src/VBox/Frontends/VBoxShell/vboxshell.py b/src/VBox/Frontends/VBoxShell/vboxshell.py index f1a658341..e3d10dfa6 100755..100644 --- a/src/VBox/Frontends/VBoxShell/vboxshell.py +++ b/src/VBox/Frontends/VBoxShell/vboxshell.py @@ -51,7 +51,8 @@ term_colors = { 'blue':'\033[94m', 'green':'\033[92m', 'yellow':'\033[93m', - 'magenta':'\033[35m' + 'magenta':'\033[35m', + 'cyan':'\033[36m' } def colored(string,color): if not g_hascolors: @@ -179,6 +180,7 @@ def progressBar(ctx,p,wait=1000): return 1 except KeyboardInterrupt: print "Interrupted." + ctx['interrupt'] = True if p.cancelable: print "Canceling task..." p.cancel() @@ -190,7 +192,7 @@ def printErr(ctx,e): def reportError(ctx,progress): ei = progress.errorInfo if ei: - print colored("Error in %s: %s" %(ei.component, ei.text), 'red') + print colored("Error in module '%s': %s" %(ei.component, ei.text), 'red') def colCat(ctx,str): return colored(str, 'magenta') @@ -204,6 +206,12 @@ def colPath(ctx,p): def colSize(ctx,m): return colored(m, 'red') +def colPci(ctx,vm): + return colored(vm, 'green') + +def colDev(ctx,vm): + return colored(vm, 'cyan') + def colSizeM(ctx,m): return colored(str(m)+'M', 'red') @@ -245,10 +253,7 @@ def startVm(ctx,mach,type): printErr(ctx, e) if g_verbose: traceback.print_exc() - # if session not opened, close doesn't make sense session.unlockMachine() - else: - reportError(ctx,progress) class CachedMach: def __init__(self, mach): @@ -481,6 +486,8 @@ def playbackDemo(ctx, console, file, dur): mouse.putMouseEvent(int(mdict['x']), int(mdict['y']), int(mdict['z']), int(mdict['w']), int(mdict['b'])) # We need to catch all exceptions here, to close file + except KeyboardInterrupt: + ctx['interrupt'] = True except: traceback.print_exc() pass @@ -683,6 +690,8 @@ def cmdExistingVm(ctx,mach,cmd,args): } try: ops[cmd]() + except KeyboardInterrupt: + ctx['interrupt'] = True except Exception, e: printErr(ctx,e) if g_verbose: @@ -808,7 +817,7 @@ class XPathNodeVM(XPathNode): class XPathNodeHolderNIC(XPathNodeHolder): def __init__(self, parent, mach): XPathNodeHolder.__init__(self, parent, mach, 'nics', XPathNodeVM, 'nics') - self.maxNic = self.getCtx()['vb'].systemProperties.networkAdapterCount + self.maxNic = self.getCtx()['vb'].systemProperties.getMaxNetworkAdapters(self.obj.chipsetType) def enum(self): children = [] for i in range(0, self.maxNic): @@ -1106,6 +1115,7 @@ def execInGuest(ctx,console,args,env,user,passwd,tmo,inputPipe=None,outputPipe=N except KeyboardInterrupt: print "Interrupted." + ctx['interrupt'] = True if progress.cancelable: progress.cancel() (reason, code, flags) = guest.getProcessStatus(pid) @@ -1470,7 +1480,6 @@ def hostCmd(ctx, args): print "VirtualBox version %s" %(colored(vb.version, 'blue')) props = vb.systemProperties print "Machines: %s" %(colPath(ctx,props.defaultMachineFolder)) - print "HDDs: %s" %(colPath(ctx,props.defaultHardDiskFolder)) #print "Global shared folders:" #for ud in ctx['global'].getArray(vb, 'sharedFolders'): @@ -1723,7 +1732,6 @@ def reloadExtCmd(ctx, args): autoCompletion(commands, ctx) return 0 - def runScriptCmd(ctx, args): if (len(args) != 2): print "usage: runScript <script>" @@ -1735,9 +1743,16 @@ def runScriptCmd(ctx, args): return 0 try: - for line in lf: + lines = lf.readlines() + ctx['scriptLine'] = 0 + ctx['interrupt'] = False + while ctx['scriptLine'] < len(lines): + line = lines[ctx['scriptLine']] + ctx['scriptLine'] = ctx['scriptLine'] + 1 done = runCommand(ctx, line) - if done != 0: break + if done != 0 or ctx['interrupt']: + break + except Exception,e: printErr(ctx,e) if g_verbose: @@ -2602,9 +2617,9 @@ def natAlias(ctx, mach, nicnum, nat, args=[]): else: msg += ', ' if int(nat.aliasMode) & aliaskey: - msg += '{0}: {1}'.format(aliasmode, 'on') + msg += '%d: %s' % (aliasmode, 'on') else: - msg += '{0}: {1}'.format(aliasmode, 'off') + msg += '%d: %s' % (aliasmode, 'off') msg += ')' return (0, [msg]) else: @@ -2632,15 +2647,15 @@ def natSettings(ctx, mach, nicnum, nat, args): if sockrcvbuf == 0: sockrcvbuf = 64 if tcpsndwnd == 0: tcpsndwnd = 64 if tcprcvwnd == 0: tcprcvwnd = 64 - msg = 'mtu:{0} socket(snd:{1}, rcv:{2}) tcpwnd(snd:{3}, rcv:{4})'.format(mtu, socksndbuf, sockrcvbuf, tcpsndwnd, tcprcvwnd); + msg = 'mtu:%s socket(snd:%s, rcv:%s) tcpwnd(snd:%s, rcv:%s)' % (mtu, socksndbuf, sockrcvbuf, tcpsndwnd, tcprcvwnd); return (0, [msg]) else: if args[1] < 16000: - print 'invalid mtu value ({0} no in range [65 - 16000])'.format(args[1]) + print 'invalid mtu value (%s not in range [65 - 16000])' % (args[1]) return (1, None) for i in range(2, len(args)): if not args[i].isdigit() or int(args[i]) < 8 or int(args[i]) > 1024: - print 'invalid {0} parameter ({1} not in range [8-1024])'.format(i, args[i]) + print 'invalid %s parameter (%i not in range [8-1024])' % (i, args[i]) return (1, None) a = [args[1]] if len(args) < 6: @@ -2661,7 +2676,7 @@ def natDns(ctx, mach, nicnum, nat, args): """ yesno = {0: 'off', 1: 'on'} if len(args) == 1: - msg = 'passdomain:{0}, proxy:{1}, usehostresolver:{2}'.format(yesno[int(nat.dnsPassDomain)], yesno[int(nat.dnsProxy)], yesno[int(nat.dnsUseHostResolver)]) + msg = 'passdomain:%s, proxy:%s, usehostresolver:%s' % (yesno[int(nat.dnsPassDomain)], yesno[int(nat.dnsProxy)], yesno[int(nat.dnsUseHostResolver)]) return (0, [msg]) else: nat.dnsPassDomain = 'passdomain' in args @@ -2681,19 +2696,19 @@ def natTftp(ctx, mach, nicnum, nat, args): if server is None: server = nat.network if server is None: - server = '10.0.{0}/24'.format(int(nicnum) + 2) + server = '10.0.%d/24' % (int(nicnum) + 2) (server,mask) = server.split('/') while server.count('.') != 3: server += '.0' (a,b,c,d) = server.split('.') - server = '{0}.{1}.{2}.4'.format(a,b,c) + server = '%d.%d.%d.4' % (a,b,c) prefix = nat.tftpPrefix if prefix is None: - prefix = '{0}/TFTP/'.format(ctx['vb'].homeFolder) + prefix = '%s/TFTP/' % (ctx['vb'].homeFolder) bootfile = nat.tftpBootFile if bootfile is None: - bootfile = '{0}.pxe'.format(mach.name) - msg = 'server:{0}, prefix:{1}, bootfile:{2}'.format(server, prefix, bootfile) + bootfile = '%s.pxe' % (mach.name) + msg = 'server:%s, prefix:%s, bootfile:%s' % (server, prefix, bootfile) return (0, [msg]) else: @@ -2725,7 +2740,7 @@ def natPortForwarding(ctx, mach, nicnum, nat, args): pfs = ctx['global'].getArray(nat, 'redirects') for pf in pfs: (pfnme, pfp, pfhip, pfhp, pfgip, pfgp) = str(pf).split(',') - msg.append('{0}: {1} {2}:{3} => {4}:{5}'.format(pfnme, proto[int(pfp)], pfhip, pfhp, pfgip, pfgp)) + msg.append('%s: %s %s:%s => %s:%s' % (pfnme, proto[int(pfp)], pfhip, pfhp, pfgip, pfgp)) return (0, msg) # msg is array else: proto = {'udp': 0, 'tcp': 1} @@ -2764,7 +2779,7 @@ def natNetwork(ctx, mach, nicnum, nat, args): if nat.network is not None and len(str(nat.network)) != 0: msg = '\'%s\'' % (nat.network) else: - msg = '10.0.{0}.0/24'.format(int(nicnum) + 2) + msg = '10.0.%d.0/24' % (int(nicnum) + 2) return (0, [msg]) else: (addr, mask) = args[1].split('/') @@ -2804,8 +2819,8 @@ def natCmd(ctx, args): if mach == None: print "please specify vm" return 0 - if len(args) < 3 or not args[2].isdigit() or int(args[2]) not in range(0, ctx['vb'].systemProperties.networkAdapterCount): - print 'please specify adapter num {0} isn\'t in range [0-{1}]'.format(args[2], ctx['vb'].systemProperties.networkAdapterCount) + if len(args) < 3 or not args[2].isdigit() or int(args[2]) not in range(0, ctx['vb'].systemProperties.getMaxNetworkAdapters(mach.chipsetType)): + print 'please specify adapter num %d isn\'t in range [0-%d]' % (args[2], ctx['vb'].systemProperties.getMaxNetworkAdapters(mach.chipsetType)) return 0 nicnum = int(args[2]) cmdargs = [] @@ -2831,7 +2846,7 @@ def natCmd(ctx, args): session.unlockMachine() elif report is not None: for r in report: - msg ='{0} nic{1} {2}: {3}'.format(mach.name, nicnum, func, r) + msg ='%s nic%d %s: %s' % (mach.name, nicnum, func, r) print msg return 0 @@ -2866,7 +2881,7 @@ def nicLineSpeedSubCmd(ctx, vm, nicnum, adapter, args): return (0, r) else: if not args[1].isdigit(): - print '%s isn\'t a number'.format(args[1]) + print '%s isn\'t a number' % (args[1]) print (1, None) adapter.lineSpeed = int(args[1]) return (0, None) @@ -2903,16 +2918,17 @@ def nicTypeSubCmd(ctx, vm, nicnum, adapter, args): def nicAttachmentSubCmd(ctx, vm, nicnum, adapter, args): ''' - usage: nic <vm> <nicnum> attachment [Null|NAT|Bridged <interface>|Internal <name>|HostOnly <interface>] + usage: nic <vm> <nicnum> attachment [Null|NAT|Bridged <interface>|Internal <name>|HostOnly <interface> ''' if len(args) == 1: nicAttachmentType = { ctx['global'].constants.NetworkAttachmentType_Null: ('Null', ''), ctx['global'].constants.NetworkAttachmentType_NAT: ('NAT', ''), - ctx['global'].constants.NetworkAttachmentType_Bridged: ('Bridged', adapter.hostInterface), + ctx['global'].constants.NetworkAttachmentType_Bridged: ('Bridged', adapter.bridgedInterface), ctx['global'].constants.NetworkAttachmentType_Internal: ('Internal', adapter.internalNetwork), - ctx['global'].constants.NetworkAttachmentType_HostOnly: ('HostOnly', adapter.hostInterface), - #ctx['global'].constants.NetworkAttachmentType_VDE: ('VDE', adapter.VDENetwork) + ctx['global'].constants.NetworkAttachmentType_HostOnly: ('HostOnly', adapter.hostOnlyInterface), + # @todo show details of the generic network attachment type + ctx['global'].constants.NetworkAttachmentType_Generic: ('Generic', ''), } import types if type(adapter.attachmentType) != types.IntType: @@ -2920,42 +2936,43 @@ def nicAttachmentSubCmd(ctx, vm, nicnum, adapter, args): else: t = adapter.attachmentType (r, p) = nicAttachmentType[t] - return (0, 'attachment:{0}, name:{1}'.format(r, p)) + return (0, 'attachment:%s, name:%s' % (r, p)) else: nicAttachmentType = { 'Null': { 'v': lambda: len(args) == 2, 'p': lambda: 'do nothing', - 'f': lambda: adapter.detach()}, + 'f': lambda: ctx['global'].constants.NetworkAttachmentType_Null}, 'NAT': { 'v': lambda: len(args) == 2, 'p': lambda: 'do nothing', - 'f': lambda: adapter.attachToNAT()}, + 'f': lambda: ctx['global'].constants.NetworkAttachmentType_NAT}, 'Bridged': { 'v': lambda: len(args) == 3, - 'p': lambda: adapter.__setattr__('hostInterface', args[2]), - 'f': lambda: adapter.attachToBridgedInterface()}, + 'p': lambda: adapter.__setattr__('bridgedInterface', args[2]), + 'f': lambda: ctx['global'].constants.NetworkAttachmentType_Bridged}, 'Internal': { 'v': lambda: len(args) == 3, 'p': lambda: adapter.__setattr__('internalNetwork', args[2]), - 'f': lambda: adapter.attachToInternalNetwork()}, + 'f': lambda: ctx['global'].constants.NetworkAttachmentType_Internal}, 'HostOnly': { 'v': lambda: len(args) == 2, - 'p': lambda: adapter.__setattr__('hostInterface', args[2]), - 'f': lambda: adapter.attachToHostOnlyInterface()}, - 'VDE': { + 'p': lambda: adapter.__setattr__('hostOnlyInterface', args[2]), + 'f': lambda: ctx['global'].constants.NetworkAttachmentType_HostOnly}, + # @todo implement setting the properties of a generic attachment + 'Generic': { 'v': lambda: len(args) == 3, - 'p': lambda: adapter.__setattr__('VDENetwork', args[2]), - 'f': lambda: adapter.attachToVDE()} + 'p': lambda: 'do nothing', + 'f': lambda: ctx['global'].constants.NetworkAttachmentType_Generic} } if args[1] not in nicAttachmentType.keys(): - print '{0} not in acceptable values ({1})'.format(args[1], nicAttachmentType.keys()) + print '%s not in acceptable values (%s)' % (args[1], nicAttachmentType.keys()) return (1, None) if not nicAttachmentType[args[1]]['v'](): print nicAttachmentType.__doc__ return (1, None) nicAttachmentType[args[1]]['p']() - nicAttachmentType[args[1]]['f']() + adapter.attachmentType = nicAttachmentType[args[1]]['f']() return (0, None) def nicCmd(ctx, args): @@ -2989,8 +3006,8 @@ def nicCmd(ctx, args): return 0 if len(args) < 3 \ - or int(args[2]) not in range(0, ctx['vb'].systemProperties.networkAdapterCount): - print 'please specify adapter num %d isn\'t in range [0-%d]'%(args[2], ctx['vb'].systemProperties.networkAdapterCount) + or int(args[2]) not in range(0, ctx['vb'].systemProperties.getMaxNetworkAdapters(vm.chipsetType)): + print 'please specify adapter num %d isn\'t in range [0-%d]'%(args[2], ctx['vb'].systemProperties.getMaxNetworkAdapters(vm.chipsetType)) return 0 nicnum = int(args[2]) cmdargs = args[3:] @@ -3071,6 +3088,91 @@ def playbackDemoCmd(ctx, args): cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx,mach,console,args: playbackDemo(ctx, console, filename, dur)]) return 0 + +def pciAddr(ctx,addr): + str = "%02x:%02x.%d" %(addr >> 8, (addr & 0xff) >> 3, addr & 7) + return colPci(ctx, str) + +def lspci(ctx, console): + assigned = ctx['global'].getArray(console.machine, 'pciDeviceAssignments') + for a in assigned: + if a.isPhysicalDevice: + print "%s: assigned host device %s guest %s" %(colDev(ctx, a.name), pciAddr(ctx, a.hostAddress), pciAddr(ctx, a.guestAddress)) + + atts = ctx['global'].getArray(console, 'attachedPciDevices') + for a in atts: + if a.isPhysicalDevice: + print "%s: physical, guest %s, host %s" %(colDev(ctx, a.name), pciAddr(ctx, a.guestAddress), pciAddr(ctx, a.hostAddress)) + else: + print "%s: virtual, guest %s" %(colDev(ctx, a.name), pciAddr(ctx, a.guestAddress)) + return + +def parsePci(str): + pcire = re.compile(r'(?P<b>[0-9a-fA-F]+):(?P<d>[0-9a-fA-F]+)\.(?P<f>\d)') + m = pcire.search(str) + if m is None: + return -1 + dict = m.groupdict() + return ((int(dict['b'], 16)) << 8) | ((int(dict['d'], 16)) << 3) | int(dict['f']) + +def lspciCmd(ctx, args): + if (len(args) < 2): + print "usage: lspci vm" + return 0 + mach = argsToMach(ctx,args) + if mach == None: + return 0 + cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx,mach,console,args: lspci(ctx, console)]) + return 0 + +def attachpciCmd(ctx, args): + if (len(args) < 3): + print "usage: attachpci vm hostpci <guestpci>" + return 0 + mach = argsToMach(ctx,args) + if mach == None: + return 0 + hostaddr = parsePci(args[2]) + if hostaddr == -1: + print "invalid host PCI %s, accepted format 01:02.3 for bus 1, device 2, function 3" %(args[2]) + return 0 + + if (len(args) > 3): + guestaddr = parsePci(args[3]) + if guestaddr == -1: + print "invalid guest PCI %s, accepted format 01:02.3 for bus 1, device 2, function 3" %(args[3]) + return 0 + else: + guestaddr = hostaddr + cmdClosedVm(ctx, mach, lambda ctx,mach,a: mach.attachHostPciDevice(hostaddr, guestaddr, True)) + return 0 + +def detachpciCmd(ctx, args): + if (len(args) < 3): + print "usage: detachpci vm hostpci" + return 0 + mach = argsToMach(ctx,args) + if mach == None: + return 0 + hostaddr = parsePci(args[2]) + if hostaddr == -1: + print "invalid host PCI %s, accepted format 01:02.3 for bus 1, device 2, function 3" %(args[2]) + return 0 + + cmdClosedVm(ctx, mach, lambda ctx,mach,a: mach.detachHostPciDevice(hostaddr)) + return 0 + +def gotoCmd(ctx, args): + if (len(args) < 2): + print "usage: goto line" + return 0 + + line = int(args[1]) + + ctx['scriptLine'] = line + + return 0 + aliases = {'s':'start', 'i':'info', 'l':'list', @@ -3152,11 +3254,15 @@ commands = {'help':['Prints help information', helpCmd, 0], 'snapshot':['VM snapshot manipulation, snapshot help for more info', snapshotCmd, 0], 'nat':['NAT (network address translation engine) manipulation, nat help for more info', natCmd, 0], 'nic' : ['Network adapter management', nicCmd, 0], - 'prompt' : ['Control prompt', promptCmd, 0], + 'prompt' : ['Control shell prompt', promptCmd, 0], 'foreachvm' : ['Perform command for each VM', foreachvmCmd, 0], 'foreach' : ['Generic "for each" construction, using XPath-like notation: foreach //vms/vm[@OSTypeId=\'MacOS\'] "print obj.name"', foreachCmd, 0], 'recordDemo':['Record demo: recordDemo Win32 file.dmo 10', recordDemoCmd, 0], - 'playbackDemo':['Playback demo: playbackDemo Win32 file.dmo 10', playbackDemoCmd, 0] + 'playbackDemo':['Playback demo: playbackDemo Win32 file.dmo 10', playbackDemoCmd, 0], + 'lspci': ['List PCI devices attached to the VM: lspci Win32', lspciCmd, 0], + 'attachpci': ['Attach host PCI device to the VM: attachpci Win32 01:00.0', attachpciCmd, 0], + 'detachpci': ['Detach host PCI device from the VM: detachpci Win32 01:00.0', detachpciCmd, 0], + 'goto': ['Go to line in script (script-only)', gotoCmd, 0] } def runCommandArgs(ctx, args): @@ -3250,7 +3356,7 @@ def interpret(ctx): home = getHomeFolder(ctx) checkUserExtensions(ctx, commands, home) - if platform.system() == 'Windows': + if platform.system() in ['Windows', 'Microsoft']: global g_hascolors g_hascolors = False hist_file=os.path.join(home, ".vboxshellhistory") @@ -3383,7 +3489,9 @@ def main(argv): 'progressBar': lambda p: progressBar(ctx,p), 'typeInGuest': typeInGuest, '_machlist': None, - 'prompt': g_prompt + 'prompt': g_prompt, + 'scriptLine': 0, + 'interrupt': False } interpret(ctx) g_virtualBoxManager.deinit() |