VirtualBox

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

Last change on this file since 91396 was 91204, checked in by vboxsync, 3 years ago

doc, Frontends/VBoxManage: Integrate several refentry documentation pieces, bringing them up to date (making sure everything documented is actually understood). Remove the corresponding old style documentation and also the manually written help text in VBoxManage. Also fixes the synopsis printing when showing a syntax error message for new style documentation.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.1 KB
Line 
1/* $Id: VBoxManage.cpp 91204 2021-09-10 14:59:21Z vboxsync $ */
2/** @file
3 * VBoxManage - VirtualBox's command-line interface.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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/version.h>
35
36#include <iprt/asm.h>
37#include <iprt/buildconfig.h>
38#include <iprt/ctype.h>
39#include <iprt/file.h>
40#include <iprt/getopt.h>
41#include <iprt/initterm.h>
42#include <iprt/path.h>
43#include <iprt/stream.h>
44#include <iprt/string.h>
45
46#include <signal.h>
47
48#include "VBoxManage.h"
49
50
51/*********************************************************************************************************************************
52* Defined Constants And Macros *
53*********************************************************************************************************************************/
54/** The command doesn't need the COM stuff. */
55#define VBMG_CMD_F_NO_COM RT_BIT_32(0)
56
57#define VBMG_CMD_TODO HELP_CMD_VBOXMANAGE_INVALID
58
59
60/*********************************************************************************************************************************
61* Structures and Typedefs *
62*********************************************************************************************************************************/
63#ifndef VBOX_ONLY_DOCS
64/**
65 * VBoxManage command descriptor.
66 */
67typedef struct VBMGCMD
68{
69 /** The command. */
70 const char *pszCommand;
71 /** The help category. */
72 USAGECATEGORY enmHelpCat;
73 /** The new help command. */
74 enum HELP_CMD_VBOXMANAGE enmCmdHelp;
75 /** The handler. */
76 RTEXITCODE (*pfnHandler)(HandlerArg *pArg);
77 /** VBMG_CMD_F_XXX, */
78 uint32_t fFlags;
79} VBMGCMD;
80/** Pointer to a const VBoxManage command descriptor. */
81typedef VBMGCMD const *PCVBMGCMD;
82#endif
83
84
85/*********************************************************************************************************************************
86* Global Variables *
87*********************************************************************************************************************************/
88/*extern*/ bool g_fDetailedProgress = false;
89
90#ifndef VBOX_ONLY_DOCS
91/** Set by the signal handler. */
92static volatile bool g_fCanceled = false;
93
94
95/**
96 * All registered command handlers
97 */
98static const VBMGCMD g_aCommands[] =
99{
100 { "internalcommands", USAGE_INVALID, VBMG_CMD_TODO, handleInternalCommands, 0 },
101 { "list", USAGE_S_NEWCMD, HELP_CMD_LIST, handleList, 0 },
102 { "showvminfo", USAGE_S_NEWCMD, HELP_CMD_SHOWVMINFO, handleShowVMInfo, 0 },
103 { "registervm", USAGE_S_NEWCMD, HELP_CMD_REGISTERVM, handleRegisterVM, 0 },
104 { "unregistervm", USAGE_S_NEWCMD, HELP_CMD_UNREGISTERVM, handleUnregisterVM, 0 },
105 { "clonevm", USAGE_S_NEWCMD, HELP_CMD_CLONEVM, handleCloneVM, 0 },
106 { "movevm", USAGE_S_NEWCMD, HELP_CMD_MOVEVM, handleMoveVM, 0 },
107 { "mediumproperty", USAGE_MEDIUMPROPERTY, VBMG_CMD_TODO, handleMediumProperty, 0 },
108 { "hdproperty", USAGE_MEDIUMPROPERTY, VBMG_CMD_TODO, handleMediumProperty, 0 }, /* backward compatibility */
109 { "createmedium", USAGE_CREATEMEDIUM, VBMG_CMD_TODO, handleCreateMedium, 0 },
110 { "createhd", USAGE_CREATEMEDIUM, VBMG_CMD_TODO, handleCreateMedium, 0 }, /* backward compatibility */
111 { "createvdi", USAGE_CREATEMEDIUM, VBMG_CMD_TODO, handleCreateMedium, 0 }, /* backward compatibility */
112 { "modifymedium", USAGE_MODIFYMEDIUM, VBMG_CMD_TODO, handleModifyMedium, 0 },
113 { "modifyhd", USAGE_MODIFYMEDIUM, VBMG_CMD_TODO, handleModifyMedium, 0 }, /* backward compatibility */
114 { "modifyvdi", USAGE_MODIFYMEDIUM, VBMG_CMD_TODO, handleModifyMedium, 0 }, /* backward compatibility */
115 { "clonemedium", USAGE_CLONEMEDIUM, VBMG_CMD_TODO, handleCloneMedium, 0 },
116 { "clonehd", USAGE_CLONEMEDIUM, VBMG_CMD_TODO, handleCloneMedium, 0 }, /* backward compatibility */
117 { "clonevdi", USAGE_CLONEMEDIUM, VBMG_CMD_TODO, handleCloneMedium, 0 }, /* backward compatibility */
118 { "encryptmedium", USAGE_ENCRYPTMEDIUM, VBMG_CMD_TODO, handleEncryptMedium, 0 },
119 { "checkmediumpwd", USAGE_MEDIUMENCCHKPWD, VBMG_CMD_TODO, handleCheckMediumPassword, 0 },
120 { "createvm", USAGE_S_NEWCMD, HELP_CMD_CREATEVM, handleCreateVM, 0 },
121 { "modifyvm", USAGE_S_NEWCMD, HELP_CMD_MODIFYVM, handleModifyVM, 0 },
122 { "startvm", USAGE_STARTVM, VBMG_CMD_TODO, handleStartVM, 0 },
123 { "controlvm", USAGE_CONTROLVM, VBMG_CMD_TODO, handleControlVM, 0 },
124 { "unattended", USAGE_S_NEWCMD, HELP_CMD_UNATTENDED, handleUnattended, 0 },
125 { "discardstate", USAGE_DISCARDSTATE, VBMG_CMD_TODO, handleDiscardState, 0 },
126 { "adoptstate", USAGE_ADOPTSTATE, VBMG_CMD_TODO, handleAdoptState, 0 },
127 { "snapshot", USAGE_S_NEWCMD, HELP_CMD_SNAPSHOT, handleSnapshot, 0 },
128 { "closemedium", USAGE_CLOSEMEDIUM, VBMG_CMD_TODO, handleCloseMedium, 0 },
129 { "storageattach", USAGE_STORAGEATTACH, VBMG_CMD_TODO, handleStorageAttach, 0 },
130 { "storagectl", USAGE_STORAGECONTROLLER,VBMG_CMD_TODO, handleStorageController, 0 },
131 { "showmediuminfo", USAGE_SHOWMEDIUMINFO, VBMG_CMD_TODO, handleShowMediumInfo, 0 },
132 { "showhdinfo", USAGE_SHOWMEDIUMINFO, VBMG_CMD_TODO, handleShowMediumInfo, 0 }, /* backward compatibility */
133 { "showvdiinfo", USAGE_SHOWMEDIUMINFO, VBMG_CMD_TODO, handleShowMediumInfo, 0 }, /* backward compatibility */
134 { "mediumio", USAGE_S_NEWCMD, HELP_CMD_MEDIUMIO, handleMediumIO, 0 },
135 { "getextradata", USAGE_GETEXTRADATA, VBMG_CMD_TODO, handleGetExtraData, 0 },
136 { "setextradata", USAGE_SETEXTRADATA, VBMG_CMD_TODO, handleSetExtraData, 0 },
137 { "setproperty", USAGE_SETPROPERTY, VBMG_CMD_TODO, handleSetProperty, 0 },
138 { "usbfilter", USAGE_USBFILTER, VBMG_CMD_TODO, handleUSBFilter, 0 },
139 { "sharedfolder", USAGE_S_NEWCMD, HELP_CMD_SHAREDFOLDER, handleSharedFolder, 0 },
140#ifdef VBOX_WITH_GUEST_PROPS
141 { "guestproperty", USAGE_GUESTPROPERTY, VBMG_CMD_TODO, handleGuestProperty, 0 },
142#endif
143#ifdef VBOX_WITH_GUEST_CONTROL
144 { "guestcontrol", USAGE_GUESTCONTROL, VBMG_CMD_TODO, handleGuestControl, 0 },
145#endif
146 { "metrics", USAGE_METRICS, VBMG_CMD_TODO, handleMetrics, 0 },
147 { "import", USAGE_S_NEWCMD, HELP_CMD_IMPORT, handleImportAppliance, 0 },
148 { "export", USAGE_S_NEWCMD, HELP_CMD_EXPORT, handleExportAppliance, 0 },
149 { "signova", USAGE_S_NEWCMD, HELP_CMD_SIGNOVA, handleSignAppliance, VBMG_CMD_F_NO_COM },
150#ifdef VBOX_WITH_NETFLT
151 { "hostonlyif", USAGE_HOSTONLYIFS, VBMG_CMD_TODO, handleHostonlyIf, 0 },
152#endif
153 { "dhcpserver", USAGE_S_NEWCMD, HELP_CMD_DHCPSERVER, handleDHCPServer, 0 },
154#ifdef VBOX_WITH_NAT_SERVICE
155 { "natnetwork", USAGE_NATNETWORK, VBMG_CMD_TODO, handleNATNetwork, 0 },
156#endif
157 { "extpack", USAGE_S_NEWCMD, HELP_CMD_EXTPACK, handleExtPack, 0 },
158 { "bandwidthctl", USAGE_BANDWIDTHCONTROL, VBMG_CMD_TODO, handleBandwidthControl, 0 },
159 { "debugvm", USAGE_S_NEWCMD, HELP_CMD_DEBUGVM, handleDebugVM, 0 },
160 { "convertfromraw", USAGE_CONVERTFROMRAW, VBMG_CMD_TODO, handleConvertFromRaw, VBMG_CMD_F_NO_COM },
161 { "convertdd", USAGE_CONVERTFROMRAW, VBMG_CMD_TODO, handleConvertFromRaw, VBMG_CMD_F_NO_COM },
162 { "usbdevsource", USAGE_USBDEVSOURCE, VBMG_CMD_TODO, handleUSBDevSource, 0 },
163 { "cloudprofile", USAGE_S_NEWCMD, HELP_CMD_CLOUDPROFILE, handleCloudProfile, 0 },
164 { "cloud", USAGE_S_NEWCMD, HELP_CMD_CLOUD, handleCloud, 0 },
165 { "updatecheck", USAGE_S_NEWCMD, HELP_CMD_UPDATECHECK, handleUpdateCheck, 0 }
166};
167
168/**
169 * Looks up a command by name.
170 *
171 * @returns Pointer to the command structure.
172 * @param pszCommand Name of the command.
173 */
174static PCVBMGCMD lookupCommand(const char *pszCommand)
175{
176 if (pszCommand)
177 for (uint32_t i = 0; i < RT_ELEMENTS(g_aCommands); i++)
178 if (!strcmp(g_aCommands[i].pszCommand, pszCommand))
179 return &g_aCommands[i];
180 return NULL;
181}
182
183
184/**
185 * Signal handler that sets g_fCanceled.
186 *
187 * This can be executed on any thread in the process, on Windows it may even be
188 * a thread dedicated to delivering this signal. Do not doing anything
189 * unnecessary here.
190 */
191static void showProgressSignalHandler(int iSignal) RT_NOTHROW_DEF
192{
193 NOREF(iSignal);
194 ASMAtomicWriteBool(&g_fCanceled, true);
195}
196
197/**
198 * Print out progress on the console.
199 *
200 * This runs the main event queue every now and then to prevent piling up
201 * unhandled things (which doesn't cause real problems, just makes things
202 * react a little slower than in the ideal case).
203 */
204HRESULT showProgress(ComPtr<IProgress> progress, unsigned int fFlags)
205{
206 using namespace com;
207 HRESULT hrc;
208
209 AssertReturn(progress.isNotNull(), E_FAIL);
210
211 /* grandfather the old callers */
212 if (g_fDetailedProgress)
213 fFlags = SHOW_PROGRESS_DETAILS;
214
215 const bool fDetailed = RT_BOOL(fFlags & SHOW_PROGRESS_DETAILS);
216 const bool fQuiet = !RT_BOOL(fFlags & (SHOW_PROGRESS | SHOW_PROGRESS_DETAILS));
217
218
219 BOOL fCompleted = FALSE;
220 ULONG ulCurrentPercent = 0;
221 ULONG ulLastPercent = 0;
222
223 ULONG ulLastOperationPercent = (ULONG)-1;
224
225 ULONG ulLastOperation = (ULONG)-1;
226 Bstr bstrOperationDescription;
227
228 NativeEventQueue::getMainEventQueue()->processEventQueue(0);
229
230 ULONG cOperations = 1;
231 hrc = progress->COMGETTER(OperationCount)(&cOperations);
232 if (FAILED(hrc))
233 {
234 RTStrmPrintf(g_pStdErr, "Progress object failure: %Rhrc\n", hrc);
235 RTStrmFlush(g_pStdErr);
236 return hrc;
237 }
238
239 /*
240 * Note: Outputting the progress info to stderr (g_pStdErr) is intentional
241 * to not get intermixed with other (raw) stdout data which might get
242 * written in the meanwhile.
243 */
244
245 if (fFlags & SHOW_PROGRESS_DESC)
246 {
247 com::Bstr bstrDescription;
248 hrc = progress->COMGETTER(Description(bstrDescription.asOutParam()));
249 if (FAILED(hrc))
250 {
251 RTStrmPrintf(g_pStdErr, "Failed to get progress description: %Rhrc\n", hrc);
252 return hrc;
253 }
254
255 const char *pcszDescSep;
256 if (fDetailed) /* multiline output */
257 pcszDescSep = "\n";
258 else /* continues on the same line */
259 pcszDescSep = ": ";
260
261 RTStrmPrintf(g_pStdErr, "%ls%s", bstrDescription.raw(), pcszDescSep);
262 RTStrmFlush(g_pStdErr);
263 }
264
265 if (!fQuiet && !fDetailed)
266 {
267 RTStrmPrintf(g_pStdErr, "0%%...");
268 RTStrmFlush(g_pStdErr);
269 }
270
271 /* setup signal handling if cancelable */
272 bool fCanceledAlready = false;
273 BOOL fCancelable;
274 hrc = progress->COMGETTER(Cancelable)(&fCancelable);
275 if (FAILED(hrc))
276 fCancelable = FALSE;
277 if (fCancelable)
278 {
279 signal(SIGINT, showProgressSignalHandler);
280 signal(SIGTERM, showProgressSignalHandler);
281#ifdef SIGBREAK
282 signal(SIGBREAK, showProgressSignalHandler);
283#endif
284 }
285
286 hrc = progress->COMGETTER(Completed(&fCompleted));
287 while (SUCCEEDED(hrc))
288 {
289 progress->COMGETTER(Percent(&ulCurrentPercent));
290
291 if (fDetailed)
292 {
293 ULONG ulOperation = 1;
294 hrc = progress->COMGETTER(Operation)(&ulOperation);
295 if (FAILED(hrc))
296 break;
297 ULONG ulCurrentOperationPercent = 0;
298 hrc = progress->COMGETTER(OperationPercent(&ulCurrentOperationPercent));
299 if (FAILED(hrc))
300 break;
301
302 if (ulLastOperation != ulOperation)
303 {
304 hrc = progress->COMGETTER(OperationDescription(bstrOperationDescription.asOutParam()));
305 if (FAILED(hrc))
306 break;
307 ulLastPercent = (ULONG)-1; // force print
308 ulLastOperation = ulOperation;
309 }
310
311 if ( ulCurrentPercent != ulLastPercent
312 || ulCurrentOperationPercent != ulLastOperationPercent
313 )
314 {
315 LONG lSecsRem = 0;
316 progress->COMGETTER(TimeRemaining)(&lSecsRem);
317
318 RTStrmPrintf(g_pStdErr, "(%u/%u) %ls %02u%% => %02u%% (%d s remaining)\n", ulOperation + 1, cOperations,
319 bstrOperationDescription.raw(), ulCurrentOperationPercent, ulCurrentPercent, lSecsRem);
320 ulLastPercent = ulCurrentPercent;
321 ulLastOperationPercent = ulCurrentOperationPercent;
322 }
323 }
324 else if (!fQuiet)
325 {
326 /* did we cross a 10% mark? */
327 if (ulCurrentPercent / 10 > ulLastPercent / 10)
328 {
329 /* make sure to also print out missed steps */
330 for (ULONG curVal = (ulLastPercent / 10) * 10 + 10; curVal <= (ulCurrentPercent / 10) * 10; curVal += 10)
331 {
332 if (curVal < 100)
333 {
334 RTStrmPrintf(g_pStdErr, "%u%%...", curVal);
335 RTStrmFlush(g_pStdErr);
336 }
337 }
338 ulLastPercent = (ulCurrentPercent / 10) * 10;
339 }
340 }
341 if (fCompleted)
342 break;
343
344 /* process async cancelation */
345 if (g_fCanceled && !fCanceledAlready)
346 {
347 hrc = progress->Cancel();
348 if (SUCCEEDED(hrc))
349 fCanceledAlready = true;
350 else
351 g_fCanceled = false;
352 }
353
354 /* make sure the loop is not too tight */
355 progress->WaitForCompletion(100);
356
357 NativeEventQueue::getMainEventQueue()->processEventQueue(0);
358 hrc = progress->COMGETTER(Completed(&fCompleted));
359 }
360
361 /* undo signal handling */
362 if (fCancelable)
363 {
364 signal(SIGINT, SIG_DFL);
365 signal(SIGTERM, SIG_DFL);
366# ifdef SIGBREAK
367 signal(SIGBREAK, SIG_DFL);
368# endif
369 }
370
371 /* complete the line. */
372 LONG iRc = E_FAIL;
373 hrc = progress->COMGETTER(ResultCode)(&iRc);
374 if (SUCCEEDED(hrc))
375 {
376 /* async operation completed successfully */
377 if (SUCCEEDED(iRc))
378 {
379 if (!fDetailed)
380 {
381 if (fFlags == SHOW_PROGRESS_DESC)
382 RTStrmPrintf(g_pStdErr, "ok\n");
383 else if (!fQuiet)
384 RTStrmPrintf(g_pStdErr, "100%%\n");
385 }
386 }
387 else if (g_fCanceled)
388 RTStrmPrintf(g_pStdErr, "CANCELED\n");
389 else
390 {
391 if (fDetailed)
392 RTStrmPrintf(g_pStdErr, "Progress state: %Rhrc\n", iRc);
393 else if (fFlags != SHOW_PROGRESS_NONE)
394 RTStrmPrintf(g_pStdErr, "%Rhrc\n", iRc);
395 }
396 hrc = iRc;
397 }
398 else
399 {
400 if (!fDetailed)
401 RTStrmPrintf(g_pStdErr, "\n");
402 RTStrmPrintf(g_pStdErr, "Progress object failure: %Rhrc\n", hrc);
403 }
404 RTStrmFlush(g_pStdErr);
405 return hrc;
406}
407
408#endif /* !VBOX_ONLY_DOCS */
409
410
411int main(int argc, char *argv[])
412{
413 /*
414 * Before we do anything, init the runtime without loading
415 * the support driver.
416 */
417 int vrc = RTR3InitExe(argc, &argv, 0);
418 if (RT_FAILURE(vrc))
419 return RTMsgInitFailure(vrc);
420#if defined(RT_OS_WINDOWS) && !defined(VBOX_ONLY_DOCS)
421 ATL::CComModule _Module; /* Required internally by ATL (constructor records instance in global variable). */
422#endif
423
424 /*
425 * Parse the global options
426 */
427 bool fShowLogo = false;
428 bool fShowHelp = false;
429 int iCmd = 1;
430 int iCmdArg;
431 const char *pszSettingsPw = NULL;
432 const char *pszSettingsPwFile = NULL;
433#ifndef VBOX_ONLY_DOCS
434 int cResponseFileArgs = 0;
435 char **papszResponseFileArgs = NULL;
436 char **papszNewArgv = NULL;
437#endif
438
439 for (int i = 1; i < argc || argc <= iCmd; i++)
440 {
441 if ( argc <= iCmd
442 || !strcmp(argv[i], "help")
443 || !strcmp(argv[i], "--help")
444 || !strcmp(argv[i], "-?")
445 || !strcmp(argv[i], "-h")
446 || !strcmp(argv[i], "-help"))
447 {
448 if (i >= argc - 1)
449 {
450 showLogo(g_pStdOut);
451 printUsage(USAGE_S_ALL, RTMSGREFENTRYSTR_SCOPE_GLOBAL, g_pStdOut);
452 return 0;
453 }
454 fShowLogo = true;
455 fShowHelp = true;
456 iCmd++;
457 continue;
458 }
459
460#ifndef VBOX_ONLY_DOCS
461 if ( !strcmp(argv[i], "-V")
462 || !strcmp(argv[i], "--version")
463 || !strcmp(argv[i], "-v") /* deprecated */
464 || !strcmp(argv[i], "-version") /* deprecated */
465 || !strcmp(argv[i], "-Version") /* deprecated */)
466 {
467 /* Print version number, and do nothing else. */
468 RTPrintf("%sr%u\n", VBOX_VERSION_STRING, RTBldCfgRevision());
469 return 0;
470 }
471 if (!strcmp(argv[i], "--dump-build-type"))
472 {
473 /* Print the build type, and do nothing else. (Used by ValKit to detect build type.) */
474 RTPrintf("%s\n", RTBldCfgType());
475 return 0;
476 }
477#endif
478
479 if ( !strcmp(argv[i], "--dumpopts")
480 || !strcmp(argv[i], "-dumpopts") /* deprecated */)
481 {
482 /* Special option to dump really all commands,
483 * even the ones not understood on this platform. */
484 printUsage(USAGE_S_DUMPOPTS, RTMSGREFENTRYSTR_SCOPE_GLOBAL, g_pStdOut);
485 return 0;
486 }
487
488 if ( !strcmp(argv[i], "--nologo")
489 || !strcmp(argv[i], "-q")
490 || !strcmp(argv[i], "-nologo") /* deprecated */)
491 {
492 /* suppress the logo */
493 fShowLogo = false;
494 iCmd++;
495 }
496 else if ( !strcmp(argv[i], "--detailed-progress")
497 || !strcmp(argv[i], "-d"))
498 {
499 /* detailed progress report */
500 g_fDetailedProgress = true;
501 iCmd++;
502 }
503 else if (!strcmp(argv[i], "--settingspw"))
504 {
505 if (i >= argc - 1)
506 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Password expected");
507 /* password for certain settings */
508 pszSettingsPw = argv[i + 1];
509 iCmd += 2;
510 }
511 else if (!strcmp(argv[i], "--settingspwfile"))
512 {
513 if (i >= argc-1)
514 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No password file specified");
515 pszSettingsPwFile = argv[i+1];
516 iCmd += 2;
517 }
518#ifndef VBOX_ONLY_DOCS
519 else if (argv[i][0] == '@')
520 {
521 if (papszResponseFileArgs)
522 return RTMsgErrorExitFailure("Only one response file allowed");
523
524 /* Load response file, making sure it's valid UTF-8. */
525 char *pszResponseFile;
526 size_t cbResponseFile;
527 vrc = RTFileReadAllEx(&argv[i][1], 0, RTFOFF_MAX, RTFILE_RDALL_O_DENY_NONE | RTFILE_RDALL_F_TRAILING_ZERO_BYTE,
528 (void **)&pszResponseFile, &cbResponseFile);
529 if (RT_FAILURE(vrc))
530 return RTMsgErrorExitFailure("Error reading response file '%s': %Rrc", &argv[i][1], vrc);
531 vrc = RTStrValidateEncoding(pszResponseFile);
532 if (RT_FAILURE(vrc))
533 {
534 RTFileReadAllFree(pszResponseFile, cbResponseFile);
535 return RTMsgErrorExitFailure("Invalid response file ('%s') encoding: %Rrc", &argv[i][1], vrc);
536 }
537
538 /* Parse it. */
539 vrc = RTGetOptArgvFromString(&papszResponseFileArgs, &cResponseFileArgs, pszResponseFile,
540 RTGETOPTARGV_CNV_QUOTE_BOURNE_SH, NULL);
541 RTFileReadAllFree(pszResponseFile, cbResponseFile);
542 if (RT_FAILURE(vrc))
543 return RTMsgErrorExitFailure("Failed to parse response file '%s' (bourne shell style): %Rrc", &argv[i][1], vrc);
544
545 /* Construct new argv+argc with the response file arguments inserted. */
546 int cNewArgs = argc + cResponseFileArgs;
547 papszNewArgv = (char **)RTMemAllocZ((cNewArgs + 2) * sizeof(papszNewArgv[0]));
548 if (!papszNewArgv)
549 return RTMsgErrorExitFailure("out of memory");
550 memcpy(&papszNewArgv[0], &argv[0], sizeof(argv[0]) * (i + 1));
551 memcpy(&papszNewArgv[i + 1], papszResponseFileArgs, sizeof(argv[0]) * cResponseFileArgs);
552 memcpy(&papszNewArgv[i + 1 + cResponseFileArgs], &argv[i + 1], sizeof(argv[0]) * (argc - i - 1 + 1));
553 argv = papszNewArgv;
554 argc = argc + cResponseFileArgs;
555
556 iCmd++;
557 }
558#endif
559 else
560 break;
561 }
562
563 iCmdArg = iCmd + 1;
564
565 /*
566 * Show the logo and lookup the command and deal with fShowHelp = true.
567 */
568 if (fShowLogo)
569 showLogo(g_pStdOut);
570
571#ifndef VBOX_ONLY_DOCS
572 PCVBMGCMD pCmd = lookupCommand(argv[iCmd]);
573 if (pCmd && pCmd->enmCmdHelp != VBMG_CMD_TODO)
574 setCurrentCommand(pCmd->enmCmdHelp);
575
576 if ( pCmd
577 && ( fShowHelp
578 || ( argc - iCmdArg == 0
579 && pCmd->enmHelpCat != USAGE_INVALID)))
580 {
581 if (pCmd->enmCmdHelp == VBMG_CMD_TODO)
582 printUsage(pCmd->enmHelpCat, RTMSGREFENTRYSTR_SCOPE_GLOBAL, g_pStdOut);
583 else if (fShowHelp)
584 printHelp(g_pStdOut);
585 else
586 printUsage(g_pStdOut);
587 return RTEXITCODE_FAILURE; /* error */
588 }
589 if (!pCmd)
590 {
591 if (!strcmp(argv[iCmd], "commands"))
592 {
593 RTPrintf("commands:\n");
594 for (unsigned i = 0; i < RT_ELEMENTS(g_aCommands); i++)
595 if ( i == 0 /* skip backwards compatibility entries */
596 || (g_aCommands[i].enmHelpCat != USAGE_S_NEWCMD
597 ? g_aCommands[i].enmHelpCat != g_aCommands[i - 1].enmHelpCat
598 : g_aCommands[i].enmCmdHelp != g_aCommands[i - 1].enmCmdHelp))
599 RTPrintf(" %s\n", g_aCommands[i].pszCommand);
600 return RTEXITCODE_SUCCESS;
601 }
602 return errorSyntax(USAGE_S_ALL, "Invalid command '%s'", argv[iCmd]);
603 }
604
605 RTEXITCODE rcExit;
606 if (!(pCmd->fFlags & VBMG_CMD_F_NO_COM))
607 {
608 /*
609 * Initialize COM.
610 */
611 using namespace com;
612 HRESULT hrc = com::Initialize();
613 if (FAILED(hrc))
614 {
615# ifdef VBOX_WITH_XPCOM
616 if (hrc == NS_ERROR_FILE_ACCESS_DENIED)
617 {
618 char szHome[RTPATH_MAX] = "";
619 com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome));
620 return RTMsgErrorExit(RTEXITCODE_FAILURE,
621 "Failed to initialize COM because the global settings directory '%s' is not accessible!", szHome);
622 }
623# endif
624 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize COM! (hrc=%Rhrc)", hrc);
625 }
626
627
628 /*
629 * Get the remote VirtualBox object and create a local session object.
630 */
631 rcExit = RTEXITCODE_FAILURE;
632 ComPtr<IVirtualBoxClient> virtualBoxClient;
633 ComPtr<IVirtualBox> virtualBox;
634 hrc = virtualBoxClient.createInprocObject(CLSID_VirtualBoxClient);
635 if (SUCCEEDED(hrc))
636 hrc = virtualBoxClient->COMGETTER(VirtualBox)(virtualBox.asOutParam());
637 if (SUCCEEDED(hrc))
638 {
639 ComPtr<ISession> session;
640 hrc = session.createInprocObject(CLSID_Session);
641 if (SUCCEEDED(hrc))
642 {
643 /* Session secret. */
644 if (pszSettingsPw)
645 CHECK_ERROR2I_STMT(virtualBox, SetSettingsSecret(Bstr(pszSettingsPw).raw()), rcExit = RTEXITCODE_FAILURE);
646 else if (pszSettingsPwFile)
647 rcExit = settingsPasswordFile(virtualBox, pszSettingsPwFile);
648 else
649 rcExit = RTEXITCODE_SUCCESS;
650 if (rcExit == RTEXITCODE_SUCCESS)
651 {
652 /*
653 * Call the handler.
654 */
655 HandlerArg handlerArg = { argc - iCmdArg, &argv[iCmdArg], virtualBox, session };
656 rcExit = pCmd->pfnHandler(&handlerArg);
657
658 /* Although all handlers should always close the session if they open it,
659 * we do it here just in case if some of the handlers contains a bug --
660 * leaving the direct session not closed will turn the machine state to
661 * Aborted which may have unwanted side effects like killing the saved
662 * state file (if the machine was in the Saved state before). */
663 session->UnlockMachine();
664 }
665
666 NativeEventQueue::getMainEventQueue()->processEventQueue(0);
667 }
668 else
669 {
670 com::ErrorInfo info;
671 RTMsgError("Failed to create a session object!");
672 if (!info.isFullAvailable() && !info.isBasicAvailable())
673 com::GluePrintRCMessage(hrc);
674 else
675 com::GluePrintErrorInfo(info);
676 }
677 }
678 else
679 {
680 com::ErrorInfo info;
681 RTMsgError("Failed to create the VirtualBox object!");
682 if (!info.isFullAvailable() && !info.isBasicAvailable())
683 {
684 com::GluePrintRCMessage(hrc);
685 RTMsgError("Most likely, the VirtualBox COM server is not running or failed to start.");
686 }
687 else
688 com::GluePrintErrorInfo(info);
689 }
690
691 /*
692 * Terminate COM, make sure the virtualBox object has been released.
693 */
694 virtualBox.setNull();
695 virtualBoxClient.setNull();
696 NativeEventQueue::getMainEventQueue()->processEventQueue(0);
697 com::Shutdown();
698 }
699 else
700 {
701 /*
702 * The command needs no COM.
703 */
704 HandlerArg handlerArg;
705 handlerArg.argc = argc - iCmdArg;
706 handlerArg.argv = &argv[iCmdArg];
707 rcExit = pCmd->pfnHandler(&handlerArg);
708 }
709
710 if (papszResponseFileArgs)
711 {
712 RTGetOptArgvFree(papszResponseFileArgs);
713 RTMemFree(papszNewArgv);
714 }
715
716 return rcExit;
717#else /* VBOX_ONLY_DOCS */
718 return RTEXITCODE_SUCCESS;
719#endif /* VBOX_ONLY_DOCS */
720}
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