VirtualBox

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

Last change on this file since 97364 was 96907, checked in by vboxsync, 21 months ago

Frontends/VBoxManage: The VBoxManage controlvm suboptions
'setlinkstateN' and 'nictraceN' are unable to parse boolean arguments
due to a mixed up argument index (regression from r149879).
ticketref:21113

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 88.8 KB
RevLine 
[12599]1/* $Id: VBoxManageControlVM.cpp 96907 2022-09-27 21:30:04Z vboxsync $ */
[1]2/** @file
[34913]3 * VBoxManage - Implementation of the controlvm command.
[1]4 */
5
6/*
[96407]7 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
[1]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[1]26 */
27
28
[57358]29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
[1]32#include <VBox/com/com.h>
33#include <VBox/com/string.h>
34#include <VBox/com/Guid.h>
[7379]35#include <VBox/com/array.h>
[1]36#include <VBox/com/ErrorInfo.h>
[20928]37#include <VBox/com/errorprint.h>
[1]38#include <VBox/com/VirtualBox.h>
39
[14619]40#include <iprt/ctype.h>
[24903]41#include <iprt/getopt.h>
[1]42#include <iprt/stream.h>
43#include <iprt/string.h>
[64907]44#include <iprt/thread.h>
[1]45#include <iprt/uuid.h>
[36720]46#include <iprt/file.h>
[14814]47#include <VBox/log.h>
[1]48
49#include "VBoxManage.h"
[88079]50#include "VBoxManageUtils.h"
[1]51
[32701]52#include <list>
[1]53
[93708]54DECLARE_TRANSLATION_CONTEXT(ControlVM);
[92372]55
[77910]56VMProcPriority_T nameToVMProcPriority(const char *pszName);
[32701]57
[18396]58/**
[3494]59 * Parses a number.
[1]60 *
[3494]61 * @returns Valid number on success.
[33540]62 * @returns 0 if invalid number. All necessary bitching has been done.
[1]63 * @param psz Pointer to the nic number.
64 */
[24903]65static unsigned parseNum(const char *psz, unsigned cMaxNum, const char *name)
[1]66{
67 uint32_t u32;
68 char *pszNext;
69 int rc = RTStrToUInt32Ex(psz, &pszNext, 10, &u32);
[13835]70 if ( RT_SUCCESS(rc)
[1]71 && *pszNext == '\0'
72 && u32 >= 1
[3494]73 && u32 <= cMaxNum)
[1]74 return (unsigned)u32;
[93708]75 errorArgument(ControlVM::tr("Invalid %s number '%s'."), name, psz);
[1]76 return 0;
77}
78
[64906]79#define KBDCHARDEF_MOD_NONE 0x00
80#define KBDCHARDEF_MOD_SHIFT 0x01
[35761]81
[64906]82typedef struct KBDCHARDEF
83{
84 uint8_t u8Scancode;
85 uint8_t u8Modifiers;
86} KBDCHARDEF;
87
88static const KBDCHARDEF g_aASCIIChars[0x80] =
89{
90 /* 0x00 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
91 /* 0x01 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
92 /* 0x02 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
93 /* 0x03 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
94 /* 0x04 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
95 /* 0x05 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
96 /* 0x06 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
97 /* 0x07 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
98 /* 0x08 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
[65399]99 /* 0x09 ' ' */ {0x0f, KBDCHARDEF_MOD_NONE},
[64906]100 /* 0x0A ' ' */ {0x1c, KBDCHARDEF_MOD_NONE},
101 /* 0x0B ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
102 /* 0x0C ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
103 /* 0x0D ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
104 /* 0x0E ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
105 /* 0x0F ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
106 /* 0x10 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
107 /* 0x11 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
108 /* 0x12 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
109 /* 0x13 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
110 /* 0x14 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
111 /* 0x15 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
112 /* 0x16 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
113 /* 0x17 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
114 /* 0x18 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
115 /* 0x19 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
116 /* 0x1A ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
117 /* 0x1B ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
118 /* 0x1C ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
119 /* 0x1D ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
120 /* 0x1E ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
121 /* 0x1F ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
122 /* 0x20 ' ' */ {0x39, KBDCHARDEF_MOD_NONE},
[65399]123 /* 0x21 '!' */ {0x02, KBDCHARDEF_MOD_SHIFT},
[64906]124 /* 0x22 '"' */ {0x28, KBDCHARDEF_MOD_SHIFT},
125 /* 0x23 '#' */ {0x04, KBDCHARDEF_MOD_SHIFT},
126 /* 0x24 '$' */ {0x05, KBDCHARDEF_MOD_SHIFT},
127 /* 0x25 '%' */ {0x06, KBDCHARDEF_MOD_SHIFT},
128 /* 0x26 '&' */ {0x08, KBDCHARDEF_MOD_SHIFT},
129 /* 0x27 ''' */ {0x28, KBDCHARDEF_MOD_NONE},
130 /* 0x28 '(' */ {0x0a, KBDCHARDEF_MOD_SHIFT},
131 /* 0x29 ')' */ {0x0b, KBDCHARDEF_MOD_SHIFT},
132 /* 0x2A '*' */ {0x09, KBDCHARDEF_MOD_SHIFT},
133 /* 0x2B '+' */ {0x0d, KBDCHARDEF_MOD_SHIFT},
134 /* 0x2C ',' */ {0x33, KBDCHARDEF_MOD_NONE},
135 /* 0x2D '-' */ {0x0c, KBDCHARDEF_MOD_NONE},
136 /* 0x2E '.' */ {0x34, KBDCHARDEF_MOD_NONE},
137 /* 0x2F '/' */ {0x35, KBDCHARDEF_MOD_NONE},
138 /* 0x30 '0' */ {0x0b, KBDCHARDEF_MOD_NONE},
139 /* 0x31 '1' */ {0x02, KBDCHARDEF_MOD_NONE},
140 /* 0x32 '2' */ {0x03, KBDCHARDEF_MOD_NONE},
141 /* 0x33 '3' */ {0x04, KBDCHARDEF_MOD_NONE},
142 /* 0x34 '4' */ {0x05, KBDCHARDEF_MOD_NONE},
143 /* 0x35 '5' */ {0x06, KBDCHARDEF_MOD_NONE},
144 /* 0x36 '6' */ {0x07, KBDCHARDEF_MOD_NONE},
145 /* 0x37 '7' */ {0x08, KBDCHARDEF_MOD_NONE},
146 /* 0x38 '8' */ {0x09, KBDCHARDEF_MOD_NONE},
147 /* 0x39 '9' */ {0x0a, KBDCHARDEF_MOD_NONE},
148 /* 0x3A ':' */ {0x27, KBDCHARDEF_MOD_SHIFT},
149 /* 0x3B ';' */ {0x27, KBDCHARDEF_MOD_NONE},
150 /* 0x3C '<' */ {0x33, KBDCHARDEF_MOD_SHIFT},
151 /* 0x3D '=' */ {0x0d, KBDCHARDEF_MOD_NONE},
152 /* 0x3E '>' */ {0x34, KBDCHARDEF_MOD_SHIFT},
153 /* 0x3F '?' */ {0x35, KBDCHARDEF_MOD_SHIFT},
154 /* 0x40 '@' */ {0x03, KBDCHARDEF_MOD_SHIFT},
155 /* 0x41 'A' */ {0x1e, KBDCHARDEF_MOD_SHIFT},
156 /* 0x42 'B' */ {0x30, KBDCHARDEF_MOD_SHIFT},
157 /* 0x43 'C' */ {0x2e, KBDCHARDEF_MOD_SHIFT},
158 /* 0x44 'D' */ {0x20, KBDCHARDEF_MOD_SHIFT},
159 /* 0x45 'E' */ {0x12, KBDCHARDEF_MOD_SHIFT},
160 /* 0x46 'F' */ {0x21, KBDCHARDEF_MOD_SHIFT},
161 /* 0x47 'G' */ {0x22, KBDCHARDEF_MOD_SHIFT},
162 /* 0x48 'H' */ {0x23, KBDCHARDEF_MOD_SHIFT},
163 /* 0x49 'I' */ {0x17, KBDCHARDEF_MOD_SHIFT},
164 /* 0x4A 'J' */ {0x24, KBDCHARDEF_MOD_SHIFT},
165 /* 0x4B 'K' */ {0x25, KBDCHARDEF_MOD_SHIFT},
166 /* 0x4C 'L' */ {0x26, KBDCHARDEF_MOD_SHIFT},
167 /* 0x4D 'M' */ {0x32, KBDCHARDEF_MOD_SHIFT},
168 /* 0x4E 'N' */ {0x31, KBDCHARDEF_MOD_SHIFT},
169 /* 0x4F 'O' */ {0x18, KBDCHARDEF_MOD_SHIFT},
170 /* 0x50 'P' */ {0x19, KBDCHARDEF_MOD_SHIFT},
171 /* 0x51 'Q' */ {0x10, KBDCHARDEF_MOD_SHIFT},
172 /* 0x52 'R' */ {0x13, KBDCHARDEF_MOD_SHIFT},
173 /* 0x53 'S' */ {0x1f, KBDCHARDEF_MOD_SHIFT},
174 /* 0x54 'T' */ {0x14, KBDCHARDEF_MOD_SHIFT},
175 /* 0x55 'U' */ {0x16, KBDCHARDEF_MOD_SHIFT},
176 /* 0x56 'V' */ {0x2f, KBDCHARDEF_MOD_SHIFT},
177 /* 0x57 'W' */ {0x11, KBDCHARDEF_MOD_SHIFT},
178 /* 0x58 'X' */ {0x2d, KBDCHARDEF_MOD_SHIFT},
179 /* 0x59 'Y' */ {0x15, KBDCHARDEF_MOD_SHIFT},
180 /* 0x5A 'Z' */ {0x2c, KBDCHARDEF_MOD_SHIFT},
181 /* 0x5B '[' */ {0x1a, KBDCHARDEF_MOD_NONE},
182 /* 0x5C '\' */ {0x2b, KBDCHARDEF_MOD_NONE},
183 /* 0x5D ']' */ {0x1b, KBDCHARDEF_MOD_NONE},
184 /* 0x5E '^' */ {0x07, KBDCHARDEF_MOD_SHIFT},
185 /* 0x5F '_' */ {0x0c, KBDCHARDEF_MOD_SHIFT},
186 /* 0x60 '`' */ {0x28, KBDCHARDEF_MOD_NONE},
187 /* 0x61 'a' */ {0x1e, KBDCHARDEF_MOD_NONE},
188 /* 0x62 'b' */ {0x30, KBDCHARDEF_MOD_NONE},
189 /* 0x63 'c' */ {0x2e, KBDCHARDEF_MOD_NONE},
190 /* 0x64 'd' */ {0x20, KBDCHARDEF_MOD_NONE},
191 /* 0x65 'e' */ {0x12, KBDCHARDEF_MOD_NONE},
192 /* 0x66 'f' */ {0x21, KBDCHARDEF_MOD_NONE},
193 /* 0x67 'g' */ {0x22, KBDCHARDEF_MOD_NONE},
194 /* 0x68 'h' */ {0x23, KBDCHARDEF_MOD_NONE},
195 /* 0x69 'i' */ {0x17, KBDCHARDEF_MOD_NONE},
196 /* 0x6A 'j' */ {0x24, KBDCHARDEF_MOD_NONE},
197 /* 0x6B 'k' */ {0x25, KBDCHARDEF_MOD_NONE},
198 /* 0x6C 'l' */ {0x26, KBDCHARDEF_MOD_NONE},
199 /* 0x6D 'm' */ {0x32, KBDCHARDEF_MOD_NONE},
200 /* 0x6E 'n' */ {0x31, KBDCHARDEF_MOD_NONE},
201 /* 0x6F 'o' */ {0x18, KBDCHARDEF_MOD_NONE},
202 /* 0x70 'p' */ {0x19, KBDCHARDEF_MOD_NONE},
203 /* 0x71 'q' */ {0x10, KBDCHARDEF_MOD_NONE},
204 /* 0x72 'r' */ {0x13, KBDCHARDEF_MOD_NONE},
205 /* 0x73 's' */ {0x1f, KBDCHARDEF_MOD_NONE},
206 /* 0x74 't' */ {0x14, KBDCHARDEF_MOD_NONE},
207 /* 0x75 'u' */ {0x16, KBDCHARDEF_MOD_NONE},
208 /* 0x76 'v' */ {0x2f, KBDCHARDEF_MOD_NONE},
209 /* 0x77 'w' */ {0x11, KBDCHARDEF_MOD_NONE},
210 /* 0x78 'x' */ {0x2d, KBDCHARDEF_MOD_NONE},
211 /* 0x79 'y' */ {0x15, KBDCHARDEF_MOD_NONE},
212 /* 0x7A 'z' */ {0x2c, KBDCHARDEF_MOD_NONE},
213 /* 0x7B '{' */ {0x1a, KBDCHARDEF_MOD_SHIFT},
214 /* 0x7C '|' */ {0x2b, KBDCHARDEF_MOD_SHIFT},
215 /* 0x7D '}' */ {0x1b, KBDCHARDEF_MOD_SHIFT},
216 /* 0x7E '~' */ {0x29, KBDCHARDEF_MOD_SHIFT},
217 /* 0x7F ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
218};
219
220static HRESULT keyboardPutScancodes(IKeyboard *pKeyboard, const std::list<LONG> &llScancodes)
221{
222 /* Send scancodes to the VM. */
223 com::SafeArray<LONG> saScancodes(llScancodes);
224
[95140]225 HRESULT hrc = S_OK;
[64907]226 size_t i;
[64906]227 for (i = 0; i < saScancodes.size(); ++i)
228 {
[95140]229 hrc = pKeyboard->PutScancode(saScancodes[i]);
230 if (FAILED(hrc))
[64906]231 {
[93708]232 RTMsgError(ControlVM::tr("Failed to send a scancode."));
[64906]233 break;
234 }
235
236 RTThreadSleep(10); /* "Typing" too fast causes lost characters. */
237 }
238
[95140]239 return hrc;
[64906]240}
241
242static void keyboardCharsToScancodes(const char *pch, size_t cchMax, std::list<LONG> &llScancodes, bool *pfShift)
243{
244 size_t cchProcessed = 0;
245 const char *p = pch;
246 while (cchProcessed < cchMax)
247 {
248 ++cchProcessed;
249 const uint8_t c = (uint8_t)*p++;
250 if (c < RT_ELEMENTS(g_aASCIIChars))
251 {
252 const KBDCHARDEF *d = &g_aASCIIChars[c];
253 if (d->u8Scancode)
254 {
255 const bool fNeedShift = RT_BOOL(d->u8Modifiers & KBDCHARDEF_MOD_SHIFT);
256 if (*pfShift != fNeedShift)
257 {
258 *pfShift = fNeedShift;
259 /* Press or release the SHIFT key. */
260 llScancodes.push_back(0x2a | (fNeedShift? 0x00: 0x80));
261 }
262
263 llScancodes.push_back(d->u8Scancode);
264 llScancodes.push_back(d->u8Scancode | 0x80);
265 }
266 }
267 }
268}
269
270static HRESULT keyboardPutString(IKeyboard *pKeyboard, int argc, char **argv)
271{
272 std::list<LONG> llScancodes;
273 bool fShift = false;
274
275 /* Convert command line string(s) to the en-us keyboard scancodes. */
276 int i;
277 for (i = 1 + 1; i < argc; ++i)
278 {
[72826]279 if (!llScancodes.empty())
[64906]280 {
281 /* Insert a SPACE before the next string. */
282 llScancodes.push_back(0x39);
283 llScancodes.push_back(0x39 | 0x80);
284 }
285
286 keyboardCharsToScancodes(argv[i], strlen(argv[i]), llScancodes, &fShift);
287 }
288
289 /* Release SHIFT if pressed. */
290 if (fShift)
291 llScancodes.push_back(0x2a | 0x80);
292
293 return keyboardPutScancodes(pKeyboard, llScancodes);
294}
295
296static HRESULT keyboardPutFile(IKeyboard *pKeyboard, const char *pszFilename)
297{
298 std::list<LONG> llScancodes;
299 bool fShift = false;
300
301 RTFILE File = NIL_RTFILE;
302 int vrc = RTFileOpen(&File, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
303 if (RT_SUCCESS(vrc))
304 {
305 uint64_t cbFile = 0;
[80585]306 vrc = RTFileQuerySize(File, &cbFile);
[64906]307 if (RT_SUCCESS(vrc))
308 {
309 const uint64_t cbFileMax = _64K;
310 if (cbFile <= cbFileMax)
311 {
312 const size_t cbBuffer = _4K;
313 char *pchBuf = (char *)RTMemAlloc(cbBuffer);
314 if (pchBuf)
315 {
316 size_t cbRemaining = (size_t)cbFile;
317 while (cbRemaining > 0)
318 {
319 const size_t cbToRead = cbRemaining > cbBuffer ? cbBuffer : cbRemaining;
320
321 size_t cbRead = 0;
322 vrc = RTFileRead(File, pchBuf, cbToRead, &cbRead);
323 if (RT_FAILURE(vrc) || cbRead == 0)
324 break;
325
326 keyboardCharsToScancodes(pchBuf, cbRead, llScancodes, &fShift);
327 cbRemaining -= cbRead;
328 }
329
330 RTMemFree(pchBuf);
331 }
332 else
[93708]333 RTMsgError(ControlVM::tr("Out of memory allocating %d bytes.", "", cbBuffer), cbBuffer);
[64906]334 }
335 else
[93708]336 RTMsgError(ControlVM::tr("File size %RI64 is greater than %RI64: '%s'."), cbFile, cbFileMax, pszFilename);
[64906]337 }
338 else
[93708]339 RTMsgError(ControlVM::tr("Cannot get size of file '%s': %Rrc."), pszFilename, vrc);
[64906]340
341 RTFileClose(File);
342 }
343 else
[93708]344 RTMsgError(ControlVM::tr("Cannot open file '%s': %Rrc."), pszFilename, vrc);
[64906]345
346 /* Release SHIFT if pressed. */
347 if (fShift)
348 llScancodes.push_back(0x2a | 0x80);
349
350 return keyboardPutScancodes(pKeyboard, llScancodes);
351}
352
353
[56118]354RTEXITCODE handleControlVM(HandlerArg *a)
[18782]355{
[24903]356 using namespace com;
[54523]357 bool fNeedsSaving = false;
[95140]358 HRESULT hrc;
[1]359
[16052]360 if (a->argc < 2)
[93708]361 return errorSyntax(ControlVM::tr("Not enough parameters."));
[1]362
363 /* try to find the given machine */
[47908]364 ComPtr<IMachine> machine;
[33294]365 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
366 machine.asOutParam()));
[95140]367 if (FAILED(hrc))
[56118]368 return RTEXITCODE_FAILURE;
[1]369
370 /* open a session for the VM */
[56118]371 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE);
[1]372
[54523]373 ComPtr<IConsole> console;
374 ComPtr<IMachine> sessionMachine;
375
[1]376 do
377 {
378 /* get the associated console */
[23934]379 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
[75251]380 if (!console)
[93708]381 return RTMsgErrorExit(RTEXITCODE_FAILURE, ControlVM::tr("Machine '%s' is not currently running."), a->argv[0]);
[75251]382
[1]383 /* ... and session machine */
[23934]384 CHECK_ERROR_BREAK(a->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
[1]385
386 /* which command? */
[18782]387 if (!strcmp(a->argv[1], "pause"))
[1]388 {
[93708]389 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_PAUSE);
[23934]390 CHECK_ERROR_BREAK(console, Pause());
[1]391 }
[18782]392 else if (!strcmp(a->argv[1], "resume"))
[1]393 {
[93708]394 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RESUME);
[23934]395 CHECK_ERROR_BREAK(console, Resume());
[1]396 }
[18782]397 else if (!strcmp(a->argv[1], "reset"))
[1]398 {
[93708]399 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RESET);
[23934]400 CHECK_ERROR_BREAK(console, Reset());
[1]401 }
[25901]402 else if (!strcmp(a->argv[1], "unplugcpu"))
403 {
[93708]404 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_UNPLUGCPU);
[25901]405 if (a->argc <= 1 + 1)
406 {
[93708]407 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]408 hrc = E_FAIL;
[25901]409 break;
410 }
411
412 unsigned n = parseNum(a->argv[2], 32, "CPU");
413
414 CHECK_ERROR_BREAK(sessionMachine, HotUnplugCPU(n));
415 }
416 else if (!strcmp(a->argv[1], "plugcpu"))
417 {
[93708]418 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_PLUGCPU);
[25901]419 if (a->argc <= 1 + 1)
420 {
[93708]421 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]422 hrc = E_FAIL;
[25901]423 break;
424 }
425
426 unsigned n = parseNum(a->argv[2], 32, "CPU");
427
428 CHECK_ERROR_BREAK(sessionMachine, HotPlugCPU(n));
429 }
[32885]430 else if (!strcmp(a->argv[1], "cpuexecutioncap"))
431 {
[93708]432 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_CPUEXECUTIONCAP);
[32885]433 if (a->argc <= 1 + 1)
434 {
[93708]435 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]436 hrc = E_FAIL;
[32885]437 break;
438 }
439
440 unsigned n = parseNum(a->argv[2], 100, "ExecutionCap");
441
[34604]442 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(CPUExecutionCap)(n));
[32885]443 }
[68485]444 else if (!strcmp(a->argv[1], "audioin"))
445 {
[93708]446 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_AUDIOIN);
[95423]447
448 ComPtr<IAudioSettings> audioSettings;
449 CHECK_ERROR_BREAK(sessionMachine, COMGETTER(AudioSettings)(audioSettings.asOutParam()));
[68485]450 ComPtr<IAudioAdapter> adapter;
[95423]451 CHECK_ERROR_BREAK(audioSettings, COMGETTER(Adapter)(adapter.asOutParam()));
[68485]452 if (adapter)
453 {
[93708]454 bool fEnabled;
455 if (RT_FAILURE(parseBool(a->argv[2], &fEnabled)))
[68485]456 {
[93708]457 errorSyntax(ControlVM::tr("Invalid value '%s'."), a->argv[2]);
[95140]458 hrc = E_FAIL;
[68485]459 break;
460 }
[93708]461 CHECK_ERROR_RET(adapter, COMSETTER(EnabledIn)(fEnabled), RTEXITCODE_FAILURE);
462 fNeedsSaving = true;
[68485]463 }
464 else
465 {
[93708]466 errorSyntax(ControlVM::tr("Audio adapter not enabled in VM configuration."));
[95140]467 hrc = E_FAIL;
[68485]468 break;
469 }
470 }
471 else if (!strcmp(a->argv[1], "audioout"))
472 {
[93708]473 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_AUDIOOUT);
[95423]474
475 ComPtr<IAudioSettings> audioSettings;
476 CHECK_ERROR_BREAK(sessionMachine, COMGETTER(AudioSettings)(audioSettings.asOutParam()));
[68485]477 ComPtr<IAudioAdapter> adapter;
[95423]478 CHECK_ERROR_BREAK(audioSettings, COMGETTER(Adapter)(adapter.asOutParam()));
[68485]479 if (adapter)
480 {
[93708]481 bool fEnabled;
482 if (RT_FAILURE(parseBool(a->argv[2], &fEnabled)))
[68485]483 {
[93708]484 errorSyntax(ControlVM::tr("Invalid value '%s'."), a->argv[2]);
[95140]485 hrc = E_FAIL;
[68485]486 break;
487 }
[93708]488 CHECK_ERROR_RET(adapter, COMSETTER(EnabledOut)(fEnabled), RTEXITCODE_FAILURE);
489 fNeedsSaving = true;
[68485]490 }
491 else
492 {
[93708]493 errorSyntax(ControlVM::tr("Audio adapter not enabled in VM configuration."));
[95140]494 hrc = E_FAIL;
[68485]495 break;
496 }
497 }
[81287]498#ifdef VBOX_WITH_SHARED_CLIPBOARD
[41925]499 else if (!strcmp(a->argv[1], "clipboard"))
500 {
501 if (a->argc <= 1 + 1)
502 {
[93708]503 errorArgument(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]504 hrc = E_FAIL;
[41925]505 break;
506 }
507
[63300]508 ClipboardMode_T mode = ClipboardMode_Disabled; /* Shut up MSC */
[81287]509 if (!strcmp(a->argv[2], "mode"))
[41925]510 {
[93708]511 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_CLIPBOARD_MODE);
512 if (a->argc <= 1 + 2)
513 {
514 errorSyntax(ControlVM::tr("Missing argument to '%s %s'."), a->argv[1], a->argv[2]);
[95140]515 hrc = E_FAIL;
[93708]516 break;
517 }
518
[81287]519 if (!strcmp(a->argv[3], "disabled"))
520 mode = ClipboardMode_Disabled;
521 else if (!strcmp(a->argv[3], "hosttoguest"))
522 mode = ClipboardMode_HostToGuest;
523 else if (!strcmp(a->argv[3], "guesttohost"))
524 mode = ClipboardMode_GuestToHost;
525 else if (!strcmp(a->argv[3], "bidirectional"))
526 mode = ClipboardMode_Bidirectional;
527 else
528 {
[93708]529 errorSyntax(ControlVM::tr("Invalid '%s %s' argument '%s'."), a->argv[1], a->argv[2], a->argv[3]);
[95140]530 hrc = E_FAIL;
[81287]531 break;
532 }
533
534 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(ClipboardMode)(mode));
[95140]535 if (SUCCEEDED(hrc))
[81287]536 fNeedsSaving = true;
[41925]537 }
[81287]538# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
539 else if (!strcmp(a->argv[2], "filetransfers"))
[41925]540 {
[93708]541 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_CLIPBOARD_FILETRANSFERS);
[81287]542 if (a->argc <= 1 + 2)
543 {
[93708]544 errorSyntax(ControlVM::tr("Missing argument to '%s %s'."), a->argv[1], a->argv[2]);
[95140]545 hrc = E_FAIL;
[81287]546 break;
547 }
548
[93708]549 bool fEnabled;
550 if (RT_FAILURE(parseBool(a->argv[3], &fEnabled)))
[81287]551 {
[93708]552 errorSyntax(ControlVM::tr("Invalid '%s %s' argument '%s'."), a->argv[1], a->argv[2], a->argv[3]);
[95140]553 hrc = E_FAIL;
[81287]554 break;
555 }
556
557 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(ClipboardFileTransfersEnabled)(fEnabled));
[93708]558 fNeedsSaving = true;
[41925]559 }
[81287]560# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
[81962]561 else
562 {
[93708]563 errorArgument(ControlVM::tr("Invalid '%s' argument '%s'."), a->argv[1], a->argv[2]);
[95140]564 hrc = E_FAIL;
[81962]565 break;
566 }
[41925]567 }
[81287]568#endif /* VBOX_WITH_SHARED_CLIPBOARD */
[42261]569 else if (!strcmp(a->argv[1], "draganddrop"))
570 {
[93708]571 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_DRAGANDDROP);
[42261]572 if (a->argc <= 1 + 1)
573 {
[93708]574 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]575 hrc = E_FAIL;
[42261]576 break;
577 }
578
[63300]579 DnDMode_T mode = DnDMode_Disabled; /* Shup up MSC. */
[42261]580 if (!strcmp(a->argv[2], "disabled"))
[51476]581 mode = DnDMode_Disabled;
[42261]582 else if (!strcmp(a->argv[2], "hosttoguest"))
[51476]583 mode = DnDMode_HostToGuest;
[42261]584 else if (!strcmp(a->argv[2], "guesttohost"))
[51476]585 mode = DnDMode_GuestToHost;
[42261]586 else if (!strcmp(a->argv[2], "bidirectional"))
[51476]587 mode = DnDMode_Bidirectional;
[42261]588 else
589 {
[93708]590 errorSyntax(ControlVM::tr("Invalid '%s' argument '%s'."), a->argv[1], a->argv[2]);
[95140]591 hrc = E_FAIL;
[42261]592 }
[95140]593 if (SUCCEEDED(hrc))
[42261]594 {
[51476]595 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(DnDMode)(mode));
[95140]596 if (SUCCEEDED(hrc))
[54525]597 fNeedsSaving = true;
[42261]598 }
599 }
[18782]600 else if (!strcmp(a->argv[1], "poweroff"))
[1]601 {
[93708]602 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_POWEROFF);
[20928]603 ComPtr<IProgress> progress;
[23934]604 CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam()));
[20928]605
[95140]606 hrc = showProgress(progress);
[93708]607 CHECK_PROGRESS_ERROR(progress, (ControlVM::tr("Failed to power off machine.")));
[1]608 }
[18782]609 else if (!strcmp(a->argv[1], "savestate"))
[1]610 {
[93708]611 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_SAVESTATE);
[29970]612 /* first pause so we don't trigger a live save which needs more time/resources */
[41096]613 bool fPaused = false;
[95140]614 hrc = console->Pause();
615 if (FAILED(hrc))
[35707]616 {
[41096]617 bool fError = true;
[95140]618 if (hrc == VBOX_E_INVALID_VM_STATE)
[35707]619 {
620 /* check if we are already paused */
621 MachineState_T machineState;
622 CHECK_ERROR_BREAK(console, COMGETTER(State)(&machineState));
[40673]623 /* the error code was lost by the previous instruction */
[95140]624 hrc = VBOX_E_INVALID_VM_STATE;
[35707]625 if (machineState != MachineState_Paused)
626 {
[93708]627 RTMsgError(ControlVM::tr("Machine in invalid state %d -- %s."),
[35907]628 machineState, machineStateToName(machineState, false));
[35707]629 }
[41096]630 else
631 {
632 fError = false;
633 fPaused = true;
634 }
[35707]635 }
[41096]636 if (fError)
637 break;
[35707]638 }
[29970]639
[1]640 ComPtr<IProgress> progress;
[55214]641 CHECK_ERROR(sessionMachine, SaveState(progress.asOutParam()));
[95140]642 if (FAILED(hrc))
[29979]643 {
[41096]644 if (!fPaused)
645 console->Resume();
[29979]646 break;
647 }
[1]648
[95140]649 hrc = showProgress(progress);
[93708]650 CHECK_PROGRESS_ERROR(progress, (ControlVM::tr("Failed to save machine state.")));
[95140]651 if (FAILED(hrc))
[41096]652 {
653 if (!fPaused)
654 console->Resume();
655 }
[1]656 }
[18782]657 else if (!strcmp(a->argv[1], "acpipowerbutton"))
[1]658 {
[93708]659 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_ACPIPOWERBUTTON);
[23934]660 CHECK_ERROR_BREAK(console, PowerButton());
[1]661 }
[18782]662 else if (!strcmp(a->argv[1], "acpisleepbutton"))
[6156]663 {
[93708]664 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_ACPISLEEPBUTTON);
[23934]665 CHECK_ERROR_BREAK(console, SleepButton());
[6156]666 }
[84576]667#ifdef VBOX_WITH_GUEST_CONTROL
[84575]668 else if ( !strcmp(a->argv[1], "reboot")
669 || !strcmp(a->argv[1], "shutdown")) /* With shutdown we mean gracefully powering off the VM by letting the guest OS do its thing. */
670 {
[93708]671 const bool fReboot = !strcmp(a->argv[1], "reboot");
672 if (fReboot)
673 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_REBOOT);
674 else
675 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_SHUTDOWN);
676
[84585]677 ComPtr<IGuest> pGuest;
678 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest.asOutParam()));
679 if (!pGuest)
680 {
[93708]681 RTMsgError(ControlVM::tr("Guest not running."));
[95140]682 hrc = E_FAIL;
[84585]683 break;
684 }
[84575]685
686 com::SafeArray<GuestShutdownFlag_T> aShutdownFlags;
687 if (fReboot)
688 aShutdownFlags.push_back(GuestShutdownFlag_Reboot);
689 else
690 aShutdownFlags.push_back(GuestShutdownFlag_PowerOff);
[84814]691
692 if ( a->argc >= 3
693 && !strcmp(a->argv[2], "--force"))
694 aShutdownFlags.push_back(GuestShutdownFlag_Force);
695
[84585]696 CHECK_ERROR(pGuest, Shutdown(ComSafeArrayAsInParam(aShutdownFlags)));
[95140]697 if (FAILED(hrc))
[84575]698 {
[95140]699 if (hrc == VBOX_E_NOT_SUPPORTED)
[93708]700 {
701 if (fReboot)
702 RTMsgError(ControlVM::tr("Current installed Guest Additions don't support rebooting the guest."));
703 else
704 RTMsgError(ControlVM::tr("Current installed Guest Additions don't support shutting down the guest."));
705 }
[84575]706 }
707 }
[84576]708#endif
[18782]709 else if (!strcmp(a->argv[1], "keyboardputscancode"))
[8675]710 {
[93708]711 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_KEYBOARDPUTSCANCODE);
[45190]712 ComPtr<IKeyboard> pKeyboard;
713 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
714 if (!pKeyboard)
715 {
[93708]716 RTMsgError(ControlVM::tr("Guest not running."));
[95140]717 hrc = E_FAIL;
[45190]718 break;
719 }
[8675]720
[16052]721 if (a->argc <= 1 + 1)
[8675]722 {
[93708]723 errorSyntax(ControlVM::tr("Missing argument to '%s'. Expected IBM PC AT set 2 keyboard scancode(s)."),
[92372]724 a->argv[1]);
[95140]725 hrc = E_FAIL;
[8675]726 break;
727 }
728
[32701]729 std::list<LONG> llScancodes;
[8675]730
731 /* Process the command line. */
732 int i;
[32701]733 for (i = 1 + 1; i < a->argc; i++)
[8675]734 {
[16052]735 if ( RT_C_IS_XDIGIT (a->argv[i][0])
736 && RT_C_IS_XDIGIT (a->argv[i][1])
737 && a->argv[i][2] == 0)
[8675]738 {
739 uint8_t u8Scancode;
[95140]740 int vrc = RTStrToUInt8Ex(a->argv[i], NULL, 16, &u8Scancode);
741 if (RT_FAILURE (vrc))
[8675]742 {
[95140]743 RTMsgError(ControlVM::tr("Converting '%s' returned %Rrc!"), a->argv[i], vrc);
744 hrc = E_FAIL;
[8675]745 break;
746 }
747
[32701]748 llScancodes.push_back(u8Scancode);
[8675]749 }
750 else
751 {
[93708]752 RTMsgError(ControlVM::tr("'%s' is not a hex byte!"), a->argv[i]);
[95140]753 hrc = E_FAIL;
[8675]754 break;
755 }
756 }
757
[95140]758 if (FAILED(hrc))
[8675]759 break;
760
[95140]761 hrc = keyboardPutScancodes(pKeyboard, llScancodes);
[64906]762 }
763 else if (!strcmp(a->argv[1], "keyboardputstring"))
764 {
[93708]765 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_KEYBOARDPUTSTRING);
[64906]766 ComPtr<IKeyboard> pKeyboard;
767 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
768 if (!pKeyboard)
[8675]769 {
[93708]770 RTMsgError(ControlVM::tr("Guest not running."));
[95140]771 hrc = E_FAIL;
[8675]772 break;
773 }
[64906]774
775 if (a->argc <= 1 + 1)
776 {
[93708]777 errorSyntax(ControlVM::tr("Missing argument to '%s'. Expected ASCII string(s)."), a->argv[1]);
[95140]778 hrc = E_FAIL;
[64906]779 break;
780 }
781
[95140]782 hrc = keyboardPutString(pKeyboard, a->argc, a->argv);
[8675]783 }
[64906]784 else if (!strcmp(a->argv[1], "keyboardputfile"))
785 {
[93708]786 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_KEYBOARDPUTFILE);
[64906]787 ComPtr<IKeyboard> pKeyboard;
788 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
789 if (!pKeyboard)
790 {
[93708]791 RTMsgError(ControlVM::tr("Guest not running."));
[95140]792 hrc = E_FAIL;
[64906]793 break;
794 }
795
796 if (a->argc <= 1 + 1)
797 {
[93708]798 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]799 hrc = E_FAIL;
[64906]800 break;
801 }
802
[95140]803 hrc = keyboardPutFile(pKeyboard, a->argv[2]);
[64906]804 }
[18782]805 else if (!strncmp(a->argv[1], "setlinkstate", 12))
[1]806 {
[93708]807 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_SETLINKSTATE);
[1]808 /* Get the number of network adapters */
[35761]809 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
[16052]810 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
[1]811 if (!n)
812 {
[95140]813 hrc = E_FAIL;
[1]814 break;
815 }
[16052]816 if (a->argc <= 1 + 1)
[1]817 {
[93708]818 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]819 hrc = E_FAIL;
[1]820 break;
821 }
822 /* get the corresponding network adapter */
823 ComPtr<INetworkAdapter> adapter;
[23934]824 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
[1]825 if (adapter)
826 {
[93708]827 bool fEnabled;
[96907]828 if (RT_FAILURE(parseBool(a->argv[2], &fEnabled)))
[1]829 {
[93708]830 errorSyntax(ControlVM::tr("Invalid link state '%s'."), a->argv[2]);
[95140]831 hrc = E_FAIL;
[1]832 break;
833 }
[93708]834 CHECK_ERROR_BREAK(adapter, COMSETTER(CableConnected)(fEnabled));
835 fNeedsSaving = true;
[1]836 }
837 }
[23222]838 /* here the order in which strncmp is called is important
839 * cause nictracefile can be very well compared with
840 * nictrace and nic and thus everything will always fail
841 * if the order is changed
842 */
843 else if (!strncmp(a->argv[1], "nictracefile", 12))
844 {
[93708]845 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_NICTRACEFILE);
[23222]846 /* Get the number of network adapters */
[35761]847 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
[23222]848 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
849 if (!n)
850 {
[95140]851 hrc = E_FAIL;
[23222]852 break;
853 }
854 if (a->argc <= 2)
855 {
[93708]856 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]857 hrc = E_FAIL;
[23222]858 break;
859 }
860
861 /* get the corresponding network adapter */
862 ComPtr<INetworkAdapter> adapter;
[23934]863 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
[23222]864 if (adapter)
865 {
866 BOOL fEnabled;
867 adapter->COMGETTER(Enabled)(&fEnabled);
868 if (fEnabled)
869 {
870 if (a->argv[2])
871 {
[56118]872 CHECK_ERROR_RET(adapter, COMSETTER(TraceFile)(Bstr(a->argv[2]).raw()), RTEXITCODE_FAILURE);
[23222]873 }
874 else
875 {
[93708]876 errorSyntax(ControlVM::tr("Filename not specified for NIC %lu."), n);
[95140]877 hrc = E_FAIL;
[23222]878 break;
879 }
[95140]880 if (SUCCEEDED(hrc))
[54525]881 fNeedsSaving = true;
[23222]882 }
883 else
[93708]884 RTMsgError(ControlVM::tr("The NIC %d is currently disabled and thus its tracefile can't be changed."), n);
[23222]885 }
886 }
887 else if (!strncmp(a->argv[1], "nictrace", 8))
888 {
[93708]889 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_NICTRACE);
[23222]890 /* Get the number of network adapters */
[35761]891 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
[23222]892 unsigned n = parseNum(&a->argv[1][8], NetworkAdapterCount, "NIC");
893 if (!n)
894 {
[95140]895 hrc = E_FAIL;
[23222]896 break;
897 }
898 if (a->argc <= 2)
899 {
[93708]900 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]901 hrc = E_FAIL;
[23222]902 break;
903 }
904
905 /* get the corresponding network adapter */
906 ComPtr<INetworkAdapter> adapter;
[23934]907 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
[23222]908 if (adapter)
909 {
910 BOOL fEnabled;
911 adapter->COMGETTER(Enabled)(&fEnabled);
912 if (fEnabled)
913 {
[93708]914 bool fTraceEnabled;
[96907]915 if (RT_FAILURE(parseBool(a->argv[2], &fTraceEnabled)))
[23222]916 {
[93708]917 errorSyntax(ControlVM::tr("Invalid nictrace%lu argument '%s'."), n, a->argv[2]);
[95140]918 hrc = E_FAIL;
[23222]919 break;
920 }
[93708]921 CHECK_ERROR_RET(adapter, COMSETTER(TraceEnabled)(fTraceEnabled), RTEXITCODE_FAILURE);
922 fNeedsSaving = true;
[23222]923 }
924 else
[93708]925 RTMsgError(ControlVM::tr("The NIC %d is currently disabled and thus its trace flag can't be changed."), n);
[23222]926 }
927 }
[34014]928 else if( a->argc > 2
[33825]929 && !strncmp(a->argv[1], "natpf", 5))
930 {
931 /* Get the number of network adapters */
[35761]932 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
[33825]933 unsigned n = parseNum(&a->argv[1][5], NetworkAdapterCount, "NIC");
934 if (!n)
935 {
[95140]936 hrc = E_FAIL;
[33825]937 break;
938 }
939 if (a->argc <= 2)
940 {
[93708]941 errorArgument(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]942 hrc = E_FAIL;
[33825]943 break;
944 }
945
946 /* get the corresponding network adapter */
947 ComPtr<INetworkAdapter> adapter;
948 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
949 if (!adapter)
950 {
[95140]951 hrc = E_FAIL;
[33825]952 break;
953 }
[54378]954 ComPtr<INATEngine> engine;
[42551]955 CHECK_ERROR(adapter, COMGETTER(NATEngine)(engine.asOutParam()));
[33825]956 if (!engine)
957 {
[95140]958 hrc = E_FAIL;
[33825]959 break;
960 }
961
962 if (!strcmp(a->argv[2], "delete"))
[34014]963 {
[93708]964 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_NATPF_DELETE);
[33825]965 if (a->argc >= 3)
966 CHECK_ERROR(engine, RemoveRedirect(Bstr(a->argv[3]).raw()));
967 }
968 else
969 {
[93708]970 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_NATPF);
[92372]971#define ITERATE_TO_NEXT_TERM(ch) \
972 do { \
973 while (*ch != ',') \
974 { \
975 if (*ch == 0) \
976 { \
[93708]977 return errorSyntax(ControlVM::tr("Missing or invalid argument to '%s'."), \
978 a->argv[1]); \
[92372]979 } \
980 ch++; \
981 } \
982 *ch = '\0'; \
983 ch++; \
[33825]984 } while(0)
985
986 char *strName;
987 char *strProto;
988 char *strHostIp;
989 char *strHostPort;
990 char *strGuestIp;
991 char *strGuestPort;
992 char *strRaw = RTStrDup(a->argv[2]);
993 char *ch = strRaw;
994 strName = RTStrStrip(ch);
995 ITERATE_TO_NEXT_TERM(ch);
996 strProto = RTStrStrip(ch);
997 ITERATE_TO_NEXT_TERM(ch);
998 strHostIp = RTStrStrip(ch);
999 ITERATE_TO_NEXT_TERM(ch);
1000 strHostPort = RTStrStrip(ch);
1001 ITERATE_TO_NEXT_TERM(ch);
1002 strGuestIp = RTStrStrip(ch);
1003 ITERATE_TO_NEXT_TERM(ch);
1004 strGuestPort = RTStrStrip(ch);
1005 NATProtocol_T proto;
1006 if (RTStrICmp(strProto, "udp") == 0)
1007 proto = NATProtocol_UDP;
1008 else if (RTStrICmp(strProto, "tcp") == 0)
1009 proto = NATProtocol_TCP;
[33830]1010 else
1011 {
[93708]1012 return errorSyntax(ControlVM::tr("Wrong rule proto '%s' specified -- only 'udp' and 'tcp' are allowed."),
[33830]1013 strProto);
1014 }
[33825]1015 CHECK_ERROR(engine, AddRedirect(Bstr(strName).raw(), proto, Bstr(strHostIp).raw(),
1016 RTStrToUInt16(strHostPort), Bstr(strGuestIp).raw(), RTStrToUInt16(strGuestPort)));
1017#undef ITERATE_TO_NEXT_TERM
1018 }
[95140]1019 if (SUCCEEDED(hrc))
[54523]1020 fNeedsSaving = true;
[33825]1021 }
[37200]1022 else if (!strncmp(a->argv[1], "nicproperty", 11))
1023 {
[93708]1024 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_NICPROPERTY);
[37200]1025 /* Get the number of network adapters */
[54378]1026 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
[37200]1027 unsigned n = parseNum(&a->argv[1][11], NetworkAdapterCount, "NIC");
1028 if (!n)
1029 {
[95140]1030 hrc = E_FAIL;
[37200]1031 break;
1032 }
1033 if (a->argc <= 2)
1034 {
[93708]1035 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]1036 hrc = E_FAIL;
[37200]1037 break;
1038 }
1039
1040 /* get the corresponding network adapter */
1041 ComPtr<INetworkAdapter> adapter;
1042 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
1043 if (adapter)
1044 {
1045 BOOL fEnabled;
1046 adapter->COMGETTER(Enabled)(&fEnabled);
1047 if (fEnabled)
1048 {
1049 /* Parse 'name=value' */
1050 char *pszProperty = RTStrDup(a->argv[2]);
1051 if (pszProperty)
1052 {
1053 char *pDelimiter = strchr(pszProperty, '=');
1054 if (pDelimiter)
1055 {
1056 *pDelimiter = '\0';
1057
1058 Bstr bstrName = pszProperty;
1059 Bstr bstrValue = &pDelimiter[1];
1060 CHECK_ERROR(adapter, SetProperty(bstrName.raw(), bstrValue.raw()));
[95140]1061 if (SUCCEEDED(hrc))
[54523]1062 fNeedsSaving = true;
[37200]1063 }
1064 else
1065 {
[93708]1066 errorSyntax(ControlVM::tr("Invalid nicproperty%d argument '%s'."), n, a->argv[2]);
[95140]1067 hrc = E_FAIL;
[37200]1068 }
1069 RTStrFree(pszProperty);
1070 }
1071 else
1072 {
[93708]1073 RTMsgError(ControlVM::tr("Failed to allocate memory for nicproperty%d '%s'."),
[92372]1074 n, a->argv[2]);
[95140]1075 hrc = E_FAIL;
[37200]1076 }
[95140]1077 if (FAILED(hrc))
[37200]1078 break;
1079 }
1080 else
[93708]1081 RTMsgError(ControlVM::tr("The NIC %d is currently disabled and thus its properties can't be changed."), n);
[37200]1082 }
1083 }
[45021]1084 else if (!strncmp(a->argv[1], "nicpromisc", 10))
1085 {
[93708]1086 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_NICPROMISC);
[45021]1087 /* Get the number of network adapters */
[54378]1088 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
[45021]1089 unsigned n = parseNum(&a->argv[1][10], NetworkAdapterCount, "NIC");
1090 if (!n)
1091 {
[95140]1092 hrc = E_FAIL;
[45021]1093 break;
1094 }
1095 if (a->argc <= 2)
1096 {
[93708]1097 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]1098 hrc = E_FAIL;
[45021]1099 break;
1100 }
1101
1102 /* get the corresponding network adapter */
1103 ComPtr<INetworkAdapter> adapter;
1104 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
1105 if (adapter)
1106 {
1107 BOOL fEnabled;
1108 adapter->COMGETTER(Enabled)(&fEnabled);
1109 if (fEnabled)
1110 {
1111 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
1112 if (!strcmp(a->argv[2], "deny"))
1113 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_Deny;
1114 else if ( !strcmp(a->argv[2], "allow-vms")
1115 || !strcmp(a->argv[2], "allow-network"))
1116 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowNetwork;
1117 else if (!strcmp(a->argv[2], "allow-all"))
1118 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowAll;
1119 else
1120 {
[93708]1121 errorSyntax(ControlVM::tr("Unknown promiscuous mode policy '%s'."), a->argv[2]);
[95140]1122 hrc = E_INVALIDARG;
[45021]1123 break;
1124 }
1125
1126 CHECK_ERROR(adapter, COMSETTER(PromiscModePolicy)(enmPromiscModePolicy));
[95140]1127 if (SUCCEEDED(hrc))
[54523]1128 fNeedsSaving = true;
[45021]1129 }
1130 else
[93708]1131 RTMsgError(ControlVM::tr("The NIC %d is currently disabled and thus its promiscuous mode can't be changed."), n);
[45021]1132 }
1133 }
[20521]1134 else if (!strncmp(a->argv[1], "nic", 3))
1135 {
[93708]1136 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_NIC);
[20521]1137 /* Get the number of network adapters */
[54378]1138 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
[20521]1139 unsigned n = parseNum(&a->argv[1][3], NetworkAdapterCount, "NIC");
1140 if (!n)
1141 {
[95140]1142 hrc = E_FAIL;
[20521]1143 break;
1144 }
[21729]1145 if (a->argc <= 2)
[20521]1146 {
[93708]1147 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]1148 hrc = E_FAIL;
[20521]1149 break;
1150 }
1151
1152 /* get the corresponding network adapter */
1153 ComPtr<INetworkAdapter> adapter;
[23934]1154 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
[20521]1155 if (adapter)
1156 {
[21729]1157 BOOL fEnabled;
1158 adapter->COMGETTER(Enabled)(&fEnabled);
1159 if (fEnabled)
[20521]1160 {
[21729]1161 if (!strcmp(a->argv[2], "null"))
[20521]1162 {
[56118]1163 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Null), RTEXITCODE_FAILURE);
[20521]1164 }
[21729]1165 else if (!strcmp(a->argv[2], "nat"))
[20521]1166 {
[21729]1167 if (a->argc == 4)
[56118]1168 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1169 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_NAT), RTEXITCODE_FAILURE);
[20521]1170 }
[21729]1171 else if ( !strcmp(a->argv[2], "bridged")
1172 || !strcmp(a->argv[2], "hostif")) /* backward compatibility */
1173 {
1174 if (a->argc <= 3)
1175 {
[93708]1176 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[2]);
[95140]1177 hrc = E_FAIL;
[21729]1178 break;
1179 }
[56118]1180 CHECK_ERROR_RET(adapter, COMSETTER(BridgedInterface)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
[88079]1181 verifyHostNetworkInterfaceName(a->virtualBox, a->argv[3], HostNetworkInterfaceType_Bridged);
[56118]1182 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Bridged), RTEXITCODE_FAILURE);
[21729]1183 }
1184 else if (!strcmp(a->argv[2], "intnet"))
1185 {
1186 if (a->argc <= 3)
1187 {
[93708]1188 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[2]);
[95140]1189 hrc = E_FAIL;
[21729]1190 break;
1191 }
[56118]1192 CHECK_ERROR_RET(adapter, COMSETTER(InternalNetwork)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1193 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Internal), RTEXITCODE_FAILURE);
[21729]1194 }
[20521]1195#if defined(VBOX_WITH_NETFLT)
[21729]1196 else if (!strcmp(a->argv[2], "hostonly"))
[20521]1197 {
[21729]1198 if (a->argc <= 3)
1199 {
[93708]1200 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[2]);
[95140]1201 hrc = E_FAIL;
[21729]1202 break;
1203 }
[56118]1204 CHECK_ERROR_RET(adapter, COMSETTER(HostOnlyInterface)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
[88079]1205 verifyHostNetworkInterfaceName(a->virtualBox, a->argv[3], HostNetworkInterfaceType_HostOnly);
[56118]1206 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_HostOnly), RTEXITCODE_FAILURE);
[21729]1207 }
1208#endif
[37200]1209 else if (!strcmp(a->argv[2], "generic"))
1210 {
1211 if (a->argc <= 3)
1212 {
[93708]1213 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[2]);
[95140]1214 hrc = E_FAIL;
[37200]1215 break;
1216 }
[56118]1217 CHECK_ERROR_RET(adapter, COMSETTER(GenericDriver)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1218 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic), RTEXITCODE_FAILURE);
[37200]1219 }
[48538]1220 else if (!strcmp(a->argv[2], "natnetwork"))
1221 {
1222 if (a->argc <= 3)
1223 {
[93708]1224 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[2]);
[95140]1225 hrc = E_FAIL;
[48538]1226 break;
1227 }
[56118]1228 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1229 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_NATNetwork), RTEXITCODE_FAILURE);
[48538]1230 }
[21729]1231 else
1232 {
[93708]1233 errorSyntax(ControlVM::tr("Invalid type '%s' specfied for NIC %lu."), a->argv[2], n);
[95140]1234 hrc = E_FAIL;
[20521]1235 break;
1236 }
[95140]1237 if (SUCCEEDED(hrc))
[54525]1238 fNeedsSaving = true;
[20521]1239 }
1240 else
[93708]1241 RTMsgError(ControlVM::tr("The NIC %d is currently disabled and thus its attachment type can't be changed."), n);
[20521]1242 }
1243 }
[33386]1244 else if ( !strcmp(a->argv[1], "vrde")
1245 || !strcmp(a->argv[1], "vrdp"))
[15267]1246 {
[93708]1247 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_VRDE);
[33386]1248 if (!strcmp(a->argv[1], "vrdp"))
[93708]1249 RTMsgWarning(ControlVM::tr("'vrdp' is deprecated. Use 'vrde'."));
[33386]1250
[16052]1251 if (a->argc <= 1 + 1)
[15267]1252 {
[93708]1253 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]1254 hrc = E_FAIL;
[15267]1255 break;
1256 }
[33386]1257 ComPtr<IVRDEServer> vrdeServer;
1258 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1259 ASSERT(vrdeServer);
1260 if (vrdeServer)
[15267]1261 {
[93708]1262 bool fEnabled;
1263 if (RT_FAILURE(parseBool(a->argv[2], &fEnabled)))
[15267]1264 {
[93708]1265 errorSyntax(ControlVM::tr("Invalid remote desktop server state '%s'."), a->argv[2]);
[95140]1266 hrc = E_FAIL;
[15267]1267 break;
1268 }
[93708]1269 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(fEnabled));
1270 fNeedsSaving = true;
[15267]1271 }
1272 }
[35194]1273 else if ( !strcmp(a->argv[1], "vrdeport")
1274 || !strcmp(a->argv[1], "vrdpport"))
[23129]1275 {
[93708]1276 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_VRDEPORT);
[35194]1277 if (!strcmp(a->argv[1], "vrdpport"))
[93708]1278 RTMsgWarning(ControlVM::tr("'vrdpport' is deprecated. Use 'vrdeport'."));
[35194]1279
[23129]1280 if (a->argc <= 1 + 1)
1281 {
[93708]1282 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]1283 hrc = E_FAIL;
[23129]1284 break;
1285 }
[35105]1286
[33386]1287 ComPtr<IVRDEServer> vrdeServer;
1288 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1289 ASSERT(vrdeServer);
1290 if (vrdeServer)
[23129]1291 {
[33386]1292 Bstr ports;
[23129]1293
1294 if (!strcmp(a->argv[2], "default"))
[33386]1295 ports = "0";
[23129]1296 else
[33386]1297 ports = a->argv[2];
[23129]1298
[33386]1299 CHECK_ERROR_BREAK(vrdeServer, SetVRDEProperty(Bstr("TCP/Ports").raw(), ports.raw()));
[95140]1300 if (SUCCEEDED(hrc))
[54525]1301 fNeedsSaving = true;
[23129]1302 }
1303 }
[33386]1304 else if ( !strcmp(a->argv[1], "vrdevideochannelquality")
1305 || !strcmp(a->argv[1], "vrdpvideochannelquality"))
[29364]1306 {
[93708]1307 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_VRDEVIDEOCHANNELQUALITY);
[33386]1308 if (!strcmp(a->argv[1], "vrdpvideochannelquality"))
[93708]1309 RTMsgWarning(ControlVM::tr("'vrdpvideochannelquality' is deprecated. Use 'vrdevideochannelquality'."));
[33386]1310
[29364]1311 if (a->argc <= 1 + 1)
1312 {
[93708]1313 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]1314 hrc = E_FAIL;
[29364]1315 break;
1316 }
[33386]1317 ComPtr<IVRDEServer> vrdeServer;
1318 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1319 ASSERT(vrdeServer);
1320 if (vrdeServer)
[29364]1321 {
[35146]1322 Bstr value = a->argv[2];
[29364]1323
[35146]1324 CHECK_ERROR(vrdeServer, SetVRDEProperty(Bstr("VideoChannel/Quality").raw(), value.raw()));
[95140]1325 if (SUCCEEDED(hrc))
[54525]1326 fNeedsSaving = true;
[29364]1327 }
1328 }
[33590]1329 else if (!strcmp(a->argv[1], "vrdeproperty"))
[33386]1330 {
[93708]1331 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_VRDEPROPERTY);
[33386]1332 if (a->argc <= 1 + 1)
1333 {
[93708]1334 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]1335 hrc = E_FAIL;
[33386]1336 break;
1337 }
1338 ComPtr<IVRDEServer> vrdeServer;
1339 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1340 ASSERT(vrdeServer);
1341 if (vrdeServer)
1342 {
1343 /* Parse 'name=value' */
1344 char *pszProperty = RTStrDup(a->argv[2]);
1345 if (pszProperty)
1346 {
1347 char *pDelimiter = strchr(pszProperty, '=');
1348 if (pDelimiter)
1349 {
1350 *pDelimiter = '\0';
1351
1352 Bstr bstrName = pszProperty;
1353 Bstr bstrValue = &pDelimiter[1];
1354 CHECK_ERROR(vrdeServer, SetVRDEProperty(bstrName.raw(), bstrValue.raw()));
[95140]1355 if (SUCCEEDED(hrc))
[54525]1356 fNeedsSaving = true;
[33386]1357 }
1358 else
1359 {
[93708]1360 errorSyntax(ControlVM::tr("Invalid vrdeproperty argument '%s'."), a->argv[2]);
[95140]1361 hrc = E_FAIL;
[33386]1362 }
1363 RTStrFree(pszProperty);
1364 }
1365 else
1366 {
[93708]1367 RTMsgError(ControlVM::tr("Failed to allocate memory for VRDE property '%s'."),
[92372]1368 a->argv[2]);
[95140]1369 hrc = E_FAIL;
[33386]1370 }
1371 }
[95140]1372 if (FAILED(hrc))
[33386]1373 {
1374 break;
1375 }
1376 }
[23934]1377 else if ( !strcmp(a->argv[1], "usbattach")
1378 || !strcmp(a->argv[1], "usbdetach"))
[1]1379 {
[93708]1380 bool attach = !strcmp(a->argv[1], "usbattach");
1381 if (attach)
1382 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_USBATTACH);
1383 else
1384 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_USBDETACH);
1385
[16052]1386 if (a->argc < 3)
[1]1387 {
[93708]1388 errorSyntax(ControlVM::tr("Not enough parameters."));
[95140]1389 hrc = E_FAIL;
[1]1390 break;
1391 }
[53062]1392 else if (a->argc == 4 || a->argc > 5)
1393 {
[93708]1394 errorSyntax(ControlVM::tr("Wrong number of arguments."));
[95140]1395 hrc = E_FAIL;
[53062]1396 break;
1397 }
[1]1398
[32718]1399 Bstr usbId = a->argv[2];
[53062]1400 Bstr captureFilename;
[44039]1401
[53062]1402 if (a->argc == 5)
1403 {
1404 if (!strcmp(a->argv[3], "--capturefile"))
1405 captureFilename = a->argv[4];
1406 else
1407 {
[93708]1408 errorSyntax(ControlVM::tr("Invalid parameter '%s'."), a->argv[3]);
[95140]1409 hrc = E_FAIL;
[53062]1410 break;
1411 }
1412 }
1413
[44039]1414 Guid guid(usbId);
1415 if (!guid.isValid())
[1]1416 {
1417 // assume address
1418 if (attach)
1419 {
[47908]1420 ComPtr<IHost> host;
[23934]1421 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
[17684]1422 SafeIfaceArray <IHostUSBDevice> coll;
[23934]1423 CHECK_ERROR_BREAK(host, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
[47908]1424 ComPtr<IHostUSBDevice> dev;
[32718]1425 CHECK_ERROR_BREAK(host, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
1426 dev.asOutParam()));
[23934]1427 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
[1]1428 }
1429 else
1430 {
[17553]1431 SafeIfaceArray <IUSBDevice> coll;
[23934]1432 CHECK_ERROR_BREAK(console, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
[47908]1433 ComPtr<IUSBDevice> dev;
[32718]1434 CHECK_ERROR_BREAK(console, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
1435 dev.asOutParam()));
[23934]1436 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
[1]1437 }
1438 }
[44039]1439 else if (guid.isZero())
1440 {
[93708]1441 errorSyntax(ControlVM::tr("Zero UUID argument '%s'."), a->argv[2]);
[95140]1442 hrc = E_FAIL;
[44039]1443 break;
1444 }
[1]1445
1446 if (attach)
[53062]1447 CHECK_ERROR_BREAK(console, AttachUSBDevice(usbId.raw(), captureFilename.raw()));
[1]1448 else
1449 {
[47908]1450 ComPtr<IUSBDevice> dev;
[32718]1451 CHECK_ERROR_BREAK(console, DetachUSBDevice(usbId.raw(),
1452 dev.asOutParam()));
[1]1453 }
1454 }
[18782]1455 else if (!strcmp(a->argv[1], "setvideomodehint"))
[1]1456 {
[93708]1457 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_SETVIDEOMODEHINT);
[42248]1458 if (a->argc != 5 && a->argc != 6 && a->argc != 7 && a->argc != 9)
[1]1459 {
[93708]1460 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[95140]1461 hrc = E_FAIL;
[1]1462 break;
1463 }
[42248]1464 bool fEnabled = true;
1465 uint32_t uXRes = RTStrToUInt32(a->argv[2]);
1466 uint32_t uYRes = RTStrToUInt32(a->argv[3]);
1467 uint32_t uBpp = RTStrToUInt32(a->argv[4]);
1468 uint32_t uDisplayIdx = 0;
1469 bool fChangeOrigin = false;
1470 int32_t iOriginX = 0;
1471 int32_t iOriginY = 0;
1472 if (a->argc >= 6)
1473 uDisplayIdx = RTStrToUInt32(a->argv[5]);
1474 if (a->argc >= 7)
1475 {
[93708]1476 if (RT_FAILURE(parseBool(a->argv[6], &fEnabled)))
[42248]1477 {
[93708]1478 errorSyntax(ControlVM::tr("Either \"yes\" or \"no\" is expected."));
[95140]1479 hrc = E_FAIL;
[42248]1480 break;
1481 }
1482 }
1483 if (a->argc == 9)
1484 {
1485 iOriginX = RTStrToInt32(a->argv[7]);
1486 iOriginY = RTStrToInt32(a->argv[8]);
1487 fChangeOrigin = true;
1488 }
[1]1489
[44309]1490 ComPtr<IDisplay> pDisplay;
1491 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1492 if (!pDisplay)
1493 {
[93708]1494 RTMsgError(ControlVM::tr("Guest not running."));
[95140]1495 hrc = E_FAIL;
[44309]1496 break;
1497 }
1498 CHECK_ERROR_BREAK(pDisplay, SetVideoModeHint(uDisplayIdx, fEnabled,
1499 fChangeOrigin, iOriginX, iOriginY,
[78995]1500 uXRes, uYRes, uBpp, true));
[1]1501 }
[72352]1502 else if (!strcmp(a->argv[1], "setscreenlayout"))
1503 {
[93708]1504 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_SETSCREENLAYOUT);
[72352]1505 if (a->argc < 4)
1506 {
[93708]1507 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[95140]1508 hrc = E_FAIL;
[72352]1509 break;
1510 }
1511
1512 ComPtr<IDisplay> pDisplay;
1513 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1514 if (!pDisplay)
1515 {
[93708]1516 RTMsgError(ControlVM::tr("Guest not running."));
[95140]1517 hrc = E_FAIL;
[72352]1518 break;
1519 }
1520
1521 com::SafeIfaceArray<IGuestScreenInfo> aGuestScreenInfos;
1522
1523 /* Parse "<display> on|primary <xorigin> <yorigin> <xres> <yres> <bpp> | off" sequences. */
1524 int argc = a->argc - 2;
1525 char **argv = &a->argv[2];
1526 while (argc >= 2)
1527 {
1528 ULONG aDisplay = RTStrToUInt32(argv[0]);
1529 BOOL aPrimary = FALSE;
1530
1531 GuestMonitorStatus_T aStatus;
1532 if (RTStrICmp(argv[1], "primary") == 0)
1533 {
1534 aStatus = GuestMonitorStatus_Enabled;
1535 aPrimary = TRUE;
1536 }
1537 else if (RTStrICmp(argv[1], "on") == 0)
1538 aStatus = GuestMonitorStatus_Enabled;
1539 else if (RTStrICmp(argv[1], "off") == 0)
1540 aStatus = GuestMonitorStatus_Disabled;
1541 else
1542 {
[93708]1543 errorSyntax(ControlVM::tr("Display status must be <on> or <off>."));
[95140]1544 hrc = E_FAIL;
[72352]1545 break;
1546 }
1547
1548 BOOL aChangeOrigin = FALSE;
1549 LONG aOriginX = 0;
1550 LONG aOriginY = 0;
1551 ULONG aWidth = 0;
1552 ULONG aHeight = 0;
1553 ULONG aBitsPerPixel = 0;
[72355]1554 if (aStatus == GuestMonitorStatus_Enabled)
[72352]1555 {
1556 if (argc < 7)
1557 {
[93708]1558 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[95140]1559 hrc = E_FAIL;
[72352]1560 break;
1561 }
1562
1563 aChangeOrigin = TRUE;
1564 aOriginX = RTStrToUInt32(argv[2]);
1565 aOriginY = RTStrToUInt32(argv[3]);
1566 aWidth = RTStrToUInt32(argv[4]);
1567 aHeight = RTStrToUInt32(argv[5]);
1568 aBitsPerPixel = RTStrToUInt32(argv[6]);
1569
1570 argc -= 7;
1571 argv += 7;
1572 }
1573 else
1574 {
1575 argc -= 2;
1576 argv += 2;
1577 }
1578
1579 ComPtr<IGuestScreenInfo> pInfo;
1580 CHECK_ERROR_BREAK(pDisplay, CreateGuestScreenInfo(aDisplay, aStatus, aPrimary, aChangeOrigin,
1581 aOriginX, aOriginY, aWidth, aHeight, aBitsPerPixel,
1582 pInfo.asOutParam()));
1583 aGuestScreenInfos.push_back(pInfo);
1584 }
1585
[95140]1586 if (FAILED(hrc))
[72352]1587 break;
1588
1589 CHECK_ERROR_BREAK(pDisplay, SetScreenLayout(ScreenLayoutMode_Apply, ComSafeArrayAsInParam(aGuestScreenInfos)));
1590 }
[18782]1591 else if (!strcmp(a->argv[1], "setcredentials"))
[1]1592 {
[93708]1593 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_SETCREDENTIALS);
[1]1594 bool fAllowLocalLogon = true;
[42444]1595 if ( a->argc == 7
1596 || ( a->argc == 8
1597 && ( !strcmp(a->argv[3], "-p")
1598 || !strcmp(a->argv[3], "--passwordfile"))))
[1]1599 {
[42444]1600 if ( strcmp(a->argv[5 + (a->argc - 7)], "--allowlocallogon")
1601 && strcmp(a->argv[5 + (a->argc - 7)], "-allowlocallogon"))
[1]1602 {
[93708]1603 errorSyntax(ControlVM::tr("Invalid parameter '%s'."), a->argv[5]);
[95140]1604 hrc = E_FAIL;
[1]1605 break;
1606 }
[42444]1607 if (!strcmp(a->argv[6 + (a->argc - 7)], "no"))
[1]1608 fAllowLocalLogon = false;
1609 }
[42444]1610 else if ( a->argc != 5
1611 && ( a->argc != 6
1612 || ( strcmp(a->argv[3], "-p")
1613 && strcmp(a->argv[3], "--passwordfile"))))
[1]1614 {
[93708]1615 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[95140]1616 hrc = E_FAIL;
[1]1617 break;
1618 }
[42444]1619 Utf8Str passwd, domain;
1620 if (a->argc == 5 || a->argc == 7)
1621 {
1622 passwd = a->argv[3];
1623 domain = a->argv[4];
1624 }
1625 else
1626 {
1627 RTEXITCODE rcExit = readPasswordFile(a->argv[4], &passwd);
1628 if (rcExit != RTEXITCODE_SUCCESS)
1629 {
[95140]1630 hrc = E_FAIL;
[42444]1631 break;
1632 }
1633 domain = a->argv[5];
1634 }
[1]1635
[44513]1636 ComPtr<IGuest> pGuest;
1637 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest.asOutParam()));
1638 if (!pGuest)
1639 {
[93708]1640 RTMsgError(ControlVM::tr("Guest not running."));
[95140]1641 hrc = E_FAIL;
[44513]1642 break;
1643 }
1644 CHECK_ERROR_BREAK(pGuest, SetCredentials(Bstr(a->argv[2]).raw(),
1645 Bstr(passwd).raw(),
1646 Bstr(domain).raw(),
1647 fAllowLocalLogon));
[1]1648 }
[26941]1649 else if (!strcmp(a->argv[1], "guestmemoryballoon"))
[4659]1650 {
[93708]1651 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_GUESTMEMORYBALLOON);
[16052]1652 if (a->argc != 3)
[4659]1653 {
[93708]1654 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[95140]1655 hrc = E_FAIL;
[4659]1656 break;
1657 }
1658 uint32_t uVal;
1659 int vrc;
[16052]1660 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
[4659]1661 if (vrc != VINF_SUCCESS)
1662 {
[93708]1663 errorSyntax(ControlVM::tr("Error parsing guest memory balloon size '%s'."), a->argv[2]);
[95140]1664 hrc = E_FAIL;
[4659]1665 break;
1666 }
[28528]1667 /* guest is running; update IGuest */
[47908]1668 ComPtr<IGuest> pGuest;
[95140]1669 hrc = console->COMGETTER(Guest)(pGuest.asOutParam());
1670 if (SUCCEEDED(hrc))
[45158]1671 {
1672 if (!pGuest)
1673 {
[93708]1674 RTMsgError(ControlVM::tr("Guest not running."));
[95140]1675 hrc = E_FAIL;
[45158]1676 break;
1677 }
1678 CHECK_ERROR(pGuest, COMSETTER(MemoryBalloonSize)(uVal));
1679 }
[4659]1680 }
[23801]1681 else if (!strcmp(a->argv[1], "teleport"))
[23667]1682 {
1683 Bstr bstrHostname;
[24874]1684 uint32_t uMaxDowntime = 250 /*ms*/;
1685 uint32_t uPort = UINT32_MAX;
[24969]1686 uint32_t cMsTimeout = 0;
[42445]1687 Utf8Str strPassword;
[23801]1688 static const RTGETOPTDEF s_aTeleportOptions[] =
[23667]1689 {
[30396]1690 { "--host", 'h', RTGETOPT_REQ_STRING }, /** @todo RTGETOPT_FLAG_MANDATORY */
1691 { "--maxdowntime", 'd', RTGETOPT_REQ_UINT32 },
[42445]1692 { "--port", 'P', RTGETOPT_REQ_UINT32 }, /** @todo RTGETOPT_FLAG_MANDATORY */
1693 { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
1694 { "--password", 'W', RTGETOPT_REQ_STRING },
[30396]1695 { "--timeout", 't', RTGETOPT_REQ_UINT32 },
1696 { "--detailed-progress", 'D', RTGETOPT_REQ_NOTHING }
[23667]1697 };
1698 RTGETOPTSTATE GetOptState;
[26517]1699 RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTeleportOptions, RT_ELEMENTS(s_aTeleportOptions), 2, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
[93708]1700 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_TELEPORT);
[23667]1701 int ch;
1702 RTGETOPTUNION Value;
[95140]1703 while ( SUCCEEDED(hrc)
[23667]1704 && (ch = RTGetOpt(&GetOptState, &Value)))
1705 {
1706 switch (ch)
1707 {
1708 case 'h': bstrHostname = Value.psz; break;
[24874]1709 case 'd': uMaxDowntime = Value.u32; break;
[30396]1710 case 'D': g_fDetailedProgress = true; break;
[42445]1711 case 'P': uPort = Value.u32; break;
1712 case 'p':
1713 {
1714 RTEXITCODE rcExit = readPasswordFile(Value.psz, &strPassword);
1715 if (rcExit != RTEXITCODE_SUCCESS)
[95140]1716 hrc = E_FAIL;
[42445]1717 break;
1718 }
1719 case 'W': strPassword = Value.psz; break;
[24969]1720 case 't': cMsTimeout = Value.u32; break;
[23667]1721 default:
[93708]1722 errorGetOpt(ch, &Value);
[95140]1723 hrc = E_FAIL;
[23667]1724 break;
1725 }
1726 }
[95140]1727 if (FAILED(hrc))
[23667]1728 break;
1729
1730 ComPtr<IProgress> progress;
[32718]1731 CHECK_ERROR_BREAK(console, Teleport(bstrHostname.raw(), uPort,
[42445]1732 Bstr(strPassword).raw(),
[32718]1733 uMaxDowntime,
1734 progress.asOutParam()));
[24969]1735
1736 if (cMsTimeout)
1737 {
[95140]1738 hrc = progress->COMSETTER(Timeout)(cMsTimeout);
1739 if (FAILED(hrc) && hrc != VBOX_E_INVALID_OBJECT_STATE)
[24969]1740 CHECK_ERROR_BREAK(progress, COMSETTER(Timeout)(cMsTimeout)); /* lazyness */
1741 }
1742
[95140]1743 hrc = showProgress(progress);
[93708]1744 CHECK_PROGRESS_ERROR(progress, (ControlVM::tr("Teleportation failed")));
[23667]1745 }
[36720]1746 else if (!strcmp(a->argv[1], "screenshotpng"))
1747 {
[93708]1748 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_SCREENSHOTPNG);
[36720]1749 if (a->argc <= 2 || a->argc > 4)
1750 {
[93708]1751 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[95140]1752 hrc = E_FAIL;
[36720]1753 break;
1754 }
1755 int vrc;
[46123]1756 uint32_t iScreen = 0;
[36720]1757 if (a->argc == 4)
1758 {
[46123]1759 vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &iScreen);
[36720]1760 if (vrc != VINF_SUCCESS)
1761 {
[93708]1762 errorSyntax(ControlVM::tr("Error parsing display number '%s'."), a->argv[3]);
[95140]1763 hrc = E_FAIL;
[36720]1764 break;
1765 }
1766 }
1767 ComPtr<IDisplay> pDisplay;
1768 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
[44239]1769 if (!pDisplay)
1770 {
[93708]1771 RTMsgError(ControlVM::tr("Guest not running."));
[95140]1772 hrc = E_FAIL;
[44239]1773 break;
1774 }
[36720]1775 ULONG width, height, bpp;
[47774]1776 LONG xOrigin, yOrigin;
[52978]1777 GuestMonitorStatus_T monitorStatus;
1778 CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(iScreen, &width, &height, &bpp, &xOrigin, &yOrigin, &monitorStatus));
[36720]1779 com::SafeArray<BYTE> saScreenshot;
[52200]1780 CHECK_ERROR_BREAK(pDisplay, TakeScreenShotToArray(iScreen, width, height, BitmapFormat_PNG, ComSafeArrayAsOutParam(saScreenshot)));
[36720]1781 RTFILE pngFile = NIL_RTFILE;
[41885]1782 vrc = RTFileOpen(&pngFile, a->argv[2], RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_TRUNCATE | RTFILE_O_DENY_ALL);
[36720]1783 if (RT_FAILURE(vrc))
1784 {
[93708]1785 RTMsgError(ControlVM::tr("Failed to create file '%s' (%Rrc)."), a->argv[2], vrc);
[95140]1786 hrc = E_FAIL;
[36720]1787 break;
1788 }
1789 vrc = RTFileWrite(pngFile, saScreenshot.raw(), saScreenshot.size(), NULL);
1790 if (RT_FAILURE(vrc))
1791 {
[93708]1792 RTMsgError(ControlVM::tr("Failed to write screenshot to file '%s' (%Rrc)."), a->argv[2], vrc);
[95140]1793 hrc = E_FAIL;
[36720]1794 }
1795 RTFileClose(pngFile);
1796 }
[75345]1797#ifdef VBOX_WITH_RECORDING
[79363]1798 else if ( !strcmp(a->argv[1], "recording")
1799 || !strcmp(a->argv[1], "videocap") /* legacy command */)
[46123]1800 {
[75251]1801 if (a->argc < 3)
[46523]1802 {
[93708]1803 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[95140]1804 hrc = E_FAIL;
[46523]1805 break;
1806 }
[75251]1807
[75361]1808 ComPtr<IRecordingSettings> recordingSettings;
[79363]1809 CHECK_ERROR_BREAK(sessionMachine, COMGETTER(RecordingSettings)(recordingSettings.asOutParam()));
[75251]1810
[75361]1811 SafeIfaceArray <IRecordingScreenSettings> saRecordingScreenScreens;
1812 CHECK_ERROR_BREAK(recordingSettings, COMGETTER(Screens)(ComSafeArrayAsOutParam(saRecordingScreenScreens)));
[75251]1813
[81964]1814 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
1815 CHECK_ERROR_BREAK(sessionMachine, COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam()));
1816
[75251]1817 /* Note: For now all screens have the same configuration. */
1818
1819 /*
1820 * Note: Commands starting with "vcp" are the deprecated versions and are
1821 * kept to ensure backwards compatibility.
1822 */
[93708]1823 bool fEnabled;
1824 if (RT_SUCCESS(parseBool(a->argv[2], &fEnabled)))
[46523]1825 {
[93708]1826 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING);
1827 CHECK_ERROR_RET(recordingSettings, COMSETTER(Enabled)(fEnabled), RTEXITCODE_FAILURE);
[46523]1828 }
[75251]1829 else if (!strcmp(a->argv[2], "screens"))
[46523]1830 {
[93708]1831 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_SCREENS);
[75251]1832 ULONG cMonitors = 64;
[81964]1833 CHECK_ERROR_BREAK(pGraphicsAdapter, COMGETTER(MonitorCount)(&cMonitors));
[75251]1834 com::SafeArray<BOOL> saScreens(cMonitors);
[93708]1835 if (a->argc != 4)
[75251]1836 {
[93708]1837 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[95140]1838 hrc = E_FAIL;
[93708]1839 break;
[75251]1840 }
[93708]1841 if (RT_FAILURE(parseScreens(a->argv[3], &saScreens)))
[75251]1842 {
[93708]1843 errorSyntax(ControlVM::tr("Error parsing list of screen IDs '%s'."), a->argv[3]);
[95140]1844 hrc = E_FAIL;
[93708]1845 break;
[75251]1846 }
1847
[75361]1848 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
1849 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(Enabled)(saScreens[i]));
[46123]1850 }
[75251]1851 else if (!strcmp(a->argv[2], "filename"))
[54400]1852 {
[93708]1853 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_FILENAME);
[75390]1854 if (a->argc != 4)
[75251]1855 {
[93708]1856 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[95140]1857 hrc = E_FAIL;
[75251]1858 break;
1859 }
[54400]1860
[75361]1861 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
[75926]1862 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(Filename)(Bstr(a->argv[3]).raw()));
[54400]1863 }
[75341]1864 else if ( !strcmp(a->argv[2], "videores")
1865 || !strcmp(a->argv[2], "videoresolution"))
[54400]1866 {
[93708]1867 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_VIDEORES);
[75251]1868 if (a->argc != 5)
1869 {
[93708]1870 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[95140]1871 hrc = E_FAIL;
[75251]1872 break;
1873 }
[54400]1874
[75390]1875 uint32_t uWidth;
1876 int vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uWidth);
[75251]1877 if (RT_FAILURE(vrc))
1878 {
[93708]1879 errorSyntax(ControlVM::tr("Error parsing video width '%s'."), a->argv[3]);
[95140]1880 hrc = E_FAIL;
[75251]1881 break;
1882 }
1883
[75390]1884 uint32_t uHeight;
1885 vrc = RTStrToUInt32Ex(a->argv[4], NULL, 0, &uHeight);
[75251]1886 if (RT_FAILURE(vrc))
1887 {
[93708]1888 errorSyntax(ControlVM::tr("Error parsing video height '%s'."), a->argv[4]);
[95140]1889 hrc = E_FAIL;
[75251]1890 break;
1891 }
1892
[75361]1893 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
[75251]1894 {
[75390]1895 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(VideoWidth)(uWidth));
1896 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(VideoHeight)(uHeight));
[75251]1897 }
[54400]1898 }
[75251]1899 else if (!strcmp(a->argv[2], "videorate"))
[54421]1900 {
[93708]1901 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_VIDEORATE);
[75251]1902 if (a->argc != 4)
1903 {
[93708]1904 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[95140]1905 hrc = E_FAIL;
[75251]1906 break;
1907 }
1908
[75390]1909 uint32_t uRate;
1910 int vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uRate);
[75251]1911 if (RT_FAILURE(vrc))
1912 {
[93708]1913 errorSyntax(ControlVM::tr("Error parsing video rate '%s'."), a->argv[3]);
[95140]1914 hrc = E_FAIL;
[75251]1915 break;
1916 }
1917
[75361]1918 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
[75390]1919 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(VideoRate)(uRate));
[54421]1920 }
[75251]1921 else if (!strcmp(a->argv[2], "videofps"))
[54421]1922 {
[93708]1923 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_VIDEOFPS);
[75251]1924 if (a->argc != 4)
1925 {
[93708]1926 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[95140]1927 hrc = E_FAIL;
[75251]1928 break;
1929 }
[54400]1930
[75390]1931 uint32_t uFPS;
1932 int vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uFPS);
[75251]1933 if (RT_FAILURE(vrc))
1934 {
[93708]1935 errorSyntax(ControlVM::tr("Error parsing video FPS '%s'."), a->argv[3]);
[95140]1936 hrc = E_FAIL;
[75251]1937 break;
1938 }
1939
[75361]1940 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
[75390]1941 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(VideoFPS)(uFPS));
[54400]1942 }
[75251]1943 else if (!strcmp(a->argv[2], "maxtime"))
[54400]1944 {
[93708]1945 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_MAXTIME);
[75251]1946 if (a->argc != 4)
1947 {
[93708]1948 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[95140]1949 hrc = E_FAIL;
[75251]1950 break;
1951 }
[54400]1952
[75390]1953 uint32_t uMaxTime;
1954 int vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uMaxTime);
[75251]1955 if (RT_FAILURE(vrc))
1956 {
[93708]1957 errorSyntax(ControlVM::tr("Error parsing maximum time '%s'."), a->argv[3]);
[95140]1958 hrc = E_FAIL;
[75251]1959 break;
1960 }
1961
[75361]1962 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
[75390]1963 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(MaxTime)(uMaxTime));
[54400]1964 }
[75251]1965 else if (!strcmp(a->argv[2], "maxfilesize"))
[54400]1966 {
[93708]1967 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_MAXFILESIZE);
[75251]1968 if (a->argc != 4)
1969 {
[93708]1970 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[95140]1971 hrc = E_FAIL;
[75251]1972 break;
1973 }
[54400]1974
[75390]1975 uint32_t uMaxFileSize;
1976 int vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uMaxFileSize);
[75251]1977 if (RT_FAILURE(vrc))
1978 {
[93708]1979 errorSyntax(ControlVM::tr("Error parsing maximum file size '%s'."), a->argv[3]);
[95140]1980 hrc = E_FAIL;
[75251]1981 break;
1982 }
1983
[75361]1984 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
[75390]1985 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(MaxFileSize)(uMaxFileSize));
[54400]1986 }
[75251]1987 else if (!strcmp(a->argv[2], "opts"))
[54400]1988 {
[93708]1989#if 0 /* Add when the corresponding documentation is enabled. */
1990 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_OPTS);
1991#endif
[75251]1992 if (a->argc != 4)
1993 {
[93708]1994 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[95140]1995 hrc = E_FAIL;
[75251]1996 break;
1997 }
[54400]1998
[75361]1999 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
2000 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(Options)(Bstr(a->argv[3]).raw()));
[54400]2001 }
2002 }
[75345]2003#endif /* VBOX_WITH_RECORDING */
[48406]2004 else if (!strcmp(a->argv[1], "webcam"))
2005 {
2006 if (a->argc < 3)
2007 {
[93708]2008 errorArgument(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]2009 hrc = E_FAIL;
[48406]2010 break;
2011 }
2012
2013 ComPtr<IEmulatedUSB> pEmulatedUSB;
2014 CHECK_ERROR_BREAK(console, COMGETTER(EmulatedUSB)(pEmulatedUSB.asOutParam()));
2015 if (!pEmulatedUSB)
2016 {
[93708]2017 RTMsgError(ControlVM::tr("Guest not running."));
[95140]2018 hrc = E_FAIL;
[48406]2019 break;
2020 }
2021
2022 if (!strcmp(a->argv[2], "attach"))
2023 {
[93708]2024 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_WEBCAM_ATTACH);
[48406]2025 Bstr path("");
2026 if (a->argc >= 4)
2027 path = a->argv[3];
2028 Bstr settings("");
2029 if (a->argc >= 5)
2030 settings = a->argv[4];
2031 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamAttach(path.raw(), settings.raw()));
2032 }
2033 else if (!strcmp(a->argv[2], "detach"))
2034 {
[93708]2035 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_WEBCAM_DETACH);
[48406]2036 Bstr path("");
2037 if (a->argc >= 4)
2038 path = a->argv[3];
2039 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamDetach(path.raw()));
2040 }
2041 else if (!strcmp(a->argv[2], "list"))
2042 {
[93708]2043 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_WEBCAM_LIST);
[48406]2044 com::SafeArray <BSTR> webcams;
2045 CHECK_ERROR_BREAK(pEmulatedUSB, COMGETTER(Webcams)(ComSafeArrayAsOutParam(webcams)));
2046 for (size_t i = 0; i < webcams.size(); ++i)
2047 {
2048 RTPrintf("%ls\n", webcams[i][0]? webcams[i]: Bstr("default").raw());
2049 }
2050 }
2051 else
2052 {
[93708]2053 errorArgument(ControlVM::tr("Invalid argument to '%s'."), a->argv[1]);
[95140]2054 hrc = E_FAIL;
[48406]2055 break;
2056 }
[54591]2057 }
2058 else if (!strcmp(a->argv[1], "addencpassword"))
2059 {
[93708]2060 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_ADDENCPASSWORD);
[54591]2061 if ( a->argc != 4
2062 && a->argc != 6)
2063 {
[93708]2064 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[54591]2065 break;
2066 }
[48538]2067
[58434]2068 BOOL fRemoveOnSuspend = FALSE;
2069 if (a->argc == 6)
[54591]2070 {
[58434]2071 if ( strcmp(a->argv[4], "--removeonsuspend")
2072 || ( strcmp(a->argv[5], "yes")
2073 && strcmp(a->argv[5], "no")))
2074 {
[93708]2075 errorSyntax(ControlVM::tr("Invalid parameters."));
[58434]2076 break;
2077 }
2078 if (!strcmp(a->argv[5], "yes"))
2079 fRemoveOnSuspend = TRUE;
[54591]2080 }
2081
2082 Bstr bstrPwId(a->argv[2]);
[55923]2083 Utf8Str strPassword;
2084
2085 if (!RTStrCmp(a->argv[3], "-"))
2086 {
2087 /* Get password from console. */
[93708]2088 RTEXITCODE rcExit = readPasswordFromConsole(&strPassword, ControlVM::tr("Enter password:"));
[55923]2089 if (rcExit == RTEXITCODE_FAILURE)
2090 break;
2091 }
2092 else
2093 {
2094 RTEXITCODE rcExit = readPasswordFile(a->argv[3], &strPassword);
2095 if (rcExit == RTEXITCODE_FAILURE)
2096 {
[93708]2097 RTMsgError(ControlVM::tr("Failed to read new password from file."));
[55923]2098 break;
2099 }
2100 }
2101
[94660]2102 CHECK_ERROR_BREAK(console, AddEncryptionPassword(bstrPwId.raw(), Bstr(strPassword).raw(), fRemoveOnSuspend));
[48406]2103 }
[54591]2104 else if (!strcmp(a->argv[1], "removeencpassword"))
2105 {
[93708]2106 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_REMOVEENCPASSWORD);
[54591]2107 if (a->argc != 3)
2108 {
[93708]2109 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
[54591]2110 break;
2111 }
2112 Bstr bstrPwId(a->argv[2]);
[94660]2113 CHECK_ERROR_BREAK(console, RemoveEncryptionPassword(bstrPwId.raw()));
[54591]2114 }
2115 else if (!strcmp(a->argv[1], "removeallencpasswords"))
2116 {
[93708]2117 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_REMOVEALLENCPASSWORDS);
[94660]2118 CHECK_ERROR_BREAK(console, ClearAllEncryptionPasswords());
[54591]2119 }
[70766]2120 else if (!strncmp(a->argv[1], "changeuartmode", 14))
2121 {
[93708]2122 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_CHANGEUARTMODE);
[70766]2123 unsigned n = parseNum(&a->argv[1][14], 4, "UART");
2124 if (!n)
2125 {
[95140]2126 hrc = E_FAIL;
[70766]2127 break;
2128 }
2129 if (a->argc < 3)
2130 {
[93708]2131 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
[95140]2132 hrc = E_FAIL;
[70766]2133 break;
2134 }
2135
2136 ComPtr<ISerialPort> uart;
2137
2138 CHECK_ERROR_BREAK(sessionMachine, GetSerialPort(n - 1, uart.asOutParam()));
2139 ASSERT(uart);
2140
2141 if (!RTStrICmp(a->argv[2], "disconnected"))
2142 {
2143 if (a->argc != 3)
2144 {
[93708]2145 errorSyntax(ControlVM::tr("Incorrect arguments to '%s'."), a->argv[1]);
[95140]2146 hrc = E_FAIL;
[70766]2147 break;
2148 }
2149 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_Disconnected));
2150 }
2151 else if ( !RTStrICmp(a->argv[2], "server")
2152 || !RTStrICmp(a->argv[2], "client")
2153 || !RTStrICmp(a->argv[2], "tcpserver")
2154 || !RTStrICmp(a->argv[2], "tcpclient")
2155 || !RTStrICmp(a->argv[2], "file"))
2156 {
2157 const char *pszMode = a->argv[2];
2158 if (a->argc != 4)
2159 {
[93708]2160 errorSyntax(ControlVM::tr("Incorrect arguments to '%s'."), a->argv[1]);
[95140]2161 hrc = E_FAIL;
[70766]2162 break;
2163 }
2164
2165 CHECK_ERROR(uart, COMSETTER(Path)(Bstr(a->argv[3]).raw()));
2166
2167 /*
2168 * Change to disconnected first to get changes in just a parameter causing
2169 * the correct changes later on.
2170 */
2171 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_Disconnected));
2172 if (!RTStrICmp(pszMode, "server"))
2173 {
2174 CHECK_ERROR(uart, COMSETTER(Server)(TRUE));
2175 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_HostPipe));
2176 }
2177 else if (!RTStrICmp(pszMode, "client"))
2178 {
2179 CHECK_ERROR(uart, COMSETTER(Server)(FALSE));
2180 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_HostPipe));
2181 }
2182 else if (!RTStrICmp(pszMode, "tcpserver"))
2183 {
2184 CHECK_ERROR(uart, COMSETTER(Server)(TRUE));
2185 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_TCP));
2186 }
2187 else if (!RTStrICmp(pszMode, "tcpclient"))
2188 {
2189 CHECK_ERROR(uart, COMSETTER(Server)(FALSE));
2190 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_TCP));
2191 }
2192 else if (!RTStrICmp(pszMode, "file"))
2193 {
2194 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_RawFile));
2195 }
2196 }
2197 else
2198 {
2199 if (a->argc != 3)
2200 {
[93708]2201 errorSyntax(ControlVM::tr("Incorrect arguments to '%s'."), a->argv[1]);
[95140]2202 hrc = E_FAIL;
[70766]2203 break;
2204 }
2205 CHECK_ERROR(uart, COMSETTER(Path)(Bstr(a->argv[2]).raw()));
2206 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_HostDevice));
2207 }
2208 }
[77910]2209 else if (!strncmp(a->argv[1], "vm-process-priority", 14))
2210 {
[93708]2211 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_VM_PROCESS_PRIORITY);
[77910]2212 if (a->argc != 3)
2213 {
[93708]2214 errorSyntax(ControlVM::tr("Incorrect arguments to '%s'."), a->argv[1]);
[95140]2215 hrc = E_FAIL;
[77910]2216 break;
2217 }
2218 VMProcPriority_T enmPriority = nameToVMProcPriority(a->argv[2]);
2219 if (enmPriority == VMProcPriority_Invalid)
2220 {
[93708]2221 errorSyntax(ControlVM::tr("Invalid vm-process-priority '%s'."), a->argv[2]);
[95140]2222 hrc = E_FAIL;
[77910]2223 }
2224 else
2225 {
2226 CHECK_ERROR(sessionMachine, COMSETTER(VMProcessPriority)(enmPriority));
2227 }
2228 break;
2229 }
[89597]2230 else if (!strncmp(a->argv[1], "autostart-enabled", 17))
2231 {
[93708]2232 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_AUTOSTART_ENABLED);
[89597]2233 if (a->argc != 3)
2234 {
[93708]2235 errorSyntax(ControlVM::tr("Incorrect arguments to '%s'."), a->argv[1]);
[95140]2236 hrc = E_FAIL;
[89597]2237 break;
2238 }
[93708]2239 bool fEnabled;
2240 if (RT_FAILURE(parseBool(a->argv[2], &fEnabled)))
[89597]2241 {
[93708]2242 errorSyntax(ControlVM::tr("Invalid value '%s'."), a->argv[2]);
[95140]2243 hrc = E_FAIL;
[89597]2244 break;
2245 }
[93708]2246 CHECK_ERROR(sessionMachine, COMSETTER(AutostartEnabled)(TRUE));
2247 fNeedsSaving = true;
[89597]2248 break;
2249 }
2250 else if (!strncmp(a->argv[1], "autostart-delay", 15))
2251 {
[93708]2252 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_AUTOSTART_DELAY);
[89597]2253 if (a->argc != 3)
2254 {
[93708]2255 errorSyntax(ControlVM::tr("Incorrect arguments to '%s'."), a->argv[1]);
[95140]2256 hrc = E_FAIL;
[89597]2257 break;
2258 }
2259 uint32_t u32;
2260 char *pszNext;
2261 int vrc = RTStrToUInt32Ex(a->argv[2], &pszNext, 10, &u32);
2262 if (RT_FAILURE(vrc) || *pszNext != '\0')
2263 {
[93708]2264 errorSyntax(ControlVM::tr("Invalid autostart delay number '%s'."), a->argv[2]);
[95140]2265 hrc = E_FAIL;
[89597]2266 break;
2267 }
2268 CHECK_ERROR(sessionMachine, COMSETTER(AutostartDelay)(u32));
[95140]2269 if (SUCCEEDED(hrc))
[89597]2270 fNeedsSaving = true;
2271 break;
2272 }
[1]2273 else
2274 {
[93708]2275 errorSyntax(ControlVM::tr("Invalid parameter '%s'."), a->argv[1]);
[95140]2276 hrc = E_FAIL;
[1]2277 }
[23934]2278 } while (0);
[1]2279
[54523]2280 /* The client has to trigger saving the state explicitely. */
2281 if (fNeedsSaving)
2282 CHECK_ERROR(sessionMachine, SaveSettings());
2283
[31070]2284 a->session->UnlockMachine();
[1]2285
[95140]2286 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
[1]2287}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use