Sometimes what should be simple isn't. I wanted a CUPS printer that would just print to a file. Actually, I wanted a bit more than that, but printing to a file was a reasonable start.
What I really wanted to be able to do was examine a print job and then, based on its content, put it into a particular file or perhaps send it on its way somewhere else. The reason for this is that a "printer" is often a convenient and easy abstraction that some other program can use - whether or not that program is on this machine or not. You can do (and I have done) similar things with special email addresses, but printers are often easier (see also Using System V interface scripts with CUPS printing).
So..although the ultimate place this printer would live would be on a RedHat 8.0 system, I initially attempted to configure it on my Mac OS X machine. Why? Well, because my main RedHat machine is a 7.2 box that doesn't use CUPS, and although I have an 8.0 machine, it's dual boot and at the moment it is tied up with a project I'm doing on one of its other OSes. I usually have more than one thing going on at the same time, and it would have been mildly annoying to keep rebooting that as I switched gears. Besides, Mac OS X uses CUPS, so why not?
Small gripe here: aside from the problems I ran into on this, I do like CUPS. It's very flexible, I think it combines the best of SysV and BSD style printing, and I'm sure it will gain ground quickly. However: the documentation bites. Unix documentation is well known for its assumption of prior knowledge, but the CUPS docs take that to a whole new level. In my search for answers to what seemed like simple questions, I kept running into stone walls that had tantalizing hints, but very little real help. The "HowTo" reached from http://www.cups.org is mostly a long winded treatise advising you to read the manual before you dare ask a question on the newsgroup. The "Overview" isn't much help, and either is the FAQ. All very disappointing.
When I have a better handle on this myself I intend to write up something of my own.
One of the really nice things about CUPS is its browser interface. Point your browser at localhost:631 and you have pretty good control of CUPS. It isn't quite as good as you can get at the command line, but it's certainly a heck of a lot better than, for example, what Apple supplies to define and manage printers.
The browser interface certainly makes it seem to be possible to create a simple printer. It even shows the syntax you should use for printing to a file:
file:/path/to/filename.prn
However, if you actually try to use such syntax, it complains "client-error-not-possible". The same thing happens if you try to use lpadmin,
bash-2.05a$ sudo lpadmin -p fprint -E -v /tmp/xx -m raw
lpadmin: add-printer failed: client-error-not-possible
and if you actually manually modify /etc/cups/printers.conf the printer just doesn't work.
Of course, I really didn't want to print to a file anyway. I really want to print to a script. The easy way to do that on System V is to print to a named pipe, and have a program that constantly reads that data, passing it on to a program. Well, it was beginning to look like this just wasn't going to happen with CUPS.
I had already added my Netgear print server to CUPS. That was easy:
sudo lpadmin -p laserjet6L -E -v socket://10.1.36.221:4010 -m laserjet
Since CUPS can very easily print to a network socket, I added a new printer:
sudo lpadmin -p tofile -E -v socket://localhost:12000 -m raw
Now all I needed was a server listening on port 12000. That's easy enough in Perl:
#!/usr/bin/perl
use IO::Socket::INET;
$myport=12000;
$pserve=IO::Socket::INET->new(LocalPort => $myport,Type=>SOCK_STREAM,Reuse=>1,Listen=>1) or die "can't do that $!\n";
while ($pjob=$pserve->accept()) {
open(J,">>/private/tmp/x") or print "having issues $!\n";
print J "New job...\n";
while (<$pjob>) {
print J "$_";
}
close J;
close $pjob;
}
Obviously this is just the shell of what I really want, but it is the basic functionality: anything printed to "tofile" ends up in /tmp/x All I need to do now is write more code, which can be incorporated here or spun off to other programs (see also Using System V interface scripts with CUPS printing).
Enter your email address for automatic notification of new posts here
(be sure to whitelist 'feedburner.com' if you use spam filtering)
| Views for this page | ||||
|---|---|---|---|---|
| Today | This Week | This Month | This Year | Overall |
| 27 | 118 | 165 | 5,582 | 52,099 |
Have you tried Searching this site?
Unix/Linux/Mac OS X support by phone, email or on-site: Support Rates
This is a Unix/Linux resource website. It contains technical articles about Unix, Linux and general computing related subjects, opinion, news, help files, how-to's, tutorials and more. We appreciate comments and article submissions.

