VirtualBox

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

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

OVF: prototypes for export.

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

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