I got this interesting question on my blog post ‘Setting up an Epson receipt printer’:
Wondering if you had an idea on how to map a linux device to the netcat command so that I could “convert” the printer to be a local one? -Marco
I have previously written about the opposite use case: How to use a Raspberry Pi as a print server, where I used netcat
to pass data to a local USB printer.
The setup
In this setup, I will assume that you have a working Ethernet printer, which accepts raw data on port 9100.
The aim is to make this appear as a file, so that you can print to it as if it were a local USB printer:
Before you begin
Make sure you have netcat
. It’s not used for the real setup, but you will need it for testing. There are a few versions of this tool around, the one used here is from the Debian repositories:
|
|
Verify that your printer accepts text on port 9100 via netcat
:
|
|
Set up a fake printer on localhost, and leave it running:
|
|
Now, test that your fake printer shows output when you send it:
|
|
Why I’m not using ___
/dev/tcp
If you search for how to redirect data to a TCP socket, a common suggestion is:
|
|
This uses a bash built-in, so unless your use case involves printing from bash, read on.
CUPS
CUPS does not expose the printer as a file, which is the aim here. It also takes a few seconds to print, so we get much faster results if we remove CUPS from the loop and speak to the printer directly.
Use socat to move data
Socat is capable of making a FIFO file (‘pipe’), and writing this out over the network.
|
|
Redirect /tmp/my-printer
to localhost:9100
:
|
|
Next, test that you can see the printer file and write to it. The text sent here should appear on your local netcat “fake printer”:
|
|
This file is a “pipe”, so it behaves very similarly to a character device.
If the connection is dropped, socat will exit, and the file will be deleted.
There are some big problems though:
- If your printer is offline, and you try to print, then data will be left in regular file at “/tmp/my-printer”, which breaks this setup
- This is not a self-restarting service, nor does it start on boot
- Only the user who runs the command can print
Setting this up as a service
The usblp
driver allows anybody from the lp
group to print, so we will try to do something similar, and get a group-writable pipe:
|
|
We don’t need to run socat
as root, so make a new user called fileprint
who is in the lp
group.
|
|
Add yourself to the lp
group as well:
|
|
Next, write this systemd
service file to /etc/systemd/system/fileprint.service
.
|
|
What’s going on here? This service file:
- Runs
socat
as userfileprint
and grouplp
- Manages a runtime directory at
/var/run/fileprint
- Creates a pipe that is group-writeable at
/var/run/fileprint/printer
- Forwards traffic to
127.0.0.1:9100
- Re-starts automatically
Load and start the service:
|
|
Test out printing to your local netcat “fake printer”:
|
|
Note that if you are not in the lp
group (check with groups
command), you should expect a permission error here - just the same as usblp
.
Next, replace 127.0.0.1
with your real printer IP, reload systemd, and restart the service:
|
|
Test it again, and your actual printer should print a line of text this time:
|
|
Finally, enable on boot:
|
|
When the printer is unplugged, the /var/run/fileprint
directory will vanish, so that you can see the missing printer as a “File Not Found” error — just the same as usblp
.
Drawbacks
This will hold a connection open at all times, which (depending on your printer) may prevent other computers from using it.