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 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 176 isdk(dv) 177 struct device *dv; 178 { 179 180 return (dv->dv_class == DV_DISK); 181 } 182 183 void 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 ** 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 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