VirtualBox

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

Last change on this file since 45559 was 45190, checked in by vboxsync, 12 years ago

VBoxManage: one more check for 'controlvm'; removed long obsolete 'gueststatisticsinterval' help

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.8 KB
Line 
1/* $Id: VBoxManageControlVM.cpp 45190 2013-03-26 10:59:17Z vboxsync $ */
2/** @file
3 * VBoxManage - Implementation of the controlvm command.
4 */
5
6/*
7 * Copyright (C) 2006-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <VBox/com/com.h>
23#include <VBox/com/string.h>
24#include <VBox/com/Guid.h>
25#include <VBox/com/array.h>
26#include <VBox/com/ErrorInfo.h>
27#include <VBox/com/errorprint.h>
28#include <VBox/com/EventQueue.h>
29
30#include <VBox/com/VirtualBox.h>
31
32#include <iprt/ctype.h>
33#include <VBox/err.h>
34#include <iprt/getopt.h>
35#include <iprt/stream.h>
36#include <iprt/string.h>
37#include <iprt/uuid.h>
38#include <iprt/file.h>
39#include <VBox/log.h>
40
41#include "VBoxManage.h"
42
43#include <list>
44
45
46/**
47 * Parses a number.
48 *
49 * @returns Valid number on success.
50 * @returns 0 if invalid number. All necessary bitching has been done.
51 * @param psz Pointer to the nic number.
52 */
53static unsigned parseNum(const char *psz, unsigned cMaxNum, const char *name)
54{
55 uint32_t u32;
56 char *pszNext;
57 int rc = RTStrToUInt32Ex(psz, &pszNext, 10, &u32);
58 if ( RT_SUCCESS(rc)
59 && *pszNext == '\0'
60 && u32 >= 1
61 && u32 <= cMaxNum)
62 return (unsigned)u32;
63 errorArgument("Invalid %s number '%s'", name, psz);
64 return 0;
65}
66
67unsigned int getMaxNics(IVirtualBox* vbox, IMachine* mach)
68{
69 ComPtr <ISystemProperties> info;
70 ChipsetType_T aChipset;
71 ULONG NetworkAdapterCount = 0;
72 HRESULT rc;
73
74 do {
75 CHECK_ERROR_BREAK(vbox, COMGETTER(SystemProperties)(info.asOutParam()));
76 CHECK_ERROR_BREAK(mach, COMGETTER(ChipsetType)(&aChipset));
77 CHECK_ERROR_BREAK(info, GetMaxNetworkAdapters(aChipset, &NetworkAdapterCount));
78
79 return (unsigned int)NetworkAdapterCount;
80 } while (0);
81
82 return 0;
83}
84
85
86int handleControlVM(HandlerArg *a)
87{
88 using namespace com;
89 HRESULT rc;
90
91 if (a->argc < 2)
92 return errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
93
94 /* try to find the given machine */
95 ComPtr <IMachine> machine;
96 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
97 machine.asOutParam()));
98 if (FAILED(rc))
99 return 1;
100
101 /* open a session for the VM */
102 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);
103
104 do
105 {
106 /* get the associated console */
107 ComPtr<IConsole> console;
108 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
109 /* ... and session machine */
110 ComPtr<IMachine> sessionMachine;
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 }
192 }
193 else if (!strcmp(a->argv[1], "draganddrop"))
194 {
195 if (a->argc <= 1 + 1)
196 {
197 errorArgument("Missing argument to '%s'. Expected drag'n'drop mode.", a->argv[1]);
198 rc = E_FAIL;
199 break;
200 }
201
202 DragAndDropMode_T mode;
203 if (!strcmp(a->argv[2], "disabled"))
204 mode = DragAndDropMode_Disabled;
205 else if (!strcmp(a->argv[2], "hosttoguest"))
206 mode = DragAndDropMode_HostToGuest;
207 else if (!strcmp(a->argv[2], "guesttohost"))
208 mode = DragAndDropMode_GuestToHost;
209 else if (!strcmp(a->argv[2], "bidirectional"))
210 mode = DragAndDropMode_Bidirectional;
211 else
212 {
213 errorArgument("Invalid '%s' argument '%s'.", a->argv[1], a->argv[2]);
214 rc = E_FAIL;
215 }
216 if (SUCCEEDED(rc))
217 {
218 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(DragAndDropMode)(mode));
219 }
220 }
221 else if (!strcmp(a->argv[1], "poweroff"))
222 {
223 ComPtr<IProgress> progress;
224 CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam()));
225
226 rc = showProgress(progress);
227 CHECK_PROGRESS_ERROR(progress, ("Failed to power off machine"));
228 }
229 else if (!strcmp(a->argv[1], "savestate"))
230 {
231 /* first pause so we don't trigger a live save which needs more time/resources */
232 bool fPaused = false;
233 rc = console->Pause();
234 if (FAILED(rc))
235 {
236 bool fError = true;
237 if (rc == VBOX_E_INVALID_VM_STATE)
238 {
239 /* check if we are already paused */
240 MachineState_T machineState;
241 CHECK_ERROR_BREAK(console, COMGETTER(State)(&machineState));
242 /* the error code was lost by the previous instruction */
243 rc = VBOX_E_INVALID_VM_STATE;
244 if (machineState != MachineState_Paused)
245 {
246 RTMsgError("Machine in invalid state %d -- %s\n",
247 machineState, machineStateToName(machineState, false));
248 }
249 else
250 {
251 fError = false;
252 fPaused = true;
253 }
254 }
255 if (fError)
256 break;
257 }
258
259 ComPtr<IProgress> progress;
260 CHECK_ERROR(console, SaveState(progress.asOutParam()));
261 if (FAILED(rc))
262 {
263 if (!fPaused)
264 console->Resume();
265 break;
266 }
267
268 rc = showProgress(progress);
269 CHECK_PROGRESS_ERROR(progress, ("Failed to save machine state"));
270 if (FAILED(rc))
271 {
272 if (!fPaused)
273 console->Resume();
274 }
275 }
276 else if (!strcmp(a->argv[1], "acpipowerbutton"))
277 {
278 CHECK_ERROR_BREAK(console, PowerButton());
279 }
280 else if (!strcmp(a->argv[1], "acpisleepbutton"))
281 {
282 CHECK_ERROR_BREAK(console, SleepButton());
283 }
284 else if (!strcmp(a->argv[1], "keyboardputscancode"))
285 {
286 ComPtr<IKeyboard> pKeyboard;
287 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
288 if (!pKeyboard)
289 {
290 RTMsgError("Guest not running");
291 rc = E_FAIL;
292 break;
293 }
294
295 if (a->argc <= 1 + 1)
296 {
297 errorArgument("Missing argument to '%s'. Expected IBM PC AT set 2 keyboard scancode(s) as hex byte(s).", a->argv[1]);
298 rc = E_FAIL;
299 break;
300 }
301
302 std::list<LONG> llScancodes;
303
304 /* Process the command line. */
305 int i;
306 for (i = 1 + 1; i < a->argc; i++)
307 {
308 if ( RT_C_IS_XDIGIT (a->argv[i][0])
309 && RT_C_IS_XDIGIT (a->argv[i][1])
310 && a->argv[i][2] == 0)
311 {
312 uint8_t u8Scancode;
313 int irc = RTStrToUInt8Ex(a->argv[i], NULL, 16, &u8Scancode);
314 if (RT_FAILURE (irc))
315 {
316 RTMsgError("Converting '%s' returned %Rrc!", a->argv[i], rc);
317 rc = E_FAIL;
318 break;
319 }
320
321 llScancodes.push_back(u8Scancode);
322 }
323 else
324 {
325 RTMsgError("Error: '%s' is not a hex byte!", a->argv[i]);
326 rc = E_FAIL;
327 break;
328 }
329 }
330
331 if (FAILED(rc))
332 break;
333
334 /* Send scancodes to the VM. */
335 com::SafeArray<LONG> saScancodes(llScancodes);
336 ULONG codesStored = 0;
337 CHECK_ERROR_BREAK(pKeyboard, PutScancodes(ComSafeArrayAsInParam(saScancodes),
338 &codesStored));
339 if (codesStored < saScancodes.size())
340 {
341 RTMsgError("Only %d scancodes were stored", codesStored);
342 rc = E_FAIL;
343 break;
344 }
345 }
346 else if (!strncmp(a->argv[1], "setlinkstate", 12))
347 {
348 /* Get the number of network adapters */
349 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
350
351 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
352 if (!n)
353 {
354 rc = E_FAIL;
355 break;
356 }
357 if (a->argc <= 1 + 1)
358 {
359 errorArgument("Missing argument to '%s'", a->argv[1]);
360 rc = E_FAIL;
361 break;
362 }
363 /* get the corresponding network adapter */
364 ComPtr<INetworkAdapter> adapter;
365 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
366 if (adapter)
367 {
368 if (!strcmp(a->argv[2], "on"))
369 {
370 CHECK_ERROR_BREAK(adapter, COMSETTER(CableConnected)(TRUE));
371 }
372 else if (!strcmp(a->argv[2], "off"))
373 {
374 CHECK_ERROR_BREAK(adapter, COMSETTER(CableConnected)(FALSE));
375 }
376 else
377 {
378 errorArgument("Invalid link state '%s'", Utf8Str(a->argv[2]).c_str());
379 rc = E_FAIL;
380 break;
381 }
382 }
383 }
384 /* here the order in which strncmp is called is important
385 * cause nictracefile can be very well compared with
386 * nictrace and nic and thus everything will always fail
387 * if the order is changed
388 */
389 else if (!strncmp(a->argv[1], "nictracefile", 12))
390 {
391 /* Get the number of network adapters */
392 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
393 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
394 if (!n)
395 {
396 rc = E_FAIL;
397 break;
398 }
399 if (a->argc <= 2)
400 {
401 errorArgument("Missing argument to '%s'", a->argv[1]);
402 rc = E_FAIL;
403 break;
404 }
405
406 /* get the corresponding network adapter */
407 ComPtr<INetworkAdapter> adapter;
408 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
409 if (adapter)
410 {
411 BOOL fEnabled;
412 adapter->COMGETTER(Enabled)(&fEnabled);
413 if (fEnabled)
414 {
415 if (a->argv[2])
416 {
417 CHECK_ERROR_RET(adapter, COMSETTER(TraceFile)(Bstr(a->argv[2]).raw()), 1);
418 }
419 else
420 {
421 errorArgument("Invalid filename or filename not specified for NIC %lu", n);
422 rc = E_FAIL;
423 break;
424 }
425 }
426 else
427 RTMsgError("The NIC %d is currently disabled and thus its tracefile can't be changed", n);
428 }
429 }
430 else if (!strncmp(a->argv[1], "nictrace", 8))
431 {
432 /* Get the number of network adapters */
433 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
434
435 unsigned n = parseNum(&a->argv[1][8], NetworkAdapterCount, "NIC");
436 if (!n)
437 {
438 rc = E_FAIL;
439 break;
440 }
441 if (a->argc <= 2)
442 {
443 errorArgument("Missing argument to '%s'", a->argv[1]);
444 rc = E_FAIL;
445 break;
446 }
447
448 /* get the corresponding network adapter */
449 ComPtr<INetworkAdapter> adapter;
450 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
451 if (adapter)
452 {
453 BOOL fEnabled;
454 adapter->COMGETTER(Enabled)(&fEnabled);
455 if (fEnabled)
456 {
457 if (!strcmp(a->argv[2], "on"))
458 {
459 CHECK_ERROR_RET(adapter, COMSETTER(TraceEnabled)(TRUE), 1);
460 }
461 else if (!strcmp(a->argv[2], "off"))
462 {
463 CHECK_ERROR_RET(adapter, COMSETTER(TraceEnabled)(FALSE), 1);
464 }
465 else
466 {
467 errorArgument("Invalid nictrace%lu argument '%s'", n, Utf8Str(a->argv[2]).c_str());
468 rc = E_FAIL;
469 break;
470 }
471 }
472 else
473 RTMsgError("The NIC %d is currently disabled and thus its trace flag can't be changed", n);
474 }
475 }
476 else if( a->argc > 2
477 && !strncmp(a->argv[1], "natpf", 5))
478 {
479 /* Get the number of network adapters */
480 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox, sessionMachine);
481 ComPtr<INATEngine> engine;
482 unsigned n = parseNum(&a->argv[1][5], NetworkAdapterCount, "NIC");
483 if (!n)
484 {
485 rc = E_FAIL;
486 break;
487 }
488 if (a->argc <= 2)
489 {
490 errorArgument("Missing argument to '%s'", a->argv[1]);
491 rc = E_FAIL;
492 break;
493 }
494
495 /* get the corresponding network adapter */
496 ComPtr<INetworkAdapter> adapter;
497 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
498 if (!adapter)
499 {
500 rc = E_FAIL;
501 break;
502 }
503 CHECK_ERROR(adapter, COMGETTER(NATEngine)(engine.asOutParam()));
504 if (!engine)
505 {
506 rc = E_FAIL;
507 break;
508 }
509
510 if (!strcmp(a->argv[2], "delete"))
511 {
512 if (a->argc >= 3)
513 CHECK_ERROR(engine, RemoveRedirect(Bstr(a->argv[3]).raw()));
514 }
515 else
516 {
517#define ITERATE_TO_NEXT_TERM(ch) \
518 do { \
519 while (*ch != ',') \
520 { \
521 if (*ch == 0) \
522 { \
523 return errorSyntax(USAGE_CONTROLVM, \
524 "Missing or invalid argument to '%s'", \
525 a->argv[1]); \
526 } \
527 ch++; \
528 } \
529 *ch = '\0'; \
530 ch++; \
531 } while(0)
532
533 char *strName;
534 char *strProto;
535 char *strHostIp;
536 char *strHostPort;
537 char *strGuestIp;
538 char *strGuestPort;
539 char *strRaw = RTStrDup(a->argv[2]);
540 char *ch = strRaw;
541 strName = RTStrStrip(ch);
542 ITERATE_TO_NEXT_TERM(ch);
543 strProto = RTStrStrip(ch);
544 ITERATE_TO_NEXT_TERM(ch);
545 strHostIp = RTStrStrip(ch);
546 ITERATE_TO_NEXT_TERM(ch);
547 strHostPort = RTStrStrip(ch);
548 ITERATE_TO_NEXT_TERM(ch);
549 strGuestIp = RTStrStrip(ch);
550 ITERATE_TO_NEXT_TERM(ch);
551 strGuestPort = RTStrStrip(ch);
552 NATProtocol_T proto;
553 if (RTStrICmp(strProto, "udp") == 0)
554 proto = NATProtocol_UDP;
555 else if (RTStrICmp(strProto, "tcp") == 0)
556 proto = NATProtocol_TCP;
557 else
558 {
559 return errorSyntax(USAGE_CONTROLVM,
560 "Wrong rule proto '%s' specified -- only 'udp' and 'tcp' are allowed.",
561 strProto);
562 }
563 CHECK_ERROR(engine, AddRedirect(Bstr(strName).raw(), proto, Bstr(strHostIp).raw(),
564 RTStrToUInt16(strHostPort), Bstr(strGuestIp).raw(), RTStrToUInt16(strGuestPort)));
565#undef ITERATE_TO_NEXT_TERM
566 }
567 /* commit changes */
568 if (SUCCEEDED(rc))
569 CHECK_ERROR(sessionMachine, SaveSettings());
570 }
571 else if (!strncmp(a->argv[1], "nicproperty", 11))
572 {
573 /* Get the number of network adapters */
574 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox,sessionMachine) ;
575 unsigned n = parseNum(&a->argv[1][11], NetworkAdapterCount, "NIC");
576 if (!n)
577 {
578 rc = E_FAIL;
579 break;
580 }
581 if (a->argc <= 2)
582 {
583 errorArgument("Missing argument to '%s'", a->argv[1]);
584 rc = E_FAIL;
585 break;
586 }
587
588 /* get the corresponding network adapter */
589 ComPtr<INetworkAdapter> adapter;
590 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
591 if (adapter)
592 {
593 BOOL fEnabled;
594 adapter->COMGETTER(Enabled)(&fEnabled);
595 if (fEnabled)
596 {
597 /* Parse 'name=value' */
598 char *pszProperty = RTStrDup(a->argv[2]);
599 if (pszProperty)
600 {
601 char *pDelimiter = strchr(pszProperty, '=');
602 if (pDelimiter)
603 {
604 *pDelimiter = '\0';
605
606 Bstr bstrName = pszProperty;
607 Bstr bstrValue = &pDelimiter[1];
608 CHECK_ERROR(adapter, SetProperty(bstrName.raw(), bstrValue.raw()));
609 }
610 else
611 {
612 errorArgument("Invalid nicproperty%d argument '%s'", n, a->argv[2]);
613 rc = E_FAIL;
614 }
615 RTStrFree(pszProperty);
616 }
617 else
618 {
619 RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for nicproperty%d '%s'\n", n, a->argv[2]);
620 rc = E_FAIL;
621 }
622 if (FAILED(rc))
623 break;
624 }
625 else
626 RTMsgError("The NIC %d is currently disabled and thus its properties can't be changed", n);
627 }
628 }
629 else if (!strncmp(a->argv[1], "nicpromisc", 10))
630 {
631 /* Get the number of network adapters */
632 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox,sessionMachine) ;
633 unsigned n = parseNum(&a->argv[1][10], NetworkAdapterCount, "NIC");
634 if (!n)
635 {
636 rc = E_FAIL;
637 break;
638 }
639 if (a->argc <= 2)
640 {
641 errorArgument("Missing argument to '%s'", a->argv[1]);
642 rc = E_FAIL;
643 break;
644 }
645
646 /* get the corresponding network adapter */
647 ComPtr<INetworkAdapter> adapter;
648 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
649 if (adapter)
650 {
651 BOOL fEnabled;
652 adapter->COMGETTER(Enabled)(&fEnabled);
653 if (fEnabled)
654 {
655 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
656 if (!strcmp(a->argv[2], "deny"))
657 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_Deny;
658 else if ( !strcmp(a->argv[2], "allow-vms")
659 || !strcmp(a->argv[2], "allow-network"))
660 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowNetwork;
661 else if (!strcmp(a->argv[2], "allow-all"))
662 enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowAll;
663 else
664 {
665 errorArgument("Unknown promiscuous mode policy '%s'", a->argv[2]);
666 rc = E_INVALIDARG;
667 break;
668 }
669
670 CHECK_ERROR(adapter, COMSETTER(PromiscModePolicy)(enmPromiscModePolicy));
671 }
672 else
673 RTMsgError("The NIC %d is currently disabled and thus its promiscuous mode can't be changed", n);
674 }
675 }
676 else if (!strncmp(a->argv[1], "nic", 3))
677 {
678 /* Get the number of network adapters */
679 ULONG NetworkAdapterCount = getMaxNics(a->virtualBox,sessionMachine) ;
680 unsigned n = parseNum(&a->argv[1][3], NetworkAdapterCount, "NIC");
681 if (!n)
682 {
683 rc = E_FAIL;
684 break;
685 }
686 if (a->argc <= 2)
687 {
688 errorArgument("Missing argument to '%s'", a->argv[1]);
689 rc = E_FAIL;
690 break;
691 }
692
693 /* get the corresponding network adapter */
694 ComPtr<INetworkAdapter> adapter;
695 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
696 if (adapter)
697 {
698 BOOL fEnabled;
699 adapter->COMGETTER(Enabled)(&fEnabled);
700 if (fEnabled)
701 {
702 if (!strcmp(a->argv[2], "null"))
703 {
704 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
705 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Null), 1);
706 }
707 else if (!strcmp(a->argv[2], "nat"))
708 {
709 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
710 if (a->argc == 4)
711 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3]).raw()), 1);
712 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_NAT), 1);
713 }
714 else if ( !strcmp(a->argv[2], "bridged")
715 || !strcmp(a->argv[2], "hostif")) /* backward compatibility */
716 {
717 if (a->argc <= 3)
718 {
719 errorArgument("Missing argument to '%s'", a->argv[2]);
720 rc = E_FAIL;
721 break;
722 }
723 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
724 CHECK_ERROR_RET(adapter, COMSETTER(BridgedInterface)(Bstr(a->argv[3]).raw()), 1);
725 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Bridged), 1);
726 }
727 else if (!strcmp(a->argv[2], "intnet"))
728 {
729 if (a->argc <= 3)
730 {
731 errorArgument("Missing argument to '%s'", a->argv[2]);
732 rc = E_FAIL;
733 break;
734 }
735 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
736 CHECK_ERROR_RET(adapter, COMSETTER(InternalNetwork)(Bstr(a->argv[3]).raw()), 1);
737 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Internal), 1);
738 }
739#if defined(VBOX_WITH_NETFLT)
740 else if (!strcmp(a->argv[2], "hostonly"))
741 {
742 if (a->argc <= 3)
743 {
744 errorArgument("Missing argument to '%s'", a->argv[2]);
745 rc = E_FAIL;
746 break;
747 }
748 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
749 CHECK_ERROR_RET(adapter, COMSETTER(HostOnlyInterface)(Bstr(a->argv[3]).raw()), 1);
750 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_HostOnly), 1);
751 }
752#endif
753 else if (!strcmp(a->argv[2], "generic"))
754 {
755 if (a->argc <= 3)
756 {
757 errorArgument("Missing argument to '%s'", a->argv[2]);
758 rc = E_FAIL;
759 break;
760 }
761 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
762 CHECK_ERROR_RET(adapter, COMSETTER(GenericDriver)(Bstr(a->argv[3]).raw()), 1);
763 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic), 1);
764 }
765 /** @todo obsolete, remove eventually */
766 else if (!strcmp(a->argv[2], "vde"))
767 {
768 if (a->argc <= 3)
769 {
770 errorArgument("Missing argument to '%s'", a->argv[2]);
771 rc = E_FAIL;
772 break;
773 }
774 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
775 CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic), 1);
776 CHECK_ERROR_RET(adapter, SetProperty(Bstr("name").raw(), Bstr(a->argv[3]).raw()), 1);
777 }
778 else
779 {
780 errorArgument("Invalid type '%s' specfied for NIC %lu", Utf8Str(a->argv[2]).c_str(), n);
781 rc = E_FAIL;
782 break;
783 }
784 }
785 else
786 RTMsgError("The NIC %d is currently disabled and thus its attachment type can't be changed", n);
787 }
788 }
789 else if ( !strcmp(a->argv[1], "vrde")
790 || !strcmp(a->argv[1], "vrdp"))
791 {
792 if (!strcmp(a->argv[1], "vrdp"))
793 RTStrmPrintf(g_pStdErr, "Warning: 'vrdp' is deprecated. Use 'vrde'.\n");
794
795 if (a->argc <= 1 + 1)
796 {
797 errorArgument("Missing argument to '%s'", a->argv[1]);
798 rc = E_FAIL;
799 break;
800 }
801 ComPtr<IVRDEServer> vrdeServer;
802 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
803 ASSERT(vrdeServer);
804 if (vrdeServer)
805 {
806 if (!strcmp(a->argv[2], "on"))
807 {
808 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(TRUE));
809 }
810 else if (!strcmp(a->argv[2], "off"))
811 {
812 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(FALSE));
813 }
814 else
815 {
816 errorArgument("Invalid remote desktop server state '%s'", Utf8Str(a->argv[2]).c_str());
817 rc = E_FAIL;
818 break;
819 }
820 }
821 }
822 else if ( !strcmp(a->argv[1], "vrdeport")
823 || !strcmp(a->argv[1], "vrdpport"))
824 {
825 if (!strcmp(a->argv[1], "vrdpport"))
826 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpport' is deprecated. Use 'vrdeport'.\n");
827
828 if (a->argc <= 1 + 1)
829 {
830 errorArgument("Missing argument to '%s'", a->argv[1]);
831 rc = E_FAIL;
832 break;
833 }
834
835 ComPtr<IVRDEServer> vrdeServer;
836 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
837 ASSERT(vrdeServer);
838 if (vrdeServer)
839 {
840 Bstr ports;
841
842 if (!strcmp(a->argv[2], "default"))
843 ports = "0";
844 else
845 ports = a->argv[2];
846
847 CHECK_ERROR_BREAK(vrdeServer, SetVRDEProperty(Bstr("TCP/Ports").raw(), ports.raw()));
848 }
849 }
850 else if ( !strcmp(a->argv[1], "vrdevideochannelquality")
851 || !strcmp(a->argv[1], "vrdpvideochannelquality"))
852 {
853 if (!strcmp(a->argv[1], "vrdpvideochannelquality"))
854 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpvideochannelquality' is deprecated. Use 'vrdevideochannelquality'.\n");
855
856 if (a->argc <= 1 + 1)
857 {
858 errorArgument("Missing argument to '%s'", a->argv[1]);
859 rc = E_FAIL;
860 break;
861 }
862 ComPtr<IVRDEServer> vrdeServer;
863 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
864 ASSERT(vrdeServer);
865 if (vrdeServer)
866 {
867 Bstr value = a->argv[2];
868
869 CHECK_ERROR(vrdeServer, SetVRDEProperty(Bstr("VideoChannel/Quality").raw(), value.raw()));
870 }
871 }
872 else if (!strcmp(a->argv[1], "vrdeproperty"))
873 {
874 if (a->argc <= 1 + 1)
875 {
876 errorArgument("Missing argument to '%s'", a->argv[1]);
877 rc = E_FAIL;
878 break;
879 }
880 ComPtr<IVRDEServer> vrdeServer;
881 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
882 ASSERT(vrdeServer);
883 if (vrdeServer)
884 {
885 /* Parse 'name=value' */
886 char *pszProperty = RTStrDup(a->argv[2]);
887 if (pszProperty)
888 {
889 char *pDelimiter = strchr(pszProperty, '=');
890 if (pDelimiter)
891 {
892 *pDelimiter = '\0';
893
894 Bstr bstrName = pszProperty;
895 Bstr bstrValue = &pDelimiter[1];
896 CHECK_ERROR(vrdeServer, SetVRDEProperty(bstrName.raw(), bstrValue.raw()));
897 }
898 else
899 {
900 errorArgument("Invalid vrdeproperty argument '%s'", a->argv[2]);
901 rc = E_FAIL;
902 }
903 RTStrFree(pszProperty);
904 }
905 else
906 {
907 RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for VRDE property '%s'\n", a->argv[2]);
908 rc = E_FAIL;
909 }
910 }
911 if (FAILED(rc))
912 {
913 break;
914 }
915 }
916 else if ( !strcmp(a->argv[1], "usbattach")
917 || !strcmp(a->argv[1], "usbdetach"))
918 {
919 if (a->argc < 3)
920 {
921 errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
922 rc = E_FAIL;
923 break;
924 }
925
926 bool attach = !strcmp(a->argv[1], "usbattach");
927
928 Bstr usbId = a->argv[2];
929
930 Guid guid(usbId);
931 if (!guid.isValid())
932 {
933 // assume address
934 if (attach)
935 {
936 ComPtr <IHost> host;
937 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
938 SafeIfaceArray <IHostUSBDevice> coll;
939 CHECK_ERROR_BREAK(host, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
940 ComPtr <IHostUSBDevice> dev;
941 CHECK_ERROR_BREAK(host, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
942 dev.asOutParam()));
943 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
944 }
945 else
946 {
947 SafeIfaceArray <IUSBDevice> coll;
948 CHECK_ERROR_BREAK(console, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
949 ComPtr <IUSBDevice> dev;
950 CHECK_ERROR_BREAK(console, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
951 dev.asOutParam()));
952 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
953 }
954 }
955 else if (guid.isZero())
956 {
957 errorArgument("Zero UUID argument '%s'", a->argv[2]);
958 rc = E_FAIL;
959 break;
960 }
961
962 if (attach)
963 CHECK_ERROR_BREAK(console, AttachUSBDevice(usbId.raw()));
964 else
965 {
966 ComPtr <IUSBDevice> dev;
967 CHECK_ERROR_BREAK(console, DetachUSBDevice(usbId.raw(),
968 dev.asOutParam()));
969 }
970 }
971 else if (!strcmp(a->argv[1], "setvideomodehint"))
972 {
973 if (a->argc != 5 && a->argc != 6 && a->argc != 7 && a->argc != 9)
974 {
975 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
976 rc = E_FAIL;
977 break;
978 }
979 bool fEnabled = true;
980 uint32_t uXRes = RTStrToUInt32(a->argv[2]);
981 uint32_t uYRes = RTStrToUInt32(a->argv[3]);
982 uint32_t uBpp = RTStrToUInt32(a->argv[4]);
983 uint32_t uDisplayIdx = 0;
984 bool fChangeOrigin = false;
985 int32_t iOriginX = 0;
986 int32_t iOriginY = 0;
987 if (a->argc >= 6)
988 uDisplayIdx = RTStrToUInt32(a->argv[5]);
989 if (a->argc >= 7)
990 {
991 int vrc = parseBool(a->argv[6], &fEnabled);
992 if (RT_FAILURE(vrc))
993 {
994 errorSyntax(USAGE_CONTROLVM, "Either \"yes\" or \"no\" is expected");
995 rc = E_FAIL;
996 break;
997 }
998 fEnabled = !RTStrICmp(a->argv[6], "yes");
999 }
1000 if (a->argc == 9)
1001 {
1002 iOriginX = RTStrToInt32(a->argv[7]);
1003 iOriginY = RTStrToInt32(a->argv[8]);
1004 fChangeOrigin = true;
1005 }
1006
1007 ComPtr<IDisplay> pDisplay;
1008 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1009 if (!pDisplay)
1010 {
1011 RTMsgError("Guest not running");
1012 rc = E_FAIL;
1013 break;
1014 }
1015 CHECK_ERROR_BREAK(pDisplay, SetVideoModeHint(uDisplayIdx, fEnabled,
1016 fChangeOrigin, iOriginX, iOriginY,
1017 uXRes, uYRes, uBpp));
1018 }
1019 else if (!strcmp(a->argv[1], "setcredentials"))
1020 {
1021 bool fAllowLocalLogon = true;
1022 if ( a->argc == 7
1023 || ( a->argc == 8
1024 && ( !strcmp(a->argv[3], "-p")
1025 || !strcmp(a->argv[3], "--passwordfile"))))
1026 {
1027 if ( strcmp(a->argv[5 + (a->argc - 7)], "--allowlocallogon")
1028 && strcmp(a->argv[5 + (a->argc - 7)], "-allowlocallogon"))
1029 {
1030 errorArgument("Invalid parameter '%s'", a->argv[5]);
1031 rc = E_FAIL;
1032 break;
1033 }
1034 if (!strcmp(a->argv[6 + (a->argc - 7)], "no"))
1035 fAllowLocalLogon = false;
1036 }
1037 else if ( a->argc != 5
1038 && ( a->argc != 6
1039 || ( strcmp(a->argv[3], "-p")
1040 && strcmp(a->argv[3], "--passwordfile"))))
1041 {
1042 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1043 rc = E_FAIL;
1044 break;
1045 }
1046 Utf8Str passwd, domain;
1047 if (a->argc == 5 || a->argc == 7)
1048 {
1049 passwd = a->argv[3];
1050 domain = a->argv[4];
1051 }
1052 else
1053 {
1054 RTEXITCODE rcExit = readPasswordFile(a->argv[4], &passwd);
1055 if (rcExit != RTEXITCODE_SUCCESS)
1056 {
1057 rc = E_FAIL;
1058 break;
1059 }
1060 domain = a->argv[5];
1061 }
1062
1063 ComPtr<IGuest> pGuest;
1064 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest.asOutParam()));
1065 if (!pGuest)
1066 {
1067 RTMsgError("Guest not running");
1068 rc = E_FAIL;
1069 break;
1070 }
1071 CHECK_ERROR_BREAK(pGuest, SetCredentials(Bstr(a->argv[2]).raw(),
1072 Bstr(passwd).raw(),
1073 Bstr(domain).raw(),
1074 fAllowLocalLogon));
1075 }
1076#if 0 /* TODO: review & remove */
1077 else if (!strcmp(a->argv[1], "dvdattach"))
1078 {
1079 Bstr uuid;
1080 if (a->argc != 3)
1081 {
1082 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1083 rc = E_FAIL;
1084 break;
1085 }
1086
1087 ComPtr<IMedium> dvdMedium;
1088
1089 /* unmount? */
1090 if (!strcmp(a->argv[2], "none"))
1091 {
1092 /* nothing to do, NULL object will cause unmount */
1093 }
1094 /* host drive? */
1095 else if (!strncmp(a->argv[2], "host:", 5))
1096 {
1097 ComPtr<IHost> host;
1098 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1099
1100 rc = host->FindHostDVDDrive(Bstr(a->argv[2] + 5), dvdMedium.asOutParam());
1101 if (!dvdMedium)
1102 {
1103 errorArgument("Invalid host DVD drive name \"%s\"",
1104 a->argv[2] + 5);
1105 rc = E_FAIL;
1106 break;
1107 }
1108 }
1109 else
1110 {
1111 /* first assume it's a UUID */
1112 uuid = a->argv[2];
1113 rc = a->virtualBox->GetDVDImage(uuid, dvdMedium.asOutParam());
1114 if (FAILED(rc) || !dvdMedium)
1115 {
1116 /* must be a filename, check if it's in the collection */
1117 rc = a->virtualBox->FindDVDImage(Bstr(a->argv[2]), dvdMedium.asOutParam());
1118 /* not registered, do that on the fly */
1119 if (!dvdMedium)
1120 {
1121 Bstr emptyUUID;
1122 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(a->argv[2]), emptyUUID, dvdMedium.asOutParam()));
1123 }
1124 }
1125 if (!dvdMedium)
1126 {
1127 rc = E_FAIL;
1128 break;
1129 }
1130 }
1131
1132 /** @todo generalize this, allow arbitrary number of DVD drives
1133 * and as a consequence multiple attachments and different
1134 * storage controllers. */
1135 if (dvdMedium)
1136 dvdMedium->COMGETTER(Id)(uuid.asOutParam());
1137 else
1138 uuid = Guid().toString();
1139 CHECK_ERROR(machine, MountMedium(Bstr("IDE Controller"), 1, 0, uuid, FALSE /* aForce */));
1140 }
1141 else if (!strcmp(a->argv[1], "floppyattach"))
1142 {
1143 Bstr uuid;
1144 if (a->argc != 3)
1145 {
1146 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1147 rc = E_FAIL;
1148 break;
1149 }
1150
1151 ComPtr<IMedium> floppyMedium;
1152
1153 /* unmount? */
1154 if (!strcmp(a->argv[2], "none"))
1155 {
1156 /* nothing to do, NULL object will cause unmount */
1157 }
1158 /* host drive? */
1159 else if (!strncmp(a->argv[2], "host:", 5))
1160 {
1161 ComPtr<IHost> host;
1162 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1163 host->FindHostFloppyDrive(Bstr(a->argv[2] + 5), floppyMedium.asOutParam());
1164 if (!floppyMedium)
1165 {
1166 errorArgument("Invalid host floppy drive name \"%s\"",
1167 a->argv[2] + 5);
1168 rc = E_FAIL;
1169 break;
1170 }
1171 }
1172 else
1173 {
1174 /* first assume it's a UUID */
1175 uuid = a->argv[2];
1176 rc = a->virtualBox->GetFloppyImage(uuid, floppyMedium.asOutParam());
1177 if (FAILED(rc) || !floppyMedium)
1178 {
1179 /* must be a filename, check if it's in the collection */
1180 rc = a->virtualBox->FindFloppyImage(Bstr(a->argv[2]), floppyMedium.asOutParam());
1181 /* not registered, do that on the fly */
1182 if (!floppyMedium)
1183 {
1184 Bstr emptyUUID;
1185 CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(a->argv[2]), emptyUUID, floppyMedium.asOutParam()));
1186 }
1187 }
1188 if (!floppyMedium)
1189 {
1190 rc = E_FAIL;
1191 break;
1192 }
1193 }
1194 floppyMedium->COMGETTER(Id)(uuid.asOutParam());
1195 CHECK_ERROR(machine, MountMedium(Bstr("Floppy Controller"), 0, 0, uuid, FALSE /* aForce */));
1196 }
1197#endif /* obsolete dvdattach/floppyattach */
1198 else if (!strcmp(a->argv[1], "guestmemoryballoon"))
1199 {
1200 if (a->argc != 3)
1201 {
1202 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1203 rc = E_FAIL;
1204 break;
1205 }
1206 uint32_t uVal;
1207 int vrc;
1208 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1209 if (vrc != VINF_SUCCESS)
1210 {
1211 errorArgument("Error parsing guest memory balloon size '%s'", a->argv[2]);
1212 rc = E_FAIL;
1213 break;
1214 }
1215 /* guest is running; update IGuest */
1216 ComPtr <IGuest> pGuest;
1217 rc = console->COMGETTER(Guest)(pGuest.asOutParam());
1218 if (SUCCEEDED(rc))
1219 {
1220 if (!pGuest)
1221 {
1222 RTMsgError("Guest not running");
1223 rc = E_FAIL;
1224 break;
1225 }
1226 CHECK_ERROR(pGuest, COMSETTER(MemoryBalloonSize)(uVal));
1227 }
1228 }
1229 else if (!strcmp(a->argv[1], "teleport"))
1230 {
1231 Bstr bstrHostname;
1232 uint32_t uMaxDowntime = 250 /*ms*/;
1233 uint32_t uPort = UINT32_MAX;
1234 uint32_t cMsTimeout = 0;
1235 Utf8Str strPassword;
1236 static const RTGETOPTDEF s_aTeleportOptions[] =
1237 {
1238 { "--host", 'h', RTGETOPT_REQ_STRING }, /** @todo RTGETOPT_FLAG_MANDATORY */
1239 { "--hostname", 'h', RTGETOPT_REQ_STRING }, /** @todo remove this */
1240 { "--maxdowntime", 'd', RTGETOPT_REQ_UINT32 },
1241 { "--port", 'P', RTGETOPT_REQ_UINT32 }, /** @todo RTGETOPT_FLAG_MANDATORY */
1242 { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
1243 { "--password", 'W', RTGETOPT_REQ_STRING },
1244 { "--timeout", 't', RTGETOPT_REQ_UINT32 },
1245 { "--detailed-progress", 'D', RTGETOPT_REQ_NOTHING }
1246 };
1247 RTGETOPTSTATE GetOptState;
1248 RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTeleportOptions, RT_ELEMENTS(s_aTeleportOptions), 2, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1249 int ch;
1250 RTGETOPTUNION Value;
1251 while ( SUCCEEDED(rc)
1252 && (ch = RTGetOpt(&GetOptState, &Value)))
1253 {
1254 switch (ch)
1255 {
1256 case 'h': bstrHostname = Value.psz; break;
1257 case 'd': uMaxDowntime = Value.u32; break;
1258 case 'D': g_fDetailedProgress = true; break;
1259 case 'P': uPort = Value.u32; break;
1260 case 'p':
1261 {
1262 RTEXITCODE rcExit = readPasswordFile(Value.psz, &strPassword);
1263 if (rcExit != RTEXITCODE_SUCCESS)
1264 rc = E_FAIL;
1265 break;
1266 }
1267 case 'W': strPassword = Value.psz; break;
1268 case 't': cMsTimeout = Value.u32; break;
1269 default:
1270 errorGetOpt(USAGE_CONTROLVM, ch, &Value);
1271 rc = E_FAIL;
1272 break;
1273 }
1274 }
1275 if (FAILED(rc))
1276 break;
1277
1278 ComPtr<IProgress> progress;
1279 CHECK_ERROR_BREAK(console, Teleport(bstrHostname.raw(), uPort,
1280 Bstr(strPassword).raw(),
1281 uMaxDowntime,
1282 progress.asOutParam()));
1283
1284 if (cMsTimeout)
1285 {
1286 rc = progress->COMSETTER(Timeout)(cMsTimeout);
1287 if (FAILED(rc) && rc != VBOX_E_INVALID_OBJECT_STATE)
1288 CHECK_ERROR_BREAK(progress, COMSETTER(Timeout)(cMsTimeout)); /* lazyness */
1289 }
1290
1291 rc = showProgress(progress);
1292 CHECK_PROGRESS_ERROR(progress, ("Teleportation failed"));
1293 }
1294 else if (!strcmp(a->argv[1], "screenshotpng"))
1295 {
1296 if (a->argc <= 2 || a->argc > 4)
1297 {
1298 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1299 rc = E_FAIL;
1300 break;
1301 }
1302 int vrc;
1303 uint32_t displayIdx = 0;
1304 if (a->argc == 4)
1305 {
1306 vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &displayIdx);
1307 if (vrc != VINF_SUCCESS)
1308 {
1309 errorArgument("Error parsing display number '%s'", a->argv[3]);
1310 rc = E_FAIL;
1311 break;
1312 }
1313 }
1314 ComPtr<IDisplay> pDisplay;
1315 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1316 if (!pDisplay)
1317 {
1318 RTMsgError("Guest not running");
1319 rc = E_FAIL;
1320 break;
1321 }
1322 ULONG width, height, bpp;
1323 CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(displayIdx, &width, &height, &bpp));
1324 com::SafeArray<BYTE> saScreenshot;
1325 CHECK_ERROR_BREAK(pDisplay, TakeScreenShotPNGToArray(displayIdx, width, height, ComSafeArrayAsOutParam(saScreenshot)));
1326 RTFILE pngFile = NIL_RTFILE;
1327 vrc = RTFileOpen(&pngFile, a->argv[2], RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_TRUNCATE | RTFILE_O_DENY_ALL);
1328 if (RT_FAILURE(vrc))
1329 {
1330 RTMsgError("Failed to create file '%s'. rc=%Rrc", a->argv[2], vrc);
1331 rc = E_FAIL;
1332 break;
1333 }
1334 vrc = RTFileWrite(pngFile, saScreenshot.raw(), saScreenshot.size(), NULL);
1335 if (RT_FAILURE(vrc))
1336 {
1337 RTMsgError("Failed to write screenshot to file '%s'. rc=%Rrc", a->argv[2], vrc);
1338 rc = E_FAIL;
1339 }
1340 RTFileClose(pngFile);
1341 }
1342 else
1343 {
1344 errorSyntax(USAGE_CONTROLVM, "Invalid parameter '%s'", a->argv[1]);
1345 rc = E_FAIL;
1346 }
1347 } while (0);
1348
1349 a->session->UnlockMachine();
1350
1351 return SUCCEEDED(rc) ? 0 : 1;
1352}
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