VirtualBox

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

Last change on this file since 74942 was 73198, checked in by vboxsync, 6 years ago

FE/Qt: Few style fixes for r123794, r123795 and r123796.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use