VirtualBox

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

最後變更 在這個檔案從91170是 91170,由 vboxsync 提交於 4 年 前

VBoxManage: With SHOW_PROGRESS_NONE don't print "progress state" when
the async operation completes with an error. bugref:10065.

That's a bit ambiguously phrased too, as it's not the state of the
progress (object itself) that is being reported here, but the state of
the async operation progress this progress object is tracking. But
that's not the yak I want to shave.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 28.0 KB
 
1/* $Id: VBoxManage.cpp 91170 2021-09-08 19:21:10Z 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.alldomusa.eu.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_LIST, VBMG_CMD_TODO, handleList, 0 },
102 { "showvminfo", USAGE_SHOWVMINFO, VBMG_CMD_TODO, handleShowVMInfo, 0 },
103 { "registervm", USAGE_REGISTERVM, VBMG_CMD_TODO, handleRegisterVM, 0 },
104 { "unregistervm", USAGE_UNREGISTERVM, VBMG_CMD_TODO, handleUnregisterVM, 0 },
105 { "clonevm", USAGE_S_NEWCMD, HELP_CMD_CLONEVM, handleCloneVM, 0 },
106 { "movevm", USAGE_MOVEVM, VBMG_CMD_TODO, 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_CREATEVM, VBMG_CMD_TODO, handleCreateVM, 0 },
121 { "modifyvm", USAGE_MODIFYVM, VBMG_CMD_TODO, 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_IMPORTAPPLIANCE, VBMG_CMD_TODO, handleImportAppliance, 0 },
148 { "export", USAGE_EXPORTAPPLIANCE, VBMG_CMD_TODO, 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 if (fFlags & SHOW_PROGRESS_DESC)
240 {
241 com::Bstr bstrDescription;
242 hrc = progress->COMGETTER(Description(bstrDescription.asOutParam()));
243 if (FAILED(hrc))
244 {
245 RTStrmPrintf(g_pStdErr, "Failed to get progress description: %Rhrc\n", hrc);
246 return hrc;
247 }
248
249 const char *pcszDescSep;
250 if (fFlags & SHOW_PROGRESS_DETAILS)
251 pcszDescSep = "\n";
252 else
253 pcszDescSep = ": ";
254
255 RTStrmPrintf(g_pStdErr, "%ls%s", bstrDescription.raw(), pcszDescSep);
256 RTStrmFlush(g_pStdErr);
257 }
258
259 /*
260 * Note: Outputting the progress info to stderr (g_pStdErr) is intentional
261 * to not get intermixed with other (raw) stdout data which might get
262 * written in the meanwhile.
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 (!fQuiet)
392 {
393 if (!fDetailed)
394 RTStrmPrintf(g_pStdErr, "\n");
395 RTStrmPrintf(g_pStdErr, "Progress state: %Rhrc\n", iRc);
396 }
397 }
398 hrc = iRc;
399 }
400 else
401 {
402 if (!fDetailed)
403 RTStrmPrintf(g_pStdErr, "\n");
404 RTStrmPrintf(g_pStdErr, "Progress object failure: %Rhrc\n", hrc);
405 }
406 RTStrmFlush(g_pStdErr);
407 return hrc;
408}
409
410#endif /* !VBOX_ONLY_DOCS */
411
412
413int main(int argc, char *argv[])
414{
415 /*
416 * Before we do anything, init the runtime without loading
417 * the support driver.
418 */
419 int vrc = RTR3InitExe(argc, &argv, 0);
420 if (RT_FAILURE(vrc))
421 return RTMsgInitFailure(vrc);
422#if defined(RT_OS_WINDOWS) && !defined(VBOX_ONLY_DOCS)
423 ATL::CComModule _Module; /* Required internally by ATL (constructor records instance in global variable). */
424#endif
425
426 /*
427 * Parse the global options
428 */
429 bool fShowLogo = false;
430 bool fShowHelp = false;
431 int iCmd = 1;
432 int iCmdArg;
433 const char *pszSettingsPw = NULL;
434 const char *pszSettingsPwFile = NULL;
435#ifndef VBOX_ONLY_DOCS
436 int cResponseFileArgs = 0;
437 char **papszResponseFileArgs = NULL;
438 char **papszNewArgv = NULL;
439#endif
440
441 for (int i = 1; i < argc || argc <= iCmd; i++)
442 {
443 if ( argc <= iCmd
444 || !strcmp(argv[i], "help")
445 || !strcmp(argv[i], "--help")
446 || !strcmp(argv[i], "-?")
447 || !strcmp(argv[i], "-h")
448 || !strcmp(argv[i], "-help"))
449 {
450 if (i >= argc - 1)
451 {
452 showLogo(g_pStdOut);
453 printUsage(USAGE_S_ALL, RTMSGREFENTRYSTR_SCOPE_GLOBAL, g_pStdOut);
454 return 0;
455 }
456 fShowLogo = true;
457 fShowHelp = true;
458 iCmd++;
459 continue;
460 }
461
462#ifndef VBOX_ONLY_DOCS
463 if ( !strcmp(argv[i], "-V")
464 || !strcmp(argv[i], "--version")
465 || !strcmp(argv[i], "-v") /* deprecated */
466 || !strcmp(argv[i], "-version") /* deprecated */
467 || !strcmp(argv[i], "-Version") /* deprecated */)
468 {
469 /* Print version number, and do nothing else. */
470 RTPrintf("%sr%u\n", VBOX_VERSION_STRING, RTBldCfgRevision());
471 return 0;
472 }
473 if (!strcmp(argv[i], "--dump-build-type"))
474 {
475 /* Print the build type, and do nothing else. (Used by ValKit to detect build type.) */
476 RTPrintf("%s\n", RTBldCfgType());
477 return 0;
478 }
479#endif
480
481 if ( !strcmp(argv[i], "--dumpopts")
482 || !strcmp(argv[i], "-dumpopts") /* deprecated */)
483 {
484 /* Special option to dump really all commands,
485 * even the ones not understood on this platform. */
486 printUsage(USAGE_S_DUMPOPTS, RTMSGREFENTRYSTR_SCOPE_GLOBAL, g_pStdOut);
487 return 0;
488 }
489
490 if ( !strcmp(argv[i], "--nologo")
491 || !strcmp(argv[i], "-q")
492 || !strcmp(argv[i], "-nologo") /* deprecated */)
493 {
494 /* suppress the logo */
495 fShowLogo = false;
496 iCmd++;
497 }
498 else if ( !strcmp(argv[i], "--detailed-progress")
499 || !strcmp(argv[i], "-d"))
500 {
501 /* detailed progress report */
502 g_fDetailedProgress = true;
503 iCmd++;
504 }
505 else if (!strcmp(argv[i], "--settingspw"))
506 {
507 if (i >= argc - 1)
508 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Password expected");
509 /* password for certain settings */
510 pszSettingsPw = argv[i + 1];
511 iCmd += 2;
512 }
513 else if (!strcmp(argv[i], "--settingspwfile"))
514 {
515 if (i >= argc-1)
516 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No password file specified");
517 pszSettingsPwFile = argv[i+1];
518 iCmd += 2;
519 }
520#ifndef VBOX_ONLY_DOCS
521 else if (argv[i][0] == '@')
522 {
523 if (papszResponseFileArgs)
524 return RTMsgErrorExitFailure("Only one response file allowed");
525
526 /* Load response file, making sure it's valid UTF-8. */
527 char *pszResponseFile;
528 size_t cbResponseFile;
529 vrc = RTFileReadAllEx(&argv[i][1], 0, RTFOFF_MAX, RTFILE_RDALL_O_DENY_NONE | RTFILE_RDALL_F_TRAILING_ZERO_BYTE,
530 (void **)&pszResponseFile, &cbResponseFile);
531 if (RT_FAILURE(vrc))
532 return RTMsgErrorExitFailure("Error reading response file '%s': %Rrc", &argv[i][1], vrc);
533 vrc = RTStrValidateEncoding(pszResponseFile);
534 if (RT_FAILURE(vrc))
535 {
536 RTFileReadAllFree(pszResponseFile, cbResponseFile);
537 return RTMsgErrorExitFailure("Invalid response file ('%s') encoding: %Rrc", &argv[i][1], vrc);
538 }
539
540 /* Parse it. */
541 vrc = RTGetOptArgvFromString(&papszResponseFileArgs, &cResponseFileArgs, pszResponseFile,
542 RTGETOPTARGV_CNV_QUOTE_BOURNE_SH, NULL);
543 RTFileReadAllFree(pszResponseFile, cbResponseFile);
544 if (RT_FAILURE(vrc))
545 return RTMsgErrorExitFailure("Failed to parse response file '%s' (bourne shell style): %Rrc", &argv[i][1], vrc);
546
547 /* Construct new argv+argc with the response file arguments inserted. */
548 int cNewArgs = argc + cResponseFileArgs;
549 papszNewArgv = (char **)RTMemAllocZ((cNewArgs + 2) * sizeof(papszNewArgv[0]));
550 if (!papszNewArgv)
551 return RTMsgErrorExitFailure("out of memory");
552 memcpy(&papszNewArgv[0], &argv[0], sizeof(argv[0]) * (i + 1));
553 memcpy(&papszNewArgv[i + 1], papszResponseFileArgs, sizeof(argv[0]) * cResponseFileArgs);
554 memcpy(&papszNewArgv[i + 1 + cResponseFileArgs], &argv[i + 1], sizeof(argv[0]) * (argc - i - 1 + 1));
555 argv = papszNewArgv;
556 argc = argc + cResponseFileArgs;
557
558 iCmd++;
559 }
560#endif
561 else
562 break;
563 }
564
565 iCmdArg = iCmd + 1;
566
567 /*
568 * Show the logo and lookup the command and deal with fShowHelp = true.
569 */
570 if (fShowLogo)
571 showLogo(g_pStdOut);
572
573#ifndef VBOX_ONLY_DOCS
574 PCVBMGCMD pCmd = lookupCommand(argv[iCmd]);
575 if (pCmd && pCmd->enmCmdHelp != VBMG_CMD_TODO)
576 setCurrentCommand(pCmd->enmCmdHelp);
577
578 if ( pCmd
579 && ( fShowHelp
580 || ( argc - iCmdArg == 0
581 && pCmd->enmHelpCat != USAGE_INVALID)))
582 {
583 if (pCmd->enmCmdHelp == VBMG_CMD_TODO)
584 printUsage(pCmd->enmHelpCat, RTMSGREFENTRYSTR_SCOPE_GLOBAL, g_pStdOut);
585 else if (fShowHelp)
586 printHelp(g_pStdOut);
587 else
588 printUsage(g_pStdOut);
589 return RTEXITCODE_FAILURE; /* error */
590 }
591 if (!pCmd)
592 {
593 if (!strcmp(argv[iCmd], "commands"))
594 {
595 RTPrintf("commands:\n");
596 for (unsigned i = 0; i < RT_ELEMENTS(g_aCommands); i++)
597 if ( i == 0 /* skip backwards compatibility entries */
598 || (g_aCommands[i].enmHelpCat != USAGE_S_NEWCMD
599 ? g_aCommands[i].enmHelpCat != g_aCommands[i - 1].enmHelpCat
600 : g_aCommands[i].enmCmdHelp != g_aCommands[i - 1].enmCmdHelp))
601 RTPrintf(" %s\n", g_aCommands[i].pszCommand);
602 return RTEXITCODE_SUCCESS;
603 }
604 return errorSyntax(USAGE_S_ALL, "Invalid command '%s'", argv[iCmd]);
605 }
606
607 RTEXITCODE rcExit;
608 if (!(pCmd->fFlags & VBMG_CMD_F_NO_COM))
609 {
610 /*
611 * Initialize COM.
612 */
613 using namespace com;
614 HRESULT hrc = com::Initialize();
615 if (FAILED(hrc))
616 {
617# ifdef VBOX_WITH_XPCOM
618 if (hrc == NS_ERROR_FILE_ACCESS_DENIED)
619 {
620 char szHome[RTPATH_MAX] = "";
621 com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome));
622 return RTMsgErrorExit(RTEXITCODE_FAILURE,
623 "Failed to initialize COM because the global settings directory '%s' is not accessible!", szHome);
624 }
625# endif
626 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize COM! (hrc=%Rhrc)", hrc);
627 }
628
629
630 /*
631 * Get the remote VirtualBox object and create a local session object.
632 */
633 rcExit = RTEXITCODE_FAILURE;
634 ComPtr<IVirtualBoxClient> virtualBoxClient;
635 ComPtr<IVirtualBox> virtualBox;
636 hrc = virtualBoxClient.createInprocObject(CLSID_VirtualBoxClient);
637 if (SUCCEEDED(hrc))
638 hrc = virtualBoxClient->COMGETTER(VirtualBox)(virtualBox.asOutParam());
639 if (SUCCEEDED(hrc))
640 {
641 ComPtr<ISession> session;
642 hrc = session.createInprocObject(CLSID_Session);
643 if (SUCCEEDED(hrc))
644 {
645 /* Session secret. */
646 if (pszSettingsPw)
647 CHECK_ERROR2I_STMT(virtualBox, SetSettingsSecret(Bstr(pszSettingsPw).raw()), rcExit = RTEXITCODE_FAILURE);
648 else if (pszSettingsPwFile)
649 rcExit = settingsPasswordFile(virtualBox, pszSettingsPwFile);
650 else
651 rcExit = RTEXITCODE_SUCCESS;
652 if (rcExit == RTEXITCODE_SUCCESS)
653 {
654 /*
655 * Call the handler.
656 */
657 HandlerArg handlerArg = { argc - iCmdArg, &argv[iCmdArg], virtualBox, session };
658 rcExit = pCmd->pfnHandler(&handlerArg);
659
660 /* Although all handlers should always close the session if they open it,
661 * we do it here just in case if some of the handlers contains a bug --
662 * leaving the direct session not closed will turn the machine state to
663 * Aborted which may have unwanted side effects like killing the saved
664 * state file (if the machine was in the Saved state before). */
665 session->UnlockMachine();
666 }
667
668 NativeEventQueue::getMainEventQueue()->processEventQueue(0);
669 }
670 else
671 {
672 com::ErrorInfo info;
673 RTMsgError("Failed to create a session object!");
674 if (!info.isFullAvailable() && !info.isBasicAvailable())
675 com::GluePrintRCMessage(hrc);
676 else
677 com::GluePrintErrorInfo(info);
678 }
679 }
680 else
681 {
682 com::ErrorInfo info;
683 RTMsgError("Failed to create the VirtualBox object!");
684 if (!info.isFullAvailable() && !info.isBasicAvailable())
685 {
686 com::GluePrintRCMessage(hrc);
687 RTMsgError("Most likely, the VirtualBox COM server is not running or failed to start.");
688 }
689 else
690 com::GluePrintErrorInfo(info);
691 }
692
693 /*
694 * Terminate COM, make sure the virtualBox object has been released.
695 */
696 virtualBox.setNull();
697 virtualBoxClient.setNull();
698 NativeEventQueue::getMainEventQueue()->processEventQueue(0);
699 com::Shutdown();
700 }
701 else
702 {
703 /*
704 * The command needs no COM.
705 */
706 HandlerArg handlerArg;
707 handlerArg.argc = argc - iCmdArg;
708 handlerArg.argv = &argv[iCmdArg];
709 rcExit = pCmd->pfnHandler(&handlerArg);
710 }
711
712 if (papszResponseFileArgs)
713 {
714 RTGetOptArgvFree(papszResponseFileArgs);
715 RTMemFree(papszNewArgv);
716 }
717
718 return rcExit;
719#else /* VBOX_ONLY_DOCS */
720 return RTEXITCODE_SUCCESS;
721#endif /* VBOX_ONLY_DOCS */
722}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette