[ntpsec commit] First-cut JSON output of ntptime. Not finished yet...

Eric S. Raymond esr at ntpsec.org
Thu Oct 15 04:04:13 UTC 2015


Module:    ntpsec
Branch:    master
Commit:    41f9295dee6ab93eb321785f24f9af4c004d8df9
Changeset: http://git.ntpsec.org/ntpsec/commit/?id=41f9295dee6ab93eb321785f24f9af4c004d8df9

Author:    Eric S. Raymond <esr at thyrsus.com>
Date:      Thu Oct 15 00:02:45 2015 -0400

First-cut JSON output of ntptime.  Not finished yet...

...time field should be RFC3339.

---

 devel-docs/hacking.txt         |   2 +-
 docs/includes/ntptime-body.txt |   3 ++
 util/ntptime.c                 | 118 ++++++++++++++++++++++++++++-------------
 3 files changed, 86 insertions(+), 37 deletions(-)

diff --git a/devel-docs/hacking.txt b/devel-docs/hacking.txt
index 503b6e6..bdae879 100644
--- a/devel-docs/hacking.txt
+++ b/devel-docs/hacking.txt
@@ -93,7 +93,7 @@ object.  You can read about JSON at
 	 http://www.json.org/
 
 Be aware that if you present a tool design with a messy output format
-abd no JSON option it is quite likely to be rejected.
+and no JSON option it is quite likely to be rejected.
 
 === Copyrights and licenses ===
 
diff --git a/docs/includes/ntptime-body.txt b/docs/includes/ntptime-body.txt
index 1876fd7..a29efb3 100644
--- a/docs/includes/ntptime-body.txt
+++ b/docs/includes/ntptime-body.txt
@@ -9,6 +9,7 @@
 
 == Description ==
 
+//FIXME: Is this all modern Unix kernels?  Probably.
 This program is useful only with special kernels described in the
 link:kern.html[A Kernel Model for Precision Timekeeping] page. It reads
 and displays time-related kernel variables using the `ntp_gettime()`
@@ -25,6 +26,8 @@ and `kerninfo` command.
   Specify frequency offset, in parts per million.
 `-h`::
   Display help information.
+`-j`::
+  Report in JSON rather than plain text.
 `-m` 'max_error'::
   Specify max possible errors, in microseconds.
 `-o` 'offset'::
diff --git a/util/ntptime.c b/util/ntptime.c
index b64f893..99b6c7d 100644
--- a/util/ntptime.c
+++ b/util/ntptime.c
@@ -18,6 +18,7 @@
 #include <ctype.h>
 #include <signal.h>
 #include <setjmp.h>
+#include <stdbool.h>
 
 #ifdef STRUCT_NTP_TIMEVAL_HAS_TV_NSEC
 #define tv_frac_sec tv_nsec
@@ -63,7 +64,7 @@ static volatile int pll_control; /* (0) daemon, (1) kernel loop */
 static volatile int status;	/* most recent status bits */
 static volatile int flash;	/* most recent ntp_adjtime() bits */
 char* progname;
