VirtualBox

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

Last change on this file since 42248 was 42248, checked in by vboxsync, 13 years ago

API change for SetVideoModeHint to be able to disable guest screens and to set the origin of guest screens

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette