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