[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

lpd applying if to jobs to remote printers



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