xref: /illumos-gate/usr/src/cmd/zonestat/zonestat/zonestat.c (revision 4dd5791f4808cfb6a8024ebd3065cb4cebd15df5)
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