VirtualBox

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

Last change on this file since 41328 was 39454, checked in by vboxsync, 13 years ago

Additions-X11: initial DnD support

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.0 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/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 /* Initialise our runtime before all else. */
174 int rc = RTR3InitExe(argc, &argv, 0);
175 if (RT_FAILURE(rc))
176 return RTMsgInitFailure(rc);
177
178 int rcClipboard;
179 const char *pszFileName = RTPathFilename(argv[0]);
180 bool fDaemonise = true;
181 /* Have any fatal errors occurred yet? */
182 bool fSuccess = true;
183 /* Do we know which service we wish to run? */
184 bool fHaveService = false;
185
186 if (NULL == pszFileName)
187 pszFileName = "VBoxClient";
188
189 /* Initialise our global clean-up critical section */
190 rc = RTCritSectInit(&g_critSect);
191 if (RT_FAILURE(rc))
192 {
193 /* Of course, this should never happen. */
194 RTPrintf("%s: Failed to initialise the global critical section, rc=%Rrc\n", pszFileName, rc);
195 return 1;
196 }
197
198 /* Parse our option(s) */
199 /** @todo Use RTGetOpt() if the arguments become more complex. */
200 for (int i = 1; i < argc; ++i)
201 {
202 if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--nodaemon"))
203 fDaemonise = false;
204 else if (!strcmp(argv[i], "--clipboard"))
205 {
206 if (g_pService == NULL)
207 g_pService = VBoxClient::GetClipboardService();
208 else
209 fSuccess = false;
210 }
211 else if (!strcmp(argv[i], "--display"))
212 {
213 if (g_pService == NULL)
214 g_pService = VBoxClient::GetDisplayService();
215 else
216 fSuccess = false;
217 }
218 else if (!strcmp(argv[i], "--seamless"))
219 {
220 if (g_pService == NULL)
221 g_pService = VBoxClient::GetSeamlessService();
222 else
223 fSuccess = false;
224 }
225 else if (!strcmp(argv[i], "--checkhostversion"))
226 {
227 if (g_pService == NULL)
228 g_pService = VBoxClient::GetHostVersionService();
229 else
230 fSuccess = false;
231 }
232#ifdef VBOX_WITH_DRAG_AND_DROP
233 else if (!strcmp(argv[i], "--draganddrop"))
234 {
235 if (g_pService == NULL)
236 g_pService = VBoxClient::GetDragAndDropService();
237 else
238 fSuccess = false;
239 }
240#endif /* VBOX_WITH_DRAG_AND_DROP */
241 else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
242 {
243 vboxClientUsage(pszFileName);
244 return 0;
245 }
246 else
247 {
248 RTPrintf("%s: unrecognized option `%s'\n", pszFileName, argv[i]);
249 RTPrintf("Try `%s --help' for more information\n", pszFileName);
250 return 1;
251 }
252 }
253 if (!fSuccess || !g_pService)
254 {
255 vboxClientUsage(pszFileName);
256 return 1;
257 }
258 /* Get the path for the pidfiles */
259 rc = RTPathUserHome(g_szPidFile, sizeof(g_szPidFile));
260 if (RT_FAILURE(rc))
261 {
262 RTPrintf("VBoxClient: failed to get home directory, rc=%Rrc. Exiting.\n", rc);
263 LogRel(("VBoxClient: failed to get home directory, rc=%Rrc. Exiting.\n", rc));
264 return 1;
265 }
266 rc = RTPathAppend(g_szPidFile, sizeof(g_szPidFile), g_pService->getPidFilePath());
267 if (RT_FAILURE(rc))
268 {
269 RTPrintf("VBoxClient: RTPathAppend failed with rc=%Rrc. Exiting.\n", rc);
270 LogRel(("VBoxClient: RTPathAppend failed with rc=%Rrc. Exiting.\n", rc));
271 return 1;
272 }
273
274 /* Initialise the guest library. */
275 if (RT_FAILURE(VbglR3InitUser()))
276 {
277 RTPrintf("Failed to connect to the VirtualBox kernel service\n");
278 LogRel(("Failed to connect to the VirtualBox kernel service\n"));
279 return 1;
280 }
281 if (fDaemonise)
282 {
283 rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */);
284 if (RT_FAILURE(rc))
285 {
286 RTPrintf("VBoxClient: failed to daemonize. Exiting.\n");
287 LogRel(("VBoxClient: failed to daemonize. Exiting.\n"));
288# ifdef DEBUG
289 RTPrintf("Error %Rrc\n", rc);
290# endif
291 return 1;
292 }
293 }
294 if (g_szPidFile[0] && RT_FAILURE(VbglR3PidFile(g_szPidFile, &g_hPidFile)))
295 {
296 RTPrintf("Failed to create a pidfile. Exiting.\n");
297 LogRel(("Failed to create a pidfile. Exiting.\n"));
298 VbglR3Term();
299 return 1;
300 }
301 /* Set signal handlers to clean up on exit. */
302 vboxClientSetSignalHandlers();
303 /* Set an X11 error handler, so that we don't die when we get unavoidable errors. */
304 XSetErrorHandler(vboxClientXLibErrorHandler);
305 /* Set an X11 I/O error handler, so that we can shutdown properly on fatal errors. */
306 XSetIOErrorHandler(vboxClientXLibIOErrorHandler);
307 g_pService->run(fDaemonise);
308 VBoxClient::CleanUp();
309 return 1; /* We should never get here. */
310}
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