VirtualBox

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

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

NetworkAttachment: Allow changing the attachment between NONE/NAT/HIF/host-only/.. dynamically #3573

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