VirtualBox

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

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

Main: renavation com::Guid class. PR5744

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

© 2023 Oracle
ContactPrivacy policyTerms of Use