/* $Id: VBoxManageHelp.cpp 61673 2016-06-13 11:50:22Z vboxsync $ */ /** @file * VBoxManage - help and other message output. */ /* * Copyright (C) 2006-2016 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include #include #include #include #include #include #include "VBoxManage.h" /********************************************************************************************************************************* * Defined Constants And Macros * *********************************************************************************************************************************/ /** If the usage is the given number of length long or longer, the error is * repeated so the user can actually see it. */ #define ERROR_REPEAT_AFTER_USAGE_LENGTH 16 /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ #ifndef VBOX_ONLY_DOCS enum HELP_CMD_VBOXMANAGE g_enmCurCommand = HELP_CMD_VBOXMANAGE_INVALID; /** The scope maskt for the current subcommand. */ uint64_t g_fCurSubcommandScope = REFENTRYSTR_SCOPE_GLOBAL; /** String of spaces that can be used for indentation. */ static const char g_szSpaces[] = " "; /** * Sets the current command. * * This affects future calls to error and help functions. * * @param enmCommand The command. */ void setCurrentCommand(enum HELP_CMD_VBOXMANAGE enmCommand) { Assert(g_enmCurCommand == HELP_CMD_VBOXMANAGE_INVALID); g_enmCurCommand = enmCommand; g_fCurSubcommandScope = REFENTRYSTR_SCOPE_GLOBAL; } /** * Sets the current subcommand. * * This affects future calls to error and help functions. * * @param fSubcommandScope The subcommand scope. */ void setCurrentSubcommand(uint64_t fSubcommandScope) { g_fCurSubcommandScope = fSubcommandScope; } /** * Retruns the width for the given handle. * * @returns Screen width. * @param pStrm The stream, g_pStdErr or g_pStdOut. */ static uint32_t getScreenWidth(PRTSTREAM pStrm) { static uint32_t s_acch[2] = { 0, 0}; uint32_t iWhich = pStrm == g_pStdErr ? 1 : 0; uint32_t cch = s_acch[iWhich]; if (cch) return cch; cch = 80; /** @todo screen width IPRT API. */ s_acch[iWhich] = cch; return cch; } /** * Prints a string table string (paragraph), performing non-breaking-space * replacement and wrapping. * * @returns Number of lines written. * @param pStrm The output stream. * @param psz The string table string to print. * @param cchMaxWidth The maximum output width. * @param fFlags String flags that may affect formatting. */ static uint32_t printString(PRTSTREAM pStrm, const char *psz, uint32_t cchMaxWidth, uint64_t fFlags) { uint32_t cLinesWritten; size_t cch = strlen(psz); const char *pszNbsp = strchr(psz, REFENTRY_NBSP); /* * No-wrap case is simpler, so handle that separately. */ if (cch <= cchMaxWidth) { if (!pszNbsp) RTStrmWrite(pStrm, psz, cch); else { do { RTStrmWrite(pStrm, psz, pszNbsp - psz); RTStrmPutCh(pStrm, ' '); psz = pszNbsp + 1; pszNbsp = strchr(psz, REFENTRY_NBSP); } while (pszNbsp); RTStrmWrite(pStrm, psz, strlen(psz)); } RTStrmPutCh(pStrm, '\n'); cLinesWritten = 1; } /* * We need to wrap stuff, too bad. */ else { /* Figure the paragraph indent level first. */ const char * const pszIndent = psz; uint32_t cchIndent = 0; while (*psz == ' ') cchIndent++, psz++; Assert(cchIndent + 4 + 1 <= RT_ELEMENTS(g_szSpaces)); if (cchIndent + 8 >= cchMaxWidth) cchMaxWidth += cchIndent + 8; /* Work our way thru the string, line by line. */ uint32_t cchHangingIndent = 0; cLinesWritten = 0; do { RTStrmWrite(pStrm, g_szSpaces, cchIndent + cchHangingIndent); size_t offLine = cchIndent + cchHangingIndent; bool fPendingSpace = false; do { const char *pszSpace = strchr(psz, ' '); size_t cchWord = pszSpace ? pszSpace - psz : strlen(psz); if ( offLine + cchWord + fPendingSpace > cchMaxWidth && offLine != cchIndent) break; pszNbsp = (const char *)memchr(psz, REFENTRY_NBSP, cchWord); while (pszNbsp) { size_t cchSubWord = pszNbsp - psz; if (fPendingSpace) RTStrmPutCh(pStrm, ' '); RTStrmWrite(pStrm, psz, cchSubWord); offLine += cchSubWord + fPendingSpace; psz += cchSubWord + 1; cchWord -= cchSubWord + 1; pszNbsp = (const char *)memchr(psz, REFENTRY_NBSP, cchWord); fPendingSpace = true; } if (fPendingSpace) RTStrmPutCh(pStrm, ' '); RTStrmWrite(pStrm, psz, cchWord); offLine += cchWord + fPendingSpace; psz = pszSpace ? pszSpace + 1 : strchr(psz, '\0'); fPendingSpace = true; } while (offLine < cchMaxWidth && *psz != '\0'); RTStrmPutCh(pStrm, '\n'); cLinesWritten++; /* Set up hanging indent if relevant. */ if (fFlags & REFENTRYSTR_FLAGS_SYNOPSIS) cchHangingIndent = 4; } while (*psz != '\0'); } return cLinesWritten; } /** * Checks if the given string is empty (only spaces). * @returns true if empty, false if not. * @param psz The string to examine. */ DECLINLINE(bool) isEmptyString(const char *psz) { char ch; while ((ch = *psz) == ' ') psz++; return ch == '\0'; } /** * Prints a string table. * * @returns Current number of pending blank lines. * @param pStrm The output stream. * @param pStrTab The string table. * @param fScope The selection scope. * @param cPendingBlankLines Pending blank lines from previous string table. * @param pcLinesWritten Pointer to variable that should be incremented * by the number of lines written. Optional. */ static uint32_t printStringTable(PRTSTREAM pStrm, PCREFENTRYSTRTAB pStrTab, uint64_t fScope, uint32_t cPendingBlankLines, uint32_t *pcLinesWritten = NULL) { uint32_t cLinesWritten = 0; uint32_t cchWidth = getScreenWidth(pStrm); uint64_t fPrevScope = fScope; for (uint32_t i = 0; i < pStrTab->cStrings; i++) { uint64_t fCurScope = pStrTab->paStrings[i].fScope; if ((fCurScope & REFENTRYSTR_SCOPE_MASK) == REFENTRYSTR_SCOPE_SAME) { fCurScope &= ~REFENTRYSTR_SCOPE_MASK; fCurScope |= (fPrevScope & REFENTRYSTR_SCOPE_MASK); } if (fCurScope & REFENTRYSTR_SCOPE_MASK & fScope) { const char *psz = pStrTab->paStrings[i].psz; if (psz && !isEmptyString(psz)) { while (cPendingBlankLines > 0) { cPendingBlankLines--; RTStrmPutCh(pStrm, '\n'); cLinesWritten++; } cLinesWritten += printString(pStrm, psz, cchWidth, fCurScope & REFENTRYSTR_FLAGS_MASK); } else cPendingBlankLines++; } fPrevScope = fCurScope; } if (pcLinesWritten) *pcLinesWritten += cLinesWritten; return cPendingBlankLines; } /** * Prints brief help for a command or subcommand. * * @returns Number of lines written. * @param enmCommand The command. * @param fSubcommandScope The subcommand scope, REFENTRYSTR_SCOPE_GLOBAL * for all. * @param pStrm The output stream. */ static uint32_t printBriefCommandOrSubcommandHelp(enum HELP_CMD_VBOXMANAGE enmCommand, uint64_t fSubcommandScope, PRTSTREAM pStrm) { uint32_t cLinesWritten = 0; uint32_t cPendingBlankLines = 0; uint32_t cFound = 0; for (uint32_t i = 0; i < g_cHelpEntries; i++) { PCREFENTRY pHelp = g_apHelpEntries[i]; if (pHelp->idInternal == (int64_t)enmCommand) { cFound++; if (cFound == 1) { if (fSubcommandScope == REFENTRYSTR_SCOPE_GLOBAL) RTStrmPrintf(pStrm, "Usage - %c%s:\n", RT_C_TO_UPPER(pHelp->pszBrief[0]), pHelp->pszBrief + 1); else RTStrmPrintf(pStrm, "Usage:\n"); } cPendingBlankLines = printStringTable(pStrm, &pHelp->Synopsis, fSubcommandScope, cPendingBlankLines, &cLinesWritten); if (!cPendingBlankLines) cPendingBlankLines = 1; } } Assert(cFound > 0); return cLinesWritten; } /** * Prints the brief usage information for the current (sub)command. * * @param pStrm The output stream. */ void printUsage(PRTSTREAM pStrm) { printBriefCommandOrSubcommandHelp(g_enmCurCommand, g_fCurSubcommandScope, pStrm); } /** * Prints full help for a command or subcommand. * * @param enmCommand The command. * @param fSubcommandScope The subcommand scope, REFENTRYSTR_SCOPE_GLOBAL * for all. * @param pStrm The output stream. */ static void printFullCommandOrSubcommandHelp(enum HELP_CMD_VBOXMANAGE enmCommand, uint64_t fSubcommandScope, PRTSTREAM pStrm) { uint32_t cPendingBlankLines = 0; uint32_t cFound = 0; for (uint32_t i = 0; i < g_cHelpEntries; i++) { PCREFENTRY pHelp = g_apHelpEntries[i]; if ( pHelp->idInternal == (int64_t)enmCommand || enmCommand == HELP_CMD_VBOXMANAGE_INVALID) { cFound++; cPendingBlankLines = printStringTable(pStrm, &pHelp->Help, fSubcommandScope, cPendingBlankLines); if (cPendingBlankLines < 2) cPendingBlankLines = 2; } } Assert(cFound > 0); } /** * Prints the full help for the current (sub)command. * * @param pStrm The output stream. */ void printHelp(PRTSTREAM pStrm) { printFullCommandOrSubcommandHelp(g_enmCurCommand, g_fCurSubcommandScope, pStrm); } /** * Display no subcommand error message and current command usage. * * @returns RTEXITCODE_SYNTAX. */ RTEXITCODE errorNoSubcommand(void) { Assert(g_enmCurCommand != HELP_CMD_VBOXMANAGE_INVALID); Assert(g_fCurSubcommandScope == REFENTRYSTR_SCOPE_GLOBAL); return errorSyntax("No subcommand specified"); } /** * Display unknown subcommand error message and current command usage. * * May show full command help instead if the subcommand is a common help option. * * @returns RTEXITCODE_SYNTAX, or RTEXITCODE_SUCCESS if common help option. * @param pszSubcommand The name of the alleged subcommand. */ RTEXITCODE errorUnknownSubcommand(const char *pszSubcommand) { Assert(g_enmCurCommand != HELP_CMD_VBOXMANAGE_INVALID); Assert(g_fCurSubcommandScope == REFENTRYSTR_SCOPE_GLOBAL); /* check if help was requested. */ if ( strcmp(pszSubcommand, "--help") == 0 || strcmp(pszSubcommand, "-h") == 0 || strcmp(pszSubcommand, "-?") == 0) { printFullCommandOrSubcommandHelp(g_enmCurCommand, g_fCurSubcommandScope, g_pStdOut); return RTEXITCODE_SUCCESS; } return errorSyntax("Unknown subcommand: %s", pszSubcommand); } /** * Display too many parameters error message and current command usage. * * May show full command help instead if the subcommand is a common help option. * * @returns RTEXITCODE_SYNTAX, or RTEXITCODE_SUCCESS if common help option. * @param papszArgs The first unwanted parameter. Terminated by * NULL entry. */ RTEXITCODE errorTooManyParameters(char **papszArgs) { Assert(g_enmCurCommand != HELP_CMD_VBOXMANAGE_INVALID); Assert(g_fCurSubcommandScope != REFENTRYSTR_SCOPE_GLOBAL); /* check if help was requested. */ if (papszArgs) { for (uint32_t i = 0; papszArgs[i]; i++) if ( strcmp(papszArgs[i], "--help") == 0 || strcmp(papszArgs[i], "-h") == 0 || strcmp(papszArgs[i], "-?") == 0) { printFullCommandOrSubcommandHelp(g_enmCurCommand, g_fCurSubcommandScope, g_pStdOut); return RTEXITCODE_SUCCESS; } else if (!strcmp(papszArgs[i], "--")) break; } return errorSyntax("Too many parameters"); } /** * Display current (sub)command usage and the custom error message. * * @returns RTEXITCODE_SYNTAX. * @param pszFormat Custom error message format string. * @param ... Format arguments. */ RTEXITCODE errorSyntax(const char *pszFormat, ...) { Assert(g_enmCurCommand != HELP_CMD_VBOXMANAGE_INVALID); showLogo(g_pStdErr); va_list va; va_start(va, pszFormat); RTMsgErrorV(pszFormat, va); va_end(va); RTStrmPutCh(g_pStdErr, '\n'); if ( printBriefCommandOrSubcommandHelp(g_enmCurCommand, g_fCurSubcommandScope, g_pStdErr) >= ERROR_REPEAT_AFTER_USAGE_LENGTH) { /* Usage was very long, repeat the error message. */ RTStrmPutCh(g_pStdErr, '\n'); va_start(va, pszFormat); RTMsgErrorV(pszFormat, va); va_end(va); } return RTEXITCODE_SYNTAX; } /** * Worker for errorGetOpt. * * @param rcGetOpt The RTGetOpt return value. * @param pValueUnion The value union returned by RTGetOpt. */ static void errorGetOptWorker(int rcGetOpt, union RTGETOPTUNION const *pValueUnion) { if (rcGetOpt == VINF_GETOPT_NOT_OPTION) RTMsgError("Invalid parameter '%s'", pValueUnion->psz); else if (rcGetOpt > 0) { if (RT_C_IS_PRINT(rcGetOpt)) RTMsgError("Invalid option -%c", rcGetOpt); else RTMsgError("Invalid option case %i", rcGetOpt); } else if (rcGetOpt == VERR_GETOPT_UNKNOWN_OPTION) RTMsgError("Unknown option: %s", pValueUnion->psz); else if (rcGetOpt == VERR_GETOPT_INVALID_ARGUMENT_FORMAT) RTMsgError("Invalid argument format: %s", pValueUnion->psz); else if (pValueUnion->pDef) RTMsgError("%s: %Rrs", pValueUnion->pDef->pszLong, rcGetOpt); else RTMsgError("%Rrs", rcGetOpt); } /** * Handled an RTGetOpt error or common option. * * This implements the 'V' and 'h' cases. It reports appropriate syntax errors * for other @a rcGetOpt values. * * @retval RTEXITCODE_SUCCESS if help or version request. * @retval RTEXITCODE_SYNTAX if not help or version request. * @param rcGetOpt The RTGetOpt return value. * @param pValueUnion The value union returned by RTGetOpt. */ RTEXITCODE errorGetOpt(int rcGetOpt, union RTGETOPTUNION const *pValueUnion) { Assert(g_enmCurCommand != HELP_CMD_VBOXMANAGE_INVALID); /* * Check if it is an unhandled standard option. */ if (rcGetOpt == 'V') { RTPrintf("%sr%d\n", VBOX_VERSION_STRING, RTBldCfgRevision()); return RTEXITCODE_SUCCESS; } if (rcGetOpt == 'h') { printFullCommandOrSubcommandHelp(g_enmCurCommand, g_fCurSubcommandScope, g_pStdOut); return RTEXITCODE_SUCCESS; } /* * We failed. */ showLogo(g_pStdErr); errorGetOptWorker(rcGetOpt, pValueUnion); if ( printBriefCommandOrSubcommandHelp(g_enmCurCommand, g_fCurSubcommandScope, g_pStdErr) >= ERROR_REPEAT_AFTER_USAGE_LENGTH) { /* Usage was very long, repeat the error message. */ RTStrmPutCh(g_pStdErr, '\n'); errorGetOptWorker(rcGetOpt, pValueUnion); } return RTEXITCODE_SYNTAX; } #endif /* !VBOX_ONLY_DOCS */ void showLogo(PRTSTREAM pStrm) { static bool s_fShown; /* show only once */ if (!s_fShown) { RTStrmPrintf(pStrm, VBOX_PRODUCT " Command Line Management Interface Version " VBOX_VERSION_STRING "\n" "(C) 2005-" VBOX_C_YEAR " " VBOX_VENDOR "\n" "All rights reserved.\n" "\n"); s_fShown = true; } } void printUsage(USAGECATEGORY fCategory, uint32_t fSubCategory, PRTSTREAM pStrm) { bool fDumpOpts = false; #ifdef RT_OS_LINUX bool fLinux = true; #else bool fLinux = false; #endif #ifdef RT_OS_WINDOWS bool fWin = true; #else bool fWin = false; #endif #ifdef RT_OS_SOLARIS bool fSolaris = true; #else bool fSolaris = false; #endif #ifdef RT_OS_FREEBSD bool fFreeBSD = true; #else bool fFreeBSD = false; #endif #ifdef RT_OS_DARWIN bool fDarwin = true; #else bool fDarwin = false; #endif #ifdef VBOX_WITH_VBOXSDL bool fVBoxSDL = true; #else bool fVBoxSDL = false; #endif if (fCategory == USAGE_DUMPOPTS) { fDumpOpts = true; fLinux = true; fWin = true; fSolaris = true; fFreeBSD = true; fDarwin = true; fVBoxSDL = true; fCategory = USAGE_ALL; } RTStrmPrintf(pStrm, "Usage:\n" "\n"); if (fCategory == USAGE_ALL) RTStrmPrintf(pStrm, " VBoxManage [] \n" " \n \n" "General Options:\n \n" " [-v|--version] print version number and exit\n" " [-q|--nologo] suppress the logo\n" " [--settingspw ] provide the settings password\n" " [--settingspwfile ] provide a file containing the settings password\n" " \n \n" "Commands:\n \n"); const char *pcszSep1 = " "; const char *pcszSep2 = " "; if (fCategory != USAGE_ALL) { pcszSep1 = "VBoxManage"; pcszSep2 = ""; } #define SEP pcszSep1, pcszSep2 if (fCategory & USAGE_LIST) RTStrmPrintf(pStrm, "%s list [--long|-l]%s vms|runningvms|ostypes|hostdvds|hostfloppies|\n" #if defined(VBOX_WITH_NETFLT) " intnets|bridgedifs|hostonlyifs|natnets|dhcpservers|\n" #else " intnets|bridgedifs|natnets|dhcpservers|hostinfo|\n" #endif " hostinfo|hostcpuids|hddbackends|hdds|dvds|floppies|\n" " usbhost|usbfilters|systemproperties|extpacks|\n" " groups|webcams|screenshotformats\n" "\n", SEP); if (fCategory & USAGE_SHOWVMINFO) RTStrmPrintf(pStrm, "%s showvminfo %s [--details]\n" " [--machinereadable]\n" "%s showvminfo %s --log \n" "\n", SEP, SEP); if (fCategory & USAGE_REGISTERVM) RTStrmPrintf(pStrm, "%s registervm %s \n" "\n", SEP); if (fCategory & USAGE_UNREGISTERVM) RTStrmPrintf(pStrm, "%s unregistervm %s [--delete]\n" "\n", SEP); if (fCategory & USAGE_CREATEVM) RTStrmPrintf(pStrm, "%s createvm %s --name \n" " [--groups , ...]\n" " [--ostype ]\n" " [--register]\n" " [--basefolder ]\n" " [--uuid ]\n" "\n", SEP); if (fCategory & USAGE_MODIFYVM) { RTStrmPrintf(pStrm, "%s modifyvm %s \n" " [--name ]\n" " [--groups , ...]\n" " [--description ]\n" " [--ostype ]\n" " [--iconfile ]\n" " [--memory ]\n" " [--pagefusion on|off]\n" " [--vram ]\n" " [--acpi on|off]\n" #ifdef VBOX_WITH_PCI_PASSTHROUGH " [--pciattach 03:04.0]\n" " [--pciattach 03:04.0@02:01.0]\n" " [--pcidetach 03:04.0]\n" #endif " [--ioapic on|off]\n" " [--hpet on|off]\n" " [--triplefaultreset on|off]\n" " [--apic on|off]\n" " [--x2apic on|off]\n" " [--paravirtprovider none|default|legacy|minimal|\n" " hyperv|kvm]\n" " [--paravirtdebug [, ...]]\n" " [--hwvirtex on|off]\n" " [--nestedpaging on|off]\n" " [--largepages on|off]\n" " [--vtxvpid on|off]\n" " [--vtxux on|off]\n" " [--pae on|off]\n" " [--longmode on|off]\n" " [--cpu-profile \"host|Intel 80[86|286|386]\"]\n" " [--cpuid-portability-level <0..3>\n" " [--cpuidset ]\n" " [--cpuidremove ]\n" " [--cpuidremoveall]\n" " [--hardwareuuid ]\n" " [--cpus ]\n" " [--cpuhotplug on|off]\n" " [--plugcpu ]\n" " [--unplugcpu ]\n" " [--cpuexecutioncap <1-100>]\n" " [--rtcuseutc on|off]\n" #ifdef VBOX_WITH_VMSVGA " [--graphicscontroller none|vboxvga|vmsvga]\n" #else " [--graphicscontroller none|vboxvga]\n" #endif " [--monitorcount ]\n" " [--accelerate3d on|off]\n" #ifdef VBOX_WITH_VIDEOHWACCEL " [--accelerate2dvideo on|off]\n" #endif " [--firmware bios|efi|efi32|efi64]\n" " [--chipset ich9|piix3]\n" " [--bioslogofadein on|off]\n" " [--bioslogofadeout on|off]\n" " [--bioslogodisplaytime ]\n" " [--bioslogoimagepath ]\n" " [--biosbootmenu disabled|menuonly|messageandmenu]\n" " [--biosapic disabled|apic|x2apic]\n" " [--biossystemtimeoffset ]\n" " [--biospxedebug on|off]\n" " [--boot<1-4> none|floppy|dvd|disk|net>]\n" " [--nic<1-N> none|null|nat|bridged|intnet" #if defined(VBOX_WITH_NETFLT) "|hostonly" #endif "|\n" " generic|natnetwork" "]\n" " [--nictype<1-N> Am79C970A|Am79C973" #ifdef VBOX_WITH_E1000 "|\n 82540EM|82543GC|82545EM" #endif #ifdef VBOX_WITH_VIRTIO "|\n virtio" #endif /* VBOX_WITH_VIRTIO */ "]\n" " [--cableconnected<1-N> on|off]\n" " [--nictrace<1-N> on|off]\n" " [--nictracefile<1-N> ]\n" " [--nicproperty<1-N> name=[value]]\n" " [--nicspeed<1-N> ]\n" " [--nicbootprio<1-N> ]\n" " [--nicpromisc<1-N> deny|allow-vms|allow-all]\n" " [--nicbandwidthgroup<1-N> none|]\n" " [--bridgeadapter<1-N> none|]\n" #if defined(VBOX_WITH_NETFLT) " [--hostonlyadapter<1-N> none|]\n" #endif " [--intnet<1-N> ]\n" " [--nat-network<1-N> ]\n" " [--nicgenericdrv<1-N> \n" " [--natnet<1-N> |default]\n" " [--natsettings<1-N> [],[],\n" " [],[],\n" " []]\n" " [--natpf<1-N> [],tcp|udp,[],\n" " ,[],]\n" " [--natpf<1-N> delete ]\n" " [--nattftpprefix<1-N> ]\n" " [--nattftpfile<1-N> ]\n" " [--nattftpserver<1-N> ]\n" " [--natbindip<1-N> \n" " [--natdnspassdomain<1-N> on|off]\n" " [--natdnsproxy<1-N> on|off]\n" " [--natdnshostresolver<1-N> on|off]\n" " [--nataliasmode<1-N> default|[log],[proxyonly],\n" " [sameports]]\n" " [--macaddress<1-N> auto|]\n" " [--mouse ps2|usb|usbtablet|usbmultitouch]\n" " [--keyboard ps2|usb\n" " [--uart<1-N> off| ]\n" " [--uartmode<1-N> disconnected|\n" " server |\n" " client |\n" " tcpserver |\n" " tcpclient |\n" " file |\n" " ]\n" #if defined(RT_OS_LINUX) || defined(RT_OS_WINDOWS) " [--lpt<1-N> off| ]\n" " [--lptmode<1-N> ]\n" #endif " [--guestmemoryballoon ]\n" " [--audio none|null", SEP); if (fWin) { #ifdef VBOX_WITH_WINMM RTStrmPrintf(pStrm, "|winmm|dsound"); #else RTStrmPrintf(pStrm, "|dsound"); #endif } if (fSolaris) { RTStrmPrintf(pStrm, "|solaudio" #ifdef VBOX_WITH_SOLARIS_OSS "|oss" #endif ); } if (fLinux) { RTStrmPrintf(pStrm, "|oss" #ifdef VBOX_WITH_ALSA "|alsa" #endif #ifdef VBOX_WITH_PULSE "|pulse" #endif ); } if (fFreeBSD) { /* Get the line break sorted when dumping all option variants. */ if (fDumpOpts) { RTStrmPrintf(pStrm, "|\n" " oss"); } else RTStrmPrintf(pStrm, "|oss"); #ifdef VBOX_WITH_PULSE RTStrmPrintf(pStrm, "|pulse"); #endif } if (fDarwin) { RTStrmPrintf(pStrm, "|coreaudio"); } RTStrmPrintf(pStrm, "]\n"); RTStrmPrintf(pStrm, " [--audiocontroller ac97|hda|sb16]\n" " [--audiocodec stac9700|ad1980|stac9221|sb16]\n" " [--clipboard disabled|hosttoguest|guesttohost|\n" " bidirectional]\n" " [--draganddrop disabled|hosttoguest]\n"); RTStrmPrintf(pStrm, " [--vrde on|off]\n" " [--vrdeextpack default|\n" " [--vrdeproperty ]\n" " [--vrdeport ]\n" " [--vrdeaddress ]\n" " [--vrdeauthtype null|external|guest]\n" " [--vrdeauthlibrary default|\n" " [--vrdemulticon on|off]\n" " [--vrdereusecon on|off]\n" " [--vrdevideochannel on|off]\n" " [--vrdevideochannelquality ]\n"); RTStrmPrintf(pStrm, " [--usb on|off]\n" " [--usbehci on|off]\n" " [--usbxhci on|off]\n" " [--usbrename ]\n" " [--snapshotfolder default|]\n" " [--teleporter on|off]\n" " [--teleporterport ]\n" " [--teleporteraddress \n" " [--teleporterpassword ]\n" " [--teleporterpasswordfile |stdin]\n" " [--tracing-enabled on|off]\n" " [--tracing-config ]\n" " [--tracing-allow-vm-access on|off]\n" #if 0 " [--iocache on|off]\n" " [--iocachesize ]\n" #endif #if 0 " [--faulttolerance master|standby]\n" " [--faulttoleranceaddress ]\n" " [--faulttoleranceport ]\n" " [--faulttolerancesyncinterval ]\n" " [--faulttolerancepassword ]\n" #endif #ifdef VBOX_WITH_USB_CARDREADER " [--usbcardreader on|off]\n" #endif " [--autostart-enabled on|off]\n" " [--autostart-delay ]\n" #if 0 " [--autostop-type disabled|savestate|poweroff|\n" " acpishutdown]\n" #endif #ifdef VBOX_WITH_VPX " [--videocap on|off]\n" " [--videocapscreens all| [ ...]]\n" " [--videocapfile ]\n" " [--videocapres ]\n" " [--videocaprate ]\n" " [--videocapfps ]\n" " [--videocapmaxtime ]\n" " [--videocapmaxsize ]\n" " [--videocapopts [, ...]]\n" #endif " [--defaultfrontend default|]\n" "\n"); } if (fCategory & USAGE_CLONEVM) RTStrmPrintf(pStrm, "%s clonevm %s \n" " [--snapshot |]\n" " [--mode machine|machineandchildren|all]\n" " [--options link|keepallmacs|keepnatmacs|\n" " keepdisknames]\n" " [--name ]\n" " [--groups , ...]\n" " [--basefolder ]\n" " [--uuid ]\n" " [--register]\n" "\n", SEP); if (fCategory & USAGE_IMPORTAPPLIANCE) RTStrmPrintf(pStrm, "%s import %s \n" " [--dry-run|-n]\n" " [--options keepallmacs|keepnatmacs|importtovdi]\n" " [more options]\n" " (run with -n to have options displayed\n" " for a particular OVF)\n\n", SEP); if (fCategory & USAGE_EXPORTAPPLIANCE) RTStrmPrintf(pStrm, "%s export %s --output|-o .\n" " [--legacy09|--ovf09|--ovf10|--ovf20]\n" " [--manifest]\n" " [--iso]\n" " [--options manifest|iso|nomacs|nomacsbutnat]\n" " [--vsys ]\n" " [--product ]\n" " [--producturl ]\n" " [--vendor ]\n" " [--vendorurl ]\n" " [--version ]\n" " [--description ]\n" " [--eula ]\n" " [--eulafile ]\n" "\n", SEP); if (fCategory & USAGE_STARTVM) { RTStrmPrintf(pStrm, "%s startvm %s ...\n" " [--type gui", SEP); if (fVBoxSDL) RTStrmPrintf(pStrm, "|sdl"); RTStrmPrintf(pStrm, "|headless|separate]\n"); RTStrmPrintf(pStrm, "\n"); } if (fCategory & USAGE_CONTROLVM) { RTStrmPrintf(pStrm, "%s controlvm %s \n" " pause|resume|reset|poweroff|savestate|\n" " acpipowerbutton|acpisleepbutton|\n" " keyboardputscancode [ ...]|\n" " setlinkstate<1-N> on|off |\n" #if defined(VBOX_WITH_NETFLT) " nic<1-N> null|nat|bridged|intnet|hostonly|generic|\n" " natnetwork [] |\n" #else /* !VBOX_WITH_NETFLT */ " nic<1-N> null|nat|bridged|intnet|generic|natnetwork\n" " [] |\n" #endif /* !VBOX_WITH_NETFLT */ " nictrace<1-N> on|off |\n" " nictracefile<1-N> |\n" " nicproperty<1-N> name=[value] |\n" " nicpromisc<1-N> deny|allow-vms|allow-all |\n" " natpf<1-N> [],tcp|udp,[],\n" " ,[], |\n" " natpf<1-N> delete |\n" " guestmemoryballoon |\n" " usbattach |
\n" " [--capturefile ] |\n" " usbdetach |
|\n" " clipboard disabled|hosttoguest|guesttohost|\n" " bidirectional |\n" " draganddrop disabled|hosttoguest |\n" " vrde on|off |\n" " vrdeport |\n" " vrdeproperty |\n" " vrdevideochannelquality |\n" " setvideomodehint \n" " [[] [ |\n" " [ ]]] |\n" " screenshotpng [display] |\n" " videocap on|off |\n" " videocapscreens all|none|,[...] |\n" " videocapfile \n" " videocapres x\n" " videocaprate \n" " videocapfps \n" " videocapmaxtime \n" " videocapmaxsize \n" " setcredentials \n" " --passwordfile | \n" " \n" " [--allowlocallogon ] |\n" " teleport --host --port \n" " [--maxdowntime ]\n" " [--passwordfile |\n" " --password ] |\n" " plugcpu |\n" " unplugcpu |\n" " cpuexecutioncap <1-100>\n" " webcam | | \n" " addencpassword \n" " |-\n" " [--removeonsuspend ]\n" " removeencpassword \n" " removeallencpasswords\n" "\n", SEP); } if (fCategory & USAGE_DISCARDSTATE) RTStrmPrintf(pStrm, "%s discardstate %s \n" "\n", SEP); if (fCategory & USAGE_ADOPTSTATE) RTStrmPrintf(pStrm, "%s adoptstate %s \n" "\n", SEP); if (fCategory & USAGE_SNAPSHOT) RTStrmPrintf(pStrm, "%s snapshot %s \n" " take [--description ] [--live]\n" " [--uniquename Number,Timestamp,Space,Force] |\n" " delete |\n" " restore |\n" " restorecurrent |\n" " edit |--current\n" " [--name ]\n" " [--description ] |\n" " list [--details|--machinereadable]\n" " showvminfo \n" "\n", SEP); if (fCategory & USAGE_CLOSEMEDIUM) RTStrmPrintf(pStrm, "%s closemedium %s [disk|dvd|floppy] \n" " [--delete]\n" "\n", SEP); if (fCategory & USAGE_STORAGEATTACH) RTStrmPrintf(pStrm, "%s storageattach %s \n" " --storagectl \n" " [--port ]\n" " [--device ]\n" " [--type dvddrive|hdd|fdd]\n" " [--medium none|emptydrive|additions|\n" " |host:|iscsi]\n" " [--mtype normal|writethrough|immutable|shareable|\n" " readonly|multiattach]\n" " [--comment ]\n" " [--setuuid ]\n" " [--setparentuuid ]\n" " [--passthrough on|off]\n" " [--tempeject on|off]\n" " [--nonrotational on|off]\n" " [--discard on|off]\n" " [--hotpluggable on|off]\n" " [--bandwidthgroup ]\n" " [--forceunmount]\n" " [--server |]\n" " [--target ]\n" " [--tport ]\n" " [--lun ]\n" " [--encodedlun ]\n" " [--username ]\n" " [--password ]\n" " [--initiator ]\n" " [--intnet]\n" "\n", SEP); if (fCategory & USAGE_STORAGECONTROLLER) RTStrmPrintf(pStrm, "%s storagectl %s \n" " --name \n" " [--add ide|sata|scsi|floppy|sas|pcie]\n" " [--controller LSILogic|LSILogicSAS|BusLogic|\n" " IntelAHCI|PIIX3|PIIX4|ICH6|I82078|NVMe]\n" " [--portcount <1-n>]\n" " [--hostiocache on|off]\n" " [--bootable on|off]\n" " [--rename ]\n" " [--remove]\n" "\n", SEP); if (fCategory & USAGE_BANDWIDTHCONTROL) RTStrmPrintf(pStrm, "%s bandwidthctl %s \n" " add --type disk|network\n" " --limit [k|m|g|K|M|G] |\n" " set \n" " --limit [k|m|g|K|M|G] |\n" " remove |\n" " list [--machinereadable]\n" " (limit units: k=kilobit, m=megabit, g=gigabit,\n" " K=kilobyte, M=megabyte, G=gigabyte)\n" "\n", SEP); if (fCategory & USAGE_SHOWMEDIUMINFO) RTStrmPrintf(pStrm, "%s showmediuminfo %s [disk|dvd|floppy] \n" "\n", SEP); if (fCategory & USAGE_CREATEMEDIUM) RTStrmPrintf(pStrm, "%s createmedium %s [disk|dvd|floppy] --filename \n" " [--size |--sizebyte ]\n" " [--diffparent |\n" " [--format VDI|VMDK|VHD] (default: VDI)\n" " [--variant Standard,Fixed,Split2G,Stream,ESX]\n" "\n", SEP); if (fCategory & USAGE_MODIFYMEDIUM) RTStrmPrintf(pStrm, "%s modifymedium %s [disk|dvd|floppy] \n" " [--type normal|writethrough|immutable|shareable|\n" " readonly|multiattach]\n" " [--autoreset on|off]\n" " [--property ]\n" " [--compact]\n" " [--resize |--resizebyte ]\n" " [--move ]" "\n", SEP); if (fCategory & USAGE_CLONEMEDIUM) RTStrmPrintf(pStrm, "%s clonemedium %s [disk|dvd|floppy] \n" " [--format VDI|VMDK|VHD|RAW|]\n" " [--variant Standard,Fixed,Split2G,Stream,ESX]\n" " [--existing]\n" "\n", SEP); if (fCategory & USAGE_MEDIUMPROPERTY) RTStrmPrintf(pStrm, "%s mediumproperty %s [disk|dvd|floppy] set \n" " \n" "\n" " [disk|dvd|floppy] get \n" " \n" "\n" " [disk|dvd|floppy] delete \n" " \n" "\n", SEP); if (fCategory & USAGE_ENCRYPTMEDIUM) RTStrmPrintf(pStrm, "%s encryptmedium %s \n" " [--newpassword |-]\n" " [--oldpassword |-]\n" " [--cipher ]\n" " [--newpasswordid ]\n" "\n", SEP); if (fCategory & USAGE_MEDIUMENCCHKPWD) RTStrmPrintf(pStrm, "%s checkmediumpwd %s \n" " |-\n" "\n", SEP); if (fCategory & USAGE_CONVERTFROMRAW) RTStrmPrintf(pStrm, "%s convertfromraw %s \n" " [--format VDI|VMDK|VHD]\n" " [--variant Standard,Fixed,Split2G,Stream,ESX]\n" " [--uuid ]\n" "%s convertfromraw %s stdin \n" " [--format VDI|VMDK|VHD]\n" " [--variant Standard,Fixed,Split2G,Stream,ESX]\n" " [--uuid ]\n" "\n", SEP, SEP); if (fCategory & USAGE_GETEXTRADATA) RTStrmPrintf(pStrm, "%s getextradata %s global|\n" " |enumerate\n" "\n", SEP); if (fCategory & USAGE_SETEXTRADATA) RTStrmPrintf(pStrm, "%s setextradata %s global|\n" " \n" " [] (no value deletes key)\n" "\n", SEP); if (fCategory & USAGE_SETPROPERTY) RTStrmPrintf(pStrm, "%s setproperty %s machinefolder default| |\n" " hwvirtexclusive on|off |\n" " vrdeauthlibrary default| |\n" " websrvauthlibrary default|null| |\n" " vrdeextpack null| |\n" " autostartdbpath null| |\n" " loghistorycount \n" " defaultfrontend default|\n" " logginglevel \n" "\n", SEP); if (fCategory & USAGE_USBFILTER_ADD) RTStrmPrintf(pStrm, "%s usbfilter %s add \n" " --target |global\n" " --name \n" " --action ignore|hold (global filters only)\n" " [--active yes|no] (yes)\n" " [--vendorid ] (null)\n" " [--productid ] (null)\n" " [--revision ] (null)\n" " [--manufacturer ] (null)\n" " [--product ] (null)\n" " [--remote yes|no] (null, VM filters only)\n" " [--serialnumber ] (null)\n" " [--maskedinterfaces ]\n" "\n", SEP); if (fCategory & USAGE_USBFILTER_MODIFY) RTStrmPrintf(pStrm, "%s usbfilter %s modify \n" " --target |global\n" " [--name ]\n" " [--action ignore|hold] (global filters only)\n" " [--active yes|no]\n" " [--vendorid |\"\"]\n" " [--productid |\"\"]\n" " [--revision |\"\"]\n" " [--manufacturer |\"\"]\n" " [--product |\"\"]\n" " [--remote yes|no] (null, VM filters only)\n" " [--serialnumber |\"\"]\n" " [--maskedinterfaces ]\n" "\n", SEP); if (fCategory & USAGE_USBFILTER_REMOVE) RTStrmPrintf(pStrm, "%s usbfilter %s remove \n" " --target |global\n" "\n", SEP); if (fCategory & USAGE_SHAREDFOLDER_ADD) RTStrmPrintf(pStrm, "%s sharedfolder %s add \n" " --name --hostpath \n" " [--transient] [--readonly] [--automount]\n" "\n", SEP); if (fCategory & USAGE_SHAREDFOLDER_REMOVE) RTStrmPrintf(pStrm, "%s sharedfolder %s remove \n" " --name [--transient]\n" "\n", SEP); #ifdef VBOX_WITH_GUEST_PROPS if (fCategory & USAGE_GUESTPROPERTY) usageGuestProperty(pStrm, SEP); #endif /* VBOX_WITH_GUEST_PROPS defined */ #ifdef VBOX_WITH_GUEST_CONTROL if (fCategory & USAGE_GUESTCONTROL) usageGuestControl(pStrm, SEP, fSubCategory); #endif /* VBOX_WITH_GUEST_CONTROL defined */ if (fCategory & USAGE_DEBUGVM) { RTStrmPrintf(pStrm, "%s debugvm %s \n" " dumpvmcore --filename |\n" " dumpgueststack [--cpu ]\n" " info [args] |\n" " injectnmi |\n" " log [--release|--debug] ...|\n" " logdest [--release|--debug] ...|\n" " logflags [--release|--debug] ...|\n" " osdetect |\n" " osinfo |\n" " osdmesg [--lines|-n ] |\n" " getregisters [--cpu ] |all ... |\n" " setregisters [--cpu ] = ... |\n" " show [--human-readable|--sh-export|--sh-eval|\n" " --cmd-set] \n" " \n" " [[opt] what ...] |\n" " statistics [--reset] [--pattern ]\n" " [--descriptions]\n" "\n", SEP); } if (fCategory & USAGE_METRICS) RTStrmPrintf(pStrm, "%s metrics %s list [*|host| []]\n" " (comma-separated)\n\n" "%s metrics %s setup\n" " [--period ] (default: 1)\n" " [--samples ] (default: 1)\n" " [--list]\n" " [*|host| []]\n\n" "%s metrics %s query [*|host| []]\n\n" "%s metrics %s enable\n" " [--list]\n" " [*|host| []]\n\n" "%s metrics %s disable\n" " [--list]\n" " [*|host| []]\n\n" "%s metrics %s collect\n" " [--period ] (default: 1)\n" " [--samples ] (default: 1)\n" " [--list]\n" " [--detach]\n" " [*|host| []]\n" "\n", SEP, SEP, SEP, SEP, SEP, SEP); #if defined(VBOX_WITH_NAT_SERVICE) if (fCategory & USAGE_NATNETWORK) { RTStrmPrintf(pStrm, "%s natnetwork %s add --netname \n" " --network \n" " [--enable|--disable]\n" " [--dhcp on|off]\n" " [--port-forward-4 ]\n" " [--loopback-4 ]\n" " [--ipv6 on|off]\n" " [--port-forward-6 ]\n" " [--loopback-6 ]\n\n" "%s natnetwork %s remove --netname \n\n" "%s natnetwork %s modify --netname \n" " [--network ]\n" " [--enable|--disable]\n" " [--dhcp on|off]\n" " [--port-forward-4 ]\n" " [--loopback-4 ]\n" " [--ipv6 on|off]\n" " [--port-forward-6 ]\n" " [--loopback-6 ]\n\n" "%s natnetwork %s start --netname \n\n" "%s natnetwork %s stop --netname \n\n" "%s natnetwork %s list []\n" "\n", SEP, SEP, SEP, SEP, SEP, SEP); } #endif #if defined(VBOX_WITH_NETFLT) if (fCategory & USAGE_HOSTONLYIFS) { RTStrmPrintf(pStrm, "%s hostonlyif %s ipconfig \n" " [--dhcp |\n" " --ip [--netmask (def: 255.255.255.0)] |\n" " --ipv6 [--netmasklengthv6 (def: 64)]]\n" # if !defined(RT_OS_SOLARIS) || defined(VBOX_ONLY_DOCS) " create |\n" " remove \n" # endif "\n", SEP); } #endif if (fCategory & USAGE_DHCPSERVER) { RTStrmPrintf(pStrm, "%s dhcpserver %s add|modify --netname |\n" #if defined(VBOX_WITH_NETFLT) " --ifname \n" #endif " [--ip \n" " --netmask \n" " --lowerip \n" " --upperip ]\n" " [--enable | --disable]\n\n" "%s dhcpserver %s remove --netname |\n" #if defined(VBOX_WITH_NETFLT) " --ifname \n" #endif "\n", SEP, SEP); } if (fCategory & USAGE_USBDEVSOURCE) { RTStrmPrintf(pStrm, "%s usbdevsource %s add \n" " --backend \n" " --address
\n" "%s usbdevsource %s remove \n" "\n", SEP, SEP); } #ifndef VBOX_ONLY_DOCS /* Converted to man page, not needed. */ if (fCategory == USAGE_ALL) { uint32_t cPendingBlankLines = 0; for (uint32_t i = 0; i < g_cHelpEntries; i++) { PCREFENTRY pHelp = g_apHelpEntries[i]; RTStrmPrintf(pStrm, " %c%s:\n", RT_C_TO_UPPER(pHelp->pszBrief[0]), pHelp->pszBrief + 1); cPendingBlankLines = printStringTable(pStrm, &pHelp->Synopsis, REFENTRYSTR_SCOPE_GLOBAL, cPendingBlankLines); if (!cPendingBlankLines) cPendingBlankLines = 1; } } #endif } /** * Print a usage synopsis and the syntax error message. * @returns RTEXITCODE_SYNTAX. */ RTEXITCODE errorSyntax(USAGECATEGORY fCategory, const char *pszFormat, ...) { va_list args; showLogo(g_pStdErr); // show logo even if suppressed #ifndef VBOX_ONLY_DOCS if (g_fInternalMode) printUsageInternal(fCategory, g_pStdErr); else printUsage(fCategory, ~0U, g_pStdErr); #endif /* !VBOX_ONLY_DOCS */ va_start(args, pszFormat); RTStrmPrintf(g_pStdErr, "\nSyntax error: %N\n", pszFormat, &args); va_end(args); return RTEXITCODE_SYNTAX; } /** * Print a usage synopsis and the syntax error message. * @returns RTEXITCODE_SYNTAX. */ RTEXITCODE errorSyntaxEx(USAGECATEGORY fCategory, uint32_t fSubCategory, const char *pszFormat, ...) { va_list args; showLogo(g_pStdErr); // show logo even if suppressed #ifndef VBOX_ONLY_DOCS if (g_fInternalMode) printUsageInternal(fCategory, g_pStdErr); else printUsage(fCategory, fSubCategory, g_pStdErr); #endif /* !VBOX_ONLY_DOCS */ va_start(args, pszFormat); RTStrmPrintf(g_pStdErr, "\nSyntax error: %N\n", pszFormat, &args); va_end(args); return RTEXITCODE_SYNTAX; } /** * errorSyntax for RTGetOpt users. * * @returns RTEXITCODE_SYNTAX. * * @param fCategory The usage category of the command. * @param fSubCategory The usage sub-category of the command. * @param rc The RTGetOpt return code. * @param pValueUnion The value union. */ RTEXITCODE errorGetOptEx(USAGECATEGORY fCategory, uint32_t fSubCategory, int rc, union RTGETOPTUNION const *pValueUnion) { /* * Check if it is an unhandled standard option. */ #ifndef VBOX_ONLY_DOCS if (rc == 'V') { RTPrintf("%sr%d\n", VBOX_VERSION_STRING, RTBldCfgRevision()); return RTEXITCODE_SUCCESS; } #endif if (rc == 'h') { showLogo(g_pStdErr); #ifndef VBOX_ONLY_DOCS if (g_fInternalMode) printUsageInternal(fCategory, g_pStdOut); else printUsage(fCategory, fSubCategory, g_pStdOut); #endif return RTEXITCODE_SUCCESS; } /* * General failure. */ showLogo(g_pStdErr); // show logo even if suppressed #ifndef VBOX_ONLY_DOCS if (g_fInternalMode) printUsageInternal(fCategory, g_pStdErr); else printUsage(fCategory, fSubCategory, g_pStdErr); #endif /* !VBOX_ONLY_DOCS */ if (rc == VINF_GETOPT_NOT_OPTION) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid parameter '%s'", pValueUnion->psz); if (rc > 0) { if (RT_C_IS_PRINT(rc)) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid option -%c", rc); return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid option case %i", rc); } if (rc == VERR_GETOPT_UNKNOWN_OPTION) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option: %s", pValueUnion->psz); if (rc == VERR_GETOPT_INVALID_ARGUMENT_FORMAT) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid argument format: %s", pValueUnion->psz); if (pValueUnion->pDef) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "%s: %Rrs", pValueUnion->pDef->pszLong, rc); return RTMsgErrorExit(RTEXITCODE_SYNTAX, "%Rrs", rc); } /** * errorSyntax for RTGetOpt users. * * @returns RTEXITCODE_SYNTAX. * * @param fUsageCategory The usage category of the command. * @param rc The RTGetOpt return code. * @param pValueUnion The value union. */ RTEXITCODE errorGetOpt(USAGECATEGORY fCategory, int rc, union RTGETOPTUNION const *pValueUnion) { return errorGetOptEx(fCategory, ~0U, rc, pValueUnion); } /** * Print an error message without the syntax stuff. * * @returns RTEXITCODE_SYNTAX. */ RTEXITCODE errorArgument(const char *pszFormat, ...) { va_list args; va_start(args, pszFormat); RTMsgErrorV(pszFormat, args); va_end(args); return RTEXITCODE_SYNTAX; }