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