VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/xclient/main.cpp@ 16774

Last change on this file since 16774 was 11822, checked in by vboxsync, 16 years ago

IPRT: RTR3Init cleanup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.3 KB
Line 
1/** @file
2 *
3 * VirtualBox Guest Service:
4 * Linux guest.
5 */
6
7/*
8 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#include <VBox/VBoxGuest.h>
24#include <VBox/log.h>
25#include <iprt/initterm.h>
26#include <iprt/path.h>
27#include <iprt/stream.h>
28
29#include <sys/types.h>
30#include <stdlib.h> /* For exit */
31#include <stdio.h>
32#include <unistd.h>
33#include <errno.h>
34#include <signal.h>
35
36#include <X11/Xlib.h>
37#include <X11/Intrinsic.h>
38
39#include "clipboard.h"
40
41#ifdef DYNAMIC_RESIZE
42# include "displaychange.h"
43# ifdef SEAMLESS_GUEST
44# include "seamless.h"
45# endif
46#endif
47
48#define TRACE RTPrintf("%s: %d\n", __PRETTY_FUNCTION__, __LINE__); Log(("%s: %d\n", __PRETTY_FUNCTION__, __LINE__))
49
50static int (*gpfnOldIOErrorHandler)(Display *) = NULL;
51
52/* Make these global so that the destructors are called if we make an "emergency exit",
53 i.e. a (handled) signal or an X11 error. */
54#ifdef DYNAMIC_RESIZE
55VBoxGuestDisplayChangeMonitor gDisplayChange;
56# ifdef SEAMLESS_GUEST
57 /** Our instance of the seamless class. This only makes sense if dynamic resizing
58 is enabled. */
59 VBoxGuestSeamless gSeamless;
60# endif /* SEAMLESS_GUEST defined */
61#endif /* DYNAMIC_RESIZE */
62#ifdef VBOX_X11_CLIPBOARD
63 VBoxGuestClipboard gClipboard;
64#endif
65
66/**
67 * Drop the programmes privileges to the caller's.
68 * @returns IPRT status code
69 * @todo move this into the R3 guest library
70 */
71int vboxClientDropPrivileges(void)
72{
73 int rc = VINF_SUCCESS;
74 int rcSystem, rcErrno;
75
76 LogFlowFunc(("\n"));
77#ifdef _POSIX_SAVED_IDS
78 rcSystem = setuid(getuid());
79#else
80 rcSystem = setreuid(-1, getuid());
81#endif
82 if (rcSystem < 0)
83 {
84 rcErrno = errno;
85 rc = RTErrConvertFromErrno(rcErrno);
86 LogRel(("VBoxClient: failed to drop privileges, error %Rrc.\n", rc));
87 }
88 LogFlowFunc(("returning %Rrc\n", rc));
89 return rc;
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 if (pError->error_code == BadAtom)
100 {
101 /* This can be triggered in debug builds if a guest application passes a bad atom
102 in its list of supported clipboard formats. As such it is harmless. */
103 Log(("VBoxClient: ignoring BadAtom error and returning\n"));
104 return 0;
105 }
106 if (pError->error_code == BadWindow)
107 {
108 /* This can be triggered if a guest application destroys a window before we notice. */
109 Log(("VBoxClient: ignoring BadWindow error and returning\n"));
110 return 0;
111 }
112 XGetErrorText(pDisplay, pError->error_code, errorText, sizeof(errorText));
113 LogRel(("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));
114 /** Disable seamless mode */
115 VbglR3SeamlessSetCap(false);
116 VbglR3Term();
117 exit(1);
118}
119
120/**
121 * Xlib error handler for fatal errors. This often means that the programme is still running
122 * when X exits.
123 */
124int vboxClientXLibIOErrorHandler(Display *pDisplay)
125{
126 Log(("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"));
127 /** Disable seamless mode */
128 VbglR3SeamlessSetCap(false);
129 VbglR3Term();
130 return gpfnOldIOErrorHandler(pDisplay);
131}
132
133/**
134 * A standard signal handler which cleans up and exits. Our global static objects will
135 * be cleaned up properly as we exit using "exit".
136 */
137void vboxClientSignalHandler(int cSignal)
138{
139 Log(("VBoxClient: terminated with signal %d\n", cSignal));
140 /** Disable seamless mode */
141 VbglR3SeamlessSetCap(false);
142 RTPrintf(("VBoxClient: terminating...\n"));
143 /* don't call VbglR3Term() here otherwise the /dev/vboxadd filehandle is closed */
144 /* Our pause() call will now return and exit. */
145}
146
147/**
148 * Reset all standard termination signals to call our signal handler, which cleans up
149 * and exits.
150 */
151void vboxClientSetSignalHandlers(void)
152{
153 struct sigaction sigAction;
154
155 LogFlowFunc(("\n"));
156 sigAction.sa_handler = vboxClientSignalHandler;
157 sigemptyset(&sigAction.sa_mask);
158 sigAction.sa_flags = 0;
159 sigaction(SIGHUP, &sigAction, NULL);
160 sigaction(SIGINT, &sigAction, NULL);
161 sigaction(SIGQUIT, &sigAction, NULL);
162 sigaction(SIGABRT, &sigAction, NULL);
163 sigaction(SIGPIPE, &sigAction, NULL);
164 sigaction(SIGALRM, &sigAction, NULL);
165 sigaction(SIGTERM, &sigAction, NULL);
166 sigaction(SIGUSR1, &sigAction, NULL);
167 sigaction(SIGUSR2, &sigAction, NULL);
168 LogFlowFunc(("returning\n"));
169}
170
171/**
172 * Print out a usage message and exit with success.
173 */
174void vboxClientUsage(const char *pcszFileName)
175{
176 RTPrintf("Usage: %s [-d|--nodaemon]\n", pcszFileName);
177 RTPrintf("Start the VirtualBox X Window System guest services.\n\n");
178 RTPrintf("Options:\n");
179 RTPrintf(" -d, --nodaemon do not lower privileges and continue running as a system\n");
180 RTPrintf(" service\n");
181 RTPrintf("\n");
182 exit(0);
183}
184
185/**
186 * The main loop for the VBoxClient daemon.
187 */
188int main(int argc, char *argv[])
189{
190 int rcClipboard, rc = VINF_SUCCESS;
191 const char *pszFileName = RTPathFilename(argv[0]);
192 bool fDaemonise = true;
193
194 if (NULL == pszFileName)
195 pszFileName = "VBoxClient";
196
197 /* Initialise our runtime before all else. */
198 RTR3Init();
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], "-h") || !strcmp(argv[i], "--help"))
207 {
208 vboxClientUsage(pszFileName);
209 exit(0);
210 }
211 else
212 {
213 RTPrintf("%s: unrecognized option `%s'\n", pszFileName, argv[i]);
214 RTPrintf("Try `%s --help' for more information\n", pszFileName);
215 exit(1);
216 }
217 }
218 if (fDaemonise)
219 {
220 rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */,
221 NULL);
222 if (RT_FAILURE(rc))
223 {
224 RTPrintf("VBoxClient: failed to daemonize. exiting.\n");
225#ifdef DEBUG
226 RTPrintf("Error %Rrc\n", rc);
227#endif
228 return 1;
229 }
230 }
231 /* Initialise the guest library. */
232 if (RT_FAILURE(VbglR3Init()))
233 {
234 RTPrintf("Failed to connect to the VirtualBox kernel service\n");
235 return 1;
236 }
237 if (fDaemonise && RT_FAILURE(vboxClientDropPrivileges()))
238 return 1;
239 LogRel(("VBoxClient: starting...\n"));
240 /* Initialise threading in X11 and in Xt. */
241 if (!XInitThreads() || !XtToolkitThreadInitialize())
242 {
243 LogRel(("VBoxClient: error initialising threads in X11, exiting.\n"));
244 return 1;
245 }
246 /* Set an X11 error handler, so that we don't die when we get unavoidable errors. */
247 XSetErrorHandler(vboxClientXLibErrorHandler);
248 /* Set an X11 I/O error handler, so that we can shutdown properly on fatal errors. */
249 gpfnOldIOErrorHandler = XSetIOErrorHandler(vboxClientXLibIOErrorHandler);
250 vboxClientSetSignalHandlers();
251 try
252 {
253#ifdef VBOX_X11_CLIPBOARD
254 /* Connect to the host clipboard. */
255 LogRel(("VBoxClient: starting clipboard Guest Additions...\n"));
256 rcClipboard = gClipboard.init();
257 if (RT_FAILURE(rcClipboard))
258 {
259 LogRel(("VBoxClient: vboxClipboardConnect failed with rc = %Rrc\n", rcClipboard));
260 }
261#endif /* VBOX_X11_CLIPBOARD defined */
262#ifdef DYNAMIC_RESIZE
263 LogRel(("VBoxClient: starting dynamic guest resizing...\n"));
264 rc = gDisplayChange.init();
265 if (RT_FAILURE(rc))
266 {
267 LogRel(("VBoxClient: failed to start dynamic guest resizing, rc = %Rrc\n", rc));
268 }
269# ifdef SEAMLESS_GUEST
270 if (RT_SUCCESS(rc))
271 {
272 LogRel(("VBoxClient: starting seamless Guest Additions...\n"));
273 rc = gSeamless.init();
274 if (RT_FAILURE(rc))
275 {
276 LogRel(("VBoxClient: failed to start seamless Additions, rc = %Rrc\n", rc));
277 }
278 }
279# endif /* SEAMLESS_GUEST defined */
280#endif /* DYNAMIC_RESIZE defined */
281 }
282 catch (std::exception e)
283 {
284 LogRel(("VBoxClient: failed to initialise Guest Additions - caught exception: %s\n", e.what()));
285 rc = VERR_UNRESOLVED_ERROR;
286 }
287 catch (...)
288 {
289 LogRel(("VBoxClient: failed to initialise Guest Additions - caught unknown exception.\n"));
290 rc = VERR_UNRESOLVED_ERROR;
291 }
292 LogRel(("VBoxClient: sleeping...\n"));
293 pause();
294 LogRel(("VBoxClient: exiting...\n"));
295 try
296 {
297 /* r=frank: Why all these 2s delays? What are we waiting for? */
298#ifdef DYNAMIC_RESIZE
299# ifdef SEAMLESS_GUEST
300 LogRel(("VBoxClient: shutting down seamless Guest Additions...\n"));
301 gSeamless.uninit(2000);
302# endif /* SEAMLESS_GUEST defined */
303 LogRel(("VBoxClient: shutting down dynamic guest resizing...\n"));
304 gDisplayChange.uninit(2000);
305#endif /* DYNAMIC_RESIZE defined */
306#ifdef VBOX_X11_CLIPBOARD
307 /* Connect to the host clipboard. */
308 LogRel(("VBoxClient: shutting down clipboard Guest Additions...\n"));
309 gClipboard.uninit(2000);
310#endif /* VBOX_X11_CLIPBOARD defined */
311 }
312 catch (std::exception e)
313 {
314 LogRel(("VBoxClient: failed to shut down Guest Additions - caught exception: %s\n", e.what()));
315 rc = VERR_UNRESOLVED_ERROR;
316 }
317 catch (...)
318 {
319 LogRel(("VBoxClient: failed to shut down Guest Additions - caught unknown exception.\n"));
320 rc = VERR_UNRESOLVED_ERROR;
321 }
322 VbglR3Term();
323 return RT_SUCCESS(rc) ? 0 : 1;
324}
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