2006-05-11 04:22:52 +04:00
|
|
|
/* $NetBSD: printjob.c,v 1.50 2006/05/11 00:22:53 mrg Exp $ */
|
1997-07-17 09:51:18 +04:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
1994-05-18 05:25:37 +04:00
|
|
|
* Copyright (c) 1983, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
1993-03-21 12:45:37 +03:00
|
|
|
*
|
|
|
|
* 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.
|
2003-08-07 15:25:11 +04:00
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
1993-03-21 12:45:37 +03:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
1997-07-17 09:51:18 +04:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
#ifndef lint
|
1997-07-17 09:51:18 +04:00
|
|
|
__COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
|
|
|
|
The Regents of the University of California. All rights reserved.\n");
|
1993-03-21 12:45:37 +03:00
|
|
|
#endif /* not lint */
|
|
|
|
|
1994-05-18 05:25:37 +04:00
|
|
|
#ifndef lint
|
1997-07-10 10:28:58 +04:00
|
|
|
#if 0
|
1997-10-05 15:52:17 +04:00
|
|
|
static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95";
|
1997-07-10 10:28:58 +04:00
|
|
|
#else
|
2006-05-11 04:22:52 +04:00
|
|
|
__RCSID("$NetBSD: printjob.c,v 1.50 2006/05/11 00:22:53 mrg Exp $");
|
1997-07-10 10:28:58 +04:00
|
|
|
#endif
|
1994-05-18 05:25:37 +04:00
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
1994-05-18 05:25:37 +04:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
1997-10-05 15:52:17 +04:00
|
|
|
#include <sys/file.h>
|
1994-05-18 05:25:37 +04:00
|
|
|
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <unistd.h>
|
2004-08-26 17:05:14 +04:00
|
|
|
#include <sys/uio.h>
|
1994-05-18 05:25:37 +04:00
|
|
|
#include <signal.h>
|
1995-10-03 18:02:17 +03:00
|
|
|
#include <termios.h>
|
1994-05-18 05:25:37 +04:00
|
|
|
#include <syslog.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
1997-10-05 19:11:58 +04:00
|
|
|
#include <ctype.h>
|
1993-03-21 12:45:37 +03:00
|
|
|
#include "lp.h"
|
1994-05-18 05:25:37 +04:00
|
|
|
#include "lp.local.h"
|
1993-03-21 12:45:37 +03:00
|
|
|
#include "pathnames.h"
|
1994-05-18 05:25:37 +04:00
|
|
|
#include "extern.h"
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
#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
|
|
|
|
|
- add timeouts to displayq(), rmremote(), sendfile() and response(),
and use these timeout in the lpq, lpd and lprm programs.
these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.
- add a -r flag to lpd to allow `of' filters for remote jobs.
i know there are ways around this, but i just don't care.
- add a -f flag to lpf to add missing carriage returns.
useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text. stair-stepped text is no fun.
- implement child process accounting: we just have a limit on the number
of children we can have (settable by the sysadmin), and we sleep when
this number is reached. this can reduce malicious not-so-malicious
attacks on the print server by a rogue remote client..
- use setproctitle() where appropriate so the sysadmin has a clue about
what each of the lpd's here are doing.
this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.
i have been running these changes in production for about a year.
1999-12-07 17:54:44 +03:00
|
|
|
static dev_t fdev; /* device of file pointed to by symlink */
|
|
|
|
static ino_t fino; /* inode of file pointed to by symlink */
|
1994-05-18 05:25:37 +04:00
|
|
|
static FILE *cfp; /* control file */
|
- add timeouts to displayq(), rmremote(), sendfile() and response(),
and use these timeout in the lpq, lpd and lprm programs.
these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.
- add a -r flag to lpd to allow `of' filters for remote jobs.
i know there are ways around this, but i just don't care.
- add a -f flag to lpf to add missing carriage returns.
useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text. stair-stepped text is no fun.
- implement child process accounting: we just have a limit on the number
of children we can have (settable by the sysadmin), and we sleep when
this number is reached. this can reduce malicious not-so-malicious
attacks on the print server by a rogue remote client..
- use setproctitle() where appropriate so the sysadmin has a clue about
what each of the lpd's here are doing.
this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.
i have been running these changes in production for about a year.
1999-12-07 17:54:44 +03:00
|
|
|
static int child; /* id of any filters */
|
|
|
|
static int lfd; /* lock file descriptor */
|
|
|
|
static int ofd; /* output filter file descriptor */
|
|
|
|
static int ofilter; /* id of output filter, if any */
|
2002-07-09 05:12:35 +04:00
|
|
|
static int pfd; /* printer file descriptor */
|
- add timeouts to displayq(), rmremote(), sendfile() and response(),
and use these timeout in the lpq, lpd and lprm programs.
these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.
- add a -r flag to lpd to allow `of' filters for remote jobs.
i know there are ways around this, but i just don't care.
- add a -f flag to lpf to add missing carriage returns.
useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text. stair-stepped text is no fun.
- implement child process accounting: we just have a limit on the number
of children we can have (settable by the sysadmin), and we sleep when
this number is reached. this can reduce malicious not-so-malicious
attacks on the print server by a rogue remote client..
- use setproctitle() where appropriate so the sysadmin has a clue about
what each of the lpd's here are doing.
this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.
i have been running these changes in production for about a year.
1999-12-07 17:54:44 +03:00
|
|
|
static int pid; /* pid of lpd process */
|
|
|
|
static int prchild; /* id of pr process */
|
|
|
|
static char title[80]; /* ``pr'' title */
|
|
|
|
static int tof; /* true if at top of form */
|
1994-05-18 05:25:37 +04:00
|
|
|
|
|
|
|
static char class[32]; /* classification field */
|
|
|
|
static char fromhost[32]; /* user's host machine */
|
|
|
|
/* indentation size in static characters */
|
|
|
|
static char indent[10] = "-i0";
|
|
|
|
static char jobname[100]; /* job or file name */
|
|
|
|
static char length[10] = "-l"; /* page length in lines */
|
|
|
|
static char logname[32]; /* user's login name */
|
|
|
|
static char pxlength[10] = "-y"; /* page length in pixels */
|
|
|
|
static char pxwidth[10] = "-x"; /* page width in pixels */
|
|
|
|
static char tempfile[] = "errsXXXXXX"; /* file name for filter output */
|
2002-09-03 22:35:11 +04:00
|
|
|
static char tempremote[] = "remoteXXXXXX"; /* file name for remote filter */
|
1994-05-18 05:25:37 +04:00
|
|
|
static char width[10] = "-w"; /* page width in static characters */
|
|
|
|
|
2002-07-14 19:27:58 +04:00
|
|
|
static void abortpr(int);
|
|
|
|
static void banner(char *, char *);
|
|
|
|
static int dofork(int);
|
|
|
|
static int dropit(int);
|
|
|
|
static void init(void);
|
2002-09-03 22:35:11 +04:00
|
|
|
static void setup_ofilter(int);
|
|
|
|
static void close_ofilter(void);
|
2002-07-14 19:27:58 +04:00
|
|
|
static void openpr(void);
|
2006-01-20 20:30:00 +03:00
|
|
|
static void opennet(void);
|
2002-07-14 19:27:58 +04:00
|
|
|
static void opentty(void);
|
|
|
|
static void openrem(void);
|
|
|
|
static int print(int, char *);
|
|
|
|
static int printit(char *);
|
2002-09-04 17:49:20 +04:00
|
|
|
static void pstatus(const char *, ...)
|
|
|
|
__attribute__((__format__(__printf__, 1, 2)));
|
2002-07-14 19:27:58 +04:00
|
|
|
static char response(void);
|
|
|
|
static void scan_out(int, char *, int);
|
|
|
|
static char *scnline(int, char *, int);
|
|
|
|
static int sendfile(int, char *);
|
|
|
|
static int sendit(char *);
|
|
|
|
static void sendmail(char *, int);
|
|
|
|
static void setty(void);
|
|
|
|
static void alarmer(int);
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1994-05-18 05:25:37 +04:00
|
|
|
void
|
2001-10-09 06:15:37 +04:00
|
|
|
printjob(void)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
|
|
|
struct stat stb;
|
1997-10-05 19:11:58 +04:00
|
|
|
struct queue *q, **qp;
|
1993-03-21 12:45:37 +03:00
|
|
|
struct queue **queue;
|
2002-10-26 05:47:52 +04:00
|
|
|
int i, nitems, fd;
|
1997-10-05 15:52:17 +04:00
|
|
|
off_t pidoff;
|
|
|
|
int errcnt, count = 0;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
init(); /* set up capabilities */
|
2002-10-26 05:47:52 +04:00
|
|
|
(void)write(STDOUT_FILENO, "", 1); /* ack that daemon is started */
|
|
|
|
|
|
|
|
/* set up log file */
|
|
|
|
if ((fd = open(LF, O_WRONLY|O_APPEND, 0664)) < 0) {
|
1993-03-21 12:45:37 +03:00
|
|
|
syslog(LOG_ERR, "%s: %m", LF);
|
2002-10-26 05:47:52 +04:00
|
|
|
fd = open(_PATH_DEVNULL, O_WRONLY);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2002-10-26 05:47:52 +04:00
|
|
|
if (fd > 0) {
|
|
|
|
(void) dup2(fd, STDERR_FILENO);
|
|
|
|
(void) close(fd);
|
|
|
|
} else
|
|
|
|
(void)close(STDERR_FILENO);
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
setgid(getegid());
|
|
|
|
pid = getpid(); /* for use with lprm */
|
|
|
|
setpgrp(0, pid);
|
|
|
|
signal(SIGHUP, abortpr);
|
|
|
|
signal(SIGINT, abortpr);
|
|
|
|
signal(SIGQUIT, abortpr);
|
|
|
|
signal(SIGTERM, abortpr);
|
|
|
|
|
2005-11-27 15:52:30 +03:00
|
|
|
(void)mktemp(tempfile); /* XXX */
|
|
|
|
(void)mktemp(tempremote); /* XXX */
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* uses short form file names
|
|
|
|
*/
|
|
|
|
if (chdir(SD) < 0) {
|
|
|
|
syslog(LOG_ERR, "%s: %m", SD);
|
|
|
|
exit(1);
|
|
|
|
}
|
1999-12-11 05:01:18 +03:00
|
|
|
if (stat(LO, &stb) == 0 && (stb.st_mode & S_IXUSR))
|
1993-03-21 12:45:37 +03:00
|
|
|
exit(0); /* printing disabled */
|
|
|
|
lfd = open(LO, O_WRONLY|O_CREAT, 0644);
|
|
|
|
if (lfd < 0) {
|
|
|
|
syslog(LOG_ERR, "%s: %s: %m", printer, LO);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
|
2002-01-21 17:42:26 +03:00
|
|
|
if (errno == EWOULDBLOCK) /* active daemon present */
|
1993-03-21 12:45:37 +03:00
|
|
|
exit(0);
|
|
|
|
syslog(LOG_ERR, "%s: %s: %m", printer, LO);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
ftruncate(lfd, 0);
|
|
|
|
/*
|
|
|
|
* write process id for others to know
|
|
|
|
*/
|
1996-12-09 12:57:40 +03:00
|
|
|
pidoff = i = snprintf(line, sizeof(line), "%u\n", pid);
|
1993-03-21 12:45:37 +03:00
|
|
|
if (write(lfd, line, i) != i) {
|
|
|
|
syslog(LOG_ERR, "%s: %s: %m", printer, LO);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* search the spool directory for work and sort by queue order.
|
|
|
|
*/
|
|
|
|
if ((nitems = getq(&queue)) < 0) {
|
|
|
|
syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (nitems == 0) /* no work to do */
|
|
|
|
exit(0);
|
1999-12-11 05:01:18 +03:00
|
|
|
if (stb.st_mode & S_IXOTH) { /* reset queue flag */
|
2002-06-09 03:40:12 +04:00
|
|
|
stb.st_mode &= ~S_IXOTH;
|
|
|
|
if (fchmod(lfd, stb.st_mode & 0777) < 0)
|
1993-03-21 12:45:37 +03:00
|
|
|
syslog(LOG_ERR, "%s: %s: %m", printer, LO);
|
|
|
|
}
|
|
|
|
openpr(); /* open printer or remote */
|
|
|
|
again:
|
|
|
|
/*
|
|
|
|
* we found something to do now do it --
|
|
|
|
* write the name of the current control file into the lock file
|
|
|
|
* so the spool queue program can tell what we're working on
|
|
|
|
*/
|
|
|
|
for (qp = queue; nitems--; free((char *) q)) {
|
|
|
|
q = *qp++;
|
|
|
|
if (stat(q->q_name, &stb) < 0)
|
|
|
|
continue;
|
1997-10-05 15:52:17 +04:00
|
|
|
errcnt = 0;
|
1993-03-21 12:45:37 +03:00
|
|
|
restart:
|
1997-10-05 15:52:17 +04:00
|
|
|
(void)lseek(lfd, pidoff, 0);
|
1996-12-09 12:57:40 +03:00
|
|
|
i = snprintf(line, sizeof(line), "%s\n", q->q_name);
|
1993-03-21 12:45:37 +03:00
|
|
|
if (write(lfd, line, i) != i)
|
|
|
|
syslog(LOG_ERR, "%s: %s: %m", printer, LO);
|
|
|
|
if (!remote)
|
|
|
|
i = printit(q->q_name);
|
|
|
|
else
|
|
|
|
i = sendit(q->q_name);
|
|
|
|
/*
|
|
|
|
* Check to see if we are supposed to stop printing or
|
|
|
|
* if we are to rebuild the queue.
|
|
|
|
*/
|
|
|
|
if (fstat(lfd, &stb) == 0) {
|
|
|
|
/* stop printing before starting next job? */
|
1999-12-11 05:01:18 +03:00
|
|
|
if (stb.st_mode & S_IXUSR)
|
1993-03-21 12:45:37 +03:00
|
|
|
goto done;
|
|
|
|
/* rebuild queue (after lpc topq) */
|
1999-12-11 05:01:18 +03:00
|
|
|
if (stb.st_mode & S_IXOTH) {
|
1993-03-21 12:45:37 +03:00
|
|
|
for (free((char *) q); nitems--; free((char *) q))
|
|
|
|
q = *qp++;
|
2002-06-09 03:40:12 +04:00
|
|
|
stb.st_mode &= ~S_IXOTH;
|
|
|
|
if (fchmod(lfd, stb.st_mode & 0777) < 0)
|
1993-03-21 12:45:37 +03:00
|
|
|
syslog(LOG_WARNING, "%s: %s: %m",
|
|
|
|
printer, LO);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i == OK) /* file ok and printed */
|
|
|
|
count++;
|
1997-10-05 15:52:17 +04:00
|
|
|
else if (i == REPRINT && ++errcnt < 5) {
|
|
|
|
/* try reprinting the job */
|
1993-03-21 12:45:37 +03:00
|
|
|
syslog(LOG_INFO, "restarting %s", printer);
|
2002-09-03 22:35:11 +04:00
|
|
|
if (ofilter > 0)
|
|
|
|
close_ofilter();
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(pfd); /* close printer */
|
1993-03-21 12:45:37 +03:00
|
|
|
if (ftruncate(lfd, pidoff) < 0)
|
|
|
|
syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
|
|
|
|
openpr(); /* try to reopen printer */
|
|
|
|
goto restart;
|
1997-10-05 15:52:17 +04:00
|
|
|
} else {
|
|
|
|
syslog(LOG_WARNING, "%s: job could not be %s (%s)", printer,
|
|
|
|
remote ? "sent to remote host" : "printed", q->q_name);
|
|
|
|
if (i == REPRINT) {
|
1999-12-11 05:01:18 +03:00
|
|
|
/* ensure we don't attempt this job again */
|
1997-10-05 15:52:17 +04:00
|
|
|
(void) unlink(q->q_name);
|
|
|
|
q->q_name[0] = 'd';
|
|
|
|
(void) unlink(q->q_name);
|
|
|
|
if (logname[0])
|
|
|
|
sendmail(logname, FATALERR);
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
}
|
2006-03-17 20:06:30 +03:00
|
|
|
free(queue);
|
|
|
|
queue = NULL;
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* search the spool directory for more work.
|
|
|
|
*/
|
|
|
|
if ((nitems = getq(&queue)) < 0) {
|
|
|
|
syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (nitems == 0) { /* no more work to do */
|
|
|
|
done:
|
|
|
|
if (count > 0) { /* Files actually printed */
|
|
|
|
if (!SF && !tof)
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)write(ofd, FF, strlen(FF));
|
1993-03-21 12:45:37 +03:00
|
|
|
if (TR != NULL) /* output trailer */
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)write(ofd, TR, strlen(TR));
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)unlink(tempfile);
|
2002-09-03 22:35:11 +04:00
|
|
|
(void)unlink(tempremote);
|
1993-03-21 12:45:37 +03:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
|
1996-12-09 12:57:40 +03:00
|
|
|
#define FONTLEN 50
|
|
|
|
char fonts[4][FONTLEN]; /* fonts for troff */
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
1994-05-18 05:25:37 +04:00
|
|
|
static int
|
2001-10-09 06:15:37 +04:00
|
|
|
printit(char *file)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
1997-10-05 19:11:58 +04:00
|
|
|
int i;
|
1993-03-21 12:45:37 +03:00
|
|
|
char *cp;
|
|
|
|
int bombed = OK;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* open control file; ignore if no longer there.
|
|
|
|
*/
|
|
|
|
if ((cfp = fopen(file, "r")) == NULL) {
|
|
|
|
syslog(LOG_INFO, "%s: %s: %m", printer, file);
|
|
|
|
return(OK);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Reset troff fonts.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < 4; i++)
|
2003-05-18 00:46:42 +04:00
|
|
|
strlcpy(fonts[i], ifonts[i], sizeof(fonts[i]));
|
1997-07-10 10:28:58 +04:00
|
|
|
(void)snprintf(&width[2], sizeof(width) - 2, "%ld", PW);
|
1996-12-09 12:57:40 +03:00
|
|
|
indent[2] = '0';
|
|
|
|
indent[3] = '\0';
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
1997-10-05 15:52:17 +04:00
|
|
|
* R -- laser dpi "resolution"
|
1993-03-21 12:45:37 +03:00
|
|
|
* 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
|
2006-01-17 22:12:17 +03:00
|
|
|
* o -- "file name" postscript file to print
|
1993-03-21 12:45:37 +03:00
|
|
|
* 1 -- "R font file" for troff
|
|
|
|
* 2 -- "I font file" for troff
|
|
|
|
* 3 -- "B font file" for troff
|
|
|
|
* 4 -- "S font file" for troff
|
|
|
|
* N -- "name" of file (used by lpq)
|
|
|
|
* U -- "unlink" name of file to remove
|
|
|
|
* (after we print it. (Pass 2 only)).
|
|
|
|
* M -- "mail" to user when done printing
|
|
|
|
*
|
|
|
|
* getline reads a line and expands tabs to blanks
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* pass 1 */
|
|
|
|
|
|
|
|
while (getline(cfp))
|
|
|
|
switch (line[0]) {
|
|
|
|
case 'H':
|
2003-05-18 00:46:42 +04:00
|
|
|
strlcpy(fromhost, line+1, sizeof(fromhost));
|
1993-03-21 12:45:37 +03:00
|
|
|
if (class[0] == '\0')
|
2003-05-18 00:46:42 +04:00
|
|
|
strlcpy(class, line+1, sizeof(class));
|
1993-03-21 12:45:37 +03:00
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'P':
|
2003-05-18 00:46:42 +04:00
|
|
|
strlcpy(logname, line+1, sizeof(logname));
|
1993-03-21 12:45:37 +03:00
|
|
|
if (RS) { /* restricted */
|
1994-05-18 05:25:37 +04:00
|
|
|
if (getpwnam(logname) == NULL) {
|
1993-03-21 12:45:37 +03:00
|
|
|
bombed = NOACCT;
|
|
|
|
sendmail(line+1, bombed);
|
|
|
|
goto pass2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'S':
|
|
|
|
cp = line+1;
|
|
|
|
i = 0;
|
|
|
|
while (*cp >= '0' && *cp <= '9')
|
|
|
|
i = i * 10 + (*cp++ - '0');
|
|
|
|
fdev = i;
|
|
|
|
cp++;
|
|
|
|
i = 0;
|
|
|
|
while (*cp >= '0' && *cp <= '9')
|
|
|
|
i = i * 10 + (*cp++ - '0');
|
|
|
|
fino = i;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'J':
|
2003-05-18 00:46:42 +04:00
|
|
|
if (line[1] != '\0')
|
|
|
|
strlcpy(jobname, line+1, sizeof(jobname));
|
|
|
|
else {
|
1996-12-09 12:57:40 +03:00
|
|
|
jobname[0] = ' ';
|
|
|
|
jobname[1] = '\0';
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'C':
|
2003-05-18 00:46:42 +04:00
|
|
|
if (line[1] != '\0')
|
|
|
|
strlcpy(class, line+1, sizeof(class));
|
|
|
|
else if (class[0] == '\0') {
|
1993-03-21 12:45:37 +03:00
|
|
|
gethostname(class, sizeof(class));
|
1998-07-06 10:56:06 +04:00
|
|
|
class[sizeof(class) - 1] = '\0';
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'T': /* header title for pr */
|
2003-05-18 00:46:42 +04:00
|
|
|
strlcpy(title, line+1, sizeof(title));
|
1993-03-21 12:45:37 +03:00
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'L': /* identification line */
|
|
|
|
if (!SH && !HL)
|
|
|
|
banner(line+1, jobname);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case '1': /* troff fonts */
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
1997-10-05 19:11:58 +04:00
|
|
|
if (line[1] != '\0') {
|
2003-05-18 00:46:42 +04:00
|
|
|
strlcpy(fonts[line[0]-'1'], line+1,
|
|
|
|
sizeof(fonts[line[0]-'1']));
|
1997-10-05 19:11:58 +04:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'W': /* page width */
|
2003-05-18 00:46:42 +04:00
|
|
|
strlcpy(width+2, line+1, sizeof(width) - 2);
|
1993-03-21 12:45:37 +03:00
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'I': /* indent amount */
|
2003-05-18 00:46:42 +04:00
|
|
|
strlcpy(indent+2, line+1, sizeof(indent) - 2);
|
1993-03-21 12:45:37 +03:00
|
|
|
continue;
|
|
|
|
|
|
|
|
default: /* some file to print */
|
|
|
|
switch (i = print(line[0], line+1)) {
|
|
|
|
case ERROR:
|
|
|
|
if (bombed == OK)
|
|
|
|
bombed = FATALERR;
|
|
|
|
break;
|
|
|
|
case REPRINT:
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)fclose(cfp);
|
1993-03-21 12:45:37 +03:00
|
|
|
return(REPRINT);
|
|
|
|
case FILTERERR:
|
|
|
|
case ACCESS:
|
|
|
|
bombed = i;
|
|
|
|
sendmail(logname, bombed);
|
|
|
|
}
|
|
|
|
title[0] = '\0';
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'N':
|
|
|
|
case 'U':
|
|
|
|
case 'M':
|
1997-10-05 15:52:17 +04:00
|
|
|
case 'R':
|
1993-03-21 12:45:37 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* pass 2 */
|
|
|
|
|
|
|
|
pass2:
|
|
|
|
fseek(cfp, 0L, 0);
|
|
|
|
while (getline(cfp))
|
|
|
|
switch (line[0]) {
|
|
|
|
case 'L': /* identification line */
|
|
|
|
if (!SH && HL)
|
|
|
|
banner(line+1, jobname);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'M':
|
|
|
|
if (bombed < NOACCT) /* already sent if >= NOACCT */
|
|
|
|
sendmail(line+1, bombed);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'U':
|
1997-10-05 19:11:58 +04:00
|
|
|
if (strchr(line+1, '/'))
|
|
|
|
continue;
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)unlink(line+1);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* clean-up in case another control file exists
|
|
|
|
*/
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)fclose(cfp);
|
|
|
|
(void)unlink(file);
|
1993-03-21 12:45:37 +03:00
|
|
|
return(bombed == OK ? OK : ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print a file.
|
|
|
|
* Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
|
2001-09-16 20:34:23 +04:00
|
|
|
* Return -1 if a non-recoverable error occurred,
|
1993-03-21 12:45:37 +03:00
|
|
|
* 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.
|
|
|
|
*/
|
1994-05-18 05:25:37 +04:00
|
|
|
static int
|
2001-10-09 06:15:37 +04:00
|
|
|
print(int format, char *file)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
|
|
|
FILE *fp;
|
1997-10-05 19:11:58 +04:00
|
|
|
int status;
|
1993-03-21 12:45:37 +03:00
|
|
|
struct stat stb;
|
2005-11-28 06:26:06 +03:00
|
|
|
const char *prog, *av[15];
|
|
|
|
char buf[BUFSIZ];
|
|
|
|
int n, fi, fo, child_pid, p[2], stopped = 0, nofile;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
1997-10-19 23:40:21 +04:00
|
|
|
if (S_ISLNK(stb.st_mode) && fstat(fi, &stb) == 0 &&
|
1993-03-21 12:45:37 +03:00
|
|
|
(stb.st_dev != fdev || stb.st_ino != fino))
|
|
|
|
return(ACCESS);
|
|
|
|
if (!SF && !tof) { /* start on a fresh page */
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)write(ofd, FF, strlen(FF));
|
1993-03-21 12:45:37 +03:00
|
|
|
tof = 1;
|
|
|
|
}
|
|
|
|
if (IF == NULL && (format == 'f' || format == 'l')) {
|
|
|
|
tof = 0;
|
|
|
|
while ((n = read(fi, buf, BUFSIZ)) > 0)
|
|
|
|
if (write(ofd, buf, n) != n) {
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(fi);
|
1993-03-21 12:45:37 +03:00
|
|
|
return(REPRINT);
|
|
|
|
}
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(fi);
|
1993-03-21 12:45:37 +03:00
|
|
|
return(OK);
|
|
|
|
}
|
|
|
|
switch (format) {
|
|
|
|
case 'p': /* print file using 'pr' */
|
|
|
|
if (IF == NULL) { /* use output filter */
|
|
|
|
prog = _PATH_PR;
|
|
|
|
av[0] = "pr";
|
|
|
|
av[1] = width;
|
|
|
|
av[2] = length;
|
|
|
|
av[3] = "-h";
|
|
|
|
av[4] = *title ? title : " ";
|
|
|
|
av[5] = 0;
|
|
|
|
fo = ofd;
|
|
|
|
goto start;
|
|
|
|
}
|
|
|
|
pipe(p);
|
|
|
|
if ((prchild = dofork(DORETURN)) == 0) { /* child */
|
|
|
|
dup2(fi, 0); /* file is stdin */
|
|
|
|
dup2(p[1], 1); /* pipe is stdout */
|
1997-10-05 15:52:17 +04:00
|
|
|
closelog();
|
1997-10-05 19:11:58 +04:00
|
|
|
nofile = sysconf(_SC_OPEN_MAX);
|
|
|
|
for (n = 3; n < nofile; n++)
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(n);
|
1993-03-21 12:45:37 +03:00
|
|
|
execl(_PATH_PR, "pr", width, length,
|
2006-05-11 04:22:52 +04:00
|
|
|
"-h", *title ? title : " ", NULL);
|
1993-03-21 12:45:37 +03:00
|
|
|
syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
|
|
|
|
exit(2);
|
|
|
|
}
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(p[1]); /* close output side */
|
|
|
|
(void)close(fi);
|
1993-03-21 12:45:37 +03:00
|
|
|
if (prchild < 0) {
|
|
|
|
prchild = 0;
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(p[0]);
|
1993-03-21 12:45:37 +03:00
|
|
|
return(ERROR);
|
|
|
|
}
|
|
|
|
fi = p[0]; /* use pipe for input */
|
|
|
|
case 'f': /* print plain text file */
|
|
|
|
prog = IF;
|
|
|
|
av[1] = width;
|
|
|
|
av[2] = length;
|
|
|
|
av[3] = indent;
|
|
|
|
n = 4;
|
|
|
|
break;
|
2006-01-17 22:11:12 +03:00
|
|
|
case 'o': /* print a postscript file */
|
|
|
|
if (PF == NULL) {
|
|
|
|
/* if PF is not set, handle it like an 'l' */
|
|
|
|
prog = IF;
|
|
|
|
av[1] = "-c";
|
|
|
|
av[2] = width;
|
|
|
|
av[3] = length;
|
|
|
|
av[4] = indent;
|
|
|
|
n = 5;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
prog = PF;
|
|
|
|
av[1] = pxwidth;
|
|
|
|
av[2] = pxlength;
|
|
|
|
n = 3;
|
|
|
|
break;
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
case 'l': /* like 'f' but pass control characters */
|
|
|
|
prog = IF;
|
|
|
|
av[1] = "-c";
|
|
|
|
av[2] = width;
|
|
|
|
av[3] = length;
|
|
|
|
av[4] = indent;
|
|
|
|
n = 5;
|
|
|
|
break;
|
|
|
|
case 'r': /* print a fortran text file */
|
|
|
|
prog = RF;
|
|
|
|
av[1] = width;
|
|
|
|
av[2] = length;
|
|
|
|
n = 3;
|
|
|
|
break;
|
|
|
|
case 't': /* print troff output */
|
|
|
|
case 'n': /* print ditroff output */
|
|
|
|
case 'd': /* print tex output */
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)unlink(".railmag");
|
1993-03-21 12:45:37 +03:00
|
|
|
if ((fo = creat(".railmag", FILMOD)) < 0) {
|
|
|
|
syslog(LOG_ERR, "%s: cannot create .railmag", printer);
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)unlink(".railmag");
|
1993-03-21 12:45:37 +03:00
|
|
|
} else {
|
|
|
|
for (n = 0; n < 4; n++) {
|
|
|
|
if (fonts[n][0] != '/')
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)write(fo, _PATH_VFONT,
|
1994-05-18 05:25:37 +04:00
|
|
|
sizeof(_PATH_VFONT) - 1);
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)write(fo, fonts[n], strlen(fonts[n]));
|
|
|
|
(void)write(fo, "\n", 1);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(fo);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
|
|
|
|
av[1] = pxwidth;
|
|
|
|
av[2] = pxlength;
|
|
|
|
n = 3;
|
|
|
|
break;
|
|
|
|
case 'c': /* print cifplot output */
|
|
|
|
prog = CF;
|
|
|
|
av[1] = pxwidth;
|
|
|
|
av[2] = pxlength;
|
|
|
|
n = 3;
|
|
|
|
break;
|
|
|
|
case 'g': /* print plot(1G) output */
|
|
|
|
prog = GF;
|
|
|
|
av[1] = pxwidth;
|
|
|
|
av[2] = pxlength;
|
|
|
|
n = 3;
|
|
|
|
break;
|
|
|
|
case 'v': /* print raster output */
|
|
|
|
prog = VF;
|
|
|
|
av[1] = pxwidth;
|
|
|
|
av[2] = pxlength;
|
|
|
|
n = 3;
|
|
|
|
break;
|
|
|
|
default:
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(fi);
|
1993-03-21 12:45:37 +03:00
|
|
|
syslog(LOG_ERR, "%s: illegal format character '%c'",
|
|
|
|
printer, format);
|
|
|
|
return(ERROR);
|
|
|
|
}
|
1997-10-05 15:52:17 +04:00
|
|
|
if (prog == NULL) {
|
1997-10-05 19:11:58 +04:00
|
|
|
(void)close(fi);
|
1997-10-05 15:52:17 +04:00
|
|
|
syslog(LOG_ERR,
|
1997-10-05 19:11:58 +04:00
|
|
|
"%s: no filter found in printcap for format character '%c'",
|
|
|
|
printer, format);
|
|
|
|
return (ERROR);
|
1997-10-05 15:52:17 +04:00
|
|
|
}
|
1997-10-05 19:11:58 +04:00
|
|
|
if ((av[0] = strrchr(prog, '/')) != NULL)
|
1993-03-21 12:45:37 +03:00
|
|
|
av[0]++;
|
|
|
|
else
|
|
|
|
av[0] = prog;
|
|
|
|
av[n++] = "-n";
|
|
|
|
av[n++] = logname;
|
|
|
|
av[n++] = "-h";
|
|
|
|
av[n++] = fromhost;
|
|
|
|
av[n++] = AF;
|
|
|
|
av[n] = 0;
|
|
|
|
fo = pfd;
|
|
|
|
if (ofilter > 0) { /* stop output filter */
|
|
|
|
write(ofd, "\031\1", 2);
|
2005-11-28 06:26:06 +03:00
|
|
|
while ((child_pid =
|
|
|
|
wait3(&status, WUNTRACED, 0)) > 0 && child_pid != ofilter)
|
1993-03-21 12:45:37 +03:00
|
|
|
;
|
1997-10-05 19:11:58 +04:00
|
|
|
if (WIFSTOPPED(status) == 0) {
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(fi);
|
1997-10-05 15:52:17 +04:00
|
|
|
syslog(LOG_WARNING,
|
1997-10-05 19:11:58 +04:00
|
|
|
"%s: output filter died (retcode=%d termsig=%d)",
|
|
|
|
printer, WEXITSTATUS(status), WTERMSIG(status));
|
1993-03-21 12:45:37 +03:00
|
|
|
return(REPRINT);
|
|
|
|
}
|
|
|
|
stopped++;
|
|
|
|
}
|
|
|
|
start:
|
|
|
|
if ((child = dofork(DORETURN)) == 0) { /* child */
|
|
|
|
dup2(fi, 0);
|
|
|
|
dup2(fo, 1);
|
1997-03-22 06:20:38 +03:00
|
|
|
unlink(tempfile);
|
|
|
|
n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0664);
|
1993-03-21 12:45:37 +03:00
|
|
|
if (n >= 0)
|
|
|
|
dup2(n, 2);
|
1997-10-05 15:52:17 +04:00
|
|
|
closelog();
|
1997-10-05 19:11:58 +04:00
|
|
|
nofile = sysconf(_SC_OPEN_MAX);
|
|
|
|
for (n = 3; n < nofile; n++)
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(n);
|
2005-11-28 06:26:06 +03:00
|
|
|
execv(prog, __UNCONST(av));
|
1993-03-21 12:45:37 +03:00
|
|
|
syslog(LOG_ERR, "cannot execv %s", prog);
|
|
|
|
exit(2);
|
|
|
|
}
|
1997-10-05 19:11:58 +04:00
|
|
|
if (child < 0) {
|
|
|
|
child = 0;
|
|
|
|
prchild = 0;
|
|
|
|
tof = 0;
|
|
|
|
syslog(LOG_ERR, "cannot start child process: %m");
|
|
|
|
return (ERROR);
|
|
|
|
}
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(fi);
|
2005-11-28 06:26:06 +03:00
|
|
|
while ((child_pid = wait(&status)) > 0 && child_pid != child)
|
1997-10-05 19:11:58 +04:00
|
|
|
;
|
1993-03-21 12:45:37 +03:00
|
|
|
child = 0;
|
|
|
|
prchild = 0;
|
|
|
|
if (stopped) { /* restart output filter */
|
|
|
|
if (kill(ofilter, SIGCONT) < 0) {
|
|
|
|
syslog(LOG_ERR, "cannot restart output filter");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tof = 0;
|
|
|
|
|
|
|
|
/* Copy filter output to "lf" logfile */
|
1997-07-10 10:28:58 +04:00
|
|
|
if ((fp = fopen(tempfile, "r")) != NULL) {
|
1993-03-21 12:45:37 +03:00
|
|
|
while (fgets(buf, sizeof(buf), fp))
|
|
|
|
fputs(buf, stderr);
|
1994-05-18 05:25:37 +04:00
|
|
|
fclose(fp);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!WIFEXITED(status)) {
|
1997-10-05 19:11:58 +04:00
|
|
|
syslog(LOG_WARNING,
|
2002-09-03 22:35:11 +04:00
|
|
|
"%s: Daemon filter '%c' terminated (pid=%d) (termsig=%d)",
|
2005-11-28 06:26:06 +03:00
|
|
|
printer, format, (int)child_pid, WTERMSIG(status));
|
1993-03-21 12:45:37 +03:00
|
|
|
return(ERROR);
|
|
|
|
}
|
1997-10-05 19:11:58 +04:00
|
|
|
switch (WEXITSTATUS(status)) {
|
1993-03-21 12:45:37 +03:00
|
|
|
case 0:
|
|
|
|
tof = 1;
|
|
|
|
return(OK);
|
|
|
|
case 1:
|
|
|
|
return(REPRINT);
|
|
|
|
case 2:
|
|
|
|
return(ERROR);
|
1997-10-05 15:52:17 +04:00
|
|
|
default:
|
|
|
|
syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
|
1997-10-05 19:11:58 +04:00
|
|
|
printer, format, WEXITSTATUS(status));
|
1997-10-05 15:52:17 +04:00
|
|
|
return(FILTERERR);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send the daemon control file (cf) and any data files.
|
2001-09-16 20:34:23 +04:00
|
|
|
* Return -1 if a non-recoverable error occurred, 1 if a recoverable error and
|
1993-03-21 12:45:37 +03:00
|
|
|
* 0 if all is well.
|
|
|
|
*/
|
1994-05-18 05:25:37 +04:00
|
|
|
static int
|
2001-10-09 06:15:37 +04:00
|
|
|
sendit(char *file)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
1997-10-05 19:11:58 +04:00
|
|
|
int i, err = OK;
|
1993-03-21 12:45:37 +03:00
|
|
|
char *cp, last[BUFSIZ];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* open control file
|
|
|
|
*/
|
|
|
|
if ((cfp = fopen(file, "r")) == NULL)
|
|
|
|
return(OK);
|
|
|
|
/*
|
|
|
|
* read the control file for work to do
|
|
|
|
*
|
|
|
|
* file format -- first character in the line is a command
|
|
|
|
* rest of the line is the argument.
|
|
|
|
* commands of interest are:
|
|
|
|
*
|
|
|
|
* a-z -- "file name" name of file to print
|
|
|
|
* U -- "unlink" name of file to remove
|
|
|
|
* (after we print it. (Pass 2 only)).
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pass 1
|
|
|
|
*/
|
|
|
|
while (getline(cfp)) {
|
|
|
|
again:
|
|
|
|
if (line[0] == 'S') {
|
|
|
|
cp = line+1;
|
|
|
|
i = 0;
|
|
|
|
while (*cp >= '0' && *cp <= '9')
|
|
|
|
i = i * 10 + (*cp++ - '0');
|
|
|
|
fdev = i;
|
|
|
|
cp++;
|
|
|
|
i = 0;
|
|
|
|
while (*cp >= '0' && *cp <= '9')
|
|
|
|
i = i * 10 + (*cp++ - '0');
|
|
|
|
fino = i;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (line[0] >= 'a' && line[0] <= 'z') {
|
2003-05-18 00:46:42 +04:00
|
|
|
strlcpy(last, line, sizeof(last));
|
1997-07-10 10:28:58 +04:00
|
|
|
while ((i = getline(cfp)) != 0)
|
1993-03-21 12:45:37 +03:00
|
|
|
if (strcmp(last, line))
|
|
|
|
break;
|
|
|
|
switch (sendfile('\3', last+1)) {
|
|
|
|
case OK:
|
|
|
|
if (i)
|
|
|
|
goto again;
|
|
|
|
break;
|
|
|
|
case REPRINT:
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)fclose(cfp);
|
1993-03-21 12:45:37 +03:00
|
|
|
return(REPRINT);
|
|
|
|
case ACCESS:
|
|
|
|
sendmail(logname, ACCESS);
|
|
|
|
case ERROR:
|
|
|
|
err = ERROR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (err == OK && sendfile('\2', file) > 0) {
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)fclose(cfp);
|
1993-03-21 12:45:37 +03:00
|
|
|
return(REPRINT);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* pass 2
|
|
|
|
*/
|
|
|
|
fseek(cfp, 0L, 0);
|
|
|
|
while (getline(cfp))
|
1997-10-05 19:11:58 +04:00
|
|
|
if (line[0] == 'U' && strchr(line+1, '/') == 0)
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)unlink(line+1);
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* clean-up in case another control file exists
|
|
|
|
*/
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)fclose(cfp);
|
|
|
|
(void)unlink(file);
|
1993-03-21 12:45:37 +03:00
|
|
|
return(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send a data file to the remote machine and spool it.
|
|
|
|
* Return positive if we should try resending.
|
|
|
|
*/
|
1994-05-18 05:25:37 +04:00
|
|
|
static int
|
2001-10-09 06:15:37 +04:00
|
|
|
sendfile(int type, char *file)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
1997-10-05 19:11:58 +04:00
|
|
|
int f, i, amt;
|
1993-03-21 12:45:37 +03:00
|
|
|
struct stat stb;
|
|
|
|
char buf[BUFSIZ];
|
|
|
|
int sizerr, resp;
|
2002-09-03 22:35:11 +04:00
|
|
|
extern int rflag;
|
2006-01-19 22:17:59 +03:00
|
|
|
char *save_file;
|
2002-09-03 22:35:11 +04:00
|
|
|
|
2006-01-19 22:17:59 +03:00
|
|
|
save_file = file;
|
2002-09-03 22:35:11 +04:00
|
|
|
if (type == '\3' && rflag && (OF || IF)) {
|
|
|
|
int save_pfd = pfd;
|
|
|
|
|
|
|
|
(void)unlink(tempremote);
|
|
|
|
pfd = open(tempremote, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0664);
|
|
|
|
if (pfd == -1) {
|
|
|
|
pfd = save_pfd;
|
|
|
|
return ERROR;
|
|
|
|
}
|
|
|
|
setup_ofilter(1);
|
|
|
|
switch (i = print('f', file)) {
|
|
|
|
case ERROR:
|
|
|
|
case REPRINT:
|
|
|
|
case FILTERERR:
|
|
|
|
case ACCESS:
|
|
|
|
return(i);
|
|
|
|
}
|
|
|
|
close_ofilter();
|
|
|
|
pfd = save_pfd;
|
|
|
|
file = tempremote;
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
1997-10-19 23:40:21 +04:00
|
|
|
if (S_ISLNK(stb.st_mode) && fstat(f, &stb) == 0 &&
|
1993-03-21 12:45:37 +03:00
|
|
|
(stb.st_dev != fdev || stb.st_ino != fino))
|
|
|
|
return(ACCESS);
|
2002-09-03 22:35:11 +04:00
|
|
|
|
2001-01-05 06:27:26 +03:00
|
|
|
amt = snprintf(buf, sizeof(buf), "%c%lld %s\n", type,
|
2006-01-19 22:17:59 +03:00
|
|
|
(long long)stb.st_size, save_file);
|
- add timeouts to displayq(), rmremote(), sendfile() and response(),
and use these timeout in the lpq, lpd and lprm programs.
these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.
- add a -r flag to lpd to allow `of' filters for remote jobs.
i know there are ways around this, but i just don't care.
- add a -f flag to lpf to add missing carriage returns.
useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text. stair-stepped text is no fun.
- implement child process accounting: we just have a limit on the number
of children we can have (settable by the sysadmin), and we sleep when
this number is reached. this can reduce malicious not-so-malicious
attacks on the print server by a rogue remote client..
- use setproctitle() where appropriate so the sysadmin has a clue about
what each of the lpd's here are doing.
this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.
i have been running these changes in production for about a year.
1999-12-07 17:54:44 +03:00
|
|
|
for (i = 0; ; i++) {
|
1993-03-21 12:45:37 +03:00
|
|
|
if (write(pfd, buf, amt) != amt ||
|
|
|
|
(resp = response()) < 0 || resp == '\1') {
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(f);
|
1993-03-21 12:45:37 +03:00
|
|
|
return(REPRINT);
|
|
|
|
} else if (resp == '\0')
|
|
|
|
break;
|
|
|
|
if (i == 0)
|
1994-05-18 05:25:37 +04:00
|
|
|
pstatus("no space on remote; waiting for queue to drain");
|
1993-03-21 12:45:37 +03:00
|
|
|
if (i == 10)
|
|
|
|
syslog(LOG_ALERT, "%s: can't send to %s; queue full",
|
|
|
|
printer, RM);
|
|
|
|
sleep(5 * 60);
|
|
|
|
}
|
|
|
|
if (i)
|
1994-05-18 05:25:37 +04:00
|
|
|
pstatus("sending to %s", RM);
|
1993-03-21 12:45:37 +03:00
|
|
|
sizerr = 0;
|
|
|
|
for (i = 0; i < stb.st_size; i += BUFSIZ) {
|
- add timeouts to displayq(), rmremote(), sendfile() and response(),
and use these timeout in the lpq, lpd and lprm programs.
these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.
- add a -r flag to lpd to allow `of' filters for remote jobs.
i know there are ways around this, but i just don't care.
- add a -f flag to lpf to add missing carriage returns.
useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text. stair-stepped text is no fun.
- implement child process accounting: we just have a limit on the number
of children we can have (settable by the sysadmin), and we sleep when
this number is reached. this can reduce malicious not-so-malicious
attacks on the print server by a rogue remote client..
- use setproctitle() where appropriate so the sysadmin has a clue about
what each of the lpd's here are doing.
this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.
i have been running these changes in production for about a year.
1999-12-07 17:54:44 +03:00
|
|
|
struct sigaction osa, nsa;
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
amt = BUFSIZ;
|
|
|
|
if (i + amt > stb.st_size)
|
|
|
|
amt = stb.st_size - i;
|
|
|
|
if (sizerr == 0 && read(f, buf, amt) != amt)
|
|
|
|
sizerr = 1;
|
- add timeouts to displayq(), rmremote(), sendfile() and response(),
and use these timeout in the lpq, lpd and lprm programs.
these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.
- add a -r flag to lpd to allow `of' filters for remote jobs.
i know there are ways around this, but i just don't care.
- add a -f flag to lpf to add missing carriage returns.
useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text. stair-stepped text is no fun.
- implement child process accounting: we just have a limit on the number
of children we can have (settable by the sysadmin), and we sleep when
this number is reached. this can reduce malicious not-so-malicious
attacks on the print server by a rogue remote client..
- use setproctitle() where appropriate so the sysadmin has a clue about
what each of the lpd's here are doing.
this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.
i have been running these changes in production for about a year.
1999-12-07 17:54:44 +03:00
|
|
|
nsa.sa_handler = alarmer;
|
|
|
|
sigemptyset(&nsa.sa_mask);
|
|
|
|
sigaddset(&nsa.sa_mask, SIGALRM);
|
|
|
|
nsa.sa_flags = 0;
|
|
|
|
(void)sigaction(SIGALRM, &nsa, &osa);
|
|
|
|
alarm(wait_time);
|
1993-03-21 12:45:37 +03:00
|
|
|
if (write(pfd, buf, amt) != amt) {
|
- add timeouts to displayq(), rmremote(), sendfile() and response(),
and use these timeout in the lpq, lpd and lprm programs.
these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.
- add a -r flag to lpd to allow `of' filters for remote jobs.
i know there are ways around this, but i just don't care.
- add a -f flag to lpf to add missing carriage returns.
useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text. stair-stepped text is no fun.
- implement child process accounting: we just have a limit on the number
of children we can have (settable by the sysadmin), and we sleep when
this number is reached. this can reduce malicious not-so-malicious
attacks on the print server by a rogue remote client..
- use setproctitle() where appropriate so the sysadmin has a clue about
what each of the lpd's here are doing.
this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.
i have been running these changes in production for about a year.
1999-12-07 17:54:44 +03:00
|
|
|
alarm(0);
|
|
|
|
(void)sigaction(SIGALRM, &osa, NULL);
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(f);
|
1993-03-21 12:45:37 +03:00
|
|
|
return(REPRINT);
|
|
|
|
}
|
- add timeouts to displayq(), rmremote(), sendfile() and response(),
and use these timeout in the lpq, lpd and lprm programs.
these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.
- add a -r flag to lpd to allow `of' filters for remote jobs.
i know there are ways around this, but i just don't care.
- add a -f flag to lpf to add missing carriage returns.
useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text. stair-stepped text is no fun.
- implement child process accounting: we just have a limit on the number
of children we can have (settable by the sysadmin), and we sleep when
this number is reached. this can reduce malicious not-so-malicious
attacks on the print server by a rogue remote client..
- use setproctitle() where appropriate so the sysadmin has a clue about
what each of the lpd's here are doing.
this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.
i have been running these changes in production for about a year.
1999-12-07 17:54:44 +03:00
|
|
|
alarm(0);
|
|
|
|
(void)sigaction(SIGALRM, &osa, NULL);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1994-05-18 05:25:37 +04:00
|
|
|
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(f);
|
1993-03-21 12:45:37 +03:00
|
|
|
if (sizerr) {
|
|
|
|
syslog(LOG_INFO, "%s: %s: changed size", printer, file);
|
|
|
|
/* tell recvjob to ignore this file */
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)write(pfd, "\1", 1);
|
1993-03-21 12:45:37 +03:00
|
|
|
return(ERROR);
|
|
|
|
}
|
|
|
|
if (write(pfd, "", 1) != 1 || response())
|
|
|
|
return(REPRINT);
|
|
|
|
return(OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check to make sure there have been no errors and that both programs
|
|
|
|
* are in sync with eachother.
|
|
|
|
* Return non-zero if the connection was lost.
|
|
|
|
*/
|
1994-05-18 05:25:37 +04:00
|
|
|
static char
|
2001-10-09 06:15:37 +04:00
|
|
|
response(void)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
- add timeouts to displayq(), rmremote(), sendfile() and response(),
and use these timeout in the lpq, lpd and lprm programs.
these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.
- add a -r flag to lpd to allow `of' filters for remote jobs.
i know there are ways around this, but i just don't care.
- add a -f flag to lpf to add missing carriage returns.
useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text. stair-stepped text is no fun.
- implement child process accounting: we just have a limit on the number
of children we can have (settable by the sysadmin), and we sleep when
this number is reached. this can reduce malicious not-so-malicious
attacks on the print server by a rogue remote client..
- use setproctitle() where appropriate so the sysadmin has a clue about
what each of the lpd's here are doing.
this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.
i have been running these changes in production for about a year.
1999-12-07 17:54:44 +03:00
|
|
|
struct sigaction osa, nsa;
|
1993-03-21 12:45:37 +03:00
|
|
|
char resp;
|
|
|
|
|
- add timeouts to displayq(), rmremote(), sendfile() and response(),
and use these timeout in the lpq, lpd and lprm programs.
these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.
- add a -r flag to lpd to allow `of' filters for remote jobs.
i know there are ways around this, but i just don't care.
- add a -f flag to lpf to add missing carriage returns.
useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text. stair-stepped text is no fun.
- implement child process accounting: we just have a limit on the number
of children we can have (settable by the sysadmin), and we sleep when
this number is reached. this can reduce malicious not-so-malicious
attacks on the print server by a rogue remote client..
- use setproctitle() where appropriate so the sysadmin has a clue about
what each of the lpd's here are doing.
this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.
i have been running these changes in production for about a year.
1999-12-07 17:54:44 +03:00
|
|
|
nsa.sa_handler = alarmer;
|
|
|
|
sigemptyset(&nsa.sa_mask);
|
|
|
|
sigaddset(&nsa.sa_mask, SIGALRM);
|
|
|
|
nsa.sa_flags = 0;
|
|
|
|
(void)sigaction(SIGALRM, &nsa, &osa);
|
|
|
|
alarm(wait_time);
|
1993-03-21 12:45:37 +03:00
|
|
|
if (read(pfd, &resp, 1) != 1) {
|
|
|
|
syslog(LOG_INFO, "%s: lost connection", printer);
|
- add timeouts to displayq(), rmremote(), sendfile() and response(),
and use these timeout in the lpq, lpd and lprm programs.
these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.
- add a -r flag to lpd to allow `of' filters for remote jobs.
i know there are ways around this, but i just don't care.
- add a -f flag to lpf to add missing carriage returns.
useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text. stair-stepped text is no fun.
- implement child process accounting: we just have a limit on the number
of children we can have (settable by the sysadmin), and we sleep when
this number is reached. this can reduce malicious not-so-malicious
attacks on the print server by a rogue remote client..
- use setproctitle() where appropriate so the sysadmin has a clue about
what each of the lpd's here are doing.
this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.
i have been running these changes in production for about a year.
1999-12-07 17:54:44 +03:00
|
|
|
resp = -1;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
- add timeouts to displayq(), rmremote(), sendfile() and response(),
and use these timeout in the lpq, lpd and lprm programs.
these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.
- add a -r flag to lpd to allow `of' filters for remote jobs.
i know there are ways around this, but i just don't care.
- add a -f flag to lpf to add missing carriage returns.
useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text. stair-stepped text is no fun.
- implement child process accounting: we just have a limit on the number
of children we can have (settable by the sysadmin), and we sleep when
this number is reached. this can reduce malicious not-so-malicious
attacks on the print server by a rogue remote client..
- use setproctitle() where appropriate so the sysadmin has a clue about
what each of the lpd's here are doing.
this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.
i have been running these changes in production for about a year.
1999-12-07 17:54:44 +03:00
|
|
|
alarm(0);
|
|
|
|
(void)sigaction(SIGALRM, &osa, NULL);
|
|
|
|
return (resp);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Banner printing stuff
|
|
|
|
*/
|
1994-05-18 05:25:37 +04:00
|
|
|
static void
|
2001-10-09 06:15:37 +04:00
|
|
|
banner(char *name1, char *name2)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
|
|
|
time_t tvec;
|
|
|
|
|
|
|
|
time(&tvec);
|
|
|
|
if (!SF && !tof)
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)write(ofd, FF, strlen(FF));
|
1993-03-21 12:45:37 +03:00
|
|
|
if (SB) { /* short banner only */
|
|
|
|
if (class[0]) {
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)write(ofd, class, strlen(class));
|
|
|
|
(void)write(ofd, ":", 1);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1996-12-09 12:57:40 +03:00
|
|
|
(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);
|
1993-03-21 12:45:37 +03:00
|
|
|
} else { /* normal banner */
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)write(ofd, "\n\n\n", 3);
|
1993-03-21 12:45:37 +03:00
|
|
|
scan_out(ofd, name1, '\0');
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)write(ofd, "\n\n", 2);
|
1993-03-21 12:45:37 +03:00
|
|
|
scan_out(ofd, name2, '\0');
|
|
|
|
if (class[0]) {
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)write(ofd,"\n\n\n",3);
|
1993-03-21 12:45:37 +03:00
|
|
|
scan_out(ofd, class, '\0');
|
|
|
|
}
|
1996-12-09 12:57:40 +03:00
|
|
|
(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);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
if (!SF)
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)write(ofd, FF, strlen(FF));
|
1993-03-21 12:45:37 +03:00
|
|
|
tof = 1;
|
|
|
|
}
|
|
|
|
|
1994-05-18 05:25:37 +04:00
|
|
|
static char *
|
2002-07-14 19:27:58 +04:00
|
|
|
scnline(int key, char *p, int c)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
1997-10-05 19:11:58 +04:00
|
|
|
int scnwidth;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
for (scnwidth = WIDTH; --scnwidth;) {
|
|
|
|
key <<= 1;
|
|
|
|
*p++ = key & 0200 ? c : BACKGND;
|
|
|
|
}
|
|
|
|
return (p);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define TRC(q) (((q)-' ')&0177)
|
|
|
|
|
1994-05-18 05:25:37 +04:00
|
|
|
static void
|
2001-10-09 06:15:37 +04:00
|
|
|
scan_out(int scfd, char *scsp, int dlm)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
1997-10-05 19:11:58 +04:00
|
|
|
char *strp;
|
|
|
|
int nchrs, j;
|
1993-03-21 12:45:37 +03:00
|
|
|
char outbuf[LINELEN+1], *sp, c, cc;
|
|
|
|
int d, scnhgt;
|
|
|
|
extern char scnkey[][HEIGHT]; /* in lpdchar.c */
|
|
|
|
|
|
|
|
for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
|
|
|
|
strp = &outbuf[0];
|
|
|
|
sp = scsp;
|
|
|
|
for (nchrs = 0; ; ) {
|
|
|
|
d = dropit(c = TRC(cc = *sp++));
|
|
|
|
if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
|
|
|
|
for (j = WIDTH; --j;)
|
|
|
|
*strp++ = BACKGND;
|
|
|
|
else
|
1997-07-10 10:28:58 +04:00
|
|
|
strp = scnline(scnkey[(int)c][scnhgt-1-d],
|
|
|
|
strp, cc);
|
|
|
|
if (*sp == dlm || *sp == '\0' ||
|
|
|
|
nchrs++ >= PW/(WIDTH+1)-1)
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
*strp++ = BACKGND;
|
|
|
|
*strp++ = BACKGND;
|
|
|
|
}
|
|
|
|
while (*--strp == BACKGND && strp >= outbuf)
|
|
|
|
;
|
|
|
|
strp++;
|
|
|
|
*strp++ = '\n';
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)write(scfd, outbuf, strp-outbuf);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1994-05-18 05:25:37 +04:00
|
|
|
static int
|
2002-07-09 05:12:35 +04:00
|
|
|
dropit(int c)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
|
|
|
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
|
|
|
|
*/
|
1994-05-18 05:25:37 +04:00
|
|
|
static void
|
2001-10-09 06:15:37 +04:00
|
|
|
sendmail(char *user, int bombed)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
1997-10-05 19:11:58 +04:00
|
|
|
int i, p[2], s, nofile;
|
2005-11-28 06:26:06 +03:00
|
|
|
const char *cp = NULL; /* XXX gcc */
|
1993-03-21 12:45:37 +03:00
|
|
|
struct stat stb;
|
|
|
|
FILE *fp;
|
|
|
|
|
2004-10-30 12:44:25 +04:00
|
|
|
if (user[0] == '-' || user[0] == '/' || !isprint((unsigned char)user[0]))
|
1997-10-05 19:11:58 +04:00
|
|
|
return;
|
1993-03-21 12:45:37 +03:00
|
|
|
pipe(p);
|
|
|
|
if ((s = dofork(DORETURN)) == 0) { /* child */
|
|
|
|
dup2(p[0], 0);
|
1997-10-05 15:52:17 +04:00
|
|
|
closelog();
|
1997-10-05 19:11:58 +04:00
|
|
|
nofile = sysconf(_SC_OPEN_MAX);
|
|
|
|
for (i = 3; i < nofile; i++)
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(i);
|
1997-10-05 19:11:58 +04:00
|
|
|
if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
|
1993-03-21 12:45:37 +03:00
|
|
|
cp++;
|
1997-10-05 19:11:58 +04:00
|
|
|
else
|
1993-03-21 12:45:37 +03:00
|
|
|
cp = _PATH_SENDMAIL;
|
2006-05-11 04:22:52 +04:00
|
|
|
execl(_PATH_SENDMAIL, cp, "-t", NULL);
|
1999-12-11 05:01:18 +03:00
|
|
|
_exit(0);
|
1993-03-21 12:45:37 +03:00
|
|
|
} else if (s > 0) { /* parent */
|
|
|
|
dup2(p[1], 1);
|
|
|
|
printf("To: %s@%s\n", user, fromhost);
|
1997-10-05 15:52:17 +04:00
|
|
|
printf("Subject: %s printer job \"%s\"\n", printer,
|
|
|
|
*jobname ? jobname : "<unknown>");
|
|
|
|
printf("Reply-To: root@%s\n\n", host);
|
1993-03-21 12:45:37 +03:00
|
|
|
printf("Your printer job ");
|
|
|
|
if (*jobname)
|
|
|
|
printf("(%s) ", jobname);
|
|
|
|
switch (bombed) {
|
|
|
|
case OK:
|
|
|
|
printf("\ncompleted successfully\n");
|
1997-10-05 15:52:17 +04:00
|
|
|
cp = "OK";
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case FATALERR:
|
|
|
|
printf("\ncould not be printed\n");
|
1997-10-05 15:52:17 +04:00
|
|
|
cp = "FATALERR";
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
case NOACCT:
|
|
|
|
printf("\ncould not be printed without an account on %s\n", host);
|
1997-10-05 15:52:17 +04:00
|
|
|
cp = "NOACCT";
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
case FILTERERR:
|
2000-08-24 06:03:54 +04:00
|
|
|
cp = "FILTERERR";
|
1993-03-21 12:45:37 +03:00
|
|
|
if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
|
|
|
|
(fp = fopen(tempfile, "r")) == NULL) {
|
1997-10-05 15:52:17 +04:00
|
|
|
printf("\nhad some errors and may not have printed\n");
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
}
|
1997-10-05 15:52:17 +04:00
|
|
|
printf("\nhad the following errors and may not have printed:\n");
|
1993-03-21 12:45:37 +03:00
|
|
|
while ((i = getc(fp)) != EOF)
|
|
|
|
putchar(i);
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)fclose(fp);
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
case ACCESS:
|
|
|
|
printf("\nwas not printed because it was not linked to the original file\n");
|
1997-10-05 15:52:17 +04:00
|
|
|
cp = "ACCESS";
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
fflush(stdout);
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(1);
|
1997-10-05 19:11:58 +04:00
|
|
|
} else {
|
|
|
|
syslog(LOG_ERR, "fork for sendmail failed: %m");
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(p[0]);
|
|
|
|
(void)close(p[1]);
|
1997-10-05 19:11:58 +04:00
|
|
|
if (s > 0) {
|
|
|
|
wait(NULL);
|
|
|
|
syslog(LOG_INFO, "mail sent to user %s about job %s on "
|
|
|
|
"printer %s (%s)", user, *jobname ? jobname : "<unknown>",
|
|
|
|
printer, cp);
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dofork - fork with retries on failure
|
|
|
|
*/
|
1994-05-18 05:25:37 +04:00
|
|
|
static int
|
2001-10-09 06:15:37 +04:00
|
|
|
dofork(int action)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2005-11-28 06:26:06 +03:00
|
|
|
int i, child_pid;
|
1995-04-14 23:23:43 +04:00
|
|
|
struct passwd *pw;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
for (i = 0; i < 20; i++) {
|
2005-11-28 06:26:06 +03:00
|
|
|
if ((child_pid = fork()) < 0) {
|
1993-03-21 12:45:37 +03:00
|
|
|
sleep((unsigned)(i*i));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Child should run as daemon instead of root
|
|
|
|
*/
|
2005-11-28 06:26:06 +03:00
|
|
|
if (child_pid == 0) {
|
1995-04-14 23:23:43 +04:00
|
|
|
pw = getpwuid(DU);
|
|
|
|
if (pw == 0) {
|
1997-07-10 10:28:58 +04:00
|
|
|
syslog(LOG_ERR, "uid %ld not in password file",
|
1995-04-14 23:23:43 +04:00
|
|
|
DU);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
initgroups(pw->pw_name, pw->pw_gid);
|
|
|
|
setgid(pw->pw_gid);
|
1993-03-21 12:45:37 +03:00
|
|
|
setuid(DU);
|
2002-09-03 22:35:11 +04:00
|
|
|
signal(SIGCHLD, SIG_DFL);
|
1995-04-14 23:23:43 +04:00
|
|
|
}
|
2005-11-28 06:26:06 +03:00
|
|
|
return (child_pid);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
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.
|
|
|
|
*/
|
1994-05-18 05:25:37 +04:00
|
|
|
static void
|
2002-07-09 05:12:35 +04:00
|
|
|
abortpr(int signo)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)unlink(tempfile);
|
2002-09-03 22:35:11 +04:00
|
|
|
(void)unlink(tempremote);
|
1993-03-21 12:45:37 +03:00
|
|
|
kill(0, SIGINT);
|
|
|
|
if (ofilter > 0)
|
|
|
|
kill(ofilter, SIGCONT);
|
|
|
|
while (wait(NULL) > 0)
|
|
|
|
;
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
1994-05-18 05:25:37 +04:00
|
|
|
static void
|
2001-10-09 06:15:37 +04:00
|
|
|
init(void)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
|
|
|
char *s;
|
|
|
|
|
2005-11-28 06:26:06 +03:00
|
|
|
getprintcap(printer);
|
|
|
|
|
|
|
|
FF = cgetstr(bp, "ff", &s) == -1 ? DEFFF : s;
|
|
|
|
|
1994-05-18 05:25:37 +04:00
|
|
|
if (cgetnum(bp, "du", &DU) < 0)
|
1993-03-21 12:45:37 +03:00
|
|
|
DU = DEFUID;
|
1994-05-18 05:25:37 +04:00
|
|
|
if (cgetnum(bp, "pw", &PW) < 0)
|
1993-03-21 12:45:37 +03:00
|
|
|
PW = DEFWIDTH;
|
1997-07-10 10:28:58 +04:00
|
|
|
(void)snprintf(&width[2], sizeof(width) - 2, "%ld", PW);
|
1994-05-18 05:25:37 +04:00
|
|
|
if (cgetnum(bp, "pl", &PL) < 0)
|
1993-03-21 12:45:37 +03:00
|
|
|
PL = DEFLENGTH;
|
1997-07-10 10:28:58 +04:00
|
|
|
(void)snprintf(&length[2], sizeof(length) - 2, "%ld", PL);
|
1994-05-18 05:25:37 +04:00
|
|
|
if (cgetnum(bp,"px", &PX) < 0)
|
1993-03-21 12:45:37 +03:00
|
|
|
PX = 0;
|
1997-07-10 10:28:58 +04:00
|
|
|
(void)snprintf(&pxwidth[2], sizeof(pxwidth) - 2, "%ld", PX);
|
1994-05-18 05:25:37 +04:00
|
|
|
if (cgetnum(bp, "py", &PY) < 0)
|
1993-03-21 12:45:37 +03:00
|
|
|
PY = 0;
|
1997-07-10 10:28:58 +04:00
|
|
|
(void)snprintf(&pxlength[2], sizeof(pxlength) - 2, "%ld", PY);
|
2005-11-28 06:26:06 +03:00
|
|
|
|
|
|
|
AF = cgetstr(bp, "af", &s) == -1 ? NULL : s;
|
|
|
|
OF = cgetstr(bp, "of", &s) == -1 ? NULL : s;
|
|
|
|
IF = cgetstr(bp, "if", &s) == -1 ? NULL : s;
|
|
|
|
RF = cgetstr(bp, "rf", &s) == -1 ? NULL : s;
|
|
|
|
TF = cgetstr(bp, "tf", &s) == -1 ? NULL : s;
|
|
|
|
NF = cgetstr(bp, "nf", &s) == -1 ? NULL : s;
|
|
|
|
DF = cgetstr(bp, "df", &s) == -1 ? NULL : s;
|
|
|
|
GF = cgetstr(bp, "gf", &s) == -1 ? NULL : s;
|
|
|
|
VF = cgetstr(bp, "vf", &s) == -1 ? NULL : s;
|
|
|
|
CF = cgetstr(bp, "cf", &s) == -1 ? NULL : s;
|
2006-01-17 22:11:12 +03:00
|
|
|
PF = cgetstr(bp, "pf", &s) == -1 ? NULL : s;
|
2005-11-28 06:26:06 +03:00
|
|
|
TR = cgetstr(bp, "tr", &s) == -1 ? NULL : s;
|
1994-05-18 05:25:37 +04:00
|
|
|
|
|
|
|
RS = (cgetcap(bp, "rs", ':') != NULL);
|
|
|
|
SF = (cgetcap(bp, "sf", ':') != NULL);
|
|
|
|
SH = (cgetcap(bp, "sh", ':') != NULL);
|
|
|
|
SB = (cgetcap(bp, "sb", ':') != NULL);
|
|
|
|
HL = (cgetcap(bp, "hl", ':') != NULL);
|
|
|
|
RW = (cgetcap(bp, "rw", ':') != NULL);
|
|
|
|
|
|
|
|
cgetnum(bp, "br", &BR);
|
|
|
|
if (cgetnum(bp, "fc", &FC) < 0)
|
1993-03-21 12:45:37 +03:00
|
|
|
FC = 0;
|
1994-05-18 05:25:37 +04:00
|
|
|
if (cgetnum(bp, "fs", &FS) < 0)
|
1993-03-21 12:45:37 +03:00
|
|
|
FS = 0;
|
1994-05-18 05:25:37 +04:00
|
|
|
if (cgetnum(bp, "xc", &XC) < 0)
|
1993-03-21 12:45:37 +03:00
|
|
|
XC = 0;
|
1994-05-18 05:25:37 +04:00
|
|
|
if (cgetnum(bp, "xs", &XS) < 0)
|
1993-03-21 12:45:37 +03:00
|
|
|
XS = 0;
|
2005-11-28 06:26:06 +03:00
|
|
|
MS = cgetstr(bp, "ms", &s) == -1 ? NULL : s;
|
1994-05-18 05:25:37 +04:00
|
|
|
|
|
|
|
tof = (cgetcap(bp, "fo", ':') == NULL);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
2002-09-03 22:35:11 +04:00
|
|
|
/*
|
|
|
|
* Setup output filter - called once for local printer, or (if -r given to lpd)
|
|
|
|
* once per file for remote printers
|
|
|
|
*/
|
1994-05-18 05:25:37 +04:00
|
|
|
static void
|
2002-09-03 22:35:11 +04:00
|
|
|
setup_ofilter(int check_rflag)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
- add timeouts to displayq(), rmremote(), sendfile() and response(),
and use these timeout in the lpq, lpd and lprm programs.
these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.
- add a -r flag to lpd to allow `of' filters for remote jobs.
i know there are ways around this, but i just don't care.
- add a -f flag to lpf to add missing carriage returns.
useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text. stair-stepped text is no fun.
- implement child process accounting: we just have a limit on the number
of children we can have (settable by the sysadmin), and we sleep when
this number is reached. this can reduce malicious not-so-malicious
attacks on the print server by a rogue remote client..
- use setproctitle() where appropriate so the sysadmin has a clue about
what each of the lpd's here are doing.
this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.
i have been running these changes in production for about a year.
1999-12-07 17:54:44 +03:00
|
|
|
extern int rflag;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2002-09-03 22:35:11 +04:00
|
|
|
if (OF && (!remote || (check_rflag && rflag))) {
|
1993-03-21 12:45:37 +03:00
|
|
|
int p[2];
|
2002-09-03 22:35:11 +04:00
|
|
|
int i, nofile;
|
2005-11-28 06:26:06 +03:00
|
|
|
const char *cp;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
pipe(p);
|
|
|
|
if ((ofilter = dofork(DOABORT)) == 0) { /* child */
|
|
|
|
dup2(p[0], 0); /* pipe is std in */
|
|
|
|
dup2(pfd, 1); /* printer is std out */
|
1997-10-05 15:52:17 +04:00
|
|
|
closelog();
|
1997-10-05 19:11:58 +04:00
|
|
|
nofile = sysconf(_SC_OPEN_MAX);
|
|
|
|
for (i = 3; i < nofile; i++)
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(i);
|
1997-10-05 19:11:58 +04:00
|
|
|
if ((cp = strrchr(OF, '/')) == NULL)
|
1993-03-21 12:45:37 +03:00
|
|
|
cp = OF;
|
|
|
|
else
|
|
|
|
cp++;
|
2006-05-11 04:22:52 +04:00
|
|
|
execl(OF, cp, width, length, NULL);
|
1993-03-21 12:45:37 +03:00
|
|
|
syslog(LOG_ERR, "%s: %s: %m", printer, OF);
|
|
|
|
exit(1);
|
|
|
|
}
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(p[0]); /* close input side */
|
1993-03-21 12:45:37 +03:00
|
|
|
ofd = p[1]; /* use pipe for output */
|
|
|
|
} else {
|
|
|
|
ofd = pfd;
|
|
|
|
ofilter = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-09-03 22:35:11 +04:00
|
|
|
/*
|
|
|
|
* Close the output filter and reset ofd back to the main pfd descriptor
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
close_ofilter(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (ofilter) {
|
|
|
|
kill(ofilter, SIGCONT); /* to be sure */
|
|
|
|
(void)close(ofd);
|
|
|
|
ofd = pfd;
|
|
|
|
while ((i = wait(NULL)) > 0 && i != ofilter)
|
|
|
|
;
|
|
|
|
ofilter = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Acquire line printer or remote connection.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
openpr(void)
|
|
|
|
{
|
|
|
|
if (!remote && *LP) {
|
2006-01-20 20:30:00 +03:00
|
|
|
if (strchr(LP, '@') != NULL)
|
|
|
|
opennet();
|
2002-09-03 22:35:11 +04:00
|
|
|
else
|
|
|
|
opentty();
|
|
|
|
} else if (remote) {
|
|
|
|
openrem();
|
|
|
|
} else {
|
|
|
|
syslog(LOG_ERR, "%s: no line printer device or host name",
|
|
|
|
printer);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start up an output filter, if needed.
|
|
|
|
*/
|
|
|
|
setup_ofilter(0);
|
|
|
|
}
|
|
|
|
|
1997-10-05 15:52:17 +04:00
|
|
|
/*
|
|
|
|
* Printer connected directly to the network
|
|
|
|
* or to a terminal server on the net
|
|
|
|
*/
|
|
|
|
static void
|
2006-01-20 20:30:00 +03:00
|
|
|
opennet(void)
|
1997-10-05 15:52:17 +04:00
|
|
|
{
|
1997-10-05 19:11:58 +04:00
|
|
|
int i;
|
2006-01-20 20:30:00 +03:00
|
|
|
int resp;
|
1997-10-05 15:52:17 +04:00
|
|
|
|
|
|
|
for (i = 1; ; i = i < 256 ? i << 1 : i) {
|
|
|
|
resp = -1;
|
2006-01-20 20:30:00 +03:00
|
|
|
pfd = getport(LP);
|
1997-10-05 15:52:17 +04:00
|
|
|
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("waiting for %s to come up", LP);
|
|
|
|
else
|
|
|
|
pstatus("waiting for access to printer on %s", LP);
|
|
|
|
}
|
|
|
|
sleep(i);
|
|
|
|
}
|
2006-01-20 20:30:00 +03:00
|
|
|
pstatus("sending to %s", LP);
|
1997-10-05 15:52:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Printer is connected to an RS232 port on this host
|
|
|
|
*/
|
|
|
|
static void
|
2001-10-09 06:15:37 +04:00
|
|
|
opentty(void)
|
1997-10-05 15:52:17 +04:00
|
|
|
{
|
1997-10-05 19:11:58 +04:00
|
|
|
int i;
|
1997-10-05 15:52:17 +04:00
|
|
|
|
|
|
|
for (i = 1; ; i = i < 32 ? i << 1 : i) {
|
|
|
|
pfd = open(LP, RW ? O_RDWR : O_WRONLY);
|
|
|
|
if (pfd >= 0) {
|
|
|
|
delay(500);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (errno == ENOENT) {
|
|
|
|
syslog(LOG_ERR, "%s: %m", LP);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (i == 1)
|
|
|
|
pstatus("waiting for %s to become ready (offline ?)",
|
|
|
|
printer);
|
|
|
|
sleep(i);
|
|
|
|
}
|
|
|
|
if (isatty(pfd))
|
|
|
|
setty();
|
|
|
|
pstatus("%s is ready and printing", printer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Printer is on a remote host
|
|
|
|
*/
|
|
|
|
static void
|
2001-10-09 06:15:37 +04:00
|
|
|
openrem(void)
|
1997-10-05 15:52:17 +04:00
|
|
|
{
|
1997-10-05 19:11:58 +04:00
|
|
|
int i, n;
|
|
|
|
int resp;
|
1997-10-05 15:52:17 +04:00
|
|
|
|
|
|
|
for (i = 1; ; i = i < 256 ? i << 1 : i) {
|
|
|
|
resp = -1;
|
2006-01-20 20:30:00 +03:00
|
|
|
pfd = getport(RM);
|
1997-10-05 15:52:17 +04:00
|
|
|
if (pfd >= 0) {
|
|
|
|
n = snprintf(line, sizeof(line), "\2%s\n", RP);
|
|
|
|
if (write(pfd, line, n) == n &&
|
|
|
|
(resp = response()) == '\0')
|
|
|
|
break;
|
|
|
|
(void) close(pfd);
|
|
|
|
}
|
|
|
|
if (i == 1) {
|
|
|
|
if (resp < 0)
|
|
|
|
pstatus("waiting for %s to come up", RM);
|
|
|
|
else {
|
|
|
|
pstatus("waiting for queue to be enabled on %s",
|
|
|
|
RM);
|
|
|
|
i = 256;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sleep(i);
|
|
|
|
}
|
|
|
|
pstatus("sending to %s", RM);
|
|
|
|
}
|
|
|
|
|
- add timeouts to displayq(), rmremote(), sendfile() and response(),
and use these timeout in the lpq, lpd and lprm programs.
these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.
- add a -r flag to lpd to allow `of' filters for remote jobs.
i know there are ways around this, but i just don't care.
- add a -f flag to lpf to add missing carriage returns.
useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text. stair-stepped text is no fun.
- implement child process accounting: we just have a limit on the number
of children we can have (settable by the sysadmin), and we sleep when
this number is reached. this can reduce malicious not-so-malicious
attacks on the print server by a rogue remote client..
- use setproctitle() where appropriate so the sysadmin has a clue about
what each of the lpd's here are doing.
this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.
i have been running these changes in production for about a year.
1999-12-07 17:54:44 +03:00
|
|
|
static void
|
2001-10-09 06:15:37 +04:00
|
|
|
alarmer(int s)
|
- add timeouts to displayq(), rmremote(), sendfile() and response(),
and use these timeout in the lpq, lpd and lprm programs.
these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.
- add a -r flag to lpd to allow `of' filters for remote jobs.
i know there are ways around this, but i just don't care.
- add a -f flag to lpf to add missing carriage returns.
useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text. stair-stepped text is no fun.
- implement child process accounting: we just have a limit on the number
of children we can have (settable by the sysadmin), and we sleep when
this number is reached. this can reduce malicious not-so-malicious
attacks on the print server by a rogue remote client..
- use setproctitle() where appropriate so the sysadmin has a clue about
what each of the lpd's here are doing.
this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.
i have been running these changes in production for about a year.
1999-12-07 17:54:44 +03:00
|
|
|
{
|
|
|
|
/* nothing */
|
|
|
|
}
|
|
|
|
|
1996-07-01 03:55:49 +04:00
|
|
|
#if !defined(__NetBSD__)
|
1993-03-21 12:45:37 +03:00
|
|
|
struct bauds {
|
|
|
|
int baud;
|
|
|
|
int speed;
|
|
|
|
} bauds[] = {
|
|
|
|
50, B50,
|
|
|
|
75, B75,
|
|
|
|
110, B110,
|
|
|
|
134, B134,
|
|
|
|
150, B150,
|
|
|
|
200, B200,
|
|
|
|
300, B300,
|
|
|
|
600, B600,
|
|
|
|
1200, B1200,
|
|
|
|
1800, B1800,
|
|
|
|
2400, B2400,
|
|
|
|
4800, B4800,
|
|
|
|
9600, B9600,
|
1995-10-03 18:02:17 +03:00
|
|
|
19200, B19200,
|
|
|
|
38400, B38400,
|
1997-10-05 19:11:58 +04:00
|
|
|
57600, B57600,
|
|
|
|
115200, B115200,
|
1993-03-21 12:45:37 +03:00
|
|
|
0, 0
|
|
|
|
};
|
1996-07-01 03:55:49 +04:00
|
|
|
#endif
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* setup tty lines.
|
|
|
|
*/
|
1994-05-18 05:25:37 +04:00
|
|
|
static void
|
2001-10-09 06:15:37 +04:00
|
|
|
setty(void)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
1995-10-03 18:02:17 +03:00
|
|
|
struct info i;
|
|
|
|
char **argv, **ap, *p, *val;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1995-10-03 18:02:17 +03:00
|
|
|
i.fd = pfd;
|
|
|
|
i.set = i.wset = 0;
|
|
|
|
if (ioctl(i.fd, TIOCEXCL, (char *)0) < 0) {
|
1993-03-21 12:45:37 +03:00
|
|
|
syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
|
|
|
|
exit(1);
|
|
|
|
}
|
1995-10-03 18:02:17 +03:00
|
|
|
if (tcgetattr(i.fd, &i.t) < 0) {
|
|
|
|
syslog(LOG_ERR, "%s: tcgetattr: %m", printer);
|
1993-03-21 12:45:37 +03:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (BR > 0) {
|
1996-07-01 03:55:49 +04:00
|
|
|
#if !defined(__NetBSD__)
|
1997-10-05 19:11:58 +04:00
|
|
|
struct bauds *bp;
|
1993-03-21 12:45:37 +03:00
|
|
|
for (bp = bauds; bp->baud; bp++)
|
|
|
|
if (BR == bp->baud)
|
|
|
|
break;
|
|
|
|
if (!bp->baud) {
|
|
|
|
syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
|
|
|
|
exit(1);
|
|
|
|
}
|
1995-10-03 18:02:17 +03:00
|
|
|
cfsetspeed(&i.t, bp->speed);
|
1996-07-01 03:55:49 +04:00
|
|
|
#else
|
|
|
|
cfsetspeed(&i.t, BR);
|
|
|
|
#endif
|
1995-10-03 18:02:17 +03:00
|
|
|
i.set = 1;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1995-10-03 18:02:17 +03:00
|
|
|
if (MS) {
|
|
|
|
if (ioctl(i.fd, TIOCGETD, &i.ldisc) < 0) {
|
|
|
|
syslog(LOG_ERR, "%s: ioctl(TIOCGETD): %m", printer);
|
1993-03-21 12:45:37 +03:00
|
|
|
exit(1);
|
|
|
|
}
|
1995-10-03 18:02:17 +03:00
|
|
|
if (ioctl(i.fd, TIOCGWINSZ, &i.win) < 0)
|
|
|
|
syslog(LOG_INFO, "%s: ioctl(TIOCGWINSZ): %m",
|
|
|
|
printer);
|
|
|
|
|
|
|
|
argv = (char **)calloc(256, sizeof(char *));
|
|
|
|
if (argv == NULL) {
|
|
|
|
syslog(LOG_ERR, "%s: calloc: %m", printer);
|
1993-03-21 12:45:37 +03:00
|
|
|
exit(1);
|
|
|
|
}
|
1995-10-03 18:02:17 +03:00
|
|
|
p = strdup(MS);
|
|
|
|
ap = argv;
|
|
|
|
while ((val = strsep(&p, " \t,")) != NULL) {
|
|
|
|
*ap++ = strdup(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; *argv; ++argv) {
|
|
|
|
if (ksearch(&argv, &i))
|
|
|
|
continue;
|
|
|
|
if (msearch(&argv, &i))
|
|
|
|
continue;
|
|
|
|
syslog(LOG_INFO, "%s: unknown stty flag: %s",
|
|
|
|
printer, *argv);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (FC) {
|
|
|
|
sttyclearflags(&i.t, FC);
|
|
|
|
i.set = 1;
|
|
|
|
}
|
|
|
|
if (FS) {
|
|
|
|
sttysetflags(&i.t, FS);
|
|
|
|
i.set = 1;
|
|
|
|
}
|
|
|
|
if (XC) {
|
|
|
|
sttyclearlflags(&i.t, XC);
|
|
|
|
i.set = 1;
|
|
|
|
}
|
|
|
|
if (XS) {
|
1996-04-30 04:07:00 +04:00
|
|
|
sttysetlflags(&i.t, XS);
|
1995-10-03 18:02:17 +03:00
|
|
|
i.set = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i.set && tcsetattr(i.fd, TCSANOW, &i.t) < 0) {
|
|
|
|
syslog(LOG_ERR, "%s: tcsetattr: %m", printer);
|
|
|
|
exit(1);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1995-10-03 18:02:17 +03:00
|
|
|
if (i.wset && ioctl(i.fd, TIOCSWINSZ, &i.win) < 0)
|
|
|
|
syslog(LOG_INFO, "%s: ioctl(TIOCSWINSZ): %m", printer);
|
|
|
|
return;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
1994-05-18 05:25:37 +04:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
1997-10-05 15:52:17 +04:00
|
|
|
static void
|
1994-05-18 05:25:37 +04:00
|
|
|
pstatus(const char *msg, ...)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
1997-10-05 19:11:58 +04:00
|
|
|
int fd;
|
1999-12-11 05:01:18 +03:00
|
|
|
char *buf;
|
1994-05-18 05:25:37 +04:00
|
|
|
va_list ap;
|
2004-08-26 17:05:14 +04:00
|
|
|
struct iovec iov[2];
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
umask(0);
|
|
|
|
fd = open(ST, O_WRONLY|O_CREAT, 0664);
|
|
|
|
if (fd < 0 || flock(fd, LOCK_EX) < 0) {
|
|
|
|
syslog(LOG_ERR, "%s: %s: %m", printer, ST);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
ftruncate(fd, 0);
|
2001-09-24 17:22:25 +04:00
|
|
|
va_start(ap, msg);
|
1999-12-11 05:01:18 +03:00
|
|
|
(void)vasprintf(&buf, msg, ap);
|
1994-05-18 05:25:37 +04:00
|
|
|
va_end(ap);
|
2004-08-26 17:05:14 +04:00
|
|
|
|
|
|
|
iov[0].iov_base = buf;
|
|
|
|
iov[0].iov_len = strlen(buf);
|
2005-11-28 06:26:06 +03:00
|
|
|
iov[1].iov_base = __UNCONST("\n");
|
2004-08-26 17:05:14 +04:00
|
|
|
iov[1].iov_len = 1;
|
|
|
|
(void)writev(fd, iov, 2);
|
1996-12-09 12:57:40 +03:00
|
|
|
(void)close(fd);
|
1999-12-11 05:01:18 +03:00
|
|
|
free(buf);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|