2012年3月13日火曜日

CUPSで一苦労


印刷の調子が悪いのでまた CUPS。Linux 使っていて一番苦労するのは印刷だな。

どう悪いかというと、単に相当時間がかかったり、あまりに遅くてストールしてしまうあたり。ある 8 ページのファイルなんかは食事から戻ってきてもまだ印刷出来ていなかった。汎用機の時代のようだ。(超高いインパクトプリンタを使っている場合を除く)

CUPS は何をやっているのかさっぱり見えないので、とりあえず受けて (フィルタ通して) プリンタに送るだけのお仕事しかしないサーバのほうは lprng に変更。入れるのは apt-get で一発。

とりあえず昔使った printcap をそのままに lprng を起動する。基本的に直結か、"gs -q -dDuplex -dNOPAUSE -sDEVICE=lp2200 -r600 -sOutputFile=- -" ぐらいしかやってない簡単な奴。これに test.ps を流し込むとすばやく綺麗に印刷出来た。

次にデスクトップのほうの CUPS をこれを使うように設定してやる。ポートを "lpd://print_server/lp" (デフォルト、postscript を入れると gs で変換してプリンタに送る) にしてやり、Generic Postscript プリンタを選べば終了。のはずだが印刷出来ない。エラーは "/usr/lib/cups/filter/foomatic-rip failed" とか。

このエラーに関する情報はほとんどない (というか、「そのエラーだけでは判らない」という情報は見た) のだが、ネットまわりが怪しいと直感したので、nmap を使って調べてみるとサーバのポートが開いてない。これは
/etc/lprng/lpd.conf に
lpd_listen_port=515
を書けばいいとすぐ判った。

で、再起動したがやっぱり駄目。"telnet print_server 515" として見るが "no connect permissions" ではねられる。nmap で見ても開いているし、サーバにログインして "telnet localhost 515" は大丈夫なので、daemon が動いてないのではなくどっかにアクセス制御があるらしい。(もちろん /etc/hosts.lpd ではない)

これを探すのは苦労したが
/etc/lprng/lpd.perms の関係部分を
#REJECT NOT SERVER
のようにコメントアウトすれば良いと判明。うん、そのまんまだね。
ただ、開けたくないポートもあったので、最終的には
ACCEPT SERVICE=X REMOTEIP=192.168.0.0/255.255.255.0,127.0.0.0/8
REJECT SERVICE=X
みたいな設定になった。ひとつだけポートを開けりゃいいってことなら
/etc/lprng/lpd.conf に
lpd_listen_port=xxx.xxx.xxx.xxx%515
でも OK。複数書く方法もあるんじゃないかと思うのだが、見付けられず。

ついでなので、Desktop のほうの CUPS にいくつかプリンタを追加した。ひとつは手元で変換して raw printer に送るやつ。ポートとして "lpd://print_server/raw" (まんま。何もしないで受けたものをそのままプリンタに送る) を選び、プリンタドライバに EPSON LP-2200 を選ぶ。もうひとつは、考えてみりゃプリンタサーバのほうは postscript を受ける前提で作ってあるんだよなあ、ということでポートとして "lpd://print_server/lp"、ドライバとして raw プリンタを選んだ。これで手元のアプリで出来た postscript ファイルがそのまんまプリンタサーバに送られるはず。

整理すると
1. local filter : ps => server port : ps を受けて gs を通りプリンタへ
2. local filter : lp2200.ppd で escpage => server port : プリンタ直結
3. local filter : なし (アプリ製 ps) => server port : ps を受けて gs を通りプリンタへ
ができたわけだ。

と、色々苦労して (一番苦労したのはネットワーク) 設定したのだが、全然早くならない。なんで?

2. はすぐ判った。手元で gs を通過するのに分単位で時間がかかり、出来たものがネットを通るのにまた時間がかかっている。他は?
少なくともサーバ側は何をやっているのか判るので、フィルタ中にデータをトラップする設定を書いて調べてみた。すると 1. は ps を送っているのだが、3. は pdf を送っていることが判明した。どうしてこうなった?

1. は ps ではあるのだが、ブラウザなどに直接吐かせた ps に比べると異様にでかい。中を見ると ascii decode してあるようだ。そのせいかどうかは不明だが、それを gs に解釈させると数倍以上の時間がかかる。そこで遅くなっているらしい。もちろんサイズが大きいのでネットワークに時間がかかっている部分もある。
だいたいの感触だが、同じブラウザに同じページを吐かせた時、gs が pdf を解釈するのには ps の 10 倍ぐらいの時間がかかる。ブラウザの吐いた ps と cups が造った ps とでは、1.5 倍以上かかっている。

結局、ブラウザ等に直接吐かせた ps をサーバに転送、lpr に送るれば待ち時間なく出力できるはずのものが、cups を入れることによって余分な変換を何度もかまされ、データもでかくなってしまってストールしていたわけだ。「CUPS で簡単印刷」とかどの口で言っているのだろうか?

しかも腹の立つことに raw プリンタですら pdf を送る仕様になっているために、一番単純な構成を組むことが出来ない。そいつが CUPS のせいかのかアプリのせいなのかというと... よくわからん。Firefox の場合は、pdf ファイルに吐いたのも raw に送るのも同じ内容だが、google-chrome だと異なる。なんなんだ?
(Firefox もいつも同じというわけではないようだ。理解不能。)
"Generic text-only printer" っていけそうかな?と思ったが駄目。"client-error-document-format-not-supported" なんて言うところを見ると、text-only かどうか判断するフィルタがあるのだろう。余計なお世話だっての。

lpadmin あたりでなんとか出来そうな感じだったので、いろいろ試すがやっぱり駄目。単純にしても (lpadmin -p test -E -v lpd://192.168.0.1/ps ぐらい) pdf を吐く。勘弁してくれ。

まあ cups の lpr は入れて設定したので、なんなら手元で ps 作って lpr にかけりゃいいや。リモートに出すための printcap の設定はこんなかんじ。
lp|remote printer:\
        :lp=:\
        :rm=192.168.0.1:\
        :rp=ps:\
        :mx#0:sh:
rm にサーバ名かアドレス、rp にキュー名を書く。

ついでなので 他所で発見した lprng で foomatic-rip (PPD, OpenPrinting から持ってくる) を使う設定を書いとく。CUPS の優位ってこれだけだよな。
psf|post scriput printer with foomatic:\
        :lp=/dev/usb/lp0:\
        :sd=/var/spool/lpd/pdf:\
        :af=/usr/local/lib/Epson-LP-2200-eplaser-jp.ppd:\
        :if=/usr/bin/foomatic-rip:\
        :lf=/var/log/lp-errs:\
        :mx#0:sh:

lpr/lpd の頃も苦労したもんだが、それはデバイスが対応してないから苦労したって話であって、それ以外の部分は単純で一度書けばずっと動いたもんだった。今はデバイスのほうはちゃんと対応しているが、身内の CUPS が裏切りやがる。