| /* |
| chronyd/chronyc - Programs for keeping computer clocks accurate. |
| |
| ********************************************************************** |
| * Copyright (C) Richard P. Curnow 1997-2003 |
| * Copyright (C) Miroslav Lichvar 2009-2017, 2020 |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of version 2 of the GNU General Public License as |
| * published by the Free Software Foundation. |
| * |
| * 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. |
| * |
| ********************************************************************** |
| |
| ======================================================================= |
| |
| Module that reads and processes the configuration file. |
| */ |
| |
| #include "config.h" |
| |
| #include "sysincl.h" |
| |
| #include "array.h" |
| #include "conf.h" |
| #include "ntp_sources.h" |
| #include "ntp_core.h" |
| #include "nts_ke.h" |
| #include "refclock.h" |
| #include "cmdmon.h" |
| #include "socket.h" |
| #include "srcparams.h" |
| #include "logging.h" |
| #include "nameserv.h" |
| #include "memory.h" |
| #include "cmdparse.h" |
| #include "util.h" |
| |
| /* ================================================== */ |
| |
| #define MAX_LINE_LENGTH 2048 |
| #define MAX_CONF_DIRS 10 |
| #define MAX_INCLUDE_LEVEL 10 |
| |
| /* ================================================== */ |
| /* Forward prototypes */ |
| |
| static int parse_string(char *line, char **result); |
| static int parse_int(char *line, int *result); |
| static int parse_double(char *line, double *result); |
| static int parse_null(char *line); |
| |
| static void parse_allow_deny(char *line, ARR_Instance restrictions, int allow); |
| static void parse_authselectmode(char *); |
| static void parse_bindacqaddress(char *); |
| static void parse_bindaddress(char *); |
| static void parse_bindcmdaddress(char *); |
| static void parse_broadcast(char *); |
| static void parse_clientloglimit(char *); |
| static void parse_confdir(char *); |
| static void parse_fallbackdrift(char *); |
| static void parse_hwtimestamp(char *); |
| static void parse_include(char *); |
| static void parse_initstepslew(char *); |
| static void parse_leapsecmode(char *); |
| static void parse_local(char *); |
| static void parse_log(char *); |
| static void parse_mailonchange(char *); |
| static void parse_makestep(char *); |
| static void parse_maxchange(char *); |
| static void parse_ntsserver(char *, ARR_Instance files); |
| static void parse_ntstrustedcerts(char *); |
| static void parse_ratelimit(char *line, int *enabled, int *interval, |
| int *burst, int *leak); |
| static void parse_refclock(char *); |
| static void parse_smoothtime(char *); |
| static void parse_source(char *line, char *type, int fatal); |
| static void parse_sourcedir(char *); |
| static void parse_tempcomp(char *); |
| |
| /* ================================================== */ |
| /* Configuration variables */ |
| |
| static int print_config = 0; |
| static int restarted = 0; |
| static char *rtc_device; |
| static int acquisition_port = -1; |
| static int ntp_port = NTP_PORT; |
| static char *keys_file = NULL; |
| static char *drift_file = NULL; |
| static char *rtc_file = NULL; |
| static double max_update_skew = 1000.0; |
| static double correction_time_ratio = 3.0; |
| static double max_clock_error = 1.0; /* in ppm */ |
| static double max_drift = 500000.0; /* in ppm */ |
| static double max_slew_rate = 1e6 / 12.0; /* in ppm */ |
| static double clock_precision = 0.0; /* in seconds */ |
| |
| static SRC_AuthSelectMode authselect_mode = SRC_AUTHSELECT_MIX; |
| static double max_distance = 3.0; |
| static double max_jitter = 1.0; |
| static double reselect_distance = 1e-4; |
| static double stratum_weight = 1e-3; |
| static double combine_limit = 3.0; |
| |
| static int cmd_port = DEFAULT_CANDM_PORT; |
| |
| static int raw_measurements = 0; |
| static int do_log_measurements = 0; |
| static int do_log_statistics = 0; |
| static int do_log_tracking = 0; |
| static int do_log_rtc = 0; |
| static int do_log_refclocks = 0; |
| static int do_log_tempcomp = 0; |
| static int log_banner = 32; |
| static char *logdir = NULL; |
| static char *dumpdir = NULL; |
| |
| static int enable_local=0; |
| static int local_stratum; |
| static int local_orphan; |
| static double local_distance; |
| |
| /* Threshold (in seconds) - if absolute value of initial error is less |
| than this, slew instead of stepping */ |
| static double init_slew_threshold; |
| /* Array of IPAddr */ |
| static ARR_Instance init_sources; |
| |
| static int enable_manual=0; |
| |
| /* Flag set if the RTC runs UTC (default is it runs local time |
| incl. daylight saving). */ |
| static int rtc_on_utc = 0; |
| |
| /* Filename used to read the hwclock(8) LOCAL/UTC setting */ |
| static char *hwclock_file; |
| |
| /* Flag set if the RTC should be automatically synchronised by kernel */ |
| static int rtc_sync = 0; |
| |
| /* Limit and threshold for clock stepping */ |
| static int make_step_limit = 0; |
| static double make_step_threshold = 0.0; |
| |
| /* Threshold for automatic RTC trimming */ |
| static double rtc_autotrim_threshold = 0.0; |
| |
| /* Minimum number of selectables sources required to update the clock */ |
| static int min_sources = 1; |
| |
| /* Number of updates before offset checking, number of ignored updates |
| before exiting and the maximum allowed offset */ |
| static int max_offset_delay = -1; |
| static int max_offset_ignore; |
| static double max_offset; |
| |
| /* Maximum and minimum number of samples per source */ |
| static int max_samples = 0; /* no limit */ |
| static int min_samples = 6; |
| |
| /* Threshold for a time adjustment to be logged to syslog */ |
| static double log_change_threshold = 1.0; |
| |
| static char *mail_user_on_change = NULL; |
| static double mail_change_threshold = 0.0; |
| |
| /* Flag indicating that we don't want to log clients, e.g. to save |
| memory */ |
| static int no_client_log = 0; |
| |
| /* Limit memory allocated for the clients log */ |
| static unsigned long client_log_limit = 524288; |
| |
| /* Minimum and maximum fallback drift intervals */ |
| static int fb_drift_min = 0; |
| static int fb_drift_max = 0; |
| |
| /* IP addresses for binding the NTP server sockets to. UNSPEC family means |
| INADDR_ANY will be used */ |
| static IPAddr bind_address4, bind_address6; |
| |
| /* IP addresses for binding the NTP client sockets to. UNSPEC family means |
| INADDR_ANY will be used */ |
| static IPAddr bind_acq_address4, bind_acq_address6; |
| |
| /* IP addresses for binding the command socket to. UNSPEC family means |
| the loopback address will be used */ |
| static IPAddr bind_cmd_address4, bind_cmd_address6; |
| |
| /* Interface names to bind the NTP server, NTP client, and command socket */ |
| static char *bind_ntp_iface = NULL; |
| static char *bind_acq_iface = NULL; |
| static char *bind_cmd_iface = NULL; |
| |
| /* Path to the Unix domain command socket. */ |
| static char *bind_cmd_path = NULL; |
| |
| /* Differentiated Services Code Point (DSCP) in transmitted NTP packets */ |
| static int ntp_dscp = 0; |
| |
| /* Path to Samba (ntp_signd) socket. */ |
| static char *ntp_signd_socket = NULL; |
| |
| /* Filename to use for storing pid of running chronyd, to prevent multiple |
| * chronyds being started. */ |
| static char *pidfile = NULL; |
| |
| /* Rate limiting parameters */ |
| static int ntp_ratelimit_enabled = 0; |
| static int ntp_ratelimit_interval = 3; |
| static int ntp_ratelimit_burst = 8; |
| static int ntp_ratelimit_leak = 2; |
| static int nts_ratelimit_enabled = 0; |
| static int nts_ratelimit_interval = 6; |
| static int nts_ratelimit_burst = 8; |
| static int nts_ratelimit_leak = 2; |
| static int cmd_ratelimit_enabled = 0; |
| static int cmd_ratelimit_interval = -4; |
| static int cmd_ratelimit_burst = 8; |
| static int cmd_ratelimit_leak = 2; |
| |
| /* Smoothing constants */ |
| static double smooth_max_freq = 0.0; /* in ppm */ |
| static double smooth_max_wander = 0.0; /* in ppm/s */ |
| static int smooth_leap_only = 0; |
| |
| /* Temperature sensor, update interval and compensation coefficients */ |
| static char *tempcomp_sensor_file = NULL; |
| static char *tempcomp_point_file = NULL; |
| static double tempcomp_interval; |
| static double tempcomp_T0, tempcomp_k0, tempcomp_k1, tempcomp_k2; |
| |
| static int sched_priority = 0; |
| static int lock_memory = 0; |
| |
| /* Leap second handling mode */ |
| static REF_LeapMode leapsec_mode = REF_LeapModeSystem; |
| |
| /* Name of a system timezone containing leap seconds occuring at midnight */ |
| static char *leapsec_tz = NULL; |
| |
| /* Name of the user to which will be dropped root privileges. */ |
| static char *user; |
| |
| /* NTS server and client configuration */ |
| static char *nts_dump_dir = NULL; |
| static char *nts_ntp_server = NULL; |
| static ARR_Instance nts_server_cert_files; /* array of (char *) */ |
| static ARR_Instance nts_server_key_files; /* array of (char *) */ |
| static int nts_server_port = NKE_PORT; |
| static int nts_server_processes = 1; |
| static int nts_server_connections = 100; |
| static int nts_refresh = 2419200; /* 4 weeks */ |
| static int nts_rotate = 604800; /* 1 week */ |
| static ARR_Instance nts_trusted_certs_paths; /* array of (char *) */ |
| static ARR_Instance nts_trusted_certs_ids; /* array of uint32_t */ |
| |
| /* Number of clock updates needed to enable certificate time checks */ |
| static int no_cert_time_check = 0; |
| |
| /* Flag disabling use of system trusted certificates */ |
| static int no_system_cert = 0; |
| |
| /* Array of CNF_HwTsInterface */ |
| static ARR_Instance hwts_interfaces; |
| |
| /* PTP event port (disabled by default) */ |
| static int ptp_port = 0; |
| |
| typedef struct { |
| NTP_Source_Type type; |
| int pool; |
| CPS_NTP_Source params; |
| } NTP_Source; |
| |
| /* Array of NTP_Source */ |
| static ARR_Instance ntp_sources; |
| /* Array of (char *) */ |
| static ARR_Instance ntp_source_dirs; |
| /* Array of uint32_t corresponding to ntp_sources (for sourcedirs reload) */ |
| static ARR_Instance ntp_source_ids; |
| |
| /* Array of RefclockParameters */ |
| static ARR_Instance refclock_sources; |
| |
| typedef struct _AllowDeny { |
| IPAddr ip; |
| int subnet_bits; |
| int all; /* 1 to override existing more specific defns */ |
| int allow; /* 0 for deny, 1 for allow */ |
| } AllowDeny; |
| |
| /* Arrays of AllowDeny */ |
| static ARR_Instance ntp_restrictions; |
| static ARR_Instance cmd_restrictions; |
| |
| typedef struct { |
| NTP_Remote_Address addr; |
| int interval; |
| } NTP_Broadcast_Destination; |
| |
| /* Array of NTP_Broadcast_Destination */ |
| static ARR_Instance broadcasts; |
| |
| /* ================================================== */ |
| |
| /* The line number in the configuration file being processed */ |
| static int line_number; |
| static const char *processed_file; |
| static const char *processed_command; |
| |
| static int include_level = 0; |
| |
| /* ================================================== */ |
| |
| static void |
| command_parse_error(void) |
| { |
| LOG_FATAL("Could not parse %s directive at line %d%s%s", |
| processed_command, line_number, processed_file ? " in file " : "", |
| processed_file ? processed_file : ""); |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| other_parse_error(const char *message) |
| { |
| LOG_FATAL("%s at line %d%s%s", |
| message, line_number, processed_file ? " in file " : "", |
| processed_file ? processed_file : ""); |
| } |
| |
| /* ================================================== */ |
| |
| static int |
| get_number_of_args(char *line) |
| { |
| int num = 0; |
| |
| /* The line is normalized, between arguments is just one space */ |
| if (*line == ' ') |
| line++; |
| if (*line) |
| num++; |
| for (; *line; line++) { |
| if (*line == ' ') |
| num++; |
| } |
| |
| return num; |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| check_number_of_args(char *line, int num) |
| { |
| num -= get_number_of_args(line); |
| |
| if (num) { |
| LOG_FATAL("%s arguments for %s directive at line %d%s%s", |
| num > 0 ? "Missing" : "Too many", |
| processed_command, line_number, processed_file ? " in file " : "", |
| processed_file ? processed_file : ""); |
| } |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_Initialise(int r, int client_only) |
| { |
| restarted = r; |
| |
| hwts_interfaces = ARR_CreateInstance(sizeof (CNF_HwTsInterface)); |
| |
| init_sources = ARR_CreateInstance(sizeof (IPAddr)); |
| ntp_sources = ARR_CreateInstance(sizeof (NTP_Source)); |
| ntp_source_dirs = ARR_CreateInstance(sizeof (char *)); |
| ntp_source_ids = ARR_CreateInstance(sizeof (uint32_t)); |
| refclock_sources = ARR_CreateInstance(sizeof (RefclockParameters)); |
| broadcasts = ARR_CreateInstance(sizeof (NTP_Broadcast_Destination)); |
| |
| ntp_restrictions = ARR_CreateInstance(sizeof (AllowDeny)); |
| cmd_restrictions = ARR_CreateInstance(sizeof (AllowDeny)); |
| |
| nts_server_cert_files = ARR_CreateInstance(sizeof (char *)); |
| nts_server_key_files = ARR_CreateInstance(sizeof (char *)); |
| nts_trusted_certs_paths = ARR_CreateInstance(sizeof (char *)); |
| nts_trusted_certs_ids = ARR_CreateInstance(sizeof (uint32_t)); |
| |
| rtc_device = Strdup(DEFAULT_RTC_DEVICE); |
| hwclock_file = Strdup(DEFAULT_HWCLOCK_FILE); |
| user = Strdup(DEFAULT_USER); |
| |
| if (client_only) { |
| cmd_port = ntp_port = 0; |
| } else { |
| bind_cmd_path = Strdup(DEFAULT_COMMAND_SOCKET); |
| pidfile = Strdup(DEFAULT_PID_FILE); |
| } |
| |
| SCK_GetAnyLocalIPAddress(IPADDR_INET4, &bind_address4); |
| SCK_GetAnyLocalIPAddress(IPADDR_INET6, &bind_address6); |
| SCK_GetAnyLocalIPAddress(IPADDR_INET4, &bind_acq_address4); |
| SCK_GetAnyLocalIPAddress(IPADDR_INET6, &bind_acq_address6); |
| SCK_GetLoopbackIPAddress(IPADDR_INET4, &bind_cmd_address4); |
| SCK_GetLoopbackIPAddress(IPADDR_INET6, &bind_cmd_address6); |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_Finalise(void) |
| { |
| unsigned int i; |
| |
| for (i = 0; i < ARR_GetSize(hwts_interfaces); i++) |
| Free(((CNF_HwTsInterface *)ARR_GetElement(hwts_interfaces, i))->name); |
| ARR_DestroyInstance(hwts_interfaces); |
| |
| for (i = 0; i < ARR_GetSize(ntp_sources); i++) |
| Free(((NTP_Source *)ARR_GetElement(ntp_sources, i))->params.name); |
| for (i = 0; i < ARR_GetSize(ntp_source_dirs); i++) |
| Free(*(char **)ARR_GetElement(ntp_source_dirs, i)); |
| for (i = 0; i < ARR_GetSize(refclock_sources); i++) { |
| Free(((RefclockParameters *)ARR_GetElement(refclock_sources, i))->driver_name); |
| Free(((RefclockParameters *)ARR_GetElement(refclock_sources, i))->driver_parameter); |
| } |
| for (i = 0; i < ARR_GetSize(nts_server_cert_files); i++) |
| Free(*(char **)ARR_GetElement(nts_server_cert_files, i)); |
| for (i = 0; i < ARR_GetSize(nts_server_key_files); i++) |
| Free(*(char **)ARR_GetElement(nts_server_key_files, i)); |
| for (i = 0; i < ARR_GetSize(nts_trusted_certs_paths); i++) |
| Free(*(char **)ARR_GetElement(nts_trusted_certs_paths, i)); |
| |
| ARR_DestroyInstance(init_sources); |
| ARR_DestroyInstance(ntp_sources); |
| ARR_DestroyInstance(ntp_source_dirs); |
| ARR_DestroyInstance(ntp_source_ids); |
| ARR_DestroyInstance(refclock_sources); |
| ARR_DestroyInstance(broadcasts); |
| |
| ARR_DestroyInstance(ntp_restrictions); |
| ARR_DestroyInstance(cmd_restrictions); |
| |
| ARR_DestroyInstance(nts_server_cert_files); |
| ARR_DestroyInstance(nts_server_key_files); |
| ARR_DestroyInstance(nts_trusted_certs_paths); |
| ARR_DestroyInstance(nts_trusted_certs_ids); |
| |
| Free(drift_file); |
| Free(dumpdir); |
| Free(hwclock_file); |
| Free(keys_file); |
| Free(leapsec_tz); |
| Free(logdir); |
| Free(bind_ntp_iface); |
| Free(bind_acq_iface); |
| Free(bind_cmd_iface); |
| Free(bind_cmd_path); |
| Free(ntp_signd_socket); |
| Free(pidfile); |
| Free(rtc_device); |
| Free(rtc_file); |
| Free(user); |
| Free(mail_user_on_change); |
| Free(tempcomp_sensor_file); |
| Free(tempcomp_point_file); |
| Free(nts_dump_dir); |
| Free(nts_ntp_server); |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_EnablePrint(void) |
| { |
| print_config = 1; |
| } |
| |
| /* ================================================== */ |
| |
| /* Read the configuration file */ |
| void |
| CNF_ReadFile(const char *filename) |
| { |
| FILE *in; |
| char line[MAX_LINE_LENGTH + 1]; |
| int i; |
| |
| include_level++; |
| if (include_level > MAX_INCLUDE_LEVEL) |
| LOG_FATAL("Maximum include level reached"); |
| |
| in = UTI_OpenFile(NULL, filename, NULL, 'R', 0); |
| |
| for (i = 1; fgets(line, sizeof(line), in); i++) { |
| CNF_ParseLine(filename, i, line); |
| } |
| |
| fclose(in); |
| |
| include_level--; |
| } |
| |
| /* ================================================== */ |
| |
| /* Parse one configuration line */ |
| void |
| CNF_ParseLine(const char *filename, int number, char *line) |
| { |
| char *p, *command; |
| |
| /* Set global variables used in error messages */ |
| processed_file = filename; |
| line_number = number; |
| |
| /* Detect truncated line */ |
| if (strlen(line) >= MAX_LINE_LENGTH) |
| other_parse_error("String too long"); |
| |
| /* Remove extra white-space and comments */ |
| CPS_NormalizeLine(line); |
| |
| /* Skip blank lines */ |
| if (!*line) { |
| processed_file = NULL; |
| return; |
| } |
| |
| /* We have a real line, now try to match commands */ |
| processed_command = command = line; |
| p = CPS_SplitWord(line); |
| |
| if (print_config && strcasecmp(command, "include") && strcasecmp(command, "confdir")) |
| printf("%s%s%s\n", command, p[0] != '\0' ? " " : "", p); |
| |
| if (!strcasecmp(command, "acquisitionport")) { |
| parse_int(p, &acquisition_port); |
| } else if (!strcasecmp(command, "allow")) { |
| parse_allow_deny(p, ntp_restrictions, 1); |
| } else if (!strcasecmp(command, "authselectmode")) { |
| parse_authselectmode(p); |
| } else if (!strcasecmp(command, "bindacqaddress")) { |
| parse_bindacqaddress(p); |
| } else if (!strcasecmp(command, "bindacqdevice")) { |
| parse_string(p, &bind_acq_iface); |
| } else if (!strcasecmp(command, "bindaddress")) { |
| parse_bindaddress(p); |
| } else if (!strcasecmp(command, "bindcmdaddress")) { |
| parse_bindcmdaddress(p); |
| } else if (!strcasecmp(command, "bindcmddevice")) { |
| parse_string(p, &bind_cmd_iface); |
| } else if (!strcasecmp(command, "binddevice")) { |
| parse_string(p, &bind_ntp_iface); |
| } else if (!strcasecmp(command, "broadcast")) { |
| parse_broadcast(p); |
| } else if (!strcasecmp(command, "clientloglimit")) { |
| parse_clientloglimit(p); |
| } else if (!strcasecmp(command, "clockprecision")) { |
| parse_double(p, &clock_precision); |
| } else if (!strcasecmp(command, "cmdallow")) { |
| parse_allow_deny(p, cmd_restrictions, 1); |
| } else if (!strcasecmp(command, "cmddeny")) { |
| parse_allow_deny(p, cmd_restrictions, 0); |
| } else if (!strcasecmp(command, "cmdport")) { |
| parse_int(p, &cmd_port); |
| } else if (!strcasecmp(command, "cmdratelimit")) { |
| parse_ratelimit(p, &cmd_ratelimit_enabled, &cmd_ratelimit_interval, |
| &cmd_ratelimit_burst, &cmd_ratelimit_leak); |
| } else if (!strcasecmp(command, "combinelimit")) { |
| parse_double(p, &combine_limit); |
| } else if (!strcasecmp(command, "confdir")) { |
| parse_confdir(p); |
| } else if (!strcasecmp(command, "corrtimeratio")) { |
| parse_double(p, &correction_time_ratio); |
| } else if (!strcasecmp(command, "deny")) { |
| parse_allow_deny(p, ntp_restrictions, 0); |
| } else if (!strcasecmp(command, "driftfile")) { |
| parse_string(p, &drift_file); |
| } else if (!strcasecmp(command, "dscp")) { |
| parse_int(p, &ntp_dscp); |
| } else if (!strcasecmp(command, "dumpdir")) { |
| parse_string(p, &dumpdir); |
| } else if (!strcasecmp(command, "dumponexit")) { |
| /* Silently ignored */ |
| } else if (!strcasecmp(command, "fallbackdrift")) { |
| parse_fallbackdrift(p); |
| } else if (!strcasecmp(command, "hwclockfile")) { |
| parse_string(p, &hwclock_file); |
| } else if (!strcasecmp(command, "hwtimestamp")) { |
| parse_hwtimestamp(p); |
| } else if (!strcasecmp(command, "include")) { |
| parse_include(p); |
| } else if (!strcasecmp(command, "initstepslew")) { |
| parse_initstepslew(p); |
| } else if (!strcasecmp(command, "keyfile")) { |
| parse_string(p, &keys_file); |
| } else if (!strcasecmp(command, "leapsecmode")) { |
| parse_leapsecmode(p); |
| } else if (!strcasecmp(command, "leapsectz")) { |
| parse_string(p, &leapsec_tz); |
| } else if (!strcasecmp(command, "local")) { |
| parse_local(p); |
| } else if (!strcasecmp(command, "lock_all")) { |
| lock_memory = parse_null(p); |
| } else if (!strcasecmp(command, "log")) { |
| parse_log(p); |
| } else if (!strcasecmp(command, "logbanner")) { |
| parse_int(p, &log_banner); |
| } else if (!strcasecmp(command, "logchange")) { |
| parse_double(p, &log_change_threshold); |
| } else if (!strcasecmp(command, "logdir")) { |
| parse_string(p, &logdir); |
| } else if (!strcasecmp(command, "mailonchange")) { |
| parse_mailonchange(p); |
| } else if (!strcasecmp(command, "makestep")) { |
| parse_makestep(p); |
| } else if (!strcasecmp(command, "manual")) { |
| enable_manual = parse_null(p); |
| } else if (!strcasecmp(command, "maxchange")) { |
| parse_maxchange(p); |
| } else if (!strcasecmp(command, "maxclockerror")) { |
| parse_double(p, &max_clock_error); |
| } else if (!strcasecmp(command, "maxdistance")) { |
| parse_double(p, &max_distance); |
| } else if (!strcasecmp(command, "maxdrift")) { |
| parse_double(p, &max_drift); |
| } else if (!strcasecmp(command, "maxjitter")) { |
| parse_double(p, &max_jitter); |
| } else if (!strcasecmp(command, "maxntsconnections")) { |
| parse_int(p, &nts_server_connections); |
| } else if (!strcasecmp(command, "maxsamples")) { |
| parse_int(p, &max_samples); |
| } else if (!strcasecmp(command, "maxslewrate")) { |
| parse_double(p, &max_slew_rate); |
| } else if (!strcasecmp(command, "maxupdateskew")) { |
| parse_double(p, &max_update_skew); |
| } else if (!strcasecmp(command, "minsamples")) { |
| parse_int(p, &min_samples); |
| } else if (!strcasecmp(command, "minsources")) { |
| parse_int(p, &min_sources); |
| } else if (!strcasecmp(command, "nocerttimecheck")) { |
| parse_int(p, &no_cert_time_check); |
| } else if (!strcasecmp(command, "noclientlog")) { |
| no_client_log = parse_null(p); |
| } else if (!strcasecmp(command, "nosystemcert")) { |
| no_system_cert = parse_null(p); |
| } else if (!strcasecmp(command, "ntpsigndsocket")) { |
| parse_string(p, &ntp_signd_socket); |
| } else if (!strcasecmp(command, "ntsratelimit")) { |
| parse_ratelimit(p, &nts_ratelimit_enabled, &nts_ratelimit_interval, |
| &nts_ratelimit_burst, &nts_ratelimit_leak); |
| } else if (!strcasecmp(command, "ntscachedir") || |
| !strcasecmp(command, "ntsdumpdir")) { |
| parse_string(p, &nts_dump_dir); |
| } else if (!strcasecmp(command, "ntsntpserver")) { |
| parse_string(p, &nts_ntp_server); |
| } else if (!strcasecmp(command, "ntsport")) { |
| parse_int(p, &nts_server_port); |
| } else if (!strcasecmp(command, "ntsprocesses")) { |
| parse_int(p, &nts_server_processes); |
| } else if (!strcasecmp(command, "ntsrefresh")) { |
| parse_int(p, &nts_refresh); |
| } else if (!strcasecmp(command, "ntsrotate")) { |
| parse_int(p, &nts_rotate); |
| } else if (!strcasecmp(command, "ntsservercert")) { |
| parse_ntsserver(p, nts_server_cert_files); |
| } else if (!strcasecmp(command, "ntsserverkey")) { |
| parse_ntsserver(p, nts_server_key_files); |
| } else if (!strcasecmp(command, "ntstrustedcerts")) { |
| parse_ntstrustedcerts(p); |
| } else if (!strcasecmp(command, "peer")) { |
| parse_source(p, command, 1); |
| } else if (!strcasecmp(command, "pidfile")) { |
| parse_string(p, &pidfile); |
| } else if (!strcasecmp(command, "pool")) { |
| parse_source(p, command, 1); |
| } else if (!strcasecmp(command, "port")) { |
| parse_int(p, &ntp_port); |
| } else if (!strcasecmp(command, "ptpport")) { |
| parse_int(p, &ptp_port); |
| } else if (!strcasecmp(command, "ratelimit")) { |
| parse_ratelimit(p, &ntp_ratelimit_enabled, &ntp_ratelimit_interval, |
| &ntp_ratelimit_burst, &ntp_ratelimit_leak); |
| } else if (!strcasecmp(command, "refclock")) { |
| parse_refclock(p); |
| } else if (!strcasecmp(command, "reselectdist")) { |
| parse_double(p, &reselect_distance); |
| } else if (!strcasecmp(command, "rtcautotrim")) { |
| parse_double(p, &rtc_autotrim_threshold); |
| } else if (!strcasecmp(command, "rtcdevice")) { |
| parse_string(p, &rtc_device); |
| } else if (!strcasecmp(command, "rtcfile")) { |
| parse_string(p, &rtc_file); |
| } else if (!strcasecmp(command, "rtconutc")) { |
| rtc_on_utc = parse_null(p); |
| } else if (!strcasecmp(command, "rtcsync")) { |
| rtc_sync = parse_null(p); |
| } else if (!strcasecmp(command, "sched_priority")) { |
| parse_int(p, &sched_priority); |
| } else if (!strcasecmp(command, "server")) { |
| parse_source(p, command, 1); |
| } else if (!strcasecmp(command, "smoothtime")) { |
| parse_smoothtime(p); |
| } else if (!strcasecmp(command, "sourcedir")) { |
| parse_sourcedir(p); |
| } else if (!strcasecmp(command, "stratumweight")) { |
| parse_double(p, &stratum_weight); |
| } else if (!strcasecmp(command, "tempcomp")) { |
| parse_tempcomp(p); |
| } else if (!strcasecmp(command, "user")) { |
| parse_string(p, &user); |
| } else if (!strcasecmp(command, "commandkey") || |
| !strcasecmp(command, "generatecommandkey") || |
| !strcasecmp(command, "linux_freq_scale") || |
| !strcasecmp(command, "linux_hz")) { |
| LOG(LOGS_WARN, "%s directive is no longer supported", command); |
| } else { |
| other_parse_error("Invalid directive"); |
| } |
| |
| processed_file = processed_command = NULL; |
| } |
| |
| /* ================================================== */ |
| |
| static int |
| parse_string(char *line, char **result) |
| { |
| check_number_of_args(line, 1); |
| Free(*result); |
| *result = Strdup(line); |
| return 1; |
| } |
| |
| /* ================================================== */ |
| |
| static int |
| parse_int(char *line, int *result) |
| { |
| check_number_of_args(line, 1); |
| if (sscanf(line, "%d", result) != 1) { |
| command_parse_error(); |
| return 0; |
| } |
| return 1; |
| } |
| |
| /* ================================================== */ |
| |
| static int |
| parse_double(char *line, double *result) |
| { |
| check_number_of_args(line, 1); |
| if (sscanf(line, "%lf", result) != 1) { |
| command_parse_error(); |
| return 0; |
| } |
| return 1; |
| } |
| |
| /* ================================================== */ |
| |
| static int |
| parse_null(char *line) |
| { |
| check_number_of_args(line, 0); |
| return 1; |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_source(char *line, char *type, int fatal) |
| { |
| NTP_Source source; |
| |
| if (strcasecmp(type, "peer") == 0) { |
| source.type = NTP_PEER; |
| source.pool = 0; |
| } else if (strcasecmp(type, "pool") == 0) { |
| source.type = NTP_SERVER; |
| source.pool = 1; |
| } else if (strcasecmp(type, "server") == 0) { |
| source.type = NTP_SERVER; |
| source.pool = 0; |
| } else { |
| if (fatal) |
| command_parse_error(); |
| return; |
| } |
| |
| /* Avoid comparing uninitialized data in compare_sources() */ |
| memset(&source.params, 0, sizeof (source.params)); |
| |
| if (!CPS_ParseNTPSourceAdd(line, &source.params)) { |
| if (fatal) |
| command_parse_error(); |
| return; |
| } |
| |
| source.params.name = Strdup(source.params.name); |
| ARR_AppendElement(ntp_sources, &source); |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_sourcedir(char *line) |
| { |
| char *s; |
| |
| s = Strdup(line); |
| ARR_AppendElement(ntp_source_dirs, &s); |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_ratelimit(char *line, int *enabled, int *interval, int *burst, int *leak) |
| { |
| int n, val; |
| char *opt; |
| |
| *enabled = 1; |
| |
| while (*line) { |
| opt = line; |
| line = CPS_SplitWord(line); |
| if (sscanf(line, "%d%n", &val, &n) != 1) { |
| command_parse_error(); |
| return; |
| } |
| line += n; |
| if (!strcasecmp(opt, "interval")) |
| *interval = val; |
| else if (!strcasecmp(opt, "burst")) |
| *burst = val; |
| else if (!strcasecmp(opt, "leak")) |
| *leak = val; |
| else |
| command_parse_error(); |
| } |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_refclock(char *line) |
| { |
| int n, poll, dpoll, filter_length, pps_rate, min_samples, max_samples, sel_options; |
| int max_lock_age, pps_forced, stratum, tai; |
| uint32_t ref_id, lock_ref_id; |
| double offset, delay, precision, max_dispersion, pulse_width; |
| char *p, *cmd, *name, *param; |
| unsigned char ref[5]; |
| RefclockParameters *refclock; |
| |
| poll = 4; |
| dpoll = 0; |
| filter_length = 64; |
| pps_forced = 0; |
| pps_rate = 0; |
| min_samples = SRC_DEFAULT_MINSAMPLES; |
| max_samples = SRC_DEFAULT_MAXSAMPLES; |
| sel_options = 0; |
| offset = 0.0; |
| delay = 1e-9; |
| precision = 0.0; |
| max_dispersion = 0.0; |
| pulse_width = 0.0; |
| ref_id = 0; |
| max_lock_age = 2; |
| lock_ref_id = 0; |
| stratum = 0; |
| tai = 0; |
| |
| if (!*line) { |
| command_parse_error(); |
| return; |
| } |
| |
| p = line; |
| line = CPS_SplitWord(line); |
| |
| if (!*line) { |
| command_parse_error(); |
| return; |
| } |
| |
| name = Strdup(p); |
| |
| p = line; |
| line = CPS_SplitWord(line); |
| param = Strdup(p); |
| |
| for (cmd = line; *cmd; line += n, cmd = line) { |
| line = CPS_SplitWord(line); |
| |
| if (!strcasecmp(cmd, "refid")) { |
| if (sscanf(line, "%4s%n", (char *)ref, &n) != 1) |
| break; |
| ref_id = (uint32_t)ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3]; |
| } else if (!strcasecmp(cmd, "lock")) { |
| if (sscanf(line, "%4s%n", (char *)ref, &n) != 1) |
| break; |
| lock_ref_id = (uint32_t)ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3]; |
| } else if (!strcasecmp(cmd, "poll")) { |
| if (sscanf(line, "%d%n", &poll, &n) != 1) { |
| break; |
| } |
| } else if (!strcasecmp(cmd, "dpoll")) { |
| if (sscanf(line, "%d%n", &dpoll, &n) != 1) { |
| break; |
| } |
| } else if (!strcasecmp(cmd, "filter")) { |
| if (sscanf(line, "%d%n", &filter_length, &n) != 1) { |
| break; |
| } |
| } else if (!strcasecmp(cmd, "rate")) { |
| if (sscanf(line, "%d%n", &pps_rate, &n) != 1) |
| break; |
| } else if (!strcasecmp(cmd, "minsamples")) { |
| if (sscanf(line, "%d%n", &min_samples, &n) != 1) |
| break; |
| } else if (!strcasecmp(cmd, "maxlockage")) { |
| if (sscanf(line, "%d%n", &max_lock_age, &n) != 1) |
| break; |
| } else if (!strcasecmp(cmd, "maxsamples")) { |
| if (sscanf(line, "%d%n", &max_samples, &n) != 1) |
| break; |
| } else if (!strcasecmp(cmd, "offset")) { |
| if (sscanf(line, "%lf%n", &offset, &n) != 1) |
| break; |
| } else if (!strcasecmp(cmd, "delay")) { |
| if (sscanf(line, "%lf%n", &delay, &n) != 1) |
| break; |
| } else if (!strcasecmp(cmd, "pps")) { |
| n = 0; |
| pps_forced = 1; |
| } else if (!strcasecmp(cmd, "precision")) { |
| if (sscanf(line, "%lf%n", &precision, &n) != 1) |
| break; |
| } else if (!strcasecmp(cmd, "maxdispersion")) { |
| if (sscanf(line, "%lf%n", &max_dispersion, &n) != 1) |
| break; |
| } else if (!strcasecmp(cmd, "stratum")) { |
| if (sscanf(line, "%d%n", &stratum, &n) != 1 || |
| stratum >= NTP_MAX_STRATUM || stratum < 0) |
| break; |
| } else if (!strcasecmp(cmd, "tai")) { |
| n = 0; |
| tai = 1; |
| } else if (!strcasecmp(cmd, "width")) { |
| if (sscanf(line, "%lf%n", &pulse_width, &n) != 1) |
| break; |
| } else if (!strcasecmp(cmd, "noselect")) { |
| n = 0; |
| sel_options |= SRC_SELECT_NOSELECT; |
| } else if (!strcasecmp(cmd, "prefer")) { |
| n = 0; |
| sel_options |= SRC_SELECT_PREFER; |
| } else if (!strcasecmp(cmd, "trust")) { |
| n = 0; |
| sel_options |= SRC_SELECT_TRUST; |
| } else if (!strcasecmp(cmd, "require")) { |
| n = 0; |
| sel_options |= SRC_SELECT_REQUIRE; |
| } else { |
| other_parse_error("Invalid refclock option"); |
| return; |
| } |
| } |
| |
| if (*cmd) { |
| command_parse_error(); |
| return; |
| } |
| |
| refclock = (RefclockParameters *)ARR_GetNewElement(refclock_sources); |
| refclock->driver_name = name; |
| refclock->driver_parameter = param; |
| refclock->driver_poll = dpoll; |
| refclock->poll = poll; |
| refclock->filter_length = filter_length; |
| refclock->pps_forced = pps_forced; |
| refclock->pps_rate = pps_rate; |
| refclock->min_samples = min_samples; |
| refclock->max_samples = max_samples; |
| refclock->sel_options = sel_options; |
| refclock->stratum = stratum; |
| refclock->tai = tai; |
| refclock->offset = offset; |
| refclock->delay = delay; |
| refclock->precision = precision; |
| refclock->max_dispersion = max_dispersion; |
| refclock->pulse_width = pulse_width; |
| refclock->ref_id = ref_id; |
| refclock->max_lock_age = max_lock_age; |
| refclock->lock_ref_id = lock_ref_id; |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_log(char *line) |
| { |
| char *log_name; |
| do { |
| log_name = line; |
| line = CPS_SplitWord(line); |
| if (*log_name) { |
| if (!strcmp(log_name, "rawmeasurements")) { |
| do_log_measurements = 1; |
| raw_measurements = 1; |
| } else if (!strcmp(log_name, "measurements")) { |
| do_log_measurements = 1; |
| } else if (!strcmp(log_name, "statistics")) { |
| do_log_statistics = 1; |
| } else if (!strcmp(log_name, "tracking")) { |
| do_log_tracking = 1; |
| } else if (!strcmp(log_name, "rtc")) { |
| do_log_rtc = 1; |
| } else if (!strcmp(log_name, "refclocks")) { |
| do_log_refclocks = 1; |
| } else if (!strcmp(log_name, "tempcomp")) { |
| do_log_tempcomp = 1; |
| } else { |
| other_parse_error("Invalid log parameter"); |
| break; |
| } |
| } else { |
| break; |
| } |
| } while (1); |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_local(char *line) |
| { |
| if (!CPS_ParseLocal(line, &local_stratum, &local_orphan, &local_distance)) |
| command_parse_error(); |
| enable_local = 1; |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_initstepslew(char *line) |
| { |
| char *p, *hostname; |
| IPAddr ip_addr; |
| |
| /* Ignore the line if chronyd was started with -R. */ |
| if (restarted) { |
| return; |
| } |
| |
| ARR_SetSize(init_sources, 0); |
| p = CPS_SplitWord(line); |
| |
| if (sscanf(line, "%lf", &init_slew_threshold) != 1) { |
| command_parse_error(); |
| return; |
| } |
| |
| while (*p) { |
| hostname = p; |
| p = CPS_SplitWord(p); |
| if (*hostname) { |
| if (DNS_Name2IPAddress(hostname, &ip_addr, 1) == DNS_Success) { |
| ARR_AppendElement(init_sources, &ip_addr); |
| } else { |
| LOG(LOGS_WARN, "Could not resolve address of initstepslew server %s", hostname); |
| } |
| } |
| } |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_leapsecmode(char *line) |
| { |
| if (!strcasecmp(line, "system")) |
| leapsec_mode = REF_LeapModeSystem; |
| else if (!strcasecmp(line, "slew")) |
| leapsec_mode = REF_LeapModeSlew; |
| else if (!strcasecmp(line, "step")) |
| leapsec_mode = REF_LeapModeStep; |
| else if (!strcasecmp(line, "ignore")) |
| leapsec_mode = REF_LeapModeIgnore; |
| else |
| command_parse_error(); |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_clientloglimit(char *line) |
| { |
| check_number_of_args(line, 1); |
| if (sscanf(line, "%lu", &client_log_limit) != 1) { |
| command_parse_error(); |
| } |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_fallbackdrift(char *line) |
| { |
| check_number_of_args(line, 2); |
| if (sscanf(line, "%d %d", &fb_drift_min, &fb_drift_max) != 2) { |
| command_parse_error(); |
| } |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_makestep(char *line) |
| { |
| check_number_of_args(line, 2); |
| if (sscanf(line, "%lf %d", &make_step_threshold, &make_step_limit) != 2) { |
| make_step_limit = 0; |
| command_parse_error(); |
| } |
| |
| /* Disable limited makestep if chronyd was started with -R. */ |
| if (restarted && make_step_limit > 0) { |
| make_step_limit = 0; |
| } |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_maxchange(char *line) |
| { |
| check_number_of_args(line, 3); |
| if (sscanf(line, "%lf %d %d", &max_offset, &max_offset_delay, &max_offset_ignore) != 3) { |
| max_offset_delay = -1; |
| command_parse_error(); |
| } |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_mailonchange(char *line) |
| { |
| char *address; |
| check_number_of_args(line, 2); |
| address = line; |
| line = CPS_SplitWord(line); |
| Free(mail_user_on_change); |
| if (sscanf(line, "%lf", &mail_change_threshold) == 1) { |
| mail_user_on_change = Strdup(address); |
| } else { |
| mail_user_on_change = NULL; |
| command_parse_error(); |
| } |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_ntsserver(char *line, ARR_Instance files) |
| { |
| char *file = NULL; |
| |
| parse_string(line, &file); |
| ARR_AppendElement(files, &file); |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_ntstrustedcerts(char *line) |
| { |
| uint32_t id; |
| char *path; |
| |
| if (get_number_of_args(line) == 2) { |
| path = CPS_SplitWord(line); |
| if (sscanf(line, "%"SCNu32, &id) != 1) |
| command_parse_error(); |
| } else { |
| check_number_of_args(line, 1); |
| path = line; |
| id = 0; |
| } |
| |
| path = Strdup(path); |
| |
| ARR_AppendElement(nts_trusted_certs_paths, &path); |
| ARR_AppendElement(nts_trusted_certs_ids, &id); |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_allow_deny(char *line, ARR_Instance restrictions, int allow) |
| { |
| int all, subnet_bits; |
| AllowDeny *node; |
| IPAddr ip; |
| |
| if (!CPS_ParseAllowDeny(line, &all, &ip, &subnet_bits)) |
| command_parse_error(); |
| |
| node = ARR_GetNewElement(restrictions); |
| node->allow = allow; |
| node->all = all; |
| node->ip = ip; |
| node->subnet_bits = subnet_bits; |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_authselectmode(char *line) |
| { |
| if (!strcasecmp(line, "require")) |
| authselect_mode = SRC_AUTHSELECT_REQUIRE; |
| else if (!strcasecmp(line, "prefer")) |
| authselect_mode = SRC_AUTHSELECT_PREFER; |
| else if (!strcasecmp(line, "mix")) |
| authselect_mode = SRC_AUTHSELECT_MIX; |
| else if (!strcasecmp(line, "ignore")) |
| authselect_mode = SRC_AUTHSELECT_IGNORE; |
| else |
| command_parse_error(); |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_bindacqaddress(char *line) |
| { |
| IPAddr ip; |
| |
| check_number_of_args(line, 1); |
| if (UTI_StringToIP(line, &ip)) { |
| if (ip.family == IPADDR_INET4) |
| bind_acq_address4 = ip; |
| else if (ip.family == IPADDR_INET6) |
| bind_acq_address6 = ip; |
| } else { |
| command_parse_error(); |
| } |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_bindaddress(char *line) |
| { |
| IPAddr ip; |
| |
| check_number_of_args(line, 1); |
| if (UTI_StringToIP(line, &ip)) { |
| if (ip.family == IPADDR_INET4) |
| bind_address4 = ip; |
| else if (ip.family == IPADDR_INET6) |
| bind_address6 = ip; |
| } else { |
| command_parse_error(); |
| } |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_bindcmdaddress(char *line) |
| { |
| IPAddr ip; |
| |
| check_number_of_args(line, 1); |
| |
| /* Address starting with / is for the Unix domain socket */ |
| if (line[0] == '/') { |
| parse_string(line, &bind_cmd_path); |
| /* / disables the socket */ |
| if (strcmp(bind_cmd_path, "/") == 0) { |
| Free(bind_cmd_path); |
| bind_cmd_path = NULL; |
| } |
| } else if (UTI_StringToIP(line, &ip)) { |
| if (ip.family == IPADDR_INET4) |
| bind_cmd_address4 = ip; |
| else if (ip.family == IPADDR_INET6) |
| bind_cmd_address6 = ip; |
| } else { |
| command_parse_error(); |
| } |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_broadcast(char *line) |
| { |
| /* Syntax : broadcast <interval> <broadcast-IP-addr> [<port>] */ |
| NTP_Broadcast_Destination *destination; |
| int port; |
| int interval; |
| char *p; |
| IPAddr ip; |
| |
| p = line; |
| line = CPS_SplitWord(line); |
| |
| if (sscanf(p, "%d", &interval) != 1) { |
| command_parse_error(); |
| return; |
| } |
| |
| p = line; |
| line = CPS_SplitWord(line); |
| |
| if (!UTI_StringToIP(p, &ip)) { |
| command_parse_error(); |
| return; |
| } |
| |
| p = line; |
| line = CPS_SplitWord(line); |
| |
| if (*p) { |
| if (sscanf(p, "%d", &port) != 1 || *line) { |
| command_parse_error(); |
| return; |
| } |
| } else { |
| /* default port */ |
| port = NTP_PORT; |
| } |
| |
| destination = (NTP_Broadcast_Destination *)ARR_GetNewElement(broadcasts); |
| destination->addr.ip_addr = ip; |
| destination->addr.port = port; |
| destination->interval = interval; |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_smoothtime(char *line) |
| { |
| if (get_number_of_args(line) != 3) |
| check_number_of_args(line, 2); |
| |
| if (sscanf(line, "%lf %lf", &smooth_max_freq, &smooth_max_wander) != 2) { |
| smooth_max_freq = 0.0; |
| command_parse_error(); |
| } |
| |
| line = CPS_SplitWord(CPS_SplitWord(line)); |
| smooth_leap_only = 0; |
| |
| if (*line) { |
| if (!strcasecmp(line, "leaponly")) |
| smooth_leap_only = 1; |
| else |
| command_parse_error(); |
| } |
| } |
| |
| /* ================================================== */ |
| static void |
| parse_tempcomp(char *line) |
| { |
| char *p; |
| int point_form; |
| |
| point_form = get_number_of_args(line) == 3; |
| |
| if (!point_form) |
| check_number_of_args(line, 6); |
| |
| p = line; |
| line = CPS_SplitWord(line); |
| |
| if (!*p) { |
| command_parse_error(); |
| return; |
| } |
| |
| Free(tempcomp_point_file); |
| |
| if (point_form) { |
| if (sscanf(line, "%lf", &tempcomp_interval) != 1) { |
| command_parse_error(); |
| return; |
| } |
| tempcomp_point_file = Strdup(CPS_SplitWord(line)); |
| } else { |
| if (sscanf(line, "%lf %lf %lf %lf %lf", &tempcomp_interval, |
| &tempcomp_T0, &tempcomp_k0, &tempcomp_k1, &tempcomp_k2) != 5) { |
| command_parse_error(); |
| return; |
| } |
| tempcomp_point_file = NULL; |
| } |
| |
| Free(tempcomp_sensor_file); |
| tempcomp_sensor_file = Strdup(p); |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_hwtimestamp(char *line) |
| { |
| CNF_HwTsInterface *iface; |
| char *p, filter[5]; |
| int n; |
| |
| if (!*line) { |
| command_parse_error(); |
| return; |
| } |
| |
| p = line; |
| line = CPS_SplitWord(line); |
| |
| iface = ARR_GetNewElement(hwts_interfaces); |
| iface->name = Strdup(p); |
| iface->minpoll = 0; |
| iface->min_samples = 2; |
| iface->max_samples = 16; |
| iface->nocrossts = 0; |
| iface->rxfilter = CNF_HWTS_RXFILTER_ANY; |
| iface->precision = 100.0e-9; |
| iface->tx_comp = 0.0; |
| iface->rx_comp = 0.0; |
| |
| for (p = line; *p; line += n, p = line) { |
| line = CPS_SplitWord(line); |
| |
| if (!strcasecmp(p, "maxsamples")) { |
| if (sscanf(line, "%d%n", &iface->max_samples, &n) != 1) |
| break; |
| } else if (!strcasecmp(p, "minpoll")) { |
| if (sscanf(line, "%d%n", &iface->minpoll, &n) != 1) |
| break; |
| } else if (!strcasecmp(p, "minsamples")) { |
| if (sscanf(line, "%d%n", &iface->min_samples, &n) != 1) |
| break; |
| } else if (!strcasecmp(p, "precision")) { |
| if (sscanf(line, "%lf%n", &iface->precision, &n) != 1) |
| break; |
| } else if (!strcasecmp(p, "rxcomp")) { |
| if (sscanf(line, "%lf%n", &iface->rx_comp, &n) != 1) |
| break; |
| } else if (!strcasecmp(p, "txcomp")) { |
| if (sscanf(line, "%lf%n", &iface->tx_comp, &n) != 1) |
| break; |
| } else if (!strcasecmp(p, "rxfilter")) { |
| if (sscanf(line, "%4s%n", filter, &n) != 1) |
| break; |
| if (!strcasecmp(filter, "none")) |
| iface->rxfilter = CNF_HWTS_RXFILTER_NONE; |
| else if (!strcasecmp(filter, "ntp")) |
| iface->rxfilter = CNF_HWTS_RXFILTER_NTP; |
| else if (!strcasecmp(filter, "ptp")) |
| iface->rxfilter = CNF_HWTS_RXFILTER_PTP; |
| else if (!strcasecmp(filter, "all")) |
| iface->rxfilter = CNF_HWTS_RXFILTER_ALL; |
| else |
| break; |
| } else if (!strcasecmp(p, "nocrossts")) { |
| n = 0; |
| iface->nocrossts = 1; |
| } else { |
| break; |
| } |
| } |
| |
| if (*p) |
| command_parse_error(); |
| } |
| |
| /* ================================================== */ |
| |
| static const char * |
| get_basename(const char *path) |
| { |
| const char *b = strrchr(path, '/'); |
| return b ? b + 1 : path; |
| } |
| |
| /* ================================================== */ |
| |
| static int |
| compare_basenames(const void *a, const void *b) |
| { |
| return strcmp(get_basename(*(const char * const *)a), |
| get_basename(*(const char * const *)b)); |
| } |
| |
| /* ================================================== */ |
| |
| static int |
| search_dirs(char *line, const char *suffix, void (*file_handler)(const char *path)) |
| { |
| char *dirs[MAX_CONF_DIRS], buf[MAX_LINE_LENGTH], *path; |
| size_t i, j, k, locations, n_dirs; |
| glob_t gl; |
| |
| n_dirs = UTI_SplitString(line, dirs, MAX_CONF_DIRS); |
| if (n_dirs < 1 || n_dirs > MAX_CONF_DIRS) |
| return 0; |
| |
| /* Get the paths of all config files in the specified directories */ |
| for (i = 0; i < n_dirs; i++) { |
| if (snprintf(buf, sizeof (buf), "%s/*%s", dirs[i], suffix) >= sizeof (buf)) |
| assert(0); |
| if (glob(buf, GLOB_NOSORT | (i > 0 ? GLOB_APPEND : 0), NULL, &gl) != 0) |
| ; |
| } |
| |
| if (gl.gl_pathc > 0) { |
| /* Sort the paths by filenames */ |
| qsort(gl.gl_pathv, gl.gl_pathc, sizeof (gl.gl_pathv[0]), compare_basenames); |
| |
| for (i = 0; i < gl.gl_pathc; i += locations) { |
| /* Count directories containing files with this name */ |
| for (j = i + 1, locations = 1; j < gl.gl_pathc; j++, locations++) { |
| if (compare_basenames(&gl.gl_pathv[i], &gl.gl_pathv[j]) != 0) |
| break; |
| } |
| |
| /* Read the first file of this name in the order of the directive */ |
| for (j = 0; j < n_dirs; j++) { |
| for (k = 0; k < locations; k++) { |
| path = gl.gl_pathv[i + k]; |
| if (strncmp(path, dirs[j], strlen(dirs[j])) == 0 && |
| strlen(dirs[j]) + 1 + strlen(get_basename(path)) == strlen(path)) { |
| file_handler(path); |
| break; |
| } |
| } |
| if (k < locations) |
| break; |
| } |
| } |
| } |
| |
| globfree(&gl); |
| |
| return 1; |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_confdir(char *line) |
| { |
| if (!search_dirs(line, ".conf", CNF_ReadFile)) |
| command_parse_error(); |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| parse_include(char *line) |
| { |
| glob_t gl; |
| size_t i; |
| int r; |
| |
| check_number_of_args(line, 1); |
| |
| if ((r = glob(line, |
| #ifdef GLOB_NOMAGIC |
| GLOB_NOMAGIC | |
| #endif |
| GLOB_ERR, NULL, &gl)) != 0) { |
| if (r != GLOB_NOMATCH) |
| LOG_FATAL("Could not search for files matching %s", line); |
| |
| DEBUG_LOG("glob of %s failed", line); |
| return; |
| } |
| |
| for (i = 0; i < gl.gl_pathc; i++) |
| CNF_ReadFile(gl.gl_pathv[i]); |
| |
| globfree(&gl); |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| load_source_file(const char *filename) |
| { |
| char line[MAX_LINE_LENGTH + 1]; |
| FILE *f; |
| |
| f = UTI_OpenFile(NULL, filename, NULL, 'r', 0); |
| if (!f) |
| return; |
| |
| while (fgets(line, sizeof (line), f)) { |
| /* Require lines to be terminated */ |
| if (line[0] == '\0' || line[strlen(line) - 1] != '\n') |
| break; |
| |
| CPS_NormalizeLine(line); |
| if (line[0] == '\0') |
| continue; |
| |
| parse_source(CPS_SplitWord(line), line, 0); |
| } |
| |
| fclose(f); |
| } |
| |
| /* ================================================== */ |
| |
| static int |
| compare_sources(const void *a, const void *b) |
| { |
| const NTP_Source *sa = a, *sb = b; |
| int d; |
| |
| if (!sa->params.name) |
| return -1; |
| if (!sb->params.name) |
| return 1; |
| if ((d = strcmp(sa->params.name, sb->params.name)) != 0) |
| return d; |
| if ((d = (int)(sa->type) - (int)(sb->type)) != 0) |
| return d; |
| if ((d = sa->pool - sb->pool) != 0) |
| return d; |
| if ((d = sa->params.port - sb->params.port) != 0) |
| return d; |
| return memcmp(&sa->params.params, &sb->params.params, sizeof (sa->params.params)); |
| } |
| |
| /* ================================================== */ |
| |
| static void |
| reload_source_dirs(void) |
| { |
| NTP_Source *prev_sources, *new_sources, *source; |
| unsigned int i, j, prev_size, new_size, unresolved; |
| uint32_t *prev_ids, *new_ids; |
| char buf[MAX_LINE_LENGTH]; |
| NSR_Status s; |
| int d; |
| |
| prev_size = ARR_GetSize(ntp_source_ids); |
| if (prev_size > 0 && ARR_GetSize(ntp_sources) != prev_size) |
| assert(0); |
| |
| /* Save the current sources and their configuration IDs */ |
| prev_ids = MallocArray(uint32_t, prev_size); |
| memcpy(prev_ids, ARR_GetElements(ntp_source_ids), prev_size * sizeof (prev_ids[0])); |
| prev_sources = MallocArray(NTP_Source, prev_size); |
| memcpy(prev_sources, ARR_GetElements(ntp_sources), prev_size * sizeof (prev_sources[0])); |
| |
| /* Load the sources again */ |
| ARR_SetSize(ntp_sources, 0); |
| for (i = 0; i < ARR_GetSize(ntp_source_dirs); i++) { |
| if (snprintf(buf, sizeof (buf), "%s", |
| *(char **)ARR_GetElement(ntp_source_dirs, i)) >= sizeof (buf)) |
| assert(0); |
| search_dirs(buf, ".sources", load_source_file); |
| } |
| |
| /* Add new and remove existing sources according to the new configuration. |
| Avoid removing and adding the same source again to keep its state. */ |
| |
| new_size = ARR_GetSize(ntp_sources); |
| new_sources = ARR_GetElements(ntp_sources); |
| ARR_SetSize(ntp_source_ids, new_size); |
| new_ids = ARR_GetElements(ntp_source_ids); |
| unresolved = 0; |
| |
| qsort(new_sources, new_size, sizeof (new_sources[0]), compare_sources); |
| |
| for (i = j = 0; i < prev_size || j < new_size; ) { |
| if (i < prev_size && j < new_size) |
| d = compare_sources(&prev_sources[i], &new_sources[j]); |
| else |
| d = i < prev_size ? -1 : 1; |
| |
| if (d < 0) { |
| /* Remove the missing source */ |
| if (prev_sources[i].params.name[0] != '\0') |
| NSR_RemoveSourcesById(prev_ids[i]); |
| i++; |
| } else if (d > 0) { |
| /* Add a newly configured source */ |
| source = &new_sources[j]; |
| s = NSR_AddSourceByName(source->params.name, source->params.port, source->pool, |
| source->type, &source->params.params, &new_ids[j]); |
| |
| if (s == NSR_UnresolvedName) { |
| unresolved++; |
| } else if (s != NSR_Success) { |
| LOG(LOGS_ERR, "Could not add source %s", source->params.name); |
| |
| /* Mark the source as not present */ |
| source->params.name[0] = '\0'; |
| } |
| j++; |
| } else { |
| /* Keep the existing source */ |
| new_ids[j] = prev_ids[i]; |
| i++, j++; |
| } |
| } |
| |
| for (i = 0; i < prev_size; i++) |
| Free(prev_sources[i].params.name); |
| Free(prev_sources); |
| Free(prev_ids); |
| |
| if (unresolved > 0) |
| NSR_ResolveSources(); |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_CreateDirs(uid_t uid, gid_t gid) |
| { |
| char *dir; |
| |
| /* Create a directory for the Unix domain command socket */ |
| if (bind_cmd_path) { |
| dir = UTI_PathToDir(bind_cmd_path); |
| UTI_CreateDirAndParents(dir, 0770, uid, gid); |
| |
| /* Check the permissions and owner/group in case the directory already |
| existed. It MUST NOT be accessible by others as permissions on Unix |
| domain sockets are ignored on some systems (e.g. Solaris). */ |
| if (!UTI_CheckDirPermissions(dir, 0770, uid, gid)) { |
| LOG(LOGS_WARN, "Disabled command socket %s", bind_cmd_path); |
| Free(bind_cmd_path); |
| bind_cmd_path = NULL; |
| } |
| |
| Free(dir); |
| } |
| |
| if (logdir) |
| UTI_CreateDirAndParents(logdir, 0750, uid, gid); |
| if (dumpdir) |
| UTI_CreateDirAndParents(dumpdir, 0750, uid, gid); |
| if (nts_dump_dir) |
| UTI_CreateDirAndParents(nts_dump_dir, 0750, uid, gid); |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_AddInitSources(void) |
| { |
| CPS_NTP_Source cps_source; |
| NTP_Remote_Address ntp_addr; |
| char dummy_hostname[2] = "H"; |
| unsigned int i; |
| |
| for (i = 0; i < ARR_GetSize(init_sources); i++) { |
| /* Get the default NTP params */ |
| CPS_ParseNTPSourceAdd(dummy_hostname, &cps_source); |
| |
| /* Add the address as a server specified with the iburst option */ |
| ntp_addr.ip_addr = *(IPAddr *)ARR_GetElement(init_sources, i); |
| ntp_addr.port = cps_source.port; |
| cps_source.params.iburst = 1; |
| |
| if (NSR_AddSource(&ntp_addr, NTP_SERVER, &cps_source.params, NULL) != NSR_Success) |
| LOG(LOGS_ERR, "Could not add source %s", UTI_IPToString(&ntp_addr.ip_addr)); |
| } |
| |
| ARR_SetSize(init_sources, 0); |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_AddSources(void) |
| { |
| NTP_Source *source; |
| unsigned int i; |
| NSR_Status s; |
| |
| for (i = 0; i < ARR_GetSize(ntp_sources); i++) { |
| source = (NTP_Source *)ARR_GetElement(ntp_sources, i); |
| |
| s = NSR_AddSourceByName(source->params.name, source->params.port, source->pool, |
| source->type, &source->params.params, NULL); |
| if (s != NSR_Success && s != NSR_UnresolvedName) |
| LOG(LOGS_ERR, "Could not add source %s", source->params.name); |
| |
| Free(source->params.name); |
| } |
| |
| ARR_SetSize(ntp_sources, 0); |
| |
| reload_source_dirs(); |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_AddRefclocks(void) |
| { |
| RefclockParameters *refclock; |
| unsigned int i; |
| |
| for (i = 0; i < ARR_GetSize(refclock_sources); i++) { |
| refclock = ARR_GetElement(refclock_sources, i); |
| RCL_AddRefclock(refclock); |
| Free(refclock->driver_name); |
| Free(refclock->driver_parameter); |
| } |
| |
| ARR_SetSize(refclock_sources, 0); |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_AddBroadcasts(void) |
| { |
| unsigned int i; |
| NTP_Broadcast_Destination *destination; |
| |
| for (i = 0; i < ARR_GetSize(broadcasts); i++) { |
| destination = (NTP_Broadcast_Destination *)ARR_GetElement(broadcasts, i); |
| NCR_AddBroadcastDestination(&destination->addr, destination->interval); |
| } |
| |
| ARR_SetSize(broadcasts, 0); |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_ReloadSources(void) |
| { |
| reload_source_dirs(); |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetNTPPort(void) |
| { |
| return ntp_port; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetAcquisitionPort(void) |
| { |
| return acquisition_port; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetDriftFile(void) |
| { |
| return drift_file; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetLogBanner(void) |
| { |
| return log_banner; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetLogDir(void) |
| { |
| return logdir; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetDumpDir(void) |
| { |
| return dumpdir; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetLogMeasurements(int *raw) |
| { |
| *raw = raw_measurements; |
| return do_log_measurements; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetLogStatistics(void) |
| { |
| return do_log_statistics; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetLogTracking(void) |
| { |
| return do_log_tracking; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetLogRtc(void) |
| { |
| return do_log_rtc; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetLogRefclocks(void) |
| { |
| return do_log_refclocks; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetLogTempComp(void) |
| { |
| return do_log_tempcomp; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetKeysFile(void) |
| { |
| return keys_file; |
| } |
| |
| /* ================================================== */ |
| |
| double |
| CNF_GetRtcAutotrim(void) |
| { |
| return rtc_autotrim_threshold; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetRtcFile(void) |
| { |
| return rtc_file; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetRtcDevice(void) |
| { |
| return rtc_device; |
| } |
| |
| /* ================================================== */ |
| |
| double |
| CNF_GetMaxUpdateSkew(void) |
| { |
| return max_update_skew; |
| } |
| |
| /* ================================================== */ |
| |
| double |
| CNF_GetMaxDrift(void) |
| { |
| return max_drift; |
| } |
| |
| /* ================================================== */ |
| |
| double |
| CNF_GetMaxClockError(void) |
| { |
| return max_clock_error; |
| } |
| |
| /* ================================================== */ |
| |
| double |
| CNF_GetCorrectionTimeRatio(void) |
| { |
| return correction_time_ratio; |
| } |
| |
| /* ================================================== */ |
| |
| SRC_AuthSelectMode |
| CNF_GetAuthSelectMode(void) |
| { |
| return authselect_mode; |
| } |
| |
| /* ================================================== */ |
| |
| double |
| CNF_GetMaxSlewRate(void) |
| { |
| return max_slew_rate; |
| } |
| |
| /* ================================================== */ |
| |
| double |
| CNF_GetClockPrecision(void) |
| { |
| return clock_precision; |
| } |
| |
| /* ================================================== */ |
| |
| double |
| CNF_GetMaxDistance(void) |
| { |
| return max_distance; |
| } |
| |
| /* ================================================== */ |
| |
| double |
| CNF_GetMaxJitter(void) |
| { |
| return max_jitter; |
| } |
| |
| /* ================================================== */ |
| |
| double |
| CNF_GetReselectDistance(void) |
| { |
| return reselect_distance; |
| } |
| |
| /* ================================================== */ |
| |
| double |
| CNF_GetStratumWeight(void) |
| { |
| return stratum_weight; |
| } |
| |
| /* ================================================== */ |
| |
| double |
| CNF_GetCombineLimit(void) |
| { |
| return combine_limit; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetManualEnabled(void) |
| { |
| return enable_manual; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetCommandPort(void) { |
| return cmd_port; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_AllowLocalReference(int *stratum, int *orphan, double *distance) |
| { |
| if (enable_local) { |
| *stratum = local_stratum; |
| *orphan = local_orphan; |
| *distance = local_distance; |
| return 1; |
| } else { |
| return 0; |
| } |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetRtcOnUtc(void) |
| { |
| return rtc_on_utc; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetRtcSync(void) |
| { |
| return rtc_sync; |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_GetMakeStep(int *limit, double *threshold) |
| { |
| *limit = make_step_limit; |
| *threshold = make_step_threshold; |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_GetMaxChange(int *delay, int *ignore, double *offset) |
| { |
| *delay = max_offset_delay; |
| *ignore = max_offset_ignore; |
| *offset = max_offset; |
| } |
| |
| /* ================================================== */ |
| |
| double |
| CNF_GetLogChange(void) |
| { |
| return log_change_threshold; |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_GetMailOnChange(int *enabled, double *threshold, char **user) |
| { |
| if (mail_user_on_change) { |
| *enabled = 1; |
| *threshold = mail_change_threshold; |
| *user = mail_user_on_change; |
| } else { |
| *enabled = 0; |
| *threshold = 0.0; |
| *user = NULL; |
| } |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_SetupAccessRestrictions(void) |
| { |
| AllowDeny *node; |
| int status; |
| unsigned int i; |
| |
| for (i = 0; i < ARR_GetSize(ntp_restrictions); i++) { |
| node = ARR_GetElement(ntp_restrictions, i); |
| status = NCR_AddAccessRestriction(&node->ip, node->subnet_bits, node->allow, node->all); |
| if (!status) { |
| LOG_FATAL("Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits); |
| } |
| } |
| |
| for (i = 0; i < ARR_GetSize(cmd_restrictions); i++) { |
| node = ARR_GetElement(cmd_restrictions, i); |
| status = CAM_AddAccessRestriction(&node->ip, node->subnet_bits, node->allow, node->all); |
| if (!status) { |
| LOG_FATAL("Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits); |
| } |
| } |
| |
| ARR_SetSize(ntp_restrictions, 0); |
| ARR_SetSize(cmd_restrictions, 0); |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetNoClientLog(void) |
| { |
| return no_client_log; |
| } |
| |
| /* ================================================== */ |
| |
| unsigned long |
| CNF_GetClientLogLimit(void) |
| { |
| return client_log_limit; |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_GetFallbackDrifts(int *min, int *max) |
| { |
| *min = fb_drift_min; |
| *max = fb_drift_max; |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_GetBindAddress(int family, IPAddr *addr) |
| { |
| if (family == IPADDR_INET4) |
| *addr = bind_address4; |
| else if (family == IPADDR_INET6) |
| *addr = bind_address6; |
| else |
| addr->family = IPADDR_UNSPEC; |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_GetBindAcquisitionAddress(int family, IPAddr *addr) |
| { |
| if (family == IPADDR_INET4) |
| *addr = bind_acq_address4; |
| else if (family == IPADDR_INET6) |
| *addr = bind_acq_address6; |
| else |
| addr->family = IPADDR_UNSPEC; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetBindNtpInterface(void) |
| { |
| return bind_ntp_iface; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetBindAcquisitionInterface(void) |
| { |
| return bind_acq_iface; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetBindCommandInterface(void) |
| { |
| return bind_cmd_iface; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetBindCommandPath(void) |
| { |
| return bind_cmd_path; |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_GetBindCommandAddress(int family, IPAddr *addr) |
| { |
| if (family == IPADDR_INET4) |
| *addr = bind_cmd_address4; |
| else if (family == IPADDR_INET6) |
| *addr = bind_cmd_address6; |
| else |
| addr->family = IPADDR_UNSPEC; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetNtpDscp(void) |
| { |
| return ntp_dscp; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetNtpSigndSocket(void) |
| { |
| return ntp_signd_socket; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetPidFile(void) |
| { |
| return pidfile; |
| } |
| |
| /* ================================================== */ |
| |
| REF_LeapMode |
| CNF_GetLeapSecMode(void) |
| { |
| return leapsec_mode; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetLeapSecTimezone(void) |
| { |
| return leapsec_tz; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetSchedPriority(void) |
| { |
| return sched_priority; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetLockMemory(void) |
| { |
| return lock_memory; |
| } |
| |
| /* ================================================== */ |
| |
| int CNF_GetNTPRateLimit(int *interval, int *burst, int *leak) |
| { |
| *interval = ntp_ratelimit_interval; |
| *burst = ntp_ratelimit_burst; |
| *leak = ntp_ratelimit_leak; |
| return ntp_ratelimit_enabled; |
| } |
| |
| /* ================================================== */ |
| |
| int CNF_GetNtsRateLimit(int *interval, int *burst, int *leak) |
| { |
| *interval = nts_ratelimit_interval; |
| *burst = nts_ratelimit_burst; |
| *leak = nts_ratelimit_leak; |
| return nts_ratelimit_enabled; |
| } |
| |
| /* ================================================== */ |
| |
| int CNF_GetCommandRateLimit(int *interval, int *burst, int *leak) |
| { |
| *interval = cmd_ratelimit_interval; |
| *burst = cmd_ratelimit_burst; |
| *leak = cmd_ratelimit_leak; |
| return cmd_ratelimit_enabled; |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only) |
| { |
| *max_freq = smooth_max_freq; |
| *max_wander = smooth_max_wander; |
| *leap_only = smooth_leap_only; |
| } |
| |
| /* ================================================== */ |
| |
| void |
| CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2) |
| { |
| *file = tempcomp_sensor_file; |
| *point_file = tempcomp_point_file; |
| *interval = tempcomp_interval; |
| *T0 = tempcomp_T0; |
| *k0 = tempcomp_k0; |
| *k1 = tempcomp_k1; |
| *k2 = tempcomp_k2; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetUser(void) |
| { |
| return user; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetMaxSamples(void) |
| { |
| return max_samples; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetMinSamples(void) |
| { |
| return min_samples; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetMinSources(void) |
| { |
| return min_sources; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetHwclockFile(void) |
| { |
| return hwclock_file; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetInitSources(void) |
| { |
| return ARR_GetSize(init_sources); |
| } |
| |
| /* ================================================== */ |
| |
| double |
| CNF_GetInitStepThreshold(void) |
| { |
| return init_slew_threshold; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface) |
| { |
| if (index >= ARR_GetSize(hwts_interfaces)) |
| return 0; |
| |
| *iface = (CNF_HwTsInterface *)ARR_GetElement(hwts_interfaces, index); |
| return 1; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetPtpPort(void) |
| { |
| return ptp_port; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetNtsDumpDir(void) |
| { |
| return nts_dump_dir; |
| } |
| |
| /* ================================================== */ |
| |
| char * |
| CNF_GetNtsNtpServer(void) |
| { |
| return nts_ntp_server; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetNtsServerCertAndKeyFiles(const char ***certs, const char ***keys) |
| { |
| *certs = ARR_GetElements(nts_server_cert_files); |
| *keys = ARR_GetElements(nts_server_key_files); |
| |
| if (ARR_GetSize(nts_server_cert_files) != ARR_GetSize(nts_server_key_files)) |
| LOG_FATAL("Uneven number of NTS certs and keys"); |
| |
| return ARR_GetSize(nts_server_cert_files); |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetNtsServerPort(void) |
| { |
| return nts_server_port; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetNtsServerProcesses(void) |
| { |
| return nts_server_processes; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetNtsServerConnections(void) |
| { |
| return nts_server_connections; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetNtsRefresh(void) |
| { |
| return nts_refresh; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetNtsRotate(void) |
| { |
| return nts_rotate; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetNtsTrustedCertsPaths(const char ***paths, uint32_t **ids) |
| { |
| *paths = ARR_GetElements(nts_trusted_certs_paths); |
| *ids = ARR_GetElements(nts_trusted_certs_ids); |
| |
| if (ARR_GetSize(nts_trusted_certs_paths) != ARR_GetSize(nts_trusted_certs_ids)) |
| assert(0); |
| |
| return ARR_GetSize(nts_trusted_certs_paths); |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetNoSystemCert(void) |
| { |
| return no_system_cert; |
| } |
| |
| /* ================================================== */ |
| |
| int |
| CNF_GetNoCertTimeCheck(void) |
| { |
| return no_cert_time_check; |
| } |