Subject: bin/806: rpc.rstatd screws up reported stats (fix included)
To: None <gnats-admin@NetBSD.ORG>
From: None <jarle@idt.unit.no>
List: netbsd-bugs
Date: 02/18/1995 16:50:05
>Number:         806
>Category:       bin
>Synopsis:       Union of structures leads to incorrect results.
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Feb 18 16:50:04 1995
>Originator:     Jarle Greipsland
>Organization:
"Bozos'R'Us.	"
>Release:        1.0
>Environment:
	
System: NetBSD darling.idt.unit.no 1.0 NetBSD 1.0 (DARLING) #9: Wed Feb 15 21:11:36 MET 1995 root@darling.idt.unit.no:/usr/src/sys/arch/i386/compile/DARLING i386


>Description:
rpc.rstatd handles the 3 different protocol version by assuming that ver 3
is the superset of the other 2.  This is correct as far as the variables
go, but it is not correct when it comes to the layout of the variables in
their structures.  The culprit is the field if_opackets that is always at
the end of the stats-structures.  New fields in the newer version of the
protocol have been inserted prior to this field, see the file
/usr/src/lib/librpcsvc/src/rstat.x for details.  rpc.rstatd overwrites the 
v_swtch field with the value of if_opackets.  The most intuitive fix
would probably be to shuffle the fields around a bit, but this will break
compatibility with other systems as well as with previous versions of
NetBSD.  The proper fix is therefore to repair rpc.rstatd.  Diffs below.
	
>How-To-Repeat:
Modify 'rup' so that it will print out the v_swtch field.  This field will then
incorrectly hold the number of output packets instead of the number of context
switches.
	
>Fix:
	
Apply diffs.  Sets everything up to use the ver 3 superset.  If some program
wants an older version of the results, fix it at replytime.  The diffs are for
a pure NetBSD/i386 1.0 system, so you may need to do some diddling for it to 
snap into -current.

*** src/libexec/rpc.rstatd/rstat_proc.c.orig	Sat Feb 18 21:44:17 1995
--- src/libexec/rpc.rstatd/rstat_proc.c	Sat Feb 18 21:51:09 1995
***************
*** 173,176 ****
--- 173,177 ----
          stat_init();
      sincelastreq = 0;
+     stats_all.s2.if_opackets = stats_all.s3.if_opackets;
      return(&stats_all.s2);
  }
***************
*** 182,185 ****
--- 183,187 ----
          stat_init();
      sincelastreq = 0;
+     stats_all.s1.if_opackets = stats_all.s3.if_opackets;
      return(&stats_all.s1);
  }
***************
*** 250,259 ****
  	}
  	for (i = 0; i < CPUSTATES; i++)
! 		stats_all.s1.cp_time[i] = cp_time[cp_xlat[i]];
  #else
   	if (kvm_read(kfd, (long)nl[X_CPTIME].n_value,
! 		     (char *)stats_all.s1.cp_time,
! 		     sizeof (stats_all.s1.cp_time))
! 	    != sizeof (stats_all.s1.cp_time)) {
  		syslog(LOG_ERR, "rstat: can't read cp_time from kmem\n");
  		exit(1);
--- 252,261 ----
  	}
  	for (i = 0; i < CPUSTATES; i++)
! 		stats_all.s3.cp_time[i] = cp_time[cp_xlat[i]];
  #else
   	if (kvm_read(kfd, (long)nl[X_CPTIME].n_value,
! 		     (char *)stats_all.s3.cp_time,
! 		     sizeof (stats_all.s3.cp_time))
! 	    != sizeof (stats_all.s3.cp_time)) {
  		syslog(LOG_ERR, "rstat: can't read cp_time from kmem\n");
  		exit(1);
***************
*** 284,289 ****
  
  #ifdef DEBUG
! 	fprintf(stderr, "%d %d %d %d\n", stats_all.s1.cp_time[0],
! 	    stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]);
  #endif
  
--- 286,291 ----
  
  #ifdef DEBUG
! 	fprintf(stderr, "%d %d %d %d\n", stats_all.s3.cp_time[0],
! 	    stats_all.s3.cp_time[1], stats_all.s3.cp_time[2], stats_all.s3.cp_time[3]);
  #endif
  
