Changes to lpd to run if and of on remote printers

David Brownlee <[email protected]>
Newsgroups gmane.os.netbsd.devel.general
Message-ID <[email protected]>
	lpd has a '-r' option to run 'of' for remote printers, but it
	doesn't actually pass the contents of any files through it.

	We have another application here that means we want to run
	'if' in that same situation (-r passed).

	Complications:
	    - lpd has to send the size of the file across before its
	      contents, so to work the filter has to store the results
	      to a temporary file.
	    - Each file is sent separately so 'of' has to be run for each
	      entry, rather than once for everything sent (assuming I've
	      followed the logic correctly).

	I've come up with a set of patches that handles this - does
	anyone have any thought/objections/comments?

-- 
		David Brownlee/absolute          [email protected]
diff (text/plain, 4.6 KB)
Index: lpd/printjob.c
===================================================================
RCS file: /cvsroot/basesrc/usr.sbin/lpr/lpd/printjob.c,v
retrieving revision 1.34
diff -u -B -r1.34 printjob.c
--- lpd/printjob.c	2002/07/14 15:28:00	1.34
+++ lpd/printjob.c	2002/08/28 14:38:07
@@ -117,6 +117,7 @@
 static char	pxlength[10] = "-y";	/* page length in pixels */
 static char	pxwidth[10] = "-x";	/* page width in pixels */
 static char	tempfile[] = "errsXXXXXX"; /* file name for filter output */
+static char	tempremote[] = "remoteXXXXXX"; /* file name for remote filter */
 static char	width[10] = "-w";	/* page width in static characters */
 
 static void	abortpr(int);
@@ -124,14 +125,15 @@
 static int	dofork(int);
 static int	dropit(int);
 static void	init(void);
+static void	setup_ofilter(int);
+static void	close_ofilter(void);
 static void	openpr(void);
 static void	opennet(char *);
 static void	opentty(void);
 static void	openrem(void);
 static int	print(int, char *);
 static int	printit(char *);
-static void	pstatus(const char *, ...)
-	__attribute__((__format__(__printf__, 1, 2)));
+static void	pstatus(const char *, ...);
 static char	response(void);
 static void	scan_out(int, char *, int);
 static char	*scnline(int, char *, int);
@@ -167,6 +169,7 @@
 	signal(SIGTERM, abortpr);
 
 	(void)mktemp(tempfile);		/* OK */
+	(void)mktemp(tempremote);	/* OK */
 
 	/*
 	 * uses short form file names
@@ -256,13 +259,8 @@
 		else if (i == REPRINT && ++errcnt < 5) {
 			/* try reprinting the job */
 			syslog(LOG_INFO, "restarting %s", printer);
-			if (ofilter > 0) {
-				kill(ofilter, SIGCONT);	/* to be sure */
-				(void)close(ofd);
-				while ((i = wait(NULL)) > 0 && i != ofilter)
-					;
-				ofilter = 0;
-			}
+			if (ofilter > 0)
+				close_ofilter();
 			(void)close(pfd);	/* close printer */
 			if (ftruncate(lfd, pidoff) < 0)
 				syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
@@ -298,6 +296,7 @@
 				(void)write(ofd, TR, strlen(TR));
 		}
 		(void)unlink(tempfile);
+		(void)unlink(tempremote);
 		exit(0);
 	}
 	goto again;
@@ -854,7 +853,30 @@
 	struct stat stb;
 	char buf[BUFSIZ];
 	int sizerr, resp;
+	extern int rflag;
+
+	if (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;
+	}
+
 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
 		return(ERROR);
 	/*
@@ -1188,6 +1211,7 @@
 abortpr(int signo)
 {
 	(void)unlink(tempfile);
+	(void)unlink(tempremote);
 	kill(0, SIGINT);
 	if (ofilter > 0)
 		kill(ofilter, SIGCONT);
@@ -1276,34 +1300,19 @@
 	tof = (cgetcap(bp, "fo", ':') == NULL);
 }
 
-/*
- * Acquire line printer or remote connection.
- */
+/*      
+ * Setup output filter - called once for local printer, or (if -r given to lpd)
+ * once per file for remote printers
+ */     
 static void
-openpr(void)
+setup_ofilter(int check_rflag)
 {
-	int i, nofile;
-	char *cp;
 	extern int rflag;
-
-	if (!remote && *LP) {
-		if ((cp = strchr(LP, '@')))
-			opennet(cp);
-		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.
-	 */
-	if ((!remote || rflag) && OF) {
+	if (OF && (!remote || (check_rflag && rflag))) {
 		int p[2];
+		int i, nofile;
+		char *cp;
 
 		pipe(p);
 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
@@ -1327,6 +1336,51 @@
 		ofd = pfd;
 		ofilter = 0;
 	}
+}
+
+/*
+ * 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)
+{
+	char *cp;
+
+	if (!remote && *LP) {
+		if ((cp = strchr(LP, '@')))
+			opennet(cp);
+		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);
 }
 
 /*
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.