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