diff --git a/.gitignore b/.gitignore
index 987eddf..8069dde 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
-SOURCES/clknetsim-e63178.tar.gz
-SOURCES/linuxptp-20140718gitbdb6a3.tar.gz
-SOURCES/testsuite-7c523f.tar.gz
+SOURCES/clknetsim-ce89a1.tar.gz
+SOURCES/linuxptp-1.8.tgz
+SOURCES/linuxptp-testsuite-502e82.tar.gz
diff --git a/.linuxptp.metadata b/.linuxptp.metadata
index 8beb86f..bb51355 100644
--- a/.linuxptp.metadata
+++ b/.linuxptp.metadata
@@ -1,3 +1,3 @@
-29583b9a274e1d89e9fdcd400ce427a513a666c9 SOURCES/clknetsim-e63178.tar.gz
-3bbf8fbe1db7b344d5d465728a83abf877a6032f SOURCES/linuxptp-20140718gitbdb6a3.tar.gz
-1d4505f7bac98e143d22b2d84c812f4ec92bb127 SOURCES/testsuite-7c523f.tar.gz
+922f475728383b56b03eeadaf990c9231a51a9e3 SOURCES/clknetsim-ce89a1.tar.gz
+449cf190347d24846440bd757570e391dd7dff96 SOURCES/linuxptp-1.8.tgz
+1b6395c22a47a4af60db6963d063697ef6daae08 SOURCES/linuxptp-testsuite-502e82.tar.gz
diff --git a/SOURCES/linuxptp-closesocket.patch b/SOURCES/linuxptp-closesocket.patch
new file mode 100644
index 0000000..6b27b99
--- /dev/null
+++ b/SOURCES/linuxptp-closesocket.patch
@@ -0,0 +1,38 @@
+commit a3500e14ca4af38034d5ad2115ca7ac271c8c5b4
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date:   Mon Feb 6 15:43:00 2017 +0100
+
+    Fix leaks of sockets on errors.
+    
+    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
+
+diff --git a/clock.c b/clock.c
+index a6a1a1a..9481606 100644
+--- a/clock.c
++++ b/clock.c
+@@ -824,11 +824,13 @@ static int clock_add_port(struct clock *c, int phc_index,
+ 	}
+ 	index = sk_interface_index(fd, iface->name);
+ 	if (index < 0) {
++		close(fd);
+ 		return -1;
+ 	}
+ 	snprintf(key, sizeof(key), "%d", index);
+ 	if (hash_insert(c->index2port, key, p)) {
+ 		pr_err("failed to add port with index %d twice!", index);
++		close(fd);
+ 		return -1;
+ 	}
+ 	close(fd);
+diff --git a/rtnl.c b/rtnl.c
+index 7f5dc45..251b5f3 100644
+--- a/rtnl.c
++++ b/rtnl.c
+@@ -160,6 +160,7 @@ int rtnl_open(void)
+ 	}
+ 	if (bind(fd, (struct sockaddr *) &sa, sizeof(sa))) {
+ 		pr_err("failed to bind netlink socket: %m");
++		close(fd);
+ 		return -1;
+ 	}
+ 	return fd;
diff --git a/SOURCES/linuxptp-linkdown.patch b/SOURCES/linuxptp-linkdown.patch
new file mode 100644
index 0000000..34d1ae3
--- /dev/null
+++ b/SOURCES/linuxptp-linkdown.patch
@@ -0,0 +1,75 @@
+Backport of commit 73318c5b99571c8da01474ad665e2e2e06ab12bb
+Author: Richard Cochran <richardcochran@gmail.com>
+Date:   Sun Feb 5 18:31:27 2017 +0100
+
+    clock: Force a BMC election when a port link goes down.
+    
+    Having one fewer port may affect the result of the BMCA.  This patch
+    changes the main loop so that a link down event also causes a state
+    decision event.
+    
+    Signed-off-by: Richard Cochran <richardcochran@gmail.com>
+    Reported-by: Henry Jesuiter <Henry.Jesuiter@alcnetworx.de>
+
+diff -up linuxptp-1.8/clock.c.linkdown linuxptp-1.8/clock.c
+--- linuxptp-1.8/clock.c.linkdown	2017-03-15 08:37:03.017542152 +0100
++++ linuxptp-1.8/clock.c	2017-03-15 08:42:53.238682318 +0100
+@@ -96,6 +96,7 @@ struct clock {
+ 	int pollfd_valid;
+ 	int nports; /* does not include the UDS port */
+ 	int last_port_number;
++	int sde;
+ 	struct hash *index2port;
+ 	int free_running;
+ 	int freq_est_interval;
+@@ -341,6 +342,11 @@ static void clock_link_status(void *ctx,
+ 		port_dispatch(p, EV_FAULT_CLEARED, 0);
+ 	} else {
+ 		port_dispatch(p, EV_FAULT_DETECTED, 0);
++		/*
++		 * A port going down can affect the BMCA result.
++		 * Force a state decision event.
++		 */
++		c->sde = 1;
+ 	}
+ }
+ 
+@@ -1465,7 +1471,7 @@ struct PortIdentity clock_parent_identit
+ 
+ int clock_poll(struct clock *c)
+ {
+-	int cnt, err, i, sde = 0;
++	int cnt, err, i;
+ 	enum fsm_event event;
+ 	struct pollfd *cur;
+ 	struct port *p;
+@@ -1496,9 +1502,9 @@ int clock_poll(struct clock *c)
+ 			if (cur[i].revents & (POLLIN|POLLPRI)) {
+ 				event = port_event(p, i);
+ 				if (EV_STATE_DECISION_EVENT == event)
+-					sde = 1;
++					c->sde = 1;
+ 				if (EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES == event)
+-					sde = 1;
++					c->sde = 1;
+ 				err = port_dispatch(p, event, 0);
+ 				/* Clear any fault after a little while. */
+ 				if (PS_FAULTY == port_state(p)) {
+@@ -1527,13 +1533,14 @@ int clock_poll(struct clock *c)
+ 		if (cur[i].revents & (POLLIN|POLLPRI)) {
+ 			event = port_event(c->uds_port, i);
+ 			if (EV_STATE_DECISION_EVENT == event)
+-				sde = 1;
++				c->sde = 1;
+ 		}
+ 	}
+ 
+-	if (sde)
++	if (c->sde) {
+ 		handle_state_decision_event(c);
+-
++		c->sde = 0;
++	}
+ 	clock_prune_subscriptions(c);
+ 	return 0;
+ }
diff --git a/SOURCES/linuxptp-linreg_reset.patch b/SOURCES/linuxptp-linreg_reset.patch
deleted file mode 100644
index 24eb16c..0000000
--- a/SOURCES/linuxptp-linreg_reset.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-commit 37459fd1ad1ac48a121ab0edae331090fb8e2833
-Author: Miroslav Lichvar <mlichvar@redhat.com>
-Date:   Thu Nov 20 17:30:28 2014 +0100
-
-    linreg: fix servo resetting
-    
-    The stats for the maximum size were not reset, which caused the
-    the servo to reuse old data instead of returning with unlocked
-    state.
-    
-    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
-
-diff --git a/linreg.c b/linreg.c
-index b94c44e..fde604d 100644
---- a/linreg.c
-+++ b/linreg.c
-@@ -294,7 +294,7 @@ static void linreg_reset(struct servo *servo)
- 	s->last_update = 0;
- 	s->frequency_ratio = 1.0;
- 
--	for (i = MIN_SIZE; i < MAX_SIZE; i++) {
-+	for (i = MIN_SIZE; i <= MAX_SIZE; i++) {
- 		s->results[i - MIN_SIZE].slope = 0.0;
- 		s->results[i - MIN_SIZE].err_updates = 0;
- 	}
diff --git a/SOURCES/linuxptp-messagetag.patch b/SOURCES/linuxptp-messagetag.patch
new file mode 100644
index 0000000..dc9caa8
--- /dev/null
+++ b/SOURCES/linuxptp-messagetag.patch
@@ -0,0 +1,553 @@
+commit 4e8dbd84925d36f1193a7339a542677d884d3ba1
+Author: Richard Cochran <richardcochran@gmail.com>
+Date:   Tue Dec 6 19:40:36 2016 +0100
+
+    ptp4l: Accept any configuration option as a command line argument.
+    
+    This patch provides a way to use the entire table of configuration options
+    as "long" command line switches.
+    
+    Signed-off-by: Richard Cochran <richardcochran@gmail.com>
+
+diff --git a/config.c b/config.c
+index 5da5ecc..384b437 100644
+--- a/config.c
++++ b/config.c
+@@ -329,6 +329,7 @@ static enum parser_result parse_section_line(char *s, enum config_section *secti
+ }
+ 
+ static enum parser_result parse_item(struct config *cfg,
++				     int commandline,
+ 				     const char *section,
+ 				     const char *option,
+ 				     const char *value)
+@@ -387,7 +388,7 @@ static enum parser_result parse_item(struct config *cfg,
+ 				return NOT_PARSED;
+ 			}
+ 		}
+-	} else if (cgi->flags & CFG_ITEM_LOCKED) {
++	} else if (!commandline && cgi->flags & CFG_ITEM_LOCKED) {
+ 		/* This global option was set on the command line. */
+ 		return PARSED_OK;
+ 	} else {
+@@ -415,6 +416,10 @@ static enum parser_result parse_item(struct config *cfg,
+ 		dst->flags |= CFG_ITEM_DYNSTR;
+ 		break;
+ 	}
++
++	if (commandline) {
++		dst->flags &= CFG_ITEM_LOCKED;
++	}
+ 	return PARSED_OK;
+ }
+ 
+@@ -490,6 +495,25 @@ static void check_deprecated_options(const char **option)
+ 	}
+ }
+ 
++static struct option *config_alloc_longopts(struct config *cfg)
++{
++	struct config_item *ci;
++	struct option *opts;
++	int i;
++
++	opts = calloc(1, (1 + N_CONFIG_ITEMS) * sizeof(*opts));
++	if (!opts) {
++		return NULL;
++	}
++	for (i = 0; i < N_CONFIG_ITEMS; i++) {
++		ci = &config_tab[i];
++		opts[i].name = ci->label;
++		opts[i].has_arg = required_argument;
++	}
++
++	return opts;
++}
++
+ int config_read(char *name, struct config *cfg)
+ {
+ 	enum config_section current_section = UNKNOWN_SECTION;
+@@ -554,7 +578,7 @@ int config_read(char *name, struct config *cfg)
+ 
+ 		check_deprecated_options(&option);
+ 
+-		parser_res = parse_item(cfg, current_section == GLOBAL_SECTION ?
++		parser_res = parse_item(cfg, 0, current_section == GLOBAL_SECTION ?
+ 					NULL : current_port->name, option, value);
+ 
+ 		switch (parser_res) {
+@@ -627,8 +651,15 @@ struct config *config_create(void)
+ 	}
+ 	STAILQ_INIT(&cfg->interfaces);
+ 
++	cfg->opts = config_alloc_longopts(cfg);
++	if (!cfg->opts) {
++		free(cfg);
++		return NULL;
++	}
++
+ 	cfg->htab = hash_create();
+ 	if (!cfg->htab) {
++		free(cfg->opts);
+ 		free(cfg);
+ 		return NULL;
+ 	}
+@@ -657,6 +688,7 @@ struct config *config_create(void)
+ 	return cfg;
+ fail:
+ 	hash_destroy(cfg->htab, NULL);
++	free(cfg->opts);
+ 	free(cfg);
+ 	return NULL;
+ }
+@@ -670,6 +702,7 @@ void config_destroy(struct config *cfg)
+ 		free(iface);
+ 	}
+ 	hash_destroy(cfg->htab, config_item_free);
++	free(cfg->opts);
+ 	free(cfg);
+ }
+ 
+@@ -720,6 +753,33 @@ char *config_get_string(struct config *cfg, const char *section,
+ 	return ci->val.s;
+ }
+ 
++int config_parse_option(struct config *cfg, const char *opt, const char *val)
++{
++	enum parser_result result;
++
++	result = parse_item(cfg, 1, NULL, opt, val);
++
++	switch (result) {
++	case PARSED_OK:
++		return 0;
++	case NOT_PARSED:
++		fprintf(stderr, "unknown option %s\n", opt);
++		break;
++	case BAD_VALUE:
++		fprintf(stderr, "%s is a bad value for option %s\n", val, opt);
++		break;
++	case MALFORMED:
++		fprintf(stderr, "%s is a malformed value for option %s\n",
++			val, opt);
++		break;
++	case OUT_OF_RANGE:
++		fprintf(stderr, "%s is an out of range value for option %s\n",
++			val, opt);
++		break;
++	}
++	return -1;
++}
++
+ int config_set_double(struct config *cfg, const char *option, double val)
+ {
+ 	struct config_item *ci = config_find_item(cfg, NULL, option);
+diff --git a/config.h b/config.h
+index b02bde6..1cc7051 100644
+--- a/config.h
++++ b/config.h
+@@ -20,6 +20,7 @@
+ #ifndef HAVE_CONFIG_H
+ #define HAVE_CONFIG_H
+ 
++#include <getopt.h>
+ #include <sys/queue.h>
+ 
+ #include "ds.h"
+@@ -43,6 +44,9 @@ struct config {
+ 	STAILQ_HEAD(interfaces_head, interface) interfaces;
+ 	int n_interfaces;
+ 
++	/* for parsing command line options */
++	struct option *opts;
++
+ 	/* hash of all non-legacy items */
+ 	struct hash *htab;
+ };
+@@ -64,6 +68,13 @@ int config_get_int(struct config *cfg, const char *section,
+ char *config_get_string(struct config *cfg, const char *section,
+ 			const char *option);
+ 
++static inline struct option *config_long_options(struct config *cfg)
++{
++	return cfg->opts;
++}
++
++int config_parse_option(struct config *cfg, const char *opt, const char *val);
++
+ int config_set_double(struct config *cfg, const char *option, double val);
+ 
+ int config_set_section_int(struct config *cfg, const char *section,
+diff --git a/ptp4l.c b/ptp4l.c
+index a87e7e6..e90fcb2 100644
+--- a/ptp4l.c
++++ b/ptp4l.c
+@@ -73,8 +73,9 @@ static void usage(char *progname)
+ int main(int argc, char *argv[])
+ {
+ 	char *config = NULL, *req_phc = NULL, *progname;
+-	int c, err = -1, print_level;
++	int c, err = -1, index, print_level;
+ 	struct clock *clock = NULL;
++	struct option *opts;
+ 	struct config *cfg;
+ 
+ 	if (handle_term_signals())
+@@ -84,12 +85,18 @@ int main(int argc, char *argv[])
+ 	if (!cfg) {
+ 		return -1;
+ 	}
++	opts = config_long_options(cfg);
+ 
+ 	/* Process the command line arguments. */
+ 	progname = strrchr(argv[0], '/');
+ 	progname = progname ? 1+progname : argv[0];
+-	while (EOF != (c = getopt(argc, argv, "AEP246HSLf:i:p:sl:mqvh"))) {
++	while (EOF != (c = getopt_long(argc, argv, "AEP246HSLf:i:p:sl:mqvh",
++				       opts, &index))) {
+ 		switch (c) {
++		case 0:
++			if (config_parse_option(cfg, opts[index].name, optarg))
++				goto out;
++			break;
+ 		case 'A':
+ 			if (config_set_int(cfg, "delay_mechanism", DM_AUTO))
+ 				goto out;
+
+commit e658982624bfd5cd998066fdf35b93cdcf8797ca
+Author: Richard Cochran <rcochran@linutronix.de>
+Date:   Tue Dec 13 19:55:39 2016 +0100
+
+    config: Fix bitwise copy-and-pasto for command line items.
+    
+    The recent change allowing every configuration option to appear on the
+    command line wrongly used bitwise AND to set a flag.  This patch fixes
+    the bug by using the proper bitwise OR idiom.
+    
+    Signed-off-by: Richard Cochran <rcochran@linutronix.de>
+    Reported-by: Miroslav Lichvar <mlichvar@redhat.com>
+    Fixes: 4e8dbd8 ("ptp4l: Accept any configuration option as a command line argument.")
+
+diff --git a/config.c b/config.c
+index 384b437..b19f3ad 100644
+--- a/config.c
++++ b/config.c
+@@ -418,7 +418,7 @@ static enum parser_result parse_item(struct config *cfg,
+ 	}
+ 
+ 	if (commandline) {
+-		dst->flags &= CFG_ITEM_LOCKED;
++		dst->flags |= CFG_ITEM_LOCKED;
+ 	}
+ 	return PARSED_OK;
+ }
+
+commit 4e966536c6253d73e1a3202e8b562ab0f518e33b
+Author: Richard Cochran <rcochran@linutronix.de>
+Date:   Tue Dec 13 20:49:22 2016 +0100
+
+    ptp4l: Document the "long" command line options in the man page.
+    
+    Signed-off-by: Richard Cochran <rcochran@linutronix.de>
+
+diff --git a/ptp4l.8 b/ptp4l.8
+index 63e9abd..f53fc6e 100644
+--- a/ptp4l.8
++++ b/ptp4l.8
+@@ -1,4 +1,4 @@
+-.TH PTP4l 8 "July 2016" "linuxptp"
++.TH PTP4l 8 "December 2016" "linuxptp"
+ .SH NAME
+ ptp4l - PTP Boundary/Ordinary Clock
+ 
+@@ -15,6 +15,8 @@ ptp4l - PTP Boundary/Ordinary Clock
+ ]
+ [
+ .BI \-i " interface"
++] [
++.I long-options
+ ]
+ .I .\|.\|.
+ 
+@@ -94,6 +96,19 @@ Prints the software version and exits.
+ .BI \-h
+ Display a help message.
+ 
++.SH LONG OPTIONS
++
++Each and every configuration file option (see below) may also appear
++as a "long" style command line argument.  For example, the slaveOnly
++option may be set using either of these two forms.
++
++.RS
++\f(CW\-\-slaveOnly 1   \-\-slaveOnly=1\fP
++.RE
++
++Option values given on the command line override values in the global
++section of the configuration file.
++
+ .SH CONFIGURATION FILE
+ 
+ The configuration file is divided into sections. Each section starts with a
+
+commit 0f6c6972c791813e0b9618e9158da3951a099737
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date:   Tue Jan 17 14:17:39 2017 +0100
+
+    Add options to tag ptp4l and phc2sys log messages.
+    
+    When running multiple instances of ptp4l or phc2sys, it's difficult to
+    tell which log message belongs to which instance. Add new options to
+    ptp4l and phc2sys which can specify a tag for all messages printed to
+    the standard output or system log, so messages from different instances
+    can have different tags.
+    
+    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
+
+diff --git a/config.c b/config.c
+index 7bb949d..e6fe676 100644
+--- a/config.c
++++ b/config.c
+@@ -199,6 +199,7 @@ struct config_item config_tab[] = {
+ 	PORT_ITEM_INT("logMinPdelayReqInterval", 0, INT8_MIN, INT8_MAX),
+ 	PORT_ITEM_INT("logSyncInterval", 0, INT8_MIN, INT8_MAX),
+ 	GLOB_ITEM_INT("logging_level", LOG_INFO, PRINT_LEVEL_MIN, PRINT_LEVEL_MAX),
++	GLOB_ITEM_STR("message_tag", NULL),
+ 	GLOB_ITEM_STR("manufacturerIdentity", "00:00:00"),
+ 	GLOB_ITEM_INT("max_frequency", 900000000, 0, INT_MAX),
+ 	PORT_ITEM_INT("min_neighbor_prop_delay", -20000000, INT_MIN, -1),
+diff --git a/phc2sys.8 b/phc2sys.8
+index 22d02c2..2559c74 100644
+--- a/phc2sys.8
++++ b/phc2sys.8
+@@ -206,6 +206,10 @@ The default is /var/run/ptp4l.
+ Set the maximum syslog level of messages which should be printed or sent to
+ the system logger. The default is 6 (LOG_INFO).
+ .TP
++.BI \-t " message-tag"
++Specify the tag which is added to all messages printed to the standard output
++or system log. The default is an empty string.
++.TP
+ .B \-m
+ Print messages to the standard output.
+ .TP
+diff --git a/phc2sys.c b/phc2sys.c
+index 35cf6fa..aa4186b 100644
+--- a/phc2sys.c
++++ b/phc2sys.c
+@@ -1209,6 +1209,7 @@ static void usage(char *progname)
+ 		" -x             apply leap seconds by servo instead of kernel\n"
+ 		" -z [path]      server address for UDS (/var/run/ptp4l)\n"
+ 		" -l [num]       set the logging level to 'num' (6)\n"
++		" -t [tag]       add tag to log messages\n"
+ 		" -m             print messages to stdout\n"
+ 		" -q             do not print messages to the syslog\n"
+ 		" -v             prints the software version and exits\n"
+@@ -1219,7 +1220,7 @@ static void usage(char *progname)
+ 
+ int main(int argc, char *argv[])
+ {
+-	char *progname;
++	char *progname, *message_tag = NULL;
+ 	char *src_name = NULL, *dst_name = NULL;
+ 	struct clock *src, *dst;
+ 	struct config *cfg;
+@@ -1251,7 +1252,7 @@ int main(int argc, char *argv[])
+ 	progname = strrchr(argv[0], '/');
+ 	progname = progname ? 1+progname : argv[0];
+ 	while (EOF != (c = getopt(argc, argv,
+-				  "arc:d:s:E:P:I:S:F:R:N:O:L:M:i:u:wn:xz:l:mqvh"))) {
++				  "arc:d:s:E:P:I:S:F:R:N:O:L:M:i:u:wn:xz:l:t:mqvh"))) {
+ 		switch (c) {
+ 		case 'a':
+ 			autocfg = 1;
+@@ -1363,6 +1364,9 @@ int main(int argc, char *argv[])
+ 					  PRINT_LEVEL_MIN, PRINT_LEVEL_MAX))
+ 				goto end;
+ 			break;
++		case 't':
++			message_tag = optarg;
++			break;
+ 		case 'm':
+ 			verbose = 1;
+ 			break;
+@@ -1405,6 +1409,7 @@ int main(int argc, char *argv[])
+ 	}
+ 
+ 	print_set_progname(progname);
++	print_set_tag(message_tag);
+ 	print_set_verbose(verbose);
+ 	print_set_syslog(use_syslog);
+ 	print_set_level(print_level);
+diff --git a/print.c b/print.c
+index a82d0e7..6c48e1e 100644
+--- a/print.c
++++ b/print.c
+@@ -28,12 +28,18 @@ static int verbose = 0;
+ static int print_level = LOG_INFO;
+ static int use_syslog = 1;
+ static const char *progname;
++static const char *message_tag;
+ 
+ void print_set_progname(const char *name)
+ {
+ 	progname = name;
+ }
+ 
++void print_set_tag(const char *tag)
++{
++	message_tag = tag;
++}
++
+ void print_set_syslog(int value)
+ {
+ 	use_syslog = value ? 1 : 0;
+@@ -67,13 +73,17 @@ void print(int level, char const *format, ...)
+ 
+ 	if (verbose) {
+ 		f = level >= LOG_NOTICE ? stdout : stderr;
+-		fprintf(f, "%s[%ld.%03ld]: %s\n",
++		fprintf(f, "%s[%ld.%03ld]: %s%s%s\n",
+ 			progname ? progname : "",
+-			ts.tv_sec, ts.tv_nsec / 1000000, buf);
++			ts.tv_sec, ts.tv_nsec / 1000000,
++			message_tag ? message_tag : "", message_tag ? " " : "",
++			buf);
+ 		fflush(f);
+ 	}
+ 	if (use_syslog) {
+-		syslog(level, "[%ld.%03ld] %s",
+-		       ts.tv_sec, ts.tv_nsec / 1000000, buf);
++		syslog(level, "[%ld.%03ld] %s%s%s",
++		       ts.tv_sec, ts.tv_nsec / 1000000,
++		       message_tag ? message_tag : "", message_tag ? " " : "",
++		       buf);
+ 	}
+ }
+diff --git a/print.h b/print.h
+index e8f2c8e..1723d8a 100644
+--- a/print.h
++++ b/print.h
+@@ -33,6 +33,7 @@ __attribute__ ((format (printf, 2, 3)))
+ void print(int level, char const *format, ...);
+ 
+ void print_set_progname(const char *name);
++void print_set_tag(const char *tag);
+ void print_set_syslog(int value);
+ void print_set_level(int level);
+ void print_set_verbose(int value);
+diff --git a/ptp4l.8 b/ptp4l.8
+index 53d5f28..a724151 100644
+--- a/ptp4l.8
++++ b/ptp4l.8
+@@ -485,6 +485,12 @@ is 0.
+ The maximum logging level of messages which should be printed.
+ The default is 6 (LOG_INFO).
+ .TP
++.B message_tag
++The tag which is added to all messages printed to the standard output or system
++log.
++The default is an empty string (which cannot be set in the configuration file
++as the option requires an argument).
++.TP
+ .B verbose
+ Print messages to the standard output if enabled.
+ The default is 0 (disabled).
+diff --git a/ptp4l.c b/ptp4l.c
+index e90fcb2..f01ff6f 100644
+--- a/ptp4l.c
++++ b/ptp4l.c
+@@ -183,6 +183,7 @@ int main(int argc, char *argv[])
+ 	}
+ 
+ 	print_set_progname(progname);
++	print_set_tag(config_get_string(cfg, NULL, "message_tag"));
+ 	print_set_verbose(config_get_int(cfg, NULL, "verbose"));
+ 	print_set_syslog(config_get_int(cfg, NULL, "use_syslog"));
+ 	print_set_level(config_get_int(cfg, NULL, "logging_level"));
+
+commit e54158195b1eadfdb6275646bc3dfb7611dba5b6
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date:   Tue Jan 17 14:17:40 2017 +0100
+
+    timemaster: tag ptp4l and phc2sys messages.
+    
+    Use the new options of ptp4l and phc2sys to tag their log messages with
+    the PTP domain number and name(s) of interface(s) in the domain.
+    
+    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
+
+diff --git a/timemaster.c b/timemaster.c
+index 66ac521..880b2ab 100644
+--- a/timemaster.c
++++ b/timemaster.c
+@@ -599,7 +599,8 @@ static char **get_ptp4l_command(struct program_config *config,
+ }
+ 
+ static char **get_phc2sys_command(struct program_config *config, int domain,
+-				  int poll, int shm_segment, char *uds_path)
++				  int poll, int shm_segment, char *uds_path,
++				  char *message_tag)
+ {
+ 	char **command = (char **)parray_new();
+ 
+@@ -610,6 +611,7 @@ static char **get_phc2sys_command(struct program_config *config, int domain,
+ 		      xstrdup("-R"), string_newf("%.2f", poll > 0 ?
+ 						1.0 / (1 << poll) : 1 << -poll),
+ 		      xstrdup("-z"), xstrdup(uds_path),
++		      xstrdup("-t"), xstrdup(message_tag),
+ 		      xstrdup("-n"), string_newf("%d", domain),
+ 		      xstrdup("-E"), xstrdup("ntpshm"),
+ 		      xstrdup("-M"), string_newf("%d", shm_segment), NULL);
+@@ -671,7 +673,7 @@ static int add_ptp_source(struct ptp_domain *source,
+ 			  struct script *script)
+ {
+ 	struct config_file *config_file;
+-	char **command, *uds_path, **interfaces;
++	char **command, *uds_path, **interfaces, *message_tag;
+ 	int i, j, num_interfaces, *phc, *phcs, hw_ts;
+ 	struct sk_ts_info ts_info;
+ 
+@@ -749,6 +751,12 @@ static int add_ptp_source(struct ptp_domain *source,
+ 		uds_path = string_newf("%s/ptp4l.%d.socket",
+ 				       config->rundir, *shm_segment);
+ 
++		message_tag = string_newf("[%d", source->domain);
++		for (j = 0; interfaces[j]; j++)
++			string_appendf(&message_tag, "%s%s", j ? "+" : ":",
++				       interfaces[j]);
++		string_appendf(&message_tag, "]");
++
+ 		config_file = xmalloc(sizeof(*config_file));
+ 		config_file->path = string_newf("%s/ptp4l.%d.conf",
+ 						config->rundir, *shm_segment);
+@@ -760,8 +768,9 @@ static int add_ptp_source(struct ptp_domain *source,
+ 		string_appendf(&config_file->content,
+ 			       "slaveOnly 1\n"
+ 			       "domainNumber %d\n"
+-			       "uds_address %s\n",
+-			       source->domain, uds_path);
++			       "uds_address %s\n"
++			       "message_tag %s\n",
++			       source->domain, uds_path, message_tag);
+ 
+ 		if (phcs[i] >= 0) {
+ 			/* HW time stamping */
+@@ -772,7 +781,8 @@ static int add_ptp_source(struct ptp_domain *source,
+ 			command = get_phc2sys_command(&config->phc2sys,
+ 						      source->domain,
+ 						      source->phc2sys_poll,
+-						      *shm_segment, uds_path);
++						      *shm_segment, uds_path,
++						      message_tag);
+ 			parray_append((void ***)&script->commands, command);
+ 		} else {
+ 			/* SW time stamping */
+@@ -793,6 +803,7 @@ static int add_ptp_source(struct ptp_domain *source,
+ 
+ 		(*shm_segment)++;
+ 
++		free(message_tag);
+ 		free(uds_path);
+ 		free(interfaces);
+ 	}
diff --git a/SOURCES/linuxptp-peeraddress.patch b/SOURCES/linuxptp-peeraddress.patch
deleted file mode 100644
index db6f335..0000000
--- a/SOURCES/linuxptp-peeraddress.patch
+++ /dev/null
@@ -1,65 +0,0 @@
-commit 6b05b4e7d3255a3bbf49e20abccb511290b6196d
-Author: Richard Cochran <richardcochran@gmail.com>
-Date:   Thu Oct 9 22:09:06 2014 +0200
-
-    Restore the peer addresses in P2P mode.
-    
-    Commit ea7a7882 removed the calls to transport_peer(), inadvertently
-    substituting them with transport_send(), resulting in PDelay messages
-    being sent with an incorrect destination address.
-    
-    This patch fixes the issue by introducing peer_prepare_and_send(),
-    analogous to the port_prepare_and_send() function.
-    
-    Signed-off-by: Richard Cochran <richardcochran@gmail.com>
-    Acked-by: Jiri Benc <jbenc@redhat.com>
-
-diff --git a/port.c b/port.c
-index 18405c6..caea891 100644
---- a/port.c
-+++ b/port.c
-@@ -484,6 +484,17 @@ static int path_trace_ignore(struct port *p, struct ptp_message *m)
- 	return 0;
- }
- 
-+static int peer_prepare_and_send(struct port *p, struct ptp_message *msg,
-+				 int event)
-+{
-+	int cnt;
-+	if (msg_pre_send(msg)) {
-+		return -1;
-+	}
-+	cnt = transport_peer(p->trp, &p->fda, event, msg);
-+	return cnt <= 0 ? -1 : 0;
-+}
-+
- static int port_capable(struct port *p)
- {
- 	if (!port_is_ieee8021as(p)) {
-@@ -1114,7 +1125,7 @@ static int port_pdelay_request(struct port *p)
- 	msg->header.logMessageInterval = port_is_ieee8021as(p) ?
- 		p->logMinPdelayReqInterval : 0x7f;
- 
--	err = port_prepare_and_send(p, msg, 1);
-+	err = peer_prepare_and_send(p, msg, 1);
- 	if (err) {
- 		pr_err("port %hu: send peer delay request failed", portnum(p));
- 		goto out;
-@@ -1728,7 +1739,7 @@ static int process_pdelay_req(struct port *p, struct ptp_message *m)
- 
- 	fup->pdelay_resp_fup.requestingPortIdentity = m->header.sourcePortIdentity;
- 
--	err = port_prepare_and_send(p, rsp, 1);
-+	err = peer_prepare_and_send(p, rsp, 1);
- 	if (err) {
- 		pr_err("port %hu: send peer delay response failed", portnum(p));
- 		goto out;
-@@ -1741,7 +1752,7 @@ static int process_pdelay_req(struct port *p, struct ptp_message *m)
- 	ts_to_timestamp(&rsp->hwts.ts,
- 			&fup->pdelay_resp_fup.responseOriginTimestamp);
- 
--	err = port_prepare_and_send(p, fup, 0);
-+	err = peer_prepare_and_send(p, fup, 0);
- 	if (err)
- 		pr_err("port %hu: send pdelay_resp_fup failed", portnum(p));
- 
diff --git a/SOURCES/linuxptp-phc2sys_state.patch b/SOURCES/linuxptp-phc2sys_state.patch
deleted file mode 100644
index f0989f5..0000000
--- a/SOURCES/linuxptp-phc2sys_state.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-commit 7455c241485e01da12d107f5b665e10794330967
-Author: Jiri Benc <jbenc@redhat.com>
-Date:   Thu Nov 13 18:18:12 2014 +0100
-
-    phc2sys: fix overwriting of the clock state
-    
-    The reconfigure function is missing a check whether state for the given
-    clock actually changed or not. This caused state for all unchanged ports to
-    be zeroed.
-    
-    Reported-by: Richard Cochran <richardcochran@gmail.com>
-    Signed-off-by: Jiri Benc <jbenc@redhat.com>
-
-diff --git a/phc2sys.c b/phc2sys.c
-index 22eb9c9..67d8a58 100644
---- a/phc2sys.c
-+++ b/phc2sys.c
-@@ -305,11 +305,13 @@ static void reconfigure(struct node *node)
- 			continue;
- 		}
- 
--		if (c->new_state == PS_MASTER)
--			clock_reinit(c);
-+		if (c->new_state) {
-+			if (c->new_state == PS_MASTER)
-+				clock_reinit(c);
- 
--		c->state = c->new_state;
--		c->new_state = 0;
-+			c->state = c->new_state;
-+			c->new_state = 0;
-+		}
- 
- 		if (c->state == PS_SLAVE) {
- 			src = c;
diff --git a/SOURCES/linuxptp-shm.patch b/SOURCES/linuxptp-shm.patch
deleted file mode 100644
index 317c94c..0000000
--- a/SOURCES/linuxptp-shm.patch
+++ /dev/null
@@ -1,140 +0,0 @@
-commit 3760f8b6537ec4f614d9aa07d957716ee2e51059
-Author: Miroslav Lichvar <mlichvar@redhat.com>
-Date:   Wed Jul 9 16:25:08 2014 +0200
-
-    Add option to set NTP SHM segment number.
-    
-    Instead of setting it to the PTP domain number, add a new option to
-    ptp4l and phc2sys to set it as needed. The default value is 0. This
-    allows multiple ptp4l/phc2sys instances running in the same domain.
-    
-    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
-
-diff --git a/config.c b/config.c
-index 0bc85c1..0983c62 100644
---- a/config.c
-+++ b/config.c
-@@ -284,7 +284,6 @@ static enum parser_result parse_global_setting(const char *option,
- 		if (r != PARSED_OK)
- 			return r;
- 		dds->domainNumber = uval;
--		*cfg->ntpshm_segment = uval;
- 
- 	} else if (!strcmp(option, "clockClass")) {
- 		r = get_ranged_uint(value, &uval, 0, UINT8_MAX);
-@@ -408,6 +407,12 @@ static enum parser_result parse_global_setting(const char *option,
- 			return r;
- 		cfg->dds.sanity_freq_limit = val;
- 
-+	} else if (!strcmp(option, "ntpshm_segment")) {
-+		r = get_ranged_int(value, &val, INT_MIN, INT_MAX);
-+		if (r != PARSED_OK)
-+			return r;
-+		*cfg->ntpshm_segment = val;
-+
- 	} else if (!strcmp(option, "ptp_dst_mac")) {
- 		if (MAC_LEN != sscanf(value, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
- 				      &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]))
-diff --git a/default.cfg b/default.cfg
-index 9f01eda..9e794ba 100644
---- a/default.cfg
-+++ b/default.cfg
-@@ -53,6 +53,7 @@ first_step_threshold	0.00002
- max_frequency		900000000
- clock_servo		pi
- sanity_freq_limit	200000000
-+ntpshm_segment		0
- #
- # Transport options
- #
-diff --git a/gPTP.cfg b/gPTP.cfg
-index 4d0a38c..e15a05a 100644
---- a/gPTP.cfg
-+++ b/gPTP.cfg
-@@ -53,6 +53,7 @@ first_step_threshold	0.00002
- max_frequency		900000000
- clock_servo		pi
- sanity_freq_limit	200000000
-+ntpshm_segment		0
- #
- # Transport options
- #
-diff --git a/phc2sys.8 b/phc2sys.8
-index c4fb6f6..22d02c2 100644
---- a/phc2sys.8
-+++ b/phc2sys.8
-@@ -116,7 +116,7 @@ option.
- Specify which clock servo should be used. Valid values are pi for a PI
- controller, linreg for an adaptive controller using linear regression, and
- ntpshm for the NTP SHM reference clock to allow another process to synchronize
--the local clock (the SHM segment number is set to the domain number).
-+the local clock.
- The default is pi.
- .TP
- .BI \-P " kp"
-@@ -166,6 +166,10 @@ the synchronized clock. When a larger offset is measured, a warning message
- will be printed and the servo will be reset. When set to 0, the sanity check is
- disabled. The default is 200000000 (20%).
- .TP
-+.BI \-M " segment"
-+The number of the SHM segment used by ntpshm servo.
-+The default is 0.
-+.TP
- .BI \-u " summary-updates"
- Specify the number of clock updates included in summary statistics. The
- statistics include offset root mean square (RMS), maximum absolute offset,
-diff --git a/phc2sys.c b/phc2sys.c
-index 391ae62..22eb9c9 100644
---- a/phc2sys.c
-+++ b/phc2sys.c
-@@ -1159,6 +1159,7 @@ static void usage(char *progname)
- 		" -R [rate]      slave clock update rate in HZ (1.0)\n"
- 		" -N [num]       number of master clock readings per update (5)\n"
- 		" -L [limit]     sanity frequency limit in ppb (200000000)\n"
-+		" -M [num]       NTP SHM segment number (0)\n"
- 		" -u [num]       number of clock updates in summary stats (0)\n"
- 		" -n [num]       domain number (0)\n"
- 		" -x             apply leap seconds by servo instead of kernel\n"
-@@ -1199,7 +1200,7 @@ int main(int argc, char *argv[])
- 	progname = strrchr(argv[0], '/');
- 	progname = progname ? 1+progname : argv[0];
- 	while (EOF != (c = getopt(argc, argv,
--				  "arc:d:s:E:P:I:S:F:R:N:O:L:i:u:wn:xz:l:mqvh"))) {
-+				  "arc:d:s:E:P:I:S:F:R:N:O:L:M:i:u:wn:xz:l:mqvh"))) {
- 		switch (c) {
- 		case 'a':
- 			autocfg = 1;
-@@ -1276,6 +1277,10 @@ int main(int argc, char *argv[])
- 			if (get_arg_val_i(c, optarg, &node.sanity_freq_limit, 0, INT_MAX))
- 				return -1;
- 			break;
-+		case 'M':
-+			if (get_arg_val_i(c, optarg, &ntpshm_segment, INT_MIN, INT_MAX))
-+				return -1;
-+			break;
- 		case 'u':
- 			if (get_arg_val_ui(c, optarg, &node.stats_max_count,
- 					  0, UINT_MAX))
-@@ -1287,7 +1292,6 @@ int main(int argc, char *argv[])
- 		case 'n':
- 			if (get_arg_val_i(c, optarg, &domain_number, 0, 255))
- 				return -1;
--			ntpshm_segment = domain_number;
- 			break;
- 		case 'x':
- 			node.kernel_leap = 0;
-diff --git a/ptp4l.8 b/ptp4l.8
-index 1bae78c..687beb6 100644
---- a/ptp4l.8
-+++ b/ptp4l.8
-@@ -376,6 +376,10 @@ the synchronized clock. When a larger offset is measured, a warning message
- will be printed and the servo will be reset. When set to 0, the sanity check is
- disabled. The default is 200000000 (20%).
- .TP
-+.B ntpshm_segment
-+The number of the SHM segment used by ntpshm servo.
-+The default is 0.
-+.TP
- .B ptp_dst_mac
- The MAC address where should be PTP messages sent.
- Relevant only with L2 transport. The default is 01:1B:19:00:00:00.
diff --git a/SOURCES/linuxptp-swtscheck.patch b/SOURCES/linuxptp-swtscheck.patch
new file mode 100644
index 0000000..e448dbd
--- /dev/null
+++ b/SOURCES/linuxptp-swtscheck.patch
@@ -0,0 +1,50 @@
+commit 117ed5c2d0f865894dd930d877f0ec28bc23d951
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date:   Tue Jan 17 14:17:41 2017 +0100
+
+    timemaster: check support for SW time stamping.
+    
+    When an interface doesn't support HW time stamping, before falling back
+    to SW time stamping, check if it's actually supported and exit with an
+    error message if not.
+    
+    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
+
+diff --git a/timemaster.c b/timemaster.c
+index 880b2ab..cda2d90 100644
+--- a/timemaster.c
++++ b/timemaster.c
+@@ -674,13 +674,15 @@ static int add_ptp_source(struct ptp_domain *source,
+ {
+ 	struct config_file *config_file;
+ 	char **command, *uds_path, **interfaces, *message_tag;
+-	int i, j, num_interfaces, *phc, *phcs, hw_ts;
++	int i, j, num_interfaces, *phc, *phcs, hw_ts, sw_ts;
+ 	struct sk_ts_info ts_info;
+ 
+ 	pr_debug("adding PTP domain %d", source->domain);
+ 
+ 	hw_ts = SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE |
+ 		SOF_TIMESTAMPING_RAW_HARDWARE;
++	sw_ts = SOF_TIMESTAMPING_TX_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE |
++		SOF_TIMESTAMPING_SOFTWARE;
+ 
+ 	for (num_interfaces = 0;
+ 	     source->interfaces[num_interfaces]; num_interfaces++)
+@@ -702,9 +704,14 @@ static int add_ptp_source(struct ptp_domain *source,
+ 			return 1;
+ 		}
+ 
+-		if (!ts_info.valid ||
+-		    ((ts_info.so_timestamping & hw_ts) != hw_ts)) {
++		if (((ts_info.so_timestamping & hw_ts) != hw_ts)) {
+ 			pr_debug("interface %s: no PHC", source->interfaces[i]);
++			if ((ts_info.so_timestamping & sw_ts) != sw_ts) {
++				pr_err("time stamping not supported on %s",
++				       source->interfaces[i]);
++				free(phcs);
++				return 1;
++			}
+ 			continue;
+ 		}
+ 
diff --git a/SOURCES/linuxptp-timemaster.patch b/SOURCES/linuxptp-timemaster.patch
deleted file mode 100644
index ee23915..0000000
--- a/SOURCES/linuxptp-timemaster.patch
+++ /dev/null
@@ -1,1887 +0,0 @@
-commit 48046e593efc9583335632f25805153cc2ca8114
-Author: Miroslav Lichvar <mlichvar@redhat.com>
-Date:   Fri Oct 3 14:13:50 2014 +0200
-
-    Don't include config.h in util.h
-    
-    The config module is used by ptp4l only, but util is shared with other
-    programs.
-    
-    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
-
-diff --git a/config.h b/config.h
-index 9b74f12..d580496 100644
---- a/config.h
-+++ b/config.h
-@@ -51,14 +51,6 @@ struct interface {
- #define CFG_IGNORE_USE_SYSLOG   (1 << 5)
- #define CFG_IGNORE_VERBOSE      (1 << 6)
- 
--enum parser_result {
--	PARSED_OK,
--	NOT_PARSED,
--	BAD_VALUE,
--	MALFORMED,
--	OUT_OF_RANGE,
--};
--
- struct config {
- 	/* configuration override */
- 	int cfg_ignore;
-diff --git a/phc_ctl.c b/phc_ctl.c
-index dc9c29c..461f2ac 100644
---- a/phc_ctl.c
-+++ b/phc_ctl.c
-@@ -43,6 +43,7 @@
- #include "missing.h"
- #include "phc.h"
- #include "print.h"
-+#include "sk.h"
- #include "sysoff.h"
- #include "util.h"
- #include "version.h"
-diff --git a/util.h b/util.h
-index cf05e49..bb29e11 100644
---- a/util.h
-+++ b/util.h
-@@ -20,7 +20,6 @@
- #ifndef HAVE_UTIL_H
- #define HAVE_UTIL_H
- 
--#include "config.h"
- #include "ddt.h"
- 
- /**
-@@ -126,6 +125,17 @@ int is_utc_ambiguous(uint64_t ts);
- int leap_second_status(uint64_t ts, int leap_set, int *leap, int *utc_offset);
- 
- /**
-+ * Values returned by get_ranged_*().
-+ */
-+enum parser_result {
-+	PARSED_OK,
-+	NOT_PARSED,
-+	BAD_VALUE,
-+	MALFORMED,
-+	OUT_OF_RANGE,
-+};
-+
-+/**
-  * Get an integer value from string with error checking and range
-  * specification.
-  *
-
-commit 2098d7c1626e934e50da24ef4c5810a5b69064b4
-Author: Miroslav Lichvar <mlichvar@redhat.com>
-Date:   Fri Oct 3 14:13:51 2014 +0200
-
-    Add string and pointer array utility functions.
-    
-    Add some functions to work with strings and arrays of pointers that will
-    be useful later.
-    
-    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
-
-diff --git a/incdefs.sh b/incdefs.sh
-index cf00eaf..5bbdcea 100755
---- a/incdefs.sh
-+++ b/incdefs.sh
-@@ -23,12 +23,15 @@
- #
- user_flags()
- {
-+	# Needed for vasprintf().
-+	printf " -D_GNU_SOURCE"
-+
- 	dirs=$(echo "" | ${CROSS_COMPILE}cpp -Wp,-v 2>&1 >/dev/null | grep ^" /")
- 	for d in $dirs; do
- 		files=$(find $d -type f -name time.h)
- 		for f in $files; do
- 			if grep -q clock_adjtime $f; then
--				printf " -D_GNU_SOURCE -DHAVE_CLOCK_ADJTIME"
-+				printf " -DHAVE_CLOCK_ADJTIME"
- 				return
- 			fi
- 		done
-diff --git a/util.c b/util.c
-index cb428b1..06c3296 100644
---- a/util.c
-+++ b/util.c
-@@ -18,6 +18,7 @@
-  */
- #include <errno.h>
- #include <signal.h>
-+#include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-@@ -342,3 +343,97 @@ int is_running(void)
- {
- 	return running;
- }
-+
-+char *string_newf(const char *format, ...)
-+{
-+	va_list ap;
-+	char *s;
-+
-+	va_start(ap, format);
-+	if (vasprintf(&s, format, ap) < 0)
-+		s = NULL;
-+	va_end(ap);
-+
-+	return s;
-+}
-+
-+void string_append(char **s, const char *str)
-+{
-+	size_t len1, len2;
-+
-+	len1 = strlen(*s);
-+	len2 = strlen(str);
-+	*s = realloc(*s, len1 + len2 + 1);
-+	if (*s)
-+		memcpy((*s) + len1, str, len2 + 1);
-+}
-+
-+void string_appendf(char **s, const char *format, ...)
-+{
-+	va_list ap;
-+	size_t len1, len2;
-+	char *s2;
-+
-+	len1 = strlen(*s);
-+
-+	va_start(ap, format);
-+	len2 = vasprintf(&s2, format, ap);
-+	va_end(ap);
-+
-+	if (len2 < 0) {
-+		*s = NULL;
-+		return;
-+	}
-+
-+	*s = realloc(*s, len1 + len2 + 1);
-+	if (*s)
-+		memcpy((*s) + len1, s2, len2 + 1);
-+	free(s2);
-+}
-+
-+void **parray_new(void)
-+{
-+	void **a = malloc(sizeof(*a));
-+
-+	if (a)
-+		*a = NULL;
-+	return a;
-+}
-+
-+void parray_append(void ***a, void *p)
-+{
-+	parray_extend(a, p, NULL);
-+}
-+
-+void parray_extend(void ***a, ...)
-+{
-+	va_list ap;
-+	int ilen, len, alloced;
-+	void *p;
-+
-+	for (len = 0; (*a)[len]; len++)
-+		;
-+	len++;
-+
-+	va_start(ap, a);
-+	for (ilen = 0; va_arg(ap, void *); ilen++)
-+		;
-+	va_end(ap);
-+
-+	/* Reallocate in exponentially increasing sizes. */
-+	for (alloced = 1; alloced < len; alloced <<= 1)
-+		;
-+	if (alloced < len + ilen) {
-+		while (alloced < len + ilen)
-+			alloced *= 2;
-+		*a = realloc(*a, alloced * sizeof **a);
-+		if (!*a)
-+			return;
-+	}
-+
-+	va_start(ap, a);
-+	while ((p = va_arg(ap, void *)))
-+		(*a)[len++ - 1] = p;
-+	va_end(ap);
-+	(*a)[len - 1] = NULL;
-+}
-diff --git a/util.h b/util.h
-index bb29e11..98b395b 100644
---- a/util.h
-+++ b/util.h
-@@ -236,4 +236,61 @@ int handle_term_signals(void);
-  */
- int is_running(void);
- 
-+/**
-+ * Get an allocated and formatted string. This is a wrapper around asprintf().
-+ *
-+ * @param format    printf() format string.
-+ * @param ...       printf() arguments.
-+ * @return          Pointer to the allocated string, NULL on error.
-+ */
-+#ifdef __GNUC__
-+__attribute__ ((format (printf, 1, 2)))
-+#endif
-+char *string_newf(const char *format, ...);
-+
-+/**
-+ * Reallocate a string and append another string to it.
-+ *
-+ * @param s         String that should be extended, set to NULL on error.
-+ * @param str       String appended to s.
-+ */
-+void string_append(char **s, const char *str);
-+#ifdef __GNUC__
-+__attribute__ ((format (printf, 2, 3)))
-+#endif
-+/**
-+ * Reallocate a string and append a formatted string to it.
-+ *
-+ * @param s         String that should be extended, set to NULL on error.
-+ * @param format    printf() format string.
-+ * @param ...       printf() arguments.
-+ */
-+void string_appendf(char **s, const char *format, ...);
-+
-+/**
-+ * Get an empty array of pointers terminated by NULL.
-+ *
-+ * @return          Pointer to the allocated array, NULL on error.
-+ */
-+void **parray_new(void);
-+
-+/**
-+ * Append pointer to a NULL-terminated pointer array. The array is reallocated
-+ * in exponentially increasing sizes.
-+ *
-+ * @param a         Pointer to pointer array, set to NULL on error.
-+ * @param p         Pointer appended to the array.
-+ */
-+void parray_append(void ***a, void *p);
-+
-+
-+/**
-+ * Append pointers to a NULL-terminated pointer array. The array is reallocated
-+ * in exponentially increasing sizes.
-+ *
-+ * @param a         Pointer to pointer array, set to NULL on error.
-+ * @param ...       NULL-terminated list of pointers.
-+ */
-+void parray_extend(void ***a, ...);
-+
- #endif
-
-commit 82f13c594a8860274e62bc999520b8a434a80a53
-Author: Miroslav Lichvar <mlichvar@redhat.com>
-Date:   Fri Oct 3 14:13:52 2014 +0200
-
-    Add timemaster.
-    
-    timemaster is a program that uses ptp4l and phc2sys in combination with
-    chronyd or ntpd to synchronize the system clock to NTP and PTP time
-    sources. The PTP time is provided by phc2sys and ptp4l via SHM reference
-    clocks to chronyd/ntpd, which can compare all time sources and use the
-    best sources to synchronize the system clock.
-    
-    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
-
-diff --git a/incdefs.sh b/incdefs.sh
-index 5bbdcea..34e227f 100755
---- a/incdefs.sh
-+++ b/incdefs.sh
-@@ -19,20 +19,34 @@
- # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- 
- #
--# Look for the clock_adjtime functional prototype in the C library.
-+# Look for functional prototypes in the C library.
- #
- user_flags()
- {
- 	# Needed for vasprintf().
- 	printf " -D_GNU_SOURCE"
- 
-+	# Get list of directories searched for header files.
- 	dirs=$(echo "" | ${CROSS_COMPILE}cpp -Wp,-v 2>&1 >/dev/null | grep ^" /")
-+
-+	# Look for clock_adjtime().
- 	for d in $dirs; do
- 		files=$(find $d -type f -name time.h)
- 		for f in $files; do
- 			if grep -q clock_adjtime $f; then
- 				printf " -DHAVE_CLOCK_ADJTIME"
--				return
-+				break 2
-+			fi
-+		done
-+	done
-+
-+	# Look for posix_spawn().
-+	for d in $dirs; do
-+		files=$(find $d -type f -name spawn.h)
-+		for f in $files; do
-+			if grep -q posix_spawn $f; then
-+				printf " -DHAVE_POSIX_SPAWN"
-+				break 2
- 			fi
- 		done
- 	done
-diff --git a/makefile b/makefile
-index 74a7fe2..5469301 100644
---- a/makefile
-+++ b/makefile
-@@ -22,13 +22,14 @@ CC	= $(CROSS_COMPILE)gcc
- VER     = -DVER=$(version)
- CFLAGS	= -Wall $(VER) $(incdefs) $(DEBUG) $(EXTRA_CFLAGS)
- LDLIBS	= -lm -lrt $(EXTRA_LDFLAGS)
--PRG	= ptp4l pmc phc2sys hwstamp_ctl phc_ctl
-+PRG	= ptp4l pmc phc2sys hwstamp_ctl phc_ctl timemaster
- OBJ     = bmc.o clock.o clockadj.o clockcheck.o config.o fault.o \
-  filter.o fsm.o linreg.o mave.o mmedian.o msg.o ntpshm.o phc.o \
-  pi.o port.o print.o ptp4l.o raw.o servo.o sk.o stats.o tlv.o \
-  transport.o udp.o udp6.o uds.o util.o version.o
- 
--OBJECTS	= $(OBJ) hwstamp_ctl.o phc2sys.o pmc.o pmc_common.o sysoff.o phc_ctl.o
-+OBJECTS	= $(OBJ) hwstamp_ctl.o phc2sys.o phc_ctl.o pmc.o pmc_common.o \
-+ sysoff.o timemaster.o
- SRC	= $(OBJECTS:.o=.c)
- DEPEND	= $(OBJECTS:.o=.d)
- srcdir	:= $(dir $(lastword $(MAKEFILE_LIST)))
-@@ -56,6 +57,8 @@ hwstamp_ctl: hwstamp_ctl.o version.o
- 
- phc_ctl: phc_ctl.o phc.o sk.o util.o clockadj.o sysoff.o print.o version.o
- 
-+timemaster: print.o sk.o timemaster.o util.o version.o
-+
- version.o: .version version.sh $(filter-out version.d,$(DEPEND))
- 
- .version: force
-diff --git a/timemaster.8 b/timemaster.8
-new file mode 100644
-index 0000000..9a3ddb4
---- /dev/null
-+++ b/timemaster.8
-@@ -0,0 +1,335 @@
-+.TH TIMEMASTER 8 "October 2014" "linuxptp"
-+.SH NAME
-+
-+timemaster \- run NTP with PTP as reference clocks
-+
-+.SH SYNOPSIS
-+
-+.B timemaster
-+[
-+.B \-nmqv
-+] [
-+.BI \-l " print-level"
-+]
-+.BI \-f " file"
-+
-+.SH DESCRIPTION
-+\fBtimemaster\fR is a program that uses \fBptp4l\fR and \fBphc2sys\fR in
-+combination with \fBchronyd\fR or \fBntpd\fR to synchronize the system clock to
-+NTP and PTP time sources. The PTP time is provided by \fBphc2sys\fR and
-+\fBptp4l\fR via SHM reference clocks to \fBchronyd\fR/\fBntpd\fR, which
-+can compare all time sources and use the best sources to synchronize the system
-+clock.
-+
-+On start, \fBtimemaster\fR reads a configuration file that specifies the NTP
-+and PTP time sources, checks which network interfaces have and share a PTP
-+hardware clock (PHC), generates configuration files for \fBptp4l\fR and
-+\fBchronyd\fR/\fBntpd\fR, and start the \fBptp4l\fR, \fBphc2sys\fR,
-+\fBchronyd\fR/\fBntpd\fR processes as needed. Then, it waits for a signal to
-+kill the processes, remove the generated configuration files and exit.
-+
-+.SH OPTIONS
-+
-+.TP
-+.BI \-f " file"
-+Specify the path to the \fBtimemaster\fR configuration file.
-+.TP
-+.BI \-n
-+Don't start the programs, only print their configuration files and the commands
-+that would be executed if this option wasn't specified.
-+.TP
-+.BI \-l " level"
-+Set the maximum syslog level of messages which should be printed or sent to
-+the system logger. The default value is 6 (LOG_INFO).
-+.TP
-+.B \-m
-+Print messages to the standard output.
-+.TP
-+.B \-q
-+Don't send messages to the system logger.
-+.TP
-+.B \-v
-+Print the software version and exit.
-+.TP
-+.BI \-h
-+Display a help message and exit.
-+
-+.SH CONFIGURATION FILE
-+
-+The configuration file is divided into sections. Each section starts with a
-+line containing its name enclosed in brackets and it follows with settings.
-+Each setting is placed on a separate line, it contains the name of the
-+option and the value separated by whitespace characters. Empty lines and lines
-+starting with # are ignored.
-+
-+Sections that can used in the configuration file and options that can be set in
-+them are described below.
-+
-+.SS [timemaster]
-+
-+.TP
-+.B ntp_program
-+Select which NTP implementation should be used. Possible values are
-+\fBchronyd\fR and \fBntpd\fR. The default value is \fBchronyd\fR. Limitations
-+of the implementations relevant to the timemaster configuration are listed in
-+\fBNOTES\fR.
-+
-+.TP
-+.B rundir
-+Specify the directory where should be generated \fBchronyd\fR, \fBntpd\fR and
-+\fBptp4l\fR configuration files and sockets. The directory will be created if
-+it doesn't exist. The default value is \fB/var/run/timemaster\fR.
-+
-+.SS [ntp_server address]
-+
-+The \fBntp_server\fR section specifies an NTP server that should be used as a
-+time source. The address of the server is included in the name of the section.
-+
-+.TP
-+.B minpoll
-+.TQ
-+.B maxpoll
-+Specify the minimum and maximum NTP polling interval as powers of two in
-+seconds. The default values are 6 (64 seconds) and 10 (1024 seconds)
-+respectively. Shorter polling intervals usually improve the accuracy
-+significantly, but they should be used only when allowed by the operators of
-+the NTP service (public NTP servers generally don't allow too frequent
-+queries). If the NTP server is located on the same LAN, polling intervals
-+around 4 (16 seconds) might give best accuracy.
-+
-+.TP
-+.B iburst
-+Enable or disable sending a burst of NTP packets on start to speed up the
-+initial synchronization. Possible values are 1 and 0. The default value is 0
-+(disabled).
-+
-+.SS [ptp_domain number]
-+
-+The \fBptp_domain\fR section specifies a PTP domain that should be used as a
-+time source. The PTP domain number is included in the name of the section. The
-+\fBptp4l\fR instances are configured to run in the \fBslaveOnly\fR mode. In
-+this section at least the \fBinterfaces\fR option needs to be set, other
-+options are optional.
-+
-+.TP
-+.B interfaces
-+Specify which network interfaces should be used for this PTP domain. A separate
-+\fBptp4l\fR instance will be started for each group of interfaces sharing the
-+same PHC and for each interface that supports only SW time stamping. HW time
-+stamping is enabled automatically. If an interface with HW time stamping is
-+specified also in other PTP domains, only the \fBptp4l\fR instance from the
-+first PTP domain will be using HW time stamping.
-+
-+.TP
-+.B ntp_poll
-+Specify the polling interval of the NTP SHM reference clock reading samples
-+from \fBptp4l\fR or \fBphc2sys\fR. It's specified as a power of two in seconds.
-+The default value is 2 (4 seconds).
-+
-+.TP
-+.B phc2sys_poll
-+Specify the polling interval used by \fBphc2sys\fR to read a PTP clock
-+synchronized by \fBptp4l\fR and update the SHM sample for
-+\fBchronyd\fR/\fBntpd\fR. It's specified as a power of two in seconds. The
-+default value is 0 (1 second).
-+
-+.TP
-+.B delay
-+Specify the maximum assumed roundtrip delay to the primary source of the time
-+in this PTP domain. This value is included in the distance used by
-+\fBchronyd\fR in the source selection algorithm to detect falsetickers and
-+assign weights for source combining. The default value is 1e-4 (100
-+microseconds). With \fBntpd\fR, the \fBtos mindist\fR command can be used to
-+set a limit with similar purpose globally for all time sources.
-+
-+.TP
-+.B ptp4l_option
-+Specify an extra \fBptp4l\fR option specific to this PTP domain that should be
-+added to the configuration files generated for \fBptp4l\fR. This option may be
-+used multiple times in one \fBptp_domain\fR section.
-+
-+.SS [chronyd]
-+
-+.TP
-+.B path
-+Specify the path to the \fBchronyd\fR binary. The default value is
-+\fBchronyd\fR to search for the binary in \fBPATH\fR.
-+
-+.TP
-+.B options
-+Specify extra options that should be added to the \fBchronyd\fR command line.
-+No extra options are added by default.
-+
-+.SS [chrony.conf]
-+
-+Settings specified in this section are copied directly to the configuration
-+file generated for \fBchronyd\fR. If this section is not present in the
-+\fBtimemaster\fR configuration file, the following setting will be added:
-+
-+.EX
-+makestep 1 3
-+.EE
-+
-+This configures \fBchronyd\fR to step the system clock in the first three
-+updates if the offset is larger than 1 second.
-+
-+.SS [ntpd]
-+
-+.TP
-+.B path
-+Specify the path to the \fBntpd\fR binary. The default value is \fBntpd\fR to
-+search for the binary in \fBPATH\fR.
-+
-+.TP
-+.B options
-+Specify extra options that should be added to the \fBntpd\fR command line. No
-+extra options are added by default.
-+
-+.SS [ntp.conf]
-+
-+Settings specified in this section are copied directly to the configuration
-+file generated for \fBntpd\fR. If this section is not present in the
-+\fBtimemaster\fR configuration file, the following settings will be added:
-+
-+.EX
-+restrict default nomodify notrap nopeer noquery
-+restrict 127.0.0.1
-+restrict ::1
-+.EE
-+
-+This configures \fBntpd\fR to use safe default restrictions.
-+
-+.SS [phc2sys]
-+
-+.TP
-+.B path
-+Specify the path to the \fBphc2sys\fR binary. The default value is
-+\fBphc2sys\fR to search for the binary in \fBPATH\fR.
-+
-+.TP
-+.B options
-+Specify extra options that should be added to all \fBphc2sys\fR command lines.
-+By default, \fB-l 5\fR is added to the command lines.
-+
-+.SS [ptp4l]
-+
-+.TP
-+.B path
-+Specify the path to the \fBptp4l\fR binary. The default value is \fBptp4l\fR to
-+search for the binary in \fBPATH\fR.
-+
-+.TP
-+.B options
-+Specify extra options that should be added to all \fBptp4l\fR command lines. By
-+default, \fB-l 5\fR is added to the command lines.
-+
-+.SS [ptp4l.conf]
-+Settings specified in this section are copied directly to the configuration
-+files generated for all \fBptp4l\fR instances. There is no default content of
-+this section.
-+
-+.SH NOTES
-+For best accuracy, \fBchronyd\fR is usually preferred over \fBntpd\fR, it also
-+synchronizes the system clock faster. Both NTP implementations, however, have
-+some limitations that need to be considered before choosing the one to be used
-+in a given \fBtimemaster\fR configuration.
-+
-+The \fBchronyd\fR limitations are:
-+
-+.RS
-+In version 1.31 and older, the maximum number of reference clocks used at the
-+same time is 8. This limits the number of PHCs and interfaces using SW time
-+stamping that can be used for PTP.
-+
-+Using polling intervals (\fBminpoll\fR, \fBmaxpoll\fR, \fBntp_poll\fR options)
-+shorter than 2 (4 seconds) is not recommended with versions before 1.30. With
-+1.30 and later values of 0 or 1 can be used for NTP sources and negative values
-+for PTP sources (\fBntp_poll\fR) to specify a subsecond interval.
-+.RE
-+
-+The \fBntpd\fR limitations are:
-+
-+.RS
-+Only the first two shared-memory segments created by the SHM refclock driver
-+in \fBntpd\fR have owner-only access. Other segments are created with world
-+access, possibly allowing any user on the system writing to the segments and
-+disrupting the synchronization.
-+
-+The shortest polling interval for all sources is 3 (8 seconds).
-+
-+Nanosecond resolution in the SHM refclock driver is supported in version
-+4.2.7p303 and later, older versions have only microsecond resolution.
-+.RE
-+
-+.SH EXAMPLES
-+
-+A minimal configuration file using one NTP source and two PTP sources would be:
-+
-+.EX
-+[ntp_server 10.1.1.1]
-+
-+[ptp_domain 0]
-+interfaces eth0
-+
-+[ptp_domain 1]
-+interfaces eth1
-+.EE
-+
-+A more complex example using all \fBtimemaster\fR options would be:
-+
-+.EX
-+[ntp_server 10.1.1.1]
-+minpoll 3
-+maxpoll 4
-+iburst 1
-+
-+[ptp_domain 0]
-+interfaces eth0 eth1
-+ntp_poll 0
-+phc2sys_poll -2
-+delay 10e-6
-+ptp4l_option clock_servo linreg
-+ptp4l_option delay_mechanism P2P
-+
-+[timemaster]
-+ntp_program chronyd
-+rundir /var/run/timemaster
-+
-+[chronyd]
-+path /usr/sbin/chronyd
-+options
-+
-+[chrony.conf]
-+makestep 1 3
-+logchange 0.5
-+rtcsync
-+driftfile /var/lib/chrony/drift
-+
-+[ntpd]
-+path /usr/sbin/ntpd
-+options -u ntp:ntp
-+
-+[ntp.conf]
-+restrict default nomodify notrap nopeer noquery
-+restrict 127.0.0.1
-+restrict ::1
-+driftfile /var/lib/ntp/drift
-+
-+[phc2sys]
-+path /usr/sbin/phc2sys
-+options -l 5
-+
-+[ptp4l]
-+path /usr/sbin/ptp4l
-+options
-+
-+[ptp4l.conf]
-+logging_level 5
-+.EE
-+
-+.SH SEE ALSO
-+
-+.BR chronyd (8),
-+.BR ntpd (8),
-+.BR phc2sys (8),
-+.BR ptp4l (8)
-diff --git a/timemaster.c b/timemaster.c
-new file mode 100644
-index 0000000..83a5b83
---- /dev/null
-+++ b/timemaster.c
-@@ -0,0 +1,1173 @@
-+/**
-+ * @file timemaster.c
-+ * @brief Program to run NTP with PTP as reference clocks.
-+ * @note Copyright (C) 2014 Miroslav Lichvar <mlichvar@redhat.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.
-+ */
-+
-+#include <ctype.h>
-+#include <errno.h>
-+#include <libgen.h>
-+#include <limits.h>
-+#include <linux/net_tstamp.h>
-+#include <signal.h>
-+#include <spawn.h>
-+#include <stdarg.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <sys/stat.h>
-+#include <sys/types.h>
-+#include <sys/wait.h>
-+#include <unistd.h>
-+
-+#include "print.h"
-+#include "sk.h"
-+#include "util.h"
-+#include "version.h"
-+
-+#define DEFAULT_RUNDIR "/var/run/timemaster"
-+
-+#define DEFAULT_NTP_PROGRAM CHRONYD
-+#define DEFAULT_NTP_MINPOLL 6
-+#define DEFAULT_NTP_MAXPOLL 10
-+#define DEFAULT_PTP_DELAY 1e-4
-+#define DEFAULT_PTP_NTP_POLL 2
-+#define DEFAULT_PTP_PHC2SYS_POLL 0
-+
-+#define DEFAULT_CHRONYD_SETTINGS \
-+	"makestep 1 3"
-+#define DEFAULT_NTPD_SETTINGS \
-+	"restrict default nomodify notrap nopeer noquery", \
-+	"restrict 127.0.0.1", \
-+	"restrict ::1"
-+#define DEFAULT_PTP4L_OPTIONS "-l", "5"
-+#define DEFAULT_PHC2SYS_OPTIONS "-l", "5"
-+
-+enum source_type {
-+	NTP_SERVER,
-+	PTP_DOMAIN,
-+};
-+
-+enum ntp_program {
-+	CHRONYD,
-+	NTPD,
-+};
-+
-+struct ntp_server {
-+	char *address;
-+	int minpoll;
-+	int maxpoll;
-+	int iburst;
-+};
-+
-+struct ptp_domain {
-+	int domain;
-+	int ntp_poll;
-+	int phc2sys_poll;
-+	double delay;
-+	char **interfaces;
-+	char **ptp4l_settings;
-+};
-+
-+struct source {
-+	enum source_type type;
-+	union {
-+		struct ntp_server ntp;
-+		struct ptp_domain ptp;
-+	};
-+};
-+
-+struct program_config {
-+	char *path;
-+	char **options;
-+	char **settings;
-+};
-+
-+struct timemaster_config {
-+	struct source **sources;
-+	enum ntp_program ntp_program;
-+	char *rundir;
-+	struct program_config chronyd;
-+	struct program_config ntpd;
-+	struct program_config phc2sys;
-+	struct program_config ptp4l;
-+};
-+
-+struct config_file {
-+	char *path;
-+	char *content;
-+};
-+
-+struct script {
-+	struct config_file **configs;
-+	char ***commands;
-+};
-+
-+static void free_parray(void **a)
-+{
-+	void **p;
-+
-+	for (p = a; *p; p++)
-+		free(*p);
-+	free(a);
-+}
-+
-+static void extend_string_array(char ***a, char **strings)
-+{
-+	char **s;
-+
-+	for (s = strings; *s; s++)
-+		parray_append((void ***)a, strdup(*s));
-+}
-+
-+static void extend_config_string(char **s, char **lines)
-+{
-+	for (; *lines; lines++)
-+		string_appendf(s, "%s\n", *lines);
-+}
-+
-+static int parse_bool(char *s, int *b)
-+{
-+	if (get_ranged_int(s, b, 0, 1) != PARSED_OK)
-+		return 1;
-+
-+	return 0;
-+}
-+
-+static int parse_int(char *s, int *i)
-+{
-+	if (get_ranged_int(s, i, INT_MIN, INT_MAX) != PARSED_OK)
-+		return 1;
-+
-+	return 0;
-+}
-+
-+static int parse_double(char *s, double *d)
-+{
-+	if (get_ranged_double(s, d, INT_MIN, INT_MAX) != PARSED_OK)
-+		return 1;
-+
-+	return 0;
-+}
-+
-+static char *parse_word(char *s)
-+{
-+	while (*s && !isspace(*s))
-+		s++;
-+	while (*s && isspace(*s))
-+		*(s++) = '\0';
-+	return s;
-+}
-+
-+static void parse_words(char *s, char ***a)
-+{
-+	char *w;
-+
-+	if (**a) {
-+		free_parray((void **)(*a));
-+		*a = (char **)parray_new();
-+	}
-+	while (*s) {
-+		w = s;
-+		s = parse_word(s);
-+		parray_append((void ***)a, strdup(w));
-+	}
-+}
-+
-+static void replace_string(char *s, char **str)
-+{
-+	if (*str)
-+		free(*str);
-+	*str = strdup(s);
-+}
-+
-+static char *parse_section_name(char *s)
-+{
-+	char *s1, *s2;
-+
-+	s1 = s + 1;
-+	for (s2 = s1; *s2 && *s2 != ']'; s2++)
-+		;
-+	*s2 = '\0';
-+
-+	return strdup(s1);
-+}
-+
-+static void parse_setting(char *s, char **name, char **value)
-+{
-+	*name = s;
-+	for (*value = s; **value && !isspace(**value); (*value)++)
-+		;
-+	for (; **value && !isspace(**value); (*value)++)
-+		;
-+	for (; **value && isspace(**value); (*value)++)
-+		**value = '\0';
-+}
-+
-+static void source_destroy(struct source *source)
-+{
-+	switch (source->type) {
-+	case NTP_SERVER:
-+		free(source->ntp.address);
-+		break;
-+	case PTP_DOMAIN:
-+		free_parray((void **)source->ptp.interfaces);
-+		free_parray((void **)source->ptp.ptp4l_settings);
-+		break;
-+	}
-+	free(source);
-+}
-+
-+static struct source *source_ntp_parse(char *parameter, char **settings)
-+{
-+	char *name, *value;
-+	struct ntp_server ntp_server;
-+	struct source *source;
-+	int r = 0;
-+
-+	if (!*parameter) {
-+		pr_err("missing address for ntp_server");
-+		return NULL;
-+	}
-+
-+	ntp_server.address = parameter;
-+	ntp_server.minpoll = DEFAULT_NTP_MINPOLL;
-+	ntp_server.maxpoll = DEFAULT_NTP_MAXPOLL;
-+	ntp_server.iburst = 0;
-+
-+	for (; *settings; settings++) {
-+		parse_setting(*settings, &name, &value);
-+		if (!strcasecmp(name, "minpoll")) {
-+			r = parse_int(value, &ntp_server.minpoll);
-+		} else if (!strcasecmp(name, "maxpoll")) {
-+			r = parse_int(value, &ntp_server.maxpoll);
-+		} else if (!strcasecmp(name, "iburst")) {
-+			r = parse_bool(value, &ntp_server.iburst);
-+		} else {
-+			pr_err("unknown ntp_server setting %s", name);
-+			return NULL;
-+		}
-+		if (r) {
-+			pr_err("invalid value %s for %s", value, name);
-+			return NULL;
-+		}
-+	}
-+
-+	source = malloc(sizeof(*source));
-+	source->type = NTP_SERVER;
-+	source->ntp = ntp_server;
-+	source->ntp.address = strdup(source->ntp.address);
-+
-+	return source;
-+}
-+
-+static struct source *source_ptp_parse(char *parameter, char **settings)
-+{
-+	char *name, *value;
-+	struct source *source;
-+	int r = 0;
-+
-+	source = malloc(sizeof(*source));
-+	source->type = PTP_DOMAIN;
-+	source->ptp.delay = DEFAULT_PTP_DELAY;
-+	source->ptp.ntp_poll = DEFAULT_PTP_NTP_POLL;
-+	source->ptp.phc2sys_poll = DEFAULT_PTP_PHC2SYS_POLL;
-+	source->ptp.interfaces = (char **)parray_new();
-+	source->ptp.ptp4l_settings = (char **)parray_new();
-+
-+	if (parse_int(parameter, &source->ptp.domain)) {
-+		pr_err("invalid ptp_domain number %s", parameter);
-+		goto failed;
-+	}
-+
-+	for (; *settings; settings++) {
-+		parse_setting(*settings, &name, &value);
-+		if (!strcasecmp(name, "delay")) {
-+			r = parse_double(value, &source->ptp.delay);
-+		} else if (!strcasecmp(name, "ntp_poll")) {
-+			r = parse_int(value, &source->ptp.ntp_poll);
-+		} else if (!strcasecmp(name, "phc2sys_poll")) {
-+			r = parse_int(value, &source->ptp.phc2sys_poll);
-+		} else if (!strcasecmp(name, "ptp4l_option")) {
-+			parray_append((void ***)&source->ptp.ptp4l_settings,
-+				      strdup(value));
-+		} else if (!strcasecmp(name, "interfaces")) {
-+			parse_words(value, &source->ptp.interfaces);
-+		} else {
-+			pr_err("unknown ptp_domain setting %s", name);
-+			goto failed;
-+		}
-+
-+		if (r) {
-+			pr_err("invalid value %s for %s", value, name);
-+			goto failed;
-+		}
-+	}
-+
-+	if (!*source->ptp.interfaces) {
-+		pr_err("no interfaces specified for ptp_domain %d",
-+		       source->ptp.domain);
-+		goto failed;
-+	}
-+
-+	return source;
-+failed:
-+	source_destroy(source);
-+	return NULL;
-+}
-+
-+static int parse_program_settings(char **settings,
-+				  struct program_config *config)
-+{
-+	char *name, *value;
-+
-+	for (; *settings; settings++) {
-+		parse_setting(*settings, &name, &value);
-+		if (!strcasecmp(name, "path")) {
-+			replace_string(value, &config->path);
-+		} else if (!strcasecmp(name, "options")) {
-+			parse_words(value, &config->options);
-+		} else {
-+			pr_err("unknown program setting %s", name);
-+			return 1;
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+static int parse_timemaster_settings(char **settings,
-+				     struct timemaster_config *config)
-+{
-+	char *name, *value;
-+
-+	for (; *settings; settings++) {
-+		parse_setting(*settings, &name, &value);
-+		if (!strcasecmp(name, "ntp_program")) {
-+			if (!strcasecmp(value, "chronyd")) {
-+				config->ntp_program = CHRONYD;
-+			} else if (!strcasecmp(value, "ntpd")) {
-+				config->ntp_program = NTPD;
-+			} else {
-+				pr_err("unknown ntp program %s", value);
-+				return 1;
-+			}
-+		} else if (!strcasecmp(name, "rundir")) {
-+			replace_string(value, &config->rundir);
-+		} else {
-+			pr_err("unknown timemaster setting %s", name);
-+			return 1;
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+static int parse_section(char **settings, char *name,
-+			 struct timemaster_config *config)
-+{
-+	struct source *source = NULL;
-+	char ***settings_dst = NULL;
-+	char *parameter = parse_word(name);
-+
-+	if (!strcasecmp(name, "ntp_server")) {
-+		source = source_ntp_parse(parameter, settings);
-+		if (!source)
-+			return 1;
-+	} else if (!strcasecmp(name, "ptp_domain")) {
-+		source = source_ptp_parse(parameter, settings);
-+		if (!source)
-+			return 1;
-+	} else if (!strcasecmp(name, "chrony.conf")) {
-+		settings_dst = &config->chronyd.settings;
-+	} else if (!strcasecmp(name, "ntp.conf")) {
-+		settings_dst = &config->ntpd.settings;
-+	} else if (!strcasecmp(name, "ptp4l.conf")) {
-+		settings_dst = &config->ptp4l.settings;
-+	} else if (!strcasecmp(name, "chronyd")) {
-+		if (parse_program_settings(settings, &config->chronyd))
-+			return 1;
-+	} else if (!strcasecmp(name, "ntpd")) {
-+		if (parse_program_settings(settings, &config->ntpd))
-+			return 1;
-+	} else if (!strcasecmp(name, "phc2sys")) {
-+		if (parse_program_settings(settings, &config->phc2sys))
-+			return 1;
-+	} else if (!strcasecmp(name, "ptp4l")) {
-+		if (parse_program_settings(settings, &config->ptp4l))
-+			return 1;
-+	} else if (!strcasecmp(name, "timemaster")) {
-+		if (parse_timemaster_settings(settings, config))
-+			return 1;
-+	} else {
-+		pr_err("unknown section %s", name);
-+		return 1;
-+	}
-+
-+	if (source)
-+		parray_append((void ***)&config->sources, source);
-+
-+	if (settings_dst) {
-+		free_parray((void **)*settings_dst);
-+		*settings_dst = (char **)parray_new();
-+		extend_string_array(settings_dst, settings);
-+	}
-+
-+	return 0;
-+}
-+
-+static void init_program_config(struct program_config *config,
-+				const char *name, ...)
-+{
-+	const char *s;
-+	va_list ap;
-+
-+	config->path = strdup(name);
-+	config->settings = (char **)parray_new();
-+	config->options = (char **)parray_new();
-+
-+	va_start(ap, name);
-+
-+	/* add default options and settings */
-+	while ((s = va_arg(ap, const char *)))
-+		parray_append((void ***)&config->options, strdup(s));
-+	while ((s = va_arg(ap, const char *)))
-+		parray_append((void ***)&config->settings, strdup(s));
-+
-+	va_end(ap);
-+}
-+
-+static void free_program_config(struct program_config *config)
-+{
-+	free(config->path);
-+	free_parray((void **)config->settings);
-+	free_parray((void **)config->options);
-+}
-+
-+static void config_destroy(struct timemaster_config *config)
-+{
-+	struct source **sources;
-+
-+	for (sources = config->sources; *sources; sources++)
-+		source_destroy(*sources);
-+	free(config->sources);
-+
-+	free_program_config(&config->chronyd);
-+	free_program_config(&config->ntpd);
-+	free_program_config(&config->phc2sys);
-+	free_program_config(&config->ptp4l);
-+
-+	free(config->rundir);
-+	free(config);
-+}
-+
-+static struct timemaster_config *config_parse(char *path)
-+{
-+	struct timemaster_config *config = calloc(1, sizeof(*config));
-+	FILE *f;
-+	char buf[4096], *line, *section_name = NULL;
-+	char **section_lines = NULL;
-+	int ret = 0;
-+
-+	config->sources = (struct source **)parray_new();
-+	config->ntp_program = DEFAULT_NTP_PROGRAM;
-+	config->rundir = strdup(DEFAULT_RUNDIR);
-+
-+	init_program_config(&config->chronyd, "chronyd",
-+			    NULL, DEFAULT_CHRONYD_SETTINGS, NULL);
-+	init_program_config(&config->ntpd, "ntpd",
-+			    NULL, DEFAULT_NTPD_SETTINGS, NULL);
-+	init_program_config(&config->phc2sys, "phc2sys",
-+			    DEFAULT_PHC2SYS_OPTIONS, NULL, NULL);
-+	init_program_config(&config->ptp4l, "ptp4l",
-+			    DEFAULT_PTP4L_OPTIONS, NULL, NULL);
-+
-+	f = fopen(path, "r");
-+	if (!f) {
-+		pr_err("failed to open %s: %m", path);
-+		free(config);
-+		return NULL;
-+	}
-+
-+	while (fgets(buf, sizeof(buf), f)) {
-+		/* remove trailing and leading whitespace */
-+		for (line = buf + strlen(buf) - 1;
-+		     line >= buf && isspace(*line); line--)
-+			*line = '\0';
-+		for (line = buf; *line && isspace(*line); line++)
-+			;
-+		/* skip comments and empty lines */
-+		if (!*line || *line == '#')
-+			continue;
-+
-+		if (*line == '[') {
-+			/* parse previous section before starting another */
-+			if (section_name) {
-+				if (parse_section(section_lines, section_name,
-+						  config)) {
-+					ret = 1;
-+					break;
-+				}
-+				free_parray((void **)section_lines);
-+				free(section_name);
-+			}
-+			section_name = parse_section_name(line);
-+			section_lines = (char **)parray_new();
-+			continue;
-+		}
-+
-+		if (!section_lines) {
-+			pr_err("settings outside section");
-+			ret = 1;
-+			break;
-+		}
-+
-+		parray_append((void ***)&section_lines, strdup(line));
-+	}
-+
-+	if (!ret && section_name &&
-+	    parse_section(section_lines, section_name, config)) {
-+		ret = 1;
-+	}
-+
-+	fclose(f);
-+
-+	if (section_name)
-+		free(section_name);
-+	if (section_lines)
-+		free_parray((void **)section_lines);
-+
-+	if (ret) {
-+		config_destroy(config);
-+		return NULL;
-+	}
-+
-+	return config;
-+}
-+
-+static char **get_ptp4l_command(struct program_config *config,
-+				struct config_file *file, char **interfaces,
-+				int hw_ts)
-+{
-+	char **command = (char **)parray_new();
-+
-+	parray_append((void ***)&command, strdup(config->path));
-+	extend_string_array(&command, config->options);
-+	parray_extend((void ***)&command,
-+		      strdup("-f"), strdup(file->path),
-+		      strdup(hw_ts ? "-H" : "-S"), NULL);
-+
-+	for (; *interfaces; interfaces++)
-+		parray_extend((void ***)&command,
-+			      strdup("-i"), strdup(*interfaces), NULL);
-+
-+	return command;
-+}
-+
-+static char **get_phc2sys_command(struct program_config *config, int domain,
-+				  int poll, int shm_segment, char *uds_path)
-+{
-+	char **command = (char **)parray_new();
-+
-+	parray_append((void ***)&command, strdup(config->path));
-+	extend_string_array(&command, config->options);
-+	parray_extend((void ***)&command,
-+		      strdup("-a"), strdup("-r"),
-+		      strdup("-R"), string_newf("%.2f", poll > 0 ?
-+						1.0 / (1 << poll) : 1 << -poll),
-+		      strdup("-z"), strdup(uds_path),
-+		      strdup("-n"), string_newf("%d", domain),
-+		      strdup("-E"), strdup("ntpshm"),
-+		      strdup("-M"), string_newf("%d", shm_segment), NULL);
-+
-+	return command;
-+}
-+
-+static char *get_refid(char *prefix, unsigned int number)
-+{
-+	if (number < 10)
-+		return string_newf("%.3s%u", prefix, number);
-+	else if (number < 100)
-+		return string_newf("%.2s%u", prefix, number);
-+	else if (number < 1000)
-+		return string_newf("%.1s%u", prefix, number);
-+	return NULL;
-+};
-+
-+static void add_shm_source(int shm_segment, int poll, int dpoll, double delay,
-+			   char *prefix, struct timemaster_config *config,
-+			   char **ntp_config)
-+{
-+	char *refid = get_refid(prefix, shm_segment);
-+
-+	switch (config->ntp_program) {
-+	case CHRONYD:
-+		string_appendf(ntp_config,
-+			       "refclock SHM %d poll %d dpoll %d "
-+			       "refid %s precision 1.0e-9 delay %.1e\n",
-+			       shm_segment, poll, dpoll, refid, delay);
-+		break;
-+	case NTPD:
-+		string_appendf(ntp_config,
-+			       "server 127.127.28.%d minpoll %d maxpoll %d\n"
-+			       "fudge 127.127.28.%d refid %s\n",
-+			       shm_segment, poll, poll, shm_segment, refid);
-+		break;
-+	}
-+
-+	free(refid);
-+}
-+
-+static int add_ntp_source(struct ntp_server *source, char **ntp_config)
-+{
-+	pr_debug("adding NTP server %s", source->address);
-+
-+	string_appendf(ntp_config, "server %s minpoll %d maxpoll %d%s\n",
-+		       source->address, source->minpoll, source->maxpoll,
-+		       source->iburst ? " iburst" : "");
-+	return 0;
-+}
-+
-+static int add_ptp_source(struct ptp_domain *source,
-+			  struct timemaster_config *config, int *shm_segment,
-+			  int ***allocated_phcs, char **ntp_config,
-+			  struct script *script)
-+{
-+	struct config_file *config_file;
-+	char **command, *uds_path, **interfaces;
-+	int i, j, num_interfaces, *phc, *phcs, hw_ts;
-+	struct sk_ts_info ts_info;
-+
-+	pr_debug("adding PTP domain %d", source->domain);
-+
-+	hw_ts = SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE |
-+		SOF_TIMESTAMPING_RAW_HARDWARE;
-+
-+	for (num_interfaces = 0;
-+	     source->interfaces[num_interfaces]; num_interfaces++)
-+		;
-+
-+	if (!num_interfaces)
-+		return 0;
-+
-+	/* get PHCs used by specified interfaces */
-+	phcs = malloc(num_interfaces * sizeof(int));
-+	for (i = 0; i < num_interfaces; i++) {
-+		phcs[i] = -1;
-+
-+		/* check if the interface has a usable PHC */
-+		if (sk_get_ts_info(source->interfaces[i], &ts_info)) {
-+			pr_err("failed to get time stamping info for %s",
-+			       source->interfaces[i]);
-+			free(phcs);
-+			return 1;
-+		}
-+
-+		if (!ts_info.valid ||
-+		    ((ts_info.so_timestamping & hw_ts) != hw_ts)) {
-+			pr_debug("interface %s: no PHC", source->interfaces[i]);
-+			continue;
-+		}
-+
-+		pr_debug("interface %s: PHC %d", source->interfaces[i],
-+			 ts_info.phc_index);
-+
-+		/* and the PHC isn't already used in another source */
-+		for (j = 0; (*allocated_phcs)[j]; j++) {
-+			if (*(*allocated_phcs)[j] == ts_info.phc_index) {
-+				pr_debug("PHC %d already allocated",
-+					 ts_info.phc_index);
-+				break;
-+			}
-+		}
-+		if (!(*allocated_phcs)[j])
-+			phcs[i] = ts_info.phc_index;
-+	}
-+
-+	for (i = 0; i < num_interfaces; i++) {
-+		/* skip if already used by ptp4l in this domain */
-+		if (phcs[i] == -2)
-+			continue;
-+
-+		interfaces = (char **)parray_new();
-+		parray_append((void ***)&interfaces, source->interfaces[i]);
-+
-+		/* merge all interfaces sharing PHC to one ptp4l command */
-+		if (phcs[i] >= 0) {
-+			for (j = i + 1; j < num_interfaces; j++) {
-+				if (phcs[i] == phcs[j]) {
-+					parray_append((void ***)&interfaces,
-+						      source->interfaces[j]);
-+					/* mark the interface as used */
-+					phcs[j] = -2;
-+				}
-+			}
-+
-+			/* don't use this PHC in other sources */
-+			phc = malloc(sizeof(int));
-+			*phc = phcs[i];
-+			parray_append((void ***)allocated_phcs, phc);
-+		}
-+
-+		uds_path = string_newf("%s/ptp4l.%d.socket",
-+				       config->rundir, *shm_segment);
-+
-+		config_file = malloc(sizeof(*config_file));
-+		config_file->path = string_newf("%s/ptp4l.%d.conf",
-+						config->rundir, *shm_segment);
-+		config_file->content = strdup("[global]\n");
-+		extend_config_string(&config_file->content,
-+				     config->ptp4l.settings);
-+		extend_config_string(&config_file->content,
-+				     source->ptp4l_settings);
-+		string_appendf(&config_file->content,
-+			       "slaveOnly 1\n"
-+			       "domainNumber %d\n"
-+			       "uds_address %s\n",
-+			       source->domain, uds_path);
-+
-+		if (phcs[i] >= 0) {
-+			/* HW time stamping */
-+			command = get_ptp4l_command(&config->ptp4l, config_file,
-+						    interfaces, 1);
-+			parray_append((void ***)&script->commands, command);
-+
-+			command = get_phc2sys_command(&config->phc2sys,
-+						      source->domain,
-+						      source->phc2sys_poll,
-+						      *shm_segment, uds_path);
-+			parray_append((void ***)&script->commands, command);
-+		} else {
-+			/* SW time stamping */
-+			command = get_ptp4l_command(&config->ptp4l, config_file,
-+						    interfaces, 0);
-+			parray_append((void ***)&script->commands, command);
-+
-+			string_appendf(&config_file->content,
-+				       "clock_servo ntpshm\n"
-+				       "ntpshm_segment %d\n", *shm_segment);
-+		}
-+
-+		parray_append((void ***)&script->configs, config_file);
-+
-+		add_shm_source(*shm_segment, source->ntp_poll,
-+			       source->phc2sys_poll, source->delay, "PTP",
-+			       config, ntp_config);
-+
-+		(*shm_segment)++;
-+
-+		free(uds_path);
-+		free(interfaces);
-+	}
-+
-+	free(phcs);
-+
-+	return 0;
-+}
-+
-+static char **get_chronyd_command(struct program_config *config,
-+				  struct config_file *file)
-+{
-+	char **command = (char **)parray_new();
-+
-+	parray_append((void ***)&command, strdup(config->path));
-+	extend_string_array(&command, config->options);
-+	parray_extend((void ***)&command, strdup("-n"),
-+		      strdup("-f"), strdup(file->path), NULL);
-+
-+	return command;
-+}
-+
-+static char **get_ntpd_command(struct program_config *config,
-+			       struct config_file *file)
-+{
-+	char **command = (char **)parray_new();
-+
-+	parray_append((void ***)&command, strdup(config->path));
-+	extend_string_array(&command, config->options);
-+	parray_extend((void ***)&command, strdup("-n"),
-+		      strdup("-c"), strdup(file->path), NULL);
-+
-+	return command;
-+}
-+
-+static struct config_file *add_ntp_program(struct timemaster_config *config,
-+					   struct script *script)
-+{
-+	struct config_file *ntp_config = malloc(sizeof(*ntp_config));
-+	char **command = NULL;
-+
-+	ntp_config->content = strdup("");
-+
-+	switch (config->ntp_program) {
-+	case CHRONYD:
-+		extend_config_string(&ntp_config->content,
-+				     config->chronyd.settings);
-+		ntp_config->path = string_newf("%s/chrony.conf",
-+					       config->rundir);
-+		command = get_chronyd_command(&config->chronyd, ntp_config);
-+		break;
-+	case NTPD:
-+		extend_config_string(&ntp_config->content,
-+				     config->ntpd.settings);
-+		ntp_config->path = string_newf("%s/ntp.conf", config->rundir);
-+		command = get_ntpd_command(&config->ntpd, ntp_config);
-+		break;
-+	}
-+
-+	parray_append((void ***)&script->configs, ntp_config);
-+	parray_append((void ***)&script->commands, command);
-+
-+	return ntp_config;
-+}
-+
-+static void script_destroy(struct script *script)
-+{
-+	char ***commands, **command;
-+	struct config_file *config, **configs;
-+
-+	for (configs = script->configs; *configs; configs++) {
-+		config = *configs;
-+		free(config->path);
-+		free(config->content);
-+		free(config);
-+	}
-+	free(script->configs);
-+
-+	for (commands = script->commands; *commands; commands++) {
-+		for (command = *commands; *command; command++)
-+			free(*command);
-+		free(*commands);
-+	}
-+	free(script->commands);
-+
-+	free(script);
-+}
-+
-+static struct script *script_create(struct timemaster_config *config)
-+{
-+	struct script *script = malloc(sizeof(*script));
-+	struct source *source, **sources;
-+	struct config_file *ntp_config = NULL;
-+	int **allocated_phcs = (int **)parray_new();
-+	int ret = 0, shm_segment = 0;
-+
-+	script->configs = (struct config_file **)parray_new();
-+	script->commands = (char ***)parray_new();
-+
-+	ntp_config = add_ntp_program(config, script);
-+
-+	for (sources = config->sources; (source = *sources); sources++) {
-+		switch (source->type) {
-+		case NTP_SERVER:
-+			if (add_ntp_source(&source->ntp, &ntp_config->content))
-+				ret = 1;
-+			break;
-+		case PTP_DOMAIN:
-+			if (add_ptp_source(&source->ptp, config, &shm_segment,
-+					   &allocated_phcs,
-+					   &ntp_config->content, script))
-+				ret = 1;
-+			break;
-+		}
-+	}
-+
-+	free_parray((void **)allocated_phcs);
-+
-+	if (ret) {
-+		script_destroy(script);
-+		return NULL;
-+	}
-+
-+	return script;
-+}
-+
-+static int start_program(char **command, sigset_t *mask)
-+{
-+	char **arg, *s;
-+	pid_t pid;
-+
-+#ifdef HAVE_POSIX_SPAWN
-+	posix_spawnattr_t attr;
-+
-+	if (posix_spawnattr_init(&attr)) {
-+		pr_err("failed to init spawn attributes: %m");
-+		return 1;
-+	}
-+
-+	if (posix_spawnattr_setsigmask(&attr, mask) ||
-+	    posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) ||
-+	    posix_spawnp(&pid, command[0], NULL, &attr, command, environ)) {
-+		pr_err("failed to spawn %s: %m", command[0]);
-+		posix_spawnattr_destroy(&attr);
-+		return 1;
-+	}
-+
-+	posix_spawnattr_destroy(&attr);
-+#else
-+	pid = fork();
-+
-+	if (pid < 0) {
-+		pr_err("fork() failed: %m");
-+		return 1;
-+	}
-+
-+	if (!pid) {
-+		/* restore the signal mask */
-+		if (sigprocmask(SIG_SETMASK, mask, NULL) < 0) {
-+			pr_err("sigprocmask() failed: %m");
-+			exit(100);
-+		}
-+
-+		execvp(command[0], (char **)command);
-+
-+		pr_err("failed to execute %s: %m", command[0]);
-+
-+		exit(101);
-+	}
-+#endif
-+
-+	for (s = strdup(""), arg = command; *arg; arg++)
-+		string_appendf(&s, "%s ", *arg);
-+
-+	pr_info("process %d started: %s", pid, s);
-+
-+	free(s);
-+
-+	return 0;
-+}
-+
-+static int create_config_files(struct config_file **configs)
-+{
-+	struct config_file *config;
-+	FILE *file;
-+	char *tmp, *dir;
-+	struct stat st;
-+
-+	for (; (config = *configs); configs++) {
-+		tmp = strdup(config->path);
-+		dir = dirname(tmp);
-+		if (stat(dir, &st) < 0 && errno == ENOENT &&
-+		    mkdir(dir, 0755) < 0) {
-+			pr_err("failed to create %s: %m", dir);
-+			free(tmp);
-+			return 1;
-+		}
-+		free(tmp);
-+
-+		pr_debug("creating %s", config->path);
-+
-+		file = fopen(config->path, "w");
-+		if (!file) {
-+			pr_err("failed to open %s: %m", config->path);
-+			return 1;
-+		}
-+
-+		if (fwrite(config->content,
-+			   strlen(config->content), 1, file) != 1) {
-+			pr_err("failed to write to %s", config->path);
-+			fclose(file);
-+			return 1;
-+		}
-+
-+		fclose(file);
-+	}
-+
-+	return 0;
-+}
-+
-+static int remove_config_files(struct config_file **configs)
-+{
-+	struct config_file *config;
-+
-+	for (; (config = *configs); configs++) {
-+		pr_debug("removing %s", config->path);
-+
-+		if (unlink(config->path))
-+			pr_err("failed to remove %s: %m", config->path);
-+	}
-+
-+	return 0;
-+}
-+
-+static int script_run(struct script *script)
-+{
-+	sigset_t mask, old_mask;
-+	siginfo_t info;
-+	pid_t pid;
-+	int status, ret = 0;
-+	char ***command;
-+
-+	if (create_config_files(script->configs))
-+		return 1;
-+
-+	sigemptyset(&mask);
-+	sigaddset(&mask, SIGCHLD);
-+	sigaddset(&mask, SIGTERM);
-+	sigaddset(&mask, SIGQUIT);
-+	sigaddset(&mask, SIGINT);
-+
-+	/* block the signals */
-+	if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) {
-+		pr_err("sigprocmask() failed: %m");
-+		return 1;
-+	}
-+
-+	for (command = script->commands; *command; command++) {
-+		if (start_program(*command, &old_mask)) {
-+			kill(getpid(), SIGTERM);
-+			break;
-+		}
-+	}
-+
-+	/* wait for one of the blocked signals */
-+	while (1) {
-+		if (sigwaitinfo(&mask, &info) > 0)
-+			break;
-+		if (errno != EINTR) {
-+			pr_err("sigwaitinfo() failed: %m");
-+			break;
-+		}
-+	}
-+
-+	pr_info("received signal %d", info.si_signo);
-+
-+	/* kill the process group */
-+	kill(0, SIGTERM);
-+
-+	while ((pid = wait(&status)) >= 0) {
-+		if (!WIFEXITED(status)) {
-+			pr_info("process %d terminated abnormally", pid);
-+			ret = 1;
-+		} else {
-+			if (WEXITSTATUS(status))
-+				ret = 1;
-+			pr_info("process %d terminated with status %d", pid,
-+				WEXITSTATUS(status));
-+		}
-+	}
-+
-+	if (remove_config_files(script->configs))
-+		return 1;
-+
-+	return ret;
-+}
-+
-+static void script_print(struct script *script)
-+{
-+	char ***commands, **command;
-+	struct config_file *config, **configs;
-+
-+	for (configs = script->configs; *configs; configs++) {
-+		config = *configs;
-+		fprintf(stderr, "%s:\n\n%s\n", config->path, config->content);
-+	}
-+
-+	fprintf(stderr, "commands:\n\n");
-+	for (commands = script->commands; *commands; commands++) {
-+		for (command = *commands; *command; command++)
-+			fprintf(stderr, "%s ", *command);
-+		fprintf(stderr, "\n");
-+	}
-+}
-+
-+static void usage(char *progname)
-+{
-+	fprintf(stderr,
-+		"\nusage: %s [options] -f file\n\n"
-+		" -f file      specify path to configuration file\n"
-+		" -n           only print generated files and commands\n"
-+		" -l level     set logging level (6)\n"
-+		" -m           print messages to stdout\n"
-+		" -q           do not print messages to syslog\n"
-+		" -v           print version and exit\n"
-+		" -h           print this message and exit\n",
-+		progname);
-+}
-+
-+int main(int argc, char **argv)
-+{
-+	struct timemaster_config *config;
-+	struct script *script;
-+	char *progname, *config_path = NULL;
-+	int c, ret = 0, log_stdout = 0, log_syslog = 1, dry_run = 0;
-+
-+	progname = strrchr(argv[0], '/');
-+	progname = progname ? progname + 1 : argv[0];
-+
-+	print_set_progname(progname);
-+	print_set_verbose(1);
-+	print_set_syslog(0);
-+
-+	while (EOF != (c = getopt(argc, argv, "f:nl:mqvh"))) {
-+		switch (c) {
-+		case 'f':
-+			config_path = optarg;
-+			break;
-+		case 'n':
-+			dry_run = 1;
-+			break;
-+		case 'l':
-+			print_set_level(atoi(optarg));
-+			break;
-+		case 'm':
-+			log_stdout = 1;
-+			break;
-+		case 'q':
-+			log_syslog = 0;
-+			break;
-+		case 'v':
-+			version_show(stdout);
-+			return 0;
-+		case 'h':
-+			usage(progname);
-+			return 0;
-+		default:
-+			usage(progname);
-+			return 1;
-+		}
-+	}
-+
-+	if (!config_path) {
-+		pr_err("no configuration file specified");
-+		return 1;
-+	}
-+
-+	config = config_parse(config_path);
-+	if (!config)
-+		return 1;
-+
-+	script = script_create(config);
-+	config_destroy(config);
-+	if (!script)
-+		return 1;
-+
-+	print_set_verbose(log_stdout);
-+	print_set_syslog(log_syslog);
-+
-+	if (dry_run)
-+		script_print(script);
-+	else
-+		ret = script_run(script);
-+
-+	script_destroy(script);
-+
-+	if (!dry_run)
-+		pr_info("exiting");
-+
-+	return ret;
-+}
diff --git a/SOURCES/linuxptp-uds.patch b/SOURCES/linuxptp-uds.patch
deleted file mode 100644
index e03c944..0000000
--- a/SOURCES/linuxptp-uds.patch
+++ /dev/null
@@ -1,511 +0,0 @@
-commit 28865f91df96e83b28bb40565f12e62bd86e451f
-Author: Miroslav Lichvar <mlichvar@redhat.com>
-Date:   Tue Jul 8 16:14:18 2014 +0200
-
-    phc2sys: Add option to set path to ptp4l UDS.
-    
-    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
-
-diff --git a/phc2sys.8 b/phc2sys.8
-index a906fb3..c4fb6f6 100644
---- a/phc2sys.8
-+++ b/phc2sys.8
-@@ -194,6 +194,10 @@ clock frequency (unless the
- .B \-S
- option is used).
- .TP
-+.BI \-z " uds-address"
-+Specifies the address of the server's UNIX domain socket.
-+The default is /var/run/ptp4l.
-+.TP
- .BI \-l " print-level"
- Set the maximum syslog level of messages which should be printed or sent to
- the system logger. The default is 6 (LOG_INFO).
-diff --git a/phc2sys.c b/phc2sys.c
-index 7815a8e..418f4ac 100644
---- a/phc2sys.c
-+++ b/phc2sys.c
-@@ -53,6 +53,7 @@
- #include "stats.h"
- #include "sysoff.h"
- #include "tlv.h"
-+#include "uds.h"
- #include "util.h"
- #include "version.h"
- 
-@@ -1158,6 +1159,7 @@ static void usage(char *progname)
- 		" -u [num]       number of clock updates in summary stats (0)\n"
- 		" -n [num]       domain number (0)\n"
- 		" -x             apply leap seconds by servo instead of kernel\n"
-+		" -z [path]      server address for UDS (/var/run/ptp4l)\n"
- 		" -l [num]       set the logging level to 'num' (6)\n"
- 		" -m             print messages to stdout\n"
- 		" -q             do not print messages to the syslog\n"
-@@ -1192,7 +1194,7 @@ int main(int argc, char *argv[])
- 	progname = strrchr(argv[0], '/');
- 	progname = progname ? 1+progname : argv[0];
- 	while (EOF != (c = getopt(argc, argv,
--				  "arc:d:s:E:P:I:S:F:R:N:O:L:i:u:wn:xl:mqvh"))) {
-+				  "arc:d:s:E:P:I:S:F:R:N:O:L:i:u:wn:xz:l:mqvh"))) {
- 		switch (c) {
- 		case 'a':
- 			autocfg = 1;
-@@ -1285,6 +1287,14 @@ int main(int argc, char *argv[])
- 		case 'x':
- 			node.kernel_leap = 0;
- 			break;
-+		case 'z':
-+			if (strlen(optarg) > MAX_IFNAME_SIZE) {
-+				fprintf(stderr, "path %s too long, max is %d\n",
-+					optarg, MAX_IFNAME_SIZE);
-+				return -1;
-+			}
-+			strncpy(uds_path, optarg, MAX_IFNAME_SIZE);
-+			break;
- 		case 'l':
- 			if (get_arg_val_i(c, optarg, &print_level,
- 					  PRINT_LEVEL_MIN, PRINT_LEVEL_MAX))
-
-commit 2423357754ae7d64d844fc064c72b8d27adf40c4
-Author: Miroslav Lichvar <mlichvar@redhat.com>
-Date:   Tue Jul 8 16:14:19 2014 +0200
-
-    Remove socket when closing UDS transport.
-    
-    [RC: added cast to sockaddr to avoid compiler warning. ]
-    
-    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
-
-diff --git a/uds.c b/uds.c
-index e98e32c..97edb97 100644
---- a/uds.c
-+++ b/uds.c
-@@ -42,6 +42,14 @@ struct uds {
- 
- static int uds_close(struct transport *t, struct fdarray *fda)
- {
-+	struct sockaddr_un sa;
-+	socklen_t len = sizeof(sa);
-+
-+	if (!getsockname(fda->fd[FD_GENERAL], (struct sockaddr *) &sa, &len) &&
-+	    sa.sun_family == AF_LOCAL) {
-+		unlink(sa.sun_path);
-+	}
-+
- 	close(fda->fd[FD_GENERAL]);
- 	return 0;
- }
-
-commit ca637b2067ae78c9830c38bb5e9a659255b1a4a2
-Author: Miroslav Lichvar <mlichvar@redhat.com>
-Date:   Tue Jul 8 16:14:20 2014 +0200
-
-    Move signal handling to util.c.
-    
-    This will be useful in phc2sys and pmc.
-    
-    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
-
-diff --git a/ptp4l.c b/ptp4l.c
-index 25270c6..5080a79 100644
---- a/ptp4l.c
-+++ b/ptp4l.c
-@@ -18,7 +18,6 @@
-  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-  */
- #include <limits.h>
--#include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-@@ -40,8 +39,6 @@
- 
- int assume_two_step = 0;
- 
--static int running = 1;
--
- static struct config cfg_settings = {
- 	.dds = {
- 		.dds = {
-@@ -131,12 +128,6 @@ static struct config cfg_settings = {
- 	.cfg_ignore = 0,
- };
- 
--static void handle_int_quit_term(int s)
--{
--	pr_notice("caught signal %d", s);
--	running = 0;
--}
--
- static void usage(char *progname)
- {
- 	fprintf(stderr,
-@@ -184,18 +175,8 @@ int main(int argc, char *argv[])
- 	struct defaultDS *ds = &cfg_settings.dds.dds;
- 	int phc_index = -1, required_modes = 0;
- 
--	if (SIG_ERR == signal(SIGINT, handle_int_quit_term)) {
--		fprintf(stderr, "cannot handle SIGINT\n");
-+	if (handle_term_signals())
- 		return -1;
--	}
--	if (SIG_ERR == signal(SIGQUIT, handle_int_quit_term)) {
--		fprintf(stderr, "cannot handle SIGQUIT\n");
--		return -1;
--	}
--	if (SIG_ERR == signal(SIGTERM, handle_int_quit_term)) {
--		fprintf(stderr, "cannot handle SIGTERM\n");
--		return -1;
--	}
- 
- 	/* Set fault timeouts to a default value */
- 	for (i = 0; i < FT_CNT; i++) {
-@@ -404,7 +385,7 @@ int main(int argc, char *argv[])
- 		return -1;
- 	}
- 
--	while (running) {
-+	while (is_running()) {
- 		if (clock_poll(clock))
- 			break;
- 	}
-diff --git a/util.c b/util.c
-index 1e86040..ae66bb1 100644
---- a/util.c
-+++ b/util.c
-@@ -17,11 +17,13 @@
-  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-  */
- #include <errno.h>
-+#include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- 
- #include "address.h"
-+#include "print.h"
- #include "sk.h"
- #include "util.h"
- 
-@@ -29,6 +31,8 @@
- #define NS_PER_HOUR (3600 * NS_PER_SEC)
- #define NS_PER_DAY (24 * NS_PER_HOUR)
- 
-+static int running = 1;
-+
- const char *ps_str[] = {
- 	"NONE",
- 	"INITIALIZING",
-@@ -311,3 +315,31 @@ int get_arg_val_d(int op, const char *optarg, double *val,
- 	}
- 	return 0;
- }
-+
-+static void handle_int_quit_term(int s)
-+{
-+	pr_notice("caught signal %d", s);
-+	running = 0;
-+}
-+
-+int handle_term_signals(void)
-+{
-+	if (SIG_ERR == signal(SIGINT, handle_int_quit_term)) {
-+		fprintf(stderr, "cannot handle SIGINT\n");
-+		return -1;
-+	}
-+	if (SIG_ERR == signal(SIGQUIT, handle_int_quit_term)) {
-+		fprintf(stderr, "cannot handle SIGQUIT\n");
-+		return -1;
-+	}
-+	if (SIG_ERR == signal(SIGTERM, handle_int_quit_term)) {
-+		fprintf(stderr, "cannot handle SIGTERM\n");
-+		return -1;
-+	}
-+	return 0;
-+}
-+
-+int is_running(void)
-+{
-+	return running;
-+}
-diff --git a/util.h b/util.h
-index 3fae51c..cf05e49 100644
---- a/util.h
-+++ b/util.h
-@@ -212,4 +212,18 @@ int get_arg_val_ui(int op, const char *optarg, unsigned int *val,
- int get_arg_val_d(int op, const char *optarg, double *val,
- 		  double min, double max);
- 
-+/**
-+ * Setup a handler for terminating signals (SIGINT, SIGQUIT, SIGTERM).
-+ *
-+ * @return       0 on success, -1 on error.
-+ */
-+int handle_term_signals(void);
-+
-+/**
-+ * Check if a terminating signal was received.
-+ *
-+ * @return       1 if no terminating signal was received, 0 otherwise.
-+ */
-+int is_running(void);
-+
- #endif
-
-commit 30841a68495b5e9ba11ff4b056c4a79b0b73d14a
-Author: Miroslav Lichvar <mlichvar@redhat.com>
-Date:   Tue Jul 8 16:14:21 2014 +0200
-
-    Close client UDS transport before exit.
-    
-    In pmc and phc2sys handle terminating signals and close the UDS
-    transport before exit to remove the sockets in /var/run.
-    
-    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
-
-diff --git a/phc2sys.c b/phc2sys.c
-index 418f4ac..3039e51 100644
---- a/phc2sys.c
-+++ b/phc2sys.c
-@@ -526,7 +526,7 @@ static int do_pps_loop(struct node *node, struct clock *clock, int fd)
- 		enable_pps_output(node->master->clkid);
- 	}
- 
--	while (1) {
-+	while (is_running()) {
- 		if (!read_pps(fd, &pps_offset, &pps_ts)) {
- 			continue;
- 		}
-@@ -570,7 +570,7 @@ static int do_loop(struct node *node, int subscriptions)
- 	interval.tv_sec = node->phc_interval;
- 	interval.tv_nsec = (node->phc_interval - interval.tv_sec) * 1e9;
- 
--	while (1) {
-+	while (is_running()) {
- 		clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, NULL);
- 		if (update_pmc(node, subscriptions) < 0)
- 			continue;
-@@ -611,7 +611,7 @@ static int do_loop(struct node *node, int subscriptions)
- 			update_clock(node, clock, offset, ts, delay);
- 		}
- 	}
--	return 0; /* unreachable */
-+	return 0;
- }
- 
- static int check_clock_identity(struct node *node, struct ptp_message *msg)
-@@ -1187,6 +1187,8 @@ int main(int argc, char *argv[])
- 		.kernel_leap = 1,
- 	};
- 
-+	handle_term_signals();
-+
- 	configured_pi_kp = KP;
- 	configured_pi_ki = KI;
- 
-@@ -1349,7 +1351,8 @@ int main(int argc, char *argv[])
- 			return -1;
- 		if (auto_init_ports(&node, rt) < 0)
- 			return -1;
--		return do_loop(&node, 1);
-+		r = do_loop(&node, 1);
-+		goto end;
- 	}
- 
- 	src = clock_add(&node, src_name);
-@@ -1377,14 +1380,16 @@ int main(int argc, char *argv[])
- 		goto bad_usage;
- 	}
- 
-+	r = -1;
-+
- 	if (wait_sync) {
- 		if (init_pmc(&node, domain_number))
--			return -1;
-+			goto end;
- 
--		while (1) {
-+		while (is_running()) {
- 			r = run_pmc_wait_sync(&node, 1000);
- 			if (r < 0)
--				return -1;
-+				goto end;
- 			if (r > 0)
- 				break;
- 			else
-@@ -1395,7 +1400,7 @@ int main(int argc, char *argv[])
- 			r = run_pmc_get_utc_offset(&node, 1000);
- 			if (r <= 0) {
- 				pr_err("failed to get UTC offset");
--				return -1;
-+				goto end;
- 			}
- 		}
- 
-@@ -1409,11 +1414,16 @@ int main(int argc, char *argv[])
- 		/* only one destination clock allowed with PPS until we
- 		 * implement a mean to specify PTP port to PPS mapping */
- 		servo_sync_interval(dst->servo, 1.0);
--		return do_pps_loop(&node, dst, pps_fd);
-+		r = do_pps_loop(&node, dst, pps_fd);
-+	} else {
-+		r = do_loop(&node, 0);
- 	}
- 
--	return do_loop(&node, 0);
-+end:
-+	if (node.pmc)
-+		close_pmc(&node);
- 
-+	return r;
- bad_usage:
- 	usage(progname);
- 	return -1;
-diff --git a/pmc.c b/pmc.c
-index ba06293..8cfae92 100644
---- a/pmc.c
-+++ b/pmc.c
-@@ -714,6 +714,7 @@ int main(int argc, char *argv[])
- 	const char *iface_name = NULL;
- 	char *progname;
- 	int c, cnt, length, tmo = -1, batch_mode = 0, zero_datalen = 0;
-+	int ret = 0;
- 	char line[1024], *command = NULL;
- 	enum transport_type transport_type = TRANS_UDP_IPV4;
- 	UInteger8 boundary_hops = 1, domain_number = 0, transport_specific = 0;
-@@ -721,6 +722,8 @@ int main(int argc, char *argv[])
- #define N_FD 2
- 	struct pollfd pollfd[N_FD];
- 
-+	handle_term_signals();
-+
- 	/* Process the command line arguments. */
- 	progname = strrchr(argv[0], '/');
- 	progname = progname ? 1+progname : argv[0];
-@@ -798,7 +801,7 @@ int main(int argc, char *argv[])
- 	pollfd[0].fd = batch_mode ? -1 : STDIN_FILENO;
- 	pollfd[1].fd = pmc_get_transport_fd(pmc);
- 
--	while (1) {
-+	while (is_running()) {
- 		if (batch_mode && !command) {
- 			if (optind < argc) {
- 				command = argv[optind++];
-@@ -823,7 +826,8 @@ int main(int argc, char *argv[])
- 				continue;
- 			} else {
- 				pr_emerg("poll failed");
--				return -1;
-+				ret = -1;
-+				break;
- 			}
- 		} else if (!cnt) {
- 			break;
-@@ -866,5 +870,5 @@ int main(int argc, char *argv[])
- 
- 	pmc_destroy(pmc);
- 	msg_cleanup();
--	return 0;
-+	return ret;
- }
-
-commit 1773d21f26eb1aa2da0645af116d6ce27591a9cc
-Author: Miroslav Lichvar <mlichvar@redhat.com>
-Date:   Tue Jul 8 16:14:22 2014 +0200
-
-    Append PID to client UDS paths.
-    
-    This allows running multiple phc2sys and pmc instances at the same time.
-    
-    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
-
-diff --git a/phc2sys.c b/phc2sys.c
-index 3039e51..391ae62 100644
---- a/phc2sys.c
-+++ b/phc2sys.c
-@@ -738,8 +738,11 @@ static void send_subscription(struct node *node)
- 
- static int init_pmc(struct node *node, int domain_number)
- {
--	node->pmc = pmc_create(TRANS_UDS, "/var/run/phc2sys", 0,
--				domain_number, 0, 1);
-+	char uds_local[MAX_IFNAME_SIZE + 1];
-+
-+	snprintf(uds_local, sizeof(uds_local), "/var/run/phc2sys.%d",
-+		 getpid());
-+	node->pmc = pmc_create(TRANS_UDS, uds_local, 0, domain_number, 0, 1);
- 	if (!node->pmc) {
- 		pr_err("failed to create pmc");
- 		return -1;
-diff --git a/pmc.8 b/pmc.8
-index 0d36354..b113c78 100644
---- a/pmc.8
-+++ b/pmc.8
-@@ -73,7 +73,7 @@ Specify the boundary hops value in sent messages. The default is 1.
- Specify the domain number in sent messages. The default is 0.
- .TP
- .BI \-i " interface"
--Specify the network interface. The default is /var/run/pmc for the Unix Domain
-+Specify the network interface. The default is /var/run/pmc.$pid for the Unix Domain
- Socket transport and eth0 for the other transports.
- .TP
- .BI \-s " uds-address"
-diff --git a/pmc.c b/pmc.c
-index 8cfae92..d58e190 100644
---- a/pmc.c
-+++ b/pmc.c
-@@ -700,7 +700,7 @@ static void usage(char *progname)
- 		" -d [num]  domain number, default 0\n"
- 		" -h        prints this message and exits\n"
- 		" -i [dev]  interface device to use, default 'eth0'\n"
--		"           for network and '/var/run/pmc' for UDS.\n"
-+		"           for network and '/var/run/pmc.$pid' for UDS.\n"
- 		" -s [path] server address for UDS, default '/var/run/ptp4l'.\n"
- 		" -t [hex]  transport specific field, default 0x0\n"
- 		" -v        prints the software version and exits\n"
-@@ -715,7 +715,7 @@ int main(int argc, char *argv[])
- 	char *progname;
- 	int c, cnt, length, tmo = -1, batch_mode = 0, zero_datalen = 0;
- 	int ret = 0;
--	char line[1024], *command = NULL;
-+	char line[1024], *command = NULL, uds_local[MAX_IFNAME_SIZE + 1];
- 	enum transport_type transport_type = TRANS_UDP_IPV4;
- 	UInteger8 boundary_hops = 1, domain_number = 0, transport_specific = 0;
- 	struct ptp_message *msg;
-@@ -781,7 +781,13 @@ int main(int argc, char *argv[])
- 	}
- 
- 	if (!iface_name) {
--		iface_name = transport_type == TRANS_UDS ? "/var/run/pmc" : "eth0";
-+		if (transport_type == TRANS_UDS) {
-+			snprintf(uds_local, sizeof(uds_local),
-+				 "/var/run/pmc.%d", getpid());
-+			iface_name = uds_local;
-+		} else {
-+			iface_name = "eth0";
-+		}
- 	}
- 	if (optind < argc) {
- 		batch_mode = 1;
-commit aa24ba58e1901f9397624665c1f19a2432e426d0
-Author: Miroslav Lichvar <mlichvar@redhat.com>
-Date:   Fri Oct 3 14:13:49 2014 +0200
-
-    Don't print messages in signal handler.
-    
-    Only reentrant functions should be called here.
-    
-    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
-
-diff --git a/util.c b/util.c
-index ae66bb1..cb428b1 100644
---- a/util.c
-+++ b/util.c
-@@ -318,7 +318,6 @@ int get_arg_val_d(int op, const char *optarg, double *val,
- 
- static void handle_int_quit_term(int s)
- {
--	pr_notice("caught signal %d", s);
- 	running = 0;
- }
- 
diff --git a/SOURCES/linuxptp-utcoffset.patch b/SOURCES/linuxptp-utcoffset.patch
new file mode 100644
index 0000000..b54f800
--- /dev/null
+++ b/SOURCES/linuxptp-utcoffset.patch
@@ -0,0 +1,130 @@
+commit 0309a880fb4389e869ae0ba431d3d17b1ec5a272
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date:   Thu Jan 5 10:15:53 2017 +0100
+
+    Update TAI-UTC offset
+    
+    A leap second was applied to UTC on 2016-12-31 and the offset between
+    TAI and UTC is now 37 seconds.
+    
+    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
+
+diff --git a/ds.h b/ds.h
+index b36862d..0e48d05 100644
+--- a/ds.h
++++ b/ds.h
+@@ -84,7 +84,7 @@ struct parent_ds {
+ 	unsigned int path_length;
+ };
+ 
+-#define CURRENT_UTC_OFFSET  36 /* 1 Jul 2015 */
++#define CURRENT_UTC_OFFSET  37 /* 1 Jan 2017 */
+ #define INTERNAL_OSCILLATOR 0xA0
+ 
+ struct timePropertiesDS {
+commit 33e62f992542ac5ce6bdbb8ae6c34dec7011b543
+Author: Viliam Lejcik <viliam.lejcik@kistler.com>
+Date:   Tue Jan 17 18:25:26 2017 +0100
+
+    ptp4l: Make UTC offset configurable.
+    
+    Currently UTC offset is defined as a constant - CURRENT_UTC_OFFSET, and if
+    a leap second is added, that constant is no longer valid. Ptp4l was
+    updated to read the UTC offset from configuration instead.
+    
+    Signed-off-by: Viliam Lejcik <viliam.lejcik@kistler.com>
+
+diff --git a/clock.c b/clock.c
+index c716f01..a6a1a1a 100644
+--- a/clock.c
++++ b/clock.c
+@@ -105,6 +105,7 @@ struct clock {
+ 	int leap_set;
+ 	int kernel_leap;
+ 	int utc_offset;  /* grand master role */
++	int current_utc_offset;  /* UTC offset fallback */
+ 	int time_flags;  /* grand master role */
+ 	int time_source; /* grand master role */
+ 	enum servo_state servo_state;
+@@ -681,7 +682,7 @@ static void clock_update_slave(struct clock *c)
+ 	if (!(c->tds.flags & PTP_TIMESCALE)) {
+ 		pr_warning("foreign master not using PTP timescale");
+ 	}
+-	if (c->tds.currentUtcOffset < CURRENT_UTC_OFFSET) {
++	if (c->tds.currentUtcOffset < c->current_utc_offset) {
+ 		pr_warning("running in a temporal vortex");
+ 	}
+ }
+@@ -697,10 +698,10 @@ static int clock_utc_correct(struct clock *c, tmv_t ingress)
+ 
+ 	if (c->tds.flags & UTC_OFF_VALID && c->tds.flags & TIME_TRACEABLE) {
+ 		utc_offset = c->tds.currentUtcOffset;
+-	} else if (c->tds.currentUtcOffset > CURRENT_UTC_OFFSET) {
++	} else if (c->tds.currentUtcOffset > c->current_utc_offset) {
+ 		utc_offset = c->tds.currentUtcOffset;
+ 	} else {
+-		utc_offset = CURRENT_UTC_OFFSET;
++		utc_offset = c->current_utc_offset;
+ 	}
+ 
+ 	if (c->tds.flags & LEAP_61) {
+@@ -1035,7 +1036,7 @@ struct clock *clock_create(enum clock_type type, struct config *config,
+ 	c->freq_est_interval = config_get_int(config, NULL, "freq_est_interval");
+ 	c->grand_master_capable = config_get_int(config, NULL, "gmCapable");
+ 	c->kernel_leap = config_get_int(config, NULL, "kernel_leap");
+-	c->utc_offset = CURRENT_UTC_OFFSET;
++	c->utc_offset = c->current_utc_offset = config_get_int(config, NULL, "utc_offset");
+ 	c->time_source = config_get_int(config, NULL, "timeSource");
+ 
+ 	if (c->free_running) {
+diff --git a/config.c b/config.c
+index b19f3ad..7bb949d 100644
+--- a/config.c
++++ b/config.c
+@@ -237,6 +237,7 @@ struct config_item config_tab[] = {
+ 	GLOB_ITEM_STR("uds_address", "/var/run/ptp4l"),
+ 	GLOB_ITEM_INT("use_syslog", 1, 0, 1),
+ 	GLOB_ITEM_STR("userDescription", ""),
++	GLOB_ITEM_INT("utc_offset", CURRENT_UTC_OFFSET, 0, INT_MAX),
+ 	GLOB_ITEM_INT("verbose", 0, 0, 1),
+ };
+ 
+diff --git a/default.cfg b/default.cfg
+index 12542c0..ebb263a 100644
+--- a/default.cfg
++++ b/default.cfg
+@@ -7,6 +7,7 @@ slaveOnly		0
+ priority1		128
+ priority2		128
+ domainNumber		0
++#utc_offset		37
+ clockClass		248
+ clockAccuracy		0xFE
+ offsetScaledLogVariance	0xFFFF
+diff --git a/gPTP.cfg b/gPTP.cfg
+index 75e996c..142996a 100644
+--- a/gPTP.cfg
++++ b/gPTP.cfg
+@@ -7,6 +7,7 @@ gmCapable		1
+ priority1		248
+ priority2		248
+ domainNumber		0
++#utc_offset		37
+ clockClass		248
+ clockAccuracy		0xFE
+ offsetScaledLogVariance	0xFFFF
+diff --git a/ptp4l.8 b/ptp4l.8
+index f53fc6e..53d5f28 100644
+--- a/ptp4l.8
++++ b/ptp4l.8
+@@ -327,6 +327,10 @@ The default is 0xFFFF.
+ The domain attribute of the local clock.
+ The default is 0.
+ .TP
++.B utc_offset
++The current offset between TAI and UTC.
++The default is 37.
++.TP
+ .B free_running
+ Don't adjust the local clock if enabled.
+ The default is 0 (disabled).
diff --git a/SOURCES/linuxptp-warnings.patch b/SOURCES/linuxptp-warnings.patch
deleted file mode 100644
index e1d99ae..0000000
--- a/SOURCES/linuxptp-warnings.patch
+++ /dev/null
@@ -1,89 +0,0 @@
-commit 9ddd2a60249eaf2b2a48bf9af3843fa06cf0a095
-Author: Miroslav Lichvar <mlichvar@redhat.com>
-Date:   Wed Sep 17 11:11:15 2014 +0200
-
-    Fix copying of device name to ifreq.
-    
-    Don't overwrite the last NUL with strncpy() and also replace strcpy()
-    with strncpy().
-    
-    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
-
-diff --git a/hwstamp_ctl.c b/hwstamp_ctl.c
-index ec5dd6d..0d21843 100644
---- a/hwstamp_ctl.c
-+++ b/hwstamp_ctl.c
-@@ -131,7 +131,7 @@ int main(int argc, char *argv[])
- 	memset(&ifreq, 0, sizeof(ifreq));
- 	memset(&cfg, 0, sizeof(cfg));
- 
--	strncpy(ifreq.ifr_name, device, sizeof(ifreq.ifr_name));
-+	strncpy(ifreq.ifr_name, device, sizeof(ifreq.ifr_name) - 1);
- 
- 	ifreq.ifr_data = (void *) &cfg;
- 
-diff --git a/sk.c b/sk.c
-index f694bbd..a9133fd 100644
---- a/sk.c
-+++ b/sk.c
-@@ -51,7 +51,7 @@ static int hwts_init(int fd, const char *device, int rx_filter, int one_step)
- 	memset(&ifreq, 0, sizeof(ifreq));
- 	memset(&cfg, 0, sizeof(cfg));
- 
--	strncpy(ifreq.ifr_name, device, sizeof(ifreq.ifr_name));
-+	strncpy(ifreq.ifr_name, device, sizeof(ifreq.ifr_name) - 1);
- 
- 	ifreq.ifr_data = (void *) &cfg;
- 	cfg.tx_type    = one_step ? HWTSTAMP_TX_ONESTEP_SYNC : HWTSTAMP_TX_ON;
-@@ -85,7 +85,7 @@ int sk_interface_index(int fd, const char *name)
- 	int err;
- 
- 	memset(&ifreq, 0, sizeof(ifreq));
--	strcpy(ifreq.ifr_name, name);
-+	strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name) - 1);
- 	err = ioctl(fd, SIOCGIFINDEX, &ifreq);
- 	if (err < 0) {
- 		pr_err("ioctl SIOCGIFINDEX failed: %m");
-@@ -154,7 +154,7 @@ int sk_interface_macaddr(const char *name, struct address *mac)
- 	int err, fd;
- 
- 	memset(&ifreq, 0, sizeof(ifreq));
--	strcpy(ifreq.ifr_name, name);
-+	strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name) - 1);
- 
- 	fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
- 	if (fd < 0) {
-
-commit 6b459abc8c54189ec3315404057923c039c1796a
-Author: Miroslav Lichvar <mlichvar@redhat.com>
-Date:   Wed Sep 17 11:11:16 2014 +0200
-
-    Fix Coverity warning in sk_interface_addr().
-    
-    Copy the address directly to struct sockaddr_in or sockaddr_in6 instead
-    of sockaddr as Coverity doesn't seem to understand the union and reports
-    a buffer overflow.
-    
-    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
-
-diff --git a/sk.c b/sk.c
-index a9133fd..c48cf45 100644
---- a/sk.c
-+++ b/sk.c
-@@ -191,14 +191,15 @@ int sk_interface_addr(const char *name, int family, struct address *addr)
- 			switch (family) {
- 			case AF_INET:
- 				addr->len = sizeof(addr->sin);
-+				memcpy(&addr->sin, i->ifa_addr, addr->len);
- 				break;
- 			case AF_INET6:
- 				addr->len = sizeof(addr->sin6);
-+				memcpy(&addr->sin6, i->ifa_addr, addr->len);
- 				break;
- 			default:
- 				continue;
- 			}
--			memcpy(&addr->sa, i->ifa_addr, addr->len);
- 			result = 0;
- 			break;
- 		}
diff --git a/SPECS/linuxptp.spec b/SPECS/linuxptp.spec
index 89a64c2..7ade9b1 100644
--- a/SPECS/linuxptp.spec
+++ b/SPECS/linuxptp.spec
@@ -1,36 +1,35 @@
 %global _hardened_build 1
-%global gitdate	20140718
-%global gitrev	bdb6a3
+%global testsuite_ver 502e82
+%global clknetsim_ver ce89a1
 Name:		linuxptp
-Version:	1.4
-Release:	3.%{gitdate}git%{gitrev}%{?dist}
+Version:	1.8
+Release:	3%{?dist}
 Summary:	PTP implementation for Linux
 
 Group:		System Environment/Base
 License:	GPLv2+
 URL:		http://linuxptp.sourceforge.net/
 
-#Source0:      http://downloads.sourceforge.net/%{name}/%{name}-%{version}.tgz
-# git clone git://git.code.sf.net/p/linuxptp/code linuxptp; cd linuxptp
-# git archive --prefix=linuxptp-%{version}/ %{gitrev} | \
-# gzip > linuxptp-%{gitdate}git%{gitrev}.tar.gz
-Source0:	%{name}-%{gitdate}git%{gitrev}.tar.gz
+Source0:	https://downloads.sourceforge.net/%{name}/%{name}-%{version}.tgz
 Source1:	phc2sys.service
 Source2:	ptp4l.service
 Source3:	timemaster.service
 Source4:	timemaster.conf
-# test suite from https://github.com/mlichvar/linuxptp-testsuite.git
-Source10:	testsuite-7c523f.tar.gz
-# simulator for test suite from https://github.com/mlichvar/clknetsim.git
-Source11:	clknetsim-e63178.tar.gz
-
-Patch1:		linuxptp-warnings.patch
-Patch2:		linuxptp-uds.patch
-Patch3:		linuxptp-shm.patch
-Patch4:		linuxptp-timemaster.patch
-Patch5:		linuxptp-peeraddress.patch
-Patch6:		linuxptp-linreg_reset.patch
-Patch7:		linuxptp-phc2sys_state.patch
+# external test suite
+Source10:	https://github.com/mlichvar/linuxptp-testsuite/archive/%{testsuite_ver}/linuxptp-testsuite-%{testsuite_ver}.tar.gz
+# simulator for test suite
+Source11:	https://github.com/mlichvar/clknetsim/archive/%{clknetsim_ver}/clknetsim-%{clknetsim_ver}.tar.gz
+
+# update default TAI-UTC offset and make it configurable
+Patch1:		linuxptp-utcoffset.patch
+# add options to tag ptp4l/phc2sys log messages and use them in timemaster
+Patch2:		linuxptp-messagetag.patch
+# check support for SW timestamping in timemaster
+Patch3:		linuxptp-swtscheck.patch
+# fix leaks of sockets in error handling
+Patch4:		linuxptp-closesocket.patch
+# force BMC election when link goes down
+Patch5:		linuxptp-linkdown.patch
 
 BuildRequires:	systemd-units
 
@@ -47,14 +46,13 @@ Supporting legacy APIs and other platforms is not a goal.
 
 %prep
 %setup -q -a 10 -a 11
-%patch1 -p1 -b .warnings
-%patch2 -p1 -b .uds
-%patch3 -p1 -b .shm
-%patch4 -p1 -b .timemaster
-%patch5 -p1 -b .peeraddress
-%patch6 -p1 -b .linreg_reset
-%patch7 -p1 -b .phc2sys_state
-mv clknetsim testsuite
+%patch1 -p1 -b .utcoffset
+%patch2 -p1 -b .messagetag
+%patch3 -p1 -b .swtscheck
+%patch4 -p1 -b .closesocket
+%patch5 -p1 -b .linkdown
+mv linuxptp-testsuite-%{testsuite_ver}* testsuite
+mv clknetsim-%{clknetsim_ver}* testsuite/clknetsim
 
 %build
 make %{?_smp_mflags} \
@@ -78,6 +76,8 @@ echo '.so man8/timemaster.8' > $RPM_BUILD_ROOT%{_mandir}/man5/timemaster.conf.5
 
 %check
 cd testsuite
+# set random seed to get deterministic results
+export CLKNETSIM_RANDOM_SEED=26743
 make %{?_smp_mflags} -C clknetsim
 PATH=..:$PATH ./run
 
@@ -109,6 +109,15 @@ PATH=..:$PATH ./run
 %{_mandir}/man8/*.8*
 
 %changelog
+* Wed Mar 15 2017 Miroslav Lichvar <mlichvar@redhat.com> 1.8-3
+- fix backport of linkdown patch
+
+* Tue Mar 14 2017 Miroslav Lichvar <mlichvar@redhat.com> 1.8-2
+- force BMC election when link goes down
+
+* Tue Feb 07 2017 Miroslav Lichvar <mlichvar@redhat.com> 1.8-1
+- update to 1.8 (#1359311 #1353336)
+
 * Tue Nov 25 2014 Miroslav Lichvar <mlichvar@redhat.com> 1.4-3.20140718gitbdb6a3
 - fix resetting of linreg servo (#1165045)
 - fix phc2sys automatic mode with multiple interfaces (#1108795)