Index | Thread | Search

From:
Job Snijders <job@openbsd.org>
Subject:
rpki-client: normalize 'buildtime' in the output
To:
tech@openbsd.org
Date:
Thu, 30 Oct 2025 19:40:36 +0000

Download raw body.

Thread
Hello,

In some of my analytics pipelines it became a nuisance how outputs from
the same validation run could have slightly different timestamps,
because of slight delays in I/O.

With the below diff the outputs generated from the same validated data
will have the same timestamp, and the modification time on disk will
also reflect this timestamp.

OK?

Kind regards,

Job

Index: ccr.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/ccr.c,v
diff -u -p -r1.26 ccr.c
--- ccr.c	18 Oct 2025 08:12:32 -0000	1.26
+++ ccr.c	30 Oct 2025 19:36:21 -0000
@@ -603,7 +603,6 @@ static CanonicalCacheRepresentation *
 generate_ccr(struct validation_data *vd)
 {
 	CanonicalCacheRepresentation *ccr = NULL;
-	time_t now = get_current_time();
 
 	if ((ccr = CanonicalCacheRepresentation_new()) == NULL)
 		errx(1, "CanonicalCacheRepresentation_new");
@@ -612,7 +611,7 @@ generate_ccr(struct validation_data *vd)
 	if ((ccr->hashAlg = OBJ_nid2obj(NID_sha256)) == NULL)
 		errx(1, "OBJ_nid2obj");
 
-	if (ASN1_GENERALIZEDTIME_set(ccr->producedAt, now) == NULL)
+	if (ASN1_GENERALIZEDTIME_set(ccr->producedAt, vd->buildtime) == NULL)
 		errx(1, "ASN1_GENERALIZEDTIME_set");
 
 	if ((ccr->mfts = generate_manifeststate(vd)) == NULL)
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
diff -u -p -r1.265 extern.h
--- extern.h	16 Oct 2025 06:46:31 -0000	1.265
+++ extern.h	30 Oct 2025 19:36:21 -0000
@@ -512,6 +512,7 @@ struct ccr {
 };
 
 struct validation_data {
+	time_t buildtime;
 	struct vrp_tree	vrps;
 	struct brk_tree	brks;
 	struct vap_tree	vaps;
Index: main.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v
diff -u -p -r1.300 main.c
--- main.c	17 Oct 2025 08:09:21 -0000	1.300
+++ main.c	30 Oct 2025 19:36:21 -0000
@@ -1553,6 +1553,8 @@ main(int argc, char *argv[])
 		timespecadd(&stats.system_time, &ts, &stats.system_time);
 	}
 
+	vd.buildtime = get_current_time();
+
 	/* change working directory to the output directory */
 	if (fchdir(outdirfd) == -1)
 		err(1, "fchdir output dir");
Index: output-bird.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/output-bird.c,v
diff -u -p -r1.25 output-bird.c
--- output-bird.c	23 Aug 2025 09:13:14 -0000	1.25
+++ output-bird.c	30 Oct 2025 19:36:21 -0000
@@ -25,7 +25,6 @@ output_bird(FILE *out, struct validation
 {
 	struct vrp	*v;
 	struct vap	*vap;
-	time_t		 now = get_current_time();
 	size_t		 i;
 
 	if (fprintf(out, "# For BIRD %s\n#\n", excludeaspa ? "2" : "2.16+") < 0)
@@ -35,7 +34,8 @@ output_bird(FILE *out, struct validation
 		return -1;
 
 	if (fprintf(out, "\ndefine force_roa_table_update = %lld;\n\n"
-	    "roa4 table ROAS4;\nroa6 table ROAS6;\n", (long long)now) < 0)
+	    "roa4 table ROAS4;\nroa6 table ROAS6;\n",
+	    (long long)vd->buildtime) < 0)
 		return -1;
 
 	if (!excludeaspa) {
Index: output-json.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/output-json.c,v
diff -u -p -r1.57 output-json.c
--- output-json.c	17 Sep 2025 12:10:08 -0000	1.57
+++ output-json.c	30 Oct 2025 19:36:21 -0000
@@ -28,11 +28,9 @@ outputheader_json(struct validation_data
 {
 	char		 hn[NI_MAXHOST], tbuf[26];
 	struct tm	*tp;
-	time_t		 t;
 	int		 i;
 
-	time(&t);
-	tp = gmtime(&t);
+	tp = gmtime(&vd->buildtime);
 	strftime(tbuf, sizeof tbuf, "%FT%TZ", tp);
 
 	gethostname(hn, sizeof hn);
Index: output.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/output.c,v
diff -u -p -r1.42 output.c
--- output.c	23 Aug 2025 09:13:14 -0000	1.42
+++ output.c	30 Oct 2025 19:36:21 -0000
@@ -76,7 +76,7 @@ static const struct outputs {
 
 static FILE	*output_createtmp(char *);
 static void	 output_cleantmp(void);
-static int	 output_finish(FILE *);
+static int	 output_finish(FILE *, time_t);
 static void	 sig_handler(int);
 static void	 set_signal_handler(void);
 
@@ -152,7 +152,7 @@ outputfiles(struct validation_data *vd, 
 			rc = 1;
 			continue;
 		}
-		if (output_finish(fout) != 0) {
+		if (output_finish(fout, vd->buildtime) != 0) {
 			warn("finish for %s format failed", outputs[i].name);
 			output_cleantmp();
 			rc = 1;
@@ -187,12 +187,23 @@ output_createtmp(char *name)
 }
 
 static int
-output_finish(FILE *out)
+output_finish(FILE *out, time_t buildtime)
 {
+	struct timespec ts[2];
+
 	if (fclose(out) != 0)
 		return -1;
+
+	ts[0].tv_nsec = UTIME_OMIT;
+	ts[1].tv_sec = buildtime;
+	ts[1].tv_nsec = 0;
+
+	if (utimensat(AT_FDCWD, output_tmpname, ts, 0) == -1)
+		return -1;
+
 	if (rename(output_tmpname, output_name) == -1)
 		return -1;
+
 	output_tmpname[0] = '\0';
 	return 0;
 }
@@ -243,11 +254,9 @@ outputheader(FILE *out, struct validatio
 {
 	char		hn[NI_MAXHOST], tbuf[80];
 	struct tm	*tp;
-	time_t		t;
 	int		i;
 
-	time(&t);
-	tp = gmtime(&t);
+	tp = gmtime(&vd->buildtime);
 	strftime(tbuf, sizeof tbuf, "%a %b %e %H:%M:%S UTC %Y", tp);
 
 	gethostname(hn, sizeof hn);