/**
 * initialise the service.
 */
int SeamlessMain::init(void)
{
    int rc;
    const char *pcszStage;

    LogRelFlowFunc(("\n"));
    do {
        pcszStage = "Connecting to the X server";
        rc = mX11Monitor.init(sendRegionUpdate);
        if (RT_FAILURE(rc))
            break;
        pcszStage = "Setting guest IRQ filter mask";
        rc = VbglR3CtlFilterMask(VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST, 0);
        if (RT_FAILURE(rc))
            break;
        pcszStage = "Reporting support for seamless capability";
        rc = VbglR3SeamlessSetCap(true);
        if (RT_FAILURE(rc))
            break;
        rc = startX11MonitorThread();
        if (RT_FAILURE(rc))
            break;
    } while(0);
    if (RT_FAILURE(rc))
        VBClFatalError(("VBoxClient (seamless): failed to start.  Stage: \"%s\"  Error: %Rrc\n",
                pcszStage, rc));
    return rc;
}
static struct SEAMLESSSERVICE *getClassFromInterface(struct VBCLSERVICE **
                                                         ppInterface)
{
    struct SEAMLESSSERVICE *pSelf = (struct SEAMLESSSERVICE *)ppInterface;
    if (pSelf->magic != SEAMLESSSERVICE_MAGIC)
        VBClFatalError(("Bad seamless service object!\n"));
    return pSelf;
}
/** Check whether X.Org has acquired or lost the current virtual terminal and
 * call the service @a pause() or @a resume() call-back if appropriate.
 * The functionality is provided by the vboxvideo driver for pre-1.16 X servers
 * and by 1.16 and later series servers.
 * This can either be called directly from a service's event loop or the service
 * can call VBClStartVTMonitor() to start an event loop in a separate thread.
 * Property notification for the root window should be selected first.  Services
 * are not required to check VT changes if they do not need the information.
 * @param  pEvent an event received on a display connection which will be
 *                checked to see if it is change to the XFree86_has_VT property
 */
void VBClCheckXOrgVT(union _XEvent *pEvent)
{
    Atom actualType;
    int actualFormat;
    unsigned long cItems, cbLeft;
    bool fHasVT = false;
    unsigned long *pValue;
    int rc;
    Display *pDisplay = pEvent->xany.display;
    Atom hasVT = XInternAtom(pDisplay, "XFree86_has_VT", False);

    if (   pEvent->type != PropertyNotify
        || pEvent->xproperty.window != DefaultRootWindow(pDisplay)
        || pEvent->xproperty.atom != hasVT)
        return;
    XGetWindowProperty(pDisplay, DefaultRootWindow(pDisplay), hasVT, 0, 1,
                       False, XA_INTEGER, &actualType, &actualFormat, &cItems,
                       &cbLeft, (unsigned char **)&pValue);
    if (cItems && actualFormat == 32)
    {
        fHasVT = *pValue != 0;
        XFree(pValue);
    }
    else
        return;
    if (fHasVT)
    {
        rc = (*g_pService)->resume(g_pService);
        if (RT_FAILURE(rc))
            VBClFatalError(("Error resuming the service: %Rrc\n"));
    }
    if (!fHasVT)
    {
        rc = (*g_pService)->pause(g_pService);
        if (RT_FAILURE(rc))
            VBClFatalError(("Error pausing the service: %Rrc\n"));
    }
}
/** Clean up if we get a signal or something.  This is extern so that we
 * can call it from other compilation units. */
