VirtualBox

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

Last change on this file since 82781 was 81964, checked in by vboxsync, 5 years ago

Main/GraphicsAdapter: Split off a few attributes from Machine interface, which affects quite a few other interfaces.
Frontends/VirtualBox+VBoxManage+VBoxSDL+VBoxShell: Adapt accordingly.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use