VirtualBox

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

Last change on this file since 92742 was 92594, checked in by vboxsync, 3 years ago

Main: bugref:1909: Added translation into VBoxManage excluding built-in docbook help. Fixed translation marks in the VBoxManage

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