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(8)\n"
292 " Name of a zone using dedicated-cpu\n"),
293 "-z", "-n",
294 ZONESTAT_NAME_MEM_DEFAULT, ZONESTAT_NAME_VM_DEFAULT);
295 (void) fprintf(fd, 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) fprintf(fd, 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) fprintf(fd, 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 if (zonestat_match_zonename(zonename) == 0)
1417 continue;
1418
1419 cused = zs_resource_used_zone_uint64(z, ZS_RESOURCE_CPU);
1420 mused = zs_resource_used_zone_uint64(z, ZS_RESOURCE_RAM_RSS);
1421 vused = zs_resource_used_zone_uint64(z, ZS_RESOURCE_VM);
1422
1423 ppart = zs_resource_used_zone_pct(z, ZS_RESOURCE_CPU);
1424 mpct = zs_resource_used_zone_pct(z, ZS_RESOURCE_RAM_RSS);
1425 vpct = zs_resource_used_zone_pct(z, ZS_RESOURCE_VM);
1426
1427 pshru = zs_zone_limit_used_pct(z, ZS_LIMIT_CPU_SHARES);
1428 pccap = zs_zone_limit_used_pct(z, ZS_LIMIT_CPU);
1429 pmcap = zs_zone_limit_used_pct(z, ZS_LIMIT_RAM_RSS);
1430 pvcap = zs_zone_limit_used_pct(z, ZS_LIMIT_VM);
1431
1432 zonestat_print_summary_zone(namewidth, report_fmt, zonename,
1433 cused, ppart, pccap, pshru, mused, mpct, pmcap, vused, vpct,
1434 pvcap);
1435 }
1436
1437 if (!opt_parseable)
1438 (void) printf("\n");
1439 (void) fflush(stdout);
1440 }
1441
1442 static void
zonestat_print_res(int report_fmt,char * header,char * sizename,char * resname,char * name,zs_usage_t * u,int res,int limit)1443 zonestat_print_res(int report_fmt, char *header, char *sizename, char *resname,
1444 char *name, zs_usage_t *u, int res, int limit)
1445 {
1446 zs_zone_t *zone;
1447 char zonename[ZS_ZONENAME_MAX];
1448 uint64_t size;
1449 uint64_t used;
1450 uint64_t cap;
1451 uint_t pct;
1452 uint_t pctcap;
1453 zs_property_t *prop;
1454 int num, i;
1455 size_t namelen, len;
1456
1457 prop = (zs_property_t *)alloca(zs_property_size());
1458
1459 /* See if resource matches specified resource names */
1460 if (zonestat_match_resname(name) == 0)
1461 return;
1462
1463 namelen = strlen(resname);
1464 if (ZSTAT_RESOURCE_MIN_RESNAME > namelen)
1465 namelen = ZSTAT_RESOURCE_MIN_RESNAME;
1466
1467 zonestat_print_resource__header(namelen, header, sizename);
1468
1469 size = zs_resource_total_uint64(u, res);
1470
1471 if (opt_line_resource)
1472 zonestat_print_resource_(namelen, report_fmt, resname, name,
1473 size);
1474
1475 again:
1476 num = zs_zone_list(u, g_zone_list, g_zone_num);
1477 if (num > g_zone_num) {
1478 if (g_zone_list != NULL)
1479 free(g_zone_list);
1480 g_zone_list = (zs_zone_t **) malloc(sizeof (zs_zone_t *) * num);
1481 g_zone_num = num;
1482 goto again;
1483 }
1484 namelen = ZSTAT_RESOURCE_MIN_ZONENAME;
1485 for (i = 0; i < num; i++) {
1486 zone = g_zone_list[i];
1487 (void) zs_zone_property(zone, ZS_ZONE_PROP_NAME, prop);
1488 len = strlen(zs_property_string(prop));
1489 if (len > namelen)
1490 namelen = len;
1491 }
1492
1493 zonestat_print_resource_zone_header(namelen);
1494
1495 used = zs_resource_used_uint64(u, res, ZS_USER_ALL);
1496 pct = zs_resource_used_pct(u, res, ZS_USER_ALL);
1497
1498 if (opt_line_total) {
1499 (void) snprintf(zonename, sizeof (zonename), "[%s]",
1500 ZONESTAT_NAME_TOTAL);
1501 zonestat_print_resource_zone(namelen, report_fmt, resname,
1502 name, zonename, used, pct, ZS_LIMIT_NONE, ZS_PCT_NONE);
1503 }
1504 used = zs_resource_used_uint64(u, res, ZS_USER_KERNEL);
1505 pct = zs_resource_used_pct(u, res, ZS_USER_KERNEL);
1506
1507 if (opt_line_system) {
1508 (void) snprintf(zonename, sizeof (zonename), "[%s]",
1509 ZONESTAT_NAME_SYSTEM);
1510 zonestat_print_resource_zone(namelen, report_fmt, resname, name,
1511 zonename, used, pct, ZS_LIMIT_NONE, ZS_PCT_NONE);
1512 }
1513 zonestat_qsort(g_zone_list, num, sizeof (zs_zone_t *),
1514 zonestat_zone_compare_resource, res);
1515
1516 for (i = 0; i < num; i++) {
1517
1518 zone = g_zone_list[i];
1519 zs_zone_property(zone, ZS_ZONE_PROP_NAME, prop);
1520 (void) strlcpy(zonename, zs_property_string(prop),
1521 sizeof (zonename));
1522
1523 if (zonestat_match_zonename(zonename) == 0)
1524 continue;
1525
1526 used = zs_resource_used_zone_uint64(zone, res);
1527 pct = zs_resource_used_zone_pct(zone, res);
1528
1529 cap = zs_zone_limit_uint64(zone, limit);
1530 pctcap = zs_zone_limit_used_pct(zone, limit);
1531
1532 if (opt_line_zones)
1533 zonestat_print_resource_zone(namelen, report_fmt,
1534 resname, name, zonename, used, pct, cap, pctcap);
1535 }
1536 if (!opt_parseable)
1537 (void) printf("\n");
1538 }
1539
1540 static void
zonestat_print_cpu_res_header(size_t namelen)1541 zonestat_print_cpu_res_header(size_t namelen)
1542 {
1543 char name_format[ZS_NAME_STRLEN];
1544
1545 if (opt_parseable)
1546 return;
1547
1548 (void) snprintf(name_format, sizeof (name_format), "%%-%ds ", namelen);
1549 /* LINTED */
1550 (void) printf(name_format, "PROCESSOR_SET");
1551 (void) printf(ZSTAT_CPU_RES_FORMAT, "TYPE", "ONLINE/CPUS", "MIN/MAX");
1552 }
1553 static void
zonestat_print_cpu_zone_header(size_t namelen)1554 zonestat_print_cpu_zone_header(size_t namelen)
1555 {
1556 char name_format[ZS_NAME_STRLEN];
1557
1558 if (opt_parseable)
1559 return;
1560
1561 (void) snprintf(name_format, sizeof (name_format), "%%%ds ", namelen);
1562 /* LINTED */
1563 (void) printf(name_format, "ZONE");
1564
1565 (void) printf(ZSTAT_CPU_ZONE_FORMAT, "USED", "PCT", "CAP",
1566 "%CAP", "SHRS", "%SHR", "%SHRU");
1567 }
1568
1569 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)1570 zonestat_print_cpu_res(size_t namelen, int report_fmt, char *cputype,
1571 char *name, uint64_t online, uint64_t size, uint64_t min, uint64_t max,
1572 timestruc_t *ts)
1573 {
1574 char online_str[ZS_UINT64_STRLEN];
1575 char size_str[ZS_UINT64_STRLEN];
1576 char min_str[ZS_UINT64_STRLEN];
1577 char max_str[ZS_UINT64_STRLEN];
1578 char cpus_str[ZS_UINT64_STRLEN + ZS_UINT64_STRLEN + 1];
1579 char minmax_str[ZS_UINT64_STRLEN + ZS_UINT64_STRLEN + 1];
1580 char ts_str[ZS_TIME_STRLEN];
1581 char name_format[ZS_NAME_STRLEN];
1582
1583 char *label;
1584
1585 format_uint64(online, online_str, sizeof (online_str));
1586 format_uint64(size, size_str, sizeof (size_str));
1587 format_uint64(min, min_str, sizeof (min_str));
1588 format_uint64(max, max_str, sizeof (max_str));
1589 format_ts(ts, ts_str, sizeof (ts_str), B_FALSE);
1590
1591 if (opt_parseable) {
1592 if (opt_timestamp) {
1593 zonestat_print_timestamp(g_now_time);
1594 (void) printf(":");
1595 }
1596 label = zonestat_get_plabel(report_fmt);
1597
1598 (void) printf("%s:%s:%s:%s:[%s]:%s:%s:%s:%s:%s\n", label,
1599 ZONESTAT_PROCESSOR_SET, cputype, name,
1600 ZONESTAT_NAME_RESOURCE, online_str, size_str, min_str,
1601 max_str, ts_str);
1602 return;
1603 }
1604
1605 (void) snprintf(cpus_str, sizeof (cpus_str), "%s/%s", online_str,
1606 size_str);
1607 (void) snprintf(minmax_str, sizeof (minmax_str), "%s/%s", min_str,
1608 max_str);
1609
1610 (void) snprintf(name_format, sizeof (name_format), "%%-%ds ", namelen);
1611 /* LINTED */
1612 (void) printf(name_format, name);
1613 (void) printf(ZSTAT_CPU_RES_FORMAT, cputype, cpus_str, minmax_str);
1614 }
1615
1616 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)1617 zonestat_print_cpu_zone(size_t namelen, int report_fmt, char *cputype,
1618 char *name, char *zonename, uint64_t used, uint_t pct, uint64_t cap,
1619 uint_t pct_cap, uint64_t shares, uint_t scheds, uint_t pct_shares,
1620 uint_t pct_shares_used, timestruc_t *ts, boolean_t report_conflict)
1621 {
1622 char used_str[ZS_UINT64_STRLEN];
1623 char pct_str[ZS_PCT_STRLEN];
1624 char cap_str[ZS_UINT64_STRLEN];
1625 char pct_cap_str[ZS_PCT_STRLEN];
1626 char shares_str[ZS_UINT64_STRLEN];
1627 char pct_shares_str[ZS_PCT_STRLEN];
1628 char pct_shares_used_str[ZS_PCT_STRLEN];
1629 char ts_str[ZS_TIME_STRLEN];
1630 char name_format[ZS_NAME_STRLEN];
1631 char *label;
1632
1633 format_cpu(used, used_str, sizeof (used_str));
1634 format_pct(pct, pct_str, sizeof (pct_str));
1635 format_ts(ts, ts_str, sizeof (ts_str), B_FALSE);
1636
1637 if (cap == ZS_LIMIT_NONE)
1638 (void) strlcpy(cap_str, "-", sizeof (cap_str));
1639 else
1640 format_cpu(cap, cap_str, sizeof (cap_str));
1641
1642 if (pct_cap == ZS_PCT_NONE)
1643 (void) strlcpy(pct_cap_str, "-", sizeof (pct_cap_str));
1644 else
1645 format_pct(pct_cap, pct_cap_str, sizeof (pct_cap_str));
1646
1647 if ((scheds & ZS_SCHED_CONFLICT) &&
1648 (!(scheds & ZS_SCHED_FSS)))
1649 (void) strlcpy(shares_str, "no-fss", sizeof (shares_str));
1650 else if (shares == ZS_LIMIT_NONE)
1651 (void) strlcpy(shares_str, "-", sizeof (shares_str));
1652 else if (shares == ZS_SHARES_UNLIMITED)
1653 (void) strlcpy(shares_str, "inf", sizeof (shares_str));
1654 else
1655 format_uint64(shares, shares_str, sizeof (shares_str));
1656
1657 if (pct_shares == ZS_PCT_NONE)
1658 (void) strlcpy(pct_shares_str, "-", sizeof (pct_shares_str));
1659 else
1660 format_pct(pct_shares, pct_shares_str,
1661 sizeof (pct_shares_str));
1662
1663 if (pct_shares_used == ZS_PCT_NONE) {
1664 (void) strlcpy(pct_shares_used_str, "-",
1665 sizeof (pct_shares_used_str));
1666 } else {
1667 format_pct(pct_shares_used, pct_shares_used_str,
1668 sizeof (pct_shares_used_str));
1669 }
1670 if (opt_parseable) {
1671 if (opt_timestamp) {
1672 zonestat_print_timestamp(g_now_time);
1673 (void) printf(":");
1674 }
1675 label = zonestat_get_plabel(report_fmt);
1676
1677 (void) printf("%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", label,
1678 ZONESTAT_PROCESSOR_SET, cputype, name, zonename, used_str,
1679 pct_str, cap_str, pct_cap_str, shares_str, pct_shares_str,
1680 pct_shares_used_str, ts_str);
1681 return;
1682 } else {
1683 (void) snprintf(name_format, sizeof (name_format), "%%%ds ",
1684 namelen);
1685 /* LINTED */
1686 (void) printf(name_format, zonename);
1687
1688 (void) printf(ZSTAT_CPU_ZONE_FORMAT, used_str,
1689 pct_str, cap_str, pct_cap_str, shares_str, pct_shares_str,
1690 pct_shares_used_str);
1691 }
1692 /* Report if zone has mix of schedulers conflicting with FSS */
1693 if (report_conflict && (scheds & ZS_SCHED_CONFLICT) &&
1694 (scheds & ZS_SCHED_FSS)) {
1695 /* LINTED */
1696 (void) printf(name_format, "");
1697 (void) printf(" mixed schedulers found:");
1698 (void) printf(" FSS");
1699 if (scheds & ZS_SCHED_TS)
1700 (void) printf(", TS");
1701 if (scheds & ZS_SCHED_IA)
1702 (void) printf(", IA");
1703 if (scheds & ZS_SCHED_FX)
1704 (void) printf(", FX");
1705 (void) printf("\n");
1706 }
1707 }
1708
1709 static void
zonestat_print_pset(int report_fmt,zs_pset_t * pset,char * cputype)1710 zonestat_print_pset(int report_fmt, zs_pset_t *pset, char *cputype)
1711 {
1712 zs_pset_zone_t *pz;
1713 zs_zone_t *zone;
1714 uint64_t cpus;
1715 uint64_t size;
1716 uint64_t min;
1717 uint64_t max;
1718 uint_t scheds;
1719 uint64_t used;
1720 uint_t pct;
1721 uint64_t cap;
1722 uint_t pct_cap;
1723 uint64_t shares;
1724 uint_t pct_shares;
1725 uint_t pct_shares_used;
1726 char psetname[ZS_PSETNAME_MAX];
1727 char zonename[ZS_PSETNAME_MAX];
1728 char *name;
1729 zs_property_t *prop;
1730 boolean_t zone_match;
1731 int num, i;
1732 timestruc_t ts;
1733 size_t namelen, len;
1734
1735 prop = (zs_property_t *)alloca(zs_property_size());
1736
1737 zs_pset_property(pset, ZS_PSET_PROP_NAME, prop);
1738 (void) strlcpy(psetname, zs_property_string(prop), sizeof (psetname));
1739
1740 /* Check if pset contains specified zone */
1741 if (arg_zonename_count > 0) {
1742 zone_match = B_FALSE;
1743 for (pz = zs_pset_zone_first(pset); pz != NULL;
1744 pz = zs_pset_zone_next(pset, pz)) {
1745 zone = zs_pset_zone_get_zone(pz);
1746 (void) zs_zone_property(zone, ZS_ZONE_PROP_NAME, prop);
1747 (void) strlcpy(zonename, zs_property_string(prop),
1748 sizeof (zonename));
1749
1750 if (zonestat_match_zonename(zonename) == 1) {
1751 zone_match = B_TRUE;
1752 break;
1753 }
1754 }
1755 if (zone_match == B_FALSE)
1756 return;
1757 }
1758
1759 if (zonestat_match_resname(psetname) == 0)
1760 return;
1761
1762 zs_pset_property(pset, ZS_PSET_PROP_ONLINE, prop);
1763 cpus = zs_property_uint64(prop);
1764 zs_pset_property(pset, ZS_PSET_PROP_SIZE, prop);
1765 size = zs_property_uint64(prop);
1766 zs_pset_property(pset, ZS_PSET_PROP_MIN, prop);
1767 min = zs_property_uint64(prop);
1768 zs_pset_property(pset, ZS_PSET_PROP_MAX, prop);
1769 max = zs_property_uint64(prop);
1770 zs_pset_total_time(pset, &ts);
1771
1772 /* Strip off SUNWtmp_ from pset name */
1773 name = psetname;
1774 if (strncmp(psetname, "SUNWtmp_", strlen("SUNWtmp_")) == 0) {
1775 name = strchr(psetname, '_');
1776 name++;
1777 }
1778
1779 /* Strip off SUNWlegacy_pst for psrset psets */
1780 if (strncmp(psetname, "SUNWlegacy_pset_",
1781 strlen("SUNWlegacy_pset_")) == 0) {
1782 name = strrchr(psetname, '_');
1783 name++;
1784 }
1785
1786 namelen = strlen(name);
1787 if (ZSTAT_CPU_MIN_PSETNAME > namelen)
1788 namelen = ZSTAT_CPU_MIN_PSETNAME;
1789
1790 zonestat_print_cpu_res_header(namelen);
1791
1792 if (opt_line_resource)
1793 zonestat_print_cpu_res(namelen, report_fmt, cputype, name, cpus,
1794 size, min, max, &ts);
1795
1796 again:
1797 num = zs_pset_zone_list(pset, g_pz_list, g_pz_num);
1798 if (num > g_pz_num) {
1799 if (g_pz_list != NULL)
1800 free(g_pz_list);
1801 g_pz_list = (zs_pset_zone_t **)malloc(
1802 sizeof (zs_pset_zone_t *) * num);
1803 g_pz_num = num;
1804 goto again;
1805 }
1806
1807 /* Find longest zone name in pset */
1808 namelen = ZSTAT_CPU_MIN_ZONENAME;
1809 for (i = 0; i < num; i++) {
1810 pz = g_pz_list[i];
1811 zone = zs_pset_zone_get_zone(pz);
1812 zs_zone_property(zone, ZS_ZONE_PROP_NAME, prop);
1813 len = strlen(zs_property_string(prop));
1814 if (len > namelen)
1815 namelen = len;
1816 }
1817
1818 qsort(g_pz_list, num, sizeof (zs_pset_zone_t *),
1819 zonestat_pz_compare_usage);
1820
1821 zonestat_print_cpu_zone_header(namelen);
1822
1823 zs_pset_property(pset, ZS_PSET_PROP_CPU_SHARES, prop);
1824 shares = zs_property_uint64(prop);
1825 zs_pset_property(pset, ZS_PSET_PROP_SCHEDULERS, prop);
1826 scheds = zs_property_uint(prop);
1827
1828 zs_pset_used_time(pset, ZS_USER_ALL, &ts);
1829 used = zs_pset_used_cpus(pset, ZS_USER_ALL);
1830 pct = zs_pset_used_pct(pset, ZS_USER_ALL);
1831
1832 if (opt_line_total) {
1833 (void) snprintf(zonename, sizeof (zonename), "[%s]",
1834 ZONESTAT_NAME_TOTAL);
1835 zonestat_print_cpu_zone(namelen, report_fmt, cputype, name,
1836 zonename, used, pct, ZS_LIMIT_NONE, ZS_PCT_NONE, shares,
1837 scheds, ZS_PCT_NONE, ZS_PCT_NONE, &ts, B_FALSE);
1838 }
1839 zs_pset_used_time(pset, ZS_USER_KERNEL, &ts);
1840 used = zs_pset_used_cpus(pset, ZS_USER_KERNEL);
1841 pct = zs_pset_used_pct(pset, ZS_USER_KERNEL);
1842
1843 if (opt_line_system) {
1844 (void) snprintf(zonename, sizeof (zonename), "[%s]",
1845 ZONESTAT_NAME_SYSTEM);
1846 zonestat_print_cpu_zone(namelen, report_fmt, cputype, name,
1847 zonename, used, pct, ZS_LIMIT_NONE, ZS_PCT_NONE,
1848 ZS_LIMIT_NONE, 0, ZS_PCT_NONE, ZS_PCT_NONE, &ts, B_FALSE);
1849 }
1850 for (i = 0; i < num; i++) {
1851
1852 pz = g_pz_list[i];
1853 zone = zs_pset_zone_get_zone(pz);
1854 zs_zone_property(zone, ZS_ZONE_PROP_NAME, prop);
1855 (void) strlcpy(zonename, zs_property_string(prop),
1856 sizeof (zonename));
1857
1858 if (zonestat_match_zonename(zonename) == 0)
1859 continue;
1860
1861 zs_pset_zone_property(pz, ZS_PZ_PROP_CPU_CAP, prop);
1862 cap = zs_property_uint64(prop);
1863
1864 zs_pset_zone_property(pz, ZS_PZ_PROP_CPU_SHARES, prop);
1865 shares = zs_property_uint64(prop);
1866 zs_pset_zone_property(pz, ZS_PZ_PROP_SCHEDULERS, prop);
1867 scheds = zs_property_uint(prop);
1868
1869 used = zs_pset_zone_used_cpus(pz);
1870 zs_pset_zone_used_time(pz, &ts);
1871 pct = zs_pset_zone_used_pct(pz, ZS_PZ_PCT_PSET);
1872 pct_cap = zs_pset_zone_used_pct(pz, ZS_PZ_PCT_CPU_CAP);
1873 pct_shares = zs_pset_zone_used_pct(pz, ZS_PZ_PCT_PSET_SHARES);
1874 pct_shares_used = zs_pset_zone_used_pct(pz,
1875 ZS_PZ_PCT_CPU_SHARES);
1876
1877 if (opt_line_zones)
1878 zonestat_print_cpu_zone(namelen, report_fmt, cputype,
1879 name, zonename, used, pct, cap, pct_cap, shares,
1880 scheds, pct_shares, pct_shares_used, &ts, B_TRUE);
1881 }
1882 if (!opt_parseable)
1883 (void) printf("\n");
1884 }
1885
1886 /* ARGSUSED */
1887 static void
zonestat_quithandler(int sig)1888 zonestat_quithandler(int sig)
1889 {
1890 g_quit = B_TRUE;
1891 }
1892
1893 static void
zonestat_print_footer(int report_fmt)1894 zonestat_print_footer(int report_fmt)
1895 {
1896 char *label;
1897
1898 if (!opt_parseable)
1899 return;
1900
1901 if (opt_timestamp) {
1902 zonestat_print_timestamp(g_now_time);
1903 (void) printf(":");
1904 }
1905 label = zonestat_get_plabel(report_fmt);
1906 (void) printf("%s:%s:", label, ZONESTAT_NAME_FOOTER);
1907 zonestat_print_timestamp(g_now_time);
1908 (void) printf("%d:%ld\n", g_interval, g_seconds);
1909 (void) fflush(stdout);
1910 }
1911
1912 static void
zonestat_print_header(int report_fmt)1913 zonestat_print_header(int report_fmt)
1914 {
1915 char *label;
1916 timestruc_t ts;
1917 char string[ZS_TIME_STRLEN];
1918
1919 if (!opt_parseable) {
1920
1921 /* Human readable header */
1922 if (opt_timestamp) {
1923 zonestat_print_timestamp(g_now_time);
1924 (void) printf(", ");
1925 }
1926 if (report_fmt == ZSTAT_REPORT_FMT_INTERVAL) {
1927 ts.tv_sec = g_seconds;
1928 ts.tv_nsec = 0;
1929 format_ts(&ts, string, sizeof (string), B_TRUE);
1930 (void) printf("Interval: %d, Duration: %s\n", g_count,
1931 string);
1932 (void) fflush(stdout);
1933 return;
1934 } else {
1935 switch (report_fmt) {
1936 case ZSTAT_REPORT_FMT_TOTAL:
1937 label = "Report: Total Usage";
1938 break;
1939 case ZSTAT_REPORT_FMT_AVERAGE:
1940 label = "Report: Average Usage";
1941 break;
1942 case ZSTAT_REPORT_FMT_HIGH:
1943 label = "Report: High Usage";
1944 break;
1945 default:
1946 exit(zonestat_error(gettext(
1947 "Internal error, invalid header")));
1948 }
1949 /* Left are the report header formats */
1950 (void) printf("%s\n", label);
1951 (void) printf(" Start: ");
1952 zonestat_print_timestamp(g_start_time);
1953 (void) printf("\n End: ");
1954 zonestat_print_timestamp(g_end_time);
1955 (void) printf("\n");
1956 ts.tv_sec = g_seconds;
1957 ts.tv_nsec = 0;
1958 format_ts(&ts, string, sizeof (string), B_TRUE);
1959 (void) printf(" Intervals: %d, Duration: %s\n",
1960 g_count, string);
1961
1962 (void) fflush(stdout);
1963 return;
1964 }
1965 }
1966
1967 if (!opt_line_header)
1968 return;
1969
1970 /* Parseable header */
1971 if (opt_timestamp) {
1972 zonestat_print_timestamp(g_now_time);
1973 (void) printf(":");
1974 }
1975 label = zonestat_get_plabel(report_fmt);
1976
1977 (void) printf("%s:%s:", label, ZONESTAT_NAME_HEADER);
1978 if (report_fmt == ZSTAT_REPORT_FMT_INTERVAL) {
1979 (void) printf("since-last-interval:");
1980 zonestat_print_timestamp(g_now_time);
1981 (void) printf(":%d:%ld\n", g_count, g_seconds);
1982 (void) fflush(stdout);
1983 return;
1984 }
1985
1986 /* Left are the report header formats */
1987 zonestat_print_timestamp(g_start_time);
1988 (void) printf(":");
1989 zonestat_print_timestamp(g_end_time);
1990 (void) printf(":");
1991 (void) printf("%d:%ld\n", g_interval, g_seconds);
1992 (void) fflush(stdout);
1993 }
1994
1995 static void
zonestat_print_psets(int report_fmt,zs_usage_t * u)1996 zonestat_print_psets(int report_fmt, zs_usage_t *u)
1997 {
1998 zs_pset_t *pset;
1999 char *psettype;
2000 uint_t cputype, num, i;
2001 zs_property_t *p;
2002
2003 again:
2004 num = zs_pset_list(u, g_pset_list, g_pset_num);
2005 if (num > g_pset_num) {
2006 if (g_pset_list != NULL)
2007 free(g_pset_list);
2008 g_pset_list = (zs_pset_t **)malloc(
2009 sizeof (zs_pset_t *) * num);
2010 g_pset_num = num;
2011 goto again;
2012 }
2013
2014 /* Sort, default pset first, then pool, psrset, and dedicated psets */
2015 qsort(g_pset_list, num, sizeof (zs_pset_t *), zonestat_pset_compare);
2016
2017 p = (zs_property_t *)alloca(zs_property_size());
2018 for (i = 0; i < num; i++) {
2019 pset = g_pset_list[i];
2020 (void) zs_pset_property(pset, ZS_PSET_PROP_CPUTYPE, p);
2021 cputype = zs_property_uint(p);
2022 if (cputype == ZS_CPUTYPE_DEFAULT_PSET &&
2023 (g_resources & (ZSTAT_RES_PSETS |
2024 ZSTAT_RES_DEFAULT_PSET))) {
2025 psettype = ZONESTAT_DEFAULT_PSET;
2026 } else if (cputype == ZS_CPUTYPE_POOL_PSET &&
2027 (g_resources & ZSTAT_RES_PSETS)) {
2028 psettype = ZONESTAT_POOL_PSET;
2029 } else if (cputype == ZS_CPUTYPE_PSRSET_PSET &&
2030 (g_resources & ZSTAT_RES_PSETS)) {
2031 psettype = ZONESTAT_PSRSET_PSET;
2032 } else if (cputype == ZS_CPUTYPE_DEDICATED &&
2033 (g_resources & ZSTAT_RES_PSETS)) {
2034 psettype = ZONESTAT_DEDICATED_CPU;
2035 } else {
2036 continue;
2037 }
2038 zonestat_print_pset(report_fmt, pset, psettype);
2039 }
2040 }
2041
2042 static void
zonestat_print_resources(int report_fmt,zs_usage_t * usage)2043 zonestat_print_resources(int report_fmt, zs_usage_t *usage)
2044 {
2045 if (g_resources & ZSTAT_RES_SUMMARY)
2046 zonestat_print_summary(report_fmt, usage);
2047
2048 if (g_resources & ZSTAT_RES_PHYSICAL_MEMORY)
2049 zonestat_print_res(report_fmt, "PHYSICAL-MEMORY",
2050 "SYSTEM MEMORY", ZONESTAT_PHYSICAL_MEMORY,
2051 ZONESTAT_NAME_MEM_DEFAULT, usage,
2052 ZS_RESOURCE_RAM_RSS, ZS_LIMIT_RAM_RSS);
2053 if (g_resources & ZSTAT_RES_VIRTUAL_MEMORY)
2054 zonestat_print_res(report_fmt, "VIRTUAL-MEMORY",
2055 "SYSTEM MEMORY", ZONESTAT_VIRTUAL_MEMORY,
2056 ZONESTAT_NAME_VM_DEFAULT, usage,
2057 ZS_RESOURCE_VM, ZS_LIMIT_VM);
2058 if (g_resources & ZSTAT_RES_LOCKED_MEMORY)
2059 zonestat_print_res(report_fmt, "LOCKED-MEMORY", "SYSTEM MEMORY",
2060 ZONESTAT_LOCKED_MEMORY, ZONESTAT_NAME_MEM_DEFAULT, usage,
2061 ZS_RESOURCE_RAM_LOCKED, ZS_LIMIT_RAM_LOCKED);
2062
2063 if (g_resources & (ZSTAT_RES_PSETS | ZSTAT_RES_DEFAULT_PSET))
2064 zonestat_print_psets(report_fmt, usage);
2065
2066 if (g_resources & ZSTAT_RES_PROCESSES)
2067 zonestat_print_res(report_fmt, "PROCESSES", "SYSTEM LIMIT",
2068 ZONESTAT_PROCESSES, ZONESTAT_NAME_SYSTEM_LIMIT,
2069 usage, ZS_RESOURCE_PROCESSES, ZS_LIMIT_PROCESSES);
2070
2071 if (g_resources & ZSTAT_RES_LWPS)
2072 zonestat_print_res(report_fmt, "LWPS", "SYSTEM LIMIT",
2073 ZONESTAT_LWPS, ZONESTAT_NAME_SYSTEM_LIMIT, usage,
2074 ZS_RESOURCE_LWPS, ZS_LIMIT_LWPS);
2075 if (g_resources & ZSTAT_RES_LOFI)
2076 zonestat_print_res(report_fmt, "LOFI", "SYSTEM LIMIT",
2077 ZONESTAT_LOFI, ZONESTAT_NAME_SYSTEM_LIMIT,
2078 usage, ZS_RESOURCE_LOFI, ZS_LIMIT_LOFI);
2079
2080 if (g_resources & ZSTAT_RES_SHM_MEMORY)
2081 zonestat_print_res(report_fmt, "SHM_MEMORY", "SYSTEM LIMIT",
2082 ZONESTAT_SHM_MEMORY, ZONESTAT_NAME_SYSTEM_LIMIT,
2083 usage, ZS_RESOURCE_SHM_MEMORY, ZS_LIMIT_SHM_MEMORY);
2084
2085 if (g_resources & ZSTAT_RES_SHM_IDS)
2086 zonestat_print_res(report_fmt, "SHM_IDS", "SYSTEM LIMIT",
2087 ZONESTAT_SHM_IDS, ZONESTAT_NAME_SYSTEM_LIMIT,
2088 usage, ZS_RESOURCE_SHM_IDS, ZS_LIMIT_SHM_IDS);
2089
2090 if (g_resources & ZSTAT_RES_SEM_IDS)
2091 zonestat_print_res(report_fmt, "SEM_IDS", "SYSTEM LIMIT",
2092 ZONESTAT_SEM_IDS, ZONESTAT_NAME_SYSTEM_LIMIT,
2093 usage, ZS_RESOURCE_SEM_IDS, ZS_LIMIT_SEM_IDS);
2094
2095 if (g_resources & ZSTAT_RES_MSG_IDS)
2096 zonestat_print_res(report_fmt, "MSG_IDS", "SYSTEM LIMIT",
2097 ZONESTAT_MSG_IDS, ZONESTAT_NAME_SYSTEM_LIMIT,
2098 usage, ZS_RESOURCE_MSG_IDS, ZS_LIMIT_MSG_IDS);
2099 }
2100
2101 /*
2102 * Adds comma seperated list of names to array of names
2103 * Returns new total number of names.
2104 */
2105 static size_t
zonestat_parse_names(char * names,char *** namelist,size_t count)2106 zonestat_parse_names(char *names, char ***namelist, size_t count)
2107 {
2108 size_t num, i;
2109 char *next, *string;
2110
2111 string = strdup(names);
2112 if (string == NULL)
2113 exit(zonestat_error(gettext("Out of Memory")));
2114
2115 /* count names, delimiting with '\0'. */
2116 next = string;
2117 num = 1;
2118 while ((next = strchr(next, ',')) != NULL) {
2119 *next++ = '\0';
2120 num++;
2121 }
2122
2123 /* Resise names array */
2124 *namelist = realloc(*namelist, sizeof (char *) * (num + count));
2125 if (*namelist == NULL)
2126 exit(zonestat_error(gettext("Out of Memory")));
2127
2128 /* add names to names array */
2129 next = string;
2130 for (i = 0; i < num; i++) {
2131 (*namelist)[count + i] = next;
2132 next += strlen(next) + 1;
2133 }
2134 return (count + num);
2135 }
2136
2137 static int
zonestat_extract_int(char * start,char * end,char ** tail)2138 zonestat_extract_int(char *start, char *end, char **tail)
2139 {
2140 int val;
2141 int save;
2142
2143 save = *end;
2144 *end = '\0';
2145 errno = 0;
2146 val = strtol(start, tail, 0);
2147 *end = save;
2148 if (errno != 0 || *tail == start)
2149 return (-1);
2150
2151 return (val);
2152 }
2153
2154 /*
2155 * parses and [nh][nm][hs] notation into seconds
2156 */
2157 static int
zonestat_parse_time(char * string,boolean_t * formatted)2158 zonestat_parse_time(char *string, boolean_t *formatted)
2159 {
2160 int seconds = 0;
2161 int minutes = 0;
2162 int hours = 0;
2163 char *this, *next, *end;
2164
2165 *formatted = B_FALSE;
2166
2167 /* Look for special tokens */
2168 if (strcmp("default", string) == 0)
2169 return (ZSTAT_INTERVAL_DEFAULT);
2170
2171 if (strcmp("inf", string) == 0)
2172 return (ZSTAT_DURATION_INF);
2173
2174 /* Look for hours */
2175 this = string;
2176 next = strchr(this, 'h');
2177 if (next != NULL) {
2178 if ((hours = zonestat_extract_int(this, next, &end)) == -1)
2179 return (-1);
2180
2181 *formatted = B_TRUE;
2182 this = next + 1;
2183 end++;
2184 }
2185
2186 /* Look for minutes delimiter */
2187 next = strrchr(this, 'm');
2188 if (next != NULL) {
2189 if ((minutes = zonestat_extract_int(this, next, &end)) == -1)
2190 return (-1);
2191
2192 *formatted = B_TRUE;
2193 this = next + 1;
2194 end++;
2195 }
2196
2197 /* Look for seconds delimiter */
2198 next = strrchr(this, 's');
2199 if (next != NULL) {
2200 if ((seconds = zonestat_extract_int(this, next, &end)) == -1)
2201 return (-1);
2202
2203 *formatted = B_TRUE;
2204 this = next + 1;
2205 end++;
2206 }
2207
2208 /* No delimiter found. Treat as seconds */
2209 if (*formatted == B_FALSE) {
2210 errno = 0;
2211 seconds = strtol(this, &end, 0);
2212 if (errno != 0 || end == this)
2213 return (-1);
2214 }
2215
2216 if (*end != '\0')
2217 return (-1);
2218
2219 seconds += (minutes * 60);
2220 seconds += (hours * 60 * 60);
2221
2222 return (seconds);
2223 }
2224
2225 static void
zonestat_print_reports(zs_usage_set_t * set)2226 zonestat_print_reports(zs_usage_set_t *set)
2227 {
2228 zs_usage_t *usage_print;
2229
2230 if (opt_report_total == B_TRUE) {
2231 usage_print = zs_usage_set_compute(set,
2232 ZS_COMPUTE_SET_TOTAL);
2233 zonestat_print_header(ZSTAT_REPORT_FMT_TOTAL);
2234 zonestat_print_resources(ZSTAT_REPORT_FMT_TOTAL, usage_print);
2235 zonestat_print_footer(ZSTAT_REPORT_FMT_TOTAL);
2236 (void) fflush(stdout);
2237 }
2238 if (opt_report_average == B_TRUE) {
2239 usage_print = zs_usage_set_compute(set,
2240 ZS_COMPUTE_SET_AVERAGE);
2241 zonestat_print_header(ZSTAT_REPORT_FMT_AVERAGE);
2242 zonestat_print_resources(ZSTAT_REPORT_FMT_AVERAGE, usage_print);
2243 zonestat_print_footer(ZSTAT_REPORT_FMT_AVERAGE);
2244 (void) fflush(stdout);
2245 }
2246 if (opt_report_high == B_TRUE) {
2247 usage_print = zs_usage_set_compute(set,
2248 ZS_COMPUTE_SET_HIGH);
2249 zonestat_print_header(ZSTAT_REPORT_FMT_HIGH);
2250 zonestat_print_resources(ZSTAT_REPORT_FMT_HIGH, usage_print);
2251 zonestat_print_footer(ZSTAT_REPORT_FMT_HIGH);
2252 (void) fflush(stdout);
2253 }
2254 }
2255
2256 static void
zonestat_set_fx()2257 zonestat_set_fx()
2258 {
2259 pcinfo_t pcinfo;
2260 pcparms_t pcparms;
2261
2262 (void) strlcpy(pcinfo.pc_clname, "FX", sizeof (pcinfo.pc_clname));
2263 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) {
2264 return;
2265 }
2266 pcparms.pc_cid = pcinfo.pc_cid;
2267 ((fxparms_t *)pcparms.pc_clparms)->fx_upri = 60;
2268 ((fxparms_t *)pcparms.pc_clparms)->fx_uprilim = 60;
2269 ((fxparms_t *)pcparms.pc_clparms)->fx_tqsecs = 0;
2270 ((fxparms_t *)pcparms.pc_clparms)->fx_tqnsecs = FX_NOCHANGE;
2271 (void) priocntl(P_PID, getpid(), PC_SETPARMS, (caddr_t)&pcparms);
2272 }
2273
2274 static time_t
zonestat_time()2275 zonestat_time()
2276 {
2277 time_t t;
2278
2279 t = time(NULL);
2280 if (t < 0 && g_quit == B_FALSE)
2281 exit(zonestat_error(gettext(
2282 "Unable to fetch current time")));
2283
2284 return (t);
2285 }
2286
2287 int
main(int argc,char * argv[])2288 main(int argc, char *argv[])
2289 {
2290 int arg;
2291 time_t now, next, start, next_report;
2292 zs_usage_t *usage, *usage_last = NULL, *usage_print;
2293 zs_usage_set_t *set;
2294 boolean_t formatted;
2295 scf_simple_prop_t *prop;
2296 uint64_t *intervalp;
2297 char *not_responding;
2298
2299 /* Process command line options and args */
2300 while ((arg = getopt(argc, argv, "z:r:n:T:R:qpP:S:D?"))
2301 != EOF) {
2302 switch (arg) {
2303 case 'z':
2304 opt_zonenames = B_TRUE;
2305 arg_zonename_count = zonestat_parse_names(optarg,
2306 &arg_zonenames, arg_zonename_count);
2307 break;
2308 case 'r':
2309 arg_restype_count = zonestat_parse_names(optarg,
2310 &arg_restypes, arg_restype_count);
2311 opt_restypes = B_TRUE;
2312 break;
2313 case 'n':
2314 opt_resnames = B_TRUE;
2315 arg_resname_count = zonestat_parse_names(optarg,
2316 &arg_resnames, arg_resname_count);
2317 break;
2318 case 'R':
2319 opt_report = B_TRUE;
2320 arg_report_count = zonestat_parse_names(optarg,
2321 &arg_reports, arg_report_count);
2322 break;
2323 case 'S':
2324 opt_sort = B_TRUE;
2325 arg_sort_count = zonestat_parse_names(optarg,
2326 &arg_sort_list, arg_sort_count);
2327 break;
2328 case 'T':
2329 opt_timestamp = B_TRUE;
2330 if (strcmp(optarg, "u") == 0) {
2331 arg_timestamp = ZSTAT_UNIX_TIMESTAMP;
2332 } else if (strcmp(optarg, "d") == 0) {
2333 arg_timestamp = ZSTAT_DATE_TIMESTAMP;
2334 } else if (strcmp(optarg, "i") == 0) {
2335 arg_timestamp = ZSTAT_ISO_TIMESTAMP;
2336 } else {
2337 (void) zonestat_error(gettext(
2338 "Invalid -T arg \"%s\". "
2339 "Must be 'u', 'i', or 'd'."), optarg);
2340 return (zonestat_usage(B_FALSE));
2341 }
2342 break;
2343 case 'q':
2344 opt_quiet_intervals = B_TRUE;
2345 break;
2346 case 'p':
2347 opt_parseable = B_TRUE;
2348 break;
2349 case 'P':
2350 opt_line_any = B_TRUE;
2351 arg_line_count = zonestat_parse_names(optarg,
2352 &arg_line_list, arg_line_count);
2353 break;
2354 case 'D':
2355 opt_debug = B_TRUE;
2356 break;
2357 case '?':
2358 return (zonestat_usage(B_TRUE));
2359 default:
2360 return (zonestat_usage(B_FALSE));
2361 }
2362 }
2363
2364 if (opt_line_any && (!opt_parseable)) {
2365 (void) zonestat_error(gettext("-P requires -p"));
2366 return (zonestat_usage(B_FALSE));
2367 }
2368
2369 if (opt_timestamp && arg_timestamp == ZSTAT_DATE_TIMESTAMP &&
2370 opt_parseable) {
2371 (void) zonestat_error(gettext(
2372 "-T d invalid with -p. Use -T [u | i]"));
2373 return (zonestat_usage(B_FALSE));
2374
2375 }
2376 /* Default to ISO timetamp in parseable output */
2377 if (!opt_timestamp && opt_parseable)
2378 arg_timestamp = ZSTAT_ISO_TIMESTAMP;
2379
2380 /* Get the interval and count */
2381 optind++;
2382 if (argc >= optind) {
2383 if ((arg_interval = zonestat_parse_time(argv[optind - 1],
2384 &formatted)) < 0 || arg_interval == 0) {
2385 (void) zonestat_error(gettext(
2386 "Invalid interval: \"%s\""), argv[optind - 1]);
2387 return (zonestat_usage(B_FALSE));
2388 }
2389 } else {
2390 (void) zonestat_error(gettext("Interval required."));
2391 return (zonestat_usage(B_FALSE));
2392 }
2393
2394 if (arg_interval == ZSTAT_INTERVAL_DEFAULT) {
2395 /* Get the configured sample interval */
2396 prop = scf_simple_prop_get(NULL,
2397 "svc:/system/zones-monitoring:default", "config",
2398 "sample_interval");
2399
2400 if (prop == NULL) {
2401 return (zonestat_error(gettext(
2402 "Unable to fetch SMF property "
2403 "\"config/sample_interval\"")));
2404 }
2405 if (scf_simple_prop_type(prop) != SCF_TYPE_COUNT) {
2406 return (zonestat_error(gettext("Malformed SMF property "
2407 "\"config/sample_interval\". Must be of type "
2408 "\"count\"")));
2409 }
2410 intervalp = scf_simple_prop_next_count(prop);
2411 arg_interval = *intervalp;
2412 if (arg_interval == 0)
2413 return (zonestat_error(gettext("Malformed SMF property "
2414 "\"config/sample_interval\". Must be greater than"
2415 "zero")));
2416
2417 scf_simple_prop_free(prop);
2418 }
2419 optind++;
2420 if (argc >= optind) {
2421 if ((arg_duration = zonestat_parse_time(argv[optind - 1],
2422 &formatted)) < 0 || arg_duration == 0) {
2423 (void) zonestat_error(gettext(
2424 "Invalid duration: \"%s\""), argv[optind - 1]);
2425 return (zonestat_usage(B_FALSE));
2426 }
2427 /* If not formatted [nh][nm][ns], treat as count */
2428 if (arg_duration != ZSTAT_DURATION_INF &&
2429 formatted == B_FALSE)
2430 arg_duration *= arg_interval;
2431 } else {
2432 arg_duration = ZSTAT_DURATION_INF;
2433 }
2434 optind++;
2435 if (argc >= optind) {
2436 if ((arg_report = zonestat_parse_time(argv[optind - 1],
2437 &formatted)) < 0 || arg_report == 0) {
2438 (void) zonestat_error(gettext(
2439 "Invalid report period: \"%s\""), argv[optind - 1]);
2440 return (zonestat_usage(B_FALSE));
2441 }
2442 /* If not formatted as [nh][nm][ns] treat as count */
2443 if (formatted == B_FALSE)
2444 arg_report *= arg_interval;
2445 } else {
2446 arg_report = ZSTAT_REPORT_END;
2447 }
2448
2449 if (opt_quiet_intervals && (!opt_report)) {
2450 (void) zonestat_error(gettext("-q requires -R"));
2451 return (zonestat_usage(B_FALSE));
2452 }
2453
2454 /* Figure out what resources to report on */
2455 zonestat_determine_resources();
2456 zonestat_determine_reports();
2457 zonestat_determine_lines();
2458 zonestat_determine_sort();
2459
2460 /* Done parsing args beyond this point */
2461
2462 (void) signal(SIGINT, zonestat_quithandler);
2463 (void) signal(SIGTERM, zonestat_quithandler);
2464 (void) signal(SIGHUP, zonestat_quithandler);
2465
2466 /* Run at high priority to keep up with busy system */
2467 zonestat_set_fx();
2468
2469 not_responding = gettext(
2470 "Zones monitoring service \"svc:/system/zones-monitoring:default\" "
2471 "not enabled or responding.");
2472
2473 /* Open zone statistics */
2474 g_zsctl = zs_open();
2475 if (g_zsctl == NULL) {
2476 if (errno == EPERM)
2477 return (zonestat_error(gettext("Permission denied")));
2478 if (errno == EINTR || errno == ESRCH) {
2479 (void) zonestat_error(not_responding);
2480 return (3);
2481 }
2482 if (errno == ENOTSUP)
2483 return (zonestat_error(gettext(
2484 "Mismatched zonestat version. "
2485 "Re-install system/zones package.")));
2486
2487 return (zonestat_error(gettext(
2488 "Unexpected error. Unable to open zone statistics.")));
2489 }
2490 usage_last = zs_usage_read(g_zsctl);
2491 if (usage_last == NULL) {
2492 if (errno == EINTR && g_quit == B_TRUE)
2493 return (0);
2494 (void) zonestat_error(not_responding);
2495 return (3);
2496 }
2497 set = zs_usage_set_alloc(g_zsctl);
2498
2499 g_start_time = g_now_time = start = now = zonestat_time();
2500 g_interval = arg_interval;
2501 g_report_count = g_count = g_seconds = 0;
2502
2503 if (opt_quiet_intervals == B_FALSE && opt_parseable == B_FALSE)
2504 (void) printf(gettext(
2505 "Collecting data for first interval...\n"));
2506
2507 for (;;) {
2508 time_t tosleep;
2509
2510 g_now_time = now = zonestat_time();
2511
2512 if (arg_report != ZSTAT_REPORT_END)
2513 next_report = start + ((g_report_count + 1) *
2514 arg_report);
2515
2516 /*
2517 * Sleep till next interval.
2518 */
2519 g_count++;
2520 next = g_start_time + (g_count) * g_interval;
2521 /*
2522 * Skip to next interval if due to busy system, zonestat did
2523 * not complete in time.
2524 */
2525 while (now >= g_start_time + ((g_count + 1) * g_interval))
2526 g_count++;
2527
2528 while (now < next) {
2529 /* Sleep until at next interval */
2530 tosleep = next - now;
2531 (void) sleep(tosleep);
2532 now = zonestat_time();
2533 if (g_quit == B_TRUE)
2534 goto interval_loop_done;
2535 }
2536
2537 g_seconds = now - start;
2538 g_now_time = now;
2539 if ((usage = zs_usage_read(g_zsctl)) == NULL) {
2540 if (errno == EINTR && g_quit == B_TRUE)
2541 break;
2542 (void) zonestat_error(not_responding);
2543 return (3);
2544 }
2545
2546 /* Compute cpu used since last interval */
2547 usage_print = zs_usage_compute(NULL, usage_last,
2548 usage, ZS_COMPUTE_USAGE_INTERVAL);
2549 if (usage_print == NULL)
2550 (void) zonestat_error(gettext("Out of Memory"));
2551
2552
2553 if (opt_quiet_intervals == B_TRUE)
2554 goto interval_print_end;
2555
2556 zonestat_print_header(ZSTAT_REPORT_FMT_INTERVAL);
2557 zonestat_print_resources(ZSTAT_REPORT_FMT_INTERVAL,
2558 usage_print);
2559 zonestat_print_footer(ZSTAT_REPORT_FMT_INTERVAL);
2560 (void) fflush(stdout);
2561
2562 interval_print_end:
2563 (void) zs_usage_set_add(set, usage_print);
2564
2565
2566 /* Print reports if they are due */
2567 if (opt_report && arg_report != ZSTAT_REPORT_END &&
2568 now >= next_report) {
2569 g_end_time = now;
2570 zonestat_print_reports(set);
2571 zs_usage_set_free(set);
2572 set = zs_usage_set_alloc();
2573 g_start_time = now;
2574 g_report_count++;
2575 }
2576 zs_usage_free(usage_last);
2577 usage_last = usage;
2578 if (arg_duration != ZSTAT_DURATION_INF &&
2579 g_seconds >= arg_duration)
2580 break;
2581 }
2582 interval_loop_done:
2583
2584 /* Print last reports if due */
2585 g_end_time = g_now_time;
2586 if (opt_report && zs_usage_set_count(set) > 0 &&
2587 (arg_report == ZSTAT_REPORT_END || now < next_report))
2588 zonestat_print_reports(set);
2589
2590 zs_usage_set_free(set);
2591 if (usage_last != NULL)
2592 zs_usage_free(usage_last);
2593
2594 if (g_zsctl != NULL)
2595 zs_close(g_zsctl);
2596
2597 return (0);
2598 }
2599