rsalz@bbn.com (Rich Salz) (09/15/88)
Submitted-by: papowell@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@uunet.uu.net.