void VBClCleanUp()
{
    /* We never release this, as we end up with a call to exit(3) which is not
     * async-safe.  Unless we fix this application properly, we should be sure
     * never to exit from anywhere except from this method. */
    int rc = RTCritSectEnter(&g_critSect);
    if (RT_FAILURE(rc))
        VBClFatalError(("VBoxClient: Failure while acquiring the global critical section, rc=%Rrc\n", rc));
    if (g_pService)
        (*g_pService)->cleanup(g_pService);
    if (g_szPidFile[0] && g_hPidFile)
        VbglR3ClosePidFile(g_szPidFile, g_hPidFile);
    exit(0);
}
static int init(struct VBCLSERVICE **ppInterface)
{
    struct SEAMLESSSERVICE *pSelf = getClassFromInterface(ppInterface);
    int rc;

    if (pSelf->mIsInitialised)
        return VERR_INTERNAL_ERROR;
    /* Initialise the guest library. */
    rc = VbglR3InitUser();
    if (RT_FAILURE(rc))
        VBClFatalError(("Failed to connect to the VirtualBox kernel service, rc=%Rrc\n", rc));
    rc = pSelf->mSeamless.init();
    if (RT_FAILURE(rc))
        return rc;
    pSelf->mIsInitialised = true;
    return VINF_SUCCESS;
}
/**
 * Thread which notifies the service when we switch to a different VT or back
 * and cleans up when the X server exits.
 * @note runs until programme exit.
 */
static int pfnMonitorThread(RTTHREAD self, void *pvUser)
{
    Display *pDisplay;
    bool fHasVT = true;
    
    pDisplay = XOpenDisplay(NULL);
    if (!pDisplay)
        VBClFatalError(("Failed to open the X11 display\n"));
    XSelectInput(pDisplay, DefaultRootWindow(pDisplay), PropertyChangeMask);
    while (true)
    {
        XEvent event;

        XNextEvent(pDisplay, &event);
        VBClCheckXOrgVT(&event);
    }
    return VINF_SUCCESS;  /* Should never be reached. */
}
Exemple #7
0
static int run(struct VBCLSERVICE **ppInterface, bool fDaemonised)
{
    int rc;

    NOREF(ppInterface);
    /* Initialise the guest library. */
    rc = VbglR3InitUser();
    if (RT_FAILURE(rc))
        VBClFatalError(("Failed to connect to the VirtualBox kernel service, rc=%Rrc\n", rc));
    rc = vboxClipboardConnect();
    /* Not RT_SUCCESS: VINF_PERMISSION_DENIED is host service not present. */
    if (rc == VINF_SUCCESS)
        rc = vboxClipboardMain();
    if (rc == VERR_NOT_SUPPORTED)
        rc = VINF_SUCCESS;  /* Prevent automatic restart. */
    if (RT_FAILURE(rc))
        LogRelFunc(("guest clipboard service terminated abnormally: return code %Rrc\n", rc));
    return rc;
}
/**
 * The actual X11 window configuration change monitor thread function.
 */
int SeamlessMain::x11MonitorThread(RTTHREAD hThreadSelf, void *pvUser)
{
    RT_NOREF1(hThreadSelf);
    SeamlessMain *pHost = (SeamlessMain *)pvUser;
    int rc = VINF_SUCCESS;

    LogRelFlowFunc(("\n"));
    while (!pHost->mX11MonitorThreadStopping)
    {
        if (!pHost->mfPaused)
        {
            rc = pHost->mX11Monitor.start();
            if (RT_FAILURE(rc))
                VBClFatalError(("Failed to change the X11 seamless service state, mfPaused=%RTbool, rc=%Rrc\n",
                                pHost->mfPaused, rc));
        }
        pHost->mX11Monitor.nextConfigurationEvent();
        if (pHost->mfPaused || pHost->mX11MonitorThreadStopping)
            pHost->mX11Monitor.stop();
    }
    LogRelFlowFunc(("returning %Rrc\n", rc));
    return rc;
}
Exemple #9
0
/** @todo Move this part in VbglR3 and just provide a callback for the platform-specific
          notification stuff, since this is very similar to the VBoxTray code. */
