[news.sysadmin] Tekvm corrupts data in pipes; fix for rnews

snoopy@sopwith.UUCP (Snoopy T. Beagle) (11/02/88)

If you are not running a Tektronix machine, and your news neighbors are
not, it is probably safe for you to skip this article.

There is a bug in the Tektronix implementation of the shared memory features
(mmap(2) and friends) which were documented in the 4.[23] BSD manuals.  It
causes corruption of data sent from a parent to a child through a pipe.
The stock rnews program corrupts news articles when run under a tekvm kernel.
I have included a context diff for a kludge workaround for rnews below.
This kludge fixes news unbatching, but there may be other programs which
use pipes in this manner, so beware.  Typical pipes between siblings as
setup by normal shell command pipelines seem to work fine.  The problem
*may* be unique to parent->child pipes.

All tekvm kernels tested have had the bug.  No kernels tested using the stock
BSD memory system have displayed the bug.  If you are running the default
kernel that came with release 2.2 or newer you are probably running a
tekvm kernel.  If you are running 2.1.1 or older software, if your machine
is a 6200 series, or if your kernel claims to be "bsdvm" or "oldvm", you
are probably safe.  If you have been running news for awhile and are
receiving your news in compressed batches and have not noticed any
corruption of articles, you are probably safe.

If you have questions about this, you may send me mail at the
addresses below.

Here is a context diff to ifuncs.c for rnews:
======================  cut here  =================================
--- ifuncs.c
***************
*** 1249,1254
  	int c;
  	char *cp;
  
  	setbuf(infp, (char *)NULL);
  	while ((c = getc(infp)) == '#') {
  		/* some kind of batch, investigate further */

--- 1249,1264 -----
  	int c;
  	char *cp;
  
+ 	int avoid_pipe = 1;	/* Kludge for tekvm: avoid using a pipe,
+ 				 * since tekvm corrupts the data if a
+ 				 * pipe is used.  This forces rnews to
+ 				 * always use a tmp file; less efficient,
+ 				 * but the articles don't get corrupted.
+ 				 * Kludge may be turned off when using 
+ 				 * bsdvm kernels by setting avoid_pipe
+ 				 * to 0.
+ 				 */
+ 
  	setbuf(infp, (char *)NULL);
  	while ((c = getc(infp)) == '#') {
  		/* some kind of batch, investigate further */
***************
*** 1302,1308
  					if (rc <= 0)
  						break;
  					if (fd < 0) {
! 						if (rc == asize)
  							break;	/* fits in buffer */
  						if (!tfilename) {
  							tfilename = "/tmp/unbnewsXXXXXX";

--- 1312,1318 -----
  					if (rc <= 0)
  						break;
  					if (fd < 0) {
! /* kludge for tekvm */				if ((!avoid_pipe) && (rc == asize))
  							break;	/* fits in buffer */
  						if (!tfilename) {
  							tfilename = "/tmp/unbnewsXXXXXX";
***************
*** 1342,1348
  				 * of ourselves for each article and allow it
  				 * to process. 
  				 */
! 				if (rc == asize) {
  					/*
  					 * article fits in buffer, use a pipe
  					 * instead of a temporary file. 

--- 1352,1358 -----
  				 * of ourselves for each article and allow it
  				 * to process. 
  				 */
! /* tekvm kludge */			if ((!avoid_pipe) && (rc == asize)) {
  					/*
  					 * article fits in buffer, use a pipe
  					 * instead of a temporary file. 
***************
*** 1355,1361
  					sleep(60);
  				}
  				if (pid == 0) {
! 					if (rc == asize) {
  						/* article fits in buffer
  						 * make the output of the
  						 * pipe for STDIN 

--- 1365,1371 -----
  					sleep(60);
  				}
  				if (pid == 0) {
! /* tekvm kludge */			if ((!avoid_pipe) && (rc == asize)) {
  						/* article fits in buffer
  						 * make the output of the
  						 * pipe for STDIN 
***************
*** 1375,1381
  						 * normal article */
  				}
  				/* parent of fork */
! 				if (rc == asize) {
  					/* article fits in buffer */
  					wc = write(piped[1], buf, rc);
  					if (wc != rc) {

--- 1385,1391 -----
  						 * normal article */
  				}
  				/* parent of fork */
! /* tekvm kludge */		if ((!avoid_pipe) && (rc == asize)) {
  					/* article fits in buffer */
  					wc = write(piped[1], buf, rc);
  					if (wc != rc) {
======================  cut here  =================================
    _____     
   /_____\    Snoopy
  /_______\   
    |___|     tektronix!tekecs!sopwith!snoopy
    |___|     sun!nosun!illian!sopwith!snoopy