VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManage.cpp@ 22489

Last change on this file since 22489 was 22173, checked in by vboxsync, 15 years ago

Main: the big XML settings rework. Move XML reading/writing out of interface implementation code into separate layer so it can handle individual settings versions in the future.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.7 KB
Line 
1/* $Id: VBoxManage.cpp 22173 2009-08-11 15:38:59Z vboxsync $ */
2/** @file
3 * VBoxManage - VirtualBox's command-line interface.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#ifndef VBOX_ONLY_DOCS
27#include <VBox/com/com.h>
28#include <VBox/com/string.h>
29#include <VBox/com/Guid.h>
30#include <VBox/com/array.h>
31#include <VBox/com/ErrorInfo.h>
32#include <VBox/com/errorprint.h>
33#include <VBox/com/EventQueue.h>
34
35#include <VBox/com/VirtualBox.h>
36
37#include <vector>
38#include <list>
39#endif /* !VBOX_ONLY_DOCS */
40
41#include <iprt/asm.h>
42#include <iprt/cidr.h>
43#include <iprt/ctype.h>
44#include <iprt/dir.h>
45#include <iprt/env.h>
46#include <VBox/err.h>
47#include <iprt/file.h>
48#include <iprt/initterm.h>
49#include <iprt/param.h>
50#include <iprt/path.h>
51#include <iprt/stream.h>
52#include <iprt/string.h>
53#include <iprt/stdarg.h>
54#include <iprt/thread.h>
55#include <iprt/uuid.h>
56#include <iprt/getopt.h>
57#include <iprt/ctype.h>
58#include <VBox/version.h>
59#include <VBox/log.h>
60
61#include "VBoxManage.h"
62
63#ifndef VBOX_ONLY_DOCS
64using namespace com;
65
66/** command handler type */
67typedef int (*PFNHANDLER)(HandlerArg *a);
68
69#endif /* !VBOX_ONLY_DOCS */
70
71////////////////////////////////////////////////////////////////////////////////
72//
73// global variables
74//
75////////////////////////////////////////////////////////////////////////////////
76
77/*extern*/ bool g_fDetailedProgress = false;
78
79////////////////////////////////////////////////////////////////////////////////
80//
81// functions
82//
83////////////////////////////////////////////////////////////////////////////////
84
85#ifndef VBOX_ONLY_DOCS
86/**
87 * Print out progress on the console
88 */
89LONG showProgress(ComPtr<IProgress> progress)
90{
91 BOOL fCompleted;
92 ULONG ulCurrentPercent;
93 ULONG ulLastPercent = 0;
94
95 ULONG ulCurrentOperationPercent;
96 ULONG ulLastOperationPercent = (ULONG)-1;
97
98 ULONG ulLastOperation = (ULONG)-1;
99 Bstr bstrOperationDescription;
100
101 ULONG cOperations;
102 progress->COMGETTER(OperationCount)(&cOperations);
103
104 if (!g_fDetailedProgress)
105 {
106 RTPrintf("0%%...");
107 RTStrmFlush(g_pStdOut);
108 }
109
110 while (SUCCEEDED(progress->COMGETTER(Completed(&fCompleted))))
111 {
112 ULONG ulOperation;
113 progress->COMGETTER(Operation)(&ulOperation);
114
115 progress->COMGETTER(Percent(&ulCurrentPercent));
116 progress->COMGETTER(OperationPercent(&ulCurrentOperationPercent));
117
118 if (g_fDetailedProgress)
119 {
120 if (ulLastOperation != ulOperation)
121 {
122 progress->COMGETTER(OperationDescription(bstrOperationDescription.asOutParam()));
123 ulLastPercent = (ULONG)-1; // force print
124 ulLastOperation = ulOperation;
125 }
126
127 if ( (ulCurrentPercent != ulLastPercent)
128 || (ulCurrentOperationPercent != ulLastOperationPercent)
129 )
130 {
131 LONG lSecsRem;
132 progress->COMGETTER(TimeRemaining)(&lSecsRem);
133
134 RTPrintf("(%ld/%ld) %ls %ld%% => %ld%% (%d s remaining)\n", ulOperation + 1, cOperations, bstrOperationDescription.raw(), ulCurrentOperationPercent, ulCurrentPercent, lSecsRem);
135 ulLastPercent = ulCurrentPercent;
136 ulLastOperationPercent = ulCurrentOperationPercent;
137 }
138 }
139 else
140 {
141 /* did we cross a 10% mark? */
142 if (((ulCurrentPercent / 10) > (ulLastPercent / 10)))
143 {
144 /* make sure to also print out missed steps */
145 for (ULONG curVal = (ulLastPercent / 10) * 10 + 10; curVal <= (ulCurrentPercent / 10) * 10; curVal += 10)
146 {
147 if (curVal < 100)
148 {
149 RTPrintf("%ld%%...", curVal);
150 RTStrmFlush(g_pStdOut);
151 }
152 }
153 ulLastPercent = (ulCurrentPercent / 10) * 10;
154 }
155 }
156 if (fCompleted)
157 break;
158
159 /* make sure the loop is not too tight */
160 progress->WaitForCompletion(100);
161 }
162
163 /* complete the line. */
164 LONG iRc;
165 if (SUCCEEDED(progress->COMGETTER(ResultCode)(&iRc)))
166 {
167 if (SUCCEEDED(iRc))
168 RTPrintf("100%%\n");
169 else
170 RTPrintf("FAILED\n");
171 }
172 else
173 RTPrintf("\n");
174 RTStrmFlush(g_pStdOut);
175 return iRc;
176}
177#endif /* !VBOX_ONLY_DOCS */
178
179void showLogo(void)
180{
181 static bool fShown; /* show only once */
182
183 if (!fShown)
184 {
185 RTPrintf("VirtualBox Command Line Management Interface Version "
186 VBOX_VERSION_STRING "\n"
187 "(C) 2005-2009 Sun Microsystems, Inc.\n"
188 "All rights reserved.\n"
189 "\n");
190 fShown = true;
191 }
192}
193
194#ifndef VBOX_ONLY_DOCS
195
196static int handleRegisterVM(HandlerArg *a)
197{
198 HRESULT rc;
199
200 if (a->argc != 1)
201 return errorSyntax(USAGE_REGISTERVM, "Incorrect number of parameters");
202
203 ComPtr<IMachine> machine;
204 /** @todo Ugly hack to get both the API interpretation of relative paths
205 * and the client's interpretation of relative paths. Remove after the API
206 * has been redesigned. */
207 rc = a->virtualBox->OpenMachine(Bstr(a->argv[0]), machine.asOutParam());
208 if (rc == VBOX_E_FILE_ERROR)
209 {
210 char szVMFileAbs[RTPATH_MAX] = "";
211 int vrc = RTPathAbs(a->argv[0], szVMFileAbs, sizeof(szVMFileAbs));
212 if (RT_FAILURE(vrc))
213 {
214 RTPrintf("Cannot convert filename \"%s\" to absolute path\n", a->argv[0]);
215 return 1;
216 }
217 CHECK_ERROR(a->virtualBox, OpenMachine(Bstr(szVMFileAbs), machine.asOutParam()));
218 }
219 else if (FAILED(rc))
220 CHECK_ERROR(a->virtualBox, OpenMachine(Bstr(a->argv[0]), machine.asOutParam()));
221 if (SUCCEEDED(rc))
222 {
223 ASSERT(machine);
224 CHECK_ERROR(a->virtualBox, RegisterMachine(machine));
225 }
226 return SUCCEEDED(rc) ? 0 : 1;
227}
228
229static const RTGETOPTDEF g_aUnregisterVMOptions[] =
230{
231 { "--delete", 'd', RTGETOPT_REQ_NOTHING },
232 { "-delete", 'd', RTGETOPT_REQ_NOTHING }, // deprecated
233};
234
235static int handleUnregisterVM(HandlerArg *a)
236{
237 HRESULT rc;
238 const char *VMName = NULL;
239 bool fDelete = false;
240
241 int c;
242 RTGETOPTUNION ValueUnion;
243 RTGETOPTSTATE GetState;
244 // start at 0 because main() has hacked both the argc and argv given to us
245 RTGetOptInit(&GetState, a->argc, a->argv, g_aUnregisterVMOptions, RT_ELEMENTS(g_aUnregisterVMOptions), 0, 0 /* fFlags */);
246 while ((c = RTGetOpt(&GetState, &ValueUnion)))
247 {
248 switch (c)
249 {
250 case 'd': // --delete
251 fDelete = true;
252 break;
253
254 case VINF_GETOPT_NOT_OPTION:
255 if (!VMName)
256 VMName = ValueUnion.psz;
257 else
258 return errorSyntax(USAGE_UNREGISTERVM, "Invalid parameter '%s'", ValueUnion.psz);
259 break;
260
261 default:
262 if (c > 0)
263 {
264 if (RT_C_IS_PRINT(c))
265 return errorSyntax(USAGE_UNREGISTERVM, "Invalid option -%c", c);
266 else
267 return errorSyntax(USAGE_UNREGISTERVM, "Invalid option case %i", c);
268 }
269 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
270 return errorSyntax(USAGE_UNREGISTERVM, "unknown option: %s\n", ValueUnion.psz);
271 else if (ValueUnion.pDef)
272 return errorSyntax(USAGE_UNREGISTERVM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
273 else
274 return errorSyntax(USAGE_UNREGISTERVM, "error: %Rrs", c);
275 }
276 }
277
278 /* check for required options */
279 if (!VMName)
280 return errorSyntax(USAGE_UNREGISTERVM, "VM name required");
281
282 ComPtr<IMachine> machine;
283 /* assume it's a UUID */
284 rc = a->virtualBox->GetMachine(Guid(VMName).toUtf16(), machine.asOutParam());
285 if (FAILED(rc) || !machine)
286 {
287 /* must be a name */
288 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(VMName), machine.asOutParam()));
289 }
290 if (machine)
291 {
292 Bstr uuid;
293 machine->COMGETTER(Id)(uuid.asOutParam());
294 machine = NULL;
295 CHECK_ERROR(a->virtualBox, UnregisterMachine(uuid, machine.asOutParam()));
296 if (SUCCEEDED(rc) && machine && fDelete)
297 CHECK_ERROR(machine, DeleteSettings());
298 }
299 return SUCCEEDED(rc) ? 0 : 1;
300}
301
302static int handleCreateVM(HandlerArg *a)
303{
304 HRESULT rc;
305 Bstr baseFolder;
306 Bstr settingsFile;
307 Bstr name;
308 Bstr osTypeId;
309 RTUUID id;
310 bool fRegister = false;
311
312 RTUuidClear(&id);
313 for (int i = 0; i < a->argc; i++)
314 {
315 if ( !strcmp(a->argv[i], "--basefolder")
316 || !strcmp(a->argv[i], "-basefolder"))
317 {
318 if (a->argc <= i + 1)
319 return errorArgument("Missing argument to '%s'", a->argv[i]);
320 i++;
321 baseFolder = a->argv[i];
322 }
323 else if ( !strcmp(a->argv[i], "--settingsfile")
324 || !strcmp(a->argv[i], "-settingsfile"))
325 {
326 if (a->argc <= i + 1)
327 return errorArgument("Missing argument to '%s'", a->argv[i]);
328 i++;
329 settingsFile = a->argv[i];
330 }
331 else if ( !strcmp(a->argv[i], "--name")
332 || !strcmp(a->argv[i], "-name"))
333 {
334 if (a->argc <= i + 1)
335 return errorArgument("Missing argument to '%s'", a->argv[i]);
336 i++;
337 name = a->argv[i];
338 }
339 else if ( !strcmp(a->argv[i], "--ostype")
340 || !strcmp(a->argv[i], "-ostype"))
341 {
342 if (a->argc <= i + 1)
343 return errorArgument("Missing argument to '%s'", a->argv[i]);
344 i++;
345 osTypeId = a->argv[i];
346 }
347 else if ( !strcmp(a->argv[i], "--uuid")
348 || !strcmp(a->argv[i], "-uuid"))
349 {
350 if (a->argc <= i + 1)
351 return errorArgument("Missing argument to '%s'", a->argv[i]);
352 i++;
353 if (RT_FAILURE(RTUuidFromStr(&id, a->argv[i])))
354 return errorArgument("Invalid UUID format %s\n", a->argv[i]);
355 }
356 else if ( !strcmp(a->argv[i], "--register")
357 || !strcmp(a->argv[i], "-register"))
358 {
359 fRegister = true;
360 }
361 else
362 return errorSyntax(USAGE_CREATEVM, "Invalid parameter '%s'", Utf8Str(a->argv[i]).raw());
363 }
364 if (!name)
365 return errorSyntax(USAGE_CREATEVM, "Parameter --name is required");
366
367 if (!!baseFolder && !!settingsFile)
368 return errorSyntax(USAGE_CREATEVM, "Either --basefolder or --settingsfile must be specified");
369
370 do
371 {
372 ComPtr<IMachine> machine;
373
374 if (!settingsFile)
375 CHECK_ERROR_BREAK(a->virtualBox,
376 CreateMachine(name, osTypeId, baseFolder, Guid(id).toUtf16(), machine.asOutParam()));
377 else
378 CHECK_ERROR_BREAK(a->virtualBox,
379 CreateLegacyMachine(name, osTypeId, settingsFile, Guid(id).toUtf16(), machine.asOutParam()));
380
381 CHECK_ERROR_BREAK(machine, SaveSettings());
382 if (fRegister)
383 {
384 CHECK_ERROR_BREAK(a->virtualBox, RegisterMachine(machine));
385 }
386 Bstr uuid;
387 CHECK_ERROR_BREAK(machine, COMGETTER(Id)(uuid.asOutParam()));
388 CHECK_ERROR_BREAK(machine, COMGETTER(SettingsFilePath)(settingsFile.asOutParam()));
389 RTPrintf("Virtual machine '%ls' is created%s.\n"
390 "UUID: %s\n"
391 "Settings file: '%ls'\n",
392 name.raw(), fRegister ? " and registered" : "",
393 Utf8Str(uuid).raw(), settingsFile.raw());
394 }
395 while (0);
396
397 return SUCCEEDED(rc) ? 0 : 1;
398}
399
400/**
401 * Parses a number.
402 *
403 * @returns Valid number on success.
404 * @returns 0 if invalid number. All necesary bitching has been done.
405 * @param psz Pointer to the nic number.
406 */
407unsigned parseNum(const char *psz, unsigned cMaxNum, const char *name)
408{
409 uint32_t u32;
410 char *pszNext;
411 int rc = RTStrToUInt32Ex(psz, &pszNext, 10, &u32);
412 if ( RT_SUCCESS(rc)
413 && *pszNext == '\0'
414 && u32 >= 1
415 && u32 <= cMaxNum)
416 return (unsigned)u32;
417 errorArgument("Invalid %s number '%s'", name, psz);
418 return 0;
419}
420
421
422/** @todo refine this after HDD changes; MSC 8.0/64 has trouble with handleModifyVM. */
423#if defined(_MSC_VER)
424# pragma optimize("", on)
425#endif
426
427static const RTGETOPTDEF g_aStartVMOptions[] =
428{
429 { "--type", 't', RTGETOPT_REQ_STRING },
430 { "-type", 't', RTGETOPT_REQ_STRING }, // deprecated
431};
432
433static int handleStartVM(HandlerArg *a)
434{
435 HRESULT rc;
436 const char *VMName = NULL;
437 Bstr sessionType = "gui";
438
439 int c;
440 RTGETOPTUNION ValueUnion;
441 RTGETOPTSTATE GetState;
442 // start at 0 because main() has hacked both the argc and argv given to us
443 RTGetOptInit(&GetState, a->argc, a->argv, g_aStartVMOptions, RT_ELEMENTS(g_aStartVMOptions), 0, 0 /* fFlags */);
444 while ((c = RTGetOpt(&GetState, &ValueUnion)))
445 {
446 switch (c)
447 {
448 case 't': // --type
449 if (!RTStrICmp(ValueUnion.psz, "gui"))
450 {
451 sessionType = "gui";
452 }
453#ifdef VBOX_WITH_VBOXSDL
454 else if (!RTStrICmp(ValueUnion.psz, "sdl"))
455 {
456 sessionType = "sdl";
457 }
458#endif
459#ifdef VBOX_WITH_VRDP
460 else if (!RTStrICmp(ValueUnion.psz, "vrdp"))
461 {
462 sessionType = "vrdp";
463 }
464#endif
465#ifdef VBOX_WITH_HEADLESS
466 else if (!RTStrICmp(ValueUnion.psz, "capture"))
467 {
468 sessionType = "capture";
469 }
470 else if (!RTStrICmp(ValueUnion.psz, "headless"))
471 {
472 sessionType = "headless";
473 }
474#endif
475 else
476 return errorArgument("Invalid session type '%s'", ValueUnion.psz);
477 break;
478
479 case VINF_GETOPT_NOT_OPTION:
480 if (!VMName)
481 VMName = ValueUnion.psz;
482 else
483 return errorSyntax(USAGE_STARTVM, "Invalid parameter '%s'", ValueUnion.psz);
484 break;
485
486 default:
487 if (c > 0)
488 {
489 if (RT_C_IS_PRINT(c))
490 return errorSyntax(USAGE_STARTVM, "Invalid option -%c", c);
491 else
492 return errorSyntax(USAGE_STARTVM, "Invalid option case %i", c);
493 }
494 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
495 return errorSyntax(USAGE_STARTVM, "unknown option: %s\n", ValueUnion.psz);
496 else if (ValueUnion.pDef)
497 return errorSyntax(USAGE_STARTVM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
498 else
499 return errorSyntax(USAGE_STARTVM, "error: %Rrs", c);
500 }
501 }
502
503 /* check for required options */
504 if (!VMName)
505 return errorSyntax(USAGE_STARTVM, "VM name required");
506
507 ComPtr<IMachine> machine;
508 /* assume it's a UUID */
509 rc = a->virtualBox->GetMachine(Guid(VMName).toUtf16(), machine.asOutParam());
510 if (FAILED(rc) || !machine)
511 {
512 /* must be a name */
513 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(VMName), machine.asOutParam()));
514 }
515 if (machine)
516 {
517 Bstr uuid;
518 machine->COMGETTER(Id)(uuid.asOutParam());
519
520
521 Bstr env;
522#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
523 /* make sure the VM process will start on the same display as VBoxManage */
524 {
525 const char *display = RTEnvGet ("DISPLAY");
526 if (display)
527 env = Utf8StrFmt ("DISPLAY=%s", display);
528 }
529#endif
530 ComPtr<IProgress> progress;
531 CHECK_ERROR_RET(a->virtualBox, OpenRemoteSession(a->session, uuid, sessionType,
532 env, progress.asOutParam()), rc);
533 RTPrintf("Waiting for the remote session to open...\n");
534 CHECK_ERROR_RET(progress, WaitForCompletion (-1), 1);
535
536 BOOL completed;
537 CHECK_ERROR_RET(progress, COMGETTER(Completed)(&completed), rc);
538 ASSERT(completed);
539
540 LONG iRc;
541 CHECK_ERROR_RET(progress, COMGETTER(ResultCode)(&iRc), rc);
542 if (FAILED(iRc))
543 {
544 ComPtr <IVirtualBoxErrorInfo> errorInfo;
545 CHECK_ERROR_RET(progress, COMGETTER(ErrorInfo)(errorInfo.asOutParam()), 1);
546 ErrorInfo info (errorInfo);
547 com::GluePrintErrorInfo(info);
548 }
549 else
550 {
551 RTPrintf("Remote session has been successfully opened.\n");
552 }
553 }
554
555 /* it's important to always close sessions */
556 a->session->Close();
557
558 return SUCCEEDED(rc) ? 0 : 1;
559}
560
561static int handleControlVM(HandlerArg *a)
562{
563 HRESULT rc;
564
565 if (a->argc < 2)
566 return errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
567
568 /* try to find the given machine */
569 ComPtr <IMachine> machine;
570 Bstr uuid (a->argv[0]);
571 if (!Guid(uuid).isEmpty())
572 {
573 CHECK_ERROR (a->virtualBox, GetMachine (uuid, machine.asOutParam()));
574 }
575 else
576 {
577 CHECK_ERROR (a->virtualBox, FindMachine (uuid, machine.asOutParam()));
578 if (SUCCEEDED (rc))
579 machine->COMGETTER(Id) (uuid.asOutParam());
580 }
581 if (FAILED (rc))
582 return 1;
583
584 /* open a session for the VM */
585 CHECK_ERROR_RET (a->virtualBox, OpenExistingSession (a->session, uuid), 1);
586
587 do
588 {
589 /* get the associated console */
590 ComPtr<IConsole> console;
591 CHECK_ERROR_BREAK (a->session, COMGETTER(Console)(console.asOutParam()));
592 /* ... and session machine */
593 ComPtr<IMachine> sessionMachine;
594 CHECK_ERROR_BREAK (a->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
595
596 /* which command? */
597 if (!strcmp(a->argv[1], "pause"))
598 {
599 CHECK_ERROR_BREAK (console, Pause());
600 }
601 else if (!strcmp(a->argv[1], "resume"))
602 {
603 CHECK_ERROR_BREAK (console, Resume());
604 }
605 else if (!strcmp(a->argv[1], "reset"))
606 {
607 CHECK_ERROR_BREAK (console, Reset());
608 }
609 else if (!strcmp(a->argv[1], "poweroff"))
610 {
611 ComPtr<IProgress> progress;
612 CHECK_ERROR_BREAK (console, PowerDown(progress.asOutParam()));
613
614 showProgress(progress);
615
616 LONG iRc;
617 progress->COMGETTER(ResultCode)(&iRc);
618 if (FAILED(iRc))
619 {
620 com::ProgressErrorInfo info(progress);
621 if (info.isBasicAvailable())
622 {
623 RTPrintf("Error: failed to power off machine. Error message: %lS\n", info.getText().raw());
624 }
625 else
626 {
627 RTPrintf("Error: failed to power off machine. No error message available!\n");
628 }
629 }
630 }
631 else if (!strcmp(a->argv[1], "savestate"))
632 {
633 ComPtr<IProgress> progress;
634 CHECK_ERROR_BREAK (console, SaveState(progress.asOutParam()));
635
636 showProgress(progress);
637
638 LONG iRc;
639 progress->COMGETTER(ResultCode)(&iRc);
640 if (FAILED(iRc))
641 {
642 com::ProgressErrorInfo info(progress);
643 if (info.isBasicAvailable())
644 {
645 RTPrintf("Error: failed to save machine state. Error message: %lS\n", info.getText().raw());
646 }
647 else
648 {
649 RTPrintf("Error: failed to save machine state. No error message available!\n");
650 }
651 }
652 }
653 else if (!strcmp(a->argv[1], "acpipowerbutton"))
654 {
655 CHECK_ERROR_BREAK (console, PowerButton());
656 }
657 else if (!strcmp(a->argv[1], "acpisleepbutton"))
658 {
659 CHECK_ERROR_BREAK (console, SleepButton());
660 }
661 else if (!strcmp(a->argv[1], "injectnmi"))
662 {
663 /* get the machine debugger. */
664 ComPtr <IMachineDebugger> debugger;
665 CHECK_ERROR_BREAK(console, COMGETTER(Debugger)(debugger.asOutParam()));
666 CHECK_ERROR_BREAK(debugger, InjectNMI());
667 }
668 else if (!strcmp(a->argv[1], "keyboardputscancode"))
669 {
670 ComPtr<IKeyboard> keyboard;
671 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(keyboard.asOutParam()));
672
673 if (a->argc <= 1 + 1)
674 {
675 errorArgument("Missing argument to '%s'. Expected IBM PC AT set 2 keyboard scancode(s) as hex byte(s).", a->argv[1]);
676 rc = E_FAIL;
677 break;
678 }
679
680 /* Arbitrary restrict the length of a sequence of scancodes to 1024. */
681 LONG alScancodes[1024];
682 int cScancodes = 0;
683
684 /* Process the command line. */
685 int i;
686 for (i = 1 + 1; i < a->argc && cScancodes < (int)RT_ELEMENTS(alScancodes); i++, cScancodes++)
687 {
688 if ( RT_C_IS_XDIGIT (a->argv[i][0])
689 && RT_C_IS_XDIGIT (a->argv[i][1])
690 && a->argv[i][2] == 0)
691 {
692 uint8_t u8Scancode;
693 int rc = RTStrToUInt8Ex(a->argv[i], NULL, 16, &u8Scancode);
694 if (RT_FAILURE (rc))
695 {
696 RTPrintf("Error: converting '%s' returned %Rrc!\n", a->argv[i], rc);
697 rc = E_FAIL;
698 break;
699 }
700
701 alScancodes[cScancodes] = u8Scancode;
702 }
703 else
704 {
705 RTPrintf("Error: '%s' is not a hex byte!\n", a->argv[i]);
706 rc = E_FAIL;
707 break;
708 }
709 }
710
711 if (FAILED(rc))
712 break;
713
714 if ( cScancodes == RT_ELEMENTS(alScancodes)
715 && i < a->argc)
716 {
717 RTPrintf("Error: too many scancodes, maximum %d allowed!\n", RT_ELEMENTS(alScancodes));
718 rc = E_FAIL;
719 break;
720 }
721
722 /* Send scancodes to the VM.
723 * Note: 'PutScancodes' did not work here. Only the first scancode was transmitted.
724 */
725 for (i = 0; i < cScancodes; i++)
726 {
727 CHECK_ERROR_BREAK(keyboard, PutScancode(alScancodes[i]));
728 RTPrintf("Scancode[%d]: 0x%02X\n", i, alScancodes[i]);
729 }
730 }
731 else if (!strncmp(a->argv[1], "setlinkstate", 12))
732 {
733 /* Get the number of network adapters */
734 ULONG NetworkAdapterCount = 0;
735 ComPtr <ISystemProperties> info;
736 CHECK_ERROR_BREAK (a->virtualBox, COMGETTER(SystemProperties) (info.asOutParam()));
737 CHECK_ERROR_BREAK (info, COMGETTER(NetworkAdapterCount) (&NetworkAdapterCount));
738
739 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
740 if (!n)
741 {
742 rc = E_FAIL;
743 break;
744 }
745 if (a->argc <= 1 + 1)
746 {
747 errorArgument("Missing argument to '%s'", a->argv[1]);
748 rc = E_FAIL;
749 break;
750 }
751 /* get the corresponding network adapter */
752 ComPtr<INetworkAdapter> adapter;
753 CHECK_ERROR_BREAK (sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
754 if (adapter)
755 {
756 if (!strcmp(a->argv[2], "on"))
757 {
758 CHECK_ERROR_BREAK (adapter, COMSETTER(CableConnected)(TRUE));
759 }
760 else if (!strcmp(a->argv[2], "off"))
761 {
762 CHECK_ERROR_BREAK (adapter, COMSETTER(CableConnected)(FALSE));
763 }
764 else
765 {
766 errorArgument("Invalid link state '%s'", Utf8Str(a->argv[2]).raw());
767 rc = E_FAIL;
768 break;
769 }
770 }
771 }
772#ifdef VBOX_DYNAMIC_NET_ATTACH
773 else if (!strncmp(a->argv[1], "nic", 3))
774 {
775 /* Get the number of network adapters */
776 ULONG NetworkAdapterCount = 0;
777 ComPtr <ISystemProperties> info;
778 CHECK_ERROR_BREAK (a->virtualBox, COMGETTER(SystemProperties) (info.asOutParam()));
779 CHECK_ERROR_BREAK (info, COMGETTER(NetworkAdapterCount) (&NetworkAdapterCount));
780
781 unsigned n = parseNum(&a->argv[1][3], NetworkAdapterCount, "NIC");
782 if (!n)
783 {
784 rc = E_FAIL;
785 break;
786 }
787 if (a->argc <= 2)
788 {
789 errorArgument("Missing argument to '%s'", a->argv[1]);
790 rc = E_FAIL;
791 break;
792 }
793
794 /* get the corresponding network adapter */
795 ComPtr<INetworkAdapter> adapter;
796 CHECK_ERROR_BREAK (sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
797 if (adapter)
798 {
799 BOOL fEnabled;
800 adapter->COMGETTER(Enabled)(&fEnabled);
801 if (fEnabled)
802 {
803 if (!strcmp(a->argv[2], "null"))
804 {
805 CHECK_ERROR_RET(adapter, COMSETTER(Enabled) (TRUE), 1);
806 CHECK_ERROR_RET(adapter, Detach(), 1);
807 }
808 else if (!strcmp(a->argv[2], "nat"))
809 {
810 CHECK_ERROR_RET(adapter, COMSETTER(Enabled) (TRUE), 1);
811 if (a->argc == 4)
812 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3])), 1);
813 CHECK_ERROR_RET(adapter, AttachToNAT(), 1);
814 }
815 else if ( !strcmp(a->argv[2], "bridged")
816 || !strcmp(a->argv[2], "hostif")) /* backward compatibility */
817 {
818 if (a->argc <= 3)
819 {
820 errorArgument("Missing argument to '%s'", a->argv[2]);
821 rc = E_FAIL;
822 break;
823 }
824 CHECK_ERROR_RET(adapter, COMSETTER(Enabled) (TRUE), 1);
825 CHECK_ERROR_RET(adapter, COMSETTER(HostInterface)(Bstr(a->argv[3])), 1);
826 CHECK_ERROR_RET(adapter, AttachToBridgedInterface(), 1);
827 }
828 else if (!strcmp(a->argv[2], "intnet"))
829 {
830 if (a->argc <= 3)
831 {
832 errorArgument("Missing argument to '%s'", a->argv[2]);
833 rc = E_FAIL;
834 break;
835 }
836 CHECK_ERROR_RET(adapter, COMSETTER(Enabled) (TRUE), 1);
837 CHECK_ERROR_RET(adapter, COMSETTER(InternalNetwork)(Bstr(a->argv[3])), 1);
838 CHECK_ERROR_RET(adapter, AttachToInternalNetwork(), 1);
839 }
840#if defined(VBOX_WITH_NETFLT)
841 else if (!strcmp(a->argv[2], "hostonly"))
842 {
843 if (a->argc <= 3)
844 {
845 errorArgument("Missing argument to '%s'", a->argv[2]);
846 rc = E_FAIL;
847 break;
848 }
849 CHECK_ERROR_RET(adapter, COMSETTER(Enabled) (TRUE), 1);
850 CHECK_ERROR_RET(adapter, COMSETTER(HostInterface)(Bstr(a->argv[3])), 1);
851 CHECK_ERROR_RET(adapter, AttachToHostOnlyInterface(), 1);
852 }
853#endif
854 else
855 {
856 errorArgument("Invalid type '%s' specfied for NIC %lu", Utf8Str(a->argv[2]).raw(), n);
857 rc = E_FAIL;
858 break;
859 }
860 }
861 else
862 {
863 RTPrintf("The NIC %d is currently disabled and thus can't change its attachment type\n", n);
864 }
865 }
866 }
867#endif /* VBOX_DYNAMIC_NET_ATTACH */
868#ifdef VBOX_WITH_VRDP
869 else if (!strcmp(a->argv[1], "vrdp"))
870 {
871 if (a->argc <= 1 + 1)
872 {
873 errorArgument("Missing argument to '%s'", a->argv[1]);
874 rc = E_FAIL;
875 break;
876 }
877 /* get the corresponding VRDP server */
878 ComPtr<IVRDPServer> vrdpServer;
879 sessionMachine->COMGETTER(VRDPServer)(vrdpServer.asOutParam());
880 ASSERT(vrdpServer);
881 if (vrdpServer)
882 {
883 if (!strcmp(a->argv[2], "on"))
884 {
885 CHECK_ERROR_BREAK (vrdpServer, COMSETTER(Enabled)(TRUE));
886 }
887 else if (!strcmp(a->argv[2], "off"))
888 {
889 CHECK_ERROR_BREAK (vrdpServer, COMSETTER(Enabled)(FALSE));
890 }
891 else
892 {
893 errorArgument("Invalid vrdp server state '%s'", Utf8Str(a->argv[2]).raw());
894 rc = E_FAIL;
895 break;
896 }
897 }
898 }
899#endif /* VBOX_WITH_VRDP */
900 else if ( !strcmp (a->argv[1], "usbattach")
901 || !strcmp (a->argv[1], "usbdetach"))
902 {
903 if (a->argc < 3)
904 {
905 errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
906 rc = E_FAIL;
907 break;
908 }
909
910 bool attach = !strcmp(a->argv[1], "usbattach");
911
912 Bstr usbId = a->argv [2];
913 if (Guid(usbId).isEmpty())
914 {
915 // assume address
916 if (attach)
917 {
918 ComPtr <IHost> host;
919 CHECK_ERROR_BREAK (a->virtualBox, COMGETTER(Host) (host.asOutParam()));
920 SafeIfaceArray <IHostUSBDevice> coll;
921 CHECK_ERROR_BREAK (host, COMGETTER(USBDevices) (ComSafeArrayAsOutParam(coll)));
922 ComPtr <IHostUSBDevice> dev;
923 CHECK_ERROR_BREAK (host, FindUSBDeviceByAddress (Bstr (a->argv [2]), dev.asOutParam()));
924 CHECK_ERROR_BREAK (dev, COMGETTER(Id) (usbId.asOutParam()));
925 }
926 else
927 {
928 SafeIfaceArray <IUSBDevice> coll;
929 CHECK_ERROR_BREAK (console, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
930 ComPtr <IUSBDevice> dev;
931 CHECK_ERROR_BREAK (console, FindUSBDeviceByAddress (Bstr (a->argv [2]),
932 dev.asOutParam()));
933 CHECK_ERROR_BREAK (dev, COMGETTER(Id) (usbId.asOutParam()));
934 }
935 }
936
937 if (attach)
938 CHECK_ERROR_BREAK (console, AttachUSBDevice (usbId));
939 else
940 {
941 ComPtr <IUSBDevice> dev;
942 CHECK_ERROR_BREAK (console, DetachUSBDevice (usbId, dev.asOutParam()));
943 }
944 }
945 else if (!strcmp(a->argv[1], "setvideomodehint"))
946 {
947 if (a->argc != 5 && a->argc != 6)
948 {
949 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
950 rc = E_FAIL;
951 break;
952 }
953 uint32_t xres = RTStrToUInt32(a->argv[2]);
954 uint32_t yres = RTStrToUInt32(a->argv[3]);
955 uint32_t bpp = RTStrToUInt32(a->argv[4]);
956 uint32_t displayIdx = 0;
957 if (a->argc == 6)
958 displayIdx = RTStrToUInt32(a->argv[5]);
959
960 ComPtr<IDisplay> display;
961 CHECK_ERROR_BREAK(console, COMGETTER(Display)(display.asOutParam()));
962 CHECK_ERROR_BREAK(display, SetVideoModeHint(xres, yres, bpp, displayIdx));
963 }
964 else if (!strcmp(a->argv[1], "setcredentials"))
965 {
966 bool fAllowLocalLogon = true;
967 if (a->argc == 7)
968 {
969 if ( strcmp(a->argv[5], "--allowlocallogon")
970 && strcmp(a->argv[5], "-allowlocallogon"))
971 {
972 errorArgument("Invalid parameter '%s'", a->argv[5]);
973 rc = E_FAIL;
974 break;
975 }
976 if (!strcmp(a->argv[6], "no"))
977 fAllowLocalLogon = false;
978 }
979 else if (a->argc != 5)
980 {
981 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
982 rc = E_FAIL;
983 break;
984 }
985
986 ComPtr<IGuest> guest;
987 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(guest.asOutParam()));
988 CHECK_ERROR_BREAK(guest, SetCredentials(Bstr(a->argv[2]), Bstr(a->argv[3]), Bstr(a->argv[4]), fAllowLocalLogon));
989 }
990 else if (!strcmp(a->argv[1], "dvdattach"))
991 {
992 if (a->argc != 3)
993 {
994 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
995 rc = E_FAIL;
996 break;
997 }
998 ComPtr<IDVDDrive> dvdDrive;
999 sessionMachine->COMGETTER(DVDDrive)(dvdDrive.asOutParam());
1000 ASSERT(dvdDrive);
1001
1002 /* unmount? */
1003 if (!strcmp(a->argv[2], "none"))
1004 {
1005 CHECK_ERROR(dvdDrive, Unmount());
1006 }
1007 /* host drive? */
1008 else if (!strncmp(a->argv[2], "host:", 5))
1009 {
1010 ComPtr<IHost> host;
1011 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1012 com::SafeIfaceArray <IHostDVDDrive> hostDVDs;
1013 rc = host->COMGETTER(DVDDrives)(ComSafeArrayAsOutParam(hostDVDs));
1014
1015 ComPtr<IHostDVDDrive> hostDVDDrive;
1016 rc = host->FindHostDVDDrive(Bstr(a->argv[2] + 5), hostDVDDrive.asOutParam());
1017 if (!hostDVDDrive)
1018 {
1019 errorArgument("Invalid host DVD drive name");
1020 rc = E_FAIL;
1021 break;
1022 }
1023 CHECK_ERROR(dvdDrive, CaptureHostDrive(hostDVDDrive));
1024 }
1025 else
1026 {
1027 /* first assume it's a UUID */
1028 Bstr uuid(a->argv[2]);
1029 ComPtr<IDVDImage> dvdImage;
1030 rc = a->virtualBox->GetDVDImage(uuid, dvdImage.asOutParam());
1031 if (FAILED(rc) || !dvdImage)
1032 {
1033 /* must be a filename, check if it's in the collection */
1034 rc = a->virtualBox->FindDVDImage(Bstr(a->argv[2]), dvdImage.asOutParam());
1035 /* not registered, do that on the fly */
1036 if (!dvdImage)
1037 {
1038 Bstr emptyUUID;
1039 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(a->argv[2]), emptyUUID, dvdImage.asOutParam()));
1040 }
1041 }
1042 if (!dvdImage)
1043 {
1044 rc = E_FAIL;
1045 break;
1046 }
1047 dvdImage->COMGETTER(Id)(uuid.asOutParam());
1048 CHECK_ERROR(dvdDrive, MountImage(uuid));
1049 }
1050 }
1051 else if (!strcmp(a->argv[1], "floppyattach"))
1052 {
1053 if (a->argc != 3)
1054 {
1055 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1056 rc = E_FAIL;
1057 break;
1058 }
1059
1060 ComPtr<IFloppyDrive> floppyDrive;
1061 sessionMachine->COMGETTER(FloppyDrive)(floppyDrive.asOutParam());
1062 ASSERT(floppyDrive);
1063
1064 /* unmount? */
1065 if (!strcmp(a->argv[2], "none"))
1066 {
1067 CHECK_ERROR(floppyDrive, Unmount());
1068 }
1069 /* host drive? */
1070 else if (!strncmp(a->argv[2], "host:", 5))
1071 {
1072 ComPtr<IHost> host;
1073 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1074 com::SafeIfaceArray <IHostFloppyDrive> hostFloppies;
1075 rc = host->COMGETTER(FloppyDrives)(ComSafeArrayAsOutParam(hostFloppies));
1076 CheckComRCReturnRC (rc);
1077 ComPtr<IHostFloppyDrive> hostFloppyDrive;
1078 host->FindHostFloppyDrive(Bstr(a->argv[2] + 5), hostFloppyDrive.asOutParam());
1079 if (!hostFloppyDrive)
1080 {
1081 errorArgument("Invalid host floppy drive name");
1082 rc = E_FAIL;
1083 break;
1084 }
1085 CHECK_ERROR(floppyDrive, CaptureHostDrive(hostFloppyDrive));
1086 }
1087 else
1088 {
1089 /* first assume it's a UUID */
1090 Bstr uuid(a->argv[2]);
1091 ComPtr<IFloppyImage> floppyImage;
1092 rc = a->virtualBox->GetFloppyImage(uuid, floppyImage.asOutParam());
1093 if (FAILED(rc) || !floppyImage)
1094 {
1095 /* must be a filename, check if it's in the collection */
1096 rc = a->virtualBox->FindFloppyImage(Bstr(a->argv[2]), floppyImage.asOutParam());
1097 /* not registered, do that on the fly */
1098 if (!floppyImage)
1099 {
1100 Bstr emptyUUID;
1101 CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(a->argv[2]), emptyUUID, floppyImage.asOutParam()));
1102 }
1103 }
1104 if (!floppyImage)
1105 {
1106 rc = E_FAIL;
1107 break;
1108 }
1109 floppyImage->COMGETTER(Id)(uuid.asOutParam());
1110 CHECK_ERROR(floppyDrive, MountImage(uuid));
1111 }
1112 }
1113#ifdef VBOX_WITH_MEM_BALLOONING
1114 else if ( !strcmp(a->argv[1], "--guestmemoryballoon")
1115 || !strcmp(a->argv[1], "-guestmemoryballoon"))
1116 {
1117 if (a->argc != 3)
1118 {
1119 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1120 rc = E_FAIL;
1121 break;
1122 }
1123 uint32_t uVal;
1124 int vrc;
1125 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1126 if (vrc != VINF_SUCCESS)
1127 {
1128 errorArgument("Error parsing guest memory balloon size '%s'", a->argv[2]);
1129 rc = E_FAIL;
1130 break;
1131 }
1132
1133 /* guest is running; update IGuest */
1134 ComPtr <IGuest> guest;
1135
1136 rc = console->COMGETTER(Guest)(guest.asOutParam());
1137 if (SUCCEEDED(rc))
1138 CHECK_ERROR(guest, COMSETTER(MemoryBalloonSize)(uVal));
1139 }
1140#endif
1141 else if ( !strcmp(a->argv[1], "--gueststatisticsinterval")
1142 || !strcmp(a->argv[1], "-gueststatisticsinterval"))
1143 {
1144 if (a->argc != 3)
1145 {
1146 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1147 rc = E_FAIL;
1148 break;
1149 }
1150 uint32_t uVal;
1151 int vrc;
1152 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1153 if (vrc != VINF_SUCCESS)
1154 {
1155 errorArgument("Error parsing guest statistics interval '%s'", a->argv[2]);
1156 rc = E_FAIL;
1157 break;
1158 }
1159
1160 /* guest is running; update IGuest */
1161 ComPtr <IGuest> guest;
1162
1163 rc = console->COMGETTER(Guest)(guest.asOutParam());
1164 if (SUCCEEDED(rc))
1165 CHECK_ERROR(guest, COMSETTER(StatisticsUpdateInterval)(uVal));
1166 }
1167 else
1168 {
1169 errorSyntax(USAGE_CONTROLVM, "Invalid parameter '%s'", Utf8Str(a->argv[1]).raw());
1170 rc = E_FAIL;
1171 }
1172 }
1173 while (0);
1174
1175 a->session->Close();
1176
1177 return SUCCEEDED (rc) ? 0 : 1;
1178}
1179
1180static int handleDiscardState(HandlerArg *a)
1181{
1182 HRESULT rc;
1183
1184 if (a->argc != 1)
1185 return errorSyntax(USAGE_DISCARDSTATE, "Incorrect number of parameters");
1186
1187 ComPtr<IMachine> machine;
1188 /* assume it's a UUID */
1189 rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
1190 if (FAILED(rc) || !machine)
1191 {
1192 /* must be a name */
1193 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
1194 }
1195 if (machine)
1196 {
1197 do
1198 {
1199 /* we have to open a session for this task */
1200 Bstr guid;
1201 machine->COMGETTER(Id)(guid.asOutParam());
1202 CHECK_ERROR_BREAK(a->virtualBox, OpenSession(a->session, guid));
1203 do
1204 {
1205 ComPtr<IConsole> console;
1206 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
1207 CHECK_ERROR_BREAK(console, ForgetSavedState(true));
1208 }
1209 while (0);
1210 CHECK_ERROR_BREAK(a->session, Close());
1211 }
1212 while (0);
1213 }
1214
1215 return SUCCEEDED(rc) ? 0 : 1;
1216}
1217
1218static int handleAdoptdState(HandlerArg *a)
1219{
1220 HRESULT rc;
1221
1222 if (a->argc != 2)
1223 return errorSyntax(USAGE_ADOPTSTATE, "Incorrect number of parameters");
1224
1225 ComPtr<IMachine> machine;
1226 /* assume it's a UUID */
1227 rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
1228 if (FAILED(rc) || !machine)
1229 {
1230 /* must be a name */
1231 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
1232 }
1233 if (machine)
1234 {
1235 do
1236 {
1237 /* we have to open a session for this task */
1238 Bstr guid;
1239 machine->COMGETTER(Id)(guid.asOutParam());
1240 CHECK_ERROR_BREAK(a->virtualBox, OpenSession(a->session, guid));
1241 do
1242 {
1243 ComPtr<IConsole> console;
1244 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
1245 CHECK_ERROR_BREAK(console, AdoptSavedState (Bstr (a->argv[1])));
1246 }
1247 while (0);
1248 CHECK_ERROR_BREAK(a->session, Close());
1249 }
1250 while (0);
1251 }
1252
1253 return SUCCEEDED(rc) ? 0 : 1;
1254}
1255
1256static int handleGetExtraData(HandlerArg *a)
1257{
1258 HRESULT rc = S_OK;
1259
1260 if (a->argc != 2)
1261 return errorSyntax(USAGE_GETEXTRADATA, "Incorrect number of parameters");
1262
1263 /* global data? */
1264 if (!strcmp(a->argv[0], "global"))
1265 {
1266 /* enumeration? */
1267 if (!strcmp(a->argv[1], "enumerate"))
1268 {
1269 SafeArray<BSTR> aKeys;
1270 CHECK_ERROR(a->virtualBox, GetExtraDataKeys(ComSafeArrayAsOutParam(aKeys)));
1271
1272 for (size_t i = 0;
1273 i < aKeys.size();
1274 ++i)
1275 {
1276 Bstr bstrKey(aKeys[i]);
1277 Bstr bstrValue;
1278 CHECK_ERROR(a->virtualBox, GetExtraData(bstrKey, bstrValue.asOutParam()));
1279
1280 RTPrintf("Key: %lS, Value: %lS\n", bstrKey.raw(), bstrValue.raw());
1281 }
1282 }
1283 else
1284 {
1285 Bstr value;
1286 CHECK_ERROR(a->virtualBox, GetExtraData(Bstr(a->argv[1]), value.asOutParam()));
1287 if (!value.isEmpty())
1288 RTPrintf("Value: %lS\n", value.raw());
1289 else
1290 RTPrintf("No value set!\n");
1291 }
1292 }
1293 else
1294 {
1295 ComPtr<IMachine> machine;
1296 /* assume it's a UUID */
1297 rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
1298 if (FAILED(rc) || !machine)
1299 {
1300 /* must be a name */
1301 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
1302 }
1303 if (machine)
1304 {
1305 /* enumeration? */
1306 if (!strcmp(a->argv[1], "enumerate"))
1307 {
1308 SafeArray<BSTR> aKeys;
1309 CHECK_ERROR(machine, GetExtraDataKeys(ComSafeArrayAsOutParam(aKeys)));
1310
1311 for (size_t i = 0;
1312 i < aKeys.size();
1313 ++i)
1314 {
1315 Bstr bstrKey(aKeys[i]);
1316 Bstr bstrValue;
1317 CHECK_ERROR(machine, GetExtraData(bstrKey, bstrValue.asOutParam()));
1318
1319 RTPrintf("Key: %lS, Value: %lS\n", bstrKey.raw(), bstrValue.raw());
1320 }
1321 }
1322 else
1323 {
1324 Bstr value;
1325 CHECK_ERROR(machine, GetExtraData(Bstr(a->argv[1]), value.asOutParam()));
1326 if (!value.isEmpty())
1327 RTPrintf("Value: %lS\n", value.raw());
1328 else
1329 RTPrintf("No value set!\n");
1330 }
1331 }
1332 }
1333 return SUCCEEDED(rc) ? 0 : 1;
1334}
1335
1336static int handleSetExtraData(HandlerArg *a)
1337{
1338 HRESULT rc = S_OK;
1339
1340 if (a->argc < 2)
1341 return errorSyntax(USAGE_SETEXTRADATA, "Not enough parameters");
1342
1343 /* global data? */
1344 if (!strcmp(a->argv[0], "global"))
1345 {
1346 if (a->argc < 3)
1347 CHECK_ERROR(a->virtualBox, SetExtraData(Bstr(a->argv[1]), NULL));
1348 else if (a->argc == 3)
1349 CHECK_ERROR(a->virtualBox, SetExtraData(Bstr(a->argv[1]), Bstr(a->argv[2])));
1350 else
1351 return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
1352 }
1353 else
1354 {
1355 ComPtr<IMachine> machine;
1356 /* assume it's a UUID */
1357 rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
1358 if (FAILED(rc) || !machine)
1359 {
1360 /* must be a name */
1361 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
1362 }
1363 if (machine)
1364 {
1365 if (a->argc < 3)
1366 CHECK_ERROR(machine, SetExtraData(Bstr(a->argv[1]), NULL));
1367 else if (a->argc == 3)
1368 CHECK_ERROR(machine, SetExtraData(Bstr(a->argv[1]), Bstr(a->argv[2])));
1369 else
1370 return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
1371 }
1372 }
1373 return SUCCEEDED(rc) ? 0 : 1;
1374}
1375
1376static int handleSetProperty(HandlerArg *a)
1377{
1378 HRESULT rc;
1379
1380 /* there must be two arguments: property name and value */
1381 if (a->argc != 2)
1382 return errorSyntax(USAGE_SETPROPERTY, "Incorrect number of parameters");
1383
1384 ComPtr<ISystemProperties> systemProperties;
1385 a->virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
1386
1387 if (!strcmp(a->argv[0], "hdfolder"))
1388 {
1389 /* reset to default? */
1390 if (!strcmp(a->argv[1], "default"))
1391 CHECK_ERROR(systemProperties, COMSETTER(DefaultHardDiskFolder)(NULL));
1392 else
1393 CHECK_ERROR(systemProperties, COMSETTER(DefaultHardDiskFolder)(Bstr(a->argv[1])));
1394 }
1395 else if (!strcmp(a->argv[0], "machinefolder"))
1396 {
1397 /* reset to default? */
1398 if (!strcmp(a->argv[1], "default"))
1399 CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(NULL));
1400 else
1401 CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(Bstr(a->argv[1])));
1402 }
1403 else if (!strcmp(a->argv[0], "vrdpauthlibrary"))
1404 {
1405 /* reset to default? */
1406 if (!strcmp(a->argv[1], "default"))
1407 CHECK_ERROR(systemProperties, COMSETTER(RemoteDisplayAuthLibrary)(NULL));
1408 else
1409 CHECK_ERROR(systemProperties, COMSETTER(RemoteDisplayAuthLibrary)(Bstr(a->argv[1])));
1410 }
1411 else if (!strcmp(a->argv[0], "websrvauthlibrary"))
1412 {
1413 /* reset to default? */
1414 if (!strcmp(a->argv[1], "default"))
1415 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(NULL));
1416 else
1417 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(Bstr(a->argv[1])));
1418 }
1419 else if (!strcmp(a->argv[0], "loghistorycount"))
1420 {
1421 uint32_t uVal;
1422 int vrc;
1423 vrc = RTStrToUInt32Ex(a->argv[1], NULL, 0, &uVal);
1424 if (vrc != VINF_SUCCESS)
1425 return errorArgument("Error parsing Log history count '%s'", a->argv[1]);
1426 CHECK_ERROR(systemProperties, COMSETTER(LogHistoryCount)(uVal));
1427 }
1428 else
1429 return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", a->argv[0]);
1430
1431 return SUCCEEDED(rc) ? 0 : 1;
1432}
1433
1434static int handleSharedFolder (HandlerArg *a)
1435{
1436 HRESULT rc;
1437
1438 /* we need at least a command and target */
1439 if (a->argc < 2)
1440 return errorSyntax(USAGE_SHAREDFOLDER, "Not enough parameters");
1441
1442 ComPtr<IMachine> machine;
1443 /* assume it's a UUID */
1444 rc = a->virtualBox->GetMachine(Bstr(a->argv[1]), machine.asOutParam());
1445 if (FAILED(rc) || !machine)
1446 {
1447 /* must be a name */
1448 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[1]), machine.asOutParam()));
1449 }
1450 if (!machine)
1451 return 1;
1452 Bstr uuid;
1453 machine->COMGETTER(Id)(uuid.asOutParam());
1454
1455 if (!strcmp(a->argv[0], "add"))
1456 {
1457 /* we need at least four more parameters */
1458 if (a->argc < 5)
1459 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Not enough parameters");
1460
1461 char *name = NULL;
1462 char *hostpath = NULL;
1463 bool fTransient = false;
1464 bool fWritable = true;
1465
1466 for (int i = 2; i < a->argc; i++)
1467 {
1468 if ( !strcmp(a->argv[i], "--name")
1469 || !strcmp(a->argv[i], "-name"))
1470 {
1471 if (a->argc <= i + 1 || !*a->argv[i+1])
1472 return errorArgument("Missing argument to '%s'", a->argv[i]);
1473 i++;
1474 name = a->argv[i];
1475 }
1476 else if ( !strcmp(a->argv[i], "--hostpath")
1477 || !strcmp(a->argv[i], "-hostpath"))
1478 {
1479 if (a->argc <= i + 1 || !*a->argv[i+1])
1480 return errorArgument("Missing argument to '%s'", a->argv[i]);
1481 i++;
1482 hostpath = a->argv[i];
1483 }
1484 else if ( !strcmp(a->argv[i], "--readonly")
1485 || !strcmp(a->argv[i], "-readonly"))
1486 {
1487 fWritable = false;
1488 }
1489 else if ( !strcmp(a->argv[i], "--transient")
1490 || !strcmp(a->argv[i], "-transient"))
1491 {
1492 fTransient = true;
1493 }
1494 else
1495 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Invalid parameter '%s'", Utf8Str(a->argv[i]).raw());
1496 }
1497
1498 if (NULL != strstr(name, " "))
1499 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "No spaces allowed in parameter '-name'!");
1500
1501 /* required arguments */
1502 if (!name || !hostpath)
1503 {
1504 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Parameters --name and --hostpath are required");
1505 }
1506
1507 if (fTransient)
1508 {
1509 ComPtr <IConsole> console;
1510
1511 /* open an existing session for the VM */
1512 CHECK_ERROR_RET(a->virtualBox, OpenExistingSession (a->session, uuid), 1);
1513 /* get the session machine */
1514 CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
1515 /* get the session console */
1516 CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
1517
1518 CHECK_ERROR(console, CreateSharedFolder(Bstr(name), Bstr(hostpath), fWritable));
1519
1520 if (console)
1521 a->session->Close();
1522 }
1523 else
1524 {
1525 /* open a session for the VM */
1526 CHECK_ERROR_RET (a->virtualBox, OpenSession(a->session, uuid), 1);
1527
1528 /* get the mutable session machine */
1529 a->session->COMGETTER(Machine)(machine.asOutParam());
1530
1531 CHECK_ERROR(machine, CreateSharedFolder(Bstr(name), Bstr(hostpath), fWritable));
1532
1533 if (SUCCEEDED(rc))
1534 CHECK_ERROR(machine, SaveSettings());
1535
1536 a->session->Close();
1537 }
1538 }
1539 else if (!strcmp(a->argv[0], "remove"))
1540 {
1541 /* we need at least two more parameters */
1542 if (a->argc < 3)
1543 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Not enough parameters");
1544
1545 char *name = NULL;
1546 bool fTransient = false;
1547
1548 for (int i = 2; i < a->argc; i++)
1549 {
1550 if ( !strcmp(a->argv[i], "--name")
1551 || !strcmp(a->argv[i], "-name"))
1552 {
1553 if (a->argc <= i + 1 || !*a->argv[i+1])
1554 return errorArgument("Missing argument to '%s'", a->argv[i]);
1555 i++;
1556 name = a->argv[i];
1557 }
1558 else if ( !strcmp(a->argv[i], "--transient")
1559 || !strcmp(a->argv[i], "-transient"))
1560 {
1561 fTransient = true;
1562 }
1563 else
1564 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Invalid parameter '%s'", Utf8Str(a->argv[i]).raw());
1565 }
1566
1567 /* required arguments */
1568 if (!name)
1569 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Parameter --name is required");
1570
1571 if (fTransient)
1572 {
1573 ComPtr <IConsole> console;
1574
1575 /* open an existing session for the VM */
1576 CHECK_ERROR_RET(a->virtualBox, OpenExistingSession (a->session, uuid), 1);
1577 /* get the session machine */
1578 CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
1579 /* get the session console */
1580 CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
1581
1582 CHECK_ERROR(console, RemoveSharedFolder(Bstr(name)));
1583
1584 if (console)
1585 a->session->Close();
1586 }
1587 else
1588 {
1589 /* open a session for the VM */
1590 CHECK_ERROR_RET (a->virtualBox, OpenSession(a->session, uuid), 1);
1591
1592 /* get the mutable session machine */
1593 a->session->COMGETTER(Machine)(machine.asOutParam());
1594
1595 CHECK_ERROR(machine, RemoveSharedFolder(Bstr(name)));
1596
1597 /* commit and close the session */
1598 CHECK_ERROR(machine, SaveSettings());
1599 a->session->Close();
1600 }
1601 }
1602 else
1603 return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", Utf8Str(a->argv[0]).raw());
1604
1605 return 0;
1606}
1607
1608static int handleVMStatistics(HandlerArg *a)
1609{
1610 HRESULT rc;
1611
1612 /* at least one option: the UUID or name of the VM */
1613 if (a->argc < 1)
1614 return errorSyntax(USAGE_VM_STATISTICS, "Incorrect number of parameters");
1615
1616 /* try to find the given machine */
1617 ComPtr <IMachine> machine;
1618 Bstr uuid (a->argv[0]);
1619 if (!Guid (a->argv[0]).isEmpty())
1620 CHECK_ERROR(a->virtualBox, GetMachine(uuid, machine.asOutParam()));
1621 else
1622 {
1623 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
1624 if (SUCCEEDED (rc))
1625 machine->COMGETTER(Id)(uuid.asOutParam());
1626 }
1627 if (FAILED(rc))
1628 return 1;
1629
1630 /* parse arguments. */
1631 bool fReset = false;
1632 bool fWithDescriptions = false;
1633 const char *pszPattern = NULL; /* all */
1634 for (int i = 1; i < a->argc; i++)
1635 {
1636 if ( !strcmp(a->argv[i], "--pattern")
1637 || !strcmp(a->argv[i], "-pattern"))
1638 {
1639 if (pszPattern)
1640 return errorSyntax(USAGE_VM_STATISTICS, "Multiple --patterns options is not permitted");
1641 if (i + 1 >= a->argc)
1642 return errorArgument("Missing argument to '%s'", a->argv[i]);
1643 pszPattern = a->argv[++i];
1644 }
1645 else if ( !strcmp(a->argv[i], "--descriptions")
1646 || !strcmp(a->argv[i], "-descriptions"))
1647 fWithDescriptions = true;
1648 /* add: --file <filename> and --formatted */
1649 else if ( !strcmp(a->argv[i], "--reset")
1650 || !strcmp(a->argv[i], "-reset"))
1651 fReset = true;
1652 else
1653 return errorSyntax(USAGE_VM_STATISTICS, "Unknown option '%s'", a->argv[i]);
1654 }
1655 if (fReset && fWithDescriptions)
1656 return errorSyntax(USAGE_VM_STATISTICS, "The --reset and --descriptions options does not mix");
1657
1658
1659 /* open an existing session for the VM. */
1660 CHECK_ERROR(a->virtualBox, OpenExistingSession(a->session, uuid));
1661 if (SUCCEEDED(rc))
1662 {
1663 /* get the session console. */
1664 ComPtr <IConsole> console;
1665 CHECK_ERROR(a->session, COMGETTER(Console)(console.asOutParam()));
1666 if (SUCCEEDED(rc))
1667 {
1668 /* get the machine debugger. */
1669 ComPtr <IMachineDebugger> debugger;
1670 CHECK_ERROR(console, COMGETTER(Debugger)(debugger.asOutParam()));
1671 if (SUCCEEDED(rc))
1672 {
1673 if (fReset)
1674 CHECK_ERROR(debugger, ResetStats(Bstr(pszPattern)));
1675 else
1676 {
1677 Bstr stats;
1678 CHECK_ERROR(debugger, GetStats(Bstr(pszPattern), fWithDescriptions, stats.asOutParam()));
1679 if (SUCCEEDED(rc))
1680 {
1681 /* if (fFormatted)
1682 { big mess }
1683 else
1684 */
1685 RTPrintf("%ls\n", stats.raw());
1686 }
1687 }
1688 }
1689 a->session->Close();
1690 }
1691 }
1692
1693 return SUCCEEDED(rc) ? 0 : 1;
1694}
1695#endif /* !VBOX_ONLY_DOCS */
1696
1697// main
1698///////////////////////////////////////////////////////////////////////////////
1699
1700int main(int argc, char *argv[])
1701{
1702 /*
1703 * Before we do anything, init the runtime without loading
1704 * the support driver.
1705 */
1706 RTR3Init();
1707
1708 bool fShowLogo = true;
1709 int iCmd = 1;
1710 int iCmdArg;
1711
1712 /* global options */
1713 for (int i = 1; i < argc || argc <= iCmd; i++)
1714 {
1715 if ( argc <= iCmd
1716 || !strcmp(argv[i], "help")
1717 || !strcmp(argv[i], "-?")
1718 || !strcmp(argv[i], "-h")
1719 || !strcmp(argv[i], "-help")
1720 || !strcmp(argv[i], "--help"))
1721 {
1722 showLogo();
1723 printUsage(USAGE_ALL);
1724 return 0;
1725 }
1726 else if ( !strcmp(argv[i], "-v")
1727 || !strcmp(argv[i], "-version")
1728 || !strcmp(argv[i], "-Version")
1729 || !strcmp(argv[i], "--version"))
1730 {
1731 /* Print version number, and do nothing else. */
1732 RTPrintf("%sr%d\n", VBOX_VERSION_STRING, VBoxSVNRev ());
1733 return 0;
1734 }
1735 else if ( !strcmp(argv[i], "--dumpopts")
1736 || !strcmp(argv[i], "-dumpopts"))
1737 {
1738 /* Special option to dump really all commands,
1739 * even the ones not understood on this platform. */
1740 printUsage(USAGE_DUMPOPTS);
1741 return 0;
1742 }
1743 else if ( !strcmp(argv[i], "--nologo")
1744 || !strcmp(argv[i], "-nologo")
1745 || !strcmp(argv[i], "-q"))
1746 {
1747 /* suppress the logo */
1748 fShowLogo = false;
1749 iCmd++;
1750 }
1751 else
1752 {
1753 break;
1754 }
1755 }
1756
1757 iCmdArg = iCmd + 1;
1758
1759 if (fShowLogo)
1760 showLogo();
1761
1762
1763#ifdef VBOX_ONLY_DOCS
1764 int rc = 0;
1765#else /* !VBOX_ONLY_DOCS */
1766 HRESULT rc = 0;
1767
1768 rc = com::Initialize();
1769 if (FAILED(rc))
1770 {
1771 RTPrintf("ERROR: failed to initialize COM!\n");
1772 return rc;
1773 }
1774
1775 /*
1776 * The input is in the host OS'es codepage (NT guarantees ACP).
1777 * For VBox we use UTF-8 and convert to UCS-2 when calling (XP)COM APIs.
1778 * For simplicity, just convert the argv[] array here.
1779 */
1780 for (int i = iCmdArg; i < argc; i++)
1781 {
1782 char *converted;
1783 RTStrCurrentCPToUtf8(&converted, argv[i]);
1784 argv[i] = converted;
1785 }
1786
1787 do
1788 {
1789 // scopes all the stuff till shutdown
1790 ////////////////////////////////////////////////////////////////////////////
1791
1792 /* convertfromraw: does not need a VirtualBox instantiation. */
1793 if (argc >= iCmdArg && ( !strcmp(argv[iCmd], "convertfromraw")
1794 || !strcmp(argv[iCmd], "convertdd")))
1795 {
1796 rc = handleConvertFromRaw(argc - iCmdArg, argv + iCmdArg);
1797 break;
1798 }
1799
1800 ComPtr<IVirtualBox> virtualBox;
1801 ComPtr<ISession> session;
1802
1803 rc = virtualBox.createLocalObject(CLSID_VirtualBox);
1804 if (FAILED(rc))
1805 RTPrintf("ERROR: failed to create the VirtualBox object!\n");
1806 else
1807 {
1808 rc = session.createInprocObject(CLSID_Session);
1809 if (FAILED(rc))
1810 RTPrintf("ERROR: failed to create a session object!\n");
1811 }
1812
1813 if (FAILED(rc))
1814 {
1815 com::ErrorInfo info;
1816 if (!info.isFullAvailable() && !info.isBasicAvailable())
1817 {
1818 com::GluePrintRCMessage(rc);
1819 RTPrintf("Most likely, the VirtualBox COM server is not running or failed to start.\n");
1820 }
1821 else
1822 com::GluePrintErrorInfo(info);
1823 break;
1824 }
1825
1826 /* create the event queue
1827 * (here it is necessary only to process remaining XPCOM/IPC events
1828 * after the session is closed) */
1829
1830#ifdef USE_XPCOM_QUEUE
1831 nsCOMPtr<nsIEventQueue> eventQ;
1832 NS_GetMainEventQ(getter_AddRefs(eventQ));
1833#endif
1834
1835#ifdef USE_XPCOM_QUEUE
1836 HandlerArg handlerArg = { 0, NULL, eventQ, virtualBox, session };
1837#else
1838 HandlerArg handlerArg = { 0, NULL, virtualBox, session };
1839#endif
1840
1841 /*
1842 * All registered command handlers
1843 */
1844 struct
1845 {
1846 const char *command;
1847 PFNHANDLER handler;
1848 } commandHandlers[] =
1849 {
1850 { "internalcommands", handleInternalCommands },
1851 { "list", handleList },
1852 { "showvminfo", handleShowVMInfo },
1853 { "registervm", handleRegisterVM },
1854 { "unregistervm", handleUnregisterVM },
1855 { "createhd", handleCreateHardDisk },
1856 { "createvdi", handleCreateHardDisk }, /* backward compatiblity */
1857 { "modifyhd", handleModifyHardDisk },
1858 { "modifyvdi", handleModifyHardDisk }, /* backward compatiblity */
1859 { "clonehd", handleCloneHardDisk },
1860 { "clonevdi", handleCloneHardDisk }, /* backward compatiblity */
1861 { "addiscsidisk", handleAddiSCSIDisk },
1862 { "createvm", handleCreateVM },
1863 { "modifyvm", handleModifyVM },
1864 { "startvm", handleStartVM },
1865 { "controlvm", handleControlVM },
1866 { "discardstate", handleDiscardState },
1867 { "adoptstate", handleAdoptdState },
1868 { "snapshot", handleSnapshot },
1869 { "openmedium", handleOpenMedium },
1870 { "registerimage", handleOpenMedium }, /* backward compatiblity */
1871 { "closemedium", handleCloseMedium },
1872 { "unregisterimage", handleCloseMedium }, /* backward compatiblity */
1873 { "showhdinfo", handleShowHardDiskInfo },
1874 { "showvdiinfo", handleShowHardDiskInfo }, /* backward compatiblity */
1875 { "getextradata", handleGetExtraData },
1876 { "setextradata", handleSetExtraData },
1877 { "setproperty", handleSetProperty },
1878 { "usbfilter", handleUSBFilter },
1879 { "sharedfolder", handleSharedFolder },
1880 { "vmstatistics", handleVMStatistics },
1881#ifdef VBOX_WITH_GUEST_PROPS
1882 { "guestproperty", handleGuestProperty },
1883#endif /* VBOX_WITH_GUEST_PROPS defined */
1884 { "metrics", handleMetrics },
1885 { "import", handleImportAppliance },
1886 { "export", handleExportAppliance },
1887#if defined(VBOX_WITH_NETFLT)
1888 { "hostonlyif", handleHostonlyIf },
1889#endif
1890 { "dhcpserver", handleDHCPServer},
1891 { NULL, NULL }
1892 };
1893
1894 int commandIndex;
1895 for (commandIndex = 0; commandHandlers[commandIndex].command != NULL; commandIndex++)
1896 {
1897 if (!strcmp(commandHandlers[commandIndex].command, argv[iCmd]))
1898 {
1899 handlerArg.argc = argc - iCmdArg;
1900 handlerArg.argv = &argv[iCmdArg];
1901
1902 rc = commandHandlers[commandIndex].handler(&handlerArg);
1903 break;
1904 }
1905 }
1906 if (!commandHandlers[commandIndex].command)
1907 {
1908 rc = errorSyntax(USAGE_ALL, "Invalid command '%s'", Utf8Str(argv[iCmd]).raw());
1909 }
1910
1911 /* Although all handlers should always close the session if they open it,
1912 * we do it here just in case if some of the handlers contains a bug --
1913 * leaving the direct session not closed will turn the machine state to
1914 * Aborted which may have unwanted side effects like killing the saved
1915 * state file (if the machine was in the Saved state before). */
1916 session->Close();
1917
1918#ifdef USE_XPCOM_QUEUE
1919 eventQ->ProcessPendingEvents();
1920#endif
1921
1922 // end "all-stuff" scope
1923 ////////////////////////////////////////////////////////////////////////////
1924 }
1925 while (0);
1926
1927 com::Shutdown();
1928#endif /* !VBOX_ONLY_DOCS */
1929
1930 /*
1931 * Free converted argument vector
1932 */
1933 for (int i = iCmdArg; i < argc; i++)
1934 RTStrFree(argv[i]);
1935
1936 return rc != 0;
1937}
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