VirtualBox

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

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

#2954 & #3569: Linux TAP driver is embedded to vboxnetflt. API, VBoxManage and VirtualBox now provide host-only network attachment on Linux.

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

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