1 { config, lib, pkgs, ... }:
4 pkg = config.hardware.sane.backends-package.override {
5 scanSnapDriversUnfree = config.hardware.sane.drivers.scanSnap.enable;
6 scanSnapDriversPackage = config.hardware.sane.drivers.scanSnap.package;
9 sanedConf = pkgs.writeTextFile {
11 destination = "/etc/sane.d/saned.conf";
14 ${config.services.saned.extraConfig}
18 netConf = pkgs.writeTextFile {
20 destination = "/etc/sane.d/net.conf";
22 ${lib.optionalString config.services.saned.enable "localhost"}
23 ${config.hardware.sane.netConf}
28 SANE_CONFIG_DIR = "/etc/sane-config";
29 LD_LIBRARY_PATH = [ "/etc/sane-libs" ];
32 backends = [ pkg netConf ] ++ lib.optional config.services.saned.enable sanedConf ++ config.hardware.sane.extraBackends;
33 saneConfig = pkgs.mkSaneConfig { paths = backends; inherit (config.hardware.sane) disabledDefaultBackends; };
35 enabled = config.hardware.sane.enable || config.services.saned.enable;
45 hardware.sane.enable = lib.mkOption {
46 type = lib.types.bool;
49 Enable support for SANE scanners.
52 Users in the "scanner" group will gain access to the scanner, or the "lp" group if it's also a printer.
57 hardware.sane.backends-package = lib.mkOption {
58 type = lib.types.package;
59 default = pkgs.sane-backends;
60 defaultText = lib.literalExpression "pkgs.sane-backends";
61 description = "Backends driver package to use.";
64 hardware.sane.snapshot = lib.mkOption {
65 type = lib.types.bool;
67 description = "Use a development snapshot of SANE scanner drivers.";
70 hardware.sane.extraBackends = lib.mkOption {
71 type = lib.types.listOf lib.types.path;
74 Packages providing extra SANE backends to enable.
77 The example contains the package for HP scanners, and the package for
78 Apple AirScan and Microsoft WSD support (supports many
82 example = lib.literalExpression "[ pkgs.hplipWithPlugin pkgs.sane-airscan ]";
85 hardware.sane.disabledDefaultBackends = lib.mkOption {
86 type = lib.types.listOf lib.types.str;
90 Names of backends which are enabled by default but should be disabled.
91 See `$SANE_CONFIG_DIR/dll.conf` for the list of possible names.
95 hardware.sane.configDir = lib.mkOption {
98 description = "The value of SANE_CONFIG_DIR.";
101 hardware.sane.netConf = lib.mkOption {
102 type = lib.types.lines;
104 example = "192.168.0.16";
106 Network hosts that should be probed for remote scanners.
110 hardware.sane.drivers.scanSnap.enable = lib.mkOption {
111 type = lib.types.bool;
115 Whether to enable drivers for the Fujitsu ScanSnap scanners.
117 The driver files are unfree and extracted from the Windows driver image.
121 hardware.sane.drivers.scanSnap.package = lib.mkPackageOption pkgs [ "sane-drivers" "epjitsu" ] {
122 extraDescription = ''
123 Useful if you want to extract the driver files yourself.
125 The process is described in the {file}`/etc/sane.d/epjitsu.conf` file in
126 the `sane-backends` package.
130 hardware.sane.openFirewall = lib.mkOption {
131 type = lib.types.bool;
134 Open ports needed for discovery of scanners on the local network, e.g.
135 needed for Canon scanners (BJNP protocol).
139 services.saned.enable = lib.mkOption {
140 type = lib.types.bool;
143 Enable saned network daemon for remote connection to scanners.
145 saned would be run from `scanner` user; to allow
146 access to hardware that doesn't have `scanner` group
147 you should add needed groups to this user.
151 services.saned.extraConfig = lib.mkOption {
152 type = lib.types.lines;
154 example = "192.168.0.0/24";
156 Extra saned configuration lines.
163 ###### implementation
165 config = lib.mkMerge [
167 hardware.sane.configDir = lib.mkDefault "${saneConfig}/etc/sane.d";
169 environment.systemPackages = backends;
170 environment.sessionVariables = env;
171 environment.etc."sane-config".source = config.hardware.sane.configDir;
172 environment.etc."sane-libs".source = "${saneConfig}/lib/sane";
173 services.udev.packages = backends;
175 users.groups.scanner.gid = config.ids.gids.scanner;
176 networking.firewall.allowedUDPPorts = lib.mkIf config.hardware.sane.openFirewall [ 8612 ];
178 systemd.tmpfiles.rules = [
179 "d /var/lock/sane 0770 root scanner - -"
183 (lib.mkIf config.services.saned.enable {
184 networking.firewall.connectionTrackingModules = [ "sane" ];
186 systemd.services."saned@" = {
187 description = "Scanner Service";
188 environment = lib.mapAttrs (name: val: toString val) env;
192 ExecStart = "${pkg}/bin/saned";
196 systemd.sockets.saned = {
197 description = "saned incoming socket";
198 wantedBy = [ "sockets.target" ];
199 listenStreams = [ "0.0.0.0:6566" "[::]:6566" ];
201 # saned needs to distinguish between IPv4 and IPv6 to open matching data sockets.
202 BindIPv6Only = "ipv6-only";
208 users.users.scanner = {
209 uid = config.ids.uids.scanner;
211 extraGroups = [ "lp" ] ++ lib.optionals config.services.avahi.enable [ "avahi" ];