static int run(struct VBCLSERVICE **ppInterface, bool fDaemonised)
{
    int rc;
    LogFlowFunc(("\n"));

    NOREF(ppInterface);
    /* Initialise the guest library. */
    rc = VbglR3InitUser();
    if (RT_FAILURE(rc))
        VBClFatalError(("Failed to connect to the VirtualBox kernel service, rc=%Rrc\n", rc));
    /* Because we need desktop notifications to be displayed, wait
     * some time to make the desktop environment load (as a work around). */
    if (fDaemonised)
        RTThreadSleep(30 * 1000 /* Wait 30 seconds */);

# ifdef VBOX_WITH_DBUS
    rc = RTDBusLoadLib();
    if (RT_FAILURE(rc))
        LogRel(("VBoxClient: D-Bus seems not to be installed; no host version check/notification done.\n"));
# else
    rc = VERR_NOT_IMPLEMENTED;
# endif /* VBOX_WITH_DBUS */

# ifdef VBOX_WITH_GUEST_PROPS
    uint32_t uGuestPropSvcClientID;
    if (RT_SUCCESS(rc))
    {
        rc = VbglR3GuestPropConnect(&uGuestPropSvcClientID);
        if (RT_FAILURE(rc))
            LogRel(("VBoxClient: Cannot connect to guest property service while chcking for host version! rc = %Rrc\n", rc));
    }

    if (RT_SUCCESS(rc))
    {
        char *pszHostVersion;
        char *pszGuestVersion;
        bool bUpdate;

        rc = VbglR3HostVersionCheckForUpdate(uGuestPropSvcClientID, &bUpdate, &pszHostVersion, &pszGuestVersion);
        if (RT_SUCCESS(rc))
        {
            if (bUpdate)
            {
                char szMsg[1024];
                char szTitle[64];

                /** @todo add some translation macros here */
                RTStrPrintf(szTitle, sizeof(szTitle), "VirtualBox Guest Additions update available!");
#ifndef VBOX_OSE
                RTStrPrintf(szMsg, sizeof(szMsg), "Your guest is currently running the Guest Additions version %s. "
                                                  "We recommend updating to the latest version (%s) by choosing the "
                                                  "install option from the Devices menu.", pszGuestVersion, pszHostVersion);
#else
/* This is the message which appears for non-Oracle builds of the
* Guest Additions.  Distributors are encouraged to customise this. */
                RTStrPrintf(szMsg, sizeof(szMsg), "Your virtual machine is currently running the Guest Additions version %s. Since you are running a version of the Guest Additions provided by the operating system you installed in the virtual machine we recommend that you update it to at least version %s using that system's update features, or alternatively that you remove this version and then install the " VBOX_VENDOR_SHORT " Guest Additions package using the install option from the Devices menu. Please consult the documentation for the operating system you are running to find out how to update or remove the current Guest Additions package.", pszGuestVersion, pszHostVersion);
#endif
                rc = showNotify(szTitle, szMsg);
                LogRel(("VBoxClient: VirtualBox Guest Additions update available!"));
                if (RT_FAILURE(rc))
                    LogRel(("VBoxClient: Could not show version notifier tooltip! rc = %d\n", rc));
            }

            /* Store host version to not notify again */
            rc = VbglR3HostVersionLastCheckedStore(uGuestPropSvcClientID, pszHostVersion);

            VbglR3GuestPropReadValueFree(pszHostVersion);
            VbglR3GuestPropReadValueFree(pszGuestVersion);
        }
        VbglR3GuestPropDisconnect(uGuestPropSvcClientID);
    }
# endif /* VBOX_WITH_GUEST_PROPS */
    VbglR3Term();
    LogFlowFunc(("returning %Rrc\n", rc));
    return rc;
}
/**
 * The main loop for the VBoxClient daemon.
 * @todo Clean up for readability.
 */
