VirtualBox

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

Last change on this file since 108103 was 108046, checked in by vboxsync, 3 months ago

doc/manual,include/VBox,Frontends/{VBoxManage,VirtualBox/src},Main/{include,SharedFolder,Console,Machine,VirtualBox,VirtualBox.xidl}: Added global shared folders and adjusted fetching and handling of folders between shared folder types bugref:3544

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

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