1 /*
2 * Copyright (c) 1980, 1986, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1980, 1986, 1991, 1993\n\
11 The Regents of the University of California. All rights reserved.\n";
12 #endif /* not lint */
13
14 #ifndef lint
15 static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 06/06/93";
16 #endif /* not lint */
17
18 #include <sys/param.h>
19 #include <sys/device.h>
20 #include <sys/disklabel.h>
21 #include <sys/disk.h>
22 #include <sys/time.h>
23 #include <sys/dkstat.h>
24 #include <sys/ioctl.h>
25 #include <vm/vm.h>
26
27 #include <ctype.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <kvm.h>
31 #include <limits.h>
32 #include <nlist.h>
33 #include <paths.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <time.h>
38 #include <unistd.h>
39
40 #include "extern.h"
41 #include "getdev.h"
42
43 struct nlist nl[] = {
44 { "_alldevs" },
45 #define X_ALLDEVS 0
46 { "_boottime" },
47 #define X_BOOTTIME 1
48 0
49 };
50
51 struct dkinfo *dkinfo, **nextdk = &dkinfo;
52 int ndrives;
53 kvm_t *kd;
54
55 void dkadd __P((u_long, struct device *));
56 char **dkselect __P((char **));
57 void getdisks __P((u_long));
58 int isdk __P((struct device *));
59
60 #define INTRSTAT 0x01
61 #define MEMSTAT 0x02
62 #define SUMSTAT 0x04
63 #define VMSTAT 0x08
64
65 int
main(argc,argv)66 main(argc, argv)
67 register int argc;
68 register char **argv;
69 {
70 extern int optind;
71 extern char *optarg;
72 register int c, todo;
73 u_int interval;
74 int reps;
75 char *memf, *nlistf;
76 char errbuf[_POSIX2_LINE_MAX];
77
78 memf = nlistf = NULL;
79 interval = reps = todo = 0;
80 while ((c = getopt(argc, argv, "c:iM:mN:sw:")) != EOF) {
81 switch (c) {
82 case 'c':
83 reps = atoi(optarg);
84 break;
85 case 'i':
86 todo |= INTRSTAT;
87 break;
88 case 'M':
89 memf = optarg;
90 break;
91 case 'm':
92 todo |= MEMSTAT;
93 break;
94 case 'N':
95 nlistf = optarg;
96 break;
97 case 's':
98 todo |= SUMSTAT;
99 break;
100 case 'w':
101 interval = atoi(optarg);
102 break;
103 case '?':
104 default:
105 errexit("usage: vmstat [-ims] [-c count] [-M core] \
106 [-N system] [-w wait] [disks]\n");
107 /* NOTREACHED */
108 }
109 }
110 argc -= optind;
111 argv += optind;
112
113 if (todo == 0)
114 todo = VMSTAT;
115
116 /*
117 * Discard setgid privileges if not the running kernel so that bad
118 * guys can't print interesting stuff from kernel memory.
119 */
120 if (nlistf != NULL || memf != NULL)
121 setgid(getgid());
122
123 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
124 if (kd == 0) {
125 (void)fprintf(stderr,
126 "vmstat: kvm_openfiles: %s\n", errbuf);
127 exit(1);
128 }
129
130 if ((c = kvm_nlist(kd, nl)) != 0) {
131 if (c > 0) {
132 (void)fprintf(stderr,
133 "vmstat: undefined symbols: ");
134 for (c = 0; c < sizeof(nl)/sizeof(nl[0]) - 1; c++)
135 if (nl[c].n_type == 0)
136 printf(" %s", nl[c].n_name);
137 (void)fputc('\n', stderr);
138 } else
139 (void)fprintf(stderr, "vmstat: kvm_nlist: %s\n",
140 kvm_geterr(kd));
141 exit(1);
142 }
143
144 if (todo & VMSTAT) {
145 getdev(nl[X_ALLDEVS].n_value, isdk, dkadd);
146 argv = dkselect(argv);
147 }
148
149 #define BACKWARD_COMPATIBILITY
150 #ifdef BACKWARD_COMPATIBILITY
151 if (*argv) {
152 interval = atoi(*argv);
153 if (*++argv)
154 reps = atoi(*argv);
155 }
156 #endif
157
158 if (interval) {
159 if (!reps)
160 reps = -1;
161 } else if (reps)
162 interval = 1;
163
164 if (todo & MEMSTAT)
165 domem();
166 if (todo & SUMSTAT)
167 dosum();
168 if (todo & INTRSTAT)
169 dointr();
170 if (todo & VMSTAT)
171 dovmstat(interval, reps);
172 exit(0);
173 }
174
175 int
isdk(dv)176 isdk(dv)
177 struct device *dv;
178 {
179
180 return (dv->dv_class == DV_DISK);
181 }
182
183 void
dkadd(addr,dv)184 dkadd(addr, dv)
185 u_long addr;
186 struct device *dv;
187 {
188 register struct dkinfo *dk;
189 register char *name;
190
191 name = dv->dv_xname;
192 dk = malloc(sizeof *dk);
193 if (dk == NULL || (dk->dk_name = strdup(name)) == NULL)
194 errexit("dkadd(%s): malloc: %s\n", name, strerror(errno));
195 *nextdk = dk;
196 nextdk = &dk->dk_next;
197 dk->dk_next = NULL;
198 dk->dk_sel = 0;
199 dk->dk_addr = addr;
200 dk->dk_2c[0] = name[0];
201 dk->dk_2c[1] = name[strlen(name) - 1];
202 dk->dk_2c[2] = 0;
203 #ifdef notyet
204 /*
205 * Fill in dk_oxfer so that we can compute deltas next time.
206 */
207 (void)snprintf(buf, sizeof buf, "%s xfer", name);
208 kread(addr + offsetof(struct dkdevice, dk_xfer),
209 &dk->dk_oxfer, sizeof dk->dk_oxfer, buf);
210 #endif
211 }
212
213 /*
214 * Choose drives to be displayed. Priority goes to (in order) drives
215 * supplied as arguments, default drives. If everything isn't filled
216 * in and there are drives not taken care of, display the first few
217 * that fit.
218 */
219 char **
dkselect(argv)220 dkselect(argv)
221 char **argv;
222 {
223 register struct dkinfo *dk;
224 register char **cpp, *cp;
225 extern char *defdrives[];
226 #define BACKWARD_COMPATIBILITY
227
228 for (; (cp = *argv) != NULL; ++argv) {
229 #ifdef BACKWARD_COMPATIBILITY
230 if (isdigit(*cp))
231 break;
232 #endif
233 for (dk = dkinfo; dk != NULL; dk = dk->dk_next) {
234 if (strcmp(dk->dk_name, cp) != 0)
235 continue;
236 if (!dk->dk_sel) {
237 dk->dk_sel = 1;
238 ++ndrives;
239 }
240 break;
241 }
242 }
243 for (dk = dkinfo; dk != NULL && ndrives < 4; dk = dk->dk_next) {
244 if (dk->dk_sel)
245 continue;
246 for (cpp = defdrives; (cp = *cpp) != NULL; cpp++)
247 if (strcmp(dk->dk_name, cp) == 0) {
248 dk->dk_sel = 1;
249 ++ndrives;
250 break;
251 }
252 }
253 for (dk = dkinfo; dk != NULL && ndrives < 4; dk = dk->dk_next) {
254 if (dk->dk_sel)
255 continue;
256 dk->dk_sel = 1;
257 ++ndrives;
258 }
259 return (argv);
260 }
261
262 long
getuptime()263 getuptime()
264 {
265 static time_t boottime;
266 time_t now, uptime;
267
268 if (boottime == 0)
269 kread(nl[X_BOOTTIME].n_value, &boottime, sizeof boottime,
270 "boottime");
271 (void)time(&now);
272 uptime = now - boottime;
273 if (uptime <= 0 || uptime > 60*60*24*365*10) {
274 (void)fprintf(stderr,
275 "vmstat: time makes no sense; namelist must be wrong.\n");
276 exit(1);
277 }
278 return (uptime);
279 }
280