1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 2723 cth * Common Development and Distribution License (the "License"). 6 2723 cth * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 3331 as158974 22 0 stevel /* 23 9123 john * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel * 26 0 stevel * rewritten from UCB 4.13 83/09/25 27 0 stevel * rewritten from SunOS 4.1 SID 1.18 89/10/06 28 0 stevel */ 29 0 stevel 30 0 stevel #include <stdio.h> 31 0 stevel #include <stdlib.h> 32 0 stevel #include <stdarg.h> 33 0 stevel #include <ctype.h> 34 0 stevel #include <unistd.h> 35 0 stevel #include <memory.h> 36 0 stevel #include <errno.h> 37 0 stevel #include <string.h> 38 0 stevel #include <signal.h> 39 0 stevel #include <sys/types.h> 40 0 stevel #include <time.h> 41 0 stevel #include <sys/time.h> 42 0 stevel #include <sys/sysinfo.h> 43 0 stevel #include <inttypes.h> 44 0 stevel #include <strings.h> 45 0 stevel #include <sys/systeminfo.h> 46 0 stevel #include <kstat.h> 47 9123 john #include <locale.h> 48 0 stevel 49 0 stevel #include "dsr.h" 50 0 stevel #include "statcommon.h" 51 0 stevel 52 0 stevel #define DISK_OLD 0x0001 53 0 stevel #define DISK_NEW 0x0002 54 0 stevel #define DISK_EXTENDED 0x0004 55 0 stevel #define DISK_ERRORS 0x0008 56 0 stevel #define DISK_EXTENDED_ERRORS 0x0010 57 2907 cth #define DISK_IOPATH_LI 0x0020 /* LunInitiator */ 58 2907 cth #define DISK_IOPATH_LTI 0x0040 /* LunTargetInitiator */ 59 2907 cth 60 0 stevel #define DISK_NORMAL (DISK_OLD | DISK_NEW) 61 0 stevel #define DISK_IO_MASK (DISK_OLD | DISK_NEW | DISK_EXTENDED) 62 0 stevel #define DISK_ERROR_MASK (DISK_ERRORS | DISK_EXTENDED_ERRORS) 63 2907 cth #define PRINT_VERTICAL (DISK_ERROR_MASK | DISK_EXTENDED) 64 0 stevel 65 0 stevel #define REPRINT 19 66 10933 Jose 67 10933 Jose #define NUMBER_OF_ERR_COUNTERS 3 68 0 stevel 69 0 stevel /* 70 0 stevel * It's really a pseudo-gigabyte. We use 1000000000 bytes so that the disk 71 0 stevel * labels don't look bad. 1GB is really 1073741824 bytes. 72 0 stevel */ 73 0 stevel #define DISK_GIGABYTE 1000000000.0 74 0 stevel 75 0 stevel /* 76 0 stevel * Function desciptor to be called when extended 77 0 stevel * headers are used. 78 0 stevel */ 79 0 stevel typedef struct formatter { 80 0 stevel void (*nfunc)(void); 81 0 stevel struct formatter *next; 82 0 stevel } format_t; 83 0 stevel 84 0 stevel /* 85 0 stevel * Used to get formatting right when printing tty/cpu 86 0 stevel * data to the right of disk data 87 0 stevel */ 88 0 stevel enum show_disk_mode { 89 0 stevel SHOW_FIRST_ONLY, 90 0 stevel SHOW_SECOND_ONWARDS, 91 0 stevel SHOW_ALL 92 0 stevel }; 93 0 stevel 94 0 stevel enum show_disk_mode show_disk_mode = SHOW_ALL; 95 0 stevel 96 5461 tc35445 char *cmdname = "iostat"; 97 5461 tc35445 int caught_cont = 0; 98 0 stevel 99 0 stevel static char one_blank[] = " "; 100 0 stevel static char two_blanks[] = " "; 101 0 stevel 102 0 stevel /* 103 0 stevel * count for number of lines to be emitted before a header is 104 0 stevel * shown again. Only used for the basic format. 105 0 stevel */ 106 0 stevel static uint_t tohdr = 1; 107 0 stevel 108 0 stevel /* 109 0 stevel * If we're in raw format, have we printed a header? We only do it 110 0 stevel * once for raw but we emit it every REPRINT lines in non-raw format. 111 0 stevel * This applies only for the basic header. The extended header is 112 0 stevel * done only once in both formats. 113 0 stevel */ 114 0 stevel static uint_t hdr_out; 115 0 stevel 116 0 stevel /* 117 0 stevel * Flags representing arguments from command line 118 0 stevel */ 119 0 stevel static uint_t do_tty; /* show tty info (-t) */ 120 0 stevel static uint_t do_disk; /* show disk info per selected */ 121 2907 cth /* format (-d, -D, -e, -E, -x -X -Y) */ 122 0 stevel static uint_t do_cpu; /* show cpu info (-c) */ 123 0 stevel static uint_t do_interval; /* do intervals (-I) */ 124 0 stevel static int do_partitions; /* per-partition stats (-p) */ 125 0 stevel static int do_partitions_only; /* per-partition stats only (-P) */ 126 0 stevel /* no per-device stats for disks */ 127 0 stevel static uint_t do_conversions; /* display disks as cXtYdZ (-n) */ 128 0 stevel static uint_t do_megabytes; /* display data in MB/sec (-M) */ 129 0 stevel static uint_t do_controller; /* display controller info (-C) */ 130 0 stevel static uint_t do_raw; /* emit raw format (-r) */ 131 10265 Krishnendu static uint_t timestamp_fmt = NODATE; /* timestamp each display (-T) */ 132 0 stevel static uint_t do_devid; /* -E should show devid */ 133 0 stevel 134 0 stevel /* 135 0 stevel * Default number of disk drives to be displayed in basic format 136 0 stevel */ 137 0 stevel #define DEFAULT_LIMIT 4 138 0 stevel 139 0 stevel struct iodev_filter df; 140 0 stevel 141 0 stevel static uint_t suppress_state; /* skip state change messages */ 142 0 stevel static uint_t suppress_zero; /* skip zero valued lines */ 143 0 stevel static uint_t show_mountpts; /* show mount points */ 144 0 stevel static int interval; /* interval (seconds) to output */ 145 0 stevel static int iter; /* iterations from command line */ 146 0 stevel 147 2907 cth #define SMALL_SCRATCH_BUFLEN MAXNAMELEN 148 2907 cth 149 2907 cth static int iodevs_nl; /* name field width */ 150 2907 cth #define IODEVS_NL_MIN 6 /* not too thin for "device" */ 151 2907 cth #define IODEVS_NL_MAX 24 /* but keep full width under 80 */ 152 0 stevel 153 0 stevel static char disk_header[132]; 154 0 stevel static uint_t dh_len; /* disk header length for centering */ 155 0 stevel static int lineout; /* data waiting to be printed? */ 156 0 stevel 157 0 stevel static struct snapshot *newss; 158 0 stevel static struct snapshot *oldss; 159 2907 cth static double getime; /* elapsed time */ 160 2907 cth static double percent; /* 100 / etime */ 161 0 stevel 162 0 stevel /* 163 0 stevel * List of functions to be called which will construct the desired output 164 0 stevel */ 165 0 stevel static format_t *formatter_list; 166 0 stevel static format_t *formatter_end; 167 0 stevel 168 0 stevel static u_longlong_t ull_delta(u_longlong_t, u_longlong_t); 169 0 stevel static uint_t u32_delta(uint_t, uint_t); 170 0 stevel static void setup(void (*nfunc)(void)); 171 0 stevel static void print_tty_hdr1(void); 172 0 stevel static void print_tty_hdr2(void); 173 0 stevel static void print_cpu_hdr1(void); 174 0 stevel static void print_cpu_hdr2(void); 175 0 stevel static void print_tty_data(void); 176 0 stevel static void print_cpu_data(void); 177 0 stevel static void print_err_hdr(void); 178 0 stevel static void print_disk_header(void); 179 0 stevel static void hdrout(void); 180 0 stevel static void disk_errors(void); 181 0 stevel static void do_newline(void); 182 0 stevel static void push_out(const char *, ...); 183 0 stevel static void printhdr(int); 184 0 stevel static void printxhdr(void); 185 0 stevel static void usage(void); 186 0 stevel static void do_args(int, char **); 187 0 stevel static void do_format(void); 188 0 stevel static void show_all_disks(void); 189 0 stevel static void show_first_disk(void); 190 0 stevel static void show_other_disks(void); 191 0 stevel static void show_disk_errors(void *, void *, void *); 192 0 stevel static void write_core_header(void); 193 0 stevel static int fzero(double value); 194 0 stevel static int safe_strtoi(char const *val, char *errmsg); 195 0 stevel 196 0 stevel int 197 0 stevel main(int argc, char **argv) 198 0 stevel { 199 0 stevel enum snapshot_types types = SNAP_SYSTEM; 200 0 stevel kstat_ctl_t *kc; 201 0 stevel long hz; 202 5957 wroche int forever; 203 5461 tc35445 hrtime_t start_n; 204 5461 tc35445 hrtime_t period_n; 205 9123 john 206 9123 john (void) setlocale(LC_ALL, ""); 207 9123 john #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 208 9123 john #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 209 9123 john #endif 210 9123 john (void) textdomain(TEXT_DOMAIN); 211 0 stevel 212 0 stevel do_args(argc, argv); 213 0 stevel 214 0 stevel /* 215 0 stevel * iostat historically showed CPU changes, even though 216 0 stevel * it doesn't provide much useful information 217 0 stevel */ 218 0 stevel types |= SNAP_CPUS; 219 0 stevel 220 0 stevel if (do_disk) 221 0 stevel types |= SNAP_IODEVS; 222 0 stevel 223 0 stevel if (do_disk && !do_partitions_only) 224 0 stevel df.if_allowed_types |= IODEV_DISK; 225 2907 cth if (do_disk & DISK_IOPATH_LI) { 226 2907 cth df.if_allowed_types |= IODEV_IOPATH_LTI; 227 2907 cth types |= SNAP_IOPATHS_LI; 228 2907 cth } 229 2907 cth if (do_disk & DISK_IOPATH_LTI) { 230 2907 cth df.if_allowed_types |= IODEV_IOPATH_LTI; 231 2907 cth types |= SNAP_IOPATHS_LTI; 232 0 stevel } 233 0 stevel if (do_disk & DISK_ERROR_MASK) 234 0 stevel types |= SNAP_IODEV_ERRORS; 235 0 stevel if (do_partitions || do_partitions_only) 236 0 stevel df.if_allowed_types |= IODEV_PARTITION; 237 0 stevel if (do_conversions) 238 0 stevel types |= SNAP_IODEV_PRETTY; 239 2723 cth if (do_devid) 240 2723 cth types |= SNAP_IODEV_DEVID; 241 0 stevel if (do_controller) { 242 0 stevel if (!(do_disk & PRINT_VERTICAL) || 243 2907 cth (do_disk & DISK_EXTENDED_ERRORS)) 244 0 stevel fail(0, "-C can only be used with -e or -x."); 245 0 stevel types |= SNAP_CONTROLLERS; 246 0 stevel df.if_allowed_types |= IODEV_CONTROLLER; 247 0 stevel } 248 0 stevel 249 0 stevel hz = sysconf(_SC_CLK_TCK); 250 0 stevel 251 0 stevel /* 252 0 stevel * Undocumented behavior - sending a SIGCONT will result 253 0 stevel * in a new header being emitted. Used only if we're not 254 0 stevel * doing extended headers. This is a historical 255 0 stevel * artifact. 256 0 stevel */ 257 0 stevel if (!(do_disk & PRINT_VERTICAL)) 258 0 stevel (void) signal(SIGCONT, printhdr); 259 0 stevel 260 0 stevel if (interval) 261 5461 tc35445 period_n = (hrtime_t)interval * NANOSEC; 262 0 stevel 263 0 stevel kc = open_kstat(); 264 5461 tc35445 if (interval) 265 5461 tc35445 start_n = gethrtime(); 266 0 stevel newss = acquire_snapshot(kc, types, &df); 267 2907 cth 268 2907 cth /* compute width of "device" field */ 269 2907 cth iodevs_nl = newss->s_iodevs_is_name_maxlen; 270 2907 cth iodevs_nl = (iodevs_nl < IODEVS_NL_MIN) ? 271 2907 cth IODEVS_NL_MIN : iodevs_nl; 272 2907 cth iodevs_nl = (iodevs_nl > IODEVS_NL_MAX) ? 273 2907 cth IODEVS_NL_MAX : iodevs_nl; 274 2907 cth 275 2907 cth do_format(); 276 0 stevel 277 5957 wroche forever = (iter == 0); 278 0 stevel do { 279 6266 wroche if (do_conversions && show_mountpts) 280 6266 wroche do_mnttab(); 281 6266 wroche 282 0 stevel if (do_tty || do_cpu) { 283 0 stevel kstat_t *oldks; 284 0 stevel oldks = oldss ? &oldss->s_sys.ss_agg_sys : NULL; 285 0 stevel getime = cpu_ticks_delta(oldks, 286 0 stevel &newss->s_sys.ss_agg_sys); 287 0 stevel percent = (getime > 0.0) ? 100.0 / getime : 0.0; 288 0 stevel getime = (getime / nr_active_cpus(newss)) / hz; 289 0 stevel if (getime == 0.0) 290 0 stevel getime = (double)interval; 291 0 stevel if (getime == 0.0 || do_interval) 292 0 stevel getime = 1.0; 293 0 stevel } 294 0 stevel 295 0 stevel if (formatter_list) { 296 0 stevel format_t *tmp; 297 0 stevel tmp = formatter_list; 298 10265 Krishnendu 299 10265 Krishnendu if (timestamp_fmt != NODATE) 300 10265 Krishnendu print_timestamp(timestamp_fmt); 301 10265 Krishnendu 302 0 stevel while (tmp) { 303 0 stevel (tmp->nfunc)(); 304 0 stevel tmp = tmp->next; 305 0 stevel } 306 0 stevel (void) fflush(stdout); 307 0 stevel } 308 0 stevel 309 5957 wroche /* only remaining/doing a single iteration, we are done */ 310 5957 wroche if (iter == 1) 311 2723 cth continue; 312 2723 cth 313 5957 wroche if (interval > 0) 314 5461 tc35445 /* Have a kip */ 315 5957 wroche sleep_until(&start_n, period_n, forever, &caught_cont); 316 0 stevel 317 0 stevel free_snapshot(oldss); 318 0 stevel oldss = newss; 319 0 stevel newss = acquire_snapshot(kc, types, &df); 320 2907 cth iodevs_nl = (newss->s_iodevs_is_name_maxlen > iodevs_nl) ? 321 2907 cth newss->s_iodevs_is_name_maxlen : iodevs_nl; 322 2907 cth iodevs_nl = (iodevs_nl < IODEVS_NL_MIN) ? 323 2907 cth IODEVS_NL_MIN : iodevs_nl; 324 2907 cth iodevs_nl = (iodevs_nl > IODEVS_NL_MAX) ? 325 2907 cth IODEVS_NL_MAX : iodevs_nl; 326 0 stevel 327 0 stevel if (!suppress_state) 328 0 stevel snapshot_report_changes(oldss, newss); 329 0 stevel 330 0 stevel /* if config changed, show stats from boot */ 331 0 stevel if (snapshot_has_changed(oldss, newss)) { 332 0 stevel free_snapshot(oldss); 333 0 stevel oldss = NULL; 334 0 stevel } 335 0 stevel 336 0 stevel } while (--iter); 337 0 stevel 338 0 stevel free_snapshot(oldss); 339 0 stevel free_snapshot(newss); 340 2723 cth (void) kstat_close(kc); 341 2907 cth free(df.if_names); 342 0 stevel return (0); 343 0 stevel } 344 0 stevel 345 0 stevel /* 346 0 stevel * Some magic numbers used in header formatting. 347 0 stevel * 348 0 stevel * DISK_LEN = length of either "kps tps serv" or "wps rps util" 349 0 stevel * using 0 as the first position 350 0 stevel * 351 0 stevel * DISK_ERROR_LEN = length of "s/w h/w trn tot" with one space on 352 0 stevel * either side. Does not use zero as first pos. 353 0 stevel * 354 0 stevel * DEVICE_LEN = length of "device" + 1 character. 355 0 stevel */ 356 0 stevel 357 0 stevel #define DISK_LEN 11 358 0 stevel #define DISK_ERROR_LEN 16 359 0 stevel #define DEVICE_LEN 7 360 0 stevel 361 0 stevel /*ARGSUSED*/ 362 0 stevel static void 363 0 stevel show_disk_name(void *v1, void *v2, void *data) 364 0 stevel { 365 0 stevel struct iodev_snapshot *dev = (struct iodev_snapshot *)v2; 366 0 stevel size_t slen; 367 0 stevel char *name; 368 0 stevel char fbuf[SMALL_SCRATCH_BUFLEN]; 369 0 stevel 370 0 stevel if (dev == NULL) 371 0 stevel return; 372 0 stevel 373 2907 cth name = do_conversions ? dev->is_pretty : dev->is_name; 374 2907 cth name = name ? name : dev->is_name; 375 2907 cth 376 0 stevel if (!do_raw) { 377 0 stevel uint_t width; 378 0 stevel 379 0 stevel slen = strlen(name); 380 0 stevel /* 381 0 stevel * The length is less 382 0 stevel * than the section 383 0 stevel * which will be displayed 384 0 stevel * on the next line. 385 0 stevel * Center the entry. 386 0 stevel */ 387 0 stevel 388 0 stevel width = (DISK_LEN + 1)/2 + (slen / 2); 389 0 stevel (void) snprintf(fbuf, sizeof (fbuf), 390 0 stevel "%*s", width, name); 391 0 stevel name = fbuf; 392 2723 cth push_out("%-13.13s ", name); 393 0 stevel } else { 394 0 stevel push_out(name); 395 0 stevel } 396 0 stevel } 397 0 stevel 398 0 stevel /*ARGSUSED*/ 399 0 stevel static void 400 0 stevel show_disk_header(void *v1, void *v2, void *data) 401 0 stevel { 402 0 stevel push_out(disk_header); 403 0 stevel } 404 0 stevel 405 0 stevel /* 406 0 stevel * Write out a two line header. What is written out depends on the flags 407 0 stevel * selected but in the worst case consists of a tty header, a disk header 408 0 stevel * providing information for 4 disks and a cpu header. 409 0 stevel * 410 0 stevel * The tty header consists of the word "tty" on the first line above the 411 0 stevel * words "tin tout" on the next line. If present the tty portion consumes 412 0 stevel * the first 10 characters of each line since "tin tout" is surrounded 413 0 stevel * by single spaces. 414 0 stevel * 415 0 stevel * Each of the disk sections is a 14 character "block" in which the name of 416 0 stevel * the disk is centered in the first 12 characters of the first line. 417 0 stevel * 418 0 stevel * The cpu section is an 11 character block with "cpu" centered over the 419 0 stevel * section. 420 0 stevel * 421 0 stevel * The worst case should look as follows: 422 0 stevel * 423 0 stevel * 0---------1--------2---------3---------4---------5---------6---------7------- 424 0 stevel * tty sd0 sd1 sd2 sd3 cpu 425 0 stevel * tin tout kps tps serv kps tps serv kps tps serv kps tps serv us sy wt id 426 0 stevel * NNN NNNN NNN NNN NNNN NNN NNN NNNN NNN NNN NNNN NNN NNN NNNN NN NN NN NN 427 0 stevel * 428 0 stevel * When -D is specified, the disk header looks as follows (worst case): 429 0 stevel * 430 0 stevel * 0---------1--------2---------3---------4---------5---------6---------7------- 431 0 stevel * tty sd0 sd1 sd2 sd3 cpu 432 0 stevel * tin tout rps wps util rps wps util rps wps util rps wps util us sy wt id 433 0 stevel * NNN NNNN NNN NNN NNNN NNN NNN NNNN NNN NNN NNNN NNN NNN NNNN NN NN NN NN 434 0 stevel */ 435 0 stevel static void 436 0 stevel printhdr(int sig) 437 0 stevel { 438 0 stevel /* 439 0 stevel * If we're here because a signal fired, reenable the 440 0 stevel * signal. 441 0 stevel */ 442 0 stevel if (sig) 443 0 stevel (void) signal(SIGCONT, printhdr); 444 5461 tc35445 if (sig == SIGCONT) 445 5461 tc35445 caught_cont = 1; 446 0 stevel /* 447 0 stevel * Horizontal mode headers 448 0 stevel * 449 0 stevel * First line 450 0 stevel */ 451 0 stevel if (do_tty) 452 0 stevel print_tty_hdr1(); 453 0 stevel 454 0 stevel if (do_disk & DISK_NORMAL) { 455 0 stevel (void) snapshot_walk(SNAP_IODEVS, NULL, newss, 456 0 stevel show_disk_name, NULL); 457 0 stevel } 458 0 stevel 459 0 stevel if (do_cpu) 460 0 stevel print_cpu_hdr1(); 461 0 stevel do_newline(); 462 0 stevel 463 0 stevel /* 464 0 stevel * Second line 465 0 stevel */ 466 0 stevel if (do_tty) 467 0 stevel print_tty_hdr2(); 468 0 stevel 469 0 stevel if (do_disk & DISK_NORMAL) { 470 0 stevel (void) snapshot_walk(SNAP_IODEVS, NULL, newss, 471 0 stevel show_disk_header, NULL); 472 0 stevel } 473 0 stevel 474 0 stevel if (do_cpu) 475 0 stevel print_cpu_hdr2(); 476 0 stevel do_newline(); 477 0 stevel 478 0 stevel tohdr = REPRINT; 479 0 stevel } 480 0 stevel 481 0 stevel /* 482 0 stevel * Write out the extended header centered over the core information. 483 0 stevel */ 484 0 stevel static void 485 0 stevel write_core_header(void) 486 0 stevel { 487 0 stevel char *edev = "extended device statistics"; 488 0 stevel uint_t lead_space_ct; 489 0 stevel uint_t follow_space_ct; 490 0 stevel size_t edevlen; 491 0 stevel 492 0 stevel if (do_raw == 0) { 493 0 stevel /* 494 0 stevel * The things we do to look nice... 495 0 stevel * 496 0 stevel * Center the core output header. Make sure we have the 497 0 stevel * right number of trailing spaces for follow-on headers 498 0 stevel * (i.e., cpu and/or tty and/or errors). 499 0 stevel */ 500 0 stevel edevlen = strlen(edev); 501 0 stevel lead_space_ct = dh_len - edevlen; 502 0 stevel lead_space_ct /= 2; 503 0 stevel if (lead_space_ct > 0) { 504 0 stevel follow_space_ct = dh_len - (lead_space_ct + edevlen); 505 0 stevel if (do_disk & DISK_ERRORS) 506 0 stevel follow_space_ct -= DISK_ERROR_LEN; 507 0 stevel if ((do_disk & DISK_EXTENDED) && do_conversions) 508 0 stevel follow_space_ct -= DEVICE_LEN; 509 0 stevel 510 0 stevel push_out("%1$*2$.*2$s%3$s%4$*5$.*5$s", one_blank, 511 0 stevel lead_space_ct, edev, one_blank, follow_space_ct); 512 0 stevel } else 513 0 stevel push_out("%56s", edev); 514 0 stevel } else 515 0 stevel push_out(edev); 516 0 stevel } 517 0 stevel 518 0 stevel /* 519 0 stevel * In extended mode headers, we don't want to reprint the header on 520 0 stevel * signals as they are printed every time anyways. 521 0 stevel */ 522 0 stevel static void 523 0 stevel printxhdr(void) 524 0 stevel { 525 0 stevel 526 0 stevel /* 527 0 stevel * Vertical mode headers 528 0 stevel */ 529 0 stevel if (do_disk & DISK_EXTENDED) 530 0 stevel setup(write_core_header); 531 0 stevel if (do_disk & DISK_ERRORS) 532 0 stevel setup(print_err_hdr); 533 0 stevel 534 0 stevel if (do_conversions) { 535 0 stevel setup(do_newline); 536 0 stevel if (do_disk & (DISK_EXTENDED | DISK_ERRORS)) 537 0 stevel setup(print_disk_header); 538 0 stevel setup(do_newline); 539 0 stevel } else { 540 0 stevel if (do_tty) 541 0 stevel setup(print_tty_hdr1); 542 0 stevel if (do_cpu) 543 0 stevel setup(print_cpu_hdr1); 544 0 stevel setup(do_newline); 545 0 stevel 546 0 stevel if (do_disk & (DISK_EXTENDED | DISK_ERRORS)) 547 0 stevel setup(print_disk_header); 548 0 stevel if (do_tty) 549 0 stevel setup(print_tty_hdr2); 550 0 stevel if (do_cpu) 551 0 stevel setup(print_cpu_hdr2); 552 0 stevel setup(do_newline); 553 0 stevel } 554 0 stevel } 555 0 stevel 556 0 stevel /* 557 0 stevel * Write out a line for this disk - note that show_disk writes out 558 0 stevel * full lines or blocks for each selected disk. 559 0 stevel */ 560 0 stevel static void 561 0 stevel show_disk(void *v1, void *v2, void *data) 562 0 stevel { 563 10933 Jose uint32_t err_counters[NUMBER_OF_ERR_COUNTERS]; 564 10933 Jose boolean_t display_err_counters = do_disk & DISK_ERRORS; 565 0 stevel struct iodev_snapshot *old = (struct iodev_snapshot *)v1; 566 0 stevel struct iodev_snapshot *new = (struct iodev_snapshot *)v2; 567 0 stevel int *count = (int *)data; 568 0 stevel double rps, wps, tps, mtps, krps, kwps, kps, avw, avr, w_pct, r_pct; 569 0 stevel double wserv, rserv, serv; 570 0 stevel double iosize; /* kb/sec or MB/sec */ 571 0 stevel double etime, hr_etime; 572 0 stevel char *disk_name; 573 0 stevel u_longlong_t ldeltas; 574 0 stevel uint_t udeltas; 575 0 stevel uint64_t t_delta; 576 0 stevel uint64_t w_delta; 577 0 stevel uint64_t r_delta; 578 0 stevel int doit = 1; 579 0 stevel uint_t toterrs; 580 0 stevel char *fstr; 581 0 stevel 582 0 stevel if (new == NULL) 583 0 stevel return; 584 0 stevel 585 0 stevel switch (show_disk_mode) { 586 0 stevel case SHOW_FIRST_ONLY: 587 0 stevel if (count != NULL && *count) 588 0 stevel return; 589 0 stevel break; 590 0 stevel 591 0 stevel case SHOW_SECOND_ONWARDS: 592 0 stevel if (count != NULL && !*count) { 593 0 stevel (*count)++; 594 0 stevel return; 595 0 stevel } 596 0 stevel break; 597 0 stevel 598 0 stevel default: 599 0 stevel break; 600 0 stevel } 601 0 stevel 602 2907 cth disk_name = do_conversions ? new->is_pretty : new->is_name; 603 2907 cth disk_name = disk_name ? disk_name : new->is_name; 604 0 stevel 605 0 stevel /* 606 0 stevel * Only do if we want IO stats - Avoids errors traveling this 607 0 stevel * section if that's all we want to see. 608 0 stevel */ 609 0 stevel if (do_disk & DISK_IO_MASK) { 610 0 stevel if (old) { 611 0 stevel t_delta = hrtime_delta(old->is_snaptime, 612 0 stevel new->is_snaptime); 613 0 stevel } else { 614 0 stevel t_delta = hrtime_delta(new->is_crtime, 615 0 stevel new->is_snaptime); 616 0 stevel } 617 0 stevel 618 2907 cth if (new->is_nr_children) { 619 2907 cth if (new->is_type == IODEV_CONTROLLER) { 620 2907 cth t_delta /= new->is_nr_children; 621 2907 cth } else if ((new->is_type == IODEV_IOPATH_LT) || 622 2907 cth (new->is_type == IODEV_IOPATH_LI)) { 623 2907 cth /* synthetic path */ 624 2907 cth if (!old) { 625 2907 cth t_delta = new->is_crtime; 626 2907 cth } 627 2907 cth t_delta /= new->is_nr_children; 628 2907 cth } 629 2907 cth } 630 0 stevel 631 0 stevel hr_etime = (double)t_delta; 632 0 stevel if (hr_etime == 0.0) 633 0 stevel hr_etime = (double)NANOSEC; 634 0 stevel etime = hr_etime / (double)NANOSEC; 635 0 stevel 636 0 stevel /* reads per second */ 637 0 stevel udeltas = u32_delta(old ? old->is_stats.reads : 0, 638 0 stevel new->is_stats.reads); 639 0 stevel rps = (double)udeltas; 640 0 stevel rps /= etime; 641 0 stevel 642 0 stevel /* writes per second */ 643 0 stevel udeltas = u32_delta(old ? old->is_stats.writes : 0, 644 0 stevel new->is_stats.writes); 645 0 stevel wps = (double)udeltas; 646 0 stevel wps /= etime; 647 0 stevel 648 0 stevel tps = rps + wps; 649 0 stevel /* transactions per second */ 650 0 stevel 651 0 stevel /* 652 0 stevel * report throughput as either kb/sec or MB/sec 653 0 stevel */ 654 0 stevel 655 0 stevel if (!do_megabytes) 656 0 stevel iosize = 1024.0; 657 0 stevel else 658 0 stevel iosize = 1048576.0; 659 0 stevel 660 0 stevel ldeltas = ull_delta(old ? old->is_stats.nread : 0, 661 0 stevel new->is_stats.nread); 662 0 stevel if (ldeltas) { 663 0 stevel krps = (double)ldeltas; 664 0 stevel krps /= etime; 665 0 stevel krps /= iosize; 666 0 stevel } else 667 0 stevel krps = 0.0; 668 0 stevel 669 0 stevel ldeltas = ull_delta(old ? old->is_stats.nwritten : 0, 670 0 stevel new->is_stats.nwritten); 671 0 stevel if (ldeltas) { 672 0 stevel kwps = (double)ldeltas; 673 0 stevel kwps /= etime; 674 0 stevel kwps /= iosize; 675 0 stevel } else 676 0 stevel kwps = 0.0; 677 0 stevel 678 0 stevel /* 679 0 stevel * Blocks transferred per second 680 0 stevel */ 681 0 stevel kps = krps + kwps; 682 0 stevel 683 0 stevel /* 684 207 petede * Average number of wait transactions waiting 685 0 stevel */ 686 0 stevel w_delta = hrtime_delta((u_longlong_t) 687 0 stevel (old ? old->is_stats.wlentime : 0), 688 0 stevel new->is_stats.wlentime); 689 0 stevel if (w_delta) { 690 0 stevel avw = (double)w_delta; 691 0 stevel avw /= hr_etime; 692 0 stevel } else 693 0 stevel avw = 0.0; 694 0 stevel 695 0 stevel /* 696 207 petede * Average number of run transactions waiting 697 0 stevel */ 698 0 stevel r_delta = hrtime_delta(old ? old->is_stats.rlentime : 0, 699 0 stevel new->is_stats.rlentime); 700 0 stevel if (r_delta) { 701 0 stevel avr = (double)r_delta; 702 0 stevel avr /= hr_etime; 703 0 stevel } else 704 0 stevel avr = 0.0; 705 0 stevel 706 0 stevel /* 707 0 stevel * Average wait service time in milliseconds 708 0 stevel */ 709 0 stevel if (tps > 0.0 && (avw != 0.0 || avr != 0.0)) { 710 0 stevel mtps = 1000.0 / tps; 711 0 stevel if (avw != 0.0) 712 0 stevel wserv = avw * mtps; 713 0 stevel else 714 0 stevel wserv = 0.0; 715 0 stevel 716 0 stevel if (avr != 0.0) 717 0 stevel rserv = avr * mtps; 718 0 stevel else 719 0 stevel rserv = 0.0; 720 0 stevel serv = rserv + wserv; 721 0 stevel } else { 722 0 stevel rserv = 0.0; 723 0 stevel wserv = 0.0; 724 0 stevel serv = 0.0; 725 0 stevel } 726 0 stevel 727 0 stevel /* % of time there is a transaction waiting for service */ 728 0 stevel t_delta = hrtime_delta(old ? old->is_stats.wtime : 0, 729 0 stevel new->is_stats.wtime); 730 0 stevel if (t_delta) { 731 0 stevel w_pct = (double)t_delta; 732 0 stevel w_pct /= hr_etime; 733 0 stevel w_pct *= 100.0; 734 0 stevel 735 0 stevel /* 736 0 stevel * Average the wait queue utilization over the 737 0 stevel * the controller's devices, if this is a controller. 738 0 stevel */ 739 0 stevel if (new->is_type == IODEV_CONTROLLER) 740 0 stevel w_pct /= new->is_nr_children; 741 0 stevel } else 742 0 stevel w_pct = 0.0; 743 0 stevel 744 0 stevel /* % of time there is a transaction running */ 745 0 stevel t_delta = hrtime_delta(old ? old->is_stats.rtime : 0, 746 0 stevel new->is_stats.rtime); 747 0 stevel if (t_delta) { 748 0 stevel r_pct = (double)t_delta; 749 0 stevel r_pct /= hr_etime; 750 0 stevel r_pct *= 100.0; 751 0 stevel 752 0 stevel /* 753 0 stevel * Average the percent busy over the controller's 754 0 stevel * devices, if this is a controller. 755 0 stevel */ 756 0 stevel if (new->is_type == IODEV_CONTROLLER) 757 0 stevel w_pct /= new->is_nr_children; 758 0 stevel } else { 759 0 stevel r_pct = 0.0; 760 0 stevel } 761 0 stevel 762 0 stevel /* % of time there is a transaction running */ 763 0 stevel if (do_interval) { 764 0 stevel rps *= etime; 765 0 stevel wps *= etime; 766 0 stevel tps *= etime; 767 0 stevel krps *= etime; 768 0 stevel kwps *= etime; 769 0 stevel kps *= etime; 770 0 stevel } 771 0 stevel } 772 0 stevel 773 0 stevel if (do_disk & (DISK_EXTENDED | DISK_ERRORS)) { 774 0 stevel if ((!do_conversions) && ((suppress_zero == 0) || 775 0 stevel ((do_disk & DISK_EXTENDED) == 0))) { 776 2907 cth if (do_raw == 0) { 777 2907 cth push_out("%-*.*s", 778 2907 cth iodevs_nl, iodevs_nl, disk_name); 779 2907 cth } else { 780 0 stevel push_out(disk_name); 781 2907 cth } 782 0 stevel } 783 0 stevel } 784 0 stevel 785 10933 Jose /* 786 10933 Jose * The error counters are read first (if asked for and if they are 787 10933 Jose * available). 788 10933 Jose */ 789 10933 Jose bzero(err_counters, sizeof (err_counters)); 790 10933 Jose toterrs = 0; 791 10933 Jose if (display_err_counters && (new->is_errors.ks_data != NULL)) { 792 10933 Jose kstat_named_t *knp; 793 10933 Jose int i; 794 10933 Jose 795 10933 Jose knp = KSTAT_NAMED_PTR(&new->is_errors); 796 10933 Jose for (i = 0; i < NUMBER_OF_ERR_COUNTERS; i++) { 797 10933 Jose switch (knp[i].data_type) { 798 10933 Jose case KSTAT_DATA_ULONG: 799 10933 Jose case KSTAT_DATA_ULONGLONG: 800 10933 Jose err_counters[i] = knp[i].value.ui32; 801 10933 Jose toterrs += knp[i].value.ui32; 802 10933 Jose break; 803 10933 Jose default: 804 10933 Jose break; 805 10933 Jose } 806 10933 Jose } 807 10933 Jose } 808 10933 Jose 809 0 stevel switch (do_disk & DISK_IO_MASK) { 810 5957 wroche case DISK_OLD: 811 0 stevel if (do_raw == 0) 812 0 stevel fstr = "%3.0f %3.0f %4.0f "; 813 0 stevel else 814 0 stevel fstr = "%.0f,%.0f,%.0f"; 815 0 stevel push_out(fstr, kps, tps, serv); 816 0 stevel break; 817 5957 wroche case DISK_NEW: 818 0 stevel if (do_raw == 0) 819 0 stevel fstr = "%3.0f %3.0f %4.1f "; 820 0 stevel else 821 0 stevel fstr = "%.0f,%.0f,%.1f"; 822 0 stevel push_out(fstr, rps, wps, r_pct); 823 0 stevel break; 824 5957 wroche case DISK_EXTENDED: 825 0 stevel if (suppress_zero) { 826 0 stevel if (fzero(rps) && fzero(wps) && fzero(krps) && 827 0 stevel fzero(kwps) && fzero(avw) && fzero(avr) && 828 10933 Jose fzero(serv) && fzero(w_pct) && fzero(r_pct) && 829 10933 Jose (toterrs == 0)) { 830 0 stevel doit = 0; 831 10933 Jose display_err_counters = B_FALSE; 832 2907 cth } else if (do_conversions == 0) { 833 2907 cth if (do_raw == 0) { 834 2907 cth push_out("%-*.*s", 835 2907 cth iodevs_nl, iodevs_nl, disk_name); 836 2907 cth } else { 837 0 stevel push_out(disk_name); 838 2907 cth } 839 0 stevel } 840 0 stevel } 841 0 stevel if (doit) { 842 0 stevel if (!do_conversions) { 843 0 stevel if (do_raw == 0) { 844 0 stevel fstr = " %6.1f %6.1f %6.1f %6.1f " 845 5957 wroche "%4.1f %4.1f %6.1f %3.0f " 846 5957 wroche "%3.0f "; 847 0 stevel } else { 848 0 stevel fstr = "%.1f,%.1f,%.1f,%.1f,%.1f,%.1f," 849 5957 wroche "%.1f,%.0f,%.0f"; 850 0 stevel } 851 0 stevel push_out(fstr, rps, wps, krps, kwps, avw, avr, 852 0 stevel serv, w_pct, r_pct); 853 0 stevel } else { 854 0 stevel if (do_raw == 0) { 855 0 stevel fstr = " %6.1f %6.1f %6.1f %6.1f " 856 5957 wroche "%4.1f %4.1f %6.1f %6.1f " 857 5957 wroche "%3.0f %3.0f "; 858 0 stevel } else { 859 0 stevel fstr = "%.1f,%.1f,%.1f,%.1f,%.1f,%.1f," 860 5957 wroche "%.1f,%.1f,%.0f,%.0f"; 861 0 stevel } 862 0 stevel push_out(fstr, rps, wps, krps, kwps, avw, avr, 863 0 stevel wserv, rserv, w_pct, r_pct); 864 0 stevel } 865 0 stevel } 866 0 stevel break; 867 0 stevel } 868 0 stevel 869 10933 Jose if (display_err_counters) { 870 10933 Jose char *efstr; 871 10933 Jose int i; 872 10933 Jose 873 10933 Jose if (do_raw == 0) { 874 10933 Jose if (do_disk == DISK_ERRORS) 875 0 stevel push_out(two_blanks); 876 10933 Jose efstr = "%3u "; 877 10933 Jose } else { 878 10933 Jose efstr = "%u"; 879 0 stevel } 880 0 stevel 881 10933 Jose for (i = 0; i < NUMBER_OF_ERR_COUNTERS; i++) 882 10933 Jose push_out(efstr, err_counters[i]); 883 0 stevel 884 10933 Jose push_out(efstr, toterrs); 885 0 stevel } 886 0 stevel 887 0 stevel if (suppress_zero == 0 || doit == 1) { 888 0 stevel if ((do_disk & (DISK_EXTENDED | DISK_ERRORS)) && 889 5957 wroche do_conversions) { 890 0 stevel push_out("%s", disk_name); 891 0 stevel if (show_mountpts && new->is_dname) { 892 0 stevel mnt_t *mount_pt; 893 0 stevel char *lu; 894 6266 wroche char *dnlu; 895 0 stevel char lub[SMALL_SCRATCH_BUFLEN]; 896 0 stevel 897 0 stevel lu = strrchr(new->is_dname, '/'); 898 0 stevel if (lu) { 899 6266 wroche /* only the part after a possible '/' */ 900 6266 wroche dnlu = strrchr(disk_name, '/'); 901 6266 wroche if (dnlu != NULL && 902 6266 wroche strcmp(dnlu, lu) == 0) 903 0 stevel lu = new->is_dname; 904 0 stevel else { 905 0 stevel *lu = 0; 906 0 stevel (void) strcpy(lub, 907 0 stevel new->is_dname); 908 0 stevel *lu = '/'; 909 0 stevel (void) strcat(lub, "/"); 910 0 stevel (void) strcat(lub, 911 0 stevel disk_name); 912 0 stevel lu = lub; 913 0 stevel } 914 0 stevel } else 915 0 stevel lu = disk_name; 916 0 stevel mount_pt = lookup_mntent_byname(lu); 917 0 stevel if (mount_pt) { 918 0 stevel if (do_raw == 0) 919 0 stevel push_out(" (%s)", 920 0 stevel mount_pt->mount_point); 921 0 stevel else 922 0 stevel push_out("(%s)", 923 0 stevel mount_pt->mount_point); 924 0 stevel } 925 0 stevel } 926 0 stevel } 927 0 stevel } 928 0 stevel 929 0 stevel if ((do_disk & PRINT_VERTICAL) && show_disk_mode != SHOW_FIRST_ONLY) 930 0 stevel do_newline(); 931 0 stevel 932 0 stevel if (count != NULL) 933 0 stevel (*count)++; 934 0 stevel } 935 0 stevel 936 0 stevel static void 937 0 stevel usage(void) 938 0 stevel { 939 0 stevel (void) fprintf(stderr, 940 2907 cth "Usage: iostat [-cCdDeEiImMnpPrstxXYz] " 941 0 stevel " [-l n] [-T d|u] [disk ...] [interval [count]]\n" 942 0 stevel "\t\t-c: report percentage of time system has spent\n" 943 0 stevel "\t\t\tin user/system/wait/idle mode\n" 944 0 stevel "\t\t-C: report disk statistics by controller\n" 945 0 stevel "\t\t-d: display disk Kb/sec, transfers/sec, avg. \n" 946 0 stevel "\t\t\tservice time in milliseconds \n" 947 0 stevel "\t\t-D: display disk reads/sec, writes/sec, \n" 948 0 stevel "\t\t\tpercentage disk utilization \n" 949 0 stevel "\t\t-e: report device error summary statistics\n" 950 0 stevel "\t\t-E: report extended device error statistics\n" 951 0 stevel "\t\t-i: show device IDs for -E output\n" 952 0 stevel "\t\t-I: report the counts in each interval,\n" 953 0 stevel "\t\t\tinstead of rates, where applicable\n" 954 0 stevel "\t\t-l n: Limit the number of disks to n\n" 955 0 stevel "\t\t-m: Display mount points (most useful with -p)\n" 956 0 stevel "\t\t-M: Display data throughput in MB/sec " 957 0 stevel "instead of Kb/sec\n" 958 0 stevel "\t\t-n: convert device names to cXdYtZ format\n" 959 0 stevel "\t\t-p: report per-partition disk statistics\n" 960 0 stevel "\t\t-P: report per-partition disk statistics only,\n" 961 0 stevel "\t\t\tno per-device disk statistics\n" 962 0 stevel "\t\t-r: Display data in comma separated format\n" 963 0 stevel "\t\t-s: Suppress state change messages\n" 964 0 stevel "\t\t-T d|u Display a timestamp in date (d) or unix " 965 0 stevel "time_t (u)\n" 966 0 stevel "\t\t-t: display chars read/written to terminals\n" 967 0 stevel "\t\t-x: display extended disk statistics\n" 968 0 stevel "\t\t-X: display I/O path statistics\n" 969 2907 cth "\t\t-Y: display I/O path (I/T/L) statistics\n" 970 0 stevel "\t\t-z: Suppress entries with all zero values\n"); 971 0 stevel exit(1); 972 0 stevel } 973 0 stevel 974 0 stevel /*ARGSUSED*/ 975 0 stevel static void 976 0 stevel show_disk_errors(void *v1, void *v2, void *d) 977 0 stevel { 978 0 stevel struct iodev_snapshot *disk = (struct iodev_snapshot *)v2; 979 0 stevel kstat_named_t *knp; 980 0 stevel size_t col; 981 0 stevel int i, len; 982 2907 cth char *dev_name; 983 0 stevel 984 0 stevel if (disk->is_errors.ks_ndata == 0) 985 0 stevel return; 986 0 stevel if (disk->is_type == IODEV_CONTROLLER) 987 0 stevel return; 988 0 stevel 989 2907 cth dev_name = do_conversions ? disk->is_pretty : disk->is_name; 990 2907 cth dev_name = dev_name ? dev_name : disk->is_name; 991 0 stevel 992 0 stevel len = strlen(dev_name); 993 0 stevel if (len > 20) 994 0 stevel push_out("%s ", dev_name); 995 0 stevel else if (len > 16) 996 0 stevel push_out("%-20.20s ", dev_name); 997 0 stevel else { 998 0 stevel if (do_conversions) 999 0 stevel push_out("%-16.16s ", dev_name); 1000 0 stevel else 1001 0 stevel push_out("%-9.9s ", dev_name); 1002 0 stevel } 1003 0 stevel col = 0; 1004 0 stevel 1005 0 stevel knp = KSTAT_NAMED_PTR(&disk->is_errors); 1006 0 stevel for (i = 0; i < disk->is_errors.ks_ndata; i++) { 1007 0 stevel /* skip kstats that the driver did not kstat_named_init */ 1008 0 stevel if (knp[i].name[0] == 0) 1009 0 stevel continue; 1010 0 stevel 1011 0 stevel col += strlen(knp[i].name); 1012 0 stevel 1013 0 stevel switch (knp[i].data_type) { 1014 0 stevel case KSTAT_DATA_CHAR: 1015 0 stevel if ((strcmp(knp[i].name, "Serial No") == 0) && 1016 0 stevel do_devid) { 1017 0 stevel if (disk->is_devid) { 1018 0 stevel push_out("Device Id: %s ", 1019 0 stevel disk->is_devid); 1020 0 stevel col += strlen(disk->is_devid); 1021 0 stevel } else 1022 0 stevel push_out("Device Id: "); 1023 0 stevel } else { 1024 0 stevel push_out("%s: %-.16s ", knp[i].name, 1025 0 stevel &knp[i].value.c[0]); 1026 0 stevel col += strlen(&knp[i].value.c[0]); 1027 0 stevel } 1028 0 stevel break; 1029 0 stevel case KSTAT_DATA_ULONG: 1030 0 stevel push_out("%s: %u ", knp[i].name, 1031 0 stevel knp[i].value.ui32); 1032 0 stevel col += 4; 1033 0 stevel break; 1034 0 stevel case KSTAT_DATA_ULONGLONG: 1035 0 stevel if (strcmp(knp[i].name, "Size") == 0) { 1036 0 stevel push_out("%s: %2.2fGB <%llu bytes>\n", 1037 0 stevel knp[i].name, 1038 0 stevel (float)knp[i].value.ui64 / 1039 0 stevel DISK_GIGABYTE, 1040 0 stevel knp[i].value.ui64); 1041 0 stevel col = 0; 1042 0 stevel break; 1043 0 stevel } 1044 0 stevel push_out("%s: %u ", knp[i].name, 1045 0 stevel knp[i].value.ui32); 1046 0 stevel col += 4; 1047 0 stevel break; 1048 0 stevel } 1049 0 stevel if ((col >= 62) || (i == 2)) { 1050 0 stevel do_newline(); 1051 0 stevel col = 0; 1052 0 stevel } 1053 0 stevel } 1054 0 stevel if (col > 0) { 1055 0 stevel do_newline(); 1056 0 stevel } 1057 0 stevel do_newline(); 1058 0 stevel } 1059 0 stevel 1060 0 stevel void 1061 0 stevel do_args(int argc, char **argv) 1062 0 stevel { 1063 0 stevel int c; 1064 0 stevel int errflg = 0; 1065 0 stevel extern char *optarg; 1066 0 stevel extern int optind; 1067 0 stevel 1068 2907 cth while ((c = getopt(argc, argv, "tdDxXYCciIpPnmMeEszrT:l:")) != EOF) 1069 0 stevel switch (c) { 1070 0 stevel case 't': 1071 0 stevel do_tty++; 1072 0 stevel break; 1073 0 stevel case 'd': 1074 0 stevel do_disk |= DISK_OLD; 1075 0 stevel break; 1076 0 stevel case 'D': 1077 0 stevel do_disk |= DISK_NEW; 1078 0 stevel break; 1079 0 stevel case 'x': 1080 0 stevel do_disk |= DISK_EXTENDED; 1081 0 stevel break; 1082 0 stevel case 'X': 1083 2907 cth if (do_disk & DISK_IOPATH_LTI) 1084 2907 cth errflg++; /* -Y already used */ 1085 2907 cth else 1086 2907 cth do_disk |= DISK_IOPATH_LI; 1087 2907 cth break; 1088 2907 cth case 'Y': 1089 2907 cth if (do_disk & DISK_IOPATH_LI) 1090 2907 cth errflg++; /* -X already used */ 1091 2907 cth else 1092 2907 cth do_disk |= DISK_IOPATH_LTI; 1093 0 stevel break; 1094 0 stevel case 'C': 1095 0 stevel do_controller++; 1096 0 stevel break; 1097 0 stevel case 'c': 1098 0 stevel do_cpu++; 1099 0 stevel break; 1100 0 stevel case 'I': 1101 0 stevel do_interval++; 1102 0 stevel break; 1103 0 stevel case 'p': 1104 0 stevel do_partitions++; 1105 0 stevel break; 1106 0 stevel case 'P': 1107 0 stevel do_partitions_only++; 1108 0 stevel break; 1109 0 stevel case 'n': 1110 0 stevel do_conversions++; 1111 0 stevel break; 1112 0 stevel case 'M': 1113 0 stevel do_megabytes++; 1114 0 stevel break; 1115 0 stevel case 'e': 1116 0 stevel do_disk |= DISK_ERRORS; 1117 0 stevel break; 1118 0 stevel case 'E': 1119 0 stevel do_disk |= DISK_EXTENDED_ERRORS; 1120 0 stevel break; 1121 0 stevel case 'i': 1122 0 stevel do_devid = 1; 1123 0 stevel break; 1124 0 stevel case 's': 1125 0 stevel suppress_state = 1; 1126 0 stevel break; 1127 0 stevel case 'z': 1128 0 stevel suppress_zero = 1; 1129 0 stevel break; 1130 0 stevel case 'm': 1131 0 stevel show_mountpts = 1; 1132 0 stevel break; 1133 0 stevel case 'T': 1134 0 stevel if (optarg) { 1135 0 stevel if (*optarg == 'u') 1136 9123 john timestamp_fmt = UDATE; 1137 0 stevel else if (*optarg == 'd') 1138 9123 john timestamp_fmt = DDATE; 1139 0 stevel else 1140 0 stevel errflg++; 1141 9123 john } else { 1142 0 stevel errflg++; 1143 9123 john } 1144 0 stevel break; 1145 0 stevel case 'r': 1146 0 stevel do_raw = 1; 1147 0 stevel break; 1148 0 stevel case 'l': 1149 0 stevel df.if_max_iodevs = safe_strtoi(optarg, "invalid limit"); 1150 0 stevel if (df.if_max_iodevs < 1) 1151 0 stevel usage(); 1152 0 stevel break; 1153 0 stevel case '?': 1154 0 stevel errflg++; 1155 0 stevel } 1156 0 stevel 1157 0 stevel if ((do_disk & DISK_OLD) && (do_disk & DISK_NEW)) { 1158 0 stevel (void) fprintf(stderr, "-d and -D are incompatible.\n"); 1159 0 stevel usage(); 1160 0 stevel } 1161 0 stevel 1162 0 stevel if (errflg) { 1163 0 stevel usage(); 1164 0 stevel } 1165 2907 cth 1166 0 stevel /* if no output classes explicity specified, use defaults */ 1167 0 stevel if (do_tty == 0 && do_disk == 0 && do_cpu == 0) 1168 0 stevel do_tty = do_cpu = 1, do_disk = DISK_OLD; 1169 2907 cth 1170 2907 cth /* 1171 2907 cth * multi-path options (-X, -Y) without a specific vertical 1172 2907 cth * output format (-x, -e, -E) imply extended -x format 1173 2907 cth */ 1174 2907 cth if ((do_disk & (DISK_IOPATH_LI | DISK_IOPATH_LTI)) && 1175 2907 cth !(do_disk & PRINT_VERTICAL)) 1176 2907 cth do_disk |= DISK_EXTENDED; 1177 0 stevel 1178 0 stevel /* 1179 0 stevel * If conflicting options take the preferred 1180 0 stevel * -D and -x result in -x 1181 0 stevel * -d or -D and -e or -E gives only whatever -d or -D was specified 1182 0 stevel */ 1183 0 stevel if ((do_disk & DISK_EXTENDED) && (do_disk & DISK_NORMAL)) 1184 0 stevel do_disk &= ~DISK_NORMAL; 1185 0 stevel if ((do_disk & DISK_NORMAL) && (do_disk & DISK_ERROR_MASK)) 1186 0 stevel do_disk &= ~DISK_ERROR_MASK; 1187 0 stevel 1188 0 stevel /* nfs, tape, always shown */ 1189 0 stevel df.if_allowed_types = IODEV_NFS | IODEV_TAPE; 1190 0 stevel 1191 0 stevel /* 1192 0 stevel * If limit == 0 then no command line limit was set, else if any of 1193 0 stevel * the flags that cause unlimited disks were not set, 1194 0 stevel * use the default of 4 1195 0 stevel */ 1196 0 stevel if (df.if_max_iodevs == 0) { 1197 0 stevel df.if_max_iodevs = DEFAULT_LIMIT; 1198 0 stevel df.if_skip_floppy = 1; 1199 0 stevel if (do_disk & (DISK_EXTENDED | DISK_ERRORS | 1200 0 stevel DISK_EXTENDED_ERRORS)) { 1201 0 stevel df.if_max_iodevs = UNLIMITED_IODEVS; 1202 0 stevel df.if_skip_floppy = 0; 1203 0 stevel } 1204 0 stevel } 1205 0 stevel if (do_disk) { 1206 0 stevel size_t count = 0; 1207 0 stevel size_t i = optind; 1208 0 stevel 1209 0 stevel while (i < argc && !isdigit(argv[i][0])) { 1210 0 stevel count++; 1211 0 stevel i++; 1212 0 stevel } 1213 0 stevel 1214 0 stevel /* 1215 0 stevel * "Note: disks explicitly requested 1216 0 stevel * are not subject to this disk limit" 1217 0 stevel */ 1218 2907 cth if ((count > df.if_max_iodevs) || 1219 2907 cth (count && (df.if_max_iodevs == UNLIMITED_IODEVS))) 1220 0 stevel df.if_max_iodevs = count; 1221 2907 cth 1222 0 stevel df.if_names = safe_alloc(count * sizeof (char *)); 1223 0 stevel (void) memset(df.if_names, 0, count * sizeof (char *)); 1224 0 stevel 1225 2907 cth df.if_nr_names = 0; 1226 0 stevel while (optind < argc && !isdigit(argv[optind][0])) 1227 0 stevel df.if_names[df.if_nr_names++] = argv[optind++]; 1228 0 stevel } 1229 0 stevel if (optind < argc) { 1230 0 stevel interval = safe_strtoi(argv[optind], "invalid interval"); 1231 0 stevel if (interval < 1) 1232 0 stevel fail(0, "invalid interval"); 1233 0 stevel optind++; 1234 0 stevel 1235 0 stevel if (optind < argc) { 1236 0 stevel iter = safe_strtoi(argv[optind], "invalid count"); 1237 0 stevel if (iter < 1) 1238 0 stevel fail(0, "invalid count"); 1239 0 stevel optind++; 1240 0 stevel } 1241 0 stevel } 1242 0 stevel if (interval == 0) 1243 0 stevel iter = 1; 1244 0 stevel if (optind < argc) 1245 0 stevel usage(); 1246 0 stevel } 1247 0 stevel 1248 0 stevel /* 1249 0 stevel * Driver for doing the extended header formatting. Will produce 1250 0 stevel * the function stack needed to output an extended header based 1251 0 stevel * on the options selected. 1252 0 stevel */ 1253 0 stevel 1254 0 stevel void 1255 0 stevel do_format(void) 1256 0 stevel { 1257 0 stevel char header[SMALL_SCRATCH_BUFLEN]; 1258 0 stevel char ch; 1259 0 stevel char iosz; 1260 0 stevel const char *fstr; 1261 0 stevel 1262 0 stevel disk_header[0] = 0; 1263 0 stevel ch = (do_interval ? 'i' : 's'); 1264 0 stevel iosz = (do_megabytes ? 'M' : 'k'); 1265 0 stevel if (do_disk & DISK_ERRORS) { 1266 0 stevel if (do_raw == 0) { 1267 0 stevel (void) sprintf(header, "s/w h/w trn tot "); 1268 0 stevel } else 1269 0 stevel (void) sprintf(header, "s/w,h/w,trn,tot"); 1270 0 stevel } else 1271 0 stevel *header = NULL; 1272 0 stevel switch (do_disk & DISK_IO_MASK) { 1273 0 stevel case DISK_OLD: 1274 0 stevel if (do_raw == 0) 1275 0 stevel fstr = "%cp%c tp%c serv "; 1276 0 stevel else 1277 0 stevel fstr = "%cp%c,tp%c,serv"; 1278 0 stevel (void) snprintf(disk_header, sizeof (disk_header), 1279 0 stevel fstr, iosz, ch, ch); 1280 0 stevel break; 1281 0 stevel case DISK_NEW: 1282 0 stevel if (do_raw == 0) 1283 0 stevel fstr = "rp%c wp%c util "; 1284 0 stevel else 1285 0 stevel fstr = "%rp%c,wp%c,util"; 1286 0 stevel (void) snprintf(disk_header, sizeof (disk_header), 1287 0 stevel fstr, ch, ch); 1288 0 stevel break; 1289 0 stevel case DISK_EXTENDED: 1290 2907 cth /* This is -x option */ 1291 0 stevel if (!do_conversions) { 1292 2907 cth /* without -n option */ 1293 2907 cth if (do_raw == 0) { 1294 2907 cth /* without -r option */ 1295 2907 cth (void) snprintf(disk_header, 1296 2907 cth sizeof (disk_header), 1297 2907 cth "%-*.*s r/%c w/%c " 1298 0 stevel "%cr/%c %cw/%c wait actv " 1299 2907 cth "svc_t %%%%w %%%%b %s", 1300 2907 cth iodevs_nl, iodevs_nl, "device", 1301 2907 cth ch, ch, iosz, ch, iosz, ch, header); 1302 2907 cth } else { 1303 2907 cth /* with -r option */ 1304 2907 cth (void) snprintf(disk_header, 1305 2907 cth sizeof (disk_header), 1306 2907 cth "device,r/%c,w/%c,%cr/%c,%cw/%c," 1307 2907 cth "wait,actv,svc_t,%%%%w," 1308 2907 cth "%%%%b,%s", 1309 2907 cth ch, ch, iosz, ch, iosz, ch, header); 1310 2907 cth } 1311 0 stevel } else { 1312 2907 cth /* with -n option */ 1313 0 stevel if (do_raw == 0) { 1314 0 stevel fstr = " r/%c w/%c %cr/%c " 1315 0 stevel "%cw/%c wait actv wsvc_t asvc_t " 1316 0 stevel "%%%%w %%%%b %sdevice"; 1317 0 stevel } else { 1318 0 stevel fstr = "r/%c,w/%c,%cr/%c,%cw/%c," 1319 0 stevel "wait,actv,wsvc_t,asvc_t," 1320 0 stevel "%%%%w,%%%%b,%sdevice"; 1321 0 stevel } 1322 0 stevel (void) snprintf(disk_header, 1323 0 stevel sizeof (disk_header), 1324 0 stevel fstr, ch, ch, iosz, ch, iosz, 1325 0 stevel ch, header); 1326 0 stevel } 1327 0 stevel break; 1328 0 stevel default: 1329 0 stevel break; 1330 0 stevel } 1331 2723 cth 1332 2723 cth /* do DISK_ERRORS header (already added above for DISK_EXTENDED) */ 1333 2723 cth if ((do_disk & DISK_ERRORS) && 1334 2723 cth ((do_disk & DISK_IO_MASK) != DISK_EXTENDED)) { 1335 0 stevel if (!do_conversions) { 1336 2907 cth if (do_raw == 0) 1337 2907 cth (void) snprintf(disk_header, 1338 2907 cth sizeof (disk_header), "%-*.*s %s", 1339 2907 cth iodevs_nl, iodevs_nl, "device", header); 1340 2907 cth else 1341 2907 cth (void) snprintf(disk_header, 1342 2907 cth sizeof (disk_header), "device,%s", header); 1343 0 stevel } else { 1344 0 stevel if (do_raw == 0) { 1345 0 stevel (void) snprintf(disk_header, 1346 0 stevel sizeof (disk_header), 1347 2723 cth " %sdevice", header); 1348 2723 cth } else { 1349 2723 cth (void) snprintf(disk_header, 1350 2723 cth sizeof (disk_header), 1351 2723 cth "%s,device", header); 1352 2723 cth } 1353 0 stevel } 1354 0 stevel } else { 1355 0 stevel /* 1356 0 stevel * Need to subtract two characters for the % escape in 1357 0 stevel * the string. 1358 0 stevel */ 1359 0 stevel dh_len = strlen(disk_header) - 2; 1360 0 stevel } 1361 0 stevel 1362 0 stevel /* 1363 0 stevel * -n *and* (-E *or* -e *or* -x) 1364 0 stevel */ 1365 0 stevel if (do_conversions && (do_disk & PRINT_VERTICAL)) { 1366 0 stevel if (do_tty) 1367 0 stevel setup(print_tty_hdr1); 1368 0 stevel if (do_cpu) 1369 0 stevel setup(print_cpu_hdr1); 1370 0 stevel if (do_tty || do_cpu) 1371 0 stevel setup(do_newline); 1372 0 stevel if (do_tty) 1373 0 stevel setup(print_tty_hdr2); 1374 0 stevel if (do_cpu) 1375 0 stevel setup(print_cpu_hdr2); 1376 0 stevel if (do_tty || do_cpu) 1377 0 stevel setup(do_newline); 1378 0 stevel if (do_tty) 1379 0 stevel setup(print_tty_data); 1380 0 stevel if (do_cpu) 1381 0 stevel setup(print_cpu_data); 1382 0 stevel if (do_tty || do_cpu) 1383 0 stevel setup(do_newline); 1384 0 stevel printxhdr(); 1385 0 stevel 1386 0 stevel setup(show_all_disks); 1387 0 stevel } else { 1388 0 stevel /* 1389 0 stevel * These unholy gymnastics are necessary to place CPU/tty 1390 0 stevel * data to the right of the disks/errors for the first 1391 0 stevel * line in vertical mode. 1392 0 stevel */ 1393 0 stevel if (do_disk & PRINT_VERTICAL) { 1394 0 stevel printxhdr(); 1395 0 stevel 1396 0 stevel setup(show_first_disk); 1397 0 stevel if (do_tty) 1398 0 stevel setup(print_tty_data); 1399 0 stevel if (do_cpu) 1400 0 stevel setup(print_cpu_data); 1401 0 stevel setup(do_newline); 1402 0 stevel 1403 0 stevel setup(show_other_disks); 1404 0 stevel } else { 1405 0 stevel setup(hdrout); 1406 0 stevel if (do_tty) 1407 0 stevel setup(print_tty_data); 1408 0 stevel setup(show_all_disks); 1409 0 stevel if (do_cpu) 1410 0 stevel setup(print_cpu_data); 1411 0 stevel } 1412 0 stevel 1413 0 stevel setup(do_newline); 1414 0 stevel } 1415 0 stevel if (do_disk & DISK_EXTENDED_ERRORS) 1416 0 stevel setup(disk_errors); 1417 0 stevel } 1418 0 stevel 1419 0 stevel /* 1420 0 stevel * Add a new function to the list of functions 1421 0 stevel * for this invocation. Once on the stack the 1422 0 stevel * function is never removed nor does its place 1423 0 stevel * change. 1424 0 stevel */ 1425 0 stevel void 1426 0 stevel setup(void (*nfunc)(void)) 1427 0 stevel { 1428 0 stevel format_t *tmp; 1429 0 stevel 1430 0 stevel tmp = safe_alloc(sizeof (format_t)); 1431 0 stevel tmp->nfunc = nfunc; 1432 0 stevel tmp->next = 0; 1433 0 stevel if (formatter_end) 1434 0 stevel formatter_end->next = tmp; 1435 0 stevel else 1436 0 stevel formatter_list = tmp; 1437 0 stevel formatter_end = tmp; 1438 0 stevel 1439 0 stevel } 1440 0 stevel 1441 0 stevel /* 1442 0 stevel * The functions after this comment are devoted to printing 1443 0 stevel * various parts of the header. They are selected based on the 1444 0 stevel * options provided when the program was invoked. The functions 1445 0 stevel * are either directly invoked in printhdr() or are indirectly 1446 0 stevel * invoked by being placed on the list of functions used when 1447 0 stevel * extended headers are used. 1448 0 stevel */ 1449 0 stevel void 1450 0 stevel print_tty_hdr1(void) 1451 0 stevel { 1452 0 stevel char *fstr; 1453 0 stevel char *dstr; 1454 0 stevel 1455 0 stevel if (do_raw == 0) { 1456 0 stevel fstr = "%10.10s"; 1457 0 stevel dstr = "tty "; 1458 0 stevel } else { 1459 0 stevel fstr = "%s"; 1460 0 stevel dstr = "tty"; 1461 0 stevel } 1462 0 stevel push_out(fstr, dstr); 1463 0 stevel } 1464 0 stevel 1465 0 stevel void 1466 0 stevel print_tty_hdr2(void) 1467 0 stevel { 1468 0 stevel if (do_raw == 0) 1469 0 stevel push_out("%-10.10s", " tin tout"); 1470 0 stevel else 1471 0 stevel push_out("tin,tout"); 1472 0 stevel } 1473 0 stevel 1474 0 stevel void 1475 0 stevel print_cpu_hdr1(void) 1476 0 stevel { 1477 0 stevel char *dstr; 1478 0 stevel 1479 0 stevel if (do_raw == 0) 1480 0 stevel dstr = " cpu"; 1481 0 stevel else 1482 0 stevel dstr = "cpu"; 1483 0 stevel push_out(dstr); 1484 0 stevel } 1485 0 stevel 1486 0 stevel void 1487 0 stevel print_cpu_hdr2(void) 1488 0 stevel { 1489 0 stevel char *dstr; 1490 0 stevel 1491 0 stevel if (do_raw == 0) 1492 0 stevel dstr = " us sy wt id"; 1493 0 stevel else 1494 0 stevel dstr = "us,sy,wt,id"; 1495 0 stevel push_out(dstr); 1496 0 stevel } 1497 0 stevel 1498 0 stevel /* 1499 0 stevel * Assumption is that tty data is always first - no need for raw mode leading 1500 0 stevel * comma. 1501 0 stevel */ 1502 0 stevel void 1503 0 stevel print_tty_data(void) 1504 0 stevel { 1505 0 stevel char *fstr; 1506 0 stevel uint64_t deltas; 1507 0 stevel double raw; 1508 0 stevel double outch; 1509 0 stevel kstat_t *oldks = NULL; 1510 0 stevel 1511 0 stevel if (oldss) 1512 0 stevel oldks = &oldss->s_sys.ss_agg_sys; 1513 0 stevel 1514 0 stevel if (do_raw == 0) 1515 0 stevel fstr = " %3.0f %4.0f "; 1516 0 stevel else 1517 0 stevel fstr = "%.0f,%.0f"; 1518 0 stevel deltas = kstat_delta(oldks, &newss->s_sys.ss_agg_sys, "rawch"); 1519 0 stevel raw = deltas; 1520 0 stevel raw /= getime; 1521 0 stevel deltas = kstat_delta(oldks, &newss->s_sys.ss_agg_sys, "outch"); 1522 0 stevel outch = deltas; 1523 0 stevel outch /= getime; 1524 0 stevel push_out(fstr, raw, outch); 1525 0 stevel } 1526 0 stevel 1527 0 stevel /* 1528 0 stevel * Write out CPU data 1529 0 stevel */ 1530 0 stevel void 1531 0 stevel print_cpu_data(void) 1532 0 stevel { 1533 0 stevel char *fstr; 1534 0 stevel uint64_t idle; 1535 0 stevel uint64_t user; 1536 0 stevel uint64_t kern; 1537 0 stevel uint64_t wait; 1538 0 stevel kstat_t *oldks = NULL; 1539 0 stevel 1540 0 stevel if (oldss) 1541 0 stevel oldks = &oldss->s_sys.ss_agg_sys; 1542 0 stevel 1543 0 stevel if (do_raw == 0) 1544 0 stevel fstr = " %2.0f %2.0f %2.0f %2.0f"; 1545 0 stevel else 1546 0 stevel fstr = "%.0f,%.0f,%.0f,%.0f"; 1547 0 stevel 1548 0 stevel idle = kstat_delta(oldks, &newss->s_sys.ss_agg_sys, "cpu_ticks_idle"); 1549 0 stevel user = kstat_delta(oldks, &newss->s_sys.ss_agg_sys, "cpu_ticks_user"); 1550 0 stevel kern = kstat_delta(oldks, &newss->s_sys.ss_agg_sys, "cpu_ticks_kernel"); 1551 0 stevel wait = kstat_delta(oldks, &newss->s_sys.ss_agg_sys, "cpu_ticks_wait"); 1552 0 stevel push_out(fstr, user * percent, kern * percent, 1553 5957 wroche wait * percent, idle * percent); 1554 0 stevel } 1555 0 stevel 1556 0 stevel /* 1557 0 stevel * Emit the appropriate header. 1558 0 stevel */ 1559 0 stevel void 1560 0 stevel hdrout(void) 1561 0 stevel { 1562 0 stevel if (do_raw == 0) { 1563 0 stevel if (--tohdr == 0) 1564 0 stevel printhdr(0); 1565 0 stevel } else if (hdr_out == 0) { 1566 0 stevel printhdr(0); 1567 0 stevel hdr_out = 1; 1568 0 stevel } 1569 0 stevel } 1570 0 stevel 1571 0 stevel /* 1572 0 stevel * Write out disk errors when -E is specified. 1573 0 stevel */ 1574 0 stevel void 1575 0 stevel disk_errors(void) 1576 0 stevel { 1577 0 stevel (void) snapshot_walk(SNAP_IODEVS, oldss, newss, show_disk_errors, NULL); 1578 0 stevel } 1579 0 stevel 1580 0 stevel void 1581 0 stevel show_first_disk(void) 1582 0 stevel { 1583 0 stevel int count = 0; 1584 0 stevel 1585 0 stevel show_disk_mode = SHOW_FIRST_ONLY; 1586 0 stevel 1587 0 stevel (void) snapshot_walk(SNAP_IODEVS, oldss, newss, show_disk, &count); 1588 0 stevel } 1589 0 stevel 1590 0 stevel void 1591 0 stevel show_other_disks(void) 1592 0 stevel { 1593 0 stevel int count = 0; 1594 0 stevel 1595 0 stevel show_disk_mode = SHOW_SECOND_ONWARDS; 1596 0 stevel 1597 0 stevel (void) snapshot_walk(SNAP_IODEVS, oldss, newss, show_disk, &count); 1598 0 stevel } 1599 0 stevel 1600 0 stevel void 1601 0 stevel show_all_disks(void) 1602 0 stevel { 1603 0 stevel int count = 0; 1604 0 stevel 1605 0 stevel show_disk_mode = SHOW_ALL; 1606 0 stevel 1607 0 stevel (void) snapshot_walk(SNAP_IODEVS, oldss, newss, show_disk, &count); 1608 0 stevel } 1609 0 stevel 1610 0 stevel /* 1611 0 stevel * Write a newline out and clear the lineout flag. 1612 0 stevel */ 1613 0 stevel static void 1614 0 stevel do_newline(void) 1615 0 stevel { 1616 0 stevel if (lineout) { 1617 0 stevel (void) putchar('\n'); 1618 0 stevel lineout = 0; 1619 0 stevel } 1620 0 stevel } 1621 0 stevel 1622 0 stevel /* 1623 0 stevel * Generalized printf function that determines what extra 1624 0 stevel * to print out if we're in raw mode. At this time we 1625 0 stevel * don't care about errors. 1626 0 stevel */ 1627 0 stevel static void 1628 0 stevel push_out(const char *message, ...) 1629 0 stevel { 1630 0 stevel va_list args; 1631 0 stevel 1632 0 stevel va_start(args, message); 1633 0 stevel if (do_raw && lineout == 1) 1634 0 stevel (void) putchar(','); 1635 0 stevel (void) vprintf(message, args); 1636 0 stevel va_end(args); 1637 0 stevel lineout = 1; 1638 0 stevel } 1639 0 stevel 1640 0 stevel /* 1641 0 stevel * Emit the header string when -e is specified. 1642 0 stevel */ 1643 0 stevel static void 1644 0 stevel print_err_hdr(void) 1645 0 stevel { 1646 0 stevel char obuf[SMALL_SCRATCH_BUFLEN]; 1647 0 stevel 1648 2723 cth if (do_raw) { 1649 2723 cth push_out("errors"); 1650 2723 cth return; 1651 2723 cth } 1652 2723 cth 1653 0 stevel if (do_conversions == 0) { 1654 0 stevel if (!(do_disk & DISK_EXTENDED)) { 1655 0 stevel (void) snprintf(obuf, sizeof (obuf), 1656 0 stevel "%11s", one_blank); 1657 0 stevel push_out(obuf); 1658 0 stevel } 1659 0 stevel } else if (do_disk == DISK_ERRORS) 1660 0 stevel push_out(two_blanks); 1661 0 stevel else 1662 0 stevel push_out(one_blank); 1663 0 stevel push_out("---- errors --- "); 1664 0 stevel } 1665 0 stevel 1666 0 stevel /* 1667 0 stevel * Emit the header string when -e is specified. 1668 0 stevel */ 1669 0 stevel static void 1670 0 stevel print_disk_header(void) 1671 0 stevel { 1672 0 stevel push_out(disk_header); 1673 0 stevel } 1674 0 stevel 1675 0 stevel /* 1676 0 stevel * No, UINTMAX_MAX isn't the right thing here since 1677 0 stevel * it is #defined to be either INT32_MAX or INT64_MAX 1678 0 stevel * depending on the whether _LP64 is defined. 1679 0 stevel * 1680 0 stevel * We want to handle the odd future case of having 1681 0 stevel * ulonglong_t be more than 64 bits but we have 1682 0 stevel * no nice #define MAX value we can drop in place 1683 0 stevel * without having to change this code in the future. 1684 0 stevel */ 1685 0 stevel 1686 0 stevel u_longlong_t 1687 0 stevel ull_delta(u_longlong_t old, u_longlong_t new) 1688 0 stevel { 1689 0 stevel if (new >= old) 1690 0 stevel return (new - old); 1691 0 stevel else 1692 0 stevel return ((UINT64_MAX - old) + new + 1); 1693 0 stevel } 1694 0 stevel 1695 0 stevel /* 1696 0 stevel * Take the difference of an unsigned 32 1697 0 stevel * bit int attempting to cater for 1698 0 stevel * overflow. 1699 0 stevel */ 1700 0 stevel uint_t 1701 0 stevel u32_delta(uint_t old, uint_t new) 1702 0 stevel { 1703 0 stevel if (new >= old) 1704 0 stevel return (new - old); 1705 0 stevel else 1706 0 stevel return ((UINT32_MAX - old) + new + 1); 1707 0 stevel } 1708 0 stevel 1709 0 stevel /* 1710 0 stevel * This is exactly what is needed for standard iostat output, 1711 0 stevel * but make sure to use it only for that 1712 0 stevel */ 1713 0 stevel #define EPSILON (0.1) 1714 0 stevel static int 1715 0 stevel fzero(double value) 1716 0 stevel { 1717 0 stevel return (value >= 0.0 && value < EPSILON); 1718 0 stevel } 1719 0 stevel 1720 0 stevel static int 1721 0 stevel safe_strtoi(char const *val, char *errmsg) 1722 0 stevel { 1723 0 stevel char *end; 1724 0 stevel long tmp; 1725 0 stevel 1726 0 stevel errno = 0; 1727 0 stevel tmp = strtol(val, &end, 10); 1728 0 stevel if (*end != '\0' || errno) 1729 0 stevel fail(0, "%s %s", errmsg, val); 1730 0 stevel return ((int)tmp); 1731 0 stevel } 1732