int main(int argc, char *argv[])
{
    bool fDaemonise = true, fRespawn = true;
    int rc;
    const char *pcszFileName, *pcszStage;

    /* Initialise our runtime before all else. */
    rc = RTR3InitExe(argc, &argv, 0);
    if (RT_FAILURE(rc))
        return RTMsgInitFailure(rc);
    /* This should never be called twice in one process - in fact one Display
     * object should probably never be used from multiple threads anyway. */
    if (!XInitThreads())
        VBClFatalError(("Failed to initialize X11 threads\n"));
    /* Get our file name for error output. */
    pcszFileName = RTPathFilename(argv[0]);
    if (!pcszFileName)
        pcszFileName = "VBoxClient";

    /* Parse our option(s) */
    /** @todo Use RTGetOpt() if the arguments become more complex. */
    for (int i = 1; i < argc; ++i)
    {
        rc = VERR_INVALID_PARAMETER;
        if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--nodaemon"))
        {
            /* If the user is running in "no daemon" mode anyway, send critical
             * logging to stdout as well. */
            PRTLOGGER pReleaseLog = RTLogRelDefaultInstance();

            if (pReleaseLog)
                rc = RTLogDestinations(pReleaseLog, "stdout");
            if (pReleaseLog && RT_FAILURE(rc))
                RTPrintf("%s: failed to redivert error output, rc=%Rrc\n",
                         pcszFileName, rc);
            fDaemonise = false;
        }
        else if (!strcmp(argv[i], "--no-respawn"))
        {
            fRespawn = false;
        }
        else if (!strcmp(argv[i], "--clipboard"))
        {
            if (g_pService)
                break;
            g_pService = VBClGetClipboardService();
        }
        else if (!strcmp(argv[i], "--display"))
        {
            if (g_pService)
                break;
            g_pService = VBClGetDisplayService();
        }
        else if (!strcmp(argv[i], "--seamless"))
        {
            if (g_pService)
                break;
            g_pService = VBClGetSeamlessService();
        }
        else if (!strcmp(argv[i], "--checkhostversion"))
        {
            if (g_pService)
                break;
            g_pService = VBClGetHostVersionService();
        }
#ifdef VBOX_WITH_DRAG_AND_DROP
        else if (!strcmp(argv[i], "--draganddrop"))
        {
            if (g_pService)
                break;
            g_pService = VBClGetDragAndDropService();
        }
#endif /* VBOX_WITH_DRAG_AND_DROP */
        else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
        {
            vboxClientUsage(pcszFileName);
            return 0;
        }
        else
        {
            RTPrintf("%s: unrecognized option `%s'\n", pcszFileName, argv[i]);
            RTPrintf("Try `%s --help' for more information\n", pcszFileName);
            return 1;
        }
        rc = VINF_SUCCESS;
    }
    if (RT_FAILURE(rc) || !g_pService)
    {
        vboxClientUsage(pcszFileName);
        return 1;
    }

    rc = RTCritSectInit(&g_critSect);
    if (RT_FAILURE(rc))
        VBClFatalError(("Initialising critical section: %Rrc\n", rc));
    rc = RTPathUserHome(g_szPidFile, sizeof(g_szPidFile));
    if (RT_FAILURE(rc))
        VBClFatalError(("Getting home directory for pid-file: %Rrc\n", rc));
    rc = RTPathAppend(g_szPidFile, sizeof(g_szPidFile),
                      (*g_pService)->getPidFilePath());
    if (RT_FAILURE(rc))
        VBClFatalError(("Creating pid-file path: %Rrc\n", rc));
    if (fDaemonise)
        rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */, fRespawn, &cRespawn);
    if (RT_FAILURE(rc))
        VBClFatalError(("Daemonizing: %Rrc\n", rc));
    if (g_szPidFile[0])
        rc = VbglR3PidFile(g_szPidFile, &g_hPidFile);
    if (rc == VERR_FILE_LOCK_VIOLATION)  /* Already running. */
        return 0;
    if (RT_FAILURE(rc))
        VBClFatalError(("Creating pid-file: %Rrc\n", rc));
    /* Set signal handlers to clean up on exit. */
    vboxClientSetSignalHandlers();
#ifndef VBOXCLIENT_WITHOUT_X11
    /* Set an X11 error handler, so that we don't die when we get unavoidable
     * errors. */
    XSetErrorHandler(vboxClientXLibErrorHandler);
    /* Set an X11 I/O error handler, so that we can shutdown properly on
     * fatal errors. */
    XSetIOErrorHandler(vboxClientXLibIOErrorHandler);
#endif
    rc = (*g_pService)->init(g_pService);
    if (RT_FAILURE(rc))
        VBClFatalError(("Initialising service: %Rrc\n", rc));
    rc = (*g_pService)->run(g_pService, fDaemonise);
    if (RT_FAILURE(rc))
        VBClFatalError(("Service main loop failed: %Rrc\n", rc));
    VBClCleanUp();
    return 0;
}