VirtualBox

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

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

*: scm cleanup run.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette