diff --git a/usr.bin/mkimg/mkimg.h b/usr.bin/mkimg/mkimg.h --- a/usr.bin/mkimg/mkimg.h +++ b/usr.bin/mkimg/mkimg.h @@ -29,6 +29,10 @@ #include #include +#include + +extern bool reproducible; +extern time_t source_date_epoch; struct part { TAILQ_ENTRY(part) link; diff --git a/usr.bin/mkimg/mkimg.1 b/usr.bin/mkimg/mkimg.1 --- a/usr.bin/mkimg/mkimg.1 +++ b/usr.bin/mkimg/mkimg.1 @@ -41,6 +41,7 @@ .Op Fl f Ar format .Op Fl o Ar outfile .Op Fl a Ar active +.Op Fl R .Op Fl v .Op Fl y .Op Fl s Ar scheme Op Fl p Ar partition ... @@ -138,6 +139,13 @@ same time. .Pp The +.Fl R +option enables reproducible mode: any timestamps or random identifiers will +be fixed so as to ensure consistent output. +See also the description of +.Ev SOURCE_DATE_EPOCH . +.Pp +The .Fl v option increases the level of output that the .Nm @@ -329,6 +337,9 @@ .It Ev TMPDIR Directory to put temporary files in; default is .Pa /tmp . +.It Ev SOURCE_DATE_EPOCH +The source of any timestamps embedded in the output file. +The value must be an ASCII representation of a UNIX timestamp. .El .Sh EXAMPLES To create a bootable disk image that is partitioned using the GPT scheme and diff --git a/usr.bin/mkimg/mkimg.c b/usr.bin/mkimg/mkimg.c --- a/usr.bin/mkimg/mkimg.c +++ b/usr.bin/mkimg/mkimg.c @@ -61,6 +61,9 @@ static uint64_t min_capacity = 0; static uint64_t max_capacity = 0; +bool reproducible = false; +time_t source_date_epoch = -1; + struct partlisthead partlist = TAILQ_HEAD_INITIALIZER(partlist); u_int nparts = 0; @@ -555,13 +558,23 @@ int main(int argc, char *argv[]) { - const char *format_name; + const char *format_name, *var; int bcfd, outfd; int c, error; + var = getenv("SOURCE_DATE_EPOCH"); + if (var != NULL) { + char *end; + + errno = 0; + source_date_epoch = (time_t)strtoul(var, &end, 10); + if (*end != '\0' || errno != 0 || source_date_epoch < 0) + errx(EX_DATAERR, "invalid SOURCE_DATE_EPOCH"); + } + bcfd = -1; outfd = 1; /* Write to stdout by default */ - while ((c = getopt_long(argc, argv, "a:b:c:C:f:o:p:s:vyH:P:S:T:", + while ((c = getopt_long(argc, argv, "a:b:c:C:f:o:p:s:vyH:P:RS:T:", longopts, NULL)) != -1) { switch (c) { case 'a': /* ACTIVE PARTITION, if supported */ @@ -606,6 +619,9 @@ if (error) errc(EX_DATAERR, error, "partition"); break; + case 'R': + reproducible = true; + break; case 's': /* SCHEME */ if (scheme_selected() != NULL) usage("multiple schemes given"); @@ -675,6 +691,9 @@ if (max_capacity != 0 && min_capacity > max_capacity) usage("minimum capacity cannot be larger than the maximum one"); + if (reproducible) + srandom(42); + if (secsz > blksz) { if (blksz != 0) errx(EX_DATAERR, "the physical block size cannot " diff --git a/usr.bin/mkimg/uuid.c b/usr.bin/mkimg/uuid.c --- a/usr.bin/mkimg/uuid.c +++ b/usr.bin/mkimg/uuid.c @@ -45,20 +45,9 @@ } #endif /* __APPLE__ */ -#ifdef __FreeBSD__ -#include - -static void -osdep_uuidgen(mkimg_uuid_t *uuid) -{ - - uuidgen((void *)uuid, 1); -} -#endif /* __FreeBSD__ */ - -#ifdef __linux__ +#if defined(__linux__) || defined(__FreeBSD__) +#include #include -#include static void osdep_uuidgen(mkimg_uuid_t *uuid) @@ -68,7 +57,12 @@ u_int i; uint16_t seq; - if (gettimeofday(&tv, NULL) == -1) + if (reproducible) + memset(&tv, 0, sizeof(tv)); + else if (source_date_epoch >= 0) { + tv.tv_sec = source_date_epoch; + tv.tv_usec = 0; + } else if (gettimeofday(&tv, NULL) == -1) abort(); time += (uint64_t)tv.tv_sec * 10000000LL;