VirtualBox

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

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

Main + FE/VBoxManage: Fixes / better logging for reboot / shutdown support.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 89.4 KB
Line 
1/* $Id: VBoxManageControlVM.cpp 84585 2020-05-28 12:14:17Z 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.215389.xyz. 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#ifdef VBOX_WITH_GUEST_CONTROL
680 else if ( !strcmp(a->argv[1], "reboot")
681 || !strcmp(a->argv[1], "shutdown")) /* With shutdown we mean gracefully powering off the VM by letting the guest OS do its thing. */
682 {
683 ComPtr<IGuest> pGuest;
684 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest.asOutParam()));
685 if (!pGuest)
686 {
687 RTMsgError("Guest not running");
688 rc = E_FAIL;
689 break;
690 }
691
692 const bool fReboot = !strcmp(a->argv[1], "reboot");
693
694 com::SafeArray<GuestShutdownFlag_T> aShutdownFlags;
695 aShutdownFlags.resize(1);
696
697 if (fReboot)
698 aShutdownFlags.push_back(GuestShutdownFlag_Reboot);
699 else
700 aShutdownFlags.push_back(GuestShutdownFlag_PowerOff);
701 CHECK_ERROR(pGuest, Shutdown(ComSafeArrayAsInParam(aShutdownFlags)));
702 if (FAILED(rc))
703 {
704 if (rc == VBOX_E_NOT_SUPPORTED)
705 RTPrintf("Current installed Guest Additions don't support %s the guest.",
706 fReboot ? "rebooting" : "shutting down");
707 }
708 }
709#endif
710 else if (!strcmp(a->argv[1], "keyboardputscancode"))
711 {
712 ComPtr<IKeyboard> pKeyboard;
713 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
714 if (!pKeyboard)
715 {
716 RTMsgError("Guest not running");
717 rc = E_FAIL;
718 break;
719 }
720
721 if (a->argc <= 1 + 1)
722 {
723 errorArgument("Missing argument to '%s'. Expected IBM PC AT set 2 keyboard scancode(s) as hex byte(s).", a->argv[1]);
724 rc = E_FAIL;
725 break;
726 }
727
728 std::list<LONG> llScancodes;
729
730 /* Process the command line. */
731 int i;
732 for (i = 1 + 1; i < a->argc; i++)
733 {
734 if ( RT_C_IS_XDIGIT (a->argv[i][0])
735 && RT_C_IS_XDIGIT (a->argv[i][1])
736 && a->argv[i][2] == 0)
737 {
738 uint8_t u8Scancode;
739 int irc = RTStrToUInt8Ex(a->argv[i], NULL, 16, &u8Scancode);
740 if (RT_FAILURE (irc))
741 {
742 RTMsgError("Converting '%s' returned %Rrc!", a->argv[i], rc);
743 rc = E_FAIL;
744 break;
745 }
746
747 llScancodes.push_back(u8Scancode);
748 }
749 else
750 {
751 RTMsgError("Error: '%s' is not a hex byte!", a->argv[i]);
752 rc = E_FAIL;
753 break;
754 }
755 }
756
757 if (FAILED(rc))
758 break;
759
760 rc = keyboardPutScancodes(pKeyboard, llScancodes);
761 }
762 else if (!strcmp(a->argv[1], "keyboardputstring"))
763 {
764 ComPtr<IKeyboard> pKeyboard;
765 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
766 if (!pKeyboard)
767 {
768 RTMsgError("Guest not running");
769 rc = E_FAIL;
770 break;
771 }
772
773 if (a->argc <= 1 + 1)
774 {
775 errorArgument("Missing argument to '%s'. Expected ASCII string(s).", a->argv[1]);
776 rc = E_FAIL;
777 break;
778 }
779
780 rc = keyboardPutString(pKeyboard, a->argc, a->argv);
781 }
782 else if (!strcmp(a->argv[1], "keyboardputfile"))
783 {
784 ComPtr<IKeyboard> pKeyboard;
785 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
786 if (!pKeyboard)
787 {
788 RTMsgError("Guest not running");
789 rc = E_FAIL;
790 break;
791 }
792
793 if (a->argc <= 1 + 1)
794 {
795 errorArgument("Missing argument to '%s'. Expected file name.", a->argv[1]);
796 rc = E_FAIL;
797 break;
798 }
799
800 rc = keyboardPutFile(pKeyboard, a->argv[2]);
801 }
802 else if (!strncmp(a->argv[1], "setlinkstate", 12))
803 {
804 /* Get the number of network adapters */
805 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
806 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
807 if (!n)
808 {
809 rc = E_FAIL;
810 break;
811 }
812 if (a->argc <= 1 + 1)
813 {
814 errorArgument("Missing argument to '%s'", a->argv[1]);
815 rc = E_FAIL;
816 break;
817 }
818 /* get the corresponding network adapter */
819 ComPtr<INetworkAdapter> adapter;
820 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
821 if (adapter)
822 {
823 if (!strcmp(a->argv[2], "on"))
824 {
825 CHECK_ERROR_BREAK(adapter, COMSETTER(CableConnected)(TRUE));
826 }
827 else if (!strcmp(a->argv[2], "off"))
828 {
829 CHECK_ERROR_BREAK(adapter, COMSETTER(CableConnected)(FALSE));
830 }
831 else
832 {
833 errorArgument("Invalid link state '%s'", Utf8Str(a->argv[2]).c_str());
834 rc = E_FAIL;
835 break;
836 }
837 if (SUCCEEDED(rc))
838 fNeedsSaving = true;
839 }
840 }
841 /* here the order in which strncmp is called is important
842 * cause nictracefile can be very well compared with
843 * nictrace and nic and thus everything will always fail
844 * if the order is changed
845 */
846 else if (!strncmp(a->argv[1], "nictracefile", 12))
847 {
848 /* Get the number of network adapters */
849 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
850 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
851 if (!n)
852 {
853 rc = E_FAIL;
854 break;
855 }
856 if (a->argc <= 2)
857 {
858 errorArgument("Missing argument to '%s'", a->argv[1]);
859 rc = E_FAIL;
860 break;
861 }
862
863 /* get the corresponding network adapter */
864 ComPtr<INetworkAdapter> adapter;
865 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
866 if (adapter)
867 {
868 BOOL fEnabled;
869 adapter->COMGETTER(Enabled)(&fEnabled);
870 if (fEnabled)
871 {
872 if (a->argv[2])
873 {
874 CHECK_ERROR_RET(adapter, COMSETTER(TraceFile)(Bstr(a->argv[2]).raw()), RTEXITCODE_FAILURE);
875 }
876 else
877 {
878 errorArgument("Invalid filename or filename not specified for NIC %lu", n);
879 rc = E_FAIL;
880 break;
881 }
882 if (SUCCEEDED(rc))
883 fNeedsSaving = true;
884 }
885 else
886 RTMsgError("The NIC %d is currently disabled and thus its tracefile can't be changed", n);
887 }
888 }
889 else if (!strncmp(a->argv[1], "nictrace", 8))
890 {
891 /* Get the number of network adapters */
892 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
893 unsigned n = parseNum(&a->argv[1][8], NetworkAdapterCount, "NIC");
894 if (!n)
895 {
896 rc = E_FAIL;
897 break;
898 }
899 if (a->argc <= 2)
900 {
901 errorArgument("Missing argument to '%s'", a->argv[1]);
902 rc = E_FAIL;
903 break;
904 }
905
906 /* get the corresponding network adapter */
907 ComPtr<INetworkAdapter> adapter;
908 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
909 if (adapter)
910 {
911 BOOL fEnabled;
912 adapter->COMGETTER(Enabled)(&fEnabled);
913 if (fEnabled)
914 {
915 if (!strcmp(a->argv[2], "on"))
916 {
917 CHECK_ERROR_RET(adapter, COMSETTER(TraceEnabled)(TRUE), RTEXITCODE_FAILURE);
918 }
919 else if (!strcmp(a->argv[2], "off"))
920 {
921 CHECK_ERROR_RET(adapter, COMSETTER(TraceEnabled)(FALSE), RTEXITCODE_FAILURE);
922 }
923 else
924 {
925 errorArgument("Invalid nictrace%lu argument '%s'", n, Utf8Str(a->argv[2]).c_str());
926 rc = E_FAIL;
927 break;
928 }
929 if (SUCCEEDED(rc))
930 fNeedsSaving = true;
931 }
932 else
933 RTMsgError("The NIC %d is currently disabled and thus its trace flag can't be changed", n);
934 }
935 }
936 else if( a->argc > 2
937 && !strncmp(a->argv[1], "natpf", 5))
938 {
939 /* Get the number of network adapters */
940 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
941 unsigned n = parseNum(&a->argv[1][5], NetworkAdapterCount, "NIC");
942 if (!n)
943 {
944 rc = E_FAIL;
945 break;
946 }
947 if (a->argc <= 2)
948 {
949 errorArgument("Missing argument to '%s'", a->argv[1]);
950 rc = E_FAIL;
951 break;
952 }
953
954 /* get the corresponding network adapter */
955 ComPtr<INetworkAdapter> adapter;
956 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
957 if (!adapter)
958 {
959 rc = E_FAIL;
960 break;
961 }
962 ComPtr<INATEngine> engine;
963 CHECK_ERROR(adapter, COMGETTER(NATEngine)(engine.asOutParam()));
964 if (!engine)
965 {
966 rc = E_FAIL;
967 break;
968 }
969
970 if (!strcmp(a->argv[2], "delete"))
971 {
972 if (a->argc >= 3)
973 CHECK_ERROR(engine, RemoveRedirect(Bstr(a->argv[3]).raw()));
974 }
975 else
976 {
977#define ITERATE_TO_NEXT_TERM(ch) \
978 do { \
979 while (*ch != ',') \
980 { \
981 if (*ch == 0) \
982 { \
983 return errorSyntax(USAGE_CONTROLVM, \
984 "Missing or invalid argument to '%s'", \
985 a->argv[1]); \
986 } \
987 ch++; \
988 } \
989 *ch = '\0'; \
990 ch++; \
991 } while(0)
992
993 char *strName;
994 char *strProto;
995 char *strHostIp;
996 char *strHostPort;
997 char *strGuestIp;
998 char *strGuestPort;
999 char *strRaw = RTStrDup(a->argv[2]);
1000 char *ch = strRaw;
1001 strName = RTStrStrip(ch);
1002 ITERATE_TO_NEXT_TERM(ch);
1003 strProto = RTStrStrip(ch);
1004 ITERATE_TO_NEXT_TERM(ch);
1005 strHostIp = RTStrStrip(ch);
1006 ITERATE_TO_NEXT_TERM(ch);
1007 strHostPort = RTStrStrip(ch);
1008 ITERATE_TO_NEXT_TERM(ch);
1009 strGuestIp = RTStrStrip(ch);
1010 ITERATE_TO_NEXT_TERM(ch);
1011 strGuestPort = RTStrStrip(ch);
1012 NATProtocol_T proto;
1013 if (RTStrICmp(strProto, "udp") == 0)
1014 proto = NATProtocol_UDP;
1015 else if (RTStrICmp(strProto, "tcp") == 0)
1016 proto = NATProtocol_TCP;
1017 else
1018 {
1019 return errorSyntax(USAGE_CONTROLVM,
1020 "Wrong rule proto '%s' specified -- only 'udp' and 'tcp' are allowed.",
1021 strProto);
1022 }
1023 CHECK_ERROR(engine, AddRedirect(Bstr(strName).raw(), proto, Bstr(strHostIp).raw(),
1024 RTStrToUInt16(strHostPort), Bstr(strGuestIp).raw(), RTStrToUInt16(strGuestPort)));
1025#undef ITERATE_TO_NEXT_TERM
1026 }
1027 if (SUCCEEDED(rc))
1028 fNeedsSaving = true;
1029 }
1030 else if (!strncmp(a->argv[1], "nicproperty", 11))
1031 {
1032 /* Get the number of network adapters */
1033 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
1034 unsigned n = parseNum(&a->argv[1][11], NetworkAdapterCount, "NIC");
1035 if (!n)
1036 {
1037 rc = E_FAIL;
1038 break;
1039 }
1040 if (a->argc <= 2)
1041 {
1042 errorArgument("Missing argument to '%s'", a->argv[1]);
1043 rc = E_FAIL;
1044 break;
1045 }
1046
1047 /* get the corresponding network adapter */
1048 ComPtr<INetworkAdapter> adapter;
1049 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
1050 if (adapter)
1051 {
1052 BOOL fEnabled;
1053 adapter->COMGETTER(Enabled)(&fEnabled);
1054 if (fEnabled)
1055 {
1056 /* Parse 'name=value' */
1057 char *pszProperty = RTStrDup(a->argv[2]);
1058 if (pszProperty)
1059 {
1060 char *pDelimiter = strchr(pszProperty, '=');
1061 if (pDelimiter)
1062 {
1063 *pDelimiter = '\0';
1064
1065 Bstr bstrName = pszProperty;
1066 Bstr bstrValue = &pDelimiter[1];
1067 CHECK_ERROR(adapter, SetProperty(bstrName.raw(), bstrValue.raw()));
1068 if (SUCCEEDED(rc))
1069 fNeedsSaving = true;
1070 }
1071 else
1072 {
1073 errorArgument("Invalid nicproperty%d argument '%s'", n, a->argv[2]);
1074 rc = E_FAIL;
1075 }
1076 RTStrFree(pszProperty);
1077 }
1078 else
1079 {
1080 RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for nicproperty%d '%s'\n", n, a->argv[2]);
1081 rc = E_FAIL;
1082 }
1083 if (FAILED(rc))
1084 break;
1085 }
1086 else
1087 RTMsgError("The NIC %d is currently disabled and thus its properties can't be changed", n);
1088 }
1089 }
1090 else if (!strncmp(a->argv[1], "nicpromisc", 10))
1091 {
1092 /* Get the number of network adapters */
1093 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
1094 unsigned n = parseNum(&a->argv[1][10], NetworkAdapterCount, "NIC");
1095 if (!n)
1096 {
1097 rc = E_FAIL;
1098 break;
1099 }
1100 if (a->argc <= 2)
1101 {
1102 errorArgument("Missing argument to '%s'", a->argv[1]);
1103 rc = E_FAIL;
1104 break;
1105 }
1106
1107 /* get the corresponding network adapter */
1108 ComPtr<INetworkAdapter> adapter;
1109 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
1110 if (adapter)
1111 {
1112 BOOL fEnabled;
1113 adapter->COMGETTER(Enabled)(&fEnabled);
1114 if (fEnabled)
1115 {
1116 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
1117 if (!strcmp(a->argv[2], "deny"))
1118 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_Deny;
1119 else if ( !strcmp(a->argv[2], "allow-vms")
1120 || !strcmp(a->argv[2], "allow-network"))
1121 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowNetwork;
1122 else if (!strcmp(a->argv[2], "allow-all"))
1123 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowAll;
1124 else
1125 {
1126 errorArgument("Unknown promiscuous mode policy '%s'", a->argv[2]);
1127 rc = E_INVALIDARG;
1128 break;
1129 }
1130
1131 CHECK_ERROR(adapter, COMSETTER(PromiscModePolicy)(enmPromiscModePolicy));
1132 if (SUCCEEDED(rc))
1133 fNeedsSaving = true;
1134 }
1135 else
1136 RTMsgError("The NIC %d is currently disabled and thus its promiscuous mode can't be changed", n);
1137 }
1138 }
1139 else if (!strncmp(a->argv[1], "nic", 3))
1140 {
1141 /* Get the number of network adapters */
1142 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
1143 unsigned n = parseNum(&a->argv[1][3], NetworkAdapterCount, "NIC");
1144 if (!n)
1145 {
1146 rc = E_FAIL;
1147 break;
1148 }
1149 if (a->argc <= 2)
1150 {
1151 errorArgument("Missing argument to '%s'", a->argv[1]);
1152 rc = E_FAIL;
1153 break;
1154 }
1155
1156 /* get the corresponding network adapter */
1157 ComPtr<INetworkAdapter> adapter;
1158 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
1159 if (adapter)
1160 {
1161 BOOL fEnabled;
1162 adapter->COMGETTER(Enabled)(&fEnabled);
1163 if (fEnabled)
1164 {
1165 if (!strcmp(a->argv[2], "null"))
1166 {
1167 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Null), RTEXITCODE_FAILURE);
1168 }
1169 else if (!strcmp(a->argv[2], "nat"))
1170 {
1171 if (a->argc == 4)
1172 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1173 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_NAT), RTEXITCODE_FAILURE);
1174 }
1175 else if ( !strcmp(a->argv[2], "bridged")
1176 || !strcmp(a->argv[2], "hostif")) /* backward compatibility */
1177 {
1178 if (a->argc <= 3)
1179 {
1180 errorArgument("Missing argument to '%s'", a->argv[2]);
1181 rc = E_FAIL;
1182 break;
1183 }
1184 CHECK_ERROR_RET(adapter, COMSETTER(BridgedInterface)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1185 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Bridged), RTEXITCODE_FAILURE);
1186 }
1187 else if (!strcmp(a->argv[2], "intnet"))
1188 {
1189 if (a->argc <= 3)
1190 {
1191 errorArgument("Missing argument to '%s'", a->argv[2]);
1192 rc = E_FAIL;
1193 break;
1194 }
1195 CHECK_ERROR_RET(adapter, COMSETTER(InternalNetwork)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1196 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Internal), RTEXITCODE_FAILURE);
1197 }
1198#if defined(VBOX_WITH_NETFLT)
1199 else if (!strcmp(a->argv[2], "hostonly"))
1200 {
1201 if (a->argc <= 3)
1202 {
1203 errorArgument("Missing argument to '%s'", a->argv[2]);
1204 rc = E_FAIL;
1205 break;
1206 }
1207 CHECK_ERROR_RET(adapter, COMSETTER(HostOnlyInterface)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1208 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_HostOnly), RTEXITCODE_FAILURE);
1209 }
1210#endif
1211 else if (!strcmp(a->argv[2], "generic"))
1212 {
1213 if (a->argc <= 3)
1214 {
1215 errorArgument("Missing argument to '%s'", a->argv[2]);
1216 rc = E_FAIL;
1217 break;
1218 }
1219 CHECK_ERROR_RET(adapter, COMSETTER(GenericDriver)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1220 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic), RTEXITCODE_FAILURE);
1221 }
1222 else if (!strcmp(a->argv[2], "natnetwork"))
1223 {
1224 if (a->argc <= 3)
1225 {
1226 errorArgument("Missing argument to '%s'", a->argv[2]);
1227 rc = E_FAIL;
1228 break;
1229 }
1230 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1231 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_NATNetwork), RTEXITCODE_FAILURE);
1232 }
1233 /** @todo obsolete, remove eventually */
1234 else if (!strcmp(a->argv[2], "vde"))
1235 {
1236 if (a->argc <= 3)
1237 {
1238 errorArgument("Missing argument to '%s'", a->argv[2]);
1239 rc = E_FAIL;
1240 break;
1241 }
1242 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic), RTEXITCODE_FAILURE);
1243 CHECK_ERROR_RET(adapter, SetProperty(Bstr("name").raw(), Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1244 }
1245 else
1246 {
1247 errorArgument("Invalid type '%s' specfied for NIC %lu", Utf8Str(a->argv[2]).c_str(), n);
1248 rc = E_FAIL;
1249 break;
1250 }
1251 if (SUCCEEDED(rc))
1252 fNeedsSaving = true;
1253 }
1254 else
1255 RTMsgError("The NIC %d is currently disabled and thus its attachment type can't be changed", n);
1256 }
1257 }
1258 else if ( !strcmp(a->argv[1], "vrde")
1259 || !strcmp(a->argv[1], "vrdp"))
1260 {
1261 if (!strcmp(a->argv[1], "vrdp"))
1262 RTStrmPrintf(g_pStdErr, "Warning: 'vrdp' is deprecated. Use 'vrde'.\n");
1263
1264 if (a->argc <= 1 + 1)
1265 {
1266 errorArgument("Missing argument to '%s'", a->argv[1]);
1267 rc = E_FAIL;
1268 break;
1269 }
1270 ComPtr<IVRDEServer> vrdeServer;
1271 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1272 ASSERT(vrdeServer);
1273 if (vrdeServer)
1274 {
1275 if (!strcmp(a->argv[2], "on"))
1276 {
1277 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(TRUE));
1278 }
1279 else if (!strcmp(a->argv[2], "off"))
1280 {
1281 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(FALSE));
1282 }
1283 else
1284 {
1285 errorArgument("Invalid remote desktop server state '%s'", Utf8Str(a->argv[2]).c_str());
1286 rc = E_FAIL;
1287 break;
1288 }
1289 if (SUCCEEDED(rc))
1290 fNeedsSaving = true;
1291 }
1292 }
1293 else if ( !strcmp(a->argv[1], "vrdeport")
1294 || !strcmp(a->argv[1], "vrdpport"))
1295 {
1296 if (!strcmp(a->argv[1], "vrdpport"))
1297 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpport' is deprecated. Use 'vrdeport'.\n");
1298
1299 if (a->argc <= 1 + 1)
1300 {
1301 errorArgument("Missing argument to '%s'", a->argv[1]);
1302 rc = E_FAIL;
1303 break;
1304 }
1305
1306 ComPtr<IVRDEServer> vrdeServer;
1307 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1308 ASSERT(vrdeServer);
1309 if (vrdeServer)
1310 {
1311 Bstr ports;
1312
1313 if (!strcmp(a->argv[2], "default"))
1314 ports = "0";
1315 else
1316 ports = a->argv[2];
1317
1318 CHECK_ERROR_BREAK(vrdeServer, SetVRDEProperty(Bstr("TCP/Ports").raw(), ports.raw()));
1319 if (SUCCEEDED(rc))
1320 fNeedsSaving = true;
1321 }
1322 }
1323 else if ( !strcmp(a->argv[1], "vrdevideochannelquality")
1324 || !strcmp(a->argv[1], "vrdpvideochannelquality"))
1325 {
1326 if (!strcmp(a->argv[1], "vrdpvideochannelquality"))
1327 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpvideochannelquality' is deprecated. Use 'vrdevideochannelquality'.\n");
1328
1329 if (a->argc <= 1 + 1)
1330 {
1331 errorArgument("Missing argument to '%s'", a->argv[1]);
1332 rc = E_FAIL;
1333 break;
1334 }
1335 ComPtr<IVRDEServer> vrdeServer;
1336 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1337 ASSERT(vrdeServer);
1338 if (vrdeServer)
1339 {
1340 Bstr value = a->argv[2];
1341
1342 CHECK_ERROR(vrdeServer, SetVRDEProperty(Bstr("VideoChannel/Quality").raw(), value.raw()));
1343 if (SUCCEEDED(rc))
1344 fNeedsSaving = true;
1345 }
1346 }
1347 else if (!strcmp(a->argv[1], "vrdeproperty"))
1348 {
1349 if (a->argc <= 1 + 1)
1350 {
1351 errorArgument("Missing argument to '%s'", a->argv[1]);
1352 rc = E_FAIL;
1353 break;
1354 }
1355 ComPtr<IVRDEServer> vrdeServer;
1356 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1357 ASSERT(vrdeServer);
1358 if (vrdeServer)
1359 {
1360 /* Parse 'name=value' */
1361 char *pszProperty = RTStrDup(a->argv[2]);
1362 if (pszProperty)
1363 {
1364 char *pDelimiter = strchr(pszProperty, '=');
1365 if (pDelimiter)
1366 {
1367 *pDelimiter = '\0';
1368
1369 Bstr bstrName = pszProperty;
1370 Bstr bstrValue = &pDelimiter[1];
1371 CHECK_ERROR(vrdeServer, SetVRDEProperty(bstrName.raw(), bstrValue.raw()));
1372 if (SUCCEEDED(rc))
1373 fNeedsSaving = true;
1374 }
1375 else
1376 {
1377 errorArgument("Invalid vrdeproperty argument '%s'", a->argv[2]);
1378 rc = E_FAIL;
1379 }
1380 RTStrFree(pszProperty);
1381 }
1382 else
1383 {
1384 RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for VRDE property '%s'\n", a->argv[2]);
1385 rc = E_FAIL;
1386 }
1387 }
1388 if (FAILED(rc))
1389 {
1390 break;
1391 }
1392 }
1393 else if ( !strcmp(a->argv[1], "usbattach")
1394 || !strcmp(a->argv[1], "usbdetach"))
1395 {
1396 if (a->argc < 3)
1397 {
1398 errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
1399 rc = E_FAIL;
1400 break;
1401 }
1402 else if (a->argc == 4 || a->argc > 5)
1403 {
1404 errorSyntax(USAGE_CONTROLVM, "Wrong number of arguments");
1405 rc = E_FAIL;
1406 break;
1407 }
1408
1409 bool attach = !strcmp(a->argv[1], "usbattach");
1410
1411 Bstr usbId = a->argv[2];
1412 Bstr captureFilename;
1413
1414 if (a->argc == 5)
1415 {
1416 if (!strcmp(a->argv[3], "--capturefile"))
1417 captureFilename = a->argv[4];
1418 else
1419 {
1420 errorArgument("Invalid parameter '%s'", a->argv[3]);
1421 rc = E_FAIL;
1422 break;
1423 }
1424 }
1425
1426 Guid guid(usbId);
1427 if (!guid.isValid())
1428 {
1429 // assume address
1430 if (attach)
1431 {
1432 ComPtr<IHost> host;
1433 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1434 SafeIfaceArray <IHostUSBDevice> coll;
1435 CHECK_ERROR_BREAK(host, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
1436 ComPtr<IHostUSBDevice> dev;
1437 CHECK_ERROR_BREAK(host, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
1438 dev.asOutParam()));
1439 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
1440 }
1441 else
1442 {
1443 SafeIfaceArray <IUSBDevice> coll;
1444 CHECK_ERROR_BREAK(console, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
1445 ComPtr<IUSBDevice> dev;
1446 CHECK_ERROR_BREAK(console, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
1447 dev.asOutParam()));
1448 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
1449 }
1450 }
1451 else if (guid.isZero())
1452 {
1453 errorArgument("Zero UUID argument '%s'", a->argv[2]);
1454 rc = E_FAIL;
1455 break;
1456 }
1457
1458 if (attach)
1459 CHECK_ERROR_BREAK(console, AttachUSBDevice(usbId.raw(), captureFilename.raw()));
1460 else
1461 {
1462 ComPtr<IUSBDevice> dev;
1463 CHECK_ERROR_BREAK(console, DetachUSBDevice(usbId.raw(),
1464 dev.asOutParam()));
1465 }
1466 }
1467 else if (!strcmp(a->argv[1], "setvideomodehint"))
1468 {
1469 if (a->argc != 5 && a->argc != 6 && a->argc != 7 && a->argc != 9)
1470 {
1471 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1472 rc = E_FAIL;
1473 break;
1474 }
1475 bool fEnabled = true;
1476 uint32_t uXRes = RTStrToUInt32(a->argv[2]);
1477 uint32_t uYRes = RTStrToUInt32(a->argv[3]);
1478 uint32_t uBpp = RTStrToUInt32(a->argv[4]);
1479 uint32_t uDisplayIdx = 0;
1480 bool fChangeOrigin = false;
1481 int32_t iOriginX = 0;
1482 int32_t iOriginY = 0;
1483 if (a->argc >= 6)
1484 uDisplayIdx = RTStrToUInt32(a->argv[5]);
1485 if (a->argc >= 7)
1486 {
1487 int vrc = parseBool(a->argv[6], &fEnabled);
1488 if (RT_FAILURE(vrc))
1489 {
1490 errorSyntax(USAGE_CONTROLVM, "Either \"yes\" or \"no\" is expected");
1491 rc = E_FAIL;
1492 break;
1493 }
1494 fEnabled = !RTStrICmp(a->argv[6], "yes");
1495 }
1496 if (a->argc == 9)
1497 {
1498 iOriginX = RTStrToInt32(a->argv[7]);
1499 iOriginY = RTStrToInt32(a->argv[8]);
1500 fChangeOrigin = true;
1501 }
1502
1503 ComPtr<IDisplay> pDisplay;
1504 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1505 if (!pDisplay)
1506 {
1507 RTMsgError("Guest not running");
1508 rc = E_FAIL;
1509 break;
1510 }
1511 CHECK_ERROR_BREAK(pDisplay, SetVideoModeHint(uDisplayIdx, fEnabled,
1512 fChangeOrigin, iOriginX, iOriginY,
1513 uXRes, uYRes, uBpp, true));
1514 }
1515 else if (!strcmp(a->argv[1], "setscreenlayout"))
1516 {
1517 if (a->argc < 4)
1518 {
1519 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1520 rc = E_FAIL;
1521 break;
1522 }
1523
1524 ComPtr<IDisplay> pDisplay;
1525 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1526 if (!pDisplay)
1527 {
1528 RTMsgError("Guest not running");
1529 rc = E_FAIL;
1530 break;
1531 }
1532
1533 com::SafeIfaceArray<IGuestScreenInfo> aGuestScreenInfos;
1534
1535 /* Parse "<display> on|primary <xorigin> <yorigin> <xres> <yres> <bpp> | off" sequences. */
1536 int argc = a->argc - 2;
1537 char **argv = &a->argv[2];
1538 while (argc >= 2)
1539 {
1540 ULONG aDisplay = RTStrToUInt32(argv[0]);
1541 BOOL aPrimary = FALSE;
1542
1543 GuestMonitorStatus_T aStatus;
1544 if (RTStrICmp(argv[1], "primary") == 0)
1545 {
1546 aStatus = GuestMonitorStatus_Enabled;
1547 aPrimary = TRUE;
1548 }
1549 else if (RTStrICmp(argv[1], "on") == 0)
1550 aStatus = GuestMonitorStatus_Enabled;
1551 else if (RTStrICmp(argv[1], "off") == 0)
1552 aStatus = GuestMonitorStatus_Disabled;
1553 else
1554 {
1555 errorSyntax(USAGE_CONTROLVM, "Display status must be <on> or <off>");
1556 rc = E_FAIL;
1557 break;
1558 }
1559
1560 BOOL aChangeOrigin = FALSE;
1561 LONG aOriginX = 0;
1562 LONG aOriginY = 0;
1563 ULONG aWidth = 0;
1564 ULONG aHeight = 0;
1565 ULONG aBitsPerPixel = 0;
1566 if (aStatus == GuestMonitorStatus_Enabled)
1567 {
1568 if (argc < 7)
1569 {
1570 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1571 rc = E_FAIL;
1572 break;
1573 }
1574
1575 aChangeOrigin = TRUE;
1576 aOriginX = RTStrToUInt32(argv[2]);
1577 aOriginY = RTStrToUInt32(argv[3]);
1578 aWidth = RTStrToUInt32(argv[4]);
1579 aHeight = RTStrToUInt32(argv[5]);
1580 aBitsPerPixel = RTStrToUInt32(argv[6]);
1581
1582 argc -= 7;
1583 argv += 7;
1584 }
1585 else
1586 {
1587 argc -= 2;
1588 argv += 2;
1589 }
1590
1591 ComPtr<IGuestScreenInfo> pInfo;
1592 CHECK_ERROR_BREAK(pDisplay, CreateGuestScreenInfo(aDisplay, aStatus, aPrimary, aChangeOrigin,
1593 aOriginX, aOriginY, aWidth, aHeight, aBitsPerPixel,
1594 pInfo.asOutParam()));
1595 aGuestScreenInfos.push_back(pInfo);
1596 }
1597
1598 if (FAILED(rc))
1599 break;
1600
1601 CHECK_ERROR_BREAK(pDisplay, SetScreenLayout(ScreenLayoutMode_Apply, ComSafeArrayAsInParam(aGuestScreenInfos)));
1602 }
1603 else if (!strcmp(a->argv[1], "setcredentials"))
1604 {
1605 bool fAllowLocalLogon = true;
1606 if ( a->argc == 7
1607 || ( a->argc == 8
1608 && ( !strcmp(a->argv[3], "-p")
1609 || !strcmp(a->argv[3], "--passwordfile"))))
1610 {
1611 if ( strcmp(a->argv[5 + (a->argc - 7)], "--allowlocallogon")
1612 && strcmp(a->argv[5 + (a->argc - 7)], "-allowlocallogon"))
1613 {
1614 errorArgument("Invalid parameter '%s'", a->argv[5]);
1615 rc = E_FAIL;
1616 break;
1617 }
1618 if (!strcmp(a->argv[6 + (a->argc - 7)], "no"))
1619 fAllowLocalLogon = false;
1620 }
1621 else if ( a->argc != 5
1622 && ( a->argc != 6
1623 || ( strcmp(a->argv[3], "-p")
1624 && strcmp(a->argv[3], "--passwordfile"))))
1625 {
1626 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1627 rc = E_FAIL;
1628 break;
1629 }
1630 Utf8Str passwd, domain;
1631 if (a->argc == 5 || a->argc == 7)
1632 {
1633 passwd = a->argv[3];
1634 domain = a->argv[4];
1635 }
1636 else
1637 {
1638 RTEXITCODE rcExit = readPasswordFile(a->argv[4], &passwd);
1639 if (rcExit != RTEXITCODE_SUCCESS)
1640 {
1641 rc = E_FAIL;
1642 break;
1643 }
1644 domain = a->argv[5];
1645 }
1646
1647 ComPtr<IGuest> pGuest;
1648 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest.asOutParam()));
1649 if (!pGuest)
1650 {
1651 RTMsgError("Guest not running");
1652 rc = E_FAIL;
1653 break;
1654 }
1655 CHECK_ERROR_BREAK(pGuest, SetCredentials(Bstr(a->argv[2]).raw(),
1656 Bstr(passwd).raw(),
1657 Bstr(domain).raw(),
1658 fAllowLocalLogon));
1659 }
1660#if 0 /** @todo review & remove */
1661 else if (!strcmp(a->argv[1], "dvdattach"))
1662 {
1663 Bstr uuid;
1664 if (a->argc != 3)
1665 {
1666 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1667 rc = E_FAIL;
1668 break;
1669 }
1670
1671 ComPtr<IMedium> dvdMedium;
1672
1673 /* unmount? */
1674 if (!strcmp(a->argv[2], "none"))
1675 {
1676 /* nothing to do, NULL object will cause unmount */
1677 }
1678 /* host drive? */
1679 else if (!strncmp(a->argv[2], "host:", 5))
1680 {
1681 ComPtr<IHost> host;
1682 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1683
1684 rc = host->FindHostDVDDrive(Bstr(a->argv[2] + 5), dvdMedium.asOutParam());
1685 if (!dvdMedium)
1686 {
1687 errorArgument("Invalid host DVD drive name \"%s\"",
1688 a->argv[2] + 5);
1689 rc = E_FAIL;
1690 break;
1691 }
1692 }
1693 else
1694 {
1695 /* first assume it's a UUID */
1696 uuid = a->argv[2];
1697 rc = a->virtualBox->GetDVDImage(uuid, dvdMedium.asOutParam());
1698 if (FAILED(rc) || !dvdMedium)
1699 {
1700 /* must be a filename, check if it's in the collection */
1701 rc = a->virtualBox->FindDVDImage(Bstr(a->argv[2]), dvdMedium.asOutParam());
1702 /* not registered, do that on the fly */
1703 if (!dvdMedium)
1704 {
1705 Bstr emptyUUID;
1706 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(a->argv[2]), emptyUUID, dvdMedium.asOutParam()));
1707 }
1708 }
1709 if (!dvdMedium)
1710 {
1711 rc = E_FAIL;
1712 break;
1713 }
1714 }
1715
1716 /** @todo generalize this, allow arbitrary number of DVD drives
1717 * and as a consequence multiple attachments and different
1718 * storage controllers. */
1719 if (dvdMedium)
1720 dvdMedium->COMGETTER(Id)(uuid.asOutParam());
1721 else
1722 uuid = Guid().toString();
1723 CHECK_ERROR(sessionMachine, MountMedium(Bstr("IDE Controller"), 1, 0, uuid, FALSE /* aForce */));
1724 }
1725 else if (!strcmp(a->argv[1], "floppyattach"))
1726 {
1727 Bstr uuid;
1728 if (a->argc != 3)
1729 {
1730 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1731 rc = E_FAIL;
1732 break;
1733 }
1734
1735 ComPtr<IMedium> floppyMedium;
1736
1737 /* unmount? */
1738 if (!strcmp(a->argv[2], "none"))
1739 {
1740 /* nothing to do, NULL object will cause unmount */
1741 }
1742 /* host drive? */
1743 else if (!strncmp(a->argv[2], "host:", 5))
1744 {
1745 ComPtr<IHost> host;
1746 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1747 host->FindHostFloppyDrive(Bstr(a->argv[2] + 5), floppyMedium.asOutParam());
1748 if (!floppyMedium)
1749 {
1750 errorArgument("Invalid host floppy drive name \"%s\"",
1751 a->argv[2] + 5);
1752 rc = E_FAIL;
1753 break;
1754 }
1755 }
1756 else
1757 {
1758 /* first assume it's a UUID */
1759 uuid = a->argv[2];
1760 rc = a->virtualBox->GetFloppyImage(uuid, floppyMedium.asOutParam());
1761 if (FAILED(rc) || !floppyMedium)
1762 {
1763 /* must be a filename, check if it's in the collection */
1764 rc = a->virtualBox->FindFloppyImage(Bstr(a->argv[2]), floppyMedium.asOutParam());
1765 /* not registered, do that on the fly */
1766 if (!floppyMedium)
1767 {
1768 Bstr emptyUUID;
1769 CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(a->argv[2]), emptyUUID, floppyMedium.asOutParam()));
1770 }
1771 }
1772 if (!floppyMedium)
1773 {
1774 rc = E_FAIL;
1775 break;
1776 }
1777 }
1778 floppyMedium->COMGETTER(Id)(uuid.asOutParam());
1779 CHECK_ERROR(sessionMachine, MountMedium(Bstr("Floppy Controller"), 0, 0, uuid, FALSE /* aForce */));
1780 }
1781#endif /* obsolete dvdattach/floppyattach */
1782 else if (!strcmp(a->argv[1], "guestmemoryballoon"))
1783 {
1784 if (a->argc != 3)
1785 {
1786 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1787 rc = E_FAIL;
1788 break;
1789 }
1790 uint32_t uVal;
1791 int vrc;
1792 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1793 if (vrc != VINF_SUCCESS)
1794 {
1795 errorArgument("Error parsing guest memory balloon size '%s'", a->argv[2]);
1796 rc = E_FAIL;
1797 break;
1798 }
1799 /* guest is running; update IGuest */
1800 ComPtr<IGuest> pGuest;
1801 rc = console->COMGETTER(Guest)(pGuest.asOutParam());
1802 if (SUCCEEDED(rc))
1803 {
1804 if (!pGuest)
1805 {
1806 RTMsgError("Guest not running");
1807 rc = E_FAIL;
1808 break;
1809 }
1810 CHECK_ERROR(pGuest, COMSETTER(MemoryBalloonSize)(uVal));
1811 }
1812 }
1813 else if (!strcmp(a->argv[1], "teleport"))
1814 {
1815 Bstr bstrHostname;
1816 uint32_t uMaxDowntime = 250 /*ms*/;
1817 uint32_t uPort = UINT32_MAX;
1818 uint32_t cMsTimeout = 0;
1819 Utf8Str strPassword;
1820 static const RTGETOPTDEF s_aTeleportOptions[] =
1821 {
1822 { "--host", 'h', RTGETOPT_REQ_STRING }, /** @todo RTGETOPT_FLAG_MANDATORY */
1823 { "--hostname", 'h', RTGETOPT_REQ_STRING }, /** @todo remove this */
1824 { "--maxdowntime", 'd', RTGETOPT_REQ_UINT32 },
1825 { "--port", 'P', RTGETOPT_REQ_UINT32 }, /** @todo RTGETOPT_FLAG_MANDATORY */
1826 { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
1827 { "--password", 'W', RTGETOPT_REQ_STRING },
1828 { "--timeout", 't', RTGETOPT_REQ_UINT32 },
1829 { "--detailed-progress", 'D', RTGETOPT_REQ_NOTHING }
1830 };
1831 RTGETOPTSTATE GetOptState;
1832 RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTeleportOptions, RT_ELEMENTS(s_aTeleportOptions), 2, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1833 int ch;
1834 RTGETOPTUNION Value;
1835 while ( SUCCEEDED(rc)
1836 && (ch = RTGetOpt(&GetOptState, &Value)))
1837 {
1838 switch (ch)
1839 {
1840 case 'h': bstrHostname = Value.psz; break;
1841 case 'd': uMaxDowntime = Value.u32; break;
1842 case 'D': g_fDetailedProgress = true; break;
1843 case 'P': uPort = Value.u32; break;
1844 case 'p':
1845 {
1846 RTEXITCODE rcExit = readPasswordFile(Value.psz, &strPassword);
1847 if (rcExit != RTEXITCODE_SUCCESS)
1848 rc = E_FAIL;
1849 break;
1850 }
1851 case 'W': strPassword = Value.psz; break;
1852 case 't': cMsTimeout = Value.u32; break;
1853 default:
1854 errorGetOpt(USAGE_CONTROLVM, ch, &Value);
1855 rc = E_FAIL;
1856 break;
1857 }
1858 }
1859 if (FAILED(rc))
1860 break;
1861
1862 ComPtr<IProgress> progress;
1863 CHECK_ERROR_BREAK(console, Teleport(bstrHostname.raw(), uPort,
1864 Bstr(strPassword).raw(),
1865 uMaxDowntime,
1866 progress.asOutParam()));
1867
1868 if (cMsTimeout)
1869 {
1870 rc = progress->COMSETTER(Timeout)(cMsTimeout);
1871 if (FAILED(rc) && rc != VBOX_E_INVALID_OBJECT_STATE)
1872 CHECK_ERROR_BREAK(progress, COMSETTER(Timeout)(cMsTimeout)); /* lazyness */
1873 }
1874
1875 rc = showProgress(progress);
1876 CHECK_PROGRESS_ERROR(progress, ("Teleportation failed"));
1877 }
1878 else if (!strcmp(a->argv[1], "screenshotpng"))
1879 {
1880 if (a->argc <= 2 || a->argc > 4)
1881 {
1882 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1883 rc = E_FAIL;
1884 break;
1885 }
1886 int vrc;
1887 uint32_t iScreen = 0;
1888 if (a->argc == 4)
1889 {
1890 vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &iScreen);
1891 if (vrc != VINF_SUCCESS)
1892 {
1893 errorArgument("Error parsing display number '%s'", a->argv[3]);
1894 rc = E_FAIL;
1895 break;
1896 }
1897 }
1898 ComPtr<IDisplay> pDisplay;
1899 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1900 if (!pDisplay)
1901 {
1902 RTMsgError("Guest not running");
1903 rc = E_FAIL;
1904 break;
1905 }
1906 ULONG width, height, bpp;
1907 LONG xOrigin, yOrigin;
1908 GuestMonitorStatus_T monitorStatus;
1909 CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(iScreen, &width, &height, &bpp, &xOrigin, &yOrigin, &monitorStatus));
1910 com::SafeArray<BYTE> saScreenshot;
1911 CHECK_ERROR_BREAK(pDisplay, TakeScreenShotToArray(iScreen, width, height, BitmapFormat_PNG, ComSafeArrayAsOutParam(saScreenshot)));
1912 RTFILE pngFile = NIL_RTFILE;
1913 vrc = RTFileOpen(&pngFile, a->argv[2], RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_TRUNCATE | RTFILE_O_DENY_ALL);
1914 if (RT_FAILURE(vrc))
1915 {
1916 RTMsgError("Failed to create file '%s' (%Rrc)", a->argv[2], vrc);
1917 rc = E_FAIL;
1918 break;
1919 }
1920 vrc = RTFileWrite(pngFile, saScreenshot.raw(), saScreenshot.size(), NULL);
1921 if (RT_FAILURE(vrc))
1922 {
1923 RTMsgError("Failed to write screenshot to file '%s' (%Rrc)", a->argv[2], vrc);
1924 rc = E_FAIL;
1925 }
1926 RTFileClose(pngFile);
1927 }
1928#ifdef VBOX_WITH_RECORDING
1929 else if ( !strcmp(a->argv[1], "recording")
1930 || !strcmp(a->argv[1], "videocap") /* legacy command */)
1931 {
1932 if (a->argc < 3)
1933 {
1934 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1935 rc = E_FAIL;
1936 break;
1937 }
1938
1939 ComPtr<IRecordingSettings> recordingSettings;
1940 CHECK_ERROR_BREAK(sessionMachine, COMGETTER(RecordingSettings)(recordingSettings.asOutParam()));
1941
1942 SafeIfaceArray <IRecordingScreenSettings> saRecordingScreenScreens;
1943 CHECK_ERROR_BREAK(recordingSettings, COMGETTER(Screens)(ComSafeArrayAsOutParam(saRecordingScreenScreens)));
1944
1945 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
1946 CHECK_ERROR_BREAK(sessionMachine, COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam()));
1947
1948 /* Note: For now all screens have the same configuration. */
1949
1950 /*
1951 * Note: Commands starting with "vcp" are the deprecated versions and are
1952 * kept to ensure backwards compatibility.
1953 */
1954 if (!strcmp(a->argv[2], "on"))
1955 {
1956 CHECK_ERROR_RET(recordingSettings, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE);
1957 }
1958 else if (!strcmp(a->argv[2], "off"))
1959 {
1960 CHECK_ERROR_RET(recordingSettings, COMSETTER(Enabled)(FALSE), RTEXITCODE_FAILURE);
1961 }
1962 else if (!strcmp(a->argv[2], "screens"))
1963 {
1964 ULONG cMonitors = 64;
1965 CHECK_ERROR_BREAK(pGraphicsAdapter, COMGETTER(MonitorCount)(&cMonitors));
1966 com::SafeArray<BOOL> saScreens(cMonitors);
1967 if ( a->argc == 4
1968 && !strcmp(a->argv[3], "all"))
1969 {
1970 /* enable all screens */
1971 for (unsigned i = 0; i < cMonitors; i++)
1972 saScreens[i] = true;
1973 }
1974 else if ( a->argc == 4
1975 && !strcmp(a->argv[3], "none"))
1976 {
1977 /* disable all screens */
1978 for (unsigned i = 0; i < cMonitors; i++)
1979 saScreens[i] = false;
1980
1981 /** @todo r=andy What if this is specified? */
1982 }
1983 else
1984 {
1985 /* enable selected screens */
1986 for (unsigned i = 0; i < cMonitors; i++)
1987 saScreens[i] = false;
1988 for (int i = 3; SUCCEEDED(rc) && i < a->argc; i++)
1989 {
1990 uint32_t iScreen;
1991 int vrc = RTStrToUInt32Ex(a->argv[i], NULL, 0, &iScreen);
1992 if (vrc != VINF_SUCCESS)
1993 {
1994 errorArgument("Error parsing display number '%s'", a->argv[i]);
1995 rc = E_FAIL;
1996 break;
1997 }
1998 if (iScreen >= cMonitors)
1999 {
2000 errorArgument("Invalid screen ID specified '%u'", iScreen);
2001 rc = E_FAIL;
2002 break;
2003 }
2004 saScreens[iScreen] = true;
2005 }
2006 }
2007
2008 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
2009 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(Enabled)(saScreens[i]));
2010 }
2011 else if (!strcmp(a->argv[2], "filename"))
2012 {
2013 if (a->argc != 4)
2014 {
2015 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
2016 rc = E_FAIL;
2017 break;
2018 }
2019
2020 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
2021 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(Filename)(Bstr(a->argv[3]).raw()));
2022 }
2023 else if ( !strcmp(a->argv[2], "videores")
2024 || !strcmp(a->argv[2], "videoresolution"))
2025 {
2026 if (a->argc != 5)
2027 {
2028 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
2029 rc = E_FAIL;
2030 break;
2031 }
2032
2033 uint32_t uWidth;
2034 int vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uWidth);
2035 if (RT_FAILURE(vrc))
2036 {
2037 errorArgument("Error parsing video width '%s'", a->argv[3]);
2038 rc = E_FAIL;
2039 break;
2040 }
2041
2042 uint32_t uHeight;
2043 vrc = RTStrToUInt32Ex(a->argv[4], NULL, 0, &uHeight);
2044 if (RT_FAILURE(vrc))
2045 {
2046 errorArgument("Error parsing video height '%s'", a->argv[4]);
2047 rc = E_FAIL;
2048 break;
2049 }
2050
2051 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
2052 {
2053 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(VideoWidth)(uWidth));
2054 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(VideoHeight)(uHeight));
2055 }
2056 }
2057 else if (!strcmp(a->argv[2], "videorate"))
2058 {
2059 if (a->argc != 4)
2060 {
2061 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
2062 rc = E_FAIL;
2063 break;
2064 }
2065
2066 uint32_t uRate;
2067 int vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uRate);
2068 if (RT_FAILURE(vrc))
2069 {
2070 errorArgument("Error parsing video rate '%s'", a->argv[3]);
2071 rc = E_FAIL;
2072 break;
2073 }
2074
2075 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
2076 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(VideoRate)(uRate));
2077 }
2078 else if (!strcmp(a->argv[2], "videofps"))
2079 {
2080 if (a->argc != 4)
2081 {
2082 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
2083 rc = E_FAIL;
2084 break;
2085 }
2086
2087 uint32_t uFPS;
2088 int vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uFPS);
2089 if (RT_FAILURE(vrc))
2090 {
2091 errorArgument("Error parsing video FPS '%s'", a->argv[3]);
2092 rc = E_FAIL;
2093 break;
2094 }
2095
2096 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
2097 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(VideoFPS)(uFPS));
2098 }
2099 else if (!strcmp(a->argv[2], "maxtime"))
2100 {
2101 if (a->argc != 4)
2102 {
2103 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
2104 rc = E_FAIL;
2105 break;
2106 }
2107
2108 uint32_t uMaxTime;
2109 int vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uMaxTime);
2110 if (RT_FAILURE(vrc))
2111 {
2112 errorArgument("Error parsing maximum time '%s'", a->argv[3]);
2113 rc = E_FAIL;
2114 break;
2115 }
2116
2117 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
2118 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(MaxTime)(uMaxTime));
2119 }
2120 else if (!strcmp(a->argv[2], "maxfilesize"))
2121 {
2122 if (a->argc != 4)
2123 {
2124 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
2125 rc = E_FAIL;
2126 break;
2127 }
2128
2129 uint32_t uMaxFileSize;
2130 int vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uMaxFileSize);
2131 if (RT_FAILURE(vrc))
2132 {
2133 errorArgument("Error parsing maximum file size '%s'", a->argv[3]);
2134 rc = E_FAIL;
2135 break;
2136 }
2137
2138 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
2139 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(MaxFileSize)(uMaxFileSize));
2140 }
2141 else if (!strcmp(a->argv[2], "opts"))
2142 {
2143 if (a->argc != 4)
2144 {
2145 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
2146 rc = E_FAIL;
2147 break;
2148 }
2149
2150 for (size_t i = 0; i < saRecordingScreenScreens.size(); ++i)
2151 CHECK_ERROR_BREAK(saRecordingScreenScreens[i], COMSETTER(Options)(Bstr(a->argv[3]).raw()));
2152 }
2153 }
2154#endif /* VBOX_WITH_RECORDING */
2155 else if (!strcmp(a->argv[1], "webcam"))
2156 {
2157 if (a->argc < 3)
2158 {
2159 errorArgument("Missing argument to '%s'", a->argv[1]);
2160 rc = E_FAIL;
2161 break;
2162 }
2163
2164 ComPtr<IEmulatedUSB> pEmulatedUSB;
2165 CHECK_ERROR_BREAK(console, COMGETTER(EmulatedUSB)(pEmulatedUSB.asOutParam()));
2166 if (!pEmulatedUSB)
2167 {
2168 RTMsgError("Guest not running");
2169 rc = E_FAIL;
2170 break;
2171 }
2172
2173 if (!strcmp(a->argv[2], "attach"))
2174 {
2175 Bstr path("");
2176 if (a->argc >= 4)
2177 path = a->argv[3];
2178 Bstr settings("");
2179 if (a->argc >= 5)
2180 settings = a->argv[4];
2181 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamAttach(path.raw(), settings.raw()));
2182 }
2183 else if (!strcmp(a->argv[2], "detach"))
2184 {
2185 Bstr path("");
2186 if (a->argc >= 4)
2187 path = a->argv[3];
2188 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamDetach(path.raw()));
2189 }
2190 else if (!strcmp(a->argv[2], "list"))
2191 {
2192 com::SafeArray <BSTR> webcams;
2193 CHECK_ERROR_BREAK(pEmulatedUSB, COMGETTER(Webcams)(ComSafeArrayAsOutParam(webcams)));
2194 for (size_t i = 0; i < webcams.size(); ++i)
2195 {
2196 RTPrintf("%ls\n", webcams[i][0]? webcams[i]: Bstr("default").raw());
2197 }
2198 }
2199 else
2200 {
2201 errorArgument("Invalid argument to '%s'", a->argv[1]);
2202 rc = E_FAIL;
2203 break;
2204 }
2205 }
2206 else if (!strcmp(a->argv[1], "addencpassword"))
2207 {
2208 if ( a->argc != 4
2209 && a->argc != 6)
2210 {
2211 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
2212 break;
2213 }
2214
2215 BOOL fRemoveOnSuspend = FALSE;
2216 if (a->argc == 6)
2217 {
2218 if ( strcmp(a->argv[4], "--removeonsuspend")
2219 || ( strcmp(a->argv[5], "yes")
2220 && strcmp(a->argv[5], "no")))
2221 {
2222 errorSyntax(USAGE_CONTROLVM, "Invalid parameters");
2223 break;
2224 }
2225 if (!strcmp(a->argv[5], "yes"))
2226 fRemoveOnSuspend = TRUE;
2227 }
2228
2229 Bstr bstrPwId(a->argv[2]);
2230 Utf8Str strPassword;
2231
2232 if (!RTStrCmp(a->argv[3], "-"))
2233 {
2234 /* Get password from console. */
2235 RTEXITCODE rcExit = readPasswordFromConsole(&strPassword, "Enter password:");
2236 if (rcExit == RTEXITCODE_FAILURE)
2237 break;
2238 }
2239 else
2240 {
2241 RTEXITCODE rcExit = readPasswordFile(a->argv[3], &strPassword);
2242 if (rcExit == RTEXITCODE_FAILURE)
2243 {
2244 RTMsgError("Failed to read new password from file");
2245 break;
2246 }
2247 }
2248
2249 CHECK_ERROR_BREAK(console, AddDiskEncryptionPassword(bstrPwId.raw(), Bstr(strPassword).raw(), fRemoveOnSuspend));
2250 }
2251 else if (!strcmp(a->argv[1], "removeencpassword"))
2252 {
2253 if (a->argc != 3)
2254 {
2255 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
2256 break;
2257 }
2258 Bstr bstrPwId(a->argv[2]);
2259 CHECK_ERROR_BREAK(console, RemoveDiskEncryptionPassword(bstrPwId.raw()));
2260 }
2261 else if (!strcmp(a->argv[1], "removeallencpasswords"))
2262 {
2263 CHECK_ERROR_BREAK(console, ClearAllDiskEncryptionPasswords());
2264 }
2265 else if (!strncmp(a->argv[1], "changeuartmode", 14))
2266 {
2267 unsigned n = parseNum(&a->argv[1][14], 4, "UART");
2268 if (!n)
2269 {
2270 rc = E_FAIL;
2271 break;
2272 }
2273 if (a->argc < 3)
2274 {
2275 errorArgument("Missing argument to '%s'", a->argv[1]);
2276 rc = E_FAIL;
2277 break;
2278 }
2279
2280 ComPtr<ISerialPort> uart;
2281
2282 CHECK_ERROR_BREAK(sessionMachine, GetSerialPort(n - 1, uart.asOutParam()));
2283 ASSERT(uart);
2284
2285 if (!RTStrICmp(a->argv[2], "disconnected"))
2286 {
2287 if (a->argc != 3)
2288 {
2289 errorArgument("Incorrect arguments to '%s'", a->argv[1]);
2290 rc = E_FAIL;
2291 break;
2292 }
2293 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_Disconnected));
2294 }
2295 else if ( !RTStrICmp(a->argv[2], "server")
2296 || !RTStrICmp(a->argv[2], "client")
2297 || !RTStrICmp(a->argv[2], "tcpserver")
2298 || !RTStrICmp(a->argv[2], "tcpclient")
2299 || !RTStrICmp(a->argv[2], "file"))
2300 {
2301 const char *pszMode = a->argv[2];
2302 if (a->argc != 4)
2303 {
2304 errorArgument("Incorrect arguments to '%s'", a->argv[1]);
2305 rc = E_FAIL;
2306 break;
2307 }
2308
2309 CHECK_ERROR(uart, COMSETTER(Path)(Bstr(a->argv[3]).raw()));
2310
2311 /*
2312 * Change to disconnected first to get changes in just a parameter causing
2313 * the correct changes later on.
2314 */
2315 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_Disconnected));
2316 if (!RTStrICmp(pszMode, "server"))
2317 {
2318 CHECK_ERROR(uart, COMSETTER(Server)(TRUE));
2319 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_HostPipe));
2320 }
2321 else if (!RTStrICmp(pszMode, "client"))
2322 {
2323 CHECK_ERROR(uart, COMSETTER(Server)(FALSE));
2324 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_HostPipe));
2325 }
2326 else if (!RTStrICmp(pszMode, "tcpserver"))
2327 {
2328 CHECK_ERROR(uart, COMSETTER(Server)(TRUE));
2329 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_TCP));
2330 }
2331 else if (!RTStrICmp(pszMode, "tcpclient"))
2332 {
2333 CHECK_ERROR(uart, COMSETTER(Server)(FALSE));
2334 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_TCP));
2335 }
2336 else if (!RTStrICmp(pszMode, "file"))
2337 {
2338 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_RawFile));
2339 }
2340 }
2341 else
2342 {
2343 if (a->argc != 3)
2344 {
2345 errorArgument("Incorrect arguments to '%s'", a->argv[1]);
2346 rc = E_FAIL;
2347 break;
2348 }
2349 CHECK_ERROR(uart, COMSETTER(Path)(Bstr(a->argv[2]).raw()));
2350 CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_HostDevice));
2351 }
2352 }
2353 else if (!strncmp(a->argv[1], "vm-process-priority", 14))
2354 {
2355 if (a->argc != 3)
2356 {
2357 errorArgument("Incorrect arguments to '%s'", a->argv[1]);
2358 rc = E_FAIL;
2359 break;
2360 }
2361 VMProcPriority_T enmPriority = nameToVMProcPriority(a->argv[2]);
2362 if (enmPriority == VMProcPriority_Invalid)
2363 {
2364 errorArgument("Invalid vm-process-priority '%s'", a->argv[2]);
2365 rc = E_FAIL;
2366 }
2367 else
2368 {
2369 CHECK_ERROR(sessionMachine, COMSETTER(VMProcessPriority)(enmPriority));
2370 }
2371 break;
2372 }
2373 else
2374 {
2375 errorSyntax(USAGE_CONTROLVM, "Invalid parameter '%s'", a->argv[1]);
2376 rc = E_FAIL;
2377 }
2378 } while (0);
2379
2380 /* The client has to trigger saving the state explicitely. */
2381 if (fNeedsSaving)
2382 CHECK_ERROR(sessionMachine, SaveSettings());
2383
2384 a->session->UnlockMachine();
2385
2386 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2387}
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