Download raw body.
rpki-client: normalize 'buildtime' in the output
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);
>
rpki-client: normalize 'buildtime' in the output