VirtualBox

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

Last change on this file since 49704 was 49704, checked in by vboxsync, 11 years ago

Frontends/VBoxShell: extend event dumping code slighty, good testcase for the now fixed event interface declarations

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