VirtualBox

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

Last change on this file since 95639 was 95423, checked in by vboxsync, 3 years ago

Audio/Main: Bigger revamp of the audio interface(s) to later also support host audio device enumeration and selection for individual VMs. The audio settings now live in a dedicated (per-VM) IAudioSettings interface (audio adapter + audio host device stuff), to further tidy up the IMachine interface. Also added stubs for IAudioDevice + IHostAudioDevice, plus enmuerations, left for further implementation. Added a new IHostAudioDeviceChangedEvent that can also be used later by API clients. bugref:10050

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

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