VirtualBox

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

Last change on this file since 67954 was 67564, checked in by vboxsync, 7 years ago

VBoxManage: fixed 'VBoxManage controlvm videocapfile'

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 76.9 KB
Line 
1/* $Id: VBoxManageControlVM.cpp 67564 2017-06-22 14:39:12Z vboxsync $ */
2/** @file
3 * VBoxManage - Implementation of the controlvm command.
4 */
5
6/*
7 * Copyright (C) 2006-2017 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 <VBox/err.h>
32#include <iprt/getopt.h>
33#include <iprt/stream.h>
34#include <iprt/string.h>
35#include <iprt/thread.h>
36#include <iprt/uuid.h>
37#include <iprt/file.h>
38#include <VBox/log.h>
39
40#include "VBoxManage.h"
41
42#include <list>
43
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.size() > 0)
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 = RTFileGetSize(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 /* ... and session machine */
398 CHECK_ERROR_BREAK(a->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
399
400 if (!console)
401 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Machine '%s' is not currently running", a->argv[0]);
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], "clipboard"))
456 {
457 if (a->argc <= 1 + 1)
458 {
459 errorArgument("Missing argument to '%s'. Expected clipboard mode.", a->argv[1]);
460 rc = E_FAIL;
461 break;
462 }
463
464 ClipboardMode_T mode = ClipboardMode_Disabled; /* Shut up MSC */
465 if (!strcmp(a->argv[2], "disabled"))
466 mode = ClipboardMode_Disabled;
467 else if (!strcmp(a->argv[2], "hosttoguest"))
468 mode = ClipboardMode_HostToGuest;
469 else if (!strcmp(a->argv[2], "guesttohost"))
470 mode = ClipboardMode_GuestToHost;
471 else if (!strcmp(a->argv[2], "bidirectional"))
472 mode = ClipboardMode_Bidirectional;
473 else
474 {
475 errorArgument("Invalid '%s' argument '%s'.", a->argv[1], a->argv[2]);
476 rc = E_FAIL;
477 }
478 if (SUCCEEDED(rc))
479 {
480 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(ClipboardMode)(mode));
481 if (SUCCEEDED(rc))
482 fNeedsSaving = true;
483 }
484 }
485 else if (!strcmp(a->argv[1], "draganddrop"))
486 {
487 if (a->argc <= 1 + 1)
488 {
489 errorArgument("Missing argument to '%s'. Expected drag and drop mode.", a->argv[1]);
490 rc = E_FAIL;
491 break;
492 }
493
494 DnDMode_T mode = DnDMode_Disabled; /* Shup up MSC. */
495 if (!strcmp(a->argv[2], "disabled"))
496 mode = DnDMode_Disabled;
497 else if (!strcmp(a->argv[2], "hosttoguest"))
498 mode = DnDMode_HostToGuest;
499 else if (!strcmp(a->argv[2], "guesttohost"))
500 mode = DnDMode_GuestToHost;
501 else if (!strcmp(a->argv[2], "bidirectional"))
502 mode = DnDMode_Bidirectional;
503 else
504 {
505 errorArgument("Invalid '%s' argument '%s'.", a->argv[1], a->argv[2]);
506 rc = E_FAIL;
507 }
508 if (SUCCEEDED(rc))
509 {
510 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(DnDMode)(mode));
511 if (SUCCEEDED(rc))
512 fNeedsSaving = true;
513 }
514 }
515 else if (!strcmp(a->argv[1], "poweroff"))
516 {
517 ComPtr<IProgress> progress;
518 CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam()));
519
520 rc = showProgress(progress);
521 CHECK_PROGRESS_ERROR(progress, ("Failed to power off machine"));
522 }
523 else if (!strcmp(a->argv[1], "savestate"))
524 {
525 /* first pause so we don't trigger a live save which needs more time/resources */
526 bool fPaused = false;
527 rc = console->Pause();
528 if (FAILED(rc))
529 {
530 bool fError = true;
531 if (rc == VBOX_E_INVALID_VM_STATE)
532 {
533 /* check if we are already paused */
534 MachineState_T machineState;
535 CHECK_ERROR_BREAK(console, COMGETTER(State)(&machineState));
536 /* the error code was lost by the previous instruction */
537 rc = VBOX_E_INVALID_VM_STATE;
538 if (machineState != MachineState_Paused)
539 {
540 RTMsgError("Machine in invalid state %d -- %s\n",
541 machineState, machineStateToName(machineState, false));
542 }
543 else
544 {
545 fError = false;
546 fPaused = true;
547 }
548 }
549 if (fError)
550 break;
551 }
552
553 ComPtr<IProgress> progress;
554 CHECK_ERROR(sessionMachine, SaveState(progress.asOutParam()));
555 if (FAILED(rc))
556 {
557 if (!fPaused)
558 console->Resume();
559 break;
560 }
561
562 rc = showProgress(progress);
563 CHECK_PROGRESS_ERROR(progress, ("Failed to save machine state"));
564 if (FAILED(rc))
565 {
566 if (!fPaused)
567 console->Resume();
568 }
569 }
570 else if (!strcmp(a->argv[1], "acpipowerbutton"))
571 {
572 CHECK_ERROR_BREAK(console, PowerButton());
573 }
574 else if (!strcmp(a->argv[1], "acpisleepbutton"))
575 {
576 CHECK_ERROR_BREAK(console, SleepButton());
577 }
578 else if (!strcmp(a->argv[1], "keyboardputscancode"))
579 {
580 ComPtr<IKeyboard> pKeyboard;
581 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
582 if (!pKeyboard)
583 {
584 RTMsgError("Guest not running");
585 rc = E_FAIL;
586 break;
587 }
588
589 if (a->argc <= 1 + 1)
590 {
591 errorArgument("Missing argument to '%s'. Expected IBM PC AT set 2 keyboard scancode(s) as hex byte(s).", a->argv[1]);
592 rc = E_FAIL;
593 break;
594 }
595
596 std::list<LONG> llScancodes;
597
598 /* Process the command line. */
599 int i;
600 for (i = 1 + 1; i < a->argc; i++)
601 {
602 if ( RT_C_IS_XDIGIT (a->argv[i][0])
603 && RT_C_IS_XDIGIT (a->argv[i][1])
604 && a->argv[i][2] == 0)
605 {
606 uint8_t u8Scancode;
607 int irc = RTStrToUInt8Ex(a->argv[i], NULL, 16, &u8Scancode);
608 if (RT_FAILURE (irc))
609 {
610 RTMsgError("Converting '%s' returned %Rrc!", a->argv[i], rc);
611 rc = E_FAIL;
612 break;
613 }
614
615 llScancodes.push_back(u8Scancode);
616 }
617 else
618 {
619 RTMsgError("Error: '%s' is not a hex byte!", a->argv[i]);
620 rc = E_FAIL;
621 break;
622 }
623 }
624
625 if (FAILED(rc))
626 break;
627
628 rc = keyboardPutScancodes(pKeyboard, llScancodes);
629 }
630 else if (!strcmp(a->argv[1], "keyboardputstring"))
631 {
632 ComPtr<IKeyboard> pKeyboard;
633 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
634 if (!pKeyboard)
635 {
636 RTMsgError("Guest not running");
637 rc = E_FAIL;
638 break;
639 }
640
641 if (a->argc <= 1 + 1)
642 {
643 errorArgument("Missing argument to '%s'. Expected ASCII string(s).", a->argv[1]);
644 rc = E_FAIL;
645 break;
646 }
647
648 rc = keyboardPutString(pKeyboard, a->argc, a->argv);
649 }
650 else if (!strcmp(a->argv[1], "keyboardputfile"))
651 {
652 ComPtr<IKeyboard> pKeyboard;
653 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
654 if (!pKeyboard)
655 {
656 RTMsgError("Guest not running");
657 rc = E_FAIL;
658 break;
659 }
660
661 if (a->argc <= 1 + 1)
662 {
663 errorArgument("Missing argument to '%s'. Expected file name.", a->argv[1]);
664 rc = E_FAIL;
665 break;
666 }
667
668 rc = keyboardPutFile(pKeyboard, a->argv[2]);
669 }
670 else if (!strncmp(a->argv[1], "setlinkstate", 12))
671 {
672 /* Get the number of network adapters */
673 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
674 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
675 if (!n)
676 {
677 rc = E_FAIL;
678 break;
679 }
680 if (a->argc <= 1 + 1)
681 {
682 errorArgument("Missing argument to '%s'", a->argv[1]);
683 rc = E_FAIL;
684 break;
685 }
686 /* get the corresponding network adapter */
687 ComPtr<INetworkAdapter> adapter;
688 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
689 if (adapter)
690 {
691 if (!strcmp(a->argv[2], "on"))
692 {
693 CHECK_ERROR_BREAK(adapter, COMSETTER(CableConnected)(TRUE));
694 }
695 else if (!strcmp(a->argv[2], "off"))
696 {
697 CHECK_ERROR_BREAK(adapter, COMSETTER(CableConnected)(FALSE));
698 }
699 else
700 {
701 errorArgument("Invalid link state '%s'", Utf8Str(a->argv[2]).c_str());
702 rc = E_FAIL;
703 break;
704 }
705 if (SUCCEEDED(rc))
706 fNeedsSaving = true;
707 }
708 }
709 /* here the order in which strncmp is called is important
710 * cause nictracefile can be very well compared with
711 * nictrace and nic and thus everything will always fail
712 * if the order is changed
713 */
714 else if (!strncmp(a->argv[1], "nictracefile", 12))
715 {
716 /* Get the number of network adapters */
717 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
718 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
719 if (!n)
720 {
721 rc = E_FAIL;
722 break;
723 }
724 if (a->argc <= 2)
725 {
726 errorArgument("Missing argument to '%s'", a->argv[1]);
727 rc = E_FAIL;
728 break;
729 }
730
731 /* get the corresponding network adapter */
732 ComPtr<INetworkAdapter> adapter;
733 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
734 if (adapter)
735 {
736 BOOL fEnabled;
737 adapter->COMGETTER(Enabled)(&fEnabled);
738 if (fEnabled)
739 {
740 if (a->argv[2])
741 {
742 CHECK_ERROR_RET(adapter, COMSETTER(TraceFile)(Bstr(a->argv[2]).raw()), RTEXITCODE_FAILURE);
743 }
744 else
745 {
746 errorArgument("Invalid filename or filename not specified for NIC %lu", n);
747 rc = E_FAIL;
748 break;
749 }
750 if (SUCCEEDED(rc))
751 fNeedsSaving = true;
752 }
753 else
754 RTMsgError("The NIC %d is currently disabled and thus its tracefile can't be changed", n);
755 }
756 }
757 else if (!strncmp(a->argv[1], "nictrace", 8))
758 {
759 /* Get the number of network adapters */
760 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
761 unsigned n = parseNum(&a->argv[1][8], NetworkAdapterCount, "NIC");
762 if (!n)
763 {
764 rc = E_FAIL;
765 break;
766 }
767 if (a->argc <= 2)
768 {
769 errorArgument("Missing argument to '%s'", a->argv[1]);
770 rc = E_FAIL;
771 break;
772 }
773
774 /* get the corresponding network adapter */
775 ComPtr<INetworkAdapter> adapter;
776 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
777 if (adapter)
778 {
779 BOOL fEnabled;
780 adapter->COMGETTER(Enabled)(&fEnabled);
781 if (fEnabled)
782 {
783 if (!strcmp(a->argv[2], "on"))
784 {
785 CHECK_ERROR_RET(adapter, COMSETTER(TraceEnabled)(TRUE), RTEXITCODE_FAILURE);
786 }
787 else if (!strcmp(a->argv[2], "off"))
788 {
789 CHECK_ERROR_RET(adapter, COMSETTER(TraceEnabled)(FALSE), RTEXITCODE_FAILURE);
790 }
791 else
792 {
793 errorArgument("Invalid nictrace%lu argument '%s'", n, Utf8Str(a->argv[2]).c_str());
794 rc = E_FAIL;
795 break;
796 }
797 if (SUCCEEDED(rc))
798 fNeedsSaving = true;
799 }
800 else
801 RTMsgError("The NIC %d is currently disabled and thus its trace flag can't be changed", n);
802 }
803 }
804 else if( a->argc > 2
805 && !strncmp(a->argv[1], "natpf", 5))
806 {
807 /* Get the number of network adapters */
808 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
809 unsigned n = parseNum(&a->argv[1][5], NetworkAdapterCount, "NIC");
810 if (!n)
811 {
812 rc = E_FAIL;
813 break;
814 }
815 if (a->argc <= 2)
816 {
817 errorArgument("Missing argument to '%s'", a->argv[1]);
818 rc = E_FAIL;
819 break;
820 }
821
822 /* get the corresponding network adapter */
823 ComPtr<INetworkAdapter> adapter;
824 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
825 if (!adapter)
826 {
827 rc = E_FAIL;
828 break;
829 }
830 ComPtr<INATEngine> engine;
831 CHECK_ERROR(adapter, COMGETTER(NATEngine)(engine.asOutParam()));
832 if (!engine)
833 {
834 rc = E_FAIL;
835 break;
836 }
837
838 if (!strcmp(a->argv[2], "delete"))
839 {
840 if (a->argc >= 3)
841 CHECK_ERROR(engine, RemoveRedirect(Bstr(a->argv[3]).raw()));
842 }
843 else
844 {
845#define ITERATE_TO_NEXT_TERM(ch) \
846 do { \
847 while (*ch != ',') \
848 { \
849 if (*ch == 0) \
850 { \
851 return errorSyntax(USAGE_CONTROLVM, \
852 "Missing or invalid argument to '%s'", \
853 a->argv[1]); \
854 } \
855 ch++; \
856 } \
857 *ch = '\0'; \
858 ch++; \
859 } while(0)
860
861 char *strName;
862 char *strProto;
863 char *strHostIp;
864 char *strHostPort;
865 char *strGuestIp;
866 char *strGuestPort;
867 char *strRaw = RTStrDup(a->argv[2]);
868 char *ch = strRaw;
869 strName = RTStrStrip(ch);
870 ITERATE_TO_NEXT_TERM(ch);
871 strProto = RTStrStrip(ch);
872 ITERATE_TO_NEXT_TERM(ch);
873 strHostIp = RTStrStrip(ch);
874 ITERATE_TO_NEXT_TERM(ch);
875 strHostPort = RTStrStrip(ch);
876 ITERATE_TO_NEXT_TERM(ch);
877 strGuestIp = RTStrStrip(ch);
878 ITERATE_TO_NEXT_TERM(ch);
879 strGuestPort = RTStrStrip(ch);
880 NATProtocol_T proto;
881 if (RTStrICmp(strProto, "udp") == 0)
882 proto = NATProtocol_UDP;
883 else if (RTStrICmp(strProto, "tcp") == 0)
884 proto = NATProtocol_TCP;
885 else
886 {
887 return errorSyntax(USAGE_CONTROLVM,
888 "Wrong rule proto '%s' specified -- only 'udp' and 'tcp' are allowed.",
889 strProto);
890 }
891 CHECK_ERROR(engine, AddRedirect(Bstr(strName).raw(), proto, Bstr(strHostIp).raw(),
892 RTStrToUInt16(strHostPort), Bstr(strGuestIp).raw(), RTStrToUInt16(strGuestPort)));
893#undef ITERATE_TO_NEXT_TERM
894 }
895 if (SUCCEEDED(rc))
896 fNeedsSaving = true;
897 }
898 else if (!strncmp(a->argv[1], "nicproperty", 11))
899 {
900 /* Get the number of network adapters */
901 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
902 unsigned n = parseNum(&a->argv[1][11], NetworkAdapterCount, "NIC");
903 if (!n)
904 {
905 rc = E_FAIL;
906 break;
907 }
908 if (a->argc <= 2)
909 {
910 errorArgument("Missing argument to '%s'", a->argv[1]);
911 rc = E_FAIL;
912 break;
913 }
914
915 /* get the corresponding network adapter */
916 ComPtr<INetworkAdapter> adapter;
917 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
918 if (adapter)
919 {
920 BOOL fEnabled;
921 adapter->COMGETTER(Enabled)(&fEnabled);
922 if (fEnabled)
923 {
924 /* Parse 'name=value' */
925 char *pszProperty = RTStrDup(a->argv[2]);
926 if (pszProperty)
927 {
928 char *pDelimiter = strchr(pszProperty, '=');
929 if (pDelimiter)
930 {
931 *pDelimiter = '\0';
932
933 Bstr bstrName = pszProperty;
934 Bstr bstrValue = &pDelimiter[1];
935 CHECK_ERROR(adapter, SetProperty(bstrName.raw(), bstrValue.raw()));
936 if (SUCCEEDED(rc))
937 fNeedsSaving = true;
938 }
939 else
940 {
941 errorArgument("Invalid nicproperty%d argument '%s'", n, a->argv[2]);
942 rc = E_FAIL;
943 }
944 RTStrFree(pszProperty);
945 }
946 else
947 {
948 RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for nicproperty%d '%s'\n", n, a->argv[2]);
949 rc = E_FAIL;
950 }
951 if (FAILED(rc))
952 break;
953 }
954 else
955 RTMsgError("The NIC %d is currently disabled and thus its properties can't be changed", n);
956 }
957 }
958 else if (!strncmp(a->argv[1], "nicpromisc", 10))
959 {
960 /* Get the number of network adapters */
961 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
962 unsigned n = parseNum(&a->argv[1][10], NetworkAdapterCount, "NIC");
963 if (!n)
964 {
965 rc = E_FAIL;
966 break;
967 }
968 if (a->argc <= 2)
969 {
970 errorArgument("Missing argument to '%s'", a->argv[1]);
971 rc = E_FAIL;
972 break;
973 }
974
975 /* get the corresponding network adapter */
976 ComPtr<INetworkAdapter> adapter;
977 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
978 if (adapter)
979 {
980 BOOL fEnabled;
981 adapter->COMGETTER(Enabled)(&fEnabled);
982 if (fEnabled)
983 {
984 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
985 if (!strcmp(a->argv[2], "deny"))
986 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_Deny;
987 else if ( !strcmp(a->argv[2], "allow-vms")
988 || !strcmp(a->argv[2], "allow-network"))
989 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowNetwork;
990 else if (!strcmp(a->argv[2], "allow-all"))
991 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowAll;
992 else
993 {
994 errorArgument("Unknown promiscuous mode policy '%s'", a->argv[2]);
995 rc = E_INVALIDARG;
996 break;
997 }
998
999 CHECK_ERROR(adapter, COMSETTER(PromiscModePolicy)(enmPromiscModePolicy));
1000 if (SUCCEEDED(rc))
1001 fNeedsSaving = true;
1002 }
1003 else
1004 RTMsgError("The NIC %d is currently disabled and thus its promiscuous mode can't be changed", n);
1005 }
1006 }
1007 else if (!strncmp(a->argv[1], "nic", 3))
1008 {
1009 /* Get the number of network adapters */
1010 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
1011 unsigned n = parseNum(&a->argv[1][3], NetworkAdapterCount, "NIC");
1012 if (!n)
1013 {
1014 rc = E_FAIL;
1015 break;
1016 }
1017 if (a->argc <= 2)
1018 {
1019 errorArgument("Missing argument to '%s'", a->argv[1]);
1020 rc = E_FAIL;
1021 break;
1022 }
1023
1024 /* get the corresponding network adapter */
1025 ComPtr<INetworkAdapter> adapter;
1026 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
1027 if (adapter)
1028 {
1029 BOOL fEnabled;
1030 adapter->COMGETTER(Enabled)(&fEnabled);
1031 if (fEnabled)
1032 {
1033 if (!strcmp(a->argv[2], "null"))
1034 {
1035 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Null), RTEXITCODE_FAILURE);
1036 }
1037 else if (!strcmp(a->argv[2], "nat"))
1038 {
1039 if (a->argc == 4)
1040 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1041 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_NAT), RTEXITCODE_FAILURE);
1042 }
1043 else if ( !strcmp(a->argv[2], "bridged")
1044 || !strcmp(a->argv[2], "hostif")) /* backward compatibility */
1045 {
1046 if (a->argc <= 3)
1047 {
1048 errorArgument("Missing argument to '%s'", a->argv[2]);
1049 rc = E_FAIL;
1050 break;
1051 }
1052 CHECK_ERROR_RET(adapter, COMSETTER(BridgedInterface)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1053 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Bridged), RTEXITCODE_FAILURE);
1054 }
1055 else if (!strcmp(a->argv[2], "intnet"))
1056 {
1057 if (a->argc <= 3)
1058 {
1059 errorArgument("Missing argument to '%s'", a->argv[2]);
1060 rc = E_FAIL;
1061 break;
1062 }
1063 CHECK_ERROR_RET(adapter, COMSETTER(InternalNetwork)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1064 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Internal), RTEXITCODE_FAILURE);
1065 }
1066#if defined(VBOX_WITH_NETFLT)
1067 else if (!strcmp(a->argv[2], "hostonly"))
1068 {
1069 if (a->argc <= 3)
1070 {
1071 errorArgument("Missing argument to '%s'", a->argv[2]);
1072 rc = E_FAIL;
1073 break;
1074 }
1075 CHECK_ERROR_RET(adapter, COMSETTER(HostOnlyInterface)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1076 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_HostOnly), RTEXITCODE_FAILURE);
1077 }
1078#endif
1079 else if (!strcmp(a->argv[2], "generic"))
1080 {
1081 if (a->argc <= 3)
1082 {
1083 errorArgument("Missing argument to '%s'", a->argv[2]);
1084 rc = E_FAIL;
1085 break;
1086 }
1087 CHECK_ERROR_RET(adapter, COMSETTER(GenericDriver)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1088 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic), RTEXITCODE_FAILURE);
1089 }
1090 else if (!strcmp(a->argv[2], "natnetwork"))
1091 {
1092 if (a->argc <= 3)
1093 {
1094 errorArgument("Missing argument to '%s'", a->argv[2]);
1095 rc = E_FAIL;
1096 break;
1097 }
1098 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1099 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_NATNetwork), RTEXITCODE_FAILURE);
1100 }
1101 /** @todo obsolete, remove eventually */
1102 else if (!strcmp(a->argv[2], "vde"))
1103 {
1104 if (a->argc <= 3)
1105 {
1106 errorArgument("Missing argument to '%s'", a->argv[2]);
1107 rc = E_FAIL;
1108 break;
1109 }
1110 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic), RTEXITCODE_FAILURE);
1111 CHECK_ERROR_RET(adapter, SetProperty(Bstr("name").raw(), Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
1112 }
1113 else
1114 {
1115 errorArgument("Invalid type '%s' specfied for NIC %lu", Utf8Str(a->argv[2]).c_str(), n);
1116 rc = E_FAIL;
1117 break;
1118 }
1119 if (SUCCEEDED(rc))
1120 fNeedsSaving = true;
1121 }
1122 else
1123 RTMsgError("The NIC %d is currently disabled and thus its attachment type can't be changed", n);
1124 }
1125 }
1126 else if ( !strcmp(a->argv[1], "vrde")
1127 || !strcmp(a->argv[1], "vrdp"))
1128 {
1129 if (!strcmp(a->argv[1], "vrdp"))
1130 RTStrmPrintf(g_pStdErr, "Warning: 'vrdp' is deprecated. Use 'vrde'.\n");
1131
1132 if (a->argc <= 1 + 1)
1133 {
1134 errorArgument("Missing argument to '%s'", a->argv[1]);
1135 rc = E_FAIL;
1136 break;
1137 }
1138 ComPtr<IVRDEServer> vrdeServer;
1139 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1140 ASSERT(vrdeServer);
1141 if (vrdeServer)
1142 {
1143 if (!strcmp(a->argv[2], "on"))
1144 {
1145 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(TRUE));
1146 }
1147 else if (!strcmp(a->argv[2], "off"))
1148 {
1149 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(FALSE));
1150 }
1151 else
1152 {
1153 errorArgument("Invalid remote desktop server state '%s'", Utf8Str(a->argv[2]).c_str());
1154 rc = E_FAIL;
1155 break;
1156 }
1157 if (SUCCEEDED(rc))
1158 fNeedsSaving = true;
1159 }
1160 }
1161 else if ( !strcmp(a->argv[1], "vrdeport")
1162 || !strcmp(a->argv[1], "vrdpport"))
1163 {
1164 if (!strcmp(a->argv[1], "vrdpport"))
1165 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpport' is deprecated. Use 'vrdeport'.\n");
1166
1167 if (a->argc <= 1 + 1)
1168 {
1169 errorArgument("Missing argument to '%s'", a->argv[1]);
1170 rc = E_FAIL;
1171 break;
1172 }
1173
1174 ComPtr<IVRDEServer> vrdeServer;
1175 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1176 ASSERT(vrdeServer);
1177 if (vrdeServer)
1178 {
1179 Bstr ports;
1180
1181 if (!strcmp(a->argv[2], "default"))
1182 ports = "0";
1183 else
1184 ports = a->argv[2];
1185
1186 CHECK_ERROR_BREAK(vrdeServer, SetVRDEProperty(Bstr("TCP/Ports").raw(), ports.raw()));
1187 if (SUCCEEDED(rc))
1188 fNeedsSaving = true;
1189 }
1190 }
1191 else if ( !strcmp(a->argv[1], "vrdevideochannelquality")
1192 || !strcmp(a->argv[1], "vrdpvideochannelquality"))
1193 {
1194 if (!strcmp(a->argv[1], "vrdpvideochannelquality"))
1195 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpvideochannelquality' is deprecated. Use 'vrdevideochannelquality'.\n");
1196
1197 if (a->argc <= 1 + 1)
1198 {
1199 errorArgument("Missing argument to '%s'", a->argv[1]);
1200 rc = E_FAIL;
1201 break;
1202 }
1203 ComPtr<IVRDEServer> vrdeServer;
1204 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1205 ASSERT(vrdeServer);
1206 if (vrdeServer)
1207 {
1208 Bstr value = a->argv[2];
1209
1210 CHECK_ERROR(vrdeServer, SetVRDEProperty(Bstr("VideoChannel/Quality").raw(), value.raw()));
1211 if (SUCCEEDED(rc))
1212 fNeedsSaving = true;
1213 }
1214 }
1215 else if (!strcmp(a->argv[1], "vrdeproperty"))
1216 {
1217 if (a->argc <= 1 + 1)
1218 {
1219 errorArgument("Missing argument to '%s'", a->argv[1]);
1220 rc = E_FAIL;
1221 break;
1222 }
1223 ComPtr<IVRDEServer> vrdeServer;
1224 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1225 ASSERT(vrdeServer);
1226 if (vrdeServer)
1227 {
1228 /* Parse 'name=value' */
1229 char *pszProperty = RTStrDup(a->argv[2]);
1230 if (pszProperty)
1231 {
1232 char *pDelimiter = strchr(pszProperty, '=');
1233 if (pDelimiter)
1234 {
1235 *pDelimiter = '\0';
1236
1237 Bstr bstrName = pszProperty;
1238 Bstr bstrValue = &pDelimiter[1];
1239 CHECK_ERROR(vrdeServer, SetVRDEProperty(bstrName.raw(), bstrValue.raw()));
1240 if (SUCCEEDED(rc))
1241 fNeedsSaving = true;
1242 }
1243 else
1244 {
1245 errorArgument("Invalid vrdeproperty argument '%s'", a->argv[2]);
1246 rc = E_FAIL;
1247 }
1248 RTStrFree(pszProperty);
1249 }
1250 else
1251 {
1252 RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for VRDE property '%s'\n", a->argv[2]);
1253 rc = E_FAIL;
1254 }
1255 }
1256 if (FAILED(rc))
1257 {
1258 break;
1259 }
1260 }
1261 else if ( !strcmp(a->argv[1], "usbattach")
1262 || !strcmp(a->argv[1], "usbdetach"))
1263 {
1264 if (a->argc < 3)
1265 {
1266 errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
1267 rc = E_FAIL;
1268 break;
1269 }
1270 else if (a->argc == 4 || a->argc > 5)
1271 {
1272 errorSyntax(USAGE_CONTROLVM, "Wrong number of arguments");
1273 rc = E_FAIL;
1274 break;
1275 }
1276
1277 bool attach = !strcmp(a->argv[1], "usbattach");
1278
1279 Bstr usbId = a->argv[2];
1280 Bstr captureFilename;
1281
1282 if (a->argc == 5)
1283 {
1284 if (!strcmp(a->argv[3], "--capturefile"))
1285 captureFilename = a->argv[4];
1286 else
1287 {
1288 errorArgument("Invalid parameter '%s'", a->argv[3]);
1289 rc = E_FAIL;
1290 break;
1291 }
1292 }
1293
1294 Guid guid(usbId);
1295 if (!guid.isValid())
1296 {
1297 // assume address
1298 if (attach)
1299 {
1300 ComPtr<IHost> host;
1301 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1302 SafeIfaceArray <IHostUSBDevice> coll;
1303 CHECK_ERROR_BREAK(host, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
1304 ComPtr<IHostUSBDevice> dev;
1305 CHECK_ERROR_BREAK(host, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
1306 dev.asOutParam()));
1307 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
1308 }
1309 else
1310 {
1311 SafeIfaceArray <IUSBDevice> coll;
1312 CHECK_ERROR_BREAK(console, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
1313 ComPtr<IUSBDevice> dev;
1314 CHECK_ERROR_BREAK(console, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
1315 dev.asOutParam()));
1316 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
1317 }
1318 }
1319 else if (guid.isZero())
1320 {
1321 errorArgument("Zero UUID argument '%s'", a->argv[2]);
1322 rc = E_FAIL;
1323 break;
1324 }
1325
1326 if (attach)
1327 CHECK_ERROR_BREAK(console, AttachUSBDevice(usbId.raw(), captureFilename.raw()));
1328 else
1329 {
1330 ComPtr<IUSBDevice> dev;
1331 CHECK_ERROR_BREAK(console, DetachUSBDevice(usbId.raw(),
1332 dev.asOutParam()));
1333 }
1334 }
1335 else if (!strcmp(a->argv[1], "setvideomodehint"))
1336 {
1337 if (a->argc != 5 && a->argc != 6 && a->argc != 7 && a->argc != 9)
1338 {
1339 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1340 rc = E_FAIL;
1341 break;
1342 }
1343 bool fEnabled = true;
1344 uint32_t uXRes = RTStrToUInt32(a->argv[2]);
1345 uint32_t uYRes = RTStrToUInt32(a->argv[3]);
1346 uint32_t uBpp = RTStrToUInt32(a->argv[4]);
1347 uint32_t uDisplayIdx = 0;
1348 bool fChangeOrigin = false;
1349 int32_t iOriginX = 0;
1350 int32_t iOriginY = 0;
1351 if (a->argc >= 6)
1352 uDisplayIdx = RTStrToUInt32(a->argv[5]);
1353 if (a->argc >= 7)
1354 {
1355 int vrc = parseBool(a->argv[6], &fEnabled);
1356 if (RT_FAILURE(vrc))
1357 {
1358 errorSyntax(USAGE_CONTROLVM, "Either \"yes\" or \"no\" is expected");
1359 rc = E_FAIL;
1360 break;
1361 }
1362 fEnabled = !RTStrICmp(a->argv[6], "yes");
1363 }
1364 if (a->argc == 9)
1365 {
1366 iOriginX = RTStrToInt32(a->argv[7]);
1367 iOriginY = RTStrToInt32(a->argv[8]);
1368 fChangeOrigin = true;
1369 }
1370
1371 ComPtr<IDisplay> pDisplay;
1372 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1373 if (!pDisplay)
1374 {
1375 RTMsgError("Guest not running");
1376 rc = E_FAIL;
1377 break;
1378 }
1379 CHECK_ERROR_BREAK(pDisplay, SetVideoModeHint(uDisplayIdx, fEnabled,
1380 fChangeOrigin, iOriginX, iOriginY,
1381 uXRes, uYRes, uBpp));
1382 }
1383 else if (!strcmp(a->argv[1], "setcredentials"))
1384 {
1385 bool fAllowLocalLogon = true;
1386 if ( a->argc == 7
1387 || ( a->argc == 8
1388 && ( !strcmp(a->argv[3], "-p")
1389 || !strcmp(a->argv[3], "--passwordfile"))))
1390 {
1391 if ( strcmp(a->argv[5 + (a->argc - 7)], "--allowlocallogon")
1392 && strcmp(a->argv[5 + (a->argc - 7)], "-allowlocallogon"))
1393 {
1394 errorArgument("Invalid parameter '%s'", a->argv[5]);
1395 rc = E_FAIL;
1396 break;
1397 }
1398 if (!strcmp(a->argv[6 + (a->argc - 7)], "no"))
1399 fAllowLocalLogon = false;
1400 }
1401 else if ( a->argc != 5
1402 && ( a->argc != 6
1403 || ( strcmp(a->argv[3], "-p")
1404 && strcmp(a->argv[3], "--passwordfile"))))
1405 {
1406 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1407 rc = E_FAIL;
1408 break;
1409 }
1410 Utf8Str passwd, domain;
1411 if (a->argc == 5 || a->argc == 7)
1412 {
1413 passwd = a->argv[3];
1414 domain = a->argv[4];
1415 }
1416 else
1417 {
1418 RTEXITCODE rcExit = readPasswordFile(a->argv[4], &passwd);
1419 if (rcExit != RTEXITCODE_SUCCESS)
1420 {
1421 rc = E_FAIL;
1422 break;
1423 }
1424 domain = a->argv[5];
1425 }
1426
1427 ComPtr<IGuest> pGuest;
1428 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest.asOutParam()));
1429 if (!pGuest)
1430 {
1431 RTMsgError("Guest not running");
1432 rc = E_FAIL;
1433 break;
1434 }
1435 CHECK_ERROR_BREAK(pGuest, SetCredentials(Bstr(a->argv[2]).raw(),
1436 Bstr(passwd).raw(),
1437 Bstr(domain).raw(),
1438 fAllowLocalLogon));
1439 }
1440#if 0 /** @todo review & remove */
1441 else if (!strcmp(a->argv[1], "dvdattach"))
1442 {
1443 Bstr uuid;
1444 if (a->argc != 3)
1445 {
1446 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1447 rc = E_FAIL;
1448 break;
1449 }
1450
1451 ComPtr<IMedium> dvdMedium;
1452
1453 /* unmount? */
1454 if (!strcmp(a->argv[2], "none"))
1455 {
1456 /* nothing to do, NULL object will cause unmount */
1457 }
1458 /* host drive? */
1459 else if (!strncmp(a->argv[2], "host:", 5))
1460 {
1461 ComPtr<IHost> host;
1462 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1463
1464 rc = host->FindHostDVDDrive(Bstr(a->argv[2] + 5), dvdMedium.asOutParam());
1465 if (!dvdMedium)
1466 {
1467 errorArgument("Invalid host DVD drive name \"%s\"",
1468 a->argv[2] + 5);
1469 rc = E_FAIL;
1470 break;
1471 }
1472 }
1473 else
1474 {
1475 /* first assume it's a UUID */
1476 uuid = a->argv[2];
1477 rc = a->virtualBox->GetDVDImage(uuid, dvdMedium.asOutParam());
1478 if (FAILED(rc) || !dvdMedium)
1479 {
1480 /* must be a filename, check if it's in the collection */
1481 rc = a->virtualBox->FindDVDImage(Bstr(a->argv[2]), dvdMedium.asOutParam());
1482 /* not registered, do that on the fly */
1483 if (!dvdMedium)
1484 {
1485 Bstr emptyUUID;
1486 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(a->argv[2]), emptyUUID, dvdMedium.asOutParam()));
1487 }
1488 }
1489 if (!dvdMedium)
1490 {
1491 rc = E_FAIL;
1492 break;
1493 }
1494 }
1495
1496 /** @todo generalize this, allow arbitrary number of DVD drives
1497 * and as a consequence multiple attachments and different
1498 * storage controllers. */
1499 if (dvdMedium)
1500 dvdMedium->COMGETTER(Id)(uuid.asOutParam());
1501 else
1502 uuid = Guid().toString();
1503 CHECK_ERROR(machine, MountMedium(Bstr("IDE Controller"), 1, 0, uuid, FALSE /* aForce */));
1504 }
1505 else if (!strcmp(a->argv[1], "floppyattach"))
1506 {
1507 Bstr uuid;
1508 if (a->argc != 3)
1509 {
1510 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1511 rc = E_FAIL;
1512 break;
1513 }
1514
1515 ComPtr<IMedium> floppyMedium;
1516
1517 /* unmount? */
1518 if (!strcmp(a->argv[2], "none"))
1519 {
1520 /* nothing to do, NULL object will cause unmount */
1521 }
1522 /* host drive? */
1523 else if (!strncmp(a->argv[2], "host:", 5))
1524 {
1525 ComPtr<IHost> host;
1526 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1527 host->FindHostFloppyDrive(Bstr(a->argv[2] + 5), floppyMedium.asOutParam());
1528 if (!floppyMedium)
1529 {
1530 errorArgument("Invalid host floppy drive name \"%s\"",
1531 a->argv[2] + 5);
1532 rc = E_FAIL;
1533 break;
1534 }
1535 }
1536 else
1537 {
1538 /* first assume it's a UUID */
1539 uuid = a->argv[2];
1540 rc = a->virtualBox->GetFloppyImage(uuid, floppyMedium.asOutParam());
1541 if (FAILED(rc) || !floppyMedium)
1542 {
1543 /* must be a filename, check if it's in the collection */
1544 rc = a->virtualBox->FindFloppyImage(Bstr(a->argv[2]), floppyMedium.asOutParam());
1545 /* not registered, do that on the fly */
1546 if (!floppyMedium)
1547 {
1548 Bstr emptyUUID;
1549 CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(a->argv[2]), emptyUUID, floppyMedium.asOutParam()));
1550 }
1551 }
1552 if (!floppyMedium)
1553 {
1554 rc = E_FAIL;
1555 break;
1556 }
1557 }
1558 floppyMedium->COMGETTER(Id)(uuid.asOutParam());
1559 CHECK_ERROR(machine, MountMedium(Bstr("Floppy Controller"), 0, 0, uuid, FALSE /* aForce */));
1560 }
1561#endif /* obsolete dvdattach/floppyattach */
1562 else if (!strcmp(a->argv[1], "guestmemoryballoon"))
1563 {
1564 if (a->argc != 3)
1565 {
1566 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1567 rc = E_FAIL;
1568 break;
1569 }
1570 uint32_t uVal;
1571 int vrc;
1572 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1573 if (vrc != VINF_SUCCESS)
1574 {
1575 errorArgument("Error parsing guest memory balloon size '%s'", a->argv[2]);
1576 rc = E_FAIL;
1577 break;
1578 }
1579 /* guest is running; update IGuest */
1580 ComPtr<IGuest> pGuest;
1581 rc = console->COMGETTER(Guest)(pGuest.asOutParam());
1582 if (SUCCEEDED(rc))
1583 {
1584 if (!pGuest)
1585 {
1586 RTMsgError("Guest not running");
1587 rc = E_FAIL;
1588 break;
1589 }
1590 CHECK_ERROR(pGuest, COMSETTER(MemoryBalloonSize)(uVal));
1591 }
1592 }
1593 else if (!strcmp(a->argv[1], "teleport"))
1594 {
1595 Bstr bstrHostname;
1596 uint32_t uMaxDowntime = 250 /*ms*/;
1597 uint32_t uPort = UINT32_MAX;
1598 uint32_t cMsTimeout = 0;
1599 Utf8Str strPassword;
1600 static const RTGETOPTDEF s_aTeleportOptions[] =
1601 {
1602 { "--host", 'h', RTGETOPT_REQ_STRING }, /** @todo RTGETOPT_FLAG_MANDATORY */
1603 { "--hostname", 'h', RTGETOPT_REQ_STRING }, /** @todo remove this */
1604 { "--maxdowntime", 'd', RTGETOPT_REQ_UINT32 },
1605 { "--port", 'P', RTGETOPT_REQ_UINT32 }, /** @todo RTGETOPT_FLAG_MANDATORY */
1606 { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
1607 { "--password", 'W', RTGETOPT_REQ_STRING },
1608 { "--timeout", 't', RTGETOPT_REQ_UINT32 },
1609 { "--detailed-progress", 'D', RTGETOPT_REQ_NOTHING }
1610 };
1611 RTGETOPTSTATE GetOptState;
1612 RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTeleportOptions, RT_ELEMENTS(s_aTeleportOptions), 2, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1613 int ch;
1614 RTGETOPTUNION Value;
1615 while ( SUCCEEDED(rc)
1616 && (ch = RTGetOpt(&GetOptState, &Value)))
1617 {
1618 switch (ch)
1619 {
1620 case 'h': bstrHostname = Value.psz; break;
1621 case 'd': uMaxDowntime = Value.u32; break;
1622 case 'D': g_fDetailedProgress = true; break;
1623 case 'P': uPort = Value.u32; break;
1624 case 'p':
1625 {
1626 RTEXITCODE rcExit = readPasswordFile(Value.psz, &strPassword);
1627 if (rcExit != RTEXITCODE_SUCCESS)
1628 rc = E_FAIL;
1629 break;
1630 }
1631 case 'W': strPassword = Value.psz; break;
1632 case 't': cMsTimeout = Value.u32; break;
1633 default:
1634 errorGetOpt(USAGE_CONTROLVM, ch, &Value);
1635 rc = E_FAIL;
1636 break;
1637 }
1638 }
1639 if (FAILED(rc))
1640 break;
1641
1642 ComPtr<IProgress> progress;
1643 CHECK_ERROR_BREAK(console, Teleport(bstrHostname.raw(), uPort,
1644 Bstr(strPassword).raw(),
1645 uMaxDowntime,
1646 progress.asOutParam()));
1647
1648 if (cMsTimeout)
1649 {
1650 rc = progress->COMSETTER(Timeout)(cMsTimeout);
1651 if (FAILED(rc) && rc != VBOX_E_INVALID_OBJECT_STATE)
1652 CHECK_ERROR_BREAK(progress, COMSETTER(Timeout)(cMsTimeout)); /* lazyness */
1653 }
1654
1655 rc = showProgress(progress);
1656 CHECK_PROGRESS_ERROR(progress, ("Teleportation failed"));
1657 }
1658 else if (!strcmp(a->argv[1], "screenshotpng"))
1659 {
1660 if (a->argc <= 2 || a->argc > 4)
1661 {
1662 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1663 rc = E_FAIL;
1664 break;
1665 }
1666 int vrc;
1667 uint32_t iScreen = 0;
1668 if (a->argc == 4)
1669 {
1670 vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &iScreen);
1671 if (vrc != VINF_SUCCESS)
1672 {
1673 errorArgument("Error parsing display number '%s'", a->argv[3]);
1674 rc = E_FAIL;
1675 break;
1676 }
1677 }
1678 ComPtr<IDisplay> pDisplay;
1679 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1680 if (!pDisplay)
1681 {
1682 RTMsgError("Guest not running");
1683 rc = E_FAIL;
1684 break;
1685 }
1686 ULONG width, height, bpp;
1687 LONG xOrigin, yOrigin;
1688 GuestMonitorStatus_T monitorStatus;
1689 CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(iScreen, &width, &height, &bpp, &xOrigin, &yOrigin, &monitorStatus));
1690 com::SafeArray<BYTE> saScreenshot;
1691 CHECK_ERROR_BREAK(pDisplay, TakeScreenShotToArray(iScreen, width, height, BitmapFormat_PNG, ComSafeArrayAsOutParam(saScreenshot)));
1692 RTFILE pngFile = NIL_RTFILE;
1693 vrc = RTFileOpen(&pngFile, a->argv[2], RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_TRUNCATE | RTFILE_O_DENY_ALL);
1694 if (RT_FAILURE(vrc))
1695 {
1696 RTMsgError("Failed to create file '%s' (%Rrc)", a->argv[2], vrc);
1697 rc = E_FAIL;
1698 break;
1699 }
1700 vrc = RTFileWrite(pngFile, saScreenshot.raw(), saScreenshot.size(), NULL);
1701 if (RT_FAILURE(vrc))
1702 {
1703 RTMsgError("Failed to write screenshot to file '%s' (%Rrc)", a->argv[2], vrc);
1704 rc = E_FAIL;
1705 }
1706 RTFileClose(pngFile);
1707 }
1708#ifdef VBOX_WITH_VIDEOREC
1709 /*
1710 * Note: Commands starting with "vcp" are the deprecated versions and are
1711 * kept to ensure backwards compatibility.
1712 */
1713 else if ( !strcmp(a->argv[1], "videocap")
1714 || !strcmp(a->argv[1], "vcpenabled"))
1715 {
1716 if (a->argc != 3)
1717 {
1718 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1719 rc = E_FAIL;
1720 break;
1721 }
1722 if (!strcmp(a->argv[2], "on"))
1723 {
1724 CHECK_ERROR_RET(sessionMachine, COMSETTER(VideoCaptureEnabled)(TRUE), RTEXITCODE_FAILURE);
1725 }
1726 else if (!strcmp(a->argv[2], "off"))
1727 {
1728 CHECK_ERROR_RET(sessionMachine, COMSETTER(VideoCaptureEnabled)(FALSE), RTEXITCODE_FAILURE);
1729 }
1730 else
1731 {
1732 errorArgument("Invalid state '%s'", Utf8Str(a->argv[2]).c_str());
1733 rc = E_FAIL;
1734 break;
1735 }
1736 }
1737 else if ( !strcmp(a->argv[1], "videocapscreens")
1738 || !strcmp(a->argv[1], "vcpscreens"))
1739 {
1740 ULONG cMonitors = 64;
1741 CHECK_ERROR_BREAK(machine, COMGETTER(MonitorCount)(&cMonitors));
1742 com::SafeArray<BOOL> saScreens(cMonitors);
1743 if ( a->argc == 3
1744 && !strcmp(a->argv[2], "all"))
1745 {
1746 /* enable all screens */
1747 for (unsigned i = 0; i < cMonitors; i++)
1748 saScreens[i] = true;
1749 }
1750 else if ( a->argc == 3
1751 && !strcmp(a->argv[2], "none"))
1752 {
1753 /* disable all screens */
1754 for (unsigned i = 0; i < cMonitors; i++)
1755 saScreens[i] = false;
1756
1757 /** @todo r=andy What if this is specified? */
1758 }
1759 else
1760 {
1761 /* enable selected screens */
1762 for (unsigned i = 0; i < cMonitors; i++)
1763 saScreens[i] = false;
1764 for (int i = 2; SUCCEEDED(rc) && i < a->argc; i++)
1765 {
1766 uint32_t iScreen;
1767 int vrc = RTStrToUInt32Ex(a->argv[i], NULL, 0, &iScreen);
1768 if (vrc != VINF_SUCCESS)
1769 {
1770 errorArgument("Error parsing display number '%s'", a->argv[i]);
1771 rc = E_FAIL;
1772 break;
1773 }
1774 if (iScreen >= cMonitors)
1775 {
1776 errorArgument("Invalid screen ID specified '%u'", iScreen);
1777 rc = E_FAIL;
1778 break;
1779 }
1780 saScreens[iScreen] = true;
1781 }
1782 }
1783
1784 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureScreens)(ComSafeArrayAsInParam(saScreens)));
1785 }
1786 else if ( !strcmp(a->argv[1], "videocapfile")
1787 || !strcmp(a->argv[1], "vcpfile"))
1788 {
1789 if (a->argc != 3)
1790 {
1791 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1792 rc = E_FAIL;
1793 break;
1794 }
1795
1796 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureFile)(Bstr(a->argv[2]).raw()));
1797 }
1798 else if (!strcmp(a->argv[1], "videocapres"))
1799 {
1800 if (a->argc != 4)
1801 {
1802 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1803 rc = E_FAIL;
1804 break;
1805 }
1806
1807 uint32_t uVal;
1808 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1809 if (RT_FAILURE(vrc))
1810 {
1811 errorArgument("Error parsing width '%s'", a->argv[2]);
1812 rc = E_FAIL;
1813 break;
1814 }
1815 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureWidth)(uVal));
1816
1817 vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uVal);
1818 if (RT_FAILURE(vrc))
1819 {
1820 errorArgument("Error parsing height '%s'", a->argv[3]);
1821 rc = E_FAIL;
1822 break;
1823 }
1824 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureHeight)(uVal));
1825 }
1826 else if (!strcmp(a->argv[1], "vcpwidth")) /* Deprecated; keeping for compatibility. */
1827 {
1828 uint32_t uVal;
1829 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1830 if (RT_FAILURE(vrc))
1831 {
1832 errorArgument("Error parsing width '%s'", a->argv[2]);
1833 rc = E_FAIL;
1834 break;
1835 }
1836 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureWidth)(uVal));
1837 }
1838 else if (!strcmp(a->argv[1], "vcpheight")) /* Deprecated; keeping for compatibility. */
1839 {
1840 uint32_t uVal;
1841 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1842 if (RT_FAILURE(vrc))
1843 {
1844 errorArgument("Error parsing height '%s'", a->argv[2]);
1845 rc = E_FAIL;
1846 break;
1847 }
1848 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureHeight)(uVal));
1849 }
1850 else if ( !strcmp(a->argv[1], "videocaprate")
1851 || !strcmp(a->argv[1], "vcprate"))
1852 {
1853 if (a->argc != 3)
1854 {
1855 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1856 rc = E_FAIL;
1857 break;
1858 }
1859
1860 uint32_t uVal;
1861 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1862 if (RT_FAILURE(vrc))
1863 {
1864 errorArgument("Error parsing rate '%s'", a->argv[2]);
1865 rc = E_FAIL;
1866 break;
1867 }
1868 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureRate)(uVal));
1869 }
1870 else if ( !strcmp(a->argv[1], "videocapfps")
1871 || !strcmp(a->argv[1], "vcpfps"))
1872 {
1873 if (a->argc != 3)
1874 {
1875 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1876 rc = E_FAIL;
1877 break;
1878 }
1879
1880 uint32_t uVal;
1881 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1882 if (RT_FAILURE(vrc))
1883 {
1884 errorArgument("Error parsing FPS '%s'", a->argv[2]);
1885 rc = E_FAIL;
1886 break;
1887 }
1888 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureFPS)(uVal));
1889 }
1890 else if ( !strcmp(a->argv[1], "videocapmaxtime")
1891 || !strcmp(a->argv[1], "vcpmaxtime"))
1892 {
1893 if (a->argc != 3)
1894 {
1895 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1896 rc = E_FAIL;
1897 break;
1898 }
1899
1900 uint32_t uVal;
1901 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1902 if (RT_FAILURE(vrc))
1903 {
1904 errorArgument("Error parsing maximum time '%s'", a->argv[2]);
1905 rc = E_FAIL;
1906 break;
1907 }
1908 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureMaxTime)(uVal));
1909 }
1910 else if ( !strcmp(a->argv[1], "videocapmaxsize")
1911 || !strcmp(a->argv[1], "vcpmaxsize"))
1912 {
1913 if (a->argc != 3)
1914 {
1915 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1916 rc = E_FAIL;
1917 break;
1918 }
1919
1920 uint32_t uVal;
1921 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1922 if (RT_FAILURE(vrc))
1923 {
1924 errorArgument("Error parsing maximum file size '%s'", a->argv[2]);
1925 rc = E_FAIL;
1926 break;
1927 }
1928 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureMaxFileSize)(uVal));
1929 }
1930 else if ( !strcmp(a->argv[1], "videocapopts")
1931 || !strcmp(a->argv[1], "vcpoptions"))
1932 {
1933 if (a->argc != 3)
1934 {
1935 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1936 rc = E_FAIL;
1937 break;
1938 }
1939
1940 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureOptions)(Bstr(a->argv[3]).raw()));
1941 }
1942#endif /* VBOX_WITH_VIDEOREC */
1943 else if (!strcmp(a->argv[1], "webcam"))
1944 {
1945 if (a->argc < 3)
1946 {
1947 errorArgument("Missing argument to '%s'", a->argv[1]);
1948 rc = E_FAIL;
1949 break;
1950 }
1951
1952 ComPtr<IEmulatedUSB> pEmulatedUSB;
1953 CHECK_ERROR_BREAK(console, COMGETTER(EmulatedUSB)(pEmulatedUSB.asOutParam()));
1954 if (!pEmulatedUSB)
1955 {
1956 RTMsgError("Guest not running");
1957 rc = E_FAIL;
1958 break;
1959 }
1960
1961 if (!strcmp(a->argv[2], "attach"))
1962 {
1963 Bstr path("");
1964 if (a->argc >= 4)
1965 path = a->argv[3];
1966 Bstr settings("");
1967 if (a->argc >= 5)
1968 settings = a->argv[4];
1969 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamAttach(path.raw(), settings.raw()));
1970 }
1971 else if (!strcmp(a->argv[2], "detach"))
1972 {
1973 Bstr path("");
1974 if (a->argc >= 4)
1975 path = a->argv[3];
1976 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamDetach(path.raw()));
1977 }
1978 else if (!strcmp(a->argv[2], "list"))
1979 {
1980 com::SafeArray <BSTR> webcams;
1981 CHECK_ERROR_BREAK(pEmulatedUSB, COMGETTER(Webcams)(ComSafeArrayAsOutParam(webcams)));
1982 for (size_t i = 0; i < webcams.size(); ++i)
1983 {
1984 RTPrintf("%ls\n", webcams[i][0]? webcams[i]: Bstr("default").raw());
1985 }
1986 }
1987 else
1988 {
1989 errorArgument("Invalid argument to '%s'", a->argv[1]);
1990 rc = E_FAIL;
1991 break;
1992 }
1993 }
1994 else if (!strcmp(a->argv[1], "addencpassword"))
1995 {
1996 if ( a->argc != 4
1997 && a->argc != 6)
1998 {
1999 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
2000 break;
2001 }
2002
2003 BOOL fRemoveOnSuspend = FALSE;
2004 if (a->argc == 6)
2005 {
2006 if ( strcmp(a->argv[4], "--removeonsuspend")
2007 || ( strcmp(a->argv[5], "yes")
2008 && strcmp(a->argv[5], "no")))
2009 {
2010 errorSyntax(USAGE_CONTROLVM, "Invalid parameters");
2011 break;
2012 }
2013 if (!strcmp(a->argv[5], "yes"))
2014 fRemoveOnSuspend = TRUE;
2015 }
2016
2017 Bstr bstrPwId(a->argv[2]);
2018 Utf8Str strPassword;
2019
2020 if (!RTStrCmp(a->argv[3], "-"))
2021 {
2022 /* Get password from console. */
2023 RTEXITCODE rcExit = readPasswordFromConsole(&strPassword, "Enter password:");
2024 if (rcExit == RTEXITCODE_FAILURE)
2025 break;
2026 }
2027 else
2028 {
2029 RTEXITCODE rcExit = readPasswordFile(a->argv[3], &strPassword);
2030 if (rcExit == RTEXITCODE_FAILURE)
2031 {
2032 RTMsgError("Failed to read new password from file");
2033 break;
2034 }
2035 }
2036
2037 CHECK_ERROR_BREAK(console, AddDiskEncryptionPassword(bstrPwId.raw(), Bstr(strPassword).raw(), fRemoveOnSuspend));
2038 }
2039 else if (!strcmp(a->argv[1], "removeencpassword"))
2040 {
2041 if (a->argc != 3)
2042 {
2043 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
2044 break;
2045 }
2046 Bstr bstrPwId(a->argv[2]);
2047 CHECK_ERROR_BREAK(console, RemoveDiskEncryptionPassword(bstrPwId.raw()));
2048 }
2049 else if (!strcmp(a->argv[1], "removeallencpasswords"))
2050 {
2051 CHECK_ERROR_BREAK(console, ClearAllDiskEncryptionPasswords());
2052 }
2053 else
2054 {
2055 errorSyntax(USAGE_CONTROLVM, "Invalid parameter '%s'", a->argv[1]);
2056 rc = E_FAIL;
2057 }
2058 } while (0);
2059
2060 /* The client has to trigger saving the state explicitely. */
2061 if (fNeedsSaving)
2062 CHECK_ERROR(sessionMachine, SaveSettings());
2063
2064 a->session->UnlockMachine();
2065
2066 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2067}
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