VirtualBox

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

Last change on this file since 60352 was 58993, checked in by vboxsync, 9 years ago

bugref:8153: vboxvideo: ABI issues / software rendering on Linux guests: add a new service to VBoxClient to test whether accelerated 3D pass-through is currently available by trying to connect to the HGCM service and signalling success or failure in the process exit code. Add generic HGCM connect and disconnect functionality to VBoxGuestR3Lib to support this. Add the concept of non-daemon services to VBoxClient as we do not need to daemonise or create a pid-file for this quick test.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 11.1 KB
Line 
1/* $Id: main.cpp 58993 2015-12-04 16:26:50Z vboxsync $ */
2/** @file
3 *
4 * VirtualBox Guest Service:
5 * Linux guest.
6 */
7
8/*
9 * Copyright (C) 2006-2015 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#include <sys/types.h>
21#include <stdlib.h> /* For exit */
22#include <stdio.h>
23#include <string.h>
24#include <unistd.h>
25#include <errno.h>
26#include <poll.h>
27#include <signal.h>
28
29#include <X11/Xlib.h>
30#include <X11/Xatom.h>
31
32#include <iprt/buildconfig.h>
33#include <iprt/critsect.h>
34#include <iprt/env.h>
35#include <iprt/file.h>
36#include <iprt/initterm.h>
37#include <iprt/message.h>
38#include <iprt/path.h>
39#include <iprt/param.h>
40#include <iprt/stream.h>
41#include <iprt/string.h>
42#include <iprt/types.h>
43#include <VBox/VBoxGuestLib.h>
44#include <VBox/log.h>
45
46#include "VBoxClient.h"
47
48static int (*gpfnOldIOErrorHandler)(Display *) = NULL;
49
50/** Object representing the service we are running. This has to be global
51 * so that the cleanup routine can access it. */
52struct VBCLSERVICE **g_pService;
53/** The name of our pidfile. It is global for the benefit of the cleanup
54 * routine. */
55static char g_szPidFile[RTPATH_MAX] = "";
56/** The file handle of our pidfile. It is global for the benefit of the
57 * cleanup routine. */
58static RTFILE g_hPidFile;
59/** Global critical section held during the clean-up routine (to prevent it
60 * being called on multiple threads at once) or things which may not happen
61 * during clean-up (e.g. pausing and resuming the service).
62 */
63RTCRITSECT g_critSect;
64/** Counter of how often our deamon has been respawned. */
65unsigned cRespawn = 0;
66
67/** Exit with a fatal error. */
68void vbclFatalError(char *pszMessage)
69{
70 char *pszCommand;
71 if (pszMessage && cRespawn == 0)
72 {
73 pszCommand = RTStrAPrintf2("notify-send \"VBoxClient: %s\"", pszMessage);
74 if (pszCommand)
75 system(pszCommand);
76 }
77 _exit(1);
78}
79
80/** Clean up if we get a signal or something. This is extern so that we
81 * can call it from other compilation units. */
82void VBClCleanUp()
83{
84 /* We never release this, as we end up with a call to exit(3) which is not
85 * async-safe. Unless we fix this application properly, we should be sure
86 * never to exit from anywhere except from this method. */
87 int rc = RTCritSectEnter(&g_critSect);
88 if (RT_FAILURE(rc))
89 VBClFatalError(("VBoxClient: Failure while acquiring the global critical section, rc=%Rrc\n", rc));
90 if (g_pService)
91 (*g_pService)->cleanup(g_pService);
92 if (g_szPidFile[0] && g_hPidFile)
93 VbglR3ClosePidFile(g_szPidFile, g_hPidFile);
94 exit(0);
95}
96
97/**
98 * A standard signal handler which cleans up and exits.
99 */
100static void vboxClientSignalHandler(int cSignal)
101{
102 LogRel(("VBoxClient: terminated with signal %d\n", cSignal));
103 /** Disable seamless mode */
104 RTPrintf(("VBoxClient: terminating...\n"));
105 VBClCleanUp();
106}
107
108/**
109 * Xlib error handler for certain errors that we can't avoid.
110 */
111static int vboxClientXLibErrorHandler(Display *pDisplay, XErrorEvent *pError)
112{
113 char errorText[1024];
114
115 XGetErrorText(pDisplay, pError->error_code, errorText, sizeof(errorText));
116 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));
117 return 0;
118}
119
120/**
121 * Xlib error handler for fatal errors. This often means that the programme is still running
122 * when X exits.
123 */
124static int vboxClientXLibIOErrorHandler(Display *pDisplay)
125{
126 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"));
127 VBClCleanUp();
128 return 0; /* We should never reach this. */
129}
130
131/**
132 * Reset all standard termination signals to call our signal handler, which
133 * cleans up and exits.
134 */
135static void vboxClientSetSignalHandlers(void)
136{
137 struct sigaction sigAction;
138
139 LogRelFlowFunc(("\n"));
140 sigAction.sa_handler = vboxClientSignalHandler;
141 sigemptyset(&sigAction.sa_mask);
142 sigAction.sa_flags = 0;
143 sigaction(SIGHUP, &sigAction, NULL);
144 sigaction(SIGINT, &sigAction, NULL);
145 sigaction(SIGQUIT, &sigAction, NULL);
146 sigaction(SIGPIPE, &sigAction, NULL);
147 sigaction(SIGALRM, &sigAction, NULL);
148 sigaction(SIGTERM, &sigAction, NULL);
149 sigaction(SIGUSR1, &sigAction, NULL);
150 sigaction(SIGUSR2, &sigAction, NULL);
151 LogRelFlowFunc(("returning\n"));
152}
153
154/**
155 * Print out a usage message and exit with success.
156 */
157void vboxClientUsage(const char *pcszFileName)
158{
159 RTPrintf("Usage: %s --clipboard|"
160#ifdef VBOX_WITH_DRAG_AND_DROP
161 "--draganddrop|"
162#endif
163 "--display|"
164# ifdef VBOX_WITH_GUEST_PROPS
165 "--checkhostversion|"
166#endif
167 "--seamless|check3d [-d|--nodaemon]\n", pcszFileName);
168 RTPrintf("Starts the VirtualBox X Window System guest services.\n\n");
169 RTPrintf("Options:\n");
170 RTPrintf(" --clipboard starts the shared clipboard service\n");
171#ifdef VBOX_WITH_DRAG_AND_DROP
172 RTPrintf(" --draganddrop starts the drag and drop service\n");
173#endif
174 RTPrintf(" --display starts the display management service\n");
175#ifdef VBOX_WITH_GUEST_PROPS
176 RTPrintf(" --checkhostversion starts the host version notifier service\n");
177#endif
178 RTPrintf(" --check3d tests whether 3D pass-through is enabled\n");
179 RTPrintf(" --seamless starts the seamless windows service\n");
180 RTPrintf(" -d, --nodaemon continues running as a system service\n");
181 RTPrintf(" -h, --help shows this help text\n");
182 RTPrintf(" -V, --version shows version information\n");
183 RTPrintf("\n");
184 exit(0);
185}
186
187/**
188 * The main loop for the VBoxClient daemon.
189 * @todo Clean up for readability.
190 */
191int main(int argc, char *argv[])
192{
193 bool fDaemonise = true, fRespawn = true;
194 int rc;
195 const char *pcszFileName;
196
197 /* Initialise our runtime before all else. */
198 rc = RTR3InitExe(argc, &argv, 0);
199 if (RT_FAILURE(rc))
200 return RTMsgInitFailure(rc);
201 /* This should never be called twice in one process - in fact one Display
202 * object should probably never be used from multiple threads anyway. */
203 if (!XInitThreads())
204 VBClFatalError(("Failed to initialize X11 threads\n"));
205 /* Get our file name for error output. */
206 pcszFileName = RTPathFilename(argv[0]);
207 if (!pcszFileName)
208 pcszFileName = "VBoxClient";
209
210 /* Parse our option(s) */
211 /** @todo Use RTGetOpt() if the arguments become more complex. */
212 for (int i = 1; i < argc; ++i)
213 {
214 rc = VERR_INVALID_PARAMETER;
215 if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--nodaemon"))
216 {
217 /* If the user is running in "no daemon" mode anyway, send critical
218 * logging to stdout as well. */
219 PRTLOGGER pReleaseLog = RTLogRelGetDefaultInstance();
220 if (pReleaseLog)
221 rc = RTLogDestinations(pReleaseLog, "stdout");
222 if (pReleaseLog && RT_FAILURE(rc))
223 RTPrintf("%s: failed to redivert error output, rc=%Rrc\n",
224 pcszFileName, rc);
225 fDaemonise = false;
226 }
227 else if (!strcmp(argv[i], "--no-respawn"))
228 {
229 fRespawn = false;
230 }
231 else if (!strcmp(argv[i], "--clipboard"))
232 {
233 if (g_pService)
234 break;
235 g_pService = VBClGetClipboardService();
236 }
237 else if (!strcmp(argv[i], "--display"))
238 {
239 if (g_pService)
240 break;
241 g_pService = VBClGetDisplayService();
242 }
243 else if (!strcmp(argv[i], "--seamless"))
244 {
245 if (g_pService)
246 break;
247 g_pService = VBClGetSeamlessService();
248 }
249 else if (!strcmp(argv[i], "--checkhostversion"))
250 {
251 if (g_pService)
252 break;
253 g_pService = VBClGetHostVersionService();
254 }
255#ifdef VBOX_WITH_DRAG_AND_DROP
256 else if (!strcmp(argv[i], "--draganddrop"))
257 {
258 if (g_pService)
259 break;
260 g_pService = VBClGetDragAndDropService();
261 }
262#endif /* VBOX_WITH_DRAG_AND_DROP */
263 else if (!strcmp(argv[i], "--check3d"))
264 {
265 if (g_pService)
266 break;
267 g_pService = VBClCheck3DService();
268 }
269 else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
270 {
271 vboxClientUsage(pcszFileName);
272 return 0;
273 }
274 else if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version"))
275 {
276 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
277 return 0;
278 }
279 else
280 {
281 RTPrintf("%s: unrecognized option `%s'\n", pcszFileName, argv[i]);
282 RTPrintf("Try `%s --help' for more information\n", pcszFileName);
283 return 1;
284 }
285 rc = VINF_SUCCESS;
286 }
287 if (RT_FAILURE(rc) || !g_pService)
288 {
289 vboxClientUsage(pcszFileName);
290 return 1;
291 }
292
293 rc = RTCritSectInit(&g_critSect);
294 if (RT_FAILURE(rc))
295 VBClFatalError(("Initialising critical section: %Rrc\n", rc));
296 if ((*g_pService)->getPidFilePath)
297 {
298 rc = RTPathUserHome(g_szPidFile, sizeof(g_szPidFile));
299 if (RT_FAILURE(rc))
300 VBClFatalError(("Getting home directory for pid-file: %Rrc\n", rc));
301 rc = RTPathAppend(g_szPidFile, sizeof(g_szPidFile),
302 (*g_pService)->getPidFilePath());
303 if (RT_FAILURE(rc))
304 VBClFatalError(("Creating pid-file path: %Rrc\n", rc));
305 if (fDaemonise)
306 rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */, fRespawn, &cRespawn);
307 if (RT_FAILURE(rc))
308 VBClFatalError(("Daemonizing: %Rrc\n", rc));
309 if (g_szPidFile[0])
310 rc = VbglR3PidFile(g_szPidFile, &g_hPidFile);
311 if (rc == VERR_FILE_LOCK_VIOLATION) /* Already running. */
312 return 0;
313 if (RT_FAILURE(rc))
314 VBClFatalError(("Creating pid-file: %Rrc\n", rc));
315 }
316 /* Set signal handlers to clean up on exit. */
317 vboxClientSetSignalHandlers();
318#ifndef VBOXCLIENT_WITHOUT_X11
319 /* Set an X11 error handler, so that we don't die when we get unavoidable
320 * errors. */
321 XSetErrorHandler(vboxClientXLibErrorHandler);
322 /* Set an X11 I/O error handler, so that we can shutdown properly on
323 * fatal errors. */
324 XSetIOErrorHandler(vboxClientXLibIOErrorHandler);
325#endif
326 rc = (*g_pService)->init(g_pService);
327 if (RT_FAILURE(rc))
328 VBClFatalError(("Initialising service: %Rrc\n", rc));
329 rc = (*g_pService)->run(g_pService, fDaemonise);
330 if (RT_FAILURE(rc))
331 VBClFatalError(("Service main loop failed: %Rrc\n", rc));
332 VBClCleanUp();
333 return 0;
334}
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