[comp.unix.ultrix] rpc rstatd for RISC Ultrix

iglesias@draco.acs.uci.edu (Mike Iglesias) (11/10/90)

Recently, I posted a question about whether anyone had a rpc.rstatd (as
Sun calls it) for Ultrix on DECstations.  I didn't get any answers, so
I started looking into it myself.  I found a copy of the Sun RPC sources
on uunet.uu.net in comp.sources.unix/volume13/rpc3.9 and started working
from there.

I found that the sources included the source for the rpc rstatd daemon,
so I modified the code using the sources for 'top' that are on
gatekeeper.dec.com as a guide.  You need to do the following:

  Build rpcgen from the sources and put it in your path so it can
  be found in the next step.

  cd to the rpcsvc directory and type 'make'.  Kill the make when
  it starts compiling the sources (let the rpcgen stuff finish!).

  Apply the patch at the end of this message to rstat_proc.c.

  Modify the Makefile CFLAGS to include -DULTRIXV4 (for Ultrix v4.x)
  or -DULTRIXV3 (for Ultrix v3.x).  Type 'make' again and it should
  compile and link rstat_svc.

I've run the daemon under Ultrix v3.1, v4.0, and v4.1, and it appears
to work correctly.  Please note that I've only run it on DECstation
3100s and 5000; we don't have any vaxen running Ultrix around here
so I couldn't test it for those systems.

I wasn't able to get the rpc library to compile correctly (dies in
xdr_float.c), but the routines supplied by DEC (in libc.a) seem to
work.  I haven't been able to get any client programs (for example,
xmeter) to work on the DECstations; they all complain that they can't
decode the results from either my daemons or daemons running on Sun
systems.  I have no idea what the problem is, nor have I had time to
look into it further.  Clients running on Suns are able to get the
data correctly from my daemons. 

Since I did the changes, I have found out that titan.rice.edu has
a newer release of the RPC sources.  I haven't had a chance to look
at those and put my changes into them.  If you try to put my changes
into the newer sources, you're on your own!

As always, use these changes at your own risk.  I can't mail out
the RPC sources;  you'll have to get them from uunet yourself.


Mike Iglesias
University of California, Irvine
Internet:    iglesias@draco.acs.uci.edu
BITNET:      iglesias@uci
uucp:        ...!ucbvax!ucivax!iglesias



*** rstat_proc.c.orig	Fri Oct 19 10:53:59 1990
--- rstat_proc.c	Fri Nov  9 10:25:54 1990
***************
*** 50,60 ****
--- 50,73 ----
  #include <sys/vmmeter.h>
  #include <net/if.h>
  #include <sys/time.h>
+ #ifdef  ultrix
+ # include <sys/fixpoint.h>
+ # ifdef ULTRIXV4
+ #  include <sys/param.h>
+ #  include <machine/cpu.h>
+ #  include <sys/cpudata.h>
+ # endif
+ #endif
  #include "rstat.h"
  
  struct nlist nl[] = {
+ #ifdef ULTRIXV4
+ #define X_CPUDATA	0
+ 	{ "_cpudata" },
+ #else
  #define	X_CPTIME	0
  	{ "_cp_time" },
+ #endif
  #define	X_SUM		1
  	{ "_sum" },
  #define	X_IFNET		2
***************
*** 67,72 ****
--- 80,91 ----
  	{ "_avenrun" },
  #define X_HZ		6
  	{ "_hz" },
+ #ifdef ULTRIXV4
+ #define X_LOWCPU	7
+ 	{ "_lowcpu" },
+ #define X_HIGHCPU	8
+ 	{ "_highcpu" },
+ #endif
  	"",
  };
  int kmem;
***************
*** 73,78 ****
--- 92,106 ----
  int firstifnet, numintfs;	/* chain of ethernet interfaces */
  int stats_service();
  
