From 81526ae67b2baafb5bb020abf19a1178c36b6083 Mon Sep 17 00:00:00 2001 From: castrojo Date: Wed, 16 Sep 2026 07:17:55 -0400 Subject: [PATCH 1/5] docs: plan packaged FSDK drivers Assisted-by: github-copilot/gpt-5.6-sol via pi --- .../2026-09-16-fsdk-packaged-cups-drivers.md | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/superpowers/plans/2026-09-16-fsdk-packaged-cups-drivers.md diff --git a/docs/superpowers/plans/2026-09-16-fsdk-packaged-cups-drivers.md b/docs/superpowers/plans/2026-09-16-fsdk-packaged-cups-drivers.md new file mode 100644 index 0000000..db70e77 --- /dev/null +++ b/docs/superpowers/plans/2026-09-16-fsdk-packaged-cups-drivers.md @@ -0,0 +1,36 @@ +# FSDK Packaged CUPS Drivers Implementation Plan + +**Goal:** Restore c2esp, Dymo, fxlinuxprint, Oki, pxljr, rastertosag-gdi, SpliX, brlaser, and P-Touch with discoverable driver data and executable conversion paths. + +**Architecture:** One pinned element per source package. Elements install filters under `/usr/lib/ghostscript-printer-app/filter` and either pyppd archives or `.drv` descriptions under `/usr/share/ppd`. FSDK remains the sole CUPS/libcupsfilters/libppd owner. Minimal IJS/JBIG helper artifacts are allowed only where FSDK exposes no usable artifact. Shared runtime composition and verification stay centralized. + +## Task 1: Build immutable driver artifacts + +- [ ] Add c2esp at `90a09ca4927fca5e1ae08307cd3ca9c0f0ca5b5b`, apply and execute the existing libcupsfilters2 patch. +- [ ] Add Dymo at `e69dceba792dc23d2894d57b0468009e52109625` and generate `dymo-ppds`. +- [ ] Add fxlinuxprint at `3e640d5cf2881b01b6dab16e7d899290e61b0417` and generate `fxlinuxprint-ppds`. +- [ ] Add Oki at `9f48d5a6c5938126a5aa91a902668aa877c3c22b`, replacing confinement paths with real OCI paths, and generate `oki-ppds`. +- [ ] Add pxljr at `6b0dafe66965e5fa398733c04160bd6436d13254`, including the minimal IJS dependency and 3500/3550/3600 PPD archive. +- [ ] Add rastertosag-gdi at `6f4028f36f015692a602077b7060438d0bf9f634` and generate its PPD archive. +- [ ] Add SpliX at `505f24d43fdb86eaa41a44486e7ef88226bb2c0c`, including the minimal JBIG dependency, QPDL filters, and PPD archive. +- [ ] Add brlaser at `23117fe9e0266396e4791cdae84d979928aed135` with its filter and `.drv` description. +- [ ] Add P-Touch at `ccfa92351be3ce601f212048b174147a5496d8be` and generate only its Foomatic PPD archive. + +## Task 2: Compose runtime and prove discovery + +- [ ] Add all driver artifacts to `core-stack.bst`; keep toolchains, source databases, and generators build-only. +- [ ] Add an image-level `verify-packaged-drivers` command that checks filters, helper executables/libraries, PPD archives/descriptions, and complete ELF/interpreter closure. +- [ ] Start the real appliance and require representative driver names from every family in the Printer Application driver list. + +## Task 3: Exercise conversion families + +- [ ] Run c2esp's FSDK libcupsfilters2 path and require printer-language output. +- [ ] Exercise representative raster filters for Dymo, pxljr, SpliX, brlaser, and P-Touch with valid deterministic raster/input fixtures. +- [ ] Exercise shell/script families for Oki, fxlinuxprint, and rastertosag-gdi with inherited runtime paths and TMPDIR. +- [ ] Require stable protocol signatures and repeatable output digests; a successful process with empty output fails. + +## Task 4: Verify and publish + +- [ ] Run `just validate`, prior slice gates, `just verify-packaged-drivers`, workflow lint, shell syntax checks, and `git diff --check`. +- [ ] Review the full diff from `feat/fsdk-raster-drivers`. +- [ ] Resolve issue 05, commit the completed plan, push `feat/fsdk-packaged-drivers`, and open a stacked PR based on `feat/fsdk-raster-drivers`. From 100424bd7bdad379979a1d5e337edb4af46c7ec0 Mon Sep 17 00:00:00 2001 From: castrojo Date: Wed, 16 Sep 2026 07:34:25 -0400 Subject: [PATCH 2/5] build: add packaged CUPS drivers Assisted-by: github-copilot/gpt-5.6-sol via pi --- elements/printer-app/brlaser.bst | 24 +++++++++++++ elements/printer-app/c2esp.bst | 36 +++++++++++++++++++ elements/printer-app/core-stack.bst | 9 +++++ elements/printer-app/dymo-cups-drivers.bst | 26 ++++++++++++++ elements/printer-app/fxlinuxprint.bst | 27 ++++++++++++++ elements/printer-app/ijs.bst | 20 +++++++++++ elements/printer-app/jbigkit.bst | 22 ++++++++++++ elements/printer-app/printer-driver-oki.bst | 37 +++++++++++++++++++ elements/printer-app/ptouch-driver.bst | 39 +++++++++++++++++++++ elements/printer-app/pxljr.bst | 38 ++++++++++++++++++++ elements/printer-app/rastertosag-gdi.bst | 19 ++++++++++ elements/printer-app/splix.bst | 31 ++++++++++++++++ 12 files changed, 328 insertions(+) create mode 100644 elements/printer-app/brlaser.bst create mode 100644 elements/printer-app/c2esp.bst create mode 100644 elements/printer-app/dymo-cups-drivers.bst create mode 100644 elements/printer-app/fxlinuxprint.bst create mode 100644 elements/printer-app/ijs.bst create mode 100644 elements/printer-app/jbigkit.bst create mode 100644 elements/printer-app/printer-driver-oki.bst create mode 100644 elements/printer-app/ptouch-driver.bst create mode 100644 elements/printer-app/pxljr.bst create mode 100644 elements/printer-app/rastertosag-gdi.bst create mode 100644 elements/printer-app/splix.bst diff --git a/elements/printer-app/brlaser.bst b/elements/printer-app/brlaser.bst new file mode 100644 index 0000000..d58d1ea --- /dev/null +++ b/elements/printer-app/brlaser.bst @@ -0,0 +1,24 @@ +kind: manual +description: Build the brlaser Brother laser raster filter. + +sources: + - kind: git_repo + url: github:pdewacht/brlaser.git + track: v6 + ref: v6-0-g23117fe9e0266396e4791cdae84d979928aed135 + +build-depends: + - freedesktop-sdk.bst:public-stacks/buildsystem-cmake.bst + - freedesktop-sdk.bst:public-stacks/buildsystem-make.bst + +depends: + - freedesktop-sdk.bst:components/cups.bst + - freedesktop-sdk.bst:components/cups-filters.bst + +config: + build-commands: + - cmake -S . -B build -DCMAKE_POLICY_VERSION_MINIMUM=3.5 + - cmake --build build --target rastertobrlaser -j2 + install-commands: + - install -D -m 0755 build/rastertobrlaser "%{install-root}/usr/lib/cups/filter/rastertobrlaser" + - install -D -m 0644 build/brlaser.drv "%{install-root}/usr/share/ppd/brlaser.drv" diff --git a/elements/printer-app/c2esp.bst b/elements/printer-app/c2esp.bst new file mode 100644 index 0000000..953a1da --- /dev/null +++ b/elements/printer-app/c2esp.bst @@ -0,0 +1,36 @@ +kind: manual +description: Build the c2esp Kodak raster filters and driver descriptions. + +sources: + - kind: git_repo + url: salsa:printing-team/c2esp.git + track: debian/27-11 + ref: debian/27-11-0-g90a09ca4927fca5e1ae08307cd3ca9c0f0ca5b5b + - kind: local + path: patches/c2esp-libcupsfilters2-api.patch + directory: patches + +build-depends: + - freedesktop-sdk.bst:public-stacks/buildsystem-autotools.bst + - freedesktop-sdk.bst:components/patch.bst + +depends: + - printer-app/jbigkit.bst + - freedesktop-sdk.bst:components/cups.bst + - freedesktop-sdk.bst:components/libcupsfilters.bst + - freedesktop-sdk.bst:components/libppd.bst + - freedesktop-sdk.bst:components/cups-filters.bst + +config: + build-commands: + - patch -p1 < patches/c2esp-libcupsfilters2-api.patch + - autoreconf --install + - ./configure --prefix=/usr + - make -j2 + install-commands: + - install -D -m 0755 src/c2esp "%{install-root}/usr/lib/cups/filter/c2esp" + - install -D -m 0755 src/c2espC "%{install-root}/usr/lib/cups/filter/c2espC" + - install -D -m 0755 src/command2esp "%{install-root}/usr/lib/cups/filter/command2esp" + - install -d "%{install-root}/usr/share/ppd" + - install -m 0644 src/*.drv "%{install-root}/usr/share/ppd/" + - sed -i 's:/usr/lib/cups/filter/::g' "%{install-root}"/usr/share/ppd/*.drv diff --git a/elements/printer-app/core-stack.bst b/elements/printer-app/core-stack.bst index 97b3b7a..d44236c 100644 --- a/elements/printer-app/core-stack.bst +++ b/elements/printer-app/core-stack.bst @@ -9,6 +9,15 @@ depends: - printer-app/cjet.bst - printer-app/min12xxw.bst - printer-app/pnm2ppa.bst + - printer-app/brlaser.bst + - printer-app/c2esp.bst + - printer-app/dymo-cups-drivers.bst + - printer-app/fxlinuxprint.bst + - printer-app/printer-driver-oki.bst + - printer-app/ptouch-driver.bst + - printer-app/pxljr.bst + - printer-app/rastertosag-gdi.bst + - printer-app/splix.bst - freedesktop-sdk.bst:public-stacks/runtime-gnu.bst - freedesktop-sdk.bst:components/avahi.bst - freedesktop-sdk.bst:components/ca-certificates.bst diff --git a/elements/printer-app/dymo-cups-drivers.bst b/elements/printer-app/dymo-cups-drivers.bst new file mode 100644 index 0000000..b69f5be --- /dev/null +++ b/elements/printer-app/dymo-cups-drivers.bst @@ -0,0 +1,26 @@ +kind: manual +description: Build the DYMO CUPS raster filters and PPD archive. + +sources: + - kind: git_repo + url: salsa:printing-team/dymo-cups-drivers.git + track: debian/1.4.0-12 + ref: debian/1.4.0-12-0-ge69dceba792dc23d2894d57b0468009e52109625 + +build-depends: + - printer-app/pyppd.bst + - freedesktop-sdk.bst:public-stacks/buildsystem-autotools.bst + +depends: + - freedesktop-sdk.bst:components/cups.bst + +config: + build-commands: + - autoreconf --install + - ./configure --prefix=/usr + - make -j2 + - pyppd -v -o dymo-ppds ppd + install-commands: + - install -D -m 0755 src/lw/raster2dymolw "%{install-root}/usr/lib/cups/filter/raster2dymolw" + - install -D -m 0755 src/lm/raster2dymolm "%{install-root}/usr/lib/cups/filter/raster2dymolm" + - install -D -m 0755 dymo-ppds "%{install-root}/usr/share/ppd/dymo-ppds" diff --git a/elements/printer-app/fxlinuxprint.bst b/elements/printer-app/fxlinuxprint.bst new file mode 100644 index 0000000..03c92dc --- /dev/null +++ b/elements/printer-app/fxlinuxprint.bst @@ -0,0 +1,27 @@ +kind: manual +description: Build the Fuji Xerox PDF printer CUPS filters and PPD archive. + +sources: + - kind: git_repo + url: salsa:printing-team/fxlinuxprint.git + track: debian/1.1.0+ds-4 + ref: debian/1.1.0+ds-4-0-g3e640d5cf2881b01b6dab16e7d899290e61b0417 + +build-depends: + - printer-app/pyppd.bst + - freedesktop-sdk.bst:public-stacks/buildsystem-autotools.bst + +depends: + - freedesktop-sdk.bst:components/cups.bst + +config: + build-commands: + - autoreconf --install + - ./configure --prefix=/usr + - make -j2 + - pyppd -v -o fxlinuxprint-ppds . + install-commands: + - install -D -m 0755 pstopdffx "%{install-root}/usr/lib/cups/filter/pstopdffx" + - install -D -m 0755 pdftopjlfx "%{install-root}/usr/lib/cups/filter/pdftopjlfx" + - install -D -m 0755 pdftopdffx "%{install-root}/usr/lib/cups/filter/pdftopdffx" + - install -D -m 0755 fxlinuxprint-ppds "%{install-root}/usr/share/ppd/fxlinuxprint-ppds" diff --git a/elements/printer-app/ijs.bst b/elements/printer-app/ijs.bst new file mode 100644 index 0000000..1783e59 --- /dev/null +++ b/elements/printer-app/ijs.bst @@ -0,0 +1,20 @@ +kind: manual +description: Build the standalone IJS library from the FSDK-pinned Ghostscript source. + +sources: + - kind: git_repo + url: github:ArtifexSoftware/ghostpdl.git + track: ghostpdl-10.07.1 + ref: ghostpdl-10.07.1-0-g9a39d68ca934f8e9343f46a2803e765122a3b4a9 + +build-depends: + - freedesktop-sdk.bst:public-stacks/buildsystem-autotools.bst + +config: + build-commands: + - cd ijs && autoreconf --force --install && ./configure --prefix=/usr --libdir="%{libdir}" --enable-shared --disable-static + - make -C ijs -j2 + install-commands: + - make -C ijs DESTDIR="$PWD/full-install" install + - mkdir -p "%{install-root}%{libdir}" && cp -a "full-install%{libdir}"/libijs*.so* "%{install-root}%{libdir}/" + - mkdir -p "%{install-root}/usr/include" && cp -a full-install/usr/include/ijs "%{install-root}/usr/include/" diff --git a/elements/printer-app/jbigkit.bst b/elements/printer-app/jbigkit.bst new file mode 100644 index 0000000..cdf8a05 --- /dev/null +++ b/elements/printer-app/jbigkit.bst @@ -0,0 +1,22 @@ +kind: manual +description: Build the minimal JBIG85 shared library required by SpliX. + +sources: + - kind: git_repo + url: https://www.cl.cam.ac.uk/~mgk25/git/jbigkit + track: v2.1 + ref: v2.1-0-g60bd8bd6579c12e5e3a24782bd49af2046a9738a + +build-depends: + - freedesktop-sdk.bst:public-stacks/buildsystem-make.bst + +config: + build-commands: + - cc $CFLAGS -fPIC -Ilibjbig -c libjbig/jbig85.c -o jbig85.o + - cc $CFLAGS -fPIC -Ilibjbig -c libjbig/jbig_ar.c -o jbig_ar.o + - cc $LDFLAGS -shared -Wl,-soname,libjbig85.so.0 -o libjbig85.so.0 jbig85.o jbig_ar.o + install-commands: + - install -D -m 0644 libjbig85.so.0 "%{install-root}%{libdir}/libjbig85.so.0" + - ln -s libjbig85.so.0 "%{install-root}%{libdir}/libjbig85.so" + - install -D -m 0644 libjbig/jbig85.h "%{install-root}/usr/include/jbig85.h" + - install -D -m 0644 libjbig/jbig_ar.h "%{install-root}/usr/include/jbig_ar.h" diff --git a/elements/printer-app/printer-driver-oki.bst b/elements/printer-app/printer-driver-oki.bst new file mode 100644 index 0000000..8f673a1 --- /dev/null +++ b/elements/printer-app/printer-driver-oki.bst @@ -0,0 +1,37 @@ +kind: manual +description: Package the OKI shell filters and PPD archive. + +sources: + - kind: git_repo + url: github:rbalint/printer-driver-oki.git + track: 1.0.2 + ref: 1.0.2-0-g9f48d5a6c5938126a5aa91a902668aa877c3c22b + +build-depends: + - printer-app/pyppd.bst + - freedesktop-sdk.bst:public-stacks/runtime-gnu.bst + - freedesktop-sdk.bst:components/sed.bst + +depends: + - freedesktop-sdk.bst:components/cups-filters.bst + - freedesktop-sdk.bst:components/ghostscript.bst + +config: + build-commands: + - | + sed -i \ + -e '/^[[:space:]]*PATH=/d' \ + -e '/^[[:space:]]*export PATH[[:space:]]*$/d' \ + -e '/^[[:space:]]*GSCRIPT_LIB=/d' \ + -e '/^[[:space:]]*export GSCRIPT_LIB[[:space:]]*$/d' \ + -e 's|${TMPDIR:-/tmp}|${TMPDIR}|g' \ + filters/* + - sed -i 's/^\(\*LanguageVersion:[[:space:]]*\).*/\1Portuguese/' MFP/OK4X1PSBR.ppd + - | + mkdir ppd + cp */*.ppd */*/*/*.ppd */*/*/*/*.ppd ppd/ + pyppd -v -o oki-ppds ppd + install-commands: + - install -d -m 0755 "%{install-root}/usr/lib/cups/filter" + - install -m 0755 filters/* "%{install-root}/usr/lib/cups/filter/" + - install -D -m 0755 oki-ppds "%{install-root}/usr/share/ppd/oki-ppds" diff --git a/elements/printer-app/ptouch-driver.bst b/elements/printer-app/ptouch-driver.bst new file mode 100644 index 0000000..23d0df6 --- /dev/null +++ b/elements/printer-app/ptouch-driver.bst @@ -0,0 +1,39 @@ +kind: manual +description: Build the P-Touch CUPS raster filter and Foomatic PPD archive. + +sources: + - kind: git_repo + url: salsa:printing-team/ptouch-driver.git + track: debian/1.7-1 + ref: debian/1.7-1-0-gccfa92351be3ce601f212048b174147a5496d8be + +build-depends: + - printer-app/foomatic-db-engine.bst + - printer-app/pyppd.bst + - printer-app/perl-clone.bst + - printer-app/perl-xml-libxml.bst + - freedesktop-sdk.bst:public-stacks/buildsystem-autotools.bst + - freedesktop-sdk.bst:components/cups-filters.bst + - freedesktop-sdk.bst:components/foomatic-db.bst + - freedesktop-sdk.bst:components/gzip.bst + - freedesktop-sdk.bst:components/perl.bst + - freedesktop-sdk.bst:components/perl-xml-parser.bst + +depends: + - freedesktop-sdk.bst:components/cups.bst + +config: + build-commands: + - autoreconf --install + - ./configure --prefix=/usr + - make -j"%{max-jobs}" rastertoptch generated/stamp-h1 + - | + cp -a /usr/share/foomatic "$PWD/foomatic-db" + cp -a generated/. foomatic-db/db/source/ + printf '#\n' > foomatic-db/db/oldprinterids + FOOMATICDB="$PWD/foomatic-db" \ + foomatic-compiledb -j "%{max-jobs}" -t ppd -d ppd ptouch-pt ptouch-ql + pyppd -v -o ptouch-ppds ppd + install-commands: + - install -D -m 0755 rastertoptch "%{install-root}/usr/lib/cups/filter/rastertoptch" + - install -D -m 0755 ptouch-ppds "%{install-root}/usr/share/ppd/ptouch-ppds" diff --git a/elements/printer-app/pxljr.bst b/elements/printer-app/pxljr.bst new file mode 100644 index 0000000..31dd3b4 --- /dev/null +++ b/elements/printer-app/pxljr.bst @@ -0,0 +1,38 @@ +kind: manual +description: Build the pxljr HP Color LaserJet IJS driver and PPD archive. + +sources: + - kind: git_repo + url: salsa:printing-team/pxljr.git + track: debian/1.4+repack0-6 + ref: debian/1.4+repack0-6-0-g6b0dafe66965e5fa398733c04160bd6436d13254 + +build-depends: + - printer-app/pyppd.bst + - freedesktop-sdk.bst:public-stacks/buildsystem-autotools.bst + - freedesktop-sdk.bst:components/perl.bst + +depends: + - freedesktop-sdk.bst:components/cups.bst + - printer-app/ijs.bst + - freedesktop-sdk.bst:components/jpeg.bst + +config: + build-commands: + - autoreconf --force --install + - ./configure --prefix=/usr + - make -j2 + - | + mkdir ppd + cp HP-Color_LaserJet_3550-pxljr.ppd ppd/ + cd ppd + for model in 3500 3600; do + perl -p -e "s:3550(?!\"):${model}:g" HP-Color_LaserJet_3550-pxljr.ppd > "HP-Color_LaserJet_${model}-pxljr.ppd" + done + perl -p -i -e 's,^\*cupsFilter:\s*"application/vnd.cups-postscript\s+0\s+foomatic-rip",*cupsFilter: "application/vnd.cups-postscript 100 foomatic-rip"\n*cupsFilter: "application/vnd.cups-pdf 0 foomatic-rip",' *.ppd + perl -p -i -e 's,(\-sDEVICE=ijs),-dNOINTERPOLATE \1,' *.ppd + cd .. + pyppd -v -o pxljr-ppds ppd + install-commands: + - install -D -m 0755 ijs_pxljr "%{install-root}/usr/bin/ijs_pxljr" + - install -D -m 0755 pxljr-ppds "%{install-root}/usr/share/ppd/pxljr-ppds" diff --git a/elements/printer-app/rastertosag-gdi.bst b/elements/printer-app/rastertosag-gdi.bst new file mode 100644 index 0000000..c5365b6 --- /dev/null +++ b/elements/printer-app/rastertosag-gdi.bst @@ -0,0 +1,19 @@ +kind: manual +description: Package the rastertosag-gdi Ricoh raster filter and PPDs. + +sources: + - kind: git_repo + url: salsa:printing-team/rastertosag-gdi.git + track: debian/0.1-8 + ref: debian/0.1-8-0-g6f4028f36f015692a602077b7060438d0bf9f634 + +build-depends: + - printer-app/pyppd.bst + - freedesktop-sdk.bst:public-stacks/runtime-gnu.bst + +config: + build-commands: + - pyppd -v -o rastertosag-gdi-ppds ppd + install-commands: + - install -D -m 0755 rastertosag-gdi "%{install-root}/usr/lib/cups/filter/rastertosag-gdi" + - install -D -m 0755 rastertosag-gdi-ppds "%{install-root}/usr/share/ppd/rastertosag-gdi-ppds" diff --git a/elements/printer-app/splix.bst b/elements/printer-app/splix.bst new file mode 100644 index 0000000..4c2309d --- /dev/null +++ b/elements/printer-app/splix.bst @@ -0,0 +1,31 @@ +kind: manual +description: Build the SpliX QPDL printer filters and PPD archive. + +sources: + - kind: git_repo + url: salsa:printing-team/splix.git + track: debian/2.0.1-1 + ref: debian/2.0.1-1-0-g505f24d43fdb86eaa41a44486e7ef88226bb2c0c + +build-depends: + - printer-app/jbigkit.bst + - printer-app/pyppd.bst + - freedesktop-sdk.bst:public-stacks/buildsystem-make.bst + +depends: + - freedesktop-sdk.bst:components/cups.bst + +config: + build-commands: + - >- + make -j2 V=1 + CUPSFILTER="/usr/lib/cups/filter" + rastertoqpdl_LIBS="-lcupsimage -lcups -lpthread -ljbig85" + pstoqpdl_LIBS="-lcupsimage -lcups -lpthread" + - cp *.ppd ppd/ + - pyppd -v -o splix-ppds ppd + install-commands: + - install -D -m 0755 optimized/pstoqpdl "%{install-root}/usr/lib/cups/filter/pstoqpdl" + - install -D -m 0755 optimized/rastertoqpdl "%{install-root}/usr/lib/cups/filter/rastertoqpdl" + - install -D -m 0644 "%{libdir}/libjbig85.so.0" "%{install-root}%{libdir}/libjbig85.so.0" + - install -D -m 0755 splix-ppds "%{install-root}/usr/share/ppd/splix-ppds" From c213040a399f2d88cba356828aef4a9547aa5036 Mon Sep 17 00:00:00 2001 From: castrojo Date: Wed, 16 Sep 2026 07:39:43 -0400 Subject: [PATCH 3/5] docs(skills): record canonical CUPS filter path Assisted-by: github-copilot/gpt-5.6-sol via pi --- docs/skills/fsdk-cups-patching.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/skills/fsdk-cups-patching.md b/docs/skills/fsdk-cups-patching.md index 2a93473..714fab7 100644 --- a/docs/skills/fsdk-cups-patching.md +++ b/docs/skills/fsdk-cups-patching.md @@ -33,6 +33,7 @@ metadata: 9. Match FSDK's multiarch install layout for every repository-built library. Define `gcc-triplet`, `lib`, and `libdir` in the root project and pass `--libdir=%{libdir}` to Autotools; FSDK's `pkg-config` searches `/usr/lib//pkgconfig`, not `/usr/lib/pkgconfig`. 10. Do not `chown` high numeric runtime IDs inside the BuildStream sandbox; user-namespace mappings can reject them with `EINVAL`. After composition, reapply writable directory modes in the final OCI layer. Remove inherited `/run` service directories and let the numeric runtime user recreate them so ownership checks observe the actual user. 11. Avahi's `--no-drop-root` still resolves its compiled `AVAHI_USER`/`AVAHI_GROUP` and requires its runtime directory to have those numeric IDs. Configure FSDK's Avahi build with `--with-avahi-user=nonroot --with-avahi-group=nonroot`; never create a second passwd/group name with UID/GID `65532`. Remove D-Bus's `` directive so it does not attempt a second privilege drop, and patch Avahi policy at `/etc/dbus-1/system.d/avahi-dbus.conf`. +12. Install repository-built CUPS filters into `/usr/lib/cups/filter`. The appliance exposes `/usr/lib/ghostscript-printer-app` as a symlink to `/usr/lib/cups`; creating a real `/usr/lib/ghostscript-printer-app/filter` directory in another artifact conflicts with that symlink during composition. ## Common Rationalizations @@ -57,6 +58,7 @@ metadata: - Pre-creating Avahi's runtime directory as root; Avahi verifies it belongs to its compiled service UID even with `--no-drop-root`. - Giving `avahi` and `nonroot` the same UID/GID; numeric-to-name lookup becomes ambiguous and can hide a broken OCI identity. - Editing `/usr/share/dbus-1/system.d/avahi-dbus.conf`; the FSDK runtime installs that policy under `/etc/dbus-1/system.d/`. +- Installing a driver artifact beneath `/usr/lib/ghostscript-printer-app/filter`; the canonical artifact path is `/usr/lib/cups/filter`, reached at runtime through the application symlink. ## Verification From 5e410dd4466bf8ccab349633c85f0fc8c6bc6f26 Mon Sep 17 00:00:00 2001 From: castrojo Date: Wed, 16 Sep 2026 09:39:57 -0400 Subject: [PATCH 4/5] fix: complete packaged driver runtime Assisted-by: github-copilot/gpt-5.6-sol via pi --- Justfile | 3 + docs/skills/fsdk-cups-patching.md | 9 +- .../2026-09-16-fsdk-packaged-cups-drivers.md | 38 +-- elements/freedesktop-sdk.bst | 3 + elements/printer-app/c2esp.bst | 1 + elements/printer-app/dymo-cups-drivers.bst | 1 + elements/printer-app/fxlinuxprint.bst | 4 + elements/printer-app/ijs.bst | 8 + elements/printer-app/jbigkit.bst | 8 + elements/printer-app/printer-driver-oki.bst | 7 +- elements/printer-app/ptouch-driver.bst | 3 + elements/printer-app/pxljr.bst | 3 + elements/printer-app/rastertosag-gdi.bst | 3 + elements/printer-app/splix.bst | 5 +- files/container-entrypoint.sh | 3 +- ghostscript-printer-app.c | 3 - .../foomatic-rip-option-use-after-free.patch | 27 ++ ...stomize-cups-for-printer-application.patch | 21 ++ tests/packaged-drivers.sh | 309 ++++++++++++++++++ 19 files changed, 431 insertions(+), 28 deletions(-) create mode 100644 patches/cups-filters/foomatic-rip-option-use-after-free.patch create mode 100755 tests/packaged-drivers.sh diff --git a/Justfile b/Justfile index 0af750b..36cd830 100644 --- a/Justfile +++ b/Justfile @@ -70,5 +70,8 @@ verify-payload: verify-raster-drivers: tests/standalone-raster-drivers.sh +verify-packaged-drivers: + tests/packaged-drivers.sh + verify-cups-patch-chain: tests/cups-patch-chain.sh diff --git a/docs/skills/fsdk-cups-patching.md b/docs/skills/fsdk-cups-patching.md index 714fab7..b608c07 100644 --- a/docs/skills/fsdk-cups-patching.md +++ b/docs/skills/fsdk-cups-patching.md @@ -1,6 +1,6 @@ --- name: fsdk-cups-patching -description: Use when changing the freedesktop-sdk junction, CUPS build configuration, CUPS backends, or CUPS source patches for the OCI appliance. +description: Use when changing the freedesktop-sdk junction, CUPS or cups-filters build configuration, Ghostscript compression ownership, CUPS backends, filters, or print-stack source patches for the OCI appliance. metadata: context7-sources: - /apache/buildstream @@ -13,6 +13,7 @@ metadata: - Changing the pinned freedesktop-sdk junction. - Changing CUPS TLS configuration, backends, filters, or source patches. - Diagnosing CUPS graph or source-staging failures in the OCI build. +- Changing FSDK-owned cups-filters or Ghostscript behavior required by a legacy driver. ## When NOT to Use @@ -34,6 +35,9 @@ metadata: 10. Do not `chown` high numeric runtime IDs inside the BuildStream sandbox; user-namespace mappings can reject them with `EINVAL`. After composition, reapply writable directory modes in the final OCI layer. Remove inherited `/run` service directories and let the numeric runtime user recreate them so ownership checks observe the actual user. 11. Avahi's `--no-drop-root` still resolves its compiled `AVAHI_USER`/`AVAHI_GROUP` and requires its runtime directory to have those numeric IDs. Configure FSDK's Avahi build with `--with-avahi-user=nonroot --with-avahi-group=nonroot`; never create a second passwd/group name with UID/GID `65532`. Remove D-Bus's `` directive so it does not attempt a second privilege drop, and patch Avahi policy at `/etc/dbus-1/system.d/avahi-dbus.conf`. 12. Install repository-built CUPS filters into `/usr/lib/cups/filter`. The appliance exposes `/usr/lib/ghostscript-printer-app` as a symlink to `/usr/lib/cups`; creating a real `/usr/lib/ghostscript-printer-app/filter` directory in another artifact conflicts with that symlink during composition. +13. Stage component-specific source patches in separate junction directories. `patches/cups-filters/` is injected into FSDK's existing `components/cups-filters.bst`; never mix it with CUPS or libcupsfilters patches. +14. Keep Ghostscript on its bundled zlib. FSDK's zlib-ng compatibility library corrupts compiled Ghostscript ROMFS reads when a full-size IJS page lazily loads an ICC profile; the failure appears as `free(): invalid size` from `s_block_read_process`. A default Letter pxljr conversion is the regression probe. +15. Treat filter executables by format: use `ldd` only for ELF binaries, and resolve script shebangs plus every invoked command separately. Generated pyppd archives use `#!/usr/bin/env python3`, so each owning element declares the Python runtime even when another aggregate currently supplies it. ## Common Rationalizations @@ -59,6 +63,9 @@ metadata: - Giving `avahi` and `nonroot` the same UID/GID; numeric-to-name lookup becomes ambiguous and can hide a broken OCI identity. - Editing `/usr/share/dbus-1/system.d/avahi-dbus.conf`; the FSDK runtime installs that policy under `/etc/dbus-1/system.d/`. - Installing a driver artifact beneath `/usr/lib/ghostscript-printer-app/filter`; the canonical artifact path is `/usr/lib/cups/filter`, reached at runtime through the application symlink. +- Running `ldd` on shell or Python filters; `not a dynamic executable` is not an ELF closure result. +- Letting aggregate composition mask an undeclared pyppd Python runtime or shell-filter command dependency. +- Building Ghostscript against FSDK's zlib-ng compatibility library when the appliance ships an IJS driver. ## Verification diff --git a/docs/superpowers/plans/2026-09-16-fsdk-packaged-cups-drivers.md b/docs/superpowers/plans/2026-09-16-fsdk-packaged-cups-drivers.md index db70e77..dbf6a1c 100644 --- a/docs/superpowers/plans/2026-09-16-fsdk-packaged-cups-drivers.md +++ b/docs/superpowers/plans/2026-09-16-fsdk-packaged-cups-drivers.md @@ -2,35 +2,35 @@ **Goal:** Restore c2esp, Dymo, fxlinuxprint, Oki, pxljr, rastertosag-gdi, SpliX, brlaser, and P-Touch with discoverable driver data and executable conversion paths. -**Architecture:** One pinned element per source package. Elements install filters under `/usr/lib/ghostscript-printer-app/filter` and either pyppd archives or `.drv` descriptions under `/usr/share/ppd`. FSDK remains the sole CUPS/libcupsfilters/libppd owner. Minimal IJS/JBIG helper artifacts are allowed only where FSDK exposes no usable artifact. Shared runtime composition and verification stay centralized. +**Architecture:** One pinned element per source package. Elements install filters under `/usr/lib/cups/filter` and either pyppd archives or `.drv` descriptions under `/usr/share/ppd`. FSDK remains the sole CUPS/libcupsfilters/libppd owner. Minimal IJS/JBIG helper artifacts are allowed only where FSDK exposes no usable artifact. Shared runtime composition and verification stay centralized. ## Task 1: Build immutable driver artifacts -- [ ] Add c2esp at `90a09ca4927fca5e1ae08307cd3ca9c0f0ca5b5b`, apply and execute the existing libcupsfilters2 patch. -- [ ] Add Dymo at `e69dceba792dc23d2894d57b0468009e52109625` and generate `dymo-ppds`. -- [ ] Add fxlinuxprint at `3e640d5cf2881b01b6dab16e7d899290e61b0417` and generate `fxlinuxprint-ppds`. -- [ ] Add Oki at `9f48d5a6c5938126a5aa91a902668aa877c3c22b`, replacing confinement paths with real OCI paths, and generate `oki-ppds`. -- [ ] Add pxljr at `6b0dafe66965e5fa398733c04160bd6436d13254`, including the minimal IJS dependency and 3500/3550/3600 PPD archive. -- [ ] Add rastertosag-gdi at `6f4028f36f015692a602077b7060438d0bf9f634` and generate its PPD archive. -- [ ] Add SpliX at `505f24d43fdb86eaa41a44486e7ef88226bb2c0c`, including the minimal JBIG dependency, QPDL filters, and PPD archive. -- [ ] Add brlaser at `23117fe9e0266396e4791cdae84d979928aed135` with its filter and `.drv` description. -- [ ] Add P-Touch at `ccfa92351be3ce601f212048b174147a5496d8be` and generate only its Foomatic PPD archive. +- [x] Add c2esp at `90a09ca4927fca5e1ae08307cd3ca9c0f0ca5b5b`, apply and execute the existing libcupsfilters2 patch. +- [x] Add Dymo at `e69dceba792dc23d2894d57b0468009e52109625` and generate `dymo-ppds`. +- [x] Add fxlinuxprint at `3e640d5cf2881b01b6dab16e7d899290e61b0417` and generate `fxlinuxprint-ppds`. +- [x] Add Oki at `9f48d5a6c5938126a5aa91a902668aa877c3c22b`, replacing confinement paths with real OCI paths, and generate `oki-ppds`. +- [x] Add pxljr at `6b0dafe66965e5fa398733c04160bd6436d13254`, including the minimal IJS dependency and 3500/3550/3600 PPD archive. +- [x] Add rastertosag-gdi at `6f4028f36f015692a602077b7060438d0bf9f634` and generate its PPD archive. +- [x] Add SpliX at `505f24d43fdb86eaa41a44486e7ef88226bb2c0c`, including the minimal JBIG dependency, QPDL filters, and PPD archive. +- [x] Add brlaser at `23117fe9e0266396e4791cdae84d979928aed135` with its filter and `.drv` description. +- [x] Add P-Touch at `ccfa92351be3ce601f212048b174147a5496d8be` and generate only its Foomatic PPD archive. ## Task 2: Compose runtime and prove discovery -- [ ] Add all driver artifacts to `core-stack.bst`; keep toolchains, source databases, and generators build-only. -- [ ] Add an image-level `verify-packaged-drivers` command that checks filters, helper executables/libraries, PPD archives/descriptions, and complete ELF/interpreter closure. -- [ ] Start the real appliance and require representative driver names from every family in the Printer Application driver list. +- [x] Add all driver artifacts to `core-stack.bst`; keep toolchains, source databases, and generators build-only. +- [x] Add an image-level `verify-packaged-drivers` command that checks filters, helper executables/libraries, PPD archives/descriptions, and complete ELF/interpreter closure. +- [x] Start the real appliance and require representative driver names from every family in the Printer Application driver list. ## Task 3: Exercise conversion families -- [ ] Run c2esp's FSDK libcupsfilters2 path and require printer-language output. -- [ ] Exercise representative raster filters for Dymo, pxljr, SpliX, brlaser, and P-Touch with valid deterministic raster/input fixtures. -- [ ] Exercise shell/script families for Oki, fxlinuxprint, and rastertosag-gdi with inherited runtime paths and TMPDIR. -- [ ] Require stable protocol signatures and repeatable output digests; a successful process with empty output fails. +- [x] Run c2esp's FSDK libcupsfilters2 path and require printer-language output. +- [x] Exercise representative raster filters for Dymo, pxljr, SpliX, brlaser, and P-Touch with valid deterministic raster/input fixtures. +- [x] Exercise shell/script families for Oki, fxlinuxprint, and rastertosag-gdi with inherited runtime paths and TMPDIR. +- [x] Require stable protocol signatures and repeatable output digests; a successful process with empty output fails. ## Task 4: Verify and publish -- [ ] Run `just validate`, prior slice gates, `just verify-packaged-drivers`, workflow lint, shell syntax checks, and `git diff --check`. -- [ ] Review the full diff from `feat/fsdk-raster-drivers`. +- [x] Run `just validate`, prior slice gates, `just verify-packaged-drivers`, workflow lint, shell syntax checks, and `git diff --check`. +- [x] Review the full diff from `feat/fsdk-raster-drivers`. - [ ] Resolve issue 05, commit the completed plan, push `feat/fsdk-packaged-drivers`, and open a stacked PR based on `feat/fsdk-raster-drivers`. diff --git a/elements/freedesktop-sdk.bst b/elements/freedesktop-sdk.bst index 930295e..106f4e4 100644 --- a/elements/freedesktop-sdk.bst +++ b/elements/freedesktop-sdk.bst @@ -11,6 +11,9 @@ sources: - kind: local path: patches/libcupsfilters directory: patches/ghostscript-printer-app/libcupsfilters + - kind: local + path: patches/cups-filters + directory: patches/ghostscript-printer-app/cups-filters - kind: patch_queue path: patches/freedesktop-sdk diff --git a/elements/printer-app/c2esp.bst b/elements/printer-app/c2esp.bst index 953a1da..13c58a9 100644 --- a/elements/printer-app/c2esp.bst +++ b/elements/printer-app/c2esp.bst @@ -20,6 +20,7 @@ depends: - freedesktop-sdk.bst:components/libcupsfilters.bst - freedesktop-sdk.bst:components/libppd.bst - freedesktop-sdk.bst:components/cups-filters.bst + - freedesktop-sdk.bst:components/zlib.bst config: build-commands: diff --git a/elements/printer-app/dymo-cups-drivers.bst b/elements/printer-app/dymo-cups-drivers.bst index b69f5be..a387cb4 100644 --- a/elements/printer-app/dymo-cups-drivers.bst +++ b/elements/printer-app/dymo-cups-drivers.bst @@ -13,6 +13,7 @@ build-depends: depends: - freedesktop-sdk.bst:components/cups.bst + - freedesktop-sdk.bst:components/python3.bst config: build-commands: diff --git a/elements/printer-app/fxlinuxprint.bst b/elements/printer-app/fxlinuxprint.bst index 03c92dc..c7166ba 100644 --- a/elements/printer-app/fxlinuxprint.bst +++ b/elements/printer-app/fxlinuxprint.bst @@ -13,6 +13,8 @@ build-depends: depends: - freedesktop-sdk.bst:components/cups.bst + - freedesktop-sdk.bst:components/python3.bst + - freedesktop-sdk.bst:components/ghostscript.bst config: build-commands: @@ -25,3 +27,5 @@ config: - install -D -m 0755 pdftopjlfx "%{install-root}/usr/lib/cups/filter/pdftopjlfx" - install -D -m 0755 pdftopdffx "%{install-root}/usr/lib/cups/filter/pdftopdffx" - install -D -m 0755 fxlinuxprint-ppds "%{install-root}/usr/share/ppd/fxlinuxprint-ppds" + - install -D -m 0644 mimefx.types "%{install-root}/usr/share/cups/mime/mimefx.types" + - install -D -m 0644 mimefx.convs "%{install-root}/usr/share/cups/mime/mimefx.convs" diff --git a/elements/printer-app/ijs.bst b/elements/printer-app/ijs.bst index 1783e59..a06c28c 100644 --- a/elements/printer-app/ijs.bst +++ b/elements/printer-app/ijs.bst @@ -10,6 +10,14 @@ sources: build-depends: - freedesktop-sdk.bst:public-stacks/buildsystem-autotools.bst +public: + bst: + split-rules: + devel: + - "%{includedir}" + - "%{includedir}/**" + - "%{libdir}/libijs.so" + config: build-commands: - cd ijs && autoreconf --force --install && ./configure --prefix=/usr --libdir="%{libdir}" --enable-shared --disable-static diff --git a/elements/printer-app/jbigkit.bst b/elements/printer-app/jbigkit.bst index cdf8a05..690edd4 100644 --- a/elements/printer-app/jbigkit.bst +++ b/elements/printer-app/jbigkit.bst @@ -10,6 +10,14 @@ sources: build-depends: - freedesktop-sdk.bst:public-stacks/buildsystem-make.bst +public: + bst: + split-rules: + devel: + - "%{includedir}/jbig85.h" + - "%{includedir}/jbig_ar.h" + - "%{libdir}/libjbig85.so" + config: build-commands: - cc $CFLAGS -fPIC -Ilibjbig -c libjbig/jbig85.c -o jbig85.o diff --git a/elements/printer-app/printer-driver-oki.bst b/elements/printer-app/printer-driver-oki.bst index 8f673a1..c50b865 100644 --- a/elements/printer-app/printer-driver-oki.bst +++ b/elements/printer-app/printer-driver-oki.bst @@ -9,12 +9,15 @@ sources: build-depends: - printer-app/pyppd.bst - - freedesktop-sdk.bst:public-stacks/runtime-gnu.bst - - freedesktop-sdk.bst:components/sed.bst depends: - freedesktop-sdk.bst:components/cups-filters.bst + - freedesktop-sdk.bst:components/cups-daemon-only.bst + - freedesktop-sdk.bst:components/grep.bst + - freedesktop-sdk.bst:components/sed.bst - freedesktop-sdk.bst:components/ghostscript.bst + - freedesktop-sdk.bst:components/python3.bst + - freedesktop-sdk.bst:public-stacks/runtime-gnu.bst config: build-commands: diff --git a/elements/printer-app/ptouch-driver.bst b/elements/printer-app/ptouch-driver.bst index 23d0df6..8ae70c2 100644 --- a/elements/printer-app/ptouch-driver.bst +++ b/elements/printer-app/ptouch-driver.bst @@ -21,6 +21,9 @@ build-depends: depends: - freedesktop-sdk.bst:components/cups.bst + - freedesktop-sdk.bst:components/python3.bst + - freedesktop-sdk.bst:components/cups-filters.bst + - freedesktop-sdk.bst:components/ghostscript.bst config: build-commands: diff --git a/elements/printer-app/pxljr.bst b/elements/printer-app/pxljr.bst index 31dd3b4..971973d 100644 --- a/elements/printer-app/pxljr.bst +++ b/elements/printer-app/pxljr.bst @@ -16,6 +16,9 @@ depends: - freedesktop-sdk.bst:components/cups.bst - printer-app/ijs.bst - freedesktop-sdk.bst:components/jpeg.bst + - freedesktop-sdk.bst:components/python3.bst + - freedesktop-sdk.bst:components/cups-filters.bst + - freedesktop-sdk.bst:components/ghostscript.bst config: build-commands: diff --git a/elements/printer-app/rastertosag-gdi.bst b/elements/printer-app/rastertosag-gdi.bst index c5365b6..7591ec3 100644 --- a/elements/printer-app/rastertosag-gdi.bst +++ b/elements/printer-app/rastertosag-gdi.bst @@ -11,6 +11,9 @@ build-depends: - printer-app/pyppd.bst - freedesktop-sdk.bst:public-stacks/runtime-gnu.bst +depends: + - freedesktop-sdk.bst:components/python3.bst + config: build-commands: - pyppd -v -o rastertosag-gdi-ppds ppd diff --git a/elements/printer-app/splix.bst b/elements/printer-app/splix.bst index 4c2309d..2114761 100644 --- a/elements/printer-app/splix.bst +++ b/elements/printer-app/splix.bst @@ -8,12 +8,14 @@ sources: ref: debian/2.0.1-1-0-g505f24d43fdb86eaa41a44486e7ef88226bb2c0c build-depends: - - printer-app/jbigkit.bst - printer-app/pyppd.bst - freedesktop-sdk.bst:public-stacks/buildsystem-make.bst depends: - freedesktop-sdk.bst:components/cups.bst + - freedesktop-sdk.bst:components/python3.bst + - printer-app/jbigkit.bst + - freedesktop-sdk.bst:components/cups-filters.bst config: build-commands: @@ -27,5 +29,4 @@ config: install-commands: - install -D -m 0755 optimized/pstoqpdl "%{install-root}/usr/lib/cups/filter/pstoqpdl" - install -D -m 0755 optimized/rastertoqpdl "%{install-root}/usr/lib/cups/filter/rastertoqpdl" - - install -D -m 0644 "%{libdir}/libjbig85.so.0" "%{install-root}%{libdir}/libjbig85.so.0" - install -D -m 0755 splix-ppds "%{install-root}/usr/share/ppd/splix-ppds" diff --git a/files/container-entrypoint.sh b/files/container-entrypoint.sh index e527beb..fd1a6a0 100755 --- a/files/container-entrypoint.sh +++ b/files/container-entrypoint.sh @@ -19,8 +19,9 @@ export BACKEND_DIR=/usr/lib/ghostscript-printer-app/backend export CUPS_SERVERBIN=/usr/lib/ghostscript-printer-app export CUPS_SERVERROOT="$state_dir/cups" export FILTER_DIR=/usr/lib/ghostscript-printer-app/filter +export PATH="$FILTER_DIR:$PATH" export PPDC_DATADIR=/usr/share/ppdc -export PPD_PATHS="/usr/share/ppd/:$state_dir/ppd/" +export PPD_PATHS="${PPD_PATHS:-/usr/share/ppd/:$state_dir/ppd/}" export SPOOL_DIR="$state_dir/spool" export STATE_DIR="$state_dir" export STATE_FILE="$state_dir/ghostscript-printer-app.state" diff --git a/ghostscript-printer-app.c b/ghostscript-printer-app.c index 08fd41e..f0d4341 100644 --- a/ghostscript-printer-app.c +++ b/ghostscript-printer-app.c @@ -215,9 +215,6 @@ main(int argc, // I - Number of command-line arguments SYSTEM_WEB_IF_FOOTER, // Footer for web interface (in HTML) PR_COPTIONS_QUERY_PS_DEFAULTS | // pappl-retrofit special features to be PR_COPTIONS_NO_GENERIC_DRIVER | // used -#if !SNAP - PR_COPTIONS_USE_ONLY_MATCHING_NICKNAMES | -#endif // !SNAP PR_COPTIONS_NO_PAPPL_BACKENDS | PR_COPTIONS_CUPS_BACKENDS, ghostscript_autoadd, // Auto-add (driver assignment) callback diff --git a/patches/cups-filters/foomatic-rip-option-use-after-free.patch b/patches/cups-filters/foomatic-rip-option-use-after-free.patch new file mode 100644 index 0000000..9b1df90 --- /dev/null +++ b/patches/cups-filters/foomatic-rip-option-use-after-free.patch @@ -0,0 +1,27 @@ +--- a/filter/foomatic-rip/options.c ++++ b/filter/foomatic-rip/options.c +@@ -1205,6 +1205,10 @@ option_set_value(option_t *opt, + if (!newvalue) + return (0); + ++ choice = NULL; ++ if (option_is_composite(opt)) ++ choice = option_find_choice(opt, newvalue); ++ + free(val->value); + val->value = NULL; + +@@ -1221,10 +1225,9 @@ option_set_value(option_t *opt, + else + val->value = newvalue; + +- if (option_is_composite(opt)) ++ if (choice) + { + // set dependent values +- choice = option_find_choice(opt, value); +- if (choice && !isempty(choice->command)) ++ if (!isempty(choice->command)) + composite_set_values(opt, optionset, choice->command); + } + return (1); diff --git a/patches/freedesktop-sdk/0001-customize-cups-for-printer-application.patch b/patches/freedesktop-sdk/0001-customize-cups-for-printer-application.patch index 38b4857..f03510b 100644 --- a/patches/freedesktop-sdk/0001-customize-cups-for-printer-application.patch +++ b/patches/freedesktop-sdk/0001-customize-cups-for-printer-application.patch @@ -61,3 +61,24 @@ diff --git a/elements/components/libcupsfilters.bst b/elements/components/libcup ref: 2.2.1-0-g2a00cf6aa4234e2e0ac91b9844ab8990d04c7089 +- kind: patch_queue + path: patches/ghostscript-printer-app/libcupsfilters +diff --git a/elements/components/cups-filters.bst b/elements/components/cups-filters.bst +--- a/elements/components/cups-filters.bst ++++ b/elements/components/cups-filters.bst +@@ -24,3 +24,5 @@ sources: + ref: 2.0.1-0-g5a73330fbd0cde494d984141f9add1565aef8171 + - kind: patch_queue + path: patches/cups-filters ++- kind: patch_queue ++ path: patches/ghostscript-printer-app/cups-filters +diff --git a/elements/components/ghostscript.bst b/elements/components/ghostscript.bst +--- a/elements/components/ghostscript.bst ++++ b/elements/components/ghostscript.bst +@@ -21,7 +21,7 @@ + variables: + conf-local: >- + --with-drivers=ALL + --with-system-libtiff=yes +- --with-local-zlib=no ++ --with-local-zlib=yes + + config: diff --git a/tests/packaged-drivers.sh b/tests/packaged-drivers.sh new file mode 100755 index 0000000..8832f69 --- /dev/null +++ b/tests/packaged-drivers.sh @@ -0,0 +1,309 @@ +#!/usr/bin/env bash +set -euo pipefail + +image="ghcr.io/projectbluefin/ghostscript-printer-app:build" +name="ghostscript-printer-app-packaged-drivers" +port="${PORT:-18030}" +state_dir="$(mktemp -d)" + +cleanup() { + podman rm -f "$name" >/dev/null 2>&1 || true + podman unshare rm -rf "$state_dir" +} +trap cleanup EXIT + +just build + +for element in \ + dymo-cups-drivers \ + fxlinuxprint \ + printer-driver-oki \ + ptouch-driver \ + pxljr \ + rastertosag-gdi \ + splix; do + runtime_graph="$(just bst show --deps run --format '%{name}' "printer-app/$element.bst")" + [[ "$runtime_graph" == *"freedesktop-sdk.bst:components/python3.bst"* ]] +done +oki_runtime_graph="$(just bst show --deps run --format '%{name}' printer-app/printer-driver-oki.bst)" +[[ "$oki_runtime_graph" == *"freedesktop-sdk.bst:components/grep.bst"* ]] +[[ "$oki_runtime_graph" == *"freedesktop-sdk.bst:components/sed.bst"* ]] +for element in fxlinuxprint ptouch-driver pxljr; do + runtime_graph="$(just bst show --deps run --format '%{name}' "printer-app/$element.bst")" + [[ "$runtime_graph" == *"freedesktop-sdk.bst:components/ghostscript.bst"* ]] +done +for element in ptouch-driver pxljr; do + runtime_graph="$(just bst show --deps run --format '%{name}' "printer-app/$element.bst")" + [[ "$runtime_graph" == *"freedesktop-sdk.bst:components/cups-filters.bst"* ]] +done +[[ "$oki_runtime_graph" == *"freedesktop-sdk.bst:public-stacks/runtime-gnu.bst"* ]] +[[ "$oki_runtime_graph" == *"freedesktop-sdk.bst:components/cups-filters.bst"* ]] +[[ "$oki_runtime_graph" == *"freedesktop-sdk.bst:components/cups-daemon-only.bst"* ]] +c2esp_runtime_graph="$(just bst show --deps run --format '%{name}' printer-app/c2esp.bst)" +[[ "$c2esp_runtime_graph" == *"freedesktop-sdk.bst:components/zlib.bst"* ]] +splix_runtime_graph="$(just bst show --deps run --format '%{name}' printer-app/splix.bst)" +[[ "$splix_runtime_graph" == *"printer-app/jbigkit.bst"* ]] +[[ "$splix_runtime_graph" == *"freedesktop-sdk.bst:components/cups-filters.bst"* ]] + +chmod 0777 "$state_dir" +podman run --rm --entrypoint /usr/bin/bash \ + -v "$state_dir:/state:Z" "$image" -c ' + set -euo pipefail + + filter_dir=/usr/lib/cups/filter + ppd_dir=/usr/share/ppd + work=/tmp/packaged-drivers + export PATH="$filter_dir:/usr/bin:/bin" + export TMPDIR=/tmp + mkdir -p "$work" /state/ppd + + printf "%s\n" \ + "%!PS-Adobe-3.0" \ + "%%Pages: 1" \ + "%%Page: 1 1" \ + "newpath 10 10 moveto 60 60 lineto stroke" \ + "showpage" \ + "%%EOF" > "$work/page.ps" + + assert_prefix() { + local file="$1" bytes="$2" expected="$3" + test -s "$file" + [[ "$(od -An -tx1 -N "$bytes" "$file")" == "$expected" ]] + } + + assert_suffix() { + local file="$1" bytes="$2" expected="$3" size + size="$(stat -c %s "$file")" + ((size >= bytes)) + [[ "$(od -An -tx1 -j "$((size - bytes))" -N "$bytes" "$file")" == "$expected" ]] + } + + assert_repeatable() { + local first_hash second_hash + read -r first_hash _ < <(sha256sum "$1") + read -r second_hash _ < <(sha256sum "$2") + [[ "$first_hash" == "$second_hash" ]] + } + + assert_archive() { + local archive="$ppd_dir/$1" marker="$2" entries + test -x "$archive" + entries="$("$archive" list)" + [[ "$entries" == *"$marker"* ]] + cp "$archive" /state/ppd/ + } + + extract_ppd() { + "$ppd_dir/$1" cat "$2" > "$3" + test -s "$3" + } + + make_raster() { + local ppd="$1" resolution="$2" geometry="$3" output="$4" + shift 4 + PPD="$ppd" gs -q -dSAFER -dNOPAUSE -dBATCH -sDEVICE=cups \ + -r"$resolution" -g"$geometry" "$@" \ + -sOutputFile="$output" "$work/page.ps" 2>"$output.log" + test -s "$output" + } + + run_filter() { + local filter="$1" ppd="$2" options="$3" input="$4" stem="$5" suffix + for suffix in first second; do + if ! PPD="$ppd" DEVICE_URI=file:/dev/null \ + "$filter" 1 test test 1 "$options" "$input" \ + 3/dev/null \ + >"$work/$stem-$suffix.prn" 2>"$work/$stem-$suffix.log"; then + cat "$work/$stem-$suffix.log" >&2 + return 1 + fi + done + assert_repeatable "$work/$stem-first.prn" "$work/$stem-second.prn" + } + + filters=(c2esp c2espC command2esp raster2dymolm raster2dymolw pstopdffx pdftopjlfx pdftopdffx okijobaccounting rastertookidotmatrix rastertookimonochrome rastertoptch rastertosag-gdi pstoqpdl rastertoqpdl rastertobrlaser) + for filter in "${filters[@]}"; do + test -x "$filter_dir/$filter" + done + + binaries=(c2esp c2espC command2esp raster2dymolm raster2dymolw pstopdffx pdftopjlfx pdftopdffx rastertoptch pstoqpdl rastertoqpdl rastertobrlaser /usr/bin/ijs_pxljr) + for binary in "${binaries[@]}"; do + [[ "$binary" == /* ]] || binary="$filter_dir/$binary" + dependencies="$(ldd "$binary")" + [[ "$dependencies" != *"not found"* ]] + done + + test -x /bin/sh + test -x /bin/grep + test -x /bin/sed + test -x /usr/bin/python3 + test -x "$filter_dir/rastertohp" + for devel_path in \ + /usr/include/ijs \ + /usr/include/jbig85.h \ + /usr/include/jbig_ar.h \ + /usr/lib/*-linux-gnu/libijs.so \ + /usr/lib/*-linux-gnu/libjbig85.so; do + test ! -e "$devel_path" + done + read -r shebang < "$filter_dir/okijobaccounting" + [[ "$shebang" == "#!/bin/sh" ]] + for script in rastertookidotmatrix rastertookimonochrome; do + read -r shebang < "$filter_dir/$script" + [[ "$shebang" == "#!/bin/sh" ]] + done + read -r shebang < "$filter_dir/rastertosag-gdi" + [[ "$shebang" == "#!/usr/bin/python3 -u" ]] + for archive in dymo-ppds fxlinuxprint-ppds oki-ppds ptouch-ppds pxljr-ppds rastertosag-gdi-ppds splix-ppds; do + read -r shebang < "$ppd_dir/$archive" + [[ "$shebang" == "#!/usr/bin/env python3" ]] + done + + assert_archive dymo-ppds "DYMO LabelMANAGER 400" + assert_archive fxlinuxprint-ppds "Fuji Xerox PDF Printer" + assert_archive oki-ppds "OKI B2200" + assert_archive ptouch-ppds "Brother PT-1500PC" + assert_archive pxljr-ppds "HP Color LaserJet 3500" + assert_archive rastertosag-gdi-ppds "Ricoh Aficio SP 1000S" + assert_archive splix-ppds "Dell 1100" + test -f "$ppd_dir/brlaser.drv" + test -f "$ppd_dir/KodakESP_16.drv" + test -f "$ppd_dir/KodakESP_C_07.drv" + test -f /usr/share/cups/mime/mimefx.types + test -f /usr/share/cups/mime/mimefx.convs + + mkdir "$work/c2esp" "$work/brlaser" + ppdc -d "$work/c2esp" "$ppd_dir/KodakESP_16.drv" + ppdc -d "$work/brlaser" "$ppd_dir/brlaser.drv" + cp "$work/c2esp"/*.ppd "$work/brlaser"/*.ppd /state/ppd/ + + c2esp_ppd="$work/c2esp/Kodak_ESP_3.ppd" + make_raster "$c2esp_ppd" 300x1200 300x1200 "$work/c2esp.ras" + run_filter "$filter_dir/c2esp" "$c2esp_ppd" "" "$work/c2esp.ras" c2esp + assert_prefix "$work/c2esp-first.prn" 16 " 4c 6f 63 6b 50 72 69 6e 74 65 72 57 61 69 74 3f" + printf "OK: c2esp conversion\n" + + extract_ppd dymo-ppds dymo-ppds:0/lm400.ppd "$work/dymo-lm.ppd" + make_raster "$work/dymo-lm.ppd" 180 170x630 "$work/dymo-lm.ras" + run_filter "$filter_dir/raster2dymolm" "$work/dymo-lm.ppd" "PageSize=w68h252.2" "$work/dymo-lm.ras" dymo-lm + assert_prefix "$work/dymo-lm-first.prn" 16 " 00 00 00 00 00 00 00 00 00 00 00 00 1b 43 00 1b" + + extract_ppd dymo-ppds dymo-ppds:0/lw400.ppd "$work/dymo-lw.ppd" + make_raster "$work/dymo-lw.ppd" 300 300x300 "$work/dymo-lw.ras" + run_filter "$filter_dir/raster2dymolw" "$work/dymo-lw.ppd" "PageSize=w72h72" "$work/dymo-lw.ras" dymo-lw + assert_prefix "$work/dymo-lw-first.prn" 16 " 1b 1b 1b 1b 1b 1b 1b 1b 1b 1b 1b 1b 1b 1b 1b 1b" + printf "OK: Dymo LabelManager and LabelWriter conversions\n" + + extract_ppd fxlinuxprint-ppds fxlinuxprint-ppds:0/fxlinuxprint.ppd "$work/fx.ppd" + if ! PPD="$work/fx.ppd" TMPDIR=/tmp \ + "$filter_dir/pstopdffx" 1 test test 1 "" "$work/page.ps" \ + >"$work/fx-postscript.prn" 2>"$work/fx-postscript.log"; then + cat "$work/fx-postscript.log" >&2 + exit 1 + fi + assert_prefix "$work/fx-postscript.prn" 16 " 1b 25 2d 31 32 33 34 35 58 40 50 4a 4c 0a 40 50" + gs -q -dSAFER -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \ + -sOutputFile="$work/fx.pdf" "$work/page.ps" + run_filter "$filter_dir/pdftopjlfx" "$work/fx.ppd" "" "$work/fx.pdf" fx + assert_prefix "$work/fx-first.prn" 16 " 1b 25 2d 31 32 33 34 35 58 40 50 4a 4c 0a 40 50" + printf "OK: fxlinuxprint conversion\n" + + extract_ppd oki-ppds oki-ppds:0/B2200PCL.ppd "$work/oki.ppd" + make_raster "$work/oki.ppd" 600 600x600 "$work/oki.ras" + for suffix in first second; do + if ! PPD="$work/oki.ppd" TMPDIR=/tmp \ + "$filter_dir/rastertookimonochrome" 1 test test 1 "" \ + < "$work/oki.ras" \ + > "$work/oki-$suffix.prn" 2> "$work/oki-$suffix.log"; then + cat "$work/oki-$suffix.log" >&2 + exit 1 + fi + done + assert_repeatable "$work/oki-first.prn" "$work/oki-second.prn" + assert_prefix "$work/oki-first.prn" 16 " 1b 25 2d 31 32 33 34 35 58 40 50 4a 4c 20 43 4f" + (("$(stat -c %s "$work/oki-first.prn")" > 1000)) + printf "%s\n" "@PJL ENTER LANGUAGE = POSTSCRIPT" "showpage" > "$work/oki.ps" + for suffix in first second; do + TMPDIR=/tmp "$filter_dir/okijobaccounting" 1 test test 1 "" \ + < "$work/oki.ps" > "$work/oki-accounting-$suffix.prn" + done + assert_repeatable "$work/oki-accounting-first.prn" "$work/oki-accounting-second.prn" + accounting="$(cat "$work/oki-accounting-first.prn")" + [[ "$accounting" == *"@PJL OKIJOBACCOUNTJOB"* ]] + printf "OK: Oki raster and accounting conversions\n" + + extract_ppd ptouch-ppds ptouch-ppds:0/Brother-PT-1500PC-ptouch-pt.ppd "$work/ptouch.ppd" + run_filter "$filter_dir/foomatic-rip" "$work/ptouch.ppd" "" "$work/page.ps" ptouch + assert_suffix "$work/ptouch-first.prn" 2 " 5a 1a" + printf "OK: P-Touch conversion\n" + + extract_ppd pxljr-ppds pxljr-ppds:0/HP-Color_LaserJet_3500-pxljr.ppd "$work/pxljr.ppd" + run_filter "$filter_dir/foomatic-rip" "$work/pxljr.ppd" "" "$work/page.ps" pxljr + assert_prefix "$work/pxljr-first.prn" 16 " 1b 25 2d 31 32 33 34 35 58 40 50 4a 4c 20 53 45" + printf "OK: pxljr default conversion\n" + + extract_ppd rastertosag-gdi-ppds rastertosag-gdi-ppds:0/rsp1000s.ppd "$work/sag.ppd" + make_raster "$work/sag.ppd" 600 600x600 "$work/sag.ras" + run_filter "$filter_dir/rastertosag-gdi" "$work/sag.ppd" "" "$work/sag.ras" sag + assert_prefix "$work/sag-first.prn" 9 " 29 20 53 41 47 2d 47 44 49" + printf "OK: rastertosag-gdi conversion\n" + + extract_ppd splix-ppds splix-ppds:0/1100.ppd "$work/splix.ppd" + make_raster "$work/splix.ppd" 600 600x600 "$work/splix.ras" \ + -dcupsCompression=17 -dcupsColorSpace=3 -dcupsColorOrder=0 + run_filter "$filter_dir/rastertoqpdl" "$work/splix.ppd" "ColorModel=Gray Resolution=600dpi" "$work/splix.ras" splix + assert_prefix "$work/splix-first.prn" 16 " 1b 25 2d 31 32 33 34 35 58 40 50 4a 4c 20 44 45" + run_filter "$filter_dir/pstoqpdl" "$work/splix.ppd" "ColorModel=Gray Resolution=600dpi" "$work/page.ps" splix-ps + assert_prefix "$work/splix-ps-first.prn" 16 " 1b 25 2d 31 32 33 34 35 58 40 50 4a 4c 20 44 45" + printf "OK: SpliX conversion\n" + + brlaser_ppd= + for candidate in "$work/brlaser"/*.ppd; do + brlaser_ppd="$candidate" + break + done + test -n "$brlaser_ppd" + make_raster "$brlaser_ppd" 600 600x600 "$work/brlaser.ras" + run_filter "$filter_dir/rastertobrlaser" "$brlaser_ppd" "" "$work/brlaser.ras" brlaser + assert_suffix "$work/brlaser-first.prn" 10 " 1b 25 2d 31 32 33 34 35 58 0a" + printf "OK: brlaser conversion\n" +' + +podman run -d --name "$name" --network host -e PORT="$port" \ + -e PPD_PATHS=/var/lib/ghostscript-printer-app/ppd \ + -v "$state_dir:/var/lib/ghostscript-printer-app:Z" "$image" >/dev/null +for _ in $(seq 1 60); do + curl --fail --silent "http://127.0.0.1:${port}/" >/dev/null 2>&1 && break + sleep 1 +done +drivers="$(podman exec "$name" ghostscript-printer-app -u "ipp://127.0.0.1:${port}/ipp/system" drivers)" +for marker in \ + "Kodak ESP 3" \ + "DYMO LabelMANAGER 400" \ + "Fuji Xerox PDF Printer" \ + "OKI B2200" \ + "Brother 1500PC" \ + "HP Color LaserJet 3500" \ + "Ricoh Aficio SP 1000S" \ + "Dell 1100" \ + "brlaser"; do + if [[ "$drivers" != *"$marker"* ]]; then + printf 'Missing live driver: %s\n' "$marker" >&2 + exit 1 + fi +done + +podman stop --time 15 "$name" >/dev/null +podman rm "$name" >/dev/null +podman run -d --name "$name" --network host -e PORT="$port" \ + -e PPD_PATHS=/usr/share/ppd/ \ + -v "$state_dir:/var/lib/ghostscript-printer-app:Z" "$image" >/dev/null +for _ in $(seq 1 60); do + curl --fail --silent "http://127.0.0.1:${port}/" >/dev/null 2>&1 && break + sleep 1 +done +installed_drivers="$(podman exec "$name" ghostscript-printer-app -u "ipp://127.0.0.1:${port}/ipp/system" drivers)" +[[ "$installed_drivers" == *"kodak--esp-3-aio--en"* ]] +[[ "$installed_drivers" == *"brlaser"* ]] + +printf 'OK: packaged drivers convert, resolve dependencies, and appear in the live catalog\n' From a099976dee497d1eb5b068f10fb484a1a1e37cad Mon Sep 17 00:00:00 2001 From: castrojo Date: Wed, 16 Sep 2026 09:43:22 -0400 Subject: [PATCH 5/5] docs: complete packaged driver plan Assisted-by: github-copilot/gpt-5.6-sol via pi --- docs/superpowers/plans/2026-09-16-fsdk-packaged-cups-drivers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/superpowers/plans/2026-09-16-fsdk-packaged-cups-drivers.md b/docs/superpowers/plans/2026-09-16-fsdk-packaged-cups-drivers.md index dbf6a1c..6c6fe80 100644 --- a/docs/superpowers/plans/2026-09-16-fsdk-packaged-cups-drivers.md +++ b/docs/superpowers/plans/2026-09-16-fsdk-packaged-cups-drivers.md @@ -33,4 +33,4 @@ - [x] Run `just validate`, prior slice gates, `just verify-packaged-drivers`, workflow lint, shell syntax checks, and `git diff --check`. - [x] Review the full diff from `feat/fsdk-raster-drivers`. -- [ ] Resolve issue 05, commit the completed plan, push `feat/fsdk-packaged-drivers`, and open a stacked PR based on `feat/fsdk-raster-drivers`. +- [x] Resolve issue 05, commit the completed plan, push `feat/fsdk-packaged-drivers`, and open a stacked PR based on `feat/fsdk-raster-drivers`.