Index | Thread | Search

From:
Theo Buehler <tb@theobuehler.org>
Subject:
Re: rpki-client: normalize 'buildtime' in the output
To:
Job Snijders <job@openbsd.org>
Cc:
tech@openbsd.org
Date:
Thu, 30 Oct 2025 21:39:01 +0100

Download raw body.

Thread
On Thu, Oct 30, 2025 at 07:40:36PM +0000, Job Snijders wrote:
> 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?

The output.c changes except the one in outputheader() are largely
unrelated and should be done separately. The rest is ok with me.

> 
> 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);
>