VirtualBox

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

Last change on this file since 17884 was 17882, checked in by vboxsync, 16 years ago

VBoxManage: dhcp cfg basics, neither list nor help yet

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

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