VirtualBox

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

Last change on this file since 49762 was 48945, checked in by vboxsync, 11 years ago

Additions/x11: Whitespace and svn:keyword cleanups by scm.

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