1 /*- 2 * Copyright (c) 1986, 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1986, 1991 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)iostat.c 5.15 (Berkeley) 09/02/92"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/buf.h> 20 #include <sys/dkstat.h> 21 #include <signal.h> 22 #include <fcntl.h> 23 #include <nlist.h> 24 #include <unistd.h> 25 #include <stdio.h> 26 #include <ctype.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <paths.h> 30 #include <kvm.h> 31 #include <limits.h> 32 33 struct nlist nl[] = { 34 #define X_DK_TIME 0 35 { "_dk_time" }, 36 #define X_DK_XFER 1 37 { "_dk_xfer" }, 38 #define X_DK_WDS 2 39 { "_dk_wds" }, 40 #define X_TK_NIN 3 41 { "_tk_nin" }, 42 #define X_TK_NOUT 4 43 { "_tk_nout" }, 44 #define X_DK_SEEK 5 45 { "_dk_seek" }, 46 #define X_CP_TIME 6 47 { "_cp_time" }, 48 #define X_DK_WPMS 7 49 { "_dk_wpms" }, 50 #define X_HZ 8 51 { "_hz" }, 52 #define X_STATHZ 9 53 { "_stathz" }, 54 #define X_DK_NDRIVE 10 55 { "_dk_ndrive" }, 56 #define X_END 10 57 #if defined(hp300) || defined(luna68k) 58 #define X_HPDINIT (X_END+1) 59 { "_hp_dinit" }, 60 #endif 61 #ifdef tahoe 62 #define X_VBDINIT (X_END+1) 63 { "_vbdinit" }, 64 #endif 65 #ifdef vax 66 { "_mbdinit" }, 67 #define X_MBDINIT (X_END+1) 68 { "_ubdinit" }, 69 #define X_UBDINIT (X_END+2) 70 #endif 71 { NULL }, 72 }; 73 74 struct _disk { 75 long cp_time[CPUSTATES]; 76 long *dk_time; 77 long *dk_wds; 78 long *dk_seek; 79 long *dk_xfer; 80 long tk_nin; 81 long tk_nout; 82 } cur, last; 83 84 double etime; 85 long *dk_wpms; 86 int dk_ndrive, *dr_select, hz, kmemfd, ndrives; 87 char **dr_name; 88 89 kvm_t *kd; 90 91 #define nlread(x, v) \ 92 kvm_read(kd, nl[x].n_value, &(v), sizeof(v)) 93 94 #include "names.c" /* XXX */ 95 96 void cpustats __P((void)); 97 void dkstats __P((void)); 98 void err __P((const char *, ...)); 99 void phdr __P((int)); 100 void usage __P((void)); 101 102 main(argc, argv) 103 int argc; 104 char **argv; 105 { 106 register int i; 107 long tmp; 108 int ch, hdrcnt, reps, interval, stathz, ndrives; 109 char **cp, *memf, *nlistf, buf[30]; 110 char errbuf[_POSIX2_LINE_MAX]; 111 112 interval = reps = 0; 113 nlistf = memf = NULL; 114 while ((ch = getopt(argc, argv, "c:M:N:w:")) != EOF) 115 switch(ch) { 116 case 'c': 117 reps = atoi(optarg); 118 break; 119 case 'M': 120 memf = optarg; 121 break; 122 case 'N': 123 nlistf = optarg; 124 break; 125 case 'w': 126 interval = atoi(optarg); 127 break; 128 case '?': 129 default: 130 usage(); 131 } 132 argc -= optind; 133 argv += optind; 134 135 /* 136 * Discard setgid privileges if not the running kernel so that bad 137 * guys can't print interesting stuff from kernel memory. 138 */ 139 if (nlistf != NULL || memf != NULL) 140 setgid(getgid()); 141 142 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 143 if (kd == 0) 144 err("kvm_openfiles: %s", errbuf); 145 if (kvm_nlist(kd, nl) == -1) 146 err("kvm_nlist: %s", kvm_geterr(kd)); 147 if (nl[X_DK_NDRIVE].n_type == 0) 148 err("dk_ndrive not found in namelist"); 149 (void)nlread(X_DK_NDRIVE, dk_ndrive); 150 if (dk_ndrive <= 0) 151 err("invalid dk_ndrive %d\n", dk_ndrive); 152 153 cur.dk_time = calloc(dk_ndrive, sizeof(long)); 154 cur.dk_wds = calloc(dk_ndrive, sizeof(long)); 155 cur.dk_seek = calloc(dk_ndrive, sizeof(long)); 156 cur.dk_xfer = calloc(dk_ndrive, sizeof(long)); 157 last.dk_time = calloc(dk_ndrive, sizeof(long)); 158 last.dk_wds = calloc(dk_ndrive, sizeof(long)); 159 last.dk_seek = calloc(dk_ndrive, sizeof(long)); 160 last.dk_xfer = calloc(dk_ndrive, sizeof(long)); 161 dr_select = calloc(dk_ndrive, sizeof(int)); 162 dr_name = calloc(dk_ndrive, sizeof(char *)); 163 dk_wpms = calloc(dk_ndrive, sizeof(long)); 164 165 for (i = 0; i < dk_ndrive; i++) { 166 (void)sprintf(buf, "dk%d", i); 167 dr_name[i] = strdup(buf); 168 } 169 if (!read_names()) 170 exit(1); 171 (void)nlread(X_HZ, hz); 172 (void)nlread(X_STATHZ, stathz); 173 if (stathz) 174 hz = stathz; 175 (void)kvm_read(kd, nl[X_DK_WPMS].n_value, dk_wpms, 176 dk_ndrive * sizeof(dk_wpms)); 177 178 /* 179 * Choose drives to be displayed. Priority goes to (in order) drives 180 * supplied as arguments and default drives. If everything isn't 181 * filled in and there are drives not taken care of, display the first 182 * few that fit. 183 * 184 * The backward compatibility #ifdefs permit the syntax: 185 * iostat [ drives ] [ interval [ count ] ] 186 */ 187 #define BACKWARD_COMPATIBILITY 188 for (ndrives = 0; *argv; ++argv) { 189 #ifdef BACKWARD_COMPATIBILITY 190 if (isdigit(**argv)) 191 break; 192 #endif 193 for (i = 0; i < dk_ndrive; i++) { 194 if (strcmp(dr_name[i], *argv)) 195 continue; 196 dr_select[i] = 1; 197 ++ndrives; 198 } 199 } 200 #ifdef BACKWARD_COMPATIBILITY 201 if (*argv) { 202 interval = atoi(*argv); 203 if (*++argv) 204 reps = atoi(*argv); 205 } 206 #endif 207 208 if (interval) { 209 if (!reps) 210 reps = -1; 211 } else 212 if (reps) 213 interval = 1; 214 215 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 216 if (dr_select[i] || dk_wpms[i] == 0) 217 continue; 218 for (cp = defdrives; *cp; cp++) 219 if (strcmp(dr_name[i], *cp) == 0) { 220 dr_select[i] = 1; 221 ++ndrives; 222 break; 223 } 224 } 225 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 226 if (dr_select[i]) 227 continue; 228 dr_select[i] = 1; 229 ++ndrives; 230 } 231 232 (void)signal(SIGCONT, phdr); 233 234 for (hdrcnt = 1;;) { 235 if (!--hdrcnt) { 236 phdr(0); 237 hdrcnt = 20; 238 } 239 (void)kvm_read(kd, nl[X_DK_TIME].n_value, 240 cur.dk_time, dk_ndrive * sizeof(long)); 241 (void)kvm_read(kd, nl[X_DK_XFER].n_value, 242 cur.dk_xfer, dk_ndrive * sizeof(long)); 243 (void)kvm_read(kd, nl[X_DK_WDS].n_value, 244 cur.dk_wds, dk_ndrive * sizeof(long)); 245 (void)kvm_read(kd, nl[X_DK_SEEK].n_value, 246 cur.dk_seek, dk_ndrive * sizeof(long)); 247 (void)kvm_read(kd, nl[X_TK_NIN].n_value, 248 &cur.tk_nin, sizeof(cur.tk_nin)); 249 (void)kvm_read(kd, nl[X_TK_NOUT].n_value, 250 &cur.tk_nout, sizeof(cur.tk_nout)); 251 (void)kvm_read(kd, nl[X_CP_TIME].n_value, 252 cur.cp_time, sizeof(cur.cp_time)); 253 for (i = 0; i < dk_ndrive; i++) { 254 if (!dr_select[i]) 255 continue; 256 #define X(fld) tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp 257 X(dk_xfer); 258 X(dk_seek); 259 X(dk_wds); 260 X(dk_time); 261 } 262 tmp = cur.tk_nin; 263 cur.tk_nin -= last.tk_nin; 264 last.tk_nin = tmp; 265 tmp = cur.tk_nout; 266 cur.tk_nout -= last.tk_nout; 267 last.tk_nout = tmp; 268 etime = 0; 269 for (i = 0; i < CPUSTATES; i++) { 270 X(cp_time); 271 etime += cur.cp_time[i]; 272 } 273 if (etime == 0.0) 274 etime = 1.0; 275 etime /= (float)hz; 276 (void)printf("%4.0f%5.0f", 277 cur.tk_nin / etime, cur.tk_nout / etime); 278 dkstats(); 279 cpustats(); 280 (void)printf("\n"); 281 (void)fflush(stdout); 282 283 if (reps >= 0 && --reps <= 0) 284 break; 285 (void)sleep(interval); 286 } 287 exit(0); 288 } 289 290 /* ARGUSED */ 291 void 292 phdr(notused) 293 int notused; 294 { 295 register int i; 296 297 (void)printf(" tty"); 298 for (i = 0; i < dk_ndrive; i++) 299 if (dr_select[i]) 300 (void)printf(" %3.3s ", dr_name[i]); 301 (void)printf(" cpu\n tin tout"); 302 for (i = 0; i < dk_ndrive; i++) 303 if (dr_select[i]) 304 (void)printf(" sps tps msps "); 305 (void)printf(" us ni sy id\n"); 306 } 307 308 void 309 dkstats() 310 { 311 register int dn; 312 double atime, itime, msps, words, xtime; 313 314 for (dn = 0; dn < dk_ndrive; ++dn) { 315 if (!dr_select[dn]) 316 continue; 317 words = cur.dk_wds[dn] * 32; /* words xfer'd */ 318 (void)printf("%4.0f", /* sectors */ 319 words / (DEV_BSIZE / 2) / etime); 320 321 (void)printf("%4.0f", cur.dk_xfer[dn] / etime); 322 323 if (dk_wpms[dn] && cur.dk_xfer[dn]) { 324 atime = cur.dk_time[dn]; /* ticks disk busy */ 325 atime /= (float)hz; /* ticks to seconds */ 326 xtime = words / dk_wpms[dn]; /* transfer time */ 327 itime = atime - xtime; /* time not xfer'ing */ 328 if (itime < 0) 329 msps = 0; 330 else 331 msps = itime * 1000 / cur.dk_xfer[dn]; 332 } else 333 msps = 0; 334 (void)printf("%5.1f ", msps); 335 } 336 } 337 338 void 339 cpustats() 340 { 341 register int state; 342 double time; 343 344 time = 0; 345 for (state = 0; state < CPUSTATES; ++state) 346 time += cur.cp_time[state]; 347 for (state = 0; state < CPUSTATES; ++state) 348 (void)printf("%3.0f", 349 100. * cur.cp_time[state] / (time ? time : 1)); 350 } 351 352 void 353 usage() 354 { 355 (void)fprintf(stderr, 356 "usage: iostat [-c count] [-M core] [-N system] [-w wait] [drives]\n"); 357 exit(1); 358 } 359 360 #if __STDC__ 361 #include <stdarg.h> 362 #else 363 #include <varargs.h> 364 #endif 365 366 void 367 #if __STDC__ 368 err(const char *fmt, ...) 369 #else 370 err(fmt, va_alist) 371 char *fmt; 372 va_dcl 373 #endif 374 { 375 va_list ap; 376 #if __STDC__ 377 va_start(ap, fmt); 378 #else 379 va_start(ap); 380 #endif 381 (void)fprintf(stderr, "iostat: "); 382 (void)vfprintf(stderr, fmt, ap); 383 va_end(ap); 384 (void)fprintf(stderr, "\n"); 385 exit(1); 386 /* NOTREACHED */ 387 } 388