brscan5: init at 1.2.6-0

+418 -2
+6
maintainers/maintainer-list.nix
··· 6238 githubId = 11810057; 6239 name = "Matt Snider"; 6240 }; 6241 matthewbauer = { 6242 email = "mjbauer95@gmail.com"; 6243 github = "matthewbauer";
··· 6238 githubId = 11810057; 6239 name = "Matt Snider"; 6240 }; 6241 + mattchrist = { 6242 + email = "nixpkgs-matt@christ.systems"; 6243 + github = "mattchrist"; 6244 + githubId = 952712; 6245 + name = "Matt Christ"; 6246 + }; 6247 matthewbauer = { 6248 email = "mjbauer95@gmail.com"; 6249 github = "matthewbauer";
+1
nixos/modules/module-list.nix
··· 398 ./services/hardware/ratbagd.nix 399 ./services/hardware/sane.nix 400 ./services/hardware/sane_extra_backends/brscan4.nix 401 ./services/hardware/sane_extra_backends/dsseries.nix 402 ./services/hardware/spacenavd.nix 403 ./services/hardware/tcsd.nix
··· 398 ./services/hardware/ratbagd.nix 399 ./services/hardware/sane.nix 400 ./services/hardware/sane_extra_backends/brscan4.nix 401 + ./services/hardware/sane_extra_backends/brscan5.nix 402 ./services/hardware/sane_extra_backends/dsseries.nix 403 ./services/hardware/spacenavd.nix 404 ./services/hardware/tcsd.nix
+115
nixos/modules/services/hardware/sane_extra_backends/brscan5.nix
···
··· 1 + { config, lib, pkgs, ... }: 2 + 3 + with lib; 4 + 5 + let 6 + cfg = config.hardware.sane.brscan5; 7 + 8 + netDeviceList = attrValues cfg.netDevices; 9 + 10 + etcFiles = pkgs.callPackage ./brscan5_etc_files.nix { netDevices = netDeviceList; }; 11 + 12 + netDeviceOpts = { name, ... }: { 13 + 14 + options = { 15 + 16 + name = mkOption { 17 + type = types.str; 18 + description = '' 19 + The friendly name you give to the network device. If undefined, 20 + the name of attribute will be used. 21 + ''; 22 + 23 + example = literalExample "office1"; 24 + }; 25 + 26 + model = mkOption { 27 + type = types.str; 28 + description = '' 29 + The model of the network device. 30 + ''; 31 + 32 + example = literalExample "MFC-7860DW"; 33 + }; 34 + 35 + ip = mkOption { 36 + type = with types; nullOr str; 37 + default = null; 38 + description = '' 39 + The ip address of the device. If undefined, you will have to 40 + provide a nodename. 41 + ''; 42 + 43 + example = literalExample "192.168.1.2"; 44 + }; 45 + 46 + nodename = mkOption { 47 + type = with types; nullOr str; 48 + default = null; 49 + description = '' 50 + The node name of the device. If undefined, you will have to 51 + provide an ip. 52 + ''; 53 + 54 + example = literalExample "BRW0080927AFBCE"; 55 + }; 56 + 57 + }; 58 + 59 + 60 + config = 61 + { name = mkDefault name; 62 + }; 63 + }; 64 + 65 + in 66 + 67 + { 68 + options = { 69 + 70 + hardware.sane.brscan5.enable = 71 + mkEnableOption "Brother's brscan5 scan backend" // { 72 + description = '' 73 + When enabled, will automatically register the "brscan5" sane 74 + backend and bring configuration files to their expected location. 75 + ''; 76 + }; 77 + 78 + hardware.sane.brscan5.netDevices = mkOption { 79 + default = {}; 80 + example = 81 + { office1 = { model = "MFC-7860DW"; ip = "192.168.1.2"; }; 82 + office2 = { model = "MFC-7860DW"; nodename = "BRW0080927AFBCE"; }; 83 + }; 84 + type = with types; attrsOf (submodule netDeviceOpts); 85 + description = '' 86 + The list of network devices that will be registered against the brscan5 87 + sane backend. 88 + ''; 89 + }; 90 + }; 91 + 92 + config = mkIf (config.hardware.sane.enable && cfg.enable) { 93 + 94 + hardware.sane.extraBackends = [ 95 + pkgs.brscan5 96 + ]; 97 + 98 + environment.etc."opt/brother/scanner/brscan5" = 99 + { source = "${etcFiles}/etc/opt/brother/scanner/brscan5"; }; 100 + environment.etc."opt/brother/scanner/models" = 101 + { source = "${etcFiles}/etc/opt/brother/scanner/brscan5/models"; }; 102 + environment.etc."sane.d/dll.d/brother5.conf".source = "${pkgs.brscan5}/etc/sane.d/dll.d/brother.conf"; 103 + 104 + assertions = [ 105 + { assertion = all (x: !(null != x.ip && null != x.nodename)) netDeviceList; 106 + message = '' 107 + When describing a network device as part of the attribute list 108 + `hardware.sane.brscan5.netDevices`, only one of its `ip` or `nodename` 109 + attribute should be specified, not both! 110 + ''; 111 + } 112 + ]; 113 + 114 + }; 115 + }
+77
nixos/modules/services/hardware/sane_extra_backends/brscan5_etc_files.nix
···
··· 1 + { stdenv, lib, brscan5, netDevices ? [] }: 2 + 3 + /* 4 + 5 + Testing 6 + ------- 7 + From nixpkgs repo 8 + 9 + No net devices: 10 + 11 + ~~~ 12 + nix-build -E 'let pkgs = import ./. {}; 13 + brscan5-etc-files = pkgs.callPackage (import ./nixos/modules/services/hardware/sane_extra_backends/brscan5_etc_files.nix) {}; 14 + in brscan5-etc-files' 15 + ~~~ 16 + 17 + Two net devices: 18 + 19 + ~~~ 20 + nix-build -E 'let pkgs = import ./. {}; 21 + brscan5-etc-files = pkgs.callPackage (import ./nixos/modules/services/hardware/sane_extra_backends/brscan5_etc_files.nix) {}; 22 + in brscan5-etc-files.override { 23 + netDevices = [ 24 + {name="a"; model="MFC-7860DW"; nodename="BRW0080927AFBCE";} 25 + {name="b"; model="MFC-7860DW"; ip="192.168.1.2";} 26 + ]; 27 + }' 28 + ~~~ 29 + 30 + */ 31 + 32 + let 33 + 34 + addNetDev = nd: '' 35 + brsaneconfig5 -a \ 36 + name="${nd.name}" \ 37 + model="${nd.model}" \ 38 + ${if (lib.hasAttr "nodename" nd && nd.nodename != null) then 39 + ''nodename="${nd.nodename}"'' else 40 + ''ip="${nd.ip}"''}''; 41 + addAllNetDev = xs: lib.concatStringsSep "\n" (map addNetDev xs); 42 + in 43 + 44 + stdenv.mkDerivation { 45 + 46 + name = "brscan5-etc-files"; 47 + version = "1.2.6-0"; 48 + src = "${brscan5}/opt/brother/scanner/brscan5"; 49 + 50 + nativeBuildInputs = [ brscan5 ]; 51 + 52 + dontConfigure = true; 53 + 54 + buildPhase = '' 55 + TARGET_DIR="$out/etc/opt/brother/scanner/brscan5" 56 + mkdir -p "$TARGET_DIR" 57 + cp -rp "./models" "$TARGET_DIR" 58 + cp -rp "./brscan5.ini" "$TARGET_DIR" 59 + cp -rp "./brsanenetdevice.cfg" "$TARGET_DIR" 60 + 61 + export NIX_REDIRECTS="/etc/opt/brother/scanner/brscan5//brsanenetdevice.cfg=$TARGET_DIR/brsanenetdevice.cfg" 62 + 63 + printf '${addAllNetDev netDevices}\n' 64 + 65 + ${addAllNetDev netDevices} 66 + ''; 67 + 68 + dontInstall = true; 69 + 70 + meta = with lib; { 71 + description = "Brother brscan5 sane backend driver etc files"; 72 + homepage = "https://www.brother.com"; 73 + platforms = platforms.linux; 74 + license = licenses.unfree; 75 + maintainers = with maintainers; [ mattchrist ]; 76 + }; 77 + }
+34
nixos/tests/brscan5.nix
···
··· 1 + # integration tests for brscan5 sane driver 2 + # 3 + 4 + import ./make-test-python.nix ({ pkgs, ...} : { 5 + name = "brscan5"; 6 + meta = with pkgs.lib.maintainers; { 7 + maintainers = [ mattchrist ]; 8 + }; 9 + 10 + machine = { pkgs, ... }: 11 + { 12 + nixpkgs.config.allowUnfree = true; 13 + hardware.sane = { 14 + enable = true; 15 + brscan5 = { 16 + enable = true; 17 + netDevices = { 18 + "a" = { model="MFC-7860DW"; nodename="BRW0080927AFBCE"; }; 19 + "b" = { model="MFC-7860DW"; ip="192.168.1.2"; }; 20 + }; 21 + }; 22 + }; 23 + }; 24 + 25 + testScript = '' 26 + # sane loads libsane-brother5.so.1 successfully, and scanimage doesn't die 27 + assert 'libsane-brother5.so.1", O_RDONLY|O_CLOEXEC) = 10' in machine.succeed('strace scanimage -L 2>&1') 28 + 29 + # module creates a config 30 + cfg = machine.succeed('cat /etc/opt/brother/scanner/brscan5/brsanenetdevice.cfg') 31 + assert 'DEVICE=a , "MFC-7860DW" , Unknown , NODENAME=BRW0080927AFBCE' in cfg 32 + assert 'DEVICE=b , "MFC-7860DW" , Unknown , IP-ADDRESS=192.168.1.2' in cfg 33 + ''; 34 + })
+98
pkgs/applications/graphics/sane/backends/brscan5/default.nix
···
··· 1 + { stdenv, lib, fetchurl, callPackage, patchelf, makeWrapper, coreutils, libusb1, avahi-compat, glib, libredirect }: 2 + let 3 + myPatchElf = file: with lib; '' 4 + patchelf --set-interpreter \ 5 + ${stdenv.glibc}/lib/ld-linux${optionalString stdenv.is64bit "-x86-64"}.so.2 \ 6 + ${file} 7 + ''; 8 + 9 + in 10 + stdenv.mkDerivation rec { 11 + pname = "brscan5"; 12 + version = "1.2.6-0"; 13 + src = { 14 + "i686-linux" = fetchurl { 15 + url = "https://download.brother.com/welcome/dlf104034/${pname}-${version}.i386.deb"; 16 + sha256 = "102q745pc0168syggd4gym51qf3m3iqld3a4skfnbkm6yky4w4s8"; 17 + }; 18 + "x86_64-linux" = fetchurl { 19 + url = "https://download.brother.com/welcome/dlf104033/${pname}-${version}.amd64.deb"; 20 + sha256 = "1pwbzhpg5nzpw2rw936vf2cr334v8iny16y8fbb1zimgzmv427wx"; 21 + }; 22 + }."${stdenv.hostPlatform.system}"; 23 + 24 + unpackPhase = '' 25 + ar x $src 26 + tar xfv data.tar.xz 27 + ''; 28 + 29 + nativeBuildInputs = [ makeWrapper patchelf coreutils ]; 30 + buildInputs = [ libusb1 avahi-compat stdenv.cc.cc glib ]; 31 + dontBuild = true; 32 + 33 + postPatch = '' 34 + ${myPatchElf "opt/brother/scanner/brscan5/brsaneconfig5"} 35 + ${myPatchElf "opt/brother/scanner/brscan5/brscan_cnetconfig"} 36 + ${myPatchElf "opt/brother/scanner/brscan5/brscan_gnetconfig"} 37 + 38 + for a in opt/brother/scanner/brscan5/*.so.* opt/brother/scanner/brscan5/brscan_[cg]netconfig; do 39 + if ! test -L $a; then 40 + patchelf --set-rpath ${lib.makeLibraryPath buildInputs} $a 41 + fi 42 + done 43 + 44 + # driver is hardcoded to look in /opt/brother/scanner/brscan5/models for model metadata. 45 + # patch it to look in /etc/opt/brother/scanner/models instead, so nixos environment.etc can make it available 46 + printf '/etc/opt/brother/scanner/models\x00' | dd of=opt/brother/scanner/brscan5/libsane-brother5.so.1.0.7 bs=1 seek=84632 conv=notrunc 47 + ''; 48 + 49 + installPhase = with lib; '' 50 + runHook preInstall 51 + PATH_TO_BRSCAN5="opt/brother/scanner/brscan5" 52 + mkdir -p $out/$PATH_TO_BRSCAN5 53 + cp -rp $PATH_TO_BRSCAN5/* $out/$PATH_TO_BRSCAN5 54 + 55 + 56 + pushd $out/$PATH_TO_BRSCAN5 57 + ln -s libLxBsDeviceAccs.so.1.0.0 libLxBsDeviceAccs.so.1 58 + ln -s libLxBsNetDevAccs.so.1.0.0 libLxBsNetDevAccs.so.1 59 + ln -s libLxBsScanCoreApi.so.3.0.0 libLxBsScanCoreApi.so.3 60 + ln -s libLxBsUsbDevAccs.so.1.0.0 libLxBsUsbDevAccs.so.1 61 + ln -s libsane-brother5.so.1.0.7 libsane-brother5.so.1 62 + popd 63 + 64 + mkdir -p $out/lib/sane 65 + for file in $out/$PATH_TO_BRSCAN5/*.so.* ; do 66 + ln -s $file $out/lib/sane/ 67 + done 68 + 69 + makeWrapper \ 70 + "$out/$PATH_TO_BRSCAN5/brsaneconfig5" \ 71 + "$out/bin/brsaneconfig5" \ 72 + --suffix-each NIX_REDIRECT ":" "/etc/opt/brother/scanner/brscan5=$out/opt/brother/scanner/brscan5 /opt/brother/scanner/brscan5=$out/opt/brother/scanner/brscan5" \ 73 + --set LD_PRELOAD ${libredirect}/lib/libredirect.so 74 + 75 + mkdir -p $out/etc/sane.d/dll.d 76 + echo "brother5" > $out/etc/sane.d/dll.d/brother5.conf 77 + 78 + mkdir -p $out/etc/udev/rules.d 79 + cp -p $PATH_TO_BRSCAN5/udev-rules/NN-brother-mfp-brscan5-1.0.2-2.rules \ 80 + $out/etc/udev/rules.d/49-brother-mfp-brscan5-1.0.2-2.rules 81 + 82 + ETCDIR=$out/etc/opt/brother/scanner/brscan5 83 + mkdir -p $ETCDIR 84 + cp -rp $PATH_TO_BRSCAN5/{models,brscan5.ini,brsanenetdevice.cfg} $ETCDIR/ 85 + 86 + runHook postInstall 87 + ''; 88 + 89 + dontPatchELF = true; 90 + 91 + meta = { 92 + description = "Brother brscan5 sane backend driver"; 93 + homepage = "https://www.brother.com"; 94 + platforms = [ "i686-linux" "x86_64-linux" ]; 95 + license = lib.licenses.unfree; 96 + maintainers = with lib.maintainers; [ mattchrist ]; 97 + }; 98 + }
+79 -2
pkgs/build-support/libredirect/libredirect.c
··· 9 #include <limits.h> 10 #include <string.h> 11 #include <spawn.h> 12 13 #define MAX_REDIRECTS 128 14 ··· 189 return posix_spawnp_real(pid, rewrite(file, buf), file_actions, attrp, argv, envp); 190 } 191 192 - int execv(const char *path, char *const argv[]) 193 { 194 - int (*execv_real) (const char *path, char *const argv[]) = dlsym(RTLD_NEXT, "execv"); 195 char buf[PATH_MAX]; 196 return execv_real(rewrite(path, buf), argv); 197 }
··· 9 #include <limits.h> 10 #include <string.h> 11 #include <spawn.h> 12 + #include <dirent.h> 13 14 #define MAX_REDIRECTS 128 15 ··· 190 return posix_spawnp_real(pid, rewrite(file, buf), file_actions, attrp, argv, envp); 191 } 192 193 + int execv(const char * path, char * const argv[]) 194 { 195 + int (*execv_real) (const char * path, char * const argv[]) = dlsym(RTLD_NEXT, "execv"); 196 char buf[PATH_MAX]; 197 return execv_real(rewrite(path, buf), argv); 198 } 199 + 200 + int execvp(const char * path, char * const argv[]) 201 + { 202 + int (*_execvp) (const char *, char * const argv[]) = dlsym(RTLD_NEXT, "execvp"); 203 + char buf[PATH_MAX]; 204 + return _execvp(rewrite(path, buf), argv); 205 + } 206 + 207 + int execve(const char * path, char * const argv[], char * const envp[]) 208 + { 209 + int (*_execve) (const char *, char * const argv[], char * const envp[]) = dlsym(RTLD_NEXT, "execve"); 210 + char buf[PATH_MAX]; 211 + return _execve(rewrite(path, buf), argv, envp); 212 + } 213 + 214 + DIR * opendir(const char * path) 215 + { 216 + char buf[PATH_MAX]; 217 + DIR * (*_opendir) (const char*) = dlsym(RTLD_NEXT, "opendir"); 218 + 219 + return _opendir(rewrite(path, buf)); 220 + } 221 + 222 + #define SYSTEM_CMD_MAX 512 223 + 224 + char *replace_substring(char * source, char * buf, char * replace_string, char * start_ptr, char * suffix_ptr) { 225 + char head[SYSTEM_CMD_MAX] = {0}; 226 + strncpy(head, source, start_ptr - source); 227 + 228 + char tail[SYSTEM_CMD_MAX] = {0}; 229 + if(suffix_ptr < source + strlen(source)) { 230 + strcpy(tail, suffix_ptr); 231 + } 232 + 233 + sprintf(buf, "%s%s%s", head, replace_string, tail); 234 + return buf; 235 + } 236 + 237 + char *replace_string(char * buf, char * from, char * to) { 238 + int num_matches = 0; 239 + char * matches[SYSTEM_CMD_MAX]; 240 + int from_len = strlen(from); 241 + for(int i=0; i<strlen(buf); i++){ 242 + char *cmp_start = buf + i; 243 + if(strncmp(from, cmp_start, from_len) == 0){ 244 + matches[num_matches] = cmp_start; 245 + num_matches++; 246 + } 247 + } 248 + int len_diff = strlen(to) - strlen(from); 249 + for(int n = 0; n < num_matches; n++) { 250 + char replaced[SYSTEM_CMD_MAX]; 251 + replace_substring(buf, replaced, to, matches[n], matches[n]+from_len); 252 + strcpy(buf, replaced); 253 + for(int nn = n+1; nn < num_matches; nn++) { 254 + matches[nn] += len_diff; 255 + } 256 + } 257 + return buf; 258 + } 259 + 260 + void rewriteSystemCall(const char * command, char * buf) { 261 + strcpy(buf, command); 262 + for (int n = 0; n < nrRedirects; ++n) { 263 + replace_string(buf, from[n], to[n]); 264 + } 265 + } 266 + 267 + int system(const char *command) 268 + { 269 + int (*_system) (const char*) = dlsym(RTLD_NEXT, "system"); 270 + 271 + char newCommand[SYSTEM_CMD_MAX]; 272 + rewriteSystemCall(command, newCommand); 273 + return _system(newCommand); 274 + }
+6
pkgs/build-support/libredirect/test.c
··· 2 #include <fcntl.h> 3 #include <spawn.h> 4 #include <stdio.h> 5 #include <unistd.h> 6 7 #include <sys/stat.h> ··· 31 assert(execv(TESTPATH, argv) == 0); 32 } 33 34 int main(void) 35 { 36 FILE *testfp; ··· 50 assert(stat(TESTPATH, &testsb) != -1); 51 52 test_spawn(); 53 test_execv(); 54 55 /* If all goes well, this is never reached because test_execv() replaces
··· 2 #include <fcntl.h> 3 #include <spawn.h> 4 #include <stdio.h> 5 + #include <stdlib.h> 6 #include <unistd.h> 7 8 #include <sys/stat.h> ··· 32 assert(execv(TESTPATH, argv) == 0); 33 } 34 35 + void test_system(void) { 36 + assert(system(TESTPATH) == 0); 37 + } 38 + 39 int main(void) 40 { 41 FILE *testfp; ··· 55 assert(stat(TESTPATH, &testsb) != -1); 56 57 test_spawn(); 58 + test_system(); 59 test_execv(); 60 61 /* If all goes well, this is never reached because test_execv() replaces
+2
pkgs/top-level/all-packages.nix
··· 30783 30784 brscan4 = callPackage ../applications/graphics/sane/backends/brscan4 { }; 30785 30786 dsseries = callPackage ../applications/graphics/sane/backends/dsseries { }; 30787 30788 sane-airscan = callPackage ../applications/graphics/sane/backends/airscan { };
··· 30783 30784 brscan4 = callPackage ../applications/graphics/sane/backends/brscan4 { }; 30785 30786 + brscan5 = callPackage ../applications/graphics/sane/backends/brscan5 { }; 30787 + 30788 dsseries = callPackage ../applications/graphics/sane/backends/dsseries { }; 30789 30790 sane-airscan = callPackage ../applications/graphics/sane/backends/airscan { };