aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/lpr
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/lpr')
-rw-r--r--usr.sbin/lpr/Makefile6
-rw-r--r--usr.sbin/lpr/SMM.doc/0.t68
-rw-r--r--usr.sbin/lpr/SMM.doc/1.t77
-rw-r--r--usr.sbin/lpr/SMM.doc/2.t141
-rw-r--r--usr.sbin/lpr/SMM.doc/3.t73
-rw-r--r--usr.sbin/lpr/SMM.doc/4.t206
-rw-r--r--usr.sbin/lpr/SMM.doc/5.t116
-rw-r--r--usr.sbin/lpr/SMM.doc/6.t94
-rw-r--r--usr.sbin/lpr/SMM.doc/7.t226
-rw-r--r--usr.sbin/lpr/SMM.doc/Makefile10
-rw-r--r--usr.sbin/lpr/SMM.doc/spell.ok70
-rw-r--r--usr.sbin/lpr/common_source/common.c352
-rw-r--r--usr.sbin/lpr/common_source/displayq.c449
-rw-r--r--usr.sbin/lpr/common_source/lp.h126
-rw-r--r--usr.sbin/lpr/common_source/lp.local.h80
-rw-r--r--usr.sbin/lpr/common_source/pathnames.h50
-rw-r--r--usr.sbin/lpr/common_source/printcap.c458
-rw-r--r--usr.sbin/lpr/common_source/recvjob.c358
-rw-r--r--usr.sbin/lpr/common_source/rmjob.c339
-rw-r--r--usr.sbin/lpr/common_source/startdaemon.c108
-rw-r--r--usr.sbin/lpr/filters/Makefile7
-rw-r--r--usr.sbin/lpr/filters/lpf.c217
-rw-r--r--usr.sbin/lpr/lpc/Makefile12
-rw-r--r--usr.sbin/lpr/lpc/cmds.c1107
-rw-r--r--usr.sbin/lpr/lpc/cmdtab.c79
-rw-r--r--usr.sbin/lpr/lpc/extern.h58
-rw-r--r--usr.sbin/lpr/lpc/lpc.8174
-rw-r--r--usr.sbin/lpr/lpc/lpc.c277
-rw-r--r--usr.sbin/lpr/lpc/lpc.h45
-rw-r--r--usr.sbin/lpr/lpd/Makefile11
-rw-r--r--usr.sbin/lpr/lpd/extern.h39
-rw-r--r--usr.sbin/lpr/lpd/lpd.8249
-rw-r--r--usr.sbin/lpr/lpd/lpd.c507
-rw-r--r--usr.sbin/lpr/lpd/lpdchar.c1066
-rw-r--r--usr.sbin/lpr/lpd/printjob.c1377
-rw-r--r--usr.sbin/lpr/lpd/recvjob.c358
-rw-r--r--usr.sbin/lpr/lpq/Makefile12
-rw-r--r--usr.sbin/lpr/lpq/lpq.1134
-rw-r--r--usr.sbin/lpr/lpq/lpq.c126
-rw-r--r--usr.sbin/lpr/lpr/Makefile12
-rw-r--r--usr.sbin/lpr/lpr/lpr.1256
-rw-r--r--usr.sbin/lpr/lpr/lpr.c744
-rw-r--r--usr.sbin/lpr/lprm/Makefile12
-rw-r--r--usr.sbin/lpr/lprm/lprm.1145
-rw-r--r--usr.sbin/lpr/lprm/lprm.c144
-rw-r--r--usr.sbin/lpr/lptest/Makefile6
-rw-r--r--usr.sbin/lpr/lptest/lptest.174
-rw-r--r--usr.sbin/lpr/lptest/lptest.c83
-rw-r--r--usr.sbin/lpr/pac/Makefile10
-rw-r--r--usr.sbin/lpr/pac/pac.8106
-rw-r--r--usr.sbin/lpr/pac/pac.c444
-rw-r--r--usr.sbin/lpr/runqueue/extern.h39
-rw-r--r--usr.sbin/lpr/runqueue/lpdchar.c1066
-rw-r--r--usr.sbin/lpr/runqueue/printjob.c1377
54 files changed, 13780 insertions, 0 deletions
diff --git a/usr.sbin/lpr/Makefile b/usr.sbin/lpr/Makefile
new file mode 100644
index 000000000000..9b4d7d2b4164
--- /dev/null
+++ b/usr.sbin/lpr/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+SUBDIR= lpc lpd lpq lpr lprm lptest pac filters
+
+.include <bsd.subdir.mk>
+
diff --git a/usr.sbin/lpr/SMM.doc/0.t b/usr.sbin/lpr/SMM.doc/0.t
new file mode 100644
index 000000000000..65ecd4e44aa9
--- /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 000000000000..1d34e9ea86ce
--- /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 000000000000..9da2ae231cc6
--- /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 000000000000..8c950a961c8d
--- /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 000000000000..8800bc0d51c0
--- /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 000000000000..137a342640bc
--- /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 000000000000..708779055f7d
--- /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 000000000000..a6f6bea50320
--- /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 000000000000..1701c865d63a
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/Makefile
@@ -0,0 +1,10 @@
+# @(#)Makefile 8.1 (Berkeley) 6/8/93
+
+DIR= smm/07.lpd
+SRCS= 0.t 1.t 2.t 3.t 4.t 5.t 6.t 7.t
+MACROS= -ms
+
+paper.ps: ${SRCS}
+ ${TBL} ${SRCS} | ${ROFF} > ${.TARGET}
+
+.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 000000000000..bf31319943d6
--- /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/common_source/common.c b/usr.sbin/lpr/common_source/common.c
new file mode 100644
index 000000000000..49f79390e6e6
--- /dev/null
+++ b/usr.sbin/lpr/common_source/common.c
@@ -0,0 +1,352 @@
+/*
+ * 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.2 (Berkeley) 1/21/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "lp.h"
+#include "pathnames.h"
+
+/*
+ * Routines and data common to all the line printer functions.
+ */
+
+char *AF; /* accounting file */
+long BR; /* baud rate if lp is a tty */
+char *CF; /* name of cifplot filter (per job) */
+char *DF; /* name of tex filter (per job) */
+long DU; /* daeomon user-id */
+long FC; /* flags to clear if lp is a tty */
+char *FF; /* form feed string */
+long FS; /* flags to set if lp is a tty */
+char *GF; /* name of graph(1G) filter (per job) */
+long HL; /* print header last */
+char *IF; /* name of input filter (created per job) */
+char *LF; /* log file for error messages */
+char *LO; /* lock file name */
+char *LP; /* line printer device name */
+long MC; /* maximum number of copies allowed */
+long MX; /* maximum number of blocks to copy */
+char *NF; /* name of ditroff filter (per job) */
+char *OF; /* name of output filter (created once) */
+char *PF; /* name of vrast filter (per job) */
+long PL; /* page length */
+long PW; /* page width */
+long PX; /* page width in pixels */
+long PY; /* page length in pixels */
+char *RF; /* name of fortran text filter (per job) */
+char *RG; /* resricted group */
+char *RM; /* remote machine name */
+char *RP; /* remote printer name */
+long RS; /* restricted to those with local accounts */
+long RW; /* open LP for reading and writing */
+long SB; /* short banner instead of normal header */
+long SC; /* suppress multiple copies */
+char *SD; /* spool directory */
+long SF; /* suppress FF on each print job */
+long SH; /* suppress header page */
+char *ST; /* status file name */
+char *TF; /* name of troff filter (per job) */
+char *TR; /* trailer string to be output when Q empties */
+char *VF; /* name of vplot filter (per job) */
+long XC; /* flags to clear for local mode */
+long XS; /* flags to set for local mode */
+
+char line[BUFSIZ];
+char *bp; /* pointer into printcap buffer. */
+char *name; /* program name */
+char *printer; /* printer name */
+ /* host machine name */
+char host[MAXHOSTNAMELEN];
+char *from = host; /* client's machine name */
+int sendtorem; /* are we sending to a remote? */
+char *printcapdb[2] = { _PATH_PRINTCAP, 0 };
+
+static int compar __P((const void *, const void *));
+
+/*
+ * Create a connection to the remote printer server.
+ * Most of this code comes from rcmd.c.
+ */
+int
+getport(rhost)
+ char *rhost;
+{
+ 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("no remote host to connect to");
+ hp = gethostbyname(rhost);
+ if (hp == NULL)
+ fatal("unknown host %s", rhost);
+ sp = getservbyname("printer", "tcp");
+ if (sp == NULL)
+ fatal("printer/tcp: unknown service");
+ bzero((char *)&sin, sizeof(sin));
+ bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
+ sin.sin_family = hp->h_addrtype;
+ sin.sin_port = sp->s_port;
+
+ /*
+ * Try connecting to the server.
+ */
+retry:
+ s = rresvport(&lport);
+ if (s < 0)
+ return(-1);
+ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ err = errno;
+ (void) close(s);
+ errno = err;
+ if (errno == EADDRINUSE) {
+ lport--;
+ goto retry;
+ }
+ if (errno == ECONNREFUSED && timo <= 16) {
+ sleep(timo);
+ timo *= 2;
+ goto retry;
+ }
+ return(-1);
+ }
+ return(s);
+}
+
+/*
+ * 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 c;
+
+ while ((c = getc(cfp)) != '\n') {
+ if (c == EOF)
+ return(0);
+ if (c == '\t') {
+ do {
+ *lp++ = ' ';
+ linel++;
+ } while ((linel & 07) != 0);
+ 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(namelist)
+ struct queue *(*namelist[]);
+{
+ register struct dirent *d;
+ register struct queue *q, **queue;
+ register int nitems;
+ struct stat stbuf;
+ DIR *dirp;
+ int arraysz;
+
+ if ((dirp = opendir(SD)) == NULL)
+ return(-1);
+ if (fstat(dirp->dd_fd, &stbuf) < 0)
+ goto errdone;
+
+ /*
+ * 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 */
+ if (stat(d->d_name, &stbuf) < 0)
+ continue; /* Doesn't exist */
+ 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) {
+ queue = (struct queue **)realloc((char *)queue,
+ (stbuf.st_size/12) * 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;
+{
+ if ((*(struct queue **)p1)->q_time < (*(struct queue **)p2)->q_time)
+ return(-1);
+ if ((*(struct queue **)p1)->q_time > (*(struct queue **)p2)->q_time)
+ return(1);
+ return(0);
+}
+
+/*
+ * Figure out whether the local machine is the same
+ * as the remote machine (RM) entry (if it exists).
+ */
+char *
+checkremote()
+{
+ char name[MAXHOSTNAMELEN];
+ register struct hostent *hp;
+ static char errbuf[128];
+
+ sendtorem = 0; /* assume printer is local */
+ if (RM != (char *)NULL) {
+ /* get the official name of the local host */
+ gethostname(name, sizeof(name));
+ name[sizeof(name)-1] = '\0';
+ hp = gethostbyname(name);
+ if (hp == (struct hostent *) NULL) {
+ (void) snprintf(errbuf, sizeof(errbuf),
+ "unable to get official name for local machine %s",
+ name);
+ return errbuf;
+ } else (void) strcpy(name, hp->h_name);
+
+ /* get the official name of RM */
+ hp = gethostbyname(RM);
+ if (hp == (struct hostent *) NULL) {
+ (void) snprintf(errbuf, sizeof(errbuf),
+ "unable to get official name for remote machine %s",
+ RM);
+ return errbuf;
+ }
+
+ /*
+ * if the two hosts are not the same,
+ * then the printer must be remote.
+ */
+ if (strcmp(name, hp->h_name) != 0)
+ sendtorem = 1;
+ }
+ return (char *)0;
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+fatal(const char *msg, ...)
+#else
+fatal(msg, va_alist)
+ char *msg;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+ if (from != host)
+ (void)printf("%s: ", host);
+ (void)printf("%s: ", name);
+ if (printer)
+ (void)printf("%s: ", printer);
+ (void)vprintf(msg, ap);
+ va_end(ap);
+ (void)putchar('\n');
+ exit(1);
+}
diff --git a/usr.sbin/lpr/common_source/displayq.c b/usr.sbin/lpr/common_source/displayq.c
new file mode 100644
index 000000000000..59d3cc9c2ad6
--- /dev/null
+++ b/usr.sbin/lpr/common_source/displayq.c
@@ -0,0 +1,449 @@
+/*
+ * 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.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <signal.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#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 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 */
+
+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";
+
+/*
+ * Display the current state of the queue. Format = 1 if long format.
+ */
+void
+displayq(format)
+ int format;
+{
+ register struct queue *q;
+ register int i, nitems, fd;
+ register char *cp;
+ struct queue **queue;
+ struct stat statb;
+ FILE *fp;
+
+ lflag = format;
+ totsize = 0;
+ rank = -1;
+ if ((i = cgetent(&bp, printcapdb, printer)) == -2)
+ fatal("can't open printer description file");
+ else if (i == -1)
+ fatal("unknown printer");
+ else if (i == -3)
+ fatal("potential reference loop detected in printcap file");
+ if (cgetstr(bp, "lp", &LP) < 0)
+ LP = _PATH_DEFDEVLP;
+ if (cgetstr(bp, "rp", &RP) < 0)
+ RP = DEFLP;
+ if (cgetstr(bp, "sd", &SD) < 0)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp,"lo", &LO) < 0)
+ LO = DEFLOCK;
+ if (cgetstr(bp, "st", &ST) < 0)
+ ST = DEFSTAT;
+ cgetstr(bp, "rm", &RM);
+ if (cp = checkremote())
+ printf("Warning: %s\n", cp);
+
+ /*
+ * Print out local queue
+ * Find all the control files in the spooling directory
+ */
+ if (chdir(SD) < 0)
+ fatal("cannot chdir to spooling directory");
+ if ((nitems = getq(&queue)) < 0)
+ fatal("cannot examine spooling area\n");
+ if (stat(LO, &statb) >= 0) {
+ if (statb.st_mode & 0100) {
+ if (sendtorem)
+ printf("%s: ", host);
+ printf("Warning: %s is down: ", printer);
+ fd = open(ST, O_RDONLY);
+ if (fd >= 0) {
+ (void) flock(fd, LOCK_SH);
+ 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 & 010) {
+ if (sendtorem)
+ printf("%s: ", host);
+ printf("Warning: %s queue is turned off\n", printer);
+ }
+ }
+
+ if (nitems) {
+ fp = fopen(LO, "r");
+ if (fp == NULL)
+ warn();
+ else {
+ /* get daemon pid */
+ cp = current;
+ while ((*cp = getc(fp)) != EOF && *cp != '\n')
+ cp++;
+ *cp = '\0';
+ i = atoi(current);
+ if (i <= 0 || kill(i, 0) < 0)
+ warn();
+ else {
+ /* read current file name */
+ cp = current;
+ while ((*cp = getc(fp)) != EOF && *cp != '\n')
+ cp++;
+ *cp = '\0';
+ /*
+ * Print the status file.
+ */
+ if (sendtorem)
+ printf("%s: ", host);
+ fd = open(ST, O_RDONLY);
+ if (fd >= 0) {
+ (void) flock(fd, LOCK_SH);
+ while ((i = read(fd, line, sizeof(line))) > 0)
+ (void) fwrite(line, 1, i, stdout);
+ (void) 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(q->q_name);
+ free(q);
+ }
+ free(queue);
+ }
+ if (!sendtorem) {
+ 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) sprintf(line, "%c%s", format + '\3', RP);
+ cp = line;
+ for (i = 0; i < requests; i++) {
+ cp += strlen(cp);
+ (void) sprintf(cp, " %d", requ[i]);
+ }
+ for (i = 0; i < users; i++) {
+ cp += strlen(cp);
+ *cp++ = ' ';
+ (void) strcpy(cp, user[i]);
+ }
+ strcat(line, "\n");
+ fd = getport(RM);
+ if (fd < 0) {
+ if (from != host)
+ printf("%s: ", host);
+ printf("connection to %s is down\n", RM);
+ }
+ else {
+ i = strlen(line);
+ if (write(fd, line, i) != i)
+ fatal("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.
+ */
+void
+warn()
+{
+ if (sendtorem)
+ printf("\n%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(cf)
+ char *cf;
+{
+ register int j;
+ FILE *cfp;
+
+ /*
+ * There's a chance the control file has gone away
+ * in the meantime; if this is the case just keep going
+ */
+ if ((cfp = fopen(cf, "r")) == NULL)
+ return;
+
+ if (rank < 0)
+ rank = 0;
+ if (sendtorem || garbage || strcmp(cf, current))
+ rank++;
+ j = 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')
+ continue;
+ if (j == 0 || strcmp(file, line+1) != 0)
+ (void) strcpy(file, line+1);
+ j++;
+ continue;
+ case 'N':
+ show(line+1, file, j);
+ file[0] = '\0';
+ j = 0;
+ }
+ }
+ fclose(cfp);
+ 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;
+{
+ register short n, fill;
+ struct stat lbuf;
+
+ /*
+ * Print as many files as will fit
+ * (leaving room for the total size)
+ */
+ fill = first ? 0 : 2; /* fill space for ``, '' */
+ if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
+ if (col < SIZCOL) {
+ printf(" ..."), col += 4;
+ blankfill(SIZCOL);
+ }
+ } else {
+ if (first)
+ first = 0;
+ else
+ printf(", ");
+ printf("%s", nfile);
+ col += n+fill;
+ }
+ if (*file && !stat(file, &lbuf))
+ totsize += copies * lbuf.st_size;
+}
+
+/*
+ * 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", 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);
+}
diff --git a/usr.sbin/lpr/common_source/lp.h b/usr.sbin/lpr/common_source/lp.h
new file mode 100644
index 000000000000..6dd1bf040969
--- /dev/null
+++ b/usr.sbin/lpr/common_source/lp.h
@@ -0,0 +1,126 @@
+/*
+ * 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.h 8.1 (Berkeley) 6/6/93
+ */
+
+
+/*
+ * Global definitions for the line printer system.
+ */
+
+extern char *AF; /* accounting file */
+extern long BR; /* baud rate if lp is a tty */
+extern char *CF; /* name of cifplot filter (per job) */
+extern char *DF; /* name of tex filter (per job) */
+extern long DU; /* daeomon user-id */
+extern long FC; /* flags to clear if lp is a tty */
+extern char *FF; /* form feed string */
+extern long FS; /* flags to set if lp is a tty */
+extern char *GF; /* name of graph(1G) filter (per job) */
+extern long HL; /* print header last */
+extern char *IF; /* name of input filter (created per job) */
+extern char *LF; /* log file for error messages */
+extern char *LO; /* lock file name */
+extern char *LP; /* line printer device name */
+extern long MC; /* maximum number of copies allowed */
+extern long MX; /* maximum number of blocks to copy */
+extern char *NF; /* name of ditroff(1) filter (per job) */
+extern char *OF; /* name of output filter (created once) */
+extern long PL; /* page length */
+extern long PW; /* page width */
+extern long PX; /* page width in pixels */
+extern long PY; /* page length in pixels */
+extern char *RF; /* name of fortran text filter (per job) */
+extern char *RG; /* restricted group */
+extern char *RM; /* remote machine name */
+extern char *RP; /* remote printer name */
+extern long RS; /* restricted to those with local accounts */
+extern long RW; /* open LP for reading and writing */
+extern long SB; /* short banner instead of normal header */
+extern long SC; /* suppress multiple copies */
+extern char *SD; /* spool directory */
+extern long SF; /* suppress FF on each print job */
+extern long SH; /* suppress header page */
+extern char *ST; /* status file name */
+extern char *TF; /* name of troff(1) filter (per job) */
+extern char *TR; /* trailer string to be output when Q empties */
+extern char *VF; /* name of raster filter (per job) */
+extern long XC; /* flags to clear for local mode */
+extern long XS; /* flags to set for local mode */
+
+extern char line[BUFSIZ];
+extern char *bp; /* pointer into printcap buffer */
+extern char *name; /* program name */
+extern char *printer; /* printer name */
+ /* host machine name */
+extern char host[MAXHOSTNAMELEN];
+extern char *from; /* client's machine name */
+extern int sendtorem; /* are we sending to a remote? */
+extern char *printcapdb[]; /* printcap database array */
+/*
+ * 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 */
+};
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+struct dirent;
+
+void blankfill __P((int));
+char *checkremote __P((void));
+int chk __P((char *));
+void displayq __P((int));
+void dump __P((char *, char *, int));
+void fatal __P((const char *, ...));
+int getline __P((FILE *));
+int getport __P((char *));
+int getq __P((struct queue *(*[])));
+void header __P((void));
+void inform __P((char *));
+int inlist __P((char *, char *));
+int iscf __P((struct dirent *));
+int isowner __P((char *, char *));
+void ldump __P((char *, char *, int));
+int lockchk __P((char *));
+void prank __P((int));
+void process __P((char *));
+void rmjob __P((void));
+void rmremote __P((void));
+void show __P((char *, char *, int));
+int startdaemon __P((char *));
+void warn __P((void));
+__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 000000000000..837fd2fcb53c
--- /dev/null
+++ b/usr.sbin/lpr/common_source/lp.local.h
@@ -0,0 +1,80 @@
+/*
+ * 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
+
+/*
+ * 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/pathnames.h b/usr.sbin/lpr/common_source/pathnames.h
new file mode 100644
index 000000000000..5c07cdb820a9
--- /dev/null
+++ b/usr.sbin/lpr/common_source/pathnames.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.
+ *
+ * @(#)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"
diff --git a/usr.sbin/lpr/common_source/printcap.c b/usr.sbin/lpr/common_source/printcap.c
new file mode 100644
index 000000000000..627d2ce9fbfc
--- /dev/null
+++ b/usr.sbin/lpr/common_source/printcap.c
@@ -0,0 +1,458 @@
+/*
+ * 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[] = "@(#)printcap.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "lp.h"
+#include "pathnames.h"
+
+#ifndef BUFSIZ
+#define BUFSIZ 1024
+#endif
+#define MAXHOP 32 /* max number of tc= indirections */
+
+/*
+ * termcap - routines for dealing with the terminal capability data base
+ *
+ * BUG: Should use a "last" pointer in tbuf, so that searching
+ * for capabilities alphabetically would not be a n**2/2
+ * process when large numbers of capabilities are given.
+ * Note: If we add a last pointer now we will screw up the
+ * tc capability. We really should compile termcap.
+ *
+ * Essentially all the work here is scanning and decoding escapes
+ * in string capabilities. We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
+
+#define PRINTCAP
+
+#ifdef PRINTCAP
+#define tgetent pgetent
+#define tskip pskip
+#define tgetstr pgetstr
+#define tdecode pdecode
+#define tgetnum pgetnum
+#define tgetflag pgetflag
+#define tdecode pdecode
+#define tnchktc pnchktc
+#define tnamatch pnamatch
+#define V6
+#endif
+
+static FILE *pfp = NULL; /* printcap data base file pointer */
+static char *tbuf;
+static int hopcount; /* detect infinite loops in termcap, init 0 */
+
+static char *tskip __P((char *));
+static char *tskip __P((char *bp));
+static char *tdecode __P((char *, char **));
+
+/*
+ * Similar to tgetent except it returns the next enrty instead of
+ * doing a lookup.
+ */
+int
+getprent(bp)
+ register char *bp;
+{
+ register int c, skip = 0;
+
+ if (pfp == NULL && (pfp = fopen(_PATH_PRINTCAP, "r")) == NULL)
+ return(-1);
+ tbuf = bp;
+ for (;;) {
+ switch (c = getc(pfp)) {
+ case EOF:
+ fclose(pfp);
+ pfp = NULL;
+ return(0);
+ case '\n':
+ if (bp == tbuf) {
+ skip = 0;
+ continue;
+ }
+ if (bp[-1] == '\\') {
+ bp--;
+ continue;
+ }
+ *bp = '\0';
+ return(1);
+ case '#':
+ if (bp == tbuf)
+ skip++;
+ default:
+ if (skip)
+ continue;
+ if (bp >= tbuf+BUFSIZ) {
+ write(2, "Termcap entry too long\n", 23);
+ *bp = '\0';
+ return(1);
+ }
+ *bp++ = c;
+ }
+ }
+}
+
+void
+endprent()
+{
+ if (pfp != NULL)
+ fclose(pfp);
+}
+
+/*
+ * Get an entry for terminal name in buffer bp,
+ * from the termcap file. Parse is very rudimentary;
+ * we just notice escaped newlines.
+ */
+int
+tgetent(bp, name)
+ char *bp, *name;
+{
+ register char *cp;
+ register int c;
+ register int i = 0, cnt = 0;
+ char ibuf[BUFSIZ];
+ int tf;
+
+ tbuf = bp;
+ tf = 0;
+#ifndef V6
+ cp = getenv("TERMCAP");
+ /*
+ * TERMCAP can have one of two things in it. It can be the
+ * name of a file to use instead of /etc/termcap. In this
+ * case it better start with a "/". Or it can be an entry to
+ * use so we don't have to read the file. In this case it
+ * has to already have the newlines crunched out.
+ */
+ if (cp && *cp) {
+ if (*cp!='/') {
+ cp2 = getenv("TERM");
+ if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
+ strcpy(bp,cp);
+ return(tnchktc());
+ } else {
+ tf = open(_PATH_PRINTCAP, 0);
+ }
+ } else
+ tf = open(cp, 0);
+ }
+ if (tf==0)
+ tf = open(_PATH_PRINTCAP, 0);
+#else
+ tf = open(_PATH_PRINTCAP, 0);
+#endif
+ if (tf < 0)
+ return (-1);
+ for (;;) {
+ cp = bp;
+ for (;;) {
+ if (i == cnt) {
+ cnt = read(tf, ibuf, BUFSIZ);
+ if (cnt <= 0) {
+ close(tf);
+ return (0);
+ }
+ i = 0;
+ }
+ c = ibuf[i++];
+ if (c == '\n') {
+ if (cp > bp && cp[-1] == '\\'){
+ cp--;
+ continue;
+ }
+ break;
+ }
+ if (cp >= bp+BUFSIZ) {
+ write(2,"Termcap entry too long\n", 23);
+ break;
+ } else
+ *cp++ = c;
+ }
+ *cp = 0;
+
+ /*
+ * The real work for the match.
+ */
+ if (tnamatch(name)) {
+ close(tf);
+ return(tnchktc());
+ }
+ }
+}
+
+/*
+ * tnchktc: check the last entry, see if it's tc=xxx. If so,
+ * recursively find xxx and append that entry (minus the names)
+ * to take the place of the tc=xxx entry. This allows termcap
+ * entries to say "like an HP2621 but doesn't turn on the labels".
+ * Note that this works because of the left to right scan.
+ */
+int
+tnchktc()
+{
+ register char *p, *q;
+ char tcname[16]; /* name of similar terminal */
+ char tcbuf[BUFSIZ];
+ char *holdtbuf = tbuf;
+ int l;
+
+ p = tbuf + strlen(tbuf) - 2; /* before the last colon */
+ while (*--p != ':')
+ if (p<tbuf) {
+ write(2, "Bad termcap entry\n", 18);
+ return (0);
+ }
+ p++;
+ /* p now points to beginning of last field */
+ if (p[0] != 't' || p[1] != 'c')
+ return(1);
+ strcpy(tcname,p+3);
+ q = tcname;
+ while (q && *q != ':')
+ q++;
+ *q = 0;
+ if (++hopcount > MAXHOP) {
+ write(2, "Infinite tc= loop\n", 18);
+ return (0);
+ }
+ if (tgetent(tcbuf, tcname) != 1)
+ return(0);
+ for (q=tcbuf; *q != ':'; q++)
+ ;
+ l = p - holdtbuf + strlen(q);
+ if (l > BUFSIZ) {
+ write(2, "Termcap entry too long\n", 23);
+ q[BUFSIZ - (p-tbuf)] = 0;
+ }
+ strcpy(p, q+1);
+ tbuf = holdtbuf;
+ return(1);
+}
+
+/*
+ * Tnamatch deals with name matching. The first field of the termcap
+ * entry is a sequence of names separated by |'s, so we compare
+ * against each such name. The normal : terminator after the last
+ * name (before the first field) stops us.
+ */
+int
+tnamatch(np)
+ char *np;
+{
+ register char *Np, *Bp;
+
+ Bp = tbuf;
+ if (*Bp == '#')
+ return(0);
+ for (;;) {
+ for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
+ continue;
+ if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
+ return (1);
+ while (*Bp && *Bp != ':' && *Bp != '|')
+ Bp++;
+ if (*Bp == 0 || *Bp == ':')
+ return (0);
+ Bp++;
+ }
+}
+
+/*
+ * Skip to the next field. Notice that this is very dumb, not
+ * knowing about \: escapes or any such. If necessary, :'s can be put
+ * into the termcap file in octal.
+ */
+static char *
+tskip(bp)
+ register char *bp;
+{
+
+ while (*bp && *bp != ':')
+ bp++;
+ if (*bp == ':')
+ bp++;
+ return (bp);
+}
+
+/*
+ * Return the (numeric) option id.
+ * Numeric options look like
+ * li#80
+ * i.e. the option string is separated from the numeric value by
+ * a # character. If the option is not found we return -1.
+ * Note that we handle octal numbers beginning with 0.
+ */
+int
+tgetnum(id)
+ char *id;
+{
+ register int i, base;
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (*bp == 0)
+ return (-1);
+ if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+ continue;
+ if (*bp == '@')
+ return(-1);
+ if (*bp != '#')
+ continue;
+ bp++;
+ base = 10;
+ if (*bp == '0')
+ base = 8;
+ i = 0;
+ while (isdigit(*bp))
+ i *= base, i += *bp++ - '0';
+ return (i);
+ }
+}
+
+/*
+ * Handle a flag option.
+ * Flag options are given "naked", i.e. followed by a : or the end
+ * of the buffer. Return 1 if we find the option, or 0 if it is
+ * not given.
+ */
+int
+tgetflag(id)
+ char *id;
+{
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
+ if (!*bp || *bp == ':')
+ return (1);
+ else if (*bp == '@')
+ return(0);
+ }
+ }
+}
+
+/*
+ * Get a string valued option.
+ * These are given as
+ * cl=^Z
+ * Much decoding is done on the strings, and the strings are
+ * placed in area, which is a ref parameter which is updated.
+ * No checking on area overflow.
+ */
+char *
+tgetstr(id, area)
+ char *id, **area;
+{
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+ continue;
+ if (*bp == '@')
+ return(0);
+ if (*bp != '=')
+ continue;
+ bp++;
+ return (tdecode(bp, area));
+ }
+}
+
+/*
+ * Tdecode does the grung work to decode the
+ * string capability escapes.
+ */
+static char *
+tdecode(str, area)
+ register char *str;
+ char **area;
+{
+ register char *cp;
+ register int c;
+ register char *dp;
+ int i;
+
+ cp = *area;
+ while ((c = *str++) && c != ':') {
+ switch (c) {
+
+ case '^':
+ c = *str++ & 037;
+ break;
+
+ case '\\':
+ dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
+ c = *str++;
+nextc:
+ if (*dp++ == c) {
+ c = *dp++;
+ break;
+ }
+ dp++;
+ if (*dp)
+ goto nextc;
+ if (isdigit(c)) {
+ c -= '0', i = 2;
+ do
+ c <<= 3, c |= *str++ - '0';
+ while (--i && isdigit(*str));
+ }
+ break;
+ }
+ *cp++ = c;
+ }
+ *cp++ = 0;
+ str = *area;
+ *area = cp;
+ return (str);
+}
+
diff --git a/usr.sbin/lpr/common_source/recvjob.c b/usr.sbin/lpr/common_source/recvjob.c
new file mode 100644
index 000000000000..67a61830ff29
--- /dev/null
+++ b/usr.sbin/lpr/common_source/recvjob.c
@@ -0,0 +1,358 @@
+/*
+ * 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[] = "@(#)recvjob.c 8.1 (Berkeley) 6/6/93";
+#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[40]; /* data files */
+static int minfree; /* keep at least minfree blocks available */
+static char *sp = "";
+static char tfname[40]; /* 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((char *, int));
+static int readjob __P((void));
+
+
+void
+recvjob()
+{
+ struct stat stb;
+ int status;
+
+ /*
+ * Perform lookup for printer name or abbreviation
+ */
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2)
+ frecverr("cannot open printer description file");
+ else if (status == -1)
+ frecverr("unknown printer %s", printer);
+ else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ if (cgetstr(bp, "lf", &LF) == -1)
+ LF = _PATH_CONSOLE;
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+
+ (void) close(2); /* set up log file */
+ if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
+ syslog(LOG_ERR, "%s: %m", LF);
+ (void) open(_PATH_DEVNULL, O_WRONLY);
+ }
+
+ if (chdir(SD) < 0)
+ frecverr("%s: %s: %m", printer, SD);
+ if (stat(LO, &stb) == 0) {
+ if (stb.st_mode & 010) {
+ /* queue is disabled */
+ putchar('\1'); /* return error code */
+ exit(1);
+ }
+ } else if (stat(SD, &stb) < 0)
+ frecverr("%s: %s: %m", printer, SD);
+ minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */
+ signal(SIGTERM, rcleanup);
+ signal(SIGPIPE, rcleanup);
+
+ if (readjob())
+ printjob();
+}
+
+/*
+ * Read printer jobs sent by lpd and copy them to the spooling directory.
+ * Return the number of jobs successfully transfered.
+ */
+static int
+readjob()
+{
+ register int size, nfiles;
+ register char *cp;
+
+ ack();
+ nfiles = 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",printer);
+ return(nfiles);
+ }
+ } while (*cp++ != '\n');
+ *--cp = '\0';
+ cp = line;
+ switch (*cp++) {
+ case '\1': /* cleanup because data sent was bad */
+ rcleanup(0);
+ continue;
+
+ case '\2': /* read cf file */
+ size = 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
+ */
+ strcpy(cp + 6, from);
+ strcpy(tfname, cp);
+ tfname[0] = 't';
+ if (!chksize(size)) {
+ (void) write(1, "\2", 1);
+ continue;
+ }
+ if (!readfile(tfname, size)) {
+ rcleanup(0);
+ continue;
+ }
+ if (link(tfname, cp) < 0)
+ frecverr("%s: %m", tfname);
+ (void) unlink(tfname);
+ tfname[0] = '\0';
+ nfiles++;
+ continue;
+
+ case '\3': /* read df file */
+ 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) strcpy(dfname, cp);
+ if (index(dfname, '/'))
+ frecverr("readjob: %s: illegal path name",
+ dfname);
+ (void) readfile(dfname, size);
+ continue;
+ }
+ frecverr("protocol screwup: %s", line);
+ }
+}
+
+/*
+ * Read files send by lpd and copy them to the spooling directory.
+ */
+static int
+readfile(file, size)
+ 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("readfile: %s: illegal path name: %m", file);
+ 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("Lost connection");
+ 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", file);
+ if (noresponse()) { /* file sent had bad data in it */
+ (void) unlink(file);
+ return(0);
+ }
+ ack();
+ return(1);
+}
+
+static int
+noresponse()
+{
+ char resp;
+
+ if (read(1, &resp, 1) != 1)
+ frecverr("Lost connection");
+ 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])
+ (void) unlink(tfname);
+ if (dfname[0])
+ do {
+ do
+ (void) unlink(dfname);
+ while (dfname[2]-- != 'A');
+ dfname[2] = 'z';
+ } while (dfname[0]-- != 'd');
+ dfname[0] = '\0';
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+static void
+#if __STDC__
+frecverr(const char *msg, ...)
+#else
+frecverr(msg, va_alist)
+ char *msg;
+ va_dcl
+#endif
+{
+ extern char *fromb;
+ va_list ap;
+#if __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+ rcleanup(0);
+ syslog(LOG_ERR, "%s", fromb);
+ vsyslog(LOG_ERR, msg, ap);
+ va_end(ap);
+ putchar('\1'); /* return error code */
+ exit(1);
+}
diff --git a/usr.sbin/lpr/common_source/rmjob.c b/usr.sbin/lpr/common_source/rmjob.c
new file mode 100644
index 000000000000..74a94d8a4c97
--- /dev/null
+++ b/usr.sbin/lpr/common_source/rmjob.c
@@ -0,0 +1,339 @@
+/*
+ * 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[] = "@(#)rmjob.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <signal.h>
+#include <errno.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+
+/*
+ * rmjob - remove the specified jobs from the queue.
+ */
+
+/*
+ * Stuff for handling lprm specifications
+ */
+extern char *user[]; /* users to process */
+extern int users; /* # of users in user array */
+extern int requ[]; /* job number of spool entries */
+extern int requests; /* # of spool requests */
+extern char *person; /* name of person doing lprm */
+
+static char root[] = "root";
+static int all = 0; /* eliminate all files (root only) */
+static int cur_daemon; /* daemon's pid */
+static char current[40]; /* active control file name */
+
+void
+rmjob()
+{
+ register int i, nitems;
+ int assasinated = 0;
+ struct dirent **files;
+ char *cp;
+
+ if ((i = cgetent(&bp, printcapdb, printer)) == -2)
+ fatal("can't open printer description file");
+ else if (i == -1)
+ fatal("unknown printer");
+ else if (i == -3)
+ fatal("potential reference loop detected in printcap file");
+ if (cgetstr(bp, "lp", &LP) < 0)
+ LP = _PATH_DEFDEVLP;
+ if (cgetstr(bp, "rp", &RP) < 0)
+ RP = DEFLP;
+ if (cgetstr(bp, "sd", &SD) < 0)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp,"lo", &LO) < 0)
+ LO = DEFLOCK;
+ cgetstr(bp, "rm", &RM);
+ if (cp = checkremote())
+ printf("Warning: %s\n", 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("The login name \"-all\" is reserved");
+ all = 1; /* all those from 'from' */
+ person = root;
+ }
+
+ if (chdir(SD) < 0)
+ fatal("cannot chdir to spool directory");
+ if ((nitems = scandir(".", &files, iscf, NULL)) < 0)
+ fatal("cannot access spool directory");
+
+ 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(LO) && chk(current)) {
+ assasinated = kill(cur_daemon, SIGINT) == 0;
+ if (!assasinated)
+ fatal("cannot kill printer daemon");
+ }
+ /*
+ * process the files
+ */
+ for (i = 0; i < nitems; i++)
+ process(files[i]->d_name);
+ }
+ rmremote();
+ /*
+ * Restart the printer daemon if it was killed
+ */
+ if (assasinated && !startdaemon(printer))
+ fatal("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(s)
+ char *s;
+{
+ register FILE *fp;
+ register int i, n;
+
+ if ((fp = fopen(s, "r")) == NULL)
+ if (errno == EACCES)
+ fatal("can't access lock file");
+ else
+ return(0);
+ if (!getline(fp)) {
+ (void) fclose(fp);
+ return(0); /* no daemon present */
+ }
+ cur_daemon = atoi(line);
+ if (kill(cur_daemon, 0) < 0) {
+ (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(file)
+ char *file;
+{
+ FILE *cfp;
+
+ if (!chk(file))
+ return;
+ if ((cfp = fopen(file, "r")) == NULL)
+ fatal("cannot open %s", file);
+ while (getline(cfp)) {
+ switch (line[0]) {
+ case 'U': /* unlink associated files */
+ if (from != host)
+ printf("%s: ", host);
+ printf(unlink(line+1) ? "cannot dequeue %s\n" :
+ "%s dequeued\n", line+1);
+ }
+ }
+ (void) fclose(cfp);
+ if (from != host)
+ printf("%s: ", host);
+ printf(unlink(file) ? "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.
+ */
+ if ((cfp = fopen(file, "r")) == NULL)
+ return(0);
+ 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()
+{
+ register char *cp;
+ register int i, rem;
+ char buf[BUFSIZ];
+
+ if (!sendtorem)
+ 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);
+
+ (void)snprintf(buf, sizeof(buf), "\5%s %s", RP, all ? "-all" : person);
+ cp = buf;
+ for (i = 0; i < users; i++) {
+ cp += strlen(cp);
+ *cp++ = ' ';
+ strcpy(cp, user[i]);
+ }
+ for (i = 0; i < requests; i++) {
+ cp += strlen(cp);
+ (void) sprintf(cp, " %d", requ[i]);
+ }
+ strcat(cp, "\n");
+ rem = getport(RM);
+ if (rem < 0) {
+ if (from != host)
+ printf("%s: ", host);
+ printf("connection to %s is down\n", RM);
+ } else {
+ i = strlen(buf);
+ if (write(rem, buf, i) != i)
+ fatal("Lost connection");
+ while ((i = read(rem, buf, sizeof(buf))) > 0)
+ (void) fwrite(buf, 1, i, stdout);
+ (void) close(rem);
+ }
+}
+
+/*
+ * 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');
+}
diff --git a/usr.sbin/lpr/common_source/startdaemon.c b/usr.sbin/lpr/common_source/startdaemon.c
new file mode 100644
index 000000000000..237769e773bd
--- /dev/null
+++ b/usr.sbin/lpr/common_source/startdaemon.c
@@ -0,0 +1,108 @@
+/*
+ * 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 char sccsid[] = "@(#)startdaemon.c 8.2 (Berkeley) 4/17/94";
+#endif /* not lint */
+
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include "lp.h"
+#include "pathnames.h"
+
+static void perr __P((char *));
+
+/*
+ * Tell the printer daemon that there are new files in the spool directory.
+ */
+
+int
+startdaemon(printer)
+ char *printer;
+{
+ struct sockaddr_un un;
+ register int s, n;
+ char buf[BUFSIZ];
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s < 0) {
+ perr("socket");
+ return(0);
+ }
+ 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 (connect(s, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) {
+ perr("connect");
+ (void) close(s);
+ return(0);
+ }
+ (void) sprintf(buf, "\1%s\n", printer);
+ n = strlen(buf);
+ if (write(s, buf, n) != n) {
+ perr("write");
+ (void) close(s);
+ return(0);
+ }
+ if (read(s, buf, 1) == 1) {
+ if (buf[0] == '\0') { /* everything is OK */
+ (void) close(s);
+ return(1);
+ }
+ putchar(buf[0]);
+ }
+ while ((n = read(s, buf, sizeof(buf))) > 0)
+ fwrite(buf, 1, n, stdout);
+ (void) close(s);
+ return(0);
+}
+
+static void
+perr(msg)
+ char *msg;
+{
+ extern char *name;
+
+ (void)printf("%s: %s: %s\n", name, msg, strerror(errno));
+}
diff --git a/usr.sbin/lpr/filters/Makefile b/usr.sbin/lpr/filters/Makefile
new file mode 100644
index 000000000000..c9d5c4f02158
--- /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 000000000000..5335f316c564
--- /dev/null
+++ b/usr.sbin/lpr/filters/lpf.c
@@ -0,0 +1,217 @@
+/*
+ * 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[] = "@(#)lpf.c 8.1 (Berkeley) 6/6/93";
+#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 ch, *limit;
+
+ 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/lpc/Makefile b/usr.sbin/lpr/lpc/Makefile
new file mode 100644
index 000000000000..10a3d6964d6c
--- /dev/null
+++ b/usr.sbin/lpr/lpc/Makefile
@@ -0,0 +1,12 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lpc
+CFLAGS+=-I${.CURDIR}/../common_source
+MAN8= lpc.0
+SRCS= lpc.c cmds.c cmdtab.c startdaemon.c common.c
+BINGRP= daemon
+BINMODE=2555
+.PATH: ${.CURDIR}/../common_source
+
+.include "../../Makefile.inc"
+.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 000000000000..7c2b6fe632be
--- /dev/null
+++ b/usr.sbin/lpr/lpc/cmds.c
@@ -0,0 +1,1107 @@
+/*
+ * 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[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * lpc -- line printer control program -- commands:
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.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((int));
+static void cleanpr __P((void));
+static void disablepr __P((void));
+static int doarg __P((char *));
+static int doselect __P((struct dirent *));
+static void enablepr __P((void));
+static void prstat __P((void));
+static void putmsg __P((int, char **));
+static int sortq __P((const void *, const void *));
+static void startpr __P((int));
+static void stoppr __P((void));
+static int touch __P((struct queue *));
+static void unlinkf __P((char *));
+static void upstat __P((char *));
+
+/*
+ * kill an existing daemon and disable printing.
+ */
+void
+doabort(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: abort {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ abortpr(1);
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+ abortpr(1);
+ }
+}
+
+static void
+abortpr(dis)
+ int dis;
+{
+ register FILE *fp;
+ struct stat stbuf;
+ int pid, fd;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ (void) sprintf(line, "%s/%s", SD, LO);
+ printf("%s:\n", printer);
+
+ /*
+ * Turn on the owner execute bit of the lock file to disable printing.
+ */
+ if (dis) {
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0)
+ printf("\tcannot disable printing\n");
+ else {
+ upstat("printing disabled\n");
+ printf("\tprinting disabled\n");
+ }
+ } else if (errno == ENOENT) {
+ if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0)
+ printf("\tcannot create lock file\n");
+ else {
+ (void) close(fd);
+ upstat("printing disabled\n");
+ printf("\tprinting disabled\n");
+ printf("\tno daemon to abort\n");
+ }
+ return;
+ } else {
+ printf("\tcannot stat lock file\n");
+ return;
+ }
+ }
+ /*
+ * Kill the current daemon to stop printing now.
+ */
+ if ((fp = fopen(line, "r")) == NULL) {
+ printf("\tcannot open lock file\n");
+ return;
+ }
+ if (!getline(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) {
+ (void) fclose(fp); /* unlocks as well */
+ printf("\tno daemon to abort\n");
+ return;
+ }
+ (void) fclose(fp);
+ if (kill(pid = atoi(line), SIGTERM) < 0)
+ printf("\tWarning: daemon (pid %d) not killed\n", pid);
+ else
+ printf("\tdaemon (pid %d) killed\n", pid);
+}
+
+/*
+ * Write a message into the status file.
+ */
+static void
+upstat(msg)
+ char *msg;
+{
+ register int fd;
+ char statfile[BUFSIZ];
+
+ if (cgetstr(bp, "st", &ST) == -1)
+ ST = DEFSTAT;
+ (void) sprintf(statfile, "%s/%s", SD, ST);
+ umask(0);
+ fd = open(statfile, O_WRONLY|O_CREAT, 0664);
+ if (fd < 0 || flock(fd, LOCK_EX) < 0) {
+ printf("\tcannot create status file\n");
+ return;
+ }
+ (void) ftruncate(fd, 0);
+ if (msg == (char *)NULL)
+ (void) write(fd, "\n", 1);
+ else
+ (void) write(fd, msg, strlen(msg));
+ (void) close(fd);
+}
+
+/*
+ * Remove all spool files and temporaries from the spooling area.
+ */
+void
+clean(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: clean {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ cleanpr();
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ cleanpr();
+ }
+}
+
+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 incomplete jobs from spooling area.
+ */
+static void
+cleanpr()
+{
+ register int i, n;
+ register char *cp, *cp1, *lp;
+ struct dirent **queue;
+ int nitems;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ printf("%s:\n", printer);
+
+ for (lp = line, cp = SD; *lp++ = *cp++; )
+ ;
+ lp[-1] = '/';
+
+ nitems = scandir(SD, &queue, doselect, sortq);
+ 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) {
+ strcpy(lp, cp);
+ 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).
+ */
+ strcpy(lp, cp);
+ unlinkf(line);
+ }
+ } while (++i < nitems);
+}
+
+static void
+unlinkf(name)
+ char *name;
+{
+ if (unlink(name) < 0)
+ printf("\tcannot remove %s\n", name);
+ else
+ printf("\tremoved %s\n", name);
+}
+
+/*
+ * Enable queuing to the printer (allow lpr's).
+ */
+void
+enable(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: enable {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ enablepr();
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ enablepr();
+ }
+}
+
+static void
+enablepr()
+{
+ struct stat stbuf;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ (void) sprintf(line, "%s/%s", SD, LO);
+ printf("%s:\n", printer);
+
+ /*
+ * Turn off the group execute bit of the lock file to enable queuing.
+ */
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, stbuf.st_mode & 0767) < 0)
+ printf("\tcannot enable queuing\n");
+ else
+ printf("\tqueuing enabled\n");
+ }
+}
+
+/*
+ * Disable queuing.
+ */
+void
+disable(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: disable {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ disablepr();
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ disablepr();
+ }
+}
+
+static void
+disablepr()
+{
+ register int fd;
+ struct stat stbuf;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ (void) sprintf(line, "%s/%s", SD, LO);
+ printf("%s:\n", printer);
+ /*
+ * Turn on the group execute bit of the lock file to disable queuing.
+ */
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, (stbuf.st_mode & 0777) | 010) < 0)
+ printf("\tcannot disable queuing\n");
+ else
+ printf("\tqueuing disabled\n");
+ } else if (errno == ENOENT) {
+ if ((fd = open(line, O_WRONLY|O_CREAT, 0670)) < 0)
+ printf("\tcannot create lock file\n");
+ else {
+ (void) close(fd);
+ printf("\tqueuing disabled\n");
+ }
+ return;
+ } else
+ printf("\tcannot stat lock file\n");
+}
+
+/*
+ * Disable queuing and printing and put a message into the status file
+ * (reason for being down).
+ */
+void
+down(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: down {all | printer} [message ...]\n");
+ return;
+ }
+ if (!strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ putmsg(argc - 2, argv + 2);
+ }
+ return;
+ }
+ printer = argv[1];
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ return;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ return;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ putmsg(argc - 2, argv + 2);
+}
+
+static void
+putmsg(argc, argv)
+ int argc;
+ char **argv;
+{
+ register int fd;
+ register char *cp1, *cp2;
+ char buf[1024];
+ struct stat stbuf;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ if (cgetstr(bp, "st", &ST) == -1)
+ ST = DEFSTAT;
+ printf("%s:\n", printer);
+ /*
+ * Turn on the group execute bit of the lock file to disable queuing and
+ * turn on the owner execute bit of the lock file to disable printing.
+ */
+ (void) sprintf(line, "%s/%s", SD, LO);
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, (stbuf.st_mode & 0777) | 0110) < 0)
+ printf("\tcannot disable queuing\n");
+ else
+ printf("\tprinter and queuing disabled\n");
+ } else if (errno == ENOENT) {
+ if ((fd = open(line, O_WRONLY|O_CREAT, 0770)) < 0)
+ printf("\tcannot create lock file\n");
+ else {
+ (void) close(fd);
+ printf("\tprinter and queuing disabled\n");
+ }
+ return;
+ } else
+ printf("\tcannot stat lock file\n");
+ /*
+ * Write the message into the status file.
+ */
+ (void) sprintf(line, "%s/%s", SD, ST);
+ fd = open(line, O_WRONLY|O_CREAT, 0664);
+ if (fd < 0 || flock(fd, LOCK_EX) < 0) {
+ printf("\tcannot create status file\n");
+ return;
+ }
+ (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++ = *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(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: restart {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ abortpr(0);
+ startpr(0);
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ abortpr(0);
+ startpr(0);
+ }
+}
+
+/*
+ * Enable printing on the specified printer and startup the daemon.
+ */
+void
+startcmd(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: start {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ startpr(1);
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ startpr(1);
+ }
+}
+
+static void
+startpr(enable)
+ int enable;
+{
+ struct stat stbuf;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ (void) sprintf(line, "%s/%s", SD, LO);
+ printf("%s:\n", printer);
+
+ /*
+ * Turn off the owner execute bit of the lock file to enable printing.
+ */
+ if (enable && stat(line, &stbuf) >= 0) {
+ if (chmod(line, stbuf.st_mode & (enable==2 ? 0666 : 0677)) < 0)
+ printf("\tcannot enable printing\n");
+ else
+ printf("\tprinting enabled\n");
+ }
+ if (!startdaemon(printer))
+ printf("\tcouldn't start daemon\n");
+ else
+ printf("\tdaemon started\n");
+}
+
+/*
+ * Print the status of each queue listed or all the queues.
+ */
+void
+status(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ prstat();
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ prstat();
+ }
+}
+
+/*
+ * Print the status of the printer queue.
+ */
+static void
+prstat()
+{
+ struct stat stbuf;
+ register int fd, i;
+ register struct dirent *dp;
+ DIR *dirp;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ if (cgetstr(bp, "st", &ST) == -1)
+ ST = DEFSTAT;
+ printf("%s:\n", printer);
+ (void) sprintf(line, "%s/%s", SD, LO);
+ if (stat(line, &stbuf) >= 0) {
+ printf("\tqueuing is %s\n",
+ (stbuf.st_mode & 010) ? "disabled" : "enabled");
+ printf("\tprinting is %s\n",
+ (stbuf.st_mode & 0100) ? "disabled" : "enabled");
+ } else {
+ printf("\tqueuing is enabled\n");
+ printf("\tprinting is enabled\n");
+ }
+ if ((dirp = opendir(SD)) == 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\n");
+ else if (i == 1)
+ printf("\t1 entry in spool area\n");
+ else
+ printf("\t%d entries in spool area\n", i);
+ fd = open(line, O_RDONLY);
+ if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) {
+ (void) close(fd); /* unlocks as well */
+ printf("\tno daemon present\n");
+ return;
+ }
+ (void) close(fd);
+ putchar('\t');
+ (void) sprintf(line, "%s/%s", SD, ST);
+ fd = open(line, O_RDONLY);
+ if (fd >= 0) {
+ (void) flock(fd, LOCK_SH);
+ 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(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: stop {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ stoppr();
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ stoppr();
+ }
+}
+
+static void
+stoppr()
+{
+ register int fd;
+ struct stat stbuf;
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ (void) sprintf(line, "%s/%s", SD, LO);
+ printf("%s:\n", printer);
+
+ /*
+ * Turn on the owner execute bit of the lock file to disable printing.
+ */
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0)
+ printf("\tcannot disable printing\n");
+ else {
+ upstat("printing disabled\n");
+ printf("\tprinting disabled\n");
+ }
+ } else if (errno == ENOENT) {
+ if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0)
+ printf("\tcannot create lock file\n");
+ else {
+ (void) close(fd);
+ upstat("printing disabled\n");
+ printf("\tprinting disabled\n");
+ }
+ } else
+ printf("\tcannot stat lock file\n");
+}
+
+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;
+
+ if (argc < 3) {
+ printf("Usage: topq printer [jobnum ...] [user ...]\n");
+ return;
+ }
+
+ --argc;
+ printer = *++argv;
+ status = cgetent(&bp, printcapdb, printer);
+ if (status == -2) {
+ printf("cannot open printer description file\n");
+ return;
+ } else if (status == -1) {
+ printf("%s: unknown printer\n", printer);
+ return;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ printf("%s:\n", printer);
+
+ if (chdir(SD) < 0) {
+ printf("\tcannot chdir to %s\n", SD);
+ return;
+ }
+ nitems = getq(&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.
+ */
+ if (changed && stat(LO, &stbuf) >= 0)
+ (void) chmod(LO, (stbuf.st_mode & 0777) | 01);
+}
+
+/*
+ * Reposition the job by changing the modification time of
+ * the control file.
+ */
+static int
+touch(q)
+ struct queue *q;
+{
+ struct timeval tvp[2];
+
+ tvp[0].tv_sec = tvp[1].tv_sec = --mtime;
+ tvp[0].tv_usec = tvp[1].tv_usec = 0;
+ return(utimes(q->q_name, tvp));
+}
+
+/*
+ * 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 = index(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; ) {
+ if ((fp = fopen((*qq)->q_name, "r")) == 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(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: up {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (cgetnext(&bp, printcapdb) > 0) {
+ cp1 = prbuf;
+ cp2 = bp;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ startpr(2);
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == -1) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ startpr(2);
+ }
+}
diff --git a/usr.sbin/lpr/lpc/cmdtab.c b/usr.sbin/lpr/lpc/cmdtab.c
new file mode 100644
index 000000000000..7619791cdcaa
--- /dev/null
+++ b/usr.sbin/lpr/lpc/cmdtab.c
@@ -0,0 +1,79 @@
+/*
+ * 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";
+#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, doabort, 1 },
+ { "clean", cleanhelp, clean, 1 },
+ { "enable", enablehelp, enable, 1 },
+ { "exit", quithelp, quit, 0 },
+ { "disable", disablehelp, disable, 1 },
+ { "down", downhelp, down, 1 },
+ { "help", helphelp, help, 0 },
+ { "quit", quithelp, quit, 0 },
+ { "restart", restarthelp, restart, 0 },
+ { "start", starthelp, startcmd, 1 },
+ { "status", statushelp, status, 0 },
+ { "stop", stophelp, stop, 1 },
+ { "topq", topqhelp, topq, 1 },
+ { "up", uphelp, up, 1 },
+ { "?", 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 000000000000..1b807b132df5
--- /dev/null
+++ b/usr.sbin/lpr/lpc/extern.h
@@ -0,0 +1,58 @@
+/*
+ * 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/cdefs.h>
+
+
+__BEGIN_DECLS
+void clean __P((int, char **));
+void disable __P((int, char **));
+void doabort __P((int, char **));
+void down __P((int, char **));
+void enable __P((int, char **));
+void help __P((int, char **));
+void quit __P((int, char **));
+void restart __P((int, char **));
+void startcmd __P((int, char **));
+void status __P((int, char **));
+void stop __P((int, char **));
+void topq __P((int, char **));
+void up __P((int, char **));
+__END_DECLS
+
+extern int NCMDS;
+extern struct cmd cmdtab[];
diff --git a/usr.sbin/lpr/lpc/lpc.8 b/usr.sbin/lpr/lpc/lpc.8
new file mode 100644
index 000000000000..a786adcad94c
--- /dev/null
+++ b/usr.sbin/lpr/lpc/lpc.8
@@ -0,0 +1,174 @@
+.\" 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.3 (Berkeley) 4/19/94
+.\"
+.Dd April 19, 1994
+.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 lpc
+will prompt for commands from the standard input.
+If arguments are supplied,
+.Nm lpc
+interprets the first argument as a command and the remaining
+arguments as parameters to the command. The standard input
+may be redirected causing
+.Nm lpc
+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 )
+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 .
+.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.
+.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
+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 lpd 8 ,
+.Xr lpr 1 ,
+.Xr lpq 1 ,
+.Xr lprm 1 ,
+.Xr printcap 5
+.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"
+command can be executed by root only
+.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 000000000000..01cfc121a412
--- /dev/null
+++ b/usr.sbin/lpr/lpc/lpc.c
@@ -0,0 +1,277 @@
+/*
+ * 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[] = "@(#)lpc.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <dirent.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "lp.h"
+#include "lpc.h"
+#include "extern.h"
+
+/*
+ * lpc -- line printer control program
+ */
+
+int fromatty;
+
+char cmdline[200];
+int margc;
+char *margv[20];
+int top;
+
+jmp_buf toplevel;
+
+static void cmdscanner __P((int));
+static struct cmd *getcmd __P((char *));
+static void intr __P((int));
+static void makeargv __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct cmd *c;
+
+ 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()) {
+ printf("?Privileged command\n");
+ exit(1);
+ }
+ (*c->c_handler)(argc, argv);
+ exit(0);
+ }
+ fromatty = isatty(fileno(stdin));
+ top = setjmp(toplevel) == 0;
+ if (top)
+ signal(SIGINT, intr);
+ for (;;) {
+ cmdscanner(top);
+ top = 1;
+ }
+}
+
+static void
+intr(signo)
+ int signo;
+{
+ if (!fromatty)
+ exit(0);
+ longjmp(toplevel, 1);
+}
+
+/*
+ * Command parser.
+ */
+static void
+cmdscanner(top)
+ int top;
+{
+ register struct cmd *c;
+
+ if (!top)
+ putchar('\n');
+ for (;;) {
+ if (fromatty) {
+ printf("lpc> ");
+ fflush(stdout);
+ }
+ if (fgets(cmdline, sizeof(cmdline), stdin) == 0)
+ quit(0, NULL);
+ if (cmdline[0] == 0 || cmdline[0] == '\n')
+ break;
+ makeargv();
+ 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()) {
+ printf("?Privileged command\n");
+ continue;
+ }
+ (*c->c_handler)(margc, margv);
+ }
+ longjmp(toplevel, 0);
+}
+
+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;
+
+ margc = 0;
+ for (cp = cmdline; *cp;) {
+ 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;
+ extern int NCMDS;
+
+ 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", HELPINDENT,
+ c->c_name, c->c_help);
+ }
+}
diff --git a/usr.sbin/lpr/lpc/lpc.h b/usr.sbin/lpr/lpc/lpc.h
new file mode 100644
index 000000000000..5e7120315f59
--- /dev/null
+++ b/usr.sbin/lpr/lpc/lpc.h
@@ -0,0 +1,45 @@
+/*
+ * 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 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 */
+};
diff --git a/usr.sbin/lpr/lpd/Makefile b/usr.sbin/lpr/lpd/Makefile
new file mode 100644
index 000000000000..da95bacac731
--- /dev/null
+++ b/usr.sbin/lpr/lpd/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lpd
+CFLAGS+=-I${.CURDIR}/../common_source
+MAN8= lpd.0
+SRCS= lpd.c printjob.c recvjob.c displayq.c rmjob.c startdaemon.c \
+ lpdchar.c common.c
+.PATH: ${.CURDIR}/../common_source
+
+.include "../../Makefile.inc"
+.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 000000000000..64dec12dc9ef
--- /dev/null
+++ b/usr.sbin/lpr/lpd/extern.h
@@ -0,0 +1,39 @@
+/*
+ * 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/cdefs.h>
+
+void printjob __P((void));
+void recvjob __P((void));
diff --git a/usr.sbin/lpr/lpd/lpd.8 b/usr.sbin/lpr/lpd/lpd.8
new file mode 100644
index 000000000000..1e4677ff91e9
--- /dev/null
+++ b/usr.sbin/lpr/lpd/lpd.8
@@ -0,0 +1,249 @@
+.\" 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
+.\"
+.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 l
+.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 l
+The
+.Fl l
+flag causes
+.Nm lpd
+to log valid requests received from the network. This can be useful
+for debugging purposes.
+.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).
+.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 lpd
+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 /dev/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 lpc 8 ,
+.Xr pac 1 ,
+.Xr lpr 1 ,
+.Xr lpq 1 ,
+.Xr lprm 1 ,
+.Xr syslog 3 ,
+.Xr printcap 5
+.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 000000000000..aaf72b76f627
--- /dev/null
+++ b/usr.sbin/lpr/lpd/lpd.c
@@ -0,0 +1,507 @@
+/*
+ * 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 char copyright[] =
+"@(#) Copyright (c) 1983, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)lpd.c 8.4 (Berkeley) 4/17/94";
+#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 <netinet/in.h>
+
+#include <netdb.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+#include "extern.h"
+
+int lflag; /* log requests flag */
+int from_remote; /* from remote socket */
+
+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 *));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int f, funix, finet, options, fromlen;
+ fd_set defreadfds;
+ struct sockaddr_un un, fromunix;
+ struct sockaddr_in sin, frominet;
+ int omask, lfd;
+
+ options = 0;
+ gethostname(host, sizeof(host));
+ name = argv[0];
+
+ while (--argc > 0) {
+ argv++;
+ if (argv[0][0] == '-')
+ switch (argv[0][1]) {
+ case 'd':
+ options |= SO_DEBUG;
+ break;
+ case 'l':
+ lflag++;
+ break;
+ }
+ }
+
+#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);
+ lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644);
+ if (lfd < 0) {
+ syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
+ exit(1);
+ }
+ if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
+ if (errno == EWOULDBLOCK) /* active deamon present */
+ exit(0);
+ syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
+ exit(1);
+ }
+ 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);
+ }
+#define mask(s) (1 << ((s) - 1))
+ omask = sigblock(mask(SIGHUP)|mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));
+ 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);
+ }
+ sigsetmask(omask);
+ FD_ZERO(&defreadfds);
+ FD_SET(funix, &defreadfds);
+ listen(funix, 5);
+ finet = socket(AF_INET, SOCK_STREAM, 0);
+ if (finet >= 0) {
+ struct servent *sp;
+
+ if (options & SO_DEBUG)
+ if (setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) {
+ syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
+ mcleanup(0);
+ }
+ sp = getservbyname("printer", "tcp");
+ if (sp == NULL) {
+ syslog(LOG_ERR, "printer/tcp: unknown service");
+ 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));
+ 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 (FD_ISSET(finet, &readfds)) */ {
+ domain = AF_INET, fromlen = sizeof(frominet);
+ s = accept(finet,
+ (struct sockaddr *)&frominet, &fromlen);
+ }
+ 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);
+ (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;
+{
+ if (lflag)
+ 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()
+{
+ register char *cp;
+ register int n;
+
+ for (;;) {
+ cp = cbuf;
+ do {
+ if (cp >= &cbuf[sizeof(cbuf) - 1])
+ fatal("Command line too long");
+ if ((n = read(1, cp, 1)) != 1) {
+ if (n < 0)
+ fatal("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[*cp], cp+1);
+ else
+ syslog(LOG_INFO, "bad request (%d) from %s",
+ *cp, from);
+ }
+ switch (*cp++) {
+ case '\1': /* check the queue and print any jobs there */
+ printer = cp;
+ printjob();
+ break;
+ case '\2': /* receive files to be queued */
+ if (!from_remote) {
+ syslog(LOG_INFO, "illegal request (%d)", *cp);
+ exit(1);
+ }
+ printer = cp;
+ recvjob();
+ break;
+ case '\3': /* display the queue (short form) */
+ case '\4': /* display the queue (long form) */
+ 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("Too many requests");
+ requ[requests++] = atoi(cp);
+ } else {
+ if (users >= MAXUSERS)
+ fatal("Too many users");
+ user[users++] = cp;
+ }
+ }
+ displayq(cbuf[0] - '\3');
+ exit(0);
+ case '\5': /* 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("Too many requests");
+ requ[requests++] = atoi(cp);
+ } else {
+ if (users >= MAXUSERS)
+ fatal("Too many users");
+ user[users++] = cp;
+ }
+ }
+ rmjob();
+ break;
+ }
+ fatal("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()
+{
+ char *buf;
+ register char *cp;
+ int pid;
+
+ /*
+ * Restart the daemons.
+ */
+ while (cgetnext(&buf, printcapdb) > 0) {
+ for (cp = buf; *cp; cp++)
+ if (*cp == '|' || *cp == ':') {
+ *cp = '\0';
+ break;
+ }
+ if ((pid = fork()) < 0) {
+ syslog(LOG_WARNING, "startup: cannot fork");
+ mcleanup(0);
+ }
+ if (!pid) {
+ printer = buf;
+ cgetclose();
+ printjob();
+ }
+ }
+}
+
+#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;
+ extern char *inet_ntoa();
+
+ f->sin_port = ntohs(f->sin_port);
+ if (f->sin_family != AF_INET || f->sin_port >= IPPORT_RESERVED)
+ fatal("Malformed from address");
+
+ /* Need real hostname for temporary filenames */
+ hp = gethostbyaddr((char *)&f->sin_addr,
+ sizeof(struct in_addr), f->sin_family);
+ if (hp == NULL)
+ fatal("Host name for your address (%s) unknown",
+ inet_ntoa(f->sin_addr));
+
+ (void) strncpy(fromb, hp->h_name, sizeof(fromb));
+ from[sizeof(fromb) - 1] = '\0';
+ from = fromb;
+
+ 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("Your host does not have line printer access");
+ /*NOTREACHED*/
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/usr.sbin/lpr/lpd/lpdchar.c b/usr.sbin/lpr/lpd/lpdchar.c
new file mode 100644
index 000000000000..4a4f5da1ccbe
--- /dev/null
+++ b/usr.sbin/lpr/lpd/lpdchar.c
@@ -0,0 +1,1066 @@
+/*
+ * 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";
+#endif /* not lint */
+
+/*
+ * Character set for line printer daemon
+ */
+#include "lp.local.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/printjob.c b/usr.sbin/lpr/lpd/printjob.c
new file mode 100644
index 000000000000..87c935214747
--- /dev/null
+++ b/usr.sbin/lpr/lpd/printjob.c
@@ -0,0 +1,1377 @@
+/*
+ * 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[] = "@(#)printjob.c 8.2 (Berkeley) 4/16/94";
+#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 <sgtty.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.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 lfd; /* lock file descriptor */
+static int ofd; /* output filter file descriptor */
+static int ofilter; /* id of output filter, if any */
+static int pfd; /* prstatic inter file descriptor */
+static int pid; /* pid of lpd process */
+static int prchild; /* id of pr process */
+static int remote; /* true if sending files to remote */
+static char title[80]; /* ``pr'' title */
+static int tof; /* true if at top of form */
+
+static char class[32]; /* classification field */
+static char fromhost[32]; /* 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 output */
+static char width[10] = "-w"; /* page width in static characters */
+
+static void abortpr __P((int));
+static void banner __P((char *, char *));
+static int dofork __P((int));
+static int dropit __P((int));
+static void init __P((void));
+static void openpr __P((void));
+static int print __P((int, char *));
+static int printit __P((char *));
+static void pstatus __P((const char *, ...));
+static char response __P((void));
+static void scan_out __P((int, char *, int));
+static char *scnline __P((int, char *, int));
+static int sendfile __P((int, char *));
+static int sendit __P((char *));
+static void sendmail __P((char *, int));
+static void setty __P((void));
+
+void
+printjob()
+{
+ struct stat stb;
+ register struct queue *q, **qp;
+ struct queue **queue;
+ register int i, nitems;
+ long pidoff;
+ int count = 0;
+
+ init(); /* set up capabilities */
+ (void) write(1, "", 1); /* ack that daemon is started */
+ (void) close(2); /* set up log file */
+ if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
+ syslog(LOG_ERR, "%s: %m", LF);
+ (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(SD) < 0) {
+ syslog(LOG_ERR, "%s: %m", SD);
+ exit(1);
+ }
+ if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
+ exit(0); /* printing disabled */
+ lfd = open(LO, O_WRONLY|O_CREAT, 0644);
+ if (lfd < 0) {
+ syslog(LOG_ERR, "%s: %s: %m", printer, LO);
+ exit(1);
+ }
+ if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
+ if (errno == EWOULDBLOCK) /* active deamon present */
+ exit(0);
+ syslog(LOG_ERR, "%s: %s: %m", printer, LO);
+ 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", printer, LO);
+ exit(1);
+ }
+ /*
+ * search the spool directory for work and sort by queue order.
+ */
+ if ((nitems = getq(&queue)) < 0) {
+ syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
+ exit(1);
+ }
+ if (nitems == 0) /* no work to do */
+ exit(0);
+ if (stb.st_mode & 01) { /* reset queue flag */
+ if (fchmod(lfd, stb.st_mode & 0776) < 0)
+ syslog(LOG_ERR, "%s: %s: %m", printer, LO);
+ }
+ openpr(); /* 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;
+ restart:
+ (void) lseek(lfd, (off_t)pidoff, 0);
+ (void) sprintf(line, "%s\n", q->q_name);
+ i = strlen(line);
+ if (write(lfd, line, i) != i)
+ syslog(LOG_ERR, "%s: %s: %m", printer, LO);
+ if (!remote)
+ i = printit(q->q_name);
+ else
+ i = sendit(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 & 0100)
+ goto done;
+ /* rebuild queue (after lpc topq) */
+ if (stb.st_mode & 01) {
+ for (free((char *) q); nitems--; free((char *) q))
+ q = *qp++;
+ if (fchmod(lfd, stb.st_mode & 0776) < 0)
+ syslog(LOG_WARNING, "%s: %s: %m",
+ printer, LO);
+ break;
+ }
+ }
+ if (i == OK) /* file ok and printed */
+ count++;
+ else if (i == REPRINT) { /* try reprinting the job */
+ syslog(LOG_INFO, "restarting %s", printer);
+ if (ofilter > 0) {
+ kill(ofilter, SIGCONT); /* to be sure */
+ (void) close(ofd);
+ while ((i = wait(0)) > 0 && i != ofilter)
+ ;
+ ofilter = 0;
+ }
+ (void) close(pfd); /* close printer */
+ if (ftruncate(lfd, pidoff) < 0)
+ syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
+ openpr(); /* try to reopen printer */
+ goto restart;
+ }
+ }
+ free((char *) queue);
+ /*
+ * search the spool directory for more work.
+ */
+ if ((nitems = getq(&queue)) < 0) {
+ syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
+ exit(1);
+ }
+ if (nitems == 0) { /* no more work to do */
+ done:
+ if (count > 0) { /* Files actually printed */
+ if (!SF && !tof)
+ (void) write(ofd, FF, strlen(FF));
+ if (TR != NULL) /* output trailer */
+ (void) write(ofd, TR, strlen(TR));
+ }
+ (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(file)
+ 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", printer, file);
+ return(OK);
+ }
+ /*
+ * Reset troff fonts.
+ */
+ for (i = 0; i < 4; i++)
+ strcpy(fonts[i], ifonts[i]);
+ sprintf(&width[2], "%d", PW);
+ strcpy(indent+2, "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
+ * 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
+ *
+ * getline reads a line and expands tabs to blanks
+ */
+
+ /* pass 1 */
+
+ while (getline(cfp))
+ switch (line[0]) {
+ case 'H':
+ strcpy(fromhost, line+1);
+ if (class[0] == '\0')
+ strncpy(class, line+1, sizeof(class)-1);
+ continue;
+
+ case 'P':
+ strncpy(logname, line+1, sizeof(logname)-1);
+ if (RS) { /* restricted */
+ if (getpwnam(logname) == NULL) {
+ bombed = NOACCT;
+ sendmail(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);
+ 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));
+ continue;
+
+ case 'T': /* header title for pr */
+ strncpy(title, line+1, sizeof(title)-1);
+ continue;
+
+ case 'L': /* identification line */
+ if (!SH && !HL)
+ banner(line+1, jobname);
+ continue;
+
+ case '1': /* troff fonts */
+ case '2':
+ case '3':
+ case '4':
+ if (line[1] != '\0')
+ strcpy(fonts[line[0]-'1'], line+1);
+ continue;
+
+ case 'W': /* page width */
+ strncpy(width+2, line+1, sizeof(width)-3);
+ continue;
+
+ case 'I': /* indent amount */
+ strncpy(indent+2, line+1, sizeof(indent)-3);
+ continue;
+
+ default: /* some file to print */
+ switch (i = print(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(logname, bombed);
+ }
+ title[0] = '\0';
+ continue;
+
+ case 'N':
+ case 'U':
+ case 'M':
+ continue;
+ }
+
+ /* pass 2 */
+
+pass2:
+ fseek(cfp, 0L, 0);
+ while (getline(cfp))
+ switch (line[0]) {
+ case 'L': /* identification line */
+ if (!SH && HL)
+ banner(line+1, jobname);
+ continue;
+
+ case 'M':
+ if (bombed < NOACCT) /* already sent if >= NOACCT */
+ sendmail(line+1, bombed);
+ continue;
+
+ case 'U':
+ (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(format, file)
+ int format;
+ char *file;
+{
+ register int n;
+ 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);
+ if (!SF && !tof) { /* start on a fresh page */
+ (void) write(ofd, FF, strlen(FF));
+ tof = 1;
+ }
+ if (IF == NULL && (format == 'f' || format == 'l')) {
+ 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 (IF == NULL) { /* use output filter */
+ prog = _PATH_PR;
+ av[0] = "pr";
+ av[1] = width;
+ av[2] = length;
+ av[3] = "-h";
+ av[4] = *title ? title : " ";
+ av[5] = 0;
+ fo = ofd;
+ goto start;
+ }
+ pipe(p);
+ if ((prchild = dofork(DORETURN)) == 0) { /* child */
+ dup2(fi, 0); /* file is stdin */
+ dup2(p[1], 1); /* pipe is stdout */
+ for (n = 3; n < NOFILE; n++)
+ (void) close(n);
+ execl(_PATH_PR, "pr", width, length,
+ "-h", *title ? title : " ", 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 = IF;
+ av[1] = width;
+ av[2] = length;
+ av[3] = indent;
+ n = 4;
+ break;
+ case 'l': /* like 'f' but pass control characters */
+ prog = IF;
+ av[1] = "-c";
+ av[2] = width;
+ av[3] = length;
+ av[4] = indent;
+ n = 5;
+ break;
+ case 'r': /* print a fortran text file */
+ prog = RF;
+ 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", 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') ? TF : (format == 'n') ? NF : DF;
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ case 'c': /* print cifplot output */
+ prog = CF;
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ case 'g': /* print plot(1G) output */
+ prog = GF;
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ case 'v': /* print raster output */
+ prog = VF;
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ default:
+ (void) close(fi);
+ syslog(LOG_ERR, "%s: illegal format character '%c'",
+ printer, format);
+ return(ERROR);
+ }
+ if ((av[0] = rindex(prog, '/')) != NULL)
+ av[0]++;
+ else
+ av[0] = prog;
+ av[n++] = "-n";
+ av[n++] = logname;
+ av[n++] = "-h";
+ av[n++] = fromhost;
+ av[n++] = AF;
+ 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 (%d)",
+ printer, status.w_retcode);
+ return(REPRINT);
+ }
+ stopped++;
+ }
+start:
+ if ((child = dofork(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);
+ for (n = 3; n < NOFILE; n++)
+ (void) close(n);
+ 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);
+ }
+ }
+ 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: Daemon filter '%c' terminated (%d)",
+ printer, format, status.w_termsig);
+ return(ERROR);
+ }
+ switch (status.w_retcode) {
+ case 0:
+ tof = 1;
+ return(OK);
+ case 1:
+ return(REPRINT);
+ default:
+ syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
+ printer, format, status.w_retcode);
+ case 2:
+ return(ERROR);
+ }
+}
+
+/*
+ * 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(file)
+ char *file;
+{
+ register int i, err = OK;
+ char *cp, last[BUFSIZ];
+
+ /*
+ * open control file
+ */
+ if ((cfp = fopen(file, "r")) == NULL)
+ return(OK);
+ /*
+ * 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;
+ continue;
+ }
+ if (line[0] >= 'a' && line[0] <= 'z') {
+ strcpy(last, line);
+ while (i = getline(cfp))
+ if (strcmp(last, line))
+ break;
+ switch (sendfile('\3', last+1)) {
+ case OK:
+ if (i)
+ goto again;
+ break;
+ case REPRINT:
+ (void) fclose(cfp);
+ return(REPRINT);
+ case ACCESS:
+ sendmail(logname, ACCESS);
+ case ERROR:
+ err = ERROR;
+ }
+ break;
+ }
+ }
+ if (err == OK && sendfile('\2', file) > 0) {
+ (void) fclose(cfp);
+ return(REPRINT);
+ }
+ /*
+ * pass 2
+ */
+ fseek(cfp, 0L, 0);
+ while (getline(cfp))
+ if (line[0] == 'U')
+ (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(type, file)
+ int type;
+ char *file;
+{
+ register int f, i, amt;
+ struct stat stb;
+ char buf[BUFSIZ];
+ int sizerr, resp;
+
+ 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);
+ (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()) < 0 || resp == '\1') {
+ (void) close(f);
+ return(REPRINT);
+ } else if (resp == '\0')
+ break;
+ if (i == 0)
+ pstatus("no space on remote; waiting for queue to drain");
+ if (i == 10)
+ syslog(LOG_ALERT, "%s: can't send to %s; queue full",
+ printer, RM);
+ sleep(5 * 60);
+ }
+ if (i)
+ pstatus("sending to %s", RM);
+ sizerr = 0;
+ 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);
+ return(REPRINT);
+ }
+ }
+
+
+
+
+ (void) close(f);
+ if (sizerr) {
+ syslog(LOG_INFO, "%s: %s: changed size", printer, file);
+ /* tell recvjob to ignore this file */
+ (void) write(pfd, "\1", 1);
+ return(ERROR);
+ }
+ if (write(pfd, "", 1) != 1 || response())
+ return(REPRINT);
+ 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()
+{
+ char resp;
+
+ if (read(pfd, &resp, 1) != 1) {
+ syslog(LOG_INFO, "%s: lost connection", printer);
+ return(-1);
+ }
+ return(resp);
+}
+
+/*
+ * Banner printing stuff
+ */
+static void
+banner(name1, name2)
+ char *name1, *name2;
+{
+ time_t tvec;
+ extern char *ctime();
+
+ time(&tvec);
+ if (!SF && !tof)
+ (void) write(ofd, FF, strlen(FF));
+ if (SB) { /* 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(ofd, name1, '\0');
+ (void) write(ofd, "\n\n", 2);
+ scan_out(ofd, name2, '\0');
+ if (class[0]) {
+ (void) write(ofd,"\n\n\n",3);
+ scan_out(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 (!SF)
+ (void) write(ofd, FF, strlen(FF));
+ tof = 1;
+}
+
+static char *
+scnline(key, p, c)
+ register int key;
+ register char *p;
+ int c;
+{
+ register scnwidth;
+
+ for (scnwidth = WIDTH; --scnwidth;) {
+ key <<= 1;
+ *p++ = key & 0200 ? c : BACKGND;
+ }
+ return (p);
+}
+
+#define TRC(q) (((q)-' ')&0177)
+
+static void
+scan_out(scfd, scsp, dlm)
+ int scfd, dlm;
+ char *scsp;
+{
+ register char *strp;
+ register nchrs, j;
+ char outbuf[LINELEN+1], *sp, c, cc;
+ int d, scnhgt;
+ extern char scnkey[][HEIGHT]; /* in lpdchar.c */
+
+ 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[c][scnhgt-1-d], strp, cc);
+ if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(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(user, bombed)
+ char *user;
+ int bombed;
+{
+ register int i;
+ int p[2], s;
+ register char *cp;
+ char buf[100];
+ struct stat stb;
+ FILE *fp;
+
+ pipe(p);
+ if ((s = dofork(DORETURN)) == 0) { /* child */
+ dup2(p[0], 0);
+ for (i = 3; i < NOFILE; i++)
+ (void) close(i);
+ if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
+ cp++;
+ else
+ cp = _PATH_SENDMAIL;
+ sprintf(buf, "%s@%s", user, fromhost);
+ execl(_PATH_SENDMAIL, cp, buf, 0);
+ exit(0);
+ } else if (s > 0) { /* parent */
+ dup2(p[1], 1);
+ printf("To: %s@%s\n", user, fromhost);
+ printf("Subject: printer job\n\n");
+ printf("Your printer job ");
+ if (*jobname)
+ printf("(%s) ", jobname);
+ switch (bombed) {
+ case OK:
+ printf("\ncompleted successfully\n");
+ break;
+ default:
+ case FATALERR:
+ printf("\ncould not be printed\n");
+ break;
+ case NOACCT:
+ printf("\ncould not be printed without an account on %s\n", host);
+ break;
+ case FILTERERR:
+ if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
+ (fp = fopen(tempfile, "r")) == NULL) {
+ printf("\nwas printed but had some errors\n");
+ break;
+ }
+ printf("\nwas printed but had the following errors:\n");
+ while ((i = getc(fp)) != EOF)
+ putchar(i);
+ (void) fclose(fp);
+ break;
+ case ACCESS:
+ printf("\nwas not printed because it was not linked to the original file\n");
+ }
+ fflush(stdout);
+ (void) close(1);
+ }
+ (void) close(p[0]);
+ (void) close(p[1]);
+ wait(&s);
+}
+
+/*
+ * dofork - fork with retries on failure
+ */
+static int
+dofork(action)
+ int action;
+{
+ register int i, pid;
+
+ 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)
+ setuid(DU);
+ 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)
+ ;
+ exit(0);
+}
+
+static void
+init()
+{
+ int status;
+ char *s;
+
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ syslog(LOG_ERR, "can't open printer description file");
+ exit(1);
+ } else if (status == -1) {
+ syslog(LOG_ERR, "unknown printer: %s", printer);
+ exit(1);
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ if (cgetstr(bp, "lp", &LP) == -1)
+ LP = _PATH_DEFDEVLP;
+ if (cgetstr(bp, "rp", &RP) == -1)
+ RP = DEFLP;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ if (cgetstr(bp, "st", &ST) == -1)
+ ST = DEFSTAT;
+ if (cgetstr(bp, "lf", &LF) == -1)
+ LF = _PATH_CONSOLE;
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetnum(bp, "du", &DU) < 0)
+ DU = DEFUID;
+ if (cgetstr(bp,"ff", &FF) == -1)
+ FF = DEFFF;
+ if (cgetnum(bp, "pw", &PW) < 0)
+ PW = DEFWIDTH;
+ sprintf(&width[2], "%d", PW);
+ if (cgetnum(bp, "pl", &PL) < 0)
+ PL = DEFLENGTH;
+ sprintf(&length[2], "%d", PL);
+ if (cgetnum(bp,"px", &PX) < 0)
+ PX = 0;
+ sprintf(&pxwidth[2], "%d", PX);
+ if (cgetnum(bp, "py", &PY) < 0)
+ PY = 0;
+ sprintf(&pxlength[2], "%d", PY);
+ cgetstr(bp, "rm", &RM);
+ if (s = checkremote())
+ syslog(LOG_WARNING, s);
+
+ cgetstr(bp, "af", &AF);
+ cgetstr(bp, "of", &OF);
+ cgetstr(bp, "if", &IF);
+ cgetstr(bp, "rf", &RF);
+ cgetstr(bp, "tf", &TF);
+ cgetstr(bp, "nf", &NF);
+ cgetstr(bp, "df", &DF);
+ cgetstr(bp, "gf", &GF);
+ cgetstr(bp, "vf", &VF);
+ cgetstr(bp, "cf", &CF);
+ cgetstr(bp, "tr", &TR);
+
+ RS = (cgetcap(bp, "rs", ':') != NULL);
+ SF = (cgetcap(bp, "sf", ':') != NULL);
+ SH = (cgetcap(bp, "sh", ':') != NULL);
+ SB = (cgetcap(bp, "sb", ':') != NULL);
+ HL = (cgetcap(bp, "hl", ':') != NULL);
+ RW = (cgetcap(bp, "rw", ':') != NULL);
+
+ cgetnum(bp, "br", &BR);
+ if (cgetnum(bp, "fc", &FC) < 0)
+ FC = 0;
+ if (cgetnum(bp, "fs", &FS) < 0)
+ FS = 0;
+ if (cgetnum(bp, "xc", &XC) < 0)
+ XC = 0;
+ if (cgetnum(bp, "xs", &XS) < 0)
+ XS = 0;
+
+ tof = (cgetcap(bp, "fo", ':') == NULL);
+}
+
+/*
+ * Acquire line printer or remote connection.
+ */
+static void
+openpr()
+{
+ register int i, n;
+ int resp;
+
+ if (!sendtorem && *LP) {
+ for (i = 1; ; i = i < 32 ? i << 1 : i) {
+ pfd = open(LP, RW ? O_RDWR : O_WRONLY);
+ if (pfd >= 0)
+ break;
+ if (errno == ENOENT) {
+ syslog(LOG_ERR, "%s: %m", LP);
+ exit(1);
+ }
+ if (i == 1)
+ pstatus("waiting for %s to become ready (offline ?)", printer);
+ sleep(i);
+ }
+ if (isatty(pfd))
+ setty();
+ pstatus("%s is ready and printing", printer);
+ } else if (RM != NULL) {
+ for (i = 1; ; i = i < 256 ? i << 1 : i) {
+ resp = -1;
+ pfd = getport(RM);
+ if (pfd >= 0) {
+ (void) sprintf(line, "\2%s\n", RP);
+ n = strlen(line);
+ if (write(pfd, line, n) == n &&
+ (resp = response()) == '\0')
+ break;
+ (void) close(pfd);
+ }
+ if (i == 1) {
+ if (resp < 0)
+ pstatus("waiting for %s to come up", RM);
+ else {
+ pstatus("waiting for queue to be enabled on %s", RM);
+ i = 256;
+ }
+ }
+ sleep(i);
+ }
+ pstatus("sending to %s", RM);
+ remote = 1;
+ } else {
+ syslog(LOG_ERR, "%s: no line printer device or host name",
+ printer);
+ exit(1);
+ }
+ /*
+ * Start up an output filter, if needed.
+ */
+ if (!remote && OF) {
+ int p[2];
+ char *cp;
+
+ pipe(p);
+ if ((ofilter = dofork(DOABORT)) == 0) { /* child */
+ dup2(p[0], 0); /* pipe is std in */
+ dup2(pfd, 1); /* printer is std out */
+ for (i = 3; i < NOFILE; i++)
+ (void) close(i);
+ if ((cp = rindex(OF, '/')) == NULL)
+ cp = OF;
+ else
+ cp++;
+ execl(OF, cp, width, length, 0);
+ syslog(LOG_ERR, "%s: %s: %m", printer, OF);
+ exit(1);
+ }
+ (void) close(p[0]); /* close input side */
+ ofd = p[1]; /* use pipe for output */
+ } else {
+ ofd = pfd;
+ ofilter = 0;
+ }
+}
+
+struct bauds {
+ int baud;
+ int speed;
+} bauds[] = {
+ 50, B50,
+ 75, B75,
+ 110, B110,
+ 134, B134,
+ 150, B150,
+ 200, B200,
+ 300, B300,
+ 600, B600,
+ 1200, B1200,
+ 1800, B1800,
+ 2400, B2400,
+ 4800, B4800,
+ 9600, B9600,
+ 19200, EXTA,
+ 38400, EXTB,
+ 0, 0
+};
+
+/*
+ * setup tty lines.
+ */
+static void
+setty()
+{
+ struct sgttyb ttybuf;
+ register struct bauds *bp;
+
+ if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
+ exit(1);
+ }
+ if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
+ exit(1);
+ }
+ if (BR > 0) {
+ for (bp = bauds; bp->baud; bp++)
+ if (BR == bp->baud)
+ break;
+ if (!bp->baud) {
+ syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
+ exit(1);
+ }
+ ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
+ }
+ ttybuf.sg_flags &= ~FC;
+ ttybuf.sg_flags |= FS;
+ if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
+ exit(1);
+ }
+ if (XC) {
+ if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
+ exit(1);
+ }
+ }
+ if (XS) {
+ if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
+ exit(1);
+ }
+ }
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+pstatus(const char *msg, ...)
+#else
+pstatus(msg, va_alist)
+ char *msg;
+ va_dcl
+#endif
+{
+ register int fd;
+ char buf[BUFSIZ];
+ va_list ap;
+#if __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+
+ umask(0);
+ fd = open(ST, O_WRONLY|O_CREAT, 0664);
+ if (fd < 0 || flock(fd, LOCK_EX) < 0) {
+ syslog(LOG_ERR, "%s: %s: %m", printer, ST);
+ exit(1);
+ }
+ ftruncate(fd, 0);
+ (void)vsnprintf(buf, sizeof(buf), msg, ap);
+ va_end(ap);
+ strcat(buf, "\n");
+ (void) write(fd, buf, strlen(buf));
+ (void) close(fd);
+}
diff --git a/usr.sbin/lpr/lpd/recvjob.c b/usr.sbin/lpr/lpd/recvjob.c
new file mode 100644
index 000000000000..67a61830ff29
--- /dev/null
+++ b/usr.sbin/lpr/lpd/recvjob.c
@@ -0,0 +1,358 @@
+/*
+ * 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[] = "@(#)recvjob.c 8.1 (Berkeley) 6/6/93";
+#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[40]; /* data files */
+static int minfree; /* keep at least minfree blocks available */
+static char *sp = "";
+static char tfname[40]; /* 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((char *, int));
+static int readjob __P((void));
+
+
+void
+recvjob()
+{
+ struct stat stb;
+ int status;
+
+ /*
+ * Perform lookup for printer name or abbreviation
+ */
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2)
+ frecverr("cannot open printer description file");
+ else if (status == -1)
+ frecverr("unknown printer %s", printer);
+ else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ if (cgetstr(bp, "lf", &LF) == -1)
+ LF = _PATH_CONSOLE;
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+
+ (void) close(2); /* set up log file */
+ if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
+ syslog(LOG_ERR, "%s: %m", LF);
+ (void) open(_PATH_DEVNULL, O_WRONLY);
+ }
+
+ if (chdir(SD) < 0)
+ frecverr("%s: %s: %m", printer, SD);
+ if (stat(LO, &stb) == 0) {
+ if (stb.st_mode & 010) {
+ /* queue is disabled */
+ putchar('\1'); /* return error code */
+ exit(1);
+ }
+ } else if (stat(SD, &stb) < 0)
+ frecverr("%s: %s: %m", printer, SD);
+ minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */
+ signal(SIGTERM, rcleanup);
+ signal(SIGPIPE, rcleanup);
+
+ if (readjob())
+ printjob();
+}
+
+/*
+ * Read printer jobs sent by lpd and copy them to the spooling directory.
+ * Return the number of jobs successfully transfered.
+ */
+static int
+readjob()
+{
+ register int size, nfiles;
+ register char *cp;
+
+ ack();
+ nfiles = 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",printer);
+ return(nfiles);
+ }
+ } while (*cp++ != '\n');
+ *--cp = '\0';
+ cp = line;
+ switch (*cp++) {
+ case '\1': /* cleanup because data sent was bad */
+ rcleanup(0);
+ continue;
+
+ case '\2': /* read cf file */
+ size = 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
+ */
+ strcpy(cp + 6, from);
+ strcpy(tfname, cp);
+ tfname[0] = 't';
+ if (!chksize(size)) {
+ (void) write(1, "\2", 1);
+ continue;
+ }
+ if (!readfile(tfname, size)) {
+ rcleanup(0);
+ continue;
+ }
+ if (link(tfname, cp) < 0)
+ frecverr("%s: %m", tfname);
+ (void) unlink(tfname);
+ tfname[0] = '\0';
+ nfiles++;
+ continue;
+
+ case '\3': /* read df file */
+ 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) strcpy(dfname, cp);
+ if (index(dfname, '/'))
+ frecverr("readjob: %s: illegal path name",
+ dfname);
+ (void) readfile(dfname, size);
+ continue;
+ }
+ frecverr("protocol screwup: %s", line);
+ }
+}
+
+/*
+ * Read files send by lpd and copy them to the spooling directory.
+ */
+static int
+readfile(file, size)
+ 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("readfile: %s: illegal path name: %m", file);
+ 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("Lost connection");
+ 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", file);
+ if (noresponse()) { /* file sent had bad data in it */
+ (void) unlink(file);
+ return(0);
+ }
+ ack();
+ return(1);
+}
+
+static int
+noresponse()
+{
+ char resp;
+
+ if (read(1, &resp, 1) != 1)
+ frecverr("Lost connection");
+ 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])
+ (void) unlink(tfname);
+ if (dfname[0])
+ do {
+ do
+ (void) unlink(dfname);
+ while (dfname[2]-- != 'A');
+ dfname[2] = 'z';
+ } while (dfname[0]-- != 'd');
+ dfname[0] = '\0';
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+static void
+#if __STDC__
+frecverr(const char *msg, ...)
+#else
+frecverr(msg, va_alist)
+ char *msg;
+ va_dcl
+#endif
+{
+ extern char *fromb;
+ va_list ap;
+#if __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+ rcleanup(0);
+ syslog(LOG_ERR, "%s", fromb);
+ vsyslog(LOG_ERR, msg, ap);
+ va_end(ap);
+ 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 000000000000..1c730c1a4b8d
--- /dev/null
+++ b/usr.sbin/lpr/lpq/Makefile
@@ -0,0 +1,12 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lpq
+CFLAGS+=-I${.CURDIR}/../common_source
+SRCS= lpq.c displayq.c common.c
+BINOWN= root
+BINGRP= daemon
+BINMODE=6555
+BINDIR= /usr/bin
+.PATH: ${.CURDIR}/../common_source
+
+.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 000000000000..50e1474121e1
--- /dev/null
+++ b/usr.sbin/lpr/lpq/lpq.1
@@ -0,0 +1,134 @@
+.\" 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.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt LPQ 1
+.Os BSD 4.2
+.Sh NAME
+.Nm lpq
+.Nd spool queue examination program
+.Sh SYNOPSIS
+.Nm lpq
+.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.
+.El
+.Pp
+For each job submitted (i.e. invocation of
+.Xr lpr 1 )
+.Nm lpq
+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 lpq
+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 /usr/share/misc/termcap -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.
+.It Pa /usr/share/misc/termcap
+For manipulating the screen for repeated display.
+.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 lpq
+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 000000000000..b091e8e942ea
--- /dev/null
+++ b/usr.sbin/lpr/lpq/lpq.c
@@ -0,0 +1,126 @@
+/*
+ * 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[] = "@(#)lpq.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Spool Queue examination program
+ *
+ * lpq [-l] [-Pprinter] [user...] [job...]
+ *
+ * -l long output
+ * -P used to identify printer as per lpr/lprm
+ */
+
+#include <sys/param.h>
+
+#include <syslog.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "lp.h"
+#include "lp.local.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 */
+
+void usage __P((void));
+
+int
+main(argc, argv)
+ register int argc;
+ register char **argv;
+{
+ extern char *optarg;
+ extern int optind;
+ int ch, lflag; /* long output option */
+
+ name = *argv;
+ if (gethostname(host, sizeof(host))) {
+ perror("lpq: gethostname");
+ exit(1);
+ }
+ openlog("lpd", 0, LOG_LPR);
+
+ lflag = 0;
+ while ((ch = getopt(argc, argv, "lP:")) != EOF)
+ switch((char)ch) {
+ case 'l': /* long output */
+ ++lflag;
+ break;
+ case 'P': /* printer name */
+ printer = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+
+ if (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("too many requests");
+ requ[requests++] = atoi(*argv);
+ }
+ else {
+ if (users >= MAXUSERS)
+ fatal("too many users");
+ user[users++] = *argv;
+ }
+
+ displayq(lflag);
+ exit(0);
+}
+
+void
+usage()
+{
+ puts("usage: lpq [-l] [-Pprinter] [user ...] [job ...]");
+ exit(1);
+}
diff --git a/usr.sbin/lpr/lpr/Makefile b/usr.sbin/lpr/lpr/Makefile
new file mode 100644
index 000000000000..9a3cbfd591e6
--- /dev/null
+++ b/usr.sbin/lpr/lpr/Makefile
@@ -0,0 +1,12 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lpr
+CFLAGS+=-I${.CURDIR}/../common_source
+SRCS= lpr.c startdaemon.c common.c
+BINOWN= root
+BINGRP= daemon
+BINMODE=6555
+BINDIR= /usr/bin
+.PATH: ${.CURDIR}/../common_source
+
+.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 000000000000..382d50886a93
--- /dev/null
+++ b/usr.sbin/lpr/lpr/lpr.1
@@ -0,0 +1,256 @@
+.\" 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.
+.\"
+.\" @(#)lpr.1 8.1 (Berkeley) 6/6/93
+.\"
+.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 T Ar title
+.Op Fl U Ar user
+.Op Fl i Op Ar numcols
+.Op Fl 1234 Ar font
+.Op Fl w Ns 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.
+.Bl -tag -width indent
+.It Fl c
+The files are assumed to contain data produced by
+.Xr cifplot 1
+.It Fl d
+The files are assumed to contain data from
+.Em tex
+.Pf ( Tn DVI
+format from Stanford).
+.It Fl f
+Use a filter which interprets the first character of each line as a
+standard
+.Tn FORTRAN
+carriage control character.
+.It Fl g
+The files are assumed to contain standard plot data as produced by the
+.Xr plot
+routines (see also
+.Xr plot
+for the filters used by the printer spooler).
+.It Fl l
+Use a filter which allows control characters to be printed and suppresses
+page breaks.
+.It Fl n
+The files are assumed to contain data from
+.Em ditroff
+(device independent troff).
+.It Fl p
+Use
+.Xr pr 1
+to format the files (equivalent to
+.Xr print ) .
+.It Fl t
+The files are assumed to contain data from
+.Xr troff 1
+(cat phototypesetter commands).
+.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 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 i Op numcols
+The output is indented. If the next argument
+is numeric
+.Pq Ar numcols ,
+it is used as the number of blanks to be printed before each
+line; otherwise, 8 characters are printed.
+.It Fl w Ns 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 lpr :
+.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 lpr
+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 lpr
+will print a message saying so and will not put jobs in the queue.
+If a connection to
+.Xr lpd 1
+on the local machine cannot be made,
+.Nm lpr
+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 1 .
+.Sh BUGS
+Fonts for
+.Xr troff 1
+and
+.Xr tex
+reside on the host with the printer. It is currently not possible to
+use local font libraries.
diff --git a/usr.sbin/lpr/lpr/lpr.c b/usr.sbin/lpr/lpr/lpr.c
new file mode 100644
index 000000000000..8e9c45f955e4
--- /dev/null
+++ b/usr.sbin/lpr/lpr/lpr.c
@@ -0,0 +1,744 @@
+/*
+ * 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 char copyright[] =
+"@(#) Copyright (c) 1983, 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)lpr.c 8.3 (Berkeley) 3/30/94";
+#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 <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 int userid; /* user id */
+static char *width; /* width for versatec printing */
+
+static struct stat statb;
+
+static void card __P((int, char *));
+static void chkprinter __P((char *));
+static void cleanup __P((int));
+static void copy __P((int, char []));
+static void fatal2 __P((const char *, ...));
+static char *itoa __P((int));
+static char *linked __P((char *));
+static char *lmktemp __P((char *, int, int));
+static void mktemps __P((void));
+static int nfile __P((char *));
+static int test __P((char *));
+
+void
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct passwd *pw;
+ struct group *gptr;
+ extern char *itoa();
+ register char *arg, *cp;
+ char buf[BUFSIZ];
+ int i, f;
+ struct stat stb;
+
+ 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);
+
+ while (argc > 1 && argv[1][0] == '-') {
+ argc--;
+ arg = *++argv;
+ switch (arg[1]) {
+
+ case 'P': /* specifiy printer name */
+ if (arg[2])
+ printer = &arg[2];
+ else if (argc > 1) {
+ argc--;
+ printer = *++argv;
+ }
+ break;
+
+ case 'C': /* classification spec */
+ hdr++;
+ if (arg[2])
+ class = &arg[2];
+ else if (argc > 1) {
+ argc--;
+ class = *++argv;
+ }
+ break;
+
+ case 'U': /* user name */
+ hdr++;
+ if (arg[2])
+ person = &arg[2];
+ else if (argc > 1) {
+ argc--;
+ person = *++argv;
+ }
+ break;
+
+ case 'J': /* job name */
+ hdr++;
+ if (arg[2])
+ jobname = &arg[2];
+ else if (argc > 1) {
+ argc--;
+ jobname = *++argv;
+ }
+ break;
+
+ case 'T': /* pr's title line */
+ if (arg[2])
+ title = &arg[2];
+ else if (argc > 1) {
+ argc--;
+ title = *++argv;
+ }
+ break;
+
+ case 'l': /* literal output */
+ case 'p': /* print using ``pr'' */
+ case 't': /* print troff output (cat files) */
+ case 'n': /* print ditroff output */
+ case 'd': /* print tex output (dvi files) */
+ case 'g': /* print graph(1G) output */
+ case 'c': /* print cifplot output */
+ case 'v': /* print vplot output */
+ format = arg[1];
+ break;
+
+ case 'f': /* print fortran output */
+ format = 'r';
+ break;
+
+ case '4': /* troff fonts */
+ case '3':
+ case '2':
+ case '1':
+ if (argc > 1) {
+ argc--;
+ fonts[arg[1] - '1'] = *++argv;
+ }
+ break;
+
+ case 'w': /* versatec page width */
+ width = arg+2;
+ break;
+
+ case 'r': /* remove file when done */
+ rflag++;
+ break;
+
+ case 'm': /* send mail when done */
+ mailflg++;
+ break;
+
+ case 'h': /* toggle want of header page */
+ hdr = !hdr;
+ break;
+
+ case 's': /* try to link files */
+ sflag++;
+ break;
+
+ case 'q': /* just q job */
+ qflag++;
+ break;
+
+ case 'i': /* indent output */
+ iflag++;
+ indent = arg[2] ? atoi(&arg[2]) : 8;
+ break;
+
+ case '#': /* n copies */
+ if (isdigit(arg[2])) {
+ i = atoi(&arg[2]);
+ if (i > 0)
+ ncopies = i;
+ }
+ }
+ }
+ if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
+ printer = DEFLP;
+ chkprinter(printer);
+ if (SC && ncopies > 1)
+ fatal2("multiple copies are not allowed");
+ if (MC > 0 && ncopies > MC)
+ fatal2("only %d copies are allowed", MC);
+ /*
+ * Get the identity of the person doing the lpr using the same
+ * algorithm as lprm.
+ */
+ userid = getuid();
+ if (userid != DU || person == 0) {
+ if ((pw = getpwuid(userid)) == NULL)
+ fatal2("Who are you?");
+ person = pw->pw_name;
+ }
+ /*
+ * Check for restricted group access.
+ */
+ if (RG != NULL && userid != DU) {
+ if ((gptr = getgrnam(RG)) == NULL)
+ fatal2("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)
+ fatal2("Not a member of the restricted group");
+ }
+ }
+ /*
+ * Check to make sure queuing is enabled if userid is not root.
+ */
+ (void) sprintf(buf, "%s/%s", SD, LO);
+ if (userid && stat(buf, &stb) == 0 && (stb.st_mode & 010))
+ fatal2("Printer queue is disabled");
+ /*
+ * Initialize the control file.
+ */
+ mktemps();
+ tfd = nfile(tfname);
+ (void) fchown(tfd, DU, -1); /* owned by daemon for protection */
+ card('H', host);
+ card('P', person);
+ if (hdr) {
+ if (jobname == NULL) {
+ if (argc == 1)
+ jobname = "stdin";
+ else
+ jobname = (arg = rindex(argv[1], '/')) ? arg+1 : argv[1];
+ }
+ card('J', jobname);
+ card('C', class);
+ card('L', person);
+ }
+ 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);
+
+ /*
+ * Read the files and spool them.
+ */
+ if (argc == 1)
+ copy(0, " ");
+ else while (--argc) {
+ if ((f = test(arg = *++argv)) < 0)
+ continue; /* file unreasonable */
+
+ if (sflag && (cp = linked(arg)) != NULL) {
+ (void) sprintf(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 ((i = open(arg, O_RDONLY)) < 0) {
+ printf("%s: cannot open %s\n", name, arg);
+ continue;
+ }
+ copy(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.
+ */
+ 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);
+ if (qflag) /* just q things up */
+ exit(0);
+ if (!startdaemon(printer))
+ printf("jobs queued, but cannot start daemon.\n");
+ exit(0);
+ }
+ cleanup(0);
+ /* NOTREACHED */
+}
+
+/*
+ * Create the file n and copy from file descriptor f.
+ */
+static void
+copy(f, n)
+ 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 (MX > 0 && nr > MX) {
+ 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[BUFSIZ];
+
+ if (*file != '/') {
+ if (getwd(buf) == NULL)
+ return(NULL);
+ while (file[0] == '.') {
+ switch (file[1]) {
+ case '/':
+ file += 2;
+ continue;
+ case '.':
+ if (file[2] == '/') {
+ if ((cp = rindex(buf, '/')) != NULL)
+ *cp = '\0';
+ file += 3;
+ continue;
+ }
+ }
+ break;
+ }
+ strcat(buf, "/");
+ strcat(buf, file);
+ file = buf;
+ }
+ return(symlink(file, dfname) ? 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') {
+ *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 */
+
+ 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);
+ }
+ 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 i;
+
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ i = inchar;
+ 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;
+ 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);
+ }
+ 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 = rindex(file, '/')) == NULL) {
+ if (access(".", 2) == 0)
+ return(1);
+ } else {
+ if (cp == file) {
+ fd = access("/", 2);
+ } else {
+ *cp = '\0';
+ fd = access(file, 2);
+ *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);
+}
+
+/*
+ * 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)
+ char *s;
+{
+ int status;
+
+ if ((status = cgetent(&bp, printcapdb, s)) == -2)
+ fatal2("cannot open printer description file");
+ else if (status == -1)
+ fatal2("%s: unknown printer", s);
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ cgetstr(bp, "rg", &RG);
+ if (cgetnum(bp, "mx", &MX) < 0)
+ MX = DEFMX;
+ if (cgetnum(bp,"mc", &MC) < 0)
+ MC = DEFMAXCOPIES;
+ if (cgetnum(bp, "du", &DU) < 0)
+ DU = DEFUID;
+ SC = (cgetcap(bp, "sc", ':') != NULL);
+}
+
+/*
+ * Make the temp files.
+ */
+static void
+mktemps()
+{
+ register int len, fd, n;
+ register char *cp;
+ char buf[BUFSIZ];
+ char *lmktemp();
+
+ (void) sprintf(buf, "%s/.seq", SD);
+ 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);
+ }
+ 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(SD) + strlen(host) + 8;
+ tfname = lmktemp("tf", n, len);
+ cfname = lmktemp("cf", n, len);
+ dfname = lmktemp("df", n, len);
+ inchar = strlen(SD) + 3;
+ n = (n + 1) % 1000;
+ (void) lseek(fd, (off_t)0, 0);
+ sprintf(buf, "%03d\n", n);
+ (void) write(fd, buf, strlen(buf));
+ (void) close(fd); /* unlocks as well */
+}
+
+/*
+ * Make a temp file name.
+ */
+static char *
+lmktemp(id, num, len)
+ char *id;
+ int num, len;
+{
+ register char *s;
+
+ if ((s = malloc(len)) == NULL)
+ fatal2("out of memory");
+ (void) sprintf(s, "%s/%sA%03d%s", SD, id, num, host);
+ return(s);
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+static void
+#if __STDC__
+fatal2(const char *msg, ...)
+#else
+fatal2(msg, va_alist)
+ char *msg;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+ printf("%s: ", name);
+ vprintf(msg, ap);
+ putchar('\n');
+ va_end(ap);
+ exit(1);
+}
diff --git a/usr.sbin/lpr/lprm/Makefile b/usr.sbin/lpr/lprm/Makefile
new file mode 100644
index 000000000000..d1362f5cdced
--- /dev/null
+++ b/usr.sbin/lpr/lprm/Makefile
@@ -0,0 +1,12 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lprm
+CFLAGS+=-I${.CURDIR}/../common_source
+SRCS= lprm.c rmjob.c startdaemon.c common.c
+BINOWN= root
+BINGRP= daemon
+BINMODE=6555
+BINDIR= /usr/bin
+.PATH: ${.CURDIR}/../common_source
+
+.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 000000000000..22309d188013
--- /dev/null
+++ b/usr.sbin/lpr/lprm/lprm.1
@@ -0,0 +1,145 @@
+.\" 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
+.\"
+.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 lprm
+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 lprm
+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
+Causes
+.Nm lprm
+to attempt to remove any jobs queued belonging to that user
+(or users). This form of invoking
+.Nm lprm
+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 Lprm
+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 lpr 1 ,
+.Xr lpq 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 lprm
+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 000000000000..20c4ee7321ba
--- /dev/null
+++ b/usr.sbin/lpr/lprm/lprm.c
@@ -0,0 +1,144 @@
+/*
+ * 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[] = "@(#)lprm.c 8.1 (Berkeley) 6/6/93";
+#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 */
+
+static char luser[16]; /* buffer for person */
+
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register char *arg;
+ struct passwd *p;
+
+ name = argv[0];
+ gethostname(host, sizeof(host));
+ openlog("lpd", 0, LOG_LPR);
+ if ((p = getpwuid(getuid())) == NULL)
+ fatal("Who are you?");
+ if (strlen(p->pw_name) >= sizeof(luser))
+ fatal("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("Too many requests");
+ requ[requests++] = atoi(arg);
+ } else {
+ if (users >= MAXUSERS)
+ fatal("Too many users");
+ user[users++] = arg;
+ }
+ }
+ }
+ if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
+ printer = DEFLP;
+
+ rmjob();
+ exit(0);
+}
+
+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 000000000000..6ff8e7fe9c7a
--- /dev/null
+++ b/usr.sbin/lpr/lptest/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lptest
+
+.include "../../Makefile.inc"
+.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 000000000000..95b28f3525b4
--- /dev/null
+++ b/usr.sbin/lpr/lptest/lptest.1
@@ -0,0 +1,74 @@
+.\" 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
+.\"
+.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 000000000000..5ce80b5d4fa3
--- /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).
+ */
+void
+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 000000000000..70cea8994c77
--- /dev/null
+++ b/usr.sbin/lpr/pac/Makefile
@@ -0,0 +1,10 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= pac
+CFLAGS+=-I${.CURDIR}/../common_source
+MAN8= pac.0
+SRCS= pac.c common.c
+.PATH: ${.CURDIR}/../common_source
+
+.include "../../Makefile.inc"
+.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 000000000000..6e7ffc0b765d
--- /dev/null
+++ b/usr.sbin/lpr/pac/pac.8
@@ -0,0 +1,106 @@
+.\" 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
+.\"
+.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
+flag causes the output to be sorted by cost; usually the
+output is sorted alphabetically by name.
+.It Fl m
+flag causes 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 000000000000..af0c8ccb12b9
--- /dev/null
+++ b/usr.sbin/lpr/pac/pac.c
@@ -0,0 +1,444 @@
+/*
+ * 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[] = "@(#)pac.c 8.1 (Berkeley) 6/6/93";
+#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 <stdlib.h>
+#include <stdio.h>
+#include <string.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 */
+
+/*
+ * 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 */
+
+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));
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ register FILE *acct;
+ register char *cp;
+
+ 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:
+fprintf(stderr,
+ "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [-m] [user ...]\n");
+ exit(1);
+ }
+ }
+ (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);
+}
+
+/*
+ * 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\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 && index(cp, ':'))
+ cp = index(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) {
+ perror(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)) {
+ perror(sumfile);
+ errs++;
+ }
+ fclose(acctf);
+ if ((acctf = fopen(acctfile, "w")) == NULL)
+ perror(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;
+
+ if ((stat = cgetent(&bp, printcapdb, s)) == -2) {
+ printf("pac: can't open printer description file\n");
+ exit(3);
+ } else if (stat == -1)
+ return(0);
+ else if (stat == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ if (cgetstr(bp, "af", &acctfile) == -1) {
+ printf("accounting not enabled for printer %s\n", printer);
+ exit(2);
+ }
+ if (!pflag && (cgetnum(bp, "pc", &price100) == 0))
+ price = price100/10000.0;
+ sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5);
+ if (sumfile == NULL) {
+ perror("pac");
+ exit(1);
+ }
+ strcpy(sumfile, acctfile);
+ strcat(sumfile, "_sum");
+ return(1);
+}
diff --git a/usr.sbin/lpr/runqueue/extern.h b/usr.sbin/lpr/runqueue/extern.h
new file mode 100644
index 000000000000..64dec12dc9ef
--- /dev/null
+++ b/usr.sbin/lpr/runqueue/extern.h
@@ -0,0 +1,39 @@
+/*
+ * 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/cdefs.h>
+
+void printjob __P((void));
+void recvjob __P((void));
diff --git a/usr.sbin/lpr/runqueue/lpdchar.c b/usr.sbin/lpr/runqueue/lpdchar.c
new file mode 100644
index 000000000000..4a4f5da1ccbe
--- /dev/null
+++ b/usr.sbin/lpr/runqueue/lpdchar.c
@@ -0,0 +1,1066 @@
+/*
+ * 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";
+#endif /* not lint */
+
+/*
+ * Character set for line printer daemon
+ */
+#include "lp.local.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/runqueue/printjob.c b/usr.sbin/lpr/runqueue/printjob.c
new file mode 100644
index 000000000000..87c935214747
--- /dev/null
+++ b/usr.sbin/lpr/runqueue/printjob.c
@@ -0,0 +1,1377 @@
+/*
+ * 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[] = "@(#)printjob.c 8.2 (Berkeley) 4/16/94";
+#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 <sgtty.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.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 lfd; /* lock file descriptor */
+static int ofd; /* output filter file descriptor */
+static int ofilter; /* id of output filter, if any */
+static int pfd; /* prstatic inter file descriptor */
+static int pid; /* pid of lpd process */
+static int prchild; /* id of pr process */
+static int remote; /* true if sending files to remote */
+static char title[80]; /* ``pr'' title */
+static int tof; /* true if at top of form */
+
+static char class[32]; /* classification field */
+static char fromhost[32]; /* 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 output */
+static char width[10] = "-w"; /* page width in static characters */
+
+static void abortpr __P((int));
+static void banner __P((char *, char *));
+static int dofork __P((int));
+static int dropit __P((int));
+static void init __P((void));
+static void openpr __P((void));
+static int print __P((int, char *));
+static int printit __P((char *));
+static void pstatus __P((const char *, ...));
+static char response __P((void));
+static void scan_out __P((int, char *, int));
+static char *scnline __P((int, char *, int));
+static int sendfile __P((int, char *));
+static int sendit __P((char *));
+static void sendmail __P((char *, int));
+static void setty __P((void));
+
+void
+printjob()
+{
+ struct stat stb;
+ register struct queue *q, **qp;
+ struct queue **queue;
+ register int i, nitems;
+ long pidoff;
+ int count = 0;
+
+ init(); /* set up capabilities */
+ (void) write(1, "", 1); /* ack that daemon is started */
+ (void) close(2); /* set up log file */
+ if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
+ syslog(LOG_ERR, "%s: %m", LF);
+ (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(SD) < 0) {
+ syslog(LOG_ERR, "%s: %m", SD);
+ exit(1);
+ }
+ if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
+ exit(0); /* printing disabled */
+ lfd = open(LO, O_WRONLY|O_CREAT, 0644);
+ if (lfd < 0) {
+ syslog(LOG_ERR, "%s: %s: %m", printer, LO);
+ exit(1);
+ }
+ if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
+ if (errno == EWOULDBLOCK) /* active deamon present */
+ exit(0);
+ syslog(LOG_ERR, "%s: %s: %m", printer, LO);
+ 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", printer, LO);
+ exit(1);
+ }
+ /*
+ * search the spool directory for work and sort by queue order.
+ */
+ if ((nitems = getq(&queue)) < 0) {
+ syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
+ exit(1);
+ }
+ if (nitems == 0) /* no work to do */
+ exit(0);
+ if (stb.st_mode & 01) { /* reset queue flag */
+ if (fchmod(lfd, stb.st_mode & 0776) < 0)
+ syslog(LOG_ERR, "%s: %s: %m", printer, LO);
+ }
+ openpr(); /* 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;
+ restart:
+ (void) lseek(lfd, (off_t)pidoff, 0);
+ (void) sprintf(line, "%s\n", q->q_name);
+ i = strlen(line);
+ if (write(lfd, line, i) != i)
+ syslog(LOG_ERR, "%s: %s: %m", printer, LO);
+ if (!remote)
+ i = printit(q->q_name);
+ else
+ i = sendit(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 & 0100)
+ goto done;
+ /* rebuild queue (after lpc topq) */
+ if (stb.st_mode & 01) {
+ for (free((char *) q); nitems--; free((char *) q))
+ q = *qp++;
+ if (fchmod(lfd, stb.st_mode & 0776) < 0)
+ syslog(LOG_WARNING, "%s: %s: %m",
+ printer, LO);
+ break;
+ }
+ }
+ if (i == OK) /* file ok and printed */
+ count++;
+ else if (i == REPRINT) { /* try reprinting the job */
+ syslog(LOG_INFO, "restarting %s", printer);
+ if (ofilter > 0) {
+ kill(ofilter, SIGCONT); /* to be sure */
+ (void) close(ofd);
+ while ((i = wait(0)) > 0 && i != ofilter)
+ ;
+ ofilter = 0;
+ }
+ (void) close(pfd); /* close printer */
+ if (ftruncate(lfd, pidoff) < 0)
+ syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
+ openpr(); /* try to reopen printer */
+ goto restart;
+ }
+ }
+ free((char *) queue);
+ /*
+ * search the spool directory for more work.
+ */
+ if ((nitems = getq(&queue)) < 0) {
+ syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
+ exit(1);
+ }
+ if (nitems == 0) { /* no more work to do */
+ done:
+ if (count > 0) { /* Files actually printed */
+ if (!SF && !tof)
+ (void) write(ofd, FF, strlen(FF));
+ if (TR != NULL) /* output trailer */
+ (void) write(ofd, TR, strlen(TR));
+ }
+ (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(file)
+ 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", printer, file);
+ return(OK);
+ }
+ /*
+ * Reset troff fonts.
+ */
+ for (i = 0; i < 4; i++)
+ strcpy(fonts[i], ifonts[i]);
+ sprintf(&width[2], "%d", PW);
+ strcpy(indent+2, "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
+ * 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
+ *
+ * getline reads a line and expands tabs to blanks
+ */
+
+ /* pass 1 */
+
+ while (getline(cfp))
+ switch (line[0]) {
+ case 'H':
+ strcpy(fromhost, line+1);
+ if (class[0] == '\0')
+ strncpy(class, line+1, sizeof(class)-1);
+ continue;
+
+ case 'P':
+ strncpy(logname, line+1, sizeof(logname)-1);
+ if (RS) { /* restricted */
+ if (getpwnam(logname) == NULL) {
+ bombed = NOACCT;
+ sendmail(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);
+ 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));
+ continue;
+
+ case 'T': /* header title for pr */
+ strncpy(title, line+1, sizeof(title)-1);
+ continue;
+
+ case 'L': /* identification line */
+ if (!SH && !HL)
+ banner(line+1, jobname);
+ continue;
+
+ case '1': /* troff fonts */
+ case '2':
+ case '3':
+ case '4':
+ if (line[1] != '\0')
+ strcpy(fonts[line[0]-'1'], line+1);
+ continue;
+
+ case 'W': /* page width */
+ strncpy(width+2, line+1, sizeof(width)-3);
+ continue;
+
+ case 'I': /* indent amount */
+ strncpy(indent+2, line+1, sizeof(indent)-3);
+ continue;
+
+ default: /* some file to print */
+ switch (i = print(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(logname, bombed);
+ }
+ title[0] = '\0';
+ continue;
+
+ case 'N':
+ case 'U':
+ case 'M':
+ continue;
+ }
+
+ /* pass 2 */
+
+pass2:
+ fseek(cfp, 0L, 0);
+ while (getline(cfp))
+ switch (line[0]) {
+ case 'L': /* identification line */
+ if (!SH && HL)
+ banner(line+1, jobname);
+ continue;
+
+ case 'M':
+ if (bombed < NOACCT) /* already sent if >= NOACCT */
+ sendmail(line+1, bombed);
+ continue;
+
+ case 'U':
+ (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(format, file)
+ int format;
+ char *file;
+{
+ register int n;
+ 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);
+ if (!SF && !tof) { /* start on a fresh page */
+ (void) write(ofd, FF, strlen(FF));
+ tof = 1;
+ }
+ if (IF == NULL && (format == 'f' || format == 'l')) {
+ 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 (IF == NULL) { /* use output filter */
+ prog = _PATH_PR;
+ av[0] = "pr";
+ av[1] = width;
+ av[2] = length;
+ av[3] = "-h";
+ av[4] = *title ? title : " ";
+ av[5] = 0;
+ fo = ofd;
+ goto start;
+ }
+ pipe(p);
+ if ((prchild = dofork(DORETURN)) == 0) { /* child */
+ dup2(fi, 0); /* file is stdin */
+ dup2(p[1], 1); /* pipe is stdout */
+ for (n = 3; n < NOFILE; n++)
+ (void) close(n);
+ execl(_PATH_PR, "pr", width, length,
+ "-h", *title ? title : " ", 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 = IF;
+ av[1] = width;
+ av[2] = length;
+ av[3] = indent;
+ n = 4;
+ break;
+ case 'l': /* like 'f' but pass control characters */
+ prog = IF;
+ av[1] = "-c";
+ av[2] = width;
+ av[3] = length;
+ av[4] = indent;
+ n = 5;
+ break;
+ case 'r': /* print a fortran text file */
+ prog = RF;
+ 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", 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') ? TF : (format == 'n') ? NF : DF;
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ case 'c': /* print cifplot output */
+ prog = CF;
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ case 'g': /* print plot(1G) output */
+ prog = GF;
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ case 'v': /* print raster output */
+ prog = VF;
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ default:
+ (void) close(fi);
+ syslog(LOG_ERR, "%s: illegal format character '%c'",
+ printer, format);
+ return(ERROR);
+ }
+ if ((av[0] = rindex(prog, '/')) != NULL)
+ av[0]++;
+ else
+ av[0] = prog;
+ av[n++] = "-n";
+ av[n++] = logname;
+ av[n++] = "-h";
+ av[n++] = fromhost;
+ av[n++] = AF;
+ 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 (%d)",
+ printer, status.w_retcode);
+ return(REPRINT);
+ }
+ stopped++;
+ }
+start:
+ if ((child = dofork(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);
+ for (n = 3; n < NOFILE; n++)
+ (void) close(n);
+ 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);
+ }
+ }
+ 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: Daemon filter '%c' terminated (%d)",
+ printer, format, status.w_termsig);
+ return(ERROR);
+ }
+ switch (status.w_retcode) {
+ case 0:
+ tof = 1;
+ return(OK);
+ case 1:
+ return(REPRINT);
+ default:
+ syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
+ printer, format, status.w_retcode);
+ case 2:
+ return(ERROR);
+ }
+}
+
+/*
+ * 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(file)
+ char *file;
+{
+ register int i, err = OK;
+ char *cp, last[BUFSIZ];
+
+ /*
+ * open control file
+ */
+ if ((cfp = fopen(file, "r")) == NULL)
+ return(OK);
+ /*
+ * 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;
+ continue;
+ }
+ if (line[0] >= 'a' && line[0] <= 'z') {
+ strcpy(last, line);
+ while (i = getline(cfp))
+ if (strcmp(last, line))
+ break;
+ switch (sendfile('\3', last+1)) {
+ case OK:
+ if (i)
+ goto again;
+ break;
+ case REPRINT:
+ (void) fclose(cfp);
+ return(REPRINT);
+ case ACCESS:
+ sendmail(logname, ACCESS);
+ case ERROR:
+ err = ERROR;
+ }
+ break;
+ }
+ }
+ if (err == OK && sendfile('\2', file) > 0) {
+ (void) fclose(cfp);
+ return(REPRINT);
+ }
+ /*
+ * pass 2
+ */
+ fseek(cfp, 0L, 0);
+ while (getline(cfp))
+ if (line[0] == 'U')
+ (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(type, file)
+ int type;
+ char *file;
+{
+ register int f, i, amt;
+ struct stat stb;
+ char buf[BUFSIZ];
+ int sizerr, resp;
+
+ 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);
+ (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()) < 0 || resp == '\1') {
+ (void) close(f);
+ return(REPRINT);
+ } else if (resp == '\0')
+ break;
+ if (i == 0)
+ pstatus("no space on remote; waiting for queue to drain");
+ if (i == 10)
+ syslog(LOG_ALERT, "%s: can't send to %s; queue full",
+ printer, RM);
+ sleep(5 * 60);
+ }
+ if (i)
+ pstatus("sending to %s", RM);
+ sizerr = 0;
+ 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);
+ return(REPRINT);
+ }
+ }
+
+
+
+
+ (void) close(f);
+ if (sizerr) {
+ syslog(LOG_INFO, "%s: %s: changed size", printer, file);
+ /* tell recvjob to ignore this file */
+ (void) write(pfd, "\1", 1);
+ return(ERROR);
+ }
+ if (write(pfd, "", 1) != 1 || response())
+ return(REPRINT);
+ 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()
+{
+ char resp;
+
+ if (read(pfd, &resp, 1) != 1) {
+ syslog(LOG_INFO, "%s: lost connection", printer);
+ return(-1);
+ }
+ return(resp);
+}
+
+/*
+ * Banner printing stuff
+ */
+static void
+banner(name1, name2)
+ char *name1, *name2;
+{
+ time_t tvec;
+ extern char *ctime();
+
+ time(&tvec);
+ if (!SF && !tof)
+ (void) write(ofd, FF, strlen(FF));
+ if (SB) { /* 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(ofd, name1, '\0');
+ (void) write(ofd, "\n\n", 2);
+ scan_out(ofd, name2, '\0');
+ if (class[0]) {
+ (void) write(ofd,"\n\n\n",3);
+ scan_out(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 (!SF)
+ (void) write(ofd, FF, strlen(FF));
+ tof = 1;
+}
+
+static char *
+scnline(key, p, c)
+ register int key;
+ register char *p;
+ int c;
+{
+ register scnwidth;
+
+ for (scnwidth = WIDTH; --scnwidth;) {
+ key <<= 1;
+ *p++ = key & 0200 ? c : BACKGND;
+ }
+ return (p);
+}
+
+#define TRC(q) (((q)-' ')&0177)
+
+static void
+scan_out(scfd, scsp, dlm)
+ int scfd, dlm;
+ char *scsp;
+{
+ register char *strp;
+ register nchrs, j;
+ char outbuf[LINELEN+1], *sp, c, cc;
+ int d, scnhgt;
+ extern char scnkey[][HEIGHT]; /* in lpdchar.c */
+
+ 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[c][scnhgt-1-d], strp, cc);
+ if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(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(user, bombed)
+ char *user;
+ int bombed;
+{
+ register int i;
+ int p[2], s;
+ register char *cp;
+ char buf[100];
+ struct stat stb;
+ FILE *fp;
+
+ pipe(p);
+ if ((s = dofork(DORETURN)) == 0) { /* child */
+ dup2(p[0], 0);
+ for (i = 3; i < NOFILE; i++)
+ (void) close(i);
+ if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
+ cp++;
+ else
+ cp = _PATH_SENDMAIL;
+ sprintf(buf, "%s@%s", user, fromhost);
+ execl(_PATH_SENDMAIL, cp, buf, 0);
+ exit(0);
+ } else if (s > 0) { /* parent */
+ dup2(p[1], 1);
+ printf("To: %s@%s\n", user, fromhost);
+ printf("Subject: printer job\n\n");
+ printf("Your printer job ");
+ if (*jobname)
+ printf("(%s) ", jobname);
+ switch (bombed) {
+ case OK:
+ printf("\ncompleted successfully\n");
+ break;
+ default:
+ case FATALERR:
+ printf("\ncould not be printed\n");
+ break;
+ case NOACCT:
+ printf("\ncould not be printed without an account on %s\n", host);
+ break;
+ case FILTERERR:
+ if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
+ (fp = fopen(tempfile, "r")) == NULL) {
+ printf("\nwas printed but had some errors\n");
+ break;
+ }
+ printf("\nwas printed but had the following errors:\n");
+ while ((i = getc(fp)) != EOF)
+ putchar(i);
+ (void) fclose(fp);
+ break;
+ case ACCESS:
+ printf("\nwas not printed because it was not linked to the original file\n");
+ }
+ fflush(stdout);
+ (void) close(1);
+ }
+ (void) close(p[0]);
+ (void) close(p[1]);
+ wait(&s);
+}
+
+/*
+ * dofork - fork with retries on failure
+ */
+static int
+dofork(action)
+ int action;
+{
+ register int i, pid;
+
+ 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)
+ setuid(DU);
+ 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)
+ ;
+ exit(0);
+}
+
+static void
+init()
+{
+ int status;
+ char *s;
+
+ if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+ syslog(LOG_ERR, "can't open printer description file");
+ exit(1);
+ } else if (status == -1) {
+ syslog(LOG_ERR, "unknown printer: %s", printer);
+ exit(1);
+ } else if (status == -3)
+ fatal("potential reference loop detected in printcap file");
+
+ if (cgetstr(bp, "lp", &LP) == -1)
+ LP = _PATH_DEFDEVLP;
+ if (cgetstr(bp, "rp", &RP) == -1)
+ RP = DEFLP;
+ if (cgetstr(bp, "lo", &LO) == -1)
+ LO = DEFLOCK;
+ if (cgetstr(bp, "st", &ST) == -1)
+ ST = DEFSTAT;
+ if (cgetstr(bp, "lf", &LF) == -1)
+ LF = _PATH_CONSOLE;
+ if (cgetstr(bp, "sd", &SD) == -1)
+ SD = _PATH_DEFSPOOL;
+ if (cgetnum(bp, "du", &DU) < 0)
+ DU = DEFUID;
+ if (cgetstr(bp,"ff", &FF) == -1)
+ FF = DEFFF;
+ if (cgetnum(bp, "pw", &PW) < 0)
+ PW = DEFWIDTH;
+ sprintf(&width[2], "%d", PW);
+ if (cgetnum(bp, "pl", &PL) < 0)
+ PL = DEFLENGTH;
+ sprintf(&length[2], "%d", PL);
+ if (cgetnum(bp,"px", &PX) < 0)
+ PX = 0;
+ sprintf(&pxwidth[2], "%d", PX);
+ if (cgetnum(bp, "py", &PY) < 0)
+ PY = 0;
+ sprintf(&pxlength[2], "%d", PY);
+ cgetstr(bp, "rm", &RM);
+ if (s = checkremote())
+ syslog(LOG_WARNING, s);
+
+ cgetstr(bp, "af", &AF);
+ cgetstr(bp, "of", &OF);
+ cgetstr(bp, "if", &IF);
+ cgetstr(bp, "rf", &RF);
+ cgetstr(bp, "tf", &TF);
+ cgetstr(bp, "nf", &NF);
+ cgetstr(bp, "df", &DF);
+ cgetstr(bp, "gf", &GF);
+ cgetstr(bp, "vf", &VF);
+ cgetstr(bp, "cf", &CF);
+ cgetstr(bp, "tr", &TR);
+
+ RS = (cgetcap(bp, "rs", ':') != NULL);
+ SF = (cgetcap(bp, "sf", ':') != NULL);
+ SH = (cgetcap(bp, "sh", ':') != NULL);
+ SB = (cgetcap(bp, "sb", ':') != NULL);
+ HL = (cgetcap(bp, "hl", ':') != NULL);
+ RW = (cgetcap(bp, "rw", ':') != NULL);
+
+ cgetnum(bp, "br", &BR);
+ if (cgetnum(bp, "fc", &FC) < 0)
+ FC = 0;
+ if (cgetnum(bp, "fs", &FS) < 0)
+ FS = 0;
+ if (cgetnum(bp, "xc", &XC) < 0)
+ XC = 0;
+ if (cgetnum(bp, "xs", &XS) < 0)
+ XS = 0;
+
+ tof = (cgetcap(bp, "fo", ':') == NULL);
+}
+
+/*
+ * Acquire line printer or remote connection.
+ */
+static void
+openpr()
+{
+ register int i, n;
+ int resp;
+
+ if (!sendtorem && *LP) {
+ for (i = 1; ; i = i < 32 ? i << 1 : i) {
+ pfd = open(LP, RW ? O_RDWR : O_WRONLY);
+ if (pfd >= 0)
+ break;
+ if (errno == ENOENT) {
+ syslog(LOG_ERR, "%s: %m", LP);
+ exit(1);
+ }
+ if (i == 1)
+ pstatus("waiting for %s to become ready (offline ?)", printer);
+ sleep(i);
+ }
+ if (isatty(pfd))
+ setty();
+ pstatus("%s is ready and printing", printer);
+ } else if (RM != NULL) {
+ for (i = 1; ; i = i < 256 ? i << 1 : i) {
+ resp = -1;
+ pfd = getport(RM);
+ if (pfd >= 0) {
+ (void) sprintf(line, "\2%s\n", RP);
+ n = strlen(line);
+ if (write(pfd, line, n) == n &&
+ (resp = response()) == '\0')
+ break;
+ (void) close(pfd);
+ }
+ if (i == 1) {
+ if (resp < 0)
+ pstatus("waiting for %s to come up", RM);
+ else {
+ pstatus("waiting for queue to be enabled on %s", RM);
+ i = 256;
+ }
+ }
+ sleep(i);
+ }
+ pstatus("sending to %s", RM);
+ remote = 1;
+ } else {
+ syslog(LOG_ERR, "%s: no line printer device or host name",
+ printer);
+ exit(1);
+ }
+ /*
+ * Start up an output filter, if needed.
+ */
+ if (!remote && OF) {
+ int p[2];
+ char *cp;
+
+ pipe(p);
+ if ((ofilter = dofork(DOABORT)) == 0) { /* child */
+ dup2(p[0], 0); /* pipe is std in */
+ dup2(pfd, 1); /* printer is std out */
+ for (i = 3; i < NOFILE; i++)
+ (void) close(i);
+ if ((cp = rindex(OF, '/')) == NULL)
+ cp = OF;
+ else
+ cp++;
+ execl(OF, cp, width, length, 0);
+ syslog(LOG_ERR, "%s: %s: %m", printer, OF);
+ exit(1);
+ }
+ (void) close(p[0]); /* close input side */
+ ofd = p[1]; /* use pipe for output */
+ } else {
+ ofd = pfd;
+ ofilter = 0;
+ }
+}
+
+struct bauds {
+ int baud;
+ int speed;
+} bauds[] = {
+ 50, B50,
+ 75, B75,
+ 110, B110,
+ 134, B134,
+ 150, B150,
+ 200, B200,
+ 300, B300,
+ 600, B600,
+ 1200, B1200,
+ 1800, B1800,
+ 2400, B2400,
+ 4800, B4800,
+ 9600, B9600,
+ 19200, EXTA,
+ 38400, EXTB,
+ 0, 0
+};
+
+/*
+ * setup tty lines.
+ */
+static void
+setty()
+{
+ struct sgttyb ttybuf;
+ register struct bauds *bp;
+
+ if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
+ exit(1);
+ }
+ if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
+ exit(1);
+ }
+ if (BR > 0) {
+ for (bp = bauds; bp->baud; bp++)
+ if (BR == bp->baud)
+ break;
+ if (!bp->baud) {
+ syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
+ exit(1);
+ }
+ ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
+ }
+ ttybuf.sg_flags &= ~FC;
+ ttybuf.sg_flags |= FS;
+ if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
+ exit(1);
+ }
+ if (XC) {
+ if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
+ exit(1);
+ }
+ }
+ if (XS) {
+ if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
+ exit(1);
+ }
+ }
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+pstatus(const char *msg, ...)
+#else
+pstatus(msg, va_alist)
+ char *msg;
+ va_dcl
+#endif
+{
+ register int fd;
+ char buf[BUFSIZ];
+ va_list ap;
+#if __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+
+ umask(0);
+ fd = open(ST, O_WRONLY|O_CREAT, 0664);
+ if (fd < 0 || flock(fd, LOCK_EX) < 0) {
+ syslog(LOG_ERR, "%s: %s: %m", printer, ST);
+ exit(1);
+ }
+ ftruncate(fd, 0);
+ (void)vsnprintf(buf, sizeof(buf), msg, ap);
+ va_end(ap);
+ strcat(buf, "\n");
+ (void) write(fd, buf, strlen(buf));
+ (void) close(fd);
+}