vboxadd_timesync.c revision 240f7d7012a5f64bcde850bcf048531a710d81cf
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/** @file
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync *
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync * VirtualBox timesync daemon for Linux
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/*
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync *
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync * available from http://www.virtualbox.org. This file is free software;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync * you can redistribute it and/or modify it under the terms of the GNU
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync * General Public License (GPL) as published by the Free Software
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync *
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync * additional information or have any questions.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <stdio.h>
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <stdlib.h>
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <string.h>
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <unistd.h>
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <getopt.h>
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <errno.h>
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <sys/fcntl.h>
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <sys/ioctl.h>
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <sys/time.h>
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <time.h>
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <VBox/VBoxGuest.h>
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <VBox/err.h>
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsyncstatic void usage(void)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync{
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync printf("vboxadd-timesync [--interval <seconds>]\n"
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync " [--daemonize]\n");
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync}
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsyncstatic void safe_sleep(time_t seconds)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync{
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync struct timespec requestedSleepTime;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync requestedSleepTime.tv_sec = seconds;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync requestedSleepTime.tv_nsec = 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync for (;;)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int err;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync struct timespec remainingSleepTime;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync err = nanosleep(&requestedSleepTime, &remainingSleepTime);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (err)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* if the sleep was interrupted, remember remaining sleep time */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (errno == EINTR)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync requestedSleepTime = remainingSleepTime;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync else
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* not good... */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync else
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* nanosleep completed and took at least the requested time */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync}
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsyncint main(int argc, char *argv[])
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync{
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync const struct option options[] =
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync { "interval", required_argument, NULL, 'i' },
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync { "daemonize", no_argument, NULL, 'd' },
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync { "help", no_argument, NULL, 'h' },
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync { NULL, 0, NULL, 0 }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync };
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int secInterval = 10;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int fDaemonize = 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int c, fd;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync VMMDevReqHostTime req;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* command line parsing */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync for (;;)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync c = getopt_long(argc, argv, "i:dh", options, NULL);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (c == -1)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync switch (c)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync case 'i':
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync secInterval = atoi(optarg);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync case 'd':
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fDaemonize = 1;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync case 'h':
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync usage();
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync case ':':
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync case '?':
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* unrecognized option (?) or parameter missing (:) */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return 1;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync default:
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* open the driver */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fd = open(VBOXGUEST_DEVICE_NAME, O_RDWR, 0);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (fd < 0)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync printf("Error opening kernel module! rc = %d\n", errno);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return 1;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* prepare the request structure */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync vmmdevInitRequest((VMMDevRequestHeader*)&req, VMMDevReq_GetHostTime);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (!fDaemonize)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync printf("VirtualBox timesync daemon.\n"
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync "(C) 2008 Sun Microsystems, Inc.\n"
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync "\nSync interval: %d seconds.\n", secInterval);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (fDaemonize)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync daemon(1, 0);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync do
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* perform VMM request */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (ioctl(fd, VBOXGUEST_IOCTL_VMMREQUEST(0), (void*)&req) >= 0)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (RT_SUCCESS(req.header.rc))
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* Adapt time smoothly and try to prevent negative time differences. */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync uint64_t u64Now;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int64_t i64Diff;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int64_t i64AbsDiff;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync struct timeval tv;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#undef USE_ADJTIME
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#ifdef USE_ADJTIME
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync gettimeofday(&tv, NULL);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync u64Now = (uint64_t)tv.tv_sec * 1000 + (uint64_t)tv.tv_usec / 1000;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync i64Diff = (int64_t)(req.time - u64Now);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync i64AbsDiff = i64Diff < 0 ? -i64Diff : i64Diff;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (i64AbsDiff < 300000)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* difference less than 5 minutes => smoothly adapt the guest time */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int32_t i32Diff = (int32_t)i64Diff;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int32_t i32Sec, i32Micro;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync struct timeval delta;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync i32Sec = i32Diff / 1000;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync i32Micro = (i32Diff % 1000) * 1000;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (i32Micro < 0)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync i32Micro = -i32Micro;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync delta.tv_sec = i32Sec;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync delta.tv_usec = i32Micro;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* adjtime on Linux adjusts the time about 5 ms per 10 seconds, even
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync * for very huge differences */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync adjtime(&delta, NULL);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync else
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#endif
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* difference more than 5 minutes => set the time with all consequences */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync tv.tv_sec = req.time / (uint64_t)1000;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync tv.tv_usec = (req.time % (uint64_t)1000) * 1000;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync settimeofday(&tv, NULL);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync else
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync printf("Error querying host time! header.rc = %d\n", req.header.rc);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync else
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync printf("Error performing VMM request! errno = %d\n", errno);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* wait for the next run */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync safe_sleep(secInterval);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync } while (1);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync close(fd);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync}
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync