v16i021: Public lineprinter spooler package, Part08/16

Rich Salz rsalz at bbn.com
Thu Sep 15 22:12:17 AEST 1988


Submitted-by: papowell at julius.cs.umn.edu
Posting-number: Volume 16, Issue 21
Archive-name: plp/part08

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 8 (of 16)."
# Contents:  filters/main.c src/link_support.c src/lpr.c
#   src/lpr_filters.c
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'filters/main.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'filters/main.c'\"
else
echo shar: Extracting \"'filters/main.c'\" \(11034 characters\)
sed "s/^X//" >'filters/main.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: main.c for filters
X ***************************************************************************
X * Revision History: Created Fri Mar  4 19:45:03 CST 1988
X * $Log:	main.c,v $
X * Revision 2.2  88/05/19  07:36:17  papowell
X * Added a -D (debug) flag
X * 
X * Revision 2.1  88/05/09  10:12:10  papowell
X * *** empty log message ***
X * 
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: main.c,v 2.2 88/05/19 07:36:17 papowell Locked $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X/***************************************************************************
X *  UMN-LPR filter template and frontend.
X *
X *	A filter is invoked with the following parameters,
X *  which can be in any order, and perhaps some missing.
X *
X *  filtername arguments \   <- from PRINTCAP entry
X *      -PPrinter -wwidth -llength -xwidth -ylength [-c] [-iindent] \
X *		[-Zoptions] [-Cclass] [-Jjob] [-Raccntname] -nlogin -hHost  \
X *      -Fformat -Ddebug [affile]
X * 
X *  1. Parameters can be in different order than the above.
X *  2. Optional parameters can be missing
X *  3. Values specified for the width, length, etc., are from PRINTCAP
X *     or from the overridding user specified options.
X *
X *  This program provides a common front end for most of the necessary
X *  grunt work.  This falls into the following classes:
X * 1. Parameter extraction.
X * 2. Suspension when used as the "of" filter.
X * 3. Termination and accounting
X *  The front end will extract parameters,  then call the filter()
X *  routine,  which is responsible for carrying out the required filter
X *  actions. filter() is invoked with the printer device on fd 1,
X *	and error log on fd 2.  The npages variable is used to record the
X *  number of pages that were used.
X *  The "halt string", which is a sequence of characters that
X *  should cause the filter to suspend itself, is passed to filter.
X *  When these characters are detected,  the "suspend()" routine should be
X *  called.
X *
X *  On successful termination,  the accounting file will be updated.
X *
X *  The filter() routine should return 0 (success), 1 (retry) or 2 (abort).
X *
X * Parameter Extraction
X *	The main() routine will extract parameters
X *  whose values are placed in the appropriate variables.  This is done
X *  by using the ParmTable[], which has entries for each valid letter
X *  parmeter, such as the letter flag, the type of variable,
X *  and the address of the variable.
X *  The following variables are provided as a default set.
X *      -PPrinter -wwidth -llength -xwidth -ylength [-c] [-iindent] \
X *		[-Zoptions] [-Cclass] [-Jjob] [-Raccntname] -nlogin -hHost  \
X *      -Fformat [affile]
X * VARIABLE  FLAG          TYPE    PURPOSE / PRINTCAP ENTRTY
X * name     name of filter char*    argv[0], program identification
X * width    -wwidth	       int      PW, width in chars
X * length   -llength	   int      PL, length in lines
X * xwidth   -xwidth        int      PX, width in pixels
X * xlength  -xlength       int      PY, length in pixels
X * literal  -c	           int      if set, ignore control chars
X * indent   -iindent       int      indent amount (depends on device)
X * zopts    -Zoptions      char*    extra options for printer
X * class    -Cclass        char*    classname
X * job      -Jjob          char*    jobname
X * accntname -Raccntname   char*    account for billing purposes
X * login    -nlogin        char*    login name
X * host     -hhost         char*    host name
X * format   -Fformat       char*    format
X * accntfile file          char*    AF, accounting file
X *
X * npages    - number of pages for accounting
X * debug     - sets debug level
X *
X *	The functions fatal(), logerr(), and logerr_die() can be used to report
X *	status. The variable errorcode can be set by the user before calling
X *	these functions, and will be the exit value of the program. Its default
X *	value will be 2 (abort status).
X *	fatal() reports a fatal message, and terminates.
X *	logerr() reports a message, appends information indicated by errno
X *	(see perror(2) for details), and then returns.
X *	logerr_die() will call logerr(), and then will exit with errorcode
X *	status.
X *	Both fatal() and logerr_die() call the cleanup() function before exit.
X *
X * DEBUGGING:  a simple minded debugging version can be enabled by
X * compiling with the -DDEBUG option.
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/file.h>
X#include <signal.h>
X
X/*
X * default exit status, causes abort
X */
int errorcode = 2;
X
char *name;		/* name of filter */
X/* set from flags */
int debug, width, length, xwidth, ylength, literal, indent;
char *zopts, *class, *job, *login, *accntname, *host, *accntfile, *format;
char *printer;
int npages;	/* number of pages */
char filter_stop[] = "\031\001";	/* sent to cause filter to suspend */
X
main( argc, argv )
X	int argc;
X	char **argv;
X{
X	int i;
X
X	getargs( argc, argv );
X	/*
X	 * Turn off SIGPIPE
X	 */
X	(void)signal( SIGPIPE, SIG_IGN );
X	if( format && *format == 'o' ){
X		filter( filter_stop );
X	} else {
X		filter( (char *)0 );
X	}
X	doaccnt();
X	return(0);
X}
X
X/*VARARGS1*/
log(msg, a1, a2, a3)
X	char *msg;
X{
X	(void)fprintf(stderr, "%s: ", name);
X	(void)fprintf(stderr, msg, a1, a2, a3);
X	(void)putc('\n', stderr);
X	(void)fflush(stderr);
X}
X
X
X/*VARARGS1*/
fatal(msg, a1, a2, a3)
X	char *msg;
X{
X	log(msg, a1, a2, a3);
X	cleanup();
X	exit(errorcode);
X}
X
X
X/*VARARGS1*/
logerr(msg, a1, a2, a3)
X	char *msg;
X{
X	extern int errno, sys_nerr;
X	extern char *sys_errlist[];
X	int err = errno;
X
X	(void)fprintf(stderr, "%s: ", name);
X	if (msg){
X		(void)fprintf(stderr, msg, a1, a2, a3);
X		(void)fputs( "- ", stderr);
X	}
X	if( err < sys_nerr ){
X		(void)fputs(sys_errlist[err]);
X	} else {
X		(void)fprintf(stderr, "Unknown error %d", err);
X	}
X	(void)putc('\n', stderr);
X	(void)fflush(stderr);
X}
X
X/*VARARGS1*/
logerr_die(msg, a1, a2, a3)
X	char *msg;
X{
X	logerr(msg, a1, a2, a3);
X	cleanup();
X	exit(errorcode);
X}
X
X/*
X *	doaccnt()
X *	writes the accounting information to the accounting file
X *  This has the format: user host printer pages format date
X */
doaccnt()
X{
X	time_t t, time();
X	char *ctime();
X	FILE *f;
X
X	t = time((time_t *)0);
X	if(accntfile && access(accntfile, W_OK) >= 0 &&
X	    (f = fopen(accntfile, "a" )) != NULL) {
X		fprintf(f,"%s\t%s\t%s\t%7d\t%s\t%s",
X			login? login: "NULL", 
X			host? host: "NULL", 
X			printer? printer: "NULL", 
X			npages,
X			format? format: "NULL", 
X			ctime(&t));
X		(void)fclose(f);
X	}
X}
X
getargs(argc, argv)
X	int argc;
X	char **argv;
X{
X	int i;		/* argument index */
X	char *arg;	/* argument */
X	int flag;	/* flag */
X
X	name = argv[0];
X	for( i = 1; i < argc; ++i ){
X		arg = argv[i];
X		if( *arg == '-' ){ /* arg will be string */
X				setvar( arg[1], &arg[2] );
X		} else {
X			/* must be accounting file */
X			accntfile = arg;
X		}
X	}
X	if( debug ){
X		for( i = 0; i < argc; ++i ){
X			fprintf(stderr, "%s ", argv[i] );
X		}
X		fprintf( stderr, "\n" );
X		fprintf(stderr,"login '%s'\n", login? login : "null" );
X		fprintf(stderr,"host '%s'\n", host? host : "null" );
X		fprintf(stderr,"class '%s'\n", class? class : "null" );
X		fprintf(stderr,"format '%s'\n", format? format : "null" );
X		fprintf(stderr,"job '%s'\n", job? job : "null" );
X		fprintf(stderr,"printer '%s'\n", printer? printer : "null" );
X		fprintf(stderr,"accntname '%s'\n", accntname? accntname : "null" );
X		fprintf(stderr,"zopts '%s'\n", zopts? zopts : "null" );
X		fprintf(stderr,"literal, %d\n", literal);
X		fprintf(stderr,"indent, %d\n", indent);
X		fprintf(stderr,"length, %d\n", length);
X		fprintf(stderr,"width, %d\n", width);
X		fprintf(stderr,"xwidth, %d\n", xwidth);
X		fprintf(stderr,"ylength, %d\n", ylength);
X		fprintf(stderr,"accntfile '%s'\n", accntfile? accntfile : "null" );
X		for( i = 0; i < argc; ++i ){
X			fprintf(stderr, "%s ", argv[i] );
X		}
X		fprintf( stderr, "\n" );
X		fflush(stderr);
X		fflush(stderr);
X	}
X}
X			
X#define INTV 0
X#define STRV 1
X#define FLGV 2
struct parm {
X	int flag;
X	char **var;
X	int kind;
X} Parmlist[] = {
X{'C', &class, STRV },
X{'D', (char **)&debug, INTV },
X{'F', &format, STRV },
X{'J', &job, STRV },
X{'P', &printer, STRV },
X{'R', &accntname, STRV },
X{'Z', &zopts, STRV },
X{'c', (char **)&literal, FLGV },
X{'h', &host, STRV },
X{'i', (char **)&indent, INTV },
X{'l', (char **)&length, INTV },
X{'n', &login, STRV },
X{'w', (char **)&width, INTV },
X{'x', (char **)&xwidth, INTV },
X{'y', (char **)&ylength, INTV } };
X
int Parmlen = sizeof(Parmlist)/sizeof(struct parm);
X
X/*
X * setvar( int flag, char *arg )
X * 1. look in table and find entry
X * 2. if STRV, then set 
X * 3. if INTV, then convert and set
X * 4. if FLGV, then set to 1
X */
setvar( flag, arg )
X	int flag;
X	char *arg;
X{
X	int u, l, i, c;	/* upper, lower, i */
X
X	l = 0; u = Parmlen;
X	while( l <= u ){
X		i = (u+l)/2;
X		c = flag - Parmlist[i].flag;
X		if( 0 == c ){
X			/* printf( "found parm %c, %d\n", flag, i ); */
X			switch( Parmlist[i].kind ){
X			case STRV: *Parmlist[i].var = arg; break;
X			case INTV: *(int *)Parmlist[i].var = atoi(arg); break;
X			case FLGV: *(int *)Parmlist[i].var = 1; break;
X			}
X			return;
X		} else if( c < 0 ){
X			/* fprintf(stderr, "down parm %c, %d\n", flag, i ); */
X			u = i - 1 ;
X		} else {
X			/* fprintf(stderr, "up parm %c, %d\n", flag, i ); */
X			l = i + 1 ;
X		}
X	}
X	/* fprintf(stderr, "did not find parm %c, %d\n", flag, i ); */
X	return;
X}
X
X/*
X * suspend():  suspends the output filter, waits for a signal
X */
suspend()
X{
X	if(debug)fprintf(stderr,"suspending\n");
X	fflush(stderr);
X	kill(getpid(), SIGSTOP);
X	if(debug)fprintf(stderr,"awake\n");
X	fflush(stderr);
X}
X#ifdef DEBUG
X/******************************************
X * prototype filter() and cleanup() functions;
X * filter will scan the input looking for the suspend string
X * if any.
X ******************************************/
cleanup() {}
X
filter(stop)
X	char *stop;
X{
X	int c;
X	int state, i;
X	int lines = 0;
X
X	/*
X	 * do whatever initializations are needed
X	 */
X	/* fprintf(stderr, "filter ('%s')\n", stop ? stop : "NULL" ); */
X	/*
X	 * now scan the input string, looking for the stop string
X	 */
X	state = 0;
X	npages = 1;
X
X	while( (c = getchar()) != EOF ){
X		if( c == '\n' ){
X			++lines;
X			if( lines > length ){
X				lines -= length;
X				++npages;
X			}
X		}
X		if( stop || state ){
X			if( c == stop[state] ){
X				++state;
X				if( stop[state] == 0 ){
X					state = 0;
X					if( fflush(stdout) ){
X						logerr_die( "fflush returned error" );
X					}
X					suspend();
X				}
X			} else if( state ){
X				for( i = 0; i < state; ++i ){
X					dochar( stop[i] );
X				}
X				state = 0;
X				dochar( c );
X			} else {
X				dochar( c );
X			}
X		} else {
X			dochar( c );
X		}
X	}
X	if( ferror( stdin ) ){
X		logerr_die( "read error on stdin");
X	}
X	for( i = 0; i < state; ++i ){
X		dochar( stop[i] );
X	}
X	if( lines > 0 ){
X		++npages;
X	}
X	if( fflush(stdout) ){
X		logerr_die( "fflush returned error" );
X	}
X}
X
dochar(c)
X	int c;
X{
X	putchar( c );
X}
X#endif DEBUG
END_OF_FILE
if test 11034 -ne `wc -c <'filters/main.c'`; then
    echo shar: \"'filters/main.c'\" unpacked with wrong size!
fi
# end of 'filters/main.c'
fi
if test -f 'src/link_support.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/link_support.c'\"
else
echo shar: Extracting \"'src/link_support.c'\" \(12422 characters\)
sed "s/^X//" >'src/link_support.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: Link_support.c
X ***************************************************************************
X * Revision History:  Created Fri Jan 15 20:13:48 CST 1988
X * $Log:	link_support.c,v $
X * Revision 3.1  88/06/18  09:34:21  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 2.1  88/05/09  10:08:20  papowell
X * PLP: Released Version
X * 
X * Revision 1.5  88/04/06  12:12:12  papowell
X * Minor updates, changes in error message formats.
X * Elimination of the AF_UNIX connections, use AF_INET only.
X * Better error messages.
X * 
X * Revision 1.4  88/03/25  14:59:39  papowell
X * Debugged Version:
X * 1. Added the PLP control file first transfer
X * 2. Checks for MX during file transfers
X * 3. Found and fixed a mysterious bug involving the SYSLOG facilities;
X * 	apparently they open files and then assume that they will stay
X * 	open.
X * 4. Made sure that stdin, stdout, stderr was available at all times.
X * 
X * Revision 1.3  88/03/12  10:03:50  papowell
X * *** empty log message ***
X * 
X * Revision 1.2  88/03/11  19:28:26  papowell
X * Minor Changes, Updates
X * 
X * Revision 1.1  88/03/01  11:08:29  papowell
X * Initial revision
X * 
X * Support for the inter-machine communications
X * Link_open(int retry)
X *  opens a link to the remote host
X * Link_close()
X *  closes the link to the remote Printer
X * Link_send( char *l)
X *  sends a line to the remote host
X * Link_line( int retry, char *l)
X *  opens the link (with or without retry)
X *  sends a line to the remote host
X * Link_confirm()
X *  gets a single character back, confirming the action
X * Link_ack( c )
X *  sends a single character back, confirming the action
X * Link_copy( FILE *fp, count)
X *  copies a file to the remote host;
X *  if count bytes not transfered, an error is generated
X * Link_get()
X *  gets and prints all information  on stdout
X * Link_port_num()
X *	gets remote port number for connection
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: link_support.c,v 3.1 88/06/18 09:34:21 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X
X#include "lp.h"
X
static int Link_fd;			/* fd for the socket */
X
X/***************************************************************************
X * Link_open(retry)
X * 1. Set up an inet socket;  a socket has a local host/local port and
X *    remote host/remote port address part.  The LPR software runs SUID
X *    root,  and will attempt to open a privileged port (number less than
X *    PRIV);  at the remote end this is checked to make sure that the
X *    remote machine is running SUID root.  Primitive,  but it is adequate
X *    in a trusting environment.
X *
X * (See Advanced 4.3 BSD IPC Tutorial for more information) The server on
X * the remote machine will be listening on the port given by the entry in
X * the /etc/service for the particular service desired.  If we are using
X * the "real" version of lpd this will be the "Printer" service, the test
X * version will use a "test" service.  The LPD daemon will open a socket
X * and bind to the appropriate "port" number.  The
X * getservbyname("printer","tcp"), is used to get the port information
X * (sp->s_port), which is used in a bind call.
X * 
X * When we want to communicate with the lpd daemon on the remote machine,
X * listening on that particular port, we call getseverbyname(...) to get
X * the port number and protocol.  The remote host expects the local port
X * to be in a range that is available only to a root UID process, i.e.-
X * less than IPPORT_RESERVED.  When we open the local port, we get a local
X * port in this range.  At the remote end, the port number is checked to
X * ensure that it is in a valid range.  Since the reserved ports can only
X * be accessed by UID 0 (root) processes, this would appear to prevent
X * ordinary users from directly contacting the remote daemon.
X *
X ***************************************************************************/
X/*
X * getport()
X *   gets a port,  in the correct range,  to the remote machine
X *   This code comes from a description of the RLOGIN and LPD
X *   materials
X */
static int
getport()
X{
X	struct hostent *host;			/* host entry pointer */
X	int port_num;					/* port number to connect to */
X	struct sockaddr_in sin;			/* inet socket address */
X	int sock;						/* socket */
X
X	/*
X	 * !!! Warning: zero out the sockaddr_in struct
X	 */
X	bzero( (char *)&sin, sizeof( sin ));
X	/*
X	 * Get the host address and port number to connect to.
X	 */
X	if(Debug>4)log( XLOG_DEBUG, "getport: host %s", RM );
X	host = gethostbyname(RM);
X	if (host == NULL){
X		logerr_die( XLOG_INFO,"getport: unknown host %s", RM);
X	}
X	/*
X	 * get the server name and protocol information from /etc/services
X	 */
X	port_num = Link_port_num();
X	/*
X	 * set up the address information
X	 */
X	bzero((char *)&sin, sizeof(sin));
X	bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length);
X	sin.sin_family = host->h_addrtype;
X	sin.sin_port = port_num;
X
X	/*
X	 * Try connecting to the server.
X	 */
X	if(Debug>3)log( XLOG_DEBUG, "trying connection to %s", RM );
X	sock = reserveport(Maxportno,Minportno);
X	if(sock < 0){
X		return(-1);
X	}
X	if(connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0){
X		if(Debug>2)logerr( XLOG_DEBUG, "connect failed to %s", RM );
X		(void) close(sock);
X		return(-1);
X	}
X	return(sock);
X}
X
X/*
X * reserveport(int port_no, min_port_no)
X * Reserve a port, starting at port_no, down to min_port_no.
X * while port_no > min_port_no
X *   try to grab the port;
X *   if you can, then return socket
X *   else return -1
X * Returns: socket if successful, -1 if not
X */
static int
reserveport(port_no, min_port_no)
X	int port_no, min_port_no;
X{
X	struct sockaddr_in sin;
X	int sock;
X
X	sock = socket(AF_INET, SOCK_STREAM, 0);
X	if(sock < 0){
X		logerr_die( XLOG_INFO, "reserveport socket call failed" );
X	} else if( sock == 0 ){
X		logerr_die( XLOG_INFO, "reserveport: socket returns 0" );
X	}
X	while( port_no >= min_port_no ){
X		bzero( (char *)&sin, sizeof( sin ));
X		sin.sin_family = AF_INET;
X		sin.sin_addr.s_addr = 0;
X		sin.sin_port = htons((u_short) port_no);
X		if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) >= 0){
X			if(Debug>4)log( XLOG_DEBUG, "reserveport got socket %d", port_no );
X			return(sock);
X		}
X		if(Debug>4)logerr( XLOG_DEBUG,"reserveport bind failed on %d",port_no );
X		if (errno != EADDRINUSE && errno != EADDRNOTAVAIL){
X			logerr_die( XLOG_INFO, "reserveport: bind failed" );
X		}
X		--port_no;
X	}
X	(void)close(sock);
X	return(-1);
X}
X
Link_open(retry)
X	int retry;
X{
X	unsigned int i = 1;
X	int l;
X
X	if( Link_fd ){
X		return( JSUCC );
X	}
X	while( Link_fd == 0 ){
X		if(Debug>3)log( XLOG_DEBUG,"Link_open: retry %d, attempt %d",retry,i );
X		l = getport();
X		if( l < 0 ){
X			if( retry == 0 ){
X				if(Debug>3)log( XLOG_DEBUG,"Link_open: failed" );
X				return( JFAIL );
X			} else if( retry > 0 ){
X				--retry;
X			}
X			sleep((unsigned)i);
X			if( i < 512 ){
X				i = i << 1;
X			}
X		} else if( l == 0 ){
X			fatal( XLOG_INFO, "Link_open: cannot happen- fd 0" );
X		} else {
X			Link_fd = l;
X		}
X	}
X	if(Debug>3)log( XLOG_DEBUG, "made connection to %s", RM );
X	return( JSUCC );
X}
X
X/***************************************************************************
X * Link_close()
X * 1. close the link
X ***************************************************************************/
void
Link_close()
X{
X	if(Debug>4)log(XLOG_DEBUG,"Link_close: closing link (%d)", Link_fd);
X	if( Link_fd ){
X		(void)close( Link_fd );
X	}
X	Link_fd = 0;
X}
X
X
X/***************************************************************************
X * Link_line( int retry; char *line )
X * send a line to the remote end
X * if retry != 0, blocks until connection made
X ***************************************************************************/
X
int
Link_line( retry, str )
X	char *str;
X{
X	if( Link_open(retry) != JSUCC ){
X		return( JFAIL );
X	}
X	return( Link_send( str ));
X}
X
int
Link_send( str )
X	char *str;
X{
X	int i, l;		/* ACME Integers, Inc. */
X
X	l = strlen( str );
X	if( Link_fd == 0 ){
X		log(XLOG_INFO, "Link_send: link to %s not open", RM);
X		return( JFAIL );
X	}
X	if( l != 0 && (i = write( Link_fd, str, l )) != l){
X		if( i < 0 ){
X			logerr( XLOG_INFO, "write error to remote site %s", RM);
X		}
X		Link_close();
X		return( JFAIL );
X	}
X	if(Debug>4)log(XLOG_DEBUG,"Link_send: sent to %s- '%d'%s",RM,*str,str+1);
X	return( JSUCC );
X}
X
X/***************************************************************************
X * Link_confirm()
X *  gets a single character back, confirming the action
X ***************************************************************************/
Link_confirm()
X{
X	char buf[1];	/* buffer */
X	int n;
X
X	if( Link_fd == 0 ){
X		log( XLOG_INFO, "link to %s not open", RM);
X		return( JFAIL );
X	}
X	if( (n = read( Link_fd, buf, 1 )) != 1 ){
X		if( n == 0 ){
X			log( XLOG_INFO, "Link_confirm: nothing from remote site %s", RM);
X		} else {
X			logerr( XLOG_INFO, "Link_confirm: error from remote site %s", RM);
X		}
X		Link_close();
X		return( JFAIL );
X	}
X	if( buf[0] != 0 ){
X		if(Debug>4)log(XLOG_DEBUG,"Link_confim: failed (%d) from %s",*buf,RM);
X		Link_close();
X		return( JFAIL );
X	}
X	if(Debug>4)log( XLOG_DEBUG, "successful confirm from %s", RM);
X	return( JSUCC );
X}
X
X/***************************************************************************
X * Link_copy( FILE *fp; long count; char *name)
X *  copies a file to the remote nost;
X *  if count bytes not transfered, an error is generated
X ***************************************************************************/
Link_copy( fp, count, name )
X	FILE *fp;
X	long count;
X	char *name;
X{
X	char buf[BUFSIZ];	/* buffer */
X	int i, l;				/* ACME Integer, Inc. */
X	long total;			/* total number of bytes */
X
X	if(Debug>4)log( XLOG_DEBUG, "Link_copy: %s- %d bytes to %s",name,count,RM);
X	if( Link_fd == 0 ){
X		log( XLOG_INFO, "Link_copy: Link_fd is not open");
X		goto error;
X	}
X
X	total = 0;
X	while( (i = fread( buf, 1, sizeof(buf), fp )) > 0 ){
X		total = total + i;
X		if( total > count ){
X			log(XLOG_DEBUG,
X			"Link_copy: file '%s', length %d instead of %d bytes",
X				name, total, count );
X			goto error;
X		}
X		if( (l = write( Link_fd, buf, i )) != i ){
X			if( l < 0 ){
X			logerr(XLOG_INFO,"Link_copy: write error while sending '%s' to %s",
X				name, RM);
X			} else {
X			logerr(XLOG_INFO,"Link_copy: partial write sending '%s' to %s",
X				name, RM);
X			}
X			goto error;
X		}
X	}
X	if( i < 0 ){
X		logerr(XLOG_INFO,"Link_copy: file '%s' read error", name);
X		goto error;
X	} else if( total != count ){
X		log(XLOG_DEBUG,
X		"Link_copy: file '%s', copied %d instead of %d bytes to %s",
X			name, total, count, RM);
X		goto error;
X	}
X	if(Debug>4)log(XLOG_DEBUG,"Link_copy: file '%s' %d bytes to %s",
X		name,count,RM);
X	return( JSUCC );
error:
X	Link_close();
X	return( JFAIL );
X}
X
Link_ack( c )
X	int c;
X{
X	char buf[1];
X	int succ;
X
X	buf[0] = c;
X	succ = JFAIL;
X
X	if( write( Link_fd, buf, 1 ) != 1 ){
X		if(Debug>4)logerr(XLOG_DEBUG,"ack '%d' write error to %s",c,RM);
X	} else {
X		succ = JSUCC;
X		if(Debug>4)log(XLOG_DEBUG,"ack '%d' sent to site %s",c,RM);
X	}
X	if( succ != JSUCC ){
X		Link_close();
X	}
X	return( succ );
X}
X
X/***************************************************************************
X * Link_get()
X * reads all information from the link, and prints on stdout
X ***************************************************************************/
Link_get()
X{
X	int i;				/* ACME Integers, Inc. */
X	char buf[BUFSIZ];	/* buffer */
X
X	if( Link_fd == 0 ){
X		fatal( XLOG_INFO, "Link_copy: Link_fd is not open");
X	}
X
X	while( (i = read( Link_fd, buf, sizeof(buf)) ) > 0 ){
X		(void)fwrite( buf, 1, i, stdout );
X	}
X}
X
X/***************************************************************************
X * Link_port_num()
X * - look up the service in the service directory using getservent
X * - if the port number has been set, don't do it a second time.
X * - Note that Setup_test will set the port number if necessary.
X ***************************************************************************/
X
Link_port_num()
X{
X	static char *name = SERVERNAME;
X	static char *prot = SERVERPROT;
X	struct servent *sp;
X	if( Lpr_port_num == 0 ){
X		if( ( sp = getservbyname( name, prot )) == 0 ){
X			logerr_die( XLOG_CRIT, "Get_port_nun: getservbyname(%s,%s) failed",
X				name, prot );
X		}
X		Lpr_port_num = sp->s_port;
X	}
X	return( Lpr_port_num );
X}
END_OF_FILE
if test 12422 -ne `wc -c <'src/link_support.c'`; then
    echo shar: \"'src/link_support.c'\" unpacked with wrong size!
