This is dialmond.c in view mode; [Download] [Up]
/*
** Copyright (c) 1991 Bolt Beranek and Newman, Inc.
** All rights reserved.
**
** Redistribution and use in source and binary forms are permitted
** provided that: (1) source distributions retain this entire copyright
** notice and comment, and (2) distributions including binaries display
** the following acknowledgement: ``This product includes software
** developed by Bolt Beranek and Newman, Inc. and CREN/CSNET'' in the
** documentation or other materials provided with the distribution and in
** all advertising materials mentioning features or use of this software.
** Neither the name of Bolt Beranek and Newman nor CREN/CSNET may be used
** to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
** WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <stdio.h>
#include <nlist.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#ifdef sun
#include <sys/param.h>
#endif /* sun */
#include <sys/dk.h>
#include <net/if.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <net/if_du.h>
#include "dialupip.h"
#include "dialmon.h"
#define INTERVAL 5 /* Seconds between samples */
#define VMUNIX "/vmunix"
#define KMEM "/dev/kmem"
/* wish list for kernel symbols */
static struct nlist nlst[] = {
{ "_du_softc" },
#define X_DU_SOFTC 0
{ "_globdialstats" },
#define X_GLOBDIALSTATS 1
{ "_cp_time" },
#define X_CP_TIME 2
{ "_avenrun" },
#define X_AVENRUN 3
{ NULL },
};
static int fpkmem; /* descriptor for /dev/kmem */
static FILE *log;
extern char *progname;
extern int errno;
extern int optind;
extern long lseek();
extern unsigned int sleep();
extern void exit();
extern char *strerror();
/*
** Print error message and exit.
*/
static void
fatal(p)
char *p;
{
if (log)
(void)fprintf(log, "%s: %s, %s\n", progname, p, strerror(errno));
exit(1);
}
/*
** Read something from /dev/kmem.
*/
static void
readkernel(i, buff, size)
int i;
char *buff;
int size;
{
char log[80];
if (lseek(fpkmem, (long)nlst[i].n_value, 0) == -1) {
(void)sprintf(log, "Can't lseek to %ld (symbol #%d)",
(long)nlst[i].n_value, i);
fatal(log);
}
if (read(fpkmem, buff, size) < 0)
fatal("Can't read kmem");
}
/*
** Copy some fields from the CYLN structure into the LINESTATUS part.
** Returns the size of the structure.
*/
static void
CopyLineStats(sp, dup)
DIALSTATS *sp;
struct du_softc *dup;
{
int i;
LINESTATS *lsp;
/* Size of Stats structure without the line variables. */
for (lsp = sp->ln, i = 0; i < sp->ndu; lsp++, i++, dup++)
if (dup->ds_if.if_flags & IFF_UP) {
lsp->ln = (char)i;
lsp->cchr = dup->ds_cchr;
lsp->cchs = dup->ds_cchs;
lsp->cpsip = dup->ds_cpsip;
lsp->cprip = dup->ds_cprip;
lsp->flags = dup->ds_flags;
lsp->ctpbusy = dup->ds_ctpbusy;
lsp->ctpidle = dup->ds_ctpidle;
lsp->sesc = dup->ds_sesc;
lsp->resc = dup->ds_resc;
lsp->ierror = dup->ds_if.if_ierrors;
lsp->oerror = dup->ds_if.if_oerrors;
}
else
lsp->ln = (unsigned long)-1;
}
/*
** Convert fields in struct to network order.
*/
static void
ToNetworkOrder(sp)
DIALSTATS *sp;
{
int i;
unsigned long ul;
LINESTATS *lsp;
ul = sp->when;
sp->when = htonl(ul);
for (i = 0; i < 3; i++)
sp->avenrun[i] = htonl(sp->avenrun[i]);
for (i = 0; i < CPUSTATES; i++)
sp->cputime[i] = htonl(sp->cputime[i]);
sp->ipup = htonl(sp->ipup);
sp->ipln = htonl(sp->ipln);
sp->opln = htonl(sp->opln);
sp->opup = htonl(sp->opup);
sp->ndu = htonl(sp->ndu);
for (lsp = sp->ln; lsp < &sp->ln[sp->ndu]; lsp++) {
lsp->cchr = htonl(lsp->cchr);
lsp->cchs = htonl(lsp->cchs);
lsp->cpsip = htonl(lsp->cpsip);
lsp->cprip = htonl(lsp->cprip);
lsp->flags = htonl(lsp->flags);
lsp->ctpbusy = htonl(lsp->ctpbusy);
lsp->ctpidle = htonl(lsp->ctpidle);
lsp->sesc = htonl(lsp->sesc);
lsp->resc = htonl(lsp->resc);
lsp->dest.s_addr = htonl(lsp->dest.s_addr);
lsp->ierror = htonl(lsp->ierror);
lsp->oerror = htonl(lsp->oerror);
lsp->ln = htonl(lsp->ln);
}
}
/*
** Main client routine to print statistics.
*/
static void
sendstats(f)
int f;
{
struct globdialstats gstats;
struct du_softc du_softc[MAX_NDU];
struct timeval tv;
DIALSTATS Stats;
int i;
unsigned long size;
long cpuold[CPUSTATES];
long cpucur[CPUSTATES];
#ifdef sun
int avenrun[3];
#else
double avenrun[3];
#endif /* sun */
if ((fpkmem = open(KMEM, 0)) < 0)
fatal("Can't open kmem");
nlist(VMUNIX, nlst);
if (nlst[0].n_type == 0)
fatal("Can't nlist /vmunix");
for (i = 0; i < CPUSTATES; i++)
cpuold[i] = cpucur[i] = 0;
for ( ; ; ) {
/* Get global status values, copy into the local area. */
readkernel(X_GLOBDIALSTATS, (char *)&gstats, sizeof gstats);
Stats.ipup = gstats.gds_ipup;
Stats.ipln = gstats.gds_ipln;
Stats.opln = gstats.gds_opln;
Stats.opup = gstats.gds_opup;
Stats.ndu = gstats.gds_ndu;
/* get line stat values */
readkernel(X_DU_SOFTC, (char *)du_softc, sizeof du_softc);
CopyLineStats(&Stats, du_softc);
/* Get the load average. */
readkernel(X_AVENRUN, (char *)avenrun, sizeof avenrun);
#ifdef sun
for (i = 0; i < 3; i++)
Stats.avenrun[i] = (unsigned long)(avenrun[i] / (FSCALE / 100));
#else
for (i = 0; i < 3; i++)
Stats.avenrun[i] = (unsigned long)(avenrun[i] * 100);
#endif /* sun */
/* Get amount of CPU time in USER/NICE/SYS/IDLE state. */
readkernel(X_CP_TIME, (char *)cpucur, sizeof cpucur);
for (i = 0; i < CPUSTATES; i++) {
if (cpucur[i] < cpuold[i])
/* Counter wrapped around */
Stats.cputime[i] =
(unsigned long)cpucur[i] - (unsigned long)cpuold[i];
else
Stats.cputime[i] = cpucur[i] - cpuold[i];
cpuold[i] = cpucur[i];
}
/* Get time this structure was made */
if (gettimeofday(&tv, (struct timezone *)NULL) < 0)
fatal("Can't do gettimeofday");
Stats.when = tv.tv_sec;
/* Convert to network order. Write the length, in net order,
* then the buffer. */
ToNetworkOrder(&Stats);
size = sizeof Stats;
size = htonl(size);
(void)write(f, (char *)&size, sizeof size);
size = htonl(size);
i = write(f, (char *)&Stats, (int)size);
if (i < size)
fatal("write");
(void)sleep(INTERVAL);
}
}
static void
usage()
{
(void)fprintf(stderr, "usage: %s\n", progname);
exit(1);
}
main(argc, argv)
int argc;
char *argv[];
{
int i;
/* Set defaults. */
log = NULL;
setprogname(argv[0]);
/* Parse arguments. */
while ((i = getopt(argc, argv, "")) != EOF)
switch (i) {
default:
usage();
/* NOTREACHED */
}
argc -= optind;
argv += optind;
if (argc)
usage();
/* Set the log file. */
if ((log = fopen(DIALMOND_LOG, "a")) == NULL)
log = fopen("/dev/console", "w");
/* All inetd's put the incoming socket on stdin, so... */
sendstats(0);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.