VirtualBox

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

Last change on this file since 18709 was 18516, checked in by vboxsync, 16 years ago

VBoxManage: uninitialized variable

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