#!/usr/bin/perl # The above Perl path may vary on your system; fix it!!! -*- perl -*- # beh - Backend Error Handler # A wrapper for CUPS backends to make error handling configurable # Usually, if a CUPS backend exits with an error status other than zero # (for example if a printer is not turned on or not reachable on the # network), CUPS disables the print queue and one can only print again # if a system administrator re-enables the queue manually. Even restarting # CUPS (or rebooting) does not re-enable disabled queues. # # For system administrators this can get annoying, for newbie users # who are not aware of this problem it looks like that CUPS is severely # broken. They remove and re-install print queues, getting on the nerves # of distro install support, people, or even switch back to a proprietary # operating system. # # This script makes the handling of such backend errors configurable, so # that the problem can easily be worked around. The new possibilities are: # # - Let queues simply not being disabled. Simple approach, but job gets # lost. # # - Repeat a given number of times. # # - Repeat infinitely often, until the job gets finally through. This # is the standard of LPRng, and it eliminates loss of the job. # # - The interval between two attemts to run the backend can also be # configured. # # - Configuration is done independently for each print queue. So local # printers and network printers can be treated differently. # Save this file in your CUPS backend directory, usually # /usr/lib/cups/backend/ or /usr/local/lib/cups/backend/ # # Mark this filter world-readable and world-executable. Restart CUPS to # make the new backend known to the spooler. # # See http://www.openprinting.org/cups-doc.html and the additional # instructions below. # beh - Backend Error Handler # # Copyright 2005 Till Kamppeter # # 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. # Usage: # # cp beh /usr/lib/cups/backend/ # chmod 755 /usr/lib/cups/backend/beh # killall -HUP cupsd (or "/etc/init.d/cups restart") # lpadmin -p -E -v beh:/
/// # # with # : The name of your print queue #
: Don't Disable, if "1", beh always exits with zero # status, so the queue gets never disabled when the # original backend exits with an error. "0" carries # the error status of the last call of the backend # (after retries) on to CUPS, so the queue # usually gets disabled. # : Attempts, number of attempts to recall the backend # in case of an error. "0" means infinite retries. In # this case
gets meaningless. # : Delay between two attempts to call the beckend, to # be given in seconds and as an integer number. # Meaningless if is one. # : The original URI, which your queue had before. # # All parameters, especially,
, , and have always to # be specified, even if one of them is meaningless due to the setting of # the others. # # beh works with every backend except the "hp" backend of HPLIP. # # Example URIs: # # beh:/1/3/5/socket://printer:9100 # # On the network printer with host name "printer" it is tried to access # 3 times with 5 second delays between the attempts. If the job still # fails, the queue is not disabled (and the job discarded). # # beh:/0/10/60/socket://printer:9100 # # Retry 10 times in one minute intervals, disable the queue when still # not succeeding. # # beh:/1/0/60/usb://Brother/HL-5040%20series # # On a Brother HL-5040 on the USB try infinitely often until the printer # comes back, in intervals of one minute. This way the job does not get # lost when the printer is turned off and one can intendedly delay # printing by simply switching off the printer. The ideal configuration # for desktop printers and/or home users. # Acknowledgement # # Thanks to Jeff Hardy (hardyjm at potsdam dot edu) for writing the # "accsnmp" wrapper backend (http://fritz.potsdam.edu/projects/cupsapps/). # This backend showed me the trick how to write a universal wrapper # backend in a scripting language. use strict; $0 =~ m!^(.*)/([^/]+)\s*$!; my $progname = ($2 || $0); my $progpath = ($1 || "/usr/lib/cups/backend"); if (!$ARGV[0]){ print "network $progname \"Unknown\" \"Backend Error Handler\"\n"; exit 0; } if (scalar(@ARGV) < 5 || scalar(@ARGV) > 6){ print STDERR "ERROR: Usage: $progname job-id user title copies options [file]\n"; exit 1; } my ($jobID, $userName, $jobTitle, $copies, $printOptions, $printFile) = @ARGV; my $tempFile; if (!$printFile) { my $jid = $jobID; my $uid = $userName; $jid =~ s/\W//g; #sanity check $uid =~ s/\W//g; #sanity check my $tmpDir = $ENV{TMPDIR}; $tmpDir ||= "/tmp"; $tempFile = "$tmpDir/$jid-$uid-cupsjob$$"; open (OUT, ">$tempFile") or die "ERROR: Cannot write $tempFile: $!\n"; while(){ print OUT "$_"; } close OUT; $printFile = $tempFile; # Backends should only produce multiple copies if a file name is # supplied (see CUPS Software Programmers Manual) $copies = 1; } my $uri = $ENV{DEVICE_URI}; $uri =~ m!^$progname:/(\d+)/(\d+)/(\d+)/(\S+)$! or die "URI must be \"beh:/
///\"!\n"; my $dontdisable = $1; my $attempts = $2; my $delay = $3; $uri = $4; $uri =~ m!^([^:\s]+):!; my $backend = $1; $ENV{DEVICE_URI} = $uri; # Control by "lpr" command line options, commented out for security # reasons (user could intendedly make queues being disabled) #$printOptions =~ m/\bBackendErrorDisableQueue=(\S*)\b/ && # ($dontdisable = ($1 =~ /no/i ? 1 : 0)); #$printOptions =~ m/\bBackendErrorRetries=(\S*)\b/ && ($attempts = $1); #$printOptions =~ m/\bBackendErrorRetryDelay=(\S*)\b/ && ($delay = $1); #$printOptions =~ m/\bBackendErrorRetryForever=(\S*)\b/ && # ($delay = ($1 =~ /yes/i ? 0 : $delay)); my $exitvalue; while($exitvalue = (($uri !~ m!^file:(.*)$!) && ($uri !~ m!^(/.*)$!) ? system {"$progpath/$backend"} ($uri, $jobID, $userName, $jobTitle, $copies, $printOptions, $printFile) : system ("cat $printFile > $1")) >> 8) { if ($attempts > 0) { $attempts --; last if $attempts == 0; } sleep $delay if $delay > 0; } unlink $tempFile if $tempFile; $exitvalue = 0 if $dontdisable; exit $exitvalue;