VirtualBox

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

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

Shared Clipboard/Transfers: Added controlvm/modifyvm options for enabling/disabling the clipboard file transfers.

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