Bug#864082: fontconfig: please make the cache files reproducible
Chris Lamb
lamby at debian.org
Sun Jun 4 08:13:09 UTC 2017
Source: fontconfig
Version: 2.12.1-0.1
Severity: wishlist
Tags: patch
User: reproducible-builds at lists.alioth.debian.org
Usertags: timestamps
X-Debbugs-Cc: reproducible-bugs at lists.alioth.debian.org
Hi,
Whilst working on the Reproducible Builds effort [0], we noticed that
fontconfig generates non-reproducible cache files under
/var/cache/fontconfig.
This is because fontconfig embeds the mtime of each font directory
in a "checksum" member of a "_FcCache" struct. This is so that it
can identify which cache files remain valid and/or require
regeneration.
We therefore "clamp" the mtimes of font directories to SOURCE_DATE_EPOCH
prior to calling fc-cache to avoid these non-deterministic values
appearing in the files themselves. This is safe as we now force
regeneration in subsequent fc-cache calls with -f.
(We can't just replace the checksum value with SOURCE_DATE_EPOCH as it
will result in fontconfig believing the cache to be outdated, defeating
the entire point of generating them in the first place.)
This work was sponsored by Tails[1].
Patch attached.
[0] https://reproducible-builds.org/
[1] https://tails.boum.org/
Regards,
--
,''`.
: :' : Chris Lamb
`. `'` lamby at debian.org / chris-lamb.co.uk
`-
-------------- next part --------------
diff --git a/debian/fontconfig.postinst b/debian/fontconfig.postinst
index ad7ac19..dfba70e 100644
--- a/debian/fontconfig.postinst
+++ b/debian/fontconfig.postinst
@@ -2,10 +2,28 @@
set -e
+if [ -n "$SOURCE_DATE_EPOCH" ]; then
+ # fontconfig embeds the mtime of each font directory in a "checksum" member
+ # of a "_FcCache" struct. This is so that it can identify which cache files
+ # remain valid and/or require regeneration.
+ #
+ # We therefore "clamp" the mtimes of font directories to SOURCE_DATE_EPOCH
+ # prior to calling fc-cache to avoid these non-deterministic values appearing
+ # in the files themselves. This is safe as we force regeneration in
+ # subsequent fc-cache calls with -f.
+ #
+ # (We can't just replace the checksum value with SOURCE_DATE_EPOCH as it will
+ # result in fontconfig believing the cache to be outdated, defeating the
+ # entire point of generating them in the first place.
+ fc-cache -s --list-dirs | \
+ xargs -I{} find {} -type d -follow -newermt "@$SOURCE_DATE_EPOCH" -print0 2>/dev/null | \
+ xargs -0r touch --date="@$SOURCE_DATE_EPOCH"
+fi
+
if [ "$1" = triggered ]; then
# Force regeneration of all fontconfig cache files.
mkdir -p /var/cache/fontconfig
- fc-cache -s -v 1>/var/log/fontconfig.log 2>&1 || printf "fc-cache failed.\nSee /var/log/fontconfig.log for more information.\n"
+ fc-cache -s -f -v 1>/var/log/fontconfig.log 2>&1 || printf "fc-cache failed.\nSee /var/log/fontconfig.log for more information.\n"
exit 0
fi
diff --git a/fc-cache/fc-cache.1 b/fc-cache/fc-cache.1
index e514779..f5a733d 100644
--- a/fc-cache/fc-cache.1
+++ b/fc-cache/fc-cache.1
@@ -4,7 +4,7 @@
fc-cache \- build font information cache files
.SH SYNOPSIS
.sp
-\fBfc-cache\fR [ \fB-EfrsvVh\fR ] [ \fB--error-on-no-fonts\fR ] [ \fB--force\fR ] [ \fB--really-force\fR ] [ \fB [ -y \fIdir\fB ] [ --sysroot \fIdir\fB ] \fR ] [ \fB--system-only\fR ] [ \fB--verbose\fR ] [ \fB--version\fR ] [ \fB--help\fR ] [ \fB\fIdir\fB\fR\fI...\fR ]
+\fBfc-cache\fR [ \fB-EfrsvVh\fR ] [ \fB--error-on-no-fonts\fR ] [ \fB--force\fR ] [ \fB--really-force\fR ] [ \fB [ -y \fIdir\fB ] [ --sysroot \fIdir\fB ] \fR ] [ \fB--system-only\fR ] [ \fB--list-dirs\fR ] [ \fB--verbose\fR ] [ \fB--version\fR ] [ \fB--help\fR ] [ \fB\fIdir\fB\fR\fI...\fR ]
.SH "DESCRIPTION"
.PP
\fBfc-cache\fR scans the font directories on
@@ -44,6 +44,9 @@ Erase all existing cache files and rescan.
Only scan system-wide directories, omitting the places
located in the user's home directory.
.TP
+\fB-l\fR
+Only list directories, don't regenerate anything.
+.TP
\fB-v\fR
Display status information while busy.
.TP
diff --git a/fc-cache/fc-cache.c b/fc-cache/fc-cache.c
index 0336073..fc5ff07 100644
--- a/fc-cache/fc-cache.c
+++ b/fc-cache/fc-cache.c
@@ -70,6 +70,7 @@ const struct option longopts[] = {
{"really-force", 0, 0, 'r'},
{"sysroot", required_argument, 0, 'y'},
{"system-only", 0, 0, 's'},
+ {"list-dirs", 0, 0, 'l'},
{"version", 0, 0, 'V'},
{"verbose", 0, 0, 'v'},
{"help", 0, 0, 'h'},
@@ -87,10 +88,10 @@ usage (char *program, int error)
{
FILE *file = error ? stderr : stdout;
#if HAVE_GETOPT_LONG
- fprintf (file, "usage: %s [-EfrsvVh] [-y SYSROOT] [--error-on-no-fonts] [--force|--really-force] [--sysroot=SYSROOT] [--system-only] [--verbose] [--version] [--help] [dirs]\n",
+ fprintf (file, "usage: %s [-EfrslvVh] [-y SYSROOT] [--error-on-no-fonts] [--force|--really-force] [--sysroot=SYSROOT] [--system-only] [--list-dirs] [--verbose] [--version] [--help] [dirs]\n",
program);
#else
- fprintf (file, "usage: %s [-EfrsvVh] [-y SYSROOT] [dirs]\n",
+ fprintf (file, "usage: %s [-EfrslvVh] [-y SYSROOT] [dirs]\n",
program);
#endif
fprintf (file, "Build font information caches in [dirs]\n"
@@ -102,6 +103,7 @@ usage (char *program, int error)
fprintf (file, " -r, --really-force erase all existing caches, then rescan\n");
fprintf (file, " -s, --system-only scan system-wide directories only\n");
fprintf (file, " -y, --sysroot=SYSROOT prepend SYSROOT to all paths for scanning\n");
+ fprintf (file, " -l, --list-dirs list directories only\n");
fprintf (file, " -v, --verbose display status information while busy\n");
fprintf (file, " -V, --version display font config version and exit\n");
fprintf (file, " -h, --help display this help and exit\n");
@@ -112,6 +114,7 @@ usage (char *program, int error)
fprintf (file, " -r, (really force) erase all existing caches, then rescan\n");
fprintf (file, " -s (system) scan system-wide directories only\n");
fprintf (file, " -y SYSROOT (sysroot) prepend SYSROOT to all paths for scanning\n");
+ fprintf (file, " -l (list-dirs) list directories only\n");
fprintf (file, " -v (verbose) display status information while busy\n");
fprintf (file, " -V (version) display font config version and exit\n");
fprintf (file, " -h (help) display this help and exit\n");
@@ -282,19 +285,21 @@ main (int argc, char **argv)
FcBool force = FcFalse;
FcBool really_force = FcFalse;
FcBool systemOnly = FcFalse;
+ FcBool listDirs = FcFalse;
FcBool error_on_no_fonts = FcFalse;
FcConfig *config;
FcChar8 *sysroot = NULL;
+ FcChar8 *dir;
int i;
int changed;
- int ret;
+ int ret = 0;
#if HAVE_GETOPT_LONG || HAVE_GETOPT
int c;
#if HAVE_GETOPT_LONG
- while ((c = getopt_long (argc, argv, "Efrsy:Vvh", longopts, NULL)) != -1)
+ while ((c = getopt_long (argc, argv, "Efrsly:Vvh", longopts, NULL)) != -1)
#else
- while ((c = getopt (argc, argv, "Efrsy:Vvh")) != -1)
+ while ((c = getopt (argc, argv, "Efrsly:Vvh")) != -1)
#endif
{
switch (c) {
@@ -313,6 +318,9 @@ main (int argc, char **argv)
case 'y':
sysroot = FcStrCopy ((const FcChar8 *)optarg);
break;
+ case 'l':
+ listDirs = FcTrue;
+ break;
case 'V':
fprintf (stderr, "fontconfig version %d.%d.%d\n",
FC_MAJOR, FC_MINOR, FC_REVISION);
@@ -374,6 +382,13 @@ main (int argc, char **argv)
else
list = FcConfigGetConfigDirs (config);
+ if (listDirs)
+ {
+ while ((dir = FcStrListNext (list)))
+ printf ("%s\n", dir);
+ goto done;
+ }
+
if ((processed_dirs = FcStrSetCreate()) == NULL) {
fprintf(stderr, "Cannot malloc\n");
return 1;
@@ -394,6 +409,7 @@ main (int argc, char **argv)
cleanCacheDirectories (config, verbose);
+done:
FcConfigDestroy (config);
FcFini ();
/*
diff --git a/fc-cache/fc-cache.sgml b/fc-cache/fc-cache.sgml
index 5ae0107..4430010 100644
--- a/fc-cache/fc-cache.sgml
+++ b/fc-cache/fc-cache.sgml
@@ -72,6 +72,7 @@ manpage.1: manpage.sgml
<arg><option>--sysroot</option> <option><replaceable>dir</replaceable></option></arg>
</group>
<arg><option>--system-only</option></arg>
+ <arg><option>--list-dirs</option></arg>
<arg><option>--verbose</option></arg>
<arg><option>--version</option></arg>
<arg><option>--help</option></arg>
@@ -144,6 +145,14 @@ manpage.1: manpage.sgml
</listitem>
</varlistentry>
<varlistentry>
+ <term><option>-l</option>
+ <option>--list-dirs</option>
+ </term>
+ <listitem>
+ <para>Only list directories, don't regenerate anything.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><option>-v</option>
<option>--verbose</option>
</term>
More information about the Reproducible-bugs
mailing list