/*
 * C version of the perl version of the Linux version of vmstat.
 *
 * Copyright (c) 1994 lm@engr.sgi.com.  Distributed under the GPL.
 *
 * $Id: vmstat.c,v 1.1 1995/02/23 19:25:38 lm Exp $
 */

#include	<stdio.h>

int	steady = 1;

main(int ac, char **av)
{
	int	iter = 0;
	int	slp;

	if (ac == 2 && !strcmp(av[1], "--help")) {
usage:		fprintf(stderr, "usage: %s [interval]\n", av[0]);
		exit(0);
	}
	if (ac == 2) {
		slp = atoi(av[1]);
	} else if (ac != 1) {
		goto usage;
	} else {
		slp = 5;
	}

	data(0);

	for ( ;; ) {
		sleep(steady);

		if (iter++ % 20 == 0) {
			header();
		}

		data(1);

		steady = slp;
	}
	/* NOTREACHED */
}

inline header()
{
	printf("load free cache swap pgin pgou dk0 dk1 dk2 dk3 ipkt opkt int   ctx   usr sys idl\n");
}

#define	uint	unsigned int

struct stats {
	uint	user, sys;
	uint	dk[4];
	uint	intr;
	uint	pgin, pgou;
	uint	ctx;
	uint	ipkt, opkt;
	uint	free, swap, buffers;
	char	load[7];
} old, new;

data(int delta)
{
	FILE	*stream;
	char	buf[256];
	uint	a, b, c, d, e, f, g, h, i;

	if (!(stream = fopen("/proc/stat", "r"))) {
		exit(1);
	}
	while (fgets(buf, sizeof(buf), stream)) {
		if (!strncmp("cpu ", buf, 4)) {
			sscanf(buf, "cpu %d %d %d", &a, &b, &new.sys);
			new.user = a + b;
		}
		if (!strncmp("disk ", buf, 5)) {
			sscanf(buf, "disk %d %d %d %d", 
			    &new.dk[0], &new.dk[1], &new.dk[2], &new.dk[3]);
		}
		if (!strncmp("intr ", buf, 5)) {
			sscanf(buf, "intr %d", &new.intr);
		}
		if (!strncmp("page ", buf, 5)) {
			sscanf(buf, "page %d %d", &new.pgin, &new.pgou);
		}
		if (!strncmp("ctxt ", buf, 5)) {
			sscanf(buf, "ctxt %d", &new.ctx);
		}
	}
	fclose(stream);

	if (!(stream = fopen("/proc/net/dev", "r"))) {
		exit(1);
	}
	fgets(buf, sizeof(buf), stream);	/* first header */
	fgets(buf, sizeof(buf), stream);	/* second header */
	new.ipkt = new.opkt = 0;
	while (fgets(buf, sizeof(buf), stream)) {
		/* XXX - includes loopback */
		sscanf(&buf[7], "%d %d %d %d %d %d", &a, &b, &c, &d, &e, &f);
		new.ipkt += a;
		new.opkt += f;
	}
	fclose(stream);

	if (!(stream = fopen("/proc/meminfo", "r"))) {
		exit(1);
	}
	while (fgets(buf, sizeof(buf), stream)) {
		if (!strncmp("Mem:", buf, 4)) {
			sscanf(buf, "Mem: %d %d %d %d %d", &a, &b, &c, &d, &e);
			new.free = c;
			new.buffers = e;
		}
		if (!strncmp("Swap:", buf, 5)) {
			sscanf(buf, "Swap: %d %d", &a, &new.swap);
		}
	}
	fclose(stream);

	if (!(stream = fopen("/proc/loadavg", "r"))) {
		exit(1);
	}
	fgets(buf, sizeof(buf), stream);
	sscanf(buf, "%s ", new.load);
	fclose(stream);

	if (!delta) {
		old = new;
		return;
	}

#define	avg(field)	(new.field - old.field) / steady

	/*
	 * Note - because this can be off a little, I calculate idle as !busy.
	 * I also back things down until they equal 100.
	 *
	 * Also, I don't include clock interrupts (100/sec).
	 */
	a = avg(user);
	b = avg(sys);
	while (a + b > 100) {
		a--;
		if (a + b > 100)
			b--;
	}
	c = 100 - (a + b);
	printf("%4s %4.1f %5.1f %4.1f %4d %4d %3d %3d %3d %3d %4d %4d %3d %5d %5d %3d %3d\n",
	    new.load, new.free / (1024.*1024), new.buffers / (1024.*1024),
	    new.swap / (1024.*1024), avg(pgin), avg(pgou), avg(dk[0]),
	    avg(dk[1]), avg(dk[2]), avg(dk[3]), avg(ipkt), avg(opkt),
	    avg(intr) - 100, avg(ctx), a, b, c);

	old = new;
}
