VirtualBox

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

Last change on this file since 48248 was 47981, checked in by vboxsync, 12 years ago

vboxapi.py: Started on error abstrations (testsuite needs errIsDeadInterface).

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

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