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