VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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