VirtualBox

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

Last change on this file since 61226 was 58434, checked in by vboxsync, 9 years ago

VBoxManage: don't crash on 'control addencpassword'

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 65.3 KB
Line 
1/* $Id: VBoxManageControlVM.cpp 58434 2015-10-27 16:11:52Z 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(AttachmentType)(NetworkAttachmentType_Null), RTEXITCODE_FAILURE);
719 }
720 else if (!strcmp(a->argv[2], "nat"))
721 {
722 if (a->argc == 4)
723 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
724 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_NAT), RTEXITCODE_FAILURE);
725 }
726 else if ( !strcmp(a->argv[2], "bridged")
727 || !strcmp(a->argv[2], "hostif")) /* backward compatibility */
728 {
729 if (a->argc <= 3)
730 {
731 errorArgument("Missing argument to '%s'", a->argv[2]);
732 rc = E_FAIL;
733 break;
734 }
735 CHECK_ERROR_RET(adapter, COMSETTER(BridgedInterface)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
736 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Bridged), RTEXITCODE_FAILURE);
737 }
738 else if (!strcmp(a->argv[2], "intnet"))
739 {
740 if (a->argc <= 3)
741 {
742 errorArgument("Missing argument to '%s'", a->argv[2]);
743 rc = E_FAIL;
744 break;
745 }
746 CHECK_ERROR_RET(adapter, COMSETTER(InternalNetwork)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
747 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Internal), RTEXITCODE_FAILURE);
748 }
749#if defined(VBOX_WITH_NETFLT)
750 else if (!strcmp(a->argv[2], "hostonly"))
751 {
752 if (a->argc <= 3)
753 {
754 errorArgument("Missing argument to '%s'", a->argv[2]);
755 rc = E_FAIL;
756 break;
757 }
758 CHECK_ERROR_RET(adapter, COMSETTER(HostOnlyInterface)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
759 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_HostOnly), RTEXITCODE_FAILURE);
760 }
761#endif
762 else if (!strcmp(a->argv[2], "generic"))
763 {
764 if (a->argc <= 3)
765 {
766 errorArgument("Missing argument to '%s'", a->argv[2]);
767 rc = E_FAIL;
768 break;
769 }
770 CHECK_ERROR_RET(adapter, COMSETTER(GenericDriver)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
771 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic), RTEXITCODE_FAILURE);
772 }
773 else if (!strcmp(a->argv[2], "natnetwork"))
774 {
775 if (a->argc <= 3)
776 {
777 errorArgument("Missing argument to '%s'", a->argv[2]);
778 rc = E_FAIL;
779 break;
780 }
781 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
782 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_NATNetwork), RTEXITCODE_FAILURE);
783 }
784 /** @todo obsolete, remove eventually */
785 else if (!strcmp(a->argv[2], "vde"))
786 {
787 if (a->argc <= 3)
788 {
789 errorArgument("Missing argument to '%s'", a->argv[2]);
790 rc = E_FAIL;
791 break;
792 }
793 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic), RTEXITCODE_FAILURE);
794 CHECK_ERROR_RET(adapter, SetProperty(Bstr("name").raw(), Bstr(a->argv[3]).raw()), RTEXITCODE_FAILURE);
795 }
796 else
797 {
798 errorArgument("Invalid type '%s' specfied for NIC %lu", Utf8Str(a->argv[2]).c_str(), n);
799 rc = E_FAIL;
800 break;
801 }
802 if (SUCCEEDED(rc))
803 fNeedsSaving = true;
804 }
805 else
806 RTMsgError("The NIC %d is currently disabled and thus its attachment type can't be changed", n);
807 }
808 }
809 else if ( !strcmp(a->argv[1], "vrde")
810 || !strcmp(a->argv[1], "vrdp"))
811 {
812 if (!strcmp(a->argv[1], "vrdp"))
813 RTStrmPrintf(g_pStdErr, "Warning: 'vrdp' is deprecated. Use 'vrde'.\n");
814
815 if (a->argc <= 1 + 1)
816 {
817 errorArgument("Missing argument to '%s'", a->argv[1]);
818 rc = E_FAIL;
819 break;
820 }
821 ComPtr<IVRDEServer> vrdeServer;
822 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
823 ASSERT(vrdeServer);
824 if (vrdeServer)
825 {
826 if (!strcmp(a->argv[2], "on"))
827 {
828 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(TRUE));
829 }
830 else if (!strcmp(a->argv[2], "off"))
831 {
832 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(FALSE));
833 }
834 else
835 {
836 errorArgument("Invalid remote desktop server state '%s'", Utf8Str(a->argv[2]).c_str());
837 rc = E_FAIL;
838 break;
839 }
840 if (SUCCEEDED(rc))
841 fNeedsSaving = true;
842 }
843 }
844 else if ( !strcmp(a->argv[1], "vrdeport")
845 || !strcmp(a->argv[1], "vrdpport"))
846 {
847 if (!strcmp(a->argv[1], "vrdpport"))
848 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpport' is deprecated. Use 'vrdeport'.\n");
849
850 if (a->argc <= 1 + 1)
851 {
852 errorArgument("Missing argument to '%s'", a->argv[1]);
853 rc = E_FAIL;
854 break;
855 }
856
857 ComPtr<IVRDEServer> vrdeServer;
858 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
859 ASSERT(vrdeServer);
860 if (vrdeServer)
861 {
862 Bstr ports;
863
864 if (!strcmp(a->argv[2], "default"))
865 ports = "0";
866 else
867 ports = a->argv[2];
868
869 CHECK_ERROR_BREAK(vrdeServer, SetVRDEProperty(Bstr("TCP/Ports").raw(), ports.raw()));
870 if (SUCCEEDED(rc))
871 fNeedsSaving = true;
872 }
873 }
874 else if ( !strcmp(a->argv[1], "vrdevideochannelquality")
875 || !strcmp(a->argv[1], "vrdpvideochannelquality"))
876 {
877 if (!strcmp(a->argv[1], "vrdpvideochannelquality"))
878 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpvideochannelquality' is deprecated. Use 'vrdevideochannelquality'.\n");
879
880 if (a->argc <= 1 + 1)
881 {
882 errorArgument("Missing argument to '%s'", a->argv[1]);
883 rc = E_FAIL;
884 break;
885 }
886 ComPtr<IVRDEServer> vrdeServer;
887 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
888 ASSERT(vrdeServer);
889 if (vrdeServer)
890 {
891 Bstr value = a->argv[2];
892
893 CHECK_ERROR(vrdeServer, SetVRDEProperty(Bstr("VideoChannel/Quality").raw(), value.raw()));
894 if (SUCCEEDED(rc))
895 fNeedsSaving = true;
896 }
897 }
898 else if (!strcmp(a->argv[1], "vrdeproperty"))
899 {
900 if (a->argc <= 1 + 1)
901 {
902 errorArgument("Missing argument to '%s'", a->argv[1]);
903 rc = E_FAIL;
904 break;
905 }
906 ComPtr<IVRDEServer> vrdeServer;
907 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
908 ASSERT(vrdeServer);
909 if (vrdeServer)
910 {
911 /* Parse 'name=value' */
912 char *pszProperty = RTStrDup(a->argv[2]);
913 if (pszProperty)
914 {
915 char *pDelimiter = strchr(pszProperty, '=');
916 if (pDelimiter)
917 {
918 *pDelimiter = '\0';
919
920 Bstr bstrName = pszProperty;
921 Bstr bstrValue = &pDelimiter[1];
922 CHECK_ERROR(vrdeServer, SetVRDEProperty(bstrName.raw(), bstrValue.raw()));
923 if (SUCCEEDED(rc))
924 fNeedsSaving = true;
925 }
926 else
927 {
928 errorArgument("Invalid vrdeproperty argument '%s'", a->argv[2]);
929 rc = E_FAIL;
930 }
931 RTStrFree(pszProperty);
932 }
933 else
934 {
935 RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for VRDE property '%s'\n", a->argv[2]);
936 rc = E_FAIL;
937 }
938 }
939 if (FAILED(rc))
940 {
941 break;
942 }
943 }
944 else if ( !strcmp(a->argv[1], "usbattach")
945 || !strcmp(a->argv[1], "usbdetach"))
946 {
947 if (a->argc < 3)
948 {
949 errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
950 rc = E_FAIL;
951 break;
952 }
953 else if (a->argc == 4 || a->argc > 5)
954 {
955 errorSyntax(USAGE_CONTROLVM, "Wrong number of arguments");
956 rc = E_FAIL;
957 break;
958 }
959
960 bool attach = !strcmp(a->argv[1], "usbattach");
961
962 Bstr usbId = a->argv[2];
963 Bstr captureFilename;
964
965 if (a->argc == 5)
966 {
967 if (!strcmp(a->argv[3], "--capturefile"))
968 captureFilename = a->argv[4];
969 else
970 {
971 errorArgument("Invalid parameter '%s'", a->argv[3]);
972 rc = E_FAIL;
973 break;
974 }
975 }
976
977 Guid guid(usbId);
978 if (!guid.isValid())
979 {
980 // assume address
981 if (attach)
982 {
983 ComPtr<IHost> host;
984 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
985 SafeIfaceArray <IHostUSBDevice> coll;
986 CHECK_ERROR_BREAK(host, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
987 ComPtr<IHostUSBDevice> dev;
988 CHECK_ERROR_BREAK(host, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
989 dev.asOutParam()));
990 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
991 }
992 else
993 {
994 SafeIfaceArray <IUSBDevice> coll;
995 CHECK_ERROR_BREAK(console, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
996 ComPtr<IUSBDevice> dev;
997 CHECK_ERROR_BREAK(console, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
998 dev.asOutParam()));
999 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
1000 }
1001 }
1002 else if (guid.isZero())
1003 {
1004 errorArgument("Zero UUID argument '%s'", a->argv[2]);
1005 rc = E_FAIL;
1006 break;
1007 }
1008
1009 if (attach)
1010 CHECK_ERROR_BREAK(console, AttachUSBDevice(usbId.raw(), captureFilename.raw()));
1011 else
1012 {
1013 ComPtr<IUSBDevice> dev;
1014 CHECK_ERROR_BREAK(console, DetachUSBDevice(usbId.raw(),
1015 dev.asOutParam()));
1016 }
1017 }
1018 else if (!strcmp(a->argv[1], "setvideomodehint"))
1019 {
1020 if (a->argc != 5 && a->argc != 6 && a->argc != 7 && a->argc != 9)
1021 {
1022 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1023 rc = E_FAIL;
1024 break;
1025 }
1026 bool fEnabled = true;
1027 uint32_t uXRes = RTStrToUInt32(a->argv[2]);
1028 uint32_t uYRes = RTStrToUInt32(a->argv[3]);
1029 uint32_t uBpp = RTStrToUInt32(a->argv[4]);
1030 uint32_t uDisplayIdx = 0;
1031 bool fChangeOrigin = false;
1032 int32_t iOriginX = 0;
1033 int32_t iOriginY = 0;
1034 if (a->argc >= 6)
1035 uDisplayIdx = RTStrToUInt32(a->argv[5]);
1036 if (a->argc >= 7)
1037 {
1038 int vrc = parseBool(a->argv[6], &fEnabled);
1039 if (RT_FAILURE(vrc))
1040 {
1041 errorSyntax(USAGE_CONTROLVM, "Either \"yes\" or \"no\" is expected");
1042 rc = E_FAIL;
1043 break;
1044 }
1045 fEnabled = !RTStrICmp(a->argv[6], "yes");
1046 }
1047 if (a->argc == 9)
1048 {
1049 iOriginX = RTStrToInt32(a->argv[7]);
1050 iOriginY = RTStrToInt32(a->argv[8]);
1051 fChangeOrigin = true;
1052 }
1053
1054 ComPtr<IDisplay> pDisplay;
1055 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1056 if (!pDisplay)
1057 {
1058 RTMsgError("Guest not running");
1059 rc = E_FAIL;
1060 break;
1061 }
1062 CHECK_ERROR_BREAK(pDisplay, SetVideoModeHint(uDisplayIdx, fEnabled,
1063 fChangeOrigin, iOriginX, iOriginY,
1064 uXRes, uYRes, uBpp));
1065 }
1066 else if (!strcmp(a->argv[1], "setcredentials"))
1067 {
1068 bool fAllowLocalLogon = true;
1069 if ( a->argc == 7
1070 || ( a->argc == 8
1071 && ( !strcmp(a->argv[3], "-p")
1072 || !strcmp(a->argv[3], "--passwordfile"))))
1073 {
1074 if ( strcmp(a->argv[5 + (a->argc - 7)], "--allowlocallogon")
1075 && strcmp(a->argv[5 + (a->argc - 7)], "-allowlocallogon"))
1076 {
1077 errorArgument("Invalid parameter '%s'", a->argv[5]);
1078 rc = E_FAIL;
1079 break;
1080 }
1081 if (!strcmp(a->argv[6 + (a->argc - 7)], "no"))
1082 fAllowLocalLogon = false;
1083 }
1084 else if ( a->argc != 5
1085 && ( a->argc != 6
1086 || ( strcmp(a->argv[3], "-p")
1087 && strcmp(a->argv[3], "--passwordfile"))))
1088 {
1089 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1090 rc = E_FAIL;
1091 break;
1092 }
1093 Utf8Str passwd, domain;
1094 if (a->argc == 5 || a->argc == 7)
1095 {
1096 passwd = a->argv[3];
1097 domain = a->argv[4];
1098 }
1099 else
1100 {
1101 RTEXITCODE rcExit = readPasswordFile(a->argv[4], &passwd);
1102 if (rcExit != RTEXITCODE_SUCCESS)
1103 {
1104 rc = E_FAIL;
1105 break;
1106 }
1107 domain = a->argv[5];
1108 }
1109
1110 ComPtr<IGuest> pGuest;
1111 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest.asOutParam()));
1112 if (!pGuest)
1113 {
1114 RTMsgError("Guest not running");
1115 rc = E_FAIL;
1116 break;
1117 }
1118 CHECK_ERROR_BREAK(pGuest, SetCredentials(Bstr(a->argv[2]).raw(),
1119 Bstr(passwd).raw(),
1120 Bstr(domain).raw(),
1121 fAllowLocalLogon));
1122 }
1123#if 0 /* TODO: review & remove */
1124 else if (!strcmp(a->argv[1], "dvdattach"))
1125 {
1126 Bstr uuid;
1127 if (a->argc != 3)
1128 {
1129 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1130 rc = E_FAIL;
1131 break;
1132 }
1133
1134 ComPtr<IMedium> dvdMedium;
1135
1136 /* unmount? */
1137 if (!strcmp(a->argv[2], "none"))
1138 {
1139 /* nothing to do, NULL object will cause unmount */
1140 }
1141 /* host drive? */
1142 else if (!strncmp(a->argv[2], "host:", 5))
1143 {
1144 ComPtr<IHost> host;
1145 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1146
1147 rc = host->FindHostDVDDrive(Bstr(a->argv[2] + 5), dvdMedium.asOutParam());
1148 if (!dvdMedium)
1149 {
1150 errorArgument("Invalid host DVD drive name \"%s\"",
1151 a->argv[2] + 5);
1152 rc = E_FAIL;
1153 break;
1154 }
1155 }
1156 else
1157 {
1158 /* first assume it's a UUID */
1159 uuid = a->argv[2];
1160 rc = a->virtualBox->GetDVDImage(uuid, dvdMedium.asOutParam());
1161 if (FAILED(rc) || !dvdMedium)
1162 {
1163 /* must be a filename, check if it's in the collection */
1164 rc = a->virtualBox->FindDVDImage(Bstr(a->argv[2]), dvdMedium.asOutParam());
1165 /* not registered, do that on the fly */
1166 if (!dvdMedium)
1167 {
1168 Bstr emptyUUID;
1169 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(a->argv[2]), emptyUUID, dvdMedium.asOutParam()));
1170 }
1171 }
1172 if (!dvdMedium)
1173 {
1174 rc = E_FAIL;
1175 break;
1176 }
1177 }
1178
1179 /** @todo generalize this, allow arbitrary number of DVD drives
1180 * and as a consequence multiple attachments and different
1181 * storage controllers. */
1182 if (dvdMedium)
1183 dvdMedium->COMGETTER(Id)(uuid.asOutParam());
1184 else
1185 uuid = Guid().toString();
1186 CHECK_ERROR(machine, MountMedium(Bstr("IDE Controller"), 1, 0, uuid, FALSE /* aForce */));
1187 }
1188 else if (!strcmp(a->argv[1], "floppyattach"))
1189 {
1190 Bstr uuid;
1191 if (a->argc != 3)
1192 {
1193 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1194 rc = E_FAIL;
1195 break;
1196 }
1197
1198 ComPtr<IMedium> floppyMedium;
1199
1200 /* unmount? */
1201 if (!strcmp(a->argv[2], "none"))
1202 {
1203 /* nothing to do, NULL object will cause unmount */
1204 }
1205 /* host drive? */
1206 else if (!strncmp(a->argv[2], "host:", 5))
1207 {
1208 ComPtr<IHost> host;
1209 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1210 host->FindHostFloppyDrive(Bstr(a->argv[2] + 5), floppyMedium.asOutParam());
1211 if (!floppyMedium)
1212 {
1213 errorArgument("Invalid host floppy drive name \"%s\"",
1214 a->argv[2] + 5);
1215 rc = E_FAIL;
1216 break;
1217 }
1218 }
1219 else
1220 {
1221 /* first assume it's a UUID */
1222 uuid = a->argv[2];
1223 rc = a->virtualBox->GetFloppyImage(uuid, floppyMedium.asOutParam());
1224 if (FAILED(rc) || !floppyMedium)
1225 {
1226 /* must be a filename, check if it's in the collection */
1227 rc = a->virtualBox->FindFloppyImage(Bstr(a->argv[2]), floppyMedium.asOutParam());
1228 /* not registered, do that on the fly */
1229 if (!floppyMedium)
1230 {
1231 Bstr emptyUUID;
1232 CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(a->argv[2]), emptyUUID, floppyMedium.asOutParam()));
1233 }
1234 }
1235 if (!floppyMedium)
1236 {
1237 rc = E_FAIL;
1238 break;
1239 }
1240 }
1241 floppyMedium->COMGETTER(Id)(uuid.asOutParam());
1242 CHECK_ERROR(machine, MountMedium(Bstr("Floppy Controller"), 0, 0, uuid, FALSE /* aForce */));
1243 }
1244#endif /* obsolete dvdattach/floppyattach */
1245 else if (!strcmp(a->argv[1], "guestmemoryballoon"))
1246 {
1247 if (a->argc != 3)
1248 {
1249 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1250 rc = E_FAIL;
1251 break;
1252 }
1253 uint32_t uVal;
1254 int vrc;
1255 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1256 if (vrc != VINF_SUCCESS)
1257 {
1258 errorArgument("Error parsing guest memory balloon size '%s'", a->argv[2]);
1259 rc = E_FAIL;
1260 break;
1261 }
1262 /* guest is running; update IGuest */
1263 ComPtr<IGuest> pGuest;
1264 rc = console->COMGETTER(Guest)(pGuest.asOutParam());
1265 if (SUCCEEDED(rc))
1266 {
1267 if (!pGuest)
1268 {
1269 RTMsgError("Guest not running");
1270 rc = E_FAIL;
1271 break;
1272 }
1273 CHECK_ERROR(pGuest, COMSETTER(MemoryBalloonSize)(uVal));
1274 }
1275 }
1276 else if (!strcmp(a->argv[1], "teleport"))
1277 {
1278 Bstr bstrHostname;
1279 uint32_t uMaxDowntime = 250 /*ms*/;
1280 uint32_t uPort = UINT32_MAX;
1281 uint32_t cMsTimeout = 0;
1282 Utf8Str strPassword;
1283 static const RTGETOPTDEF s_aTeleportOptions[] =
1284 {
1285 { "--host", 'h', RTGETOPT_REQ_STRING }, /** @todo RTGETOPT_FLAG_MANDATORY */
1286 { "--hostname", 'h', RTGETOPT_REQ_STRING }, /** @todo remove this */
1287 { "--maxdowntime", 'd', RTGETOPT_REQ_UINT32 },
1288 { "--port", 'P', RTGETOPT_REQ_UINT32 }, /** @todo RTGETOPT_FLAG_MANDATORY */
1289 { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
1290 { "--password", 'W', RTGETOPT_REQ_STRING },
1291 { "--timeout", 't', RTGETOPT_REQ_UINT32 },
1292 { "--detailed-progress", 'D', RTGETOPT_REQ_NOTHING }
1293 };
1294 RTGETOPTSTATE GetOptState;
1295 RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTeleportOptions, RT_ELEMENTS(s_aTeleportOptions), 2, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1296 int ch;
1297 RTGETOPTUNION Value;
1298 while ( SUCCEEDED(rc)
1299 && (ch = RTGetOpt(&GetOptState, &Value)))
1300 {
1301 switch (ch)
1302 {
1303 case 'h': bstrHostname = Value.psz; break;
1304 case 'd': uMaxDowntime = Value.u32; break;
1305 case 'D': g_fDetailedProgress = true; break;
1306 case 'P': uPort = Value.u32; break;
1307 case 'p':
1308 {
1309 RTEXITCODE rcExit = readPasswordFile(Value.psz, &strPassword);
1310 if (rcExit != RTEXITCODE_SUCCESS)
1311 rc = E_FAIL;
1312 break;
1313 }
1314 case 'W': strPassword = Value.psz; break;
1315 case 't': cMsTimeout = Value.u32; break;
1316 default:
1317 errorGetOpt(USAGE_CONTROLVM, ch, &Value);
1318 rc = E_FAIL;
1319 break;
1320 }
1321 }
1322 if (FAILED(rc))
1323 break;
1324
1325 ComPtr<IProgress> progress;
1326 CHECK_ERROR_BREAK(console, Teleport(bstrHostname.raw(), uPort,
1327 Bstr(strPassword).raw(),
1328 uMaxDowntime,
1329 progress.asOutParam()));
1330
1331 if (cMsTimeout)
1332 {
1333 rc = progress->COMSETTER(Timeout)(cMsTimeout);
1334 if (FAILED(rc) && rc != VBOX_E_INVALID_OBJECT_STATE)
1335 CHECK_ERROR_BREAK(progress, COMSETTER(Timeout)(cMsTimeout)); /* lazyness */
1336 }
1337
1338 rc = showProgress(progress);
1339 CHECK_PROGRESS_ERROR(progress, ("Teleportation failed"));
1340 }
1341 else if (!strcmp(a->argv[1], "screenshotpng"))
1342 {
1343 if (a->argc <= 2 || a->argc > 4)
1344 {
1345 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1346 rc = E_FAIL;
1347 break;
1348 }
1349 int vrc;
1350 uint32_t iScreen = 0;
1351 if (a->argc == 4)
1352 {
1353 vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &iScreen);
1354 if (vrc != VINF_SUCCESS)
1355 {
1356 errorArgument("Error parsing display number '%s'", a->argv[3]);
1357 rc = E_FAIL;
1358 break;
1359 }
1360 }
1361 ComPtr<IDisplay> pDisplay;
1362 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1363 if (!pDisplay)
1364 {
1365 RTMsgError("Guest not running");
1366 rc = E_FAIL;
1367 break;
1368 }
1369 ULONG width, height, bpp;
1370 LONG xOrigin, yOrigin;
1371 GuestMonitorStatus_T monitorStatus;
1372 CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(iScreen, &width, &height, &bpp, &xOrigin, &yOrigin, &monitorStatus));
1373 com::SafeArray<BYTE> saScreenshot;
1374 CHECK_ERROR_BREAK(pDisplay, TakeScreenShotToArray(iScreen, width, height, BitmapFormat_PNG, ComSafeArrayAsOutParam(saScreenshot)));
1375 RTFILE pngFile = NIL_RTFILE;
1376 vrc = RTFileOpen(&pngFile, a->argv[2], RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_TRUNCATE | RTFILE_O_DENY_ALL);
1377 if (RT_FAILURE(vrc))
1378 {
1379 RTMsgError("Failed to create file '%s' (%Rrc)", a->argv[2], vrc);
1380 rc = E_FAIL;
1381 break;
1382 }
1383 vrc = RTFileWrite(pngFile, saScreenshot.raw(), saScreenshot.size(), NULL);
1384 if (RT_FAILURE(vrc))
1385 {
1386 RTMsgError("Failed to write screenshot to file '%s' (%Rrc)", a->argv[2], vrc);
1387 rc = E_FAIL;
1388 }
1389 RTFileClose(pngFile);
1390 }
1391#ifdef VBOX_WITH_VPX
1392 /*
1393 * Note: Commands starting with "vcp" are the deprecated versions and are
1394 * kept to ensure backwards compatibility.
1395 */
1396 else if ( !strcmp(a->argv[1], "videocap")
1397 || !strcmp(a->argv[1], "vcpenabled"))
1398 {
1399 if (a->argc != 3)
1400 {
1401 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1402 rc = E_FAIL;
1403 break;
1404 }
1405 if (!strcmp(a->argv[2], "on"))
1406 {
1407 CHECK_ERROR_RET(sessionMachine, COMSETTER(VideoCaptureEnabled)(TRUE), RTEXITCODE_FAILURE);
1408 }
1409 else if (!strcmp(a->argv[2], "off"))
1410 {
1411 CHECK_ERROR_RET(sessionMachine, COMSETTER(VideoCaptureEnabled)(FALSE), RTEXITCODE_FAILURE);
1412 }
1413 else
1414 {
1415 errorArgument("Invalid state '%s'", Utf8Str(a->argv[2]).c_str());
1416 rc = E_FAIL;
1417 break;
1418 }
1419 }
1420 else if ( !strcmp(a->argv[1], "videocapscreens")
1421 || !strcmp(a->argv[1], "vcpscreens"))
1422 {
1423 ULONG cMonitors = 64;
1424 CHECK_ERROR_BREAK(machine, COMGETTER(MonitorCount)(&cMonitors));
1425 com::SafeArray<BOOL> saScreens(cMonitors);
1426 if ( a->argc == 3
1427 && !strcmp(a->argv[2], "all"))
1428 {
1429 /* enable all screens */
1430 for (unsigned i = 0; i < cMonitors; i++)
1431 saScreens[i] = true;
1432 }
1433 else if ( a->argc == 3
1434 && !strcmp(a->argv[2], "none"))
1435 {
1436 /* disable all screens */
1437 for (unsigned i = 0; i < cMonitors; i++)
1438 saScreens[i] = false;
1439
1440 /** @todo r=andy What if this is specified? */
1441 }
1442 else
1443 {
1444 /* enable selected screens */
1445 for (unsigned i = 0; i < cMonitors; i++)
1446 saScreens[i] = false;
1447 for (int i = 2; SUCCEEDED(rc) && i < a->argc; i++)
1448 {
1449 uint32_t iScreen;
1450 int vrc = RTStrToUInt32Ex(a->argv[i], NULL, 0, &iScreen);
1451 if (vrc != VINF_SUCCESS)
1452 {
1453 errorArgument("Error parsing display number '%s'", a->argv[i]);
1454 rc = E_FAIL;
1455 break;
1456 }
1457 if (iScreen >= cMonitors)
1458 {
1459 errorArgument("Invalid screen ID specified '%u'", iScreen);
1460 rc = E_FAIL;
1461 break;
1462 }
1463 saScreens[iScreen] = true;
1464 }
1465 }
1466
1467 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureScreens)(ComSafeArrayAsInParam(saScreens)));
1468 }
1469 else if ( !strcmp(a->argv[1], "videocapfile")
1470 || !strcmp(a->argv[1], "vcpfile"))
1471 {
1472 if (a->argc != 3)
1473 {
1474 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1475 rc = E_FAIL;
1476 break;
1477 }
1478
1479 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureFile)(Bstr(a->argv[3]).raw()));
1480 }
1481 else if (!strcmp(a->argv[1], "videocapres"))
1482 {
1483 if (a->argc != 4)
1484 {
1485 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1486 rc = E_FAIL;
1487 break;
1488 }
1489
1490 uint32_t uVal;
1491 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1492 if (RT_FAILURE(vrc))
1493 {
1494 errorArgument("Error parsing width '%s'", a->argv[2]);
1495 rc = E_FAIL;
1496 break;
1497 }
1498 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureWidth)(uVal));
1499
1500 vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &uVal);
1501 if (RT_FAILURE(vrc))
1502 {
1503 errorArgument("Error parsing height '%s'", a->argv[3]);
1504 rc = E_FAIL;
1505 break;
1506 }
1507 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureHeight)(uVal));
1508 }
1509 else if (!strcmp(a->argv[1], "vcpwidth")) /* Deprecated; keeping for compatibility. */
1510 {
1511 uint32_t uVal;
1512 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1513 if (RT_FAILURE(vrc))
1514 {
1515 errorArgument("Error parsing width '%s'", a->argv[2]);
1516 rc = E_FAIL;
1517 break;
1518 }
1519 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureWidth)(uVal));
1520 }
1521 else if (!strcmp(a->argv[1], "vcpheight")) /* Deprecated; keeping for compatibility. */
1522 {
1523 uint32_t uVal;
1524 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1525 if (RT_FAILURE(vrc))
1526 {
1527 errorArgument("Error parsing height '%s'", a->argv[2]);
1528 rc = E_FAIL;
1529 break;
1530 }
1531 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureHeight)(uVal));
1532 }
1533 else if ( !strcmp(a->argv[1], "videocaprate")
1534 || !strcmp(a->argv[1], "vcprate"))
1535 {
1536 if (a->argc != 3)
1537 {
1538 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1539 rc = E_FAIL;
1540 break;
1541 }
1542
1543 uint32_t uVal;
1544 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1545 if (RT_FAILURE(vrc))
1546 {
1547 errorArgument("Error parsing rate '%s'", a->argv[2]);
1548 rc = E_FAIL;
1549 break;
1550 }
1551 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureRate)(uVal));
1552 }
1553 else if ( !strcmp(a->argv[1], "videocapfps")
1554 || !strcmp(a->argv[1], "vcpfps"))
1555 {
1556 if (a->argc != 3)
1557 {
1558 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1559 rc = E_FAIL;
1560 break;
1561 }
1562
1563 uint32_t uVal;
1564 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1565 if (RT_FAILURE(vrc))
1566 {
1567 errorArgument("Error parsing FPS '%s'", a->argv[2]);
1568 rc = E_FAIL;
1569 break;
1570 }
1571 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureFPS)(uVal));
1572 }
1573 else if ( !strcmp(a->argv[1], "videocapmaxtime")
1574 || !strcmp(a->argv[1], "vcpmaxtime"))
1575 {
1576 if (a->argc != 3)
1577 {
1578 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1579 rc = E_FAIL;
1580 break;
1581 }
1582
1583 uint32_t uVal;
1584 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1585 if (RT_FAILURE(vrc))
1586 {
1587 errorArgument("Error parsing maximum time '%s'", a->argv[2]);
1588 rc = E_FAIL;
1589 break;
1590 }
1591 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureMaxTime)(uVal));
1592 }
1593 else if ( !strcmp(a->argv[1], "videocapmaxsize")
1594 || !strcmp(a->argv[1], "vcpmaxsize"))
1595 {
1596 if (a->argc != 3)
1597 {
1598 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1599 rc = E_FAIL;
1600 break;
1601 }
1602
1603 uint32_t uVal;
1604 int vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1605 if (RT_FAILURE(vrc))
1606 {
1607 errorArgument("Error parsing maximum file size '%s'", a->argv[2]);
1608 rc = E_FAIL;
1609 break;
1610 }
1611 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureMaxFileSize)(uVal));
1612 }
1613 else if ( !strcmp(a->argv[1], "videocapopts")
1614 || !strcmp(a->argv[1], "vcpoptions"))
1615 {
1616 if (a->argc != 3)
1617 {
1618 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1619 rc = E_FAIL;
1620 break;
1621 }
1622
1623 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureOptions)(Bstr(a->argv[3]).raw()));
1624 }
1625#endif /* VBOX_WITH_VPX */
1626 else if (!strcmp(a->argv[1], "webcam"))
1627 {
1628 if (a->argc < 3)
1629 {
1630 errorArgument("Missing argument to '%s'", a->argv[1]);
1631 rc = E_FAIL;
1632 break;
1633 }
1634
1635 ComPtr<IEmulatedUSB> pEmulatedUSB;
1636 CHECK_ERROR_BREAK(console, COMGETTER(EmulatedUSB)(pEmulatedUSB.asOutParam()));
1637 if (!pEmulatedUSB)
1638 {
1639 RTMsgError("Guest not running");
1640 rc = E_FAIL;
1641 break;
1642 }
1643
1644 if (!strcmp(a->argv[2], "attach"))
1645 {
1646 Bstr path("");
1647 if (a->argc >= 4)
1648 path = a->argv[3];
1649 Bstr settings("");
1650 if (a->argc >= 5)
1651 settings = a->argv[4];
1652 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamAttach(path.raw(), settings.raw()));
1653 }
1654 else if (!strcmp(a->argv[2], "detach"))
1655 {
1656 Bstr path("");
1657 if (a->argc >= 4)
1658 path = a->argv[3];
1659 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamDetach(path.raw()));
1660 }
1661 else if (!strcmp(a->argv[2], "list"))
1662 {
1663 com::SafeArray <BSTR> webcams;
1664 CHECK_ERROR_BREAK(pEmulatedUSB, COMGETTER(Webcams)(ComSafeArrayAsOutParam(webcams)));
1665 for (size_t i = 0; i < webcams.size(); ++i)
1666 {
1667 RTPrintf("%ls\n", webcams[i][0]? webcams[i]: Bstr("default").raw());
1668 }
1669 }
1670 else
1671 {
1672 errorArgument("Invalid argument to '%s'", a->argv[1]);
1673 rc = E_FAIL;
1674 break;
1675 }
1676 }
1677 else if (!strcmp(a->argv[1], "addencpassword"))
1678 {
1679 if ( a->argc != 4
1680 && a->argc != 6)
1681 {
1682 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1683 break;
1684 }
1685
1686 BOOL fRemoveOnSuspend = FALSE;
1687 if (a->argc == 6)
1688 {
1689 if ( strcmp(a->argv[4], "--removeonsuspend")
1690 || ( strcmp(a->argv[5], "yes")
1691 && strcmp(a->argv[5], "no")))
1692 {
1693 errorSyntax(USAGE_CONTROLVM, "Invalid parameters");
1694 break;
1695 }
1696 if (!strcmp(a->argv[5], "yes"))
1697 fRemoveOnSuspend = TRUE;
1698 }
1699
1700 Bstr bstrPwId(a->argv[2]);
1701 Utf8Str strPassword;
1702
1703 if (!RTStrCmp(a->argv[3], "-"))
1704 {
1705 /* Get password from console. */
1706 RTEXITCODE rcExit = readPasswordFromConsole(&strPassword, "Enter password:");
1707 if (rcExit == RTEXITCODE_FAILURE)
1708 break;
1709 }
1710 else
1711 {
1712 RTEXITCODE rcExit = readPasswordFile(a->argv[3], &strPassword);
1713 if (rcExit == RTEXITCODE_FAILURE)
1714 {
1715 RTMsgError("Failed to read new password from file");
1716 break;
1717 }
1718 }
1719
1720 CHECK_ERROR_BREAK(console, AddDiskEncryptionPassword(bstrPwId.raw(), Bstr(strPassword).raw(), fRemoveOnSuspend));
1721 }
1722 else if (!strcmp(a->argv[1], "removeencpassword"))
1723 {
1724 if (a->argc != 3)
1725 {
1726 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1727 break;
1728 }
1729 Bstr bstrPwId(a->argv[2]);
1730 CHECK_ERROR_BREAK(console, RemoveDiskEncryptionPassword(bstrPwId.raw()));
1731 }
1732 else if (!strcmp(a->argv[1], "removeallencpasswords"))
1733 {
1734 CHECK_ERROR_BREAK(console, ClearAllDiskEncryptionPasswords());
1735 }
1736 else
1737 {
1738 errorSyntax(USAGE_CONTROLVM, "Invalid parameter '%s'", a->argv[1]);
1739 rc = E_FAIL;
1740 }
1741 } while (0);
1742
1743 /* The client has to trigger saving the state explicitely. */
1744 if (fNeedsSaving)
1745 CHECK_ERROR(sessionMachine, SaveSettings());
1746
1747 a->session->UnlockMachine();
1748
1749 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1750}
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