VirtualBox

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

Last change on this file since 9412 was 8695, checked in by vboxsync, 17 years ago

X11 Additions: improved termination of VBoxClient

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