VirtualBox

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

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

FE/CLI: use CHECK_PROGRESS_ERROR

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