VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxShell/vboxshell.py@ 55747

Last change on this file since 55747 was 55214, checked in by vboxsync, 10 years ago

Main/Console+Machine+Session+Snapshot: move the save state and snapshot related methods from IConsole to IMachine, with lots of unavoidable code restructuring and cleanup. Also define two new machine states (so that the "Saving" one is specifically for saving state now) which requires more changes everywhere
Frontends: necessary adjustments
doc/SDK: document the changes

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 118.4 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: vboxshell.py 55214 2015-04-13 15:53:01Z vboxsync $
4"""
5VirtualBox Python Shell.
6
7This program is a simple interactive shell for VirtualBox. You can query
8information and issue commands from a simple command line.
9
10It also provides you with examples on how to use VirtualBox's Python API.
11This shell is even somewhat documented, supports TAB-completion and
12history if you have Python readline installed.
13
14Finally, shell allows arbitrary custom extensions, just create
15.VirtualBox/shexts/ and drop your extensions there.
16 Enjoy.
17
18P.S. Our apologies for the code quality.
19"""
20
21__copyright__ = \
22"""
23Copyright (C) 2009-2015 Oracle Corporation
24
25This file is part of VirtualBox Open Source Edition (OSE), as
26available from http://www.virtualbox.org. This file is free software;
27you can redistribute it and/or modify it under the terms of the GNU
28General Public License (GPL) as published by the Free Software
29Foundation, in version 2 as it comes in the "COPYING" file of the
30VirtualBox OSE distribution. VirtualBox OSE is distributed in the
31hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
32"""
33__version__ = "$Revision: 55214 $"
34
35
36import os, sys
37import traceback
38import shlex
39import time
40import re
41import platform
42from optparse import OptionParser
43from pprint import pprint
44
45
46
47#
48# Global Variables
49#
50g_fBatchMode = False
51g_sScriptFile = None
52g_sCmd = None
53g_fHasReadline = True
54try:
55 import readline
56 import rlcompleter
57except ImportError:
58 g_fHasReadline = False
59
60g_sPrompt = "vbox> "
61
62g_fHasColors = True
63g_dTermColors = {
64 'red': '\033[31m',
65 'blue': '\033[94m',
66 'green': '\033[92m',
67 'yellow': '\033[93m',
68 'magenta': '\033[35m',
69 'cyan': '\033[36m'
70}
71
72
73
74def colored(strg, color):
75 """
76 Translates a string to one including coloring settings, if enabled.
77 """
78 if not g_fHasColors:
79 return strg
80 col = g_dTermColors.get(color, None)
81 if col:
82 return col+str(strg)+'\033[0m'
83 return strg
84
85if g_fHasReadline:
86 class CompleterNG(rlcompleter.Completer):
87 def __init__(self, dic, ctx):
88 self.ctx = ctx
89 rlcompleter.Completer.__init__(self, dic)
90
91 def complete(self, text, state):
92 """
93 taken from:
94 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496812
95 """
96 if False and text == "":
97 return ['\t', None][state]
98 else:
99 return rlcompleter.Completer.complete(self, text, state)
100
101 def canBePath(self, _phrase, word):
102 return word.startswith('/')
103
104 def canBeCommand(self, phrase, _word):
105 spaceIdx = phrase.find(" ")
106 begIdx = readline.get_begidx()
107 firstWord = (spaceIdx == -1 or begIdx < spaceIdx)
108 if firstWord:
109 return True
110 if phrase.startswith('help'):
111 return True
112 return False
113
114 def canBeMachine(self, phrase, word):
115 return not self.canBePath(phrase, word) and not self.canBeCommand(phrase, word)
116
117 def global_matches(self, text):
118 """
119 Compute matches when text is a simple name.
120 Return a list of all names currently defined
121 in self.namespace that match.
122 """
123
124 matches = []
125 phrase = readline.get_line_buffer()
126
127 try:
128 if self.canBePath(phrase, text):
129 (directory, rest) = os.path.split(text)
130 c = len(rest)
131 for word in os.listdir(directory):
132 if c == 0 or word[:c] == rest:
133 matches.append(os.path.join(directory, word))
134
135 if self.canBeCommand(phrase, text):
136 c = len(text)
137 for lst in [ self.namespace ]:
138 for word in lst:
139 if word[:c] == text:
140 matches.append(word)
141
142 if self.canBeMachine(phrase, text):
143 c = len(text)
144 for mach in getMachines(self.ctx, False, True):
145 # although it has autoconversion, we need to cast
146 # explicitly for subscripts to work
147 word = re.sub("(?<!\\\\) ", "\\ ", str(mach.name))
148 if word[:c] == text:
149 matches.append(word)
150 word = str(mach.id)
151 if word[:c] == text:
152 matches.append(word)
153
154 except Exception, e:
155 printErr(self.ctx, e)
156 if g_fVerbose:
157 traceback.print_exc()
158
159 return matches
160
161def autoCompletion(cmds, ctx):
162 if not g_fHasReadline:
163 return
164
165 comps = {}
166 for (key, _value) in cmds.items():
167 comps[key] = None
168 completer = CompleterNG(comps, ctx)
169 readline.set_completer(completer.complete)
170 delims = readline.get_completer_delims()
171 readline.set_completer_delims(re.sub("[\\./-]", "", delims)) # remove some of the delimiters
172 readline.parse_and_bind("set editing-mode emacs")
173 # OSX need it
174 if platform.system() == 'Darwin':
175 # see http://www.certif.com/spec_help/readline.html
176 readline.parse_and_bind ("bind ^I rl_complete")
177 readline.parse_and_bind ("bind ^W ed-delete-prev-word")
178 # Doesn't work well
179 # readline.parse_and_bind ("bind ^R em-inc-search-prev")
180 readline.parse_and_bind("tab: complete")
181
182
183g_fVerbose = False
184
185def split_no_quotes(s):
186 return shlex.split(s)
187
188def progressBar(ctx, progress, wait=1000):
189 try:
190 while not progress.completed:
191 print "%s %%\r" % (colored(str(progress.percent), 'red')),
192 sys.stdout.flush()
193 progress.waitForCompletion(wait)
194 ctx['global'].waitForEvents(0)
195 if int(progress.resultCode) != 0:
196 reportError(ctx, progress)
197 return 1
198 except KeyboardInterrupt:
199 print "Interrupted."
200 ctx['interrupt'] = True
201 if progress.cancelable:
202 print "Canceling task..."
203 progress.cancel()
204 return 0
205
206def printErr(_ctx, e):
207 oVBoxMgr = _ctx['global'];
208 if oVBoxMgr.errIsOurXcptKind(e):
209 print colored('%s: %s' % (oVBoxMgr.xcptToString(e), oVBoxMgr.xcptGetMessage(e)), 'red');
210 else:
211 print colored(str(e), 'red')
212
213def reportError(_ctx, progress):
214 errorinfo = progress.errorInfo
215 if errorinfo:
216 print colored("Error in module '%s': %s" % (errorinfo.component, errorinfo.text), 'red')
217
218def colCat(_ctx, strg):
219 return colored(strg, 'magenta')
220
221def colVm(_ctx, vmname):
222 return colored(vmname, 'blue')
223
224def colPath(_ctx, path):
225 return colored(path, 'green')
226
227def colSize(_ctx, byte):
228 return colored(byte, 'red')
229
230def colPci(_ctx, pcidev):
231 return colored(pcidev, 'green')
232
233def colDev(_ctx, pcidev):
234 return colored(pcidev, 'cyan')
235
236def colSizeM(_ctx, mbyte):
237 return colored(str(mbyte)+'M', 'red')
238
239def createVm(ctx, name, kind):
240 vbox = ctx['vb']
241 mach = vbox.createMachine("", name, [], kind, "")
242 mach.saveSettings()
243 print "created machine with UUID", mach.id
244 vbox.registerMachine(mach)
245 # update cache
246 getMachines(ctx, True)
247
248def removeVm(ctx, mach):
249 uuid = mach.id
250 print "removing machine ", mach.name, "with UUID", uuid
251 cmdClosedVm(ctx, mach, detachVmDevice, ["ALL"])
252 disks = mach.unregister(ctx['global'].constants.CleanupMode_Full)
253 if mach:
254 progress = mach.deleteConfig(disks)
255 if progressBar(ctx, progress, 100) and int(progress.resultCode) == 0:
256 print "Success!"
257 else:
258 reportError(ctx, progress)
259 # update cache
260 getMachines(ctx, True)
261
262def startVm(ctx, mach, vmtype):
263 vbox = ctx['vb']
264 perf = ctx['perf']
265 session = ctx['global'].getSessionObject(vbox)
266 progress = mach.launchVMProcess(session, vmtype, "")
267 if progressBar(ctx, progress, 100) and int(progress.resultCode) == 0:
268 # we ignore exceptions to allow starting VM even if
269 # perf collector cannot be started
270 if perf:
271 try:
272 perf.setup(['*'], [mach], 10, 15)
273 except Exception, e:
274 printErr(ctx, e)
275 if g_fVerbose:
276 traceback.print_exc()
277 session.unlockMachine()
278
279class CachedMach:
280 def __init__(self, mach):
281 if mach.accessible:
282 self.name = mach.name
283 else:
284 self.name = '<inaccessible>'
285 self.id = mach.id
286
287def cacheMachines(_ctx, lst):
288 result = []
289 for mach in lst:
290 elem = CachedMach(mach)
291 result.append(elem)
292 return result
293
294def getMachines(ctx, invalidate = False, simple=False):
295 if ctx['vb'] is not None:
296 if ctx['_machlist'] is None or invalidate:
297 ctx['_machlist'] = ctx['global'].getArray(ctx['vb'], 'machines')
298 ctx['_machlistsimple'] = cacheMachines(ctx, ctx['_machlist'])
299 if simple:
300 return ctx['_machlistsimple']
301 else:
302 return ctx['_machlist']
303 else:
304 return []
305
306def asState(var):
307 if var:
308 return colored('on', 'green')
309 else:
310 return colored('off', 'green')
311
312def asFlag(var):
313 if var:
314 return 'yes'
315 else:
316 return 'no'
317
318def getFacilityStatus(ctx, guest, facilityType):
319 (status, _timestamp) = guest.getFacilityStatus(facilityType)
320 return asEnumElem(ctx, 'AdditionsFacilityStatus', status)
321
322def perfStats(ctx, mach):
323 if not ctx['perf']:
324 return
325 for metric in ctx['perf'].query(["*"], [mach]):
326 print metric['name'], metric['values_as_string']
327
328def guestExec(ctx, machine, console, cmds):
329 exec cmds
330
331def printMouseEvent(_ctx, mev):
332 print "Mouse : mode=%d x=%d y=%d z=%d w=%d buttons=%x" % (mev.mode, mev.x, mev.y, mev.z, mev.w, mev.buttons)
333
334def printKbdEvent(ctx, kev):
335 print "Kbd: ", ctx['global'].getArray(kev, 'scancodes')
336
337def printMultiTouchEvent(ctx, mtev):
338 print "MultiTouch : contacts=%d time=%d" % (mtev.contactCount, mtev.scanTime)
339 xPositions = ctx['global'].getArray(mtev, 'xPositions')
340 yPositions = ctx['global'].getArray(mtev, 'yPositions')
341 contactIds = ctx['global'].getArray(mtev, 'contactIds')
342 contactFlags = ctx['global'].getArray(mtev, 'contactFlags')
343
344 for i in range(0, mtev.contactCount):
345 print " [%d] %d,%d %d %d" % (i, xPositions[i], yPositions[i], contactIds[i], contactFlags[i])
346
347def monitorSource(ctx, eventSource, active, dur):
348 def handleEventImpl(event):
349 evtype = event.type
350 print "got event: %s %s" % (str(evtype), asEnumElem(ctx, 'VBoxEventType', evtype))
351 if evtype == ctx['global'].constants.VBoxEventType_OnMachineStateChanged:
352 scev = ctx['global'].queryInterface(event, 'IMachineStateChangedEvent')
353 if scev:
354 print "machine state event: mach=%s state=%s" % (scev.machineId, scev.state)
355 elif evtype == ctx['global'].constants.VBoxEventType_OnSnapshotTaken:
356 stev = ctx['global'].queryInterface(event, 'ISnapshotTakenEvent')
357 if stev:
358 print "snapshot taken event: mach=%s snap=%s" % (stev.machineId, stev.snapshotId)
359 elif evtype == ctx['global'].constants.VBoxEventType_OnGuestPropertyChanged:
360 gpcev = ctx['global'].queryInterface(event, 'IGuestPropertyChangedEvent')
361 if gpcev:
362 print "guest property change: name=%s value=%s" % (gpcev.name, gpcev.value)
363 elif evtype == ctx['global'].constants.VBoxEventType_OnMousePointerShapeChanged:
364 psev = ctx['global'].queryInterface(event, 'IMousePointerShapeChangedEvent')
365 if psev:
366 shape = ctx['global'].getArray(psev, 'shape')
367 if shape is None:
368 print "pointer shape event - empty shape"
369 else:
370 print "pointer shape event: w=%d h=%d shape len=%d" % (psev.width, psev.height, len(shape))
371 elif evtype == ctx['global'].constants.VBoxEventType_OnGuestMouse:
372 mev = ctx['global'].queryInterface(event, 'IGuestMouseEvent')
373 if mev:
374 printMouseEvent(ctx, mev)
375 elif evtype == ctx['global'].constants.VBoxEventType_OnGuestKeyboard:
376 kev = ctx['global'].queryInterface(event, 'IGuestKeyboardEvent')
377 if kev:
378 printKbdEvent(ctx, kev)
379 elif evtype == ctx['global'].constants.VBoxEventType_OnGuestMultiTouch:
380 mtev = ctx['global'].queryInterface(event, 'IGuestMultiTouchEvent')
381 if mtev:
382 printMultiTouchEvent(ctx, mtev)
383
384 class EventListener(object):
385 def __init__(self, arg):
386 pass
387
388 def handleEvent(self, event):
389 try:
390 # a bit convoluted QI to make it work with MS COM
391 handleEventImpl(ctx['global'].queryInterface(event, 'IEvent'))
392 except:
393 traceback.print_exc()
394 pass
395
396 if active:
397 listener = ctx['global'].createListener(EventListener)
398 else:
399 listener = eventSource.createListener()
400 registered = False
401 if dur == -1:
402 # not infinity, but close enough
403 dur = 100000
404 try:
405 eventSource.registerListener(listener, [ctx['global'].constants.VBoxEventType_Any], active)
406 registered = True
407 end = time.time() + dur
408 while time.time() < end:
409 if active:
410 ctx['global'].waitForEvents(500)
411 else:
412 event = eventSource.getEvent(listener, 500)
413 if event:
414 handleEventImpl(event)
415 # otherwise waitable events will leak (active listeners ACK automatically)
416 eventSource.eventProcessed(listener, event)
417 # We need to catch all exceptions here, otherwise listener will never be unregistered
418 except:
419 traceback.print_exc()
420 pass
421 if listener and registered:
422 eventSource.unregisterListener(listener)
423
424
425g_tsLast = 0
426def recordDemo(ctx, console, filename, dur):
427 demo = open(filename, 'w')
428 header = "VM=" + console.machine.name + "\n"
429 demo.write(header)
430
431 global g_tsLast
432 g_tsLast = time.time()
433
434 def stamp():
435 global g_tsLast
436 tsCur = time.time()
437 timePassed = int((tsCur-g_tsLast)*1000)
438 g_tsLast = tsCur
439 return timePassed
440
441 def handleEventImpl(event):
442 evtype = event.type
443 #print "got event: %s %s" % (str(evtype), asEnumElem(ctx, 'VBoxEventType', evtype))
444 if evtype == ctx['global'].constants.VBoxEventType_OnGuestMouse:
445 mev = ctx['global'].queryInterface(event, 'IGuestMouseEvent')
446 if mev:
447 line = "%d: m %d %d %d %d %d %d\n" % (stamp(), mev.mode, mev.x, mev.y, mev.z, mev.w, mev.buttons)
448 demo.write(line)
449 elif evtype == ctx['global'].constants.VBoxEventType_OnGuestKeyboard:
450 kev = ctx['global'].queryInterface(event, 'IGuestKeyboardEvent')
451 if kev:
452 line = "%d: k %s\n" % (stamp(), str(ctx['global'].getArray(kev, 'scancodes')))
453 demo.write(line)
454
455 listener = console.eventSource.createListener()
456 registered = False
457 # we create an aggregated event source to listen for multiple event sources (keyboard and mouse in our case)
458 agg = console.eventSource.createAggregator([console.keyboard.eventSource, console.mouse.eventSource])
459 demo = open(filename, 'w')
460 header = "VM=" + console.machine.name + "\n"
461 demo.write(header)
462 if dur == -1:
463 # not infinity, but close enough
464 dur = 100000
465 try:
466 agg.registerListener(listener, [ctx['global'].constants.VBoxEventType_Any], False)
467 registered = True
468 end = time.time() + dur
469 while time.time() < end:
470 event = agg.getEvent(listener, 1000)
471 if event:
472 handleEventImpl(event)
473 # keyboard/mouse events aren't waitable, so no need for eventProcessed
474 # We need to catch all exceptions here, otherwise listener will never be unregistered
475 except:
476 traceback.print_exc()
477 pass
478 demo.close()
479 if listener and registered:
480 agg.unregisterListener(listener)
481
482
483def playbackDemo(ctx, console, filename, dur):
484 demo = open(filename, 'r')
485
486 if dur == -1:
487 # not infinity, but close enough
488 dur = 100000
489
490 header = demo.readline()
491 print "Header is", header
492 basere = re.compile(r'(?P<s>\d+): (?P<t>[km]) (?P<p>.*)')
493 mre = re.compile(r'(?P<a>\d+) (?P<x>-*\d+) (?P<y>-*\d+) (?P<z>-*\d+) (?P<w>-*\d+) (?P<b>-*\d+)')
494 kre = re.compile(r'\d+')
495
496 kbd = console.keyboard
497 mouse = console.mouse
498
499 try:
500 end = time.time() + dur
501 for line in demo:
502 if time.time() > end:
503 break
504 match = basere.search(line)
505 if match is None:
506 continue
507
508 rdict = match.groupdict()
509 stamp = rdict['s']
510 params = rdict['p']
511 rtype = rdict['t']
512
513 time.sleep(float(stamp)/1000)
514
515 if rtype == 'k':
516 codes = kre.findall(params)
517 #print "KBD:", codes
518 kbd.putScancodes(codes)
519 elif rtype == 'm':
520 mm = mre.search(params)
521 if mm is not None:
522 mdict = mm.groupdict()
523 if mdict['a'] == '1':
524 # absolute
525 #print "MA: ", mdict['x'], mdict['y'], mdict['z'], mdict['b']
526 mouse.putMouseEventAbsolute(int(mdict['x']), int(mdict['y']), int(mdict['z']), int(mdict['w']), int(mdict['b']))
527 else:
528 #print "MR: ", mdict['x'], mdict['y'], mdict['b']
529 mouse.putMouseEvent(int(mdict['x']), int(mdict['y']), int(mdict['z']), int(mdict['w']), int(mdict['b']))
530
531 # We need to catch all exceptions here, to close file
532 except KeyboardInterrupt:
533 ctx['interrupt'] = True
534 except:
535 traceback.print_exc()
536 pass
537 demo.close()
538
539
540def takeScreenshotOld(_ctx, console, args):
541 from PIL import Image
542 display = console.display
543 if len(args) > 0:
544 f = args[0]
545 else:
546 f = "/tmp/screenshot.png"
547 if len(args) > 3:
548 screen = int(args[3])
549 else:
550 screen = 0
551 (fbw, fbh, _fbbpp, fbx, fby, _) = display.getScreenResolution(screen)
552 if len(args) > 1:
553 w = int(args[1])
554 else:
555 w = fbw
556 if len(args) > 2:
557 h = int(args[2])
558 else:
559 h = fbh
560
561 print "Saving screenshot (%d x %d) screen %d in %s..." % (w, h, screen, f)
562 data = display.takeScreenShotToArray(screen, w, h, ctx['const'].BitmapFormat_RGBA)
563 size = (w, h)
564 mode = "RGBA"
565 im = Image.frombuffer(mode, size, str(data), "raw", mode, 0, 1)
566 im.save(f, "PNG")
567
568def takeScreenshot(_ctx, console, args):
569 display = console.display
570 if len(args) > 0:
571 f = args[0]
572 else:
573 f = "/tmp/screenshot.png"
574 if len(args) > 3:
575 screen = int(args[3])
576 else:
577 screen = 0
578 (fbw, fbh, _fbbpp, fbx, fby, _) = display.getScreenResolution(screen)
579 if len(args) > 1:
580 w = int(args[1])
581 else:
582 w = fbw
583 if len(args) > 2:
584 h = int(args[2])
585 else:
586 h = fbh
587
588 print "Saving screenshot (%d x %d) screen %d in %s..." % (w, h, screen, f)
589 data = display.takeScreenShotToArray(screen, w, h, ctx['const'].BitmapFormat_PNG)
590 pngfile = open(f, 'wb')
591 pngfile.write(data)
592 pngfile.close()
593
594def teleport(ctx, _session, console, args):
595 if args[0].find(":") == -1:
596 print "Use host:port format for teleport target"
597 return
598 (host, port) = args[0].split(":")
599 if len(args) > 1:
600 passwd = args[1]
601 else:
602 passwd = ""
603
604 if len(args) > 2:
605 maxDowntime = int(args[2])
606 else:
607 maxDowntime = 250
608
609 port = int(port)
610 print "Teleporting to %s:%d..." % (host, port)
611 progress = console.teleport(host, port, passwd, maxDowntime)
612 if progressBar(ctx, progress, 100) and int(progress.resultCode) == 0:
613 print "Success!"
614 else:
615 reportError(ctx, progress)
616
617
618def guestStats(ctx, console, args):
619 guest = console.guest
620 # we need to set up guest statistics
621 if len(args) > 0 :
622 update = args[0]
623 else:
624 update = 1
625 if guest.statisticsUpdateInterval != update:
626 guest.statisticsUpdateInterval = update
627 try:
628 time.sleep(float(update)+0.1)
629 except:
630 # to allow sleep interruption
631 pass
632 all_stats = ctx['const'].all_values('GuestStatisticType')
633 cpu = 0
634 for s in all_stats.keys():
635 try:
636 val = guest.getStatistic( cpu, all_stats[s])
637 print "%s: %d" % (s, val)
638 except:
639 # likely not implemented
640 pass
641
642def plugCpu(_ctx, machine, _session, args):
643 cpu = int(args[0])
644 print "Adding CPU %d..." % (cpu)
645 machine.hotPlugCPU(cpu)
646
647def unplugCpu(_ctx, machine, _session, args):
648 cpu = int(args[0])
649 print "Removing CPU %d..." % (cpu)
650 machine.hotUnplugCPU(cpu)
651
652def mountIso(_ctx, machine, _session, args):
653 machine.mountMedium(args[0], args[1], args[2], args[3], args[4])
654 machine.saveSettings()
655
656def cond(c, v1, v2):
657 if c:
658 return v1
659 else:
660 return v2
661
662def printHostUsbDev(ctx, ud):
663 print " %s: %s (vendorId=%d productId=%d serial=%s) %s" % (ud.id, colored(ud.product, 'blue'), ud.vendorId, ud.productId, ud.serialNumber, asEnumElem(ctx, 'USBDeviceState', ud.state))
664
665def printUsbDev(_ctx, ud):
666 print " %s: %s (vendorId=%d productId=%d serial=%s)" % (ud.id, colored(ud.product, 'blue'), ud.vendorId, ud.productId, ud.serialNumber)
667
668def printSf(ctx, sf):
669 print " name=%s host=%s %s %s" % (sf.name, colPath(ctx, sf.hostPath), cond(sf.accessible, "accessible", "not accessible"), cond(sf.writable, "writable", "read-only"))
670
671def ginfo(ctx, console, _args):
672 guest = console.guest
673 if guest.additionsRunLevel != ctx['const'].AdditionsRunLevelType_None:
674 print "Additions active, version %s" % (guest.additionsVersion)
675 print "Support seamless: %s" % (getFacilityStatus(ctx, guest, ctx['const'].AdditionsFacilityType_Seamless))
676 print "Support graphics: %s" % (getFacilityStatus(ctx, guest, ctx['const'].AdditionsFacilityType_Graphics))
677 print "Balloon size: %d" % (guest.memoryBalloonSize)
678 print "Statistic update interval: %d" % (guest.statisticsUpdateInterval)
679 else:
680 print "No additions"
681 usbs = ctx['global'].getArray(console, 'USBDevices')
682 print "Attached USB:"
683 for ud in usbs:
684 printUsbDev(ctx, ud)
685 rusbs = ctx['global'].getArray(console, 'remoteUSBDevices')
686 print "Remote USB:"
687 for ud in rusbs:
688 printHostUsbDev(ctx, ud)
689 print "Transient shared folders:"
690 sfs = rusbs = ctx['global'].getArray(console, 'sharedFolders')
691 for sf in sfs:
692 printSf(ctx, sf)
693
694def cmdExistingVm(ctx, mach, cmd, args):
695 session = None
696 try:
697 vbox = ctx['vb']
698 session = ctx['global'].getSessionObject(vbox)
699 mach.lockMachine(session, ctx['global'].constants.LockType_Shared)
700 except Exception, e:
701 printErr(ctx, "Session to '%s' not open: %s" % (mach.name, str(e)))
702 if g_fVerbose:
703 traceback.print_exc()
704 return
705 if session.state != ctx['const'].SessionState_Locked:
706 print "Session to '%s' in wrong state: %s" % (mach.name, session.state)
707 session.unlockMachine()
708 return
709 # this could be an example how to handle local only (i.e. unavailable
710 # in Webservices) functionality
711 if ctx['remote'] and cmd == 'some_local_only_command':
712 print 'Trying to use local only functionality, ignored'
713 session.unlockMachine()
714 return
715 console = session.console
716 ops = {'pause': lambda: console.pause(),
717 'resume': lambda: console.resume(),
718 'powerdown': lambda: console.powerDown(),
719 'powerbutton': lambda: console.powerButton(),
720 'stats': lambda: perfStats(ctx, mach),
721 'guest': lambda: guestExec(ctx, mach, console, args),
722 'ginfo': lambda: ginfo(ctx, console, args),
723 'guestlambda': lambda: args[0](ctx, mach, console, args[1:]),
724 'save': lambda: progressBar(ctx, session.machine.saveState()),
725 'screenshot': lambda: takeScreenshot(ctx, console, args),
726 'teleport': lambda: teleport(ctx, session, console, args),
727 'gueststats': lambda: guestStats(ctx, console, args),
728 'plugcpu': lambda: plugCpu(ctx, session.machine, session, args),
729 'unplugcpu': lambda: unplugCpu(ctx, session.machine, session, args),
730 'mountiso': lambda: mountIso(ctx, session.machine, session, args),
731 }
732 try:
733 ops[cmd]()
734 except KeyboardInterrupt:
735 ctx['interrupt'] = True
736 except Exception, e:
737 printErr(ctx, e)
738 if g_fVerbose:
739 traceback.print_exc()
740
741 session.unlockMachine()
742
743
744def cmdClosedVm(ctx, mach, cmd, args=[], save=True):
745 session = ctx['global'].openMachineSession(mach, True)
746 mach = session.machine
747 try:
748 cmd(ctx, mach, args)
749 except Exception, e:
750 save = False
751 printErr(ctx, e)
752 if g_fVerbose:
753 traceback.print_exc()
754 if save:
755 try:
756 mach.saveSettings()
757 except Exception, e:
758 printErr(ctx, e)
759 if g_fVerbose:
760 traceback.print_exc()
761 ctx['global'].closeMachineSession(session)
762
763
764def cmdAnyVm(ctx, mach, cmd, args=[], save=False):
765 session = ctx['global'].openMachineSession(mach)
766 mach = session.machine
767 try:
768 cmd(ctx, mach, session.console, args)
769 except Exception, e:
770 save = False
771 printErr(ctx, e)
772 if g_fVerbose:
773 traceback.print_exc()
774 if save:
775 mach.saveSettings()
776 ctx['global'].closeMachineSession(session)
777
778def machById(ctx, uuid):
779 try:
780 mach = ctx['vb'].getMachine(uuid)
781 except:
782 mach = ctx['vb'].findMachine(uuid)
783 return mach
784
785class XPathNode:
786 def __init__(self, parent, obj, ntype):
787 self.parent = parent
788 self.obj = obj
789 self.ntype = ntype
790 def lookup(self, subpath):
791 children = self.enum()
792 matches = []
793 for e in children:
794 if e.matches(subpath):
795 matches.append(e)
796 return matches
797 def enum(self):
798 return []
799 def matches(self, subexp):
800 if subexp == self.ntype:
801 return True
802 if not subexp.startswith(self.ntype):
803 return False
804 match = re.search(r"@(?P<a>\w+)=(?P<v>[^\'\[\]]+)", subexp)
805 matches = False
806 try:
807 if match is not None:
808 xdict = match.groupdict()
809 attr = xdict['a']
810 val = xdict['v']
811 matches = (str(getattr(self.obj, attr)) == val)
812 except:
813 pass
814 return matches
815 def apply(self, cmd):
816 exec(cmd, {'obj':self.obj, 'node':self, 'ctx':self.getCtx()}, {})
817 def getCtx(self):
818 if hasattr(self, 'ctx'):
819 return self.ctx
820 return self.parent.getCtx()
821
822class XPathNodeHolder(XPathNode):
823 def __init__(self, parent, obj, attr, heldClass, xpathname):
824 XPathNode.__init__(self, parent, obj, 'hld '+xpathname)
825 self.attr = attr
826 self.heldClass = heldClass
827 self.xpathname = xpathname
828 def enum(self):
829 children = []
830 for node in self.getCtx()['global'].getArray(self.obj, self.attr):
831 nodexml = self.heldClass(self, node)
832 children.append(nodexml)
833 return children
834 def matches(self, subexp):
835 return subexp == self.xpathname
836
837class XPathNodeValue(XPathNode):
838 def __init__(self, parent, obj, xpathname):
839 XPathNode.__init__(self, parent, obj, 'val '+xpathname)
840 self.xpathname = xpathname
841 def matches(self, subexp):
842 return subexp == self.xpathname
843
844class XPathNodeHolderVM(XPathNodeHolder):
845 def __init__(self, parent, vbox):
846 XPathNodeHolder.__init__(self, parent, vbox, 'machines', XPathNodeVM, 'vms')
847
848class XPathNodeVM(XPathNode):
849 def __init__(self, parent, obj):
850 XPathNode.__init__(self, parent, obj, 'vm')
851 #def matches(self, subexp):
852 # return subexp=='vm'
853 def enum(self):
854 return [XPathNodeHolderNIC(self, self.obj),
855 XPathNodeValue(self, self.obj.BIOSSettings, 'bios'), ]
856
857class XPathNodeHolderNIC(XPathNodeHolder):
858 def __init__(self, parent, mach):
859 XPathNodeHolder.__init__(self, parent, mach, 'nics', XPathNodeVM, 'nics')
860 self.maxNic = self.getCtx()['vb'].systemProperties.getMaxNetworkAdapters(self.obj.chipsetType)
861 def enum(self):
862 children = []
863 for i in range(0, self.maxNic):
864 node = XPathNodeNIC(self, self.obj.getNetworkAdapter(i))
865 children.append(node)
866 return children
867
868class XPathNodeNIC(XPathNode):
869 def __init__(self, parent, obj):
870 XPathNode.__init__(self, parent, obj, 'nic')
871 def matches(self, subexp):
872 return subexp == 'nic'
873
874class XPathNodeRoot(XPathNode):
875 def __init__(self, ctx):
876 XPathNode.__init__(self, None, None, 'root')
877 self.ctx = ctx
878 def enum(self):
879 return [XPathNodeHolderVM(self, self.ctx['vb'])]
880 def matches(self, subexp):
881 return True
882
883def eval_xpath(ctx, scope):
884 pathnames = scope.split("/")[2:]
885 nodes = [XPathNodeRoot(ctx)]
886 for path in pathnames:
887 seen = []
888 while len(nodes) > 0:
889 node = nodes.pop()
890 seen.append(node)
891 for s in seen:
892 matches = s.lookup(path)
893 for match in matches:
894 nodes.append(match)
895 if len(nodes) == 0:
896 break
897 return nodes
898
899def argsToMach(ctx, args):
900 if len(args) < 2:
901 print "usage: %s [vmname|uuid]" % (args[0])
902 return None
903 uuid = args[1]
904 mach = machById(ctx, uuid)
905 if mach == None:
906 print "Machine '%s' is unknown, use list command to find available machines" % (uuid)
907 return mach
908
909def helpSingleCmd(cmd, h, sp):
910 if sp != 0:
911 spec = " [ext from "+sp+"]"
912 else:
913 spec = ""
914 print " %s: %s%s" % (colored(cmd, 'blue'), h, spec)
915
916def helpCmd(_ctx, args):
917 if len(args) == 1:
918 print "Help page:"
919 names = commands.keys()
920 names.sort()
921 for i in names:
922 helpSingleCmd(i, commands[i][0], commands[i][2])
923 else:
924 cmd = args[1]
925 c = commands.get(cmd)
926 if c == None:
927 print "Command '%s' not known" % (cmd)
928 else:
929 helpSingleCmd(cmd, c[0], c[2])
930 return 0
931
932def asEnumElem(ctx, enum, elem):
933 enumVals = ctx['const'].all_values(enum)
934 for e in enumVals.keys():
935 if str(elem) == str(enumVals[e]):
936 return colored(e, 'green')
937 return colored("<unknown>", 'green')
938
939def enumFromString(ctx, enum, strg):
940 enumVals = ctx['const'].all_values(enum)
941 return enumVals.get(strg, None)
942
943def listCmd(ctx, _args):
944 for mach in getMachines(ctx, True):
945 try:
946 if mach.teleporterEnabled:
947 tele = "[T] "
948 else:
949 tele = " "
950 print "%sMachine '%s' [%s], machineState=%s, sessionState=%s" % (tele, colVm(ctx, mach.name), mach.id, asEnumElem(ctx, "MachineState", mach.state), asEnumElem(ctx, "SessionState", mach.sessionState))
951 except Exception, e:
952 printErr(ctx, e)
953 if g_fVerbose:
954 traceback.print_exc()
955 return 0
956
957def infoCmd(ctx, args):
958 if (len(args) < 2):
959 print "usage: info [vmname|uuid]"
960 return 0
961 mach = argsToMach(ctx, args)
962 if mach == None:
963 return 0
964 vmos = ctx['vb'].getGuestOSType(mach.OSTypeId)
965 print " One can use setvar <mach> <var> <value> to change variable, using name in []."
966 print " Name [name]: %s" % (colVm(ctx, mach.name))
967 print " Description [description]: %s" % (mach.description)
968 print " ID [n/a]: %s" % (mach.id)
969 print " OS Type [via OSTypeId]: %s" % (vmos.description)
970 print " Firmware [firmwareType]: %s (%s)" % (asEnumElem(ctx, "FirmwareType", mach.firmwareType), mach.firmwareType)
971 print
972 print " CPUs [CPUCount]: %d" % (mach.CPUCount)
973 print " RAM [memorySize]: %dM" % (mach.memorySize)
974 print " VRAM [VRAMSize]: %dM" % (mach.VRAMSize)
975 print " Monitors [monitorCount]: %d" % (mach.monitorCount)
976 print " Chipset [chipsetType]: %s (%s)" % (asEnumElem(ctx, "ChipsetType", mach.chipsetType), mach.chipsetType)
977 print
978 print " Clipboard mode [clipboardMode]: %s (%s)" % (asEnumElem(ctx, "ClipboardMode", mach.clipboardMode), mach.clipboardMode)
979 print " Machine status [n/a]: %s (%s)" % (asEnumElem(ctx, "SessionState", mach.sessionState), mach.sessionState)
980 print
981 if mach.teleporterEnabled:
982 print " Teleport target on port %d (%s)" % (mach.teleporterPort, mach.teleporterPassword)
983 print
984 bios = mach.BIOSSettings
985 print " ACPI [BIOSSettings.ACPIEnabled]: %s" % (asState(bios.ACPIEnabled))
986 print " APIC [BIOSSettings.IOAPICEnabled]: %s" % (asState(bios.IOAPICEnabled))
987 hwVirtEnabled = mach.getHWVirtExProperty(ctx['global'].constants.HWVirtExPropertyType_Enabled)
988 print " Hardware virtualization [guest win machine.setHWVirtExProperty(ctx[\\'const\\'].HWVirtExPropertyType_Enabled, value)]: " + asState(hwVirtEnabled)
989 hwVirtVPID = mach.getHWVirtExProperty(ctx['const'].HWVirtExPropertyType_VPID)
990 print " VPID support [guest win machine.setHWVirtExProperty(ctx[\\'const\\'].HWVirtExPropertyType_VPID, value)]: " + asState(hwVirtVPID)
991 hwVirtNestedPaging = mach.getHWVirtExProperty(ctx['const'].HWVirtExPropertyType_NestedPaging)
992 print " Nested paging [guest win machine.setHWVirtExProperty(ctx[\\'const\\'].HWVirtExPropertyType_NestedPaging, value)]: " + asState(hwVirtNestedPaging)
993
994 print " Hardware 3d acceleration [accelerate3DEnabled]: " + asState(mach.accelerate3DEnabled)
995 print " Hardware 2d video acceleration [accelerate2DVideoEnabled]: " + asState(mach.accelerate2DVideoEnabled)
996
997 print " Use universal time [RTCUseUTC]: %s" % (asState(mach.RTCUseUTC))
998 print " HPET [HPETEnabled]: %s" % (asState(mach.HPETEnabled))
999 if mach.audioAdapter.enabled:
1000 print " Audio [via audioAdapter]: chip %s; host driver %s" % (asEnumElem(ctx, "AudioControllerType", mach.audioAdapter.audioController), asEnumElem(ctx, "AudioDriverType", mach.audioAdapter.audioDriver))
1001 print " CPU hotplugging [CPUHotPlugEnabled]: %s" % (asState(mach.CPUHotPlugEnabled))
1002
1003 print " Keyboard [keyboardHIDType]: %s (%s)" % (asEnumElem(ctx, "KeyboardHIDType", mach.keyboardHIDType), mach.keyboardHIDType)
1004 print " Pointing device [pointingHIDType]: %s (%s)" % (asEnumElem(ctx, "PointingHIDType", mach.pointingHIDType), mach.pointingHIDType)
1005 print " Last changed [n/a]: " + time.asctime(time.localtime(long(mach.lastStateChange)/1000))
1006 # OSE has no VRDE
1007 try:
1008 print " VRDE server [VRDEServer.enabled]: %s" % (asState(mach.VRDEServer.enabled))
1009 except:
1010 pass
1011
1012 print
1013 print colCat(ctx, " USB Controllers:")
1014 for oUsbCtrl in ctx['global'].getArray(mach, 'USBControllers'):
1015 print " '%s': type %s standard: %#x" \
1016 % (oUsbCtrl.name, asEnumElem(ctx, "USBControllerType", oUsbCtrl.type), oUsbCtrl.USBStandard);
1017
1018 print
1019 print colCat(ctx, " I/O subsystem info:")
1020 print " Cache enabled [IOCacheEnabled]: %s" % (asState(mach.IOCacheEnabled))
1021 print " Cache size [IOCacheSize]: %dM" % (mach.IOCacheSize)
1022
1023 controllers = ctx['global'].getArray(mach, 'storageControllers')
1024 if controllers:
1025 print
1026 print colCat(ctx, " Storage Controllers:")
1027 for controller in controllers:
1028 print " '%s': bus %s type %s" % (controller.name, asEnumElem(ctx, "StorageBus", controller.bus), asEnumElem(ctx, "StorageControllerType", controller.controllerType))
1029
1030 attaches = ctx['global'].getArray(mach, 'mediumAttachments')
1031 if attaches:
1032 print
1033 print colCat(ctx, " Media:")
1034 for a in attaches:
1035 print " Controller: '%s' port/device: %d:%d type: %s (%s):" % (a.controller, a.port, a.device, asEnumElem(ctx, "DeviceType", a.type), a.type)
1036 medium = a.medium
1037 if a.type == ctx['global'].constants.DeviceType_HardDisk:
1038 print " HDD:"
1039 print " Id: %s" % (medium.id)
1040 print " Location: %s" % (colPath(ctx, medium.location))
1041 print " Name: %s" % (medium.name)
1042 print " Format: %s" % (medium.format)
1043
1044 if a.type == ctx['global'].constants.DeviceType_DVD:
1045 print " DVD:"
1046 if medium:
1047 print " Id: %s" % (medium.id)
1048 print " Name: %s" % (medium.name)
1049 if medium.hostDrive:
1050 print " Host DVD %s" % (colPath(ctx, medium.location))
1051 if a.passthrough:
1052 print " [passthrough mode]"
1053 else:
1054 print " Virtual image at %s" % (colPath(ctx, medium.location))
1055 print " Size: %s" % (medium.size)
1056
1057 if a.type == ctx['global'].constants.DeviceType_Floppy:
1058 print " Floppy:"
1059 if medium:
1060 print " Id: %s" % (medium.id)
1061 print " Name: %s" % (medium.name)
1062 if medium.hostDrive:
1063 print " Host floppy %s" % (colPath(ctx, medium.location))
1064 else:
1065 print " Virtual image at %s" % (colPath(ctx, medium.location))
1066 print " Size: %s" % (medium.size)
1067
1068 print
1069 print colCat(ctx, " Shared folders:")
1070 for sf in ctx['global'].getArray(mach, 'sharedFolders'):
1071 printSf(ctx, sf)
1072
1073 return 0
1074
1075def startCmd(ctx, args):
1076 if len(args) < 2:
1077 print "usage: start name <frontend>"
1078 return 0
1079 mach = argsToMach(ctx, args)
1080 if mach == None:
1081 return 0
1082 if len(args) > 2:
1083 vmtype = args[2]
1084 else:
1085 vmtype = "gui"
1086 startVm(ctx, mach, vmtype)
1087 return 0
1088
1089def createVmCmd(ctx, args):
1090 if (len(args) != 3):
1091 print "usage: createvm name ostype"
1092 return 0
1093 name = args[1]
1094 oskind = args[2]
1095 try:
1096 ctx['vb'].getGuestOSType(oskind)
1097 except Exception:
1098 print 'Unknown OS type:', oskind
1099 return 0
1100 createVm(ctx, name, oskind)
1101 return 0
1102
1103def ginfoCmd(ctx, args):
1104 if (len(args) < 2):
1105 print "usage: ginfo [vmname|uuid]"
1106 return 0
1107 mach = argsToMach(ctx, args)
1108 if mach == None:
1109 return 0
1110 cmdExistingVm(ctx, mach, 'ginfo', '')
1111 return 0
1112
1113def execInGuest(ctx, console, args, env, user, passwd, tmo, inputPipe=None, outputPipe=None):
1114 if len(args) < 1:
1115 print "exec in guest needs at least program name"
1116 return
1117 guest = console.guest
1118 guestSession = guest.createSession(user, passwd, "", "vboxshell guest exec")
1119 # shall contain program name as argv[0]
1120 gargs = args
1121 print "executing %s with args %s as %s" % (args[0], gargs, user)
1122 flags = 0
1123 if inputPipe is not None:
1124 flags = 1 # set WaitForProcessStartOnly
1125 print args[0]
1126 process = guestSession.processCreate(args[0], gargs, env, [], tmo)
1127 print "executed with pid %d" % (process.PID)
1128 if pid != 0:
1129 try:
1130 while True:
1131 if inputPipe is not None:
1132 indata = inputPipe(ctx)
1133 if indata is not None:
1134 write = len(indata)
1135 off = 0
1136 while write > 0:
1137 w = guest.setProcessInput(pid, 0, 10*1000, indata[off:])
1138 off = off + w
1139 write = write - w
1140 else:
1141 # EOF
1142 try:
1143 guest.setProcessInput(pid, 1, 10*1000, " ")
1144 except:
1145 pass
1146 data = guest.getProcessOutput(pid, 0, 10000, 4096)
1147 if data and len(data) > 0:
1148 sys.stdout.write(data)
1149 continue
1150 progress.waitForCompletion(100)
1151 ctx['global'].waitForEvents(0)
1152 data = guest.getProcessOutput(pid, 0, 0, 4096)
1153 if data and len(data) > 0:
1154 if outputPipe is not None:
1155 outputPipe(ctx, data)
1156 else:
1157 sys.stdout.write(data)
1158 continue
1159 if progress.completed:
1160 break
1161
1162 except KeyboardInterrupt:
1163 print "Interrupted."
1164 ctx['interrupt'] = True
1165 if progress.cancelable:
1166 progress.cancel()
1167 (_reason, code, _flags) = guest.getProcessStatus(pid)
1168 print "Exit code: %d" % (code)
1169 return 0
1170 else:
1171 reportError(ctx, progress)
1172
1173def copyToGuest(ctx, console, args, user, passwd):
1174 src = args[0]
1175 dst = args[1]
1176 flags = 0
1177 print "Copying host %s to guest %s" % (src, dst)
1178 progress = console.guest.copyToGuest(src, dst, user, passwd, flags)
1179 progressBar(ctx, progress)
1180
1181def nh_raw_input(prompt=""):
1182 stream = sys.stdout
1183 prompt = str(prompt)
1184 if prompt:
1185 stream.write(prompt)
1186 line = sys.stdin.readline()
1187 if not line:
1188 raise EOFError
1189 if line[-1] == '\n':
1190 line = line[:-1]
1191 return line
1192
1193
1194def getCred(_ctx):
1195 import getpass
1196 user = getpass.getuser()
1197 user_inp = nh_raw_input("User (%s): " % (user))
1198 if len (user_inp) > 0:
1199 user = user_inp
1200 passwd = getpass.getpass()
1201
1202 return (user, passwd)
1203
1204def gexecCmd(ctx, args):
1205 if (len(args) < 2):
1206 print "usage: gexec [vmname|uuid] command args"
1207 return 0
1208 mach = argsToMach(ctx, args)
1209 if mach == None:
1210 return 0
1211 gargs = args[2:]
1212 env = [] # ["DISPLAY=:0"]
1213 (user, passwd) = getCred(ctx)
1214 gargs.insert(0, lambda ctx, mach, console, args: execInGuest(ctx, console, args, env, user, passwd, 10000))
1215 cmdExistingVm(ctx, mach, 'guestlambda', gargs)
1216 return 0
1217
1218def gcopyCmd(ctx, args):
1219 if (len(args) < 2):
1220 print "usage: gcopy [vmname|uuid] host_path guest_path"
1221 return 0
1222 mach = argsToMach(ctx, args)
1223 if mach == None:
1224 return 0
1225 gargs = args[2:]
1226 (user, passwd) = getCred(ctx)
1227 gargs.insert(0, lambda ctx, mach, console, args: copyToGuest(ctx, console, args, user, passwd))
1228 cmdExistingVm(ctx, mach, 'guestlambda', gargs)
1229 return 0
1230
1231def readCmdPipe(ctx, _hcmd):
1232 try:
1233 return ctx['process'].communicate()[0]
1234 except:
1235 return None
1236
1237def gpipeCmd(ctx, args):
1238 if (len(args) < 4):
1239 print "usage: gpipe [vmname|uuid] hostProgram guestProgram, such as gpipe linux '/bin/uname -a' '/bin/sh -c \"/usr/bin/tee; /bin/uname -a\"'"
1240 return 0
1241 mach = argsToMach(ctx, args)
1242 if mach == None:
1243 return 0
1244 hcmd = args[2]
1245 gcmd = args[3]
1246 (user, passwd) = getCred(ctx)
1247 import subprocess
1248 ctx['process'] = subprocess.Popen(split_no_quotes(hcmd), stdout=subprocess.PIPE)
1249 gargs = split_no_quotes(gcmd)
1250 env = []
1251 gargs.insert(0, lambda ctx, mach, console, args: execInGuest(ctx, console, args, env, user, passwd, 10000, lambda ctx:readCmdPipe(ctx, hcmd)))
1252 cmdExistingVm(ctx, mach, 'guestlambda', gargs)
1253 try:
1254 ctx['process'].terminate()
1255 except:
1256 pass
1257 ctx['process'] = None
1258 return 0
1259
1260
1261def removeVmCmd(ctx, args):
1262 mach = argsToMach(ctx, args)
1263 if mach == None:
1264 return 0
1265 removeVm(ctx, mach)
1266 return 0
1267
1268def pauseCmd(ctx, args):
1269 mach = argsToMach(ctx, args)
1270 if mach == None:
1271 return 0
1272 cmdExistingVm(ctx, mach, 'pause', '')
1273 return 0
1274
1275def powerdownCmd(ctx, args):
1276 mach = argsToMach(ctx, args)
1277 if mach == None:
1278 return 0
1279 cmdExistingVm(ctx, mach, 'powerdown', '')
1280 return 0
1281
1282def powerbuttonCmd(ctx, args):
1283 mach = argsToMach(ctx, args)
1284 if mach == None:
1285 return 0
1286 cmdExistingVm(ctx, mach, 'powerbutton', '')
1287 return 0
1288
1289def resumeCmd(ctx, args):
1290 mach = argsToMach(ctx, args)
1291 if mach == None:
1292 return 0
1293 cmdExistingVm(ctx, mach, 'resume', '')
1294 return 0
1295
1296def saveCmd(ctx, args):
1297 mach = argsToMach(ctx, args)
1298 if mach == None:
1299 return 0
1300 cmdExistingVm(ctx, mach, 'save', '')
1301 return 0
1302
1303def statsCmd(ctx, args):
1304 mach = argsToMach(ctx, args)
1305 if mach == None:
1306 return 0
1307 cmdExistingVm(ctx, mach, 'stats', '')
1308 return 0
1309
1310def guestCmd(ctx, args):
1311 if (len(args) < 3):
1312 print "usage: guest name commands"
1313 return 0
1314 mach = argsToMach(ctx, args)
1315 if mach == None:
1316 return 0
1317 if mach.state != ctx['const'].MachineState_Running:
1318 cmdClosedVm(ctx, mach, lambda ctx, mach, a: guestExec (ctx, mach, None, ' '.join(args[2:])))
1319 else:
1320 cmdExistingVm(ctx, mach, 'guest', ' '.join(args[2:]))
1321 return 0
1322
1323def screenshotCmd(ctx, args):
1324 if (len(args) < 2):
1325 print "usage: screenshot vm <file> <width> <height> <monitor>"
1326 return 0
1327 mach = argsToMach(ctx, args)
1328 if mach == None:
1329 return 0
1330 cmdExistingVm(ctx, mach, 'screenshot', args[2:])
1331 return 0
1332
1333def teleportCmd(ctx, args):
1334 if (len(args) < 3):
1335 print "usage: teleport name host:port <password>"
1336 return 0
1337 mach = argsToMach(ctx, args)
1338 if mach == None:
1339 return 0
1340 cmdExistingVm(ctx, mach, 'teleport', args[2:])
1341 return 0
1342
1343def portalsettings(_ctx, mach, args):
1344 enabled = args[0]
1345 mach.teleporterEnabled = enabled
1346 if enabled:
1347 port = args[1]
1348 passwd = args[2]
1349 mach.teleporterPort = port
1350 mach.teleporterPassword = passwd
1351
1352def openportalCmd(ctx, args):
1353 if (len(args) < 3):
1354 print "usage: openportal name port <password>"
1355 return 0
1356 mach = argsToMach(ctx, args)
1357 if mach == None:
1358 return 0
1359 port = int(args[2])
1360 if (len(args) > 3):
1361 passwd = args[3]
1362 else:
1363 passwd = ""
1364 if not mach.teleporterEnabled or mach.teleporterPort != port or passwd:
1365 cmdClosedVm(ctx, mach, portalsettings, [True, port, passwd])
1366 startVm(ctx, mach, "gui")
1367 return 0
1368
1369def closeportalCmd(ctx, args):
1370 if (len(args) < 2):
1371 print "usage: closeportal name"
1372 return 0
1373 mach = argsToMach(ctx, args)
1374 if mach == None:
1375 return 0
1376 if mach.teleporterEnabled:
1377 cmdClosedVm(ctx, mach, portalsettings, [False])
1378 return 0
1379
1380def gueststatsCmd(ctx, args):
1381 if (len(args) < 2):
1382 print "usage: gueststats name <check interval>"
1383 return 0
1384 mach = argsToMach(ctx, args)
1385 if mach == None:
1386 return 0
1387 cmdExistingVm(ctx, mach, 'gueststats', args[2:])
1388 return 0
1389
1390def plugcpu(_ctx, mach, args):
1391 plug = args[0]
1392 cpu = args[1]
1393 if plug:
1394 print "Adding CPU %d..." % (cpu)
1395 mach.hotPlugCPU(cpu)
1396 else:
1397 print "Removing CPU %d..." % (cpu)
1398 mach.hotUnplugCPU(cpu)
1399
1400def plugcpuCmd(ctx, args):
1401 if (len(args) < 2):
1402 print "usage: plugcpu name cpuid"
1403 return 0
1404 mach = argsToMach(ctx, args)
1405 if mach == None:
1406 return 0
1407 if str(mach.sessionState) != str(ctx['const'].SessionState_Locked):
1408 if mach.CPUHotPlugEnabled:
1409 cmdClosedVm(ctx, mach, plugcpu, [True, int(args[2])])
1410 else:
1411 cmdExistingVm(ctx, mach, 'plugcpu', args[2])
1412 return 0
1413
1414def unplugcpuCmd(ctx, args):
1415 if (len(args) < 2):
1416 print "usage: unplugcpu name cpuid"
1417 return 0
1418 mach = argsToMach(ctx, args)
1419 if mach == None:
1420 return 0
1421 if str(mach.sessionState) != str(ctx['const'].SessionState_Locked):
1422 if mach.CPUHotPlugEnabled:
1423 cmdClosedVm(ctx, mach, plugcpu, [False, int(args[2])])
1424 else:
1425 cmdExistingVm(ctx, mach, 'unplugcpu', args[2])
1426 return 0
1427
1428def setvar(_ctx, _mach, args):
1429 expr = 'mach.'+args[0]+' = '+args[1]
1430 print "Executing", expr
1431 exec expr
1432
1433def setvarCmd(ctx, args):
1434 if (len(args) < 4):
1435 print "usage: setvar [vmname|uuid] expr value"
1436 return 0
1437 mach = argsToMach(ctx, args)
1438 if mach == None:
1439 return 0
1440 cmdClosedVm(ctx, mach, setvar, args[2:])
1441 return 0
1442
1443def setvmextra(_ctx, mach, args):
1444 key = args[0]
1445 value = args[1]
1446 print "%s: setting %s to %s" % (mach.name, key, value)
1447 mach.setExtraData(key, value)
1448
1449def setExtraDataCmd(ctx, args):
1450 if (len(args) < 3):
1451 print "usage: setextra [vmname|uuid|global] key <value>"
1452 return 0
1453 key = args[2]
1454 if len(args) == 4:
1455 value = args[3]
1456 else:
1457 value = None
1458 if args[1] == 'global':
1459 ctx['vb'].setExtraData(key, value)
1460 return 0
1461
1462 mach = argsToMach(ctx, args)
1463 if mach == None:
1464 return 0
1465 cmdClosedVm(ctx, mach, setvmextra, [key, value])
1466 return 0
1467
1468def printExtraKey(obj, key, value):
1469 print "%s: '%s' = '%s'" % (obj, key, value)
1470
1471def getExtraDataCmd(ctx, args):
1472 if (len(args) < 2):
1473 print "usage: getextra [vmname|uuid|global] <key>"
1474 return 0
1475 if len(args) == 3:
1476 key = args[2]
1477 else:
1478 key = None
1479
1480 if args[1] == 'global':
1481 obj = ctx['vb']
1482 else:
1483 obj = argsToMach(ctx, args)
1484 if obj == None:
1485 return 0
1486
1487 if key == None:
1488 keys = obj.getExtraDataKeys()
1489 else:
1490 keys = [ key ]
1491 for k in keys:
1492 printExtraKey(args[1], k, obj.getExtraData(k))
1493
1494 return 0
1495
1496def quitCmd(_ctx, _args):
1497 return 1
1498
1499def aliasCmd(ctx, args):
1500 if (len(args) == 3):
1501 aliases[args[1]] = args[2]
1502 return 0
1503
1504 for (key, value) in aliases.items():
1505 print "'%s' is an alias for '%s'" % (key, value)
1506 return 0
1507
1508def verboseCmd(ctx, args):
1509 global g_fVerbose
1510 if (len(args) > 1):
1511 g_fVerbose = (args[1]=='on')
1512 else:
1513 g_fVerbose = not g_fVerbose
1514 return 0
1515
1516def colorsCmd(ctx, args):
1517 global g_fHasColors
1518 if (len(args) > 1):
1519 g_fHasColors = (args[1] == 'on')
1520 else:
1521 g_fHasColors = not g_fHasColors
1522 return 0
1523
1524def hostCmd(ctx, args):
1525 vbox = ctx['vb']
1526 try:
1527 print "VirtualBox version %s" % (colored(vbox.version, 'blue'))
1528 except Exception, e:
1529 printErr(ctx, e)
1530 if g_fVerbose:
1531 traceback.print_exc()
1532 props = vbox.systemProperties
1533 print "Machines: %s" % (colPath(ctx, props.defaultMachineFolder))
1534
1535 #print "Global shared folders:"
1536 #for ud in ctx['global'].getArray(vbox, 'sharedFolders'):
1537 # printSf(ctx, sf)
1538 host = vbox.host
1539 cnt = host.processorCount
1540 print colCat(ctx, "Processors:")
1541 print " available/online: %d/%d " % (cnt, host.processorOnlineCount)
1542 for i in range(0, cnt):
1543 print " processor #%d speed: %dMHz %s" % (i, host.getProcessorSpeed(i), host.getProcessorDescription(i))
1544
1545 print colCat(ctx, "RAM:")
1546 print " %dM (free %dM)" % (host.memorySize, host.memoryAvailable)
1547 print colCat(ctx, "OS:")
1548 print " %s (%s)" % (host.operatingSystem, host.OSVersion)
1549 if host.acceleration3DAvailable:
1550 print colCat(ctx, "3D acceleration available")
1551 else:
1552 print colCat(ctx, "3D acceleration NOT available")
1553
1554 print colCat(ctx, "Network interfaces:")
1555 for ni in ctx['global'].getArray(host, 'networkInterfaces'):
1556 print " %s (%s)" % (ni.name, ni.IPAddress)
1557
1558 print colCat(ctx, "DVD drives:")
1559 for dd in ctx['global'].getArray(host, 'DVDDrives'):
1560 print " %s - %s" % (dd.name, dd.description)
1561
1562 print colCat(ctx, "Floppy drives:")
1563 for dd in ctx['global'].getArray(host, 'floppyDrives'):
1564 print " %s - %s" % (dd.name, dd.description)
1565
1566 print colCat(ctx, "USB devices:")
1567 for ud in ctx['global'].getArray(host, 'USBDevices'):
1568 printHostUsbDev(ctx, ud)
1569
1570 if ctx['perf']:
1571 for metric in ctx['perf'].query(["*"], [host]):
1572 print metric['name'], metric['values_as_string']
1573
1574 return 0
1575
1576def monitorGuestCmd(ctx, args):
1577 if (len(args) < 2):
1578 print "usage: monitorGuest name (duration)"
1579 return 0
1580 mach = argsToMach(ctx, args)
1581 if mach == None:
1582 return 0
1583 dur = 5
1584 if len(args) > 2:
1585 dur = float(args[2])
1586 active = False
1587 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: monitorSource(ctx, console.eventSource, active, dur)])
1588 return 0
1589
1590def monitorGuestKbdCmd(ctx, args):
1591 if (len(args) < 2):
1592 print "usage: monitorGuestKbd name (duration)"
1593 return 0
1594 mach = argsToMach(ctx, args)
1595 if mach == None:
1596 return 0
1597 dur = 5
1598 if len(args) > 2:
1599 dur = float(args[2])
1600 active = False
1601 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: monitorSource(ctx, console.keyboard.eventSource, active, dur)])
1602 return 0
1603
1604def monitorGuestMouseCmd(ctx, args):
1605 if (len(args) < 2):
1606 print "usage: monitorGuestMouse name (duration)"
1607 return 0
1608 mach = argsToMach(ctx, args)
1609 if mach == None:
1610 return 0
1611 dur = 5
1612 if len(args) > 2:
1613 dur = float(args[2])
1614 active = False
1615 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: monitorSource(ctx, console.mouse.eventSource, active, dur)])
1616 return 0
1617
1618def monitorGuestMultiTouchCmd(ctx, args):
1619 if (len(args) < 2):
1620 print "usage: monitorGuestMultiTouch name (duration)"
1621 return 0
1622 mach = argsToMach(ctx, args)
1623 if mach == None:
1624 return 0
1625 dur = 5
1626 if len(args) > 2:
1627 dur = float(args[2])
1628 active = False
1629 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: monitorSource(ctx, console.mouse.eventSource, active, dur)])
1630 return 0
1631
1632def monitorVBoxCmd(ctx, args):
1633 if (len(args) > 2):
1634 print "usage: monitorVBox (duration)"
1635 return 0
1636 dur = 5
1637 if len(args) > 1:
1638 dur = float(args[1])
1639 vbox = ctx['vb']
1640 active = False
1641 monitorSource(ctx, vbox.eventSource, active, dur)
1642 return 0
1643
1644def getAdapterType(ctx, natype):
1645 if (natype == ctx['global'].constants.NetworkAdapterType_Am79C970A or
1646 natype == ctx['global'].constants.NetworkAdapterType_Am79C973):
1647 return "pcnet"
1648 elif (natype == ctx['global'].constants.NetworkAdapterType_I82540EM or
1649 natype == ctx['global'].constants.NetworkAdapterType_I82545EM or
1650 natype == ctx['global'].constants.NetworkAdapterType_I82543GC):
1651 return "e1000"
1652 elif (natype == ctx['global'].constants.NetworkAdapterType_Virtio):
1653 return "virtio"
1654 elif (natype == ctx['global'].constants.NetworkAdapterType_Null):
1655 return None
1656 else:
1657 raise Exception("Unknown adapter type: "+natype)
1658
1659
1660def portForwardCmd(ctx, args):
1661 if (len(args) != 5):
1662 print "usage: portForward <vm> <adapter> <hostPort> <guestPort>"
1663 return 0
1664 mach = argsToMach(ctx, args)
1665 if mach == None:
1666 return 0
1667 adapterNum = int(args[2])
1668 hostPort = int(args[3])
1669 guestPort = int(args[4])
1670 proto = "TCP"
1671 session = ctx['global'].openMachineSession(mach)
1672 mach = session.machine
1673
1674 adapter = mach.getNetworkAdapter(adapterNum)
1675 adapterType = getAdapterType(ctx, adapter.adapterType)
1676
1677 profile_name = proto+"_"+str(hostPort)+"_"+str(guestPort)
1678 config = "VBoxInternal/Devices/" + adapterType + "/"
1679 config = config + str(adapter.slot) +"/LUN#0/Config/" + profile_name
1680
1681 mach.setExtraData(config + "/Protocol", proto)
1682 mach.setExtraData(config + "/HostPort", str(hostPort))
1683 mach.setExtraData(config + "/GuestPort", str(guestPort))
1684
1685 mach.saveSettings()
1686 session.unlockMachine()
1687
1688 return 0
1689
1690
1691def showLogCmd(ctx, args):
1692 if (len(args) < 2):
1693 print "usage: showLog vm <num>"
1694 return 0
1695 mach = argsToMach(ctx, args)
1696 if mach == None:
1697 return 0
1698
1699 log = 0
1700 if (len(args) > 2):
1701 log = args[2]
1702
1703 uOffset = 0
1704 while True:
1705 data = mach.readLog(log, uOffset, 4096)
1706 if (len(data) == 0):
1707 break
1708 # print adds either NL or space to chunks not ending with a NL
1709 sys.stdout.write(str(data))
1710 uOffset += len(data)
1711
1712 return 0
1713
1714def findLogCmd(ctx, args):
1715 if (len(args) < 3):
1716 print "usage: findLog vm pattern <num>"
1717 return 0
1718 mach = argsToMach(ctx, args)
1719 if mach == None:
1720 return 0
1721
1722 log = 0
1723 if (len(args) > 3):
1724 log = args[3]
1725
1726 pattern = args[2]
1727 uOffset = 0
1728 while True:
1729 # to reduce line splits on buffer boundary
1730 data = mach.readLog(log, uOffset, 512*1024)
1731 if (len(data) == 0):
1732 break
1733 d = str(data).split("\n")
1734 for s in d:
1735 match = re.findall(pattern, s)
1736 if len(match) > 0:
1737 for mt in match:
1738 s = s.replace(mt, colored(mt, 'red'))
1739 print s
1740 uOffset += len(data)
1741
1742 return 0
1743
1744
1745def findAssertCmd(ctx, args):
1746 if (len(args) < 2):
1747 print "usage: findAssert vm <num>"
1748 return 0
1749 mach = argsToMach(ctx, args)
1750 if mach == None:
1751 return 0
1752
1753 log = 0
1754 if (len(args) > 2):
1755 log = args[2]
1756
1757 uOffset = 0
1758 ere = re.compile(r'(Expression:|\!\!\!\!\!\!)')
1759 active = False
1760 context = 0
1761 while True:
1762 # to reduce line splits on buffer boundary
1763 data = mach.readLog(log, uOffset, 512*1024)
1764 if (len(data) == 0):
1765 break
1766 d = str(data).split("\n")
1767 for s in d:
1768 if active:
1769 print s
1770 if context == 0:
1771 active = False
1772 else:
1773 context = context - 1
1774 continue
1775 match = ere.findall(s)
1776 if len(match) > 0:
1777 active = True
1778 context = 50
1779 print s
1780 uOffset += len(data)
1781
1782 return 0
1783
1784def evalCmd(ctx, args):
1785 expr = ' '.join(args[1:])
1786 try:
1787 exec expr
1788 except Exception, e:
1789 printErr(ctx, e)
1790 if g_fVerbose:
1791 traceback.print_exc()
1792 return 0
1793
1794def reloadExtCmd(ctx, args):
1795 # maybe will want more args smartness
1796 checkUserExtensions(ctx, commands, getHomeFolder(ctx))
1797 autoCompletion(commands, ctx)
1798 return 0
1799
1800def runScriptCmd(ctx, args):
1801 if (len(args) != 2):
1802 print "usage: runScript <script>"
1803 return 0
1804 try:
1805 lf = open(args[1], 'r')
1806 except IOError, e:
1807 print "cannot open:", args[1], ":", e
1808 return 0
1809
1810 try:
1811 lines = lf.readlines()
1812 ctx['scriptLine'] = 0
1813 ctx['interrupt'] = False
1814 while ctx['scriptLine'] < len(lines):
1815 line = lines[ctx['scriptLine']]
1816 ctx['scriptLine'] = ctx['scriptLine'] + 1
1817 done = runCommand(ctx, line)
1818 if done != 0 or ctx['interrupt']:
1819 break
1820
1821 except Exception, e:
1822 printErr(ctx, e)
1823 if g_fVerbose:
1824 traceback.print_exc()
1825 lf.close()
1826 return 0
1827
1828def sleepCmd(ctx, args):
1829 if (len(args) != 2):
1830 print "usage: sleep <secs>"
1831 return 0
1832
1833 try:
1834 time.sleep(float(args[1]))
1835 except:
1836 # to allow sleep interrupt
1837 pass
1838 return 0
1839
1840
1841def shellCmd(ctx, args):
1842 if (len(args) < 2):
1843 print "usage: shell <commands>"
1844 return 0
1845 cmd = ' '.join(args[1:])
1846
1847 try:
1848 os.system(cmd)
1849 except KeyboardInterrupt:
1850 # to allow shell command interruption
1851 pass
1852 return 0
1853
1854
1855def connectCmd(ctx, args):
1856 if (len(args) > 4):
1857 print "usage: connect url <username> <passwd>"
1858 return 0
1859
1860 if ctx['vb'] is not None:
1861 print "Already connected, disconnect first..."
1862 return 0
1863
1864 if (len(args) > 1):
1865 url = args[1]
1866 else:
1867 url = None
1868
1869 if (len(args) > 2):
1870 user = args[2]
1871 else:
1872 user = ""
1873
1874 if (len(args) > 3):
1875 passwd = args[3]
1876 else:
1877 passwd = ""
1878
1879 ctx['wsinfo'] = [url, user, passwd]
1880 vbox = ctx['global'].platform.connect(url, user, passwd)
1881 ctx['vb'] = vbox
1882 try:
1883 print "Running VirtualBox version %s" % (vbox.version)
1884 except Exception, e:
1885 printErr(ctx, e)
1886 if g_fVerbose:
1887 traceback.print_exc()
1888 ctx['perf'] = ctx['global'].getPerfCollector(ctx['vb'])
1889 return 0
1890
1891def disconnectCmd(ctx, args):
1892 if (len(args) != 1):
1893 print "usage: disconnect"
1894 return 0
1895
1896 if ctx['vb'] is None:
1897 print "Not connected yet."
1898 return 0
1899
1900 try:
1901 ctx['global'].platform.disconnect()
1902 except:
1903 ctx['vb'] = None
1904 raise
1905
1906 ctx['vb'] = None
1907 return 0
1908
1909def reconnectCmd(ctx, args):
1910 if ctx['wsinfo'] is None:
1911 print "Never connected..."
1912 return 0
1913
1914 try:
1915 ctx['global'].platform.disconnect()
1916 except:
1917 pass
1918
1919 [url, user, passwd] = ctx['wsinfo']
1920 ctx['vb'] = ctx['global'].platform.connect(url, user, passwd)
1921 try:
1922 print "Running VirtualBox version %s" % (ctx['vb'].version)
1923 except Exception, e:
1924 printErr(ctx, e)
1925 if g_fVerbose:
1926 traceback.print_exc()
1927 return 0
1928
1929def exportVMCmd(ctx, args):
1930 if len(args) < 3:
1931 print "usage: exportVm <machine> <path> <format> <license>"
1932 return 0
1933 mach = argsToMach(ctx, args)
1934 if mach is None:
1935 return 0
1936 path = args[2]
1937 if (len(args) > 3):
1938 fmt = args[3]
1939 else:
1940 fmt = "ovf-1.0"
1941 if (len(args) > 4):
1942 lic = args[4]
1943 else:
1944 lic = "GPL"
1945
1946 app = ctx['vb'].createAppliance()
1947 desc = mach.export(app)
1948 desc.addDescription(ctx['global'].constants.VirtualSystemDescriptionType_License, lic, "")
1949 progress = app.write(fmt, path)
1950 if (progressBar(ctx, progress) and int(progress.resultCode) == 0):
1951 print "Exported to %s in format %s" % (path, fmt)
1952 else:
1953 reportError(ctx, progress)
1954 return 0
1955
1956# PC XT scancodes
1957scancodes = {
1958 'a': 0x1e,
1959 'b': 0x30,
1960 'c': 0x2e,
1961 'd': 0x20,
1962 'e': 0x12,
1963 'f': 0x21,
1964 'g': 0x22,
1965 'h': 0x23,
1966 'i': 0x17,
1967 'j': 0x24,
1968 'k': 0x25,
1969 'l': 0x26,
1970 'm': 0x32,
1971 'n': 0x31,
1972 'o': 0x18,
1973 'p': 0x19,
1974 'q': 0x10,
1975 'r': 0x13,
1976 's': 0x1f,
1977 't': 0x14,
1978 'u': 0x16,
1979 'v': 0x2f,
1980 'w': 0x11,
1981 'x': 0x2d,
1982 'y': 0x15,
1983 'z': 0x2c,
1984 '0': 0x0b,
1985 '1': 0x02,
1986 '2': 0x03,
1987 '3': 0x04,
1988 '4': 0x05,
1989 '5': 0x06,
1990 '6': 0x07,
1991 '7': 0x08,
1992 '8': 0x09,
1993 '9': 0x0a,
1994 ' ': 0x39,
1995 '-': 0xc,
1996 '=': 0xd,
1997 '[': 0x1a,
1998 ']': 0x1b,
1999 ';': 0x27,
2000 '\'': 0x28,
2001 ',': 0x33,
2002 '.': 0x34,
2003 '/': 0x35,
2004 '\t': 0xf,
2005 '\n': 0x1c,
2006 '`': 0x29
2007}
2008
2009extScancodes = {
2010 'ESC' : [0x01],
2011 'BKSP': [0xe],
2012 'SPACE': [0x39],
2013 'TAB': [0x0f],
2014 'CAPS': [0x3a],
2015 'ENTER': [0x1c],
2016 'LSHIFT': [0x2a],
2017 'RSHIFT': [0x36],
2018 'INS': [0xe0, 0x52],
2019 'DEL': [0xe0, 0x53],
2020 'END': [0xe0, 0x4f],
2021 'HOME': [0xe0, 0x47],
2022 'PGUP': [0xe0, 0x49],
2023 'PGDOWN': [0xe0, 0x51],
2024 'LGUI': [0xe0, 0x5b], # GUI, aka Win, aka Apple key
2025 'RGUI': [0xe0, 0x5c],
2026 'LCTR': [0x1d],
2027 'RCTR': [0xe0, 0x1d],
2028 'LALT': [0x38],
2029 'RALT': [0xe0, 0x38],
2030 'APPS': [0xe0, 0x5d],
2031 'F1': [0x3b],
2032 'F2': [0x3c],
2033 'F3': [0x3d],
2034 'F4': [0x3e],
2035 'F5': [0x3f],
2036 'F6': [0x40],
2037 'F7': [0x41],
2038 'F8': [0x42],
2039 'F9': [0x43],
2040 'F10': [0x44 ],
2041 'F11': [0x57],
2042 'F12': [0x58],
2043 'UP': [0xe0, 0x48],
2044 'LEFT': [0xe0, 0x4b],
2045 'DOWN': [0xe0, 0x50],
2046 'RIGHT': [0xe0, 0x4d],
2047}
2048
2049def keyDown(ch):
2050 code = scancodes.get(ch, 0x0)
2051 if code != 0:
2052 return [code]
2053 extCode = extScancodes.get(ch, [])
2054 if len(extCode) == 0:
2055 print "bad ext", ch
2056 return extCode
2057
2058def keyUp(ch):
2059 codes = keyDown(ch)[:] # make a copy
2060 if len(codes) > 0:
2061 codes[len(codes)-1] += 0x80
2062 return codes
2063
2064def typeInGuest(console, text, delay):
2065 pressed = []
2066 group = False
2067 modGroupEnd = True
2068 i = 0
2069 kbd = console.keyboard
2070 while i < len(text):
2071 ch = text[i]
2072 i = i+1
2073 if ch == '{':
2074 # start group, all keys to be pressed at the same time
2075 group = True
2076 continue
2077 if ch == '}':
2078 # end group, release all keys
2079 for c in pressed:
2080 kbd.putScancodes(keyUp(c))
2081 pressed = []
2082 group = False
2083 continue
2084 if ch == 'W':
2085 # just wait a bit
2086 time.sleep(0.3)
2087 continue
2088 if ch == '^' or ch == '|' or ch == '$' or ch == '_':
2089 if ch == '^':
2090 ch = 'LCTR'
2091 if ch == '|':
2092 ch = 'LSHIFT'
2093 if ch == '_':
2094 ch = 'LALT'
2095 if ch == '$':
2096 ch = 'LGUI'
2097 if not group:
2098 modGroupEnd = False
2099 else:
2100 if ch == '\\':
2101 if i < len(text):
2102 ch = text[i]
2103 i = i+1
2104 if ch == 'n':
2105 ch = '\n'
2106 elif ch == '&':
2107 combo = ""
2108 while i < len(text):
2109 ch = text[i]
2110 i = i+1
2111 if ch == ';':
2112 break
2113 combo += ch
2114 ch = combo
2115 modGroupEnd = True
2116 kbd.putScancodes(keyDown(ch))
2117 pressed.insert(0, ch)
2118 if not group and modGroupEnd:
2119 for c in pressed:
2120 kbd.putScancodes(keyUp(c))
2121 pressed = []
2122 modGroupEnd = True
2123 time.sleep(delay)
2124
2125def typeGuestCmd(ctx, args):
2126 if len(args) < 3:
2127 print "usage: typeGuest <machine> <text> <charDelay>"
2128 return 0
2129 mach = argsToMach(ctx, args)
2130 if mach is None:
2131 return 0
2132
2133 text = args[2]
2134
2135 if len(args) > 3:
2136 delay = float(args[3])
2137 else:
2138 delay = 0.1
2139
2140 gargs = [lambda ctx, mach, console, args: typeInGuest(console, text, delay)]
2141 cmdExistingVm(ctx, mach, 'guestlambda', gargs)
2142
2143 return 0
2144
2145def optId(verbose, uuid):
2146 if verbose:
2147 return ": "+uuid
2148 else:
2149 return ""
2150
2151def asSize(val, inBytes):
2152 if inBytes:
2153 return int(val)/(1024*1024)
2154 else:
2155 return int(val)
2156
2157def listMediaCmd(ctx, args):
2158 if len(args) > 1:
2159 verbose = int(args[1])
2160 else:
2161 verbose = False
2162 hdds = ctx['global'].getArray(ctx['vb'], 'hardDisks')
2163 print colCat(ctx, "Hard disks:")
2164 for hdd in hdds:
2165 if hdd.state != ctx['global'].constants.MediumState_Created:
2166 hdd.refreshState()
2167 print " %s (%s)%s %s [logical %s]" % (colPath(ctx, hdd.location), hdd.format, optId(verbose, hdd.id), colSizeM(ctx, asSize(hdd.size, True)), colSizeM(ctx, asSize(hdd.logicalSize, True)))
2168
2169 dvds = ctx['global'].getArray(ctx['vb'], 'DVDImages')
2170 print colCat(ctx, "CD/DVD disks:")
2171 for dvd in dvds:
2172 if dvd.state != ctx['global'].constants.MediumState_Created:
2173 dvd.refreshState()
2174 print " %s (%s)%s %s" % (colPath(ctx, dvd.location), dvd.format, optId(verbose, dvd.id), colSizeM(ctx, asSize(dvd.size, True)))
2175
2176 floppys = ctx['global'].getArray(ctx['vb'], 'floppyImages')
2177 print colCat(ctx, "Floppy disks:")
2178 for floppy in floppys:
2179 if floppy.state != ctx['global'].constants.MediumState_Created:
2180 floppy.refreshState()
2181 print " %s (%s)%s %s" % (colPath(ctx, floppy.location), floppy.format, optId(verbose, floppy.id), colSizeM(ctx, asSize(floppy.size, True)))
2182
2183 return 0
2184
2185def listUsbCmd(ctx, args):
2186 if (len(args) > 1):
2187 print "usage: listUsb"
2188 return 0
2189
2190 host = ctx['vb'].host
2191 for ud in ctx['global'].getArray(host, 'USBDevices'):
2192 printHostUsbDev(ctx, ud)
2193
2194 return 0
2195
2196def findDevOfType(ctx, mach, devtype):
2197 atts = ctx['global'].getArray(mach, 'mediumAttachments')
2198 for a in atts:
2199 if a.type == devtype:
2200 return [a.controller, a.port, a.device]
2201 return [None, 0, 0]
2202
2203def createHddCmd(ctx, args):
2204 if (len(args) < 3):
2205 print "usage: createHdd sizeM location type"
2206 return 0
2207
2208 size = int(args[1])
2209 loc = args[2]
2210 if len(args) > 3:
2211 fmt = args[3]
2212 else:
2213 fmt = "vdi"
2214
2215 hdd = ctx['vb'].createMedium(format, loc, ctx['global'].constants.AccessMode_ReadWrite, ctx['global'].constants.DeviceType_HardDisk)
2216 progress = hdd.createBaseStorage(size, (ctx['global'].constants.MediumVariant_Standard, ))
2217 if progressBar(ctx,progress) and hdd.id:
2218 print "created HDD at %s as %s" % (colPath(ctx,hdd.location), hdd.id)
2219 else:
2220 print "cannot create disk (file %s exist?)" % (loc)
2221 reportError(ctx,progress)
2222 return 0
2223
2224 return 0
2225
2226def registerHddCmd(ctx, args):
2227 if (len(args) < 2):
2228 print "usage: registerHdd location"
2229 return 0
2230
2231 vbox = ctx['vb']
2232 loc = args[1]
2233 setImageId = False
2234 imageId = ""
2235 setParentId = False
2236 parentId = ""
2237 hdd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_HardDisk, ctx['global'].constants.AccessMode_ReadWrite, false)
2238 print "registered HDD as %s" % (hdd.id)
2239 return 0
2240
2241def controldevice(ctx, mach, args):
2242 [ctr, port, slot, devtype, uuid] = args
2243 mach.attachDevice(ctr, port, slot, devtype, uuid)
2244
2245def attachHddCmd(ctx, args):
2246 if (len(args) < 3):
2247 print "usage: attachHdd vm hdd controller port:slot"
2248 return 0
2249
2250 mach = argsToMach(ctx, args)
2251 if mach is None:
2252 return 0
2253 vbox = ctx['vb']
2254 loc = args[2]
2255 try:
2256 hdd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_HardDisk, ctx['global'].constants.AccessMode_ReadWrite, false)
2257 except:
2258 print "no HDD with path %s registered" % (loc)
2259 return 0
2260 if len(args) > 3:
2261 ctr = args[3]
2262 (port, slot) = args[4].split(":")
2263 else:
2264 [ctr, port, slot] = findDevOfType(ctx, mach, ctx['global'].constants.DeviceType_HardDisk)
2265
2266 cmdClosedVm(ctx, mach, lambda ctx, mach, args: mach.attachDevice(ctr, port, slot, ctx['global'].constants.DeviceType_HardDisk, hdd.id))
2267 return 0
2268
2269def detachVmDevice(ctx, mach, args):
2270 atts = ctx['global'].getArray(mach, 'mediumAttachments')
2271 hid = args[0]
2272 for a in atts:
2273 if a.medium:
2274 if hid == "ALL" or a.medium.id == hid:
2275 mach.detachDevice(a.controller, a.port, a.device)
2276
2277def detachMedium(ctx, mid, medium):
2278 cmdClosedVm(ctx, machById(ctx, mid), detachVmDevice, [medium])
2279
2280def detachHddCmd(ctx, args):
2281 if (len(args) < 3):
2282 print "usage: detachHdd vm hdd"
2283 return 0
2284
2285 mach = argsToMach(ctx, args)
2286 if mach is None:
2287 return 0
2288 vbox = ctx['vb']
2289 loc = args[2]
2290 try:
2291 hdd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_HardDisk, ctx['global'].constants.AccessMode_ReadWrite, false)
2292 except:
2293 print "no HDD with path %s registered" % (loc)
2294 return 0
2295
2296 detachMedium(ctx, mach.id, hdd)
2297 return 0
2298
2299def unregisterHddCmd(ctx, args):
2300 if (len(args) < 2):
2301 print "usage: unregisterHdd path <vmunreg>"
2302 return 0
2303
2304 vbox = ctx['vb']
2305 loc = args[1]
2306 if (len(args) > 2):
2307 vmunreg = int(args[2])
2308 else:
2309 vmunreg = 0
2310 try:
2311 hdd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_HardDisk, ctx['global'].constants.AccessMode_ReadWrite, false)
2312 except:
2313 print "no HDD with path %s registered" % (loc)
2314 return 0
2315
2316 if vmunreg != 0:
2317 machs = ctx['global'].getArray(hdd, 'machineIds')
2318 try:
2319 for mach in machs:
2320 print "Trying to detach from %s" % (mach)
2321 detachMedium(ctx, mach, hdd)
2322 except Exception, e:
2323 print 'failed: ', e
2324 return 0
2325 hdd.close()
2326 return 0
2327
2328def removeHddCmd(ctx, args):
2329 if (len(args) != 2):
2330 print "usage: removeHdd path"
2331 return 0
2332
2333 vbox = ctx['vb']
2334 loc = args[1]
2335 try:
2336 hdd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_HardDisk, ctx['global'].constants.AccessMode_ReadWrite, false)
2337 except:
2338 print "no HDD with path %s registered" % (loc)
2339 return 0
2340
2341 progress = hdd.deleteStorage()
2342 progressBar(ctx, progress)
2343
2344 return 0
2345
2346def registerIsoCmd(ctx, args):
2347 if (len(args) < 2):
2348 print "usage: registerIso location"
2349 return 0
2350
2351 vbox = ctx['vb']
2352 loc = args[1]
2353 iso = vbox.openMedium(loc, ctx['global'].constants.DeviceType_DVD, ctx['global'].constants.AccessMode_ReadOnly, false)
2354 print "registered ISO as %s" % (iso.id)
2355 return 0
2356
2357def unregisterIsoCmd(ctx, args):
2358 if (len(args) != 2):
2359 print "usage: unregisterIso path"
2360 return 0
2361
2362 vbox = ctx['vb']
2363 loc = args[1]
2364 try:
2365 dvd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_DVD, ctx['global'].constants.AccessMode_ReadOnly, false)
2366 except:
2367 print "no DVD with path %s registered" % (loc)
2368 return 0
2369
2370 progress = dvd.close()
2371 print "Unregistered ISO at %s" % (colPath(ctx, loc))
2372
2373 return 0
2374
2375def removeIsoCmd(ctx, args):
2376 if (len(args) != 2):
2377 print "usage: removeIso path"
2378 return 0
2379
2380 vbox = ctx['vb']
2381 loc = args[1]
2382 try:
2383 dvd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_DVD, ctx['global'].constants.AccessMode_ReadOnly, false)
2384 except:
2385 print "no DVD with path %s registered" % (loc)
2386 return 0
2387
2388 progress = dvd.deleteStorage()
2389 if progressBar(ctx, progress):
2390 print "Removed ISO at %s" % (colPath(ctx, dvd.location))
2391 else:
2392 reportError(ctx, progress)
2393 return 0
2394
2395def attachIsoCmd(ctx, args):
2396 if (len(args) < 3):
2397 print "usage: attachIso vm iso controller port:slot"
2398 return 0
2399
2400 mach = argsToMach(ctx, args)
2401 if mach is None:
2402 return 0
2403 vbox = ctx['vb']
2404 loc = args[2]
2405 try:
2406 dvd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_DVD, ctx['global'].constants.AccessMode_ReadOnly, false)
2407 except:
2408 print "no DVD with path %s registered" % (loc)
2409 return 0
2410 if len(args) > 3:
2411 ctr = args[3]
2412 (port, slot) = args[4].split(":")
2413 else:
2414 [ctr, port, slot] = findDevOfType(ctx, mach, ctx['global'].constants.DeviceType_DVD)
2415 cmdClosedVm(ctx, mach, lambda ctx, mach, args: mach.attachDevice(ctr, port, slot, ctx['global'].constants.DeviceType_DVD, dvd))
2416 return 0
2417
2418def detachIsoCmd(ctx, args):
2419 if (len(args) < 3):
2420 print "usage: detachIso vm iso"
2421 return 0
2422
2423 mach = argsToMach(ctx, args)
2424 if mach is None:
2425 return 0
2426 vbox = ctx['vb']
2427 loc = args[2]
2428 try:
2429 dvd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_DVD, ctx['global'].constants.AccessMode_ReadOnly, false)
2430 except:
2431 print "no DVD with path %s registered" % (loc)
2432 return 0
2433
2434 detachMedium(ctx, mach.id, dvd)
2435 return 0
2436
2437def mountIsoCmd(ctx, args):
2438 if (len(args) < 3):
2439 print "usage: mountIso vm iso controller port:slot"
2440 return 0
2441
2442 mach = argsToMach(ctx, args)
2443 if mach is None:
2444 return 0
2445 vbox = ctx['vb']
2446 loc = args[2]
2447 try:
2448 dvd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_DVD, ctx['global'].constants.AccessMode_ReadOnly, false)
2449 except:
2450 print "no DVD with path %s registered" % (loc)
2451 return 0
2452
2453 if len(args) > 3:
2454 ctr = args[3]
2455 (port, slot) = args[4].split(":")
2456 else:
2457 # autodetect controller and location, just find first controller with media == DVD
2458 [ctr, port, slot] = findDevOfType(ctx, mach, ctx['global'].constants.DeviceType_DVD)
2459
2460 cmdExistingVm(ctx, mach, 'mountiso', [ctr, port, slot, dvd, True])
2461
2462 return 0
2463
2464def unmountIsoCmd(ctx, args):
2465 if (len(args) < 2):
2466 print "usage: unmountIso vm controller port:slot"
2467 return 0
2468
2469 mach = argsToMach(ctx, args)
2470 if mach is None:
2471 return 0
2472 vbox = ctx['vb']
2473
2474 if len(args) > 3:
2475 ctr = args[2]
2476 (port, slot) = args[3].split(":")
2477 else:
2478 # autodetect controller and location, just find first controller with media == DVD
2479 [ctr, port, slot] = findDevOfType(ctx, mach, ctx['global'].constants.DeviceType_DVD)
2480
2481 cmdExistingVm(ctx, mach, 'mountiso', [ctr, port, slot, None, True])
2482
2483 return 0
2484
2485def attachCtr(ctx, mach, args):
2486 [name, bus, ctrltype] = args
2487 ctr = mach.addStorageController(name, bus)
2488 if ctrltype != None:
2489 ctr.controllerType = ctrltype
2490
2491def attachCtrCmd(ctx, args):
2492 if (len(args) < 4):
2493 print "usage: attachCtr vm cname bus <type>"
2494 return 0
2495
2496 if len(args) > 4:
2497 ctrltype = enumFromString(ctx, 'StorageControllerType', args[4])
2498 if ctrltype == None:
2499 print "Controller type %s unknown" % (args[4])
2500 return 0
2501 else:
2502 ctrltype = None
2503
2504 mach = argsToMach(ctx, args)
2505 if mach is None:
2506 return 0
2507 bus = enumFromString(ctx, 'StorageBus', args[3])
2508 if bus is None:
2509 print "Bus type %s unknown" % (args[3])
2510 return 0
2511 name = args[2]
2512 cmdClosedVm(ctx, mach, attachCtr, [name, bus, ctrltype])
2513 return 0
2514
2515def detachCtrCmd(ctx, args):
2516 if (len(args) < 3):
2517 print "usage: detachCtr vm name"
2518 return 0
2519
2520 mach = argsToMach(ctx, args)
2521 if mach is None:
2522 return 0
2523 ctr = args[2]
2524 cmdClosedVm(ctx, mach, lambda ctx, mach, args: mach.removeStorageController(ctr))
2525 return 0
2526
2527def usbctr(ctx, mach, console, args):
2528 if (args[0]):
2529 console.attachUSBDevice(args[1])
2530 else:
2531 console.detachUSBDevice(args[1])
2532
2533def attachUsbCmd(ctx, args):
2534 if (len(args) < 3):
2535 print "usage: attachUsb vm deviceuid"
2536 return 0
2537
2538 mach = argsToMach(ctx, args)
2539 if mach is None:
2540 return 0
2541 dev = args[2]
2542 cmdExistingVm(ctx, mach, 'guestlambda', [usbctr, True, dev])
2543 return 0
2544
2545def detachUsbCmd(ctx, args):
2546 if (len(args) < 3):
2547 print "usage: detachUsb vm deviceuid"
2548 return 0
2549
2550 mach = argsToMach(ctx, args)
2551 if mach is None:
2552 return 0
2553 dev = args[2]
2554 cmdExistingVm(ctx, mach, 'guestlambda', [usbctr, False, dev])
2555 return 0
2556
2557
2558def guiCmd(ctx, args):
2559 if (len(args) > 1):
2560 print "usage: gui"
2561 return 0
2562
2563 binDir = ctx['global'].getBinDir()
2564
2565 vbox = os.path.join(binDir, 'VirtualBox')
2566 try:
2567 os.system(vbox)
2568 except KeyboardInterrupt:
2569 # to allow interruption
2570 pass
2571 return 0
2572
2573def shareFolderCmd(ctx, args):
2574 if (len(args) < 4):
2575 print "usage: shareFolder vm path name <writable> <persistent>"
2576 return 0
2577
2578 mach = argsToMach(ctx, args)
2579 if mach is None:
2580 return 0
2581 path = args[2]
2582 name = args[3]
2583 writable = False
2584 persistent = False
2585 if len(args) > 4:
2586 for a in args[4:]:
2587 if a == 'writable':
2588 writable = True
2589 if a == 'persistent':
2590 persistent = True
2591 if persistent:
2592 cmdClosedVm(ctx, mach, lambda ctx, mach, args: mach.createSharedFolder(name, path, writable), [])
2593 else:
2594 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: console.createSharedFolder(name, path, writable)])
2595 return 0
2596
2597def unshareFolderCmd(ctx, args):
2598 if (len(args) < 3):
2599 print "usage: unshareFolder vm name"
2600 return 0
2601
2602 mach = argsToMach(ctx, args)
2603 if mach is None:
2604 return 0
2605 name = args[2]
2606 found = False
2607 for sf in ctx['global'].getArray(mach, 'sharedFolders'):
2608 if sf.name == name:
2609 cmdClosedVm(ctx, mach, lambda ctx, mach, args: mach.removeSharedFolder(name), [])
2610 found = True
2611 break
2612 if not found:
2613 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: console.removeSharedFolder(name)])
2614 return 0
2615
2616
2617def snapshotCmd(ctx, args):
2618 if (len(args) < 2 or args[1] == 'help'):
2619 print "Take snapshot: snapshot vm take name <description>"
2620 print "Restore snapshot: snapshot vm restore name"
2621 print "Merge snapshot: snapshot vm merge name"
2622 return 0
2623
2624 mach = argsToMach(ctx, args)
2625 if mach is None:
2626 return 0
2627 cmd = args[2]
2628 if cmd == 'take':
2629 if (len(args) < 4):
2630 print "usage: snapshot vm take name <description>"
2631 return 0
2632 name = args[3]
2633 if (len(args) > 4):
2634 desc = args[4]
2635 else:
2636 desc = ""
2637 cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, mach.takeSnapshot(name, desc, true)))
2638 return 0
2639
2640 if cmd == 'restore':
2641 if (len(args) < 4):
2642 print "usage: snapshot vm restore name"
2643 return 0
2644 name = args[3]
2645 snap = mach.findSnapshot(name)
2646 cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, mach.restoreSnapshot(snap)))
2647 return 0
2648
2649 if cmd == 'restorecurrent':
2650 if (len(args) < 4):
2651 print "usage: snapshot vm restorecurrent"
2652 return 0
2653 snap = mach.currentSnapshot()
2654 cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, mach.restoreSnapshot(snap)))
2655 return 0
2656
2657 if cmd == 'delete':
2658 if (len(args) < 4):
2659 print "usage: snapshot vm delete name"
2660 return 0
2661 name = args[3]
2662 snap = mach.findSnapshot(name)
2663 cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, mach.deleteSnapshot(snap.id)))
2664 return 0
2665
2666 print "Command '%s' is unknown" % (cmd)
2667 return 0
2668
2669def natAlias(ctx, mach, nicnum, nat, args=[]):
2670 """This command shows/alters NAT's alias settings.
2671 usage: nat <vm> <nicnum> alias [default|[log] [proxyonly] [sameports]]
2672 default - set settings to default values
2673 log - switch on alias logging
2674 proxyonly - switch proxyonly mode on
2675 sameports - enforces NAT using the same ports
2676 """
2677 alias = {
2678 'log': 0x1,
2679 'proxyonly': 0x2,
2680 'sameports': 0x4
2681 }
2682 if len(args) == 1:
2683 first = 0
2684 msg = ''
2685 for aliasmode, aliaskey in alias.iteritems():
2686 if first == 0:
2687 first = 1
2688 else:
2689 msg += ', '
2690 if int(nat.aliasMode) & aliaskey:
2691 msg += '%d: %s' % (aliasmode, 'on')
2692 else:
2693 msg += '%d: %s' % (aliasmode, 'off')
2694 msg += ')'
2695 return (0, [msg])
2696 else:
2697 nat.aliasMode = 0
2698 if 'default' not in args:
2699 for a in range(1, len(args)):
2700 if not alias.has_key(args[a]):
2701 print 'Invalid alias mode: ' + args[a]
2702 print natAlias.__doc__
2703 return (1, None)
2704 nat.aliasMode = int(nat.aliasMode) | alias[args[a]]
2705 return (0, None)
2706
2707def natSettings(ctx, mach, nicnum, nat, args):
2708 """This command shows/alters NAT settings.
2709 usage: nat <vm> <nicnum> settings [<mtu> [[<socsndbuf> <sockrcvbuf> [<tcpsndwnd> <tcprcvwnd>]]]]
2710 mtu - set mtu <= 16000
2711 socksndbuf/sockrcvbuf - sets amount of kb for socket sending/receiving buffer
2712 tcpsndwnd/tcprcvwnd - sets size of initial tcp sending/receiving window
2713 """
2714 if len(args) == 1:
2715 (mtu, socksndbuf, sockrcvbuf, tcpsndwnd, tcprcvwnd) = nat.getNetworkSettings()
2716 if mtu == 0: mtu = 1500
2717 if socksndbuf == 0: socksndbuf = 64
2718 if sockrcvbuf == 0: sockrcvbuf = 64
2719 if tcpsndwnd == 0: tcpsndwnd = 64
2720 if tcprcvwnd == 0: tcprcvwnd = 64
2721 msg = 'mtu:%s socket(snd:%s, rcv:%s) tcpwnd(snd:%s, rcv:%s)' % (mtu, socksndbuf, sockrcvbuf, tcpsndwnd, tcprcvwnd)
2722 return (0, [msg])
2723 else:
2724 if args[1] < 16000:
2725 print 'invalid mtu value (%s not in range [65 - 16000])' % (args[1])
2726 return (1, None)
2727 for i in range(2, len(args)):
2728 if not args[i].isdigit() or int(args[i]) < 8 or int(args[i]) > 1024:
2729 print 'invalid %s parameter (%i not in range [8-1024])' % (i, args[i])
2730 return (1, None)
2731 a = [args[1]]
2732 if len(args) < 6:
2733 for i in range(2, len(args)): a.append(args[i])
2734 for i in range(len(args), 6): a.append(0)
2735 else:
2736 for i in range(2, len(args)): a.append(args[i])
2737 #print a
2738 nat.setNetworkSettings(int(a[0]), int(a[1]), int(a[2]), int(a[3]), int(a[4]))
2739 return (0, None)
2740
2741def natDns(ctx, mach, nicnum, nat, args):
2742 """This command shows/alters DNS's NAT settings
2743 usage: nat <vm> <nicnum> dns [passdomain] [proxy] [usehostresolver]
2744 passdomain - enforces builtin DHCP server to pass domain
2745 proxy - switch on builtin NAT DNS proxying mechanism
2746 usehostresolver - proxies all DNS requests to Host Resolver interface
2747 """
2748 yesno = {0: 'off', 1: 'on'}
2749 if len(args) == 1:
2750 msg = 'passdomain:%s, proxy:%s, usehostresolver:%s' % (yesno[int(nat.DNSPassDomain)], yesno[int(nat.DNSProxy)], yesno[int(nat.DNSUseHostResolver)])
2751 return (0, [msg])
2752 else:
2753 nat.DNSPassDomain = 'passdomain' in args
2754 nat.DNSProxy = 'proxy' in args
2755 nat.DNSUseHostResolver = 'usehostresolver' in args
2756 return (0, None)
2757
2758def natTftp(ctx, mach, nicnum, nat, args):
2759 """This command shows/alters TFTP settings
2760 usage nat <vm> <nicnum> tftp [prefix <prefix>| bootfile <bootfile>| server <server>]
2761 prefix - alters prefix TFTP settings
2762 bootfile - alters bootfile TFTP settings
2763 server - sets booting server
2764 """
2765 if len(args) == 1:
2766 server = nat.TFTPNextServer
2767 if server is None:
2768 server = nat.network
2769 if server is None:
2770 server = '10.0.%d/24' % (int(nicnum) + 2)
2771 (server, mask) = server.split('/')
2772 while server.count('.') != 3:
2773 server += '.0'
2774 (a, b, c, d) = server.split('.')
2775 server = '%d.%d.%d.4' % (a, b, c)
2776 prefix = nat.TFTPPrefix
2777 if prefix is None:
2778 prefix = '%s/TFTP/' % (ctx['vb'].homeFolder)
2779 bootfile = nat.TFTPBootFile
2780 if bootfile is None:
2781 bootfile = '%s.pxe' % (mach.name)
2782 msg = 'server:%s, prefix:%s, bootfile:%s' % (server, prefix, bootfile)
2783 return (0, [msg])
2784 else:
2785
2786 cmd = args[1]
2787 if len(args) != 3:
2788 print 'invalid args:', args
2789 print natTftp.__doc__
2790 return (1, None)
2791 if cmd == 'prefix': nat.TFTPPrefix = args[2]
2792 elif cmd == 'bootfile': nat.TFTPBootFile = args[2]
2793 elif cmd == 'server': nat.TFTPNextServer = args[2]
2794 else:
2795 print "invalid cmd:", cmd
2796 return (1, None)
2797 return (0, None)
2798
2799def natPortForwarding(ctx, mach, nicnum, nat, args):
2800 """This command shows/manages port-forwarding settings
2801 usage:
2802 nat <vm> <nicnum> <pf> [ simple tcp|udp <hostport> <guestport>]
2803 |[no_name tcp|udp <hostip> <hostport> <guestip> <guestport>]
2804 |[ex tcp|udp <pf-name> <hostip> <hostport> <guestip> <guestport>]
2805 |[delete <pf-name>]
2806 """
2807 if len(args) == 1:
2808 # note: keys/values are swapped in defining part of the function
2809 proto = {0: 'udp', 1: 'tcp'}
2810 msg = []
2811 pfs = ctx['global'].getArray(nat, 'redirects')
2812 for pf in pfs:
2813 (pfnme, pfp, pfhip, pfhp, pfgip, pfgp) = str(pf).split(', ')
2814 msg.append('%s: %s %s:%s => %s:%s' % (pfnme, proto[int(pfp)], pfhip, pfhp, pfgip, pfgp))
2815 return (0, msg) # msg is array
2816 else:
2817 proto = {'udp': 0, 'tcp': 1}
2818 pfcmd = {
2819 'simple': {
2820 'validate': lambda: args[1] in pfcmd.keys() and args[2] in proto.keys() and len(args) == 5,
2821 'func':lambda: nat.addRedirect('', proto[args[2]], '', int(args[3]), '', int(args[4]))
2822 },
2823 'no_name': {
2824 'validate': lambda: args[1] in pfcmd.keys() and args[2] in proto.keys() and len(args) == 7,
2825 'func': lambda: nat.addRedirect('', proto[args[2]], args[3], int(args[4]), args[5], int(args[6]))
2826 },
2827 'ex': {
2828 'validate': lambda: args[1] in pfcmd.keys() and args[2] in proto.keys() and len(args) == 8,
2829 'func': lambda: nat.addRedirect(args[3], proto[args[2]], args[4], int(args[5]), args[6], int(args[7]))
2830 },
2831 'delete': {
2832 'validate': lambda: len(args) == 3,
2833 'func': lambda: nat.removeRedirect(args[2])
2834 }
2835 }
2836
2837 if not pfcmd[args[1]]['validate']():
2838 print 'invalid port-forwarding or args of sub command ', args[1]
2839 print natPortForwarding.__doc__
2840 return (1, None)
2841
2842 a = pfcmd[args[1]]['func']()
2843 return (0, None)
2844
2845def natNetwork(ctx, mach, nicnum, nat, args):
2846 """This command shows/alters NAT network settings
2847 usage: nat <vm> <nicnum> network [<network>]
2848 """
2849 if len(args) == 1:
2850 if nat.network is not None and len(str(nat.network)) != 0:
2851 msg = '\'%s\'' % (nat.network)
2852 else:
2853 msg = '10.0.%d.0/24' % (int(nicnum) + 2)
2854 return (0, [msg])
2855 else:
2856 (addr, mask) = args[1].split('/')
2857 if addr.count('.') > 3 or int(mask) < 0 or int(mask) > 32:
2858 print 'Invalid arguments'
2859 return (1, None)
2860 nat.network = args[1]
2861 return (0, None)
2862
2863def natCmd(ctx, args):
2864 """This command is entry point to NAT settins management
2865 usage: nat <vm> <nicnum> <cmd> <cmd-args>
2866 cmd - [alias|settings|tftp|dns|pf|network]
2867 for more information about commands:
2868 nat help <cmd>
2869 """
2870
2871 natcommands = {
2872 'alias' : natAlias,
2873 'settings' : natSettings,
2874 'tftp': natTftp,
2875 'dns': natDns,
2876 'pf': natPortForwarding,
2877 'network': natNetwork
2878 }
2879
2880 if len(args) < 2 or args[1] == 'help':
2881 if len(args) > 2:
2882 print natcommands[args[2]].__doc__
2883 else:
2884 print natCmd.__doc__
2885 return 0
2886 if len(args) == 1 or len(args) < 4 or args[3] not in natcommands:
2887 print natCmd.__doc__
2888 return 0
2889 mach = ctx['argsToMach'](args)
2890 if mach == None:
2891 print "please specify vm"
2892 return 0
2893 if len(args) < 3 or not args[2].isdigit() or int(args[2]) not in range(0, ctx['vb'].systemProperties.getMaxNetworkAdapters(mach.chipsetType)):
2894 print 'please specify adapter num %d isn\'t in range [0-%d]' % (args[2], ctx['vb'].systemProperties.getMaxNetworkAdapters(mach.chipsetType))
2895 return 0
2896 nicnum = int(args[2])
2897 cmdargs = []
2898 for i in range(3, len(args)):
2899 cmdargs.append(args[i])
2900
2901 # @todo vvl if nicnum is missed but command is entered
2902 # use NAT func for every adapter on machine.
2903 func = args[3]
2904 rosession = 1
2905 session = None
2906 if len(cmdargs) > 1:
2907 rosession = 0
2908 session = ctx['global'].openMachineSession(mach, False)
2909 mach = session.machine
2910
2911 adapter = mach.getNetworkAdapter(nicnum)
2912 natEngine = adapter.NATEngine
2913 (rc, report) = natcommands[func](ctx, mach, nicnum, natEngine, cmdargs)
2914 if rosession == 0:
2915 if rc == 0:
2916 mach.saveSettings()
2917 session.unlockMachine()
2918 elif report is not None:
2919 for r in report:
2920 msg ='%s nic%d %s: %s' % (mach.name, nicnum, func, r)
2921 print msg
2922 return 0
2923
2924def nicSwitchOnOff(adapter, attr, args):
2925 if len(args) == 1:
2926 yesno = {0: 'off', 1: 'on'}
2927 r = yesno[int(adapter.__getattr__(attr))]
2928 return (0, r)
2929 else:
2930 yesno = {'off' : 0, 'on' : 1}
2931 if args[1] not in yesno:
2932 print '%s isn\'t acceptable, please choose %s' % (args[1], yesno.keys())
2933 return (1, None)
2934 adapter.__setattr__(attr, yesno[args[1]])
2935 return (0, None)
2936
2937def nicTraceSubCmd(ctx, vm, nicnum, adapter, args):
2938 '''
2939 usage: nic <vm> <nicnum> trace [on|off [file]]
2940 '''
2941 (rc, r) = nicSwitchOnOff(adapter, 'traceEnabled', args)
2942 if len(args) == 1 and rc == 0:
2943 r = '%s file:%s' % (r, adapter.traceFile)
2944 return (0, r)
2945 elif len(args) == 3 and rc == 0:
2946 adapter.traceFile = args[2]
2947 return (0, None)
2948
2949def nicLineSpeedSubCmd(ctx, vm, nicnum, adapter, args):
2950 if len(args) == 1:
2951 r = '%d kbps'% (adapter.lineSpeed)
2952 return (0, r)
2953 else:
2954 if not args[1].isdigit():
2955 print '%s isn\'t a number' % (args[1])
2956 print (1, None)
2957 adapter.lineSpeed = int(args[1])
2958 return (0, None)
2959
2960def nicCableSubCmd(ctx, vm, nicnum, adapter, args):
2961 '''
2962 usage: nic <vm> <nicnum> cable [on|off]
2963 '''
2964 return nicSwitchOnOff(adapter, 'cableConnected', args)
2965
2966def nicEnableSubCmd(ctx, vm, nicnum, adapter, args):
2967 '''
2968 usage: nic <vm> <nicnum> enable [on|off]
2969 '''
2970 return nicSwitchOnOff(adapter, 'enabled', args)
2971
2972def nicTypeSubCmd(ctx, vm, nicnum, adapter, args):
2973 '''
2974 usage: nic <vm> <nicnum> type [Am79c970A|Am79c970A|I82540EM|I82545EM|I82543GC|Virtio]
2975 '''
2976 if len(args) == 1:
2977 nictypes = ctx['const'].all_values('NetworkAdapterType')
2978 for key in nictypes.keys():
2979 if str(adapter.adapterType) == str(nictypes[key]):
2980 return (0, str(key))
2981 return (1, None)
2982 else:
2983 nictypes = ctx['const'].all_values('NetworkAdapterType')
2984 if args[1] not in nictypes.keys():
2985 print '%s not in acceptable values (%s)' % (args[1], nictypes.keys())
2986 return (1, None)
2987 adapter.adapterType = nictypes[args[1]]
2988 return (0, None)
2989
2990def nicAttachmentSubCmd(ctx, vm, nicnum, adapter, args):
2991 '''
2992 usage: nic <vm> <nicnum> attachment [Null|NAT|Bridged <interface>|Internal <name>|HostOnly <interface>
2993 '''
2994 if len(args) == 1:
2995 nicAttachmentType = {
2996 ctx['global'].constants.NetworkAttachmentType_Null: ('Null', ''),
2997 ctx['global'].constants.NetworkAttachmentType_NAT: ('NAT', ''),
2998 ctx['global'].constants.NetworkAttachmentType_Bridged: ('Bridged', adapter.bridgedInterface),
2999 ctx['global'].constants.NetworkAttachmentType_Internal: ('Internal', adapter.internalNetwork),
3000 ctx['global'].constants.NetworkAttachmentType_HostOnly: ('HostOnly', adapter.hostOnlyInterface),
3001 # @todo show details of the generic network attachment type
3002 ctx['global'].constants.NetworkAttachmentType_Generic: ('Generic', ''),
3003 }
3004 import types
3005 if type(adapter.attachmentType) != types.IntType:
3006 t = str(adapter.attachmentType)
3007 else:
3008 t = adapter.attachmentType
3009 (r, p) = nicAttachmentType[t]
3010 return (0, 'attachment:%s, name:%s' % (r, p))
3011 else:
3012 nicAttachmentType = {
3013 'Null': {
3014 'v': lambda: len(args) == 2,
3015 'p': lambda: 'do nothing',
3016 'f': lambda: ctx['global'].constants.NetworkAttachmentType_Null},
3017 'NAT': {
3018 'v': lambda: len(args) == 2,
3019 'p': lambda: 'do nothing',
3020 'f': lambda: ctx['global'].constants.NetworkAttachmentType_NAT},
3021 'Bridged': {
3022 'v': lambda: len(args) == 3,
3023 'p': lambda: adapter.__setattr__('bridgedInterface', args[2]),
3024 'f': lambda: ctx['global'].constants.NetworkAttachmentType_Bridged},
3025 'Internal': {
3026 'v': lambda: len(args) == 3,
3027 'p': lambda: adapter.__setattr__('internalNetwork', args[2]),
3028 'f': lambda: ctx['global'].constants.NetworkAttachmentType_Internal},
3029 'HostOnly': {
3030 'v': lambda: len(args) == 2,
3031 'p': lambda: adapter.__setattr__('hostOnlyInterface', args[2]),
3032 'f': lambda: ctx['global'].constants.NetworkAttachmentType_HostOnly},
3033 # @todo implement setting the properties of a generic attachment
3034 'Generic': {
3035 'v': lambda: len(args) == 3,
3036 'p': lambda: 'do nothing',
3037 'f': lambda: ctx['global'].constants.NetworkAttachmentType_Generic}
3038 }
3039 if args[1] not in nicAttachmentType.keys():
3040 print '%s not in acceptable values (%s)' % (args[1], nicAttachmentType.keys())
3041 return (1, None)
3042 if not nicAttachmentType[args[1]]['v']():
3043 print nicAttachmentType.__doc__
3044 return (1, None)
3045 nicAttachmentType[args[1]]['p']()
3046 adapter.attachmentType = nicAttachmentType[args[1]]['f']()
3047 return (0, None)
3048
3049def nicCmd(ctx, args):
3050 '''
3051 This command to manage network adapters
3052 usage: nic <vm> <nicnum> <cmd> <cmd-args>
3053 where cmd : attachment, trace, linespeed, cable, enable, type
3054 '''
3055 # 'command name':{'runtime': is_callable_at_runtime, 'op': function_name}
3056 niccomand = {
3057 'attachment': nicAttachmentSubCmd,
3058 'trace': nicTraceSubCmd,
3059 'linespeed': nicLineSpeedSubCmd,
3060 'cable': nicCableSubCmd,
3061 'enable': nicEnableSubCmd,
3062 'type': nicTypeSubCmd
3063 }
3064 if len(args) < 2 \
3065 or args[1] == 'help' \
3066 or (len(args) > 2 and args[3] not in niccomand):
3067 if len(args) == 3 \
3068 and args[2] in niccomand:
3069 print niccomand[args[2]].__doc__
3070 else:
3071 print nicCmd.__doc__
3072 return 0
3073
3074 vm = ctx['argsToMach'](args)
3075 if vm is None:
3076 print 'please specify vm'
3077 return 0
3078
3079 if len(args) < 3 \
3080 or int(args[2]) not in range(0, ctx['vb'].systemProperties.getMaxNetworkAdapters(vm.chipsetType)):
3081 print 'please specify adapter num %d isn\'t in range [0-%d]'% (args[2], ctx['vb'].systemProperties.getMaxNetworkAdapters(vm.chipsetType))
3082 return 0
3083 nicnum = int(args[2])
3084 cmdargs = args[3:]
3085 func = args[3]
3086 session = None
3087 session = ctx['global'].openMachineSession(vm)
3088 vm = session.machine
3089 adapter = vm.getNetworkAdapter(nicnum)
3090 (rc, report) = niccomand[func](ctx, vm, nicnum, adapter, cmdargs)
3091 if rc == 0:
3092 vm.saveSettings()
3093 if report is not None:
3094 print '%s nic %d %s: %s' % (vm.name, nicnum, args[3], report)
3095 session.unlockMachine()
3096 return 0
3097
3098
3099def promptCmd(ctx, args):
3100 if len(args) < 2:
3101 print "Current prompt: '%s'" % (ctx['prompt'])
3102 return 0
3103
3104 ctx['prompt'] = args[1]
3105 return 0
3106
3107def foreachCmd(ctx, args):
3108 if len(args) < 3:
3109 print "usage: foreach scope command, where scope is XPath-like expression //vms/vm[@CPUCount='2']"
3110 return 0
3111
3112 scope = args[1]
3113 cmd = args[2]
3114 elems = eval_xpath(ctx, scope)
3115 try:
3116 for e in elems:
3117 e.apply(cmd)
3118 except:
3119 print "Error executing"
3120 traceback.print_exc()
3121 return 0
3122
3123def foreachvmCmd(ctx, args):
3124 if len(args) < 2:
3125 print "foreachvm command <args>"
3126 return 0
3127 cmdargs = args[1:]
3128 cmdargs.insert(1, '')
3129 for mach in getMachines(ctx):
3130 cmdargs[1] = mach.id
3131 runCommandArgs(ctx, cmdargs)
3132 return 0
3133
3134def recordDemoCmd(ctx, args):
3135 if (len(args) < 3):
3136 print "usage: recordDemo vm filename (duration)"
3137 return 0
3138 mach = argsToMach(ctx, args)
3139 if mach == None:
3140 return 0
3141 filename = args[2]
3142 dur = 10000
3143 if len(args) > 3:
3144 dur = float(args[3])
3145 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: recordDemo(ctx, console, filename, dur)])
3146 return 0
3147
3148def playbackDemoCmd(ctx, args):
3149 if (len(args) < 3):
3150 print "usage: playbackDemo vm filename (duration)"
3151 return 0
3152 mach = argsToMach(ctx, args)
3153 if mach == None:
3154 return 0
3155 filename = args[2]
3156 dur = 10000
3157 if len(args) > 3:
3158 dur = float(args[3])
3159 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: playbackDemo(ctx, console, filename, dur)])
3160 return 0
3161
3162
3163def pciAddr(ctx, addr):
3164 strg = "%02x:%02x.%d" % (addr >> 8, (addr & 0xff) >> 3, addr & 7)
3165 return colPci(ctx, strg)
3166
3167def lspci(ctx, console):
3168 assigned = ctx['global'].getArray(console.machine, 'PCIDeviceAssignments')
3169 for a in assigned:
3170 if a.isPhysicalDevice:
3171 print "%s: assigned host device %s guest %s" % (colDev(ctx, a.name), pciAddr(ctx, a.hostAddress), pciAddr(ctx, a.guestAddress))
3172
3173 atts = ctx['global'].getArray(console, 'attachedPCIDevices')
3174 for a in atts:
3175 if a.isPhysicalDevice:
3176 print "%s: physical, guest %s, host %s" % (colDev(ctx, a.name), pciAddr(ctx, a.guestAddress), pciAddr(ctx, a.hostAddress))
3177 else:
3178 print "%s: virtual, guest %s" % (colDev(ctx, a.name), pciAddr(ctx, a.guestAddress))
3179 return
3180
3181def parsePci(strg):
3182 pcire = re.compile(r'(?P<b>[0-9a-fA-F]+):(?P<d>[0-9a-fA-F]+)\.(?P<f>\d)')
3183 match = pcire.search(strg)
3184 if match is None:
3185 return -1
3186 pdict = match.groupdict()
3187 return ((int(pdict['b'], 16)) << 8) | ((int(pdict['d'], 16)) << 3) | int(pdict['f'])
3188
3189def lspciCmd(ctx, args):
3190 if (len(args) < 2):
3191 print "usage: lspci vm"
3192 return 0
3193 mach = argsToMach(ctx, args)
3194 if mach == None:
3195 return 0
3196 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: lspci(ctx, console)])
3197 return 0
3198
3199def attachpciCmd(ctx, args):
3200 if (len(args) < 3):
3201 print "usage: attachpci vm hostpci <guestpci>"
3202 return 0
3203 mach = argsToMach(ctx, args)
3204 if mach == None:
3205 return 0
3206 hostaddr = parsePci(args[2])
3207 if hostaddr == -1:
3208 print "invalid host PCI %s, accepted format 01:02.3 for bus 1, device 2, function 3" % (args[2])
3209 return 0
3210
3211 if (len(args) > 3):
3212 guestaddr = parsePci(args[3])
3213 if guestaddr == -1:
3214 print "invalid guest PCI %s, accepted format 01:02.3 for bus 1, device 2, function 3" % (args[3])
3215 return 0
3216 else:
3217 guestaddr = hostaddr
3218 cmdClosedVm(ctx, mach, lambda ctx, mach, a: mach.attachHostPCIDevice(hostaddr, guestaddr, True))
3219 return 0
3220
3221def detachpciCmd(ctx, args):
3222 if (len(args) < 3):
3223 print "usage: detachpci vm hostpci"
3224 return 0
3225 mach = argsToMach(ctx, args)
3226 if mach == None:
3227 return 0
3228 hostaddr = parsePci(args[2])
3229 if hostaddr == -1:
3230 print "invalid host PCI %s, accepted format 01:02.3 for bus 1, device 2, function 3" % (args[2])
3231 return 0
3232
3233 cmdClosedVm(ctx, mach, lambda ctx, mach, a: mach.detachHostPCIDevice(hostaddr))
3234 return 0
3235
3236def gotoCmd(ctx, args):
3237 if (len(args) < 2):
3238 print "usage: goto line"
3239 return 0
3240
3241 line = int(args[1])
3242
3243 ctx['scriptLine'] = line
3244
3245 return 0
3246
3247aliases = {'s':'start',
3248 'i':'info',
3249 'l':'list',
3250 'h':'help',
3251 'a':'alias',
3252 'q':'quit', 'exit':'quit',
3253 'tg': 'typeGuest',
3254 'v':'verbose'}
3255
3256commands = {'help':['Prints help information', helpCmd, 0],
3257 'start':['Start virtual machine by name or uuid: start Linux headless', startCmd, 0],
3258 'createVm':['Create virtual machine: createVm macvm MacOS', createVmCmd, 0],
3259 'removeVm':['Remove virtual machine', removeVmCmd, 0],
3260 'pause':['Pause virtual machine', pauseCmd, 0],
3261 'resume':['Resume virtual machine', resumeCmd, 0],
3262 'save':['Save execution state of virtual machine', saveCmd, 0],
3263 'stats':['Stats for virtual machine', statsCmd, 0],
3264 'powerdown':['Power down virtual machine', powerdownCmd, 0],
3265 'powerbutton':['Effectively press power button', powerbuttonCmd, 0],
3266 'list':['Shows known virtual machines', listCmd, 0],
3267 'info':['Shows info on machine', infoCmd, 0],
3268 'ginfo':['Shows info on guest', ginfoCmd, 0],
3269 'gexec':['Executes program in the guest', gexecCmd, 0],
3270 'gcopy':['Copy file to the guest', gcopyCmd, 0],
3271 'gpipe':['Pipe between host and guest', gpipeCmd, 0],
3272 'alias':['Control aliases', aliasCmd, 0],
3273 'verbose':['Toggle verbosity', verboseCmd, 0],
3274 'setvar':['Set VMs variable: setvar Fedora BIOSSettings.ACPIEnabled True', setvarCmd, 0],
3275 'eval':['Evaluate arbitrary Python construction: eval \'for m in getMachines(ctx): print m.name, "has", m.memorySize, "M"\'', evalCmd, 0],
3276 'quit':['Exits', quitCmd, 0],
3277 'host':['Show host information', hostCmd, 0],
3278 'guest':['Execute command for guest: guest Win32 \'console.mouse.putMouseEvent(20, 20, 0, 0, 0)\'', guestCmd, 0],
3279 'monitorGuest':['Monitor what happens with the guest for some time: monitorGuest Win32 10', monitorGuestCmd, 0],
3280 'monitorGuestKbd':['Monitor guest keyboard for some time: monitorGuestKbd Win32 10', monitorGuestKbdCmd, 0],
3281 'monitorGuestMouse':['Monitor guest mouse for some time: monitorGuestMouse Win32 10', monitorGuestMouseCmd, 0],
3282 'monitorGuestMultiTouch':['Monitor guest touch screen for some time: monitorGuestMultiTouch Win32 10', monitorGuestMultiTouchCmd, 0],
3283 'monitorVBox':['Monitor what happens with Virtual Box for some time: monitorVBox 10', monitorVBoxCmd, 0],
3284 'portForward':['Setup permanent port forwarding for a VM, takes adapter number host port and guest port: portForward Win32 0 8080 80', portForwardCmd, 0],
3285 'showLog':['Show log file of the VM, : showLog Win32', showLogCmd, 0],
3286 'findLog':['Show entries matching pattern in log file of the VM, : findLog Win32 PDM|CPUM', findLogCmd, 0],
3287 'findAssert':['Find assert in log file of the VM, : findAssert Win32', findAssertCmd, 0],
3288 'reloadExt':['Reload custom extensions: reloadExt', reloadExtCmd, 0],
3289 'runScript':['Run VBox script: runScript script.vbox', runScriptCmd, 0],
3290 'sleep':['Sleep for specified number of seconds: sleep 3.14159', sleepCmd, 0],
3291 'shell':['Execute external shell command: shell "ls /etc/rc*"', shellCmd, 0],
3292 'exportVm':['Export VM in OVF format: exportVm Win /tmp/win.ovf', exportVMCmd, 0],
3293 'screenshot':['Take VM screenshot to a file: screenshot Win /tmp/win.png 1024 768 0', screenshotCmd, 0],
3294 'teleport':['Teleport VM to another box (see openportal): teleport Win anotherhost:8000 <passwd> <maxDowntime>', teleportCmd, 0],
3295 'typeGuest':['Type arbitrary text in guest: typeGuest Linux "^lls\\n&UP;&BKSP;ess /etc/hosts\\nq^c" 0.7', typeGuestCmd, 0],
3296 'openportal':['Open portal for teleportation of VM from another box (see teleport): openportal Win 8000 <passwd>', openportalCmd, 0],
3297 'closeportal':['Close teleportation portal (see openportal, teleport): closeportal Win', closeportalCmd, 0],
3298 'getextra':['Get extra data, empty key lists all: getextra <vm|global> <key>', getExtraDataCmd, 0],
3299 'setextra':['Set extra data, empty value removes key: setextra <vm|global> <key> <value>', setExtraDataCmd, 0],
3300 'gueststats':['Print available guest stats (only Windows guests with additions so far): gueststats Win32', gueststatsCmd, 0],
3301 'plugcpu':['Add a CPU to a running VM: plugcpu Win 1', plugcpuCmd, 0],
3302 'unplugcpu':['Remove a CPU from a running VM (additions required, Windows cannot unplug): unplugcpu Linux 1', unplugcpuCmd, 0],
3303 'createHdd': ['Create virtual HDD: createHdd 1000 /disk.vdi ', createHddCmd, 0],
3304 'removeHdd': ['Permanently remove virtual HDD: removeHdd /disk.vdi', removeHddCmd, 0],
3305 'registerHdd': ['Register HDD image with VirtualBox instance: registerHdd /disk.vdi', registerHddCmd, 0],
3306 'unregisterHdd': ['Unregister HDD image with VirtualBox instance: unregisterHdd /disk.vdi', unregisterHddCmd, 0],
3307 'attachHdd': ['Attach HDD to the VM: attachHdd win /disk.vdi "IDE Controller" 0:1', attachHddCmd, 0],
3308 'detachHdd': ['Detach HDD from the VM: detachHdd win /disk.vdi', detachHddCmd, 0],
3309 'registerIso': ['Register CD/DVD image with VirtualBox instance: registerIso /os.iso', registerIsoCmd, 0],
3310 'unregisterIso': ['Unregister CD/DVD image with VirtualBox instance: unregisterIso /os.iso', unregisterIsoCmd, 0],
3311 'removeIso': ['Permanently remove CD/DVD image: removeIso /os.iso', removeIsoCmd, 0],
3312 'attachIso': ['Attach CD/DVD to the VM: attachIso win /os.iso "IDE Controller" 0:1', attachIsoCmd, 0],
3313 'detachIso': ['Detach CD/DVD from the VM: detachIso win /os.iso', detachIsoCmd, 0],
3314 'mountIso': ['Mount CD/DVD to the running VM: mountIso win /os.iso "IDE Controller" 0:1', mountIsoCmd, 0],
3315 'unmountIso': ['Unmount CD/DVD from running VM: unmountIso win "IDE Controller" 0:1', unmountIsoCmd, 0],
3316 'attachCtr': ['Attach storage controller to the VM: attachCtr win Ctr0 IDE ICH6', attachCtrCmd, 0],
3317 'detachCtr': ['Detach HDD from the VM: detachCtr win Ctr0', detachCtrCmd, 0],
3318 'attachUsb': ['Attach USB device to the VM (use listUsb to show available devices): attachUsb win uuid', attachUsbCmd, 0],
3319 'detachUsb': ['Detach USB device from the VM: detachUsb win uuid', detachUsbCmd, 0],
3320 'listMedia': ['List media known to this VBox instance', listMediaCmd, 0],
3321 'listUsb': ['List known USB devices', listUsbCmd, 0],
3322 'shareFolder': ['Make host\'s folder visible to guest: shareFolder win /share share writable', shareFolderCmd, 0],
3323 'unshareFolder': ['Remove folder sharing', unshareFolderCmd, 0],
3324 'gui': ['Start GUI frontend', guiCmd, 0],
3325 'colors':['Toggle colors', colorsCmd, 0],
3326 'snapshot':['VM snapshot manipulation, snapshot help for more info', snapshotCmd, 0],
3327 'nat':['NAT (network address translation engine) manipulation, nat help for more info', natCmd, 0],
3328 'nic' : ['Network adapter management', nicCmd, 0],
3329 'prompt' : ['Control shell prompt', promptCmd, 0],
3330 'foreachvm' : ['Perform command for each VM', foreachvmCmd, 0],
3331 'foreach' : ['Generic "for each" construction, using XPath-like notation: foreach //vms/vm[@OSTypeId=\'MacOS\'] "print obj.name"', foreachCmd, 0],
3332 'recordDemo':['Record demo: recordDemo Win32 file.dmo 10', recordDemoCmd, 0],
3333 'playbackDemo':['Playback demo: playbackDemo Win32 file.dmo 10', playbackDemoCmd, 0],
3334 'lspci': ['List PCI devices attached to the VM: lspci Win32', lspciCmd, 0],
3335 'attachpci': ['Attach host PCI device to the VM: attachpci Win32 01:00.0', attachpciCmd, 0],
3336 'detachpci': ['Detach host PCI device from the VM: detachpci Win32 01:00.0', detachpciCmd, 0],
3337 'goto': ['Go to line in script (script-only)', gotoCmd, 0]
3338 }
3339
3340def runCommandArgs(ctx, args):
3341 c = args[0]
3342 if aliases.get(c, None) != None:
3343 c = aliases[c]
3344 ci = commands.get(c, None)
3345 if ci == None:
3346 print "Unknown command: '%s', type 'help' for list of known commands" % (c)
3347 return 0
3348 if ctx['remote'] and ctx['vb'] is None:
3349 if c not in ['connect', 'reconnect', 'help', 'quit']:
3350 print "First connect to remote server with %s command." % (colored('connect', 'blue'))
3351 return 0
3352 return ci[1](ctx, args)
3353
3354
3355def runCommand(ctx, cmd):
3356 if len(cmd) == 0: return 0
3357 args = split_no_quotes(cmd)
3358 if len(args) == 0: return 0
3359 return runCommandArgs(ctx, args)
3360
3361#
3362# To write your own custom commands to vboxshell, create
3363# file ~/.VirtualBox/shellext.py with content like
3364#
3365# def runTestCmd(ctx, args):
3366# print "Testy test", ctx['vb']
3367# return 0
3368#
3369# commands = {
3370# 'test': ['Test help', runTestCmd]
3371# }
3372# and issue reloadExt shell command.
3373# This file also will be read automatically on startup or 'reloadExt'.
3374#
3375# Also one can put shell extensions into ~/.VirtualBox/shexts and
3376# they will also be picked up, so this way one can exchange
3377# shell extensions easily.
3378def addExtsFromFile(ctx, cmds, filename):
3379 if not os.path.isfile(filename):
3380 return
3381 d = {}
3382 try:
3383 execfile(filename, d, d)
3384 for (k, v) in d['commands'].items():
3385 if g_fVerbose:
3386 print "customize: adding \"%s\" - %s" % (k, v[0])
3387 cmds[k] = [v[0], v[1], filename]
3388 except:
3389 print "Error loading user extensions from %s" % (filename)
3390 traceback.print_exc()
3391
3392
3393def checkUserExtensions(ctx, cmds, folder):
3394 folder = str(folder)
3395 name = os.path.join(folder, "shellext.py")
3396 addExtsFromFile(ctx, cmds, name)
3397 # also check 'exts' directory for all files
3398 shextdir = os.path.join(folder, "shexts")
3399 if not os.path.isdir(shextdir):
3400 return
3401 exts = os.listdir(shextdir)
3402 for e in exts:
3403 # not editor temporary files, please.
3404 if e.endswith('.py'):
3405 addExtsFromFile(ctx, cmds, os.path.join(shextdir, e))
3406
3407def getHomeFolder(ctx):
3408 if ctx['remote'] or ctx['vb'] is None:
3409 if 'VBOX_USER_HOME' in os.environ:
3410 return os.path.join(os.environ['VBOX_USER_HOME'])
3411 return os.path.join(os.path.expanduser("~"), ".VirtualBox")
3412 else:
3413 return ctx['vb'].homeFolder
3414
3415def interpret(ctx):
3416 if ctx['remote']:
3417 commands['connect'] = ["Connect to remote VBox instance: connect http://server:18083 user password", connectCmd, 0]
3418 commands['disconnect'] = ["Disconnect from remote VBox instance", disconnectCmd, 0]
3419 commands['reconnect'] = ["Reconnect to remote VBox instance", reconnectCmd, 0]
3420 ctx['wsinfo'] = ["http://localhost:18083", "", ""]
3421
3422 vbox = ctx['vb']
3423 if vbox is not None:
3424 try:
3425 print "Running VirtualBox version %s" % (vbox.version)
3426 except Exception, e:
3427 printErr(ctx, e)
3428 if g_fVerbose:
3429 traceback.print_exc()
3430 ctx['perf'] = None # ctx['global'].getPerfCollector(vbox)
3431 else:
3432 ctx['perf'] = None
3433
3434 home = getHomeFolder(ctx)
3435 checkUserExtensions(ctx, commands, home)
3436 if platform.system() in ['Windows', 'Microsoft']:
3437 global g_fHasColors
3438 g_fHasColors = False
3439 hist_file = os.path.join(home, ".vboxshellhistory")
3440 autoCompletion(commands, ctx)
3441
3442 if g_fHasReadline and os.path.exists(hist_file):
3443 readline.read_history_file(hist_file)
3444
3445 # to allow to print actual host information, we collect info for
3446 # last 150 secs maximum, (sample every 10 secs and keep up to 15 samples)
3447 if ctx['perf']:
3448 try:
3449 ctx['perf'].setup(['*'], [vbox.host], 10, 15)
3450 except:
3451 pass
3452 cmds = []
3453
3454 if g_sCmd is not None:
3455 cmds = g_sCmd.split(';')
3456 it = cmds.__iter__()
3457
3458 while True:
3459 try:
3460 if g_fBatchMode:
3461 cmd = 'runScript %s'% (g_sScriptFile)
3462 elif g_sCmd is not None:
3463 cmd = it.next()
3464 else:
3465 cmd = raw_input(ctx['prompt'])
3466 done = runCommand(ctx, cmd)
3467 if done != 0: break
3468 if g_fBatchMode:
3469 break
3470 except KeyboardInterrupt:
3471 print '====== You can type quit or q to leave'
3472 except StopIteration:
3473 break
3474 except EOFError:
3475 break
3476 except Exception, e:
3477 printErr(ctx, e)
3478 if g_fVerbose:
3479 traceback.print_exc()
3480 ctx['global'].waitForEvents(0)
3481 try:
3482 # There is no need to disable metric collection. This is just an example.
3483 if ct['perf']:
3484 ctx['perf'].disable(['*'], [vbox.host])
3485 except:
3486 pass
3487 if g_fHasReadline:
3488 readline.write_history_file(hist_file)
3489
3490def runCommandCb(ctx, cmd, args):
3491 args.insert(0, cmd)
3492 return runCommandArgs(ctx, args)
3493
3494def runGuestCommandCb(ctx, uuid, guestLambda, args):
3495 mach = machById(ctx, uuid)
3496 if mach == None:
3497 return 0
3498 args.insert(0, guestLambda)
3499 cmdExistingVm(ctx, mach, 'guestlambda', args)
3500 return 0
3501
3502def main(argv):
3503
3504 #
3505 # Parse command line arguments.
3506 #
3507 parse = OptionParser()
3508 parse.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, help = "switch on verbose")
3509 parse.add_option("-a", "--autopath", dest="autopath", action="store_true", default=False, help = "switch on autopath")
3510 parse.add_option("-w", "--webservice", dest="style", action="store_const", const="WEBSERVICE", help = "connect to webservice")
3511 parse.add_option("-b", "--batch", dest="batch_file", help = "script file to execute")
3512 parse.add_option("-c", dest="command_line", help = "command sequence to execute")
3513 parse.add_option("-o", dest="opt_line", help = "option line")
3514 global g_fVerbose, g_sScriptFile, g_fBatchMode, g_fHasColors, g_fHasReadline, g_sCmd
3515 (options, args) = parse.parse_args()
3516 g_fVerbose = options.verbose
3517 style = options.style
3518 if options.batch_file is not None:
3519 g_fBatchMode = True
3520 g_fHasColors = False
3521 g_fHasReadline = False
3522 g_sScriptFile = options.batch_file
3523 if options.command_line is not None:
3524 g_fHasColors = False
3525 g_fHasReadline = False
3526 g_sCmd = options.command_line
3527
3528 params = None
3529 if options.opt_line is not None:
3530 params = {}
3531 strparams = options.opt_line
3532 strparamlist = strparams.split(',')
3533 for strparam in strparamlist:
3534 (key, value) = strparam.split('=')
3535 params[key] = value
3536
3537 if options.autopath:
3538 asLocations = [ os.getcwd(), ];
3539 try: sScriptDir = os.path.dirname(os.path.abspath(__file__));
3540 except: pass; # In case __file__ isn't there.
3541 else:
3542 if platform.system() in [ 'SunOS', ]:
3543 asLocations.append(os.path.join(sScriptDir, 'amd64'));
3544 asLocations.append(sScriptDir);
3545
3546
3547 sPath = os.environ.get("VBOX_PROGRAM_PATH")
3548 if sPath is None:
3549 for sCurLoc in asLocations:
3550 if os.path.isfile(os.path.join(sCurLoc, "VirtualBox")) \
3551 or os.path.isfile(os.path.join(sCurLoc, "VirtualBox.exe")):
3552 print "Autodetected VBOX_PROGRAM_PATH as", sCurLoc
3553 os.environ["VBOX_PROGRAM_PATH"] = sCurLoc
3554 sPath = sCurLoc
3555 break;
3556 if sPath:
3557 sys.path.append(os.path.join(sPath, "sdk", "installer"))
3558
3559 sPath = os.environ.get("VBOX_SDK_PATH")
3560 if sPath is None:
3561 for sCurLoc in asLocations:
3562 if os.path.isfile(os.path.join(sCurLoc, "sdk", "bindings", "VirtualBox.xidl")):
3563 sCurLoc = os.path.join(sCurLoc, "sdk");
3564 print "Autodetected VBOX_SDK_PATH as", sCurLoc
3565 os.environ["VBOX_SDK_PATH"] = sCurLoc
3566 sPath = sCurLoc;
3567 break;
3568 if sPath:
3569 sTmp = os.path.join(sCurLoc, 'sdk', 'bindings', 'xpcom', 'python');
3570 if os.path.isdir(sTmp):
3571 sys.path.append(sTmp);
3572 del sTmp;
3573 del sPath, asLocations;
3574
3575
3576 #
3577 # Set up the shell interpreter context and
3578 #
3579 from vboxapi import VirtualBoxManager
3580 oVBoxMgr = VirtualBoxManager(style, params)
3581 ctx = {
3582 'global': oVBoxMgr,
3583 'vb': oVBoxMgr.vbox,
3584 'const': oVBoxMgr.constants,
3585 'remote': oVBoxMgr.remote,
3586 'type': oVBoxMgr.type,
3587 'run': lambda cmd, args: runCommandCb(ctx, cmd, args),
3588 'guestlambda': lambda uuid, guestLambda, args: runGuestCommandCb(ctx, uuid, guestLambda, args),
3589 'machById': lambda uuid: machById(ctx, uuid),
3590 'argsToMach': lambda args: argsToMach(ctx, args),
3591 'progressBar': lambda p: progressBar(ctx, p),
3592 'typeInGuest': typeInGuest,
3593 '_machlist': None,
3594 'prompt': g_sPrompt,
3595 'scriptLine': 0,
3596 'interrupt': False,
3597 }
3598 interpret(ctx)
3599 oVBoxMgr.deinit()
3600 del oVBoxMgr
3601
3602if __name__ == '__main__':
3603 main(sys.argv)
3604
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette