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