[net.bugs.4bsd] Line printer bug and some bonus features

jim@mit-athena.UUCP (Jim Fulton) (02/26/85)

[Go ahead, make my day.]

There is a slight problem in the line printer spooling software that will
bite you if you use remote printers and accidently include an output filter
(OF) in the /etc/printcap.  Lpd will start up a filter even if it is sending
the file to be printed on a remote machine (note that it doesn't even use the
filter in sending).  Thus, the filter ends up sitting around forever, 
preventing the local lpd from telling the remote lpd to look in its queues for
jobs to print.

Now, for those who would answer "don't be stupid and list an output filter
if you are sending to a remote machine", think about what happens when someone
makes a mistake.  Perhaps, but it would be nice if "mistakes" like this
(I argue that since the OF isn't used, it shouldn't matter).  Besides, it 
would be nicer to list both remote and local info and have the printing 
software figure out what to use (see below).

The problem is in the routine openpr() in printjob.c and the fix is fairly 
easy to make.  Move the if block 

/*
 * Start up an output filter, if needed.
 */
    if (OF) {
	...
    }


inside the "if (*LP) { ... }" block that does processing if the printer is
attached to this machine so that it comes after the 

	status ("%s is ready and printing", printer);

line.  Now, you only get filters started up if they are actually going to
be used.


While I'm at it, here is another useful thing.  Having to keep different 
printcap files (or even entries) for machines with printers attached and 
machines without printers is a REAL pain in the neck.  If you insert the 
following code into init() in printjob.c and displayq() in displayq.c 
after the line

	RM = pgetstr("rm", &bp);

then you can include entries in the printcap for both local and remote
hosts (i.e. lp= and rp=/rm=):

	/*
	 * Figure out whether the local machine is the same as the remote 
	 * machine entry (if it exists).  If not, then ignore the local
	 * queue information.
	 */

	 if (RM != (char *) NULL) {

		char name[255];
		struct hostent *hp;

			/* get the name of the local host */
		gethostname (name, sizeof(name) - 1);
		name[sizeof(name)-1] = '\0';

			/* get the network standard name of the local host */
		hp = gethostbyname (name);
		if (hp == (struct hostent *) NULL) {
		    printf ("unable to get hostname for local machine %s\n",
				name);
		    goto localcheck_done;
		} else strcpy (name, hp->h_name);

			/* get the network standard name of RM */
		hp = gethostbyname (RM);
		if (hp == (struct hostent *) NULL) {
		    printf ("unable to get hostname for remote machine %s\n",
		    		RM);
		    goto localcheck_done;
		}

			/* if printer is not on local machine, ignore LP */
		if (strcmp (name, hp->h_name) != 0) *LP = '\0';
	}

    localcheck_done:

I apologize if I've forgotten anything.  This code has been running here at 
Athena for awhile on a network with almost 2 dozen printers and over 50
vaxen and has been incredibly useful.  We now have one 
printcap file for all of our machines.  For those who are interested, local 
aliases for printer names (i.e. lpr -Plaser where laser means the laser 
printer in the cluster nearest me) are provided using a cluster information 
database that I will probably post to the net after I've released it here.


	Jim Fulton			arpa:  jim%mit-athena@mit-mc.ARPA
	MIT Project Athena		uucp:  decvax!mit-athena!jim