5f9a30d335
This way it gives more control over time synchronization to the VM. For example Whonix VMs can decide to not use this mechanism. Also VM can choose how that time will be set (chronyc call?). And finally it will be possible to implement the same for other OS-es (Windows). Additionally because of calling date as "localcmd" each time, instead of once at the beginning, time synchronization is more accurrate now. If some VM stall the time set call, other VMs time will no longer be affected (but still synchronization will be delayed).
126 lines
4.1 KiB
Python
Executable File
126 lines
4.1 KiB
Python
Executable File
#!/usr/bin/python2
|
|
# -*- encoding: utf8 -*-
|
|
#
|
|
# The Qubes OS Project, http://www.qubes-os.org
|
|
#
|
|
# Copyright (C) 2010 Marek Marczykowski <marmarek@invisiblethingslab.com>
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
#
|
|
import fcntl
|
|
|
|
from qubes.qubes import QubesVmCollection
|
|
import os.path
|
|
import os
|
|
import sys
|
|
import re
|
|
import subprocess
|
|
|
|
qvm_collection = None
|
|
|
|
def get_netvm_of_vm(vm):
|
|
netvm = vm
|
|
while netvm.netvm is not None:
|
|
netvm = netvm.netvm
|
|
if netvm is None or netvm.name == 'dom0':
|
|
print >> sys.stderr, 'There seems to be no network connected to ClockVM, aborting.'
|
|
sys.exit(1)
|
|
return netvm
|
|
|
|
def main():
|
|
verbose = False
|
|
if len(sys.argv) > 1 and sys.argv[1] in [ '--verbose', '-v' ]:
|
|
verbose = True
|
|
|
|
lockfile_name = "/var/run/qubes/qvm-sync-clock.lock"
|
|
if os.path.exists(lockfile_name):
|
|
lockfile = open(lockfile_name, "r")
|
|
else:
|
|
lockfile = open(lockfile_name, "w")
|
|
|
|
fcntl.fcntl(lockfile.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC)
|
|
try:
|
|
fcntl.flock(lockfile.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
except IOError:
|
|
print >>sys.stderr, "qvm-sync-clock already running, aborting"
|
|
sys.exit(1)
|
|
|
|
qvm_collection = QubesVmCollection()
|
|
qvm_collection.lock_db_for_reading()
|
|
qvm_collection.load()
|
|
qvm_collection.unlock_db()
|
|
|
|
clock_vm = qvm_collection.get_clockvm_vm()
|
|
|
|
if clock_vm is None:
|
|
print >> sys.stderr, 'There is no selected ClockVM, aborting.'
|
|
sys.exit(1)
|
|
|
|
if not clock_vm.is_running():
|
|
print >> sys.stderr, 'ClockVM not started, exiting!'
|
|
sys.exit(1)
|
|
|
|
net_vm = get_netvm_of_vm(clock_vm)
|
|
if verbose:
|
|
print >> sys.stderr, '--> Waiting for network for ClockVM.'
|
|
|
|
# Ignore retcode, try even if nm-online failed - user can setup network manually
|
|
# on-online has timeout 30sec by default
|
|
net_vm.run('nm-online -x', verbose=verbose, gui=False, wait=True,
|
|
ignore_stderr=True)
|
|
|
|
# Sync clock
|
|
if clock_vm.run('QUBESRPC qubes.SyncNtpClock dom0', user="root",
|
|
verbose=verbose, gui=False, wait=True, ignore_stderr=True) \
|
|
!= 0:
|
|
print >> sys.stderr, 'Time sync failed, aborting!'
|
|
sys.exit(1)
|
|
|
|
# Use the date format based on RFC2822 to avoid localisation issues
|
|
p = clock_vm.run('date -u -Iseconds', verbose=verbose,
|
|
gui=False, passio_popen=True, ignore_stderr=True)
|
|
date_out = p.stdout.read(100)
|
|
date_out = date_out.strip()
|
|
if not re.match(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+0000$', date_out):
|
|
print >> sys.stderr, 'Invalid date output, aborting!'
|
|
sys.exit(1)
|
|
|
|
# Sync dom0 time
|
|
if verbose:
|
|
print >> sys.stderr, '--> Syncing dom0 clock.'
|
|
|
|
subprocess.check_call(['sudo', 'date', '-u', '-Iseconds', '-s', date_out])
|
|
subprocess.check_call(['sudo', 'hwclock', '--systohc'])
|
|
|
|
# Sync other VMs clock
|
|
for vm in qvm_collection.values():
|
|
if vm.is_running() and vm.qid != 0 and vm.qid != clock_vm.qid:
|
|
if verbose:
|
|
print >> sys.stderr, '--> Syncing \'%s\' clock.' % vm.name
|
|
try:
|
|
vm.run_service("qubes.SetDateTime", user="root",
|
|
localcmd="date -u -Iseconds")
|
|
except Exception as e:
|
|
print >> sys.stderr, "ERROR syncing time in VM '%s': %s" % (vm.name, str(e))
|
|
pass
|
|
|
|
# order is important!
|
|
os.unlink(lockfile_name)
|
|
lockfile.close()
|
|
|
|
main()
|
|
|