VirtualBox

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

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

Main: API event for multitouch input.

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