VirtualBox

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

Last change on this file since 56225 was 56119, checked in by vboxsync, 10 years ago

Don't use ISession::COMGETTER(Console) return without checking for NULL. Will crash if VM isn't running.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 65.8 KB
Line 
1/* $Id: VBoxManageControlVM.cpp 56119 2015-05-27 20:11:38Z vboxsync $ */
2/** @file
3 * VBoxManage - Implementation of the controlvm command.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <VBox/com/com.h>
23#include <VBox/com/string.h>
24#include <VBox/com/Guid.h>
25#include <VBox/com/array.h>
26#include <VBox/com/ErrorInfo.h>
27#include <VBox/com/errorprint.h>
28#include <VBox/com/VirtualBox.h>
29
30#include <iprt/ctype.h>
31#include <VBox/err.h>
32#include <iprt/getopt.h>
33#include <iprt/stream.h>
34#include <iprt/string.h>
35#include <iprt/uuid.h>
36#include <iprt/file.h>
37#include <VBox/log.h>
38
39#include "VBoxManage.h"
40
41#include <list>
42
43
44/**
45 * Parses a number.
46 *
47 * @returns Valid number on success.
48 * @returns 0 if invalid number. All necessary bitching has been done.
49 * @param psz Pointer to the nic number.
50 */
51static unsigned parseNum(const char *psz, unsigned cMaxNum, const char *name)
52{
53 uint32_t u32;
54 char *pszNext;
55 int rc = RTStrToUInt32Ex(psz, &pszNext, 10, &u32);
56 if ( RT_SUCCESS(rc)
57 && *pszNext == '\0'
58 && u32 >= 1
59 && u32 <= cMaxNum)
60 return (unsigned)u32;
61 errorArgument("Invalid %s number '%s'", name, psz);
62 return 0;
63}
64
65unsigned int getMaxNics(IVirtualBox* vbox, IMachine* mach)
66{
67 ComPtr<ISystemProperties> info;
68 ChipsetType_T aChipset;
69 ULONG NetworkAdapterCount = 0;
70 HRESULT rc;
71
72 do {
73 CHECK_ERROR_BREAK(vbox, COMGETTER(SystemProperties)(info.asOutParam()));
74 CHECK_ERROR_BREAK(mach, COMGETTER(ChipsetType)(&aChipset));
75 CHECK_ERROR_BREAK(info, GetMaxNetworkAdapters(aChipset, &NetworkAdapterCount));
76
77 return (unsigned int)NetworkAdapterCount;
78 } while (0);
79
80 return 0;
81}
82
83
84RTEXITCODE handleControlVM(HandlerArg *a)
85{
86 using namespace com;
87 bool fNeedsSaving = false;
88 HRESULT rc;
89
90 if (a->argc < 2)
91 return errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
92
93 /* try to find the given machine */
94 ComPtr<IMachine> machine;
95 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
96 machine.asOutParam()));
97 if (FAILED(rc))
98 return RTEXITCODE_FAILURE;
99
100 /* open a session for the VM */
101 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE);
102
103 ComPtr<IConsole> console;
104 ComPtr<IMachine> sessionMachine;
105
106 do
107 {
108 /* get the associated console */
109 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
110 /* ... and session machine */
111 CHECK_ERROR_BREAK(a->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
112
113 if (!console)
114 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Machine '%s' is not currently running", a->argv[0]);
115
116 /* which command? */
117 if (!strcmp(a->argv[1], "pause"))
118 {
119 CHECK_ERROR_BREAK(console, Pause());
120 }
121 else if (!strcmp(a->argv[1], "resume"))
122 {
123 CHECK_ERROR_BREAK(console, Resume());
124 }
125 else if (!strcmp(a->argv[1], "reset"))
126 {
127 CHECK_ERROR_BREAK(console, Reset());
128 }
129 else if (!strcmp(a->argv[1], "unplugcpu"))
130 {
131 if (a->argc <= 1 + 1)
132 {
133 errorArgument("Missing argument to '%s'. Expected CPU number.", a->argv[1]);
134 rc = E_FAIL;
135 break;
136 }
137
138 unsigned n = parseNum(a->argv[2], 32, "CPU");
139
140 CHECK_ERROR_BREAK(sessionMachine, HotUnplugCPU(n));
141 }
142 else if (!strcmp(a->argv[1], "plugcpu"))
143 {
144 if (a->argc <= 1 + 1)
145 {
146 errorArgument("Missing argument to '%s'. Expected CPU number.", a->argv[1]);
147 rc = E_FAIL;
148 break;
149 }
150
151 unsigned n = parseNum(a->argv[2], 32, "CPU");
152
153 CHECK_ERROR_BREAK(sessionMachine, HotPlugCPU(n));
154 }
155 else if (!strcmp(a->argv[1], "cpuexecutioncap"))
156 {
157 if (a->argc <= 1 + 1)
158 {
159 errorArgument("Missing argument to '%s'. Expected execution cap number.", a->argv[1]);
160 rc = E_FAIL;
161 break;
162 }
163
164 unsigned n = parseNum(a->argv[2], 100, "ExecutionCap");
165
166 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(CPUExecutionCap)(n));
167 }
168 else if (!strcmp(a->argv[1], "clipboard"))
169 {
170 if (a->argc <= 1 + 1)
171 {
172 errorArgument("Missing argument to '%s'. Expected clipboard mode.", a->argv[1]);
173 rc = E_FAIL;
174 break;
175 }
176
177 ClipboardMode_T mode;
178 if (!strcmp(a->argv[2], "disabled"))
179 mode = ClipboardMode_Disabled;
180 else if (!strcmp(a->argv[2], "hosttoguest"))
181 mode = ClipboardMode_HostToGuest;
182 else if (!strcmp(a->argv[2], "guesttohost"))
183 mode = ClipboardMode_GuestToHost;
184 else if (!strcmp(a->argv[2], "bidirectional"))
185 mode = ClipboardMode_Bidirectional;
186 else
187 {
188 errorArgument("Invalid '%s' argument '%s'.", a->argv[1], a->argv[2]);
189 rc = E_FAIL;
190 }
191 if (SUCCEEDED(rc))
192 {
193 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(ClipboardMode)(mode));
194 if (SUCCEEDED(rc))
195 fNeedsSaving = true;
196 }
197 }
198 else if (!strcmp(a->argv[1], "draganddrop"))
199 {
200 if (a->argc <= 1 + 1)
201 {
202 errorArgument("Missing argument to '%s'. Expected drag and drop mode.", a->argv[1]);
203 rc = E_FAIL;
204 break;
205 }
206
207 DnDMode_T mode;
208 if (!strcmp(a->argv[2], "disabled"))
209 mode = DnDMode_Disabled;
210 else if (!strcmp(a->argv[2], "hosttoguest"))
211 mode = DnDMode_HostToGuest;
212 else if (!strcmp(a->argv[2], "guesttohost"))
213 mode = DnDMode_GuestToHost;
214 else if (!strcmp(a->argv[2], "bidirectional"))
215 mode = DnDMode_Bidirectional;
216 else
217 {
218 errorArgument("Invalid '%s' argument '%s'.", a->argv[1], a->argv[2]);
219 rc = E_FAIL;
220 }
221 if (SUCCEEDED(rc))
222 {
223 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(DnDMode)(mode));
224 if (SUCCEEDED(rc))
225 fNeedsSaving = true;
226 }
227 }
228 else if (!strcmp(a->argv[1], "poweroff"))
229 {
230 ComPtr<IProgress> progress;
231 CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam()));
232
233 rc = showProgress(progress);
234 CHECK_PROGRESS_ERROR(progress, ("Failed to power off machine"));
235 }
236 else if (!strcmp(a->argv[1], "savestate"))
237 {
238 /* first pause so we don't trigger a live save which needs more time/resources */
239 bool fPaused = false;
240 rc = console->Pause();
241 if (FAILED(rc))
242 {
243 bool fError = true;
244 if (rc == VBOX_E_INVALID_VM_STATE)
245 {
246 /* check if we are already paused */
247 MachineState_T machineState;
248 CHECK_ERROR_BREAK(console, COMGETTER(State)(&machineState));
249 /* the error code was lost by the previous instruction */
250 rc = VBOX_E_INVALID_VM_STATE;
251 if (machineState != MachineState_Paused)
252 {
253 RTMsgError("Machine in invalid state %d -- %s\n",
254 machineState, machineStateToName(machineState, false));
255 }
256 else
257 {
258 fError = false;
259 fPaused = true;
260 }
261 }
262 if (fError)
263 break;
264 }
265
266 ComPtr<IProgress> progress;
267 CHECK_ERROR(sessionMachine, SaveState(progress.asOutParam()));
268 if (FAILED(rc))
269 {
270 if (!fPaused)
271 console->Resume();
272 break;
273 }
274
275 rc = showProgress(progress);
276 CHECK_PROGRESS_ERROR(progress, ("Failed to save machine state"));
277 if (FAILED(rc))
278 {
279 if (!fPaused)
280 console->Resume();
281 }
282 }
283 else if (!strcmp(a->argv[1], "acpipowerbutton"))
284 {
285 CHECK_ERROR_BREAK(console, PowerButton());
286 }
287 else if (!strcmp(a->argv[1], "acpisleepbutton"))
288 {
289 CHECK_ERROR_BREAK(console, SleepButton());
290 }
291 else if (!strcmp(a->argv[1], "keyboardputscancode"))
292 {
293 ComPtr<IKeyboard> pKeyboard;
294 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
295 if (!pKeyboard)
296 {
297 RTMsgError("Guest not running");
298 rc = E_FAIL;
299 break;
300 }
301
302 if (a->argc <= 1 + 1)
303 {
304 errorArgument("Missing argument to '%s'. Expected IBM PC AT set 2 keyboard scancode(s) as hex byte(s).", a->argv[1]);
305 rc = E_FAIL;
306 break;
307 }
308
309 std::list<LONG> llScancodes;
310
311 /* Process the command line. */
312 int i;
313 for (i = 1 + 1; i < a->argc; i++)
314 {
315 if ( RT_C_IS_XDIGIT (a->argv[i][0])
316 && RT_C_IS_XDIGIT (a->argv[i][1])
317 && a->argv[i][2] == 0)
318 {
319 uint8_t u8Scancode;
320 int irc = RTStrToUInt8Ex(a->argv[i], NULL, 16, &u8Scancode);
321 if (RT_FAILURE (irc))
322 {
323 RTMsgError("Converting '%s' returned %Rrc!", a->argv[i], rc);
324 rc = E_FAIL;
325 break;
326 }
327
328 llScancodes.push_back(u8Scancode);
329 }
330 else
331 {
332 RTMsgError("Error: '%s' is not a hex byte!", a->argv[i]);
333 rc = E_FAIL;
334 break;
335 }
336 }
337
338 if (FAILED(rc))
339 break;
340
341 /* Send scancodes to the VM. */
342 com::SafeArray<LONG> saScancodes(llScancodes);
343 ULONG codesStored = 0;
344 CHECK_ERROR_BREAK(pKeyboard, PutScancodes(ComSafeArrayAsInParam(saScancodes),
345 &codesStored));
346 if (codesStored < saScancodes.size())
347 {
348 RTMsgError("Only %d scancodes were stored", codesStored);
349 rc = E_FAIL;
350 break;
351 }
352 }
353 else if (!strncmp(a->argv[1], "setlinkstate", 12))
354 {
355 /* Get the number of network adapters */
356 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
357 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
358 if (!n)
359 {
360 rc = E_FAIL;
361 break;
362 }
363 if (a->argc <= 1 + 1)
364 {
365 errorArgument("Missing argument to '%s'", a->argv[1]);
366 rc = E_FAIL;
367 break;
368 }
369 /* get the corresponding network adapter */
370 ComPtr<INetworkAdapter> adapter;
371 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
372 if (adapter)
373 {
374 if (!strcmp(a->argv[2], "on"))
375 {
376 CHECK_ERROR_BREAK(adapter, COMSETTER(CableConnected)(TRUE));
377 }
378 else if (!strcmp(a->argv[2], "off"))
379 {
380 CHECK_ERROR_BREAK(adapter, COMSETTER(CableConnected)(FALSE));
381 }
382 else
383 {
384 errorArgument("Invalid link state '%s'", Utf8Str(a->argv[2]).c_str());
385 rc = E_FAIL;
386 break;
387 }
388 if (SUCCEEDED(rc))
389 fNeedsSaving = true;
390 }
391 }
392 /* here the order in which strncmp is called is important
393 * cause nictracefile can be very well compared with
394 * nictrace and nic and thus everything will always fail
395 * if the order is changed
396 */
397 else if (!strncmp(a->argv[1], "nictracefile", 12))
398 {
399 /* Get the number of network adapters */
400 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
401 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
402 if (!n)
403 {
404 rc = E_FAIL;
405 break;
406 }
407 if (a->argc <= 2)
408 {
409 errorArgument("Missing argument to '%s'", a->argv[1]);
410 rc = E_FAIL;
411 break;
412 }
413
414 /* get the corresponding network adapter */
415 ComPtr<INetworkAdapter> adapter;
416 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
417 if (adapter)
418 {
419 BOOL fEnabled;
420 adapter->COMGETTER(Enabled)(&fEnabled);
421 if (fEnabled)
422 {
423 if (a->argv[2])
424 {
425 CHECK_ERROR_RET(adapter, COMSETTER(TraceFile)(Bstr(a->argv[2]).raw()), RTEXITCODE_FAILURE);
426 }
427 else
428 {
429 errorArgument("Invalid filename or filename not specified for NIC %lu", n);
430 rc = E_FAIL;
431 break;
432 }
433 if (SUCCEEDED(rc))
434 fNeedsSaving = true;
435 }
436 else
437 RTMsgError("The NIC %d is currently disabled and thus its tracefile can't be changed", n);
438 }
439 }
440 else if (!strncmp(a->argv[1], "nictrace", 8))
441 {
442 /* Get the number of network adapters */
443 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
444 unsigned n = parseNum(&a->argv[1][8], NetworkAdapterCount, "NIC");
445 if (!n)
446 {
447 rc = E_FAIL;
448 break;
449 }
450 if (a->argc <= 2)
451 {
452 errorArgument("Missing argument to '%s'", a->argv[1]);
453 rc = E_FAIL;
454 break;
455 }
456
457 /* get the corresponding network adapter */
458 ComPtr<INetworkAdapter> adapter;
459 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
460 if (adapter)
461 {
462 BOOL fEnabled;
463 adapter->COMGETTER(Enabled)(&fEnabled);
464 if (fEnabled)
465 {
466 if (!strcmp(a->argv[2], "on"))
467 {
468 CHECK_ERROR_RET(adapter, COMSETTER(TraceEnabled)(TRUE), RTEXITCODE_FAILURE);
469 }
470 else if (!strcmp(a->argv[2], "off"))
471 {
472 CHECK_ERROR_RET(adapter, COMSETTER(TraceEnabled)(FALSE), RTEXITCODE_FAILURE);
473 }
474 else
475 {
476 errorArgument("Invalid nictrace%lu argument '%s'", n, Utf8Str(a->argv[2]).c_str());
477 rc = E_FAIL;
478 break;
479 }
480 if (SUCCEEDED(rc))
481 fNeedsSaving = true;
482 }
483 else
484 RTMsgError("The NIC %d is currently disabled and thus its trace flag can't be changed", n);
485 }
486 }
487 else if( a->argc > 2
488 && !strncmp(a->argv[1], "natpf", 5))
489 {
490 /* Get the number of network adapters */
491 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
492 unsigned n = parseNum(&a->argv[1][5], NetworkAdapterCount, "NIC");
493 if (!n)
494 {
495 rc = E_FAIL;
496 break;
497 }
498 if (a->argc <= 2)
499 {
500 errorArgument("Missing argument to '%s'", a->argv[1]);
501 rc = E_FAIL;
502 break;
503 }
504
505 /* get the corresponding network adapter */
506 ComPtr<INetworkAdapter> adapter;
507 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
508 if (!adapter)
509 {
510 rc = E_FAIL;
511 break;
512 }
513 ComPtr<INATEngine> engine;
514 CHECK_ERROR(adapter, COMGETTER(NATEngine)(engine.asOutParam()));
515 if (!engine)
516 {
517 rc = E_FAIL;
518 break;
519 }
520
521 if (!strcmp(a->argv[2], "delete"))
522 {
523 if (a->argc >= 3)
524 CHECK_ERROR(engine, RemoveRedirect(Bstr(a->argv[3]).raw()));
525 }
526 else
527 {
528#define ITERATE_TO_NEXT_TERM(ch) \
529 do { \
530 while (*ch != ',') \
531 { \
532 if (*ch == 0) \
533 { \
534 return errorSyntax(USAGE_CONTROLVM, \
535 "Missing or invalid argument to '%s'", \
536 a->argv[1]); \
537 } \
538 ch++; \
539 } \
540 *ch = '\0'; \
541 ch++; \
542 } while(0)
543
544 char *strName;
545 char *strProto;
546 char *strHostIp;
547 char *strHostPort;
548 char *strGuestIp;
549 char *strGuestPort;
550 char *strRaw = RTStrDup(a->argv[2]);
551 char *ch = strRaw;
552 strName = RTStrStrip(ch);
553 ITERATE_TO_NEXT_TERM(ch);
554 strProto = RTStrStrip(ch);
555 ITERATE_TO_NEXT_TERM(ch);
556 strHostIp = RTStrStrip(ch);
557 ITERATE_TO_NEXT_TERM(ch);
558 strHostPort = RTStrStrip(ch);
559 ITERATE_TO_NEXT_TERM(ch);
560 strGuestIp = RTStrStrip(ch);
561 ITERATE_TO_NEXT_TERM(ch);
562 strGuestPort = RTStrStrip(ch);
563 NATProtocol_T proto;
564 if (RTStrICmp(strProto, "udp") == 0)
565 proto = NATProtocol_UDP;
566 else if (RTStrICmp(strProto, "tcp") == 0)
567 proto = NATProtocol_TCP;
568 else
569 {
570 return errorSyntax(USAGE_CONTROLVM,
571 "Wrong rule proto '%s' specified -- only 'udp' and 'tcp' are allowed.",
572 strProto);
573 }
574 CHECK_ERROR(engine, AddRedirect(Bstr(strName).raw(), proto, Bstr(strHostIp).raw(),
575 RTStrToUInt16(strHostPort), Bstr(strGuestIp).raw(), RTStrToUInt16(strGuestPort)));
576#undef ITERATE_TO_NEXT_TERM
577 }
578 if (SUCCEEDED(rc))
579 fNeedsSaving = true;
580 }
581 else if (!strncmp(a->argv[1], "nicproperty", 11))
582 {
583 /* Get the number of network adapters */
584 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
585 unsigned n = parseNum(&a->argv[1][11], NetworkAdapterCount, "NIC");
586 if (!n)
587 {
588 rc = E_FAIL;
589 break;
590 }
591 if (a->argc <= 2)
592 {
593 errorArgument("Missing argument to '%s'", a->argv[1]);
594 rc = E_FAIL;
595 break;
596 }
597
598 /* get the corresponding network adapter */
599 ComPtr<INetworkAdapter> adapter;
600 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
601 if (adapter)
602 {
603 BOOL fEnabled;
604 adapter->COMGETTER(Enabled)(&fEnabled);
605 if (fEnabled)
606 {
607 /* Parse 'name=value' */
608 char *pszProperty = RTStrDup(a->argv[2]);
609 if (pszProperty)
610 {
611 char *pDelimiter = strchr(pszProperty, '=');
612 if (pDelimiter)
613 {
614 *pDelimiter = '\0';
615
616 Bstr bstrName = pszProperty;
617 Bstr bstrValue = &pDelimiter[1];
618 CHECK_ERROR(adapter, SetProperty(bstrName.raw(), bstrValue.raw()));
619 if (SUCCEEDED(rc))
620 fNeedsSaving = true;
621 }
622 else
623 {
624 errorArgument("Invalid nicproperty%d argument '%s'", n, a->argv[2]);
625 rc = E_FAIL;
626 }
627 RTStrFree(pszProperty);
628 }
629 else
630 {
631 RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for nicproperty%d '%s'\n", n, a->argv[2]);
632 rc = E_FAIL;
633 }
634 if (FAILED(rc))
635 break;
636 }
637 else
638 RTMsgError("The NIC %d is currently disabled and thus its properties can't be changed", n);
639 }
640 }
641 else if (!strncmp(a->argv[1], "nicpromisc", 10))
642 {
643 /* Get the number of network adapters */
644 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
645 unsigned n = parseNum(&a->argv[1][10], NetworkAdapterCount, "NIC");
646 if (!n)
647 {
648 rc = E_FAIL;
649 break;
650 }
651 if (a->argc <= 2)
652 {
653 errorArgument("Missing argument to '%s'", a->argv[1]);
654 rc = E_FAIL;
655 break;
656 }
657
658 /* get the corresponding network adapter */
659 ComPtr<INetworkAdapter> adapter;
660 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
661 if (adapter)
662 {
663 BOOL fEnabled;
664 adapter->COMGETTER(Enabled)(&fEnabled);
665 if (fEnabled)
666 {
667 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
668 if (!strcmp(a->argv[2], "deny"))
669 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_Deny;
670 else if ( !strcmp(a->argv[2], "allow-vms")
671 || !strcmp(a->argv[2], "allow-network"))
672 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowNetwork;
673 else if (!strcmp(a->argv[2], "allow-all"))
674 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowAll;
675 else
676 {
677 errorArgument("Unknown promiscuous mode policy '%s'", a->argv[2]);
678 rc = E_INVALIDARG;
679 break;
680 }
681
682 CHECK_ERROR(adapter, COMSETTER(PromiscModePolicy)(enmPromiscModePolicy));
683 if (SUCCEEDED(rc))
684 fNeedsSaving = true;
685 }
686 else
687 RTMsgError("The NIC %d is currently disabled and thus its promiscuous mode can't be changed", n);
688 }
689 }
690 else if (!strncmp(a->argv[1], "nic", 3))
691 {
692 /* Get the number of network adapters */
693 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
694 unsigned n = parseNum(&a->argv[1][3], NetworkAdapterCount, "NIC");
695 if (!n)
696 {
697 rc = E_FAIL;
698 break;
699 }
700 if (a->argc <= 2)
701 {
702 errorArgument("Missing argument to '%s'", a->argv[1]);
703 rc = E_FAIL;
704 break;
705 }
706
707 /* get the corresponding network adapter */
708 ComPtr<INetworkAdapter> adapter;
709 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
710 if (adapter)
711 {
712 BOOL fEnabled;
713 adapter->COMGETTER(Enabled)(&fEnabled);
714 if (fEnabled)
715 {
716 if (!strcmp(a->argv[2], "null"))
717 {
718 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE);
719 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Null), RTEXITCODE_FAILURE);
720 }
721 else if (!strcmp(a->argv[2], "nat"))
722 {
723 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE);
724 if (a->argc == 4)
725 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
726 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_NAT), RTEXITCODE_FAILURE);
727 }
728 else if ( !strcmp(a->argv[2], "bridged")
729 || !strcmp(a->argv[2], "hostif")) /* backward compatibility */
730 {
731 if (a->argc <= 3)
732 {
733 errorArgument("Missing argument to '%s'", a->argv[2]);
734 rc = E_FAIL;
735 break;
736 }
737 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE);
738 CHECK_ERROR_RET(adapter, COMSETTER(BridgedInterface)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
739 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Bridged), RTEXITCODE_FAILURE);
740 }
741 else if (!strcmp(a->argv[2], "intnet"))
742 {
743 if (a->argc <= 3)
744 {
745 errorArgument("Missing argument to '%s'", a->argv[2]);
746 rc = E_FAIL;
747 break;
748 }
749 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE);
750 CHECK_ERROR_RET(adapter, COMSETTER(InternalNetwork)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
751 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Internal), RTEXITCODE_FAILURE);
752 }
753#if defined(VBOX_WITH_NETFLT)
754 else if (!strcmp(a->argv[2], "hostonly"))
755 {
756 if (a->argc <= 3)
757 {
758 errorArgument("Missing argument to '%s'", a->argv[2]);
759 rc = E_FAIL;
760 break;
761 }
762 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE);
763 CHECK_ERROR_RET(adapter, COMSETTER(HostOnlyInterface)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
764 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_HostOnly), RTEXITCODE_FAILURE);
765 }
766#endif
767 else if (!strcmp(a->argv[2], "generic"))
768 {
769 if (a->argc <= 3)
770 {
771 errorArgument("Missing argument to '%s'", a->argv[2]);
772 rc = E_FAIL;
773 break;
774 }
775 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE);
776 CHECK_ERROR_RET(adapter, COMSETTER(GenericDriver)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
777 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic), RTEXITCODE_FAILURE);
778 }
779 else if (!strcmp(a->argv[2], "natnetwork"))
780 {
781 if (a->argc <= 3)
782 {
783 errorArgument("Missing argument to '%s'", a->argv[2]);
784 rc = E_FAIL;
785 break;
786 }
787 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE);
788 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
789 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_NATNetwork), RTEXITCODE_FAILURE);
790 }
791 /** @todo obsolete, remove eventually */
792 else if (!strcmp(a->argv[2], "vde"))
793 {
794 if (a->argc <= 3)
795 {
796 errorArgument("Missing argument to '%s'", a->argv[2]);
797 rc = E_FAIL;
798 break;
799 }
800 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE);
801 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic), RTEXITCODE_FAILURE);
802 CHECK_ERROR_RET(adapter, SetProperty(Bstr("name").raw(), Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
803 }
804 else
805 {
806 errorArgument("Invalid type '%s' specfied for NIC %lu", Utf8Str(a->argv[2]).c_str(), n);
807 rc = E_FAIL;
808 break;
809 }
810 if (SUCCEEDED(rc))
811 fNeedsSaving = true;
812 }
813 else
814 RTMsgError("The NIC %d is currently disabled and thus its attachment type can't be changed", n);
815 }
816 }
817 else if ( !strcmp(a->argv[1], "vrde")
818 || !strcmp(a->argv[1], "vrdp"))
819 {
820 if (!strcmp(a->argv[1], "vrdp"))
821 RTStrmPrintf(g_pStdErr, "Warning: 'vrdp' is deprecated. Use 'vrde'.\n");
822
823 if (a->argc <= 1 + 1)
824 {
825 errorArgument("Missing argument to '%s'", a->argv[1]);
826 rc = E_FAIL;
827 break;
828 }
829 ComPtr<IVRDEServer> vrdeServer;
830 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
831 ASSERT(vrdeServer);
832 if (vrdeServer)
833 {
834 if (!strcmp(a->argv[2], "on"))
835 {
836 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(TRUE));
837 }
838 else if (!strcmp(a->argv[2], "off"))
839 {
840 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(FALSE));
841 }
842 else
843 {
844 errorArgument("Invalid remote desktop server state '%s'", Utf8Str(a->argv[2]).c_str());
845 rc = E_FAIL;
846 break;
847 }
848 if (SUCCEEDED(rc))
849 fNeedsSaving = true;
850 }
851 }
852 else if ( !strcmp(a->argv[1], "vrdeport")
853 || !strcmp(a->argv[1], "vrdpport"))
854 {
855 if (!strcmp(a->argv[1], "vrdpport"))
856 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpport' is deprecated. Use 'vrdeport'.\n");
857
858 if (a->argc <= 1 + 1)
859 {
860 errorArgument("Missing argument to '%s'", a->argv[1]);
861 rc = E_FAIL;
862 break;
863 }
864
865 ComPtr<IVRDEServer> vrdeServer;
866 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
867 ASSERT(vrdeServer);
868 if (vrdeServer)
869 {
870 Bstr ports;
871
872 if (!strcmp(a->argv[2], "default"))
873 ports = "0";
874 else
875 ports = a->argv[2];
876
877 CHECK_ERROR_BREAK(vrdeServer, SetVRDEProperty(Bstr("TCP/Ports").raw(), ports.raw()));
878 if (SUCCEEDED(rc))
879 fNeedsSaving = true;
880 }
881 }
882 else if ( !strcmp(a->argv[1], "vrdevideochannelquality")
883 || !strcmp(a->argv[1], "vrdpvideochannelquality"))
884 {
885 if (!strcmp(a->argv[1], "vrdpvideochannelquality"))
886 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpvideochannelquality' is deprecated. Use 'vrdevideochannelquality'.\n");
887
888 if (a->argc <= 1 + 1)
889 {
890 errorArgument("Missing argument to '%s'", a->argv[1]);
891 rc = E_FAIL;
892 break;
893 }
894 ComPtr<IVRDEServer> vrdeServer;
895 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
896 ASSERT(vrdeServer);
897 if (vrdeServer)
898 {
899 Bstr value = a->argv[2];
900
901 CHECK_ERROR(vrdeServer, SetVRDEProperty(Bstr("VideoChannel/Quality").raw(), value.raw()));
902 if (SUCCEEDED(rc))
903 fNeedsSaving = true;
904 }
905 }
906 else if (!strcmp(a->argv[1], "vrdeproperty"))
907 {
908 if (a->argc <= 1 + 1)
909 {
910 errorArgument("Missing argument to '%s'", a->argv[1]);
911 rc = E_FAIL;
912 break;
913 }
914 ComPtr<IVRDEServer> vrdeServer;
915 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
916 ASSERT(vrdeServer);
917 if (vrdeServer)
918 {
919 /* Parse 'name=value' */
920 char *pszProperty = RTStrDup(a->argv[2]);
921 if (pszProperty)
922 {
923 char *pDelimiter = strchr(pszProperty, '=');
924 if (pDelimiter)
925 {
926 *pDelimiter = '\0';
927
928 Bstr bstrName = pszProperty;
929 Bstr bstrValue = &pDelimiter[1];
930 CHECK_ERROR(vrdeServer, SetVRDEProperty(bstrName.raw(), bstrValue.raw()));
931 if (SUCCEEDED(rc))
932 fNeedsSaving = true;
933 }
934 else
935 {
936 errorArgument("Invalid vrdeproperty argument '%s'", a->argv[2]);
937 rc = E_FAIL;
938 }
939 RTStrFree(pszProperty);
940 }
941 else
942 {
943 RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for VRDE property '%s'\n", a->argv[2]);
944 rc = E_FAIL;
945 }
946 }
947 if (FAILED(rc))
948 {
949 break;
950 }
951 }
952 else if ( !strcmp(a->argv[1], "usbattach")
953 || !strcmp(a->argv[1], "usbdetach"))
954 {
955 if (a->argc < 3)
956 {
957 errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
958 rc = E_FAIL;
959 break;
960 }
961 else if (a->argc == 4 || a->argc > 5)
962 {
963 errorSyntax(USAGE_CONTROLVM, "Wrong number of arguments");
964 rc = E_FAIL;
965 break;
966 }
967
968 bool attach = !strcmp(a->argv[1], "usbattach");
969
970 Bstr usbId = a->argv[2];
971 Bstr captureFilename;
972
973 if (a->argc == 5)
974 {
975 if (!strcmp(a->argv[3], "--capturefile"))
976 captureFilename = a->argv[4];
977 else
978 {
979 errorArgument("Invalid parameter '%s'", a->argv[3]);
980 rc = E_FAIL;
981 break;
982 }
983 }
984
985 Guid guid(usbId);
986 if (!guid.isValid())
987 {
988 // assume address
989 if (attach)
990 {
991 ComPtr<IHost> host;
992 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
993 SafeIfaceArray <IHostUSBDevice> coll;
994 CHECK_ERROR_BREAK(host, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
995 ComPtr<IHostUSBDevice> dev;
996 CHECK_ERROR_BREAK(host, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
997 dev.asOutParam()));
998 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
999 }
1000 else
1001 {
1002 SafeIfaceArray <IUSBDevice> coll;
1003 CHECK_ERROR_BREAK(console, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
1004 ComPtr<IUSBDevice> dev;
1005 CHECK_ERROR_BREAK(console, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
1006 dev.asOutParam()));
1007 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
1008 }
1009 }
1010 else if (guid.isZero())
1011 {
1012 errorArgument("Zero UUID argument '%s'", a->argv[2]);
1013 rc = E_FAIL;
1014 break;
1015 }
1016
1017 if (attach)
1018 CHECK_ERROR_BREAK(console, AttachUSBDevice(usbId.raw(), captureFilename.raw()));
1019 else
1020 {
1021 ComPtr<IUSBDevice> dev;
1022 CHECK_ERROR_BREAK(console, DetachUSBDevice(usbId.raw(),
1023 dev.asOutParam()));
1024 }
1025 }
1026 else if (!strcmp(a->argv[1], "setvideomodehint"))
1027 {
1028 if (a->argc != 5 && a->argc != 6 && a->argc != 7 && a->argc != 9)
1029 {
1030 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1031 rc = E_FAIL;
1032 break;
1033 }
1034 bool fEnabled = true;
1035 uint32_t uXRes = RTStrToUInt32(a->argv[2]);
1036 uint32_t uYRes = RTStrToUInt32(a->argv[3]);
1037 uint32_t uBpp = RTStrToUInt32(a->argv[4]);
1038 uint32_t uDisplayIdx = 0;
1039 bool fChangeOrigin = false;
1040 int32_t iOriginX = 0;
1041 int32_t iOriginY = 0;
1042 if (a->argc >= 6)
1043 uDisplayIdx = RTStrToUInt32(a->argv[5]);
1044 if (a->argc >= 7)
1045 {
1046 int vrc = parseBool(a->argv[6], &fEnabled);
1047 if (RT_FAILURE(vrc))
1048 {
1049 errorSyntax(USAGE_CONTROLVM, "Either \"yes\" or \"no\" is expected");
1050 rc = E_FAIL;
1051 break;
1052 }
1053 fEnabled = !RTStrICmp(a->argv[6], "yes");
1054 }
1055 if (a->argc == 9)
1056 {
1057 iOriginX = RTStrToInt32(a->argv[7]);
1058 iOriginY = RTStrToInt32(a->argv[8]);
1059 fChangeOrigin = true;
1060 }
1061
1062 ComPtr<IDisplay> pDisplay;
1063 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1064 if (!pDisplay)
1065 {
1066 RTMsgError("Guest not running");
1067 rc = E_FAIL;
1068 break;
1069 }
1070 CHECK_ERROR_BREAK(pDisplay, SetVideoModeHint(uDisplayIdx, fEnabled,
1071 fChangeOrigin, iOriginX, iOriginY,
1072 uXRes, uYRes, uBpp));
1073 }
1074 else if (!strcmp(a->argv[1], "setcredentials"))
1075 {
1076 bool fAllowLocalLogon = true;
1077 if ( a->argc == 7
1078 || ( a->argc == 8
1079 && ( !strcmp(a->argv[3], "-p")
1080 || !strcmp(a->argv[3], "--passwordfile"))))
1081 {
1082 if ( strcmp(a->argv[5 + (a->argc - 7)], "--allowlocallogon")
1083 && strcmp(a->argv[5 + (a->argc - 7)], "-allowlocallogon"))
1084 {
1085 errorArgument("Invalid parameter '%s'", a->argv[5]);
1086 rc = E_FAIL;
1087 break;
1088 }
1089 if (!strcmp(a->argv[6 + (a->argc - 7)], "no"))
1090 fAllowLocalLogon = false;
1091 }
1092 else if ( a->argc != 5
1093 && ( a->argc != 6
1094 || ( strcmp(a->argv[3], "-p")
1095 && strcmp(a->argv[3], "--passwordfile"))))
1096 {
1097 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1098 rc = E_FAIL;
1099 break;
1100 }
1101 Utf8Str passwd, domain;
1102 if (a->argc == 5 || a->argc == 7)
1103 {
1104 passwd = a->argv[3];
1105 domain = a->argv[4];
1106 }
1107 else
1108 {
1109 RTEXITCODE rcExit = readPasswordFile(a->argv[4], &passwd);
1110 if (rcExit != RTEXITCODE_SUCCESS)
1111 {
1112 rc = E_FAIL;
1113 break;
1114 }
1115 domain = a->argv[5];
1116 }
1117
1118 ComPtr<IGuest> pGuest;
1119 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest.asOutParam()));
1120 if (!pGuest)
1121 {
1122 RTMsgError("Guest not running");
1123 rc = E_FAIL;
1124 break;
1125 }
1126 CHECK_ERROR_BREAK(pGuest, SetCredentials(Bstr(a->argv[2]).raw(),
1127 Bstr(passwd).raw(),
1128 Bstr(domain).raw(),
1129 fAllowLocalLogon));
1130 }
1131#if 0 /* TODO: review & remove */
1132 else if (!strcmp(a->argv[1], "dvdattach"))
1133 {
1134 Bstr uuid;
1135 if (a->argc != 3)
1136 {
1137 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1138 rc = E_FAIL;
1139 break;
1140 }
1141
1142 ComPtr<IMedium> dvdMedium;
1143
1144 /* unmount? */
1145 if (!strcmp(a->argv[2], "none"))
1146 {
1147 /* nothing to do, NULL object will cause unmount */
1148 }
1149 /* host drive? */
1150 else if (!strncmp(a->argv[2], "host:", 5))
1151 {
1152 ComPtr<IHost> host;
1153 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1154
1155 rc = host->FindHostDVDDrive(Bstr(a->argv[2] + 5), dvdMedium.asOutParam());
1156 if (!dvdMedium)
1157 {
1158 errorArgument("Invalid host DVD drive name \"%s\"",
1159 a->argv[2] + 5);
1160 rc = E_FAIL;
1161 break;
1162 }
1163 }
1164 else
1165 {
1166 /* first assume it's a UUID */
1167 uuid = a->argv[2];
1168 rc = a->virtualBox->GetDVDImage(uuid, dvdMedium.asOutParam());
1169 if (FAILED(rc) || !dvdMedium)
1170 {
1171 /* must be a filename, check if it's in the collection */
1172 rc = a->virtualBox->FindDVDImage(Bstr(a->argv[2]), dvdMedium.asOutParam());
1173 /* not registered, do that on the fly */
1174 if (!dvdMedium)
1175 {
1176 Bstr emptyUUID;
1177 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(a->argv[2]), emptyUUID, dvdMedium.asOutParam()));
1178 }
1179 }
1180 if (!dvdMedium)
1181 {
1182 rc = E_FAIL;
1183 break;
1184 }
1185 }
1186
1187 /** @todo generalize this, allow arbitrary number of DVD drives
1188 * and as a consequence multiple attachments and different
1189 * storage controllers. */
1190 if (dvdMedium)
1191 dvdMedium->COMGETTER(Id)(uuid.asOutParam());
1192 else
1193 uuid = Guid().toString();
1194 CHECK_ERROR(machine, MountMedium(Bstr("IDE Controller"), 1, 0, uuid, FALSE /* aForce */));
1195 }
1196 else if (!strcmp(a->argv[1], "floppyattach"))
1197 {
1198 Bstr uuid;
1199 if (a->argc != 3)
1200 {
1201 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1202 rc = E_FAIL;
1203 break;
1204 }
1205
1206 ComPtr<IMedium> floppyMedium;
1207
1208 /* unmount? */
1209 if (!strcmp(a->argv[2], "none"))
1210 {
1211 /* nothing to do, NULL object will cause unmount */
1212 }
1213 /* host drive? */
1214 else if (!strncmp(a->argv[2], "host:", 5))
1215 {
1216 ComPtr<IHost> host;
1217 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1218 host->FindHostFloppyDrive(Bstr(a->argv[2] + 5), floppyMedium.asOutParam());
1219 if (!floppyMedium)
1220 {
1221 errorArgument("Invalid host floppy drive name \"%s\"",
1222 a->argv[2] + 5);
1223 rc = E_FAIL;
1224 break;
1225 }
1226 }
1227 else
1228 {
1229 /* first assume it's a UUID */
1230 uuid = a->argv[2];
1231 rc = a->virtualBox->GetFloppyImage(uuid, floppyMedium.asOutParam());
1232 if (FAILED(rc) || !floppyMedium)
1233 {
1234 /* must be a filename, check if it's in the collection */
1235 rc = a->virtualBox->FindFloppyImage(Bstr(a->argv[2]), floppyMedium.asOutParam());
1236 /* not registered, do that on the fly */
1237 if (!floppyMedium)
1238 {
1239 Bstr emptyUUID;
1240 CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(a->argv[2]), emptyUUID, floppyMedium.asOutParam()));
1241 }
1242 }
1243 if (!floppyMedium)
1244 {
1245 rc = E_FAIL;
1246 break;
1247 }
1248 }
1249 floppyMedium->COMGETTER(Id)(uuid.asOutParam());
1250 CHECK_ERROR(machine, MountMedium(Bstr("Floppy Controller"), 0, 0, uuid, FALSE /* aForce */));
1251 }
1252#endif /* obsolete dvdattach/floppyattach */
1253 else if (!strcmp(a->argv[1], "guestmemoryballoon"))
1254 {
1255 if (a->argc != 3)
1256 {
1257 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1258 rc = E_FAIL;
1259 break;
1260 }
1261 uint32_t uVal;
1262 int vrc;
1263 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1264 if (vrc != VINF_SUCCESS)
1265 {
1266 errorArgument("Error parsing guest memory balloon size '%s'", a->argv[2]);
1267 rc = E_FAIL;
1268 break;
1269 }
1270 /* guest is running; update IGuest */
1271 ComPtr<IGuest> pGuest;
1272 rc = console->COMGETTER(Guest)(pGuest.asOutParam());
1273 if (SUCCEEDED(rc))
1274 {
1275 if (!pGuest)
1276 {
1277 RTMsgError("Guest not running");
1278 rc = E_FAIL;
1279 break;
1280 }
1281 CHECK_ERROR(pGuest, COMSETTER(MemoryBalloonSize)(uVal));
1282 }
1283 }
1284 else if (!strcmp(a->argv[1], "teleport"))
1285 {
1286 Bstr bstrHostname;
1287 uint32_t uMaxDowntime = 250 /*ms*/;
1288 uint32_t uPort = UINT32_MAX;
1289 uint32_t cMsTimeout = 0;
1290 Utf8Str strPassword;
1291 static const RTGETOPTDEF s_aTeleportOptions[] =
1292 {
1293 { "--host", 'h', RTGETOPT_REQ_STRING }, /** @todo RTGETOPT_FLAG_MANDATORY */
1294 { "--hostname", 'h', RTGETOPT_REQ_STRING }, /** @todo remove this */
1295 { "--maxdowntime", 'd', RTGETOPT_REQ_UINT32 },
1296 { "--port", 'P', RTGETOPT_REQ_UINT32 }, /** @todo RTGETOPT_FLAG_MANDATORY */
1297 { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
1298 { "--password", 'W', RTGETOPT_REQ_STRING },
1299 { "--timeout", 't', RTGETOPT_REQ_UINT32 },
1300 { "--detailed-progress", 'D', RTGETOPT_REQ_NOTHING }
1301 };
1302 RTGETOPTSTATE GetOptState;
1303 RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTeleportOptions, RT_ELEMENTS(s_aTeleportOptions), 2, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1304 int ch;
1305 RTGETOPTUNION Value;
1306 while ( SUCCEEDED(rc)
1307 && (ch = RTGetOpt(&GetOptState, &Value)))
1308 {
1309 switch (ch)
1310 {
1311 case 'h': bstrHostname = Value.psz; break;
1312 case 'd': uMaxDowntime = Value.u32; break;
1313 case 'D': g_fDetailedProgress = true; break;
1314 case 'P': uPort = Value.u32; break;
1315 case 'p':
1316 {
1317 RTEXITCODE rcExit = readPasswordFile(Value.psz, &strPassword);
1318 if (rcExit != RTEXITCODE_SUCCESS)
1319 rc = E_FAIL;
1320 break;
1321 }
1322 case 'W': strPassword = Value.psz; break;
1323 case 't': cMsTimeout = Value.u32; break;
1324 default:
1325 errorGetOpt(USAGE_CONTROLVM, ch, &Value);
1326 rc = E_FAIL;
1327 break;
1328 }
1329 }
1330 if (FAILED(rc))
1331 break;
1332
1333 ComPtr<IProgress> progress;
1334 CHECK_ERROR_BREAK(console, Teleport(bstrHostname.raw(), uPort,
1335 Bstr(strPassword).raw(),
1336 uMaxDowntime,
1337 progress.asOutParam()));
1338
1339 if (cMsTimeout)
1340 {
1341 rc = progress->COMSETTER(Timeout)(cMsTimeout);
1342 if (FAILED(rc) && rc != VBOX_E_INVALID_OBJECT_STATE)
1343 CHECK_ERROR_BREAK(progress, COMSETTER(Timeout)(cMsTimeout)); /* lazyness */
1344 }
1345
1346 rc = showProgress(progress);
1347 CHECK_PROGRESS_ERROR(progress, ("Teleportation failed"));
1348 }
1349 else if (!strcmp(a->argv[1], "screenshotpng"))
1350 {
1351 if (a->argc <= 2 || a->argc > 4)
1352 {
1353 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1354 rc = E_FAIL;
1355 break;
1356 }
1357 int vrc;
1358 uint32_t iScreen = 0;
1359 if (a->argc == 4)
1360 {
1361 vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &iScreen);
1362 if (vrc != VINF_SUCCESS)
1363 {
1364 errorArgument("Error parsing display number '%s'", a->argv[3]);
1365 rc = E_FAIL;
1366 break;
1367 }
1368 }
1369 ComPtr<IDisplay> pDisplay;
1370 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1371 if (!pDisplay)
1372 {
1373 RTMsgError("Guest not running");
1374 rc = E_FAIL;
1375 break;
1376 }
1377 ULONG width, height, bpp;
1378 LONG xOrigin, yOrigin;
1379 GuestMonitorStatus_T monitorStatus;
1380 CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(iScreen, &width, &height, &bpp, &xOrigin, &yOrigin, &monitorStatus));
1381 com::SafeArray<BYTE> saScreenshot;
1382 CHECK_ERROR_BREAK(pDisplay, TakeScreenShotToArray(iScreen, width, height, BitmapFormat_PNG, ComSafeArrayAsOutParam(saScreenshot)));
1383 RTFILE pngFile = NIL_RTFILE;
1384 vrc = RTFileOpen(&pngFile, a->argv[2], RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_TRUNCATE | RTFILE_O_DENY_ALL);
1385 if (RT_FAILURE(vrc))
1386 {
1387 RTMsgError("Failed to create file '%s' (%Rrc)", a->argv[2], vrc);
1388 rc = E_FAIL;
1389 break;
1390 }
1391 vrc = RTFileWrite(pngFile, saScreenshot.raw(), saScreenshot.size(), NULL);
1392 if (RT_FAILURE(vrc))
1393 {
1394 RTMsgError("Failed to write screenshot to file '%s' (%Rrc)", a->argv[2], vrc);
1395 rc = E_FAIL;
1396 }
1397 RTFileClose(pngFile);
1398 }
1399#ifdef VBOX_WITH_VPX
1400 /*
1401 * Note: Commands starting with "vcp" are the deprecated versions and are
1402 * kept to ensure backwards compatibility.
1403 */
1404 else if ( !strcmp(a->argv[1], "videocap")
1405 || !strcmp(a->argv[1], "vcpenabled"))
1406 {
1407 if (a->argc != 3)
1408 {
1409 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1410 rc = E_FAIL;
1411 break;
1412 }
1413 if (!strcmp(a->argv[2], "on"))
1414 {
1415 CHECK_ERROR_RET(sessionMachine, COMSETTER(VideoCaptureEnabled)(TRUE), RTEXITCODE_FAILURE);
1416 }
1417 else if (!strcmp(a->argv[2], "off"))
1418 {
1419 CHECK_ERROR_RET(sessionMachine, COMSETTER(VideoCaptureEnabled)(FALSE), RTEXITCODE_FAILURE);
1420 }
1421 else
1422 {
1423 errorArgument("Invalid state '%s'", Utf8Str(a->argv[2]).c_str());
1424 rc = E_FAIL;
1425 break;
1426 }
1427 }
1428 else if ( !strcmp(a->argv[1], "videocapscreens")
1429 || !strcmp(a->argv[1], "vcpscreens"))
1430 {
1431 ULONG cMonitors = 64;
1432 CHECK_ERROR_BREAK(machine, COMGETTER(MonitorCount)(&cMonitors));
1433 com::SafeArray<BOOL> saScreens(cMonitors);
1434 if ( a->argc == 3
1435 && !strcmp(a->argv[2], "all"))
1436 {
1437 /* enable all screens */
1438 for (unsigned i = 0; i < cMonitors; i++)
1439 saScreens[i] = true;
1440 }
1441 else if ( a->argc == 3
1442 && !strcmp(a->argv[2], "none"))
1443 {
1444 /* disable all screens */
1445 for (unsigned i = 0; i < cMonitors; i++)
1446 saScreens[i] = false;
1447
1448 /** @todo r=andy What if this is specified? */
1449 }
1450 else
1451 {
1452 /* enable selected screens */
1453 for (unsigned i = 0; i < cMonitors; i++)
1454 saScreens[i] = false;
1455 for (int i = 2; SUCCEEDED(rc) && i < a->argc; i++)
1456 {
1457 uint32_t iScreen;
1458 int vrc = RTStrToUInt32Ex(a->argv[i], NULL, 0, &iScreen);
1459 if (vrc != VINF_SUCCESS)
1460 {
1461 errorArgument("Error parsing display number '%s'", a->argv[i]);
1462 rc = E_FAIL;
1463 break;
1464 }
1465 if (iScreen >= cMonitors)
1466 {
1467 errorArgument("Invalid screen ID specified '%u'", iScreen);
1468 rc = E_FAIL;
1469 break;
1470 }
1471 saScreens[iScreen] = true;
1472 }
1473 }
1474
1475 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureScreens)(ComSafeArrayAsInParam(saScreens)));
1476 }
1477 else if ( !strcmp(a->argv[1], "videocapfile")
1478 || !strcmp(a->argv[1], "vcpfile"))
1479 {
1480 if (a->argc != 3)
1481 {
1482 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1483 rc = E_FAIL;
1484 break;
1485 }
1486
1487 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureFile)(Bstr(a->argv[3]).raw()));
1488 }
1489 else if (!strcmp(a->argv[1], "videocapres"))
1490 {
1491 if (a->argc != 4)
1492 {
1493 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1494 rc = E_FAIL;
1495 break;
1496 }
1497
1498 uint32_t uVal;
1499 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1500 if (RT_FAILURE(vrc))
1501 {
1502 errorArgument("Error parsing width '%s'", a->argv[2]);
1503 rc = E_FAIL;
1504 break;
1505 }
1506 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureWidth)(uVal));
1507
1508 vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uVal);
1509 if (RT_FAILURE(vrc))
1510 {
1511 errorArgument("Error parsing height '%s'", a->argv[3]);
1512 rc = E_FAIL;
1513 break;
1514 }
1515 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureHeight)(uVal));
1516 }
1517 else if (!strcmp(a->argv[1], "vcpwidth")) /* Deprecated; keeping for compatibility. */
1518 {
1519 uint32_t uVal;
1520 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1521 if (RT_FAILURE(vrc))
1522 {
1523 errorArgument("Error parsing width '%s'", a->argv[2]);
1524 rc = E_FAIL;
1525 break;
1526 }
1527 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureWidth)(uVal));
1528 }
1529 else if (!strcmp(a->argv[1], "vcpheight")) /* Deprecated; keeping for compatibility. */
1530 {
1531 uint32_t uVal;
1532 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1533 if (RT_FAILURE(vrc))
1534 {
1535 errorArgument("Error parsing height '%s'", a->argv[2]);
1536 rc = E_FAIL;
1537 break;
1538 }
1539 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureHeight)(uVal));
1540 }
1541 else if ( !strcmp(a->argv[1], "videocaprate")
1542 || !strcmp(a->argv[1], "vcprate"))
1543 {
1544 if (a->argc != 3)
1545 {
1546 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1547 rc = E_FAIL;
1548 break;
1549 }
1550
1551 uint32_t uVal;
1552 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1553 if (RT_FAILURE(vrc))
1554 {
1555 errorArgument("Error parsing rate '%s'", a->argv[2]);
1556 rc = E_FAIL;
1557 break;
1558 }
1559 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureRate)(uVal));
1560 }
1561 else if ( !strcmp(a->argv[1], "videocapfps")
1562 || !strcmp(a->argv[1], "vcpfps"))
1563 {
1564 if (a->argc != 3)
1565 {
1566 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1567 rc = E_FAIL;
1568 break;
1569 }
1570
1571 uint32_t uVal;
1572 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1573 if (RT_FAILURE(vrc))
1574 {
1575 errorArgument("Error parsing FPS '%s'", a->argv[2]);
1576 rc = E_FAIL;
1577 break;
1578 }
1579 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureFPS)(uVal));
1580 }
1581 else if ( !strcmp(a->argv[1], "videocapmaxtime")
1582 || !strcmp(a->argv[1], "vcpmaxtime"))
1583 {
1584 if (a->argc != 3)
1585 {
1586 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1587 rc = E_FAIL;
1588 break;
1589 }
1590
1591 uint32_t uVal;
1592 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1593 if (RT_FAILURE(vrc))
1594 {
1595 errorArgument("Error parsing maximum time '%s'", a->argv[2]);
1596 rc = E_FAIL;
1597 break;
1598 }
1599 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureMaxTime)(uVal));
1600 }
1601 else if ( !strcmp(a->argv[1], "videocapmaxsize")
1602 || !strcmp(a->argv[1], "vcpmaxsize"))
1603 {
1604 if (a->argc != 3)
1605 {
1606 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1607 rc = E_FAIL;
1608 break;
1609 }
1610
1611 uint32_t uVal;
1612 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1613 if (RT_FAILURE(vrc))
1614 {
1615 errorArgument("Error parsing maximum file size '%s'", a->argv[2]);
1616 rc = E_FAIL;
1617 break;
1618 }
1619 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureMaxFileSize)(uVal));
1620 }
1621 else if ( !strcmp(a->argv[1], "videocapopts")
1622 || !strcmp(a->argv[1], "vcpoptions"))
1623 {
1624 if (a->argc != 3)
1625 {
1626 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1627 rc = E_FAIL;
1628 break;
1629 }
1630
1631 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureOptions)(Bstr(a->argv[3]).raw()));
1632 }
1633#endif /* VBOX_WITH_VPX */
1634 else if (!strcmp(a->argv[1], "webcam"))
1635 {
1636 if (a->argc < 3)
1637 {
1638 errorArgument("Missing argument to '%s'", a->argv[1]);
1639 rc = E_FAIL;
1640 break;
1641 }
1642
1643 ComPtr<IEmulatedUSB> pEmulatedUSB;
1644 CHECK_ERROR_BREAK(console, COMGETTER(EmulatedUSB)(pEmulatedUSB.asOutParam()));
1645 if (!pEmulatedUSB)
1646 {
1647 RTMsgError("Guest not running");
1648 rc = E_FAIL;
1649 break;
1650 }
1651
1652 if (!strcmp(a->argv[2], "attach"))
1653 {
1654 Bstr path("");
1655 if (a->argc >= 4)
1656 path = a->argv[3];
1657 Bstr settings("");
1658 if (a->argc >= 5)
1659 settings = a->argv[4];
1660 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamAttach(path.raw(), settings.raw()));
1661 }
1662 else if (!strcmp(a->argv[2], "detach"))
1663 {
1664 Bstr path("");
1665 if (a->argc >= 4)
1666 path = a->argv[3];
1667 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamDetach(path.raw()));
1668 }
1669 else if (!strcmp(a->argv[2], "list"))
1670 {
1671 com::SafeArray <BSTR> webcams;
1672 CHECK_ERROR_BREAK(pEmulatedUSB, COMGETTER(Webcams)(ComSafeArrayAsOutParam(webcams)));
1673 for (size_t i = 0; i < webcams.size(); ++i)
1674 {
1675 RTPrintf("%ls\n", webcams[i][0]? webcams[i]: Bstr("default").raw());
1676 }
1677 }
1678 else
1679 {
1680 errorArgument("Invalid argument to '%s'", a->argv[1]);
1681 rc = E_FAIL;
1682 break;
1683 }
1684 }
1685 else if (!strcmp(a->argv[1], "addencpassword"))
1686 {
1687 if ( a->argc != 4
1688 && a->argc != 6)
1689 {
1690 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1691 break;
1692 }
1693
1694 if ( strcmp(a->argv[4], "--removeonsuspend")
1695 || ( strcmp(a->argv[5], "yes")
1696 && strcmp(a->argv[5], "no")))
1697 {
1698 errorSyntax(USAGE_CONTROLVM, "Invalid parameters");
1699 break;
1700 }
1701
1702 BOOL fRemoveOnSuspend = FALSE;
1703 Bstr bstrPwId(a->argv[2]);
1704 Utf8Str strPassword;
1705
1706 if (!RTStrCmp(a->argv[3], "-"))
1707 {
1708 /* Get password from console. */
1709 RTEXITCODE rcExit = readPasswordFromConsole(&strPassword, "Enter password:");
1710 if (rcExit == RTEXITCODE_FAILURE)
1711 break;
1712 }
1713 else
1714 {
1715 RTEXITCODE rcExit = readPasswordFile(a->argv[3], &strPassword);
1716 if (rcExit == RTEXITCODE_FAILURE)
1717 {
1718 RTMsgError("Failed to read new password from file");
1719 break;
1720 }
1721 }
1722
1723 if ( a->argc == 6
1724 && !strcmp(a->argv[5], "yes"))
1725 fRemoveOnSuspend = TRUE;
1726
1727 CHECK_ERROR_BREAK(console, AddDiskEncryptionPassword(bstrPwId.raw(), Bstr(strPassword).raw(), fRemoveOnSuspend));
1728 }
1729 else if (!strcmp(a->argv[1], "removeencpassword"))
1730 {
1731 if (a->argc != 3)
1732 {
1733 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1734 break;
1735 }
1736 Bstr bstrPwId(a->argv[2]);
1737 CHECK_ERROR_BREAK(console, RemoveDiskEncryptionPassword(bstrPwId.raw()));
1738 }
1739 else if (!strcmp(a->argv[1], "removeallencpasswords"))
1740 {
1741 CHECK_ERROR_BREAK(console, ClearAllDiskEncryptionPasswords());
1742 }
1743 else
1744 {
1745 errorSyntax(USAGE_CONTROLVM, "Invalid parameter '%s'", a->argv[1]);
1746 rc = E_FAIL;
1747 }
1748 } while (0);
1749
1750 /* The client has to trigger saving the state explicitely. */
1751 if (fNeedsSaving)
1752 CHECK_ERROR(sessionMachine, SaveSettings());
1753
1754 a->session->UnlockMachine();
1755
1756 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1757}
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