VirtualBox

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

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

VBoxManage: more compact command line help

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

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