3

I have a linux (Fedora 22) machine and two thermal printers with a Digitus print server attached to each one. All are on the same LAN. Digitus print servers are each running LPD daemon and each one is configured to offer just one queue: lpd://192.168.1.2/queue and lpd://192.168.1.3/queue

I just want to be able to lpr a file from Fedora to an LPD server using only an LPR client (No full CUPS install). I tried cups-client (dnf install cups-client), which installs lpr binary and I added the remote print servers to my /etc/printcap, but I get Bad file descriptor error whenever I run lpr.

Any ideas?

Paralife
  • 161
  • 1
  • 7

4 Answers4

3

I found a very nice solution: rlpr. (Here is a link for anyone interested.Scroll down to the bottom of the page for rlpr, although all of the entries are old gems)

rlpr does exactly what I need: It talks the LPR protocol directly to the remote LPD daemons without even having to declare the remote printers locally (e.g. /etc/printcap):

rlpr --printer=queue@remotehost file_to_print

I downloaded the tar.gz, configure, make and just used the binary (I didnt even install).

Paralife
  • 161
  • 1
  • 7
3

One thing to remember when using a client-only function like rlpr is that if it is a non-interactive batch process or something similar generating the print request, and there is a network outage between client system and printer/spooler, at best the listing will be lost, and at worst the batch job will fail.

This is one of the reasons for local daemon functions like CUPS/LPRng/classic LPD, where the lpr client actually talks to a local daemon listening to 127.0.0.1:515 or :631, and proxies the request via that daemon: the daemon provides store-and-forward.

No network outage or glitch can possible take down that process. The client submits the print request successfully, it is accepted by that local daemon, and then the lpd/whatever daemon continues trying to forward the listing to its final destination until it achieves success. The listing is not lost, and meanwhile the batch job/whatever continues on successfully.

Whereas with rlpr, if the network glitches - you're out of luck.

It is also an issue if you use the lpr.cups client, but point it directly to a remote print spooler/printer using -H. Failure is non-recoverable.

Not an issue with interactive use, but something to remember with automated processes.

2

RFC 1179 isn't otherwise too hard to write a client for, with most of the work being error checking and getting the input formats right.

#!/usr/bin/perl
# Lobs PostScript at a LPD printer (see RFC 1179). Poorly. Use at own risk,
use strict;
use warnings;
use IO::Socket::INET;
use Sys::Hostname qw(hostname);

my $printer_addr = shift or die "Usage: $0 host [file.ps|-]\n";
my $file         = shift;

my $queue       = "queue";               # may not be needed?
my $client_host = substr hostname(), 0, 31;
my $user        = substr $ENV{USER}, 0, 31;
my $jobnum      = sprintf "%03d", rand 1000;

my $sock = IO::Socket::INET->new(
# if server mandates this, client will need to be run as root,
# or Linux capabilities delved into
#   LocalPort => 721,                    # RFC 1179 sec 3.1
    PeerAddr  => $printer_addr,
    PeerPort  => 515,
    Proto     => 'tcp',
    ReuseAddr => 1,
) or die "$0: could not connect to $printer_addr: $@\n";

# o - Postscript
# f - ASCII
# l - ASCII, leaving control chars
my $control_file = <<"END_CONTROL_FILE";
H$client_host
P$user
odfA$jobnum$client_host
UdfA$jobnum$client_host
END_CONTROL_FILE
my $control_file_size = length $control_file;

my ($data_file_size, $fh);
if (defined $file and $file ne '-') {
    open $fh, '<', $file or die "$0: could not open '$file': $!\n";
    $data_file_size = -s $file;
} else {
    $fh = \*STDIN;
    $data_file_size = 0;
}

sendcmd(sprintf "%c%s\n",    0x02, $queue);

sendcmd(sprintf "%c%u %s\n", 0x02, $control_file_size, "cfA$jobnum$client_host");
$control_file .= "\0";                   # must pad message 
sendcmd($control_file);

sendcmd(sprintf "%c%u %s\n", 0x03, $data_file_size, "dfA$jobnum$client_host");

binmode $fh;
my $buf;
while (1) {
    my $buflen = sysread $fh, $buf, 4096;
    die "sysread() failed: $!\n" if !defined $buflen;
    last if $buflen == 0;                # EOF
    syswrite $sock, $buf, $buflen;
}
syswrite $sock, 0x00, 1 if $data_file_size == 0;

# meh, blocks program when input from STDIN
#my $resp;
#sysread $sock, $resp, 1;
#
#syswrite $sock, 0x00, 1;

sub sendcmd {
    my $cmd = shift;
    my $response;
    syswrite $sock, $cmd, length $cmd;
    sysread $sock, $response, 1;
    chomp $cmd;
    die "$0: unexpected lack of response to '$cmd'\n"
      if !defined $response;
    die sprintf "$0: not-zero response to '$cmd': %vx\n", $response
      if $response ne "\0";
}
thrig
  • 34,333
  • 3
  • 63
  • 84
  • Cool :) I also took a look in the RFC and it is simple. And in my case the printers are zebra thermals, so it is just ZPL text. If i hadnt found rlpr maybe I would pursue it. – Paralife Jan 25 '16 at 23:44
1

Fedora uses CUPS as print server, handling both local and remote printers. As far as I know, there are no native packages which talk the (legacy, deprecated) LP or LPR protocols, and haven't been for quite some time. CUPS is the de facto printing standard nowadays. Search OpenPrinting for suggestions on handling your particular beast.

You might get lucky and grab sources to the relevant clients and servers, and get them to run. Probably not worth it, but hey, it's your time.

Just make sure to add your experiences on success (or not) as an answer here.

vonbrand
  • 18,156
  • 2
  • 37
  • 59
  • Found a solution, see my answer. Btw, I dont think LPR is deprecated practically. I see it a lot on all those print server devices that attach to printers without a network iface. – Paralife Jan 25 '16 at 22:01