VirtualBox

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

Last change on this file was 102957, checked in by vboxsync, 6 months ago

Main/Python bindings: Moved the Python deprecation warning from VBoxShell into the actual Python bindings module where it belongs. This way all Python API clients get notified (as long as they show stdout somehow).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use