VirtualBox

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

Last change on this file since 92506 was 92404, checked in by vboxsync, 3 years ago

Main: bugref:1909: Fixed scm issues

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