+ #ifdef ULTRIXV4
+ struct	cpudata *cpudata[MAXCPU];
+ struct  cpudata onecpu;
+ int ncpu;
+ int i;
+ int lowcpu = 0;
+ int highcpu = 0;
+ #endif
+ 
  /*
   *  Define EXIT_WHEN_IDLE if you are able to have this program invoked
   *  automatically on demand (as from inetd).  When defined, the service
***************
*** 163,169 ****
--- 191,201 ----
  	int off, i, hz;
  	struct vmmeter sum;
  	struct ifnet ifnet;
+ #if defined(ultrix) && defined(mips)
+ 	fix avrun[3];
+ #else
  	double avrun[3];
+ #endif
  	struct timeval tm, btm;
  
  #ifdef DEBUG
***************
*** 186,191 ****
--- 218,274 ----
  		fprintf(stderr, "rstat: can't read hz from kmem\n");
  		exit(1);
  	}
+ #ifdef ULTRIXV4
+ 	if (lseek(kmem, (long)nl[X_CPUDATA].n_value, 0) == -1) {
+ 		fprintf(stderr, "rstat: can't seek in kmem\n");
+ 		exit(1);
+ 	}
+ 	if (read(kmem, (char *)cpudata, sizeof(cpudata)) != sizeof(cpudata)) {
+ 		fprintf(stderr, "rstat: can't read cpudata from kmem\n");
+ 		exit(1);
+ 	}		
+ 	if (lseek(kmem, (long)nl[X_LOWCPU].n_value, 0) == -1) {
+ 		fprintf(stderr, "rstat: can't seek in kmem\n");
+ 		exit(1);
+ 	}
+ 	if (read(kmem, (char *)&lowcpu, sizeof(lowcpu)) != sizeof(lowcpu)) {
+ 		fprintf(stderr, "rstat: can't read lowcpu from kmem\n");
+ 		exit(1);
+ 	}		
+ 
+ 	if (lseek(kmem, (long)nl[X_HIGHCPU].n_value, 0) == -1) {
+ 		fprintf(stderr, "rstat: can't seek in kmem\n");
+ 		exit(1);
+ 	}
+ 	if (read(kmem, (char *)&highcpu, sizeof(highcpu)) != sizeof(highcpu)) {
+ 		fprintf(stderr, "rstat: can't read highcpu from kmem\n");
+ 		exit(1);
+ 	}		
+ 
+ 	for (i = 0; i < CPUSTATES; ++i)
+ 		stats_all.s1.cp_time[i] = 0;
+ 
+ 	stats_all.s1.v_intr = 0;
+ 	stats_all.s2.v_swtch = 0;
+ 
+ 	for (ncpu = lowcpu; ncpu <= highcpu; ++ncpu) {
+ 		if (cpudata[ncpu]) {
+ 			if (lseek(kmem, cpudata[ncpu], 0) == -1) {
+ 				fprintf(stderr, "rstat: can't seek in kmem(cpudata)\n");
+ 				exit(1);
+ 			}
+ 			if (read(kmem, (char *)&onecpu, sizeof (onecpu)) != sizeof(onecpu)) {
+ 				fprintf(stderr, "rstat: can't read *cpudata from kmem\n");
+ 				exit(1);
+ 			}
+ 			stats_all.s1.v_intr += onecpu.cpu_intr;
+ 		        stats_all.s2.v_swtch += onecpu.cpu_switch;
+ 
+ 			for (i = 0; i < CPUSTATES; i++)
+ 				stats_all.s1.cp_time[i] += onecpu.cpu_cptime[i];
+ 		}
+ 	}
+ #else
  	if (lseek(kmem, (long)nl[X_CPTIME].n_value, 0) == -1) {
  		fprintf(stderr, "rstat: can't seek in kmem\n");
  		exit(1);
***************
*** 195,200 ****
--- 278,284 ----
  		fprintf(stderr, "rstat: can't read cp_time from kmem\n");
  		exit(1);
  	}
+ #endif
  	if (lseek(kmem, (long)nl[X_AVENRUN].n_value, 0) ==-1) {
  		fprintf(stderr, "rstat: can't seek in kmem\n");
  		exit(1);
***************
*** 208,213 ****
--- 292,306 ----
  	stats_all.s2.avenrun[1] = avrun[1] * FSCALE;
  	stats_all.s2.avenrun[2] = avrun[2] * FSCALE;
  #endif
+ #if defined(ultrix) && defined(mips)
+  	if (read(kmem, (char *)avrun, sizeof (avrun)) != sizeof (avrun)) {
+ 		fprintf(stderr, "rstat: can't read avenrun from kmem\n");
+ 		exit(1);
+ 	}
+ 	stats_all.s2.avenrun[0] = avrun[0];
+ 	stats_all.s2.avenrun[1] = avrun[1];
+ 	stats_all.s2.avenrun[2] = avrun[2];
+ #endif
  	if (lseek(kmem, (long)nl[X_BOOTTIME].n_value, 0) == -1) {
  		fprintf(stderr, "rstat: can't seek in kmem\n");
  		exit(1);
***************
*** 238,248 ****
  	stats_all.s1.v_pgpgout = sum.v_pgpgout;
  	stats_all.s1.v_pswpin = sum.v_pswpin;
  	stats_all.s1.v_pswpout = sum.v_pswpout;
  	stats_all.s1.v_intr = sum.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 = sum.v_swtch;
  
  	if (lseek(kmem, (long)nl[X_DKXFER].n_value, 0) == -1) {
  		fprintf(stderr, "rstat: can't seek in kmem\n");
--- 331,345 ----
  	stats_all.s1.v_pgpgout = sum.v_pgpgout;
  	stats_all.s1.v_pswpin = sum.v_pswpin;
  	stats_all.s1.v_pswpout = sum.v_pswpout;
+ #ifndef ULTRIXV4 
  	stats_all.s1.v_intr = sum.v_intr;
+ 	stats_all.s2.v_swtch = sum.v_swtch;
+ #endif
+ #ifndef ULTRIXV3
  	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;
! #endif
  
  	if (lseek(kmem, (long)nl[X_DKXFER].n_value, 0) == -1) {
  		fprintf(stderr, "rstat: can't seek in kmem\n");

frank@croton.enet.dec.com (Frank Wortner) (11/12/90)

> I wasn't able to get the rpc library to compile correctly (dies in
> xdr_float.c), but the routines supplied by DEC (in libc.a) seem to
> work.  I haven't been able to get any client programs (for example,
> xmeter) to work on the DECstations; they all complain that they can't
> decode the results from either my daemons or daemons running on Sun
> systems.  I have no idea what the problem is, nor have I had time to
> look into it further.  Clients running on Suns are able to get the
> data correctly from my daemons. 

xdr_float.o is broken on pre 4.x versions of ULTRIX software, so that might
be your problem.  The source version of xdr_float.c as distributed by Sun
doesn't have support for little-endian IEEE machines.  Funny, it does
support VAXen, though!  Anyway, here's a version I kludged together which
compiles and works (for me, at least).

Enjoy!
					Frank


/* @(#)xdr_float.c	1.1 87/11/04 3.9 RPCSRC */
/*
 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
 * unrestricted use provided that this legend is included on all tape
 * media and as a part of the software program in whole or part.  Users
 * may copy or modify Sun RPC without charge, but are not authorized
 * to license or distribute it to anyone else except as part of a product or
 * program developed by the user.
 * 
 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
 * 
 * Sun RPC is provided with no support and without any obligation on the
 * part of Sun Microsystems, Inc. to assist in its use, correction,
 * modification or enhancement.
 * 
 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
 * OR ANY PART THEREOF.
 * 
 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
 * or profits or other special, indirect and consequential damages, even if
 * Sun has been advised of the possibility of such damages.
 * 
 * Sun Microsystems, Inc.
 * 2550 Garcia Avenue
 * Mountain View, California  94043
 */
