VirtualBox

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

Last change on this file since 91999 was 89597, checked in by vboxsync, 4 years ago

Main: bugref:9341: Added ability to change VM autostart options when VM is powered on

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

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