Open nh2 opened 6 months ago
I suspect the code involved is this:
static void
create_lock_filename( char *fn, const char *devname )
{
char *p;
strcpy( fn, STRINGIFY(PATH_SANE_LOCK_DIR)"/LCK.." );
/** Set a lock.
*
* The function tries to open/create exclusively a lock file in
* $PATH_SANE_LOCK_DIR.
* If the file could be created successfully, the function fills in the
* process ID.
* The complete filename of the lockfile is created as follows:
* $PATH_SANE_LOCK_DIR/LCK..<devicename>
* If the lock could not be set, the function tries it until the timeout
* period has been elapsed.
*
* @param devicename - unique part of the lockfile name
* @param timeout - time in seconds to try to set a lock
* @return
* - SANE_STATUS_GOOD - if the lock has been successfully set
* - SANE_STATUS_ACCESS_DENIED - the lock could not set
*/
extern SANE_Status sanei_access_lock( const char * devicename, SANE_Word timeout );
$ strings /nix/store/4wxksva2132pc1ddy4rk83mx2j8q9p82-sane-backends-1.2.1/lib/sane/libsane-plustek.so | grep /var/lock
/nix/store/4wxksva2132pc1ddy4rk83mx2j8q9p82-sane-backends-1.2.1/1/var/lock/LCK..
Looks like the packaging overrode the /var/lock/LCK..
string, putting the nix output store path prefix in front; that seems wrong.
Grepping further:
dnl Check for lock dir
AC_ARG_WITH(lockdir, AC_HELP_STRING([--with-lockdir=DIR],
[set SANE lockdir @<:@localstatedir/lock/sane@:>@]),
[locksanedir=$withval],[locksanedir=${localstatedir}/lock/sane])
AC_SUBST(locksanedir)
configdir="${sysconfdir}/sane.d"
AC_SUBST(configdir)
dnl ***********************************************************************
dnl enable/disable backends and features based on previous tests and user's
dnl choice
dnl ***********************************************************************
CPPFLAGS="${CPPFLAGS} -DPATH_SANE_CONFIG_DIR=\$(configdir) \
-DPATH_SANE_DATA_DIR=\$(datadir) \
-DPATH_SANE_LOCK_DIR=\$(locksanedir) \
-DV_MAJOR=${V_MAJOR} -DV_MINOR=${V_MINOR}"
Indeed, the build logs show the wrong Lockfiles
path:
% nix --extra-experimental-features nix-command log /nix/store/4wxksva2132pc1ddy4rk83mx2j8q9p82-sane-backends-1.2.1/ | grep -i lock
checking whether to enable device locking... yes
checking for struct flock in fcntl.h... yes
AM_CPPFLAGS=" -D_REENTRANT -DPATH_SANE_CONFIG_DIR=$(configdir) -DPATH_SANE_DATA_DIR=$(datadir) -DPATH_SANE_LOCK_DIR=$(locksanedir) -DV_MAJOR=1 -DV_MINOR=2"
Lockfiles: /nix/store/4wxksva2132pc1ddy4rk83mx2j8q9p82-sane-backends-1.2.1/var/lock
Probably the nix build sets localstatedir
to a store path.
Fixing it via:
configureFlags = [
"--localstatedir=/var" # `sane-backends` puts e.g. lock files in here, must not be in /nix/store
]
Other nixpkgs packages also set "--localstatedir=/var"
.
Maybe nixpkgs should do this automatically for all autoconf
packages?
https://www.gnu.org/prep/standards/html_node/Directory-Variables.html
localstatedir
The directory for installing data files which the programs modify while they run$(localstatedir)
should normally be/usr/local/var
, but write it as$(prefix)/var
.
Probably $(prefix)/var
is what puts the nix store path in.
However, trying the workaround fails the build at step:
/nix/store/q1c2flcykgr4wwg5a6h450hxbk4ch589-bash-5.2-p15/bin/bash /build/sane-backends-1.2.1/install-sh -d -m 775 /var/lock
mkdir: cannot create directory '/var': Permission denied
mkdir: cannot create directory '/var': Permission denied
In PR #273286 I made an option to set the sane-backends
package without mass rebuilds.
With that, the following workarounds make the scanner work:
hardware.sane.enable = true; # enables support for SANE scanners
hardware.sane.backends-package = pkgs.sane-backends.overrideAttrs (old: {
configureFlags = (old.configureFlags or []) ++ [
# "--localstatedir=/var" # `sane-backends` puts e.g. lock files in here, must not be in /nix/store
# "--with-lockdir=/var/lock/sane" # `sane-backends` puts e.g. lock files in here, must not be in /nix/store
# Ugly workaround for https://github.com/NixOS/nixpkgs/issues/273280#issuecomment-1848873028
# Really we should make `sane-backends` be able to provide a real lock dir (e.g. `/var/lock/sane`).
"--disable-locking"
];
# Alternative workaround for https://github.com/NixOS/nixpkgs/issues/273280#issuecomment-1848873028
# We'd prefer to just set in `configureFlags`
# "--localstatedir=/var" # `sane-backends` puts e.g. lock files in here, must not be in /nix/store
# but that does not work because the install step tries to create this directory,
# which fails in the nix build sandbox.
# So instead, we set the preprocessor variable directly, see:
# https://gitlab.com/sane-project/backends/-/blob/65779d6b595547d155a1954958bce5faaad45a5d/configure.ac#L635-652
# A problem is that this lock dir also needs to exist and have write permissions.
# Right now you have to do that manually with:
# sudo mkdir -p /var/lock/sane && sudo chown root:scanner /var/lock/sane && sudo chmod g+w /var/lock/sane
# Maybe we should use the `scanner` group for that, and/or configure it with systemd `tmpfiles`.
#NIX_CFLAGS_COMPILE = "-DPATH_SANE_LOCK_DIR=/var/lock/sane";
});
Now I can scan.
I'd be happy if somebody could pick up the task to pass a proper lock dir and ensure it exists in NixOS.
Another option is to disable locking entirely. Putting this in my nixos config is working for me:
{
nixpkgs.overlays = [
(final: prev: {
# Fixes a problem that attempt to access /nix/store/.../var/lock .
# Without this, the scanner is not detected.
sane-backends = prev.sane-backends.overrideAttrs
({ configureFlags ? [ ], ... }: {
configureFlags = configureFlags ++ [ "--disable-locking" ];
});
})
];
}
Another option is to disable locking entirely. Putting this in my nixos config is working for me:
Yes, that's what's mentioned in the comment just above: https://github.com/NixOS/nixpkgs/issues/273280#issuecomment-1848875571
It seems only scanners covered by SANE's plustek
driver are affected by this, as only those use locks as per grep
:
% grep -R /var/lock /nix/store/4wxksva2132pc1ddy4rk83mx2j8q9p82-sane-backends-1.2.1
grep: /nix/store/4wxksva2132pc1ddy4rk83mx2j8q9p82-sane-backends-1.2.1/lib/sane/libsane-plustek.so.1.2.1: binary file matches
grep: /nix/store/4wxksva2132pc1ddy4rk83mx2j8q9p82-sane-backends-1.2.1/lib/sane/libsane-plustek.so.1: binary file matches
grep: /nix/store/4wxksva2132pc1ddy4rk83mx2j8q9p82-sane-backends-1.2.1/lib/sane/libsane-plustek.so: binary file matches
http://www.sane-project.org/lists/sane-backends-cvs.html#S-PLUSTEK
Note this driver, even though called plustek
, handles also many other vendors' scanners, including some Canon, Epson, HP, and others.
Other nixpkgs packages also set "--localstatedir=/var".
Maybe nixpkgs should do this automatically for all autoconf packages? [...] However, trying the workaround fails the build at step:
/nix/store/q1c2flcykgr4wwg5a6h450hxbk4ch589-bash-5.2-p15/bin/bash /build/sane-backends-1.2.1/install-sh -d -m 775 /var/lock mkdir: cannot create directory '/var': Permission denied
I think that's the reason it isn't being done by default, because upstream build systems try to create directories inside the runtime state directory at install time.
So we're trading build time successes for runtime failures.
A similar situation exists with /etc (sysconfdir), where I think the default should be /etc, but nixpkgs uses $prefix/etc because it has a higher success rate at build time.
With the workaround mentioned in https://github.com/NixOS/nixpkgs/issues/273280#issuecomment-1848875571 I'm able to scan on a CanonScan Lide 25 using the sane-plustek backend. Would be great to have this properly fixed.
My Canon CanoScan LiDE 20 does not work on NixOS.
I wrote a minimal SANE config dir to reproduce:
Invocation:
Reveals:
Important part:
It's failing because it's trying to write a lock file into
/nix/store
.