VirtualBox

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

Last change on this file since 56103 was 55940, checked in by vboxsync, 10 years ago

Frontends/VBoxManage: make sure we don't crash when there's no VM process (and thus no console) for the named machine with controlvm.

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