0

I'm currently packaging a printer driver, which uses a shell script as the CUPS filter. Obviously, CUPS needs to be able to run that script. Currently, however, it is giving me an exec format error while trying it. The shell script starts with a #!/bin/sh shebang.

The following code for the package is going to be really ugly/hacky because my knowledge of Nix is very basic, so sorry in advance. If you feel like providing suggestions for making it better, go ahead, but I'm mostly concerned with how to get it to work for now.

with import <nixpkgs> {};

let
  srcs = {
    lpr-deb = fetchurl {
      url = "http://download.brother.com/welcome/dlf101620/mfc9332cdwlpr-1.1.3-0.i386.deb";
      sha256 = "0mmqcwpbw4dx2hqaxhnvm52jm84vq8c55xrixsvapxwrdbpkdcca";
      name = "mfc9332cdwlpr-1.1.3-0.i386.deb";
    };
    cupswrapper-deb = fetchurl {
      url = "http://download.brother.com/welcome/dlf101621/mfc9332cdwcupswrapper-1.1.4-0.i386.deb";
      sha256 = "1q9y90hdrgl80zwqk2vn7b1znjvf15l8q0zg868sv0by6rdq8r5w";
      name = "mfc9332cdwcupswrapper-1.1.4-0.i386.deb";
    };
  };
