VirtualBox

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

Last change on this file since 45078 was 45021, checked in by vboxsync, 12 years ago

VBoxManage: implemented 'controlvm nicpromisc'

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