1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * poolstat - report active pool statistics 31 */ 32 #include <stdio.h> 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <locale.h> 37 #include <string.h> 38 #include <ctype.h> 39 #include <limits.h> 40 #include <errno.h> 41 42 #include <pool.h> 43 #include "utils.h" 44 #include "poolstat.h" 45 #include "poolstat_utils.h" 46 47 #ifndef TEXT_DOMAIN 48 #define TEXT_DOMAIN "SYS_TEST" 49 #endif 50 51 /* calculate offset of a particular element in a structure */ 52 #define offsetof(s, m) ((size_t)(&(((s *)0)->m))) 53 #define addrof(s) ((char **)&(s)) 54 55 /* verify if a field is printable in respect of the current option flags */ 56 #define PRINTABLE(i) ((lf->plf_ffs[(i)].pff_prt & D_FIELD) || \ 57 (lf->plf_ffs[(i)].pff_prt & X_FIELD)) 58 59 typedef int (* formatter) (char *, int, int, poolstat_field_format_t *, char *); 60 61 /* available field formatters */ 62 static int default_f(char *, int, int, poolstat_field_format_t *, char *); 63 static int bigno_f(char *, int, int, poolstat_field_format_t *, char *); 64 static int used_stat_f(char *, int, int, poolstat_field_format_t *, char *); 65 static int header_f(char *, int, int, poolstat_field_format_t *, char *); 66 67 /* statistics bags used to collect data from various provider */ 68 static statistic_bag_t pool_sbag_s; 69 static statistic_bag_t pset_sbag_s; 70 static statistic_bag_t *pool_sbag = &pool_sbag_s; 71 static statistic_bag_t *pset_sbag = &pset_sbag_s; 72 73 /* formatter objects for pset, defined in a default printing sequence */ 74 static poolstat_field_format_t pset_ffs[] = { 75 /* prt flags,name,header,type,width,minwidth,offset,formatter */ 76 { DX_FIELD, "id", "id", LL, 3, 1, addrof(pool_sbag), 77 offsetof(statistic_bag_t, sb_sysid), 78 (formatter)default_f }, 79 { DX_FIELD, "pool", "pool", STR, 20, 14, addrof(pool_sbag), 80 offsetof(statistic_bag_t, sb_name), 81 (formatter)default_f }, 82 { DX_FIELD, "type", "type", STR, 4, 5, addrof(pset_sbag), 83 offsetof(statistic_bag_t, sb_type), 84 (formatter)default_f }, 85 { D_FIELD, "rid", "rid", LL, 3, 1, addrof(pset_sbag_s.bag), 86 offsetof(pset_statistic_bag_t, pset_sb_sysid), 87 (formatter)default_f }, 88 { DX_FIELD, "rset", "rset", STR, 20, 14, addrof(pset_sbag), 89 offsetof(statistic_bag_t, sb_name), 90 (formatter)default_f }, 91 { DX_FIELD, "min", "min", ULL, 4, 1, addrof(pset_sbag_s.bag), 92 offsetof(pset_statistic_bag_t, pset_sb_min), 93 (formatter)bigno_f }, 94 { DX_FIELD, "max", "max", ULL, 4, 1, addrof(pset_sbag_s.bag), 95 offsetof(pset_statistic_bag_t, pset_sb_max), 96 (formatter)bigno_f }, 97 { DX_FIELD, "size", "size", ULL, 4, 1, addrof(pset_sbag_s.bag), 98 offsetof(pset_statistic_bag_t, pset_sb_size), 99 (formatter)default_f }, 100 { DX_FIELD, "used", "used", FL, 4, -1, addrof(pset_sbag_s.bag), 101 offsetof(pset_statistic_bag_t, pset_sb_used), 102 (formatter)used_stat_f }, 103 { DX_FIELD, "load", "load", FL, 4, -1, addrof(pset_sbag_s.bag), 104 offsetof(pset_statistic_bag_t, pset_sb_load), 105 (formatter)default_f } 106 }; 107 108 /* formatter objects for pool, defined in a default printing sequence */ 109 static poolstat_field_format_t pool_ffs[] = { 110 /* prt flags,name,header,type,width,minwidth,offset,formatter */ 111 { D_FIELD, "id", "id", LL, 3, 1, addrof(pool_sbag), 112 offsetof(statistic_bag_t, sb_sysid), 113 (formatter)default_f }, 114 { D_FIELD, "pool", "pool", STR, 20, 13, addrof(pool_sbag), 115 offsetof(statistic_bag_t, sb_name), 116 (formatter)default_f }, 117 { D_FIELD, "p_size", "size", ULL, 4, 1, addrof(pset_sbag_s.bag), 118 offsetof(pset_statistic_bag_t, pset_sb_size), 119 (formatter)default_f }, 120 { D_FIELD, "p_used", "used", FL, 4, -1, addrof(pset_sbag_s.bag), 121 offsetof(pset_statistic_bag_t, pset_sb_used), 122 (formatter)default_f }, 123 { D_FIELD, "p_load", "load", FL, 4, -1, addrof(pset_sbag_s.bag), 124 offsetof(pset_statistic_bag_t, pset_sb_load), 125 (formatter)default_f }, 126 }; 127 128 /* lists with formatter objects, one for each statistics field */ 129 static poolstat_line_format_t pool_lf; /* formatting list in default mode */ 130 static poolstat_line_format_t pset_lf; /* formatting list for psets */ 131 132 /* name of pools to be shown */ 133 static poolstat_list_element_t *pnames; 134 /* 135 * type of resources to be shown, currently we only have one type 'pset' 136 * but, poolstat can be extended to handle new upcoming resource types. 137 */ 138 static poolstat_list_element_t *rtypes; 139 140 /* a handle to the pool configuration */ 141 static pool_conf_t *conf; 142 143 /* option flags */ 144 static int rflag; 145 static int pflag; 146 static int oflag; 147 148 /* operands */ 149 static int interval = 0; /* update interval */ 150 static long count = 1; /* one run */ 151 152 /* data structure handlers */ 153 static poolstat_list_element_t * 154 create_prt_sequence_list(char *, poolstat_line_format_t *); 155 static poolstat_list_element_t * 156 create_args_list(char *, poolstat_list_element_t *, const char *); 157 158 /* statistics update function */ 159 static void sa_update(statistic_bag_t *, int); 160 161 /* statistics printing function */ 162 static void prt_pool_stats(poolstat_list_element_t *); 163 164 static void 165 usage(void) 166 { 167 (void) fprintf(stderr, gettext( 168 "Usage:\n" 169 "poolstat [-p pool-list] [-r rset-list] [interval [count]]\n" 170 "poolstat [-p pool-list] [-o format -r rset-list] [interval [count]]\n" 171 " \'pool-list\' is a space-separated list of pool IDs or names\n" 172 " \'rset-list\' is \'all\' or \'pset\'\n" 173 " \'format\' for all resource types is one or more of:\n" 174 "\tid pool type rid rset min max size used load\n")); 175 (void) exit(E_USAGE); 176 } 177 178 static int 179 Atoi(char *p, int *errp) 180 { 181 int i; 182 char *q; 183 errno = 0; 184 i = strtol(p, &q, 10); 185 if (errno != 0 || q == p || *q != '\0') 186 *errp = -1; 187 else 188 *errp = 0; 189 return (i); 190 } 191 192 int 193 main(int argc, char *argv[]) 194 { 195 char c; 196 int error = 0; 197 198 (void) getpname(argv[0]); 199 (void) setlocale(LC_ALL, ""); 200 (void) textdomain(TEXT_DOMAIN); 201 202 /* pset_sbag_s is used to collect pset statistics */ 203 pset_sbag_s.sb_type = PSET_TYPE_NAME; 204 pset_sbag_s.bag = ZALLOC(sizeof (pset_statistic_bag_t)); 205 pool_sbag_s.sb_type = POOL_TYPE_NAME; 206 207 pset_lf.plf_ffs = pset_ffs; 208 pset_lf.plf_ff_len = sizeof (pset_ffs) / 209 sizeof (poolstat_field_format_t); 210 pool_lf.plf_ffs = pool_ffs; 211 pool_lf.plf_ff_len = sizeof (pool_ffs) / 212 sizeof (poolstat_field_format_t); 213 214 while ((c = getopt(argc, argv, ":p:r:o:")) != EOF) { 215 switch (c) { 216 case 'p': /* pool name specification */ 217 pflag++; 218 pnames = create_args_list(optarg, pnames, 219 " \t"); 220 break; 221 case 'r': { /* resource type */ 222 rflag++; 223 rtypes = create_args_list(optarg, rtypes, 224 " \t,"); 225 break; 226 } 227 case 'o': { /* format specification */ 228 oflag++; 229 if (create_prt_sequence_list(optarg, &pset_lf) == NULL) 230 usage(); 231 break; 232 } 233 case ':': { 234 (void) fprintf(stderr, 235 gettext(ERR_OPTION_ARGS), optopt); 236 usage(); 237 /*NOTREACHED*/ 238 } 239 default: 240 (void) fprintf(stderr, gettext(ERR_OPTION), optopt); 241 usage(); 242 /*NOTREACHED*/ 243 } 244 } 245 246 /* get operands */ 247 if (argc > optind) { 248 if ((interval = Atoi(argv[optind++], &error)) < 1 || error != 0) 249 usage(); 250 count = -1; 251 } 252 if (argc > optind) { 253 if ((count = Atoi(argv[optind++], &error)) < 1 || error != 0) 254 usage(); 255 } 256 /* check for extra options/operands */ 257 if (argc > optind) 258 usage(); 259 260 /* check options */ 261 if (oflag && !rflag) 262 usage(); 263 264 /* global initializations */ 265 if (!oflag) { 266 /* create the default print sequences */ 267 (void) create_prt_sequence_list(NULL, &pool_lf); 268 (void) create_prt_sequence_list(NULL, &pset_lf); 269 } 270 271 if (rtypes == NULL || strcmp(rtypes->ple_obj, "all") == 0) { 272 /* crate a default resource list */ 273 FREE(rtypes); 274 rtypes = create_args_list("pset", NULL, " \t,"); 275 } 276 277 if ((conf = pool_conf_alloc()) == NULL) 278 die(gettext(ERR_NOMEM)); 279 if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) 280 != PO_SUCCESS) 281 die(gettext(ERR_OPEN_DYNAMIC), get_errstr()); 282 283 /* initialize statistic adapters */ 284 sa_libpool_init(conf); 285 sa_kstat_init(NULL); 286 287 /* collect and print out statistics */ 288 while (count-- != 0) { 289 sa_update(pool_sbag, SA_REFRESH); 290 if (pool_sbag->sb_changed & POU_POOL) 291 (void) printf( 292 "<<State change>>\n"); 293 prt_pool_stats(pnames); 294 if (count != 0) { 295 (void) sleep(interval); 296 if (rflag) 297 (void) printf("\n"); 298 } 299 } 300 301 return (E_PO_SUCCESS); 302 } 303 304 /* 305 * Take the arguments and create/append a string list to the 'le' list. 306 */ 307 static poolstat_list_element_t * 308 create_args_list(char *arg, poolstat_list_element_t *le, const char *delim) 309 { 310 poolstat_list_element_t *head = le; 311 312 while (arg != NULL && *arg != '\0') { 313 char *name = arg; 314 arg = strpbrk(arg, delim); 315 if (arg != NULL) { 316 *arg++ = '\0'; 317 } 318 if (le == NULL) { 319 /* create first element */ 320 NEW0(le); 321 head = le; 322 } else { 323 /* find last and append */ 324 while (le->ple_next != NULL) 325 le = le->ple_next; 326 NEW0(le->ple_next); 327 le = le->ple_next; 328 } 329 le->ple_obj = (void *)name; 330 } 331 332 return (head); 333 } 334 335 /* 336 * Take the arguments to the -o option, and create a format field list in order 337 * specified by 'arg'. 338 * If 'arg' is NULL a list in a default printing order is created. 339 */ 340 static poolstat_list_element_t * 341 create_prt_sequence_list(char *arg, poolstat_line_format_t *lf) 342 { 343 /* 344 * Create a default print sequence. It is the sequence defined 345 * statically in the format list. At the same time mark the fields 346 * printable according to the current option settings. 347 */ 348 if (arg == NULL) { 349 int i; 350 NEW0(lf->plf_prt_seq); 351 lf->plf_ffs[0].pff_prt |= PRINTABLE(0) ? PABLE_FIELD : 0; 352 lf->plf_last = lf->plf_prt_seq; 353 lf->plf_last->ple_obj = &(lf->plf_ffs[0]); 354 for (i = 1; i < lf->plf_ff_len; i++) { 355 lf->plf_ffs[i].pff_prt |= 356 PRINTABLE(i) ? PABLE_FIELD : 0; 357 NEW0(lf->plf_last->ple_next); 358 lf->plf_last = lf->plf_last->ple_next; 359 lf->plf_last->ple_obj = &(lf->plf_ffs[i]); 360 } 361 return (lf->plf_prt_seq); 362 } 363 364 while (arg != NULL && *arg != '\0') { 365 poolstat_field_format_t *ff; /* current format field */ 366 int ffIdx; /* format field index */ 367 char *name; /* name of field */ 368 int n; /* no. of chars to strip */ 369 370 n = strspn(arg, " ,\t\r\v\f\n"); 371 arg += n; /* strip multiples separator */ 372 name = arg; 373 374 if (strlen(name) < 1) 375 break; 376 377 if ((arg = strpbrk(arg, " ,\t\r\v\f\n")) != NULL) 378 *arg++ = '\0'; 379 380 /* search for a named format field */ 381 for (ffIdx = 0; ffIdx < lf->plf_ff_len; ffIdx++) { 382 ff = lf->plf_ffs + ffIdx; 383 if (strcmp(ff->pff_name, name) == 0) { 384 ff->pff_prt |= PABLE_FIELD; 385 break; 386 } 387 } 388 /* if the name wasn't found */ 389 if (ffIdx == lf->plf_ff_len) { 390 (void) fprintf(stderr, gettext(ERR_UNSUPP_STAT_FIELD), 391 name); 392 usage(); 393 } 394 if (lf->plf_last == NULL) { 395 /* create first print handle */ 396 NEW0(lf->plf_prt_seq); 397 lf->plf_last = lf->plf_prt_seq; 398 } else { 399 NEW0(lf->plf_last->ple_next); 400 lf->plf_last = lf->plf_last->ple_next; 401 } 402 lf->plf_last->ple_obj = ff; /* refer to the format field */ 403 } 404 405 return (lf->plf_prt_seq); 406 } 407 408 /* update the statistic data by adapters */ 409 static void 410 sa_update(statistic_bag_t *sbag, int flags) 411 { 412 sa_libpool_update(sbag, flags); 413 sa_kstat_update(sbag, flags); 414 } 415 416 /* 417 * Format one statistic field and put it into the 'str' buffer. 'ff' contains 418 * the field formatting parameters. Return the number of used bytes. 419 */ 420 static int 421 default_f(char *str, int pos, int left, poolstat_field_format_t *ff, char *data) 422 { 423 int used; 424 425 switch (ff->pff_type) { 426 case LL: { 427 int64_t v; 428 v = *((int64_t *)(void *)(data + ff->pff_offset)); 429 used = snprintf(str + pos, left, "%*.*lld", 430 ff->pff_width, ff->pff_minwidth, v); 431 } 432 break; 433 case ULL: { 434 uint64_t v; 435 v = *((uint64_t *)(void *)(data + ff->pff_offset)); 436 used = snprintf(str + pos, left, "%*.*llu", 437 ff->pff_width, ff->pff_minwidth, v); 438 }; 439 break; 440 case FL: { 441 int pw = 0; 442 double v = *((double *)(void *)(data + ff->pff_offset)); 443 if (v < 10) { 444 pw = ff->pff_width - 2; 445 } else if (v < 100) { 446 pw = ff->pff_width - 3; 447 } else if (v < 1000) { 448 pw = ff->pff_width - 4; 449 } 450 if (pw < 0) 451 pw = 0; 452 used = snprintf(str + pos, left, "%*.*f", 453 ff->pff_width, pw, v); 454 }; 455 break; 456 case STR: { 457 char *v; 458 int sl; 459 v = *((char **)(void *)(data + ff->pff_offset)); 460 sl = strlen(v); 461 /* truncate if it doesn't fit */ 462 if (sl > ff->pff_width) { 463 char *cp = v + ff->pff_width - 1; 464 if (ff->pff_width < 4) 465 die(gettext(ERR_STATS_FORMAT), 466 ff->pff_header); 467 *cp-- = 0; 468 *cp-- = '.'; 469 *cp-- = '.'; 470 *cp-- = '.'; 471 } 472 used = snprintf(str + pos, left, "%-*s", ff->pff_width, 473 v); 474 } 475 break; 476 } 477 478 return (used); 479 } 480 481 /* format big numbers */ 482 static int 483 bigno_f(char *str, int pos, int left, poolstat_field_format_t *ff, char *data) 484 { 485 uint64_t v; 486 char tag; 487 int pw = ff->pff_width - 4; 488 double pv; 489 int used; 490 491 v = *((uint64_t *)(void *)(data + ff->pff_offset)); 492 /* 493 * the max value can be ULONG_MAX, which is formatted as: 494 * E P T G M K 495 * 18 446 744 073 709 551 615 496 * As a result ULONG_MAX is displayed as 18E 497 */ 498 pv = v; 499 if (v < 1000) { 500 pw = 0; 501 } else if (v < KILO * 10) { 502 pv = (double)v / KILO; 503 tag = 'K'; 504 } else if (v < KILO * 100) { 505 pv = (double)v / KILO; 506 tag = 'K'; pw -= 1; 507 } else if (v < KILO * 1000) { 508 pv = (double)v / KILO; 509 tag = 'K'; pw -= 2; 510 } else if (v < MEGA * 10) { 511 pv = (double)v / MEGA; 512 tag = 'M'; 513 } else if (v < MEGA * 100) { 514 pv = (double)v / MEGA; 515 tag = 'M'; pw -= 1; 516 } else if (v < MEGA * 1000) { 517 pv = (double)v / MEGA; 518 tag = 'M'; pw -= 2; 519 } else if (v < GIGA * 10) { 520 pv = (double)v / GIGA; 521 tag = 'G'; 522 } else if (v < GIGA * 100) { 523 pv = (double)v / GIGA; 524 tag = 'G'; pw -= 1; 525 } else if (v < GIGA * 1000) { 526 pv = (double)v / GIGA; 527 tag = 'G'; pw -= 2; 528 } else if (v < TERA * 10) { 529 pv = (double)v / TERA; 530 tag = 'T'; 531 } else if (v < TERA * 100) { 532 pv = (double)v / TERA; 533 tag = 'T'; pw -= 1; 534 } else if (v < TERA * 1000) { 535 pv = (double)v / TERA; 536 tag = 'T'; pw -= 2; 537 } else if (v < PETA * 10) { 538 pv = (double)v / PETA; 539 tag = 'P'; 540 } else if (v < PETA * 100) { 541 pv = (double)v / PETA; 542 tag = 'P'; pw -= 1; 543 } else if (v < PETA * 1000) { 544 pv = (double)v / PETA; 545 tag = 'P'; pw -= 2; 546 } else if (v < EXA * 10) { 547 pv = (double)v / EXA; 548 tag = 'E'; 549 } else if (v < EXA * 100) { 550 pv = (double)v / EXA; 551 tag = 'E'; pw -= 1; 552 } else { 553 pv = (double)v / EXA; 554 tag = 'E'; pw -= 2; 555 } 556 if (pw < 0) 557 pw = 0; 558 if (v < 1000) 559 used = snprintf(str + pos, left, "%*.*f", 560 ff->pff_width, pw, pv); 561 else 562 used = snprintf(str + pos, left, "%*.*f%c", 563 ff->pff_width - 1, pw, pv, tag); 564 565 return (used); 566 } 567 568 /* format usage statistic, if configuration has changed print '-'. */ 569 static int 570 used_stat_f(char *str, int pos, int left, poolstat_field_format_t *ff, 571 char *data) 572 { 573 int pw = 0; 574 double v = *((double *)(void *)(data + ff->pff_offset)); 575 int used; 576 577 if (pool_sbag->sb_changed & POU_POOL) { 578 used = snprintf(str + pos, left, "%*c", ff->pff_width, '-'); 579 } else { 580 if (v < 10) { 581 pw = ff->pff_width - 2; 582 } else if (v < 100) { 583 pw = ff->pff_width - 3; 584 } else if (v < 1000) { 585 pw = ff->pff_width - 4; 586 } 587 if (pw < 0) 588 pw = 0; 589 used = snprintf(str + pos, left, "%*.*f", 590 ff->pff_width, pw, v); 591 } 592 return (used); 593 } 594 595 /* 596 * Format one header field and put it into the 'str' buffer. 597 */ 598 /*ARGSUSED*/ 599 static int 600 header_f(char *str, int pos, int left, poolstat_field_format_t *ff, char *data) 601 { 602 int used = 0; 603 604 if (ff->pff_type == STR) 605 /* strings are left justified */ 606 used = snprintf(str + pos, left, "%-*s", 607 ff->pff_width, ff->pff_header); 608 else 609 used = snprintf(str + pos, left, "%*s", 610 ff->pff_width, ff->pff_header); 611 return (used); 612 } 613 614 /* 615 * Print one statistic line according to the definitions in 'lf'. 616 */ 617 static void 618 prt_stat_line(poolstat_line_format_t *lf) 619 { 620 poolstat_list_element_t *le; /* list element in the print sequence */ 621 char *line; 622 int pos = 0; /* position in the printed line */ 623 int len = MAXLINE; /* the length of the line */ 624 int left = len; /* chars left to use in the line */ 625 626 line = ZALLOC(len); 627 for (le = lf->plf_prt_seq; le; le = le->ple_next) { 628 int used; 629 poolstat_field_format_t *ff = 630 (poolstat_field_format_t *)le->ple_obj; 631 /* if the filed is marked to be printed */ 632 if (ff->pff_prt & PABLE_FIELD) { 633 if (((used = ff->pff_format(line, pos, left, ff, 634 *ff->pff_data_ptr)) + 1) >= left) { 635 /* if field doesn't fit allocate new space */ 636 len += used + MAXLINE; 637 left += used + MAXLINE; 638 line = REALLOC(line, len); 639 if (((used = ff->pff_format(line, pos, left, ff, 640 *ff->pff_data_ptr)) + 1) >= left) 641 die(gettext(ERR_STATS_FORMAT), line); 642 } 643 left -= used; 644 pos += used; 645 if (le->ple_next != NULL) { 646 /* separate columns with a space */ 647 line[pos++] = ' '; 648 left--; 649 } 650 } 651 } 652 653 (void) printf("%s\n", line); 654 FREE(line); 655 } 656 657 /* 658 * Print a statistics header line for a given resource type. 659 */ 660 static void 661 prt_stat_hd(const char *type) 662 { 663 poolstat_line_format_t *lf; /* line format */ 664 poolstat_list_element_t *le; /* list element in the print sequence */ 665 char *line; 666 int pos = 0; /* position in the printed line */ 667 int len = MAXLINE; /* the length of the line */ 668 int left = len; /* chars left to use in the line */ 669 670 if (strcmp(type, POOL_TYPE_NAME) == 0) { 671 /* pool format needs an extra header */ 672 (void) printf("%*s\n", 19 + 15, "pset"); 673 lf = &pool_lf; 674 } else if (strcmp(type, PSET_TYPE_NAME) == 0) { 675 lf = &pset_lf; 676 } else { 677 die(gettext(ERR_UNSUPP_RTYPE), type); 678 } 679 line = ZALLOC(len); 680 for (le = lf->plf_prt_seq; le; le = le->ple_next) { 681 int used; /* used chars in line */ 682 poolstat_field_format_t *ff = 683 (poolstat_field_format_t *)le->ple_obj; 684 /* if the filed is marked to be printed */ 685 if (ff->pff_prt& PABLE_FIELD) { 686 if (((used = header_f(line, pos, left, ff, NULL)) + 1) 687 >= left) { 688 /* if field doesn't fit allocate new space */ 689 len += used + MAXLINE; 690 left += used + MAXLINE; 691 line = REALLOC(line, len); 692 if (((used = header_f(line, pos, left, ff, 693 NULL)) + 1) >= left) 694 die(gettext(ERR_STATS_FORMAT), line); 695 } 696 left -= used; 697 pos += used; 698 if (le->ple_next != NULL) { 699 /* separate columns with a space */ 700 line[pos++] = ' '; 701 left--; 702 } 703 } 704 } 705 706 /* only header line with non space characters should be printed */ 707 pos = 0; 708 while (*(line + pos) != '\n') { 709 if (!isspace(*(line + pos))) { 710 (void) printf("%s\n", line); 711 712 break; 713 } 714 pos++; 715 } 716 FREE(line); 717 } 718 719 /* 720 * Create a pool value instance and set its name to 'name'. 721 */ 722 static pool_value_t * 723 create_pool_value(const char *name) 724 { 725 pool_value_t *pval; 726 727 if ((pval = pool_value_alloc()) == NULL) { 728 return (NULL); 729 } 730 if (pool_value_set_name(pval, name) != PO_SUCCESS) { 731 pool_value_free(pval); 732 return (NULL); 733 } 734 735 return (pval); 736 } 737 738 /* 739 * Find all resources of type 'rtype'. 740 * If 'pool_name' is defined find all resources bound to this pool. 741 */ 742 static pool_resource_t ** 743 get_resources(const char *pool_name, const char *rtype, uint_t *nelem) 744 { 745 pool_resource_t **resources = NULL; 746 pool_value_t *pvals[] = { NULL, NULL, NULL}; 747 pool_value_t *pv_sys_id; 748 pool_value_t *pv_name; 749 char *name_prop; /* set name property */ 750 751 if (strcmp(rtype, PSET_TYPE_NAME) == 0) { 752 if ((pv_sys_id = create_pool_value(PSET_SYSID)) == NULL) 753 goto on_error; 754 name_prop = PSET_NAME; 755 } else { 756 die(gettext(ERR_UNSUPP_RTYPE), rtype); 757 } 758 759 if ((pvals[0] = create_pool_value("type")) == NULL) 760 goto on_error; 761 if ((pool_value_set_string(pvals[0], rtype)) == -1) 762 goto on_error; 763 764 if ((pv_name = create_pool_value(name_prop)) == NULL) 765 goto on_error; 766 767 if (pool_name != NULL) { 768 /* collect resources associated to 'pool_name' */ 769 pool_t *pool; 770 if ((pool = pool_get_pool(conf, pool_name)) == NULL) 771 die(gettext(ERR_STATS_POOL_N), pool_name); 772 if ((resources = pool_query_pool_resources( 773 conf, pool, nelem, pvals)) == NULL) 774 goto on_error; 775 } else { 776 /* collect all resources */ 777 if ((resources = 778 pool_query_resources(conf, nelem, pvals)) == NULL) 779 goto on_error; 780 } 781 782 if (pv_name != NULL) 783 pool_value_free(pv_name); 784 if (pv_sys_id != NULL) 785 pool_value_free(pv_sys_id); 786 if (pvals[0] != NULL) 787 pool_value_free(pvals[0]); 788 789 return (resources); 790 on_error: 791 die(gettext(ERR_STATS_RES), get_errstr()); 792 /*NOTREACHED*/ 793 } 794 795 /* 796 * Print statistics for all resources of type 'rtype' passed in 'resources'. 797 */ 798 static void 799 prt_resource_stats_by_type(pool_resource_t **resources, const char *rtype) 800 { 801 int i; 802 pool_elem_t *elem; 803 pool_value_t *pv_name; 804 char *name_prop; 805 806 poolstat_line_format_t *lf; 807 statistic_bag_t *sbag; 808 809 if (strcmp(rtype, PSET_TYPE_NAME) == 0) { 810 name_prop = PSET_NAME; 811 lf = &pset_lf; 812 sbag = pset_sbag; 813 } else { 814 die(gettext(ERR_UNSUPP_RTYPE), rtype); 815 } 816 817 if ((pv_name = create_pool_value(name_prop)) == NULL) 818 goto on_error; 819 820 /* collect and print statistics for the given resources */ 821 for (i = 0; resources[i] != NULL; i++) { 822 if ((elem = pool_resource_to_elem(conf, resources[i])) == NULL) 823 goto on_error; 824 if (pool_get_property(conf, elem, name_prop, pv_name) == -1) 825 goto on_error; 826 if (pool_value_get_string(pv_name, &sbag->sb_name) == -1) 827 goto on_error; 828 sa_update(sbag, 0); 829 830 prt_stat_line(lf); 831 } 832 833 if (pv_name != NULL) 834 pool_value_free(pv_name); 835 return; 836 on_error: 837 die(gettext(ERR_STATS_RES), get_errstr()); 838 } 839 840 /* 841 * Update statistics for all resources of type 'rtype' pased in 'resources'. 842 */ 843 static void 844 update_resource_stats(pool_resource_t *resource, const char *rtype) 845 { 846 pool_elem_t *elem; 847 pool_value_t *pv_name; 848 char *name_prop; /* set name property */ 849 850 statistic_bag_t *sbag; 851 852 if (strcmp(rtype, PSET_TYPE_NAME) == 0) { 853 name_prop = PSET_NAME; 854 sbag = pset_sbag; 855 } else { 856 die(gettext(ERR_UNSUPP_RTYPE), rtype); 857 } 858 859 if ((pv_name = create_pool_value(name_prop)) == NULL) 860 goto on_error; 861 862 if ((elem = pool_resource_to_elem(conf, resource)) == NULL) 863 goto on_error; 864 if (pool_get_property(conf, elem, name_prop, pv_name) == -1) 865 goto on_error; 866 if (pool_value_get_string(pv_name, &sbag->sb_name) == -1) 867 goto on_error; 868 sa_update(sbag, 0); 869 870 if (pv_name != NULL) 871 pool_value_free(pv_name); 872 return; 873 874 on_error: 875 die(gettext(ERR_STATS_RES), get_errstr()); 876 } 877 878 /* 879 * For each pool in the configuration print statistics of associated resources. 880 * If the pool name list 'pn' is defined, only print resources of pools 881 * specified in the list. The list can specify the pool name or its system id. 882 */ 883 static void 884 prt_pool_stats(poolstat_list_element_t *pn) 885 { 886 uint_t nelem; 887 pool_elem_t *elem; 888 int i; 889 int error; 890 pool_t **pools = NULL; 891 pool_value_t *pvals[] = { NULL, NULL }; 892 pool_value_t *pv_name = NULL; 893 pool_value_t *pv_sys_id = NULL; 894 statistic_bag_t *sbag = pool_sbag; 895 poolstat_list_element_t *rtype; 896 pool_resource_t **resources; 897 898 if ((pv_sys_id = create_pool_value(POOL_SYSID)) == NULL) 899 goto on_error; 900 if ((pv_name = create_pool_value(POOL_NAME)) == NULL) 901 goto on_error; 902 903 if (pn == NULL) { 904 /* collect all pools */ 905 if ((pools = pool_query_pools(conf, &nelem, NULL)) == NULL) 906 goto on_error; 907 } else { 908 /* 909 * collect pools specified in the 'pn' list. 910 * 'poolid' the pool identifier can be a pool name or sys_id. 911 */ 912 poolstat_list_element_t *poolid; 913 for (poolid = pn, i = 1; poolid; poolid = poolid->ple_next) 914 i++; 915 pools = ZALLOC(sizeof (pool_t *) * (i + 1)); 916 for (poolid = pn, i = 0; poolid; 917 poolid = poolid->ple_next, i++) { 918 pool_t **pool; 919 int64_t sysid = Atoi(poolid->ple_obj, &error); 920 if (error == 0) { 921 /* the pool is identified by sys_id */ 922 pool_value_set_int64(pv_sys_id, sysid); 923 pvals[0] = pv_sys_id; 924 pool = pool_query_pools(conf, &nelem, pvals); 925 } else { 926 if (pool_value_set_string(pv_name, 927 poolid->ple_obj) == -1) 928 die(gettext(ERR_NOMEM)); 929 pvals[0] = pv_name; 930 pool = pool_query_pools(conf, &nelem, pvals); 931 } 932 if (pool == NULL) 933 die(gettext(ERR_STATS_POOL_N), poolid->ple_obj); 934 pools[i] = pool[0]; 935 FREE(pool); 936 } 937 } 938 939 /* print statistic for all pools found */ 940 if (!rflag) { 941 /* print the common resource header */ 942 prt_stat_hd(POOL_TYPE_NAME); 943 944 /* print statistics for the resources bound to the pools */ 945 for (i = 0; pools[i] != NULL; i++) { 946 elem = pool_to_elem(conf, pools[i]); 947 if (pool_get_property(conf, elem, POOL_NAME, pv_name) 948 == -1) 949 goto on_error; 950 if (pool_value_get_string(pv_name, &sbag->sb_name) != 0) 951 goto on_error; 952 if (pool_get_property( 953 conf, elem, "pool.sys_id", pv_sys_id) == -1) 954 goto on_error; 955 if (pool_value_get_int64( 956 pv_sys_id, &sbag->sb_sysid) != 0) 957 goto on_error; 958 959 for (rtype = rtypes; rtype; rtype = rtype->ple_next) { 960 resources = get_resources( 961 sbag->sb_name, rtype->ple_obj, &nelem); 962 update_resource_stats(*resources, 963 rtype->ple_obj); 964 FREE(resources); 965 } 966 prt_stat_line(&pool_lf); 967 } 968 } else { 969 /* print statistic for all resource types defined in rtypes */ 970 for (rtype = rtypes; rtype; rtype = rtype->ple_next) { 971 prt_stat_hd(rtype->ple_obj); 972 for (i = 0; pools[i] != NULL; i++) { 973 elem = pool_to_elem(conf, pools[i]); 974 if (pool_get_property( 975 conf, elem, POOL_NAME, pv_name) == -1) 976 goto on_error; 977 if (pool_value_get_string( 978 pv_name, &sbag->sb_name) != 0) 979 goto on_error; 980 if (pool_get_property( 981 conf, elem, POOL_SYSID, pv_sys_id) 982 == -1) 983 goto on_error; 984 if (pool_value_get_int64( 985 pv_sys_id, &sbag->sb_sysid) != 0) 986 goto on_error; 987 resources = get_resources( 988 sbag->sb_name, rtype->ple_obj, &nelem); 989 if (resources == NULL) 990 continue; 991 update_resource_stats( 992 *resources, rtype->ple_obj); 993 prt_resource_stats_by_type(resources, 994 rtype->ple_obj); 995 FREE(resources); 996 } 997 } 998 } 999 1000 FREE(pools); 1001 if (pv_name != NULL) 1002 pool_value_free(pv_name); 1003 if (pv_sys_id != NULL) 1004 pool_value_free(pv_sys_id); 1005 1006 return; 1007 on_error: 1008 die(gettext(ERR_STATS_POOL), get_errstr()); 1009 } 1010