VirtualBox

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

Last change on this file since 54791 was 54591, checked in by vboxsync, 10 years ago

Add support to supply passwords for disk encryption while the VM is running

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