VirtualBox

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

Last change on this file since 56051 was 55182, checked in by vboxsync, 10 years ago

Main,FE/VBoxManage: Support exporting machines as appliances which have encrypted disks. Because the OVF standard doesn't support encrypted disks so far we always decrypt exported images which requires the password before starting the export proess

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.4 KB
Line 
1/* $Id: VBoxManage.cpp 55182 2015-04-10 14:26:59Z vboxsync $ */
2/** @file
3 * VBoxManage - VirtualBox's command-line interface.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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#ifndef VBOX_ONLY_DOCS
23# include <VBox/com/com.h>
24# include <VBox/com/string.h>
25# include <VBox/com/Guid.h>
26# include <VBox/com/array.h>
27# include <VBox/com/ErrorInfo.h>
28# include <VBox/com/errorprint.h>
29# include <VBox/com/NativeEventQueue.h>
30
31# include <VBox/com/VirtualBox.h>
32#endif /* !VBOX_ONLY_DOCS */
33
34#include <VBox/err.h>
35#include <VBox/version.h>
36
37#include <iprt/asm.h>
38#include <iprt/buildconfig.h>
39#include <iprt/ctype.h>
40#include <iprt/initterm.h>
41#include <iprt/path.h>
42#include <iprt/stream.h>
43#include <iprt/string.h>
44
45#include <signal.h>
46
47#include "VBoxManage.h"
48
49
50/*******************************************************************************
51* Global Variables *
52*******************************************************************************/
53/*extern*/ bool g_fDetailedProgress = false;
54
55#ifndef VBOX_ONLY_DOCS
56/** Set by the signal handler. */
57static volatile bool g_fCanceled = false;
58
59
60/**
61 * Signal handler that sets g_fCanceled.
62 *
63 * This can be executed on any thread in the process, on Windows it may even be
64 * a thread dedicated to delivering this signal. Do not doing anything
65 * unnecessary here.
66 */
67static void showProgressSignalHandler(int iSignal)
68{
69 NOREF(iSignal);
70 ASMAtomicWriteBool(&g_fCanceled, true);
71}
72
73/**
74 * Print out progress on the console.
75 *
76 * This runs the main event queue every now and then to prevent piling up
77 * unhandled things (which doesn't cause real problems, just makes things
78 * react a little slower than in the ideal case).
79 */
80HRESULT showProgress(ComPtr<IProgress> progress)
81{
82 using namespace com;
83
84 BOOL fCompleted = FALSE;
85 ULONG ulCurrentPercent = 0;
86 ULONG ulLastPercent = 0;
87
88 ULONG ulLastOperationPercent = (ULONG)-1;
89
90 ULONG ulLastOperation = (ULONG)-1;
91 Bstr bstrOperationDescription;
92
93 NativeEventQueue::getMainEventQueue()->processEventQueue(0);
94
95 ULONG cOperations = 1;
96 HRESULT hrc = progress->COMGETTER(OperationCount)(&cOperations);
97 if (FAILED(hrc))
98 {
99 RTStrmPrintf(g_pStdErr, "Progress object failure: %Rhrc\n", hrc);
100 RTStrmFlush(g_pStdErr);
101 return hrc;
102 }
103
104 /*
105 * Note: Outputting the progress info to stderr (g_pStdErr) is intentional
106 * to not get intermixed with other (raw) stdout data which might get
107 * written in the meanwhile.
108 */
109
110 if (!g_fDetailedProgress)
111 {
112 RTStrmPrintf(g_pStdErr, "0%%...");
113 RTStrmFlush(g_pStdErr);
114 }
115
116 /* setup signal handling if cancelable */
117 bool fCanceledAlready = false;
118 BOOL fCancelable;
119 hrc = progress->COMGETTER(Cancelable)(&fCancelable);
120 if (FAILED(hrc))
121 fCancelable = FALSE;
122 if (fCancelable)
123 {
124 signal(SIGINT, showProgressSignalHandler);
125#ifdef SIGBREAK
126 signal(SIGBREAK, showProgressSignalHandler);
127#endif
128 }
129
130 hrc = progress->COMGETTER(Completed(&fCompleted));
131 while (SUCCEEDED(hrc))
132 {
133 progress->COMGETTER(Percent(&ulCurrentPercent));
134
135 if (g_fDetailedProgress)
136 {
137 ULONG ulOperation = 1;
138 hrc = progress->COMGETTER(Operation)(&ulOperation);
139 if (FAILED(hrc))
140 break;
141 ULONG ulCurrentOperationPercent = 0;
142 hrc = progress->COMGETTER(OperationPercent(&ulCurrentOperationPercent));
143 if (FAILED(hrc))
144 break;
145
146 if (ulLastOperation != ulOperation)
147 {
148 hrc = progress->COMGETTER(OperationDescription(bstrOperationDescription.asOutParam()));
149 if (FAILED(hrc))
150 break;
151 ulLastPercent = (ULONG)-1; // force print
152 ulLastOperation = ulOperation;
153 }
154
155 if ( ulCurrentPercent != ulLastPercent
156 || ulCurrentOperationPercent != ulLastOperationPercent
157 )
158 {
159 LONG lSecsRem = 0;
160 progress->COMGETTER(TimeRemaining)(&lSecsRem);
161
162 RTStrmPrintf(g_pStdErr, "(%u/%u) %ls %02u%% => %02u%% (%d s remaining)\n", ulOperation + 1, cOperations,
163 bstrOperationDescription.raw(), ulCurrentOperationPercent, ulCurrentPercent, lSecsRem);
164 ulLastPercent = ulCurrentPercent;
165 ulLastOperationPercent = ulCurrentOperationPercent;
166 }
167 }
168 else
169 {
170 /* did we cross a 10% mark? */
171 if (ulCurrentPercent / 10 > ulLastPercent / 10)
172 {
173 /* make sure to also print out missed steps */
174 for (ULONG curVal = (ulLastPercent / 10) * 10 + 10; curVal <= (ulCurrentPercent / 10) * 10; curVal += 10)
175 {
176 if (curVal < 100)
177 {
178 RTStrmPrintf(g_pStdErr, "%u%%...", curVal);
179 RTStrmFlush(g_pStdErr);
180 }
181 }
182 ulLastPercent = (ulCurrentPercent / 10) * 10;
183 }
184 }
185 if (fCompleted)
186 break;
187
188 /* process async cancelation */
189 if (g_fCanceled && !fCanceledAlready)
190 {
191 hrc = progress->Cancel();
192 if (SUCCEEDED(hrc))
193 fCanceledAlready = true;
194 else
195 g_fCanceled = false;
196 }
197
198 /* make sure the loop is not too tight */
199 progress->WaitForCompletion(100);
200
201 NativeEventQueue::getMainEventQueue()->processEventQueue(0);
202 hrc = progress->COMGETTER(Completed(&fCompleted));
203 }
204
205 /* undo signal handling */
206 if (fCancelable)
207 {
208 signal(SIGINT, SIG_DFL);
209#ifdef SIGBREAK
210 signal(SIGBREAK, SIG_DFL);
211#endif
212 }
213
214 /* complete the line. */
215 LONG iRc = E_FAIL;
216 hrc = progress->COMGETTER(ResultCode)(&iRc);
217 if (SUCCEEDED(hrc))
218 {
219 if (SUCCEEDED(iRc))
220 RTStrmPrintf(g_pStdErr, "100%%\n");
221 else if (g_fCanceled)
222 RTStrmPrintf(g_pStdErr, "CANCELED\n");
223 else
224 {
225 if (!g_fDetailedProgress)
226 RTStrmPrintf(g_pStdErr, "\n");
227 RTStrmPrintf(g_pStdErr, "Progress state: %Rhrc\n", iRc);
228 }
229 hrc = iRc;
230 }
231 else
232 {
233 if (!g_fDetailedProgress)
234 RTStrmPrintf(g_pStdErr, "\n");
235 RTStrmPrintf(g_pStdErr, "Progress object failure: %Rhrc\n", hrc);
236 }
237 RTStrmFlush(g_pStdErr);
238 return hrc;
239}
240
241#ifdef RT_OS_WINDOWS
242// Required for ATL
243static CComModule _Module;
244#endif
245
246#endif /* !VBOX_ONLY_DOCS */
247
248
249#ifndef VBOX_ONLY_DOCS
250RTEXITCODE readPasswordFile(const char *pszFilename, com::Utf8Str *pPasswd)
251{
252 size_t cbFile;
253 char szPasswd[512];
254 int vrc = VINF_SUCCESS;
255 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
256 bool fStdIn = !strcmp(pszFilename, "stdin");
257 PRTSTREAM pStrm;
258 if (!fStdIn)
259 vrc = RTStrmOpen(pszFilename, "r", &pStrm);
260 else
261 pStrm = g_pStdIn;
262 if (RT_SUCCESS(vrc))
263 {
264 vrc = RTStrmReadEx(pStrm, szPasswd, sizeof(szPasswd)-1, &cbFile);
265 if (RT_SUCCESS(vrc))
266 {
267 if (cbFile >= sizeof(szPasswd)-1)
268 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Provided password in file '%s' is too long", pszFilename);
269 else
270 {
271 unsigned i;
272 for (i = 0; i < cbFile && !RT_C_IS_CNTRL(szPasswd[i]); i++)
273 ;
274 szPasswd[i] = '\0';
275 *pPasswd = szPasswd;
276 }
277 }
278 else
279 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Cannot read password from file '%s': %Rrc", pszFilename, vrc);
280 if (!fStdIn)
281 RTStrmClose(pStrm);
282 }
283 else
284 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Cannot open password file '%s' (%Rrc)", pszFilename, vrc);
285
286 return rcExit;
287}
288
289static RTEXITCODE settingsPasswordFile(ComPtr<IVirtualBox> virtualBox, const char *pszFilename)
290{
291 com::Utf8Str passwd;
292 RTEXITCODE rcExit = readPasswordFile(pszFilename, &passwd);
293 if (rcExit == RTEXITCODE_SUCCESS)
294 {
295 int rc;
296 CHECK_ERROR(virtualBox, SetSettingsSecret(com::Bstr(passwd).raw()));
297 if (FAILED(rc))
298 rcExit = RTEXITCODE_FAILURE;
299 }
300
301 return rcExit;
302}
303
304RTEXITCODE readPasswordFromConsole(com::Utf8Str *pPassword, const char *pszPrompt, ...)
305{
306 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
307 char aszPwdInput[_1K] = { 0 };
308 va_list vaArgs;
309
310 va_start(vaArgs, pszPrompt);
311 int vrc = RTStrmPrintfV(g_pStdOut, pszPrompt, vaArgs);
312 if (RT_SUCCESS(vrc))
313 {
314 bool fEchoOld = false;
315 vrc = RTStrmInputGetEchoChars(g_pStdIn, &fEchoOld);
316 if (RT_SUCCESS(vrc))
317 {
318 vrc = RTStrmInputSetEchoChars(g_pStdIn, false);
319 if (RT_SUCCESS(vrc))
320 {
321 vrc = RTStrmGetLine(g_pStdIn, &aszPwdInput[0], sizeof(aszPwdInput));
322 if (RT_SUCCESS(vrc))
323 *pPassword = aszPwdInput;
324 else
325 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed read password from command line (%Rrc)", vrc);
326
327 int vrc2 = RTStrmInputSetEchoChars(g_pStdIn, fEchoOld);
328 AssertRC(vrc2);
329 }
330 else
331 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to disable echoing typed characters (%Rrc)", vrc);
332 }
333 else
334 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to retrieve echo setting (%Rrc)", vrc);
335
336 RTStrmPutStr(g_pStdOut, "\n");
337 }
338 else
339 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to print prompt (%Rrc)", vrc);
340 va_end(vaArgs);
341
342 return rcExit;
343}
344
345#endif
346
347int main(int argc, char *argv[])
348{
349 /*
350 * Before we do anything, init the runtime without loading
351 * the support driver.
352 */
353 RTR3InitExe(argc, &argv, 0);
354
355 /*
356 * Parse the global options
357 */
358 bool fShowLogo = false;
359 bool fShowHelp = false;
360 int iCmd = 1;
361 int iCmdArg;
362 const char *g_pszSettingsPw = NULL;
363 const char *g_pszSettingsPwFile = NULL;
364
365 for (int i = 1; i < argc || argc <= iCmd; i++)
366 {
367 if ( argc <= iCmd
368 || !strcmp(argv[i], "help")
369 || !strcmp(argv[i], "-?")
370 || !strcmp(argv[i], "-h")
371 || !strcmp(argv[i], "-help")
372 || !strcmp(argv[i], "--help"))
373 {
374 if (i >= argc - 1)
375 {
376 showLogo(g_pStdOut);
377 printUsage(USAGE_ALL, ~0U, g_pStdOut);
378 return 0;
379 }
380 fShowLogo = true;
381 fShowHelp = true;
382 iCmd++;
383 continue;
384 }
385
386 if ( !strcmp(argv[i], "-v")
387 || !strcmp(argv[i], "-version")
388 || !strcmp(argv[i], "-Version")
389 || !strcmp(argv[i], "--version"))
390 {
391 /* Print version number, and do nothing else. */
392 RTPrintf("%sr%d\n", VBOX_VERSION_STRING, RTBldCfgRevision());
393 return 0;
394 }
395
396 if ( !strcmp(argv[i], "--dumpopts")
397 || !strcmp(argv[i], "-dumpopts"))
398 {
399 /* Special option to dump really all commands,
400 * even the ones not understood on this platform. */
401 printUsage(USAGE_DUMPOPTS, ~0U, g_pStdOut);
402 return 0;
403 }
404
405 if ( !strcmp(argv[i], "--nologo")
406 || !strcmp(argv[i], "-nologo")
407 || !strcmp(argv[i], "-q"))
408 {
409 /* suppress the logo */
410 fShowLogo = false;
411 iCmd++;
412 }
413 else if ( !strcmp(argv[i], "--detailed-progress")
414 || !strcmp(argv[i], "-d"))
415 {
416 /* detailed progress report */
417 g_fDetailedProgress = true;
418 iCmd++;
419 }
420 else if (!strcmp(argv[i], "--settingspw"))
421 {
422 if (i >= argc-1)
423 return RTMsgErrorExit(RTEXITCODE_FAILURE,
424 "Password expected");
425 /* password for certain settings */
426 g_pszSettingsPw = argv[i+1];
427 iCmd += 2;
428 }
429 else if (!strcmp(argv[i], "--settingspwfile"))
430 {
431 if (i >= argc-1)
432 return RTMsgErrorExit(RTEXITCODE_FAILURE,
433 "No password file specified");
434 g_pszSettingsPwFile = argv[i+1];
435 iCmd += 2;
436 }
437 else
438 break;
439 }
440
441 iCmdArg = iCmd + 1;
442
443 if (fShowLogo)
444 showLogo(g_pStdOut);
445
446
447#ifndef VBOX_ONLY_DOCS
448 /*
449 * Initialize COM.
450 */
451 using namespace com;
452 HRESULT hrc = com::Initialize();
453# ifdef VBOX_WITH_XPCOM
454 if (hrc == NS_ERROR_FILE_ACCESS_DENIED)
455 {
456 char szHome[RTPATH_MAX] = "";
457 com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome));
458 return RTMsgErrorExit(RTEXITCODE_FAILURE,
459 "Failed to initialize COM because the global settings directory '%s' is not accessible!", szHome);
460 }
461# endif
462 if (FAILED(hrc))
463 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize COM!");
464
465 RTEXITCODE rcExit = RTEXITCODE_FAILURE;
466 do
467 {
468 ///////////////////////////////////////////////////////////////////////////
469 // scopes all the stuff till shutdown
470 /*
471 * convertfromraw: does not need a VirtualBox instantiation.
472 */
473 if (argc >= iCmdArg && ( !strcmp(argv[iCmd], "convertfromraw")
474 || !strcmp(argv[iCmd], "convertdd")))
475 {
476 rcExit = handleConvertFromRaw(argc - iCmdArg, argv + iCmdArg);
477 break;
478 }
479
480 /*
481 * Get the remote VirtualBox object and create a local session object.
482 */
483 ComPtr<IVirtualBox> virtualBox;
484 ComPtr<ISession> session;
485
486 hrc = virtualBox.createLocalObject(CLSID_VirtualBox);
487 if (FAILED(hrc))
488 RTMsgError("Failed to create the VirtualBox object!");
489 else
490 {
491 hrc = session.createInprocObject(CLSID_Session);
492 if (FAILED(hrc))
493 RTMsgError("Failed to create a session object!");
494 }
495 if (FAILED(hrc))
496 {
497 com::ErrorInfo info;
498 if (!info.isFullAvailable() && !info.isBasicAvailable())
499 {
500 com::GluePrintRCMessage(hrc);
501 RTMsgError("Most likely, the VirtualBox COM server is not running or failed to start.");
502 }
503 else
504 com::GluePrintErrorInfo(info);
505 break;
506 }
507
508 /*
509 * All registered command handlers
510 */
511 static const struct
512 {
513 const char *command;
514 USAGECATEGORY help;
515 int (*handler)(HandlerArg *a);
516 } s_commandHandlers[] =
517 {
518 { "internalcommands", 0, handleInternalCommands },
519 { "list", USAGE_LIST, handleList },
520 { "showvminfo", USAGE_SHOWVMINFO, handleShowVMInfo },
521 { "registervm", USAGE_REGISTERVM, handleRegisterVM },
522 { "unregistervm", USAGE_UNREGISTERVM, handleUnregisterVM },
523 { "clonevm", USAGE_CLONEVM, handleCloneVM },
524 { "mediumproperty", USAGE_MEDIUMPROPERTY, handleMediumProperty },
525 { "hdproperty", USAGE_MEDIUMPROPERTY, handleMediumProperty }, /* backward compatibility */
526 { "createmedium", USAGE_CREATEMEDIUM, handleCreateMedium },
527 { "createhd", USAGE_CREATEMEDIUM, handleCreateMedium }, /* backward compatibility */
528 { "createvdi", USAGE_CREATEMEDIUM, handleCreateMedium }, /* backward compatibility */
529 { "modifymedium", USAGE_MODIFYMEDIUM, handleModifyMedium },
530 { "modifyhd", USAGE_MODIFYMEDIUM, handleModifyMedium }, /* backward compatibility */
531 { "modifyvdi", USAGE_MODIFYMEDIUM, handleModifyMedium }, /* backward compatibility */
532 { "clonemedium", USAGE_CLONEMEDIUM, handleCloneMedium },
533 { "clonehd", USAGE_CLONEMEDIUM, handleCloneMedium }, /* backward compatibility */
534 { "clonevdi", USAGE_CLONEMEDIUM, handleCloneMedium }, /* backward compatibility */
535 { "encryptmedium", USAGE_ENCRYPTMEDIUM, handleEncryptMedium},
536 { "checkmediumpwd", USAGE_MEDIUMENCCHKPWD, handleCheckMediumPassword},
537 { "createvm", USAGE_CREATEVM, handleCreateVM },
538 { "modifyvm", USAGE_MODIFYVM, handleModifyVM },
539 { "startvm", USAGE_STARTVM, handleStartVM },
540 { "controlvm", USAGE_CONTROLVM, handleControlVM },
541 { "discardstate", USAGE_DISCARDSTATE, handleDiscardState },
542 { "adoptstate", USAGE_ADOPTSTATE, handleAdoptState },
543 { "snapshot", USAGE_SNAPSHOT, handleSnapshot },
544 { "closemedium", USAGE_CLOSEMEDIUM, handleCloseMedium },
545 { "storageattach", USAGE_STORAGEATTACH, handleStorageAttach },
546 { "storagectl", USAGE_STORAGECONTROLLER, handleStorageController },
547 { "showmediuminfo", USAGE_SHOWMEDIUMINFO, handleShowMediumInfo },
548 { "showhdinfo", USAGE_SHOWMEDIUMINFO, handleShowMediumInfo }, /* backward compatibility */
549 { "showvdiinfo", USAGE_SHOWMEDIUMINFO, handleShowMediumInfo }, /* backward compatibility */
550 { "getextradata", USAGE_GETEXTRADATA, handleGetExtraData },
551 { "setextradata", USAGE_SETEXTRADATA, handleSetExtraData },
552 { "setproperty", USAGE_SETPROPERTY, handleSetProperty },
553 { "usbfilter", USAGE_USBFILTER, handleUSBFilter },
554 { "sharedfolder", USAGE_SHAREDFOLDER, handleSharedFolder },
555#ifdef VBOX_WITH_GUEST_PROPS
556 { "guestproperty", USAGE_GUESTPROPERTY, handleGuestProperty },
557#endif
558#ifdef VBOX_WITH_GUEST_CONTROL
559 { "guestcontrol", USAGE_GUESTCONTROL, handleGuestControl },
560#endif
561 { "metrics", USAGE_METRICS, handleMetrics },
562 { "import", USAGE_IMPORTAPPLIANCE, handleImportAppliance },
563 { "export", USAGE_EXPORTAPPLIANCE, handleExportAppliance },
564#ifdef VBOX_WITH_NETFLT
565 { "hostonlyif", USAGE_HOSTONLYIFS, handleHostonlyIf },
566#endif
567 { "dhcpserver", USAGE_DHCPSERVER, handleDHCPServer},
568#ifdef VBOX_WITH_NAT_SERVICE
569 { "natnetwork", USAGE_NATNETWORK, handleNATNetwork},
570#endif
571 { "extpack", USAGE_EXTPACK, handleExtPack},
572 { "bandwidthctl", USAGE_BANDWIDTHCONTROL, handleBandwidthControl},
573 { "debugvm", USAGE_DEBUGVM, handleDebugVM},
574 { NULL, 0, NULL }
575 };
576
577 if (g_pszSettingsPw)
578 {
579 int rc;
580 CHECK_ERROR(virtualBox, SetSettingsSecret(Bstr(g_pszSettingsPw).raw()));
581 if (FAILED(rc))
582 {
583 rcExit = RTEXITCODE_FAILURE;
584 break;
585 }
586 }
587 else if (g_pszSettingsPwFile)
588 {
589 rcExit = settingsPasswordFile(virtualBox, g_pszSettingsPwFile);
590 if (rcExit != RTEXITCODE_SUCCESS)
591 break;
592 }
593
594 HandlerArg handlerArg = { 0, NULL, virtualBox, session };
595 int commandIndex;
596 for (commandIndex = 0; s_commandHandlers[commandIndex].command != NULL; commandIndex++)
597 {
598 if (!strcmp(s_commandHandlers[commandIndex].command, argv[iCmd]))
599 {
600 handlerArg.argc = argc - iCmdArg;
601 handlerArg.argv = &argv[iCmdArg];
602
603 if ( fShowHelp
604 || ( argc - iCmdArg == 0
605 && s_commandHandlers[commandIndex].help))
606 {
607 printUsage(s_commandHandlers[commandIndex].help, ~0U, g_pStdOut);
608 rcExit = RTEXITCODE_FAILURE; /* error */
609 }
610 else
611 rcExit = (RTEXITCODE)s_commandHandlers[commandIndex].handler(&handlerArg); /** @todo Change to return RTEXITCODE. */
612 break;
613 }
614 }
615 if (!s_commandHandlers[commandIndex].command)
616 {
617 /* Help topics. */
618 if (fShowHelp && !strcmp(argv[iCmd], "commands"))
619 {
620 RTPrintf("commands:\n");
621 for (unsigned i = 0; i < RT_ELEMENTS(s_commandHandlers) - 1; i++)
622 if ( i == 0 /* skip backwards compatibility entries */
623 || s_commandHandlers[i].help != s_commandHandlers[i - 1].help)
624 RTPrintf(" %s\n", s_commandHandlers[i].command);
625 }
626 else
627 rcExit = errorSyntax(USAGE_ALL, "Invalid command '%s'", Utf8Str(argv[iCmd]).c_str());
628 }
629
630 /* Although all handlers should always close the session if they open it,
631 * we do it here just in case if some of the handlers contains a bug --
632 * leaving the direct session not closed will turn the machine state to
633 * Aborted which may have unwanted side effects like killing the saved
634 * state file (if the machine was in the Saved state before). */
635 session->UnlockMachine();
636
637 NativeEventQueue::getMainEventQueue()->processEventQueue(0);
638
639 // end "all-stuff" scope
640 ///////////////////////////////////////////////////////////////////////////
641 } while (0);
642
643 com::Shutdown();
644
645 return rcExit;
646#else /* VBOX_ONLY_DOCS */
647 return RTEXITCODE_SUCCESS;
648#endif /* VBOX_ONLY_DOCS */
649}
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