summaryrefslogtreecommitdiff
path: root/src/VBox/Frontends/VBoxShell/vboxshell.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Frontends/VBoxShell/vboxshell.py')
-rw-r--r--[-rwxr-xr-x]src/VBox/Frontends/VBoxShell/vboxshell.py208
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()