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
Line 
1/* $Id: main.cpp 79365 2019-06-26 15:57:32Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - The main() function.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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/* Qt includes: */
19#include <QApplication>
20#include <QMessageBox>
21#ifdef VBOX_WS_X11
22# ifndef Q_OS_SOLARIS
23# include <QFontDatabase>
24# endif
25#endif
26
27/* GUI includes: */
28#include "UICommon.h"
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 */
35
36/* Other VBox includes: */
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
44#if !defined(VBOX_WITH_HARDENING) || !defined(VBOX_RUNTIME_UI)
45# include <iprt/initterm.h>
46# ifdef VBOX_WS_MAC
47# include <iprt/asm.h>
48# endif
49#endif
50#ifdef VBOX_WS_X11
51# include <iprt/env.h>
52#endif
53#ifdef VBOX_WITH_HARDENING
54# include <iprt/ctype.h>
55#endif
56
57/* Other includes: */
58#ifdef VBOX_WS_MAC
59# include <dlfcn.h>
60# include <sys/mman.h>
61#endif /* VBOX_WS_MAC */
62#ifdef VBOX_WS_X11
63# include <dlfcn.h>
64# include <unistd.h>
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 */
79#endif /* VBOX_WS_X11 */
80
81
82/* XXX Temporarily. Don't rely on the user to hack the Makefile himself! */
83QString g_QStrHintLinuxNoMemory = QApplication::tr(
84 "This error means that the kernel driver was either not able to "
85 "allocate enough memory or that some mapping operation failed."
86 );
87
88QString g_QStrHintLinuxNoDriver = QApplication::tr(
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/>"
91 " <font color=blue>'/sbin/vboxconfig'</font><br/><br/>"
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."
97 );
98
99QString g_QStrHintOtherWrongDriverVersion = QApplication::tr(
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 );
105
106QString g_QStrHintLinuxWrongDriverVersion = QApplication::tr(
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/>"
110 " <font color=blue>'/sbin/vboxconfig'</font><br/><br/>"
111 "may correct this. Make sure that you are not mixing builds "
112 "of VirtualBox from different sources."
113 );
114
115QString g_QStrHintOtherNoDriver = QApplication::tr(
116 "Make sure the kernel module has been loaded successfully."
117 );
118
119/* I hope this isn't (C), (TM) or (R) Microsoft support ;-) */
120QString g_QStrHintReinstall = QApplication::tr(
121 "Please try reinstalling VirtualBox."
122 );
123
124
125#ifdef VBOX_WS_MAC
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 */
135static void HideSetUidRootFromAppKit()
136{
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 */
142}
143#endif /* VBOX_WS_MAC */
144
145#ifdef VBOX_WS_X11
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)
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{
174 void *trace[16];
175 char **messages = (char **)0;
176 int i, iTraceSize = 0;
177 ucontext_t *uc = (ucontext_t *)pSecret;
178
179 /* Do something useful with siginfo_t: */
180 if (sig == SIGSEGV)
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: */
184 else
185 Log(("GUI: Got signal %d\n", sig));
186
187 /* Acquire backtrace of 16 lvls depth: */
188 iTraceSize = backtrace(trace, 16);
189
190 /* Overwrite sigaction with caller's address: */
191 trace[1] = (void *)uc->uc_mcontext.gregs[REG_PC];
192
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);
202}
203
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}
215# endif /* RT_OS_LINUX && DEBUG */
216#endif /* VBOX_WS_X11 */
217
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);
226# ifndef VBOX_WS_X11
227 NOREF(strMessage);
228# endif
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()));
236# ifdef VBOX_WS_X11
237 /* Needed for instance for the message ``cannot connect to X server'': */
238 RTStrmPrintf(g_pStdErr, "Qt WARNING: %s\n", strMessage.toUtf8().constData());
239# endif
240 break;
241 case QtCriticalMsg:
242 Log(("Qt CRITICAL: %s\n", strMessage.toUtf8().constData()));
243# ifdef VBOX_WS_X11
244 /* Needed for instance for the message ``cannot connect to X server'': */
245 RTStrmPrintf(g_pStdErr, "Qt CRITICAL: %s\n", strMessage.toUtf8().constData());
246# endif
247 break;
248 case QtFatalMsg:
249 Log(("Qt FATAL: %s\n", strMessage.toUtf8().constData()));
250# ifdef VBOX_WS_X11
251 /* Needed for instance for the message ``cannot connect to X server'': */
252 RTStrmPrintf(g_pStdErr, "Qt FATAL: %s\n", strMessage.toUtf8().constData());
253# endif
254# if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
255 case QtInfoMsg:
256 /** @todo ignore? */
257 break;
258# endif
259 }
260}
261
262/** Shows all available command line parameters. */
263static void ShowHelp()
264{
265#ifndef VBOX_RUNTIME_UI
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[] =
271#ifdef VBOX_RUNTIME_UI
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"
284# ifdef VBOX_GUI_WITH_PIDFILE
285 " --pidfile <file> create a pidfile file when a VM is up and running\n"
286# endif /* VBOX_GUI_WITH_PIDFILE */
287# ifdef VBOX_WITH_DEBUGGER_GUI
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"
295# endif /* VBOX_WITH_DEBUGGER_GUI */
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"
308# ifdef VBOX_WITH_DEBUGGER_GUI
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"
316# endif /* VBOX_WITH_DEBUGGER_GUI */
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
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;
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 */
344 || ch == 'V' /* env.var. line */))
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] != ' ')
353 ++cchOption;
354
355 memcpy(pszDst, &s_szUsage[offSrc], cchOption);
356 offSrc += cchOption + 2;
357 pszDst += cchOption;
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')
365 ++cchLine;
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] == ' ')
375 ++offSrc;
376 }
377
378 /* Copy up to and including end of line: */
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
389}
390
391extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char ** /*envp*/)
392{
393#ifdef RT_OS_WINDOWS
394 ATL::CComModule _Module; /* Required internally by ATL (constructor records instance in global variable). */
395#endif
396
397 /* Failed result initially: */
398 int iResultCode = 1;
399
400 /* Start logging: */
401 LogFlowFuncEnter();
402
403 /* Simulate try-catch block: */
404 do
405 {
406#ifdef VBOX_WS_MAC
407 /* Hide setuid root from AppKit: */
408 HideSetUidRootFromAppKit();
409#endif /* VBOX_WS_MAC */
410
411#ifdef VBOX_WS_X11
412 /* Make sure multi-threaded environment is safe: */
413 if (!MakeSureMultiThreadingIsSafe())
414 break;
415#endif /* VBOX_WS_X11 */
416
417 /* Console help preprocessing: */
418 bool fHelpShown = false;
419 for (int i = 0; i < argc; ++i)
420 {
421 if ( !strcmp(argv[i], "-h")
422 || !strcmp(argv[i], "-?")
423 || !strcmp(argv[i], "-help")
424 || !strcmp(argv[i], "--help"))
425 {
426 fHelpShown = true;
427 ShowHelp();
428 break;
429 }
430 }
431 if (fHelpShown)
432 {
433 iResultCode = 0;
434 break;
435 }
436
437#ifdef VBOX_WITH_HARDENING
438 /* Make sure the image verification code works: */
439 SUPR3HardenedVerifyInit();
440#endif /* VBOX_WITH_HARDENING */
441
442#ifdef VBOX_WS_MAC
443 /* Apply font fixes (before QApplication get created and instantiated font-hints): */
444 switch (UICommon::determineOsRelease())
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;
448 case MacOSXRelease_ElCapitan: QFont::insertSubstitution(".SF NS Text", "Helvetica Neue"); break;
449 default: break;
450 }
451
452 /* Instantiate own NSApplication before QApplication do it for us: */
453 UICocoaApplication::instance();
454#endif /* VBOX_WS_MAC */
455
456#ifdef VBOX_WS_X11
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 */
461#endif /* VBOX_WS_X11 */
462
463 /* Install Qt console message handler: */
464 qInstallMessageHandler(QtMessageOutput);
465
466 /* Enable HiDPI support: */
467 QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
468#if (!defined(DEBUG_bird) || defined(RT_OS_DARWIN))
469 QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
470#endif
471
472 /* Create application: */
473 QApplication a(argc, argv);
474
475#ifdef VBOX_WS_WIN
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);
483#endif /* VBOX_WS_WIN */
484
485#ifdef VBOX_WS_MAC
486 /* Disable menu icons on MacOS X host: */
487 ::darwinDisableIconsInMenus();
488#endif /* VBOX_WS_MAC */
489
490#ifdef VBOX_WS_X11
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
498 a.setStyle("fusion");
499# endif /* Q_OS_SOLARIS */
500
501# ifndef Q_OS_SOLARIS
502 /* Apply font fixes (after QApplication get created and instantiated font-family): */
503 QFontDatabase fontDataBase;
504 QString currentFamily(QApplication::font().family());
505 bool isCurrentScaleable = fontDataBase.isScalable(currentFamily);
506 QString subFamily(QFont::substitute(currentFamily));
507 bool isSubScaleable = fontDataBase.isScalable(subFamily);
508 if (isCurrentScaleable && !isSubScaleable)
509 QFont::removeSubstitutions(currentFamily);
510# endif /* !Q_OS_SOLARIS */
511
512 /* Qt version check (major.minor are sensitive, fix number is ignored): */
513 if (UICommon::qtRTVersion() < (UICommon::qtCTVersion() & 0xFFFF00))
514 {
515 QString strMsg = QApplication::tr("Executable <b>%1</b> requires Qt %2.x, found Qt %3.")
516 .arg(qAppName())
517 .arg(UICommon::qtCTVersionString().section('.', 0, 1))
518 .arg(UICommon::qtRTVersionString());
519 QMessageBox::critical(0, QApplication::tr("Incompatible Qt Library Error"),
520 strMsg, QMessageBox::Abort, 0);
521 qFatal("%s", strMsg.toUtf8().constData());
522 break;
523 }
524#endif /* VBOX_WS_X11 */
525
526 /* Create modal-window manager: */
527 UIModalWindowManager::create();
528
529 /* Create UI starter: */
530 UIStarter::create();
531#ifndef VBOX_RUNTIME_UI
532 /* Create global app instance for Selector UI: */
533 UICommon::create(UICommon::UIType_SelectorUI);
534#else
535 /* Create global app instance for Runtime UI: */
536 UICommon::create(UICommon::UIType_RuntimeUI);
537#endif
538
539 /* Simulate try-catch block: */
540 do
541 {
542 /* Exit if UICommon is not valid: */
543 if (!uiCommon().isValid())
544 break;
545
546 /* Init link between UI starter and global app instance: */
547 gStarter->init();
548
549 /* Exit if UICommon pre-processed arguments: */
550 if (uiCommon().processArgs())
551 break;
552
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);
563
564 /* Request to Start UI _after_ QApplication executed: */
565 QMetaObject::invokeMethod(gStarter, "sltStartUI", Qt::QueuedConnection);
566
567 /* Start application: */
568 iResultCode = a.exec();
569
570 /* Break link between UI starter and global app instance: */
571 gStarter->deinit();
572 }
573 while (0);
574
575 /* Destroy global app instance: */
576 UICommon::destroy();
577 /* Destroy UI starter: */
578 UIStarter::destroy();
579
580 /* Destroy modal-window manager: */
581 UIModalWindowManager::destroy();
582 }
583 while (0);
584
585 /* Finish logging: */
586 LogFlowFunc(("rc=%d\n", iResultCode));
587 LogFlowFuncLeave();
588
589 /* Return result: */
590 return iResultCode;
591}
592
593#if !defined(VBOX_WITH_HARDENING) || !defined(VBOX_RUNTIME_UI)
594
595int main(int argc, char **argv, char **envp)
596{
597# ifdef VBOX_WS_X11
598 /* Make sure multi-threaded environment is safe: */
599 if (!MakeSureMultiThreadingIsSafe())
600 return 1;
601# endif /* VBOX_WS_X11 */
602
603 /* Initialize VBox Runtime: */
604# ifdef VBOX_RUNTIME_UI
605 /* Initialize the SUPLib as well only if we are really about to start a VM.
606 * Don't do this if we are only starting the selector window or a separate VM process. */
607 bool fStartVM = false;
608 bool fSeparateProcess = false;
609 for (int i = 1; i < argc && !(fStartVM && fSeparateProcess); ++i)
610 {
611 /* NOTE: the check here must match the corresponding check for the
612 * options to start a VM in hardenedmain.cpp and UICommon.cpp exactly,
613 * otherwise there will be weird error messages. */
614 if ( !::strcmp(argv[i], "--startvm")
615 || !::strcmp(argv[i], "-startvm"))
616 fStartVM = true;
617 else if ( !::strcmp(argv[i], "--separate")
618 || !::strcmp(argv[i], "-separate"))
619 fSeparateProcess = true;
620 }
621
622 uint32_t fFlags = fStartVM && !fSeparateProcess ? RTR3INIT_FLAGS_SUPLIB : 0;
623# else
624 uint32_t fFlags = 0;
625# endif
626 int rc = RTR3InitExe(argc, &argv, fFlags);
627
628 /* Initialization failed: */
629 if (RT_FAILURE(rc))
630 {
631 /* We have to create QApplication anyway
632 * just to show the only one error-message: */
633 QApplication a(argc, &argv[0]);
634 Q_UNUSED(a);
635
636# ifdef Q_OS_SOLARIS
637 a.setStyle("fusion");
638# endif
639
640 /* Prepare the error-message: */
641 QString strTitle = QApplication::tr("VirtualBox - Runtime Error");
642 QString strText = "<html>";
643 switch (rc)
644 {
645 case VERR_VM_DRIVER_NOT_INSTALLED:
646 case VERR_VM_DRIVER_LOAD_ERROR:
647 strText += QApplication::tr("<b>Cannot access the kernel driver!</b><br/><br/>");
648# ifdef RT_OS_LINUX
649 strText += g_QStrHintLinuxNoDriver;
650# else
651 strText += g_QStrHintOtherNoDriver;
652# endif
653 break;
654# ifdef RT_OS_LINUX
655 case VERR_NO_MEMORY:
656 strText += g_QStrHintLinuxNoMemory;
657 break;
658# endif
659 case VERR_VM_DRIVER_NOT_ACCESSIBLE:
660 strText += QApplication::tr("Kernel driver not accessible");
661 break;
662 case VERR_VM_DRIVER_VERSION_MISMATCH:
663# ifdef RT_OS_LINUX
664 strText += g_QStrHintLinuxWrongDriverVersion;
665# else
666 strText += g_QStrHintOtherWrongDriverVersion;
667# endif
668 break;
669 default:
670 strText += QApplication::tr("Unknown error %2 during initialization of the Runtime").arg(rc);
671 break;
672 }
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: */
680 return 1;
681 }
682
683 /* Call to actual main function: */
684 return TrustedMain(argc, argv, envp);
685}
686
687#endif /* !VBOX_WITH_HARDENING || !VBOX_RUNTIME_UI */
688
689#ifdef VBOX_WITH_HARDENING
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 */
702extern "C" DECLEXPORT(void) TrustedError(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, va_list va)
703{
704# ifdef VBOX_WS_MAC
705 /* Hide setuid root from AppKit: */
706 HideSetUidRootFromAppKit();
707# endif /* VBOX_WS_MAC */
708
709 char szMsgBuf[_16K];
710
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 */
715 int argc = 0;
716 char *argv[2] = { NULL, NULL };
717 QApplication a(argc, &argv[0]);
718
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;
731
732 /*
733 * Format the error message. Take whatever comes after a double new line as
734 * something better off in the details section.
735 */
736 RTStrPrintfV(szMsgBuf, sizeof(szMsgBuf), pszMsgFmt, va);
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
751 QString strText = QApplication::tr("<html><b>%1 (rc=%2)</b><br/><br/>").arg(szMsgBuf).arg(rc);
752 strText.replace(QString("\n"), QString("<br>"));
753
754 /*
755 * Append possibly helpful hints to the error message.
756 */
757 switch (enmWhat)
758 {
759 case kSupInitOp_Driver:
760# ifdef RT_OS_LINUX
761 strText += g_QStrHintLinuxNoDriver;
762# else /* RT_OS_LINUX */
763 strText += g_QStrHintOtherNoDriver;
764# endif /* !RT_OS_LINUX */
765 break;
766 case kSupInitOp_IPRT:
767 case kSupInitOp_Misc:
768 if (rc == VERR_VM_DRIVER_VERSION_MISMATCH)
769# ifndef RT_OS_LINUX
770 strText += g_QStrHintOtherWrongDriverVersion;
771# else
772 strText += g_QStrHintLinuxWrongDriverVersion;
773 else if (rc == VERR_NO_MEMORY)
774 strText += g_QStrHintLinuxNoMemory;
775# endif
776 else
777 strText += g_QStrHintReinstall;
778 break;
779 case kSupInitOp_Integrity:
780 case kSupInitOp_RootCheck:
781 strText += g_QStrHintReinstall;
782 break;
783 default:
784 /* no hints here */
785 break;
786 }
787
788# ifdef VBOX_WS_X11
789 /* We have to to make sure that we display the error-message
790 * after the parent displayed its own message. */
791 sleep(2);
792# endif /* VBOX_WS_X11 */
793
794 /* Update strText with strDetails: */
795 if (!strDetails.isEmpty())
796 strText += QString("<br><br>%1").arg(strDetails);
797
798 /* Close the <html> scope: */
799 strText += "</html>";
800
801 /* Create and show the error message-box: */
802 QMessageBox::critical(0, QApplication::tr("VirtualBox - Error In %1").arg(pszWhere), strText);
803
804 qFatal("%s", strText.toUtf8().constData());
805}
806
807#endif /* VBOX_WITH_HARDENING */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use