[comp.soft-sys.andrew] new HP getstats and anon ftp

burdick@hpindda.HP.COM (Matt Burdick) (12/02/89)

I would like to ftp a new copy of the Andrew source from
emsworth.andrew.cmu.edu, but keep getting a 'permission denied' message.
Here are some of the messages when I take a look at the directory:

ftp> dir
200 PORT command successful.
150 Opening data connection for /bin/ls (15.255.208.3,11945) (0 bytes).
[Can't determine primary cell, using workstation cell]
[Can't determine workstation cell, using 'andrew.cmu.edu']
Total: 66 kbytes
-rwx        1 80                   0              185 Oct 18 13:13 AndrewSetup
-rw-        1 469                  0              665 Nov 22 15:56 README
-r--        1 38                   0            55702 Nov 22 17:04 andrew.README

l           1 469                  0               16 Nov 27 21:55 andrew.tar.Z
-> sub/andrew.tar.Z
d           2 1342                 0             2048 Sep 20 17:10 bin
d           2 38                   0             2048 Nov 28 13:18 bugs
d           2 1342                 0             2048 Nov 15 08:56 patches
d           2 1342                 0             2048 Oct 23 09:07 util
alpha-patches: Permission denied
sub: Permission denied
andrew: Permission denied
226 Transfer complete.
755 bytes received in 1.11 seconds (0.66 Kbytes/sec)



Could someone fix the permissions on these?   Also, here is a new version
of the atk/console/stats/hp300/getstats.c file.  I am including the entire
thing, since I changed quite a lot:


#---------------------------------- cut here ----------------------------------
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Matt Burdick <burdick@hpindlw> on Fri Dec  1 16:20:17 1989
#
# This archive contains:
#	getstats.c	
#
# Error checking via wc(1) will be performed.
# Error checking via sum(1) will be performed.

LANG=""; export LANG
PATH=/bin:/usr/bin:$PATH; export PATH

if sum -r </dev/null >/dev/null 2>&1
then
	sumopt='-r'
else
	sumopt=''
fi

echo x - getstats.c
cat >getstats.c <<'@EOF'
/* ********************************************************************** *\
 *         Copyright IBM Corporation 1988,1989 - All Rights Reserved      *
 *        For full copyright information see:'andrew/config/COPYRITE'     *
\* ********************************************************************** */
/* $Header: /afs/.andrew.cmu.edu/itc/src/andrew/atk/console/stats/hp300/RCS/getstats.c,v 1.4 89/10/18 12:26:09 cfe Exp $ */
/* $Source: /afs/.andrew.cmu.edu/itc/src/andrew/atk/console/stats/hp300/RCS/getstats.c,v $ */

#ifndef lint
static char *getstats_c_id = "$Header: /afs/.andrew.cmu.edu/itc/src/andrew/atk/console/stats/hp300/RCS/getstats.c,v 1.4 89/10/18 12:26:09 cfe Exp $";
#endif /* lint */

/* **********************************************************************
*   This code is designed to read what might be priveledged (setuid) 
*   information regarding both Disk Statistics (% full) and a host of 
*   stats from /dev/kmem (including but not limited to, CPU, I/O, and VM)
*
*   When retriving the data - this program will print out to stdout
*   a string in the form of either "%d:%d\n" or "%d:%d:%s\n"
*   The latter case is for passing the name of where a disk is mounted
*   back to the parent program.
*
*   The parent program (Console, or any other program which wishes to get
*   at this information) is responsible for setting up a pipe, binding the
*   child's (this program) stdout to one end of a pipe, and parsing the
*   strings which are passed back.
*
*   The basic string format is an ID (int), a colon, a value (int), and
*   optionally another colon followed by a string.  The ID is coded from
*   the included file "getstats.h" - ID values 50 and over represent 
*   ERRORS as documented in the above mentioned inclued file.  When an 
*   ERROR or the optional string is passed, the value (second parameter)
*   can be safely ignored, and is usually set to 0.
*
*   The arguments to be passed to this program are the effective UID from
*   the parent program, a polling frequency (# of seconds) for checking
*   /dev/kmem (usually between 1 and 5, must be > 0), and a polling
*   frequency for checking how full the local disks are (generally higher
*   than the value for /dev/kmem, but could vary greatly).  Thus the call
*   is:
*
*   execvp("getstats", argv)
*
*   with argv as:
*
*   argv[0]="getstats";
*   argv[1]=~ ("%d", UID);
*   argv[2]=~ ("%d", kmempollfrequency);
*   argv[3]=~ ("%d", diskpollfrequency);
*   argv[4]=NULL;
*
********************************************************************** */
#include <sitevars.h>

#include <system.h>

#include <stdio.h>
#include <sys/param.h>
#include <sys/dir.h>
#include <sys/signal.h>
#include <sys/user.h> 
#include <sys/proc.h>
#include <sys/vm.h>
#include <sys/dk.h>
#include <sys/map.h>

#include <sys/buf.h>

#include <netinet/in.h>
#include <errno.h>
#include <sys/stat.h>

#include <sys/socket.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <checklist.h>
#include <mntent.h>
#include <sys/vfs.h>
#include <sys/fs.h>


#undef MAXUPRC

long maxuprc = 0;    /* we have to nlist in HP-UX  */

#define VMMON_DODECL
#include <getstats.h>
extern struct nlist RawStatistics[];


char	root[32];

int TotalTime;
int deficit;
int MemoryFile /* file descriptor for unix memory */ ;
int nproc;
off_t procp;
struct proc proc[8];/* 8 = a few, for fewer syscalls */
struct proc *mproc;
extern char *malloc();


struct{
   long time[CPUSTATES];
   long xfer[DK_NDRIVE];
   struct vmmeter Rate;
   struct vmtotal Total;
   long  dk_xfer[DK_NDRIVE];
}s, s1;

union {
    struct fs iu_fs;
    char dummy[SBSIZE];
} sb;

#define sendval(text) {printf text ;fflush(stdout);}




GetGVMStats(UsersID)
int UsersID;
{
    register int   i;
    long  t;
    struct mapent *sp;
    int myval = 0;

    lseek(MemoryFile,(long) RawStatistics[X_CPTIME].n_value, 0);
    read(MemoryFile, s.time, sizeof(s.time));

    lseek(MemoryFile,(long) RawStatistics[X_DKXFER].n_value, 0);
    read(MemoryFile, s.dk_xfer, sizeof(s.dk_xfer));

    lseek(MemoryFile,(long) RawStatistics[X_RATE].n_value, 0);
    read(MemoryFile, &s.Rate, sizeof(s.Rate));

    lseek(MemoryFile,(long) RawStatistics[X_TOTAL].n_value, 0);
    read(MemoryFile, &s.Total, sizeof(s.Total));

    lseek(MemoryFile,(long) RawStatistics[X_DEFICIT].n_value, 0);
    read(MemoryFile, &deficit, sizeof(deficit));
    for (i = 0; i < CPUSTATES; i++) {
	t = s.time[i];
	s.time[i] -= s1.time[i];
	s1.time[i] = t;
    }
    s.time[1] += s.time[0];
    TotalTime = 0;
    for (i = 1; i < CPUSTATES; i++)
	TotalTime += s.time[i];
    if (TotalTime == 0)
	TotalTime = 1;
    sendval(("%d:%d\n", LOADCPU, (s.time[1] + s.time[2]) * 100 / TotalTime));
    for (i = 1; i < DK_NDRIVE - 1; i++)
	s.dk_xfer[0] += s.dk_xfer[i];
    if (s1.dk_xfer[0] == 0){
	s1.dk_xfer[0] = s.dk_xfer[0];
    }
    myval = s.dk_xfer[0] - s1.dk_xfer[0];
    if (myval > 100) myval = 100;
    sendval(("%d:%d\n", LOADIO, myval));
    s1.dk_xfer[0] = s.dk_xfer[0];
    sendval(("%d:%d\n", LOADUSER, s.time[1] * 100 / TotalTime));
    sendval(("%d:%d\n", LOADSYS, s.time[2] * 100 / TotalTime));
    sendval(("%d:%d\n", LOADIDLE, s.time[3] * 100 / TotalTime));
    sendval(("%d:%d\n", VM, (int)((double)s.Total.t_avm/(double)s.Total.t_vm * 100)));
    sendval(("%d:%d\n", PAGEIN, s.Rate.v_pgpgin / 2));
    sendval(("%d:%d\n", PAGEOUT, s.Rate.v_pgpgout / 2));
    sendval(("%d:%d\n", PAGEREPLACABLE, s.Rate.v_scan));
    sendval(("%d:%d\n", PAGEDEFICIT, deficit));
    sendval(("%d:%d\n", MEMACTIVE, s.Total.t_avm / 2));
    sendval(("%d:%d\n", MEMFREE, s.Total.t_free / 2));
    sendval(("%d:%d\n", QUEUERUN, s.Total.t_rq));
    sendval(("%d:%d\n", QUEUEBLOCK, s.Total.t_dw + s.Total.t_pw));
    sendval(("%d:%d\n", QUEUEMEM, s.Total.t_sw));
    sendval(("%d:%d\n", INTSIO, s.Rate.v_intr));
    sendval(("%d:%d\n", INTSSYS, s.Rate.v_syscall));
    sendval(("%d:%d\n", INTSSWAP, s.Rate.v_swtch));
    if (1) {/* DoPROCESSES */
	int i, j, userprocesses, totalprocesses, otherprocs;
	off_t tmpprocp;

	userprocesses = 0;
	totalprocesses = 1;
	otherprocs = 0;
	tmpprocp = procp;

	for (i = 0; i < nproc; i += 8) {
	    lseek(MemoryFile, (long) tmpprocp, 0);
	    j = nproc - i;
	    if (j > 8)
		j = 8;
	    j *= sizeof(struct proc);
	    if (read(MemoryFile, (char *) proc, j) != j) {
		sendval(("%d:%d\n", GVM_ERR_1, 0));
		exit(-1);
	    }
	    tmpprocp += j;
	    for (j = j / sizeof(struct proc) - 1; j >= 0; j--) {
		mproc = &proc[j];
		if (mproc->p_pid != 0) {
		    totalprocesses++;
		    if (UsersID == mproc->p_uid) {
			userprocesses ++;
		    } else if (mproc->p_uid) {
			otherprocs++;
		    }
		}
	    }
	}
	sendval(("%d:%d\n", PROCSUSER, maxuprc ? (userprocesses * 100) / maxuprc : -1));
	sendval(("%d:%d\n", PROCSTOTAL, nproc ? totalprocesses * 100 / nproc : -1));
	sendval(("%d:%d\n", PROCSOTHER, otherprocs));
    }
}





InitGVMStats()
{
   time_t bootime;
   int code = 0;

   /* 
    set up Unix interface: scan name list for current system
    addresses and then open a file which is the memory image
    of the system.
    */
   code = nlist(_SITE_VMUNIX, RawStatistics);
   if (code == -1){
       sendval(("%d:%d\n", GVM_ERR_2, 0));
       exit(-1);
   }
   else{
       if (RawStatistics[0].n_type == 0){
	   sendval(("%d:%d\n", GVM_ERR_3, 0));
	   exit(-1);
       }
   }
   MemoryFile = open(_SITE_DEV_KMEM, 0);
   if (MemoryFile < 0){
       sendval(("%d:%d\n", GVM_ERR_4, 0));
       exit(-1);
   }
   lseek(MemoryFile,(long) RawStatistics[X_BOOTIME].n_value, 0);
   read(MemoryFile, &bootime, sizeof(bootime));

   lseek(MemoryFile, (long) RawStatistics[X_PROC].n_value, 0);
   read(MemoryFile,(char *) &procp, sizeof(procp));

   lseek(MemoryFile, (long) RawStatistics[X_NPROC].n_value, 0);
   read(MemoryFile,(char *) &nproc, sizeof(nproc));

#ifndef MAXUPRC
    lseek(MemoryFile, (long) RawStatistics[X_MAXUPRC].n_value, 0);
    read(MemoryFile,(char *) &maxuprc, sizeof(maxuprc));
#endif /* MAXUPRC */
}


/* the DeviceTable keeps a list of all the devices (and their mounted directory file name) that we should watch */

extern int getmnt();

GetDiskStats(Init)
int Init;
{
    int i = 0;
    struct stat statb;
    char tmpname[1024];
    register FILE *mtabp;
    register struct mntent *mnt;

    sync();
    if ((mtabp = setmntent(MNT_MNTTAB, "r")) == NULL) {
	sendval(("%d:%d\n", DISK_ERR_1, 0));
	exit(1);
    }
    i = DISK1 - 1; /* figuratively 0 */
    while ((mnt = getmntent(mtabp)) != NULL) {
	i++;
	if (strcmp(mnt->mnt_type, MNTTYPE_IGNORE) == 0 ||
	    strcmp(mnt->mnt_type, MNTTYPE_SWAP) == 0)
	    continue;
	if (strcmp(mnt->mnt_type, MNTTYPE_HFS) == 0 &&
	    (stat(mnt->mnt_fsname, &statb) >= 0) &&
	    (((statb.st_mode & S_IFMT) == S_IFBLK) ||
	     ((statb.st_mode & S_IFMT) == S_IFCHR))) {
	    (void) strcpy(tmpname, mnt->mnt_fsname);
	    dfree1(i, tmpname, 0, Init);
	} else {
	    dfree2(i, mnt->mnt_dir, mnt, Init);
	}
    }
    (void) endmntent(mtabp);
}

int bread(fi, bno, buf, cnt)
int fi;
daddr_t bno;
char *buf;
int cnt;
{
    extern int errno;

    (void) lseek(fi, (long)(bno * DEV_BSIZE), 0);
    if (read(fi, buf, (unsigned) cnt) < 0)
	{
	    /* probably a dismounted disk if errno == EIO */
	    if (errno != EIO) { 
		sendval(("%d:%d\n", DISK_ERR_5, 0));
	    }
	    return (0);
	}
    return (1);
}

/*
 * Given a name like /dev/rrp0h, returns the mounted path, like /usr.
 */
char *mpath(file)
char *file;
{
    FILE *mntp;
    register struct mntent *mnt;


    if ((mntp = setmntent(MNT_MNTTAB, "r")) == 0) {
	sendval(("%d:%d\n", DISK_ERR_1, 0));
	exit(1);
    }
    while ((mnt = getmntent(mntp)) != 0) {
	if (strcmp(file, mnt->mnt_fsname) == 0) {
	    (void) endmntent(mntp);
	    return (mnt->mnt_dir);
	}
    }
    (void) endmntent(mntp);
    return "";
}

int round(num)
double num;
{
    int inum = (int) num;
    return(((num - inum) >= 0.5) ? (inum + 1) : inum);
}

dfree1(id, file, infsent, Init)
int id;
char *file;
int infsent;
int Init;
{
    long totalblks, availblks, free, used;
    int fi;
    struct stat stbuf;
    struct checklist *fsp;

    if (stat(file, &stbuf) == 0 &&
	 (stbuf.st_mode&S_IFMT) != S_IFCHR &&
	 (stbuf.st_mode&S_IFMT) != S_IFBLK) {
	if (infsent) { 
	    sendval(("%d:%d\n", DISK_ERR_3, 0));
	    return;
	}
	setfsent();
	while (fsp = getfsent()) {
	    struct stat stb;

	    if (stat(fsp->fs_spec, &stb) == 0 &&
		stb.st_rdev == stbuf.st_dev) {
		file = fsp->fs_spec;
		endfsent();
		goto found;
	    }
	}
	endfsent();
	sendval(("%d:%d\n", DISK_ERR_4, 0));
	return;
    }
    found:
      fi = open(file, 0);
    if (fi < 0){
	return;
    }
    if (bread(fi, SBLOCK, (char *)&sb.iu_fs, SBSIZE) == 0) {
	(void) close(fi);
	return;
    }
    totalblks = sb.iu_fs.fs_dsize;
    free = sb.iu_fs.fs_cstotal.cs_nbfree * sb.iu_fs.fs_frag +
      sb.iu_fs.fs_cstotal.cs_nffree;
    used = totalblks - free;
    availblks = totalblks * (100 - sb.iu_fs.fs_minfree) / 100;
    if(Init){
	sendval(("%d:%d:%s\n", id, 0, mpath(file)));
    }
    else{
	sendval(("%d:%d\n", id, availblks == 0 ? 0 : round((double) used / (double) availblks * 100.0)));
    }
    (void) close(fi);
}


dfree2(id, file, mnt, Init)
int id;
char *file;
struct mntent *mnt;
int Init;
{
    struct statfs fs;
    long totalblks, avail, free, used, reserved;

    if (statfs(file, &fs) < 0) {
	return;
    }
    totalblks = fs.f_blocks;
    free = fs.f_bfree;
    used = totalblks - free;
    avail = fs.f_bavail;
    reserved = free - avail;
    if (avail < 0)
	avail = 0;
    totalblks -= reserved;
    if(Init){
	sendval(("%d:%d:%s\n",id, 0, mnt->mnt_dir));
    }
    else{
	sendval(("%d:%d\n", id, round((double) used / (double) totalblks * 100.0)));
    }
}
@EOF
set `sum $sumopt <getstats.c`; if test $1 -ne 17015
then
	echo ERROR: getstats.c checksum is $1 should be 17015
fi
set `wc -lwc <getstats.c`
if test $1$2$3 != 434145011654
then
	echo ERROR: wc results of getstats.c are $* should be 434 1450 11654
fi

chmod 644 getstats.c

exit 0

mss+@ANDREW.CMU.EDU (Mark Sherman) (12/03/89)

The previous materials on emsworth.andrew.cmu.edu were for beta testing
(as advertised). The beta test period is over, since the release had to
go to MIT at Thanksgiving in order to go on the X.V11R4 tape (as per MIT's
announced schedule). Our "lastest" sources would be the result of "patch 8"
which we never explicitly cr eated or distributed. These sources went to MIT. We then sent people to Cambridge to do last minute testing against the actual R4
servers (nearly all beta testing was against R3 servers). These people have
been making various tweaks and fixes so that the release on the tape
should build and work easily. But, the consequences of this procedure include
that we do not have a real copy of the released code, since by definition
it is still in Cambridge. Therefore, we have tried to limit access to our
(now outdated) beta sources; they will be replaced with the released sources
when we get them back and integrate the changes into our mainstream
source control system. And as promised, we will let people know when
everything is ready and when they can come and get it.
          -Mark
(By the way, we are starting to put together the final hard copy documentation
and lay in a supply of Borenstein's book on Andrew development. It would
help us if we knew how much interest there was in these materials -- a note
to me, mss@andrew.cmu.edu, would be fine; don't bother the entire group.)