VirtualBox

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

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

vboxapi.py: Some cleaning up. New features: Documentation. ;-) Dropped the session manager class as it served no purpose I could fathom.

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

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