VirtualBox

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

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

USB: Integrate USB sniffer. Make it possible to specify a file to dump the traffic to when attaching a USB device with VBoxManage

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 56.3 KB
Line 
1/* $Id: VBoxManageControlVM.cpp 53062 2014-10-15 12:34:18Z 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 else if (a->argc == 4 || a->argc > 5)
936 {
937 errorSyntax(USAGE_CONTROLVM, "Wrong number of arguments");
938 rc = E_FAIL;
939 break;
940 }
941
942 bool attach = !strcmp(a->argv[1], "usbattach");
943
944 Bstr usbId = a->argv[2];
945 Bstr captureFilename;
946
947 if (a->argc == 5)
948 {
949 if (!strcmp(a->argv[3], "--capturefile"))
950 captureFilename = a->argv[4];
951 else
952 {
953 errorArgument("Invalid parameter '%s'", a->argv[3]);
954 rc = E_FAIL;
955 break;
956 }
957 }
958
959 Guid guid(usbId);
960 if (!guid.isValid())
961 {
962 // assume address
963 if (attach)
964 {
965 ComPtr<IHost> host;
966 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
967 SafeIfaceArray <IHostUSBDevice> coll;
968 CHECK_ERROR_BREAK(host, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
969 ComPtr<IHostUSBDevice> dev;
970 CHECK_ERROR_BREAK(host, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
971 dev.asOutParam()));
972 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
973 }
974 else
975 {
976 SafeIfaceArray <IUSBDevice> coll;
977 CHECK_ERROR_BREAK(console, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
978 ComPtr<IUSBDevice> dev;
979 CHECK_ERROR_BREAK(console, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
980 dev.asOutParam()));
981 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
982 }
983 }
984 else if (guid.isZero())
985 {
986 errorArgument("Zero UUID argument '%s'", a->argv[2]);
987 rc = E_FAIL;
988 break;
989 }
990
991 if (attach)
992 CHECK_ERROR_BREAK(console, AttachUSBDevice(usbId.raw(), captureFilename.raw()));
993 else
994 {
995 ComPtr<IUSBDevice> dev;
996 CHECK_ERROR_BREAK(console, DetachUSBDevice(usbId.raw(),
997 dev.asOutParam()));
998 }
999 }
1000 else if (!strcmp(a->argv[1], "setvideomodehint"))
1001 {
1002 if (a->argc != 5 && a->argc != 6 && a->argc != 7 && a->argc != 9)
1003 {
1004 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1005 rc = E_FAIL;
1006 break;
1007 }
1008 bool fEnabled = true;
1009 uint32_t uXRes = RTStrToUInt32(a->argv[2]);
1010 uint32_t uYRes = RTStrToUInt32(a->argv[3]);
1011 uint32_t uBpp = RTStrToUInt32(a->argv[4]);
1012 uint32_t uDisplayIdx = 0;
1013 bool fChangeOrigin = false;
1014 int32_t iOriginX = 0;
1015 int32_t iOriginY = 0;
1016 if (a->argc >= 6)
1017 uDisplayIdx = RTStrToUInt32(a->argv[5]);
1018 if (a->argc >= 7)
1019 {
1020 int vrc = parseBool(a->argv[6], &fEnabled);
1021 if (RT_FAILURE(vrc))
1022 {
1023 errorSyntax(USAGE_CONTROLVM, "Either \"yes\" or \"no\" is expected");
1024 rc = E_FAIL;
1025 break;
1026 }
1027 fEnabled = !RTStrICmp(a->argv[6], "yes");
1028 }
1029 if (a->argc == 9)
1030 {
1031 iOriginX = RTStrToInt32(a->argv[7]);
1032 iOriginY = RTStrToInt32(a->argv[8]);
1033 fChangeOrigin = true;
1034 }
1035
1036 ComPtr<IDisplay> pDisplay;
1037 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1038 if (!pDisplay)
1039 {
1040 RTMsgError("Guest not running");
1041 rc = E_FAIL;
1042 break;
1043 }
1044 CHECK_ERROR_BREAK(pDisplay, SetVideoModeHint(uDisplayIdx, fEnabled,
1045 fChangeOrigin, iOriginX, iOriginY,
1046 uXRes, uYRes, uBpp));
1047 }
1048 else if (!strcmp(a->argv[1], "setcredentials"))
1049 {
1050 bool fAllowLocalLogon = true;
1051 if ( a->argc == 7
1052 || ( a->argc == 8
1053 && ( !strcmp(a->argv[3], "-p")
1054 || !strcmp(a->argv[3], "--passwordfile"))))
1055 {
1056 if ( strcmp(a->argv[5 + (a->argc - 7)], "--allowlocallogon")
1057 && strcmp(a->argv[5 + (a->argc - 7)], "-allowlocallogon"))
1058 {
1059 errorArgument("Invalid parameter '%s'", a->argv[5]);
1060 rc = E_FAIL;
1061 break;
1062 }
1063 if (!strcmp(a->argv[6 + (a->argc - 7)], "no"))
1064 fAllowLocalLogon = false;
1065 }
1066 else if ( a->argc != 5
1067 && ( a->argc != 6
1068 || ( strcmp(a->argv[3], "-p")
1069 && strcmp(a->argv[3], "--passwordfile"))))
1070 {
1071 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1072 rc = E_FAIL;
1073 break;
1074 }
1075 Utf8Str passwd, domain;
1076 if (a->argc == 5 || a->argc == 7)
1077 {
1078 passwd = a->argv[3];
1079 domain = a->argv[4];
1080 }
1081 else
1082 {
1083 RTEXITCODE rcExit = readPasswordFile(a->argv[4], &passwd);
1084 if (rcExit != RTEXITCODE_SUCCESS)
1085 {
1086 rc = E_FAIL;
1087 break;
1088 }
1089 domain = a->argv[5];
1090 }
1091
1092 ComPtr<IGuest> pGuest;
1093 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest.asOutParam()));
1094 if (!pGuest)
1095 {
1096 RTMsgError("Guest not running");
1097 rc = E_FAIL;
1098 break;
1099 }
1100 CHECK_ERROR_BREAK(pGuest, SetCredentials(Bstr(a->argv[2]).raw(),
1101 Bstr(passwd).raw(),
1102 Bstr(domain).raw(),
1103 fAllowLocalLogon));
1104 }
1105#if 0 /* TODO: review & remove */
1106 else if (!strcmp(a->argv[1], "dvdattach"))
1107 {
1108 Bstr uuid;
1109 if (a->argc != 3)
1110 {
1111 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1112 rc = E_FAIL;
1113 break;
1114 }
1115
1116 ComPtr<IMedium> dvdMedium;
1117
1118 /* unmount? */
1119 if (!strcmp(a->argv[2], "none"))
1120 {
1121 /* nothing to do, NULL object will cause unmount */
1122 }
1123 /* host drive? */
1124 else if (!strncmp(a->argv[2], "host:", 5))
1125 {
1126 ComPtr<IHost> host;
1127 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1128
1129 rc = host->FindHostDVDDrive(Bstr(a->argv[2] + 5), dvdMedium.asOutParam());
1130 if (!dvdMedium)
1131 {
1132 errorArgument("Invalid host DVD drive name \"%s\"",
1133 a->argv[2] + 5);
1134 rc = E_FAIL;
1135 break;
1136 }
1137 }
1138 else
1139 {
1140 /* first assume it's a UUID */
1141 uuid = a->argv[2];
1142 rc = a->virtualBox->GetDVDImage(uuid, dvdMedium.asOutParam());
1143 if (FAILED(rc) || !dvdMedium)
1144 {
1145 /* must be a filename, check if it's in the collection */
1146 rc = a->virtualBox->FindDVDImage(Bstr(a->argv[2]), dvdMedium.asOutParam());
1147 /* not registered, do that on the fly */
1148 if (!dvdMedium)
1149 {
1150 Bstr emptyUUID;
1151 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(a->argv[2]), emptyUUID, dvdMedium.asOutParam()));
1152 }
1153 }
1154 if (!dvdMedium)
1155 {
1156 rc = E_FAIL;
1157 break;
1158 }
1159 }
1160
1161 /** @todo generalize this, allow arbitrary number of DVD drives
1162 * and as a consequence multiple attachments and different
1163 * storage controllers. */
1164 if (dvdMedium)
1165 dvdMedium->COMGETTER(Id)(uuid.asOutParam());
1166 else
1167 uuid = Guid().toString();
1168 CHECK_ERROR(machine, MountMedium(Bstr("IDE Controller"), 1, 0, uuid, FALSE /* aForce */));
1169 }
1170 else if (!strcmp(a->argv[1], "floppyattach"))
1171 {
1172 Bstr uuid;
1173 if (a->argc != 3)
1174 {
1175 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1176 rc = E_FAIL;
1177 break;
1178 }
1179
1180 ComPtr<IMedium> floppyMedium;
1181
1182 /* unmount? */
1183 if (!strcmp(a->argv[2], "none"))
1184 {
1185 /* nothing to do, NULL object will cause unmount */
1186 }
1187 /* host drive? */
1188 else if (!strncmp(a->argv[2], "host:", 5))
1189 {
1190 ComPtr<IHost> host;
1191 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1192 host->FindHostFloppyDrive(Bstr(a->argv[2] + 5), floppyMedium.asOutParam());
1193 if (!floppyMedium)
1194 {
1195 errorArgument("Invalid host floppy drive name \"%s\"",
1196 a->argv[2] + 5);
1197 rc = E_FAIL;
1198 break;
1199 }
1200 }
1201 else
1202 {
1203 /* first assume it's a UUID */
1204 uuid = a->argv[2];
1205 rc = a->virtualBox->GetFloppyImage(uuid, floppyMedium.asOutParam());
1206 if (FAILED(rc) || !floppyMedium)
1207 {
1208 /* must be a filename, check if it's in the collection */
1209 rc = a->virtualBox->FindFloppyImage(Bstr(a->argv[2]), floppyMedium.asOutParam());
1210 /* not registered, do that on the fly */
1211 if (!floppyMedium)
1212 {
1213 Bstr emptyUUID;
1214 CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(a->argv[2]), emptyUUID, floppyMedium.asOutParam()));
1215 }
1216 }
1217 if (!floppyMedium)
1218 {
1219 rc = E_FAIL;
1220 break;
1221 }
1222 }
1223 floppyMedium->COMGETTER(Id)(uuid.asOutParam());
1224 CHECK_ERROR(machine, MountMedium(Bstr("Floppy Controller"), 0, 0, uuid, FALSE /* aForce */));
1225 }
1226#endif /* obsolete dvdattach/floppyattach */
1227 else if (!strcmp(a->argv[1], "guestmemoryballoon"))
1228 {
1229 if (a->argc != 3)
1230 {
1231 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1232 rc = E_FAIL;
1233 break;
1234 }
1235 uint32_t uVal;
1236 int vrc;
1237 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1238 if (vrc != VINF_SUCCESS)
1239 {
1240 errorArgument("Error parsing guest memory balloon size '%s'", a->argv[2]);
1241 rc = E_FAIL;
1242 break;
1243 }
1244 /* guest is running; update IGuest */
1245 ComPtr<IGuest> pGuest;
1246 rc = console->COMGETTER(Guest)(pGuest.asOutParam());
1247 if (SUCCEEDED(rc))
1248 {
1249 if (!pGuest)
1250 {
1251 RTMsgError("Guest not running");
1252 rc = E_FAIL;
1253 break;
1254 }
1255 CHECK_ERROR(pGuest, COMSETTER(MemoryBalloonSize)(uVal));
1256 }
1257 }
1258 else if (!strcmp(a->argv[1], "teleport"))
1259 {
1260 Bstr bstrHostname;
1261 uint32_t uMaxDowntime = 250 /*ms*/;
1262 uint32_t uPort = UINT32_MAX;
1263 uint32_t cMsTimeout = 0;
1264 Utf8Str strPassword;
1265 static const RTGETOPTDEF s_aTeleportOptions[] =
1266 {
1267 { "--host", 'h', RTGETOPT_REQ_STRING }, /** @todo RTGETOPT_FLAG_MANDATORY */
1268 { "--hostname", 'h', RTGETOPT_REQ_STRING }, /** @todo remove this */
1269 { "--maxdowntime", 'd', RTGETOPT_REQ_UINT32 },
1270 { "--port", 'P', RTGETOPT_REQ_UINT32 }, /** @todo RTGETOPT_FLAG_MANDATORY */
1271 { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
1272 { "--password", 'W', RTGETOPT_REQ_STRING },
1273 { "--timeout", 't', RTGETOPT_REQ_UINT32 },
1274 { "--detailed-progress", 'D', RTGETOPT_REQ_NOTHING }
1275 };
1276 RTGETOPTSTATE GetOptState;
1277 RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTeleportOptions, RT_ELEMENTS(s_aTeleportOptions), 2, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1278 int ch;
1279 RTGETOPTUNION Value;
1280 while ( SUCCEEDED(rc)
1281 && (ch = RTGetOpt(&GetOptState, &Value)))
1282 {
1283 switch (ch)
1284 {
1285 case 'h': bstrHostname = Value.psz; break;
1286 case 'd': uMaxDowntime = Value.u32; break;
1287 case 'D': g_fDetailedProgress = true; break;
1288 case 'P': uPort = Value.u32; break;
1289 case 'p':
1290 {
1291 RTEXITCODE rcExit = readPasswordFile(Value.psz, &strPassword);
1292 if (rcExit != RTEXITCODE_SUCCESS)
1293 rc = E_FAIL;
1294 break;
1295 }
1296 case 'W': strPassword = Value.psz; break;
1297 case 't': cMsTimeout = Value.u32; break;
1298 default:
1299 errorGetOpt(USAGE_CONTROLVM, ch, &Value);
1300 rc = E_FAIL;
1301 break;
1302 }
1303 }
1304 if (FAILED(rc))
1305 break;
1306
1307 ComPtr<IProgress> progress;
1308 CHECK_ERROR_BREAK(console, Teleport(bstrHostname.raw(), uPort,
1309 Bstr(strPassword).raw(),
1310 uMaxDowntime,
1311 progress.asOutParam()));
1312
1313 if (cMsTimeout)
1314 {
1315 rc = progress->COMSETTER(Timeout)(cMsTimeout);
1316 if (FAILED(rc) && rc != VBOX_E_INVALID_OBJECT_STATE)
1317 CHECK_ERROR_BREAK(progress, COMSETTER(Timeout)(cMsTimeout)); /* lazyness */
1318 }
1319
1320 rc = showProgress(progress);
1321 CHECK_PROGRESS_ERROR(progress, ("Teleportation failed"));
1322 }
1323 else if (!strcmp(a->argv[1], "screenshotpng"))
1324 {
1325 if (a->argc <= 2 || a->argc > 4)
1326 {
1327 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1328 rc = E_FAIL;
1329 break;
1330 }
1331 int vrc;
1332 uint32_t iScreen = 0;
1333 if (a->argc == 4)
1334 {
1335 vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &iScreen);
1336 if (vrc != VINF_SUCCESS)
1337 {
1338 errorArgument("Error parsing display number '%s'", a->argv[3]);
1339 rc = E_FAIL;
1340 break;
1341 }
1342 }
1343 ComPtr<IDisplay> pDisplay;
1344 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1345 if (!pDisplay)
1346 {
1347 RTMsgError("Guest not running");
1348 rc = E_FAIL;
1349 break;
1350 }
1351 ULONG width, height, bpp;
1352 LONG xOrigin, yOrigin;
1353 GuestMonitorStatus_T monitorStatus;
1354 CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(iScreen, &width, &height, &bpp, &xOrigin, &yOrigin, &monitorStatus));
1355 com::SafeArray<BYTE> saScreenshot;
1356 CHECK_ERROR_BREAK(pDisplay, TakeScreenShotToArray(iScreen, width, height, BitmapFormat_PNG, ComSafeArrayAsOutParam(saScreenshot)));
1357 RTFILE pngFile = NIL_RTFILE;
1358 vrc = RTFileOpen(&pngFile, a->argv[2], RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_TRUNCATE | RTFILE_O_DENY_ALL);
1359 if (RT_FAILURE(vrc))
1360 {
1361 RTMsgError("Failed to create file '%s'. rc=%Rrc", a->argv[2], vrc);
1362 rc = E_FAIL;
1363 break;
1364 }
1365 vrc = RTFileWrite(pngFile, saScreenshot.raw(), saScreenshot.size(), NULL);
1366 if (RT_FAILURE(vrc))
1367 {
1368 RTMsgError("Failed to write screenshot to file '%s'. rc=%Rrc", a->argv[2], vrc);
1369 rc = E_FAIL;
1370 }
1371 RTFileClose(pngFile);
1372 }
1373 else if ( !strcmp(a->argv[1], "vcpenabled"))
1374 {
1375 if (a->argc != 3)
1376 {
1377 errorArgument("Missing argument to '%s'", a->argv[1]);
1378 rc = E_FAIL;
1379 break;
1380 }
1381 if (!strcmp(a->argv[2], "on"))
1382 {
1383 CHECK_ERROR_RET(sessionMachine, COMSETTER(VideoCaptureEnabled)(TRUE), 1);
1384 }
1385 else if (!strcmp(a->argv[2], "off"))
1386 {
1387 CHECK_ERROR_RET(sessionMachine, COMSETTER(VideoCaptureEnabled)(FALSE), 1);
1388 }
1389 else
1390 {
1391 errorArgument("Invalid state '%s'", Utf8Str(a->argv[2]).c_str());
1392 rc = E_FAIL;
1393 break;
1394 }
1395 }
1396 else if ( !strcmp(a->argv[1], "videocapturescreens"))
1397 {
1398 ULONG cMonitors = 64;
1399 CHECK_ERROR_BREAK(machine, COMGETTER(MonitorCount)(&cMonitors));
1400 com::SafeArray<BOOL> saScreens(cMonitors);
1401 if ( a->argc == 3
1402 && !strcmp(a->argv[2], "all"))
1403 {
1404 /* enable all screens */
1405 for (unsigned i = 0; i < cMonitors; i++)
1406 saScreens[i] = true;
1407 }
1408 else if ( a->argc == 3
1409 && !strcmp(a->argv[2], "none"))
1410 {
1411 /* disable all screens */
1412 for (unsigned i = 0; i < cMonitors; i++)
1413 saScreens[i] = false;
1414 }
1415 else
1416 {
1417 /* enable selected screens */
1418 for (unsigned i = 0; i < cMonitors; i++)
1419 saScreens[i] = false;
1420 for (int i = 2; SUCCEEDED(rc) && i < a->argc; i++)
1421 {
1422 uint32_t iScreen;
1423 int vrc = RTStrToUInt32Ex(a->argv[i], NULL, 0, &iScreen);
1424 if (vrc != VINF_SUCCESS)
1425 {
1426 errorArgument("Error parsing display number '%s'", a->argv[i]);
1427 rc = E_FAIL;
1428 break;
1429 }
1430 if (iScreen >= cMonitors)
1431 {
1432 errorArgument("Invalid screen ID specified '%u'", iScreen);
1433 rc = E_FAIL;
1434 break;
1435 }
1436 saScreens[iScreen] = true;
1437 }
1438 }
1439
1440 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureScreens)(ComSafeArrayAsInParam(saScreens)));
1441 }
1442 else if (!strcmp(a->argv[1], "webcam"))
1443 {
1444 if (a->argc < 3)
1445 {
1446 errorArgument("Missing argument to '%s'", a->argv[1]);
1447 rc = E_FAIL;
1448 break;
1449 }
1450
1451 ComPtr<IEmulatedUSB> pEmulatedUSB;
1452 CHECK_ERROR_BREAK(console, COMGETTER(EmulatedUSB)(pEmulatedUSB.asOutParam()));
1453 if (!pEmulatedUSB)
1454 {
1455 RTMsgError("Guest not running");
1456 rc = E_FAIL;
1457 break;
1458 }
1459
1460 if (!strcmp(a->argv[2], "attach"))
1461 {
1462 Bstr path("");
1463 if (a->argc >= 4)
1464 path = a->argv[3];
1465 Bstr settings("");
1466 if (a->argc >= 5)
1467 settings = a->argv[4];
1468 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamAttach(path.raw(), settings.raw()));
1469 }
1470 else if (!strcmp(a->argv[2], "detach"))
1471 {
1472 Bstr path("");
1473 if (a->argc >= 4)
1474 path = a->argv[3];
1475 CHECK_ERROR_BREAK(pEmulatedUSB, WebcamDetach(path.raw()));
1476 }
1477 else if (!strcmp(a->argv[2], "list"))
1478 {
1479 com::SafeArray <BSTR> webcams;
1480 CHECK_ERROR_BREAK(pEmulatedUSB, COMGETTER(Webcams)(ComSafeArrayAsOutParam(webcams)));
1481 for (size_t i = 0; i < webcams.size(); ++i)
1482 {
1483 RTPrintf("%ls\n", webcams[i][0]? webcams[i]: Bstr("default").raw());
1484 }
1485 }
1486 else
1487 {
1488 errorArgument("Invalid argument to '%s'", a->argv[1]);
1489 rc = E_FAIL;
1490 break;
1491 }
1492
1493 }
1494 else
1495 {
1496 errorSyntax(USAGE_CONTROLVM, "Invalid parameter '%s'", a->argv[1]);
1497 rc = E_FAIL;
1498 }
1499 } while (0);
1500
1501 a->session->UnlockMachine();
1502
1503 return SUCCEEDED(rc) ? 0 : 1;
1504}
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