VirtualBox

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

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

VBoxManage: A little clean up in progress.

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

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