Subject: v16i024: Public lineprinter spooler package, Part11/16 Newsgroups: comp.sources.unix Sender: sources Approved: rsalz@uunet.UU.NET Submitted-by: papowell@julius.cs.umn.edu Posting-number: Volume 16, Issue 24 Archive-name: plp/part11 #! /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 'doc/PLP/11.t' <<'END_OF_FILE' X.ig X$Header: 11.t,v 1.1 88/05/21 18:39:52 papowell Locked $ X$log$ X.. X.bp X.NH 1 Installation and Testing X.PP The following is a summary of the installation and test procedures for the PLP software. X.NH 2 Source Files X.PP As distributed, all source and related files for the software have been collected under a common directory X$(PLP), The $(PLP) directory has the following structure. X.DS X.DT X.ta 12m +4n +4n X.L X.SM README -- brief summary Makefile -- calls {bin, filters, utilities}/Makefile bin/ -- directory for binaries and executables bin/Makefile -- Makefile for executables doc/ -- documentation source, this document filters/ -- output filters lint/ -- directory for lint output man/ -- man pages src/ -- source for lpd, lpr, lpc, etc. test/ -- test programs and files utilities/ -- source for pr, cpr and other handy print formatters. printcap/ -- a method to organize printcap entries X.DE X.NH 2 Printcap And Printer Permissions Files X.PP The PLP software uses a different organization of printcap and permissions files than the Berkeley LPD. All of the PLP related control and informations files are gathered in X.L /usr/spool/lpd . XFor example: X.DS X.nf X.SM X.L X.ta 15n +4n +4n +4n 8i X.vs -2 X.R X.LG X/usr/spool/lpd/printcap. # printcap for X/usr/spool/lpd/printer_perms. # printer permissions for X/usr/spool/lpd/lpd.lock. # lpd daemon lock for X/usr/spool/lpd/log. # lpd daemon log for X.vs +2 X.LG X.R X.DE In a networked base file system, this allows a single spool directory to be shared among all the systems using PLP. In addition, only system which are performing unspooling operations will need to have an LPD daemon running. XFinally, care has been taken to ensure that all accesses to the shared files are done by user id X.L daemon . X.PP In order to update an existing system, all that needs to be done is to create a spool directory and provide the above files. The file X.L $(PLP)/test/printer_perms.all is a prototype printer permissions file that does not provide many restrictions. X.KF X.in +1i X.nf X.DT X.L X.SM X.vs -2 X.ta 4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n 8i X#!/bin/csh X# Creating the /usr/spool/lpd directory set h=<<<>>>; # specify your host name mkdir /usr/spool/lpd ln -s /etc/printcap /usr/spool/lpd/printcap.${h} cp $(PLP)/test/printer_perms.all /usr/spool/lpd/printer_perms.${h} X.vs +2 X.sp .5v X.R X.LG X.in -1i X.ce XFigure 11.1 Creating Directories X.KE X.NH 2 Compilation and Installation X.PP The X.L bin directory is used to hold binaries. During the initial installation procedure, you should copy the X.L Makefile from the X.L src directory, and set any system dependent flags in the Makefile. The flags X.L IS_ are used to specify the system type, and cause conditional compilation of entries in the X.L src/lp.h file. After checking the flags and their implications, X.L "make all" can be used to compile and link the programs. X.PP As distributed, the X.L XPERIMENT compilation flag is set in the Makefile, and causes a test verion of the PLP softwar to be generated. It is strongly suggested you try the test or experimental version first, i.e.- compile with the XPERIMENT option enabled, and then try a fully functional version. X.NH 2 Test Version X.PP A test version of the spooling software can be generated by compiling with the XPERIMENT flag set. This causes X.L /tmp/printcap., X.L /tmp/printer_perms., and a non-priviledged INET port to be used, rather than X.L /usr/spool/lpd/printcap., and the priviledged TCP/IP printer server port. X.PP The PLP distribution X.B test directory contains prototype or debugging versions of printcap, printer_perms, and other files; X.B test/Makefile will generate and install the necessary directories, etc., and will install the necessary filters. The test devices have their spool directories in /tmp, and should be trivial to install. Run the tests listed below to ensure that the various programs are working. Note that all the functionality of the PLP software can be checked out as an ordinary user, and you do NOT need to run as ROOT. X.PP In summary, to make the test verions, do the following. X.IP 1). Create a bin directory, copy the Makefile from src, edit the Makefile and set the various system dependencies. X.IP 2). Run X.L "make all" . At this point you will have all of your binaries in the bin directory, where you should leave them. Set up your shell $path or $PATH to use X$(PLP)/bin directory ahead of /usr/ucb, otherwise you will use the existing LPD programs. X.IP 3). Go to the X.L test directory, read the X.L test/README file, edit the X.L test/Makefile according to directions, and do X.L "make bin" . in the X.L test directory. This generates some executables and places them in the /tmp directory, as well as installing a test version of the printer permission file. X.IP 4). Now you should take a nap, play rogue, or whatever you do to relax. The next part is not fun. X.NH 3 Test 1\- LPC, LPR, LPQ X.PP To run the first tests, change to the X.L test directory and do X.L "make test1" . This installs the printcap file of Figure 11.2 in /tmp/printcap: X.KF X.in +1i X.nf X.DT X.L X.SM X.vs -2 X.ta 4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n 8i X# X# TEST VERSION OF PRINTCAP FILE: X# Test 1: simple lpr functions X# test:\e X :fx=flpdnt:ex:\e X :pw#75:pl#66:rw:\e X :br#9600:fs#040:fc#011:\e X :ty=new 19200 even -tabs tandem:\e X :lp=output:\e X :if=/tmp/filter -delay30:\e X :of=/tmp/lpf -D5:\e X :sd=/tmp/test: X.vs +2 X.sp .5v X.R X.LG X.in -1i X.ce XFigure 11.2 Test 1 Printcap File X.KE X.PP You should look at the code for the X.L filter and the X.L lpf programs which were created by the X.L "make bin" . The X.L filter program is a handy dandy debugging filter. The X.L lpf filter simply copies stdin to stdout, and suspends itself when it detects the stop string. The X.L lpf filter source is the skeleton for any new filters that are needed. X.PP You can test the functionality of the lpq, and lpr programs by using the illustrated commands. Sample output has been provided. X.nf X.vs -2 X.DT X.SM X.L X.ta 12n +4n +4n +4n +4n +4n +4n +4n X%>lpq -D5 #should display queue (empty) lpq: pid=4233, LOG_DEBUG, First_printer: simple at Fri May 20 17:02:08 1988 lpq: simple- pid=4233, LOG_DEBUG, Get_Printer: First_printer 'simple' at Fri May 20 17:02:08 1988 lpq: simple- pid=4233, LOG_DEBUG, Get_printer: using Printer simple at Fri May 20 17:02:08 1988 lpq: simple- pid=4233, LOG_DEBUG, Readlockfile: lockfile 'lock' at Fri May 20 17:02:08 1988 lpq: simple- pid=4233, LOG_DEBUG, Readlockfile: lock, perms 0100644 at Fri May 20 17:02:08 1988 lpq: simple- pid=4233, LOG_DEBUG, Readlockfile: 'lock' pid 0 len 0 at Fri May 20 17:02:08 1988 lpq: simple- pid=4233, LOG_DEBUG, Checklockfile: lock server 0 at Fri May 20 17:02:08 1988 lpq: simple- pid=4233, LOG_DEBUG, printstatus: ST status at Fri May 20 17:02:08 1988 Printer 'simple' (attila.cs.umn.edu): X work done at Wed May 18 09:38:59 1988 X X%>lpr xx #place job in queue lpr: Warning- File 'xx' not printed: cannot access it lpr: Fatal error- nothing to print X X%>echo hi | lpr #place job in queue lpr: simple- Startserver: host 'attila.cs.umn.edu' server for 'simple' X not started - Connection refused at Fri May 20 17:08:51 1988 X X%>lpq #should display queue one entry Printer 'simple' (attila.cs.umn.edu): Warning: no server present X Rank Owner Pr Job Host Files Size X 1st papowell Z 13 attila (stdin) 3 X X%>lpc #play with lpc X>status Queue Jobs Queueing Printing simple 1 enabled enabled (no server) X X>disable simple simple: queueing disabled X>status Queue Jobs Queueing Printing simple 1 disabled enabled (no server) X>quit X.R X.LP X.NH 3 Test 2\- LPD Functionality X.PP Use the commands: X.ti +.5i X.L "echo >/tmp/error" X.ti +.5i X.L "lpd -D5 -L /tmp/error; tail -f /tmp/error" X.br to create the error log file and to start up ldp. It is best to do this at one terminal, and then do the remaining tests at another terminal. Lucky windowing system users will, of course, simply open another window. You will be amused to watch the lpd spring into action, trying to create servers, etc. The X.L simple server will log into the X.L /tmp/simple/log file. X.PP You can remove /tmp/test/log, and see the interaction of the lpd daemon and the printer server little clearer. To kill the lpd daemon, do the following: X.DS X.DT X.L X.SM lpc lpd ##- prints the lpd daemon id kill # kill off the daemon rm /tmp/test/log # remove the log file echo >/tmp/error lpd -D5 -L /tmp/error tail -f /tmp/error X.R X.DE X.PP If you are curious, try starting multiple X.L "lpd" programs; when X.L lpd is started, it checks for a running daemon, print a message, and then exits. X.PP You can examine the conditions of the servers and other activites by using X.I lpq . Note that the lpq status report includes a chatty informational piece about the job progress. X.PP The OF filter has been carefully created to print out various pieces of information. You can see what this is if you look at /tmp/test/output, where the output is going. You will notice that the IF filter is a shell script, and will do a sleep for a while. You can now test out the various lpq, lpr, and lpc functions. X.NH 3 Test 3 \- Remote Servers X.PP These tests check out the functionality of inter host spooling functions. They have been written so that they will use the local host intitially, but can be extended to the remote host. X.PP In the X.L test direcotory, do X.L "make test2" to install the second form of the printcap file. You will not have to kill the lpd to do this. Now try X.ti +.5i X.L "lpq -Premote" X.br and examine the output. The lpq program will print out the local queue, and then send a message to the remote host (which is the local host) using the INET protocol. This will check out the functionality of the network communication. You can play with lpr, lpc, etc. and check this out. Try the X.I remote functions of the X.I lpc program. X.PP If you have two hosts available, install the PLP software on both of them. XEdit the printcap files so that one of them has the local test, and the other the remote test entry. Don't forget to install and modify the printer_perms file so that the remote host can access the test spool queue. Try the communications out. X.NH 3 Test 4 \- Multiple Servers X.PP This will demonstrate how to have multiple servers for a single spool queue. Install the printcap file by doing make test3. Use lpq to check the status of the spool queue. Now use lpr to send a slog (10 or more) jobs to the multi queue. You can use X.ti +.5i X.L "lpq +10 -a" X.br to monitor what happens. X.NH 3 Test 5 \- Serial Line Control X.PP If you have a printer, attach it to a suitable serial line, and modify the test printcap entry so that it is set up for the printer. I have found that the following procedure works pretty good. X.PP Set the X.B sh X(suppress headers or banners) in the printcap entry, and remove the X.B of entry. Set up a new entry for if, X.B "if=/tmp/serial -d30" and edit the filter program to print out the stty settings. You can now run lpr to try and send things out to the printer. You will either have lots of problems or no problems in communicating with the printer. X.PP Watch out for parity; you may have to fool around with the printer parity settings. I strongly suggest a NO parity setting. Tandem flow control is another tricky area. You may have to open the printer RW using X.B rw to get tandem flow control. This has been a problem with several installations. X.NH 2 Installing a Working Version X.PP Before you install a the PLP software, you should make a copy of the existing print spooler software. There is a set of programs in the X.L backup directory of the PLP distribution that have proven to be very useful. X.IP 1). XEdit the X.L bin/Makefile , and disable the XPERIMENT flag. Do a X.L "make clean; make all" to regenerate the working version. X.IP 2). Create a printer permissions file. You can base this on the version in the X.L test directory. The version in Figure 12.3 is useful for initial installations, and can be found in X.L test/printer_perms.all . X.KF X.nf X.SM X.L X.vs -2 X# Printer permissions data base X# host user printerqueue maxpriority maxpages currentpages X# * is a wildcard X#host user printer perms pr maxpages pages X* root * * * 0 0 #root on any system X* * * R G 0 0 #anybody can do remote X.vs +2 X.LG X.R X.sp .5v X.ce XFigure 11.3 Sample Printer Permissions File X.KE X.IP 3). Do a X.L "make install" and check that permissions have been set correctly. X.IP 4). Using the same tests as outlined above, make sure that lpr, lpc, and lpq are functional. X.IP 5). Start lpd and check that files are unspooled and transferred correctly. When sending files to remote sites, both must be running PLP versions. X.NH 2 Organization of Printcap Information X.PP If you are working in an environment with a large number of different sites and different printers, you may find the programs in the X.L printcap directory handy to manage printcap files. The organization and management is based on the following structure. X.PP XEach printer has a physical location name and a set of aliases. XFor our sample printer, X.L printer_loc , There is a X.L printer_loc.local file which contains a printcap entry suitable for the host which has the device attached, a X.L printer_loc.remote file which contains a printcap entry suitable for a host which can communicate directly to the remote host, and a X.L printer_loc.forward file which contains a printcap entry suitable for a host which forwards jobs to either a local or remote host. XFor example, here are typical entries for the 3 files. These files are stored in the directory X.L printcap/devices . XFigure 12.4 is a sample of several of them. X.KF X.TS center box; lw(2.5) | lw(2.5i) . X.L X.SM dg1_lind23.local dg1_lind23.remote X_ T{ X.nf dg1_lind23.local|dg1:\e X :sd=/usr/spool/dg1_lind23:\e X :lp=/dev/tty09:sy=9600 -even -odd: T} T{ X.nf dg1_lind23.local|dg1:\e X :sd=/usr/spool/dg1_lind23:\e X :rm=attila:rp=dg1_lind23: T} X.TE X.TS center box; lw(2.5i) . X.L X.SM dg1_lind23.forward X_ T{ X.nf dg1_lind23.local|dg1:\e X :sd=/usr/spool/dg1_lind23:\e X :rm=attila:rp=dg1_lind23: T} X.TE X.ce XFigure 11.4 Sample Printcap Files X.KE X.PP XEach host will have a file containing the names of the entries in the printcap file. The X.L genpc program will generate a printcap file from the named printer file by concatenating the printcap information and placing it in a X.L host.printcap file. This file can then be copied to the desired destination. X.NH 2 Checking Out Exisitng Printcaps and Filters X.PP If you have an exisiting printcap file, you can check it out by using the XPERIMENTAL form of PLP before you commit to the actual form. X.IP 1). 3 XFirst, copy the original X.L /etc/printcap file to X.L /tmp/printcap. . X.IP 2). 3 Modify the X.L /tmp/printcap. file so that the X.L /usr/spool directories in it are modified to be X.L /tmp directories. X.IP 3). 3 Compile the test version of the PLP software; there is an entry in the makefile, X.L "make test" which will do this in an efficient manner. X.IP 4). 3 Set your X.L $path to use the test version, and run X.L "checkpc -f" to create the spool direcotories needed by the X.L /tmp/printcap. version. X.IP 4). 3 You can now run a parallel version of the PLP software, and check out the behaviour of devices and filters. END_OF_FILE if test 15498 -ne `wc -c <'doc/PLP/11.t'`; then echo shar: \"'doc/PLP/11.t'\" unpacked with wrong size! fi # end of 'doc/PLP/11.t' fi if test -f 'src/localprinter.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/localprinter.c'\" else echo shar: Extracting \"'src/localprinter.c'\" \(16055 characters\) sed "s/^X//" >'src/localprinter.c' <<'END_OF_FILE' X/*************************************************************************** X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell X *************************************************************************** X * MODULE: localprinter.c X * local Printer queue job handler X *************************************************************************** X * Revision History: Created Wed Jan 13 15:34:42 CST 1988 X * $Log: localprinter.c,v $ X * Revision 3.1 88/06/18 09:34:24 papowell X * Version 3.0- Distributed Sat Jun 18 1988 X * X * Revision 2.4 88/05/21 10:27:48 papowell X * Minor editing X * X * Revision 2.3 88/05/19 10:33:53 papowell X * Fixed open() calls to have a 0 parameter, ie: open(f, perms, 0), where needed X * X * Revision 2.2 88/05/14 10:17:51 papowell X * Use long format for job file names; X * Added 'fd', no forward flag; X * Control file has to have hostname and origination agree. X * X * Revision 2.1 88/05/09 10:08:26 papowell X * PLP: Released Version X * X * Revision 1.5 88/05/09 10:03:18 papowell X * Revised effects of -h option X * X * Revision 1.4 88/05/05 20:08:11 papowell X * Added a NOHEADER option that allows user to suppress banner X * X * Revision 1.3 88/03/25 14:59:44 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/05 15:01:02 papowell X * Minor Corrections, Lint Problems X * X * Revision 1.1 88/03/01 11:08:31 papowell X * Initial revision X * X ***************************************************************************/ X#ifndef lint static char id_str1[] = X "$Header: localprinter.c,v 3.1 88/06/18 09:34:24 papowell Exp $ PLP Copyright 1988 Patrick Powell"; X#endif lint X X#include "lp.h" X char *Setup_filter(); /* setup filter */ static int prjobs; /* numbers of jobs done */ X X/********************************************************************** X * Printinit() X * 1. set up the state to indicated 0 completed jobs X * 2. get the printer ready X **********************************************************************/ Printinit() X{ X int n; X X if(Debug>3)log(XLOG_DEBUG,"Printinit: called with prjobs %d", prjobs ); X n = Print_ready(); X return( n ); X} X X/********************************************************************** X * Printerror() X * called when there is an error in the job handling X * 1. set up the state to indicated 0 completed jobs X * 2. close the printer X **********************************************************************/ void Printerror() X{ X if(Debug>3)log(XLOG_DEBUG,"Printerror: called with prjobs %d", prjobs ); X X prjobs = 0; X Print_close(); X} X/********************************************************************** X * Printfinal() X * called when there is an error in the job handling X * 1. if there are completed jobs, print the trailer X * 2. close the printer X **********************************************************************/ void Printfinal() X{ X if(Debug>3)log(XLOG_DEBUG,"Printfinal: called with prjobs %d", prjobs ); X /* X * print out trailer on close with a job out X */ X if( prjobs ){ X /* X * FQ set means FF needed on open X */ X if( FQ && FF && *FF ){ X if(Debug>3)log( XLOG_DEBUG, "Printfinal: FF on final"); X (void)Print_string( FF ); X } X if( TR && *TR ){ X /* X * TR is sent out X */ X if(Debug>2)log( XLOG_DEBUG, "Printfinal: TR '%s'", TR); X (void)Print_string( TR ); X } X } X prjobs = 0; X Print_close(); X} X X/********************************************************************** X * Printjob X * 1. First scan extracts information which controls printing X * 2. Set any default values not passed X * 3. Second scan does the printing. X * Returns: JBUSY, JFAIL, JSUCC, JABORT X * Side effects: sets information vector CFparm[]. X **********************************************************************/ Printjob(cfp, q) X FILE *cfp; /* control file */ X struct queue *q; /* job entry */ X{ X int i; /* ACME Integer, Inc. */ X char parm[BUFSIZ]; /* holds a line read in */ X char *arg; /* control line argument */ X char opt; /* control line option */ X int jstatus; /* job status */ X int perms = 'R'; /* file perms */ X long jobsize; /* job size */ X X if( fseek( cfp, 0L, 0 ) < 0 ){ X logerr_die(XLOG_INFO, "Printjob: start- fseek failed" ); X } X /* X * set job status X */ X jstatus = JABORT; /* default */ X /* X * initialize the CFparm array, which holds value read from file X */ X for( i = 0; i < 26; ++i ){ X CFparm[i][0] = 0; X } X X /* X * read the control file and extract user information X */ X jobsize = 0; X while(fgets( parm, sizeof(parm), cfp )){ X if( (arg = index(parm, '\n')) == 0 ){ X log(XLOG_INFO,"Printjob: bad control file (%s), no endline", X q->q_name); X goto error; X } X *arg = 0; X opt = parm[0]; X arg = parm+1; X if( !isascii(opt) || ! isalnum( opt )){ X log( XLOG_INFO, "Printjob: bad control file (%s), line('%d'%s)", X q->q_name,opt, arg); X goto error; X } X /* X * copy it into the appropriate place if needed X */ X if( isupper( opt ) ){ X switch( opt ){ X case 'U': X case 'N': break; X default: X if( CFparm[opt - 'A'][0] ){ X log(XLOG_INFO, X "Printjob: duplicate %c parm '%s', previous:'%s'", X opt, arg, CFparm[opt-'A']); X goto error; X } X if( strlen( arg ) >= MAXPARMLEN ){ X log(XLOG_INFO, X "Printjob: control file %s line too long:'%s'", X q->q_name,arg); X goto error; X } X (void)strcpy( CFparm[opt - 'A'], arg ); X break; X } X } else if( islower( opt )){ X if( Job_match( q->q_name, arg) == 0 ){ X logerr(XLOG_INFO,"Printjob: bad control file '%s' entry '%s'", X q->q_name,parm); X goto error; X } X if( stat( arg, &LO_statb ) < 0 ){ X logerr( XLOG_INFO,"Printjob: cannot stat file %s",arg); X goto error; X } X if( (i = Add_name( arg )) < 0 ){ X logerr( XLOG_INFO,"Printjob: too many files %s",q->q_name); X goto error; X } X jobsize = jobsize + (LO_statb.st_size + 1023)/1024; X if( MX && jobsize > MX ){ X logerr( XLOG_INFO,"Printjob: job too big %s",q->q_name); X goto error; X } X switch( opt ){ X case 'f': /* uses the IF filter */ X case 'l': X break; X default: X if( Filter_name[opt-'a'] == 0){ X log( XLOG_INFO,"Printjob: no %c filter",opt); X goto error; X } X break; X } X } X } X /* X * Set up any parameters that were not provided to default values X */ X if( PWIDTH[0] = 0){ X (void)sprintf( PWIDTH, "%d", PW ); X } X /* X * check permissions X */ X if( strcmp( &q->q_from, FROMHOST ) ){ X log(XLOG_INFO, X "Printjob: control file origin '%s' and H entry '%s' do not match", X &q->q_from, FROMHOST ); X goto error; X } X if((Permfile && *Permfile && X !Checkperm(Permfile,FROMHOST,LOGNAME,First_name,&perms,(int *)0,0)) X ||(XU && *XU && X !Checkperm(XU,FROMHOST,LOGNAME,First_name,&perms,(int *)0,0 ) )){ X log(XLOG_INFO, X "Sorry %s@%s, you don't have permission to use '%s'", X LOGNAME, FROMHOST, First_name ); X goto error; X } else if((Permfile && *Permfile && X !Checkperm(Permfile,FROMHOST,LOGNAME,First_name,&perms,(int *)0,1)) X ||(XU && *XU && X !Checkperm(XU,FROMHOST,LOGNAME,First_name,&perms,(int *)0,1 ) )){ X log( XLOG_INFO, "Sorry %s@%s, no more pages allowed on '%s'", X LOGNAME, FROMHOST, First_name ); X goto error; X } X /* X * See if there are any files to print X */ X if( Parmcount == 0 ){ X /* no files */ X if(Debug>4)log(XLOG_DEBUG,"Printjob: no files"); X jstatus = JSUCC; X goto error; X } X /* X * Pass 2: Do the printing now X */ X if( fseek(cfp, 0L, 0) < 0 ){ X /* this is impossible */ X logerr( XLOG_NOTICE, "Printjob: fseek %s failed",q->q_name); X goto error; X } X if( QH ){ X /* X * queuejob returns one of the Job Status settings X */ X jstatus = queuejob(cfp, q); X goto error; X } X /* X * Put out FF on open and between jobs X */ X if( prjobs == 0 ){ X /* X * FO set means FF needed on open X */ X if( LD && *LD ){ X if(Debug>3)log( XLOG_DEBUG, "Printjob: putting out LD on open"); X jstatus = Print_string( LD ); X if( jstatus != JSUCC ){ X log( XLOG_INFO, "Printjob: LD on open printing failed" ); X goto error; X } X } X if( FO && FF && *FF ){ X if(Debug>3)log( XLOG_DEBUG, "Printjob: putting out FF on open"); X jstatus = Print_string( FF ); X if( jstatus != JSUCC ){ X log( XLOG_INFO, "Printjob: FF on open printing failed" ); X goto error; X } X } X prjobs = 1; X } else if( SF == 0 && FF && *FF ){ X if(Debug>3)log(XLOG_DEBUG,"Printjob: putting out FF between jobs"); X jstatus = Print_string( FF ); X if( jstatus != JSUCC ){ X log( XLOG_INFO, "Printjob: FF printing failed" ); X goto error; X } X } X /* X * print banner X * if it has not been disabled by the SH flag X * or the lpr -h flag was used and the AB (always banner) is clear X */ X if( !(SH || (NOHEADER[0] && !AB)) ){ X jstatus = Print_banner(); X if( jstatus != JSUCC ){ X log( XLOG_INFO, "Printjob: banner printing failed" ); X goto error; X } X prjobs = 1; X } X /* X * Banner Printing Program X */ X if( BP && *BP ){ X jstatus = Banner_print(BP); X if( jstatus != JSUCC ){ X log( XLOG_INFO, "Printjob: BP program %s failed", BP); X goto error; X } X prjobs = 1; X } X /* X * print individual jobs X */ X while(fgets( parm, sizeof(parm), cfp )){ X if( (arg = index(parm, '\n')) == 0 ){ X log( XLOG_INFO,"Printjob: bad control file format (%s), no endline", X q->q_name); X goto error; X } X *arg = 0; X opt = parm[0]; X arg = parm+1; X if( opt == 0 || ! isalnum( opt )){ X log( XLOG_INFO, "bad control file (%s), line(%s)", X q->q_name,parm); X goto error; X } X if( islower( opt ) ){ X /* X * print the file X */ X prjobs = 1; X jstatus = printfile( opt, arg ); X if( jstatus != JSUCC ){ X goto error; X } X } X } X /* X * End Printing Program X */ X if( EP && *EP ){ X jstatus = Banner_print(EP); X if( jstatus != JSUCC ){ X log( XLOG_INFO, "Printjob: EP program %s failed", EP); X goto error; X } X prjobs = 1; X } X X /* X * error and status reporting X */ error: X if( MAILNAME[0] ){ X sendmail(q, jstatus); X } X if(Debug>3)log(XLOG_DEBUG,"Printjob: '%s' status %d",q->q_name,jstatus); X return (jstatus); X} X X/*********************************************************************** X * printfile( int format; char *datafile ) X * 1. determine the format and corresponding filter command X * 2. if 'p' format, set up pr process to format output X * 3. output to Printer X * Returns: JFAIL if retry, JSUCC if success, JABORT if ugly X ***********************************************************************/ static int printfile(format, file) X int format; X char *file; X{ X int dfd; /* data file fd */ X int status; /* return status */ X char *filter; /* program Name */ X int nofilter = 0; /* no filter, just copy */ X char buf[BUFSIZ]; /* hold the Printer command */ X int p[2]; /* pipe file descriptors */ X int prchild; /* Printer process */ X X if(Debug>3)log( XLOG_DEBUG, "printfile: format %c, file %s", format, file); X /* X * Open input file X */ X if ((dfd = open_daemon(file, O_RDONLY, 0)) < 0) { X logerr( XLOG_NOTICE,"printfile: open failed '%s'", file); X return(JABORT); X } X /* X * find filter chain to be generated X */ X switch (format) { X /* X * use the filter Name tagged by 'Xf', where X is format X */ X default: X filter = Setup_filter( format, Filter_name[format-'a']); X break; X /* X * 'f' and 'l' formats use the IF filter, and OF if not present X */ X case 'f': /* default */ X case 'l': /* ignore control */ X case 'p': /* print file using 'pr' */ X if( IF == 0 || *IF == 0){ X /* X * you have to use the OF filter; we don't set up a filter X */ X nofilter = 1; X } else { X filter = Setup_filter( 'f', IF); X } X if( format != 'p' ){ X break; X } X /* X * create a process to invoke 'pr' X * first, set up the pr command X */ X (void)sprintf(buf, "%s -w%d -l%d %s %s", X PR, PWIDTH, PL, PRTITLE[0]?"-h":"", PRTITLE); X if(Debug>3)log( XLOG_DEBUG, "printfile: pr command '%s'", buf); X /* X * create PR process X */ X if( pipe(p) < 0 ){ X logerr_die( XLOG_NOTICE, "printfile: cannot make pipe" ); X } X /* X * make a pipe, fork PR process X * Run this process as DAEMON X */ X if ((prchild = fork()) == 0) { /* child */ X if( dup2(dfd, 0) < 0 /* file is stdin */ X || dup2(p[1], 1) < 0 ){ /* pipe stdout */ X logerr_die( XLOG_NOTICE, "printfile: dup2 failed, PR process" ); X } X /* set the uid to be safe */ X if( geteuid() == 0 && setreuid( Daemon_uid, Daemon_uid ) < 0 ){ X logerr_die( XLOG_INFO, "printfile: setreuid failed" ); X } X mexecv(buf); X logerr_die( XLOG_NOTICE,"printfile: cannot execv %s", buf); X } else if (prchild < 0) { X logerr_die( XLOG_NOTICE,"printfile: fork for pr failed"); X } X (void) close(p[1]); /* close output side */ X (void) close(dfd); X dfd = p[0]; /* use pipe for input */ X break; X } X /* X * start filter X */ X if( nofilter ){ X status = Print_copy( dfd ); X } else if (filter == 0 || *filter==0) { X log( XLOG_INFO,"printfile: no %c filter, file %s", format,file); X status = JABORT; X } else { X /* X * start filter up X */ X if(Debug>0)log( XLOG_DEBUG, X "printfile: format %c, file %s, filter %s", format,file,filter); X status = Print_filter( dfd, filter ); X } X (void)close( dfd ); X return( status ); X} X X/******************************************************************** X * Banner_print( char *prog) X * Print the banner using the user specified program X * 1. setup the filter X * 2. start program X * 3. wait for completion. X ********************************************************************/ Banner_print( prog ) X char *prog; X{ X char *filter; X int status; X X if(Debug>3)log( XLOG_DEBUG, "Banner_print %s", prog); X filter = Setup_filter( 'f', prog); X if (filter == 0 || *filter==0) { X log( XLOG_INFO,"Banner_printer: bad program %s", prog ); X status = JABORT; X } else { X /* X * start filter up X */ X if(Debug>3)log( XLOG_DEBUG, "Banner_print: filter %s", filter); X status = Print_filter( 0, filter ); X } X return( status ); X} X/******************************************************************** X * queuejob() X * Use the user specified Queue Handler. X * exec'd as `qh -PPrinter -B[nsl] control_file'. X * exit codes are used to indicate the different success: X * 0 - successful; 1 retry; anything else- abandon X * Returns: JSUCC, etc. X * NOTE: the queue handler is invoked with the control file as X * stdin and the Printer as stdout. X ********************************************************************/ X queuejob(cfp, q) X FILE *cfp; /* control file */ X struct queue *q; /* queue entry */ X{ X union wait status; X int id, pid, ret; X char buf[BUFSIZ]; X X /* X * set up arguments X */ X (void)sprintf(buf, "%s %s", QH, Printer, q->q_name); X if(Debug>0)log( XLOG_DEBUG,"queuejob: %s", buf); X /* X * Open the Printer X */ X Print_open(); X if( (pid = fork()) == 0 ){ /* child */ X if( dup2(fileno(cfp), 0) < 0 ){ /* stdin is cf */ X logerr_die( XLOG_NOTICE, "queuejob: dup2 failed" ); X } X if( dup2(Print_fd, 1) < 0 ){ /* stdin is cf */ X logerr_die( XLOG_NOTICE, "queuejob: dup2 failed" ); X } X if( geteuid() == 0 && setreuid( Daemon_uid, Daemon_uid ) < 0 ){ X logerr_die( XLOG_INFO, "queuejob: setreuid failed" ); X } X mexecv(buf); X logerr_die( XLOG_INFO, "queuejob: exec failed" ); X } else if( pid < 0 ){ X logerr_die( XLOG_INFO, "queuejob: fork failed" ); X } X /* X * wait for process X */ X if(Debug>0)log( XLOG_DEBUG, "waiting for queuejob %d", pid ); X while ((id = wait(&status) ) > 0 && pid!=id){ X if(Debug>3)log(XLOG_DEBUG,"queuejob: caught %d, %s", id, X Decode_status(&status) ); X } X if(Debug>0)log( XLOG_DEBUG, "queuejob: pid %d status %s", id, X Decode_status(&status ) ); X if( id < 0 || status.w_stopval != 0 || (unsigned)status.w_retcode > 1 ){ X logerr( XLOG_INFO, "queuejob process %d failed, status (%s)", X id, Decode_status(&status)); X ret = JABORT; X } else if( status.w_retcode == 1 ){ X ret = JFAIL; X } else { X ret = JSUCC; X } X return (ret); X} END_OF_FILE if test 16055 -ne `wc -c <'src/localprinter.c'`; then echo shar: \"'src/localprinter.c'\" unpacked with wrong size! fi # end of 'src/localprinter.c' fi if test -f 'src/lpr_parms.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/lpr_parms.c'\" else echo shar: Extracting \"'src/lpr_parms.c'\" \(15634 characters\) sed "s/^X//" >'src/lpr_parms.c' <<'END_OF_FILE' X/*************************************************************************** X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell X *************************************************************************** X * MODULE: lpr_parms.c X * get the parameters for lpr program X *************************************************************************** X * Revision History: Created Mon Jan 25 17:29:45 CST 1988 X * $Log: lpr_parms.c,v $ X * Revision 3.1 88/06/18 09:35:00 papowell X * Version 3.0- Distributed Sat Jun 18 1988 X * X * Revision 2.4 88/05/25 15:42:37 papowell X * No header flag modification X * X * Revision 2.3 88/05/19 09:00:18 papowell X * Fixed lint unused variables X * X * Revision 2.2 88/05/14 10:18:40 papowell X * Use long format for job file names; X * Added 'fd', no forward flag; X * Control file has to have hostname and origination agree. X * X * Revision 2.1 88/05/09 10:09:23 papowell X * PLP: Released Version X * X * Revision 1.8 88/05/09 10:03:47 papowell X * Revised effects of -h option X * X * Revision 1.7 88/05/05 20:08:45 papowell X * Added a NOHEADER option that allows user to suppress banner X * X * Revision 1.6 88/04/07 12:31:53 papowell X * Modified to use Getopt X * X * Revision 1.5 88/04/06 12:13:46 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 15:00: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/11 19:28:41 papowell X * Minor Changes, Updates X * X * Revision 1.2 88/03/05 15:01:51 papowell X * Minor Corrections, Lint Problems X * X * Revision 1.1 88/03/01 11:08:50 papowell X * Initial revision X * X ***************************************************************************/ X#ifndef lint static char id_str1[] = X "$Header: lpr_parms.c,v 3.1 88/06/18 09:35:00 papowell Exp $ PLP Copyright 1988 Patrick Powell"; X#endif lint X X#include "lpr.h" X X/*************************************************************************** X * Setup_parms( int argc; char **argv ) X * 1. get the parameters; X * 2. set up the get the printcap entry X * 3. check to see if any parameters violate the printcap restrictions X * 4. get the sequence number X ***************************************************************************/ X Setup_parms( argc, argv ) X int argc; X char **argv; X{ X /* X * get the parameters X */ X Get_parms( argc, argv ); X /* X * print the parameters passed X */ X if(Debug>4)Show_parms(); X /* X * get the printcap entry X */ X Get_Printer(1); X /* X * check authorizations X */ X Can_use(); X /* X * check consistency of parameters X */ X Check_parms(); X /* X * get the sequence number X */ X Get_sequence(); X if(Debug>4)Show_parms(); X} X X/*************************************************************************** X * Get_parms( int argc; char **argv ) X * 1. Scan the argument list and get the flags X ***************************************************************************/ X static char *optstr = "#:C:D:F:J:P:R:T:U:XZ:bcdfghi:lm?nprstvw:"; Get_parms( argc, argv ) X int argc; X char **argv; X{ X int option; X int i; X X while( (option = Getopt(argc,argv,optstr)) != EOF ){ X switch( option ){ X case '#': X Check_int_dup( option, &Copies, Optarg ); X break; X case 'C': X Check_str_dup( option, CLASSNAME, Optarg ); X break; X case 'D': X Check_int_dup( option, &Debug, Optarg ); X break; X case 'F': X if( strlen( Optarg ) != 1 ){ X Diemsg( "bad -F format string '%s'\n",Optarg); X } X if( Format ){ X Diemsg( "duplicate format specification -F%s\n", Optarg); X } else { X Format = *Optarg; X } X break; X case 'J': X Check_str_dup( option, JOBNAME, Optarg ); X break; X case 'P': X if( Printer ){ X Check_str_dup( option, Printer, Optarg ); X } X if( *Optarg == 0 ){ X Diemsg( "missing printer name in -P option\n" ); X } X Printer = Optarg; X break; X case 'R': X Check_str_dup( option, ACCNTNAME, Optarg ); X break; X case 'T': X Check_str_dup( option, PRTITLE, Optarg ); X break; X case 'U': X Root_only( option ); X Check_str_dup( option, BNRNAME, Optarg ); X (void)strcpy( LOGNAME, Optarg ); X break; X case 'X': X Check_dup( option, &Exper ); X# ifdef DEBUG X Setup_test(); X Tailor_names(); X# else X Diemsg( "-X not allowed" ); X# endif DEBUG X break; X case 'Z': X Check_str_dup( option, CLASSNAME, Optarg ); X break; X case 'b': X Check_dup( option, &Binary ); X break; X case 'h': X Check_dup( option, &Noheader ); X /* X * set the NOHEADER flag for lpd X */ X NOHEADER[0] = 'X'; X break; X case 'i': X Check_str_dup( option, INDENT, Optarg ); X break; X case 'm': X /* X * -m[Mailname] X */ X if( Optarg == 0 ){ X Check_str_dup( option, MAILNAME, Person ); X (void)sprintf(MAILNAME,"%s@%s",Person,Host); X } else { X Check_str_dup( option, MAILNAME, Optarg ); X } X break; X case 'r': X Check_dup( option, &Remove ); X break; X case 's': X Check_dup( option, &Use_links ); X break; X case 'c': X case 'd': X case 'f': X case 'g': X case 'l': X case 'n': X case 'p': X case 't': X case 'v': X if( Format ){ X Diemsg( "duplicate format specification -%c\n", option); X exit( 1 ); X } else { X Format = option; X } X break; X case '?': X break; X case 'w': X Check_str_dup( option, PWIDTH, Optarg ); X i = atoi( PWIDTH ); X if( i <= 0 ){ X Diemsg( "-w , width value '%s' bad", PWIDTH ); X exit( 1 ); X } X (void)sprintf( PWIDTH, "%d", i ); X break; X default: X fatal(XLOG_INFO, "Get_parms: badparm %c", option ); X } X } X X /* X * set up the Parms[] array X */ X for( ; Optind < argc; ++Optind ){ X if( Parmcount < MAXPARMS ){ X Parms[Parmcount].str = argv[Optind]; X ++Parmcount; X } else { X Diemsg( "too many files to print; break job up" ); X } X } X /* X * set default format X */ X if( Format == 0 ){ X Format = 'f'; X } X if( FROMHOST[0] == 0 ){ X (void)strcpy(FROMHOST, Host); X } X} X X/*************************************************************************** X * Check_int_dup( int option, int *value, char *arg ) X * 1. check to see if value has been set X * 2. if not, then get integer value from arg X ***************************************************************************/ X Check_int_dup( option, value, arg ) X int option; X int *value; X char *arg; X{ X if( *value ){ X Diemsg( "duplicate option %c", option ); X } X if( sscanf( arg, "%d", value ) != 1 || *value <= 0){ X Diemsg( "option %c parameter (%s) is not positive integer", X option, arg); X } X} X/*************************************************************************** X * Check_str_dup( int option, char *value, char *arg ) X * 1. check to see if value has been set X * 2. if not, then set it X ***************************************************************************/ Check_str_dup( option, value, arg ) X int option; X char *value; X char *arg; X{ X if( *value ){ X Diemsg( "duplicate option %c", option ); X } X if( strlen( arg ) > MAXPARMLEN ){ X Diemsg( "option %c arguement too long (%s)", option, arg ); X } X (void)strcpy(value, arg ); X} X/*************************************************************************** X * Check_dup( int option, int *value ) X * 1. check to see if value has been set X * 2. if not, then set it X ***************************************************************************/ Check_dup( option, value ) X int option; X int *value; X{ X if( *value ){ X Diemsg( "duplicate option %c", option ); X } X *value = 1; X} X/*************************************************************************** X * Root_only( int option ); X * 1. check to see if root X ***************************************************************************/ Root_only( option ) X int option; X{ X if( Is_root == 0 ){ X Diemsg( "option %c can be used only by root", option ); X } X} X/*************************************************************************** X * Can_use() X * Check for permissions and priority X * 1. RG - restrict access by group: must be in group X * 2. printcap: check for restrictions X * 3. XU: check for restrictions X ***************************************************************************/ Can_use() X{ X int prior; /* find the max priority */ X int op; /* 'R' for lpr */ X char buf[BUFSIZ]; X char *pf; /* XU perm file */ X X /* X * get the full path name X */ X pf = XU; X if( pf && *pf && pf[0] != '/' ){ X (void)sprintf( buf, "%s/%s", SD, pf ); X pf = buf; X } X /* X * check for priority X */ X Priority = CLASSNAME[0]; X if( Priority == 0 ){ X Priority = 'Z'; X } X if( !isascii(Priority) || !isupper(Priority) ){ X Priority = 'Z'; X Warnmsg( "Priority set to %c", Priority ); X } X /* X * check to see if we have access restricted by group perms X */ X if( !Is_root && RG && *RG && !Checkgrp( Person,RG ) ){ X Diemsg( "Sorry %s@%s, you don't have permission to use the %s", X Person, Host, Printer ); X } X /* X * check to see if we have restricted access X */ X prior = Priority; X op = 'R'; /* able to use lpr */ X if((Permfile && *Permfile X && !Checkperm(Permfile,Host,Person,First_name,&op,(int *)0,0)) X ||(pf && *pf X && !Checkperm(pf,Host,Person,First_name,&op,(int *)0,0 ) )){ X Diemsg( "Sorry %s@%s, you don't have permission to use '%s'", X Person, Host, Printer ); X } X if((Permfile && *Permfile X && !Checkperm(Permfile,Host,Person,First_name,&op,&prior,1 )) X ||(pf && *pf X && !Checkperm(pf,Host,Person,First_name,&op,&prior,1 ) )){ X Diemsg( "Sorry %s@%s, no more pages allowed on '%s'", X Person, Host, Printer ); X } X /* X * now check to see if you have not exceeded your page limits X */ X if( prior > Priority ){ X Warnmsg( "maximum Priority allowed is %c", prior ); X Priority = prior; X } X if(Debug>2)log(XLOG_DEBUG,"Can_use: %s can use %s, priority %c", X Person, Printer, Priority ); X} X X/*************************************************************************** X * Checkgrp( name, list ) X * -- check to see if person is a member of one of the groups X * Returns: 1 if person is a member, 0 if not X ***************************************************************************/ X Checkgrp( name, list ) X char *name, *list; X{ X char buf[BUFSIZ]; X char *cp, *bp; X struct group *gr; X char **grplist; X X if(Debug>4)log(XLOG_DEBUG,"Checkgrp: checking for %s in %s", name, list ); X cp = list; X while( cp && *cp ){ X for( bp = buf; *cp && (*bp = *cp) && (*bp != ','); ++bp, ++cp ); X *bp = 0; X if( *cp ){ X ++cp; X } X if(Debug>5)log(XLOG_DEBUG,"Checkgrp: checking group %s", buf ); X if( gr = getgrnam(buf) ){ X for( grplist = gr->gr_mem; *grplist; ++grplist ){ X if( strcmp( name, *grplist ) == 0 ){ X if(Debug>4)log(XLOG_DEBUG,"Checkgrp: %s in %s", X name, gr->gr_name ); X return(1); X } X } X } X } X if(Debug>4)log(XLOG_DEBUG,"Checkgrp: %s not in any group" ); X return( 0 ); X} X/*************************************************************************** X * Check_parms() X * Check for parameter consistency X * 1. Check to see if the format is allowed X * 2. Check on the multiple copies X ***************************************************************************/ Check_parms() X{ X char *msg; X /* check format and options */ X if( FX && *FX && index( FX, Format ) == 0 ){ X msg=NULL; X switch(Format){ X case 'f': msg = "Normal or plain files"; break; X case 't': msg = "Troff files, use -Fn for Ditroff"; break; X case 'n': msg = "Ditroff files, use -Ft for (old) troff files";break; X case 'v': msg = "Varian raster images"; break; X case 'd': msg = "TeX intermediate files (DVI)"; break; X case 'g': msg = "Plot intermediate files"; break; X case 'c': msg = "Cifplot intermediate files"; break; X default: msg = "format 'X' files"; msg[8]=Format; X } X Diemsg("Printer %s does not know how to interpret %s\n", Printer, msg); X } X if( SC && Copies > 1){ X Warnmsg("multiple copies are not allowed"); X Copies = 0; X } X if(MC > 0 && Copies > MC){ X Warnmsg("only %d copies are allowed", MC); X Copies = MC; X } X if( Remove && !Is_root X && (LN == 0 || *LN == 0 || !Checkgrp( Person, LN ))){ X Warnmsg( "-r (remove) not allowed" ); X Remove = 0; X } X#ifdef NOSYMLINK X if( Use_links ){ X Warnmsg("-s (symbolic links) disabled"); X Use_links = 0; X } X#else X if( Use_links ){ X /* X * check to see if we are a member of the right group X */ X if( !Is_root && (LN == 0 || *LN == 0 || !Checkgrp( Person, LN ) )){ X Warnmsg("-s (symbolic links) not allowed by user %s", Person); X Use_links = 0; X } else if( RM && NW ){ X Warnmsg("-s (symbolic links) not available for this queue" ); X Use_links = 0; X } X } X#endif NOSYMLINK X if( Remove && !Use_links ){ X Warnmsg( "-r (remove) not allowed without -s" ); X Remove = 0; X } X} X X/*************************************************************************** X * Get_sequence() X * Get the job sequence number X * 1. Check to see if queuing is enabled X * 2. Get the job number from the .job file X ***************************************************************************/ X Get_sequence() X{ X char buf[MAXPATHLEN]; /* holds the pathname */ X FILE *fp; /* for sequence number */ X int i; /* waiting time */ X X /* X * check to see if printing is enabled X */ X if( LO == 0 || *LO == 0 || SD == 0 || *SD == 0 ){ X fatal( XLOG_CRIT, "Get_sequence: bad printcap entry" ); X } X if( LO[0] == '/' ){ X (void)strcpy( buf, LO ); X } else { X (void)sprintf( buf, "%s/%s", SD, LO ); X } X /* X * get the sequence file name X */ X (void)sprintf( buf, "%s/.seq.%s", SD, Host ); X if(Debug>3)log(XLOG_DEBUG,"sequence file name '%s'", buf ); X /* X * lock the sequence file and get a new number X */ X for( i = 0; X (fp = Getlockfile( buf, &Job_number,(char *)0,0,&LO_statb )) == NULL X && i < 3; X ++i ){ X sleep( (unsigned)(i+ (getpid()&1) ) ); X } X if( fp == NULL ){ X Diemsg("cannot lock sequence file %s, try later (%s)", buf, X Errormsg( errno ) ); X } X if( !Is_root && (LO_statb.st_mode & DISABLE_QUEUE) ){ X Diemsg( "printer %s- queueing disabled", Printer ); X } X /* X * set the sequence number to the new value mod 1000; X */ X Job_number = (Job_number+1) % 1000; X Setlockfile( buf, fp, Job_number, Time_str() ); X (void)fclose(fp); X if(Debug>4)log(XLOG_DEBUG, "Get_sequence: number %d", Job_number); X} X X/*************************************************************************** X * Show_parms() X * Display the values of the parameters that were read. X * 1. Print the CFparm array X * 2. Print the other parameters X ***************************************************************************/ X Show_parms() X{ X int i; X char *s; X X /* X * CFparm first: X */ X (void)fprintf(stderr,"CFparm:\n"); X for( i = 'A'; i <= 'Z'; ++i ){ X s = CFparm[i-'A']; X if( s[0] ){ X (void)fprintf(stderr," %c '%s'\n", i, s ); X } X } X (void)fprintf(stderr, " Format: %c\n", Format ); X (void)fprintf(stderr, " Copies: %d\n", Copies ); X (void)fprintf(stderr, " Binary: %d\n", Binary ); X (void)fprintf(stderr, " Use_links: %d\n", Use_links ); X (void)fprintf(stderr, " Exper: %d\n", Exper ); X (void)fprintf(stderr, " Priority: %d\n", Priority ); X (void)fprintf(stderr, " Job_number: %d\n", Job_number ); X if( Read_stdin ){ X (void)fprintf(stderr, " Read_stdin: %s\n", Read_stdin ); X } X if( Filter_out ){ X (void)fprintf(stderr, " Filter_out: %s\n", Filter_out ); X } X (void)fprintf(stderr, " Temp_count: %d\n", Temp_count ); X (void)fprintf(stderr, " Temp_max: %d\n", Temp_max ); X for( i = 0; i < Temp_count; ++i ){ X s = Temp_file[i]; X (void)fprintf(stderr," %d '%s'\n", i, s ); X } X} END_OF_FILE if test 15634 -ne `wc -c <'src/lpr_parms.c'`; then echo shar: \"'src/lpr_parms.c'\" unpacked with wrong size! fi # end of 'src/lpr_parms.c' fi echo shar: End of archive 11 \(of 16\). cp /dev/null ark11isdone 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