v23i076: Feed multiple printers from one BSD lpr queue

Rich Salz rsalz at bbn.com
Thu Dec 6 04:27:42 AEST 1990


Submitted-by: matt robinson <yakker at ucrmath.ucr.edu>
Posting-number: Volume 23, Issue 76
Archive-name: mlpd

[ I have not tested this as I don't run LDP.  --r$ ]

This program (MLPD) is a little piece of code I wrote to use a single
printer queue for a set of multiple printers.  It's kind of wierd to
set up, but once it is running, it should help out a lot.

The program runs under a Sun OS environment.  It has been tried out
under 4.1 SunOS, and I had it tried out under a 4.3 BSD environment,
thanks to the help of nash at ucselx.sdsu.edu (Thanks, Ron!) I hope that 
it works for you.  Please send me all bug reports, special things that
would make your life easier, etc., so on, so forth.  If you do have any
questions at all, please mail me to let me know about what you need.

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix at uunet.uu.net if you want that tool.
# Contents:  COPYRIGHT Makefile README config.h daemon.c lock.c mlp.c
#   mlpd.8 pfile.c printcap.c printer.c
# Wrapped by rsalz at litchi.bbn.com on Wed Dec  5 12:24:56 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive."'
if test -f 'COPYRIGHT' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'COPYRIGHT'\"
else
  echo shar: Extracting \"'COPYRIGHT'\" \(1054 characters\)
  sed "s/^X//" >'COPYRIGHT' <<'END_OF_FILE'
X/*
X * Copyright (c) 1990 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Riverside. 
X *
X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
X *        Irvine.  Riverside.  Ri - ver - side.
X *
X * The name of the University may not be used to endorse or promote 
X * products derived from this software without specific prior written
X * permission.
X *
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X * 
X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
X * SCCS keywords: @(#)COPYRIGHT	1.3 12/1/90
X */
X
END_OF_FILE
  if test 1054 -ne `wc -c <'COPYRIGHT'`; then
    echo shar: \"'COPYRIGHT'\" unpacked with wrong size!
  fi
  # end of 'COPYRIGHT'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
  echo shar: Extracting \"'Makefile'\" \(1775 characters\)
  sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#
X# Copyright (c) 1990 Regents of the University of California.
X# All rights reserved.
X#
X# Redistribution and use in source and binary forms are permitted
X# provided that the above copyright notice and this paragraph are
X# duplicated in all such forms and that any documentation,
X# advertising materials, and other materials related to such
X# distribution and use acknowledge that the software was developed
X# by the University of California, Riverside. 
X#
X# NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
X#        Irvine.  Riverside.  Ri - ver - side.
X#
X# The name of the University may not be used to endorse or promote 
X# products derived from this software without specific prior written
X# permission.
X#
X# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X# 
X# MLPD -- Multiple Line Printer Daemon (Version 1.3)
X# SCCS keywords: @(#)Makefile	1.3 12/1/90
X#
X
X#
X# Note : Make sure to look in config.h for other parameters.
X#
X
X# Include this line if you are running under the Sun OS environment.
X# It is designed basically to change from using <sys/dir.h> to using
X# <dirent.h>, because of the System V compatibility.
X#
X# The debug flag is also specified because of some people's desire to
X# take a small peek at what is going on.  You can use it, but it is
X# very noisy, and shouldn't be used when running normally.
X#
XEXTRA_FLAGS  = -DSUN #-DDEBUG -g
X#
X# And now, the rest of the story.
X#
XOBJS         =  daemon.o lock.o pfile.o mlp.o printcap.o printer.o
XPROG         =  mlpd
XCC           =  cc
XCFLAGS       =  -c $(EXTRA_FLAGS)
X
X$(PROG) : $(OBJS)
X	$(CC) -o $(PROG) $(OBJS)
X
Xclean	:
X	/bin/rm -f *.o $(PROG)
END_OF_FILE
  if test 1775 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
  fi
  # end of 'Makefile'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
  echo shar: Extracting \"'README'\" \(4085 characters\)
  sed "s/^X//" >'README' <<'END_OF_FILE'
X/*
X * Copyright (c) 1990 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Riverside. 
X *
X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
X *        Irvine.  Riverside.  Ri - ver - side.
X *
X * The name of the University may not be used to endorse or promote 
X * products derived from this software without specific prior written
X * permission.
X *
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X * 
X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
X * SCCS keywords: @(#)README	1.3 12/1/90
X */
X
XNOTE:  This program is in its first testing stages.  If I send it out,
X       and people like it, I'll post it to the USENET network.  If
X       not, I'll just put it on a resume.  This is the first version,
X       and I have already started working on a new version that has
X       many more features, all that remain very simplistic to the
X       user, which is my main objective.
X
X
XNow on with the real important stuff:
X
X
XThis program (MLPD) is a little piece of code I wrote to use a single
Xprinter queue for a set of multiple printers.  It's kind of wierd to
Xset up, but once it is running, it should help out a lot.
X
XHere are the steps for a clean configuration, in proper order :
X---------------------------------------------------------------
X
X1.  Edit Makefile to your particular system and needs.  If you are running
X    under a SunOS environment, you need to define -DSUN, and if you want
X    to print out hari-kari debug messages, you need to specify -DDEBUG.
X
X2.  Compile the program, or get it operational. (Whichever comes first.)
X
X3.  Turn off the printing to the base printer that your employees, friends,
X    or students print to, and turn off queueing on the other printers.  For
X    example, 'lp' is your base printer (Where most people type in 'lpr'),
X    and your other printers are the real printers that will be doing the
X    actual printing (like 'lp1', 'lp2', etc.)
X
X4.  Make sure all of the printers are properly set up in the /etc/printcap
X    so that the printers can run smoothly.  Make sure that your main
X    printer ('lp' is your main printer, from #3.) doesn't do any printing
X    and that your other printers area actually connected to the devices.
X
X5.  Try it out!  The command to start off the program is :
X
X    mlpd -p [<base printer> <printer1> <printer2> ...] [-t <timeout>]
X
X    For example, a command line following #3 and #4 would be:
X
X    mlpd -p lp lp1 lp2 -t 5
X
X    In this example, the main queueing printer is lp, the other printers
X    are lp1 and lp2, and the timeout to check for a print job is 5 seconds.
X 
X6.  If it works, try to set it up in your rc.local to start up when you 
X    start up your system.  Make sure, however, that you put the mlpd entry
X    after starting up lpd.  Otherwise, mlpd will not function.
X
XThe program runs under a Sun OS environment.  It has been tried out
Xunder 4.1 SunOS, and I had it tried out under a 4.3 BSD environment,
Xthanks to the help of nash at ucselx.sdsu.edu (Thanks, Ron!) I hope that 
Xit works for you.  Please send me all bug reports, special things that
Xwould make your life easier, etc., so on, so forth.  If you do have any
Xquestions at all, please mail me to let me know about what you need.
XI'll be out with a manual page soon enough.  (Gotta learn a bit about
Xnroff...Too much TeX and LaTeX.)
X
X--Matt
X
X____________________________________________________________________________
XMatt D. Robinson                            Internet: yakker at ucrmath.ucr.edu
XSystems Programming Group, UC Riverside         UUCP: ..!ucsd!ucrmath!yakker
END_OF_FILE
  if test 4085 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
  fi
  # end of 'README'
fi
if test -f 'config.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'config.h'\"
else
  echo shar: Extracting \"'config.h'\" \(1824 characters\)
  sed "s/^X//" >'config.h' <<'END_OF_FILE'
X/*
X * Copyright (c) 1990 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Riverside. 
X *
X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
X *        Irvine.  Riverside.  Ri - ver - side.
X *
X * The name of the University may not be used to endorse or promote 
X * products derived from this software without specific prior written
X * permission.
X *
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X * 
X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
X * SCCS keywords: @(#)config.h	1.3 12/1/90
X */
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/un.h>
X#include <sys/param.h>
X#include <sys/ioctl.h>
X#include <sys/time.h>
X#include <sys/wait.h>
X#include <sys/stat.h>
X#include <syslog.h>
X#include <time.h>
X#ifdef SUN
X#include <dirent.h>
X#else
X#include <sys/dir.h>
X#endif
X#include <stdio.h>
X#include <ctype.h>
X#include <errno.h>
X
X#define TRUE                 1
X#define FALSE                0
X#ifdef DEBUG
X#define debug(x) fprintf(stderr, "%s", (x))
X#else
X#define debug(x) fprintf(stderr, "%s", "")
X#endif
X
Xtypedef struct 
X{
X	char *name[512];
X	char *directory[512];
X} printerstruct;
X
Xextern char *LP_SPOOL_DIRECTORY;
Xextern int  TIMEOUT;
X
Xint init_daemon();
Xint lock_printer();
Xint bomb();
Xint check_prs();
Xint check_base_printer();
Xvoid exit();
Xchar *malloc();
END_OF_FILE
  if test 1824 -ne `wc -c <'config.h'`; then
    echo shar: \"'config.h'\" unpacked with wrong size!
  fi
  # end of 'config.h'
fi
if test -f 'daemon.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'daemon.c'\"
else
  echo shar: Extracting \"'daemon.c'\" \(3479 characters\)
  sed "s/^X//" >'daemon.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1990 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Riverside. 
X *
X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
X *        Irvine.  Riverside.  Ri - ver - side.
X *
X * The name of the University may not be used to endorse or promote 
X * products derived from this software without specific prior written
X * permission.
X *
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X * 
X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
X * SCCS keywords: @(#)daemon.c	1.3 12/1/90
X */
X
X#include "config.h"
X
X/*
X// (int) init_daemon() -- Initialize a process as a daemon process.
X//
X// This function will start off by forking a process off from the
X// parent, and give control over to the child by opening up the
X// root directory, duplicating stdout and stderr for the child,
X// and release the terminal control for the main terminal.
X// The program also calls lock_printer() after the fork(), so that
X// the child process is saved into a file when the status of the 
X// program needs to be checked.
X//
X// Arguments : None
X*/
Xint init_daemon(base)
Xchar *base;
X{
X	int pid;
X
X	/*
X	// Fork off a process.
X	*/
X	if ((pid = fork()) < 0)
X	{
X		bomb("fork");
X	}
X	/*
X	// First we will check in on the parent, and get rid of it.
X	*/
X	if (pid)
X	{
X		exit(0);
X	}
X	/*
X	// Now we specifically want all of the code in the child.
X	// We try to lock down the printer daemon by creating a lock
X	// file.
X	*/
X	if (lock_printer(base) < 0)
X	{
X		bomb("lock_printer");
X	}
X	/*
X	// Well, if this returns, then we must start closing off the
X	// terminal control.  We call open(), then dup2() for stdout
X	// and stderr, then we try to call setpgrp on the process to
X	// put itself into the background.  Only the ioctl call will
X	// release control from the terminal.  Then we close the de-
X	// scriptor created by the second open() call.
X	*/
X	if (open("/", 0) < 0) { bomb("open"); }
X	if (dup2(0, 1) < 0) { bomb("dup2:stdout"); }
X	if (dup2(0, 2) < 0) { bomb("dup2:stderr"); }
X	if (setpgrp(0, getpid()) < 0) { bomb("setpgrp"); }
X	/*
X	// Well, everything must have worked correctly, so we will default
X	// back to the parent.
X	*/
X}
X
X/*
X// (int) bomb() -- Display an error message, then exit.
X//
X// bomb() simply will call perror() and send the function call a string
X// declaring the error to be displayed to the user.  Once this returns
X// we can then call exit().
X//
X// Arguments : char *str (The string message to be displayed)
X*/
Xint bomb(str)
Xchar *str;
X{
X	char buf[1024];
X	time_t now;
X	struct tm *nowtime;
X
X
X	buf[0] = '\0';
X	(void)perror(str);
X	now = (time_t)time();
X	nowtime = localtime(&now);
X	(void)sprintf(buf, "Date: (%d/%d/%d)\n\
X		Time: (%d:%d:%d)\n\
X		Message: Process died from error message (%s)\n\n", 
X		nowtime->tm_mon, nowtime->tm_mday, nowtime->tm_year, 
X		nowtime->tm_hour, nowtime->tm_min, nowtime->tm_sec, 
X		str);
X	(void)openlog("mlpd", LOG_PID, LOG_LPR);
X	(void)syslog(LOG_ERR, buf);
X	(void)closelog();
X	(void)exit(1);
X}
END_OF_FILE
  if test 3479 -ne `wc -c <'daemon.c'`; then
    echo shar: \"'daemon.c'\" unpacked with wrong size!
  fi
  # end of 'daemon.c'
fi
if test -f 'lock.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lock.c'\"
else
  echo shar: Extracting \"'lock.c'\" \(3637 characters\)
  sed "s/^X//" >'lock.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1990 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Riverside. 
X *
X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
X *        Irvine.  Riverside.  Ri - ver - side.
X *
X * The name of the University may not be used to endorse or promote 
X * products derived from this software without specific prior written
X * permission.
X *
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X * 
X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
X * SCCS keywords: @(#)lock.c	1.3 12/1/90
X */
X
X#include "config.h"
X
X/*
X// lock_printer() -- Lock up the printer daemon for once per machine.
X// 
X// The lock_printer() process will try to save the pid of the process
X// that is about to run to a file, to reference later when we need to
X// check to see if the program is running (We do not want to let the
X// program run more than once per machine.)
X//
X// Arguments : None
X*/
Xint lock_printer(base)
Xchar *base;
X{
X	FILE *fp, *fopen();
X	void exit();
X	char buf[1024];
X	int pid;
X
X	/*
X	// First we will try to fopen() the file.  If we can't get
X	// the file open, we have to assume that either the file has
X	// been moved, or the program has been recompiled and there
X	// is a new lock file directory.  If we can fopen() it,
X	// we will run through this [if..then] loop and handle the
X	// conditions.
X	*/
X	buf[0] = '\0';
X	(void)sprintf(buf, "/etc/mlpd.%s.pid", base);
X	if ((fp = fopen(buf, "r")) != NULL)
X	{
X		/*
X		// Try to read the number from the file.
X		*/
X		if (fscanf(fp, "%d", &pid) < 0)
X		{
X			perror("lock_printer:fscanf:fopen");
X			exit(-1);
X		}
X		/*
X		// If we can read the number, then we need to see whether
X		// the process still exists.  If it does, then we want to
X		// Just exit out, and tell the user that the program is 
X		// still running; otherwise, we need to clean up the file
X		// that exists in the directory, and create the file showing
X		// the new PID in the file.
X		*/
X		if (getpgrp(pid) >= 0)
X		{
X			if (fprintf(stderr, "This program is already running \
X					(PID# : %d)\n", pid) < 0)
X			{
X				bomb("lock_printer");
X			}
X			exit(1);
X		}
X	}
X	/*
X	// If we got to this point in the code, then either there wasn't a
X	// lock file in the directory, or the process which was running
X	// died off.  In either case, remove the file that we found, if
X	// there.
X	*/
X	if (unlink(buf) < 0)
X	{
X		/* 
X		// Do nothing.  We want to try to remove the 
X		// file no matter what.
X		*/
X	}
X	/*
X	// Now we want to try and fopen the file for writing.  This is
X	// to place the present getpid() into the file for reference
X	// later.
X	*/
X	if ((fp = fopen(buf, "w")) == NULL)
X	{
X		bomb("lock_printer:/etc/mlpd.pid:fopen");
X	}
X	/*
X	// Try to fprintf() the getpid() return value into the file.
X	*/
X	if (fprintf(fp, "%d", getpid()) < 0)
X	{
X		bomb("lock_printer:fprintf");
X	}
X	/*
X	// If we get here, all we have to do is close the file, and
X	// go back to the init_daemon() process.
X	*/
X	if (fclose(fp) < 0)
X	{
X		bomb("lock_printer:fclose");
X	}
X	/*
X	// Well, everything must have worked, so we'll just head back and
X	// tell the calling program that everything is okay.
X	*/
X	return 1;
X}
END_OF_FILE
  if test 3637 -ne `wc -c <'lock.c'`; then
    echo shar: \"'lock.c'\" unpacked with wrong size!
  fi
  # end of 'lock.c'
fi
if test -f 'mlp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mlp.c'\"
else
  echo shar: Extracting \"'mlp.c'\" \(4126 characters\)
  sed "s/^X//" >'mlp.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1990 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Riverside. 
X *
X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
X *        Irvine.  Riverside.  Ri - ver - side.
X *
X * The name of the University may not be used to endorse or promote 
X * products derived from this software without specific prior written
X * permission.
X *
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X * 
X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
X * SCCS keywords: @(#)mlp.c	1.3 12/1/90
X */
X
X#include "config.h"
Xchar *LP_SPOOL_DIRECTORY;
Xint  TIMEOUT;
Xint  errno;
X
X/*
X// main() -- The main program.
X//
X// This will start off looking to create the printer structure,
X// initialize the process so that it is running as a daemon,
X// find the total number of printers to check, and start up a
X// select/test loop that looks for print jobs in the main queue
X// and moves/prints the new files in new queues.
X//
X// Arguments : None
X*/
Xint main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int count, clt, nready, pready, no_of_printers;
X	struct timeval timeout;
X	printerstruct *printers;
X#ifndef lint
X	FILE *myfp, *fopen();
X#endif
X	int fprintf();
X	int write();
X	void exit();
X
X	/* 
X	// First, initialize the printer structure.
X	*/
X#ifdef lint
X	printers = NULL;
X#else
X	printers = (printerstruct *) malloc(sizeof(printerstruct));
X#endif
X	/*
X	// Next, parse through all of the arguments to find information
X	// that we need, and set all variables necessary.
X	*/
X	no_of_printers = parse_arguments(argc, argv, printers);
X	/* 
X	// Set the timeout values for the select process to be 2 seconds,
X	// which keeps the CPU usage down.
X	*/
X	timeout.tv_sec = 2;
X	timeout.tv_usec = 0;
X	count = 0;
X	while(TRUE)
X	{
X		/*
X		// Do a select() for about 2 seconds on nothing, so that
X		// all we do is a time wait without causing a lot of CPU
X		// usage.  I'm hoping that this isn't too much bother for
X		// the users.  
X		*/
X		if (count == 0)
X		{
X			(void)restart_all_printers(no_of_printers, printers);
X			/* 
X			// (15 * 2 seconds) + 2 seconds;
X			*/
X			count = 16;            
X		}
X		--count;
X		if ((nready = select((int) 0, (fd_set *) NULL, (fd_set *) NULL, 
X			(fd_set *) NULL, (struct timeval *) &timeout)) < 0)
X		{
X			if (errno != EINTR)
X			{
X				bomb("select");
X			}
X			else
X			{
X				nready = 0;
X			}
X		}
X		/*
X		// Well, from here, we want to go through the printers
X		// to make sure we either don't have anything to print,
X		// or all of the printers are busy.  We check the base
X		// printer (Which ever one that is), and see if it has
X		// any files to print.  If it does, then we want to print
X		// out the file to one of the other printers, if any
X		// of them are available.
X		*/
X		pready = 0;
X		while ((nready == 0) && 
X			(check_base_printer() > 0) &&
X			(pready == 0))
X		{
X			debug("Found a file to print.\n");
X			/*
X			// Begin to check through the list of printers
X			// and see if we have one free.  If we do, print
X			// to that printer, otherwise, skip it.  We do 
X			// NOT want to queue files on printers...We want
X			// to maintain one queue.  (See README).
X			*/
X			for (clt = 0; clt < no_of_printers; ++clt)
X			{
X				/*
X				// This checks to see if the printer is
X				// available to print on.
X				*/
X				if ((pready = check_prs(printers, clt)) < 0)
X				{
X					bomb("check_prs");
X				}
X				else if (pready == 0)
X				{
X					debug("I can print out a file.\n");
X					/*
X					// If we get here, we can print
X					// out a file on this printer.
X					*/
X					if (print_file(printers, clt) < 0)
X					{
X						bomb("print_file");
X					}
X					clt = no_of_printers;
X				}
X			}
X		}
X	}
X}
END_OF_FILE
  if test 4126 -ne `wc -c <'mlp.c'`; then
    echo shar: \"'mlp.c'\" unpacked with wrong size!
  fi
  # end of 'mlp.c'
fi
if test -f 'mlpd.8' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mlpd.8'\"
else
  echo shar: Extracting \"'mlpd.8'\" \(3786 characters\)
  sed "s/^X//" >'mlpd.8' <<'END_OF_FILE'
X.\" Copyright (c) 1983 Regents of the University of California.
X.\" All rights reserved.  The Berkeley software License Agreement
X.\" specifies the terms and conditions for redistribution.
X.\"
X.\" @(#)mlpd.8 1.3 12/1/90; from UCR SunOS 4.1
X.\"
X.TH MLPD 8 "8 November 1990"
X.SH NAME
Xmlpd \- multiple line printer daemon
X.SH SYNOPSIS
X
X.B mlpd 
X[
X.B \-p <base pr> <pr1> <pr2> ...
X] [
X.B \-t <timeout>
X]
X.SH DESCRIPTION
X
X.LP
X.B mlpd 
Xis a multiple line printer daemon, which is set up in your
Xrc.local (read the manual on rc (8)) script, which will monitor files
Xbeing printed on your system.  mlpd will look in the base printer
Xdirectory for files, try to find jobs that need to be printed, and
Xtake those jobs and move them to any available printers.  Printer jobs
Xno longer have to wait for a larger job in front of them.  This allows
Xfor optimization in printing files to any number of printers.
X
X.SH OPTIONS
X
X.LP
X.SS \-p <base pr> <pr1> <pr2> ...
X
X.LP
XSpecifies the printers to print on.  For example, if lp is the 
Xnormal line printer to queue to, and the real printers are connected
Xlp1 and lp2, then I would specify
X.B \-p lp lp1 lp2
Xas my print options.  The super-user can specify any number of printers 
Xfrom the command line.  The program will look up these printers in 
X/etc/printcap entry to verify their existance, and use their 
Xspooling directories as the directories to queue in.  If the printers 
Xare not in /etc/printcap, or the proper spooling directories do not 
Xexist, then the program will exit and log all information to syslog().
X.LP
X.SS \-t <timeout>
X
X.LP
XSpecifies the amount of time to wait before checking the base printer
Xqueue.  Normally this time is set to 2 seconds, but the user can specify
Xwhat they wish.  It is normally suggested to let the default remain intact,
Xas the program will run better under this environment.
X.SH OPERATION
X.SS Operation/Syntax of Program
X.LP
XThe program runs by first trying to check all of the command line arguments,
Xand setting all of the proper printing options.  Once it knows where each
Xprinter queueing directory is, it then goes out and starts into a loop,
Xwhere is calls select() for a period of seconds equal to that specified on
Xthe command line, or a default of 2 seconds.  After the timeout has occurred,
Xthe daemon will go out and look for jobs in the base printer queue.  If
Xit finds any jobs, it will then check to see if any of the printers specified
Xare available for printing.  If one of the printers is free to print, it
Xwill send that printer the print job first available.  It will continue to
Xdo this until either there are no more jobs in the printer queue, or all 
Xof the printers are busy.  Every 30 seconds, the printers are restarted
Xagain, in case any printer files become jammed for some reason.  Should
Xthe super-user want to kill off the program, there will be a lock file in
X/etc with the name "mlpd.<base pr>.pid", which will contain the PID of 
Xthe daemon running.
X
X.SH "SEE ALSO"
X.BR lpq (1),
X.BR lpr (1),
X.BR lprm (1),
X.BR hosts (5),
X.BR hosts.equiv (5),
X.BR printcap (5),
X.BR lpc (8),
X.BR pac (8)
X.SH BUGS
X
XThe program can only allow for 512 printers.  If you can edit the code,
Xyou can raise this amount, but I really didn't imagine someone trying
Xto watch over more than 512 printers.
X
XIf you start up mlpd before starting up lpd in rc.local, the program 
Xwill exit, because it was not able to connect to the lpd device.
X
XThe timeout value is set to 2 seconds, so if this begins to slow your
Xsystem down, increase this value.  I would not suggest lowering it.
X
XIf you find something else wrong with it, please let me know.  I'm ever
Xwilling to fix anything wrong with it, add new functionality, and so forth.
XContact yakker at ucrmath.ucr.edu for any other information, bug reports, etc.
END_OF_FILE
  if test 3786 -ne `wc -c <'mlpd.8'`; then
    echo shar: \"'mlpd.8'\" unpacked with wrong size!
  fi
  # end of 'mlpd.8'
fi
if test -f 'pfile.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pfile.c'\"
else
  echo shar: Extracting \"'pfile.c'\" \(4610 characters\)
  sed "s/^X//" >'pfile.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1990 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Riverside. 
X *
X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
X *        Irvine.  Riverside.  Ri - ver - side.
X *
X * The name of the University may not be used to endorse or promote 
X * products derived from this software without specific prior written
X * permission.
X *
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X * 
X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
X * SCCS keywords: @(#)pfile.c	1.3 12/1/90
X */
X
X#include "config.h"
Xextern char *LP_SPOOL_DIRECTORY; 
Xextern int TIMEOUT;
X
X/*
X// parse_arguments() -- Get printer information from argv.
X//
X// This function when called will return a structure containing
X// the printers and their respective spooling directories in
X// a structure.  
X//
X// Arguments : printerstruct *printers (The printer structure)
X*/
Xint parse_arguments(argc, argv, printers)
Xint argc;
Xchar *argv[];
Xprinterstruct *printers;
X{
X	int i, origargc;
X	int no_of_printers, ncnt, can_exit;
X	char base[1024];
X	
X	can_exit = FALSE;
X	i = 0;
X	origargc = argc;
X	if (argc < 5)
X	{
X		usage(argv[0], "Not enough arguments.\n");
X	}
X	while (--argc)
X	{
X		if (!strcmp("-t", argv[i]))
X		{
X			if ((atoi(argv[i+1])) && (i+1 != argc))
X			{
X				TIMEOUT = atoi(argv[i + 1]);
X			}
X			else
X			{
X				usage(argv[0], "Bad timeout value.\n");
X			}
X		}
X		if (!strcmp("-p", argv[i]))
X		{
X			can_exit = TRUE;
X			no_of_printers = 0;
X			for (ncnt = i + 1; ncnt < origargc; ++ncnt)
X			{
X				if (!strcmp(argv[ncnt], "-t"))
X				{
X					ncnt = origargc;
X				}
X				else if (ncnt == i + 1)
X				{
X					(void)strcpy(base, argv[ncnt]);
X					find_pr(argv[ncnt]);
X				}
X				else
X				{
X					add_pr(printers, argv[ncnt],
X						no_of_printers);
X					++no_of_printers;
X				}
X			}
X			if (no_of_printers < 2)
X			{
X				usage(argv[0], "Less than 2 printers specified.\n");
X			}
X		}
X		++i;
X	}
X	if (!TIMEOUT) TIMEOUT = 2;
X	if (can_exit == FALSE)
X	{
X		usage(argv[0], "Bad arguments used.  Must use -p option.\n");
X	}
X	init_daemon(base);
X	return(no_of_printers);
X}
X
Xusage(arg, str)
Xchar *arg, *str;
X{
X	(void)fprintf(stderr, "%sUsage : %s [-p <main printer> <pr1> <pr2> ...] [-t <timeout>]\n", str, arg);
X	exit(1);
X}
X
X/* 
X// add_pr() - add a printer to the list of printers.
X// 
X// Arguments :  printerstruct *printers -- the printer structure.
X//		char *str -- the name of the printer specified on command line.
X//              int nop -- the number of the printer item;
X*/
Xint add_pr(printers, str, nop)
Xprinterstruct *printers;
Xchar *str;
Xint nop;
X{
X	char line[BUFSIZ];
X	char *tmpbuf;
X	int status;
X	char *bp;
X
X#ifndef lint
X	printers->directory[nop] = (char *) malloc(512);
X	printers->name[nop] = (char *) malloc(512);
X	tmpbuf = (char *)malloc(BUFSIZ);
X	bp = (char *)malloc(BUFSIZ/2);
X#else
X	printers->directory[nop] = NULL;
X	printers->name[nop] = NULL;
X	tmpbuf = NULL;
X	bp = NULL;
X#endif
X	if ((status = pgetent(line, str)) < 0)
X	{
X		bomb("pgetent");
X	}
X	if (status == 0)
X	{
X		(void)fprintf(stderr, "No such printer (%s) exists on this system.\n", str);
X		exit(1);
X	}
X	if ((tmpbuf = (char *)pgetstr((char *)"sd", (char *)&bp)) == NULL)
X	{
X		bomb("get_prdir_from_printcap:pgetstr");
X	}
X	(void)strcpy((char *)printers->directory[nop], (char *)tmpbuf);
X	(void)strcpy((char *)printers->name[nop], (char *)str);
X}
X
X/* 
X// find_pr() - find the base printer in the printcap file.
X// 
X// This function will set the LP_SPOOL_DIRECTORY to the base printer
X// spooling directory specified in /etc/printcap.
X//
X// Arguments : char *str -- the name of the printer specified on command line.
X*/
X
Xfind_pr(str)
Xchar *str;
X{
X	char line[BUFSIZ];
X#ifndef lint
X	char *newdir;
X	char *bp;
X#endif
X	int status;
X
X#ifndef lint
X	newdir = (char *)malloc(BUFSIZ);
X	bp = (char *)malloc(BUFSIZ/2);
X#endif
X	if ((status = pgetent(line, str)) < 0)
X	{
X		bomb("pgetent");
X	}
X	if (status == 0)
X	{
X		(void)fprintf(stderr, "No such printer (%s) exists on this system.\n", str);
X		exit(1);
X	}
X	if ((newdir = (char *)pgetstr("sd", &bp)) == NULL)
X	{
X		bomb("get_prdir_from_printcap:pgetstr");
X	}
X	LP_SPOOL_DIRECTORY = (char *)strdup(newdir);
X}
END_OF_FILE
  if test 4610 -ne `wc -c <'pfile.c'`; then
    echo shar: \"'pfile.c'\" unpacked with wrong size!
  fi
  # end of 'pfile.c'
fi
if test -f 'printcap.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'printcap.c'\"
else
  echo shar: Extracting \"'printcap.c'\" \(6858 characters\)
  sed "s/^X//" >'printcap.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1983 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)printcap.c	5.3 (Berkeley) 6/30/88";
X#endif /* not lint */
X
X#define	BUFSIZ	1024
X#define MAXHOP	32	/* max number of tc= indirections */
X
X#include <ctype.h>
X#include <stdio.h>
X/*
X * termcap - routines for dealing with the terminal capability data base
X *
X * BUG:		Should use a "last" pointer in tbuf, so that searching
X *		for capabilities alphabetically would not be a n**2/2
X *		process when large numbers of capabilities are given.
X * Note:	If we add a last pointer now we will screw up the
X *		tc capability. We really should compile termcap.
X *
X * Essentially all the work here is scanning and decoding escapes
X * in string capabilities.  We don't use stdio because the editor
X * doesn't, and because living w/o it is not hard.
X */
X
X#define PRINTCAP
X
X#ifdef PRINTCAP
X#define tgetent	pgetent
X#define tskip	pskip
X#define tgetstr	pgetstr
X#define tdecode pdecode
X#define tdecode pdecode
X#define tnchktc	pnchktc
X#define	tnamatch pnamatch
X#undef E_TERMCAP
X#define E_TERMCAP "/etc/printcap"
X#define V6
X#endif
X
Xstatic	char *tbuf;
Xstatic	int hopcount;		/* detect infinite loops in termcap, init 0 */
Xchar	*tskip();
Xchar	*tgetstr();
Xchar	*tdecode();
Xchar	*getenv();
X
X/*
X * Get an entry for terminal name in buffer bp,
X * from the termcap file.  Parse is very rudimentary;
X * we just notice escaped newlines.
X */
Xtgetent(bp, name)
X	char *bp, *name;
X{
X	register char *cp;
X	register int c;
X	register int i = 0, cnt = 0;
X	char ibuf[BUFSIZ];
X#ifndef lint
X	char *cp2;
X#endif
X	int tf;
X
X	tbuf = bp;
X	tf = 0;
X#ifndef V6
X	cp = getenv("TERMCAP");
X	/*
X	 * TERMCAP can have one of two things in it. It can be the
X	 * name of a file to use instead of /etc/termcap. In this
X	 * case it better start with a "/". Or it can be an entry to
X	 * use so we don't have to read the file. In this case it
X	 * has to already have the newlines crunched out.
X	 */
X	if (cp && *cp) {
X		if (*cp!='/') {
X			cp2 = getenv("TERM");
X			if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
X				(void)strcpy(bp,cp);
X				return(tnchktc());
X			} else {
X				tf = open(E_TERMCAP, 0);
X			}
X		} else
X			tf = open(cp, 0);
X	}
X	if (tf==0)
X		tf = open(E_TERMCAP, 0);
X#else
X	tf = open(E_TERMCAP, 0);
X#endif
X	if (tf < 0)
X		return (-1);
X	for (;;) {
X		cp = bp;
X		for (;;) {
X			if (i == cnt) {
X				cnt = read(tf, ibuf, BUFSIZ);
X				if (cnt <= 0) {
X					(void)close(tf);
X					return (0);
X				}
X				i = 0;
X			}
X			c = ibuf[i++];
X			if (c == '\n') {
X				if (cp > bp && cp[-1] == '\\'){
X					cp--;
X					continue;
X				}
X				break;
X			}
X			if (cp >= bp+BUFSIZ) {
X				(void)write(2,"Termcap entry too long\n", 23);
X				break;
X			} else
X				*cp++ = c;
X		}
X		*cp = 0;
X
X		/*
X		 * The real work for the match.
X		 */
X		if (tnamatch(name)) {
X			(void)close(tf);
X			return(tnchktc());
X		}
X	}
X}
X
X/*
X * tnchktc: check the last entry, see if it's tc=xxx. If so,
X * recursively find xxx and append that entry (minus the names)
X * to take the place of the tc=xxx entry. This allows termcap
X * entries to say "like an HP2621 but doesn't turn on the labels".
X * Note that this works because of the left to right scan.
X */
Xtnchktc()
X{
X	register char *p, *q;
X	char tcname[16];	/* name of similar terminal */
X	char tcbuf[BUFSIZ];
X	char *holdtbuf = tbuf;
X	int l;
X
X	p = tbuf + strlen(tbuf) - 2;	/* before the last colon */
X	while (*--p != ':')
X		if (p<tbuf) {
X			(void)write(2, "Bad termcap entry\n", 18);
X			return (0);
X		}
X	p++;
X	/* p now points to beginning of last field */
X	if (p[0] != 't' || p[1] != 'c')
X		return(1);
X	(void)strcpy(tcname,p+3);
X	q = tcname;
X	while (q && *q != ':')
X		q++;
X	*q = 0;
X	if (++hopcount > MAXHOP) {
X		(void)write(2, "Infinite tc= loop\n", 18);
X		return (0);
X	}
X	if (tgetent(tcbuf, tcname) != 1)
X		return(0);
X	for (q=tcbuf; *q != ':'; q++)
X		;
X	l = p - holdtbuf + strlen(q);
X	if (l > BUFSIZ) {
X		(void)write(2, "Termcap entry too long\n", 23);
X		q[BUFSIZ - (p-tbuf)] = 0;
X	}
X	(void)strcpy(p, q+1);
X	tbuf = holdtbuf;
X	return(1);
X}
X
X/*
X * Tnamatch deals with name matching.  The first field of the termcap
X * entry is a sequence of names separated by |'s, so we compare
X * against each such name.  The normal : terminator after the last
X * name (before the first field) stops us.
X */
Xtnamatch(np)
X	char *np;
X{
X	register char *Np, *Bp;
X
X	Bp = tbuf;
X	if (*Bp == '#')
X		return(0);
X	for (;;) {
X		for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
X			continue;
X		if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
X			return (1);
X		while (*Bp && *Bp != ':' && *Bp != '|')
X			Bp++;
X		if (*Bp == 0 || *Bp == ':')
X			return (0);
X		Bp++;
X	}
X}
X
X/*
X * Skip to the next field.  Notice that this is very dumb, not
X * knowing about \: escapes or any such.  If necessary, :'s can be put
X * into the termcap file in octal.
X */
Xstatic char *
Xtskip(bp)
X	register char *bp;
X{
X
X	while (*bp && *bp != ':')
X		bp++;
X	if (*bp == ':')
X		bp++;
X	return (bp);
X}
X
X/*
X * Get a string valued option.
X * These are given as
X *	cl=^Z
X * Much decoding is done on the strings, and the strings are
X * placed in area, which is a ref parameter which is updated.
X * No checking on area overflow.
X */
Xchar *
Xtgetstr(id, area)
X	char *id, **area;
X{
X	register char *bp = tbuf;
X
X	for (;;) {
X		bp = tskip(bp);
X		if (!*bp)
X			return (0);
X		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
X			continue;
X		if (*bp == '@')
X			return(0);
X		if (*bp != '=')
X			continue;
X		bp++;
X		return (tdecode(bp, area));
X	}
X}
X
X/*
X * Tdecode does the grung work to decode the
X * string capability escapes.
X */
Xstatic char *
Xtdecode(str, area)
X	register char *str;
X	char **area;
X{
X	register char *cp;
X	register int c;
X	register char *dp;
X	int i;
X
X	cp = *area;
X	while ((c = *str++) && c != ':') {
X		switch (c) {
X
X		case '^':
X			c = *str++ & 037;
X			break;
X
X		case '\\':
X			dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
X			c = *str++;
Xnextc:
X			if (*dp++ == c) {
X				c = *dp++;
X				break;
X			}
X			dp++;
X			if (*dp)
X				goto nextc;
X			if (isdigit(c)) {
X				c -= '0', i = 2;
X				do
X					c <<= 3, c |= *str++ - '0';
X				while (--i && isdigit(*str));
X			}
X			break;
X		}
X		*cp++ = c;
X	}
X	*cp++ = 0;
X	str = *area;
X	*area = cp;
X	return (str);
X}
END_OF_FILE
  if test 6858 -ne `wc -c <'printcap.c'`; then
    echo shar: \"'printcap.c'\" unpacked with wrong size!
  fi
  # end of 'printcap.c'
fi
if test -f 'printer.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'printer.c'\"
else
  echo shar: Extracting \"'printer.c'\" \(9835 characters\)
  sed "s/^X//" >'printer.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1990 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Riverside. 
X *
X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
X *        Irvine.  Riverside.  Ri - ver - side.
X *
X * The name of the University may not be used to endorse or promote 
X * products derived from this software without specific prior written
X * permission.
X *
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X * 
X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
X * SCCS keywords: @(#)printer.c	1.3 12/1/90
X */
X
X#include "config.h"
X
X/*
X// check_base_printer() -- Check the main printer queue.
X//
X// This function will go through the main printer queue and see
X// whether or not there are any files to print out.  If there are,
X// notify the main program the number of files to print out.  We
X// mainly want to see that there are files to print, so that all
X// of the other printer queues can be checked.
X*/
X
Xint check_base_printer()
X{
X#ifdef  SUN
X	struct dirent *d; 
X#else
X	struct direct *d;
X#endif
X	DIR *dirpointer; 
X	int nitems;
X
X	/*
X	// First we open up the spooling directory for the main
X	// spooler.  Queueing should be allowed on this printer,
X	// but printing should be turned off.  We open up the
X	// directory to read the files in them.
X	*/
X	(void)debug("Checking base printer spooling directory...\n");
X	if ((dirpointer = opendir(LP_SPOOL_DIRECTORY)) == NULL)
X	{
X		debug("Couldn't open directory.\n");
X		return -1;
X	}
X	nitems = 0;
X	/*
X	// Now, while we have the chance, let's check out the files
X	// in the directory and see whether something is printing or
X	// not (if nothing is printing, there won't be any files in
X	// the directory.  lpd will delete them off.)
X	*/
X	while ((d = readdir(dirpointer)) != NULL)
X	{
X		debug("Checking files in directory.\n");
X		/*
X		// See if the file has a df* extension.
X		// This is the type of file that we want to use to 
X		// print out.
X		*/
X		if (!strncmp(d->d_name, "cf", 2))
X		{
X			debug("Incrementing file count.\n");
X			++nitems;
X		}
X	}
X	/*
X	// Now close off the directory, and get back to main().
X	*/
X	(void)closedir(dirpointer);
X	return (nitems);
X}
X
X/*
X// check_prs() -- Check each printer queue.
X//
X// This function will go through the each printer queue and see
X// whether or not there are any files to print out.  If there are,
X// notify the main program the printer is busy, otherwise tell the
X// main program that we would like a print job sent to us.  All of
X// the printer queues are checked through this machine.
X*/
X
Xint check_prs(printers, cnt)
Xprinterstruct *printers;
Xint cnt;
X{
X#ifdef  SUN
X	struct dirent *d; 
X#else
X	struct direct *d;
X#endif
X	DIR *dirpointer; 
X	int nitems;
X
X	/*
X	// Try and create a char[] for the directory where 
X	// the printer is located.  
X	*/
X	/*
X	// First we open up the spooling directory for our new
X	// spooler.  Printing should be allowed on this printer,
X	// but queueing should be turned off.  We open up the
X	// directory to read the files in them.
X	*/
X	if ((dirpointer = opendir(printers->directory[cnt])) == NULL)
X	{
X		bomb("check_prs:opendir");
X		return -1;
X	}
X	nitems = 0;
X	/*
X	// Now, while we have the chance, let's check out the files
X	// in the directory and see whether something is printing or
X	// not.  If something is printing, then we don't want to send
X	// a job to this printer.  If nothing is printing, we want
X	// to ship out a job to the printer ASAP.
X	*/
X	while ((d = readdir(dirpointer)) != NULL)
X	{
X		if (!strncmp(d->d_name, "cf", 2))
X		{
X			++nitems;
X		}
X	}
X	/*
X	// Close off the directory pointer.
X	*/
X	(void)closedir(dirpointer);
X	/*
X	// Return the number of files that are printing.
X	*/
X	return(nitems);
X}
X
X/*
X// print_file() -- Print out a file in the spool directory.
X//
X// First, we try to find a file in the directory where we have
X// specified that we are going to print from.  If we do, then we
X// take the job from one printer area to another, and "kick-start"
X// the new printer into printing out the jobs (We should have to
X// send a signal to lpd to get this job running.)
X*/
X
Xint print_file(p, cnt)
Xprinterstruct *p;
Xint cnt;
X{
X#ifdef  SUN
X	struct dirent *d; 
X#else
X	struct direct *d;
X#endif
X	DIR *dirpointer; 
X	int nitems;
X
X	/*
X	// Open up the spooling directory.
X	*/ 
X	(void)debug("Yes, I can now print out a file!\n");
X	if ((dirpointer = opendir(LP_SPOOL_DIRECTORY)) == NULL)
X	{
X		return -1;
X	}
X	nitems = 0;
X	/*
X	// Try to find some number of files to print out on the 
X	// printer.  If we find a file, we send that file to the new
X	// directory, and send a signal to the lpd program and 
X	// return back to the main program.  If we do not get any
X	// file from the directory, something must be messed up, so
X	// we need to return our exit status to the main program.
X	// While we are at it, we should pass along the control file 
X	// that goes with the data file, so that the printer can get 
X	// the proper information for the banner page, accounting, etc.
X	*/
X	while (((d = readdir(dirpointer)) != NULL) && (nitems == 0))
X	{
X		/*
X		// Check to see that the file we want to print
X		// is a data file type in the directory.
X		*/
X		if (!strncmp(d->d_name, "cf", 2))
X		{
X			/*
X			// Move the files.
X			*/
X			(void)debug("I am now attempting to move the files.\n");
X			move_files(d->d_name, p, cnt);
X			/*
X			// Send off the signal to the lpd program.
X			// We never use the return value, though.
X			*/
X			(void)debug("Starting up the printer.\n");
X			(void)send_lpd_signal(p->name[cnt]);
X			++nitems;
X		}
X	}
X	/*
X	// Close off the directory.
X	*/
X	(void)closedir(dirpointer);
X	if (nitems == 0)
X	{
X		bomb("readdir");
X	}
X	return(0);
X}
X
X/*
X// move_files() -- move the files from one spooling directory to another.
X//
X// This function will move all of the files associated with a print job
X// to a new spooling directory.
X//
X// Arguments: char *cffile -- the name of the control file.
X//            printerstruct *p -- the printers structure.
X//            int cnt -- the index into printerstruct specifying the printer
X//                       directory to move the files to.
X*/
Xmove_files(cffile, p, cnt)
Xchar *cffile;
Xprinterstruct *p;
Xint cnt;
X{
X	char tmpbuf1[1024],tmpbuf2[1024],xbuf[1024],data[1024];
X	FILE *fp, *fopen();
X
X	xbuf[0] = '\0'; data[0] = '\0';
X	(void)sprintf(xbuf, "%s/%s", LP_SPOOL_DIRECTORY, cffile);
X	(void)debug("Opening and reading control file");
X	if ((fp = fopen(xbuf, "r")) == NULL)
X	{
X		(void)debug("Bombing on fopen().\n");
X		bomb("move_files:fopen");
X	}
X	data[0] = '\0';
X	while (fgets(data, 1024, fp) > 0)
X	{
X		if (data[0] == 'f')
X		{
X			/* 
X			// Must be a file that we want...Move it.
X			*/
X			(void)debug("Moving data file.\n");
X			tmpbuf1[0] = '\0'; tmpbuf2[0] = '\0';
X			data[strlen(data)-1] = '\0';
X			(void)sprintf(tmpbuf1,"%s/%s",LP_SPOOL_DIRECTORY,&data[1]);
X			(void)sprintf(tmpbuf2,"%s/%s",p->directory[cnt],&data[1]);
X			if (rename(tmpbuf1, tmpbuf2) != 0)
X			{
X				bomb("move_files:fgets:rename");
X			}
X		}
X		data[0] = '\0';
X	}
X	(void)fclose(fp);
X	tmpbuf1[0] = '\0'; tmpbuf2[0] = '\0';
X	(void)sprintf(tmpbuf1, "%s/%s", LP_SPOOL_DIRECTORY,cffile);
X	(void)sprintf(tmpbuf2, "%s/%s", p->directory[cnt],cffile);
X	(void)debug("Moving control file.\n");
X	if (rename(tmpbuf1, tmpbuf2) != 0)
X	{
X		bomb("move_files:rename");
X	}
X}
X
X/*
X// restart_all_printers() -- send a signal to restart all printers.
X//
X// We want to restart all printers when we first start up so that we can
X// clear jobs from those queues.  This will be run every 30 seconds.
X//
X// Arguments: int nop -- The total number of printers.
X//            printerstruct *printers -- the printers structure.
X*/
X
Xint restart_all_printers(nop, printers)
Xint nop;
Xprinterstruct *printers;
X{
X	int clt;
X
X	for (clt = 0; clt < nop; ++clt)
X	{
X		(void)send_lpd_signal(printers->name[clt]);
X	}
X}
X
X/*
X// send_lpd_signal() -- Send a signal to lpd to start printing from a printer.
X//
X// This function will create a socket, try and connect using that socket to
X// the default socket for the printer, and then if a connection can be made,
X// the printer is sent a control code to print out all files for a specific
X// printer.  If this returns a \0, then everything was okay.
X//
X// Arguments : char *printer; (Name of the printer to use)
X*/
X
Xint send_lpd_signal(printer)
Xchar *printer;
X{
X	struct sockaddr_un server;
X	register int s, n;
X	char buf[1024];
X
X	s = socket(AF_UNIX, SOCK_STREAM, 0);
X	if (s < 0) 
X	{
X		if (errno == EMFILE)
X		{
X			bomb("send_lpd_signal:socket:EMFILE");
X		}
X		else if (errno == ENFILE)
X		{
X			bomb("send_lpd_signal:socket:ENFILE");
X		}
X		else if (errno == ENOBUFS)
X		{
X			bomb("send_lpd_signal:socket:ENOBUFS");
X		}
X		bomb("send_lpd_signal:socket:dont_know");
X	}
X	server.sun_family = AF_UNIX;
X#ifndef lint
X	(void)strcpy((char *)server.sun_path, (char *)"/dev/printer");
X#endif
X	if ((int)connect(s, (struct sockaddr *)&server, (int)strlen(server.sun_path) + 2) < 0) 
X	{
X		bomb("connect");
X		(void) close(s);
X		return(0);
X	}
X	(void) sprintf(buf, "\1%s\n", printer);
X	n = strlen(buf);
X	if (write(s, buf, n) != n) 
X	{
X		bomb("write");
X		(void) close(s);
X		return(0);
X	}
X	if (read(s, buf, 1) == 1) 
X	{
X		if (buf[0] == '\0') 
X		{
X			(void)close(s);
X			return(1);
X		}
X		(void)putchar(buf[0]);
X	}
X	while ((n = read(s, buf, sizeof(buf))) > 0)
X		(void)fwrite(buf, 1, n, stdout);
X	(void)close(s);
X	(void)debug("Signal has been sent to the printer %s.\n");
X	return(0);
X}
END_OF_FILE
  if test 9835 -ne `wc -c <'printer.c'`; then
    echo shar: \"'printer.c'\" unpacked with wrong size!
  fi
  # end of 'printer.c'
fi
echo shar: End of archive.
exit 0
exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.



More information about the Comp.sources.unix mailing list