VirtualBox

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

Last change on this file since 48285 was 48285, checked in by vboxsync, 11 years ago

vboxshell.py: Fixed some bustage and improved the path autodetection.

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