VirtualBox

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

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

API/Machine,Session: add a force mount parameter to MountMedium and the associated other places

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