VirtualBox

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

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

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

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

© 2023 Oracle
ContactPrivacy policyTerms of Use