ntpclients/ntpviz.py: Whoops no datetime.UTC befor 3.11.
[ntpsec.git] / ntpclients / ntpwait.py
blobedebf307a00d3dcf45f43fefad7feec344f91b16
1 #! @PYSHEBANG@
2 # -*- coding: utf-8 -*-
3 """\
4 ntpwait - Wait for ntpd to stabilize the system clock.
5 USAGE: ntpwait [-n tries] [-s sleeptime] [-v] [-h]
7 -n, --tries=num Number of times to check ntpd
8 -s, --sleep=num How long to sleep between tries
9 -v, --verbose Be verbose
10 -h, --help Issue help
11 -V, --version Output version information and exit
13 Options are specified by doubled hyphens and their name or by a single
14 hyphen and the flag character.
16 A spurious 'not running' message can result from queries being disabled.
17 """
19 # Copyright the NTPsec project contributors
21 # SPDX-License-Identifier: BSD-2-Clause
23 # Because we've actually seen this fail on a ^C during import of ntp.packet.
24 import signal
25 import sys
26 signal.signal(signal.SIGINT, lambda signal, frame: sys.exit(2))
28 import getopt
29 import re
30 import time
31 import socket
33 try:
34 import ntp.magic
35 import ntp.packet
36 import ntp.util
37 except ImportError as e:
38 sys.stderr.write(
39 "ntpwait: can't find Python NTP library.\n")
40 sys.stderr.write("%s\n" % e)
41 sys.exit(1)
44 class Unbuffered(object):
45 def __init__(self, stream):
46 self.stream = stream
48 def write(self, data):
49 self.stream.write(data)
50 self.stream.flush()
52 def __getattr__(self, attr):
53 return getattr(self.stream, attr)
56 if __name__ == "__main__":
57 bin_ver = "ntpsec-@NTPSEC_VERSION_EXTENDED@"
58 ntp.util.stdversioncheck(bin_ver)
59 try:
60 (options, arguments) = getopt.getopt(sys.argv[1:], "hn:s:vV", [
61 "tries=", "sleep=", "verbose", "help", "version"
63 except getopt.GetoptError as err:
64 sys.stderr.write(str(err) + "\n")
65 raise SystemExit(2)
66 tries = 100
67 sleep = 6
68 verbose = 0
69 for (switch, val) in options:
70 if switch in ("-n", "--tries"):
71 errmsg = "Error: -n parameter '%s' not a number\n"
72 tries = ntp.util.safeargcast(val, int, errmsg, __doc__)
73 elif switch in ("-s", "--sleep"):
74 errmsg = "Error: -s parameter '%s' not a number\n"
75 sleep = ntp.util.safeargcast(val, int, errmsg, __doc__)
76 elif switch in ("-v", "--verbose"):
77 verbose += 1
78 elif switch in ("-h", "--help"):
79 sys.stdout.write(__doc__)
80 raise SystemExit(0)
81 elif switch in ("-V", "--version"):
82 print("ntpwait %s" % ntp.util.stdversion())
83 raise SystemExit(0)
85 # Autoflush stdout
86 sys.stdout = Unbuffered(sys.stdout)
88 basetime = ntp.util.monoclock()
89 if verbose:
90 sys.stdout.write("Waiting for ntpd to synchronize... ")
92 for i in range(1, tries):
93 session = ntp.packet.ControlSession()
94 # session.debug = 4
95 if not session.openhost("localhost"):
96 if verbose:
97 sys.stdout.write("\bntpd is not running!\n")
98 continue
100 msg = None
101 try:
102 msg = session.doquery(2) # Request system variables
103 except ntp.packet.ControlException as e:
104 sys.stderr.write("localhost: timed out, nothing received\n")
105 sys.stderr.write(e.message)
106 except socket.error:
107 if verbose:
108 sys.stdout.write("\b" + "*+:."[i % 4])
109 time.sleep(sleep)
110 continue
112 if verbose >= 2:
113 sys.stderr.write(repr(session.response) + "\n")
115 if msg and msg.startswith("***"):
116 if verbose:
117 sys.stdout.write("\b" + msg + "\n")
118 sys.exit(1)
120 m = re.search(r"leap=([^,]*),", repr(session.response))
121 if m:
122 leap = int(m.group(1))
123 else:
124 sys.stdout.write("\bLeap status not available\n")
125 sys.exit(1)
127 if leap == ntp.magic.LEAP_NOTINSYNC:
128 if verbose:
129 sys.stdout.write("\b" + "*+:."[i % 4])
130 if i < tries:
131 time.sleep(sleep)
132 continue
134 if leap in (ntp.magic.LEAP_NOWARNING, ntp.magic.LEAP_ADDSECOND,
135 ntp.magic.LEAP_DELSECOND):
136 # We could check "sync" here to make sure we like the source...
137 if verbose:
138 sys.stdout.write("\bOK! (%.1f seconds)\n" %
139 (ntp.util.monoclock() - basetime))
140 sys.exit(0)
142 sys.stdout.write("\bUnexpected 'leap' status <%s>\n" % leap)
143 sys.exit(1)
145 if verbose:
146 sys.stdout.write("\bNo!\nntpd did not synchronize.\n")
147 sys.exit(1)
149 # end