From c9248551038642c9f036920a9d82b19acee741ed Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Sun, 10 Nov 2024 10:49:28 +0000 Subject: [PATCH] Support SOURCE_DATE_EPOCH If set, it is used to set the "created" and "modified" fields in the OpenType 'head' table. This means that builds of Bedstead can be reproducible. The current code just casts the "long long" interpretation of the environment variable into a time_t. This is potentially undefined behaviour, because time_t might be a signed integer type smaller than "long long". But I can't find a way to properly range-check it. Even in POSIX, where time_t is required to be an integer type, there doesn't seem to be a constant that specifies its range. --- bedstead.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/bedstead.c b/bedstead.c index 7522b6e..104983b 100644 --- a/bedstead.c +++ b/bedstead.c @@ -99,6 +99,7 @@ #include #include #include +#include #include #include #include @@ -2730,14 +2731,34 @@ static char * time_for_ttx(void) { time_t now; + long long epochll; struct tm *timeptr; - char *timestr; + char *epochstr, *endptr, *timestr; /* Work out what timestamp to use. */ - now = time(NULL); - if (now == (time_t)-1) { - fprintf(stderr, "Can't get current time\n"); - return NULL; + if ((epochstr = getenv("SOURCE_DATE_EPOCH")) != NULL) { + /* + * Assume that SOURCE_DATE_EPOCH is set only on + * systems where time_t is also in seconds since the + * epoch. + */ + epochll = strtoll(epochstr, &endptr, 10); + if (endptr == epochstr || *endptr != '\0' || + epochll == LLONG_MAX) { + fprintf(stderr, "Invalid SOURCE_DATE_EPOCH\n"); + return NULL; + } + /* + * I can't find a way to range-check this assignment + * in standard C or even in POSIX. + */ + now = epochll; + } else { + now = time(NULL); + if (now == (time_t)-1) { + fprintf(stderr, "Can't get current time\n"); + return NULL; + } } timeptr = gmtime(&now); if (timeptr == NULL) { -- 2.30.2