[sane-devel] Passing all scanner usage through local saned
Guillaume Girol
symphorien_sane at xlumurb.eu
Thu May 9 16:39:12 BST 2024
Hello,
I'm a downstream maintainer of SANE on NixOS, a linux distribution. I
consider modifying NixOS to make it so all application using libsane
would actually only use saned, and never load the backends to directly
access scanners themselves. I send this message to the mailing list to
know if I missed reasons it could be a bad idea.
Rationale
=========
NixOS is quite different from typical linux distributions in that there
is no globally installed library. /usr/lib does not exist and without
special packaging care, dlopen() never finds anything. Each library is
installed in a unique prefix /nix/store/unique-id/lib/foo.so so several
versions of the same library can coexist. Exeecutable find the
libraries they depend on via explicit RPATH. As a result I can have an
old version of python in /nix/store/some-id/bin/python using an old
version of glibc in /nix/store/other-id/lib/libc.so via RPATH and the
rest of the system using a newer version of glibc in /nix/store/yet-
another-id/lib/libc.so also via RPATH.
This does not work for SANE as it uses dlopen() to find backends
depending on a single, global configuration file. For now we have an
exception to the "no lib installed globally" design for SANE. However
this is not perfect: if I use an old version of, say, simple-scan, it
may dlopen() more recent version of some SANE backend, which depends on
a more recent glibc than the version that old simple-scan brings with
its RPATH. Thus dlopen() fails. In practice this means that software
installed from the past or the future often fails to scan, whereas this
usually works quite well for other functionnality.
Solution considered
===================
To solve this, I want applications using SANE to stop using dlopen() to
access the scanner, but to use a network protocol instead. This is a
bit like glibc can talk to nscd over a socket instead of dlopening nss
modules.
The solution I'm considering consists in linking all normal
applications to a stripped-down variant of libsane which only has the
network backend and is configured to connect to a saned instance on
localhost (instead of obeying what you would find in /etc/sane.d on
typical distros). Each application comes with its own copy of this
libsane, it's not global anymore. (Don't mind the disk space cost, all
of NixOS works this way, this is part of the tradeoff). When the user
configures their system for scanner support, a global instance of saned
is setup which is linked against a full-fledged copy of libsane obeying
the full configuration files you would typically find in /etc/sane.d.
When an old application attempts to scan, it uses its own, old version
of libsane to talk to a recent saned which dlopen()s sane backends of
matching version, so all works fine.
Possible issues?
================
Any issues with this design I missed? In my light testing, it appears
to work quite fine. The problems I found:
- all users can use the scanners instead of just users in the lp or
scanner group previously. I suppose this can be solved with a firewall
(firewalls can filter the uid of local sockets).
- network scanners are not available. I propose a fix in
https://gitlab.com/sane-project/backends/-/merge_requests/834
- is the network protocol that saned uses stable across versions? In my
testing, it is, but maybe it's by sheer luck.
- maybe stuff I have not considered.
Cheers,
Guillaume Girol
More information about the sane-devel
mailing list