VirtualBox

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

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

Frontends/VBoxManage, Main/Machine: implement new session type "headless" which suppresses any output. Based on the contribution by Josh Wright.

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