/* 
 * rstat RPC code
 */
/* John DiMarco, CSLab, University of Toronto <jdd@cs.toronto.edu> */

#ifdef RSTAT

/* LINTLIBRARY */
#define MULTIPROCESSOR

#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
#include <rpc/rpc.h>
#include "rstat.h"

/* most typical cpu states; for BSD systems */
#define CP_USER         0
#define CP_NICE         1
#define CP_SYS          2
#define CP_IDLE         3

#ifndef MAXDISKXFER
#define MAXDISKXFER 100
#endif /* MAXDISKXFER */

#define DISKSTATES 2 /* idle, transfer */

#define MAXCPUS 1 /* rstat only supports uniprocessors */
int ncpu;       /* number of CPUs */
int ndisk;      /* number of disks */

#define BUFFSIZE 64

#ifndef MAXHOSTNAMELEN
  /* Some U*x deviants managed to not have this in sys/param.h */
# define MAXHOSTNAMELEN 64
#endif

static statstime *sts;

static CLIENT *cl;

extern void draw_bar(/*int bar_num, int *states, int num_states*/);

extern char *rstathost;
extern int cpuflag, diskflag;

extern char *xmalloc(/* int nbytes */);
extern void shorten(/* char *hname */);

/* Called by -version */
void
rstat_version()
{
        printf("RSTAT: maxcpu=%d, maxdisk=%d\n", MAXCPUS,  RSTAT_DK_NDRIVE);
}

/* Called at the beginning to inquire how many bars are needed. */
int
rstat_num_bars()
{
	int nbars=0;

	if(NULL==(cl=clnt_create(rstathost, RSTATPROG, RSTATVERS_TIME, "udp"))){
		clnt_pcreateerror(rstathost);
		exit(1);
	}

	if(cpuflag){
		ncpu=MAXCPUS; 
		nbars += ncpu;
	}
	if(diskflag){
		ndisk=RSTAT_DK_NDRIVE;
		nbars += ndisk;
	}
	return(nbars);
}

/*
 * Indicates how many levels each bar has.  For most machines, each bar will
 * have the same stuff.  But one can, for instance, display memory use on one
 * bar, processor levels on others, etc.
 */
void
rstat_bar_items(nbars, items)
int nbars;
int items[];    /* nbars items in this */
{
    int i, n=0;

    if(cpuflag){
        for(i=0; i<ncpu; i++,n++){
                items[n] = RSTAT_CPUSTATES;
        }
    }
    if(diskflag){
	for(i=0; i<ndisk; i++,n++){
		items[n] = DISKSTATES;
	}
    }
}

/* Called after num_bars to ask for the bar names */
char **
rstat_label_bars(nbars)
{
        char **names;
        int i, base;
        static char hname[MAXHOSTNAMELEN + 1];
	char buf[MAXHOSTNAMELEN + 1 + BUFFSIZE];
	char *cpname="";

	(void)strcpy(hname, rstathost);
        shorten(hname);
        names = (char **) xmalloc(nbars * sizeof(char *));

	base=0; 

	if(cpuflag) {
		/* do cpu names */
		for(i=0; i<ncpu; i++) {
			(void) sprintf(buf, "%s%s%s%d", hname, 
					hname[0]?" ":"", cpname, i);
			names[base+i] = xmalloc(strlen(buf) + 1);
			strcpy(names[base+i], buf);
		}
		base+=ncpu;
	}
	if(diskflag) {
		/* do disk names */
		for(i=0; i <ndisk; i++) {
			(void) sprintf(buf, "%s%sd%d", hname, hname[0]?" ":"", 
					i);
			names[base+i] = xmalloc(strlen(buf) + 1);
			strcpy(names[base+i], buf);
		}
		base+=ndisk;
        }
        return names;
}

/* 
 *  Called after the bars are created to perform any machine dependent
 *  initializations.
 */
/* ARGSUSED */
void
rstat_init_bars(nbars)
int nbars;
{
}

static void
display_cpu(base)
int base;
{
	int states[RSTAT_CPUSTATES], i;
	static long old[RSTAT_CPUSTATES];

	states[0] = (long)(sts->cp_time[CP_IDLE] - old[CP_IDLE]);
	states[1] = (long)(sts->cp_time[CP_NICE] - old[CP_NICE]);
	states[2] = (long)(sts->cp_time[CP_USER] - old[CP_USER]);
	states[3] = (long)(sts->cp_time[CP_SYS] - old[CP_SYS]);
	for(i=0;i<RSTAT_CPUSTATES;i++) old[i]=sts->cp_time[i];
	draw_bar(base, states, RSTAT_CPUSTATES);
}

static void
display_disk(base)
int base;
{
	int states[2], i;
	static long old[RSTAT_DK_NDRIVE];

	for(i=0;i<RSTAT_DK_NDRIVE;i++){
		long xfer;

		xfer = sts->dk_xfer[i]-old[i];
		if(xfer>MAXDISKXFER) xfer=MAXDISKXFER;
		states[0] = MAXDISKXFER - xfer;
		states[1] = xfer;
		draw_bar(base+i, states, 2);
		old[i] = sts->dk_xfer[i];
	}
}


/* 
 *  This procedure gets called every interval to compute and display the
 *  bars. It should call draw_bar() with the bar number, the array of
 *  integer values to display in the bar, and the number of values in
 *  the array.
 */
/* ARGSUSED */
void
rstat_display_bars(nbars)
int nbars;
{
	int n=0;
	if(NULL==(sts=rstatproc_stats_3((void *)NULL, cl))){
		clnt_perror(cl, rstathost);
		exit(1);
	}
	if(cpuflag) {
		display_cpu(n);
		n+=ncpu;
	}
	if(diskflag) {
		display_disk(n);
		n+=ndisk;
	}
}

#endif /* RSTAT */


syntax highlighted by Code2HTML, v. 0.9.1