1 { config, lib, pkgs, ... }:
7 pkg = pkgs.sane-backends.override {
8 scanSnapDriversUnfree = config.hardware.sane.drivers.scanSnap.enable;
9 scanSnapDriversPackage = config.hardware.sane.drivers.scanSnap.package;
12 sanedConf = pkgs.writeTextFile {
14 destination = "/etc/sane.d/saned.conf";
17 ${config.services.saned.extraConfig}
21 netConf = pkgs.writeTextFile {
23 destination = "/etc/sane.d/net.conf";
25 ${lib.optionalString config.services.saned.enable "localhost"}
26 ${config.hardware.sane.netConf}
31 SANE_CONFIG_DIR = "/etc/sane-config";
32 LD_LIBRARY_PATH = [ "/etc/sane-libs" ];
35 backends = [ pkg netConf ] ++ optional config.services.saned.enable sanedConf ++ config.hardware.sane.extraBackends;
36 saneConfig = pkgs.mkSaneConfig { paths = backends; inherit (config.hardware.sane) disabledDefaultBackends; };
38 enabled = config.hardware.sane.enable || config.services.saned.enable;
48 hardware.sane.enable = mkOption {
51 description = lib.mdDoc ''
52 Enable support for SANE scanners.
55 Users in the "scanner" group will gain access to the scanner, or the "lp" group if it's also a printer.
60 hardware.sane.snapshot = mkOption {
63 description = lib.mdDoc "Use a development snapshot of SANE scanner drivers.";
66 hardware.sane.extraBackends = mkOption {
67 type = types.listOf types.path;
69 description = lib.mdDoc ''
70 Packages providing extra SANE backends to enable.
73 The example contains the package for HP scanners, and the package for
74 Apple AirScan and Microsoft WSD support (supports many
78 example = literalExpression "[ pkgs.hplipWithPlugin pkgs.sane-airscan ]";
81 hardware.sane.disabledDefaultBackends = mkOption {
82 type = types.listOf types.str;
85 description = lib.mdDoc ''
86 Names of backends which are enabled by default but should be disabled.
87 See `$SANE_CONFIG_DIR/dll.conf` for the list of possible names.
91 hardware.sane.configDir = mkOption {
94 description = lib.mdDoc "The value of SANE_CONFIG_DIR.";
97 hardware.sane.netConf = mkOption {
100 example = "192.168.0.16";
101 description = lib.mdDoc ''
102 Network hosts that should be probed for remote scanners.
106 hardware.sane.drivers.scanSnap.enable = mkOption {
110 description = lib.mdDoc ''
111 Whether to enable drivers for the Fujitsu ScanSnap scanners.
113 The driver files are unfree and extracted from the Windows driver image.
117 hardware.sane.drivers.scanSnap.package = mkOption {
118 type = types.package;
119 default = pkgs.sane-drivers.epjitsu;
120 defaultText = literalExpression "pkgs.sane-drivers.epjitsu";
121 description = lib.mdDoc ''
122 Epjitsu driver package to use. Useful if you want to extract the driver files yourself.
124 The process is described in the `/etc/sane.d/epjitsu.conf` file in
125 the `sane-backends` package.
129 hardware.sane.openFirewall = mkOption {
132 description = lib.mdDoc ''
133 Open ports needed for discovery of scanners on the local network, e.g.
134 needed for Canon scanners (BJNP protocol).
138 services.saned.enable = mkOption {
141 description = lib.mdDoc ''
142 Enable saned network daemon for remote connection to scanners.
144 saned would be run from `scanner` user; to allow
145 access to hardware that doesn't have `scanner` group
146 you should add needed groups to this user.
150 services.saned.extraConfig = mkOption {
153 example = "192.168.0.0/24";
154 description = lib.mdDoc ''
155 Extra saned configuration lines.
162 ###### implementation
166 hardware.sane.configDir = mkDefault "${saneConfig}/etc/sane.d";
168 environment.systemPackages = backends;
169 environment.sessionVariables = env;
170 environment.etc."sane-config".source = config.hardware.sane.configDir;
171 environment.etc."sane-libs".source = "${saneConfig}/lib/sane";
172 services.udev.packages = backends;
174 users.groups.scanner.gid = config.ids.gids.scanner;
175 networking.firewall.allowedUDPPorts = mkIf config.hardware.sane.openFirewall [ 8612 ];
178 (mkIf config.services.saned.enable {
179 networking.firewall.connectionTrackingModules = [ "sane" ];
181 systemd.services."saned@" = {
182 description = "Scanner Service";
183 environment = mapAttrs (name: val: toString val) env;
187 ExecStart = "${pkg}/bin/saned";
191 systemd.sockets.saned = {
192 description = "saned incoming socket";
193 wantedBy = [ "sockets.target" ];
194 listenStreams = [ "0.0.0.0:6566" "[::]:6566" ];
196 # saned needs to distinguish between IPv4 and IPv6 to open matching data sockets.
197 BindIPv6Only = "ipv6-only";
203 users.users.scanner = {
204 uid = config.ids.uids.scanner;
206 extraGroups = [ "lp" ] ++ optionals config.services.avahi.enable [ "avahi" ];