+/* Returns false if SOURCE_DATE_EPOCH was not defined in the environment.
+ *
+ * Returns true if SOURCE_DATE_EPOCH is in the environment and represent
+ * a valid timestamp, in which case the timestamp is formatted into the
+ * global variables _date_ and _time_.
+ *
+ * Aborts if SOURCE_DATE_EPOCH was set in the environment but did not
+ * contain a valid timestamp.
+ *
+ * Valid values are defined in the spec:
+ * https://reproducible-builds.org/specs/source-date-epoch/
+ * but we further restrict them to be positive or null.
+ */
+bool parse_source_date_epoch_from_env(void)
+{
+ char *epoch_env, *endptr;
+ time_t epoch;
+ struct tm epoch_tm;
+
+ if ((epoch_env = getenv("SOURCE_DATE_EPOCH")) == NULL)
+ return false;
+ errno = 0;
+ epoch = (time_t) strtoll(epoch_env, &endptr, 10);
+ /* We just need to test if it is incorrect, but we do not
+ * care why it is incorrect.
+ */
+ if ((errno != 0) || !*epoch_env || *endptr || (epoch < 0)) {
+ fprintf(stderr, "%s: invalid SOURCE_DATE_EPOCH='%s'\n",
+ program_invocation_short_name,
+ epoch_env);
+ exit(1);
+ }
+ tzset(); /* For localtime_r(), below. */
+ if (localtime_r(&epoch, &epoch_tm) == NULL) {
+ fprintf(stderr, "%s: cannot parse SOURCE_DATE_EPOCH=%s\n",
+ program_invocation_short_name,
+ getenv("SOURCE_DATE_EPOCH"));
+ exit(1);
+ }
+ if (!strftime(_time_, sizeof(_time_), "-D__TIME__=\"%T\"", &epoch_tm)) {
+ fprintf(stderr, "%s: cannot set time from SOURCE_DATE_EPOCH=%s\n",
+ program_invocation_short_name,
+ getenv("SOURCE_DATE_EPOCH"));
+ exit(1);
+ }
+ if (!strftime(_date_, sizeof(_date_), "-D__DATE__=\"%b %e %Y\"", &epoch_tm)) {
+ fprintf(stderr, "%s: cannot set date from SOURCE_DATE_EPOCH=%s\n",
+ program_invocation_short_name,
+ getenv("SOURCE_DATE_EPOCH"));
+ exit(1);
+ }
+ return true;
+}
+