VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/VBoxClient/main.cpp@ 82972

Last change on this file since 82972 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 24.5 KB
Line 
1/* $Id: main.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * VirtualBox Guest Additions - X11 Client.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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 <sys/types.h>
23#include <sys/wait.h>
24#include <stdlib.h> /* For exit */
25#include <stdio.h>
26#include <string.h>
27#include <unistd.h>
28#include <errno.h>
29#include <poll.h>
30#include <signal.h>
31
32#include <X11/Xlib.h>
33#include <X11/Xatom.h>
34
35#include <package-generated.h>
36#include "product-generated.h"
37
38#include <iprt/buildconfig.h>
39#include <iprt/critsect.h>
40#include <iprt/env.h>
41#include <iprt/file.h>
42#include <iprt/getopt.h>
43#include <iprt/initterm.h>
44#include <iprt/message.h>
45#include <iprt/path.h>
46#include <iprt/param.h>
47#include <iprt/process.h>
48#include <iprt/stream.h>
49#include <iprt/string.h>
50#include <iprt/system.h>
51#include <iprt/types.h>
52#include <VBox/VBoxGuestLib.h>
53#include <VBox/err.h>
54#include <VBox/log.h>
55
56#include "VBoxClient.h"
57
58
59/*********************************************************************************************************************************
60* Defines *
61*********************************************************************************************************************************/
62#define VBOXCLIENT_OPT_NORESPAWN 950
63
64#define VBOXCLIENT_OPT_SERVICES 980
65#define VBOXCLIENT_OPT_CHECKHOSTVERSION VBOXCLIENT_OPT_SERVICES
66#define VBOXCLIENT_OPT_CLIPBOARD VBOXCLIENT_OPT_SERVICES + 1
67#define VBOXCLIENT_OPT_DISPLAY VBOXCLIENT_OPT_SERVICES + 2
68#define VBOXCLIENT_OPT_DRAGANDDROP VBOXCLIENT_OPT_SERVICES + 3
69#define VBOXCLIENT_OPT_SEAMLESS VBOXCLIENT_OPT_SERVICES + 4
70#define VBOXCLIENT_OPT_VMSVGA VBOXCLIENT_OPT_SERVICES + 5
71#define VBOXCLIENT_OPT_VMSVGA_X11 VBOXCLIENT_OPT_SERVICES + 6
72
73
74/*********************************************************************************************************************************
75* Global Variables *
76*********************************************************************************************************************************/
77/*static int (*gpfnOldIOErrorHandler)(Display *) = NULL; - unused */
78
79/** Object representing the service we are running. This has to be global
80 * so that the cleanup routine can access it. */
81struct VBCLSERVICE **g_pService;
82/** The name of our pidfile. It is global for the benefit of the cleanup
83 * routine. */
84static char g_szPidFile[RTPATH_MAX] = "";
85/** The file handle of our pidfile. It is global for the benefit of the
86 * cleanup routine. */
87static RTFILE g_hPidFile;
88/** Global critical section held during the clean-up routine (to prevent it
89 * being called on multiple threads at once) or things which may not happen
90 * during clean-up (e.g. pausing and resuming the service).
91 */
92static RTCRITSECT g_critSect;
93/** Counter of how often our daemon has been respawned. */
94static unsigned g_cRespawn = 0;
95/** Logging verbosity level. */
96static unsigned g_cVerbosity = 0;
97static char g_szLogFile[RTPATH_MAX + 128] = "";
98/** Logging parameters. */
99/** @todo Make this configurable later. */
100static PRTLOGGER g_pLoggerRelease = NULL;
101static uint32_t g_cHistory = 10; /* Enable log rotation, 10 files. */
102static uint32_t g_uHistoryFileTime = RT_SEC_1DAY; /* Max 1 day per file. */
103static uint64_t g_uHistoryFileSize = 100 * _1M; /* Max 100MB per file. */
104
105/**
106 * Notifies the desktop environment with a message.
107 *
108 * @param pszMessage Message to notify desktop environment with.
109 */
110int vbclLogNotify(const char *pszMessage)
111{
112 AssertPtrReturn(pszMessage, VERR_INVALID_POINTER);
113
114 int rc = VINF_SUCCESS;
115
116 if (g_cRespawn == 0)
117 {
118 char *pszCommand = RTStrAPrintf2("notify-send \"VBoxClient: %s\"", pszMessage);
119 if (pszCommand)
120 {
121 int status = system(pszCommand);
122
123 RTStrFree(pszCommand);
124
125 if (WEXITSTATUS(status) != 0) /* Utility or extension not available. */
126 {
127 pszCommand = RTStrAPrintf2("xmessage -buttons OK:0 -center \"VBoxClient: %s\"",
128 pszMessage);
129 if (pszCommand)
130 {
131 status = system(pszCommand);
132 if (WEXITSTATUS(status) != 0) /* Utility or extension not available. */
133 {
134 RTPrintf("VBoxClient: %s", pszMessage);
135 }
136
137 RTStrFree(pszCommand);
138 }
139 else
140 rc = VERR_NO_MEMORY;
141 }
142 }
143 else
144 rc = VERR_NO_MEMORY;
145 }
146
147 return rc;
148}
149
150/**
151 * Logs a fatal error, notifies the desktop environment via a message and
152 * exits the application immediately.
153 *
154 * @param pszFormat Format string to log.
155 * @param ... Variable arguments for format string. Optional.
156 */
157void VBClLogFatalError(const char *pszFormat, ...)
158{
159 va_list args;
160 va_start(args, pszFormat);
161 char *psz = NULL;
162 RTStrAPrintfV(&psz, pszFormat, args);
163 va_end(args);
164
165 AssertPtr(psz);
166 LogFlowFunc(("%s", psz));
167 LogRel(("%s", psz));
168
169 vbclLogNotify(psz);
170
171 RTStrFree(psz);
172}
173
174/**
175 * Logs an error message to the (release) logging instance.
176 *
177 * @param pszFormat Format string to log.
178 */
179void VBClLogError(const char *pszFormat, ...)
180{
181 va_list args;
182 va_start(args, pszFormat);
183 char *psz = NULL;
184 RTStrAPrintfV(&psz, pszFormat, args);
185 va_end(args);
186
187 AssertPtr(psz);
188 LogFlowFunc(("%s", psz));
189 LogRel(("%s", psz));
190
191 RTStrFree(psz);
192}
193
194/**
195 * Logs an info message to the (release) logging instance.
196 *
197 * @param pszFormat Format string to log.
198 */
199void VBClLogInfo(const char *pszFormat, ...)
200{
201 va_list args;
202 va_start(args, pszFormat);
203 char *psz = NULL;
204 RTStrAPrintfV(&psz, pszFormat, args);
205 va_end(args);
206
207 AssertPtr(psz);
208 LogFlowFunc(("%s", psz));
209 LogRel(("%s", psz));
210
211 RTStrFree(psz);
212}
213
214/**
215 * @callback_method_impl{FNRTLOGPHASE, Release logger callback}
216 */
217static DECLCALLBACK(void) vbClLogHeaderFooter(PRTLOGGER pLoggerRelease, RTLOGPHASE enmPhase, PFNRTLOGPHASEMSG pfnLog)
218{
219 /* Some introductory information. */
220 static RTTIMESPEC s_TimeSpec;
221 char szTmp[256];
222 if (enmPhase == RTLOGPHASE_BEGIN)
223 RTTimeNow(&s_TimeSpec);
224 RTTimeSpecToString(&s_TimeSpec, szTmp, sizeof(szTmp));
225
226 switch (enmPhase)
227 {
228 case RTLOGPHASE_BEGIN:
229 {
230 pfnLog(pLoggerRelease,
231 "VBoxClient %s r%s (verbosity: %u) %s (%s %s) release log\n"
232 "Log opened %s\n",
233 RTBldCfgVersion(), RTBldCfgRevisionStr(), g_cVerbosity, VBOX_BUILD_TARGET,
234 __DATE__, __TIME__, szTmp);
235
236 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp));
237 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
238 pfnLog(pLoggerRelease, "OS Product: %s\n", szTmp);
239 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp));
240 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
241 pfnLog(pLoggerRelease, "OS Release: %s\n", szTmp);
242 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp));
243 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
244 pfnLog(pLoggerRelease, "OS Version: %s\n", szTmp);
245 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szTmp, sizeof(szTmp));
246 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
247 pfnLog(pLoggerRelease, "OS Service Pack: %s\n", szTmp);
248
249 /* the package type is interesting for Linux distributions */
250 char szExecName[RTPATH_MAX];
251 char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName));
252 pfnLog(pLoggerRelease,
253 "Executable: %s\n"
254 "Process ID: %u\n"
255 "Package type: %s"
256#ifdef VBOX_OSE
257 " (OSE)"
258#endif
259 "\n",
260 pszExecName ? pszExecName : "unknown",
261 RTProcSelf(),
262 VBOX_PACKAGE_STRING);
263 break;
264 }
265
266 case RTLOGPHASE_PREROTATE:
267 pfnLog(pLoggerRelease, "Log rotated - Log started %s\n", szTmp);
268 break;
269
270 case RTLOGPHASE_POSTROTATE:
271 pfnLog(pLoggerRelease, "Log continuation - Log started %s\n", szTmp);
272 break;
273
274 case RTLOGPHASE_END:
275 pfnLog(pLoggerRelease, "End of log file - Log started %s\n", szTmp);
276 break;
277
278 default:
279 /* nothing */
280 break;
281 }
282}
283
284/**
285 * Creates the default release logger outputting to the specified file.
286 *
287 * Pass NULL to disabled logging.
288 *
289 * @return IPRT status code.
290 * @param pszLogFile Filename for log output. NULL disables custom handling.
291 */
292int VBClLogCreate(const char *pszLogFile)
293{
294 if (!pszLogFile)
295 return VINF_SUCCESS;
296
297 /* Create release logger (stdout + file). */
298 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
299 RTUINT fFlags = RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME;
300#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
301 fFlags |= RTLOGFLAGS_USECRLF;
302#endif
303 int rc = RTLogCreateEx(&g_pLoggerRelease, fFlags, "all",
304#ifdef DEBUG
305 "VBOXCLIENT_LOG",
306#else
307 "VBOXCLIENT_RELEASE_LOG",
308#endif
309 RT_ELEMENTS(s_apszGroups), s_apszGroups, UINT32_MAX /*cMaxEntriesPerGroup*/,
310 RTLOGDEST_STDOUT | RTLOGDEST_USER,
311 vbClLogHeaderFooter, g_cHistory, g_uHistoryFileSize, g_uHistoryFileTime,
312 NULL /*pErrInfo*/, "%s", pszLogFile ? pszLogFile : "");
313 if (RT_SUCCESS(rc))
314 {
315 /* register this logger as the release logger */
316 RTLogRelSetDefaultInstance(g_pLoggerRelease);
317
318 /* Explicitly flush the log in case of VBOXSERVICE_RELEASE_LOG=buffered. */
319 RTLogFlush(g_pLoggerRelease);
320 }
321
322 return rc;
323}
324
325/**
326 * Destroys the currently active logging instance.
327 */
328void VBClLogDestroy(void)
329{
330 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
331}
332
333/**
334 * Clean up if we get a signal or something.
335 *
336 * This is extern so that we can call it from other compilation units.
337 */
338void VBClCleanUp(bool fExit /*=true*/)
339{
340 /* We never release this, as we end up with a call to exit(3) which is not
341 * async-safe. Unless we fix this application properly, we should be sure
342 * never to exit from anywhere except from this method. */
343 int rc = RTCritSectEnter(&g_critSect);
344 if (RT_FAILURE(rc))
345 VBClLogFatalError("Failure while acquiring the global critical section, rc=%Rrc\n", rc);
346 if (g_pService)
347 (*g_pService)->cleanup(g_pService);
348 if (g_szPidFile[0] && g_hPidFile)
349 VbglR3ClosePidFile(g_szPidFile, g_hPidFile);
350
351 VBClLogDestroy();
352
353 if (fExit)
354 exit(RTEXITCODE_SUCCESS);
355}
356
357/**
358 * A standard signal handler which cleans up and exits.
359 */
360static void vboxClientSignalHandler(int cSignal)
361{
362 VBClLogInfo("Terminated with signal %d\n", cSignal);
363 /** Disable seamless mode */
364 VBClLogInfo("Terminating ...\n");
365 VBClCleanUp();
366}
367
368/**
369 * Xlib error handler for certain errors that we can't avoid.
370 */
371static int vboxClientXLibErrorHandler(Display *pDisplay, XErrorEvent *pError)
372{
373 char errorText[1024];
374
375 XGetErrorText(pDisplay, pError->error_code, errorText, sizeof(errorText));
376 VBClLogError("An X Window protocol error occurred: %s (error code %d). Request code: %d, minor code: %d, serial number: %d\n", errorText, pError->error_code, pError->request_code, pError->minor_code, pError->serial);
377 return 0;
378}
379
380/**
381 * Xlib error handler for fatal errors. This often means that the programme is still running
382 * when X exits.
383 */
384static int vboxClientXLibIOErrorHandler(Display *pDisplay)
385{
386 RT_NOREF1(pDisplay);
387 VBClLogError("A fatal guest X Window error occurred. This may just mean that the Window system was shut down while the client was still running\n");
388 VBClCleanUp();
389 return 0; /* We should never reach this. */
390}
391
392/**
393 * Reset all standard termination signals to call our signal handler, which
394 * cleans up and exits.
395 */
396static void vboxClientSetSignalHandlers(void)
397{
398 struct sigaction sigAction;
399
400 LogRelFlowFuncEnter();
401 sigAction.sa_handler = vboxClientSignalHandler;
402 sigemptyset(&sigAction.sa_mask);
403 sigAction.sa_flags = 0;
404 sigaction(SIGHUP, &sigAction, NULL);
405 sigaction(SIGINT, &sigAction, NULL);
406 sigaction(SIGQUIT, &sigAction, NULL);
407 sigaction(SIGPIPE, &sigAction, NULL);
408 sigaction(SIGALRM, &sigAction, NULL);
409 sigaction(SIGTERM, &sigAction, NULL);
410 sigaction(SIGUSR1, &sigAction, NULL);
411 sigaction(SIGUSR2, &sigAction, NULL);
412 LogRelFlowFuncLeave();
413}
414
415/**
416 * Print out a usage message and exit with success.
417 */
418static void vboxClientUsage(const char *pcszFileName)
419{
420 RTPrintf("Usage: %s "
421#ifdef VBOX_WITH_SHARED_CLIPBOARD
422 "--clipboard|"
423#endif
424#ifdef VBOX_WITH_DRAG_AND_DROP
425 "--draganddrop|"
426#endif
427 "--display|"
428# ifdef VBOX_WITH_GUEST_PROPS
429 "--checkhostversion|"
430#endif
431 "--seamless|"
432 "--vmsvga|--vmsvga-x11"
433 "[-d|--nodaemon]\n", pcszFileName);
434 RTPrintf("Starts the VirtualBox DRM/X Window System guest services.\n\n");
435 RTPrintf("Options:\n");
436#ifdef VBOX_WITH_SHARED_CLIPBOARD
437 RTPrintf(" --clipboard starts the shared clipboard service\n");
438#endif
439#ifdef VBOX_WITH_DRAG_AND_DROP
440 RTPrintf(" --draganddrop starts the drag and drop service\n");
441#endif
442 RTPrintf(" --display starts the display management service\n");
443#ifdef VBOX_WITH_GUEST_PROPS
444 RTPrintf(" --checkhostversion starts the host version notifier service\n");
445#endif
446 RTPrintf(" --seamless starts the seamless windows service\n");
447 RTPrintf(" --vmsvga starts VMSVGA dynamic resizing for DRM\n");
448 RTPrintf(" --vmsvga-x11 starts VMSVGA dynamic resizing for X11\n");
449 RTPrintf(" -f, --foreground run in the foreground (no daemonizing)\n");
450 RTPrintf(" -d, --nodaemon continues running as a system service\n");
451 RTPrintf(" -h, --help shows this help text\n");
452 RTPrintf(" -v, --verbose increases logging verbosity level\n");
453 RTPrintf(" -V, --version shows version information\n");
454 RTPrintf("\n");
455}
456
457/**
458 * Complains about seeing more than one service specification.
459 *
460 * @returns RTEXITCODE_SYNTAX.
461 */
462static int vbclSyntaxOnlyOneService(void)
463{
464 RTMsgError("More than one service specified! Only one, please.");
465 return RTEXITCODE_SYNTAX;
466}
467
468/**
469 * The main loop for the VBoxClient daemon.
470 * @todo Clean up for readability.
471 */
472int main(int argc, char *argv[])
473{
474 /* Initialise our runtime before all else. */
475 int rc = RTR3InitExe(argc, &argv, 0);
476 if (RT_FAILURE(rc))
477 return RTMsgInitFailure(rc);
478
479 /* This should never be called twice in one process - in fact one Display
480 * object should probably never be used from multiple threads anyway. */
481 if (!XInitThreads())
482 VBClLogFatalError("Failed to initialize X11 threads\n");
483
484 /* Get our file name for usage info and hints. */
485 const char *pcszFileName = RTPathFilename(argv[0]);
486 if (!pcszFileName)
487 pcszFileName = "VBoxClient";
488
489 /* Parse our option(s). */
490 static const RTGETOPTDEF s_aOptions[] =
491 {
492 { "--nodaemon", 'd', RTGETOPT_REQ_NOTHING },
493 { "--foreground", 'f', RTGETOPT_REQ_NOTHING },
494 { "--help", 'h', RTGETOPT_REQ_NOTHING },
495 { "--logfile", 'l', RTGETOPT_REQ_STRING },
496 { "--no-respawn", VBOXCLIENT_OPT_NORESPAWN, RTGETOPT_REQ_NOTHING },
497 { "--version", 'V', RTGETOPT_REQ_NOTHING },
498 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
499
500 /* Services */
501 { "--checkhostversion", VBOXCLIENT_OPT_CHECKHOSTVERSION, RTGETOPT_REQ_NOTHING },
502#ifdef VBOX_WITH_SHARED_CLIPBOARD
503 { "--clipboard", VBOXCLIENT_OPT_CLIPBOARD, RTGETOPT_REQ_NOTHING },
504#endif
505 { "--display", VBOXCLIENT_OPT_DISPLAY, RTGETOPT_REQ_NOTHING },
506#ifdef VBOX_WITH_DRAG_AND_DROP
507 { "--draganddrop", VBOXCLIENT_OPT_DRAGANDDROP, RTGETOPT_REQ_NOTHING },
508#endif
509 { "--seamless", VBOXCLIENT_OPT_SEAMLESS, RTGETOPT_REQ_NOTHING },
510 { "--vmsvga", VBOXCLIENT_OPT_VMSVGA, RTGETOPT_REQ_NOTHING },
511 { "--vmsvga-x11", VBOXCLIENT_OPT_VMSVGA_X11, RTGETOPT_REQ_NOTHING }
512 };
513
514 int ch;
515 RTGETOPTUNION ValueUnion;
516 RTGETOPTSTATE GetState;
517 rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
518 AssertRC(rc);
519
520 bool fDaemonise = true;
521 bool fRespawn = true;
522
523 while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
524 {
525 /* For options that require an argument, ValueUnion has received the value. */
526 switch (ch)
527 {
528 case 'd':
529 {
530 fDaemonise = false;
531 break;
532 }
533
534 case 'h':
535 {
536 vboxClientUsage(pcszFileName);
537 return RTEXITCODE_SUCCESS;
538 }
539
540 case 'f':
541 {
542 fDaemonise = false;
543 fRespawn = false;
544 break;
545 }
546
547 case 'l':
548 {
549 rc = RTStrCopy(g_szLogFile, sizeof(g_szLogFile), ValueUnion.psz);
550 if (RT_FAILURE(rc))
551 VBClLogFatalError("Unable to create log file path, rc=%Rrc\n", rc);
552 break;
553 }
554
555 case 'n':
556 {
557 fRespawn = false;
558 break;
559 }
560
561 case 'v':
562 {
563 g_cVerbosity++;
564 break;
565 }
566
567 case 'V':
568 {
569 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
570 return RTEXITCODE_SUCCESS;
571 }
572
573 /* Services */
574
575#ifdef VBOX_WITH_SHARED_CLIPBOARD
576 case VBOXCLIENT_OPT_CLIPBOARD:
577 {
578 if (g_pService)
579 return vbclSyntaxOnlyOneService();
580 g_pService = VBClGetClipboardService();
581 break;
582 }
583#endif
584 case VBOXCLIENT_OPT_DISPLAY:
585 {
586 if (g_pService)
587 return vbclSyntaxOnlyOneService();
588 g_pService = VBClGetDisplayService();
589 break;
590 }
591
592#ifdef VBOX_WITH_DRAG_AND_DROP
593 case VBOXCLIENT_OPT_DRAGANDDROP:
594 {
595 if (g_pService)
596 return vbclSyntaxOnlyOneService();
597 g_pService = VBClGetDragAndDropService();
598 break;
599 }
600#endif
601 case VBOXCLIENT_OPT_SEAMLESS:
602 {
603 if (g_pService)
604 return vbclSyntaxOnlyOneService();
605 g_pService = VBClGetSeamlessService();
606 break;
607 }
608
609 case VBOXCLIENT_OPT_VMSVGA:
610 {
611 if (g_pService)
612 return vbclSyntaxOnlyOneService();
613 g_pService = VBClDisplaySVGAService();
614 break;
615 }
616
617 case VBOXCLIENT_OPT_VMSVGA_X11:
618 {
619 if (g_pService)
620 return vbclSyntaxOnlyOneService();
621 g_pService = VBClDisplaySVGAX11Service();
622 break;
623 }
624
625 case VERR_GETOPT_UNKNOWN_OPTION:
626 {
627 RTMsgError("unrecognized option '%s'", ValueUnion.psz);
628 RTMsgInfo("Try '%s --help' for more information", pcszFileName);
629 return RTEXITCODE_SYNTAX;
630 }
631
632 case VINF_GETOPT_NOT_OPTION:
633 default:
634 break;
635
636 } /* switch */
637 } /* while RTGetOpt */
638
639 if (!g_pService)
640 {
641 RTMsgError("No service specified. Quitting because nothing to do!");
642 return RTEXITCODE_SYNTAX;
643 }
644
645 /* Initialize VbglR3 before we do anything else with the logger. */
646 rc = VbglR3InitUser();
647 if (RT_FAILURE(rc))
648 VBClLogFatalError("VbglR3InitUser failed: %Rrc", rc);
649
650 rc = VBClLogCreate(g_szLogFile[0] ? g_szLogFile : NULL);
651 if (RT_FAILURE(rc))
652 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log '%s', rc=%Rrc\n",
653 g_szLogFile[0] ? g_szLogFile : "<None>", rc);
654
655 LogRel(("Service: %s\n", (*g_pService)->getName()));
656
657 if (!fDaemonise)
658 {
659 /* If the user is running in "no daemon" mode, send critical logging to stdout as well. */
660 PRTLOGGER pReleaseLog = RTLogRelGetDefaultInstance();
661 if (pReleaseLog)
662 {
663 rc = RTLogDestinations(pReleaseLog, "stdout");
664 if (RT_FAILURE(rc))
665 return RTMsgErrorExitFailure("Failed to redivert error output, rc=%Rrc", rc);
666 }
667 }
668
669 rc = RTCritSectInit(&g_critSect);
670 if (RT_FAILURE(rc))
671 VBClLogFatalError("Initialising critical section failed: %Rrc\n", rc);
672 if ((*g_pService)->getPidFilePath)
673 {
674 rc = RTPathUserHome(g_szPidFile, sizeof(g_szPidFile));
675 if (RT_FAILURE(rc))
676 VBClLogFatalError("Getting home directory for PID file failed: %Rrc\n", rc);
677 rc = RTPathAppend(g_szPidFile, sizeof(g_szPidFile),
678 (*g_pService)->getPidFilePath());
679 if (RT_FAILURE(rc))
680 VBClLogFatalError("Creating PID file path failed: %Rrc\n", rc);
681 if (fDaemonise)
682 rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */, fRespawn, &g_cRespawn);
683 if (RT_FAILURE(rc))
684 VBClLogFatalError("Daemonizing failed: %Rrc\n", rc);
685 if (g_szPidFile[0])
686 rc = VbglR3PidFile(g_szPidFile, &g_hPidFile);
687 if (rc == VERR_FILE_LOCK_VIOLATION) /* Already running. */
688 return RTEXITCODE_SUCCESS;
689 if (RT_FAILURE(rc))
690 VBClLogFatalError("Creating PID file failed: %Rrc\n", rc);
691 }
692 /* Set signal handlers to clean up on exit. */
693 vboxClientSetSignalHandlers();
694#ifndef VBOXCLIENT_WITHOUT_X11
695 /* Set an X11 error handler, so that we don't die when we get unavoidable
696 * errors. */
697 XSetErrorHandler(vboxClientXLibErrorHandler);
698 /* Set an X11 I/O error handler, so that we can shutdown properly on
699 * fatal errors. */
700 XSetIOErrorHandler(vboxClientXLibIOErrorHandler);
701#endif
702 rc = (*g_pService)->init(g_pService);
703 if (RT_SUCCESS(rc))
704 {
705 rc = (*g_pService)->run(g_pService, fDaemonise);
706 if (RT_FAILURE(rc))
707 VBClLogError("Running service failed: %Rrc\n", rc);
708 }
709 else
710 {
711 /** @todo r=andy Should we return an appropriate exit code if the service failed to init?
712 * Must be tested carefully with our init scripts first. */
713 VBClLogError("Initializing service failed: %Rrc\n", rc);
714 }
715 VBClCleanUp(false /*fExit*/);
716 return RTEXITCODE_SUCCESS;
717}
718
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