VirtualBox

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

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

VBoxManage: split out modifyvm into separate file, add import command (to be implemented)

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