VirtualBox

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

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

doc/manual,Main,Frontends: API changes in preparation for full VM encryption, guarded by VBOX_WITH_FULL_VM_ENCRYPTION (disabled by default) and returning a not supported error for now, bugref:9955

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