VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/main.cpp@ 82781

Last change on this file since 82781 was 79365, checked in by vboxsync, 5 years ago

Renaming VBoxGlobal to UICommon for bugref:9049 as planned.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.5 KB
RevLine 
[26719]1/* $Id: main.cpp 79365 2019-06-26 15:57:32Z vboxsync $ */
[382]2/** @file
[52722]3 * VBox Qt GUI - The main() function.
[382]4 */
5
6/*
[76553]7 * Copyright (C) 2006-2019 Oracle Corporation
[382]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
[5999]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.
[382]16 */
17
[57764]18/* Qt includes: */
[76606]19#include <QApplication>
20#include <QMessageBox>
21#ifdef VBOX_WS_X11
22# ifndef Q_OS_SOLARIS
23# include <QFontDatabase>
24# endif
25#endif
[57764]26
27/* GUI includes: */
[79365]28#include "UICommon.h"
[76606]29#include "UIStarter.h"
30#include "UIModalWindowManager.h"
31#ifdef VBOX_WS_MAC
32# include "VBoxUtils.h"
33# include "UICocoaApplication.h"
34#endif /* VBOX_WS_MAC */
[13500]35
[57764]36/* Other VBox includes: */
[76606]37#include <iprt/buildconfig.h>
38#include <iprt/stream.h>
39#include <VBox/err.h>
40#include <VBox/version.h>
41#ifdef VBOX_WITH_HARDENING
42# include <VBox/sup.h>
43#endif
[76818]44#if !defined(VBOX_WITH_HARDENING) || !defined(VBOX_RUNTIME_UI)
[76606]45# include <iprt/initterm.h>
46# ifdef VBOX_WS_MAC
47# include <iprt/asm.h>
[72242]48# endif
[76606]49#endif
[60362]50#ifdef VBOX_WS_X11
[76606]51# include <iprt/env.h>
52#endif
[57883]53#ifdef VBOX_WITH_HARDENING
54# include <iprt/ctype.h>
[76392]55#endif
[382]56
[57764]57/* Other includes: */
[60362]58#ifdef VBOX_WS_MAC
[57764]59# include <dlfcn.h>
60# include <sys/mman.h>
[60362]61#endif /* VBOX_WS_MAC */
62#ifdef VBOX_WS_X11
[57764]63# include <dlfcn.h>
[57767]64# include <unistd.h>
[57764]65# include <X11/Xlib.h>
66# if defined(RT_OS_LINUX) && defined(DEBUG)
67# include <signal.h>
68# include <execinfo.h>
69# ifndef __USE_GNU
70# define __USE_GNU
71# endif /* !__USE_GNU */
72# include <ucontext.h>
73# ifdef RT_ARCH_AMD64
74# define REG_PC REG_RIP
75# else /* !RT_ARCH_AMD64 */
76# define REG_PC REG_EIP
77# endif /* !RT_ARCH_AMD64 */
78# endif /* RT_OS_LINUX && DEBUG */
[60362]79#endif /* VBOX_WS_X11 */
[19094]80
[52722]81
[33540]82/* XXX Temporarily. Don't rely on the user to hack the Makefile himself! */
[18242]83QString g_QStrHintLinuxNoMemory = QApplication::tr(
[57768]84 "This error means that the kernel driver was either not able to "
85 "allocate enough memory or that some mapping operation failed."
86 );
[18242]87
88QString g_QStrHintLinuxNoDriver = QApplication::tr(
[77196]89 "The VirtualBox Linux kernel driver is either not loaded or not set "
90 "up correctly. Please try setting it up again by executing<br/><br/>"
[58090]91 " <font color=blue>'/sbin/vboxconfig'</font><br/><br/>"
[77196]92 "as root.<br/><br/>"
93 "If your system has EFI Secure Boot enabled you may also need to sign "
94 "the kernel modules (vboxdrv, vboxnetflt, vboxnetadp, vboxpci) before "
95 "you can load them. Please see your Linux system's documentation for "
96 "more information."
[57768]97 );
[18242]98
[20193]99QString g_QStrHintOtherWrongDriverVersion = QApplication::tr(
[57768]100 "The VirtualBox kernel modules do not match this version of "
101 "VirtualBox. The installation of VirtualBox was apparently not "
102 "successful. Please try completely uninstalling and reinstalling "
103 "VirtualBox."
104 );
[20188]105
106QString g_QStrHintLinuxWrongDriverVersion = QApplication::tr(
[57768]107 "The VirtualBox kernel modules do not match this version of "
108 "VirtualBox. The installation of VirtualBox was apparently not "
109 "successful. Executing<br/><br/>"
[58090]110 " <font color=blue>'/sbin/vboxconfig'</font><br/><br/>"
[77196]111 "may correct this. Make sure that you are not mixing builds "
112 "of VirtualBox from different sources."
[57768]113 );
[20188]114
[18242]115QString g_QStrHintOtherNoDriver = QApplication::tr(
[57768]116 "Make sure the kernel module has been loaded successfully."
117 );
[18242]118
119/* I hope this isn't (C), (TM) or (R) Microsoft support ;-) */
120QString g_QStrHintReinstall = QApplication::tr(
[57768]121 "Please try reinstalling VirtualBox."
122 );
[18242]123
[57764]124
[60362]125#ifdef VBOX_WS_MAC
[57780]126/**
127 * Mac OS X: Really ugly hack to bypass a set-uid check in AppKit.
128 *
129 * This will modify the issetugid() function to always return zero. This must
130 * be done _before_ AppKit is initialized, otherwise it will refuse to play ball
131 * with us as it distrusts set-uid processes since Snow Leopard. We, however,
132 * have carefully dropped all root privileges at this point and there should be
133 * no reason for any security concern here.
134 */
[57779]135static void HideSetUidRootFromAppKit()
[57765]136{
[57780]137 /* Find issetguid() and make it always return 0 by modifying the code: */
138 void *pvAddr = dlsym(RTLD_DEFAULT, "issetugid");
139 int rc = mprotect((void *)((uintptr_t)pvAddr & ~(uintptr_t)0xfff), 0x2000, PROT_WRITE | PROT_READ | PROT_EXEC);
140 if (!rc)
141 ASMAtomicWriteU32((volatile uint32_t *)pvAddr, 0xccc3c031); /* xor eax, eax; ret; int3 */
[57765]142}
[60362]143#endif /* VBOX_WS_MAC */
[57765]144
[60362]145#ifdef VBOX_WS_X11
[57765]146/** X11: For versions of Xlib which are aware of multi-threaded environments this function
147 * calls for XInitThreads() which initializes Xlib support for concurrent threads.
148 * @returns @c non-zero unless it is unsafe to make multi-threaded calls to Xlib.
149 * @remarks This is a workaround for a bug on old Xlib versions, fixed in commit
150 * 941f02e and released in Xlib version 1.1. We check for the symbol
151 * "xcb_connect" which was introduced in that version. */
152static Status MakeSureMultiThreadingIsSafe()
153{
154 /* Success by default: */
155 Status rc = 1;
156 /* Get a global handle to process symbols: */
157 void *pvProcess = dlopen(0, RTLD_GLOBAL | RTLD_LAZY);
158 /* Initialize multi-thread environment only if we can obtain
159 * an address of xcb_connect symbol in this process: */
160 if (pvProcess && dlsym(pvProcess, "xcb_connect"))
161 rc = XInitThreads();
162 /* Close the handle: */
163 if (pvProcess)
164 dlclose(pvProcess);
165 /* Return result: */
166 return rc;
167}
168
169# if defined(RT_OS_LINUX) && defined(DEBUG)
[57750]170/** X11, Linux, Debug: The signal handler that prints out a backtrace of the call stack.
171 * @remarks The code is taken from http://www.linuxjournal.com/article/6391. */
172static void BackTraceSignalHandler(int sig, siginfo_t *pInfo, void *pSecret)
173{
[382]174 void *trace[16];
[57750]175 char **messages = (char **)0;
176 int i, iTraceSize = 0;
177 ucontext_t *uc = (ucontext_t *)pSecret;
[382]178
[57750]179 /* Do something useful with siginfo_t: */
[382]180 if (sig == SIGSEGV)
[57750]181 Log(("GUI: Got signal %d, faulty address is %p, from %p\n",
182 sig, pInfo->si_addr, uc->uc_mcontext.gregs[REG_PC]));
183 /* Or do nothing by default: */
[382]184 else
[57750]185 Log(("GUI: Got signal %d\n", sig));
[382]186
[57750]187 /* Acquire backtrace of 16 lvls depth: */
188 iTraceSize = backtrace(trace, 16);
[382]189
[57750]190 /* Overwrite sigaction with caller's address: */
191 trace[1] = (void *)uc->uc_mcontext.gregs[REG_PC];
[382]192
[57750]193 /* Translate the addresses into an array of messages: */
194 messages = backtrace_symbols(trace, iTraceSize);
195
196 /* Skip first stack frame (points here): */
197 Log(("GUI: [bt] Execution path:\n"));
198 for (i = 1; i < iTraceSize; ++i)
199 Log(("GUI: [bt] %s\n", messages[i]));
200
201 exit(0);
[382]202}
203
[57750]204/** X11, Linux, Debug: Installs signal handler printing backtrace of the call stack. */
205static void InstallSignalHandler()
206{
207 struct sigaction sa;
208 sa.sa_sigaction = BackTraceSignalHandler;
209 sigemptyset(&sa.sa_mask);
210 sa.sa_flags = SA_RESTART | SA_SIGINFO;
211 sigaction(SIGSEGV, &sa, 0);
212 sigaction(SIGBUS, &sa, 0);
213 sigaction(SIGUSR1, &sa, 0);
214}
[57765]215# endif /* RT_OS_LINUX && DEBUG */
[60362]216#endif /* VBOX_WS_X11 */
[382]217
[58848]218/** Qt5 message handler, function that prints out
219 * debug, warning, critical, fatal and system error messages.
220 * @param type Holds the type of the message.
221 * @param context Holds the message context.
222 * @param strMessage Holds the message body. */
223static void QtMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &strMessage)
224{
225 NOREF(context);
[60362]226# ifndef VBOX_WS_X11
[58848]227 NOREF(strMessage);
[63305]228# endif
[58848]229 switch (type)
230 {
231 case QtDebugMsg:
232 Log(("Qt DEBUG: %s\n", strMessage.toUtf8().constData()));
233 break;
234 case QtWarningMsg:
235 Log(("Qt WARNING: %s\n", strMessage.toUtf8().constData()));
[60362]236# ifdef VBOX_WS_X11
[58848]237 /* Needed for instance for the message ``cannot connect to X server'': */
238 RTStrmPrintf(g_pStdErr, "Qt WARNING: %s\n", strMessage.toUtf8().constData());
[63305]239# endif
[58848]240 break;
241 case QtCriticalMsg:
242 Log(("Qt CRITICAL: %s\n", strMessage.toUtf8().constData()));
[60362]243# ifdef VBOX_WS_X11
[58848]244 /* Needed for instance for the message ``cannot connect to X server'': */
245 RTStrmPrintf(g_pStdErr, "Qt CRITICAL: %s\n", strMessage.toUtf8().constData());
[63305]246# endif
[58848]247 break;
248 case QtFatalMsg:
249 Log(("Qt FATAL: %s\n", strMessage.toUtf8().constData()));
[60362]250# ifdef VBOX_WS_X11
[58848]251 /* Needed for instance for the message ``cannot connect to X server'': */
252 RTStrmPrintf(g_pStdErr, "Qt FATAL: %s\n", strMessage.toUtf8().constData());
[63305]253# endif
[63306]254# if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
[63305]255 case QtInfoMsg:
[63306]256 /** @todo ignore? */
[63305]257 break;
[63306]258# endif
[58848]259 }
260}
[382]261
[57762]262/** Shows all available command line parameters. */
263static void ShowHelp()
[12026]264{
[76818]265#ifndef VBOX_RUNTIME_UI
[73191]266 static const char s_szTitle[] = VBOX_PRODUCT " VM Selector";
267#else
268 static const char s_szTitle[] = VBOX_PRODUCT " VM Runner";
269#endif
270 static const char s_szUsage[] =
[76818]271#ifdef VBOX_RUNTIME_UI
[73191]272 "Options:\n"
273 " --startvm <vmname|UUID> start a VM by specifying its UUID or name\n"
274 " --separate start a separate VM process\n"
275 " --normal keep normal (windowed) mode during startup\n"
276 " --fullscreen switch to fullscreen mode during startup\n"
277 " --seamless switch to seamless mode during startup\n"
278 " --scale switch to scale mode during startup\n"
279 " --no-startvm-errormsgbox do not show a message box for VM start errors\n"
280 " --restore-current restore the current snapshot before starting\n"
281 " --no-aggressive-caching delays caching media info in VM processes\n"
282 " --fda <image|none> Mount the specified floppy image\n"
283 " --dvd <image|none> Mount the specified DVD image\n"
[35564]284# ifdef VBOX_GUI_WITH_PIDFILE
[73191]285 " --pidfile <file> create a pidfile file when a VM is up and running\n"
[57762]286# endif /* VBOX_GUI_WITH_PIDFILE */
[14198]287# ifdef VBOX_WITH_DEBUGGER_GUI
[73191]288 " --dbg enable the GUI debug menu\n"
289 " --debug like --dbg and show debug windows at VM startup\n"
290 " --debug-command-line like --dbg and show command line window at VM startup\n"
291 " --debug-statistics like --dbg and show statistics window at VM startup\n"
292 " --no-debug disable the GUI debug menu and debug windows\n"
293 " --start-paused start the VM in the paused state\n"
294 " --start-running start the VM running (for overriding --debug*)\n"
[57762]295# endif /* VBOX_WITH_DEBUGGER_GUI */
[73191]296 "\n"
297 "Expert options:\n"
298 " --disable-patm disable code patching (ignored by AMD-V/VT-x)\n"
299 " --disable-csam disable code scanning (ignored by AMD-V/VT-x)\n"
300 " --recompile-supervisor recompiled execution of supervisor code (*)\n"
301 " --recompile-user recompiled execution of user code (*)\n"
302 " --recompile-all recompiled execution of all code, with disabled\n"
303 " code patching and scanning\n"
304 " --execute-all-in-iem For debugging the interpreted execution mode.\n"
305 " --warp-pct <pct> time warp factor, 100%% (= 1.0) = normal speed\n"
306 " (*) For AMD-V/VT-x setups the effect is --recompile-all.\n"
307 "\n"
[38324]308# ifdef VBOX_WITH_DEBUGGER_GUI
[73191]309 "The following environment (and extra data) variables are evaluated:\n"
310 " VBOX_GUI_DBG_ENABLED (GUI/Dbg/Enabled)\n"
311 " enable the GUI debug menu if set\n"
312 " VBOX_GUI_DBG_AUTO_SHOW (GUI/Dbg/AutoShow)\n"
313 " show debug windows at VM startup\n"
314 " VBOX_GUI_NO_DEBUGGER\n"
315 " disable the GUI debug menu and debug windows\n"
[57762]316# endif /* VBOX_WITH_DEBUGGER_GUI */
[73191]317#else
318 "No special options.\n"
319 "\n"
320 "If you are looking for --startvm and related options, you need to use VirtualBoxVM.\n"
321#endif
322 ;
323
324 RTPrintf("%s v%s\n"
325 "(C) 2005-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
326 "All rights reserved.\n"
327 "\n"
328 "%s",
329 s_szTitle, RTBldCfgVersion(), s_szUsage);
330
331#ifdef RT_OS_WINDOWS
[73198]332 /* Show message box. Modify the option list a little
333 * to better make it fit in the upcoming dialog. */
334 char szTitleWithVersion[sizeof(s_szTitle) + 128];
335 char szMsg[sizeof(s_szUsage) + 128];
336 char *pszDst = szMsg;
337 size_t offSrc = 0;
[73191]338 while (offSrc < sizeof(s_szUsage) - 1U)
339 {
340 char ch;
341 if ( s_szUsage[offSrc] == ' '
342 && s_szUsage[offSrc + 1] == ' '
343 && ( (ch = s_szUsage[offSrc + 2]) == '-' /* option line */
[73198]344 || ch == 'V' /* env.var. line */))
[73191]345 {
346 /* Split option lines: */
347 if (ch == '-')
348 {
349 offSrc += 2;
350 size_t cchOption = 0;
351 while ( s_szUsage[offSrc + cchOption] != ' '
352 || s_szUsage[offSrc + cchOption + 1] != ' ')
[73198]353 ++cchOption;
[73191]354
355 memcpy(pszDst, &s_szUsage[offSrc], cchOption);
[73198]356 offSrc += cchOption + 2;
357 pszDst += cchOption;
[73191]358 }
359 /* Change environment variable indentation: */
360 else
361 {
362 offSrc += 2;
363 size_t cchLine = 0;
364 while ((ch = s_szUsage[offSrc + cchLine]) != '\n' && ch != '\0')
[73198]365 ++cchLine;
[73191]366
367 memcpy(pszDst, &s_szUsage[offSrc], cchLine);
368 offSrc += cchLine + 1;
369 pszDst += cchLine;
370 }
371 *pszDst++ = '\n';
372 *pszDst++ = '\t';
373
374 while (s_szUsage[offSrc] == ' ')
[73198]375 ++offSrc;
[73191]376 }
377
[73198]378 /* Copy up to and including end of line: */
[73191]379 while ((ch = s_szUsage[offSrc++]) != '\n' && ch != '\0')
380 *pszDst++ = ch;
381 *pszDst++ = ch;
382 }
383 *pszDst = '\0';
384
385 RTStrPrintf(szTitleWithVersion, sizeof(szTitleWithVersion), "%s v%s - Command Line Options", s_szTitle, RTBldCfgVersion());
386 MessageBoxExA(NULL /*hwndOwner*/, szMsg, szTitleWithVersion, MB_OK | MB_ICONINFORMATION,
387 MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
388#endif
[12026]389}
390
[45439]391extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char ** /*envp*/)
[382]392{
[60865]393#ifdef RT_OS_WINDOWS
394 ATL::CComModule _Module; /* Required internally by ATL (constructor records instance in global variable). */
395#endif
396
[57883]397 /* Failed result initially: */
398 int iResultCode = 1;
399
[45439]400 /* Start logging: */
[382]401 LogFlowFuncEnter();
[45439]402
[45448]403 /* Simulate try-catch block: */
404 do
405 {
[60362]406#ifdef VBOX_WS_MAC
[57779]407 /* Hide setuid root from AppKit: */
408 HideSetUidRootFromAppKit();
[60362]409#endif /* VBOX_WS_MAC */
[57779]410
[60362]411#ifdef VBOX_WS_X11
[57779]412 /* Make sure multi-threaded environment is safe: */
413 if (!MakeSureMultiThreadingIsSafe())
414 break;
[60362]415#endif /* VBOX_WS_X11 */
[57779]416
[45448]417 /* Console help preprocessing: */
418 bool fHelpShown = false;
419 for (int i = 0; i < argc; ++i)
[12026]420 {
[45448]421 if ( !strcmp(argv[i], "-h")
422 || !strcmp(argv[i], "-?")
423 || !strcmp(argv[i], "-help")
424 || !strcmp(argv[i], "--help"))
425 {
426 fHelpShown = true;
[57762]427 ShowHelp();
[45448]428 break;
429 }
[12026]430 }
[45448]431 if (fHelpShown)
432 {
433 iResultCode = 0;
434 break;
435 }
[12026]436
[52174]437#ifdef VBOX_WITH_HARDENING
[57768]438 /* Make sure the image verification code works: */
[52174]439 SUPR3HardenedVerifyInit();
[57768]440#endif /* VBOX_WITH_HARDENING */
[52174]441
[60362]442#ifdef VBOX_WS_MAC
[57769]443 /* Apply font fixes (before QApplication get created and instantiated font-hints): */
[79365]444 switch (UICommon::determineOsRelease())
[54077]445 {
446 case MacOSXRelease_Mavericks: QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande"); break;
447 case MacOSXRelease_Yosemite: QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Helvetica Neue"); break;
[57953]448 case MacOSXRelease_ElCapitan: QFont::insertSubstitution(".SF NS Text", "Helvetica Neue"); break;
[54077]449 default: break;
450 }
[57769]451
[57768]452 /* Instantiate own NSApplication before QApplication do it for us: */
[45448]453 UICocoaApplication::instance();
[60362]454#endif /* VBOX_WS_MAC */
[16610]455
[60362]456#ifdef VBOX_WS_X11
[57769]457# if defined(RT_OS_LINUX) && defined(DEBUG)
458 /* Install signal handler to backtrace the call stack: */
459 InstallSignalHandler();
460# endif /* RT_OS_LINUX && DEBUG */
[60362]461#endif /* VBOX_WS_X11 */
[57769]462
[45448]463 /* Install Qt console message handler: */
[58848]464 qInstallMessageHandler(QtMessageOutput);
[13505]465
[69957]466 /* Enable HiDPI support: */
467 QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
[70112]468#if (!defined(DEBUG_bird) || defined(RT_OS_DARWIN))
[69957]469 QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
[70112]470#endif
[69957]471
[52784]472 /* Create application: */
[45439]473 QApplication a(argc, argv);
[4862]474
[60362]475#ifdef VBOX_WS_WIN
[57769]476 /* Drag in the sound drivers and DLLs early to get rid of the delay taking
477 * place when the main menu bar (or any action from that menu bar) is
478 * activated for the first time. This delay is especially annoying if it
479 * happens when the VM is executing in real mode (which gives 100% CPU
480 * load and slows down the load process that happens on the main GUI
481 * thread to several seconds). */
482 PlaySound(NULL, NULL, 0);
[60362]483#endif /* VBOX_WS_WIN */
[56916]484
[60362]485#ifdef VBOX_WS_MAC
[57769]486 /* Disable menu icons on MacOS X host: */
487 ::darwinDisableIconsInMenus();
[60362]488#endif /* VBOX_WS_MAC */
[50934]489
[60362]490#ifdef VBOX_WS_X11
[57769]491 /* Make all widget native.
492 * We did it to avoid various Qt crashes while testing widget attributes or acquiring winIds.
493 * Yes, we aware of note that alien widgets faster to draw but the only widget we need to be fast
494 * is viewport of VM which was always native since we are using his id for 3D service needs. */
495 a.setAttribute(Qt::AA_NativeWindows);
496
497# ifdef Q_OS_SOLARIS
[62471]498 a.setStyle("fusion");
[57769]499# endif /* Q_OS_SOLARIS */
[17959]500
[45439]501# ifndef Q_OS_SOLARIS
[57769]502 /* Apply font fixes (after QApplication get created and instantiated font-family): */
[13531]503 QFontDatabase fontDataBase;
[45439]504 QString currentFamily(QApplication::font().family());
505 bool isCurrentScaleable = fontDataBase.isScalable(currentFamily);
[45452]506 QString subFamily(QFont::substitute(currentFamily));
507 bool isSubScaleable = fontDataBase.isScalable(subFamily);
[13535]508 if (isCurrentScaleable && !isSubScaleable)
[58849]509 QFont::removeSubstitutions(currentFamily);
[57768]510# endif /* !Q_OS_SOLARIS */
[13505]511
[45439]512 /* Qt version check (major.minor are sensitive, fix number is ignored): */
[79365]513 if (UICommon::qtRTVersion() < (UICommon::qtCTVersion() & 0xFFFF00))
[4862]514 {
[45439]515 QString strMsg = QApplication::tr("Executable <b>%1</b> requires Qt %2.x, found Qt %3.")
516 .arg(qAppName())
[79365]517 .arg(UICommon::qtCTVersionString().section('.', 0, 1))
518 .arg(UICommon::qtRTVersionString());
[45439]519 QMessageBox::critical(0, QApplication::tr("Incompatible Qt Library Error"),
520 strMsg, QMessageBox::Abort, 0);
[53481]521 qFatal("%s", strMsg.toUtf8().constData());
[45452]522 break;
[13505]523 }
[60362]524#endif /* VBOX_WS_X11 */
[13505]525
[45439]526 /* Create modal-window manager: */
527 UIModalWindowManager::create();
528
[71360]529 /* Create UI starter: */
530 UIStarter::create();
[76818]531#ifndef VBOX_RUNTIME_UI
[73191]532 /* Create global app instance for Selector UI: */
[79365]533 UICommon::create(UICommon::UIType_SelectorUI);
[76818]534#else
[72389]535 /* Create global app instance for Runtime UI: */
[79365]536 UICommon::create(UICommon::UIType_RuntimeUI);
[72389]537#endif
[13505]538
[45439]539 /* Simulate try-catch block: */
[13505]540 do
541 {
[79365]542 /* Exit if UICommon is not valid: */
543 if (!uiCommon().isValid())
[13505]544 break;
545
[71360]546 /* Init link between UI starter and global app instance: */
547 gStarter->init();
548
[79365]549 /* Exit if UICommon pre-processed arguments: */
550 if (uiCommon().processArgs())
[45448]551 break;
[34275]552
[72363]553 // WORKAROUND:
554 // Initially we wanted to make that workaround for Runtime UI only,
555 // because only there we had a strict handling for proper application quit
556 // procedure. But it appeared on X11 (as usually due to an async nature) there
557 // can happen situations that Qt application is checking whether at least one
558 // window is already shown and if not - exits prematurely _before_ it is actually
559 // shown. That can happen for example if window is not yet shown because blocked
560 // by startup error message-box which is not treated as real window by some
561 // reason. So we are making application exit manual everywhere.
562 qApp->setQuitOnLastWindowClosed(false);
[59910]563
[72360]564 /* Request to Start UI _after_ QApplication executed: */
565 QMetaObject::invokeMethod(gStarter, "sltStartUI", Qt::QueuedConnection);
[23948]566
[57883]567 /* Start application: */
568 iResultCode = a.exec();
[71360]569
570 /* Break link between UI starter and global app instance: */
571 gStarter->deinit();
[382]572 }
[13505]573 while (0);
[45183]574
[71360]575 /* Destroy global app instance: */
[79365]576 UICommon::destroy();
[71360]577 /* Destroy UI starter: */
578 UIStarter::destroy();
[45452]579
[45448]580 /* Destroy modal-window manager: */
[45183]581 UIModalWindowManager::destroy();
[382]582 }
[45448]583 while (0);
[382]584
[45439]585 /* Finish logging: */
[45448]586 LogFlowFunc(("rc=%d\n", iResultCode));
[382]587 LogFlowFuncLeave();
588
[45439]589 /* Return result: */
[45448]590 return iResultCode;
[382]591}
[11725]592
[76818]593#if !defined(VBOX_WITH_HARDENING) || !defined(VBOX_RUNTIME_UI)
[11725]594
[45435]595int main(int argc, char **argv, char **envp)
[11725]596{
[68315]597# ifdef VBOX_WS_X11
[57779]598 /* Make sure multi-threaded environment is safe: */
[57748]599 if (!MakeSureMultiThreadingIsSafe())
[48137]600 return 1;
[68315]601# endif /* VBOX_WS_X11 */
[52902]602
[73198]603 /* Initialize VBox Runtime: */
[76818]604# ifdef VBOX_RUNTIME_UI
[73192]605 /* Initialize the SUPLib as well only if we are really about to start a VM.
[52902]606 * Don't do this if we are only starting the selector window or a separate VM process. */
[52894]607 bool fStartVM = false;
[52902]608 bool fSeparateProcess = false;
609 for (int i = 1; i < argc && !(fStartVM && fSeparateProcess); ++i)
[11725]610 {
[24252]611 /* NOTE: the check here must match the corresponding check for the
[79365]612 * options to start a VM in hardenedmain.cpp and UICommon.cpp exactly,
[24252]613 * otherwise there will be weird error messages. */
614 if ( !::strcmp(argv[i], "--startvm")
615 || !::strcmp(argv[i], "-startvm"))
[52894]616 fStartVM = true;
617 else if ( !::strcmp(argv[i], "--separate")
618 || !::strcmp(argv[i], "-separate"))
[52902]619 fSeparateProcess = true;
[11725]620 }
621
[52902]622 uint32_t fFlags = fStartVM && !fSeparateProcess ? RTR3INIT_FLAGS_SUPLIB : 0;
[76818]623# else
[73192]624 uint32_t fFlags = 0;
[76818]625# endif
[52894]626 int rc = RTR3InitExe(argc, &argv, fFlags);
627
[45435]628 /* Initialization failed: */
[18222]629 if (RT_FAILURE(rc))
630 {
[45435]631 /* We have to create QApplication anyway
632 * just to show the only one error-message: */
633 QApplication a(argc, &argv[0]);
[52902]634 Q_UNUSED(a);
635
[68315]636# ifdef Q_OS_SOLARIS
[62471]637 a.setStyle("fusion");
[73192]638# endif
[18762]639
[45435]640 /* Prepare the error-message: */
641 QString strTitle = QApplication::tr("VirtualBox - Runtime Error");
642 QString strText = "<html>";
[18222]643 switch (rc)
644 {
645 case VERR_VM_DRIVER_NOT_INSTALLED:
[41016]646 case VERR_VM_DRIVER_LOAD_ERROR:
[45435]647 strText += QApplication::tr("<b>Cannot access the kernel driver!</b><br/><br/>");
[18222]648# ifdef RT_OS_LINUX
[45435]649 strText += g_QStrHintLinuxNoDriver;
[73192]650# else
[45435]651 strText += g_QStrHintOtherNoDriver;
[73192]652# endif
[18222]653 break;
[18242]654# ifdef RT_OS_LINUX
655 case VERR_NO_MEMORY:
[45435]656 strText += g_QStrHintLinuxNoMemory;
[18242]657 break;
[73192]658# endif
[18762]659 case VERR_VM_DRIVER_NOT_ACCESSIBLE:
[45435]660 strText += QApplication::tr("Kernel driver not accessible");
[18762]661 break;
[20188]662 case VERR_VM_DRIVER_VERSION_MISMATCH:
663# ifdef RT_OS_LINUX
[45435]664 strText += g_QStrHintLinuxWrongDriverVersion;
[73192]665# else
[45435]666 strText += g_QStrHintOtherWrongDriverVersion;
[73192]667# endif
[20188]668 break;
[18222]669 default:
[45435]670 strText += QApplication::tr("Unknown error %2 during initialization of the Runtime").arg(rc);
[18222]671 break;
672 }
[45435]673 strText += "</html>";
674
675 /* Show the error-message: */
676 QMessageBox::critical(0 /* parent */, strTitle, strText,
677 QMessageBox::Abort /* 1st button */, 0 /* 2nd button */);
678
679 /* Default error-result: */
[18222]680 return 1;
681 }
[11822]682
[73198]683 /* Call to actual main function: */
[45435]684 return TrustedMain(argc, argv, envp);
[11725]685}
686
[76818]687#endif /* !VBOX_WITH_HARDENING || !VBOX_RUNTIME_UI */
[13458]688
[72242]689#ifdef VBOX_WITH_HARDENING
[57501]690
691/**
692 * Special entrypoint used by the hardening code when something goes south.
693 *
694 * Display an error dialog to the user.
695 *
696 * @param pszWhere Indicates where the error occured.
697 * @param enmWhat Indicates what init operation was going on at the time.
698 * @param rc The VBox status code corresponding to the error.
699 * @param pszMsgFmt The message format string.
700 * @param va Format arguments.
701 */
[45435]702extern "C" DECLEXPORT(void) TrustedError(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, va_list va)
[13458]703{
[60362]704# ifdef VBOX_WS_MAC
[57779]705 /* Hide setuid root from AppKit: */
706 HideSetUidRootFromAppKit();
[60362]707# endif /* VBOX_WS_MAC */
[57747]708
[57501]709 char szMsgBuf[_16K];
[17862]710
[57501]711 /*
712 * We have to create QApplication anyway just to show the only one error-message.
713 * This is a bit hackish as we don't have the argument vector handy.
714 */
[13505]715 int argc = 0;
716 char *argv[2] = { NULL, NULL };
[45435]717 QApplication a(argc, &argv[0]);
[13458]718
[57501]719 /*
720 * The details starts off a properly formatted rc and where/what, we use
721 * the szMsgBuf for this, thus this have to come before the actual message
722 * formatting.
723 */
724 RTStrPrintf(szMsgBuf, sizeof(szMsgBuf),
725 "<!--EOM-->"
726 "where: %s\n"
727 "what: %d\n"
728 "%Rra\n",
729 pszWhere, enmWhat, rc);
730 QString strDetails = szMsgBuf;
[51770]731
[57501]732 /*
733 * Format the error message. Take whatever comes after a double new line as
734 * something better off in the details section.
735 */
[51770]736 RTStrPrintfV(szMsgBuf, sizeof(szMsgBuf), pszMsgFmt, va);
[57501]737
738 char *pszDetails = strstr(szMsgBuf, "\n\n");
739 if (pszDetails)
740 {
741 while (RT_C_IS_SPACE(*pszDetails))
742 *pszDetails++ = '\0';
743 if (*pszDetails)
744 {
745 strDetails += "\n";
746 strDetails += pszDetails;
747 }
748 RTStrStripR(szMsgBuf);
749 }
750
[51770]751 QString strText = QApplication::tr("<html><b>%1 (rc=%2)</b><br/><br/>").arg(szMsgBuf).arg(rc);
[52007]752 strText.replace(QString("\n"), QString("<br>"));
[51770]753
[57501]754 /*
755 * Append possibly helpful hints to the error message.
756 */
[13458]757 switch (enmWhat)
758 {
759 case kSupInitOp_Driver:
[18242]760# ifdef RT_OS_LINUX
[45435]761 strText += g_QStrHintLinuxNoDriver;
762# else /* RT_OS_LINUX */
763 strText += g_QStrHintOtherNoDriver;
764# endif /* !RT_OS_LINUX */
[13458]765 break;
766 case kSupInitOp_IPRT:
[51770]767 case kSupInitOp_Misc:
[20188]768 if (rc == VERR_VM_DRIVER_VERSION_MISMATCH)
[63305]769# ifndef RT_OS_LINUX
770 strText += g_QStrHintOtherWrongDriverVersion;
771# else
[45435]772 strText += g_QStrHintLinuxWrongDriverVersion;
[63305]773 else if (rc == VERR_NO_MEMORY)
774 strText += g_QStrHintLinuxNoMemory;
775# endif
[20188]776 else
[45435]777 strText += g_QStrHintReinstall;
[18242]778 break;
[13458]779 case kSupInitOp_Integrity:
780 case kSupInitOp_RootCheck:
[45435]781 strText += g_QStrHintReinstall;
[13458]782 break;
783 default:
784 /* no hints here */
785 break;
786 }
[51770]787
[60362]788# ifdef VBOX_WS_X11
[57767]789 /* We have to to make sure that we display the error-message
790 * after the parent displayed its own message. */
[13506]791 sleep(2);
[60362]792# endif /* VBOX_WS_X11 */
[45435]793
[57964]794 /* Update strText with strDetails: */
[57501]795 if (!strDetails.isEmpty())
[57964]796 strText += QString("<br><br>%1").arg(strDetails);
[57501]797
[57964]798 /* Close the <html> scope: */
799 strText += "</html>";
[57501]800
[57964]801 /* Create and show the error message-box: */
802 QMessageBox::critical(0, QApplication::tr("VirtualBox - Error In %1").arg(pszWhere), strText);
803
[53481]804 qFatal("%s", strText.toUtf8().constData());
[13458]805}
806
807#endif /* VBOX_WITH_HARDENING */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use