fi
# end of 'src/link_support.c'
fi
if test -f 'src/lpr.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/lpr.c'\"
else
echo shar: Extracting \"'src/lpr.c'\" \(10711 characters\)
sed "s/^X//" >'src/lpr.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: lpr.c
X * lpr - off line print
X ***************************************************************************
X * Revision History: Created Mon Jan 25 14:04:26 CST 1988
X * $Log:	lpr.c,v $
X * Revision 3.2  88/06/24  17:56:01  papowell
X * MODS for VAX 4.3BSD UNIX
X * 
X * Revision 3.1  88/06/18  09:34:46  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 2.1  88/05/09  10:09:00  papowell
X * PLP: Released Version
X * 
X * Revision 1.6  88/04/27  18:02:45  papowell
X * The SIGCHLD signal has an odd behaviour on some systems.  Modified so that
X * it will not get set UNLESS processes are started;  also,  it is reset
X * to SIG_DFL, not SIG_IGN.
X * 
X * Revision 1.5  88/04/15  13:06:09  papowell
X * Std_environ() call added, to ensure that fd 0 (stdin), 1 (stdout), 2(stderr)
X * have valid file descriptors;  if not open, then /dev/null is used.
X * 
X * Revision 1.4  88/04/06  12:13:28  papowell
X * Minor updates, changes in error message formats.
X * Elimination of the AF_UNIX connections, use AF_INET only.
X * Better error messages.
X * 
X * Revision 1.3  88/03/25  15:00:16  papowell
X * Debugged Version:
X * 1. Added the PLP control file first transfer
X * 2. Checks for MX during file transfers
X * 3. Found and fixed a mysterious bug involving the SYSLOG facilities;
X * 	apparently they open files and then assume that they will stay
X * 	open.
X * 4. Made sure that stdin, stdout, stderr was available at all times.
X * 
X * Revision 1.2  88/03/11  19:28:47  papowell
X * Minor Changes, Updates
X * 
X * Revision 1.1  88/03/01  11:08:41  papowell
X * Initial revision
X * 
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: lpr.c,v 3.2 88/06/24 17:56:01 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X#include "lpr.h"
X
X/***************************************************************************
X * SYNOPSIS
X *      lpr [ -PPrinter ] [ -#num ] [ -C class ] [ -J job ] [
X *      -RremoteAccount ] [ -m[mailTo] ] [ -T title ] [-i[numcols]]
X *      [ -1234 font ] [ -wnum ] [ -Zzoptions ] [ -Uuser ] [ -HHost
X *      ] [ -Ffilter ] [ -bhrs ] [ -Dn ] [ -X ] [ filename ...  ]
X * DESCRIPTION
X *      Lpr uses a spooling server to print the named files when
X *      facilities become available.  If no Names appear, the stan-
X *      dard input is assumed.
X *      -PPrinter  Output to the specified Printer
X *      -F?  Filter or format specification
X *      -p text to be printed using pr(1) to format the files.
X *      -l (literal) text with control characters to be printed
X *      -t output from troff(1)
X *      -n output from DITROFF
X *      -d output from tex(l) (DVI format from Stanford).
X *      -g standard plot data as produced by the plot(3X) routines
X *      -v a raster image for devices like the Benson Varian.
X *      -c data produced by cifplot(l).
X *      -f same as -Fr, FORTAN carriage control
X *      -m[mailTo] Send mail upon completion
X *      -s Use symbolic links.
X *      -J jobname  Specify the job name to print on the burst page
X *      -T title specify the title used by pr(1);
X *      -wwidth  specify the page width for pr.
X *      -C class or priority (A - Z)
X *      -R remoteAccount
X *      -#num number of copies of each file to be printed.
X *      -i[numcols] Cause the output to be indented
X *      -b The files are assumed to contain binary data
X *      -Z extra options
X *      -D[n] debug level
X *      -X Use an Xperimental version of LPD
X *      -Uuser Used by root process to specify a user
X *      -HHost Used by root process to specify a Host
X ****************************************************************************
X * Implementation:
X * 	Each time lpr is invoked it creates a "job" entry in the appropriate
X * spool directory.  Each job consists of a control file and zero or more
X * data files.  The control file contains lines that specify the job
X * parameters, such as job Name, etc., and the Names of the data files.
X *      Control file format
X *      First character in the line flags kind of entry, remainder of line is
X *          the arguemnt.
X *
X *		C -- "class Name" on banner page
X *		H -- "Host Name" of machine where lpr was done
X *		I -- "indent" amount to indent output
X *		J -- "job Name" on banner page
X *		L -- "literal" user's Name to print on banner
X *		M -- "mail" to user when done printing
X *		N -- "Name" of file (used by lpq)
X *		P -- "Person" user's login Name
X *		R -- account id  for charging 
X *		U -- "unlink" Name of file to remove after we print it
X *		W -- "width" page width for PR
X *		X -- "header" header title for PR
X *		Z -- xtra options to filters 
X *
X *	Lower case letters are formats, and are together with the Name
X *      of the file to print
X *		f -- "file Name" Name of text file to print
X *		l -- "file Name" text file with control chars
X *		p -- "file Name" text file to print with pr(1)
X *		t -- "file Name" troff(1) file to print
X *		n -- "file Name" ditroff(1) file to print
X *		d -- "file Name" dvi file to print
X *		g -- "file Name" plot(1G) file to print
X *		v -- "file Name" plain raster file to print
X *		c -- "file Name" cifplot file to print
X ***************************************************************************/
X
X/***************************************************************************
X * main(int argc, char **argv)
X * 1. get the Host computer Name and user Name
X * 2. get the parameters and other information
X * 3. set up signals to handle abrupt termination.
X * 4. set up the control file for the job
X * 5. if we are spooling from stdin, copy stdin to a file.
X * 6. if we have -p option (use pr), run the input files through pr
X *    and save to a single file.
X * 7. create a job entry
X * 8. start the server
X ****************************************************************************/
X
extern int cleanup();
X
main(argc, argv)
X	int argc;
X	char **argv;
X{
X	int i;						/* ACME Integers, Inc. */
X	struct passwd *pw_ent;		/* user entry in /etc/passwd */
X	int fd, job_size;	/* size of file and job */
X
X	/*
X	 * set umask to avoid problems with user umask
X	 */
X	(void)umask(0);
X	/*
X	 * Set fd 0, 1, 2 to /dev/null if not open
X	 */
X	Std_environ();
X#	ifdef XPERIMENT
X		Setup_test();
X#	endif XPERIMENT
X
X	/*
X     * set up the pathnames for information files
X	 */
X	Tailor_names();
X	/*
X	 * set up the From information
X	 */
X	From = Host;
X	/*
X	 * get user name
X	 */
X	if( (pw_ent = getpwuid( getuid() )) == 0 ){
X		logerr_die( XLOG_INFO, "getpwuid failed on uid %d", getuid());
X	}
X	(void)strcpy( LOGNAME, pw_ent->pw_name );
X	Person = LOGNAME;
X	if( getuid() == 0 ){
X		/* we are being invoked by root */
X		Is_root = 1;
X	}
X	/*
X	 * Get the home directory for the use
X	 */
X	(void)Get_home();
X	/*
X	 * setup parameters
X	 */
X	Setup_parms(argc, argv);
X	/*
X	 * set up chatty information for user
X	 */
X	if( BNRNAME[0] == 0 ){
X		if( strcmp( LOGNAME, pw_ent->pw_name ) == 0 ){
X			(void)strncpy( BNRNAME, pw_ent->pw_gecos, MAXPARMLEN );
X		} else {
X			(void)strcpy( BNRNAME, LOGNAME );
X		}
X	}
X	/*
X	 * set signals
X	 */
X	(void)signal(SIGPIPE, SIG_IGN);
X	(void)signal(SIGHUP, cleanup);
X	(void)signal(SIGINT, cleanup);
X	(void)signal(SIGQUIT, cleanup);
X	(void)signal(SIGTERM, cleanup);
X	/**************************************************************************
X	 * The following possibilities exist:
X	 *                         Files              No Files
X	 * p format,no 'f' PF      PR ->spool         input->PR -> spool
X	 * p format, 'f' PF        PR->PF->spool      input->PR->PF->spool
X	 * ? format, no PF         files->spool files input->spool
X	 * ? format, PF            PF(files) -> file  input->spool
X	 * 
X	 * If we have a prefilter for a file format,  we have to run the files
X	 * through the prefilter,  and spool the output of the prefilter.
X	 * The prefilter will create a single output file which is printed
X	 *
X	 * If we have 'p' format,  we will create a printer process, and run
X	 * its output into a temporary file in the spool directory.
X	 * If there are no names specified, we copy the input to a temporary
X	 * file in the spool directory.  The Read_stdin file is the name of the
X	 * output file.  This is also used to hold the name of the output of
X	 * the PR program.
X	 *
X	 * If we have a prefilter,  we place its output in the Read_filter
X	 * file.
X	 *************************************************************************/
X	if( Format == 'p' ){
X		/*
X		 * run PR and put the output in a spool file
X		 */
X		if(Debug>3)log(XLOG_DEBUG,"using PR" );
X		if( Run_pr() == 0 ){
X			Diemsg( "nothing to print" );
X		}
X		Format = 'f';
X	} else if( Parmcount == 0 ){
X		if(Debug>3)log(XLOG_DEBUG,"Copying stdin" );
X		if( Copy_stdin()  == 0 ){
X			Diemsg( "nothing to print" );
X		}
X	} else {
X		/*
X		 * check to see that the input files are printable
X		 */
X		job_size = 0;
X		for(i = 0; i < Parmcount; ++i ){
X			fd = Is_printable( Parms[i].str, &LO_statb );
X			if( fd < 0 ){
X				Parms[i].str = 0;
X			} else {
X				job_size = 1;
X			}
X			(void)close(fd);
X		}
X		if( job_size == 0 ){
X			Diemsg( "nothing to print" );
X		}
X	}
X	/*
X	 * now we check for prefilter;
X	 * if we have one, then we have to run all the files through it;
X	 * we invoke the prefilter with the appropriate parameters.
X	 * The output of the prefilter (on stdout) is spooled
X	 */
X	if( Prefilter_name[Format - 'a'] ){
X		/* yes, we have prefilter */
X		if(Debug>3)log(XLOG_DEBUG,"Prefilter %c '%s'",Format,
X			Prefilter_name[Format - 'a'] );
X		if( Do_prefilter(Prefilter_name[Format - 'a'], Read_stdin) <= 0 ){
X			Diemsg( "nothing to print" );
X		}
X	}
X	/*
X	 * we now either have to spool a single file, produced by the
X	 * PR and/or Prefilters, or we have to spool all the input files
X	 */
X	Make_job();
X	/*
X	 * start up the server
X	 */
X	(void)Startserver();
X	exit( 0 );
X}
X/***************************************************************************
X * cleanup()
X * remove the temp files
X ***************************************************************************/
X
cleanup()
X{
X	(void)sigblock(sigmask(SIGCHLD)|sigmask(SIGHUP)
X		|sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
X	if( geteuid() && geteuid() != getuid() ){
X		/*
X		 * whoops, we must have been caught as user
X		 * try and force to EUID root
X		 */
X		if( setreuid( geteuid(), 0 ) < 0 ){
X			logerr( XLOG_INFO, "cleanup: setreuid( %d, %d) failed",
X				geteuid(), 0 );
X			exit(1);
X		}
X	}
X	if( geteuid() == 0 && setreuid( -1, Daemon_uid ) < 0 ){
X		logerr( XLOG_INFO, "cleanup: setreuid( %d, %d) failed",
X			-1, Daemon_uid );
X			exit(1);
X	}
X	Remove_temp();
X	exit( 1 );
X}
END_OF_FILE
if test 10711 -ne `wc -c <'src/lpr.c'`; then
    echo shar: \"'src/lpr.c'\" unpacked with wrong size!
fi
# end of 'src/lpr.c'
fi
if test -f 'src/lpr_filters.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/lpr_filters.c'\"
else
echo shar: Extracting \"'src/lpr_filters.c'\" \(11355 characters\)
sed "s/^X//" >'src/lpr_filters.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: lpr_filters.c
X * filter programs for LPR
X * Supports the reading and enqueuing of input
X ***************************************************************************
X * Revision History: Created Sat Jan 30 08:06:50 CST 1988
X * $Log:	lpr_filters.c,v $
X * Revision 3.1  88/06/18  09:34:53  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 2.1  88/05/09  10:09:11  papowell
X * PLP: Released Version
X * 
X * Revision 1.3  88/03/25  15:00:27  papowell
X * Debugged Version:
X * 1. Added the PLP control file first transfer
X * 2. Checks for MX during file transfers
X * 3. Found and fixed a mysterious bug involving the SYSLOG facilities;
X * 	apparently they open files and then assume that they will stay
X * 	open.
X * 4. Made sure that stdin, stdout, stderr was available at all times.
X * 
X * Revision 1.2  88/03/11  19:28:36  papowell
X * Minor Changes, Updates
X * 
X * Revision 1.1  88/03/01  11:08:45  papowell
X * Initial revision
X * 
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: lpr_filters.c,v 3.1 88/06/18 09:34:53 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X#include "lpr.h"
X
X/***************************************************************************
X * Run_pr()
X *   Copies input the PR program; temp file name left in Read_stdin
X *   Returns: 0 if nothing, 1 otherwise
X * Copy_stdin()
X *   Copies input to a temporary file; temp file name left in Read_stdin
X *   Returns: 0 if nothing, 1 otherwise
X * char *Copy_file( int infile, char *name ) 
X *    copies file to temp file, returns name of temp file
X * int Open_SD(char *s) Open the file in the spool directory
X ***************************************************************************/
X
X/***************************************************************************
X * Run_pr()
X * 1. Gets the name of a temporary file for the output
X * 2. Sets up the PR command
X * 3. Forks a process
X * 4. Arranges the process output goes to the output file
X * 5. Waits for PR to complete
X ***************************************************************************/
char * estr3();		/* copies 3 strings to end */
X
Run_pr()
X{
X	int fd;				/* Data file */
X	char cmdbuf[BUFSIZ];	/* build up the command here */
X	char buf[BUFSIZ];		/* local buf up the command here */
X	char *bp;				/*  bp points to cmdbuf */
X	char *ep;				/*  ep is limit */
X	int pid;				/* pid of pr process */
X	union wait status;		/* the status.w_status is the integer value */
X	int i;					/* ACME Integer, Inc. */
X	struct stat statb;		/* for stating the output file */
X
X	/*
X	 * get name of the data file
X	 */
X	Read_stdin = Get_tmp_data();
X	fd = Open_SD( Read_stdin );
X	/*
X	 * set up the printer name
X	 */
X	if( PR == 0 || *PR == 0 ){
X		Diemsg( "there is no pr program specified for -p format");
X	}
X	/* set up the command */
X	ep = cmdbuf + sizeof(cmdbuf);
X	bp = estr3( cmdbuf, PR,(char *)0,(char *)0, ep );
X	/*
X	 * set the width, length, and title flags
X	 */
X
X	if( PWIDTH[0] ){
X		bp = estr3( bp, " -w", PWIDTH, " ", ep );
X	} else if( PW ){
X		(void)sprintf( buf, " -w%d ", PW );
X		bp = estrcp( bp, buf, ep );
X	}
X	if( PL ){
X		(void)sprintf( buf, "-l%d ", PL );
X		bp = estrcp( bp, buf, ep );
X	}
X	if( PRTITLE[0] ){
X		bp = estr3( bp, "-h '", PRTITLE, "' ", ep );
X	} else if( JOBNAME[0] ){
X		bp = estr3( bp, "-h '", JOBNAME, "' ", ep );
X	} else if( Parmcount == 0 ){
X		bp = estr3( bp, "-h '", "(stdin)", "' ", ep );
X	}
X	/*
X	 * Put the file names in the list
X	 */
X	for( i = 0; i < Parmcount; ++i ){
X		bp = estr3( bp, Parms[i].str, " ", (char *)0, ep );
X	}
X	if( bp == 0 ){
X		Diemsg( "pr command is too long: %s", cmdbuf);
X	}
X	if(Debug>2)log(XLOG_DEBUG, "pr command is '%s'", cmdbuf);
X	/*
X	 * start up the pr process
X	 */
X	if( (pid = fork()) < 0 ){
X		logerr_die(XLOG_INFO,"Run_pr: fork failed");
X	} else if( pid == 0 ){
X		if( dup2(fd,1) < 0 ){
X			logerr_die(XLOG_INFO,"Run_pr: dup2 failed" );
X		}
X		if( setreuid( getuid(), getuid() )< 0 ){
X			logerr_die(XLOG_INFO,"setreuid failed" );
X		}
X		mexecv( cmdbuf );
X		exit(1);
X	}
X	/* wait for printer */
X	while ((i = wait(&status)) > 0 && i != pid);
X	if( i < 0 || status.w_status ){
X		logerr_die(XLOG_INFO,"pr failed (%s)", Decode_status(&status) );
X	}
X	if(Debug>3)log(XLOG_DEBUG,"pr done successfully");
X	if( fstat( fd, &statb ) <0 ){
X		logerr_die(XLOG_INFO, "Run_pr: cannot stat output file %s", Read_stdin);
X	}
X	if(Debug>3)log(XLOG_DEBUG,"Run_pr: %s is %d",Read_stdin,statb.st_size);
X	(void)close(fd);
X	return( statb.st_size != 0 );
X}
X
static char *
estr3( s, s1, s2, s3, e )
X	char *s, *s1, *s2, *s3, *e;
X{
X	if( s1 ) s = estrcp( s, s1, e );
X	if( s2 ) s = estrcp( s, s2, e );
X	if( s3 ) s = estrcp( s, s3, e );
X	return( s );
X}
X
X/***************************************************************************
X * int Open_SD(char *s)
X * Open the name of the file in the spool directory
X * 1. Prepend the SD name
X * 2. Create the file with the desired perms
X * Returns: fd if successful; dies otherwise
X ***************************************************************************/
X
Open_SD( s )
X	char *s;
X{
X	char buf[BUFSIZ];
X	int fd;
X
X	(void)sprintf(buf, "%s/%s", SD, s);
X	fd = Exlockcf( buf );
X	if( fd < 0 ){
X		logerr_die( XLOG_INFO, "Open_SD: could not open and lock %s", buf );
X	}
X	if(Debug>3)log(XLOG_DEBUG,"Open_SD: file %s, fd %d", buf, fd );
X	return( fd );
X}
X
X/***************************************************************************
X * Copy_stdin()
X * 1. Gets the name of a temporary file for the output
X * 2. Copies stdin to the file
X * 3. Returns 0 if empty file, 1 otherwise
X ***************************************************************************/
X
Copy_stdin()
X{
X	int fd;					/* Data file */
X	char buf[BUFSIZ];		/* local buf up the command here */
X	int n, i;				/* bytes read */
X	int count;				/* number of bytes */
X	long blocks;				/* number of blocks */
X
X	/*
X	 * get name of the data file
X	 */
X	Read_stdin = Get_tmp_data();
X	fd = Open_SD( Read_stdin );
X
X	count = 0;
X	blocks = 0;
X	while( (n = fread( buf, 1, sizeof(buf), stdin )) > 0 ){
X		count += n;	/* update count */
X		while( count >= 1024 ){
X			count -= 1024;
X			++blocks;
X		}
X		if( MX && blocks > MX ){
X			Diemsg( "input from stdin exceeds maximum file size limits" );
X		}
X		i = write( fd, buf, n );
X		if( i != n ){
X			logerr_die(XLOG_INFO,"Copy_stdin: cannot write %s",Read_stdin);
X		}
X	}
X	if( ferror( stdin ) ){
X		Diemsg( "error reading from stdin" );
X	}
X	(void)close(fd);
X	if( count ){
X		++blocks;
X	}
X	if(Debug>3)log(XLOG_DEBUG,"Copy_stdin: %s is %d blocks", Read_stdin,blocks);
X	return( blocks != 0 );
X}
X/***************************************************************************
X * char *Copy_file( int *in_fp, char *in_file )
X * 1. Gets the name of a temporary file for the output
X * 2. Copies file to the temporary file
X * Returns: temporary file name
X ***************************************************************************/
X
char *
Copy_file( in_fd, in_file, statb )
X	int in_fd;
X	char *in_file;
X	struct stat *statb;
X{
X	int out_fd;				/* Data file */
X	char buf[BUFSIZ];		/* local buf for IO */
X	int n, i;				/* bytes read */
X	int count;				/* number of bytes */
X	long blocks;			/* number of blocks */
X	char *fname;			/* file name */
X
X	/*
X	 * get name of the data file
X	 */
X	fname = Get_tmp_data();
X	out_fd = Open_SD( fname );
X
X	count = 0;
X	blocks = 0;
X	while( (n = read( in_fd, buf, sizeof(buf))) > 0 ){
X		count += n;	/* update count */
X		while( count >= 1024 ){
X			count -= 1024;
X			++blocks;
X		}
X		if( MX && blocks > MX ){
X			Diemsg( "file %s too large",in_file);
X		}
X		i = write( out_fd, buf, n );
X		if( i != n ){
X			logerr_die(XLOG_INFO,"Copy_file: cannot write to file %s",in_file);
X		}
X	}
X	if( n < 0 ){
X		logerr_die( XLOG_INFO,"Copy_file: error reading from %s", in_file );
X	}
X	if( fstat( out_fd, statb ) < 0 ){
X		logerr_die( XLOG_INFO,"Copy_file: cannot stat %s", fname);
X	}
X	(void)close( out_fd );
X	return( fname );
X}
X/***************************************************************************
X * Do_prefilter( char *cmd, char *file )
X *
X *	Prefilter handler
X *  1. Sets up a prefilter command.
X *  filtername arguments \   <- from filtername
X *      -PPrinter -wwidth -llength -xwidth -ylength [-c] [-iindent] \
X *      [-Zoptions] [-Cclass] [-Jjob] [-Raccntname] -nlogin -hHost
X *      -Fformat [file]
X *     Note: the filter parameter is of the form "filter,X", where
X *     output format is specified.  If there is no specified format,
X *     'f' will be used.
X *  2. Gets a temporary file for output
X *  3. If file is explicitly named,  uses that for input instead of
X *     parameter files.
X *  4. Forks and runs the command.
X *  5. Filter must return 0 for successful status, otherwise we abort
X ***************************************************************************/
X
Do_prefilter( cmd, file )
X	char *cmd;
X	char *file;
X{
X	char cmdbuf[BUFSIZ];	/* build up the command here */
X	union wait status;		/* the status.w_status is the integer value */
X	char *cp, *ep;			/* ACME Pointers, Inc. */
X	int i, l, pid;			/* ACME Integers, Inc. */
X	int new_format = 'f';	/* new format */
X	int fd;					/* the output file */
X	struct stat statb;		/* for stating the output file */
X	
X	/*
X	 * get the output format
X	 */
X	(void)strcpy(cmdbuf, cmd);
X	l = strlen( cmdbuf );
X	if( l > 2 ){
X		if( cmdbuf[l-2] == ',' ){
X			new_format = cmdbuf[l-1];
X			cmdbuf[l-2] = 0;
X		}
X	}
X	if( !isascii(new_format) || !islower(new_format)){
X		fatal(XLOG_INFO, "bad prefilter new format, %s", cmd);
X	}
X	/*
X	 * set up the basic filter command 
X	 */
X	AF = 0;
X	cp = Setup_filter( Format, cmdbuf );
X	Format = new_format;
X	ep = cmdbuf+sizeof(cmdbuf);
X	/*
X	 * copy command to buffer
X	 */
X	cp = estrcp( cmdbuf, cp, ep );
X
X	/*
X	 * add the file names
X	 */
X	if( file ){
X		/*
X		 * we have an explicitly named file
X		 */
X		cp = estrcp( cp, " ", ep );
X		cp = estrcp( cp, file, ep );
X	} else {
X		for( l = 0; l < Parmcount; ++l ){
X			cp = estrcp( cp, " ", ep );
X			cp = estrcp( cp, Parms[l].str, ep );
X		}
X	}
X	if( cp == 0 ){
X		fatal( XLOG_INFO, "Do_prefilter: command too long: %s", cmd);
X	}
X	if(Debug>3)log(XLOG_DEBUG, "Do_prefilter: command '%s'", cmdbuf);
X	/*
X	 * get the output file name
X	 */
X	Filter_out = Get_tmp_data();
X	fd = Open_SD( Filter_out );
X
X	/*
X	 * start the prefilter up and wait for output
X	 */
X	if( (pid = fork()) < 0 ){
X		logerr_die(XLOG_INFO,"Do_prefilter: fork failed");
X	} else if( pid == 0 ){
X		if( dup2(fd,1) < 0 ){
X			logerr_die(XLOG_INFO,"Do_prefilter: dup2 failed" );
X		}
X		if( setreuid( getuid(), Daemon_uid ) < 0 ){
X			logerr_die(XLOG_INFO,"Do_prefilter: setreuid failed" );
X		}
X		mexecv( cmdbuf );
X		logerr_die(XLOG_INFO,"Do_prefilter: execv failed");
X	}
X	/*
X	 * wait for prefilter
X	 */
X	while ((i = wait(&status)) > 0 && i != pid) ;
X	if( i < 0 || status.w_status ){
X		logerr_die(XLOG_INFO,"Do_prefilter: prefilter %d failed (%s)", i,
X			Decode_status( &status ) );
X	}
X	if(Debug>3)log(XLOG_DEBUG,"Do_prefilter: prefilter successful");
X	if( fstat( fd, &statb ) <0 ){
X		logerr_die(XLOG_INFO, "Do_prefilter: cannot stat output file %s",
X			Filter_out);
X	}
X	if(Debug>3)log(XLOG_DEBUG,"Do_prefilter: %s is %ld",
X			Filter_out,statb.st_size);
X	(void)close(fd);
X	return( statb.st_size != 0 );
X}
END_OF_FILE
if test 11355 -ne `wc -c <'src/lpr_filters.c'`; then
    echo shar: \"'src/lpr_filters.c'\" unpacked with wrong size!
fi
# end of 'src/lpr_filters.c'
fi
echo shar: End of archive 8 \(of 16\).
cp /dev/null ark8isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 16 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.



More information about the Comp.sources.unix mailing list