VirtualBox

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

Last change on this file since 37763 was 37202, checked in by vboxsync, 14 years ago

VBoxManage: more build fixes for CBSTR/BSTR/wchar_t[] string incompatibilities

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