VirtualBox

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

Last change on this file since 48406 was 48406, checked in by vboxsync, 11 years ago

Main,VBoxManage: Implemented IConsole::EmulatedUSB. Removed IMachine::emulatedUSBWebcameraEnabled.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 55.1 KB
Line 
1/* $Id: VBoxManageControlVM.cpp 48406 2013-09-10 12:53:50Z vboxsync $ */
2/** @file
3 * VBoxManage - Implementation of the controlvm command.
4 */
5
6/*
7 * Copyright (C) 2006-2013 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 DragAndDropMode_T mode;
201 if (!strcmp(a->argv[2], "disabled"))
202 mode = DragAndDropMode_Disabled;
203 else if (!strcmp(a->argv[2], "hosttoguest"))
204 mode = DragAndDropMode_HostToGuest;
205 else if (!strcmp(a->argv[2], "guesttohost"))
206 mode = DragAndDropMode_GuestToHost;
207 else if (!strcmp(a->argv[2], "bidirectional"))
208 mode = DragAndDropMode_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(DragAndDropMode)(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
349 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
350 if (!n)
351 {
352 rc = E_FAIL;
353 break;
354 }
355 if (a->argc <= 1 + 1)
356 {
357 errorArgument("Missing argument to '%s'", a->argv[1]);
358 rc = E_FAIL;
359 break;
360 }
361 /* get the corresponding network adapter */
362 ComPtr<INetworkAdapter> adapter;
363 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
364 if (adapter)
365 {
366 if (!strcmp(a->argv[2], "on"))
367 {
368 CHECK_ERROR_BREAK(adapter, COMSETTER(CableConnected)(TRUE));
369 }
370 else if (!strcmp(a->argv[2], "off"))
371 {
372 CHECK_ERROR_BREAK(adapter, COMSETTER(CableConnected)(FALSE));
373 }
374 else
375 {
376 errorArgument("Invalid link state '%s'", Utf8Str(a->argv[2]).c_str());
377 rc = E_FAIL;
378 break;
379 }
380 }
381 }
382 /* here the order in which strncmp is called is important
383 * cause nictracefile can be very well compared with
384 * nictrace and nic and thus everything will always fail
385 * if the order is changed
386 */
387 else if (!strncmp(a->argv[1], "nictracefile", 12))
388 {
389 /* Get the number of network adapters */
390 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
391 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
392 if (!n)
393 {
394 rc = E_FAIL;
395 break;
396 }
397 if (a->argc <= 2)
398 {
399 errorArgument("Missing argument to '%s'", a->argv[1]);
400 rc = E_FAIL;
401 break;
402 }
403
404 /* get the corresponding network adapter */
405 ComPtr<INetworkAdapter> adapter;
406 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
407 if (adapter)
408 {
409 BOOL fEnabled;
410 adapter->COMGETTER(Enabled)(&fEnabled);
411 if (fEnabled)
412 {
413 if (a->argv[2])
414 {
415 CHECK_ERROR_RET(adapter, COMSETTER(TraceFile)(Bstr(a->argv[2]).raw()), 1);
416 }
417 else
418 {
419 errorArgument("Invalid filename or filename not specified for NIC %lu", n);
420 rc = E_FAIL;
421 break;
422 }
423 }
424 else
425 RTMsgError("The NIC %d is currently disabled and thus its tracefile can't be changed", n);
426 }
427 }
428 else if (!strncmp(a->argv[1], "nictrace", 8))
429 {
430 /* Get the number of network adapters */
431 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
432
433 unsigned n = parseNum(&a->argv[1][8], NetworkAdapterCount, "NIC");
434 if (!n)
435 {
436 rc = E_FAIL;
437 break;
438 }
439 if (a->argc <= 2)
440 {
441 errorArgument("Missing argument to '%s'", a->argv[1]);
442 rc = E_FAIL;
443 break;
444 }
445
446 /* get the corresponding network adapter */
447 ComPtr<INetworkAdapter> adapter;
448 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
449 if (adapter)
450 {
451 BOOL fEnabled;
452 adapter->COMGETTER(Enabled)(&fEnabled);
453 if (fEnabled)
454 {
455 if (!strcmp(a->argv[2], "on"))
456 {
457 CHECK_ERROR_RET(adapter, COMSETTER(TraceEnabled)(TRUE), 1);
458 }
459 else if (!strcmp(a->argv[2], "off"))
460 {
461 CHECK_ERROR_RET(adapter, COMSETTER(TraceEnabled)(FALSE), 1);
462 }
463 else
464 {
465 errorArgument("Invalid nictrace%lu argument '%s'", n, Utf8Str(a->argv[2]).c_str());
466 rc = E_FAIL;
467 break;
468 }
469 }
470 else
471 RTMsgError("The NIC %d is currently disabled and thus its trace flag can't be changed", n);
472 }
473 }
474 else if( a->argc > 2
475 && !strncmp(a->argv[1], "natpf", 5))
476 {
477 /* Get the number of network adapters */
478 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
479 ComPtr<INATEngine> engine;
480 unsigned n = parseNum(&a->argv[1][5], NetworkAdapterCount, "NIC");
481 if (!n)
482 {
483 rc = E_FAIL;
484 break;
485 }
486 if (a->argc <= 2)
487 {
488 errorArgument("Missing argument to '%s'", a->argv[1]);
489 rc = E_FAIL;
490 break;
491 }
492
493 /* get the corresponding network adapter */
494 ComPtr<INetworkAdapter> adapter;
495 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
496 if (!adapter)
497 {
498 rc = E_FAIL;
499 break;
500 }
501 CHECK_ERROR(adapter, COMGETTER(NATEngine)(engine.asOutParam()));
502 if (!engine)
503 {
504 rc = E_FAIL;
505 break;
506 }
507
508 if (!strcmp(a->argv[2], "delete"))
509 {
510 if (a->argc >= 3)
511 CHECK_ERROR(engine, RemoveRedirect(Bstr(a->argv[3]).raw()));
512 }
513 else
514 {
515#define ITERATE_TO_NEXT_TERM(ch) \
516 do { \
517 while (*ch != ',') \
518 { \
519 if (*ch == 0) \
520 { \
521 return errorSyntax(USAGE_CONTROLVM, \
522 "Missing or invalid argument to '%s'", \
523 a->argv[1]); \
524 } \
525 ch++; \
526 } \
527 *ch = '\0'; \
528 ch++; \
529 } while(0)
530
531 char *strName;
532 char *strProto;
533 char *strHostIp;
534 char *strHostPort;
535 char *strGuestIp;
536 char *strGuestPort;
537 char *strRaw = RTStrDup(a->argv[2]);
538 char *ch = strRaw;
539 strName = RTStrStrip(ch);
540 ITERATE_TO_NEXT_TERM(ch);
541 strProto = RTStrStrip(ch);
542 ITERATE_TO_NEXT_TERM(ch);
543 strHostIp = RTStrStrip(ch);
544 ITERATE_TO_NEXT_TERM(ch);
545 strHostPort = RTStrStrip(ch);
546 ITERATE_TO_NEXT_TERM(ch);
547 strGuestIp = RTStrStrip(ch);
548 ITERATE_TO_NEXT_TERM(ch);
549 strGuestPort = RTStrStrip(ch);
550 NATProtocol_T proto;
551 if (RTStrICmp(strProto, "udp") == 0)
552 proto = NATProtocol_UDP;
553 else if (RTStrICmp(strProto, "tcp") == 0)
554 proto = NATProtocol_TCP;
555 else
556 {
557 return errorSyntax(USAGE_CONTROLVM,
558 "Wrong rule proto '%s' specified -- only 'udp' and 'tcp' are allowed.",
559 strProto);
560 }
561 CHECK_ERROR(engine, AddRedirect(Bstr(strName).raw(), proto, Bstr(strHostIp).raw(),
562 RTStrToUInt16(strHostPort), Bstr(strGuestIp).raw(), RTStrToUInt16(strGuestPort)));
563#undef ITERATE_TO_NEXT_TERM
564 }
565 /* commit changes */
566 if (SUCCEEDED(rc))
567 CHECK_ERROR(sessionMachine, SaveSettings());
568 }
569 else if (!strncmp(a->argv[1], "nicproperty", 11))
570 {
571 /* Get the number of network adapters */
572 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox,sessionMachine) ;
573 unsigned n = parseNum(&a->argv[1][11], NetworkAdapterCount, "NIC");
574 if (!n)
575 {
576 rc = E_FAIL;
577 break;
578 }
579 if (a->argc <= 2)
580 {
581 errorArgument("Missing argument to '%s'", a->argv[1]);
582 rc = E_FAIL;
583 break;
584 }
585
586 /* get the corresponding network adapter */
587 ComPtr<INetworkAdapter> adapter;
588 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
589 if (adapter)
590 {
591 BOOL fEnabled;
592 adapter->COMGETTER(Enabled)(&fEnabled);
593 if (fEnabled)
594 {
595 /* Parse 'name=value' */
596 char *pszProperty = RTStrDup(a->argv[2]);
597 if (pszProperty)
598 {
599 char *pDelimiter = strchr(pszProperty, '=');
600 if (pDelimiter)
601 {
602 *pDelimiter = '\0';
603
604 Bstr bstrName = pszProperty;
605 Bstr bstrValue = &pDelimiter[1];
606 CHECK_ERROR(adapter, SetProperty(bstrName.raw(), bstrValue.raw()));
607 }
608 else
609 {
610 errorArgument("Invalid nicproperty%d argument '%s'", n, a->argv[2]);
611 rc = E_FAIL;
612 }
613 RTStrFree(pszProperty);
614 }
615 else
616 {
617 RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for nicproperty%d '%s'\n", n, a->argv[2]);
618 rc = E_FAIL;
619 }
620 if (FAILED(rc))
621 break;
622 }
623 else
624 RTMsgError("The NIC %d is currently disabled and thus its properties can't be changed", n);
625 }
626 }
627 else if (!strncmp(a->argv[1], "nicpromisc", 10))
628 {
629 /* Get the number of network adapters */
630 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox,sessionMachine) ;
631 unsigned n = parseNum(&a->argv[1][10], NetworkAdapterCount, "NIC");
632 if (!n)
633 {
634 rc = E_FAIL;
635 break;
636 }
637 if (a->argc <= 2)
638 {
639 errorArgument("Missing argument to '%s'", a->argv[1]);
640 rc = E_FAIL;
641 break;
642 }
643
644 /* get the corresponding network adapter */
645 ComPtr<INetworkAdapter> adapter;
646 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
647 if (adapter)
648 {
649 BOOL fEnabled;
650 adapter->COMGETTER(Enabled)(&fEnabled);
651 if (fEnabled)
652 {
653 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
654 if (!strcmp(a->argv[2], "deny"))
655 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_Deny;
656 else if ( !strcmp(a->argv[2], "allow-vms")
657 || !strcmp(a->argv[2], "allow-network"))
658 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowNetwork;
659 else if (!strcmp(a->argv[2], "allow-all"))
660 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowAll;
661 else
662 {
663 errorArgument("Unknown promiscuous mode policy '%s'", a->argv[2]);
664 rc = E_INVALIDARG;
665 break;
666 }
667
668 CHECK_ERROR(adapter, COMSETTER(PromiscModePolicy)(enmPromiscModePolicy));
669 }
670 else
671 RTMsgError("The NIC %d is currently disabled and thus its promiscuous mode can't be changed", n);
672 }
673 }
674 else if (!strncmp(a->argv[1], "nic", 3))
675 {
676 /* Get the number of network adapters */
677 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox,sessionMachine) ;
678 unsigned n = parseNum(&a->argv[1][3], NetworkAdapterCount, "NIC");
679 if (!n)
680 {
681 rc = E_FAIL;
682 break;
683 }
684 if (a->argc <= 2)
685 {
686 errorArgument("Missing argument to '%s'", a->argv[1]);
687 rc = E_FAIL;
688 break;
689 }
690
691 /* get the corresponding network adapter */
692 ComPtr<INetworkAdapter> adapter;
693 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
694 if (adapter)
695 {
696 BOOL fEnabled;
697 adapter->COMGETTER(Enabled)(&fEnabled);
698 if (fEnabled)
699 {
700 if (!strcmp(a->argv[2], "null"))
701 {
702 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
703 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Null), 1);
704 }
705 else if (!strcmp(a->argv[2], "nat"))
706 {
707 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
708 if (a->argc == 4)
709 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3]).raw()), 1);
710 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_NAT), 1);
711 }
712 else if ( !strcmp(a->argv[2], "bridged")
713 || !strcmp(a->argv[2], "hostif")) /* backward compatibility */
714 {
715 if (a->argc <= 3)
716 {
717 errorArgument("Missing argument to '%s'", a->argv[2]);
718 rc = E_FAIL;
719 break;
720 }
721 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
722 CHECK_ERROR_RET(adapter, COMSETTER(BridgedInterface)(Bstr(a->argv[3]).raw()), 1);
723 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Bridged), 1);
724 }
725 else if (!strcmp(a->argv[2], "intnet"))
726 {
727 if (a->argc <= 3)
728 {
729 errorArgument("Missing argument to '%s'", a->argv[2]);
730 rc = E_FAIL;
731 break;
732 }
733 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
734 CHECK_ERROR_RET(adapter, COMSETTER(InternalNetwork)(Bstr(a->argv[3]).raw()), 1);
735 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Internal), 1);
736 }
737#if defined(VBOX_WITH_NETFLT)
738 else if (!strcmp(a->argv[2], "hostonly"))
739 {
740 if (a->argc <= 3)
741 {
742 errorArgument("Missing argument to '%s'", a->argv[2]);
743 rc = E_FAIL;
744 break;
745 }
746 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
747 CHECK_ERROR_RET(adapter, COMSETTER(HostOnlyInterface)(Bstr(a->argv[3]).raw()), 1);
748 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_HostOnly), 1);
749 }
750#endif
751 else if (!strcmp(a->argv[2], "generic"))
752 {
753 if (a->argc <= 3)
754 {
755 errorArgument("Missing argument to '%s'", a->argv[2]);
756 rc = E_FAIL;
757 break;
758 }
759 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
760 CHECK_ERROR_RET(adapter, COMSETTER(GenericDriver)(Bstr(a->argv[3]).raw()), 1);
761 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic), 1);
762 }
763 /** @todo obsolete, remove eventually */
764 else if (!strcmp(a->argv[2], "vde"))
765 {
766 if (a->argc <= 3)
767 {
768 errorArgument("Missing argument to '%s'", a->argv[2]);
769 rc = E_FAIL;
770 break;
771 }
772 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
773 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic), 1);
774 CHECK_ERROR_RET(adapter, SetProperty(Bstr("name").raw(), Bstr(a->argv[3]).raw()), 1);
775 }
776 else
777 {
778 errorArgument("Invalid type '%s' specfied for NIC %lu", Utf8Str(a->argv[2]).c_str(), n);
779 rc = E_FAIL;
780 break;
781 }
782 }
783 else
784 RTMsgError("The NIC %d is currently disabled and thus its attachment type can't be changed", n);
785 }
786 }
787 else if ( !strcmp(a->argv[1], "vrde")
788 || !strcmp(a->argv[1], "vrdp"))
789 {
790 if (!strcmp(a->argv[1], "vrdp"))
791 RTStrmPrintf(g_pStdErr, "Warning: 'vrdp' is deprecated. Use 'vrde'.\n");
792
793 if (a->argc <= 1 + 1)
794 {
795 errorArgument("Missing argument to '%s'", a->argv[1]);
796 rc = E_FAIL;
797 break;
798 }
799 ComPtr<IVRDEServer> vrdeServer;
800 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
801 ASSERT(vrdeServer);
802 if (vrdeServer)
803 {
804 if (!strcmp(a->argv[2], "on"))
805 {
806 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(TRUE));
807 }
808 else if (!strcmp(a->argv[2], "off"))
809 {
810 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(FALSE));
811 }
812 else
813 {
814 errorArgument("Invalid remote desktop server state '%s'", Utf8Str(a->argv[2]).c_str());
815 rc = E_FAIL;
816 break;
817 }
818 }
819 }
820 else if ( !strcmp(a->argv[1], "vrdeport")
821 || !strcmp(a->argv[1], "vrdpport"))
822 {
823 if (!strcmp(a->argv[1], "vrdpport"))
824 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpport' is deprecated. Use 'vrdeport'.\n");
825
826 if (a->argc <= 1 + 1)
827 {
828 errorArgument("Missing argument to '%s'", a->argv[1]);
829 rc = E_FAIL;
830 break;
831 }
832
833 ComPtr<IVRDEServer> vrdeServer;
834 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
835 ASSERT(vrdeServer);
836 if (vrdeServer)
837 {
838 Bstr ports;
839
840 if (!strcmp(a->argv[2], "default"))
841 ports = "0";
842 else
843 ports = a->argv[2];
844
845 CHECK_ERROR_BREAK(vrdeServer, SetVRDEProperty(Bstr("TCP/Ports").raw(), ports.raw()));
846 }
847 }
848 else if ( !strcmp(a->argv[1], "vrdevideochannelquality")
849 || !strcmp(a->argv[1], "vrdpvideochannelquality"))
850 {
851 if (!strcmp(a->argv[1], "vrdpvideochannelquality"))
852 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpvideochannelquality' is deprecated. Use 'vrdevideochannelquality'.\n");
853
854 if (a->argc <= 1 + 1)
855 {
856 errorArgument("Missing argument to '%s'", a->argv[1]);
857 rc = E_FAIL;
858 break;
859 }
860 ComPtr<IVRDEServer> vrdeServer;
861 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
862 ASSERT(vrdeServer);
863 if (vrdeServer)
864 {
865 Bstr value = a->argv[2];
866
867 CHECK_ERROR(vrdeServer, SetVRDEProperty(Bstr("VideoChannel/Quality").raw(), value.raw()));
868 }
869 }
870 else if (!strcmp(a->argv[1], "vrdeproperty"))
871 {
872 if (a->argc <= 1 + 1)
873 {
874 errorArgument("Missing argument to '%s'", a->argv[1]);
875 rc = E_FAIL;
876 break;
877 }
878 ComPtr<IVRDEServer> vrdeServer;
879 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
880 ASSERT(vrdeServer);
881 if (vrdeServer)
882 {
883 /* Parse 'name=value' */
884 char *pszProperty = RTStrDup(a->argv[2]);
885 if (pszProperty)
886 {
887 char *pDelimiter = strchr(pszProperty, '=');
888 if (pDelimiter)
889 {
890 *pDelimiter = '\0';
891
892 Bstr bstrName = pszProperty;
893 Bstr bstrValue = &pDelimiter[1];
894 CHECK_ERROR(vrdeServer, SetVRDEProperty(bstrName.raw(), bstrValue.raw()));
895 }
896 else
897 {
898 errorArgument("Invalid vrdeproperty argument '%s'", a->argv[2]);
899 rc = E_FAIL;
900 }
901 RTStrFree(pszProperty);
902 }
903 else
904 {
905 RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for VRDE property '%s'\n", a->argv[2]);
906 rc = E_FAIL;
907 }
908 }
909 if (FAILED(rc))
910 {
911 break;
912 }
913 }
914 else if ( !strcmp(a->argv[1], "usbattach")
915 || !strcmp(a->argv[1], "usbdetach"))
916 {
917 if (a->argc < 3)
918 {
919 errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
920 rc = E_FAIL;
921 break;
922 }
923
924 bool attach = !strcmp(a->argv[1], "usbattach");
925
926 Bstr usbId = a->argv[2];
927
928 Guid guid(usbId);
929 if (!guid.isValid())
930 {
931 // assume address
932 if (attach)
933 {
934 ComPtr<IHost> host;
935 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
936 SafeIfaceArray <IHostUSBDevice> coll;
937 CHECK_ERROR_BREAK(host, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
938 ComPtr<IHostUSBDevice> dev;
939 CHECK_ERROR_BREAK(host, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
940 dev.asOutParam()));
941 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
942 }
943 else
944 {
945 SafeIfaceArray <IUSBDevice> coll;
946 CHECK_ERROR_BREAK(console, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
947 ComPtr<IUSBDevice> dev;
948 CHECK_ERROR_BREAK(console, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
949 dev.asOutParam()));
950 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
951 }
952 }
953 else if (guid.isZero())
954 {
955 errorArgument("Zero UUID argument '%s'", a->argv[2]);
956 rc = E_FAIL;
957 break;
958 }
959
960 if (attach)
961 CHECK_ERROR_BREAK(console, AttachUSBDevice(usbId.raw()));
962 else
963 {
964 ComPtr<IUSBDevice> dev;
965 CHECK_ERROR_BREAK(console, DetachUSBDevice(usbId.raw(),
966 dev.asOutParam()));
967 }
968 }
969 else if (!strcmp(a->argv[1], "setvideomodehint"))
970 {
971 if (a->argc != 5 && a->argc != 6 && a->argc != 7 && a->argc != 9)
972 {
973 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
974 rc = E_FAIL;
975 break;
976 }
977 bool fEnabled = true;
978 uint32_t uXRes = RTStrToUInt32(a->argv[2]);
979 uint32_t uYRes = RTStrToUInt32(a->argv[3]);
980 uint32_t uBpp = RTStrToUInt32(a->argv[4]);
981 uint32_t uDisplayIdx = 0;
982 bool fChangeOrigin = false;
983 int32_t iOriginX = 0;
984 int32_t iOriginY = 0;
985 if (a->argc >= 6)
986 uDisplayIdx = RTStrToUInt32(a->argv[5]);
987 if (a->argc >= 7)
988 {
989 int vrc = parseBool(a->argv[6], &fEnabled);
990 if (RT_FAILURE(vrc))
991 {
992 errorSyntax(USAGE_CONTROLVM, "Either \"yes\" or \"no\" is expected");
993 rc = E_FAIL;
994 break;
995 }
996 fEnabled = !RTStrICmp(a->argv[6], "yes");
997 }
998 if (a->argc == 9)
999 {
1000 iOriginX = RTStrToInt32(a->argv[7]);
1001 iOriginY = RTStrToInt32(a->argv[8]);
1002 fChangeOrigin = true;
1003 }
1004
1005 ComPtr<IDisplay> pDisplay;
1006 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1007 if (!pDisplay)
1008 {
1009 RTMsgError("Guest not running");
1010 rc = E_FAIL;
1011 break;
1012 }
1013 CHECK_ERROR_BREAK(pDisplay, SetVideoModeHint(uDisplayIdx, fEnabled,
1014 fChangeOrigin, iOriginX, iOriginY,
1015 uXRes, uYRes, uBpp));
1016 }
1017 else if (!strcmp(a->argv[1], "setcredentials"))
1018 {
1019 bool fAllowLocalLogon = true;
1020 if ( a->argc == 7
1021 || ( a->argc == 8
1022 && ( !strcmp(a->argv[3], "-p")
1023 || !strcmp(a->argv[3], "--passwordfile"))))
1024 {
1025 if ( strcmp(a->argv[5 + (a->argc - 7)], "--allowlocallogon")
1026 && strcmp(a->argv[5 + (a->argc - 7)], "-allowlocallogon"))
1027 {
1028 errorArgument("Invalid parameter '%s'", a->argv[5]);
1029 rc = E_FAIL;
1030 break;
1031 }
1032 if (!strcmp(a->argv[6 + (a->argc - 7)], "no"))
1033 fAllowLocalLogon = false;
1034 }
1035 else if ( a->argc != 5
1036 && ( a->argc != 6
1037 || ( strcmp(a->argv[3], "-p")
1038 && strcmp(a->argv[3], "--passwordfile"))))
1039 {
1040 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1041 rc = E_FAIL;
1042 break;
1043 }
1044 Utf8Str passwd, domain;
1045 if (a->argc == 5 || a->argc == 7)
1046 {
1047 passwd = a->argv[3];
1048 domain = a->argv[4];
1049 }
1050 else
1051 {
1052 RTEXITCODE rcExit = readPasswordFile(a->argv[4], &passwd);
1053 if (rcExit != RTEXITCODE_SUCCESS)
1054 {
1055 rc = E_FAIL;
1056 break;
1057 }
1058 domain = a->argv[5];
1059 }
1060
1061 ComPtr<IGuest> pGuest;
1062 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest.asOutParam()));
1063 if (!pGuest)
1064 {
1065 RTMsgError("Guest not running");
1066 rc = E_FAIL;
1067 break;
1068 }
1069 CHECK_ERROR_BREAK(pGuest, SetCredentials(Bstr(a->argv[2]).raw(),
1070 Bstr(passwd).raw(),
1071 Bstr(domain).raw(),
1072 fAllowLocalLogon));
1073 }
1074#if 0 /* TODO: review & remove */
1075 else if (!strcmp(a->argv[1], "dvdattach"))
1076 {
1077 Bstr uuid;
1078 if (a->argc != 3)
1079 {
1080 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1081 rc = E_FAIL;
1082 break;
1083 }
1084
1085 ComPtr<IMedium> dvdMedium;
1086
1087 /* unmount? */
1088 if (!strcmp(a->argv[2], "none"))
1089 {
1090 /* nothing to do, NULL object will cause unmount */
1091 }
1092 /* host drive? */
1093 else if (!strncmp(a->argv[2], "host:", 5))
1094 {
1095 ComPtr<IHost> host;
1096 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1097
1098 rc = host->FindHostDVDDrive(Bstr(a->argv[2] + 5), dvdMedium.asOutParam());
1099 if (!dvdMedium)
1100 {
1101 errorArgument("Invalid host DVD drive name \"%s\"",
1102 a->argv[2] + 5);
1103 rc = E_FAIL;
1104 break;
1105 }
1106 }
1107 else
1108 {
1109 /* first assume it's a UUID */
1110 uuid = a->argv[2];
1111 rc = a->virtualBox->GetDVDImage(uuid, dvdMedium.asOutParam());
1112 if (FAILED(rc) || !dvdMedium)
1113 {
1114 /* must be a filename, check if it's in the collection */
1115 rc = a->virtualBox->FindDVDImage(Bstr(a->argv[2]), dvdMedium.asOutParam());
1116 /* not registered, do that on the fly */
1117 if (!dvdMedium)
1118 {
1119 Bstr emptyUUID;
1120 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(a->argv[2]), emptyUUID, dvdMedium.asOutParam()));
1121 }
1122 }
1123 if (!dvdMedium)
1124 {
1125 rc = E_FAIL;
1126 break;
1127 }
1128 }
1129
1130 /** @todo generalize this, allow arbitrary number of DVD drives
1131 * and as a consequence multiple attachments and different
1132 * storage controllers. */
1133 if (dvdMedium)
1134 dvdMedium->COMGETTER(Id)(uuid.asOutParam());
1135 else
1136 uuid = Guid().toString();
1137 CHECK_ERROR(machine, MountMedium(Bstr("IDE Controller"), 1, 0, uuid, FALSE /* aForce */));
1138 }
1139 else if (!strcmp(a->argv[1], "floppyattach"))
1140 {
1141 Bstr uuid;
1142 if (a->argc != 3)
1143 {
1144 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1145 rc = E_FAIL;
1146 break;
1147 }
1148
1149 ComPtr<IMedium> floppyMedium;
1150
1151 /* unmount? */
1152 if (!strcmp(a->argv[2], "none"))
1153 {
1154 /* nothing to do, NULL object will cause unmount */
1155 }
1156 /* host drive? */
1157 else if (!strncmp(a->argv[2], "host:", 5))
1158 {
1159 ComPtr<IHost> host;
1160 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1161 host->FindHostFloppyDrive(Bstr(a->argv[2] + 5), floppyMedium.asOutParam());
1162 if (!floppyMedium)
1163 {
1164 errorArgument("Invalid host floppy drive name \"%s\"",
1165 a->argv[2] + 5);
1166 rc = E_FAIL;
1167 break;
1168 }
1169 }
1170 else
1171 {
1172 /* first assume it's a UUID */
1173 uuid = a->argv[2];
1174 rc = a->virtualBox->GetFloppyImage(uuid, floppyMedium.asOutParam());
1175 if (FAILED(rc) || !floppyMedium)
1176 {
1177 /* must be a filename, check if it's in the collection */
1178 rc = a->virtualBox->FindFloppyImage(Bstr(a->argv[2]), floppyMedium.asOutParam());
1179 /* not registered, do that on the fly */
1180 if (!floppyMedium)
1181 {
1182 Bstr emptyUUID;
1183 CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(a->argv[2]), emptyUUID, floppyMedium.asOutParam()));
1184 }
1185 }
1186 if (!floppyMedium)
1187 {
1188 rc = E_FAIL;
1189 break;
1190 }
1191 }
1192 floppyMedium->COMGETTER(Id)(uuid.asOutParam());
1193 CHECK_ERROR(machine, MountMedium(Bstr("Floppy Controller"), 0, 0, uuid, FALSE /* aForce */));
1194 }
1195#endif /* obsolete dvdattach/floppyattach */
1196 else if (!strcmp(a->argv[1], "guestmemoryballoon"))
1197 {
1198 if (a->argc != 3)
1199 {
1200 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1201 rc = E_FAIL;
1202 break;
1203 }
1204 uint32_t uVal;
1205 int vrc;
1206 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1207 if (vrc != VINF_SUCCESS)
1208 {
1209 errorArgument("Error parsing guest memory balloon size '%s'", a->argv[2]);
1210 rc = E_FAIL;
1211 break;
1212 }
1213 /* guest is running; update IGuest */
1214 ComPtr<IGuest> pGuest;
1215 rc = console->COMGETTER(Guest)(pGuest.asOutParam());
1216 if (SUCCEEDED(rc))
1217 {
1218 if (!pGuest)
1219 {
1220 RTMsgError("Guest not running");
1221 rc = E_FAIL;
1222 break;
1223 }
1224 CHECK_ERROR(pGuest, COMSETTER(MemoryBalloonSize)(uVal));
1225 }
1226 }
1227 else if (!strcmp(a->argv[1], "teleport"))
1228 {
1229 Bstr bstrHostname;
1230 uint32_t uMaxDowntime = 250 /*ms*/;
1231 uint32_t uPort = UINT32_MAX;
1232 uint32_t cMsTimeout = 0;
1233 Utf8Str strPassword;
1234 static const RTGETOPTDEF s_aTeleportOptions[] =
1235 {
1236 { "--host", 'h', RTGETOPT_REQ_STRING }, /** @todo RTGETOPT_FLAG_MANDATORY */
1237 { "--hostname", 'h', RTGETOPT_REQ_STRING }, /** @todo remove this */
1238 { "--maxdowntime", 'd', RTGETOPT_REQ_UINT32 },
1239 { "--port", 'P', RTGETOPT_REQ_UINT32 }, /** @todo RTGETOPT_FLAG_MANDATORY */
1240 { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
1241 { "--password", 'W', RTGETOPT_REQ_STRING },
1242 { "--timeout", 't', RTGETOPT_REQ_UINT32 },
1243 { "--detailed-progress", 'D', RTGETOPT_REQ_NOTHING }
1244 };
1245 RTGETOPTSTATE GetOptState;
1246 RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTeleportOptions, RT_ELEMENTS(s_aTeleportOptions), 2, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1247 int ch;
1248 RTGETOPTUNION Value;
1249 while ( SUCCEEDED(rc)
1250 && (ch = RTGetOpt(&GetOptState, &Value)))
1251 {
1252 switch (ch)
1253 {
1254 case 'h': bstrHostname = Value.psz; break;
1255 case 'd': uMaxDowntime = Value.u32; break;
1256 case 'D': g_fDetailedProgress = true; break;
1257 case 'P': uPort = Value.u32; break;
1258 case 'p':
1259 {
1260 RTEXITCODE rcExit = readPasswordFile(Value.psz, &strPassword);
1261 if (rcExit != RTEXITCODE_SUCCESS)
1262 rc = E_FAIL;
1263 break;
1264 }
1265 case 'W': strPassword = Value.psz; break;
1266 case 't': cMsTimeout = Value.u32; break;
1267 default:
1268 errorGetOpt(USAGE_CONTROLVM, ch, &Value);
1269 rc = E_FAIL;
1270 break;
1271 }
1272 }
1273 if (FAILED(rc))
1274 break;
1275
1276 ComPtr<IProgress> progress;
1277 CHECK_ERROR_BREAK(console, Teleport(bstrHostname.raw(), uPort,
1278 Bstr(strPassword).raw(),
1279 uMaxDowntime,
1280 progress.asOutParam()));
1281
1282 if (cMsTimeout)
1283 {
1284 rc = progress->COMSETTER(Timeout)(cMsTimeout);
1285 if (FAILED(rc) && rc != VBOX_E_INVALID_OBJECT_STATE)
1286 CHECK_ERROR_BREAK(progress, COMSETTER(Timeout)(cMsTimeout)); /* lazyness */
1287 }
1288
1289 rc = showProgress(progress);
1290 CHECK_PROGRESS_ERROR(progress, ("Teleportation failed"));
1291 }
1292 else if (!strcmp(a->argv[1], "screenshotpng"))
1293 {
1294 if (a->argc <= 2 || a->argc > 4)
1295 {
1296 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1297 rc = E_FAIL;
1298 break;
1299 }
1300 int vrc;
1301 uint32_t iScreen = 0;
1302 if (a->argc == 4)
1303 {
1304 vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &iScreen);
1305 if (vrc != VINF_SUCCESS)
1306 {
1307 errorArgument("Error parsing display number '%s'", a->argv[3]);
1308 rc = E_FAIL;
1309 break;
1310 }
1311 }
1312 ComPtr<IDisplay> pDisplay;
1313 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1314 if (!pDisplay)
1315 {
1316 RTMsgError("Guest not running");
1317 rc = E_FAIL;
1318 break;
1319 }
1320 ULONG width, height, bpp;
1321 LONG xOrigin, yOrigin;
1322 CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(iScreen, &width, &height, &bpp, &xOrigin, &yOrigin));
1323 com::SafeArray<BYTE> saScreenshot;
1324 CHECK_ERROR_BREAK(pDisplay, TakeScreenShotPNGToArray(iScreen, width, height, ComSafeArrayAsOutParam(saScreenshot)));
1325 RTFILE pngFile = NIL_RTFILE;
1326 vrc = RTFileOpen(&pngFile, a->argv[2], RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_TRUNCATE | RTFILE_O_DENY_ALL);
1327 if (RT_FAILURE(vrc))
1328 {
1329 RTMsgError("Failed to create file '%s'. rc=%Rrc", a->argv[2], vrc);
1330 rc = E_FAIL;
1331 break;
1332 }
1333 vrc = RTFileWrite(pngFile, saScreenshot.raw(), saScreenshot.size(), NULL);
1334 if (RT_FAILURE(vrc))
1335 {
1336 RTMsgError("Failed to write screenshot to file '%s'. rc=%Rrc", a->argv[2], vrc);
1337 rc = E_FAIL;
1338 }
1339 RTFileClose(pngFile);
1340 }
1341 else if ( !strcmp(a->argv[1], "vcpenabled"))
1342 {
1343 if (a->argc != 3)
1344 {
1345 errorArgument("Missing argument to '%s'", a->argv[1]);
1346 rc = E_FAIL;
1347 break;
1348 }
1349 if (!strcmp(a->argv[2], "on"))
1350 {
1351 CHECK_ERROR_RET(sessionMachine, COMSETTER(VideoCaptureEnabled)(TRUE), 1);
1352 }
1353 else if (!strcmp(a->argv[2], "off"))
1354 {
1355 CHECK_ERROR_RET(sessionMachine, COMSETTER(VideoCaptureEnabled)(FALSE), 1);
1356 }
1357 else
1358 {
1359 errorArgument("Invalid state '%s'", Utf8Str(a->argv[2]).c_str());
1360 rc = E_FAIL;
1361 break;
1362 }
1363 }
1364 else if ( !strcmp(a->argv[1], "videocapturescreens"))
1365 {
1366 ULONG cMonitors = 64;
1367 CHECK_ERROR_BREAK(machine, COMGETTER(MonitorCount)(&cMonitors));
1368 com::SafeArray<BOOL> saScreens(cMonitors);
1369 if ( a->argc == 3
1370 && !strcmp(a->argv[2], "all"))
1371 {
1372 /* enable all screens */
1373 for (unsigned i = 0; i < cMonitors; i++)
1374 saScreens[i] = true;
1375 }
1376 else if ( a->argc == 3
1377 && !strcmp(a->argv[2], "none"))
1378 {
1379 /* disable all screens */
1380 for (unsigned i = 0; i < cMonitors; i++)
1381 saScreens[i] = false;
1382 }
1383 else
1384 {
1385 /* enable selected screens */
1386 for (unsigned i = 0; i < cMonitors; i++)
1387 saScreens[i] = false;
1388 for (int i = 2; SUCCEEDED(rc) && i < a->argc; i++)
1389 {
1390 uint32_t iScreen;
1391 int vrc = RTStrToUInt32Ex(a->argv[i], NULL, 0, &iScreen);
1392 if (vrc != VINF_SUCCESS)
1393 {
1394 errorArgument("Error parsing display number '%s'", a->argv[i]);
1395 rc = E_FAIL;
1396 break;
1397 }
1398 if (iScreen >= cMonitors)
1399 {
1400 errorArgument("Invalid screen ID specified '%u'", iScreen);
1401 rc = E_FAIL;
1402 break;
1403 }
1404 saScreens[iScreen] = true;
1405 }
1406 }
1407
1408 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureScreens)(ComSafeArrayAsInParam(saScreens)));
1409 }
1410 else if (!strcmp(a->argv[1], "webcam"))
1411 {
1412 if (a->argc < 3)
1413 {
1414 errorArgument("Missing argument to '%s'", a->argv[1]);
1415 rc = E_FAIL;
1416 break;
1417 }
1418
1419 ComPtr<IEmulatedUSB> pEmulatedUSB;
1420 CHECK_ERROR_BREAK(console, COMGETTER(EmulatedUSB)(pEmulatedUSB.asOutParam()));
1421 if (!pEmulatedUSB)
1422 {
1423 RTMsgError("Guest not running");
1424 rc = E_FAIL;
1425 break;
1426 }
1427
1428 if (!strcmp(a->argv[2], "attach"))
1429 {
1430 Bstr path("");
1431 if (a->argc >= 4)
1432 path = a->argv[3];
1433 Bstr settings("");
1434 if (a->argc >= 5)
1435 settings = a->argv[4];
1436 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamAttach(path.raw(), settings.raw()));
1437 }
1438 else if (!strcmp(a->argv[2], "detach"))
1439 {
1440 Bstr path("");
1441 if (a->argc >= 4)
1442 path = a->argv[3];
1443 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamDetach(path.raw()));
1444 }
1445 else if (!strcmp(a->argv[2], "list"))
1446 {
1447 com::SafeArray <BSTR> webcams;
1448 CHECK_ERROR_BREAK(pEmulatedUSB, COMGETTER(Webcams)(ComSafeArrayAsOutParam(webcams)));
1449 for (size_t i = 0; i < webcams.size(); ++i)
1450 {
1451 RTPrintf("%ls\n", webcams[i][0]? webcams[i]: Bstr("default").raw());
1452 }
1453 }
1454 else
1455 {
1456 errorArgument("Invalid argument to '%s'", a->argv[1]);
1457 rc = E_FAIL;
1458 break;
1459 }
1460
1461 }
1462 else
1463 {
1464 errorSyntax(USAGE_CONTROLVM, "Invalid parameter '%s'", a->argv[1]);
1465 rc = E_FAIL;
1466 }
1467 } while (0);
1468
1469 a->session->UnlockMachine();
1470
1471 return SUCCEEDED(rc) ? 0 : 1;
1472}
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