1# -*- coding: utf-8 -*- 2# SPDX-License-Identifier: BSD-2-Clause 3"""Access libntp funtions from Python.""" 4from __future__ import absolute_import 5import ctypes 6import ctypes.util 7import errno 8import os 9import os.path 10import sys 11import ntp.poly 12 13LIB = 'ntpc' 14 15 16def _fmt(): 17 """Produce library naming scheme.""" 18 if sys.platform.startswith('darwin'): 19 return 'lib%s.dylib' 20 if sys.platform.startswith('win32'): 21 return '%s.dll' 22 if sys.platform.startswith('cygwin'): 23 return 'lib%s.dll' 24 return 'lib%s.so' 25 26 27def _importado(): 28 """Load the ntpc library or throw an OSError trying.""" 29 ntpc_paths = [] # places to look 30 31 j = __file__.split(os.sep)[:-1] 32 ntpc_paths.append(os.sep.join(j + [_fmt() % LIB])) 33 34 ntpc_path = ctypes.util.find_library(LIB) 35 if ntpc_path: 36 ntpc_paths.append(ntpc_path) 37 38 return _dlo(ntpc_paths) 39 40 41def _dlo(paths): 42 """Try opening library from a list.""" 43 for ntpc_path in paths: 44 try: 45 lib = ctypes.CDLL(ntpc_path, use_errno=True) 46 wrap_version = "@NTPSEC_VERSION_EXTENDED@" 47 clib_version = ntp.poly.polystr(ctypes.c_char_p.in_dll(lib, 'version').value) 48 if clib_version != wrap_version: 49 sys.stderr.write("ntp.ntpc wrong version '%s' != '%s'\n" % (clib_version, wrap_version)) 50 return lib 51 except OSError: 52 pass 53 raise OSError("Can't find %s library" % LIB) 54 55 56_ntpc = _importado() 57progname = ctypes.c_char_p.in_dll(_ntpc, 'progname') 58# log_sys = ctypes.c_bool.in_dll(_ntpc, 'syslogit') 59# log_term = ctypes.c_bool.in_dll(_ntpc, 'termlogit') 60# log_pid = ctypes.c_bool.in_dll(_ntpc, 'termlogit_pid') 61# log_time = ctypes.c_bool.in_dll(_ntpc, 'msyslog_include_timestamp') 62 63TYPE_SYS = ctypes.c_int.in_dll(_ntpc, 'SYS_TYPE').value 64TYPE_PEER = ctypes.c_int.in_dll(_ntpc, 'PEER_TYPE').value 65TYPE_CLOCK = ctypes.c_int.in_dll(_ntpc, 'CLOCK_TYPE').value 66 67 68def checkname(name): 69 """Check if name is a valid algorithm name.""" 70 _ntpc.do_checkname.restype = ctypes.c_int 71 mid_bytes = ntp.poly.polybytes(name) 72 _ntpc.do_checkname.argtypes = [ctypes.c_char_p] 73 return _ntpc.do_checkname(mid_bytes) 74 75 76def mac(data, key, name): 77 """Compute HMAC or CMAC from data, key, and algorithm name.""" 78 resultlen = ctypes.c_size_t() 79 result = (ctypes.c_char * 64)() 80 result.value = b'\0' * 64 81 _ntpc.do_mac.restype = None 82 _ntpc.do_mac(ntp.poly.polybytes(name), 83 ntp.poly.polybytes(data), len(data), 84 ntp.poly.polybytes(key), len(key), 85 ctypes.byref(result), ctypes.byref(resultlen)) 86 return result.value 87 88 89def setprogname(in_string): 90 """Set program name for logging purposes.""" 91 mid_bytes = ntp.poly.polybytes(in_string) 92 _setprogname(mid_bytes) 93 94 95def _lfp_wrap(callback, in_string): 96 """NTP l_fp to other Python-style format.""" 97 mid_bytes = ntp.poly.polybytes(in_string) 98 out_value = callback(mid_bytes) 99 err = ctypes.get_errno() 100 if err == errno.EINVAL: 101 raise ValueError('ill-formed hex date') 102 return out_value 103 104 105def statustoa(i_type, i_st): 106 """Convert a time stamp to something readable.""" 107 mid_str = _statustoa(i_type, i_st) 108 return ntp.poly.polystr(mid_str) 109 110 111def prettydate(in_string): 112 """Convert a time stamp to something readable.""" 113 mid_str = _lfp_wrap(_prettydate, in_string) 114 return ntp.poly.polystr(mid_str) 115 116 117def lfptofloat(in_string): 118 """NTP l_fp to Python-style float time.""" 119 return _lfp_wrap(_lfptofloat, in_string) 120 121 122def msyslog(level, in_string): 123 """Log send a message to terminal or output.""" 124 mid_bytes = ntp.poly.polybytes(in_string) 125 _msyslog(level, mid_bytes) 126 127 128# Set return type and argument types of hidden ffi handlers 129_msyslog = _ntpc.msyslog 130_msyslog.restype = None 131_msyslog.argtypes = [ctypes.c_int, ctypes.c_char_p] 132 133_setprogname = _ntpc.ntpc_setprogname 134_setprogname.restype = None 135_setprogname.argtypes = [ctypes.c_char_p] 136 137_prettydate = _ntpc.ntpc_prettydate 138_prettydate.restype = ctypes.c_char_p 139_prettydate.argtypes = [ctypes.c_char_p] 140 141_lfptofloat = _ntpc.ntpc_lfptofloat 142_lfptofloat.restype = ctypes.c_double 143_lfptofloat.argtypes = [ctypes.c_char_p] 144 145# Status string display from peer status word. 146_statustoa = _ntpc.statustoa 147_statustoa.restype = ctypes.c_char_p 148_statustoa.argtypes = [ctypes.c_int, ctypes.c_int] 149 150# Set time to nanosecond precision. 151set_tod = _ntpc.ntpc_set_tod 152set_tod.restype = ctypes.c_int 153set_tod.argtypes = [ctypes.c_int, ctypes.c_int] 154 155# Adjust system time by slewing. 156adj_systime = _ntpc.ntpc_adj_systime 157adj_systime.restype = ctypes.c_bool 158adj_systime.argtypes = [ctypes.c_double] 159 160# Adjust system time by stepping. 161step_systime = _ntpc.ntpc_step_systime 162step_systime.restype = ctypes.c_bool 163step_systime.argtypes = [ctypes.c_double] 164