VirtualBox

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

Last change on this file since 96588 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 88.8 KB
Line 
1/* $Id: VBoxManageControlVM.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * VBoxManage - Implementation of the controlvm command.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
8 *
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
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <VBox/com/com.h>
33#include <VBox/com/string.h>
34#include <VBox/com/Guid.h>
35#include <VBox/com/array.h>
36#include <VBox/com/ErrorInfo.h>
37#include <VBox/com/errorprint.h>
38#include <VBox/com/VirtualBox.h>
39
40#include <iprt/ctype.h>
41#include <iprt/getopt.h>
42#include <iprt/stream.h>
43#include <iprt/string.h>
44#include <iprt/thread.h>
45#include <iprt/uuid.h>
46#include <iprt/file.h>
47#include <VBox/log.h>
48
49#include "VBoxManage.h"
50#include "VBoxManageUtils.h"
51
52#include <list>
53
54DECLARE_TRANSLATION_CONTEXT(ControlVM);
55
56VMProcPriority_T nameToVMProcPriority(const char *pszName);
57
58/**
59 * Parses a number.
60 *
61 * @returns Valid number on success.
62 * @returns 0 if invalid number. All necessary bitching has been done.
63 * @param psz Pointer to the nic number.
64 */
65static unsigned parseNum(const char *psz, unsigned cMaxNum, const char *name)
66{
67 uint32_t u32;
68 char *pszNext;
69 int rc = RTStrToUInt32Ex(psz, &pszNext, 10, &u32);
70 if ( RT_SUCCESS(rc)
71 && *pszNext == '\0'
72 && u32 >= 1
73 && u32 <= cMaxNum)
74 return (unsigned)u32;
75 errorArgument(ControlVM::tr("Invalid %s number '%s'."), name, psz);
76 return 0;
77}
78
79#define KBDCHARDEF_MOD_NONE 0x00
80#define KBDCHARDEF_MOD_SHIFT 0x01
81
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},
99 /* 0x09 ' ' */ {0x0f, KBDCHARDEF_MOD_NONE},
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},
123 /* 0x21 '!' */ {0x02, KBDCHARDEF_MOD_SHIFT},
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
225 HRESULT hrc = S_OK;
226 size_t i;
227 for (i = 0; i < saScancodes.size(); ++i)
228 {
229 hrc = pKeyboard->PutScancode(saScancodes[i]);
230 if (FAILED(hrc))
231 {
232 RTMsgError(ControlVM::tr("Failed to send a scancode."));
233 break;
234 }
235
236 RTThreadSleep(10); /* "Typing" too fast causes lost characters. */
237 }
238
239 return hrc;
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 {
279 if (!llScancodes.empty())
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;
306 vrc = RTFileQuerySize(File, &cbFile);
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
333 RTMsgError(ControlVM::tr("Out of memory allocating %d bytes.", "", cbBuffer), cbBuffer);
334 }
335 else
336 RTMsgError(ControlVM::tr("File size %RI64 is greater than %RI64: '%s'."), cbFile, cbFileMax, pszFilename);
337 }
338 else
339 RTMsgError(ControlVM::tr("Cannot get size of file '%s': %Rrc."), pszFilename, vrc);
340
341 RTFileClose(File);
342 }
343 else
344 RTMsgError(ControlVM::tr("Cannot open file '%s': %Rrc."), pszFilename, vrc);
345
346 /* Release SHIFT if pressed. */
347 if (fShift)
348 llScancodes.push_back(0x2a | 0x80);
349
350 return keyboardPutScancodes(pKeyboard, llScancodes);
351}
352
353
354RTEXITCODE handleControlVM(HandlerArg *a)
355{
356 using namespace com;
357 bool fNeedsSaving = false;
358 HRESULT hrc;
359
360 if (a->argc < 2)
361 return errorSyntax(ControlVM::tr("Not enough parameters."));
362
363 /* try to find the given machine */
364 ComPtr<IMachine> machine;
365 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
366 machine.asOutParam()));
367 if (FAILED(hrc))
368 return RTEXITCODE_FAILURE;
369
370 /* open a session for the VM */
371 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE);
372
373 ComPtr<IConsole> console;
374 ComPtr<IMachine> sessionMachine;
375
376 do
377 {
378 /* get the associated console */
379 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
380 if (!console)
381 return RTMsgErrorExit(RTEXITCODE_FAILURE, ControlVM::tr("Machine '%s' is not currently running."), a->argv[0]);
382
383 /* ... and session machine */
384 CHECK_ERROR_BREAK(a->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
385
386 /* which command? */
387 if (!strcmp(a->argv[1], "pause"))
388 {
389 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_PAUSE);
390 CHECK_ERROR_BREAK(console, Pause());
391 }
392 else if (!strcmp(a->argv[1], "resume"))
393 {
394 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RESUME);
395 CHECK_ERROR_BREAK(console, Resume());
396 }
397 else if (!strcmp(a->argv[1], "reset"))
398 {
399 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RESET);
400 CHECK_ERROR_BREAK(console, Reset());
401 }
402 else if (!strcmp(a->argv[1], "unplugcpu"))
403 {
404 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_UNPLUGCPU);
405 if (a->argc <= 1 + 1)
406 {
407 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
408 hrc = E_FAIL;
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 {
418 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_PLUGCPU);
419 if (a->argc <= 1 + 1)
420 {
421 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
422 hrc = E_FAIL;
423 break;
424 }
425
426 unsigned n = parseNum(a->argv[2], 32, "CPU");
427
428 CHECK_ERROR_BREAK(sessionMachine, HotPlugCPU(n));
429 }
430 else if (!strcmp(a->argv[1], "cpuexecutioncap"))
431 {
432 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_CPUEXECUTIONCAP);
433 if (a->argc <= 1 + 1)
434 {
435 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
436 hrc = E_FAIL;
437 break;
438 }
439
440 unsigned n = parseNum(a->argv[2], 100, "ExecutionCap");
441
442 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(CPUExecutionCap)(n));
443 }
444 else if (!strcmp(a->argv[1], "audioin"))
445 {
446 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_AUDIOIN);
447
448 ComPtr<IAudioSettings> audioSettings;
449 CHECK_ERROR_BREAK(sessionMachine, COMGETTER(AudioSettings)(audioSettings.asOutParam()));
450 ComPtr<IAudioAdapter> adapter;
451 CHECK_ERROR_BREAK(audioSettings, COMGETTER(Adapter)(adapter.asOutParam()));
452 if (adapter)
453 {
454 bool fEnabled;
455 if (RT_FAILURE(parseBool(a->argv[2], &fEnabled)))
456 {
457 errorSyntax(ControlVM::tr("Invalid value '%s'."), a->argv[2]);
458 hrc = E_FAIL;
459 break;
460 }
461 CHECK_ERROR_RET(adapter, COMSETTER(EnabledIn)(fEnabled), RTEXITCODE_FAILURE);
462 fNeedsSaving = true;
463 }
464 else
465 {
466 errorSyntax(ControlVM::tr("Audio adapter not enabled in VM configuration."));
467 hrc = E_FAIL;
468 break;
469 }
470 }
471 else if (!strcmp(a->argv[1], "audioout"))
472 {
473 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_AUDIOOUT);
474
475 ComPtr<IAudioSettings> audioSettings;
476 CHECK_ERROR_BREAK(sessionMachine, COMGETTER(AudioSettings)(audioSettings.asOutParam()));
477 ComPtr<IAudioAdapter> adapter;
478 CHECK_ERROR_BREAK(audioSettings, COMGETTER(Adapter)(adapter.asOutParam()));
479 if (adapter)
480 {
481 bool fEnabled;
482 if (RT_FAILURE(parseBool(a->argv[2], &fEnabled)))
483 {
484 errorSyntax(ControlVM::tr("Invalid value '%s'."), a->argv[2]);
485 hrc = E_FAIL;
486 break;
487 }
488 CHECK_ERROR_RET(adapter, COMSETTER(EnabledOut)(fEnabled), RTEXITCODE_FAILURE);
489 fNeedsSaving = true;
490 }
491 else
492 {
493 errorSyntax(ControlVM::tr("Audio adapter not enabled in VM configuration."));
494 hrc = E_FAIL;
495 break;
496 }
497 }
498#ifdef VBOX_WITH_SHARED_CLIPBOARD
499 else if (!strcmp(a->argv[1], "clipboard"))
500 {
501 if (a->argc <= 1 + 1)
502 {
503 errorArgument(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
504 hrc = E_FAIL;
505 break;
506 }
507
508 ClipboardMode_T mode = ClipboardMode_Disabled; /* Shut up MSC */
509 if (!strcmp(a->argv[2], "mode"))
510 {
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]);
515 hrc = E_FAIL;
516 break;
517 }
518
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 {
529 errorSyntax(ControlVM::tr("Invalid '%s %s' argument '%s'."), a->argv[1], a->argv[2], a->argv[3]);
530 hrc = E_FAIL;
531 break;
532 }
533
534 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(ClipboardMode)(mode));
535 if (SUCCEEDED(hrc))
536 fNeedsSaving = true;
537 }
538# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
539 else if (!strcmp(a->argv[2], "filetransfers"))
540 {
541 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_CLIPBOARD_FILETRANSFERS);
542 if (a->argc <= 1 + 2)
543 {
544 errorSyntax(ControlVM::tr("Missing argument to '%s %s'."), a->argv[1], a->argv[2]);
545 hrc = E_FAIL;
546 break;
547 }
548
549 bool fEnabled;
550 if (RT_FAILURE(parseBool(a->argv[3], &fEnabled)))
551 {
552 errorSyntax(ControlVM::tr("Invalid '%s %s' argument '%s'."), a->argv[1], a->argv[2], a->argv[3]);
553 hrc = E_FAIL;
554 break;
555 }
556
557 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(ClipboardFileTransfersEnabled)(fEnabled));
558 fNeedsSaving = true;
559 }
560# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
561 else
562 {
563 errorArgument(ControlVM::tr("Invalid '%s' argument '%s'."), a->argv[1], a->argv[2]);
564 hrc = E_FAIL;
565 break;
566 }
567 }
568#endif /* VBOX_WITH_SHARED_CLIPBOARD */
569 else if (!strcmp(a->argv[1], "draganddrop"))
570 {
571 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_DRAGANDDROP);
572 if (a->argc <= 1 + 1)
573 {
574 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
575 hrc = E_FAIL;
576 break;
577 }
578
579 DnDMode_T mode = DnDMode_Disabled; /* Shup up MSC. */
580 if (!strcmp(a->argv[2], "disabled"))
581 mode = DnDMode_Disabled;
582 else if (!strcmp(a->argv[2], "hosttoguest"))
583 mode = DnDMode_HostToGuest;
584 else if (!strcmp(a->argv[2], "guesttohost"))
585 mode = DnDMode_GuestToHost;
586 else if (!strcmp(a->argv[2], "bidirectional"))
587 mode = DnDMode_Bidirectional;
588 else
589 {
590 errorSyntax(ControlVM::tr("Invalid '%s' argument '%s'."), a->argv[1], a->argv[2]);
591 hrc = E_FAIL;
592 }
593 if (SUCCEEDED(hrc))
594 {
595 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(DnDMode)(mode));
596 if (SUCCEEDED(hrc))
597 fNeedsSaving = true;
598 }
599 }
600 else if (!strcmp(a->argv[1], "poweroff"))
601 {
602 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_POWEROFF);
603 ComPtr<IProgress> progress;
604 CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam()));
605
606 hrc = showProgress(progress);
607 CHECK_PROGRESS_ERROR(progress, (ControlVM::tr("Failed to power off machine.")));
608 }
609 else if (!strcmp(a->argv[1], "savestate"))
610 {
611 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_SAVESTATE);
612 /* first pause so we don't trigger a live save which needs more time/resources */
613 bool fPaused = false;
614 hrc = console->Pause();
615 if (FAILED(hrc))
616 {
617 bool fError = true;
618 if (hrc == VBOX_E_INVALID_VM_STATE)
619 {
620 /* check if we are already paused */
621 MachineState_T machineState;
622 CHECK_ERROR_BREAK(console, COMGETTER(State)(&machineState));
623 /* the error code was lost by the previous instruction */
624 hrc = VBOX_E_INVALID_VM_STATE;
625 if (machineState != MachineState_Paused)
626 {
627 RTMsgError(ControlVM::tr("Machine in invalid state %d -- %s."),
628 machineState, machineStateToName(machineState, false));
629 }
630 else
631 {
632 fError = false;
633 fPaused = true;
634 }
635 }
636 if (fError)
637 break;
638 }
639
640 ComPtr<IProgress> progress;
641 CHECK_ERROR(sessionMachine, SaveState(progress.asOutParam()));
642 if (FAILED(hrc))
643 {
644 if (!fPaused)
645 console->Resume();
646 break;
647 }
648
649 hrc = showProgress(progress);
650 CHECK_PROGRESS_ERROR(progress, (ControlVM::tr("Failed to save machine state.")));
651 if (FAILED(hrc))
652 {
653 if (!fPaused)
654 console->Resume();
655 }
656 }
657 else if (!strcmp(a->argv[1], "acpipowerbutton"))
658 {
659 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_ACPIPOWERBUTTON);
660 CHECK_ERROR_BREAK(console, PowerButton());
661 }
662 else if (!strcmp(a->argv[1], "acpisleepbutton"))
663 {
664 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_ACPISLEEPBUTTON);
665 CHECK_ERROR_BREAK(console, SleepButton());
666 }
667#ifdef VBOX_WITH_GUEST_CONTROL
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 {
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
677 ComPtr<IGuest> pGuest;
678 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest.asOutParam()));
679 if (!pGuest)
680 {
681 RTMsgError(ControlVM::tr("Guest not running."));
682 hrc = E_FAIL;
683 break;
684 }
685
686 com::SafeArray<GuestShutdownFlag_T> aShutdownFlags;
687 if (fReboot)
688 aShutdownFlags.push_back(GuestShutdownFlag_Reboot);
689 else
690 aShutdownFlags.push_back(GuestShutdownFlag_PowerOff);
691
692 if ( a->argc >= 3
693 && !strcmp(a->argv[2], "--force"))
694 aShutdownFlags.push_back(GuestShutdownFlag_Force);
695
696 CHECK_ERROR(pGuest, Shutdown(ComSafeArrayAsInParam(aShutdownFlags)));
697 if (FAILED(hrc))
698 {
699 if (hrc == VBOX_E_NOT_SUPPORTED)
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 }
706 }
707 }
708#endif
709 else if (!strcmp(a->argv[1], "keyboardputscancode"))
710 {
711 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_KEYBOARDPUTSCANCODE);
712 ComPtr<IKeyboard> pKeyboard;
713 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
714 if (!pKeyboard)
715 {
716 RTMsgError(ControlVM::tr("Guest not running."));
717 hrc = E_FAIL;
718 break;
719 }
720
721 if (a->argc <= 1 + 1)
722 {
723 errorSyntax(ControlVM::tr("Missing argument to '%s'. Expected IBM PC AT set 2 keyboard scancode(s)."),
724 a->argv[1]);
725 hrc = E_FAIL;
726 break;
727 }
728
729 std::list<LONG> llScancodes;
730
731 /* Process the command line. */
732 int i;
733 for (i = 1 + 1; i < a->argc; i++)
734 {
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)
738 {
739 uint8_t u8Scancode;
740 int vrc = RTStrToUInt8Ex(a->argv[i], NULL, 16, &u8Scancode);
741 if (RT_FAILURE (vrc))
742 {
743 RTMsgError(ControlVM::tr("Converting '%s' returned %Rrc!"), a->argv[i], vrc);
744 hrc = E_FAIL;
745 break;
746 }
747
748 llScancodes.push_back(u8Scancode);
749 }
750 else
751 {
752 RTMsgError(ControlVM::tr("'%s' is not a hex byte!"), a->argv[i]);
753 hrc = E_FAIL;
754 break;
755 }
756 }
757
758 if (FAILED(hrc))
759 break;
760
761 hrc = keyboardPutScancodes(pKeyboard, llScancodes);
762 }
763 else if (!strcmp(a->argv[1], "keyboardputstring"))
764 {
765 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_KEYBOARDPUTSTRING);
766 ComPtr<IKeyboard> pKeyboard;
767 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
768 if (!pKeyboard)
769 {
770 RTMsgError(ControlVM::tr("Guest not running."));
771 hrc = E_FAIL;
772 break;
773 }
774
775 if (a->argc <= 1 + 1)
776 {
777 errorSyntax(ControlVM::tr("Missing argument to '%s'. Expected ASCII string(s)."), a->argv[1]);
778 hrc = E_FAIL;
779 break;
780 }
781
782 hrc = keyboardPutString(pKeyboard, a->argc, a->argv);
783 }
784 else if (!strcmp(a->argv[1], "keyboardputfile"))
785 {
786 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_KEYBOARDPUTFILE);
787 ComPtr<IKeyboard> pKeyboard;
788 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
789 if (!pKeyboard)
790 {
791 RTMsgError(ControlVM::tr("Guest not running."));
792 hrc = E_FAIL;
793 break;
794 }
795
796 if (a->argc <= 1 + 1)
797 {
798 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
799 hrc = E_FAIL;
800 break;
801 }
802
803 hrc = keyboardPutFile(pKeyboard, a->argv[2]);
804 }
805 else if (!strncmp(a->argv[1], "setlinkstate", 12))
806 {
807 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_SETLINKSTATE);
808 /* Get the number of network adapters */
809 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
810 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
811 if (!n)
812 {
813 hrc = E_FAIL;
814 break;
815 }
816 if (a->argc <= 1 + 1)
817 {
818 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
819 hrc = E_FAIL;
820 break;
821 }
822 /* get the corresponding network adapter */
823 ComPtr<INetworkAdapter> adapter;
824 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
825 if (adapter)
826 {
827 bool fEnabled;
828 if (RT_FAILURE(parseBool(a->argv[3], &fEnabled)))
829 {
830 errorSyntax(ControlVM::tr("Invalid link state '%s'."), a->argv[2]);
831 hrc = E_FAIL;
832 break;
833 }
834 CHECK_ERROR_BREAK(adapter, COMSETTER(CableConnected)(fEnabled));
835 fNeedsSaving = true;
836 }
837 }
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 {
845 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_NICTRACEFILE);
846 /* Get the number of network adapters */
847 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
848 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
849 if (!n)
850 {
851 hrc = E_FAIL;
852 break;
853 }
854 if (a->argc <= 2)
855 {
856 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
857 hrc = E_FAIL;
858 break;
859 }
860
861 /* get the corresponding network adapter */
862 ComPtr<INetworkAdapter> adapter;
863 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
864 if (adapter)
865 {
866 BOOL fEnabled;
867 adapter->COMGETTER(Enabled)(&fEnabled);
868 if (fEnabled)
869 {
870 if (a->argv[2])
871 {
872 CHECK_ERROR_RET(adapter, COMSETTER(TraceFile)(Bstr(a->argv[2]).raw()), RTEXITCODE_FAILURE);
873 }
874 else
875 {
876 errorSyntax(ControlVM::tr("Filename not specified for NIC %lu."), n);
877 hrc = E_FAIL;
878 break;
879 }
880 if (SUCCEEDED(hrc))
881 fNeedsSaving = true;
882 }
883 else
884 RTMsgError(ControlVM::tr("The NIC %d is currently disabled and thus its tracefile can't be changed."), n);
885 }
886 }
887 else if (!strncmp(a->argv[1], "nictrace", 8))
888 {
889 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_NICTRACE);
890 /* Get the number of network adapters */
891 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
892 unsigned n = parseNum(&a->argv[1][8], NetworkAdapterCount, "NIC");
893 if (!n)
894 {
895 hrc = E_FAIL;
896 break;
897 }
898 if (a->argc <= 2)
899 {
900 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
901 hrc = E_FAIL;
902 break;
903 }
904
905 /* get the corresponding network adapter */
906 ComPtr<INetworkAdapter> adapter;
907 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
908 if (adapter)
909 {
910 BOOL fEnabled;
911 adapter->COMGETTER(Enabled)(&fEnabled);
912 if (fEnabled)
913 {
914 bool fTraceEnabled;
915 if (RT_FAILURE(parseBool(a->argv[3], &fTraceEnabled)))
916 {
917 errorSyntax(ControlVM::tr("Invalid nictrace%lu argument '%s'."), n, a->argv[2]);
918 hrc = E_FAIL;
919 break;
920 }
921 CHECK_ERROR_RET(adapter, COMSETTER(TraceEnabled)(fTraceEnabled), RTEXITCODE_FAILURE);
922 fNeedsSaving = true;
923 }
924 else
925 RTMsgError(ControlVM::tr("The NIC %d is currently disabled and thus its trace flag can't be changed."), n);
926 }
927 }
928 else if( a->argc > 2
929 && !strncmp(a->argv[1], "natpf", 5))
930 {
931 /* Get the number of network adapters */
932 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
933 unsigned n = parseNum(&a->argv[1][5], NetworkAdapterCount, "NIC");
934 if (!n)
935 {
936 hrc = E_FAIL;
937 break;
938 }
939 if (a->argc <= 2)
940 {
941 errorArgument(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
942 hrc = E_FAIL;
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 {
951 hrc = E_FAIL;
952 break;
953 }
954 ComPtr<INATEngine> engine;
955 CHECK_ERROR(adapter, COMGETTER(NATEngine)(engine.asOutParam()));
956 if (!engine)
957 {
958 hrc = E_FAIL;
959 break;
960 }
961
962 if (!strcmp(a->argv[2], "delete"))
963 {
964 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_NATPF_DELETE);
965 if (a->argc >= 3)
966 CHECK_ERROR(engine, RemoveRedirect(Bstr(a->argv[3]).raw()));
967 }
968 else
969 {
970 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_NATPF);
971#define ITERATE_TO_NEXT_TERM(ch) \
972 do { \
973 while (*ch != ',') \
974 { \
975 if (*ch == 0) \
976 { \
977 return errorSyntax(ControlVM::tr("Missing or invalid argument to '%s'."), \
978 a->argv[1]); \
979 } \
980 ch++; \
981 } \
982 *ch = '\0'; \
983 ch++; \
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;
1010 else
1011 {
1012 return errorSyntax(ControlVM::tr("Wrong rule proto '%s' specified -- only 'udp' and 'tcp' are allowed."),
1013 strProto);
1014 }
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 }
1019 if (SUCCEEDED(hrc))
1020 fNeedsSaving = true;
1021 }
1022 else if (!strncmp(a->argv[1], "nicproperty", 11))
1023 {
1024 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_NICPROPERTY);
1025 /* Get the number of network adapters */
1026 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
1027 unsigned n = parseNum(&a->argv[1][11], NetworkAdapterCount, "NIC");
1028 if (!n)
1029 {
1030 hrc = E_FAIL;
1031 break;
1032 }
1033 if (a->argc <= 2)
1034 {
1035 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
1036 hrc = E_FAIL;
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()));
1061 if (SUCCEEDED(hrc))
1062 fNeedsSaving = true;
1063 }
1064 else
1065 {
1066 errorSyntax(ControlVM::tr("Invalid nicproperty%d argument '%s'."), n, a->argv[2]);
1067 hrc = E_FAIL;
1068 }
1069 RTStrFree(pszProperty);
1070 }
1071 else
1072 {
1073 RTMsgError(ControlVM::tr("Failed to allocate memory for nicproperty%d '%s'."),
1074 n, a->argv[2]);
1075 hrc = E_FAIL;
1076 }
1077 if (FAILED(hrc))
1078 break;
1079 }
1080 else
1081 RTMsgError(ControlVM::tr("The NIC %d is currently disabled and thus its properties can't be changed."), n);
1082 }
1083 }
1084 else if (!strncmp(a->argv[1], "nicpromisc", 10))
1085 {
1086 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_NICPROMISC);
1087 /* Get the number of network adapters */
1088 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
1089 unsigned n = parseNum(&a->argv[1][10], NetworkAdapterCount, "NIC");
1090 if (!n)
1091 {
1092 hrc = E_FAIL;
1093 break;
1094 }
1095 if (a->argc <= 2)
1096 {
1097 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
1098 hrc = E_FAIL;
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 {
1121 errorSyntax(ControlVM::tr("Unknown promiscuous mode policy '%s'."), a->argv[2]);
1122 hrc = E_INVALIDARG;
1123 break;
1124 }
1125
1126 CHECK_ERROR(adapter, COMSETTER(PromiscModePolicy)(enmPromiscModePolicy));
1127 if (SUCCEEDED(hrc))
1128 fNeedsSaving = true;
1129 }
1130 else
1131 RTMsgError(ControlVM::tr("The NIC %d is currently disabled and thus its promiscuous mode can't be changed."), n);
1132 }
1133 }
1134 else if (!strncmp(a->argv[1], "nic", 3))
1135 {
1136 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_NIC);
1137 /* Get the number of network adapters */
1138 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
1139 unsigned n = parseNum(&a->argv[1][3], NetworkAdapterCount, "NIC");
1140 if (!n)
1141 {
1142 hrc = E_FAIL;
1143 break;
1144 }
1145 if (a->argc <= 2)
1146 {
1147 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
1148 hrc = E_FAIL;
1149 break;
1150 }
1151
1152 /* get the corresponding network adapter */
1153 ComPtr<INetworkAdapter> adapter;
1154 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
1155 if (adapter)
1156 {
1157 BOOL fEnabled;
1158 adapter->COMGETTER(Enabled)(&fEnabled);
1159 if (fEnabled)
1160 {
1161 if (!strcmp(a->argv[2], "null"))
1162 {
1163 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Null), RTEXITCODE_FAILURE);
1164 }
1165 else if (!strcmp(a->argv[2], "nat"))
1166 {
1167 if (a->argc == 4)
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);
1170 }
1171 else if ( !strcmp(a->argv[2], "bridged")
1172 || !strcmp(a->argv[2], "hostif")) /* backward compatibility */
1173 {
1174 if (a->argc <= 3)
1175 {
1176 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[2]);
1177 hrc = E_FAIL;
1178 break;
1179 }
1180 CHECK_ERROR_RET(adapter, COMSETTER(BridgedInterface)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1181 verifyHostNetworkInterfaceName(a->virtualBox, a->argv[3], HostNetworkInterfaceType_Bridged);
1182 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Bridged), RTEXITCODE_FAILURE);
1183 }
1184 else if (!strcmp(a->argv[2], "intnet"))
1185 {
1186 if (a->argc <= 3)
1187 {
1188 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[2]);
1189 hrc = E_FAIL;
1190 break;
1191 }
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);
1194 }
1195#if defined(VBOX_WITH_NETFLT)
1196 else if (!strcmp(a->argv[2], "hostonly"))
1197 {
1198 if (a->argc <= 3)
1199 {
1200 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[2]);
1201 hrc = E_FAIL;
1202 break;
1203 }
1204 CHECK_ERROR_RET(adapter, COMSETTER(HostOnlyInterface)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1205 verifyHostNetworkInterfaceName(a->virtualBox, a->argv[3], HostNetworkInterfaceType_HostOnly);
1206 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_HostOnly), RTEXITCODE_FAILURE);
1207 }
1208#endif
1209 else if (!strcmp(a->argv[2], "generic"))
1210 {
1211 if (a->argc <= 3)
1212 {
1213 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[2]);
1214 hrc = E_FAIL;
1215 break;
1216 }
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);
1219 }
1220 else if (!strcmp(a->argv[2], "natnetwork"))
1221 {
1222 if (a->argc <= 3)
1223 {
1224 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[2]);
1225 hrc = E_FAIL;
1226 break;
1227 }
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);
1230 }
1231 else
1232 {
1233 errorSyntax(ControlVM::tr("Invalid type '%s' specfied for NIC %lu."), a->argv[2], n);
1234 hrc = E_FAIL;
1235 break;
1236 }
1237 if (SUCCEEDED(hrc))
1238 fNeedsSaving = true;
1239 }
1240 else
1241 RTMsgError(ControlVM::tr("The NIC %d is currently disabled and thus its attachment type can't be changed."), n);
1242 }
1243 }
1244 else if ( !strcmp(a->argv[1], "vrde")
1245 || !strcmp(a->argv[1], "vrdp"))
1246 {
1247 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_VRDE);
1248 if (!strcmp(a->argv[1], "vrdp"))
1249 RTMsgWarning(ControlVM::tr("'vrdp' is deprecated. Use 'vrde'."));
1250
1251 if (a->argc <= 1 + 1)
1252 {
1253 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
1254 hrc = E_FAIL;
1255 break;
1256 }
1257 ComPtr<IVRDEServer> vrdeServer;
1258 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1259 ASSERT(vrdeServer);
1260 if (vrdeServer)
1261 {
1262 bool fEnabled;
1263 if (RT_FAILURE(parseBool(a->argv[2], &fEnabled)))
1264 {
1265 errorSyntax(ControlVM::tr("Invalid remote desktop server state '%s'."), a->argv[2]);
1266 hrc = E_FAIL;
1267 break;
1268 }
1269 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(fEnabled));
1270 fNeedsSaving = true;
1271 }
1272 }
1273 else if ( !strcmp(a->argv[1], "vrdeport")
1274 || !strcmp(a->argv[1], "vrdpport"))
1275 {
1276 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_VRDEPORT);
1277 if (!strcmp(a->argv[1], "vrdpport"))
1278 RTMsgWarning(ControlVM::tr("'vrdpport' is deprecated. Use 'vrdeport'."));
1279
1280 if (a->argc <= 1 + 1)
1281 {
1282 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
1283 hrc = E_FAIL;
1284 break;
1285 }
1286
1287 ComPtr<IVRDEServer> vrdeServer;
1288 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1289 ASSERT(vrdeServer);
1290 if (vrdeServer)
1291 {
1292 Bstr ports;
1293
1294 if (!strcmp(a->argv[2], "default"))
1295 ports = "0";
1296 else
1297 ports = a->argv[2];
1298
1299 CHECK_ERROR_BREAK(vrdeServer, SetVRDEProperty(Bstr("TCP/Ports").raw(), ports.raw()));
1300 if (SUCCEEDED(hrc))
1301 fNeedsSaving = true;
1302 }
1303 }
1304 else if ( !strcmp(a->argv[1], "vrdevideochannelquality")
1305 || !strcmp(a->argv[1], "vrdpvideochannelquality"))
1306 {
1307 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_VRDEVIDEOCHANNELQUALITY);
1308 if (!strcmp(a->argv[1], "vrdpvideochannelquality"))
1309 RTMsgWarning(ControlVM::tr("'vrdpvideochannelquality' is deprecated. Use 'vrdevideochannelquality'."));
1310
1311 if (a->argc <= 1 + 1)
1312 {
1313 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
1314 hrc = E_FAIL;
1315 break;
1316 }
1317 ComPtr<IVRDEServer> vrdeServer;
1318 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1319 ASSERT(vrdeServer);
1320 if (vrdeServer)
1321 {
1322 Bstr value = a->argv[2];
1323
1324 CHECK_ERROR(vrdeServer, SetVRDEProperty(Bstr("VideoChannel/Quality").raw(), value.raw()));
1325 if (SUCCEEDED(hrc))
1326 fNeedsSaving = true;
1327 }
1328 }
1329 else if (!strcmp(a->argv[1], "vrdeproperty"))
1330 {
1331 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_VRDEPROPERTY);
1332 if (a->argc <= 1 + 1)
1333 {
1334 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
1335 hrc = E_FAIL;
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()));
1355 if (SUCCEEDED(hrc))
1356 fNeedsSaving = true;
1357 }
1358 else
1359 {
1360 errorSyntax(ControlVM::tr("Invalid vrdeproperty argument '%s'."), a->argv[2]);
1361 hrc = E_FAIL;
1362 }
1363 RTStrFree(pszProperty);
1364 }
1365 else
1366 {
1367 RTMsgError(ControlVM::tr("Failed to allocate memory for VRDE property '%s'."),
1368 a->argv[2]);
1369 hrc = E_FAIL;
1370 }
1371 }
1372 if (FAILED(hrc))
1373 {
1374 break;
1375 }
1376 }
1377 else if ( !strcmp(a->argv[1], "usbattach")
1378 || !strcmp(a->argv[1], "usbdetach"))
1379 {
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
1386 if (a->argc < 3)
1387 {
1388 errorSyntax(ControlVM::tr("Not enough parameters."));
1389 hrc = E_FAIL;
1390 break;
1391 }
1392 else if (a->argc == 4 || a->argc > 5)
1393 {
1394 errorSyntax(ControlVM::tr("Wrong number of arguments."));
1395 hrc = E_FAIL;
1396 break;
1397 }
1398
1399 Bstr usbId = a->argv[2];
1400 Bstr captureFilename;
1401
1402 if (a->argc == 5)
1403 {
1404 if (!strcmp(a->argv[3], "--capturefile"))
1405 captureFilename = a->argv[4];
1406 else
1407 {
1408 errorSyntax(ControlVM::tr("Invalid parameter '%s'."), a->argv[3]);
1409 hrc = E_FAIL;
1410 break;
1411 }
1412 }
1413
1414 Guid guid(usbId);
1415 if (!guid.isValid())
1416 {
1417 // assume address
1418 if (attach)
1419 {
1420 ComPtr<IHost> host;
1421 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1422 SafeIfaceArray <IHostUSBDevice> coll;
1423 CHECK_ERROR_BREAK(host, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
1424 ComPtr<IHostUSBDevice> dev;
1425 CHECK_ERROR_BREAK(host, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
1426 dev.asOutParam()));
1427 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
1428 }
1429 else
1430 {
1431 SafeIfaceArray <IUSBDevice> coll;
1432 CHECK_ERROR_BREAK(console, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
1433 ComPtr<IUSBDevice> dev;
1434 CHECK_ERROR_BREAK(console, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
1435 dev.asOutParam()));
1436 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
1437 }
1438 }
1439 else if (guid.isZero())
1440 {
1441 errorSyntax(ControlVM::tr("Zero UUID argument '%s'."), a->argv[2]);
1442 hrc = E_FAIL;
1443 break;
1444 }
1445
1446 if (attach)
1447 CHECK_ERROR_BREAK(console, AttachUSBDevice(usbId.raw(), captureFilename.raw()));
1448 else
1449 {
1450 ComPtr<IUSBDevice> dev;
1451 CHECK_ERROR_BREAK(console, DetachUSBDevice(usbId.raw(),
1452 dev.asOutParam()));
1453 }
1454 }
1455 else if (!strcmp(a->argv[1], "setvideomodehint"))
1456 {
1457 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_SETVIDEOMODEHINT);
1458 if (a->argc != 5 && a->argc != 6 && a->argc != 7 && a->argc != 9)
1459 {
1460 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
1461 hrc = E_FAIL;
1462 break;
1463 }
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 {
1476 if (RT_FAILURE(parseBool(a->argv[6], &fEnabled)))
1477 {
1478 errorSyntax(ControlVM::tr("Either \"yes\" or \"no\" is expected."));
1479 hrc = E_FAIL;
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 }
1489
1490 ComPtr<IDisplay> pDisplay;
1491 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1492 if (!pDisplay)
1493 {
1494 RTMsgError(ControlVM::tr("Guest not running."));
1495 hrc = E_FAIL;
1496 break;
1497 }
1498 CHECK_ERROR_BREAK(pDisplay, SetVideoModeHint(uDisplayIdx, fEnabled,
1499 fChangeOrigin, iOriginX, iOriginY,
1500 uXRes, uYRes, uBpp, true));
1501 }
1502 else if (!strcmp(a->argv[1], "setscreenlayout"))
1503 {
1504 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_SETSCREENLAYOUT);
1505 if (a->argc < 4)
1506 {
1507 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
1508 hrc = E_FAIL;
1509 break;
1510 }
1511
1512 ComPtr<IDisplay> pDisplay;
1513 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1514 if (!pDisplay)
1515 {
1516 RTMsgError(ControlVM::tr("Guest not running."));
1517 hrc = E_FAIL;
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 {
1543 errorSyntax(ControlVM::tr("Display status must be <on> or <off>."));
1544 hrc = E_FAIL;
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;
1554 if (aStatus == GuestMonitorStatus_Enabled)
1555 {
1556 if (argc < 7)
1557 {
1558 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
1559 hrc = E_FAIL;
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
1586 if (FAILED(hrc))
1587 break;
1588
1589 CHECK_ERROR_BREAK(pDisplay, SetScreenLayout(ScreenLayoutMode_Apply, ComSafeArrayAsInParam(aGuestScreenInfos)));
1590 }
1591 else if (!strcmp(a->argv[1], "setcredentials"))
1592 {
1593 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_SETCREDENTIALS);
1594 bool fAllowLocalLogon = true;
1595 if ( a->argc == 7
1596 || ( a->argc == 8
1597 && ( !strcmp(a->argv[3], "-p")
1598 || !strcmp(a->argv[3], "--passwordfile"))))
1599 {
1600 if ( strcmp(a->argv[5 + (a->argc - 7)], "--allowlocallogon")
1601 && strcmp(a->argv[5 + (a->argc - 7)], "-allowlocallogon"))
1602 {
1603 errorSyntax(ControlVM::tr("Invalid parameter '%s'."), a->argv[5]);
1604 hrc = E_FAIL;
1605 break;
1606 }
1607 if (!strcmp(a->argv[6 + (a->argc - 7)], "no"))
1608 fAllowLocalLogon = false;
1609 }
1610 else if ( a->argc != 5
1611 && ( a->argc != 6
1612 || ( strcmp(a->argv[3], "-p")
1613 && strcmp(a->argv[3], "--passwordfile"))))
1614 {
1615 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
1616 hrc = E_FAIL;
1617 break;
1618 }
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 {
1630 hrc = E_FAIL;
1631 break;
1632 }
1633 domain = a->argv[5];
1634 }
1635
1636 ComPtr<IGuest> pGuest;
1637 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest.asOutParam()));
1638 if (!pGuest)
1639 {
1640 RTMsgError(ControlVM::tr("Guest not running."));
1641 hrc = E_FAIL;
1642 break;
1643 }
1644 CHECK_ERROR_BREAK(pGuest, SetCredentials(Bstr(a->argv[2]).raw(),
1645 Bstr(passwd).raw(),
1646 Bstr(domain).raw(),
1647 fAllowLocalLogon));
1648 }
1649 else if (!strcmp(a->argv[1], "guestmemoryballoon"))
1650 {
1651 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_GUESTMEMORYBALLOON);
1652 if (a->argc != 3)
1653 {
1654 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
1655 hrc = E_FAIL;
1656 break;
1657 }
1658 uint32_t uVal;
1659 int vrc;
1660 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1661 if (vrc != VINF_SUCCESS)
1662 {
1663 errorSyntax(ControlVM::tr("Error parsing guest memory balloon size '%s'."), a->argv[2]);
1664 hrc = E_FAIL;
1665 break;
1666 }
1667 /* guest is running; update IGuest */
1668 ComPtr<IGuest> pGuest;
1669 hrc = console->COMGETTER(Guest)(pGuest.asOutParam());
1670 if (SUCCEEDED(hrc))
1671 {
1672 if (!pGuest)
1673 {
1674 RTMsgError(ControlVM::tr("Guest not running."));
1675 hrc = E_FAIL;
1676 break;
1677 }
1678 CHECK_ERROR(pGuest, COMSETTER(MemoryBalloonSize)(uVal));
1679 }
1680 }
1681 else if (!strcmp(a->argv[1], "teleport"))
1682 {
1683 Bstr bstrHostname;
1684 uint32_t uMaxDowntime = 250 /*ms*/;
1685 uint32_t uPort = UINT32_MAX;
1686 uint32_t cMsTimeout = 0;
1687 Utf8Str strPassword;
1688 static const RTGETOPTDEF s_aTeleportOptions[] =
1689 {
1690 { "--host", 'h', RTGETOPT_REQ_STRING }, /** @todo RTGETOPT_FLAG_MANDATORY */
1691 { "--maxdowntime", 'd', RTGETOPT_REQ_UINT32 },
1692 { "--port", 'P', RTGETOPT_REQ_UINT32 }, /** @todo RTGETOPT_FLAG_MANDATORY */
1693 { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
1694 { "--password", 'W', RTGETOPT_REQ_STRING },
1695 { "--timeout", 't', RTGETOPT_REQ_UINT32 },
1696 { "--detailed-progress", 'D', RTGETOPT_REQ_NOTHING }
1697 };
1698 RTGETOPTSTATE GetOptState;
1699 RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTeleportOptions, RT_ELEMENTS(s_aTeleportOptions), 2, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1700 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_TELEPORT);
1701 int ch;
1702 RTGETOPTUNION Value;
1703 while ( SUCCEEDED(hrc)
1704 && (ch = RTGetOpt(&GetOptState, &Value)))
1705 {
1706 switch (ch)
1707 {
1708 case 'h': bstrHostname = Value.psz; break;
1709 case 'd': uMaxDowntime = Value.u32; break;
1710 case 'D': g_fDetailedProgress = true; break;
1711 case 'P': uPort = Value.u32; break;
1712 case 'p':
1713 {
1714 RTEXITCODE rcExit = readPasswordFile(Value.psz, &strPassword);
1715 if (rcExit != RTEXITCODE_SUCCESS)
1716 hrc = E_FAIL;
1717 break;
1718 }
1719 case 'W': strPassword = Value.psz; break;
1720 case 't': cMsTimeout = Value.u32; break;
1721 default:
1722 errorGetOpt(ch, &Value);
1723 hrc = E_FAIL;
1724 break;
1725 }
1726 }
1727 if (FAILED(hrc))
1728 break;
1729
1730 ComPtr<IProgress> progress;
1731 CHECK_ERROR_BREAK(console, Teleport(bstrHostname.raw(), uPort,
1732 Bstr(strPassword).raw(),
1733 uMaxDowntime,
1734 progress.asOutParam()));
1735
1736 if (cMsTimeout)
1737 {
1738 hrc = progress->COMSETTER(Timeout)(cMsTimeout);
1739 if (FAILED(hrc) && hrc != VBOX_E_INVALID_OBJECT_STATE)
1740 CHECK_ERROR_BREAK(progress, COMSETTER(Timeout)(cMsTimeout)); /* lazyness */
1741 }
1742
1743 hrc = showProgress(progress);
1744 CHECK_PROGRESS_ERROR(progress, (ControlVM::tr("Teleportation failed")));
1745 }
1746 else if (!strcmp(a->argv[1], "screenshotpng"))
1747 {
1748 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_SCREENSHOTPNG);
1749 if (a->argc <= 2 || a->argc > 4)
1750 {
1751 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
1752 hrc = E_FAIL;
1753 break;
1754 }
1755 int vrc;
1756 uint32_t iScreen = 0;
1757 if (a->argc == 4)
1758 {
1759 vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &iScreen);
1760 if (vrc != VINF_SUCCESS)
1761 {
1762 errorSyntax(ControlVM::tr("Error parsing display number '%s'."), a->argv[3]);
1763 hrc = E_FAIL;
1764 break;
1765 }
1766 }
1767 ComPtr<IDisplay> pDisplay;
1768 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1769 if (!pDisplay)
1770 {
1771 RTMsgError(ControlVM::tr("Guest not running."));
1772 hrc = E_FAIL;
1773 break;
1774 }
1775 ULONG width, height, bpp;
1776 LONG xOrigin, yOrigin;
1777 GuestMonitorStatus_T monitorStatus;
1778 CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(iScreen, &width, &height, &bpp, &xOrigin, &yOrigin, &monitorStatus));
1779 com::SafeArray<BYTE> saScreenshot;
1780 CHECK_ERROR_BREAK(pDisplay, TakeScreenShotToArray(iScreen, width, height, BitmapFormat_PNG, ComSafeArrayAsOutParam(saScreenshot)));
1781 RTFILE pngFile = NIL_RTFILE;
1782 vrc = RTFileOpen(&pngFile, a->argv[2], RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_TRUNCATE | RTFILE_O_DENY_ALL);
1783 if (RT_FAILURE(vrc))
1784 {
1785 RTMsgError(ControlVM::tr("Failed to create file '%s' (%Rrc)."), a->argv[2], vrc);
1786 hrc = E_FAIL;
1787 break;
1788 }
1789 vrc = RTFileWrite(pngFile, saScreenshot.raw(), saScreenshot.size(), NULL);
1790 if (RT_FAILURE(vrc))
1791 {
1792 RTMsgError(ControlVM::tr("Failed to write screenshot to file '%s' (%Rrc)."), a->argv[2], vrc);
1793 hrc = E_FAIL;
1794 }
1795 RTFileClose(pngFile);
1796 }
1797#ifdef VBOX_WITH_RECORDING
1798 else if ( !strcmp(a->argv[1], "recording")
1799 || !strcmp(a->argv[1], "videocap") /* legacy command */)
1800 {
1801 if (a->argc < 3)
1802 {
1803 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
1804 hrc = E_FAIL;
1805 break;
1806 }
1807
1808 ComPtr<IRecordingSettings> recordingSettings;
1809 CHECK_ERROR_BREAK(sessionMachine, COMGETTER(RecordingSettings)(recordingSettings.asOutParam()));
1810
1811 SafeIfaceArray <IRecordingScreenSettings> saRecordingScreenScreens;
1812 CHECK_ERROR_BREAK(recordingSettings, COMGETTER(Screens)(ComSafeArrayAsOutParam(saRecordingScreenScreens)));
1813
1814 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
1815 CHECK_ERROR_BREAK(sessionMachine, COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam()));
1816
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 */
1823 bool fEnabled;
1824 if (RT_SUCCESS(parseBool(a->argv[2], &fEnabled)))
1825 {
1826 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING);
1827 CHECK_ERROR_RET(recordingSettings, COMSETTER(Enabled)(fEnabled), RTEXITCODE_FAILURE);
1828 }
1829 else if (!strcmp(a->argv[2], "screens"))
1830 {
1831 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_SCREENS);
1832 ULONG cMonitors = 64;
1833 CHECK_ERROR_BREAK(pGraphicsAdapter, COMGETTER(MonitorCount)(&cMonitors));
1834 com::SafeArray<BOOL> saScreens(cMonitors);
1835 if (a->argc != 4)
1836 {
1837 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
1838 hrc = E_FAIL;
1839 break;
1840 }
1841 if (RT_FAILURE(parseScreens(a->argv[3], &saScreens)))
1842 {
1843 errorSyntax(ControlVM::tr("Error parsing list of screen IDs '%s'."), a->argv[3]);
1844 hrc = E_FAIL;
1845 break;
1846 }
1847
1848 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
1849 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(Enabled)(saScreens[i]));
1850 }
1851 else if (!strcmp(a->argv[2], "filename"))
1852 {
1853 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_FILENAME);
1854 if (a->argc != 4)
1855 {
1856 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
1857 hrc = E_FAIL;
1858 break;
1859 }
1860
1861 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
1862 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(Filename)(Bstr(a->argv[3]).raw()));
1863 }
1864 else if ( !strcmp(a->argv[2], "videores")
1865 || !strcmp(a->argv[2], "videoresolution"))
1866 {
1867 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_VIDEORES);
1868 if (a->argc != 5)
1869 {
1870 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
1871 hrc = E_FAIL;
1872 break;
1873 }
1874
1875 uint32_t uWidth;
1876 int vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uWidth);
1877 if (RT_FAILURE(vrc))
1878 {
1879 errorSyntax(ControlVM::tr("Error parsing video width '%s'."), a->argv[3]);
1880 hrc = E_FAIL;
1881 break;
1882 }
1883
1884 uint32_t uHeight;
1885 vrc = RTStrToUInt32Ex(a->argv[4], NULL, 0, &uHeight);
1886 if (RT_FAILURE(vrc))
1887 {
1888 errorSyntax(ControlVM::tr("Error parsing video height '%s'."), a->argv[4]);
1889 hrc = E_FAIL;
1890 break;
1891 }
1892
1893 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
1894 {
1895 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(VideoWidth)(uWidth));
1896 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(VideoHeight)(uHeight));
1897 }
1898 }
1899 else if (!strcmp(a->argv[2], "videorate"))
1900 {
1901 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_VIDEORATE);
1902 if (a->argc != 4)
1903 {
1904 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
1905 hrc = E_FAIL;
1906 break;
1907 }
1908
1909 uint32_t uRate;
1910 int vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uRate);
1911 if (RT_FAILURE(vrc))
1912 {
1913 errorSyntax(ControlVM::tr("Error parsing video rate '%s'."), a->argv[3]);
1914 hrc = E_FAIL;
1915 break;
1916 }
1917
1918 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
1919 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(VideoRate)(uRate));
1920 }
1921 else if (!strcmp(a->argv[2], "videofps"))
1922 {
1923 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_VIDEOFPS);
1924 if (a->argc != 4)
1925 {
1926 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
1927 hrc = E_FAIL;
1928 break;
1929 }
1930
1931 uint32_t uFPS;
1932 int vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uFPS);
1933 if (RT_FAILURE(vrc))
1934 {
1935 errorSyntax(ControlVM::tr("Error parsing video FPS '%s'."), a->argv[3]);
1936 hrc = E_FAIL;
1937 break;
1938 }
1939
1940 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
1941 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(VideoFPS)(uFPS));
1942 }
1943 else if (!strcmp(a->argv[2], "maxtime"))
1944 {
1945 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_MAXTIME);
1946 if (a->argc != 4)
1947 {
1948 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
1949 hrc = E_FAIL;
1950 break;
1951 }
1952
1953 uint32_t uMaxTime;
1954 int vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uMaxTime);
1955 if (RT_FAILURE(vrc))
1956 {
1957 errorSyntax(ControlVM::tr("Error parsing maximum time '%s'."), a->argv[3]);
1958 hrc = E_FAIL;
1959 break;
1960 }
1961
1962 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
1963 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(MaxTime)(uMaxTime));
1964 }
1965 else if (!strcmp(a->argv[2], "maxfilesize"))
1966 {
1967 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_MAXFILESIZE);
1968 if (a->argc != 4)
1969 {
1970 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
1971 hrc = E_FAIL;
1972 break;
1973 }
1974
1975 uint32_t uMaxFileSize;
1976 int vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uMaxFileSize);
1977 if (RT_FAILURE(vrc))
1978 {
1979 errorSyntax(ControlVM::tr("Error parsing maximum file size '%s'."), a->argv[3]);
1980 hrc = E_FAIL;
1981 break;
1982 }
1983
1984 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
1985 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(MaxFileSize)(uMaxFileSize));
1986 }
1987 else if (!strcmp(a->argv[2], "opts"))
1988 {
1989#if 0 /* Add when the corresponding documentation is enabled. */
1990 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_RECORDING_OPTS);
1991#endif
1992 if (a->argc != 4)
1993 {
1994 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
1995 hrc = E_FAIL;
1996 break;
1997 }
1998
1999 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
2000 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(Options)(Bstr(a->argv[3]).raw()));
2001 }
2002 }
2003#endif /* VBOX_WITH_RECORDING */
2004 else if (!strcmp(a->argv[1], "webcam"))
2005 {
2006 if (a->argc < 3)
2007 {
2008 errorArgument(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
2009 hrc = E_FAIL;
2010 break;
2011 }
2012
2013 ComPtr<IEmulatedUSB> pEmulatedUSB;
2014 CHECK_ERROR_BREAK(console, COMGETTER(EmulatedUSB)(pEmulatedUSB.asOutParam()));
2015 if (!pEmulatedUSB)
2016 {
2017 RTMsgError(ControlVM::tr("Guest not running."));
2018 hrc = E_FAIL;
2019 break;
2020 }
2021
2022 if (!strcmp(a->argv[2], "attach"))
2023 {
2024 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_WEBCAM_ATTACH);
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 {
2035 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_WEBCAM_DETACH);
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 {
2043 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_WEBCAM_LIST);
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 {
2053 errorArgument(ControlVM::tr("Invalid argument to '%s'."), a->argv[1]);
2054 hrc = E_FAIL;
2055 break;
2056 }
2057 }
2058 else if (!strcmp(a->argv[1], "addencpassword"))
2059 {
2060 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_ADDENCPASSWORD);
2061 if ( a->argc != 4
2062 && a->argc != 6)
2063 {
2064 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
2065 break;
2066 }
2067
2068 BOOL fRemoveOnSuspend = FALSE;
2069 if (a->argc == 6)
2070 {
2071 if ( strcmp(a->argv[4], "--removeonsuspend")
2072 || ( strcmp(a->argv[5], "yes")
2073 && strcmp(a->argv[5], "no")))
2074 {
2075 errorSyntax(ControlVM::tr("Invalid parameters."));
2076 break;
2077 }
2078 if (!strcmp(a->argv[5], "yes"))
2079 fRemoveOnSuspend = TRUE;
2080 }
2081
2082 Bstr bstrPwId(a->argv[2]);
2083 Utf8Str strPassword;
2084
2085 if (!RTStrCmp(a->argv[3], "-"))
2086 {
2087 /* Get password from console. */
2088 RTEXITCODE rcExit = readPasswordFromConsole(&strPassword, ControlVM::tr("Enter password:"));
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 {
2097 RTMsgError(ControlVM::tr("Failed to read new password from file."));
2098 break;
2099 }
2100 }
2101
2102 CHECK_ERROR_BREAK(console, AddEncryptionPassword(bstrPwId.raw(), Bstr(strPassword).raw(), fRemoveOnSuspend));
2103 }
2104 else if (!strcmp(a->argv[1], "removeencpassword"))
2105 {
2106 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_REMOVEENCPASSWORD);
2107 if (a->argc != 3)
2108 {
2109 errorSyntax(ControlVM::tr("Incorrect number of parameters."));
2110 break;
2111 }
2112 Bstr bstrPwId(a->argv[2]);
2113 CHECK_ERROR_BREAK(console, RemoveEncryptionPassword(bstrPwId.raw()));
2114 }
2115 else if (!strcmp(a->argv[1], "removeallencpasswords"))
2116 {
2117 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_REMOVEALLENCPASSWORDS);
2118 CHECK_ERROR_BREAK(console, ClearAllEncryptionPasswords());
2119 }
2120 else if (!strncmp(a->argv[1], "changeuartmode", 14))
2121 {
2122 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_CHANGEUARTMODE);
2123 unsigned n = parseNum(&a->argv[1][14], 4, "UART");
2124 if (!n)
2125 {
2126 hrc = E_FAIL;
2127 break;
2128 }
2129 if (a->argc < 3)
2130 {
2131 errorSyntax(ControlVM::tr("Missing argument to '%s'."), a->argv[1]);
2132 hrc = E_FAIL;
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 {
2145 errorSyntax(ControlVM::tr("Incorrect arguments to '%s'."), a->argv[1]);
2146 hrc = E_FAIL;
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 {
2160 errorSyntax(ControlVM::tr("Incorrect arguments to '%s'."), a->argv[1]);
2161 hrc = E_FAIL;
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 {
2201 errorSyntax(ControlVM::tr("Incorrect arguments to '%s'."), a->argv[1]);
2202 hrc = E_FAIL;
2203 break;
2204 }
2205 CHECK_ERROR(uart, COMSETTER(Path)(Bstr(a->argv[2]).raw()));
2206 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_HostDevice));
2207 }
2208 }
2209 else if (!strncmp(a->argv[1], "vm-process-priority", 14))
2210 {
2211 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_VM_PROCESS_PRIORITY);
2212 if (a->argc != 3)
2213 {
2214 errorSyntax(ControlVM::tr("Incorrect arguments to '%s'."), a->argv[1]);
2215 hrc = E_FAIL;
2216 break;
2217 }
2218 VMProcPriority_T enmPriority = nameToVMProcPriority(a->argv[2]);
2219 if (enmPriority == VMProcPriority_Invalid)
2220 {
2221 errorSyntax(ControlVM::tr("Invalid vm-process-priority '%s'."), a->argv[2]);
2222 hrc = E_FAIL;
2223 }
2224 else
2225 {
2226 CHECK_ERROR(sessionMachine, COMSETTER(VMProcessPriority)(enmPriority));
2227 }
2228 break;
2229 }
2230 else if (!strncmp(a->argv[1], "autostart-enabled", 17))
2231 {
2232 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_AUTOSTART_ENABLED);
2233 if (a->argc != 3)
2234 {
2235 errorSyntax(ControlVM::tr("Incorrect arguments to '%s'."), a->argv[1]);
2236 hrc = E_FAIL;
2237 break;
2238 }
2239 bool fEnabled;
2240 if (RT_FAILURE(parseBool(a->argv[2], &fEnabled)))
2241 {
2242 errorSyntax(ControlVM::tr("Invalid value '%s'."), a->argv[2]);
2243 hrc = E_FAIL;
2244 break;
2245 }
2246 CHECK_ERROR(sessionMachine, COMSETTER(AutostartEnabled)(TRUE));
2247 fNeedsSaving = true;
2248 break;
2249 }
2250 else if (!strncmp(a->argv[1], "autostart-delay", 15))
2251 {
2252 setCurrentSubcommand(HELP_SCOPE_CONTROLVM_AUTOSTART_DELAY);
2253 if (a->argc != 3)
2254 {
2255 errorSyntax(ControlVM::tr("Incorrect arguments to '%s'."), a->argv[1]);
2256 hrc = E_FAIL;
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 {
2264 errorSyntax(ControlVM::tr("Invalid autostart delay number '%s'."), a->argv[2]);
2265 hrc = E_FAIL;
2266 break;
2267 }
2268 CHECK_ERROR(sessionMachine, COMSETTER(AutostartDelay)(u32));
2269 if (SUCCEEDED(hrc))
2270 fNeedsSaving = true;
2271 break;
2272 }
2273 else
2274 {
2275 errorSyntax(ControlVM::tr("Invalid parameter '%s'."), a->argv[1]);
2276 hrc = E_FAIL;
2277 }
2278 } while (0);
2279
2280 /* The client has to trigger saving the state explicitely. */
2281 if (fNeedsSaving)
2282 CHECK_ERROR(sessionMachine, SaveSettings());
2283
2284 a->session->UnlockMachine();
2285
2286 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2287}
Note: See TracBrowser for help on using the repository browser.

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