VirtualBox

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

Last change on this file since 83224 was 83218, checked in by vboxsync, 5 years ago

bugref:9637. removing an obsolete VBoxClient service.

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