VirtualBox

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

Last change on this file since 54514 was 54421, checked in by vboxsync, 10 years ago

FE/VBoxManage: Backwards compatibility for video capturing options.

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

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