A new option can be now used in the pool directive: maxsources sets the maximum number of sources that can be used from the pool, the default value is 4. On start, when the pool name is resolved, chronyd will add up to 16 sources, one for each resolved address. When the number of sources from which at least one valid reply was received reaches maxsources, the other sources will be removed.
285 lines
7.5 KiB
C
285 lines
7.5 KiB
C
/*
|
|
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
|
|
|
**********************************************************************
|
|
* Copyright (C) Richard P. Curnow 1997-2003
|
|
* Copyright (C) Miroslav Lichvar 2013
|
|
*
|
|
* 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 for parsing various forms of directive and command lines that
|
|
are common to the configuration file and to the command client.
|
|
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "sysincl.h"
|
|
|
|
#include "cmdparse.h"
|
|
#include "memory.h"
|
|
#include "nameserv.h"
|
|
#include "ntp.h"
|
|
#include "util.h"
|
|
|
|
/* ================================================== */
|
|
|
|
CPS_Status
|
|
CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
|
{
|
|
char *hostname, *cmd;
|
|
int n, done;
|
|
CPS_Status result;
|
|
|
|
src->port = SRC_DEFAULT_PORT;
|
|
src->params.minpoll = SRC_DEFAULT_MINPOLL;
|
|
src->params.maxpoll = SRC_DEFAULT_MAXPOLL;
|
|
src->params.presend_minpoll = SRC_DEFAULT_PRESEND_MINPOLL;
|
|
src->params.authkey = INACTIVE_AUTHKEY;
|
|
src->params.max_delay = SRC_DEFAULT_MAXDELAY;
|
|
src->params.max_delay_ratio = SRC_DEFAULT_MAXDELAYRATIO;
|
|
src->params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
|
|
src->params.online = 1;
|
|
src->params.auto_offline = 0;
|
|
src->params.iburst = 0;
|
|
src->params.min_stratum = SRC_DEFAULT_MINSTRATUM;
|
|
src->params.poll_target = SRC_DEFAULT_POLLTARGET;
|
|
src->params.version = NTP_VERSION;
|
|
src->params.max_sources = SRC_DEFAULT_MAXSOURCES;
|
|
src->params.sel_option = SRC_SelectNormal;
|
|
|
|
result = CPS_Success;
|
|
|
|
hostname = line;
|
|
line = CPS_SplitWord(line);
|
|
|
|
if (!*hostname) {
|
|
result = CPS_BadHost;
|
|
} else {
|
|
src->name = hostname;
|
|
|
|
/* Parse subfields */
|
|
done = 0;
|
|
do {
|
|
cmd = line;
|
|
line = CPS_SplitWord(line);
|
|
|
|
if (*cmd) {
|
|
if (!strcasecmp(cmd, "port")) {
|
|
if (sscanf(line, "%hu%n", &src->port, &n) != 1) {
|
|
result = CPS_BadPort;
|
|
done = 1;
|
|
} else {
|
|
line += n;
|
|
}
|
|
} else if (!strcasecmp(cmd, "minpoll")) {
|
|
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1) {
|
|
result = CPS_BadMinpoll;
|
|
done = 1;
|
|
} else {
|
|
line += n;
|
|
}
|
|
} else if (!strcasecmp(cmd, "maxpoll")) {
|
|
if (sscanf(line, "%d%n", &src->params.maxpoll, &n) != 1) {
|
|
result = CPS_BadMaxpoll;
|
|
done = 1;
|
|
} else {
|
|
line += n;
|
|
}
|
|
} else if (!strcasecmp(cmd, "presend")) {
|
|
if (sscanf(line, "%d%n", &src->params.presend_minpoll, &n) != 1) {
|
|
result = CPS_BadPresend;
|
|
done = 1;
|
|
} else {
|
|
line += n;
|
|
}
|
|
} else if (!strcasecmp(cmd, "maxdelaydevratio")) {
|
|
if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1) {
|
|
result = CPS_BadMaxdelaydevratio;
|
|
done = 1;
|
|
} else {
|
|
line += n;
|
|
}
|
|
} else if (!strcasecmp(cmd, "maxdelayratio")) {
|
|
if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1) {
|
|
result = CPS_BadMaxdelayratio;
|
|
done = 1;
|
|
} else {
|
|
line += n;
|
|
}
|
|
} else if (!strcasecmp(cmd, "maxdelay")) {
|
|
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1) {
|
|
result = CPS_BadMaxdelay;
|
|
done = 1;
|
|
} else {
|
|
line += n;
|
|
}
|
|
} else if (!strcasecmp(cmd, "key")) {
|
|
if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
|
|
src->params.authkey == INACTIVE_AUTHKEY) {
|
|
result = CPS_BadKey;
|
|
done = 1;
|
|
} else {
|
|
line += n;
|
|
}
|
|
} else if (!strcasecmp(cmd, "offline")) {
|
|
src->params.online = 0;
|
|
|
|
} else if (!strcasecmp(cmd, "auto_offline")) {
|
|
src->params.auto_offline = 1;
|
|
|
|
} else if (!strcasecmp(cmd, "iburst")) {
|
|
src->params.iburst = 1;
|
|
|
|
} else if (!strcasecmp(cmd, "minstratum")) {
|
|
if (sscanf(line, "%d%n", &src->params.min_stratum, &n) != 1) {
|
|
result = CPS_BadMinstratum;
|
|
done = 1;
|
|
} else {
|
|
line += n;
|
|
}
|
|
|
|
} else if (!strcasecmp(cmd, "polltarget")) {
|
|
if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1) {
|
|
result = CPS_BadPolltarget;
|
|
done = 1;
|
|
} else {
|
|
line += n;
|
|
}
|
|
|
|
} else if (!strcasecmp(cmd, "noselect")) {
|
|
src->params.sel_option = SRC_SelectNoselect;
|
|
|
|
} else if (!strcasecmp(cmd, "prefer")) {
|
|
src->params.sel_option = SRC_SelectPrefer;
|
|
|
|
} else if (!strcasecmp(cmd, "version")) {
|
|
if (sscanf(line, "%d%n", &src->params.version, &n) != 1) {
|
|
result = CPS_BadVersion;
|
|
done = 1;
|
|
} else {
|
|
line += n;
|
|
}
|
|
|
|
} else if (!strcasecmp(cmd, "maxsources")) {
|
|
if (sscanf(line, "%d%n", &src->params.max_sources, &n) != 1) {
|
|
result = CPS_BadMaxsources;
|
|
done = 1;
|
|
} else {
|
|
line += n;
|
|
}
|
|
|
|
} else {
|
|
result = CPS_BadOption;
|
|
done = 1;
|
|
}
|
|
} else {
|
|
done = 1;
|
|
}
|
|
} while (!done);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CPS_NormalizeLine(char *line)
|
|
{
|
|
char *p, *q;
|
|
int space = 1, first = 1;
|
|
|
|
/* Remove white-space at beginning and replace white-spaces with space char */
|
|
for (p = q = line; *p; p++) {
|
|
if (isspace((unsigned char)*p)) {
|
|
if (!space)
|
|
*q++ = ' ';
|
|
space = 1;
|
|
continue;
|
|
}
|
|
|
|
/* Discard comment lines */
|
|
if (first && strchr("!;#%", *p))
|
|
break;
|
|
|
|
*q++ = *p;
|
|
space = first = 0;
|
|
}
|
|
|
|
/* Strip trailing space */
|
|
if (q > line && q[-1] == ' ')
|
|
q--;
|
|
|
|
*q = '\0';
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
char *
|
|
CPS_SplitWord(char *line)
|
|
{
|
|
char *p = line, *q = line;
|
|
|
|
/* Skip white-space before the word */
|
|
while (*q && isspace((unsigned char)*q))
|
|
q++;
|
|
|
|
/* Move the word to the beginning */
|
|
while (*q && !isspace((unsigned char)*q))
|
|
*p++ = *q++;
|
|
|
|
/* Find the next word */
|
|
while (*q && isspace((unsigned char)*q))
|
|
q++;
|
|
|
|
*p = '\0';
|
|
|
|
/* Return pointer to the next word or NUL */
|
|
return q;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CPS_ParseKey(char *line, uint32_t *id, const char **hash, char **key)
|
|
{
|
|
char *s1, *s2, *s3, *s4;
|
|
|
|
s1 = line;
|
|
s2 = CPS_SplitWord(s1);
|
|
s3 = CPS_SplitWord(s2);
|
|
s4 = CPS_SplitWord(s3);
|
|
|
|
/* Require two or three words */
|
|
if (!*s2 || *s4)
|
|
return 0;
|
|
|
|
if (sscanf(s1, "%"SCNu32, id) != 1)
|
|
return 0;
|
|
|
|
if (*s3) {
|
|
*hash = s2;
|
|
*key = s3;
|
|
} else {
|
|
*hash = "MD5";
|
|
*key = s2;
|
|
}
|
|
|
|
return 1;
|
|
}
|