-static char optargs[] = "MNT:cde:f:hm:o:rs:t:";
+static char optargs[] = "MNT:cde:f:hjm:o:rs:t:";
 
 int
 main(
@@ -87,6 +88,7 @@ main(
 	int ch;
 	int errflg	= 0;
 	int cost	= 0;
+	bool json       = false;
 	volatile int rawtime	= 0;
 	char ascbuf[BUFSIZ];
 
@@ -126,6 +128,10 @@ main(
 			ntx.freq = (long)(atof(ntp_optarg) * SCALE_FREQ);
 			break;
 
+		case 'j':
+			json = true;
+			break;
+
 		case 'm':
 			ntx.modes |= MOD_MAXERROR;
 			ntx.maxerror = atoi(ntp_optarg);
@@ -164,6 +170,7 @@ main(
 -e esterror	estimate of the error (us)\n\
 -f frequency	Frequency error (-500 .. 500) (ppm)\n\
 -h		display this help info\n\
+-j              report in JSON\n\
 -m maxerror	max possible error (us)\n\
 -o offset	current offset (ms)\n\
 -r		print the unix and NTP time raw\n\
@@ -260,8 +267,27 @@ main(
 	if (status < 0) {
 		perror("ntp_gettime() call fails");
 	} else {
-		printf("ntp_gettime() returns code %d (%s)\n",
-		    status, timex_state(status));
+		/* oldstyle formats */
+		const char *ofmt1 = "ntp_gettime() returns code %d (%s)\n";
+		const char *ofmt2 = "  time %s, (.%0*d),\n";
+		const char *ofmt3 = "  maximum error %lu us, estimated error %lu us";
+		const char *ofmt4 = "  ntptime=%x.%x unixtime=%x.%0*d %s";
+#if NTP_API > 3
+		const char *ofmt5 = ", TAI offset %ld\n";
+#else
+		const char *ofmt6 = "\n";
+#endif /* NTP_API */
+		/* JSON formats */
+		const char *jfmt1 = "{\"gettime-code\":%d,\"gettime-status\":%s,";
+		const char *jfmt2 = "\"time\":\"%s\",\"fractional time\":\".%0*d\",";
+		const char *jfmt3 = "\"maximum error\":%lu,\"estimated error\":%lu,";
+		const char *jfmt4 = "\"raw ntp time\":\"%x.%x\",\"raw unix time\":\"%x.%0*d %s\",";
+#if NTP_API > 3
+		const char *jfmt5 = "\"TAI offset\":%d,";
+#else
+		const char *jfmt6 = "";
+#endif /* NTP_API */
+		printf(json ? jfmt1 : ofmt1, status, timex_state(status));
 		time_frac = ntv.time.tv_frac_sec;
 #ifdef STA_NANO
 		if (flash & STA_NANO) {
@@ -277,20 +303,18 @@ main(
 		ts.l_ui += JAN_1970;
 		ts.l_uf += ts_roundbit;
 		ts.l_uf &= ts_mask;
-		printf("  time %s, (.%0*d),\n",
-		       prettydate(&ts), fdigits, (int)time_frac);
-		printf("  maximum error %lu us, estimated error %lu us",
-		       (u_long)ntv.maxerror, (u_long)ntv.esterror);
+		printf(json ? jfmt2 : ofmt2,  prettydate(&ts), fdigits, (int)time_frac);
+		printf(json ? jfmt3 : ofmt3,  (u_long)ntv.maxerror, (u_long)ntv.esterror);
 		if (rawtime)
-			printf("  ntptime=%x.%x unixtime=%x.%0*d %s",
+			printf(json ? jfmt4 : ofmt4,
 			       (u_int)ts.l_ui, (u_int)ts.l_uf,
 			       (int)ntv.time.tv_sec, fdigits,
 			       (int)time_frac,
 			       ctime_r((time_t *)&ntv.time.tv_sec, ascbuf));
 #if NTP_API > 3
-		printf(", TAI offset %ld\n", (long)ntv.tai);
+		printf(json ? jfmt5 : ofmt5, (long)ntv.tai);
 #else
-		printf("\n");
+		printf(json ? jfmt6 : ofmt6);
 #endif /* NTP_API */
 	}
 	status = ntp_adjtime(&ntx);
@@ -299,47 +323,67 @@ main(
 		   "Must be root to set kernel values\nntp_adjtime() call fails" :
 		   "ntp_adjtime() call fails");
 	} else {
+		/* oldstyle formats */
+		char *ofmt7 = "ntp_adjtime() returns code %d (%s)\n";
+		char *ofmt8 = "  modes %s,\n";
+		char *ofmt9 = "  offset %.3f";
+		char *ofmt10 = " us, frequency %.3f ppm, interval %d s,\n";
+		char *ofmt11 = "  maximum error %lu us, estimated error %lu us,\n";
+		char *ofmt12 = "  status %s,\n";
+		char *ofmt13 = "  time constant %lu, precision %.3f us, tolerance %.0f ppm,\n";
+		char *ofmt14 = "  pps frequency %.3f ppm, stability %.3f ppm, jitter %.3f us,\n";
+		char *ofmt15 = "  intervals %lu, jitter exceeded %lu, stability exceeded %lu, errors %lu.\n";
+		/* JSON formats */
+		char *jfmt7 = "\"adjtime-code\":%d,\"adjtime-status\":%s,";
+		char *jfmt8 = "\"modes\":\"%s\",";
+		char *jfmt9 = "\"offset\":%.3f,";
+		char *jfmt10 = "\"frequency\":%.3f,\"interval\":%d,";
+		char *jfmt11 = "\"maximum error\":%lu,\"estimated error\":%lu,";
+		char *jfmt12 = "\"status\":\"%s\",";
+		char *jfmt13 = "\"time constant\":%lu,\"precision\":%.3f,\"tolerance\":%.0f,";
+		char *jfmt14 = "\"pps frequency\":%.3f,\"stability\":%.3f,\"jitter\":%.3f,";
+		char *jfmt15 = "\"intervals\":%lu,\"jitter exceeded\":%lu,\"stability exceeded\":%lu,\"errors:%lu\n";
+
 		flash = ntx.status;
-		printf("ntp_adjtime() returns code %d (%s)\n",
-		     status, timex_state(status));
-		printf("  modes %s,\n", sprintb(ntx.modes, TIMEX_MOD_BITS));
+		printf(json ? jfmt7 : ofmt7, status, timex_state(status));
+		printf(json ? jfmt8 : ofmt8, sprintb(ntx.modes, TIMEX_MOD_BITS));
 		ftemp = (double)ntx.offset;
 #ifdef STA_NANO
 		if (flash & STA_NANO)
 			ftemp /= 1000.0;
 #endif
-		printf("  offset %.3f", ftemp);
+		printf(json ? jfmt9 : ofmt9, ftemp);
 		ftemp = (double)ntx.freq / SCALE_FREQ;
-		printf(" us, frequency %.3f ppm, interval %d s,\n",
-		     ftemp, 1 << ntx.shift);
-		printf("  maximum error %lu us, estimated error %lu us,\n",
+		printf(json ? jfmt10 : ofmt10, ftemp, 1 << ntx.shift);
+		printf(json ? jfmt11 : ofmt11,
 		     (u_long)ntx.maxerror, (u_long)ntx.esterror);
-		printf("  status %s,\n", sprintb((u_int)ntx.status, TIMEX_STA_BITS));
+		printf(json ? jfmt12 : ofmt12,
+		       sprintb((u_int)ntx.status, TIMEX_STA_BITS));
 		ftemp = (double)ntx.tolerance / SCALE_FREQ;
 		gtemp = (double)ntx.precision;
 #ifdef STA_NANO
 		if (flash & STA_NANO)
 			gtemp /= 1000.0;
 #endif
-		printf(
-		    "  time constant %lu, precision %.3f us, tolerance %.0f ppm,\n",
-		    (u_long)ntx.constant, gtemp, ftemp);
-		if (ntx.shift == 0)
-			exit(0);
-		ftemp = (double)ntx.ppsfreq / SCALE_FREQ;
-		gtemp = (double)ntx.stabil / SCALE_FREQ;
-		htemp = (double)ntx.jitter;
+		printf(json ? jfmt13 : ofmt13,
+			(u_long)ntx.constant, gtemp, ftemp);
+		if (ntx.shift != 0) {
+			ftemp = (double)ntx.ppsfreq / SCALE_FREQ;
+			gtemp = (double)ntx.stabil / SCALE_FREQ;
+			htemp = (double)ntx.jitter;
 #ifdef STA_NANO
-		if (flash & STA_NANO)
-			htemp /= 1000.0;
+			if (flash & STA_NANO)
+				htemp /= 1000.0;
 #endif
-		printf(
-		    "  pps frequency %.3f ppm, stability %.3f ppm, jitter %.3f us,\n",
-		    ftemp, gtemp, htemp);
-		printf("  intervals %lu, jitter exceeded %lu, stability exceeded %lu, errors %lu.\n",
-		    (u_long)ntx.calcnt, (u_long)ntx.jitcnt,
-		    (u_long)ntx.stbcnt, (u_long)ntx.errcnt);
-		return 0;
+			printf(json ? jfmt14 : ofmt14,
+			    ftemp, gtemp, htemp);
+			printf(json ? jfmt15 : ofmt15,
+			    (u_long)ntx.calcnt, (u_long)ntx.jitcnt,
+			    (u_long)ntx.stbcnt, (u_long)ntx.errcnt);
+		}
+		if (json)
+			fputs("}\n", stdout);
+		exit(EXIT_SUCCESS);
 	}
 
 	/*
@@ -352,7 +396,9 @@ main(
 		exit(1);
 	}
 #endif
-	exit(0);
+	if (json)
+	    fputs("}\n", stdout);
+	exit(status < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
 }
 
 #ifdef SIGSYS



More information about the vc mailing list