Skip to content

Instantly share code, notes, and snippets.

@eqhmcow
Created August 20, 2009 10:58
Show Gist options
  • Save eqhmcow/170984 to your computer and use it in GitHub Desktop.
Save eqhmcow/170984 to your computer and use it in GitHub Desktop.
script that automatically resets a virtual machine's system time after the host resumes from sleep. This is handy e.g. when using vmware on a laptop
#!/usr/bin/perl
use strict;
use warnings;
=pod
check_time.pl
This script automatically resets a virtual machine's system time after the
host resumes from sleep. This is handy e.g. when using vmware on a laptop.
The NTP daemon is stopped and the system time is immediately set from the
hardware clock if the hardware clock is more than a few seconds in the future.
After setting system time, the script runs ntpdate and finally restarts the
NTP daemon. This ensures the proper time is set even if the guest doesn't have
network connectivity, while also allowing NTP to resume maintaining the
system clock as quickly as possible.
When the host suspends, so does the guest; on resume, the guest system time
will be the time when the host suspended, which will be much earlier than
the host clock. This script checks the clock every minute to ensure the
guest system time is automatically reset to the correct time soon after a
resume. In combination with ntpd, this is superior to forced periodic host
to guest time synchronization; ntpd will keep the guest clock properly set
while the system is running, and forced syncs will only occur after the host
resumes from sleep.
This script is meant to be run as a daemon. Add the following line to your
rc.local or equivalent startup file:
nohup /usr/local/bin/check_time.pl &
=cut
# configurable settings
# how often to check the time, in seconds
my $check_every = 60; # seconds
# system log entry if the hardware clock is out of sync
my $log_if_delta_larger_than = 1; # seconds
# reset system time if hardware clock is out of sync
my $reset_if_delta_larger_than = 5; # seconds
# list of NTP servers that ntpdate will attempt to use
# servers are tried in order until ntpdate is successful or we run out
# we only try once per server.
# list local servers (if any) first
my @ntp_servers = qw/
wingfly
0.north-america.pool.ntp.org
1.north-america.pool.ntp.org
2.north-america.pool.ntp.org
3.north-america.pool.ntp.org
ntp.apple.com
ntp.ubuntu.com
time.windows.com
/;
use Date::Parse;
use Time::HiRes 'time';
while (1) {
check_time();
sleep $check_every;
}
sub check_time
{
my $initial_time = time;
my $hw_time = `hwclock --show`;
my $time = time;
($hw_time, my $adj) = $hw_time =~ m/^(.*\S)\s+(\S+) seconds$/;
$hw_time = str2time($hw_time);
#print "initl time: $initial_time\n";
#print "local time: $time\n";
my $local_sec = $time;
$local_sec =~ s/^[^.]+(\..*)$/$1/;
$hw_time = $hw_time . $local_sec;
$hw_time += $adj;
#print "hware time: $hw_time\n";
my $delta = $hw_time - $initial_time;
#print "delta: $delta\n";
# we shouldn't be more than a second off hardware clock if ntpd is working
# on both the host and the guest
`logger -- $0 delta $delta` if abs $delta > $log_if_delta_larger_than;
# hardware clock will be quite a bit in the future if we've been sleeping
return 0 unless $delta > $reset_if_delta_larger_than;
`logger -- $0 delta too large [$delta \\> $reset_if_delta_larger_than], resetting clock`;
# using sudo allows this script to run without root if you so desire
# sudo also logs the exact commands the script runs
my $msg = `sudo /etc/init.d/ntp stop`;
`logger -- $0 ntp stop '$msg'`;
$msg = `sudo hwclock --hctosys`;
`logger -- $0 hwclock --hctosys '$msg'`;
foreach my $ntp_server (@ntp_servers) {
sleep 5; # wait a bit in case the network is slow to come up
$msg = `sudo ntpdate '$ntp_server'`;
my $result = $? >> 8;
`logger -- $0 ntpdate '$msg'`;
last unless $result;
}
$msg = `sudo /etc/init.d/ntp start`;
`logger -- $0 ntp start '$msg'`;
return 1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment