diff options
Diffstat (limited to 'usr.sbin/lpr')
69 files changed, 14149 insertions, 0 deletions
diff --git a/usr.sbin/lpr/Makefile b/usr.sbin/lpr/Makefile new file mode 100644 index 0000000..4343200 --- /dev/null +++ b/usr.sbin/lpr/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +SUBDIR= common_source chkprintcap lp lpc lpd lpq lpr lprm lptest pac \ + filters filters.ru SMM.doc + +MAINTAINER= wollman@FreeBSD.org +MAINTAINER+= gad@FreeBSD.org + +.include <bsd.subdir.mk> + diff --git a/usr.sbin/lpr/Makefile.inc b/usr.sbin/lpr/Makefile.inc new file mode 100644 index 0000000..141373e --- /dev/null +++ b/usr.sbin/lpr/Makefile.inc @@ -0,0 +1,11 @@ +# $FreeBSD$ + +CWARNFLAGS= -Wall -Wnested-externs -Wmissing-prototypes -Wno-unused -Wredundant-decls -Wstrict-prototypes + +.if exists(${.OBJDIR}/../common_source) +LIBLPR= ${.OBJDIR}/../common_source/liblpr.a +.else +LIBLPR= ${.CURDIR}/../common_source/liblpr.a +.endif + +.include "../Makefile.inc" diff --git a/usr.sbin/lpr/SMM.doc/0.t b/usr.sbin/lpr/SMM.doc/0.t new file mode 100644 index 0000000..65ecd4e --- /dev/null +++ b/usr.sbin/lpr/SMM.doc/0.t @@ -0,0 +1,68 @@ +.\" Copyright (c) 1983, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)0.t 8.1 (Berkeley) 6/8/93 +.\" +.if n .ND +.TL +4.3BSD Line Printer Spooler Manual +.EH 'SMM:7-%''4.3BSD Line Printer Spooler Manual' +.OH '4.3BSD Line Printer Spooler Manual''SMM:7-%' +.AU +Ralph Campbell +.AI +Computer Systems Research Group +Computer Science Division +Department of Electrical Engineering and Computer Science +University of California, Berkeley +Berkeley, CA 94720 +.AB +.FS +* UNIX is a trademark of Bell Laboratories. +.FE +This document describes the structure and installation procedure +for the line printer spooling system +developed for the 4.3BSD version +of the UNIX* operating system. +.de D? +.ie \\n(.$>1 Revised \\$1 \\$2 \\$3 +.el DRAFT of \n(mo/\n(dy/\n(yr +.. +.sp 2 +.LP +.D? June 8, 1993 +.AE +.de IR +\fI\\$1\fP\\$2 +.. +.de DT +.TA 8 16 24 32 40 48 56 64 72 80 +.. diff --git a/usr.sbin/lpr/SMM.doc/1.t b/usr.sbin/lpr/SMM.doc/1.t new file mode 100644 index 0000000..1d34e9e --- /dev/null +++ b/usr.sbin/lpr/SMM.doc/1.t @@ -0,0 +1,77 @@ +.\" Copyright (c) 1983, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)1.t 8.1 (Berkeley) 6/8/93 +.\" +.NH 1 +Overview +.PP +The line printer system supports: +.IP \(bu 3 +multiple printers, +.IP \(bu 3 +multiple spooling queues, +.IP \(bu 3 +both local and remote +printers, and +.IP \(bu 3 +printers attached via serial lines that require +line initialization such as the baud rate. +.LP +Raster output devices +such as a Varian or Versatec, and laser printers such as an Imagen, +are also supported by the line printer system. +.PP +The line printer system consists mainly of the +following files and commands: +.DS +.TS +l l. +/etc/printcap printer configuration and capability data base +/usr/lib/lpd line printer daemon, does all the real work +/usr/ucb/lpr program to enter a job in a printer queue +/usr/ucb/lpq spooling queue examination program +/usr/ucb/lprm program to delete jobs from a queue +/etc/lpc program to administer printers and spooling queues +/dev/printer socket on which lpd listens +.TE +.DE +The file /etc/printcap is a master data base describing line +printers directly attached to a machine and, also, printers +accessible across a network. The manual page entry +.IR printcap (5) +provides the authoritative definition of +the format of this data base, as well as +specifying default values for important items +such as the directory in which spooling is performed. +This document introduces some of the +information that may be placed +.IR printcap . diff --git a/usr.sbin/lpr/SMM.doc/2.t b/usr.sbin/lpr/SMM.doc/2.t new file mode 100644 index 0000000..9da2ae2 --- /dev/null +++ b/usr.sbin/lpr/SMM.doc/2.t @@ -0,0 +1,141 @@ +.\" Copyright (c) 1983, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)2.t 8.1 (Berkeley) 6/8/93 +.\" +.NH 1 +Commands +.NH 2 +lpd \- line printer daemon +.PP +The program +.IR lpd (8), +usually invoked at boot time from the /etc/rc file, acts as +a master server for coordinating and controlling +the spooling queues configured in the printcap file. +When +.I lpd +is started it makes a single pass through the +.I printcap +database restarting any printers that have jobs. +In normal operation +.I lpd +listens for service requests on multiple sockets, +one in the UNIX domain (named ``/dev/printer'') for +local requests, and one in the Internet domain +(under the ``printer'' service specification) +for requests for printer access from off machine; +see \fIsocket\fP\|(2) and \fIservices\fP\|(5) +for more information on sockets and service +specifications, respectively. +.I Lpd +spawns a copy of itself to process the request; the master daemon +continues to listen for new requests. +.PP +Clients communicate with +.I lpd +using a simple transaction oriented protocol. +Authentication of remote clients is done based +on the ``privilege port'' scheme employed by +\fIrshd\fP\|(8C) and \fIrcmd\fP\|(3X). +The following table shows the requests +understood by +.IR lpd . +In each request the first byte indicates the +``meaning'' of the request, followed by the name +of the printer to which it should be applied. Additional +qualifiers may follow, depending on the request. +.DS +.TS +l l. +Request Interpretation +_ +^Aprinter\en check the queue for jobs and print any found +^Bprinter\en receive and queue a job from another machine +^Cprinter [users ...] [jobs ...]\en return short list of current queue state +^Dprinter [users ...] [jobs ...]\en return long list of current queue state +^Eprinter person [users ...] [jobs ...]\en remove jobs from a queue +.TE +.DE +.PP +The \fIlpr\fP\|(1) command +is used by users to enter a print job in a local queue and to notify +the local +.I lpd +that there are new jobs in the spooling area. +.I Lpd +either schedules the job to be printed locally, or if +printing remotely, attempts to forward +the job to the appropriate machine. +If the printer cannot be opened or the destination +machine is unreachable, the job will remain queued until it is +possible to complete the work. +.NH 2 +lpq \- show line printer queue +.PP +The \fIlpq\fP\|(1) +program works recursively backwards displaying the queue of the machine with +the printer and then the queue(s) of the machine(s) that lead to it. +.I Lpq +has two forms of output: in the default, short, format it +gives a single line of output per queued job; in the long +format it shows the list of files, and their sizes, that +comprise a job. +.NH 2 +lprm \- remove jobs from a queue +.PP +The \fIlprm\fP\|(1) command deletes jobs from a spooling +queue. If necessary, \fIlprm\fP will first kill off a +running daemon that is servicing the queue and restart +it after the required files are removed. When removing +jobs destined for a remote printer, \fIlprm\fP acts +similarly to \fIlpq\fP except it first checks locally +for jobs to remove and then +tries to remove files in queues off-machine. +.NH 2 +lpc \- line printer control program +.PP +The +.IR lpc (8) +program is used by the system administrator to control the +operation of the line printer system. +For each line printer configured in /etc/printcap, +.I lpc +may be used to: +.IP \(bu +disable or enable a printer, +.IP \(bu +disable or enable a printer's spooling queue, +.IP \(bu +rearrange the order of jobs in a spooling queue, +.IP \(bu +find the status of printers, and their associated +spooling queues and printer daemons. diff --git a/usr.sbin/lpr/SMM.doc/3.t b/usr.sbin/lpr/SMM.doc/3.t new file mode 100644 index 0000000..8c950a9 --- /dev/null +++ b/usr.sbin/lpr/SMM.doc/3.t @@ -0,0 +1,73 @@ +.\" Copyright (c) 1983, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)3.t 8.1 (Berkeley) 6/8/93 +.\" +.NH 1 +Access control +.PP +The printer system maintains protected spooling areas so that +users cannot circumvent printer accounting or +remove files other than their own. +The strategy used to maintain protected +spooling areas is as follows: +.IP \(bu 3 +The spooling area is writable only by a \fIdaemon\fP user +and \fIdaemon\fP group. +.IP \(bu 3 +The \fIlpr\fP program runs set-user-id to \fIroot\fP and +set-group-id to group \fIdaemon\fP. The \fIroot\fP access permits +reading any file required. Accessibility is verified +with an \fIaccess\fP\|(2) call. The group ID +is used in setting up proper ownership of files +in the spooling area for \fIlprm\fP. +.IP \(bu 3 +Control files in a spooling area are made with \fIdaemon\fP +ownership and group ownership \fIdaemon\fP. Their mode is 0660. +This insures control files are not modified by a user +and that no user can remove files except through \fIlprm\fP. +.IP \(bu 3 +The spooling programs, +\fIlpd\fP, \fIlpq\fP, and \fIlprm\fP run set-user-id to \fIroot\fP +and set-group-id to group \fIdaemon\fP to access spool files and printers. +.IP \(bu 3 +The printer server, \fIlpd\fP, +uses the same verification procedures as \fIrshd\fP\|(8C) +in authenticating remote clients. The host on which a client +resides must be present in the file /etc/hosts.equiv or /etc/hosts.lpd and +the request message must come from a reserved port number. +.PP +In practice, none of \fIlpd\fP, \fIlpq\fP, or +\fIlprm\fP would have to run as user \fIroot\fP if remote +spooling were not supported. In previous incarnations of +the printer system \fIlpd\fP ran set-user-id to \fIdaemon\fP, +set-group-id to group \fIspooling\fP, and \fIlpq\fP and \fIlprm\fP ran +set-group-id to group \fIspooling\fP. diff --git a/usr.sbin/lpr/SMM.doc/4.t b/usr.sbin/lpr/SMM.doc/4.t new file mode 100644 index 0000000..8800bc0 --- /dev/null +++ b/usr.sbin/lpr/SMM.doc/4.t @@ -0,0 +1,206 @@ +.\" Copyright (c) 1983, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)4.t 8.1 (Berkeley) 6/8/93 +.\" +.NH 1 +Setting up +.PP +The 4.3BSD release comes with the necessary programs +installed and with the default line printer queue +created. If the system must be modified, the +makefile in the directory /usr/src/usr.lib/lpr +should be used in recompiling and reinstalling +the necessary programs. +.PP +The real work in setting up is to create the +.I printcap +file and any printer filters for printers not supported +in the distribution system. +.NH 2 +Creating a printcap file +.PP +The +.I printcap +database contains one or more entries per printer. +A printer should have a separate spooling directory; +otherwise, jobs will be printed on +different printers depending on which printer daemon starts first. +This section describes how to create entries for printers that do not +conform to the default printer description (an LP-11 style interface to a +standard, band printer). +.NH 3 +Printers on serial lines +.PP +When a printer is connected via a serial communication line +it must have the proper baud rate and terminal modes set. +The following example is for a DecWriter III printer connected +locally via a 1200 baud serial line. +.DS +.DT +lp|LA-180 DecWriter III:\e + :lp=/dev/lp:br#1200:fs#06320:\e + :tr=\ef:of=/usr/lib/lpf:lf=/usr/adm/lpd-errs: +.DE +The +.B lp +entry specifies the file name to open for output. Here it could +be left out since ``/dev/lp'' is the default. +The +.B br +entry sets the baud rate for the tty line and the +.B fs +entry sets CRMOD, no parity, and XTABS (see \fItty\fP\|(4)). +The +.B tr +entry indicates that a form-feed should be printed when the queue +empties so the paper can be torn off without turning the printer off-line and +pressing form feed. +The +.B of +entry specifies the filter program +.I lpf +should be used for printing the files; +more will be said about filters later. +The last entry causes errors +to be written to the file ``/usr/adm/lpd-errs'' +instead of the console. Most errors from \fIlpd\fP are logged using +\fIsyslogd\fP\|(8) and will not be logged in the specified file. The +filters should use \fIsyslogd\fP to report errors; only those that +write to standard error output will end up with errors in the \fBlf\fP file. +(Occasionally errors sent to standard error output have not appeared +in the log file; the use of \fIsyslogd\fP is highly recommended.) +.NH 3 +Remote printers +.PP +Printers that reside on remote hosts should have an empty +.B lp +entry. +For example, the following printcap entry would send output to the printer +named ``lp'' on the machine ``ucbvax''. +.DS +.DT +lp|default line printer:\e + :lp=:rm=ucbvax:rp=lp:sd=/usr/spool/vaxlpd: +.DE +The +.B rm +entry is the name of the remote machine to connect to; this name must +be a known host name for a machine on the network. +The +.B rp +capability indicates +the name of the printer on the remote machine is ``lp''; +here it could be left out since this is the default value. +The +.B sd +entry specifies ``/usr/spool/vaxlpd'' +as the spooling directory instead of the +default value of ``/usr/spool/lpd''. +.NH 2 +Output filters +.PP +Filters are used to handle device dependencies and to +do accounting functions. The output filtering of +.B of +is used when accounting is +not being done or when all text data must be passed through a filter. +It is not intended to do accounting since it is started only once, +all text files are filtered through it, and no provision is made for passing +owners' login name, identifying the beginning and ending of jobs, etc. +The other filters (if specified) are started for each file +printed and do accounting if there is an +.B af +entry. +If entries for both +.B of +and other filters are specified, +the output filter is used only to print the banner page; +it is then stopped to allow other filters access to the printer. +An example of a printer that requires output filters +is the Benson-Varian. +.DS +.DT +va|varian|Benson-Varian:\e + :lp=/dev/va0:sd=/usr/spool/vad:of=/usr/lib/vpf:\e + :tf=/usr/lib/rvcat:mx#2000:pl#58:px=2112:py=1700:tr=\ef: +.DE +The +.B tf +entry specifies ``/usr/lib/rvcat'' as the filter to be +used in printing \fItroff\fP\|(1) output. +This filter is needed to set the device into print mode +for text, and plot mode for printing +.I troff +files and raster images (see \fIva\fP\|(4V)). +Note that the page length is set to 58 lines by the +.B pl +entry for 8.5" by 11" fan-fold paper. +To enable accounting, the varian entry would be +augmented with an +.B af +filter as shown below. +.DS +.DT +va|varian|Benson-Varian:\e + :lp=/dev/va0:sd=/usr/spool/vad:of=/usr/lib/vpf:\e + :if=/usr/lib/vpf:tf=/usr/lib/rvcat:af=/usr/adm/vaacct:\e + :mx#2000:pl#58:px=2112:py=1700:tr=\ef: +.DE +.NH 2 +Access Control +.PP +Local access to printer queues is controlled with the +.B rg +printcap entry. +.DS + :rg=lprgroup: +.DE +Users must be in the group +.I lprgroup +to submit jobs to the specified printer. +The default is to allow all users access. +Note that once the files are in the local queue, they can be printed +locally or forwarded to another host depending on the configuration. +.PP +Remote access is controlled by listing the hosts in either the file +/etc/hosts.equiv or /etc/hosts.lpd, one host per line. Note that +.IR rsh (1) +and +.IR rlogin (1) +use /etc/hosts.equiv to determine which hosts are equivalent for allowing logins +without passwords. The file /etc/hosts.lpd is only used to control +which hosts have line printer access. +Remote access can be further restricted to only allow remote users with accounts +on the local host to print jobs by using the \fBrs\fP printcap entry. +.DS + :rs: +.DE diff --git a/usr.sbin/lpr/SMM.doc/5.t b/usr.sbin/lpr/SMM.doc/5.t new file mode 100644 index 0000000..137a342 --- /dev/null +++ b/usr.sbin/lpr/SMM.doc/5.t @@ -0,0 +1,116 @@ +.\" Copyright (c) 1983, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)5.t 8.1 (Berkeley) 6/8/93 +.\" +.NH 1 +Output filter specifications +.PP +The filters supplied with 4.3BSD +handle printing and accounting for most common +line printers, the Benson-Varian, the wide (36") and +narrow (11") Versatec printer/plotters. For other devices or accounting +methods, it may be necessary to create a new filter. +.PP +Filters are spawned by \fIlpd\fP +with their standard input the data to be printed, and standard output +the printer. The standard error is attached to the +.B lf +file for logging errors or \fIsyslogd\fP may be used for logging errors. +A filter must return a 0 exit +code if there were no errors, 1 if the job should be reprinted, +and 2 if the job should be thrown away. +When \fIlprm\fP +sends a kill signal to the \fIlpd\fP process controlling +printing, it sends a SIGINT signal +to all filters and descendents of filters. +This signal can be trapped by filters that need +to do cleanup operations such as +deleting temporary files. +.PP +Arguments passed to a filter depend on its type. +The +.B of +filter is called with the following arguments. +.DS +\fIfilter\fP \fB\-w\fPwidth \fB\-l\fPlength +.DE +The \fIwidth\fP and \fIlength\fP values come from the +.B pw +and +.B pl +entries in the printcap database. +The +.B if +filter is passed the following parameters. +.DS +\fIfilter\fP [\|\fB\-c\fP\|] \fB\-w\fPwidth \fB\-l\fPlength \fB\-i\fPindent \fB\-n\fP login \fB\-h\fP host accounting_file +.DE +The +.B \-c +flag is optional, and only supplied when control characters +are to be passed uninterpreted to the printer (when using the +.B \-l +option of +.I lpr +to print the file). +The +.B \-w +and +.B \-l +parameters are the same as for the +.B of +filter. +The +.B \-n +and +.B \-h +parameters specify the login name and host name of the job owner. +The last argument is the name of the accounting file from +.IR printcap . +.PP +All other filters are called with the following arguments: +.DS +\fIfilter\fP \fB\-x\fPwidth \fB\-y\fPlength \fB\-n\fP login \fB\-h\fP host accounting_file +.DE +The +.B \-x +and +.B \-y +options specify the horizontal and vertical page +size in pixels (from the +.B px +and +.B py +entries in the printcap file). +The rest of the arguments are the same as for the +.B if +filter. diff --git a/usr.sbin/lpr/SMM.doc/6.t b/usr.sbin/lpr/SMM.doc/6.t new file mode 100644 index 0000000..7087790 --- /dev/null +++ b/usr.sbin/lpr/SMM.doc/6.t @@ -0,0 +1,94 @@ +.\" Copyright (c) 1983, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)6.t 8.1 (Berkeley) 6/8/93 +.\" +.NH 1 +Line printer Administration +.PP +The +.I lpc +program provides local control over line printer activity. +The major commands and their intended use will be described. +The command format and remaining commands are described in +.IR lpc (8). +.LP +\fBabort\fP and \fBstart\fP +.IP +.I Abort +terminates an active spooling daemon on the local host immediately and +then disables printing (preventing new daemons from being started by +.IR lpr ). +This is normally used to forcibly restart a hung line printer daemon +(i.e., \fIlpq\fP reports that there is a daemon present but nothing is +happening). It does not remove any jobs from the queue +(use the \fIlprm\fP command instead). +.I Start +enables printing and requests \fIlpd\fP to start printing jobs. +.LP +\fBenable\fP and \fBdisable\fP +.IP +\fIEnable\fP and \fIdisable\fP allow spooling in the local queue to be +turned on/off. +This will allow/prevent +.I lpr +from putting new jobs in the spool queue. It is frequently convenient +to turn spooling off while testing new line printer filters since the +.I root +user can still use +.I lpr +to put jobs in the queue but no one else can. +The other main use is to prevent users from putting jobs in the queue +when the printer is expected to be unavailable for a long time. +.LP +\fBrestart\fP +.IP +.I Restart +allows ordinary users to restart printer daemons when +.I lpq +reports that there is no daemon present. +.LP +\fBstop\fP +.IP +.I Stop +halts a spooling daemon after the current job completes; +this also disables printing. This is a clean way to shutdown a +printer to do maintenance, etc. Note that users can still enter jobs in a +spool queue while a printer is +.IR stopped . +.LP +\fBtopq\fP +.IP +.I Topq +places jobs at the top of a printer queue. This can be used +to reorder high priority jobs since +.I lpr +only provides first-come-first-serve ordering of jobs. diff --git a/usr.sbin/lpr/SMM.doc/7.t b/usr.sbin/lpr/SMM.doc/7.t new file mode 100644 index 0000000..a6f6bea --- /dev/null +++ b/usr.sbin/lpr/SMM.doc/7.t @@ -0,0 +1,226 @@ +.\" Copyright (c) 1983, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)7.t 8.1 (Berkeley) 6/8/93 +.\" +.NH 1 +Troubleshooting +.PP +There are several messages that may be generated by the +the line printer system. This section +categorizes the most common and explains the cause +for their generation. Where the message implies a failure, +directions are given to remedy the problem. +.PP +In the examples below, the name +.I printer +is the name of the printer from the +.I printcap +database. +.NH 2 +LPR +.SH +lpr: \fIprinter\fP\|: unknown printer +.IP +The +.I printer +was not found in the +.I printcap +database. Usually this is a typing mistake; however, it may indicate +a missing or incorrect entry in the /etc/printcap file. +.SH +lpr: \fIprinter\fP\|: jobs queued, but cannot start daemon. +.IP +The connection to +.I lpd +on the local machine failed. +This usually means the printer server started at +boot time has died or is hung. Check the local socket +/dev/printer to be sure it still exists (if it does not exist, +there is no +.I lpd +process running). +Usually it is enough to get a super-user to type the following to +restart +.IR lpd . +.DS +% /usr/lib/lpd +.DE +You can also check the state of the master printer daemon with the following. +.DS +% ps l`cat /usr/spool/lpd.lock` +.DE +.IP +Another possibility is that the +.I lpr +program is not set-user-id to \fIroot\fP, set-group-id to group \fIdaemon\fP. +This can be checked with +.DS +% ls \-lg /usr/ucb/lpr +.DE +.SH +lpr: \fIprinter\fP\|: printer queue is disabled +.IP +This means the queue was turned off with +.DS +% lpc disable \fIprinter\fP +.DE +to prevent +.I lpr +from putting files in the queue. This is normally +done by the system manager when a printer is +going to be down for a long time. The +printer can be turned back on by a super-user with +.IR lpc . +.NH 2 +LPQ +.SH +waiting for \fIprinter\fP to become ready (offline ?) +.IP +The printer device could not be opened by the daemon. +This can happen for several reasons, +the most common is that the printer is turned off-line. +This message can also be generated if the printer is out +of paper, the paper is jammed, etc. +The actual reason is dependent on the meaning +of error codes returned by system device driver. +Not all printers supply enough information +to distinguish when a printer is off-line or having +trouble (e.g. a printer connected through a serial line). +Another possible cause of this message is +some other process, such as an output filter, +has an exclusive open on the device. Your only recourse +here is to kill off the offending program(s) and +restart the printer with +.IR lpc . +.SH +\fIprinter\fP is ready and printing +.IP +The +.I lpq +program checks to see if a daemon process exists for +.I printer +and prints the file \fIstatus\fP located in the spooling directory. +If the daemon is hung, a super user can use +.I lpc +to abort the current daemon and start a new one. +.SH +waiting for \fIhost\fP to come up +.IP +This implies there is a daemon trying to connect to the remote +machine named +.I host +to send the files in the local queue. +If the remote machine is up, +.I lpd +on the remote machine is probably dead or +hung and should be restarted as mentioned for +.IR lpr . +.SH +sending to \fIhost\fP +.IP +The files should be in the process of being transferred to the remote +.IR host . +If not, the local daemon should be aborted and started with +.IR lpc . +.SH +Warning: \fIprinter\fP is down +.IP +The printer has been marked as being unavailable with +.IR lpc . +.SH +Warning: no daemon present +.IP +The \fIlpd\fP process overseeing +the spooling queue, as specified in the ``lock'' file +in that directory, does not exist. This normally occurs +only when the daemon has unexpectedly died. +The error log file for the printer and the \fIsyslogd\fP logs +should be checked for a +diagnostic from the deceased process. +To restart an \fIlpd\fP, use +.DS +% lpc restart \fIprinter\fP +.DE +.SH +no space on remote; waiting for queue to drain +.IP +This implies that there is insufficient disk space on the remote. +If the file is large enough, there will never be enough space on +the remote (even after the queue on the remote is empty). The solution here +is to move the spooling queue or make more free space on the remote. +.NH 2 +LPRM +.SH +lprm: \fIprinter\fP\|: cannot restart printer daemon +.IP +This case is the same as when +.I lpr +prints that the daemon cannot be started. +.NH 2 +LPD +.PP +The +.I lpd +program can log many different messages using \fIsyslogd\fP\|(8). +Most of these messages are about files that can not +be opened and usually imply that the +.I printcap +file or the protection modes of the files are +incorrect. Files may also be inaccessible if people +manually manipulate the line printer system (i.e. they +bypass the +.I lpr +program). +.PP +In addition to messages generated by +.IR lpd , +any of the filters that +.I lpd +spawns may log messages using \fIsyslogd\fP or to the error log file +(the file specified in the \fBlf\fP entry in \fIprintcap\fP\|). +.NH 2 +LPC +.PP +.SH +couldn't start printer +.IP +This case is the same as when +.I lpr +reports that the daemon cannot be started. +.SH +cannot examine spool directory +.IP +Error messages beginning with ``cannot ...'' are usually because of +incorrect ownership or protection mode of the lock file, spooling +directory or the +.I lpc +program. diff --git a/usr.sbin/lpr/SMM.doc/Makefile b/usr.sbin/lpr/SMM.doc/Makefile new file mode 100644 index 0000000..faeb266 --- /dev/null +++ b/usr.sbin/lpr/SMM.doc/Makefile @@ -0,0 +1,12 @@ +# From: @(#)Makefile 8.1 (Berkeley) 6/8/93 +# $FreeBSD$ + +BINDIR= /usr/share/doc +VOLUME= smm/07.lpd +SRCS= 0.t 1.t 2.t 3.t 4.t 5.t 6.t 7.t +MACROS= -ms + +USE_TBL= yes +SRCDIR= ${.CURDIR} + +.include <bsd.doc.mk> diff --git a/usr.sbin/lpr/SMM.doc/spell.ok b/usr.sbin/lpr/SMM.doc/spell.ok new file mode 100644 index 0000000..bf31319 --- /dev/null +++ b/usr.sbin/lpr/SMM.doc/spell.ok @@ -0,0 +1,70 @@ +Aprinter +Bprinter +CRMOD +Cprinter +DecWriter +Dprinter +Eprinter +LPC +LPD +Lpd +Manual''SMM:5 +SIGINT +SMM:5 +Topq +XTABS +adm +af +br +daemon +daemons +dev +f:of +fs +hosts.equiv +hosts.lpd +lf +lg +lib +lp:br +lp:sd +lpc +lpd +lpd.lock +lpf +lpf:lf +lprgroup +makefile +mx +offline +pl +printcap +pw +py +rc +rcmd +rg +rlogin +rp +rs +rsh +rshd +rvcat +rvcat:af +rvcat:mx +sd +src +syslogd +tf +topq +ucb +ucbvax +ucbvax:rp +usr.lib +va0:sd +vaacct +vad:of +varian +vaxlpd +vpf +vpf:tf diff --git a/usr.sbin/lpr/chkprintcap/Makefile b/usr.sbin/lpr/chkprintcap/Makefile new file mode 100644 index 0000000..e671ec9 --- /dev/null +++ b/usr.sbin/lpr/chkprintcap/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +PROG= chkprintcap +MAN8= chkprintcap.8 +CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS} +.PATH: ${.CURDIR}/../common_source +DPADD= ${LIBLPR} +LDADD= ${LIBLPR} + +.include <bsd.prog.mk> diff --git a/usr.sbin/lpr/chkprintcap/chkprintcap.8 b/usr.sbin/lpr/chkprintcap/chkprintcap.8 new file mode 100644 index 0000000..ecf7822 --- /dev/null +++ b/usr.sbin/lpr/chkprintcap/chkprintcap.8 @@ -0,0 +1,96 @@ +.\" Copyright 1997 Massachusetts Institute of Technology +.\" +.\" Permission to use, copy, modify, and distribute this software and +.\" its documentation for any purpose and without fee is hereby +.\" granted, provided that both the above copyright notice and this +.\" permission notice appear in all copies, that both the above +.\" copyright notice and this permission notice appear in all +.\" supporting documentation, and that the name of M.I.T. not be used +.\" in advertising or publicity pertaining to distribution of the +.\" software without specific, written prior permission. M.I.T. makes +.\" no representations about the suitability of this software for any +.\" purpose. It is provided "as is" without express or implied +.\" warranty. +.\" +.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS +.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, +.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT +.\" SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.Dd November 30, 1997 +.Dt CHKPRINTCAP 8 +.Os +.Sh NAME +.Nm chkprintcap +.Nd check validity of entries in the print spooler database +.Sh SYNOPSIS +.Nm chkprintcap +.Op Fl d +.Op Fl f Ar printcap +.Sh DESCRIPTION +.Nm Chkprintcap +scans a +.Xr printcap 5 +database +(named by the +.Ar printcap +argument, or by default +.Pa /etc/printcap ) , +looking for entries which are invalid in one way or another. +The following checks are currently implemented: +.Bl -enum -offset indent +.It +.Sq Li tc= +references were properly expanded +.It +.Sq Li tc= +references did not form a loop +.It +No two printers share the same spool directory +.Po +.Sq Li sd= +capability +.Pc . +.El +.Pp +.Nm Chkprintcap +exits with a status equal to the number of errors encountered before +processing stopped. (In some cases, processing can stop before the +entire file is scanned.) +.Pp +If the +.Fl d +flag is given, +.Nm chkprintcap +will attempt to create any missing spool directories, giving them +.Sq Li u=rwx,go=rx +(0755) mode, group +.Sq Li daemon , +and the owner specified by the +.Sq Li du= +capability in the database (default 1, which corresponds to user +.Sq Li daemon ) . +.Sh SEE ALSO +.Xr lpr 1 , +.Xr printcap 5 , +.Xr lpd 8 +.Sh AUTHORS +The +.Nm chkprintcap +command was written by +.An Garrett A. Wollman Aq wollman@lcs.mit.edu . +.Sh BUGS +Not enough sanity-checking is done. At a minimum, the ownership and +mode of the spool directories should also be checked. Other +parameters whose value could cause +.Xr lpd 8 +to fail should be diagnosed. diff --git a/usr.sbin/lpr/chkprintcap/chkprintcap.c b/usr.sbin/lpr/chkprintcap/chkprintcap.c new file mode 100644 index 0000000..8b84656 --- /dev/null +++ b/usr.sbin/lpr/chkprintcap/chkprintcap.c @@ -0,0 +1,277 @@ +/* + * Copyright 1997 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +static const char copyright[] = + "Copyright (C) 1997, Massachusetts Institute of Technology\r\n"; +static const char rcsid[] = + "$FreeBSD$"; + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/stat.h> + +#include <err.h> +#include <errno.h> +#include <grp.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include <sys/param.h> /* needed for lp.h but not used here */ +#include <dirent.h> /* ditto */ +#include "lp.h" +#include "lp.local.h" + +static void check_spool_dirs(void); +static int interpret_error(const struct printer *pp, int error); +static void make_spool_dir(const struct printer *pp); +static void note_spool_dir(const struct printer *pp, const struct stat *st); +static void usage(void) __dead2; + +static int problems; /* number of problems encountered */ + +/* + * chkprintcap - check the printcap file for syntactic and semantic errors + * Returns the number of problems found. + */ +int +main(int argc, char **argv) +{ + int c, error, makedirs, more; + struct printer myprinter, *pp; + + makedirs = 0; + pp = &myprinter; + + while ((c = getopt(argc, argv, "df:")) != -1) { + switch (c) { + case 'd': + makedirs = 1; + break; + + case 'f': + setprintcap(optarg); + break; + + default: + usage(); + } + } + + if (optind != argc) + usage(); + + more = firstprinter(pp, &error); + if (interpret_error(pp, error) && more) + goto next; + + while (more) { + struct stat stab; + + errno = 0; + if (stat(pp->spool_dir, &stab) < 0) { + if (errno == ENOENT && makedirs) { + make_spool_dir(pp); + } else { + problems++; + warn("%s: %s", pp->printer, pp->spool_dir); + } + } else { + note_spool_dir(pp, &stab); + } + + /* Make other validity checks here... */ + +next: + more = nextprinter(pp, &error); + if (interpret_error(pp, error) && more) + goto next; + } + check_spool_dirs(); + return problems; +} + +/* + * Interpret the error code. Returns 1 if we should skip to the next + * record (as this record is unlikely to make sense). If the problem + * is very severe, exit. Otherwise, return zero. + */ +static int +interpret_error(const struct printer *pp, int error) +{ + switch(error) { + case PCAPERR_OSERR: + err(++problems, "reading printer database"); + case PCAPERR_TCLOOP: + ++problems; + warnx("%s: loop detected in tc= expansion", pp->printer); + return 1; + case PCAPERR_TCOPEN: + warnx("%s: unresolved tc= expansion", pp->printer); + return 1; + case PCAPERR_SUCCESS: + break; + default: + errx(++problems, "unknown printcap library error %d", error); + } + return 0; +} + +/* + * Keep the list of spool directories. Note that we don't whine + * until all spool directories are noted, so that all of the more serious + * problems are noted first. We keep the list sorted by st_dev and + * st_ino, so that the problem spool directories can be noted in + * a single loop. + */ +struct dirlist { + LIST_ENTRY(dirlist) link; + struct stat stab; + char *path; + char *printer; +}; + +static LIST_HEAD(, dirlist) dirlist; + +static int +lessp(const struct dirlist *a, const struct dirlist *b) +{ + if (a->stab.st_dev == b->stab.st_dev) + return a->stab.st_ino < b->stab.st_ino; + return a->stab.st_dev < b->stab.st_dev; +} + +static int +equal(const struct dirlist *a, const struct dirlist *b) +{ + return ((a->stab.st_dev == b->stab.st_dev) + && (a->stab.st_ino == b->stab.st_ino)); +} + +static void +note_spool_dir(const struct printer *pp, const struct stat *st) +{ + struct dirlist *dp, *dp2, *last; + + dp = malloc(sizeof *dp); + if (dp == 0) + err(++problems, "malloc(%lu)", (u_long)sizeof *dp); + + dp->stab = *st; + dp->printer = strdup(pp->printer); + if (dp->printer == 0) + err(++problems, "malloc(%lu)", strlen(pp->printer) + 1UL); + dp->path = strdup(pp->spool_dir); + if (dp->path == 0) + err(++problems, "malloc(%lu)", strlen(pp->spool_dir) + 1UL); + + last = 0; + dp2 = dirlist.lh_first; + while (dp2 && lessp(dp, dp2)) { + last = dp2; + dp2 = dp2->link.le_next; + } + + if (last) { + LIST_INSERT_AFTER(last, dp, link); + } else { + LIST_INSERT_HEAD(&dirlist, dp, link); + } +} + +static void +check_spool_dirs(void) +{ + struct dirlist *dp, *dp2; + + for (dp = dirlist.lh_first; dp; dp = dp2) { + dp2 = dp->link.le_next; + + if (dp2 != 0 && equal(dp, dp2)) { + ++problems; + if (strcmp(dp->path, dp2->path) == 0) { + warnx("%s and %s share the same spool, %s", + dp->printer, dp2->printer, dp->path); + } else { + warnx("%s (%s) and %s (%s) are the same " + "directory", dp->path, dp->printer, + dp2->path, dp2->printer); + } + continue; + } + /* Should probably check owners and modes here. */ + } +} + +#ifndef SPOOL_DIR_MODE +#define SPOOL_DIR_MODE (S_IRUSR | S_IWUSR | S_IXUSR \ + | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) +#endif + +static void +make_spool_dir(const struct printer *pp) +{ + char *sd = pp->spool_dir; + struct group *gr; + struct stat stab; + + if (mkdir(sd, S_IRUSR | S_IXUSR) < 0) { + problems++; + warn("%s: mkdir %s", pp->printer, sd); + return; + } + gr = getgrnam("daemon"); + if (gr == 0) + errx(++problems, "cannot locate daemon group"); + + if (chown(sd, pp->daemon_user, gr->gr_gid) < 0) { + ++problems; + warn("%s: cannot change ownership to %ld:%ld", sd, + (long)pp->daemon_user, (long)gr->gr_gid); + return; + } + + if (chmod(sd, SPOOL_DIR_MODE) < 0) { + ++problems; + warn("%s: cannot change mode to %lo", sd, (long)SPOOL_DIR_MODE); + return; + } + if (stat(sd, &stab) < 0) + err(++problems, "stat: %s", sd); + + note_spool_dir(pp, &stab); +} + +static void +usage(void) +{ + fprintf(stderr, "usage:\n\tchkprintcap [-d] [-f printcapfile]\n"); + exit(1); +} diff --git a/usr.sbin/lpr/common_source/Makefile b/usr.sbin/lpr/common_source/Makefile new file mode 100644 index 0000000..e5c6191 --- /dev/null +++ b/usr.sbin/lpr/common_source/Makefile @@ -0,0 +1,18 @@ +# $FreeBSD$ + +# +# Library of internal routines for the print spooler suite. +# Originally these were compiled separately into each program, +# but the library makes it much easier to modularize them. +# +LIB= lpr +SRCS= common.c displayq.c net.c printcap.c request.c rmjob.c \ + startdaemon.c +NOMAN= noman +NOPROFILE= noprofile +NOPIC= nopic +CFLAGS+= ${CWARNFLAGS} + +install: + +.include <bsd.lib.mk> diff --git a/usr.sbin/lpr/common_source/common.c b/usr.sbin/lpr/common_source/common.c new file mode 100644 index 0000000..67a1725 --- /dev/null +++ b/usr.sbin/lpr/common_source/common.c @@ -0,0 +1,592 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +/* +static char sccsid[] = "@(#)common.c 8.5 (Berkeley) 4/28/95"; +*/ +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> + +#include <dirent.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "lp.h" +#include "lp.local.h" +#include "pathnames.h" + +/* + * Routines and data common to all the line printer functions. + */ +char line[BUFSIZ]; +char *name; /* program name */ + +extern uid_t uid, euid; + +static int compar __P((const void *, const void *)); + +/* + * Getline reads a line from the control file cfp, removes tabs, converts + * new-line to null and leaves it in line. + * Returns 0 at EOF or the number of characters read. + */ +int +getline(cfp) + FILE *cfp; +{ + register int linel = 0; + register char *lp = line; + register int c; + + while ((c = getc(cfp)) != '\n' && linel+1 < sizeof(line)) { + if (c == EOF) + return(0); + if (c == '\t') { + do { + *lp++ = ' '; + linel++; + } while ((linel & 07) != 0 && linel+1 < sizeof(line)); + continue; + } + *lp++ = c; + linel++; + } + *lp++ = '\0'; + return(linel); +} + +/* + * Scan the current directory and make a list of daemon files sorted by + * creation time. + * Return the number of entries and a pointer to the list. + */ +int +getq(pp, namelist) + const struct printer *pp; + struct queue *(*namelist[]); +{ + register struct dirent *d; + register struct queue *q, **queue; + register int nitems; + struct stat stbuf; + DIR *dirp; + int arraysz; + + seteuid(euid); + if ((dirp = opendir(pp->spool_dir)) == NULL) + return(-1); + if (fstat(dirp->dd_fd, &stbuf) < 0) + goto errdone; + seteuid(uid); + + /* + * Estimate the array size by taking the size of the directory file + * and dividing it by a multiple of the minimum size entry. + */ + arraysz = (stbuf.st_size / 24); + queue = (struct queue **)malloc(arraysz * sizeof(struct queue *)); + if (queue == NULL) + goto errdone; + + nitems = 0; + while ((d = readdir(dirp)) != NULL) { + if (d->d_name[0] != 'c' || d->d_name[1] != 'f') + continue; /* daemon control files only */ + seteuid(euid); + if (stat(d->d_name, &stbuf) < 0) + continue; /* Doesn't exist */ + seteuid(uid); + q = (struct queue *)malloc(sizeof(time_t)+strlen(d->d_name)+1); + if (q == NULL) + goto errdone; + q->q_time = stbuf.st_mtime; + strcpy(q->q_name, d->d_name); + /* + * Check to make sure the array has space left and + * realloc the maximum size. + */ + if (++nitems > arraysz) { + arraysz *= 2; + queue = (struct queue **)realloc((char *)queue, + arraysz * sizeof(struct queue *)); + if (queue == NULL) + goto errdone; + } + queue[nitems-1] = q; + } + closedir(dirp); + if (nitems) + qsort(queue, nitems, sizeof(struct queue *), compar); + *namelist = queue; + return(nitems); + +errdone: + closedir(dirp); + return(-1); +} + +/* + * Compare modification times. + */ +static int +compar(p1, p2) + const void *p1, *p2; +{ + const struct queue *qe1, *qe2; + qe1 = *(const struct queue **)p1; + qe2 = *(const struct queue **)p2; + + if (qe1->q_time < qe2->q_time) + return (-1); + if (qe1->q_time > qe2->q_time) + return (1); + /* + * At this point, the two files have the same last-modification time. + * return a result based on filenames, so that 'cfA001some.host' will + * come before 'cfA002some.host'. Since the jobid ('001') will wrap + * around when it gets to '999', we also assume that '9xx' jobs are + * older than '0xx' jobs. + */ + if ((qe1->q_name[3] == '9') && (qe2->q_name[3] == '0')) + return (-1); + if ((qe1->q_name[3] == '0') && (qe2->q_name[3] == '9')) + return (1); + return (strcmp(qe1->q_name,qe2->q_name)); +} + +/* sleep n milliseconds */ +void +delay(n) + int n; +{ + struct timeval tdelay; + + if (n <= 0 || n > 10000) + fatal((struct printer *)0, /* fatal() knows how to deal */ + "unreasonable delay period (%d)", n); + tdelay.tv_sec = n / 1000; + tdelay.tv_usec = n * 1000 % 1000000; + (void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tdelay); +} + +char * +lock_file_name(pp, buf, len) + const struct printer *pp; + char *buf; + size_t len; +{ + static char staticbuf[MAXPATHLEN]; + + if (buf == 0) + buf = staticbuf; + if (len == 0) + len = MAXPATHLEN; + + if (pp->lock_file[0] == '/') { + buf[0] = '\0'; + strncpy(buf, pp->lock_file, len); + } else { + snprintf(buf, len, "%s/%s", pp->spool_dir, pp->lock_file); + } + return buf; +} + +char * +status_file_name(pp, buf, len) + const struct printer *pp; + char *buf; + size_t len; +{ + static char staticbuf[MAXPATHLEN]; + + if (buf == 0) + buf = staticbuf; + if (len == 0) + len = MAXPATHLEN; + + if (pp->status_file[0] == '/') { + buf[0] = '\0'; + strncpy(buf, pp->status_file, len); + } else { + snprintf(buf, len, "%s/%s", pp->spool_dir, pp->status_file); + } + return buf; +} + +/* routine to get a current timestamp, optionally in a standard-fmt string */ +void +lpd_gettime(tsp, strp, strsize) + struct timespec *tsp; + char *strp; + int strsize; +{ + struct timespec local_ts; + struct timeval btime; + char *destp; + char tempstr[TIMESTR_SIZE]; + + if (tsp == NULL) + tsp = &local_ts; + + /* some platforms have a routine called clock_gettime, but the + * routine does nothing but return "not implemented". */ + memset(tsp, 0, sizeof(struct timespec)); + if (clock_gettime(CLOCK_REALTIME, tsp)) { + /* nanosec-aware rtn failed, fall back to microsec-aware rtn */ + memset(tsp, 0, sizeof(struct timespec)); + gettimeofday(&btime, NULL); + tsp->tv_sec = btime.tv_sec; + tsp->tv_nsec = btime.tv_usec * 1000; + } + + /* caller may not need a character-ized version */ + if ((strp == NULL) || (strsize < 1)) + return; + + strftime(tempstr, TIMESTR_SIZE, LPD_TIMESTAMP_PATTERN, + localtime(&tsp->tv_sec)); + + /* + * This check is for implementations of strftime which treat %z + * (timezone as [+-]hhmm ) like %Z (timezone as characters), or + * completely ignore %z. This section is not needed on freebsd. + * I'm not sure this is completely right, but it should work OK + * for EST and EDT... + */ +#ifdef STRFTIME_WRONG_z + destp = strrchr(tempstr, ':'); + if (destp != NULL) { + destp += 3; + if ((*destp != '+') && (*destp != '-')) { + char savday[6]; + int tzmin = timezone / 60; + int tzhr = tzmin / 60; + if (daylight) + tzhr--; + strcpy(savday, destp + strlen(destp) - 4); + snprintf(destp, (destp - tempstr), "%+03d%02d", + (-1*tzhr), tzmin % 60); + strcat(destp, savday); + } + } +#endif + + if (strsize > TIMESTR_SIZE) { + strsize = TIMESTR_SIZE; + strp[TIMESTR_SIZE+1] = '\0'; + } + strncpy(strp, tempstr, strsize); +} + +/* routines for writing transfer-statistic records */ +void +trstat_init(pp, fname, filenum) + struct printer *pp; + const char *fname; + int filenum; +{ + register const char *srcp; + register char *destp, *endp; + + /* + * Figure out the job id of this file. The filename should be + * 'cf', 'df', or maybe 'tf', followed by a letter (or sometimes + * two), followed by the jobnum, followed by a hostname. + * The jobnum is usually 3 digits, but might be as many as 5. + * Note that some care has to be taken parsing this, as the + * filename could be coming from a remote-host, and thus might + * not look anything like what is expected... + */ + memset(pp->jobnum, 0, sizeof(pp->jobnum)); + pp->jobnum[0] = '0'; + srcp = strchr(fname, '/'); + if (srcp == NULL) + srcp = fname; + destp = &(pp->jobnum[0]); + endp = destp + 5; + while (*srcp != '\0' && (*srcp < '0' || *srcp > '9')) + srcp++; + while (*srcp >= '0' && *srcp <= '9' && destp < endp) + *(destp++) = *(srcp++); + + /* get the starting time in both numeric and string formats, and + * save those away along with the file-number */ + pp->jobdfnum = filenum; + lpd_gettime(&pp->tr_start, pp->tr_timestr, TIMESTR_SIZE); + + return; +} + +void +trstat_write(pp, sendrecv, bytecnt, userid, otherhost, orighost) + struct printer *pp; + tr_sendrecv sendrecv; + size_t bytecnt; + const char *userid; + const char *otherhost; + const char *orighost; +{ +#define STATLINE_SIZE 1024 + double trtime; + int remspace; + int statfile; + char thishost[MAXHOSTNAMELEN+1], statline[STATLINE_SIZE]; + const char *rectype, *statfname; + const char *lprhost, *sendhost, *recvhost, *recvdev; + char *eostat; +#define UPD_EOSTAT(xStr) do { \ + eostat = strchr(xStr, '\0'); \ + remspace = eostat - xStr; \ +} while(0) + + lpd_gettime(&pp->tr_done, NULL, 0); + trtime = DIFFTIME_TS(pp->tr_done, pp->tr_start); + + gethostname(thishost, sizeof(thishost)); + lprhost = sendhost = recvhost = recvdev = NULL; + switch (sendrecv) { + case TR_SENDING: + rectype = "send"; + statfname = pp->stat_send; + sendhost = thishost; + recvhost = otherhost; + break; + case TR_RECVING: + rectype = "recv"; + statfname = pp->stat_recv; + sendhost = otherhost; + recvhost = thishost; + break; + case TR_PRINTING: + /* copying to a device (presumably local, though things + * like 'net/CAP' can confuse this assumption...) */ + rectype = "prnt"; + statfname = pp->stat_send; + sendhost = thishost; + recvdev = _PATH_DEFDEVLP; + if (pp->lp) recvdev = pp->lp; + break; + default: + /* internal error... should we syslog/printf an error? */ + return; + } + if (statfname == NULL) return; + + /* + * the original-host and userid are found out by reading thru the + * cf (control-file) for the job. Unfortunately, on incoming jobs + * the df's (data-files) are sent before the matching cf, so the + * orighost & userid are generally not-available for incoming jobs. + * + * (it would be nice to create a work-around for that..) + */ + if (orighost && (*orighost != '\0')) + lprhost = orighost; + else + lprhost = ".na."; + if (*userid == '\0') userid = NULL; + + /* + * Format of statline. + * Some of the keywords listed here are not implemented here, but + * they are listed to reserve the meaning for a given keyword. + * Fields are separated by a blank. The fields in statline are: + * <tstamp> - time the transfer started + * <ptrqueue> - name of the printer queue (the short-name...) + * <hname> - hostname the file originally came from (the + * 'lpr host'), if known, or "_na_" if not known. + * <xxx> - id of job from that host (generally three digits) + * <n> - file count (# of file within job) + * <rectype> - 4-byte field indicating the type of transfer + * statistics record. "send" means it's from the + * host sending a datafile, "recv" means it's from + * a host as it receives a datafile. + * user=<userid> - user who sent the job (if known) + * secs=<n> - seconds it took to transfer the file + * bytes=<n> - number of bytes transfered (ie, "bytecount") + * bps=<n.n>e<n> - Bytes/sec (if the transfer was "big enough" + * for this to be useful) + * ! top=<str> - type of printer (if the type is defined in + * printcap, and if this statline is for sending + * a file to that ptr) + * ! qls=<n> - queue-length at start of send/print-ing a job + * ! qle=<n> - queue-length at end of send/print-ing a job + * sip=<addr> - IP address of sending host, only included when + * receiving a job. + * shost=<hname> - sending host (if that does != the original host) + * rhost=<hname> - hostname receiving the file (ie, "destination") + * rdev=<dev> - device receiving the file, when the file is being + * send to a device instead of a remote host. + * + * Note: A single print job may be transferred multiple times. The + * original 'lpr' occurs on one host, and that original host might + * send to some interim host (or print server). That interim host + * might turn around and send the job to yet another host (most likely + * the real printer). The 'shost=' parameter is only included if the + * sending host for this particular transfer is NOT the same as the + * host which did the original 'lpr'. + * + * Many values have 'something=' tags before them, because they are + * in some sense "optional", or their order may vary. "Optional" may + * mean in the sense that different SITES might choose to have other + * fields in the record, or that some fields are only included under + * some circumstances. Programs processing these records should not + * assume the order or existence of any of these keyword fields. + */ + snprintf(statline, STATLINE_SIZE, "%s %s %s %s %03ld %s", + pp->tr_timestr, pp->printer, lprhost, + pp->jobnum, pp->jobdfnum, rectype); + UPD_EOSTAT(statline); + + if (userid != NULL) { + snprintf(eostat, remspace, " user=%s", userid); + UPD_EOSTAT(statline); + } + snprintf(eostat, remspace, " secs=%#.2f bytes=%u", trtime, bytecnt); + UPD_EOSTAT(statline); + + /* the bps field duplicates info from bytes and secs, so do not + * bother to include it for very small files */ + if ((bytecnt > 25000) && (trtime > 1.1)) { + snprintf(eostat, remspace, " bps=%#.2e", + ((double)bytecnt/trtime)); + UPD_EOSTAT(statline); + } + + if (sendrecv == TR_RECVING) { + if (remspace > 5+strlen(from_ip) ) { + snprintf(eostat, remspace, " sip=%s", from_ip); + UPD_EOSTAT(statline); + } + } + if (0 != strcmp(lprhost, sendhost)) { + if (remspace > 7+strlen(sendhost) ) { + snprintf(eostat, remspace, " shost=%s", sendhost); + UPD_EOSTAT(statline); + } + } + if (recvhost) { + if (remspace > 7+strlen(recvhost) ) { + snprintf(eostat, remspace, " rhost=%s", recvhost); + UPD_EOSTAT(statline); + } + } + if (recvdev) { + if (remspace > 6+strlen(recvdev) ) { + snprintf(eostat, remspace, " rdev=%s", recvdev); + UPD_EOSTAT(statline); + } + } + if (remspace > 1) { + strcpy(eostat, "\n"); + } else { + /* probably should back up to just before the final " x=".. */ + strcpy(statline+STATLINE_SIZE-2, "\n"); + } + statfile = open(statfname, O_WRONLY|O_APPEND, 0664); + if (statfile < 0) { + /* statfile was given, but we can't open it. should we + * syslog/printf this as an error? */ + return; + } + write(statfile, statline, strlen(statline)); + close(statfile); + + return; +#undef UPD_EOSTAT +} + +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +void +#ifdef __STDC__ +fatal(const struct printer *pp, const char *msg, ...) +#else +fatal(pp, msg, va_alist) + const struct printer *pp; + char *msg; + va_dcl +#endif +{ + va_list ap; +#ifdef __STDC__ + va_start(ap, msg); +#else + va_start(ap); +#endif + if (from != host) + (void)printf("%s: ", host); + (void)printf("%s: ", name); + if (pp && pp->printer) + (void)printf("%s: ", pp->printer); + (void)vprintf(msg, ap); + va_end(ap); + (void)putchar('\n'); + exit(1); +} + +/* + * Close all file descriptors from START on up. + * This is a horrific kluge, since getdtablesize() might return + * ``infinity'', in which case we will be spending a long time + * closing ``files'' which were never open. Perhaps it would + * be better to close the first N fds, for some small value of N. + */ +void +closeallfds(start) + int start; +{ + int stop = getdtablesize(); + for (; start < stop; start++) + close(start); +} + diff --git a/usr.sbin/lpr/common_source/displayq.c b/usr.sbin/lpr/common_source/displayq.c new file mode 100644 index 0000000..7b1df2c --- /dev/null +++ b/usr.sbin/lpr/common_source/displayq.c @@ -0,0 +1,549 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +/* +static char sccsid[] = "@(#)displayq.c 8.4 (Berkeley) 4/28/95"; +*/ +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#define psignal foil_gcc_psignal +#define sys_siglist foil_gcc_siglist +#include <unistd.h> +#undef psignal +#undef sys_siglist + +#include "lp.h" +#include "lp.local.h" +#include "pathnames.h" + +/* + * Routines to display the state of the queue. + */ +#define JOBCOL 40 /* column for job # in -l format */ +#define OWNCOL 7 /* start of Owner column in normal */ +#define SIZCOL 62 /* start of Size column in normal */ + +/* + * Stuff for handling job specifications + */ +extern uid_t uid, euid; + +static int col; /* column on screen */ +static char current[40]; /* current file being printed */ +static char file[132]; /* print file name */ +static int first; /* first file in ``files'' column? */ +static int garbage; /* # of garbage cf files */ +static int lflag; /* long output option */ +static int rank; /* order to be printed (-1=none, 0=active) */ +static long totsize; /* total print job size in bytes */ + +static char *head0 = "Rank Owner Job Files"; +static char *head1 = "Total Size\n"; + +static void alarmhandler __P((int)); +static void warn __P((const struct printer *pp)); + +/* + * Display the current state of the queue. Format = 1 if long format. + */ +void +displayq(pp, format) + struct printer *pp; + int format; +{ + register struct queue *q; + register int i, nitems, fd, ret; + register char *cp; + struct queue **queue; + struct stat statb; + FILE *fp; + void (*savealrm)(int); + + lflag = format; + totsize = 0; + rank = -1; + + if ((cp = checkremote(pp))) { + printf("Warning: %s\n", cp); + free(cp); + } + + /* + * Print out local queue + * Find all the control files in the spooling directory + */ + seteuid(euid); + if (chdir(pp->spool_dir) < 0) + fatal(pp, "cannot chdir to spooling directory: %s", + strerror(errno)); + seteuid(uid); + if ((nitems = getq(pp, &queue)) < 0) + fatal(pp, "cannot examine spooling area\n"); + seteuid(euid); + ret = stat(pp->lock_file, &statb); + seteuid(uid); + if (ret >= 0) { + if (statb.st_mode & LFM_PRINT_DIS) { + if (pp->remote) + printf("%s: ", host); + printf("Warning: %s is down: ", pp->printer); + seteuid(euid); + fd = open(pp->status_file, O_RDONLY|O_SHLOCK); + seteuid(uid); + if (fd >= 0) { + while ((i = read(fd, line, sizeof(line))) > 0) + (void) fwrite(line, 1, i, stdout); + (void) close(fd); /* unlocks as well */ + } else + putchar('\n'); + } + if (statb.st_mode & LFM_QUEUE_DIS) { + if (pp->remote) + printf("%s: ", host); + printf("Warning: %s queue is turned off\n", + pp->printer); + } + } + + if (nitems) { + seteuid(euid); + fp = fopen(pp->lock_file, "r"); + seteuid(uid); + if (fp == NULL) + warn(pp); + else { + /* get daemon pid */ + cp = current; + while ((i = getc(fp)) != EOF && i != '\n') + *cp++ = i; + *cp = '\0'; + i = atoi(current); + if (i <= 0) { + ret = -1; + } else { + seteuid(euid); + ret = kill(i, 0); + seteuid(uid); + } + if (ret < 0) { + warn(pp); + } else { + /* read current file name */ + cp = current; + while ((i = getc(fp)) != EOF && i != '\n') + *cp++ = i; + *cp = '\0'; + /* + * Print the status file. + */ + if (pp->remote) + printf("%s: ", host); + seteuid(euid); + fd = open(pp->status_file, O_RDONLY|O_SHLOCK); + seteuid(uid); + if (fd >= 0) { + while ((i = read(fd, line, + sizeof(line))) > 0) + fwrite(line, 1, i, stdout); + close(fd); /* unlocks as well */ + } else + putchar('\n'); + } + (void) fclose(fp); + } + /* + * Now, examine the control files and print out the jobs to + * be done for each user. + */ + if (!lflag) + header(); + for (i = 0; i < nitems; i++) { + q = queue[i]; + inform(pp, q->q_name); + free(q); + } + free(queue); + } + if (!pp->remote) { + if (nitems == 0) + puts("no entries"); + return; + } + + /* + * Print foreign queue + * Note that a file in transit may show up in either queue. + */ + if (nitems) + putchar('\n'); + (void) snprintf(line, sizeof(line), "%c%s", format ? '\4' : '\3', + pp->remote_queue); + cp = line; + for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) { + cp += strlen(cp); + (void) sprintf(cp, " %d", requ[i]); + } + for (i = 0; i < users && cp - line + 1 + strlen(user[i]) < + sizeof(line) - 1; i++) { + cp += strlen(cp); + *cp++ = ' '; + (void) strcpy(cp, user[i]); + } + strcat(line, "\n"); + savealrm = signal(SIGALRM, alarmhandler); + alarm(pp->conn_timeout); + fd = getport(pp, pp->remote_host, 0); + alarm(0); + (void)signal(SIGALRM, savealrm); + if (fd < 0) { + if (from != host) + printf("%s: ", host); + printf("connection to %s is down\n", pp->remote_host); + } + else { + i = strlen(line); + if (write(fd, line, i) != i) + fatal(pp, "Lost connection"); + while ((i = read(fd, line, sizeof(line))) > 0) + (void) fwrite(line, 1, i, stdout); + (void) close(fd); + } +} + +/* + * Print a warning message if there is no daemon present. + */ +static void +warn(pp) + const struct printer *pp; +{ + if (pp->remote) + printf("%s: ", host); + puts("Warning: no daemon present"); + current[0] = '\0'; +} + +/* + * Print the header for the short listing format + */ +void +header() +{ + printf(head0); + col = strlen(head0)+1; + blankfill(SIZCOL); + printf(head1); +} + +void +inform(pp, cf) + const struct printer *pp; + char *cf; +{ + register int copycnt; + char savedname[MAXPATHLEN+1]; + FILE *cfp; + + /* + * There's a chance the control file has gone away + * in the meantime; if this is the case just keep going + */ + seteuid(euid); + if ((cfp = fopen(cf, "r")) == NULL) + return; + seteuid(uid); + + if (rank < 0) + rank = 0; + if (pp->remote || garbage || strcmp(cf, current)) + rank++; + + /* + * The cf-file may include commands to print more than one datafile + * from the user. For each datafile, the cf-file contains at least + * one line which starts with some format-specifier ('a'-'z'), and + * a second line ('N'ame) which indicates the original name the user + * specified for that file. There can be multiple format-spec lines + * for a single Name-line, if the user requested multiple copies of + * that file. Standard lpr puts the format-spec line(s) before the + * Name-line, while lprNG puts the Name-line before the format-spec + * line(s). This section needs to handle the lines in either order. + */ + copycnt = 0; + file[0] = '\0'; + savedname[0] = '\0'; + while (getline(cfp)) { + switch (line[0]) { + case 'P': /* Was this file specified in the user's list? */ + if (!inlist(line+1, cf)) { + fclose(cfp); + return; + } + if (lflag) { + printf("\n%s: ", line+1); + col = strlen(line+1) + 2; + prank(rank); + blankfill(JOBCOL); + printf(" [job %s]\n", cf+3); + } else { + col = 0; + prank(rank); + blankfill(OWNCOL); + printf("%-10s %-3d ", line+1, atoi(cf+3)); + col += 16; + first = 1; + } + continue; + default: /* some format specifer and file name? */ + if (line[0] < 'a' || line[0] > 'z') + break; + if (copycnt == 0 || strcmp(file, line+1) != 0) { + strncpy(file, line + 1, sizeof(file) - 1); + file[sizeof(file) - 1] = '\0'; + } + copycnt++; + /* + * deliberately 'continue' to another getline(), so + * all format-spec lines for this datafile are read + * in and counted before calling show() + */ + continue; + case 'N': + strncpy(savedname, line + 1, sizeof(savedname) - 1); + savedname[sizeof(savedname) - 1] = '\0'; + break; + } + if ((file[0] != '\0') && (savedname[0] != '\0')) { + show(savedname, file, copycnt); + copycnt = 0; + file[0] = '\0'; + savedname[0] = '\0'; + } + } + fclose(cfp); + /* check for a file which hasn't been shown yet */ + if (file[0] != '\0') { + if (savedname[0] == '\0') { + /* a safeguard in case the N-ame line is missing */ + strncpy(savedname, file, sizeof(savedname) - 1); + savedname[sizeof(savedname) - 1] = '\0'; + } + show(savedname, file, copycnt); + } + if (!lflag) { + blankfill(SIZCOL); + printf("%ld bytes\n", totsize); + totsize = 0; + } +} + +int +inlist(name, file) + char *name, *file; +{ + register int *r, n; + register char **u, *cp; + + if (users == 0 && requests == 0) + return(1); + /* + * Check to see if it's in the user list + */ + for (u = user; u < &user[users]; u++) + if (!strcmp(*u, name)) + return(1); + /* + * Check the request list + */ + for (n = 0, cp = file+3; isdigit(*cp); ) + n = n * 10 + (*cp++ - '0'); + for (r = requ; r < &requ[requests]; r++) + if (*r == n && !strcmp(cp, from)) + return(1); + return(0); +} + +void +show(nfile, file, copies) + register char *nfile, *file; + int copies; +{ + if (strcmp(nfile, " ") == 0) + nfile = "(standard input)"; + if (lflag) + ldump(nfile, file, copies); + else + dump(nfile, file, copies); +} + +/* + * Fill the line with blanks to the specified column + */ +void +blankfill(n) + register int n; +{ + while (col++ < n) + putchar(' '); +} + +/* + * Give the abbreviated dump of the file names + */ +void +dump(nfile, file, copies) + char *nfile, *file; + int copies; +{ + struct stat lbuf; + const char etctmpl[] = ", ..."; + char etc[sizeof(etctmpl)]; + char *lastsep; + short fill, nlen; + short rem, remetc; + + /* + * Print as many filenames as will fit + * (leaving room for the 'total size' field) + */ + fill = first ? 0 : 2; /* fill space for ``, '' */ + nlen = strlen(nfile); + rem = SIZCOL - 1 - col; + if (nlen + fill > rem) { + if (first) { + /* print the right-most part of the name */ + printf("...%s ", &nfile[3+nlen-rem]); + col = SIZCOL; + } else if (rem > 0) { + /* fit as much of the etc-string as we can */ + remetc = rem; + if (rem > strlen(etctmpl)) + remetc = strlen(etctmpl); + etc[0] = '\0'; + strncat(etc, etctmpl, remetc); + printf(etc); + col += remetc; + rem -= remetc; + /* room for the last segment of this filename? */ + lastsep = strrchr(nfile, '/'); + if ((lastsep != NULL) && (rem > strlen(lastsep))) { + /* print the right-most part of this name */ + printf("%s", lastsep); + col += strlen(lastsep); + } else { + /* do not pack any more names in here */ + blankfill(SIZCOL); + } + } + } else { + if (!first) + printf(", "); + printf("%s", nfile); + col += nlen + fill; + } + first = 0; + + seteuid(euid); + if (*file && !stat(file, &lbuf)) + totsize += copies * lbuf.st_size; + seteuid(uid); +} + +/* + * Print the long info about the file + */ +void +ldump(nfile, file, copies) + char *nfile, *file; + int copies; +{ + struct stat lbuf; + + putchar('\t'); + if (copies > 1) + printf("%-2d copies of %-19s", copies, nfile); + else + printf("%-32s", nfile); + if (*file && !stat(file, &lbuf)) + printf(" %qd bytes", (long long) lbuf.st_size); + else + printf(" ??? bytes"); + putchar('\n'); +} + +/* + * Print the job's rank in the queue, + * update col for screen management + */ +void +prank(n) + int n; +{ + char rline[100]; + static char *r[] = { + "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" + }; + + if (n == 0) { + printf("active"); + col += 6; + return; + } + if ((n/10)%10 == 1) + (void)snprintf(rline, sizeof(rline), "%dth", n); + else + (void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]); + col += strlen(rline); + printf("%s", rline); +} + +void +alarmhandler(signo) + int signo; +{ + /* ignored */ +} diff --git a/usr.sbin/lpr/common_source/lp.h b/usr.sbin/lpr/common_source/lp.h new file mode 100644 index 0000000..276108a --- /dev/null +++ b/usr.sbin/lpr/common_source/lp.h @@ -0,0 +1,267 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: @(#)lp.h 8.2 (Berkeley) 4/28/95 + * $FreeBSD$ + */ + +#include <sys/queue.h> +#include <time.h> + +/* + * All this information used to be in global static variables shared + * mysteriously by various parts of the lpr/lpd suite. + * This structure attempts to centralize all these declarations in the + * hope that they can later be made more dynamic. + */ +enum lpd_filters { LPF_CIFPLOT, LPF_DVI, LPF_GRAPH, LPF_INPUT, + LPF_DITROFF, LPF_OUTPUT, LPF_FORTRAN, LPF_TROFF, + LPF_RASTER, LPF_COUNT }; +/* NB: there is a table in common.c giving the mapping from capability names */ + +struct printer { + char *printer; /* printer name */ + int remote; /* true if RM points to a remote host */ + int rp_matches_local; /* true if rp has same name as us */ + int tof; /* true if we are at top-of-form */ + /* ------------------------------------------------------ */ + char *acct_file; /* AF: accounting file */ + long baud_rate; /* BR: baud rate if lp is a tty */ + char *filters[LPF_COUNT]; /* CF, DF, GF, IF, NF, OF, RF, TF, VF */ + long conn_timeout; /* CT: TCP connection timeout */ + long daemon_user; /* DU: daemon user id -- XXX belongs ???? */ + char *form_feed; /* FF: form feed */ + long header_last; /* HL: print header last */ + char *log_file; /* LF: log file */ + char *lock_file; /* LO: lock file */ + char *lp; /* LP: device name or network address */ + long max_copies; /* MC: maximum number of copies allowed */ + long max_blocks; /* MX: maximum number of blocks to copy */ + long price100; /* PC: price per 100 units of output */ + long page_length; /* PL: page length */ + long page_width; /* PW: page width */ + long page_pwidth; /* PX: page width in pixels */ + long page_plength; /* PY: page length in pixels */ + char *restrict_grp; /* RG: restricted group */ + char *remote_host; /* RM: remote machine name */ + char *remote_queue; /* RP: remote printer name */ + long restricted; /* RS: restricted to those with local accts */ + long rw; /* RW: open LP for reading and writing */ + long short_banner; /* SB: short banner */ + long no_copies; /* SC: suppress multiple copies */ + char *spool_dir; /* SD: spool directory */ + long no_formfeed; /* SF: suppress FF on each print job */ + long no_header; /* SH: suppress header page */ + char *stat_recv; /* SR: statistics file, receiving jobs */ + char *stat_send; /* SS: statistics file, sending jobs */ + char *status_file; /* ST: status file name */ + char *trailer; /* TR: trailer string send when Q empties */ + char *mode_set; /* MS: mode set, a la stty */ + + /* variables used by trstat*() to keep statistics on file transfers */ +#define JOBNUM_SIZE 8 + char jobnum[JOBNUM_SIZE]; + long jobdfnum; /* current datafile number within job */ + struct timespec tr_start, tr_done; +#define TIMESTR_SIZE 40 /* holds result from LPD_TIMESTAMP_PATTERN */ + char tr_timestr[TIMESTR_SIZE]; +#define DIFFTIME_TS(endTS,startTS) \ + ((double)(endTS.tv_sec - startTS.tv_sec) \ + + (endTS.tv_nsec - startTS.tv_nsec) * 1.0e-9) +}; + +/* + * Lists of user names and job numbers, for the benefit of the structs + * defined below. We use TAILQs so that requests don't get mysteriously + * reversed in process. + */ +struct req_user { + TAILQ_ENTRY(req_user) ru_link; /* macro glue */ + char ru_uname[1]; /* name of user */ +}; +TAILQ_HEAD(req_user_head, req_user); + +struct req_file { + TAILQ_ENTRY(req_file) rf_link; /* macro glue */ + char rf_type; /* type (lowercase cf file letter) of file */ + char *rf_prettyname; /* user-visible name of file */ + char rf_fname[1]; /* name of file */ +}; +TAILQ_HEAD(req_file_head, req_file); + +struct req_jobid { + TAILQ_ENTRY(req_jobid) rj_link; /* macro glue */ + int rj_job; /* job number */ +}; +TAILQ_HEAD(req_jobid_head, req_jobid); + +/* + * Encapsulate all the information relevant to a request in the + * lpr/lpd protocol. + */ +enum req_type { REQ_START, REQ_RECVJOB, REQ_LIST, REQ_DELETE }; + +struct request { + enum req_type type; /* what sort of request is this? */ + struct printer prtr; /* which printer is it for? */ + int remote; /* did request arrive over network? */ + char *logname; /* login name of requesting user */ + char *authname; /* authenticated identity of requesting user */ + char *prettyname; /* ``pretty'' name of requesting user */ + int privileged; /* was the request from a privileged user? */ + void *authinfo; /* authentication information */ + int authentic; /* was the request securely authenticated? */ + + /* Information for queries and deletes... */ + int nusers; /* length of following list... */ + struct req_user_head users; /* list of users to query/delete */ + int njobids; /* length of following list... */ + struct req_jobid_head jobids; /* list of jobids to query/delete */ +}; + +/* + * Global definitions for the line printer system. + */ +extern char line[BUFSIZ]; +extern char *name; /* program name */ + /* host machine name */ +extern char host[MAXHOSTNAMELEN]; +extern char *from; /* client's machine name */ +#define MAXIPSTRLEN 32 /* maxlen of an IP-address as a string */ +extern char from_ip[MAXIPSTRLEN]; /* client machine's IP address */ + +extern int requ[]; /* job number of spool entries */ +extern int requests; /* # of spool requests */ +extern char *user[]; /* users to process */ +extern int users; /* # of users in user array */ +extern char *person; /* name of person doing lprm */ + +/* + * Structure used for building a sorted list of control files. + */ +struct queue { + time_t q_time; /* modification time */ + char q_name[MAXNAMLEN+1]; /* control file name */ +}; + +/* lpr/lpd generates readable timestamps for logfiles, etc. Have all those + * timestamps be in the same format wrt strftime(). This is ISO 8601 format, + * with the addition of an easy-readable day-of-the-week field. Note that + * '%T' = '%H:%M:%S', and that '%z' is not available on all platforms. + */ +#define LPD_TIMESTAMP_PATTERN "%Y-%m-%dT%T%z %a" + +/* + * Codes to indicate which statistic records trstat_write should write. + */ +typedef enum { TR_SENDING, TR_RECVING, TR_PRINTING } tr_sendrecv; + +/* + * Error codes for our mini printcap library. + */ +#define PCAPERR_TCLOOP (-3) +#define PCAPERR_OSERR (-2) +#define PCAPERR_NOTFOUND (-1) +#define PCAPERR_SUCCESS 0 +#define PCAPERR_TCOPEN 1 + +/* + * File modes for the various status files maintained by lpd. + */ +#define LOCK_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) +#define LFM_PRINT_DIS (S_IXUSR) +#define LFM_QUEUE_DIS (S_IXGRP) +#define LFM_RESET_QUE (S_IXOTH) + +#define STAT_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) +#define LOG_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) +#define TEMP_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) + +/* + * Command codes used in the protocol. + */ +#define CMD_CHECK_QUE '\1' +#define CMD_TAKE_THIS '\2' +#define CMD_SHOWQ_SHORT '\3' +#define CMD_SHOWQ_LONG '\4' +#define CMD_RMJOB '\5' + +#include <sys/cdefs.h> + +__BEGIN_DECLS +struct dirent; + +void blankfill __P((int)); +char *checkremote __P((struct printer *pp)); +int chk __P((char *)); +void closeallfds __P((int start)); +void delay __P((int)); +void displayq __P((struct printer *pp, int format)); +void dump __P((char *, char *, int)); +void fatal __P((const struct printer *pp, const char *fmp, ...)); +int firstprinter __P((struct printer *pp, int *status)); +void free_printer __P((struct printer *pp)); +void free_request __P((struct request *rp)); +int getline __P((FILE *)); +int getport __P((const struct printer *pp, const char *, int)); +int getprintcap __P((const char *printer, struct printer *pp)); +int getq __P((const struct printer *, struct queue *(*[]))); +void header __P((void)); +void inform __P((const struct printer *pp, char *cf)); +void init_printer __P((struct printer *pp)); +void init_request __P((struct request *rp)); +int inlist __P((char *, char *)); +int iscf __P((struct dirent *)); +int isowner __P((char *, char *)); +void ldump __P((char *, char *, int)); +void lastprinter __P((void)); +int lockchk __P((struct printer *pp, char *)); +char *lock_file_name __P((const struct printer *pp, char *buf, size_t len)); +void lpd_gettime __P((struct timespec *_tsp, char *_strp, int _strsize)); +int nextprinter __P((struct printer *pp, int *status)); +const +char *pcaperr __P((int error)); +void prank __P((int)); +void process __P((const struct printer *pp, char *)); +void rmjob __P((const char *printer)); +void rmremote __P((const struct printer *pp)); +void setprintcap __P((char *newprintcap)); +void show __P((char *, char *, int)); +int startdaemon __P((const struct printer *pp)); +char *status_file_name __P((const struct printer *pp, char *buf, + size_t len)); +void trstat_init __P((struct printer *pp, const char *fname, int filenum)); +void trstat_write __P((struct printer *pp, tr_sendrecv sendrecv, + size_t bytecnt, const char *userid, + const char *otherhost, const char *orighost)); +ssize_t writel __P((int s, ...)); +__END_DECLS diff --git a/usr.sbin/lpr/common_source/lp.local.h b/usr.sbin/lpr/common_source/lp.local.h new file mode 100644 index 0000000..bc60549 --- /dev/null +++ b/usr.sbin/lpr/common_source/lp.local.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)lp.local.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Possibly, local parameters to the spooling system + */ + +/* + * Defaults for line printer capabilities data base + */ +#define DEFLP "lp" +#define DEFLOCK "lock" +#define DEFSTAT "status" +#define DEFMX 1000 +#define DEFMAXCOPIES 0 +#define DEFFF "\f" +#define DEFWIDTH 132 +#define DEFLENGTH 66 +#define DEFUID 1 +#define DEFTIMEOUT 120 + +/* + * When files are created in the spooling area, they are normally + * readable only by their owner and the spooling group. If you + * want otherwise, change this mode. + */ +#define FILMOD 0660 + +/* + * Printer is assumed to support LINELEN (for block chars) + * and background character (blank) is a space + */ +#define LINELEN 132 +#define BACKGND ' ' + +#define HEIGHT 9 /* height of characters */ +#define WIDTH 8 /* width of characters */ +#define DROP 3 /* offset to drop characters with descenders */ + +/* + * Define TERMCAP if the terminal capabilites are to be used for lpq. + */ +#define TERMCAP + +/* + * Maximum number of user and job requests for lpq and lprm. + */ +#define MAXUSERS 50 +#define MAXREQUESTS 50 diff --git a/usr.sbin/lpr/common_source/net.c b/usr.sbin/lpr/common_source/net.c new file mode 100644 index 0000000..4cfabfa --- /dev/null +++ b/usr.sbin/lpr/common_source/net.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: @(#)common.c 8.5 (Berkeley) 4/28/95 + */ + +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/uio.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <dirent.h> /* required for lp.h, not used here */ +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "lp.h" +#include "lp.local.h" +#include "pathnames.h" + +char host[MAXHOSTNAMELEN]; /* host machine name */ +char *from = host; /* client's machine name */ +char from_ip[MAXIPSTRLEN] = ""; /* client machine's IP address */ + +extern uid_t uid, euid; + +/* + * Create a TCP connection to host "rhost" at port "rport". + * If rport == 0, then use the printer service port. + * Most of this code comes from rcmd.c. + */ +int +getport(const struct printer *pp, const char *rhost, int rport) +{ + struct hostent *hp; + struct servent *sp; + struct sockaddr_in sin; + int s, timo = 1, lport = IPPORT_RESERVED - 1; + int err; + + /* + * Get the host address and port number to connect to. + */ + if (rhost == NULL) + fatal(pp, "no remote host to connect to"); + bzero((char *)&sin, sizeof(sin)); + sin.sin_len = sizeof sin; + sin.sin_family = AF_INET; + if (inet_aton(rhost, &sin.sin_addr) == 0) { + hp = gethostbyname2(rhost, AF_INET); + if (hp == NULL) + fatal(pp, "cannot resolve %s: %s", rhost, + hstrerror(h_errno)); + /* XXX - should deal with more addresses */ + sin.sin_addr = *(struct in_addr *)hp->h_addr_list[0]; + } + if (rport == 0) { + sp = getservbyname("printer", "tcp"); + if (sp == NULL) + fatal(pp, "printer/tcp: unknown service"); + sin.sin_port = sp->s_port; + } else + sin.sin_port = htons(rport); + + /* + * Try connecting to the server. + */ +retry: + seteuid(euid); + s = rresvport(&lport); + seteuid(uid); + if (s < 0) + return(-1); + if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + err = errno; + (void) close(s); + errno = err; + /* + * This used to decrement lport, but the current semantics + * of rresvport do not provide such a function (in fact, + * rresvport should guarantee that the chosen port will + * never result in an EADDRINUSE). + */ + if (errno == EADDRINUSE) + goto retry; + + if (errno == ECONNREFUSED && timo <= 16) { + sleep(timo); + timo *= 2; + goto retry; + } + return(-1); + } + return(s); +} + +/* + * Figure out whether the local machine is the same + * as the remote machine (RM) entry (if it exists). + * We do this by counting the intersection of our + * address list and theirs. This is better than the + * old method (comparing the canonical names), as it + * allows load-sharing between multiple print servers. + * The return value is an error message which must be + * free()d. + */ +char * +checkremote(struct printer *pp) +{ + char name[MAXHOSTNAMELEN]; + register struct hostent *hp; + char *err; + struct in_addr *localaddrs; + int i, j, nlocaladdrs, ncommonaddrs; + + if (!pp->rp_matches_local) { /* Remote printer doesn't match local */ + pp->remote = 1; + return NULL; + } + + pp->remote = 0; /* assume printer is local */ + if (pp->remote_host != NULL) { + /* get the addresses of the local host */ + gethostname(name, sizeof(name)); + name[sizeof(name) - 1] = '\0'; + hp = gethostbyname2(name, AF_INET); + if (hp == (struct hostent *) NULL) { + asprintf(&err, "unable to get official name " + "for local machine %s: %s", + name, hstrerror(h_errno)); + return err; + } + for (i = 0; hp->h_addr_list[i]; i++) + ; + nlocaladdrs = i; + localaddrs = malloc(i * sizeof(struct in_addr)); + if (localaddrs == 0) { + asprintf(&err, "malloc %lu bytes failed", + (u_long)i * sizeof(struct in_addr)); + return err; + } + for (i = 0; hp->h_addr_list[i]; i++) + localaddrs[i] = *(struct in_addr *)hp->h_addr_list[i]; + + /* get the official name of RM */ + hp = gethostbyname2(pp->remote_host, AF_INET); + if (hp == (struct hostent *) NULL) { + asprintf(&err, "unable to get address list for " + "remote machine %s: %s", + pp->remote_host, hstrerror(h_errno)); + free(localaddrs); + return err; + } + + ncommonaddrs = 0; + for (i = 0; i < nlocaladdrs; i++) { + for (j = 0; hp->h_addr_list[j]; j++) { + char *them = hp->h_addr_list[j]; + if (localaddrs[i].s_addr == + (*(struct in_addr *)them).s_addr) + ncommonaddrs++; + } + } + + /* + * if the two hosts do not share at least one IP address + * then the printer must be remote. + */ + if (ncommonaddrs == 0) + pp->remote = 1; + free(localaddrs); + } + return NULL; +} + +/* + * This isn't really network-related, but it's used here to write + * multi-part strings onto sockets without using stdio. Return + * values are as for writev(2). + */ +ssize_t +writel(int s, ...) +{ + va_list ap; + int i, n; + const char *cp; +#define NIOV 12 + struct iovec iov[NIOV], *iovp = iov; + ssize_t retval; + + /* first count them */ + va_start(ap, s); + n = 0; + do { + cp = va_arg(ap, char *); + n++; + } while (cp); + va_end(ap); + n--; /* correct for count of trailing null */ + + if (n > NIOV) { + iovp = malloc(n * sizeof *iovp); + if (iovp == 0) + return -1; + } + + /* now make up iovec and send */ + va_start(ap, s); + for (i = 0; i < n; i++) { + iovp[i].iov_base = va_arg(ap, char *); + iovp[i].iov_len = strlen(iovp[i].iov_base); + } + va_end(ap); + retval = writev(s, iovp, n); + if (iovp != iov) + free(iovp); + return retval; +} diff --git a/usr.sbin/lpr/common_source/pathnames.h b/usr.sbin/lpr/common_source/pathnames.h new file mode 100644 index 0000000..78ccc7b --- /dev/null +++ b/usr.sbin/lpr/common_source/pathnames.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#include <paths.h> + +#define _PATH_DEFDEVLP "/dev/lp" +#define _PATH_DEFSPOOL "/var/spool/output/lpd" +#define _PATH_HOSTSEQUIV "/etc/hosts.equiv" +#define _PATH_HOSTSLPD "/etc/hosts.lpd" +#define _PATH_MASTERLOCK "/var/spool/output/lpd.lock" +#define _PATH_PR "/usr/bin/pr" +#define _PATH_PRINTCAP "/etc/printcap" +#define _PATH_SOCKETNAME "/var/run/printer" +#define _PATH_VFONT "/usr/libdata/vfont/" +#define _PATH_VFONTB "/usr/libdata/vfont/B" +#define _PATH_VFONTI "/usr/libdata/vfont/I" +#define _PATH_VFONTR "/usr/libdata/vfont/R" +#define _PATH_VFONTS "/usr/libdata/vfont/S" +#define _PATH_CHKPRINTCAP "/usr/sbin/chkprintcap" diff --git a/usr.sbin/lpr/common_source/printcap.c b/usr.sbin/lpr/common_source/printcap.c new file mode 100644 index 0000000..390de46 --- /dev/null +++ b/usr.sbin/lpr/common_source/printcap.c @@ -0,0 +1,448 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: @(#)common.c 8.5 (Berkeley) 4/28/95 + */ + +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sys/param.h> /* required for lp.h, but not used here */ +#include <sys/dirent.h> /* ditto */ +#include "lp.h" +#include "lp.local.h" +#include "pathnames.h" + +/* + * Routines and data used in processing the printcap file. + */ +static char *printcapdb[2] = { _PATH_PRINTCAP, 0 }; /* list for cget* */ + +static char *capdb_canonical_name(const char *); +static int capdb_getaltlog(char *, const char *, const char *); +static int capdb_getaltnum(char *, const char *, const char *, long, long *); +static int capdb_getaltstr(char *, const char *, const char *, const char *, + char **); +static int getprintcap_int(char *bp, struct printer *pp); + +/* + * Change the name of the printcap file. Used by chkprintcap(8), + * but could be used by other members of the suite with appropriate + * security measures. + */ +void +setprintcap(char *newfile) +{ + printcapdb[0] = newfile; +} + +/* + * Read the printcap database for printer `printer' into the + * struct printer pointed by `pp'. Return values are as for + * cgetent(3): -1 means we could not find what we wanted, -2 + * means a system error occurred (and errno is set), -3 if a + * reference (`tc=') loop was detected, and 0 means success. + * + * Copied from lpr; should add additional capabilities as they + * are required by the other programs in the suite so that + * printcap-reading is consistent across the entire family. + */ +int +getprintcap(const char *printer, struct printer *pp) +{ + int status; + char *XXX; + char *bp; + + /* + * A bug in the declaration of cgetent(3) means that we have + * to hide the constness of its third argument. + */ + XXX = (char *)printer; + if ((status = cgetent(&bp, printcapdb, XXX)) < 0) + return status; + status = getprintcap_int(bp, pp); + free(bp); + return status; +} + +/* + * Map the status values returned by cgetfirst/cgetnext into those + * used by cgetent, returning truth if there are more records to + * examine. This points out what is arguably a bug in the cget* + * interface (or at least a nasty wart). + */ +static int +firstnextmap(int *status) +{ + switch (*status) { + case 0: + return 0; + case 1: + *status = 0; + return 1; + case 2: + *status = 1; + return 1; + case -1: + *status = -2; + return 0; + case -2: + *status = -3; + return 1; + default: + return 0; + } +} + +/* + * Scan through the database of printers using cgetfirst/cgetnext. + * Return false of error or end-of-database; else true. + */ +int +firstprinter(struct printer *pp, int *error) +{ + int status; + char *bp; + + init_printer(pp); + status = cgetfirst(&bp, printcapdb); + if (firstnextmap(&status) == 0) { + if (error) + *error = status; + return 0; + } + if (error) + *error = status; + status = getprintcap_int(bp, pp); + free(bp); + if (error && status) + *error = status; + return 1; +} + +int +nextprinter(struct printer *pp, int *error) +{ + int status; + char *bp; + + free_printer(pp); + status = cgetnext(&bp, printcapdb); + if (firstnextmap(&status) == 0) { + if (error) + *error = status; + return 0; + } + if (error) + *error = status; + status = getprintcap_int(bp, pp); + free(bp); + if (error && status) + *error = status; + return 1; +} + +void +lastprinter(void) +{ + cgetclose(); +} + +/* + * This must match the order of declaration of enum filter in lp.h. + */ +static const char *filters[] = { + "cf", "df", "gf", "if", "nf", "of", "rf", "tf", "vf" +}; + +static const char *longfilters[] = { + "filt.cifplot", "filt.dvi", "filt.plot", "filt.input", "filt.ditroff", + "filt.output", "filt.fortran", "filt.troff", "filt.raster" +}; + +/* + * Internal routine for both getprintcap() and nextprinter(). + * Actually parse the printcap entry using cget* functions. + * Also attempt to figure out the canonical name of the printer + * and store a malloced copy of it in pp->printer. + */ +static int +getprintcap_int(bp, pp) + char *bp; + struct printer *pp; +{ + enum lpd_filters filt; + char *rp_name; + int error; + + if ((pp->printer = capdb_canonical_name(bp)) == 0) + return PCAPERR_OSERR; + +#define CHK(x) do {if ((x) == PCAPERR_OSERR) return PCAPERR_OSERR;}while(0) + CHK(capdb_getaltstr(bp, "af", "acct.file", 0, &pp->acct_file)); + CHK(capdb_getaltnum(bp, "br", "tty.rate", 0, &pp->baud_rate)); + CHK(capdb_getaltnum(bp, "ct", "remote.timeout", DEFTIMEOUT, + &pp->conn_timeout)); + CHK(capdb_getaltnum(bp, "du", "daemon.user", DEFUID, + &pp->daemon_user)); + CHK(capdb_getaltstr(bp, "ff", "job.formfeed", DEFFF, &pp->form_feed)); + CHK(capdb_getaltstr(bp, "lf", "spool.log", _PATH_CONSOLE, + &pp->log_file)); + CHK(capdb_getaltstr(bp, "lo", "spool.lock", DEFLOCK, &pp->lock_file)); + CHK(capdb_getaltstr(bp, "lp", "tty.device", _PATH_DEFDEVLP, &pp->lp)); + CHK(capdb_getaltnum(bp, "mc", "max.copies", DEFMAXCOPIES, + &pp->max_copies)); + CHK(capdb_getaltstr(bp, "ms", "tty.mode", 0, &pp->mode_set)); + CHK(capdb_getaltnum(bp, "mx", "max.blocks", DEFMX, &pp->max_blocks)); + CHK(capdb_getaltnum(bp, "pc", "acct.price", 0, &pp->price100)); + CHK(capdb_getaltnum(bp, "pl", "page.length", DEFLENGTH, + &pp->page_length)); + CHK(capdb_getaltnum(bp, "pw", "page.width", DEFWIDTH, + &pp->page_width)); + CHK(capdb_getaltnum(bp, "px", "page.pwidth", 0, &pp->page_pwidth)); + CHK(capdb_getaltnum(bp, "py", "page.plength", 0, &pp->page_plength)); + CHK(capdb_getaltstr(bp, "rg", "daemon.restrictgrp", 0, + &pp->restrict_grp)); + CHK(capdb_getaltstr(bp, "rm", "remote.host", 0, &pp->remote_host)); + CHK(capdb_getaltstr(bp, "rp", "remote.queue", DEFLP, + &pp->remote_queue)); + CHK(capdb_getaltstr(bp, "sd", "spool.dir", _PATH_DEFSPOOL, + &pp->spool_dir)); + CHK(capdb_getaltstr(bp, "sr", "stat.recv", 0, &pp->stat_recv)); + CHK(capdb_getaltstr(bp, "ss", "stat.send", 0, &pp->stat_send)); + CHK(capdb_getaltstr(bp, "st", "spool.status", DEFSTAT, + &pp->status_file)); + CHK(capdb_getaltstr(bp, "tr", "job.trailer", 0, &pp->trailer)); + + pp->restricted = capdb_getaltlog(bp, "rs", "daemon.restricted"); + pp->short_banner = capdb_getaltlog(bp, "sb", "banner.short"); + pp->no_copies = capdb_getaltlog(bp, "sc", "job.no_copies"); + pp->no_formfeed = capdb_getaltlog(bp, "sf", "job.no_formfeed"); + pp->no_header = capdb_getaltlog(bp, "sh", "banner.disable"); + pp->header_last = capdb_getaltlog(bp, "hl", "banner.last"); + pp->rw = capdb_getaltlog(bp, "rw", "tty.rw"); + pp->tof = !capdb_getaltlog(bp, "fo", "job.topofform"); + + /* + * Decide if the remote printer name matches the local printer name. + * If no name is given then we assume they mean them to match. + * If a name is given see if the rp_name is one of the names for + * this printer. + */ + pp->rp_matches_local = 1; + CHK((error = capdb_getaltstr(bp, "rp", "remote.queue", 0, &rp_name))); + if (error != PCAPERR_NOTFOUND && rp_name != NULL) { + if (cgetmatch(bp,rp_name) != 0) + pp->rp_matches_local = 0; + free(rp_name); + } + + /* + * Filters: + */ + for (filt = 0; filt < LPF_COUNT; filt++) { + CHK(capdb_getaltstr(bp, filters[filt], longfilters[filt], 0, + &pp->filters[filt])); + } + + return 0; +} + +/* + * Decode the error codes returned by cgetent() using the names we + * made up for them from "lp.h". + * This would have been much better done with Common Error, >sigh<. + * Perhaps this can be fixed in the next incarnation of cget*. + */ +const char * +pcaperr(int error) +{ + switch(error) { + case PCAPERR_TCOPEN: + return "unresolved tc= expansion"; + case PCAPERR_SUCCESS: + return "no error"; + case PCAPERR_NOTFOUND: + return "printer not found"; + case PCAPERR_OSERR: + return strerror(errno); + case PCAPERR_TCLOOP: + return "loop detected in tc= expansion"; + default: + return "unknown printcap error"; + } +} + +/* + * Initialize a `struct printer' to contain values harmless to + * the other routines in liblpr. + */ +void +init_printer(struct printer *pp) +{ + static struct printer zero; + *pp = zero; +} + +/* + * Free the dynamically-allocated strings in a `struct printer'. + * Idempotent. + */ +void +free_printer(struct printer *pp) +{ + enum lpd_filters filt; +#define cfree(x) do { if (x) free(x); } while(0) + cfree(pp->printer); + cfree(pp->acct_file); + for (filt = 0; filt < LPF_COUNT; filt++) + cfree(pp->filters[filt]); + cfree(pp->form_feed); + cfree(pp->log_file); + cfree(pp->lock_file); + cfree(pp->lp); + cfree(pp->restrict_grp); + cfree(pp->remote_host); + cfree(pp->remote_queue); + cfree(pp->spool_dir); + cfree(pp->stat_recv); + cfree(pp->stat_send); + cfree(pp->status_file); + cfree(pp->trailer); + cfree(pp->mode_set); + + init_printer(pp); +} + + +/* + * The following routines are part of what would be a sensible library + * interface to capability databases. Maybe someday this will become + * the default. + */ + +/* + * It provides similar functionality to cgetstr(), + * except that it provides for both a long and a short + * capability name and allows for a default to be specified. + */ +static int +capdb_getaltstr(char *bp, const char *shrt, const char *lng, + const char *dflt, char **result) +{ + int status; + + status = cgetstr(bp, (char *)/*XXX*/lng, result); + if (status >= 0 || status == PCAPERR_OSERR) + return status; + status = cgetstr(bp, (char *)/*XXX*/shrt, result); + if (status >= 0 || status == PCAPERR_OSERR) + return status; + if (dflt) { + *result = strdup(dflt); + if (*result == 0) + return PCAPERR_OSERR; + return strlen(*result); + } + return PCAPERR_NOTFOUND; +} + +/* + * The same, only for integers. + */ +static int +capdb_getaltnum(char *bp, const char *shrt, const char *lng, long dflt, + long *result) +{ + int status; + + status = cgetnum(bp, (char *)/*XXX*/lng, result); + if (status >= 0) + return status; + status = cgetnum(bp, (char *)/*XXX*/shrt, result); + if (status >= 0) + return status; + *result = dflt; + return 0; +} + +/* + * Likewise for logical values. There's no need for a default parameter + * because the default is always false. + */ +static int +capdb_getaltlog(char *bp, const char *shrt, const char *lng) +{ + if (cgetcap(bp, (char *)/*XXX*/lng, ':')) + return 1; + if (cgetcap(bp, (char *)/*XXX*/shrt, ':')) + return 1; + return 0; +} + +/* + * Also should be a part of a better cget* library. + * Given a capdb entry, attempt to figure out what its canonical name + * is, and return a malloced copy of it. The canonical name is + * considered to be the first one listed. + */ +static char * +capdb_canonical_name(const char *bp) +{ + char *retval; + const char *nameend; + + nameend = strpbrk(bp, "|:"); + if (nameend == 0) + nameend = bp + 1; + if ((retval = malloc(nameend - bp + 1)) != 0) { + retval[0] = '\0'; + strncat(retval, bp, nameend - bp); + } + return retval; +} + + diff --git a/usr.sbin/lpr/common_source/request.c b/usr.sbin/lpr/common_source/request.c new file mode 100644 index 0000000..e3e4366 --- /dev/null +++ b/usr.sbin/lpr/common_source/request.c @@ -0,0 +1,80 @@ +/* + * Copyright 1997 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +static const char copyright[] = + "Copyright (C) 1997, Massachusetts Institute of Technology\r\n"; +static const char rcsid[] = + "$FreeBSD$"; + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdlib.h> +#include <unistd.h> + +#include <sys/param.h> /* needed for lp.h but not used here */ +#include <dirent.h> /* ditto */ +#include <stdio.h> /* ditto */ +#include "lp.h" +#include "lp.local.h" + +void +init_request(struct request *rp) +{ + static struct request zero; + + *rp = zero; + TAILQ_INIT(&rp->users); + TAILQ_INIT(&rp->jobids); +} + +void +free_request(struct request *rp) +{ + struct req_user *ru; + struct req_jobid *rj; + + if (rp->logname) + free(rp->logname); + if (rp->authname) + free(rp->authname); + if (rp->prettyname) + free(rp->prettyname); + if (rp->authinfo) + free(rp->authinfo); + while ((ru = rp->users.tqh_first) != 0) { + TAILQ_REMOVE(&rp->users, ru, ru_link); + free(ru); + } + while ((rj = rp->jobids.tqh_first) != 0) { + TAILQ_REMOVE(&rp->jobids, rj, rj_link); + free(rj); + } + init_request(rp); +} diff --git a/usr.sbin/lpr/common_source/rmjob.c b/usr.sbin/lpr/common_source/rmjob.c new file mode 100644 index 0000000..4450368 --- /dev/null +++ b/usr.sbin/lpr/common_source/rmjob.c @@ -0,0 +1,397 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)rmjob.c 8.2 (Berkeley) 4/28/95"; +#endif +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/uio.h> + +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#define psignal foil_gcc_psignal +#define sys_siglist foil_gcc_siglist +#include <unistd.h> +#undef psignal +#undef sys_siglist + +#include "lp.h" +#include "lp.local.h" +#include "pathnames.h" + +/* + * rmjob - remove the specified jobs from the queue. + */ + +/* + * Stuff for handling lprm specifications + */ +static char root[] = "root"; +static int all = 0; /* eliminate all files (root only) */ +static int cur_daemon; /* daemon's pid */ +static char current[7+MAXHOSTNAMELEN]; /* active control file name */ + +extern uid_t uid, euid; /* real and effective user id's */ + +static void alarmhandler __P((int)); +static void do_unlink __P((char *)); + +void +rmjob(printer) + const char *printer; +{ + register int i, nitems; + int assasinated = 0; + struct dirent **files; + char *cp; + struct printer myprinter, *pp = &myprinter; + + init_printer(pp); + if ((i = getprintcap(printer, pp)) < 0) + fatal(pp, "getprintcap: %s", pcaperr(i)); + if ((cp = checkremote(pp))) { + printf("Warning: %s\n", cp); + free(cp); + } + + /* + * If the format was `lprm -' and the user isn't the super-user, + * then fake things to look like he said `lprm user'. + */ + if (users < 0) { + if (getuid() == 0) + all = 1; /* all files in local queue */ + else { + user[0] = person; + users = 1; + } + } + if (!strcmp(person, "-all")) { + if (from == host) + fatal(pp, "The login name \"-all\" is reserved"); + all = 1; /* all those from 'from' */ + person = root; + } + + seteuid(euid); + if (chdir(pp->spool_dir) < 0) + fatal(pp, "cannot chdir to spool directory"); + if ((nitems = scandir(".", &files, iscf, NULL)) < 0) + fatal(pp, "cannot access spool directory"); + seteuid(uid); + + if (nitems) { + /* + * Check for an active printer daemon (in which case we + * kill it if it is reading our file) then remove stuff + * (after which we have to restart the daemon). + */ + if (lockchk(pp, pp->lock_file) && chk(current)) { + seteuid(euid); + assasinated = kill(cur_daemon, SIGINT) == 0; + seteuid(uid); + if (!assasinated) + fatal(pp, "cannot kill printer daemon"); + } + /* + * process the files + */ + for (i = 0; i < nitems; i++) + process(pp, files[i]->d_name); + } + rmremote(pp); + /* + * Restart the printer daemon if it was killed + */ + if (assasinated && !startdaemon(pp)) + fatal(pp, "cannot restart printer daemon\n"); + exit(0); +} + +/* + * Process a lock file: collect the pid of the active + * daemon and the file name of the active spool entry. + * Return boolean indicating existence of a lock file. + */ +int +lockchk(pp, s) + struct printer *pp; + char *s; +{ + register FILE *fp; + register int i, n; + + seteuid(euid); + if ((fp = fopen(s, "r")) == NULL) { + if (errno == EACCES) + fatal(pp, "%s: %s", s, strerror(errno)); + else + return(0); + } + seteuid(uid); + if (!getline(fp)) { + (void) fclose(fp); + return(0); /* no daemon present */ + } + cur_daemon = atoi(line); + if (kill(cur_daemon, 0) < 0 && errno != EPERM) { + (void) fclose(fp); + return(0); /* no daemon present */ + } + for (i = 1; (n = fread(current, sizeof(char), sizeof(current), fp)) <= 0; i++) { + if (i > 5) { + n = 1; + break; + } + sleep(i); + } + current[n-1] = '\0'; + (void) fclose(fp); + return(1); +} + +/* + * Process a control file. + */ +void +process(pp, file) + const struct printer *pp; + char *file; +{ + FILE *cfp; + + if (!chk(file)) + return; + seteuid(euid); + if ((cfp = fopen(file, "r")) == NULL) + fatal(pp, "cannot open %s", file); + seteuid(uid); + while (getline(cfp)) { + switch (line[0]) { + case 'U': /* unlink associated files */ + if (strchr(line+1, '/') || strncmp(line+1, "df", 2)) + break; + do_unlink(line+1); + } + } + (void) fclose(cfp); + do_unlink(file); +} + +static void +do_unlink(file) + char *file; +{ + int ret; + + if (from != host) + printf("%s: ", host); + seteuid(euid); + ret = unlink(file); + seteuid(uid); + printf(ret ? "cannot dequeue %s\n" : "%s dequeued\n", file); +} + +/* + * Do the dirty work in checking + */ +int +chk(file) + char *file; +{ + register int *r, n; + register char **u, *cp; + FILE *cfp; + + /* + * Check for valid cf file name (mostly checking current). + */ + if (strlen(file) < 7 || file[0] != 'c' || file[1] != 'f') + return(0); + + if (all && (from == host || !strcmp(from, file+6))) + return(1); + + /* + * get the owner's name from the control file. + */ + seteuid(euid); + if ((cfp = fopen(file, "r")) == NULL) + return(0); + seteuid(uid); + while (getline(cfp)) { + if (line[0] == 'P') + break; + } + (void) fclose(cfp); + if (line[0] != 'P') + return(0); + + if (users == 0 && requests == 0) + return(!strcmp(file, current) && isowner(line+1, file)); + /* + * Check the request list + */ + for (n = 0, cp = file+3; isdigit(*cp); ) + n = n * 10 + (*cp++ - '0'); + for (r = requ; r < &requ[requests]; r++) + if (*r == n && isowner(line+1, file)) + return(1); + /* + * Check to see if it's in the user list + */ + for (u = user; u < &user[users]; u++) + if (!strcmp(*u, line+1) && isowner(line+1, file)) + return(1); + return(0); +} + +/* + * If root is removing a file on the local machine, allow it. + * If root is removing a file from a remote machine, only allow + * files sent from the remote machine to be removed. + * Normal users can only remove the file from where it was sent. + */ +int +isowner(owner, file) + char *owner, *file; +{ + if (!strcmp(person, root) && (from == host || !strcmp(from, file+6))) + return(1); + if (!strcmp(person, owner) && !strcmp(from, file+6)) + return(1); + if (from != host) + printf("%s: ", host); + printf("%s: Permission denied\n", file); + return(0); +} + +/* + * Check to see if we are sending files to a remote machine. If we are, + * then try removing files on the remote machine. + */ +void +rmremote(pp) + const struct printer *pp; +{ + int i, rem, niov, totlen; + char buf[BUFSIZ]; + void (*savealrm)(int); + struct iovec *iov; + + if (!pp->remote) + return; /* not sending to a remote machine */ + + /* + * Flush stdout so the user can see what has been deleted + * while we wait (possibly) for the connection. + */ + fflush(stdout); + + /* + * Counting: + * 4 == "\5" + remote_queue + " " + person + * 2 * users == " " + user[i] for each user + * requests == asprintf results for each request + * 1 == "\n" + * Although laborious, doing it this way makes it possible for + * us to process requests of indeterminate length without + * applying an arbitrary limit. Arbitrary Limits Are Bad (tm). + */ + niov = 4 + 2 * users + requests + 1; + iov = malloc(niov * sizeof *iov); + if (iov == 0) + fatal(pp, "out of memory"); + iov[0].iov_base = "\5"; + iov[1].iov_base = pp->remote_queue; + iov[2].iov_base = " "; + iov[3].iov_base = all ? "-all" : person; + for (i = 0; i < users; i++) { + iov[4 + 2 * i].iov_base = " "; + iov[4 + 2 * i + 1].iov_base = user[i]; + } + for (i = 0; i < requests; i++) { + asprintf(&iov[4 + 2 * users + i].iov_base, " %d", requ[i]); + if (iov[4 + 2 * users + i].iov_base == 0) + fatal(pp, "out of memory"); + } + iov[4 + 2 * users + requests].iov_base = "\n"; + for (totlen = i = 0; i < niov; i++) + totlen += (iov[i].iov_len = strlen(iov[i].iov_base)); + + savealrm = signal(SIGALRM, alarmhandler); + alarm(pp->conn_timeout); + rem = getport(pp, pp->remote_host, 0); + (void)signal(SIGALRM, savealrm); + if (rem < 0) { + if (from != host) + printf("%s: ", host); + printf("connection to %s is down\n", pp->remote_host); + } else { + if (writev(rem, iov, niov) != totlen) + fatal(pp, "Lost connection"); + while ((i = read(rem, buf, sizeof(buf))) > 0) + (void) fwrite(buf, 1, i, stdout); + (void) close(rem); + } + for (i = 0; i < requests; i++) + free(iov[4 + 2 * users + i].iov_base); + free(iov); +} + +/* + * Return 1 if the filename begins with 'cf' + */ +int +iscf(d) + struct dirent *d; +{ + return(d->d_name[0] == 'c' && d->d_name[1] == 'f'); +} + +void +alarmhandler(signo) + int signo; +{ + /* ignored */ +} diff --git a/usr.sbin/lpr/common_source/startdaemon.c b/usr.sbin/lpr/common_source/startdaemon.c new file mode 100644 index 0000000..29866b2 --- /dev/null +++ b/usr.sbin/lpr/common_source/startdaemon.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1983, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)startdaemon.c 8.2 (Berkeley) 4/17/94"; +#endif +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/un.h> + +#include <dirent.h> +#include <err.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include "lp.h" +#include "pathnames.h" + +extern uid_t uid, euid; + +/* + * Tell the printer daemon that there are new files in the spool directory. + */ + +int +startdaemon(pp) + const struct printer *pp; +{ + struct sockaddr_un un; + register int s, n; + char c; + + s = socket(PF_LOCAL, SOCK_STREAM, 0); + if (s < 0) { + warn("socket"); + return(0); + } + memset(&un, 0, sizeof(un)); + un.sun_family = AF_LOCAL; + strcpy(un.sun_path, _PATH_SOCKETNAME); +#ifndef SUN_LEN +#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) +#endif + seteuid(euid); + if (connect(s, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { + seteuid(uid); + warn("connect"); + (void) close(s); + return(0); + } + seteuid(uid); + + /* + * Avoid overruns without putting artificial limitations on + * the length. + */ + if (writel(s, "\1", pp->printer, "\n", (char *)0) <= 0) { + warn("write"); + (void) close(s); + return(0); + } + if (read(s, &c, 1) == 1) { + if (c == '\0') { /* everything is OK */ + (void) close(s); + return(1); + } + putchar(c); + } + while ((n = read(s, &c, 1)) > 0) + putchar(c); + (void) close(s); + return(0); +} diff --git a/usr.sbin/lpr/filters.ru/Makefile b/usr.sbin/lpr/filters.ru/Makefile new file mode 100644 index 0000000..0c7be10 --- /dev/null +++ b/usr.sbin/lpr/filters.ru/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +SUBDIR = koi2alt koi2855 + +SAMPLES=bjc-240.sh.sample + +afterinstall: + cd ${.CURDIR} && \ + ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${SHAREMODE} \ + ${SAMPLES} ${DESTDIR}${BINDIR} + +.include "Makefile.inc" +.include <bsd.prog.mk> + diff --git a/usr.sbin/lpr/filters.ru/Makefile.inc b/usr.sbin/lpr/filters.ru/Makefile.inc new file mode 100644 index 0000000..c4a3a7fc --- /dev/null +++ b/usr.sbin/lpr/filters.ru/Makefile.inc @@ -0,0 +1,2 @@ +# $FreeBSD$ +BINDIR= /usr/libexec/lpr/ru diff --git a/usr.sbin/lpr/filters.ru/bjc-240.sh.sample b/usr.sbin/lpr/filters.ru/bjc-240.sh.sample new file mode 100644 index 0000000..1bc907a --- /dev/null +++ b/usr.sbin/lpr/filters.ru/bjc-240.sh.sample @@ -0,0 +1,64 @@ +#!/bin/sh +# +# Canon BJC-240 Setup script +# +# Settings are: +# Epson LQ emulation, A4, Code Page 866, 66 lines, Roman font, Smoothing, +# HQ mode, no CR translation, power off in 10min, auto power on +# + +printf "\033[K\00200\037" | tr 0 "\0" + +cat << EOF1 +BJLSTART +ControlMode=BJ +Font=Roman +PageLength=12 +CodePage=866 +AutoLF=Off +TextScaleMode=On +AutoCR=Off +CharacterSet=Set2 +AGM=Off +BJLEND +EOF1 + +printf "\033[K\00200\037" | tr 0 "\0" + +cat << EOF2 +BJLSTART +ControlMode=LQ +Font=Roman +PageLength=12 +CodePage=866 +AutoLF=Off +TextScaleMode=On +CharacterSet=Graphics +International=USA +BJLEND +EOF2 + +printf "\033[K\00200\037" | tr 0 "\0" + +cat << EOF3 +BJLSTART +@SetControlMode=LQ +BJLEND +EOF3 + +printf "\033[K\00200\037" | tr 0 "\0" + +cat << EOF4 +BJLSTART +ControlMode=Common +PrintMode=HQ +Reduction=Off +Smoothing=On +PaperSelect=A4 +I/D-Buffer=Input +AutoPowerOff=10 +AutoPowerOn=Enable +BJLEND +EOF4 + +exec /usr/libexec/lpr/ru/koi2alt $* diff --git a/usr.sbin/lpr/filters.ru/koi2855/Makefile b/usr.sbin/lpr/filters.ru/koi2855/Makefile new file mode 100644 index 0000000..3e83d97 --- /dev/null +++ b/usr.sbin/lpr/filters.ru/koi2855/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +PROG=koi2855 +NOMAN= noman + +.include <bsd.prog.mk> diff --git a/usr.sbin/lpr/filters.ru/koi2855/koi2855.c b/usr.sbin/lpr/filters.ru/koi2855/koi2855.c new file mode 100644 index 0000000..67a9bc5 --- /dev/null +++ b/usr.sbin/lpr/filters.ru/koi2855/koi2855.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 1999 by Andrey A. Chernov, Moscow, Russia. + * (C) 18 Sep 1999, Alex G. Bulushev (bag@demos.su) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * KOI8-R -> CP855 conversion filter (Russian character sets) + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + +int length = 66; +int lines; + +unsigned char koi2855 [] = { +0xc4, 0xb3, 0xda, 0xbf, 0xc0, 0xd9, 0xc3, 0xb4, +0xc2, 0xc1, 0xc5, 0xdf, 0xdc, 0xdb, 0xdb, 0xdb, +0xb0, 0xb1, 0xb2, 0xda, 0xfe, 0x2e, 0xad, 0x3d, +0xae, 0xaf, 0xff, 0xd9, 0xcf, 0x32, 0x2e, 0x25, +0xcd, 0xba, 0xc9, 0x84, 0xc9, 0xc9, 0xbb, 0xbb, +0xbb, 0xc8, 0xc8, 0xc8, 0xbc, 0xbc, 0xbc, 0xcc, +0xcc, 0xcc, 0xb9, 0x85, 0xb9, 0xb9, 0xcb, 0xcb, +0xcb, 0xca, 0xca, 0xca, 0xce, 0xce, 0xce, 0x43, +0x9c, 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, +0xb5, 0xb7, 0xbd, 0xc6, 0xd0, 0xd2, 0xd4, 0xd6, +0xd8, 0xde, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, +0xed, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0x9e, +0x9d, 0xa1, 0xa3, 0xa5, 0xa7, 0xa9, 0xab, 0xad, +0xb6, 0xb8, 0xbe, 0xc7, 0xd1, 0xd3, 0xd5, 0xd7, +0xdd, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, +0xee, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0x9f +}; + +int main(int argc, char *argv[]) +{ + int c, i; + char *cp; + + while (--argc) { + if (*(cp = *++argv) == '-') { + switch (*++cp) { + case 'l': + if ((i = atoi(++cp)) > 0) + length = i; + break; + } + } + } + + while ((c = getchar()) != EOF) { + if (c == '\031') { + if ((c = getchar()) == '\1') { + lines = 0; + fflush(stdout); + kill(getpid(), SIGSTOP); + continue; + } else { + ungetc(c, stdin); + c = '\031'; + } + } else if (c & 0x80) { + putchar(koi2855[c & 0x7F]); + continue; + } else if (c == '\n') + lines++; + else if (c == '\f') + lines = length; + putchar(c); + if (lines >= length) { + lines = 0; + fflush(stdout); + } + } + return 0; +} diff --git a/usr.sbin/lpr/filters.ru/koi2alt/Makefile b/usr.sbin/lpr/filters.ru/koi2alt/Makefile new file mode 100644 index 0000000..f980bbf --- /dev/null +++ b/usr.sbin/lpr/filters.ru/koi2alt/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +PROG=koi2alt +NOMAN= noman + +.include <bsd.prog.mk> diff --git a/usr.sbin/lpr/filters.ru/koi2alt/koi2alt.c b/usr.sbin/lpr/filters.ru/koi2alt/koi2alt.c new file mode 100644 index 0000000..928e97e --- /dev/null +++ b/usr.sbin/lpr/filters.ru/koi2alt/koi2alt.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 1993-98 by Andrey A. Chernov, Moscow, Russia. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * KOI8-R -> CP866 conversion filter (Russian character sets) + */ + +#include <sys/types.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + +int length = 66; +int lines; + +char *koi2alt[] = { +/* 0 1 2 3 4 5 6 7 */ +/* 8 9 A B C D E F */ +/* 8 */ "\xc4","\xb3","\xda","\xbf","\xc0","\xd9","\xc3","\xb4", + "\xc2","\xc1","\xc5","\xdf","\xdc","\xdb","\xdd","\xde", +/* 9 */ "\xb0","\xb1","\xb2","\xb3","\xfe","\xf9","\xfb","-\b~", + "<\b_",">\b_","\xff","\xb3","\xf8","2\b-","\xfa",":\b-", +/* A */ "\xcd","\xba","\xd5","\xf1","\xd6","\xc9","\xb8","\xb7", + "\xbb","\xd4","\xd3","\xc8","\xbe","\xbd","\xbc","\xc6", +/* B */ "\xc7","\xcc","\xb5","\xf0","\xb6","\xb9","\xd1","\xd2", + "\xcb","\xcf","\xd0","\xca","\xd8","\xd7","\xce","c\b_", +/* C */ "\xee","\xa0","\xa1","\xe6","\xa4","\xa5","\xe4","\xa3", + "\xe5","\xa8","\xa9","\xaa","\xab","\xac","\xad","\xae", +/* D */ "\xaf","\xef","\xe0","\xe1","\xe2","\xe3","\xa6","\xa2", + "\xec","\xeb","\xa7","\xe8","\xed","\xe9","\xe7","\xea", +/* E */ "\x9e","\x80","\x81","\x96","\x84","\x85","\x94","\x83", + "\x95","\x88","\x89","\x8a","\x8b","\x8c","\x8d","\x8e", +/* F */ "\x8f","\x9f","\x90","\x91","\x92","\x93","\x86","\x82", + "\x9c","\x9b","\x87","\x98","\x9d","\x99","\x97","\x9a" +}; + +int main(int argc, char *argv[]) +{ + int c, i; + char *cp; + + while (--argc) { + if (*(cp = *++argv) == '-') { + switch (*++cp) { + case 'l': + if ((i = atoi(++cp)) > 0) + length = i; + break; + } + } + } + + while ((c = getchar()) != EOF) { + if (c == '\031') { + if ((c = getchar()) == '\1') { + lines = 0; + fflush(stdout); + kill(getpid(), SIGSTOP); + continue; + } else { + ungetc(c, stdin); + c = '\031'; + } + } else if (c & 0x80) { + fputs(koi2alt[c & 0x7F], stdout); + continue; + } else if (c == '\n') + lines++; + else if (c == '\f') + lines = length; + putchar(c); + if (lines >= length) { + lines = 0; + fflush(stdout); + } + } + return 0; +} diff --git a/usr.sbin/lpr/filters/Makefile b/usr.sbin/lpr/filters/Makefile new file mode 100644 index 0000000..c9d5c4f --- /dev/null +++ b/usr.sbin/lpr/filters/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= lpf +NOMAN= noman +BINDIR= /usr/libexec/lpr + +.include <bsd.prog.mk> diff --git a/usr.sbin/lpr/filters/lpf.c b/usr.sbin/lpr/filters/lpf.c new file mode 100644 index 0000000..6fef3c4 --- /dev/null +++ b/usr.sbin/lpr/filters/lpf.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "From: @(#)lpf.c 8.1 (Berkeley) 6/6/93"; +static char id[] = "$FreeBSD$"; +#endif /* not lint */ + +/* + * filter which reads the output of nroff and converts lines + * with ^H's to overwritten lines. Thus this works like 'ul' + * but is much better: it can handle more than 2 overwrites + * and it is written with some style. + * modified by kls to use register references instead of arrays + * to try to gain a little speed. + */ + +#include <signal.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> + +#define MAXWIDTH 132 +#define MAXREP 10 + +char buf[MAXREP][MAXWIDTH]; +int maxcol[MAXREP] = {-1}; +int lineno; +int width = 132; /* default line length */ +int length = 66; /* page length */ +int indent; /* indentation length */ +int npages = 1; +int literal; /* print control characters */ +char *name; /* user's login name */ +char *host; /* user's machine name */ +char *acctfile; /* accounting information file */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register FILE *p = stdin, *o = stdout; + register int i, col; + register char *cp; + int done, linedone, maxrep; + char *limit; + int ch; + + while (--argc) { + if (*(cp = *++argv) == '-') { + switch (cp[1]) { + case 'n': + argc--; + name = *++argv; + break; + + case 'h': + argc--; + host = *++argv; + break; + + case 'w': + if ((i = atoi(&cp[2])) > 0 && i <= MAXWIDTH) + width = i; + break; + + case 'l': + length = atoi(&cp[2]); + break; + + case 'i': + indent = atoi(&cp[2]); + break; + + case 'c': /* Print control chars */ + literal++; + break; + } + } else + acctfile = cp; + } + + for (cp = buf[0], limit = buf[MAXREP]; cp < limit; *cp++ = ' '); + done = 0; + + while (!done) { + col = indent; + maxrep = -1; + linedone = 0; + while (!linedone) { + switch (ch = getc(p)) { + case EOF: + linedone = done = 1; + ch = '\n'; + break; + + case '\f': + lineno = length; + case '\n': + if (maxrep < 0) + maxrep = 0; + linedone = 1; + break; + + case '\b': + if (--col < indent) + col = indent; + break; + + case '\r': + col = indent; + break; + + case '\t': + col = ((col - indent) | 07) + indent + 1; + break; + + case '\031': + /* + * lpd needs to use a different filter to + * print data so stop what we are doing and + * wait for lpd to restart us. + */ + if ((ch = getchar()) == '\1') { + fflush(stdout); + kill(getpid(), SIGSTOP); + break; + } else { + ungetc(ch, stdin); + ch = '\031'; + } + + default: + if (col >= width || !literal && ch < ' ') { + col++; + break; + } + cp = &buf[0][col]; + for (i = 0; i < MAXREP; i++) { + if (i > maxrep) + maxrep = i; + if (*cp == ' ') { + *cp = ch; + if (col > maxcol[i]) + maxcol[i] = col; + break; + } + cp += MAXWIDTH; + } + col++; + break; + } + } + + /* print out lines */ + for (i = 0; i <= maxrep; i++) { + for (cp = buf[i], limit = cp+maxcol[i]; cp <= limit;) { + putc(*cp, o); + *cp++ = ' '; + } + if (i < maxrep) + putc('\r', o); + else + putc(ch, o); + if (++lineno >= length) { + fflush(o); + npages++; + lineno = 0; + } + maxcol[i] = -1; + } + } + if (lineno) { /* be sure to end on a page boundary */ + putchar('\f'); + npages++; + } + if (name && acctfile && access(acctfile, 02) >= 0 && + freopen(acctfile, "a", stdout) != NULL) { + printf("%7.2f\t%s:%s\n", (float)npages, host, name); + } + exit(0); +} diff --git a/usr.sbin/lpr/lp/Makefile b/usr.sbin/lpr/lp/Makefile new file mode 100644 index 0000000..9522fc3 --- /dev/null +++ b/usr.sbin/lpr/lp/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +BINDIR = /usr/bin +MAN1 = lp.1 + +beforeinstall: + ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/lp.sh ${DESTDIR}${BINDIR}/lp + +.include <bsd.prog.mk> diff --git a/usr.sbin/lpr/lp/lp.1 b/usr.sbin/lpr/lp/lp.1 new file mode 100644 index 0000000..8666925 --- /dev/null +++ b/usr.sbin/lpr/lp/lp.1 @@ -0,0 +1,117 @@ +.\" +.\" Copyright (c) 1995 Joerg Wunsch +.\" +.\" All rights reserved. +.\" +.\" This program is free software. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by Joerg Wunsch +.\" 4. The name of the developer may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd January 22, 1995 +.Dt LP 1 +.Os +.Sh NAME +.Nm lp +.Nd front-end to the print spooler +.Sh SYNOPSIS +.Nm lp +.Op Fl cs +.Op Fl o Ar option +.Op Fl d Ar printer +.Op Fl n Ar num +.Op Ar name ... +.Sh DESCRIPTION +.Nm Lp +is a front-end to the print spooler as required by the +.St -p1003.2 +specification. It effectively invokes +.Xr lpr 1 +with the proper set of arguments. +.Pp +It generally prints the named files on the destination printer. +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl c +Make the +.Nm +command exit only after further access to any of the input files is no +longer required. The application can then safely delete or modify the +files without affecting the output operation. +.It Fl d Ar dest +Specify a particular printer. +If no +.Fl d +is provided on the command line, the contents of the environment +variables +.Ev LPDEST +or +.Ev PRINTER +.Pq with this precedence +are taken as the destination printer. +.It Fl n Ar num +Specify that +.Ar num +copies of each of the named files shall be printed. +.It Fl o Ar option +Printer specific options. +Not supported, provided only as a compatibility +option for SVR. +.It Fl s +Silent operation. +Not supported, +provided only as a compatibility option for +.St -susv2 . +.El +.Sh ENVIRONMENT +As described above, the variables +.Ev LPDEST +and +.Ev PRINTER +are examined to select the destination printer. +.Sh SEE ALSO +.Xr lpr 1 +.Sh STANDARDS +The +.Nm +command is expected to comply with the +.St -p1003.2 +specification. +.Sh AUTHORS +This implementation of the +.Nm +command has been written by +.if t J\(:org Wunsch. +.if n Joerg Wunsch. +.Sh BUGS +The +.St -p1003.2 +specification does not provide any means to print non-text files. It +rather requires the files to be printed to be text files limited to +reasonable line lengths and printable characters. diff --git a/usr.sbin/lpr/lp/lp.sh b/usr.sbin/lpr/lp/lp.sh new file mode 100644 index 0000000..e7c0688 --- /dev/null +++ b/usr.sbin/lpr/lp/lp.sh @@ -0,0 +1,75 @@ +#!/bin/sh +# +# +# Copyright (c) 1995 Joerg Wunsch +# +# All rights reserved. +# +# This program is free software. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by Joerg Wunsch +# 4. The name of the developer may not be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# +# Posix 1003.2 compliant print spooler interface. +# +# $FreeBSD$ +# + +ncopies="" +symlink="-s" + +# Posix says LPDEST gets precedence over PRINTER +dest=${LPDEST:-${PRINTER:-lp}} + +# +# XXX We include the -o flag as a dummy. Posix 1003.2 does not require +# it, but the rationale mentions it as a possible future extension. +# XXX We include the -s flag as a dummy. SUSv2 requires it, +# although we do not yet emit the affected messages. +# +while getopts "cd:n:o:s" option +do + case $option in + + c) # copy files before printing + symlink="";; + d) # destination + dest="${OPTARG}";; + n) # number of copies + ncopies="-#${OPTARG}";; + o) # (printer option) + : ;; + s) # (silent option) + : ;; + *) # (error msg printed by getopts) + exit 2;; + esac +done + +shift $(($OPTIND - 1)) + +exec /usr/bin/lpr "-P${dest}" ${symlink} ${ncopies} "$@" diff --git a/usr.sbin/lpr/lpc/Makefile b/usr.sbin/lpr/lpc/Makefile new file mode 100644 index 0000000..48fd38b --- /dev/null +++ b/usr.sbin/lpr/lpc/Makefile @@ -0,0 +1,14 @@ +# From: @(#)Makefile 8.1 (Berkeley) 6/6/93 +# $FreeBSD$ + +PROG= lpc +CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS} +MAN8= lpc.8 +SRCS= lpc.c cmds.c cmdtab.c +BINGRP= daemon +BINMODE=2555 +.PATH: ${.CURDIR}/../common_source +DPADD= ${LIBLPR} ${LIBEDIT} ${LIBTERMCAP} +LDADD= ${LIBLPR} -ledit -ltermcap + +.include <bsd.prog.mk> diff --git a/usr.sbin/lpr/lpc/cmds.c b/usr.sbin/lpr/lpc/cmds.c new file mode 100644 index 0000000..1ed69c8 --- /dev/null +++ b/usr.sbin/lpr/lpc/cmds.c @@ -0,0 +1,891 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +/* +static char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 4/28/95"; +*/ +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +/* + * lpc -- line printer control program -- commands: + */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <sys/file.h> + +#include <signal.h> +#include <fcntl.h> +#include <errno.h> +#include <dirent.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include "lp.h" +#include "lp.local.h" +#include "lpc.h" +#include "extern.h" +#include "pathnames.h" + +static void abortpr __P((struct printer *, int)); +static int doarg __P((char *)); +static int doselect __P((struct dirent *)); +static void putmsg __P((struct printer *, int, char **)); +static int sortq __P((const void *, const void *)); +static void startpr __P((struct printer *, int)); +static int touch __P((struct queue *)); +static void unlinkf __P((char *)); +static void upstat __P((struct printer *, char *)); + +/* + * generic framework for commands which operate on all or a specified + * set of printers + */ +void +generic(doit, argc, argv) + void (*doit) __P((struct printer *)); + int argc; + char *argv[]; +{ + int status, more; + struct printer myprinter, *pp = &myprinter; + + if (argc == 1) { + printf("Usage: %s {all | printer ...}\n", argv[0]); + return; + } + if (argc == 2 && strcmp(argv[1], "all") == 0) { + more = firstprinter(pp, &status); + if (status) + goto looperr; + while (more) { + (*doit)(pp); + do { + more = nextprinter(pp, &status); +looperr: + switch (status) { + case PCAPERR_TCOPEN: + printf("warning: %s: unresolved " + "tc= reference(s) ", + pp->printer); + case PCAPERR_SUCCESS: + break; + default: + fatal(pp, pcaperr(status)); + } + } while (more && status); + } + return; + } + while (--argc) { + ++argv; + init_printer(pp); + status = getprintcap(*argv, pp); + switch(status) { + default: + fatal(pp, pcaperr(status)); + case PCAPERR_NOTFOUND: + printf("unknown printer %s\n", *argv); + continue; + case PCAPERR_TCOPEN: + printf("warning: %s: unresolved tc= reference(s)\n", + *argv); + break; + case PCAPERR_SUCCESS: + break; + } + (*doit)(pp); + } +} + +/* + * kill an existing daemon and disable printing. + */ +void +doabort(pp) + struct printer *pp; +{ + abortpr(pp, 1); +} + +static void +abortpr(pp, dis) + struct printer *pp; + int dis; +{ + register FILE *fp; + struct stat stbuf; + int pid, fd; + char lf[MAXPATHLEN]; + + lock_file_name(pp, lf, sizeof lf); + printf("%s:\n", pp->printer); + + /* + * Turn on the owner execute bit of the lock file to disable printing. + */ + if (dis) { + seteuid(euid); + if (stat(lf, &stbuf) >= 0) { + if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0) + printf("\tcannot disable printing: %s\n", + strerror(errno)); + else { + upstat(pp, "printing disabled\n"); + printf("\tprinting disabled\n"); + } + } else if (errno == ENOENT) { + if ((fd = open(lf, O_WRONLY|O_CREAT, + LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0) + printf("\tcannot create lock file: %s\n", + strerror(errno)); + else { + (void) close(fd); + upstat(pp, "printing disabled\n"); + printf("\tprinting disabled\n"); + printf("\tno daemon to abort\n"); + } + goto out; + } else { + printf("\tcannot stat lock file\n"); + goto out; + } + } + /* + * Kill the current daemon to stop printing now. + */ + if ((fp = fopen(lf, "r")) == NULL) { + printf("\tcannot open lock file\n"); + goto out; + } + if (!getline(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) { + (void) fclose(fp); /* unlocks as well */ + printf("\tno daemon to abort\n"); + goto out; + } + (void) fclose(fp); + if (kill(pid = atoi(line), SIGTERM) < 0) { + if (errno == ESRCH) + printf("\tno daemon to abort\n"); + else + printf("\tWarning: daemon (pid %d) not killed\n", pid); + } else + printf("\tdaemon (pid %d) killed\n", pid); +out: + seteuid(uid); +} + +/* + * Write a message into the status file. + */ +static void +upstat(pp, msg) + struct printer *pp; + char *msg; +{ + register int fd; + char statfile[MAXPATHLEN]; + + status_file_name(pp, statfile, sizeof statfile); + umask(0); + fd = open(statfile, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); + if (fd < 0) { + printf("\tcannot create status file: %s\n", strerror(errno)); + return; + } + (void) ftruncate(fd, 0); + if (msg == (char *)NULL) + (void) write(fd, "\n", 1); + else + (void) write(fd, msg, strlen(msg)); + (void) close(fd); +} + +static int +doselect(d) + struct dirent *d; +{ + int c = d->d_name[0]; + + if ((c == 't' || c == 'c' || c == 'd') && d->d_name[1] == 'f') + return(1); + return(0); +} + +/* + * Comparison routine for scandir. Sort by job number and machine, then + * by `cf', `tf', or `df', then by the sequence letter A-Z, a-z. + */ +static int +sortq(a, b) + const void *a, *b; +{ + struct dirent **d1, **d2; + int c1, c2; + + d1 = (struct dirent **)a; + d2 = (struct dirent **)b; + if ((c1 = strcmp((*d1)->d_name + 3, (*d2)->d_name + 3))) + return(c1); + c1 = (*d1)->d_name[0]; + c2 = (*d2)->d_name[0]; + if (c1 == c2) + return((*d1)->d_name[2] - (*d2)->d_name[2]); + if (c1 == 'c') + return(-1); + if (c1 == 'd' || c2 == 'c') + return(1); + return(-1); +} + +/* + * Remove all spool files and temporaries from the spooling area. + * Or, perhaps: + * Remove incomplete jobs from spooling area. + */ +void +clean(pp) + struct printer *pp; +{ + register int i, n; + register char *cp, *cp1, *lp; + struct dirent **queue; + int nitems; + + printf("%s:\n", pp->printer); + + lp = line; + cp = pp->spool_dir; + while (lp < &line[sizeof(line) - 1]) { + if ((*lp++ = *cp++) == 0) + break; + } + lp[-1] = '/'; + + seteuid(euid); + nitems = scandir(pp->spool_dir, &queue, doselect, sortq); + seteuid(uid); + if (nitems < 0) { + printf("\tcannot examine spool directory\n"); + return; + } + if (nitems == 0) + return; + i = 0; + do { + cp = queue[i]->d_name; + if (*cp == 'c') { + n = 0; + while (i + 1 < nitems) { + cp1 = queue[i + 1]->d_name; + if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3)) + break; + i++; + n++; + } + if (n == 0) { + strncpy(lp, cp, sizeof(line) - strlen(line) - 1); + line[sizeof(line) - 1] = '\0'; + unlinkf(line); + } + } else { + /* + * Must be a df with no cf (otherwise, it would have + * been skipped above) or a tf file (which can always + * be removed). + */ + strncpy(lp, cp, sizeof(line) - strlen(line) - 1); + line[sizeof(line) - 1] = '\0'; + unlinkf(line); + } + } while (++i < nitems); +} + +static void +unlinkf(name) + char *name; +{ + seteuid(euid); + if (unlink(name) < 0) + printf("\tcannot remove %s\n", name); + else + printf("\tremoved %s\n", name); + seteuid(uid); +} + +/* + * Enable queuing to the printer (allow lpr's). + */ +void +enable(pp) + struct printer *pp; +{ + struct stat stbuf; + char lf[MAXPATHLEN]; + + lock_file_name(pp, lf, sizeof lf); + printf("%s:\n", pp->printer); + + /* + * Turn off the group execute bit of the lock file to enable queuing. + */ + seteuid(euid); + if (stat(lf, &stbuf) >= 0) { + if (chmod(lf, stbuf.st_mode & ~LFM_QUEUE_DIS) < 0) + printf("\tcannot enable queuing\n"); + else + printf("\tqueuing enabled\n"); + } + seteuid(uid); +} + +/* + * Disable queuing. + */ +void +disable(pp) + struct printer *pp; +{ + register int fd; + struct stat stbuf; + char lf[MAXPATHLEN]; + + lock_file_name(pp, lf, sizeof lf); + printf("%s:\n", pp->printer); + /* + * Turn on the group execute bit of the lock file to disable queuing. + */ + seteuid(euid); + if (stat(lf, &stbuf) >= 0) { + if (chmod(lf, stbuf.st_mode | LFM_QUEUE_DIS) < 0) + printf("\tcannot disable queuing: %s\n", + strerror(errno)); + else + printf("\tqueuing disabled\n"); + } else if (errno == ENOENT) { + if ((fd = open(lf, O_WRONLY|O_CREAT, + LOCK_FILE_MODE | LFM_QUEUE_DIS)) < 0) + printf("\tcannot create lock file: %s\n", + strerror(errno)); + else { + (void) close(fd); + printf("\tqueuing disabled\n"); + } + } else + printf("\tcannot stat lock file\n"); + seteuid(uid); +} + +/* + * Disable queuing and printing and put a message into the status file + * (reason for being down). + */ +void +down(argc, argv) + int argc; + char *argv[]; +{ + int status, more; + struct printer myprinter, *pp = &myprinter; + + if (argc == 1) { + printf("Usage: down {all | printer} [message ...]\n"); + return; + } + if (!strcmp(argv[1], "all")) { + more = firstprinter(pp, &status); + if (status) + goto looperr; + while (more) { + putmsg(pp, argc - 2, argv + 2); + do { + more = nextprinter(pp, &status); +looperr: + switch (status) { + case PCAPERR_TCOPEN: + printf("warning: %s: unresolved " + "tc= reference(s) ", + pp->printer); + case PCAPERR_SUCCESS: + break; + default: + fatal(pp, pcaperr(status)); + } + } while (more && status); + } + return; + } + init_printer(pp); + status = getprintcap(argv[1], pp); + switch(status) { + default: + fatal(pp, pcaperr(status)); + case PCAPERR_NOTFOUND: + printf("unknown printer %s\n", argv[1]); + return; + case PCAPERR_TCOPEN: + printf("warning: %s: unresolved tc= reference(s)", argv[1]); + break; + case PCAPERR_SUCCESS: + break; + } + putmsg(pp, argc - 2, argv + 2); +} + +static void +putmsg(pp, argc, argv) + struct printer *pp; + int argc; + char **argv; +{ + register int fd; + register char *cp1, *cp2; + char buf[1024]; + char file[MAXPATHLEN]; + struct stat stbuf; + + printf("%s:\n", pp->printer); + /* + * Turn on the group execute bit of the lock file to disable queuing; + * turn on the owner execute bit of the lock file to disable printing. + */ + lock_file_name(pp, file, sizeof file); + seteuid(euid); + if (stat(file, &stbuf) >= 0) { + if (chmod(file, stbuf.st_mode|LFM_PRINT_DIS|LFM_QUEUE_DIS) < 0) + printf("\tcannot disable queuing: %s\n", + strerror(errno)); + else + printf("\tprinter and queuing disabled\n"); + } else if (errno == ENOENT) { + if ((fd = open(file, O_WRONLY|O_CREAT, + LOCK_FILE_MODE|LFM_PRINT_DIS|LFM_QUEUE_DIS)) < 0) + printf("\tcannot create lock file: %s\n", + strerror(errno)); + else { + (void) close(fd); + printf("\tprinter and queuing disabled\n"); + } + seteuid(uid); + return; + } else + printf("\tcannot stat lock file\n"); + /* + * Write the message into the status file. + */ + status_file_name(pp, file, sizeof file); + fd = open(file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); + if (fd < 0) { + printf("\tcannot create status file: %s\n", strerror(errno)); + seteuid(uid); + return; + } + seteuid(uid); + (void) ftruncate(fd, 0); + if (argc <= 0) { + (void) write(fd, "\n", 1); + (void) close(fd); + return; + } + cp1 = buf; + while (--argc >= 0) { + cp2 = *argv++; + while ((cp1 - buf) < sizeof(buf) && (*cp1++ = *cp2++)) + ; + cp1[-1] = ' '; + } + cp1[-1] = '\n'; + *cp1 = '\0'; + (void) write(fd, buf, strlen(buf)); + (void) close(fd); +} + +/* + * Exit lpc + */ +void +quit(argc, argv) + int argc; + char *argv[]; +{ + exit(0); +} + +/* + * Kill and restart the daemon. + */ +void +restart(pp) + struct printer *pp; +{ + abortpr(pp, 0); + startpr(pp, 0); +} + +/* + * Enable printing on the specified printer and startup the daemon. + */ +void +startcmd(pp) + struct printer *pp; +{ + startpr(pp, 1); +} + +static void +startpr(pp, enable) + struct printer *pp; + int enable; +{ + struct stat stbuf; + char lf[MAXPATHLEN]; + + lock_file_name(pp, lf, sizeof lf); + printf("%s:\n", pp->printer); + + /* + * For enable==1 ('start'), turn off the LFM_PRINT_DIS bit of the + * lock file to re-enable printing. For enable==2 ('up'), also + * turn off the LFM_QUEUE_DIS bit to re-enable queueing. + */ + seteuid(euid); + if (enable && stat(lf, &stbuf) >= 0) { + mode_t bits = (enable == 2 ? 0 : LFM_QUEUE_DIS); + if (chmod(lf, stbuf.st_mode & (LOCK_FILE_MODE | bits)) < 0) + printf("\tcannot enable printing\n"); + else + printf("\tprinting enabled\n"); + } + if (!startdaemon(pp)) + printf("\tcouldn't start daemon\n"); + else + printf("\tdaemon started\n"); + seteuid(uid); +} + +/* + * Print the status of the printer queue. + */ +void +status(pp) + struct printer *pp; +{ + struct stat stbuf; + register int fd, i; + register struct dirent *dp; + DIR *dirp; + char file[MAXPATHLEN]; + + printf("%s:\n", pp->printer); + lock_file_name(pp, file, sizeof file); + if (stat(file, &stbuf) >= 0) { + printf("\tqueuing is %s\n", + ((stbuf.st_mode & LFM_QUEUE_DIS) ? "disabled" + : "enabled")); + printf("\tprinting is %s\n", + ((stbuf.st_mode & LFM_PRINT_DIS) ? "disabled" + : "enabled")); + } else { + printf("\tqueuing is enabled\n"); + printf("\tprinting is enabled\n"); + } + if ((dirp = opendir(pp->spool_dir)) == NULL) { + printf("\tcannot examine spool directory\n"); + return; + } + i = 0; + while ((dp = readdir(dirp)) != NULL) { + if (*dp->d_name == 'c' && dp->d_name[1] == 'f') + i++; + } + closedir(dirp); + if (i == 0) + printf("\tno entries in spool area\n"); + else if (i == 1) + printf("\t1 entry in spool area\n"); + else + printf("\t%d entries in spool area\n", i); + fd = open(file, O_RDONLY); + if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) { + (void) close(fd); /* unlocks as well */ + printf("\tprinter idle\n"); + return; + } + (void) close(fd); + /* print out the contents of the status file, if it exists */ + status_file_name(pp, file, sizeof file); + fd = open(file, O_RDONLY|O_SHLOCK); + if (fd >= 0) { + (void) fstat(fd, &stbuf); + if (stbuf.st_size > 0) { + putchar('\t'); + while ((i = read(fd, line, sizeof(line))) > 0) + (void) fwrite(line, 1, i, stdout); + } + (void) close(fd); /* unlocks as well */ + } +} + +/* + * Stop the specified daemon after completing the current job and disable + * printing. + */ +void +stop(pp) + struct printer *pp; +{ + register int fd; + struct stat stbuf; + char lf[MAXPATHLEN]; + + lock_file_name(pp, lf, sizeof lf); + printf("%s:\n", pp->printer); + + /* + * Turn on the owner execute bit of the lock file to disable printing. + */ + seteuid(euid); + if (stat(lf, &stbuf) >= 0) { + if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0) + printf("\tcannot disable printing: %s\n", + strerror(errno)); + else { + upstat(pp, "printing disabled\n"); + printf("\tprinting disabled\n"); + } + } else if (errno == ENOENT) { + if ((fd = open(lf, O_WRONLY|O_CREAT, + LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0) + printf("\tcannot create lock file: %s\n", + strerror(errno)); + else { + (void) close(fd); + upstat(pp, "printing disabled\n"); + printf("\tprinting disabled\n"); + } + } else + printf("\tcannot stat lock file\n"); + seteuid(uid); +} + +struct queue **queue; +int nitems; +time_t mtime; + +/* + * Put the specified jobs at the top of printer queue. + */ +void +topq(argc, argv) + int argc; + char *argv[]; +{ + register int i; + struct stat stbuf; + int status, changed; + struct printer myprinter, *pp = &myprinter; + + if (argc < 3) { + printf("Usage: topq printer [jobnum ...] [user ...]\n"); + return; + } + + --argc; + ++argv; + init_printer(pp); + status = getprintcap(*argv, pp); + switch(status) { + default: + fatal(pp, pcaperr(status)); + case PCAPERR_NOTFOUND: + printf("unknown printer %s\n", *argv); + return; + case PCAPERR_TCOPEN: + printf("warning: %s: unresolved tc= reference(s)", *argv); + break; + case PCAPERR_SUCCESS: + break; + } + printf("%s:\n", pp->printer); + + seteuid(euid); + if (chdir(pp->spool_dir) < 0) { + printf("\tcannot chdir to %s\n", pp->spool_dir); + goto out; + } + seteuid(uid); + nitems = getq(pp, &queue); + if (nitems == 0) + return; + changed = 0; + mtime = queue[0]->q_time; + for (i = argc; --i; ) { + if (doarg(argv[i]) == 0) { + printf("\tjob %s is not in the queue\n", argv[i]); + continue; + } else + changed++; + } + for (i = 0; i < nitems; i++) + free(queue[i]); + free(queue); + if (!changed) { + printf("\tqueue order unchanged\n"); + return; + } + /* + * Turn on the public execute bit of the lock file to + * get lpd to rebuild the queue after the current job. + */ + seteuid(euid); + if (changed && stat(pp->lock_file, &stbuf) >= 0) + (void) chmod(pp->lock_file, stbuf.st_mode | LFM_RESET_QUE); + +out: + seteuid(uid); +} + +/* + * Reposition the job by changing the modification time of + * the control file. + */ +static int +touch(q) + struct queue *q; +{ + struct timeval tvp[2]; + int ret; + + tvp[0].tv_sec = tvp[1].tv_sec = --mtime; + tvp[0].tv_usec = tvp[1].tv_usec = 0; + seteuid(euid); + ret = utimes(q->q_name, tvp); + seteuid(uid); + return (ret); +} + +/* + * Checks if specified job name is in the printer's queue. + * Returns: negative (-1) if argument name is not in the queue. + */ +static int +doarg(job) + char *job; +{ + register struct queue **qq; + register int jobnum, n; + register char *cp, *machine; + int cnt = 0; + FILE *fp; + + /* + * Look for a job item consisting of system name, colon, number + * (example: ucbarpa:114) + */ + if ((cp = strchr(job, ':')) != NULL) { + machine = job; + *cp++ = '\0'; + job = cp; + } else + machine = NULL; + + /* + * Check for job specified by number (example: 112 or 235ucbarpa). + */ + if (isdigit(*job)) { + jobnum = 0; + do + jobnum = jobnum * 10 + (*job++ - '0'); + while (isdigit(*job)); + for (qq = queue + nitems; --qq >= queue; ) { + n = 0; + for (cp = (*qq)->q_name+3; isdigit(*cp); ) + n = n * 10 + (*cp++ - '0'); + if (jobnum != n) + continue; + if (*job && strcmp(job, cp) != 0) + continue; + if (machine != NULL && strcmp(machine, cp) != 0) + continue; + if (touch(*qq) == 0) { + printf("\tmoved %s\n", (*qq)->q_name); + cnt++; + } + } + return(cnt); + } + /* + * Process item consisting of owner's name (example: henry). + */ + for (qq = queue + nitems; --qq >= queue; ) { + seteuid(euid); + fp = fopen((*qq)->q_name, "r"); + seteuid(uid); + if (fp == NULL) + continue; + while (getline(fp) > 0) + if (line[0] == 'P') + break; + (void) fclose(fp); + if (line[0] != 'P' || strcmp(job, line+1) != 0) + continue; + if (touch(*qq) == 0) { + printf("\tmoved %s\n", (*qq)->q_name); + cnt++; + } + } + return(cnt); +} + +/* + * Enable everything and start printer (undo `down'). + */ +void +up(pp) + struct printer *pp; +{ + startpr(pp, 2); +} diff --git a/usr.sbin/lpr/lpc/cmdtab.c b/usr.sbin/lpr/lpc/cmdtab.c new file mode 100644 index 0000000..8e2b6ef --- /dev/null +++ b/usr.sbin/lpr/lpc/cmdtab.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +/* +static char sccsid[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93"; +*/ +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/cdefs.h> + +#include "lpc.h" +#include "extern.h" + +/* + * lpc -- command tables + */ +char aborthelp[] = "terminate a spooling daemon immediately and disable printing"; +char cleanhelp[] = "remove cruft files from a queue"; +char enablehelp[] = "turn a spooling queue on"; +char disablehelp[] = "turn a spooling queue off"; +char downhelp[] = "do a 'stop' followed by 'disable' and put a message in status"; +char helphelp[] = "get help on commands"; +char quithelp[] = "exit lpc"; +char restarthelp[] = "kill (if possible) and restart a spooling daemon"; +char starthelp[] = "enable printing and start a spooling daemon"; +char statushelp[] = "show status of daemon and queue"; +char stophelp[] = "stop a spooling daemon after current job completes and disable printing"; +char topqhelp[] = "put job at top of printer queue"; +char uphelp[] = "enable everything and restart spooling daemon"; + +struct cmd cmdtab[] = { + { "abort", aborthelp, 0, 1, doabort }, + { "clean", cleanhelp, 0, 1, clean }, + { "enable", enablehelp, 0, 1, enable }, + { "exit", quithelp, quit, 0 }, + { "disable", disablehelp, 0, 1, disable }, + { "down", downhelp, down, 1 }, + { "help", helphelp, help, 0 }, + { "quit", quithelp, quit, 0 }, + { "restart", restarthelp, 0, 0, restart }, + { "start", starthelp, 0, 1, startcmd }, + { "status", statushelp, 0, 0, status }, + { "stop", stophelp, 0, 1, stop }, + { "topq", topqhelp, topq, 1 }, + { "up", uphelp, 0, 1, up }, + { "?", helphelp, help, 0 }, + { 0 }, +}; + +int NCMDS = sizeof (cmdtab) / sizeof (cmdtab[0]); diff --git a/usr.sbin/lpr/lpc/extern.h b/usr.sbin/lpr/lpc/extern.h new file mode 100644 index 0000000..a07a09a --- /dev/null +++ b/usr.sbin/lpr/lpc/extern.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)extern.h 8.1 (Berkeley) 6/6/93 + */ + + +#include <sys/types.h> +#include <sys/cdefs.h> + + +__BEGIN_DECLS +void clean __P((struct printer *)); +void disable __P((struct printer *)); +void doabort __P((struct printer *)); +void down __P((int, char **)); +void enable __P((struct printer *)); +void generic __P((void (*) __P((struct printer *)), int, char **)); +void help __P((int, char **)); +void quit __P((int, char **)); +void restart __P((struct printer *)); +void startcmd __P((struct printer *)); +void status __P((struct printer *)); +void stop __P((struct printer *)); +void topq __P((int, char **)); +void up __P((struct printer *)); +__END_DECLS + +extern int NCMDS; +extern struct cmd cmdtab[]; +extern uid_t uid, euid; diff --git a/usr.sbin/lpr/lpc/lpc.8 b/usr.sbin/lpr/lpc/lpc.8 new file mode 100644 index 0000000..f0586d7 --- /dev/null +++ b/usr.sbin/lpr/lpc/lpc.8 @@ -0,0 +1,178 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)lpc.8 8.5 (Berkeley) 4/28/95 +.\" $FreeBSD$ +.\" +.Dd April 28, 1995 +.Dt LPC 8 +.Os BSD 4.2 +.Sh NAME +.Nm lpc +.Nd line printer control program +.Sh SYNOPSIS +.Nm lpc +.Oo +.Ar command +.Op Ar argument ... +.Oc +.Sh DESCRIPTION +.Nm Lpc +is used by the system administrator to control the +operation of the line printer system. +For each line printer configured in +.Pa /etc/printcap , +.Nm lpc +may be used to: +.Bl -bullet -offset indent +.It +disable or enable a printer, +.It +disable or enable a printer's spooling queue, +.It +rearrange the order of jobs in a spooling queue, +.It +find the status of printers, and their associated +spooling queues and printer daemons. +.El +.Pp +Without any arguments, +.Nm +will prompt for commands from the standard input. +If arguments are supplied, +.Nm +interprets the first argument as a command and the remaining +arguments as parameters to the command. The standard input +may be redirected causing +.Nm +to read commands from file. +Commands may be abbreviated; +the following is the list of recognized commands. +.Pp +.Bl -tag -width Ds -compact +.It Ic \&? No [ command ... ] +.It Ic help No [ command ... ] +Print a short description of each command specified in the argument list, +or, if no argument is given, a list of the recognized commands. +.Pp +.It Ic abort No {\ all\ |\ printer\ } +Terminate an active spooling daemon on the local host immediately and +then disable printing (preventing new daemons from being started by +.Xr lpr 1 ) +for the specified printers. +.Pp +.It Ic clean No {\ all\ |\ printer\ } +Remove any temporary files, data files, and control files that cannot +be printed (i.e., do not form a complete printer job) +from the specified printer queue(s) on the local machine. +.Pp +.It Ic disable No {\ all\ |\ printer\ } +Turn the specified printer queues off. This prevents new +printer jobs from being entered into the queue by +.Xr lpr 1 . +.Pp +.It Ic down No {\ all\ |\ printer\ } message ... +Turn the specified printer queue off, disable printing and put +.Em message +in the printer status file. +The message doesn't need to be quoted, the +remaining arguments are treated like +.Xr echo 1 . +This is normally used to take a printer down and let others know why +.Xr lpq 1 +will indicate the printer is down and print the status message). +.Pp +.It Ic enable No {\ all\ |\ printer\ } +Enable spooling on the local queue for the listed printers. +This will allow +.Xr lpr 1 +to put new jobs in the spool queue. +.Pp +.It Ic exit +.It Ic quit +Exit from lpc. +.\" ne 1i +.Pp +.It Ic restart No {\ all\ |\ printer\ } +Attempt to start a new printer daemon. +This is useful when some abnormal condition causes the daemon to +die unexpectedly, leaving jobs in the queue. +.Xr Lpq 1 +will report that there is no daemon present when this condition occurs. +If the user is the super-user, +try to abort the current daemon first (i.e., kill and restart a stuck daemon). +.Pp +.It Ic start No {\ all\ |\ printer\ } +Enable printing and start a spooling daemon for the listed printers. +.Pp +.It Ic status No {\ all\ |\ printer\ } +Display the status of daemons and queues on the local machine. +.Pp +.It Ic stop No {\ all\ |\ printer\ } +Stop a spooling daemon after the current job completes and disable +printing. +.Pp +.It Ic topq No printer\ [\ jobnum\ ...\ ]\ [\ user\ ...\ ] +Place the jobs in the order listed at the top of the printer queue. +.Pp +.It Ic up No {\ all\ |\ printer\ } +Enable everything and start a new printer daemon. +Undoes the effects of +.Ic down . +.Sh FILES +.Bl -tag -width /var/spool/*/lockx -compact +.It Pa /etc/printcap +printer description file +.It Pa /var/spool/* +spool directories +.It Pa /var/spool/*/lock +lock file for queue control +.El +.Sh SEE ALSO +.Xr lpq 1 , +.Xr lpr 1 , +.Xr lprm 1 , +.Xr printcap 5 , +.Xr lpd 8 +.Sh DIAGNOSTICS +.Bl -tag -width Ds +.It Sy "?Ambiguous command" +abbreviation matches more than one command +.It Sy "?Invalid command" +no match was found +.It Sy "?Privileged command" +you must be a member of group "operator" or root to execute this command +.El +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.2 . diff --git a/usr.sbin/lpr/lpc/lpc.c b/usr.sbin/lpr/lpc/lpc.c new file mode 100644 index 0000000..866b8ac --- /dev/null +++ b/usr.sbin/lpr/lpc/lpc.c @@ -0,0 +1,356 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)lpc.c 8.3 (Berkeley) 4/28/95"; +#endif +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/param.h> + +#include <ctype.h> +#include <dirent.h> +#include <err.h> +#include <grp.h> +#include <setjmp.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <string.h> +#include <unistd.h> +#include <histedit.h> + +#include "lp.h" +#include "lpc.h" +#include "extern.h" + +#ifndef LPR_OPER +#define LPR_OPER "operator" /* group name of lpr operators */ +#endif + +/* + * lpc -- line printer control program + */ + +#define MAX_CMDLINE 200 +#define MAX_MARGV 20 +static int fromatty; + +static char cmdline[MAX_CMDLINE]; +static int margc; +static char *margv[MAX_MARGV]; +uid_t uid, euid; + +int main __P((int, char *[])); +static void cmdscanner __P((void)); +static struct cmd *getcmd __P((char *)); +static void intr __P((int)); +static void makeargv __P((void)); +static int ingroup __P((char *)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register struct cmd *c; + + euid = geteuid(); + uid = getuid(); + seteuid(uid); + name = argv[0]; + openlog("lpd", 0, LOG_LPR); + + if (--argc > 0) { + c = getcmd(*++argv); + if (c == (struct cmd *)-1) { + printf("?Ambiguous command\n"); + exit(1); + } + if (c == 0) { + printf("?Invalid command\n"); + exit(1); + } + if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) { + printf("?Privileged command\n"); + exit(1); + } + if (c->c_generic != 0) + generic(c->c_generic, argc, argv); + else + (*c->c_handler)(argc, argv); + exit(0); + } + fromatty = isatty(fileno(stdin)); + if (!fromatty) + signal(SIGINT, intr); + for (;;) { + cmdscanner(); + } +} + +static void +intr(signo) + int signo; +{ + exit(0); +} + +static char * +lpc_prompt() +{ + return("lpc> "); +} + +/* + * Command parser. + */ +static void +cmdscanner() +{ + register struct cmd *c; + static EditLine *el = NULL; + static History *hist = NULL; + int num = 0; + int len; + const char *bp = NULL; + + for (;;) { + if (fromatty) { + if (!el) { + el = el_init("lpc", stdin, stdout); + hist = history_init(); + history(hist, H_EVENT, 100); + el_set(el, EL_HIST, history, hist); + el_set(el, EL_EDITOR, "emacs"); + el_set(el, EL_PROMPT, lpc_prompt); + el_set(el, EL_SIGNAL, 1); + el_source(el, NULL); + } + if ((bp = el_gets(el, &num)) == NULL || num == 0) + quit(0, NULL); + + len = (num > MAX_CMDLINE) ? MAX_CMDLINE : num; + memcpy(cmdline, bp, len); + cmdline[len] = 0; + history(hist, H_ENTER, bp); + + } else { + if (fgets(cmdline, MAX_CMDLINE, stdin) == 0) + quit(0, NULL); + if (cmdline[0] == 0 || cmdline[0] == '\n') + break; + } + + makeargv(); + if (margc == 0) + continue; + if (el_parse(el, margc, margv) != -1) + continue; + + c = getcmd(margv[0]); + if (c == (struct cmd *)-1) { + printf("?Ambiguous command\n"); + continue; + } + if (c == 0) { + printf("?Invalid command\n"); + continue; + } + if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) { + printf("?Privileged command\n"); + continue; + } + if (c->c_generic != 0) + generic(c->c_generic, margc, margv); + else + (*c->c_handler)(margc, margv); + } +} + +static struct cmd * +getcmd(name) + register char *name; +{ + register char *p, *q; + register struct cmd *c, *found; + register int nmatches, longest; + + longest = 0; + nmatches = 0; + found = 0; + for (c = cmdtab; (p = c->c_name); c++) { + for (q = name; *q == *p++; q++) + if (*q == 0) /* exact match? */ + return(c); + if (!*q) { /* the name was a prefix */ + if (q - name > longest) { + longest = q - name; + nmatches = 1; + found = c; + } else if (q - name == longest) + nmatches++; + } + } + if (nmatches > 1) + return((struct cmd *)-1); + return(found); +} + +/* + * Slice a string up into argc/argv. + */ +static void +makeargv() +{ + register char *cp; + register char **argp = margv; + register int n = 0; + + margc = 0; + for (cp = cmdline; *cp && (cp - cmdline) < sizeof(cmdline) && + n < MAX_MARGV; n++) { + while (isspace(*cp)) + cp++; + if (*cp == '\0') + break; + *argp++ = cp; + margc += 1; + while (*cp != '\0' && !isspace(*cp)) + cp++; + if (*cp == '\0') + break; + *cp++ = '\0'; + } + *argp++ = 0; +} + +#define HELPINDENT (sizeof ("directory")) + +/* + * Help command. + */ +void +help(argc, argv) + int argc; + char *argv[]; +{ + register struct cmd *c; + + if (argc == 1) { + register int i, j, w; + int columns, width = 0, lines; + + printf("Commands may be abbreviated. Commands are:\n\n"); + for (c = cmdtab; c->c_name; c++) { + int len = strlen(c->c_name); + + if (len > width) + width = len; + } + width = (width + 8) &~ 7; + columns = 80 / width; + if (columns == 0) + columns = 1; + lines = (NCMDS + columns - 1) / columns; + for (i = 0; i < lines; i++) { + for (j = 0; j < columns; j++) { + c = cmdtab + j * lines + i; + if (c->c_name) + printf("%s", c->c_name); + if (c + lines >= &cmdtab[NCMDS]) { + printf("\n"); + break; + } + w = strlen(c->c_name); + while (w < width) { + w = (w + 8) &~ 7; + putchar('\t'); + } + } + } + return; + } + while (--argc > 0) { + register char *arg; + arg = *++argv; + c = getcmd(arg); + if (c == (struct cmd *)-1) + printf("?Ambiguous help command %s\n", arg); + else if (c == (struct cmd *)0) + printf("?Invalid help command %s\n", arg); + else + printf("%-*s\t%s\n", (int) HELPINDENT, + c->c_name, c->c_help); + } +} + +/* + * return non-zero if the user is a member of the given group + */ +static int +ingroup(grname) + char *grname; +{ + static struct group *gptr=NULL; + static int ngroups = 0; + static gid_t groups[NGROUPS]; + register gid_t gid; + register int i; + + if (gptr == NULL) { + if ((gptr = getgrnam(grname)) == NULL) { + warnx("warning: unknown group '%s'", grname); + return(0); + } + ngroups = getgroups(NGROUPS, groups); + if (ngroups < 0) + err(1, "getgroups"); + } + gid = gptr->gr_gid; + for (i = 0; i < ngroups; i++) + if (gid == groups[i]) + return(1); + return(0); +} diff --git a/usr.sbin/lpr/lpc/lpc.h b/usr.sbin/lpr/lpc/lpc.h new file mode 100644 index 0000000..eca7b91 --- /dev/null +++ b/usr.sbin/lpr/lpc/lpc.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)lpc.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Line printer control program. + */ +struct printer; + +struct cmd { + char *c_name; /* command name */ + char *c_help; /* help message */ + /* routine to do the work */ + void (*c_handler) __P((int, char *[])); + int c_priv; /* privileged command */ + void (*c_generic) __P((struct printer *)); /* generic command */ +}; diff --git a/usr.sbin/lpr/lpd/Makefile b/usr.sbin/lpr/lpd/Makefile new file mode 100644 index 0000000..e107e97 --- /dev/null +++ b/usr.sbin/lpr/lpd/Makefile @@ -0,0 +1,11 @@ +# From: @(#)Makefile 8.1 (Berkeley) 6/6/93 +# $FreeBSD$ + +PROG= lpd +CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS} +MAN8= lpd.8 +SRCS= lpd.c printjob.c recvjob.c lpdchar.c modes.c +DPADD= ${LIBLPR} +LDADD= ${LIBLPR} + +.include <bsd.prog.mk> diff --git a/usr.sbin/lpr/lpd/extern.h b/usr.sbin/lpr/lpd/extern.h new file mode 100644 index 0000000..70c536d --- /dev/null +++ b/usr.sbin/lpr/lpd/extern.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: @(#)extern.h 8.1 (Berkeley) 6/6/93 + * $FreeBSD$ + */ + +#include <sys/cdefs.h> + +extern char scnkey[][HEIGHT]; /* in lpdchar.c */ +extern char fromb[]; + +struct printer; +struct termios; + +__BEGIN_DECLS +void printjob __P((struct printer *pp)); +void startprinting __P((const char *printer)); +void recvjob __P((const char *printer)); +int msearch __P((char *str, struct termios *ip)); +__END_DECLS diff --git a/usr.sbin/lpr/lpd/lpd.8 b/usr.sbin/lpr/lpd/lpd.8 new file mode 100644 index 0000000..f882a31 --- /dev/null +++ b/usr.sbin/lpr/lpd/lpd.8 @@ -0,0 +1,271 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)lpd.8 8.3 (Berkeley) 4/19/94 +.\" $FreeBSD$ +.\" +.Dd April 19, 1994 +.Dt LPD 8 +.Os BSD 4.2 +.Sh NAME +.Nm lpd +.Nd line printer spooler daemon +.Sh SYNOPSIS +.Nm lpd +.Op Fl dlp +.Op Ar port# +.Sh DESCRIPTION +.Nm Lpd +is the line printer daemon (spool area handler) and is normally invoked +at boot time from the +.Xr rc 8 +file. It makes a single pass through the +.Xr printcap 5 +file to find out about the existing printers and +prints any files left after a crash. +It then uses the system calls +.Xr listen 2 +and +.Xr accept 2 +to receive requests to print files in the queue, +transfer files to the spooling area, display the queue, +or remove jobs from the queue. In each case, it forks a child to handle +the request so the parent can continue to listen for more requests. +.Pp +Available options: +.Bl -tag -width Ds +.It Fl d +Turn on +.Dv SO_DEBUG +on the Internet listening socket (see +.Xr setsockopt 2 ) . +.It Fl l +The +.Fl l +flag causes +.Nm +to log valid requests received from the network. +This can be useful +for debugging purposes. +.It Fl p +The +.Fl p +flag causes +.Nm +not to open an Internet listening socket. +.It Ar "port#" +The Internet port number used to rendezvous +with other processes is normally obtained with +.Xr getservbyname 3 +but can be changed with the +.Ar port# +argument. +.El +.Pp +Access control is provided by two means. +First, all requests must come from +one of the machines listed in the file +.Pa /etc/hosts.equiv +or +.Pa /etc/hosts.lpd . +Second, if the +.Li rs +capability is specified in the +.Xr printcap +entry for the printer being accessed, +.Em lpr +requests will only be honored for those users with accounts on the +machine with the printer. +.Pp +The file +.Em minfree +in each spool directory contains the number of disk blocks to leave free +so that the line printer queue won't completely fill the disk. +The +.Em minfree +file can be edited with your favorite text editor. +.Pp +The daemon begins processing files +after it has successfully set the lock for exclusive +access (described a bit later), +and scans the spool directory +for files beginning with +.Em cf . +Lines in each +.Em cf +file specify files to be printed or non-printing actions to be +performed. Each such line begins with a key character +to specify what to do with the remainder of the line. +.Bl -tag -width Ds +.It J +Job Name. String to be used for the job name on the burst page. +.It C +Classification. String to be used for the classification line +on the burst page. +.It L +Literal. The line contains identification info from +the password file and causes the banner page to be printed. +.It T +Title. String to be used as the title for +.Xr pr 1 . +.It H +Host Name. Name of the machine where +.Xr lpr +was invoked. +.It P +Person. Login name of the person who invoked +.Xr lpr . +This is used to verify ownership by +.Xr lprm . +.It M +Send mail to the specified user when the current print job completes. +.It f +Formatted File. Name of a file to print which is already formatted. +.It l +Like ``f'' but passes control characters and does not make page breaks. +.It p +Name of a file to print using +.Xr pr 1 +as a filter. +.It t +Troff File. The file contains +.Xr troff 1 +output (cat phototypesetter commands). +.It n +Ditroff File. The file contains device independent troff +output. +.It r +DVI File. The file contains +.Tn Tex l +output +DVI format from Standford. +.It g +Graph File. The file contains data produced by +.Xr plot 3 . +.It c +Cifplot File. +The file contains data produced by +.Em cifplot . +.It v +The file contains a raster image. +.It r +The file contains text data with +FORTRAN carriage control characters. +.It \&1 +Troff Font R. Name of the font file to use instead of the default. +.It \&2 +Troff Font I. Name of the font file to use instead of the default. +.It \&3 +Troff Font B. Name of the font file to use instead of the default. +.It \&4 +Troff Font S. Name of the font file to use instead of the default. +.It W +Width. +Changes the page width (in characters) used by +.Xr pr 1 +and the text filters. +.It I +Indent. The number of characters to indent the output by (in ASCII). +.It U +Unlink. Name of file to remove upon completion of printing. +.It N +File name. The name of the file which is being printed, or a blank +for the standard input (when +.Xr lpr +is invoked in a pipeline). +.It Z +Locale. String to be used as the locale for +.Xr pr 1 . +.El +.Pp +If a file cannot be opened, a message will be logged via +.Xr syslog 3 +using the +.Em LOG_LPR +facility. +.Nm Lpd +will try up to 20 times +to reopen a file it expects to be there, after which it will +skip the file to be printed. +.Pp +.Nm Lpd +uses +.Xr flock 2 +to provide exclusive access to the lock file and to prevent multiple +daemons from becoming active simultaneously. If the daemon should be killed +or die unexpectedly, the lock file need not be removed. +The lock file is kept in a readable +.Tn ASCII +form +and contains two lines. +The first is the process id of the daemon and the second is the control +file name of the current job being printed. The second line is updated to +reflect the current status of +.Nm +for the programs +.Xr lpq 1 +and +.Xr lprm 1 . +.Sh FILES +.Bl -tag -width "/var/spool/*/minfree" -compact +.It Pa /etc/printcap +printer description file +.It Pa /var/spool/* +spool directories +.It Pa /var/spool/*/minfree +minimum free space to leave +.It Pa /dev/lp* +line printer devices +.It Pa /var/run/printer +socket for local requests +.It Pa /etc/hosts.equiv +lists machine names allowed printer access +.It Pa /etc/hosts.lpd +lists machine names allowed printer access, +but not under same administrative control. +.El +.Sh SEE ALSO +.Xr lpq 1 , +.Xr lpr 1 , +.Xr lprm 1 , +.Xr setsockopt 2 , +.Xr syslog 3 , +.Xr hosts.lpd 5 , +.Xr printcap 5 , +.Xr lpc 8 , +.Xr pac 8 +.Rs +.%T "4.2 BSD Line Printer Spooler Manual" +.Re +.Sh HISTORY +An +.Nm +daemon appeared in Version 6 AT&T UNIX. diff --git a/usr.sbin/lpr/lpd/lpd.c b/usr.sbin/lpr/lpd/lpd.c new file mode 100644 index 0000000..6d3a710 --- /dev/null +++ b/usr.sbin/lpr/lpd/lpd.c @@ -0,0 +1,657 @@ +/* + * Copyright (c) 1983, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1983, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95"; +#endif +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +/* + * lpd -- line printer daemon. + * + * Listen for a connection and perform the requested operation. + * Operations are: + * \1printer\n + * check the queue for jobs and print any found. + * \2printer\n + * receive a job from another machine and queue it. + * \3printer [users ...] [jobs ...]\n + * return the current state of the queue (short form). + * \4printer [users ...] [jobs ...]\n + * return the current state of the queue (long form). + * \5printer person [users ...] [jobs ...]\n + * remove jobs from the queue. + * + * Strategy to maintain protected spooling area: + * 1. Spooling area is writable only by daemon and spooling group + * 2. lpr runs setuid root and setgrp spooling group; it uses + * root to access any file it wants (verifying things before + * with an access call) and group id to know how it should + * set up ownership of files in the spooling area. + * 3. Files in spooling area are owned by root, group spooling + * group, with mode 660. + * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to + * access files and printer. Users can't get to anything + * w/o help of lpq and lprm programs. + */ + +#include <sys/param.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <netdb.h> +#include <unistd.h> +#include <syslog.h> +#include <signal.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <ctype.h> +#include "lp.h" +#include "lp.local.h" +#include "pathnames.h" +#include "extern.h" + +int lflag; /* log requests flag */ +int pflag; /* no incoming port flag */ +int from_remote; /* from remote socket */ + +int main __P((int, char **)); +static void reapchild __P((int)); +static void mcleanup __P((int)); +static void doit __P((void)); +static void startup __P((void)); +static void chkhost __P((struct sockaddr_in *)); +static int ckqueue __P((struct printer *)); +static void usage __P((void)); +/* From rcmd.c: */ +int __ivaliduser __P((FILE *, u_long, const char *, + const char *)); + +uid_t uid, euid; + +int +main(argc, argv) + int argc; + char **argv; +{ + int f, funix, finet, options, fromlen, i, errs; + fd_set defreadfds; + struct sockaddr_un un, fromunix; + struct sockaddr_in sin, frominet; + int lfd; + sigset_t omask, nmask; + struct servent *sp, serv; + + euid = geteuid(); /* these shouldn't be different */ + uid = getuid(); + options = 0; + gethostname(host, sizeof(host)); + + name = "lpd"; + + if (euid != 0) + errx(EX_NOPERM,"must run as root"); + + errs = 0; + while ((i = getopt(argc, argv, "dlp")) != -1) + switch (i) { + case 'd': + options |= SO_DEBUG; + break; + case 'l': + lflag++; + break; + case 'p': + pflag++; + break; + default: + errs++; + } + argc -= optind; + argv += optind; + if (errs) + usage(); + + if (argc == 1) { + if ((i = atoi(argv[0])) == 0) + usage(); + if (i < 0 || i > USHRT_MAX) + errx(EX_USAGE, "port # %d is invalid", i); + + serv.s_port = htons(i); + sp = &serv; + argc--; + } else { + sp = getservbyname("printer", "tcp"); + if (sp == NULL) + errx(EX_OSFILE, "printer/tcp: unknown service"); + } + + if (argc != 0) + usage(); + + /* + * We run chkprintcap right away to catch any errors and blat them + * to stderr while we still have it open, rather than sending them + * to syslog and leaving the user wondering why lpd started and + * then stopped. There should probably be a command-line flag to + * ignore errors from chkprintcap. + */ + { + pid_t pid; + int status; + pid = fork(); + if (pid < 0) { + err(EX_OSERR, "cannot fork"); + } else if (pid == 0) { /* child */ + execl(_PATH_CHKPRINTCAP, _PATH_CHKPRINTCAP, (char *)0); + err(EX_OSERR, "cannot execute %s", _PATH_CHKPRINTCAP); + } + if (waitpid(pid, &status, 0) < 0) { + err(EX_OSERR, "cannot wait"); + } + if (WIFEXITED(status) && WEXITSTATUS(status) != 0) + errx(EX_OSFILE, "%d errors in printcap file, exiting", + WEXITSTATUS(status)); + } + +#ifndef DEBUG + /* + * Set up standard environment by detaching from the parent. + */ + daemon(0, 0); +#endif + + openlog("lpd", LOG_PID, LOG_LPR); + syslog(LOG_INFO, "restarted"); + (void) umask(0); + /* + * NB: This depends on O_NONBLOCK semantics doing the right thing; + * i.e., applying only to the O_EXLOCK and not to the rest of the + * open/creation. As of 1997-12-02, this is the case for commonly- + * used filesystems. There are other places in this code which + * make the same assumption. + */ + lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, + LOCK_FILE_MODE); + if (lfd < 0) { + if (errno == EWOULDBLOCK) /* active deamon present */ + exit(0); + syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); + exit(1); + } + fcntl(lfd, F_SETFL, 0); /* turn off non-blocking mode */ + ftruncate(lfd, 0); + /* + * write process id for others to know + */ + sprintf(line, "%u\n", getpid()); + f = strlen(line); + if (write(lfd, line, f) != f) { + syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); + exit(1); + } + signal(SIGCHLD, reapchild); + /* + * Restart all the printers. + */ + startup(); + (void) unlink(_PATH_SOCKETNAME); + funix = socket(AF_UNIX, SOCK_STREAM, 0); + if (funix < 0) { + syslog(LOG_ERR, "socket: %m"); + exit(1); + } + + sigemptyset(&nmask); + sigaddset(&nmask, SIGHUP); + sigaddset(&nmask, SIGINT); + sigaddset(&nmask, SIGQUIT); + sigaddset(&nmask, SIGTERM); + sigprocmask(SIG_BLOCK, &nmask, &omask); + + (void) umask(07); + signal(SIGHUP, mcleanup); + signal(SIGINT, mcleanup); + signal(SIGQUIT, mcleanup); + signal(SIGTERM, mcleanup); + memset(&un, 0, sizeof(un)); + un.sun_family = AF_UNIX; + strcpy(un.sun_path, _PATH_SOCKETNAME); +#ifndef SUN_LEN +#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) +#endif + if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { + syslog(LOG_ERR, "ubind: %m"); + exit(1); + } + (void) umask(0); + sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); + FD_ZERO(&defreadfds); + FD_SET(funix, &defreadfds); + listen(funix, 5); + if (pflag == 0) { + finet = socket(AF_INET, SOCK_STREAM, 0); + if (finet >= 0) { + i = 1; + if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR, &i, + sizeof i) < 0) { + syslog(LOG_ERR, "setsockopt(SO_REUSEADDR): %m"); + mcleanup(0); + } + if (options & SO_DEBUG && + setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) { + syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); + mcleanup(0); + } + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = sp->s_port; + if (bind(finet, (struct sockaddr *)&sin, + sizeof(sin)) < 0) { + syslog(LOG_ERR, "bind: %m"); + mcleanup(0); + } + FD_SET(finet, &defreadfds); + listen(finet, 5); + } + } + /* + * Main loop: accept, do a request, continue. + */ + memset(&frominet, 0, sizeof(frominet)); + memset(&fromunix, 0, sizeof(fromunix)); + /* + * XXX - should be redone for multi-protocol + */ + for (;;) { + int domain, nfds, s; + fd_set readfds; + + FD_COPY(&defreadfds, &readfds); + nfds = select(20, &readfds, 0, 0, 0); + if (nfds <= 0) { + if (nfds < 0 && errno != EINTR) + syslog(LOG_WARNING, "select: %m"); + continue; + } + if (FD_ISSET(funix, &readfds)) { + domain = AF_UNIX, fromlen = sizeof(fromunix); + s = accept(funix, + (struct sockaddr *)&fromunix, &fromlen); + } else if (pflag == 0) /* if (FD_ISSET(finet, &readfds)) */ { + domain = AF_INET, fromlen = sizeof(frominet); + s = accept(finet, + (struct sockaddr *)&frominet, &fromlen); + if (frominet.sin_port == htons(20)) { + close(s); + continue; + } + } + if (s < 0) { + if (errno != EINTR) + syslog(LOG_WARNING, "accept: %m"); + continue; + } + if (fork() == 0) { + signal(SIGCHLD, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + (void) close(funix); + if (pflag == 0) { + (void) close(finet); + } + dup2(s, 1); + (void) close(s); + if (domain == AF_INET) { + from_remote = 1; + chkhost(&frominet); + } else + from_remote = 0; + doit(); + exit(0); + } + (void) close(s); + } +} + +static void +reapchild(signo) + int signo; +{ + union wait status; + + while (wait3((int *)&status, WNOHANG, 0) > 0) + ; +} + +static void +mcleanup(signo) + int signo; +{ + /* + * XXX syslog(3) is not signal-safe. + */ + if (lflag) { + if (signo) + syslog(LOG_INFO, "exiting on signal %d", signo); + else + syslog(LOG_INFO, "exiting"); + } + unlink(_PATH_SOCKETNAME); + exit(0); +} + +/* + * Stuff for handling job specifications + */ +char *user[MAXUSERS]; /* users to process */ +int users; /* # of users in user array */ +int requ[MAXREQUESTS]; /* job number of spool entries */ +int requests; /* # of spool requests */ +char *person; /* name of person doing lprm */ + +char fromb[MAXHOSTNAMELEN]; /* buffer for client's machine name */ +char cbuf[BUFSIZ]; /* command line buffer */ +char *cmdnames[] = { + "null", + "printjob", + "recvjob", + "displayq short", + "displayq long", + "rmjob" +}; + +static void +doit() +{ + char *cp, *printer; + int n; + int status; + struct printer myprinter, *pp = &myprinter; + + init_printer(&myprinter); + + for (;;) { + cp = cbuf; + do { + if (cp >= &cbuf[sizeof(cbuf) - 1]) + fatal(0, "Command line too long"); + if ((n = read(1, cp, 1)) != 1) { + if (n < 0) + fatal(0, "Lost connection"); + return; + } + } while (*cp++ != '\n'); + *--cp = '\0'; + cp = cbuf; + if (lflag) { + if (*cp >= '\1' && *cp <= '\5') + syslog(LOG_INFO, "%s requests %s %s", + from, cmdnames[(u_char)*cp], cp+1); + else + syslog(LOG_INFO, "bad request (%d) from %s", + *cp, from); + } + switch (*cp++) { + case CMD_CHECK_QUE: /* check the queue, print any jobs there */ + startprinting(cp); + break; + case CMD_TAKE_THIS: /* receive files to be queued */ + if (!from_remote) { + syslog(LOG_INFO, "illegal request (%d)", *cp); + exit(1); + } + recvjob(cp); + break; + case CMD_SHOWQ_SHORT: /* display the queue (short form) */ + case CMD_SHOWQ_LONG: /* display the queue (long form) */ + /* XXX - this all needs to be redone. */ + printer = cp; + while (*cp) { + if (*cp != ' ') { + cp++; + continue; + } + *cp++ = '\0'; + while (isspace(*cp)) + cp++; + if (*cp == '\0') + break; + if (isdigit(*cp)) { + if (requests >= MAXREQUESTS) + fatal(0, "Too many requests"); + requ[requests++] = atoi(cp); + } else { + if (users >= MAXUSERS) + fatal(0, "Too many users"); + user[users++] = cp; + } + } + status = getprintcap(printer, pp); + if (status < 0) + fatal(pp, pcaperr(status)); + displayq(pp, cbuf[0] == CMD_SHOWQ_LONG); + exit(0); + case CMD_RMJOB: /* remove a job from the queue */ + if (!from_remote) { + syslog(LOG_INFO, "illegal request (%d)", *cp); + exit(1); + } + printer = cp; + while (*cp && *cp != ' ') + cp++; + if (!*cp) + break; + *cp++ = '\0'; + person = cp; + while (*cp) { + if (*cp != ' ') { + cp++; + continue; + } + *cp++ = '\0'; + while (isspace(*cp)) + cp++; + if (*cp == '\0') + break; + if (isdigit(*cp)) { + if (requests >= MAXREQUESTS) + fatal(0, "Too many requests"); + requ[requests++] = atoi(cp); + } else { + if (users >= MAXUSERS) + fatal(0, "Too many users"); + user[users++] = cp; + } + } + rmjob(printer); + break; + } + fatal(0, "Illegal service request"); + } +} + +/* + * Make a pass through the printcap database and start printing any + * files left from the last time the machine went down. + */ +static void +startup() +{ + int pid, status, more; + struct printer myprinter, *pp = &myprinter; + + more = firstprinter(pp, &status); + if (status) + goto errloop; + while (more) { + if (ckqueue(pp) <= 0) { + goto next; + } + if (lflag) + syslog(LOG_INFO, "work for %s", pp->printer); + if ((pid = fork()) < 0) { + syslog(LOG_WARNING, "startup: cannot fork"); + mcleanup(0); + } + if (pid == 0) { + lastprinter(); + printjob(pp); + /* NOTREACHED */ + } + do { +next: + more = nextprinter(pp, &status); +errloop: + if (status) + syslog(LOG_WARNING, + "printcap for %s has errors, skipping", + pp->printer ? pp->printer : "<???>"); + } while (more && status); + } +} + +/* + * Make sure there's some work to do before forking off a child + */ +static int +ckqueue(pp) + struct printer *pp; +{ + register struct dirent *d; + DIR *dirp; + char *spooldir; + + spooldir = pp->spool_dir; + if ((dirp = opendir(spooldir)) == NULL) + return (-1); + while ((d = readdir(dirp)) != NULL) { + if (d->d_name[0] != 'c' || d->d_name[1] != 'f') + continue; /* daemon control files only */ + closedir(dirp); + return (1); /* found something */ + } + closedir(dirp); + return (0); +} + +#define DUMMY ":nobody::" + +/* + * Check to see if the from host has access to the line printer. + */ +static void +chkhost(f) + struct sockaddr_in *f; +{ + register struct hostent *hp; + register FILE *hostf; + int first = 1; + int good = 0; + + /* Need real hostname for temporary filenames */ + hp = gethostbyaddr((char *)&f->sin_addr, + sizeof(struct in_addr), f->sin_family); + if (hp == NULL) + fatal(0, "Host name for your address (%s) unknown", + inet_ntoa(f->sin_addr)); + + (void) strncpy(fromb, hp->h_name, sizeof(fromb) - 1); + fromb[sizeof(fromb) - 1] = '\0'; + from = fromb; + strncpy(from_ip, inet_ntoa(f->sin_addr), MAXIPSTRLEN); + from_ip[sizeof(from_ip) - 1] = '\0'; + + /* Check for spoof, ala rlogind */ + hp = gethostbyname(fromb); + if (!hp) + fatal(0, "hostname for your address (%s) unknown", from_ip); + for (; good == 0 && hp->h_addr_list[0] != NULL; hp->h_addr_list++) { + if (!bcmp(hp->h_addr_list[0], (caddr_t)&f->sin_addr, + sizeof(f->sin_addr))) + good = 1; + } + if (good == 0) + fatal(0, "address for your hostname (%s) not matched", + from_ip); + + hostf = fopen(_PATH_HOSTSEQUIV, "r"); +again: + if (hostf) { + if (__ivaliduser(hostf, f->sin_addr.s_addr, + DUMMY, DUMMY) == 0) { + (void) fclose(hostf); + return; + } + (void) fclose(hostf); + } + if (first == 1) { + first = 0; + hostf = fopen(_PATH_HOSTSLPD, "r"); + goto again; + } + fatal(0, "Your host does not have line printer access"); + /*NOTREACHED*/ +} + +static void +usage() +{ + fprintf(stderr, "usage: lpd [-dlp] [port#]\n"); + exit(EX_USAGE); +} diff --git a/usr.sbin/lpr/lpd/lpdchar.c b/usr.sbin/lpr/lpd/lpdchar.c new file mode 100644 index 0000000..ba39a9f --- /dev/null +++ b/usr.sbin/lpr/lpd/lpdchar.c @@ -0,0 +1,1071 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +/* +static char sccsid[] = "@(#)lpdchar.c 8.1 (Berkeley) 6/6/93"; +*/ +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +/* + * Character set for line printer daemon + */ +#include "lp.local.h" +#include "extern.h" + +#define c_______ 0 +#define c______1 01 +#define c_____1_ 02 +#define c____1__ 04 +#define c____11_ 06 +#define c___1___ 010 +#define c___1__1 011 +#define c___1_1_ 012 +#define c___11__ 014 +#define c__1____ 020 +#define c__1__1_ 022 +#define c__1_1__ 024 +#define c__11___ 030 +#define c__111__ 034 +#define c__111_1 035 +#define c__1111_ 036 +#define c__11111 037 +#define c_1_____ 040 +#define c_1____1 041 +#define c_1___1_ 042 +#define c_1__1__ 044 +#define c_1_1___ 050 +#define c_1_1__1 051 +#define c_1_1_1_ 052 +#define c_11____ 060 +#define c_11_11_ 066 +#define c_111___ 070 +#define c_111__1 071 +#define c_111_1_ 072 +#define c_1111__ 074 +#define c_1111_1 075 +#define c_11111_ 076 +#define c_111111 077 +#define c1______ 0100 +#define c1_____1 0101 +#define c1____1_ 0102 +#define c1____11 0103 +#define c1___1__ 0104 +#define c1___1_1 0105 +#define c1___11_ 0106 +#define c1__1___ 0110 +#define c1__1__1 0111 +#define c1__11_1 0115 +#define c1__1111 0117 +#define c1_1____ 0120 +#define c1_1___1 0121 +#define c1_1_1_1 0125 +#define c1_1_11_ 0126 +#define c1_111__ 0134 +#define c1_1111_ 0136 +#define c11____1 0141 +#define c11___1_ 0142 +#define c11___11 0143 +#define c11_1___ 0150 +#define c11_1__1 0151 +#define c111_11_ 0166 +#define c1111___ 0170 +#define c11111__ 0174 +#define c111111_ 0176 +#define c1111111 0177 + +char scnkey[][HEIGHT] = /* this is relatively easy to modify */ + /* just look: */ +{ + { c_______, + c_______, + c_______, + c_______, + c_______, + c_______, + c_______, + c_______, + c_______ }, /* */ + + { c__11___, + c__11___, + c__11___, + c__11___, + c__11___, + c_______, + c_______, + c__11___, + c__11___ }, /* ! */ + + { c_1__1__, + c_1__1__, + c_______, + c_______, + c_______, + c_______, + c_______, + c_______, + c_______ }, /* " */ + + { c_______, + c__1_1__, + c__1_1__, + c1111111, + c__1_1__, + c1111111, + c__1_1__, + c__1_1__, + c_______ }, /* # */ + + { c___1___, + c_11111_, + c1__1__1, + c1__1___, + c_11111_, + c___1__1, + c1__1__1, + c_11111_, + c___1___ }, /* $ */ + + { c_1_____, + c1_1___1, + c_1___1_, + c____1__, + c___1___, + c__1____, + c_1___1_, + c1___1_1, + c_____1_ }, /* % */ + + { c_11____, + c1__1___, + c1___1__, + c_1_1___, + c__1____, + c_1_1__1, + c1___11_, + c1___11_, + c_111__1 }, /* & */ + + { c___11__, + c___11__, + c___1___, + c__1____, + c_______, + c_______, + c_______, + c_______, + c_______ }, /* ' */ + + { c____1__, + c___1___, + c__1____, + c__1____, + c__1____, + c__1____, + c__1____, + c___1___, + c____1__ }, /* ( */ + + { c__1____, + c___1___, + c____1__, + c____1__, + c____1__, + c____1__, + c____1__, + c___1___, + c__1____ }, /* ) */ + + { c_______, + c___1___, + c1__1__1, + c_1_1_1_, + c__111__, + c_1_1_1_, + c1__1__1, + c___1___, + c_______ }, /* * */ + + { c_______, + c___1___, + c___1___, + c___1___, + c1111111, + c___1___, + c___1___, + c___1___, + c_______ }, /* + */ + + { c_______, + c_______, + c_______, + c_______, + c__11___, + c__11___, + c__1____, + c_1_____, + c_______ }, /* , */ + + { c_______, + c_______, + c_______, + c_______, + c1111111, + c_______, + c_______, + c_______, + c_______ }, /* - */ + + { c_______, + c_______, + c_______, + c_______, + c_______, + c_______, + c_______, + c__11___, + c__11___ }, /* . */ + + { c_______, + c______1, + c_____1_, + c____1__, + c___1___, + c__1____, + c_1_____, + c1______, + c_______ }, /* / */ + + { c_11111_, + c1_____1, + c1____11, + c1___1_1, + c1__1__1, + c1_1___1, + c11____1, + c1_____1, + c_11111_ }, /* 0 */ + + { c___1___, + c__11___, + c_1_1___, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___, + c_11111_ }, /* 1 */ + + { c_11111_, + c1_____1, + c______1, + c_____1_, + c__111__, + c_1_____, + c1______, + c1______, + c1111111 }, /* 2 */ + + { c_11111_, + c1_____1, + c______1, + c______1, + c__1111_, + c______1, + c______1, + c1_____1, + c_11111_ }, /* 3 */ + + { c_____1_, + c____11_, + c___1_1_, + c__1__1_, + c_1___1_, + c1____1_, + c1111111, + c_____1_, + c_____1_ }, /* 4 */ + + { c1111111, + c1______, + c1______, + c11111__, + c_____1_, + c______1, + c______1, + c1____1_, + c_1111__ }, /* 5 */ + + { c__1111_, + c_1_____, + c1______, + c1______, + c1_1111_, + c11____1, + c1_____1, + c1_____1, + c_11111_ }, /* 6 */ + + { c1111111, + c1_____1, + c_____1_, + c____1__, + c___1___, + c__1____, + c__1____, + c__1____, + c__1____ }, /* 7 */ + + { c_11111_, + c1_____1, + c1_____1, + c1_____1, + c_11111_, + c1_____1, + c1_____1, + c1_____1, + c_11111_ }, /* 8 */ + + { c_11111_, + c1_____1, + c1_____1, + c1_____1, + c_111111, + c______1, + c______1, + c1_____1, + c_1111__ }, /* 9 */ + + { c_______, + c_______, + c_______, + c__11___, + c__11___, + c_______, + c_______, + c__11___, + c__11___ }, /* : */ + + + { c__11___, + c__11___, + c_______, + c_______, + c__11___, + c__11___, + c__1____, + c_1_____, + c_______ }, /* ; */ + + { c____1__, + c___1___, + c__1____, + c_1_____, + c1______, + c_1_____, + c__1____, + c___1___, + c____1__ }, /* < */ + + { c_______, + c_______, + c_______, + c1111111, + c_______, + c1111111, + c_______, + c_______, + c_______ }, /* = */ + + { c__1____, + c___1___, + c____1__, + c_____1_, + c______1, + c_____1_, + c____1__, + c___1___, + c__1____ }, /* > */ + + { c__1111_, + c_1____1, + c_1____1, + c______1, + c____11_, + c___1___, + c___1___, + c_______, + c___1___ }, /* ? */ + + { c__1111_, + c_1____1, + c1__11_1, + c1_1_1_1, + c1_1_1_1, + c1_1111_, + c1______, + c_1____1, + c__1111_ }, /* @ */ + + { c__111__, + c_1___1_, + c1_____1, + c1_____1, + c1111111, + c1_____1, + c1_____1, + c1_____1, + c1_____1 }, /* A */ + + { c111111_, + c_1____1, + c_1____1, + c_1____1, + c_11111_, + c_1____1, + c_1____1, + c_1____1, + c111111_ }, /* B */ + + { c__1111_, + c_1____1, + c1______, + c1______, + c1______, + c1______, + c1______, + c_1____1, + c__1111_ }, /* C */ + + { c11111__, + c_1___1_, + c_1____1, + c_1____1, + c_1____1, + c_1____1, + c_1____1, + c_1___1_, + c11111__ }, /* D */ + + { c1111111, + c1______, + c1______, + c1______, + c111111_, + c1______, + c1______, + c1______, + c1111111 }, /* E */ + + { c1111111, + c1______, + c1______, + c1______, + c111111_, + c1______, + c1______, + c1______, + c1______ }, /* F */ + + { c__1111_, + c_1____1, + c1______, + c1______, + c1______, + c1__1111, + c1_____1, + c_1____1, + c__1111_ }, /* G */ + + { c1_____1, + c1_____1, + c1_____1, + c1_____1, + c1111111, + c1_____1, + c1_____1, + c1_____1, + c1_____1 }, /* H */ + + { c_11111_, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___, + c_11111_ }, /* I */ + + { c__11111, + c____1__, + c____1__, + c____1__, + c____1__, + c____1__, + c____1__, + c1___1__, + c_111___ }, /* J */ + + { c1_____1, + c1____1_, + c1___1__, + c1__1___, + c1_1____, + c11_1___, + c1___1__, + c1____1_, + c1_____1 }, /* K */ + + { c1______, + c1______, + c1______, + c1______, + c1______, + c1______, + c1______, + c1______, + c1111111 }, /* L */ + + { c1_____1, + c11___11, + c1_1_1_1, + c1__1__1, + c1_____1, + c1_____1, + c1_____1, + c1_____1, + c1_____1 }, /* M */ + + { c1_____1, + c11____1, + c1_1___1, + c1__1__1, + c1___1_1, + c1____11, + c1_____1, + c1_____1, + c1_____1 }, /* N */ + + { c__111__, + c_1___1_, + c1_____1, + c1_____1, + c1_____1, + c1_____1, + c1_____1, + c_1___1_, + c__111__ }, /* O */ + + { c111111_, + c1_____1, + c1_____1, + c1_____1, + c111111_, + c1______, + c1______, + c1______, + c1______ }, /* P */ + + { c__111__, + c_1___1_, + c1_____1, + c1_____1, + c1_____1, + c1__1__1, + c1___1_1, + c_1___1_, + c__111_1 }, /* Q */ + + { c111111_, + c1_____1, + c1_____1, + c1_____1, + c111111_, + c1__1___, + c1___1__, + c1____1_, + c1_____1 }, /* R */ + + { c_11111_, + c1_____1, + c1______, + c1______, + c_11111_, + c______1, + c______1, + c1_____1, + c_11111_ }, /* S */ + + { c1111111, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___ }, /* T */ + + { c1_____1, + c1_____1, + c1_____1, + c1_____1, + c1_____1, + c1_____1, + c1_____1, + c1_____1, + c_11111_ }, /* U */ + + { c1_____1, + c1_____1, + c1_____1, + c_1___1_, + c_1___1_, + c__1_1__, + c__1_1__, + c___1___, + c___1___ }, /* V */ + + { c1_____1, + c1_____1, + c1_____1, + c1_____1, + c1__1__1, + c1__1__1, + c1_1_1_1, + c11___11, + c1_____1 }, /* W */ + + { c1_____1, + c1_____1, + c_1___1_, + c__1_1__, + c___1___, + c__1_1__, + c_1___1_, + c1_____1, + c1_____1 }, /* X */ + + { c1_____1, + c1_____1, + c_1___1_, + c__1_1__, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___ }, /* Y */ + + { c1111111, + c______1, + c_____1_, + c____1__, + c___1___, + c__1____, + c_1_____, + c1______, + c1111111 }, /* Z */ + + { c_1111__, + c_1_____, + c_1_____, + c_1_____, + c_1_____, + c_1_____, + c_1_____, + c_1_____, + c_1111__ }, /* [ */ + + { c_______, + c1______, + c_1_____, + c__1____, + c___1___, + c____1__, + c_____1_, + c______1, + c_______ }, /* \ */ + + { c__1111_, + c_____1_, + c_____1_, + c_____1_, + c_____1_, + c_____1_, + c_____1_, + c_____1_, + c__1111_ }, /* ] */ + + { c___1___, + c__1_1__, + c_1___1_, + c1_____1, + c_______, + c_______, + c_______, + c_______ }, /* ^ */ + + { c_______, + c_______, + c_______, + c_______, + c_______, + c_______, + c_______, + c1111111, + c_______ }, /* _ */ + + { c__11___, + c__11___, + c___1___, + c____1__, + c_______, + c_______, + c_______, + c_______, + c_______ }, /* ` */ + + { c_______, + c_______, + c_______, + c_1111__, + c_____1_, + c_11111_, + c1_____1, + c1____11, + c_1111_1 }, /* a */ + + { c1______, + c1______, + c1______, + c1_111__, + c11___1_, + c1_____1, + c1_____1, + c11___1_, + c1_111__ }, /* b */ + + { c_______, + c_______, + c_______, + c_1111__, + c1____1_, + c1______, + c1______, + c1____1_, + c_1111__ }, /* c */ + + { c_____1_, + c_____1_, + c_____1_, + c_111_1_, + c1___11_, + c1____1_, + c1____1_, + c1___11_, + c_111_1_ }, /* d */ + + { c_______, + c_______, + c_______, + c_1111__, + c1____1_, + c111111_, + c1______, + c1____1_, + c_1111__ }, /* e */ + + { c___11__, + c__1__1_, + c__1____, + c__1____, + c11111__, + c__1____, + c__1____, + c__1____, + c__1____ }, /* f */ + + { c_111_1_, + c1___11_, + c1____1_, + c1____1_, + c1___11_, + c_111_1_, + c_____1_, + c1____1_, + c_1111__ }, /* g */ + + { c1______, + c1______, + c1______, + c1_111__, + c11___1_, + c1____1_, + c1____1_, + c1____1_, + c1____1_ }, /* h */ + + { c_______, + c___1___, + c_______, + c__11___, + c___1___, + c___1___, + c___1___, + c___1___, + c__111__ }, /* i */ + + { c____11_, + c_____1_, + c_____1_, + c_____1_, + c_____1_, + c_____1_, + c_____1_, + c_1___1_, + c__111__ }, /* j */ + + { c1______, + c1______, + c1______, + c1___1__, + c1__1___, + c1_1____, + c11_1___, + c1___1__, + c1____1_ }, /* k */ + + { c__11___, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___, + c__111__ }, /* l */ + + { c_______, + c_______, + c_______, + c1_1_11_, + c11_1__1, + c1__1__1, + c1__1__1, + c1__1__1, + c1__1__1 }, /* m */ + + { c_______, + c_______, + c_______, + c1_111__, + c11___1_, + c1____1_, + c1____1_, + c1____1_, + c1____1_ }, /* n */ + + { c_______, + c_______, + c_______, + c_1111__, + c1____1_, + c1____1_, + c1____1_, + c1____1_, + c_1111__ }, /* o */ + + { c1_111__, + c11___1_, + c1____1_, + c1____1_, + c11___1_, + c1_111__, + c1______, + c1______, + c1______ }, /* p */ + + { c_111_1_, + c1___11_, + c1____1_, + c1____1_, + c1___11_, + c_111_1_, + c_____1_, + c_____1_, + c_____1_ }, /* q */ + + { c_______, + c_______, + c_______, + c1_111__, + c11___1_, + c1______, + c1______, + c1______, + c1______ }, /* r */ + + { c_______, + c_______, + c_______, + c_1111__, + c1____1_, + c_11____, + c___11__, + c1____1_, + c_1111__ }, /* s */ + + { c_______, + c__1____, + c__1____, + c11111__, + c__1____, + c__1____, + c__1____, + c__1__1_, + c___11__ }, /* t */ + + { c_______, + c_______, + c_______, + c1____1_, + c1____1_, + c1____1_, + c1____1_, + c1___11_, + c_111_1_ }, /* u */ + + { c_______, + c_______, + c_______, + c1_____1, + c1_____1, + c1_____1, + c_1___1_, + c__1_1__, + c___1___ }, /* v */ + + { c_______, + c_______, + c_______, + c1_____1, + c1__1__1, + c1__1__1, + c1__1__1, + c1__1__1, + c_11_11_ }, /* w */ + + { c_______, + c_______, + c_______, + c1____1_, + c_1__1__, + c__11___, + c__11___, + c_1__1__, + c1____1_ }, /* x */ + + { c1____1_, + c1____1_, + c1____1_, + c1____1_, + c1___11_, + c_111_1_, + c_____1_, + c1____1_, + c_1111__ }, /* y */ + + { c_______, + c_______, + c_______, + c111111_, + c____1__, + c___1___, + c__1____, + c_1_____, + c111111_ }, /* z */ + + { c___11__, + c__1____, + c__1____, + c__1____, + c_1_____, + c__1____, + c__1____, + c__1____, + c___11__ }, /* } */ + + { c___1___, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___, + c___1___ }, /* | */ + + { c__11___, + c____1__, + c____1__, + c____1__, + c_____1_, + c____1__, + c____1__, + c____1__, + c__11___ }, /* } */ + + { c_11____, + c1__1__1, + c____11_, + c_______, + c_______, + c_______, + c_______, + c_______, + c_______ }, /* ~ */ + + { c_1__1__, + c1__1__1, + c__1__1_, + c_1__1__, + c1__1__1, + c__1__1_, + c_1__1__, + c1__1__1, + c__1__1_ } /* rub-out */ +}; diff --git a/usr.sbin/lpr/lpd/modes.c b/usr.sbin/lpr/lpd/modes.c new file mode 100644 index 0000000..4bb2ea0 --- /dev/null +++ b/usr.sbin/lpr/lpd/modes.c @@ -0,0 +1,236 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +/* +static char sccsid[] = "@(#)modes.c 8.3 (Berkeley) 4/2/94"; +*/ +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <stddef.h> +#include <string.h> +#include <termios.h> +#include "lp.local.h" +#include "extern.h" + +struct modes { + char *name; + long set; + long unset; +}; + +/* + * The code in optlist() depends on minus options following regular + * options, i.e. "foo" must immediately precede "-foo". + */ +struct modes cmodes[] = { + { "cs5", CS5, CSIZE }, + { "cs6", CS6, CSIZE }, + { "cs7", CS7, CSIZE }, + { "cs8", CS8, CSIZE }, + { "cstopb", CSTOPB, 0 }, + { "-cstopb", 0, CSTOPB }, + { "cread", CREAD, 0 }, + { "-cread", 0, CREAD }, + { "parenb", PARENB, 0 }, + { "-parenb", 0, PARENB }, + { "parodd", PARODD, 0 }, + { "-parodd", 0, PARODD }, + { "parity", PARENB | CS7, PARODD | CSIZE }, + { "-parity", CS8, PARODD | PARENB | CSIZE }, + { "evenp", PARENB | CS7, PARODD | CSIZE }, + { "-evenp", CS8, PARODD | PARENB | CSIZE }, + { "oddp", PARENB | CS7 | PARODD, CSIZE }, + { "-oddp", CS8, PARODD | PARENB | CSIZE }, + { "pass8", CS8, PARODD | PARENB | CSIZE }, + { "-pass8", PARENB | CS7, PARODD | CSIZE }, + { "hupcl", HUPCL, 0 }, + { "-hupcl", 0, HUPCL }, + { "hup", HUPCL, 0 }, + { "-hup", 0, HUPCL }, + { "clocal", CLOCAL, 0 }, + { "-clocal", 0, CLOCAL }, + { "crtscts", CRTSCTS, 0 }, + { "-crtscts", 0, CRTSCTS }, + { "ctsflow", CCTS_OFLOW, 0 }, + { "-ctsflow", 0, CCTS_OFLOW }, + { "dsrflow", CDSR_OFLOW, 0 }, + { "-dsrflow", 0, CDSR_OFLOW }, + { "dtrflow", CDTR_IFLOW, 0 }, + { "-dtrflow", 0, CDTR_IFLOW }, + { "rtsflow", CRTS_IFLOW, 0 }, + { "-rtsflow", 0, CRTS_IFLOW }, + { "mdmbuf", MDMBUF, 0 }, + { "-mdmbuf", 0, MDMBUF }, + { NULL }, +}; + +struct modes imodes[] = { + { "ignbrk", IGNBRK, 0 }, + { "-ignbrk", 0, IGNBRK }, + { "brkint", BRKINT, 0 }, + { "-brkint", 0, BRKINT }, + { "ignpar", IGNPAR, 0 }, + { "-ignpar", 0, IGNPAR }, + { "parmrk", PARMRK, 0 }, + { "-parmrk", 0, PARMRK }, + { "inpck", INPCK, 0 }, + { "-inpck", 0, INPCK }, + { "istrip", ISTRIP, 0 }, + { "-istrip", 0, ISTRIP }, + { "inlcr", INLCR, 0 }, + { "-inlcr", 0, INLCR }, + { "igncr", IGNCR, 0 }, + { "-igncr", 0, IGNCR }, + { "icrnl", ICRNL, 0 }, + { "-icrnl", 0, ICRNL }, + { "ixon", IXON, 0 }, + { "-ixon", 0, IXON }, + { "flow", IXON, 0 }, + { "-flow", 0, IXON }, + { "ixoff", IXOFF, 0 }, + { "-ixoff", 0, IXOFF }, + { "tandem", IXOFF, 0 }, + { "-tandem", 0, IXOFF }, + { "ixany", IXANY, 0 }, + { "-ixany", 0, IXANY }, + { "decctlq", 0, IXANY }, + { "-decctlq", IXANY, 0 }, + { "imaxbel", IMAXBEL, 0 }, + { "-imaxbel", 0, IMAXBEL }, + { NULL }, +}; + +struct modes lmodes[] = { + { "echo", ECHO, 0 }, + { "-echo", 0, ECHO }, + { "echoe", ECHOE, 0 }, + { "-echoe", 0, ECHOE }, + { "crterase", ECHOE, 0 }, + { "-crterase", 0, ECHOE }, + { "crtbs", ECHOE, 0 }, /* crtbs not supported, close enough */ + { "-crtbs", 0, ECHOE }, + { "echok", ECHOK, 0 }, + { "-echok", 0, ECHOK }, + { "echoke", ECHOKE, 0 }, + { "-echoke", 0, ECHOKE }, + { "crtkill", ECHOKE, 0 }, + { "-crtkill", 0, ECHOKE }, + { "altwerase", ALTWERASE, 0 }, + { "-altwerase", 0, ALTWERASE }, + { "iexten", IEXTEN, 0 }, + { "-iexten", 0, IEXTEN }, + { "echonl", ECHONL, 0 }, + { "-echonl", 0, ECHONL }, + { "echoctl", ECHOCTL, 0 }, + { "-echoctl", 0, ECHOCTL }, + { "ctlecho", ECHOCTL, 0 }, + { "-ctlecho", 0, ECHOCTL }, + { "echoprt", ECHOPRT, 0 }, + { "-echoprt", 0, ECHOPRT }, + { "prterase", ECHOPRT, 0 }, + { "-prterase", 0, ECHOPRT }, + { "isig", ISIG, 0 }, + { "-isig", 0, ISIG }, + { "icanon", ICANON, 0 }, + { "-icanon", 0, ICANON }, + { "noflsh", NOFLSH, 0 }, + { "-noflsh", 0, NOFLSH }, + { "tostop", TOSTOP, 0 }, + { "-tostop", 0, TOSTOP }, + { "flusho", FLUSHO, 0 }, + { "-flusho", 0, FLUSHO }, + { "pendin", PENDIN, 0 }, + { "-pendin", 0, PENDIN }, + { "crt", ECHOE|ECHOKE|ECHOCTL, ECHOK|ECHOPRT }, + { "-crt", ECHOK, ECHOE|ECHOKE|ECHOCTL }, + { "newcrt", ECHOE|ECHOKE|ECHOCTL, ECHOK|ECHOPRT }, + { "-newcrt", ECHOK, ECHOE|ECHOKE|ECHOCTL }, + { "nokerninfo", NOKERNINFO, 0 }, + { "-nokerninfo",0, NOKERNINFO }, + { "kerninfo", 0, NOKERNINFO }, + { "-kerninfo", NOKERNINFO, 0 }, + { NULL }, +}; + +struct modes omodes[] = { + { "opost", OPOST, 0 }, + { "-opost", 0, OPOST }, + { "litout", 0, OPOST }, + { "-litout", OPOST, 0 }, + { "onlcr", ONLCR, 0 }, + { "-onlcr", 0, ONLCR }, + { "tabs", 0, OXTABS }, /* "preserve" tabs */ + { "-tabs", OXTABS, 0 }, + { "oxtabs", OXTABS, 0 }, + { "-oxtabs", 0, OXTABS }, + { NULL }, +}; + +#define CHK(name, s) (*name == s[0] && !strcmp(name, s)) + +int +msearch(str, ip) + char *str; + struct termios *ip; +{ + struct modes *mp; + + for (mp = cmodes; mp->name; ++mp) + if (CHK(str, mp->name)) { + ip->c_cflag &= ~mp->unset; + ip->c_cflag |= mp->set; + return (1); + } + for (mp = imodes; mp->name; ++mp) + if (CHK(str, mp->name)) { + ip->c_iflag &= ~mp->unset; + ip->c_iflag |= mp->set; + return (1); + } + for (mp = lmodes; mp->name; ++mp) + if (CHK(str, mp->name)) { + ip->c_lflag &= ~mp->unset; + ip->c_lflag |= mp->set; + return (1); + } + for (mp = omodes; mp->name; ++mp) + if (CHK(str, mp->name)) { + ip->c_oflag &= ~mp->unset; + ip->c_oflag |= mp->set; + return (1); + } + return (0); +} diff --git a/usr.sbin/lpr/lpd/printjob.c b/usr.sbin/lpr/lpd/printjob.c new file mode 100644 index 0000000..7fe4f04 --- /dev/null +++ b/usr.sbin/lpr/lpd/printjob.c @@ -0,0 +1,1694 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +/* +static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95"; +*/ +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + + +/* + * printjob -- print jobs in the queue. + * + * NOTE: the lock file is used to pass information to lpq and lprm. + * it does not need to be removed because file locks are dynamic. + */ + +#include <sys/param.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <pwd.h> +#include <unistd.h> +#include <signal.h> +#include <syslog.h> +#include <fcntl.h> +#include <dirent.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <termios.h> +#include <time.h> +#include "lp.h" +#include "lp.local.h" +#include "pathnames.h" +#include "extern.h" + +#define DORETURN 0 /* absorb fork error */ +#define DOABORT 1 /* abort if dofork fails */ + +/* + * Error tokens + */ +#define REPRINT -2 +#define ERROR -1 +#define OK 0 +#define FATALERR 1 +#define NOACCT 2 +#define FILTERERR 3 +#define ACCESS 4 + +static dev_t fdev; /* device of file pointed to by symlink */ +static ino_t fino; /* inode of file pointed to by symlink */ +static FILE *cfp; /* control file */ +static int child; /* id of any filters */ +static int job_dfcnt; /* count of datafiles in current user job */ +static int lfd; /* lock file descriptor */ +static int ofd; /* output filter file descriptor */ +static int ofilter; /* id of output filter, if any */ +static int tfd = -1; /* output filter temp file output */ +static int pfd; /* prstatic inter file descriptor */ +static int pid; /* pid of lpd process */ +static int prchild; /* id of pr process */ +static char title[80]; /* ``pr'' title */ +static char locale[80]; /* ``pr'' locale */ + +static char class[32]; /* classification field */ +static char fromhost[MAXHOSTNAMELEN]; /* user's host machine */ + /* indentation size in static characters */ +static char indent[10] = "-i0"; +static char jobname[100]; /* job or file name */ +static char length[10] = "-l"; /* page length in lines */ +static char logname[32]; /* user's login name */ +static char pxlength[10] = "-y"; /* page length in pixels */ +static char pxwidth[10] = "-x"; /* page width in pixels */ +static char tempfile[] = "errsXXXXXX"; /* file name for filter errors */ +static char width[10] = "-w"; /* page width in static characters */ +#define TFILENAME "fltXXXXXX" +static char tfile[] = TFILENAME; /* file name for filter output */ + +static void abortpr __P((int)); +static void alarmhandler __P((int)); +static void banner __P((struct printer *pp, char *name1, char *name2)); +static int dofork __P((const struct printer *pp, int action)); +static int dropit __P((int)); +static void init __P((struct printer *pp)); +static void openpr __P((const struct printer *pp)); +static void opennet __P((const struct printer *pp)); +static void opentty __P((const struct printer *pp)); +static void openrem __P((const struct printer *pp)); +static int print __P((struct printer *pp, int format, char *file)); +static int printit __P((struct printer *pp, char *file)); +static void pstatus __P((const struct printer *, const char *, ...)); +static char response __P((const struct printer *pp)); +static void scan_out __P((struct printer *pp, int scfd, char *scsp, + int dlm)); +static char *scnline __P((int, char *, int)); +static int sendfile __P((struct printer *pp, int type, char *file, + int format)); +static int sendit __P((struct printer *pp, char *file)); +static void sendmail __P((struct printer *pp, char *user, int bombed)); +static void setty __P((const struct printer *pp)); + +void +printjob(pp) + struct printer *pp; +{ + struct stat stb; + register struct queue *q, **qp; + struct queue **queue; + register int i, nitems; + off_t pidoff; + int errcnt, count = 0; + + init(pp); /* set up capabilities */ + (void) write(1, "", 1); /* ack that daemon is started */ + (void) close(2); /* set up log file */ + if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) { + syslog(LOG_ERR, "%s: %m", pp->log_file); + (void) open(_PATH_DEVNULL, O_WRONLY); + } + setgid(getegid()); + pid = getpid(); /* for use with lprm */ + setpgrp(0, pid); + signal(SIGHUP, abortpr); + signal(SIGINT, abortpr); + signal(SIGQUIT, abortpr); + signal(SIGTERM, abortpr); + + (void) mktemp(tempfile); + + /* + * uses short form file names + */ + if (chdir(pp->spool_dir) < 0) { + syslog(LOG_ERR, "%s: %m", pp->spool_dir); + exit(1); + } + if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS)) + exit(0); /* printing disabled */ + lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, + LOCK_FILE_MODE); + if (lfd < 0) { + if (errno == EWOULDBLOCK) /* active daemon present */ + exit(0); + syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); + exit(1); + } + /* turn off non-blocking mode (was turned on for lock effects only) */ + if (fcntl(lfd, F_SETFL, 0) < 0) { + syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); + exit(1); + } + ftruncate(lfd, 0); + /* + * write process id for others to know + */ + sprintf(line, "%u\n", pid); + pidoff = i = strlen(line); + if (write(lfd, line, i) != i) { + syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); + exit(1); + } + /* + * search the spool directory for work and sort by queue order. + */ + if ((nitems = getq(pp, &queue)) < 0) { + syslog(LOG_ERR, "%s: can't scan %s", pp->printer, + pp->spool_dir); + exit(1); + } + if (nitems == 0) /* no work to do */ + exit(0); + if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */ + if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0) + syslog(LOG_ERR, "%s: %s: %m", pp->printer, + pp->lock_file); + } + openpr(pp); /* open printer or remote */ +again: + /* + * we found something to do now do it -- + * write the name of the current control file into the lock file + * so the spool queue program can tell what we're working on + */ + for (qp = queue; nitems--; free((char *) q)) { + q = *qp++; + if (stat(q->q_name, &stb) < 0) + continue; + errcnt = 0; + restart: + (void) lseek(lfd, pidoff, 0); + (void) snprintf(line, sizeof(line), "%s\n", q->q_name); + i = strlen(line); + if (write(lfd, line, i) != i) + syslog(LOG_ERR, "%s: %s: %m", pp->printer, + pp->lock_file); + if (!pp->remote) + i = printit(pp, q->q_name); + else + i = sendit(pp, q->q_name); + /* + * Check to see if we are supposed to stop printing or + * if we are to rebuild the queue. + */ + if (fstat(lfd, &stb) == 0) { + /* stop printing before starting next job? */ + if (stb.st_mode & LFM_PRINT_DIS) + goto done; + /* rebuild queue (after lpc topq) */ + if (stb.st_mode & LFM_RESET_QUE) { + for (free(q); nitems--; free(q)) + q = *qp++; + if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) + < 0) + syslog(LOG_WARNING, "%s: %s: %m", + pp->printer, pp->lock_file); + break; + } + } + if (i == OK) /* file ok and printed */ + count++; + else if (i == REPRINT && ++errcnt < 5) { + /* try reprinting the job */ + syslog(LOG_INFO, "restarting %s", pp->printer); + if (ofilter > 0) { + kill(ofilter, SIGCONT); /* to be sure */ + (void) close(ofd); + while ((i = wait(NULL)) > 0 && i != ofilter) + ; + ofilter = 0; + } + (void) close(pfd); /* close printer */ + if (ftruncate(lfd, pidoff) < 0) + syslog(LOG_WARNING, "%s: %s: %m", + pp->printer, pp->lock_file); + openpr(pp); /* try to reopen printer */ + goto restart; + } else { + syslog(LOG_WARNING, "%s: job could not be %s (%s)", + pp->printer, + pp->remote ? "sent to remote host" : "printed", + q->q_name); + if (i == REPRINT) { + /* ensure we don't attempt this job again */ + (void) unlink(q->q_name); + q->q_name[0] = 'd'; + (void) unlink(q->q_name); + if (logname[0]) + sendmail(pp, logname, FATALERR); + } + } + } + free(queue); + /* + * search the spool directory for more work. + */ + if ((nitems = getq(pp, &queue)) < 0) { + syslog(LOG_ERR, "%s: can't scan %s", pp->printer, + pp->spool_dir); + exit(1); + } + if (nitems == 0) { /* no more work to do */ + done: + if (count > 0) { /* Files actually printed */ + if (!pp->no_formfeed && !pp->tof) + (void) write(ofd, pp->form_feed, + strlen(pp->form_feed)); + if (pp->trailer != NULL) /* output trailer */ + (void) write(ofd, pp->trailer, + strlen(pp->trailer)); + } + (void) close(ofd); + (void) wait(NULL); + (void) unlink(tempfile); + exit(0); + } + goto again; +} + +char fonts[4][50]; /* fonts for troff */ + +char ifonts[4][40] = { + _PATH_VFONTR, + _PATH_VFONTI, + _PATH_VFONTB, + _PATH_VFONTS, +}; + +/* + * The remaining part is the reading of the control file (cf) + * and performing the various actions. + */ +static int +printit(pp, file) + struct printer *pp; + char *file; +{ + register int i; + char *cp; + int bombed = OK; + + /* + * open control file; ignore if no longer there. + */ + if ((cfp = fopen(file, "r")) == NULL) { + syslog(LOG_INFO, "%s: %s: %m", pp->printer, file); + return(OK); + } + /* + * Reset troff fonts. + */ + for (i = 0; i < 4; i++) + strcpy(fonts[i], ifonts[i]); + sprintf(&width[2], "%ld", pp->page_width); + strcpy(indent+2, "0"); + + /* initialize job-specific count of datafiles processed */ + job_dfcnt = 0; + + /* + * read the control file for work to do + * + * file format -- first character in the line is a command + * rest of the line is the argument. + * valid commands are: + * + * S -- "stat info" for symbolic link protection + * J -- "job name" on banner page + * C -- "class name" on banner page + * L -- "literal" user's name to print on banner + * T -- "title" for pr + * H -- "host name" of machine where lpr was done + * P -- "person" user's login name + * I -- "indent" amount to indent output + * R -- laser dpi "resolution" + * f -- "file name" name of text file to print + * l -- "file name" text file with control chars + * p -- "file name" text file to print with pr(1) + * t -- "file name" troff(1) file to print + * n -- "file name" ditroff(1) file to print + * d -- "file name" dvi file to print + * g -- "file name" plot(1G) file to print + * v -- "file name" plain raster file to print + * c -- "file name" cifplot file to print + * 1 -- "R font file" for troff + * 2 -- "I font file" for troff + * 3 -- "B font file" for troff + * 4 -- "S font file" for troff + * N -- "name" of file (used by lpq) + * U -- "unlink" name of file to remove + * (after we print it. (Pass 2 only)). + * M -- "mail" to user when done printing + * Z -- "locale" for pr + * + * getline reads a line and expands tabs to blanks + */ + + /* pass 1 */ + + while (getline(cfp)) + switch (line[0]) { + case 'H': + strncpy(fromhost, line+1, sizeof(fromhost) - 1); + fromhost[sizeof(fromhost) - 1] = '\0'; + if (class[0] == '\0') { + strncpy(class, line+1, sizeof(class) - 1); + class[sizeof(class) - 1] = '\0'; + } + continue; + + case 'P': + strncpy(logname, line+1, sizeof(logname) - 1); + logname[sizeof(logname) - 1] = '\0'; + if (pp->restricted) { /* restricted */ + if (getpwnam(logname) == NULL) { + bombed = NOACCT; + sendmail(pp, line+1, bombed); + goto pass2; + } + } + continue; + + case 'S': + cp = line+1; + i = 0; + while (*cp >= '0' && *cp <= '9') + i = i * 10 + (*cp++ - '0'); + fdev = i; + cp++; + i = 0; + while (*cp >= '0' && *cp <= '9') + i = i * 10 + (*cp++ - '0'); + fino = i; + continue; + + case 'J': + if (line[1] != '\0') { + strncpy(jobname, line+1, sizeof(jobname) - 1); + jobname[sizeof(jobname) - 1] = '\0'; + } else + strcpy(jobname, " "); + continue; + + case 'C': + if (line[1] != '\0') + strncpy(class, line+1, sizeof(class) - 1); + else if (class[0] == '\0') + gethostname(class, sizeof(class)); + class[sizeof(class) - 1] = '\0'; + continue; + + case 'T': /* header title for pr */ + strncpy(title, line+1, sizeof(title) - 1); + title[sizeof(title) - 1] = '\0'; + continue; + + case 'L': /* identification line */ + if (!pp->no_header && !pp->header_last) + banner(pp, line+1, jobname); + continue; + + case '1': /* troff fonts */ + case '2': + case '3': + case '4': + if (line[1] != '\0') { + strncpy(fonts[line[0]-'1'], line+1, + 50-1); + fonts[line[0]-'1'][50-1] = '\0'; + } + continue; + + case 'W': /* page width */ + strncpy(width+2, line+1, sizeof(width) - 3); + width[2+sizeof(width) - 3] = '\0'; + continue; + + case 'I': /* indent amount */ + strncpy(indent+2, line+1, sizeof(indent) - 3); + indent[2+sizeof(indent) - 3] = '\0'; + continue; + + case 'Z': /* locale for pr */ + strncpy(locale, line+1, sizeof(locale) - 1); + locale[sizeof(locale) - 1] = '\0'; + continue; + + default: /* some file to print */ + switch (i = print(pp, line[0], line+1)) { + case ERROR: + if (bombed == OK) + bombed = FATALERR; + break; + case REPRINT: + (void) fclose(cfp); + return(REPRINT); + case FILTERERR: + case ACCESS: + bombed = i; + sendmail(pp, logname, bombed); + } + title[0] = '\0'; + continue; + + case 'N': + case 'U': + case 'M': + case 'R': + continue; + } + + /* pass 2 */ + +pass2: + fseek(cfp, 0L, 0); + while (getline(cfp)) + switch (line[0]) { + case 'L': /* identification line */ + if (!pp->no_header && pp->header_last) + banner(pp, line+1, jobname); + continue; + + case 'M': + if (bombed < NOACCT) /* already sent if >= NOACCT */ + sendmail(pp, line+1, bombed); + continue; + + case 'U': + if (strchr(line+1, '/')) + continue; + (void) unlink(line+1); + } + /* + * clean-up in case another control file exists + */ + (void) fclose(cfp); + (void) unlink(file); + return(bombed == OK ? OK : ERROR); +} + +/* + * Print a file. + * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. + * Return -1 if a non-recoverable error occured, + * 2 if the filter detected some errors (but printed the job anyway), + * 1 if we should try to reprint this job and + * 0 if all is well. + * Note: all filters take stdin as the file, stdout as the printer, + * stderr as the log file, and must not ignore SIGINT. + */ +static int +print(pp, format, file) + struct printer *pp; + int format; + char *file; +{ + register int n, i; + register char *prog; + int fi, fo; + FILE *fp; + char *av[15], buf[BUFSIZ]; + int pid, p[2], stopped = 0; + union wait status; + struct stat stb; + + if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) + return(ERROR); + /* + * Check to see if data file is a symbolic link. If so, it should + * still point to the same file or someone is trying to print + * something he shouldn't. + */ + if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && + (stb.st_dev != fdev || stb.st_ino != fino)) + return(ACCESS); + + job_dfcnt++; /* increment datafile counter for this job */ + + /* everything seems OK, start it up */ + if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */ + (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); + pp->tof = 1; + } + if (pp->filters[LPF_INPUT] == NULL + && (format == 'f' || format == 'l')) { + pp->tof = 0; + while ((n = read(fi, buf, BUFSIZ)) > 0) + if (write(ofd, buf, n) != n) { + (void) close(fi); + return(REPRINT); + } + (void) close(fi); + return(OK); + } + switch (format) { + case 'p': /* print file using 'pr' */ + if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */ + prog = _PATH_PR; + i = 0; + av[i++] = "pr"; + av[i++] = width; + av[i++] = length; + av[i++] = "-h"; + av[i++] = *title ? title : " "; + av[i++] = "-L"; + av[i++] = *locale ? locale : "C"; + av[i++] = "-F"; + av[i] = 0; + fo = ofd; + goto start; + } + pipe(p); + if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */ + dup2(fi, 0); /* file is stdin */ + dup2(p[1], 1); /* pipe is stdout */ + closelog(); + closeallfds(3); + execl(_PATH_PR, "pr", width, length, + "-h", *title ? title : " ", + "-L", *locale ? locale : "C", + "-F", 0); + syslog(LOG_ERR, "cannot execl %s", _PATH_PR); + exit(2); + } + (void) close(p[1]); /* close output side */ + (void) close(fi); + if (prchild < 0) { + prchild = 0; + (void) close(p[0]); + return(ERROR); + } + fi = p[0]; /* use pipe for input */ + case 'f': /* print plain text file */ + prog = pp->filters[LPF_INPUT]; + av[1] = width; + av[2] = length; + av[3] = indent; + n = 4; + break; + case 'l': /* like 'f' but pass control characters */ + prog = pp->filters[LPF_INPUT]; + av[1] = "-c"; + av[2] = width; + av[3] = length; + av[4] = indent; + n = 5; + break; + case 'r': /* print a fortran text file */ + prog = pp->filters[LPF_FORTRAN]; + av[1] = width; + av[2] = length; + n = 3; + break; + case 't': /* print troff output */ + case 'n': /* print ditroff output */ + case 'd': /* print tex output */ + (void) unlink(".railmag"); + if ((fo = creat(".railmag", FILMOD)) < 0) { + syslog(LOG_ERR, "%s: cannot create .railmag", + pp->printer); + (void) unlink(".railmag"); + } else { + for (n = 0; n < 4; n++) { + if (fonts[n][0] != '/') + (void) write(fo, _PATH_VFONT, + sizeof(_PATH_VFONT) - 1); + (void) write(fo, fonts[n], strlen(fonts[n])); + (void) write(fo, "\n", 1); + } + (void) close(fo); + } + prog = (format == 't') ? pp->filters[LPF_TROFF] + : ((format == 'n') ? pp->filters[LPF_DITROFF] + : pp->filters[LPF_DVI]); + av[1] = pxwidth; + av[2] = pxlength; + n = 3; + break; + case 'c': /* print cifplot output */ + prog = pp->filters[LPF_CIFPLOT]; + av[1] = pxwidth; + av[2] = pxlength; + n = 3; + break; + case 'g': /* print plot(1G) output */ + prog = pp->filters[LPF_GRAPH]; + av[1] = pxwidth; + av[2] = pxlength; + n = 3; + break; + case 'v': /* print raster output */ + prog = pp->filters[LPF_RASTER]; + av[1] = pxwidth; + av[2] = pxlength; + n = 3; + break; + default: + (void) close(fi); + syslog(LOG_ERR, "%s: illegal format character '%c'", + pp->printer, format); + return(ERROR); + } + if (prog == NULL) { + (void) close(fi); + syslog(LOG_ERR, + "%s: no filter found in printcap for format character '%c'", + pp->printer, format); + return(ERROR); + } + if ((av[0] = strrchr(prog, '/')) != NULL) + av[0]++; + else + av[0] = prog; + av[n++] = "-n"; + av[n++] = logname; + av[n++] = "-h"; + av[n++] = fromhost; + av[n++] = pp->acct_file; + av[n] = 0; + fo = pfd; + if (ofilter > 0) { /* stop output filter */ + write(ofd, "\031\1", 2); + while ((pid = + wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) + ; + if (status.w_stopval != WSTOPPED) { + (void) close(fi); + syslog(LOG_WARNING, + "%s: output filter died " + "(retcode=%d termsig=%d)", + pp->printer, status.w_retcode, + status.w_termsig); + return(REPRINT); + } + stopped++; + } +start: + if ((child = dofork(pp, DORETURN)) == 0) { /* child */ + dup2(fi, 0); + dup2(fo, 1); + n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); + if (n >= 0) + dup2(n, 2); + closelog(); + closeallfds(3); + execv(prog, av); + syslog(LOG_ERR, "cannot execv %s", prog); + exit(2); + } + (void) close(fi); + if (child < 0) + status.w_retcode = 100; + else + while ((pid = wait((int *)&status)) > 0 && pid != child) + ; + child = 0; + prchild = 0; + if (stopped) { /* restart output filter */ + if (kill(ofilter, SIGCONT) < 0) { + syslog(LOG_ERR, "cannot restart output filter"); + exit(1); + } + } + pp->tof = 0; + + /* Copy filter output to "lf" logfile */ + if ((fp = fopen(tempfile, "r"))) { + while (fgets(buf, sizeof(buf), fp)) + fputs(buf, stderr); + fclose(fp); + } + + if (!WIFEXITED(status)) { + syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", + pp->printer, format, status.w_termsig); + return(ERROR); + } + switch (status.w_retcode) { + case 0: + pp->tof = 1; + return(OK); + case 1: + return(REPRINT); + case 2: + return(ERROR); + default: + syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", + pp->printer, format, status.w_retcode); + return(FILTERERR); + } +} + +/* + * Send the daemon control file (cf) and any data files. + * Return -1 if a non-recoverable error occured, 1 if a recoverable error and + * 0 if all is well. + */ +static int +sendit(pp, file) + struct printer *pp; + char *file; +{ + register int i, err = OK; + char *cp, last[BUFSIZ]; + + /* + * open control file + */ + if ((cfp = fopen(file, "r")) == NULL) + return(OK); + + /* initialize job-specific count of datafiles processed */ + job_dfcnt = 0; + + /* + * read the control file for work to do + * + * file format -- first character in the line is a command + * rest of the line is the argument. + * commands of interest are: + * + * a-z -- "file name" name of file to print + * U -- "unlink" name of file to remove + * (after we print it. (Pass 2 only)). + */ + + /* + * pass 1 + */ + while (getline(cfp)) { + again: + if (line[0] == 'S') { + cp = line+1; + i = 0; + while (*cp >= '0' && *cp <= '9') + i = i * 10 + (*cp++ - '0'); + fdev = i; + cp++; + i = 0; + while (*cp >= '0' && *cp <= '9') + i = i * 10 + (*cp++ - '0'); + fino = i; + } else if (line[0] == 'H') { + strncpy(fromhost, line+1, sizeof(fromhost) - 1); + fromhost[sizeof(fromhost) - 1] = '\0'; + if (class[0] == '\0') { + strncpy(class, line+1, sizeof(class) - 1); + class[sizeof(class) - 1] = '\0'; + } + } else if (line[0] == 'P') { + strncpy(logname, line+1, sizeof(logname) - 1); + if (pp->restricted) { /* restricted */ + if (getpwnam(logname) == NULL) { + sendmail(pp, line+1, NOACCT); + err = ERROR; + break; + } + } + } else if (line[0] == 'I') { + strncpy(indent+2, line+1, sizeof(indent) - 3); + } else if (line[0] >= 'a' && line[0] <= 'z') { + strcpy(last, line); + while ((i = getline(cfp)) != 0) + if (strcmp(last, line)) + break; + switch (sendfile(pp, '\3', last+1, *last)) { + case OK: + if (i) + goto again; + break; + case REPRINT: + (void) fclose(cfp); + return(REPRINT); + case ACCESS: + sendmail(pp, logname, ACCESS); + case ERROR: + err = ERROR; + } + break; + } + } + if (err == OK && sendfile(pp, '\2', file, '\0') > 0) { + (void) fclose(cfp); + return(REPRINT); + } + /* + * pass 2 + */ + fseek(cfp, 0L, 0); + while (getline(cfp)) + if (line[0] == 'U' && !strchr(line+1, '/')) + (void) unlink(line+1); + /* + * clean-up in case another control file exists + */ + (void) fclose(cfp); + (void) unlink(file); + return(err); +} + +/* + * Send a data file to the remote machine and spool it. + * Return positive if we should try resending. + */ +static int +sendfile(pp, type, file, format) + struct printer *pp; + int type; + char *file; + char format; +{ + register int f, i, amt; + struct stat stb; + char buf[BUFSIZ]; + int sizerr, resp, closedpr; + + if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) + return(ERROR); + /* + * Check to see if data file is a symbolic link. If so, it should + * still point to the same file or someone is trying to print something + * he shouldn't. + */ + if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && + (stb.st_dev != fdev || stb.st_ino != fino)) + return(ACCESS); + + job_dfcnt++; /* increment datafile counter for this job */ + + /* everything seems OK, start it up */ + sizerr = 0; + closedpr = 0; + if (type == '\3') { + if (pp->filters[LPF_INPUT]) { + /* + * We're sending something with an ifilter, we have to + * run the ifilter and store the output as a + * temporary file (tfile)... the protocol requires us + * to send the file size + */ + char *av[15]; + int n; + int ifilter; + union wait status; /* XXX */ + + strcpy(tfile,TFILENAME); + if ((tfd = mkstemp(tfile)) == -1) { + syslog(LOG_ERR, "mkstemp: %m"); + return(ERROR); + } + if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL) + av[0] = pp->filters[LPF_INPUT]; + else + av[0]++; + if (format == 'l') + av[n=1] = "-c"; + else + n = 0; + av[++n] = width; + av[++n] = length; + av[++n] = indent; + av[++n] = "-n"; + av[++n] = logname; + av[++n] = "-h"; + av[++n] = fromhost; + av[++n] = pp->acct_file; + av[++n] = 0; + if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */ + dup2(f, 0); + dup2(tfd, 1); + n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, + TEMP_FILE_MODE); + if (n >= 0) + dup2(n, 2); + closelog(); + closeallfds(3); + execv(pp->filters[LPF_INPUT], av); + syslog(LOG_ERR, "cannot execv %s", + pp->filters[LPF_INPUT]); + exit(2); + } + (void) close(f); + if (ifilter < 0) + status.w_retcode = 100; + else + while ((pid = wait((int *)&status)) > 0 && + pid != ifilter) + ; + switch (status.w_retcode) { + case 0: + break; + case 1: + unlink(tfile); + return(REPRINT); + case 2: + unlink(tfile); + return(ERROR); + default: + syslog(LOG_WARNING, "%s: filter '%c' exited" + " (retcode=%d)", + pp->printer, format, status.w_retcode); + unlink(tfile); + return(FILTERERR); + } + if (fstat(tfd, &stb) < 0) /* the size of tfile */ + return(ERROR); + f = tfd; + lseek(f,0,SEEK_SET); + } else if (ofilter) { + /* + * We're sending something with an ofilter, we have to + * store the output as a temporary file (tfile)... the + * protocol requires us to send the file size + */ + int i; + for (i = 0; i < stb.st_size; i += BUFSIZ) { + amt = BUFSIZ; + if (i + amt > stb.st_size) + amt = stb.st_size - i; + if (sizerr == 0 && read(f, buf, amt) != amt) { + sizerr = 1; + break; + } + if (write(ofd, buf, amt) != amt) { + (void) close(f); + return(REPRINT); + } + } + close(ofd); + close(f); + while ((i = wait(NULL)) > 0 && i != ofilter) + ; + ofilter = 0; + if (fstat(tfd, &stb) < 0) { /* the size of tfile */ + openpr(pp); + return(ERROR); + } + f = tfd; + lseek(f,0,SEEK_SET); + closedpr = 1; + } + } + + (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); + amt = strlen(buf); + for (i = 0; ; i++) { + if (write(pfd, buf, amt) != amt || + (resp = response(pp)) < 0 || resp == '\1') { + (void) close(f); + if (tfd != -1 && type == '\3') { + tfd = -1; + unlink(tfile); + if (closedpr) + openpr(pp); + } + return(REPRINT); + } else if (resp == '\0') + break; + if (i == 0) + pstatus(pp, + "no space on remote; waiting for queue to drain"); + if (i == 10) + syslog(LOG_ALERT, "%s: can't send to %s; queue full", + pp->printer, pp->remote_host); + sleep(5 * 60); + } + if (i) + pstatus(pp, "sending to %s", pp->remote_host); + if (type == '\3') + trstat_init(pp, file, job_dfcnt); + for (i = 0; i < stb.st_size; i += BUFSIZ) { + amt = BUFSIZ; + if (i + amt > stb.st_size) + amt = stb.st_size - i; + if (sizerr == 0 && read(f, buf, amt) != amt) + sizerr = 1; + if (write(pfd, buf, amt) != amt) { + (void) close(f); + if (tfd != -1 && type == '\3') { + tfd = -1; + unlink(tfile); + if (closedpr) + openpr(pp); + } + return(REPRINT); + } + } + + (void) close(f); + if (tfd != -1 && type == '\3') { + tfd = -1; + unlink(tfile); + } + if (sizerr) { + syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file); + /* tell recvjob to ignore this file */ + (void) write(pfd, "\1", 1); + if (closedpr) + openpr(pp); + return(ERROR); + } + if (write(pfd, "", 1) != 1 || response(pp)) { + if (closedpr) + openpr(pp); + return(REPRINT); + } + if (closedpr) + openpr(pp); + if (type == '\3') + trstat_write(pp, TR_SENDING, stb.st_size, logname, + pp->remote_host, fromhost); + return(OK); +} + +/* + * Check to make sure there have been no errors and that both programs + * are in sync with eachother. + * Return non-zero if the connection was lost. + */ +static char +response(pp) + const struct printer *pp; +{ + char resp; + + if (read(pfd, &resp, 1) != 1) { + syslog(LOG_INFO, "%s: lost connection", pp->printer); + return(-1); + } + return(resp); +} + +/* + * Banner printing stuff + */ +static void +banner(pp, name1, name2) + struct printer *pp; + char *name1, *name2; +{ + time_t tvec; + + time(&tvec); + if (!pp->no_formfeed && !pp->tof) + (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); + if (pp->short_banner) { /* short banner only */ + if (class[0]) { + (void) write(ofd, class, strlen(class)); + (void) write(ofd, ":", 1); + } + (void) write(ofd, name1, strlen(name1)); + (void) write(ofd, " Job: ", 7); + (void) write(ofd, name2, strlen(name2)); + (void) write(ofd, " Date: ", 8); + (void) write(ofd, ctime(&tvec), 24); + (void) write(ofd, "\n", 1); + } else { /* normal banner */ + (void) write(ofd, "\n\n\n", 3); + scan_out(pp, ofd, name1, '\0'); + (void) write(ofd, "\n\n", 2); + scan_out(pp, ofd, name2, '\0'); + if (class[0]) { + (void) write(ofd,"\n\n\n",3); + scan_out(pp, ofd, class, '\0'); + } + (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); + (void) write(ofd, name2, strlen(name2)); + (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); + (void) write(ofd, ctime(&tvec), 24); + (void) write(ofd, "\n", 1); + } + if (!pp->no_formfeed) + (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); + pp->tof = 1; +} + +static char * +scnline(key, p, c) + register int key; + register char *p; + int c; +{ + register int scnwidth; + + for (scnwidth = WIDTH; --scnwidth;) { + key <<= 1; + *p++ = key & 0200 ? c : BACKGND; + } + return (p); +} + +#define TRC(q) (((q)-' ')&0177) + +static void +scan_out(pp, scfd, scsp, dlm) + struct printer *pp; + int scfd, dlm; + char *scsp; +{ + register char *strp; + register int nchrs, j; + char outbuf[LINELEN+1], *sp, c, cc; + int d, scnhgt; + + for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { + strp = &outbuf[0]; + sp = scsp; + for (nchrs = 0; ; ) { + d = dropit(c = TRC(cc = *sp++)); + if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) + for (j = WIDTH; --j;) + *strp++ = BACKGND; + else + strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc); + if (*sp == dlm || *sp == '\0' || + nchrs++ >= pp->page_width/(WIDTH+1)-1) + break; + *strp++ = BACKGND; + *strp++ = BACKGND; + } + while (*--strp == BACKGND && strp >= outbuf) + ; + strp++; + *strp++ = '\n'; + (void) write(scfd, outbuf, strp-outbuf); + } +} + +static int +dropit(c) + int c; +{ + switch(c) { + + case TRC('_'): + case TRC(';'): + case TRC(','): + case TRC('g'): + case TRC('j'): + case TRC('p'): + case TRC('q'): + case TRC('y'): + return (DROP); + + default: + return (0); + } +} + +/* + * sendmail --- + * tell people about job completion + */ +static void +sendmail(pp, user, bombed) + struct printer *pp; + char *user; + int bombed; +{ + register int i; + int p[2], s; + register char *cp; + struct stat stb; + FILE *fp; + + pipe(p); + if ((s = dofork(pp, DORETURN)) == 0) { /* child */ + dup2(p[0], 0); + closelog(); + closeallfds(3); + if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) + cp++; + else + cp = _PATH_SENDMAIL; + execl(_PATH_SENDMAIL, cp, "-t", 0); + _exit(0); + } else if (s > 0) { /* parent */ + dup2(p[1], 1); + printf("To: %s@%s\n", user, fromhost); + printf("Subject: %s printer job \"%s\"\n", pp->printer, + *jobname ? jobname : "<unknown>"); + printf("Reply-To: root@%s\n\n", host); + printf("Your printer job "); + if (*jobname) + printf("(%s) ", jobname); + + cp = "XXX compiler confusion"; /* XXX shut GCC up */ + switch (bombed) { + case OK: + printf("\ncompleted successfully\n"); + cp = "OK"; + break; + default: + case FATALERR: + printf("\ncould not be printed\n"); + cp = "FATALERR"; + break; + case NOACCT: + printf("\ncould not be printed without an account on %s\n", host); + cp = "NOACCT"; + break; + case FILTERERR: + if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || + (fp = fopen(tempfile, "r")) == NULL) { + printf("\nhad some errors and may not have printed\n"); + break; + } + printf("\nhad the following errors and may not have printed:\n"); + while ((i = getc(fp)) != EOF) + putchar(i); + (void) fclose(fp); + cp = "FILTERERR"; + break; + case ACCESS: + printf("\nwas not printed because it was not linked to the original file\n"); + cp = "ACCESS"; + } + fflush(stdout); + (void) close(1); + } else { + syslog(LOG_WARNING, "unable to send mail to %s: %m", user); + return; + } + (void) close(p[0]); + (void) close(p[1]); + wait(NULL); + syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", + user, *jobname ? jobname : "<unknown>", pp->printer, cp); +} + +/* + * dofork - fork with retries on failure + */ +static int +dofork(pp, action) + const struct printer *pp; + int action; +{ + register int i, pid; + struct passwd *pwd; + + for (i = 0; i < 20; i++) { + if ((pid = fork()) < 0) { + sleep((unsigned)(i*i)); + continue; + } + /* + * Child should run as daemon instead of root + */ + if (pid == 0) { + if ((pwd = getpwuid(pp->daemon_user)) == NULL) { + syslog(LOG_ERR, "Can't lookup default daemon uid (%ld) in password file", + pp->daemon_user); + break; + } + initgroups(pwd->pw_name, pwd->pw_gid); + setgid(pwd->pw_gid); + setuid(pp->daemon_user); + } + return(pid); + } + syslog(LOG_ERR, "can't fork"); + + switch (action) { + case DORETURN: + return (-1); + default: + syslog(LOG_ERR, "bad action (%d) to dofork", action); + /*FALL THRU*/ + case DOABORT: + exit(1); + } + /*NOTREACHED*/ +} + +/* + * Kill child processes to abort current job. + */ +static void +abortpr(signo) + int signo; +{ + (void) unlink(tempfile); + kill(0, SIGINT); + if (ofilter > 0) + kill(ofilter, SIGCONT); + while (wait(NULL) > 0) + ; + if (ofilter > 0 && tfd != -1) + unlink(tfile); + exit(0); +} + +static void +init(pp) + struct printer *pp; +{ + char *s; + + sprintf(&width[2], "%ld", pp->page_width); + sprintf(&length[2], "%ld", pp->page_length); + sprintf(&pxwidth[2], "%ld", pp->page_pwidth); + sprintf(&pxlength[2], "%ld", pp->page_plength); + if ((s = checkremote(pp)) != 0) { + syslog(LOG_WARNING, "%s", s); + free(s); + } +} + +void +startprinting(printer) + const char *printer; +{ + struct printer myprinter, *pp = &myprinter; + int status; + + init_printer(pp); + status = getprintcap(printer, pp); + switch(status) { + case PCAPERR_OSERR: + syslog(LOG_ERR, "can't open printer description file: %m"); + exit(1); + case PCAPERR_NOTFOUND: + syslog(LOG_ERR, "unknown printer: %s", printer); + exit(1); + case PCAPERR_TCLOOP: + fatal(pp, "potential reference loop detected in printcap file"); + default: + break; + } + printjob(pp); +} + +/* + * Acquire line printer or remote connection. + */ +static void +openpr(pp) + const struct printer *pp; +{ + int p[2]; + char *cp; + + if (pp->remote) { + openrem(pp); + } else if (*pp->lp) { + if ((cp = strchr(pp->lp, '@')) != NULL) + opennet(pp); + else + opentty(pp); + } else { + syslog(LOG_ERR, "%s: no line printer device or host name", + pp->printer); + exit(1); + } + + /* + * Start up an output filter, if needed. + */ + if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) { + pipe(p); + if (pp->remote) { + strcpy(tfile, TFILENAME); + tfd = mkstemp(tfile); + } + if ((ofilter = dofork(pp, DOABORT)) == 0) { /* child */ + dup2(p[0], 0); /* pipe is std in */ + /* tfile/printer is stdout */ + dup2(pp->remote ? tfd : pfd, 1); + closelog(); + closeallfds(3); + if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL) + cp = pp->filters[LPF_OUTPUT]; + else + cp++; + execl(pp->filters[LPF_OUTPUT], cp, width, length, 0); + syslog(LOG_ERR, "%s: %s: %m", pp->printer, + pp->filters[LPF_OUTPUT]); + exit(1); + } + (void) close(p[0]); /* close input side */ + ofd = p[1]; /* use pipe for output */ + } else { + ofd = pfd; + ofilter = 0; + } +} + +/* + * Printer connected directly to the network + * or to a terminal server on the net + */ +static void +opennet(pp) + const struct printer *pp; +{ + register int i; + int resp; + u_long port; + char *ep; + void (*savealrm)(int); + + port = strtoul(pp->lp, &ep, 0); + if (*ep != '@' || port > 65535) { + syslog(LOG_ERR, "%s: bad port number: %s", pp->printer, + pp->lp); + exit(1); + } + ep++; + + for (i = 1; ; i = i < 256 ? i << 1 : i) { + resp = -1; + savealrm = signal(SIGALRM, alarmhandler); + alarm(pp->conn_timeout); + pfd = getport(pp, ep, port); + alarm(0); + (void)signal(SIGALRM, savealrm); + if (pfd < 0 && errno == ECONNREFUSED) + resp = 1; + else if (pfd >= 0) { + /* + * need to delay a bit for rs232 lines + * to stabilize in case printer is + * connected via a terminal server + */ + delay(500); + break; + } + if (i == 1) { + if (resp < 0) + pstatus(pp, "waiting for %s to come up", + pp->lp); + else + pstatus(pp, + "waiting for access to printer on %s", + pp->lp); + } + sleep(i); + } + pstatus(pp, "sending to %s port %d", ep, port); +} + +/* + * Printer is connected to an RS232 port on this host + */ +static void +opentty(pp) + const struct printer *pp; +{ + register int i; + + for (i = 1; ; i = i < 32 ? i << 1 : i) { + pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY); + if (pfd >= 0) { + delay(500); + break; + } + if (errno == ENOENT) { + syslog(LOG_ERR, "%s: %m", pp->lp); + exit(1); + } + if (i == 1) + pstatus(pp, + "waiting for %s to become ready (offline?)", + pp->printer); + sleep(i); + } + if (isatty(pfd)) + setty(pp); + pstatus(pp, "%s is ready and printing", pp->printer); +} + +/* + * Printer is on a remote host + */ +static void +openrem(pp) + const struct printer *pp; +{ + register int i; + int resp; + void (*savealrm)(int); + + for (i = 1; ; i = i < 256 ? i << 1 : i) { + resp = -1; + savealrm = signal(SIGALRM, alarmhandler); + alarm(pp->conn_timeout); + pfd = getport(pp, pp->remote_host, 0); + alarm(0); + (void)signal(SIGALRM, savealrm); + if (pfd >= 0) { + if ((writel(pfd, "\2", pp->remote_queue, "\n", + (char *)0) + == 2 + strlen(pp->remote_queue)) + && (resp = response(pp)) == 0) + break; + (void) close(pfd); + } + if (i == 1) { + if (resp < 0) + pstatus(pp, "waiting for %s to come up", + pp->remote_host); + else { + pstatus(pp, + "waiting for queue to be enabled on %s", + pp->remote_host); + i = 256; + } + } + sleep(i); + } + pstatus(pp, "sending to %s", pp->remote_host); +} + +/* + * setup tty lines. + */ +static void +setty(pp) + const struct printer *pp; +{ + struct termios ttybuf; + + if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { + syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer); + exit(1); + } + if (tcgetattr(pfd, &ttybuf) < 0) { + syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer); + exit(1); + } + if (pp->baud_rate > 0) + cfsetspeed(&ttybuf, pp->baud_rate); + if (pp->mode_set) { + char *s = strdup(pp->mode_set), *tmp; + + while ((tmp = strsep(&s, ",")) != NULL) { + (void) msearch(tmp, &ttybuf); + } + } + if (pp->mode_set != 0 || pp->baud_rate > 0) { + if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { + syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer); + } + } +} + +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +static void +#ifdef __STDC__ +pstatus(const struct printer *pp, const char *msg, ...) +#else +pstatus(pp, msg, va_alist) + const struct printer *pp; + char *msg; + va_dcl +#endif +{ + int fd; + char *buf; + va_list ap; +#ifdef __STDC__ + va_start(ap, msg); +#else + va_start(ap); +#endif + + umask(0); + fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); + if (fd < 0) { + syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file); + exit(1); + } + ftruncate(fd, 0); + vasprintf(&buf, msg, ap); + va_end(ap); + writel(fd, buf, "\n", (char *)0); + close(fd); + free(buf); +} + +void +alarmhandler(signo) +{ + /* ignored */ +} diff --git a/usr.sbin/lpr/lpd/recvjob.c b/usr.sbin/lpr/lpd/recvjob.c new file mode 100644 index 0000000..255a5e3 --- /dev/null +++ b/usr.sbin/lpr/lpd/recvjob.c @@ -0,0 +1,418 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)recvjob.c 8.2 (Berkeley) 4/27/95"; +#endif +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +/* + * Receive printer jobs from the network, queue them and + * start the printer daemon. + */ +#include <sys/param.h> +#include <sys/mount.h> +#include <sys/stat.h> + +#include <unistd.h> +#include <signal.h> +#include <fcntl.h> +#include <dirent.h> +#include <syslog.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "lp.h" +#include "lp.local.h" +#include "extern.h" +#include "pathnames.h" + +#define ack() (void) write(1, sp, 1); + +static char dfname[NAME_MAX]; /* data files */ +static int minfree; /* keep at least minfree blocks available */ +static char *sp = ""; +static char tfname[NAME_MAX]; /* tmp copy of cf before linking */ + +static int chksize __P((int)); +static void frecverr __P((const char *, ...)); +static int noresponse __P((void)); +static void rcleanup __P((int)); +static int read_number __P((char *)); +static int readfile __P((struct printer *pp, char *, int)); +static int readjob __P((struct printer *pp)); + + +void +recvjob(printer) + const char *printer; +{ + struct stat stb; + int status; + struct printer myprinter, *pp = &myprinter; + + /* + * Perform lookup for printer name or abbreviation + */ + init_printer(pp); + status = getprintcap(printer, pp); + switch (status) { + case PCAPERR_OSERR: + frecverr("cannot open printer description file"); + break; + case PCAPERR_NOTFOUND: + frecverr("unknown printer %s", printer); + break; + case PCAPERR_TCLOOP: + fatal(pp, "potential reference loop detected in printcap file"); + default: + break; + } + + (void) close(2); /* set up log file */ + if (open(pp->log_file, O_WRONLY|O_APPEND, 0664) < 0) { + syslog(LOG_ERR, "%s: %m", pp->log_file); + (void) open(_PATH_DEVNULL, O_WRONLY); + } + + if (chdir(pp->spool_dir) < 0) + frecverr("%s: %s: %m", pp->printer, pp->spool_dir); + if (stat(pp->lock_file, &stb) == 0) { + if (stb.st_mode & 010) { + /* queue is disabled */ + putchar('\1'); /* return error code */ + exit(1); + } + } else if (stat(pp->spool_dir, &stb) < 0) + frecverr("%s: %s: %m", pp->printer, pp->spool_dir); + minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */ + signal(SIGTERM, rcleanup); + signal(SIGPIPE, rcleanup); + + if (readjob(pp)) + printjob(pp); +} + +/* + * Read printer jobs sent by lpd and copy them to the spooling directory. + * Return the number of jobs successfully transfered. + */ +static int +readjob(pp) + struct printer *pp; +{ + register int size; + register char *cp; + int cfcnt, dfcnt; + char givenid[32], givenhost[MAXHOSTNAMELEN]; + + ack(); + cfcnt = 0; + dfcnt = 0; + for (;;) { + /* + * Read a command to tell us what to do + */ + cp = line; + do { + if ((size = read(1, cp, 1)) != 1) { + if (size < 0) { + frecverr("%s: lost connection", + pp->printer); + /*NOTREACHED*/ + } + return (cfcnt); + } + } while (*cp++ != '\n' && (cp - line + 1) < sizeof(line)); + if (cp - line + 1 >= sizeof(line)) { + frecverr("%s: readjob overflow", pp->printer); + /*NOTREACHED*/ + } + *--cp = '\0'; + cp = line; + switch (*cp++) { + case '\1': /* cleanup because data sent was bad */ + rcleanup(0); + continue; + + case '\2': /* read cf file */ + size = 0; + dfcnt = 0; + while (*cp >= '0' && *cp <= '9') + size = size * 10 + (*cp++ - '0'); + if (*cp++ != ' ') + break; + /* + * host name has been authenticated, we use our + * view of the host name since we may be passed + * something different than what gethostbyaddr() + * returns + */ + strncpy(cp + 6, from, sizeof(line) + line - cp - 7); + line[sizeof(line) - 1 ] = '\0'; + strncpy(tfname, cp, sizeof(tfname) - 1); + tfname[sizeof (tfname) - 1] = '\0'; + tfname[0] = 't'; + if (strchr(tfname, '/')) + frecverr("readjob: %s: illegal path name", + tfname); + if (!chksize(size)) { + (void) write(1, "\2", 1); + continue; + } + if (!readfile(pp, tfname, size)) { + rcleanup(0); + continue; + } + if (link(tfname, cp) < 0) + frecverr("%s: %m", tfname); + (void) unlink(tfname); + tfname[0] = '\0'; + cfcnt++; + continue; + + case '\3': /* read df file */ + *givenid = '\0'; + *givenhost = '\0'; + size = 0; + while (*cp >= '0' && *cp <= '9') + size = size * 10 + (*cp++ - '0'); + if (*cp++ != ' ') + break; + if (!chksize(size)) { + (void) write(1, "\2", 1); + continue; + } + (void) strncpy(dfname, cp, sizeof(dfname) - 1); + dfname[sizeof(dfname) - 1] = '\0'; + if (strchr(dfname, '/')) { + frecverr("readjob: %s: illegal path name", + dfname); + /*NOTREACHED*/ + } + dfcnt++; + trstat_init(pp, dfname, dfcnt); + (void) readfile(pp, dfname, size); + trstat_write(pp, TR_RECVING, size, givenid, from, + givenhost); + continue; + } + frecverr("protocol screwup: %s", line); + /*NOTREACHED*/ + } +} + +/* + * Read files send by lpd and copy them to the spooling directory. + */ +static int +readfile(pp, file, size) + struct printer *pp; + char *file; + int size; +{ + register char *cp; + char buf[BUFSIZ]; + register int i, j, amt; + int fd, err; + + fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD); + if (fd < 0) { + frecverr("%s: readfile: error on open(%s): %m", + pp->printer, file); + /*NOTREACHED*/ + } + ack(); + err = 0; + for (i = 0; i < size; i += BUFSIZ) { + amt = BUFSIZ; + cp = buf; + if (i + amt > size) + amt = size - i; + do { + j = read(1, cp, amt); + if (j <= 0) { + frecverr("%s: lost connection", pp->printer); + /*NOTREACHED*/ + } + amt -= j; + cp += j; + } while (amt > 0); + amt = BUFSIZ; + if (i + amt > size) + amt = size - i; + if (write(fd, buf, amt) != amt) { + err++; + break; + } + } + (void) close(fd); + if (err) { + frecverr("%s: write error on close(%s)", pp->printer, file); + /*NOTREACHED*/ + } + if (noresponse()) { /* file sent had bad data in it */ + if (strchr(file, '/') == NULL) + (void) unlink(file); + return (0); + } + ack(); + return (1); +} + +static int +noresponse() +{ + char resp; + + if (read(1, &resp, 1) != 1) { + frecverr("lost connection in noresponse()"); + /*NOTREACHED*/ + } + if (resp == '\0') + return(0); + return(1); +} + +/* + * Check to see if there is enough space on the disk for size bytes. + * 1 == OK, 0 == Not OK. + */ +static int +chksize(size) + int size; +{ + int spacefree; + struct statfs sfb; + + if (statfs(".", &sfb) < 0) { + syslog(LOG_ERR, "%s: %m", "statfs(\".\")"); + return (1); + } + spacefree = sfb.f_bavail * (sfb.f_bsize / 512); + size = (size + 511) / 512; + if (minfree + size > spacefree) + return(0); + return(1); +} + +static int +read_number(fn) + char *fn; +{ + char lin[80]; + register FILE *fp; + + if ((fp = fopen(fn, "r")) == NULL) + return (0); + if (fgets(lin, 80, fp) == NULL) { + fclose(fp); + return (0); + } + fclose(fp); + return (atoi(lin)); +} + +/* + * Remove all the files associated with the current job being transfered. + */ +static void +rcleanup(signo) + int signo; +{ + if (tfname[0] && strchr(tfname, '/') == NULL) + (void) unlink(tfname); + if (dfname[0] && strchr(dfname, '/') == NULL) { + do { + do + (void) unlink(dfname); + while (dfname[2]-- != 'A'); + dfname[2] = 'z'; + } while (dfname[0]-- != 'd'); + } + dfname[0] = '\0'; +} + +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +static void +#ifdef __STDC__ +frecverr(const char *msg, ...) +#else +frecverr(msg, va_alist) + char *msg; + va_dcl +#endif +{ + va_list ap; +#ifdef __STDC__ + va_start(ap, msg); +#else + va_start(ap); +#endif + syslog(LOG_ERR, "Error receiving job from %s:", fromb); + vsyslog(LOG_ERR, msg, ap); + va_end(ap); + /* + * rcleanup is not called until AFTER logging the error message, + * because rcleanup will zap some variables which may have been + * supplied as parameters for that msg... + */ + rcleanup(0); + /* + * Add a minimal delay before returning the final error code to + * the sending host. This just in case that machine responds + * this error by INSTANTLY retrying (and instantly re-failing...). + * It would be stupid of the sending host to do that, but if there + * was a broken implementation which did it, the result might be + * obscure performance problems and a flood of syslog messages on + * the receiving host. + */ + sleep(2); /* a paranoid throttling measure */ + putchar('\1'); /* return error code */ + exit(1); +} diff --git a/usr.sbin/lpr/lpq/Makefile b/usr.sbin/lpr/lpq/Makefile new file mode 100644 index 0000000..24afb7a --- /dev/null +++ b/usr.sbin/lpr/lpq/Makefile @@ -0,0 +1,13 @@ +# From: @(#)Makefile 8.1 (Berkeley) 6/6/93 +# $FreeBSD$ + +PROG= lpq +CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS} +DPADD= ${LIBLPR} +LDADD= ${LIBLPR} + +BINGRP= daemon +BINMODE=6555 +BINDIR= /usr/bin + +.include <bsd.prog.mk> diff --git a/usr.sbin/lpr/lpq/lpq.1 b/usr.sbin/lpr/lpq/lpq.1 new file mode 100644 index 0000000..cff76b24 --- /dev/null +++ b/usr.sbin/lpr/lpq/lpq.1 @@ -0,0 +1,137 @@ +.\" Copyright (c) 1983, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)lpq.1 8.2 (Berkeley) 4/28/95 +.\" $FreeBSD$ +.\" +.Dd April 28, 1995 +.Dt LPQ 1 +.Os BSD 4.2 +.Sh NAME +.Nm lpq +.Nd spool queue examination program +.Sh SYNOPSIS +.Nm lpq +.Op Fl a +.Op Fl l +.Op Fl P Ns Ar printer +.Op job # ... +.Op user ... +.Sh DESCRIPTION +.Nm Lpq +examines the spooling area used by +.Xr lpd 8 +for printing files on the line printer, and reports the status of the +specified jobs or all jobs associated with a user. +.Nm Lpq +invoked +without any arguments reports on any jobs currently in the queue. +.Pp +Options: +.Pp +.Bl -tag -width indent +.It Fl P +Specify a particular printer, otherwise the default +line printer is used (or the value of the +.Ev PRINTER +variable in the +environment). All other arguments supplied are interpreted as user +names or job numbers to filter out only those jobs of interest. +.It Fl l +Information about each of the files comprising the job entry +is printed. +Normally, only as much information as will fit on one line is displayed. +.It Fl a +Report on the local queues for all printers, +rather than just the specified printer. +.El +.Pp +For each job submitted (i.e. invocation of +.Xr lpr 1 ) +.Nm +reports the user's name, current rank in the queue, the +names of files comprising the job, the job identifier (a number which +may be supplied to +.Xr lprm 1 +for removing a specific job), and the total size in bytes. +Job ordering is dependent on +the algorithm used to scan the spooling directory and is supposed +to be +.Tn FIFO +(First in First Out). +File names comprising a job may be unavailable +(when +.Xr lpr 1 +is used as a sink in a pipeline) in which case the file +is indicated as ``(standard input)''. +.Pp +If +.Nm +warns that there is no daemon present (i.e. due to some malfunction), +the +.Xr lpc 8 +command can be used to restart the printer daemon. +.Sh ENVIRONMENT +If the following environment variable exists, it is used by +.Nm lpq : +.Bl -tag -width PRINTER +.It Ev PRINTER +Specifies an alternate default printer. +.El +.Sh FILES +.Bl -tag -width "/var/spool/*/lock" -compact +.It Pa /etc/printcap +To determine printer characteristics. +.It Pa /var/spool/* +The spooling directory, as determined from printcap. +.It Pa /var/spool/*/cf* +Control files specifying jobs. +.It Pa /var/spool/*/lock +The lock file to obtain the currently active job. +.El +.Sh SEE ALSO +.Xr lpr 1 , +.Xr lprm 1 , +.Xr lpc 8 , +.Xr lpd 8 +.Sh HISTORY +.Nm Lpq +appeared in +.Bx 3 . +.Sh BUGS +Due to the dynamic nature of the information in the spooling directory +.Nm +may report unreliably. +Output formatting is sensitive to the line length of the terminal; +this can results in widely spaced columns. +.Sh DIAGNOSTICS +Unable to open various files. The lock file being malformed. Garbage +files when there is no daemon active, but files in the spooling directory. diff --git a/usr.sbin/lpr/lpq/lpq.c b/usr.sbin/lpr/lpq/lpq.c new file mode 100644 index 0000000..67de966 --- /dev/null +++ b/usr.sbin/lpr/lpq/lpq.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +/* +static char sccsid[] = "@(#)lpq.c 8.3 (Berkeley) 5/10/95"; +*/ +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +/* + * Spool Queue examination program + * + * lpq [-a] [-l] [-Pprinter] [user...] [job...] + * + * -a show all non-null queues on the local machine + * -l long output + * -P used to identify printer as per lpr/lprm + */ + +#include <sys/param.h> + +#include <ctype.h> +#include <dirent.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <unistd.h> + +#include "lp.h" +#include "lp.local.h" +#include "pathnames.h" + +int requ[MAXREQUESTS]; /* job number of spool entries */ +int requests; /* # of spool requests */ +char *user[MAXUSERS]; /* users to process */ +int users; /* # of users in user array */ + +uid_t uid, euid; + +static int ckqueue __P((const struct printer *)); +static void usage __P((void)); +int main __P((int, char **)); + +int +main(argc, argv) + int argc; + char **argv; +{ + int ch, aflag, lflag; + char *printer; + struct printer myprinter, *pp = &myprinter; + + printer = NULL; + euid = geteuid(); + uid = getuid(); + seteuid(uid); + name = *argv; + if (gethostname(host, sizeof(host))) + err(1, "gethostname"); + openlog("lpd", 0, LOG_LPR); + + aflag = lflag = 0; + while ((ch = getopt(argc, argv, "alP:")) != -1) + switch((char)ch) { + case 'a': + ++aflag; + break; + case 'l': /* long output */ + ++lflag; + break; + case 'P': /* printer name */ + printer = optarg; + break; + case '?': + default: + usage(); + } + + if (!aflag && printer == NULL && (printer = getenv("PRINTER")) == NULL) + printer = DEFLP; + + for (argc -= optind, argv += optind; argc; --argc, ++argv) + if (isdigit(argv[0][0])) { + if (requests >= MAXREQUESTS) + fatal(0, "too many requests"); + requ[requests++] = atoi(*argv); + } + else { + if (users >= MAXUSERS) + fatal(0, "too many users"); + user[users++] = *argv; + } + + if (aflag) { + int more, status; + + more = firstprinter(pp, &status); + if (status) + goto looperr; + while (more) { + if (ckqueue(pp) > 0) { + printf("%s:\n", pp->printer); + displayq(pp, lflag); + printf("\n"); + } + do { + more = nextprinter(pp, &status); +looperr: + switch (status) { + case PCAPERR_TCOPEN: + printf("warning: %s: unresolved " + "tc= reference(s) ", + pp->printer); + case PCAPERR_SUCCESS: + break; + default: + fatal(pp, pcaperr(status)); + } + } while (more && status); + } + } else { + int status; + + init_printer(pp); + status = getprintcap(printer, pp); + if (status < 0) + fatal(pp, pcaperr(status)); + + displayq(pp, lflag); + } + exit(0); +} + +static int +ckqueue(pp) + const struct printer *pp; +{ + register struct dirent *d; + DIR *dirp; + char *spooldir; + + spooldir = pp->spool_dir; + if ((dirp = opendir(spooldir)) == NULL) + return (-1); + while ((d = readdir(dirp)) != NULL) { + if (d->d_name[0] != 'c' || d->d_name[1] != 'f') + continue; /* daemon control files only */ + closedir(dirp); + return (1); /* found something */ + } + closedir(dirp); + return (0); +} + +static void +usage() +{ + fprintf(stderr, + "usage: lpq [-a] [-l] [-Pprinter] [user ...] [job ...]\n"); + exit(1); +} diff --git a/usr.sbin/lpr/lpr/Makefile b/usr.sbin/lpr/lpr/Makefile new file mode 100644 index 0000000..e82347c --- /dev/null +++ b/usr.sbin/lpr/lpr/Makefile @@ -0,0 +1,15 @@ +# From: @(#)Makefile 8.1 (Berkeley) 6/6/93 +# $FreeBSD$ + +PROG= lpr +CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS} +BINGRP= daemon +BINMODE=6555 +BINDIR= /usr/bin +MAN1= lpr.1 +MAN5= printcap.5 +.PATH: ${.CURDIR}/../common_source +DPADD= ${LIBLPR} +LDADD= ${LIBLPR} + +.include <bsd.prog.mk> diff --git a/usr.sbin/lpr/lpr/lpr.1 b/usr.sbin/lpr/lpr/lpr.1 new file mode 100644 index 0000000..e05290d --- /dev/null +++ b/usr.sbin/lpr/lpr/lpr.1 @@ -0,0 +1,315 @@ +.\" Copyright (c) 1980, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" From @(#)lpr.1 8.1 (Berkeley) 6/6/93 +.\" $FreeBSD$ +.\" " +.Dd June 6, 1993 +.Dt LPR 1 +.Os BSD 4 +.Sh NAME +.Nm lpr +.Nd off line print +.Sh SYNOPSIS +.Nm lpr +.Op Fl P Ns Ar printer +.Op Fl \&# Ns Ar num +.Op Fl C Ar class +.Op Fl J Ar job +.Op Fl L Ar locale +.Op Fl T Ar title +.Op Fl U Ar user +.Op Fl Z Ar daemon-options +.Op Fl i Ar numcols +.Op Fl 1234 Ar font +.Op Fl w Ar num +.Op Fl cdfghlnmprstv +.Op Ar name ... +.Sh DESCRIPTION +.Nm Lpr +uses a spooling daemon to print the named files when facilities +become available. If no names appear, the standard input is assumed. +.Pp +The following single letter options are used to notify the line printer +spooler that the files are not standard text files. +The spooling daemon will +use the appropriate filters to print the data accordingly. +Note that not all spoolers implement filters for all data types, +and some sites may use these types for other purposes than the ones +described here. +.Bl -tag -width indent +.It Fl d +The files are assumed to contain data in +.Tn DVI +format from the +.Tn TeX +typesetting system. +.It Fl f +Use a filter which interprets the first character of each line as a +standard +.Tn FORTRAN +carriage control character. +.It Fl l +Use a filter which allows control characters to be printed and suppresses +page breaks. +.It Fl p +Use +.Xr pr 1 +to format the files. +.El +.Pp +The following options are historical and not directly supported by any +software included in +.Fx . +.Bl -tag -width indent +.It Fl c +The files are assumed to contain data produced by +.Xr cifplot 1 . +.It Fl g +The files are assumed to contain standard plot data as produced by the +.Ux +.Xr plot 3 +routines. +.It Fl n +The files are assumed to contain data from +.Em ditroff +(device independent troff). +.It Fl t +The files are assumed to contain +.Tn C/A/T +phototypesetter commands from ancient versions of +.Ux +.Xr troff 1 . +.It Fl v +The files are assumed to contain a raster image for devices like the +Benson Varian. +.El +.Pp +These options apply to the handling of +the print job: +.Bl -tag -width indent +.It Fl P +Force output to a specific printer. Normally, +the default printer is used (site dependent), or the value of the +environment variable +.Ev PRINTER +is used. +.It Fl h +Suppress the printing of the burst page. +.It Fl m +Send mail upon completion. +.It Fl r +Remove the file upon completion of spooling or upon completion of +printing (with the +.Fl s +option). +.It Fl s +Use symbolic links. Usually files are copied to the spool directory. +The +.Fl s +option will use +.Xr symlink 2 +to link data files rather than trying to copy them so large files can be +printed. This means the files should +not be modified or removed until they have been printed. +.El +.Pp +The remaining options apply to copies, the page display, and headers: +.Bl -tag -width indent +.It Fl \&# Ns Ar num +The quantity +.Ar num +is the number of copies desired of each file named. For example, +.Bd -literal -offset indent +lpr \-#3 foo.c bar.c more.c +.Ed +would result in 3 copies of the file foo.c, followed by 3 copies +of the file bar.c, etc. On the other hand, +.Bd -literal -offset indent +cat foo.c bar.c more.c \&| lpr \-#3 +.Ed +.Pp +will give three copies of the concatenation of the files. +Often +a site will disable this feature to encourage use of a photocopier +instead. +.It Xo +.Fl Ns Oo Cm 1234 Oc Ar font +.Xc +Specifies a +.Ar font +to be mounted on font position +.Ar i . +The daemon +will construct a +.Li .railmag +file referencing +the font pathname. +.It Fl C Ar class +Job classification +to use on the burst page. For example, +.Bd -literal -offset indent +lpr \-C EECS foo.c +.Ed +.Pp +causes the system name (the name returned by +.Xr hostname 1 ) +to be replaced on the burst page by +.Tn EECS , +and the file foo.c to be printed. +.It Fl J Ar job +Job name to print on the burst page. +Normally, the first file's name is used. +.It Fl L Ar locale +Use +.Ar locale +specified as argument instead of one found in environment. +(Only effective when filtering through +.Xr pr 1 +is requested using the +.Fl p +option.) +.It Fl T Ar title +Title name for +.Xr pr 1 , +instead of the file name. +.It Fl U Ar user +User name to print on the burst page, +also for accounting purposes. +This option is only honored if the real user-id is daemon +(or that specified in the printcap file instead of daemon), +and is intended for those instances where print filters wish to requeue jobs. +.It Fl Z Ar daemon-options +Some spoolers, such as +.Tn LPRng , +accept additional per-job options using a +.Ql Z +control line. +When +.Fl Z +is specified, and +.Fl p +.Pq Xr pr 1 +is not requested, the specified +.Ar daemon-options +will be passed to the remote +.Tn LPRng +spooler. +.It Fl i Ar numcols +The output is indented by +.Pq Ar numcols . +.It Fl w Ar num +Uses +.Ar num +as the page width for +.Xr pr 1 . +.El +.Sh ENVIRONMENT +If the following environment variable exists, it is used by +.Nm Ns : +.Bl -tag -width PRINTER +.It Ev PRINTER +Specifies an alternate default printer. +.El +.Sh FILES +.Bl -tag -width /var/spool/output/*/tf* -compact +.It Pa /etc/passwd +Personal identification. +.It Pa /etc/printcap +Printer capabilities data base. +.It Pa /usr/sbin/lpd +Line printer daemons. +.It Pa /var/spool/output/* +Directories used for spooling. +.It Pa /var/spool/output/*/cf* +Daemon control files. +.It Pa /var/spool/output/*/df* +Data files specified in "cf" files. +.It Pa /var/spool/output/*/tf* +Temporary copies of "cf" files. +.El +.Sh SEE ALSO +.Xr lpq 1 , +.Xr lprm 1 , +.Xr pr 1 , +.Xr symlink 2 , +.Xr printcap 5 , +.Xr lpc 8 , +.Xr lpd 8 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3 . +.Sh DIAGNOSTICS +If you try to spool too large a file, it will be truncated. +.Nm Lpr +will object to printing binary files. +If a user other than root prints a file and spooling is disabled, +.Nm +will print a message saying so and will not put jobs in the queue. +If a connection to +.Xr lpd 8 +on the local machine cannot be made, +.Nm +will say that the daemon cannot be started. +Diagnostics may be printed in the daemon's log file +regarding missing spool files by +.Xr lpd 8 . +.Sh BUGS +Fonts for +.Xr troff 1 +and +.Tn TeX +reside on the host with the printer. +It is currently not possible to +use local font libraries. +.Pp +The +.Ql Z +control file line is used for two different purposes; for +standard +.Fx +.Xr lpd 8 , +it specifies a locale to be passed to +.Xr pr 1 . +For +.Tn LPRng +.Xr lpd 8 , +it specifies additional options to be interpreted by the spooler's +input and output filters. +When submitting jobs via +.Nm Ns , +.Fl p +.Fl L Ar locale +is used in the former context, and +.Fl Z Ar daemon-options +is used in the latter. diff --git a/usr.sbin/lpr/lpr/lpr.c b/usr.sbin/lpr/lpr/lpr.c new file mode 100644 index 0000000..f43767c --- /dev/null +++ b/usr.sbin/lpr/lpr/lpr.c @@ -0,0 +1,895 @@ +/* + * Copyright (c) 1983, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1983, 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)from: lpr.c 8.4 (Berkeley) 4/28/95"; +#endif +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +/* + * lpr -- off line print + * + * Allows multiple printers and printers on remote machines by + * using information from a printer data base. + */ + +#include <sys/param.h> +#include <sys/stat.h> + +#include <dirent.h> +#include <fcntl.h> +#include <a.out.h> +#include <err.h> +#include <locale.h> +#include <signal.h> +#include <syslog.h> +#include <pwd.h> +#include <grp.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include "lp.h" +#include "lp.local.h" +#include "pathnames.h" + +static char *cfname; /* daemon control files, linked from tf's */ +static char *class = host; /* class title on header page */ +static char *dfname; /* data files */ +static char *fonts[4]; /* troff font names */ +static char format = 'f'; /* format char for printing files */ +static int hdr = 1; /* print header or not (default is yes) */ +static int iflag; /* indentation wanted */ +static int inchar; /* location to increment char in file names */ +static int indent; /* amount to indent */ +static char *jobname; /* job name on header page */ +static int mailflg; /* send mail */ +static int nact; /* number of jobs to act on */ +static int ncopies = 1; /* # of copies to make */ +static char *person; /* user name */ +static int qflag; /* q job, but don't exec daemon */ +static int rflag; /* remove files upon completion */ +static int sflag; /* symbolic link flag */ +static int tfd; /* control file descriptor */ +static char *tfname; /* tmp copy of cf before linking */ +static char *title; /* pr'ing title */ +static char *locale; /* pr'ing locale */ +static int userid; /* user id */ +static char *Uflag; /* user name specified with -U flag */ +static char *width; /* width for versatec printing */ +static char *Zflag; /* extra filter options for LPRng servers */ + +static struct stat statb; + +static void card __P((int, char *)); +static int checkwriteperm __P((char*, char *)); +static void chkprinter __P((char *printer, struct printer *pp)); +static void cleanup __P((int)); +static void copy __P((const struct printer *, int, char [])); +static char *itoa __P((int)); +static char *linked __P((char *)); +int main __P((int, char **)); +static char *lmktemp __P((const struct printer *pp, char *, int, int)); +static void mktemps __P((const struct printer *pp)); +static int nfile __P((char *)); +static int test __P((char *)); +static void usage __P((void)); + +uid_t uid, euid; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct passwd *pw; + struct group *gptr; + char *arg, *cp, *printer, *p; + char buf[BUFSIZ]; + int c, i, f, errs; + int ret, didlink; + struct stat stb; + struct stat statb1, statb2; + struct printer myprinter, *pp = &myprinter; + + printer = NULL; + euid = geteuid(); + uid = getuid(); + seteuid(uid); + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) + signal(SIGHUP, cleanup); + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, cleanup); + if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) + signal(SIGQUIT, cleanup); + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) + signal(SIGTERM, cleanup); + + name = argv[0]; + gethostname(host, sizeof(host)); + openlog("lpd", 0, LOG_LPR); + + errs = 0; + while ((c = getopt(argc, argv, + ":#:1:2:3:4:C:J:L:P:T:U:Z:cdfghi:lnmprstvw:")) + != -1) + switch (c) { + case '#': /* n copies */ + i = strtol(optarg, &p, 10); + if (*p) + errx(1, "Bad argument to -#, number expected"); + if (i > 0) + ncopies = i; + break; + + case '1': /* troff fonts */ + case '2': + case '3': + case '4': + fonts[optopt - '1'] = optarg; + break; + + case 'C': /* classification spec */ + hdr++; + class = optarg; + break; + + case 'J': /* job name */ + hdr++; + jobname = optarg; + break; + + case 'P': /* specifiy printer name */ + printer = optarg; + break; + + case 'L': /* pr's locale */ + locale = optarg; + break; + + case 'T': /* pr's title line */ + title = optarg; + break; + + case 'U': /* user name */ + hdr++; + Uflag = optarg; + break; + + case 'Z': + Zflag = optarg; + break; + + case 'c': /* print cifplot output */ + case 'd': /* print tex output (dvi files) */ + case 'g': /* print graph(1G) output */ + case 'l': /* literal output */ + case 'n': /* print ditroff output */ + case 't': /* print troff output (cat files) */ + case 'p': /* print using ``pr'' */ + case 'v': /* print vplot output */ + format = optopt; + break; + + case 'f': /* print fortran output */ + format = 'r'; + break; + + case 'h': /* nulifiy header page */ + hdr = 0; + break; + + case 'i': /* indent output */ + iflag++; + indent = strtol(optarg, &p, 10); + if (*p) + errx(1, "Bad argument to -i, number expected"); + break; + + case 'm': /* send mail when done */ + mailflg++; + break; + + case 'q': /* just queue job */ + qflag++; + break; + + case 'r': /* remove file when done */ + rflag++; + break; + + case 's': /* try to link files */ + sflag++; + break; + + case 'w': /* versatec page width */ + width = optarg; + break; + + case ':': /* catch "missing argument" error */ + if (optopt == 'i') { + iflag++; /* -i without args is valid */ + indent = 8; + } else + errs++; + break; + + default: + errs++; + } + argc -= optind; + argv += optind; + if (errs) + usage(); + if (printer == NULL && (printer = getenv("PRINTER")) == NULL) + printer = DEFLP; + chkprinter(printer, pp); + if (pp->no_copies && ncopies > 1) + errx(1, "multiple copies are not allowed"); + if (pp->max_copies > 0 && ncopies > pp->max_copies) + errx(1, "only %ld copies are allowed", pp->max_copies); + /* + * Get the identity of the person doing the lpr using the same + * algorithm as lprm. Actually, not quite -- lprm will override + * the login name with "root" if the user is running as root; + * the daemon actually checks for the string "root" in its + * permission checking. Sigh. + */ + userid = getuid(); + if (Uflag) { + if (userid != 0 && userid != pp->daemon_user) + errx(1, "only privileged users may use the `-U' flag"); + person = Uflag; + } else { + person = getlogin(); + if (userid != pp->daemon_user || person == 0) { + if ((pw = getpwuid(userid)) == NULL) + errx(1, "Who are you?"); + person = pw->pw_name; + } + } + + /* + * Check for restricted group access. + */ + if (pp->restrict_grp != NULL && userid != pp->daemon_user) { + if ((gptr = getgrnam(pp->restrict_grp)) == NULL) + errx(1, "Restricted group specified incorrectly"); + if (gptr->gr_gid != getgid()) { + while (*gptr->gr_mem != NULL) { + if ((strcmp(person, *gptr->gr_mem)) == 0) + break; + gptr->gr_mem++; + } + if (*gptr->gr_mem == NULL) + errx(1, "Not a member of the restricted group"); + } + } + /* + * Check to make sure queuing is enabled if userid is not root. + */ + lock_file_name(pp, buf, sizeof buf); + if (userid && stat(buf, &stb) == 0 && (stb.st_mode & LFM_QUEUE_DIS)) + errx(1, "Printer queue is disabled"); + /* + * Initialize the control file. + */ + mktemps(pp); + tfd = nfile(tfname); + seteuid(euid); + (void) fchown(tfd, pp->daemon_user, -1); + /* owned by daemon for protection */ + seteuid(uid); + card('H', host); + card('P', person); + card('C', class); + if (hdr && !pp->no_header) { + if (jobname == NULL) { + if (argc == 0) + jobname = "stdin"; + else + jobname = ((arg = strrchr(argv[0], '/')) + ? arg + 1 : argv[0]); + } + card('J', jobname); + card('L', person); + } + if (format != 'p' && Zflag != 0) + card('Z', Zflag); + if (iflag) + card('I', itoa(indent)); + if (mailflg) + card('M', person); + if (format == 't' || format == 'n' || format == 'd') + for (i = 0; i < 4; i++) + if (fonts[i] != NULL) + card('1'+i, fonts[i]); + if (width != NULL) + card('W', width); + /* + * XXX + * Our use of `Z' here is incompatible with LPRng's + * use. We assume that the only use of our existing + * `Z' card is as shown for `p' format (pr) files. + */ + if (format == 'p') { + char *s; + + if (locale) + card('Z', locale); + else if ((s = setlocale(LC_TIME, "")) != NULL) + card('Z', s); + } + + /* + * Read the files and spool them. + */ + if (argc == 0) + copy(pp, 0, " "); + else while (argc--) { + if (argv[0][0] == '-' && argv[0][1] == '\0') { + /* use stdin */ + copy(pp, 0, " "); + argv++; + continue; + } + if ((f = test(arg = *argv++)) < 0) + continue; /* file unreasonable */ + + if (sflag && (cp = linked(arg)) != NULL) { + (void) snprintf(buf, sizeof(buf), "%d %d", statb.st_dev, + statb.st_ino); + card('S', buf); + if (format == 'p') + card('T', title ? title : arg); + for (i = 0; i < ncopies; i++) + card(format, &dfname[inchar-2]); + card('U', &dfname[inchar-2]); + if (f) + card('U', cp); + card('N', arg); + dfname[inchar]++; + nact++; + continue; + } + if (sflag) + printf("%s: %s: not linked, copying instead\n", name, arg); + + if (f) { + /* + * The user wants the file removed after it is copied + * to the spool area, so see if the file can be moved + * instead of copy/unlink'ed. This is much faster and + * uses less spool space than copying the file. This + * can be very significant when running services like + * samba, pcnfs, CAP, et al. + */ + seteuid(euid); + didlink = 0; + /* + * There are several things to check to avoid any + * security issues. Some of these are redundant + * under BSD's, but are necessary when lpr is built + * under some other OS's (which I do do...) + */ + if (lstat(arg, &statb1) < 0) + goto nohardlink; + if (S_ISLNK(statb1.st_mode)) + goto nohardlink; + if (link(arg, dfname) != 0) + goto nohardlink; + didlink = 1; + /* + * Make sure the user hasn't tried to trick us via + * any race conditions + */ + if (lstat(dfname, &statb2) < 0) + goto nohardlink; + if (statb1.st_dev != statb2.st_dev) + goto nohardlink; + if (statb1.st_ino != statb2.st_ino) + goto nohardlink; + /* + * Skip if the file already had multiple hard links, + * because changing the owner and access-bits would + * change ALL versions of the file + */ + if (statb2.st_nlink > 2) + goto nohardlink; + /* + * If we can access and remove the original file + * without special setuid-ness then this method is + * safe. Otherwise, abandon the move and fall back + * to the (usual) copy method. + */ + seteuid(uid); + ret = access(dfname, R_OK); + if (ret == 0) + ret = unlink(arg); + seteuid(euid); + if (ret != 0) + goto nohardlink; + /* + * Unlink of user file was successful. Change the + * owner and permissions, add entries to the control + * file, and skip the file copying step. + */ + chown(dfname, pp->daemon_user, getegid()); + chmod(dfname, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + seteuid(uid); + if (format == 'p') + card('T', title ? title : arg); + for (i = 0; i < ncopies; i++) + card(format, &dfname[inchar-2]); + card('U', &dfname[inchar-2]); + card('N', arg); + nact++; + continue; + nohardlink: + if (didlink) + unlink(dfname); + seteuid(uid); /* restore old uid */ + } /* end: if (f) */ + + if ((i = open(arg, O_RDONLY)) < 0) { + printf("%s: cannot open %s\n", name, arg); + } else { + copy(pp, i, arg); + (void) close(i); + if (f && unlink(arg) < 0) + printf("%s: %s: not removed\n", name, arg); + } + } + + if (nact) { + (void) close(tfd); + tfname[inchar]--; + /* + * Touch the control file to fix position in the queue. + */ + seteuid(euid); + if ((tfd = open(tfname, O_RDWR)) >= 0) { + char c; + + if (read(tfd, &c, 1) == 1 && + lseek(tfd, (off_t)0, 0) == 0 && + write(tfd, &c, 1) != 1) { + printf("%s: cannot touch %s\n", name, tfname); + tfname[inchar]++; + cleanup(0); + } + (void) close(tfd); + } + if (link(tfname, cfname) < 0) { + printf("%s: cannot rename %s\n", name, cfname); + tfname[inchar]++; + cleanup(0); + } + unlink(tfname); + seteuid(uid); + if (qflag) /* just q things up */ + exit(0); + if (!startdaemon(pp)) + printf("jobs queued, but cannot start daemon.\n"); + exit(0); + } + cleanup(0); + return (1); + /* NOTREACHED */ +} + +/* + * Create the file n and copy from file descriptor f. + */ +static void +copy(pp, f, n) + const struct printer *pp; + int f; + char n[]; +{ + register int fd, i, nr, nc; + char buf[BUFSIZ]; + + if (format == 'p') + card('T', title ? title : n); + for (i = 0; i < ncopies; i++) + card(format, &dfname[inchar-2]); + card('U', &dfname[inchar-2]); + card('N', n); + fd = nfile(dfname); + nr = nc = 0; + while ((i = read(f, buf, BUFSIZ)) > 0) { + if (write(fd, buf, i) != i) { + printf("%s: %s: temp file write error\n", name, n); + break; + } + nc += i; + if (nc >= BUFSIZ) { + nc -= BUFSIZ; + nr++; + if (pp->max_blocks > 0 && nr > pp->max_blocks) { + printf("%s: %s: copy file is too large\n", + name, n); + break; + } + } + } + (void) close(fd); + if (nc==0 && nr==0) + printf("%s: %s: empty input file\n", name, f ? n : "stdin"); + else + nact++; +} + +/* + * Try and link the file to dfname. Return a pointer to the full + * path name if successful. + */ +static char * +linked(file) + register char *file; +{ + register char *cp; + static char buf[MAXPATHLEN]; + register int ret; + + if (*file != '/') { + if (getcwd(buf, sizeof(buf)) == NULL) + return(NULL); + while (file[0] == '.') { + switch (file[1]) { + case '/': + file += 2; + continue; + case '.': + if (file[2] == '/') { + if ((cp = strrchr(buf, '/')) != NULL) + *cp = '\0'; + file += 3; + continue; + } + } + break; + } + strncat(buf, "/", sizeof(buf) - strlen(buf) - 1); + strncat(buf, file, sizeof(buf) - strlen(buf) - 1); + file = buf; + } + seteuid(euid); + ret = symlink(file, dfname); + seteuid(uid); + return(ret ? NULL : file); +} + +/* + * Put a line into the control file. + */ +static void +card(c, p2) + register int c; + register char *p2; +{ + char buf[BUFSIZ]; + register char *p1 = buf; + register int len = 2; + + *p1++ = c; + while ((c = *p2++) != '\0' && len < sizeof(buf)) { + *p1++ = (c == '\n') ? ' ' : c; + len++; + } + *p1++ = '\n'; + write(tfd, buf, len); +} + +/* + * Create a new file in the spool directory. + */ +static int +nfile(n) + char *n; +{ + register int f; + int oldumask = umask(0); /* should block signals */ + + seteuid(euid); + f = open(n, O_WRONLY | O_EXCL | O_CREAT, FILMOD); + (void) umask(oldumask); + if (f < 0) { + printf("%s: cannot create %s\n", name, n); + cleanup(0); + } + if (fchown(f, userid, -1) < 0) { + printf("%s: cannot chown %s\n", name, n); + cleanup(0); /* cleanup does exit */ + } + seteuid(uid); + if (++n[inchar] > 'z') { + if (++n[inchar-2] == 't') { + printf("too many files - break up the job\n"); + cleanup(0); + } + n[inchar] = 'A'; + } else if (n[inchar] == '[') + n[inchar] = 'a'; + return(f); +} + +/* + * Cleanup after interrupts and errors. + */ +static void +cleanup(signo) + int signo; +{ + register int i; + + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + i = inchar; + seteuid(euid); + if (tfname) + do + unlink(tfname); + while (tfname[i]-- != 'A'); + if (cfname) + do + unlink(cfname); + while (cfname[i]-- != 'A'); + if (dfname) + do { + do + unlink(dfname); + while (dfname[i]-- != 'A'); + dfname[i] = 'z'; + } while (dfname[i-2]-- != 'd'); + exit(1); +} + +/* + * Test to see if this is a printable file. + * Return -1 if it is not, 0 if its printable, and 1 if + * we should remove it after printing. + */ +static int +test(file) + char *file; +{ + struct exec execb; + char *path; + register int fd; + register char *cp; + + if (access(file, 4) < 0) { + printf("%s: cannot access %s\n", name, file); + return(-1); + } + if (stat(file, &statb) < 0) { + printf("%s: cannot stat %s\n", name, file); + return(-1); + } + if ((statb.st_mode & S_IFMT) == S_IFDIR) { + printf("%s: %s is a directory\n", name, file); + return(-1); + } + if (statb.st_size == 0) { + printf("%s: %s is an empty file\n", name, file); + return(-1); + } + if ((fd = open(file, O_RDONLY)) < 0) { + printf("%s: cannot open %s\n", name, file); + return(-1); + } + /* + * XXX Shall we add a similar test for ELF? + */ + if (read(fd, &execb, sizeof(execb)) == sizeof(execb) && + !N_BADMAG(execb)) { + printf("%s: %s is an executable program", name, file); + goto error1; + } + (void) close(fd); + if (rflag) { + if ((cp = strrchr(file, '/')) == NULL) { + if (checkwriteperm(file,".") == 0) + return(1); + } else { + if (cp == file) { + fd = checkwriteperm(file,"/"); + } else { + path = alloca(strlen(file) + 1); + strcpy(path,file); + *cp = '\0'; + fd = checkwriteperm(path,file); + *cp = '/'; + } + if (fd == 0) + return(1); + } + printf("%s: %s: is not removable by you\n", name, file); + } + return(0); + +error1: + printf(" and is unprintable\n"); + (void) close(fd); + return(-1); +} + +static int +checkwriteperm(file, directory) + char *file, *directory; +{ + struct stat stats; + if (access(directory, W_OK) == 0) { + stat(directory, &stats); + if (stats.st_mode & S_ISVTX) { + stat(file, &stats); + if(stats.st_uid == userid) { + return(0); + } + } else return(0); + } + return(-1); +} + +/* + * itoa - integer to string conversion + */ +static char * +itoa(i) + register int i; +{ + static char b[10] = "########"; + register char *p; + + p = &b[8]; + do + *p-- = i%10 + '0'; + while (i /= 10); + return(++p); +} + +/* + * Perform lookup for printer name or abbreviation -- + */ +static void +chkprinter(s, pp) + char *s; + struct printer *pp; +{ + int status; + + init_printer(pp); + status = getprintcap(s, pp); + switch(status) { + case PCAPERR_OSERR: + case PCAPERR_TCLOOP: + errx(1, "%s: %s", s, pcaperr(status)); + case PCAPERR_NOTFOUND: + errx(1, "%s: unknown printer", s); + case PCAPERR_TCOPEN: + warnx("%s: unresolved tc= reference(s)", s); + } +} + +/* + * Tell the user what we wanna get. + */ +static void +usage() +{ + fprintf(stderr, "%s\n", +"usage: lpr [-Pprinter] [-#num] [-C class] [-J job] [-T title] [-U user]\n" + "\t[-Z daemon-options] [-i[numcols]] [-i[numcols]] [-1234 font]\n" + "\t[-L locale] [-wnum] [-cdfghlnmprstv] [name ...]"); + exit(1); +} + + +/* + * Make the temp files. + */ +static void +mktemps(pp) + const struct printer *pp; +{ + register int len, fd, n; + register char *cp; + char buf[BUFSIZ]; + + (void) snprintf(buf, sizeof(buf), "%s/.seq", pp->spool_dir); + seteuid(euid); + if ((fd = open(buf, O_RDWR|O_CREAT, 0661)) < 0) { + printf("%s: cannot create %s\n", name, buf); + exit(1); + } + if (flock(fd, LOCK_EX)) { + printf("%s: cannot lock %s\n", name, buf); + exit(1); + } + seteuid(uid); + n = 0; + if ((len = read(fd, buf, sizeof(buf))) > 0) { + for (cp = buf; len--; ) { + if (*cp < '0' || *cp > '9') + break; + n = n * 10 + (*cp++ - '0'); + } + } + len = strlen(pp->spool_dir) + strlen(host) + 8; + tfname = lmktemp(pp, "tf", n, len); + cfname = lmktemp(pp, "cf", n, len); + dfname = lmktemp(pp, "df", n, len); + inchar = strlen(pp->spool_dir) + 3; + n = (n + 1) % 1000; + (void) lseek(fd, (off_t)0, 0); + snprintf(buf, sizeof(buf), "%03d\n", n); + (void) write(fd, buf, strlen(buf)); + (void) close(fd); /* unlocks as well */ +} + +/* + * Make a temp file name. + */ +static char * +lmktemp(pp, id, num, len) + const struct printer *pp; + char *id; + int num, len; +{ + register char *s; + + if ((s = malloc(len)) == NULL) + errx(1, "out of memory"); + (void) snprintf(s, len, "%s/%sA%03d%s", pp->spool_dir, id, num, host); + return(s); +} diff --git a/usr.sbin/lpr/lpr/printcap.5 b/usr.sbin/lpr/lpr/printcap.5 new file mode 100644 index 0000000..61850a5 --- /dev/null +++ b/usr.sbin/lpr/lpr/printcap.5 @@ -0,0 +1,398 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)printcap.5 8.2 (Berkeley) 12/11/93 +.\" $FreeBSD$ +.\" +.Dd October 11, 2000 +.Dt PRINTCAP 5 +.Os BSD 4.2 +.Sh NAME +.Nm printcap +.Nd printer capability data base +.Sh SYNOPSIS +.Nm printcap +.Sh DESCRIPTION +The +.Nm Printcap +function +is a simplified version of the +.Xr termcap 5 +data base +used to describe line printers. The spooling system accesses the +.Nm printcap +file every time it is used, allowing dynamic +addition and deletion of printers. Each entry in the data base +is used to describe one printer. This data base may not be +substituted for, as is possible for +.Xr termcap 5 , +because it may allow accounting to be bypassed. +.Pp +The default printer is normally +.Em lp , +though the environment variable +.Ev PRINTER +may be used to override this. Each spooling utility supports an option, +.Fl P Ar printer , +to allow explicit naming of a destination printer. +.Pp +Refer to the +.%T "4.3 BSD Line Printer Spooler Manual" +for a complete discussion on how to setup the database for a given printer. +.Sh CAPABILITIES +Refer to +.Xr termcap 5 +for a description of the file layout. +.Bl -column Namexxx Typexx "/var/spool/lpdxxxxx" +.Sy Name Type Default Description +.It "af str" Ta Dv NULL Ta No "name of accounting file" +.It "br num none if lp is a tty, set the baud rate" +.Pf ( Xr ioctl 2 +call) +.It "cf str" Ta Dv NULL Ta No "cifplot data filter" +.It "ct num 120 TCP connection timeout in seconds" +.It "df str" Ta Dv NULL Ta No "tex data filter" +.Pf ( Tn DVI +format) +.It "ff str" Ta So Li \ef Sc Ta No "string to send for a form feed" +.It "fo bool false print a form feed when device is opened" +.It "gf str" Ta Dv NULL Ta No "graph data filter" +.Pf ( Xr plot 3 +format +.It "hl bool false print the burst header page last" +.It "ic bool false driver supports (non standard) ioctl to indent printout" +.It "if str" Ta Dv NULL Ta No "name of text filter which does accounting" +.It "lf str" Ta Pa /dev/console Ta No "error logging file name" +.It "lo str" Ta Pa lock Ta No "name of lock file" +.It "lp str" Ta Pa /dev/lp Ta No "device name to open for output" +.It "ms str" Ta Dv NULL Ta No "if lp is a tty, a comma-separated, " +.Xr stty 1 +-like list describing the tty modes +.It "mx num 1000 maximum file size (in" +.Dv BUFSIZ +blocks), zero = unlimited +.It "nd str" Ta Dv NULL Ta No "next directory for list of queues (unimplemented)" +.It "nf str" Ta Dv NULL Ta No "ditroff data filter (device independent troff)" +.It "of str" Ta Dv NULL Ta No "name of output filtering program" +.It "pc num 200 price per foot or page in hundredths of cents" +.It "pl num 66 page length (in lines)" +.It "pw num 132 page width (in characters)" +.It "px num 0 page width in pixels (horizontal)" +.It "py num 0 page length in pixels (vertical)" +.It "rf str" Ta Dv NULL Ta No "filter for printing" +.Tn FORTRAN +style text files +.It "rg str" Ta Dv NULL Ta No "restricted group. Only members of group allowed access" +.It "rm str" Ta Dv NULL Ta No "machine name for remote printer" +.It "rp str ``lp'' remote printer name argument" +.It "rs bool false restrict remote users to those with local accounts" +.It "rw bool false open the printer device for reading and writing" +.It "sb bool false short banner (one line only)" +.It "sc bool false suppress multiple copies" +.It "sd str" Ta Pa /var/spool/lpd Ta No "spool directory" +.It "sf bool false suppress form feeds" +.It "sh bool false suppress printing of burst page header" +.It "sr str" Ta Dv NULL Ta No "file name to hold statistics of each datafile as it is received" +.It "ss str" Ta Dv NULL Ta No "file name to hold statistics of each datafile as it is sent" +.It "st str" Ta Pa status Ta No "status file name" +.It "tf str" Ta Dv NULL Ta No "troff data filter (cat phototypesetter)" +.It "tr str" Ta Dv NULL Ta No "trailer string to print when queue empties" +.It "vf str" Ta Dv NULL Ta No "raster image filter" +.El +.Pp +Each two-letter capability has a human-readable alternate name. +.Bl -column "Short form" "Long form" +.Sy "Short form Long form" +.It "af acct.file" +.It "br tty.rate" +.It "cf filt.cifplot" +.It "ct remote.timeout" +.It "df filt.dvi" +.It "du daemon.user" +.It "ff job.formfeed" +.It "fo job.topofform" +.It "gf filt.plot" +.It "hl banner.last" +.It "if filt.input" +.It "lf spool.log" +.It "lo spool.lock" +.It "lp tty.device" +.It "mc max.copies" +.It "ms tty.mode" +.It "mx max.blocks" +.It "nf filt.ditroff" +.It "of filt.output" +.It "pc acct.price" +.It "pl page.length" +.It "pw page.width" +.It "px page.pwidth" +.It "py page.plength" +.It "rf filt.fortran" +.It "rg daemon.restrictgrp" +.It "rm remote.host" +.It "rp remote.queue" +.It "rs daemon.restricted" +.It "rw tty.rw" +.It "sb banner.short" +.It "sc job.no_copies" +.It "sd spool.dir" +.It "sf job.no_formfeed" +.It "sh banner.disable" +.It "sr stat.recv" +.It "ss stat.send" +.It "st spool.status" +.It "tr job.trailer" +.It "vf filt.raster" +.El +.Pp +If the local line printer driver supports indentation, the daemon +must understand how to invoke it. +.Sh FILTERS +The +.Xr lpd 8 +daemon creates a pipeline of +.Em filters +to process files for various printer types. +The filters selected depend on the flags passed to +.Xr lpr 1 . +The pipeline set up is: +.Bd -literal -offset indent +p pr | if regular text + pr(1) +none if regular text +c cf cifplot +d df DVI (tex) +g gf plot(3) +n nf ditroff +f rf Fortran +t tf troff +v vf raster image +.Ed +.Pp +The +.Sy if +filter is invoked with arguments: +.Bd -filled -offset indent +.Cm if +.Op Fl c +.Fl w Ns Ar width +.Fl l Ns Ar length +.Fl i Ns Ar indent +.Fl n Ar login +.Fl h Ar host acct-file +.Ed +.Pp +The +.Fl c +flag is passed only if the +.Fl l +flag (pass control characters literally) +is specified to +.Xr lpr 1 . +The +.Ar Width +function +and +.Ar length +specify the page width and length +(from +.Cm pw +and +.Cm pl +respectively) in characters. +The +.Fl n +and +.Fl h +parameters specify the login name and host name of the owner +of the job respectively. +The +.Ar Acct-file +function +is passed from the +.Cm af +.Nm printcap +entry. +.Pp +If no +.Cm if +is specified, +.Cm of +is used instead, +with the distinction that +.Cm of +is opened only once, +while +.Cm if +is opened for every individual job. +Thus, +.Cm if +is better suited to performing accounting. +The +.Cm of +is only given the +.Ar width +and +.Ar length +flags. +.Pp +All other filters are called as: +.Bd -filled -offset indent +.Nm filter +.Fl x Ns Ar width +.Fl y Ns Ar length +.Fl n Ar login +.Fl h Ar host acct-file +.Ed +.Pp +where +.Ar width +and +.Ar length +are represented in pixels, +specified by the +.Cm px +and +.Cm py +entries respectively. +.Pp +All filters take +.Em stdin +as the file, +.Em stdout +as the printer, +may log either to +.Em stderr +or using +.Xr syslog 3 , +and must not ignore +.Dv SIGINT . +.Sh REMOTE PRINTING +When printing to a remote printer using +.Cm rm , +it is possible to use either +.Cm if +or +.Cm of . +If both are specified, +.Cm of +is ignored. Both filters behave the same except that they are passed +different arguments as above. Specifically, the output filter is +terminated and restarted for each file transmitted. This is necessary +in order to pass the resulting size to the remote +.Xr lpd 8 . +.Pp +If the +.Fl p +flag was passed to +.Xr lpr 1 , +.Xr pr 1 +is not executed locally, but is requested of the remote +.Xr lpd 8 . +Any input filtering via +.Cm if +will therefore happen before +.Xr pr 1 +is executed rather than afterwards. +.Pp +If +.Cm lp +is specified as +.Em port Ns No @ Ns Em machine +(and +.Cm rm +is not in use), printing will be send directly to the given +.Em port +on the given +.Em machine . +.Sh TRANSFER STATISTICS +When a print job is transfered to a remote machine (which might be +another unix box, or may be a network printer), it may be useful +to keep statistics on each transfer. The +.Cm sr +and +.Cm ss +options indicate filenames that lpd should use to store such +statistics. A statistics line is written for each datafile of a +job as the file is successfully transferred. The format of the +line is the same for both the sending and receiving side of a +transfer. +.Pp +Statistics on datafiles being received would be used on a print +server, if you are interested in network performance between a +variety of machines which are sending jobs to that print server. +The print server could collect statistics on the speed of each +print job as it arrived on the server. +.Pp +Statistics on datafiles being sent might be used as a minimal +accounting record, when you want to know who sent which jobs to a +remote printer, when they were sent, and how large (in bytes) the +files were. This will not give include any idea of how many pages +were printed, because there is no standard way to get that information +back from a remote (network) printer in this case. +.Sh LOGGING +Error messages generated by the line printer programs themselves +(that is, the +.Xr lpd 8 +and related programs) +are logged by +.Xr syslog 3 +using the +.Dv LPR +facility. +Messages printed on +.Em stderr +of one of the filters +are sent to the corresponding +.Cm lf +file. +The filters may, of course, use +.Xr syslog 8 +themselves. +.Pp +Error messages sent to the console have a carriage return and a line +feed appended to them, rather than just a line feed. +.Sh SEE ALSO +.Xr lpq 1 , +.Xr lpr 1 , +.Xr lprm 1 , +.Xr hosts.lpd 5 , +.Xr termcap 5 , +.Xr lpc 8 , +.Xr lpd 8 , +.Xr pac 8 +.Rs +.%T "4.3 BSD Line Printer Spooler Manual" +.Re +.Sh HISTORY +The +.Nm +file format appeared in +.Bx 4.2 . diff --git a/usr.sbin/lpr/lprm/Makefile b/usr.sbin/lpr/lprm/Makefile new file mode 100644 index 0000000..abeac25 --- /dev/null +++ b/usr.sbin/lpr/lprm/Makefile @@ -0,0 +1,14 @@ +# From: @(#)Makefile 8.1 (Berkeley) 6/6/93 +# $FreeBSD$ + +PROG= lprm +CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS} +.PATH: ${.CURDIR}/../common_source +DPADD= ${LIBLPR} +LDADD= ${LIBLPR} + +BINGRP= daemon +BINMODE=6555 +BINDIR= /usr/bin + +.include <bsd.prog.mk> diff --git a/usr.sbin/lpr/lprm/lprm.1 b/usr.sbin/lpr/lprm/lprm.1 new file mode 100644 index 0000000..1a17ea6 --- /dev/null +++ b/usr.sbin/lpr/lprm/lprm.1 @@ -0,0 +1,146 @@ +.\" Copyright (c) 1983, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)lprm.1 8.1 (Berkeley) 6/6/93 +.\" $FreeBSD$ +.\" +.Dd June 6, 1993 +.Dt LPRM 1 +.Os BSD 4.2 +.Sh NAME +.Nm lprm +.Nd remove jobs from the line printer spooling queue +.Sh SYNOPSIS +.Nm lprm +.Op Fl P Ns Ar printer +.Op Fl +.Op job # ... +.Op Ar user ... +.Sh DESCRIPTION +.Nm Lprm +will remove a job, or jobs, from a printer's spool queue. +Since the spooling directory is protected from users, using +.Nm +is normally the only method by which a user may remove a job. +The owner of a job is determined by the user's login name +and host name on the machine where the +.Xr lpr 1 +command was invoked. +.Pp +Options and arguments: +.Bl -tag -width indent +.It Fl P Ns Ar printer +Specify the queue associated with a specific +.Ar printer +(otherwise the default printer is used). +.It Fl +If a single +.Sq Fl +is given, +.Nm +will remove all jobs which a user +owns. If the super-user employs this flag, the spool queue will +be emptied entirely. +.It Ar user +Cause +.Nm +to attempt to remove any jobs queued belonging to that user +(or users). This form of invoking +.Nm +is useful only to the super-user. +.It Ar job\ \&# +A user may dequeue an individual job by specifying its job number. +This number may be obtained from the +.Xr lpq 1 +program, e.g. +.Pp +.Bd -literal -offset indent +\&% lpq \-l + +1st:ken [job #013ucbarpa] + (standard input) 100 bytes +% lprm 13 +.Ed +.El +.Pp +If neither arguments or options are given, +.Nm +will delete the currently active job if it is +owned by the user who invoked +.Nm lprm . +.Pp +.Nm Lprm +announces the names of any files it removes and is silent if +there are no jobs in the queue which match the request list. +.Pp +.Nm Lprm +will kill off an active daemon, if necessary, before removing +any spooling files. If a daemon is killed, a new one is +automatically restarted upon completion of file removals. +.Sh ENVIRONMENT +If the following environment variable exists, it is utilized by +.Nm lprm . +.Bl -tag -width PRINTER +.It Ev PRINTER +If the environment variable +.Ev PRINTER +exists, +and a printer has not been specified with the +.Fl P +option, +the default printer is assumed from +.Ev PRINTER . +.El +.Sh FILES +.Bl -tag -width /var/spool/*/lock/ -compact +.It Pa /etc/printcap +Printer characteristics file. +.It Pa /var/spool/* +Spooling directories. +.It Pa /var/spool/*/lock +Lock file used to obtain the pid of the current +daemon and the job number of the currently active job. +.El +.Sh SEE ALSO +.Xr lpq 1 , +.Xr lpr 1 , +.Xr lpd 8 +.Sh DIAGNOSTICS +``Permission denied" if the user tries to remove files other than his +own. +.Sh BUGS +Since there are race conditions possible in the update of the lock file, +the currently active job may be incorrectly identified. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . diff --git a/usr.sbin/lpr/lprm/lprm.c b/usr.sbin/lpr/lprm/lprm.c new file mode 100644 index 0000000..ca52f5d --- /dev/null +++ b/usr.sbin/lpr/lprm/lprm.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)lprm.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +/* + * lprm - remove the current user's spool entry + * + * lprm [-] [[job #] [user] ...] + * + * Using information in the lock file, lprm will kill the + * currently active daemon (if necessary), remove the associated files, + * and startup a new daemon. Priviledged users may remove anyone's spool + * entries, otherwise one can only remove their own. + */ + +#include <sys/param.h> + +#include <syslog.h> +#include <dirent.h> +#include <pwd.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include "lp.h" +#include "lp.local.h" + +/* + * Stuff for handling job specifications + */ +char *person; /* name of person doing lprm */ +int requ[MAXREQUESTS]; /* job number of spool entries */ +int requests; /* # of spool requests */ +char *user[MAXUSERS]; /* users to process */ +int users; /* # of users in user array */ +uid_t uid, euid; /* real and effective user id's */ + +static char luser[16]; /* buffer for person */ + +int main __P((int, char *[])); +static void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + char *arg, *printer; + struct passwd *p; + static char root[] = "root"; + + printer = NULL; + uid = getuid(); + euid = geteuid(); + seteuid(uid); /* be safe */ + name = argv[0]; + gethostname(host, sizeof(host)); + openlog("lpd", 0, LOG_LPR); + + /* + * Bogus code later checks for string equality between + * `person' and "root", so if we are root, better make sure + * that code will succeed. + */ + if (getuid() == 0) { + person = root; + } else if ((person = getlogin()) == NULL) { + if ((p = getpwuid(getuid())) == NULL) + fatal(0, "Who are you?"); + if (strlen(p->pw_name) >= sizeof(luser)) + fatal(0, "Your name is too long"); + strcpy(luser, p->pw_name); + person = luser; + } + while (--argc) { + if ((arg = *++argv)[0] == '-') + switch (arg[1]) { + case 'P': + if (arg[2]) + printer = &arg[2]; + else if (argc > 1) { + argc--; + printer = *++argv; + } + break; + case '\0': + if (!users) { + users = -1; + break; + } + default: + usage(); + } + else { + if (users < 0) + usage(); + if (isdigit(arg[0])) { + if (requests >= MAXREQUESTS) + fatal(0, "Too many requests"); + requ[requests++] = atoi(arg); + } else { + if (users >= MAXUSERS) + fatal(0, "Too many users"); + user[users++] = arg; + } + } + } + if (printer == NULL && (printer = getenv("PRINTER")) == NULL) + printer = DEFLP; + + rmjob(printer); + exit(0); +} + +static void +usage() +{ + fprintf(stderr, "usage: lprm [-] [-Pprinter] [[job #] [user] ...]\n"); + exit(2); +} diff --git a/usr.sbin/lpr/lptest/Makefile b/usr.sbin/lpr/lptest/Makefile new file mode 100644 index 0000000..fe13560 --- /dev/null +++ b/usr.sbin/lpr/lptest/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= lptest + +.include <bsd.prog.mk> diff --git a/usr.sbin/lpr/lptest/lptest.1 b/usr.sbin/lpr/lptest/lptest.1 new file mode 100644 index 0000000..73f9fe9 --- /dev/null +++ b/usr.sbin/lpr/lptest/lptest.1 @@ -0,0 +1,75 @@ +.\" Copyright (c) 1985, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)lptest.1 8.2 (Berkeley) 12/30/93 +.\" $FreeBSD$ +.\" +.Dd December 30, 1993 +.Dt LPTEST 1 +.Os BSD 4.3 +.Sh NAME +.Nm lptest +.Nd generate lineprinter ripple pattern +.Sh SYNOPSIS +.Nm lptest +.Op Ar length +.Op Ar count +.Sh DESCRIPTION +.Nm Lptest +writes the traditional "ripple test" pattern on standard output. +In 96 lines, +this pattern will print all 96 printable +.Tn ASCII +characters +in each position. +While originally created to test printers, it is quite +useful for testing terminals, +driving terminal ports for debugging purposes, +or any other task where a quick supply of random data is needed. +.Pp +The +.Ar length +argument specifies the output line length if the default +length of 79 is inappropriate. +.Pp +The +.Ar count +argument specifies the number of output lines to be generated if +the default count of 200 is inappropriate. +Note that if +.Ar count +is to be specified, +.Ar length +must be also be specified. +.Sh HISTORY +.Nm Lptest +appeared in +.Bx 4.3 . diff --git a/usr.sbin/lpr/lptest/lptest.c b/usr.sbin/lpr/lptest/lptest.c new file mode 100644 index 0000000..1cf2206 --- /dev/null +++ b/usr.sbin/lpr/lptest/lptest.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)lptest.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include <stdlib.h> +#include <stdio.h> + +/* + * lptest -- line printer test program (and other devices). + */ +int +main(argc, argv) + int argc; + char **argv; +{ + int len, count; + register i, j, fc, nc; + char outbuf[BUFSIZ]; + + setbuf(stdout, outbuf); + if (argc >= 2) + len = atoi(argv[1]); + else + len = 79; + if (argc >= 3) + count = atoi(argv[2]); + else + count = 200; + fc = ' '; + for (i = 0; i < count; i++) { + if (++fc == 0177) + fc = ' '; + nc = fc; + for (j = 0; j < len; j++) { + putchar(nc); + if (++nc == 0177) + nc = ' '; + } + putchar('\n'); + } + (void) fflush(stdout); + exit(0); +} diff --git a/usr.sbin/lpr/pac/Makefile b/usr.sbin/lpr/pac/Makefile new file mode 100644 index 0000000..2b8d6ed --- /dev/null +++ b/usr.sbin/lpr/pac/Makefile @@ -0,0 +1,11 @@ +# From: @(#)Makefile 8.1 (Berkeley) 6/6/93 +# $FreeBSD$ + +PROG= pac +CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS} +MAN8= pac.8 +.PATH: ${.CURDIR}/../common_source +DPADD= ${LIBLPR} +LDADD= ${LIBLPR} + +.include <bsd.prog.mk> diff --git a/usr.sbin/lpr/pac/pac.8 b/usr.sbin/lpr/pac/pac.8 new file mode 100644 index 0000000..0fddaec --- /dev/null +++ b/usr.sbin/lpr/pac/pac.8 @@ -0,0 +1,107 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)pac.8 8.1 (Berkeley) 6/6/93 +.\" $FreeBSD$ +.\" +.Dd June 6, 1993 +.Dt PAC 8 +.Os BSD 4.2 +.Sh NAME +.Nm pac +.Nd printer/plotter accounting information +.Sh SYNOPSIS +.Nm pac +.Op Fl P Ns Ar printer +.Op Fl c +.Op Fl m +.Op Fl p Ns Ar price +.Op Fl s +.Op Fl r +.Op Ar name ... +.Sh DESCRIPTION +.Nm Pac +reads the printer/plotter accounting files, accumulating the number +of pages (the usual case) or feet (for raster devices) +of paper consumed by each user, and printing out +how much each user consumed in pages or feet and dollars. +.Pp +Options and operands available: +.Bl -tag -width PPprinter +.It Fl P Ns Ar printer +Accounting is done for the named printer. +Normally, accounting is done for the default printer (site dependent) or +the value of the environment variable +.Ev PRINTER +is used. +.It Fl c +Cause the output to be sorted by cost; usually the +output is sorted alphabetically by name. +.It Fl m +Cause the host name to be ignored in the accounting file. This +allows for a user on multiple machines to have all of his printing +charges grouped together. +.It Fl p Ns Ar price +The value +.Ar price +is used for the cost in dollars instead of the default value of 0.02 +or the price specified in +.Pa /etc/printcap . +.It Fl r +Reverse the sorting order. +.It Fl s +Accounting information is summarized on the +summary accounting file; this summarization is necessary since on a +busy system, the accounting file can grow by several lines per day. +.It Ar names +Statistics are only printed for user(s) +.Ar name ; +usually, statistics are printed for every user who has used any paper. +.El +.Sh FILES +.Bl -tag -width /var/account/?_sum -compact +.It Pa /var/account/?acct +raw accounting files +.It Pa /var/account/?_sum +summary accounting files +.It Pa /etc/printcap +printer capability data base +.El +.Sh SEE ALSO +.Xr printcap 5 +.Sh BUGS +The relationship between the computed price and reality is +as yet unknown. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.0 . diff --git a/usr.sbin/lpr/pac/pac.c b/usr.sbin/lpr/pac/pac.c new file mode 100644 index 0000000..08de114 --- /dev/null +++ b/usr.sbin/lpr/pac/pac.c @@ -0,0 +1,462 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)pac.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +/* + * Do Printer accounting summary. + * Currently, usage is + * pac [-Pprinter] [-pprice] [-s] [-r] [-c] [-m] [user ...] + * to print the usage information for the named people. + */ + +#include <sys/param.h> + +#include <dirent.h> +#include <err.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include "lp.h" +#include "lp.local.h" + +static char *acctfile; /* accounting file (input data) */ +static int allflag = 1; /* Get stats on everybody */ +static int errs; +static int hcount; /* Count of hash entries */ +static int mflag = 0; /* disregard machine names */ +static int pflag = 0; /* 1 if -p on cmd line */ +static float price = 0.02; /* cost per page (or what ever) */ +static long price100; /* per-page cost in 100th of a cent */ +static int reverse; /* Reverse sort order */ +static int sort; /* Sort by cost */ +static char *sumfile; /* summary file */ +static int summarize; /* Compress accounting file */ + +uid_t uid, euid; + +/* + * Grossness follows: + * Names to be accumulated are hashed into the following + * table. + */ + +#define HSHSIZE 97 /* Number of hash buckets */ + +struct hent { + struct hent *h_link; /* Forward hash link */ + char *h_name; /* Name of this user */ + float h_feetpages; /* Feet or pages of paper */ + int h_count; /* Number of runs */ +}; + +static struct hent *hashtab[HSHSIZE]; /* Hash table proper */ + +int main __P((int, char **)); +static void account __P((FILE *)); +static int any __P((int, char [])); +static int chkprinter __P((char *)); +static void dumpit __P((void)); +static int hash __P((char [])); +static struct hent *enter __P((char [])); +static struct hent *lookup __P((char [])); +static int qucmp __P((const void *, const void *)); +static void rewrite __P((void)); +static void usage __P((void)); + +int +main(argc, argv) + int argc; + char **argv; +{ + FILE *acct; + char *cp, *printer; + + printer = NULL; + euid = geteuid(); /* these aren't used in pac(1) */ + uid = getuid(); + while (--argc) { + cp = *++argv; + if (*cp++ == '-') { + switch(*cp++) { + case 'P': + /* + * Printer name. + */ + printer = cp; + continue; + + case 'p': + /* + * get the price. + */ + price = atof(cp); + pflag = 1; + continue; + + case 's': + /* + * Summarize and compress accounting file. + */ + summarize++; + continue; + + case 'c': + /* + * Sort by cost. + */ + sort++; + continue; + + case 'm': + /* + * disregard machine names for each user + */ + mflag = 1; + continue; + + case 'r': + /* + * Reverse sorting order. + */ + reverse++; + continue; + + default: + usage(); + } + } + (void) enter(--cp); + allflag = 0; + } + if (printer == NULL && (printer = getenv("PRINTER")) == NULL) + printer = DEFLP; + if (!chkprinter(printer)) { + printf("pac: unknown printer %s\n", printer); + exit(2); + } + + if ((acct = fopen(acctfile, "r")) == NULL) { + perror(acctfile); + exit(1); + } + account(acct); + fclose(acct); + if ((acct = fopen(sumfile, "r")) != NULL) { + account(acct); + fclose(acct); + } + if (summarize) + rewrite(); + else + dumpit(); + exit(errs); +} + +static void +usage() +{ + fprintf(stderr, + "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [-m] [user ...]\n"); + exit(1); +} + +/* + * Read the entire accounting file, accumulating statistics + * for the users that we have in the hash table. If allflag + * is set, then just gather the facts on everyone. + * Note that we must accomodate both the active and summary file + * formats here. + * Host names are ignored if the -m flag is present. + */ +static void +account(acct) + register FILE *acct; +{ + char linebuf[BUFSIZ]; + double t; + register char *cp, *cp2; + register struct hent *hp; + register int ic; + + while (fgets(linebuf, BUFSIZ, acct) != NULL) { + cp = linebuf; + while (any(*cp, " \t")) + cp++; + t = atof(cp); + while (any(*cp, ".0123456789")) + cp++; + while (any(*cp, " \t")) + cp++; + for (cp2 = cp; !any(*cp2, " \t\n"); cp2++) + ; + ic = atoi(cp2); + *cp2 = '\0'; + if (mflag && strchr(cp, ':')) + cp = strchr(cp, ':') + 1; + hp = lookup(cp); + if (hp == NULL) { + if (!allflag) + continue; + hp = enter(cp); + } + hp->h_feetpages += t; + if (ic) + hp->h_count += ic; + else + hp->h_count++; + } +} + +/* + * Sort the hashed entries by name or footage + * and print it all out. + */ +static void +dumpit() +{ + struct hent **base; + register struct hent *hp, **ap; + register int hno, c, runs; + float feet; + + hp = hashtab[0]; + hno = 1; + base = (struct hent **) calloc(sizeof hp, hcount); + for (ap = base, c = hcount; c--; ap++) { + while (hp == NULL) + hp = hashtab[hno++]; + *ap = hp; + hp = hp->h_link; + } + qsort(base, hcount, sizeof hp, qucmp); + printf(" Login pages/feet runs price\n"); + feet = 0.0; + runs = 0; + for (ap = base, c = hcount; c--; ap++) { + hp = *ap; + runs += hp->h_count; + feet += hp->h_feetpages; + printf("%-24s %7.2f %4d $%6.2f\n", hp->h_name, + hp->h_feetpages, hp->h_count, hp->h_feetpages * price); + } + if (allflag) { + printf("\n"); + printf("%-24s %7.2f %4d $%6.2f\n", "total", feet, + runs, feet * price); + } +} + +/* + * Rewrite the summary file with the summary information we have accumulated. + */ +static void +rewrite() +{ + register struct hent *hp; + register int i; + register FILE *acctf; + + if ((acctf = fopen(sumfile, "w")) == NULL) { + warn("%s", sumfile); + errs++; + return; + } + for (i = 0; i < HSHSIZE; i++) { + hp = hashtab[i]; + while (hp != NULL) { + fprintf(acctf, "%7.2f\t%s\t%d\n", hp->h_feetpages, + hp->h_name, hp->h_count); + hp = hp->h_link; + } + } + fflush(acctf); + if (ferror(acctf)) { + warn("%s", sumfile); + errs++; + } + fclose(acctf); + if ((acctf = fopen(acctfile, "w")) == NULL) + warn("%s", acctfile); + else + fclose(acctf); +} + +/* + * Hashing routines. + */ + +/* + * Enter the name into the hash table and return the pointer allocated. + */ + +static struct hent * +enter(name) + char name[]; +{ + register struct hent *hp; + register int h; + + if ((hp = lookup(name)) != NULL) + return(hp); + h = hash(name); + hcount++; + hp = (struct hent *) calloc(sizeof *hp, 1); + hp->h_name = (char *) calloc(sizeof(char), strlen(name)+1); + strcpy(hp->h_name, name); + hp->h_feetpages = 0.0; + hp->h_count = 0; + hp->h_link = hashtab[h]; + hashtab[h] = hp; + return(hp); +} + +/* + * Lookup a name in the hash table and return a pointer + * to it. + */ + +static struct hent * +lookup(name) + char name[]; +{ + register int h; + register struct hent *hp; + + h = hash(name); + for (hp = hashtab[h]; hp != NULL; hp = hp->h_link) + if (strcmp(hp->h_name, name) == 0) + return(hp); + return(NULL); +} + +/* + * Hash the passed name and return the index in + * the hash table to begin the search. + */ +static int +hash(name) + char name[]; +{ + register int h; + register char *cp; + + for (cp = name, h = 0; *cp; h = (h << 2) + *cp++) + ; + return((h & 0x7fffffff) % HSHSIZE); +} + +/* + * Other stuff + */ +static int +any(ch, str) + int ch; + char str[]; +{ + register int c = ch; + register char *cp = str; + + while (*cp) + if (*cp++ == c) + return(1); + return(0); +} + +/* + * The qsort comparison routine. + * The comparison is ascii collating order + * or by feet of typesetter film, according to sort. + */ +static int +qucmp(a, b) + const void *a, *b; +{ + register struct hent *h1, *h2; + register int r; + + h1 = *(struct hent **)a; + h2 = *(struct hent **)b; + if (sort) + r = h1->h_feetpages < h2->h_feetpages ? + -1 : h1->h_feetpages > h2->h_feetpages; + else + r = strcmp(h1->h_name, h2->h_name); + return(reverse ? -r : r); +} + +/* + * Perform lookup for printer name or abbreviation -- + */ +static int +chkprinter(s) + register char *s; +{ + int stat; + struct printer myprinter, *pp = &myprinter; + + init_printer(&myprinter); + stat = getprintcap(s, pp); + switch(stat) { + case PCAPERR_OSERR: + printf("pac: getprintcap: %s\n", pcaperr(stat)); + exit(3); + case PCAPERR_NOTFOUND: + return 0; + case PCAPERR_TCLOOP: + fatal(pp, "%s", pcaperr(stat)); + } + acctfile = pp->acct_file; + if (!pflag && pp->price100) + price = pp->price100/10000.0; + sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5); + if (sumfile == NULL) + errx(1, "calloc failed"); + strcpy(sumfile, acctfile); + strcat(sumfile, "_sum"); + return(1); +} |