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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 #include <alloca.h>
27 #include <assert.h>
28 #include <errno.h>
29 #include <langinfo.h>
30 #include <libintl.h>
31 #include <libscf.h>
32 #include <signal.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <strings.h>
37 #include <sys/fxpriocntl.h>
38 #include <sys/priocntl.h>
39 #include <sys/types.h>
40 #include <time.h>
41 #include <unistd.h>
42 #include <zonestat.h>
43
44 extern char *optarg;
45 extern int optind, opterr, optopt;
46
47 #define ZSTAT_OK 0
48 #define ZSTAT_ERROR 1
49 #define ZSTAT_USAGE 2
50
51 #define ZSTAT_UNIX_TIMESTAMP 1
52 #define ZSTAT_ISO_TIMESTAMP 2
53 #define ZSTAT_DATE_TIMESTAMP 3
54
55 #define ZSTAT_RES_PHYSICAL_MEMORY 0x1
56 #define ZSTAT_RES_VIRTUAL_MEMORY 0x2
57 #define ZSTAT_RES_LOCKED_MEMORY 0x4
58 #define ZSTAT_RES_MEMORY 0x7
59
60 #define ZSTAT_RES_DEFAULT_PSET 0x10
61 #define ZSTAT_RES_PSETS 0x20
62 #define ZSTAT_RES_SUMMARY 0x40
63
64 #define ZSTAT_RES_PROCESSES 0x100
65 #define ZSTAT_RES_LWPS 0x200
66 #define ZSTAT_RES_LOFI 0x400
67 #define ZSTAT_RES_LIMITS 0x700
68
69 #define ZSTAT_RES_SHM_MEMORY 0x1000
70 #define ZSTAT_RES_SHM_IDS 0x2000
71 #define ZSTAT_RES_SEM_IDS 0x4000
72 #define ZSTAT_RES_MSG_IDS 0x8000
73 #define ZSTAT_RES_SYSV 0xF000
74
75 #define ZSTAT_RES_ALL 0xF777
76
77 #define ZONESTAT_PHYSICAL_MEMORY "physical-memory"
78 #define ZONESTAT_VIRTUAL_MEMORY "virtual-memory"
79 #define ZONESTAT_LOCKED_MEMORY "locked-memory"
80 #define ZONESTAT_MEMORY "memory"
81
82 #define ZONESTAT_DEFAULT_PSET "default-pset"
83 #define ZONESTAT_POOL_PSET "pool-pset"
84 #define ZONESTAT_PSRSET_PSET "psrset-pset"
85 #define ZONESTAT_DEDICATED_CPU "dedicated-cpu"
86 #define ZONESTAT_PROCESSOR_SET "processor-set"
87 #define ZONESTAT_PSETS "psets"
88 #define ZONESTAT_SUMMARY "summary"
89
90 #define ZONESTAT_PROCESSES "processes"
91 #define ZONESTAT_LWPS "lwps"
92 #define ZONESTAT_LOFI "lofi"
93 #define ZONESTAT_LIMITS "limits"
94
95 #define ZONESTAT_SHM_MEMORY "shm-memory"
96 #define ZONESTAT_SHM_IDS "shm-ids"
97 #define ZONESTAT_SEM_IDS "sem-ids"
98 #define ZONESTAT_MSG_IDS "msg-ids"
99 #define ZONESTAT_SYSV "sysv"
100
101 #define ZONESTAT_ALL "all"
102
103 #define ZONESTAT_NAME_MEM_DEFAULT "mem_default"
104 #define ZONESTAT_NAME_VM_DEFAULT "vm_default"
105
106 #define ZONESTAT_NAME_AVERAGE "average"
107 #define ZONESTAT_NAME_HIGH "high"
108
109 #define ZONESTAT_NAME_RESOURCE "resource"
110 #define ZONESTAT_NAME_TOTAL "total"
111 #define ZONESTAT_NAME_SYSTEM "system"
112 #define ZONESTAT_NAME_ZONES "zones"
113 #define ZONESTAT_NAME_HEADER "header"
114 #define ZONESTAT_NAME_FOOTER "footer"
115
116 #define ZONESTAT_NAME_NAME "name"
117 #define ZONESTAT_NAME_USED "used"
118 #define ZONESTAT_NAME_CAP "cap"
119 #define ZONESTAT_NAME_PCAP "pcap"
120 #define ZONESTAT_NAME_SHR "shr"
121 #define ZONESTAT_NAME_PSHRU "pshru"
122 #define ZONESTAT_NAME_CPU "cpu"
123 #define ZONESTAT_NAME_PHYSICAL_MEMORY ZONESTAT_PHYSICAL_MEMORY
124 #define ZONESTAT_NAME_VIRTUAL_MEMORY ZONESTAT_VIRTUAL_MEMORY
125
126 #define ZONESTAT_NAME_SYSTEM_LIMIT "system-limit"
127
128 #define ZSTAT_REPORT_FMT_INTERVAL 0
129 #define ZSTAT_REPORT_FMT_TOTAL 1
130 #define ZSTAT_REPORT_FMT_AVERAGE 2
131 #define ZSTAT_REPORT_FMT_HIGH 3
132 #define ZSTAT_REPORT_FMT_END 4
133
134 #define ZSTAT_REPORT_TEXT_INTERVAL "interval"
135 #define ZSTAT_REPORT_TEXT_TOTAL "report-total"
136 #define ZSTAT_REPORT_TEXT_AVERAGE "report-average"
137 #define ZSTAT_REPORT_TEXT_HIGH "report-high"
138 #define ZSTAT_REPORT_TEXT_END "footer"
139
140 #define ZSTAT_DURATION_INF ((int)INT_MAX)
141 #define ZSTAT_INTERVAL_DEFAULT ((int)INT_MAX)
142 #define ZSTAT_REPORT_END ((int)INT_MAX)
143
144 #define ZSTAT_SORT_CPU 1
145 #define ZSTAT_SORT_PHYSICAL 2
146 #define ZSTAT_SORT_VIRTUAL 3
147 #define ZSTAT_SORT_USED 4
148 #define ZSTAT_SORT_CAP 5
149 #define ZSTAT_SORT_PCAP 6
150 #define ZSTAT_SORT_SHR 7
151 #define ZSTAT_SORT_PSHRU 8
152 #define ZSTAT_SORT_NAME 9
153 #define ZSTAT_SORT_MAX 10
154
155 #define ZSTAT_SUM_MIN_ZONENAME 19
156 #define ZSTAT_SUM_HDR_FORMAT "%23s %17s %17s\n"
157 #define ZSTAT_SUM_ZONE_FORMAT "%5s %5s %5s %5s %5s %5s %5s %5s %5s %5s\n"
158
159 #define ZSTAT_CPU_MIN_PSETNAME 22
160 #define ZSTAT_CPU_MIN_ZONENAME 36
161 #define ZSTAT_CPU_RES_FORMAT "%13s %11s %11s\n"
162 #define ZSTAT_CPU_ZONE_FORMAT "%5s %5s %5s %5s %6s %5s %5s\n"
163
164 #define ZSTAT_RESOURCE_MIN_RESNAME 28
165 #define ZSTAT_RESOURCE_MIN_ZONENAME 36
166 #define ZSTAT_RESOURCE_FORMAT "%13s\n"
167 #define ZSTAT_RESOURCE_ZONE_FORMAT "%5s %5s %5s %5s\n"
168
169 #define ZS_UINT64_STRLEN 20
170 #define ZS_PCT_STRLEN 10
171 #define ZS_TIME_STRLEN 20
172 #define ZS_NAME_STRLEN 10
173
174 time_t g_now_time;
175 time_t g_boot_time;
176 time_t g_start_time;
177 time_t g_end_time;
178 int g_interval;
179 int g_count;
180 int g_report_count;
181 time_t g_seconds;
182
183 int g_resources;
184 zs_ctl_t *g_zsctl;
185 boolean_t g_quit = B_FALSE;
186 zs_zone_t **g_zone_list;
187 int g_zone_num;
188 zs_pset_zone_t **g_pz_list;
189 int g_pz_num;
190 zs_pset_t **g_pset_list;
191 int g_pset_num;
192 int g_sort_by;
193 int g_sorts[ZSTAT_SORT_MAX];
194 int g_sort_summary;
195 size_t g_max_zonename;
196
197 /* Storage for command line arguments. */
198 char **arg_zonenames;
199 int arg_zonename_count;
200 char **arg_resnames;
201 int arg_resname_count;
202 char **arg_restypes;
203 int arg_restype_count;
204 char ** arg_reports;
205 int arg_report_count;
206 char ** arg_sort_list;
207 int arg_sort_count;
208 char ** arg_line_list;
209 int arg_line_count;
210
211 time_t arg_starttime;
212 time_t arg_endtime;
213 uint_t arg_timestamp = ZSTAT_DATE_TIMESTAMP;
214 int arg_interval = 5;
215 int arg_duration = -1;
216 int arg_report = -1;
217
218 /* Options with or as arguments */
219 boolean_t opt_zonenames = B_FALSE;
220 boolean_t opt_resnames = B_FALSE;
221 boolean_t opt_restypes = B_FALSE;
222 boolean_t opt_start = B_FALSE;
223 boolean_t opt_end = B_FALSE;
224 boolean_t opt_in = B_FALSE;
225 boolean_t opt_out = B_FALSE;
226 boolean_t opt_timestamp = B_FALSE;
227 boolean_t opt_report = B_FALSE;
228 boolean_t opt_sort = B_FALSE;
229
230 boolean_t opt_report_high = B_FALSE;
231 boolean_t opt_report_total = B_FALSE;
232 boolean_t opt_report_average = B_FALSE;
233
234 boolean_t opt_line_resource = B_FALSE;
235 boolean_t opt_line_total = B_FALSE;
236 boolean_t opt_line_system = B_FALSE;
237 boolean_t opt_line_zones = B_FALSE;
238 boolean_t opt_line_header = B_FALSE;
239 boolean_t opt_line_any = B_FALSE;
240
241 /* Options without arguments */
242 boolean_t opt_quiet_intervals = B_FALSE;
243 boolean_t opt_parseable = B_FALSE;
244 boolean_t opt_debug = B_FALSE;
245
246 static int
zonestat_usage(boolean_t explicit)247 zonestat_usage(boolean_t explicit)
248 {
249 FILE *fd = explicit ? stdout : stderr;
250
251 (void) fprintf(fd, gettext("Usage:\n"));
252 (void) fprintf(fd,
253 " zonestat [-z zonelist] [-r reslist] [-n namelist]\n"
254 " [-T u | d | i] [-R reports] [-q] [-p [-P lines]] [-S cols]\n"
255 " interval [duration [report]]\n"
256 "\n");
257 (void) fprintf(fd, gettext(
258 " Options:\n"
259 " %s Report resources of specified types.\n"
260 " Valid resource types are:\n"
261 " \"%s\"\n"
262 " \"%s\"\n"
263 " \"%s\"\n"
264 " \"%s\"\n"
265 " \"%s\", \"%s\", \"%s\"\n"
266 " \"%s\", \"%s\", \"%s\", \"%s\"\n"),
267 "-r",
268 ZONESTAT_VIRTUAL_MEMORY, ZONESTAT_PHYSICAL_MEMORY,
269 ZONESTAT_LOCKED_MEMORY, ZONESTAT_PROCESSOR_SET,
270 ZONESTAT_PROCESSES, ZONESTAT_LWPS, ZONESTAT_LOFI,
271 ZONESTAT_SHM_MEMORY, ZONESTAT_SHM_IDS, ZONESTAT_SEM_IDS,
272 ZONESTAT_MSG_IDS);
273
274 (void) fprintf(fd, gettext(
275 " The following resource nicknames can also be specified:\n"
276 " \"%s\"\n"
277 " \"%s\"\n"
278 " \"%s\"\n"
279 " \"%s\"\n"
280 " \"%s\"\n"
281 " \"%s\"\n"),
282 ZONESTAT_SUMMARY, ZONESTAT_MEMORY, ZONESTAT_PSETS,
283 ZONESTAT_DEFAULT_PSET, ZONESTAT_LIMITS, ZONESTAT_SYSV);
284 (void) fprintf(fd, gettext(
285 " %s Report resources used by zones\n"
286 " %s Report resources with specific names.\n"
287 " Valid resource names are:\n"
288 " \"%s\"\n"
289 " \"%s\"\n"
290 " Name of a pool processor set\n"
291 " Id of a processor set created with psrset(1m)\n"
292 " Name of a zone using dedicated-cpu\n"),
293 "-z", "-n",
294 ZONESTAT_NAME_MEM_DEFAULT, ZONESTAT_NAME_VM_DEFAULT);
295 (void) printf(gettext(
296 " %s Print timestamp. Valid timestamps are:\n"
297 " \"%s\"\tDate as specifed by date(1) command\n"
298 " \"%s\"\tUnix time as returned by time(2)\n"
299 " \"%s\"\tISO 8601 timestamp \"%s\"\n"
300 " %s Print reports at end or after each report interval.\n"
301 " Valid reports are:\n"
302 " \"%s\"\tUsage of each zone\n"
303 " \"%s\"\tUsage of each zone while running\n"
304 " \"%s\"\tMaximum usage of each zone\n"
305 " %s Quiet. Do not print intervals. Only print reports.\n"
306 " %s Machine parseable output.\n"),
307 "-T", "d", "u", "i", "YYYYMMDDThhmmssZ",
308 "-R", ZONESTAT_NAME_TOTAL, ZONESTAT_NAME_AVERAGE,
309 ZONESTAT_NAME_HIGH,
310 "-q", "-p");
311
312 (void) printf(gettext(
313 " %s Select desired lines in parseable output.\n"
314 " \"%s\"\tLines describing each resource\n"
315 " \"%s\"\tTotal usage of each resource\n"
316 " \"%s\"\tSystem usage of each resource\n"
317 " \"%s\"\tPer-zone usage of each resource\n"
318 " \"%s\"\tHeader lines between intervals and reports\n"),
319 "-P", ZONESTAT_NAME_RESOURCE, ZONESTAT_NAME_TOTAL,
320 ZONESTAT_NAME_SYSTEM, ZONESTAT_NAME_ZONES, ZONESTAT_NAME_HEADER);
321
322 (void) printf(gettext(
323 " %s Sort output by the specified columns:\n"
324 " \"%s\"\tby name alphanumerically\n"
325 " \"%s\"\tby percent of resource used\n"
326 " \"%s\"\tby configured cap\n"
327 " \"%s\"\tby percent of cap used\n"
328 " \"%s\"\tby shares configured\n"
329 " \"%s\"\tby percent of share used\n"
330 " \"%s\"\tSort summary by cpu\n"
331 " \"%s\"\tSort summary by physical memory\n"
332 " \"%s\"\tSort summary by virtual memory\n"),
333 "-S", ZONESTAT_NAME_NAME, ZONESTAT_NAME_USED, ZONESTAT_NAME_CAP,
334 ZONESTAT_NAME_PCAP, ZONESTAT_NAME_SHR, ZONESTAT_NAME_PSHRU,
335 ZONESTAT_NAME_CPU, ZONESTAT_NAME_PHYSICAL_MEMORY,
336 ZONESTAT_NAME_VIRTUAL_MEMORY);
337
338 if (!explicit)
339 (void) fputs("\n", fd);
340 return (ZSTAT_USAGE);
341 }
342
343 /* PRINTFLIKE1 */
344 static int
zonestat_error(const char * fmt,...)345 zonestat_error(const char *fmt, ...)
346 {
347 va_list alist;
348
349 va_start(alist, fmt);
350
351 (void) fprintf(stderr, "zonestat: Error: ");
352 (void) vfprintf(stderr, fmt, alist);
353 (void) fprintf(stderr, "\n");
354 va_end(alist);
355 return (ZSTAT_ERROR);
356 }
357
358 static void
zonestat_determine_lines()359 zonestat_determine_lines()
360 {
361 int i;
362 boolean_t fail = B_FALSE;
363
364 if (arg_line_count == 0) {
365 opt_line_resource = B_TRUE;
366 opt_line_total = B_TRUE;
367 opt_line_system = B_TRUE;
368 opt_line_zones = B_TRUE;
369 opt_line_header = B_TRUE;
370 }
371 for (i = 0; i < arg_line_count; i++) {
372 if (strcmp(arg_line_list[i], ZONESTAT_NAME_RESOURCE) == 0)
373 opt_line_resource = B_TRUE;
374 else if (strcmp(arg_line_list[i], ZONESTAT_NAME_TOTAL) == 0)
375 opt_line_total = B_TRUE;
376 else if (strcmp(arg_line_list[i], ZONESTAT_NAME_SYSTEM) == 0)
377 opt_line_system = B_TRUE;
378 else if (strcmp(arg_line_list[i], ZONESTAT_NAME_ZONES) == 0)
379 opt_line_zones = B_TRUE;
380 else if (strcmp(arg_line_list[i], ZONESTAT_NAME_HEADER) == 0)
381 opt_line_header = B_TRUE;
382 else {
383 (void) zonestat_error(gettext("Unknown -O arg: %s"),
384 arg_line_list[i]);
385 fail = B_TRUE;
386 }
387 }
388 if (fail == B_TRUE)
389 exit(zonestat_usage(B_FALSE));
390 }
391
392 static void
zonestat_determine_reports()393 zonestat_determine_reports()
394 {
395 int i;
396 boolean_t fail = B_FALSE;
397
398 for (i = 0; i < arg_report_count; i++) {
399 if (strcmp(arg_reports[i], ZONESTAT_NAME_TOTAL) == 0)
400 opt_report_total = B_TRUE;
401 else if (strcmp(arg_reports[i], ZONESTAT_NAME_AVERAGE) == 0)
402 opt_report_average = B_TRUE;
403 else if (strcmp(arg_reports[i], ZONESTAT_NAME_HIGH) == 0)
404 opt_report_high = B_TRUE;
405 else {
406 (void) zonestat_error(gettext("Unknown -R arg: %s"),
407 arg_reports[i]);
408 fail = B_TRUE;
409 }
410 }
411 if (fail == B_TRUE)
412 exit(zonestat_usage(B_FALSE));
413 }
414
415 /*
416 * Compares list of -S sort arguments to the list of known sorts. Only
417 * one of cpu, physical memory, and virtual memory can be specified.
418 */
419 static void
zonestat_determine_sort()420 zonestat_determine_sort()
421 {
422 int i, count = 0;
423 boolean_t fail = B_FALSE;
424
425 if (arg_sort_count == 0) {
426 g_sort_summary = ZS_RESOURCE_CPU;
427 g_sorts[0] = ZSTAT_SORT_USED;
428 g_sorts[1] = ZSTAT_SORT_NAME;
429 arg_sort_count = 2;
430 return;
431 }
432
433 if (arg_sort_count > ZSTAT_SORT_MAX)
434 exit(zonestat_error(gettext(
435 "Too many -S sort columns specified")));
436
437 for (i = 0; i < arg_sort_count; i++) {
438 if (strcmp(arg_sort_list[i], ZONESTAT_NAME_NAME) == 0)
439 g_sorts[count++] = ZSTAT_SORT_NAME;
440 else if (strcmp(arg_sort_list[i], ZONESTAT_NAME_USED) == 0)
441 g_sorts[count++] = ZSTAT_SORT_USED;
442 else if (strcmp(arg_sort_list[i], ZONESTAT_NAME_CAP) == 0)
443 g_sorts[count++] = ZSTAT_SORT_CAP;
444 else if (strcmp(arg_sort_list[i], ZONESTAT_NAME_PCAP) == 0)
445 g_sorts[count++] = ZSTAT_SORT_PCAP;
446 else if (strcmp(arg_sort_list[i], ZONESTAT_NAME_SHR) == 0)
447 g_sorts[count++] = ZSTAT_SORT_SHR;
448 else if (strcmp(arg_sort_list[i], ZONESTAT_NAME_PSHRU) == 0)
449 g_sorts[count++] = ZSTAT_SORT_PSHRU;
450 else if (strcmp(arg_sort_list[i], ZONESTAT_NAME_CPU) == 0) {
451 if (g_sort_summary != 0)
452 fail = B_TRUE;
453 g_sort_summary = ZS_RESOURCE_CPU;
454 } else if (strcmp(arg_sort_list[i],
455 ZONESTAT_NAME_PHYSICAL_MEMORY) == 0) {
456 if (g_sort_summary != 0)
457 fail = B_TRUE;
458 g_sort_summary = ZS_RESOURCE_RAM_RSS;
459 } else if (strcmp(arg_sort_list[i],
460 ZONESTAT_NAME_VIRTUAL_MEMORY) == 0) {
461 if (g_sort_summary != 0)
462 fail = B_TRUE;
463 g_sort_summary = ZS_RESOURCE_VM;
464 } else {
465 (void) zonestat_error(gettext("Unknown -S arg: %s"),
466 arg_sort_list[i]);
467 fail = B_TRUE;
468 }
469 }
470 if (g_sort_summary == 0)
471 g_sort_summary = ZS_RESOURCE_CPU;
472
473 if (fail == B_TRUE) {
474 (void) zonestat_error(gettext(
475 "-S: only one of \"%s\", \"%s\", or "
476 "\"%s\" permitted"), "-S", ZONESTAT_NAME_CPU,
477 ZONESTAT_NAME_PHYSICAL_MEMORY,
478 ZONESTAT_NAME_VIRTUAL_MEMORY);
479 exit(zonestat_usage(B_FALSE));
480 }
481 }
482
483 typedef struct zonestat_resource_struct {
484 char *zr_name;
485 uint_t zr_flag;
486 } zonestat_resource_t;
487
488
489 /* Used to map resource name strings to resource flags */
490 zonestat_resource_t g_resource_list[] = {
491 ZONESTAT_PHYSICAL_MEMORY, ZSTAT_RES_PHYSICAL_MEMORY,
492 ZONESTAT_VIRTUAL_MEMORY, ZSTAT_RES_VIRTUAL_MEMORY,
493 ZONESTAT_LOCKED_MEMORY, ZSTAT_RES_LOCKED_MEMORY,
494 ZONESTAT_MEMORY, ZSTAT_RES_MEMORY,
495 ZONESTAT_PROCESSOR_SET, ZSTAT_RES_PSETS,
496 ZONESTAT_PSETS, ZSTAT_RES_PSETS,
497 ZONESTAT_DEFAULT_PSET, ZSTAT_RES_DEFAULT_PSET,
498 ZONESTAT_PROCESSES, ZSTAT_RES_PROCESSES,
499 ZONESTAT_LWPS, ZSTAT_RES_LWPS,
500 ZONESTAT_LOFI, ZSTAT_RES_LOFI,
501 ZONESTAT_LIMITS, ZSTAT_RES_LIMITS,
502 ZONESTAT_SHM_MEMORY, ZSTAT_RES_SHM_MEMORY,
503 ZONESTAT_SHM_IDS, ZSTAT_RES_SHM_IDS,
504 ZONESTAT_SEM_IDS, ZSTAT_RES_SEM_IDS,
505 ZONESTAT_MSG_IDS, ZSTAT_RES_MSG_IDS,
506 ZONESTAT_SYSV, ZSTAT_RES_SYSV,
507 ZONESTAT_SUMMARY, ZSTAT_RES_SUMMARY,
508 ZONESTAT_ALL, ZSTAT_RES_ALL
509 };
510
511 /*
512 * Compares list of resources passed to -r to the known list of
513 * resources.
514 */
515 static void
zonestat_determine_resources()516 zonestat_determine_resources()
517 {
518 int i, j, count;
519 boolean_t found, fail = B_FALSE;
520
521 if (arg_restype_count == 0) {
522 g_resources = ZSTAT_RES_SUMMARY;
523 return;
524 }
525
526 count = sizeof (g_resource_list) / sizeof (zonestat_resource_t);
527
528 for (i = 0; i < arg_restype_count; i++) {
529 found = B_FALSE;
530 for (j = 0; j < count; j++) {
531 if (strcmp(arg_restypes[i], g_resource_list[j].zr_name)
532 == 0) {
533 g_resources |= g_resource_list[j].zr_flag;
534 found = B_TRUE;
535 break;
536 }
537 }
538 if (found == B_FALSE) {
539 (void) zonestat_error(gettext("Unknown resource: %s"),
540 arg_restypes[i]);
541 fail = B_TRUE;
542 }
543 }
544 if (fail == B_TRUE)
545 exit(zonestat_usage(B_FALSE));
546 }
547
548 /*
549 * Returns 1 if the name matches one of the specified zone names. 0
550 * otherwise. Always matches if no zone names were specified.
551 */
552 static int
zonestat_match_zonename(char * name)553 zonestat_match_zonename(char *name)
554 {
555 int i;
556
557 if (arg_zonename_count == 0)
558 return (1);
559 for (i = 0; i < arg_zonename_count; i++) {
560 if (strcmp(name, arg_zonenames[i]) == 0)
561 return (1);
562 }
563 return (0);
564 }
565
566 /*
567 * compare name to base, ignoring prefix on name.
568 */
569 static int
zonestat_match_with_prefix(char * prefix,char * name,char * base)570 zonestat_match_with_prefix(char *prefix, char *name, char *base)
571 {
572 size_t prefix_len;
573
574 prefix_len = strlen(prefix);
575 if (strncmp(name, prefix, prefix_len) == 0) {
576 name += prefix_len;
577 if (strcmp(name, base) == 0)
578 return (1);
579 }
580 return (0);
581 }
582 /*
583 * Returns 1 if the resource matches one of the specified resource names. 0
584 * otherwise. Always matches if no resource names were specified.
585 */
586 static int
zonestat_match_resname(char * name)587 zonestat_match_resname(char *name)
588 {
589 int i;
590
591 if (arg_resname_count == 0)
592 return (1);
593 for (i = 0; i < arg_resname_count; i++) {
594
595 if (strcmp(name, arg_resnames[i]) == 0)
596 return (1);
597
598 if (zonestat_match_with_prefix("SUNWtmp_", name,
599 arg_resnames[i]))
600 return (1);
601
602 if (zonestat_match_with_prefix("SUNWlegacy_pset_", name,
603 arg_resnames[i]))
604 return (1);
605 }
606 return (0);
607 }
608
609 /*
610 * Format unsigned uint64_t
611 *
612 * 9999 9999
613 * 99.9K 99999
614 * 9999K 9999999
615 * 99.9M 99999999
616 * 9999M 9999999999
617 * 99.9G 99999999999
618 * 9999G 9999999999999
619 * 99.9T 99999999999999
620 * 9999T 9999999999999999
621 * 99.9P 99999999999999999
622 * 9999P 9999999999999999999
623 * 99.9E UINT64_MAX
624 */
625 static void
format_uint64(uint64_t val,char * str,size_t len)626 format_uint64(uint64_t val, char *str, size_t len)
627 {
628 uint64_t high;
629 uint64_t low;
630
631 if (val == UINT64_MAX) {
632 (void) snprintf(str, len, "-");
633 return;
634 }
635 if (val <= 9999) {
636 (void) snprintf(str, len, "%llu", val);
637 return;
638 }
639 if (val <= 99999) {
640 high = val / 1024;
641 low = val * 10 / 1024 - (high * 10);
642 (void) snprintf(str, len, "%llu%1.1lluK", high, low);
643 return;
644 }
645 val = val / 1024;
646 if (val <= 9999 || opt_parseable) {
647 high = val;
648 (void) snprintf(str, len, "%lluK", high);
649 return;
650 }
651 if (val <= 99999) {
652 high = val / 1024;
653 low = val * 10 / 1024 - (high * 10);
654 (void) snprintf(str, len, "%llu.%1.1lluM", high, low);
655 return;
656 }
657 val = val / 1024;
658 if (val <= 9999) {
659 high = val;
660 (void) snprintf(str, len, "%lluM", high);
661 return;
662 }
663 if (val <= 99999) {
664 high = val / 1024;
665 low = val * 10 / 1024 - (high * 10);
666 (void) snprintf(str, len, "%llu.%1.1lluG", high, low);
667 return;
668 }
669 val = val / 1024;
670 if (val <= 9999) {
671 high = val;
672 (void) snprintf(str, len, "%lluG", high);
673 return;
674 }
675 if (val <= 99999) {
676 high = val / 1024;
677 low = val * 10 / 1024 - (high * 10);
678 (void) snprintf(str, len, "%llu.%1.1lluT", high, low);
679 return;
680 }
681 val = val / 1024;
682 if (val <= 9999) {
683 high = val;
684 (void) snprintf(str, len, "%lluT", high);
685 return;
686 }
687 if (val <= 99999) {
688 high = val / 1024;
689 low = val * 10 / 1024 - (high * 10);
690 (void) snprintf(str, len, "%llu.%1.1lluP", high, low);
691 return;
692 }
693 val = val / 1024;
694 if (val <= 9999) {
695 high = val;
696 (void) snprintf(str, len, "%lluP", high);
697 return;
698 }
699 high = val / 1024;
700 low = val * 10 / 1024 - (high * 10);
701 (void) snprintf(str, len, "%llu.%1.1lluE", high, low);
702 }
703
704
705 static void
format_pct(uint_t pct,char * str,size_t len)706 format_pct(uint_t pct, char *str, size_t len)
707 {
708 uint_t high;
709 uint_t low;
710
711 if (pct == ZS_PCT_NONE) {
712 (void) snprintf(str, len, "-");
713 return;
714 }
715 /*
716 * pct's are printed as one of:
717 * #.##%
718 * ##.#%
719 * ###%
720 * ####%
721 *
722 * The value is fixed decimal. 10000 equals 100.00 percent.
723 * Percents can exceed 100.00 percent. Percents greater than
724 * 9999% will exceed the 5 column width.
725 */
726 if (pct <= 999 || opt_parseable) {
727 high = pct / 100;
728 low = pct - (high * 100);
729 (void) snprintf(str, len, "%u.%2.2u%%", high, low);
730 } else if (pct <= 9999) {
731 pct = pct / 10;
732 high = pct / 10;
733 low = pct - (high * 10);
734 (void) snprintf(str, len, "%u.%1.1u%%", high, low);
735 } else {
736 pct = pct / 100;
737 (void) snprintf(str, len, "%u%%", pct);
738 }
739 }
740 /*
741 * Cpu cap is 100 times the number of cpus allocated. It is formatted as a
742 * decimal. Example, a cpu-cap of 50 is 0.50 cpus.
743 *
744 * The cpu cap value can go up to UINT_MAX, so handle all cases even though
745 * the higher ones are nonsense.
746 *
747 * Format Max cpu-cap value for format.
748 * 42.9M 4294967296
749 * 9999K 999999999
750 * 99.9K 9999999
751 * 9999 999999
752 * 999.9 99999
753 * 9.99 999
754 */
755 void
format_cpu(uint64_t cpu,char * str,size_t len)756 format_cpu(uint64_t cpu, char *str, size_t len)
757 {
758
759 uint64_t high;
760 uint64_t low;
761
762 /* #.## cpus */
763 if (cpu <= 999 || opt_parseable) {
764 high = cpu / 100;
765 low = cpu - (high * 100);
766 (void) snprintf(str, len, "%llu.%2.2llu", high, low);
767 return;
768 }
769 /* ##.# cpus */
770 if (cpu <= 99999) {
771 high = cpu / 100;
772 low = cpu - (high * 100);
773 (void) snprintf(str, len, "%llu.%1.1llu", high, low);
774 return;
775 }
776 /* #### cpus */
777 if (cpu <= 999999) {
778 cpu = cpu / 100;
779 (void) snprintf(str, len, "%llu", cpu);
780 return;
781 }
782 /* ##.#K cpus */
783 cpu = cpu / 1000;
784 if (cpu <= 99999) {
785 high = cpu / 100;
786 low = cpu - (high * 100);
787 (void) snprintf(str, len, "%llu.%1.1lluK", high, low);
788 return;
789 }
790 /* ####K cpus */
791 if (cpu <= 999999) {
792 cpu = cpu / 100;
793 (void) snprintf(str, len, "%lluK", cpu);
794 return;
795 }
796 /* ##.#M cpus */
797 cpu = cpu / 1000;
798 if (cpu <= UINT_MAX) {
799 high = cpu / 100;
800 low = cpu - (high * 100);
801 (void) snprintf(str, len, "%llu.%1.1lluM", high, low);
802 return;
803 }
804 (void) snprintf(str, len, "error", high, low);
805 }
806
807 /*
808 * Format a timetruct as:
809 * HH:MM:SS.SS
810 *
811 * Human readable format omits the fractional seconds.
812 */
813 static void
format_ts(timestruc_t * ts,char * str,size_t len,boolean_t human_readable)814 format_ts(timestruc_t *ts, char *str, size_t len, boolean_t human_readable)
815 {
816 uint64_t secs, mins, hours, pct;
817
818 hours = 0;
819 mins = 0;
820
821 secs = ts->tv_sec;
822 pct = ts->tv_nsec / 1000 / 1000 / 10;
823 while (pct >= 100) {
824 pct -= 100;
825 secs++;
826 }
827 if (secs >= 60) {
828 mins = secs / 60;
829 secs = secs % 60;
830 }
831 if (mins >= 60) {
832 hours = mins / 60;
833 mins = mins % 60;
834 }
835 if (human_readable)
836 (void) snprintf(str, len, "%llu:%2.2llu:%2.2llu", hours,
837 mins, secs);
838 else
839 (void) snprintf(str, len, "%llu-%2.2llu-%2.2llu.%2.2llu", hours,
840 mins, secs, pct);
841 }
842
843 char *g_report_formats[] = {
844 ZSTAT_REPORT_TEXT_INTERVAL,
845 ZSTAT_REPORT_TEXT_TOTAL,
846 ZSTAT_REPORT_TEXT_AVERAGE,
847 ZSTAT_REPORT_TEXT_HIGH,
848 ZSTAT_REPORT_TEXT_END
849 };
850
851 /* Get the label for the current report type */
852 static char *
zonestat_get_plabel(int format)853 zonestat_get_plabel(int format)
854 {
855 if (format >= sizeof (g_report_formats) / sizeof (char *))
856 exit(zonestat_error(gettext(
857 "Internal error, invalid report format")));
858
859 return (g_report_formats[format]);
860 }
861
862 #define ZSTAT_CPULINE "----------CPU----------"
863 #define ZSTAT_MEMLINE "----PHYSICAL-----"
864 #define ZSTAT_VMLINE "-----VIRTUAL-----"
865
866 static void
zonestat_print_summary_header(size_t namewidth,int report_fmt,uint64_t cpu,uint64_t online,uint64_t mem,uint64_t vm)867 zonestat_print_summary_header(size_t namewidth, int report_fmt, uint64_t cpu,
868 uint64_t online, uint64_t mem, uint64_t vm)
869 {
870 char str_cpu[ZS_UINT64_STRLEN];
871 char str_online[ZS_UINT64_STRLEN];
872 char str_mem[ZS_UINT64_STRLEN];
873 char str_vm[ZS_UINT64_STRLEN];
874 char name_format[ZS_NAME_STRLEN];
875 char tot_cpu[sizeof (ZSTAT_CPULINE)];
876 char tot_mem[sizeof (ZSTAT_MEMLINE)];
877 char tot_vm[sizeof (ZSTAT_VMLINE)];
878
879 char *label;
880
881 format_uint64(cpu, str_cpu, sizeof (str_cpu));
882 format_uint64(online, str_online, sizeof (str_online));
883 format_uint64(mem, str_mem, sizeof (str_mem));
884 format_uint64(vm, str_vm, sizeof (str_vm));
885
886 if (opt_parseable) {
887 label = zonestat_get_plabel(report_fmt);
888 (void) printf("%s:%s:[%s]:%s:%s:%s:%s\n", label,
889 ZONESTAT_SUMMARY, ZONESTAT_NAME_RESOURCE, str_cpu,
890 str_online, str_mem, str_vm);
891 return;
892 }
893
894 (void) snprintf(tot_cpu, sizeof (tot_cpu), "Cpus/Online: %s/%s",
895 str_cpu, str_online);
896
897 (void) snprintf(tot_mem, sizeof (tot_mem), "Physical: %s", str_mem);
898
899 (void) snprintf(tot_vm, sizeof (tot_vm), "Virtual: %s", str_vm);
900
901 /* Make first column as wide as longest zonename */
902 (void) snprintf(name_format, sizeof (name_format), "%%-%ds ",
903 namewidth);
904 /* LINTED */
905 (void) printf(name_format, "SUMMARY");
906 (void) printf(ZSTAT_SUM_HDR_FORMAT, tot_cpu, tot_mem,
907 tot_vm);
908
909 /* LINTED */
910 (void) printf(name_format, "");
911 (void) printf(ZSTAT_SUM_HDR_FORMAT, ZSTAT_CPULINE,
912 ZSTAT_MEMLINE, ZSTAT_VMLINE);
913
914 (void) snprintf(name_format, sizeof (name_format), "%%%ds ",
915 namewidth);
916 /* LINTED */
917 (void) printf(name_format, "ZONE");
918
919 (void) printf(ZSTAT_SUM_ZONE_FORMAT, "USED", "%PART", "%CAP",
920 "%SHRU", "USED", "PCT", "%CAP", "USED", "PCT", "%CAP");
921 }
922
923 static void
zonestat_print_resource__header(size_t namelen,char * restype,char * size)924 zonestat_print_resource__header(size_t namelen, char *restype, char *size)
925 {
926 char name_format[ZS_NAME_STRLEN];
927
928 if (opt_parseable)
929 return;
930
931 (void) snprintf(name_format, sizeof (name_format), "%%-%ds ", namelen);
932 /* LINTED */
933 (void) printf(name_format, restype);
934 (void) printf(ZSTAT_RESOURCE_FORMAT, size);
935 }
936
937 static void
zonestat_print_resource_zone_header(size_t namelen)938 zonestat_print_resource_zone_header(size_t namelen)
939 {
940 char name_format[ZS_NAME_STRLEN];
941
942 if (opt_parseable)
943 return;
944
945 (void) snprintf(name_format, sizeof (name_format), "%%%ds ", namelen);
946 /* LINTED */
947 (void) printf(name_format, "ZONE");
948
949 (void) printf(ZSTAT_RESOURCE_ZONE_FORMAT, "USED", "PCT", "CAP", "%CAP");
950 }
951
952 static void
zonestat_print_timestamp(time_t t)953 zonestat_print_timestamp(time_t t)
954 {
955 static char *fmt = NULL;
956 int len;
957 char dstr[64];
958
959 /* We only need to retrieve this once per invocation */
960
961 if (arg_timestamp == ZSTAT_UNIX_TIMESTAMP) {
962 (void) printf("%ld", t);
963 } else if (arg_timestamp == ZSTAT_ISO_TIMESTAMP) {
964
965 len = strftime(dstr, sizeof (dstr), "%Y%m%dT%H%M%SZ",
966 gmtime(&t));
967 if (len > 0)
968 (void) printf("%s", dstr);
969
970 } else {
971
972 if (fmt == NULL)
973 fmt = nl_langinfo(_DATE_FMT);
974
975 len = strftime(dstr, sizeof (dstr), fmt, localtime(&t));
976 if (len > 0)
977 (void) printf("%s", dstr);
978 }
979 }
980
981 static void
zonestat_print_summary_zone(size_t namewidth,int report_fmt,char * name,uint64_t cused,uint_t ppart,uint_t pccap,uint_t pshru,uint64_t mused,uint_t mpct,uint_t pmcap,uint64_t vused,uint_t vpct,uint_t pvcap)982 zonestat_print_summary_zone(size_t namewidth, int report_fmt, char *name,
983 uint64_t cused, uint_t ppart, uint_t pccap, uint_t pshru, uint64_t mused,
984 uint_t mpct, uint_t pmcap, uint64_t vused, uint_t vpct, uint_t pvcap)
985 {
986 char *label;
987
988 char str_cused[ZS_UINT64_STRLEN];
989 char str_ppart[ZS_PCT_STRLEN];
990 char str_pccap[ZS_PCT_STRLEN];
991 char str_pshru[ZS_PCT_STRLEN];
992 char str_mused[ZS_UINT64_STRLEN];
993 char str_mpct[ZS_PCT_STRLEN];
994 char str_pmcap[ZS_PCT_STRLEN];
995 char str_vused[ZS_UINT64_STRLEN];
996 char str_vpct[ZS_PCT_STRLEN];
997 char str_pvcap[ZS_PCT_STRLEN];
998 char name_format[ZS_NAME_STRLEN];
999
1000 format_cpu(cused, str_cused, sizeof (str_cused));
1001 format_pct(ppart, str_ppart, sizeof (str_ppart));
1002 format_pct(pccap, str_pccap, sizeof (str_pccap));
1003 format_pct(pshru, str_pshru, sizeof (str_pshru));
1004 format_uint64(mused, str_mused, sizeof (str_mused));
1005 format_pct(mpct, str_mpct, sizeof (str_mpct));
1006 format_pct(pmcap, str_pmcap, sizeof (str_pmcap));
1007 format_uint64(vused, str_vused, sizeof (str_vused));
1008 format_pct(vpct, str_vpct, sizeof (str_vpct));
1009 format_pct(pvcap, str_pvcap, sizeof (str_pvcap));
1010
1011 if (opt_parseable) {
1012 if (opt_timestamp) {
1013 zonestat_print_timestamp(g_now_time);
1014 (void) printf(":");
1015 }
1016 label = zonestat_get_plabel(report_fmt);
1017 (void) printf("%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n",
1018 label, ZONESTAT_SUMMARY, name, str_cused, str_ppart,
1019 str_pccap, str_pshru, str_mused, str_mpct, str_pmcap,
1020 str_vused, str_vpct, str_pvcap);
1021 return;
1022 }
1023 (void) snprintf(name_format, sizeof (name_format), "%%%ds ",
1024 namewidth);
1025 /* LINTED */
1026 (void) printf(name_format, name);
1027 (void) printf(ZSTAT_SUM_ZONE_FORMAT, str_cused, str_ppart,
1028 str_pccap, str_pshru, str_mused, str_mpct, str_pmcap, str_vused,
1029 str_vpct, str_pvcap);
1030 }
1031
1032 static void
zonestat_print_resource_(size_t namelen,int report_fmt,char * res,char * name,uint64_t size)1033 zonestat_print_resource_(size_t namelen, int report_fmt, char *res,
1034 char *name, uint64_t size)
1035 {
1036 char strsize[ZS_UINT64_STRLEN];
1037 char *label;
1038 char name_format[ZS_NAME_STRLEN];
1039
1040 format_uint64(size, strsize, sizeof (strsize));
1041 if (opt_parseable) {
1042 if (opt_timestamp) {
1043 zonestat_print_timestamp(g_now_time);
1044 (void) printf(":");
1045 }
1046 label = zonestat_get_plabel(report_fmt);
1047 (void) printf("%s:%s:%s:[%s]:%s\n", label, res, name,
1048 ZONESTAT_NAME_RESOURCE, strsize);
1049 return;
1050 }
1051
1052 (void) snprintf(name_format, sizeof (name_format), "%%-%ds ", namelen);
1053 /* LINTED */
1054 (void) printf(name_format, name);
1055 (void) printf(ZSTAT_RESOURCE_FORMAT, strsize);
1056 }
1057
1058 static void
zonestat_print_resource_zone(size_t namelen,int report_fmt,char * restype,char * resname,char * name,uint64_t used,uint_t pct,uint64_t cap,uint_t pctcap)1059 zonestat_print_resource_zone(size_t namelen, int report_fmt, char *restype,
1060 char *resname, char *name, uint64_t used, uint_t pct, uint64_t cap,
1061 uint_t pctcap)
1062 {
1063 char strused[ZS_UINT64_STRLEN];
1064 char strpct[ZS_PCT_STRLEN];
1065 char strcap[ZS_UINT64_STRLEN];
1066 char strpctcap[ZS_PCT_STRLEN];
1067 char name_format[ZS_NAME_STRLEN];
1068
1069 char *label;
1070
1071 format_uint64(used, strused, sizeof (strused));
1072 format_pct(pct, strpct, sizeof (strpct));
1073 if (cap == ZS_LIMIT_NONE)
1074 (void) strlcpy(strcap, "-", sizeof (strcap));
1075 else
1076 format_uint64(cap, strcap, sizeof (strcap));
1077
1078 if (pctcap == ZS_PCT_NONE)
1079 (void) strlcpy(strpctcap, "-", sizeof (strpctcap));
1080 else
1081 format_pct(pctcap, strpctcap, sizeof (strpctcap));
1082
1083 if (opt_parseable) {
1084 if (opt_timestamp) {
1085 zonestat_print_timestamp(g_now_time);
1086 (void) printf(":");
1087 }
1088 label = zonestat_get_plabel(report_fmt);
1089 (void) printf("%s:%s:%s:%s:%s:%s:%s:%s\n", label, restype,
1090 resname, name, strused, strpct, strcap, strpctcap);
1091 return;
1092 }
1093
1094 (void) snprintf(name_format, sizeof (name_format), "%%%ds ", namelen);
1095 /* LINTED */
1096 (void) printf(name_format, name);
1097 (void) printf(ZSTAT_RESOURCE_ZONE_FORMAT, strused, strpct, strcap,
1098 strpctcap);
1099 }
1100
1101 /*
1102 * Not thread safe.
1103 */
1104 static void
zonestat_qsort(void * base,size_t nel,size_t width,int (* compar)(const void *,const void *),int by)1105 zonestat_qsort(void *base, size_t nel, size_t width,
1106 int (*compar)(const void *, const void *), int by)
1107 {
1108 g_sort_by = by;
1109 g_max_zonename = 0;
1110 qsort(base, nel, width, compar);
1111 }
1112
1113 static int
zonestat_zone_compare_resource(const void * a,const void * b)1114 zonestat_zone_compare_resource(const void *a, const void *b)
1115 {
1116 zs_zone_t *zonea = *(zs_zone_t **)a;
1117 zs_zone_t *zoneb = *(zs_zone_t **)b;
1118 zs_property_t *prop, *propb;
1119 uint64_t resa, resb;
1120 uint_t uinta, uintb;
1121 int i, res;
1122
1123 prop = alloca(zs_property_size());
1124 propb = alloca(zs_property_size());
1125
1126 for (i = 0; i < arg_sort_count; i++) {
1127
1128 /* Sort by order of selection */
1129 switch (g_sorts[i]) {
1130 case ZSTAT_SORT_USED:
1131 resa = zs_resource_used_zone_uint64(zonea, g_sort_by);
1132 resb = zs_resource_used_zone_uint64(zoneb, g_sort_by);
1133 break;
1134 case ZSTAT_SORT_CAP:
1135 resa = zs_zone_limit_uint64(zonea, g_sort_by);
1136 if (resa == ZS_LIMIT_NONE)
1137 resa = 0;
1138 resb = zs_zone_limit_uint64(zoneb, g_sort_by);
1139 if (resb == ZS_LIMIT_NONE)
1140 resb = 0;
1141 break;
1142 case ZSTAT_SORT_PCAP:
1143 uinta = zs_zone_limit_used_pct(zonea, g_sort_by);
1144 uintb = zs_zone_limit_used_pct(zoneb, g_sort_by);
1145 if (uinta == ZS_PCT_NONE)
1146 resa = 0;
1147 else
1148 resa = uinta;
1149 if (uintb == ZS_PCT_NONE)
1150 resb = 0;
1151 else
1152 resb = uintb;
1153 break;
1154 case ZSTAT_SORT_SHR:
1155 zs_zone_property(zonea, ZS_PZ_PROP_CPU_SHARES, prop);
1156 resa = zs_property_uint64(prop);
1157 if (resa == ZS_LIMIT_NONE)
1158 resa = 0;
1159 zs_zone_property(zoneb, ZS_PZ_PROP_CPU_SHARES, prop);
1160 resb = zs_property_uint64(prop);
1161 if (resb == ZS_LIMIT_NONE)
1162 resb = 0;
1163 break;
1164 case ZSTAT_SORT_PSHRU:
1165 uinta = zs_zone_limit_used_pct(zonea,
1166 ZS_LIMIT_CPU_SHARES);
1167 uintb = zs_zone_limit_used_pct(zoneb,
1168 ZS_LIMIT_CPU_SHARES);
1169 if (uinta == ZS_PCT_NONE)
1170 resa = 0;
1171 else
1172 resa = uinta;
1173 if (uintb == ZS_PCT_NONE)
1174 resb = 0;
1175 else
1176 resb = uintb;
1177 break;
1178 case ZSTAT_SORT_NAME:
1179 zs_zone_property(zonea, ZS_ZONE_PROP_NAME, prop);
1180 zs_zone_property(zoneb, ZS_ZONE_PROP_NAME, propb);
1181
1182 res = strcmp(zs_property_string(prop),
1183 zs_property_string(propb));
1184 if (res != 0)
1185 return (res);
1186 break;
1187 default:
1188 exit(zonestat_error(gettext("Internal sort error")));
1189 }
1190 if (resa < resb)
1191 return (1);
1192 if (resb < resa)
1193 return (-1);
1194 }
1195 /* No difference, return 0 */
1196 return (0);
1197 }
1198 /*
1199 * Sort psets. Default pset first, then shared psets, then dedicated
1200 * psets.
1201 */
1202 static int
zonestat_pset_compare(const void * a,const void * b)1203 zonestat_pset_compare(const void *a, const void *b)
1204 {
1205 zs_pset_t *pseta = *(zs_pset_t **)a;
1206 zs_pset_t *psetb = *(zs_pset_t **)b;
1207 zs_property_t *p;
1208 uint_t typea, typeb;
1209
1210
1211 p = (zs_property_t *)alloca(zs_property_size());
1212 zs_pset_property(pseta, ZS_PSET_PROP_CPUTYPE, p);
1213 typea = zs_property_uint(p);
1214 zs_pset_property(psetb, ZS_PSET_PROP_CPUTYPE, p);
1215 typeb = zs_property_uint(p);
1216
1217 if (typea == ZS_CPUTYPE_DEFAULT_PSET)
1218 return (-1);
1219 if (typeb == ZS_CPUTYPE_DEFAULT_PSET)
1220 return (1);
1221 if (typea == ZS_CPUTYPE_POOL_PSET)
1222 return (-1);
1223 if (typeb == ZS_CPUTYPE_POOL_PSET)
1224 return (1);
1225 if (typea == ZS_CPUTYPE_PSRSET_PSET)
1226 return (-1);
1227 if (typeb == ZS_CPUTYPE_PSRSET_PSET)
1228 return (1);
1229
1230 return (0);
1231 }
1232
1233 static int
zonestat_pz_compare_usage(const void * a,const void * b)1234 zonestat_pz_compare_usage(const void *a, const void *b)
1235 {
1236 zs_pset_zone_t *zonea = *(zs_pset_zone_t **)a;
1237 zs_pset_zone_t *zoneb = *(zs_pset_zone_t **)b;
1238 zs_property_t *prop, *propb;
1239 uint64_t resa, resb;
1240 uint_t uinta, uintb;
1241 int i, res;
1242
1243 prop = alloca(zs_property_size());
1244 propb = alloca(zs_property_size());
1245
1246 for (i = 0; i < arg_sort_count; i++) {
1247
1248 /* Sort by order of selection */
1249 switch (g_sorts[i]) {
1250 case ZSTAT_SORT_USED:
1251 resa = zs_pset_zone_used_cpus(zonea);
1252 resb = zs_pset_zone_used_cpus(zoneb);
1253 break;
1254 case ZSTAT_SORT_CAP:
1255 zs_pset_zone_property(zonea, ZS_PZ_PROP_CPU_CAP,
1256 prop);
1257 resa = zs_property_uint64(prop);
1258 if (resa == ZS_LIMIT_NONE)
1259 resa = 0;
1260 zs_pset_zone_property(zoneb, ZS_PZ_PROP_CPU_CAP,
1261 prop);
1262 resb = zs_property_uint64(prop);
1263 if (resb == ZS_LIMIT_NONE)
1264 resb = 0;
1265 break;
1266 case ZSTAT_SORT_PCAP:
1267 uinta = zs_pset_zone_used_pct(zonea, ZS_PZ_PCT_CPU_CAP);
1268 uintb = zs_pset_zone_used_pct(zoneb, ZS_PZ_PCT_CPU_CAP);
1269 if (uinta == ZS_PCT_NONE)
1270 resa = 0;
1271 else
1272 resa = uinta;
1273 if (uintb == ZS_PCT_NONE)
1274 resb = 0;
1275 else
1276 resb = uintb;
1277 break;
1278 case ZSTAT_SORT_SHR:
1279 zs_pset_zone_property(zonea, ZS_PZ_PROP_CPU_SHARES,
1280 prop);
1281 resa = zs_property_uint64(prop);
1282 if (resa == ZS_LIMIT_NONE)
1283 resa = 0;
1284 zs_pset_zone_property(zoneb, ZS_PZ_PROP_CPU_SHARES,
1285 prop);
1286 resb = zs_property_uint64(prop);
1287 if (resb == ZS_LIMIT_NONE)
1288 resb = 0;
1289 break;
1290 case ZSTAT_SORT_PSHRU:
1291 uinta = zs_pset_zone_used_pct(zonea,
1292 ZS_PZ_PCT_CPU_SHARES);
1293 uintb = zs_pset_zone_used_pct(zoneb,
1294 ZS_PZ_PCT_CPU_SHARES);
1295 if (uinta == ZS_PCT_NONE)
1296 resa = 0;
1297 else
1298 resa = uinta;
1299 if (uintb == ZS_PCT_NONE)
1300 resb = 0;
1301 else
1302 resb = uintb;
1303 break;
1304 case ZSTAT_SORT_NAME:
1305 zs_zone_property(zs_pset_zone_get_zone(zonea),
1306 ZS_ZONE_PROP_NAME, prop);
1307 zs_zone_property(zs_pset_zone_get_zone(zoneb),
1308 ZS_ZONE_PROP_NAME, propb);
1309
1310 res = strcmp(zs_property_string(prop),
1311 zs_property_string(propb));
1312 if (res != 0)
1313 return (res);
1314 break;
1315 default:
1316 exit(zonestat_error(gettext("Internal sort error")));
1317 }
1318 if (resa < resb)
1319 return (1);
1320 if (resb < resa)
1321 return (-1);
1322 }
1323 /* No difference, return 0 */
1324 return (0);
1325 }
1326
1327
1328 static void
zonestat_print_summary(int report_fmt,zs_usage_t * u)1329 zonestat_print_summary(int report_fmt, zs_usage_t *u)
1330 {
1331 int num, i;
1332 zs_zone_t *z;
1333 uint64_t cpus, online, tot_mem, tot_vm;
1334 uint64_t cused, mused, vused;
1335 uint_t ppart, pshru, pccap, mpct, pmcap, vpct, pvcap;
1336 char zonename[ZS_ZONENAME_MAX];
1337 zs_property_t *prop;
1338 size_t namewidth = 0, len;
1339
1340 prop = (zs_property_t *)alloca(zs_property_size());
1341
1342 zs_resource_property(u, ZS_RESOURCE_CPU, ZS_RESOURCE_PROP_CPU_TOTAL,
1343 prop);
1344 cpus = zs_property_uint64(prop);
1345
1346 zs_resource_property(u, ZS_RESOURCE_CPU,
1347 ZS_RESOURCE_PROP_CPU_ONLINE, prop);
1348 online = zs_property_uint64(prop);
1349
1350 tot_mem = zs_resource_total_uint64(u, ZS_RESOURCE_RAM_RSS);
1351 tot_vm = zs_resource_total_uint64(u, ZS_RESOURCE_VM);
1352
1353 again:
1354 num = zs_zone_list(u, g_zone_list, g_zone_num);
1355 if (num > g_zone_num) {
1356 if (g_zone_list != NULL)
1357 free(g_zone_list);
1358 g_zone_list = (zs_zone_t **) malloc(sizeof (zs_zone_t *) * num);
1359 g_zone_num = num;
1360 goto again;
1361 }
1362
1363 /* Find the longest zone name to set output width. */
1364 namewidth = ZSTAT_SUM_MIN_ZONENAME;
1365 for (i = 0; i < num; i++) {
1366 z = g_zone_list[i];
1367 (void) zs_zone_property(z, ZS_ZONE_PROP_NAME, prop);
1368 len = strlen(zs_property_string(prop));
1369 if (len > namewidth)
1370 namewidth = len;
1371 }
1372 zonestat_print_summary_header(namewidth, report_fmt, cpus, online,
1373 tot_mem, tot_vm);
1374
1375 zonestat_qsort(g_zone_list, num, sizeof (zs_zone_t *),
1376 zonestat_zone_compare_resource, g_sort_summary);
1377
1378 cused = zs_resource_used_uint64(u, ZS_RESOURCE_CPU, ZS_USER_ALL);
1379 mused = zs_resource_used_uint64(u, ZS_RESOURCE_RAM_RSS, ZS_USER_ALL);
1380 vused = zs_resource_used_uint64(u, ZS_RESOURCE_VM, ZS_USER_ALL);
1381
1382 ppart = zs_resource_used_pct(u, ZS_RESOURCE_CPU, ZS_USER_ALL);
1383 mpct = zs_resource_used_pct(u, ZS_RESOURCE_RAM_RSS, ZS_USER_ALL);
1384 vpct = zs_resource_used_pct(u, ZS_RESOURCE_VM, ZS_USER_ALL);
1385
1386 if (opt_line_total) {
1387 (void) snprintf(zonename, sizeof (zonename), "[%s]",
1388 ZONESTAT_NAME_TOTAL);
1389 zonestat_print_summary_zone(namewidth, report_fmt, zonename,
1390 cused, ppart, ZS_PCT_NONE, ZS_PCT_NONE, mused, mpct,
1391 ZS_PCT_NONE, vused, vpct, ZS_PCT_NONE);
1392 }
1393 cused = zs_resource_used_uint64(u, ZS_RESOURCE_CPU, ZS_USER_KERNEL);
1394 mused = zs_resource_used_uint64(u, ZS_RESOURCE_RAM_RSS, ZS_USER_KERNEL);
1395 vused = zs_resource_used_uint64(u, ZS_RESOURCE_VM, ZS_USER_KERNEL);
1396
1397 ppart = zs_resource_used_pct(u, ZS_RESOURCE_CPU, ZS_USER_KERNEL);
1398 mpct = zs_resource_used_pct(u, ZS_RESOURCE_RAM_RSS, ZS_USER_KERNEL);
1399 vpct = zs_resource_used_pct(u, ZS_RESOURCE_VM, ZS_USER_KERNEL);
1400
1401 if (opt_line_system) {
1402 (void) snprintf(zonename, sizeof (zonename), "[%s]",
1403 ZONESTAT_NAME_SYSTEM);
1404 zonestat_print_summary_zone(namewidth, report_fmt, zonename,
1405 cused, ppart, ZS_PCT_NONE, ZS_PCT_NONE, mused, mpct,
1406 ZS_PCT_NONE, vused, vpct, ZS_PCT_NONE);
1407 }
1408 for (i = 0; i < num; i++) {
1409
1410 z = g_zone_list[i];
1411
1412 zs_zone_property(z, ZS_ZONE_PROP_NAME, prop);
1413 (void) strlcpy(zonename, zs_property_string(prop),
1414 sizeof (zonename));
1415
1416 cused = zs_resource_used_zone_uint64(z, ZS_RESOURCE_CPU);
1417 mused = zs_resource_used_zone_uint64(z, ZS_RESOURCE_RAM_RSS);
1418 vused = zs_resource_used_zone_uint64(z, ZS_RESOURCE_VM);
1419
1420 ppart = zs_resource_used_zone_pct(z, ZS_RESOURCE_CPU);
1421 mpct = zs_resource_used_zone_pct(z, ZS_RESOURCE_RAM_RSS);
1422 vpct = zs_resource_used_zone_pct(z, ZS_RESOURCE_VM);
1423
1424 pshru = zs_zone_limit_used_pct(z, ZS_LIMIT_CPU_SHARES);
1425 pccap = zs_zone_limit_used_pct(z, ZS_LIMIT_CPU);
1426 pmcap = zs_zone_limit_used_pct(z, ZS_LIMIT_RAM_RSS);
1427 pvcap = zs_zone_limit_used_pct(z, ZS_LIMIT_VM);
1428
1429 zonestat_print_summary_zone(namewidth, report_fmt, zonename,
1430 cused, ppart, pccap, pshru, mused, mpct, pmcap, vused, vpct,
1431 pvcap);
1432 }
1433
1434 if (!opt_parseable)
1435 (void) printf("\n");
1436 (void) fflush(stdout);
1437 }
1438
1439 static void
zonestat_print_res(int report_fmt,char * header,char * sizename,char * resname,char * name,zs_usage_t * u,int res,int limit)1440 zonestat_print_res(int report_fmt, char *header, char *sizename, char *resname,
1441 char *name, zs_usage_t *u, int res, int limit)
1442 {
1443 zs_zone_t *zone;
1444 char zonename[ZS_ZONENAME_MAX];
1445 uint64_t size;
1446 uint64_t used;
1447 uint64_t cap;
1448 uint_t pct;
1449 uint_t pctcap;
1450 zs_property_t *prop;
1451 int num, i;
1452 size_t namelen, len;
1453
1454 prop = (zs_property_t *)alloca(zs_property_size());
1455
1456 /* See if resource matches specified resource names */
1457 if (zonestat_match_resname(name) == 0)
1458 return;
1459
1460 namelen = strlen(resname);
1461 if (ZSTAT_RESOURCE_MIN_RESNAME > namelen)
1462 namelen = ZSTAT_RESOURCE_MIN_RESNAME;
1463
1464 zonestat_print_resource__header(namelen, header, sizename);
1465
1466 size = zs_resource_total_uint64(u, res);
1467
1468 if (opt_line_resource)
1469 zonestat_print_resource_(namelen, report_fmt, resname, name,
1470 size);
1471
1472 again:
1473 num = zs_zone_list(u, g_zone_list, g_zone_num);
1474 if (num > g_zone_num) {
1475 if (g_zone_list != NULL)
1476 free(g_zone_list);
1477 g_zone_list = (zs_zone_t **) malloc(sizeof (zs_zone_t *) * num);
1478 g_zone_num = num;
1479 goto again;
1480 }
1481 namelen = ZSTAT_RESOURCE_MIN_ZONENAME;
1482 for (i = 0; i < num; i++) {
1483 zone = g_zone_list[i];
1484 (void) zs_zone_property(zone, ZS_ZONE_PROP_NAME, prop);
1485 len = strlen(zs_property_string(prop));
1486 if (len > namelen)
1487 namelen = len;
1488 }
1489
1490 zonestat_print_resource_zone_header(namelen);
1491
1492 used = zs_resource_used_uint64(u, res, ZS_USER_ALL);
1493 pct = zs_resource_used_pct(u, res, ZS_USER_ALL);
1494
1495 if (opt_line_total) {
1496 (void) snprintf(zonename, sizeof (zonename), "[%s]",
1497 ZONESTAT_NAME_TOTAL);
1498 zonestat_print_resource_zone(namelen, report_fmt, resname,
1499 name, zonename, used, pct, ZS_LIMIT_NONE, ZS_PCT_NONE);
1500 }
1501 used = zs_resource_used_uint64(u, res, ZS_USER_KERNEL);
1502 pct = zs_resource_used_pct(u, res, ZS_USER_KERNEL);
1503
1504 if (opt_line_system) {
1505 (void) snprintf(zonename, sizeof (zonename), "[%s]",
1506 ZONESTAT_NAME_SYSTEM);
1507 zonestat_print_resource_zone(namelen, report_fmt, resname, name,
1508 zonename, used, pct, ZS_LIMIT_NONE, ZS_PCT_NONE);
1509 }
1510 zonestat_qsort(g_zone_list, num, sizeof (zs_zone_t *),
1511 zonestat_zone_compare_resource, res);
1512
1513 for (i = 0; i < num; i++) {
1514
1515 zone = g_zone_list[i];
1516 zs_zone_property(zone, ZS_ZONE_PROP_NAME, prop);
1517 (void) strlcpy(zonename, zs_property_string(prop),
1518 sizeof (zonename));
1519
1520 if (zonestat_match_zonename(zonename) == 0)
1521 continue;
1522
1523 used = zs_resource_used_zone_uint64(zone, res);
1524 pct = zs_resource_used_zone_pct(zone, res);
1525
1526 cap = zs_zone_limit_uint64(zone, limit);
1527 pctcap = zs_zone_limit_used_pct(zone, limit);
1528
1529 if (opt_line_zones)
1530 zonestat_print_resource_zone(namelen, report_fmt,
1531 resname, name, zonename, used, pct, cap, pctcap);
1532 }
1533 if (!opt_parseable)
1534 (void) printf("\n");
1535 }
1536
1537 static void
zonestat_print_cpu_res_header(size_t namelen)1538 zonestat_print_cpu_res_header(size_t namelen)
1539 {
1540 char name_format[ZS_NAME_STRLEN];
1541
1542 if (opt_parseable)
1543 return;
1544
1545 (void) snprintf(name_format, sizeof (name_format), "%%-%ds ", namelen);
1546 /* LINTED */
1547 (void) printf(name_format, "PROCESSOR_SET");
1548 (void) printf(ZSTAT_CPU_RES_FORMAT, "TYPE", "ONLINE/CPUS", "MIN/MAX");
1549 }
1550 static void
zonestat_print_cpu_zone_header(size_t namelen)1551 zonestat_print_cpu_zone_header(size_t namelen)
1552 {
1553 char name_format[ZS_NAME_STRLEN];
1554
1555 if (opt_parseable)
1556 return;
1557
1558 (void) snprintf(name_format, sizeof (name_format), "%%%ds ", namelen);
1559 /* LINTED */
1560 (void) printf(name_format, "ZONE");
1561
1562 (void) printf(ZSTAT_CPU_ZONE_FORMAT, "USED", "PCT", "CAP",
1563 "%CAP", "SHRS", "%SHR", "%SHRU");
1564 }
1565
1566 static void
zonestat_print_cpu_res(size_t namelen,int report_fmt,char * cputype,char * name,uint64_t online,uint64_t size,uint64_t min,uint64_t max,timestruc_t * ts)1567 zonestat_print_cpu_res(size_t namelen, int report_fmt, char *cputype,
1568 char *name, uint64_t online, uint64_t size, uint64_t min, uint64_t max,
1569 timestruc_t *ts)
1570 {
1571 char online_str[ZS_UINT64_STRLEN];
1572 char size_str[ZS_UINT64_STRLEN];
1573 char min_str[ZS_UINT64_STRLEN];
1574 char max_str[ZS_UINT64_STRLEN];
1575 char cpus_str[ZS_UINT64_STRLEN + ZS_UINT64_STRLEN + 1];
1576 char minmax_str[ZS_UINT64_STRLEN + ZS_UINT64_STRLEN + 1];
1577 char ts_str[ZS_TIME_STRLEN];
1578 char name_format[ZS_NAME_STRLEN];
1579
1580 char *label;
1581
1582 format_uint64(online, online_str, sizeof (online_str));
1583 format_uint64(size, size_str, sizeof (size_str));
1584 format_uint64(min, min_str, sizeof (min_str));
1585 format_uint64(max, max_str, sizeof (max_str));
1586 format_ts(ts, ts_str, sizeof (ts_str), B_FALSE);
1587
1588 if (opt_parseable) {
1589 if (opt_timestamp) {
1590 zonestat_print_timestamp(g_now_time);
1591 (void) printf(":");
1592 }
1593 label = zonestat_get_plabel(report_fmt);
1594
1595 (void) printf("%s:%s:%s:%s:[%s]:%s:%s:%s:%s:%s\n", label,
1596 ZONESTAT_PROCESSOR_SET, cputype, name,
1597 ZONESTAT_NAME_RESOURCE, online_str, size_str, min_str,
1598 max_str, ts_str);
1599 return;
1600 }
1601
1602 (void) snprintf(cpus_str, sizeof (cpus_str), "%s/%s", online_str,
1603 size_str);
1604 (void) snprintf(minmax_str, sizeof (minmax_str), "%s/%s", min_str,
1605 max_str);
1606
1607 (void) snprintf(name_format, sizeof (name_format), "%%-%ds ", namelen);
1608 /* LINTED */
1609 (void) printf(name_format, name);
1610 (void) printf(ZSTAT_CPU_RES_FORMAT, cputype, cpus_str, minmax_str);
1611 }
1612
1613 static void
zonestat_print_cpu_zone(size_t namelen,int report_fmt,char * cputype,char * name,char * zonename,uint64_t used,uint_t pct,uint64_t cap,uint_t pct_cap,uint64_t shares,uint_t scheds,uint_t pct_shares,uint_t pct_shares_used,timestruc_t * ts,boolean_t report_conflict)1614 zonestat_print_cpu_zone(size_t namelen, int report_fmt, char *cputype,
1615 char *name, char *zonename, uint64_t used, uint_t pct, uint64_t cap,
1616 uint_t pct_cap, uint64_t shares, uint_t scheds, uint_t pct_shares,
1617 uint_t pct_shares_used, timestruc_t *ts, boolean_t report_conflict)
1618 {
1619 char used_str[ZS_UINT64_STRLEN];
1620 char pct_str[ZS_PCT_STRLEN];
1621 char cap_str[ZS_UINT64_STRLEN];
1622 char pct_cap_str[ZS_PCT_STRLEN];
1623 char shares_str[ZS_UINT64_STRLEN];
1624 char pct_shares_str[ZS_PCT_STRLEN];
1625 char pct_shares_used_str[ZS_PCT_STRLEN];
1626 char ts_str[ZS_TIME_STRLEN];
1627 char name_format[ZS_NAME_STRLEN];
1628 char *label;
1629
1630 format_cpu(used, used_str, sizeof (used_str));
1631 format_pct(pct, pct_str, sizeof (pct_str));
1632 format_ts(ts, ts_str, sizeof (ts_str), B_FALSE);
1633
1634 if (cap == ZS_LIMIT_NONE)
1635 (void) strlcpy(cap_str, "-", sizeof (cap_str));
1636 else
1637 format_cpu(cap, cap_str, sizeof (cap_str));
1638
1639 if (pct_cap == ZS_PCT_NONE)
1640 (void) strlcpy(pct_cap_str, "-", sizeof (pct_cap_str));
1641 else
1642 format_pct(pct_cap, pct_cap_str, sizeof (pct_cap_str));
1643
1644 if ((scheds & ZS_SCHED_CONFLICT) &&
1645 (!(scheds & ZS_SCHED_FSS)))
1646 (void) strlcpy(shares_str, "no-fss", sizeof (shares_str));
1647 else if (shares == ZS_LIMIT_NONE)
1648 (void) strlcpy(shares_str, "-", sizeof (shares_str));
1649 else if (shares == ZS_SHARES_UNLIMITED)
1650 (void) strlcpy(shares_str, "inf", sizeof (shares_str));
1651 else
1652 format_uint64(shares, shares_str, sizeof (shares_str));
1653
1654 if (pct_shares == ZS_PCT_NONE)
1655 (void) strlcpy(pct_shares_str, "-", sizeof (pct_shares_str));
1656 else
1657 format_pct(pct_shares, pct_shares_str,
1658 sizeof (pct_shares_str));
1659
1660 if (pct_shares_used == ZS_PCT_NONE) {
1661 (void) strlcpy(pct_shares_used_str, "-",
1662 sizeof (pct_shares_used_str));
1663 } else {
1664 format_pct(pct_shares_used, pct_shares_used_str,
1665 sizeof (pct_shares_used_str));
1666 }
1667 if (opt_parseable) {
1668 if (opt_timestamp) {
1669 zonestat_print_timestamp(g_now_time);
1670 (void) printf(":");
1671 }
1672 label = zonestat_get_plabel(report_fmt);
1673
1674 (void) printf("%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", label,
1675 ZONESTAT_PROCESSOR_SET, cputype, name, zonename, used_str,
1676 pct_str, cap_str, pct_cap_str, shares_str, pct_shares_str,
1677 pct_shares_used_str, ts_str);
1678 return;
1679 } else {
1680 (void) snprintf(name_format, sizeof (name_format), "%%%ds ",
1681 namelen);
1682 /* LINTED */
1683 (void) printf(name_format, zonename);
1684
1685 (void) printf(ZSTAT_CPU_ZONE_FORMAT, used_str,
1686 pct_str, cap_str, pct_cap_str, shares_str, pct_shares_str,
1687 pct_shares_used_str);
1688 }
1689 /* Report if zone has mix of schedulers conflicting with FSS */
1690 if (report_conflict && (scheds & ZS_SCHED_CONFLICT) &&
1691 (scheds & ZS_SCHED_FSS)) {
1692 /* LINTED */
1693 (void) printf(name_format, "");
1694 (void) printf(" mixed schedulers found:");
1695 (void) printf(" FSS");
1696 if (scheds & ZS_SCHED_TS)
1697 (void) printf(", TS");
1698 if (scheds & ZS_SCHED_IA)
1699 (void) printf(", IA");
1700 if (scheds & ZS_SCHED_FX)
1701 (void) printf(", FX");
1702 (void) printf("\n");
1703 }
1704 }
1705
1706 static void
zonestat_print_pset(int report_fmt,zs_pset_t * pset,char * cputype)1707 zonestat_print_pset(int report_fmt, zs_pset_t *pset, char *cputype)
1708 {
1709 zs_pset_zone_t *pz;
1710 zs_zone_t *zone;
1711 uint64_t cpus;
1712 uint64_t size;
1713 uint64_t min;
1714 uint64_t max;
1715 uint_t scheds;
1716 uint64_t used;
1717 uint_t pct;
1718 uint64_t cap;
1719 uint_t pct_cap;
1720 uint64_t shares;
1721 uint_t pct_shares;
1722 uint_t pct_shares_used;
1723 char psetname[ZS_PSETNAME_MAX];
1724 char zonename[ZS_PSETNAME_MAX];
1725 char *name;
1726 zs_property_t *prop;
1727 boolean_t zone_match;
1728 int num, i;
1729 timestruc_t ts;
1730 size_t namelen, len;
1731
1732 prop = (zs_property_t *)alloca(zs_property_size());
1733
1734 zs_pset_property(pset, ZS_PSET_PROP_NAME, prop);
1735 (void) strlcpy(psetname, zs_property_string(prop), sizeof (psetname));
1736
1737 /* Check if pset contains specified zone */
1738 if (arg_zonename_count > 0) {
1739 zone_match = B_FALSE;
1740 for (pz = zs_pset_zone_first(pset); pz != NULL;
1741 pz = zs_pset_zone_next(pset, pz)) {
1742 zone = zs_pset_zone_get_zone(pz);
1743 (void) zs_zone_property(zone, ZS_ZONE_PROP_NAME, prop);
1744 (void) strlcpy(zonename, zs_property_string(prop),
1745 sizeof (zonename));
1746
1747 if (zonestat_match_zonename(zonename) == 1) {
1748 zone_match = B_TRUE;
1749 break;
1750 }
1751 }
1752 if (zone_match == B_FALSE)
1753 return;
1754 }
1755
1756 if (zonestat_match_resname(psetname) == 0)
1757 return;
1758
1759 zs_pset_property(pset, ZS_PSET_PROP_ONLINE, prop);
1760 cpus = zs_property_uint64(prop);
1761 zs_pset_property(pset, ZS_PSET_PROP_SIZE, prop);
1762 size = zs_property_uint64(prop);
1763 zs_pset_property(pset, ZS_PSET_PROP_MIN, prop);
1764 min = zs_property_uint64(prop);
1765 zs_pset_property(pset, ZS_PSET_PROP_MAX, prop);
1766 max = zs_property_uint64(prop);
1767 zs_pset_total_time(pset, &ts);
1768
1769 /* Strip off SUNWtmp_ from pset name */
1770 name = psetname;
1771 if (strncmp(psetname, "SUNWtmp_", strlen("SUNWtmp_")) == 0) {
1772 name = strchr(psetname, '_');
1773 name++;
1774 }
1775
1776 /* Strip off SUNWlegacy_pst for psrset psets */
1777 if (strncmp(psetname, "SUNWlegacy_pset_",
1778 strlen("SUNWlegacy_pset_")) == 0) {
1779 name = strrchr(psetname, '_');
1780 name++;
1781 }
1782
1783 namelen = strlen(name);
1784 if (ZSTAT_CPU_MIN_PSETNAME > namelen)
1785 namelen = ZSTAT_CPU_MIN_PSETNAME;
1786
1787 zonestat_print_cpu_res_header(namelen);
1788
1789 if (opt_line_resource)
1790 zonestat_print_cpu_res(namelen, report_fmt, cputype, name, cpus,
1791 size, min, max, &ts);
1792
1793 again:
1794 num = zs_pset_zone_list(pset, g_pz_list, g_pz_num);
1795 if (num > g_pz_num) {
1796 if (g_pz_list != NULL)
1797 free(g_pz_list);
1798 g_pz_list = (zs_pset_zone_t **)malloc(
1799 sizeof (zs_pset_zone_t *) * num);
1800 g_pz_num = num;
1801 goto again;
1802 }
1803
1804 /* Find longest zone name in pset */
1805 namelen = ZSTAT_CPU_MIN_ZONENAME;
1806 for (i = 0; i < num; i++) {
1807 pz = g_pz_list[i];
1808 zone = zs_pset_zone_get_zone(pz);
1809 zs_zone_property(zone, ZS_ZONE_PROP_NAME, prop);
1810 len = strlen(zs_property_string(prop));
1811 if (len > namelen)
1812 namelen = len;
1813 }
1814
1815 qsort(g_pz_list, num, sizeof (zs_pset_zone_t *),
1816 zonestat_pz_compare_usage);
1817
1818 zonestat_print_cpu_zone_header(namelen);
1819
1820 zs_pset_property(pset, ZS_PSET_PROP_CPU_SHARES, prop);
1821 shares = zs_property_uint64(prop);
1822 zs_pset_property(pset, ZS_PSET_PROP_SCHEDULERS, prop);
1823 scheds = zs_property_uint(prop);
1824
1825 zs_pset_used_time(pset, ZS_USER_ALL, &ts);
1826 used = zs_pset_used_cpus(pset, ZS_USER_ALL);
1827 pct = zs_pset_used_pct(pset, ZS_USER_ALL);
1828
1829 if (opt_line_total) {
1830 (void) snprintf(zonename, sizeof (zonename), "[%s]",
1831 ZONESTAT_NAME_TOTAL);
1832 zonestat_print_cpu_zone(namelen, report_fmt, cputype, name,
1833 zonename, used, pct, ZS_LIMIT_NONE, ZS_PCT_NONE, shares,
1834 scheds, ZS_PCT_NONE, ZS_PCT_NONE, &ts, B_FALSE);
1835 }
1836 zs_pset_used_time(pset, ZS_USER_KERNEL, &ts);
1837 used = zs_pset_used_cpus(pset, ZS_USER_KERNEL);
1838 pct = zs_pset_used_pct(pset, ZS_USER_KERNEL);
1839
1840 if (opt_line_system) {
1841 (void) snprintf(zonename, sizeof (zonename), "[%s]",
1842 ZONESTAT_NAME_SYSTEM);
1843 zonestat_print_cpu_zone(namelen, report_fmt, cputype, name,
1844 zonename, used, pct, ZS_LIMIT_NONE, ZS_PCT_NONE,
1845 ZS_LIMIT_NONE, 0, ZS_PCT_NONE, ZS_PCT_NONE, &ts, B_FALSE);
1846 }
1847 for (i = 0; i < num; i++) {
1848
1849 pz = g_pz_list[i];
1850 zone = zs_pset_zone_get_zone(pz);
1851 zs_zone_property(zone, ZS_ZONE_PROP_NAME, prop);
1852 (void) strlcpy(zonename, zs_property_string(prop),
1853 sizeof (zonename));
1854
1855 if (zonestat_match_zonename(zonename) == 0)
1856 continue;
1857
1858 zs_pset_zone_property(pz, ZS_PZ_PROP_CPU_CAP, prop);
1859 cap = zs_property_uint64(prop);
1860
1861 zs_pset_zone_property(pz, ZS_PZ_PROP_CPU_SHARES, prop);
1862 shares = zs_property_uint64(prop);
1863 zs_pset_zone_property(pz, ZS_PZ_PROP_SCHEDULERS, prop);
1864 scheds = zs_property_uint(prop);
1865
1866 used = zs_pset_zone_used_cpus(pz);
1867 zs_pset_zone_used_time(pz, &ts);
1868 pct = zs_pset_zone_used_pct(pz, ZS_PZ_PCT_PSET);
1869 pct_cap = zs_pset_zone_used_pct(pz, ZS_PZ_PCT_CPU_CAP);
1870 pct_shares = zs_pset_zone_used_pct(pz, ZS_PZ_PCT_PSET_SHARES);
1871 pct_shares_used = zs_pset_zone_used_pct(pz,
1872 ZS_PZ_PCT_CPU_SHARES);
1873
1874 if (opt_line_zones)
1875 zonestat_print_cpu_zone(namelen, report_fmt, cputype,
1876 name, zonename, used, pct, cap, pct_cap, shares,
1877 scheds, pct_shares, pct_shares_used, &ts, B_TRUE);
1878 }
1879 if (!opt_parseable)
1880 (void) printf("\n");
1881 }
1882
1883 /* ARGSUSED */
1884 static void
zonestat_quithandler(int sig)1885 zonestat_quithandler(int sig)
1886 {
1887 g_quit = B_TRUE;
1888 }
1889
1890 static void
zonestat_print_footer(int report_fmt)1891 zonestat_print_footer(int report_fmt)
1892 {
1893 char *label;
1894
1895 if (!opt_parseable)
1896 return;
1897
1898 if (opt_timestamp) {
1899 zonestat_print_timestamp(g_now_time);
1900 (void) printf(":");
1901 }
1902 label = zonestat_get_plabel(report_fmt);
1903 (void) printf("%s:%s:", label, ZONESTAT_NAME_FOOTER);
1904 zonestat_print_timestamp(g_now_time);
1905 (void) printf("%d:%ld\n", g_interval, g_seconds);
1906 (void) fflush(stdout);
1907 }
1908
1909 static void
zonestat_print_header(int report_fmt)1910 zonestat_print_header(int report_fmt)
1911 {
1912 char *label;
1913 timestruc_t ts;
1914 char string[ZS_TIME_STRLEN];
1915
1916 if (!opt_parseable) {
1917
1918 /* Human readable header */
1919 if (opt_timestamp) {
1920 zonestat_print_timestamp(g_now_time);
1921 (void) printf(", ");
1922 }
1923 if (report_fmt == ZSTAT_REPORT_FMT_INTERVAL) {
1924 ts.tv_sec = g_seconds;
1925 ts.tv_nsec = 0;
1926 format_ts(&ts, string, sizeof (string), B_TRUE);
1927 (void) printf("Interval: %d, Duration: %s\n", g_count,
1928 string);
1929 (void) fflush(stdout);
1930 return;
1931 } else {
1932 switch (report_fmt) {
1933 case ZSTAT_REPORT_FMT_TOTAL:
1934 label = "Report: Total Usage";
1935 break;
1936 case ZSTAT_REPORT_FMT_AVERAGE:
1937 label = "Report: Average Usage";
1938 break;
1939 case ZSTAT_REPORT_FMT_HIGH:
1940 label = "Report: High Usage";
1941 break;
1942 default:
1943 exit(zonestat_error(gettext(
1944 "Internal error, invalid header")));
1945 }
1946 /* Left are the report header formats */
1947 (void) printf("%s\n", label);
1948 (void) printf(" Start: ");
1949 zonestat_print_timestamp(g_start_time);
1950 (void) printf("\n End: ");
1951 zonestat_print_timestamp(g_end_time);
1952 (void) printf("\n");
1953 ts.tv_sec = g_seconds;
1954 ts.tv_nsec = 0;
1955 format_ts(&ts, string, sizeof (string), B_TRUE);
1956 (void) printf(" Intervals: %d, Duration: %s\n",
1957 g_count, string);
1958
1959 (void) fflush(stdout);
1960 return;
1961 }
1962 }
1963
1964 if (!opt_line_header)
1965 return;
1966
1967 /* Parseable header */
1968 if (opt_timestamp) {
1969 zonestat_print_timestamp(g_now_time);
1970 (void) printf(":");
1971 }
1972 label = zonestat_get_plabel(report_fmt);
1973
1974 (void) printf("%s:%s:", label, ZONESTAT_NAME_HEADER);
1975 if (report_fmt == ZSTAT_REPORT_FMT_INTERVAL) {
1976 (void) printf("since-last-interval:");
1977 zonestat_print_timestamp(g_now_time);
1978 (void) printf(":%d:%ld\n", g_count, g_seconds);
1979 (void) fflush(stdout);
1980 return;
1981 }
1982
1983 /* Left are the report header formats */
1984 zonestat_print_timestamp(g_start_time);
1985 (void) printf(":");
1986 zonestat_print_timestamp(g_end_time);
1987 (void) printf(":");
1988 (void) printf("%d:%ld\n", g_interval, g_seconds);
1989 (void) fflush(stdout);
1990 }
1991
1992 static void
zonestat_print_psets(int report_fmt,zs_usage_t * u)1993 zonestat_print_psets(int report_fmt, zs_usage_t *u)
1994 {
1995 zs_pset_t *pset;
1996 char *psettype;
1997 uint_t cputype, num, i;
1998 zs_property_t *p;
1999
2000 again:
2001 num = zs_pset_list(u, g_pset_list, g_pset_num);
2002 if (num > g_pset_num) {
2003 if (g_pset_list != NULL)
2004 free(g_pset_list);
2005 g_pset_list = (zs_pset_t **)malloc(
2006 sizeof (zs_pset_t *) * num);
2007 g_pset_num = num;
2008 goto again;
2009 }
2010
2011 /* Sort, default pset first, then pool, psrset, and dedicated psets */
2012 qsort(g_pset_list, num, sizeof (zs_pset_t *), zonestat_pset_compare);
2013
2014 p = (zs_property_t *)alloca(zs_property_size());
2015 for (i = 0; i < num; i++) {
2016 pset = g_pset_list[i];
2017 (void) zs_pset_property(pset, ZS_PSET_PROP_CPUTYPE, p);
2018 cputype = zs_property_uint(p);
2019 if (cputype == ZS_CPUTYPE_DEFAULT_PSET &&
2020 (g_resources & (ZSTAT_RES_PSETS |
2021 ZSTAT_RES_DEFAULT_PSET))) {
2022 psettype = ZONESTAT_DEFAULT_PSET;
2023 } else if (cputype == ZS_CPUTYPE_POOL_PSET &&
2024 (g_resources & ZSTAT_RES_PSETS)) {
2025 psettype = ZONESTAT_POOL_PSET;
2026 } else if (cputype == ZS_CPUTYPE_PSRSET_PSET &&
2027 (g_resources & ZSTAT_RES_PSETS)) {
2028 psettype = ZONESTAT_PSRSET_PSET;
2029 } else if (cputype == ZS_CPUTYPE_DEDICATED &&
2030 (g_resources & ZSTAT_RES_PSETS)) {
2031 psettype = ZONESTAT_DEDICATED_CPU;
2032 } else {
2033 continue;
2034 }
2035 zonestat_print_pset(report_fmt, pset, psettype);
2036 }
2037 }
2038
2039 static void
zonestat_print_resources(int report_fmt,zs_usage_t * usage)2040 zonestat_print_resources(int report_fmt, zs_usage_t *usage)
2041 {
2042 if (g_resources & ZSTAT_RES_SUMMARY)
2043 zonestat_print_summary(report_fmt, usage);
2044
2045 if (g_resources & ZSTAT_RES_PHYSICAL_MEMORY)
2046 zonestat_print_res(report_fmt, "PHYSICAL-MEMORY",
2047 "SYSTEM MEMORY", ZONESTAT_PHYSICAL_MEMORY,
2048 ZONESTAT_NAME_MEM_DEFAULT, usage,
2049 ZS_RESOURCE_RAM_RSS, ZS_LIMIT_RAM_RSS);
2050 if (g_resources & ZSTAT_RES_VIRTUAL_MEMORY)
2051 zonestat_print_res(report_fmt, "VIRTUAL-MEMORY",
2052 "SYSTEM MEMORY", ZONESTAT_VIRTUAL_MEMORY,
2053 ZONESTAT_NAME_VM_DEFAULT, usage,
2054 ZS_RESOURCE_VM, ZS_LIMIT_VM);
2055 if (g_resources & ZSTAT_RES_LOCKED_MEMORY)
2056 zonestat_print_res(report_fmt, "LOCKED-MEMORY", "SYSTEM MEMORY",
2057 ZONESTAT_LOCKED_MEMORY, ZONESTAT_NAME_MEM_DEFAULT, usage,
2058 ZS_RESOURCE_RAM_LOCKED, ZS_LIMIT_RAM_LOCKED);
2059
2060 if (g_resources & (ZSTAT_RES_PSETS | ZSTAT_RES_DEFAULT_PSET))
2061 zonestat_print_psets(report_fmt, usage);
2062
2063 if (g_resources & ZSTAT_RES_PROCESSES)
2064 zonestat_print_res(report_fmt, "PROCESSES", "SYSTEM LIMIT",
2065 ZONESTAT_PROCESSES, ZONESTAT_NAME_SYSTEM_LIMIT,
2066 usage, ZS_RESOURCE_PROCESSES, ZS_LIMIT_PROCESSES);
2067
2068 if (g_resources & ZSTAT_RES_LWPS)
2069 zonestat_print_res(report_fmt, "LWPS", "SYSTEM LIMIT",
2070 ZONESTAT_LWPS, ZONESTAT_NAME_SYSTEM_LIMIT, usage,
2071 ZS_RESOURCE_LWPS, ZS_LIMIT_LWPS);
2072 if (g_resources & ZSTAT_RES_LOFI)
2073 zonestat_print_res(report_fmt, "LOFI", "SYSTEM LIMIT",
2074 ZONESTAT_LOFI, ZONESTAT_NAME_SYSTEM_LIMIT,
2075 usage, ZS_RESOURCE_LOFI, ZS_LIMIT_LOFI);
2076
2077 if (g_resources & ZSTAT_RES_SHM_MEMORY)
2078 zonestat_print_res(report_fmt, "SHM_MEMORY", "SYSTEM LIMIT",
2079 ZONESTAT_SHM_MEMORY, ZONESTAT_NAME_SYSTEM_LIMIT,
2080 usage, ZS_RESOURCE_SHM_MEMORY, ZS_LIMIT_SHM_MEMORY);
2081
2082 if (g_resources & ZSTAT_RES_SHM_IDS)
2083 zonestat_print_res(report_fmt, "SHM_IDS", "SYSTEM LIMIT",
2084 ZONESTAT_SHM_IDS, ZONESTAT_NAME_SYSTEM_LIMIT,
2085 usage, ZS_RESOURCE_SHM_IDS, ZS_LIMIT_SHM_IDS);
2086
2087 if (g_resources & ZSTAT_RES_SEM_IDS)
2088 zonestat_print_res(report_fmt, "SEM_IDS", "SYSTEM LIMIT",
2089 ZONESTAT_SEM_IDS, ZONESTAT_NAME_SYSTEM_LIMIT,
2090 usage, ZS_RESOURCE_SEM_IDS, ZS_LIMIT_SEM_IDS);
2091
2092 if (g_resources & ZSTAT_RES_MSG_IDS)
2093 zonestat_print_res(report_fmt, "MSG_IDS", "SYSTEM LIMIT",
2094 ZONESTAT_MSG_IDS, ZONESTAT_NAME_SYSTEM_LIMIT,
2095 usage, ZS_RESOURCE_MSG_IDS, ZS_LIMIT_MSG_IDS);
2096 }
2097
2098 /*
2099 * Adds comma seperated list of names to array of names
2100 * Returns new total number of names.
2101 */
2102 static size_t
zonestat_parse_names(char * names,char *** namelist,size_t count)2103 zonestat_parse_names(char *names, char ***namelist, size_t count)
2104 {
2105 size_t num, i;
2106 char *next, *string;
2107
2108 string = strdup(names);
2109 if (string == NULL)
2110 exit(zonestat_error(gettext("Out of Memory")));
2111
2112 /* count names, delimiting with '\0'. */
2113 next = string;
2114 num = 1;
2115 while ((next = strchr(next, ',')) != NULL) {
2116 *next++ = '\0';
2117 num++;
2118 }
2119
2120 /* Resise names array */
2121 *namelist = realloc(*namelist, sizeof (char *) * (num + count));
2122 if (*namelist == NULL)
2123 exit(zonestat_error(gettext("Out of Memory")));
2124
2125 /* add names to names array */
2126 next = string;
2127 for (i = 0; i < num; i++) {
2128 (*namelist)[count + i] = next;
2129 next += strlen(next) + 1;
2130 }
2131 return (count + num);
2132 }
2133
2134 static int
zonestat_extract_int(char * start,char * end,char ** tail)2135 zonestat_extract_int(char *start, char *end, char **tail)
2136 {
2137 int val;
2138 int save;
2139
2140 save = *end;
2141 *end = '\0';
2142 errno = 0;
2143 val = strtol(start, tail, 0);
2144 *end = save;
2145 if (errno != 0 || *tail == start)
2146 return (-1);
2147
2148 return (val);
2149 }
2150
2151 /*
2152 * parses and [nh][nm][hs] notation into seconds
2153 */
2154 static int
zonestat_parse_time(char * string,boolean_t * formatted)2155 zonestat_parse_time(char *string, boolean_t *formatted)
2156 {
2157 int seconds = 0;
2158 int minutes = 0;
2159 int hours = 0;
2160 char *this, *next, *end;
2161
2162 *formatted = B_FALSE;
2163
2164 /* Look for special tokens */
2165 if (strcmp("default", string) == 0)
2166 return (ZSTAT_INTERVAL_DEFAULT);
2167
2168 if (strcmp("inf", string) == 0)
2169 return (ZSTAT_DURATION_INF);
2170
2171 /* Look for hours */
2172 this = string;
2173 next = strchr(this, 'h');
2174 if (next != NULL) {
2175 if ((hours = zonestat_extract_int(this, next, &end)) == -1)
2176 return (-1);
2177
2178 *formatted = B_TRUE;
2179 this = next + 1;
2180 end++;
2181 }
2182
2183 /* Look for minutes delimiter */
2184 next = strrchr(this, 'm');
2185 if (next != NULL) {
2186 if ((minutes = zonestat_extract_int(this, next, &end)) == -1)
2187 return (-1);
2188
2189 *formatted = B_TRUE;
2190 this = next + 1;
2191 end++;
2192 }
2193
2194 /* Look for seconds delimiter */
2195 next = strrchr(this, 's');
2196 if (next != NULL) {
2197 if ((seconds = zonestat_extract_int(this, next, &end)) == -1)
2198 return (-1);
2199
2200 *formatted = B_TRUE;
2201 this = next + 1;
2202 end++;
2203 }
2204
2205 /* No delimiter found. Treat as seconds */
2206 if (*formatted == B_FALSE) {
2207 errno = 0;
2208 seconds = strtol(this, &end, 0);
2209 if (errno != 0 || end == this)
2210 return (-1);
2211 }
2212
2213 if (*end != '\0')
2214 return (-1);
2215
2216 seconds += (minutes * 60);
2217 seconds += (hours * 60 * 60);
2218
2219 return (seconds);
2220 }
2221
2222 static void
zonestat_print_reports(zs_usage_set_t * set)2223 zonestat_print_reports(zs_usage_set_t *set)
2224 {
2225 zs_usage_t *usage_print;
2226
2227 if (opt_report_total == B_TRUE) {
2228 usage_print = zs_usage_set_compute(set,
2229 ZS_COMPUTE_SET_TOTAL);
2230 zonestat_print_header(ZSTAT_REPORT_FMT_TOTAL);
2231 zonestat_print_resources(ZSTAT_REPORT_FMT_TOTAL, usage_print);
2232 zonestat_print_footer(ZSTAT_REPORT_FMT_TOTAL);
2233 (void) fflush(stdout);
2234 }
2235 if (opt_report_average == B_TRUE) {
2236 usage_print = zs_usage_set_compute(set,
2237 ZS_COMPUTE_SET_AVERAGE);
2238 zonestat_print_header(ZSTAT_REPORT_FMT_AVERAGE);
2239 zonestat_print_resources(ZSTAT_REPORT_FMT_AVERAGE, usage_print);
2240 zonestat_print_footer(ZSTAT_REPORT_FMT_AVERAGE);
2241 (void) fflush(stdout);
2242 }
2243 if (opt_report_high == B_TRUE) {
2244 usage_print = zs_usage_set_compute(set,
2245 ZS_COMPUTE_SET_HIGH);
2246 zonestat_print_header(ZSTAT_REPORT_FMT_HIGH);
2247 zonestat_print_resources(ZSTAT_REPORT_FMT_HIGH, usage_print);
2248 zonestat_print_footer(ZSTAT_REPORT_FMT_HIGH);
2249 (void) fflush(stdout);
2250 }
2251 }
2252
2253 static void
zonestat_set_fx()2254 zonestat_set_fx()
2255 {
2256 pcinfo_t pcinfo;
2257 pcparms_t pcparms;
2258
2259 (void) strlcpy(pcinfo.pc_clname, "FX", sizeof (pcinfo.pc_clname));
2260 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) {
2261 return;
2262 }
2263 pcparms.pc_cid = pcinfo.pc_cid;
2264 ((fxparms_t *)pcparms.pc_clparms)->fx_upri = 60;
2265 ((fxparms_t *)pcparms.pc_clparms)->fx_uprilim = 60;
2266 ((fxparms_t *)pcparms.pc_clparms)->fx_tqsecs = 0;
2267 ((fxparms_t *)pcparms.pc_clparms)->fx_tqnsecs = FX_NOCHANGE;
2268 (void) priocntl(P_PID, getpid(), PC_SETPARMS, (caddr_t)&pcparms);
2269 }
2270
2271 static time_t
zonestat_time()2272 zonestat_time()
2273 {
2274 time_t t;
2275
2276 t = time(NULL);
2277 if (t < 0 && g_quit == B_FALSE)
2278 exit(zonestat_error(gettext(
2279 "Unable to fetch current time")));
2280
2281 return (t);
2282 }
2283
2284 int
main(int argc,char * argv[])2285 main(int argc, char *argv[])
2286 {
2287 int arg;
2288 time_t now, next, start, next_report;
2289 zs_usage_t *usage, *usage_last = NULL, *usage_print;
2290 zs_usage_set_t *set;
2291 boolean_t formatted;
2292 scf_simple_prop_t *prop;
2293 uint64_t *intervalp;
2294 char *not_responding;
2295
2296 /* Process command line options and args */
2297 while ((arg = getopt(argc, argv, "z:r:n:T:R:qpP:S:D?"))
2298 != EOF) {
2299 switch (arg) {
2300 case 'z':
2301 opt_zonenames = B_TRUE;
2302 arg_zonename_count = zonestat_parse_names(optarg,
2303 &arg_zonenames, arg_zonename_count);
2304 break;
2305 case 'r':
2306 arg_restype_count = zonestat_parse_names(optarg,
2307 &arg_restypes, arg_restype_count);
2308 opt_restypes = B_TRUE;
2309 break;
2310 case 'n':
2311 opt_resnames = B_TRUE;
2312 arg_resname_count = zonestat_parse_names(optarg,
2313 &arg_resnames, arg_resname_count);
2314 break;
2315 case 'R':
2316 opt_report = B_TRUE;
2317 arg_report_count = zonestat_parse_names(optarg,
2318 &arg_reports, arg_report_count);
2319 break;
2320 case 'S':
2321 opt_sort = B_TRUE;
2322 arg_sort_count = zonestat_parse_names(optarg,
2323 &arg_sort_list, arg_sort_count);
2324 break;
2325 case 'T':
2326 opt_timestamp = B_TRUE;
2327 if (strcmp(optarg, "u") == 0) {
2328 arg_timestamp = ZSTAT_UNIX_TIMESTAMP;
2329 } else if (strcmp(optarg, "d") == 0) {
2330 arg_timestamp = ZSTAT_DATE_TIMESTAMP;
2331 } else if (strcmp(optarg, "i") == 0) {
2332 arg_timestamp = ZSTAT_ISO_TIMESTAMP;
2333 } else {
2334 (void) zonestat_error(gettext(
2335 "Invalid -T arg \"%s\". "
2336 "Must be 'u', 'i', or 'd'."), optarg);
2337 return (zonestat_usage(B_FALSE));
2338 }
2339 break;
2340 case 'q':
2341 opt_quiet_intervals = B_TRUE;
2342 break;
2343 case 'p':
2344 opt_parseable = B_TRUE;
2345 break;
2346 case 'P':
2347 opt_line_any = B_TRUE;
2348 arg_line_count = zonestat_parse_names(optarg,
2349 &arg_line_list, arg_line_count);
2350 break;
2351 case 'D':
2352 opt_debug = B_TRUE;
2353 break;
2354 case '?':
2355 return (zonestat_usage(B_TRUE));
2356 default:
2357 return (zonestat_usage(B_FALSE));
2358 }
2359 }
2360
2361 if (opt_line_any & (!opt_parseable)) {
2362 (void) zonestat_error(gettext("-P requires -p"));
2363 return (zonestat_usage(B_FALSE));
2364 }
2365
2366 if (opt_timestamp && arg_timestamp == ZSTAT_DATE_TIMESTAMP &&
2367 opt_parseable) {
2368 (void) zonestat_error(gettext(
2369 "-T d invalid with -p. Use -T [u | i]"));
2370 return (zonestat_usage(B_FALSE));
2371
2372 }
2373 /* Default to ISO timetamp in parseable output */
2374 if (!opt_timestamp && opt_parseable)
2375 arg_timestamp = ZSTAT_ISO_TIMESTAMP;
2376
2377 /* Get the interval and count */
2378 optind++;
2379 if (argc >= optind) {
2380 if ((arg_interval = zonestat_parse_time(argv[optind - 1],
2381 &formatted)) < 0 || arg_interval == 0) {
2382 (void) zonestat_error(gettext(
2383 "Invalid interval: \"%s\""), argv[optind - 1]);
2384 return (zonestat_usage(B_FALSE));
2385 }
2386 } else {
2387 (void) zonestat_error(gettext("Interval required."));
2388 return (zonestat_usage(B_FALSE));
2389 }
2390
2391 if (arg_interval == ZSTAT_INTERVAL_DEFAULT) {
2392 /* Get the configured sample interval */
2393 prop = scf_simple_prop_get(NULL,
2394 "svc:/system/zones-monitoring:default", "config",
2395 "sample_interval");
2396
2397 if (prop == NULL) {
2398 return (zonestat_error(gettext(
2399 "Unable to fetch SMF property "
2400 "\"config/sample_interval\"")));
2401 }
2402 if (scf_simple_prop_type(prop) != SCF_TYPE_COUNT) {
2403 return (zonestat_error(gettext("Malformed SMF property "
2404 "\"config/sample_interval\". Must be of type "
2405 "\"count\"")));
2406 }
2407 intervalp = scf_simple_prop_next_count(prop);
2408 arg_interval = *intervalp;
2409 if (arg_interval == 0)
2410 return (zonestat_error(gettext("Malformed SMF property "
2411 "\"config/sample_interval\". Must be greater than"
2412 "zero")));
2413
2414 scf_simple_prop_free(prop);
2415 }
2416 optind++;
2417 if (argc >= optind) {
2418 if ((arg_duration = zonestat_parse_time(argv[optind - 1],
2419 &formatted)) < 0 || arg_duration == 0) {
2420 (void) zonestat_error(gettext(
2421 "Invalid duration: \"%s\""), argv[optind - 1]);
2422 return (zonestat_usage(B_FALSE));
2423 }
2424 /* If not formatted [nh][nm][ns], treat as count */
2425 if (arg_duration != ZSTAT_DURATION_INF &&
2426 formatted == B_FALSE)
2427 arg_duration *= arg_interval;
2428 } else {
2429 arg_duration = ZSTAT_DURATION_INF;
2430 }
2431 optind++;
2432 if (argc >= optind) {
2433 if ((arg_report = zonestat_parse_time(argv[optind - 1],
2434 &formatted)) < 0 || arg_report == 0) {
2435 (void) zonestat_error(gettext(
2436 "Invalid report period: \"%s\""), argv[optind - 1]);
2437 return (zonestat_usage(B_FALSE));
2438 }
2439 /* If not formatted as [nh][nm][ns] treat as count */
2440 if (formatted == B_FALSE)
2441 arg_report *= arg_interval;
2442 } else {
2443 arg_report = ZSTAT_REPORT_END;
2444 }
2445
2446 if (opt_quiet_intervals && (!opt_report)) {
2447 (void) zonestat_error(gettext("-q requires -R"));
2448 return (zonestat_usage(B_FALSE));
2449 }
2450
2451 /* Figure out what resources to report on */
2452 zonestat_determine_resources();
2453 zonestat_determine_reports();
2454 zonestat_determine_lines();
2455 zonestat_determine_sort();
2456
2457 /* Done parsing args beyond this point */
2458
2459 (void) signal(SIGINT, zonestat_quithandler);
2460 (void) signal(SIGTERM, zonestat_quithandler);
2461 (void) signal(SIGHUP, zonestat_quithandler);
2462
2463 /* Run at high priority to keep up with busy system */
2464 zonestat_set_fx();
2465
2466 not_responding = gettext(
2467 "Zones monitoring service \"svc:/system/zones-monitoring:default\" "
2468 "not enabled or responding.");
2469
2470 /* Open zone statistics */
2471 g_zsctl = zs_open();
2472 if (g_zsctl == NULL) {
2473 if (errno == EPERM)
2474 return (zonestat_error(gettext("Permission denied")));
2475 if (errno == EINTR || errno == ESRCH) {
2476 (void) zonestat_error(not_responding);
2477 return (3);
2478 }
2479 if (errno == ENOTSUP)
2480 return (zonestat_error(gettext(
2481 "Mismatched zonestat version. "
2482 "Re-install system/zones package.")));
2483
2484 return (zonestat_error(gettext(
2485 "Unexpected error. Unable to open zone statistics.")));
2486 }
2487 usage_last = zs_usage_read(g_zsctl);
2488 if (usage_last == NULL) {
2489 if (errno == EINTR && g_quit == B_TRUE)
2490 return (0);
2491 (void) zonestat_error(not_responding);
2492 return (3);
2493 }
2494 set = zs_usage_set_alloc(g_zsctl);
2495
2496 g_start_time = g_now_time = start = now = zonestat_time();
2497 g_interval = arg_interval;
2498 g_report_count = g_count = g_seconds = 0;
2499
2500 if (opt_quiet_intervals == B_FALSE && opt_parseable == B_FALSE)
2501 (void) printf(gettext(
2502 "Collecting data for first interval...\n"));
2503
2504 for (;;) {
2505 time_t tosleep;
2506
2507 g_now_time = now = zonestat_time();
2508
2509 if (arg_report != ZSTAT_REPORT_END)
2510 next_report = start + ((g_report_count + 1) *
2511 arg_report);
2512
2513 /*
2514 * Sleep till next interval.
2515 */
2516 g_count++;
2517 next = g_start_time + (g_count) * g_interval;
2518 /*
2519 * Skip to next interval if due to busy system, zonestat did
2520 * not complete in time.
2521 */
2522 while (now >= g_start_time + ((g_count + 1) * g_interval))
2523 g_count++;
2524
2525 while (now < next) {
2526 /* Sleep until at next interval */
2527 tosleep = next - now;
2528 (void) sleep(tosleep);
2529 now = zonestat_time();
2530 if (g_quit == B_TRUE)
2531 goto interval_loop_done;
2532 }
2533
2534 g_seconds = now - start;
2535 g_now_time = now;
2536 if ((usage = zs_usage_read(g_zsctl)) == NULL) {
2537 if (errno == EINTR && g_quit == B_TRUE)
2538 break;
2539 (void) zonestat_error(not_responding);
2540 return (3);
2541 }
2542
2543 /* Compute cpu used since last interval */
2544 usage_print = zs_usage_compute(NULL, usage_last,
2545 usage, ZS_COMPUTE_USAGE_INTERVAL);
2546 if (usage_print == NULL)
2547 (void) zonestat_error(gettext("Out of Memory"));
2548
2549
2550 if (opt_quiet_intervals == B_TRUE)
2551 goto interval_print_end;
2552
2553 zonestat_print_header(ZSTAT_REPORT_FMT_INTERVAL);
2554 zonestat_print_resources(ZSTAT_REPORT_FMT_INTERVAL,
2555 usage_print);
2556 zonestat_print_footer(ZSTAT_REPORT_FMT_INTERVAL);
2557 (void) fflush(stdout);
2558
2559 interval_print_end:
2560 (void) zs_usage_set_add(set, usage_print);
2561
2562
2563 /* Print reports if they are due */
2564 if (opt_report && arg_report != ZSTAT_REPORT_END &&
2565 now >= next_report) {
2566 g_end_time = now;
2567 zonestat_print_reports(set);
2568 zs_usage_set_free(set);
2569 set = zs_usage_set_alloc();
2570 g_start_time = now;
2571 g_report_count++;
2572 }
2573 zs_usage_free(usage_last);
2574 usage_last = usage;
2575 if (arg_duration != ZSTAT_DURATION_INF &&
2576 g_seconds >= arg_duration)
2577 break;
2578 }
2579 interval_loop_done:
2580
2581 /* Print last reports if due */
2582 g_end_time = g_now_time;
2583 if (opt_report && zs_usage_set_count(set) > 0 &&
2584 (arg_report == ZSTAT_REPORT_END || now < next_report))
2585 zonestat_print_reports(set);
2586
2587 zs_usage_set_free(set);
2588 if (usage_last != NULL)
2589 zs_usage_free(usage_last);
2590
2591 if (g_zsctl != NULL)
2592 zs_close(g_zsctl);
2593
2594 return (0);
2595 }
2596