[buug] Managing without CUPS
Ian Zimmerman
itz at buug.org
Thu Sep 6 22:50:48 PDT 2012
At the meeting tonight I mentioned that I no longer use the buggy &
bloated CUPS spooler for printing, or any other spooler. Instead, I
pass input files through a foomatic-rip pipeline directly to the printer
port on a printer server machine, subject only to a UUCP-like locking
protocol.
Here are the 2 scripts involved:
/usr/local/bin/noqp:
#! /usr/bin/python
# Trivial script for No Queue Printing.
import subprocess as SP
import getopt
import sys
import os
import select
opts, args = getopt.getopt(sys.argv[1:], 'P:J:o:')
jobname = None
printer = None
popts = []
for k, v in opts:
if k == '-J':
if jobname is not None:
sys.stderr.write('Multiple -J options\n')
sys.exit(2)
jobname = v
elif k == '-P':
if printer is not None:
sys.stderr.write('Multiple -P options\n')
sys.exit(2)
printer = v
elif k == '-o':
popts.append(v)
# foomatic-rip in no spool mode has no default for -P so we have to
# supply it, one way or another
if printer is None:
try:
printer = os.environ['PRINTER']
except KeyError:
sys.stderr.write('No -P option and no PRINTER envvar\n')
sys.exit(2)
if not printer:
sys.stderr.write('No -P option and PRINTER envvar empty\n')
sys.exit(2)
# remote printer details
try:
host, device = os.environ['NOQP_HOST'], os.environ['NOQP_DEVICE']
except KeyError:
sys.stderr.write('NOQP_HOST or NOQP_DEVICE envvar unset\n')
sys.exit(2)
if not host or not device:
sys.stderr.write('NOQP_HOST or NOQP_DEVICE envvar empty\n')
# gather arguments for foomatic
foomargs = ['-P', printer]
if jobname:
foomargs.extend(('-J', jobname))
for popt in popts:
foomargs,extend(('-o', popt))
# set up the pipeline
sp_cat = SP.Popen(['cat'] + args, stdout=SP.PIPE, close_fds=True)
sp_rip = SP.Popen(['foomatic-rip'] + foomargs,
stdin=SP.PIPE, stdout=SP.PIPE, close_fds=True)
sp_ssh = SP.Popen(['ssh', host, 'lockedcat', device],
stdin=SP.PIPE, close_fds=True)
buf_cat_rip = ''
buf_rip_ssh = ''
rdict = {'cat': sp_cat.stdout, 'rip': sp_rip.stdout}
wdict = {'rip': sp_rip.stdin, 'ssh': sp_ssh.stdin}
# limit buffering, otherwise we might read the entire file into memory
MAX_BUF = 40 * select.PIPE_BUF
while rdict or wdict:
if not buf_cat_rip and 'cat' not in rdict and 'rip' in wdict:
sp_rip.stdin.close()
del wdict['rip']
if not buf_rip_ssh and 'rip' not in rdict and 'ssh' in wdict:
sp_ssh.stdin.close()
del wdict['ssh']
wlist = []
if 'rip' in wdict and buf_cat_rip:
wlist.append(wdict['rip'])
if 'ssh' in wdict and buf_rip_ssh:
wlist.append(wdict['ssh'])
rlist = []
if 'cat' in rdict and len(buf_cat_rip) < MAX_BUF:
rlist.append(rdict['cat'])
if 'rip' in rdict and len(buf_rip_ssh) < MAX_BUF:
rlist.append(rdict['rip'])
rset, wset, _ = select.select(rlist, wlist, [], 1.0)
if sp_rip.stdin in wset:
amount = min(select.PIPE_BUF, len(buf_cat_rip))
sp_rip.stdin.write(buf_cat_rip[:amount])
buf_cat_rip = buf_cat_rip[amount:]
if sp_ssh.stdin in wset:
amount = min(select.PIPE_BUF, len(buf_rip_ssh))
sp_ssh.stdin.write(buf_rip_ssh[:amount])
buf_rip_ssh = buf_rip_ssh[amount:]
if sp_cat.stdout in rset:
new_cat = sp_cat.stdout.read(select.PIPE_BUF)
if not new_cat:
del rdict['cat']
sp_cat.stdout.close()
else:
buf_cat_rip = buf_cat_rip + new_cat
if sp_rip.stdout in rset:
new_rip = sp_rip.stdout.read(select.PIPE_BUF)
if not new_rip:
del rdict['rip']
sp_rip.stdout.close()
else:
buf_rip_ssh = buf_rip_ssh + new_rip
status = 0
for sp in (sp_cat, sp_rip, sp_ssh):
sp.wait()
if sp.returncode != 0:
status = 1
sys.exit(status)
/usr/local/bin/lockedcat:
#! /bin/sh
set -e
device="$1"
lockfile="/run/lock/LCK..`basename ${device}`"
dotlockfile -r 100 -p "${lockfile}"
trap "dotlockfile -u ${lockfile}" EXIT HUP TERM INT
buffer -p 75 > "${device}"
--
Ian Zimmerman
gpg public key: 1024D/C6FF61AD
fingerprint: 66DC D68F 5C1B 4D71 2EE5 BD03 8A00 786C C6FF 61AD
http://www.gravatar.com/avatar/c66875cda51109f76c6312f4d4743d1e.png
Rule 420: All persons more than eight miles high to leave the court.
More information about the buug
mailing list