I gave this a try, and it works great as far as it goes. For those who haven't tried it, the result is a file containing PDFs of print jobs. The first modification I made was to have the perl script dump each PDF into a new file. I then noticed that the resultant PDFs were not of very high quality. About screen resolution, to my eye, and very hard to read when eventually printed. So I made more modifications to the procedure and am posting them here in case anyone else has had the same problem.
1. Create a new printer using the Printer Setup Utility. Give it the following characteristics:
- "IP Printing"
- Printer Type: "Socket/HP Jet Direct"
- Printer Address: "localhost:12000"
- Queue Name: "localhost:12000"
- Printer Model: "Apple"
- Model Name: "Apple Color LaserWriter 12/600 PS v2014.108"
2. Use the lpadmin utility to fix the URL, since the one the utility creates will be incorrect:
- lpadmin -p localhost:12000 -v socket://localhost:12000/
The jobs coming into the perl script will now be very high quality postscript, easily converted to PDF using any of the standard methods and look much better than the other PDFs did for me.
Thanks for the tip!
MacOSXMacosxcupstofile :
The "client-error-not-possible" when you attempt to add a file printer can possibly be avoided by enabling file printers in cupsd.conf or similar. This enables the printer to be set up and printed to. But mine never actually creates or appends to the specified file, sigh!
This MAY clarify the problem (or not)... an excerpt from the cups manual.
<b>FileDevice</b>
Examples<br/>
FileDevice Yes<br/>
FileDevice No<br/>
Description<br/>
The FileDevice directive determines whether the scheduler allows new printers to be added using device URIs of the form file:/filename. File devices are most often used to test new printer drivers and do no support raw file printing.<br/>
The default setting is No.<br/>
Note:
File devices are managed by the scheduler. Since the scheduler normally runs as the root user, file devices can be used to overwrite system files and potentially gain unauthorized access to the system. If you must create printers using file devices, we recommend that you set the FileDevice directive to Yes for only as long as you need to add the printers to the system, and then reset the directive to No.
Mon Mar 14 21:23:12 2005: Subject: TonyLawrence
Turns out that the easy way to do this is to edit /etc/cups/printers.conf and fix the line with the device to be whatever you want, but tell cups it's parallel:
DeviceURI parallel:/tmp/whatever
Restart cups and all is happy..
To add it that way to start with, use
Tue Mar 29 14:59:15 2005: Subject: anonymous
The parallel way is the best for me, but remember that you must create first
the file,
> /tmp/myfile.prn
chmod a+rw /tmp/myfile.prn
and if cupsd is running with lp user then
chown lp:lp /tmp/myfile.prn
I miss LPRng. (may be better than cups??!)
Wed Jul 27 23:12:22 2005: Subject: This is actually much easier on MacOS than you imply. tlambert
All you need to do is add a new backend type "file" (run these commands as root):
cd /usr/libexec/cups/backend
cat > file
#!/bin/sh
#
# Stupid printer backend that just appends to the file "fee" in /tmp
cat >> /tmp/fee
^D
Then you have to make it executable:
chmod 755 file
Now you want to add a printer that uses this:
cd /etc/cups
cat >> printers.conf
<Printer foofile>
Info foofile
DeviceURI file:/tmp/doesntmatter
State Idle
Accepting Yes
Shared Yes
JobSheets none none
QuotaPeriod 0
PageLimit 0
KLimit 0
</Printer>
^D
Next, kick the cupsd:
killall -1 cupsd
Verify that it's there:
lpstat -p foofile
printer foofile is idle. enabled since Jan 01 00:00
Obviously, you can make the backend do whatever you want it to do. You could also pass it a file name as arguments using "job title" or whatever that CUPS passes to a backend.
-- Terry
Wed Jul 27 23:17:34 2005: Subject: Other example backend code for print-to-file tlambert
Other examples live here:
http://users.phg-online.de/tk/CUPS/backend/
Thu Jul 28 10:57:22 2005: Subject: TonyLawrence
Yes, thank you. There's a reason why "The Hard Way" was part of the title: Cups has very poor documentation and I hadn't grokked the backend concept when I needed this feature.
There are several other articles here dealing with Cups, but I sure wouldn't mind seeing more. It's a good system, but suffers a little from "too much power". You can, of course, bypass all that confusion by using SysV style interface scripts ( http://aplawrence.com/Forum/TonyLawrence11.html ) when you don't need all the other stuff.
Sat Oct 15 22:12:17 2005: Subject: Netcat anonymous
You can use netcat as a socket listener then spool the printer output to the socket on which netcat is listening.
nc -l -p9100 >filename.out
I have found netcat to be very useful in capuring and redirecting print output streams.
Wed Jun 14 14:00:37 2006: Subject: printing to a file from cups YDurant
you could add FileDevice YES to cupsd.conf to allow printing to a file from cups.
Installation and light training Boston and New England
Reliable and experienced, punctual and professional.
Wed Jun 14 14:11:15 2006: Subject: TonyLawrence
Yeah: that's all discussed above.
Wed Jul 2 22:02:34 2008: Subject: SimonBunker
http://rendermania.com
Thanks for writing this. Particularly useful was finding out about the backend filters. They really do make this sort of thing easy. I have used this to create a render farm for rendering 3d animations - the details are here: http://rendermania.com/building-a-renderfarm-with-cups/
Add your comments