#if !defined(lint) && defined(SCCSIDS)
static char sccsid[] = "@(#)xdr_float.c 1.12 87/08/11 Copyr 1984 Sun Micro";
#endif

/*
 * xdr_float.c, Generic XDR routines impelmentation.
 *
 * Copyright (C) 1984, Sun Microsystems, Inc.
 *
 * These are the "floating point" xdr routines used to (de)serialize
 * most common data items.  See xdr.h for more info on the interface to
 * xdr.
 */

#include <stdio.h>

#include <rpc/types.h>
#include <rpc/xdr.h>

/*
 * NB: Not portable.
 * This routine works on Suns (Sky / 68000's) and Vaxen.
 * MIPSEL works now, too.  --- 10-NOV-89  Frank Wortner
 */

#ifdef vax

/* What IEEE single precision floating point looks like on a Vax */
struct	ieee_single {
	unsigned int	mantissa: 23;
	unsigned int	exp     : 8;
	unsigned int	sign    : 1;
};

/* Vax single precision floating point */
struct	vax_single {
	unsigned int	mantissa1 : 7;
	unsigned int	exp       : 8;
	unsigned int	sign      : 1;
	unsigned int	mantissa2 : 16;
};

#define VAX_SNG_BIAS	0x81
#define IEEE_SNG_BIAS	0x7f

