160194Storek /*
2*62431Sbostic * Copyright (c) 1980, 1986, 1991, 1993
3*62431Sbostic * The Regents of the University of California. All rights reserved.
460194Storek *
560194Storek * %sccs.include.redist.c%
660194Storek */
760194Storek
860194Storek #ifndef lint
9*62431Sbostic static char copyright[] =
10*62431Sbostic "@(#) Copyright (c) 1980, 1986, 1991, 1993\n\
11*62431Sbostic The Regents of the University of California. All rights reserved.\n";
1260194Storek #endif /* not lint */
1360194Storek
1460194Storek #ifndef lint
15*62431Sbostic static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 06/06/93";
1660194Storek #endif /* not lint */
1760194Storek
1860194Storek #include <sys/param.h>
1960194Storek #include <sys/device.h>
2060194Storek #include <sys/disklabel.h>
2160194Storek #include <sys/disk.h>
2260194Storek #include <sys/time.h>
2360194Storek #include <sys/dkstat.h>
2460194Storek #include <sys/ioctl.h>
2560194Storek #include <vm/vm.h>
2660194Storek
2760194Storek #include <ctype.h>
2860194Storek #include <errno.h>
2960194Storek #include <fcntl.h>
3060194Storek #include <kvm.h>
3160194Storek #include <limits.h>
3260194Storek #include <nlist.h>
3360194Storek #include <paths.h>
3460194Storek #include <stdio.h>
3560194Storek #include <stdlib.h>
3660194Storek #include <string.h>
3760194Storek #include <time.h>
3860194Storek #include <unistd.h>
3960194Storek
4060194Storek #include "extern.h"
4160194Storek #include "getdev.h"
4260194Storek
4360194Storek struct nlist nl[] = {
4460194Storek { "_alldevs" },
4560194Storek #define X_ALLDEVS 0
4660194Storek { "_boottime" },
4760194Storek #define X_BOOTTIME 1
4860194Storek 0
4960194Storek };
5060194Storek
5160194Storek struct dkinfo *dkinfo, **nextdk = &dkinfo;
5260194Storek int ndrives;
5360194Storek kvm_t *kd;
5460194Storek
5560194Storek void dkadd __P((u_long, struct device *));
5660194Storek char **dkselect __P((char **));
5760194Storek void getdisks __P((u_long));
5860194Storek int isdk __P((struct device *));
5960194Storek
6060194Storek #define INTRSTAT 0x01
6160194Storek #define MEMSTAT 0x02
6260194Storek #define SUMSTAT 0x04
6360194Storek #define VMSTAT 0x08
6460194Storek
6560194Storek int
main(argc,argv)6660194Storek main(argc, argv)
6760194Storek register int argc;
6860194Storek register char **argv;
6960194Storek {
7060194Storek extern int optind;
7160194Storek extern char *optarg;
7260194Storek register int c, todo;
7360194Storek u_int interval;
7460194Storek int reps;
7560194Storek char *memf, *nlistf;
7660194Storek char errbuf[_POSIX2_LINE_MAX];
7760194Storek
7860194Storek memf = nlistf = NULL;
7960194Storek interval = reps = todo = 0;
8060194Storek while ((c = getopt(argc, argv, "c:iM:mN:sw:")) != EOF) {
8160194Storek switch (c) {
8260194Storek case 'c':
8360194Storek reps = atoi(optarg);
8460194Storek break;
8560194Storek case 'i':
8660194Storek todo |= INTRSTAT;
8760194Storek break;
8860194Storek case 'M':
8960194Storek memf = optarg;
9060194Storek break;
9160194Storek case 'm':
9260194Storek todo |= MEMSTAT;
9360194Storek break;
9460194Storek case 'N':
9560194Storek nlistf = optarg;
9660194Storek break;
9760194Storek case 's':
9860194Storek todo |= SUMSTAT;
9960194Storek break;
10060194Storek case 'w':
10160194Storek interval = atoi(optarg);
10260194Storek break;
10360194Storek case '?':
10460194Storek default:
10560194Storek errexit("usage: vmstat [-ims] [-c count] [-M core] \
10660194Storek [-N system] [-w wait] [disks]\n");
10760194Storek /* NOTREACHED */
10860194Storek }
10960194Storek }
11060194Storek argc -= optind;
11160194Storek argv += optind;
11260194Storek
11360194Storek if (todo == 0)
11460194Storek todo = VMSTAT;
11560194Storek
11660194Storek /*
11760194Storek * Discard setgid privileges if not the running kernel so that bad
11860194Storek * guys can't print interesting stuff from kernel memory.
11960194Storek */
12060194Storek if (nlistf != NULL || memf != NULL)
12160194Storek setgid(getgid());
12260194Storek
12360194Storek kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
12460194Storek if (kd == 0) {
12560194Storek (void)fprintf(stderr,
12660194Storek "vmstat: kvm_openfiles: %s\n", errbuf);
12760194Storek exit(1);
12860194Storek }
12960194Storek
13060194Storek if ((c = kvm_nlist(kd, nl)) != 0) {
13160194Storek if (c > 0) {
13260194Storek (void)fprintf(stderr,
13360194Storek "vmstat: undefined symbols: ");
13460194Storek for (c = 0; c < sizeof(nl)/sizeof(nl[0]) - 1; c++)
13560194Storek if (nl[c].n_type == 0)
13660194Storek printf(" %s", nl[c].n_name);
13760194Storek (void)fputc('\n', stderr);
13860194Storek } else
13960194Storek (void)fprintf(stderr, "vmstat: kvm_nlist: %s\n",
14060194Storek kvm_geterr(kd));
14160194Storek exit(1);
14260194Storek }
14360194Storek
14460194Storek if (todo & VMSTAT) {
14560194Storek getdev(nl[X_ALLDEVS].n_value, isdk, dkadd);
14660194Storek argv = dkselect(argv);
14760194Storek }
14860194Storek
14960194Storek #define BACKWARD_COMPATIBILITY
15060194Storek #ifdef BACKWARD_COMPATIBILITY
15160194Storek if (*argv) {
15260194Storek interval = atoi(*argv);
15360194Storek if (*++argv)
15460194Storek reps = atoi(*argv);
15560194Storek }
15660194Storek #endif
15760194Storek
15860194Storek if (interval) {
15960194Storek if (!reps)
16060194Storek reps = -1;
16160194Storek } else if (reps)
16260194Storek interval = 1;
16360194Storek
16460194Storek if (todo & MEMSTAT)
16560194Storek domem();
16660194Storek if (todo & SUMSTAT)
16760194Storek dosum();
16860194Storek if (todo & INTRSTAT)
16960194Storek dointr();
17060194Storek if (todo & VMSTAT)
17160194Storek dovmstat(interval, reps);
17260194Storek exit(0);
17360194Storek }
17460194Storek
17560194Storek int
isdk(dv)17660194Storek isdk(dv)
17760194Storek struct device *dv;
17860194Storek {
17960194Storek
18060194Storek return (dv->dv_class == DV_DISK);
18160194Storek }
18260194Storek
18360194Storek void
dkadd(addr,dv)18460194Storek dkadd(addr, dv)
18560194Storek u_long addr;
18660194Storek struct device *dv;
18760194Storek {
18860194Storek register struct dkinfo *dk;
18960194Storek register char *name;
19060194Storek
19160194Storek name = dv->dv_xname;
19260194Storek dk = malloc(sizeof *dk);
19360194Storek if (dk == NULL || (dk->dk_name = strdup(name)) == NULL)
19460194Storek errexit("dkadd(%s): malloc: %s\n", name, strerror(errno));
19560194Storek *nextdk = dk;
19660194Storek nextdk = &dk->dk_next;
19760194Storek dk->dk_next = NULL;
19860194Storek dk->dk_sel = 0;
19960194Storek dk->dk_addr = addr;
20060194Storek dk->dk_2c[0] = name[0];
20160194Storek dk->dk_2c[1] = name[strlen(name) - 1];
20260194Storek dk->dk_2c[2] = 0;
20360194Storek #ifdef notyet
20460194Storek /*
20560194Storek * Fill in dk_oxfer so that we can compute deltas next time.
20660194Storek */
20760194Storek (void)snprintf(buf, sizeof buf, "%s xfer", name);
20860194Storek kread(addr + offsetof(struct dkdevice, dk_xfer),
20960194Storek &dk->dk_oxfer, sizeof dk->dk_oxfer, buf);
21060194Storek #endif
21160194Storek }
21260194Storek
21360194Storek /*
21460194Storek * Choose drives to be displayed. Priority goes to (in order) drives
21560194Storek * supplied as arguments, default drives. If everything isn't filled
21660194Storek * in and there are drives not taken care of, display the first few
21760194Storek * that fit.
21860194Storek */
21960194Storek char **
dkselect(argv)22060194Storek dkselect(argv)
22160194Storek char **argv;
22260194Storek {
22360194Storek register struct dkinfo *dk;
22460194Storek register char **cpp, *cp;
22560194Storek extern char *defdrives[];
22660194Storek #define BACKWARD_COMPATIBILITY
22760194Storek
22860194Storek for (; (cp = *argv) != NULL; ++argv) {
22960194Storek #ifdef BACKWARD_COMPATIBILITY
23060194Storek if (isdigit(*cp))
23160194Storek break;
23260194Storek #endif
23360194Storek for (dk = dkinfo; dk != NULL; dk = dk->dk_next) {
23460194Storek if (strcmp(dk->dk_name, cp) != 0)
23560194Storek continue;
23660194Storek if (!dk->dk_sel) {
23760194Storek dk->dk_sel = 1;
23860194Storek ++ndrives;
23960194Storek }
24060194Storek break;
24160194Storek }
24260194Storek }
24360194Storek for (dk = dkinfo; dk != NULL && ndrives < 4; dk = dk->dk_next) {
24460194Storek if (dk->dk_sel)
24560194Storek continue;
24660194Storek for (cpp = defdrives; (cp = *cpp) != NULL; cpp++)
24760194Storek if (strcmp(dk->dk_name, cp) == 0) {
24860194Storek dk->dk_sel = 1;
24960194Storek ++ndrives;
25060194Storek break;
25160194Storek }
25260194Storek }
25360194Storek for (dk = dkinfo; dk != NULL && ndrives < 4; dk = dk->dk_next) {
25460194Storek if (dk->dk_sel)
25560194Storek continue;
25660194Storek dk->dk_sel = 1;
25760194Storek ++ndrives;
25860194Storek }
25960194Storek return (argv);
26060194Storek }
26160194Storek
26260194Storek long
getuptime()26360194Storek getuptime()
26460194Storek {
26560194Storek static time_t boottime;
26660194Storek time_t now, uptime;
26760194Storek
26860194Storek if (boottime == 0)
26960194Storek kread(nl[X_BOOTTIME].n_value, &boottime, sizeof boottime,
27060194Storek "boottime");
27160194Storek (void)time(&now);
27260194Storek uptime = now - boottime;
27360194Storek if (uptime <= 0 || uptime > 60*60*24*365*10) {
27460194Storek (void)fprintf(stderr,
27560194Storek "vmstat: time makes no sense; namelist must be wrong.\n");
27660194Storek exit(1);
27760194Storek }
27860194Storek return (uptime);
27960194Storek }
280