[comp.sources.misc] v02i014: psmon - monitor error messages from postscript printers

moss@ptsfa.UUCP (01/20/88)

Comp.sources.misc: Volume 2, Issue 14
Submitted-By: <moss@ptsfa.UUCP>
Archive-Name: psmon

[The only BSD porting needed should be termio-relative stuff.  ++bsa]

Here's a submission for a simple monitor program for Postscript 
error messages. It was written for SYS5 line printer spooling, and
writes printer-detected error messages into a status file, along
with the user's name and lp job id number.

Ken Keirnan

------------------------------cut here----------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	README
#	ps.monitor.c
# This archive created by Ken Keirnan, Mon Jan 18 09:04:19 1988
export PATH; PATH=/bin:$PATH
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
CFLAGS = -O -s
# Uncomment the CLIB line if you have SYS5 shared libraries
# CLIB = -lc_s

all:		ps.monitor

ps.monitor:	ps.monitor.c
		cc $(CFLAGS) -o ps.monitor ps.monitor.c $(CLIB)

install:	all
		mv ps.monitor /usr/lib/ps.monitor
		chown lp /usr/lib/ps.monitor
		chgrp sys /usr/lib/ps.monitor
		chmod 4755 /usr/lib/ps.monitor
SHAR_EOF
chmod +x 'Makefile'
fi # end of overwriting check
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
Ps.monitor is a program to monitor and log input from a tty line connected
to a PostScript printer.  It creates a log file "/usr/spool/lp/ps.error"
and a lock file "/usr/spool/lp/PS_LOCK" to prevent multiple instances of
the program.  Ps.monitor will clean up the lock file and stop on a SIGTERM.
When ps.monitor starts, it move an existing "ps.error" file to "Ops.error",
and writes the date and time as the first line in the new "ps.error" file.

To make the program just type "make".  To make the program and install in
/usr/lib type "make install".

The program is kept in /usr/lib/ps.monitor, and is called with two arguments,
the baud rate of the tty port, and the ttyxx name (without the "/dev/") as in:

		/usr/lib/ps.monitor 9600 tty22

In the system startup files or wherever the lineprinter startup is called
(such as /etc/rc or /etc/rc2.d, etc.), the following lines should be added:

		rm -f /usr/spool/lp/PS_LOCK
		/usr/lib/ps.monitor <baud> <ttyxx>

where <baud> is baud rate of the tty device and <ttyxx> is the tty name in
the "/dev" directory.

Also, if the printer driver or interface is a shell procedure, a line
similar to the following could be used to keep track of the user, job id
and time in the "ps.error" file:

	echo "<$JOB>, <$USER>, `/bin/date`" >> /usr/spool/lp/ps.error

The location of the lock file and the error log can be changed by modifying
the defines for LOCK, PSERR and OPSERR near the beginning of the program,
and the directory containing the program can be changed in the Makefile.

Precautions:

The program was intended for SYS5 line printer spooling systems, and may
require modifications for use on other flavors of Unices.....


					Ken Keirnan
					Pacific [*] Bell
					Minicomputer Operations Support Staff
					San Ramon, CA.  94583
					(415) 823-3911
					{ames,pyramid,sun}!pacbell!pt06a!kk1
			or		{ames,pyramid,sun}!ptsfa!pt06a!kk1
SHAR_EOF
chmod +x 'README'
fi # end of overwriting check
if test -f 'ps.monitor.c'
then
	echo shar: will not over-write existing file "'ps.monitor.c'"
else
cat << \SHAR_EOF > 'ps.monitor.c'
/*
 * ps.monitor - log output from PostScript printer
 *
 *	This program will monitor a tty port for error/diagnostic messages
 *	from a PostScript printer, and log them in /usr/spool/lp/ps.error.
 *	The program runs as a daemon (places itself in the background and
 *	ignores most interrupts), and will stop cleanly on SIGTERM.  A lock
 *	file (/usr/spool/lp/PS_LOCK) is created to prevent multiple instances
 *	of the program, and the lock may have to be removed manually if the
 *	program is stopped with other than SIGTERM.
 *
 *	To compile:	cc -O -s -o /usr/lib/ps.monitor ps.monitor.c
 *			chown lp /usr/lib/ps.monitor
 *			chmod 4755 /usr/lib/ps.monitor
 *
 *	Usage:		/usr/lib/ps.monitor <baud> <ttyxx>
 */
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <termio.h>
#include <time.h>

