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