VirtualBox

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

Last change on this file since 17320 was 17255, checked in by vboxsync, 16 years ago

#3551: “Main: Replace remaining collections with safe arrays”
Replaced HostFloppyDriveCollection; tested by lelik with (GASP!) real floppy hardware.

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