VirtualBox

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

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

Main/Console+Machine+Session+Snapshot: move the save state and snapshot related methods from IConsole to IMachine, with lots of unavoidable code restructuring and cleanup. Also define two new machine states (so that the "Saving" one is specifically for saving state now) which requires more changes everywhere
Frontends: necessary adjustments
doc/SDK: document the changes

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