VirtualBox

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

Last change on this file since 88084 was 88079, checked in by vboxsync, 4 years ago

VBoxManage: When setting the host interface for bridging or hostonly
attachments do a sanity check on it. Make sure IHost knows about it
and that the interface is of correct type. Warn the user if that's
not the case, but the warning is non-fatal. The API setters don't do
this, so provide at least some protection from typos and mistakes.
bugref:9966.

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