static struct sgl_limits {
	struct vax_single s;
	struct ieee_single ieee;
} sgl_limits[2] = {
	{{ 0x7f, 0xff, 0x0, 0xffff },	/* Max Vax */
	{ 0x0, 0xff, 0x0 }},		/* Max IEEE */
	{{ 0x0, 0x0, 0x0, 0x0 },	/* Min Vax */
	{ 0x0, 0x0, 0x0 }}		/* Min IEEE */
};

#endif /* vax */

bool_t
xdr_float(xdrs, fp)
	register XDR *xdrs;
	register float *fp;
{
#ifdef vax
	struct ieee_single is;
	struct vax_single vs, *vsp;
	struct sgl_limits *lim;
	int i;
#endif /* vax */

	switch (xdrs->x_op) {

	case XDR_ENCODE:

#ifndef vax 
		return (XDR_PUTLONG(xdrs, (long *)fp));
#else
		vs = *((struct vax_single *)fp);
		for (i = 0, lim = sgl_limits;
			i < sizeof(sgl_limits)/sizeof(struct sgl_limits);
			i++, lim++) {
			if ((vs.mantissa2 == lim->s.mantissa2) &&
				(vs.exp == lim->s.exp) &&
				(vs.mantissa1 == lim->s.mantissa1)) {
				is = lim->ieee;
				goto shipit;
			}
		}
		is.exp = vs.exp - VAX_SNG_BIAS + IEEE_SNG_BIAS;
		is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2;
	shipit:
		is.sign = vs.sign;
		return (XDR_PUTLONG(xdrs, (long *)&is));
#endif /* ndef vax */

	case XDR_DECODE:
#ifndef vax
		return (XDR_GETLONG(xdrs, (long *)fp));
#else
		vsp = (struct vax_single *)fp;
		if (!XDR_GETLONG(xdrs, (long *)&is))
			return (FALSE);
		for (i = 0, lim = sgl_limits;
			i < sizeof(sgl_limits)/sizeof(struct sgl_limits);
			i++, lim++) {
			if ((is.exp == lim->ieee.exp) &&
				(is.mantissa == lim->ieee.mantissa)) {
				*vsp = lim->s;
				goto doneit;
			}
		}
		vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS;
		vsp->mantissa2 = is.mantissa;
		vsp->mantissa1 = (is.mantissa >> 16);
	doneit:
		vsp->sign = is.sign;
		return (TRUE);
#endif /* ndef vax */

	case XDR_FREE:
		return (TRUE);
	}
	return (FALSE);
}

/*
 * This routine works on Suns (Sky / 68000's) and Vaxen.
 */

#ifdef vax
/* What IEEE double precision floating point looks like on a Vax */
struct	ieee_double {
	unsigned int	mantissa1 : 20;
	unsigned int	exp       : 11;
	unsigned int	sign      : 1;
	unsigned int	mantissa2 : 32;
};

/* Vax double precision floating point */
struct  vax_double {
	unsigned int	mantissa1 : 7;
	unsigned int	exp       : 8;
	unsigned int	sign      : 1;
	unsigned int	mantissa2 : 16;
	unsigned int	mantissa3 : 16;
	unsigned int	mantissa4 : 16;
};

