VirtualBox

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

最後變更 在這個檔案從21506是 21446,由 vboxsync 提交於 16 年 前

API/Machine+SystemProperties: get rid of the tri-state bool controlling hwvirtex

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 71.0 KB
 
1/* $Id: VBoxManage.cpp 21446 2009-07-09 15:09:57Z 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.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#ifndef VBOX_ONLY_DOCS
27#include <VBox/com/com.h>
28#include <VBox/com/string.h>
29#include <VBox/com/Guid.h>
30#include <VBox/com/array.h>
31#include <VBox/com/ErrorInfo.h>
32#include <VBox/com/errorprint.h>
33#include <VBox/com/EventQueue.h>
34
35#include <VBox/com/VirtualBox.h>
36
37#include <vector>
38#include <list>
39#endif /* !VBOX_ONLY_DOCS */
40
41#include <iprt/asm.h>
42#include <iprt/cidr.h>
43#include <iprt/ctype.h>
44#include <iprt/dir.h>
45#include <iprt/env.h>
46#include <VBox/err.h>
47#include <iprt/file.h>
48#include <iprt/initterm.h>
49#include <iprt/param.h>
50#include <iprt/path.h>
51#include <iprt/stream.h>
52#include <iprt/string.h>
53#include <iprt/stdarg.h>
54#include <iprt/thread.h>
55#include <iprt/uuid.h>
56#include <iprt/getopt.h>
57#include <iprt/ctype.h>
58#include <VBox/version.h>
59#include <VBox/log.h>
60
61#include "VBoxManage.h"
62
63#ifndef VBOX_ONLY_DOCS
64using namespace com;
65
66/** command handler type */
67typedef int (*PFNHANDLER)(HandlerArg *a);
68
69#endif /* !VBOX_ONLY_DOCS */
70
71////////////////////////////////////////////////////////////////////////////////
72//
73// global variables
74//
75////////////////////////////////////////////////////////////////////////////////
76
77/*extern*/ bool g_fDetailedProgress = false;
78
79////////////////////////////////////////////////////////////////////////////////
80//
81// functions
82//
83////////////////////////////////////////////////////////////////////////////////
84
85#ifndef VBOX_ONLY_DOCS
86/**
87 * Print out progress on the console
88 */
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 com::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 ComPtr<IProgress> progress;
611 CHECK_ERROR_BREAK (console, PowerDown(progress.asOutParam()));
612
613 showProgress(progress);
614
615 LONG iRc;
616 progress->COMGETTER(ResultCode)(&iRc);
617 if (FAILED(iRc))
618 {
619 com::ProgressErrorInfo info(progress);
620 if (info.isBasicAvailable())
621 {
622 RTPrintf("Error: failed to power off machine. Error message: %lS\n", info.getText().raw());
623 }
624 else
625 {
626 RTPrintf("Error: failed to power off machine. No error message available!\n");
627 }
628 }
629 }
630 else if (!strcmp(a->argv[1], "savestate"))
631 {
632 ComPtr<IProgress> progress;
633 CHECK_ERROR_BREAK (console, SaveState(progress.asOutParam()));
634
635 showProgress(progress);
636
637 LONG iRc;
638 progress->COMGETTER(ResultCode)(&iRc);
639 if (FAILED(iRc))
640 {
641 com::ProgressErrorInfo info(progress);
642 if (info.isBasicAvailable())
643 {
644 RTPrintf("Error: failed to save machine state. Error message: %lS\n", info.getText().raw());
645 }
646 else
647 {
648 RTPrintf("Error: failed to save machine state. No error message available!\n");
649 }
650 }
651 }
652 else if (!strcmp(a->argv[1], "acpipowerbutton"))
653 {
654 CHECK_ERROR_BREAK (console, PowerButton());
655 }
656 else if (!strcmp(a->argv[1], "acpisleepbutton"))
657 {
658 CHECK_ERROR_BREAK (console, SleepButton());
659 }
660 else if (!strcmp(a->argv[1], "injectnmi"))
661 {
662 /* get the machine debugger. */
663 ComPtr <IMachineDebugger> debugger;
664 CHECK_ERROR_BREAK(console, COMGETTER(Debugger)(debugger.asOutParam()));
665 CHECK_ERROR_BREAK(debugger, InjectNMI());
666 }
667 else if (!strcmp(a->argv[1], "keyboardputscancode"))
668 {
669 ComPtr<IKeyboard> keyboard;
670 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(keyboard.asOutParam()));
671
672 if (a->argc <= 1 + 1)
673 {
674 errorArgument("Missing argument to '%s'. Expected IBM PC AT set 2 keyboard scancode(s) as hex byte(s).", a->argv[1]);
675 rc = E_FAIL;
676 break;
677 }
678
679 /* Arbitrary restrict the length of a sequence of scancodes to 1024. */
680 LONG alScancodes[1024];
681 int cScancodes = 0;
682
683 /* Process the command line. */
684 int i;
685 for (i = 1 + 1; i < a->argc && cScancodes < (int)RT_ELEMENTS(alScancodes); i++, cScancodes++)
686 {
687 if ( RT_C_IS_XDIGIT (a->argv[i][0])
688 && RT_C_IS_XDIGIT (a->argv[i][1])
689 && a->argv[i][2] == 0)
690 {
691 uint8_t u8Scancode;
692 int rc = RTStrToUInt8Ex(a->argv[i], NULL, 16, &u8Scancode);
693 if (RT_FAILURE (rc))
694 {
695 RTPrintf("Error: converting '%s' returned %Rrc!\n", a->argv[i], rc);
696 rc = E_FAIL;
697 break;
698 }
699
700 alScancodes[cScancodes] = u8Scancode;
701 }
702 else
703 {
704 RTPrintf("Error: '%s' is not a hex byte!\n", a->argv[i]);
705 rc = E_FAIL;
706 break;
707 }
708 }
709
710 if (FAILED(rc))
711 break;
712
713 if ( cScancodes == RT_ELEMENTS(alScancodes)
714 && i < a->argc)
715 {
716 RTPrintf("Error: too many scancodes, maximum %d allowed!\n", RT_ELEMENTS(alScancodes));
717 rc = E_FAIL;
718 break;
719 }
720
721 /* Send scancodes to the VM.
722 * Note: 'PutScancodes' did not work here. Only the first scancode was transmitted.
723 */
724 for (i = 0; i < cScancodes; i++)
725 {
726 CHECK_ERROR_BREAK(keyboard, PutScancode(alScancodes[i]));
727 RTPrintf("Scancode[%d]: 0x%02X\n", i, alScancodes[i]);
728 }
729 }
730 else if (!strncmp(a->argv[1], "setlinkstate", 12))
731 {
732 /* Get the number of network adapters */
733 ULONG NetworkAdapterCount = 0;
734 ComPtr <ISystemProperties> info;
735 CHECK_ERROR_BREAK (a->virtualBox, COMGETTER(SystemProperties) (info.asOutParam()));
736 CHECK_ERROR_BREAK (info, COMGETTER(NetworkAdapterCount) (&NetworkAdapterCount));
737
738 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
739 if (!n)
740 {
741 rc = E_FAIL;
742 break;
743 }
744 if (a->argc <= 1 + 1)
745 {
746 errorArgument("Missing argument to '%s'", a->argv[1]);
747 rc = E_FAIL;
748 break;
749 }
750 /* get the corresponding network adapter */
751 ComPtr<INetworkAdapter> adapter;
752 CHECK_ERROR_BREAK (sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
753 if (adapter)
754 {
755 if (!strcmp(a->argv[2], "on"))
756 {
757 CHECK_ERROR_BREAK (adapter, COMSETTER(CableConnected)(TRUE));
758 }
759 else if (!strcmp(a->argv[2], "off"))
760 {
761 CHECK_ERROR_BREAK (adapter, COMSETTER(CableConnected)(FALSE));
762 }
763 else
764 {
765 errorArgument("Invalid link state '%s'", Utf8Str(a->argv[2]).raw());
766 rc = E_FAIL;
767 break;
768 }
769 }
770 }
771#ifdef VBOX_DYNAMIC_NET_ATTACH
772 else if (!strncmp(a->argv[1], "nic", 3))
773 {
774 /* Get the number of network adapters */
775 ULONG NetworkAdapterCount = 0;
776 ComPtr <ISystemProperties> info;
777 CHECK_ERROR_BREAK (a->virtualBox, COMGETTER(SystemProperties) (info.asOutParam()));
778 CHECK_ERROR_BREAK (info, COMGETTER(NetworkAdapterCount) (&NetworkAdapterCount));
779
780 unsigned n = parseNum(&a->argv[1][3], NetworkAdapterCount, "NIC");
781 if (!n)
782 {
783 rc = E_FAIL;
784 break;
785 }
786 if (a->argc <= 1 + 1)
787 {
788 errorArgument("Missing argument to '%s'", a->argv[1]);
789 rc = E_FAIL;
790 break;
791 }
792
793 /* get the corresponding network adapter */
794 ComPtr<INetworkAdapter> adapter;
795 CHECK_ERROR_BREAK (sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
796 if (adapter)
797 {
798 if (!strcmp(a->argv[2], "none"))
799 {
800 CHECK_ERROR_RET(adapter, COMSETTER(Enabled) (FALSE), 1);
801 }
802 else if (!strcmp(a->argv[2], "null"))
803 {
804 CHECK_ERROR_RET(adapter, COMSETTER(Enabled) (TRUE), 1);
805 CHECK_ERROR_RET(adapter, Detach(), 1);
806 }
807 else if (!strcmp(a->argv[2], "nat"))
808 {
809 if (a->argc == 3)
810 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3])), 1);
811 CHECK_ERROR_RET(adapter, COMSETTER(Enabled) (TRUE), 1);
812 CHECK_ERROR_RET(adapter, AttachToNAT(), 1);
813 }
814 else if ( !strcmp(a->argv[2], "bridged")
815 || !strcmp(a->argv[2], "hostif")) /* backward compatibility */
816 {
817 if (a->argc <= 1 + 2)
818 {
819 errorArgument("Missing argument to '%s'", a->argv[2]);
820 rc = E_FAIL;
821 break;
822 }
823 CHECK_ERROR_RET(adapter, COMSETTER(HostInterface)(Bstr(a->argv[3])), 1);
824 CHECK_ERROR_RET(adapter, COMSETTER(Enabled) (TRUE), 1);
825 CHECK_ERROR_RET(adapter, AttachToBridgedInterface(), 1);
826 }
827 else if (!strcmp(a->argv[2], "intnet"))
828 {
829 if (a->argc <= 1 + 2)
830 {
831 errorArgument("Missing argument to '%s'", a->argv[2]);
832 rc = E_FAIL;
833 break;
834 }
835 CHECK_ERROR_RET(adapter, COMSETTER(InternalNetwork)(Bstr(a->argv[3])), 1);
836 CHECK_ERROR_RET(adapter, COMSETTER(Enabled) (TRUE), 1);
837 CHECK_ERROR_RET(adapter, AttachToInternalNetwork(), 1);
838 }
839#if defined(VBOX_WITH_NETFLT)
840 else if (!strcmp(a->argv[2], "hostonly"))
841 {
842 if (a->argc <= 1 + 2)
843 {
844 errorArgument("Missing argument to '%s'", a->argv[2]);
845 rc = E_FAIL;
846 break;
847 }
848 CHECK_ERROR_RET(adapter, COMSETTER(HostInterface)(Bstr(a->argv[3])), 1);
849 CHECK_ERROR_RET(adapter, COMSETTER(Enabled) (TRUE), 1);
850 CHECK_ERROR_RET(adapter, AttachToHostOnlyInterface(), 1);
851 }
852#endif
853 else
854 {
855 errorArgument("Invalid type '%s' specfied for NIC %lu", Utf8Str(a->argv[2]).raw(), n + 1);
856 rc = E_FAIL;
857 break;
858 }
859 }
860 }
861#endif /* VBOX_DYNAMIC_NET_ATTACH */
862#ifdef VBOX_WITH_VRDP
863 else if (!strcmp(a->argv[1], "vrdp"))
864 {
865 if (a->argc <= 1 + 1)
866 {
867 errorArgument("Missing argument to '%s'", a->argv[1]);
868 rc = E_FAIL;
869 break;
870 }
871 /* get the corresponding VRDP server */
872 ComPtr<IVRDPServer> vrdpServer;
873 sessionMachine->COMGETTER(VRDPServer)(vrdpServer.asOutParam());
874 ASSERT(vrdpServer);
875 if (vrdpServer)
876 {
877 if (!strcmp(a->argv[2], "on"))
878 {
879 CHECK_ERROR_BREAK (vrdpServer, COMSETTER(Enabled)(TRUE));
880 }
881 else if (!strcmp(a->argv[2], "off"))
882 {
883 CHECK_ERROR_BREAK (vrdpServer, COMSETTER(Enabled)(FALSE));
884 }
885 else
886 {
887 errorArgument("Invalid vrdp server state '%s'", Utf8Str(a->argv[2]).raw());
888 rc = E_FAIL;
889 break;
890 }
891 }
892 }
893#endif /* VBOX_WITH_VRDP */
894 else if ( !strcmp (a->argv[1], "usbattach")
895 || !strcmp (a->argv[1], "usbdetach"))
896 {
897 if (a->argc < 3)
898 {
899 errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
900 rc = E_FAIL;
901 break;
902 }
903
904 bool attach = !strcmp(a->argv[1], "usbattach");
905
906 Bstr usbId = a->argv [2];
907 if (Guid(usbId).isEmpty())
908 {
909 // assume address
910 if (attach)
911 {
912 ComPtr <IHost> host;
913 CHECK_ERROR_BREAK (a->virtualBox, COMGETTER(Host) (host.asOutParam()));
914 SafeIfaceArray <IHostUSBDevice> coll;
915 CHECK_ERROR_BREAK (host, COMGETTER(USBDevices) (ComSafeArrayAsOutParam(coll)));
916 ComPtr <IHostUSBDevice> dev;
917 CHECK_ERROR_BREAK (host, FindUSBDeviceByAddress (Bstr (a->argv [2]), dev.asOutParam()));
918 CHECK_ERROR_BREAK (dev, COMGETTER(Id) (usbId.asOutParam()));
919 }
920 else
921 {
922 SafeIfaceArray <IUSBDevice> coll;
923 CHECK_ERROR_BREAK (console, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
924 ComPtr <IUSBDevice> dev;
925 CHECK_ERROR_BREAK (console, FindUSBDeviceByAddress (Bstr (a->argv [2]),
926 dev.asOutParam()));
927 CHECK_ERROR_BREAK (dev, COMGETTER(Id) (usbId.asOutParam()));
928 }
929 }
930
931 if (attach)
932 CHECK_ERROR_BREAK (console, AttachUSBDevice (usbId));
933 else
934 {
935 ComPtr <IUSBDevice> dev;
936 CHECK_ERROR_BREAK (console, DetachUSBDevice (usbId, dev.asOutParam()));
937 }
938 }
939 else if (!strcmp(a->argv[1], "setvideomodehint"))
940 {
941 if (a->argc != 5 && a->argc != 6)
942 {
943 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
944 rc = E_FAIL;
945 break;
946 }
947 uint32_t xres = RTStrToUInt32(a->argv[2]);
948 uint32_t yres = RTStrToUInt32(a->argv[3]);
949 uint32_t bpp = RTStrToUInt32(a->argv[4]);
950 uint32_t displayIdx = 0;
951 if (a->argc == 6)
952 displayIdx = RTStrToUInt32(a->argv[5]);
953
954 ComPtr<IDisplay> display;
955 CHECK_ERROR_BREAK(console, COMGETTER(Display)(display.asOutParam()));
956 CHECK_ERROR_BREAK(display, SetVideoModeHint(xres, yres, bpp, displayIdx));
957 }
958 else if (!strcmp(a->argv[1], "setcredentials"))
959 {
960 bool fAllowLocalLogon = true;
961 if (a->argc == 7)
962 {
963 if ( strcmp(a->argv[5], "--allowlocallogon")
964 && strcmp(a->argv[5], "-allowlocallogon"))
965 {
966 errorArgument("Invalid parameter '%s'", a->argv[5]);
967 rc = E_FAIL;
968 break;
969 }
970 if (!strcmp(a->argv[6], "no"))
971 fAllowLocalLogon = false;
972 }
973 else if (a->argc != 5)
974 {
975 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
976 rc = E_FAIL;
977 break;
978 }
979
980 ComPtr<IGuest> guest;
981 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(guest.asOutParam()));
982 CHECK_ERROR_BREAK(guest, SetCredentials(Bstr(a->argv[2]), Bstr(a->argv[3]), Bstr(a->argv[4]), fAllowLocalLogon));
983 }
984 else if (!strcmp(a->argv[1], "dvdattach"))
985 {
986 if (a->argc != 3)
987 {
988 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
989 rc = E_FAIL;
990 break;
991 }
992 ComPtr<IDVDDrive> dvdDrive;
993 sessionMachine->COMGETTER(DVDDrive)(dvdDrive.asOutParam());
994 ASSERT(dvdDrive);
995
996 /* unmount? */
997 if (!strcmp(a->argv[2], "none"))
998 {
999 CHECK_ERROR(dvdDrive, Unmount());
1000 }
1001 /* host drive? */
1002 else if (!strncmp(a->argv[2], "host:", 5))
1003 {
1004 ComPtr<IHost> host;
1005 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1006 com::SafeIfaceArray <IHostDVDDrive> hostDVDs;
1007 rc = host->COMGETTER(DVDDrives)(ComSafeArrayAsOutParam(hostDVDs));
1008
1009 ComPtr<IHostDVDDrive> hostDVDDrive;
1010 rc = host->FindHostDVDDrive(Bstr(a->argv[2] + 5), hostDVDDrive.asOutParam());
1011 if (!hostDVDDrive)
1012 {
1013 errorArgument("Invalid host DVD drive name");
1014 rc = E_FAIL;
1015 break;
1016 }
1017 CHECK_ERROR(dvdDrive, CaptureHostDrive(hostDVDDrive));
1018 }
1019 else
1020 {
1021 /* first assume it's a UUID */
1022 Bstr uuid(a->argv[2]);
1023 ComPtr<IDVDImage> dvdImage;
1024 rc = a->virtualBox->GetDVDImage(uuid, dvdImage.asOutParam());
1025 if (FAILED(rc) || !dvdImage)
1026 {
1027 /* must be a filename, check if it's in the collection */
1028 rc = a->virtualBox->FindDVDImage(Bstr(a->argv[2]), dvdImage.asOutParam());
1029 /* not registered, do that on the fly */
1030 if (!dvdImage)
1031 {
1032 Bstr emptyUUID;
1033 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(a->argv[2]), emptyUUID, dvdImage.asOutParam()));
1034 }
1035 }
1036 if (!dvdImage)
1037 {
1038 rc = E_FAIL;
1039 break;
1040 }
1041 dvdImage->COMGETTER(Id)(uuid.asOutParam());
1042 CHECK_ERROR(dvdDrive, MountImage(uuid));
1043 }
1044 }
1045 else if (!strcmp(a->argv[1], "floppyattach"))
1046 {
1047 if (a->argc != 3)
1048 {
1049 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1050 rc = E_FAIL;
1051 break;
1052 }
1053
1054 ComPtr<IFloppyDrive> floppyDrive;
1055 sessionMachine->COMGETTER(FloppyDrive)(floppyDrive.asOutParam());
1056 ASSERT(floppyDrive);
1057
1058 /* unmount? */
1059 if (!strcmp(a->argv[2], "none"))
1060 {
1061 CHECK_ERROR(floppyDrive, Unmount());
1062 }
1063 /* host drive? */
1064 else if (!strncmp(a->argv[2], "host:", 5))
1065 {
1066 ComPtr<IHost> host;
1067 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1068 com::SafeIfaceArray <IHostFloppyDrive> hostFloppies;
1069 rc = host->COMGETTER(FloppyDrives)(ComSafeArrayAsOutParam(hostFloppies));
1070 CheckComRCReturnRC (rc);
1071 ComPtr<IHostFloppyDrive> hostFloppyDrive;
1072 host->FindHostFloppyDrive(Bstr(a->argv[2] + 5), hostFloppyDrive.asOutParam());
1073 if (!hostFloppyDrive)
1074 {
1075 errorArgument("Invalid host floppy drive name");
1076 rc = E_FAIL;
1077 break;
1078 }
1079 CHECK_ERROR(floppyDrive, CaptureHostDrive(hostFloppyDrive));
1080 }
1081 else
1082 {
1083 /* first assume it's a UUID */
1084 Bstr uuid(a->argv[2]);
1085 ComPtr<IFloppyImage> floppyImage;
1086 rc = a->virtualBox->GetFloppyImage(uuid, floppyImage.asOutParam());
1087 if (FAILED(rc) || !floppyImage)
1088 {
1089 /* must be a filename, check if it's in the collection */
1090 rc = a->virtualBox->FindFloppyImage(Bstr(a->argv[2]), floppyImage.asOutParam());
1091 /* not registered, do that on the fly */
1092 if (!floppyImage)
1093 {
1094 Bstr emptyUUID;
1095 CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(a->argv[2]), emptyUUID, floppyImage.asOutParam()));
1096 }
1097 }
1098 if (!floppyImage)
1099 {
1100 rc = E_FAIL;
1101 break;
1102 }
1103 floppyImage->COMGETTER(Id)(uuid.asOutParam());
1104 CHECK_ERROR(floppyDrive, MountImage(uuid));
1105 }
1106 }
1107#ifdef VBOX_WITH_MEM_BALLOONING
1108 else if ( !strcmp(a->argv[1], "--guestmemoryballoon")
1109 || !strcmp(a->argv[1], "-guestmemoryballoon"))
1110 {
1111 if (a->argc != 3)
1112 {
1113 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1114 rc = E_FAIL;
1115 break;
1116 }
1117 uint32_t uVal;
1118 int vrc;
1119 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1120 if (vrc != VINF_SUCCESS)
1121 {
1122 errorArgument("Error parsing guest memory balloon size '%s'", a->argv[2]);
1123 rc = E_FAIL;
1124 break;
1125 }
1126
1127 /* guest is running; update IGuest */
1128 ComPtr <IGuest> guest;
1129
1130 rc = console->COMGETTER(Guest)(guest.asOutParam());
1131 if (SUCCEEDED(rc))
1132 CHECK_ERROR(guest, COMSETTER(MemoryBalloonSize)(uVal));
1133 }
1134#endif
1135 else if ( !strcmp(a->argv[1], "--gueststatisticsinterval")
1136 || !strcmp(a->argv[1], "-gueststatisticsinterval"))
1137 {
1138 if (a->argc != 3)
1139 {
1140 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1141 rc = E_FAIL;
1142 break;
1143 }
1144 uint32_t uVal;
1145 int vrc;
1146 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1147 if (vrc != VINF_SUCCESS)
1148 {
1149 errorArgument("Error parsing guest statistics interval '%s'", a->argv[2]);
1150 rc = E_FAIL;
1151 break;
1152 }
1153
1154 /* guest is running; update IGuest */
1155 ComPtr <IGuest> guest;
1156
1157 rc = console->COMGETTER(Guest)(guest.asOutParam());
1158 if (SUCCEEDED(rc))
1159 CHECK_ERROR(guest, COMSETTER(StatisticsUpdateInterval)(uVal));
1160 }
1161 else
1162 {
1163 errorSyntax(USAGE_CONTROLVM, "Invalid parameter '%s'", Utf8Str(a->argv[1]).raw());
1164 rc = E_FAIL;
1165 }
1166 }
1167 while (0);
1168
1169 a->session->Close();
1170
1171 return SUCCEEDED (rc) ? 0 : 1;
1172}
1173
1174static int handleDiscardState(HandlerArg *a)
1175{
1176 HRESULT rc;
1177
1178 if (a->argc != 1)
1179 return errorSyntax(USAGE_DISCARDSTATE, "Incorrect number of parameters");
1180
1181 ComPtr<IMachine> machine;
1182 /* assume it's a UUID */
1183 rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
1184 if (FAILED(rc) || !machine)
1185 {
1186 /* must be a name */
1187 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
1188 }
1189 if (machine)
1190 {
1191 do
1192 {
1193 /* we have to open a session for this task */
1194 Bstr guid;
1195 machine->COMGETTER(Id)(guid.asOutParam());
1196 CHECK_ERROR_BREAK(a->virtualBox, OpenSession(a->session, guid));
1197 do
1198 {
1199 ComPtr<IConsole> console;
1200 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
1201 CHECK_ERROR_BREAK(console, ForgetSavedState(true));
1202 }
1203 while (0);
1204 CHECK_ERROR_BREAK(a->session, Close());
1205 }
1206 while (0);
1207 }
1208
1209 return SUCCEEDED(rc) ? 0 : 1;
1210}
1211
1212static int handleAdoptdState(HandlerArg *a)
1213{
1214 HRESULT rc;
1215
1216 if (a->argc != 2)
1217 return errorSyntax(USAGE_ADOPTSTATE, "Incorrect number of parameters");
1218
1219 ComPtr<IMachine> machine;
1220 /* assume it's a UUID */
1221 rc = a->virtualBox->GetMachine(Bstr(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 do
1230 {
1231 /* we have to open a session for this task */
1232 Bstr guid;
1233 machine->COMGETTER(Id)(guid.asOutParam());
1234 CHECK_ERROR_BREAK(a->virtualBox, OpenSession(a->session, guid));
1235 do
1236 {
1237 ComPtr<IConsole> console;
1238 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
1239 CHECK_ERROR_BREAK(console, AdoptSavedState (Bstr (a->argv[1])));
1240 }
1241 while (0);
1242 CHECK_ERROR_BREAK(a->session, Close());
1243 }
1244 while (0);
1245 }
1246
1247 return SUCCEEDED(rc) ? 0 : 1;
1248}
1249
1250static int handleGetExtraData(HandlerArg *a)
1251{
1252 HRESULT rc = S_OK;
1253
1254 if (a->argc != 2)
1255 return errorSyntax(USAGE_GETEXTRADATA, "Incorrect number of parameters");
1256
1257 /* global data? */
1258 if (!strcmp(a->argv[0], "global"))
1259 {
1260 /* enumeration? */
1261 if (!strcmp(a->argv[1], "enumerate"))
1262 {
1263 Bstr extraDataKey;
1264
1265 do
1266 {
1267 Bstr nextExtraDataKey;
1268 Bstr nextExtraDataValue;
1269 HRESULT rcEnum = a->virtualBox->GetNextExtraDataKey(extraDataKey, nextExtraDataKey.asOutParam(),
1270 nextExtraDataValue.asOutParam());
1271 extraDataKey = nextExtraDataKey;
1272
1273 if (SUCCEEDED(rcEnum) && !extraDataKey.isEmpty())
1274 RTPrintf("Key: %lS, Value: %lS\n", nextExtraDataKey.raw(), nextExtraDataValue.raw());
1275 } while (!extraDataKey.isEmpty());
1276 }
1277 else
1278 {
1279 Bstr value;
1280 CHECK_ERROR(a->virtualBox, GetExtraData(Bstr(a->argv[1]), value.asOutParam()));
1281 if (!value.isEmpty())
1282 RTPrintf("Value: %lS\n", value.raw());
1283 else
1284 RTPrintf("No value set!\n");
1285 }
1286 }
1287 else
1288 {
1289 ComPtr<IMachine> machine;
1290 /* assume it's a UUID */
1291 rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
1292 if (FAILED(rc) || !machine)
1293 {
1294 /* must be a name */
1295 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
1296 }
1297 if (machine)
1298 {
1299 /* enumeration? */
1300 if (!strcmp(a->argv[1], "enumerate"))
1301 {
1302 Bstr extraDataKey;
1303
1304 do
1305 {
1306 Bstr nextExtraDataKey;
1307 Bstr nextExtraDataValue;
1308 HRESULT rcEnum = machine->GetNextExtraDataKey(extraDataKey, nextExtraDataKey.asOutParam(),
1309 nextExtraDataValue.asOutParam());
1310 extraDataKey = nextExtraDataKey;
1311
1312 if (SUCCEEDED(rcEnum) && !extraDataKey.isEmpty())
1313 {
1314 RTPrintf("Key: %lS, Value: %lS\n", nextExtraDataKey.raw(), nextExtraDataValue.raw());
1315 }
1316 } while (!extraDataKey.isEmpty());
1317 }
1318 else
1319 {
1320 Bstr value;
1321 CHECK_ERROR(machine, GetExtraData(Bstr(a->argv[1]), value.asOutParam()));
1322 if (!value.isEmpty())
1323 RTPrintf("Value: %lS\n", value.raw());
1324 else
1325 RTPrintf("No value set!\n");
1326 }
1327 }
1328 }
1329 return SUCCEEDED(rc) ? 0 : 1;
1330}
1331
1332static int handleSetExtraData(HandlerArg *a)
1333{
1334 HRESULT rc = S_OK;
1335
1336 if (a->argc < 2)
1337 return errorSyntax(USAGE_SETEXTRADATA, "Not enough parameters");
1338
1339 /* global data? */
1340 if (!strcmp(a->argv[0], "global"))
1341 {
1342 if (a->argc < 3)
1343 CHECK_ERROR(a->virtualBox, SetExtraData(Bstr(a->argv[1]), NULL));
1344 else if (a->argc == 3)
1345 CHECK_ERROR(a->virtualBox, SetExtraData(Bstr(a->argv[1]), Bstr(a->argv[2])));
1346 else
1347 return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
1348 }
1349 else
1350 {
1351 ComPtr<IMachine> machine;
1352 /* assume it's a UUID */
1353 rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
1354 if (FAILED(rc) || !machine)
1355 {
1356 /* must be a name */
1357 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
1358 }
1359 if (machine)
1360 {
1361 if (a->argc < 3)
1362 CHECK_ERROR(machine, SetExtraData(Bstr(a->argv[1]), NULL));
1363 else if (a->argc == 3)
1364 CHECK_ERROR(machine, SetExtraData(Bstr(a->argv[1]), Bstr(a->argv[2])));
1365 else
1366 return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
1367 }
1368 }
1369 return SUCCEEDED(rc) ? 0 : 1;
1370}
1371
1372static int handleSetProperty(HandlerArg *a)
1373{
1374 HRESULT rc;
1375
1376 /* there must be two arguments: property name and value */
1377 if (a->argc != 2)
1378 return errorSyntax(USAGE_SETPROPERTY, "Incorrect number of parameters");
1379
1380 ComPtr<ISystemProperties> systemProperties;
1381 a->virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
1382
1383 if (!strcmp(a->argv[0], "hdfolder"))
1384 {
1385 /* reset to default? */
1386 if (!strcmp(a->argv[1], "default"))
1387 CHECK_ERROR(systemProperties, COMSETTER(DefaultHardDiskFolder)(NULL));
1388 else
1389 CHECK_ERROR(systemProperties, COMSETTER(DefaultHardDiskFolder)(Bstr(a->argv[1])));
1390 }
1391 else if (!strcmp(a->argv[0], "machinefolder"))
1392 {
1393 /* reset to default? */
1394 if (!strcmp(a->argv[1], "default"))
1395 CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(NULL));
1396 else
1397 CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(Bstr(a->argv[1])));
1398 }
1399 else if (!strcmp(a->argv[0], "vrdpauthlibrary"))
1400 {
1401 /* reset to default? */
1402 if (!strcmp(a->argv[1], "default"))
1403 CHECK_ERROR(systemProperties, COMSETTER(RemoteDisplayAuthLibrary)(NULL));
1404 else
1405 CHECK_ERROR(systemProperties, COMSETTER(RemoteDisplayAuthLibrary)(Bstr(a->argv[1])));
1406 }
1407 else if (!strcmp(a->argv[0], "websrvauthlibrary"))
1408 {
1409 /* reset to default? */
1410 if (!strcmp(a->argv[1], "default"))
1411 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(NULL));
1412 else
1413 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(Bstr(a->argv[1])));
1414 }
1415 else if (!strcmp(a->argv[0], "loghistorycount"))
1416 {
1417 uint32_t uVal;
1418 int vrc;
1419 vrc = RTStrToUInt32Ex(a->argv[1], NULL, 0, &uVal);
1420 if (vrc != VINF_SUCCESS)
1421 return errorArgument("Error parsing Log history count '%s'", a->argv[1]);
1422 CHECK_ERROR(systemProperties, COMSETTER(LogHistoryCount)(uVal));
1423 }
1424 else
1425 return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", a->argv[0]);
1426
1427 return SUCCEEDED(rc) ? 0 : 1;
1428}
1429
1430static int handleSharedFolder (HandlerArg *a)
1431{
1432 HRESULT rc;
1433
1434 /* we need at least a command and target */
1435 if (a->argc < 2)
1436 return errorSyntax(USAGE_SHAREDFOLDER, "Not enough parameters");
1437
1438 ComPtr<IMachine> machine;
1439 /* assume it's a UUID */
1440 rc = a->virtualBox->GetMachine(Bstr(a->argv[1]), machine.asOutParam());
1441 if (FAILED(rc) || !machine)
1442 {
1443 /* must be a name */
1444 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[1]), machine.asOutParam()));
1445 }
1446 if (!machine)
1447 return 1;
1448 Bstr uuid;
1449 machine->COMGETTER(Id)(uuid.asOutParam());
1450
1451 if (!strcmp(a->argv[0], "add"))
1452 {
1453 /* we need at least four more parameters */
1454 if (a->argc < 5)
1455 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Not enough parameters");
1456
1457 char *name = NULL;
1458 char *hostpath = NULL;
1459 bool fTransient = false;
1460 bool fWritable = true;
1461
1462 for (int i = 2; i < a->argc; i++)
1463 {
1464 if ( !strcmp(a->argv[i], "--name")
1465 || !strcmp(a->argv[i], "-name"))
1466 {
1467 if (a->argc <= i + 1 || !*a->argv[i+1])
1468 return errorArgument("Missing argument to '%s'", a->argv[i]);
1469 i++;
1470 name = a->argv[i];
1471 }
1472 else if ( !strcmp(a->argv[i], "--hostpath")
1473 || !strcmp(a->argv[i], "-hostpath"))
1474 {
1475 if (a->argc <= i + 1 || !*a->argv[i+1])
1476 return errorArgument("Missing argument to '%s'", a->argv[i]);
1477 i++;
1478 hostpath = a->argv[i];
1479 }
1480 else if ( !strcmp(a->argv[i], "--readonly")
1481 || !strcmp(a->argv[i], "-readonly"))
1482 {
1483 fWritable = false;
1484 }
1485 else if ( !strcmp(a->argv[i], "--transient")
1486 || !strcmp(a->argv[i], "-transient"))
1487 {
1488 fTransient = true;
1489 }
1490 else
1491 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Invalid parameter '%s'", Utf8Str(a->argv[i]).raw());
1492 }
1493
1494 if (NULL != strstr(name, " "))
1495 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "No spaces allowed in parameter '-name'!");
1496
1497 /* required arguments */
1498 if (!name || !hostpath)
1499 {
1500 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Parameters --name and --hostpath are required");
1501 }
1502
1503 if (fTransient)
1504 {
1505 ComPtr <IConsole> console;
1506
1507 /* open an existing session for the VM */
1508 CHECK_ERROR_RET(a->virtualBox, OpenExistingSession (a->session, uuid), 1);
1509 /* get the session machine */
1510 CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
1511 /* get the session console */
1512 CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
1513
1514 CHECK_ERROR(console, CreateSharedFolder(Bstr(name), Bstr(hostpath), fWritable));
1515
1516 if (console)
1517 a->session->Close();
1518 }
1519 else
1520 {
1521 /* open a session for the VM */
1522 CHECK_ERROR_RET (a->virtualBox, OpenSession(a->session, uuid), 1);
1523
1524 /* get the mutable session machine */
1525 a->session->COMGETTER(Machine)(machine.asOutParam());
1526
1527 CHECK_ERROR(machine, CreateSharedFolder(Bstr(name), Bstr(hostpath), fWritable));
1528
1529 if (SUCCEEDED(rc))
1530 CHECK_ERROR(machine, SaveSettings());
1531
1532 a->session->Close();
1533 }
1534 }
1535 else if (!strcmp(a->argv[0], "remove"))
1536 {
1537 /* we need at least two more parameters */
1538 if (a->argc < 3)
1539 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Not enough parameters");
1540
1541 char *name = NULL;
1542 bool fTransient = false;
1543
1544 for (int i = 2; i < a->argc; i++)
1545 {
1546 if ( !strcmp(a->argv[i], "--name")
1547 || !strcmp(a->argv[i], "-name"))
1548 {
1549 if (a->argc <= i + 1 || !*a->argv[i+1])
1550 return errorArgument("Missing argument to '%s'", a->argv[i]);
1551 i++;
1552 name = a->argv[i];
1553 }
1554 else if ( !strcmp(a->argv[i], "--transient")
1555 || !strcmp(a->argv[i], "-transient"))
1556 {
1557 fTransient = true;
1558 }
1559 else
1560 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Invalid parameter '%s'", Utf8Str(a->argv[i]).raw());
1561 }
1562
1563 /* required arguments */
1564 if (!name)
1565 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Parameter --name is required");
1566
1567 if (fTransient)
1568 {
1569 ComPtr <IConsole> console;
1570
1571 /* open an existing session for the VM */
1572 CHECK_ERROR_RET(a->virtualBox, OpenExistingSession (a->session, uuid), 1);
1573 /* get the session machine */
1574 CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
1575 /* get the session console */
1576 CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
1577
1578 CHECK_ERROR(console, RemoveSharedFolder(Bstr(name)));
1579
1580 if (console)
1581 a->session->Close();
1582 }
1583 else
1584 {
1585 /* open a session for the VM */
1586 CHECK_ERROR_RET (a->virtualBox, OpenSession(a->session, uuid), 1);
1587
1588 /* get the mutable session machine */
1589 a->session->COMGETTER(Machine)(machine.asOutParam());
1590
1591 CHECK_ERROR(machine, RemoveSharedFolder(Bstr(name)));
1592
1593 /* commit and close the session */
1594 CHECK_ERROR(machine, SaveSettings());
1595 a->session->Close();
1596 }
1597 }
1598 else
1599 return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", Utf8Str(a->argv[0]).raw());
1600
1601 return 0;
1602}
1603
1604static int handleVMStatistics(HandlerArg *a)
1605{
1606 HRESULT rc;
1607
1608 /* at least one option: the UUID or name of the VM */
1609 if (a->argc < 1)
1610 return errorSyntax(USAGE_VM_STATISTICS, "Incorrect number of parameters");
1611
1612 /* try to find the given machine */
1613 ComPtr <IMachine> machine;
1614 Bstr uuid (a->argv[0]);
1615 if (!Guid (a->argv[0]).isEmpty())
1616 CHECK_ERROR(a->virtualBox, GetMachine(uuid, machine.asOutParam()));
1617 else
1618 {
1619 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
1620 if (SUCCEEDED (rc))
1621 machine->COMGETTER(Id)(uuid.asOutParam());
1622 }
1623 if (FAILED(rc))
1624 return 1;
1625
1626 /* parse arguments. */
1627 bool fReset = false;
1628 bool fWithDescriptions = false;
1629 const char *pszPattern = NULL; /* all */
1630 for (int i = 1; i < a->argc; i++)
1631 {
1632 if ( !strcmp(a->argv[i], "--pattern")
1633 || !strcmp(a->argv[i], "-pattern"))
1634 {
1635 if (pszPattern)
1636 return errorSyntax(USAGE_VM_STATISTICS, "Multiple --patterns options is not permitted");
1637 if (i + 1 >= a->argc)
1638 return errorArgument("Missing argument to '%s'", a->argv[i]);
1639 pszPattern = a->argv[++i];
1640 }
1641 else if ( !strcmp(a->argv[i], "--descriptions")
1642 || !strcmp(a->argv[i], "-descriptions"))
1643 fWithDescriptions = true;
1644 /* add: --file <filename> and --formatted */
1645 else if ( !strcmp(a->argv[i], "--reset")
1646 || !strcmp(a->argv[i], "-reset"))
1647 fReset = true;
1648 else
1649 return errorSyntax(USAGE_VM_STATISTICS, "Unknown option '%s'", a->argv[i]);
1650 }
1651 if (fReset && fWithDescriptions)
1652 return errorSyntax(USAGE_VM_STATISTICS, "The --reset and --descriptions options does not mix");
1653
1654
1655 /* open an existing session for the VM. */
1656 CHECK_ERROR(a->virtualBox, OpenExistingSession(a->session, uuid));
1657 if (SUCCEEDED(rc))
1658 {
1659 /* get the session console. */
1660 ComPtr <IConsole> console;
1661 CHECK_ERROR(a->session, COMGETTER(Console)(console.asOutParam()));
1662 if (SUCCEEDED(rc))
1663 {
1664 /* get the machine debugger. */
1665 ComPtr <IMachineDebugger> debugger;
1666 CHECK_ERROR(console, COMGETTER(Debugger)(debugger.asOutParam()));
1667 if (SUCCEEDED(rc))
1668 {
1669 if (fReset)
1670 CHECK_ERROR(debugger, ResetStats(Bstr(pszPattern)));
1671 else
1672 {
1673 Bstr stats;
1674 CHECK_ERROR(debugger, GetStats(Bstr(pszPattern), fWithDescriptions, stats.asOutParam()));
1675 if (SUCCEEDED(rc))
1676 {
1677 /* if (fFormatted)
1678 { big mess }
1679 else
1680 */
1681 RTPrintf("%ls\n", stats.raw());
1682 }
1683 }
1684 }
1685 a->session->Close();
1686 }
1687 }
1688
1689 return SUCCEEDED(rc) ? 0 : 1;
1690}
1691#endif /* !VBOX_ONLY_DOCS */
1692
1693enum ConvertSettings
1694{
1695 ConvertSettings_No = 0,
1696 ConvertSettings_Yes = 1,
1697 ConvertSettings_Backup = 2,
1698 ConvertSettings_Ignore = 3,
1699};
1700
1701#ifndef VBOX_ONLY_DOCS
1702/**
1703 * Checks if any of the settings files were auto-converted and informs the
1704 * user if so.
1705 *
1706 * @return @false if the program should terminate and @true otherwise.
1707 */
1708static bool checkForAutoConvertedSettings (ComPtr<IVirtualBox> virtualBox,
1709 ComPtr<ISession> session,
1710 ConvertSettings fConvertSettings)
1711{
1712 /* return early if nothing to do */
1713 if (fConvertSettings == ConvertSettings_Ignore)
1714 return true;
1715
1716 HRESULT rc;
1717
1718 do
1719 {
1720 Bstr formatVersion;
1721 CHECK_ERROR_BREAK(virtualBox, COMGETTER(SettingsFormatVersion) (formatVersion.asOutParam()));
1722
1723 bool isGlobalConverted = false;
1724 std::list <ComPtr <IMachine> > cvtMachines;
1725 std::list <Utf8Str> fileList;
1726 Bstr version;
1727 Bstr filePath;
1728
1729 com::SafeIfaceArray <IMachine> machines;
1730 CHECK_ERROR_BREAK(virtualBox, COMGETTER(Machines)(ComSafeArrayAsOutParam (machines)));
1731
1732 for (size_t i = 0; i < machines.size(); ++ i)
1733 {
1734 BOOL accessible;
1735 CHECK_ERROR_BREAK(machines[i], COMGETTER(Accessible) (&accessible));
1736 if (!accessible)
1737 continue;
1738
1739 CHECK_ERROR_BREAK(machines[i], COMGETTER(SettingsFileVersion) (version.asOutParam()));
1740
1741 if (version != formatVersion)
1742 {
1743 cvtMachines.push_back (machines [i]);
1744 Bstr filePath;
1745 CHECK_ERROR_BREAK(machines[i], COMGETTER(SettingsFilePath) (filePath.asOutParam()));
1746 fileList.push_back (Utf8StrFmt ("%ls (%ls)", filePath.raw(),
1747 version.raw()));
1748 }
1749 }
1750
1751 if (FAILED(rc))
1752 break;
1753
1754 CHECK_ERROR_BREAK(virtualBox, COMGETTER(SettingsFileVersion) (version.asOutParam()));
1755 if (version != formatVersion)
1756 {
1757 isGlobalConverted = true;
1758 CHECK_ERROR_BREAK(virtualBox, COMGETTER(SettingsFilePath) (filePath.asOutParam()));
1759 fileList.push_back (Utf8StrFmt ("%ls (%ls)", filePath.raw(),
1760 version.raw()));
1761 }
1762
1763 if (fileList.size() > 0)
1764 {
1765 switch (fConvertSettings)
1766 {
1767 case ConvertSettings_No:
1768 {
1769 RTPrintf (
1770"WARNING! The following VirtualBox settings files have been automatically\n"
1771"converted to the new settings file format version '%ls':\n"
1772"\n",
1773 formatVersion.raw());
1774
1775 for (std::list <Utf8Str>::const_iterator f = fileList.begin();
1776 f != fileList.end(); ++ f)
1777 RTPrintf (" %S\n", (*f).raw());
1778 RTPrintf (
1779"\n"
1780"The current command was aborted to prevent overwriting the above settings\n"
1781"files with the results of the auto-conversion without your permission.\n"
1782"Please put one of the following command line switches to the beginning of\n"
1783"the VBoxManage command line and repeat the command:\n"
1784"\n"
1785" --convertSettings - to save all auto-converted files (it will not\n"
1786" be possible to use these settings files with an\n"
1787" older version of VirtualBox in the future);\n"
1788" --convertSettingsBackup - to create backup copies of the settings files in\n"
1789" the old format before saving them in the new format;\n"
1790" --convertSettingsIgnore - to not save the auto-converted settings files.\n"
1791"\n"
1792"Note that if you use --convertSettingsIgnore, the auto-converted settings files\n"
1793"will be implicitly saved in the new format anyway once you change a setting or\n"
1794"start a virtual machine, but NO backup copies will be created in this case.\n");
1795 return false;
1796 }
1797 case ConvertSettings_Yes:
1798 case ConvertSettings_Backup:
1799 {
1800 break;
1801 }
1802 default:
1803 AssertFailedReturn (false);
1804 }
1805
1806 for (std::list <ComPtr <IMachine> >::const_iterator m = cvtMachines.begin();
1807 m != cvtMachines.end(); ++ m)
1808 {
1809 Bstr id;
1810 CHECK_ERROR_BREAK((*m), COMGETTER(Id) (id.asOutParam()));
1811
1812 /* open a session for the VM */
1813 CHECK_ERROR_BREAK (virtualBox, OpenSession (session, id));
1814
1815 ComPtr <IMachine> sm;
1816 CHECK_ERROR_BREAK(session, COMGETTER(Machine) (sm.asOutParam()));
1817
1818 Bstr bakFileName;
1819 if (fConvertSettings == ConvertSettings_Backup)
1820 CHECK_ERROR (sm, SaveSettingsWithBackup (bakFileName.asOutParam()));
1821 else
1822 CHECK_ERROR (sm, SaveSettings());
1823
1824 session->Close();
1825
1826 if (FAILED(rc))
1827 break;
1828 }
1829
1830 if (FAILED(rc))
1831 break;
1832
1833 if (isGlobalConverted)
1834 {
1835 Bstr bakFileName;
1836 if (fConvertSettings == ConvertSettings_Backup)
1837 CHECK_ERROR (virtualBox, SaveSettingsWithBackup (bakFileName.asOutParam()));
1838 else
1839 CHECK_ERROR (virtualBox, SaveSettings());
1840 }
1841
1842 if (FAILED(rc))
1843 break;
1844 }
1845 }
1846 while (0);
1847
1848 return SUCCEEDED (rc);
1849}
1850#endif /* !VBOX_ONLY_DOCS */
1851
1852// main
1853///////////////////////////////////////////////////////////////////////////////
1854
1855int main(int argc, char *argv[])
1856{
1857 /*
1858 * Before we do anything, init the runtime without loading
1859 * the support driver.
1860 */
1861 RTR3Init();
1862
1863 bool fShowLogo = true;
1864 int iCmd = 1;
1865 int iCmdArg;
1866
1867 ConvertSettings fConvertSettings = ConvertSettings_No;
1868
1869 /* global options */
1870 for (int i = 1; i < argc || argc <= iCmd; i++)
1871 {
1872 if ( argc <= iCmd
1873 || !strcmp(argv[i], "help")
1874 || !strcmp(argv[i], "-?")
1875 || !strcmp(argv[i], "-h")
1876 || !strcmp(argv[i], "-help")
1877 || !strcmp(argv[i], "--help"))
1878 {
1879 showLogo();
1880 printUsage(USAGE_ALL);
1881 return 0;
1882 }
1883 else if ( !strcmp(argv[i], "-v")
1884 || !strcmp(argv[i], "-version")
1885 || !strcmp(argv[i], "-Version")
1886 || !strcmp(argv[i], "--version"))
1887 {
1888 /* Print version number, and do nothing else. */
1889 RTPrintf("%sr%d\n", VBOX_VERSION_STRING, VBoxSVNRev ());
1890 return 0;
1891 }
1892 else if ( !strcmp(argv[i], "--dumpopts")
1893 || !strcmp(argv[i], "-dumpopts"))
1894 {
1895 /* Special option to dump really all commands,
1896 * even the ones not understood on this platform. */
1897 printUsage(USAGE_DUMPOPTS);
1898 return 0;
1899 }
1900 else if ( !strcmp(argv[i], "--nologo")
1901 || !strcmp(argv[i], "-nologo")
1902 || !strcmp(argv[i], "-q"))
1903 {
1904 /* suppress the logo */
1905 fShowLogo = false;
1906 iCmd++;
1907 }
1908 else if ( !strcmp(argv[i], "--convertSettings")
1909 || !strcmp(argv[i], "-convertSettings"))
1910 {
1911 fConvertSettings = ConvertSettings_Yes;
1912 iCmd++;
1913 }
1914 else if ( !strcmp(argv[i], "--convertSettingsBackup")
1915 || !strcmp(argv[i], "-convertSettingsBackup"))
1916 {
1917 fConvertSettings = ConvertSettings_Backup;
1918 iCmd++;
1919 }
1920 else if ( !strcmp(argv[i], "--convertSettingsIgnore")
1921 || !strcmp(argv[i], "-convertSettingsIgnore"))
1922 {
1923 fConvertSettings = ConvertSettings_Ignore;
1924 iCmd++;
1925 }
1926 else
1927 {
1928 break;
1929 }
1930 }
1931
1932 iCmdArg = iCmd + 1;
1933
1934 if (fShowLogo)
1935 showLogo();
1936
1937
1938#ifdef VBOX_ONLY_DOCS
1939 int rc = 0;
1940#else /* !VBOX_ONLY_DOCS */
1941 HRESULT rc = 0;
1942
1943 rc = com::Initialize();
1944 if (FAILED(rc))
1945 {
1946 RTPrintf("ERROR: failed to initialize COM!\n");
1947 return rc;
1948 }
1949
1950 /*
1951 * The input is in the host OS'es codepage (NT guarantees ACP).
1952 * For VBox we use UTF-8 and convert to UCS-2 when calling (XP)COM APIs.
1953 * For simplicity, just convert the argv[] array here.
1954 */
1955 for (int i = iCmdArg; i < argc; i++)
1956 {
1957 char *converted;
1958 RTStrCurrentCPToUtf8(&converted, argv[i]);
1959 argv[i] = converted;
1960 }
1961
1962 do
1963 {
1964 // scopes all the stuff till shutdown
1965 ////////////////////////////////////////////////////////////////////////////
1966
1967 /* convertfromraw: does not need a VirtualBox instantiation. */
1968 if (argc >= iCmdArg && ( !strcmp(argv[iCmd], "convertfromraw")
1969 || !strcmp(argv[iCmd], "convertdd")))
1970 {
1971 rc = handleConvertFromRaw(argc - iCmdArg, argv + iCmdArg);
1972 break;
1973 }
1974
1975 ComPtr<IVirtualBox> virtualBox;
1976 ComPtr<ISession> session;
1977
1978 rc = virtualBox.createLocalObject(CLSID_VirtualBox);
1979 if (FAILED(rc))
1980 RTPrintf("ERROR: failed to create the VirtualBox object!\n");
1981 else
1982 {
1983 rc = session.createInprocObject(CLSID_Session);
1984 if (FAILED(rc))
1985 RTPrintf("ERROR: failed to create a session object!\n");
1986 }
1987
1988 if (FAILED(rc))
1989 {
1990 com::ErrorInfo info;
1991 if (!info.isFullAvailable() && !info.isBasicAvailable())
1992 {
1993 com::GluePrintRCMessage(rc);
1994 RTPrintf("Most likely, the VirtualBox COM server is not running or failed to start.\n");
1995 }
1996 else
1997 com::GluePrintErrorInfo(info);
1998 break;
1999 }
2000
2001 /* create the event queue
2002 * (here it is necessary only to process remaining XPCOM/IPC events
2003 * after the session is closed) */
2004
2005#ifdef USE_XPCOM_QUEUE
2006 nsCOMPtr<nsIEventQueue> eventQ;
2007 NS_GetMainEventQ(getter_AddRefs(eventQ));
2008#endif
2009
2010 if (!checkForAutoConvertedSettings (virtualBox, session, fConvertSettings))
2011 break;
2012
2013#ifdef USE_XPCOM_QUEUE
2014 HandlerArg handlerArg = { 0, NULL, eventQ, virtualBox, session };
2015#else
2016 HandlerArg handlerArg = { 0, NULL, virtualBox, session };
2017#endif
2018
2019 /*
2020 * All registered command handlers
2021 */
2022 struct
2023 {
2024 const char *command;
2025 PFNHANDLER handler;
2026 } commandHandlers[] =
2027 {
2028 { "internalcommands", handleInternalCommands },
2029 { "list", handleList },
2030 { "showvminfo", handleShowVMInfo },
2031 { "registervm", handleRegisterVM },
2032 { "unregistervm", handleUnregisterVM },
2033 { "createhd", handleCreateHardDisk },
2034 { "createvdi", handleCreateHardDisk }, /* backward compatiblity */
2035 { "modifyhd", handleModifyHardDisk },
2036 { "modifyvdi", handleModifyHardDisk }, /* backward compatiblity */
2037 { "clonehd", handleCloneHardDisk },
2038 { "clonevdi", handleCloneHardDisk }, /* backward compatiblity */
2039 { "addiscsidisk", handleAddiSCSIDisk },
2040 { "createvm", handleCreateVM },
2041 { "modifyvm", handleModifyVM },
2042 { "startvm", handleStartVM },
2043 { "controlvm", handleControlVM },
2044 { "discardstate", handleDiscardState },
2045 { "adoptstate", handleAdoptdState },
2046 { "snapshot", handleSnapshot },
2047 { "openmedium", handleOpenMedium },
2048 { "registerimage", handleOpenMedium }, /* backward compatiblity */
2049 { "closemedium", handleCloseMedium },
2050 { "unregisterimage", handleCloseMedium }, /* backward compatiblity */
2051 { "showhdinfo", handleShowHardDiskInfo },
2052 { "showvdiinfo", handleShowHardDiskInfo }, /* backward compatiblity */
2053 { "getextradata", handleGetExtraData },
2054 { "setextradata", handleSetExtraData },
2055 { "setproperty", handleSetProperty },
2056 { "usbfilter", handleUSBFilter },
2057 { "sharedfolder", handleSharedFolder },
2058 { "vmstatistics", handleVMStatistics },
2059#ifdef VBOX_WITH_GUEST_PROPS
2060 { "guestproperty", handleGuestProperty },
2061#endif /* VBOX_WITH_GUEST_PROPS defined */
2062 { "metrics", handleMetrics },
2063 { "import", handleImportAppliance },
2064 { "export", handleExportAppliance },
2065#if defined(VBOX_WITH_NETFLT)
2066 { "hostonlyif", handleHostonlyIf },
2067#endif
2068 { "dhcpserver", handleDHCPServer},
2069 { NULL, NULL }
2070 };
2071
2072 int commandIndex;
2073 for (commandIndex = 0; commandHandlers[commandIndex].command != NULL; commandIndex++)
2074 {
2075 if (!strcmp(commandHandlers[commandIndex].command, argv[iCmd]))
2076 {
2077 handlerArg.argc = argc - iCmdArg;
2078 handlerArg.argv = &argv[iCmdArg];
2079
2080 rc = commandHandlers[commandIndex].handler(&handlerArg);
2081 break;
2082 }
2083 }
2084 if (!commandHandlers[commandIndex].command)
2085 {
2086 rc = errorSyntax(USAGE_ALL, "Invalid command '%s'", Utf8Str(argv[iCmd]).raw());
2087 }
2088
2089 /* Although all handlers should always close the session if they open it,
2090 * we do it here just in case if some of the handlers contains a bug --
2091 * leaving the direct session not closed will turn the machine state to
2092 * Aborted which may have unwanted side effects like killing the saved
2093 * state file (if the machine was in the Saved state before). */
2094 session->Close();
2095
2096#ifdef USE_XPCOM_QUEUE
2097 eventQ->ProcessPendingEvents();
2098#endif
2099
2100 // end "all-stuff" scope
2101 ////////////////////////////////////////////////////////////////////////////
2102 }
2103 while (0);
2104
2105 com::Shutdown();
2106#endif /* !VBOX_ONLY_DOCS */
2107
2108 /*
2109 * Free converted argument vector
2110 */
2111 for (int i = iCmdArg; i < argc; i++)
2112 RTStrFree(argv[i]);
2113
2114 return rc != 0;
2115}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette