VirtualBox

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

Last change on this file since 108699 was 108641, checked in by vboxsync, 2 months ago

Removed 2D video acceleration (aka VHWA / VBOX_WITH_VIDEOHWACCEL). bugref:10756

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 125.6 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 108641 2025-03-20 12:48:42Z 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/[email protected]/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-2024 Oracle and/or its affiliates.
47
48This file is part of VirtualBox base platform packages, as
49available from https://www.215389.xyz.
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: 108641 $"
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.isFeatureEnabled(ctx['const'].GraphicsFeature_Acceleration3D)))
1018 print(" Use universal time [RTCUseUTC]: %s" % (asState(mach.platform.RTCUseUTC)))
1019 audioAdp = mach.audioSettings.adapter
1020 if audioAdp.enabled:
1021 print(" Audio [via audioAdapter]: chip %s; host driver %s" % (asEnumElem(ctx, "AudioControllerType", audioAdp.audioController), asEnumElem(ctx, "AudioDriverType", audioAdp.audioDriver)))
1022 print(" CPU hotplugging [CPUHotPlugEnabled]: %s" % (asState(mach.CPUHotPlugEnabled)))
1023
1024 print(" Keyboard [keyboardHIDType]: %s (%s)" % (asEnumElem(ctx, "KeyboardHIDType", mach.keyboardHIDType), mach.keyboardHIDType))
1025 print(" Pointing device [pointingHIDType]: %s (%s)" % (asEnumElem(ctx, "PointingHIDType", mach.pointingHIDType), mach.pointingHIDType))
1026 print(" Last changed [n/a]: " + time.asctime(time.localtime(int(mach.lastStateChange)/1000)))
1027 # OSE has no VRDE
1028 try:
1029 print(" VRDE server [VRDEServer.enabled]: %s" % (asState(mach.VRDEServer.enabled)))
1030 except:
1031 pass
1032
1033 print()
1034 print(colCat(ctx, " USB Controllers:"))
1035 for oUsbCtrl in ctx['global'].getArray(mach, 'USBControllers'):
1036 print(" '%s': type %s standard: %#x" \
1037 % (oUsbCtrl.name, asEnumElem(ctx, "USBControllerType", oUsbCtrl.type), oUsbCtrl.USBStandard))
1038
1039 print()
1040 print(colCat(ctx, " I/O subsystem info:"))
1041 print(" Cache enabled [IOCacheEnabled]: %s" % (asState(mach.IOCacheEnabled)))
1042 print(" Cache size [IOCacheSize]: %dM" % (mach.IOCacheSize))
1043
1044 controllers = ctx['global'].getArray(mach, 'storageControllers')
1045 if controllers:
1046 print()
1047 print(colCat(ctx, " Storage Controllers:"))
1048 for controller in controllers:
1049 print(" '%s': bus %s type %s" % (controller.name, asEnumElem(ctx, "StorageBus", controller.bus), asEnumElem(ctx, "StorageControllerType", controller.controllerType)))
1050
1051 attaches = ctx['global'].getArray(mach, 'mediumAttachments')
1052 if attaches:
1053 print()
1054 print(colCat(ctx, " Media:"))
1055 for att in attaches:
1056 print(" Controller: '%s' port/device: %d:%d type: %s (%s):" % (att.controller, att.port, att.device, asEnumElem(ctx, "DeviceType", att.type), att.type))
1057 medium = att.medium
1058 if att.type == ctx['global'].constants.DeviceType_HardDisk:
1059 print(" HDD:")
1060 print(" Id: %s" % (medium.id))
1061 print(" Location: %s" % (colPath(ctx, medium.location)))
1062 print(" Name: %s" % (medium.name))
1063 print(" Format: %s" % (medium.format))
1064
1065 if att.type == ctx['global'].constants.DeviceType_DVD:
1066 print(" DVD:")
1067 if medium:
1068 print(" Id: %s" % (medium.id))
1069 print(" Name: %s" % (medium.name))
1070 if medium.hostDrive:
1071 print(" Host DVD %s" % (colPath(ctx, medium.location)))
1072 if att.passthrough:
1073 print(" [passthrough mode]")
1074 else:
1075 print(" Virtual image at %s" % (colPath(ctx, medium.location)))
1076 print(" Size: %s" % (medium.size))
1077
1078 if att.type == ctx['global'].constants.DeviceType_Floppy:
1079 print(" Floppy:")
1080 if medium:
1081 print(" Id: %s" % (medium.id))
1082 print(" Name: %s" % (medium.name))
1083 if medium.hostDrive:
1084 print(" Host floppy %s" % (colPath(ctx, medium.location)))
1085 else:
1086 print(" Virtual image at %s" % (colPath(ctx, medium.location)))
1087 print(" Size: %s" % (medium.size))
1088
1089 print()
1090 print(colCat(ctx, " Shared folders:"))
1091 for sharedfolder in ctx['global'].getArray(mach, 'sharedFolders'):
1092 printSf(ctx, sharedfolder)
1093
1094 return 0
1095
1096def startCmd(ctx, args):
1097 if len(args) < 2:
1098 print("usage: start <vmname|uuid> <frontend>")
1099 return 0
1100 mach = argsToMach(ctx, args)
1101 if not mach:
1102 return 0
1103 if len(args) > 2:
1104 vmtype = args[2]
1105 else:
1106 vmtype = "gui"
1107 startVm(ctx, mach, vmtype)
1108 return 0
1109
1110def createVmCmd(ctx, args):
1111 if len(args) != 4:
1112 print("usage: createvm <name> <arch> <ostype>")
1113 return 0
1114 name = args[1]
1115 arch = args[2]
1116 oskind = args[3]
1117 try:
1118 ctx['vb'].getGuestOSType(oskind)
1119 except Exception:
1120 print('Unknown OS type:', oskind)
1121 return 0
1122 createVm(ctx, name, arch, oskind)
1123 return 0
1124
1125def ginfoCmd(ctx, args):
1126 if len(args) < 2:
1127 print("usage: ginfo <vmname|uuid>")
1128 return 0
1129 mach = argsToMach(ctx, args)
1130 if not mach:
1131 return 0
1132 cmdExistingVm(ctx, mach, 'ginfo', '')
1133 return 0
1134
1135def gstctlPrintOk(_ctx, string):
1136 return print(colored(string, 'green'))
1137
1138def gstctlPrintErr(_ctx, string):
1139 return print(colored(string, 'red'))
1140
1141def execInGuest(ctx, console, args, env, user, passwd, tmo, inputPipe=None, _outputPipe=None):
1142 if len(args) < 1:
1143 print("exec in guest needs at least program name")
1144 return 1
1145 guest = console.guest
1146 # shall contain program name as argv[0]
1147 gargs = args
1148 if g_fVerbose:
1149 gstctlPrintOk(ctx, "starting guest session for user '%s' (password '%s')" % (user, passwd))
1150 else:
1151 gstctlPrintOk(ctx, ("starting guest session for user '%s' ..." % (user)))
1152 try:
1153 guestSession = guest.createSession(user, passwd, "", "vboxshell guest exec")
1154 guestSession.waitForArray([ ctx['global'].constants.GuestSessionWaitForFlag_Start ], 30 * 1000)
1155 except Exception as e:
1156 gstctlPrintErr(ctx, "starting guest session failed:")
1157 printErr(ctx, e)
1158 return 1
1159 if g_fVerbose:
1160 gstctlPrintOk(ctx, "guest session %d started" % guestSession.id)
1161 aProcCreateFlags = [ ctx['global'].constants.ProcessCreateFlag_WaitForStdOut, \
1162 ctx['global'].constants.ProcessCreateFlag_WaitForStdErr ]
1163 if inputPipe is not None:
1164 aProcCreateFlags.extend([ ctx['global'].constants.ProcessCreateFlag_WaitForStdIn ])
1165 if g_fVerbose:
1166 gstctlPrintOk(ctx, "starting process '%s' with args '%s' as user '%s' (password '%s')" % (args[0], gargs, user, passwd))
1167 process = guestSession.processCreate(args[0], gargs, '', env, aProcCreateFlags, tmo)
1168 try:
1169 waitResult = process.waitForArray([ ctx['global'].constants.ProcessWaitForFlag_Start ], 30 * 1000)
1170 except Exception as e:
1171 gstctlPrintErr(ctx, "waiting for guest process start failed:")
1172 printErr(ctx, e)
1173 return 1
1174 if waitResult != ctx['global'].constants.ProcessWaitResult_Start:
1175 gstctlPrintErr(ctx, "process start failed: got wait result %d, expected %d" \
1176 % (waitResult, ctx['global'].constants.ProcessWaitResult_Start) )
1177 return 1
1178 procStatus = process.status
1179 if procStatus != ctx['global'].constants.ProcessStatus_Started:
1180 gstctlPrintErr(ctx, "process start failed: got process status %d, expected %d" \
1181 % (procStatus, ctx['global'].constants.ProcessStatus_Started) )
1182 return 1
1183 if g_fVerbose:
1184 gstctlPrintOk(ctx, "process %d started" % (process.PID))
1185 if process.PID != 0:
1186 try:
1187 fCompleted = False
1188 fReadStdOut = False
1189 fReadStdErr = False
1190 while not fCompleted:
1191 waitResult = process.waitForArray([ ctx['global'].constants.ProcessWaitForFlag_Terminate, \
1192 ctx['global'].constants.ProcessWaitForFlag_StdOut, \
1193 ctx['global'].constants.ProcessWaitForFlag_StdErr ], 1000)
1194 if waitResult == ctx['global'].constants.ProcessWaitResult_WaitFlagNotSupported:
1195 fReadStdOut = True
1196 fReadStdErr = True
1197 elif waitResult == ctx['global'].constants.ProcessWaitResult_Terminate:
1198 fCompleted = True
1199 break
1200 elif waitResult == ctx['global'].constants.ProcessWaitResult_Timeout:
1201 gstctlPrintErr(ctx, "timeout while waiting for process")
1202 break
1203 else:
1204 gstctlPrintErr(ctx, "got unhandled wait result %d" % (waitResult))
1205 if inputPipe:
1206 indata = inputPipe(ctx)
1207 if indata is not None:
1208 write = len(indata)
1209 off = 0
1210 while write > 0:
1211 written = process.write(0, 10*1000, indata[off:])
1212 off = off + written
1213 write = write - written
1214 else:
1215 # EOF
1216 try:
1217 process.write(0, 10*1000, " ")
1218 except:
1219 pass
1220 if fReadStdOut:
1221 data = process.read(1, 64 * 1024, 10*1000)
1222 if data and len(data):
1223 sys.stdout.write(bytes(data).decode('utf-8'))
1224 fReadStdOut = False
1225 if fReadStdErr:
1226 data = process.read(2, 64 * 1024, 10*1000)
1227 if data and len(data):
1228 sys.stderr.write(bytes(data).decode('utf-8'))
1229 fReadStdErr = False
1230 ctx['global'].waitForEvents(0)
1231
1232 if fCompleted:
1233 exitCode = process.exitCode
1234 if exitCode == 0:
1235 gstctlPrintOk(ctx, "process exit code: %d" % (exitCode))
1236 else:
1237 gstctlPrintErr(ctx, "process exit code: %d" % (exitCode))
1238
1239 except KeyboardInterrupt:
1240 print("Interrupted.")
1241 ctx['interrupt'] = True
1242
1243 except Exception as e:
1244 printErr(ctx, e)
1245
1246 if guestSession:
1247 try:
1248 if g_fVerbose:
1249 gstctlPrintOk(ctx, "closing guest session ...")
1250 guestSession.close()
1251 except:
1252 printErr(ctx, e)
1253
1254 return 0
1255
1256
1257def copyToGuest(ctx, console, args, user, passwd):
1258 src = args[0]
1259 dst = args[1]
1260 flags = 0
1261 print("Copying host %s to guest %s" % (src, dst))
1262 progress = console.guest.copyToGuest(src, dst, user, passwd, flags)
1263 progressBar(ctx, progress)
1264
1265def nh_raw_input(prompt=""):
1266 if prompt:
1267 sys.stdout.write(prompt)
1268 sys.stdout.flush()
1269 line = sys.stdin.readline()
1270 if not line:
1271 raise EOFError
1272 if line[-1] == '\n':
1273 line = line[:-1]
1274 return line
1275
1276def getCred(_ctx):
1277 import getpass
1278 user = getpass.getuser()
1279 if user:
1280 user_inp = nh_raw_input("User (%s): " % (user))
1281 else:
1282 user_inp = nh_raw_input("User: ")
1283 if len(user_inp) > 0:
1284 user = user_inp
1285 passwd = getpass.getpass()
1286
1287 return (user, passwd)
1288
1289def gexecCmd(ctx, args):
1290 if len(args) < 2:
1291 print("usage: gexec <vmname|uuid> command args")
1292 return 0
1293 mach = argsToMach(ctx, args)
1294 if not mach:
1295 return 0
1296 gargs = args[2:]
1297 env = [] # ["DISPLAY=:0"]
1298 (user, passwd) = getCred(ctx)
1299 gargs.insert(0, lambda ctx, mach, console, args: execInGuest(ctx, console, args, env, user, passwd, 10000))
1300 cmdExistingVm(ctx, mach, 'guestlambda', gargs)
1301 return 0
1302
1303def gcopyCmd(ctx, args):
1304 if len(args) < 2:
1305 print("usage: gcopy <vmname|uuid> host_path guest_path")
1306 return 0
1307 mach = argsToMach(ctx, args)
1308 if not mach:
1309 return 0
1310 gargs = args[2:]
1311 (user, passwd) = getCred(ctx)
1312 gargs.insert(0, lambda ctx, mach, console, args: copyToGuest(ctx, console, args, user, passwd))
1313 cmdExistingVm(ctx, mach, 'guestlambda', gargs)
1314 return 0
1315
1316def readCmdPipe(ctx, _hcmd):
1317 try:
1318 return ctx['process'].communicate()[0]
1319 except:
1320 return None
1321
1322def gpipeCmd(ctx, args):
1323 if len(args) < 4:
1324 print("usage: gpipe <vmname|uuid> hostProgram guestProgram, such as gpipe linux '/bin/uname -a' '/bin/sh -c \"/usr/bin/tee; /bin/uname -a\"'")
1325 return 0
1326 mach = argsToMach(ctx, args)
1327 if not mach:
1328 return 0
1329 hcmd = args[2]
1330 gcmd = args[3]
1331 (user, passwd) = getCred(ctx)
1332 import subprocess
1333 with subprocess.Popen(split_no_quotes(hcmd), stdout=subprocess.PIPE) as ctx['process']:
1334 gargs = split_no_quotes(gcmd)
1335 env = []
1336 gargs.insert(0, lambda ctx, mach, console, args: execInGuest(ctx, console, args, env, user, passwd, 10000, lambda ctx:readCmdPipe(ctx, hcmd)))
1337 cmdExistingVm(ctx, mach, 'guestlambda', gargs)
1338 try:
1339 ctx['process'].terminate()
1340 except:
1341 pass
1342 ctx['process'] = None
1343 return 0
1344
1345
1346def removeVmCmd(ctx, args):
1347 mach = argsToMach(ctx, args)
1348 if not mach:
1349 return 0
1350 removeVm(ctx, mach)
1351 return 0
1352
1353def pauseCmd(ctx, args):
1354 mach = argsToMach(ctx, args)
1355 if not mach:
1356 return 0
1357 cmdExistingVm(ctx, mach, 'pause', '')
1358 return 0
1359
1360def powerdownCmd(ctx, args):
1361 mach = argsToMach(ctx, args)
1362 if not mach:
1363 return 0
1364 cmdExistingVm(ctx, mach, 'powerdown', '')
1365 return 0
1366
1367def powerbuttonCmd(ctx, args):
1368 mach = argsToMach(ctx, args)
1369 if not mach:
1370 return 0
1371 cmdExistingVm(ctx, mach, 'powerbutton', '')
1372 return 0
1373
1374def resumeCmd(ctx, args):
1375 mach = argsToMach(ctx, args)
1376 if not mach:
1377 return 0
1378 cmdExistingVm(ctx, mach, 'resume', '')
1379 return 0
1380
1381def saveCmd(ctx, args):
1382 mach = argsToMach(ctx, args)
1383 if not mach:
1384 return 0
1385 cmdExistingVm(ctx, mach, 'save', '')
1386 return 0
1387
1388def statsCmd(ctx, args):
1389 mach = argsToMach(ctx, args)
1390 if not mach:
1391 return 0
1392 cmdExistingVm(ctx, mach, 'stats', '')
1393 return 0
1394
1395def guestCmd(ctx, args):
1396 if len(args) < 3:
1397 print("usage: guest <vmname|uuid> commands")
1398 return 0
1399 mach = argsToMach(ctx, args)
1400 if not mach:
1401 return 0
1402 if mach.state != ctx['const'].MachineState_Running:
1403 cmdClosedVm(ctx, mach, lambda ctx, mach, a: guestExec (ctx, mach, None, ' '.join(args[2:])))
1404 else:
1405 cmdExistingVm(ctx, mach, 'guest', ' '.join(args[2:]))
1406 return 0
1407
1408def screenshotCmd(ctx, args):
1409 if len(args) < 2:
1410 print("usage: screenshot <vmname|uuid> <file> <width> <height> <monitor>")
1411 return 0
1412 mach = argsToMach(ctx, args)
1413 if not mach:
1414 return 0
1415 cmdExistingVm(ctx, mach, 'screenshot', args[2:])
1416 return 0
1417
1418def teleportCmd(ctx, args):
1419 if len(args) < 3:
1420 print("usage: teleport <vmname|uuid> host:port <password>")
1421 return 0
1422 mach = argsToMach(ctx, args)
1423 if not mach:
1424 return 0
1425 cmdExistingVm(ctx, mach, 'teleport', args[2:])
1426 return 0
1427
1428def portalsettings(_ctx, mach, args):
1429 enabled = args[0]
1430 mach.teleporterEnabled = enabled
1431 if enabled:
1432 port = args[1]
1433 passwd = args[2]
1434 mach.teleporterPort = port
1435 mach.teleporterPassword = passwd
1436
1437def openportalCmd(ctx, args):
1438 if len(args) < 3:
1439 print("usage: openportal <vmname|uuid> port <password>")
1440 return 0
1441 mach = argsToMach(ctx, args)
1442 if not mach:
1443 return 0
1444 port = int(args[2])
1445 if len(args) > 3:
1446 passwd = args[3]
1447 else:
1448 passwd = ""
1449 if not mach.teleporterEnabled or mach.teleporterPort != port or passwd:
1450 cmdClosedVm(ctx, mach, portalsettings, [True, port, passwd])
1451 startVm(ctx, mach, "gui")
1452 return 0
1453
1454def closeportalCmd(ctx, args):
1455 if len(args) < 2:
1456 print("usage: closeportal <vmname|uuid>")
1457 return 0
1458 mach = argsToMach(ctx, args)
1459 if not mach:
1460 return 0
1461 if mach.teleporterEnabled:
1462 cmdClosedVm(ctx, mach, portalsettings, [False])
1463 return 0
1464
1465def gueststatsCmd(ctx, args):
1466 if len(args) < 2:
1467 print("usage: gueststats <vmname|uuid> <check interval>")
1468 return 0
1469 mach = argsToMach(ctx, args)
1470 if not mach:
1471 return 0
1472 cmdExistingVm(ctx, mach, 'gueststats', args[2:])
1473 return 0
1474
1475def plugcpu(_ctx, mach, args):
1476 plug = args[0]
1477 cpu = args[1]
1478 if plug:
1479 print("Adding CPU %d..." % (cpu))
1480 mach.hotPlugCPU(cpu)
1481 else:
1482 print("Removing CPU %d..." % (cpu))
1483 mach.hotUnplugCPU(cpu)
1484
1485def plugcpuCmd(ctx, args):
1486 if len(args) < 2:
1487 print("usage: plugcpu <vmname|uuid> <cpuid>")
1488 return 0
1489 mach = argsToMach(ctx, args)
1490 if not mach:
1491 return 0
1492 if str(mach.sessionState) != str(ctx['const'].SessionState_Locked):
1493 if mach.CPUHotPlugEnabled:
1494 cmdClosedVm(ctx, mach, plugcpu, [True, int(args[2])])
1495 else:
1496 cmdExistingVm(ctx, mach, 'plugcpu', args[2])
1497 return 0
1498
1499def unplugcpuCmd(ctx, args):
1500 if len(args) < 2:
1501 print("usage: unplugcpu <vmname|uuid> <cpuid>")
1502 return 0
1503 mach = argsToMach(ctx, args)
1504 if not mach:
1505 return 0
1506 if str(mach.sessionState) != str(ctx['const'].SessionState_Locked):
1507 if mach.CPUHotPlugEnabled:
1508 cmdClosedVm(ctx, mach, plugcpu, [False, int(args[2])])
1509 else:
1510 cmdExistingVm(ctx, mach, 'unplugcpu', args[2])
1511 return 0
1512
1513def setvar(_ctx, _mach, args):
1514 expr = 'mach.'+args[0]+' = '+args[1]
1515 print("Executing", expr)
1516 exec(expr) # pylint: disable=exec-used
1517
1518def setvarCmd(ctx, args):
1519 if len(args) < 4:
1520 print("usage: setvar <vmname|uuid> <expr> <value>")
1521 return 0
1522 mach = argsToMach(ctx, args)
1523 if not mach:
1524 return 0
1525 cmdClosedVm(ctx, mach, setvar, args[2:])
1526 return 0
1527
1528def setvmextra(_ctx, mach, args):
1529 key = args[0]
1530 value = args[1]
1531 print("%s: setting %s to %s" % (mach.name, key, value if value else None))
1532 mach.setExtraData(key, value)
1533
1534def setExtraDataCmd(ctx, args):
1535 if len(args) < 3:
1536 print("usage: setextra [vmname|uuid|global] key <value>")
1537 return 0
1538 key = args[2]
1539 if len(args) == 4:
1540 value = args[3]
1541 else:
1542 value = ''
1543 if args[1] == 'global':
1544 ctx['vb'].setExtraData(key, value)
1545 return 0
1546
1547 mach = argsToMach(ctx, args)
1548 if not mach:
1549 return 0
1550 cmdClosedVm(ctx, mach, setvmextra, [key, value])
1551 return 0
1552
1553def printExtraKey(obj, key, value):
1554 print("%s: '%s' = '%s'" % (obj, key, value))
1555
1556def getExtraDataCmd(ctx, args):
1557 if len(args) < 2:
1558 print("usage: getextra [vmname|uuid|global] <key>")
1559 return 0
1560 if len(args) == 3:
1561 key = args[2]
1562 else:
1563 key = None
1564
1565 if args[1] == 'global':
1566 obj = ctx['vb']
1567 else:
1568 obj = argsToMach(ctx, args)
1569 if not obj:
1570 return 0
1571
1572 if not key:
1573 keys = obj.getExtraDataKeys()
1574 else:
1575 keys = [ key ]
1576 for k in keys:
1577 printExtraKey(args[1], k, obj.getExtraData(k))
1578
1579 return 0
1580
1581def quitCmd(_ctx, _args):
1582 return 1
1583
1584def aliasCmd(_ctx, args):
1585 if len(args) == 3:
1586 aliases[args[1]] = args[2]
1587 return 0
1588
1589 for (key, value) in list(aliases.items()):
1590 print("'%s' is an alias for '%s'" % (key, value))
1591 return 0
1592
1593def verboseCmd(_ctx, args):
1594 global g_fVerbose
1595 if len(args) > 1:
1596 g_fVerbose = args[1]=='on'
1597 else:
1598 g_fVerbose = not g_fVerbose
1599 return 0
1600
1601def colorsCmd(_ctx, args):
1602 global g_fHasColors
1603 if len(args) > 1:
1604 g_fHasColors = args[1] == 'on'
1605 else:
1606 g_fHasColors = not g_fHasColors
1607 return 0
1608
1609def hostCmd(ctx, _args):
1610 vbox = ctx['vb']
1611 try:
1612 print("VirtualBox version %s" % (colored(vbox.version, 'blue')))
1613 except Exception as e:
1614 printErr(ctx, e)
1615 if g_fVerbose:
1616 traceback.print_exc()
1617 props = vbox.systemProperties
1618 print("Machines: %s" % (colPath(ctx, props.defaultMachineFolder)))
1619
1620 print("Global shared folders:")
1621 for sf in ctx['global'].getArray(vbox, 'sharedFolders'):
1622 printSf(ctx, sf)
1623 host = vbox.host
1624 cnt = host.processorCount
1625 print(colCat(ctx, "Processors:"))
1626 print(" available/online: %d/%d " % (cnt, host.processorOnlineCount))
1627 for i in range(0, cnt):
1628 print(" processor #%d speed: %dMHz %s" % (i, host.getProcessorSpeed(i), host.getProcessorDescription(i)))
1629
1630 print(colCat(ctx, "RAM:"))
1631 print(" %dM (free %dM)" % (host.memorySize, host.memoryAvailable))
1632 print(colCat(ctx, "OS:"))
1633 print(" %s (%s)" % (host.operatingSystem, host.OSVersion))
1634
1635 print(colCat(ctx, "Network interfaces:"))
1636 for iface in ctx['global'].getArray(host, 'networkInterfaces'):
1637 print(" %s (%s)" % (iface.name, iface.IPAddress))
1638
1639 print(colCat(ctx, "DVD drives:"))
1640 for drive in ctx['global'].getArray(host, 'DVDDrives'):
1641 print(" %s - %s" % (drive.name, drive.description))
1642
1643 print(colCat(ctx, "Floppy drives:"))
1644 for drive in ctx['global'].getArray(host, 'floppyDrives'):
1645 print(" %s - %s" % (drive.name, drive.description))
1646
1647 print(colCat(ctx, "USB devices:"))
1648 for usbdev in ctx['global'].getArray(host, 'USBDevices'):
1649 printHostUsbDev(ctx, usbdev)
1650
1651 if ctx['perf']:
1652 for metric in ctx['perf'].query(["*"], [host]):
1653 print(metric['name'], metric['values_as_string'])
1654
1655 return 0
1656
1657def monitorGuestCmd(ctx, args):
1658 if len(args) < 2:
1659 print("usage: monitorGuest <vmname|uuid> (duration)")
1660 return 0
1661 mach = argsToMach(ctx, args)
1662 if not mach:
1663 return 0
1664 dur = 5
1665 if len(args) > 2:
1666 dur = float(args[2])
1667 active = False
1668 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: monitorSource(ctx, console.eventSource, active, dur)])
1669 return 0
1670
1671def monitorGuestKbdCmd(ctx, args):
1672 if len(args) < 2:
1673 print("usage: monitorGuestKbd name (duration)")
1674 return 0
1675 mach = argsToMach(ctx, args)
1676 if not mach:
1677 return 0
1678 dur = 5
1679 if len(args) > 2:
1680 dur = float(args[2])
1681 active = False
1682 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: monitorSource(ctx, console.keyboard.eventSource, active, dur)])
1683 return 0
1684
1685def monitorGuestMouseCmd(ctx, args):
1686 if len(args) < 2:
1687 print("usage: monitorGuestMouse name (duration)")
1688 return 0
1689 mach = argsToMach(ctx, args)
1690 if not mach:
1691 return 0
1692 dur = 5
1693 if len(args) > 2:
1694 dur = float(args[2])
1695 active = False
1696 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: monitorSource(ctx, console.mouse.eventSource, active, dur)])
1697 return 0
1698
1699def monitorGuestMultiTouchCmd(ctx, args):
1700 if len(args) < 2:
1701 print("usage: monitorGuestMultiTouch name (duration)")
1702 return 0
1703 mach = argsToMach(ctx, args)
1704 if not mach:
1705 return 0
1706 dur = 5
1707 if len(args) > 2:
1708 dur = float(args[2])
1709 active = False
1710 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: monitorSource(ctx, console.mouse.eventSource, active, dur)])
1711 return 0
1712
1713def monitorVBoxCmd(ctx, args):
1714 if len(args) > 2:
1715 print("usage: monitorVBox (duration)")
1716 return 0
1717 dur = 5
1718 if len(args) > 1:
1719 dur = float(args[1])
1720 vbox = ctx['vb']
1721 active = False
1722 monitorSource(ctx, vbox.eventSource, active, dur)
1723 return 0
1724
1725def getAdapterType(ctx, natype):
1726 if (natype in ( ctx['global'].constants.NetworkAdapterType_Am79C970A
1727 , ctx['global'].constants.NetworkAdapterType_Am79C973
1728 , ctx['global'].constants.NetworkAdapterType_Am79C960)):
1729 return "pcnet"
1730 if (natype in ( ctx['global'].constants.NetworkAdapterType_I82540EM
1731 , ctx['global'].constants.NetworkAdapterType_I82545EM
1732 , ctx['global'].constants.NetworkAdapterType_I82543GC)):
1733 return "e1000"
1734 if natype == ctx['global'].constants.NetworkAdapterType_Virtio:
1735 return "virtio"
1736 if natype == ctx['global'].constants.NetworkAdapterType_Null:
1737 return None
1738 raise Exception("Unknown adapter type: "+natype)
1739
1740def portForwardCmd(ctx, args):
1741 if len(args) != 5:
1742 print("usage: portForward <vmname|uuid> <adapter> <hostPort> <guestPort>")
1743 return 0
1744 mach = argsToMach(ctx, args)
1745 if not mach:
1746 return 0
1747 adapterNum = int(args[2])
1748 hostPort = int(args[3])
1749 guestPort = int(args[4])
1750 proto = "TCP"
1751 session = ctx['global'].openMachineSession(mach, fPermitSharing=True)
1752 mach = session.machine
1753
1754 adapter = mach.getNetworkAdapter(adapterNum)
1755 adapterType = getAdapterType(ctx, adapter.adapterType)
1756
1757 profile_name = proto+"_"+str(hostPort)+"_"+str(guestPort)
1758 config = "VBoxInternal/Devices/" + adapterType + "/"
1759 config = config + str(adapter.slot) +"/LUN#0/Config/" + profile_name
1760
1761 mach.setExtraData(config + "/Protocol", proto)
1762 mach.setExtraData(config + "/HostPort", str(hostPort))
1763 mach.setExtraData(config + "/GuestPort", str(guestPort))
1764
1765 mach.saveSettings()
1766 session.unlockMachine()
1767
1768 return 0
1769
1770
1771def showLogCmd(ctx, args):
1772 if len(args) < 2:
1773 print("usage: showLog <vmname|uuid> <num>")
1774 return 0
1775 mach = argsToMach(ctx, args)
1776 if not mach:
1777 return 0
1778
1779 log = 0
1780 if len(args) > 2:
1781 log = args[2]
1782
1783 uOffset = 0
1784 while True:
1785 data = mach.readLog(log, uOffset, 4096)
1786 if len(data) == 0:
1787 break
1788 # print adds either NL or space to chunks not ending with a NL
1789 sys.stdout.write(str(data))
1790 uOffset += len(data)
1791
1792 return 0
1793
1794def findLogCmd(ctx, args):
1795 if len(args) < 3:
1796 print("usage: findLog <vmname|uuid> <pattern> <num>")
1797 return 0
1798 mach = argsToMach(ctx, args)
1799 if not mach:
1800 return 0
1801
1802 log = 0
1803 if len(args) > 3:
1804 log = args[3]
1805
1806 pattern = args[2]
1807 uOffset = 0
1808 while True:
1809 # to reduce line splits on buffer boundary
1810 data = mach.readLog(log, uOffset, 512*1024)
1811 if len(data) == 0:
1812 break
1813 buf = str(data).split("\n")
1814 for line in buf:
1815 match = re.findall(pattern, line)
1816 if len(match) > 0:
1817 for cur_match in match:
1818 line = line.replace(cur_match, colored(cur_match, 'red'))
1819 print(line)
1820 uOffset += len(data)
1821
1822 return 0
1823
1824
1825def findAssertCmd(ctx, args):
1826 if len(args) < 2:
1827 print("usage: findAssert <vmname|uuid> <num>")
1828 return 0
1829 mach = argsToMach(ctx, args)
1830 if not mach:
1831 return 0
1832
1833 log = 0
1834 if len(args) > 2:
1835 log = args[2]
1836
1837 uOffset = 0
1838 ere = re.compile(r'(Expression:|\!\!\!\!\!\!)')
1839 active = False
1840 context = 0
1841 while True:
1842 # to reduce line splits on buffer boundary
1843 data = mach.readLog(log, uOffset, 512*1024)
1844 if len(data) == 0:
1845 break
1846 buf = str(data).split("\n")
1847 for line in buf:
1848 if active:
1849 print(line)
1850 if context == 0:
1851 active = False
1852 else:
1853 context = context - 1
1854 continue
1855 match = ere.findall(line)
1856 if len(match) > 0:
1857 active = True
1858 context = 50
1859 print(line)
1860 uOffset += len(data)
1861
1862 return 0
1863
1864def evalCmd(ctx, args):
1865 expr = ' '.join(args[1:])
1866 try:
1867 exec(expr) # pylint: disable=exec-used
1868 except Exception as e:
1869 printErr(ctx, e)
1870 if g_fVerbose:
1871 traceback.print_exc()
1872 return 0
1873
1874def reloadExtCmd(ctx, _args):
1875 # maybe will want more args smartness
1876 checkUserExtensions(ctx, commands, getHomeFolder(ctx))
1877 autoCompletion(commands, ctx)
1878 return 0
1879
1880def runScriptCmd(ctx, args):
1881 if len(args) != 2:
1882 print("usage: runScript <script>")
1883 return 0
1884
1885 try:
1886 with open(args[1], 'r', encoding='utf-8') as file:
1887 try:
1888 lines = file.readlines()
1889 ctx['scriptLine'] = 0
1890 ctx['interrupt'] = False
1891 while ctx['scriptLine'] < len(lines):
1892 line = lines[ctx['scriptLine']]
1893 ctx['scriptLine'] = ctx['scriptLine'] + 1
1894 done = runCommand(ctx, line)
1895 if done != 0 or ctx['interrupt']:
1896 break
1897
1898 except Exception as e:
1899 printErr(ctx, e)
1900 if g_fVerbose:
1901 traceback.print_exc()
1902 file.close()
1903 except IOError as e:
1904 print("cannot open:", args[1], ":", e)
1905 return 1
1906 return 0
1907
1908def sleepCmd(_ctx, args):
1909 if len(args) != 2:
1910 print("usage: sleep <secs>")
1911 return 0
1912
1913 try:
1914 time.sleep(float(args[1]))
1915 except:
1916 # to allow sleep interrupt
1917 pass
1918 return 0
1919
1920
1921def shellCmd(_ctx, args):
1922 if len(args) < 2:
1923 print("usage: shell <commands>")
1924 return 0
1925 cmd = ' '.join(args[1:])
1926
1927 try:
1928 os.system(cmd)
1929 except KeyboardInterrupt:
1930 # to allow shell command interruption
1931 pass
1932 return 0
1933
1934
1935def connectCmd(ctx, args):
1936 if len(args) > 4:
1937 print("usage: connect url <username> <passwd>")
1938 return 0
1939
1940 if ctx['vb'] is not None:
1941 print("Already connected, disconnect first...")
1942 return 0
1943
1944 if len(args) > 1:
1945 url = args[1]
1946 else:
1947 url = None
1948
1949 if len(args) > 2:
1950 user = args[2]
1951 else:
1952 user = ""
1953
1954 if len(args) > 3:
1955 passwd = args[3]
1956 else:
1957 passwd = ""
1958
1959 ctx['wsinfo'] = [url, user, passwd]
1960 ctx['vb'] = ctx['global'].platform.connect(url, user, passwd)
1961 try:
1962 print("Running VirtualBox version %s" % (ctx['vb'].version))
1963 except Exception as e:
1964 printErr(ctx, e)
1965 if g_fVerbose:
1966 traceback.print_exc()
1967 ctx['perf'] = ctx['global'].getPerfCollector(ctx['vb'])
1968 return 0
1969
1970def disconnectCmd(ctx, args):
1971 if len(args) != 1:
1972 print("usage: disconnect")
1973 return 0
1974
1975 if ctx['vb'] is None:
1976 print("Not connected yet.")
1977 return 0
1978
1979 try:
1980 ctx['global'].platform.disconnect()
1981 except:
1982 ctx['vb'] = None
1983 raise
1984
1985 ctx['vb'] = None
1986 return 0
1987
1988def reconnectCmd(ctx, _args):
1989 if ctx['wsinfo'] is None:
1990 print("Never connected...")
1991 return 0
1992
1993 try:
1994 ctx['global'].platform.disconnect()
1995 except:
1996 pass
1997
1998 [url, user, passwd] = ctx['wsinfo']
1999 ctx['vb'] = ctx['global'].platform.connect(url, user, passwd)
2000 try:
2001 print("Running VirtualBox version %s" % (ctx['vb'].version))
2002 except Exception as e:
2003 printErr(ctx, e)
2004 if g_fVerbose:
2005 traceback.print_exc()
2006 ctx['perf'] = ctx['global'].getPerfCollector(ctx['vb'])
2007 return 0
2008
2009def exportVMCmd(ctx, args):
2010 if len(args) < 3:
2011 print("usage: exportVm <machine> <path> <format> <license>")
2012 return 0
2013 mach = argsToMach(ctx, args)
2014 if mach is None:
2015 return 0
2016 path = args[2]
2017 if len(args) > 3:
2018 fmt = args[3]
2019 else:
2020 fmt = "ovf-1.0"
2021 if len(args) > 4:
2022 lic = args[4]
2023 else:
2024 lic = "GPL"
2025
2026 app = ctx['vb'].createAppliance()
2027 desc = mach.export(app)
2028 desc.addDescription(ctx['global'].constants.VirtualSystemDescriptionType_License, lic, "")
2029 progress = app.write(fmt, path)
2030 if (progressBar(ctx, progress) and int(progress.resultCode) == 0):
2031 print("Exported to %s in format %s" % (path, fmt))
2032 else:
2033 reportError(ctx, progress)
2034 return 0
2035
2036# PC XT scancodes
2037scancodes = {
2038 'a': 0x1e,
2039 'b': 0x30,
2040 'c': 0x2e,
2041 'd': 0x20,
2042 'e': 0x12,
2043 'f': 0x21,
2044 'g': 0x22,
2045 'h': 0x23,
2046 'i': 0x17,
2047 'j': 0x24,
2048 'k': 0x25,
2049 'l': 0x26,
2050 'm': 0x32,
2051 'n': 0x31,
2052 'o': 0x18,
2053 'p': 0x19,
2054 'q': 0x10,
2055 'r': 0x13,
2056 's': 0x1f,
2057 't': 0x14,
2058 'u': 0x16,
2059 'v': 0x2f,
2060 'w': 0x11,
2061 'x': 0x2d,
2062 'y': 0x15,
2063 'z': 0x2c,
2064 '0': 0x0b,
2065 '1': 0x02,
2066 '2': 0x03,
2067 '3': 0x04,
2068 '4': 0x05,
2069 '5': 0x06,
2070 '6': 0x07,
2071 '7': 0x08,
2072 '8': 0x09,
2073 '9': 0x0a,
2074 ' ': 0x39,
2075 '-': 0xc,
2076 '=': 0xd,
2077 '[': 0x1a,
2078 ']': 0x1b,
2079 ';': 0x27,
2080 '\'': 0x28,
2081 ',': 0x33,
2082 '.': 0x34,
2083 '/': 0x35,
2084 '\t': 0xf,
2085 '\n': 0x1c,
2086 '`': 0x29
2087}
2088
2089extScancodes = {
2090 'ESC' : [0x01],
2091 'BKSP': [0xe],
2092 'SPACE': [0x39],
2093 'TAB': [0x0f],
2094 'CAPS': [0x3a],
2095 'ENTER': [0x1c],
2096 'LSHIFT': [0x2a],
2097 'RSHIFT': [0x36],
2098 'INS': [0xe0, 0x52],
2099 'DEL': [0xe0, 0x53],
2100 'END': [0xe0, 0x4f],
2101 'HOME': [0xe0, 0x47],
2102 'PGUP': [0xe0, 0x49],
2103 'PGDOWN': [0xe0, 0x51],
2104 'LGUI': [0xe0, 0x5b], # GUI, aka Win, aka Apple key
2105 'RGUI': [0xe0, 0x5c],
2106 'LCTR': [0x1d],
2107 'RCTR': [0xe0, 0x1d],
2108 'LALT': [0x38],
2109 'RALT': [0xe0, 0x38],
2110 'APPS': [0xe0, 0x5d],
2111 'F1': [0x3b],
2112 'F2': [0x3c],
2113 'F3': [0x3d],
2114 'F4': [0x3e],
2115 'F5': [0x3f],
2116 'F6': [0x40],
2117 'F7': [0x41],
2118 'F8': [0x42],
2119 'F9': [0x43],
2120 'F10': [0x44 ],
2121 'F11': [0x57],
2122 'F12': [0x58],
2123 'UP': [0xe0, 0x48],
2124 'LEFT': [0xe0, 0x4b],
2125 'DOWN': [0xe0, 0x50],
2126 'RIGHT': [0xe0, 0x4d],
2127}
2128
2129def keyDown(ch):
2130 code = scancodes.get(ch, 0x0)
2131 if code != 0:
2132 return [code]
2133 extCode = extScancodes.get(ch, [])
2134 if len(extCode) == 0:
2135 print("bad ext", ch)
2136 return extCode
2137
2138def keyUp(ch):
2139 codes = keyDown(ch)[:] # make a copy
2140 if len(codes) > 0:
2141 codes[len(codes)-1] += 0x80
2142 return codes
2143
2144def typeInGuest(console, text, delay):
2145 pressed = []
2146 group = False
2147 modGroupEnd = True
2148 i = 0
2149 kbd = console.keyboard
2150 while i < len(text):
2151 ch = text[i]
2152 i = i+1
2153 if ch == '{':
2154 # start group, all keys to be pressed at the same time
2155 group = True
2156 continue
2157 if ch == '}':
2158 # end group, release all keys
2159 for c in pressed:
2160 kbd.putScancodes(keyUp(c))
2161 pressed = []
2162 group = False
2163 continue
2164 if ch == 'W':
2165 # just wait a bit
2166 time.sleep(0.3)
2167 continue
2168 if ch in ('^', '|', '$', '_'):
2169 if ch == '^':
2170 ch = 'LCTR'
2171 if ch == '|':
2172 ch = 'LSHIFT'
2173 if ch == '_':
2174 ch = 'LALT'
2175 if ch == '$':
2176 ch = 'LGUI'
2177 if not group:
2178 modGroupEnd = False
2179 else:
2180 if ch == '\\':
2181 if i < len(text):
2182 ch = text[i]
2183 i = i+1
2184 if ch == 'n':
2185 ch = '\n'
2186 elif ch == '&':
2187 combo = ""
2188 while i < len(text):
2189 ch = text[i]
2190 i = i+1
2191 if ch == ';':
2192 break
2193 combo += ch
2194 ch = combo
2195 modGroupEnd = True
2196 kbd.putScancodes(keyDown(ch))
2197 pressed.insert(0, ch)
2198 if not group and modGroupEnd:
2199 for c in pressed:
2200 kbd.putScancodes(keyUp(c))
2201 pressed = []
2202 modGroupEnd = True
2203 time.sleep(delay)
2204
2205def typeGuestCmd(ctx, args):
2206 if len(args) < 3:
2207 print("usage: typeGuest <machine> <text> <charDelay>")
2208 return 0
2209 mach = argsToMach(ctx, args)
2210 if mach is None:
2211 return 0
2212
2213 text = args[2]
2214
2215 if len(args) > 3:
2216 delay = float(args[3])
2217 else:
2218 delay = 0.1
2219
2220 gargs = [lambda ctx, mach, console, args: typeInGuest(console, text, delay)]
2221 cmdExistingVm(ctx, mach, 'guestlambda', gargs)
2222
2223 return 0
2224
2225def optId(verbose, uuid):
2226 if verbose:
2227 return ": "+uuid
2228 return ""
2229
2230def asSize(val, inBytes):
2231 if inBytes:
2232 return int(val)/(1024*1024)
2233 return int(val)
2234
2235def listMediaCmd(ctx, args):
2236 if len(args) > 1:
2237 verbose = int(args[1])
2238 else:
2239 verbose = False
2240 hdds = ctx['global'].getArray(ctx['vb'], 'hardDisks')
2241 print(colCat(ctx, "Hard disks:"))
2242 for hdd in hdds:
2243 if hdd.state != ctx['global'].constants.MediumState_Created:
2244 hdd.refreshState()
2245 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))))
2246
2247 dvds = ctx['global'].getArray(ctx['vb'], 'DVDImages')
2248 print(colCat(ctx, "CD/DVD disks:"))
2249 for dvd in dvds:
2250 if dvd.state != ctx['global'].constants.MediumState_Created:
2251 dvd.refreshState()
2252 print(" %s (%s)%s %s" % (colPath(ctx, dvd.location), dvd.format, optId(verbose, dvd.id), colSizeM(ctx, asSize(dvd.size, True))))
2253
2254 floppys = ctx['global'].getArray(ctx['vb'], 'floppyImages')
2255 print(colCat(ctx, "Floppy disks:"))
2256 for floppy in floppys:
2257 if floppy.state != ctx['global'].constants.MediumState_Created:
2258 floppy.refreshState()
2259 print(" %s (%s)%s %s" % (colPath(ctx, floppy.location), floppy.format, optId(verbose, floppy.id), colSizeM(ctx, asSize(floppy.size, True))))
2260
2261 return 0
2262
2263def listUsbCmd(ctx, args):
2264 if len(args) > 1:
2265 print("usage: listUsb")
2266 return 0
2267
2268 host = ctx['vb'].host
2269 for usbdev in ctx['global'].getArray(host, 'USBDevices'):
2270 printHostUsbDev(ctx, usbdev)
2271
2272 return 0
2273
2274def findDevOfType(ctx, mach, devtype):
2275 attachments = ctx['global'].getArray(mach, 'mediumAttachments')
2276 for att in attachments:
2277 if att.type == devtype:
2278 return [att.controller, att.port, att.device]
2279 return [None, 0, 0]
2280
2281def createHddCmd(ctx, args):
2282 if len(args) < 3:
2283 print("usage: createHdd sizeM location type")
2284 return 0
2285
2286 size = int(args[1])
2287 loc = args[2]
2288 if len(args) > 3:
2289 fmt = args[3]
2290 else:
2291 fmt = "vdi"
2292
2293 hdd = ctx['vb'].createMedium(fmt, loc, ctx['global'].constants.AccessMode_ReadWrite, ctx['global'].constants.DeviceType_HardDisk)
2294 progress = hdd.createBaseStorage(size, (ctx['global'].constants.MediumVariant_Standard, ))
2295 if progressBar(ctx,progress) and hdd.id:
2296 print("created HDD at %s as %s" % (colPath(ctx,hdd.location), hdd.id))
2297 else:
2298 print("cannot create disk (file %s exist?)" % (loc))
2299 reportError(ctx,progress)
2300 return 0
2301
2302 return 0
2303
2304def registerHddCmd(ctx, args):
2305 if len(args) < 2:
2306 print("usage: registerHdd location")
2307 return 0
2308
2309 vbox = ctx['vb']
2310 loc = args[1]
2311 hdd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_HardDisk, ctx['global'].constants.AccessMode_ReadWrite, False)
2312 print("registered HDD as %s" % (hdd.id))
2313 return 0
2314
2315def controldevice(_ctx, mach, args):
2316 [ctr, port, slot, devtype, uuid] = args
2317 mach.attachDevice(ctr, port, slot, devtype, uuid)
2318
2319def attachHddCmd(ctx, args):
2320 if len(args) < 3:
2321 print("usage: attachHdd <vmname|uuid> <hdd> <controller> <port:slot>")
2322 return 0
2323
2324 mach = argsToMach(ctx, args)
2325 if mach is None:
2326 return 0
2327 vbox = ctx['vb']
2328 loc = args[2]
2329 try:
2330 hdd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_HardDisk, ctx['global'].constants.AccessMode_ReadWrite, False)
2331 except:
2332 print("no HDD with path %s registered" % (loc))
2333 return 0
2334 if len(args) > 3:
2335 ctr = args[3]
2336 (port, slot) = args[4].split(":")
2337 else:
2338 [ctr, port, slot] = findDevOfType(ctx, mach, ctx['global'].constants.DeviceType_HardDisk)
2339
2340 cmdClosedVm(ctx, mach, lambda ctx, mach, args: mach.attachDevice(ctr, port, slot, ctx['global'].constants.DeviceType_HardDisk, hdd.id))
2341 return 0
2342
2343def detachVmDevice(ctx, mach, args):
2344 attachments = ctx['global'].getArray(mach, 'mediumAttachments')
2345 hid = args[0]
2346 for att in attachments:
2347 if att.medium:
2348 if hid in ('ALL', att.medium.id):
2349 mach.detachDevice(att.controller, att.port, att.device)
2350
2351def detachMedium(ctx, mid, medium):
2352 cmdClosedVm(ctx, machById(ctx, mid), detachVmDevice, [medium])
2353
2354def detachHddCmd(ctx, args):
2355 if len(args) < 3:
2356 print("usage: detachHdd <vmname|uuid> <hdd>")
2357 return 0
2358
2359 mach = argsToMach(ctx, args)
2360 if mach is None:
2361 return 0
2362 vbox = ctx['vb']
2363 loc = args[2]
2364 try:
2365 hdd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_HardDisk, ctx['global'].constants.AccessMode_ReadWrite, False)
2366 except:
2367 print("no HDD with path %s registered" % (loc))
2368 return 0
2369
2370 detachMedium(ctx, mach.id, hdd)
2371 return 0
2372
2373def unregisterHddCmd(ctx, args):
2374 if len(args) < 2:
2375 print("usage: unregisterHdd path <vmunreg>")
2376 return 0
2377
2378 vbox = ctx['vb']
2379 loc = args[1]
2380 if len(args) > 2:
2381 vmunreg = int(args[2])
2382 else:
2383 vmunreg = 0
2384 try:
2385 hdd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_HardDisk, ctx['global'].constants.AccessMode_ReadWrite, False)
2386 except:
2387 print("no HDD with path %s registered" % (loc))
2388 return 0
2389
2390 if vmunreg != 0:
2391 machs = ctx['global'].getArray(hdd, 'machineIds')
2392 try:
2393 for mach in machs:
2394 print("Trying to detach from %s" % (mach))
2395 detachMedium(ctx, mach, hdd)
2396 except Exception as e:
2397 print('failed: ', e)
2398 return 0
2399 hdd.close()
2400 return 0
2401
2402def removeHddCmd(ctx, args):
2403 if len(args) != 2:
2404 print("usage: removeHdd path")
2405 return 0
2406
2407 vbox = ctx['vb']
2408 loc = args[1]
2409 try:
2410 hdd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_HardDisk, ctx['global'].constants.AccessMode_ReadWrite, False)
2411 except:
2412 print("no HDD with path %s registered" % (loc))
2413 return 0
2414
2415 progress = hdd.deleteStorage()
2416 progressBar(ctx, progress)
2417
2418 return 0
2419
2420def registerIsoCmd(ctx, args):
2421 if len(args) < 2:
2422 print("usage: registerIso location")
2423 return 0
2424
2425 vbox = ctx['vb']
2426 loc = args[1]
2427 iso = vbox.openMedium(loc, ctx['global'].constants.DeviceType_DVD, ctx['global'].constants.AccessMode_ReadOnly, False)
2428 print("registered ISO as %s" % (iso.id))
2429 return 0
2430
2431def unregisterIsoCmd(ctx, args):
2432 if len(args) != 2:
2433 print("usage: unregisterIso path")
2434 return 0
2435
2436 vbox = ctx['vb']
2437 loc = args[1]
2438 try:
2439 vbox.openMedium(loc, ctx['global'].constants.DeviceType_DVD, ctx['global'].constants.AccessMode_ReadOnly, False)
2440 except:
2441 print("no DVD with path %s registered" % (loc))
2442 return 0
2443
2444 print("Unregistered ISO at %s" % (colPath(ctx, loc)))
2445 return 0
2446
2447def removeIsoCmd(ctx, args):
2448 if len(args) != 2:
2449 print("usage: removeIso path")
2450 return 0
2451
2452 vbox = ctx['vb']
2453 loc = args[1]
2454 try:
2455 dvd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_DVD, ctx['global'].constants.AccessMode_ReadOnly, False)
2456 except:
2457 print("no DVD with path %s registered" % (loc))
2458 return 0
2459
2460 progress = dvd.deleteStorage()
2461 if progressBar(ctx, progress):
2462 print("Removed ISO at %s" % (colPath(ctx, dvd.location)))
2463 else:
2464 reportError(ctx, progress)
2465 return 0
2466
2467def attachIsoCmd(ctx, args):
2468 if len(args) < 3:
2469 print("usage: attachIso <vmname|uuid> <iso> <controller> <port:slot>")
2470 return 0
2471
2472 mach = argsToMach(ctx, args)
2473 if mach is None:
2474 return 0
2475 vbox = ctx['vb']
2476 loc = args[2]
2477 try:
2478 dvd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_DVD, ctx['global'].constants.AccessMode_ReadOnly, False)
2479 except:
2480 print("no DVD with path %s registered" % (loc))
2481 return 0
2482 if len(args) > 3:
2483 ctr = args[3]
2484 (port, slot) = args[4].split(":")
2485 else:
2486 [ctr, port, slot] = findDevOfType(ctx, mach, ctx['global'].constants.DeviceType_DVD)
2487 cmdClosedVm(ctx, mach, lambda ctx, mach, args: mach.attachDevice(ctr, port, slot, ctx['global'].constants.DeviceType_DVD, dvd))
2488 return 0
2489
2490def detachIsoCmd(ctx, args):
2491 if len(args) < 3:
2492 print("usage: detachIso <vmname|uuid> <iso>")
2493 return 0
2494
2495 mach = argsToMach(ctx, args)
2496 if mach is None:
2497 return 0
2498 vbox = ctx['vb']
2499 loc = args[2]
2500 try:
2501 dvd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_DVD, ctx['global'].constants.AccessMode_ReadOnly, False)
2502 except:
2503 print("no DVD with path %s registered" % (loc))
2504 return 0
2505
2506 detachMedium(ctx, mach.id, dvd)
2507 return 0
2508
2509def mountIsoCmd(ctx, args):
2510 if len(args) < 3:
2511 print("usage: mountIso <vmname|uuid> <iso> <controller> <port:slot>")
2512 return 0
2513
2514 mach = argsToMach(ctx, args)
2515 if mach is None:
2516 return 0
2517 vbox = ctx['vb']
2518 loc = args[2]
2519 try:
2520 dvd = vbox.openMedium(loc, ctx['global'].constants.DeviceType_DVD, ctx['global'].constants.AccessMode_ReadOnly, False)
2521 except:
2522 print("no DVD with path %s registered" % (loc))
2523 return 0
2524
2525 if len(args) > 3:
2526 ctr = args[3]
2527 (port, slot) = args[4].split(":")
2528 else:
2529 # autodetect controller and location, just find first controller with media == DVD
2530 [ctr, port, slot] = findDevOfType(ctx, mach, ctx['global'].constants.DeviceType_DVD)
2531
2532 cmdExistingVm(ctx, mach, 'mountiso', [ctr, port, slot, dvd, True])
2533
2534 return 0
2535
2536def unmountIsoCmd(ctx, args):
2537 if len(args) < 2:
2538 print("usage: unmountIso <vmname|uuid> <controller> <port:slot>")
2539 return 0
2540
2541 mach = argsToMach(ctx, args)
2542 if mach is None:
2543 return 0
2544
2545 if len(args) > 3:
2546 ctr = args[2]
2547 (port, slot) = args[3].split(":")
2548 else:
2549 # autodetect controller and location, just find first controller with media == DVD
2550 [ctr, port, slot] = findDevOfType(ctx, mach, ctx['global'].constants.DeviceType_DVD)
2551
2552 cmdExistingVm(ctx, mach, 'mountiso', [ctr, port, slot, None, True])
2553
2554 return 0
2555
2556def attachCtr(_ctx, mach, args):
2557 [name, bus, ctrltype] = args
2558 ctr = mach.addStorageController(name, bus)
2559 if ctrltype:
2560 ctr.controllerType = ctrltype
2561
2562def attachCtrCmd(ctx, args):
2563 if len(args) < 4:
2564 print("usage: attachCtr <vmname|uuid> <controller name> <bus> <type>")
2565 return 0
2566
2567 if len(args) > 4:
2568 ctrltype = enumFromString(ctx, 'StorageControllerType', args[4])
2569 if not ctrltype:
2570 print("Controller type %s unknown" % (args[4]))
2571 return 0
2572 else:
2573 ctrltype = None
2574
2575 mach = argsToMach(ctx, args)
2576 if mach is None:
2577 return 0
2578 bus = enumFromString(ctx, 'StorageBus', args[3])
2579 if bus is None:
2580 print("Bus type %s unknown" % (args[3]))
2581 return 0
2582 name = args[2]
2583 cmdClosedVm(ctx, mach, attachCtr, [name, bus, ctrltype])
2584 return 0
2585
2586def detachCtrCmd(ctx, args):
2587 if len(args) < 3:
2588 print("usage: detachCtr <vmname|uuid> <controller name>")
2589 return 0
2590
2591 mach = argsToMach(ctx, args)
2592 if mach is None:
2593 return 0
2594 ctr = args[2]
2595 cmdClosedVm(ctx, mach, lambda ctx, mach, args: mach.removeStorageController(ctr))
2596 return 0
2597
2598def usbctr(_ctx, _mach, console, args):
2599 if args[0]:
2600 console.attachUSBDevice(args[1], "")
2601 else:
2602 console.detachUSBDevice(args[1])
2603
2604def attachUsbCmd(ctx, args):
2605 if len(args) < 3:
2606 print("usage: attachUsb <vmname|uuid> <device uid>")
2607 return 0
2608
2609 mach = argsToMach(ctx, args)
2610 if mach is None:
2611 return 0
2612 dev = args[2]
2613 cmdExistingVm(ctx, mach, 'guestlambda', [usbctr, True, dev])
2614 return 0
2615
2616def detachUsbCmd(ctx, args):
2617 if len(args) < 3:
2618 print("usage: detachUsb <vmname|uuid> <device uid>")
2619 return 0
2620
2621 mach = argsToMach(ctx, args)
2622 if mach is None:
2623 return 0
2624 dev = args[2]
2625 cmdExistingVm(ctx, mach, 'guestlambda', [usbctr, False, dev])
2626 return 0
2627
2628
2629def guiCmd(ctx, args):
2630 if len(args) > 1:
2631 print("usage: gui")
2632 return 0
2633
2634 binDir = ctx['global'].getBinDir()
2635
2636 vbox = os.path.join(binDir, 'VirtualBox')
2637 try:
2638 os.system(vbox)
2639 except KeyboardInterrupt:
2640 # to allow interruption
2641 pass
2642 return 0
2643
2644def shareFolderCmd(ctx, args):
2645 if len(args) < 4:
2646 print("usage: shareFolder <vmname|uuid> <path> <name> <writable|persistent>")
2647 return 0
2648
2649 if args[1] != 'global':
2650 mach = argsToMach(ctx, args)
2651 if mach is None:
2652 return 0
2653 path = args[2]
2654 name = args[3]
2655 writable = False
2656 persistent = False
2657 if len(args) > 4:
2658 for cur_arg in args[4:]:
2659 if cur_arg == 'writable':
2660 writable = True
2661 if cur_arg == 'persistent':
2662 persistent = True
2663 if args[1] == 'global':
2664 ctx['vb'].createSharedFolder(name, path, writable)
2665 elif persistent:
2666 cmdClosedVm(ctx, mach, lambda ctx, mach, args: mach.createSharedFolder(name, path, writable), [])
2667 else:
2668 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: console.createSharedFolder(name, path, writable)])
2669 return 0
2670
2671def unshareFolderCmd(ctx, args):
2672 if len(args) < 3:
2673 print("usage: unshareFolder <vmname|uuid> <name>")
2674 return 0
2675
2676 if args[1] != 'global':
2677 mach = argsToMach(ctx, args)
2678 if mach is None:
2679 return 0
2680 name = args[2]
2681 found = False
2682 if args[1] == 'global':
2683 for sharedfolder in ctx['global'].getArray(ctx['vb'], 'sharedFolders'):
2684 if sharedfolder.name == name:
2685 ctx['vb'].removeSharedFolder(name)
2686 found = True
2687 break
2688 else:
2689 for sharedfolder in ctx['global'].getArray(mach, 'sharedFolders'):
2690 if sharedfolder.name == name:
2691 cmdClosedVm(ctx, mach, lambda ctx, mach, args: mach.removeSharedFolder(name), [])
2692 found = True
2693 break
2694 if not found:
2695 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: console.removeSharedFolder(name)])
2696 return 0
2697
2698
2699def snapshotCmd(ctx, args):
2700 if (len(args) < 2 or args[1] == 'help'):
2701 print("Take snapshot: snapshot <vmname|uuid> take <name> <description>")
2702 print("Restore snapshot: snapshot <vmname|uuid> restore <name>")
2703 print("Merge snapshot: snapshot <vmname|uuid> merge <name>")
2704 return 0
2705
2706 mach = argsToMach(ctx, args)
2707 if mach is None:
2708 return 0
2709 cmd = args[2]
2710 if cmd == 'take':
2711 if len(args) < 4:
2712 print("usage: snapshot <vmname|uuid> take <name> <description>")
2713 return 0
2714 name = args[3]
2715 if len(args) > 4:
2716 desc = args[4]
2717 else:
2718 desc = ""
2719 cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, mach.takeSnapshot(name, desc, True)[0]))
2720 return 0
2721
2722 if cmd == 'restore':
2723 if len(args) < 4:
2724 print("usage: snapshot <vmname|uuid> restore <name>")
2725 return 0
2726 name = args[3]
2727 snap = mach.findSnapshot(name)
2728 cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, mach.restoreSnapshot(snap)))
2729 return 0
2730
2731 if cmd == 'restorecurrent':
2732 if len(args) < 4:
2733 print("usage: snapshot <vmname|uuid> restorecurrent")
2734 return 0
2735 snap = mach.currentSnapshot()
2736 cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, mach.restoreSnapshot(snap)))
2737 return 0
2738
2739 if cmd == 'delete':
2740 if len(args) < 4:
2741 print("usage: snapshot <vmname|uuid> delete <name>")
2742 return 0
2743 name = args[3]
2744 snap = mach.findSnapshot(name)
2745 cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, mach.deleteSnapshot(snap.id)))
2746 return 0
2747
2748 print("Command '%s' is unknown" % (cmd))
2749 return 0
2750
2751def natAlias(_ctx, _mach, _nicnum, nat, args=None):
2752 """This command shows/alters NAT's alias settings.
2753 usage: nat <vmname|uuid> <nicnum> alias [default|[log] [proxyonly] [sameports]]
2754 default - set settings to default values
2755 log - switch on alias logging
2756 proxyonly - switch proxyonly mode on
2757 sameports - enforces NAT using the same ports
2758 """
2759 alias = {
2760 'log': 0x1,
2761 'proxyonly': 0x2,
2762 'sameports': 0x4
2763 }
2764 if len(args) == 1:
2765 first = 0
2766 msg = ''
2767 for aliasmode, aliaskey in list(alias.items()):
2768 if first == 0:
2769 first = 1
2770 else:
2771 msg += ', '
2772 if int(nat.aliasMode) & aliaskey:
2773 msg += '%s: %s' % (aliasmode, 'on')
2774 else:
2775 msg += '%s: %s' % (aliasmode, 'off')
2776 return (0, [msg])
2777
2778 nat.aliasMode = 0
2779 if 'default' not in args:
2780 for idx in range(1, len(args)):
2781 if args[idx] not in alias:
2782 print('Invalid alias mode: ' + args[idx])
2783 print(natAlias.__doc__)
2784 return (1, None)
2785 nat.aliasMode = int(nat.aliasMode) | alias[args[idx]]
2786 return (0, None)
2787
2788def natSettings(_ctx, _mach, _nicnum, nat, args):
2789 """
2790 This command shows/alters NAT settings.
2791 usage: nat <vmname|uuid> <nicnum> settings [<mtu> [[<socsndbuf> <sockrcvbuf> [<tcpsndwnd> <tcprcvwnd>]]]]
2792 mtu - set mtu <= 16000
2793 socksndbuf/sockrcvbuf - sets amount of kb for socket sending/receiving buffer
2794 tcpsndwnd/tcprcvwnd - sets size of initial tcp sending/receiving window
2795 """
2796 if len(args) == 1:
2797 (mtu, socksndbuf, sockrcvbuf, tcpsndwnd, tcprcvwnd) = nat.getNetworkSettings()
2798 if mtu == 0: mtu = 1500
2799 if socksndbuf == 0: socksndbuf = 64
2800 if sockrcvbuf == 0: sockrcvbuf = 64
2801 if tcpsndwnd == 0: tcpsndwnd = 64
2802 if tcprcvwnd == 0: tcprcvwnd = 64
2803 msg = 'mtu:%s socket(snd:%s, rcv:%s) tcpwnd(snd:%s, rcv:%s)' % (mtu, socksndbuf, sockrcvbuf, tcpsndwnd, tcprcvwnd)
2804 return (0, [msg])
2805
2806 if args[1] < 16000:
2807 print('invalid mtu value (%s not in range [65 - 16000])' % (args[1]))
2808 return (1, None)
2809 for i in range(2, len(args)):
2810 if not args[i].isdigit() or int(args[i]) < 8 or int(args[i]) > 1024:
2811 print('invalid %s parameter (%i not in range [8-1024])' % (i, args[i]))
2812 return (1, None)
2813 nic_args = [args[1]]
2814 if len(args) < 6:
2815 for i in range(2, len(args)): nic_args.append(args[i])
2816 for i in range(len(args), 6): nic_args.append(0)
2817 else:
2818 for i in range(2, len(args)): nic_args.append(args[i])
2819 #print(a)
2820 nat.setNetworkSettings(int(nic_args[0]), int(nic_args[1]), int(nic_args[2]), int(nic_args[3]), int(nic_args[4]))
2821 return (0, None)
2822
2823def natDns(_ctx, _mach, _nicnum, nat, args):
2824 """This command shows/alters DNS's NAT settings
2825 usage: nat <vmname|uuid> <nicnum> dns [passdomain] [proxy] [usehostresolver]
2826 passdomain - enforces builtin DHCP server to pass domain
2827 proxy - switch on builtin NAT DNS proxying mechanism
2828 usehostresolver - proxies all DNS requests to Host Resolver interface
2829 """
2830 yesno = {0: 'off', 1: 'on'}
2831 if len(args) == 1:
2832 msg = 'passdomain:%s, proxy:%s, usehostresolver:%s' % (yesno[int(nat.DNSPassDomain)], yesno[int(nat.DNSProxy)], yesno[int(nat.DNSUseHostResolver)])
2833 return (0, [msg])
2834
2835 nat.DNSPassDomain = 'passdomain' in args
2836 nat.DNSProxy = 'proxy' in args
2837 nat.DNSUseHostResolver = 'usehostresolver' in args
2838 return (0, None)
2839
2840def natTftp(ctx, mach, nicnum, nat, args):
2841 """This command shows/alters TFTP settings
2842 usage nat <vmname|uuid> <nicnum> tftp [prefix <prefix>| bootfile <bootfile>| server <server>]
2843 prefix - alters prefix TFTP settings
2844 bootfile - alters bootfile TFTP settings
2845 server - sets booting server
2846 """
2847 if len(args) == 1:
2848 server = nat.TFTPNextServer
2849 if server is None:
2850 server = nat.network
2851 if server is None:
2852 server = '10.0.%d/24' % (int(nicnum) + 2)
2853 (server, _mask) = server.split('/')
2854 while server.count('.') != 3:
2855 server += '.0'
2856 (ipA, ipB, ipC, _ipD) = server.split('.')
2857 server = '%d.%d.%d.4' % (ipA, ipB, ipC)
2858 prefix = nat.TFTPPrefix
2859 if prefix is None:
2860 prefix = '%s/TFTP/' % (ctx['vb'].homeFolder)
2861 bootfile = nat.TFTPBootFile
2862 if bootfile is None:
2863 bootfile = '%s.pxe' % (mach.name)
2864 msg = 'server:%s, prefix:%s, bootfile:%s' % (server, prefix, bootfile)
2865 return (0, [msg])
2866
2867 cmd = args[1]
2868 if len(args) != 3:
2869 print('invalid args:', args)
2870 print(natTftp.__doc__)
2871 return (1, None)
2872 if cmd == 'prefix': nat.TFTPPrefix = args[2]
2873 elif cmd == 'bootfile': nat.TFTPBootFile = args[2]
2874 elif cmd == 'server': nat.TFTPNextServer = args[2]
2875 else:
2876 print("invalid cmd:", cmd)
2877 return (1, None)
2878 return (0, None)
2879
2880def natPortForwarding(ctx, _mach, _nicnum, nat, args):
2881 """This command shows/manages port-forwarding settings
2882 usage:
2883 nat <vmname|uuid> <nicnum> <pf> [ simple tcp|udp <hostport> <guestport>]
2884 |[no_name tcp|udp <hostip> <hostport> <guestip> <guestport>]
2885 |[ex tcp|udp <pf-name> <hostip> <hostport> <guestip> <guestport>]
2886 |[delete <pf-name>]
2887 """
2888 if len(args) == 1:
2889 # note: keys/values are swapped in defining part of the function
2890 proto = {0: 'udp', 1: 'tcp'}
2891 msg = []
2892 port_forwardings = ctx['global'].getArray(nat, 'redirects')
2893 for forwarding in port_forwardings:
2894 (pfnme, pfp, pfhip, pfhp, pfgip, pfgp) = str(forwarding).split(', ')
2895 msg.append('%s: %s %s:%s => %s:%s' % (pfnme, proto[int(pfp)], pfhip, pfhp, pfgip, pfgp))
2896 return (0, msg) # msg is array
2897
2898 proto = {'udp': 0, 'tcp': 1}
2899 pfcmd = {
2900 'simple': {
2901 'validate': lambda: args[1] in list(pfcmd) and args[2] in list(proto) and len(args) == 5,
2902 'func':lambda: nat.addRedirect('', proto[args[2]], '', int(args[3]), '', int(args[4]))
2903 },
2904 'no_name': {
2905 'validate': lambda: args[1] in list(pfcmd) and args[2] in list(proto) and len(args) == 7,
2906 'func': lambda: nat.addRedirect('', proto[args[2]], args[3], int(args[4]), args[5], int(args[6]))
2907 },
2908 'ex': {
2909 'validate': lambda: args[1] in list(pfcmd) and args[2] in list(proto) and len(args) == 8,
2910 'func': lambda: nat.addRedirect(args[3], proto[args[2]], args[4], int(args[5]), args[6], int(args[7]))
2911 },
2912 'delete': {
2913 'validate': lambda: len(args) == 3,
2914 'func': lambda: nat.removeRedirect(args[2])
2915 }
2916 }
2917
2918 if not pfcmd[args[1]]['validate']():
2919 print('invalid port-forwarding or args of sub command ', args[1])
2920 print(natPortForwarding.__doc__)
2921 return (1, None)
2922
2923 _not_sure_for_what_this_is = pfcmd[args[1]]['func']()
2924 return (0, None)
2925
2926def natNetwork(_ctx, _mach, nicnum, nat, args):
2927 """This command shows/alters NAT network settings
2928 usage: nat <vmname|uuid> <nicnum> network [<network>]
2929 """
2930 if len(args) == 1:
2931 if nat.network is not None and len(str(nat.network)) != 0:
2932 msg = '\'%s\'' % (nat.network)
2933 else:
2934 msg = '10.0.%d.0/24' % (int(nicnum) + 2)
2935 return (0, [msg])
2936
2937 (addr, mask) = args[1].split('/')
2938 if addr.count('.') > 3 or int(mask) < 0 or int(mask) > 32:
2939 print('Invalid arguments')
2940 return (1, None)
2941 nat.network = args[1]
2942 return (0, None)
2943
2944def natCmd(ctx, args):
2945 """This command is entry point to NAT settins management
2946 usage: nat <vmname|uuid> <nicnum> <cmd> <cmd-args>
2947 cmd - [alias|settings|tftp|dns|pf|network]
2948 for more information about commands:
2949 nat help <cmd>
2950 """
2951
2952 natcommands = {
2953 'alias' : natAlias,
2954 'settings' : natSettings,
2955 'tftp': natTftp,
2956 'dns': natDns,
2957 'pf': natPortForwarding,
2958 'network': natNetwork
2959 }
2960
2961 if len(args) < 2 or args[1] == 'help':
2962 if len(args) > 2:
2963 print(natcommands[args[2]].__doc__)
2964 else:
2965 print(natCmd.__doc__)
2966 return 0
2967 if len(args) == 1 or len(args) < 4 or args[3] not in natcommands:
2968 print(natCmd.__doc__)
2969 return 0
2970 mach = argsToMach(ctx, args)
2971 if not mach:
2972 print("please specify vm")
2973 return 0
2974 platformProps = mach.platform.properties
2975 if len(args) < 3 or not args[2].isdigit() or int(args[2]) not in list(range(0, platformProps.getMaxNetworkAdapters(mach.platform.chipsetType))):
2976 print('please specify adapter num %d isn\'t in range [0-%d]' % (args[2], platformProps.getMaxNetworkAdapters(mach.platform.chipsetType)))
2977 return 0
2978 nicnum = int(args[2])
2979 cmdargs = []
2980 for i in range(3, len(args)):
2981 cmdargs.append(args[i])
2982
2983 # @todo vvl if nicnum is missed but command is entered
2984 # use NAT func for every adapter on machine.
2985 func = args[3]
2986 rosession = 1
2987 session = None
2988 if len(cmdargs) > 1:
2989 rosession = 0
2990 session = ctx['global'].openMachineSession(mach, fPermitSharing=False)
2991 mach = session.machine
2992
2993 adapter = mach.getNetworkAdapter(nicnum)
2994 natEngine = adapter.NATEngine
2995 (rc, reports) = natcommands[func](ctx, mach, nicnum, natEngine, cmdargs)
2996 if rosession == 0:
2997 if rc == 0:
2998 mach.saveSettings()
2999 session.unlockMachine()
3000 elif reports:
3001 for cur_report in reports:
3002 msg ='%s nic%d %s: %s' % (mach.name, nicnum, func, cur_report)
3003 print(msg)
3004 return 0
3005
3006def nicSwitchOnOff(adapter, attr, args):
3007 if len(args) == 1:
3008 yesno = {0: 'off', 1: 'on'}
3009 resp = yesno[int(adapter.getattr(attr))]
3010 return (0, resp)
3011
3012 yesno = {'off' : 0, 'on' : 1}
3013 if args[1] not in yesno:
3014 print('%s isn\'t acceptable, please choose %s' % (args[1], list(yesno.keys())))
3015 return (1, None)
3016 adapter.setsetattr(attr, yesno[args[1]])
3017 return (0, None)
3018
3019def nicTraceSubCmd(_ctx, _vm, _nicnum, adapter, args):
3020 '''
3021 usage: nic <vmname|uuid> <nicnum> trace [on|off [file]]
3022 '''
3023 (rc, resp) = nicSwitchOnOff(adapter, 'traceEnabled', args)
3024 if len(args) == 1 and rc == 0:
3025 resp = '%s file:%s' % (resp, adapter.traceFile)
3026 return (0, resp)
3027 if len(args) == 3 and rc == 0:
3028 adapter.traceFile = args[2]
3029 return (0, None)
3030
3031def nicLineSpeedSubCmd(_ctx, _vm, _nicnum, adapter, args):
3032 if len(args) == 1:
3033 resp = '%d kbps'% (adapter.lineSpeed)
3034 return (0, resp)
3035
3036 if not args[1].isdigit():
3037 print('%s isn\'t a number' % (args[1]))
3038 return (1, None)
3039 adapter.lineSpeed = int(args[1])
3040 return (0, None)
3041
3042def nicCableSubCmd(_ctx, _vm, _nicnum, adapter, args):
3043 '''
3044 usage: nic <vmname|uuid> <nicnum> cable [on|off]
3045 '''
3046 return nicSwitchOnOff(adapter, 'cableConnected', args)
3047
3048def nicEnableSubCmd(_ctx, _vm, _nicnum, adapter, args):
3049 '''
3050 usage: nic <vmname|uuid> <nicnum> enable [on|off]
3051 '''
3052 return nicSwitchOnOff(adapter, 'enabled', args)
3053
3054def nicTypeSubCmd(ctx, _vm, _nicnum, adapter, args):
3055 '''
3056 usage: nic <vmname|uuid> <nicnum> type [Am79c970A|Am79c970A|I82540EM|I82545EM|I82543GC|Virtio]
3057 '''
3058 if len(args) == 1:
3059 nictypes = ctx['const'].all_values('NetworkAdapterType')
3060 for key in list(nictypes.keys()):
3061 if str(adapter.adapterType) == str(nictypes[key]):
3062 return (0, str(key))
3063 return (1, None)
3064
3065 nictypes = ctx['const'].all_values('NetworkAdapterType')
3066 if args[1] not in list(nictypes.keys()):
3067 print('%s not in acceptable values (%s)' % (args[1], list(nictypes.keys())))
3068 return (1, None)
3069 adapter.adapterType = nictypes[args[1]]
3070 return (0, None)
3071
3072def nicAttachmentSubCmd(ctx, _vm, _nicnum, adapter, args):
3073 '''
3074 usage: nic <vmname|uuid> <nicnum> attachment [Null|NAT|Bridged <interface>|Internal <name>|HostOnly <interface>
3075 '''
3076 if len(args) == 1:
3077 nicAttachmentType = {
3078 ctx['global'].constants.NetworkAttachmentType_Null: ('Null', ''),
3079 ctx['global'].constants.NetworkAttachmentType_NAT: ('NAT', ''),
3080 ctx['global'].constants.NetworkAttachmentType_Bridged: ('Bridged', adapter.bridgedInterface),
3081 ctx['global'].constants.NetworkAttachmentType_Internal: ('Internal', adapter.internalNetwork),
3082 ctx['global'].constants.NetworkAttachmentType_HostOnly: ('HostOnly', adapter.hostOnlyInterface),
3083 # @todo show details of the generic network attachment type
3084 ctx['global'].constants.NetworkAttachmentType_Generic: ('Generic', ''),
3085 }
3086 if not isinstance(adapter.attachmentType, int):
3087 t = str(adapter.attachmentType)
3088 else:
3089 t = adapter.attachmentType
3090 (resp, name) = nicAttachmentType[t]
3091 return (0, 'attachment:%s, name:%s' % (resp, name))
3092
3093 nicAttachmentType = {
3094 'Null': {
3095 'v': lambda: len(args) == 2,
3096 'p': lambda: 'do nothing',
3097 'f': lambda: ctx['global'].constants.NetworkAttachmentType_Null},
3098 'NAT': {
3099 'v': lambda: len(args) == 2,
3100 'p': lambda: 'do nothing',
3101 'f': lambda: ctx['global'].constants.NetworkAttachmentType_NAT},
3102 'Bridged': {
3103 'v': lambda: len(args) == 3,
3104 'p': lambda: adapter.setattr('bridgedInterface', args[2]),
3105 'f': lambda: ctx['global'].constants.NetworkAttachmentType_Bridged},
3106 'Internal': {
3107 'v': lambda: len(args) == 3,
3108 'p': lambda: adapter.setattr('internalNetwork', args[2]),
3109 'f': lambda: ctx['global'].constants.NetworkAttachmentType_Internal},
3110 'HostOnly': {
3111 'v': lambda: len(args) == 2,
3112 'p': lambda: adapter.setattr('hostOnlyInterface', args[2]),
3113 'f': lambda: ctx['global'].constants.NetworkAttachmentType_HostOnly},
3114 # @todo implement setting the properties of a generic attachment
3115 'Generic': {
3116 'v': lambda: len(args) == 3,
3117 'p': lambda: 'do nothing',
3118 'f': lambda: ctx['global'].constants.NetworkAttachmentType_Generic}
3119 }
3120 if args[1] not in list(nicAttachmentType):
3121 print('%s not in acceptable values (%s)' % (args[1], list(nicAttachmentType.keys())))
3122 return (1, None)
3123 if not nicAttachmentType[args[1]]['v']():
3124 ## @todo r=andy Log this properly!
3125 return (1, None)
3126 nicAttachmentType[args[1]]['p']()
3127 adapter.attachmentType = nicAttachmentType[args[1]]['f']()
3128 return (0, None)
3129
3130def nicCmd(ctx, args):
3131 '''
3132 This command to manage network adapters
3133 usage: nic <vmname|uuid> <nicnum> <cmd> <cmd-args>
3134 where cmd : attachment, trace, linespeed, cable, enable, type
3135 '''
3136 # 'command name':{'runtime': is_callable_at_runtime, 'op': function_name}
3137 niccomand = {
3138 'attachment': nicAttachmentSubCmd,
3139 'trace': nicTraceSubCmd,
3140 'linespeed': nicLineSpeedSubCmd,
3141 'cable': nicCableSubCmd,
3142 'enable': nicEnableSubCmd,
3143 'type': nicTypeSubCmd
3144 }
3145 if len(args) < 2 \
3146 or args[1] == 'help' \
3147 or (len(args) > 2 and args[3] not in niccomand):
3148 if len(args) == 3 \
3149 and args[2] in niccomand:
3150 print(niccomand[args[2]].__doc__)
3151 else:
3152 print(nicCmd.__doc__)
3153 return 0
3154
3155 mach = ctx['argsToMach'](args)
3156 if not mach:
3157 return 1
3158
3159 platformProps = mach.platform.properties
3160 if len(args) < 3 \
3161 or int(args[2]) not in list(range(0, platformProps.getMaxNetworkAdapters(mach.platform.chipsetType))):
3162 print('please specify adapter num %d isn\'t in range [0-%d]'% (args[2], platformProps.getMaxNetworkAdapters(mach.platform.chipsetType)))
3163 return 1
3164 nicnum = int(args[2])
3165 cmdargs = args[3:]
3166 func = args[3]
3167 session = None
3168 session = ctx['global'].openMachineSession(mach, fPermitSharing=True)
3169 mach = session.machine
3170 adapter = mach.getNetworkAdapter(nicnum)
3171 (rc, report) = niccomand[func](ctx, mach, nicnum, adapter, cmdargs)
3172 if rc == 0:
3173 mach.saveSettings()
3174 if report is not None:
3175 print('%s nic %d %s: %s' % (mach.name, nicnum, args[3], report))
3176 session.unlockMachine()
3177 return 0
3178
3179
3180def promptCmd(ctx, args):
3181 if len(args) < 2:
3182 print("Current prompt: '%s'" % (ctx['prompt']))
3183 return 0
3184
3185 ctx['prompt'] = args[1]
3186 return 0
3187
3188def foreachCmd(ctx, args):
3189 if len(args) < 3:
3190 print("usage: foreach scope command, where scope is XPath-like expression //vms/vm[@CPUCount='2']")
3191 return 0
3192
3193 scope = args[1]
3194 cmd = args[2]
3195 elems = eval_xpath(ctx, scope)
3196 try:
3197 for e in elems:
3198 e.apply(cmd)
3199 except:
3200 print("Error executing")
3201 traceback.print_exc()
3202 return 0
3203
3204def foreachvmCmd(ctx, args):
3205 if len(args) < 2:
3206 print("foreachvm command <args>")
3207 return 0
3208 cmdargs = args[1:]
3209 cmdargs.insert(1, '')
3210 for mach in getMachines(ctx):
3211 cmdargs[1] = mach.id
3212 runCommandArgs(ctx, cmdargs)
3213 return 0
3214
3215def recordDemoCmd(ctx, args):
3216 if len(args) < 3:
3217 print("usage: recordDemo <vmname|uuid> <filename> [duration in s]")
3218 return 0
3219 mach = argsToMach(ctx, args)
3220 if not mach:
3221 return 0
3222 filename = args[2]
3223 dur = 10000
3224 if len(args) > 3:
3225 dur = float(args[3])
3226 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: recordDemo(ctx, console, filename, dur)])
3227 return 0
3228
3229def playbackDemoCmd(ctx, args):
3230 if len(args) < 3:
3231 print("usage: playbackDemo <vmname|uuid> <filename> [duration in s]")
3232 return 0
3233 mach = argsToMach(ctx, args)
3234 if not mach:
3235 return 0
3236 filename = args[2]
3237 dur = 10000
3238 if len(args) > 3:
3239 dur = float(args[3])
3240 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: playbackDemo(ctx, console, filename, dur)])
3241 return 0
3242
3243
3244def pciAddr(ctx, addr):
3245 strg = "%02x:%02x.%d" % (addr >> 8, (addr & 0xff) >> 3, addr & 7)
3246 return colPci(ctx, strg)
3247
3248def lspci(ctx, console):
3249 assigned = ctx['global'].getArray(console.machine, 'PCIDeviceAssignments')
3250 for assignment in assigned:
3251 if assignment.isPhysicalDevice:
3252 print("%s: assigned host device %s guest %s" % (colDev(ctx, assignment.name), pciAddr(ctx, assignment.hostAddress), pciAddr(ctx, assignment.guestAddress)))
3253
3254 atts = ctx['global'].getArray(console, 'attachedPCIDevices')
3255 for att in atts:
3256 if att.isPhysicalDevice:
3257 print("%s: physical, guest %s, host %s" % (colDev(ctx, att.name), pciAddr(ctx, att.guestAddress), pciAddr(ctx, att.hostAddress)))
3258 else:
3259 print("%s: virtual, guest %s" % (colDev(ctx, att.name), pciAddr(ctx, att.guestAddress)))
3260 return
3261
3262def parsePci(strg):
3263 pcire = re.compile(r'(?P<b>[0-9a-fA-F]+):(?P<d>[0-9a-fA-F]+)\.(?P<f>\d)')
3264 match = pcire.search(strg)
3265 if match is None:
3266 return -1
3267 pdict = match.groupdict()
3268 return ((int(pdict['b'], 16)) << 8) | ((int(pdict['d'], 16)) << 3) | int(pdict['f'])
3269
3270def lspciCmd(ctx, args):
3271 if len(args) < 2:
3272 print("usage: lspci vm")
3273 return 0
3274 mach = argsToMach(ctx, args)
3275 if not mach:
3276 return 0
3277 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx, mach, console, args: lspci(ctx, console)])
3278 return 0
3279
3280def attachpciCmd(ctx, args):
3281 if len(args) < 3:
3282 print("usage: attachpci <vmname|uuid> <host pci address> <guest pci address>")
3283 return 0
3284 mach = argsToMach(ctx, args)
3285 if not mach:
3286 return 0
3287 hostaddr = parsePci(args[2])
3288 if hostaddr == -1:
3289 print("invalid host PCI %s, accepted format 01:02.3 for bus 1, device 2, function 3" % (args[2]))
3290 return 0
3291
3292 if len(args) > 3:
3293 guestaddr = parsePci(args[3])
3294 if guestaddr == -1:
3295 print("invalid guest PCI %s, accepted format 01:02.3 for bus 1, device 2, function 3" % (args[3]))
3296 return 0
3297 else:
3298 guestaddr = hostaddr
3299 cmdClosedVm(ctx, mach, lambda ctx, mach, a: mach.attachHostPCIDevice(hostaddr, guestaddr, True))
3300 return 0
3301
3302def detachpciCmd(ctx, args):
3303 if len(args) < 3:
3304 print("usage: detachpci <vmname|uuid> <host pci address>")
3305 return 0
3306 mach = argsToMach(ctx, args)
3307 if not mach:
3308 return 0
3309 hostaddr = parsePci(args[2])
3310 if hostaddr == -1:
3311 print("invalid host PCI %s, accepted format 01:02.3 for bus 1, device 2, function 3" % (args[2]))
3312 return 0
3313
3314 cmdClosedVm(ctx, mach, lambda ctx, mach, a: mach.detachHostPCIDevice(hostaddr))
3315 return 0
3316
3317def gotoCmd(ctx, args):
3318 if len(args) < 2:
3319 print("usage: goto line")
3320 return 0
3321
3322 line = int(args[1])
3323
3324 ctx['scriptLine'] = line
3325
3326 return 0
3327
3328aliases = {'s':'start',
3329 'i':'info',
3330 'l':'list',
3331 'h':'help',
3332 'a':'alias',
3333 'q':'quit', 'exit':'quit',
3334 'tg': 'typeGuest',
3335 'v':'verbose'}
3336
3337commands = {'help':['Prints help information', helpCmd, 0],
3338 'start':['Start virtual machine by name or uuid: start mytestvm headless', startCmd, 0],
3339 'createVm':['Create virtual machine: createVm myvmname x86 MacOS', createVmCmd, 0],
3340 'removeVm':['Remove virtual machine', removeVmCmd, 0],
3341 'pause':['Pause virtual machine', pauseCmd, 0],
3342 'resume':['Resume virtual machine', resumeCmd, 0],
3343 'save':['Save execution state of virtual machine', saveCmd, 0],
3344 'stats':['Stats for virtual machine', statsCmd, 0],
3345 'powerdown':['Power down virtual machine', powerdownCmd, 0],
3346 'powerbutton':['Effectively press power button', powerbuttonCmd, 0],
3347 'list':['Shows known virtual machines', listCmd, 0],
3348 'info':['Shows info on machine', infoCmd, 0],
3349 'ginfo':['Shows info on guest', ginfoCmd, 0],
3350 'gexec':['Executes program in the guest', gexecCmd, 0],
3351 'gcopy':['Copy file to the guest', gcopyCmd, 0],
3352 'gpipe':['Pipe between host and guest', gpipeCmd, 0],
3353 'alias':['Control aliases', aliasCmd, 0],
3354 'verbose':['Toggle verbosity', verboseCmd, 0],
3355 'setvar':['Set VM variable: setvar mytestvm firmwareSettings.ACPIEnabled True', setvarCmd, 0],
3356 'eval':['Evaluate arbitrary Python construction: eval \'for m in getMachines(ctx): print(m.name, "has", m.memorySize, "M")\'', evalCmd, 0],
3357 'quit':['Exits', quitCmd, 0],
3358 'host':['Show host information', hostCmd, 0],
3359 'guest':['Execute command for guest: guest mytestvm \'console.mouse.putMouseEvent(20, 20, 0, 0, 0)\'', guestCmd, 0],
3360 'monitorGuest':['Monitor what happens with the guest for some time: monitorGuest mytestvm 10', monitorGuestCmd, 0],
3361 'monitorGuestKbd':['Monitor guest keyboard for some time: monitorGuestKbd mytestvm 10', monitorGuestKbdCmd, 0],
3362 'monitorGuestMouse':['Monitor guest mouse for some time: monitorGuestMouse mytestvm 10', monitorGuestMouseCmd, 0],
3363 'monitorGuestMultiTouch':['Monitor guest touch screen for some time: monitorGuestMultiTouch mytestvm 10', monitorGuestMultiTouchCmd, 0],
3364 'monitorVBox':['Monitor what happens with VirtualBox for some time: monitorVBox 10', monitorVBoxCmd, 0],
3365 'portForward':['Setup permanent port forwarding for a VM, takes adapter number host port and guest port: portForward mytestvm 0 8080 80', portForwardCmd, 0],
3366 'showLog':['Show log file of the VM, : showLog mytestvm', showLogCmd, 0],
3367 'findLog':['Show entries matching pattern in log file of the VM, : findLog mytestvm PDM|CPUM', findLogCmd, 0],
3368 'findAssert':['Find assert in log file of the VM, : findAssert mytestvm', findAssertCmd, 0],
3369 'reloadExt':['Reload custom extensions: reloadExt', reloadExtCmd, 0],
3370 'runScript':['Run VBox script: runScript script.vbox', runScriptCmd, 0],
3371 'sleep':['Sleep for specified number of seconds: sleep 3.14159', sleepCmd, 0],
3372 'shell':['Execute external shell command: shell "ls /etc/rc*"', shellCmd, 0],
3373 'exportVm':['Export VM in OVF format: exportVm mytestvm /tmp/win.ovf', exportVMCmd, 0],
3374 'screenshot':['Take VM screenshot to a file: screenshot mytestvm /tmp/win.png 1024 768 0', screenshotCmd, 0],
3375 'teleport':['Teleport VM to another box (see openportal): teleport mytestvm anotherhost:8000 <passwd> <maxDowntime>', teleportCmd, 0],
3376 'typeGuest':['Type arbitrary text in guest: typeGuest Linux "^lls\\n&UP;&BKSP;ess /etc/hosts\\nq^c" 0.7', typeGuestCmd, 0],
3377 'openportal':['Open portal for teleportation of VM from another box (see teleport): openportal mytestvm 8000 <passwd>', openportalCmd, 0],
3378 'closeportal':['Close teleportation portal (see openportal, teleport): closeportal Win', closeportalCmd, 0],
3379 'getextra':['Get extra data, empty key lists all: getextra <vm|global> <key>', getExtraDataCmd, 0],
3380 'setextra':['Set extra data, empty value removes key: setextra <vm|global> <key> <value>', setExtraDataCmd, 0],
3381 'gueststats':['Print available guest stats (only Windows guests with additions so far): gueststats mytestvm', gueststatsCmd, 0],
3382 'plugcpu':['Add a CPU to a running VM: plugcpu mytestvm 1', plugcpuCmd, 0],
3383 'unplugcpu':['Remove a CPU from a running VM (additions required, Windows cannot unplug): unplugcpu Linux 1', unplugcpuCmd, 0],
3384 'createHdd': ['Create virtual HDD: createHdd 1000 /disk.vdi ', createHddCmd, 0],
3385 'removeHdd': ['Permanently remove virtual HDD: removeHdd /disk.vdi', removeHddCmd, 0],
3386 'registerHdd': ['Register HDD image with VirtualBox instance: registerHdd /disk.vdi', registerHddCmd, 0],
3387 'unregisterHdd': ['Unregister HDD image with VirtualBox instance: unregisterHdd /disk.vdi', unregisterHddCmd, 0],
3388 'attachHdd': ['Attach HDD to the VM: attachHdd mytestvm /disk.vdi "IDE Controller" 0:1', attachHddCmd, 0],
3389 'detachHdd': ['Detach HDD from the VM: detachHdd mytestvm /disk.vdi', detachHddCmd, 0],
3390 'registerIso': ['Register CD/DVD image with VirtualBox instance: registerIso /os.iso', registerIsoCmd, 0],
3391 'unregisterIso': ['Unregister CD/DVD image with VirtualBox instance: unregisterIso /os.iso', unregisterIsoCmd, 0],
3392 'removeIso': ['Permanently remove CD/DVD image: removeIso /os.iso', removeIsoCmd, 0],
3393 'attachIso': ['Attach CD/DVD to the VM: attachIso mytestvm /os.iso "IDE Controller" 0:1', attachIsoCmd, 0],
3394 'detachIso': ['Detach CD/DVD from the VM: detachIso mytestvm /os.iso', detachIsoCmd, 0],
3395 'mountIso': ['Mount CD/DVD to the running VM: mountIso mytestvm /os.iso "IDE Controller" 0:1', mountIsoCmd, 0],
3396 'unmountIso': ['Unmount CD/DVD from running VM: unmountIso mytestvm "IDE Controller" 0:1', unmountIsoCmd, 0],
3397 'attachCtr': ['Attach storage controller to the VM: attachCtr mytestvm Ctr0 IDE ICH6', attachCtrCmd, 0],
3398 'detachCtr': ['Detach HDD from the VM: detachCtr mytestvm Ctr0', detachCtrCmd, 0],
3399 'attachUsb': ['Attach USB device to the VM (use listUsb to show available devices): attachUsb mytestvm uuid', attachUsbCmd, 0],
3400 'detachUsb': ['Detach USB device from the VM: detachUsb mytestvm uuid', detachUsbCmd, 0],
3401 'listMedia': ['List media known to this VBox instance', listMediaCmd, 0],
3402 'listUsb': ['List known USB devices', listUsbCmd, 0],
3403 'shareFolder': ['Make host\'s folder visible to guest: shareFolder mytestvm /share share writable', shareFolderCmd, 0],
3404 'unshareFolder': ['Remove folder sharing', unshareFolderCmd, 0],
3405 'gui': ['Start GUI frontend', guiCmd, 0],
3406 'colors':['Toggle colors', colorsCmd, 0],
3407 'snapshot':['VM snapshot manipulation, snapshot help for more info', snapshotCmd, 0],
3408 'nat':['NAT (network address translation engine) manipulation, nat help for more info', natCmd, 0],
3409 'nic' : ['Network adapter management', nicCmd, 0],
3410 'prompt' : ['Control shell prompt', promptCmd, 0],
3411 'foreachvm' : ['Perform command for each VM', foreachvmCmd, 0],
3412 'foreach' : ['Generic "for each" construction, using XPath-like notation: foreach //vms/vm[@OSTypeId=\'MacOS\'] "print(obj.name)"', foreachCmd, 0],
3413 'recordDemo':['Record demo: recordDemo mytestvm file.dmo 10', recordDemoCmd, 0],
3414 'playbackDemo':['Playback demo: playbackDemo mytestvm file.dmo 10', playbackDemoCmd, 0],
3415 'lspci': ['List PCI devices attached to the VM: lspci mytestvm', lspciCmd, 0],
3416 'attachpci': ['Attach host PCI device to the VM: attachpci mytestvm 01:00.0', attachpciCmd, 0],
3417 'detachpci': ['Detach host PCI device from the VM: detachpci mytestvm 01:00.0', detachpciCmd, 0],
3418 'goto': ['Go to line in script (script-only)', gotoCmd, 0]
3419 }
3420
3421def runCommandArgs(ctx, args):
3422 c = args[0]
3423 if aliases.get(c, None):
3424 c = aliases[c]
3425 cmd_internal = commands.get(c, None)
3426 if not cmd_internal:
3427 print("Unknown command: '%s', type 'help' for list of known commands" % (c))
3428 return 0
3429 if ctx['remote'] and ctx['vb'] is None:
3430 if c not in ['connect', 'reconnect', 'help', 'quit']:
3431 print("First connect to remote server with %s command." % (colored('connect', 'blue')))
3432 return 0
3433 return cmd_internal[1](ctx, args)
3434
3435
3436def runCommand(ctx, cmd):
3437 if not cmd: return 0
3438 args = split_no_quotes(cmd)
3439 if len(args) == 0: return 0
3440 return runCommandArgs(ctx, args)
3441
3442#
3443# To write your own custom commands to vboxshell, create
3444# file ~/.VirtualBox/shellext.py with content like
3445#
3446# def runTestCmd(ctx, args):
3447# print("Testy test", ctx['vb'])
3448# return 0
3449#
3450# commands = {
3451# 'test': ['Test help', runTestCmd]
3452# }
3453# and issue reloadExt shell command.
3454# This file also will be read automatically on startup or 'reloadExt'.
3455#
3456# Also one can put shell extensions into ~/.VirtualBox/shexts and
3457# they will also be picked up, so this way one can exchange
3458# shell extensions easily.
3459def addExtsFromFile(_ctx, cmds, filename):
3460 if not os.path.isfile(filename):
3461 return
3462 extDict = {}
3463 try:
3464 with open(filename, encoding='utf-8') as file:
3465 file_buf = file.read()
3466 exec(compile(file_buf, filename, 'exec'), extDict, extDict) # pylint: disable=exec-used
3467 for (key, value) in list(extDict['commands'].items()):
3468 if g_fVerbose:
3469 print("customize: adding \"%s\" - %s" % (key, value[0]))
3470 cmds[key] = [value[0], value[1], filename]
3471 except:
3472 print("Error loading user extensions from %s" % (filename))
3473 traceback.print_exc()
3474
3475
3476def checkUserExtensions(ctx, cmds, folder):
3477 folder = str(folder)
3478 name = os.path.join(folder, "shellext.py")
3479 addExtsFromFile(ctx, cmds, name)
3480 # also check 'exts' directory for all files
3481 shextdir = os.path.join(folder, "shexts")
3482 if not os.path.isdir(shextdir):
3483 return
3484 exts = os.listdir(shextdir)
3485 for e in exts:
3486 # not editor temporary files, please.
3487 if e.endswith('.py'):
3488 addExtsFromFile(ctx, cmds, os.path.join(shextdir, e))
3489
3490def getHomeFolder(ctx):
3491 if ctx['remote'] or ctx['vb'] is None:
3492 if 'VBOX_USER_HOME' in os.environ:
3493 return os.path.join(os.environ['VBOX_USER_HOME'])
3494 return os.path.join(os.path.expanduser("~"), ".VirtualBox")
3495
3496 return ctx['vb'].homeFolder
3497
3498def interpret(ctx):
3499 if ctx['remote']:
3500 commands['connect'] = ["Connect to remote VBox instance: connect http://server:18083 user password", connectCmd, 0]
3501 commands['disconnect'] = ["Disconnect from remote VBox instance", disconnectCmd, 0]
3502 commands['reconnect'] = ["Reconnect to remote VBox instance", reconnectCmd, 0]
3503 ctx['wsinfo'] = ["http://localhost:18083", "", ""]
3504
3505 vbox = ctx['vb']
3506 if vbox is not None:
3507 try:
3508 print("Running VirtualBox version %s" % (vbox.version))
3509 except Exception as e:
3510 printErr(ctx, e)
3511 if g_fVerbose:
3512 traceback.print_exc()
3513 ctx['perf'] = None # ctx['global'].getPerfCollector(vbox)
3514 else:
3515 ctx['perf'] = None
3516
3517 home = getHomeFolder(ctx)
3518 checkUserExtensions(ctx, commands, home)
3519 if platform.system() in ['Windows', 'Microsoft']:
3520 global g_fHasColors
3521 g_fHasColors = False
3522 hist_file = os.path.join(home, ".vboxshellhistory")
3523 autoCompletion(commands, ctx)
3524
3525 if g_fHasReadline and os.path.exists(hist_file):
3526 readline.read_history_file(hist_file)
3527
3528 # to allow to print actual host information, we collect info for
3529 # last 150 secs maximum, (sample every 10 secs and keep up to 15 samples)
3530 if ctx['perf']:
3531 try:
3532 ctx['perf'].setup(['*'], [vbox.host], 10, 15)
3533 except:
3534 pass
3535 cmds = []
3536
3537 if g_sCmd is not None:
3538 cmds = g_sCmd.split(';')
3539 itCmd = iter(cmds)
3540
3541 while True:
3542 try:
3543 if g_fBatchMode:
3544 cmd = 'runScript %s'% (g_sScriptFile)
3545 elif g_sCmd is not None:
3546 cmd = next(itCmd)
3547 else:
3548 if sys.version_info[0] <= 2:
3549 cmd = raw_input(ctx['prompt']) # pylint: disable=undefined-variable
3550 else:
3551 cmd = input(ctx['prompt'])
3552 done = runCommand(ctx, cmd)
3553 if done != 0:
3554 break
3555 if g_fBatchMode:
3556 break
3557 except KeyboardInterrupt:
3558 print('====== You can type quit or q to leave')
3559 except StopIteration:
3560 break
3561 except EOFError:
3562 break
3563 except Exception as e:
3564 printErr(ctx, e)
3565 if g_fVerbose:
3566 traceback.print_exc()
3567 ctx['global'].waitForEvents(0)
3568 try:
3569 # There is no need to disable metric collection. This is just an example.
3570 if ctx['perf']:
3571 ctx['perf'].disable(['*'], [vbox.host])
3572 except:
3573 pass
3574 if g_fHasReadline:
3575 readline.write_history_file(hist_file)
3576
3577def runCommandCb(ctx, cmd, args):
3578 args.insert(0, cmd)
3579 return runCommandArgs(ctx, args)
3580
3581def runGuestCommandCb(ctx, uuid, guestLambda, args):
3582 mach = machById(ctx, uuid)
3583 if not mach:
3584 return 0
3585 args.insert(0, guestLambda)
3586 cmdExistingVm(ctx, mach, 'guestlambda', args)
3587 return 0
3588
3589def main(_argv):
3590
3591 #
3592 # Parse command line arguments.
3593 #
3594 parse = OptionParser()
3595 parse.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, help = "switch on verbose")
3596 parse.add_option("-a", "--autopath", dest="autopath", action="store_true", default=False, help = "switch on autopath")
3597 parse.add_option("-w", "--webservice", dest="style", action="store_const", const="WEBSERVICE", help = "connect to webservice")
3598 parse.add_option("-b", "--batch", dest="batch_file", help = "script file to execute")
3599 parse.add_option("-c", dest="command_line", help = "command sequence to execute")
3600 parse.add_option("-o", dest="opt_line", help = "option line")
3601 global g_fVerbose, g_sScriptFile, g_fBatchMode, g_fHasColors, g_fHasReadline, g_sCmd
3602 (options, _args) = parse.parse_args()
3603 g_fVerbose = options.verbose
3604 style = options.style
3605 if options.batch_file is not None:
3606 g_fBatchMode = True
3607 g_fHasColors = False
3608 g_fHasReadline = False
3609 g_sScriptFile = options.batch_file
3610 if options.command_line is not None:
3611 g_fHasColors = False
3612 g_fHasReadline = False
3613 g_sCmd = options.command_line
3614
3615 params = None
3616 if options.opt_line is not None:
3617 params = {}
3618 strparams = options.opt_line
3619 strparamlist = strparams.split(',')
3620 for strparam in strparamlist:
3621 (key, value) = strparam.split('=')
3622 params[key] = value
3623
3624 if options.autopath:
3625 asLocations = [ os.getcwd(), ]
3626 try: sScriptDir = os.path.dirname(os.path.abspath(__file__))
3627 except: pass # In case __file__ isn't there.
3628 else:
3629 if platform.system() in [ 'SunOS', ]:
3630 asLocations.append(os.path.join(sScriptDir, 'amd64'))
3631 asLocations.append(sScriptDir)
3632
3633
3634 sPath = os.environ.get("VBOX_PROGRAM_PATH")
3635 if sPath is None:
3636 for sCurLoc in asLocations:
3637 if os.path.isfile(os.path.join(sCurLoc, "VirtualBox")) \
3638 or os.path.isfile(os.path.join(sCurLoc, "VirtualBox.exe")):
3639 print("Autodetected VBOX_PROGRAM_PATH as", sCurLoc)
3640 os.environ["VBOX_PROGRAM_PATH"] = sCurLoc
3641 sPath = sCurLoc
3642 break
3643 if sPath:
3644 sys.path.append(os.path.join(sPath, "sdk", "installer"))
3645
3646 sPath = os.environ.get("VBOX_SDK_PATH")
3647 if sPath is None:
3648 for sCurLoc in asLocations:
3649 if os.path.isfile(os.path.join(sCurLoc, "sdk", "bindings", "VirtualBox.xidl")):
3650 sCurLoc = os.path.join(sCurLoc, "sdk")
3651 print("Autodetected VBOX_SDK_PATH as", sCurLoc)
3652 os.environ["VBOX_SDK_PATH"] = sCurLoc
3653 sPath = sCurLoc
3654 break
3655 if sPath:
3656 sCurLoc = sPath
3657 sTmp = os.path.join(sCurLoc, 'bindings', 'xpcom', 'python')
3658 if os.path.isdir(sTmp):
3659 sys.path.append(sTmp)
3660 del sTmp
3661 del sPath, asLocations
3662
3663 #
3664 # Set up the shell interpreter context and start working.
3665 #
3666 from vboxapi import VirtualBoxManager
3667 oVBoxMgr = VirtualBoxManager(style, params)
3668 ctx = {
3669 'global': oVBoxMgr,
3670 'vb': oVBoxMgr.getVirtualBox(),
3671 'const': oVBoxMgr.constants,
3672 'remote': oVBoxMgr.remote,
3673 'type': oVBoxMgr.type,
3674 'run': lambda cmd, args: runCommandCb(ctx, cmd, args),
3675 'guestlambda': lambda uuid, guestLambda, args: runGuestCommandCb(ctx, uuid, guestLambda, args),
3676 'machById': lambda uuid: machById(ctx, uuid),
3677 'argsToMach': lambda args: argsToMach(ctx, args),
3678 'progressBar': lambda p: progressBar(ctx, p),
3679 'typeInGuest': typeInGuest,
3680 '_machlist': None,
3681 'prompt': g_sPrompt,
3682 'scriptLine': 0,
3683 'interrupt': False,
3684 }
3685 interpret(ctx)
3686
3687 #
3688 # Release the interfaces references in ctx before cleaning up.
3689 #
3690 for sKey in list(ctx.keys()):
3691 del ctx[sKey]
3692 ctx = None
3693 gc.collect()
3694
3695 oVBoxMgr.deinit()
3696 del oVBoxMgr
3697
3698if __name__ == '__main__':
3699 main(sys.argv)
Note: See TracBrowser for help on using the repository browser.

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