#define VAX_DBL_BIAS	0x81
#define IEEE_DBL_BIAS	0x3ff
#define MASK(nbits)	((1 << nbits) - 1)

static struct dbl_limits {
	struct	vax_double d;
	struct	ieee_double ieee;
} dbl_limits[2] = {
	{{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff },	/* Max Vax */
	{ 0x0, 0x7ff, 0x0, 0x0 }},			/* Max IEEE */
	{{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},		/* Min Vax */
	{ 0x0, 0x0, 0x0, 0x0 }}				/* Min IEEE */
};

#endif /* vax */


bool_t
xdr_double(xdrs, dp)
	register XDR *xdrs;
	double *dp;
{
	register long *lp;
#ifdef vax
	struct	ieee_double id;
	struct	vax_double vd;
	register struct dbl_limits *lim;
	int i;
#endif

	switch (xdrs->x_op) {

	case XDR_ENCODE:
#ifndef vax
		lp = (long *)dp;
#else
		vd = *((struct vax_double *)dp);
		for (i = 0, lim = dbl_limits;
			i < sizeof(dbl_limits)/sizeof(struct dbl_limits);
			i++, lim++) {
			if ((vd.mantissa4 == lim->d.mantissa4) &&
				(vd.mantissa3 == lim->d.mantissa3) &&
				(vd.mantissa2 == lim->d.mantissa2) &&
				(vd.mantissa1 == lim->d.mantissa1) &&
				(vd.exp == lim->d.exp)) {
				id = lim->ieee;
				goto shipit;
			}
		}
		id.exp = vd.exp - VAX_DBL_BIAS + IEEE_DBL_BIAS;
		id.mantissa1 = (vd.mantissa1 << 13) | (vd.mantissa2 >> 3);
		id.mantissa2 = ((vd.mantissa2 & MASK(3)) << 29) |
				(vd.mantissa3 << 13) |
				((vd.mantissa4 >> 3) & MASK(13));
	shipit:
		id.sign = vd.sign;
		lp = (long *)&id;
#endif /* ndef vax */

#ifdef MIPSEL
		return (XDR_PUTLONG(xdrs, lp+1) && XDR_PUTLONG(xdrs, lp));
#else
		return (XDR_PUTLONG(xdrs, lp++) && XDR_PUTLONG(xdrs, lp));
#endif /* MIPSEL */

	case XDR_DECODE:
#ifndef vax
		lp = (long *)dp;
#ifdef MIPSEL
		return (XDR_GETLONG(xdrs, lp+1) && XDR_GETLONG(xdrs, lp));
#else /* MIPSEL */
		return (XDR_GETLONG(xdrs, lp++) && XDR_GETLONG(xdrs, lp));
#endif /* MIPSEL */
#endif /* ndef vax */

#ifdef vax
		lp = (long *)&id;
		if (!XDR_GETLONG(xdrs, lp++) || !XDR_GETLONG(xdrs, lp))
			return (FALSE);
		for (i = 0, lim = dbl_limits;
			i < sizeof(dbl_limits)/sizeof(struct dbl_limits);
			i++, lim++) {
			if ((id.mantissa2 == lim->ieee.mantissa2) &&
				(id.mantissa1 == lim->ieee.mantissa1) &&
				(id.exp == lim->ieee.exp)) {
				vd = lim->d;
				goto doneit;
			}
		}
		vd.exp = id.exp - IEEE_DBL_BIAS + VAX_DBL_BIAS;
		vd.mantissa1 = (id.mantissa1 >> 13);
		vd.mantissa2 = ((id.mantissa1 & MASK(13)) << 3) |
				(id.mantissa2 >> 29);
		vd.mantissa3 = (id.mantissa2 >> 13);
		vd.mantissa4 = (id.mantissa2 << 3);
	doneit:
		vd.sign = id.sign;
		*dp = *((double *)&vd);
		return (TRUE);
#endif /* vax */

	case XDR_FREE:
		return (TRUE);
	}
	return (FALSE);
}