in stdenv.mkDerivation rec {
  name="brother-mfc9332cdw";
  rev = "1.1.4-0";

  buildInputs = [ pkgs.wget pkgs.dpkg pkgs.perl pkgs.bash ];

  unpackPhase = ''
    dpkg-deb -x ${srcs.lpr-deb} .
    dpkg-deb -x ${srcs.cupswrapper-deb} .
    '';

  dontBuild = true;

  installPhase = ''
    perl -i -pe 's#printcap\.local#printcap#g' opt/brother/Printers/mfc9332cdw/inf/setupPrintcapij
    cp -rf usr $out/
    cp -rf opt $out/
    mkdir -p $out/share/cups/model/Brother
    cp $out/opt/brother/Printers/mfc9332cdw/cupswrapper/brother_mfc9332cdw_printer_en.ppd $out/share/cups/model/Brother
    chmod 644 $out/share/cups/model/Brother/brother_mfc9332cdw_printer_en.ppd
    cat $out/opt/brother/Printers/mfc9332cdw/cupswrapper/cupswrappermfc9332cdw | sed -n "/ENDOFWFILTER/,/ENDOFWFILTER/p" | tail -n +2 | sed "$ d" > brother_lpdwrapper_mfc9332cdw
    perl -i -pe 's#/usr/#$out/#g' brother_lpdwrapper_mfc9332cdw && perl -i -pe 's#/opt/#$out/opt/#g' brother_lpdwrapper_mfc9332cdw
    cat <<!ENDOFWFILTER! > brother_lpdwrapper_mfc9332cdw
      #!/bin/sh
      #
      # Copyright (C) 2005-2016 Brother. Industries, Ltd.
      #                                    Ver1.10

      # This program is free software; you can redistribute it and/or modify it
      # under the terms of the GNU General Public License as published by the Free
      # Software Foundation; either version 2 of the License, or (at your option)
      # any later version.
      #
      # This program is distributed in the hope that it will be useful, but WITHOUT
      # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      # more details.
      #
      # You should have received a copy of the GNU General Public License along with
      # this program; if not, write to the Free Software Foundation, Inc., 59 Temple
      # Place, Suite 330, Boston, MA  02111-1307  USA
      #

      LOGFILE="/dev/null"
      LOGLEVEL="1"
      LOGCLEVEL="7"
      DEBUG=0
      NUPENABLE=1
      LOG_LATESTONLY=1


      touch /tmp/mfc9332cdw_latest_print_info
      chmod 600 -R /tmp/mfc9332cdw_latest_print_info

      errorcode=0

      if [ \$DEBUG != 0 ]; then
          LOGFILE=/tmp/br_cupsfilter_debug_log
      fi

      PPDC=\`printenv | grep "PPD="\`
      PPDC=\`echo \$PPDC | sed -e 's/PPD=//'\`

      if [ "\$PPDC" = "" ]; then
          PPDC="$out/share/cups/model/Brother/brother_mfc9332cdw_printer_en.ppd"
      fi


      if [ \$LOGFILE != "/dev/null" ]; then
        if [ \$LOG_LATESTONLY == "1" ]; then
          rm -f \$LOGFILE
          date                                                           >\$LOGFILE
        else
          if [ -e \$LOGFILE ]; then
              date                                                        >>\$LOGFILE
          else
              date                                                        >\$LOGFILE
          fi
        fi
          echo "arg0 = \$0"                                           >>\$LOGFILE
          echo "arg1 = \$1"                                           >>\$LOGFILE
          echo "arg2 = \$2"                                           >>\$LOGFILE
          echo "arg3 = \$3"                                           >>\$LOGFILE
          echo "arg4 = \$4"                                           >>\$LOGFILE
          echo "arg5 = \$5"                                           >>\$LOGFILE
          echo "arg6 = \$6"                                           >>\$LOGFILE
          echo "PPD  = \$PPD"                                         >>\$LOGFILE
      fi

      cp  $out/opt/brother/Printers/mfc9332cdw/inf/brmfc9332cdwrc  /tmp/brmfc9332cdwrc_\$$
      chmod 777 -R /tmp/brmfc9332cdwrc_\$$
      export BRPRINTERRCFILE=/tmp/brmfc9332cdwrc_\$$

      INPUT_TEMP_PS=\`mktemp /tmp/br_input_ps.XXXXXX\`

      nup="cat"
      if [ "\`echo \$5 | grep 'Nup='\`" != "" ] && [ \$NUPENABLE != 0 ]; then

          if   [ "\`echo \$5 | grep 'Nup=64'\`" != "" ]; then
              nup="psnup -64"
          elif [ "\`echo \$5 | grep 'Nup=32'\`" != "" ]; then
              nup="psnup -32"
          elif [ "\`echo \$5 | grep 'Nup=25'\`" != "" ]; then
              nup="psnup -25"
          elif [ "\`echo \$5 | grep 'Nup=16'\`" != "" ]; then
              nup="psnup -16"
          elif [ "\`echo \$5 | grep 'Nup=8'\`" != "" ]; then
              nup="psnup -8"
          elif [ "\`echo \$5 | grep 'Nup=6'\`" != "" ]; then
              nup="psnup -6"
          elif [ "\`echo \$5 | grep 'Nup=4'\`" != "" ]; then
              nup="psnup -4"
          elif [ "\`echo \$5 | grep 'Nup=2'\`" != "" ]; then
              nup="psnup -2"
          elif [ "\`echo \$5 | grep 'Nup=1'\`" != "" ]; then
              nup="cat"
          fi
          echo   "NUP=\$nup"                                      >>\$LOGFILE
         if [ -e /usr/bin/psnup ]; then
             if [ \$# -ge 7 ]; then
                 cat \$6  | \$nup > \$INPUT_TEMP_PS
             else
                 cat       | \$nup > \$INPUT_TEMP_PS
             fi
         else
             if [ \$# -ge 7 ]; then
                 cp \$6  \$INPUT_TEMP_PS
             else
                 cat    > \$INPUT_TEMP_PS
             fi
         fi
      else
         if [ \$# -ge 7 ]; then
            cp \$6  \$INPUT_TEMP_PS
         else
            cat    > \$INPUT_TEMP_PS
         fi
      fi
      if [ -e "$out/opt/brother/Printers/mfc9332cdw/lpd/filtermfc9332cdw" ]; then
             :
      else
          echo "ERROR: /opt/brother/Printers/mfc9332cdw/lpd/filtermfc9332cdw does not exist"   >>\$LOGFILE
          echo "ERROR: /opt/brother/Printers/mfc9332cdw/lpd/filtermfc9332cdw does not exist"   >>/tmp/mfc9332cdw_latest_print_info
          errorcode=30
          exit
      fi

      CUPSOPTION=\`echo "\$5 Copies=1" | sed -e 's/BrMirror=OFF/MirrorPrint=OFF/' -e 's/BrMirror=ON/MirrorPrint=ON/' -e 's/BrChain/Chain/' -e 's/BrBrightness/Brightness/' -e 's/BrContrast/Contrast/' -e 's/BrHalfCut/HalfCut/' -e 's/BrAutoTapeCut/AutoCut/' -e 's/BrHalftonePattern/Halftone/' -e 's/Binary/Binary/' -e 's/Dither/Dither/' -e 's/ErrorDiffusion/ErrorDiffusion/' -e 's/BrSheets/Sheets/' -e 's/multiple-document-handling/Collate/' -e 's/separate-documents-collated-copies/ON/' -e 's/separate-documents-uncollated-copies/OFF/'\`
      if [ -e "$out/opt/brother/Printers/mfc9332cdw/cupswrapper/brcupsconfpt1" ]; then

        if [ \$DEBUG = 0 ]; then
           $out/opt/brother/Printers/mfc9332cdw/cupswrapper/brcupsconfpt1  MFC9332CDW  \$PPDC 0 "\$CUPSOPTION" "mfc9332cdw" \$BRPRINTERRCFILE>> /dev/null
        else
           $out/opt/brother/Printers/mfc9332cdw/cupswrapper/brcupsconfpt1  MFC9332CDW  \$PPDC \$LOGCLEVEL "\$CUPSOPTION" "mfc9332cdw" \$BRPRINTERRCFILE>>\$LOGFILE
        fi
      fi

      if [ \$DEBUG -lt 10 ]; then
          cat    \$INPUT_TEMP_PS | $out/opt/brother/Printers/mfc9332cdw/lpd/filtermfc9332cdw 
          echo brmfc9332cdwrc_\$$   > /tmp/mfc9332cdw_latest_print_info
          cat  /tmp/brmfc9332cdwrc_\$$  >> /tmp/mfc9332cdw_latest_print_info
          rm -f /tmp/brmfc9332cdwrc_\$$

          if [ \$LOGLEVEL -gt 2 ];  then
             if [ \$LOGFILE != "/dev/null" ]; then
               echo ""                                                >>\$LOGFILE
               echo "    ------PostScript Data-------"                >>\$LOGFILE
               cat    \$INPUT_TEMP_PS                                  >>\$LOGFILE
             fi
          fi
      fi
      rm -f  \$INPUT_TEMP_PS

      exit $errorcode
    !ENDOFWFILTER!
    chmod 755 brother_lpdwrapper_mfc9332cdw
    mkdir -p $out/lib/cups/filter
    cp brother_lpdwrapper_mfc9332cdw $out/lib/cups/filter
    '';
}

The bash script I'm talking about is the one that is set up with cat in installPhase (I know, terribly sorry, but this is actually just a modified version of what they did in the original brother install script, so that's my excuse).

Also, here's the relevant part of the CUPS log:

Jan 29 15:43:22 kenix-vaio cupsd[11674]: Started filter /nix/store/v0vlk9dni6kn077i3ilfkml4cr8w979b-cups-progs/lib/cups/filter/pdftopdf (PID 11799)
Jan 29 15:43:22 kenix-vaio cupsd[11674]: Started filter /nix/store/v0vlk9dni6kn077i3ilfkml4cr8w979b-cups-progs/lib/cups/filter/pdftops (PID 11800)
Jan 29 15:43:22 kenix-vaio cupsd[11674]: Started filter /nix/store/v0vlk9dni6kn077i3ilfkml4cr8w979b-cups-progs/lib/cups/filter/brother_lpdwrapper_mfc9332cdw (PID 11801)
Jan 29 15:43:22 kenix-vaio cupsd[11674]: Started backend /nix/store/v0vlk9dni6kn077i3ilfkml4cr8w979b-cups-progs/lib/cups/backend/lpd (PID 11802)
Jan 29 15:43:22 kenix-vaio cupsd[11674]: REQUEST localhost - - POST /printers/MFC9332CDW HTTP/1.1 200 127388 Send-Document successful-ok
Jan 29 15:43:22 kenix-vaio cupsd[11674]: execv failed: Exec format error
Jan 29 15:43:22 kenix-vaio cupsd[11674]: PID 11801 (/nix/store/v0vlk9dni6kn077i3ilfkml4cr8w979b-cups-progs/lib/cups/filter/brother_lpdwrapper_mfc9332cdw) stopped with status 108 (Exec format error)
  • If you try to run /nix/store/v0vlk9dni6kn077i3ilfkml4cr8w979b-cups-progs/lib/cups/filter/brother_lpdwrapper_mfc9332cdw directly (as a program), what happens? – roaima Jan 29 at 15:35
  • @roaima It runs. It doesn't print anything to the console, but it also doesn't crash or anything. It just runs until I kill it. – Keno Jan 29 at 15:49
  • 1
    @roaima yes, I ran it just like that – Keno Jan 29 at 17:37
1

You've generated your filter script incorrectly. Every line (and specifically the first) is indented by two spaces. What this means is that your #!/bin/sh line is actually ..#!/bin/sh (where I've used dots to indicate spaces), and this means the kernel cannot work out what you mean, which in turn produces the exec format error.

You're indenting everything by two spaces, so I would suggest changing this line

cat <<!ENDOFWFILTER! > brother_lpdwrapper_mfc9332cdw
...
!ENDOFWFILTER!

for this one

sed 's/^  //' <<'!ENDOFWFILTER!' > brother_lpdwrapper_mfc9332cdw
...
!ENDOFWFILTER!

While you're there, the quoted end-of-here marker will ensure that your included here text is also quoted, so you don't need to escape $ and other important characters with a backslash.

  • Perfect, thanks so much for taking the time to look into this! Do you have any idea as to why it didn't crash when I just called it manually? – Keno Jan 29 at 23:36
  • 1
    1. I would guess the shell can correctly run shell scripts without relying on the kernel to interpret the #!. 2. Try setting PATH explicitly near the top of the script. – roaima Jan 29 at 23:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.