***************
*** 293,319 ****
  		exit(1);
  	}
! 	stats_all.s1.v_pgpgin = cnt.v_pgpgin;
! 	stats_all.s1.v_pgpgout = cnt.v_pgpgout;
! 	stats_all.s1.v_pswpin = cnt.v_pswpin;
! 	stats_all.s1.v_pswpout = cnt.v_pswpout;
! 	stats_all.s1.v_intr = cnt.v_intr;
  	gettimeofday(&tm, (struct timezone *) 0);
! 	stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
  	    hz*(tm.tv_usec - btm.tv_usec)/1000000;
  	stats_all.s2.v_swtch = cnt.v_swtch;
  
   	if (kvm_read(kfd, (long)nl[X_DKXFER].n_value,
! 		     (char *)stats_all.s1.dk_xfer,
! 		     sizeof (stats_all.s1.dk_xfer))
! 	    != sizeof (stats_all.s1.dk_xfer)) {
  		syslog(LOG_ERR, "rstat: can't read dk_xfer from kmem\n");
  		exit(1);
  	}
  
! 	stats_all.s1.if_ipackets = 0;
! 	stats_all.s1.if_opackets = 0;
! 	stats_all.s1.if_ierrors = 0;
! 	stats_all.s1.if_oerrors = 0;
! 	stats_all.s1.if_collisions = 0;
  	for (off = firstifnet, i = 0; off && i < numintfs; i++) {
  		if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
--- 295,321 ----
  		exit(1);
  	}
! 	stats_all.s3.v_pgpgin = cnt.v_pgpgin;
! 	stats_all.s3.v_pgpgout = cnt.v_pgpgout;
! 	stats_all.s3.v_pswpin = cnt.v_pswpin;
! 	stats_all.s3.v_pswpout = cnt.v_pswpout;
! 	stats_all.s3.v_intr = cnt.v_intr;
  	gettimeofday(&tm, (struct timezone *) 0);
! 	stats_all.s3.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
  	    hz*(tm.tv_usec - btm.tv_usec)/1000000;
  	stats_all.s2.v_swtch = cnt.v_swtch;
  
   	if (kvm_read(kfd, (long)nl[X_DKXFER].n_value,
! 		     (char *)stats_all.s3.dk_xfer,
! 		     sizeof (stats_all.s3.dk_xfer))
! 	    != sizeof (stats_all.s3.dk_xfer)) {
  		syslog(LOG_ERR, "rstat: can't read dk_xfer from kmem\n");
  		exit(1);
  	}
  
! 	stats_all.s3.if_ipackets = 0;
! 	stats_all.s3.if_opackets = 0;
! 	stats_all.s3.if_ierrors = 0;
! 	stats_all.s3.if_oerrors = 0;
! 	stats_all.s3.if_collisions = 0;
  	for (off = firstifnet, i = 0; off && i < numintfs; i++) {
  		if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
***************
*** 322,330 ****
  			exit(1);
  		}
! 		stats_all.s1.if_ipackets += ifnet.if_data.ifi_ipackets;
! 		stats_all.s1.if_opackets += ifnet.if_data.ifi_opackets;
! 		stats_all.s1.if_ierrors += ifnet.if_data.ifi_ierrors;
! 		stats_all.s1.if_oerrors += ifnet.if_data.ifi_oerrors;
! 		stats_all.s1.if_collisions += ifnet.if_data.ifi_collisions;
  		off = (int) ifnet.if_next;
  	}
--- 324,332 ----
  			exit(1);
  		}
! 		stats_all.s3.if_ipackets += ifnet.if_data.ifi_ipackets;
! 		stats_all.s3.if_opackets += ifnet.if_data.ifi_opackets;
! 		stats_all.s3.if_ierrors += ifnet.if_data.ifi_ierrors;
! 		stats_all.s3.if_oerrors += ifnet.if_data.ifi_oerrors;
! 		stats_all.s3.if_collisions += ifnet.if_data.ifi_collisions;
  		off = (int) ifnet.if_next;
  	}

						-jarle
----
"... except from the fact that it doesn't work, what do you think about the
     program?"
>Audit-Trail:
>Unformatted: