VirtualBox

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

Last change on this file since 22145 was 21769, checked in by vboxsync, 15 years ago

Network: fixed the hostonly adaptor bringingup as mentioned in 3573#c25

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