How to access a raw network printer as a file on Linux

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.

diagram

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:

diagram2

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:

apt-get install netcat

Verify that your printer accepts text on port 9100 via netcat:

echo "Hello world" | nc -q 1 192.168.x.y 9100

Set up a fake printer on localhost, and leave it running:

nc -klp 9100

Now, test that your fake printer shows output when you send it:

echo "Hello world" | nc -q 1 127.0.0.1 9100

Why I’m not using..

/dev/tcp

If you search for how to redirect data to a TCP socket, a common suggestion is:

echo "Hello world" > /dev/tcp/127.0.0.1/9100

This is 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.

apt-get install socat

Redirect /tmp/my-printer to localhost:9100:

socat PIPE:/tmp/my-printer TCP:localhost:9100

Next, test that you can see the printer file and write to it. This line should appear on your local netcat “fake printer”:

echo "Hello world" > /tmp/my-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, you will create a regular file at “/tmp/my-printer”, breaking it.
  • 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 proper 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:

$ ls /dev/usb/lp0  -Ahl
crw-rw---- 1 root lp 180, 0 Jun 12 12:51 /dev/usb/lp0

We don’t need to run socat as root, so make a new user called fileprint who is in the lp group.

useradd --groups lp fileprint

Add yourself to the lp group as well:

usermod -a -G lp mike

Next, write this systemd service file to /etc/systemd/system/fileprint.service

[Unit]
Description=fileprint
After=network.target

[Service]
User=fileprint
Group=lp
ExecStartPre=/usr/bin/mkfifo -m '0664' /var/run/fileprint/printer
ExecStart=/usr/bin/socat PIPE:/var/run/fileprint/printer TCP:127.0.0.1:9100
Restart=always
RuntimeDirectory=fileprint

What’s going on here?

  • Runs as user fileprint and group lp
  • 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:

systemctl daemon-reload
systemctl start fileprint
systemctl status fileprint

Test out printing to your local netcat “fake printer”:

echo "Test" > /var/run/fileprint/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:

nano /etc/systemd/system/fileprint.service
systemctl daemon-reload
systemctl restart fileprint
systemctl status fileprint

Test it again, and your actual printer should print a line of text this time:

echo "Test" > /var/run/fileprint/printer

Finally, enable on boot:

systemctl enable fileprint

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.

Leave a Reply

Your email address will not be published. Required fields are marked *