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