VirtualBox

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

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

FE/VBoxManage: Remove the now unused VBoxManageHelp build target and the VBOX_ONLY_DOCS #ifdef's in the code, ​bugref:9186

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