[Reproducible-builds] Bug#794004: ghostscript: please support timestamps from environment

Dhole dhole at openmailbox.org
Wed Jul 29 17:45:02 UTC 2015


Source: ghostscript
Version: 9.15~dfsg-1
Severity: wishlist
Tags: patch
User: reproducible-builds at lists.alioth.debian.org
Usertags: toolchain timestamps
X-Debbugs-Cc: reproducible-builds at lists.alioth.debian.org

Hi,

While working on the "reproducible builds" effort [1], we have noticed
that the ghostscript embeds timestamps on the creation of pdf files.

For the Reproducible Builds effort we are proposing an environment
variable (SOURCE_DATE_EPOCH) [2] that will contain a deterministic epoch
timestamp (based on the latest debian/changelog entry) that could be
used, which should be automatically exported by debhelper in the future [3].

The attached patch proposes a way to use this variable to get
reproducible timestamps in the pdf files generated by ghostscript, if
the variable has been set (if not, it falls back to the old behavior).
With the attached patch packages using ghostscript would then
automatically generate reproducible pdf files.


[1]: https://wiki.debian.org/ReproducibleBuilds
[2]: https://wiki.debian.org/ReproducibleBuilds/TimestampsProposal
[3]: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=791815

Regards,
-- 
Dhole
-------------- next part --------------
diff -Nru ghostscript-9.15~dfsg/debian/changelog ghostscript-9.15~dfsg/debian/changelog
--- ghostscript-9.15~dfsg/debian/changelog	2015-07-26 20:17:32.000000000 +0200
+++ ghostscript-9.15~dfsg/debian/changelog	2015-07-28 18:48:03.000000000 +0200
@@ -1,3 +1,12 @@
+ghostscript (9.15~dfsg-1.0~reproducible1) UNRELEASED; urgency=medium
+
+  [ Peter De Wachter, Eduard Sanou ]
+  * Add patch to allow the build timestamp to be set through the environment
+    variable SOURCE_DATE_EPOCH, and set TZ=UTC in case the external timestamp
+    is used. This is needed for reproducible builds.
+
+ -- Eduard Sanou <dhole at openmailbox.org>  Tue, 28 Jul 2015 16:26:20 +0200
+
 ghostscript (9.15~dfsg-1) unstable; urgency=medium
 
   [ upstream ]
