VirtualBox

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

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

VBoxManage: split snapshot into separate file

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 99.7 KB
Line 
1/* $Id: VBoxManage.cpp 17102 2009-02-24 22:42:29Z 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/* missing XPCOM <-> COM wrappers */
65#ifndef STDMETHOD_
66# define STDMETHOD_(ret, meth) NS_IMETHOD_(ret) meth
67#endif
68#ifndef NS_GET_IID
69# define NS_GET_IID(I) IID_##I
70#endif
71#ifndef RT_OS_WINDOWS
72#define IUnknown nsISupports
73#endif
74
75/** command handler type */
76typedef int (*PFNHANDLER)(HandlerArg *a);
77
78/**
79 * Quick IUSBDevice implementation for detaching / attaching
80 * devices to the USB Controller.
81 */
82class MyUSBDevice : public IUSBDevice
83{
84public:
85 // public initializer/uninitializer for internal purposes only
86 MyUSBDevice(uint16_t a_u16VendorId, uint16_t a_u16ProductId, uint16_t a_bcdRevision, uint64_t a_u64SerialHash, const char *a_pszComment)
87 : m_usVendorId(a_u16VendorId), m_usProductId(a_u16ProductId),
88 m_bcdRevision(a_bcdRevision), m_u64SerialHash(a_u64SerialHash),
89 m_bstrComment(a_pszComment),
90 m_cRefs(0)
91 {
92 }
93
94 STDMETHOD_(ULONG, AddRef)(void)
95 {
96 return ASMAtomicIncU32(&m_cRefs);
97 }
98 STDMETHOD_(ULONG, Release)(void)
99 {
100 ULONG cRefs = ASMAtomicDecU32(&m_cRefs);
101 if (!cRefs)
102 delete this;
103 return cRefs;
104 }
105 STDMETHOD(QueryInterface)(const IID &iid, void **ppvObject)
106 {
107 Guid guid(iid);
108 if (guid == Guid(NS_GET_IID(IUnknown)))
109 *ppvObject = (IUnknown *)this;
110 else if (guid == Guid(NS_GET_IID(IUSBDevice)))
111 *ppvObject = (IUSBDevice *)this;
112 else
113 return E_NOINTERFACE;
114 AddRef();
115 return S_OK;
116 }
117
118 STDMETHOD(COMGETTER(Id))(OUT_GUID a_pId) { return E_NOTIMPL; }
119 STDMETHOD(COMGETTER(VendorId))(USHORT *a_pusVendorId) { *a_pusVendorId = m_usVendorId; return S_OK; }
120 STDMETHOD(COMGETTER(ProductId))(USHORT *a_pusProductId) { *a_pusProductId = m_usProductId; return S_OK; }
121 STDMETHOD(COMGETTER(Revision))(USHORT *a_pusRevision) { *a_pusRevision = m_bcdRevision; return S_OK; }
122 STDMETHOD(COMGETTER(SerialHash))(ULONG64 *a_pullSerialHash) { *a_pullSerialHash = m_u64SerialHash; return S_OK; }
123 STDMETHOD(COMGETTER(Manufacturer))(BSTR *a_pManufacturer) { return E_NOTIMPL; }
124 STDMETHOD(COMGETTER(Product))(BSTR *a_pProduct) { return E_NOTIMPL; }
125 STDMETHOD(COMGETTER(SerialNumber))(BSTR *a_pSerialNumber) { return E_NOTIMPL; }
126 STDMETHOD(COMGETTER(Address))(BSTR *a_pAddress) { return E_NOTIMPL; }
127
128private:
129 /** The vendor id of this USB device. */
130 USHORT m_usVendorId;
131 /** The product id of this USB device. */
132 USHORT m_usProductId;
133 /** The product revision number of this USB device.
134 * (high byte = integer; low byte = decimal) */
135 USHORT m_bcdRevision;
136 /** The USB serial hash of the device. */
137 uint64_t m_u64SerialHash;
138 /** The user comment string. */
139 Bstr m_bstrComment;
140 /** Reference counter. */
141 uint32_t volatile m_cRefs;
142};
143
144
145// types
146///////////////////////////////////////////////////////////////////////////////
147
148template <typename T>
149class Nullable
150{
151public:
152
153 Nullable() : mIsNull (true) {}
154 Nullable (const T &aValue, bool aIsNull = false)
155 : mIsNull (aIsNull), mValue (aValue) {}
156
157 bool isNull() const { return mIsNull; };
158 void setNull (bool aIsNull = true) { mIsNull = aIsNull; }
159
160 operator const T&() const { return mValue; }
161
162 Nullable &operator= (const T &aValue)
163 {
164 mValue = aValue;
165 mIsNull = false;
166 return *this;
167 }
168
169private:
170
171 bool mIsNull;
172 T mValue;
173};
174
175/** helper structure to encapsulate USB filter manipulation commands */
176struct USBFilterCmd
177{
178 struct USBFilter
179 {
180 USBFilter ()
181 : mAction (USBDeviceFilterAction_Null)
182 {}
183
184 Bstr mName;
185 Nullable <bool> mActive;
186 Bstr mVendorId;
187 Bstr mProductId;
188 Bstr mRevision;
189 Bstr mManufacturer;
190 Bstr mProduct;
191 Bstr mRemote;
192 Bstr mSerialNumber;
193 Nullable <ULONG> mMaskedInterfaces;
194 USBDeviceFilterAction_T mAction;
195 };
196
197 enum Action { Invalid, Add, Modify, Remove };
198
199 USBFilterCmd() : mAction (Invalid), mIndex (0), mGlobal (false) {}
200
201 Action mAction;
202 uint32_t mIndex;
203 /** flag whether the command target is a global filter */
204 bool mGlobal;
205 /** machine this command is targeted at (null for global filters) */
206 ComPtr<IMachine> mMachine;
207 USBFilter mFilter;
208};
209#endif /* !VBOX_ONLY_DOCS */
210
211// funcs
212///////////////////////////////////////////////////////////////////////////////
213
214static void showLogo(void)
215{
216 static bool fShown; /* show only once */
217
218 if (!fShown)
219 {
220 RTPrintf("VirtualBox Command Line Management Interface Version "
221 VBOX_VERSION_STRING "\n"
222 "(C) 2005-2009 Sun Microsystems, Inc.\n"
223 "All rights reserved.\n"
224 "\n");
225 fShown = true;
226 }
227}
228
229static void printUsage(USAGECATEGORY u64Cmd)
230{
231#ifdef RT_OS_LINUX
232 bool fLinux = true;
233#else
234 bool fLinux = false;
235#endif
236#ifdef RT_OS_WINDOWS
237 bool fWin = true;
238#else
239 bool fWin = false;
240#endif
241#ifdef RT_OS_SOLARIS
242 bool fSolaris = true;
243#else
244 bool fSolaris = false;
245#endif
246#ifdef RT_OS_DARWIN
247 bool fDarwin = true;
248#else
249 bool fDarwin = false;
250#endif
251#ifdef VBOX_WITH_VRDP
252 bool fVRDP = true;
253#else
254 bool fVRDP = false;
255#endif
256
257 if (u64Cmd == USAGE_DUMPOPTS)
258 {
259 fLinux = true;
260 fWin = true;
261 fSolaris = true;
262 fDarwin = true;
263 fVRDP = true;
264 u64Cmd = USAGE_ALL;
265 }
266
267 RTPrintf("Usage:\n"
268 "\n");
269
270 if (u64Cmd == USAGE_ALL)
271 {
272 RTPrintf("VBoxManage [-v|-version] print version number and exit\n"
273 "VBoxManage -nologo ... suppress the logo\n"
274 "\n");
275 }
276
277 if (u64Cmd & USAGE_LIST)
278 {
279 RTPrintf("VBoxManage list [--long|-l] vms|runningvms|ostypes|hostdvds|hostfloppies|\n"
280 " hostifs|hostinfo|hddbackends|hdds|dvds|floppies|\n"
281 " usbhost|usbfilters|systemproperties\n"
282 "\n");
283 }
284
285 if (u64Cmd & USAGE_SHOWVMINFO)
286 {
287 RTPrintf("VBoxManage showvminfo <uuid>|<name> [-details] [-statistics]\n"
288 " [-machinereadable]\n"
289 "\n");
290 }
291
292 if (u64Cmd & USAGE_REGISTERVM)
293 {
294 RTPrintf("VBoxManage registervm <filename>\n"
295 "\n");
296 }
297
298 if (u64Cmd & USAGE_UNREGISTERVM)
299 {
300 RTPrintf("VBoxManage unregistervm <uuid>|<name> [-delete]\n"
301 "\n");
302 }
303
304 if (u64Cmd & USAGE_CREATEVM)
305 {
306 RTPrintf("VBoxManage createvm -name <name>\n"
307 " [-ostype <ostype>]\n"
308 " [-register]\n"
309 " [-basefolder <path> | -settingsfile <path>]\n"
310 " [-uuid <uuid>]\n"
311 "\n");
312 }
313
314 if (u64Cmd & USAGE_IMPORTAPPLIANCE)
315 {
316 RTPrintf("VBoxManage import <ovf>\n"
317 "\n"); // @todo
318 }
319
320 if (u64Cmd & USAGE_EXPORTAPPLIANCE)
321 {
322 RTPrintf("VBoxManage export <machines> [--output|-o] <ovf>\n"
323 "\n");
324 }
325
326 if (u64Cmd & USAGE_MODIFYVM)
327 {
328 RTPrintf("VBoxManage modifyvm <uuid|name>\n"
329 " [-name <name>]\n"
330 " [-ostype <ostype>]\n"
331 " [-memory <memorysize in MB>]\n"
332 " [-vram <vramsize in MB>]\n"
333 " [-acpi on|off]\n"
334 " [-ioapic on|off]\n"
335 " [-pae on|off]\n"
336 " [-hwvirtex on|off|default]\n"
337 " [-nestedpaging on|off]\n"
338 " [-vtxvpid on|off]\n"
339 " [-monitorcount <number>]\n"
340 " [-accelerate3d <on|off>]\n"
341 " [-bioslogofadein on|off]\n"
342 " [-bioslogofadeout on|off]\n"
343 " [-bioslogodisplaytime <msec>]\n"
344 " [-bioslogoimagepath <imagepath>]\n"
345 " [-biosbootmenu disabled|menuonly|messageandmenu]\n"
346 " [-biossystemtimeoffset <msec>]\n"
347 " [-biospxedebug on|off]\n"
348 " [-boot<1-4> none|floppy|dvd|disk|net>]\n"
349 " [-hd<a|b|d> none|<uuid>|<filename>]\n"
350 " [-idecontroller PIIX3|PIIX4]\n"
351#ifdef VBOX_WITH_AHCI
352 " [-sata on|off]\n"
353 " [-sataportcount <1-30>]\n"
354 " [-sataport<1-30> none|<uuid>|<filename>]\n"
355 " [-sataideemulation<1-4> <1-30>]\n"
356#endif
357 " [-dvd none|<uuid>|<filename>|host:<drive>]\n"
358 " [-dvdpassthrough on|off]\n"
359 " [-floppy disabled|empty|<uuid>|\n"
360 " <filename>|host:<drive>]\n"
361#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN)
362 " [-nic<1-N> none|null|nat|hostif|intnet|hostonly]\n"
363#else /* !RT_OS_LINUX && !RT_OS_DARWIN */
364 " [-nic<1-N> none|null|nat|hostif|intnet]\n"
365#endif /* !RT_OS_LINUX && !RT_OS_DARWIN */
366 " [-nictype<1-N> Am79C970A|Am79C973"
367#ifdef VBOX_WITH_E1000
368 "|82540EM|82543GC"
369#endif
370 "]\n"
371 " [-cableconnected<1-N> on|off]\n"
372 " [-nictrace<1-N> on|off]\n"
373 " [-nictracefile<1-N> <filename>]\n"
374 " [-nicspeed<1-N> <kbps>]\n"
375 " [-hostifdev<1-N> none|<devicename>]\n"
376 " [-intnet<1-N> <network name>]\n"
377 " [-natnet<1-N> <network>|default]\n"
378 " [-macaddress<1-N> auto|<mac>]\n"
379 " [-uart<1-N> off|<I/O base> <IRQ>]\n"
380 " [-uartmode<1-N> disconnected|\n"
381 " server <pipe>|\n"
382 " client <pipe>|\n"
383 " <devicename>]\n"
384#ifdef VBOX_WITH_MEM_BALLOONING
385 " [-guestmemoryballoon <balloonsize in MB>]\n"
386#endif
387 " [-gueststatisticsinterval <seconds>]\n"
388 );
389 RTPrintf(" [-audio none|null");
390 if (fWin)
391 {
392#ifdef VBOX_WITH_WINMM
393 RTPrintf( "|winmm|dsound");
394#else
395 RTPrintf( "|dsound");
396#endif
397 }
398 if (fSolaris)
399 {
400 RTPrintf( "|solaudio");
401 }
402 if (fLinux)
403 {
404 RTPrintf( "|oss"
405#ifdef VBOX_WITH_ALSA
406 "|alsa"
407#endif
408#ifdef VBOX_WITH_PULSE
409 "|pulse"
410#endif
411 );
412 }
413 if (fDarwin)
414 {
415 RTPrintf( "|coreaudio");
416 }
417 RTPrintf( "]\n");
418 RTPrintf(" [-audiocontroller ac97|sb16]\n"
419 " [-clipboard disabled|hosttoguest|guesttohost|\n"
420 " bidirectional]\n");
421 if (fVRDP)
422 {
423 RTPrintf(" [-vrdp on|off]\n"
424 " [-vrdpport default|<port>]\n"
425 " [-vrdpaddress <host>]\n"
426 " [-vrdpauthtype null|external|guest]\n"
427 " [-vrdpmulticon on|off]\n"
428 " [-vrdpreusecon on|off]\n");
429 }
430 RTPrintf(" [-usb on|off]\n"
431 " [-usbehci on|off]\n"
432 " [-snapshotfolder default|<path>]\n");
433 RTPrintf("\n");
434 }
435
436 if (u64Cmd & USAGE_STARTVM)
437 {
438 RTPrintf("VBoxManage startvm <uuid>|<name>\n");
439 if (fVRDP)
440 RTPrintf(" [-type gui|vrdp]\n");
441 RTPrintf("\n");
442 }
443
444 if (u64Cmd & USAGE_CONTROLVM)
445 {
446 RTPrintf("VBoxManage controlvm <uuid>|<name>\n"
447 " pause|resume|reset|poweroff|savestate|\n"
448 " acpipowerbutton|acpisleepbutton|\n"
449 " keyboardputscancode <hex> [<hex> ...]|\n"
450 " injectnmi|\n"
451 " setlinkstate<1-4> on|off |\n"
452 " usbattach <uuid>|<address> |\n"
453 " usbdetach <uuid>|<address> |\n"
454 " dvdattach none|<uuid>|<filename>|host:<drive> |\n"
455 " floppyattach none|<uuid>|<filename>|host:<drive> |\n");
456 if (fVRDP)
457 {
458 RTPrintf(" vrdp on|off] |\n");
459 }
460 RTPrintf(" setvideomodehint <xres> <yres> <bpp> [display]|\n"
461 " setcredentials <username> <password> <domain>\n"
462 " [-allowlocallogon <yes|no>]\n"
463 "\n");
464 }
465
466 if (u64Cmd & USAGE_DISCARDSTATE)
467 {
468 RTPrintf("VBoxManage discardstate <uuid>|<name>\n"
469 "\n");
470 }
471
472 if (u64Cmd & USAGE_ADOPTSTATE)
473 {
474 RTPrintf("VBoxManage adoptstate <uuid>|<name> <state_file>\n"
475 "\n");
476 }
477
478 if (u64Cmd & USAGE_SNAPSHOT)
479 {
480 RTPrintf("VBoxManage snapshot <uuid>|<name>\n"
481 " take <name> [-desc <desc>] |\n"
482 " discard <uuid>|<name> |\n"
483 " discardcurrent -state|-all |\n"
484 " edit <uuid>|<name>|-current\n"
485 " [-newname <name>]\n"
486 " [-newdesc <desc>] |\n"
487 " showvminfo <uuid>|<name>\n"
488 "\n");
489 }
490
491 if (u64Cmd & USAGE_REGISTERIMAGE)
492 {
493 RTPrintf("VBoxManage openmedium disk|dvd|floppy <filename>\n"
494 " [-type normal|immutable|writethrough] (disk only)\n"
495 "\n");
496 }
497
498 if (u64Cmd & USAGE_UNREGISTERIMAGE)
499 {
500 RTPrintf("VBoxManage closemedium disk|dvd|floppy <uuid>|<filename>\n"
501 "\n");
502 }
503
504 if (u64Cmd & USAGE_SHOWHDINFO)
505 {
506 RTPrintf("VBoxManage showhdinfo <uuid>|<filename>\n"
507 "\n");
508 }
509
510 if (u64Cmd & USAGE_CREATEHD)
511 {
512 /// @todo NEWMEDIA add -format to specify the hard disk backend
513 RTPrintf("VBoxManage createhd -filename <filename>\n"
514 " -size <megabytes>\n"
515 " [-format VDI|VMDK|VHD]\n"
516 " [-static]\n"
517 " [-comment <comment>]\n"
518 " [-register]\n"
519 " [-type normal|writethrough] (default: normal)\n"
520 "\n");
521 }
522
523 if (u64Cmd & USAGE_MODIFYHD)
524 {
525 RTPrintf("VBoxManage modifyhd <uuid>|<filename>\n"
526 " settype normal|writethrough|immutable |\n"
527 " compact\n"
528 "\n");
529 }
530
531 if (u64Cmd & USAGE_CLONEHD)
532 {
533 RTPrintf("VBoxManage clonehd <uuid>|<filename> <outputfile>\n"
534 " [-format VDI|VMDK|VHD|RAW|<other>]\n"
535 " [-remember]\n"
536 "\n");
537 }
538
539 if (u64Cmd & USAGE_CONVERTFROMRAW)
540 {
541 RTPrintf("VBoxManage convertfromraw [-static] [-format VDI|VMDK|VHD]\n"
542 " <filename> <outputfile>\n"
543 "VBoxManage convertfromraw [-static] [-format VDI|VMDK|VHD]\n"
544 " stdin <outputfile> <bytes>\n"
545 "\n");
546 }
547
548 if (u64Cmd & USAGE_ADDISCSIDISK)
549 {
550 RTPrintf("VBoxManage addiscsidisk -server <name>|<ip>\n"
551 " -target <target>\n"
552 " [-port <port>]\n"
553 " [-lun <lun>]\n"
554 " [-encodedlun <lun>]\n"
555 " [-username <username>]\n"
556 " [-password <password>]\n"
557 " [-comment <comment>]\n"
558 " [-intnet]\n"
559 "\n");
560 }
561
562 if (u64Cmd & USAGE_GETEXTRADATA)
563 {
564 RTPrintf("VBoxManage getextradata global|<uuid>|<name>\n"
565 " <key>|enumerate\n"
566 "\n");
567 }
568
569 if (u64Cmd & USAGE_SETEXTRADATA)
570 {
571 RTPrintf("VBoxManage setextradata global|<uuid>|<name>\n"
572 " <key>\n"
573 " [<value>] (no value deletes key)\n"
574 "\n");
575 }
576
577 if (u64Cmd & USAGE_SETPROPERTY)
578 {
579 RTPrintf("VBoxManage setproperty hdfolder default|<folder> |\n"
580 " machinefolder default|<folder> |\n"
581 " vrdpauthlibrary default|<library> |\n"
582 " websrvauthlibrary default|null|<library> |\n"
583 " hwvirtexenabled yes|no\n"
584 " loghistorycount <value>\n"
585 "\n");
586 }
587
588 if (u64Cmd & USAGE_USBFILTER_ADD)
589 {
590 RTPrintf("VBoxManage usbfilter add <index,0-N>\n"
591 " -target <uuid>|<name>|global\n"
592 " -name <string>\n"
593 " -action ignore|hold (global filters only)\n"
594 " [-active yes|no] (yes)\n"
595 " [-vendorid <XXXX>] (null)\n"
596 " [-productid <XXXX>] (null)\n"
597 " [-revision <IIFF>] (null)\n"
598 " [-manufacturer <string>] (null)\n"
599 " [-product <string>] (null)\n"
600 " [-remote yes|no] (null, VM filters only)\n"
601 " [-serialnumber <string>] (null)\n"
602 " [-maskedinterfaces <XXXXXXXX>]\n"
603 "\n");
604 }
605
606 if (u64Cmd & USAGE_USBFILTER_MODIFY)
607 {
608 RTPrintf("VBoxManage usbfilter modify <index,0-N>\n"
609 " -target <uuid>|<name>|global\n"
610 " [-name <string>]\n"
611 " [-action ignore|hold] (global filters only)\n"
612 " [-active yes|no]\n"
613 " [-vendorid <XXXX>|\"\"]\n"
614 " [-productid <XXXX>|\"\"]\n"
615 " [-revision <IIFF>|\"\"]\n"
616 " [-manufacturer <string>|\"\"]\n"
617 " [-product <string>|\"\"]\n"
618 " [-remote yes|no] (null, VM filters only)\n"
619 " [-serialnumber <string>|\"\"]\n"
620 " [-maskedinterfaces <XXXXXXXX>]\n"
621 "\n");
622 }
623
624 if (u64Cmd & USAGE_USBFILTER_REMOVE)
625 {
626 RTPrintf("VBoxManage usbfilter remove <index,0-N>\n"
627 " -target <uuid>|<name>|global\n"
628 "\n");
629 }
630
631 if (u64Cmd & USAGE_SHAREDFOLDER_ADD)
632 {
633 RTPrintf("VBoxManage sharedfolder add <vmname>|<uuid>\n"
634 " -name <name> -hostpath <hostpath>\n"
635 " [-transient] [-readonly]\n"
636 "\n");
637 }
638
639 if (u64Cmd & USAGE_SHAREDFOLDER_REMOVE)
640 {
641 RTPrintf("VBoxManage sharedfolder remove <vmname>|<uuid>\n"
642 " -name <name> [-transient]\n"
643 "\n");
644 }
645
646 if (u64Cmd & USAGE_VM_STATISTICS)
647 {
648 RTPrintf("VBoxManage vmstatistics <vmname>|<uuid> [-reset]\n"
649 " [-pattern <pattern>] [-descriptions]\n"
650 "\n");
651 }
652
653#ifdef VBOX_WITH_GUEST_PROPS
654 if (u64Cmd & USAGE_GUESTPROPERTY)
655 usageGuestProperty();
656#endif /* VBOX_WITH_GUEST_PROPS defined */
657
658 if (u64Cmd & USAGE_METRICS)
659 {
660 RTPrintf("VBoxManage metrics list [*|host|<vmname> [<metric_list>]] (comma-separated)\n\n"
661 "VBoxManage metrics setup\n"
662 " [-period <seconds>]\n"
663 " [-samples <count>]\n"
664 " [-list]\n"
665 " [*|host|<vmname> [<metric_list>]]\n\n"
666 "VBoxManage metrics query [*|host|<vmname> [<metric_list>]]\n\n"
667 "VBoxManage metrics collect\n"
668 " [-period <seconds>]\n"
669 " [-samples <count>]\n"
670 " [-list]\n"
671 " [-detach]\n"
672 " [*|host|<vmname> [<metric_list>]]\n"
673 "\n");
674 }
675
676}
677
678/**
679 * Print a usage synopsis and the syntax error message.
680 */
681int errorSyntax(USAGECATEGORY u64Cmd, const char *pszFormat, ...)
682{
683 va_list args;
684 showLogo(); // show logo even if suppressed
685#ifndef VBOX_ONLY_DOCS
686 if (g_fInternalMode)
687 printUsageInternal(u64Cmd);
688 else
689 printUsage(u64Cmd);
690#endif /* !VBOX_ONLY_DOCS */
691 va_start(args, pszFormat);
692 RTPrintf("\n"
693 "Syntax error: %N\n", pszFormat, &args);
694 va_end(args);
695 return 1;
696}
697
698/**
699 * Print an error message without the syntax stuff.
700 */
701int errorArgument(const char *pszFormat, ...)
702{
703 va_list args;
704 va_start(args, pszFormat);
705 RTPrintf("error: %N\n", pszFormat, &args);
706 va_end(args);
707 return 1;
708}
709
710#ifndef VBOX_ONLY_DOCS
711/**
712 * Print out progress on the console
713 */
714void showProgress(ComPtr<IProgress> progress)
715{
716 BOOL fCompleted;
717 LONG currentPercent;
718 LONG lastPercent = 0;
719
720 RTPrintf("0%%...");
721 RTStrmFlush(g_pStdOut);
722 while (SUCCEEDED(progress->COMGETTER(Completed(&fCompleted))))
723 {
724 progress->COMGETTER(Percent(&currentPercent));
725
726 /* did we cross a 10% mark? */
727 if (((currentPercent / 10) > (lastPercent / 10)))
728 {
729 /* make sure to also print out missed steps */
730 for (LONG curVal = (lastPercent / 10) * 10 + 10; curVal <= (currentPercent / 10) * 10; curVal += 10)
731 {
732 if (curVal < 100)
733 {
734 RTPrintf("%ld%%...", curVal);
735 RTStrmFlush(g_pStdOut);
736 }
737 }
738 lastPercent = (currentPercent / 10) * 10;
739 }
740 if (fCompleted)
741 break;
742
743 /* make sure the loop is not too tight */
744 progress->WaitForCompletion(100);
745 }
746
747 /* complete the line. */
748 HRESULT rc;
749 if (SUCCEEDED(progress->COMGETTER(ResultCode)(&rc)))
750 {
751 if (SUCCEEDED(rc))
752 RTPrintf("100%%\n");
753 else
754 RTPrintf("FAILED\n");
755 }
756 else
757 RTPrintf("\n");
758 RTStrmFlush(g_pStdOut);
759}
760
761static int handleRegisterVM(HandlerArg *a)
762{
763 HRESULT rc;
764
765 if (a->argc != 1)
766 return errorSyntax(USAGE_REGISTERVM, "Incorrect number of parameters");
767
768 ComPtr<IMachine> machine;
769 CHECK_ERROR(a->virtualBox, OpenMachine(Bstr(a->argv[0]), machine.asOutParam()));
770 if (SUCCEEDED(rc))
771 {
772 ASSERT(machine);
773 CHECK_ERROR(a->virtualBox, RegisterMachine(machine));
774 }
775 return SUCCEEDED(rc) ? 0 : 1;
776}
777
778static int handleUnregisterVM(HandlerArg *a)
779{
780 HRESULT rc;
781
782 if ((a->argc != 1) && (a->argc != 2))
783 return errorSyntax(USAGE_UNREGISTERVM, "Incorrect number of parameters");
784
785 ComPtr<IMachine> machine;
786 /* assume it's a UUID */
787 rc = a->virtualBox->GetMachine(Guid(a->argv[0]), machine.asOutParam());
788 if (FAILED(rc) || !machine)
789 {
790 /* must be a name */
791 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
792 }
793 if (machine)
794 {
795 Guid uuid;
796 machine->COMGETTER(Id)(uuid.asOutParam());
797 machine = NULL;
798 CHECK_ERROR(a->virtualBox, UnregisterMachine(uuid, machine.asOutParam()));
799 if (SUCCEEDED(rc) && machine)
800 {
801 /* are we supposed to delete the config file? */
802 if ((a->argc == 2) && (strcmp(a->argv[1], "-delete") == 0))
803 {
804 CHECK_ERROR(machine, DeleteSettings());
805 }
806 }
807 }
808 return SUCCEEDED(rc) ? 0 : 1;
809}
810
811static int handleCreateVM(HandlerArg *a)
812{
813 HRESULT rc;
814 Bstr baseFolder;
815 Bstr settingsFile;
816 Bstr name;
817 Bstr osTypeId;
818 RTUUID id;
819 bool fRegister = false;
820
821 RTUuidClear(&id);
822 for (int i = 0; i < a->argc; i++)
823 {
824 if (strcmp(a->argv[i], "-basefolder") == 0)
825 {
826 if (a->argc <= i + 1)
827 return errorArgument("Missing argument to '%s'", a->argv[i]);
828 i++;
829 baseFolder = a->argv[i];
830 }
831 else if (strcmp(a->argv[i], "-settingsfile") == 0)
832 {
833 if (a->argc <= i + 1)
834 return errorArgument("Missing argument to '%s'", a->argv[i]);
835 i++;
836 settingsFile = a->argv[i];
837 }
838 else if (strcmp(a->argv[i], "-name") == 0)
839 {
840 if (a->argc <= i + 1)
841 return errorArgument("Missing argument to '%s'", a->argv[i]);
842 i++;
843 name = a->argv[i];
844 }
845 else if (strcmp(a->argv[i], "-ostype") == 0)
846 {
847 if (a->argc <= i + 1)
848 return errorArgument("Missing argument to '%s'", a->argv[i]);
849 i++;
850 osTypeId = a->argv[i];
851 }
852 else if (strcmp(a->argv[i], "-uuid") == 0)
853 {
854 if (a->argc <= i + 1)
855 return errorArgument("Missing argument to '%s'", a->argv[i]);
856 i++;
857 if (RT_FAILURE(RTUuidFromStr(&id, a->argv[i])))
858 return errorArgument("Invalid UUID format %s\n", a->argv[i]);
859 }
860 else if (strcmp(a->argv[i], "-register") == 0)
861 {
862 fRegister = true;
863 }
864 else
865 return errorSyntax(USAGE_CREATEVM, "Invalid parameter '%s'", Utf8Str(a->argv[i]).raw());
866 }
867 if (!name)
868 return errorSyntax(USAGE_CREATEVM, "Parameter -name is required");
869
870 if (!!baseFolder && !!settingsFile)
871 return errorSyntax(USAGE_CREATEVM, "Either -basefolder or -settingsfile must be specified");
872
873 do
874 {
875 ComPtr<IMachine> machine;
876
877 if (!settingsFile)
878 CHECK_ERROR_BREAK(a->virtualBox,
879 CreateMachine(name, osTypeId, baseFolder, Guid(id), machine.asOutParam()));
880 else
881 CHECK_ERROR_BREAK(a->virtualBox,
882 CreateLegacyMachine(name, osTypeId, settingsFile, Guid(id), machine.asOutParam()));
883
884 CHECK_ERROR_BREAK(machine, SaveSettings());
885 if (fRegister)
886 {
887 CHECK_ERROR_BREAK(a->virtualBox, RegisterMachine(machine));
888 }
889 Guid uuid;
890 CHECK_ERROR_BREAK(machine, COMGETTER(Id)(uuid.asOutParam()));
891 CHECK_ERROR_BREAK(machine, COMGETTER(SettingsFilePath)(settingsFile.asOutParam()));
892 RTPrintf("Virtual machine '%ls' is created%s.\n"
893 "UUID: %s\n"
894 "Settings file: '%ls'\n",
895 name.raw(), fRegister ? " and registered" : "",
896 uuid.toString().raw(), settingsFile.raw());
897 }
898 while (0);
899
900 return SUCCEEDED(rc) ? 0 : 1;
901}
902
903/**
904 * Parses a number.
905 *
906 * @returns Valid number on success.
907 * @returns 0 if invalid number. All necesary bitching has been done.
908 * @param psz Pointer to the nic number.
909 */
910unsigned parseNum(const char *psz, unsigned cMaxNum, const char *name)
911{
912 uint32_t u32;
913 char *pszNext;
914 int rc = RTStrToUInt32Ex(psz, &pszNext, 10, &u32);
915 if ( RT_SUCCESS(rc)
916 && *pszNext == '\0'
917 && u32 >= 1
918 && u32 <= cMaxNum)
919 return (unsigned)u32;
920 errorArgument("Invalid %s number '%s'", name, psz);
921 return 0;
922}
923
924
925/** @todo refine this after HDD changes; MSC 8.0/64 has trouble with handleModifyVM. */
926#if defined(_MSC_VER)
927# pragma optimize("", on)
928#endif
929
930static int handleStartVM(HandlerArg *a)
931{
932 HRESULT rc;
933
934 if (a->argc < 1)
935 return errorSyntax(USAGE_STARTVM, "Not enough parameters");
936
937 ComPtr<IMachine> machine;
938 /* assume it's a UUID */
939 rc = a->virtualBox->GetMachine(Guid(a->argv[0]), machine.asOutParam());
940 if (FAILED(rc) || !machine)
941 {
942 /* must be a name */
943 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
944 }
945 if (machine)
946 {
947 Guid uuid;
948 machine->COMGETTER(Id)(uuid.asOutParam());
949
950 /* default to GUI session type */
951 Bstr sessionType = "gui";
952 /* has a session type been specified? */
953 if ((a->argc > 2) && (strcmp(a->argv[1], "-type") == 0))
954 {
955 if (strcmp(a->argv[2], "gui") == 0)
956 {
957 sessionType = "gui";
958 }
959 else if (strcmp(a->argv[2], "vrdp") == 0)
960 {
961 sessionType = "vrdp";
962 }
963 else if (strcmp(a->argv[2], "capture") == 0)
964 {
965 sessionType = "capture";
966 }
967 else
968 return errorArgument("Invalid session type argument '%s'", a->argv[2]);
969 }
970
971 Bstr env;
972#ifdef RT_OS_LINUX
973 /* make sure the VM process will start on the same display as VBoxManage */
974 {
975 const char *display = RTEnvGet ("DISPLAY");
976 if (display)
977 env = Utf8StrFmt ("DISPLAY=%s", display);
978 }
979#endif
980 ComPtr<IProgress> progress;
981 CHECK_ERROR_RET(a->virtualBox, OpenRemoteSession(a->session, uuid, sessionType,
982 env, progress.asOutParam()), rc);
983 RTPrintf("Waiting for the remote session to open...\n");
984 CHECK_ERROR_RET(progress, WaitForCompletion (-1), 1);
985
986 BOOL completed;
987 CHECK_ERROR_RET(progress, COMGETTER(Completed)(&completed), rc);
988 ASSERT(completed);
989
990 HRESULT resultCode;
991 CHECK_ERROR_RET(progress, COMGETTER(ResultCode)(&resultCode), rc);
992 if (FAILED(resultCode))
993 {
994 ComPtr <IVirtualBoxErrorInfo> errorInfo;
995 CHECK_ERROR_RET(progress, COMGETTER(ErrorInfo)(errorInfo.asOutParam()), 1);
996 ErrorInfo info (errorInfo);
997 GluePrintErrorInfo(info);
998 }
999 else
1000 {
1001 RTPrintf("Remote session has been successfully opened.\n");
1002 }
1003 }
1004
1005 /* it's important to always close sessions */
1006 a->session->Close();
1007
1008 return SUCCEEDED(rc) ? 0 : 1;
1009}
1010
1011static int handleControlVM(HandlerArg *a)
1012{
1013 HRESULT rc;
1014
1015 if (a->argc < 2)
1016 return errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
1017
1018 /* try to find the given machine */
1019 ComPtr <IMachine> machine;
1020 Guid uuid (a->argv[0]);
1021 if (!uuid.isEmpty())
1022 {
1023 CHECK_ERROR (a->virtualBox, GetMachine (uuid, machine.asOutParam()));
1024 }
1025 else
1026 {
1027 CHECK_ERROR (a->virtualBox, FindMachine (Bstr(a->argv[0]), machine.asOutParam()));
1028 if (SUCCEEDED (rc))
1029 machine->COMGETTER(Id) (uuid.asOutParam());
1030 }
1031 if (FAILED (rc))
1032 return 1;
1033
1034 /* open a session for the VM */
1035 CHECK_ERROR_RET (a->virtualBox, OpenExistingSession (a->session, uuid), 1);
1036
1037 do
1038 {
1039 /* get the associated console */
1040 ComPtr<IConsole> console;
1041 CHECK_ERROR_BREAK (a->session, COMGETTER(Console)(console.asOutParam()));
1042 /* ... and session machine */
1043 ComPtr<IMachine> sessionMachine;
1044 CHECK_ERROR_BREAK (a->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
1045
1046 /* which command? */
1047 if (strcmp(a->argv[1], "pause") == 0)
1048 {
1049 CHECK_ERROR_BREAK (console, Pause());
1050 }
1051 else if (strcmp(a->argv[1], "resume") == 0)
1052 {
1053 CHECK_ERROR_BREAK (console, Resume());
1054 }
1055 else if (strcmp(a->argv[1], "reset") == 0)
1056 {
1057 CHECK_ERROR_BREAK (console, Reset());
1058 }
1059 else if (strcmp(a->argv[1], "poweroff") == 0)
1060 {
1061 CHECK_ERROR_BREAK (console, PowerDown());
1062 }
1063 else if (strcmp(a->argv[1], "savestate") == 0)
1064 {
1065 ComPtr<IProgress> progress;
1066 CHECK_ERROR_BREAK (console, SaveState(progress.asOutParam()));
1067
1068 showProgress(progress);
1069
1070 progress->COMGETTER(ResultCode)(&rc);
1071 if (FAILED(rc))
1072 {
1073 com::ProgressErrorInfo info(progress);
1074 if (info.isBasicAvailable())
1075 {
1076 RTPrintf("Error: failed to save machine state. Error message: %lS\n", info.getText().raw());
1077 }
1078 else
1079 {
1080 RTPrintf("Error: failed to save machine state. No error message available!\n");
1081 }
1082 }
1083 }
1084 else if (strcmp(a->argv[1], "acpipowerbutton") == 0)
1085 {
1086 CHECK_ERROR_BREAK (console, PowerButton());
1087 }
1088 else if (strcmp(a->argv[1], "acpisleepbutton") == 0)
1089 {
1090 CHECK_ERROR_BREAK (console, SleepButton());
1091 }
1092 else if (strcmp(a->argv[1], "injectnmi") == 0)
1093 {
1094 /* get the machine debugger. */
1095 ComPtr <IMachineDebugger> debugger;
1096 CHECK_ERROR_BREAK(console, COMGETTER(Debugger)(debugger.asOutParam()));
1097 CHECK_ERROR_BREAK(debugger, InjectNMI());
1098 }
1099 else if (strcmp(a->argv[1], "keyboardputscancode") == 0)
1100 {
1101 ComPtr<IKeyboard> keyboard;
1102 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(keyboard.asOutParam()));
1103
1104 if (a->argc <= 1 + 1)
1105 {
1106 errorArgument("Missing argument to '%s'. Expected IBM PC AT set 2 keyboard scancode(s) as hex byte(s).", a->argv[1]);
1107 rc = E_FAIL;
1108 break;
1109 }
1110
1111 /* Arbitrary restrict the length of a sequence of scancodes to 1024. */
1112 LONG alScancodes[1024];
1113 int cScancodes = 0;
1114
1115 /* Process the command line. */
1116 int i;
1117 for (i = 1 + 1; i < a->argc && cScancodes < (int)RT_ELEMENTS(alScancodes); i++, cScancodes++)
1118 {
1119 if ( RT_C_IS_XDIGIT (a->argv[i][0])
1120 && RT_C_IS_XDIGIT (a->argv[i][1])
1121 && a->argv[i][2] == 0)
1122 {
1123 uint8_t u8Scancode;
1124 int rc = RTStrToUInt8Ex(a->argv[i], NULL, 16, &u8Scancode);
1125 if (RT_FAILURE (rc))
1126 {
1127 RTPrintf("Error: converting '%s' returned %Rrc!\n", a->argv[i], rc);
1128 rc = E_FAIL;
1129 break;
1130 }
1131
1132 alScancodes[cScancodes] = u8Scancode;
1133 }
1134 else
1135 {
1136 RTPrintf("Error: '%s' is not a hex byte!\n", a->argv[i]);
1137 rc = E_FAIL;
1138 break;
1139 }
1140 }
1141
1142 if (FAILED(rc))
1143 break;
1144
1145 if ( cScancodes == RT_ELEMENTS(alScancodes)
1146 && i < a->argc)
1147 {
1148 RTPrintf("Error: too many scancodes, maximum %d allowed!\n", RT_ELEMENTS(alScancodes));
1149 rc = E_FAIL;
1150 break;
1151 }
1152
1153 /* Send scancodes to the VM.
1154 * Note: 'PutScancodes' did not work here. Only the first scancode was transmitted.
1155 */
1156 for (i = 0; i < cScancodes; i++)
1157 {
1158 CHECK_ERROR_BREAK(keyboard, PutScancode(alScancodes[i]));
1159 RTPrintf("Scancode[%d]: 0x%02X\n", i, alScancodes[i]);
1160 }
1161 }
1162 else if (strncmp(a->argv[1], "setlinkstate", 12) == 0)
1163 {
1164 /* Get the number of network adapters */
1165 ULONG NetworkAdapterCount = 0;
1166 ComPtr <ISystemProperties> info;
1167 CHECK_ERROR_BREAK (a->virtualBox, COMGETTER(SystemProperties) (info.asOutParam()));
1168 CHECK_ERROR_BREAK (info, COMGETTER(NetworkAdapterCount) (&NetworkAdapterCount));
1169
1170 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
1171 if (!n)
1172 {
1173 rc = E_FAIL;
1174 break;
1175 }
1176 if (a->argc <= 1 + 1)
1177 {
1178 errorArgument("Missing argument to '%s'", a->argv[1]);
1179 rc = E_FAIL;
1180 break;
1181 }
1182 /* get the corresponding network adapter */
1183 ComPtr<INetworkAdapter> adapter;
1184 CHECK_ERROR_BREAK (sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
1185 if (adapter)
1186 {
1187 if (strcmp(a->argv[2], "on") == 0)
1188 {
1189 CHECK_ERROR_BREAK (adapter, COMSETTER(CableConnected)(TRUE));
1190 }
1191 else if (strcmp(a->argv[2], "off") == 0)
1192 {
1193 CHECK_ERROR_BREAK (adapter, COMSETTER(CableConnected)(FALSE));
1194 }
1195 else
1196 {
1197 errorArgument("Invalid link state '%s'", Utf8Str(a->argv[2]).raw());
1198 rc = E_FAIL;
1199 break;
1200 }
1201 }
1202 }
1203#ifdef VBOX_WITH_VRDP
1204 else if (strcmp(a->argv[1], "vrdp") == 0)
1205 {
1206 if (a->argc <= 1 + 1)
1207 {
1208 errorArgument("Missing argument to '%s'", a->argv[1]);
1209 rc = E_FAIL;
1210 break;
1211 }
1212 /* get the corresponding VRDP server */
1213 ComPtr<IVRDPServer> vrdpServer;
1214 sessionMachine->COMGETTER(VRDPServer)(vrdpServer.asOutParam());
1215 ASSERT(vrdpServer);
1216 if (vrdpServer)
1217 {
1218 if (strcmp(a->argv[2], "on") == 0)
1219 {
1220 CHECK_ERROR_BREAK (vrdpServer, COMSETTER(Enabled)(TRUE));
1221 }
1222 else if (strcmp(a->argv[2], "off") == 0)
1223 {
1224 CHECK_ERROR_BREAK (vrdpServer, COMSETTER(Enabled)(FALSE));
1225 }
1226 else
1227 {
1228 errorArgument("Invalid vrdp server state '%s'", Utf8Str(a->argv[2]).raw());
1229 rc = E_FAIL;
1230 break;
1231 }
1232 }
1233 }
1234#endif /* VBOX_WITH_VRDP */
1235 else if (strcmp (a->argv[1], "usbattach") == 0 ||
1236 strcmp (a->argv[1], "usbdetach") == 0)
1237 {
1238 if (a->argc < 3)
1239 {
1240 errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
1241 rc = E_FAIL;
1242 break;
1243 }
1244
1245 bool attach = strcmp (a->argv[1], "usbattach") == 0;
1246
1247 Guid usbId = a->argv [2];
1248 if (usbId.isEmpty())
1249 {
1250 // assume address
1251 if (attach)
1252 {
1253 ComPtr <IHost> host;
1254 CHECK_ERROR_BREAK (a->virtualBox, COMGETTER(Host) (host.asOutParam()));
1255 ComPtr <IHostUSBDeviceCollection> coll;
1256 CHECK_ERROR_BREAK (host, COMGETTER(USBDevices) (coll.asOutParam()));
1257 ComPtr <IHostUSBDevice> dev;
1258 CHECK_ERROR_BREAK (coll, FindByAddress (Bstr (a->argv [2]), dev.asOutParam()));
1259 CHECK_ERROR_BREAK (dev, COMGETTER(Id) (usbId.asOutParam()));
1260 }
1261 else
1262 {
1263 ComPtr <IUSBDeviceCollection> coll;
1264 CHECK_ERROR_BREAK (console, COMGETTER(USBDevices)(coll.asOutParam()));
1265 ComPtr <IUSBDevice> dev;
1266 CHECK_ERROR_BREAK (coll, FindByAddress (Bstr (a->argv [2]), dev.asOutParam()));
1267 CHECK_ERROR_BREAK (dev, COMGETTER(Id) (usbId.asOutParam()));
1268 }
1269 }
1270
1271 if (attach)
1272 CHECK_ERROR_BREAK (console, AttachUSBDevice (usbId));
1273 else
1274 {
1275 ComPtr <IUSBDevice> dev;
1276 CHECK_ERROR_BREAK (console, DetachUSBDevice (usbId, dev.asOutParam()));
1277 }
1278 }
1279 else if (strcmp(a->argv[1], "setvideomodehint") == 0)
1280 {
1281 if (a->argc != 5 && a->argc != 6)
1282 {
1283 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1284 rc = E_FAIL;
1285 break;
1286 }
1287 uint32_t xres = RTStrToUInt32(a->argv[2]);
1288 uint32_t yres = RTStrToUInt32(a->argv[3]);
1289 uint32_t bpp = RTStrToUInt32(a->argv[4]);
1290 uint32_t displayIdx = 0;
1291 if (a->argc == 6)
1292 displayIdx = RTStrToUInt32(a->argv[5]);
1293
1294 ComPtr<IDisplay> display;
1295 CHECK_ERROR_BREAK(console, COMGETTER(Display)(display.asOutParam()));
1296 CHECK_ERROR_BREAK(display, SetVideoModeHint(xres, yres, bpp, displayIdx));
1297 }
1298 else if (strcmp(a->argv[1], "setcredentials") == 0)
1299 {
1300 bool fAllowLocalLogon = true;
1301 if (a->argc == 7)
1302 {
1303 if (strcmp(a->argv[5], "-allowlocallogon") != 0)
1304 {
1305 errorArgument("Invalid parameter '%s'", a->argv[5]);
1306 rc = E_FAIL;
1307 break;
1308 }
1309 if (strcmp(a->argv[6], "no") == 0)
1310 fAllowLocalLogon = false;
1311 }
1312 else if (a->argc != 5)
1313 {
1314 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1315 rc = E_FAIL;
1316 break;
1317 }
1318
1319 ComPtr<IGuest> guest;
1320 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(guest.asOutParam()));
1321 CHECK_ERROR_BREAK(guest, SetCredentials(Bstr(a->argv[2]), Bstr(a->argv[3]), Bstr(a->argv[4]), fAllowLocalLogon));
1322 }
1323 else if (strcmp(a->argv[1], "dvdattach") == 0)
1324 {
1325 if (a->argc != 3)
1326 {
1327 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1328 rc = E_FAIL;
1329 break;
1330 }
1331 ComPtr<IDVDDrive> dvdDrive;
1332 sessionMachine->COMGETTER(DVDDrive)(dvdDrive.asOutParam());
1333 ASSERT(dvdDrive);
1334
1335 /* unmount? */
1336 if (strcmp(a->argv[2], "none") == 0)
1337 {
1338 CHECK_ERROR(dvdDrive, Unmount());
1339 }
1340 /* host drive? */
1341 else if (strncmp(a->argv[2], "host:", 5) == 0)
1342 {
1343 ComPtr<IHost> host;
1344 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1345 ComPtr<IHostDVDDriveCollection> hostDVDs;
1346 CHECK_ERROR(host, COMGETTER(DVDDrives)(hostDVDs.asOutParam()));
1347 ComPtr<IHostDVDDrive> hostDVDDrive;
1348 rc = hostDVDs->FindByName(Bstr(a->argv[2] + 5), hostDVDDrive.asOutParam());
1349 if (!hostDVDDrive)
1350 {
1351 errorArgument("Invalid host DVD drive name");
1352 rc = E_FAIL;
1353 break;
1354 }
1355 CHECK_ERROR(dvdDrive, CaptureHostDrive(hostDVDDrive));
1356 }
1357 else
1358 {
1359 /* first assume it's a UUID */
1360 Guid uuid(a->argv[2]);
1361 ComPtr<IDVDImage> dvdImage;
1362 rc = a->virtualBox->GetDVDImage(uuid, dvdImage.asOutParam());
1363 if (FAILED(rc) || !dvdImage)
1364 {
1365 /* must be a filename, check if it's in the collection */
1366 rc = a->virtualBox->FindDVDImage(Bstr(a->argv[2]), dvdImage.asOutParam());
1367 /* not registered, do that on the fly */
1368 if (!dvdImage)
1369 {
1370 Guid emptyUUID;
1371 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(a->argv[2]), emptyUUID, dvdImage.asOutParam()));
1372 }
1373 }
1374 if (!dvdImage)
1375 {
1376 rc = E_FAIL;
1377 break;
1378 }
1379 dvdImage->COMGETTER(Id)(uuid.asOutParam());
1380 CHECK_ERROR(dvdDrive, MountImage(uuid));
1381 }
1382 }
1383 else if (strcmp(a->argv[1], "floppyattach") == 0)
1384 {
1385 if (a->argc != 3)
1386 {
1387 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1388 rc = E_FAIL;
1389 break;
1390 }
1391
1392 ComPtr<IFloppyDrive> floppyDrive;
1393 sessionMachine->COMGETTER(FloppyDrive)(floppyDrive.asOutParam());
1394 ASSERT(floppyDrive);
1395
1396 /* unmount? */
1397 if (strcmp(a->argv[2], "none") == 0)
1398 {
1399 CHECK_ERROR(floppyDrive, Unmount());
1400 }
1401 /* host drive? */
1402 else if (strncmp(a->argv[2], "host:", 5) == 0)
1403 {
1404 ComPtr<IHost> host;
1405 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1406 ComPtr<IHostFloppyDriveCollection> hostFloppies;
1407 CHECK_ERROR(host, COMGETTER(FloppyDrives)(hostFloppies.asOutParam()));
1408 ComPtr<IHostFloppyDrive> hostFloppyDrive;
1409 rc = hostFloppies->FindByName(Bstr(a->argv[2] + 5), hostFloppyDrive.asOutParam());
1410 if (!hostFloppyDrive)
1411 {
1412 errorArgument("Invalid host floppy drive name");
1413 rc = E_FAIL;
1414 break;
1415 }
1416 CHECK_ERROR(floppyDrive, CaptureHostDrive(hostFloppyDrive));
1417 }
1418 else
1419 {
1420 /* first assume it's a UUID */
1421 Guid uuid(a->argv[2]);
1422 ComPtr<IFloppyImage> floppyImage;
1423 rc = a->virtualBox->GetFloppyImage(uuid, floppyImage.asOutParam());
1424 if (FAILED(rc) || !floppyImage)
1425 {
1426 /* must be a filename, check if it's in the collection */
1427 rc = a->virtualBox->FindFloppyImage(Bstr(a->argv[2]), floppyImage.asOutParam());
1428 /* not registered, do that on the fly */
1429 if (!floppyImage)
1430 {
1431 Guid emptyUUID;
1432 CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(a->argv[2]), emptyUUID, floppyImage.asOutParam()));
1433 }
1434 }
1435 if (!floppyImage)
1436 {
1437 rc = E_FAIL;
1438 break;
1439 }
1440 floppyImage->COMGETTER(Id)(uuid.asOutParam());
1441 CHECK_ERROR(floppyDrive, MountImage(uuid));
1442 }
1443 }
1444#ifdef VBOX_WITH_MEM_BALLOONING
1445 else if (strncmp(a->argv[1], "-guestmemoryballoon", 19) == 0)
1446 {
1447 if (a->argc != 3)
1448 {
1449 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1450 rc = E_FAIL;
1451 break;
1452 }
1453 uint32_t uVal;
1454 int vrc;
1455 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1456 if (vrc != VINF_SUCCESS)
1457 {
1458 errorArgument("Error parsing guest memory balloon size '%s'", a->argv[2]);
1459 rc = E_FAIL;
1460 break;
1461 }
1462
1463 /* guest is running; update IGuest */
1464 ComPtr <IGuest> guest;
1465
1466 rc = console->COMGETTER(Guest)(guest.asOutParam());
1467 if (SUCCEEDED(rc))
1468 CHECK_ERROR(guest, COMSETTER(MemoryBalloonSize)(uVal));
1469 }
1470#endif
1471 else if (strncmp(a->argv[1], "-gueststatisticsinterval", 24) == 0)
1472 {
1473 if (a->argc != 3)
1474 {
1475 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1476 rc = E_FAIL;
1477 break;
1478 }
1479 uint32_t uVal;
1480 int vrc;
1481 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1482 if (vrc != VINF_SUCCESS)
1483 {
1484 errorArgument("Error parsing guest statistics interval '%s'", a->argv[2]);
1485 rc = E_FAIL;
1486 break;
1487 }
1488
1489 /* guest is running; update IGuest */
1490 ComPtr <IGuest> guest;
1491
1492 rc = console->COMGETTER(Guest)(guest.asOutParam());
1493 if (SUCCEEDED(rc))
1494 CHECK_ERROR(guest, COMSETTER(StatisticsUpdateInterval)(uVal));
1495 }
1496 else
1497 {
1498 errorSyntax(USAGE_CONTROLVM, "Invalid parameter '%s'", Utf8Str(a->argv[1]).raw());
1499 rc = E_FAIL;
1500 }
1501 }
1502 while (0);
1503
1504 a->session->Close();
1505
1506 return SUCCEEDED (rc) ? 0 : 1;
1507}
1508
1509static int handleDiscardState(HandlerArg *a)
1510{
1511 HRESULT rc;
1512
1513 if (a->argc != 1)
1514 return errorSyntax(USAGE_DISCARDSTATE, "Incorrect number of parameters");
1515
1516 ComPtr<IMachine> machine;
1517 /* assume it's a UUID */
1518 rc = a->virtualBox->GetMachine(Guid(a->argv[0]), machine.asOutParam());
1519 if (FAILED(rc) || !machine)
1520 {
1521 /* must be a name */
1522 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
1523 }
1524 if (machine)
1525 {
1526 do
1527 {
1528 /* we have to open a session for this task */
1529 Guid guid;
1530 machine->COMGETTER(Id)(guid.asOutParam());
1531 CHECK_ERROR_BREAK(a->virtualBox, OpenSession(a->session, guid));
1532 do
1533 {
1534 ComPtr<IConsole> console;
1535 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
1536 CHECK_ERROR_BREAK(console, DiscardSavedState());
1537 }
1538 while (0);
1539 CHECK_ERROR_BREAK(a->session, Close());
1540 }
1541 while (0);
1542 }
1543
1544 return SUCCEEDED(rc) ? 0 : 1;
1545}
1546
1547static int handleAdoptdState(HandlerArg *a)
1548{
1549 HRESULT rc;
1550
1551 if (a->argc != 2)
1552 return errorSyntax(USAGE_ADOPTSTATE, "Incorrect number of parameters");
1553
1554 ComPtr<IMachine> machine;
1555 /* assume it's a UUID */
1556 rc = a->virtualBox->GetMachine(Guid(a->argv[0]), machine.asOutParam());
1557 if (FAILED(rc) || !machine)
1558 {
1559 /* must be a name */
1560 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
1561 }
1562 if (machine)
1563 {
1564 do
1565 {
1566 /* we have to open a session for this task */
1567 Guid guid;
1568 machine->COMGETTER(Id)(guid.asOutParam());
1569 CHECK_ERROR_BREAK(a->virtualBox, OpenSession(a->session, guid));
1570 do
1571 {
1572 ComPtr<IConsole> console;
1573 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
1574 CHECK_ERROR_BREAK(console, AdoptSavedState (Bstr (a->argv[1])));
1575 }
1576 while (0);
1577 CHECK_ERROR_BREAK(a->session, Close());
1578 }
1579 while (0);
1580 }
1581
1582 return SUCCEEDED(rc) ? 0 : 1;
1583}
1584
1585static int handleGetExtraData(HandlerArg *a)
1586{
1587 HRESULT rc = S_OK;
1588
1589 if (a->argc != 2)
1590 return errorSyntax(USAGE_GETEXTRADATA, "Incorrect number of parameters");
1591
1592 /* global data? */
1593 if (strcmp(a->argv[0], "global") == 0)
1594 {
1595 /* enumeration? */
1596 if (strcmp(a->argv[1], "enumerate") == 0)
1597 {
1598 Bstr extraDataKey;
1599
1600 do
1601 {
1602 Bstr nextExtraDataKey;
1603 Bstr nextExtraDataValue;
1604 HRESULT rcEnum = a->virtualBox->GetNextExtraDataKey(extraDataKey, nextExtraDataKey.asOutParam(),
1605 nextExtraDataValue.asOutParam());
1606 extraDataKey = nextExtraDataKey;
1607
1608 if (SUCCEEDED(rcEnum) && extraDataKey)
1609 RTPrintf("Key: %lS, Value: %lS\n", nextExtraDataKey.raw(), nextExtraDataValue.raw());
1610 } while (extraDataKey);
1611 }
1612 else
1613 {
1614 Bstr value;
1615 CHECK_ERROR(a->virtualBox, GetExtraData(Bstr(a->argv[1]), value.asOutParam()));
1616 if (value)
1617 RTPrintf("Value: %lS\n", value.raw());
1618 else
1619 RTPrintf("No value set!\n");
1620 }
1621 }
1622 else
1623 {
1624 ComPtr<IMachine> machine;
1625 /* assume it's a UUID */
1626 rc = a->virtualBox->GetMachine(Guid(a->argv[0]), machine.asOutParam());
1627 if (FAILED(rc) || !machine)
1628 {
1629 /* must be a name */
1630 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
1631 }
1632 if (machine)
1633 {
1634 /* enumeration? */
1635 if (strcmp(a->argv[1], "enumerate") == 0)
1636 {
1637 Bstr extraDataKey;
1638
1639 do
1640 {
1641 Bstr nextExtraDataKey;
1642 Bstr nextExtraDataValue;
1643 HRESULT rcEnum = machine->GetNextExtraDataKey(extraDataKey, nextExtraDataKey.asOutParam(),
1644 nextExtraDataValue.asOutParam());
1645 extraDataKey = nextExtraDataKey;
1646
1647 if (SUCCEEDED(rcEnum) && extraDataKey)
1648 {
1649 RTPrintf("Key: %lS, Value: %lS\n", nextExtraDataKey.raw(), nextExtraDataValue.raw());
1650 }
1651 } while (extraDataKey);
1652 }
1653 else
1654 {
1655 Bstr value;
1656 CHECK_ERROR(machine, GetExtraData(Bstr(a->argv[1]), value.asOutParam()));
1657 if (value)
1658 RTPrintf("Value: %lS\n", value.raw());
1659 else
1660 RTPrintf("No value set!\n");
1661 }
1662 }
1663 }
1664 return SUCCEEDED(rc) ? 0 : 1;
1665}
1666
1667static int handleSetExtraData(HandlerArg *a)
1668{
1669 HRESULT rc = S_OK;
1670
1671 if (a->argc < 2)
1672 return errorSyntax(USAGE_SETEXTRADATA, "Not enough parameters");
1673
1674 /* global data? */
1675 if (strcmp(a->argv[0], "global") == 0)
1676 {
1677 if (a->argc < 3)
1678 CHECK_ERROR(a->virtualBox, SetExtraData(Bstr(a->argv[1]), NULL));
1679 else if (a->argc == 3)
1680 CHECK_ERROR(a->virtualBox, SetExtraData(Bstr(a->argv[1]), Bstr(a->argv[2])));
1681 else
1682 return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
1683 }
1684 else
1685 {
1686 ComPtr<IMachine> machine;
1687 /* assume it's a UUID */
1688 rc = a->virtualBox->GetMachine(Guid(a->argv[0]), machine.asOutParam());
1689 if (FAILED(rc) || !machine)
1690 {
1691 /* must be a name */
1692 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
1693 }
1694 if (machine)
1695 {
1696 if (a->argc < 3)
1697 CHECK_ERROR(machine, SetExtraData(Bstr(a->argv[1]), NULL));
1698 else if (a->argc == 3)
1699 CHECK_ERROR(machine, SetExtraData(Bstr(a->argv[1]), Bstr(a->argv[2])));
1700 else
1701 return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
1702 }
1703 }
1704 return SUCCEEDED(rc) ? 0 : 1;
1705}
1706
1707static int handleSetProperty(HandlerArg *a)
1708{
1709 HRESULT rc;
1710
1711 /* there must be two arguments: property name and value */
1712 if (a->argc != 2)
1713 return errorSyntax(USAGE_SETPROPERTY, "Incorrect number of parameters");
1714
1715 ComPtr<ISystemProperties> systemProperties;
1716 a->virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
1717
1718 if (strcmp(a->argv[0], "hdfolder") == 0)
1719 {
1720 /* reset to default? */
1721 if (strcmp(a->argv[1], "default") == 0)
1722 CHECK_ERROR(systemProperties, COMSETTER(DefaultHardDiskFolder)(NULL));
1723 else
1724 CHECK_ERROR(systemProperties, COMSETTER(DefaultHardDiskFolder)(Bstr(a->argv[1])));
1725 }
1726 else if (strcmp(a->argv[0], "machinefolder") == 0)
1727 {
1728 /* reset to default? */
1729 if (strcmp(a->argv[1], "default") == 0)
1730 CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(NULL));
1731 else
1732 CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(Bstr(a->argv[1])));
1733 }
1734 else if (strcmp(a->argv[0], "vrdpauthlibrary") == 0)
1735 {
1736 /* reset to default? */
1737 if (strcmp(a->argv[1], "default") == 0)
1738 CHECK_ERROR(systemProperties, COMSETTER(RemoteDisplayAuthLibrary)(NULL));
1739 else
1740 CHECK_ERROR(systemProperties, COMSETTER(RemoteDisplayAuthLibrary)(Bstr(a->argv[1])));
1741 }
1742 else if (strcmp(a->argv[0], "websrvauthlibrary") == 0)
1743 {
1744 /* reset to default? */
1745 if (strcmp(a->argv[1], "default") == 0)
1746 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(NULL));
1747 else
1748 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(Bstr(a->argv[1])));
1749 }
1750 else if (strcmp(a->argv[0], "hwvirtexenabled") == 0)
1751 {
1752 if (strcmp(a->argv[1], "yes") == 0)
1753 CHECK_ERROR(systemProperties, COMSETTER(HWVirtExEnabled)(TRUE));
1754 else if (strcmp(a->argv[1], "no") == 0)
1755 CHECK_ERROR(systemProperties, COMSETTER(HWVirtExEnabled)(FALSE));
1756 else
1757 return errorArgument("Invalid value '%s' for hardware virtualization extension flag", a->argv[1]);
1758 }
1759 else if (strcmp(a->argv[0], "loghistorycount") == 0)
1760 {
1761 uint32_t uVal;
1762 int vrc;
1763 vrc = RTStrToUInt32Ex(a->argv[1], NULL, 0, &uVal);
1764 if (vrc != VINF_SUCCESS)
1765 return errorArgument("Error parsing Log history count '%s'", a->argv[1]);
1766 CHECK_ERROR(systemProperties, COMSETTER(LogHistoryCount)(uVal));
1767 }
1768 else
1769 return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", a->argv[0]);
1770
1771 return SUCCEEDED(rc) ? 0 : 1;
1772}
1773
1774static int handleUSBFilter (HandlerArg *a)
1775{
1776 HRESULT rc = S_OK;
1777 USBFilterCmd cmd;
1778
1779 /* at least: 0: command, 1: index, 2: -target, 3: <target value> */
1780 if (a->argc < 4)
1781 return errorSyntax(USAGE_USBFILTER, "Not enough parameters");
1782
1783 /* which command? */
1784 cmd.mAction = USBFilterCmd::Invalid;
1785 if (strcmp (a->argv [0], "add") == 0) cmd.mAction = USBFilterCmd::Add;
1786 else if (strcmp (a->argv [0], "modify") == 0) cmd.mAction = USBFilterCmd::Modify;
1787 else if (strcmp (a->argv [0], "remove") == 0) cmd.mAction = USBFilterCmd::Remove;
1788
1789 if (cmd.mAction == USBFilterCmd::Invalid)
1790 return errorSyntax(USAGE_USBFILTER, "Invalid parameter '%s'", a->argv[0]);
1791
1792 /* which index? */
1793 if (VINF_SUCCESS != RTStrToUInt32Full (a->argv[1], 10, &cmd.mIndex))
1794 return errorSyntax(USAGE_USBFILTER, "Invalid index '%s'", a->argv[1]);
1795
1796 switch (cmd.mAction)
1797 {
1798 case USBFilterCmd::Add:
1799 case USBFilterCmd::Modify:
1800 {
1801 /* at least: 0: command, 1: index, 2: -target, 3: <target value>, 4: -name, 5: <name value> */
1802 if (a->argc < 6)
1803 {
1804 if (cmd.mAction == USBFilterCmd::Add)
1805 return errorSyntax(USAGE_USBFILTER_ADD, "Not enough parameters");
1806
1807 return errorSyntax(USAGE_USBFILTER_MODIFY, "Not enough parameters");
1808 }
1809
1810 // set Active to true by default
1811 // (assuming that the user sets up all necessary attributes
1812 // at once and wants the filter to be active immediately)
1813 if (cmd.mAction == USBFilterCmd::Add)
1814 cmd.mFilter.mActive = true;
1815
1816 for (int i = 2; i < a->argc; i++)
1817 {
1818 if (strcmp(a->argv [i], "-target") == 0)
1819 {
1820 if (a->argc <= i + 1 || !*a->argv[i+1])
1821 return errorArgument("Missing argument to '%s'", a->argv[i]);
1822 i++;
1823 if (strcmp (a->argv [i], "global") == 0)
1824 cmd.mGlobal = true;
1825 else
1826 {
1827 /* assume it's a UUID of a machine */
1828 rc = a->virtualBox->GetMachine(Guid(a->argv[i]), cmd.mMachine.asOutParam());
1829 if (FAILED(rc) || !cmd.mMachine)
1830 {
1831 /* must be a name */
1832 CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(a->argv[i]), cmd.mMachine.asOutParam()), 1);
1833 }
1834 }
1835 }
1836 else if (strcmp(a->argv [i], "-name") == 0)
1837 {
1838 if (a->argc <= i + 1 || !*a->argv[i+1])
1839 return errorArgument("Missing argument to '%s'", a->argv[i]);
1840 i++;
1841 cmd.mFilter.mName = a->argv [i];
1842 }
1843 else if (strcmp(a->argv [i], "-active") == 0)
1844 {
1845 if (a->argc <= i + 1)
1846 return errorArgument("Missing argument to '%s'", a->argv[i]);
1847 i++;
1848 if (strcmp (a->argv [i], "yes") == 0)
1849 cmd.mFilter.mActive = true;
1850 else if (strcmp (a->argv [i], "no") == 0)
1851 cmd.mFilter.mActive = false;
1852 else
1853 return errorArgument("Invalid -active argument '%s'", a->argv[i]);
1854 }
1855 else if (strcmp(a->argv [i], "-vendorid") == 0)
1856 {
1857 if (a->argc <= i + 1)
1858 return errorArgument("Missing argument to '%s'", a->argv[i]);
1859 i++;
1860 cmd.mFilter.mVendorId = a->argv [i];
1861 }
1862 else if (strcmp(a->argv [i], "-productid") == 0)
1863 {
1864 if (a->argc <= i + 1)
1865 return errorArgument("Missing argument to '%s'", a->argv[i]);
1866 i++;
1867 cmd.mFilter.mProductId = a->argv [i];
1868 }
1869 else if (strcmp(a->argv [i], "-revision") == 0)
1870 {
1871 if (a->argc <= i + 1)
1872 return errorArgument("Missing argument to '%s'", a->argv[i]);
1873 i++;
1874 cmd.mFilter.mRevision = a->argv [i];
1875 }
1876 else if (strcmp(a->argv [i], "-manufacturer") == 0)
1877 {
1878 if (a->argc <= i + 1)
1879 return errorArgument("Missing argument to '%s'", a->argv[i]);
1880 i++;
1881 cmd.mFilter.mManufacturer = a->argv [i];
1882 }
1883 else if (strcmp(a->argv [i], "-product") == 0)
1884 {
1885 if (a->argc <= i + 1)
1886 return errorArgument("Missing argument to '%s'", a->argv[i]);
1887 i++;
1888 cmd.mFilter.mProduct = a->argv [i];
1889 }
1890 else if (strcmp(a->argv [i], "-remote") == 0)
1891 {
1892 if (a->argc <= i + 1)
1893 return errorArgument("Missing argument to '%s'", a->argv[i]);
1894 i++;
1895 cmd.mFilter.mRemote = a->argv[i];
1896 }
1897 else if (strcmp(a->argv [i], "-serialnumber") == 0)
1898 {
1899 if (a->argc <= i + 1)
1900 return errorArgument("Missing argument to '%s'", a->argv[i]);
1901 i++;
1902 cmd.mFilter.mSerialNumber = a->argv [i];
1903 }
1904 else if (strcmp(a->argv [i], "-maskedinterfaces") == 0)
1905 {
1906 if (a->argc <= i + 1)
1907 return errorArgument("Missing argument to '%s'", a->argv[i]);
1908 i++;
1909 uint32_t u32;
1910 rc = RTStrToUInt32Full(a->argv[i], 0, &u32);
1911 if (RT_FAILURE(rc))
1912 return errorArgument("Failed to convert the -maskedinterfaces value '%s' to a number, rc=%Rrc", a->argv[i], rc);
1913 cmd.mFilter.mMaskedInterfaces = u32;
1914 }
1915 else if (strcmp(a->argv [i], "-action") == 0)
1916 {
1917 if (a->argc <= i + 1)
1918 return errorArgument("Missing argument to '%s'", a->argv[i]);
1919 i++;
1920 if (strcmp (a->argv [i], "ignore") == 0)
1921 cmd.mFilter.mAction = USBDeviceFilterAction_Ignore;
1922 else if (strcmp (a->argv [i], "hold") == 0)
1923 cmd.mFilter.mAction = USBDeviceFilterAction_Hold;
1924 else
1925 return errorArgument("Invalid USB filter action '%s'", a->argv[i]);
1926 }
1927 else
1928 return errorSyntax(cmd.mAction == USBFilterCmd::Add ? USAGE_USBFILTER_ADD : USAGE_USBFILTER_MODIFY,
1929 "Unknown option '%s'", a->argv[i]);
1930 }
1931
1932 if (cmd.mAction == USBFilterCmd::Add)
1933 {
1934 // mandatory/forbidden options
1935 if ( cmd.mFilter.mName.isEmpty()
1936 ||
1937 ( cmd.mGlobal
1938 && cmd.mFilter.mAction == USBDeviceFilterAction_Null
1939 )
1940 || ( !cmd.mGlobal
1941 && !cmd.mMachine)
1942 || ( cmd.mGlobal
1943 && cmd.mFilter.mRemote)
1944 )
1945 {
1946 return errorSyntax(USAGE_USBFILTER_ADD, "Mandatory options not supplied");
1947 }
1948 }
1949 break;
1950 }
1951
1952 case USBFilterCmd::Remove:
1953 {
1954 /* at least: 0: command, 1: index, 2: -target, 3: <target value> */
1955 if (a->argc < 4)
1956 return errorSyntax(USAGE_USBFILTER_REMOVE, "Not enough parameters");
1957
1958 for (int i = 2; i < a->argc; i++)
1959 {
1960 if (strcmp(a->argv [i], "-target") == 0)
1961 {
1962 if (a->argc <= i + 1 || !*a->argv[i+1])
1963 return errorArgument("Missing argument to '%s'", a->argv[i]);
1964 i++;
1965 if (strcmp (a->argv [i], "global") == 0)
1966 cmd.mGlobal = true;
1967 else
1968 {
1969 /* assume it's a UUID of a machine */
1970 rc = a->virtualBox->GetMachine(Guid(a->argv[i]), cmd.mMachine.asOutParam());
1971 if (FAILED(rc) || !cmd.mMachine)
1972 {
1973 /* must be a name */
1974 CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(a->argv[i]), cmd.mMachine.asOutParam()), 1);
1975 }
1976 }
1977 }
1978 }
1979
1980 // mandatory options
1981 if (!cmd.mGlobal && !cmd.mMachine)
1982 return errorSyntax(USAGE_USBFILTER_REMOVE, "Mandatory options not supplied");
1983
1984 break;
1985 }
1986
1987 default: break;
1988 }
1989
1990 USBFilterCmd::USBFilter &f = cmd.mFilter;
1991
1992 ComPtr <IHost> host;
1993 ComPtr <IUSBController> ctl;
1994 if (cmd.mGlobal)
1995 CHECK_ERROR_RET (a->virtualBox, COMGETTER(Host) (host.asOutParam()), 1);
1996 else
1997 {
1998 Guid uuid;
1999 cmd.mMachine->COMGETTER(Id)(uuid.asOutParam());
2000 /* open a session for the VM */
2001 CHECK_ERROR_RET (a->virtualBox, OpenSession(a->session, uuid), 1);
2002 /* get the mutable session machine */
2003 a->session->COMGETTER(Machine)(cmd.mMachine.asOutParam());
2004 /* and get the USB controller */
2005 CHECK_ERROR_RET (cmd.mMachine, COMGETTER(USBController) (ctl.asOutParam()), 1);
2006 }
2007
2008 switch (cmd.mAction)
2009 {
2010 case USBFilterCmd::Add:
2011 {
2012 if (cmd.mGlobal)
2013 {
2014 ComPtr <IHostUSBDeviceFilter> flt;
2015 CHECK_ERROR_BREAK (host, CreateUSBDeviceFilter (f.mName, flt.asOutParam()));
2016
2017 if (!f.mActive.isNull())
2018 CHECK_ERROR_BREAK (flt, COMSETTER(Active) (f.mActive));
2019 if (!f.mVendorId.isNull())
2020 CHECK_ERROR_BREAK (flt, COMSETTER(VendorId) (f.mVendorId.setNullIfEmpty()));
2021 if (!f.mProductId.isNull())
2022 CHECK_ERROR_BREAK (flt, COMSETTER(ProductId) (f.mProductId.setNullIfEmpty()));
2023 if (!f.mRevision.isNull())
2024 CHECK_ERROR_BREAK (flt, COMSETTER(Revision) (f.mRevision.setNullIfEmpty()));
2025 if (!f.mManufacturer.isNull())
2026 CHECK_ERROR_BREAK (flt, COMSETTER(Manufacturer) (f.mManufacturer.setNullIfEmpty()));
2027 if (!f.mSerialNumber.isNull())
2028 CHECK_ERROR_BREAK (flt, COMSETTER(SerialNumber) (f.mSerialNumber.setNullIfEmpty()));
2029 if (!f.mMaskedInterfaces.isNull())
2030 CHECK_ERROR_BREAK (flt, COMSETTER(MaskedInterfaces) (f.mMaskedInterfaces));
2031
2032 if (f.mAction != USBDeviceFilterAction_Null)
2033 CHECK_ERROR_BREAK (flt, COMSETTER(Action) (f.mAction));
2034
2035 CHECK_ERROR_BREAK (host, InsertUSBDeviceFilter (cmd.mIndex, flt));
2036 }
2037 else
2038 {
2039 ComPtr <IUSBDeviceFilter> flt;
2040 CHECK_ERROR_BREAK (ctl, CreateDeviceFilter (f.mName, flt.asOutParam()));
2041
2042 if (!f.mActive.isNull())
2043 CHECK_ERROR_BREAK (flt, COMSETTER(Active) (f.mActive));
2044 if (!f.mVendorId.isNull())
2045 CHECK_ERROR_BREAK (flt, COMSETTER(VendorId) (f.mVendorId.setNullIfEmpty()));
2046 if (!f.mProductId.isNull())
2047 CHECK_ERROR_BREAK (flt, COMSETTER(ProductId) (f.mProductId.setNullIfEmpty()));
2048 if (!f.mRevision.isNull())
2049 CHECK_ERROR_BREAK (flt, COMSETTER(Revision) (f.mRevision.setNullIfEmpty()));
2050 if (!f.mManufacturer.isNull())
2051 CHECK_ERROR_BREAK (flt, COMSETTER(Manufacturer) (f.mManufacturer.setNullIfEmpty()));
2052 if (!f.mRemote.isNull())
2053 CHECK_ERROR_BREAK (flt, COMSETTER(Remote) (f.mRemote.setNullIfEmpty()));
2054 if (!f.mSerialNumber.isNull())
2055 CHECK_ERROR_BREAK (flt, COMSETTER(SerialNumber) (f.mSerialNumber.setNullIfEmpty()));
2056 if (!f.mMaskedInterfaces.isNull())
2057 CHECK_ERROR_BREAK (flt, COMSETTER(MaskedInterfaces) (f.mMaskedInterfaces));
2058
2059 CHECK_ERROR_BREAK (ctl, InsertDeviceFilter (cmd.mIndex, flt));
2060 }
2061 break;
2062 }
2063 case USBFilterCmd::Modify:
2064 {
2065 if (cmd.mGlobal)
2066 {
2067 ComPtr <IHostUSBDeviceFilterCollection> coll;
2068 CHECK_ERROR_BREAK (host, COMGETTER(USBDeviceFilters) (coll.asOutParam()));
2069 ComPtr <IHostUSBDeviceFilter> flt;
2070 CHECK_ERROR_BREAK (coll, GetItemAt (cmd.mIndex, flt.asOutParam()));
2071
2072 if (!f.mName.isNull())
2073 CHECK_ERROR_BREAK (flt, COMSETTER(Name) (f.mName.setNullIfEmpty()));
2074 if (!f.mActive.isNull())
2075 CHECK_ERROR_BREAK (flt, COMSETTER(Active) (f.mActive));
2076 if (!f.mVendorId.isNull())
2077 CHECK_ERROR_BREAK (flt, COMSETTER(VendorId) (f.mVendorId.setNullIfEmpty()));
2078 if (!f.mProductId.isNull())
2079 CHECK_ERROR_BREAK (flt, COMSETTER(ProductId) (f.mProductId.setNullIfEmpty()));
2080 if (!f.mRevision.isNull())
2081 CHECK_ERROR_BREAK (flt, COMSETTER(Revision) (f.mRevision.setNullIfEmpty()));
2082 if (!f.mManufacturer.isNull())
2083 CHECK_ERROR_BREAK (flt, COMSETTER(Manufacturer) (f.mManufacturer.setNullIfEmpty()));
2084 if (!f.mSerialNumber.isNull())
2085 CHECK_ERROR_BREAK (flt, COMSETTER(SerialNumber) (f.mSerialNumber.setNullIfEmpty()));
2086 if (!f.mMaskedInterfaces.isNull())
2087 CHECK_ERROR_BREAK (flt, COMSETTER(MaskedInterfaces) (f.mMaskedInterfaces));
2088
2089 if (f.mAction != USBDeviceFilterAction_Null)
2090 CHECK_ERROR_BREAK (flt, COMSETTER(Action) (f.mAction));
2091 }
2092 else
2093 {
2094 ComPtr <IUSBDeviceFilterCollection> coll;
2095 CHECK_ERROR_BREAK (ctl, COMGETTER(DeviceFilters) (coll.asOutParam()));
2096
2097 ComPtr <IUSBDeviceFilter> flt;
2098 CHECK_ERROR_BREAK (coll, GetItemAt (cmd.mIndex, flt.asOutParam()));
2099
2100 if (!f.mName.isNull())
2101 CHECK_ERROR_BREAK (flt, COMSETTER(Name) (f.mName.setNullIfEmpty()));
2102 if (!f.mActive.isNull())
2103 CHECK_ERROR_BREAK (flt, COMSETTER(Active) (f.mActive));
2104 if (!f.mVendorId.isNull())
2105 CHECK_ERROR_BREAK (flt, COMSETTER(VendorId) (f.mVendorId.setNullIfEmpty()));
2106 if (!f.mProductId.isNull())
2107 CHECK_ERROR_BREAK (flt, COMSETTER(ProductId) (f.mProductId.setNullIfEmpty()));
2108 if (!f.mRevision.isNull())
2109 CHECK_ERROR_BREAK (flt, COMSETTER(Revision) (f.mRevision.setNullIfEmpty()));
2110 if (!f.mManufacturer.isNull())
2111 CHECK_ERROR_BREAK (flt, COMSETTER(Manufacturer) (f.mManufacturer.setNullIfEmpty()));
2112 if (!f.mRemote.isNull())
2113 CHECK_ERROR_BREAK (flt, COMSETTER(Remote) (f.mRemote.setNullIfEmpty()));
2114 if (!f.mSerialNumber.isNull())
2115 CHECK_ERROR_BREAK (flt, COMSETTER(SerialNumber) (f.mSerialNumber.setNullIfEmpty()));
2116 if (!f.mMaskedInterfaces.isNull())
2117 CHECK_ERROR_BREAK (flt, COMSETTER(MaskedInterfaces) (f.mMaskedInterfaces));
2118 }
2119 break;
2120 }
2121 case USBFilterCmd::Remove:
2122 {
2123 if (cmd.mGlobal)
2124 {
2125 ComPtr <IHostUSBDeviceFilter> flt;
2126 CHECK_ERROR_BREAK (host, RemoveUSBDeviceFilter (cmd.mIndex, flt.asOutParam()));
2127 }
2128 else
2129 {
2130 ComPtr <IUSBDeviceFilter> flt;
2131 CHECK_ERROR_BREAK (ctl, RemoveDeviceFilter (cmd.mIndex, flt.asOutParam()));
2132 }
2133 break;
2134 }
2135 default:
2136 break;
2137 }
2138
2139 if (cmd.mMachine)
2140 {
2141 /* commit and close the session */
2142 CHECK_ERROR(cmd.mMachine, SaveSettings());
2143 a->session->Close();
2144 }
2145
2146 return SUCCEEDED (rc) ? 0 : 1;
2147}
2148
2149static int handleSharedFolder (HandlerArg *a)
2150{
2151 HRESULT rc;
2152
2153 /* we need at least a command and target */
2154 if (a->argc < 2)
2155 return errorSyntax(USAGE_SHAREDFOLDER, "Not enough parameters");
2156
2157 ComPtr<IMachine> machine;
2158 /* assume it's a UUID */
2159 rc = a->virtualBox->GetMachine(Guid(a->argv[1]), machine.asOutParam());
2160 if (FAILED(rc) || !machine)
2161 {
2162 /* must be a name */
2163 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[1]), machine.asOutParam()));
2164 }
2165 if (!machine)
2166 return 1;
2167 Guid uuid;
2168 machine->COMGETTER(Id)(uuid.asOutParam());
2169
2170 if (strcmp(a->argv[0], "add") == 0)
2171 {
2172 /* we need at least four more parameters */
2173 if (a->argc < 5)
2174 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Not enough parameters");
2175
2176 char *name = NULL;
2177 char *hostpath = NULL;
2178 bool fTransient = false;
2179 bool fWritable = true;
2180
2181 for (int i = 2; i < a->argc; i++)
2182 {
2183 if (strcmp(a->argv[i], "-name") == 0)
2184 {
2185 if (a->argc <= i + 1 || !*a->argv[i+1])
2186 return errorArgument("Missing argument to '%s'", a->argv[i]);
2187 i++;
2188 name = a->argv[i];
2189 }
2190 else if (strcmp(a->argv[i], "-hostpath") == 0)
2191 {
2192 if (a->argc <= i + 1 || !*a->argv[i+1])
2193 return errorArgument("Missing argument to '%s'", a->argv[i]);
2194 i++;
2195 hostpath = a->argv[i];
2196 }
2197 else if (strcmp(a->argv[i], "-readonly") == 0)
2198 {
2199 fWritable = false;
2200 }
2201 else if (strcmp(a->argv[i], "-transient") == 0)
2202 {
2203 fTransient = true;
2204 }
2205 else
2206 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Invalid parameter '%s'", Utf8Str(a->argv[i]).raw());
2207 }
2208
2209 if (NULL != strstr(name, " "))
2210 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "No spaces allowed in parameter '-name'!");
2211
2212 /* required arguments */
2213 if (!name || !hostpath)
2214 {
2215 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Parameters -name and -hostpath are required");
2216 }
2217
2218 if (fTransient)
2219 {
2220 ComPtr <IConsole> console;
2221
2222 /* open an existing session for the VM */
2223 CHECK_ERROR_RET(a->virtualBox, OpenExistingSession (a->session, uuid), 1);
2224 /* get the session machine */
2225 CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
2226 /* get the session console */
2227 CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
2228
2229 CHECK_ERROR(console, CreateSharedFolder(Bstr(name), Bstr(hostpath), fWritable));
2230
2231 if (console)
2232 a->session->Close();
2233 }
2234 else
2235 {
2236 /* open a session for the VM */
2237 CHECK_ERROR_RET (a->virtualBox, OpenSession(a->session, uuid), 1);
2238
2239 /* get the mutable session machine */
2240 a->session->COMGETTER(Machine)(machine.asOutParam());
2241
2242 CHECK_ERROR(machine, CreateSharedFolder(Bstr(name), Bstr(hostpath), fWritable));
2243
2244 if (SUCCEEDED(rc))
2245 CHECK_ERROR(machine, SaveSettings());
2246
2247 a->session->Close();
2248 }
2249 }
2250 else if (strcmp(a->argv[0], "remove") == 0)
2251 {
2252 /* we need at least two more parameters */
2253 if (a->argc < 3)
2254 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Not enough parameters");
2255
2256 char *name = NULL;
2257 bool fTransient = false;
2258
2259 for (int i = 2; i < a->argc; i++)
2260 {
2261 if (strcmp(a->argv[i], "-name") == 0)
2262 {
2263 if (a->argc <= i + 1 || !*a->argv[i+1])
2264 return errorArgument("Missing argument to '%s'", a->argv[i]);
2265 i++;
2266 name = a->argv[i];
2267 }
2268 else if (strcmp(a->argv[i], "-transient") == 0)
2269 {
2270 fTransient = true;
2271 }
2272 else
2273 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Invalid parameter '%s'", Utf8Str(a->argv[i]).raw());
2274 }
2275
2276 /* required arguments */
2277 if (!name)
2278 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Parameter -name is required");
2279
2280 if (fTransient)
2281 {
2282 ComPtr <IConsole> console;
2283
2284 /* open an existing session for the VM */
2285 CHECK_ERROR_RET(a->virtualBox, OpenExistingSession (a->session, uuid), 1);
2286 /* get the session machine */
2287 CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
2288 /* get the session console */
2289 CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
2290
2291 CHECK_ERROR(console, RemoveSharedFolder(Bstr(name)));
2292
2293 if (console)
2294 a->session->Close();
2295 }
2296 else
2297 {
2298 /* open a session for the VM */
2299 CHECK_ERROR_RET (a->virtualBox, OpenSession(a->session, uuid), 1);
2300
2301 /* get the mutable session machine */
2302 a->session->COMGETTER(Machine)(machine.asOutParam());
2303
2304 CHECK_ERROR(machine, RemoveSharedFolder(Bstr(name)));
2305
2306 /* commit and close the session */
2307 CHECK_ERROR(machine, SaveSettings());
2308 a->session->Close();
2309 }
2310 }
2311 else
2312 return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", Utf8Str(a->argv[0]).raw());
2313
2314 return 0;
2315}
2316
2317static int handleVMStatistics(HandlerArg *a)
2318{
2319 HRESULT rc;
2320
2321 /* at least one option: the UUID or name of the VM */
2322 if (a->argc < 1)
2323 return errorSyntax(USAGE_VM_STATISTICS, "Incorrect number of parameters");
2324
2325 /* try to find the given machine */
2326 ComPtr <IMachine> machine;
2327 Guid uuid (a->argv[0]);
2328 if (!uuid.isEmpty())
2329 CHECK_ERROR(a->virtualBox, GetMachine(uuid, machine.asOutParam()));
2330 else
2331 {
2332 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
2333 if (SUCCEEDED (rc))
2334 machine->COMGETTER(Id)(uuid.asOutParam());
2335 }
2336 if (FAILED(rc))
2337 return 1;
2338
2339 /* parse arguments. */
2340 bool fReset = false;
2341 bool fWithDescriptions = false;
2342 const char *pszPattern = NULL; /* all */
2343 for (int i = 1; i < a->argc; i++)
2344 {
2345 if (!strcmp(a->argv[i], "-pattern"))
2346 {
2347 if (pszPattern)
2348 return errorSyntax(USAGE_VM_STATISTICS, "Multiple -patterns options is not permitted");
2349 if (i + 1 >= a->argc)
2350 return errorArgument("Missing argument to '%s'", a->argv[i]);
2351 pszPattern = a->argv[++i];
2352 }
2353 else if (!strcmp(a->argv[i], "-descriptions"))
2354 fWithDescriptions = true;
2355 /* add: -file <filename> and -formatted */
2356 else if (!strcmp(a->argv[i], "-reset"))
2357 fReset = true;
2358 else
2359 return errorSyntax(USAGE_VM_STATISTICS, "Unknown option '%s'", a->argv[i]);
2360 }
2361 if (fReset && fWithDescriptions)
2362 return errorSyntax(USAGE_VM_STATISTICS, "The -reset and -descriptions options does not mix");
2363
2364
2365 /* open an existing session for the VM. */
2366 CHECK_ERROR(a->virtualBox, OpenExistingSession(a->session, uuid));
2367 if (SUCCEEDED(rc))
2368 {
2369 /* get the session console. */
2370 ComPtr <IConsole> console;
2371 CHECK_ERROR(a->session, COMGETTER(Console)(console.asOutParam()));
2372 if (SUCCEEDED(rc))
2373 {
2374 /* get the machine debugger. */
2375 ComPtr <IMachineDebugger> debugger;
2376 CHECK_ERROR(console, COMGETTER(Debugger)(debugger.asOutParam()));
2377 if (SUCCEEDED(rc))
2378 {
2379 if (fReset)
2380 CHECK_ERROR(debugger, ResetStats(Bstr(pszPattern)));
2381 else
2382 {
2383 Bstr stats;
2384 CHECK_ERROR(debugger, GetStats(Bstr(pszPattern), fWithDescriptions, stats.asOutParam()));
2385 if (SUCCEEDED(rc))
2386 {
2387 /* if (fFormatted)
2388 { big mess }
2389 else
2390 */
2391 RTPrintf("%ls\n", stats.raw());
2392 }
2393 }
2394 }
2395 a->session->Close();
2396 }
2397 }
2398
2399 return SUCCEEDED(rc) ? 0 : 1;
2400}
2401#endif /* !VBOX_ONLY_DOCS */
2402
2403enum ConvertSettings
2404{
2405 ConvertSettings_No = 0,
2406 ConvertSettings_Yes = 1,
2407 ConvertSettings_Backup = 2,
2408 ConvertSettings_Ignore = 3,
2409};
2410
2411#ifndef VBOX_ONLY_DOCS
2412/**
2413 * Checks if any of the settings files were auto-converted and informs the
2414 * user if so.
2415 *
2416 * @return @false if the program should terminate and @true otherwise.
2417 */
2418static bool checkForAutoConvertedSettings (ComPtr<IVirtualBox> virtualBox,
2419 ComPtr<ISession> session,
2420 ConvertSettings fConvertSettings)
2421{
2422 /* return early if nothing to do */
2423 if (fConvertSettings == ConvertSettings_Ignore)
2424 return true;
2425
2426 HRESULT rc;
2427
2428 do
2429 {
2430 Bstr formatVersion;
2431 CHECK_ERROR_BREAK(virtualBox, COMGETTER(SettingsFormatVersion) (formatVersion.asOutParam()));
2432
2433 bool isGlobalConverted = false;
2434 std::list <ComPtr <IMachine> > cvtMachines;
2435 std::list <Utf8Str> fileList;
2436 Bstr version;
2437 Bstr filePath;
2438
2439 com::SafeIfaceArray <IMachine> machines;
2440 CHECK_ERROR_BREAK(virtualBox, COMGETTER(Machines2) (ComSafeArrayAsOutParam (machines)));
2441
2442 for (size_t i = 0; i < machines.size(); ++ i)
2443 {
2444 BOOL accessible;
2445 CHECK_ERROR_BREAK(machines[i], COMGETTER(Accessible) (&accessible));
2446 if (!accessible)
2447 continue;
2448
2449 CHECK_ERROR_BREAK(machines[i], COMGETTER(SettingsFileVersion) (version.asOutParam()));
2450
2451 if (version != formatVersion)
2452 {
2453 cvtMachines.push_back (machines [i]);
2454 Bstr filePath;
2455 CHECK_ERROR_BREAK(machines[i], COMGETTER(SettingsFilePath) (filePath.asOutParam()));
2456 fileList.push_back (Utf8StrFmt ("%ls (%ls)", filePath.raw(),
2457 version.raw()));
2458 }
2459 }
2460
2461 if (FAILED(rc))
2462 break;
2463
2464 CHECK_ERROR_BREAK(virtualBox, COMGETTER(SettingsFileVersion) (version.asOutParam()));
2465 if (version != formatVersion)
2466 {
2467 isGlobalConverted = true;
2468 CHECK_ERROR_BREAK(virtualBox, COMGETTER(SettingsFilePath) (filePath.asOutParam()));
2469 fileList.push_back (Utf8StrFmt ("%ls (%ls)", filePath.raw(),
2470 version.raw()));
2471 }
2472
2473 if (fileList.size() > 0)
2474 {
2475 switch (fConvertSettings)
2476 {
2477 case ConvertSettings_No:
2478 {
2479 RTPrintf (
2480"WARNING! The following VirtualBox settings files have been automatically\n"
2481"converted to the new settings file format version '%ls':\n"
2482"\n",
2483 formatVersion.raw());
2484
2485 for (std::list <Utf8Str>::const_iterator f = fileList.begin();
2486 f != fileList.end(); ++ f)
2487 RTPrintf (" %S\n", (*f).raw());
2488 RTPrintf (
2489"\n"
2490"The current command was aborted to prevent overwriting the above settings\n"
2491"files with the results of the auto-conversion without your permission.\n"
2492"Please put one of the following command line switches to the beginning of\n"
2493"the VBoxManage command line and repeat the command:\n"
2494"\n"
2495" -convertSettings - to save all auto-converted files (it will not\n"
2496" be possible to use these settings files with an\n"
2497" older version of VirtualBox in the future);\n"
2498" -convertSettingsBackup - to create backup copies of the settings files in\n"
2499" the old format before saving them in the new format;\n"
2500" -convertSettingsIgnore - to not save the auto-converted settings files.\n"
2501"\n"
2502"Note that if you use -convertSettingsIgnore, the auto-converted settings files\n"
2503"will be implicitly saved in the new format anyway once you change a setting or\n"
2504"start a virtual machine, but NO backup copies will be created in this case.\n");
2505 return false;
2506 }
2507 case ConvertSettings_Yes:
2508 case ConvertSettings_Backup:
2509 {
2510 break;
2511 }
2512 default:
2513 AssertFailedReturn (false);
2514 }
2515
2516 for (std::list <ComPtr <IMachine> >::const_iterator m = cvtMachines.begin();
2517 m != cvtMachines.end(); ++ m)
2518 {
2519 Guid id;
2520 CHECK_ERROR_BREAK((*m), COMGETTER(Id) (id.asOutParam()));
2521
2522 /* open a session for the VM */
2523 CHECK_ERROR_BREAK (virtualBox, OpenSession (session, id));
2524
2525 ComPtr <IMachine> sm;
2526 CHECK_ERROR_BREAK(session, COMGETTER(Machine) (sm.asOutParam()));
2527
2528 Bstr bakFileName;
2529 if (fConvertSettings == ConvertSettings_Backup)
2530 CHECK_ERROR (sm, SaveSettingsWithBackup (bakFileName.asOutParam()));
2531 else
2532 CHECK_ERROR (sm, SaveSettings());
2533
2534 session->Close();
2535
2536 if (FAILED(rc))
2537 break;
2538 }
2539
2540 if (FAILED(rc))
2541 break;
2542
2543 if (isGlobalConverted)
2544 {
2545 Bstr bakFileName;
2546 if (fConvertSettings == ConvertSettings_Backup)
2547 CHECK_ERROR (virtualBox, SaveSettingsWithBackup (bakFileName.asOutParam()));
2548 else
2549 CHECK_ERROR (virtualBox, SaveSettings());
2550 }
2551
2552 if (FAILED(rc))
2553 break;
2554 }
2555 }
2556 while (0);
2557
2558 return SUCCEEDED (rc);
2559}
2560#endif /* !VBOX_ONLY_DOCS */
2561
2562// main
2563///////////////////////////////////////////////////////////////////////////////
2564
2565int main(int argc, char *argv[])
2566{
2567 /*
2568 * Before we do anything, init the runtime without loading
2569 * the support driver.
2570 */
2571 RTR3Init();
2572
2573 bool fShowLogo = true;
2574 int iCmd = 1;
2575 int iCmdArg;
2576
2577 ConvertSettings fConvertSettings = ConvertSettings_No;
2578
2579 /* global options */
2580 for (int i = 1; i < argc || argc <= iCmd; i++)
2581 {
2582 if ( argc <= iCmd
2583 || (strcmp(argv[i], "help") == 0)
2584 || (strcmp(argv[i], "-?") == 0)
2585 || (strcmp(argv[i], "-h") == 0)
2586 || (strcmp(argv[i], "-help") == 0)
2587 || (strcmp(argv[i], "--help") == 0))
2588 {
2589 showLogo();
2590 printUsage(USAGE_ALL);
2591 return 0;
2592 }
2593 else if ( strcmp(argv[i], "-v") == 0
2594 || strcmp(argv[i], "-version") == 0
2595 || strcmp(argv[i], "-Version") == 0
2596 || strcmp(argv[i], "--version") == 0)
2597 {
2598 /* Print version number, and do nothing else. */
2599 RTPrintf("%sr%d\n", VBOX_VERSION_STRING, VBoxSVNRev ());
2600 return 0;
2601 }
2602 else if (strcmp(argv[i], "-dumpopts") == 0)
2603 {
2604 /* Special option to dump really all commands,
2605 * even the ones not understood on this platform. */
2606 printUsage(USAGE_DUMPOPTS);
2607 return 0;
2608 }
2609 else if (strcmp(argv[i], "-nologo") == 0)
2610 {
2611 /* suppress the logo */
2612 fShowLogo = false;
2613 iCmd++;
2614 }
2615 else if (strcmp(argv[i], "-convertSettings") == 0)
2616 {
2617 fConvertSettings = ConvertSettings_Yes;
2618 iCmd++;
2619 }
2620 else if (strcmp(argv[i], "-convertSettingsBackup") == 0)
2621 {
2622 fConvertSettings = ConvertSettings_Backup;
2623 iCmd++;
2624 }
2625 else if (strcmp(argv[i], "-convertSettingsIgnore") == 0)
2626 {
2627 fConvertSettings = ConvertSettings_Ignore;
2628 iCmd++;
2629 }
2630 else
2631 {
2632 break;
2633 }
2634 }
2635
2636 iCmdArg = iCmd + 1;
2637
2638 if (fShowLogo)
2639 showLogo();
2640
2641
2642#ifdef VBOX_ONLY_DOCS
2643 int rc = 0;
2644#else /* !VBOX_ONLY_DOCS */
2645 HRESULT rc = 0;
2646
2647 rc = com::Initialize();
2648 if (FAILED(rc))
2649 {
2650 RTPrintf("ERROR: failed to initialize COM!\n");
2651 return rc;
2652 }
2653
2654 /*
2655 * The input is in the host OS'es codepage (NT guarantees ACP).
2656 * For VBox we use UTF-8 and convert to UCS-2 when calling (XP)COM APIs.
2657 * For simplicity, just convert the argv[] array here.
2658 */
2659 for (int i = iCmdArg; i < argc; i++)
2660 {
2661 char *converted;
2662 RTStrCurrentCPToUtf8(&converted, argv[i]);
2663 argv[i] = converted;
2664 }
2665
2666 do
2667 {
2668 // scopes all the stuff till shutdown
2669 ////////////////////////////////////////////////////////////////////////////
2670
2671 /* convertfromraw: does not need a VirtualBox instantiation. */
2672 if (argc >= iCmdArg && ( !strcmp(argv[iCmd], "convertfromraw")
2673 || !strcmp(argv[iCmd], "convertdd")))
2674 {
2675 rc = handleConvertFromRaw(argc - iCmdArg, argv + iCmdArg);
2676 break;
2677 }
2678
2679 ComPtr<IVirtualBox> virtualBox;
2680 ComPtr<ISession> session;
2681
2682 rc = virtualBox.createLocalObject(CLSID_VirtualBox);
2683 if (FAILED(rc))
2684 RTPrintf("ERROR: failed to create the VirtualBox object!\n");
2685 else
2686 {
2687 rc = session.createInprocObject(CLSID_Session);
2688 if (FAILED(rc))
2689 RTPrintf("ERROR: failed to create a session object!\n");
2690 }
2691
2692 if (FAILED(rc))
2693 {
2694 com::ErrorInfo info;
2695 if (!info.isFullAvailable() && !info.isBasicAvailable())
2696 {
2697 com::GluePrintRCMessage(rc);
2698 RTPrintf("Most likely, the VirtualBox COM server is not running or failed to start.\n");
2699 }
2700 else
2701 GluePrintErrorInfo(info);
2702 break;
2703 }
2704
2705 /* create the event queue
2706 * (here it is necessary only to process remaining XPCOM/IPC events
2707 * after the session is closed) */
2708
2709#ifdef USE_XPCOM_QUEUE
2710 nsCOMPtr<nsIEventQueue> eventQ;
2711 NS_GetMainEventQ(getter_AddRefs(eventQ));
2712#endif
2713
2714 if (!checkForAutoConvertedSettings (virtualBox, session, fConvertSettings))
2715 break;
2716
2717#ifdef USE_XPCOM_QUEUE
2718 HandlerArg handlerArg = { 0, NULL, eventQ, virtualBox, session };
2719#else
2720 HandlerArg handlerArg = { 0, NULL, virtualBox, session };
2721#endif
2722
2723 /*
2724 * All registered command handlers
2725 */
2726 struct
2727 {
2728 const char *command;
2729 PFNHANDLER handler;
2730 } commandHandlers[] =
2731 {
2732 { "internalcommands", handleInternalCommands },
2733 { "list", handleList },
2734 { "showvminfo", handleShowVMInfo },
2735 { "registervm", handleRegisterVM },
2736 { "unregistervm", handleUnregisterVM },
2737 { "createhd", handleCreateHardDisk },
2738 { "createvdi", handleCreateHardDisk }, /* backward compatiblity */
2739 { "modifyhd", handleModifyHardDisk },
2740 { "modifyvdi", handleModifyHardDisk }, /* backward compatiblity */
2741 { "clonehd", handleCloneHardDisk },
2742 { "clonevdi", handleCloneHardDisk }, /* backward compatiblity */
2743 { "addiscsidisk", handleAddiSCSIDisk },
2744 { "createvm", handleCreateVM },
2745 { "modifyvm", handleModifyVM },
2746 { "startvm", handleStartVM },
2747 { "controlvm", handleControlVM },
2748 { "discardstate", handleDiscardState },
2749 { "adoptstate", handleAdoptdState },
2750 { "snapshot", handleSnapshot },
2751 { "openmedium", handleOpenMedium },
2752 { "registerimage", handleOpenMedium }, /* backward compatiblity */
2753 { "closemedium", handleCloseMedium },
2754 { "unregisterimage", handleCloseMedium }, /* backward compatiblity */
2755 { "showhdinfo", handleShowHardDiskInfo },
2756 { "showvdiinfo", handleShowHardDiskInfo }, /* backward compatiblity */
2757 { "getextradata", handleGetExtraData },
2758 { "setextradata", handleSetExtraData },
2759 { "setproperty", handleSetProperty },
2760 { "usbfilter", handleUSBFilter },
2761 { "sharedfolder", handleSharedFolder },
2762 { "vmstatistics", handleVMStatistics },
2763#ifdef VBOX_WITH_GUEST_PROPS
2764 { "guestproperty", handleGuestProperty },
2765#endif /* VBOX_WITH_GUEST_PROPS defined */
2766 { "metrics", handleMetrics },
2767 { "import", handleImportAppliance },
2768 { "export", handleExportAppliance },
2769 { NULL, NULL }
2770 };
2771
2772 int commandIndex;
2773 for (commandIndex = 0; commandHandlers[commandIndex].command != NULL; commandIndex++)
2774 {
2775 if (strcmp(commandHandlers[commandIndex].command, argv[iCmd]) == 0)
2776 {
2777 handlerArg.argc = argc - iCmdArg;
2778 handlerArg.argv = &argv[iCmdArg];
2779
2780 rc = commandHandlers[commandIndex].handler(&handlerArg);
2781 break;
2782 }
2783 }
2784 if (!commandHandlers[commandIndex].command)
2785 {
2786 rc = errorSyntax(USAGE_ALL, "Invalid command '%s'", Utf8Str(argv[iCmd]).raw());
2787 }
2788
2789 /* Although all handlers should always close the session if they open it,
2790 * we do it here just in case if some of the handlers contains a bug --
2791 * leaving the direct session not closed will turn the machine state to
2792 * Aborted which may have unwanted side effects like killing the saved
2793 * state file (if the machine was in the Saved state before). */
2794 session->Close();
2795
2796#ifdef USE_XPCOM_QUEUE
2797 eventQ->ProcessPendingEvents();
2798#endif
2799
2800 // end "all-stuff" scope
2801 ////////////////////////////////////////////////////////////////////////////
2802 }
2803 while (0);
2804
2805 com::Shutdown();
2806#endif /* !VBOX_ONLY_DOCS */
2807
2808 /*
2809 * Free converted argument vector
2810 */
2811 for (int i = iCmdArg; i < argc; i++)
2812 RTStrFree(argv[i]);
2813
2814 return rc != 0;
2815}
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