summaryrefslogtreecommitdiffstats
path: root/usr.sbin/lpr
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/lpr')
-rw-r--r--usr.sbin/lpr/Makefile10
-rw-r--r--usr.sbin/lpr/Makefile.inc11
-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/Makefile12
-rw-r--r--usr.sbin/lpr/SMM.doc/spell.ok70
-rw-r--r--usr.sbin/lpr/chkprintcap/Makefile10
-rw-r--r--usr.sbin/lpr/chkprintcap/chkprintcap.896
-rw-r--r--usr.sbin/lpr/chkprintcap/chkprintcap.c277
-rw-r--r--usr.sbin/lpr/common_source/Makefile18
-rw-r--r--usr.sbin/lpr/common_source/common.c592
-rw-r--r--usr.sbin/lpr/common_source/displayq.c549
-rw-r--r--usr.sbin/lpr/common_source/lp.h267
-rw-r--r--usr.sbin/lpr/common_source/lp.local.h81
-rw-r--r--usr.sbin/lpr/common_source/net.c265
-rw-r--r--usr.sbin/lpr/common_source/pathnames.h51
-rw-r--r--usr.sbin/lpr/common_source/printcap.c448
-rw-r--r--usr.sbin/lpr/common_source/request.c80
-rw-r--r--usr.sbin/lpr/common_source/rmjob.c397
-rw-r--r--usr.sbin/lpr/common_source/startdaemon.c110
-rw-r--r--usr.sbin/lpr/filters.ru/Makefile14
-rw-r--r--usr.sbin/lpr/filters.ru/Makefile.inc2
-rw-r--r--usr.sbin/lpr/filters.ru/bjc-240.sh.sample64
-rw-r--r--usr.sbin/lpr/filters.ru/koi2855/Makefile6
-rw-r--r--usr.sbin/lpr/filters.ru/koi2855/koi2855.c102
-rw-r--r--usr.sbin/lpr/filters.ru/koi2alt/Makefile6
-rw-r--r--usr.sbin/lpr/filters.ru/koi2alt/koi2alt.c101
-rw-r--r--usr.sbin/lpr/filters/Makefile7
-rw-r--r--usr.sbin/lpr/filters/lpf.c219
-rw-r--r--usr.sbin/lpr/lp/Makefile10
-rw-r--r--usr.sbin/lpr/lp/lp.1117
-rw-r--r--usr.sbin/lpr/lp/lp.sh75
-rw-r--r--usr.sbin/lpr/lpc/Makefile14
-rw-r--r--usr.sbin/lpr/lpc/cmds.c891
-rw-r--r--usr.sbin/lpr/lpc/cmdtab.c83
-rw-r--r--usr.sbin/lpr/lpc/extern.h61
-rw-r--r--usr.sbin/lpr/lpc/lpc.8178
-rw-r--r--usr.sbin/lpr/lpc/lpc.c356
-rw-r--r--usr.sbin/lpr/lpc/lpc.h48
-rw-r--r--usr.sbin/lpr/lpd/Makefile11
-rw-r--r--usr.sbin/lpr/lpd/extern.h50
-rw-r--r--usr.sbin/lpr/lpd/lpd.8271
-rw-r--r--usr.sbin/lpr/lpd/lpd.c657
-rw-r--r--usr.sbin/lpr/lpd/lpdchar.c1071
-rw-r--r--usr.sbin/lpr/lpd/modes.c236
-rw-r--r--usr.sbin/lpr/lpd/printjob.c1694
-rw-r--r--usr.sbin/lpr/lpd/recvjob.c418
-rw-r--r--usr.sbin/lpr/lpq/Makefile13
-rw-r--r--usr.sbin/lpr/lpq/lpq.1137
-rw-r--r--usr.sbin/lpr/lpq/lpq.c201
-rw-r--r--usr.sbin/lpr/lpr/Makefile15
-rw-r--r--usr.sbin/lpr/lpr/lpr.1315
-rw-r--r--usr.sbin/lpr/lpr/lpr.c895
-rw-r--r--usr.sbin/lpr/lpr/printcap.5398
-rw-r--r--usr.sbin/lpr/lprm/Makefile14
-rw-r--r--usr.sbin/lpr/lprm/lprm.1146
-rw-r--r--usr.sbin/lpr/lprm/lprm.c165
-rw-r--r--usr.sbin/lpr/lptest/Makefile5
-rw-r--r--usr.sbin/lpr/lptest/lptest.175
-rw-r--r--usr.sbin/lpr/lptest/lptest.c83
-rw-r--r--usr.sbin/lpr/pac/Makefile11
-rw-r--r--usr.sbin/lpr/pac/pac.8107
-rw-r--r--usr.sbin/lpr/pac/pac.c462
69 files changed, 14149 insertions, 0 deletions
diff --git a/usr.sbin/lpr/Makefile b/usr.sbin/lpr/Makefile
new file mode 100644
index 0000000..4343200
--- /dev/null
+++ b/usr.sbin/lpr/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+SUBDIR= common_source chkprintcap lp lpc lpd lpq lpr lprm lptest pac \
+ filters filters.ru SMM.doc
+
+MAINTAINER= wollman@FreeBSD.org
+MAINTAINER+= gad@FreeBSD.org
+
+.include <bsd.subdir.mk>
+
diff --git a/usr.sbin/lpr/Makefile.inc b/usr.sbin/lpr/Makefile.inc
new file mode 100644
index 0000000..141373e
--- /dev/null
+++ b/usr.sbin/lpr/Makefile.inc
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+CWARNFLAGS= -Wall -Wnested-externs -Wmissing-prototypes -Wno-unused -Wredundant-decls -Wstrict-prototypes
+
+.if exists(${.OBJDIR}/../common_source)
+LIBLPR= ${.OBJDIR}/../common_source/liblpr.a
+.else
+LIBLPR= ${.CURDIR}/../common_source/liblpr.a
+.endif
+
+.include "../Makefile.inc"
diff --git a/usr.sbin/lpr/SMM.doc/0.t b/usr.sbin/lpr/SMM.doc/0.t
new file mode 100644
index 0000000..65ecd4e
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/0.t
@@ -0,0 +1,68 @@
+.\" Copyright (c) 1983, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)0.t 8.1 (Berkeley) 6/8/93
+.\"
+.if n .ND
+.TL
+4.3BSD Line Printer Spooler Manual
+.EH 'SMM:7-%''4.3BSD Line Printer Spooler Manual'
+.OH '4.3BSD Line Printer Spooler Manual''SMM:7-%'
+.AU
+Ralph Campbell
+.AI
+Computer Systems Research Group
+Computer Science Division
+Department of Electrical Engineering and Computer Science
+University of California, Berkeley
+Berkeley, CA 94720
+.AB
+.FS
+* UNIX is a trademark of Bell Laboratories.
+.FE
+This document describes the structure and installation procedure
+for the line printer spooling system
+developed for the 4.3BSD version
+of the UNIX* operating system.
+.de D?
+.ie \\n(.$>1 Revised \\$1 \\$2 \\$3
+.el DRAFT of \n(mo/\n(dy/\n(yr
+..
+.sp 2
+.LP
+.D? June 8, 1993
+.AE
+.de IR
+\fI\\$1\fP\\$2
+..
+.de DT
+.TA 8 16 24 32 40 48 56 64 72 80
+..
diff --git a/usr.sbin/lpr/SMM.doc/1.t b/usr.sbin/lpr/SMM.doc/1.t
new file mode 100644
index 0000000..1d34e9e
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/1.t
@@ -0,0 +1,77 @@
+.\" Copyright (c) 1983, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)1.t 8.1 (Berkeley) 6/8/93
+.\"
+.NH 1
+Overview
+.PP
+The line printer system supports:
+.IP \(bu 3
+multiple printers,
+.IP \(bu 3
+multiple spooling queues,
+.IP \(bu 3
+both local and remote
+printers, and
+.IP \(bu 3
+printers attached via serial lines that require
+line initialization such as the baud rate.
+.LP
+Raster output devices
+such as a Varian or Versatec, and laser printers such as an Imagen,
+are also supported by the line printer system.
+.PP
+The line printer system consists mainly of the
+following files and commands:
+.DS
+.TS
+l l.
+/etc/printcap printer configuration and capability data base
+/usr/lib/lpd line printer daemon, does all the real work
+/usr/ucb/lpr program to enter a job in a printer queue
+/usr/ucb/lpq spooling queue examination program
+/usr/ucb/lprm program to delete jobs from a queue
+/etc/lpc program to administer printers and spooling queues
+/dev/printer socket on which lpd listens
+.TE
+.DE
+The file /etc/printcap is a master data base describing line
+printers directly attached to a machine and, also, printers
+accessible across a network. The manual page entry
+.IR printcap (5)
+provides the authoritative definition of
+the format of this data base, as well as
+specifying default values for important items
+such as the directory in which spooling is performed.
+This document introduces some of the
+information that may be placed
+.IR printcap .
diff --git a/usr.sbin/lpr/SMM.doc/2.t b/usr.sbin/lpr/SMM.doc/2.t
new file mode 100644
index 0000000..9da2ae2
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/2.t
@@ -0,0 +1,141 @@
+.\" Copyright (c) 1983, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)2.t 8.1 (Berkeley) 6/8/93
+.\"
+.NH 1
+Commands
+.NH 2
+lpd \- line printer daemon
+.PP
+The program
+.IR lpd (8),
+usually invoked at boot time from the /etc/rc file, acts as
+a master server for coordinating and controlling
+the spooling queues configured in the printcap file.
+When
+.I lpd
+is started it makes a single pass through the
+.I printcap
+database restarting any printers that have jobs.
+In normal operation
+.I lpd
+listens for service requests on multiple sockets,
+one in the UNIX domain (named ``/dev/printer'') for
+local requests, and one in the Internet domain
+(under the ``printer'' service specification)
+for requests for printer access from off machine;
+see \fIsocket\fP\|(2) and \fIservices\fP\|(5)
+for more information on sockets and service
+specifications, respectively.
+.I Lpd
+spawns a copy of itself to process the request; the master daemon
+continues to listen for new requests.
+.PP
+Clients communicate with
+.I lpd
+using a simple transaction oriented protocol.
+Authentication of remote clients is done based
+on the ``privilege port'' scheme employed by
+\fIrshd\fP\|(8C) and \fIrcmd\fP\|(3X).
+The following table shows the requests
+understood by
+.IR lpd .
+In each request the first byte indicates the
+``meaning'' of the request, followed by the name
+of the printer to which it should be applied. Additional
+qualifiers may follow, depending on the request.
+.DS
+.TS
+l l.
+Request Interpretation
+_
+^Aprinter\en check the queue for jobs and print any found
+^Bprinter\en receive and queue a job from another machine
+^Cprinter [users ...] [jobs ...]\en return short list of current queue state
+^Dprinter [users ...] [jobs ...]\en return long list of current queue state
+^Eprinter person [users ...] [jobs ...]\en remove jobs from a queue
+.TE
+.DE
+.PP
+The \fIlpr\fP\|(1) command
+is used by users to enter a print job in a local queue and to notify
+the local
+.I lpd
+that there are new jobs in the spooling area.
+.I Lpd
+either schedules the job to be printed locally, or if
+printing remotely, attempts to forward
+the job to the appropriate machine.
+If the printer cannot be opened or the destination
+machine is unreachable, the job will remain queued until it is
+possible to complete the work.
+.NH 2
+lpq \- show line printer queue
+.PP
+The \fIlpq\fP\|(1)
+program works recursively backwards displaying the queue of the machine with
+the printer and then the queue(s) of the machine(s) that lead to it.
+.I Lpq
+has two forms of output: in the default, short, format it
+gives a single line of output per queued job; in the long
+format it shows the list of files, and their sizes, that
+comprise a job.
+.NH 2
+lprm \- remove jobs from a queue
+.PP
+The \fIlprm\fP\|(1) command deletes jobs from a spooling
+queue. If necessary, \fIlprm\fP will first kill off a
+running daemon that is servicing the queue and restart
+it after the required files are removed. When removing
+jobs destined for a remote printer, \fIlprm\fP acts
+similarly to \fIlpq\fP except it first checks locally
+for jobs to remove and then
+tries to remove files in queues off-machine.
+.NH 2
+lpc \- line printer control program
+.PP
+The
+.IR lpc (8)
+program is used by the system administrator to control the
+operation of the line printer system.
+For each line printer configured in /etc/printcap,
+.I lpc
+may be used to:
+.IP \(bu
+disable or enable a printer,
+.IP \(bu
+disable or enable a printer's spooling queue,
+.IP \(bu
+rearrange the order of jobs in a spooling queue,
+.IP \(bu
+find the status of printers, and their associated
+spooling queues and printer daemons.
diff --git a/usr.sbin/lpr/SMM.doc/3.t b/usr.sbin/lpr/SMM.doc/3.t
new file mode 100644
index 0000000..8c950a9
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/3.t
@@ -0,0 +1,73 @@
+.\" Copyright (c) 1983, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)3.t 8.1 (Berkeley) 6/8/93
+.\"
+.NH 1
+Access control
+.PP
+The printer system maintains protected spooling areas so that
+users cannot circumvent printer accounting or
+remove files other than their own.
+The strategy used to maintain protected
+spooling areas is as follows:
+.IP \(bu 3
+The spooling area is writable only by a \fIdaemon\fP user
+and \fIdaemon\fP group.
+.IP \(bu 3
+The \fIlpr\fP program runs set-user-id to \fIroot\fP and
+set-group-id to group \fIdaemon\fP. The \fIroot\fP access permits
+reading any file required. Accessibility is verified
+with an \fIaccess\fP\|(2) call. The group ID
+is used in setting up proper ownership of files
+in the spooling area for \fIlprm\fP.
+.IP \(bu 3
+Control files in a spooling area are made with \fIdaemon\fP
+ownership and group ownership \fIdaemon\fP. Their mode is 0660.
+This insures control files are not modified by a user
+and that no user can remove files except through \fIlprm\fP.
+.IP \(bu 3
+The spooling programs,
+\fIlpd\fP, \fIlpq\fP, and \fIlprm\fP run set-user-id to \fIroot\fP
+and set-group-id to group \fIdaemon\fP to access spool files and printers.
+.IP \(bu 3
+The printer server, \fIlpd\fP,
+uses the same verification procedures as \fIrshd\fP\|(8C)
+in authenticating remote clients. The host on which a client
+resides must be present in the file /etc/hosts.equiv or /etc/hosts.lpd and
+the request message must come from a reserved port number.
+.PP
+In practice, none of \fIlpd\fP, \fIlpq\fP, or
+\fIlprm\fP would have to run as user \fIroot\fP if remote
+spooling were not supported. In previous incarnations of
+the printer system \fIlpd\fP ran set-user-id to \fIdaemon\fP,
+set-group-id to group \fIspooling\fP, and \fIlpq\fP and \fIlprm\fP ran
+set-group-id to group \fIspooling\fP.
diff --git a/usr.sbin/lpr/SMM.doc/4.t b/usr.sbin/lpr/SMM.doc/4.t
new file mode 100644
index 0000000..8800bc0
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/4.t
@@ -0,0 +1,206 @@
+.\" Copyright (c) 1983, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)4.t 8.1 (Berkeley) 6/8/93
+.\"
+.NH 1
+Setting up
+.PP
+The 4.3BSD release comes with the necessary programs
+installed and with the default line printer queue
+created. If the system must be modified, the
+makefile in the directory /usr/src/usr.lib/lpr
+should be used in recompiling and reinstalling
+the necessary programs.
+.PP
+The real work in setting up is to create the
+.I printcap
+file and any printer filters for printers not supported
+in the distribution system.
+.NH 2
+Creating a printcap file
+.PP
+The
+.I printcap
+database contains one or more entries per printer.
+A printer should have a separate spooling directory;
+otherwise, jobs will be printed on
+different printers depending on which printer daemon starts first.
+This section describes how to create entries for printers that do not
+conform to the default printer description (an LP-11 style interface to a
+standard, band printer).
+.NH 3
+Printers on serial lines
+.PP
+When a printer is connected via a serial communication line
+it must have the proper baud rate and terminal modes set.
+The following example is for a DecWriter III printer connected
+locally via a 1200 baud serial line.
+.DS
+.DT
+lp|LA-180 DecWriter III:\e
+ :lp=/dev/lp:br#1200:fs#06320:\e
+ :tr=\ef:of=/usr/lib/lpf:lf=/usr/adm/lpd-errs:
+.DE
+The
+.B lp
+entry specifies the file name to open for output. Here it could
+be left out since ``/dev/lp'' is the default.
+The
+.B br
+entry sets the baud rate for the tty line and the
+.B fs
+entry sets CRMOD, no parity, and XTABS (see \fItty\fP\|(4)).
+The
+.B tr
+entry indicates that a form-feed should be printed when the queue
+empties so the paper can be torn off without turning the printer off-line and
+pressing form feed.
+The
+.B of
+entry specifies the filter program
+.I lpf
+should be used for printing the files;
+more will be said about filters later.
+The last entry causes errors
+to be written to the file ``/usr/adm/lpd-errs''
+instead of the console. Most errors from \fIlpd\fP are logged using
+\fIsyslogd\fP\|(8) and will not be logged in the specified file. The
+filters should use \fIsyslogd\fP to report errors; only those that
+write to standard error output will end up with errors in the \fBlf\fP file.
+(Occasionally errors sent to standard error output have not appeared
+in the log file; the use of \fIsyslogd\fP is highly recommended.)
+.NH 3
+Remote printers
+.PP
+Printers that reside on remote hosts should have an empty
+.B lp
+entry.
+For example, the following printcap entry would send output to the printer
+named ``lp'' on the machine ``ucbvax''.
+.DS
+.DT
+lp|default line printer:\e
+ :lp=:rm=ucbvax:rp=lp:sd=/usr/spool/vaxlpd:
+.DE
+The
+.B rm
+entry is the name of the remote machine to connect to; this name must
+be a known host name for a machine on the network.
+The
+.B rp
+capability indicates
+the name of the printer on the remote machine is ``lp'';
+here it could be left out since this is the default value.
+The
+.B sd
+entry specifies ``/usr/spool/vaxlpd''
+as the spooling directory instead of the
+default value of ``/usr/spool/lpd''.
+.NH 2
+Output filters
+.PP
+Filters are used to handle device dependencies and to
+do accounting functions. The output filtering of
+.B of
+is used when accounting is
+not being done or when all text data must be passed through a filter.
+It is not intended to do accounting since it is started only once,
+all text files are filtered through it, and no provision is made for passing
+owners' login name, identifying the beginning and ending of jobs, etc.
+The other filters (if specified) are started for each file
+printed and do accounting if there is an
+.B af
+entry.
+If entries for both
+.B of
+and other filters are specified,
+the output filter is used only to print the banner page;
+it is then stopped to allow other filters access to the printer.
+An example of a printer that requires output filters
+is the Benson-Varian.
+.DS
+.DT
+va|varian|Benson-Varian:\e
+ :lp=/dev/va0:sd=/usr/spool/vad:of=/usr/lib/vpf:\e
+ :tf=/usr/lib/rvcat:mx#2000:pl#58:px=2112:py=1700:tr=\ef:
+.DE
+The
+.B tf
+entry specifies ``/usr/lib/rvcat'' as the filter to be
+used in printing \fItroff\fP\|(1) output.
+This filter is needed to set the device into print mode
+for text, and plot mode for printing
+.I troff
+files and raster images (see \fIva\fP\|(4V)).
+Note that the page length is set to 58 lines by the
+.B pl
+entry for 8.5" by 11" fan-fold paper.
+To enable accounting, the varian entry would be
+augmented with an
+.B af
+filter as shown below.
+.DS
+.DT
+va|varian|Benson-Varian:\e
+ :lp=/dev/va0:sd=/usr/spool/vad:of=/usr/lib/vpf:\e
+ :if=/usr/lib/vpf:tf=/usr/lib/rvcat:af=/usr/adm/vaacct:\e
+ :mx#2000:pl#58:px=2112:py=1700:tr=\ef:
+.DE
+.NH 2
+Access Control
+.PP
+Local access to printer queues is controlled with the
+.B rg
+printcap entry.
+.DS
+ :rg=lprgroup:
+.DE
+Users must be in the group
+.I lprgroup
+to submit jobs to the specified printer.
+The default is to allow all users access.
+Note that once the files are in the local queue, they can be printed
+locally or forwarded to another host depending on the configuration.
+.PP
+Remote access is controlled by listing the hosts in either the file
+/etc/hosts.equiv or /etc/hosts.lpd, one host per line. Note that
+.IR rsh (1)
+and
+.IR rlogin (1)
+use /etc/hosts.equiv to determine which hosts are equivalent for allowing logins
+without passwords. The file /etc/hosts.lpd is only used to control
+which hosts have line printer access.
+Remote access can be further restricted to only allow remote users with accounts
+on the local host to print jobs by using the \fBrs\fP printcap entry.
+.DS
+ :rs:
+.DE
diff --git a/usr.sbin/lpr/SMM.doc/5.t b/usr.sbin/lpr/SMM.doc/5.t
new file mode 100644
index 0000000..137a342
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/5.t
@@ -0,0 +1,116 @@
+.\" Copyright (c) 1983, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)5.t 8.1 (Berkeley) 6/8/93
+.\"
+.NH 1
+Output filter specifications
+.PP
+The filters supplied with 4.3BSD
+handle printing and accounting for most common
+line printers, the Benson-Varian, the wide (36") and
+narrow (11") Versatec printer/plotters. For other devices or accounting
+methods, it may be necessary to create a new filter.
+.PP
+Filters are spawned by \fIlpd\fP
+with their standard input the data to be printed, and standard output
+the printer. The standard error is attached to the
+.B lf
+file for logging errors or \fIsyslogd\fP may be used for logging errors.
+A filter must return a 0 exit
+code if there were no errors, 1 if the job should be reprinted,
+and 2 if the job should be thrown away.
+When \fIlprm\fP
+sends a kill signal to the \fIlpd\fP process controlling
+printing, it sends a SIGINT signal
+to all filters and descendents of filters.
+This signal can be trapped by filters that need
+to do cleanup operations such as
+deleting temporary files.
+.PP
+Arguments passed to a filter depend on its type.
+The
+.B of
+filter is called with the following arguments.
+.DS
+\fIfilter\fP \fB\-w\fPwidth \fB\-l\fPlength
+.DE
+The \fIwidth\fP and \fIlength\fP values come from the
+.B pw
+and
+.B pl
+entries in the printcap database.
+The
+.B if
+filter is passed the following parameters.
+.DS
+\fIfilter\fP [\|\fB\-c\fP\|] \fB\-w\fPwidth \fB\-l\fPlength \fB\-i\fPindent \fB\-n\fP login \fB\-h\fP host accounting_file
+.DE
+The
+.B \-c
+flag is optional, and only supplied when control characters
+are to be passed uninterpreted to the printer (when using the
+.B \-l
+option of
+.I lpr
+to print the file).
+The
+.B \-w
+and
+.B \-l
+parameters are the same as for the
+.B of
+filter.
+The
+.B \-n
+and
+.B \-h
+parameters specify the login name and host name of the job owner.
+The last argument is the name of the accounting file from
+.IR printcap .
+.PP
+All other filters are called with the following arguments:
+.DS
+\fIfilter\fP \fB\-x\fPwidth \fB\-y\fPlength \fB\-n\fP login \fB\-h\fP host accounting_file
+.DE
+The
+.B \-x
+and
+.B \-y
+options specify the horizontal and vertical page
+size in pixels (from the
+.B px
+and
+.B py
+entries in the printcap file).
+The rest of the arguments are the same as for the
+.B if
+filter.
diff --git a/usr.sbin/lpr/SMM.doc/6.t b/usr.sbin/lpr/SMM.doc/6.t
new file mode 100644
index 0000000..7087790
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/6.t
@@ -0,0 +1,94 @@
+.\" Copyright (c) 1983, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)6.t 8.1 (Berkeley) 6/8/93
+.\"
+.NH 1
+Line printer Administration
+.PP
+The
+.I lpc
+program provides local control over line printer activity.
+The major commands and their intended use will be described.
+The command format and remaining commands are described in
+.IR lpc (8).
+.LP
+\fBabort\fP and \fBstart\fP
+.IP
+.I Abort
+terminates an active spooling daemon on the local host immediately and
+then disables printing (preventing new daemons from being started by
+.IR lpr ).
+This is normally used to forcibly restart a hung line printer daemon
+(i.e., \fIlpq\fP reports that there is a daemon present but nothing is
+happening). It does not remove any jobs from the queue
+(use the \fIlprm\fP command instead).
+.I Start
+enables printing and requests \fIlpd\fP to start printing jobs.
+.LP
+\fBenable\fP and \fBdisable\fP
+.IP
+\fIEnable\fP and \fIdisable\fP allow spooling in the local queue to be
+turned on/off.
+This will allow/prevent
+.I lpr
+from putting new jobs in the spool queue. It is frequently convenient
+to turn spooling off while testing new line printer filters since the
+.I root
+user can still use
+.I lpr
+to put jobs in the queue but no one else can.
+The other main use is to prevent users from putting jobs in the queue
+when the printer is expected to be unavailable for a long time.
+.LP
+\fBrestart\fP
+.IP
+.I Restart
+allows ordinary users to restart printer daemons when
+.I lpq
+reports that there is no daemon present.
+.LP
+\fBstop\fP
+.IP
+.I Stop
+halts a spooling daemon after the current job completes;
+this also disables printing. This is a clean way to shutdown a
+printer to do maintenance, etc. Note that users can still enter jobs in a
+spool queue while a printer is
+.IR stopped .
+.LP
+\fBtopq\fP
+.IP
+.I Topq
+places jobs at the top of a printer queue. This can be used
+to reorder high priority jobs since
+.I lpr
+only provides first-come-first-serve ordering of jobs.
diff --git a/usr.sbin/lpr/SMM.doc/7.t b/usr.sbin/lpr/SMM.doc/7.t
new file mode 100644
index 0000000..a6f6bea
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/7.t
@@ -0,0 +1,226 @@
+.\" Copyright (c) 1983, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)7.t 8.1 (Berkeley) 6/8/93
+.\"
+.NH 1
+Troubleshooting
+.PP
+There are several messages that may be generated by the
+the line printer system. This section
+categorizes the most common and explains the cause
+for their generation. Where the message implies a failure,
+directions are given to remedy the problem.
+.PP
+In the examples below, the name
+.I printer
+is the name of the printer from the
+.I printcap
+database.
+.NH 2
+LPR
+.SH
+lpr: \fIprinter\fP\|: unknown printer
+.IP
+The
+.I printer
+was not found in the
+.I printcap
+database. Usually this is a typing mistake; however, it may indicate
+a missing or incorrect entry in the /etc/printcap file.
+.SH
+lpr: \fIprinter\fP\|: jobs queued, but cannot start daemon.
+.IP
+The connection to
+.I lpd
+on the local machine failed.
+This usually means the printer server started at
+boot time has died or is hung. Check the local socket
+/dev/printer to be sure it still exists (if it does not exist,
+there is no
+.I lpd
+process running).
+Usually it is enough to get a super-user to type the following to
+restart
+.IR lpd .
+.DS
+% /usr/lib/lpd
+.DE
+You can also check the state of the master printer daemon with the following.
+.DS
+% ps l`cat /usr/spool/lpd.lock`
+.DE
+.IP
+Another possibility is that the
+.I lpr
+program is not set-user-id to \fIroot\fP, set-group-id to group \fIdaemon\fP.
+This can be checked with
+.DS
+% ls \-lg /usr/ucb/lpr
+.DE
+.SH
+lpr: \fIprinter\fP\|: printer queue is disabled
+.IP
+This means the queue was turned off with
+.DS
+% lpc disable \fIprinter\fP
+.DE
+to prevent
+.I lpr
+from putting files in the queue. This is normally
+done by the system manager when a printer is
+going to be down for a long time. The
+printer can be turned back on by a super-user with
+.IR lpc .
+.NH 2
+LPQ
+.SH
+waiting for \fIprinter\fP to become ready (offline ?)
+.IP
+The printer device could not be opened by the daemon.
+This can happen for several reasons,
+the most common is that the printer is turned off-line.
+This message can also be generated if the printer is out
+of paper, the paper is jammed, etc.
+The actual reason is dependent on the meaning
+of error codes returned by system device driver.
+Not all printers supply enough information
+to distinguish when a printer is off-line or having
+trouble (e.g. a printer connected through a serial line).
+Another possible cause of this message is
+some other process, such as an output filter,
+has an exclusive open on the device. Your only recourse
+here is to kill off the offending program(s) and
+restart the printer with
+.IR lpc .
+.SH
+\fIprinter\fP is ready and printing
+.IP
+The
+.I lpq
+program checks to see if a daemon process exists for
+.I printer
+and prints the file \fIstatus\fP located in the spooling directory.
+If the daemon is hung, a super user can use
+.I lpc
+to abort the current daemon and start a new one.
+.SH
+waiting for \fIhost\fP to come up
+.IP
+This implies there is a daemon trying to connect to the remote
+machine named
+.I host
+to send the files in the local queue.
+If the remote machine is up,
+.I lpd
+on the remote machine is probably dead or
+hung and should be restarted as mentioned for
+.IR lpr .
+.SH
+sending to \fIhost\fP
+.IP
+The files should be in the process of being transferred to the remote
+.IR host .
+If not, the local daemon should be aborted and started with
+.IR lpc .
+.SH
+Warning: \fIprinter\fP is down
+.IP
+The printer has been marked as being unavailable with
+.IR lpc .
+.SH
+Warning: no daemon present
+.IP
+The \fIlpd\fP process overseeing
+the spooling queue, as specified in the ``lock'' file
+in that directory, does not exist. This normally occurs
+only when the daemon has unexpectedly died.
+The error log file for the printer and the \fIsyslogd\fP logs
+should be checked for a
+diagnostic from the deceased process.
+To restart an \fIlpd\fP, use
+.DS
+% lpc restart \fIprinter\fP
+.DE
+.SH
+no space on remote; waiting for queue to drain
+.IP
+This implies that there is insufficient disk space on the remote.
+If the file is large enough, there will never be enough space on
+the remote (even after the queue on the remote is empty). The solution here
+is to move the spooling queue or make more free space on the remote.
+.NH 2
+LPRM
+.SH
+lprm: \fIprinter\fP\|: cannot restart printer daemon
+.IP
+This case is the same as when
+.I lpr
+prints that the daemon cannot be started.
+.NH 2
+LPD
+.PP
+The
+.I lpd
+program can log many different messages using \fIsyslogd\fP\|(8).
+Most of these messages are about files that can not
+be opened and usually imply that the
+.I printcap
+file or the protection modes of the files are
+incorrect. Files may also be inaccessible if people
+manually manipulate the line printer system (i.e. they
+bypass the
+.I lpr
+program).
+.PP
+In addition to messages generated by
+.IR lpd ,
+any of the filters that
+.I lpd
+spawns may log messages using \fIsyslogd\fP or to the error log file
+(the file specified in the \fBlf\fP entry in \fIprintcap\fP\|).
+.NH 2
+LPC
+.PP
+.SH
+couldn't start printer
+.IP
+This case is the same as when
+.I lpr
+reports that the daemon cannot be started.
+.SH
+cannot examine spool directory
+.IP
+Error messages beginning with ``cannot ...'' are usually because of
+incorrect ownership or protection mode of the lock file, spooling
+directory or the
+.I lpc
+program.
diff --git a/usr.sbin/lpr/SMM.doc/Makefile b/usr.sbin/lpr/SMM.doc/Makefile
new file mode 100644
index 0000000..faeb266
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/Makefile
@@ -0,0 +1,12 @@
+# From: @(#)Makefile 8.1 (Berkeley) 6/8/93
+# $FreeBSD$
+
+BINDIR= /usr/share/doc
+VOLUME= smm/07.lpd
+SRCS= 0.t 1.t 2.t 3.t 4.t 5.t 6.t 7.t
+MACROS= -ms
+
+USE_TBL= yes
+SRCDIR= ${.CURDIR}
+
+.include <bsd.doc.mk>
diff --git a/usr.sbin/lpr/SMM.doc/spell.ok b/usr.sbin/lpr/SMM.doc/spell.ok
new file mode 100644
index 0000000..bf31319
--- /dev/null
+++ b/usr.sbin/lpr/SMM.doc/spell.ok
@@ -0,0 +1,70 @@
+Aprinter
+Bprinter
+CRMOD
+Cprinter
+DecWriter
+Dprinter
+Eprinter
+LPC
+LPD
+Lpd
+Manual''SMM:5
+SIGINT
+SMM:5
+Topq
+XTABS
+adm
+af
+br
+daemon
+daemons
+dev
+f:of
+fs
+hosts.equiv
+hosts.lpd
+lf
+lg
+lib
+lp:br
+lp:sd
+lpc
+lpd
+lpd.lock
+lpf
+lpf:lf
+lprgroup
+makefile
+mx
+offline
+pl
+printcap
+pw
+py
+rc
+rcmd
+rg
+rlogin
+rp
+rs
+rsh
+rshd
+rvcat
+rvcat:af
+rvcat:mx
+sd
+src
+syslogd
+tf
+topq
+ucb
+ucbvax
+ucbvax:rp
+usr.lib
+va0:sd
+vaacct
+vad:of
+varian
+vaxlpd
+vpf
+vpf:tf
diff --git a/usr.sbin/lpr/chkprintcap/Makefile b/usr.sbin/lpr/chkprintcap/Makefile
new file mode 100644
index 0000000..e671ec9
--- /dev/null
+++ b/usr.sbin/lpr/chkprintcap/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+PROG= chkprintcap
+MAN8= chkprintcap.8
+CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS}
+.PATH: ${.CURDIR}/../common_source
+DPADD= ${LIBLPR}
+LDADD= ${LIBLPR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/chkprintcap/chkprintcap.8 b/usr.sbin/lpr/chkprintcap/chkprintcap.8
new file mode 100644
index 0000000..ecf7822
--- /dev/null
+++ b/usr.sbin/lpr/chkprintcap/chkprintcap.8
@@ -0,0 +1,96 @@
+.\" Copyright 1997 Massachusetts Institute of Technology
+.\"
+.\" Permission to use, copy, modify, and distribute this software and
+.\" its documentation for any purpose and without fee is hereby
+.\" granted, provided that both the above copyright notice and this
+.\" permission notice appear in all copies, that both the above
+.\" copyright notice and this permission notice appear in all
+.\" supporting documentation, and that the name of M.I.T. not be used
+.\" in advertising or publicity pertaining to distribution of the
+.\" software without specific, written prior permission. M.I.T. makes
+.\" no representations about the suitability of this software for any
+.\" purpose. It is provided "as is" without express or implied
+.\" warranty.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+.\" SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.Dd November 30, 1997
+.Dt CHKPRINTCAP 8
+.Os
+.Sh NAME
+.Nm chkprintcap
+.Nd check validity of entries in the print spooler database
+.Sh SYNOPSIS
+.Nm chkprintcap
+.Op Fl d
+.Op Fl f Ar printcap
+.Sh DESCRIPTION
+.Nm Chkprintcap
+scans a
+.Xr printcap 5
+database
+(named by the
+.Ar printcap
+argument, or by default
+.Pa /etc/printcap ) ,
+looking for entries which are invalid in one way or another.
+The following checks are currently implemented:
+.Bl -enum -offset indent
+.It
+.Sq Li tc=
+references were properly expanded
+.It
+.Sq Li tc=
+references did not form a loop
+.It
+No two printers share the same spool directory
+.Po
+.Sq Li sd=
+capability
+.Pc .
+.El
+.Pp
+.Nm Chkprintcap
+exits with a status equal to the number of errors encountered before
+processing stopped. (In some cases, processing can stop before the
+entire file is scanned.)
+.Pp
+If the
+.Fl d
+flag is given,
+.Nm chkprintcap
+will attempt to create any missing spool directories, giving them
+.Sq Li u=rwx,go=rx
+(0755) mode, group
+.Sq Li daemon ,
+and the owner specified by the
+.Sq Li du=
+capability in the database (default 1, which corresponds to user
+.Sq Li daemon ) .
+.Sh SEE ALSO
+.Xr lpr 1 ,
+.Xr printcap 5 ,
+.Xr lpd 8
+.Sh AUTHORS
+The
+.Nm chkprintcap
+command was written by
+.An Garrett A. Wollman Aq wollman@lcs.mit.edu .
+.Sh BUGS
+Not enough sanity-checking is done. At a minimum, the ownership and
+mode of the spool directories should also be checked. Other
+parameters whose value could cause
+.Xr lpd 8
+to fail should be diagnosed.
diff --git a/usr.sbin/lpr/chkprintcap/chkprintcap.c b/usr.sbin/lpr/chkprintcap/chkprintcap.c
new file mode 100644
index 0000000..8b84656
--- /dev/null
+++ b/usr.sbin/lpr/chkprintcap/chkprintcap.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright 1997 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char copyright[] =
+ "Copyright (C) 1997, Massachusetts Institute of Technology\r\n";
+static const char rcsid[] =
+ "$FreeBSD$";
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/param.h> /* needed for lp.h but not used here */
+#include <dirent.h> /* ditto */
+#include "lp.h"
+#include "lp.local.h"
+
+static void check_spool_dirs(void);
+static int interpret_error(const struct printer *pp, int error);
+static void make_spool_dir(const struct printer *pp);
+static void note_spool_dir(const struct printer *pp, const struct stat *st);
+static void usage(void) __dead2;
+
+static int problems; /* number of problems encountered */
+
+/*
+ * chkprintcap - check the printcap file for syntactic and semantic errors
+ * Returns the number of problems found.
+ */
+int
+main(int argc, char **argv)
+{
+ int c, error, makedirs, more;
+ struct printer myprinter, *pp;
+
+ makedirs = 0;
+ pp = &myprinter;
+
+ while ((c = getopt(argc, argv, "df:")) != -1) {
+ switch (c) {
+ case 'd':
+ makedirs = 1;
+ break;
+
+ case 'f':
+ setprintcap(optarg);
+ break;
+
+ default:
+ usage();
+ }
+ }
+
+ if (optind != argc)
+ usage();
+
+ more = firstprinter(pp, &error);
+ if (interpret_error(pp, error) && more)
+ goto next;
+
+ while (more) {
+ struct stat stab;
+
+ errno = 0;
+ if (stat(pp->spool_dir, &stab) < 0) {
+ if (errno == ENOENT && makedirs) {
+ make_spool_dir(pp);
+ } else {
+ problems++;
+ warn("%s: %s", pp->printer, pp->spool_dir);
+ }
+ } else {
+ note_spool_dir(pp, &stab);
+ }
+
+ /* Make other validity checks here... */
+
+next:
+ more = nextprinter(pp, &error);
+ if (interpret_error(pp, error) && more)
+ goto next;
+ }
+ check_spool_dirs();
+ return problems;
+}
+
+/*
+ * Interpret the error code. Returns 1 if we should skip to the next
+ * record (as this record is unlikely to make sense). If the problem
+ * is very severe, exit. Otherwise, return zero.
+ */
+static int
+interpret_error(const struct printer *pp, int error)
+{
+ switch(error) {
+ case PCAPERR_OSERR:
+ err(++problems, "reading printer database");
+ case PCAPERR_TCLOOP:
+ ++problems;
+ warnx("%s: loop detected in tc= expansion", pp->printer);
+ return 1;
+ case PCAPERR_TCOPEN:
+ warnx("%s: unresolved tc= expansion", pp->printer);
+ return 1;
+ case PCAPERR_SUCCESS:
+ break;
+ default:
+ errx(++problems, "unknown printcap library error %d", error);
+ }
+ return 0;
+}
+
+/*
+ * Keep the list of spool directories. Note that we don't whine
+ * until all spool directories are noted, so that all of the more serious
+ * problems are noted first. We keep the list sorted by st_dev and
+ * st_ino, so that the problem spool directories can be noted in
+ * a single loop.
+ */
+struct dirlist {
+ LIST_ENTRY(dirlist) link;
+ struct stat stab;
+ char *path;
+ char *printer;
+};
+
+static LIST_HEAD(, dirlist) dirlist;
+
+static int
+lessp(const struct dirlist *a, const struct dirlist *b)
+{
+ if (a->stab.st_dev == b->stab.st_dev)
+ return a->stab.st_ino < b->stab.st_ino;
+ return a->stab.st_dev < b->stab.st_dev;
+}
+
+static int
+equal(const struct dirlist *a, const struct dirlist *b)
+{
+ return ((a->stab.st_dev == b->stab.st_dev)
+ && (a->stab.st_ino == b->stab.st_ino));
+}
+
+static void
+note_spool_dir(const struct printer *pp, const struct stat *st)
+{
+ struct dirlist *dp, *dp2, *last;
+
+ dp = malloc(sizeof *dp);
+ if (dp == 0)
+ err(++problems, "malloc(%lu)", (u_long)sizeof *dp);
+
+ dp->stab = *st;
+ dp->printer = strdup(pp->printer);
+ if (dp->printer == 0)
+ err(++problems, "malloc(%lu)", strlen(pp->printer) + 1UL);
+ dp->path = strdup(pp->spool_dir);
+ if (dp->path == 0)
+ err(++problems, "malloc(%lu)", strlen(pp->spool_dir) + 1UL);
+
+ last = 0;
+ dp2 = dirlist.lh_first;
+ while (dp2 && lessp(dp, dp2)) {
+ last = dp2;
+ dp2 = dp2->link.le_next;
+ }
+
+ if (last) {
+ LIST_INSERT_AFTER(last, dp, link);
+ } else {
+ LIST_INSERT_HEAD(&dirlist, dp, link);
+ }
+}
+
+static void
+check_spool_dirs(void)
+{
+ struct dirlist *dp, *dp2;
+
+ for (dp = dirlist.lh_first; dp; dp = dp2) {
+ dp2 = dp->link.le_next;
+
+ if (dp2 != 0 && equal(dp, dp2)) {
+ ++problems;
+ if (strcmp(dp->path, dp2->path) == 0) {
+ warnx("%s and %s share the same spool, %s",
+ dp->printer, dp2->printer, dp->path);
+ } else {
+ warnx("%s (%s) and %s (%s) are the same "
+ "directory", dp->path, dp->printer,
+ dp2->path, dp2->printer);
+ }
+ continue;
+ }
+ /* Should probably check owners and modes here. */
+ }
+}
+
+#ifndef SPOOL_DIR_MODE
+#define SPOOL_DIR_MODE (S_IRUSR | S_IWUSR | S_IXUSR \
+ | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
+#endif
+
+static void
+make_spool_dir(const struct printer *pp)
+{
+ char *sd = pp->spool_dir;
+ struct group *gr;
+ struct stat stab;
+
+ if (mkdir(sd, S_IRUSR | S_IXUSR) < 0) {
+ problems++;
+ warn("%s: mkdir %s", pp->printer, sd);
+ return;
+ }
+ gr = getgrnam("daemon");
+ if (gr == 0)
+ errx(++problems, "cannot locate daemon group");
+
+ if (chown(sd, pp->daemon_user, gr->gr_gid) < 0) {
+ ++problems;
+ warn("%s: cannot change ownership to %ld:%ld", sd,
+ (long)pp->daemon_user, (long)gr->gr_gid);
+ return;
+ }
+
+ if (chmod(sd, SPOOL_DIR_MODE) < 0) {
+ ++problems;
+ warn("%s: cannot change mode to %lo", sd, (long)SPOOL_DIR_MODE);
+ return;
+ }
+ if (stat(sd, &stab) < 0)
+ err(++problems, "stat: %s", sd);
+
+ note_spool_dir(pp, &stab);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage:\n\tchkprintcap [-d] [-f printcapfile]\n");
+ exit(1);
+}
diff --git a/usr.sbin/lpr/common_source/Makefile b/usr.sbin/lpr/common_source/Makefile
new file mode 100644
index 0000000..e5c6191
--- /dev/null
+++ b/usr.sbin/lpr/common_source/Makefile
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+#
+# Library of internal routines for the print spooler suite.
+# Originally these were compiled separately into each program,
+# but the library makes it much easier to modularize them.
+#
+LIB= lpr
+SRCS= common.c displayq.c net.c printcap.c request.c rmjob.c \
+ startdaemon.c
+NOMAN= noman
+NOPROFILE= noprofile
+NOPIC= nopic
+CFLAGS+= ${CWARNFLAGS}
+
+install:
+
+.include <bsd.lib.mk>
diff --git a/usr.sbin/lpr/common_source/common.c b/usr.sbin/lpr/common_source/common.c
new file mode 100644
index 0000000..67a1725
--- /dev/null
+++ b/usr.sbin/lpr/common_source/common.c
@@ -0,0 +1,592 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+/*
+static char sccsid[] = "@(#)common.c 8.5 (Berkeley) 4/28/95";
+*/
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+
+/*
+ * Routines and data common to all the line printer functions.
+ */
+char line[BUFSIZ];
+char *name; /* program name */
+
+extern uid_t uid, euid;
+
+static int compar __P((const void *, const void *));
+
+/*
+ * Getline reads a line from the control file cfp, removes tabs, converts
+ * new-line to null and leaves it in line.
+ * Returns 0 at EOF or the number of characters read.
+ */
+int
+getline(cfp)
+ FILE *cfp;
+{
+ register int linel = 0;
+ register char *lp = line;
+ register int c;
+
+ while ((c = getc(cfp)) != '\n' && linel+1 < sizeof(line)) {
+ if (c == EOF)
+ return(0);
+ if (c == '\t') {
+ do {
+ *lp++ = ' ';
+ linel++;
+ } while ((linel & 07) != 0 && linel+1 < sizeof(line));
+ continue;
+ }
+ *lp++ = c;
+ linel++;
+ }
+ *lp++ = '\0';
+ return(linel);
+}
+
+/*
+ * Scan the current directory and make a list of daemon files sorted by
+ * creation time.
+ * Return the number of entries and a pointer to the list.
+ */
+int
+getq(pp, namelist)
+ const struct printer *pp;
+ struct queue *(*namelist[]);
+{
+ register struct dirent *d;
+ register struct queue *q, **queue;
+ register int nitems;
+ struct stat stbuf;
+ DIR *dirp;
+ int arraysz;
+
+ seteuid(euid);
+ if ((dirp = opendir(pp->spool_dir)) == NULL)
+ return(-1);
+ if (fstat(dirp->dd_fd, &stbuf) < 0)
+ goto errdone;
+ seteuid(uid);
+
+ /*
+ * Estimate the array size by taking the size of the directory file
+ * and dividing it by a multiple of the minimum size entry.
+ */
+ arraysz = (stbuf.st_size / 24);
+ queue = (struct queue **)malloc(arraysz * sizeof(struct queue *));
+ if (queue == NULL)
+ goto errdone;
+
+ nitems = 0;
+ while ((d = readdir(dirp)) != NULL) {
+ if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
+ continue; /* daemon control files only */
+ seteuid(euid);
+ if (stat(d->d_name, &stbuf) < 0)
+ continue; /* Doesn't exist */
+ seteuid(uid);
+ q = (struct queue *)malloc(sizeof(time_t)+strlen(d->d_name)+1);
+ if (q == NULL)
+ goto errdone;
+ q->q_time = stbuf.st_mtime;
+ strcpy(q->q_name, d->d_name);
+ /*
+ * Check to make sure the array has space left and
+ * realloc the maximum size.
+ */
+ if (++nitems > arraysz) {
+ arraysz *= 2;
+ queue = (struct queue **)realloc((char *)queue,
+ arraysz * sizeof(struct queue *));
+ if (queue == NULL)
+ goto errdone;
+ }
+ queue[nitems-1] = q;
+ }
+ closedir(dirp);
+ if (nitems)
+ qsort(queue, nitems, sizeof(struct queue *), compar);
+ *namelist = queue;
+ return(nitems);
+
+errdone:
+ closedir(dirp);
+ return(-1);
+}
+
+/*
+ * Compare modification times.
+ */
+static int
+compar(p1, p2)
+ const void *p1, *p2;
+{
+ const struct queue *qe1, *qe2;
+ qe1 = *(const struct queue **)p1;
+ qe2 = *(const struct queue **)p2;
+
+ if (qe1->q_time < qe2->q_time)
+ return (-1);
+ if (qe1->q_time > qe2->q_time)
+ return (1);
+ /*
+ * At this point, the two files have the same last-modification time.
+ * return a result based on filenames, so that 'cfA001some.host' will
+ * come before 'cfA002some.host'. Since the jobid ('001') will wrap
+ * around when it gets to '999', we also assume that '9xx' jobs are
+ * older than '0xx' jobs.
+ */
+ if ((qe1->q_name[3] == '9') && (qe2->q_name[3] == '0'))
+ return (-1);
+ if ((qe1->q_name[3] == '0') && (qe2->q_name[3] == '9'))
+ return (1);
+ return (strcmp(qe1->q_name,qe2->q_name));
+}
+
+/* sleep n milliseconds */
+void
+delay(n)
+ int n;
+{
+ struct timeval tdelay;
+
+ if (n <= 0 || n > 10000)
+ fatal((struct printer *)0, /* fatal() knows how to deal */
+ "unreasonable delay period (%d)", n);
+ tdelay.tv_sec = n / 1000;
+ tdelay.tv_usec = n * 1000 % 1000000;
+ (void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tdelay);
+}
+
+char *
+lock_file_name(pp, buf, len)
+ const struct printer *pp;
+ char *buf;
+ size_t len;
+{
+ static char staticbuf[MAXPATHLEN];
+
+ if (buf == 0)
+ buf = staticbuf;
+ if (len == 0)
+ len = MAXPATHLEN;
+
+ if (pp->lock_file[0] == '/') {
+ buf[0] = '\0';
+ strncpy(buf, pp->lock_file, len);
+ } else {
+ snprintf(buf, len, "%s/%s", pp->spool_dir, pp->lock_file);
+ }
+ return buf;
+}
+
+char *
+status_file_name(pp, buf, len)
+ const struct printer *pp;
+ char *buf;
+ size_t len;
+{
+ static char staticbuf[MAXPATHLEN];
+
+ if (buf == 0)
+ buf = staticbuf;
+ if (len == 0)
+ len = MAXPATHLEN;
+
+ if (pp->status_file[0] == '/') {
+ buf[0] = '\0';
+ strncpy(buf, pp->status_file, len);
+ } else {
+ snprintf(buf, len, "%s/%s", pp->spool_dir, pp->status_file);
+ }
+ return buf;
+}
+
+/* routine to get a current timestamp, optionally in a standard-fmt string */
+void
+lpd_gettime(tsp, strp, strsize)
+ struct timespec *tsp;
+ char *strp;
+ int strsize;
+{
+ struct timespec local_ts;
+ struct timeval btime;
+ char *destp;
+ char tempstr[TIMESTR_SIZE];
+
+ if (tsp == NULL)
+ tsp = &local_ts;
+
+ /* some platforms have a routine called clock_gettime, but the
+ * routine does nothing but return "not implemented". */
+ memset(tsp, 0, sizeof(struct timespec));
+ if (clock_gettime(CLOCK_REALTIME, tsp)) {
+ /* nanosec-aware rtn failed, fall back to microsec-aware rtn */
+ memset(tsp, 0, sizeof(struct timespec));
+ gettimeofday(&btime, NULL);
+ tsp->tv_sec = btime.tv_sec;
+ tsp->tv_nsec = btime.tv_usec * 1000;
+ }
+
+ /* caller may not need a character-ized version */
+ if ((strp == NULL) || (strsize < 1))
+ return;
+
+ strftime(tempstr, TIMESTR_SIZE, LPD_TIMESTAMP_PATTERN,
+ localtime(&tsp->tv_sec));
+
+ /*
+ * This check is for implementations of strftime which treat %z
+ * (timezone as [+-]hhmm ) like %Z (timezone as characters), or
+ * completely ignore %z. This section is not needed on freebsd.
+ * I'm not sure this is completely right, but it should work OK
+ * for EST and EDT...
+ */
+#ifdef STRFTIME_WRONG_z
+ destp = strrchr(tempstr, ':');
+ if (destp != NULL) {
+ destp += 3;
+ if ((*destp != '+') && (*destp != '-')) {
+ char savday[6];
+ int tzmin = timezone / 60;
+ int tzhr = tzmin / 60;
+ if (daylight)
+ tzhr--;
+ strcpy(savday, destp + strlen(destp) - 4);
+ snprintf(destp, (destp - tempstr), "%+03d%02d",
+ (-1*tzhr), tzmin % 60);
+ strcat(destp, savday);
+ }
+ }
+#endif
+
+ if (strsize > TIMESTR_SIZE) {
+ strsize = TIMESTR_SIZE;
+ strp[TIMESTR_SIZE+1] = '\0';
+ }
+ strncpy(strp, tempstr, strsize);
+}
+
+/* routines for writing transfer-statistic records */
+void
+trstat_init(pp, fname, filenum)
+ struct printer *pp;
+ const char *fname;
+ int filenum;
+{
+ register const char *srcp;
+ register char *destp, *endp;
+
+ /*
+ * Figure out the job id of this file. The filename should be
+ * 'cf', 'df', or maybe 'tf', followed by a letter (or sometimes
+ * two), followed by the jobnum, followed by a hostname.
+ * The jobnum is usually 3 digits, but might be as many as 5.
+ * Note that some care has to be taken parsing this, as the
+ * filename could be coming from a remote-host, and thus might
+ * not look anything like what is expected...
+ */
+ memset(pp->jobnum, 0, sizeof(pp->jobnum));
+ pp->jobnum[0] = '0';
+ srcp = strchr(fname, '/');
+ if (srcp == NULL)
+ srcp = fname;
+ destp = &(pp->jobnum[0]);
+ endp = destp + 5;
+ while (*srcp != '\0' && (*srcp < '0' || *srcp > '9'))
+ srcp++;
+ while (*srcp >= '0' && *srcp <= '9' && destp < endp)
+ *(destp++) = *(srcp++);
+
+ /* get the starting time in both numeric and string formats, and
+ * save those away along with the file-number */
+ pp->jobdfnum = filenum;
+ lpd_gettime(&pp->tr_start, pp->tr_timestr, TIMESTR_SIZE);
+
+ return;
+}
+
+void
+trstat_write(pp, sendrecv, bytecnt, userid, otherhost, orighost)
+ struct printer *pp;
+ tr_sendrecv sendrecv;
+ size_t bytecnt;
+ const char *userid;
+ const char *otherhost;
+ const char *orighost;
+{
+#define STATLINE_SIZE 1024
+ double trtime;
+ int remspace;
+ int statfile;
+ char thishost[MAXHOSTNAMELEN+1], statline[STATLINE_SIZE];
+ const char *rectype, *statfname;
+ const char *lprhost, *sendhost, *recvhost, *recvdev;
+ char *eostat;
+#define UPD_EOSTAT(xStr) do { \
+ eostat = strchr(xStr, '\0'); \
+ remspace = eostat - xStr; \
+} while(0)
+
+ lpd_gettime(&pp->tr_done, NULL, 0);
+ trtime = DIFFTIME_TS(pp->tr_done, pp->tr_start);
+
+ gethostname(thishost, sizeof(thishost));
+ lprhost = sendhost = recvhost = recvdev = NULL;
+ switch (sendrecv) {
+ case TR_SENDING:
+ rectype = "send";
+ statfname = pp->stat_send;
+ sendhost = thishost;
+ recvhost = otherhost;
+ break;
+ case TR_RECVING:
+ rectype = "recv";
+ statfname = pp->stat_recv;
+ sendhost = otherhost;
+ recvhost = thishost;
+ break;
+ case TR_PRINTING:
+ /* copying to a device (presumably local, though things
+ * like 'net/CAP' can confuse this assumption...) */
+ rectype = "prnt";
+ statfname = pp->stat_send;
+ sendhost = thishost;
+ recvdev = _PATH_DEFDEVLP;
+ if (pp->lp) recvdev = pp->lp;
+ break;
+ default:
+ /* internal error... should we syslog/printf an error? */
+ return;
+ }
+ if (statfname == NULL) return;
+
+ /*
+ * the original-host and userid are found out by reading thru the
+ * cf (control-file) for the job. Unfortunately, on incoming jobs
+ * the df's (data-files) are sent before the matching cf, so the
+ * orighost & userid are generally not-available for incoming jobs.
+ *
+ * (it would be nice to create a work-around for that..)
+ */
+ if (orighost && (*orighost != '\0'))
+ lprhost = orighost;
+ else
+ lprhost = ".na.";
+ if (*userid == '\0') userid = NULL;
+
+ /*
+ * Format of statline.
+ * Some of the keywords listed here are not implemented here, but
+ * they are listed to reserve the meaning for a given keyword.
+ * Fields are separated by a blank. The fields in statline are:
+ * <tstamp> - time the transfer started
+ * <ptrqueue> - name of the printer queue (the short-name...)
+ * <hname> - hostname the file originally came from (the
+ * 'lpr host'), if known, or "_na_" if not known.
+ * <xxx> - id of job from that host (generally three digits)
+ * <n> - file count (# of file within job)
+ * <rectype> - 4-byte field indicating the type of transfer
+ * statistics record. "send" means it's from the
+ * host sending a datafile, "recv" means it's from
+ * a host as it receives a datafile.
+ * user=<userid> - user who sent the job (if known)
+ * secs=<n> - seconds it took to transfer the file
+ * bytes=<n> - number of bytes transfered (ie, "bytecount")
+ * bps=<n.n>e<n> - Bytes/sec (if the transfer was "big enough"
+ * for this to be useful)
+ * ! top=<str> - type of printer (if the type is defined in
+ * printcap, and if this statline is for sending
+ * a file to that ptr)
+ * ! qls=<n> - queue-length at start of send/print-ing a job
+ * ! qle=<n> - queue-length at end of send/print-ing a job
+ * sip=<addr> - IP address of sending host, only included when
+ * receiving a job.
+ * shost=<hname> - sending host (if that does != the original host)
+ * rhost=<hname> - hostname receiving the file (ie, "destination")
+ * rdev=<dev> - device receiving the file, when the file is being
+ * send to a device instead of a remote host.
+ *
+ * Note: A single print job may be transferred multiple times. The
+ * original 'lpr' occurs on one host, and that original host might
+ * send to some interim host (or print server). That interim host
+ * might turn around and send the job to yet another host (most likely
+ * the real printer). The 'shost=' parameter is only included if the
+ * sending host for this particular transfer is NOT the same as the
+ * host which did the original 'lpr'.
+ *
+ * Many values have 'something=' tags before them, because they are
+ * in some sense "optional", or their order may vary. "Optional" may
+ * mean in the sense that different SITES might choose to have other
+ * fields in the record, or that some fields are only included under
+ * some circumstances. Programs processing these records should not
+ * assume the order or existence of any of these keyword fields.
+ */
+ snprintf(statline, STATLINE_SIZE, "%s %s %s %s %03ld %s",
+ pp->tr_timestr, pp->printer, lprhost,
+ pp->jobnum, pp->jobdfnum, rectype);
+ UPD_EOSTAT(statline);
+
+ if (userid != NULL) {
+ snprintf(eostat, remspace, " user=%s", userid);
+ UPD_EOSTAT(statline);
+ }
+ snprintf(eostat, remspace, " secs=%#.2f bytes=%u", trtime, bytecnt);
+ UPD_EOSTAT(statline);
+
+ /* the bps field duplicates info from bytes and secs, so do not
+ * bother to include it for very small files */
+ if ((bytecnt > 25000) && (trtime > 1.1)) {
+ snprintf(eostat, remspace, " bps=%#.2e",
+ ((double)bytecnt/trtime));
+ UPD_EOSTAT(statline);
+ }
+
+ if (sendrecv == TR_RECVING) {
+ if (remspace > 5+strlen(from_ip) ) {
+ snprintf(eostat, remspace, " sip=%s", from_ip);
+ UPD_EOSTAT(statline);
+ }
+ }
+ if (0 != strcmp(lprhost, sendhost)) {
+ if (remspace > 7+strlen(sendhost) ) {
+ snprintf(eostat, remspace, " shost=%s", sendhost);
+ UPD_EOSTAT(statline);
+ }
+ }
+ if (recvhost) {
+ if (remspace > 7+strlen(recvhost) ) {
+ snprintf(eostat, remspace, " rhost=%s", recvhost);
+ UPD_EOSTAT(statline);
+ }
+ }
+ if (recvdev) {
+ if (remspace > 6+strlen(recvdev) ) {
+ snprintf(eostat, remspace, " rdev=%s", recvdev);
+ UPD_EOSTAT(statline);
+ }
+ }
+ if (remspace > 1) {
+ strcpy(eostat, "\n");
+ } else {
+ /* probably should back up to just before the final " x=".. */
+ strcpy(statline+STATLINE_SIZE-2, "\n");
+ }
+ statfile = open(statfname, O_WRONLY|O_APPEND, 0664);
+ if (statfile < 0) {
+ /* statfile was given, but we can't open it. should we
+ * syslog/printf this as an error? */
+ return;
+ }
+ write(statfile, statline, strlen(statline));
+ close(statfile);
+
+ return;
+#undef UPD_EOSTAT
+}
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#ifdef __STDC__
+fatal(const struct printer *pp, const char *msg, ...)
+#else
+fatal(pp, msg, va_alist)
+ const struct printer *pp;
+ char *msg;
+ va_dcl
+#endif
+{
+ va_list ap;
+#ifdef __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+ if (from != host)
+ (void)printf("%s: ", host);
+ (void)printf("%s: ", name);
+ if (pp && pp->printer)
+ (void)printf("%s: ", pp->printer);
+ (void)vprintf(msg, ap);
+ va_end(ap);
+ (void)putchar('\n');
+ exit(1);
+}
+
+/*
+ * Close all file descriptors from START on up.
+ * This is a horrific kluge, since getdtablesize() might return
+ * ``infinity'', in which case we will be spending a long time
+ * closing ``files'' which were never open. Perhaps it would
+ * be better to close the first N fds, for some small value of N.
+ */
+void
+closeallfds(start)
+ int start;
+{
+ int stop = getdtablesize();
+ for (; start < stop; start++)
+ close(start);
+}
+
diff --git a/usr.sbin/lpr/common_source/displayq.c b/usr.sbin/lpr/common_source/displayq.c
new file mode 100644
index 0000000..7b1df2c
--- /dev/null
+++ b/usr.sbin/lpr/common_source/displayq.c
@@ -0,0 +1,549 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+/*
+static char sccsid[] = "@(#)displayq.c 8.4 (Berkeley) 4/28/95";
+*/
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define psignal foil_gcc_psignal
+#define sys_siglist foil_gcc_siglist
+#include <unistd.h>
+#undef psignal
+#undef sys_siglist
+
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+
+/*
+ * Routines to display the state of the queue.
+ */
+#define JOBCOL 40 /* column for job # in -l format */
+#define OWNCOL 7 /* start of Owner column in normal */
+#define SIZCOL 62 /* start of Size column in normal */
+
+/*
+ * Stuff for handling job specifications
+ */
+extern uid_t uid, euid;
+
+static int col; /* column on screen */
+static char current[40]; /* current file being printed */
+static char file[132]; /* print file name */
+static int first; /* first file in ``files'' column? */
+static int garbage; /* # of garbage cf files */
+static int lflag; /* long output option */
+static int rank; /* order to be printed (-1=none, 0=active) */
+static long totsize; /* total print job size in bytes */
+
+static char *head0 = "Rank Owner Job Files";
+static char *head1 = "Total Size\n";
+
+static void alarmhandler __P((int));
+static void warn __P((const struct printer *pp));
+
+/*
+ * Display the current state of the queue. Format = 1 if long format.
+ */
+void
+displayq(pp, format)
+ struct printer *pp;
+ int format;
+{
+ register struct queue *q;
+ register int i, nitems, fd, ret;
+ register char *cp;
+ struct queue **queue;
+ struct stat statb;
+ FILE *fp;
+ void (*savealrm)(int);
+
+ lflag = format;
+ totsize = 0;
+ rank = -1;
+
+ if ((cp = checkremote(pp))) {
+ printf("Warning: %s\n", cp);
+ free(cp);
+ }
+
+ /*
+ * Print out local queue
+ * Find all the control files in the spooling directory
+ */
+ seteuid(euid);
+ if (chdir(pp->spool_dir) < 0)
+ fatal(pp, "cannot chdir to spooling directory: %s",
+ strerror(errno));
+ seteuid(uid);
+ if ((nitems = getq(pp, &queue)) < 0)
+ fatal(pp, "cannot examine spooling area\n");
+ seteuid(euid);
+ ret = stat(pp->lock_file, &statb);
+ seteuid(uid);
+ if (ret >= 0) {
+ if (statb.st_mode & LFM_PRINT_DIS) {
+ if (pp->remote)
+ printf("%s: ", host);
+ printf("Warning: %s is down: ", pp->printer);
+ seteuid(euid);
+ fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
+ seteuid(uid);
+ if (fd >= 0) {
+ while ((i = read(fd, line, sizeof(line))) > 0)
+ (void) fwrite(line, 1, i, stdout);
+ (void) close(fd); /* unlocks as well */
+ } else
+ putchar('\n');
+ }
+ if (statb.st_mode & LFM_QUEUE_DIS) {
+ if (pp->remote)
+ printf("%s: ", host);
+ printf("Warning: %s queue is turned off\n",
+ pp->printer);
+ }
+ }
+
+ if (nitems) {
+ seteuid(euid);
+ fp = fopen(pp->lock_file, "r");
+ seteuid(uid);
+ if (fp == NULL)
+ warn(pp);
+ else {
+ /* get daemon pid */
+ cp = current;
+ while ((i = getc(fp)) != EOF && i != '\n')
+ *cp++ = i;
+ *cp = '\0';
+ i = atoi(current);
+ if (i <= 0) {
+ ret = -1;
+ } else {
+ seteuid(euid);
+ ret = kill(i, 0);
+ seteuid(uid);
+ }
+ if (ret < 0) {
+ warn(pp);
+ } else {
+ /* read current file name */
+ cp = current;
+ while ((i = getc(fp)) != EOF && i != '\n')
+ *cp++ = i;
+ *cp = '\0';
+ /*
+ * Print the status file.
+ */
+ if (pp->remote)
+ printf("%s: ", host);
+ seteuid(euid);
+ fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
+ seteuid(uid);
+ if (fd >= 0) {
+ while ((i = read(fd, line,
+ sizeof(line))) > 0)
+ fwrite(line, 1, i, stdout);
+ close(fd); /* unlocks as well */
+ } else
+ putchar('\n');
+ }
+ (void) fclose(fp);
+ }
+ /*
+ * Now, examine the control files and print out the jobs to
+ * be done for each user.
+ */
+ if (!lflag)
+ header();
+ for (i = 0; i < nitems; i++) {
+ q = queue[i];
+ inform(pp, q->q_name);
+ free(q);
+ }
+ free(queue);
+ }
+ if (!pp->remote) {
+ if (nitems == 0)
+ puts("no entries");
+ return;
+ }
+
+ /*
+ * Print foreign queue
+ * Note that a file in transit may show up in either queue.
+ */
+ if (nitems)
+ putchar('\n');
+ (void) snprintf(line, sizeof(line), "%c%s", format ? '\4' : '\3',
+ pp->remote_queue);
+ cp = line;
+ for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) {
+ cp += strlen(cp);
+ (void) sprintf(cp, " %d", requ[i]);
+ }
+ for (i = 0; i < users && cp - line + 1 + strlen(user[i]) <
+ sizeof(line) - 1; i++) {
+ cp += strlen(cp);
+ *cp++ = ' ';
+ (void) strcpy(cp, user[i]);
+ }
+ strcat(line, "\n");
+ savealrm = signal(SIGALRM, alarmhandler);
+ alarm(pp->conn_timeout);
+ fd = getport(pp, pp->remote_host, 0);
+ alarm(0);
+ (void)signal(SIGALRM, savealrm);
+ if (fd < 0) {
+ if (from != host)
+ printf("%s: ", host);
+ printf("connection to %s is down\n", pp->remote_host);
+ }
+ else {
+ i = strlen(line);
+ if (write(fd, line, i) != i)
+ fatal(pp, "Lost connection");
+ while ((i = read(fd, line, sizeof(line))) > 0)
+ (void) fwrite(line, 1, i, stdout);
+ (void) close(fd);
+ }
+}
+
+/*
+ * Print a warning message if there is no daemon present.
+ */
+static void
+warn(pp)
+ const struct printer *pp;
+{
+ if (pp->remote)
+ printf("%s: ", host);
+ puts("Warning: no daemon present");
+ current[0] = '\0';
+}
+
+/*
+ * Print the header for the short listing format
+ */
+void
+header()
+{
+ printf(head0);
+ col = strlen(head0)+1;
+ blankfill(SIZCOL);
+ printf(head1);
+}
+
+void
+inform(pp, cf)
+ const struct printer *pp;
+ char *cf;
+{
+ register int copycnt;
+ char savedname[MAXPATHLEN+1];
+ FILE *cfp;
+
+ /*
+ * There's a chance the control file has gone away
+ * in the meantime; if this is the case just keep going
+ */
+ seteuid(euid);
+ if ((cfp = fopen(cf, "r")) == NULL)
+ return;
+ seteuid(uid);
+
+ if (rank < 0)
+ rank = 0;
+ if (pp->remote || garbage || strcmp(cf, current))
+ rank++;
+
+ /*
+ * The cf-file may include commands to print more than one datafile
+ * from the user. For each datafile, the cf-file contains at least
+ * one line which starts with some format-specifier ('a'-'z'), and
+ * a second line ('N'ame) which indicates the original name the user
+ * specified for that file. There can be multiple format-spec lines
+ * for a single Name-line, if the user requested multiple copies of
+ * that file. Standard lpr puts the format-spec line(s) before the
+ * Name-line, while lprNG puts the Name-line before the format-spec
+ * line(s). This section needs to handle the lines in either order.
+ */
+ copycnt = 0;
+ file[0] = '\0';
+ savedname[0] = '\0';
+ while (getline(cfp)) {
+ switch (line[0]) {
+ case 'P': /* Was this file specified in the user's list? */
+ if (!inlist(line+1, cf)) {
+ fclose(cfp);
+ return;
+ }
+ if (lflag) {
+ printf("\n%s: ", line+1);
+ col = strlen(line+1) + 2;
+ prank(rank);
+ blankfill(JOBCOL);
+ printf(" [job %s]\n", cf+3);
+ } else {
+ col = 0;
+ prank(rank);
+ blankfill(OWNCOL);
+ printf("%-10s %-3d ", line+1, atoi(cf+3));
+ col += 16;
+ first = 1;
+ }
+ continue;
+ default: /* some format specifer and file name? */
+ if (line[0] < 'a' || line[0] > 'z')
+ break;
+ if (copycnt == 0 || strcmp(file, line+1) != 0) {
+ strncpy(file, line + 1, sizeof(file) - 1);
+ file[sizeof(file) - 1] = '\0';
+ }
+ copycnt++;
+ /*
+ * deliberately 'continue' to another getline(), so
+ * all format-spec lines for this datafile are read
+ * in and counted before calling show()
+ */
+ continue;
+ case 'N':
+ strncpy(savedname, line + 1, sizeof(savedname) - 1);
+ savedname[sizeof(savedname) - 1] = '\0';
+ break;
+ }
+ if ((file[0] != '\0') && (savedname[0] != '\0')) {
+ show(savedname, file, copycnt);
+ copycnt = 0;
+ file[0] = '\0';
+ savedname[0] = '\0';
+ }
+ }
+ fclose(cfp);
+ /* check for a file which hasn't been shown yet */
+ if (file[0] != '\0') {
+ if (savedname[0] == '\0') {
+ /* a safeguard in case the N-ame line is missing */
+ strncpy(savedname, file, sizeof(savedname) - 1);
+ savedname[sizeof(savedname) - 1] = '\0';
+ }
+ show(savedname, file, copycnt);
+ }
+ if (!lflag) {
+ blankfill(SIZCOL);
+ printf("%ld bytes\n", totsize);
+ totsize = 0;
+ }
+}
+
+int
+inlist(name, file)
+ char *name, *file;
+{
+ register int *r, n;
+ register char **u, *cp;
+
+ if (users == 0 && requests == 0)
+ return(1);
+ /*
+ * Check to see if it's in the user list
+ */
+ for (u = user; u < &user[users]; u++)
+ if (!strcmp(*u, name))
+ return(1);
+ /*
+ * Check the request list
+ */
+ for (n = 0, cp = file+3; isdigit(*cp); )
+ n = n * 10 + (*cp++ - '0');
+ for (r = requ; r < &requ[requests]; r++)
+ if (*r == n && !strcmp(cp, from))
+ return(1);
+ return(0);
+}
+
+void
+show(nfile, file, copies)
+ register char *nfile, *file;
+ int copies;
+{
+ if (strcmp(nfile, " ") == 0)
+ nfile = "(standard input)";
+ if (lflag)
+ ldump(nfile, file, copies);
+ else
+ dump(nfile, file, copies);
+}
+
+/*
+ * Fill the line with blanks to the specified column
+ */
+void
+blankfill(n)
+ register int n;
+{
+ while (col++ < n)
+ putchar(' ');
+}
+
+/*
+ * Give the abbreviated dump of the file names
+ */
+void
+dump(nfile, file, copies)
+ char *nfile, *file;
+ int copies;
+{
+ struct stat lbuf;
+ const char etctmpl[] = ", ...";
+ char etc[sizeof(etctmpl)];
+ char *lastsep;
+ short fill, nlen;
+ short rem, remetc;
+
+ /*
+ * Print as many filenames as will fit
+ * (leaving room for the 'total size' field)
+ */
+ fill = first ? 0 : 2; /* fill space for ``, '' */
+ nlen = strlen(nfile);
+ rem = SIZCOL - 1 - col;
+ if (nlen + fill > rem) {
+ if (first) {
+ /* print the right-most part of the name */
+ printf("...%s ", &nfile[3+nlen-rem]);
+ col = SIZCOL;
+ } else if (rem > 0) {
+ /* fit as much of the etc-string as we can */
+ remetc = rem;
+ if (rem > strlen(etctmpl))
+ remetc = strlen(etctmpl);
+ etc[0] = '\0';
+ strncat(etc, etctmpl, remetc);
+ printf(etc);
+ col += remetc;
+ rem -= remetc;
+ /* room for the last segment of this filename? */
+ lastsep = strrchr(nfile, '/');
+ if ((lastsep != NULL) && (rem > strlen(lastsep))) {
+ /* print the right-most part of this name */
+ printf("%s", lastsep);
+ col += strlen(lastsep);
+ } else {
+ /* do not pack any more names in here */
+ blankfill(SIZCOL);
+ }
+ }
+ } else {
+ if (!first)
+ printf(", ");
+ printf("%s", nfile);
+ col += nlen + fill;
+ }
+ first = 0;
+
+ seteuid(euid);
+ if (*file && !stat(file, &lbuf))
+ totsize += copies * lbuf.st_size;
+ seteuid(uid);
+}
+
+/*
+ * Print the long info about the file
+ */
+void
+ldump(nfile, file, copies)
+ char *nfile, *file;
+ int copies;
+{
+ struct stat lbuf;
+
+ putchar('\t');
+ if (copies > 1)
+ printf("%-2d copies of %-19s", copies, nfile);
+ else
+ printf("%-32s", nfile);
+ if (*file && !stat(file, &lbuf))
+ printf(" %qd bytes", (long long) lbuf.st_size);
+ else
+ printf(" ??? bytes");
+ putchar('\n');
+}
+
+/*
+ * Print the job's rank in the queue,
+ * update col for screen management
+ */
+void
+prank(n)
+ int n;
+{
+ char rline[100];
+ static char *r[] = {
+ "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
+ };
+
+ if (n == 0) {
+ printf("active");
+ col += 6;
+ return;
+ }
+ if ((n/10)%10 == 1)
+ (void)snprintf(rline, sizeof(rline), "%dth", n);
+ else
+ (void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
+ col += strlen(rline);
+ printf("%s", rline);
+}
+
+void
+alarmhandler(signo)
+ int signo;
+{
+ /* ignored */
+}
diff --git a/usr.sbin/lpr/common_source/lp.h b/usr.sbin/lpr/common_source/lp.h
new file mode 100644
index 0000000..276108a
--- /dev/null
+++ b/usr.sbin/lpr/common_source/lp.h
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * From: @(#)lp.h 8.2 (Berkeley) 4/28/95
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <time.h>
+
+/*
+ * All this information used to be in global static variables shared
+ * mysteriously by various parts of the lpr/lpd suite.
+ * This structure attempts to centralize all these declarations in the
+ * hope that they can later be made more dynamic.
+ */
+enum lpd_filters { LPF_CIFPLOT, LPF_DVI, LPF_GRAPH, LPF_INPUT,
+ LPF_DITROFF, LPF_OUTPUT, LPF_FORTRAN, LPF_TROFF,
+ LPF_RASTER, LPF_COUNT };
+/* NB: there is a table in common.c giving the mapping from capability names */
+
+struct printer {
+ char *printer; /* printer name */
+ int remote; /* true if RM points to a remote host */
+ int rp_matches_local; /* true if rp has same name as us */
+ int tof; /* true if we are at top-of-form */
+ /* ------------------------------------------------------ */
+ char *acct_file; /* AF: accounting file */
+ long baud_rate; /* BR: baud rate if lp is a tty */
+ char *filters[LPF_COUNT]; /* CF, DF, GF, IF, NF, OF, RF, TF, VF */
+ long conn_timeout; /* CT: TCP connection timeout */
+ long daemon_user; /* DU: daemon user id -- XXX belongs ???? */
+ char *form_feed; /* FF: form feed */
+ long header_last; /* HL: print header last */
+ char *log_file; /* LF: log file */
+ char *lock_file; /* LO: lock file */
+ char *lp; /* LP: device name or network address */
+ long max_copies; /* MC: maximum number of copies allowed */
+ long max_blocks; /* MX: maximum number of blocks to copy */
+ long price100; /* PC: price per 100 units of output */
+ long page_length; /* PL: page length */
+ long page_width; /* PW: page width */
+ long page_pwidth; /* PX: page width in pixels */
+ long page_plength; /* PY: page length in pixels */
+ char *restrict_grp; /* RG: restricted group */
+ char *remote_host; /* RM: remote machine name */
+ char *remote_queue; /* RP: remote printer name */
+ long restricted; /* RS: restricted to those with local accts */
+ long rw; /* RW: open LP for reading and writing */
+ long short_banner; /* SB: short banner */
+ long no_copies; /* SC: suppress multiple copies */
+ char *spool_dir; /* SD: spool directory */
+ long no_formfeed; /* SF: suppress FF on each print job */
+ long no_header; /* SH: suppress header page */
+ char *stat_recv; /* SR: statistics file, receiving jobs */
+ char *stat_send; /* SS: statistics file, sending jobs */
+ char *status_file; /* ST: status file name */
+ char *trailer; /* TR: trailer string send when Q empties */
+ char *mode_set; /* MS: mode set, a la stty */
+
+ /* variables used by trstat*() to keep statistics on file transfers */
+#define JOBNUM_SIZE 8
+ char jobnum[JOBNUM_SIZE];
+ long jobdfnum; /* current datafile number within job */
+ struct timespec tr_start, tr_done;
+#define TIMESTR_SIZE 40 /* holds result from LPD_TIMESTAMP_PATTERN */
+ char tr_timestr[TIMESTR_SIZE];
+#define DIFFTIME_TS(endTS,startTS) \
+ ((double)(endTS.tv_sec - startTS.tv_sec) \
+ + (endTS.tv_nsec - startTS.tv_nsec) * 1.0e-9)
+};
+
+/*
+ * Lists of user names and job numbers, for the benefit of the structs
+ * defined below. We use TAILQs so that requests don't get mysteriously
+ * reversed in process.
+ */
+struct req_user {
+ TAILQ_ENTRY(req_user) ru_link; /* macro glue */
+ char ru_uname[1]; /* name of user */
+};
+TAILQ_HEAD(req_user_head, req_user);
+
+struct req_file {
+ TAILQ_ENTRY(req_file) rf_link; /* macro glue */
+ char rf_type; /* type (lowercase cf file letter) of file */
+ char *rf_prettyname; /* user-visible name of file */
+ char rf_fname[1]; /* name of file */
+};
+TAILQ_HEAD(req_file_head, req_file);
+
+struct req_jobid {
+ TAILQ_ENTRY(req_jobid) rj_link; /* macro glue */
+ int rj_job; /* job number */
+};
+TAILQ_HEAD(req_jobid_head, req_jobid);
+
+/*
+ * Encapsulate all the information relevant to a request in the
+ * lpr/lpd protocol.
+ */
+enum req_type { REQ_START, REQ_RECVJOB, REQ_LIST, REQ_DELETE };
+
+struct request {
+ enum req_type type; /* what sort of request is this? */
+ struct printer prtr; /* which printer is it for? */
+ int remote; /* did request arrive over network? */
+ char *logname; /* login name of requesting user */
+ char *authname; /* authenticated identity of requesting user */
+ char *prettyname; /* ``pretty'' name of requesting user */
+ int privileged; /* was the request from a privileged user? */
+ void *authinfo; /* authentication information */
+ int authentic; /* was the request securely authenticated? */
+
+ /* Information for queries and deletes... */
+ int nusers; /* length of following list... */
+ struct req_user_head users; /* list of users to query/delete */
+ int njobids; /* length of following list... */
+ struct req_jobid_head jobids; /* list of jobids to query/delete */
+};
+
+/*
+ * Global definitions for the line printer system.
+ */
+extern char line[BUFSIZ];
+extern char *name; /* program name */
+ /* host machine name */
+extern char host[MAXHOSTNAMELEN];
+extern char *from; /* client's machine name */
+#define MAXIPSTRLEN 32 /* maxlen of an IP-address as a string */
+extern char from_ip[MAXIPSTRLEN]; /* client machine's IP address */
+
+extern int requ[]; /* job number of spool entries */
+extern int requests; /* # of spool requests */
+extern char *user[]; /* users to process */
+extern int users; /* # of users in user array */
+extern char *person; /* name of person doing lprm */
+
+/*
+ * Structure used for building a sorted list of control files.
+ */
+struct queue {
+ time_t q_time; /* modification time */
+ char q_name[MAXNAMLEN+1]; /* control file name */
+};
+
+/* lpr/lpd generates readable timestamps for logfiles, etc. Have all those
+ * timestamps be in the same format wrt strftime(). This is ISO 8601 format,
+ * with the addition of an easy-readable day-of-the-week field. Note that
+ * '%T' = '%H:%M:%S', and that '%z' is not available on all platforms.
+ */
+#define LPD_TIMESTAMP_PATTERN "%Y-%m-%dT%T%z %a"
+
+/*
+ * Codes to indicate which statistic records trstat_write should write.
+ */
+typedef enum { TR_SENDING, TR_RECVING, TR_PRINTING } tr_sendrecv;
+
+/*
+ * Error codes for our mini printcap library.
+ */
+#define PCAPERR_TCLOOP (-3)
+#define PCAPERR_OSERR (-2)
+#define PCAPERR_NOTFOUND (-1)
+#define PCAPERR_SUCCESS 0
+#define PCAPERR_TCOPEN 1
+
+/*
+ * File modes for the various status files maintained by lpd.
+ */
+#define LOCK_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
+#define LFM_PRINT_DIS (S_IXUSR)
+#define LFM_QUEUE_DIS (S_IXGRP)
+#define LFM_RESET_QUE (S_IXOTH)
+
+#define STAT_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
+#define LOG_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
+#define TEMP_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
+
+/*
+ * Command codes used in the protocol.
+ */
+#define CMD_CHECK_QUE '\1'
+#define CMD_TAKE_THIS '\2'
+#define CMD_SHOWQ_SHORT '\3'
+#define CMD_SHOWQ_LONG '\4'
+#define CMD_RMJOB '\5'
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+struct dirent;
+
+void blankfill __P((int));
+char *checkremote __P((struct printer *pp));
+int chk __P((char *));
+void closeallfds __P((int start));
+void delay __P((int));
+void displayq __P((struct printer *pp, int format));
+void dump __P((char *, char *, int));
+void fatal __P((const struct printer *pp, const char *fmp, ...));
+int firstprinter __P((struct printer *pp, int *status));
+void free_printer __P((struct printer *pp));
+void free_request __P((struct request *rp));
+int getline __P((FILE *));
+int getport __P((const struct printer *pp, const char *, int));
+int getprintcap __P((const char *printer, struct printer *pp));
+int getq __P((const struct printer *, struct queue *(*[])));
+void header __P((void));
+void inform __P((const struct printer *pp, char *cf));
+void init_printer __P((struct printer *pp));
+void init_request __P((struct request *rp));
+int inlist __P((char *, char *));
+int iscf __P((struct dirent *));
+int isowner __P((char *, char *));
+void ldump __P((char *, char *, int));
+void lastprinter __P((void));
+int lockchk __P((struct printer *pp, char *));
+char *lock_file_name __P((const struct printer *pp, char *buf, size_t len));
+void lpd_gettime __P((struct timespec *_tsp, char *_strp, int _strsize));
+int nextprinter __P((struct printer *pp, int *status));
+const
+char *pcaperr __P((int error));
+void prank __P((int));
+void process __P((const struct printer *pp, char *));
+void rmjob __P((const char *printer));
+void rmremote __P((const struct printer *pp));
+void setprintcap __P((char *newprintcap));
+void show __P((char *, char *, int));
+int startdaemon __P((const struct printer *pp));
+char *status_file_name __P((const struct printer *pp, char *buf,
+ size_t len));
+void trstat_init __P((struct printer *pp, const char *fname, int filenum));
+void trstat_write __P((struct printer *pp, tr_sendrecv sendrecv,
+ size_t bytecnt, const char *userid,
+ const char *otherhost, const char *orighost));
+ssize_t writel __P((int s, ...));
+__END_DECLS
diff --git a/usr.sbin/lpr/common_source/lp.local.h b/usr.sbin/lpr/common_source/lp.local.h
new file mode 100644
index 0000000..bc60549
--- /dev/null
+++ b/usr.sbin/lpr/common_source/lp.local.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)lp.local.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * Possibly, local parameters to the spooling system
+ */
+
+/*
+ * Defaults for line printer capabilities data base
+ */
+#define DEFLP "lp"
+#define DEFLOCK "lock"
+#define DEFSTAT "status"
+#define DEFMX 1000
+#define DEFMAXCOPIES 0
+#define DEFFF "\f"
+#define DEFWIDTH 132
+#define DEFLENGTH 66
+#define DEFUID 1
+#define DEFTIMEOUT 120
+
+/*
+ * When files are created in the spooling area, they are normally
+ * readable only by their owner and the spooling group. If you
+ * want otherwise, change this mode.
+ */
+#define FILMOD 0660
+
+/*
+ * Printer is assumed to support LINELEN (for block chars)
+ * and background character (blank) is a space
+ */
+#define LINELEN 132
+#define BACKGND ' '
+
+#define HEIGHT 9 /* height of characters */
+#define WIDTH 8 /* width of characters */
+#define DROP 3 /* offset to drop characters with descenders */
+
+/*
+ * Define TERMCAP if the terminal capabilites are to be used for lpq.
+ */
+#define TERMCAP
+
+/*
+ * Maximum number of user and job requests for lpq and lprm.
+ */
+#define MAXUSERS 50
+#define MAXREQUESTS 50
diff --git a/usr.sbin/lpr/common_source/net.c b/usr.sbin/lpr/common_source/net.c
new file mode 100644
index 0000000..4cfabfa
--- /dev/null
+++ b/usr.sbin/lpr/common_source/net.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * From: @(#)common.c 8.5 (Berkeley) 4/28/95
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <dirent.h> /* required for lp.h, not used here */
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+
+char host[MAXHOSTNAMELEN]; /* host machine name */
+char *from = host; /* client's machine name */
+char from_ip[MAXIPSTRLEN] = ""; /* client machine's IP address */
+
+extern uid_t uid, euid;
+
+/*
+ * Create a TCP connection to host "rhost" at port "rport".
+ * If rport == 0, then use the printer service port.
+ * Most of this code comes from rcmd.c.
+ */
+int
+getport(const struct printer *pp, const char *rhost, int rport)
+{
+ struct hostent *hp;
+ struct servent *sp;
+ struct sockaddr_in sin;
+ int s, timo = 1, lport = IPPORT_RESERVED - 1;
+ int err;
+
+ /*
+ * Get the host address and port number to connect to.
+ */
+ if (rhost == NULL)
+ fatal(pp, "no remote host to connect to");
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_len = sizeof sin;
+ sin.sin_family = AF_INET;
+ if (inet_aton(rhost, &sin.sin_addr) == 0) {
+ hp = gethostbyname2(rhost, AF_INET);
+ if (hp == NULL)
+ fatal(pp, "cannot resolve %s: %s", rhost,
+ hstrerror(h_errno));
+ /* XXX - should deal with more addresses */
+ sin.sin_addr = *(struct in_addr *)hp->h_addr_list[0];
+ }
+ if (rport == 0) {
+ sp = getservbyname("printer", "tcp");
+ if (sp == NULL)
+ fatal(pp, "printer/tcp: unknown service");
+ sin.sin_port = sp->s_port;
+ } else
+ sin.sin_port = htons(rport);
+
+ /*
+ * Try connecting to the server.
+ */
+retry:
+ seteuid(euid);
+ s = rresvport(&lport);
+ seteuid(uid);
+ if (s < 0)
+ return(-1);
+ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ err = errno;
+ (void) close(s);
+ errno = err;
+ /*
+ * This used to decrement lport, but the current semantics
+ * of rresvport do not provide such a function (in fact,
+ * rresvport should guarantee that the chosen port will
+ * never result in an EADDRINUSE).
+ */
+ if (errno == EADDRINUSE)
+ goto retry;
+
+ if (errno == ECONNREFUSED && timo <= 16) {
+ sleep(timo);
+ timo *= 2;
+ goto retry;
+ }
+ return(-1);
+ }
+ return(s);
+}
+
+/*
+ * Figure out whether the local machine is the same
+ * as the remote machine (RM) entry (if it exists).
+ * We do this by counting the intersection of our
+ * address list and theirs. This is better than the
+ * old method (comparing the canonical names), as it
+ * allows load-sharing between multiple print servers.
+ * The return value is an error message which must be
+ * free()d.
+ */
+char *
+checkremote(struct printer *pp)
+{
+ char name[MAXHOSTNAMELEN];
+ register struct hostent *hp;
+ char *err;
+ struct in_addr *localaddrs;
+ int i, j, nlocaladdrs, ncommonaddrs;
+
+ if (!pp->rp_matches_local) { /* Remote printer doesn't match local */
+ pp->remote = 1;
+ return NULL;
+ }
+
+ pp->remote = 0; /* assume printer is local */
+ if (pp->remote_host != NULL) {
+ /* get the addresses of the local host */
+ gethostname(name, sizeof(name));
+ name[sizeof(name) - 1] = '\0';
+ hp = gethostbyname2(name, AF_INET);
+ if (hp == (struct hostent *) NULL) {
+ asprintf(&err, "unable to get official name "
+ "for local machine %s: %s",
+ name, hstrerror(h_errno));
+ return err;
+ }
+ for (i = 0; hp->h_addr_list[i]; i++)
+ ;
+ nlocaladdrs = i;
+ localaddrs = malloc(i * sizeof(struct in_addr));
+ if (localaddrs == 0) {
+ asprintf(&err, "malloc %lu bytes failed",
+ (u_long)i * sizeof(struct in_addr));
+ return err;
+ }
+ for (i = 0; hp->h_addr_list[i]; i++)
+ localaddrs[i] = *(struct in_addr *)hp->h_addr_list[i];
+
+ /* get the official name of RM */
+ hp = gethostbyname2(pp->remote_host, AF_INET);
+ if (hp == (struct hostent *) NULL) {
+ asprintf(&err, "unable to get address list for "
+ "remote machine %s: %s",
+ pp->remote_host, hstrerror(h_errno));
+ free(localaddrs);
+ return err;
+ }
+
+ ncommonaddrs = 0;
+ for (i = 0; i < nlocaladdrs; i++) {
+ for (j = 0; hp->h_addr_list[j]; j++) {
+ char *them = hp->h_addr_list[j];
+ if (localaddrs[i].s_addr ==
+ (*(struct in_addr *)them).s_addr)
+ ncommonaddrs++;
+ }
+ }
+
+ /*
+ * if the two hosts do not share at least one IP address
+ * then the printer must be remote.
+ */
+ if (ncommonaddrs == 0)
+ pp->remote = 1;
+ free(localaddrs);
+ }
+ return NULL;
+}
+
+/*
+ * This isn't really network-related, but it's used here to write
+ * multi-part strings onto sockets without using stdio. Return
+ * values are as for writev(2).
+ */
+ssize_t
+writel(int s, ...)
+{
+ va_list ap;
+ int i, n;
+ const char *cp;
+#define NIOV 12
+ struct iovec iov[NIOV], *iovp = iov;
+ ssize_t retval;
+
+ /* first count them */
+ va_start(ap, s);
+ n = 0;
+ do {
+ cp = va_arg(ap, char *);
+ n++;
+ } while (cp);
+ va_end(ap);
+ n--; /* correct for count of trailing null */
+
+ if (n > NIOV) {
+ iovp = malloc(n * sizeof *iovp);
+ if (iovp == 0)
+ return -1;
+ }
+
+ /* now make up iovec and send */
+ va_start(ap, s);
+ for (i = 0; i < n; i++) {
+ iovp[i].iov_base = va_arg(ap, char *);
+ iovp[i].iov_len = strlen(iovp[i].iov_base);
+ }
+ va_end(ap);
+ retval = writev(s, iovp, n);
+ if (iovp != iov)
+ free(iovp);
+ return retval;
+}
diff --git a/usr.sbin/lpr/common_source/pathnames.h b/usr.sbin/lpr/common_source/pathnames.h
new file mode 100644
index 0000000..78ccc7b
--- /dev/null
+++ b/usr.sbin/lpr/common_source/pathnames.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#include <paths.h>
+
+#define _PATH_DEFDEVLP "/dev/lp"
+#define _PATH_DEFSPOOL "/var/spool/output/lpd"
+#define _PATH_HOSTSEQUIV "/etc/hosts.equiv"
+#define _PATH_HOSTSLPD "/etc/hosts.lpd"
+#define _PATH_MASTERLOCK "/var/spool/output/lpd.lock"
+#define _PATH_PR "/usr/bin/pr"
+#define _PATH_PRINTCAP "/etc/printcap"
+#define _PATH_SOCKETNAME "/var/run/printer"
+#define _PATH_VFONT "/usr/libdata/vfont/"
+#define _PATH_VFONTB "/usr/libdata/vfont/B"
+#define _PATH_VFONTI "/usr/libdata/vfont/I"
+#define _PATH_VFONTR "/usr/libdata/vfont/R"
+#define _PATH_VFONTS "/usr/libdata/vfont/S"
+#define _PATH_CHKPRINTCAP "/usr/sbin/chkprintcap"
diff --git a/usr.sbin/lpr/common_source/printcap.c b/usr.sbin/lpr/common_source/printcap.c
new file mode 100644
index 0000000..390de46
--- /dev/null
+++ b/usr.sbin/lpr/common_source/printcap.c
@@ -0,0 +1,448 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * From: @(#)common.c 8.5 (Berkeley) 4/28/95
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/param.h> /* required for lp.h, but not used here */
+#include <sys/dirent.h> /* ditto */
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+
+/*
+ * Routines and data used in processing the printcap file.
+ */
+static char *printcapdb[2] = { _PATH_PRINTCAP, 0 }; /* list for cget* */
+
+static char *capdb_canonical_name(const char *);
+static int capdb_getaltlog(char *, const char *, const char *);
+static int capdb_getaltnum(char *, const char *, const char *, long, long *);
+static int capdb_getaltstr(char *, const char *, const char *, const char *,
+ char **);
+static int getprintcap_int(char *bp, struct printer *pp);
+
+/*
+ * Change the name of the printcap file. Used by chkprintcap(8),
+ * but could be used by other members of the suite with appropriate
+ * security measures.
+ */
+void
+setprintcap(char *newfile)
+{
+ printcapdb[0] = newfile;
+}
+
+/*
+ * Read the printcap database for printer `printer' into the
+ * struct printer pointed by `pp'. Return values are as for
+ * cgetent(3): -1 means we could not find what we wanted, -2
+ * means a system error occurred (and errno is set), -3 if a
+ * reference (`tc=') loop was detected, and 0 means success.
+ *
+ * Copied from lpr; should add additional capabilities as they
+ * are required by the other programs in the suite so that
+ * printcap-reading is consistent across the entire family.
+ */
+int
+getprintcap(const char *printer, struct printer *pp)
+{
+ int status;
+ char *XXX;
+ char *bp;
+
+ /*
+ * A bug in the declaration of cgetent(3) means that we have
+ * to hide the constness of its third argument.
+ */
+ XXX = (char *)printer;
+ if ((status = cgetent(&bp, printcapdb, XXX)) < 0)
+ return status;
+ status = getprintcap_int(bp, pp);
+ free(bp);
+ return status;
+}
+
+/*
+ * Map the status values returned by cgetfirst/cgetnext into those
+ * used by cgetent, returning truth if there are more records to
+ * examine. This points out what is arguably a bug in the cget*
+ * interface (or at least a nasty wart).
+ */
+static int
+firstnextmap(int *status)
+{
+ switch (*status) {
+ case 0:
+ return 0;
+ case 1:
+ *status = 0;
+ return 1;
+ case 2:
+ *status = 1;
+ return 1;
+ case -1:
+ *status = -2;
+ return 0;
+ case -2:
+ *status = -3;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Scan through the database of printers using cgetfirst/cgetnext.
+ * Return false of error or end-of-database; else true.
+ */
+int
+firstprinter(struct printer *pp, int *error)
+{
+ int status;
+ char *bp;
+
+ init_printer(pp);
+ status = cgetfirst(&bp, printcapdb);
+ if (firstnextmap(&status) == 0) {
+ if (error)
+ *error = status;
+ return 0;
+ }
+ if (error)
+ *error = status;
+ status = getprintcap_int(bp, pp);
+ free(bp);
+ if (error && status)
+ *error = status;
+ return 1;
+}
+
+int
+nextprinter(struct printer *pp, int *error)
+{
+ int status;
+ char *bp;
+
+ free_printer(pp);
+ status = cgetnext(&bp, printcapdb);
+ if (firstnextmap(&status) == 0) {
+ if (error)
+ *error = status;
+ return 0;
+ }
+ if (error)
+ *error = status;
+ status = getprintcap_int(bp, pp);
+ free(bp);
+ if (error && status)
+ *error = status;
+ return 1;
+}
+
+void
+lastprinter(void)
+{
+ cgetclose();
+}
+
+/*
+ * This must match the order of declaration of enum filter in lp.h.
+ */
+static const char *filters[] = {
+ "cf", "df", "gf", "if", "nf", "of", "rf", "tf", "vf"
+};
+
+static const char *longfilters[] = {
+ "filt.cifplot", "filt.dvi", "filt.plot", "filt.input", "filt.ditroff",
+ "filt.output", "filt.fortran", "filt.troff", "filt.raster"
+};
+
+/*
+ * Internal routine for both getprintcap() and nextprinter().
+ * Actually parse the printcap entry using cget* functions.
+ * Also attempt to figure out the canonical name of the printer
+ * and store a malloced copy of it in pp->printer.
+ */
+static int
+getprintcap_int(bp, pp)
+ char *bp;
+ struct printer *pp;
+{
+ enum lpd_filters filt;
+ char *rp_name;
+ int error;
+
+ if ((pp->printer = capdb_canonical_name(bp)) == 0)
+ return PCAPERR_OSERR;
+
+#define CHK(x) do {if ((x) == PCAPERR_OSERR) return PCAPERR_OSERR;}while(0)
+ CHK(capdb_getaltstr(bp, "af", "acct.file", 0, &pp->acct_file));
+ CHK(capdb_getaltnum(bp, "br", "tty.rate", 0, &pp->baud_rate));
+ CHK(capdb_getaltnum(bp, "ct", "remote.timeout", DEFTIMEOUT,
+ &pp->conn_timeout));
+ CHK(capdb_getaltnum(bp, "du", "daemon.user", DEFUID,
+ &pp->daemon_user));
+ CHK(capdb_getaltstr(bp, "ff", "job.formfeed", DEFFF, &pp->form_feed));
+ CHK(capdb_getaltstr(bp, "lf", "spool.log", _PATH_CONSOLE,
+ &pp->log_file));
+ CHK(capdb_getaltstr(bp, "lo", "spool.lock", DEFLOCK, &pp->lock_file));
+ CHK(capdb_getaltstr(bp, "lp", "tty.device", _PATH_DEFDEVLP, &pp->lp));
+ CHK(capdb_getaltnum(bp, "mc", "max.copies", DEFMAXCOPIES,
+ &pp->max_copies));
+ CHK(capdb_getaltstr(bp, "ms", "tty.mode", 0, &pp->mode_set));
+ CHK(capdb_getaltnum(bp, "mx", "max.blocks", DEFMX, &pp->max_blocks));
+ CHK(capdb_getaltnum(bp, "pc", "acct.price", 0, &pp->price100));
+ CHK(capdb_getaltnum(bp, "pl", "page.length", DEFLENGTH,
+ &pp->page_length));
+ CHK(capdb_getaltnum(bp, "pw", "page.width", DEFWIDTH,
+ &pp->page_width));
+ CHK(capdb_getaltnum(bp, "px", "page.pwidth", 0, &pp->page_pwidth));
+ CHK(capdb_getaltnum(bp, "py", "page.plength", 0, &pp->page_plength));
+ CHK(capdb_getaltstr(bp, "rg", "daemon.restrictgrp", 0,
+ &pp->restrict_grp));
+ CHK(capdb_getaltstr(bp, "rm", "remote.host", 0, &pp->remote_host));
+ CHK(capdb_getaltstr(bp, "rp", "remote.queue", DEFLP,
+ &pp->remote_queue));
+ CHK(capdb_getaltstr(bp, "sd", "spool.dir", _PATH_DEFSPOOL,
+ &pp->spool_dir));
+ CHK(capdb_getaltstr(bp, "sr", "stat.recv", 0, &pp->stat_recv));
+ CHK(capdb_getaltstr(bp, "ss", "stat.send", 0, &pp->stat_send));
+ CHK(capdb_getaltstr(bp, "st", "spool.status", DEFSTAT,
+ &pp->status_file));
+ CHK(capdb_getaltstr(bp, "tr", "job.trailer", 0, &pp->trailer));
+
+ pp->restricted = capdb_getaltlog(bp, "rs", "daemon.restricted");
+ pp->short_banner = capdb_getaltlog(bp, "sb", "banner.short");
+ pp->no_copies = capdb_getaltlog(bp, "sc", "job.no_copies");
+ pp->no_formfeed = capdb_getaltlog(bp, "sf", "job.no_formfeed");
+ pp->no_header = capdb_getaltlog(bp, "sh", "banner.disable");
+ pp->header_last = capdb_getaltlog(bp, "hl", "banner.last");
+ pp->rw = capdb_getaltlog(bp, "rw", "tty.rw");
+ pp->tof = !capdb_getaltlog(bp, "fo", "job.topofform");
+
+ /*
+ * Decide if the remote printer name matches the local printer name.
+ * If no name is given then we assume they mean them to match.
+ * If a name is given see if the rp_name is one of the names for
+ * this printer.
+ */
+ pp->rp_matches_local = 1;
+ CHK((error = capdb_getaltstr(bp, "rp", "remote.queue", 0, &rp_name)));
+ if (error != PCAPERR_NOTFOUND && rp_name != NULL) {
+ if (cgetmatch(bp,rp_name) != 0)
+ pp->rp_matches_local = 0;
+ free(rp_name);
+ }
+
+ /*
+ * Filters:
+ */
+ for (filt = 0; filt < LPF_COUNT; filt++) {
+ CHK(capdb_getaltstr(bp, filters[filt], longfilters[filt], 0,
+ &pp->filters[filt]));
+ }
+
+ return 0;
+}
+
+/*
+ * Decode the error codes returned by cgetent() using the names we
+ * made up for them from "lp.h".
+ * This would have been much better done with Common Error, >sigh<.
+ * Perhaps this can be fixed in the next incarnation of cget*.
+ */
+const char *
+pcaperr(int error)
+{
+ switch(error) {
+ case PCAPERR_TCOPEN:
+ return "unresolved tc= expansion";
+ case PCAPERR_SUCCESS:
+ return "no error";
+ case PCAPERR_NOTFOUND:
+ return "printer not found";
+ case PCAPERR_OSERR:
+ return strerror(errno);
+ case PCAPERR_TCLOOP:
+ return "loop detected in tc= expansion";
+ default:
+ return "unknown printcap error";
+ }
+}
+
+/*
+ * Initialize a `struct printer' to contain values harmless to
+ * the other routines in liblpr.
+ */
+void
+init_printer(struct printer *pp)
+{
+ static struct printer zero;
+ *pp = zero;
+}
+
+/*
+ * Free the dynamically-allocated strings in a `struct printer'.
+ * Idempotent.
+ */
+void
+free_printer(struct printer *pp)
+{
+ enum lpd_filters filt;
+#define cfree(x) do { if (x) free(x); } while(0)
+ cfree(pp->printer);
+ cfree(pp->acct_file);
+ for (filt = 0; filt < LPF_COUNT; filt++)
+ cfree(pp->filters[filt]);
+ cfree(pp->form_feed);
+ cfree(pp->log_file);
+ cfree(pp->lock_file);
+ cfree(pp->lp);
+ cfree(pp->restrict_grp);
+ cfree(pp->remote_host);
+ cfree(pp->remote_queue);
+ cfree(pp->spool_dir);
+ cfree(pp->stat_recv);
+ cfree(pp->stat_send);
+ cfree(pp->status_file);
+ cfree(pp->trailer);
+ cfree(pp->mode_set);
+
+ init_printer(pp);
+}
+
+
+/*
+ * The following routines are part of what would be a sensible library
+ * interface to capability databases. Maybe someday this will become
+ * the default.
+ */
+
+/*
+ * It provides similar functionality to cgetstr(),
+ * except that it provides for both a long and a short
+ * capability name and allows for a default to be specified.
+ */
+static int
+capdb_getaltstr(char *bp, const char *shrt, const char *lng,
+ const char *dflt, char **result)
+{
+ int status;
+
+ status = cgetstr(bp, (char *)/*XXX*/lng, result);
+ if (status >= 0 || status == PCAPERR_OSERR)
+ return status;
+ status = cgetstr(bp, (char *)/*XXX*/shrt, result);
+ if (status >= 0 || status == PCAPERR_OSERR)
+ return status;
+ if (dflt) {
+ *result = strdup(dflt);
+ if (*result == 0)
+ return PCAPERR_OSERR;
+ return strlen(*result);
+ }
+ return PCAPERR_NOTFOUND;
+}
+
+/*
+ * The same, only for integers.
+ */
+static int
+capdb_getaltnum(char *bp, const char *shrt, const char *lng, long dflt,
+ long *result)
+{
+ int status;
+
+ status = cgetnum(bp, (char *)/*XXX*/lng, result);
+ if (status >= 0)
+ return status;
+ status = cgetnum(bp, (char *)/*XXX*/shrt, result);
+ if (status >= 0)
+ return status;
+ *result = dflt;
+ return 0;
+}
+
+/*
+ * Likewise for logical values. There's no need for a default parameter
+ * because the default is always false.
+ */
+static int
+capdb_getaltlog(char *bp, const char *shrt, const char *lng)
+{
+ if (cgetcap(bp, (char *)/*XXX*/lng, ':'))
+ return 1;
+ if (cgetcap(bp, (char *)/*XXX*/shrt, ':'))
+ return 1;
+ return 0;
+}
+
+/*
+ * Also should be a part of a better cget* library.
+ * Given a capdb entry, attempt to figure out what its canonical name
+ * is, and return a malloced copy of it. The canonical name is
+ * considered to be the first one listed.
+ */
+static char *
+capdb_canonical_name(const char *bp)
+{
+ char *retval;
+ const char *nameend;
+
+ nameend = strpbrk(bp, "|:");
+ if (nameend == 0)
+ nameend = bp + 1;
+ if ((retval = malloc(nameend - bp + 1)) != 0) {
+ retval[0] = '\0';
+ strncat(retval, bp, nameend - bp);
+ }
+ return retval;
+}
+
+
diff --git a/usr.sbin/lpr/common_source/request.c b/usr.sbin/lpr/common_source/request.c
new file mode 100644
index 0000000..e3e4366
--- /dev/null
+++ b/usr.sbin/lpr/common_source/request.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright 1997 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char copyright[] =
+ "Copyright (C) 1997, Massachusetts Institute of Technology\r\n";
+static const char rcsid[] =
+ "$FreeBSD$";
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/param.h> /* needed for lp.h but not used here */
+#include <dirent.h> /* ditto */
+#include <stdio.h> /* ditto */
+#include "lp.h"
+#include "lp.local.h"
+
+void
+init_request(struct request *rp)
+{
+ static struct request zero;
+
+ *rp = zero;
+ TAILQ_INIT(&rp->users);
+ TAILQ_INIT(&rp->jobids);
+}
+
+void
+free_request(struct request *rp)
+{
+ struct req_user *ru;
+ struct req_jobid *rj;
+
+ if (rp->logname)
+ free(rp->logname);
+ if (rp->authname)
+ free(rp->authname);
+ if (rp->prettyname)
+ free(rp->prettyname);
+ if (rp->authinfo)
+ free(rp->authinfo);
+ while ((ru = rp->users.tqh_first) != 0) {
+ TAILQ_REMOVE(&rp->users, ru, ru_link);
+ free(ru);
+ }
+ while ((rj = rp->jobids.tqh_first) != 0) {
+ TAILQ_REMOVE(&rp->jobids, rj, rj_link);
+ free(rj);
+ }
+ init_request(rp);
+}
diff --git a/usr.sbin/lpr/common_source/rmjob.c b/usr.sbin/lpr/common_source/rmjob.c
new file mode 100644
index 0000000..4450368
--- /dev/null
+++ b/usr.sbin/lpr/common_source/rmjob.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rmjob.c 8.2 (Berkeley) 4/28/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/uio.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define psignal foil_gcc_psignal
+#define sys_siglist foil_gcc_siglist
+#include <unistd.h>
+#undef psignal
+#undef sys_siglist
+
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+
+/*
+ * rmjob - remove the specified jobs from the queue.
+ */
+
+/*
+ * Stuff for handling lprm specifications
+ */
+static char root[] = "root";
+static int all = 0; /* eliminate all files (root only) */
+static int cur_daemon; /* daemon's pid */
+static char current[7+MAXHOSTNAMELEN]; /* active control file name */
+
+extern uid_t uid, euid; /* real and effective user id's */
+
+static void alarmhandler __P((int));
+static void do_unlink __P((char *));
+
+void
+rmjob(printer)
+ const char *printer;
+{
+ register int i, nitems;
+ int assasinated = 0;
+ struct dirent **files;
+ char *cp;
+ struct printer myprinter, *pp = &myprinter;
+
+ init_printer(pp);
+ if ((i = getprintcap(printer, pp)) < 0)
+ fatal(pp, "getprintcap: %s", pcaperr(i));
+ if ((cp = checkremote(pp))) {
+ printf("Warning: %s\n", cp);
+ free(cp);
+ }
+
+ /*
+ * If the format was `lprm -' and the user isn't the super-user,
+ * then fake things to look like he said `lprm user'.
+ */
+ if (users < 0) {
+ if (getuid() == 0)
+ all = 1; /* all files in local queue */
+ else {
+ user[0] = person;
+ users = 1;
+ }
+ }
+ if (!strcmp(person, "-all")) {
+ if (from == host)
+ fatal(pp, "The login name \"-all\" is reserved");
+ all = 1; /* all those from 'from' */
+ person = root;
+ }
+
+ seteuid(euid);
+ if (chdir(pp->spool_dir) < 0)
+ fatal(pp, "cannot chdir to spool directory");
+ if ((nitems = scandir(".", &files, iscf, NULL)) < 0)
+ fatal(pp, "cannot access spool directory");
+ seteuid(uid);
+
+ if (nitems) {
+ /*
+ * Check for an active printer daemon (in which case we
+ * kill it if it is reading our file) then remove stuff
+ * (after which we have to restart the daemon).
+ */
+ if (lockchk(pp, pp->lock_file) && chk(current)) {
+ seteuid(euid);
+ assasinated = kill(cur_daemon, SIGINT) == 0;
+ seteuid(uid);
+ if (!assasinated)
+ fatal(pp, "cannot kill printer daemon");
+ }
+ /*
+ * process the files
+ */
+ for (i = 0; i < nitems; i++)
+ process(pp, files[i]->d_name);
+ }
+ rmremote(pp);
+ /*
+ * Restart the printer daemon if it was killed
+ */
+ if (assasinated && !startdaemon(pp))
+ fatal(pp, "cannot restart printer daemon\n");
+ exit(0);
+}
+
+/*
+ * Process a lock file: collect the pid of the active
+ * daemon and the file name of the active spool entry.
+ * Return boolean indicating existence of a lock file.
+ */
+int
+lockchk(pp, s)
+ struct printer *pp;
+ char *s;
+{
+ register FILE *fp;
+ register int i, n;
+
+ seteuid(euid);
+ if ((fp = fopen(s, "r")) == NULL) {
+ if (errno == EACCES)
+ fatal(pp, "%s: %s", s, strerror(errno));
+ else
+ return(0);
+ }
+ seteuid(uid);
+ if (!getline(fp)) {
+ (void) fclose(fp);
+ return(0); /* no daemon present */
+ }
+ cur_daemon = atoi(line);
+ if (kill(cur_daemon, 0) < 0 && errno != EPERM) {
+ (void) fclose(fp);
+ return(0); /* no daemon present */
+ }
+ for (i = 1; (n = fread(current, sizeof(char), sizeof(current), fp)) <= 0; i++) {
+ if (i > 5) {
+ n = 1;
+ break;
+ }
+ sleep(i);
+ }
+ current[n-1] = '\0';
+ (void) fclose(fp);
+ return(1);
+}
+
+/*
+ * Process a control file.
+ */
+void
+process(pp, file)
+ const struct printer *pp;
+ char *file;
+{
+ FILE *cfp;
+
+ if (!chk(file))
+ return;
+ seteuid(euid);
+ if ((cfp = fopen(file, "r")) == NULL)
+ fatal(pp, "cannot open %s", file);
+ seteuid(uid);
+ while (getline(cfp)) {
+ switch (line[0]) {
+ case 'U': /* unlink associated files */
+ if (strchr(line+1, '/') || strncmp(line+1, "df", 2))
+ break;
+ do_unlink(line+1);
+ }
+ }
+ (void) fclose(cfp);
+ do_unlink(file);
+}
+
+static void
+do_unlink(file)
+ char *file;
+{
+ int ret;
+
+ if (from != host)
+ printf("%s: ", host);
+ seteuid(euid);
+ ret = unlink(file);
+ seteuid(uid);
+ printf(ret ? "cannot dequeue %s\n" : "%s dequeued\n", file);
+}
+
+/*
+ * Do the dirty work in checking
+ */
+int
+chk(file)
+ char *file;
+{
+ register int *r, n;
+ register char **u, *cp;
+ FILE *cfp;
+
+ /*
+ * Check for valid cf file name (mostly checking current).
+ */
+ if (strlen(file) < 7 || file[0] != 'c' || file[1] != 'f')
+ return(0);
+
+ if (all && (from == host || !strcmp(from, file+6)))
+ return(1);
+
+ /*
+ * get the owner's name from the control file.
+ */
+ seteuid(euid);
+ if ((cfp = fopen(file, "r")) == NULL)
+ return(0);
+ seteuid(uid);
+ while (getline(cfp)) {
+ if (line[0] == 'P')
+ break;
+ }
+ (void) fclose(cfp);
+ if (line[0] != 'P')
+ return(0);
+
+ if (users == 0 && requests == 0)
+ return(!strcmp(file, current) && isowner(line+1, file));
+ /*
+ * Check the request list
+ */
+ for (n = 0, cp = file+3; isdigit(*cp); )
+ n = n * 10 + (*cp++ - '0');
+ for (r = requ; r < &requ[requests]; r++)
+ if (*r == n && isowner(line+1, file))
+ return(1);
+ /*
+ * Check to see if it's in the user list
+ */
+ for (u = user; u < &user[users]; u++)
+ if (!strcmp(*u, line+1) && isowner(line+1, file))
+ return(1);
+ return(0);
+}
+
+/*
+ * If root is removing a file on the local machine, allow it.
+ * If root is removing a file from a remote machine, only allow
+ * files sent from the remote machine to be removed.
+ * Normal users can only remove the file from where it was sent.
+ */
+int
+isowner(owner, file)
+ char *owner, *file;
+{
+ if (!strcmp(person, root) && (from == host || !strcmp(from, file+6)))
+ return(1);
+ if (!strcmp(person, owner) && !strcmp(from, file+6))
+ return(1);
+ if (from != host)
+ printf("%s: ", host);
+ printf("%s: Permission denied\n", file);
+ return(0);
+}
+
+/*
+ * Check to see if we are sending files to a remote machine. If we are,
+ * then try removing files on the remote machine.
+ */
+void
+rmremote(pp)
+ const struct printer *pp;
+{
+ int i, rem, niov, totlen;
+ char buf[BUFSIZ];
+ void (*savealrm)(int);
+ struct iovec *iov;
+
+ if (!pp->remote)
+ return; /* not sending to a remote machine */
+
+ /*
+ * Flush stdout so the user can see what has been deleted
+ * while we wait (possibly) for the connection.
+ */
+ fflush(stdout);
+
+ /*
+ * Counting:
+ * 4 == "\5" + remote_queue + " " + person
+ * 2 * users == " " + user[i] for each user
+ * requests == asprintf results for each request
+ * 1 == "\n"
+ * Although laborious, doing it this way makes it possible for
+ * us to process requests of indeterminate length without
+ * applying an arbitrary limit. Arbitrary Limits Are Bad (tm).
+ */
+ niov = 4 + 2 * users + requests + 1;
+ iov = malloc(niov * sizeof *iov);
+ if (iov == 0)
+ fatal(pp, "out of memory");
+ iov[0].iov_base = "\5";
+ iov[1].iov_base = pp->remote_queue;
+ iov[2].iov_base = " ";
+ iov[3].iov_base = all ? "-all" : person;
+ for (i = 0; i < users; i++) {
+ iov[4 + 2 * i].iov_base = " ";
+ iov[4 + 2 * i + 1].iov_base = user[i];
+ }
+ for (i = 0; i < requests; i++) {
+ asprintf(&iov[4 + 2 * users + i].iov_base, " %d", requ[i]);
+ if (iov[4 + 2 * users + i].iov_base == 0)
+ fatal(pp, "out of memory");
+ }
+ iov[4 + 2 * users + requests].iov_base = "\n";
+ for (totlen = i = 0; i < niov; i++)
+ totlen += (iov[i].iov_len = strlen(iov[i].iov_base));
+
+ savealrm = signal(SIGALRM, alarmhandler);
+ alarm(pp->conn_timeout);
+ rem = getport(pp, pp->remote_host, 0);
+ (void)signal(SIGALRM, savealrm);
+ if (rem < 0) {
+ if (from != host)
+ printf("%s: ", host);
+ printf("connection to %s is down\n", pp->remote_host);
+ } else {
+ if (writev(rem, iov, niov) != totlen)
+ fatal(pp, "Lost connection");
+ while ((i = read(rem, buf, sizeof(buf))) > 0)
+ (void) fwrite(buf, 1, i, stdout);
+ (void) close(rem);
+ }
+ for (i = 0; i < requests; i++)
+ free(iov[4 + 2 * users + i].iov_base);
+ free(iov);
+}
+
+/*
+ * Return 1 if the filename begins with 'cf'
+ */
+int
+iscf(d)
+ struct dirent *d;
+{
+ return(d->d_name[0] == 'c' && d->d_name[1] == 'f');
+}
+
+void
+alarmhandler(signo)
+ int signo;
+{
+ /* ignored */
+}
diff --git a/usr.sbin/lpr/common_source/startdaemon.c b/usr.sbin/lpr/common_source/startdaemon.c
new file mode 100644
index 0000000..29866b2
--- /dev/null
+++ b/usr.sbin/lpr/common_source/startdaemon.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 1983, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)startdaemon.c 8.2 (Berkeley) 4/17/94";
+#endif
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "lp.h"
+#include "pathnames.h"
+
+extern uid_t uid, euid;
+
+/*
+ * Tell the printer daemon that there are new files in the spool directory.
+ */
+
+int
+startdaemon(pp)
+ const struct printer *pp;
+{
+ struct sockaddr_un un;
+ register int s, n;
+ char c;
+
+ s = socket(PF_LOCAL, SOCK_STREAM, 0);
+ if (s < 0) {
+ warn("socket");
+ return(0);
+ }
+ memset(&un, 0, sizeof(un));
+ un.sun_family = AF_LOCAL;
+ strcpy(un.sun_path, _PATH_SOCKETNAME);
+#ifndef SUN_LEN
+#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
+#endif
+ seteuid(euid);
+ if (connect(s, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) {
+ seteuid(uid);
+ warn("connect");
+ (void) close(s);
+ return(0);
+ }
+ seteuid(uid);
+
+ /*
+ * Avoid overruns without putting artificial limitations on
+ * the length.
+ */
+ if (writel(s, "\1", pp->printer, "\n", (char *)0) <= 0) {
+ warn("write");
+ (void) close(s);
+ return(0);
+ }
+ if (read(s, &c, 1) == 1) {
+ if (c == '\0') { /* everything is OK */
+ (void) close(s);
+ return(1);
+ }
+ putchar(c);
+ }
+ while ((n = read(s, &c, 1)) > 0)
+ putchar(c);
+ (void) close(s);
+ return(0);
+}
diff --git a/usr.sbin/lpr/filters.ru/Makefile b/usr.sbin/lpr/filters.ru/Makefile
new file mode 100644
index 0000000..0c7be10
--- /dev/null
+++ b/usr.sbin/lpr/filters.ru/Makefile
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+SUBDIR = koi2alt koi2855
+
+SAMPLES=bjc-240.sh.sample
+
+afterinstall:
+ cd ${.CURDIR} && \
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${SHAREMODE} \
+ ${SAMPLES} ${DESTDIR}${BINDIR}
+
+.include "Makefile.inc"
+.include <bsd.prog.mk>
+
diff --git a/usr.sbin/lpr/filters.ru/Makefile.inc b/usr.sbin/lpr/filters.ru/Makefile.inc
new file mode 100644
index 0000000..c4a3a7fc
--- /dev/null
+++ b/usr.sbin/lpr/filters.ru/Makefile.inc
@@ -0,0 +1,2 @@
+# $FreeBSD$
+BINDIR= /usr/libexec/lpr/ru
diff --git a/usr.sbin/lpr/filters.ru/bjc-240.sh.sample b/usr.sbin/lpr/filters.ru/bjc-240.sh.sample
new file mode 100644
index 0000000..1bc907a
--- /dev/null
+++ b/usr.sbin/lpr/filters.ru/bjc-240.sh.sample
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# Canon BJC-240 Setup script
+#
+# Settings are:
+# Epson LQ emulation, A4, Code Page 866, 66 lines, Roman font, Smoothing,
+# HQ mode, no CR translation, power off in 10min, auto power on
+#
+
+printf "\033[K\00200\037" | tr 0 "\0"
+
+cat << EOF1
+BJLSTART
+ControlMode=BJ
+Font=Roman
+PageLength=12
+CodePage=866
+AutoLF=Off
+TextScaleMode=On
+AutoCR=Off
+CharacterSet=Set2
+AGM=Off
+BJLEND
+EOF1
+
+printf "\033[K\00200\037" | tr 0 "\0"
+
+cat << EOF2
+BJLSTART
+ControlMode=LQ
+Font=Roman
+PageLength=12
+CodePage=866
+AutoLF=Off
+TextScaleMode=On
+CharacterSet=Graphics
+International=USA
+BJLEND
+EOF2
+
+printf "\033[K\00200\037" | tr 0 "\0"
+
+cat << EOF3
+BJLSTART
+@SetControlMode=LQ
+BJLEND
+EOF3
+
+printf "\033[K\00200\037" | tr 0 "\0"
+
+cat << EOF4
+BJLSTART
+ControlMode=Common
+PrintMode=HQ
+Reduction=Off
+Smoothing=On
+PaperSelect=A4
+I/D-Buffer=Input
+AutoPowerOff=10
+AutoPowerOn=Enable
+BJLEND
+EOF4
+
+exec /usr/libexec/lpr/ru/koi2alt $*
diff --git a/usr.sbin/lpr/filters.ru/koi2855/Makefile b/usr.sbin/lpr/filters.ru/koi2855/Makefile
new file mode 100644
index 0000000..3e83d97
--- /dev/null
+++ b/usr.sbin/lpr/filters.ru/koi2855/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+PROG=koi2855
+NOMAN= noman
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/filters.ru/koi2855/koi2855.c b/usr.sbin/lpr/filters.ru/koi2855/koi2855.c
new file mode 100644
index 0000000..67a9bc5
--- /dev/null
+++ b/usr.sbin/lpr/filters.ru/koi2855/koi2855.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 1999 by Andrey A. Chernov, Moscow, Russia.
+ * (C) 18 Sep 1999, Alex G. Bulushev (bag@demos.su)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * KOI8-R -> CP855 conversion filter (Russian character sets)
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int length = 66;
+int lines;
+
+unsigned char koi2855 [] = {
+0xc4, 0xb3, 0xda, 0xbf, 0xc0, 0xd9, 0xc3, 0xb4,
+0xc2, 0xc1, 0xc5, 0xdf, 0xdc, 0xdb, 0xdb, 0xdb,
+0xb0, 0xb1, 0xb2, 0xda, 0xfe, 0x2e, 0xad, 0x3d,
+0xae, 0xaf, 0xff, 0xd9, 0xcf, 0x32, 0x2e, 0x25,
+0xcd, 0xba, 0xc9, 0x84, 0xc9, 0xc9, 0xbb, 0xbb,
+0xbb, 0xc8, 0xc8, 0xc8, 0xbc, 0xbc, 0xbc, 0xcc,
+0xcc, 0xcc, 0xb9, 0x85, 0xb9, 0xb9, 0xcb, 0xcb,
+0xcb, 0xca, 0xca, 0xca, 0xce, 0xce, 0xce, 0x43,
+0x9c, 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac,
+0xb5, 0xb7, 0xbd, 0xc6, 0xd0, 0xd2, 0xd4, 0xd6,
+0xd8, 0xde, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb,
+0xed, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0x9e,
+0x9d, 0xa1, 0xa3, 0xa5, 0xa7, 0xa9, 0xab, 0xad,
+0xb6, 0xb8, 0xbe, 0xc7, 0xd1, 0xd3, 0xd5, 0xd7,
+0xdd, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec,
+0xee, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0x9f
+};
+
+int main(int argc, char *argv[])
+{
+ int c, i;
+ char *cp;
+
+ while (--argc) {
+ if (*(cp = *++argv) == '-') {
+ switch (*++cp) {
+ case 'l':
+ if ((i = atoi(++cp)) > 0)
+ length = i;
+ break;
+ }
+ }
+ }
+
+ while ((c = getchar()) != EOF) {
+ if (c == '\031') {
+ if ((c = getchar()) == '\1') {
+ lines = 0;
+ fflush(stdout);
+ kill(getpid(), SIGSTOP);
+ continue;
+ } else {
+ ungetc(c, stdin);
+ c = '\031';
+ }
+ } else if (c & 0x80) {
+ putchar(koi2855[c & 0x7F]);
+ continue;
+ } else if (c == '\n')
+ lines++;
+ else if (c == '\f')
+ lines = length;
+ putchar(c);
+ if (lines >= length) {
+ lines = 0;
+ fflush(stdout);
+ }
+ }
+ return 0;
+}
diff --git a/usr.sbin/lpr/filters.ru/koi2alt/Makefile b/usr.sbin/lpr/filters.ru/koi2alt/Makefile
new file mode 100644
index 0000000..f980bbf
--- /dev/null
+++ b/usr.sbin/lpr/filters.ru/koi2alt/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+PROG=koi2alt
+NOMAN= noman
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/filters.ru/koi2alt/koi2alt.c b/usr.sbin/lpr/filters.ru/koi2alt/koi2alt.c
new file mode 100644
index 0000000..928e97e
--- /dev/null
+++ b/usr.sbin/lpr/filters.ru/koi2alt/koi2alt.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 1993-98 by Andrey A. Chernov, Moscow, Russia.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * KOI8-R -> CP866 conversion filter (Russian character sets)
+ */
+
+#include <sys/types.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int length = 66;
+int lines;
+
+char *koi2alt[] = {
+/* 0 1 2 3 4 5 6 7 */
+/* 8 9 A B C D E F */
+/* 8 */ "\xc4","\xb3","\xda","\xbf","\xc0","\xd9","\xc3","\xb4",
+ "\xc2","\xc1","\xc5","\xdf","\xdc","\xdb","\xdd","\xde",
+/* 9 */ "\xb0","\xb1","\xb2","\xb3","\xfe","\xf9","\xfb","-\b~",
+ "<\b_",">\b_","\xff","\xb3","\xf8","2\b-","\xfa",":\b-",
+/* A */ "\xcd","\xba","\xd5","\xf1","\xd6","\xc9","\xb8","\xb7",
+ "\xbb","\xd4","\xd3","\xc8","\xbe","\xbd","\xbc","\xc6",
+/* B */ "\xc7","\xcc","\xb5","\xf0","\xb6","\xb9","\xd1","\xd2",
+ "\xcb","\xcf","\xd0","\xca","\xd8","\xd7","\xce","c\b_",
+/* C */ "\xee","\xa0","\xa1","\xe6","\xa4","\xa5","\xe4","\xa3",
+ "\xe5","\xa8","\xa9","\xaa","\xab","\xac","\xad","\xae",
+/* D */ "\xaf","\xef","\xe0","\xe1","\xe2","\xe3","\xa6","\xa2",
+ "\xec","\xeb","\xa7","\xe8","\xed","\xe9","\xe7","\xea",
+/* E */ "\x9e","\x80","\x81","\x96","\x84","\x85","\x94","\x83",
+ "\x95","\x88","\x89","\x8a","\x8b","\x8c","\x8d","\x8e",
+/* F */ "\x8f","\x9f","\x90","\x91","\x92","\x93","\x86","\x82",
+ "\x9c","\x9b","\x87","\x98","\x9d","\x99","\x97","\x9a"
+};
+
+int main(int argc, char *argv[])
+{
+ int c, i;
+ char *cp;
+
+ while (--argc) {
+ if (*(cp = *++argv) == '-') {
+ switch (*++cp) {
+ case 'l':
+ if ((i = atoi(++cp)) > 0)
+ length = i;
+ break;
+ }
+ }
+ }
+
+ while ((c = getchar()) != EOF) {
+ if (c == '\031') {
+ if ((c = getchar()) == '\1') {
+ lines = 0;
+ fflush(stdout);
+ kill(getpid(), SIGSTOP);
+ continue;
+ } else {
+ ungetc(c, stdin);
+ c = '\031';
+ }
+ } else if (c & 0x80) {
+ fputs(koi2alt[c & 0x7F], stdout);
+ continue;
+ } else if (c == '\n')
+ lines++;
+ else if (c == '\f')
+ lines = length;
+ putchar(c);
+ if (lines >= length) {
+ lines = 0;
+ fflush(stdout);
+ }
+ }
+ return 0;
+}
diff --git a/usr.sbin/lpr/filters/Makefile b/usr.sbin/lpr/filters/Makefile
new file mode 100644
index 0000000..c9d5c4f
--- /dev/null
+++ b/usr.sbin/lpr/filters/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lpf
+NOMAN= noman
+BINDIR= /usr/libexec/lpr
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/filters/lpf.c b/usr.sbin/lpr/filters/lpf.c
new file mode 100644
index 0000000..6fef3c4
--- /dev/null
+++ b/usr.sbin/lpr/filters/lpf.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "From: @(#)lpf.c 8.1 (Berkeley) 6/6/93";
+static char id[] = "$FreeBSD$";
+#endif /* not lint */
+
+/*
+ * filter which reads the output of nroff and converts lines
+ * with ^H's to overwritten lines. Thus this works like 'ul'
+ * but is much better: it can handle more than 2 overwrites
+ * and it is written with some style.
+ * modified by kls to use register references instead of arrays
+ * to try to gain a little speed.
+ */
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define MAXWIDTH 132
+#define MAXREP 10
+
+char buf[MAXREP][MAXWIDTH];
+int maxcol[MAXREP] = {-1};
+int lineno;
+int width = 132; /* default line length */
+int length = 66; /* page length */
+int indent; /* indentation length */
+int npages = 1;
+int literal; /* print control characters */
+char *name; /* user's login name */
+char *host; /* user's machine name */
+char *acctfile; /* accounting information file */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register FILE *p = stdin, *o = stdout;
+ register int i, col;
+ register char *cp;
+ int done, linedone, maxrep;
+ char *limit;
+ int ch;
+
+ while (--argc) {
+ if (*(cp = *++argv) == '-') {
+ switch (cp[1]) {
+ case 'n':
+ argc--;
+ name = *++argv;
+ break;
+
+ case 'h':
+ argc--;
+ host = *++argv;
+ break;
+
+ case 'w':
+ if ((i = atoi(&cp[2])) > 0 && i <= MAXWIDTH)
+ width = i;
+ break;
+
+ case 'l':
+ length = atoi(&cp[2]);
+ break;
+
+ case 'i':
+ indent = atoi(&cp[2]);
+ break;
+
+ case 'c': /* Print control chars */
+ literal++;
+ break;
+ }
+ } else
+ acctfile = cp;
+ }
+
+ for (cp = buf[0], limit = buf[MAXREP]; cp < limit; *cp++ = ' ');
+ done = 0;
+
+ while (!done) {
+ col = indent;
+ maxrep = -1;
+ linedone = 0;
+ while (!linedone) {
+ switch (ch = getc(p)) {
+ case EOF:
+ linedone = done = 1;
+ ch = '\n';
+ break;
+
+ case '\f':
+ lineno = length;
+ case '\n':
+ if (maxrep < 0)
+ maxrep = 0;
+ linedone = 1;
+ break;
+
+ case '\b':
+ if (--col < indent)
+ col = indent;
+ break;
+
+ case '\r':
+ col = indent;
+ break;
+
+ case '\t':
+ col = ((col - indent) | 07) + indent + 1;
+ break;
+
+ case '\031':
+ /*
+ * lpd needs to use a different filter to
+ * print data so stop what we are doing and
+ * wait for lpd to restart us.
+ */
+ if ((ch = getchar()) == '\1') {
+ fflush(stdout);
+ kill(getpid(), SIGSTOP);
+ break;
+ } else {
+ ungetc(ch, stdin);
+ ch = '\031';
+ }
+
+ default:
+ if (col >= width || !literal && ch < ' ') {
+ col++;
+ break;
+ }
+ cp = &buf[0][col];
+ for (i = 0; i < MAXREP; i++) {
+ if (i > maxrep)
+ maxrep = i;
+ if (*cp == ' ') {
+ *cp = ch;
+ if (col > maxcol[i])
+ maxcol[i] = col;
+ break;
+ }
+ cp += MAXWIDTH;
+ }
+ col++;
+ break;
+ }
+ }
+
+ /* print out lines */
+ for (i = 0; i <= maxrep; i++) {
+ for (cp = buf[i], limit = cp+maxcol[i]; cp <= limit;) {
+ putc(*cp, o);
+ *cp++ = ' ';
+ }
+ if (i < maxrep)
+ putc('\r', o);
+ else
+ putc(ch, o);
+ if (++lineno >= length) {
+ fflush(o);
+ npages++;
+ lineno = 0;
+ }
+ maxcol[i] = -1;
+ }
+ }
+ if (lineno) { /* be sure to end on a page boundary */
+ putchar('\f');
+ npages++;
+ }
+ if (name && acctfile && access(acctfile, 02) >= 0 &&
+ freopen(acctfile, "a", stdout) != NULL) {
+ printf("%7.2f\t%s:%s\n", (float)npages, host, name);
+ }
+ exit(0);
+}
diff --git a/usr.sbin/lpr/lp/Makefile b/usr.sbin/lpr/lp/Makefile
new file mode 100644
index 0000000..9522fc3
--- /dev/null
+++ b/usr.sbin/lpr/lp/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+BINDIR = /usr/bin
+MAN1 = lp.1
+
+beforeinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/lp.sh ${DESTDIR}${BINDIR}/lp
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lp/lp.1 b/usr.sbin/lpr/lp/lp.1
new file mode 100644
index 0000000..8666925
--- /dev/null
+++ b/usr.sbin/lpr/lp/lp.1
@@ -0,0 +1,117 @@
+.\"
+.\" Copyright (c) 1995 Joerg Wunsch
+.\"
+.\" All rights reserved.
+.\"
+.\" This program is free software.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Joerg Wunsch
+.\" 4. The name of the developer may not be used to endorse or promote
+.\" products derived from this software without specific prior written
+.\" permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 22, 1995
+.Dt LP 1
+.Os
+.Sh NAME
+.Nm lp
+.Nd front-end to the print spooler
+.Sh SYNOPSIS
+.Nm lp
+.Op Fl cs
+.Op Fl o Ar option
+.Op Fl d Ar printer
+.Op Fl n Ar num
+.Op Ar name ...
+.Sh DESCRIPTION
+.Nm Lp
+is a front-end to the print spooler as required by the
+.St -p1003.2
+specification. It effectively invokes
+.Xr lpr 1
+with the proper set of arguments.
+.Pp
+It generally prints the named files on the destination printer.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl c
+Make the
+.Nm
+command exit only after further access to any of the input files is no
+longer required. The application can then safely delete or modify the
+files without affecting the output operation.
+.It Fl d Ar dest
+Specify a particular printer.
+If no
+.Fl d
+is provided on the command line, the contents of the environment
+variables
+.Ev LPDEST
+or
+.Ev PRINTER
+.Pq with this precedence
+are taken as the destination printer.
+.It Fl n Ar num
+Specify that
+.Ar num
+copies of each of the named files shall be printed.
+.It Fl o Ar option
+Printer specific options.
+Not supported, provided only as a compatibility
+option for SVR.
+.It Fl s
+Silent operation.
+Not supported,
+provided only as a compatibility option for
+.St -susv2 .
+.El
+.Sh ENVIRONMENT
+As described above, the variables
+.Ev LPDEST
+and
+.Ev PRINTER
+are examined to select the destination printer.
+.Sh SEE ALSO
+.Xr lpr 1
+.Sh STANDARDS
+The
+.Nm
+command is expected to comply with the
+.St -p1003.2
+specification.
+.Sh AUTHORS
+This implementation of the
+.Nm
+command has been written by
+.if t J\(:org Wunsch.
+.if n Joerg Wunsch.
+.Sh BUGS
+The
+.St -p1003.2
+specification does not provide any means to print non-text files. It
+rather requires the files to be printed to be text files limited to
+reasonable line lengths and printable characters.
diff --git a/usr.sbin/lpr/lp/lp.sh b/usr.sbin/lpr/lp/lp.sh
new file mode 100644
index 0000000..e7c0688
--- /dev/null
+++ b/usr.sbin/lpr/lp/lp.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+#
+#
+# Copyright (c) 1995 Joerg Wunsch
+#
+# All rights reserved.
+#
+# This program is free software.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Joerg Wunsch
+# 4. The name of the developer may not be used to endorse or promote
+# products derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#
+# Posix 1003.2 compliant print spooler interface.
+#
+# $FreeBSD$
+#
+
+ncopies=""
+symlink="-s"
+
+# Posix says LPDEST gets precedence over PRINTER
+dest=${LPDEST:-${PRINTER:-lp}}
+
+#
+# XXX We include the -o flag as a dummy. Posix 1003.2 does not require
+# it, but the rationale mentions it as a possible future extension.
+# XXX We include the -s flag as a dummy. SUSv2 requires it,
+# although we do not yet emit the affected messages.
+#
+while getopts "cd:n:o:s" option
+do
+ case $option in
+
+ c) # copy files before printing
+ symlink="";;
+ d) # destination
+ dest="${OPTARG}";;
+ n) # number of copies
+ ncopies="-#${OPTARG}";;
+ o) # (printer option)
+ : ;;
+ s) # (silent option)
+ : ;;
+ *) # (error msg printed by getopts)
+ exit 2;;
+ esac
+done
+
+shift $(($OPTIND - 1))
+
+exec /usr/bin/lpr "-P${dest}" ${symlink} ${ncopies} "$@"
diff --git a/usr.sbin/lpr/lpc/Makefile b/usr.sbin/lpr/lpc/Makefile
new file mode 100644
index 0000000..48fd38b
--- /dev/null
+++ b/usr.sbin/lpr/lpc/Makefile
@@ -0,0 +1,14 @@
+# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $FreeBSD$
+
+PROG= lpc
+CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS}
+MAN8= lpc.8
+SRCS= lpc.c cmds.c cmdtab.c
+BINGRP= daemon
+BINMODE=2555
+.PATH: ${.CURDIR}/../common_source
+DPADD= ${LIBLPR} ${LIBEDIT} ${LIBTERMCAP}
+LDADD= ${LIBLPR} -ledit -ltermcap
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lpc/cmds.c b/usr.sbin/lpr/lpc/cmds.c
new file mode 100644
index 0000000..1ed69c8
--- /dev/null
+++ b/usr.sbin/lpr/lpc/cmds.c
@@ -0,0 +1,891 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*
+static char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 4/28/95";
+*/
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+/*
+ * lpc -- line printer control program -- commands:
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "lp.h"
+#include "lp.local.h"
+#include "lpc.h"
+#include "extern.h"
+#include "pathnames.h"
+
+static void abortpr __P((struct printer *, int));
+static int doarg __P((char *));
+static int doselect __P((struct dirent *));
+static void putmsg __P((struct printer *, int, char **));
+static int sortq __P((const void *, const void *));
+static void startpr __P((struct printer *, int));
+static int touch __P((struct queue *));
+static void unlinkf __P((char *));
+static void upstat __P((struct printer *, char *));
+
+/*
+ * generic framework for commands which operate on all or a specified
+ * set of printers
+ */
+void
+generic(doit, argc, argv)
+ void (*doit) __P((struct printer *));
+ int argc;
+ char *argv[];
+{
+ int status, more;
+ struct printer myprinter, *pp = &myprinter;
+
+ if (argc == 1) {
+ printf("Usage: %s {all | printer ...}\n", argv[0]);
+ return;
+ }
+ if (argc == 2 && strcmp(argv[1], "all") == 0) {
+ more = firstprinter(pp, &status);
+ if (status)
+ goto looperr;
+ while (more) {
+ (*doit)(pp);
+ do {
+ more = nextprinter(pp, &status);
+looperr:
+ switch (status) {
+ case PCAPERR_TCOPEN:
+ printf("warning: %s: unresolved "
+ "tc= reference(s) ",
+ pp->printer);
+ case PCAPERR_SUCCESS:
+ break;
+ default:
+ fatal(pp, pcaperr(status));
+ }
+ } while (more && status);
+ }
+ return;
+ }
+ while (--argc) {
+ ++argv;
+ init_printer(pp);
+ status = getprintcap(*argv, pp);
+ switch(status) {
+ default:
+ fatal(pp, pcaperr(status));
+ case PCAPERR_NOTFOUND:
+ printf("unknown printer %s\n", *argv);
+ continue;
+ case PCAPERR_TCOPEN:
+ printf("warning: %s: unresolved tc= reference(s)\n",
+ *argv);
+ break;
+ case PCAPERR_SUCCESS:
+ break;
+ }
+ (*doit)(pp);
+ }
+}
+
+/*
+ * kill an existing daemon and disable printing.
+ */
+void
+doabort(pp)
+ struct printer *pp;
+{
+ abortpr(pp, 1);
+}
+
+static void
+abortpr(pp, dis)
+ struct printer *pp;
+ int dis;
+{
+ register FILE *fp;
+ struct stat stbuf;
+ int pid, fd;
+ char lf[MAXPATHLEN];
+
+ lock_file_name(pp, lf, sizeof lf);
+ printf("%s:\n", pp->printer);
+
+ /*
+ * Turn on the owner execute bit of the lock file to disable printing.
+ */
+ if (dis) {
+ seteuid(euid);
+ if (stat(lf, &stbuf) >= 0) {
+ if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0)
+ printf("\tcannot disable printing: %s\n",
+ strerror(errno));
+ else {
+ upstat(pp, "printing disabled\n");
+ printf("\tprinting disabled\n");
+ }
+ } else if (errno == ENOENT) {
+ if ((fd = open(lf, O_WRONLY|O_CREAT,
+ LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0)
+ printf("\tcannot create lock file: %s\n",
+ strerror(errno));
+ else {
+ (void) close(fd);
+ upstat(pp, "printing disabled\n");
+ printf("\tprinting disabled\n");
+ printf("\tno daemon to abort\n");
+ }
+ goto out;
+ } else {
+ printf("\tcannot stat lock file\n");
+ goto out;
+ }
+ }
+ /*
+ * Kill the current daemon to stop printing now.
+ */
+ if ((fp = fopen(lf, "r")) == NULL) {
+ printf("\tcannot open lock file\n");
+ goto out;
+ }
+ if (!getline(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) {
+ (void) fclose(fp); /* unlocks as well */
+ printf("\tno daemon to abort\n");
+ goto out;
+ }
+ (void) fclose(fp);
+ if (kill(pid = atoi(line), SIGTERM) < 0) {
+ if (errno == ESRCH)
+ printf("\tno daemon to abort\n");
+ else
+ printf("\tWarning: daemon (pid %d) not killed\n", pid);
+ } else
+ printf("\tdaemon (pid %d) killed\n", pid);
+out:
+ seteuid(uid);
+}
+
+/*
+ * Write a message into the status file.
+ */
+static void
+upstat(pp, msg)
+ struct printer *pp;
+ char *msg;
+{
+ register int fd;
+ char statfile[MAXPATHLEN];
+
+ status_file_name(pp, statfile, sizeof statfile);
+ umask(0);
+ fd = open(statfile, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
+ if (fd < 0) {
+ printf("\tcannot create status file: %s\n", strerror(errno));
+ return;
+ }
+ (void) ftruncate(fd, 0);
+ if (msg == (char *)NULL)
+ (void) write(fd, "\n", 1);
+ else
+ (void) write(fd, msg, strlen(msg));
+ (void) close(fd);
+}
+
+static int
+doselect(d)
+ struct dirent *d;
+{
+ int c = d->d_name[0];
+
+ if ((c == 't' || c == 'c' || c == 'd') && d->d_name[1] == 'f')
+ return(1);
+ return(0);
+}
+
+/*
+ * Comparison routine for scandir. Sort by job number and machine, then
+ * by `cf', `tf', or `df', then by the sequence letter A-Z, a-z.
+ */
+static int
+sortq(a, b)
+ const void *a, *b;
+{
+ struct dirent **d1, **d2;
+ int c1, c2;
+
+ d1 = (struct dirent **)a;
+ d2 = (struct dirent **)b;
+ if ((c1 = strcmp((*d1)->d_name + 3, (*d2)->d_name + 3)))
+ return(c1);
+ c1 = (*d1)->d_name[0];
+ c2 = (*d2)->d_name[0];
+ if (c1 == c2)
+ return((*d1)->d_name[2] - (*d2)->d_name[2]);
+ if (c1 == 'c')
+ return(-1);
+ if (c1 == 'd' || c2 == 'c')
+ return(1);
+ return(-1);
+}
+
+/*
+ * Remove all spool files and temporaries from the spooling area.
+ * Or, perhaps:
+ * Remove incomplete jobs from spooling area.
+ */
+void
+clean(pp)
+ struct printer *pp;
+{
+ register int i, n;
+ register char *cp, *cp1, *lp;
+ struct dirent **queue;
+ int nitems;
+
+ printf("%s:\n", pp->printer);
+
+ lp = line;
+ cp = pp->spool_dir;
+ while (lp < &line[sizeof(line) - 1]) {
+ if ((*lp++ = *cp++) == 0)
+ break;
+ }
+ lp[-1] = '/';
+
+ seteuid(euid);
+ nitems = scandir(pp->spool_dir, &queue, doselect, sortq);
+ seteuid(uid);
+ if (nitems < 0) {
+ printf("\tcannot examine spool directory\n");
+ return;
+ }
+ if (nitems == 0)
+ return;
+ i = 0;
+ do {
+ cp = queue[i]->d_name;
+ if (*cp == 'c') {
+ n = 0;
+ while (i + 1 < nitems) {
+ cp1 = queue[i + 1]->d_name;
+ if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3))
+ break;
+ i++;
+ n++;
+ }
+ if (n == 0) {
+ strncpy(lp, cp, sizeof(line) - strlen(line) - 1);
+ line[sizeof(line) - 1] = '\0';
+ unlinkf(line);
+ }
+ } else {
+ /*
+ * Must be a df with no cf (otherwise, it would have
+ * been skipped above) or a tf file (which can always
+ * be removed).
+ */
+ strncpy(lp, cp, sizeof(line) - strlen(line) - 1);
+ line[sizeof(line) - 1] = '\0';
+ unlinkf(line);
+ }
+ } while (++i < nitems);
+}
+
+static void
+unlinkf(name)
+ char *name;
+{
+ seteuid(euid);
+ if (unlink(name) < 0)
+ printf("\tcannot remove %s\n", name);
+ else
+ printf("\tremoved %s\n", name);
+ seteuid(uid);
+}
+
+/*
+ * Enable queuing to the printer (allow lpr's).
+ */
+void
+enable(pp)
+ struct printer *pp;
+{
+ struct stat stbuf;
+ char lf[MAXPATHLEN];
+
+ lock_file_name(pp, lf, sizeof lf);
+ printf("%s:\n", pp->printer);
+
+ /*
+ * Turn off the group execute bit of the lock file to enable queuing.
+ */
+ seteuid(euid);
+ if (stat(lf, &stbuf) >= 0) {
+ if (chmod(lf, stbuf.st_mode & ~LFM_QUEUE_DIS) < 0)
+ printf("\tcannot enable queuing\n");
+ else
+ printf("\tqueuing enabled\n");
+ }
+ seteuid(uid);
+}
+
+/*
+ * Disable queuing.
+ */
+void
+disable(pp)
+ struct printer *pp;
+{
+ register int fd;
+ struct stat stbuf;
+ char lf[MAXPATHLEN];
+
+ lock_file_name(pp, lf, sizeof lf);
+ printf("%s:\n", pp->printer);
+ /*
+ * Turn on the group execute bit of the lock file to disable queuing.
+ */
+ seteuid(euid);
+ if (stat(lf, &stbuf) >= 0) {
+ if (chmod(lf, stbuf.st_mode | LFM_QUEUE_DIS) < 0)
+ printf("\tcannot disable queuing: %s\n",
+ strerror(errno));
+ else
+ printf("\tqueuing disabled\n");
+ } else if (errno == ENOENT) {
+ if ((fd = open(lf, O_WRONLY|O_CREAT,
+ LOCK_FILE_MODE | LFM_QUEUE_DIS)) < 0)
+ printf("\tcannot create lock file: %s\n",
+ strerror(errno));
+ else {
+ (void) close(fd);
+ printf("\tqueuing disabled\n");
+ }
+ } else
+ printf("\tcannot stat lock file\n");
+ seteuid(uid);
+}
+
+/*
+ * Disable queuing and printing and put a message into the status file
+ * (reason for being down).
+ */
+void
+down(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int status, more;
+ struct printer myprinter, *pp = &myprinter;
+
+ if (argc == 1) {
+ printf("Usage: down {all | printer} [message ...]\n");
+ return;
+ }
+ if (!strcmp(argv[1], "all")) {
+ more = firstprinter(pp, &status);
+ if (status)
+ goto looperr;
+ while (more) {
+ putmsg(pp, argc - 2, argv + 2);
+ do {
+ more = nextprinter(pp, &status);
+looperr:
+ switch (status) {
+ case PCAPERR_TCOPEN:
+ printf("warning: %s: unresolved "
+ "tc= reference(s) ",
+ pp->printer);
+ case PCAPERR_SUCCESS:
+ break;
+ default:
+ fatal(pp, pcaperr(status));
+ }
+ } while (more && status);
+ }
+ return;
+ }
+ init_printer(pp);
+ status = getprintcap(argv[1], pp);
+ switch(status) {
+ default:
+ fatal(pp, pcaperr(status));
+ case PCAPERR_NOTFOUND:
+ printf("unknown printer %s\n", argv[1]);
+ return;
+ case PCAPERR_TCOPEN:
+ printf("warning: %s: unresolved tc= reference(s)", argv[1]);
+ break;
+ case PCAPERR_SUCCESS:
+ break;
+ }
+ putmsg(pp, argc - 2, argv + 2);
+}
+
+static void
+putmsg(pp, argc, argv)
+ struct printer *pp;
+ int argc;
+ char **argv;
+{
+ register int fd;
+ register char *cp1, *cp2;
+ char buf[1024];
+ char file[MAXPATHLEN];
+ struct stat stbuf;
+
+ printf("%s:\n", pp->printer);
+ /*
+ * Turn on the group execute bit of the lock file to disable queuing;
+ * turn on the owner execute bit of the lock file to disable printing.
+ */
+ lock_file_name(pp, file, sizeof file);
+ seteuid(euid);
+ if (stat(file, &stbuf) >= 0) {
+ if (chmod(file, stbuf.st_mode|LFM_PRINT_DIS|LFM_QUEUE_DIS) < 0)
+ printf("\tcannot disable queuing: %s\n",
+ strerror(errno));
+ else
+ printf("\tprinter and queuing disabled\n");
+ } else if (errno == ENOENT) {
+ if ((fd = open(file, O_WRONLY|O_CREAT,
+ LOCK_FILE_MODE|LFM_PRINT_DIS|LFM_QUEUE_DIS)) < 0)
+ printf("\tcannot create lock file: %s\n",
+ strerror(errno));
+ else {
+ (void) close(fd);
+ printf("\tprinter and queuing disabled\n");
+ }
+ seteuid(uid);
+ return;
+ } else
+ printf("\tcannot stat lock file\n");
+ /*
+ * Write the message into the status file.
+ */
+ status_file_name(pp, file, sizeof file);
+ fd = open(file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
+ if (fd < 0) {
+ printf("\tcannot create status file: %s\n", strerror(errno));
+ seteuid(uid);
+ return;
+ }
+ seteuid(uid);
+ (void) ftruncate(fd, 0);
+ if (argc <= 0) {
+ (void) write(fd, "\n", 1);
+ (void) close(fd);
+ return;
+ }
+ cp1 = buf;
+ while (--argc >= 0) {
+ cp2 = *argv++;
+ while ((cp1 - buf) < sizeof(buf) && (*cp1++ = *cp2++))
+ ;
+ cp1[-1] = ' ';
+ }
+ cp1[-1] = '\n';
+ *cp1 = '\0';
+ (void) write(fd, buf, strlen(buf));
+ (void) close(fd);
+}
+
+/*
+ * Exit lpc
+ */
+void
+quit(argc, argv)
+ int argc;
+ char *argv[];
+{
+ exit(0);
+}
+
+/*
+ * Kill and restart the daemon.
+ */
+void
+restart(pp)
+ struct printer *pp;
+{
+ abortpr(pp, 0);
+ startpr(pp, 0);
+}
+
+/*
+ * Enable printing on the specified printer and startup the daemon.
+ */
+void
+startcmd(pp)
+ struct printer *pp;
+{
+ startpr(pp, 1);
+}
+
+static void
+startpr(pp, enable)
+ struct printer *pp;
+ int enable;
+{
+ struct stat stbuf;
+ char lf[MAXPATHLEN];
+
+ lock_file_name(pp, lf, sizeof lf);
+ printf("%s:\n", pp->printer);
+
+ /*
+ * For enable==1 ('start'), turn off the LFM_PRINT_DIS bit of the
+ * lock file to re-enable printing. For enable==2 ('up'), also
+ * turn off the LFM_QUEUE_DIS bit to re-enable queueing.
+ */
+ seteuid(euid);
+ if (enable && stat(lf, &stbuf) >= 0) {
+ mode_t bits = (enable == 2 ? 0 : LFM_QUEUE_DIS);
+ if (chmod(lf, stbuf.st_mode & (LOCK_FILE_MODE | bits)) < 0)
+ printf("\tcannot enable printing\n");
+ else
+ printf("\tprinting enabled\n");
+ }
+ if (!startdaemon(pp))
+ printf("\tcouldn't start daemon\n");
+ else
+ printf("\tdaemon started\n");
+ seteuid(uid);
+}
+
+/*
+ * Print the status of the printer queue.
+ */
+void
+status(pp)
+ struct printer *pp;
+{
+ struct stat stbuf;
+ register int fd, i;
+ register struct dirent *dp;
+ DIR *dirp;
+ char file[MAXPATHLEN];
+
+ printf("%s:\n", pp->printer);
+ lock_file_name(pp, file, sizeof file);
+ if (stat(file, &stbuf) >= 0) {
+ printf("\tqueuing is %s\n",
+ ((stbuf.st_mode & LFM_QUEUE_DIS) ? "disabled"
+ : "enabled"));
+ printf("\tprinting is %s\n",
+ ((stbuf.st_mode & LFM_PRINT_DIS) ? "disabled"
+ : "enabled"));
+ } else {
+ printf("\tqueuing is enabled\n");
+ printf("\tprinting is enabled\n");
+ }
+ if ((dirp = opendir(pp->spool_dir)) == NULL) {
+ printf("\tcannot examine spool directory\n");
+ return;
+ }
+ i = 0;
+ while ((dp = readdir(dirp)) != NULL) {
+ if (*dp->d_name == 'c' && dp->d_name[1] == 'f')
+ i++;
+ }
+ closedir(dirp);
+ if (i == 0)
+ printf("\tno entries in spool area\n");
+ else if (i == 1)
+ printf("\t1 entry in spool area\n");
+ else
+ printf("\t%d entries in spool area\n", i);
+ fd = open(file, O_RDONLY);
+ if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) {
+ (void) close(fd); /* unlocks as well */
+ printf("\tprinter idle\n");
+ return;
+ }
+ (void) close(fd);
+ /* print out the contents of the status file, if it exists */
+ status_file_name(pp, file, sizeof file);
+ fd = open(file, O_RDONLY|O_SHLOCK);
+ if (fd >= 0) {
+ (void) fstat(fd, &stbuf);
+ if (stbuf.st_size > 0) {
+ putchar('\t');
+ while ((i = read(fd, line, sizeof(line))) > 0)
+ (void) fwrite(line, 1, i, stdout);
+ }
+ (void) close(fd); /* unlocks as well */
+ }
+}
+
+/*
+ * Stop the specified daemon after completing the current job and disable
+ * printing.
+ */
+void
+stop(pp)
+ struct printer *pp;
+{
+ register int fd;
+ struct stat stbuf;
+ char lf[MAXPATHLEN];
+
+ lock_file_name(pp, lf, sizeof lf);
+ printf("%s:\n", pp->printer);
+
+ /*
+ * Turn on the owner execute bit of the lock file to disable printing.
+ */
+ seteuid(euid);
+ if (stat(lf, &stbuf) >= 0) {
+ if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0)
+ printf("\tcannot disable printing: %s\n",
+ strerror(errno));
+ else {
+ upstat(pp, "printing disabled\n");
+ printf("\tprinting disabled\n");
+ }
+ } else if (errno == ENOENT) {
+ if ((fd = open(lf, O_WRONLY|O_CREAT,
+ LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0)
+ printf("\tcannot create lock file: %s\n",
+ strerror(errno));
+ else {
+ (void) close(fd);
+ upstat(pp, "printing disabled\n");
+ printf("\tprinting disabled\n");
+ }
+ } else
+ printf("\tcannot stat lock file\n");
+ seteuid(uid);
+}
+
+struct queue **queue;
+int nitems;
+time_t mtime;
+
+/*
+ * Put the specified jobs at the top of printer queue.
+ */
+void
+topq(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int i;
+ struct stat stbuf;
+ int status, changed;
+ struct printer myprinter, *pp = &myprinter;
+
+ if (argc < 3) {
+ printf("Usage: topq printer [jobnum ...] [user ...]\n");
+ return;
+ }
+
+ --argc;
+ ++argv;
+ init_printer(pp);
+ status = getprintcap(*argv, pp);
+ switch(status) {
+ default:
+ fatal(pp, pcaperr(status));
+ case PCAPERR_NOTFOUND:
+ printf("unknown printer %s\n", *argv);
+ return;
+ case PCAPERR_TCOPEN:
+ printf("warning: %s: unresolved tc= reference(s)", *argv);
+ break;
+ case PCAPERR_SUCCESS:
+ break;
+ }
+ printf("%s:\n", pp->printer);
+
+ seteuid(euid);
+ if (chdir(pp->spool_dir) < 0) {
+ printf("\tcannot chdir to %s\n", pp->spool_dir);
+ goto out;
+ }
+ seteuid(uid);
+ nitems = getq(pp, &queue);
+ if (nitems == 0)
+ return;
+ changed = 0;
+ mtime = queue[0]->q_time;
+ for (i = argc; --i; ) {
+ if (doarg(argv[i]) == 0) {
+ printf("\tjob %s is not in the queue\n", argv[i]);
+ continue;
+ } else
+ changed++;
+ }
+ for (i = 0; i < nitems; i++)
+ free(queue[i]);
+ free(queue);
+ if (!changed) {
+ printf("\tqueue order unchanged\n");
+ return;
+ }
+ /*
+ * Turn on the public execute bit of the lock file to
+ * get lpd to rebuild the queue after the current job.
+ */
+ seteuid(euid);
+ if (changed && stat(pp->lock_file, &stbuf) >= 0)
+ (void) chmod(pp->lock_file, stbuf.st_mode | LFM_RESET_QUE);
+
+out:
+ seteuid(uid);
+}
+
+/*
+ * Reposition the job by changing the modification time of
+ * the control file.
+ */
+static int
+touch(q)
+ struct queue *q;
+{
+ struct timeval tvp[2];
+ int ret;
+
+ tvp[0].tv_sec = tvp[1].tv_sec = --mtime;
+ tvp[0].tv_usec = tvp[1].tv_usec = 0;
+ seteuid(euid);
+ ret = utimes(q->q_name, tvp);
+ seteuid(uid);
+ return (ret);
+}
+
+/*
+ * Checks if specified job name is in the printer's queue.
+ * Returns: negative (-1) if argument name is not in the queue.
+ */
+static int
+doarg(job)
+ char *job;
+{
+ register struct queue **qq;
+ register int jobnum, n;
+ register char *cp, *machine;
+ int cnt = 0;
+ FILE *fp;
+
+ /*
+ * Look for a job item consisting of system name, colon, number
+ * (example: ucbarpa:114)
+ */
+ if ((cp = strchr(job, ':')) != NULL) {
+ machine = job;
+ *cp++ = '\0';
+ job = cp;
+ } else
+ machine = NULL;
+
+ /*
+ * Check for job specified by number (example: 112 or 235ucbarpa).
+ */
+ if (isdigit(*job)) {
+ jobnum = 0;
+ do
+ jobnum = jobnum * 10 + (*job++ - '0');
+ while (isdigit(*job));
+ for (qq = queue + nitems; --qq >= queue; ) {
+ n = 0;
+ for (cp = (*qq)->q_name+3; isdigit(*cp); )
+ n = n * 10 + (*cp++ - '0');
+ if (jobnum != n)
+ continue;
+ if (*job && strcmp(job, cp) != 0)
+ continue;
+ if (machine != NULL && strcmp(machine, cp) != 0)
+ continue;
+ if (touch(*qq) == 0) {
+ printf("\tmoved %s\n", (*qq)->q_name);
+ cnt++;
+ }
+ }
+ return(cnt);
+ }
+ /*
+ * Process item consisting of owner's name (example: henry).
+ */
+ for (qq = queue + nitems; --qq >= queue; ) {
+ seteuid(euid);
+ fp = fopen((*qq)->q_name, "r");
+ seteuid(uid);
+ if (fp == NULL)
+ continue;
+ while (getline(fp) > 0)
+ if (line[0] == 'P')
+ break;
+ (void) fclose(fp);
+ if (line[0] != 'P' || strcmp(job, line+1) != 0)
+ continue;
+ if (touch(*qq) == 0) {
+ printf("\tmoved %s\n", (*qq)->q_name);
+ cnt++;
+ }
+ }
+ return(cnt);
+}
+
+/*
+ * Enable everything and start printer (undo `down').
+ */
+void
+up(pp)
+ struct printer *pp;
+{
+ startpr(pp, 2);
+}
diff --git a/usr.sbin/lpr/lpc/cmdtab.c b/usr.sbin/lpr/lpc/cmdtab.c
new file mode 100644
index 0000000..8e2b6ef
--- /dev/null
+++ b/usr.sbin/lpr/lpc/cmdtab.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+/*
+static char sccsid[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93";
+*/
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "lpc.h"
+#include "extern.h"
+
+/*
+ * lpc -- command tables
+ */
+char aborthelp[] = "terminate a spooling daemon immediately and disable printing";
+char cleanhelp[] = "remove cruft files from a queue";
+char enablehelp[] = "turn a spooling queue on";
+char disablehelp[] = "turn a spooling queue off";
+char downhelp[] = "do a 'stop' followed by 'disable' and put a message in status";
+char helphelp[] = "get help on commands";
+char quithelp[] = "exit lpc";
+char restarthelp[] = "kill (if possible) and restart a spooling daemon";
+char starthelp[] = "enable printing and start a spooling daemon";
+char statushelp[] = "show status of daemon and queue";
+char stophelp[] = "stop a spooling daemon after current job completes and disable printing";
+char topqhelp[] = "put job at top of printer queue";
+char uphelp[] = "enable everything and restart spooling daemon";
+
+struct cmd cmdtab[] = {
+ { "abort", aborthelp, 0, 1, doabort },
+ { "clean", cleanhelp, 0, 1, clean },
+ { "enable", enablehelp, 0, 1, enable },
+ { "exit", quithelp, quit, 0 },
+ { "disable", disablehelp, 0, 1, disable },
+ { "down", downhelp, down, 1 },
+ { "help", helphelp, help, 0 },
+ { "quit", quithelp, quit, 0 },
+ { "restart", restarthelp, 0, 0, restart },
+ { "start", starthelp, 0, 1, startcmd },
+ { "status", statushelp, 0, 0, status },
+ { "stop", stophelp, 0, 1, stop },
+ { "topq", topqhelp, topq, 1 },
+ { "up", uphelp, 0, 1, up },
+ { "?", helphelp, help, 0 },
+ { 0 },
+};
+
+int NCMDS = sizeof (cmdtab) / sizeof (cmdtab[0]);
diff --git a/usr.sbin/lpr/lpc/extern.h b/usr.sbin/lpr/lpc/extern.h
new file mode 100644
index 0000000..a07a09a
--- /dev/null
+++ b/usr.sbin/lpr/lpc/extern.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ */
+
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+
+__BEGIN_DECLS
+void clean __P((struct printer *));
+void disable __P((struct printer *));
+void doabort __P((struct printer *));
+void down __P((int, char **));
+void enable __P((struct printer *));
+void generic __P((void (*) __P((struct printer *)), int, char **));
+void help __P((int, char **));
+void quit __P((int, char **));
+void restart __P((struct printer *));
+void startcmd __P((struct printer *));
+void status __P((struct printer *));
+void stop __P((struct printer *));
+void topq __P((int, char **));
+void up __P((struct printer *));
+__END_DECLS
+
+extern int NCMDS;
+extern struct cmd cmdtab[];
+extern uid_t uid, euid;
diff --git a/usr.sbin/lpr/lpc/lpc.8 b/usr.sbin/lpr/lpc/lpc.8
new file mode 100644
index 0000000..f0586d7
--- /dev/null
+++ b/usr.sbin/lpr/lpc/lpc.8
@@ -0,0 +1,178 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)lpc.8 8.5 (Berkeley) 4/28/95
+.\" $FreeBSD$
+.\"
+.Dd April 28, 1995
+.Dt LPC 8
+.Os BSD 4.2
+.Sh NAME
+.Nm lpc
+.Nd line printer control program
+.Sh SYNOPSIS
+.Nm lpc
+.Oo
+.Ar command
+.Op Ar argument ...
+.Oc
+.Sh DESCRIPTION
+.Nm Lpc
+is used by the system administrator to control the
+operation of the line printer system.
+For each line printer configured in
+.Pa /etc/printcap ,
+.Nm lpc
+may be used to:
+.Bl -bullet -offset indent
+.It
+disable or enable a printer,
+.It
+disable or enable a printer's spooling queue,
+.It
+rearrange the order of jobs in a spooling queue,
+.It
+find the status of printers, and their associated
+spooling queues and printer daemons.
+.El
+.Pp
+Without any arguments,
+.Nm
+will prompt for commands from the standard input.
+If arguments are supplied,
+.Nm
+interprets the first argument as a command and the remaining
+arguments as parameters to the command. The standard input
+may be redirected causing
+.Nm
+to read commands from file.
+Commands may be abbreviated;
+the following is the list of recognized commands.
+.Pp
+.Bl -tag -width Ds -compact
+.It Ic \&? No [ command ... ]
+.It Ic help No [ command ... ]
+Print a short description of each command specified in the argument list,
+or, if no argument is given, a list of the recognized commands.
+.Pp
+.It Ic abort No {\ all\ |\ printer\ }
+Terminate an active spooling daemon on the local host immediately and
+then disable printing (preventing new daemons from being started by
+.Xr lpr 1 )
+for the specified printers.
+.Pp
+.It Ic clean No {\ all\ |\ printer\ }
+Remove any temporary files, data files, and control files that cannot
+be printed (i.e., do not form a complete printer job)
+from the specified printer queue(s) on the local machine.
+.Pp
+.It Ic disable No {\ all\ |\ printer\ }
+Turn the specified printer queues off. This prevents new
+printer jobs from being entered into the queue by
+.Xr lpr 1 .
+.Pp
+.It Ic down No {\ all\ |\ printer\ } message ...
+Turn the specified printer queue off, disable printing and put
+.Em message
+in the printer status file.
+The message doesn't need to be quoted, the
+remaining arguments are treated like
+.Xr echo 1 .
+This is normally used to take a printer down and let others know why
+.Xr lpq 1
+will indicate the printer is down and print the status message).
+.Pp
+.It Ic enable No {\ all\ |\ printer\ }
+Enable spooling on the local queue for the listed printers.
+This will allow
+.Xr lpr 1
+to put new jobs in the spool queue.
+.Pp
+.It Ic exit
+.It Ic quit
+Exit from lpc.
+.\" ne 1i
+.Pp
+.It Ic restart No {\ all\ |\ printer\ }
+Attempt to start a new printer daemon.
+This is useful when some abnormal condition causes the daemon to
+die unexpectedly, leaving jobs in the queue.
+.Xr Lpq 1
+will report that there is no daemon present when this condition occurs.
+If the user is the super-user,
+try to abort the current daemon first (i.e., kill and restart a stuck daemon).
+.Pp
+.It Ic start No {\ all\ |\ printer\ }
+Enable printing and start a spooling daemon for the listed printers.
+.Pp
+.It Ic status No {\ all\ |\ printer\ }
+Display the status of daemons and queues on the local machine.
+.Pp
+.It Ic stop No {\ all\ |\ printer\ }
+Stop a spooling daemon after the current job completes and disable
+printing.
+.Pp
+.It Ic topq No printer\ [\ jobnum\ ...\ ]\ [\ user\ ...\ ]
+Place the jobs in the order listed at the top of the printer queue.
+.Pp
+.It Ic up No {\ all\ |\ printer\ }
+Enable everything and start a new printer daemon.
+Undoes the effects of
+.Ic down .
+.Sh FILES
+.Bl -tag -width /var/spool/*/lockx -compact
+.It Pa /etc/printcap
+printer description file
+.It Pa /var/spool/*
+spool directories
+.It Pa /var/spool/*/lock
+lock file for queue control
+.El
+.Sh SEE ALSO
+.Xr lpq 1 ,
+.Xr lpr 1 ,
+.Xr lprm 1 ,
+.Xr printcap 5 ,
+.Xr lpd 8
+.Sh DIAGNOSTICS
+.Bl -tag -width Ds
+.It Sy "?Ambiguous command"
+abbreviation matches more than one command
+.It Sy "?Invalid command"
+no match was found
+.It Sy "?Privileged command"
+you must be a member of group "operator" or root to execute this command
+.El
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr.sbin/lpr/lpc/lpc.c b/usr.sbin/lpr/lpc/lpc.c
new file mode 100644
index 0000000..866b8ac
--- /dev/null
+++ b/usr.sbin/lpr/lpc/lpc.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)lpc.c 8.3 (Berkeley) 4/28/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <grp.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <unistd.h>
+#include <histedit.h>
+
+#include "lp.h"
+#include "lpc.h"
+#include "extern.h"
+
+#ifndef LPR_OPER
+#define LPR_OPER "operator" /* group name of lpr operators */
+#endif
+
+/*
+ * lpc -- line printer control program
+ */
+
+#define MAX_CMDLINE 200
+#define MAX_MARGV 20
+static int fromatty;
+
+static char cmdline[MAX_CMDLINE];
+static int margc;
+static char *margv[MAX_MARGV];
+uid_t uid, euid;
+
+int main __P((int, char *[]));
+static void cmdscanner __P((void));
+static struct cmd *getcmd __P((char *));
+static void intr __P((int));
+static void makeargv __P((void));
+static int ingroup __P((char *));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct cmd *c;
+
+ euid = geteuid();
+ uid = getuid();
+ seteuid(uid);
+ name = argv[0];
+ openlog("lpd", 0, LOG_LPR);
+
+ if (--argc > 0) {
+ c = getcmd(*++argv);
+ if (c == (struct cmd *)-1) {
+ printf("?Ambiguous command\n");
+ exit(1);
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ exit(1);
+ }
+ if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
+ printf("?Privileged command\n");
+ exit(1);
+ }
+ if (c->c_generic != 0)
+ generic(c->c_generic, argc, argv);
+ else
+ (*c->c_handler)(argc, argv);
+ exit(0);
+ }
+ fromatty = isatty(fileno(stdin));
+ if (!fromatty)
+ signal(SIGINT, intr);
+ for (;;) {
+ cmdscanner();
+ }
+}
+
+static void
+intr(signo)
+ int signo;
+{
+ exit(0);
+}
+
+static char *
+lpc_prompt()
+{
+ return("lpc> ");
+}
+
+/*
+ * Command parser.
+ */
+static void
+cmdscanner()
+{
+ register struct cmd *c;
+ static EditLine *el = NULL;
+ static History *hist = NULL;
+ int num = 0;
+ int len;
+ const char *bp = NULL;
+
+ for (;;) {
+ if (fromatty) {
+ if (!el) {
+ el = el_init("lpc", stdin, stdout);
+ hist = history_init();
+ history(hist, H_EVENT, 100);
+ el_set(el, EL_HIST, history, hist);
+ el_set(el, EL_EDITOR, "emacs");
+ el_set(el, EL_PROMPT, lpc_prompt);
+ el_set(el, EL_SIGNAL, 1);
+ el_source(el, NULL);
+ }
+ if ((bp = el_gets(el, &num)) == NULL || num == 0)
+ quit(0, NULL);
+
+ len = (num > MAX_CMDLINE) ? MAX_CMDLINE : num;
+ memcpy(cmdline, bp, len);
+ cmdline[len] = 0;
+ history(hist, H_ENTER, bp);
+
+ } else {
+ if (fgets(cmdline, MAX_CMDLINE, stdin) == 0)
+ quit(0, NULL);
+ if (cmdline[0] == 0 || cmdline[0] == '\n')
+ break;
+ }
+
+ makeargv();
+ if (margc == 0)
+ continue;
+ if (el_parse(el, margc, margv) != -1)
+ continue;
+
+ c = getcmd(margv[0]);
+ if (c == (struct cmd *)-1) {
+ printf("?Ambiguous command\n");
+ continue;
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ continue;
+ }
+ if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
+ printf("?Privileged command\n");
+ continue;
+ }
+ if (c->c_generic != 0)
+ generic(c->c_generic, margc, margv);
+ else
+ (*c->c_handler)(margc, margv);
+ }
+}
+
+static struct cmd *
+getcmd(name)
+ register char *name;
+{
+ register char *p, *q;
+ register struct cmd *c, *found;
+ register int nmatches, longest;
+
+ longest = 0;
+ nmatches = 0;
+ found = 0;
+ for (c = cmdtab; (p = c->c_name); c++) {
+ for (q = name; *q == *p++; q++)
+ if (*q == 0) /* exact match? */
+ return(c);
+ if (!*q) { /* the name was a prefix */
+ if (q - name > longest) {
+ longest = q - name;
+ nmatches = 1;
+ found = c;
+ } else if (q - name == longest)
+ nmatches++;
+ }
+ }
+ if (nmatches > 1)
+ return((struct cmd *)-1);
+ return(found);
+}
+
+/*
+ * Slice a string up into argc/argv.
+ */
+static void
+makeargv()
+{
+ register char *cp;
+ register char **argp = margv;
+ register int n = 0;
+
+ margc = 0;
+ for (cp = cmdline; *cp && (cp - cmdline) < sizeof(cmdline) &&
+ n < MAX_MARGV; n++) {
+ while (isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *argp++ = cp;
+ margc += 1;
+ while (*cp != '\0' && !isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *cp++ = '\0';
+ }
+ *argp++ = 0;
+}
+
+#define HELPINDENT (sizeof ("directory"))
+
+/*
+ * Help command.
+ */
+void
+help(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct cmd *c;
+
+ if (argc == 1) {
+ register int i, j, w;
+ int columns, width = 0, lines;
+
+ printf("Commands may be abbreviated. Commands are:\n\n");
+ for (c = cmdtab; c->c_name; c++) {
+ int len = strlen(c->c_name);
+
+ if (len > width)
+ width = len;
+ }
+ width = (width + 8) &~ 7;
+ columns = 80 / width;
+ if (columns == 0)
+ columns = 1;
+ lines = (NCMDS + columns - 1) / columns;
+ for (i = 0; i < lines; i++) {
+ for (j = 0; j < columns; j++) {
+ c = cmdtab + j * lines + i;
+ if (c->c_name)
+ printf("%s", c->c_name);
+ if (c + lines >= &cmdtab[NCMDS]) {
+ printf("\n");
+ break;
+ }
+ w = strlen(c->c_name);
+ while (w < width) {
+ w = (w + 8) &~ 7;
+ putchar('\t');
+ }
+ }
+ }
+ return;
+ }
+ while (--argc > 0) {
+ register char *arg;
+ arg = *++argv;
+ c = getcmd(arg);
+ if (c == (struct cmd *)-1)
+ printf("?Ambiguous help command %s\n", arg);
+ else if (c == (struct cmd *)0)
+ printf("?Invalid help command %s\n", arg);
+ else
+ printf("%-*s\t%s\n", (int) HELPINDENT,
+ c->c_name, c->c_help);
+ }
+}
+
+/*
+ * return non-zero if the user is a member of the given group
+ */
+static int
+ingroup(grname)
+ char *grname;
+{
+ static struct group *gptr=NULL;
+ static int ngroups = 0;
+ static gid_t groups[NGROUPS];
+ register gid_t gid;
+ register int i;
+
+ if (gptr == NULL) {
+ if ((gptr = getgrnam(grname)) == NULL) {
+ warnx("warning: unknown group '%s'", grname);
+ return(0);
+ }
+ ngroups = getgroups(NGROUPS, groups);
+ if (ngroups < 0)
+ err(1, "getgroups");
+ }
+ gid = gptr->gr_gid;
+ for (i = 0; i < ngroups; i++)
+ if (gid == groups[i])
+ return(1);
+ return(0);
+}
diff --git a/usr.sbin/lpr/lpc/lpc.h b/usr.sbin/lpr/lpc/lpc.h
new file mode 100644
index 0000000..eca7b91
--- /dev/null
+++ b/usr.sbin/lpr/lpc/lpc.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)lpc.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * Line printer control program.
+ */
+struct printer;
+
+struct cmd {
+ char *c_name; /* command name */
+ char *c_help; /* help message */
+ /* routine to do the work */
+ void (*c_handler) __P((int, char *[]));
+ int c_priv; /* privileged command */
+ void (*c_generic) __P((struct printer *)); /* generic command */
+};
diff --git a/usr.sbin/lpr/lpd/Makefile b/usr.sbin/lpr/lpd/Makefile
new file mode 100644
index 0000000..e107e97
--- /dev/null
+++ b/usr.sbin/lpr/lpd/Makefile
@@ -0,0 +1,11 @@
+# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $FreeBSD$
+
+PROG= lpd
+CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS}
+MAN8= lpd.8
+SRCS= lpd.c printjob.c recvjob.c lpdchar.c modes.c
+DPADD= ${LIBLPR}
+LDADD= ${LIBLPR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lpd/extern.h b/usr.sbin/lpr/lpd/extern.h
new file mode 100644
index 0000000..70c536d
--- /dev/null
+++ b/usr.sbin/lpr/lpd/extern.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * From: @(#)extern.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+
+extern char scnkey[][HEIGHT]; /* in lpdchar.c */
+extern char fromb[];
+
+struct printer;
+struct termios;
+
+__BEGIN_DECLS
+void printjob __P((struct printer *pp));
+void startprinting __P((const char *printer));
+void recvjob __P((const char *printer));
+int msearch __P((char *str, struct termios *ip));
+__END_DECLS
diff --git a/usr.sbin/lpr/lpd/lpd.8 b/usr.sbin/lpr/lpd/lpd.8
new file mode 100644
index 0000000..f882a31
--- /dev/null
+++ b/usr.sbin/lpr/lpd/lpd.8
@@ -0,0 +1,271 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)lpd.8 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1994
+.Dt LPD 8
+.Os BSD 4.2
+.Sh NAME
+.Nm lpd
+.Nd line printer spooler daemon
+.Sh SYNOPSIS
+.Nm lpd
+.Op Fl dlp
+.Op Ar port#
+.Sh DESCRIPTION
+.Nm Lpd
+is the line printer daemon (spool area handler) and is normally invoked
+at boot time from the
+.Xr rc 8
+file. It makes a single pass through the
+.Xr printcap 5
+file to find out about the existing printers and
+prints any files left after a crash.
+It then uses the system calls
+.Xr listen 2
+and
+.Xr accept 2
+to receive requests to print files in the queue,
+transfer files to the spooling area, display the queue,
+or remove jobs from the queue. In each case, it forks a child to handle
+the request so the parent can continue to listen for more requests.
+.Pp
+Available options:
+.Bl -tag -width Ds
+.It Fl d
+Turn on
+.Dv SO_DEBUG
+on the Internet listening socket (see
+.Xr setsockopt 2 ) .
+.It Fl l
+The
+.Fl l
+flag causes
+.Nm
+to log valid requests received from the network.
+This can be useful
+for debugging purposes.
+.It Fl p
+The
+.Fl p
+flag causes
+.Nm
+not to open an Internet listening socket.
+.It Ar "port#"
+The Internet port number used to rendezvous
+with other processes is normally obtained with
+.Xr getservbyname 3
+but can be changed with the
+.Ar port#
+argument.
+.El
+.Pp
+Access control is provided by two means.
+First, all requests must come from
+one of the machines listed in the file
+.Pa /etc/hosts.equiv
+or
+.Pa /etc/hosts.lpd .
+Second, if the
+.Li rs
+capability is specified in the
+.Xr printcap
+entry for the printer being accessed,
+.Em lpr
+requests will only be honored for those users with accounts on the
+machine with the printer.
+.Pp
+The file
+.Em minfree
+in each spool directory contains the number of disk blocks to leave free
+so that the line printer queue won't completely fill the disk.
+The
+.Em minfree
+file can be edited with your favorite text editor.
+.Pp
+The daemon begins processing files
+after it has successfully set the lock for exclusive
+access (described a bit later),
+and scans the spool directory
+for files beginning with
+.Em cf .
+Lines in each
+.Em cf
+file specify files to be printed or non-printing actions to be
+performed. Each such line begins with a key character
+to specify what to do with the remainder of the line.
+.Bl -tag -width Ds
+.It J
+Job Name. String to be used for the job name on the burst page.
+.It C
+Classification. String to be used for the classification line
+on the burst page.
+.It L
+Literal. The line contains identification info from
+the password file and causes the banner page to be printed.
+.It T
+Title. String to be used as the title for
+.Xr pr 1 .
+.It H
+Host Name. Name of the machine where
+.Xr lpr
+was invoked.
+.It P
+Person. Login name of the person who invoked
+.Xr lpr .
+This is used to verify ownership by
+.Xr lprm .
+.It M
+Send mail to the specified user when the current print job completes.
+.It f
+Formatted File. Name of a file to print which is already formatted.
+.It l
+Like ``f'' but passes control characters and does not make page breaks.
+.It p
+Name of a file to print using
+.Xr pr 1
+as a filter.
+.It t
+Troff File. The file contains
+.Xr troff 1
+output (cat phototypesetter commands).
+.It n
+Ditroff File. The file contains device independent troff
+output.
+.It r
+DVI File. The file contains
+.Tn Tex l
+output
+DVI format from Standford.
+.It g
+Graph File. The file contains data produced by
+.Xr plot 3 .
+.It c
+Cifplot File.
+The file contains data produced by
+.Em cifplot .
+.It v
+The file contains a raster image.
+.It r
+The file contains text data with
+FORTRAN carriage control characters.
+.It \&1
+Troff Font R. Name of the font file to use instead of the default.
+.It \&2
+Troff Font I. Name of the font file to use instead of the default.
+.It \&3
+Troff Font B. Name of the font file to use instead of the default.
+.It \&4
+Troff Font S. Name of the font file to use instead of the default.
+.It W
+Width.
+Changes the page width (in characters) used by
+.Xr pr 1
+and the text filters.
+.It I
+Indent. The number of characters to indent the output by (in ASCII).
+.It U
+Unlink. Name of file to remove upon completion of printing.
+.It N
+File name. The name of the file which is being printed, or a blank
+for the standard input (when
+.Xr lpr
+is invoked in a pipeline).
+.It Z
+Locale. String to be used as the locale for
+.Xr pr 1 .
+.El
+.Pp
+If a file cannot be opened, a message will be logged via
+.Xr syslog 3
+using the
+.Em LOG_LPR
+facility.
+.Nm Lpd
+will try up to 20 times
+to reopen a file it expects to be there, after which it will
+skip the file to be printed.
+.Pp
+.Nm Lpd
+uses
+.Xr flock 2
+to provide exclusive access to the lock file and to prevent multiple
+daemons from becoming active simultaneously. If the daemon should be killed
+or die unexpectedly, the lock file need not be removed.
+The lock file is kept in a readable
+.Tn ASCII
+form
+and contains two lines.
+The first is the process id of the daemon and the second is the control
+file name of the current job being printed. The second line is updated to
+reflect the current status of
+.Nm
+for the programs
+.Xr lpq 1
+and
+.Xr lprm 1 .
+.Sh FILES
+.Bl -tag -width "/var/spool/*/minfree" -compact
+.It Pa /etc/printcap
+printer description file
+.It Pa /var/spool/*
+spool directories
+.It Pa /var/spool/*/minfree
+minimum free space to leave
+.It Pa /dev/lp*
+line printer devices
+.It Pa /var/run/printer
+socket for local requests
+.It Pa /etc/hosts.equiv
+lists machine names allowed printer access
+.It Pa /etc/hosts.lpd
+lists machine names allowed printer access,
+but not under same administrative control.
+.El
+.Sh SEE ALSO
+.Xr lpq 1 ,
+.Xr lpr 1 ,
+.Xr lprm 1 ,
+.Xr setsockopt 2 ,
+.Xr syslog 3 ,
+.Xr hosts.lpd 5 ,
+.Xr printcap 5 ,
+.Xr lpc 8 ,
+.Xr pac 8
+.Rs
+.%T "4.2 BSD Line Printer Spooler Manual"
+.Re
+.Sh HISTORY
+An
+.Nm
+daemon appeared in Version 6 AT&T UNIX.
diff --git a/usr.sbin/lpr/lpd/lpd.c b/usr.sbin/lpr/lpd/lpd.c
new file mode 100644
index 0000000..6d3a710
--- /dev/null
+++ b/usr.sbin/lpr/lpd/lpd.c
@@ -0,0 +1,657 @@
+/*
+ * Copyright (c) 1983, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+/*
+ * lpd -- line printer daemon.
+ *
+ * Listen for a connection and perform the requested operation.
+ * Operations are:
+ * \1printer\n
+ * check the queue for jobs and print any found.
+ * \2printer\n
+ * receive a job from another machine and queue it.
+ * \3printer [users ...] [jobs ...]\n
+ * return the current state of the queue (short form).
+ * \4printer [users ...] [jobs ...]\n
+ * return the current state of the queue (long form).
+ * \5printer person [users ...] [jobs ...]\n
+ * remove jobs from the queue.
+ *
+ * Strategy to maintain protected spooling area:
+ * 1. Spooling area is writable only by daemon and spooling group
+ * 2. lpr runs setuid root and setgrp spooling group; it uses
+ * root to access any file it wants (verifying things before
+ * with an access call) and group id to know how it should
+ * set up ownership of files in the spooling area.
+ * 3. Files in spooling area are owned by root, group spooling
+ * group, with mode 660.
+ * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to
+ * access files and printer. Users can't get to anything
+ * w/o help of lpq and lprm programs.
+ */
+
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <signal.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <ctype.h>
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+#include "extern.h"
+
+int lflag; /* log requests flag */
+int pflag; /* no incoming port flag */
+int from_remote; /* from remote socket */
+
+int main __P((int, char **));
+static void reapchild __P((int));
+static void mcleanup __P((int));
+static void doit __P((void));
+static void startup __P((void));
+static void chkhost __P((struct sockaddr_in *));
+static int ckqueue __P((struct printer *));
+static void usage __P((void));
+/* From rcmd.c: */
+int __ivaliduser __P((FILE *, u_long, const char *,
+ const char *));
+
+uid_t uid, euid;
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int f, funix, finet, options, fromlen, i, errs;
+ fd_set defreadfds;
+ struct sockaddr_un un, fromunix;
+ struct sockaddr_in sin, frominet;
+ int lfd;
+ sigset_t omask, nmask;
+ struct servent *sp, serv;
+
+ euid = geteuid(); /* these shouldn't be different */
+ uid = getuid();
+ options = 0;
+ gethostname(host, sizeof(host));
+
+ name = "lpd";
+
+ if (euid != 0)
+ errx(EX_NOPERM,"must run as root");
+
+ errs = 0;
+ while ((i = getopt(argc, argv, "dlp")) != -1)
+ switch (i) {
+ case 'd':
+ options |= SO_DEBUG;
+ break;
+ case 'l':
+ lflag++;
+ break;
+ case 'p':
+ pflag++;
+ break;
+ default:
+ errs++;
+ }
+ argc -= optind;
+ argv += optind;
+ if (errs)
+ usage();
+
+ if (argc == 1) {
+ if ((i = atoi(argv[0])) == 0)
+ usage();
+ if (i < 0 || i > USHRT_MAX)
+ errx(EX_USAGE, "port # %d is invalid", i);
+
+ serv.s_port = htons(i);
+ sp = &serv;
+ argc--;
+ } else {
+ sp = getservbyname("printer", "tcp");
+ if (sp == NULL)
+ errx(EX_OSFILE, "printer/tcp: unknown service");
+ }
+
+ if (argc != 0)
+ usage();
+
+ /*
+ * We run chkprintcap right away to catch any errors and blat them
+ * to stderr while we still have it open, rather than sending them
+ * to syslog and leaving the user wondering why lpd started and
+ * then stopped. There should probably be a command-line flag to
+ * ignore errors from chkprintcap.
+ */
+ {
+ pid_t pid;
+ int status;
+ pid = fork();
+ if (pid < 0) {
+ err(EX_OSERR, "cannot fork");
+ } else if (pid == 0) { /* child */
+ execl(_PATH_CHKPRINTCAP, _PATH_CHKPRINTCAP, (char *)0);
+ err(EX_OSERR, "cannot execute %s", _PATH_CHKPRINTCAP);
+ }
+ if (waitpid(pid, &status, 0) < 0) {
+ err(EX_OSERR, "cannot wait");
+ }
+ if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
+ errx(EX_OSFILE, "%d errors in printcap file, exiting",
+ WEXITSTATUS(status));
+ }
+
+#ifndef DEBUG
+ /*
+ * Set up standard environment by detaching from the parent.
+ */
+ daemon(0, 0);
+#endif
+
+ openlog("lpd", LOG_PID, LOG_LPR);
+ syslog(LOG_INFO, "restarted");
+ (void) umask(0);
+ /*
+ * NB: This depends on O_NONBLOCK semantics doing the right thing;
+ * i.e., applying only to the O_EXLOCK and not to the rest of the
+ * open/creation. As of 1997-12-02, this is the case for commonly-
+ * used filesystems. There are other places in this code which
+ * make the same assumption.
+ */
+ lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK,
+ LOCK_FILE_MODE);
+ if (lfd < 0) {
+ if (errno == EWOULDBLOCK) /* active deamon present */
+ exit(0);
+ syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
+ exit(1);
+ }
+ fcntl(lfd, F_SETFL, 0); /* turn off non-blocking mode */
+ ftruncate(lfd, 0);
+ /*
+ * write process id for others to know
+ */
+ sprintf(line, "%u\n", getpid());
+ f = strlen(line);
+ if (write(lfd, line, f) != f) {
+ syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
+ exit(1);
+ }
+ signal(SIGCHLD, reapchild);
+ /*
+ * Restart all the printers.
+ */
+ startup();
+ (void) unlink(_PATH_SOCKETNAME);
+ funix = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (funix < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ exit(1);
+ }
+
+ sigemptyset(&nmask);
+ sigaddset(&nmask, SIGHUP);
+ sigaddset(&nmask, SIGINT);
+ sigaddset(&nmask, SIGQUIT);
+ sigaddset(&nmask, SIGTERM);
+ sigprocmask(SIG_BLOCK, &nmask, &omask);
+
+ (void) umask(07);
+ signal(SIGHUP, mcleanup);
+ signal(SIGINT, mcleanup);
+ signal(SIGQUIT, mcleanup);
+ signal(SIGTERM, mcleanup);
+ memset(&un, 0, sizeof(un));
+ un.sun_family = AF_UNIX;
+ strcpy(un.sun_path, _PATH_SOCKETNAME);
+#ifndef SUN_LEN
+#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
+#endif
+ if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) {
+ syslog(LOG_ERR, "ubind: %m");
+ exit(1);
+ }
+ (void) umask(0);
+ sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
+ FD_ZERO(&defreadfds);
+ FD_SET(funix, &defreadfds);
+ listen(funix, 5);
+ if (pflag == 0) {
+ finet = socket(AF_INET, SOCK_STREAM, 0);
+ if (finet >= 0) {
+ i = 1;
+ if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR, &i,
+ sizeof i) < 0) {
+ syslog(LOG_ERR, "setsockopt(SO_REUSEADDR): %m");
+ mcleanup(0);
+ }
+ if (options & SO_DEBUG &&
+ setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) {
+ syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
+ mcleanup(0);
+ }
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = sp->s_port;
+ if (bind(finet, (struct sockaddr *)&sin,
+ sizeof(sin)) < 0) {
+ syslog(LOG_ERR, "bind: %m");
+ mcleanup(0);
+ }
+ FD_SET(finet, &defreadfds);
+ listen(finet, 5);
+ }
+ }
+ /*
+ * Main loop: accept, do a request, continue.
+ */
+ memset(&frominet, 0, sizeof(frominet));
+ memset(&fromunix, 0, sizeof(fromunix));
+ /*
+ * XXX - should be redone for multi-protocol
+ */
+ for (;;) {
+ int domain, nfds, s;
+ fd_set readfds;
+
+ FD_COPY(&defreadfds, &readfds);
+ nfds = select(20, &readfds, 0, 0, 0);
+ if (nfds <= 0) {
+ if (nfds < 0 && errno != EINTR)
+ syslog(LOG_WARNING, "select: %m");
+ continue;
+ }
+ if (FD_ISSET(funix, &readfds)) {
+ domain = AF_UNIX, fromlen = sizeof(fromunix);
+ s = accept(funix,
+ (struct sockaddr *)&fromunix, &fromlen);
+ } else if (pflag == 0) /* if (FD_ISSET(finet, &readfds)) */ {
+ domain = AF_INET, fromlen = sizeof(frominet);
+ s = accept(finet,
+ (struct sockaddr *)&frominet, &fromlen);
+ if (frominet.sin_port == htons(20)) {
+ close(s);
+ continue;
+ }
+ }
+ if (s < 0) {
+ if (errno != EINTR)
+ syslog(LOG_WARNING, "accept: %m");
+ continue;
+ }
+ if (fork() == 0) {
+ signal(SIGCHLD, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ (void) close(funix);
+ if (pflag == 0) {
+ (void) close(finet);
+ }
+ dup2(s, 1);
+ (void) close(s);
+ if (domain == AF_INET) {
+ from_remote = 1;
+ chkhost(&frominet);
+ } else
+ from_remote = 0;
+ doit();
+ exit(0);
+ }
+ (void) close(s);
+ }
+}
+
+static void
+reapchild(signo)
+ int signo;
+{
+ union wait status;
+
+ while (wait3((int *)&status, WNOHANG, 0) > 0)
+ ;
+}
+
+static void
+mcleanup(signo)
+ int signo;
+{
+ /*
+ * XXX syslog(3) is not signal-safe.
+ */
+ if (lflag) {
+ if (signo)
+ syslog(LOG_INFO, "exiting on signal %d", signo);
+ else
+ syslog(LOG_INFO, "exiting");
+ }
+ unlink(_PATH_SOCKETNAME);
+ exit(0);
+}
+
+/*
+ * Stuff for handling job specifications
+ */
+char *user[MAXUSERS]; /* users to process */
+int users; /* # of users in user array */
+int requ[MAXREQUESTS]; /* job number of spool entries */
+int requests; /* # of spool requests */
+char *person; /* name of person doing lprm */
+
+char fromb[MAXHOSTNAMELEN]; /* buffer for client's machine name */
+char cbuf[BUFSIZ]; /* command line buffer */
+char *cmdnames[] = {
+ "null",
+ "printjob",
+ "recvjob",
+ "displayq short",
+ "displayq long",
+ "rmjob"
+};
+
+static void
+doit()
+{
+ char *cp, *printer;
+ int n;
+ int status;
+ struct printer myprinter, *pp = &myprinter;
+
+ init_printer(&myprinter);
+
+ for (;;) {
+ cp = cbuf;
+ do {
+ if (cp >= &cbuf[sizeof(cbuf) - 1])
+ fatal(0, "Command line too long");
+ if ((n = read(1, cp, 1)) != 1) {
+ if (n < 0)
+ fatal(0, "Lost connection");
+ return;
+ }
+ } while (*cp++ != '\n');
+ *--cp = '\0';
+ cp = cbuf;
+ if (lflag) {
+ if (*cp >= '\1' && *cp <= '\5')
+ syslog(LOG_INFO, "%s requests %s %s",
+ from, cmdnames[(u_char)*cp], cp+1);
+ else
+ syslog(LOG_INFO, "bad request (%d) from %s",
+ *cp, from);
+ }
+ switch (*cp++) {
+ case CMD_CHECK_QUE: /* check the queue, print any jobs there */
+ startprinting(cp);
+ break;
+ case CMD_TAKE_THIS: /* receive files to be queued */
+ if (!from_remote) {
+ syslog(LOG_INFO, "illegal request (%d)", *cp);
+ exit(1);
+ }
+ recvjob(cp);
+ break;
+ case CMD_SHOWQ_SHORT: /* display the queue (short form) */
+ case CMD_SHOWQ_LONG: /* display the queue (long form) */
+ /* XXX - this all needs to be redone. */
+ printer = cp;
+ while (*cp) {
+ if (*cp != ' ') {
+ cp++;
+ continue;
+ }
+ *cp++ = '\0';
+ while (isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ if (isdigit(*cp)) {
+ if (requests >= MAXREQUESTS)
+ fatal(0, "Too many requests");
+ requ[requests++] = atoi(cp);
+ } else {
+ if (users >= MAXUSERS)
+ fatal(0, "Too many users");
+ user[users++] = cp;
+ }
+ }
+ status = getprintcap(printer, pp);
+ if (status < 0)
+ fatal(pp, pcaperr(status));
+ displayq(pp, cbuf[0] == CMD_SHOWQ_LONG);
+ exit(0);
+ case CMD_RMJOB: /* remove a job from the queue */
+ if (!from_remote) {
+ syslog(LOG_INFO, "illegal request (%d)", *cp);
+ exit(1);
+ }
+ printer = cp;
+ while (*cp && *cp != ' ')
+ cp++;
+ if (!*cp)
+ break;
+ *cp++ = '\0';
+ person = cp;
+ while (*cp) {
+ if (*cp != ' ') {
+ cp++;
+ continue;
+ }
+ *cp++ = '\0';
+ while (isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ if (isdigit(*cp)) {
+ if (requests >= MAXREQUESTS)
+ fatal(0, "Too many requests");
+ requ[requests++] = atoi(cp);
+ } else {
+ if (users >= MAXUSERS)
+ fatal(0, "Too many users");
+ user[users++] = cp;
+ }
+ }
+ rmjob(printer);
+ break;
+ }
+ fatal(0, "Illegal service request");
+ }
+}
+
+/*
+ * Make a pass through the printcap database and start printing any
+ * files left from the last time the machine went down.
+ */
+static void
+startup()
+{
+ int pid, status, more;
+ struct printer myprinter, *pp = &myprinter;
+
+ more = firstprinter(pp, &status);
+ if (status)
+ goto errloop;
+ while (more) {
+ if (ckqueue(pp) <= 0) {
+ goto next;
+ }
+ if (lflag)
+ syslog(LOG_INFO, "work for %s", pp->printer);
+ if ((pid = fork()) < 0) {
+ syslog(LOG_WARNING, "startup: cannot fork");
+ mcleanup(0);
+ }
+ if (pid == 0) {
+ lastprinter();
+ printjob(pp);
+ /* NOTREACHED */
+ }
+ do {
+next:
+ more = nextprinter(pp, &status);
+errloop:
+ if (status)
+ syslog(LOG_WARNING,
+ "printcap for %s has errors, skipping",
+ pp->printer ? pp->printer : "<???>");
+ } while (more && status);
+ }
+}
+
+/*
+ * Make sure there's some work to do before forking off a child
+ */
+static int
+ckqueue(pp)
+ struct printer *pp;
+{
+ register struct dirent *d;
+ DIR *dirp;
+ char *spooldir;
+
+ spooldir = pp->spool_dir;
+ if ((dirp = opendir(spooldir)) == NULL)
+ return (-1);
+ while ((d = readdir(dirp)) != NULL) {
+ if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
+ continue; /* daemon control files only */
+ closedir(dirp);
+ return (1); /* found something */
+ }
+ closedir(dirp);
+ return (0);
+}
+
+#define DUMMY ":nobody::"
+
+/*
+ * Check to see if the from host has access to the line printer.
+ */
+static void
+chkhost(f)
+ struct sockaddr_in *f;
+{
+ register struct hostent *hp;
+ register FILE *hostf;
+ int first = 1;
+ int good = 0;
+
+ /* Need real hostname for temporary filenames */
+ hp = gethostbyaddr((char *)&f->sin_addr,
+ sizeof(struct in_addr), f->sin_family);
+ if (hp == NULL)
+ fatal(0, "Host name for your address (%s) unknown",
+ inet_ntoa(f->sin_addr));
+
+ (void) strncpy(fromb, hp->h_name, sizeof(fromb) - 1);
+ fromb[sizeof(fromb) - 1] = '\0';
+ from = fromb;
+ strncpy(from_ip, inet_ntoa(f->sin_addr), MAXIPSTRLEN);
+ from_ip[sizeof(from_ip) - 1] = '\0';
+
+ /* Check for spoof, ala rlogind */
+ hp = gethostbyname(fromb);
+ if (!hp)
+ fatal(0, "hostname for your address (%s) unknown", from_ip);
+ for (; good == 0 && hp->h_addr_list[0] != NULL; hp->h_addr_list++) {
+ if (!bcmp(hp->h_addr_list[0], (caddr_t)&f->sin_addr,
+ sizeof(f->sin_addr)))
+ good = 1;
+ }
+ if (good == 0)
+ fatal(0, "address for your hostname (%s) not matched",
+ from_ip);
+
+ hostf = fopen(_PATH_HOSTSEQUIV, "r");
+again:
+ if (hostf) {
+ if (__ivaliduser(hostf, f->sin_addr.s_addr,
+ DUMMY, DUMMY) == 0) {
+ (void) fclose(hostf);
+ return;
+ }
+ (void) fclose(hostf);
+ }
+ if (first == 1) {
+ first = 0;
+ hostf = fopen(_PATH_HOSTSLPD, "r");
+ goto again;
+ }
+ fatal(0, "Your host does not have line printer access");
+ /*NOTREACHED*/
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "usage: lpd [-dlp] [port#]\n");
+ exit(EX_USAGE);
+}
diff --git a/usr.sbin/lpr/lpd/lpdchar.c b/usr.sbin/lpr/lpd/lpdchar.c
new file mode 100644
index 0000000..ba39a9f
--- /dev/null
+++ b/usr.sbin/lpr/lpd/lpdchar.c
@@ -0,0 +1,1071 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+/*
+static char sccsid[] = "@(#)lpdchar.c 8.1 (Berkeley) 6/6/93";
+*/
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+/*
+ * Character set for line printer daemon
+ */
+#include "lp.local.h"
+#include "extern.h"
+
+#define c_______ 0
+#define c______1 01
+#define c_____1_ 02
+#define c____1__ 04
+#define c____11_ 06
+#define c___1___ 010
+#define c___1__1 011
+#define c___1_1_ 012
+#define c___11__ 014
+#define c__1____ 020
+#define c__1__1_ 022
+#define c__1_1__ 024
+#define c__11___ 030
+#define c__111__ 034
+#define c__111_1 035
+#define c__1111_ 036
+#define c__11111 037
+#define c_1_____ 040
+#define c_1____1 041
+#define c_1___1_ 042
+#define c_1__1__ 044
+#define c_1_1___ 050
+#define c_1_1__1 051
+#define c_1_1_1_ 052
+#define c_11____ 060
+#define c_11_11_ 066
+#define c_111___ 070
+#define c_111__1 071
+#define c_111_1_ 072
+#define c_1111__ 074
+#define c_1111_1 075
+#define c_11111_ 076
+#define c_111111 077
+#define c1______ 0100
+#define c1_____1 0101
+#define c1____1_ 0102
+#define c1____11 0103
+#define c1___1__ 0104
+#define c1___1_1 0105
+#define c1___11_ 0106
+#define c1__1___ 0110
+#define c1__1__1 0111
+#define c1__11_1 0115
+#define c1__1111 0117
+#define c1_1____ 0120
+#define c1_1___1 0121
+#define c1_1_1_1 0125
+#define c1_1_11_ 0126
+#define c1_111__ 0134
+#define c1_1111_ 0136
+#define c11____1 0141
+#define c11___1_ 0142
+#define c11___11 0143
+#define c11_1___ 0150
+#define c11_1__1 0151
+#define c111_11_ 0166
+#define c1111___ 0170
+#define c11111__ 0174
+#define c111111_ 0176
+#define c1111111 0177
+
+char scnkey[][HEIGHT] = /* this is relatively easy to modify */
+ /* just look: */
+{
+ { c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______ }, /* */
+
+ { c__11___,
+ c__11___,
+ c__11___,
+ c__11___,
+ c__11___,
+ c_______,
+ c_______,
+ c__11___,
+ c__11___ }, /* ! */
+
+ { c_1__1__,
+ c_1__1__,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______ }, /* " */
+
+ { c_______,
+ c__1_1__,
+ c__1_1__,
+ c1111111,
+ c__1_1__,
+ c1111111,
+ c__1_1__,
+ c__1_1__,
+ c_______ }, /* # */
+
+ { c___1___,
+ c_11111_,
+ c1__1__1,
+ c1__1___,
+ c_11111_,
+ c___1__1,
+ c1__1__1,
+ c_11111_,
+ c___1___ }, /* $ */
+
+ { c_1_____,
+ c1_1___1,
+ c_1___1_,
+ c____1__,
+ c___1___,
+ c__1____,
+ c_1___1_,
+ c1___1_1,
+ c_____1_ }, /* % */
+
+ { c_11____,
+ c1__1___,
+ c1___1__,
+ c_1_1___,
+ c__1____,
+ c_1_1__1,
+ c1___11_,
+ c1___11_,
+ c_111__1 }, /* & */
+
+ { c___11__,
+ c___11__,
+ c___1___,
+ c__1____,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______ }, /* ' */
+
+ { c____1__,
+ c___1___,
+ c__1____,
+ c__1____,
+ c__1____,
+ c__1____,
+ c__1____,
+ c___1___,
+ c____1__ }, /* ( */
+
+ { c__1____,
+ c___1___,
+ c____1__,
+ c____1__,
+ c____1__,
+ c____1__,
+ c____1__,
+ c___1___,
+ c__1____ }, /* ) */
+
+ { c_______,
+ c___1___,
+ c1__1__1,
+ c_1_1_1_,
+ c__111__,
+ c_1_1_1_,
+ c1__1__1,
+ c___1___,
+ c_______ }, /* * */
+
+ { c_______,
+ c___1___,
+ c___1___,
+ c___1___,
+ c1111111,
+ c___1___,
+ c___1___,
+ c___1___,
+ c_______ }, /* + */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_______,
+ c__11___,
+ c__11___,
+ c__1____,
+ c_1_____,
+ c_______ }, /* , */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_______,
+ c1111111,
+ c_______,
+ c_______,
+ c_______,
+ c_______ }, /* - */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c__11___,
+ c__11___ }, /* . */
+
+ { c_______,
+ c______1,
+ c_____1_,
+ c____1__,
+ c___1___,
+ c__1____,
+ c_1_____,
+ c1______,
+ c_______ }, /* / */
+
+ { c_11111_,
+ c1_____1,
+ c1____11,
+ c1___1_1,
+ c1__1__1,
+ c1_1___1,
+ c11____1,
+ c1_____1,
+ c_11111_ }, /* 0 */
+
+ { c___1___,
+ c__11___,
+ c_1_1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c_11111_ }, /* 1 */
+
+ { c_11111_,
+ c1_____1,
+ c______1,
+ c_____1_,
+ c__111__,
+ c_1_____,
+ c1______,
+ c1______,
+ c1111111 }, /* 2 */
+
+ { c_11111_,
+ c1_____1,
+ c______1,
+ c______1,
+ c__1111_,
+ c______1,
+ c______1,
+ c1_____1,
+ c_11111_ }, /* 3 */
+
+ { c_____1_,
+ c____11_,
+ c___1_1_,
+ c__1__1_,
+ c_1___1_,
+ c1____1_,
+ c1111111,
+ c_____1_,
+ c_____1_ }, /* 4 */
+
+ { c1111111,
+ c1______,
+ c1______,
+ c11111__,
+ c_____1_,
+ c______1,
+ c______1,
+ c1____1_,
+ c_1111__ }, /* 5 */
+
+ { c__1111_,
+ c_1_____,
+ c1______,
+ c1______,
+ c1_1111_,
+ c11____1,
+ c1_____1,
+ c1_____1,
+ c_11111_ }, /* 6 */
+
+ { c1111111,
+ c1_____1,
+ c_____1_,
+ c____1__,
+ c___1___,
+ c__1____,
+ c__1____,
+ c__1____,
+ c__1____ }, /* 7 */
+
+ { c_11111_,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c_11111_,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c_11111_ }, /* 8 */
+
+ { c_11111_,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c_111111,
+ c______1,
+ c______1,
+ c1_____1,
+ c_1111__ }, /* 9 */
+
+ { c_______,
+ c_______,
+ c_______,
+ c__11___,
+ c__11___,
+ c_______,
+ c_______,
+ c__11___,
+ c__11___ }, /* : */
+
+
+ { c__11___,
+ c__11___,
+ c_______,
+ c_______,
+ c__11___,
+ c__11___,
+ c__1____,
+ c_1_____,
+ c_______ }, /* ; */
+
+ { c____1__,
+ c___1___,
+ c__1____,
+ c_1_____,
+ c1______,
+ c_1_____,
+ c__1____,
+ c___1___,
+ c____1__ }, /* < */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1111111,
+ c_______,
+ c1111111,
+ c_______,
+ c_______,
+ c_______ }, /* = */
+
+ { c__1____,
+ c___1___,
+ c____1__,
+ c_____1_,
+ c______1,
+ c_____1_,
+ c____1__,
+ c___1___,
+ c__1____ }, /* > */
+
+ { c__1111_,
+ c_1____1,
+ c_1____1,
+ c______1,
+ c____11_,
+ c___1___,
+ c___1___,
+ c_______,
+ c___1___ }, /* ? */
+
+ { c__1111_,
+ c_1____1,
+ c1__11_1,
+ c1_1_1_1,
+ c1_1_1_1,
+ c1_1111_,
+ c1______,
+ c_1____1,
+ c__1111_ }, /* @ */
+
+ { c__111__,
+ c_1___1_,
+ c1_____1,
+ c1_____1,
+ c1111111,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1 }, /* A */
+
+ { c111111_,
+ c_1____1,
+ c_1____1,
+ c_1____1,
+ c_11111_,
+ c_1____1,
+ c_1____1,
+ c_1____1,
+ c111111_ }, /* B */
+
+ { c__1111_,
+ c_1____1,
+ c1______,
+ c1______,
+ c1______,
+ c1______,
+ c1______,
+ c_1____1,
+ c__1111_ }, /* C */
+
+ { c11111__,
+ c_1___1_,
+ c_1____1,
+ c_1____1,
+ c_1____1,
+ c_1____1,
+ c_1____1,
+ c_1___1_,
+ c11111__ }, /* D */
+
+ { c1111111,
+ c1______,
+ c1______,
+ c1______,
+ c111111_,
+ c1______,
+ c1______,
+ c1______,
+ c1111111 }, /* E */
+
+ { c1111111,
+ c1______,
+ c1______,
+ c1______,
+ c111111_,
+ c1______,
+ c1______,
+ c1______,
+ c1______ }, /* F */
+
+ { c__1111_,
+ c_1____1,
+ c1______,
+ c1______,
+ c1______,
+ c1__1111,
+ c1_____1,
+ c_1____1,
+ c__1111_ }, /* G */
+
+ { c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1111111,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1 }, /* H */
+
+ { c_11111_,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c_11111_ }, /* I */
+
+ { c__11111,
+ c____1__,
+ c____1__,
+ c____1__,
+ c____1__,
+ c____1__,
+ c____1__,
+ c1___1__,
+ c_111___ }, /* J */
+
+ { c1_____1,
+ c1____1_,
+ c1___1__,
+ c1__1___,
+ c1_1____,
+ c11_1___,
+ c1___1__,
+ c1____1_,
+ c1_____1 }, /* K */
+
+ { c1______,
+ c1______,
+ c1______,
+ c1______,
+ c1______,
+ c1______,
+ c1______,
+ c1______,
+ c1111111 }, /* L */
+
+ { c1_____1,
+ c11___11,
+ c1_1_1_1,
+ c1__1__1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1 }, /* M */
+
+ { c1_____1,
+ c11____1,
+ c1_1___1,
+ c1__1__1,
+ c1___1_1,
+ c1____11,
+ c1_____1,
+ c1_____1,
+ c1_____1 }, /* N */
+
+ { c__111__,
+ c_1___1_,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c_1___1_,
+ c__111__ }, /* O */
+
+ { c111111_,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c111111_,
+ c1______,
+ c1______,
+ c1______,
+ c1______ }, /* P */
+
+ { c__111__,
+ c_1___1_,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1__1__1,
+ c1___1_1,
+ c_1___1_,
+ c__111_1 }, /* Q */
+
+ { c111111_,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c111111_,
+ c1__1___,
+ c1___1__,
+ c1____1_,
+ c1_____1 }, /* R */
+
+ { c_11111_,
+ c1_____1,
+ c1______,
+ c1______,
+ c_11111_,
+ c______1,
+ c______1,
+ c1_____1,
+ c_11111_ }, /* S */
+
+ { c1111111,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___ }, /* T */
+
+ { c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c_11111_ }, /* U */
+
+ { c1_____1,
+ c1_____1,
+ c1_____1,
+ c_1___1_,
+ c_1___1_,
+ c__1_1__,
+ c__1_1__,
+ c___1___,
+ c___1___ }, /* V */
+
+ { c1_____1,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c1__1__1,
+ c1__1__1,
+ c1_1_1_1,
+ c11___11,
+ c1_____1 }, /* W */
+
+ { c1_____1,
+ c1_____1,
+ c_1___1_,
+ c__1_1__,
+ c___1___,
+ c__1_1__,
+ c_1___1_,
+ c1_____1,
+ c1_____1 }, /* X */
+
+ { c1_____1,
+ c1_____1,
+ c_1___1_,
+ c__1_1__,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___ }, /* Y */
+
+ { c1111111,
+ c______1,
+ c_____1_,
+ c____1__,
+ c___1___,
+ c__1____,
+ c_1_____,
+ c1______,
+ c1111111 }, /* Z */
+
+ { c_1111__,
+ c_1_____,
+ c_1_____,
+ c_1_____,
+ c_1_____,
+ c_1_____,
+ c_1_____,
+ c_1_____,
+ c_1111__ }, /* [ */
+
+ { c_______,
+ c1______,
+ c_1_____,
+ c__1____,
+ c___1___,
+ c____1__,
+ c_____1_,
+ c______1,
+ c_______ }, /* \ */
+
+ { c__1111_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c__1111_ }, /* ] */
+
+ { c___1___,
+ c__1_1__,
+ c_1___1_,
+ c1_____1,
+ c_______,
+ c_______,
+ c_______,
+ c_______ }, /* ^ */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c1111111,
+ c_______ }, /* _ */
+
+ { c__11___,
+ c__11___,
+ c___1___,
+ c____1__,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______ }, /* ` */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_1111__,
+ c_____1_,
+ c_11111_,
+ c1_____1,
+ c1____11,
+ c_1111_1 }, /* a */
+
+ { c1______,
+ c1______,
+ c1______,
+ c1_111__,
+ c11___1_,
+ c1_____1,
+ c1_____1,
+ c11___1_,
+ c1_111__ }, /* b */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_1111__,
+ c1____1_,
+ c1______,
+ c1______,
+ c1____1_,
+ c_1111__ }, /* c */
+
+ { c_____1_,
+ c_____1_,
+ c_____1_,
+ c_111_1_,
+ c1___11_,
+ c1____1_,
+ c1____1_,
+ c1___11_,
+ c_111_1_ }, /* d */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_1111__,
+ c1____1_,
+ c111111_,
+ c1______,
+ c1____1_,
+ c_1111__ }, /* e */
+
+ { c___11__,
+ c__1__1_,
+ c__1____,
+ c__1____,
+ c11111__,
+ c__1____,
+ c__1____,
+ c__1____,
+ c__1____ }, /* f */
+
+ { c_111_1_,
+ c1___11_,
+ c1____1_,
+ c1____1_,
+ c1___11_,
+ c_111_1_,
+ c_____1_,
+ c1____1_,
+ c_1111__ }, /* g */
+
+ { c1______,
+ c1______,
+ c1______,
+ c1_111__,
+ c11___1_,
+ c1____1_,
+ c1____1_,
+ c1____1_,
+ c1____1_ }, /* h */
+
+ { c_______,
+ c___1___,
+ c_______,
+ c__11___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c__111__ }, /* i */
+
+ { c____11_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_____1_,
+ c_1___1_,
+ c__111__ }, /* j */
+
+ { c1______,
+ c1______,
+ c1______,
+ c1___1__,
+ c1__1___,
+ c1_1____,
+ c11_1___,
+ c1___1__,
+ c1____1_ }, /* k */
+
+ { c__11___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c__111__ }, /* l */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1_1_11_,
+ c11_1__1,
+ c1__1__1,
+ c1__1__1,
+ c1__1__1,
+ c1__1__1 }, /* m */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1_111__,
+ c11___1_,
+ c1____1_,
+ c1____1_,
+ c1____1_,
+ c1____1_ }, /* n */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_1111__,
+ c1____1_,
+ c1____1_,
+ c1____1_,
+ c1____1_,
+ c_1111__ }, /* o */
+
+ { c1_111__,
+ c11___1_,
+ c1____1_,
+ c1____1_,
+ c11___1_,
+ c1_111__,
+ c1______,
+ c1______,
+ c1______ }, /* p */
+
+ { c_111_1_,
+ c1___11_,
+ c1____1_,
+ c1____1_,
+ c1___11_,
+ c_111_1_,
+ c_____1_,
+ c_____1_,
+ c_____1_ }, /* q */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1_111__,
+ c11___1_,
+ c1______,
+ c1______,
+ c1______,
+ c1______ }, /* r */
+
+ { c_______,
+ c_______,
+ c_______,
+ c_1111__,
+ c1____1_,
+ c_11____,
+ c___11__,
+ c1____1_,
+ c_1111__ }, /* s */
+
+ { c_______,
+ c__1____,
+ c__1____,
+ c11111__,
+ c__1____,
+ c__1____,
+ c__1____,
+ c__1__1_,
+ c___11__ }, /* t */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1____1_,
+ c1____1_,
+ c1____1_,
+ c1____1_,
+ c1___11_,
+ c_111_1_ }, /* u */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1_____1,
+ c1_____1,
+ c1_____1,
+ c_1___1_,
+ c__1_1__,
+ c___1___ }, /* v */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1_____1,
+ c1__1__1,
+ c1__1__1,
+ c1__1__1,
+ c1__1__1,
+ c_11_11_ }, /* w */
+
+ { c_______,
+ c_______,
+ c_______,
+ c1____1_,
+ c_1__1__,
+ c__11___,
+ c__11___,
+ c_1__1__,
+ c1____1_ }, /* x */
+
+ { c1____1_,
+ c1____1_,
+ c1____1_,
+ c1____1_,
+ c1___11_,
+ c_111_1_,
+ c_____1_,
+ c1____1_,
+ c_1111__ }, /* y */
+
+ { c_______,
+ c_______,
+ c_______,
+ c111111_,
+ c____1__,
+ c___1___,
+ c__1____,
+ c_1_____,
+ c111111_ }, /* z */
+
+ { c___11__,
+ c__1____,
+ c__1____,
+ c__1____,
+ c_1_____,
+ c__1____,
+ c__1____,
+ c__1____,
+ c___11__ }, /* } */
+
+ { c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___,
+ c___1___ }, /* | */
+
+ { c__11___,
+ c____1__,
+ c____1__,
+ c____1__,
+ c_____1_,
+ c____1__,
+ c____1__,
+ c____1__,
+ c__11___ }, /* } */
+
+ { c_11____,
+ c1__1__1,
+ c____11_,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______,
+ c_______ }, /* ~ */
+
+ { c_1__1__,
+ c1__1__1,
+ c__1__1_,
+ c_1__1__,
+ c1__1__1,
+ c__1__1_,
+ c_1__1__,
+ c1__1__1,
+ c__1__1_ } /* rub-out */
+};
diff --git a/usr.sbin/lpr/lpd/modes.c b/usr.sbin/lpr/lpd/modes.c
new file mode 100644
index 0000000..4bb2ea0
--- /dev/null
+++ b/usr.sbin/lpr/lpd/modes.c
@@ -0,0 +1,236 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+/*
+static char sccsid[] = "@(#)modes.c 8.3 (Berkeley) 4/2/94";
+*/
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <stddef.h>
+#include <string.h>
+#include <termios.h>
+#include "lp.local.h"
+#include "extern.h"
+
+struct modes {
+ char *name;
+ long set;
+ long unset;
+};
+
+/*
+ * The code in optlist() depends on minus options following regular
+ * options, i.e. "foo" must immediately precede "-foo".
+ */
+struct modes cmodes[] = {
+ { "cs5", CS5, CSIZE },
+ { "cs6", CS6, CSIZE },
+ { "cs7", CS7, CSIZE },
+ { "cs8", CS8, CSIZE },
+ { "cstopb", CSTOPB, 0 },
+ { "-cstopb", 0, CSTOPB },
+ { "cread", CREAD, 0 },
+ { "-cread", 0, CREAD },
+ { "parenb", PARENB, 0 },
+ { "-parenb", 0, PARENB },
+ { "parodd", PARODD, 0 },
+ { "-parodd", 0, PARODD },
+ { "parity", PARENB | CS7, PARODD | CSIZE },
+ { "-parity", CS8, PARODD | PARENB | CSIZE },
+ { "evenp", PARENB | CS7, PARODD | CSIZE },
+ { "-evenp", CS8, PARODD | PARENB | CSIZE },
+ { "oddp", PARENB | CS7 | PARODD, CSIZE },
+ { "-oddp", CS8, PARODD | PARENB | CSIZE },
+ { "pass8", CS8, PARODD | PARENB | CSIZE },
+ { "-pass8", PARENB | CS7, PARODD | CSIZE },
+ { "hupcl", HUPCL, 0 },
+ { "-hupcl", 0, HUPCL },
+ { "hup", HUPCL, 0 },
+ { "-hup", 0, HUPCL },
+ { "clocal", CLOCAL, 0 },
+ { "-clocal", 0, CLOCAL },
+ { "crtscts", CRTSCTS, 0 },
+ { "-crtscts", 0, CRTSCTS },
+ { "ctsflow", CCTS_OFLOW, 0 },
+ { "-ctsflow", 0, CCTS_OFLOW },
+ { "dsrflow", CDSR_OFLOW, 0 },
+ { "-dsrflow", 0, CDSR_OFLOW },
+ { "dtrflow", CDTR_IFLOW, 0 },
+ { "-dtrflow", 0, CDTR_IFLOW },
+ { "rtsflow", CRTS_IFLOW, 0 },
+ { "-rtsflow", 0, CRTS_IFLOW },
+ { "mdmbuf", MDMBUF, 0 },
+ { "-mdmbuf", 0, MDMBUF },
+ { NULL },
+};
+
+struct modes imodes[] = {
+ { "ignbrk", IGNBRK, 0 },
+ { "-ignbrk", 0, IGNBRK },
+ { "brkint", BRKINT, 0 },
+ { "-brkint", 0, BRKINT },
+ { "ignpar", IGNPAR, 0 },
+ { "-ignpar", 0, IGNPAR },
+ { "parmrk", PARMRK, 0 },
+ { "-parmrk", 0, PARMRK },
+ { "inpck", INPCK, 0 },
+ { "-inpck", 0, INPCK },
+ { "istrip", ISTRIP, 0 },
+ { "-istrip", 0, ISTRIP },
+ { "inlcr", INLCR, 0 },
+ { "-inlcr", 0, INLCR },
+ { "igncr", IGNCR, 0 },
+ { "-igncr", 0, IGNCR },
+ { "icrnl", ICRNL, 0 },
+ { "-icrnl", 0, ICRNL },
+ { "ixon", IXON, 0 },
+ { "-ixon", 0, IXON },
+ { "flow", IXON, 0 },
+ { "-flow", 0, IXON },
+ { "ixoff", IXOFF, 0 },
+ { "-ixoff", 0, IXOFF },
+ { "tandem", IXOFF, 0 },
+ { "-tandem", 0, IXOFF },
+ { "ixany", IXANY, 0 },
+ { "-ixany", 0, IXANY },
+ { "decctlq", 0, IXANY },
+ { "-decctlq", IXANY, 0 },
+ { "imaxbel", IMAXBEL, 0 },
+ { "-imaxbel", 0, IMAXBEL },
+ { NULL },
+};
+
+struct modes lmodes[] = {
+ { "echo", ECHO, 0 },
+ { "-echo", 0, ECHO },
+ { "echoe", ECHOE, 0 },
+ { "-echoe", 0, ECHOE },
+ { "crterase", ECHOE, 0 },
+ { "-crterase", 0, ECHOE },
+ { "crtbs", ECHOE, 0 }, /* crtbs not supported, close enough */
+ { "-crtbs", 0, ECHOE },
+ { "echok", ECHOK, 0 },
+ { "-echok", 0, ECHOK },
+ { "echoke", ECHOKE, 0 },
+ { "-echoke", 0, ECHOKE },
+ { "crtkill", ECHOKE, 0 },
+ { "-crtkill", 0, ECHOKE },
+ { "altwerase", ALTWERASE, 0 },
+ { "-altwerase", 0, ALTWERASE },
+ { "iexten", IEXTEN, 0 },
+ { "-iexten", 0, IEXTEN },
+ { "echonl", ECHONL, 0 },
+ { "-echonl", 0, ECHONL },
+ { "echoctl", ECHOCTL, 0 },
+ { "-echoctl", 0, ECHOCTL },
+ { "ctlecho", ECHOCTL, 0 },
+ { "-ctlecho", 0, ECHOCTL },
+ { "echoprt", ECHOPRT, 0 },
+ { "-echoprt", 0, ECHOPRT },
+ { "prterase", ECHOPRT, 0 },
+ { "-prterase", 0, ECHOPRT },
+ { "isig", ISIG, 0 },
+ { "-isig", 0, ISIG },
+ { "icanon", ICANON, 0 },
+ { "-icanon", 0, ICANON },
+ { "noflsh", NOFLSH, 0 },
+ { "-noflsh", 0, NOFLSH },
+ { "tostop", TOSTOP, 0 },
+ { "-tostop", 0, TOSTOP },
+ { "flusho", FLUSHO, 0 },
+ { "-flusho", 0, FLUSHO },
+ { "pendin", PENDIN, 0 },
+ { "-pendin", 0, PENDIN },
+ { "crt", ECHOE|ECHOKE|ECHOCTL, ECHOK|ECHOPRT },
+ { "-crt", ECHOK, ECHOE|ECHOKE|ECHOCTL },
+ { "newcrt", ECHOE|ECHOKE|ECHOCTL, ECHOK|ECHOPRT },
+ { "-newcrt", ECHOK, ECHOE|ECHOKE|ECHOCTL },
+ { "nokerninfo", NOKERNINFO, 0 },
+ { "-nokerninfo",0, NOKERNINFO },
+ { "kerninfo", 0, NOKERNINFO },
+ { "-kerninfo", NOKERNINFO, 0 },
+ { NULL },
+};
+
+struct modes omodes[] = {
+ { "opost", OPOST, 0 },
+ { "-opost", 0, OPOST },
+ { "litout", 0, OPOST },
+ { "-litout", OPOST, 0 },
+ { "onlcr", ONLCR, 0 },
+ { "-onlcr", 0, ONLCR },
+ { "tabs", 0, OXTABS }, /* "preserve" tabs */
+ { "-tabs", OXTABS, 0 },
+ { "oxtabs", OXTABS, 0 },
+ { "-oxtabs", 0, OXTABS },
+ { NULL },
+};
+
+#define CHK(name, s) (*name == s[0] && !strcmp(name, s))
+
+int
+msearch(str, ip)
+ char *str;
+ struct termios *ip;
+{
+ struct modes *mp;
+
+ for (mp = cmodes; mp->name; ++mp)
+ if (CHK(str, mp->name)) {
+ ip->c_cflag &= ~mp->unset;
+ ip->c_cflag |= mp->set;
+ return (1);
+ }
+ for (mp = imodes; mp->name; ++mp)
+ if (CHK(str, mp->name)) {
+ ip->c_iflag &= ~mp->unset;
+ ip->c_iflag |= mp->set;
+ return (1);
+ }
+ for (mp = lmodes; mp->name; ++mp)
+ if (CHK(str, mp->name)) {
+ ip->c_lflag &= ~mp->unset;
+ ip->c_lflag |= mp->set;
+ return (1);
+ }
+ for (mp = omodes; mp->name; ++mp)
+ if (CHK(str, mp->name)) {
+ ip->c_oflag &= ~mp->unset;
+ ip->c_oflag |= mp->set;
+ return (1);
+ }
+ return (0);
+}
diff --git a/usr.sbin/lpr/lpd/printjob.c b/usr.sbin/lpr/lpd/printjob.c
new file mode 100644
index 0000000..7fe4f04
--- /dev/null
+++ b/usr.sbin/lpr/lpd/printjob.c
@@ -0,0 +1,1694 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*
+static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95";
+*/
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+
+/*
+ * printjob -- print jobs in the queue.
+ *
+ * NOTE: the lock file is used to pass information to lpq and lprm.
+ * it does not need to be removed because file locks are dynamic.
+ */
+
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <pwd.h>
+#include <unistd.h>
+#include <signal.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <time.h>
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+#include "extern.h"
+
+#define DORETURN 0 /* absorb fork error */
+#define DOABORT 1 /* abort if dofork fails */
+
+/*
+ * Error tokens
+ */
+#define REPRINT -2
+#define ERROR -1
+#define OK 0
+#define FATALERR 1
+#define NOACCT 2
+#define FILTERERR 3
+#define ACCESS 4
+
+static dev_t fdev; /* device of file pointed to by symlink */
+static ino_t fino; /* inode of file pointed to by symlink */
+static FILE *cfp; /* control file */
+static int child; /* id of any filters */
+static int job_dfcnt; /* count of datafiles in current user job */
+static int lfd; /* lock file descriptor */
+static int ofd; /* output filter file descriptor */
+static int ofilter; /* id of output filter, if any */
+static int tfd = -1; /* output filter temp file output */
+static int pfd; /* prstatic inter file descriptor */
+static int pid; /* pid of lpd process */
+static int prchild; /* id of pr process */
+static char title[80]; /* ``pr'' title */
+static char locale[80]; /* ``pr'' locale */
+
+static char class[32]; /* classification field */
+static char fromhost[MAXHOSTNAMELEN]; /* user's host machine */
+ /* indentation size in static characters */
+static char indent[10] = "-i0";
+static char jobname[100]; /* job or file name */
+static char length[10] = "-l"; /* page length in lines */
+static char logname[32]; /* user's login name */
+static char pxlength[10] = "-y"; /* page length in pixels */
+static char pxwidth[10] = "-x"; /* page width in pixels */
+static char tempfile[] = "errsXXXXXX"; /* file name for filter errors */
+static char width[10] = "-w"; /* page width in static characters */
+#define TFILENAME "fltXXXXXX"
+static char tfile[] = TFILENAME; /* file name for filter output */
+
+static void abortpr __P((int));
+static void alarmhandler __P((int));
+static void banner __P((struct printer *pp, char *name1, char *name2));
+static int dofork __P((const struct printer *pp, int action));
+static int dropit __P((int));
+static void init __P((struct printer *pp));
+static void openpr __P((const struct printer *pp));
+static void opennet __P((const struct printer *pp));
+static void opentty __P((const struct printer *pp));
+static void openrem __P((const struct printer *pp));
+static int print __P((struct printer *pp, int format, char *file));
+static int printit __P((struct printer *pp, char *file));
+static void pstatus __P((const struct printer *, const char *, ...));
+static char response __P((const struct printer *pp));
+static void scan_out __P((struct printer *pp, int scfd, char *scsp,
+ int dlm));
+static char *scnline __P((int, char *, int));
+static int sendfile __P((struct printer *pp, int type, char *file,
+ int format));
+static int sendit __P((struct printer *pp, char *file));
+static void sendmail __P((struct printer *pp, char *user, int bombed));
+static void setty __P((const struct printer *pp));
+
+void
+printjob(pp)
+ struct printer *pp;
+{
+ struct stat stb;
+ register struct queue *q, **qp;
+ struct queue **queue;
+ register int i, nitems;
+ off_t pidoff;
+ int errcnt, count = 0;
+
+ init(pp); /* set up capabilities */
+ (void) write(1, "", 1); /* ack that daemon is started */
+ (void) close(2); /* set up log file */
+ if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) {
+ syslog(LOG_ERR, "%s: %m", pp->log_file);
+ (void) open(_PATH_DEVNULL, O_WRONLY);
+ }
+ setgid(getegid());
+ pid = getpid(); /* for use with lprm */
+ setpgrp(0, pid);
+ signal(SIGHUP, abortpr);
+ signal(SIGINT, abortpr);
+ signal(SIGQUIT, abortpr);
+ signal(SIGTERM, abortpr);
+
+ (void) mktemp(tempfile);
+
+ /*
+ * uses short form file names
+ */
+ if (chdir(pp->spool_dir) < 0) {
+ syslog(LOG_ERR, "%s: %m", pp->spool_dir);
+ exit(1);
+ }
+ if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS))
+ exit(0); /* printing disabled */
+ lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK,
+ LOCK_FILE_MODE);
+ if (lfd < 0) {
+ if (errno == EWOULDBLOCK) /* active daemon present */
+ exit(0);
+ syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file);
+ exit(1);
+ }
+ /* turn off non-blocking mode (was turned on for lock effects only) */
+ if (fcntl(lfd, F_SETFL, 0) < 0) {
+ syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file);
+ exit(1);
+ }
+ ftruncate(lfd, 0);
+ /*
+ * write process id for others to know
+ */
+ sprintf(line, "%u\n", pid);
+ pidoff = i = strlen(line);
+ if (write(lfd, line, i) != i) {
+ syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file);
+ exit(1);
+ }
+ /*
+ * search the spool directory for work and sort by queue order.
+ */
+ if ((nitems = getq(pp, &queue)) < 0) {
+ syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
+ pp->spool_dir);
+ exit(1);
+ }
+ if (nitems == 0) /* no work to do */
+ exit(0);
+ if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */
+ if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0)
+ syslog(LOG_ERR, "%s: %s: %m", pp->printer,
+ pp->lock_file);
+ }
+ openpr(pp); /* open printer or remote */
+again:
+ /*
+ * we found something to do now do it --
+ * write the name of the current control file into the lock file
+ * so the spool queue program can tell what we're working on
+ */
+ for (qp = queue; nitems--; free((char *) q)) {
+ q = *qp++;
+ if (stat(q->q_name, &stb) < 0)
+ continue;
+ errcnt = 0;
+ restart:
+ (void) lseek(lfd, pidoff, 0);
+ (void) snprintf(line, sizeof(line), "%s\n", q->q_name);
+ i = strlen(line);
+ if (write(lfd, line, i) != i)
+ syslog(LOG_ERR, "%s: %s: %m", pp->printer,
+ pp->lock_file);
+ if (!pp->remote)
+ i = printit(pp, q->q_name);
+ else
+ i = sendit(pp, q->q_name);
+ /*
+ * Check to see if we are supposed to stop printing or
+ * if we are to rebuild the queue.
+ */
+ if (fstat(lfd, &stb) == 0) {
+ /* stop printing before starting next job? */
+ if (stb.st_mode & LFM_PRINT_DIS)
+ goto done;
+ /* rebuild queue (after lpc topq) */
+ if (stb.st_mode & LFM_RESET_QUE) {
+ for (free(q); nitems--; free(q))
+ q = *qp++;
+ if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE)
+ < 0)
+ syslog(LOG_WARNING, "%s: %s: %m",
+ pp->printer, pp->lock_file);
+ break;
+ }
+ }
+ if (i == OK) /* file ok and printed */
+ count++;
+ else if (i == REPRINT && ++errcnt < 5) {
+ /* try reprinting the job */
+ syslog(LOG_INFO, "restarting %s", pp->printer);
+ if (ofilter > 0) {
+ kill(ofilter, SIGCONT); /* to be sure */
+ (void) close(ofd);
+ while ((i = wait(NULL)) > 0 && i != ofilter)
+ ;
+ ofilter = 0;
+ }
+ (void) close(pfd); /* close printer */
+ if (ftruncate(lfd, pidoff) < 0)
+ syslog(LOG_WARNING, "%s: %s: %m",
+ pp->printer, pp->lock_file);
+ openpr(pp); /* try to reopen printer */
+ goto restart;
+ } else {
+ syslog(LOG_WARNING, "%s: job could not be %s (%s)",
+ pp->printer,
+ pp->remote ? "sent to remote host" : "printed",
+ q->q_name);
+ if (i == REPRINT) {
+ /* ensure we don't attempt this job again */
+ (void) unlink(q->q_name);
+ q->q_name[0] = 'd';
+ (void) unlink(q->q_name);
+ if (logname[0])
+ sendmail(pp, logname, FATALERR);
+ }
+ }
+ }
+ free(queue);
+ /*
+ * search the spool directory for more work.
+ */
+ if ((nitems = getq(pp, &queue)) < 0) {
+ syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
+ pp->spool_dir);
+ exit(1);
+ }
+ if (nitems == 0) { /* no more work to do */
+ done:
+ if (count > 0) { /* Files actually printed */
+ if (!pp->no_formfeed && !pp->tof)
+ (void) write(ofd, pp->form_feed,
+ strlen(pp->form_feed));
+ if (pp->trailer != NULL) /* output trailer */
+ (void) write(ofd, pp->trailer,
+ strlen(pp->trailer));
+ }
+ (void) close(ofd);
+ (void) wait(NULL);
+ (void) unlink(tempfile);
+ exit(0);
+ }
+ goto again;
+}
+
+char fonts[4][50]; /* fonts for troff */
+
+char ifonts[4][40] = {
+ _PATH_VFONTR,
+ _PATH_VFONTI,
+ _PATH_VFONTB,
+ _PATH_VFONTS,
+};
+
+/*
+ * The remaining part is the reading of the control file (cf)
+ * and performing the various actions.
+ */
+static int
+printit(pp, file)
+ struct printer *pp;
+ char *file;
+{
+ register int i;
+ char *cp;
+ int bombed = OK;
+
+ /*
+ * open control file; ignore if no longer there.
+ */
+ if ((cfp = fopen(file, "r")) == NULL) {
+ syslog(LOG_INFO, "%s: %s: %m", pp->printer, file);
+ return(OK);
+ }
+ /*
+ * Reset troff fonts.
+ */
+ for (i = 0; i < 4; i++)
+ strcpy(fonts[i], ifonts[i]);
+ sprintf(&width[2], "%ld", pp->page_width);
+ strcpy(indent+2, "0");
+
+ /* initialize job-specific count of datafiles processed */
+ job_dfcnt = 0;
+
+ /*
+ * read the control file for work to do
+ *
+ * file format -- first character in the line is a command
+ * rest of the line is the argument.
+ * valid commands are:
+ *
+ * S -- "stat info" for symbolic link protection
+ * J -- "job name" on banner page
+ * C -- "class name" on banner page
+ * L -- "literal" user's name to print on banner
+ * T -- "title" for pr
+ * H -- "host name" of machine where lpr was done
+ * P -- "person" user's login name
+ * I -- "indent" amount to indent output
+ * R -- laser dpi "resolution"
+ * f -- "file name" name of text file to print
+ * l -- "file name" text file with control chars
+ * p -- "file name" text file to print with pr(1)
+ * t -- "file name" troff(1) file to print
+ * n -- "file name" ditroff(1) file to print
+ * d -- "file name" dvi file to print
+ * g -- "file name" plot(1G) file to print
+ * v -- "file name" plain raster file to print
+ * c -- "file name" cifplot file to print
+ * 1 -- "R font file" for troff
+ * 2 -- "I font file" for troff
+ * 3 -- "B font file" for troff
+ * 4 -- "S font file" for troff
+ * N -- "name" of file (used by lpq)
+ * U -- "unlink" name of file to remove
+ * (after we print it. (Pass 2 only)).
+ * M -- "mail" to user when done printing
+ * Z -- "locale" for pr
+ *
+ * getline reads a line and expands tabs to blanks
+ */
+
+ /* pass 1 */
+
+ while (getline(cfp))
+ switch (line[0]) {
+ case 'H':
+ strncpy(fromhost, line+1, sizeof(fromhost) - 1);
+ fromhost[sizeof(fromhost) - 1] = '\0';
+ if (class[0] == '\0') {
+ strncpy(class, line+1, sizeof(class) - 1);
+ class[sizeof(class) - 1] = '\0';
+ }
+ continue;
+
+ case 'P':
+ strncpy(logname, line+1, sizeof(logname) - 1);
+ logname[sizeof(logname) - 1] = '\0';
+ if (pp->restricted) { /* restricted */
+ if (getpwnam(logname) == NULL) {
+ bombed = NOACCT;
+ sendmail(pp, line+1, bombed);
+ goto pass2;
+ }
+ }
+ continue;
+
+ case 'S':
+ cp = line+1;
+ i = 0;
+ while (*cp >= '0' && *cp <= '9')
+ i = i * 10 + (*cp++ - '0');
+ fdev = i;
+ cp++;
+ i = 0;
+ while (*cp >= '0' && *cp <= '9')
+ i = i * 10 + (*cp++ - '0');
+ fino = i;
+ continue;
+
+ case 'J':
+ if (line[1] != '\0') {
+ strncpy(jobname, line+1, sizeof(jobname) - 1);
+ jobname[sizeof(jobname) - 1] = '\0';
+ } else
+ strcpy(jobname, " ");
+ continue;
+
+ case 'C':
+ if (line[1] != '\0')
+ strncpy(class, line+1, sizeof(class) - 1);
+ else if (class[0] == '\0')
+ gethostname(class, sizeof(class));
+ class[sizeof(class) - 1] = '\0';
+ continue;
+
+ case 'T': /* header title for pr */
+ strncpy(title, line+1, sizeof(title) - 1);
+ title[sizeof(title) - 1] = '\0';
+ continue;
+
+ case 'L': /* identification line */
+ if (!pp->no_header && !pp->header_last)
+ banner(pp, line+1, jobname);
+ continue;
+
+ case '1': /* troff fonts */
+ case '2':
+ case '3':
+ case '4':
+ if (line[1] != '\0') {
+ strncpy(fonts[line[0]-'1'], line+1,
+ 50-1);
+ fonts[line[0]-'1'][50-1] = '\0';
+ }
+ continue;
+
+ case 'W': /* page width */
+ strncpy(width+2, line+1, sizeof(width) - 3);
+ width[2+sizeof(width) - 3] = '\0';
+ continue;
+
+ case 'I': /* indent amount */
+ strncpy(indent+2, line+1, sizeof(indent) - 3);
+ indent[2+sizeof(indent) - 3] = '\0';
+ continue;
+
+ case 'Z': /* locale for pr */
+ strncpy(locale, line+1, sizeof(locale) - 1);
+ locale[sizeof(locale) - 1] = '\0';
+ continue;
+
+ default: /* some file to print */
+ switch (i = print(pp, line[0], line+1)) {
+ case ERROR:
+ if (bombed == OK)
+ bombed = FATALERR;
+ break;
+ case REPRINT:
+ (void) fclose(cfp);
+ return(REPRINT);
+ case FILTERERR:
+ case ACCESS:
+ bombed = i;
+ sendmail(pp, logname, bombed);
+ }
+ title[0] = '\0';
+ continue;
+
+ case 'N':
+ case 'U':
+ case 'M':
+ case 'R':
+ continue;
+ }
+
+ /* pass 2 */
+
+pass2:
+ fseek(cfp, 0L, 0);
+ while (getline(cfp))
+ switch (line[0]) {
+ case 'L': /* identification line */
+ if (!pp->no_header && pp->header_last)
+ banner(pp, line+1, jobname);
+ continue;
+
+ case 'M':
+ if (bombed < NOACCT) /* already sent if >= NOACCT */
+ sendmail(pp, line+1, bombed);
+ continue;
+
+ case 'U':
+ if (strchr(line+1, '/'))
+ continue;
+ (void) unlink(line+1);
+ }
+ /*
+ * clean-up in case another control file exists
+ */
+ (void) fclose(cfp);
+ (void) unlink(file);
+ return(bombed == OK ? OK : ERROR);
+}
+
+/*
+ * Print a file.
+ * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
+ * Return -1 if a non-recoverable error occured,
+ * 2 if the filter detected some errors (but printed the job anyway),
+ * 1 if we should try to reprint this job and
+ * 0 if all is well.
+ * Note: all filters take stdin as the file, stdout as the printer,
+ * stderr as the log file, and must not ignore SIGINT.
+ */
+static int
+print(pp, format, file)
+ struct printer *pp;
+ int format;
+ char *file;
+{
+ register int n, i;
+ register char *prog;
+ int fi, fo;
+ FILE *fp;
+ char *av[15], buf[BUFSIZ];
+ int pid, p[2], stopped = 0;
+ union wait status;
+ struct stat stb;
+
+ if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
+ return(ERROR);
+ /*
+ * Check to see if data file is a symbolic link. If so, it should
+ * still point to the same file or someone is trying to print
+ * something he shouldn't.
+ */
+ if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
+ (stb.st_dev != fdev || stb.st_ino != fino))
+ return(ACCESS);
+
+ job_dfcnt++; /* increment datafile counter for this job */
+
+ /* everything seems OK, start it up */
+ if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */
+ (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
+ pp->tof = 1;
+ }
+ if (pp->filters[LPF_INPUT] == NULL
+ && (format == 'f' || format == 'l')) {
+ pp->tof = 0;
+ while ((n = read(fi, buf, BUFSIZ)) > 0)
+ if (write(ofd, buf, n) != n) {
+ (void) close(fi);
+ return(REPRINT);
+ }
+ (void) close(fi);
+ return(OK);
+ }
+ switch (format) {
+ case 'p': /* print file using 'pr' */
+ if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */
+ prog = _PATH_PR;
+ i = 0;
+ av[i++] = "pr";
+ av[i++] = width;
+ av[i++] = length;
+ av[i++] = "-h";
+ av[i++] = *title ? title : " ";
+ av[i++] = "-L";
+ av[i++] = *locale ? locale : "C";
+ av[i++] = "-F";
+ av[i] = 0;
+ fo = ofd;
+ goto start;
+ }
+ pipe(p);
+ if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */
+ dup2(fi, 0); /* file is stdin */
+ dup2(p[1], 1); /* pipe is stdout */
+ closelog();
+ closeallfds(3);
+ execl(_PATH_PR, "pr", width, length,
+ "-h", *title ? title : " ",
+ "-L", *locale ? locale : "C",
+ "-F", 0);
+ syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
+ exit(2);
+ }
+ (void) close(p[1]); /* close output side */
+ (void) close(fi);
+ if (prchild < 0) {
+ prchild = 0;
+ (void) close(p[0]);
+ return(ERROR);
+ }
+ fi = p[0]; /* use pipe for input */
+ case 'f': /* print plain text file */
+ prog = pp->filters[LPF_INPUT];
+ av[1] = width;
+ av[2] = length;
+ av[3] = indent;
+ n = 4;
+ break;
+ case 'l': /* like 'f' but pass control characters */
+ prog = pp->filters[LPF_INPUT];
+ av[1] = "-c";
+ av[2] = width;
+ av[3] = length;
+ av[4] = indent;
+ n = 5;
+ break;
+ case 'r': /* print a fortran text file */
+ prog = pp->filters[LPF_FORTRAN];
+ av[1] = width;
+ av[2] = length;
+ n = 3;
+ break;
+ case 't': /* print troff output */
+ case 'n': /* print ditroff output */
+ case 'd': /* print tex output */
+ (void) unlink(".railmag");
+ if ((fo = creat(".railmag", FILMOD)) < 0) {
+ syslog(LOG_ERR, "%s: cannot create .railmag",
+ pp->printer);
+ (void) unlink(".railmag");
+ } else {
+ for (n = 0; n < 4; n++) {
+ if (fonts[n][0] != '/')
+ (void) write(fo, _PATH_VFONT,
+ sizeof(_PATH_VFONT) - 1);
+ (void) write(fo, fonts[n], strlen(fonts[n]));
+ (void) write(fo, "\n", 1);
+ }
+ (void) close(fo);
+ }
+ prog = (format == 't') ? pp->filters[LPF_TROFF]
+ : ((format == 'n') ? pp->filters[LPF_DITROFF]
+ : pp->filters[LPF_DVI]);
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ case 'c': /* print cifplot output */
+ prog = pp->filters[LPF_CIFPLOT];
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ case 'g': /* print plot(1G) output */
+ prog = pp->filters[LPF_GRAPH];
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ case 'v': /* print raster output */
+ prog = pp->filters[LPF_RASTER];
+ av[1] = pxwidth;
+ av[2] = pxlength;
+ n = 3;
+ break;
+ default:
+ (void) close(fi);
+ syslog(LOG_ERR, "%s: illegal format character '%c'",
+ pp->printer, format);
+ return(ERROR);
+ }
+ if (prog == NULL) {
+ (void) close(fi);
+ syslog(LOG_ERR,
+ "%s: no filter found in printcap for format character '%c'",
+ pp->printer, format);
+ return(ERROR);
+ }
+ if ((av[0] = strrchr(prog, '/')) != NULL)
+ av[0]++;
+ else
+ av[0] = prog;
+ av[n++] = "-n";
+ av[n++] = logname;
+ av[n++] = "-h";
+ av[n++] = fromhost;
+ av[n++] = pp->acct_file;
+ av[n] = 0;
+ fo = pfd;
+ if (ofilter > 0) { /* stop output filter */
+ write(ofd, "\031\1", 2);
+ while ((pid =
+ wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
+ ;
+ if (status.w_stopval != WSTOPPED) {
+ (void) close(fi);
+ syslog(LOG_WARNING,
+ "%s: output filter died "
+ "(retcode=%d termsig=%d)",
+ pp->printer, status.w_retcode,
+ status.w_termsig);
+ return(REPRINT);
+ }
+ stopped++;
+ }
+start:
+ if ((child = dofork(pp, DORETURN)) == 0) { /* child */
+ dup2(fi, 0);
+ dup2(fo, 1);
+ n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
+ if (n >= 0)
+ dup2(n, 2);
+ closelog();
+ closeallfds(3);
+ execv(prog, av);
+ syslog(LOG_ERR, "cannot execv %s", prog);
+ exit(2);
+ }
+ (void) close(fi);
+ if (child < 0)
+ status.w_retcode = 100;
+ else
+ while ((pid = wait((int *)&status)) > 0 && pid != child)
+ ;
+ child = 0;
+ prchild = 0;
+ if (stopped) { /* restart output filter */
+ if (kill(ofilter, SIGCONT) < 0) {
+ syslog(LOG_ERR, "cannot restart output filter");
+ exit(1);
+ }
+ }
+ pp->tof = 0;
+
+ /* Copy filter output to "lf" logfile */
+ if ((fp = fopen(tempfile, "r"))) {
+ while (fgets(buf, sizeof(buf), fp))
+ fputs(buf, stderr);
+ fclose(fp);
+ }
+
+ if (!WIFEXITED(status)) {
+ syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
+ pp->printer, format, status.w_termsig);
+ return(ERROR);
+ }
+ switch (status.w_retcode) {
+ case 0:
+ pp->tof = 1;
+ return(OK);
+ case 1:
+ return(REPRINT);
+ case 2:
+ return(ERROR);
+ default:
+ syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
+ pp->printer, format, status.w_retcode);
+ return(FILTERERR);
+ }
+}
+
+/*
+ * Send the daemon control file (cf) and any data files.
+ * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
+ * 0 if all is well.
+ */
+static int
+sendit(pp, file)
+ struct printer *pp;
+ char *file;
+{
+ register int i, err = OK;
+ char *cp, last[BUFSIZ];
+
+ /*
+ * open control file
+ */
+ if ((cfp = fopen(file, "r")) == NULL)
+ return(OK);
+
+ /* initialize job-specific count of datafiles processed */
+ job_dfcnt = 0;
+
+ /*
+ * read the control file for work to do
+ *
+ * file format -- first character in the line is a command
+ * rest of the line is the argument.
+ * commands of interest are:
+ *
+ * a-z -- "file name" name of file to print
+ * U -- "unlink" name of file to remove
+ * (after we print it. (Pass 2 only)).
+ */
+
+ /*
+ * pass 1
+ */
+ while (getline(cfp)) {
+ again:
+ if (line[0] == 'S') {
+ cp = line+1;
+ i = 0;
+ while (*cp >= '0' && *cp <= '9')
+ i = i * 10 + (*cp++ - '0');
+ fdev = i;
+ cp++;
+ i = 0;
+ while (*cp >= '0' && *cp <= '9')
+ i = i * 10 + (*cp++ - '0');
+ fino = i;
+ } else if (line[0] == 'H') {
+ strncpy(fromhost, line+1, sizeof(fromhost) - 1);
+ fromhost[sizeof(fromhost) - 1] = '\0';
+ if (class[0] == '\0') {
+ strncpy(class, line+1, sizeof(class) - 1);
+ class[sizeof(class) - 1] = '\0';
+ }
+ } else if (line[0] == 'P') {
+ strncpy(logname, line+1, sizeof(logname) - 1);
+ if (pp->restricted) { /* restricted */
+ if (getpwnam(logname) == NULL) {
+ sendmail(pp, line+1, NOACCT);
+ err = ERROR;
+ break;
+ }
+ }
+ } else if (line[0] == 'I') {
+ strncpy(indent+2, line+1, sizeof(indent) - 3);
+ } else if (line[0] >= 'a' && line[0] <= 'z') {
+ strcpy(last, line);
+ while ((i = getline(cfp)) != 0)
+ if (strcmp(last, line))
+ break;
+ switch (sendfile(pp, '\3', last+1, *last)) {
+ case OK:
+ if (i)
+ goto again;
+ break;
+ case REPRINT:
+ (void) fclose(cfp);
+ return(REPRINT);
+ case ACCESS:
+ sendmail(pp, logname, ACCESS);
+ case ERROR:
+ err = ERROR;
+ }
+ break;
+ }
+ }
+ if (err == OK && sendfile(pp, '\2', file, '\0') > 0) {
+ (void) fclose(cfp);
+ return(REPRINT);
+ }
+ /*
+ * pass 2
+ */
+ fseek(cfp, 0L, 0);
+ while (getline(cfp))
+ if (line[0] == 'U' && !strchr(line+1, '/'))
+ (void) unlink(line+1);
+ /*
+ * clean-up in case another control file exists
+ */
+ (void) fclose(cfp);
+ (void) unlink(file);
+ return(err);
+}
+
+/*
+ * Send a data file to the remote machine and spool it.
+ * Return positive if we should try resending.
+ */
+static int
+sendfile(pp, type, file, format)
+ struct printer *pp;
+ int type;
+ char *file;
+ char format;
+{
+ register int f, i, amt;
+ struct stat stb;
+ char buf[BUFSIZ];
+ int sizerr, resp, closedpr;
+
+ if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
+ return(ERROR);
+ /*
+ * Check to see if data file is a symbolic link. If so, it should
+ * still point to the same file or someone is trying to print something
+ * he shouldn't.
+ */
+ if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
+ (stb.st_dev != fdev || stb.st_ino != fino))
+ return(ACCESS);
+
+ job_dfcnt++; /* increment datafile counter for this job */
+
+ /* everything seems OK, start it up */
+ sizerr = 0;
+ closedpr = 0;
+ if (type == '\3') {
+ if (pp->filters[LPF_INPUT]) {
+ /*
+ * We're sending something with an ifilter, we have to
+ * run the ifilter and store the output as a
+ * temporary file (tfile)... the protocol requires us
+ * to send the file size
+ */
+ char *av[15];
+ int n;
+ int ifilter;
+ union wait status; /* XXX */
+
+ strcpy(tfile,TFILENAME);
+ if ((tfd = mkstemp(tfile)) == -1) {
+ syslog(LOG_ERR, "mkstemp: %m");
+ return(ERROR);
+ }
+ if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL)
+ av[0] = pp->filters[LPF_INPUT];
+ else
+ av[0]++;
+ if (format == 'l')
+ av[n=1] = "-c";
+ else
+ n = 0;
+ av[++n] = width;
+ av[++n] = length;
+ av[++n] = indent;
+ av[++n] = "-n";
+ av[++n] = logname;
+ av[++n] = "-h";
+ av[++n] = fromhost;
+ av[++n] = pp->acct_file;
+ av[++n] = 0;
+ if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */
+ dup2(f, 0);
+ dup2(tfd, 1);
+ n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC,
+ TEMP_FILE_MODE);
+ if (n >= 0)
+ dup2(n, 2);
+ closelog();
+ closeallfds(3);
+ execv(pp->filters[LPF_INPUT], av);
+ syslog(LOG_ERR, "cannot execv %s",
+ pp->filters[LPF_INPUT]);
+ exit(2);
+ }
+ (void) close(f);
+ if (ifilter < 0)
+ status.w_retcode = 100;
+ else
+ while ((pid = wait((int *)&status)) > 0 &&
+ pid != ifilter)
+ ;
+ switch (status.w_retcode) {
+ case 0:
+ break;
+ case 1:
+ unlink(tfile);
+ return(REPRINT);
+ case 2:
+ unlink(tfile);
+ return(ERROR);
+ default:
+ syslog(LOG_WARNING, "%s: filter '%c' exited"
+ " (retcode=%d)",
+ pp->printer, format, status.w_retcode);
+ unlink(tfile);
+ return(FILTERERR);
+ }
+ if (fstat(tfd, &stb) < 0) /* the size of tfile */
+ return(ERROR);
+ f = tfd;
+ lseek(f,0,SEEK_SET);
+ } else if (ofilter) {
+ /*
+ * We're sending something with an ofilter, we have to
+ * store the output as a temporary file (tfile)... the
+ * protocol requires us to send the file size
+ */
+ int i;
+ for (i = 0; i < stb.st_size; i += BUFSIZ) {
+ amt = BUFSIZ;
+ if (i + amt > stb.st_size)
+ amt = stb.st_size - i;
+ if (sizerr == 0 && read(f, buf, amt) != amt) {
+ sizerr = 1;
+ break;
+ }
+ if (write(ofd, buf, amt) != amt) {
+ (void) close(f);
+ return(REPRINT);
+ }
+ }
+ close(ofd);
+ close(f);
+ while ((i = wait(NULL)) > 0 && i != ofilter)
+ ;
+ ofilter = 0;
+ if (fstat(tfd, &stb) < 0) { /* the size of tfile */
+ openpr(pp);
+ return(ERROR);
+ }
+ f = tfd;
+ lseek(f,0,SEEK_SET);
+ closedpr = 1;
+ }
+ }
+
+ (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
+ amt = strlen(buf);
+ for (i = 0; ; i++) {
+ if (write(pfd, buf, amt) != amt ||
+ (resp = response(pp)) < 0 || resp == '\1') {
+ (void) close(f);
+ if (tfd != -1 && type == '\3') {
+ tfd = -1;
+ unlink(tfile);
+ if (closedpr)
+ openpr(pp);
+ }
+ return(REPRINT);
+ } else if (resp == '\0')
+ break;
+ if (i == 0)
+ pstatus(pp,
+ "no space on remote; waiting for queue to drain");
+ if (i == 10)
+ syslog(LOG_ALERT, "%s: can't send to %s; queue full",
+ pp->printer, pp->remote_host);
+ sleep(5 * 60);
+ }
+ if (i)
+ pstatus(pp, "sending to %s", pp->remote_host);
+ if (type == '\3')
+ trstat_init(pp, file, job_dfcnt);
+ for (i = 0; i < stb.st_size; i += BUFSIZ) {
+ amt = BUFSIZ;
+ if (i + amt > stb.st_size)
+ amt = stb.st_size - i;
+ if (sizerr == 0 && read(f, buf, amt) != amt)
+ sizerr = 1;
+ if (write(pfd, buf, amt) != amt) {
+ (void) close(f);
+ if (tfd != -1 && type == '\3') {
+ tfd = -1;
+ unlink(tfile);
+ if (closedpr)
+ openpr(pp);
+ }
+ return(REPRINT);
+ }
+ }
+
+ (void) close(f);
+ if (tfd != -1 && type == '\3') {
+ tfd = -1;
+ unlink(tfile);
+ }
+ if (sizerr) {
+ syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file);
+ /* tell recvjob to ignore this file */
+ (void) write(pfd, "\1", 1);
+ if (closedpr)
+ openpr(pp);
+ return(ERROR);
+ }
+ if (write(pfd, "", 1) != 1 || response(pp)) {
+ if (closedpr)
+ openpr(pp);
+ return(REPRINT);
+ }
+ if (closedpr)
+ openpr(pp);
+ if (type == '\3')
+ trstat_write(pp, TR_SENDING, stb.st_size, logname,
+ pp->remote_host, fromhost);
+ return(OK);
+}
+
+/*
+ * Check to make sure there have been no errors and that both programs
+ * are in sync with eachother.
+ * Return non-zero if the connection was lost.
+ */
+static char
+response(pp)
+ const struct printer *pp;
+{
+ char resp;
+
+ if (read(pfd, &resp, 1) != 1) {
+ syslog(LOG_INFO, "%s: lost connection", pp->printer);
+ return(-1);
+ }
+ return(resp);
+}
+
+/*
+ * Banner printing stuff
+ */
+static void
+banner(pp, name1, name2)
+ struct printer *pp;
+ char *name1, *name2;
+{
+ time_t tvec;
+
+ time(&tvec);
+ if (!pp->no_formfeed && !pp->tof)
+ (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
+ if (pp->short_banner) { /* short banner only */
+ if (class[0]) {
+ (void) write(ofd, class, strlen(class));
+ (void) write(ofd, ":", 1);
+ }
+ (void) write(ofd, name1, strlen(name1));
+ (void) write(ofd, " Job: ", 7);
+ (void) write(ofd, name2, strlen(name2));
+ (void) write(ofd, " Date: ", 8);
+ (void) write(ofd, ctime(&tvec), 24);
+ (void) write(ofd, "\n", 1);
+ } else { /* normal banner */
+ (void) write(ofd, "\n\n\n", 3);
+ scan_out(pp, ofd, name1, '\0');
+ (void) write(ofd, "\n\n", 2);
+ scan_out(pp, ofd, name2, '\0');
+ if (class[0]) {
+ (void) write(ofd,"\n\n\n",3);
+ scan_out(pp, ofd, class, '\0');
+ }
+ (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
+ (void) write(ofd, name2, strlen(name2));
+ (void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
+ (void) write(ofd, ctime(&tvec), 24);
+ (void) write(ofd, "\n", 1);
+ }
+ if (!pp->no_formfeed)
+ (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
+ pp->tof = 1;
+}
+
+static char *
+scnline(key, p, c)
+ register int key;
+ register char *p;
+ int c;
+{
+ register int scnwidth;
+
+ for (scnwidth = WIDTH; --scnwidth;) {
+ key <<= 1;
+ *p++ = key & 0200 ? c : BACKGND;
+ }
+ return (p);
+}
+
+#define TRC(q) (((q)-' ')&0177)
+
+static void
+scan_out(pp, scfd, scsp, dlm)
+ struct printer *pp;
+ int scfd, dlm;
+ char *scsp;
+{
+ register char *strp;
+ register int nchrs, j;
+ char outbuf[LINELEN+1], *sp, c, cc;
+ int d, scnhgt;
+
+ for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
+ strp = &outbuf[0];
+ sp = scsp;
+ for (nchrs = 0; ; ) {
+ d = dropit(c = TRC(cc = *sp++));
+ if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
+ for (j = WIDTH; --j;)
+ *strp++ = BACKGND;
+ else
+ strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc);
+ if (*sp == dlm || *sp == '\0' ||
+ nchrs++ >= pp->page_width/(WIDTH+1)-1)
+ break;
+ *strp++ = BACKGND;
+ *strp++ = BACKGND;
+ }
+ while (*--strp == BACKGND && strp >= outbuf)
+ ;
+ strp++;
+ *strp++ = '\n';
+ (void) write(scfd, outbuf, strp-outbuf);
+ }
+}
+
+static int
+dropit(c)
+ int c;
+{
+ switch(c) {
+
+ case TRC('_'):
+ case TRC(';'):
+ case TRC(','):
+ case TRC('g'):
+ case TRC('j'):
+ case TRC('p'):
+ case TRC('q'):
+ case TRC('y'):
+ return (DROP);
+
+ default:
+ return (0);
+ }
+}
+
+/*
+ * sendmail ---
+ * tell people about job completion
+ */
+static void
+sendmail(pp, user, bombed)
+ struct printer *pp;
+ char *user;
+ int bombed;
+{
+ register int i;
+ int p[2], s;
+ register char *cp;
+ struct stat stb;
+ FILE *fp;
+
+ pipe(p);
+ if ((s = dofork(pp, DORETURN)) == 0) { /* child */
+ dup2(p[0], 0);
+ closelog();
+ closeallfds(3);
+ if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
+ cp++;
+ else
+ cp = _PATH_SENDMAIL;
+ execl(_PATH_SENDMAIL, cp, "-t", 0);
+ _exit(0);
+ } else if (s > 0) { /* parent */
+ dup2(p[1], 1);
+ printf("To: %s@%s\n", user, fromhost);
+ printf("Subject: %s printer job \"%s\"\n", pp->printer,
+ *jobname ? jobname : "<unknown>");
+ printf("Reply-To: root@%s\n\n", host);
+ printf("Your printer job ");
+ if (*jobname)
+ printf("(%s) ", jobname);
+
+ cp = "XXX compiler confusion"; /* XXX shut GCC up */
+ switch (bombed) {
+ case OK:
+ printf("\ncompleted successfully\n");
+ cp = "OK";
+ break;
+ default:
+ case FATALERR:
+ printf("\ncould not be printed\n");
+ cp = "FATALERR";
+ break;
+ case NOACCT:
+ printf("\ncould not be printed without an account on %s\n", host);
+ cp = "NOACCT";
+ break;
+ case FILTERERR:
+ if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
+ (fp = fopen(tempfile, "r")) == NULL) {
+ printf("\nhad some errors and may not have printed\n");
+ break;
+ }
+ printf("\nhad the following errors and may not have printed:\n");
+ while ((i = getc(fp)) != EOF)
+ putchar(i);
+ (void) fclose(fp);
+ cp = "FILTERERR";
+ break;
+ case ACCESS:
+ printf("\nwas not printed because it was not linked to the original file\n");
+ cp = "ACCESS";
+ }
+ fflush(stdout);
+ (void) close(1);
+ } else {
+ syslog(LOG_WARNING, "unable to send mail to %s: %m", user);
+ return;
+ }
+ (void) close(p[0]);
+ (void) close(p[1]);
+ wait(NULL);
+ syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
+ user, *jobname ? jobname : "<unknown>", pp->printer, cp);
+}
+
+/*
+ * dofork - fork with retries on failure
+ */
+static int
+dofork(pp, action)
+ const struct printer *pp;
+ int action;
+{
+ register int i, pid;
+ struct passwd *pwd;
+
+ for (i = 0; i < 20; i++) {
+ if ((pid = fork()) < 0) {
+ sleep((unsigned)(i*i));
+ continue;
+ }
+ /*
+ * Child should run as daemon instead of root
+ */
+ if (pid == 0) {
+ if ((pwd = getpwuid(pp->daemon_user)) == NULL) {
+ syslog(LOG_ERR, "Can't lookup default daemon uid (%ld) in password file",
+ pp->daemon_user);
+ break;
+ }
+ initgroups(pwd->pw_name, pwd->pw_gid);
+ setgid(pwd->pw_gid);
+ setuid(pp->daemon_user);
+ }
+ return(pid);
+ }
+ syslog(LOG_ERR, "can't fork");
+
+ switch (action) {
+ case DORETURN:
+ return (-1);
+ default:
+ syslog(LOG_ERR, "bad action (%d) to dofork", action);
+ /*FALL THRU*/
+ case DOABORT:
+ exit(1);
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * Kill child processes to abort current job.
+ */
+static void
+abortpr(signo)
+ int signo;
+{
+ (void) unlink(tempfile);
+ kill(0, SIGINT);
+ if (ofilter > 0)
+ kill(ofilter, SIGCONT);
+ while (wait(NULL) > 0)
+ ;
+ if (ofilter > 0 && tfd != -1)
+ unlink(tfile);
+ exit(0);
+}
+
+static void
+init(pp)
+ struct printer *pp;
+{
+ char *s;
+
+ sprintf(&width[2], "%ld", pp->page_width);
+ sprintf(&length[2], "%ld", pp->page_length);
+ sprintf(&pxwidth[2], "%ld", pp->page_pwidth);
+ sprintf(&pxlength[2], "%ld", pp->page_plength);
+ if ((s = checkremote(pp)) != 0) {
+ syslog(LOG_WARNING, "%s", s);
+ free(s);
+ }
+}
+
+void
+startprinting(printer)
+ const char *printer;
+{
+ struct printer myprinter, *pp = &myprinter;
+ int status;
+
+ init_printer(pp);
+ status = getprintcap(printer, pp);
+ switch(status) {
+ case PCAPERR_OSERR:
+ syslog(LOG_ERR, "can't open printer description file: %m");
+ exit(1);
+ case PCAPERR_NOTFOUND:
+ syslog(LOG_ERR, "unknown printer: %s", printer);
+ exit(1);
+ case PCAPERR_TCLOOP:
+ fatal(pp, "potential reference loop detected in printcap file");
+ default:
+ break;
+ }
+ printjob(pp);
+}
+
+/*
+ * Acquire line printer or remote connection.
+ */
+static void
+openpr(pp)
+ const struct printer *pp;
+{
+ int p[2];
+ char *cp;
+
+ if (pp->remote) {
+ openrem(pp);
+ } else if (*pp->lp) {
+ if ((cp = strchr(pp->lp, '@')) != NULL)
+ opennet(pp);
+ else
+ opentty(pp);
+ } else {
+ syslog(LOG_ERR, "%s: no line printer device or host name",
+ pp->printer);
+ exit(1);
+ }
+
+ /*
+ * Start up an output filter, if needed.
+ */
+ if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) {
+ pipe(p);
+ if (pp->remote) {
+ strcpy(tfile, TFILENAME);
+ tfd = mkstemp(tfile);
+ }
+ if ((ofilter = dofork(pp, DOABORT)) == 0) { /* child */
+ dup2(p[0], 0); /* pipe is std in */
+ /* tfile/printer is stdout */
+ dup2(pp->remote ? tfd : pfd, 1);
+ closelog();
+ closeallfds(3);
+ if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL)
+ cp = pp->filters[LPF_OUTPUT];
+ else
+ cp++;
+ execl(pp->filters[LPF_OUTPUT], cp, width, length, 0);
+ syslog(LOG_ERR, "%s: %s: %m", pp->printer,
+ pp->filters[LPF_OUTPUT]);
+ exit(1);
+ }
+ (void) close(p[0]); /* close input side */
+ ofd = p[1]; /* use pipe for output */
+ } else {
+ ofd = pfd;
+ ofilter = 0;
+ }
+}
+
+/*
+ * Printer connected directly to the network
+ * or to a terminal server on the net
+ */
+static void
+opennet(pp)
+ const struct printer *pp;
+{
+ register int i;
+ int resp;
+ u_long port;
+ char *ep;
+ void (*savealrm)(int);
+
+ port = strtoul(pp->lp, &ep, 0);
+ if (*ep != '@' || port > 65535) {
+ syslog(LOG_ERR, "%s: bad port number: %s", pp->printer,
+ pp->lp);
+ exit(1);
+ }
+ ep++;
+
+ for (i = 1; ; i = i < 256 ? i << 1 : i) {
+ resp = -1;
+ savealrm = signal(SIGALRM, alarmhandler);
+ alarm(pp->conn_timeout);
+ pfd = getport(pp, ep, port);
+ alarm(0);
+ (void)signal(SIGALRM, savealrm);
+ if (pfd < 0 && errno == ECONNREFUSED)
+ resp = 1;
+ else if (pfd >= 0) {
+ /*
+ * need to delay a bit for rs232 lines
+ * to stabilize in case printer is
+ * connected via a terminal server
+ */
+ delay(500);
+ break;
+ }
+ if (i == 1) {
+ if (resp < 0)
+ pstatus(pp, "waiting for %s to come up",
+ pp->lp);
+ else
+ pstatus(pp,
+ "waiting for access to printer on %s",
+ pp->lp);
+ }
+ sleep(i);
+ }
+ pstatus(pp, "sending to %s port %d", ep, port);
+}
+
+/*
+ * Printer is connected to an RS232 port on this host
+ */
+static void
+opentty(pp)
+ const struct printer *pp;
+{
+ register int i;
+
+ for (i = 1; ; i = i < 32 ? i << 1 : i) {
+ pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY);
+ if (pfd >= 0) {
+ delay(500);
+ break;
+ }
+ if (errno == ENOENT) {
+ syslog(LOG_ERR, "%s: %m", pp->lp);
+ exit(1);
+ }
+ if (i == 1)
+ pstatus(pp,
+ "waiting for %s to become ready (offline?)",
+ pp->printer);
+ sleep(i);
+ }
+ if (isatty(pfd))
+ setty(pp);
+ pstatus(pp, "%s is ready and printing", pp->printer);
+}
+
+/*
+ * Printer is on a remote host
+ */
+static void
+openrem(pp)
+ const struct printer *pp;
+{
+ register int i;
+ int resp;
+ void (*savealrm)(int);
+
+ for (i = 1; ; i = i < 256 ? i << 1 : i) {
+ resp = -1;
+ savealrm = signal(SIGALRM, alarmhandler);
+ alarm(pp->conn_timeout);
+ pfd = getport(pp, pp->remote_host, 0);
+ alarm(0);
+ (void)signal(SIGALRM, savealrm);
+ if (pfd >= 0) {
+ if ((writel(pfd, "\2", pp->remote_queue, "\n",
+ (char *)0)
+ == 2 + strlen(pp->remote_queue))
+ && (resp = response(pp)) == 0)
+ break;
+ (void) close(pfd);
+ }
+ if (i == 1) {
+ if (resp < 0)
+ pstatus(pp, "waiting for %s to come up",
+ pp->remote_host);
+ else {
+ pstatus(pp,
+ "waiting for queue to be enabled on %s",
+ pp->remote_host);
+ i = 256;
+ }
+ }
+ sleep(i);
+ }
+ pstatus(pp, "sending to %s", pp->remote_host);
+}
+
+/*
+ * setup tty lines.
+ */
+static void
+setty(pp)
+ const struct printer *pp;
+{
+ struct termios ttybuf;
+
+ if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer);
+ exit(1);
+ }
+ if (tcgetattr(pfd, &ttybuf) < 0) {
+ syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer);
+ exit(1);
+ }
+ if (pp->baud_rate > 0)
+ cfsetspeed(&ttybuf, pp->baud_rate);
+ if (pp->mode_set) {
+ char *s = strdup(pp->mode_set), *tmp;
+
+ while ((tmp = strsep(&s, ",")) != NULL) {
+ (void) msearch(tmp, &ttybuf);
+ }
+ }
+ if (pp->mode_set != 0 || pp->baud_rate > 0) {
+ if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
+ syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer);
+ }
+ }
+}
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+static void
+#ifdef __STDC__
+pstatus(const struct printer *pp, const char *msg, ...)
+#else
+pstatus(pp, msg, va_alist)
+ const struct printer *pp;
+ char *msg;
+ va_dcl
+#endif
+{
+ int fd;
+ char *buf;
+ va_list ap;
+#ifdef __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+
+ umask(0);
+ fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
+ if (fd < 0) {
+ syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file);
+ exit(1);
+ }
+ ftruncate(fd, 0);
+ vasprintf(&buf, msg, ap);
+ va_end(ap);
+ writel(fd, buf, "\n", (char *)0);
+ close(fd);
+ free(buf);
+}
+
+void
+alarmhandler(signo)
+{
+ /* ignored */
+}
diff --git a/usr.sbin/lpr/lpd/recvjob.c b/usr.sbin/lpr/lpd/recvjob.c
new file mode 100644
index 0000000..255a5e3
--- /dev/null
+++ b/usr.sbin/lpr/lpd/recvjob.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)recvjob.c 8.2 (Berkeley) 4/27/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+/*
+ * Receive printer jobs from the network, queue them and
+ * start the printer daemon.
+ */
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <syslog.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "lp.h"
+#include "lp.local.h"
+#include "extern.h"
+#include "pathnames.h"
+
+#define ack() (void) write(1, sp, 1);
+
+static char dfname[NAME_MAX]; /* data files */
+static int minfree; /* keep at least minfree blocks available */
+static char *sp = "";
+static char tfname[NAME_MAX]; /* tmp copy of cf before linking */
+
+static int chksize __P((int));
+static void frecverr __P((const char *, ...));
+static int noresponse __P((void));
+static void rcleanup __P((int));
+static int read_number __P((char *));
+static int readfile __P((struct printer *pp, char *, int));
+static int readjob __P((struct printer *pp));
+
+
+void
+recvjob(printer)
+ const char *printer;
+{
+ struct stat stb;
+ int status;
+ struct printer myprinter, *pp = &myprinter;
+
+ /*
+ * Perform lookup for printer name or abbreviation
+ */
+ init_printer(pp);
+ status = getprintcap(printer, pp);
+ switch (status) {
+ case PCAPERR_OSERR:
+ frecverr("cannot open printer description file");
+ break;
+ case PCAPERR_NOTFOUND:
+ frecverr("unknown printer %s", printer);
+ break;
+ case PCAPERR_TCLOOP:
+ fatal(pp, "potential reference loop detected in printcap file");
+ default:
+ break;
+ }
+
+ (void) close(2); /* set up log file */
+ if (open(pp->log_file, O_WRONLY|O_APPEND, 0664) < 0) {
+ syslog(LOG_ERR, "%s: %m", pp->log_file);
+ (void) open(_PATH_DEVNULL, O_WRONLY);
+ }
+
+ if (chdir(pp->spool_dir) < 0)
+ frecverr("%s: %s: %m", pp->printer, pp->spool_dir);
+ if (stat(pp->lock_file, &stb) == 0) {
+ if (stb.st_mode & 010) {
+ /* queue is disabled */
+ putchar('\1'); /* return error code */
+ exit(1);
+ }
+ } else if (stat(pp->spool_dir, &stb) < 0)
+ frecverr("%s: %s: %m", pp->printer, pp->spool_dir);
+ minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */
+ signal(SIGTERM, rcleanup);
+ signal(SIGPIPE, rcleanup);
+
+ if (readjob(pp))
+ printjob(pp);
+}
+
+/*
+ * Read printer jobs sent by lpd and copy them to the spooling directory.
+ * Return the number of jobs successfully transfered.
+ */
+static int
+readjob(pp)
+ struct printer *pp;
+{
+ register int size;
+ register char *cp;
+ int cfcnt, dfcnt;
+ char givenid[32], givenhost[MAXHOSTNAMELEN];
+
+ ack();
+ cfcnt = 0;
+ dfcnt = 0;
+ for (;;) {
+ /*
+ * Read a command to tell us what to do
+ */
+ cp = line;
+ do {
+ if ((size = read(1, cp, 1)) != 1) {
+ if (size < 0) {
+ frecverr("%s: lost connection",
+ pp->printer);
+ /*NOTREACHED*/
+ }
+ return (cfcnt);
+ }
+ } while (*cp++ != '\n' && (cp - line + 1) < sizeof(line));
+ if (cp - line + 1 >= sizeof(line)) {
+ frecverr("%s: readjob overflow", pp->printer);
+ /*NOTREACHED*/
+ }
+ *--cp = '\0';
+ cp = line;
+ switch (*cp++) {
+ case '\1': /* cleanup because data sent was bad */
+ rcleanup(0);
+ continue;
+
+ case '\2': /* read cf file */
+ size = 0;
+ dfcnt = 0;
+ while (*cp >= '0' && *cp <= '9')
+ size = size * 10 + (*cp++ - '0');
+ if (*cp++ != ' ')
+ break;
+ /*
+ * host name has been authenticated, we use our
+ * view of the host name since we may be passed
+ * something different than what gethostbyaddr()
+ * returns
+ */
+ strncpy(cp + 6, from, sizeof(line) + line - cp - 7);
+ line[sizeof(line) - 1 ] = '\0';
+ strncpy(tfname, cp, sizeof(tfname) - 1);
+ tfname[sizeof (tfname) - 1] = '\0';
+ tfname[0] = 't';
+ if (strchr(tfname, '/'))
+ frecverr("readjob: %s: illegal path name",
+ tfname);
+ if (!chksize(size)) {
+ (void) write(1, "\2", 1);
+ continue;
+ }
+ if (!readfile(pp, tfname, size)) {
+ rcleanup(0);
+ continue;
+ }
+ if (link(tfname, cp) < 0)
+ frecverr("%s: %m", tfname);
+ (void) unlink(tfname);
+ tfname[0] = '\0';
+ cfcnt++;
+ continue;
+
+ case '\3': /* read df file */
+ *givenid = '\0';
+ *givenhost = '\0';
+ size = 0;
+ while (*cp >= '0' && *cp <= '9')
+ size = size * 10 + (*cp++ - '0');
+ if (*cp++ != ' ')
+ break;
+ if (!chksize(size)) {
+ (void) write(1, "\2", 1);
+ continue;
+ }
+ (void) strncpy(dfname, cp, sizeof(dfname) - 1);
+ dfname[sizeof(dfname) - 1] = '\0';
+ if (strchr(dfname, '/')) {
+ frecverr("readjob: %s: illegal path name",
+ dfname);
+ /*NOTREACHED*/
+ }
+ dfcnt++;
+ trstat_init(pp, dfname, dfcnt);
+ (void) readfile(pp, dfname, size);
+ trstat_write(pp, TR_RECVING, size, givenid, from,
+ givenhost);
+ continue;
+ }
+ frecverr("protocol screwup: %s", line);
+ /*NOTREACHED*/
+ }
+}
+
+/*
+ * Read files send by lpd and copy them to the spooling directory.
+ */
+static int
+readfile(pp, file, size)
+ struct printer *pp;
+ char *file;
+ int size;
+{
+ register char *cp;
+ char buf[BUFSIZ];
+ register int i, j, amt;
+ int fd, err;
+
+ fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD);
+ if (fd < 0) {
+ frecverr("%s: readfile: error on open(%s): %m",
+ pp->printer, file);
+ /*NOTREACHED*/
+ }
+ ack();
+ err = 0;
+ for (i = 0; i < size; i += BUFSIZ) {
+ amt = BUFSIZ;
+ cp = buf;
+ if (i + amt > size)
+ amt = size - i;
+ do {
+ j = read(1, cp, amt);
+ if (j <= 0) {
+ frecverr("%s: lost connection", pp->printer);
+ /*NOTREACHED*/
+ }
+ amt -= j;
+ cp += j;
+ } while (amt > 0);
+ amt = BUFSIZ;
+ if (i + amt > size)
+ amt = size - i;
+ if (write(fd, buf, amt) != amt) {
+ err++;
+ break;
+ }
+ }
+ (void) close(fd);
+ if (err) {
+ frecverr("%s: write error on close(%s)", pp->printer, file);
+ /*NOTREACHED*/
+ }
+ if (noresponse()) { /* file sent had bad data in it */
+ if (strchr(file, '/') == NULL)
+ (void) unlink(file);
+ return (0);
+ }
+ ack();
+ return (1);
+}
+
+static int
+noresponse()
+{
+ char resp;
+
+ if (read(1, &resp, 1) != 1) {
+ frecverr("lost connection in noresponse()");
+ /*NOTREACHED*/
+ }
+ if (resp == '\0')
+ return(0);
+ return(1);
+}
+
+/*
+ * Check to see if there is enough space on the disk for size bytes.
+ * 1 == OK, 0 == Not OK.
+ */
+static int
+chksize(size)
+ int size;
+{
+ int spacefree;
+ struct statfs sfb;
+
+ if (statfs(".", &sfb) < 0) {
+ syslog(LOG_ERR, "%s: %m", "statfs(\".\")");
+ return (1);
+ }
+ spacefree = sfb.f_bavail * (sfb.f_bsize / 512);
+ size = (size + 511) / 512;
+ if (minfree + size > spacefree)
+ return(0);
+ return(1);
+}
+
+static int
+read_number(fn)
+ char *fn;
+{
+ char lin[80];
+ register FILE *fp;
+
+ if ((fp = fopen(fn, "r")) == NULL)
+ return (0);
+ if (fgets(lin, 80, fp) == NULL) {
+ fclose(fp);
+ return (0);
+ }
+ fclose(fp);
+ return (atoi(lin));
+}
+
+/*
+ * Remove all the files associated with the current job being transfered.
+ */
+static void
+rcleanup(signo)
+ int signo;
+{
+ if (tfname[0] && strchr(tfname, '/') == NULL)
+ (void) unlink(tfname);
+ if (dfname[0] && strchr(dfname, '/') == NULL) {
+ do {
+ do
+ (void) unlink(dfname);
+ while (dfname[2]-- != 'A');
+ dfname[2] = 'z';
+ } while (dfname[0]-- != 'd');
+ }
+ dfname[0] = '\0';
+}
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+static void
+#ifdef __STDC__
+frecverr(const char *msg, ...)
+#else
+frecverr(msg, va_alist)
+ char *msg;
+ va_dcl
+#endif
+{
+ va_list ap;
+#ifdef __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+ syslog(LOG_ERR, "Error receiving job from %s:", fromb);
+ vsyslog(LOG_ERR, msg, ap);
+ va_end(ap);
+ /*
+ * rcleanup is not called until AFTER logging the error message,
+ * because rcleanup will zap some variables which may have been
+ * supplied as parameters for that msg...
+ */
+ rcleanup(0);
+ /*
+ * Add a minimal delay before returning the final error code to
+ * the sending host. This just in case that machine responds
+ * this error by INSTANTLY retrying (and instantly re-failing...).
+ * It would be stupid of the sending host to do that, but if there
+ * was a broken implementation which did it, the result might be
+ * obscure performance problems and a flood of syslog messages on
+ * the receiving host.
+ */
+ sleep(2); /* a paranoid throttling measure */
+ putchar('\1'); /* return error code */
+ exit(1);
+}
diff --git a/usr.sbin/lpr/lpq/Makefile b/usr.sbin/lpr/lpq/Makefile
new file mode 100644
index 0000000..24afb7a
--- /dev/null
+++ b/usr.sbin/lpr/lpq/Makefile
@@ -0,0 +1,13 @@
+# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $FreeBSD$
+
+PROG= lpq
+CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS}
+DPADD= ${LIBLPR}
+LDADD= ${LIBLPR}
+
+BINGRP= daemon
+BINMODE=6555
+BINDIR= /usr/bin
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lpq/lpq.1 b/usr.sbin/lpr/lpq/lpq.1
new file mode 100644
index 0000000..cff76b24
--- /dev/null
+++ b/usr.sbin/lpr/lpq/lpq.1
@@ -0,0 +1,137 @@
+.\" Copyright (c) 1983, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)lpq.1 8.2 (Berkeley) 4/28/95
+.\" $FreeBSD$
+.\"
+.Dd April 28, 1995
+.Dt LPQ 1
+.Os BSD 4.2
+.Sh NAME
+.Nm lpq
+.Nd spool queue examination program
+.Sh SYNOPSIS
+.Nm lpq
+.Op Fl a
+.Op Fl l
+.Op Fl P Ns Ar printer
+.Op job # ...
+.Op user ...
+.Sh DESCRIPTION
+.Nm Lpq
+examines the spooling area used by
+.Xr lpd 8
+for printing files on the line printer, and reports the status of the
+specified jobs or all jobs associated with a user.
+.Nm Lpq
+invoked
+without any arguments reports on any jobs currently in the queue.
+.Pp
+Options:
+.Pp
+.Bl -tag -width indent
+.It Fl P
+Specify a particular printer, otherwise the default
+line printer is used (or the value of the
+.Ev PRINTER
+variable in the
+environment). All other arguments supplied are interpreted as user
+names or job numbers to filter out only those jobs of interest.
+.It Fl l
+Information about each of the files comprising the job entry
+is printed.
+Normally, only as much information as will fit on one line is displayed.
+.It Fl a
+Report on the local queues for all printers,
+rather than just the specified printer.
+.El
+.Pp
+For each job submitted (i.e. invocation of
+.Xr lpr 1 )
+.Nm
+reports the user's name, current rank in the queue, the
+names of files comprising the job, the job identifier (a number which
+may be supplied to
+.Xr lprm 1
+for removing a specific job), and the total size in bytes.
+Job ordering is dependent on
+the algorithm used to scan the spooling directory and is supposed
+to be
+.Tn FIFO
+(First in First Out).
+File names comprising a job may be unavailable
+(when
+.Xr lpr 1
+is used as a sink in a pipeline) in which case the file
+is indicated as ``(standard input)''.
+.Pp
+If
+.Nm
+warns that there is no daemon present (i.e. due to some malfunction),
+the
+.Xr lpc 8
+command can be used to restart the printer daemon.
+.Sh ENVIRONMENT
+If the following environment variable exists, it is used by
+.Nm lpq :
+.Bl -tag -width PRINTER
+.It Ev PRINTER
+Specifies an alternate default printer.
+.El
+.Sh FILES
+.Bl -tag -width "/var/spool/*/lock" -compact
+.It Pa /etc/printcap
+To determine printer characteristics.
+.It Pa /var/spool/*
+The spooling directory, as determined from printcap.
+.It Pa /var/spool/*/cf*
+Control files specifying jobs.
+.It Pa /var/spool/*/lock
+The lock file to obtain the currently active job.
+.El
+.Sh SEE ALSO
+.Xr lpr 1 ,
+.Xr lprm 1 ,
+.Xr lpc 8 ,
+.Xr lpd 8
+.Sh HISTORY
+.Nm Lpq
+appeared in
+.Bx 3 .
+.Sh BUGS
+Due to the dynamic nature of the information in the spooling directory
+.Nm
+may report unreliably.
+Output formatting is sensitive to the line length of the terminal;
+this can results in widely spaced columns.
+.Sh DIAGNOSTICS
+Unable to open various files. The lock file being malformed. Garbage
+files when there is no daemon active, but files in the spooling directory.
diff --git a/usr.sbin/lpr/lpq/lpq.c b/usr.sbin/lpr/lpq/lpq.c
new file mode 100644
index 0000000..67de966
--- /dev/null
+++ b/usr.sbin/lpr/lpq/lpq.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*
+static char sccsid[] = "@(#)lpq.c 8.3 (Berkeley) 5/10/95";
+*/
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+/*
+ * Spool Queue examination program
+ *
+ * lpq [-a] [-l] [-Pprinter] [user...] [job...]
+ *
+ * -a show all non-null queues on the local machine
+ * -l long output
+ * -P used to identify printer as per lpr/lprm
+ */
+
+#include <sys/param.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+
+int requ[MAXREQUESTS]; /* job number of spool entries */
+int requests; /* # of spool requests */
+char *user[MAXUSERS]; /* users to process */
+int users; /* # of users in user array */
+
+uid_t uid, euid;
+
+static int ckqueue __P((const struct printer *));
+static void usage __P((void));
+int main __P((int, char **));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int ch, aflag, lflag;
+ char *printer;
+ struct printer myprinter, *pp = &myprinter;
+
+ printer = NULL;
+ euid = geteuid();
+ uid = getuid();
+ seteuid(uid);
+ name = *argv;
+ if (gethostname(host, sizeof(host)))
+ err(1, "gethostname");
+ openlog("lpd", 0, LOG_LPR);
+
+ aflag = lflag = 0;
+ while ((ch = getopt(argc, argv, "alP:")) != -1)
+ switch((char)ch) {
+ case 'a':
+ ++aflag;
+ break;
+ case 'l': /* long output */
+ ++lflag;
+ break;
+ case 'P': /* printer name */
+ printer = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+
+ if (!aflag && printer == NULL && (printer = getenv("PRINTER")) == NULL)
+ printer = DEFLP;
+
+ for (argc -= optind, argv += optind; argc; --argc, ++argv)
+ if (isdigit(argv[0][0])) {
+ if (requests >= MAXREQUESTS)
+ fatal(0, "too many requests");
+ requ[requests++] = atoi(*argv);
+ }
+ else {
+ if (users >= MAXUSERS)
+ fatal(0, "too many users");
+ user[users++] = *argv;
+ }
+
+ if (aflag) {
+ int more, status;
+
+ more = firstprinter(pp, &status);
+ if (status)
+ goto looperr;
+ while (more) {
+ if (ckqueue(pp) > 0) {
+ printf("%s:\n", pp->printer);
+ displayq(pp, lflag);
+ printf("\n");
+ }
+ do {
+ more = nextprinter(pp, &status);
+looperr:
+ switch (status) {
+ case PCAPERR_TCOPEN:
+ printf("warning: %s: unresolved "
+ "tc= reference(s) ",
+ pp->printer);
+ case PCAPERR_SUCCESS:
+ break;
+ default:
+ fatal(pp, pcaperr(status));
+ }
+ } while (more && status);
+ }
+ } else {
+ int status;
+
+ init_printer(pp);
+ status = getprintcap(printer, pp);
+ if (status < 0)
+ fatal(pp, pcaperr(status));
+
+ displayq(pp, lflag);
+ }
+ exit(0);
+}
+
+static int
+ckqueue(pp)
+ const struct printer *pp;
+{
+ register struct dirent *d;
+ DIR *dirp;
+ char *spooldir;
+
+ spooldir = pp->spool_dir;
+ if ((dirp = opendir(spooldir)) == NULL)
+ return (-1);
+ while ((d = readdir(dirp)) != NULL) {
+ if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
+ continue; /* daemon control files only */
+ closedir(dirp);
+ return (1); /* found something */
+ }
+ closedir(dirp);
+ return (0);
+}
+
+static void
+usage()
+{
+ fprintf(stderr,
+ "usage: lpq [-a] [-l] [-Pprinter] [user ...] [job ...]\n");
+ exit(1);
+}
diff --git a/usr.sbin/lpr/lpr/Makefile b/usr.sbin/lpr/lpr/Makefile
new file mode 100644
index 0000000..e82347c
--- /dev/null
+++ b/usr.sbin/lpr/lpr/Makefile
@@ -0,0 +1,15 @@
+# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $FreeBSD$
+
+PROG= lpr
+CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS}
+BINGRP= daemon
+BINMODE=6555
+BINDIR= /usr/bin
+MAN1= lpr.1
+MAN5= printcap.5
+.PATH: ${.CURDIR}/../common_source
+DPADD= ${LIBLPR}
+LDADD= ${LIBLPR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lpr/lpr.1 b/usr.sbin/lpr/lpr/lpr.1
new file mode 100644
index 0000000..e05290d
--- /dev/null
+++ b/usr.sbin/lpr/lpr/lpr.1
@@ -0,0 +1,315 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From @(#)lpr.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD$
+.\" "
+.Dd June 6, 1993
+.Dt LPR 1
+.Os BSD 4
+.Sh NAME
+.Nm lpr
+.Nd off line print
+.Sh SYNOPSIS
+.Nm lpr
+.Op Fl P Ns Ar printer
+.Op Fl \&# Ns Ar num
+.Op Fl C Ar class
+.Op Fl J Ar job
+.Op Fl L Ar locale
+.Op Fl T Ar title
+.Op Fl U Ar user
+.Op Fl Z Ar daemon-options
+.Op Fl i Ar numcols
+.Op Fl 1234 Ar font
+.Op Fl w Ar num
+.Op Fl cdfghlnmprstv
+.Op Ar name ...
+.Sh DESCRIPTION
+.Nm Lpr
+uses a spooling daemon to print the named files when facilities
+become available. If no names appear, the standard input is assumed.
+.Pp
+The following single letter options are used to notify the line printer
+spooler that the files are not standard text files.
+The spooling daemon will
+use the appropriate filters to print the data accordingly.
+Note that not all spoolers implement filters for all data types,
+and some sites may use these types for other purposes than the ones
+described here.
+.Bl -tag -width indent
+.It Fl d
+The files are assumed to contain data in
+.Tn DVI
+format from the
+.Tn TeX
+typesetting system.
+.It Fl f
+Use a filter which interprets the first character of each line as a
+standard
+.Tn FORTRAN
+carriage control character.
+.It Fl l
+Use a filter which allows control characters to be printed and suppresses
+page breaks.
+.It Fl p
+Use
+.Xr pr 1
+to format the files.
+.El
+.Pp
+The following options are historical and not directly supported by any
+software included in
+.Fx .
+.Bl -tag -width indent
+.It Fl c
+The files are assumed to contain data produced by
+.Xr cifplot 1 .
+.It Fl g
+The files are assumed to contain standard plot data as produced by the
+.Ux
+.Xr plot 3
+routines.
+.It Fl n
+The files are assumed to contain data from
+.Em ditroff
+(device independent troff).
+.It Fl t
+The files are assumed to contain
+.Tn C/A/T
+phototypesetter commands from ancient versions of
+.Ux
+.Xr troff 1 .
+.It Fl v
+The files are assumed to contain a raster image for devices like the
+Benson Varian.
+.El
+.Pp
+These options apply to the handling of
+the print job:
+.Bl -tag -width indent
+.It Fl P
+Force output to a specific printer. Normally,
+the default printer is used (site dependent), or the value of the
+environment variable
+.Ev PRINTER
+is used.
+.It Fl h
+Suppress the printing of the burst page.
+.It Fl m
+Send mail upon completion.
+.It Fl r
+Remove the file upon completion of spooling or upon completion of
+printing (with the
+.Fl s
+option).
+.It Fl s
+Use symbolic links. Usually files are copied to the spool directory.
+The
+.Fl s
+option will use
+.Xr symlink 2
+to link data files rather than trying to copy them so large files can be
+printed. This means the files should
+not be modified or removed until they have been printed.
+.El
+.Pp
+The remaining options apply to copies, the page display, and headers:
+.Bl -tag -width indent
+.It Fl \&# Ns Ar num
+The quantity
+.Ar num
+is the number of copies desired of each file named. For example,
+.Bd -literal -offset indent
+lpr \-#3 foo.c bar.c more.c
+.Ed
+would result in 3 copies of the file foo.c, followed by 3 copies
+of the file bar.c, etc. On the other hand,
+.Bd -literal -offset indent
+cat foo.c bar.c more.c \&| lpr \-#3
+.Ed
+.Pp
+will give three copies of the concatenation of the files.
+Often
+a site will disable this feature to encourage use of a photocopier
+instead.
+.It Xo
+.Fl Ns Oo Cm 1234 Oc Ar font
+.Xc
+Specifies a
+.Ar font
+to be mounted on font position
+.Ar i .
+The daemon
+will construct a
+.Li .railmag
+file referencing
+the font pathname.
+.It Fl C Ar class
+Job classification
+to use on the burst page. For example,
+.Bd -literal -offset indent
+lpr \-C EECS foo.c
+.Ed
+.Pp
+causes the system name (the name returned by
+.Xr hostname 1 )
+to be replaced on the burst page by
+.Tn EECS ,
+and the file foo.c to be printed.
+.It Fl J Ar job
+Job name to print on the burst page.
+Normally, the first file's name is used.
+.It Fl L Ar locale
+Use
+.Ar locale
+specified as argument instead of one found in environment.
+(Only effective when filtering through
+.Xr pr 1
+is requested using the
+.Fl p
+option.)
+.It Fl T Ar title
+Title name for
+.Xr pr 1 ,
+instead of the file name.
+.It Fl U Ar user
+User name to print on the burst page,
+also for accounting purposes.
+This option is only honored if the real user-id is daemon
+(or that specified in the printcap file instead of daemon),
+and is intended for those instances where print filters wish to requeue jobs.
+.It Fl Z Ar daemon-options
+Some spoolers, such as
+.Tn LPRng ,
+accept additional per-job options using a
+.Ql Z
+control line.
+When
+.Fl Z
+is specified, and
+.Fl p
+.Pq Xr pr 1
+is not requested, the specified
+.Ar daemon-options
+will be passed to the remote
+.Tn LPRng
+spooler.
+.It Fl i Ar numcols
+The output is indented by
+.Pq Ar numcols .
+.It Fl w Ar num
+Uses
+.Ar num
+as the page width for
+.Xr pr 1 .
+.El
+.Sh ENVIRONMENT
+If the following environment variable exists, it is used by
+.Nm Ns :
+.Bl -tag -width PRINTER
+.It Ev PRINTER
+Specifies an alternate default printer.
+.El
+.Sh FILES
+.Bl -tag -width /var/spool/output/*/tf* -compact
+.It Pa /etc/passwd
+Personal identification.
+.It Pa /etc/printcap
+Printer capabilities data base.
+.It Pa /usr/sbin/lpd
+Line printer daemons.
+.It Pa /var/spool/output/*
+Directories used for spooling.
+.It Pa /var/spool/output/*/cf*
+Daemon control files.
+.It Pa /var/spool/output/*/df*
+Data files specified in "cf" files.
+.It Pa /var/spool/output/*/tf*
+Temporary copies of "cf" files.
+.El
+.Sh SEE ALSO
+.Xr lpq 1 ,
+.Xr lprm 1 ,
+.Xr pr 1 ,
+.Xr symlink 2 ,
+.Xr printcap 5 ,
+.Xr lpc 8 ,
+.Xr lpd 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3 .
+.Sh DIAGNOSTICS
+If you try to spool too large a file, it will be truncated.
+.Nm Lpr
+will object to printing binary files.
+If a user other than root prints a file and spooling is disabled,
+.Nm
+will print a message saying so and will not put jobs in the queue.
+If a connection to
+.Xr lpd 8
+on the local machine cannot be made,
+.Nm
+will say that the daemon cannot be started.
+Diagnostics may be printed in the daemon's log file
+regarding missing spool files by
+.Xr lpd 8 .
+.Sh BUGS
+Fonts for
+.Xr troff 1
+and
+.Tn TeX
+reside on the host with the printer.
+It is currently not possible to
+use local font libraries.
+.Pp
+The
+.Ql Z
+control file line is used for two different purposes; for
+standard
+.Fx
+.Xr lpd 8 ,
+it specifies a locale to be passed to
+.Xr pr 1 .
+For
+.Tn LPRng
+.Xr lpd 8 ,
+it specifies additional options to be interpreted by the spooler's
+input and output filters.
+When submitting jobs via
+.Nm Ns ,
+.Fl p
+.Fl L Ar locale
+is used in the former context, and
+.Fl Z Ar daemon-options
+is used in the latter.
diff --git a/usr.sbin/lpr/lpr/lpr.c b/usr.sbin/lpr/lpr/lpr.c
new file mode 100644
index 0000000..f43767c
--- /dev/null
+++ b/usr.sbin/lpr/lpr/lpr.c
@@ -0,0 +1,895 @@
+/*
+ * Copyright (c) 1983, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)from: lpr.c 8.4 (Berkeley) 4/28/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+/*
+ * lpr -- off line print
+ *
+ * Allows multiple printers and printers on remote machines by
+ * using information from a printer data base.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <a.out.h>
+#include <err.h>
+#include <locale.h>
+#include <signal.h>
+#include <syslog.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+
+static char *cfname; /* daemon control files, linked from tf's */
+static char *class = host; /* class title on header page */
+static char *dfname; /* data files */
+static char *fonts[4]; /* troff font names */
+static char format = 'f'; /* format char for printing files */
+static int hdr = 1; /* print header or not (default is yes) */
+static int iflag; /* indentation wanted */
+static int inchar; /* location to increment char in file names */
+static int indent; /* amount to indent */
+static char *jobname; /* job name on header page */
+static int mailflg; /* send mail */
+static int nact; /* number of jobs to act on */
+static int ncopies = 1; /* # of copies to make */
+static char *person; /* user name */
+static int qflag; /* q job, but don't exec daemon */
+static int rflag; /* remove files upon completion */
+static int sflag; /* symbolic link flag */
+static int tfd; /* control file descriptor */
+static char *tfname; /* tmp copy of cf before linking */
+static char *title; /* pr'ing title */
+static char *locale; /* pr'ing locale */
+static int userid; /* user id */
+static char *Uflag; /* user name specified with -U flag */
+static char *width; /* width for versatec printing */
+static char *Zflag; /* extra filter options for LPRng servers */
+
+static struct stat statb;
+
+static void card __P((int, char *));
+static int checkwriteperm __P((char*, char *));
+static void chkprinter __P((char *printer, struct printer *pp));
+static void cleanup __P((int));
+static void copy __P((const struct printer *, int, char []));
+static char *itoa __P((int));
+static char *linked __P((char *));
+int main __P((int, char **));
+static char *lmktemp __P((const struct printer *pp, char *, int, int));
+static void mktemps __P((const struct printer *pp));
+static int nfile __P((char *));
+static int test __P((char *));
+static void usage __P((void));
+
+uid_t uid, euid;
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct passwd *pw;
+ struct group *gptr;
+ char *arg, *cp, *printer, *p;
+ char buf[BUFSIZ];
+ int c, i, f, errs;
+ int ret, didlink;
+ struct stat stb;
+ struct stat statb1, statb2;
+ struct printer myprinter, *pp = &myprinter;
+
+ printer = NULL;
+ euid = geteuid();
+ uid = getuid();
+ seteuid(uid);
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
+ signal(SIGHUP, cleanup);
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ signal(SIGINT, cleanup);
+ if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
+ signal(SIGQUIT, cleanup);
+ if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
+ signal(SIGTERM, cleanup);
+
+ name = argv[0];
+ gethostname(host, sizeof(host));
+ openlog("lpd", 0, LOG_LPR);
+
+ errs = 0;
+ while ((c = getopt(argc, argv,
+ ":#:1:2:3:4:C:J:L:P:T:U:Z:cdfghi:lnmprstvw:"))
+ != -1)
+ switch (c) {
+ case '#': /* n copies */
+ i = strtol(optarg, &p, 10);
+ if (*p)
+ errx(1, "Bad argument to -#, number expected");
+ if (i > 0)
+ ncopies = i;
+ break;
+
+ case '1': /* troff fonts */
+ case '2':
+ case '3':
+ case '4':
+ fonts[optopt - '1'] = optarg;
+ break;
+
+ case 'C': /* classification spec */
+ hdr++;
+ class = optarg;
+ break;
+
+ case 'J': /* job name */
+ hdr++;
+ jobname = optarg;
+ break;
+
+ case 'P': /* specifiy printer name */
+ printer = optarg;
+ break;
+
+ case 'L': /* pr's locale */
+ locale = optarg;
+ break;
+
+ case 'T': /* pr's title line */
+ title = optarg;
+ break;
+
+ case 'U': /* user name */
+ hdr++;
+ Uflag = optarg;
+ break;
+
+ case 'Z':
+ Zflag = optarg;
+ break;
+
+ case 'c': /* print cifplot output */
+ case 'd': /* print tex output (dvi files) */
+ case 'g': /* print graph(1G) output */
+ case 'l': /* literal output */
+ case 'n': /* print ditroff output */
+ case 't': /* print troff output (cat files) */
+ case 'p': /* print using ``pr'' */
+ case 'v': /* print vplot output */
+ format = optopt;
+ break;
+
+ case 'f': /* print fortran output */
+ format = 'r';
+ break;
+
+ case 'h': /* nulifiy header page */
+ hdr = 0;
+ break;
+
+ case 'i': /* indent output */
+ iflag++;
+ indent = strtol(optarg, &p, 10);
+ if (*p)
+ errx(1, "Bad argument to -i, number expected");
+ break;
+
+ case 'm': /* send mail when done */
+ mailflg++;
+ break;
+
+ case 'q': /* just queue job */
+ qflag++;
+ break;
+
+ case 'r': /* remove file when done */
+ rflag++;
+ break;
+
+ case 's': /* try to link files */
+ sflag++;
+ break;
+
+ case 'w': /* versatec page width */
+ width = optarg;
+ break;
+
+ case ':': /* catch "missing argument" error */
+ if (optopt == 'i') {
+ iflag++; /* -i without args is valid */
+ indent = 8;
+ } else
+ errs++;
+ break;
+
+ default:
+ errs++;
+ }
+ argc -= optind;
+ argv += optind;
+ if (errs)
+ usage();
+ if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
+ printer = DEFLP;
+ chkprinter(printer, pp);
+ if (pp->no_copies && ncopies > 1)
+ errx(1, "multiple copies are not allowed");
+ if (pp->max_copies > 0 && ncopies > pp->max_copies)
+ errx(1, "only %ld copies are allowed", pp->max_copies);
+ /*
+ * Get the identity of the person doing the lpr using the same
+ * algorithm as lprm. Actually, not quite -- lprm will override
+ * the login name with "root" if the user is running as root;
+ * the daemon actually checks for the string "root" in its
+ * permission checking. Sigh.
+ */
+ userid = getuid();
+ if (Uflag) {
+ if (userid != 0 && userid != pp->daemon_user)
+ errx(1, "only privileged users may use the `-U' flag");
+ person = Uflag;
+ } else {
+ person = getlogin();
+ if (userid != pp->daemon_user || person == 0) {
+ if ((pw = getpwuid(userid)) == NULL)
+ errx(1, "Who are you?");
+ person = pw->pw_name;
+ }
+ }
+
+ /*
+ * Check for restricted group access.
+ */
+ if (pp->restrict_grp != NULL && userid != pp->daemon_user) {
+ if ((gptr = getgrnam(pp->restrict_grp)) == NULL)
+ errx(1, "Restricted group specified incorrectly");
+ if (gptr->gr_gid != getgid()) {
+ while (*gptr->gr_mem != NULL) {
+ if ((strcmp(person, *gptr->gr_mem)) == 0)
+ break;
+ gptr->gr_mem++;
+ }
+ if (*gptr->gr_mem == NULL)
+ errx(1, "Not a member of the restricted group");
+ }
+ }
+ /*
+ * Check to make sure queuing is enabled if userid is not root.
+ */
+ lock_file_name(pp, buf, sizeof buf);
+ if (userid && stat(buf, &stb) == 0 && (stb.st_mode & LFM_QUEUE_DIS))
+ errx(1, "Printer queue is disabled");
+ /*
+ * Initialize the control file.
+ */
+ mktemps(pp);
+ tfd = nfile(tfname);
+ seteuid(euid);
+ (void) fchown(tfd, pp->daemon_user, -1);
+ /* owned by daemon for protection */
+ seteuid(uid);
+ card('H', host);
+ card('P', person);
+ card('C', class);
+ if (hdr && !pp->no_header) {
+ if (jobname == NULL) {
+ if (argc == 0)
+ jobname = "stdin";
+ else
+ jobname = ((arg = strrchr(argv[0], '/'))
+ ? arg + 1 : argv[0]);
+ }
+ card('J', jobname);
+ card('L', person);
+ }
+ if (format != 'p' && Zflag != 0)
+ card('Z', Zflag);
+ if (iflag)
+ card('I', itoa(indent));
+ if (mailflg)
+ card('M', person);
+ if (format == 't' || format == 'n' || format == 'd')
+ for (i = 0; i < 4; i++)
+ if (fonts[i] != NULL)
+ card('1'+i, fonts[i]);
+ if (width != NULL)
+ card('W', width);
+ /*
+ * XXX
+ * Our use of `Z' here is incompatible with LPRng's
+ * use. We assume that the only use of our existing
+ * `Z' card is as shown for `p' format (pr) files.
+ */
+ if (format == 'p') {
+ char *s;
+
+ if (locale)
+ card('Z', locale);
+ else if ((s = setlocale(LC_TIME, "")) != NULL)
+ card('Z', s);
+ }
+
+ /*
+ * Read the files and spool them.
+ */
+ if (argc == 0)
+ copy(pp, 0, " ");
+ else while (argc--) {
+ if (argv[0][0] == '-' && argv[0][1] == '\0') {
+ /* use stdin */
+ copy(pp, 0, " ");
+ argv++;
+ continue;
+ }
+ if ((f = test(arg = *argv++)) < 0)
+ continue; /* file unreasonable */
+
+ if (sflag && (cp = linked(arg)) != NULL) {
+ (void) snprintf(buf, sizeof(buf), "%d %d", statb.st_dev,
+ statb.st_ino);
+ card('S', buf);
+ if (format == 'p')
+ card('T', title ? title : arg);
+ for (i = 0; i < ncopies; i++)
+ card(format, &dfname[inchar-2]);
+ card('U', &dfname[inchar-2]);
+ if (f)
+ card('U', cp);
+ card('N', arg);
+ dfname[inchar]++;
+ nact++;
+ continue;
+ }
+ if (sflag)
+ printf("%s: %s: not linked, copying instead\n", name, arg);
+
+ if (f) {
+ /*
+ * The user wants the file removed after it is copied
+ * to the spool area, so see if the file can be moved
+ * instead of copy/unlink'ed. This is much faster and
+ * uses less spool space than copying the file. This
+ * can be very significant when running services like
+ * samba, pcnfs, CAP, et al.
+ */
+ seteuid(euid);
+ didlink = 0;
+ /*
+ * There are several things to check to avoid any
+ * security issues. Some of these are redundant
+ * under BSD's, but are necessary when lpr is built
+ * under some other OS's (which I do do...)
+ */
+ if (lstat(arg, &statb1) < 0)
+ goto nohardlink;
+ if (S_ISLNK(statb1.st_mode))
+ goto nohardlink;
+ if (link(arg, dfname) != 0)
+ goto nohardlink;
+ didlink = 1;
+ /*
+ * Make sure the user hasn't tried to trick us via
+ * any race conditions
+ */
+ if (lstat(dfname, &statb2) < 0)
+ goto nohardlink;
+ if (statb1.st_dev != statb2.st_dev)
+ goto nohardlink;
+ if (statb1.st_ino != statb2.st_ino)
+ goto nohardlink;
+ /*
+ * Skip if the file already had multiple hard links,
+ * because changing the owner and access-bits would
+ * change ALL versions of the file
+ */
+ if (statb2.st_nlink > 2)
+ goto nohardlink;
+ /*
+ * If we can access and remove the original file
+ * without special setuid-ness then this method is
+ * safe. Otherwise, abandon the move and fall back
+ * to the (usual) copy method.
+ */
+ seteuid(uid);
+ ret = access(dfname, R_OK);
+ if (ret == 0)
+ ret = unlink(arg);
+ seteuid(euid);
+ if (ret != 0)
+ goto nohardlink;
+ /*
+ * Unlink of user file was successful. Change the
+ * owner and permissions, add entries to the control
+ * file, and skip the file copying step.
+ */
+ chown(dfname, pp->daemon_user, getegid());
+ chmod(dfname, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+ seteuid(uid);
+ if (format == 'p')
+ card('T', title ? title : arg);
+ for (i = 0; i < ncopies; i++)
+ card(format, &dfname[inchar-2]);
+ card('U', &dfname[inchar-2]);
+ card('N', arg);
+ nact++;
+ continue;
+ nohardlink:
+ if (didlink)
+ unlink(dfname);
+ seteuid(uid); /* restore old uid */
+ } /* end: if (f) */
+
+ if ((i = open(arg, O_RDONLY)) < 0) {
+ printf("%s: cannot open %s\n", name, arg);
+ } else {
+ copy(pp, i, arg);
+ (void) close(i);
+ if (f && unlink(arg) < 0)
+ printf("%s: %s: not removed\n", name, arg);
+ }
+ }
+
+ if (nact) {
+ (void) close(tfd);
+ tfname[inchar]--;
+ /*
+ * Touch the control file to fix position in the queue.
+ */
+ seteuid(euid);
+ if ((tfd = open(tfname, O_RDWR)) >= 0) {
+ char c;
+
+ if (read(tfd, &c, 1) == 1 &&
+ lseek(tfd, (off_t)0, 0) == 0 &&
+ write(tfd, &c, 1) != 1) {
+ printf("%s: cannot touch %s\n", name, tfname);
+ tfname[inchar]++;
+ cleanup(0);
+ }
+ (void) close(tfd);
+ }
+ if (link(tfname, cfname) < 0) {
+ printf("%s: cannot rename %s\n", name, cfname);
+ tfname[inchar]++;
+ cleanup(0);
+ }
+ unlink(tfname);
+ seteuid(uid);
+ if (qflag) /* just q things up */
+ exit(0);
+ if (!startdaemon(pp))
+ printf("jobs queued, but cannot start daemon.\n");
+ exit(0);
+ }
+ cleanup(0);
+ return (1);
+ /* NOTREACHED */
+}
+
+/*
+ * Create the file n and copy from file descriptor f.
+ */
+static void
+copy(pp, f, n)
+ const struct printer *pp;
+ int f;
+ char n[];
+{
+ register int fd, i, nr, nc;
+ char buf[BUFSIZ];
+
+ if (format == 'p')
+ card('T', title ? title : n);
+ for (i = 0; i < ncopies; i++)
+ card(format, &dfname[inchar-2]);
+ card('U', &dfname[inchar-2]);
+ card('N', n);
+ fd = nfile(dfname);
+ nr = nc = 0;
+ while ((i = read(f, buf, BUFSIZ)) > 0) {
+ if (write(fd, buf, i) != i) {
+ printf("%s: %s: temp file write error\n", name, n);
+ break;
+ }
+ nc += i;
+ if (nc >= BUFSIZ) {
+ nc -= BUFSIZ;
+ nr++;
+ if (pp->max_blocks > 0 && nr > pp->max_blocks) {
+ printf("%s: %s: copy file is too large\n",
+ name, n);
+ break;
+ }
+ }
+ }
+ (void) close(fd);
+ if (nc==0 && nr==0)
+ printf("%s: %s: empty input file\n", name, f ? n : "stdin");
+ else
+ nact++;
+}
+
+/*
+ * Try and link the file to dfname. Return a pointer to the full
+ * path name if successful.
+ */
+static char *
+linked(file)
+ register char *file;
+{
+ register char *cp;
+ static char buf[MAXPATHLEN];
+ register int ret;
+
+ if (*file != '/') {
+ if (getcwd(buf, sizeof(buf)) == NULL)
+ return(NULL);
+ while (file[0] == '.') {
+ switch (file[1]) {
+ case '/':
+ file += 2;
+ continue;
+ case '.':
+ if (file[2] == '/') {
+ if ((cp = strrchr(buf, '/')) != NULL)
+ *cp = '\0';
+ file += 3;
+ continue;
+ }
+ }
+ break;
+ }
+ strncat(buf, "/", sizeof(buf) - strlen(buf) - 1);
+ strncat(buf, file, sizeof(buf) - strlen(buf) - 1);
+ file = buf;
+ }
+ seteuid(euid);
+ ret = symlink(file, dfname);
+ seteuid(uid);
+ return(ret ? NULL : file);
+}
+
+/*
+ * Put a line into the control file.
+ */
+static void
+card(c, p2)
+ register int c;
+ register char *p2;
+{
+ char buf[BUFSIZ];
+ register char *p1 = buf;
+ register int len = 2;
+
+ *p1++ = c;
+ while ((c = *p2++) != '\0' && len < sizeof(buf)) {
+ *p1++ = (c == '\n') ? ' ' : c;
+ len++;
+ }
+ *p1++ = '\n';
+ write(tfd, buf, len);
+}
+
+/*
+ * Create a new file in the spool directory.
+ */
+static int
+nfile(n)
+ char *n;
+{
+ register int f;
+ int oldumask = umask(0); /* should block signals */
+
+ seteuid(euid);
+ f = open(n, O_WRONLY | O_EXCL | O_CREAT, FILMOD);
+ (void) umask(oldumask);
+ if (f < 0) {
+ printf("%s: cannot create %s\n", name, n);
+ cleanup(0);
+ }
+ if (fchown(f, userid, -1) < 0) {
+ printf("%s: cannot chown %s\n", name, n);
+ cleanup(0); /* cleanup does exit */
+ }
+ seteuid(uid);
+ if (++n[inchar] > 'z') {
+ if (++n[inchar-2] == 't') {
+ printf("too many files - break up the job\n");
+ cleanup(0);
+ }
+ n[inchar] = 'A';
+ } else if (n[inchar] == '[')
+ n[inchar] = 'a';
+ return(f);
+}
+
+/*
+ * Cleanup after interrupts and errors.
+ */
+static void
+cleanup(signo)
+ int signo;
+{
+ register int i;
+
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ i = inchar;
+ seteuid(euid);
+ if (tfname)
+ do
+ unlink(tfname);
+ while (tfname[i]-- != 'A');
+ if (cfname)
+ do
+ unlink(cfname);
+ while (cfname[i]-- != 'A');
+ if (dfname)
+ do {
+ do
+ unlink(dfname);
+ while (dfname[i]-- != 'A');
+ dfname[i] = 'z';
+ } while (dfname[i-2]-- != 'd');
+ exit(1);
+}
+
+/*
+ * Test to see if this is a printable file.
+ * Return -1 if it is not, 0 if its printable, and 1 if
+ * we should remove it after printing.
+ */
+static int
+test(file)
+ char *file;
+{
+ struct exec execb;
+ char *path;
+ register int fd;
+ register char *cp;
+
+ if (access(file, 4) < 0) {
+ printf("%s: cannot access %s\n", name, file);
+ return(-1);
+ }
+ if (stat(file, &statb) < 0) {
+ printf("%s: cannot stat %s\n", name, file);
+ return(-1);
+ }
+ if ((statb.st_mode & S_IFMT) == S_IFDIR) {
+ printf("%s: %s is a directory\n", name, file);
+ return(-1);
+ }
+ if (statb.st_size == 0) {
+ printf("%s: %s is an empty file\n", name, file);
+ return(-1);
+ }
+ if ((fd = open(file, O_RDONLY)) < 0) {
+ printf("%s: cannot open %s\n", name, file);
+ return(-1);
+ }
+ /*
+ * XXX Shall we add a similar test for ELF?
+ */
+ if (read(fd, &execb, sizeof(execb)) == sizeof(execb) &&
+ !N_BADMAG(execb)) {
+ printf("%s: %s is an executable program", name, file);
+ goto error1;
+ }
+ (void) close(fd);
+ if (rflag) {
+ if ((cp = strrchr(file, '/')) == NULL) {
+ if (checkwriteperm(file,".") == 0)
+ return(1);
+ } else {
+ if (cp == file) {
+ fd = checkwriteperm(file,"/");
+ } else {
+ path = alloca(strlen(file) + 1);
+ strcpy(path,file);
+ *cp = '\0';
+ fd = checkwriteperm(path,file);
+ *cp = '/';
+ }
+ if (fd == 0)
+ return(1);
+ }
+ printf("%s: %s: is not removable by you\n", name, file);
+ }
+ return(0);
+
+error1:
+ printf(" and is unprintable\n");
+ (void) close(fd);
+ return(-1);
+}
+
+static int
+checkwriteperm(file, directory)
+ char *file, *directory;
+{
+ struct stat stats;
+ if (access(directory, W_OK) == 0) {
+ stat(directory, &stats);
+ if (stats.st_mode & S_ISVTX) {
+ stat(file, &stats);
+ if(stats.st_uid == userid) {
+ return(0);
+ }
+ } else return(0);
+ }
+ return(-1);
+}
+
+/*
+ * itoa - integer to string conversion
+ */
+static char *
+itoa(i)
+ register int i;
+{
+ static char b[10] = "########";
+ register char *p;
+
+ p = &b[8];
+ do
+ *p-- = i%10 + '0';
+ while (i /= 10);
+ return(++p);
+}
+
+/*
+ * Perform lookup for printer name or abbreviation --
+ */
+static void
+chkprinter(s, pp)
+ char *s;
+ struct printer *pp;
+{
+ int status;
+
+ init_printer(pp);
+ status = getprintcap(s, pp);
+ switch(status) {
+ case PCAPERR_OSERR:
+ case PCAPERR_TCLOOP:
+ errx(1, "%s: %s", s, pcaperr(status));
+ case PCAPERR_NOTFOUND:
+ errx(1, "%s: unknown printer", s);
+ case PCAPERR_TCOPEN:
+ warnx("%s: unresolved tc= reference(s)", s);
+ }
+}
+
+/*
+ * Tell the user what we wanna get.
+ */
+static void
+usage()
+{
+ fprintf(stderr, "%s\n",
+"usage: lpr [-Pprinter] [-#num] [-C class] [-J job] [-T title] [-U user]\n"
+ "\t[-Z daemon-options] [-i[numcols]] [-i[numcols]] [-1234 font]\n"
+ "\t[-L locale] [-wnum] [-cdfghlnmprstv] [name ...]");
+ exit(1);
+}
+
+
+/*
+ * Make the temp files.
+ */
+static void
+mktemps(pp)
+ const struct printer *pp;
+{
+ register int len, fd, n;
+ register char *cp;
+ char buf[BUFSIZ];
+
+ (void) snprintf(buf, sizeof(buf), "%s/.seq", pp->spool_dir);
+ seteuid(euid);
+ if ((fd = open(buf, O_RDWR|O_CREAT, 0661)) < 0) {
+ printf("%s: cannot create %s\n", name, buf);
+ exit(1);
+ }
+ if (flock(fd, LOCK_EX)) {
+ printf("%s: cannot lock %s\n", name, buf);
+ exit(1);
+ }
+ seteuid(uid);
+ n = 0;
+ if ((len = read(fd, buf, sizeof(buf))) > 0) {
+ for (cp = buf; len--; ) {
+ if (*cp < '0' || *cp > '9')
+ break;
+ n = n * 10 + (*cp++ - '0');
+ }
+ }
+ len = strlen(pp->spool_dir) + strlen(host) + 8;
+ tfname = lmktemp(pp, "tf", n, len);
+ cfname = lmktemp(pp, "cf", n, len);
+ dfname = lmktemp(pp, "df", n, len);
+ inchar = strlen(pp->spool_dir) + 3;
+ n = (n + 1) % 1000;
+ (void) lseek(fd, (off_t)0, 0);
+ snprintf(buf, sizeof(buf), "%03d\n", n);
+ (void) write(fd, buf, strlen(buf));
+ (void) close(fd); /* unlocks as well */
+}
+
+/*
+ * Make a temp file name.
+ */
+static char *
+lmktemp(pp, id, num, len)
+ const struct printer *pp;
+ char *id;
+ int num, len;
+{
+ register char *s;
+
+ if ((s = malloc(len)) == NULL)
+ errx(1, "out of memory");
+ (void) snprintf(s, len, "%s/%sA%03d%s", pp->spool_dir, id, num, host);
+ return(s);
+}
diff --git a/usr.sbin/lpr/lpr/printcap.5 b/usr.sbin/lpr/lpr/printcap.5
new file mode 100644
index 0000000..61850a5
--- /dev/null
+++ b/usr.sbin/lpr/lpr/printcap.5
@@ -0,0 +1,398 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)printcap.5 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd October 11, 2000
+.Dt PRINTCAP 5
+.Os BSD 4.2
+.Sh NAME
+.Nm printcap
+.Nd printer capability data base
+.Sh SYNOPSIS
+.Nm printcap
+.Sh DESCRIPTION
+The
+.Nm Printcap
+function
+is a simplified version of the
+.Xr termcap 5
+data base
+used to describe line printers. The spooling system accesses the
+.Nm printcap
+file every time it is used, allowing dynamic
+addition and deletion of printers. Each entry in the data base
+is used to describe one printer. This data base may not be
+substituted for, as is possible for
+.Xr termcap 5 ,
+because it may allow accounting to be bypassed.
+.Pp
+The default printer is normally
+.Em lp ,
+though the environment variable
+.Ev PRINTER
+may be used to override this. Each spooling utility supports an option,
+.Fl P Ar printer ,
+to allow explicit naming of a destination printer.
+.Pp
+Refer to the
+.%T "4.3 BSD Line Printer Spooler Manual"
+for a complete discussion on how to setup the database for a given printer.
+.Sh CAPABILITIES
+Refer to
+.Xr termcap 5
+for a description of the file layout.
+.Bl -column Namexxx Typexx "/var/spool/lpdxxxxx"
+.Sy Name Type Default Description
+.It "af str" Ta Dv NULL Ta No "name of accounting file"
+.It "br num none if lp is a tty, set the baud rate"
+.Pf ( Xr ioctl 2
+call)
+.It "cf str" Ta Dv NULL Ta No "cifplot data filter"
+.It "ct num 120 TCP connection timeout in seconds"
+.It "df str" Ta Dv NULL Ta No "tex data filter"
+.Pf ( Tn DVI
+format)
+.It "ff str" Ta So Li \ef Sc Ta No "string to send for a form feed"
+.It "fo bool false print a form feed when device is opened"
+.It "gf str" Ta Dv NULL Ta No "graph data filter"
+.Pf ( Xr plot 3
+format
+.It "hl bool false print the burst header page last"
+.It "ic bool false driver supports (non standard) ioctl to indent printout"
+.It "if str" Ta Dv NULL Ta No "name of text filter which does accounting"
+.It "lf str" Ta Pa /dev/console Ta No "error logging file name"
+.It "lo str" Ta Pa lock Ta No "name of lock file"
+.It "lp str" Ta Pa /dev/lp Ta No "device name to open for output"
+.It "ms str" Ta Dv NULL Ta No "if lp is a tty, a comma-separated, "
+.Xr stty 1
+-like list describing the tty modes
+.It "mx num 1000 maximum file size (in"
+.Dv BUFSIZ
+blocks), zero = unlimited
+.It "nd str" Ta Dv NULL Ta No "next directory for list of queues (unimplemented)"
+.It "nf str" Ta Dv NULL Ta No "ditroff data filter (device independent troff)"
+.It "of str" Ta Dv NULL Ta No "name of output filtering program"
+.It "pc num 200 price per foot or page in hundredths of cents"
+.It "pl num 66 page length (in lines)"
+.It "pw num 132 page width (in characters)"
+.It "px num 0 page width in pixels (horizontal)"
+.It "py num 0 page length in pixels (vertical)"
+.It "rf str" Ta Dv NULL Ta No "filter for printing"
+.Tn FORTRAN
+style text files
+.It "rg str" Ta Dv NULL Ta No "restricted group. Only members of group allowed access"
+.It "rm str" Ta Dv NULL Ta No "machine name for remote printer"
+.It "rp str ``lp'' remote printer name argument"
+.It "rs bool false restrict remote users to those with local accounts"
+.It "rw bool false open the printer device for reading and writing"
+.It "sb bool false short banner (one line only)"
+.It "sc bool false suppress multiple copies"
+.It "sd str" Ta Pa /var/spool/lpd Ta No "spool directory"
+.It "sf bool false suppress form feeds"
+.It "sh bool false suppress printing of burst page header"
+.It "sr str" Ta Dv NULL Ta No "file name to hold statistics of each datafile as it is received"
+.It "ss str" Ta Dv NULL Ta No "file name to hold statistics of each datafile as it is sent"
+.It "st str" Ta Pa status Ta No "status file name"
+.It "tf str" Ta Dv NULL Ta No "troff data filter (cat phototypesetter)"
+.It "tr str" Ta Dv NULL Ta No "trailer string to print when queue empties"
+.It "vf str" Ta Dv NULL Ta No "raster image filter"
+.El
+.Pp
+Each two-letter capability has a human-readable alternate name.
+.Bl -column "Short form" "Long form"
+.Sy "Short form Long form"
+.It "af acct.file"
+.It "br tty.rate"
+.It "cf filt.cifplot"
+.It "ct remote.timeout"
+.It "df filt.dvi"
+.It "du daemon.user"
+.It "ff job.formfeed"
+.It "fo job.topofform"
+.It "gf filt.plot"
+.It "hl banner.last"
+.It "if filt.input"
+.It "lf spool.log"
+.It "lo spool.lock"
+.It "lp tty.device"
+.It "mc max.copies"
+.It "ms tty.mode"
+.It "mx max.blocks"
+.It "nf filt.ditroff"
+.It "of filt.output"
+.It "pc acct.price"
+.It "pl page.length"
+.It "pw page.width"
+.It "px page.pwidth"
+.It "py page.plength"
+.It "rf filt.fortran"
+.It "rg daemon.restrictgrp"
+.It "rm remote.host"
+.It "rp remote.queue"
+.It "rs daemon.restricted"
+.It "rw tty.rw"
+.It "sb banner.short"
+.It "sc job.no_copies"
+.It "sd spool.dir"
+.It "sf job.no_formfeed"
+.It "sh banner.disable"
+.It "sr stat.recv"
+.It "ss stat.send"
+.It "st spool.status"
+.It "tr job.trailer"
+.It "vf filt.raster"
+.El
+.Pp
+If the local line printer driver supports indentation, the daemon
+must understand how to invoke it.
+.Sh FILTERS
+The
+.Xr lpd 8
+daemon creates a pipeline of
+.Em filters
+to process files for various printer types.
+The filters selected depend on the flags passed to
+.Xr lpr 1 .
+The pipeline set up is:
+.Bd -literal -offset indent
+p pr | if regular text + pr(1)
+none if regular text
+c cf cifplot
+d df DVI (tex)
+g gf plot(3)
+n nf ditroff
+f rf Fortran
+t tf troff
+v vf raster image
+.Ed
+.Pp
+The
+.Sy if
+filter is invoked with arguments:
+.Bd -filled -offset indent
+.Cm if
+.Op Fl c
+.Fl w Ns Ar width
+.Fl l Ns Ar length
+.Fl i Ns Ar indent
+.Fl n Ar login
+.Fl h Ar host acct-file
+.Ed
+.Pp
+The
+.Fl c
+flag is passed only if the
+.Fl l
+flag (pass control characters literally)
+is specified to
+.Xr lpr 1 .
+The
+.Ar Width
+function
+and
+.Ar length
+specify the page width and length
+(from
+.Cm pw
+and
+.Cm pl
+respectively) in characters.
+The
+.Fl n
+and
+.Fl h
+parameters specify the login name and host name of the owner
+of the job respectively.
+The
+.Ar Acct-file
+function
+is passed from the
+.Cm af
+.Nm printcap
+entry.
+.Pp
+If no
+.Cm if
+is specified,
+.Cm of
+is used instead,
+with the distinction that
+.Cm of
+is opened only once,
+while
+.Cm if
+is opened for every individual job.
+Thus,
+.Cm if
+is better suited to performing accounting.
+The
+.Cm of
+is only given the
+.Ar width
+and
+.Ar length
+flags.
+.Pp
+All other filters are called as:
+.Bd -filled -offset indent
+.Nm filter
+.Fl x Ns Ar width
+.Fl y Ns Ar length
+.Fl n Ar login
+.Fl h Ar host acct-file
+.Ed
+.Pp
+where
+.Ar width
+and
+.Ar length
+are represented in pixels,
+specified by the
+.Cm px
+and
+.Cm py
+entries respectively.
+.Pp
+All filters take
+.Em stdin
+as the file,
+.Em stdout
+as the printer,
+may log either to
+.Em stderr
+or using
+.Xr syslog 3 ,
+and must not ignore
+.Dv SIGINT .
+.Sh REMOTE PRINTING
+When printing to a remote printer using
+.Cm rm ,
+it is possible to use either
+.Cm if
+or
+.Cm of .
+If both are specified,
+.Cm of
+is ignored. Both filters behave the same except that they are passed
+different arguments as above. Specifically, the output filter is
+terminated and restarted for each file transmitted. This is necessary
+in order to pass the resulting size to the remote
+.Xr lpd 8 .
+.Pp
+If the
+.Fl p
+flag was passed to
+.Xr lpr 1 ,
+.Xr pr 1
+is not executed locally, but is requested of the remote
+.Xr lpd 8 .
+Any input filtering via
+.Cm if
+will therefore happen before
+.Xr pr 1
+is executed rather than afterwards.
+.Pp
+If
+.Cm lp
+is specified as
+.Em port Ns No @ Ns Em machine
+(and
+.Cm rm
+is not in use), printing will be send directly to the given
+.Em port
+on the given
+.Em machine .
+.Sh TRANSFER STATISTICS
+When a print job is transfered to a remote machine (which might be
+another unix box, or may be a network printer), it may be useful
+to keep statistics on each transfer. The
+.Cm sr
+and
+.Cm ss
+options indicate filenames that lpd should use to store such
+statistics. A statistics line is written for each datafile of a
+job as the file is successfully transferred. The format of the
+line is the same for both the sending and receiving side of a
+transfer.
+.Pp
+Statistics on datafiles being received would be used on a print
+server, if you are interested in network performance between a
+variety of machines which are sending jobs to that print server.
+The print server could collect statistics on the speed of each
+print job as it arrived on the server.
+.Pp
+Statistics on datafiles being sent might be used as a minimal
+accounting record, when you want to know who sent which jobs to a
+remote printer, when they were sent, and how large (in bytes) the
+files were. This will not give include any idea of how many pages
+were printed, because there is no standard way to get that information
+back from a remote (network) printer in this case.
+.Sh LOGGING
+Error messages generated by the line printer programs themselves
+(that is, the
+.Xr lpd 8
+and related programs)
+are logged by
+.Xr syslog 3
+using the
+.Dv LPR
+facility.
+Messages printed on
+.Em stderr
+of one of the filters
+are sent to the corresponding
+.Cm lf
+file.
+The filters may, of course, use
+.Xr syslog 8
+themselves.
+.Pp
+Error messages sent to the console have a carriage return and a line
+feed appended to them, rather than just a line feed.
+.Sh SEE ALSO
+.Xr lpq 1 ,
+.Xr lpr 1 ,
+.Xr lprm 1 ,
+.Xr hosts.lpd 5 ,
+.Xr termcap 5 ,
+.Xr lpc 8 ,
+.Xr lpd 8 ,
+.Xr pac 8
+.Rs
+.%T "4.3 BSD Line Printer Spooler Manual"
+.Re
+.Sh HISTORY
+The
+.Nm
+file format appeared in
+.Bx 4.2 .
diff --git a/usr.sbin/lpr/lprm/Makefile b/usr.sbin/lpr/lprm/Makefile
new file mode 100644
index 0000000..abeac25
--- /dev/null
+++ b/usr.sbin/lpr/lprm/Makefile
@@ -0,0 +1,14 @@
+# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $FreeBSD$
+
+PROG= lprm
+CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS}
+.PATH: ${.CURDIR}/../common_source
+DPADD= ${LIBLPR}
+LDADD= ${LIBLPR}
+
+BINGRP= daemon
+BINMODE=6555
+BINDIR= /usr/bin
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lprm/lprm.1 b/usr.sbin/lpr/lprm/lprm.1
new file mode 100644
index 0000000..1a17ea6
--- /dev/null
+++ b/usr.sbin/lpr/lprm/lprm.1
@@ -0,0 +1,146 @@
+.\" Copyright (c) 1983, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)lprm.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD$
+.\"
+.Dd June 6, 1993
+.Dt LPRM 1
+.Os BSD 4.2
+.Sh NAME
+.Nm lprm
+.Nd remove jobs from the line printer spooling queue
+.Sh SYNOPSIS
+.Nm lprm
+.Op Fl P Ns Ar printer
+.Op Fl
+.Op job # ...
+.Op Ar user ...
+.Sh DESCRIPTION
+.Nm Lprm
+will remove a job, or jobs, from a printer's spool queue.
+Since the spooling directory is protected from users, using
+.Nm
+is normally the only method by which a user may remove a job.
+The owner of a job is determined by the user's login name
+and host name on the machine where the
+.Xr lpr 1
+command was invoked.
+.Pp
+Options and arguments:
+.Bl -tag -width indent
+.It Fl P Ns Ar printer
+Specify the queue associated with a specific
+.Ar printer
+(otherwise the default printer is used).
+.It Fl
+If a single
+.Sq Fl
+is given,
+.Nm
+will remove all jobs which a user
+owns. If the super-user employs this flag, the spool queue will
+be emptied entirely.
+.It Ar user
+Cause
+.Nm
+to attempt to remove any jobs queued belonging to that user
+(or users). This form of invoking
+.Nm
+is useful only to the super-user.
+.It Ar job\ \&#
+A user may dequeue an individual job by specifying its job number.
+This number may be obtained from the
+.Xr lpq 1
+program, e.g.
+.Pp
+.Bd -literal -offset indent
+\&% lpq \-l
+
+1st:ken [job #013ucbarpa]
+ (standard input) 100 bytes
+% lprm 13
+.Ed
+.El
+.Pp
+If neither arguments or options are given,
+.Nm
+will delete the currently active job if it is
+owned by the user who invoked
+.Nm lprm .
+.Pp
+.Nm Lprm
+announces the names of any files it removes and is silent if
+there are no jobs in the queue which match the request list.
+.Pp
+.Nm Lprm
+will kill off an active daemon, if necessary, before removing
+any spooling files. If a daemon is killed, a new one is
+automatically restarted upon completion of file removals.
+.Sh ENVIRONMENT
+If the following environment variable exists, it is utilized by
+.Nm lprm .
+.Bl -tag -width PRINTER
+.It Ev PRINTER
+If the environment variable
+.Ev PRINTER
+exists,
+and a printer has not been specified with the
+.Fl P
+option,
+the default printer is assumed from
+.Ev PRINTER .
+.El
+.Sh FILES
+.Bl -tag -width /var/spool/*/lock/ -compact
+.It Pa /etc/printcap
+Printer characteristics file.
+.It Pa /var/spool/*
+Spooling directories.
+.It Pa /var/spool/*/lock
+Lock file used to obtain the pid of the current
+daemon and the job number of the currently active job.
+.El
+.Sh SEE ALSO
+.Xr lpq 1 ,
+.Xr lpr 1 ,
+.Xr lpd 8
+.Sh DIAGNOSTICS
+``Permission denied" if the user tries to remove files other than his
+own.
+.Sh BUGS
+Since there are race conditions possible in the update of the lock file,
+the currently active job may be incorrectly identified.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/usr.sbin/lpr/lprm/lprm.c b/usr.sbin/lpr/lprm/lprm.c
new file mode 100644
index 0000000..ca52f5d
--- /dev/null
+++ b/usr.sbin/lpr/lprm/lprm.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)lprm.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+/*
+ * lprm - remove the current user's spool entry
+ *
+ * lprm [-] [[job #] [user] ...]
+ *
+ * Using information in the lock file, lprm will kill the
+ * currently active daemon (if necessary), remove the associated files,
+ * and startup a new daemon. Priviledged users may remove anyone's spool
+ * entries, otherwise one can only remove their own.
+ */
+
+#include <sys/param.h>
+
+#include <syslog.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "lp.h"
+#include "lp.local.h"
+
+/*
+ * Stuff for handling job specifications
+ */
+char *person; /* name of person doing lprm */
+int requ[MAXREQUESTS]; /* job number of spool entries */
+int requests; /* # of spool requests */
+char *user[MAXUSERS]; /* users to process */
+int users; /* # of users in user array */
+uid_t uid, euid; /* real and effective user id's */
+
+static char luser[16]; /* buffer for person */
+
+int main __P((int, char *[]));
+static void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *arg, *printer;
+ struct passwd *p;
+ static char root[] = "root";
+
+ printer = NULL;
+ uid = getuid();
+ euid = geteuid();
+ seteuid(uid); /* be safe */
+ name = argv[0];
+ gethostname(host, sizeof(host));
+ openlog("lpd", 0, LOG_LPR);
+
+ /*
+ * Bogus code later checks for string equality between
+ * `person' and "root", so if we are root, better make sure
+ * that code will succeed.
+ */
+ if (getuid() == 0) {
+ person = root;
+ } else if ((person = getlogin()) == NULL) {
+ if ((p = getpwuid(getuid())) == NULL)
+ fatal(0, "Who are you?");
+ if (strlen(p->pw_name) >= sizeof(luser))
+ fatal(0, "Your name is too long");
+ strcpy(luser, p->pw_name);
+ person = luser;
+ }
+ while (--argc) {
+ if ((arg = *++argv)[0] == '-')
+ switch (arg[1]) {
+ case 'P':
+ if (arg[2])
+ printer = &arg[2];
+ else if (argc > 1) {
+ argc--;
+ printer = *++argv;
+ }
+ break;
+ case '\0':
+ if (!users) {
+ users = -1;
+ break;
+ }
+ default:
+ usage();
+ }
+ else {
+ if (users < 0)
+ usage();
+ if (isdigit(arg[0])) {
+ if (requests >= MAXREQUESTS)
+ fatal(0, "Too many requests");
+ requ[requests++] = atoi(arg);
+ } else {
+ if (users >= MAXUSERS)
+ fatal(0, "Too many users");
+ user[users++] = arg;
+ }
+ }
+ }
+ if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
+ printer = DEFLP;
+
+ rmjob(printer);
+ exit(0);
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "usage: lprm [-] [-Pprinter] [[job #] [user] ...]\n");
+ exit(2);
+}
diff --git a/usr.sbin/lpr/lptest/Makefile b/usr.sbin/lpr/lptest/Makefile
new file mode 100644
index 0000000..fe13560
--- /dev/null
+++ b/usr.sbin/lpr/lptest/Makefile
@@ -0,0 +1,5 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lptest
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lptest/lptest.1 b/usr.sbin/lpr/lptest/lptest.1
new file mode 100644
index 0000000..73f9fe9
--- /dev/null
+++ b/usr.sbin/lpr/lptest/lptest.1
@@ -0,0 +1,75 @@
+.\" Copyright (c) 1985, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)lptest.1 8.2 (Berkeley) 12/30/93
+.\" $FreeBSD$
+.\"
+.Dd December 30, 1993
+.Dt LPTEST 1
+.Os BSD 4.3
+.Sh NAME
+.Nm lptest
+.Nd generate lineprinter ripple pattern
+.Sh SYNOPSIS
+.Nm lptest
+.Op Ar length
+.Op Ar count
+.Sh DESCRIPTION
+.Nm Lptest
+writes the traditional "ripple test" pattern on standard output.
+In 96 lines,
+this pattern will print all 96 printable
+.Tn ASCII
+characters
+in each position.
+While originally created to test printers, it is quite
+useful for testing terminals,
+driving terminal ports for debugging purposes,
+or any other task where a quick supply of random data is needed.
+.Pp
+The
+.Ar length
+argument specifies the output line length if the default
+length of 79 is inappropriate.
+.Pp
+The
+.Ar count
+argument specifies the number of output lines to be generated if
+the default count of 200 is inappropriate.
+Note that if
+.Ar count
+is to be specified,
+.Ar length
+must be also be specified.
+.Sh HISTORY
+.Nm Lptest
+appeared in
+.Bx 4.3 .
diff --git a/usr.sbin/lpr/lptest/lptest.c b/usr.sbin/lpr/lptest/lptest.c
new file mode 100644
index 0000000..1cf2206
--- /dev/null
+++ b/usr.sbin/lpr/lptest/lptest.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)lptest.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * lptest -- line printer test program (and other devices).
+ */
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int len, count;
+ register i, j, fc, nc;
+ char outbuf[BUFSIZ];
+
+ setbuf(stdout, outbuf);
+ if (argc >= 2)
+ len = atoi(argv[1]);
+ else
+ len = 79;
+ if (argc >= 3)
+ count = atoi(argv[2]);
+ else
+ count = 200;
+ fc = ' ';
+ for (i = 0; i < count; i++) {
+ if (++fc == 0177)
+ fc = ' ';
+ nc = fc;
+ for (j = 0; j < len; j++) {
+ putchar(nc);
+ if (++nc == 0177)
+ nc = ' ';
+ }
+ putchar('\n');
+ }
+ (void) fflush(stdout);
+ exit(0);
+}
diff --git a/usr.sbin/lpr/pac/Makefile b/usr.sbin/lpr/pac/Makefile
new file mode 100644
index 0000000..2b8d6ed
--- /dev/null
+++ b/usr.sbin/lpr/pac/Makefile
@@ -0,0 +1,11 @@
+# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $FreeBSD$
+
+PROG= pac
+CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS}
+MAN8= pac.8
+.PATH: ${.CURDIR}/../common_source
+DPADD= ${LIBLPR}
+LDADD= ${LIBLPR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/pac/pac.8 b/usr.sbin/lpr/pac/pac.8
new file mode 100644
index 0000000..0fddaec
--- /dev/null
+++ b/usr.sbin/lpr/pac/pac.8
@@ -0,0 +1,107 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)pac.8 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD$
+.\"
+.Dd June 6, 1993
+.Dt PAC 8
+.Os BSD 4.2
+.Sh NAME
+.Nm pac
+.Nd printer/plotter accounting information
+.Sh SYNOPSIS
+.Nm pac
+.Op Fl P Ns Ar printer
+.Op Fl c
+.Op Fl m
+.Op Fl p Ns Ar price
+.Op Fl s
+.Op Fl r
+.Op Ar name ...
+.Sh DESCRIPTION
+.Nm Pac
+reads the printer/plotter accounting files, accumulating the number
+of pages (the usual case) or feet (for raster devices)
+of paper consumed by each user, and printing out
+how much each user consumed in pages or feet and dollars.
+.Pp
+Options and operands available:
+.Bl -tag -width PPprinter
+.It Fl P Ns Ar printer
+Accounting is done for the named printer.
+Normally, accounting is done for the default printer (site dependent) or
+the value of the environment variable
+.Ev PRINTER
+is used.
+.It Fl c
+Cause the output to be sorted by cost; usually the
+output is sorted alphabetically by name.
+.It Fl m
+Cause the host name to be ignored in the accounting file. This
+allows for a user on multiple machines to have all of his printing
+charges grouped together.
+.It Fl p Ns Ar price
+The value
+.Ar price
+is used for the cost in dollars instead of the default value of 0.02
+or the price specified in
+.Pa /etc/printcap .
+.It Fl r
+Reverse the sorting order.
+.It Fl s
+Accounting information is summarized on the
+summary accounting file; this summarization is necessary since on a
+busy system, the accounting file can grow by several lines per day.
+.It Ar names
+Statistics are only printed for user(s)
+.Ar name ;
+usually, statistics are printed for every user who has used any paper.
+.El
+.Sh FILES
+.Bl -tag -width /var/account/?_sum -compact
+.It Pa /var/account/?acct
+raw accounting files
+.It Pa /var/account/?_sum
+summary accounting files
+.It Pa /etc/printcap
+printer capability data base
+.El
+.Sh SEE ALSO
+.Xr printcap 5
+.Sh BUGS
+The relationship between the computed price and reality is
+as yet unknown.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
diff --git a/usr.sbin/lpr/pac/pac.c b/usr.sbin/lpr/pac/pac.c
new file mode 100644
index 0000000..08de114
--- /dev/null
+++ b/usr.sbin/lpr/pac/pac.c
@@ -0,0 +1,462 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)pac.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+/*
+ * Do Printer accounting summary.
+ * Currently, usage is
+ * pac [-Pprinter] [-pprice] [-s] [-r] [-c] [-m] [user ...]
+ * to print the usage information for the named people.
+ */
+
+#include <sys/param.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "lp.h"
+#include "lp.local.h"
+
+static char *acctfile; /* accounting file (input data) */
+static int allflag = 1; /* Get stats on everybody */
+static int errs;
+static int hcount; /* Count of hash entries */
+static int mflag = 0; /* disregard machine names */
+static int pflag = 0; /* 1 if -p on cmd line */
+static float price = 0.02; /* cost per page (or what ever) */
+static long price100; /* per-page cost in 100th of a cent */
+static int reverse; /* Reverse sort order */
+static int sort; /* Sort by cost */
+static char *sumfile; /* summary file */
+static int summarize; /* Compress accounting file */
+
+uid_t uid, euid;
+
+/*
+ * Grossness follows:
+ * Names to be accumulated are hashed into the following
+ * table.
+ */
+
+#define HSHSIZE 97 /* Number of hash buckets */
+
+struct hent {
+ struct hent *h_link; /* Forward hash link */
+ char *h_name; /* Name of this user */
+ float h_feetpages; /* Feet or pages of paper */
+ int h_count; /* Number of runs */
+};
+
+static struct hent *hashtab[HSHSIZE]; /* Hash table proper */
+
+int main __P((int, char **));
+static void account __P((FILE *));
+static int any __P((int, char []));
+static int chkprinter __P((char *));
+static void dumpit __P((void));
+static int hash __P((char []));
+static struct hent *enter __P((char []));
+static struct hent *lookup __P((char []));
+static int qucmp __P((const void *, const void *));
+static void rewrite __P((void));
+static void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *acct;
+ char *cp, *printer;
+
+ printer = NULL;
+ euid = geteuid(); /* these aren't used in pac(1) */
+ uid = getuid();
+ while (--argc) {
+ cp = *++argv;
+ if (*cp++ == '-') {
+ switch(*cp++) {
+ case 'P':
+ /*
+ * Printer name.
+ */
+ printer = cp;
+ continue;
+
+ case 'p':
+ /*
+ * get the price.
+ */
+ price = atof(cp);
+ pflag = 1;
+ continue;
+
+ case 's':
+ /*
+ * Summarize and compress accounting file.
+ */
+ summarize++;
+ continue;
+
+ case 'c':
+ /*
+ * Sort by cost.
+ */
+ sort++;
+ continue;
+
+ case 'm':
+ /*
+ * disregard machine names for each user
+ */
+ mflag = 1;
+ continue;
+
+ case 'r':
+ /*
+ * Reverse sorting order.
+ */
+ reverse++;
+ continue;
+
+ default:
+ usage();
+ }
+ }
+ (void) enter(--cp);
+ allflag = 0;
+ }
+ if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
+ printer = DEFLP;
+ if (!chkprinter(printer)) {
+ printf("pac: unknown printer %s\n", printer);
+ exit(2);
+ }
+
+ if ((acct = fopen(acctfile, "r")) == NULL) {
+ perror(acctfile);
+ exit(1);
+ }
+ account(acct);
+ fclose(acct);
+ if ((acct = fopen(sumfile, "r")) != NULL) {
+ account(acct);
+ fclose(acct);
+ }
+ if (summarize)
+ rewrite();
+ else
+ dumpit();
+ exit(errs);
+}
+
+static void
+usage()
+{
+ fprintf(stderr,
+ "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [-m] [user ...]\n");
+ exit(1);
+}
+
+/*
+ * Read the entire accounting file, accumulating statistics
+ * for the users that we have in the hash table. If allflag
+ * is set, then just gather the facts on everyone.
+ * Note that we must accomodate both the active and summary file
+ * formats here.
+ * Host names are ignored if the -m flag is present.
+ */
+static void
+account(acct)
+ register FILE *acct;
+{
+ char linebuf[BUFSIZ];
+ double t;
+ register char *cp, *cp2;
+ register struct hent *hp;
+ register int ic;
+
+ while (fgets(linebuf, BUFSIZ, acct) != NULL) {
+ cp = linebuf;
+ while (any(*cp, " \t"))
+ cp++;
+ t = atof(cp);
+ while (any(*cp, ".0123456789"))
+ cp++;
+ while (any(*cp, " \t"))
+ cp++;
+ for (cp2 = cp; !any(*cp2, " \t\n"); cp2++)
+ ;
+ ic = atoi(cp2);
+ *cp2 = '\0';
+ if (mflag && strchr(cp, ':'))
+ cp = strchr(cp, ':') + 1;
+ hp = lookup(cp);
+ if (hp == NULL) {
+ if (!allflag)
+ continue;
+ hp = enter(cp);
+ }
+ hp->h_feetpages += t;
+ if (ic)
+ hp->h_count += ic;
+ else
+ hp->h_count++;
+ }
+}
+
+/*
+ * Sort the hashed entries by name or footage
+ * and print it all out.
+ */
+static void
+dumpit()
+{
+ struct hent **base;
+ register struct hent *hp, **ap;
+ register int hno, c, runs;
+ float feet;
+
+ hp = hashtab[0];
+ hno = 1;
+ base = (struct hent **) calloc(sizeof hp, hcount);
+ for (ap = base, c = hcount; c--; ap++) {
+ while (hp == NULL)
+ hp = hashtab[hno++];
+ *ap = hp;
+ hp = hp->h_link;
+ }
+ qsort(base, hcount, sizeof hp, qucmp);
+ printf(" Login pages/feet runs price\n");
+ feet = 0.0;
+ runs = 0;
+ for (ap = base, c = hcount; c--; ap++) {
+ hp = *ap;
+ runs += hp->h_count;
+ feet += hp->h_feetpages;
+ printf("%-24s %7.2f %4d $%6.2f\n", hp->h_name,
+ hp->h_feetpages, hp->h_count, hp->h_feetpages * price);
+ }
+ if (allflag) {
+ printf("\n");
+ printf("%-24s %7.2f %4d $%6.2f\n", "total", feet,
+ runs, feet * price);
+ }
+}
+
+/*
+ * Rewrite the summary file with the summary information we have accumulated.
+ */
+static void
+rewrite()
+{
+ register struct hent *hp;
+ register int i;
+ register FILE *acctf;
+
+ if ((acctf = fopen(sumfile, "w")) == NULL) {
+ warn("%s", sumfile);
+ errs++;
+ return;
+ }
+ for (i = 0; i < HSHSIZE; i++) {
+ hp = hashtab[i];
+ while (hp != NULL) {
+ fprintf(acctf, "%7.2f\t%s\t%d\n", hp->h_feetpages,
+ hp->h_name, hp->h_count);
+ hp = hp->h_link;
+ }
+ }
+ fflush(acctf);
+ if (ferror(acctf)) {
+ warn("%s", sumfile);
+ errs++;
+ }
+ fclose(acctf);
+ if ((acctf = fopen(acctfile, "w")) == NULL)
+ warn("%s", acctfile);
+ else
+ fclose(acctf);
+}
+
+/*
+ * Hashing routines.
+ */
+
+/*
+ * Enter the name into the hash table and return the pointer allocated.
+ */
+
+static struct hent *
+enter(name)
+ char name[];
+{
+ register struct hent *hp;
+ register int h;
+
+ if ((hp = lookup(name)) != NULL)
+ return(hp);
+ h = hash(name);
+ hcount++;
+ hp = (struct hent *) calloc(sizeof *hp, 1);
+ hp->h_name = (char *) calloc(sizeof(char), strlen(name)+1);
+ strcpy(hp->h_name, name);
+ hp->h_feetpages = 0.0;
+ hp->h_count = 0;
+ hp->h_link = hashtab[h];
+ hashtab[h] = hp;
+ return(hp);
+}
+
+/*
+ * Lookup a name in the hash table and return a pointer
+ * to it.
+ */
+
+static struct hent *
+lookup(name)
+ char name[];
+{
+ register int h;
+ register struct hent *hp;
+
+ h = hash(name);
+ for (hp = hashtab[h]; hp != NULL; hp = hp->h_link)
+ if (strcmp(hp->h_name, name) == 0)
+ return(hp);
+ return(NULL);
+}
+
+/*
+ * Hash the passed name and return the index in
+ * the hash table to begin the search.
+ */
+static int
+hash(name)
+ char name[];
+{
+ register int h;
+ register char *cp;
+
+ for (cp = name, h = 0; *cp; h = (h << 2) + *cp++)
+ ;
+ return((h & 0x7fffffff) % HSHSIZE);
+}
+
+/*
+ * Other stuff
+ */
+static int
+any(ch, str)
+ int ch;
+ char str[];
+{
+ register int c = ch;
+ register char *cp = str;
+
+ while (*cp)
+ if (*cp++ == c)
+ return(1);
+ return(0);
+}
+
+/*
+ * The qsort comparison routine.
+ * The comparison is ascii collating order
+ * or by feet of typesetter film, according to sort.
+ */
+static int
+qucmp(a, b)
+ const void *a, *b;
+{
+ register struct hent *h1, *h2;
+ register int r;
+
+ h1 = *(struct hent **)a;
+ h2 = *(struct hent **)b;
+ if (sort)
+ r = h1->h_feetpages < h2->h_feetpages ?
+ -1 : h1->h_feetpages > h2->h_feetpages;
+ else
+ r = strcmp(h1->h_name, h2->h_name);
+ return(reverse ? -r : r);
+}
+
+/*
+ * Perform lookup for printer name or abbreviation --
+ */
+static int
+chkprinter(s)
+ register char *s;
+{
+ int stat;
+ struct printer myprinter, *pp = &myprinter;
+
+ init_printer(&myprinter);
+ stat = getprintcap(s, pp);
+ switch(stat) {
+ case PCAPERR_OSERR:
+ printf("pac: getprintcap: %s\n", pcaperr(stat));
+ exit(3);
+ case PCAPERR_NOTFOUND:
+ return 0;
+ case PCAPERR_TCLOOP:
+ fatal(pp, "%s", pcaperr(stat));
+ }
+ acctfile = pp->acct_file;
+ if (!pflag && pp->price100)
+ price = pp->price100/10000.0;
+ sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5);
+ if (sumfile == NULL)
+ errx(1, "calloc failed");
+ strcpy(sumfile, acctfile);
+ strcat(sumfile, "_sum");
+ return(1);
+}
OpenPOWER on IntegriCloud