VirtualBox

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

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

API/others: Renamed IConsole::discardSavedState to IConsole::forgetSavedState, added parameter. Deleted old IConsole::powerDown, renamed IConsole::powerDownAsync to IConsole::powerDown (as promised for 2.1). Implemented perl sample code for registering a hard disk. Cleaned up constant formatting in the API docs. Updated SDK changelog. Renamed com/errorprint2.h to com/errorprint.h, added a few assertion variants. Eliminated com/errorprint_legacy.h. Adjusted all files using the affected headers and APIs. Renamed tstHeadless2 to tstHeadless.

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