VirtualBox

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

Last change on this file since 69111 was 68309, checked in by vboxsync, 7 years ago

vboxshell.py: fixed typo in createHddCmd (ticketref:16979)

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

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