VirtualBox

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

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

VBoxManage: the other problematic function is handleModifyVM, disabled global optimizations for it. Enabled the handleShowVMInfo optimization hack for x86 too, as it suffers (even if it's significantly less).

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

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