Package: netpbm Version: 2:10.0-15.3 Severity: wishlist Tags: patch upstream User: [email protected] Usertags: toolchain X-Debbugs-Cc: [email protected]
Dear Maintainer, While working on the "reproducible builds" effort [1], we have noticed that some packages (like latex2html) use one of the netpbm utilities in their process, leading to unreproducible output (due to the use of the random generator, seeded from a time() call). To solve this kind of issues, it would be nice to make netpbm support the SOURCE_DATE_EPOCH environment variable [2]. See the attached patch for a proposed solution. Regards, Alexis Bienvenüe. [1] https://wiki.debian.org/ReproducibleBuilds [2] https://reproducible-builds.org/specs/source-date-epoch/
diff -u netpbm-free-10.0/debian/changelog netpbm-free-10.0/debian/changelog --- netpbm-free-10.0/debian/changelog +++ netpbm-free-10.0/debian/changelog @@ -1,3 +1,9 @@ +netpbm-free (2:10.0-15.3.0~reproducible1) UNRELEASED; urgency=medium + + * SOURCE_DATE_EPOCH support. + + -- Alexis Bienvenüe <[email protected]> Sun, 12 Jun 2016 11:43:19 +0200 + netpbm-free (2:10.0-15.3) unstable; urgency=medium * Non-maintainer upload. only in patch2: unchanged: --- netpbm-free-10.0.orig/include/pm.h +++ netpbm-free-10.0/include/pm.h @@ -20,6 +20,7 @@ #include <stdio.h> #include <errno.h> #include <sys/stat.h> +#include <time.h> #ifdef VMS #include <perror.h> @@ -245,5 +246,10 @@ char * pm_arg0toprogname(const char arg0[]); +/* SOURCE_DATE_EPOCH support */ + +time_t +pm_source_time(int use_pid); + #endif only in patch2: unchanged: --- netpbm-free-10.0.orig/pbm/libpm.c +++ netpbm-free-10.0/pbm/libpm.c @@ -23,6 +23,9 @@ #include <stdarg.h> #include <string.h> #include <errno.h> +#include <stdlib.h> +#include <limits.h> +#include <unistd.h> /* The following are set by pm_init(), then used by subsequent calls to other pm_xxx() functions. @@ -938,3 +941,42 @@ return realloc(a, b*c); } +time_t pm_source_time(int use_pid) +{ + time_t now; + char *source_date_epoch; + unsigned long long epoch; + char *endptr; + + source_date_epoch = getenv("SOURCE_DATE_EPOCH"); + if (source_date_epoch) { + errno = 0; + epoch = strtoull(source_date_epoch, &endptr, 10); + if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0)) + || (errno != 0 && epoch == 0)) { + fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: strtoull: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + if (endptr == source_date_epoch) { + fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: No digits were found: %s\n", endptr); + exit(EXIT_FAILURE); + } + if (*endptr != '\0') { + fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: Trailing garbage: %s\n", endptr); + exit(EXIT_FAILURE); + } + if (epoch > ULONG_MAX) { + fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: value must be smaller than or equal to: %lu but was found to be: %llu \n", ULONG_MAX, epoch); + exit(EXIT_FAILURE); + } + now = epoch; + return(now); + } else { + now = time(NULL); + if(use_pid) { + return(now ^ getpid()); + } else { + return(now); + } + } +} only in patch2: unchanged: --- netpbm-free-10.0.orig/pbm/pbmreduce.c +++ netpbm-free-10.0/pbm/pbmreduce.c @@ -98,7 +98,7 @@ if ( thiserr == 0 || nexterr == 0 ) pm_error( "out of memory" ); - srand( (int) ( time( 0 ) ^ getpid( ) ) ); + srand( (int) ( pm_source_time(1) ) ); for ( col = 0; col < newcols + 2; ++col ) thiserr[col] = ( rand( ) % SCALE - HALFSCALE ) / 4; /* (random errors in [-SCALE/8 .. SCALE/8]) */ only in patch2: unchanged: --- netpbm-free-10.0.orig/pgm/pgmcrater.c +++ netpbm-free-10.0/pgm/pgmcrater.c @@ -107,7 +107,7 @@ { int i; - i = time((long *) 0) * 0xF37C; + i = pm_source_time(0) * 0xF37C; srand(i); for (i = 0; i < 7; i++) { V rand(); only in patch2: unchanged: --- netpbm-free-10.0.orig/pgm/pgmnoise.c +++ netpbm-free-10.0/pgm/pgmnoise.c @@ -57,7 +57,7 @@ pgm_writepgminit(stdout, cols, rows, PGM_MAXMAXVAL, 0); /* get time of day to feed the random number generator */ - timenow = time(NULL); + timenow = pm_source_time(0); srand(timenow); /* create the (gray) noise */ only in patch2: unchanged: --- netpbm-free-10.0.orig/pgm/pgmtopbm.c +++ netpbm-free-10.0/pgm/pgmtopbm.c @@ -132,7 +132,7 @@ overflow_add(cols, 2); thiserr = (long*) pm_allocrow( cols + 2, sizeof(long) ); nexterr = (long*) pm_allocrow( cols + 2, sizeof(long) ); - srand( (int) ( time( 0 ) ^ getpid( ) ) ); + srand( (int) ( pm_source_time(1) ) ); for ( col = 0; col < cols + 2; ++col ) thiserr[col] = ( rand( ) % FS_SCALE - HALF_FS_SCALE ) / 4; /* (random errors in [-FS_SCALE/8 .. FS_SCALE/8]) */ only in patch2: unchanged: --- netpbm-free-10.0.orig/pnm/pnmremap.c +++ netpbm-free-10.0/pnm/pnmremap.c @@ -243,7 +243,7 @@ pm_error("Out of memory allocating Floyd-Steinberg structures"); } - srand((int)(time(0) ^ getpid())); + srand((int)(pm_source_time(1))); { int col; only in patch2: unchanged: --- netpbm-free-10.0.orig/ppm/libppmfloyd.c +++ netpbm-free-10.0/ppm/libppmfloyd.c @@ -48,7 +48,7 @@ fi->flags = flags; if( flags & FS_RANDOMINIT ) { - srandom((int)(time(0) ^ getpid())); + srandom((int)(pm_source_time(1))); for( i = 0; i < cols +2; i++ ) { /* random errors in [-1..+1] */ fi->thisrederr[i] = random() % 32 - 16; only in patch2: unchanged: --- netpbm-free-10.0.orig/ppm/ppmforge.c +++ netpbm-free-10.0/ppm/ppmforge.c @@ -322,7 +322,7 @@ static void initseed() { - int i = time((long *) 0) ^ 0xF37C; + int i = pm_source_time(0) ^ 0xF37C; V srand(i); for (i = 0; i < 7; i++) V rand(); only in patch2: unchanged: --- netpbm-free-10.0.orig/ppm/ppmpat.c +++ netpbm-free-10.0/ppm/ppmpat.c @@ -142,7 +142,7 @@ if ( argn != argc ) pm_usage( usage); - srand( (int) ( time( 0 ) ^ getpid( ) ) ); + srand( (int) ( pm_source_time(1) ) ); pixels = ppm_allocarray( cols, rows ); switch ( pattern ) only in patch2: unchanged: --- netpbm-free-10.0.orig/ppm/ppmquant.c +++ netpbm-free-10.0/ppm/ppmquant.c @@ -522,7 +522,7 @@ fserrP->thisberr = (long*) pm_allocrow( cols + 2, sizeof(long) ); fserrP->nextberr = (long*) pm_allocrow( cols + 2, sizeof(long) ); - srand( (int) ( time( 0 ) ^ getpid( ) ) ); + srand( (int) ( pm_source_time(1) ) ); for (col = 0; col < cols + 2; ++col) { fserrP->thisrerr[col] = rand( ) % ( FS_SCALE * 2 ) - FS_SCALE; only in patch2: unchanged: --- netpbm-free-10.0.orig/ppm/ppmshift.c +++ netpbm-free-10.0/ppm/ppmshift.c @@ -76,7 +76,7 @@ ppm_writeppminit(stdout, cols, rows, maxval, 0); /* get time of day to feed the random number generator */ - timenow = time(NULL); + timenow = pm_source_time(0); srand(timenow); /** now do the shifting **/ only in patch2: unchanged: --- netpbm-free-10.0.orig/ppm/ppmspread.c +++ netpbm-free-10.0/ppm/ppmspread.c @@ -72,7 +72,7 @@ /* set seed for random number generator */ /* get time of day to feed the random number generator */ - timenow = time(NULL); + timenow = pm_source_time(0); srand(timenow); /* start displacing pixels */ only in patch2: unchanged: --- netpbm-free-10.0.orig/urt/rle_addhist.c +++ netpbm-free-10.0/urt/rle_addhist.c @@ -29,6 +29,7 @@ #include "rle.h" #include <stdio.h> +#include <stdlib.h> #ifdef USE_TIME_H #include <time.h> @@ -63,7 +64,7 @@ /* plus one for "=" */ static CONST_DECL char *histoire="HISTORY", *padding="\t"; - char *timedate,*old= NULL; + char *timedate,*old= NULL,*source_date_epoch; static char *newc; if(getenv("NO_ADD_RLE_HISTORY"))return; @@ -75,8 +76,14 @@ overflow_add(length+1, strlen(argv[i])); length+= strlen(argv[i]) +1; /* length of each arg plus space. */ } - (void)time (&temp); - timedate=ctime(&temp); + source_date_epoch=getenv("SOURCE_DATE_EPOCH"); + if(source_date_epoch) { + temp=strtoull(source_date_epoch,NULL,10); + timedate=asctime(gmtime(&temp)); + } else { + (void)time (&temp); + timedate=ctime(&temp); + } length+= strlen(timedate); /* length of date and time in ASCII. */ overflow_add(strlen(padding), 4);

