main.cpp revision 3805ecaf5329df050ede4219a59098e756590e4d
b450d7a1747c5f4fb7c917a8ec1f9ce8440d7ffevboxsync * VirtualBox Guest Service:
b450d7a1747c5f4fb7c917a8ec1f9ce8440d7ffevboxsync * Linux guest.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Copyright (C) 2006-2011 Oracle Corporation
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * available from http://www.virtualbox.org. This file is free software;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * General Public License (GPL) as published by the Free Software
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int (*gpfnOldIOErrorHandler)(Display *) = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Object representing the service we are running. This has to be global
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * so that the cleanup routine can access it. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** The name of our pidfile. It is global for the benefit of the cleanup
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * routine. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** The file handle of our pidfile. It is global for the benefit of the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * cleanup routine. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Global critical section held during the clean-up routine (to prevent it
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * being called on multiple threads at once) or things which may not happen
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * during clean-up (e.g. pausing and resuming the service).
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Clean up if we get a signal or something. This is extern so that we
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * can call it from other compilation units. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We never release this, as we end up with a call to exit(3) which is not
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * async-safe. Unless we fix this application properly, we should be sure
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync * never to exit from anywhere except from this method. */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync LogRel(("VBoxClient: Failure while acquiring the global critical section, rc=%Rrc\n", rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * A standard signal handler which cleans up and exits.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(("VBoxClient: terminated with signal %d\n", cSignal));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Disable seamless mode */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Xlib error handler for certain errors that we can't avoid.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncint vboxClientXLibErrorHandler(Display *pDisplay, XErrorEvent *pError)
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync XGetErrorText(pDisplay, pError->error_code, errorText, sizeof(errorText));
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync 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));
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync return 0; /* We should never reach this. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Xlib error handler for fatal errors. This often means that the programme is still running
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * when X exits.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int vboxClientXLibIOErrorHandler(Display *pDisplay)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return 0; /* We should never reach this. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Reset all standard termination signals to call our signal handler, which
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * cleans up and exits.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Connect to the X server and return the "XFree86_VT" root window property,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * or 0 on failure. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned long *pValue;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync XGetWindowProperty(pDisplay, DefaultRootWindow(pDisplay),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync XInternAtom(pDisplay, "XFree86_VT", False), 0, 1, False,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync XA_INTEGER, &actualType, &actualFormat, &cItems, &cbLeft,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (unsigned char **)&pValue);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Check whether the current virtual terminal is the one running the X server.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void checkVTSysfs(RTFILE hFile, uint32_t cVT)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTFileReadAt(hFile, 0, (void *)szTTY, sizeof(szTTY), &cbRead);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } while(false);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRelFunc(("VBoxClient: failed at stage: \"%s\" rc: %Rrc cVT: %d szTTY: %s.\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Poll for TTY changes using sysfs and for X server disconnection.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Reading from the start of the pollable file "/sys/class/tty/tty0/active"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * returns the currently active TTY as a string of the form "tty<n>", with n
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * greater than zero. Polling for POLLPRI returns when the TTY changes.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @a cVT should be zero if we do not know the X server's VT. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void pollTTYAndXServer(Display *pDisplay, uint32_t cVT)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /* This block could be Linux-only, but keeping it on Solaris too, where it
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * should just fail gracefully, gives us more code path coverage. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync rc = RTFileOpen(&hFile, "/sys/class/tty/tty0/active",
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync while (true)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* The only point of this loop is to trigger the I/O error handler if
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * appropriate. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* If we get caught in a tight loop for some reason try to limit the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * damage. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(("Monitor thread: unexpectedly fast event, revents=0x%x, 0x%x.\n",
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync if ( (poll(pollFD, cPollFD, -1) < 0 && errno != EINTR)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync LogRel(("Monitor thread: poll failed, stopping.\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Thread which notifies the service when we switch to a different VT or back
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * and cleans up when the X server exits.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @note runs until programme exit.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int pfnMonitorThread(RTTHREAD self, void *pvUser)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync unsigned long cVT;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Note: cVT will be 0 if we failed to get it. This is valid. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Should never get here. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Start the thread which notifies the service when we switch to a different
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * VT or back, and terminates us when the X server exits. The first is best
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * effort functionality: XFree86 4.3 and older do not report their VT via the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * "XFree86_VT" root window property at all, and pre-2.6.38 Linux does not
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * provide the interface in "sysfs" which we use. If there is a need for this
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * to work with pre-2.6.38 Linux we can send the VT_GETSTATE ioctl to
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * /dev/console at regular intervals.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync return RTThreadCreate(NULL, pfnMonitorThread, NULL, 0,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Print out a usage message and exit with success.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "--draganddrop|"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "--display|"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "--checkhostversion|"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTPrintf("Start the VirtualBox X Window System guest services.\n\n");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTPrintf(" --clipboard start the shared clipboard service\n");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTPrintf(" --draganddrop start the drag and drop service\n");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTPrintf(" --display start the display management service\n");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTPrintf(" --checkhostversion start the host version notifier service\n");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTPrintf(" --seamless start the seamless windows service\n");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTPrintf(" -d, --nodaemon continue running as a system service\n");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The main loop for the VBoxClient daemon.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @todo Clean up for readability.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Initialise our runtime before all else. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* This should never be called twice in one process - in fact one Display
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * object should probably never be used from multiple threads anyway. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Get our file name for error output. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Initialise the guest library. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTPrintf("%s: failed to connect to the VirtualBox kernel service, rc=%Rrc\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Parse our option(s) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** @todo Use RTGetOpt() if the arguments become more complex. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--nodaemon"))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* If the user is running in "no daemon" mode anyway, send critical
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * logging to stdout as well. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTPrintf("%s: failed to redivert error output, rc=%Rrc\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif /* VBOX_WITH_DRAG_AND_DROP */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTPrintf("%s: unrecognized option `%s'\n", pcszFileName, argv[i]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTPrintf("Try `%s --help' for more information\n", pcszFileName);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTPathUserHome(g_szPidFile, sizeof(g_szPidFile));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTPathAppend(g_szPidFile, sizeof(g_szPidFile),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Set signal handlers to clean up on exit. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Set an X11 error handler, so that we don't die when we get unavoidable
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * errors. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Set an X11 I/O error handler, so that we can shutdown properly on
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * fatal errors. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } while (0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRelFunc(("VBoxClient: failed at stage: \"%s\" rc: %Rrc\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(("Failed to start the monitor thread (%Rrc). Exiting.\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync g_pService->run(fDaemonise); /* Should never return. */