From: Ben Harris Date: Sun, 10 Nov 2024 10:49:28 +0000 (+0000) Subject: Support SOURCE_DATE_EPOCH X-Git-Tag: bedstead-3.246~40 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~bjharris/git?a=commitdiff_plain;h=c9248551038642c9f036920a9d82b19acee741ed;p=bedstead.git 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. --- 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) {