VirtualBox

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

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

Main,Frontends: TakeScreenShot API cleanup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 55.7 KB
Line 
1/* $Id: VBoxManageControlVM.cpp 52200 2014-07-25 20:00:49Z vboxsync $ */
2/** @file
3 * VBoxManage - Implementation of the controlvm command.
4 */
5
6/*
7 * Copyright (C) 2006-2014 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
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 else if (!strcmp(a->argv[2], "natnetwork"))
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(Enabled)(TRUE), 1);
772 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3]).raw()), 1);
773 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_NATNetwork), 1);
774 }
775 /** @todo obsolete, remove eventually */
776 else if (!strcmp(a->argv[2], "vde"))
777 {
778 if (a->argc <= 3)
779 {
780 errorArgument("Missing argument to '%s'", a->argv[2]);
781 rc = E_FAIL;
782 break;
783 }
784 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
785 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic), 1);
786 CHECK_ERROR_RET(adapter, SetProperty(Bstr("name").raw(), Bstr(a->argv[3]).raw()), 1);
787 }
788 else
789 {
790 errorArgument("Invalid type '%s' specfied for NIC %lu", Utf8Str(a->argv[2]).c_str(), n);
791 rc = E_FAIL;
792 break;
793 }
794 }
795 else
796 RTMsgError("The NIC %d is currently disabled and thus its attachment type can't be changed", n);
797 }
798 }
799 else if ( !strcmp(a->argv[1], "vrde")
800 || !strcmp(a->argv[1], "vrdp"))
801 {
802 if (!strcmp(a->argv[1], "vrdp"))
803 RTStrmPrintf(g_pStdErr, "Warning: 'vrdp' is deprecated. Use 'vrde'.\n");
804
805 if (a->argc <= 1 + 1)
806 {
807 errorArgument("Missing argument to '%s'", a->argv[1]);
808 rc = E_FAIL;
809 break;
810 }
811 ComPtr<IVRDEServer> vrdeServer;
812 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
813 ASSERT(vrdeServer);
814 if (vrdeServer)
815 {
816 if (!strcmp(a->argv[2], "on"))
817 {
818 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(TRUE));
819 }
820 else if (!strcmp(a->argv[2], "off"))
821 {
822 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(FALSE));
823 }
824 else
825 {
826 errorArgument("Invalid remote desktop server state '%s'", Utf8Str(a->argv[2]).c_str());
827 rc = E_FAIL;
828 break;
829 }
830 }
831 }
832 else if ( !strcmp(a->argv[1], "vrdeport")
833 || !strcmp(a->argv[1], "vrdpport"))
834 {
835 if (!strcmp(a->argv[1], "vrdpport"))
836 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpport' is deprecated. Use 'vrdeport'.\n");
837
838 if (a->argc <= 1 + 1)
839 {
840 errorArgument("Missing argument to '%s'", a->argv[1]);
841 rc = E_FAIL;
842 break;
843 }
844
845 ComPtr<IVRDEServer> vrdeServer;
846 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
847 ASSERT(vrdeServer);
848 if (vrdeServer)
849 {
850 Bstr ports;
851
852 if (!strcmp(a->argv[2], "default"))
853 ports = "0";
854 else
855 ports = a->argv[2];
856
857 CHECK_ERROR_BREAK(vrdeServer, SetVRDEProperty(Bstr("TCP/Ports").raw(), ports.raw()));
858 }
859 }
860 else if ( !strcmp(a->argv[1], "vrdevideochannelquality")
861 || !strcmp(a->argv[1], "vrdpvideochannelquality"))
862 {
863 if (!strcmp(a->argv[1], "vrdpvideochannelquality"))
864 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpvideochannelquality' is deprecated. Use 'vrdevideochannelquality'.\n");
865
866 if (a->argc <= 1 + 1)
867 {
868 errorArgument("Missing argument to '%s'", a->argv[1]);
869 rc = E_FAIL;
870 break;
871 }
872 ComPtr<IVRDEServer> vrdeServer;
873 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
874 ASSERT(vrdeServer);
875 if (vrdeServer)
876 {
877 Bstr value = a->argv[2];
878
879 CHECK_ERROR(vrdeServer, SetVRDEProperty(Bstr("VideoChannel/Quality").raw(), value.raw()));
880 }
881 }
882 else if (!strcmp(a->argv[1], "vrdeproperty"))
883 {
884 if (a->argc <= 1 + 1)
885 {
886 errorArgument("Missing argument to '%s'", a->argv[1]);
887 rc = E_FAIL;
888 break;
889 }
890 ComPtr<IVRDEServer> vrdeServer;
891 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
892 ASSERT(vrdeServer);
893 if (vrdeServer)
894 {
895 /* Parse 'name=value' */
896 char *pszProperty = RTStrDup(a->argv[2]);
897 if (pszProperty)
898 {
899 char *pDelimiter = strchr(pszProperty, '=');
900 if (pDelimiter)
901 {
902 *pDelimiter = '\0';
903
904 Bstr bstrName = pszProperty;
905 Bstr bstrValue = &pDelimiter[1];
906 CHECK_ERROR(vrdeServer, SetVRDEProperty(bstrName.raw(), bstrValue.raw()));
907 }
908 else
909 {
910 errorArgument("Invalid vrdeproperty argument '%s'", a->argv[2]);
911 rc = E_FAIL;
912 }
913 RTStrFree(pszProperty);
914 }
915 else
916 {
917 RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for VRDE property '%s'\n", a->argv[2]);
918 rc = E_FAIL;
919 }
920 }
921 if (FAILED(rc))
922 {
923 break;
924 }
925 }
926 else if ( !strcmp(a->argv[1], "usbattach")
927 || !strcmp(a->argv[1], "usbdetach"))
928 {
929 if (a->argc < 3)
930 {
931 errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
932 rc = E_FAIL;
933 break;
934 }
935
936 bool attach = !strcmp(a->argv[1], "usbattach");
937
938 Bstr usbId = a->argv[2];
939
940 Guid guid(usbId);
941 if (!guid.isValid())
942 {
943 // assume address
944 if (attach)
945 {
946 ComPtr<IHost> host;
947 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
948 SafeIfaceArray <IHostUSBDevice> coll;
949 CHECK_ERROR_BREAK(host, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
950 ComPtr<IHostUSBDevice> dev;
951 CHECK_ERROR_BREAK(host, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
952 dev.asOutParam()));
953 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
954 }
955 else
956 {
957 SafeIfaceArray <IUSBDevice> coll;
958 CHECK_ERROR_BREAK(console, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
959 ComPtr<IUSBDevice> dev;
960 CHECK_ERROR_BREAK(console, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
961 dev.asOutParam()));
962 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
963 }
964 }
965 else if (guid.isZero())
966 {
967 errorArgument("Zero UUID argument '%s'", a->argv[2]);
968 rc = E_FAIL;
969 break;
970 }
971
972 if (attach)
973 CHECK_ERROR_BREAK(console, AttachUSBDevice(usbId.raw()));
974 else
975 {
976 ComPtr<IUSBDevice> dev;
977 CHECK_ERROR_BREAK(console, DetachUSBDevice(usbId.raw(),
978 dev.asOutParam()));
979 }
980 }
981 else if (!strcmp(a->argv[1], "setvideomodehint"))
982 {
983 if (a->argc != 5 && a->argc != 6 && a->argc != 7 && a->argc != 9)
984 {
985 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
986 rc = E_FAIL;
987 break;
988 }
989 bool fEnabled = true;
990 uint32_t uXRes = RTStrToUInt32(a->argv[2]);
991 uint32_t uYRes = RTStrToUInt32(a->argv[3]);
992 uint32_t uBpp = RTStrToUInt32(a->argv[4]);
993 uint32_t uDisplayIdx = 0;
994 bool fChangeOrigin = false;
995 int32_t iOriginX = 0;
996 int32_t iOriginY = 0;
997 if (a->argc >= 6)
998 uDisplayIdx = RTStrToUInt32(a->argv[5]);
999 if (a->argc >= 7)
1000 {
1001 int vrc = parseBool(a->argv[6], &fEnabled);
1002 if (RT_FAILURE(vrc))
1003 {
1004 errorSyntax(USAGE_CONTROLVM, "Either \"yes\" or \"no\" is expected");
1005 rc = E_FAIL;
1006 break;
1007 }
1008 fEnabled = !RTStrICmp(a->argv[6], "yes");
1009 }
1010 if (a->argc == 9)
1011 {
1012 iOriginX = RTStrToInt32(a->argv[7]);
1013 iOriginY = RTStrToInt32(a->argv[8]);
1014 fChangeOrigin = true;
1015 }
1016
1017 ComPtr<IDisplay> pDisplay;
1018 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1019 if (!pDisplay)
1020 {
1021 RTMsgError("Guest not running");
1022 rc = E_FAIL;
1023 break;
1024 }
1025 CHECK_ERROR_BREAK(pDisplay, SetVideoModeHint(uDisplayIdx, fEnabled,
1026 fChangeOrigin, iOriginX, iOriginY,
1027 uXRes, uYRes, uBpp));
1028 }
1029 else if (!strcmp(a->argv[1], "setcredentials"))
1030 {
1031 bool fAllowLocalLogon = true;
1032 if ( a->argc == 7
1033 || ( a->argc == 8
1034 && ( !strcmp(a->argv[3], "-p")
1035 || !strcmp(a->argv[3], "--passwordfile"))))
1036 {
1037 if ( strcmp(a->argv[5 + (a->argc - 7)], "--allowlocallogon")
1038 && strcmp(a->argv[5 + (a->argc - 7)], "-allowlocallogon"))
1039 {
1040 errorArgument("Invalid parameter '%s'", a->argv[5]);
1041 rc = E_FAIL;
1042 break;
1043 }
1044 if (!strcmp(a->argv[6 + (a->argc - 7)], "no"))
1045 fAllowLocalLogon = false;
1046 }
1047 else if ( a->argc != 5
1048 && ( a->argc != 6
1049 || ( strcmp(a->argv[3], "-p")
1050 && strcmp(a->argv[3], "--passwordfile"))))
1051 {
1052 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1053 rc = E_FAIL;
1054 break;
1055 }
1056 Utf8Str passwd, domain;
1057 if (a->argc == 5 || a->argc == 7)
1058 {
1059 passwd = a->argv[3];
1060 domain = a->argv[4];
1061 }
1062 else
1063 {
1064 RTEXITCODE rcExit = readPasswordFile(a->argv[4], &passwd);
1065 if (rcExit != RTEXITCODE_SUCCESS)
1066 {
1067 rc = E_FAIL;
1068 break;
1069 }
1070 domain = a->argv[5];
1071 }
1072
1073 ComPtr<IGuest> pGuest;
1074 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest.asOutParam()));
1075 if (!pGuest)
1076 {
1077 RTMsgError("Guest not running");
1078 rc = E_FAIL;
1079 break;
1080 }
1081 CHECK_ERROR_BREAK(pGuest, SetCredentials(Bstr(a->argv[2]).raw(),
1082 Bstr(passwd).raw(),
1083 Bstr(domain).raw(),
1084 fAllowLocalLogon));
1085 }
1086#if 0 /* TODO: review & remove */
1087 else if (!strcmp(a->argv[1], "dvdattach"))
1088 {
1089 Bstr uuid;
1090 if (a->argc != 3)
1091 {
1092 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1093 rc = E_FAIL;
1094 break;
1095 }
1096
1097 ComPtr<IMedium> dvdMedium;
1098
1099 /* unmount? */
1100 if (!strcmp(a->argv[2], "none"))
1101 {
1102 /* nothing to do, NULL object will cause unmount */
1103 }
1104 /* host drive? */
1105 else if (!strncmp(a->argv[2], "host:", 5))
1106 {
1107 ComPtr<IHost> host;
1108 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1109
1110 rc = host->FindHostDVDDrive(Bstr(a->argv[2] + 5), dvdMedium.asOutParam());
1111 if (!dvdMedium)
1112 {
1113 errorArgument("Invalid host DVD drive name \"%s\"",
1114 a->argv[2] + 5);
1115 rc = E_FAIL;
1116 break;
1117 }
1118 }
1119 else
1120 {
1121 /* first assume it's a UUID */
1122 uuid = a->argv[2];
1123 rc = a->virtualBox->GetDVDImage(uuid, dvdMedium.asOutParam());
1124 if (FAILED(rc) || !dvdMedium)
1125 {
1126 /* must be a filename, check if it's in the collection */
1127 rc = a->virtualBox->FindDVDImage(Bstr(a->argv[2]), dvdMedium.asOutParam());
1128 /* not registered, do that on the fly */
1129 if (!dvdMedium)
1130 {
1131 Bstr emptyUUID;
1132 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(a->argv[2]), emptyUUID, dvdMedium.asOutParam()));
1133 }
1134 }
1135 if (!dvdMedium)
1136 {
1137 rc = E_FAIL;
1138 break;
1139 }
1140 }
1141
1142 /** @todo generalize this, allow arbitrary number of DVD drives
1143 * and as a consequence multiple attachments and different
1144 * storage controllers. */
1145 if (dvdMedium)
1146 dvdMedium->COMGETTER(Id)(uuid.asOutParam());
1147 else
1148 uuid = Guid().toString();
1149 CHECK_ERROR(machine, MountMedium(Bstr("IDE Controller"), 1, 0, uuid, FALSE /* aForce */));
1150 }
1151 else if (!strcmp(a->argv[1], "floppyattach"))
1152 {
1153 Bstr uuid;
1154 if (a->argc != 3)
1155 {
1156 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1157 rc = E_FAIL;
1158 break;
1159 }
1160
1161 ComPtr<IMedium> floppyMedium;
1162
1163 /* unmount? */
1164 if (!strcmp(a->argv[2], "none"))
1165 {
1166 /* nothing to do, NULL object will cause unmount */
1167 }
1168 /* host drive? */
1169 else if (!strncmp(a->argv[2], "host:", 5))
1170 {
1171 ComPtr<IHost> host;
1172 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1173 host->FindHostFloppyDrive(Bstr(a->argv[2] + 5), floppyMedium.asOutParam());
1174 if (!floppyMedium)
1175 {
1176 errorArgument("Invalid host floppy drive name \"%s\"",
1177 a->argv[2] + 5);
1178 rc = E_FAIL;
1179 break;
1180 }
1181 }
1182 else
1183 {
1184 /* first assume it's a UUID */
1185 uuid = a->argv[2];
1186 rc = a->virtualBox->GetFloppyImage(uuid, floppyMedium.asOutParam());
1187 if (FAILED(rc) || !floppyMedium)
1188 {
1189 /* must be a filename, check if it's in the collection */
1190 rc = a->virtualBox->FindFloppyImage(Bstr(a->argv[2]), floppyMedium.asOutParam());
1191 /* not registered, do that on the fly */
1192 if (!floppyMedium)
1193 {
1194 Bstr emptyUUID;
1195 CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(a->argv[2]), emptyUUID, floppyMedium.asOutParam()));
1196 }
1197 }
1198 if (!floppyMedium)
1199 {
1200 rc = E_FAIL;
1201 break;
1202 }
1203 }
1204 floppyMedium->COMGETTER(Id)(uuid.asOutParam());
1205 CHECK_ERROR(machine, MountMedium(Bstr("Floppy Controller"), 0, 0, uuid, FALSE /* aForce */));
1206 }
1207#endif /* obsolete dvdattach/floppyattach */
1208 else if (!strcmp(a->argv[1], "guestmemoryballoon"))
1209 {
1210 if (a->argc != 3)
1211 {
1212 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1213 rc = E_FAIL;
1214 break;
1215 }
1216 uint32_t uVal;
1217 int vrc;
1218 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1219 if (vrc != VINF_SUCCESS)
1220 {
1221 errorArgument("Error parsing guest memory balloon size '%s'", a->argv[2]);
1222 rc = E_FAIL;
1223 break;
1224 }
1225 /* guest is running; update IGuest */
1226 ComPtr<IGuest> pGuest;
1227 rc = console->COMGETTER(Guest)(pGuest.asOutParam());
1228 if (SUCCEEDED(rc))
1229 {
1230 if (!pGuest)
1231 {
1232 RTMsgError("Guest not running");
1233 rc = E_FAIL;
1234 break;
1235 }
1236 CHECK_ERROR(pGuest, COMSETTER(MemoryBalloonSize)(uVal));
1237 }
1238 }
1239 else if (!strcmp(a->argv[1], "teleport"))
1240 {
1241 Bstr bstrHostname;
1242 uint32_t uMaxDowntime = 250 /*ms*/;
1243 uint32_t uPort = UINT32_MAX;
1244 uint32_t cMsTimeout = 0;
1245 Utf8Str strPassword;
1246 static const RTGETOPTDEF s_aTeleportOptions[] =
1247 {
1248 { "--host", 'h', RTGETOPT_REQ_STRING }, /** @todo RTGETOPT_FLAG_MANDATORY */
1249 { "--hostname", 'h', RTGETOPT_REQ_STRING }, /** @todo remove this */
1250 { "--maxdowntime", 'd', RTGETOPT_REQ_UINT32 },
1251 { "--port", 'P', RTGETOPT_REQ_UINT32 }, /** @todo RTGETOPT_FLAG_MANDATORY */
1252 { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
1253 { "--password", 'W', RTGETOPT_REQ_STRING },
1254 { "--timeout", 't', RTGETOPT_REQ_UINT32 },
1255 { "--detailed-progress", 'D', RTGETOPT_REQ_NOTHING }
1256 };
1257 RTGETOPTSTATE GetOptState;
1258 RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTeleportOptions, RT_ELEMENTS(s_aTeleportOptions), 2, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1259 int ch;
1260 RTGETOPTUNION Value;
1261 while ( SUCCEEDED(rc)
1262 && (ch = RTGetOpt(&GetOptState, &Value)))
1263 {
1264 switch (ch)
1265 {
1266 case 'h': bstrHostname = Value.psz; break;
1267 case 'd': uMaxDowntime = Value.u32; break;
1268 case 'D': g_fDetailedProgress = true; break;
1269 case 'P': uPort = Value.u32; break;
1270 case 'p':
1271 {
1272 RTEXITCODE rcExit = readPasswordFile(Value.psz, &strPassword);
1273 if (rcExit != RTEXITCODE_SUCCESS)
1274 rc = E_FAIL;
1275 break;
1276 }
1277 case 'W': strPassword = Value.psz; break;
1278 case 't': cMsTimeout = Value.u32; break;
1279 default:
1280 errorGetOpt(USAGE_CONTROLVM, ch, &Value);
1281 rc = E_FAIL;
1282 break;
1283 }
1284 }
1285 if (FAILED(rc))
1286 break;
1287
1288 ComPtr<IProgress> progress;
1289 CHECK_ERROR_BREAK(console, Teleport(bstrHostname.raw(), uPort,
1290 Bstr(strPassword).raw(),
1291 uMaxDowntime,
1292 progress.asOutParam()));
1293
1294 if (cMsTimeout)
1295 {
1296 rc = progress->COMSETTER(Timeout)(cMsTimeout);
1297 if (FAILED(rc) && rc != VBOX_E_INVALID_OBJECT_STATE)
1298 CHECK_ERROR_BREAK(progress, COMSETTER(Timeout)(cMsTimeout)); /* lazyness */
1299 }
1300
1301 rc = showProgress(progress);
1302 CHECK_PROGRESS_ERROR(progress, ("Teleportation failed"));
1303 }
1304 else if (!strcmp(a->argv[1], "screenshotpng"))
1305 {
1306 if (a->argc <= 2 || a->argc > 4)
1307 {
1308 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1309 rc = E_FAIL;
1310 break;
1311 }
1312 int vrc;
1313 uint32_t iScreen = 0;
1314 if (a->argc == 4)
1315 {
1316 vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &iScreen);
1317 if (vrc != VINF_SUCCESS)
1318 {
1319 errorArgument("Error parsing display number '%s'", a->argv[3]);
1320 rc = E_FAIL;
1321 break;
1322 }
1323 }
1324 ComPtr<IDisplay> pDisplay;
1325 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1326 if (!pDisplay)
1327 {
1328 RTMsgError("Guest not running");
1329 rc = E_FAIL;
1330 break;
1331 }
1332 ULONG width, height, bpp;
1333 LONG xOrigin, yOrigin;
1334 CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(iScreen, &width, &height, &bpp, &xOrigin, &yOrigin));
1335 com::SafeArray<BYTE> saScreenshot;
1336 CHECK_ERROR_BREAK(pDisplay, TakeScreenShotToArray(iScreen, width, height, BitmapFormat_PNG, ComSafeArrayAsOutParam(saScreenshot)));
1337 RTFILE pngFile = NIL_RTFILE;
1338 vrc = RTFileOpen(&pngFile, a->argv[2], RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_TRUNCATE | RTFILE_O_DENY_ALL);
1339 if (RT_FAILURE(vrc))
1340 {
1341 RTMsgError("Failed to create file '%s'. rc=%Rrc", a->argv[2], vrc);
1342 rc = E_FAIL;
1343 break;
1344 }
1345 vrc = RTFileWrite(pngFile, saScreenshot.raw(), saScreenshot.size(), NULL);
1346 if (RT_FAILURE(vrc))
1347 {
1348 RTMsgError("Failed to write screenshot to file '%s'. rc=%Rrc", a->argv[2], vrc);
1349 rc = E_FAIL;
1350 }
1351 RTFileClose(pngFile);
1352 }
1353 else if ( !strcmp(a->argv[1], "vcpenabled"))
1354 {
1355 if (a->argc != 3)
1356 {
1357 errorArgument("Missing argument to '%s'", a->argv[1]);
1358 rc = E_FAIL;
1359 break;
1360 }
1361 if (!strcmp(a->argv[2], "on"))
1362 {
1363 CHECK_ERROR_RET(sessionMachine, COMSETTER(VideoCaptureEnabled)(TRUE), 1);
1364 }
1365 else if (!strcmp(a->argv[2], "off"))
1366 {
1367 CHECK_ERROR_RET(sessionMachine, COMSETTER(VideoCaptureEnabled)(FALSE), 1);
1368 }
1369 else
1370 {
1371 errorArgument("Invalid state '%s'", Utf8Str(a->argv[2]).c_str());
1372 rc = E_FAIL;
1373 break;
1374 }
1375 }
1376 else if ( !strcmp(a->argv[1], "videocapturescreens"))
1377 {
1378 ULONG cMonitors = 64;
1379 CHECK_ERROR_BREAK(machine, COMGETTER(MonitorCount)(&cMonitors));
1380 com::SafeArray<BOOL> saScreens(cMonitors);
1381 if ( a->argc == 3
1382 && !strcmp(a->argv[2], "all"))
1383 {
1384 /* enable all screens */
1385 for (unsigned i = 0; i < cMonitors; i++)
1386 saScreens[i] = true;
1387 }
1388 else if ( a->argc == 3
1389 && !strcmp(a->argv[2], "none"))
1390 {
1391 /* disable all screens */
1392 for (unsigned i = 0; i < cMonitors; i++)
1393 saScreens[i] = false;
1394 }
1395 else
1396 {
1397 /* enable selected screens */
1398 for (unsigned i = 0; i < cMonitors; i++)
1399 saScreens[i] = false;
1400 for (int i = 2; SUCCEEDED(rc) && i < a->argc; i++)
1401 {
1402 uint32_t iScreen;
1403 int vrc = RTStrToUInt32Ex(a->argv[i], NULL, 0, &iScreen);
1404 if (vrc != VINF_SUCCESS)
1405 {
1406 errorArgument("Error parsing display number '%s'", a->argv[i]);
1407 rc = E_FAIL;
1408 break;
1409 }
1410 if (iScreen >= cMonitors)
1411 {
1412 errorArgument("Invalid screen ID specified '%u'", iScreen);
1413 rc = E_FAIL;
1414 break;
1415 }
1416 saScreens[iScreen] = true;
1417 }
1418 }
1419
1420 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureScreens)(ComSafeArrayAsInParam(saScreens)));
1421 }
1422 else if (!strcmp(a->argv[1], "webcam"))
1423 {
1424 if (a->argc < 3)
1425 {
1426 errorArgument("Missing argument to '%s'", a->argv[1]);
1427 rc = E_FAIL;
1428 break;
1429 }
1430
1431 ComPtr<IEmulatedUSB> pEmulatedUSB;
1432 CHECK_ERROR_BREAK(console, COMGETTER(EmulatedUSB)(pEmulatedUSB.asOutParam()));
1433 if (!pEmulatedUSB)
1434 {
1435 RTMsgError("Guest not running");
1436 rc = E_FAIL;
1437 break;
1438 }
1439
1440 if (!strcmp(a->argv[2], "attach"))
1441 {
1442 Bstr path("");
1443 if (a->argc >= 4)
1444 path = a->argv[3];
1445 Bstr settings("");
1446 if (a->argc >= 5)
1447 settings = a->argv[4];
1448 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamAttach(path.raw(), settings.raw()));
1449 }
1450 else if (!strcmp(a->argv[2], "detach"))
1451 {
1452 Bstr path("");
1453 if (a->argc >= 4)
1454 path = a->argv[3];
1455 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamDetach(path.raw()));
1456 }
1457 else if (!strcmp(a->argv[2], "list"))
1458 {
1459 com::SafeArray <BSTR> webcams;
1460 CHECK_ERROR_BREAK(pEmulatedUSB, COMGETTER(Webcams)(ComSafeArrayAsOutParam(webcams)));
1461 for (size_t i = 0; i < webcams.size(); ++i)
1462 {
1463 RTPrintf("%ls\n", webcams[i][0]? webcams[i]: Bstr("default").raw());
1464 }
1465 }
1466 else
1467 {
1468 errorArgument("Invalid argument to '%s'", a->argv[1]);
1469 rc = E_FAIL;
1470 break;
1471 }
1472
1473 }
1474 else
1475 {
1476 errorSyntax(USAGE_CONTROLVM, "Invalid parameter '%s'", a->argv[1]);
1477 rc = E_FAIL;
1478 }
1479 } while (0);
1480
1481 a->session->UnlockMachine();
1482
1483 return SUCCEEDED(rc) ? 0 : 1;
1484}
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