Nixos

如何使現有 Nix 包中的二進製文件能夠在另一個包中執行 shell 腳本?

  • January 29, 2019

我目前正在打包一個列印機驅動程序,它使用一個 shell 腳本作為 CUPS 過濾器。顯然,CUPS 需要能夠執行該腳本。但是,目前,它在嘗試時給了我一個 exec 格式錯誤。shell 腳本以#!/bin/shshebang 開頭。

包的以下程式碼將非常醜陋/hacky,因為我對 Nix 的了解非常基礎,所以提前抱歉。如果您想提供改進建議,請繼續,但我現在最關心的是如何讓它工作。

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
   '';
}

我正在談論的 bash 腳本是用catin設置的installPhase(我知道,非常抱歉,但這實際上只是他們在原始兄弟安裝腳本中所做的修改版本,所以這是我的藉口)。

此外,這是 CUPS 日誌的相關部分:

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)

您錯誤地生成了過濾器腳本。每行(特別是第一行)都縮進兩個空格。這意味著您的#!/bin/sh行實際上是..#!/bin/sh(我用點來表示空格),這意味著核心無法理解您的意思,從而產生exec format error.

您將所有內容縮進兩個空格,所以我建議更改此行

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

對於這個

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

當您在那裡時,引用的此處結束標記將確保您包含的此處文本也被引用,因此您無需$使用反斜杠轉義和其他重要字元。

引用自:https://unix.stackexchange.com/questions/497480