CUPS Snap: Needs fontconfig for text filter, get "Fontconfig error: Cannot load default config file"

CUPS can print various file formats, by converting inpout files into PDF and this PDF into the printer’s native language, the conversion filters are provided by cups-filters. For plain text (ASCII, UTF-8) input files there is a texttopdf filter which generates a PDF file from plain text input. To do so it needs a standard, monospace font in case of latin letter text, some special fonts for greek, cyrillic, chinese, … The filter users fontconfig to find a suitable font in the system.

In the CUPS Snap this has to be performed inside a Snap, where one does not have access to all the systemś resources. So I decided to install the fonts into the CUPS Snap. With core18 this worked without problems, using this snapcraft.yaml.

Now I have switched to core20 and after some adjustments it is all working so far except the texttopdf filter which errors with

Fontconfig error: Cannot load default config file

in error_log when one tries to print a plain text file. The filter is called by cupsd when processing a plain text print job. I tried several things to fix this but did not succeed.

Here are the relevant parts of the new snapcraft.yaml:

name: cups
base: core20
[...]
environment:
  [...]
  FONTCONFIG_FILE: /snap/cups/current/etc/fonts/fonts.conf
  FONTCONFIG_PATH: /snap/cups/current/etc/fonts/conf.d
  FONTCONFIG_SYSROOT: /snap/cups/current/etc/fonts
[...]
apps:
  cupsd:
    command: scripts/run-cupsd
    [...]
    daemon: simple
    plugs: [network, network-bind, avahi-control, raw-usb, etc-cups]
[...]
parts:
  [...]
  cups-filters:
    [...]
    build-packages:
      [...]
      - libfontconfig1-dev
      [...]
    stage-packages:
      [...]
      - fonts-freefont-ttf
      - fonts-arphic-uming
      - fontconfig-config
    [...]
    override-prime: |
      set -eux
      perl -p -i \
           -e 's:<dir>\S*/usr/share/fonts</dir>:<dir>/snap/cups/current/usr/share/fonts</dir>:;' \
           -e 's:<cachedir>\S*/var/cache/fontconfig</cachedir>:<cachedir>/var/snap/cups/current/var/cache/fontconfig</cachedir>:;' \
           -e 's:<(cache|)dir>/usr/\S*</(cache|)dir>::;' \
           -e 's:<(cache|)dir>~\S*</(cache|)dir>::;' \
           $SNAPCRAFT_STAGE/etc/fonts/fonts.conf
      snapcraftctl prime
[...]

Especially I have put libfontconfig as build dependency and the fonts into the stage packages, so that they are installed in the Snap. I also have set the environment variables according to man fonts.conf and modified the $SNAP/etc/fonts/fonts.conf to pint to the font directories inside the Snap.

In addition, in run-cupsd, the script which fires up cupsd I have set the environment variables again:

export FONTCONFIG_FILE=$SNAP/etc/fonts/fonts.conf
export FONTCONFIG_PATH=$SNAP/etc/fonts/conf.d
export FONTCONFIG_SYSROOT=$SNAP/etc/fonts

What am I doing wrong?

I do not want to plug interfaces like “desktop” as I am not sure whether they pull in a lot of unneeded stuff (especially if the CUPS Snap is used on a headless server) or opens too many potential attack points.

Anyone has any experience?

Here is a font mapping file of texttopdf, /usr/share/cups/charsets/pdf.utf-8 in unsnapped CUPS, it is probably a format specific to texttopdf but it shows which fonts are used in which cases:

charset utf8

#
# This file defines the font mappings used for Unicode/UTF-8 text printing
# through PDF.
#
# Each line consists of:
#
#   first last direction width normal bold italic bold-italic
#
# First and last are the first and last glyphs in the font mapping
# that correspond to that font; contrary to PostScript printing
# they only select the font. To find the glyph the complete unicode
# character will be looked up in the (3,1) resp. (3,0) cmap of the 
# TrueType font. The glyph values are hexadecimal.
#
# Direction is the string "ltor" or "rtol", indicating left-to-right or
# right-to-left text.
#
# Width is the string "single" or "double"; double means that the glyphs
# are twice as wide as ASCII characters in the Courier typeface.
#
# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use
# for each presentation.  If characters are only available in a single
# style then only one typeface should be listed (e.g. "Symbol")
#
# Each font that is listed will be used (and downloaded if needed) when
# printing.
#

0000 04FF ltor single monospace monospace:bold monospace:oblique monospace:bold:oblique
0500 05FF rtol single monospace
3000 9FFF ltor double ARPLUmingCN

As @kenvandine asked me yesterday to switch over to core20, to get longer support life mainly, I tried the switch and only got stuck with this problem. I told him today and he gave me the hint of using layouts. And this made it actually working!!

So the relevant lines in snapcraft.yaml look like this now:

name: cups
base: core20
[...]
layout:
  /etc/fonts:
    bind: $SNAP/etc/fonts
  /usr/share/fonts:
    bind: $SNAP/usr/share/fonts
  /var/cache/fontconfig:
    bind: $SNAP_DATA/var/cache/fontconfig
[...]
parts:
  [...]
  cups-filters:
    [...]
    build-packages:
      [...]
      - libfontconfig1-dev
      [...]
    stage-packages:
      [...]
      - fonts-freefont-ttf
      - fonts-arphic-uming
      - fontconfig-config
[...]

I will commit this right now …

Thank you very much, @kenvandine !!