Setting up CUPS to spool to a file

pipitas k1pfeifle at
Thu Oct 14 16:50:45 PDT 2004

Kirk Haderlie wrote:

> Is it possible to set CUPS up to spool to a file instead of send the
> output to the printer?  We have a RIP product we would like to run the
> file through and have that that application send the final output to the
> printer.  We could write a filter to achieve this, but if CUPS can
> already spool the file to disk it would be nice to use that.
> The workflow would be CUPS -> File -> RIP -> Printer.

You can enable a very simple file:/ backend by putting "FileDevice 
Yes" into cupsd.conf. However it will not allow raw printing of
application/octet-stream files. And the second job will overwrite
the first one (because you need to give a filename to the backend,
in the device URI, like "file:/tmp/print.prn")

You could write your own CUPS backend. Here are the rules for 

* make sure it can read from SDIN and write to STDOUT

* make sure if called with zero arguments it responds with
  a message similar to the other backends (see how they do it)

* make sure it takes the 5 or 6 arguments all CUPS filters and
  backends take in the same order, i.e. 
      backendname job-id user title copies options [job-file]

* put it into /usr/lib/cups/backend/ and restart cupsd (check
  if it is recognized with "lpinfo -v")

You can write it in Bash, Perl, C, Python or whatever you like.

A very simple "filewrite" backend looks like this:

if [ $# -eq 0 ]; then
   echo "direct filewrite \"Unknown\" \"Print any job to file specified in device-URI\""
   exit 0
cat $6 > $TARGETFILE

A more advanced one is here:

--- snip --------------------------------------------------------------------
# (c) Kurt Pfeifle, Danka Deutschland GmbH
# This simple CUPS backend allows you to "print to file". Install a
# printer like this:
#   cp <this.file> /usr/lib/cups/backend/filewrite;
#   chmod a+x /usr/lib/cups/backend/filewrite;
#   /etc/init.d/cups stop;
#   /etc/init.d/cups start;
#   lpadmin -p fileprinter -v filewrite:/tmp/my_print_testfile.prn -E -P /path/to/PPD
#   (you can leave aside the "-P" option to create a "raw" printqueue without filtering)
# If you print to the new "fileprinter" printer, you will find the files your
# CUPS filtering produced in "tmp/my_print_testfile.prn".
# The filewrite backend is useful for debugging purpuses....

# test for 5 or 6 parameters
FILE=$6 || FILE="-";

LOG=/tmp/filewrite.log; export LOG ;
JOBID=$1 ;
USER=$2 ;
TITLE=$3 ;
PID=$$ ;
echo ${FILE}    >> ${LOG} ;
echo ${JOBID}   >> ${LOG} ;
echo ${USER}    >> ${LOG} ;
echo ${TITLE}   >> ${LOG} ;
echo ${COPIES}  >> ${LOG} ;
echo ${OPTIONS} >> ${LOG} ;

# if there are no arguments: print the "I'm here" message for cupsd's probing
if [ $# -eq 0 ]; then
   echo "direct filewrite \"Unknown\" \"Print any job to file specified in device-URI\""
   exit 0

# in case of wrong number of arguments: print usage hint
if [ $# -ne 5 -a $# -ne 6 ]; then
   echo ""
   echo "Usage: filewrite job-id user title copies options [file]"
   echo "       example for device-URI: 'filewrite:/path/to/targetfile'"
   echo "(this writes the printfile to disk at specified path)"
   echo ""
   echo "Install a printqueue with 'lpadmin -p <filewriter-printer-name> \
-v filewrite:/</path/to/targetfile> -E [-P /path/to/PPD]"
   echo ""
   exit 1

# sanitize $TITLE -- remove any spaces, colons and slashes or
# backslashes from filename
TITLE=`echo ${TITLE} | tr [:blank:] _ | tr : _ | tr / _ |  tr "\134" _`;
# we should now have a sanitized ${TITLE} to use with less danger of 
# screwing things up should we print from a browser or some such....

# get file to which the job is "printed" from device URI, so
# so that you can use this backend multiple times, for various
# "filewrite" printers...

### uncomment&modify the following line if you need the JOBTITLE, 
### USERNAME, JOBID, DATE as part of the filename...

# but check "accepting" status first...
GREPSTRING="not accepting" ;
if  lpstat -a $TARGETFILE | grep "$GREPSTRING" &> /dev/null ; then
        echo "ERROR: printer $TARGETFILE not accepting jobssss...."
        exit 1

# now do the job....

# just to show you how cupsd logs stuff....
echo "INFO: just a dummy string for the logfile....">&2
echo "ERROR: another dummy string for the logfile....">&2

exit 0
---- snap -------------------------------------------------------------------

A more advanced "dirwrite" would write into a target directory
that you specify as a device URI like here "dir:/tmp/cupsfiles/"

The magic line for this would be to use


You could also write a "postprocess" backend which would basically
consist of an outgoing pipe that directly inputs the CUPS output
to another command (which of course must take input from STDIN),
with the "magic line":

  cat $6 | TARGETPROG -

where your backend uses

  device-URI  postproc:/path/to/your/program

Hope this helps,

More information about the cups mailing list