diff -Nru ghostscript-9.15~dfsg/debian/patches/2010_add_build_timestamp_setting.patch ghostscript-9.15~dfsg/debian/patches/2010_add_build_timestamp_setting.patch
--- ghostscript-9.15~dfsg/debian/patches/2010_add_build_timestamp_setting.patch	1970-01-01 01:00:00.000000000 +0100
+++ ghostscript-9.15~dfsg/debian/patches/2010_add_build_timestamp_setting.patch	2015-07-29 15:59:49.000000000 +0200
@@ -0,0 +1,122 @@
+Description: Allow the build timestamp to be externally set
+ In order to make Ghostscript output reproducible, we need a way to
+ set the build timestamp to other values than the current time.
+ We now consistently use gp_get_realtime() instead of directly calling
+ time() or gp_get_usertime() and make gp_get_realtime() use the value
+ found in the SOURCE_DATE_EPOCH environment variable if set. Also,
+ environment timezone is fixed to UTC if SOURCE_DATE_EPOCH is used to
+ avoid variations.
+Author: Peter De Wachter <pdewacht at gmail.com>, Eduard Sanou <dhole at openmailbox.org>
+
+Index: ghostscript-9.15~dfsg-1.0~reproducible1/base/gp_unix.c
+===================================================================
+--- ghostscript-9.15~dfsg-1.0~reproducible1.orig/base/gp_unix.c
++++ ghostscript-9.15~dfsg-1.0~reproducible1/base/gp_unix.c
+@@ -16,6 +16,7 @@
+ 
+ /* Unix-specific routines for Ghostscript */
+ 
++#include "errno_.h"
+ #include "pipe_.h"
+ #include "string_.h"
+ #include "time_.h"
+@@ -145,6 +146,7 @@ void
+ gp_get_realtime(long *pdt)
+ {
+     struct timeval tp;
++    const char *env;
+ 
+ #if gettimeofday_no_timezone    /* older versions of SVR4 */
+     {
+@@ -164,6 +166,26 @@ gp_get_realtime(long *pdt)
+     }
+ #endif
+ 
++    env = getenv("SOURCE_DATE_EPOCH");
++    if (env) {
++        char *end;
++        long timestamp;
++
++        errno = 0;
++        timestamp = strtol(env, &end, 10);
++        if (env == end || *end || errno != 0) {
++            lprintf("Ghostscript: SOURCE_DATE_EPOCH is not a number!\n");
++            timestamp = 0;
++        }
++
++        tp.tv_sec = timestamp;
++        tp.tv_usec = 0;
++
++        /* We need to fix the environment timezone to get reproducible */
++        /* results when parsing the result of gp_get_realtime. */
++        setenv("TZ", "UTC", 1);
++    }
++
+     /* tp.tv_sec is #secs since Jan 1, 1970 */
+     pdt[0] = tp.tv_sec;
+ 
+Index: ghostscript-9.15~dfsg-1.0~reproducible1/devices/vector/gdevpdf.c
+===================================================================
+--- ghostscript-9.15~dfsg-1.0~reproducible1.orig/devices/vector/gdevpdf.c
++++ ghostscript-9.15~dfsg-1.0~reproducible1/devices/vector/gdevpdf.c
+@@ -389,12 +389,14 @@ pdf_initialize_ids(gx_device_pdf * pdev)
+      */
+     {
+         struct tm tms;
++        long secs_ns[2];
+         time_t t;
+         char buf[1+2+4+2+2+2+2+2+1+2+1+2+1+1+1]; /* (D:yyyymmddhhmmssZhh'mm')\0 */
+         int timeoffset;
+         char timesign;
+ 
+-        time(&t);
++        gp_get_realtime(secs_ns);
++        t = secs_ns[0];
+         tms = *gmtime(&t);
+         tms.tm_isdst = -1;
+         timeoffset = (int)difftime(t, mktime(&tms)); /* tz+dst in seconds */
+@@ -437,7 +439,7 @@ pdf_compute_fileID(gx_device_pdf * pdev)
+     if (s == NULL)
+         return_error(gs_error_VMerror);
+     pdev->KeyLength = 0; /* Disable encryption. Not so important though. */
+-    gp_get_usertime(secs_ns);
++    gp_get_realtime(secs_ns);
+     sputs(s, (byte *)secs_ns, sizeof(secs_ns), &ignore);
+     sputs(s, (const byte *)pdev->fname, strlen(pdev->fname), &ignore);
+     pdev->strm = s;
+Index: ghostscript-9.15~dfsg-1.0~reproducible1/devices/vector/gdevpdfe.c
+===================================================================
+--- ghostscript-9.15~dfsg-1.0~reproducible1.orig/devices/vector/gdevpdfe.c
++++ ghostscript-9.15~dfsg-1.0~reproducible1/devices/vector/gdevpdfe.c
+@@ -200,10 +200,12 @@ pdf_xmp_time(char *buf, int buf_length)
+ {
+     /* We don't write a day time because we don't have a time zone. */
+     struct tm tms;
++    long secs_ns[2];
+     time_t t;
+     char buf1[4+1+2+1+2+1]; /* yyyy-mm-dd\0 */
+ 
+-    time(&t);
++    gp_get_realtime(secs_ns);
++    t = secs_ns[0];
+     tms = *localtime(&t);
+     gs_sprintf(buf1,
+             "%04d-%02d-%02d",
+Index: ghostscript-9.15~dfsg-1.0~reproducible1/devices/vector/gdevpsu.c
+===================================================================
+--- ghostscript-9.15~dfsg-1.0~reproducible1.orig/devices/vector/gdevpsu.c
++++ ghostscript-9.15~dfsg-1.0~reproducible1/devices/vector/gdevpsu.c
+@@ -183,10 +183,12 @@ psw_begin_file_header(FILE *f, const gx_
+     fprintf(f, "%%%%Creator: %s %ld (%s)\n", gs_product, (long)gs_revision,
+             dev->dname);
+     {
++        long secs_ns[2];
+         time_t t;
+         struct tm tms;
+ 
+-        time(&t);
++        gp_get_realtime(secs_ns);
++        t = secs_ns[0];
+         tms = *localtime(&t);
+         fprintf(f, "%%%%CreationDate: %d/%02d/%02d %02d:%02d:%02d\n",
+                 tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday,
diff -Nru ghostscript-9.15~dfsg/debian/patches/series ghostscript-9.15~dfsg/debian/patches/series
--- ghostscript-9.15~dfsg/debian/patches/series	2015-07-26 12:00:49.000000000 +0200
+++ ghostscript-9.15~dfsg/debian/patches/series	2015-07-28 16:32:03.000000000 +0200
@@ -9,3 +9,4 @@
 2007_suggest_install_ghostscript-doc_in_code.patch
 2008_mention_ghostscript-x_in_docs.patch
 2009_avoid_ramfs.patch
+2010_add_build_timestamp_setting.patch
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: OpenPGP digital signature
URL: <http://lists.alioth.debian.org/pipermail/reproducible-builds/attachments/20150729/dcc62f74/attachment.sig>


More information about the Reproducible-builds mailing list