Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Posting-Version: notesnews 0.1 (unido 12/05/84); site unido.UUCP
Path: utzoo!watmath!clyde!cbosgd!cbdkc1!desoto!packard!hoxna!houxm!mtuxo!mtunh!mtung!mtunf!ariel!vax135!timeinc!phri!pesnta!amd!vecpyr!lll-crg!gymble!umcp-cs!seismo!mcvax!unido!ab
From: ab@unido.UUCP
Newsgroups: net.unix
Subject: Re: what is going on here ???
Message-ID: 
Date: Wed, 26-Jun-85 14:29:00 EDT
Article-I.D.: unido.nf11400003
Posted: Wed Jun 26 14:29:00 1985
Date-Received: Tue, 2-Jul-85 05:47:09 EDT
References: 
Sender: notes@unido.UUCP
Lines: 76
Nf-ID: #R:unido:11400002:unido:11400003:000:2266
Nf-From: unido!ab    Jun 26 14:29:00 1985

> If you are running 4.2, look at the following short program and
> guess what it will do. Then compile and run it and find out
> what it really does. 
> 
> Try to explain its behavior!! (- Is it a bug in 4.2 ??? :-) )

Here is the solution to the previously posted 'puzzle':

It is a nice method to terminate all running shells which share
the controlling terminal. -- And it is an example of unexpected
side-effects, caused by a relatively small and hidden bug.

The bug was produced by a typo in the statement which opens /dev/kmem.
Notice the wrong positions of the parentheses:

>       if((kmem = open ("/dev/kmem", 0) < 0)) {

kmem stays 0 and the lseek on kmem is actually done on stdin !!!

The lseek takes the read/write-pointer of the terminal-channel to
an unaccessible position and all following reads or writes of any
process from/to the terminal will fail. This will cause all shells
to terminate! (See also the source below.)

Andreas Bormann                 ab@unido.UUCP
University of Dortmund          N 51 29' 05"   E 07 24' 42"
West Germany

--- CUT HERE ---------- CUT HERE ---------- CUT HERE ---------- CUT HERE ----
#include 

#define NAMELIST "/vmunix"

struct nlist    avenrun[] = {
      { "_avenrun" },
      { "" }
};

main()
{
	register int    kmem;
	double  avg[3];

	if((kmem = open ("/dev/kmem", 0) < 0)) { /* HERE's THE BUG !!! */
/*
 * If the open-call succeeds, it will return a positive filedescriptor
 * and kmem will be 0 because the positive descriptor isn't less than 0.
 *
 * This is the corrected statement:
 *  
 *      if((kmem = open ("/dev/kmem", 0)) < 0) {
 */
		printf("Cannot open kmem\n");    
		exit(1);
	}
	nlist(NAMELIST, avenrun);
	if(avenrun[0].n_type == 0) {
		printf("Cannot find avenrun\n");
		exit(1);
	}
/*
 * Remember: kmem == 0 !!
 * avenrun[0].n_value is something like -2147230472,
 * so the lseek will seek the read/write-pointer ON THE STDIN to
 * an unaccessible position.
 */
	lseek(kmem, (long) avenrun[0].n_value, 0);
/*
 * All successive reads by all processes which share the terminal
 * will now return an error (-1) and the parent shells will terminate!!!
 */
	read(kmem, (char *) avg, 3 * sizeof (double));
	printf("Load average: %f %f %f\n", avg[0], avg[1], avg[2]);
	exit(0);
}