VirtualBox

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

Last change on this file since 85550 was 85121, checked in by vboxsync, 4 years ago

iprt/cdefs.h: Refactored the typedef use of DECLCALLBACK as well as DECLCALLBACKMEMBER to wrap the whole expression, similar to the DECLR?CALLBACKMEMBER macros. This allows adding a throw() at the end when compiling with the VC++ compiler to indicate that the callbacks won't throw anything, so we can stop supressing the C5039 warning about passing functions that can potential throw C++ exceptions to extern C code that can't necessarily cope with such (unwind,++). Introduced a few _EX variations that allows specifying different/no calling convention too, as that's handy when dynamically resolving host APIs. Fixed numerous places missing DECLCALLBACK and such. Left two angry @todos regarding use of CreateThread. bugref:9794

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.5 KB
Line 
1/* $Id: VBoxManage.cpp 85121 2020-07-08 19:33:26Z 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_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_SHAREDFOLDER, VBMG_CMD_TODO, 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};
166
167/**
168 * Looks up a command by name.
169 *
170 * @returns Pointer to the command structure.
171 * @param pszCommand Name of the command.
172 */
173static PCVBMGCMD lookupCommand(const char *pszCommand)
174{
175 if (pszCommand)
176 for (uint32_t i = 0; i < RT_ELEMENTS(g_aCommands); i++)
177 if (!strcmp(g_aCommands[i].pszCommand, pszCommand))
178 return &g_aCommands[i];
179 return NULL;
180}
181
182
183/**
184 * Signal handler that sets g_fCanceled.
185 *
186 * This can be executed on any thread in the process, on Windows it may even be
187 * a thread dedicated to delivering this signal. Do not doing anything
188 * unnecessary here.
189 */
190static void showProgressSignalHandler(int iSignal) RT_NOTHROW_DEF
191{
192 NOREF(iSignal);
193 ASMAtomicWriteBool(&g_fCanceled, true);
194}
195
196/**
197 * Print out progress on the console.
198 *
199 * This runs the main event queue every now and then to prevent piling up
200 * unhandled things (which doesn't cause real problems, just makes things
201 * react a little slower than in the ideal case).
202 */
203HRESULT showProgress(ComPtr<IProgress> progress)
204{
205 using namespace com;
206
207 AssertReturn(progress.isNotNull(), E_FAIL);
208
209 BOOL fCompleted = FALSE;
210 ULONG ulCurrentPercent = 0;
211 ULONG ulLastPercent = 0;
212
213 ULONG ulLastOperationPercent = (ULONG)-1;
214
215 ULONG ulLastOperation = (ULONG)-1;
216 Bstr bstrOperationDescription;
217
218 NativeEventQueue::getMainEventQueue()->processEventQueue(0);
219
220 ULONG cOperations = 1;
221 HRESULT hrc = progress->COMGETTER(OperationCount)(&cOperations);
222 if (FAILED(hrc))
223 {
224 RTStrmPrintf(g_pStdErr, "Progress object failure: %Rhrc\n", hrc);
225 RTStrmFlush(g_pStdErr);
226 return hrc;
227 }
228
229 /*
230 * Note: Outputting the progress info to stderr (g_pStdErr) is intentional
231 * to not get intermixed with other (raw) stdout data which might get
232 * written in the meanwhile.
233 */
234
235 if (!g_fDetailedProgress)
236 {
237 RTStrmPrintf(g_pStdErr, "0%%...");
238 RTStrmFlush(g_pStdErr);
239 }
240
241 /* setup signal handling if cancelable */
242 bool fCanceledAlready = false;
243 BOOL fCancelable;
244 hrc = progress->COMGETTER(Cancelable)(&fCancelable);
245 if (FAILED(hrc))
246 fCancelable = FALSE;
247 if (fCancelable)
248 {
249 signal(SIGINT, showProgressSignalHandler);
250 signal(SIGTERM, showProgressSignalHandler);
251#ifdef SIGBREAK
252 signal(SIGBREAK, showProgressSignalHandler);
253#endif
254 }
255
256 hrc = progress->COMGETTER(Completed(&fCompleted));
257 while (SUCCEEDED(hrc))
258 {
259 progress->COMGETTER(Percent(&ulCurrentPercent));
260
261 if (g_fDetailedProgress)
262 {
263 ULONG ulOperation = 1;
264 hrc = progress->COMGETTER(Operation)(&ulOperation);
265 if (FAILED(hrc))
266 break;
267 ULONG ulCurrentOperationPercent = 0;
268 hrc = progress->COMGETTER(OperationPercent(&ulCurrentOperationPercent));
269 if (FAILED(hrc))
270 break;
271
272 if (ulLastOperation != ulOperation)
273 {
274 hrc = progress->COMGETTER(OperationDescription(bstrOperationDescription.asOutParam()));
275 if (FAILED(hrc))
276 break;
277 ulLastPercent = (ULONG)-1; // force print
278 ulLastOperation = ulOperation;
279 }
280
281 if ( ulCurrentPercent != ulLastPercent
282 || ulCurrentOperationPercent != ulLastOperationPercent
283 )
284 {
285 LONG lSecsRem = 0;
286 progress->COMGETTER(TimeRemaining)(&lSecsRem);
287
288 RTStrmPrintf(g_pStdErr, "(%u/%u) %ls %02u%% => %02u%% (%d s remaining)\n", ulOperation + 1, cOperations,
289 bstrOperationDescription.raw(), ulCurrentOperationPercent, ulCurrentPercent, lSecsRem);
290 ulLastPercent = ulCurrentPercent;
291 ulLastOperationPercent = ulCurrentOperationPercent;
292 }
293 }
294 else
295 {
296 /* did we cross a 10% mark? */
297 if (ulCurrentPercent / 10 > ulLastPercent / 10)
298 {
299 /* make sure to also print out missed steps */
300 for (ULONG curVal = (ulLastPercent / 10) * 10 + 10; curVal <= (ulCurrentPercent / 10) * 10; curVal += 10)
301 {
302 if (curVal < 100)
303 {
304 RTStrmPrintf(g_pStdErr, "%u%%...", curVal);
305 RTStrmFlush(g_pStdErr);
306 }
307 }
308 ulLastPercent = (ulCurrentPercent / 10) * 10;
309 }
310 }
311 if (fCompleted)
312 break;
313
314 /* process async cancelation */
315 if (g_fCanceled && !fCanceledAlready)
316 {
317 hrc = progress->Cancel();
318 if (SUCCEEDED(hrc))
319 fCanceledAlready = true;
320 else
321 g_fCanceled = false;
322 }
323
324 /* make sure the loop is not too tight */
325 progress->WaitForCompletion(100);
326
327 NativeEventQueue::getMainEventQueue()->processEventQueue(0);
328 hrc = progress->COMGETTER(Completed(&fCompleted));
329 }
330
331 /* undo signal handling */
332 if (fCancelable)
333 {
334 signal(SIGINT, SIG_DFL);
335 signal(SIGTERM, SIG_DFL);
336# ifdef SIGBREAK
337 signal(SIGBREAK, SIG_DFL);
338# endif
339 }
340
341 /* complete the line. */
342 LONG iRc = E_FAIL;
343 hrc = progress->COMGETTER(ResultCode)(&iRc);
344 if (SUCCEEDED(hrc))
345 {
346 if (SUCCEEDED(iRc))
347 RTStrmPrintf(g_pStdErr, "100%%\n");
348 else if (g_fCanceled)
349 RTStrmPrintf(g_pStdErr, "CANCELED\n");
350 else
351 {
352 if (!g_fDetailedProgress)
353 RTStrmPrintf(g_pStdErr, "\n");
354 RTStrmPrintf(g_pStdErr, "Progress state: %Rhrc\n", iRc);
355 }
356 hrc = iRc;
357 }
358 else
359 {
360 if (!g_fDetailedProgress)
361 RTStrmPrintf(g_pStdErr, "\n");
362 RTStrmPrintf(g_pStdErr, "Progress object failure: %Rhrc\n", hrc);
363 }
364 RTStrmFlush(g_pStdErr);
365 return hrc;
366}
367
368#endif /* !VBOX_ONLY_DOCS */
369
370
371int main(int argc, char *argv[])
372{
373 /*
374 * Before we do anything, init the runtime without loading
375 * the support driver.
376 */
377 int vrc = RTR3InitExe(argc, &argv, 0);
378 if (RT_FAILURE(vrc))
379 return RTMsgInitFailure(vrc);
380#if defined(RT_OS_WINDOWS) && !defined(VBOX_ONLY_DOCS)
381 ATL::CComModule _Module; /* Required internally by ATL (constructor records instance in global variable). */
382#endif
383
384 /*
385 * Parse the global options
386 */
387 bool fShowLogo = false;
388 bool fShowHelp = false;
389 int iCmd = 1;
390 int iCmdArg;
391 const char *pszSettingsPw = NULL;
392 const char *pszSettingsPwFile = NULL;
393#ifndef VBOX_ONLY_DOCS
394 int cResponseFileArgs = 0;
395 char **papszResponseFileArgs = NULL;
396 char **papszNewArgv = NULL;
397#endif
398
399 for (int i = 1; i < argc || argc <= iCmd; i++)
400 {
401 if ( argc <= iCmd
402 || !strcmp(argv[i], "help")
403 || !strcmp(argv[i], "--help")
404 || !strcmp(argv[i], "-?")
405 || !strcmp(argv[i], "-h")
406 || !strcmp(argv[i], "-help"))
407 {
408 if (i >= argc - 1)
409 {
410 showLogo(g_pStdOut);
411 printUsage(USAGE_S_ALL, RTMSGREFENTRYSTR_SCOPE_GLOBAL, g_pStdOut);
412 return 0;
413 }
414 fShowLogo = true;
415 fShowHelp = true;
416 iCmd++;
417 continue;
418 }
419
420#ifndef VBOX_ONLY_DOCS
421 if ( !strcmp(argv[i], "-V")
422 || !strcmp(argv[i], "--version")
423 || !strcmp(argv[i], "-v") /* deprecated */
424 || !strcmp(argv[i], "-version") /* deprecated */
425 || !strcmp(argv[i], "-Version") /* deprecated */)
426 {
427 /* Print version number, and do nothing else. */
428 RTPrintf("%sr%u\n", VBOX_VERSION_STRING, RTBldCfgRevision());
429 return 0;
430 }
431#endif
432
433 if ( !strcmp(argv[i], "--dumpopts")
434 || !strcmp(argv[i], "-dumpopts") /* deprecated */)
435 {
436 /* Special option to dump really all commands,
437 * even the ones not understood on this platform. */
438 printUsage(USAGE_S_DUMPOPTS, RTMSGREFENTRYSTR_SCOPE_GLOBAL, g_pStdOut);
439 return 0;
440 }
441
442 if ( !strcmp(argv[i], "--nologo")
443 || !strcmp(argv[i], "-q")
444 || !strcmp(argv[i], "-nologo") /* deprecated */)
445 {
446 /* suppress the logo */
447 fShowLogo = false;
448 iCmd++;
449 }
450 else if ( !strcmp(argv[i], "--detailed-progress")
451 || !strcmp(argv[i], "-d"))
452 {
453 /* detailed progress report */
454 g_fDetailedProgress = true;
455 iCmd++;
456 }
457 else if (!strcmp(argv[i], "--settingspw"))
458 {
459 if (i >= argc - 1)
460 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Password expected");
461 /* password for certain settings */
462 pszSettingsPw = argv[i + 1];
463 iCmd += 2;
464 }
465 else if (!strcmp(argv[i], "--settingspwfile"))
466 {
467 if (i >= argc-1)
468 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No password file specified");
469 pszSettingsPwFile = argv[i+1];
470 iCmd += 2;
471 }
472#ifndef VBOX_ONLY_DOCS
473 else if (argv[i][0] == '@')
474 {
475 if (papszResponseFileArgs)
476 return RTMsgErrorExitFailure("Only one response file allowed");
477
478 /* Load response file, making sure it's valid UTF-8. */
479 char *pszResponseFile;
480 size_t cbResponseFile;
481 vrc = RTFileReadAllEx(&argv[i][1], 0, RTFOFF_MAX, RTFILE_RDALL_O_DENY_NONE | RTFILE_RDALL_F_TRAILING_ZERO_BYTE,
482 (void **)&pszResponseFile, &cbResponseFile);
483 if (RT_FAILURE(vrc))
484 return RTMsgErrorExitFailure("Error reading response file '%s': %Rrc", &argv[i][1], vrc);
485 vrc = RTStrValidateEncoding(pszResponseFile);
486 if (RT_FAILURE(vrc))
487 {
488 RTFileReadAllFree(pszResponseFile, cbResponseFile);
489 return RTMsgErrorExitFailure("Invalid response file ('%s') encoding: %Rrc", &argv[i][1], vrc);
490 }
491
492 /* Parse it. */
493 vrc = RTGetOptArgvFromString(&papszResponseFileArgs, &cResponseFileArgs, pszResponseFile,
494 RTGETOPTARGV_CNV_QUOTE_BOURNE_SH, NULL);
495 RTFileReadAllFree(pszResponseFile, cbResponseFile);
496 if (RT_FAILURE(vrc))
497 return RTMsgErrorExitFailure("Failed to parse response file '%s' (bourne shell style): %Rrc", &argv[i][1], vrc);
498
499 /* Construct new argv+argc with the response file arguments inserted. */
500 int cNewArgs = argc + cResponseFileArgs;
501 papszNewArgv = (char **)RTMemAllocZ((cNewArgs + 2) * sizeof(papszNewArgv[0]));
502 if (!papszNewArgv)
503 return RTMsgErrorExitFailure("out of memory");
504 memcpy(&papszNewArgv[0], &argv[0], sizeof(argv[0]) * (i + 1));
505 memcpy(&papszNewArgv[i + 1], papszResponseFileArgs, sizeof(argv[0]) * cResponseFileArgs);
506 memcpy(&papszNewArgv[i + 1 + cResponseFileArgs], &argv[i + 1], sizeof(argv[0]) * (argc - i - 1 + 1));
507 argv = papszNewArgv;
508 argc = argc + cResponseFileArgs;
509
510 iCmd++;
511 }
512#endif
513 else
514 break;
515 }
516
517 iCmdArg = iCmd + 1;
518
519 /*
520 * Show the logo and lookup the command and deal with fShowHelp = true.
521 */
522 if (fShowLogo)
523 showLogo(g_pStdOut);
524
525#ifndef VBOX_ONLY_DOCS
526 PCVBMGCMD pCmd = lookupCommand(argv[iCmd]);
527 if (pCmd && pCmd->enmCmdHelp != VBMG_CMD_TODO)
528 setCurrentCommand(pCmd->enmCmdHelp);
529
530 if ( pCmd
531 && ( fShowHelp
532 || ( argc - iCmdArg == 0
533 && pCmd->enmHelpCat != USAGE_INVALID)))
534 {
535 if (pCmd->enmCmdHelp == VBMG_CMD_TODO)
536 printUsage(pCmd->enmHelpCat, RTMSGREFENTRYSTR_SCOPE_GLOBAL, g_pStdOut);
537 else if (fShowHelp)
538 printHelp(g_pStdOut);
539 else
540 printUsage(g_pStdOut);
541 return RTEXITCODE_FAILURE; /* error */
542 }
543 if (!pCmd)
544 {
545 if (!strcmp(argv[iCmd], "commands"))
546 {
547 RTPrintf("commands:\n");
548 for (unsigned i = 0; i < RT_ELEMENTS(g_aCommands); i++)
549 if ( i == 0 /* skip backwards compatibility entries */
550 || (g_aCommands[i].enmHelpCat != USAGE_S_NEWCMD
551 ? g_aCommands[i].enmHelpCat != g_aCommands[i - 1].enmHelpCat
552 : g_aCommands[i].enmCmdHelp != g_aCommands[i - 1].enmCmdHelp))
553 RTPrintf(" %s\n", g_aCommands[i].pszCommand);
554 return RTEXITCODE_SUCCESS;
555 }
556 return errorSyntax(USAGE_S_ALL, "Invalid command '%s'", argv[iCmd]);
557 }
558
559 RTEXITCODE rcExit;
560 if (!(pCmd->fFlags & VBMG_CMD_F_NO_COM))
561 {
562 /*
563 * Initialize COM.
564 */
565 using namespace com;
566 HRESULT hrc = com::Initialize();
567 if (FAILED(hrc))
568 {
569# ifdef VBOX_WITH_XPCOM
570 if (hrc == NS_ERROR_FILE_ACCESS_DENIED)
571 {
572 char szHome[RTPATH_MAX] = "";
573 com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome));
574 return RTMsgErrorExit(RTEXITCODE_FAILURE,
575 "Failed to initialize COM because the global settings directory '%s' is not accessible!", szHome);
576 }
577# endif
578 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize COM! (hrc=%Rhrc)", hrc);
579 }
580
581
582 /*
583 * Get the remote VirtualBox object and create a local session object.
584 */
585 rcExit = RTEXITCODE_FAILURE;
586 ComPtr<IVirtualBoxClient> virtualBoxClient;
587 ComPtr<IVirtualBox> virtualBox;
588 hrc = virtualBoxClient.createInprocObject(CLSID_VirtualBoxClient);
589 if (SUCCEEDED(hrc))
590 hrc = virtualBoxClient->COMGETTER(VirtualBox)(virtualBox.asOutParam());
591 if (SUCCEEDED(hrc))
592 {
593 ComPtr<ISession> session;
594 hrc = session.createInprocObject(CLSID_Session);
595 if (SUCCEEDED(hrc))
596 {
597 /* Session secret. */
598 if (pszSettingsPw)
599 CHECK_ERROR2I_STMT(virtualBox, SetSettingsSecret(Bstr(pszSettingsPw).raw()), rcExit = RTEXITCODE_FAILURE);
600 else if (pszSettingsPwFile)
601 rcExit = settingsPasswordFile(virtualBox, pszSettingsPwFile);
602 else
603 rcExit = RTEXITCODE_SUCCESS;
604 if (rcExit == RTEXITCODE_SUCCESS)
605 {
606 /*
607 * Call the handler.
608 */
609 HandlerArg handlerArg = { argc - iCmdArg, &argv[iCmdArg], virtualBox, session };
610 rcExit = pCmd->pfnHandler(&handlerArg);
611
612 /* Although all handlers should always close the session if they open it,
613 * we do it here just in case if some of the handlers contains a bug --
614 * leaving the direct session not closed will turn the machine state to
615 * Aborted which may have unwanted side effects like killing the saved
616 * state file (if the machine was in the Saved state before). */
617 session->UnlockMachine();
618 }
619
620 NativeEventQueue::getMainEventQueue()->processEventQueue(0);
621 }
622 else
623 {
624 com::ErrorInfo info;
625 RTMsgError("Failed to create a session object!");
626 if (!info.isFullAvailable() && !info.isBasicAvailable())
627 com::GluePrintRCMessage(hrc);
628 else
629 com::GluePrintErrorInfo(info);
630 }
631 }
632 else
633 {
634 com::ErrorInfo info;
635 RTMsgError("Failed to create the VirtualBox object!");
636 if (!info.isFullAvailable() && !info.isBasicAvailable())
637 {
638 com::GluePrintRCMessage(hrc);
639 RTMsgError("Most likely, the VirtualBox COM server is not running or failed to start.");
640 }
641 else
642 com::GluePrintErrorInfo(info);
643 }
644
645 /*
646 * Terminate COM, make sure the virtualBox object has been released.
647 */
648 virtualBox.setNull();
649 virtualBoxClient.setNull();
650 NativeEventQueue::getMainEventQueue()->processEventQueue(0);
651 com::Shutdown();
652 }
653 else
654 {
655 /*
656 * The command needs no COM.
657 */
658 HandlerArg handlerArg;
659 handlerArg.argc = argc - iCmdArg;
660 handlerArg.argv = &argv[iCmdArg];
661 rcExit = pCmd->pfnHandler(&handlerArg);
662 }
663
664 if (papszResponseFileArgs)
665 {
666 RTGetOptArgvFree(papszResponseFileArgs);
667 RTMemFree(papszNewArgv);
668 }
669
670 return rcExit;
671#else /* VBOX_ONLY_DOCS */
672 return RTEXITCODE_SUCCESS;
673#endif /* VBOX_ONLY_DOCS */
674}
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