[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
lpd applying if to jobs to remote printers
- To: tech_(_at_)_openbsd_(_dot_)_org
- Subject: lpd applying if to jobs to remote printers
- From: Christoph Weiss <weissch_(_at_)_informatik_(_dot_)_tu-muenchen_(_dot_)_de>
- Date: Thu, 16 Dec 2004 22:38:14 +0100
Hello,
OpenBSD's lpd doesn't apply the ``if'' filter to remote printers.
Although this is the default behaviour, I guess there is no real reason
for it. There are reasons against it, though, as people might want to
filter their documents through apsfilter first (like me).
FreeBSD's lpd uses ``if'' for remote printers, hence I copied and
adapted their code into OpenBSD's src/usr.sbin/lpr/lpd/printjob.c
It only enables the ``if'' filter, as the -r option already handles the
output filter (or at least the man page says so, it didn't solve my
problems). The patch works fine for me here. I don't think there's
need for an extra option like -r (or for -r), because if you don't want
filtering done, just don't specify any filter in printcap.
Maybe the patch can make its way into the source tree?
I think this greatly improves lpd's usability (apsfilter even
explicitly complains about it).
--
fiesh
diff lpd/printjob.c lpd.new/printjob.c
--- lpd/printjob.c Tue Dec 7 22:32:37 2004
+++ lpd.new/printjob.c Tue Dec 7 22:32:46 2004
@@ -111,6 +111,9 @@
static char pxlength[10] = "-y"; /* page length in pixels */
static char pxwidth[10] = "-x"; /* page width in pixels */
static char tempfile[] = "errsXXXXXXXXXX"; /* file name for filter output */
+#define TFILENAME "/tmp/fltXXXXXXXXXX"
+static char tfile[] = TFILENAME; /* file name for filter output */
+
static char width[10] = "-w"; /* page width in static characters */
static void abortpr(int);
@@ -881,10 +877,11 @@
static int
sendfile(int type, char *file)
{
- int f, i, amt;
+ ssize_t nread;
+ int f, i, amt, fi, fo, n, nofile, status, fd;
struct stat stb;
- char buf[BUFSIZ];
- int sizerr, resp;
+ char buf[BUFSIZ], *av[10];
+ int sizerr, resp, sfres;
PRIV_START;
if (lstat(file, &stb) < 0 || (f = safe_open(file, O_RDONLY, 0)) < 0) {
@@ -900,14 +897,102 @@
if (S_ISLNK(stb.st_mode) && fstat(f, &stb) == 0 &&
(stb.st_dev != fdev || stb.st_ino != fino))
return(ACCESS);
+
+ if (type == '\3' && IF != NULL) {
+ av[0] = IF;
+ av[1] = width;
+ av[2] = length;
+ av[3] = indent;
+ av[4] = "-n";
+ av[5] = logname;
+ av[6] = "-h";
+ av[7] = fromhost;
+ av[8] = AF;
+ av[9] = NULL;
+
+ strcpy(tfile, TFILENAME);
+ fo = mkstemp(tfile);
+ if (fo == -1) {
+ syslog(LOG_ERR, "cannot mkstemp %s: %m", TFILENAME);
+ sfres = ERROR;
+ goto return_sfres;
+ }
+
+ if ((child = dofork(DORETURN)) == 0) { /* child */
+ dup2(f, 0);
+ dup2(fo, 1);
+ unlink(tempfile);
+ n = open(tempfile, O_WRONLY|O_CREAT|O_EXCL, 0664);
+ if (n >= 0)
+ dup2(n, 2);
+ closelog();
+ nofile = sysconf(_SC_OPEN_MAX);
+ for (n = 3; n < nofile; n++)
+ (void)close(n);
+ execv(IF, av);
+ syslog(LOG_ERR, "cannot execv %s", IF);
+ _exit(2);
+ }
+ if (child < 0) {
+ child = 0;
+ syslog(LOG_ERR, "cannot start child process: %m");
+ sfres = ERROR;
+ goto return_sfres;
+ }
+ while ((pid = wait(&status)) > 0 && pid != child)
+ ;
+ child = 0;
+
+ fd = safe_open(tempfile, O_RDONLY|O_NOFOLLOW, 0);
+ if (fd >= 0) {
+ while ((nread = read(fd, buf, sizeof(buf))) > 0)
+ (void)write(STDERR_FILENO, buf, nread);
+ (void)close(fd);
+ }
+
+ if (!WIFEXITED(status)) {
+ syslog(LOG_WARNING, "filter terminated (termsig=%d)",
+ WTERMSIG(status));
+ sfres = ERROR;
+ goto return_sfres;
+ }
+ switch (WEXITSTATUS(status)) {
+ case 0:
+ break;
+ case 1:
+ sfres = REPRINT;
+ goto return_sfres;
+ case 2:
+ sfres = ERROR;
+ goto return_sfres;
+ default:
+ syslog(LOG_WARNING, "filter exited (retcode=%d)",
+ WEXITSTATUS(status));
+ sfres = FILTERERR;
+ goto return_sfres;
+ }
+ (void)close(f);
+ f = fo;
+ file = tfile;
+ if (fstat(f, &stb) < 0) {
+ syslog(LOG_ERR, "%s: error processing 'if', lstat %s: %m", tfile);
+ sfres = ERROR;
+ goto return_sfres;
+ }
+ lseek(f, 0, SEEK_SET);
+ }
+
+
if ((amt = snprintf(buf, sizeof(buf), "%c%lld %s\n", type,
- (long long)stb.st_size, file)) >= sizeof(buf) || amt == -1)
- return (ACCESS); /* XXX hack */
+ (long long)stb.st_size, file)) >= sizeof(buf) || amt == -1) {
+ sfres = ACCESS;
+ goto return_sfres; /* XXX hack */
+ }
for (i = 0; ; i++) {
if (write(pfd, buf, amt) != amt ||
(resp = response()) < 0 || resp == '\1') {
- (void)close(f);
- return(REPRINT);
+ sfres = REPRINT;
+ goto return_sfres;
} else if (resp == '\0')
break;
if (i == 0)
@@ -938,22 +1023,34 @@
alarm(0);
(void)sigaction(SIGALRM, &osa, NULL);
(void)close(f);
- return(REPRINT);
+ sfres = REPRINT;
+ goto return_sfres;
}
alarm(0);
(void)sigaction(SIGALRM, &osa, NULL);
}
- (void)close(f);
if (sizerr) {
syslog(LOG_INFO, "%s: %s: changed size", printer, file);
/* tell recvjob to ignore this file */
(void)write(pfd, "\1", 1);
- return(ERROR);
+ sfres = ERROR;
+ goto return_sfres;
}
- if (write(pfd, "", 1) != 1 || response())
- return(REPRINT);
- return(OK);
+ if (write(pfd, "", 1) != 1 || response()) {
+ sfres = REPRINT;
+ goto return_sfres;
+ }
+ sfres = OK;
+
+return_sfres:
+ (void)close(f);
+ if (fo != -1) {
+ /* Remove temporary file */
+ fo = -1;
+ unlink(tfile);
+ }
+ return (sfres);
}
/*
Visit your host, monkey.org