VirtualBox

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

Last change on this file since 18782 was 18782, checked in by vboxsync, 16 years ago

VBoxManage: remaining double-dash command line options, help update, allow starting SDL VMs via VBoxManage startvm

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