#define	LOCK	"/usr/spool/lp/PS_LOCK"
#define PSERR	"/usr/spool/lp/ps.error"
#define OPSERR	"/usr/spool/lp/Ops.error"
#define FPR	(void)fprintf

void exit();
void spinoff();
int unlock();

main(argc, argv)
int argc;
char **argv;
{
	register FILE *ofp;
	register i, psfd;
	char lbuf[512];
	char dbuf[64];
	long t, time();

	(void)umask(0);

	if (argc != 3) {
		FPR(stderr, "Usage: ps.monitor <baud> <ttyxx>\n");
		exit(1);
	}
	if (access(LOCK, 0) == 0) {
		FPR(stderr, "ps.monitor: already active\n");
		FPR(stderr, "    (%s already exists)\n", LOCK);
		exit(0);
	}
	i = getspeed(atoi(argv[1]));

	(void)sprintf(dbuf, "/dev/%s", argv[2]);

	if ((psfd = open(dbuf, O_RDONLY)) == -1) {
		FPR(stderr, "ps.monitor: can't open %s\n", dbuf);
		exit(1);
	}
	if (settty(psfd, i) == -1) {
		FPR(stderr, "ps.monitor: ioctl failed on %s\n", dbuf);
		exit(1);
	}

	if (link(PSERR, OPSERR) != -1)
		(void)unlink(PSERR);

	if ((ofp = fopen(PSERR, "a")) == NULL) {
		FPR(stderr, "ps.monitor: can't create error log %s\n", PSERR);
		exit(1);
	}

	spinoff();

	/*
	 * Ignore common signals
	 */
	(void)signal(SIGHUP, SIG_IGN);
	(void)signal(SIGQUIT, SIG_IGN);
	(void)signal(SIGINT, SIG_IGN);
	(void)signal(SIGPIPE, SIG_IGN);
	(void)signal(SIGALRM, SIG_IGN);
	(void)signal(SIGTERM, unlock);

	t = time((long *)0);
	FPR(ofp, "Created: %s", ctime(&t));
	(void)fflush(ofp);

	while ((i = read(psfd, lbuf, 512)) >= 0)
		if (i) {
			(void)fwrite(lbuf, 1, i, ofp);
			(void)fflush(ofp);
		}

	return(0);
}

getspeed(n)
int n;
{
	switch (n) {

	case 300:
		return(B300);
	case 1200:
		return(B1200);
	case 2400:
		return(B2400);
	case 4800:
		return(B4800);
	case 9600:
		return(B9600);
	case 19200:
		return(B19200);
	}

	return(B9600);	/* default for no match 9600 baud */
}

/*
 * settty() - set tty modes (if output connected to a tty).
 */
settty(fd, speed)
int fd, speed;
{
	struct termio termbuff;

	if (ioctl(fd, TCGETA, &termbuff) == -1)
		return(-1);
	/*
	 * Enable Canonical, XON / XOFF flow control, and set baud.
	 */
	termbuff.c_lflag = ICANON;
	termbuff.c_iflag = IXON | IXOFF;
	termbuff.c_cflag = speed | CS8 | CREAD;
	termbuff.c_oflag = 0;

	(void)ioctl(fd, TCSETAW, &termbuff);

	return(0);
}

void
spinoff()
{
	register FILE *fp;
	register i;

	/*
	 * Create a child process
	 */
	if ((i = fork()) == -1) {
		FPR(stderr, "ps.monitor: can't fork()\n");
		exit(1);
	}
	/*
	 * The parent dies leaving the child inherited by pid 1
	 */
	if (i) {
		if ((fp = fopen(LOCK, "w")) == NULL) {
			FPR(stderr, "ps.monitor: can't create lock %s\n", LOCK);
			(void)kill(i, SIGKILL);
		}
		FPR(fp, "%d\n", i);
		(void)fclose(fp);
		exit(0);
	}
}

unlock()
{
	(void)unlink(LOCK);
	exit(0);
}
SHAR_EOF
chmod +x 'ps.monitor.c'
fi # end of overwriting check
#	End of shell archive
exit 0