VirtualBox

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

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

VBoxManage: started splitting it up.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 215.3 KB
Line 
1/* $Id: VBoxManage.cpp 14555 2008-11-25 09:08:06Z vboxsync $ */
2/** @file
3 * VBoxManage - VirtualBox's command-line interface.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#ifndef VBOX_ONLY_DOCS
27#include <VBox/com/com.h>
28#include <VBox/com/string.h>
29#include <VBox/com/Guid.h>
30#include <VBox/com/array.h>
31#include <VBox/com/ErrorInfo.h>
32#include <VBox/com/EventQueue.h>
33
34#include <VBox/com/VirtualBox.h>
35
36#include <stdlib.h>
37#include <stdarg.h>
38
39#include <vector>
40#include <list>
41#endif /* !VBOX_ONLY_DOCS */
42
43#include <iprt/runtime.h>
44#include <iprt/stream.h>
45#include <iprt/string.h>
46#include <iprt/asm.h>
47#include <iprt/uuid.h>
48#include <iprt/thread.h>
49#include <iprt/path.h>
50#include <iprt/param.h>
51#include <iprt/dir.h>
52#include <iprt/file.h>
53#include <iprt/env.h>
54#include <iprt/cidr.h>
55#include <VBox/err.h>
56#include <VBox/version.h>
57#include <VBox/VBoxHDD.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 DECLCALLBACK(int) FNHANDLER(int argc, char *argv[], ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession);
77typedef FNHANDLER *PFNHANDLER;
78
79#ifdef USE_XPCOM_QUEUE
80/** A pointer to the event queue, set by main() before calling any handlers. */
81nsCOMPtr<nsIEventQueue> g_pEventQ;
82#endif
83
84/**
85 * Quick IUSBDevice implementation for detaching / attaching
86 * devices to the USB Controller.
87 */
88class MyUSBDevice : public IUSBDevice
89{
90public:
91 // public initializer/uninitializer for internal purposes only
92 MyUSBDevice(uint16_t a_u16VendorId, uint16_t a_u16ProductId, uint16_t a_bcdRevision, uint64_t a_u64SerialHash, const char *a_pszComment)
93 : m_usVendorId(a_u16VendorId), m_usProductId(a_u16ProductId),
94 m_bcdRevision(a_bcdRevision), m_u64SerialHash(a_u64SerialHash),
95 m_bstrComment(a_pszComment),
96 m_cRefs(0)
97 {
98 }
99
100 STDMETHOD_(ULONG, AddRef)(void)
101 {
102 return ASMAtomicIncU32(&m_cRefs);
103 }
104 STDMETHOD_(ULONG, Release)(void)
105 {
106 ULONG cRefs = ASMAtomicDecU32(&m_cRefs);
107 if (!cRefs)
108 delete this;
109 return cRefs;
110 }
111 STDMETHOD(QueryInterface)(const IID &iid, void **ppvObject)
112 {
113 Guid guid(iid);
114 if (guid == Guid(NS_GET_IID(IUnknown)))
115 *ppvObject = (IUnknown *)this;
116 else if (guid == Guid(NS_GET_IID(IUSBDevice)))
117 *ppvObject = (IUSBDevice *)this;
118 else
119 return E_NOINTERFACE;
120 AddRef();
121 return S_OK;
122 }
123
124 STDMETHOD(COMGETTER(Id))(GUIDPARAMOUT a_pId) { return E_NOTIMPL; }
125 STDMETHOD(COMGETTER(VendorId))(USHORT *a_pusVendorId) { *a_pusVendorId = m_usVendorId; return S_OK; }
126 STDMETHOD(COMGETTER(ProductId))(USHORT *a_pusProductId) { *a_pusProductId = m_usProductId; return S_OK; }
127 STDMETHOD(COMGETTER(Revision))(USHORT *a_pusRevision) { *a_pusRevision = m_bcdRevision; return S_OK; }
128 STDMETHOD(COMGETTER(SerialHash))(ULONG64 *a_pullSerialHash) { *a_pullSerialHash = m_u64SerialHash; return S_OK; }
129 STDMETHOD(COMGETTER(Manufacturer))(BSTR *a_pManufacturer) { return E_NOTIMPL; }
130 STDMETHOD(COMGETTER(Product))(BSTR *a_pProduct) { return E_NOTIMPL; }
131 STDMETHOD(COMGETTER(SerialNumber))(BSTR *a_pSerialNumber) { return E_NOTIMPL; }
132 STDMETHOD(COMGETTER(Address))(BSTR *a_pAddress) { return E_NOTIMPL; }
133
134private:
135 /** The vendor id of this USB device. */
136 USHORT m_usVendorId;
137 /** The product id of this USB device. */
138 USHORT m_usProductId;
139 /** The product revision number of this USB device.
140 * (high byte = integer; low byte = decimal) */
141 USHORT m_bcdRevision;
142 /** The USB serial hash of the device. */
143 uint64_t m_u64SerialHash;
144 /** The user comment string. */
145 Bstr m_bstrComment;
146 /** Reference counter. */
147 uint32_t volatile m_cRefs;
148};
149
150
151// types
152///////////////////////////////////////////////////////////////////////////////
153
154template <typename T>
155class Nullable
156{
157public:
158
159 Nullable() : mIsNull (true) {}
160 Nullable (const T &aValue, bool aIsNull = false)
161 : mIsNull (aIsNull), mValue (aValue) {}
162
163 bool isNull() const { return mIsNull; };
164 void setNull (bool aIsNull = true) { mIsNull = aIsNull; }
165
166 operator const T&() const { return mValue; }
167
168 Nullable &operator= (const T &aValue)
169 {
170 mValue = aValue;
171 mIsNull = false;
172 return *this;
173 }
174
175private:
176
177 bool mIsNull;
178 T mValue;
179};
180
181/** helper structure to encapsulate USB filter manipulation commands */
182struct USBFilterCmd
183{
184 struct USBFilter
185 {
186 USBFilter ()
187 : mAction (USBDeviceFilterAction_Null)
188 {}
189
190 Bstr mName;
191 Nullable <bool> mActive;
192 Bstr mVendorId;
193 Bstr mProductId;
194 Bstr mRevision;
195 Bstr mManufacturer;
196 Bstr mProduct;
197 Bstr mRemote;
198 Bstr mSerialNumber;
199 Nullable <ULONG> mMaskedInterfaces;
200 USBDeviceFilterAction_T mAction;
201 };
202
203 enum Action { Invalid, Add, Modify, Remove };
204
205 USBFilterCmd() : mAction (Invalid), mIndex (0), mGlobal (false) {}
206
207 Action mAction;
208 ULONG mIndex;
209 /** flag whether the command target is a global filter */
210 bool mGlobal;
211 /** machine this command is targeted at (null for global filters) */
212 ComPtr<IMachine> mMachine;
213 USBFilter mFilter;
214};
215#endif /* !VBOX_ONLY_DOCS */
216
217// funcs
218///////////////////////////////////////////////////////////////////////////////
219
220static void showLogo(void)
221{
222 static bool fShown; /* show only once */
223
224 if (!fShown)
225 {
226 RTPrintf("VirtualBox Command Line Management Interface Version "
227 VBOX_VERSION_STRING "\n"
228 "(C) 2005-2008 Sun Microsystems, Inc.\n"
229 "All rights reserved.\n"
230 "\n");
231 fShown = true;
232 }
233}
234
235static void printUsage(USAGECATEGORY u64Cmd)
236{
237#ifdef RT_OS_LINUX
238 bool fLinux = true;
239#else
240 bool fLinux = false;
241#endif
242#ifdef RT_OS_WINDOWS
243 bool fWin = true;
244#else
245 bool fWin = false;
246#endif
247#ifdef RT_OS_SOLARIS
248 bool fSolaris = true;
249#else
250 bool fSolaris = false;
251#endif
252#ifdef RT_OS_DARWIN
253 bool fDarwin = true;
254#else
255 bool fDarwin = false;
256#endif
257#ifdef VBOX_WITH_VRDP
258 bool fVRDP = true;
259#else
260 bool fVRDP = false;
261#endif
262
263 if (u64Cmd == USAGE_DUMPOPTS)
264 {
265 fLinux = true;
266 fWin = true;
267 fSolaris = true;
268 fDarwin = true;
269 fVRDP = true;
270 u64Cmd = USAGE_ALL;
271 }
272
273 RTPrintf("Usage:\n"
274 "\n");
275
276 if (u64Cmd == USAGE_ALL)
277 {
278 RTPrintf("VBoxManage [-v|-version] print version number and exit\n"
279 "VBoxManage -nologo ... suppress the logo\n"
280 "\n"
281 "VBoxManage -convertSettings ... allow to auto-convert settings files\n"
282 "VBoxManage -convertSettingsBackup ... allow to auto-convert settings files\n"
283 " but create backup copies before\n"
284 "VBoxManage -convertSettingsIgnore ... allow to auto-convert settings files\n"
285 " but don't explicitly save the results\n"
286 "\n");
287 }
288
289 if (u64Cmd & USAGE_LIST)
290 {
291 RTPrintf("VBoxManage list vms|runningvms|ostypes|hostdvds|hostfloppies|\n"
292 " hostifs|hostinfo|hddbackends|hdds|dvds|floppies|\n"
293 " usbhost|usbfilters|systemproperties\n"
294 "\n");
295 }
296
297 if (u64Cmd & USAGE_SHOWVMINFO)
298 {
299 RTPrintf("VBoxManage showvminfo <uuid>|<name>\n"
300 " [-details]\n"
301 " [-statistics]\n"
302 " [-machinereadable]\n"
303 "\n");
304 }
305
306 if (u64Cmd & USAGE_REGISTERVM)
307 {
308 RTPrintf("VBoxManage registervm <filename>\n"
309 "\n");
310 }
311
312 if (u64Cmd & USAGE_UNREGISTERVM)
313 {
314 RTPrintf("VBoxManage unregistervm <uuid>|<name>\n"
315 " [-delete]\n"
316 "\n");
317 }
318
319 if (u64Cmd & USAGE_CREATEVM)
320 {
321 RTPrintf("VBoxManage createvm -name <name>\n"
322 " [-register]\n"
323 " [-basefolder <path> | -settingsfile <path>]\n"
324 " [-uuid <uuid>]\n"
325 " \n"
326 "\n");
327 }
328
329 if (u64Cmd & USAGE_MODIFYVM)
330 {
331 RTPrintf("VBoxManage modifyvm <uuid|name>\n"
332 " [-name <name>]\n"
333 " [-ostype <ostype>]\n"
334 " [-memory <memorysize>]\n"
335 " [-vram <vramsize>]\n"
336 " [-acpi on|off]\n"
337 " [-ioapic on|off]\n"
338 " [-pae on|off]\n"
339 " [-hwvirtex on|off|default]\n"
340 " [-nestedpaging on|off]\n"
341 " [-vtxvpid on|off]\n"
342 " [-monitorcount <number>]\n"
343 " [-accelerate3d <on|off>]\n"
344 " [-bioslogofadein on|off]\n"
345 " [-bioslogofadeout on|off]\n"
346 " [-bioslogodisplaytime <msec>]\n"
347 " [-bioslogoimagepath <imagepath>]\n"
348 " [-biosbootmenu disabled|menuonly|messageandmenu]\n"
349 " [-biossystemtimeoffset <msec>]\n"
350 " [-biospxedebug on|off]\n"
351 " [-boot<1-4> none|floppy|dvd|disk|net>]\n"
352 " [-hd<a|b|d> none|<uuid>|<filename>]\n"
353 " [-idecontroller PIIX3|PIIX4]\n"
354#ifdef VBOX_WITH_AHCI
355 " [-sata on|off]\n"
356 " [-sataportcount <1-30>]\n"
357 " [-sataport<1-30> none|<uuid>|<filename>]\n"
358 " [-sataideemulation<1-4> <1-30>]\n"
359#endif
360 " [-dvd none|<uuid>|<filename>|host:<drive>]\n"
361 " [-dvdpassthrough on|off]\n"
362 " [-floppy disabled|empty|<uuid>|\n"
363 " <filename>|host:<drive>]\n"
364 " [-nic<1-N> none|null|nat|hostif|intnet]\n"
365 " [-nictype<1-N> Am79C970A|Am79C973"
366#ifdef VBOX_WITH_E1000
367 "|82540EM|82543GC"
368#endif
369 "]\n"
370 " [-cableconnected<1-N> on|off]\n"
371 " [-nictrace<1-N> on|off]\n"
372 " [-nictracefile<1-N> <filename>]\n"
373 " [-nicspeed<1-N> <kbps>]\n"
374 " [-hostifdev<1-N> none|<devicename>]\n"
375 " [-intnet<1-N> <network name>]\n"
376 " [-natnet<1-N> <network>|default]\n"
377 " [-macaddress<1-N> auto|<mac>]\n"
378 " [-uart<1-N> off|<I/O base> <IRQ>]\n"
379 " [-uartmode<1-N> disconnected|\n"
380 " server <pipe>|\n"
381 " client <pipe>|\n"
382 " <devicename>]\n"
383#ifdef VBOX_WITH_MEM_BALLOONING
384 " [-guestmemoryballoon <balloonsize>]\n"
385#endif
386 " [-gueststatisticsinterval <seconds>]\n"
387 );
388 if (fLinux)
389 {
390 RTPrintf(" [-tapsetup<1-N> none|<application>]\n"
391 " [-tapterminate<1-N> none|<application>]\n");
392 }
393 RTPrintf(" [-audio none|null");
394 if (fWin)
395 {
396#ifdef VBOX_WITH_WINMM
397 RTPrintf( "|winmm|dsound");
398#else
399 RTPrintf( "|dsound");
400#endif
401 }
402 if (fSolaris)
403 {
404 RTPrintf( "|solaudio");
405 }
406 if (fLinux)
407 {
408 RTPrintf( "|oss"
409#ifdef VBOX_WITH_ALSA
410 "|alsa"
411#endif
412#ifdef VBOX_WITH_PULSE
413 "|pulse"
414#endif
415 );
416 }
417 if (fDarwin)
418 {
419 RTPrintf( "|coreaudio");
420 }
421 RTPrintf( "]\n");
422 RTPrintf(" [-audiocontroller ac97|sb16]\n"
423 " [-clipboard disabled|hosttoguest|guesttohost|\n"
424 " bidirectional]\n");
425 if (fVRDP)
426 {
427 RTPrintf(" [-vrdp on|off]\n"
428 " [-vrdpport default|<port>]\n"
429 " [-vrdpaddress <host>]\n"
430 " [-vrdpauthtype null|external|guest]\n"
431 " [-vrdpmulticon on|off]\n"
432 " [-vrdpreusecon on|off]\n");
433 }
434 RTPrintf(" [-usb on|off]\n"
435 " [-usbehci on|off]\n"
436 " [-snapshotfolder default|<path>]\n");
437 RTPrintf("\n");
438 }
439
440 if (u64Cmd & USAGE_STARTVM)
441 {
442 RTPrintf("VBoxManage startvm <uuid>|<name>\n");
443 if (fVRDP)
444 RTPrintf(" [-type gui|vrdp]\n");
445 RTPrintf("\n");
446 }
447
448 if (u64Cmd & USAGE_CONTROLVM)
449 {
450 RTPrintf("VBoxManage controlvm <uuid>|<name>\n"
451 " pause|resume|reset|poweroff|savestate|\n"
452 " acpipowerbutton|acpisleepbutton|\n"
453 " keyboardputscancode <hex> [<hex> ...]|\n"
454 " injectnmi|\n"
455 " setlinkstate<1-4> on|off |\n"
456 " usbattach <uuid>|<address> |\n"
457 " usbdetach <uuid>|<address> |\n"
458 " dvdattach none|<uuid>|<filename>|host:<drive> |\n"
459 " floppyattach none|<uuid>|<filename>|host:<drive> |\n"
460 " 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 " [-static]\n"
516 " [-comment <comment>]\n"
517 " [-register]\n"
518 " [-type normal|writethrough] (default: normal)\n"
519 "\n");
520 }
521
522 if (u64Cmd & USAGE_MODIFYHD)
523 {
524 RTPrintf("VBoxManage modifyhd <uuid>|<filename>\n"
525 " settype normal|writethrough|immutable |\n"
526 " compact\n"
527 "\n");
528 }
529
530 if (u64Cmd & USAGE_CLONEHD)
531 {
532 RTPrintf("VBoxManage clonehd <uuid>|<filename> <outputfile>\n"
533 "\n");
534 }
535
536 if (u64Cmd & USAGE_CONVERTDD)
537 {
538 RTPrintf("VBoxManage convertdd [-static] <filename> <outputfile>\n"
539 "VBoxManage convertdd [-static] stdin <outputfile> <bytes>\n"
540 "\n");
541 }
542
543 if (u64Cmd & USAGE_ADDISCSIDISK)
544 {
545 RTPrintf("VBoxManage addiscsidisk -server <name>|<ip>\n"
546 " -target <target>\n"
547 " [-port <port>]\n"
548 " [-lun <lun>]\n"
549 " [-encodedlun <lun>]\n"
550 " [-username <username>]\n"
551 " [-password <password>]\n"
552 " [-comment <comment>]\n"
553 "\n");
554 }
555
556 if (u64Cmd & USAGE_CREATEHOSTIF && fWin)
557 {
558 RTPrintf("VBoxManage createhostif <name>\n"
559 "\n");
560 }
561
562 if (u64Cmd & USAGE_REMOVEHOSTIF && fWin)
563 {
564 RTPrintf("VBoxManage removehostif <uuid>|<name>\n"
565 "\n");
566 }
567
568 if (u64Cmd & USAGE_GETEXTRADATA)
569 {
570 RTPrintf("VBoxManage getextradata global|<uuid>|<name>\n"
571 " <key>|enumerate\n"
572 "\n");
573 }
574
575 if (u64Cmd & USAGE_SETEXTRADATA)
576 {
577 RTPrintf("VBoxManage setextradata global|<uuid>|<name>\n"
578 " <key>\n"
579 " [<value>] (no value deletes key)\n"
580 "\n");
581 }
582
583 if (u64Cmd & USAGE_SETPROPERTY)
584 {
585 RTPrintf("VBoxManage setproperty hdfolder default|<folder> |\n"
586 " machinefolder default|<folder> |\n"
587 " vrdpauthlibrary default|<library> |\n"
588 " websrvauthlibrary default|null|<library> |\n"
589 " hwvirtexenabled yes|no\n"
590 " loghistorycount <value>\n"
591 "\n");
592 }
593
594 if (u64Cmd & USAGE_USBFILTER_ADD)
595 {
596 RTPrintf("VBoxManage usbfilter add <index,0-N>\n"
597 " -target <uuid>|<name>|global\n"
598 " -name <string>\n"
599 " -action ignore|hold (global filters only)\n"
600 " [-active yes|no] (yes)\n"
601 " [-vendorid <XXXX>] (null)\n"
602 " [-productid <XXXX>] (null)\n"
603 " [-revision <IIFF>] (null)\n"
604 " [-manufacturer <string>] (null)\n"
605 " [-product <string>] (null)\n"
606 " [-remote yes|no] (null, VM filters only)\n"
607 " [-serialnumber <string>] (null)\n"
608 " [-maskedinterfaces <XXXXXXXX>]\n"
609 "\n");
610 }
611
612 if (u64Cmd & USAGE_USBFILTER_MODIFY)
613 {
614 RTPrintf("VBoxManage usbfilter modify <index,0-N>\n"
615 " -target <uuid>|<name>|global\n"
616 " [-name <string>]\n"
617 " [-action ignore|hold] (global filters only)\n"
618 " [-active yes|no]\n"
619 " [-vendorid <XXXX>|\"\"]\n"
620 " [-productid <XXXX>|\"\"]\n"
621 " [-revision <IIFF>|\"\"]\n"
622 " [-manufacturer <string>|\"\"]\n"
623 " [-product <string>|\"\"]\n"
624 " [-remote yes|no] (null, VM filters only)\n"
625 " [-serialnumber <string>|\"\"]\n"
626 " [-maskedinterfaces <XXXXXXXX>]\n"
627 "\n");
628 }
629
630 if (u64Cmd & USAGE_USBFILTER_REMOVE)
631 {
632 RTPrintf("VBoxManage usbfilter remove <index,0-N>\n"
633 " -target <uuid>|<name>|global\n"
634 "\n");
635 }
636
637 if (u64Cmd & USAGE_SHAREDFOLDER_ADD)
638 {
639 RTPrintf("VBoxManage sharedfolder add <vmname>|<uuid>\n"
640 " -name <name> -hostpath <hostpath>\n"
641 " [-transient] [-readonly]\n"
642 "\n");
643 }
644
645 if (u64Cmd & USAGE_SHAREDFOLDER_REMOVE)
646 {
647 RTPrintf("VBoxManage sharedfolder remove <vmname>|<uuid>\n"
648 " -name <name> [-transient]\n"
649 "\n");
650 }
651
652 if (u64Cmd & USAGE_VM_STATISTICS)
653 {
654 RTPrintf("VBoxManage vmstatistics <vmname>|<uuid> [-reset]\n"
655 " [-pattern <pattern>] [-descriptions]\n"
656 "\n");
657 }
658
659#ifdef VBOX_WITH_GUEST_PROPS
660 if (u64Cmd & USAGE_GUESTPROPERTY)
661 usageGuestProperty();
662#endif /* VBOX_WITH_GUEST_PROPS defined */
663
664 if (u64Cmd & USAGE_METRICS)
665 {
666 RTPrintf("VBoxManage metrics list [*|host|<vmname> [<metric_list>]] (comma-separated)\n\n"
667 "VBoxManage metrics setup\n"
668 " [-period <seconds>]\n"
669 " [-samples <count>]\n"
670 " [-list]\n"
671 " [*|host|<vmname> [<metric_list>]]\n\n"
672 "VBoxManage metrics query [*|host|<vmname> [<metric_list>]]\n\n"
673 "VBoxManage metrics collect\n"
674 " [-period <seconds>]\n"
675 " [-samples <count>]\n"
676 " [-list]\n"
677 " [-detach]\n"
678 " [*|host|<vmname> [<metric_list>]]\n"
679 "\n");
680 }
681
682}
683
684/**
685 * Print a usage synopsis and the syntax error message.
686 */
687int errorSyntax(USAGECATEGORY u64Cmd, const char *pszFormat, ...)
688{
689 va_list args;
690 showLogo(); // show logo even if suppressed
691#ifndef VBOX_ONLY_DOCS
692 if (g_fInternalMode)
693 printUsageInternal(u64Cmd);
694 else
695 printUsage(u64Cmd);
696#endif /* !VBOX_ONLY_DOCS */
697 va_start(args, pszFormat);
698 RTPrintf("\n"
699 "Syntax error: %N\n", pszFormat, &args);
700 va_end(args);
701 return 1;
702}
703
704/**
705 * Print an error message without the syntax stuff.
706 */
707int errorArgument(const char *pszFormat, ...)
708{
709 va_list args;
710 va_start(args, pszFormat);
711 RTPrintf("error: %N\n", pszFormat, &args);
712 va_end(args);
713 return 1;
714}
715
716#ifndef VBOX_ONLY_DOCS
717/**
718 * Print out progress on the console
719 */
720static void showProgress(ComPtr<IProgress> progress)
721{
722 BOOL fCompleted;
723 LONG currentPercent;
724 LONG lastPercent = 0;
725
726 RTPrintf("0%%...");
727 RTStrmFlush(g_pStdOut);
728 while (SUCCEEDED(progress->COMGETTER(Completed(&fCompleted))))
729 {
730 progress->COMGETTER(Percent(&currentPercent));
731
732 /* did we cross a 10% mark? */
733 if (((currentPercent / 10) > (lastPercent / 10)))
734 {
735 /* make sure to also print out missed steps */
736 for (LONG curVal = (lastPercent / 10) * 10 + 10; curVal <= (currentPercent / 10) * 10; curVal += 10)
737 {
738 if (curVal < 100)
739 {
740 RTPrintf("%ld%%...", curVal);
741 RTStrmFlush(g_pStdOut);
742 }
743 }
744 lastPercent = (currentPercent / 10) * 10;
745 }
746 if (fCompleted)
747 break;
748
749 /* make sure the loop is not too tight */
750 progress->WaitForCompletion(100);
751 }
752
753 /* complete the line. */
754 HRESULT rc;
755 if (SUCCEEDED(progress->COMGETTER(ResultCode)(&rc)))
756 {
757 if (SUCCEEDED(rc))
758 RTPrintf("100%%\n");
759 else
760 RTPrintf("FAILED\n");
761 }
762 else
763 RTPrintf("\n");
764 RTStrmFlush(g_pStdOut);
765}
766
767static int handleRegisterVM(int argc, char *argv[],
768 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
769{
770 HRESULT rc;
771
772 if (argc != 1)
773 return errorSyntax(USAGE_REGISTERVM, "Incorrect number of parameters");
774
775 ComPtr<IMachine> machine;
776 CHECK_ERROR(virtualBox, OpenMachine(Bstr(argv[0]), machine.asOutParam()));
777 if (SUCCEEDED(rc))
778 {
779 ASSERT(machine);
780 CHECK_ERROR(virtualBox, RegisterMachine(machine));
781 }
782 return SUCCEEDED(rc) ? 0 : 1;
783}
784
785static int handleUnregisterVM(int argc, char *argv[],
786 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
787{
788 HRESULT rc;
789
790 if ((argc != 1) && (argc != 2))
791 return errorSyntax(USAGE_UNREGISTERVM, "Incorrect number of parameters");
792
793 ComPtr<IMachine> machine;
794 /* assume it's a UUID */
795 rc = virtualBox->GetMachine(Guid(argv[0]), machine.asOutParam());
796 if (FAILED(rc) || !machine)
797 {
798 /* must be a name */
799 CHECK_ERROR(virtualBox, FindMachine(Bstr(argv[0]), machine.asOutParam()));
800 }
801 if (machine)
802 {
803 Guid uuid;
804 machine->COMGETTER(Id)(uuid.asOutParam());
805 machine = NULL;
806 CHECK_ERROR(virtualBox, UnregisterMachine(uuid, machine.asOutParam()));
807 if (SUCCEEDED(rc) && machine)
808 {
809 /* are we supposed to delete the config file? */
810 if ((argc == 2) && (strcmp(argv[1], "-delete") == 0))
811 {
812 CHECK_ERROR(machine, DeleteSettings());
813 }
814 }
815 }
816 return SUCCEEDED(rc) ? 0 : 1;
817}
818
819static int handleCreateHardDisk(int argc, char *argv[],
820 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
821{
822 HRESULT rc;
823 Bstr filename;
824 uint64_t sizeMB = 0;
825 bool fStatic = false;
826 Bstr comment;
827 bool fRegister = false;
828 const char *type = "normal";
829
830 /* let's have a closer look at the arguments */
831 for (int i = 0; i < argc; i++)
832 {
833 if (strcmp(argv[i], "-filename") == 0)
834 {
835 if (argc <= i + 1)
836 return errorArgument("Missing argument to '%s'", argv[i]);
837 i++;
838 filename = argv[i];
839 }
840 else if (strcmp(argv[i], "-size") == 0)
841 {
842 if (argc <= i + 1)
843 return errorArgument("Missing argument to '%s'", argv[i]);
844 i++;
845 sizeMB = RTStrToUInt64(argv[i]);
846 }
847 else if (strcmp(argv[i], "-static") == 0)
848 {
849 fStatic = true;
850 }
851 else if (strcmp(argv[i], "-comment") == 0)
852 {
853 if (argc <= i + 1)
854 return errorArgument("Missing argument to '%s'", argv[i]);
855 i++;
856 comment = argv[i];
857 }
858 else if (strcmp(argv[i], "-register") == 0)
859 {
860 fRegister = true;
861 }
862 else if (strcmp(argv[i], "-type") == 0)
863 {
864 if (argc <= i + 1)
865 return errorArgument("Missing argument to '%s'", argv[i]);
866 i++;
867 type = argv[i];
868 }
869 else
870 return errorSyntax(USAGE_CREATEHD, "Invalid parameter '%s'", Utf8Str(argv[i]).raw());
871 }
872 /* check the outcome */
873 if (!filename || (sizeMB == 0))
874 return errorSyntax(USAGE_CREATEHD, "Parameters -filename and -size are required");
875
876 if (strcmp(type, "normal") && strcmp(type, "writethrough"))
877 return errorArgument("Invalid hard disk type '%s' specified", Utf8Str(type).raw());
878
879 ComPtr<IHardDisk2> hardDisk;
880 CHECK_ERROR(virtualBox, CreateHardDisk2(Bstr("VDI"), filename, hardDisk.asOutParam()));
881 if (SUCCEEDED(rc) && hardDisk)
882 {
883 /* we will close the hard disk after the storage has been successfully
884 * created unless fRegister is set */
885 bool doClose = false;
886
887 CHECK_ERROR(hardDisk,COMSETTER(Description)(comment));
888 ComPtr<IProgress> progress;
889 if (fStatic)
890 {
891 CHECK_ERROR(hardDisk, CreateFixedStorage(sizeMB, progress.asOutParam()));
892 }
893 else
894 {
895 CHECK_ERROR(hardDisk, CreateDynamicStorage(sizeMB, progress.asOutParam()));
896 }
897 if (SUCCEEDED(rc) && progress)
898 {
899 if (fStatic)
900 showProgress(progress);
901 else
902 CHECK_ERROR(progress, WaitForCompletion(-1));
903 if (SUCCEEDED(rc))
904 {
905 progress->COMGETTER(ResultCode)(&rc);
906 if (FAILED(rc))
907 {
908 com::ProgressErrorInfo info(progress);
909 if (info.isBasicAvailable())
910 RTPrintf("Error: failed to create hard disk. Error message: %lS\n", info.getText().raw());
911 else
912 RTPrintf("Error: failed to create hard disk. No error message available!\n");
913 }
914 else
915 {
916 doClose = !fRegister;
917
918 Guid uuid;
919 CHECK_ERROR(hardDisk, COMGETTER(Id)(uuid.asOutParam()));
920
921 if (strcmp(type, "normal") == 0)
922 {
923 /* nothing required, default */
924 }
925 else if (strcmp(type, "writethrough") == 0)
926 {
927 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Writethrough));
928 }
929
930 RTPrintf("Disk image created. UUID: %s\n", uuid.toString().raw());
931 }
932 }
933 }
934 if (doClose)
935 {
936 CHECK_ERROR(hardDisk, Close());
937 }
938 }
939 return SUCCEEDED(rc) ? 0 : 1;
940}
941
942static DECLCALLBACK(int) hardDiskProgressCallback(PVM pVM, unsigned uPercent, void *pvUser)
943{
944 unsigned *pPercent = (unsigned *)pvUser;
945
946 if (*pPercent != uPercent)
947 {
948 *pPercent = uPercent;
949 RTPrintf(".");
950 if ((uPercent % 10) == 0 && uPercent)
951 RTPrintf("%d%%", uPercent);
952 RTStrmFlush(g_pStdOut);
953 }
954
955 return VINF_SUCCESS;
956}
957
958
959static int handleModifyHardDisk(int argc, char *argv[],
960 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
961{
962 HRESULT rc;
963
964 /* The uuid/filename and a command */
965 if (argc < 2)
966 return errorSyntax(USAGE_MODIFYHD, "Incorrect number of parameters");
967
968 ComPtr<IHardDisk2> hardDisk;
969 Bstr filepath;
970
971 /* first guess is that it's a UUID */
972 Guid uuid(argv[0]);
973 rc = virtualBox->GetHardDisk2(uuid, hardDisk.asOutParam());
974 /* no? then it must be a filename */
975 if (!hardDisk)
976 {
977 filepath = argv[0];
978 CHECK_ERROR(virtualBox, FindHardDisk2(filepath, hardDisk.asOutParam()));
979 }
980
981 /* let's find out which command */
982 if (strcmp(argv[1], "settype") == 0)
983 {
984 /* hard disk must be registered */
985 if (SUCCEEDED(rc) && hardDisk)
986 {
987 char *type = NULL;
988
989 if (argc <= 2)
990 return errorArgument("Missing argument to for settype");
991
992 type = argv[2];
993
994 HardDiskType_T hddType;
995 CHECK_ERROR(hardDisk, COMGETTER(Type)(&hddType));
996
997 if (strcmp(type, "normal") == 0)
998 {
999 if (hddType != HardDiskType_Normal)
1000 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Normal));
1001 }
1002 else if (strcmp(type, "writethrough") == 0)
1003 {
1004 if (hddType != HardDiskType_Writethrough)
1005 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Writethrough));
1006
1007 }
1008 else if (strcmp(type, "immutable") == 0)
1009 {
1010 if (hddType != HardDiskType_Immutable)
1011 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Immutable));
1012 }
1013 else
1014 {
1015 return errorArgument("Invalid hard disk type '%s' specified", Utf8Str(type).raw());
1016 }
1017 }
1018 else
1019 return errorArgument("Hard disk image not registered");
1020 }
1021 else if (strcmp(argv[1], "compact") == 0)
1022 {
1023 /* the hard disk image might not be registered */
1024 if (!hardDisk)
1025 {
1026 virtualBox->OpenHardDisk2(Bstr(argv[0]), hardDisk.asOutParam());
1027 if (!hardDisk)
1028 return errorArgument("Hard disk image not found");
1029 }
1030
1031 Bstr format;
1032 hardDisk->COMGETTER(Format)(format.asOutParam());
1033 if (format != "VDI")
1034 return errorArgument("Invalid hard disk type. The command only works on VDI files\n");
1035
1036 Bstr fileName;
1037 hardDisk->COMGETTER(Location)(fileName.asOutParam());
1038
1039 /* make sure the object reference is released */
1040 hardDisk = NULL;
1041
1042 unsigned uProcent;
1043
1044 RTPrintf("Shrinking '%lS': 0%%", fileName.raw());
1045 int vrc = VDIShrinkImage(Utf8Str(fileName).raw(), hardDiskProgressCallback, &uProcent);
1046 if (RT_FAILURE(vrc))
1047 {
1048 RTPrintf("Error while shrinking hard disk image: %Rrc\n", vrc);
1049 rc = E_FAIL;
1050 }
1051 }
1052 else
1053 return errorSyntax(USAGE_MODIFYHD, "Invalid parameter '%s'", Utf8Str(argv[1]).raw());
1054
1055 return SUCCEEDED(rc) ? 0 : 1;
1056}
1057
1058static int handleCloneHardDisk(int argc, char *argv[],
1059 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
1060{
1061#if 1
1062 RTPrintf("Error: Clone hard disk operation is temporarily unavailable!\n");
1063 return 1;
1064#else
1065 /// @todo NEWMEDIA use IHardDisk2::cloneTo/flattenTo (not yet implemented)
1066 HRESULT rc;
1067
1068 /* source hard disk and target path */
1069 if (argc != 2)
1070 return errorSyntax(USAGE_CLONEHD, "Incorrect number of parameters");
1071
1072 /* first guess is that it's a UUID */
1073 Guid uuid(argv[0]);
1074 ComPtr<IHardDisk2> hardDisk;
1075 rc = virtualBox->GetHardDisk2(uuid, hardDisk.asOutParam());
1076 if (!hardDisk)
1077 {
1078 /* not successful? Then it must be a filename */
1079 CHECK_ERROR(virtualBox, OpenHardDisk2(Bstr(argv[0]), hardDisk.asOutParam()));
1080 }
1081 if (hardDisk)
1082 {
1083 ComPtr<IProgress> progress;
1084 CHECK_ERROR(hardDisk, CloneToImage(Bstr(argv[1]), hardDisk.asOutParam(), progress.asOutParam()));
1085 if (SUCCEEDED(rc))
1086 {
1087 showProgress(progress);
1088 progress->COMGETTER(ResultCode)(&rc);
1089 if (FAILED(rc))
1090 {
1091 com::ProgressErrorInfo info(progress);
1092 if (info.isBasicAvailable())
1093 {
1094 RTPrintf("Error: failed to clone disk image. Error message: %lS\n", info.getText().raw());
1095 }
1096 else
1097 {
1098 RTPrintf("Error: failed to clone disk image. No error message available!\n");
1099 }
1100 }
1101 }
1102 }
1103 return SUCCEEDED(rc) ? 0 : 1;
1104#endif
1105}
1106
1107static int handleConvertDDImage(int argc, char *argv[])
1108{
1109 int arg = 0;
1110 VDIIMAGETYPE enmImgType = VDI_IMAGE_TYPE_NORMAL;
1111 if (argc >= 1 && !strcmp(argv[arg], "-static"))
1112 {
1113 arg++;
1114 enmImgType = VDI_IMAGE_TYPE_FIXED;
1115 }
1116
1117#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
1118 const bool fReadFromStdIn = (argc >= arg + 1) && !strcmp(argv[arg], "stdin");
1119#else
1120 const bool fReadFromStdIn = false;
1121#endif
1122
1123 if ((!fReadFromStdIn && argc != arg + 2) || (fReadFromStdIn && argc != arg + 3))
1124 return errorSyntax(USAGE_CONVERTDD, "Incorrect number of parameters");
1125
1126 RTPrintf("Converting VDI: from DD image file=\"%s\" to file=\"%s\"...\n",
1127 argv[arg], argv[arg + 1]);
1128
1129 /* open raw image file. */
1130 RTFILE File;
1131 int rc = VINF_SUCCESS;
1132 if (fReadFromStdIn)
1133 File = 0;
1134 else
1135 rc = RTFileOpen(&File, argv[arg], RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
1136 if (RT_FAILURE(rc))
1137 {
1138 RTPrintf("File=\"%s\" open error: %Rrf\n", argv[arg], rc);
1139 return rc;
1140 }
1141
1142 uint64_t cbFile;
1143 /* get image size. */
1144 if (fReadFromStdIn)
1145 cbFile = RTStrToUInt64(argv[arg + 2]);
1146 else
1147 rc = RTFileGetSize(File, &cbFile);
1148 if (RT_SUCCESS(rc))
1149 {
1150 RTPrintf("Creating %s image with size %RU64 bytes (%RU64MB)...\n", (enmImgType == VDI_IMAGE_TYPE_FIXED) ? "fixed" : "dynamic", cbFile, (cbFile + _1M - 1) / _1M);
1151 char pszComment[256];
1152 RTStrPrintf(pszComment, sizeof(pszComment), "Converted image from %s", argv[arg]);
1153 rc = VDICreateBaseImage(argv[arg + 1],
1154 enmImgType,
1155 cbFile,
1156 pszComment, NULL, NULL);
1157 if (RT_SUCCESS(rc))
1158 {
1159 PVDIDISK pVdi = VDIDiskCreate();
1160 rc = VDIDiskOpenImage(pVdi, argv[arg + 1], VDI_OPEN_FLAGS_NORMAL);
1161 if (RT_SUCCESS(rc))
1162 {
1163 /* alloc work buffer. */
1164 size_t cbBuffer = VDIDiskGetBufferSize(pVdi);
1165 void *pvBuf = RTMemAlloc(cbBuffer);
1166 if (pvBuf)
1167 {
1168 uint64_t offFile = 0;
1169 while (offFile < cbFile)
1170 {
1171 size_t cbRead = 0;
1172 size_t cbToRead = cbFile - offFile >= (uint64_t) cbBuffer ?
1173 cbBuffer : (size_t) (cbFile - offFile);
1174 rc = RTFileRead(File, pvBuf, cbToRead, &cbRead);
1175 if (RT_FAILURE(rc) || !cbRead)
1176 break;
1177 rc = VDIDiskWrite(pVdi, offFile, pvBuf, cbRead);
1178 if (RT_FAILURE(rc))
1179 break;
1180 offFile += cbRead;
1181 }
1182
1183 RTMemFree(pvBuf);
1184 }
1185 else
1186 rc = VERR_NO_MEMORY;
1187
1188 VDIDiskCloseImage(pVdi);
1189 }
1190
1191 if (RT_FAILURE(rc))
1192 {
1193 /* delete image on error */
1194 RTPrintf("Failed (%Rrc)!\n", rc);
1195 VDIDeleteImage(argv[arg + 1]);
1196 }
1197 }
1198 else
1199 RTPrintf("Failed to create output file (%Rrc)!\n", rc);
1200 }
1201 RTFileClose(File);
1202
1203 return rc;
1204}
1205
1206static int handleAddiSCSIDisk(int argc, char *argv[],
1207 ComPtr <IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
1208{
1209#if 1
1210 RTPrintf("Error: Create iSCSI hard disk operation is temporarily unavailable!\n");
1211 return 1;
1212#else
1213 HRESULT rc;
1214 Bstr server;
1215 Bstr target;
1216 uint16_t port = UINT16_MAX;
1217 uint64_t lun = UINT64_MAX;
1218 Bstr username;
1219 Bstr password;
1220 Bstr comment;
1221
1222 /* at least server and target */
1223 if (argc < 4)
1224 return errorSyntax(USAGE_ADDISCSIDISK, "Not enough parameters");
1225
1226 /* let's have a closer look at the arguments */
1227 for (int i = 0; i < argc; i++)
1228 {
1229 if (strcmp(argv[i], "-server") == 0)
1230 {
1231 if (argc <= i + 1)
1232 return errorArgument("Missing argument to '%s'", argv[i]);
1233 i++;
1234 server = argv[i];
1235 }
1236 else if (strcmp(argv[i], "-target") == 0)
1237 {
1238 if (argc <= i + 1)
1239 return errorArgument("Missing argument to '%s'", argv[i]);
1240 i++;
1241 target = argv[i];
1242 }
1243 else if (strcmp(argv[i], "-port") == 0)
1244 {
1245 if (argc <= i + 1)
1246 return errorArgument("Missing argument to '%s'", argv[i]);
1247 i++;
1248 port = atoi(argv[i]);
1249 }
1250 else if (strcmp(argv[i], "-lun") == 0)
1251 {
1252 /** @todo move the LUN encoding algorithm into IISCSIHardDisk, add decoding */
1253 if (argc <= i + 1)
1254 return errorArgument("Missing argument to '%s'", argv[i]);
1255 i++;
1256 char *pszNext;
1257 int rc = RTStrToUInt64Ex(argv[i], &pszNext, 0, &lun);
1258 if (RT_FAILURE(rc) || *pszNext != '\0' || lun >= 16384)
1259 return errorArgument("Invalid LUN number '%s'", argv[i]);
1260 if (lun <= 255)
1261 {
1262 /* Assume bus identifier = 0. */
1263 lun = (lun << 48); /* uses peripheral device addressing method */
1264 }
1265 else
1266 {
1267 /* Check above already limited the LUN to 14 bits. */
1268 lun = (lun << 48) | RT_BIT_64(62); /* uses flat space addressing method */
1269 }
1270 }
1271 else if (strcmp(argv[i], "-encodedlun") == 0)
1272 {
1273 if (argc <= i + 1)
1274 return errorArgument("Missing argument to '%s'", argv[i]);
1275 i++;
1276 char *pszNext;
1277 int rc = RTStrToUInt64Ex(argv[i], &pszNext, 0, &lun);
1278 if (RT_FAILURE(rc) || *pszNext != '\0')
1279 return errorArgument("Invalid encoded LUN number '%s'", argv[i]);
1280 }
1281 else if (strcmp(argv[i], "-username") == 0)
1282 {
1283 if (argc <= i + 1)
1284 return errorArgument("Missing argument to '%s'", argv[i]);
1285 i++;
1286 username = argv[i];
1287 }
1288 else if (strcmp(argv[i], "-password") == 0)
1289 {
1290 if (argc <= i + 1)
1291 return errorArgument("Missing argument to '%s'", argv[i]);
1292 i++;
1293 password = argv[i];
1294 }
1295 else if (strcmp(argv[i], "-comment") == 0)
1296 {
1297 if (argc <= i + 1)
1298 return errorArgument("Missing argument to '%s'", argv[i]);
1299 i++;
1300 comment = argv[i];
1301 }
1302 else
1303 return errorSyntax(USAGE_ADDISCSIDISK, "Invalid parameter '%s'", Utf8Str(argv[i]).raw());
1304 }
1305
1306 /* check for required options */
1307 if (!server || !target)
1308 return errorSyntax(USAGE_ADDISCSIDISK, "Parameters -server and -target are required");
1309
1310 ComPtr<IHardDisk> hardDisk;
1311 CHECK_ERROR(aVirtualBox, CreateHardDisk(HardDiskStorageType_ISCSIHardDisk, hardDisk.asOutParam()));
1312 if (SUCCEEDED(rc) && hardDisk)
1313 {
1314 CHECK_ERROR(hardDisk, COMSETTER(Description)(comment));
1315 ComPtr<IISCSIHardDisk> iSCSIDisk = hardDisk;
1316 CHECK_ERROR(iSCSIDisk, COMSETTER(Server)(server));
1317 if (port != UINT16_MAX)
1318 CHECK_ERROR(iSCSIDisk, COMSETTER(Port)(port));
1319 CHECK_ERROR(iSCSIDisk, COMSETTER(Target)(target));
1320 if (lun != UINT64_MAX)
1321 CHECK_ERROR(iSCSIDisk, COMSETTER(Lun)(lun));
1322 CHECK_ERROR(iSCSIDisk, COMSETTER(UserName)(username));
1323 CHECK_ERROR(iSCSIDisk, COMSETTER(Password)(password));
1324
1325 if (SUCCEEDED(rc))
1326 {
1327 CHECK_ERROR(aVirtualBox, RegisterHardDisk(hardDisk));
1328 }
1329
1330 if (SUCCEEDED(rc))
1331 {
1332 Guid guid;
1333 CHECK_ERROR(hardDisk, COMGETTER(Id)(guid.asOutParam()));
1334 RTPrintf("iSCSI disk created. UUID: %s\n", guid.toString().raw());
1335 }
1336 }
1337
1338 return SUCCEEDED(rc) ? 0 : 1;
1339#endif
1340}
1341
1342static int handleCreateVM(int argc, char *argv[],
1343 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
1344{
1345 HRESULT rc;
1346 Bstr baseFolder;
1347 Bstr settingsFile;
1348 Bstr name;
1349 RTUUID id;
1350 bool fRegister = false;
1351
1352 RTUuidClear(&id);
1353 for (int i = 0; i < argc; i++)
1354 {
1355 if (strcmp(argv[i], "-basefolder") == 0)
1356 {
1357 if (argc <= i + 1)
1358 return errorArgument("Missing argument to '%s'", argv[i]);
1359 i++;
1360 baseFolder = argv[i];
1361 }
1362 else if (strcmp(argv[i], "-settingsfile") == 0)
1363 {
1364 if (argc <= i + 1)
1365 return errorArgument("Missing argument to '%s'", argv[i]);
1366 i++;
1367 settingsFile = argv[i];
1368 }
1369 else if (strcmp(argv[i], "-name") == 0)
1370 {
1371 if (argc <= i + 1)
1372 return errorArgument("Missing argument to '%s'", argv[i]);
1373 i++;
1374 name = argv[i];
1375 }
1376 else if (strcmp(argv[i], "-uuid") == 0)
1377 {
1378 if (argc <= i + 1)
1379 return errorArgument("Missing argument to '%s'", argv[i]);
1380 i++;
1381 if (RT_FAILURE(RTUuidFromStr(&id, argv[i])))
1382 return errorArgument("Invalid UUID format %s\n", argv[i]);
1383 }
1384 else if (strcmp(argv[i], "-register") == 0)
1385 {
1386 fRegister = true;
1387 }
1388 else
1389 return errorSyntax(USAGE_CREATEVM, "Invalid parameter '%s'", Utf8Str(argv[i]).raw());
1390 }
1391 if (!name)
1392 return errorSyntax(USAGE_CREATEVM, "Parameter -name is required");
1393
1394 if (!!baseFolder && !!settingsFile)
1395 return errorSyntax(USAGE_CREATEVM, "Either -basefolder or -settingsfile must be specified");
1396
1397 do
1398 {
1399 ComPtr<IMachine> machine;
1400
1401 if (!settingsFile)
1402 CHECK_ERROR_BREAK(virtualBox,
1403 CreateMachine(baseFolder, name, Guid(id), machine.asOutParam()));
1404 else
1405 CHECK_ERROR_BREAK(virtualBox,
1406 CreateLegacyMachine(settingsFile, name, Guid(id), machine.asOutParam()));
1407
1408 CHECK_ERROR_BREAK(machine, SaveSettings());
1409 if (fRegister)
1410 {
1411 CHECK_ERROR_BREAK(virtualBox, RegisterMachine(machine));
1412 }
1413 Guid uuid;
1414 CHECK_ERROR_BREAK(machine, COMGETTER(Id)(uuid.asOutParam()));
1415 CHECK_ERROR_BREAK(machine, COMGETTER(SettingsFilePath)(settingsFile.asOutParam()));
1416 RTPrintf("Virtual machine '%ls' is created%s.\n"
1417 "UUID: %s\n"
1418 "Settings file: '%ls'\n",
1419 name.raw(), fRegister ? " and registered" : "",
1420 uuid.toString().raw(), settingsFile.raw());
1421 }
1422 while (0);
1423
1424 return SUCCEEDED(rc) ? 0 : 1;
1425}
1426
1427/**
1428 * Parses a number.
1429 *
1430 * @returns Valid number on success.
1431 * @returns 0 if invalid number. All necesary bitching has been done.
1432 * @param psz Pointer to the nic number.
1433 */
1434static unsigned parseNum(const char *psz, unsigned cMaxNum, const char *name)
1435{
1436 uint32_t u32;
1437 char *pszNext;
1438 int rc = RTStrToUInt32Ex(psz, &pszNext, 10, &u32);
1439 if ( RT_SUCCESS(rc)
1440 && *pszNext == '\0'
1441 && u32 >= 1
1442 && u32 <= cMaxNum)
1443 return (unsigned)u32;
1444 errorArgument("Invalid %s number '%s'", name, psz);
1445 return 0;
1446}
1447
1448static int handleModifyVM(int argc, char *argv[],
1449 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
1450{
1451 HRESULT rc;
1452 Bstr name;
1453 Bstr ostype;
1454 ULONG memorySize = 0;
1455 ULONG vramSize = 0;
1456 char *acpi = NULL;
1457 char *hwvirtex = NULL;
1458 char *nestedpaging = NULL;
1459 char *vtxvpid = NULL;
1460 char *pae = NULL;
1461 char *ioapic = NULL;
1462 int monitorcount = -1;
1463 char *accelerate3d = NULL;
1464 char *bioslogofadein = NULL;
1465 char *bioslogofadeout = NULL;
1466 uint32_t bioslogodisplaytime = ~0;
1467 char *bioslogoimagepath = NULL;
1468 char *biosbootmenumode = NULL;
1469 char *biossystemtimeoffset = NULL;
1470 char *biospxedebug = NULL;
1471 DeviceType_T bootDevice[4];
1472 int bootDeviceChanged[4] = { false };
1473 char *hdds[34] = {0};
1474 char *dvd = NULL;
1475 char *dvdpassthrough = NULL;
1476 char *idecontroller = NULL;
1477 char *floppy = NULL;
1478 char *audio = NULL;
1479 char *audiocontroller = NULL;
1480 char *clipboard = NULL;
1481#ifdef VBOX_WITH_VRDP
1482 char *vrdp = NULL;
1483 uint16_t vrdpport = UINT16_MAX;
1484 char *vrdpaddress = NULL;
1485 char *vrdpauthtype = NULL;
1486 char *vrdpmulticon = NULL;
1487 char *vrdpreusecon = NULL;
1488#endif
1489 int fUsbEnabled = -1;
1490 int fUsbEhciEnabled = -1;
1491 char *snapshotFolder = NULL;
1492 ULONG guestMemBalloonSize = (ULONG)-1;
1493 ULONG guestStatInterval = (ULONG)-1;
1494 int fSataEnabled = -1;
1495 int sataPortCount = -1;
1496 int sataBootDevices[4] = {-1,-1,-1,-1};
1497
1498 /* VM ID + at least one parameter. Parameter arguments are checked
1499 * individually. */
1500 if (argc < 2)
1501 return errorSyntax(USAGE_MODIFYVM, "Not enough parameters");
1502
1503 /* Get the number of network adapters */
1504 ULONG NetworkAdapterCount = 0;
1505 {
1506 ComPtr <ISystemProperties> info;
1507 CHECK_ERROR_RET (virtualBox, COMGETTER(SystemProperties) (info.asOutParam()), 1);
1508 CHECK_ERROR_RET (info, COMGETTER(NetworkAdapterCount) (&NetworkAdapterCount), 1);
1509 }
1510 ULONG SerialPortCount = 0;
1511 {
1512 ComPtr <ISystemProperties> info;
1513 CHECK_ERROR_RET (virtualBox, COMGETTER(SystemProperties) (info.asOutParam()), 1);
1514 CHECK_ERROR_RET (info, COMGETTER(SerialPortCount) (&SerialPortCount), 1);
1515 }
1516
1517 std::vector <char *> nics (NetworkAdapterCount, 0);
1518 std::vector <char *> nictype (NetworkAdapterCount, 0);
1519 std::vector <char *> cableconnected (NetworkAdapterCount, 0);
1520 std::vector <char *> nictrace (NetworkAdapterCount, 0);
1521 std::vector <char *> nictracefile (NetworkAdapterCount, 0);
1522 std::vector <char *> nicspeed (NetworkAdapterCount, 0);
1523 std::vector <char *> hostifdev (NetworkAdapterCount, 0);
1524 std::vector <const char *> intnet (NetworkAdapterCount, 0);
1525 std::vector <const char *> natnet (NetworkAdapterCount, 0);
1526#ifdef RT_OS_LINUX
1527 std::vector <char *> tapsetup (NetworkAdapterCount, 0);
1528 std::vector <char *> tapterm (NetworkAdapterCount, 0);
1529#endif
1530 std::vector <char *> macs (NetworkAdapterCount, 0);
1531 std::vector <char *> uarts_mode (SerialPortCount, 0);
1532 std::vector <ULONG> uarts_base (SerialPortCount, 0);
1533 std::vector <ULONG> uarts_irq (SerialPortCount, 0);
1534 std::vector <char *> uarts_path (SerialPortCount, 0);
1535
1536 for (int i = 1; i < argc; i++)
1537 {
1538 if (strcmp(argv[i], "-name") == 0)
1539 {
1540 if (argc <= i + 1)
1541 return errorArgument("Missing argument to '%s'", argv[i]);
1542 i++;
1543 name = argv[i];
1544 }
1545 else if (strcmp(argv[i], "-ostype") == 0)
1546 {
1547 if (argc <= i + 1)
1548 return errorArgument("Missing argument to '%s'", argv[i]);
1549 i++;
1550 ostype = argv[i];
1551 }
1552 else if (strcmp(argv[i], "-memory") == 0)
1553 {
1554 if (argc <= i + 1)
1555 return errorArgument("Missing argument to '%s'", argv[i]);
1556 i++;
1557 memorySize = atoi(argv[i]);
1558 }
1559 else if (strcmp(argv[i], "-vram") == 0)
1560 {
1561 if (argc <= i + 1)
1562 return errorArgument("Missing argument to '%s'", argv[i]);
1563 i++;
1564 vramSize = atoi(argv[i]);
1565 }
1566 else if (strcmp(argv[i], "-acpi") == 0)
1567 {
1568 if (argc <= i + 1)
1569 return errorArgument("Missing argument to '%s'", argv[i]);
1570 i++;
1571 acpi = argv[i];
1572 }
1573 else if (strcmp(argv[i], "-ioapic") == 0)
1574 {
1575 if (argc <= i + 1)
1576 return errorArgument("Missing argument to '%s'", argv[i]);
1577 i++;
1578 ioapic = argv[i];
1579 }
1580 else if (strcmp(argv[i], "-hwvirtex") == 0)
1581 {
1582 if (argc <= i + 1)
1583 return errorArgument("Missing argument to '%s'", argv[i]);
1584 i++;
1585 hwvirtex = argv[i];
1586 }
1587 else if (strcmp(argv[i], "-nestedpaging") == 0)
1588 {
1589 if (argc <= i + 1)
1590 return errorArgument("Missing argument to '%s'", argv[i]);
1591 i++;
1592 nestedpaging = argv[i];
1593 }
1594 else if (strcmp(argv[i], "-vtxvpid") == 0)
1595 {
1596 if (argc <= i + 1)
1597 return errorArgument("Missing argument to '%s'", argv[i]);
1598 i++;
1599 vtxvpid = argv[i];
1600 }
1601 else if (strcmp(argv[i], "-pae") == 0)
1602 {
1603 if (argc <= i + 1)
1604 return errorArgument("Missing argument to '%s'", argv[i]);
1605 i++;
1606 pae = argv[i];
1607 }
1608 else if (strcmp(argv[i], "-monitorcount") == 0)
1609 {
1610 if (argc <= i + 1)
1611 return errorArgument("Missing argument to '%s'", argv[i]);
1612 i++;
1613 monitorcount = atoi(argv[i]);
1614 }
1615 else if (strcmp(argv[i], "-accelerate3d") == 0)
1616 {
1617 if (argc <= i + 1)
1618 return errorArgument("Missing argument to '%s'", argv[i]);
1619 i++;
1620 accelerate3d = argv[i];
1621 }
1622 else if (strcmp(argv[i], "-bioslogofadein") == 0)
1623 {
1624 if (argc <= i + 1)
1625 return errorArgument("Missing argument to '%s'", argv[i]);
1626 i++;
1627 bioslogofadein = argv[i];
1628 }
1629 else if (strcmp(argv[i], "-bioslogofadeout") == 0)
1630 {
1631 if (argc <= i + 1)
1632 return errorArgument("Missing argument to '%s'", argv[i]);
1633 i++;
1634 bioslogofadeout = argv[i];
1635 }
1636 else if (strcmp(argv[i], "-bioslogodisplaytime") == 0)
1637 {
1638 if (argc <= i + 1)
1639 return errorArgument("Missing argument to '%s'", argv[i]);
1640 i++;
1641 bioslogodisplaytime = atoi(argv[i]);
1642 }
1643 else if (strcmp(argv[i], "-bioslogoimagepath") == 0)
1644 {
1645 if (argc <= i + 1)
1646 return errorArgument("Missing argument to '%s'", argv[i]);
1647 i++;
1648 bioslogoimagepath = argv[i];
1649 }
1650 else if (strcmp(argv[i], "-biosbootmenu") == 0)
1651 {
1652 if (argc <= i + 1)
1653 return errorArgument("Missing argument to '%s'", argv[i]);
1654 i++;
1655 biosbootmenumode = argv[i];
1656 }
1657 else if (strcmp(argv[i], "-biossystemtimeoffset") == 0)
1658 {
1659 if (argc <= i + 1)
1660 return errorArgument("Missing argument to '%s'", argv[i]);
1661 i++;
1662 biossystemtimeoffset = argv[i];
1663 }
1664 else if (strcmp(argv[i], "-biospxedebug") == 0)
1665 {
1666 if (argc <= i + 1)
1667 return errorArgument("Missing argument to '%s'", argv[i]);
1668 i++;
1669 biospxedebug = argv[i];
1670 }
1671 else if (strncmp(argv[i], "-boot", 5) == 0)
1672 {
1673 ULONG n = 0;
1674 if (!argv[i][5])
1675 return errorSyntax(USAGE_MODIFYVM, "Missing boot slot number in '%s'", argv[i]);
1676 if ((n = strtoul(&argv[i][5], NULL, 10)) < 1)
1677 return errorSyntax(USAGE_MODIFYVM, "Invalid boot slot number in '%s'", argv[i]);
1678 if (argc <= i + 1)
1679 return errorArgument("Missing argument to '%s'", argv[i]);
1680 i++;
1681 if (strcmp(argv[i], "none") == 0)
1682 {
1683 bootDevice[n - 1] = DeviceType_Null;
1684 }
1685 else if (strcmp(argv[i], "floppy") == 0)
1686 {
1687 bootDevice[n - 1] = DeviceType_Floppy;
1688 }
1689 else if (strcmp(argv[i], "dvd") == 0)
1690 {
1691 bootDevice[n - 1] = DeviceType_DVD;
1692 }
1693 else if (strcmp(argv[i], "disk") == 0)
1694 {
1695 bootDevice[n - 1] = DeviceType_HardDisk;
1696 }
1697 else if (strcmp(argv[i], "net") == 0)
1698 {
1699 bootDevice[n - 1] = DeviceType_Network;
1700 }
1701 else
1702 return errorArgument("Invalid boot device '%s'", argv[i]);
1703
1704 bootDeviceChanged[n - 1] = true;
1705 }
1706 else if (strcmp(argv[i], "-hda") == 0)
1707 {
1708 if (argc <= i + 1)
1709 return errorArgument("Missing argument to '%s'", argv[i]);
1710 i++;
1711 hdds[0] = argv[i];
1712 }
1713 else if (strcmp(argv[i], "-hdb") == 0)
1714 {
1715 if (argc <= i + 1)
1716 return errorArgument("Missing argument to '%s'", argv[i]);
1717 i++;
1718 hdds[1] = argv[i];
1719 }
1720 else if (strcmp(argv[i], "-hdd") == 0)
1721 {
1722 if (argc <= i + 1)
1723 return errorArgument("Missing argument to '%s'", argv[i]);
1724 i++;
1725 hdds[2] = argv[i];
1726 }
1727 else if (strcmp(argv[i], "-dvd") == 0)
1728 {
1729 if (argc <= i + 1)
1730 return errorArgument("Missing argument to '%s'", argv[i]);
1731 i++;
1732 dvd = argv[i];
1733 }
1734 else if (strcmp(argv[i], "-dvdpassthrough") == 0)
1735 {
1736 if (argc <= i + 1)
1737 return errorArgument("Missing argument to '%s'", argv[i]);
1738 i++;
1739 dvdpassthrough = argv[i];
1740 }
1741 else if (strcmp(argv[i], "-idecontroller") == 0)
1742 {
1743 if (argc <= i + 1)
1744 return errorArgument("Missing argument to '%s'", argv[i]);
1745 i++;
1746 idecontroller = argv[i];
1747 }
1748 else if (strcmp(argv[i], "-floppy") == 0)
1749 {
1750 if (argc <= i + 1)
1751 return errorArgument("Missing argument to '%s'", argv[i]);
1752 i++;
1753 floppy = argv[i];
1754 }
1755 else if (strcmp(argv[i], "-audio") == 0)
1756 {
1757 if (argc <= i + 1)
1758 return errorArgument("Missing argument to '%s'", argv[i]);
1759 i++;
1760 audio = argv[i];
1761 }
1762 else if (strcmp(argv[i], "-audiocontroller") == 0)
1763 {
1764 if (argc <= i + 1)
1765 return errorArgument("Missing argument to '%s'", argv[i]);
1766 i++;
1767 audiocontroller = argv[i];
1768 }
1769 else if (strcmp(argv[i], "-clipboard") == 0)
1770 {
1771 if (argc <= i + 1)
1772 return errorArgument("Missing argument to '%s'", argv[i]);
1773 i++;
1774 clipboard = argv[i];
1775 }
1776 else if (strncmp(argv[i], "-cableconnected", 15) == 0)
1777 {
1778 unsigned n = parseNum(&argv[i][15], NetworkAdapterCount, "NIC");
1779 if (!n)
1780 return 1;
1781
1782 if (argc <= i + 1)
1783 return errorArgument("Missing argument to '%s'", argv[i]);
1784
1785 cableconnected[n - 1] = argv[i + 1];
1786 i++;
1787 }
1788 /* watch for the right order of these -nic* comparisons! */
1789 else if (strncmp(argv[i], "-nictracefile", 13) == 0)
1790 {
1791 unsigned n = parseNum(&argv[i][13], NetworkAdapterCount, "NIC");
1792 if (!n)
1793 return 1;
1794 if (argc <= i + 1)
1795 {
1796 return errorArgument("Missing argument to '%s'", argv[i]);
1797 }
1798 nictracefile[n - 1] = argv[i + 1];
1799 i++;
1800 }
1801 else if (strncmp(argv[i], "-nictrace", 9) == 0)
1802 {
1803 unsigned n = parseNum(&argv[i][9], NetworkAdapterCount, "NIC");
1804 if (!n)
1805 return 1;
1806 if (argc <= i + 1)
1807 return errorArgument("Missing argument to '%s'", argv[i]);
1808 nictrace[n - 1] = argv[i + 1];
1809 i++;
1810 }
1811 else if (strncmp(argv[i], "-nictype", 8) == 0)
1812 {
1813 unsigned n = parseNum(&argv[i][8], NetworkAdapterCount, "NIC");
1814 if (!n)
1815 return 1;
1816 if (argc <= i + 1)
1817 return errorArgument("Missing argument to '%s'", argv[i]);
1818 nictype[n - 1] = argv[i + 1];
1819 i++;
1820 }
1821 else if (strncmp(argv[i], "-nicspeed", 9) == 0)
1822 {
1823 unsigned n = parseNum(&argv[i][9], NetworkAdapterCount, "NIC");
1824 if (!n)
1825 return 1;
1826 if (argc <= i + 1)
1827 return errorArgument("Missing argument to '%s'", argv[i]);
1828 nicspeed[n - 1] = argv[i + 1];
1829 i++;
1830 }
1831 else if (strncmp(argv[i], "-nic", 4) == 0)
1832 {
1833 unsigned n = parseNum(&argv[i][4], NetworkAdapterCount, "NIC");
1834 if (!n)
1835 return 1;
1836 if (argc <= i + 1)
1837 return errorArgument("Missing argument to '%s'", argv[i]);
1838 nics[n - 1] = argv[i + 1];
1839 i++;
1840 }
1841 else if (strncmp(argv[i], "-hostifdev", 10) == 0)
1842 {
1843 unsigned n = parseNum(&argv[i][10], NetworkAdapterCount, "NIC");
1844 if (!n)
1845 return 1;
1846 if (argc <= i + 1)
1847 return errorArgument("Missing argument to '%s'", argv[i]);
1848 hostifdev[n - 1] = argv[i + 1];
1849 i++;
1850 }
1851 else if (strncmp(argv[i], "-intnet", 7) == 0)
1852 {
1853 unsigned n = parseNum(&argv[i][7], NetworkAdapterCount, "NIC");
1854 if (!n)
1855 return 1;
1856 if (argc <= i + 1)
1857 return errorArgument("Missing argument to '%s'", argv[i]);
1858 intnet[n - 1] = argv[i + 1];
1859 i++;
1860 }
1861 else if (strncmp(argv[i], "-natnet", 7) == 0)
1862 {
1863 unsigned n = parseNum(&argv[i][7], NetworkAdapterCount, "NIC");
1864 if (!n)
1865 return 1;
1866 if (argc <= i + 1)
1867 return errorArgument("Missing argument to '%s'", argv[i]);
1868
1869 if (!strcmp(argv[i + 1], "default"))
1870 natnet[n - 1] = "";
1871 else
1872 {
1873 RTIPV4ADDR Network;
1874 RTIPV4ADDR Netmask;
1875 int rc = RTCidrStrToIPv4(argv[i + 1], &Network, &Netmask);
1876 if (RT_FAILURE(rc))
1877 return errorArgument("Invalid IPv4 network '%s' specified -- CIDR notation expected.\n", argv[i + 1]);
1878 if (Netmask & 0x1f)
1879 return errorArgument("Prefix length of the NAT network must be less than 28.\n");
1880 natnet[n - 1] = argv[i + 1];
1881 }
1882 i++;
1883 }
1884#ifdef RT_OS_LINUX
1885 else if (strncmp(argv[i], "-tapsetup", 9) == 0)
1886 {
1887 unsigned n = parseNum(&argv[i][9], NetworkAdapterCount, "NIC");
1888 if (!n)
1889 return 1;
1890 if (argc <= i + 1)
1891 return errorArgument("Missing argument to '%s'", argv[i]);
1892 tapsetup[n - 1] = argv[i + 1];
1893 i++;
1894 }
1895 else if (strncmp(argv[i], "-tapterminate", 13) == 0)
1896 {
1897 unsigned n = parseNum(&argv[i][13], NetworkAdapterCount, "NIC");
1898 if (!n)
1899 return 1;
1900 if (argc <= i + 1)
1901 return errorArgument("Missing argument to '%s'", argv[i]);
1902 tapterm[n - 1] = argv[i + 1];
1903 i++;
1904 }
1905#endif /* RT_OS_LINUX */
1906 else if (strncmp(argv[i], "-macaddress", 11) == 0)
1907 {
1908 unsigned n = parseNum(&argv[i][11], NetworkAdapterCount, "NIC");
1909 if (!n)
1910 return 1;
1911 if (argc <= i + 1)
1912 return errorArgument("Missing argument to '%s'", argv[i]);
1913 macs[n - 1] = argv[i + 1];
1914 i++;
1915 }
1916#ifdef VBOX_WITH_VRDP
1917 else if (strcmp(argv[i], "-vrdp") == 0)
1918 {
1919 if (argc <= i + 1)
1920 return errorArgument("Missing argument to '%s'", argv[i]);
1921 i++;
1922 vrdp = argv[i];
1923 }
1924 else if (strcmp(argv[i], "-vrdpport") == 0)
1925 {
1926 if (argc <= i + 1)
1927 return errorArgument("Missing argument to '%s'", argv[i]);
1928 i++;
1929 if (strcmp(argv[i], "default") == 0)
1930 vrdpport = 0;
1931 else
1932 vrdpport = atoi(argv[i]);
1933 }
1934 else if (strcmp(argv[i], "-vrdpaddress") == 0)
1935 {
1936 if (argc <= i + 1)
1937 return errorArgument("Missing argument to '%s'", argv[i]);
1938 i++;
1939 vrdpaddress = argv[i];
1940 }
1941 else if (strcmp(argv[i], "-vrdpauthtype") == 0)
1942 {
1943 if (argc <= i + 1)
1944 return errorArgument("Missing argument to '%s'", argv[i]);
1945 i++;
1946 vrdpauthtype = argv[i];
1947 }
1948 else if (strcmp(argv[i], "-vrdpmulticon") == 0)
1949 {
1950 if (argc <= i + 1)
1951 return errorArgument("Missing argument to '%s'", argv[i]);
1952 i++;
1953 vrdpmulticon = argv[i];
1954 }
1955 else if (strcmp(argv[i], "-vrdpreusecon") == 0)
1956 {
1957 if (argc <= i + 1)
1958 return errorArgument("Missing argument to '%s'", argv[i]);
1959 i++;
1960 vrdpreusecon = argv[i];
1961 }
1962#endif /* VBOX_WITH_VRDP */
1963 else if (strcmp(argv[i], "-usb") == 0)
1964 {
1965 if (argc <= i + 1)
1966 return errorArgument("Missing argument to '%s'", argv[i]);
1967 i++;
1968 if (strcmp(argv[i], "on") == 0 || strcmp(argv[i], "enable") == 0)
1969 fUsbEnabled = 1;
1970 else if (strcmp(argv[i], "off") == 0 || strcmp(argv[i], "disable") == 0)
1971 fUsbEnabled = 0;
1972 else
1973 return errorArgument("Invalid -usb argument '%s'", argv[i]);
1974 }
1975 else if (strcmp(argv[i], "-usbehci") == 0)
1976 {
1977 if (argc <= i + 1)
1978 return errorArgument("Missing argument to '%s'", argv[i]);
1979 i++;
1980 if (strcmp(argv[i], "on") == 0 || strcmp(argv[i], "enable") == 0)
1981 fUsbEhciEnabled = 1;
1982 else if (strcmp(argv[i], "off") == 0 || strcmp(argv[i], "disable") == 0)
1983 fUsbEhciEnabled = 0;
1984 else
1985 return errorArgument("Invalid -usbehci argument '%s'", argv[i]);
1986 }
1987 else if (strcmp(argv[i], "-snapshotfolder") == 0)
1988 {
1989 if (argc <= i + 1)
1990 return errorArgument("Missing argument to '%s'", argv[i]);
1991 i++;
1992 snapshotFolder = argv[i];
1993 }
1994 else if (strncmp(argv[i], "-uartmode", 9) == 0)
1995 {
1996 unsigned n = parseNum(&argv[i][9], SerialPortCount, "UART");
1997 if (!n)
1998 return 1;
1999 i++;
2000 if (strcmp(argv[i], "disconnected") == 0)
2001 {
2002 uarts_mode[n - 1] = argv[i];
2003 }
2004 else
2005 {
2006 if (strcmp(argv[i], "server") == 0 || strcmp(argv[i], "client") == 0)
2007 {
2008 uarts_mode[n - 1] = argv[i];
2009 i++;
2010#ifdef RT_OS_WINDOWS
2011 if (strncmp(argv[i], "\\\\.\\pipe\\", 9))
2012 return errorArgument("Uart pipe must start with \\\\.\\pipe\\");
2013#endif
2014 }
2015 else
2016 {
2017 uarts_mode[n - 1] = (char*)"device";
2018 }
2019 if (argc <= i)
2020 return errorArgument("Missing argument to -uartmode");
2021 uarts_path[n - 1] = argv[i];
2022 }
2023 }
2024 else if (strncmp(argv[i], "-uart", 5) == 0)
2025 {
2026 unsigned n = parseNum(&argv[i][5], SerialPortCount, "UART");
2027 if (!n)
2028 return 1;
2029 if (argc <= i + 1)
2030 return errorArgument("Missing argument to '%s'", argv[i]);
2031 i++;
2032 if (strcmp(argv[i], "off") == 0 || strcmp(argv[i], "disable") == 0)
2033 {
2034 uarts_base[n - 1] = (ULONG)-1;
2035 }
2036 else
2037 {
2038 if (argc <= i + 1)
2039 return errorArgument("Missing argument to '%s'", argv[i-1]);
2040 uint32_t uVal;
2041 int vrc;
2042 vrc = RTStrToUInt32Ex(argv[i], NULL, 0, &uVal);
2043 if (vrc != VINF_SUCCESS || uVal == 0)
2044 return errorArgument("Error parsing UART I/O base '%s'", argv[i]);
2045 uarts_base[n - 1] = uVal;
2046 i++;
2047 vrc = RTStrToUInt32Ex(argv[i], NULL, 0, &uVal);
2048 if (vrc != VINF_SUCCESS)
2049 return errorArgument("Error parsing UART IRQ '%s'", argv[i]);
2050 uarts_irq[n - 1] = uVal;
2051 }
2052 }
2053#ifdef VBOX_WITH_MEM_BALLOONING
2054 else if (strncmp(argv[i], "-guestmemoryballoon", 19) == 0)
2055 {
2056 if (argc <= i + 1)
2057 return errorArgument("Missing argument to '%s'", argv[i]);
2058 i++;
2059 uint32_t uVal;
2060 int vrc;
2061 vrc = RTStrToUInt32Ex(argv[i], NULL, 0, &uVal);
2062 if (vrc != VINF_SUCCESS)
2063 return errorArgument("Error parsing guest memory balloon size '%s'", argv[i]);
2064 guestMemBalloonSize = uVal;
2065 }
2066#endif
2067 else if (strncmp(argv[i], "-gueststatisticsinterval", 24) == 0)
2068 {
2069 if (argc <= i + 1)
2070 return errorArgument("Missing argument to '%s'", argv[i]);
2071 i++;
2072 uint32_t uVal;
2073 int vrc;
2074 vrc = RTStrToUInt32Ex(argv[i], NULL, 0, &uVal);
2075 if (vrc != VINF_SUCCESS)
2076 return errorArgument("Error parsing guest statistics interval '%s'", argv[i]);
2077 guestStatInterval = uVal;
2078 }
2079 else if (strcmp(argv[i], "-sata") == 0)
2080 {
2081 if (argc <= i + 1)
2082 return errorArgument("Missing argument to '%s'", argv[i]);
2083 i++;
2084 if (strcmp(argv[i], "on") == 0 || strcmp(argv[i], "enable") == 0)
2085 fSataEnabled = 1;
2086 else if (strcmp(argv[i], "off") == 0 || strcmp(argv[i], "disable") == 0)
2087 fSataEnabled = 0;
2088 else
2089 return errorArgument("Invalid -usb argument '%s'", argv[i]);
2090 }
2091 else if (strcmp(argv[i], "-sataportcount") == 0)
2092 {
2093 unsigned n;
2094
2095 if (argc <= i + 1)
2096 return errorArgument("Missing arguments to '%s'", argv[i]);
2097 i++;
2098
2099 n = parseNum(argv[i], 30, "SATA");
2100 if (!n)
2101 return 1;
2102 sataPortCount = n;
2103 }
2104 else if (strncmp(argv[i], "-sataport", 9) == 0)
2105 {
2106 unsigned n = parseNum(&argv[i][9], 30, "SATA");
2107 if (!n)
2108 return 1;
2109 if (argc <= i + 1)
2110 return errorArgument("Missing argument to '%s'", argv[i]);
2111 i++;
2112 hdds[n-1+4] = argv[i];
2113 }
2114 else if (strncmp(argv[i], "-sataideemulation", 17) == 0)
2115 {
2116 unsigned bootDevicePos = 0;
2117 unsigned n;
2118
2119 bootDevicePos = parseNum(&argv[i][17], 4, "SATA");
2120 if (!bootDevicePos)
2121 return 1;
2122 bootDevicePos--;
2123
2124 if (argc <= i + 1)
2125 return errorArgument("Missing arguments to '%s'", argv[i]);
2126 i++;
2127
2128 n = parseNum(argv[i], 30, "SATA");
2129 if (!n)
2130 return 1;
2131
2132 sataBootDevices[bootDevicePos] = n-1;
2133 }
2134 else
2135 return errorSyntax(USAGE_MODIFYVM, "Invalid parameter '%s'", Utf8Str(argv[i]).raw());
2136 }
2137
2138 /* try to find the given machine */
2139 ComPtr <IMachine> machine;
2140 Guid uuid (argv[0]);
2141 if (!uuid.isEmpty())
2142 {
2143 CHECK_ERROR (virtualBox, GetMachine (uuid, machine.asOutParam()));
2144 }
2145 else
2146 {
2147 CHECK_ERROR (virtualBox, FindMachine(Bstr(argv[0]), machine.asOutParam()));
2148 if (SUCCEEDED (rc))
2149 machine->COMGETTER(Id)(uuid.asOutParam());
2150 }
2151 if (FAILED (rc))
2152 return 1;
2153
2154 /* open a session for the VM */
2155 CHECK_ERROR_RET (virtualBox, OpenSession(session, uuid), 1);
2156
2157 do
2158 {
2159 /* get the mutable session machine */
2160 session->COMGETTER(Machine)(machine.asOutParam());
2161
2162 ComPtr <IBIOSSettings> biosSettings;
2163 machine->COMGETTER(BIOSSettings)(biosSettings.asOutParam());
2164
2165 if (name)
2166 CHECK_ERROR(machine, COMSETTER(Name)(name));
2167 if (ostype)
2168 {
2169 ComPtr<IGuestOSType> guestOSType;
2170 CHECK_ERROR(virtualBox, GetGuestOSType(ostype, guestOSType.asOutParam()));
2171 if (SUCCEEDED(rc) && guestOSType)
2172 {
2173 CHECK_ERROR(machine, COMSETTER(OSTypeId)(ostype));
2174 }
2175 else
2176 {
2177 errorArgument("Invalid guest OS type '%s'", Utf8Str(ostype).raw());
2178 rc = E_FAIL;
2179 break;
2180 }
2181 }
2182 if (memorySize > 0)
2183 CHECK_ERROR(machine, COMSETTER(MemorySize)(memorySize));
2184 if (vramSize > 0)
2185 CHECK_ERROR(machine, COMSETTER(VRAMSize)(vramSize));
2186 if (acpi)
2187 {
2188 if (strcmp(acpi, "on") == 0)
2189 {
2190 CHECK_ERROR(biosSettings, COMSETTER(ACPIEnabled)(true));
2191 }
2192 else if (strcmp(acpi, "off") == 0)
2193 {
2194 CHECK_ERROR(biosSettings, COMSETTER(ACPIEnabled)(false));
2195 }
2196 else
2197 {
2198 errorArgument("Invalid -acpi argument '%s'", acpi);
2199 rc = E_FAIL;
2200 break;
2201 }
2202 }
2203 if (ioapic)
2204 {
2205 if (strcmp(ioapic, "on") == 0)
2206 {
2207 CHECK_ERROR(biosSettings, COMSETTER(IOAPICEnabled)(true));
2208 }
2209 else if (strcmp(ioapic, "off") == 0)
2210 {
2211 CHECK_ERROR(biosSettings, COMSETTER(IOAPICEnabled)(false));
2212 }
2213 else
2214 {
2215 errorArgument("Invalid -ioapic argument '%s'", ioapic);
2216 rc = E_FAIL;
2217 break;
2218 }
2219 }
2220 if (hwvirtex)
2221 {
2222 if (strcmp(hwvirtex, "on") == 0)
2223 {
2224 CHECK_ERROR(machine, COMSETTER(HWVirtExEnabled)(TSBool_True));
2225 }
2226 else if (strcmp(hwvirtex, "off") == 0)
2227 {
2228 CHECK_ERROR(machine, COMSETTER(HWVirtExEnabled)(TSBool_False));
2229 }
2230 else if (strcmp(hwvirtex, "default") == 0)
2231 {
2232 CHECK_ERROR(machine, COMSETTER(HWVirtExEnabled)(TSBool_Default));
2233 }
2234 else
2235 {
2236 errorArgument("Invalid -hwvirtex argument '%s'", hwvirtex);
2237 rc = E_FAIL;
2238 break;
2239 }
2240 }
2241 if (nestedpaging)
2242 {
2243 if (strcmp(nestedpaging, "on") == 0)
2244 {
2245 CHECK_ERROR(machine, COMSETTER(HWVirtExNestedPagingEnabled)(true));
2246 }
2247 else if (strcmp(nestedpaging, "off") == 0)
2248 {
2249 CHECK_ERROR(machine, COMSETTER(HWVirtExNestedPagingEnabled)(false));
2250 }
2251 else
2252 {
2253 errorArgument("Invalid -nestedpaging argument '%s'", ioapic);
2254 rc = E_FAIL;
2255 break;
2256 }
2257 }
2258 if (vtxvpid)
2259 {
2260 if (strcmp(vtxvpid, "on") == 0)
2261 {
2262 CHECK_ERROR(machine, COMSETTER(HWVirtExVPIDEnabled)(true));
2263 }
2264 else if (strcmp(vtxvpid, "off") == 0)
2265 {
2266 CHECK_ERROR(machine, COMSETTER(HWVirtExVPIDEnabled)(false));
2267 }
2268 else
2269 {
2270 errorArgument("Invalid -vtxvpid argument '%s'", ioapic);
2271 rc = E_FAIL;
2272 break;
2273 }
2274 }
2275 if (pae)
2276 {
2277 if (strcmp(pae, "on") == 0)
2278 {
2279 CHECK_ERROR(machine, COMSETTER(PAEEnabled)(true));
2280 }
2281 else if (strcmp(pae, "off") == 0)
2282 {
2283 CHECK_ERROR(machine, COMSETTER(PAEEnabled)(false));
2284 }
2285 else
2286 {
2287 errorArgument("Invalid -pae argument '%s'", ioapic);
2288 rc = E_FAIL;
2289 break;
2290 }
2291 }
2292 if (monitorcount != -1)
2293 {
2294 CHECK_ERROR(machine, COMSETTER(MonitorCount)(monitorcount));
2295 }
2296 if (accelerate3d)
2297 {
2298 if (strcmp(accelerate3d, "on") == 0)
2299 {
2300 CHECK_ERROR(machine, COMSETTER(Accelerate3DEnabled)(true));
2301 }
2302 else if (strcmp(accelerate3d, "off") == 0)
2303 {
2304 CHECK_ERROR(machine, COMSETTER(Accelerate3DEnabled)(false));
2305 }
2306 else
2307 {
2308 errorArgument("Invalid -accelerate3d argument '%s'", ioapic);
2309 rc = E_FAIL;
2310 break;
2311 }
2312 }
2313 if (bioslogofadein)
2314 {
2315 if (strcmp(bioslogofadein, "on") == 0)
2316 {
2317 CHECK_ERROR(biosSettings, COMSETTER(LogoFadeIn)(true));
2318 }
2319 else if (strcmp(bioslogofadein, "off") == 0)
2320 {
2321 CHECK_ERROR(biosSettings, COMSETTER(LogoFadeIn)(false));
2322 }
2323 else
2324 {
2325 errorArgument("Invalid -bioslogofadein argument '%s'", bioslogofadein);
2326 rc = E_FAIL;
2327 break;
2328 }
2329 }
2330 if (bioslogofadeout)
2331 {
2332 if (strcmp(bioslogofadeout, "on") == 0)
2333 {
2334 CHECK_ERROR(biosSettings, COMSETTER(LogoFadeOut)(true));
2335 }
2336 else if (strcmp(bioslogofadeout, "off") == 0)
2337 {
2338 CHECK_ERROR(biosSettings, COMSETTER(LogoFadeOut)(false));
2339 }
2340 else
2341 {
2342 errorArgument("Invalid -bioslogofadeout argument '%s'", bioslogofadeout);
2343 rc = E_FAIL;
2344 break;
2345 }
2346 }
2347 if (bioslogodisplaytime != ~0U)
2348 {
2349 CHECK_ERROR(biosSettings, COMSETTER(LogoDisplayTime)(bioslogodisplaytime));
2350 }
2351 if (bioslogoimagepath)
2352 {
2353 CHECK_ERROR(biosSettings, COMSETTER(LogoImagePath)(Bstr(bioslogoimagepath)));
2354 }
2355 if (biosbootmenumode)
2356 {
2357 if (strcmp(biosbootmenumode, "disabled") == 0)
2358 CHECK_ERROR(biosSettings, COMSETTER(BootMenuMode)(BIOSBootMenuMode_Disabled));
2359 else if (strcmp(biosbootmenumode, "menuonly") == 0)
2360 CHECK_ERROR(biosSettings, COMSETTER(BootMenuMode)(BIOSBootMenuMode_MenuOnly));
2361 else if (strcmp(biosbootmenumode, "messageandmenu") == 0)
2362 CHECK_ERROR(biosSettings, COMSETTER(BootMenuMode)(BIOSBootMenuMode_MessageAndMenu));
2363 else
2364 {
2365 errorArgument("Invalid -biosbootmenu argument '%s'", biosbootmenumode);
2366 rc = E_FAIL;
2367 break;
2368 }
2369
2370 }
2371 if (biossystemtimeoffset)
2372 {
2373 LONG64 timeOffset = RTStrToInt64(biossystemtimeoffset);
2374 CHECK_ERROR(biosSettings, COMSETTER(TimeOffset)(timeOffset));
2375 }
2376 if (biospxedebug)
2377 {
2378 if (strcmp(biospxedebug, "on") == 0)
2379 {
2380 CHECK_ERROR(biosSettings, COMSETTER(PXEDebugEnabled)(true));
2381 }
2382 else if (strcmp(biospxedebug, "off") == 0)
2383 {
2384 CHECK_ERROR(biosSettings, COMSETTER(PXEDebugEnabled)(false));
2385 }
2386 else
2387 {
2388 errorArgument("Invalid -biospxedebug argument '%s'", biospxedebug);
2389 rc = E_FAIL;
2390 break;
2391 }
2392 }
2393 for (int curBootDev = 0; curBootDev < 4; curBootDev++)
2394 {
2395 if (bootDeviceChanged[curBootDev])
2396 CHECK_ERROR(machine, SetBootOrder (curBootDev + 1, bootDevice[curBootDev]));
2397 }
2398 if (hdds[0])
2399 {
2400 if (strcmp(hdds[0], "none") == 0)
2401 {
2402 machine->DetachHardDisk2(StorageBus_IDE, 0, 0);
2403 }
2404 else
2405 {
2406 /* first guess is that it's a UUID */
2407 Guid uuid(hdds[0]);
2408 ComPtr<IHardDisk2> hardDisk;
2409 rc = virtualBox->GetHardDisk2(uuid, hardDisk.asOutParam());
2410 /* not successful? Then it must be a filename */
2411 if (!hardDisk)
2412 {
2413 CHECK_ERROR(virtualBox, FindHardDisk2(Bstr(hdds[0]), hardDisk.asOutParam()));
2414 if (FAILED(rc))
2415 {
2416 /* open the new hard disk object */
2417 CHECK_ERROR(virtualBox, OpenHardDisk2(Bstr(hdds[0]), hardDisk.asOutParam()));
2418 }
2419 }
2420 if (hardDisk)
2421 {
2422 hardDisk->COMGETTER(Id)(uuid.asOutParam());
2423 CHECK_ERROR(machine, AttachHardDisk2(uuid, StorageBus_IDE, 0, 0));
2424 }
2425 else
2426 rc = E_FAIL;
2427 if (FAILED(rc))
2428 break;
2429 }
2430 }
2431 if (hdds[1])
2432 {
2433 if (strcmp(hdds[1], "none") == 0)
2434 {
2435 machine->DetachHardDisk2(StorageBus_IDE, 0, 1);
2436 }
2437 else
2438 {
2439 /* first guess is that it's a UUID */
2440 Guid uuid(hdds[1]);
2441 ComPtr<IHardDisk2> hardDisk;
2442 rc = virtualBox->GetHardDisk2(uuid, hardDisk.asOutParam());
2443 /* not successful? Then it must be a filename */
2444 if (!hardDisk)
2445 {
2446 CHECK_ERROR(virtualBox, FindHardDisk2(Bstr(hdds[1]), hardDisk.asOutParam()));
2447 if (FAILED(rc))
2448 {
2449 /* open the new hard disk object */
2450 CHECK_ERROR(virtualBox, OpenHardDisk2(Bstr(hdds[1]), hardDisk.asOutParam()));
2451 }
2452 }
2453 if (hardDisk)
2454 {
2455 hardDisk->COMGETTER(Id)(uuid.asOutParam());
2456 CHECK_ERROR(machine, AttachHardDisk2(uuid, StorageBus_IDE, 0, 1));
2457 }
2458 else
2459 rc = E_FAIL;
2460 if (FAILED(rc))
2461 break;
2462 }
2463 }
2464 if (hdds[2])
2465 {
2466 if (strcmp(hdds[2], "none") == 0)
2467 {
2468 machine->DetachHardDisk2(StorageBus_IDE, 1, 1);
2469 }
2470 else
2471 {
2472 /* first guess is that it's a UUID */
2473 Guid uuid(hdds[2]);
2474 ComPtr<IHardDisk2> hardDisk;
2475 rc = virtualBox->GetHardDisk2(uuid, hardDisk.asOutParam());
2476 /* not successful? Then it must be a filename */
2477 if (!hardDisk)
2478 {
2479 CHECK_ERROR(virtualBox, FindHardDisk2(Bstr(hdds[2]), hardDisk.asOutParam()));
2480 if (FAILED(rc))
2481 {
2482 /* open the new hard disk object */
2483 CHECK_ERROR(virtualBox, OpenHardDisk2(Bstr(hdds[2]), hardDisk.asOutParam()));
2484 }
2485 }
2486 if (hardDisk)
2487 {
2488 hardDisk->COMGETTER(Id)(uuid.asOutParam());
2489 CHECK_ERROR(machine, AttachHardDisk2(uuid, StorageBus_IDE, 1, 1));
2490 }
2491 else
2492 rc = E_FAIL;
2493 if (FAILED(rc))
2494 break;
2495 }
2496 }
2497 if (dvd)
2498 {
2499 ComPtr<IDVDDrive> dvdDrive;
2500 machine->COMGETTER(DVDDrive)(dvdDrive.asOutParam());
2501 ASSERT(dvdDrive);
2502
2503 /* unmount? */
2504 if (strcmp(dvd, "none") == 0)
2505 {
2506 CHECK_ERROR(dvdDrive, Unmount());
2507 }
2508 /* host drive? */
2509 else if (strncmp(dvd, "host:", 5) == 0)
2510 {
2511 ComPtr<IHost> host;
2512 CHECK_ERROR(virtualBox, COMGETTER(Host)(host.asOutParam()));
2513 ComPtr<IHostDVDDriveCollection> hostDVDs;
2514 CHECK_ERROR(host, COMGETTER(DVDDrives)(hostDVDs.asOutParam()));
2515 ComPtr<IHostDVDDrive> hostDVDDrive;
2516 rc = hostDVDs->FindByName(Bstr(dvd + 5), hostDVDDrive.asOutParam());
2517 if (!hostDVDDrive)
2518 {
2519 /* 2nd try: try with the real name, important on Linux+libhal */
2520 char szPathReal[RTPATH_MAX];
2521 if (RT_FAILURE(RTPathReal(dvd + 5, szPathReal, sizeof(szPathReal))))
2522 {
2523 errorArgument("Invalid host DVD drive name");
2524 rc = E_FAIL;
2525 break;
2526 }
2527 rc = hostDVDs->FindByName(Bstr(szPathReal), hostDVDDrive.asOutParam());
2528 if (!hostDVDDrive)
2529 {
2530 errorArgument("Invalid host DVD drive name");
2531 rc = E_FAIL;
2532 break;
2533 }
2534 }
2535 CHECK_ERROR(dvdDrive, CaptureHostDrive(hostDVDDrive));
2536 }
2537 else
2538 {
2539 /* first assume it's a UUID */
2540 Guid uuid(dvd);
2541 ComPtr<IDVDImage2> dvdImage;
2542 rc = virtualBox->GetDVDImage(uuid, dvdImage.asOutParam());
2543 if (FAILED(rc) || !dvdImage)
2544 {
2545 /* must be a filename, check if it's in the collection */
2546 rc = virtualBox->FindDVDImage(Bstr(dvd), dvdImage.asOutParam());
2547 /* not registered, do that on the fly */
2548 if (!dvdImage)
2549 {
2550 Guid emptyUUID;
2551 CHECK_ERROR(virtualBox, OpenDVDImage(Bstr(dvd), emptyUUID, dvdImage.asOutParam()));
2552 }
2553 }
2554 if (!dvdImage)
2555 {
2556 rc = E_FAIL;
2557 break;
2558 }
2559
2560 dvdImage->COMGETTER(Id)(uuid.asOutParam());
2561 CHECK_ERROR(dvdDrive, MountImage(uuid));
2562 }
2563 }
2564 if (dvdpassthrough)
2565 {
2566 ComPtr<IDVDDrive> dvdDrive;
2567 machine->COMGETTER(DVDDrive)(dvdDrive.asOutParam());
2568 ASSERT(dvdDrive);
2569
2570 CHECK_ERROR(dvdDrive, COMSETTER(Passthrough)(strcmp(dvdpassthrough, "on") == 0));
2571 }
2572 if (idecontroller)
2573 {
2574 if (RTStrICmp(idecontroller, "PIIX3") == 0)
2575 {
2576 CHECK_ERROR(biosSettings, COMSETTER(IDEControllerType)(IDEControllerType_PIIX3));
2577 }
2578 else if (RTStrICmp(idecontroller, "PIIX4") == 0)
2579 {
2580 CHECK_ERROR(biosSettings, COMSETTER(IDEControllerType)(IDEControllerType_PIIX4));
2581 }
2582 else
2583 {
2584 errorArgument("Invalid -idecontroller argument '%s'", idecontroller);
2585 rc = E_FAIL;
2586 break;
2587 }
2588 }
2589 if (floppy)
2590 {
2591 ComPtr<IFloppyDrive> floppyDrive;
2592 machine->COMGETTER(FloppyDrive)(floppyDrive.asOutParam());
2593 ASSERT(floppyDrive);
2594
2595 /* disable? */
2596 if (strcmp(floppy, "disabled") == 0)
2597 {
2598 /* disable the controller */
2599 CHECK_ERROR(floppyDrive, COMSETTER(Enabled)(false));
2600 }
2601 else
2602 {
2603 /* enable the controller */
2604 CHECK_ERROR(floppyDrive, COMSETTER(Enabled)(true));
2605
2606 /* unmount? */
2607 if (strcmp(floppy, "empty") == 0)
2608 {
2609 CHECK_ERROR(floppyDrive, Unmount());
2610 }
2611 /* host drive? */
2612 else if (strncmp(floppy, "host:", 5) == 0)
2613 {
2614 ComPtr<IHost> host;
2615 CHECK_ERROR(virtualBox, COMGETTER(Host)(host.asOutParam()));
2616 ComPtr<IHostFloppyDriveCollection> hostFloppies;
2617 CHECK_ERROR(host, COMGETTER(FloppyDrives)(hostFloppies.asOutParam()));
2618 ComPtr<IHostFloppyDrive> hostFloppyDrive;
2619 rc = hostFloppies->FindByName(Bstr(floppy + 5), hostFloppyDrive.asOutParam());
2620 if (!hostFloppyDrive)
2621 {
2622 errorArgument("Invalid host floppy drive name");
2623 rc = E_FAIL;
2624 break;
2625 }
2626 CHECK_ERROR(floppyDrive, CaptureHostDrive(hostFloppyDrive));
2627 }
2628 else
2629 {
2630 /* first assume it's a UUID */
2631 Guid uuid(floppy);
2632 ComPtr<IFloppyImage2> floppyImage;
2633 rc = virtualBox->GetFloppyImage(uuid, floppyImage.asOutParam());
2634 if (FAILED(rc) || !floppyImage)
2635 {
2636 /* must be a filename, check if it's in the collection */
2637 rc = virtualBox->FindFloppyImage(Bstr(floppy), floppyImage.asOutParam());
2638 /* not registered, do that on the fly */
2639 if (!floppyImage)
2640 {
2641 Guid emptyUUID;
2642 CHECK_ERROR(virtualBox, OpenFloppyImage(Bstr(floppy), emptyUUID, floppyImage.asOutParam()));
2643 }
2644 }
2645 if (!floppyImage)
2646 {
2647 rc = E_FAIL;
2648 break;
2649 }
2650
2651 floppyImage->COMGETTER(Id)(uuid.asOutParam());
2652 CHECK_ERROR(floppyDrive, MountImage(uuid));
2653 }
2654 }
2655 }
2656 if (audio || audiocontroller)
2657 {
2658 ComPtr<IAudioAdapter> audioAdapter;
2659 machine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam());
2660 ASSERT(audioAdapter);
2661
2662 if (audio)
2663 {
2664 /* disable? */
2665 if (strcmp(audio, "none") == 0)
2666 {
2667 CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(false));
2668 }
2669 else if (strcmp(audio, "null") == 0)
2670 {
2671 CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_Null));
2672 CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
2673 }
2674#ifdef RT_OS_WINDOWS
2675#ifdef VBOX_WITH_WINMM
2676 else if (strcmp(audio, "winmm") == 0)
2677 {
2678 CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_WinMM));
2679 CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
2680 }
2681#endif
2682 else if (strcmp(audio, "dsound") == 0)
2683 {
2684 CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_DirectSound));
2685 CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
2686 }
2687#endif /* RT_OS_WINDOWS */
2688#ifdef RT_OS_LINUX
2689 else if (strcmp(audio, "oss") == 0)
2690 {
2691 CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_OSS));
2692 CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
2693 }
2694# ifdef VBOX_WITH_ALSA
2695 else if (strcmp(audio, "alsa") == 0)
2696 {
2697 CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_ALSA));
2698 CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
2699 }
2700# endif
2701# ifdef VBOX_WITH_PULSE
2702 else if (strcmp(audio, "pulse") == 0)
2703 {
2704 CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_Pulse));
2705 CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
2706 }
2707# endif
2708#endif /* !RT_OS_LINUX */
2709#ifdef RT_OS_SOLARIS
2710 else if (strcmp(audio, "solaudio") == 0)
2711 {
2712 CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_SolAudio));
2713 CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
2714 }
2715
2716#endif /* !RT_OS_SOLARIS */
2717#ifdef RT_OS_DARWIN
2718 else if (strcmp(audio, "coreaudio") == 0)
2719 {
2720 CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_CoreAudio));
2721 CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
2722 }
2723
2724#endif /* !RT_OS_DARWIN */
2725 else
2726 {
2727 errorArgument("Invalid -audio argument '%s'", audio);
2728 rc = E_FAIL;
2729 break;
2730 }
2731 }
2732 if (audiocontroller)
2733 {
2734 if (strcmp(audiocontroller, "sb16") == 0)
2735 CHECK_ERROR(audioAdapter, COMSETTER(AudioController)(AudioControllerType_SB16));
2736 else if (strcmp(audiocontroller, "ac97") == 0)
2737 CHECK_ERROR(audioAdapter, COMSETTER(AudioController)(AudioControllerType_AC97));
2738 else
2739 {
2740 errorArgument("Invalid -audiocontroller argument '%s'", audiocontroller);
2741 rc = E_FAIL;
2742 break;
2743 }
2744 }
2745 }
2746 /* Shared clipboard state */
2747 if (clipboard)
2748 {
2749/* ComPtr<IClipboardMode> clipboardMode;
2750 machine->COMGETTER(ClipboardMode)(clipboardMode.asOutParam());
2751 ASSERT(clipboardMode);
2752*/
2753 if (strcmp(clipboard, "disabled") == 0)
2754 {
2755 CHECK_ERROR(machine, COMSETTER(ClipboardMode)(ClipboardMode_Disabled));
2756 }
2757 else if (strcmp(clipboard, "hosttoguest") == 0)
2758 {
2759 CHECK_ERROR(machine, COMSETTER(ClipboardMode)(ClipboardMode_HostToGuest));
2760 }
2761 else if (strcmp(clipboard, "guesttohost") == 0)
2762 {
2763 CHECK_ERROR(machine, COMSETTER(ClipboardMode)(ClipboardMode_GuestToHost));
2764 }
2765 else if (strcmp(clipboard, "bidirectional") == 0)
2766 {
2767 CHECK_ERROR(machine, COMSETTER(ClipboardMode)(ClipboardMode_Bidirectional));
2768 }
2769 else
2770 {
2771 errorArgument("Invalid -clipboard argument '%s'", clipboard);
2772 rc = E_FAIL;
2773 break;
2774 }
2775 }
2776 /* iterate through all possible NICs */
2777 for (ULONG n = 0; n < NetworkAdapterCount; n ++)
2778 {
2779 ComPtr<INetworkAdapter> nic;
2780 CHECK_ERROR_RET (machine, GetNetworkAdapter (n, nic.asOutParam()), 1);
2781
2782 ASSERT(nic);
2783
2784 /* something about the NIC? */
2785 if (nics[n])
2786 {
2787 if (strcmp(nics[n], "none") == 0)
2788 {
2789 CHECK_ERROR_RET(nic, COMSETTER(Enabled) (FALSE), 1);
2790 }
2791 else if (strcmp(nics[n], "null") == 0)
2792 {
2793 CHECK_ERROR_RET(nic, COMSETTER(Enabled) (TRUE), 1);
2794 CHECK_ERROR_RET(nic, Detach(), 1);
2795 }
2796 else if (strcmp(nics[n], "nat") == 0)
2797 {
2798 CHECK_ERROR_RET(nic, COMSETTER(Enabled) (TRUE), 1);
2799 CHECK_ERROR_RET(nic, AttachToNAT(), 1);
2800 }
2801 else if (strcmp(nics[n], "hostif") == 0)
2802 {
2803 CHECK_ERROR_RET(nic, COMSETTER(Enabled) (TRUE), 1);
2804 CHECK_ERROR_RET(nic, AttachToHostInterface(), 1);
2805 }
2806 else if (strcmp(nics[n], "intnet") == 0)
2807 {
2808 CHECK_ERROR_RET(nic, COMSETTER(Enabled) (TRUE), 1);
2809 CHECK_ERROR_RET(nic, AttachToInternalNetwork(), 1);
2810 }
2811 else
2812 {
2813 errorArgument("Invalid type '%s' specfied for NIC %lu", nics[n], n + 1);
2814 rc = E_FAIL;
2815 break;
2816 }
2817 }
2818
2819 /* something about the NIC type? */
2820 if (nictype[n])
2821 {
2822 if (strcmp(nictype[n], "Am79C970A") == 0)
2823 {
2824 CHECK_ERROR_RET(nic, COMSETTER(AdapterType)(NetworkAdapterType_Am79C970A), 1);
2825 }
2826 else if (strcmp(nictype[n], "Am79C973") == 0)
2827 {
2828 CHECK_ERROR_RET(nic, COMSETTER(AdapterType)(NetworkAdapterType_Am79C973), 1);
2829 }
2830#ifdef VBOX_WITH_E1000
2831 else if (strcmp(nictype[n], "82540EM") == 0)
2832 {
2833 CHECK_ERROR_RET(nic, COMSETTER(AdapterType)(NetworkAdapterType_I82540EM), 1);
2834 }
2835 else if (strcmp(nictype[n], "82543GC") == 0)
2836 {
2837 CHECK_ERROR_RET(nic, COMSETTER(AdapterType)(NetworkAdapterType_I82543GC), 1);
2838 }
2839#endif
2840 else
2841 {
2842 errorArgument("Invalid NIC type '%s' specified for NIC %lu", nictype[n], n + 1);
2843 rc = E_FAIL;
2844 break;
2845 }
2846 }
2847
2848 /* something about the MAC address? */
2849 if (macs[n])
2850 {
2851 /* generate one? */
2852 if (strcmp(macs[n], "auto") == 0)
2853 {
2854 CHECK_ERROR_RET(nic, COMSETTER(MACAddress)(NULL), 1);
2855 }
2856 else
2857 {
2858 CHECK_ERROR_RET(nic, COMSETTER(MACAddress)(Bstr(macs[n])), 1);
2859 }
2860 }
2861
2862 /* something about the reported link speed? */
2863 if (nicspeed[n])
2864 {
2865 uint32_t u32LineSpeed;
2866
2867 u32LineSpeed = atoi(nicspeed[n]);
2868
2869 if (u32LineSpeed < 1000 || u32LineSpeed > 4000000)
2870 {
2871 errorArgument("Invalid -nicspeed%lu argument '%s'", n + 1, nicspeed[n]);
2872 rc = E_FAIL;
2873 break;
2874 }
2875 CHECK_ERROR_RET(nic, COMSETTER(LineSpeed)(u32LineSpeed), 1);
2876 }
2877
2878 /* the link status flag? */
2879 if (cableconnected[n])
2880 {
2881 if (strcmp(cableconnected[n], "on") == 0)
2882 {
2883 CHECK_ERROR_RET(nic, COMSETTER(CableConnected)(TRUE), 1);
2884 }
2885 else if (strcmp(cableconnected[n], "off") == 0)
2886 {
2887 CHECK_ERROR_RET(nic, COMSETTER(CableConnected)(FALSE), 1);
2888 }
2889 else
2890 {
2891 errorArgument("Invalid -cableconnected%lu argument '%s'", n + 1, cableconnected[n]);
2892 rc = E_FAIL;
2893 break;
2894 }
2895 }
2896
2897 /* the trace flag? */
2898 if (nictrace[n])
2899 {
2900 if (strcmp(nictrace[n], "on") == 0)
2901 {
2902 CHECK_ERROR_RET(nic, COMSETTER(TraceEnabled)(TRUE), 1);
2903 }
2904 else if (strcmp(nictrace[n], "off") == 0)
2905 {
2906 CHECK_ERROR_RET(nic, COMSETTER(TraceEnabled)(FALSE), 1);
2907 }
2908 else
2909 {
2910 errorArgument("Invalid -nictrace%lu argument '%s'", n + 1, nictrace[n]);
2911 rc = E_FAIL;
2912 break;
2913 }
2914 }
2915
2916 /* the tracefile flag? */
2917 if (nictracefile[n])
2918 {
2919 CHECK_ERROR_RET(nic, COMSETTER(TraceFile)(Bstr(nictracefile[n])), 1);
2920 }
2921
2922 /* the host interface device? */
2923 if (hostifdev[n])
2924 {
2925 /* remove it? */
2926 if (strcmp(hostifdev[n], "none") == 0)
2927 {
2928 CHECK_ERROR_RET(nic, COMSETTER(HostInterface)(NULL), 1);
2929 }
2930 else
2931 {
2932 CHECK_ERROR_RET(nic, COMSETTER(HostInterface)(Bstr(hostifdev[n])), 1);
2933 }
2934 }
2935
2936 /* the internal network name? */
2937 if (intnet[n])
2938 {
2939 /* remove it? */
2940 if (strcmp(intnet[n], "none") == 0)
2941 {
2942 CHECK_ERROR_RET(nic, COMSETTER(InternalNetwork)(NULL), 1);
2943 }
2944 else
2945 {
2946 CHECK_ERROR_RET(nic, COMSETTER(InternalNetwork)(Bstr(intnet[n])), 1);
2947 }
2948 }
2949 /* the network of the NAT */
2950 if (natnet[n])
2951 {
2952 CHECK_ERROR_RET(nic, COMSETTER(NATNetwork)(Bstr(natnet[n])), 1);
2953 }
2954#ifdef RT_OS_LINUX
2955 /* the TAP setup application? */
2956 if (tapsetup[n])
2957 {
2958 /* remove it? */
2959 if (strcmp(tapsetup[n], "none") == 0)
2960 {
2961 CHECK_ERROR_RET(nic, COMSETTER(TAPSetupApplication)(NULL), 1);
2962 }
2963 else
2964 {
2965 CHECK_ERROR_RET(nic, COMSETTER(TAPSetupApplication)(Bstr(tapsetup[n])), 1);
2966 }
2967 }
2968
2969 /* the TAP terminate application? */
2970 if (tapterm[n])
2971 {
2972 /* remove it? */
2973 if (strcmp(tapterm[n], "none") == 0)
2974 {
2975 CHECK_ERROR_RET(nic, COMSETTER(TAPTerminateApplication)(NULL), 1);
2976 }
2977 else
2978 {
2979 CHECK_ERROR_RET(nic, COMSETTER(TAPTerminateApplication)(Bstr(tapterm[n])), 1);
2980 }
2981 }
2982#endif /* RT_OS_LINUX */
2983
2984 }
2985 if (FAILED(rc))
2986 break;
2987
2988 /* iterate through all possible serial ports */
2989 for (ULONG n = 0; n < SerialPortCount; n ++)
2990 {
2991 ComPtr<ISerialPort> uart;
2992 CHECK_ERROR_RET (machine, GetSerialPort (n, uart.asOutParam()), 1);
2993
2994 ASSERT(uart);
2995
2996 if (uarts_base[n])
2997 {
2998 if (uarts_base[n] == (ULONG)-1)
2999 {
3000 CHECK_ERROR_RET(uart, COMSETTER(Enabled) (FALSE), 1);
3001 }
3002 else
3003 {
3004 CHECK_ERROR_RET(uart, COMSETTER(IOBase) (uarts_base[n]), 1);
3005 CHECK_ERROR_RET(uart, COMSETTER(IRQ) (uarts_irq[n]), 1);
3006 CHECK_ERROR_RET(uart, COMSETTER(Enabled) (TRUE), 1);
3007 }
3008 }
3009 if (uarts_mode[n])
3010 {
3011 if (strcmp(uarts_mode[n], "disconnected") == 0)
3012 {
3013 CHECK_ERROR_RET(uart, COMSETTER(HostMode) (PortMode_Disconnected), 1);
3014 }
3015 else
3016 {
3017 if (strcmp(uarts_mode[n], "server") == 0)
3018 {
3019 CHECK_ERROR_RET(uart, COMSETTER(HostMode) (PortMode_HostPipe), 1);
3020 CHECK_ERROR_RET(uart, COMSETTER(Server) (TRUE), 1);
3021 }
3022 else if (strcmp(uarts_mode[n], "client") == 0)
3023 {
3024 CHECK_ERROR_RET(uart, COMSETTER(HostMode) (PortMode_HostPipe), 1);
3025 CHECK_ERROR_RET(uart, COMSETTER(Server) (FALSE), 1);
3026 }
3027 else
3028 {
3029 CHECK_ERROR_RET(uart, COMSETTER(HostMode) (PortMode_HostDevice), 1);
3030 }
3031 CHECK_ERROR_RET(uart, COMSETTER(Path) (Bstr(uarts_path[n])), 1);
3032 }
3033 }
3034 }
3035 if (FAILED(rc))
3036 break;
3037
3038#ifdef VBOX_WITH_VRDP
3039 if (vrdp || (vrdpport != UINT16_MAX) || vrdpaddress || vrdpauthtype || vrdpmulticon || vrdpreusecon)
3040 {
3041 ComPtr<IVRDPServer> vrdpServer;
3042 machine->COMGETTER(VRDPServer)(vrdpServer.asOutParam());
3043 ASSERT(vrdpServer);
3044 if (vrdpServer)
3045 {
3046 if (vrdp)
3047 {
3048 if (strcmp(vrdp, "on") == 0)
3049 {
3050 CHECK_ERROR(vrdpServer, COMSETTER(Enabled)(true));
3051 }
3052 else if (strcmp(vrdp, "off") == 0)
3053 {
3054 CHECK_ERROR(vrdpServer, COMSETTER(Enabled)(false));
3055 }
3056 else
3057 {
3058 errorArgument("Invalid -vrdp argument '%s'", vrdp);
3059 rc = E_FAIL;
3060 break;
3061 }
3062 }
3063 if (vrdpport != UINT16_MAX)
3064 {
3065 CHECK_ERROR(vrdpServer, COMSETTER(Port)(vrdpport));
3066 }
3067 if (vrdpaddress)
3068 {
3069 CHECK_ERROR(vrdpServer, COMSETTER(NetAddress)(Bstr(vrdpaddress)));
3070 }
3071 if (vrdpauthtype)
3072 {
3073 if (strcmp(vrdpauthtype, "null") == 0)
3074 {
3075 CHECK_ERROR(vrdpServer, COMSETTER(AuthType)(VRDPAuthType_Null));
3076 }
3077 else if (strcmp(vrdpauthtype, "external") == 0)
3078 {
3079 CHECK_ERROR(vrdpServer, COMSETTER(AuthType)(VRDPAuthType_External));
3080 }
3081 else if (strcmp(vrdpauthtype, "guest") == 0)
3082 {
3083 CHECK_ERROR(vrdpServer, COMSETTER(AuthType)(VRDPAuthType_Guest));
3084 }
3085 else
3086 {
3087 errorArgument("Invalid -vrdpauthtype argument '%s'", vrdpauthtype);
3088 rc = E_FAIL;
3089 break;
3090 }
3091 }
3092 if (vrdpmulticon)
3093 {
3094 if (strcmp(vrdpmulticon, "on") == 0)
3095 {
3096 CHECK_ERROR(vrdpServer, COMSETTER(AllowMultiConnection)(true));
3097 }
3098 else if (strcmp(vrdpmulticon, "off") == 0)
3099 {
3100 CHECK_ERROR(vrdpServer, COMSETTER(AllowMultiConnection)(false));
3101 }
3102 else
3103 {
3104 errorArgument("Invalid -vrdpmulticon argument '%s'", vrdpmulticon);
3105 rc = E_FAIL;
3106 break;
3107 }
3108 }
3109 if (vrdpreusecon)
3110 {
3111 if (strcmp(vrdpreusecon, "on") == 0)
3112 {
3113 CHECK_ERROR(vrdpServer, COMSETTER(ReuseSingleConnection)(true));
3114 }
3115 else if (strcmp(vrdpreusecon, "off") == 0)
3116 {
3117 CHECK_ERROR(vrdpServer, COMSETTER(ReuseSingleConnection)(false));
3118 }
3119 else
3120 {
3121 errorArgument("Invalid -vrdpreusecon argument '%s'", vrdpreusecon);
3122 rc = E_FAIL;
3123 break;
3124 }
3125 }
3126 }
3127 }
3128#endif /* VBOX_WITH_VRDP */
3129
3130 /*
3131 * USB enable/disable
3132 */
3133 if (fUsbEnabled != -1)
3134 {
3135 ComPtr<IUSBController> UsbCtl;
3136 CHECK_ERROR(machine, COMGETTER(USBController)(UsbCtl.asOutParam()));
3137 if (SUCCEEDED(rc))
3138 {
3139 CHECK_ERROR(UsbCtl, COMSETTER(Enabled)(!!fUsbEnabled));
3140 }
3141 }
3142 /*
3143 * USB EHCI enable/disable
3144 */
3145 if (fUsbEhciEnabled != -1)
3146 {
3147 ComPtr<IUSBController> UsbCtl;
3148 CHECK_ERROR(machine, COMGETTER(USBController)(UsbCtl.asOutParam()));
3149 if (SUCCEEDED(rc))
3150 {
3151 CHECK_ERROR(UsbCtl, COMSETTER(EnabledEhci)(!!fUsbEhciEnabled));
3152 }
3153 }
3154
3155 if (snapshotFolder)
3156 {
3157 if (strcmp(snapshotFolder, "default") == 0)
3158 {
3159 CHECK_ERROR(machine, COMSETTER(SnapshotFolder)(NULL));
3160 }
3161 else
3162 {
3163 CHECK_ERROR(machine, COMSETTER(SnapshotFolder)(Bstr(snapshotFolder)));
3164 }
3165 }
3166
3167 if (guestMemBalloonSize != (ULONG)-1)
3168 CHECK_ERROR(machine, COMSETTER(MemoryBalloonSize)(guestMemBalloonSize));
3169
3170 if (guestStatInterval != (ULONG)-1)
3171 CHECK_ERROR(machine, COMSETTER(StatisticsUpdateInterval)(guestStatInterval));
3172
3173 /*
3174 * SATA controller enable/disable
3175 */
3176 if (fSataEnabled != -1)
3177 {
3178 ComPtr<ISATAController> SataCtl;
3179 CHECK_ERROR(machine, COMGETTER(SATAController)(SataCtl.asOutParam()));
3180 if (SUCCEEDED(rc))
3181 {
3182 CHECK_ERROR(SataCtl, COMSETTER(Enabled)(!!fSataEnabled));
3183 }
3184 }
3185
3186 for (uint32_t i = 4; i < 34; i++)
3187 {
3188 if (hdds[i])
3189 {
3190 if (strcmp(hdds[i], "none") == 0)
3191 {
3192 machine->DetachHardDisk2(StorageBus_SATA, i-4, 0);
3193 }
3194 else
3195 {
3196 /* first guess is that it's a UUID */
3197 Guid uuid(hdds[i]);
3198 ComPtr<IHardDisk2> hardDisk;
3199 rc = virtualBox->GetHardDisk2(uuid, hardDisk.asOutParam());
3200 /* not successful? Then it must be a filename */
3201 if (!hardDisk)
3202 {
3203 CHECK_ERROR(virtualBox, FindHardDisk2(Bstr(hdds[i]), hardDisk.asOutParam()));
3204 if (FAILED(rc))
3205 {
3206 /* open the new hard disk object */
3207 CHECK_ERROR(virtualBox, OpenHardDisk2(Bstr(hdds[i]), hardDisk.asOutParam()));
3208 }
3209 }
3210 if (hardDisk)
3211 {
3212 hardDisk->COMGETTER(Id)(uuid.asOutParam());
3213 CHECK_ERROR(machine, AttachHardDisk2(uuid, StorageBus_SATA, i-4, 0));
3214 }
3215 else
3216 rc = E_FAIL;
3217 if (FAILED(rc))
3218 break;
3219 }
3220 }
3221 }
3222
3223 for (uint32_t i = 0; i < 4; i++)
3224 {
3225 if (sataBootDevices[i] != -1)
3226 {
3227 ComPtr<ISATAController> SataCtl;
3228 CHECK_ERROR(machine, COMGETTER(SATAController)(SataCtl.asOutParam()));
3229 if (SUCCEEDED(rc))
3230 {
3231 CHECK_ERROR(SataCtl, SetIDEEmulationPort(i, sataBootDevices[i]));
3232 }
3233 }
3234 }
3235
3236 if (sataPortCount != -1)
3237 {
3238 ComPtr<ISATAController> SataCtl;
3239 CHECK_ERROR(machine, COMGETTER(SATAController)(SataCtl.asOutParam()));
3240 if (SUCCEEDED(rc))
3241 {
3242 CHECK_ERROR(SataCtl, COMSETTER(PortCount)(sataPortCount));
3243 }
3244 }
3245
3246 /* commit changes */
3247 CHECK_ERROR(machine, SaveSettings());
3248 }
3249 while (0);
3250
3251 /* it's important to always close sessions */
3252 session->Close();
3253
3254 return SUCCEEDED(rc) ? 0 : 1;
3255}
3256
3257static int handleStartVM(int argc, char *argv[],
3258 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
3259{
3260 HRESULT rc;
3261
3262 if (argc < 1)
3263 return errorSyntax(USAGE_STARTVM, "Not enough parameters");
3264
3265 ComPtr<IMachine> machine;
3266 /* assume it's a UUID */
3267 rc = virtualBox->GetMachine(Guid(argv[0]), machine.asOutParam());
3268 if (FAILED(rc) || !machine)
3269 {
3270 /* must be a name */
3271 CHECK_ERROR(virtualBox, FindMachine(Bstr(argv[0]), machine.asOutParam()));
3272 }
3273 if (machine)
3274 {
3275 Guid uuid;
3276 machine->COMGETTER(Id)(uuid.asOutParam());
3277
3278 /* default to GUI session type */
3279 Bstr sessionType = "gui";
3280 /* has a session type been specified? */
3281 if ((argc > 2) && (strcmp(argv[1], "-type") == 0))
3282 {
3283 if (strcmp(argv[2], "gui") == 0)
3284 {
3285 sessionType = "gui";
3286 }
3287 else if (strcmp(argv[2], "vrdp") == 0)
3288 {
3289 sessionType = "vrdp";
3290 }
3291 else if (strcmp(argv[2], "capture") == 0)
3292 {
3293 sessionType = "capture";
3294 }
3295 else
3296 return errorArgument("Invalid session type argument '%s'", argv[2]);
3297 }
3298
3299 Bstr env;
3300#ifdef RT_OS_LINUX
3301 /* make sure the VM process will start on the same display as VBoxManage */
3302 {
3303 const char *display = RTEnvGet ("DISPLAY");
3304 if (display)
3305 env = Utf8StrFmt ("DISPLAY=%s", display);
3306 }
3307#endif
3308 ComPtr<IProgress> progress;
3309 CHECK_ERROR_RET(virtualBox, OpenRemoteSession(session, uuid, sessionType,
3310 env, progress.asOutParam()), rc);
3311 RTPrintf("Waiting for the remote session to open...\n");
3312 CHECK_ERROR_RET(progress, WaitForCompletion (-1), 1);
3313
3314 BOOL completed;
3315 CHECK_ERROR_RET(progress, COMGETTER(Completed)(&completed), rc);
3316 ASSERT(completed);
3317
3318 HRESULT resultCode;
3319 CHECK_ERROR_RET(progress, COMGETTER(ResultCode)(&resultCode), rc);
3320 if (FAILED(resultCode))
3321 {
3322 ComPtr <IVirtualBoxErrorInfo> errorInfo;
3323 CHECK_ERROR_RET(progress, COMGETTER(ErrorInfo)(errorInfo.asOutParam()), 1);
3324 ErrorInfo info (errorInfo);
3325 PRINT_ERROR_INFO(info);
3326 }
3327 else
3328 {
3329 RTPrintf("Remote session has been successfully opened.\n");
3330 }
3331 }
3332
3333 /* it's important to always close sessions */
3334 session->Close();
3335
3336 return SUCCEEDED(rc) ? 0 : 1;
3337}
3338
3339static int handleControlVM(int argc, char *argv[],
3340 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
3341{
3342 HRESULT rc;
3343
3344 if (argc < 2)
3345 return errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
3346
3347 /* try to find the given machine */
3348 ComPtr <IMachine> machine;
3349 Guid uuid (argv[0]);
3350 if (!uuid.isEmpty())
3351 {
3352 CHECK_ERROR (virtualBox, GetMachine (uuid, machine.asOutParam()));
3353 }
3354 else
3355 {
3356 CHECK_ERROR (virtualBox, FindMachine (Bstr(argv[0]), machine.asOutParam()));
3357 if (SUCCEEDED (rc))
3358 machine->COMGETTER(Id) (uuid.asOutParam());
3359 }
3360 if (FAILED (rc))
3361 return 1;
3362
3363 /* open a session for the VM */
3364 CHECK_ERROR_RET (virtualBox, OpenExistingSession (session, uuid), 1);
3365
3366 do
3367 {
3368 /* get the associated console */
3369 ComPtr<IConsole> console;
3370 CHECK_ERROR_BREAK (session, COMGETTER(Console)(console.asOutParam()));
3371 /* ... and session machine */
3372 ComPtr<IMachine> sessionMachine;
3373 CHECK_ERROR_BREAK (session, COMGETTER(Machine)(sessionMachine.asOutParam()));
3374
3375 /* which command? */
3376 if (strcmp(argv[1], "pause") == 0)
3377 {
3378 CHECK_ERROR_BREAK (console, Pause());
3379 }
3380 else if (strcmp(argv[1], "resume") == 0)
3381 {
3382 CHECK_ERROR_BREAK (console, Resume());
3383 }
3384 else if (strcmp(argv[1], "reset") == 0)
3385 {
3386 CHECK_ERROR_BREAK (console, Reset());
3387 }
3388 else if (strcmp(argv[1], "poweroff") == 0)
3389 {
3390 CHECK_ERROR_BREAK (console, PowerDown());
3391 }
3392 else if (strcmp(argv[1], "savestate") == 0)
3393 {
3394 ComPtr<IProgress> progress;
3395 CHECK_ERROR_BREAK (console, SaveState(progress.asOutParam()));
3396
3397 showProgress(progress);
3398
3399 progress->COMGETTER(ResultCode)(&rc);
3400 if (FAILED(rc))
3401 {
3402 com::ProgressErrorInfo info(progress);
3403 if (info.isBasicAvailable())
3404 {
3405 RTPrintf("Error: failed to save machine state. Error message: %lS\n", info.getText().raw());
3406 }
3407 else
3408 {
3409 RTPrintf("Error: failed to save machine state. No error message available!\n");
3410 }
3411 }
3412 }
3413 else if (strcmp(argv[1], "acpipowerbutton") == 0)
3414 {
3415 CHECK_ERROR_BREAK (console, PowerButton());
3416 }
3417 else if (strcmp(argv[1], "acpisleepbutton") == 0)
3418 {
3419 CHECK_ERROR_BREAK (console, SleepButton());
3420 }
3421 else if (strcmp(argv[1], "injectnmi") == 0)
3422 {
3423 /* get the machine debugger. */
3424 ComPtr <IMachineDebugger> debugger;
3425 CHECK_ERROR_BREAK(console, COMGETTER(Debugger)(debugger.asOutParam()));
3426 CHECK_ERROR_BREAK(debugger, InjectNMI());
3427 }
3428 else if (strcmp(argv[1], "keyboardputscancode") == 0)
3429 {
3430 ComPtr<IKeyboard> keyboard;
3431 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(keyboard.asOutParam()));
3432
3433 if (argc <= 1 + 1)
3434 {
3435 errorArgument("Missing argument to '%s'. Expected IBM PC AT set 2 keyboard scancode(s) as hex byte(s).", argv[1]);
3436 rc = E_FAIL;
3437 break;
3438 }
3439
3440 /* Arbitrary restrict the length of a sequence of scancodes to 1024. */
3441 LONG alScancodes[1024];
3442 int cScancodes = 0;
3443
3444 /* Process the command line. */
3445 int i;
3446 for (i = 1 + 1; i < argc && cScancodes < (int)RT_ELEMENTS(alScancodes); i++, cScancodes++)
3447 {
3448 if ( isxdigit (argv[i][0])
3449 && isxdigit (argv[i][1])
3450 && argv[i][2] == 0)
3451 {
3452 uint8_t u8Scancode;
3453 int rc = RTStrToUInt8Ex(argv[i], NULL, 16, &u8Scancode);
3454 if (RT_FAILURE (rc))
3455 {
3456 RTPrintf("Error: converting '%s' returned %Rrc!\n", argv[i], rc);
3457 rc = E_FAIL;
3458 break;
3459 }
3460
3461 alScancodes[cScancodes] = u8Scancode;
3462 }
3463 else
3464 {
3465 RTPrintf("Error: '%s' is not a hex byte!\n", argv[i]);
3466 rc = E_FAIL;
3467 break;
3468 }
3469 }
3470
3471 if (FAILED(rc))
3472 break;
3473
3474 if ( cScancodes == RT_ELEMENTS(alScancodes)
3475 && i < argc)
3476 {
3477 RTPrintf("Error: too many scancodes, maximum %d allowed!\n", RT_ELEMENTS(alScancodes));
3478 rc = E_FAIL;
3479 break;
3480 }
3481
3482 /* Send scancodes to the VM.
3483 * Note: 'PutScancodes' did not work here. Only the first scancode was transmitted.
3484 */
3485 for (i = 0; i < cScancodes; i++)
3486 {
3487 CHECK_ERROR_BREAK(keyboard, PutScancode(alScancodes[i]));
3488 RTPrintf("Scancode[%d]: 0x%02X\n", i, alScancodes[i]);
3489 }
3490 }
3491 else if (strncmp(argv[1], "setlinkstate", 12) == 0)
3492 {
3493 /* Get the number of network adapters */
3494 ULONG NetworkAdapterCount = 0;
3495 ComPtr <ISystemProperties> info;
3496 CHECK_ERROR_BREAK (virtualBox, COMGETTER(SystemProperties) (info.asOutParam()));
3497 CHECK_ERROR_BREAK (info, COMGETTER(NetworkAdapterCount) (&NetworkAdapterCount));
3498
3499 unsigned n = parseNum(&argv[1][12], NetworkAdapterCount, "NIC");
3500 if (!n)
3501 {
3502 rc = E_FAIL;
3503 break;
3504 }
3505 if (argc <= 1 + 1)
3506 {
3507 errorArgument("Missing argument to '%s'", argv[1]);
3508 rc = E_FAIL;
3509 break;
3510 }
3511 /* get the corresponding network adapter */
3512 ComPtr<INetworkAdapter> adapter;
3513 CHECK_ERROR_BREAK (sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
3514 if (adapter)
3515 {
3516 if (strcmp(argv[2], "on") == 0)
3517 {
3518 CHECK_ERROR_BREAK (adapter, COMSETTER(CableConnected)(TRUE));
3519 }
3520 else if (strcmp(argv[2], "off") == 0)
3521 {
3522 CHECK_ERROR_BREAK (adapter, COMSETTER(CableConnected)(FALSE));
3523 }
3524 else
3525 {
3526 errorArgument("Invalid link state '%s'", Utf8Str(argv[2]).raw());
3527 rc = E_FAIL;
3528 break;
3529 }
3530 }
3531 }
3532 else if (strcmp (argv[1], "usbattach") == 0 ||
3533 strcmp (argv[1], "usbdetach") == 0)
3534 {
3535 if (argc < 3)
3536 {
3537 errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
3538 rc = E_FAIL;
3539 break;
3540 }
3541
3542 bool attach = strcmp (argv[1], "usbattach") == 0;
3543
3544 Guid usbId = argv [2];
3545 if (usbId.isEmpty())
3546 {
3547 // assume address
3548 if (attach)
3549 {
3550 ComPtr <IHost> host;
3551 CHECK_ERROR_BREAK (virtualBox, COMGETTER(Host) (host.asOutParam()));
3552 ComPtr <IHostUSBDeviceCollection> coll;
3553 CHECK_ERROR_BREAK (host, COMGETTER(USBDevices) (coll.asOutParam()));
3554 ComPtr <IHostUSBDevice> dev;
3555 CHECK_ERROR_BREAK (coll, FindByAddress (Bstr (argv [2]), dev.asOutParam()));
3556 CHECK_ERROR_BREAK (dev, COMGETTER(Id) (usbId.asOutParam()));
3557 }
3558 else
3559 {
3560 ComPtr <IUSBDeviceCollection> coll;
3561 CHECK_ERROR_BREAK (console, COMGETTER(USBDevices)(coll.asOutParam()));
3562 ComPtr <IUSBDevice> dev;
3563 CHECK_ERROR_BREAK (coll, FindByAddress (Bstr (argv [2]), dev.asOutParam()));
3564 CHECK_ERROR_BREAK (dev, COMGETTER(Id) (usbId.asOutParam()));
3565 }
3566 }
3567
3568 if (attach)
3569 CHECK_ERROR_BREAK (console, AttachUSBDevice (usbId));
3570 else
3571 {
3572 ComPtr <IUSBDevice> dev;
3573 CHECK_ERROR_BREAK (console, DetachUSBDevice (usbId, dev.asOutParam()));
3574 }
3575 }
3576 else if (strcmp(argv[1], "setvideomodehint") == 0)
3577 {
3578 if (argc != 5 && argc != 6)
3579 {
3580 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
3581 rc = E_FAIL;
3582 break;
3583 }
3584 uint32_t xres = atoi(argv[2]);
3585 uint32_t yres = atoi(argv[3]);
3586 uint32_t bpp = atoi(argv[4]);
3587 uint32_t displayIdx = 0;
3588 if (argc == 6)
3589 displayIdx = atoi(argv[5]);
3590
3591 ComPtr<IDisplay> display;
3592 CHECK_ERROR_BREAK(console, COMGETTER(Display)(display.asOutParam()));
3593 CHECK_ERROR_BREAK(display, SetVideoModeHint(xres, yres, bpp, displayIdx));
3594 }
3595 else if (strcmp(argv[1], "setcredentials") == 0)
3596 {
3597 bool fAllowLocalLogon = true;
3598 if (argc == 7)
3599 {
3600 if (strcmp(argv[5], "-allowlocallogon") != 0)
3601 {
3602 errorArgument("Invalid parameter '%s'", argv[5]);
3603 rc = E_FAIL;
3604 break;
3605 }
3606 if (strcmp(argv[6], "no") == 0)
3607 fAllowLocalLogon = false;
3608 }
3609 else if (argc != 5)
3610 {
3611 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
3612 rc = E_FAIL;
3613 break;
3614 }
3615
3616 ComPtr<IGuest> guest;
3617 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(guest.asOutParam()));
3618 CHECK_ERROR_BREAK(guest, SetCredentials(Bstr(argv[2]), Bstr(argv[3]), Bstr(argv[4]), fAllowLocalLogon));
3619 }
3620 else if (strcmp(argv[1], "dvdattach") == 0)
3621 {
3622 if (argc != 3)
3623 {
3624 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
3625 rc = E_FAIL;
3626 break;
3627 }
3628 ComPtr<IDVDDrive> dvdDrive;
3629 sessionMachine->COMGETTER(DVDDrive)(dvdDrive.asOutParam());
3630 ASSERT(dvdDrive);
3631
3632 /* unmount? */
3633 if (strcmp(argv[2], "none") == 0)
3634 {
3635 CHECK_ERROR(dvdDrive, Unmount());
3636 }
3637 /* host drive? */
3638 else if (strncmp(argv[2], "host:", 5) == 0)
3639 {
3640 ComPtr<IHost> host;
3641 CHECK_ERROR(virtualBox, COMGETTER(Host)(host.asOutParam()));
3642 ComPtr<IHostDVDDriveCollection> hostDVDs;
3643 CHECK_ERROR(host, COMGETTER(DVDDrives)(hostDVDs.asOutParam()));
3644 ComPtr<IHostDVDDrive> hostDVDDrive;
3645 rc = hostDVDs->FindByName(Bstr(argv[2] + 5), hostDVDDrive.asOutParam());
3646 if (!hostDVDDrive)
3647 {
3648 errorArgument("Invalid host DVD drive name");
3649 rc = E_FAIL;
3650 break;
3651 }
3652 CHECK_ERROR(dvdDrive, CaptureHostDrive(hostDVDDrive));
3653 }
3654 else
3655 {
3656 /* first assume it's a UUID */
3657 Guid uuid(argv[2]);
3658 ComPtr<IDVDImage2> dvdImage;
3659 rc = virtualBox->GetDVDImage(uuid, dvdImage.asOutParam());
3660 if (FAILED(rc) || !dvdImage)
3661 {
3662 /* must be a filename, check if it's in the collection */
3663 rc = virtualBox->FindDVDImage(Bstr(argv[2]), dvdImage.asOutParam());
3664 /* not registered, do that on the fly */
3665 if (!dvdImage)
3666 {
3667 Guid emptyUUID;
3668 CHECK_ERROR(virtualBox, OpenDVDImage(Bstr(argv[2]), emptyUUID, dvdImage.asOutParam()));
3669 }
3670 }
3671 if (!dvdImage)
3672 {
3673 rc = E_FAIL;
3674 break;
3675 }
3676 dvdImage->COMGETTER(Id)(uuid.asOutParam());
3677 CHECK_ERROR(dvdDrive, MountImage(uuid));
3678 }
3679 }
3680 else if (strcmp(argv[1], "floppyattach") == 0)
3681 {
3682 if (argc != 3)
3683 {
3684 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
3685 rc = E_FAIL;
3686 break;
3687 }
3688
3689 ComPtr<IFloppyDrive> floppyDrive;
3690 sessionMachine->COMGETTER(FloppyDrive)(floppyDrive.asOutParam());
3691 ASSERT(floppyDrive);
3692
3693 /* unmount? */
3694 if (strcmp(argv[2], "none") == 0)
3695 {
3696 CHECK_ERROR(floppyDrive, Unmount());
3697 }
3698 /* host drive? */
3699 else if (strncmp(argv[2], "host:", 5) == 0)
3700 {
3701 ComPtr<IHost> host;
3702 CHECK_ERROR(virtualBox, COMGETTER(Host)(host.asOutParam()));
3703 ComPtr<IHostFloppyDriveCollection> hostFloppies;
3704 CHECK_ERROR(host, COMGETTER(FloppyDrives)(hostFloppies.asOutParam()));
3705 ComPtr<IHostFloppyDrive> hostFloppyDrive;
3706 rc = hostFloppies->FindByName(Bstr(argv[2] + 5), hostFloppyDrive.asOutParam());
3707 if (!hostFloppyDrive)
3708 {
3709 errorArgument("Invalid host floppy drive name");
3710 rc = E_FAIL;
3711 break;
3712 }
3713 CHECK_ERROR(floppyDrive, CaptureHostDrive(hostFloppyDrive));
3714 }
3715 else
3716 {
3717 /* first assume it's a UUID */
3718 Guid uuid(argv[2]);
3719 ComPtr<IFloppyImage2> floppyImage;
3720 rc = virtualBox->GetFloppyImage(uuid, floppyImage.asOutParam());
3721 if (FAILED(rc) || !floppyImage)
3722 {
3723 /* must be a filename, check if it's in the collection */
3724 rc = virtualBox->FindFloppyImage(Bstr(argv[2]), floppyImage.asOutParam());
3725 /* not registered, do that on the fly */
3726 if (!floppyImage)
3727 {
3728 Guid emptyUUID;
3729 CHECK_ERROR(virtualBox, OpenFloppyImage(Bstr(argv[2]), emptyUUID, floppyImage.asOutParam()));
3730 }
3731 }
3732 if (!floppyImage)
3733 {
3734 rc = E_FAIL;
3735 break;
3736 }
3737 floppyImage->COMGETTER(Id)(uuid.asOutParam());
3738 CHECK_ERROR(floppyDrive, MountImage(uuid));
3739 }
3740 }
3741#ifdef VBOX_WITH_MEM_BALLOONING
3742 else if (strncmp(argv[1], "-guestmemoryballoon", 19) == 0)
3743 {
3744 if (argc != 3)
3745 {
3746 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
3747 rc = E_FAIL;
3748 break;
3749 }
3750 uint32_t uVal;
3751 int vrc;
3752 vrc = RTStrToUInt32Ex(argv[2], NULL, 0, &uVal);
3753 if (vrc != VINF_SUCCESS)
3754 {
3755 errorArgument("Error parsing guest memory balloon size '%s'", argv[2]);
3756 rc = E_FAIL;
3757 break;
3758 }
3759
3760 /* guest is running; update IGuest */
3761 ComPtr <IGuest> guest;
3762
3763 rc = console->COMGETTER(Guest)(guest.asOutParam());
3764 if (SUCCEEDED(rc))
3765 CHECK_ERROR(guest, COMSETTER(MemoryBalloonSize)(uVal));
3766 }
3767#endif
3768 else if (strncmp(argv[1], "-gueststatisticsinterval", 24) == 0)
3769 {
3770 if (argc != 3)
3771 {
3772 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
3773 rc = E_FAIL;
3774 break;
3775 }
3776 uint32_t uVal;
3777 int vrc;
3778 vrc = RTStrToUInt32Ex(argv[2], NULL, 0, &uVal);
3779 if (vrc != VINF_SUCCESS)
3780 {
3781 errorArgument("Error parsing guest statistics interval '%s'", argv[2]);
3782 rc = E_FAIL;
3783 break;
3784 }
3785
3786 /* guest is running; update IGuest */
3787 ComPtr <IGuest> guest;
3788
3789 rc = console->COMGETTER(Guest)(guest.asOutParam());
3790 if (SUCCEEDED(rc))
3791 CHECK_ERROR(guest, COMSETTER(StatisticsUpdateInterval)(uVal));
3792 }
3793 else
3794 {
3795 errorSyntax(USAGE_CONTROLVM, "Invalid parameter '%s'", Utf8Str(argv[1]).raw());
3796 rc = E_FAIL;
3797 }
3798 }
3799 while (0);
3800
3801 session->Close();
3802
3803 return SUCCEEDED (rc) ? 0 : 1;
3804}
3805
3806static int handleDiscardState(int argc, char *argv[],
3807 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
3808{
3809 HRESULT rc;
3810
3811 if (argc != 1)
3812 return errorSyntax(USAGE_DISCARDSTATE, "Incorrect number of parameters");
3813
3814 ComPtr<IMachine> machine;
3815 /* assume it's a UUID */
3816 rc = virtualBox->GetMachine(Guid(argv[0]), machine.asOutParam());
3817 if (FAILED(rc) || !machine)
3818 {
3819 /* must be a name */
3820 CHECK_ERROR(virtualBox, FindMachine(Bstr(argv[0]), machine.asOutParam()));
3821 }
3822 if (machine)
3823 {
3824 do
3825 {
3826 /* we have to open a session for this task */
3827 Guid guid;
3828 machine->COMGETTER(Id)(guid.asOutParam());
3829 CHECK_ERROR_BREAK(virtualBox, OpenSession(session, guid));
3830 do
3831 {
3832 ComPtr<IConsole> console;
3833 CHECK_ERROR_BREAK(session, COMGETTER(Console)(console.asOutParam()));
3834 CHECK_ERROR_BREAK(console, DiscardSavedState());
3835 }
3836 while (0);
3837 CHECK_ERROR_BREAK(session, Close());
3838 }
3839 while (0);
3840 }
3841
3842 return SUCCEEDED(rc) ? 0 : 1;
3843}
3844
3845static int handleAdoptdState(int argc, char *argv[],
3846 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
3847{
3848 HRESULT rc;
3849
3850 if (argc != 2)
3851 return errorSyntax(USAGE_ADOPTSTATE, "Incorrect number of parameters");
3852
3853 ComPtr<IMachine> machine;
3854 /* assume it's a UUID */
3855 rc = virtualBox->GetMachine(Guid(argv[0]), machine.asOutParam());
3856 if (FAILED(rc) || !machine)
3857 {
3858 /* must be a name */
3859 CHECK_ERROR(virtualBox, FindMachine(Bstr(argv[0]), machine.asOutParam()));
3860 }
3861 if (machine)
3862 {
3863 do
3864 {
3865 /* we have to open a session for this task */
3866 Guid guid;
3867 machine->COMGETTER(Id)(guid.asOutParam());
3868 CHECK_ERROR_BREAK(virtualBox, OpenSession(session, guid));
3869 do
3870 {
3871 ComPtr<IConsole> console;
3872 CHECK_ERROR_BREAK(session, COMGETTER(Console)(console.asOutParam()));
3873 CHECK_ERROR_BREAK(console, AdoptSavedState (Bstr (argv[1])));
3874 }
3875 while (0);
3876 CHECK_ERROR_BREAK(session, Close());
3877 }
3878 while (0);
3879 }
3880
3881 return SUCCEEDED(rc) ? 0 : 1;
3882}
3883
3884static int handleSnapshot(int argc, char *argv[],
3885 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
3886{
3887 HRESULT rc;
3888
3889 /* we need at least a VM and a command */
3890 if (argc < 2)
3891 return errorSyntax(USAGE_SNAPSHOT, "Not enough parameters");
3892
3893 /* the first argument must be the VM */
3894 ComPtr<IMachine> machine;
3895 /* assume it's a UUID */
3896 rc = virtualBox->GetMachine(Guid(argv[0]), machine.asOutParam());
3897 if (FAILED(rc) || !machine)
3898 {
3899 /* must be a name */
3900 CHECK_ERROR(virtualBox, FindMachine(Bstr(argv[0]), machine.asOutParam()));
3901 }
3902 if (!machine)
3903 return 1;
3904 Guid guid;
3905 machine->COMGETTER(Id)(guid.asOutParam());
3906
3907 do
3908 {
3909 /* we have to open a session for this task. First try an existing session */
3910 rc = virtualBox->OpenExistingSession(session, guid);
3911 if (FAILED(rc))
3912 CHECK_ERROR_BREAK(virtualBox, OpenSession(session, guid));
3913 ComPtr<IConsole> console;
3914 CHECK_ERROR_BREAK(session, COMGETTER(Console)(console.asOutParam()));
3915
3916 /* switch based on the command */
3917 if (strcmp(argv[1], "take") == 0)
3918 {
3919 /* there must be a name */
3920 if (argc < 3)
3921 {
3922 errorSyntax(USAGE_SNAPSHOT, "Missing snapshot name");
3923 rc = E_FAIL;
3924 break;
3925 }
3926 Bstr name(argv[2]);
3927 if ((argc > 3) && ((argc != 5) || (strcmp(argv[3], "-desc") != 0)))
3928 {
3929 errorSyntax(USAGE_SNAPSHOT, "Incorrect description format");
3930 rc = E_FAIL;
3931 break;
3932 }
3933 Bstr desc;
3934 if (argc == 5)
3935 desc = argv[4];
3936 ComPtr<IProgress> progress;
3937 CHECK_ERROR_BREAK(console, TakeSnapshot(name, desc, progress.asOutParam()));
3938
3939 showProgress(progress);
3940 progress->COMGETTER(ResultCode)(&rc);
3941 if (FAILED(rc))
3942 {
3943 com::ProgressErrorInfo info(progress);
3944 if (info.isBasicAvailable())
3945 RTPrintf("Error: failed to take snapshot. Error message: %lS\n", info.getText().raw());
3946 else
3947 RTPrintf("Error: failed to take snapshot. No error message available!\n");
3948 }
3949 }
3950 else if (strcmp(argv[1], "discard") == 0)
3951 {
3952 /* exactly one parameter: snapshot name */
3953 if (argc != 3)
3954 {
3955 errorSyntax(USAGE_SNAPSHOT, "Expecting snapshot name only");
3956 rc = E_FAIL;
3957 break;
3958 }
3959
3960 ComPtr<ISnapshot> snapshot;
3961
3962 /* assume it's a UUID */
3963 Guid guid(argv[2]);
3964 if (!guid.isEmpty())
3965 {
3966 CHECK_ERROR_BREAK(machine, GetSnapshot(guid, snapshot.asOutParam()));
3967 }
3968 else
3969 {
3970 /* then it must be a name */
3971 CHECK_ERROR_BREAK(machine, FindSnapshot(Bstr(argv[2]), snapshot.asOutParam()));
3972 }
3973
3974 snapshot->COMGETTER(Id)(guid.asOutParam());
3975
3976 ComPtr<IProgress> progress;
3977 CHECK_ERROR_BREAK(console, DiscardSnapshot(guid, progress.asOutParam()));
3978
3979 showProgress(progress);
3980 progress->COMGETTER(ResultCode)(&rc);
3981 if (FAILED(rc))
3982 {
3983 com::ProgressErrorInfo info(progress);
3984 if (info.isBasicAvailable())
3985 RTPrintf("Error: failed to discard snapshot. Error message: %lS\n", info.getText().raw());
3986 else
3987 RTPrintf("Error: failed to discard snapshot. No error message available!\n");
3988 }
3989 }
3990 else if (strcmp(argv[1], "discardcurrent") == 0)
3991 {
3992 if ( (argc != 3)
3993 || ( (strcmp(argv[2], "-state") != 0)
3994 && (strcmp(argv[2], "-all") != 0)))
3995 {
3996 errorSyntax(USAGE_SNAPSHOT, "Invalid parameter '%s'", Utf8Str(argv[2]).raw());
3997 rc = E_FAIL;
3998 break;
3999 }
4000 bool fAll = false;
4001 if (strcmp(argv[2], "-all") == 0)
4002 fAll = true;
4003
4004 ComPtr<IProgress> progress;
4005
4006 if (fAll)
4007 {
4008 CHECK_ERROR_BREAK(console, DiscardCurrentSnapshotAndState(progress.asOutParam()));
4009 }
4010 else
4011 {
4012 CHECK_ERROR_BREAK(console, DiscardCurrentState(progress.asOutParam()));
4013 }
4014
4015 showProgress(progress);
4016 progress->COMGETTER(ResultCode)(&rc);
4017 if (FAILED(rc))
4018 {
4019 com::ProgressErrorInfo info(progress);
4020 if (info.isBasicAvailable())
4021 RTPrintf("Error: failed to discard. Error message: %lS\n", info.getText().raw());
4022 else
4023 RTPrintf("Error: failed to discard. No error message available!\n");
4024 }
4025
4026 }
4027 else if (strcmp(argv[1], "edit") == 0)
4028 {
4029 if (argc < 3)
4030 {
4031 errorSyntax(USAGE_SNAPSHOT, "Missing snapshot name");
4032 rc = E_FAIL;
4033 break;
4034 }
4035
4036 ComPtr<ISnapshot> snapshot;
4037
4038 if (strcmp(argv[2], "-current") == 0)
4039 {
4040 CHECK_ERROR_BREAK(machine, COMGETTER(CurrentSnapshot)(snapshot.asOutParam()));
4041 }
4042 else
4043 {
4044 /* assume it's a UUID */
4045 Guid guid(argv[2]);
4046 if (!guid.isEmpty())
4047 {
4048 CHECK_ERROR_BREAK(machine, GetSnapshot(guid, snapshot.asOutParam()));
4049 }
4050 else
4051 {
4052 /* then it must be a name */
4053 CHECK_ERROR_BREAK(machine, FindSnapshot(Bstr(argv[2]), snapshot.asOutParam()));
4054 }
4055 }
4056
4057 /* parse options */
4058 for (int i = 3; i < argc; i++)
4059 {
4060 if (strcmp(argv[i], "-newname") == 0)
4061 {
4062 if (argc <= i + 1)
4063 {
4064 errorArgument("Missing argument to '%s'", argv[i]);
4065 rc = E_FAIL;
4066 break;
4067 }
4068 i++;
4069 snapshot->COMSETTER(Name)(Bstr(argv[i]));
4070 }
4071 else if (strcmp(argv[i], "-newdesc") == 0)
4072 {
4073 if (argc <= i + 1)
4074 {
4075 errorArgument("Missing argument to '%s'", argv[i]);
4076 rc = E_FAIL;
4077 break;
4078 }
4079 i++;
4080 snapshot->COMSETTER(Description)(Bstr(argv[i]));
4081 }
4082 else
4083 {
4084 errorSyntax(USAGE_SNAPSHOT, "Invalid parameter '%s'", Utf8Str(argv[i]).raw());
4085 rc = E_FAIL;
4086 break;
4087 }
4088 }
4089
4090 }
4091 else if (strcmp(argv[1], "showvminfo") == 0)
4092 {
4093 /* exactly one parameter: snapshot name */
4094 if (argc != 3)
4095 {
4096 errorSyntax(USAGE_SNAPSHOT, "Expecting snapshot name only");
4097 rc = E_FAIL;
4098 break;
4099 }
4100
4101 ComPtr<ISnapshot> snapshot;
4102
4103 /* assume it's a UUID */
4104 Guid guid(argv[2]);
4105 if (!guid.isEmpty())
4106 {
4107 CHECK_ERROR_BREAK(machine, GetSnapshot(guid, snapshot.asOutParam()));
4108 }
4109 else
4110 {
4111 /* then it must be a name */
4112 CHECK_ERROR_BREAK(machine, FindSnapshot(Bstr(argv[2]), snapshot.asOutParam()));
4113 }
4114
4115 /* get the machine of the given snapshot */
4116 ComPtr<IMachine> machine;
4117 snapshot->COMGETTER(Machine)(machine.asOutParam());
4118 showVMInfo(virtualBox, machine, console);
4119 }
4120 else
4121 {
4122 errorSyntax(USAGE_SNAPSHOT, "Invalid parameter '%s'", Utf8Str(argv[1]).raw());
4123 rc = E_FAIL;
4124 }
4125 } while (0);
4126
4127 session->Close();
4128
4129 return SUCCEEDED(rc) ? 0 : 1;
4130}
4131
4132static int handleShowHardDiskInfo(int argc, char *argv[],
4133 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
4134{
4135 HRESULT rc;
4136
4137 if (argc != 1)
4138 return errorSyntax(USAGE_SHOWHDINFO, "Incorrect number of parameters");
4139
4140 ComPtr<IHardDisk2> hardDisk;
4141 Bstr filepath;
4142
4143 bool unknown = false;
4144
4145 /* first guess is that it's a UUID */
4146 Guid uuid(argv[0]);
4147 rc = virtualBox->GetHardDisk2(uuid, hardDisk.asOutParam());
4148 /* no? then it must be a filename */
4149 if (FAILED (rc))
4150 {
4151 filepath = argv[0];
4152 rc = virtualBox->FindHardDisk2(filepath, hardDisk.asOutParam());
4153 /* no? well, then it's an unkwnown image */
4154 if (FAILED (rc))
4155 {
4156 CHECK_ERROR(virtualBox, OpenHardDisk2(filepath, hardDisk.asOutParam()));
4157 if (SUCCEEDED (rc))
4158 {
4159 unknown = true;
4160 }
4161 }
4162 }
4163 do
4164 {
4165 if (!SUCCEEDED(rc))
4166 break;
4167
4168 hardDisk->COMGETTER(Id)(uuid.asOutParam());
4169 RTPrintf("UUID: %s\n", uuid.toString().raw());
4170
4171 /* check for accessibility */
4172 /// @todo NEWMEDIA check accessibility of all parents
4173 /// @todo NEWMEDIA print the full state value
4174 MediaState_T state;
4175 CHECK_ERROR_BREAK (hardDisk, COMGETTER(State)(&state));
4176 RTPrintf("Accessible: %s\n", state != MediaState_Inaccessible ? "yes" : "no");
4177
4178 if (state == MediaState_Inaccessible)
4179 {
4180 Bstr err;
4181 CHECK_ERROR_BREAK (hardDisk, COMGETTER(LastAccessError)(err.asOutParam()));
4182 RTPrintf("Access Error: %lS\n", err.raw());
4183 }
4184
4185 Bstr description;
4186 hardDisk->COMGETTER(Description)(description.asOutParam());
4187 if (description)
4188 {
4189 RTPrintf("Description: %lS\n", description.raw());
4190 }
4191
4192 ULONG64 logicalSize;
4193 hardDisk->COMGETTER(LogicalSize)(&logicalSize);
4194 RTPrintf("Logical size: %llu MBytes\n", logicalSize);
4195 ULONG64 actualSize;
4196 hardDisk->COMGETTER(Size)(&actualSize);
4197 RTPrintf("Current size on disk: %llu MBytes\n", actualSize >> 20);
4198
4199 HardDiskType_T type;
4200 hardDisk->COMGETTER(Type)(&type);
4201 const char *typeStr = "unknown";
4202 switch (type)
4203 {
4204 case HardDiskType_Normal:
4205 typeStr = "normal";
4206 break;
4207 case HardDiskType_Immutable:
4208 typeStr = "immutable";
4209 break;
4210 case HardDiskType_Writethrough:
4211 typeStr = "writethrough";
4212 break;
4213 }
4214 RTPrintf("Type: %s\n", typeStr);
4215
4216 Bstr format;
4217 hardDisk->COMGETTER(Format)(format.asOutParam());
4218 RTPrintf("Storage format: %lS\n", format.raw());
4219
4220 if (!unknown)
4221 {
4222 com::SafeGUIDArray machineIds;
4223 hardDisk->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(machineIds));
4224 for (size_t j = 0; j < machineIds.size(); ++ j)
4225 {
4226 ComPtr<IMachine> machine;
4227 CHECK_ERROR(virtualBox, GetMachine(machineIds[j], machine.asOutParam()));
4228 ASSERT(machine);
4229 Bstr name;
4230 machine->COMGETTER(Name)(name.asOutParam());
4231 machine->COMGETTER(Id)(uuid.asOutParam());
4232 RTPrintf("%s%lS (UUID: %RTuuid)\n",
4233 j == 0 ? "In use by VMs: " : " ",
4234 name.raw(), &machineIds[j]);
4235 }
4236 /// @todo NEWMEDIA check usage in snapshots too
4237 /// @todo NEWMEDIA also list children and say 'differencing' for
4238 /// hard disks with the parent or 'base' otherwise.
4239 }
4240
4241 Bstr loc;
4242 hardDisk->COMGETTER(Location)(loc.asOutParam());
4243 RTPrintf("Location: %lS\n", loc.raw());
4244 }
4245 while (0);
4246
4247 if (unknown)
4248 {
4249 /* close the unknown hard disk to forget it again */
4250 hardDisk->Close();
4251 }
4252
4253 return SUCCEEDED(rc) ? 0 : 1;
4254}
4255
4256static int handleOpenMedium(int argc, char *argv[],
4257 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
4258{
4259 HRESULT rc;
4260
4261 if (argc < 2)
4262 return errorSyntax(USAGE_REGISTERIMAGE, "Not enough parameters");
4263
4264 Bstr filepath(argv[1]);
4265
4266 if (strcmp(argv[0], "disk") == 0)
4267 {
4268 const char *type = NULL;
4269 /* there can be a type parameter */
4270 if ((argc > 2) && (argc != 4))
4271 return errorSyntax(USAGE_REGISTERIMAGE, "Incorrect number of parameters");
4272 if (argc == 4)
4273 {
4274 if (strcmp(argv[2], "-type") != 0)
4275 return errorSyntax(USAGE_REGISTERIMAGE, "Invalid parameter '%s'", Utf8Str(argv[2]).raw());
4276 if ( (strcmp(argv[3], "normal") != 0)
4277 && (strcmp(argv[3], "immutable") != 0)
4278 && (strcmp(argv[3], "writethrough") != 0))
4279 return errorArgument("Invalid hard disk type '%s' specified", Utf8Str(argv[3]).raw());
4280 type = argv[3];
4281 }
4282
4283 ComPtr<IHardDisk2> hardDisk;
4284 CHECK_ERROR(virtualBox, OpenHardDisk2(filepath, hardDisk.asOutParam()));
4285 if (SUCCEEDED(rc) && hardDisk)
4286 {
4287 /* change the type if requested */
4288 if (type)
4289 {
4290 if (strcmp(type, "normal") == 0)
4291 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Normal));
4292 else if (strcmp(type, "immutable") == 0)
4293 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Immutable));
4294 else if (strcmp(type, "writethrough") == 0)
4295 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Writethrough));
4296 }
4297 }
4298 }
4299 else if (strcmp(argv[0], "dvd") == 0)
4300 {
4301 ComPtr<IDVDImage2> dvdImage;
4302 CHECK_ERROR(virtualBox, OpenDVDImage(filepath, Guid(), dvdImage.asOutParam()));
4303 }
4304 else if (strcmp(argv[0], "floppy") == 0)
4305 {
4306 ComPtr<IFloppyImage2> floppyImage;
4307 CHECK_ERROR(virtualBox, OpenFloppyImage(filepath, Guid(), floppyImage.asOutParam()));
4308 }
4309 else
4310 return errorSyntax(USAGE_REGISTERIMAGE, "Invalid parameter '%s'", Utf8Str(argv[1]).raw());
4311
4312 return SUCCEEDED(rc) ? 0 : 1;
4313}
4314
4315static int handleCloseMedium(int argc, char *argv[],
4316 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
4317{
4318 HRESULT rc;
4319
4320 if (argc != 2)
4321 return errorSyntax(USAGE_UNREGISTERIMAGE, "Incorrect number of parameters");
4322
4323 /* first guess is that it's a UUID */
4324 Guid uuid(argv[1]);
4325
4326 if (strcmp(argv[0], "disk") == 0)
4327 {
4328 ComPtr<IHardDisk2> hardDisk;
4329 rc = virtualBox->GetHardDisk2(uuid, hardDisk.asOutParam());
4330 /* not a UUID or not registered? Then it must be a filename */
4331 if (!hardDisk)
4332 {
4333 CHECK_ERROR(virtualBox, FindHardDisk2(Bstr(argv[1]), hardDisk.asOutParam()));
4334 }
4335 if (SUCCEEDED(rc) && hardDisk)
4336 {
4337 CHECK_ERROR(hardDisk, Close());
4338 }
4339 }
4340 else
4341 if (strcmp(argv[0], "dvd") == 0)
4342 {
4343 ComPtr<IDVDImage2> dvdImage;
4344 rc = virtualBox->GetDVDImage(uuid, dvdImage.asOutParam());
4345 /* not a UUID or not registered? Then it must be a filename */
4346 if (!dvdImage)
4347 {
4348 CHECK_ERROR(virtualBox, FindDVDImage(Bstr(argv[1]), dvdImage.asOutParam()));
4349 }
4350 if (SUCCEEDED(rc) && dvdImage)
4351 {
4352 CHECK_ERROR(dvdImage, Close());
4353 }
4354 }
4355 else
4356 if (strcmp(argv[0], "floppy") == 0)
4357 {
4358 ComPtr<IFloppyImage2> floppyImage;
4359 rc = virtualBox->GetFloppyImage(uuid, floppyImage.asOutParam());
4360 /* not a UUID or not registered? Then it must be a filename */
4361 if (!floppyImage)
4362 {
4363 CHECK_ERROR(virtualBox, FindFloppyImage(Bstr(argv[1]), floppyImage.asOutParam()));
4364 }
4365 if (SUCCEEDED(rc) && floppyImage)
4366 {
4367 CHECK_ERROR(floppyImage, Close());
4368 }
4369 }
4370 else
4371 return errorSyntax(USAGE_UNREGISTERIMAGE, "Invalid parameter '%s'", Utf8Str(argv[1]).raw());
4372
4373 return SUCCEEDED(rc) ? 0 : 1;
4374}
4375
4376#ifdef RT_OS_WINDOWS
4377static int handleCreateHostIF(int argc, char *argv[],
4378 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
4379{
4380 if (argc != 1)
4381 return errorSyntax(USAGE_CREATEHOSTIF, "Incorrect number of parameters");
4382
4383 HRESULT rc = S_OK;
4384
4385 do
4386 {
4387 ComPtr<IHost> host;
4388 CHECK_ERROR_BREAK(virtualBox, COMGETTER(Host)(host.asOutParam()));
4389
4390 ComPtr<IHostNetworkInterface> hostif;
4391 ComPtr<IProgress> progress;
4392 CHECK_ERROR_BREAK(host,
4393 CreateHostNetworkInterface(Bstr(argv[0]),
4394 hostif.asOutParam(),
4395 progress.asOutParam()));
4396
4397 showProgress(progress);
4398 HRESULT result;
4399 CHECK_ERROR_BREAK(progress, COMGETTER(ResultCode)(&result));
4400 if (FAILED(result))
4401 {
4402 com::ProgressErrorInfo info(progress);
4403 PRINT_ERROR_INFO(info);
4404 rc = result;
4405 }
4406 }
4407 while (0);
4408
4409 return SUCCEEDED(rc) ? 0 : 1;
4410}
4411
4412static int handleRemoveHostIF(int argc, char *argv[],
4413 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
4414{
4415 if (argc != 1)
4416 return errorSyntax(USAGE_REMOVEHOSTIF, "Incorrect number of parameters");
4417
4418 HRESULT rc = S_OK;
4419
4420 do
4421 {
4422 ComPtr<IHost> host;
4423 CHECK_ERROR_BREAK(virtualBox, COMGETTER(Host)(host.asOutParam()));
4424
4425 ComPtr<IHostNetworkInterface> hostif;
4426
4427 /* first guess is that it's a UUID */
4428 Guid uuid(argv[0]);
4429 if (uuid.isEmpty())
4430 {
4431 /* not a valid UUID, search for it */
4432 ComPtr<IHostNetworkInterfaceCollection> coll;
4433 CHECK_ERROR_BREAK(host, COMGETTER(NetworkInterfaces)(coll.asOutParam()));
4434 CHECK_ERROR_BREAK(coll, FindByName(Bstr(argv[0]), hostif.asOutParam()));
4435 CHECK_ERROR_BREAK(hostif, COMGETTER(Id)(uuid.asOutParam()));
4436 }
4437
4438 ComPtr<IProgress> progress;
4439 CHECK_ERROR_BREAK(host,
4440 RemoveHostNetworkInterface(uuid,
4441 hostif.asOutParam(),
4442 progress.asOutParam()));
4443
4444 showProgress(progress);
4445 HRESULT result;
4446 CHECK_ERROR_BREAK(progress, COMGETTER(ResultCode)(&result));
4447 if (FAILED(result))
4448 {
4449 com::ProgressErrorInfo info(progress);
4450 PRINT_ERROR_INFO(info);
4451 rc = result;
4452 }
4453 }
4454 while (0);
4455
4456 return SUCCEEDED(rc) ? 0 : 1;
4457}
4458#endif /* RT_OS_WINDOWS */
4459
4460static int handleGetExtraData(int argc, char *argv[],
4461 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
4462{
4463 HRESULT rc = S_OK;
4464
4465 if (argc != 2)
4466 return errorSyntax(USAGE_GETEXTRADATA, "Incorrect number of parameters");
4467
4468 /* global data? */
4469 if (strcmp(argv[0], "global") == 0)
4470 {
4471 /* enumeration? */
4472 if (strcmp(argv[1], "enumerate") == 0)
4473 {
4474 Bstr extraDataKey;
4475
4476 do
4477 {
4478 Bstr nextExtraDataKey;
4479 Bstr nextExtraDataValue;
4480 HRESULT rcEnum = virtualBox->GetNextExtraDataKey(extraDataKey, nextExtraDataKey.asOutParam(),
4481 nextExtraDataValue.asOutParam());
4482 extraDataKey = nextExtraDataKey;
4483
4484 if (SUCCEEDED(rcEnum) && extraDataKey)
4485 RTPrintf("Key: %lS, Value: %lS\n", nextExtraDataKey.raw(), nextExtraDataValue.raw());
4486 } while (extraDataKey);
4487 }
4488 else
4489 {
4490 Bstr value;
4491 CHECK_ERROR(virtualBox, GetExtraData(Bstr(argv[1]), value.asOutParam()));
4492 if (value)
4493 RTPrintf("Value: %lS\n", value.raw());
4494 else
4495 RTPrintf("No value set!\n");
4496 }
4497 }
4498 else
4499 {
4500 ComPtr<IMachine> machine;
4501 /* assume it's a UUID */
4502 rc = virtualBox->GetMachine(Guid(argv[0]), machine.asOutParam());
4503 if (FAILED(rc) || !machine)
4504 {
4505 /* must be a name */
4506 CHECK_ERROR(virtualBox, FindMachine(Bstr(argv[0]), machine.asOutParam()));
4507 }
4508 if (machine)
4509 {
4510 /* enumeration? */
4511 if (strcmp(argv[1], "enumerate") == 0)
4512 {
4513 Bstr extraDataKey;
4514
4515 do
4516 {
4517 Bstr nextExtraDataKey;
4518 Bstr nextExtraDataValue;
4519 HRESULT rcEnum = machine->GetNextExtraDataKey(extraDataKey, nextExtraDataKey.asOutParam(),
4520 nextExtraDataValue.asOutParam());
4521 extraDataKey = nextExtraDataKey;
4522
4523 if (SUCCEEDED(rcEnum) && extraDataKey)
4524 {
4525 RTPrintf("Key: %lS, Value: %lS\n", nextExtraDataKey.raw(), nextExtraDataValue.raw());
4526 }
4527 } while (extraDataKey);
4528 }
4529 else
4530 {
4531 Bstr value;
4532 CHECK_ERROR(machine, GetExtraData(Bstr(argv[1]), value.asOutParam()));
4533 if (value)
4534 RTPrintf("Value: %lS\n", value.raw());
4535 else
4536 RTPrintf("No value set!\n");
4537 }
4538 }
4539 }
4540 return SUCCEEDED(rc) ? 0 : 1;
4541}
4542
4543static int handleSetExtraData(int argc, char *argv[],
4544 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
4545{
4546 HRESULT rc = S_OK;
4547
4548 if (argc < 2)
4549 return errorSyntax(USAGE_SETEXTRADATA, "Not enough parameters");
4550
4551 /* global data? */
4552 if (strcmp(argv[0], "global") == 0)
4553 {
4554 if (argc < 3)
4555 CHECK_ERROR(virtualBox, SetExtraData(Bstr(argv[1]), NULL));
4556 else if (argc == 3)
4557 CHECK_ERROR(virtualBox, SetExtraData(Bstr(argv[1]), Bstr(argv[2])));
4558 else
4559 return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
4560 }
4561 else
4562 {
4563 ComPtr<IMachine> machine;
4564 /* assume it's a UUID */
4565 rc = virtualBox->GetMachine(Guid(argv[0]), machine.asOutParam());
4566 if (FAILED(rc) || !machine)
4567 {
4568 /* must be a name */
4569 CHECK_ERROR(virtualBox, FindMachine(Bstr(argv[0]), machine.asOutParam()));
4570 }
4571 if (machine)
4572 {
4573 if (argc < 3)
4574 CHECK_ERROR(machine, SetExtraData(Bstr(argv[1]), NULL));
4575 else if (argc == 3)
4576 CHECK_ERROR(machine, SetExtraData(Bstr(argv[1]), Bstr(argv[2])));
4577 else
4578 return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
4579 }
4580 }
4581 return SUCCEEDED(rc) ? 0 : 1;
4582}
4583
4584static int handleSetProperty(int argc, char *argv[],
4585 ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> session)
4586{
4587 HRESULT rc;
4588
4589 /* there must be two arguments: property name and value */
4590 if (argc != 2)
4591 return errorSyntax(USAGE_SETPROPERTY, "Incorrect number of parameters");
4592
4593 ComPtr<ISystemProperties> systemProperties;
4594 virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
4595
4596 if (strcmp(argv[0], "hdfolder") == 0)
4597 {
4598 /* reset to default? */
4599 if (strcmp(argv[1], "default") == 0)
4600 CHECK_ERROR(systemProperties, COMSETTER(DefaultHardDiskFolder)(NULL));
4601 else
4602 CHECK_ERROR(systemProperties, COMSETTER(DefaultHardDiskFolder)(Bstr(argv[1])));
4603 }
4604 else if (strcmp(argv[0], "machinefolder") == 0)
4605 {
4606 /* reset to default? */
4607 if (strcmp(argv[1], "default") == 0)
4608 CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(NULL));
4609 else
4610 CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(Bstr(argv[1])));
4611 }
4612 else if (strcmp(argv[0], "vrdpauthlibrary") == 0)
4613 {
4614 /* reset to default? */
4615 if (strcmp(argv[1], "default") == 0)
4616 CHECK_ERROR(systemProperties, COMSETTER(RemoteDisplayAuthLibrary)(NULL));
4617 else
4618 CHECK_ERROR(systemProperties, COMSETTER(RemoteDisplayAuthLibrary)(Bstr(argv[1])));
4619 }
4620 else if (strcmp(argv[0], "websrvauthlibrary") == 0)
4621 {
4622 /* reset to default? */
4623 if (strcmp(argv[1], "default") == 0)
4624 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(NULL));
4625 else
4626 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(Bstr(argv[1])));
4627 }
4628 else if (strcmp(argv[0], "hwvirtexenabled") == 0)
4629 {
4630 if (strcmp(argv[1], "yes") == 0)
4631 CHECK_ERROR(systemProperties, COMSETTER(HWVirtExEnabled)(TRUE));
4632 else if (strcmp(argv[1], "no") == 0)
4633 CHECK_ERROR(systemProperties, COMSETTER(HWVirtExEnabled)(FALSE));
4634 else
4635 return errorArgument("Invalid value '%s' for hardware virtualization extension flag", argv[1]);
4636 }
4637 else if (strcmp(argv[0], "loghistorycount") == 0)
4638 {
4639 uint32_t uVal;
4640 int vrc;
4641 vrc = RTStrToUInt32Ex(argv[1], NULL, 0, &uVal);
4642 if (vrc != VINF_SUCCESS)
4643 return errorArgument("Error parsing Log history count '%s'", argv[1]);
4644 CHECK_ERROR(systemProperties, COMSETTER(LogHistoryCount)(uVal));
4645 }
4646 else
4647 return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", argv[0]);
4648
4649 return SUCCEEDED(rc) ? 0 : 1;
4650}
4651
4652static int handleUSBFilter (int argc, char *argv[],
4653 ComPtr <IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
4654{
4655 HRESULT rc = S_OK;
4656 USBFilterCmd cmd;
4657
4658 /* at least: 0: command, 1: index, 2: -target, 3: <target value> */
4659 if (argc < 4)
4660 return errorSyntax(USAGE_USBFILTER, "Not enough parameters");
4661
4662 /* which command? */
4663 cmd.mAction = USBFilterCmd::Invalid;
4664 if (strcmp (argv [0], "add") == 0) cmd.mAction = USBFilterCmd::Add;
4665 else if (strcmp (argv [0], "modify") == 0) cmd.mAction = USBFilterCmd::Modify;
4666 else if (strcmp (argv [0], "remove") == 0) cmd.mAction = USBFilterCmd::Remove;
4667
4668 if (cmd.mAction == USBFilterCmd::Invalid)
4669 return errorSyntax(USAGE_USBFILTER, "Invalid parameter '%s'", argv[0]);
4670
4671 /* which index? */
4672 char *endptr = NULL;
4673 cmd.mIndex = strtoul (argv[1], &endptr, 10);
4674 if (!endptr || *endptr)
4675 return errorSyntax(USAGE_USBFILTER, "Invalid index '%s'", argv[1]);
4676
4677 switch (cmd.mAction)
4678 {
4679 case USBFilterCmd::Add:
4680 case USBFilterCmd::Modify:
4681 {
4682 /* at least: 0: command, 1: index, 2: -target, 3: <target value>, 4: -name, 5: <name value> */
4683 if (argc < 6)
4684 {
4685 if (cmd.mAction == USBFilterCmd::Add)
4686 return errorSyntax(USAGE_USBFILTER_ADD, "Not enough parameters");
4687
4688 return errorSyntax(USAGE_USBFILTER_MODIFY, "Not enough parameters");
4689 }
4690
4691 // set Active to true by default
4692 // (assuming that the user sets up all necessary attributes
4693 // at once and wants the filter to be active immediately)
4694 if (cmd.mAction == USBFilterCmd::Add)
4695 cmd.mFilter.mActive = true;
4696
4697 for (int i = 2; i < argc; i++)
4698 {
4699 if (strcmp(argv [i], "-target") == 0)
4700 {
4701 if (argc <= i + 1 || !*argv[i+1])
4702 return errorArgument("Missing argument to '%s'", argv[i]);
4703 i++;
4704 if (strcmp (argv [i], "global") == 0)
4705 cmd.mGlobal = true;
4706 else
4707 {
4708 /* assume it's a UUID of a machine */
4709 rc = aVirtualBox->GetMachine(Guid(argv[i]), cmd.mMachine.asOutParam());
4710 if (FAILED(rc) || !cmd.mMachine)
4711 {
4712 /* must be a name */
4713 CHECK_ERROR_RET(aVirtualBox, FindMachine(Bstr(argv[i]), cmd.mMachine.asOutParam()), 1);
4714 }
4715 }
4716 }
4717 else if (strcmp(argv [i], "-name") == 0)
4718 {
4719 if (argc <= i + 1 || !*argv[i+1])
4720 return errorArgument("Missing argument to '%s'", argv[i]);
4721 i++;
4722 cmd.mFilter.mName = argv [i];
4723 }
4724 else if (strcmp(argv [i], "-active") == 0)
4725 {
4726 if (argc <= i + 1)
4727 return errorArgument("Missing argument to '%s'", argv[i]);
4728 i++;
4729 if (strcmp (argv [i], "yes") == 0)
4730 cmd.mFilter.mActive = true;
4731 else if (strcmp (argv [i], "no") == 0)
4732 cmd.mFilter.mActive = false;
4733 else
4734 return errorArgument("Invalid -active argument '%s'", argv[i]);
4735 }
4736 else if (strcmp(argv [i], "-vendorid") == 0)
4737 {
4738 if (argc <= i + 1)
4739 return errorArgument("Missing argument to '%s'", argv[i]);
4740 i++;
4741 cmd.mFilter.mVendorId = argv [i];
4742 }
4743 else if (strcmp(argv [i], "-productid") == 0)
4744 {
4745 if (argc <= i + 1)
4746 return errorArgument("Missing argument to '%s'", argv[i]);
4747 i++;
4748 cmd.mFilter.mProductId = argv [i];
4749 }
4750 else if (strcmp(argv [i], "-revision") == 0)
4751 {
4752 if (argc <= i + 1)
4753 return errorArgument("Missing argument to '%s'", argv[i]);
4754 i++;
4755 cmd.mFilter.mRevision = argv [i];
4756 }
4757 else if (strcmp(argv [i], "-manufacturer") == 0)
4758 {
4759 if (argc <= i + 1)
4760 return errorArgument("Missing argument to '%s'", argv[i]);
4761 i++;
4762 cmd.mFilter.mManufacturer = argv [i];
4763 }
4764 else if (strcmp(argv [i], "-product") == 0)
4765 {
4766 if (argc <= i + 1)
4767 return errorArgument("Missing argument to '%s'", argv[i]);
4768 i++;
4769 cmd.mFilter.mProduct = argv [i];
4770 }
4771 else if (strcmp(argv [i], "-remote") == 0)
4772 {
4773 if (argc <= i + 1)
4774 return errorArgument("Missing argument to '%s'", argv[i]);
4775 i++;
4776 cmd.mFilter.mRemote = argv[i];
4777 }
4778 else if (strcmp(argv [i], "-serialnumber") == 0)
4779 {
4780 if (argc <= i + 1)
4781 return errorArgument("Missing argument to '%s'", argv[i]);
4782 i++;
4783 cmd.mFilter.mSerialNumber = argv [i];
4784 }
4785 else if (strcmp(argv [i], "-maskedinterfaces") == 0)
4786 {
4787 if (argc <= i + 1)
4788 return errorArgument("Missing argument to '%s'", argv[i]);
4789 i++;
4790 uint32_t u32;
4791 rc = RTStrToUInt32Full(argv[i], 0, &u32);
4792 if (RT_FAILURE(rc))
4793 return errorArgument("Failed to convert the -maskedinterfaces value '%s' to a number, rc=%Rrc", argv[i], rc);
4794 cmd.mFilter.mMaskedInterfaces = u32;
4795 }
4796 else if (strcmp(argv [i], "-action") == 0)
4797 {
4798 if (argc <= i + 1)
4799 return errorArgument("Missing argument to '%s'", argv[i]);
4800 i++;
4801 if (strcmp (argv [i], "ignore") == 0)
4802 cmd.mFilter.mAction = USBDeviceFilterAction_Ignore;
4803 else if (strcmp (argv [i], "hold") == 0)
4804 cmd.mFilter.mAction = USBDeviceFilterAction_Hold;
4805 else
4806 return errorArgument("Invalid USB filter action '%s'", argv[i]);
4807 }
4808 else
4809 return errorSyntax(cmd.mAction == USBFilterCmd::Add ? USAGE_USBFILTER_ADD : USAGE_USBFILTER_MODIFY,
4810 "Unknown option '%s'", argv[i]);
4811 }
4812
4813 if (cmd.mAction == USBFilterCmd::Add)
4814 {
4815 // mandatory/forbidden options
4816 if ( cmd.mFilter.mName.isEmpty()
4817 ||
4818 ( cmd.mGlobal
4819 && cmd.mFilter.mAction == USBDeviceFilterAction_Null
4820 )
4821 || ( !cmd.mGlobal
4822 && !cmd.mMachine)
4823 || ( cmd.mGlobal
4824 && cmd.mFilter.mRemote)
4825 )
4826 {
4827 return errorSyntax(USAGE_USBFILTER_ADD, "Mandatory options not supplied");
4828 }
4829 }
4830 break;
4831 }
4832
4833 case USBFilterCmd::Remove:
4834 {
4835 /* at least: 0: command, 1: index, 2: -target, 3: <target value> */
4836 if (argc < 4)
4837 return errorSyntax(USAGE_USBFILTER_REMOVE, "Not enough parameters");
4838
4839 for (int i = 2; i < argc; i++)
4840 {
4841 if (strcmp(argv [i], "-target") == 0)
4842 {
4843 if (argc <= i + 1 || !*argv[i+1])
4844 return errorArgument("Missing argument to '%s'", argv[i]);
4845 i++;
4846 if (strcmp (argv [i], "global") == 0)
4847 cmd.mGlobal = true;
4848 else
4849 {
4850 /* assume it's a UUID of a machine */
4851 rc = aVirtualBox->GetMachine(Guid(argv[i]), cmd.mMachine.asOutParam());
4852 if (FAILED(rc) || !cmd.mMachine)
4853 {
4854 /* must be a name */
4855 CHECK_ERROR_RET(aVirtualBox, FindMachine(Bstr(argv[i]), cmd.mMachine.asOutParam()), 1);
4856 }
4857 }
4858 }
4859 }
4860
4861 // mandatory options
4862 if (!cmd.mGlobal && !cmd.mMachine)
4863 return errorSyntax(USAGE_USBFILTER_REMOVE, "Mandatory options not supplied");
4864
4865 break;
4866 }
4867
4868 default: break;
4869 }
4870
4871 USBFilterCmd::USBFilter &f = cmd.mFilter;
4872
4873 ComPtr <IHost> host;
4874 ComPtr <IUSBController> ctl;
4875 if (cmd.mGlobal)
4876 CHECK_ERROR_RET (aVirtualBox, COMGETTER(Host) (host.asOutParam()), 1);
4877 else
4878 {
4879 Guid uuid;
4880 cmd.mMachine->COMGETTER(Id)(uuid.asOutParam());
4881 /* open a session for the VM */
4882 CHECK_ERROR_RET (aVirtualBox, OpenSession(aSession, uuid), 1);
4883 /* get the mutable session machine */
4884 aSession->COMGETTER(Machine)(cmd.mMachine.asOutParam());
4885 /* and get the USB controller */
4886 CHECK_ERROR_RET (cmd.mMachine, COMGETTER(USBController) (ctl.asOutParam()), 1);
4887 }
4888
4889 switch (cmd.mAction)
4890 {
4891 case USBFilterCmd::Add:
4892 {
4893 if (cmd.mGlobal)
4894 {
4895 ComPtr <IHostUSBDeviceFilter> flt;
4896 CHECK_ERROR_BREAK (host, CreateUSBDeviceFilter (f.mName, flt.asOutParam()));
4897
4898 if (!f.mActive.isNull())
4899 CHECK_ERROR_BREAK (flt, COMSETTER(Active) (f.mActive));
4900 if (!f.mVendorId.isNull())
4901 CHECK_ERROR_BREAK (flt, COMSETTER(VendorId) (f.mVendorId.setNullIfEmpty()));
4902 if (!f.mProductId.isNull())
4903 CHECK_ERROR_BREAK (flt, COMSETTER(ProductId) (f.mProductId.setNullIfEmpty()));
4904 if (!f.mRevision.isNull())
4905 CHECK_ERROR_BREAK (flt, COMSETTER(Revision) (f.mRevision.setNullIfEmpty()));
4906 if (!f.mManufacturer.isNull())
4907 CHECK_ERROR_BREAK (flt, COMSETTER(Manufacturer) (f.mManufacturer.setNullIfEmpty()));
4908 if (!f.mSerialNumber.isNull())
4909 CHECK_ERROR_BREAK (flt, COMSETTER(SerialNumber) (f.mSerialNumber.setNullIfEmpty()));
4910 if (!f.mMaskedInterfaces.isNull())
4911 CHECK_ERROR_BREAK (flt, COMSETTER(MaskedInterfaces) (f.mMaskedInterfaces));
4912
4913 if (f.mAction != USBDeviceFilterAction_Null)
4914 CHECK_ERROR_BREAK (flt, COMSETTER(Action) (f.mAction));
4915
4916 CHECK_ERROR_BREAK (host, InsertUSBDeviceFilter (cmd.mIndex, flt));
4917 }
4918 else
4919 {
4920 ComPtr <IUSBDeviceFilter> flt;
4921 CHECK_ERROR_BREAK (ctl, CreateDeviceFilter (f.mName, flt.asOutParam()));
4922
4923 if (!f.mActive.isNull())
4924 CHECK_ERROR_BREAK (flt, COMSETTER(Active) (f.mActive));
4925 if (!f.mVendorId.isNull())
4926 CHECK_ERROR_BREAK (flt, COMSETTER(VendorId) (f.mVendorId.setNullIfEmpty()));
4927 if (!f.mProductId.isNull())
4928 CHECK_ERROR_BREAK (flt, COMSETTER(ProductId) (f.mProductId.setNullIfEmpty()));
4929 if (!f.mRevision.isNull())
4930 CHECK_ERROR_BREAK (flt, COMSETTER(Revision) (f.mRevision.setNullIfEmpty()));
4931 if (!f.mManufacturer.isNull())
4932 CHECK_ERROR_BREAK (flt, COMSETTER(Manufacturer) (f.mManufacturer.setNullIfEmpty()));
4933 if (!f.mRemote.isNull())
4934 CHECK_ERROR_BREAK (flt, COMSETTER(Remote) (f.mRemote.setNullIfEmpty()));
4935 if (!f.mSerialNumber.isNull())
4936 CHECK_ERROR_BREAK (flt, COMSETTER(SerialNumber) (f.mSerialNumber.setNullIfEmpty()));
4937 if (!f.mMaskedInterfaces.isNull())
4938 CHECK_ERROR_BREAK (flt, COMSETTER(MaskedInterfaces) (f.mMaskedInterfaces));
4939
4940 CHECK_ERROR_BREAK (ctl, InsertDeviceFilter (cmd.mIndex, flt));
4941 }
4942 break;
4943 }
4944 case USBFilterCmd::Modify:
4945 {
4946 if (cmd.mGlobal)
4947 {
4948 ComPtr <IHostUSBDeviceFilterCollection> coll;
4949 CHECK_ERROR_BREAK (host, COMGETTER(USBDeviceFilters) (coll.asOutParam()));
4950 ComPtr <IHostUSBDeviceFilter> flt;
4951 CHECK_ERROR_BREAK (coll, GetItemAt (cmd.mIndex, flt.asOutParam()));
4952
4953 if (!f.mName.isNull())
4954 CHECK_ERROR_BREAK (flt, COMSETTER(Name) (f.mName.setNullIfEmpty()));
4955 if (!f.mActive.isNull())
4956 CHECK_ERROR_BREAK (flt, COMSETTER(Active) (f.mActive));
4957 if (!f.mVendorId.isNull())
4958 CHECK_ERROR_BREAK (flt, COMSETTER(VendorId) (f.mVendorId.setNullIfEmpty()));
4959 if (!f.mProductId.isNull())
4960 CHECK_ERROR_BREAK (flt, COMSETTER(ProductId) (f.mProductId.setNullIfEmpty()));
4961 if (!f.mRevision.isNull())
4962 CHECK_ERROR_BREAK (flt, COMSETTER(Revision) (f.mRevision.setNullIfEmpty()));
4963 if (!f.mManufacturer.isNull())
4964 CHECK_ERROR_BREAK (flt, COMSETTER(Manufacturer) (f.mManufacturer.setNullIfEmpty()));
4965 if (!f.mSerialNumber.isNull())
4966 CHECK_ERROR_BREAK (flt, COMSETTER(SerialNumber) (f.mSerialNumber.setNullIfEmpty()));
4967 if (!f.mMaskedInterfaces.isNull())
4968 CHECK_ERROR_BREAK (flt, COMSETTER(MaskedInterfaces) (f.mMaskedInterfaces));
4969
4970 if (f.mAction != USBDeviceFilterAction_Null)
4971 CHECK_ERROR_BREAK (flt, COMSETTER(Action) (f.mAction));
4972 }
4973 else
4974 {
4975 ComPtr <IUSBDeviceFilterCollection> coll;
4976 CHECK_ERROR_BREAK (ctl, COMGETTER(DeviceFilters) (coll.asOutParam()));
4977
4978 ComPtr <IUSBDeviceFilter> flt;
4979 CHECK_ERROR_BREAK (coll, GetItemAt (cmd.mIndex, flt.asOutParam()));
4980
4981 if (!f.mName.isNull())
4982 CHECK_ERROR_BREAK (flt, COMSETTER(Name) (f.mName.setNullIfEmpty()));
4983 if (!f.mActive.isNull())
4984 CHECK_ERROR_BREAK (flt, COMSETTER(Active) (f.mActive));
4985 if (!f.mVendorId.isNull())
4986 CHECK_ERROR_BREAK (flt, COMSETTER(VendorId) (f.mVendorId.setNullIfEmpty()));
4987 if (!f.mProductId.isNull())
4988 CHECK_ERROR_BREAK (flt, COMSETTER(ProductId) (f.mProductId.setNullIfEmpty()));
4989 if (!f.mRevision.isNull())
4990 CHECK_ERROR_BREAK (flt, COMSETTER(Revision) (f.mRevision.setNullIfEmpty()));
4991 if (!f.mManufacturer.isNull())
4992 CHECK_ERROR_BREAK (flt, COMSETTER(Manufacturer) (f.mManufacturer.setNullIfEmpty()));
4993 if (!f.mRemote.isNull())
4994 CHECK_ERROR_BREAK (flt, COMSETTER(Remote) (f.mRemote.setNullIfEmpty()));
4995 if (!f.mSerialNumber.isNull())
4996 CHECK_ERROR_BREAK (flt, COMSETTER(SerialNumber) (f.mSerialNumber.setNullIfEmpty()));
4997 if (!f.mMaskedInterfaces.isNull())
4998 CHECK_ERROR_BREAK (flt, COMSETTER(MaskedInterfaces) (f.mMaskedInterfaces));
4999 }
5000 break;
5001 }
5002 case USBFilterCmd::Remove:
5003 {
5004 if (cmd.mGlobal)
5005 {
5006 ComPtr <IHostUSBDeviceFilter> flt;
5007 CHECK_ERROR_BREAK (host, RemoveUSBDeviceFilter (cmd.mIndex, flt.asOutParam()));
5008 }
5009 else
5010 {
5011 ComPtr <IUSBDeviceFilter> flt;
5012 CHECK_ERROR_BREAK (ctl, RemoveDeviceFilter (cmd.mIndex, flt.asOutParam()));
5013 }
5014 break;
5015 }
5016 default:
5017 break;
5018 }
5019
5020 if (cmd.mMachine)
5021 {
5022 /* commit and close the session */
5023 CHECK_ERROR(cmd.mMachine, SaveSettings());
5024 aSession->Close();
5025 }
5026
5027 return SUCCEEDED (rc) ? 0 : 1;
5028}
5029
5030static int handleSharedFolder (int argc, char *argv[],
5031 ComPtr <IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
5032{
5033 HRESULT rc;
5034
5035 /* we need at least a command and target */
5036 if (argc < 2)
5037 return errorSyntax(USAGE_SHAREDFOLDER, "Not enough parameters");
5038
5039 ComPtr<IMachine> machine;
5040 /* assume it's a UUID */
5041 rc = aVirtualBox->GetMachine(Guid(argv[1]), machine.asOutParam());
5042 if (FAILED(rc) || !machine)
5043 {
5044 /* must be a name */
5045 CHECK_ERROR(aVirtualBox, FindMachine(Bstr(argv[1]), machine.asOutParam()));
5046 }
5047 if (!machine)
5048 return 1;
5049 Guid uuid;
5050 machine->COMGETTER(Id)(uuid.asOutParam());
5051
5052 if (strcmp(argv[0], "add") == 0)
5053 {
5054 /* we need at least four more parameters */
5055 if (argc < 5)
5056 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Not enough parameters");
5057
5058 char *name = NULL;
5059 char *hostpath = NULL;
5060 bool fTransient = false;
5061 bool fWritable = true;
5062
5063 for (int i = 2; i < argc; i++)
5064 {
5065 if (strcmp(argv[i], "-name") == 0)
5066 {
5067 if (argc <= i + 1 || !*argv[i+1])
5068 return errorArgument("Missing argument to '%s'", argv[i]);
5069 i++;
5070 name = argv[i];
5071 }
5072 else if (strcmp(argv[i], "-hostpath") == 0)
5073 {
5074 if (argc <= i + 1 || !*argv[i+1])
5075 return errorArgument("Missing argument to '%s'", argv[i]);
5076 i++;
5077 hostpath = argv[i];
5078 }
5079 else if (strcmp(argv[i], "-readonly") == 0)
5080 {
5081 fWritable = false;
5082 }
5083 else if (strcmp(argv[i], "-transient") == 0)
5084 {
5085 fTransient = true;
5086 }
5087 else
5088 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Invalid parameter '%s'", Utf8Str(argv[i]).raw());
5089 }
5090
5091 if (NULL != strstr(name, " "))
5092 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "No spaces allowed in parameter '-name'!");
5093
5094 /* required arguments */
5095 if (!name || !hostpath)
5096 {
5097 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Parameters -name and -hostpath are required");
5098 }
5099
5100 if (fTransient)
5101 {
5102 ComPtr <IConsole> console;
5103
5104 /* open an existing session for the VM */
5105 CHECK_ERROR_RET(aVirtualBox, OpenExistingSession (aSession, uuid), 1);
5106 /* get the session machine */
5107 CHECK_ERROR_RET(aSession, COMGETTER(Machine)(machine.asOutParam()), 1);
5108 /* get the session console */
5109 CHECK_ERROR_RET(aSession, COMGETTER(Console)(console.asOutParam()), 1);
5110
5111 CHECK_ERROR(console, CreateSharedFolder(Bstr(name), Bstr(hostpath), fWritable));
5112
5113 if (console)
5114 aSession->Close();
5115 }
5116 else
5117 {
5118 /* open a session for the VM */
5119 CHECK_ERROR_RET (aVirtualBox, OpenSession(aSession, uuid), 1);
5120
5121 /* get the mutable session machine */
5122 aSession->COMGETTER(Machine)(machine.asOutParam());
5123
5124 CHECK_ERROR(machine, CreateSharedFolder(Bstr(name), Bstr(hostpath), fWritable));
5125
5126 if (SUCCEEDED(rc))
5127 CHECK_ERROR(machine, SaveSettings());
5128
5129 aSession->Close();
5130 }
5131 }
5132 else if (strcmp(argv[0], "remove") == 0)
5133 {
5134 /* we need at least two more parameters */
5135 if (argc < 3)
5136 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Not enough parameters");
5137
5138 char *name = NULL;
5139 bool fTransient = false;
5140
5141 for (int i = 2; i < argc; i++)
5142 {
5143 if (strcmp(argv[i], "-name") == 0)
5144 {
5145 if (argc <= i + 1 || !*argv[i+1])
5146 return errorArgument("Missing argument to '%s'", argv[i]);
5147 i++;
5148 name = argv[i];
5149 }
5150 else if (strcmp(argv[i], "-transient") == 0)
5151 {
5152 fTransient = true;
5153 }
5154 else
5155 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Invalid parameter '%s'", Utf8Str(argv[i]).raw());
5156 }
5157
5158 /* required arguments */
5159 if (!name)
5160 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Parameter -name is required");
5161
5162 if (fTransient)
5163 {
5164 ComPtr <IConsole> console;
5165
5166 /* open an existing session for the VM */
5167 CHECK_ERROR_RET(aVirtualBox, OpenExistingSession (aSession, uuid), 1);
5168 /* get the session machine */
5169 CHECK_ERROR_RET(aSession, COMGETTER(Machine)(machine.asOutParam()), 1);
5170 /* get the session console */
5171 CHECK_ERROR_RET(aSession, COMGETTER(Console)(console.asOutParam()), 1);
5172
5173 CHECK_ERROR(console, RemoveSharedFolder(Bstr(name)));
5174
5175 if (console)
5176 aSession->Close();
5177 }
5178 else
5179 {
5180 /* open a session for the VM */
5181 CHECK_ERROR_RET (aVirtualBox, OpenSession(aSession, uuid), 1);
5182
5183 /* get the mutable session machine */
5184 aSession->COMGETTER(Machine)(machine.asOutParam());
5185
5186 CHECK_ERROR(machine, RemoveSharedFolder(Bstr(name)));
5187
5188 /* commit and close the session */
5189 CHECK_ERROR(machine, SaveSettings());
5190 aSession->Close();
5191 }
5192 }
5193 else
5194 return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", Utf8Str(argv[0]).raw());
5195
5196 return 0;
5197}
5198
5199static int handleVMStatistics(int argc, char *argv[],
5200 ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
5201{
5202 HRESULT rc;
5203
5204 /* at least one option: the UUID or name of the VM */
5205 if (argc < 1)
5206 return errorSyntax(USAGE_VM_STATISTICS, "Incorrect number of parameters");
5207
5208 /* try to find the given machine */
5209 ComPtr <IMachine> machine;
5210 Guid uuid (argv[0]);
5211 if (!uuid.isEmpty())
5212 CHECK_ERROR(aVirtualBox, GetMachine(uuid, machine.asOutParam()));
5213 else
5214 {
5215 CHECK_ERROR(aVirtualBox, FindMachine(Bstr(argv[0]), machine.asOutParam()));
5216 if (SUCCEEDED (rc))
5217 machine->COMGETTER(Id)(uuid.asOutParam());
5218 }
5219 if (FAILED(rc))
5220 return 1;
5221
5222 /* parse arguments. */
5223 bool fReset = false;
5224 bool fWithDescriptions = false;
5225 const char *pszPattern = NULL; /* all */
5226 for (int i = 1; i < argc; i++)
5227 {
5228 if (!strcmp(argv[i], "-pattern"))
5229 {
5230 if (pszPattern)
5231 return errorSyntax(USAGE_VM_STATISTICS, "Multiple -patterns options is not permitted");
5232 if (i + 1 >= argc)
5233 return errorArgument("Missing argument to '%s'", argv[i]);
5234 pszPattern = argv[++i];
5235 }
5236 else if (!strcmp(argv[i], "-descriptions"))
5237 fWithDescriptions = true;
5238 /* add: -file <filename> and -formatted */
5239 else if (!strcmp(argv[i], "-reset"))
5240 fReset = true;
5241 else
5242 return errorSyntax(USAGE_VM_STATISTICS, "Unknown option '%s'", argv[i]);
5243 }
5244 if (fReset && fWithDescriptions)
5245 return errorSyntax(USAGE_VM_STATISTICS, "The -reset and -descriptions options does not mix");
5246
5247
5248 /* open an existing session for the VM. */
5249 CHECK_ERROR(aVirtualBox, OpenExistingSession(aSession, uuid));
5250 if (SUCCEEDED(rc))
5251 {
5252 /* get the session console. */
5253 ComPtr <IConsole> console;
5254 CHECK_ERROR(aSession, COMGETTER(Console)(console.asOutParam()));
5255 if (SUCCEEDED(rc))
5256 {
5257 /* get the machine debugger. */
5258 ComPtr <IMachineDebugger> debugger;
5259 CHECK_ERROR(console, COMGETTER(Debugger)(debugger.asOutParam()));
5260 if (SUCCEEDED(rc))
5261 {
5262 if (fReset)
5263 CHECK_ERROR(debugger, ResetStats(Bstr(pszPattern).raw()));
5264 else
5265 {
5266 Bstr stats;
5267 CHECK_ERROR(debugger, GetStats(Bstr(pszPattern).raw(), fWithDescriptions, stats.asOutParam()));
5268 if (SUCCEEDED(rc))
5269 {
5270 /* if (fFormatted)
5271 { big mess }
5272 else
5273 */
5274 RTPrintf("%ls\n", stats.raw());
5275 }
5276 }
5277 }
5278 aSession->Close();
5279 }
5280 }
5281
5282 return SUCCEEDED(rc) ? 0 : 1;
5283}
5284
5285static char *toBaseMetricNames(const char *metricList)
5286{
5287 char *newList = (char*)RTMemAlloc(strlen(metricList) + 1);
5288 int cSlashes = 0;
5289 bool fSkip = false;
5290 const char *src = metricList;
5291 char c, *dst = newList;
5292 while ((c = *src++))
5293 if (c == ':')
5294 fSkip = true;
5295 else if (c == '/' && ++cSlashes == 2)
5296 fSkip = true;
5297 else if (c == ',')
5298 {
5299 fSkip = false;
5300 cSlashes = 0;
5301 *dst++ = c;
5302 }
5303 else
5304 if (!fSkip)
5305 *dst++ = c;
5306 *dst = 0;
5307 return newList;
5308}
5309
5310static int parseFilterParameters(int argc, char *argv[],
5311 ComPtr<IVirtualBox> aVirtualBox,
5312 ComSafeArrayOut(BSTR, outMetrics),
5313 ComSafeArrayOut(BSTR, outBaseMetrics),
5314 ComSafeArrayOut(IUnknown *, outObjects))
5315{
5316 HRESULT rc = S_OK;
5317 com::SafeArray<BSTR> retMetrics(1);
5318 com::SafeArray<BSTR> retBaseMetrics(1);
5319 com::SafeIfaceArray <IUnknown> retObjects;
5320
5321 Bstr metricNames, baseNames;
5322
5323 /* Metric list */
5324 if (argc > 1)
5325 {
5326 metricNames = argv[1];
5327 char *tmp = toBaseMetricNames(argv[1]);
5328 if (!tmp)
5329 return VERR_NO_MEMORY;
5330 baseNames = tmp;
5331 RTMemFree(tmp);
5332 }
5333 else
5334 {
5335 metricNames = L"*";
5336 baseNames = L"*";
5337 }
5338 metricNames.cloneTo(&retMetrics[0]);
5339 baseNames.cloneTo(&retBaseMetrics[0]);
5340
5341 /* Object name */
5342 if (argc > 0 && strcmp(argv[0], "*"))
5343 {
5344 if (!strcmp(argv[0], "host"))
5345 {
5346 ComPtr<IHost> host;
5347 CHECK_ERROR(aVirtualBox, COMGETTER(Host)(host.asOutParam()));
5348 retObjects.reset(1);
5349 host.queryInterfaceTo(&retObjects[0]);
5350 }
5351 else
5352 {
5353 ComPtr <IMachine> machine;
5354 rc = aVirtualBox->FindMachine(Bstr(argv[0]), machine.asOutParam());
5355 if (SUCCEEDED (rc))
5356 {
5357 retObjects.reset(1);
5358 machine.queryInterfaceTo(&retObjects[0]);
5359 }
5360 else
5361 {
5362 errorArgument("Invalid machine name: '%s'", argv[0]);
5363 return rc;
5364 }
5365 }
5366
5367 }
5368
5369 retMetrics.detachTo(ComSafeArrayOutArg(outMetrics));
5370 retBaseMetrics.detachTo(ComSafeArrayOutArg(outBaseMetrics));
5371 retObjects.detachTo(ComSafeArrayOutArg(outObjects));
5372
5373 return rc;
5374}
5375
5376static Bstr getObjectName(ComPtr<IVirtualBox> aVirtualBox,
5377 ComPtr<IUnknown> aObject)
5378{
5379 HRESULT rc;
5380
5381 ComPtr<IHost> host = aObject;
5382 if (!host.isNull())
5383 return Bstr("host");
5384
5385 ComPtr<IMachine> machine = aObject;
5386 if (!machine.isNull())
5387 {
5388 Bstr name;
5389 CHECK_ERROR(machine, COMGETTER(Name)(name.asOutParam()));
5390 if (SUCCEEDED(rc))
5391 return name;
5392 }
5393 return Bstr("unknown");
5394}
5395
5396static void listAffectedMetrics(ComPtr<IVirtualBox> aVirtualBox,
5397 ComSafeArrayIn(IPerformanceMetric*, aMetrics))
5398{
5399 HRESULT rc;
5400 com::SafeIfaceArray<IPerformanceMetric> metrics(ComSafeArrayInArg(aMetrics));
5401 if (metrics.size())
5402 {
5403 ComPtr<IUnknown> object;
5404 Bstr metricName;
5405 RTPrintf("The following metrics were modified:\n\n"
5406 "Object Metric\n"
5407 "---------- --------------------\n");
5408 for (size_t i = 0; i < metrics.size(); i++)
5409 {
5410 CHECK_ERROR(metrics[i], COMGETTER(Object)(object.asOutParam()));
5411 CHECK_ERROR(metrics[i], COMGETTER(MetricName)(metricName.asOutParam()));
5412 RTPrintf("%-10ls %-20ls\n",
5413 getObjectName(aVirtualBox, object).raw(), metricName.raw());
5414 }
5415 RTPrintf("\n");
5416 }
5417 else
5418 {
5419 RTPrintf("No metrics match the specified filter!\n");
5420 }
5421}
5422
5423/**
5424 * list *
5425 */
5426static int handleMetricsList(int argc, char *argv[],
5427 ComPtr<IVirtualBox> aVirtualBox,
5428 ComPtr<IPerformanceCollector> performanceCollector)
5429{
5430 HRESULT rc;
5431 com::SafeArray<BSTR> metrics;
5432 com::SafeArray<BSTR> baseMetrics;
5433 com::SafeIfaceArray<IUnknown> objects;
5434
5435 rc = parseFilterParameters(argc - 1, &argv[1], aVirtualBox,
5436 ComSafeArrayAsOutParam(metrics),
5437 ComSafeArrayAsOutParam(baseMetrics),
5438 ComSafeArrayAsOutParam(objects));
5439 if (FAILED(rc))
5440 return 1;
5441
5442 com::SafeIfaceArray<IPerformanceMetric> metricInfo;
5443
5444 CHECK_ERROR(performanceCollector,
5445 GetMetrics(ComSafeArrayAsInParam(metrics),
5446 ComSafeArrayAsInParam(objects),
5447 ComSafeArrayAsOutParam(metricInfo)));
5448
5449 ComPtr<IUnknown> object;
5450 Bstr metricName, unit, description;
5451 ULONG period, count;
5452 LONG minimum, maximum;
5453 RTPrintf(
5454"Object Metric Unit Minimum Maximum Period Count Description\n"
5455"---------- -------------------- ---- ---------- ---------- ---------- ---------- -----------\n");
5456 for (size_t i = 0; i < metricInfo.size(); i++)
5457 {
5458 CHECK_ERROR(metricInfo[i], COMGETTER(Object)(object.asOutParam()));
5459 CHECK_ERROR(metricInfo[i], COMGETTER(MetricName)(metricName.asOutParam()));
5460 CHECK_ERROR(metricInfo[i], COMGETTER(Period)(&period));
5461 CHECK_ERROR(metricInfo[i], COMGETTER(Count)(&count));
5462 CHECK_ERROR(metricInfo[i], COMGETTER(MinimumValue)(&minimum));
5463 CHECK_ERROR(metricInfo[i], COMGETTER(MaximumValue)(&maximum));
5464 CHECK_ERROR(metricInfo[i], COMGETTER(Unit)(unit.asOutParam()));
5465 CHECK_ERROR(metricInfo[i], COMGETTER(Description)(description.asOutParam()));
5466 RTPrintf("%-10ls %-20ls %-4ls %10d %10d %10u %10u %ls\n",
5467 getObjectName(aVirtualBox, object).raw(), metricName.raw(), unit.raw(),
5468 minimum, maximum, period, count, description.raw());
5469 }
5470
5471 return 0;
5472}
5473
5474/**
5475 * Metics setup
5476 */
5477static int handleMetricsSetup(int argc, char *argv[],
5478 ComPtr<IVirtualBox> aVirtualBox,
5479 ComPtr<IPerformanceCollector> performanceCollector)
5480{
5481 HRESULT rc;
5482 com::SafeArray<BSTR> metrics;
5483 com::SafeArray<BSTR> baseMetrics;
5484 com::SafeIfaceArray<IUnknown> objects;
5485 ULONG period = 1, samples = 1;
5486 bool listMatches = false;
5487 int i;
5488
5489 for (i = 1; i < argc; i++)
5490 {
5491 if (strcmp(argv[i], "-period") == 0)
5492 {
5493 if (argc <= i + 1)
5494 return errorArgument("Missing argument to '%s'", argv[i]);
5495 char *endptr = NULL;
5496 period = strtoul (argv[++i], &endptr, 10);
5497 if (!endptr || *endptr || !period)
5498 return errorArgument("Invalid value for 'period' parameter: '%s'", argv[i]);
5499 }
5500 else if (strcmp(argv[i], "-samples") == 0)
5501 {
5502 if (argc <= i + 1)
5503 return errorArgument("Missing argument to '%s'", argv[i]);
5504 char *endptr = NULL;
5505 samples = strtoul (argv[++i], &endptr, 10);
5506 if (!endptr || *endptr)
5507 return errorArgument("Invalid value for 'samples' parameter: '%s'", argv[i]);
5508 }
5509 else if (strcmp(argv[i], "-list") == 0)
5510 listMatches = true;
5511 else
5512 break; /* The rest of params should define the filter */
5513 }
5514
5515 rc = parseFilterParameters(argc - i, &argv[i], aVirtualBox,
5516 ComSafeArrayAsOutParam(metrics),
5517 ComSafeArrayAsOutParam(baseMetrics),
5518 ComSafeArrayAsOutParam(objects));
5519 if (FAILED(rc))
5520 return 1;
5521
5522 com::SafeIfaceArray<IPerformanceMetric> affectedMetrics;
5523 CHECK_ERROR(performanceCollector,
5524 SetupMetrics(ComSafeArrayAsInParam(metrics),
5525 ComSafeArrayAsInParam(objects), period, samples,
5526 ComSafeArrayAsOutParam(affectedMetrics)));
5527 if (listMatches)
5528 listAffectedMetrics(aVirtualBox,
5529 ComSafeArrayAsInParam(affectedMetrics));
5530
5531 return 0;
5532}
5533
5534/**
5535 * metrics query
5536 */
5537static int handleMetricsQuery(int argc, char *argv[],
5538 ComPtr<IVirtualBox> aVirtualBox,
5539 ComPtr<IPerformanceCollector> performanceCollector)
5540{
5541 HRESULT rc;
5542 com::SafeArray<BSTR> metrics;
5543 com::SafeArray<BSTR> baseMetrics;
5544 com::SafeIfaceArray<IUnknown> objects;
5545
5546 rc = parseFilterParameters(argc - 1, &argv[1], aVirtualBox,
5547 ComSafeArrayAsOutParam(metrics),
5548 ComSafeArrayAsOutParam(baseMetrics),
5549 ComSafeArrayAsOutParam(objects));
5550 if (FAILED(rc))
5551 return 1;
5552
5553 com::SafeArray<BSTR> retNames;
5554 com::SafeIfaceArray<IUnknown> retObjects;
5555 com::SafeArray<BSTR> retUnits;
5556 com::SafeArray<ULONG> retScales;
5557 com::SafeArray<ULONG> retSequenceNumbers;
5558 com::SafeArray<ULONG> retIndices;
5559 com::SafeArray<ULONG> retLengths;
5560 com::SafeArray<LONG> retData;
5561 CHECK_ERROR (performanceCollector, QueryMetricsData(ComSafeArrayAsInParam(metrics),
5562 ComSafeArrayAsInParam(objects),
5563 ComSafeArrayAsOutParam(retNames),
5564 ComSafeArrayAsOutParam(retObjects),
5565 ComSafeArrayAsOutParam(retUnits),
5566 ComSafeArrayAsOutParam(retScales),
5567 ComSafeArrayAsOutParam(retSequenceNumbers),
5568 ComSafeArrayAsOutParam(retIndices),
5569 ComSafeArrayAsOutParam(retLengths),
5570 ComSafeArrayAsOutParam(retData)) );
5571
5572 RTPrintf("Object Metric Values\n"
5573 "---------- -------------------- --------------------------------------------\n");
5574 for (unsigned i = 0; i < retNames.size(); i++)
5575 {
5576 Bstr metricUnit(retUnits[i]);
5577 Bstr metricName(retNames[i]);
5578 RTPrintf("%-10ls %-20ls ", getObjectName(aVirtualBox, retObjects[i]).raw(), metricName.raw());
5579 const char *separator = "";
5580 for (unsigned j = 0; j < retLengths[i]; j++)
5581 {
5582 if (retScales[i] == 1)
5583 RTPrintf("%s%d %ls", separator, retData[retIndices[i] + j], metricUnit.raw());
5584 else
5585 RTPrintf("%s%d.%02d%ls", separator, retData[retIndices[i] + j] / retScales[i],
5586 (retData[retIndices[i] + j] * 100 / retScales[i]) % 100, metricUnit.raw());
5587 separator = ", ";
5588 }
5589 RTPrintf("\n");
5590 }
5591
5592 return 0;
5593}
5594
5595static void getTimestamp(char *pts, size_t tsSize)
5596{
5597 *pts = 0;
5598 AssertReturnVoid(tsSize >= 13); /* 3+3+3+3+1 */
5599 RTTIMESPEC TimeSpec;
5600 RTTIME Time;
5601 RTTimeExplode(&Time, RTTimeNow(&TimeSpec));
5602 pts += RTStrFormatNumber(pts, Time.u8Hour, 10, 2, 0, RTSTR_F_ZEROPAD);
5603 *pts++ = ':';
5604 pts += RTStrFormatNumber(pts, Time.u8Minute, 10, 2, 0, RTSTR_F_ZEROPAD);
5605 *pts++ = ':';
5606 pts += RTStrFormatNumber(pts, Time.u8Second, 10, 2, 0, RTSTR_F_ZEROPAD);
5607 *pts++ = '.';
5608 pts += RTStrFormatNumber(pts, Time.u32Nanosecond / 1000000, 10, 3, 0, RTSTR_F_ZEROPAD);
5609 *pts = 0;
5610}
5611
5612/** Used by the handleMetricsCollect loop. */
5613static bool volatile g_fKeepGoing = true;
5614
5615#ifdef RT_OS_WINDOWS
5616/**
5617 * Handler routine for catching Ctrl-C, Ctrl-Break and closing of
5618 * the console.
5619 *
5620 * @returns true if handled, false if not handled.
5621 * @param dwCtrlType The type of control signal.
5622 *
5623 * @remarks This is called on a new thread.
5624 */
5625static BOOL WINAPI ctrlHandler(DWORD dwCtrlType)
5626{
5627 switch (dwCtrlType)
5628 {
5629 /* Ctrl-C or Ctrl-Break or Close */
5630 case CTRL_C_EVENT:
5631 case CTRL_BREAK_EVENT:
5632 case CTRL_CLOSE_EVENT:
5633 /* Let's shut down gracefully. */
5634 ASMAtomicWriteBool(&g_fKeepGoing, false);
5635 return TRUE;
5636 }
5637 /* Don't care about the rest -- let it die a horrible death. */
5638 return FALSE;
5639}
5640#endif /* RT_OS_WINDOWS */
5641
5642/**
5643 * collect
5644 */
5645static int handleMetricsCollect(int argc, char *argv[],
5646 ComPtr<IVirtualBox> aVirtualBox,
5647 ComPtr<IPerformanceCollector> performanceCollector)
5648{
5649 HRESULT rc;
5650 com::SafeArray<BSTR> metrics;
5651 com::SafeArray<BSTR> baseMetrics;
5652 com::SafeIfaceArray<IUnknown> objects;
5653 ULONG period = 1, samples = 1;
5654 bool isDetached = false, listMatches = false;
5655 int i;
5656 for (i = 1; i < argc; i++)
5657 {
5658 if (strcmp(argv[i], "-period") == 0)
5659 {
5660 if (argc <= i + 1)
5661 return errorArgument("Missing argument to '%s'", argv[i]);
5662 char *endptr = NULL;
5663 period = strtoul (argv[++i], &endptr, 10);
5664 if (!endptr || *endptr || !period)
5665 return errorArgument("Invalid value for 'period' parameter: '%s'", argv[i]);
5666 }
5667 else if (strcmp(argv[i], "-samples") == 0)
5668 {
5669 if (argc <= i + 1)
5670 return errorArgument("Missing argument to '%s'", argv[i]);
5671 char *endptr = NULL;
5672 samples = strtoul (argv[++i], &endptr, 10);
5673 if (!endptr || *endptr || !samples)
5674 return errorArgument("Invalid value for 'samples' parameter: '%s'", argv[i]);
5675 }
5676 else if (strcmp(argv[i], "-list") == 0)
5677 listMatches = true;
5678 else if (strcmp(argv[i], "-detach") == 0)
5679 isDetached = true;
5680 else
5681 break; /* The rest of params should define the filter */
5682 }
5683
5684 rc = parseFilterParameters(argc - i, &argv[i], aVirtualBox,
5685 ComSafeArrayAsOutParam(metrics),
5686 ComSafeArrayAsOutParam(baseMetrics),
5687 ComSafeArrayAsOutParam(objects));
5688 if (FAILED(rc))
5689 return 1;
5690
5691
5692 com::SafeIfaceArray<IPerformanceMetric> affectedMetrics;
5693 CHECK_ERROR(performanceCollector,
5694 SetupMetrics(ComSafeArrayAsInParam(baseMetrics),
5695 ComSafeArrayAsInParam(objects), period, samples,
5696 ComSafeArrayAsOutParam(affectedMetrics)));
5697 if (listMatches)
5698 listAffectedMetrics(aVirtualBox,
5699 ComSafeArrayAsInParam(affectedMetrics));
5700 if (!affectedMetrics.size())
5701 return 1;
5702
5703 if (isDetached)
5704 {
5705 RTPrintf("Warning! The background process holding collected metrics will shutdown\n"
5706 "in few seconds, discarding all collected data and parameters.\n");
5707 return 0;
5708 }
5709
5710#ifdef RT_OS_WINDOWS
5711 SetConsoleCtrlHandler(ctrlHandler, true);
5712#endif /* RT_OS_WINDOWS */
5713
5714 RTPrintf("Time stamp Object Metric Value\n");
5715
5716 while (g_fKeepGoing)
5717 {
5718 RTPrintf("------------ ---------- -------------------- --------------------\n");
5719 RTThreadSleep(period * 1000); // Sleep for 'period' seconds
5720 char ts[15];
5721
5722 getTimestamp(ts, sizeof(ts));
5723 com::SafeArray<BSTR> retNames;
5724 com::SafeIfaceArray<IUnknown> retObjects;
5725 com::SafeArray<BSTR> retUnits;
5726 com::SafeArray<ULONG> retScales;
5727 com::SafeArray<ULONG> retSequenceNumbers;
5728 com::SafeArray<ULONG> retIndices;
5729 com::SafeArray<ULONG> retLengths;
5730 com::SafeArray<LONG> retData;
5731 CHECK_ERROR (performanceCollector, QueryMetricsData(ComSafeArrayAsInParam(metrics),
5732 ComSafeArrayAsInParam(objects),
5733 ComSafeArrayAsOutParam(retNames),
5734 ComSafeArrayAsOutParam(retObjects),
5735 ComSafeArrayAsOutParam(retUnits),
5736 ComSafeArrayAsOutParam(retScales),
5737 ComSafeArrayAsOutParam(retSequenceNumbers),
5738 ComSafeArrayAsOutParam(retIndices),
5739 ComSafeArrayAsOutParam(retLengths),
5740 ComSafeArrayAsOutParam(retData)) );
5741 for (unsigned i = 0; i < retNames.size(); i++)
5742 {
5743 Bstr metricUnit(retUnits[i]);
5744 Bstr metricName(retNames[i]);
5745 RTPrintf("%-12s %-10ls %-20ls ", ts, getObjectName(aVirtualBox, retObjects[i]).raw(), metricName.raw());
5746 const char *separator = "";
5747 for (unsigned j = 0; j < retLengths[i]; j++)
5748 {
5749 if (retScales[i] == 1)
5750 RTPrintf("%s%d %ls", separator, retData[retIndices[i] + j], metricUnit.raw());
5751 else
5752 RTPrintf("%s%d.%02d%ls", separator, retData[retIndices[i] + j] / retScales[i],
5753 (retData[retIndices[i] + j] * 100 / retScales[i]) % 100, metricUnit.raw());
5754 separator = ", ";
5755 }
5756 RTPrintf("\n");
5757 }
5758 }
5759
5760#ifdef RT_OS_WINDOWS
5761 SetConsoleCtrlHandler(ctrlHandler, false);
5762#endif /* RT_OS_WINDOWS */
5763
5764 return 0;
5765}
5766
5767static int handleMetrics(int argc, char *argv[],
5768 ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
5769{
5770 int rc;
5771
5772 /* at least one option: subcommand name */
5773 if (argc < 1)
5774 return errorSyntax(USAGE_METRICS, "Subcommand missing");
5775
5776 ComPtr<IPerformanceCollector> performanceCollector;
5777 CHECK_ERROR(aVirtualBox, COMGETTER(PerformanceCollector)(performanceCollector.asOutParam()));
5778
5779 if (!strcmp(argv[0], "list"))
5780 rc = handleMetricsList(argc, argv, aVirtualBox, performanceCollector);
5781 else if (!strcmp(argv[0], "setup"))
5782 rc = handleMetricsSetup(argc, argv, aVirtualBox, performanceCollector);
5783 else if (!strcmp(argv[0], "query"))
5784 rc = handleMetricsQuery(argc, argv, aVirtualBox, performanceCollector);
5785 else if (!strcmp(argv[0], "collect"))
5786 rc = handleMetricsCollect(argc, argv, aVirtualBox, performanceCollector);
5787 else
5788 return errorSyntax(USAGE_METRICS, "Invalid subcommand '%s'", argv[0]);
5789
5790 return rc;
5791}
5792#endif /* !VBOX_ONLY_DOCS */
5793
5794enum ConvertSettings
5795{
5796 ConvertSettings_No = 0,
5797 ConvertSettings_Yes = 1,
5798 ConvertSettings_Backup = 2,
5799 ConvertSettings_Ignore = 3,
5800};
5801
5802#ifndef VBOX_ONLY_DOCS
5803/**
5804 * Checks if any of the settings files were auto-converted and informs the
5805 * user if so.
5806 *
5807 * @return @false if the program should terminate and @true otherwise.
5808 */
5809static bool checkForAutoConvertedSettings (ComPtr<IVirtualBox> virtualBox,
5810 ComPtr<ISession> session,
5811 ConvertSettings fConvertSettings)
5812{
5813 /* return early if nothing to do */
5814 if (fConvertSettings == ConvertSettings_Ignore)
5815 return true;
5816
5817 HRESULT rc;
5818
5819 do
5820 {
5821 Bstr formatVersion;
5822 CHECK_RC_BREAK (virtualBox->
5823 COMGETTER(SettingsFormatVersion) (formatVersion.asOutParam()));
5824
5825 bool isGlobalConverted = false;
5826 std::list <ComPtr <IMachine> > cvtMachines;
5827 std::list <Utf8Str> fileList;
5828 Bstr version;
5829 Bstr filePath;
5830
5831 com::SafeIfaceArray <IMachine> machines;
5832 CHECK_RC_BREAK (virtualBox->
5833 COMGETTER(Machines2) (ComSafeArrayAsOutParam (machines)));
5834
5835 for (size_t i = 0; i < machines.size(); ++ i)
5836 {
5837 BOOL accessible;
5838 CHECK_RC_BREAK (machines [i]->
5839 COMGETTER(Accessible) (&accessible));
5840 if (!accessible)
5841 continue;
5842
5843 CHECK_RC_BREAK (machines [i]->
5844 COMGETTER(SettingsFileVersion) (version.asOutParam()));
5845
5846 if (version != formatVersion)
5847 {
5848 cvtMachines.push_back (machines [i]);
5849 Bstr filePath;
5850 CHECK_RC_BREAK (machines [i]->
5851 COMGETTER(SettingsFilePath) (filePath.asOutParam()));
5852 fileList.push_back (Utf8StrFmt ("%ls (%ls)", filePath.raw(),
5853 version.raw()));
5854 }
5855 }
5856
5857 CHECK_RC_BREAK (rc);
5858
5859 CHECK_RC_BREAK (virtualBox->
5860 COMGETTER(SettingsFileVersion) (version.asOutParam()));
5861 if (version != formatVersion)
5862 {
5863 isGlobalConverted = true;
5864 CHECK_RC_BREAK (virtualBox->
5865 COMGETTER(SettingsFilePath) (filePath.asOutParam()));
5866 fileList.push_back (Utf8StrFmt ("%ls (%ls)", filePath.raw(),
5867 version.raw()));
5868 }
5869
5870 if (fileList.size() > 0)
5871 {
5872 switch (fConvertSettings)
5873 {
5874 case ConvertSettings_No:
5875 {
5876 RTPrintf (
5877"WARNING! The following VirtualBox settings files have been automatically\n"
5878"converted to the new settings file format version '%ls':\n"
5879"\n",
5880 formatVersion.raw());
5881
5882 for (std::list <Utf8Str>::const_iterator f = fileList.begin();
5883 f != fileList.end(); ++ f)
5884 RTPrintf (" %S\n", (*f).raw());
5885 RTPrintf (
5886"\n"
5887"The current command was aborted to prevent overwriting the above settings\n"
5888"files with the results of the auto-conversion without your permission.\n"
5889"Please put one of the following command line switches to the beginning of\n"
5890"the VBoxManage command line and repeat the command:\n"
5891"\n"
5892" -convertSettings - to save all auto-converted files (it will not\n"
5893" be possible to use these settings files with an\n"
5894" older version of VirtualBox in the future);\n"
5895" -convertSettingsBackup - to create backup copies of the settings files in\n"
5896" the old format before saving them in the new format;\n"
5897" -convertSettingsIgnore - to not save the auto-converted settings files.\n"
5898"\n"
5899"Note that if you use -convertSettingsIgnore, the auto-converted settings files\n"
5900"will be implicitly saved in the new format anyway once you change a setting or\n"
5901"start a virtual machine, but NO backup copies will be created in this case.\n");
5902 return false;
5903 }
5904 case ConvertSettings_Yes:
5905 case ConvertSettings_Backup:
5906 {
5907 break;
5908 }
5909 default:
5910 AssertFailedReturn (false);
5911 }
5912
5913 for (std::list <ComPtr <IMachine> >::const_iterator m = cvtMachines.begin();
5914 m != cvtMachines.end(); ++ m)
5915 {
5916 Guid id;
5917 CHECK_RC_BREAK ((*m)->COMGETTER(Id) (id.asOutParam()));
5918
5919 /* open a session for the VM */
5920 CHECK_ERROR_BREAK (virtualBox, OpenSession (session, id));
5921
5922 ComPtr <IMachine> sm;
5923 CHECK_RC_BREAK (session->COMGETTER(Machine) (sm.asOutParam()));
5924
5925 Bstr bakFileName;
5926 if (fConvertSettings == ConvertSettings_Backup)
5927 CHECK_ERROR (sm, SaveSettingsWithBackup (bakFileName.asOutParam()));
5928 else
5929 CHECK_ERROR (sm, SaveSettings());
5930
5931 session->Close();
5932
5933 CHECK_RC_BREAK (rc);
5934 }
5935
5936 CHECK_RC_BREAK (rc);
5937
5938 if (isGlobalConverted)
5939 {
5940 Bstr bakFileName;
5941 if (fConvertSettings == ConvertSettings_Backup)
5942 CHECK_ERROR (virtualBox, SaveSettingsWithBackup (bakFileName.asOutParam()));
5943 else
5944 CHECK_ERROR (virtualBox, SaveSettings());
5945 }
5946
5947 CHECK_RC_BREAK (rc);
5948 }
5949 }
5950 while (0);
5951
5952 return SUCCEEDED (rc);
5953}
5954#endif /* !VBOX_ONLY_DOCS */
5955
5956// main
5957///////////////////////////////////////////////////////////////////////////////
5958
5959int main(int argc, char *argv[])
5960{
5961 /*
5962 * Before we do anything, init the runtime without loading
5963 * the support driver.
5964 */
5965 RTR3Init();
5966
5967 bool fShowLogo = true;
5968 int iCmd = 1;
5969 int iCmdArg;
5970
5971 ConvertSettings fConvertSettings = ConvertSettings_No;
5972
5973 /* global options */
5974 for (int i = 1; i < argc || argc <= iCmd; i++)
5975 {
5976 if ( argc <= iCmd
5977 || (strcmp(argv[i], "help") == 0)
5978 || (strcmp(argv[i], "-?") == 0)
5979 || (strcmp(argv[i], "-h") == 0)
5980 || (strcmp(argv[i], "-help") == 0)
5981 || (strcmp(argv[i], "--help") == 0))
5982 {
5983 showLogo();
5984 printUsage(USAGE_ALL);
5985 return 0;
5986 }
5987 else if ( strcmp(argv[i], "-v") == 0
5988 || strcmp(argv[i], "-version") == 0
5989 || strcmp(argv[i], "-Version") == 0
5990 || strcmp(argv[i], "--version") == 0)
5991 {
5992 /* Print version number, and do nothing else. */
5993 RTPrintf("%sr%d\n", VBOX_VERSION_STRING, VBoxSVNRev ());
5994 exit(0);
5995 }
5996 else if (strcmp(argv[i], "-dumpopts") == 0)
5997 {
5998 /* Special option to dump really all commands,
5999 * even the ones not understood on this platform. */
6000 printUsage(USAGE_DUMPOPTS);
6001 return 0;
6002 }
6003 else if (strcmp(argv[i], "-nologo") == 0)
6004 {
6005 /* suppress the logo */
6006 fShowLogo = false;
6007 iCmd++;
6008 }
6009 else if (strcmp(argv[i], "-convertSettings") == 0)
6010 {
6011 fConvertSettings = ConvertSettings_Yes;
6012 iCmd++;
6013 }
6014 else if (strcmp(argv[i], "-convertSettingsBackup") == 0)
6015 {
6016 fConvertSettings = ConvertSettings_Backup;
6017 iCmd++;
6018 }
6019 else if (strcmp(argv[i], "-convertSettingsIgnore") == 0)
6020 {
6021 fConvertSettings = ConvertSettings_Ignore;
6022 iCmd++;
6023 }
6024 else
6025 {
6026 break;
6027 }
6028 }
6029
6030 iCmdArg = iCmd + 1;
6031
6032 if (fShowLogo)
6033 showLogo();
6034
6035
6036#ifdef VBOX_ONLY_DOCS
6037 int rc = 0;
6038#else /* !VBOX_ONLY_DOCS */
6039 HRESULT rc = 0;
6040
6041 CHECK_RC_RET (com::Initialize());
6042
6043 /*
6044 * The input is in the host OS'es codepage (NT guarantees ACP).
6045 * For VBox we use UTF-8 and convert to UCS-2 when calling (XP)COM APIs.
6046 * For simplicity, just convert the argv[] array here.
6047 */
6048 for (int i = iCmdArg; i < argc; i++)
6049 {
6050 char *converted;
6051 RTStrCurrentCPToUtf8(&converted, argv[i]);
6052 argv[i] = converted;
6053 }
6054
6055 do
6056 {
6057 // scopes all the stuff till shutdown
6058 ////////////////////////////////////////////////////////////////////////////
6059
6060 /* convertdd: does not need a VirtualBox instantiation) */
6061 if (argc >= iCmdArg && (strcmp(argv[iCmd], "convertdd") == 0))
6062 {
6063 rc = handleConvertDDImage(argc - iCmdArg, argv + iCmdArg);
6064 break;
6065 }
6066
6067 ComPtr <IVirtualBox> virtualBox;
6068 ComPtr <ISession> session;
6069
6070 rc = virtualBox.createLocalObject (CLSID_VirtualBox);
6071 if (FAILED(rc))
6072 {
6073 RTPrintf ("[!] Failed to create the VirtualBox object!\n");
6074 PRINT_RC_MESSAGE (rc);
6075
6076 com::ErrorInfo info;
6077 if (!info.isFullAvailable() && !info.isBasicAvailable())
6078 RTPrintf ("[!] Most likely, the VirtualBox COM server is not running "
6079 "or failed to start.\n");
6080 else
6081 PRINT_ERROR_INFO (info);
6082 break;
6083 }
6084
6085 CHECK_RC_BREAK (session.createInprocObject (CLSID_Session));
6086
6087 /* create the event queue
6088 * (here it is necessary only to process remaining XPCOM/IPC events
6089 * after the session is closed) */
6090
6091#ifdef USE_XPCOM_QUEUE
6092 NS_GetMainEventQ(getter_AddRefs(g_pEventQ));
6093#endif
6094
6095 if (!checkForAutoConvertedSettings (virtualBox, session, fConvertSettings))
6096 break;
6097
6098 /*
6099 * All registered command handlers
6100 */
6101 struct
6102 {
6103 const char *command;
6104 PFNHANDLER handler;
6105 } commandHandlers[] =
6106 {
6107 { "internalcommands", handleInternalCommands },
6108 { "list", handleList },
6109 { "showvminfo", handleShowVMInfo },
6110 { "registervm", handleRegisterVM },
6111 { "unregistervm", handleUnregisterVM },
6112 { "createhd", handleCreateHardDisk },
6113 { "createvdi", handleCreateHardDisk }, /* backward compatiblity */
6114 { "modifyhd", handleModifyHardDisk },
6115 { "modifyvdi", handleModifyHardDisk }, /* backward compatiblity */
6116 { "addiscsidisk", handleAddiSCSIDisk },
6117 { "createvm", handleCreateVM },
6118 { "modifyvm", handleModifyVM },
6119 { "clonehd", handleCloneHardDisk },
6120 { "clonevdi", handleCloneHardDisk }, /* backward compatiblity */
6121 { "startvm", handleStartVM },
6122 { "controlvm", handleControlVM },
6123 { "discardstate", handleDiscardState },
6124 { "adoptstate", handleAdoptdState },
6125 { "snapshot", handleSnapshot },
6126 { "openmedium", handleOpenMedium },
6127 { "registerimage", handleOpenMedium }, /* backward compatiblity */
6128 { "closemedium", handleCloseMedium },
6129 { "unregisterimage", handleCloseMedium }, /* backward compatiblity */
6130 { "showhdinfo", handleShowHardDiskInfo },
6131 { "showvdiinfo", handleShowHardDiskInfo }, /* backward compatiblity */
6132#ifdef RT_OS_WINDOWS
6133 { "createhostif", handleCreateHostIF },
6134 { "removehostif", handleRemoveHostIF },
6135#endif
6136 { "getextradata", handleGetExtraData },
6137 { "setextradata", handleSetExtraData },
6138 { "setproperty", handleSetProperty },
6139 { "usbfilter", handleUSBFilter },
6140 { "sharedfolder", handleSharedFolder },
6141 { "vmstatistics", handleVMStatistics },
6142#ifdef VBOX_WITH_GUEST_PROPS
6143 { "guestproperty", handleGuestProperty },
6144#endif /* VBOX_WITH_GUEST_PROPS defined */
6145 { "metrics", handleMetrics },
6146 { NULL, NULL }
6147 };
6148
6149 int commandIndex;
6150 for (commandIndex = 0; commandHandlers[commandIndex].command != NULL; commandIndex++)
6151 {
6152 if (strcmp(commandHandlers[commandIndex].command, argv[iCmd]) == 0)
6153 {
6154 rc = commandHandlers[commandIndex].handler(argc - iCmdArg, &argv[iCmdArg], virtualBox, session);
6155 break;
6156 }
6157 }
6158 if (!commandHandlers[commandIndex].command)
6159 {
6160 rc = errorSyntax(USAGE_ALL, "Invalid command '%s'", Utf8Str(argv[iCmd]).raw());
6161 }
6162
6163 /* Although all handlers should always close the session if they open it,
6164 * we do it here just in case if some of the handlers contains a bug --
6165 * leaving the direct session not closed will turn the machine state to
6166 * Aborted which may have unwanted side effects like killing the saved
6167 * state file (if the machine was in the Saved state before). */
6168 session->Close();
6169
6170#ifdef USE_XPCOM_QUEUE
6171 g_pEventQ->ProcessPendingEvents();
6172#endif
6173
6174 // end "all-stuff" scope
6175 ////////////////////////////////////////////////////////////////////////////
6176 }
6177 while (0);
6178
6179 com::Shutdown();
6180#endif /* !VBOX_ONLY_DOCS */
6181
6182 /*
6183 * Free converted argument vector
6184 */
6185 for (int i = iCmdArg; i < argc; i++)
6186 RTStrFree(argv[i]);
6187
6188 return rc != 0;
6189}
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