VirtualBox

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

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

Guest Control/VBoxManage: Made "controlvm [...] reboot|shutdown" commands conditional to VBOX_WITH_GUEST_CONTROL.

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