VirtualBox

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

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

allow to change the clipboard mode during runtime (API change including 'VBoxManage controlvm' change)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.7 KB
Line 
1/* $Id: VBoxManageControlVM.cpp 41925 2012-06-27 14:04:09Z 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)
885 {
886 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
887 rc = E_FAIL;
888 break;
889 }
890 uint32_t xres = RTStrToUInt32(a->argv[2]);
891 uint32_t yres = RTStrToUInt32(a->argv[3]);
892 uint32_t bpp = RTStrToUInt32(a->argv[4]);
893 uint32_t displayIdx = 0;
894 if (a->argc == 6)
895 displayIdx = RTStrToUInt32(a->argv[5]);
896
897 ComPtr<IDisplay> display;
898 CHECK_ERROR_BREAK(console, COMGETTER(Display)(display.asOutParam()));
899 CHECK_ERROR_BREAK(display, SetVideoModeHint(xres, yres, bpp, displayIdx));
900 }
901 else if (!strcmp(a->argv[1], "setcredentials"))
902 {
903 bool fAllowLocalLogon = true;
904 if (a->argc == 7)
905 {
906 if ( strcmp(a->argv[5], "--allowlocallogon")
907 && strcmp(a->argv[5], "-allowlocallogon"))
908 {
909 errorArgument("Invalid parameter '%s'", a->argv[5]);
910 rc = E_FAIL;
911 break;
912 }
913 if (!strcmp(a->argv[6], "no"))
914 fAllowLocalLogon = false;
915 }
916 else if (a->argc != 5)
917 {
918 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
919 rc = E_FAIL;
920 break;
921 }
922
923 ComPtr<IGuest> guest;
924 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(guest.asOutParam()));
925 CHECK_ERROR_BREAK(guest, SetCredentials(Bstr(a->argv[2]).raw(),
926 Bstr(a->argv[3]).raw(),
927 Bstr(a->argv[4]).raw(),
928 fAllowLocalLogon));
929 }
930#if 0 /* TODO: review & remove */
931 else if (!strcmp(a->argv[1], "dvdattach"))
932 {
933 Bstr uuid;
934 if (a->argc != 3)
935 {
936 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
937 rc = E_FAIL;
938 break;
939 }
940
941 ComPtr<IMedium> dvdMedium;
942
943 /* unmount? */
944 if (!strcmp(a->argv[2], "none"))
945 {
946 /* nothing to do, NULL object will cause unmount */
947 }
948 /* host drive? */
949 else if (!strncmp(a->argv[2], "host:", 5))
950 {
951 ComPtr<IHost> host;
952 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
953
954 rc = host->FindHostDVDDrive(Bstr(a->argv[2] + 5), dvdMedium.asOutParam());
955 if (!dvdMedium)
956 {
957 errorArgument("Invalid host DVD drive name \"%s\"",
958 a->argv[2] + 5);
959 rc = E_FAIL;
960 break;
961 }
962 }
963 else
964 {
965 /* first assume it's a UUID */
966 uuid = a->argv[2];
967 rc = a->virtualBox->GetDVDImage(uuid, dvdMedium.asOutParam());
968 if (FAILED(rc) || !dvdMedium)
969 {
970 /* must be a filename, check if it's in the collection */
971 rc = a->virtualBox->FindDVDImage(Bstr(a->argv[2]), dvdMedium.asOutParam());
972 /* not registered, do that on the fly */
973 if (!dvdMedium)
974 {
975 Bstr emptyUUID;
976 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(a->argv[2]), emptyUUID, dvdMedium.asOutParam()));
977 }
978 }
979 if (!dvdMedium)
980 {
981 rc = E_FAIL;
982 break;
983 }
984 }
985
986 /** @todo generalize this, allow arbitrary number of DVD drives
987 * and as a consequence multiple attachments and different
988 * storage controllers. */
989 if (dvdMedium)
990 dvdMedium->COMGETTER(Id)(uuid.asOutParam());
991 else
992 uuid = Guid().toString();
993 CHECK_ERROR(machine, MountMedium(Bstr("IDE Controller"), 1, 0, uuid, FALSE /* aForce */));
994 }
995 else if (!strcmp(a->argv[1], "floppyattach"))
996 {
997 Bstr uuid;
998 if (a->argc != 3)
999 {
1000 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1001 rc = E_FAIL;
1002 break;
1003 }
1004
1005 ComPtr<IMedium> floppyMedium;
1006
1007 /* unmount? */
1008 if (!strcmp(a->argv[2], "none"))
1009 {
1010 /* nothing to do, NULL object will cause unmount */
1011 }
1012 /* host drive? */
1013 else if (!strncmp(a->argv[2], "host:", 5))
1014 {
1015 ComPtr<IHost> host;
1016 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
1017 host->FindHostFloppyDrive(Bstr(a->argv[2] + 5), floppyMedium.asOutParam());
1018 if (!floppyMedium)
1019 {
1020 errorArgument("Invalid host floppy drive name \"%s\"",
1021 a->argv[2] + 5);
1022 rc = E_FAIL;
1023 break;
1024 }
1025 }
1026 else
1027 {
1028 /* first assume it's a UUID */
1029 uuid = a->argv[2];
1030 rc = a->virtualBox->GetFloppyImage(uuid, floppyMedium.asOutParam());
1031 if (FAILED(rc) || !floppyMedium)
1032 {
1033 /* must be a filename, check if it's in the collection */
1034 rc = a->virtualBox->FindFloppyImage(Bstr(a->argv[2]), floppyMedium.asOutParam());
1035 /* not registered, do that on the fly */
1036 if (!floppyMedium)
1037 {
1038 Bstr emptyUUID;
1039 CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(a->argv[2]), emptyUUID, floppyMedium.asOutParam()));
1040 }
1041 }
1042 if (!floppyMedium)
1043 {
1044 rc = E_FAIL;
1045 break;
1046 }
1047 }
1048 floppyMedium->COMGETTER(Id)(uuid.asOutParam());
1049 CHECK_ERROR(machine, MountMedium(Bstr("Floppy Controller"), 0, 0, uuid, FALSE /* aForce */));
1050 }
1051#endif /* obsolete dvdattach/floppyattach */
1052 else if (!strcmp(a->argv[1], "guestmemoryballoon"))
1053 {
1054 if (a->argc != 3)
1055 {
1056 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1057 rc = E_FAIL;
1058 break;
1059 }
1060 uint32_t uVal;
1061 int vrc;
1062 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
1063 if (vrc != VINF_SUCCESS)
1064 {
1065 errorArgument("Error parsing guest memory balloon size '%s'", a->argv[2]);
1066 rc = E_FAIL;
1067 break;
1068 }
1069 /* guest is running; update IGuest */
1070 ComPtr <IGuest> guest;
1071 rc = console->COMGETTER(Guest)(guest.asOutParam());
1072 if (SUCCEEDED(rc))
1073 CHECK_ERROR(guest, COMSETTER(MemoryBalloonSize)(uVal));
1074 }
1075 else if (!strcmp(a->argv[1], "teleport"))
1076 {
1077 Bstr bstrHostname;
1078 uint32_t uMaxDowntime = 250 /*ms*/;
1079 uint32_t uPort = UINT32_MAX;
1080 uint32_t cMsTimeout = 0;
1081 Bstr bstrPassword("");
1082 static const RTGETOPTDEF s_aTeleportOptions[] =
1083 {
1084 { "--host", 'h', RTGETOPT_REQ_STRING }, /** @todo RTGETOPT_FLAG_MANDATORY */
1085 { "--hostname", 'h', RTGETOPT_REQ_STRING }, /** @todo remove this */
1086 { "--maxdowntime", 'd', RTGETOPT_REQ_UINT32 },
1087 { "--port", 'p', RTGETOPT_REQ_UINT32 }, /** @todo RTGETOPT_FLAG_MANDATORY */
1088 { "--password", 'P', RTGETOPT_REQ_STRING },
1089 { "--timeout", 't', RTGETOPT_REQ_UINT32 },
1090 { "--detailed-progress", 'D', RTGETOPT_REQ_NOTHING }
1091 };
1092 RTGETOPTSTATE GetOptState;
1093 RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTeleportOptions, RT_ELEMENTS(s_aTeleportOptions), 2, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1094 int ch;
1095 RTGETOPTUNION Value;
1096 while ( SUCCEEDED(rc)
1097 && (ch = RTGetOpt(&GetOptState, &Value)))
1098 {
1099 switch (ch)
1100 {
1101 case 'h': bstrHostname = Value.psz; break;
1102 case 'd': uMaxDowntime = Value.u32; break;
1103 case 'D': g_fDetailedProgress = true; break;
1104 case 'p': uPort = Value.u32; break;
1105 case 'P': bstrPassword = Value.psz; break;
1106 case 't': cMsTimeout = Value.u32; break;
1107 default:
1108 errorGetOpt(USAGE_CONTROLVM, ch, &Value);
1109 rc = E_FAIL;
1110 break;
1111 }
1112 }
1113 if (FAILED(rc))
1114 break;
1115
1116 ComPtr<IProgress> progress;
1117 CHECK_ERROR_BREAK(console, Teleport(bstrHostname.raw(), uPort,
1118 bstrPassword.raw(),
1119 uMaxDowntime,
1120 progress.asOutParam()));
1121
1122 if (cMsTimeout)
1123 {
1124 rc = progress->COMSETTER(Timeout)(cMsTimeout);
1125 if (FAILED(rc) && rc != VBOX_E_INVALID_OBJECT_STATE)
1126 CHECK_ERROR_BREAK(progress, COMSETTER(Timeout)(cMsTimeout)); /* lazyness */
1127 }
1128
1129 rc = showProgress(progress);
1130 CHECK_PROGRESS_ERROR(progress, ("Teleportation failed"));
1131 }
1132 else if (!strcmp(a->argv[1], "screenshotpng"))
1133 {
1134 if (a->argc <= 2 || a->argc > 4)
1135 {
1136 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
1137 rc = E_FAIL;
1138 break;
1139 }
1140 int vrc;
1141 uint32_t displayIdx = 0;
1142 if (a->argc == 4)
1143 {
1144 vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &displayIdx);
1145 if (vrc != VINF_SUCCESS)
1146 {
1147 errorArgument("Error parsing display number '%s'", a->argv[3]);
1148 rc = E_FAIL;
1149 break;
1150 }
1151 }
1152 ComPtr<IDisplay> pDisplay;
1153 CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
1154 ULONG width, height, bpp;
1155 CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(displayIdx, &width, &height, &bpp));
1156 com::SafeArray<BYTE> saScreenshot;
1157 CHECK_ERROR_BREAK(pDisplay, TakeScreenShotPNGToArray(displayIdx, width, height, ComSafeArrayAsOutParam(saScreenshot)));
1158 RTFILE pngFile = NIL_RTFILE;
1159 vrc = RTFileOpen(&pngFile, a->argv[2], RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_TRUNCATE | RTFILE_O_DENY_ALL);
1160 if (RT_FAILURE(vrc))
1161 {
1162 RTMsgError("Failed to create file '%s'. rc=%Rrc", a->argv[2], vrc);
1163 rc = E_FAIL;
1164 break;
1165 }
1166 vrc = RTFileWrite(pngFile, saScreenshot.raw(), saScreenshot.size(), NULL);
1167 if (RT_FAILURE(vrc))
1168 {
1169 RTMsgError("Failed to write screenshot to file '%s'. rc=%Rrc", a->argv[2], vrc);
1170 rc = E_FAIL;
1171 }
1172 RTFileClose(pngFile);
1173 }
1174 else
1175 {
1176 errorSyntax(USAGE_CONTROLVM, "Invalid parameter '%s'", a->argv[1]);
1177 rc = E_FAIL;
1178 }
1179 } while (0);
1180
1181 a->session->UnlockMachine();
1182
1183 return SUCCEEDED(rc) ? 0 : 1;
1184}
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