VirtualBox

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

Last change on this file since 36308 was 35617, checked in by vboxsync, 14 years ago

Additions/x11/VBoxClient: daemonise later so that we get error messages if something goes wrong

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 9.6 KB
Line 
1/** @file
2 *
3 * VirtualBox Guest Service:
4 * Linux guest.
5 */
6
7/*
8 * Copyright (C) 2006-2010 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include <sys/types.h>
20#include <stdlib.h> /* For exit */
21#include <stdio.h>
22#include <string.h>
23#include <unistd.h>
24#include <errno.h>
25#include <signal.h>
26
27#include <X11/Xlib.h>
28
29#include <iprt/critsect.h>
30#include <iprt/env.h>
31#include <iprt/initterm.h>
32#include <iprt/path.h>
33#include <iprt/param.h>
34#include <iprt/stream.h>
35#include <iprt/string.h>
36#include <VBox/VBoxGuestLib.h>
37#include <VBox/log.h>
38
39#include "VBoxClient.h"
40
41#define TRACE RTPrintf("%s: %d\n", __PRETTY_FUNCTION__, __LINE__); LogRel(("%s: %d\n", __PRETTY_FUNCTION__, __LINE__))
42
43static int (*gpfnOldIOErrorHandler)(Display *) = NULL;
44
45/** Object representing the service we are running. This has to be global
46 * so that the cleanup routine can access it. */
47VBoxClient::Service *g_pService;
48/** The name of our pidfile. It is global for the benefit of the cleanup
49 * routine. */
50static char g_szPidFile[RTPATH_MAX];
51/** The file handle of our pidfile. It is global for the benefit of the
52 * cleanup routine. */
53static RTFILE g_hPidFile;
54/** Global critical section used to protect the clean-up routine, which can be
55 * called from different threads.
56 */
57RTCRITSECT g_critSect;
58
59/** Clean up if we get a signal or something. This is extern so that we
60 * can call it from other compilation units. */
61void VBoxClient::CleanUp()
62{
63 /* We never release this, as we end up with a call to exit(3) which is not
64 * async-safe. Until we fix this application properly, we should be sure
65 * never to exit from anywhere except from this method. */
66 int rc = RTCritSectEnter(&g_critSect);
67 if (RT_FAILURE(rc))
68 {
69 RTPrintf("VBoxClient: Failure while acquiring the global critical section, rc=%Rrc\n", rc);
70 abort();
71 }
72 if (g_pService)
73 g_pService->cleanup();
74 if (g_szPidFile[0] && g_hPidFile)
75 VbglR3ClosePidFile(g_szPidFile, g_hPidFile);
76 VbglR3Term();
77 exit(0);
78}
79
80/**
81 * A standard signal handler which cleans up and exits.
82 */
83void vboxClientSignalHandler(int cSignal)
84{
85 LogRel(("VBoxClient: terminated with signal %d\n", cSignal));
86 /** Disable seamless mode */
87 RTPrintf(("VBoxClient: terminating...\n"));
88 VBoxClient::CleanUp();
89}
90
91/**
92 * Xlib error handler for certain errors that we can't avoid.
93 */
94int vboxClientXLibErrorHandler(Display *pDisplay, XErrorEvent *pError)
95{
96 char errorText[1024];
97
98 XGetErrorText(pDisplay, pError->error_code, errorText, sizeof(errorText));
99 LogRelFlow(("VBoxClient: 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));
100 return 0; /* We should never reach this. */
101}
102
103/**
104 * Xlib error handler for fatal errors. This often means that the programme is still running
105 * when X exits.
106 */
107static int vboxClientXLibIOErrorHandler(Display *pDisplay)
108{
109 LogRel(("VBoxClient: 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"));
110 VBoxClient::CleanUp();
111 return 0; /* We should never reach this. */
112}
113
114/**
115 * Reset all standard termination signals to call our signal handler, which
116 * cleans up and exits.
117 */
118void vboxClientSetSignalHandlers(void)
119{
120 struct sigaction sigAction;
121
122 LogRelFlowFunc(("\n"));
123 sigAction.sa_handler = vboxClientSignalHandler;
124 sigemptyset(&sigAction.sa_mask);
125 sigAction.sa_flags = 0;
126 sigaction(SIGHUP, &sigAction, NULL);
127 sigaction(SIGINT, &sigAction, NULL);
128 sigaction(SIGQUIT, &sigAction, NULL);
129 sigaction(SIGPIPE, &sigAction, NULL);
130 sigaction(SIGALRM, &sigAction, NULL);
131 sigaction(SIGTERM, &sigAction, NULL);
132 sigaction(SIGUSR1, &sigAction, NULL);
133 sigaction(SIGUSR2, &sigAction, NULL);
134 LogRelFlowFunc(("returning\n"));
135}
136
137/**
138 * Print out a usage message and exit with success.
139 */
140void vboxClientUsage(const char *pcszFileName)
141{
142 RTPrintf("Usage: %s --clipboard|--display|--checkhostversion|--seamless [-d|--nodaemon]\n", pcszFileName);
143 RTPrintf("Start the VirtualBox X Window System guest services.\n\n");
144 RTPrintf("Options:\n");
145 RTPrintf(" --clipboard start the shared clipboard service\n");
146 RTPrintf(" --display start the display management service\n");
147# ifdef VBOX_WITH_GUEST_PROPS
148 RTPrintf(" --checkhostversion start the host version notifier service\n");
149# endif
150 RTPrintf(" --seamless start the seamless windows service\n");
151 RTPrintf(" -d, --nodaemon continue running as a system service\n");
152 RTPrintf("\n");
153 exit(0);
154}
155
156/**
157 * The main loop for the VBoxClient daemon.
158 */
159int main(int argc, char *argv[])
160{
161 int rcClipboard, rc;
162 const char *pszFileName = RTPathFilename(argv[0]);
163 bool fDaemonise = true;
164 /* Have any fatal errors occurred yet? */
165 bool fSuccess = true;
166 /* Do we know which service we wish to run? */
167 bool fHaveService = false;
168
169 if (NULL == pszFileName)
170 pszFileName = "VBoxClient";
171
172 /* Initialise our runtime before all else. */
173 rc = RTR3Init();
174 if (RT_FAILURE(rc))
175 {
176 /* Of course, this should never happen. */
177 RTPrintf("%s: Failed to initialise the run-time library, rc=%Rrc\n", pszFileName, rc);
178 exit(1);
179 }
180
181 /* Initialise our global clean-up critical section */
182 rc = RTCritSectInit(&g_critSect);
183 if (RT_FAILURE(rc))
184 {
185 /* Of course, this should never happen. */
186 RTPrintf("%s: Failed to initialise the global critical section, rc=%Rrc\n", pszFileName, rc);
187 exit(1);
188 }
189
190 /* Parse our option(s) */
191 /** @todo Use RTGetOpt() if the arguments become more complex. */
192 for (int i = 1; i < argc; ++i)
193 {
194 if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--nodaemon"))
195 fDaemonise = false;
196 else if (!strcmp(argv[i], "--clipboard"))
197 {
198 if (g_pService == NULL)
199 g_pService = VBoxClient::GetClipboardService();
200 else
201 fSuccess = false;
202 }
203 else if (!strcmp(argv[i], "--display"))
204 {
205 if (g_pService == NULL)
206 g_pService = VBoxClient::GetDisplayService();
207 else
208 fSuccess = false;
209 }
210 else if (!strcmp(argv[i], "--seamless"))
211 {
212 if (g_pService == NULL)
213 g_pService = VBoxClient::GetSeamlessService();
214 else
215 fSuccess = false;
216 }
217 else if (!strcmp(argv[i], "--checkhostversion"))
218 {
219 if (g_pService == NULL)
220 g_pService = VBoxClient::GetHostVersionService();
221 else
222 fSuccess = false;
223 }
224 else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
225 {
226 vboxClientUsage(pszFileName);
227 exit(0);
228 }
229 else
230 {
231 RTPrintf("%s: unrecognized option `%s'\n", pszFileName, argv[i]);
232 RTPrintf("Try `%s --help' for more information\n", pszFileName);
233 exit(1);
234 }
235 }
236 if (!fSuccess || !g_pService)
237 {
238 vboxClientUsage(pszFileName);
239 exit(1);
240 }
241 /* Get the path for the pidfiles */
242 rc = RTPathUserHome(g_szPidFile, sizeof(g_szPidFile));
243 if (RT_FAILURE(rc))
244 {
245 RTPrintf("VBoxClient: failed to get home directory, rc=%Rrc. Exiting.\n", rc);
246 LogRel(("VBoxClient: failed to get home directory, rc=%Rrc. Exiting.\n", rc));
247 return 1;
248 }
249 rc = RTPathAppend(g_szPidFile, sizeof(g_szPidFile), g_pService->getPidFilePath());
250 if (RT_FAILURE(rc))
251 {
252 RTPrintf("VBoxClient: RTPathAppend failed with rc=%Rrc. Exiting.\n", rc);
253 LogRel(("VBoxClient: RTPathAppend failed with rc=%Rrc. Exiting.\n", rc));
254 return 1;
255 }
256
257 /* Initialise the guest library. */
258 if (RT_FAILURE(VbglR3InitUser()))
259 {
260 RTPrintf("Failed to connect to the VirtualBox kernel service\n");
261 LogRel(("Failed to connect to the VirtualBox kernel service\n"));
262 return 1;
263 }
264 if (g_szPidFile[0] && RT_FAILURE(VbglR3PidFile(g_szPidFile, &g_hPidFile)))
265 {
266 RTPrintf("Failed to create a pidfile. Exiting.\n");
267 LogRel(("Failed to create a pidfile. Exiting.\n"));
268 VbglR3Term();
269 return 1;
270 }
271 if (fDaemonise)
272 {
273 rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */);
274 if (RT_FAILURE(rc))
275 {
276 RTPrintf("VBoxClient: failed to daemonize. Exiting.\n");
277 LogRel(("VBoxClient: failed to daemonize. Exiting.\n"));
278# ifdef DEBUG
279 RTPrintf("Error %Rrc\n", rc);
280# endif
281 return 1;
282 }
283 }
284 /* Set signal handlers to clean up on exit. */
285 vboxClientSetSignalHandlers();
286 /* Set an X11 error handler, so that we don't die when we get unavoidable errors. */
287 XSetErrorHandler(vboxClientXLibErrorHandler);
288 /* Set an X11 I/O error handler, so that we can shutdown properly on fatal errors. */
289 XSetIOErrorHandler(vboxClientXLibIOErrorHandler);
290 g_pService->run(fDaemonise);
291 VBoxClient::CleanUp();
292 return 1; /* We should never get here. */
293}
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