VirtualBox

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

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

Main: OnGuestMouse event cleanup.

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