xref: /titanic_50/usr/src/cmd/ctstat/ctstat.c (revision 26fd77009b17f8c8fb32eb362584cfd635e87ad9)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57b209c2cSacruz  * Common Development and Distribution License (the "License").
67b209c2cSacruz  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*26fd7700SKrishnendu Sadhukhan - Sun Microsystems  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/ctfs.h>
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <unistd.h>
317c478bd9Sstevel@tonic-gate #include <fcntl.h>
327c478bd9Sstevel@tonic-gate #include <string.h>
337c478bd9Sstevel@tonic-gate #include <errno.h>
347c478bd9Sstevel@tonic-gate #include <libuutil.h>
357c478bd9Sstevel@tonic-gate #include <sys/contract/process.h>
367c478bd9Sstevel@tonic-gate #include <limits.h>
377c478bd9Sstevel@tonic-gate #include <libcontract.h>
387c478bd9Sstevel@tonic-gate #include <libcontract_priv.h>
397c478bd9Sstevel@tonic-gate #include <dirent.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include <locale.h>
427c478bd9Sstevel@tonic-gate #include <langinfo.h>
437c478bd9Sstevel@tonic-gate 
44*26fd7700SKrishnendu Sadhukhan - Sun Microsystems #include "statcommon.h"
45*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 
46*26fd7700SKrishnendu Sadhukhan - Sun Microsystems static uint_t timestamp_fmt = NODATE;
47*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 
487c478bd9Sstevel@tonic-gate static int opt_verbose = 0;
497c478bd9Sstevel@tonic-gate static int opt_showall = 0;
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate  * usage
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  * Educate the user.
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate static void
577c478bd9Sstevel@tonic-gate usage(void)
587c478bd9Sstevel@tonic-gate {
597c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Usage: %s [-a] [-i ctidlist] "
60*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 	    "[-t typelist] [-T d|u] [-v] [interval [count]]\n"), uu_getpname());
617c478bd9Sstevel@tonic-gate 	exit(UU_EXIT_USAGE);
627c478bd9Sstevel@tonic-gate }
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  * mystrtoul
667c478bd9Sstevel@tonic-gate  *
677c478bd9Sstevel@tonic-gate  * Convert a string into an int in [0, INT_MAX].  Exit if the argument
687c478bd9Sstevel@tonic-gate  * doen't fit this description.
697c478bd9Sstevel@tonic-gate  */
707c478bd9Sstevel@tonic-gate static int
717c478bd9Sstevel@tonic-gate mystrtoul(const char *arg)
727c478bd9Sstevel@tonic-gate {
737c478bd9Sstevel@tonic-gate 	unsigned int result;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate 	if (uu_strtoint(arg, &result, sizeof (result), 10, 0, INT_MAX) == -1) {
767c478bd9Sstevel@tonic-gate 		uu_warn(gettext("invalid numerical argument \"%s\"\n"), arg);
777c478bd9Sstevel@tonic-gate 		usage();
787c478bd9Sstevel@tonic-gate 	}
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	return (result);
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * int_compar
857c478bd9Sstevel@tonic-gate  *
867c478bd9Sstevel@tonic-gate  * A simple integer comparator.  Also used for id_ts, since they're the
877c478bd9Sstevel@tonic-gate  * same thing.
887c478bd9Sstevel@tonic-gate  */
897c478bd9Sstevel@tonic-gate static int
907c478bd9Sstevel@tonic-gate int_compar(const void *a1, const void *a2)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	int id1 = *(int *)a1;
937c478bd9Sstevel@tonic-gate 	int id2 = *(int *)a2;
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	if (id1 > id2)
967c478bd9Sstevel@tonic-gate 		return (1);
977c478bd9Sstevel@tonic-gate 	if (id2 > id1)
987c478bd9Sstevel@tonic-gate 		return (-1);
997c478bd9Sstevel@tonic-gate 	return (0);
1007c478bd9Sstevel@tonic-gate }
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate typedef struct optvect {
1037c478bd9Sstevel@tonic-gate 	const char	*option;
1047c478bd9Sstevel@tonic-gate 	uint_t		bit;
1057c478bd9Sstevel@tonic-gate } optvect_t;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate static optvect_t option_params[] = {
1087c478bd9Sstevel@tonic-gate 	{ "inherit", CT_PR_INHERIT },
1097c478bd9Sstevel@tonic-gate 	{ "noorphan", CT_PR_NOORPHAN },
1107c478bd9Sstevel@tonic-gate 	{ "pgrponly", CT_PR_PGRPONLY },
1117c478bd9Sstevel@tonic-gate 	{ "regent", CT_PR_REGENT },
1127c478bd9Sstevel@tonic-gate 	{ NULL }
1137c478bd9Sstevel@tonic-gate };
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate static optvect_t option_events[] = {
1167c478bd9Sstevel@tonic-gate 	{ "core", CT_PR_EV_CORE },
1177c478bd9Sstevel@tonic-gate 	{ "signal", CT_PR_EV_SIGNAL },
1187c478bd9Sstevel@tonic-gate 	{ "hwerr", CT_PR_EV_HWERR },
1197c478bd9Sstevel@tonic-gate 	{ "empty", CT_PR_EV_EMPTY },
1207c478bd9Sstevel@tonic-gate 	{ "fork", CT_PR_EV_FORK },
1217c478bd9Sstevel@tonic-gate 	{ "exit", CT_PR_EV_EXIT },
1227c478bd9Sstevel@tonic-gate 	{ NULL }
1237c478bd9Sstevel@tonic-gate };
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * print_bits
1277c478bd9Sstevel@tonic-gate  *
1287c478bd9Sstevel@tonic-gate  * Display a set whose membership is identified by a bitfield.
1297c478bd9Sstevel@tonic-gate  */
1307c478bd9Sstevel@tonic-gate static void
1317c478bd9Sstevel@tonic-gate print_bits(uint_t bits, optvect_t *desc)
1327c478bd9Sstevel@tonic-gate {
1337c478bd9Sstevel@tonic-gate 	int i, printed = 0;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	for (i = 0; desc[i].option; i++)
1367c478bd9Sstevel@tonic-gate 		if (desc[i].bit & bits) {
1377c478bd9Sstevel@tonic-gate 			if (printed)
1387c478bd9Sstevel@tonic-gate 				(void) putchar(' ');
1397c478bd9Sstevel@tonic-gate 			printed = 1;
1407c478bd9Sstevel@tonic-gate 			(void) fputs(desc[i].option, stdout);
1417c478bd9Sstevel@tonic-gate 		}
1427c478bd9Sstevel@tonic-gate 	if (printed)
1437c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
1447c478bd9Sstevel@tonic-gate 	else
1457c478bd9Sstevel@tonic-gate 		(void) puts("none");
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate  * print_ids
1507c478bd9Sstevel@tonic-gate  *
1517c478bd9Sstevel@tonic-gate  * Display a list of ids, sorted.
1527c478bd9Sstevel@tonic-gate  */
1537c478bd9Sstevel@tonic-gate static void
1547c478bd9Sstevel@tonic-gate print_ids(id_t *ids, uint_t nids)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 	int i;
1577c478bd9Sstevel@tonic-gate 	int first = 1;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	qsort(ids, nids, sizeof (int), int_compar);
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	for (i = 0; i < nids; i++) {
1627c478bd9Sstevel@tonic-gate 		/*LINTED*/
1637c478bd9Sstevel@tonic-gate 		(void) printf(" %d" + first, ids[i]);
1647c478bd9Sstevel@tonic-gate 		first = 0;
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 	if (first)
1677c478bd9Sstevel@tonic-gate 		(void) puts("none");
1687c478bd9Sstevel@tonic-gate 	else
1697c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate typedef void printfunc_t(ct_stathdl_t);
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate  * A structure defining a displayed field.  Includes a label to be
1767c478bd9Sstevel@tonic-gate  * printed along side the field value, and a function which extracts
1777c478bd9Sstevel@tonic-gate  * the data from a status structure, formats it, and displays it on
1787c478bd9Sstevel@tonic-gate  * stdout.
1797c478bd9Sstevel@tonic-gate  */
1807c478bd9Sstevel@tonic-gate typedef struct verbout {
1817c478bd9Sstevel@tonic-gate 	const char	*label;	/* field label */
1827c478bd9Sstevel@tonic-gate 	printfunc_t	*func;	/* field display function */
1837c478bd9Sstevel@tonic-gate } verbout_t;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate /*
1867c478bd9Sstevel@tonic-gate  * verb_cookie
1877c478bd9Sstevel@tonic-gate  *
1887c478bd9Sstevel@tonic-gate  * Used to display an error encountered when reading a contract status
1897c478bd9Sstevel@tonic-gate  * field.
1907c478bd9Sstevel@tonic-gate  */
1917c478bd9Sstevel@tonic-gate static void
1927c478bd9Sstevel@tonic-gate verb_error(int err)
1937c478bd9Sstevel@tonic-gate {
1947c478bd9Sstevel@tonic-gate 	(void) printf("(error: %s)\n", strerror(err));
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /*
1987c478bd9Sstevel@tonic-gate  * verb_cookie
1997c478bd9Sstevel@tonic-gate  *
2007c478bd9Sstevel@tonic-gate  * Display the contract's cookie.
2017c478bd9Sstevel@tonic-gate  */
2027c478bd9Sstevel@tonic-gate static void
2037c478bd9Sstevel@tonic-gate verb_cookie(ct_stathdl_t hdl)
2047c478bd9Sstevel@tonic-gate {
2057c478bd9Sstevel@tonic-gate 	(void) printf("%#llx\n", ct_status_get_cookie(hdl));
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate /*
2097c478bd9Sstevel@tonic-gate  * verb_info
2107c478bd9Sstevel@tonic-gate  *
2117c478bd9Sstevel@tonic-gate  * Display the parameters in the parameter set.
2127c478bd9Sstevel@tonic-gate  */
2137c478bd9Sstevel@tonic-gate static void
2147c478bd9Sstevel@tonic-gate verb_param(ct_stathdl_t hdl)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate 	uint_t param;
2177c478bd9Sstevel@tonic-gate 	int err;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	if (err = ct_pr_status_get_param(hdl, &param))
2207c478bd9Sstevel@tonic-gate 		verb_error(err);
2217c478bd9Sstevel@tonic-gate 	else
2227c478bd9Sstevel@tonic-gate 		print_bits(param, option_params);
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate /*
2267c478bd9Sstevel@tonic-gate  * verb_info
2277c478bd9Sstevel@tonic-gate  *
2287c478bd9Sstevel@tonic-gate  * Display the events in the informative event set.
2297c478bd9Sstevel@tonic-gate  */
2307c478bd9Sstevel@tonic-gate static void
2317c478bd9Sstevel@tonic-gate verb_info(ct_stathdl_t hdl)
2327c478bd9Sstevel@tonic-gate {
2337c478bd9Sstevel@tonic-gate 	print_bits(ct_status_get_informative(hdl), option_events);
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate /*
2377c478bd9Sstevel@tonic-gate  * verb_crit
2387c478bd9Sstevel@tonic-gate  *
2397c478bd9Sstevel@tonic-gate  * Display the events in the critical event set.
2407c478bd9Sstevel@tonic-gate  */
2417c478bd9Sstevel@tonic-gate static void
2427c478bd9Sstevel@tonic-gate verb_crit(ct_stathdl_t hdl)
2437c478bd9Sstevel@tonic-gate {
2447c478bd9Sstevel@tonic-gate 	print_bits(ct_status_get_critical(hdl), option_events);
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate /*
2487c478bd9Sstevel@tonic-gate  * verb_fatal
2497c478bd9Sstevel@tonic-gate  *
2507c478bd9Sstevel@tonic-gate  * Display the events in the fatal event set.
2517c478bd9Sstevel@tonic-gate  */
2527c478bd9Sstevel@tonic-gate static void
2537c478bd9Sstevel@tonic-gate verb_fatal(ct_stathdl_t hdl)
2547c478bd9Sstevel@tonic-gate {
2557c478bd9Sstevel@tonic-gate 	uint_t event;
2567c478bd9Sstevel@tonic-gate 	int err;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	if (err = ct_pr_status_get_fatal(hdl, &event))
2597c478bd9Sstevel@tonic-gate 		verb_error(err);
2607c478bd9Sstevel@tonic-gate 	else
2617c478bd9Sstevel@tonic-gate 		print_bits(event, option_events);
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate  * verb_members
2667c478bd9Sstevel@tonic-gate  *
2677c478bd9Sstevel@tonic-gate  * Display the list of member contracts.
2687c478bd9Sstevel@tonic-gate  */
2697c478bd9Sstevel@tonic-gate static void
2707c478bd9Sstevel@tonic-gate verb_members(ct_stathdl_t hdl)
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate 	pid_t *pids;
2737c478bd9Sstevel@tonic-gate 	uint_t npids;
2747c478bd9Sstevel@tonic-gate 	int err;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	if (err = ct_pr_status_get_members(hdl, &pids, &npids)) {
2777c478bd9Sstevel@tonic-gate 		verb_error(err);
2787c478bd9Sstevel@tonic-gate 		return;
2797c478bd9Sstevel@tonic-gate 	}
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	print_ids(pids, npids);
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate /*
2857c478bd9Sstevel@tonic-gate  * verb_inherit
2867c478bd9Sstevel@tonic-gate  *
2877c478bd9Sstevel@tonic-gate  * Display the list of inherited contracts.
2887c478bd9Sstevel@tonic-gate  */
2897c478bd9Sstevel@tonic-gate static void
2907c478bd9Sstevel@tonic-gate verb_inherit(ct_stathdl_t hdl)
2917c478bd9Sstevel@tonic-gate {
2927c478bd9Sstevel@tonic-gate 	ctid_t *ctids;
2937c478bd9Sstevel@tonic-gate 	uint_t nctids;
2947c478bd9Sstevel@tonic-gate 	int err;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	if (err = ct_pr_status_get_contracts(hdl, &ctids, &nctids))
2977c478bd9Sstevel@tonic-gate 		verb_error(err);
2987c478bd9Sstevel@tonic-gate 	else
2997c478bd9Sstevel@tonic-gate 		print_ids(ctids, nctids);
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate /*
3037b209c2cSacruz  * verb_svc_fmri
3047b209c2cSacruz  *
3057b209c2cSacruz  * Display the process contract service fmri
3067b209c2cSacruz  */
3077b209c2cSacruz static void
3087b209c2cSacruz verb_svc_fmri(ct_stathdl_t hdl)
3097b209c2cSacruz {
3107b209c2cSacruz 	char *svc_fmri;
3117b209c2cSacruz 	int err;
3127b209c2cSacruz 	if (err = ct_pr_status_get_svc_fmri(hdl, &svc_fmri))
3137b209c2cSacruz 		verb_error(err);
3147b209c2cSacruz 	else
3157b209c2cSacruz 		(void) printf("%s\n", svc_fmri);
3167b209c2cSacruz }
3177b209c2cSacruz 
3187b209c2cSacruz /*
3197b209c2cSacruz  * verb_svc_aux
3207b209c2cSacruz  *
3217b209c2cSacruz  * Display the process contract service fmri auxiliar
3227b209c2cSacruz  */
3237b209c2cSacruz static void
3247b209c2cSacruz verb_svc_aux(ct_stathdl_t hdl)
3257b209c2cSacruz {
3267b209c2cSacruz 	char *svc_aux;
3277b209c2cSacruz 	int err;
3287b209c2cSacruz 	if (err = ct_pr_status_get_svc_aux(hdl, &svc_aux))
3297b209c2cSacruz 		verb_error(err);
3307b209c2cSacruz 	else
3317b209c2cSacruz 		(void) printf("%s\n", svc_aux);
3327b209c2cSacruz }
3337b209c2cSacruz 
3347b209c2cSacruz /*
3357b209c2cSacruz  * verb_svc_ctid
3367b209c2cSacruz  *
3377b209c2cSacruz  * Display the process contract service fmri ctid
3387b209c2cSacruz  */
3397b209c2cSacruz static void
3407b209c2cSacruz verb_svc_ctid(ct_stathdl_t hdl)
3417b209c2cSacruz {
3427b209c2cSacruz 	ctid_t svc_ctid;
3437b209c2cSacruz 	int err;
3447b209c2cSacruz 	if (err = ct_pr_status_get_svc_ctid(hdl, &svc_ctid))
3457b209c2cSacruz 		verb_error(err);
3467b209c2cSacruz 	else
3477b209c2cSacruz 		(void) printf("%ld\n", svc_ctid);
3487b209c2cSacruz }
3497b209c2cSacruz 
3507b209c2cSacruz /*
3517b209c2cSacruz  * verb_svc_creator
3527b209c2cSacruz  *
3537b209c2cSacruz  * Display the process contract creator's execname
3547b209c2cSacruz  */
3557b209c2cSacruz static void
3567b209c2cSacruz verb_svc_creator(ct_stathdl_t hdl)
3577b209c2cSacruz {
3587b209c2cSacruz 	char *svc_creator;
3597b209c2cSacruz 	int err;
3607b209c2cSacruz 	if (err = ct_pr_status_get_svc_creator(hdl, &svc_creator))
3617b209c2cSacruz 		verb_error(err);
3627b209c2cSacruz 	else
3637b209c2cSacruz 		(void) printf("%s\n", svc_creator);
3647b209c2cSacruz }
3657b209c2cSacruz 
3667b209c2cSacruz /*
3677c478bd9Sstevel@tonic-gate  * Common contract status fields.
3687c478bd9Sstevel@tonic-gate  */
3697c478bd9Sstevel@tonic-gate static verbout_t vcommon[] = {
3707c478bd9Sstevel@tonic-gate 	"cookie", verb_cookie,
3717c478bd9Sstevel@tonic-gate 	NULL,
3727c478bd9Sstevel@tonic-gate };
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate /*
3757c478bd9Sstevel@tonic-gate  * Process contract-specific status fields.
3767c478bd9Sstevel@tonic-gate  * The critical and informative event sets are here because the event
3777c478bd9Sstevel@tonic-gate  * names are contract-specific.  They are listed first, however, so
3787c478bd9Sstevel@tonic-gate  * they are displayed adjacent to the "normal" common output.
3797c478bd9Sstevel@tonic-gate  */
3807c478bd9Sstevel@tonic-gate static verbout_t vprocess[] = {
3817c478bd9Sstevel@tonic-gate 	"informative event set", verb_info,
3827c478bd9Sstevel@tonic-gate 	"critical event set", verb_crit,
3837c478bd9Sstevel@tonic-gate 	"fatal event set", verb_fatal,
3847c478bd9Sstevel@tonic-gate 	"parameter set", verb_param,
3857c478bd9Sstevel@tonic-gate 	"member processes", verb_members,
3867c478bd9Sstevel@tonic-gate 	"inherited contracts", verb_inherit,
3877b209c2cSacruz 	"service fmri", verb_svc_fmri,
3887b209c2cSacruz 	"service fmri ctid", verb_svc_ctid,
3897b209c2cSacruz 	"creator", verb_svc_creator,
3907b209c2cSacruz 	"aux", verb_svc_aux,
3917c478bd9Sstevel@tonic-gate 	NULL
3927c478bd9Sstevel@tonic-gate };
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate /*
3957c478bd9Sstevel@tonic-gate  * print_verbose
3967c478bd9Sstevel@tonic-gate  *
3977c478bd9Sstevel@tonic-gate  * Displays a contract's verbose status, common fields first.
3987c478bd9Sstevel@tonic-gate  */
3997c478bd9Sstevel@tonic-gate static void
4007c478bd9Sstevel@tonic-gate print_verbose(ct_stathdl_t hdl, verbout_t *spec, verbout_t *common)
4017c478bd9Sstevel@tonic-gate {
4027c478bd9Sstevel@tonic-gate 	int i;
4037c478bd9Sstevel@tonic-gate 	int tmp, maxwidth = 0;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	/*
4067c478bd9Sstevel@tonic-gate 	 * Compute the width of all the fields.
4077c478bd9Sstevel@tonic-gate 	 */
4087c478bd9Sstevel@tonic-gate 	for (i = 0; common[i].label; i++)
4097c478bd9Sstevel@tonic-gate 		if ((tmp = strlen(common[i].label)) > maxwidth)
4107c478bd9Sstevel@tonic-gate 			maxwidth = tmp;
4117c478bd9Sstevel@tonic-gate 	if (spec)
4127c478bd9Sstevel@tonic-gate 		for (i = 0; spec[i].label; i++)
4137c478bd9Sstevel@tonic-gate 			if ((tmp = strlen(spec[i].label)) > maxwidth)
4147c478bd9Sstevel@tonic-gate 				maxwidth = tmp;
4157c478bd9Sstevel@tonic-gate 	maxwidth += 2;
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	/*
4187c478bd9Sstevel@tonic-gate 	 * Display the data.
4197c478bd9Sstevel@tonic-gate 	 */
4207c478bd9Sstevel@tonic-gate 	for (i = 0; common[i].label; i++) {
4217c478bd9Sstevel@tonic-gate 		tmp = printf("\t%s", common[i].label);
4227c478bd9Sstevel@tonic-gate 		if (tmp < 0)
4237c478bd9Sstevel@tonic-gate 			tmp = 0;
4247c478bd9Sstevel@tonic-gate 		(void) printf("%-*s", maxwidth - tmp + 1, ":");
4257c478bd9Sstevel@tonic-gate 		common[i].func(hdl);
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 	if (spec)
4287c478bd9Sstevel@tonic-gate 		for (i = 0; spec[i].label; i++) {
4297c478bd9Sstevel@tonic-gate 			(void) printf("\t%s%n", spec[i].label, &tmp);
4307c478bd9Sstevel@tonic-gate 			(void) printf("%-*s", maxwidth - tmp + 1, ":");
4317c478bd9Sstevel@tonic-gate 			spec[i].func(hdl);
4327c478bd9Sstevel@tonic-gate 		}
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate struct {
4367c478bd9Sstevel@tonic-gate 	const char *name;
4377c478bd9Sstevel@tonic-gate 	verbout_t *verbout;
4387c478bd9Sstevel@tonic-gate } cttypes[] = {
4397c478bd9Sstevel@tonic-gate 	{ "process", vprocess },
4407c478bd9Sstevel@tonic-gate 	{ NULL }
4417c478bd9Sstevel@tonic-gate };
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate /*
4447c478bd9Sstevel@tonic-gate  * get_type
4457c478bd9Sstevel@tonic-gate  *
4467c478bd9Sstevel@tonic-gate  * Given a type name, return an index into the above array of types.
4477c478bd9Sstevel@tonic-gate  */
4487c478bd9Sstevel@tonic-gate static int
4497c478bd9Sstevel@tonic-gate get_type(const char *typestr)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate 	int i;
4527c478bd9Sstevel@tonic-gate 	for (i = 0; cttypes[i].name; i++)
4537c478bd9Sstevel@tonic-gate 		if (strcmp(cttypes[i].name, typestr) == 0)
4547c478bd9Sstevel@tonic-gate 			return (i);
4557c478bd9Sstevel@tonic-gate 	uu_die(gettext("invalid contract type: %s\n"), typestr);
4567c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
4577c478bd9Sstevel@tonic-gate }
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate /*
4607c478bd9Sstevel@tonic-gate  * print_header
4617c478bd9Sstevel@tonic-gate  *
4627c478bd9Sstevel@tonic-gate  * Display the status header.
4637c478bd9Sstevel@tonic-gate  */
4647c478bd9Sstevel@tonic-gate static void
4657c478bd9Sstevel@tonic-gate print_header(void)
4667c478bd9Sstevel@tonic-gate {
4677c478bd9Sstevel@tonic-gate 	(void) printf("%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-8s\n", "CTID", "ZONEID",
4687c478bd9Sstevel@tonic-gate 	    "TYPE", "STATE", "HOLDER", "EVENTS", "QTIME", "NTIME");
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate /*
4727c478bd9Sstevel@tonic-gate  * print_contract
4737c478bd9Sstevel@tonic-gate  *
4747c478bd9Sstevel@tonic-gate  * Display status for contract ID 'id' from type directory 'dir'.  If
4757c478bd9Sstevel@tonic-gate  * only contracts of a specific set of types should be displayed,
4767c478bd9Sstevel@tonic-gate  * 'types' will be a sorted list of type indices of length 'ntypes'.
4777c478bd9Sstevel@tonic-gate  */
4787c478bd9Sstevel@tonic-gate static void
4797c478bd9Sstevel@tonic-gate print_contract(const char *dir, ctid_t id, verbout_t *spec,
4807c478bd9Sstevel@tonic-gate     int *types, int ntypes)
4817c478bd9Sstevel@tonic-gate {
4827c478bd9Sstevel@tonic-gate 	ct_stathdl_t status;
4837c478bd9Sstevel@tonic-gate 	char hstr[100], qstr[20], nstr[20];
4847c478bd9Sstevel@tonic-gate 	ctstate_t state;
4857c478bd9Sstevel@tonic-gate 	int fd = 0;
4867c478bd9Sstevel@tonic-gate 	int t;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	/*
4897c478bd9Sstevel@tonic-gate 	 * Open and obtain status.
4907c478bd9Sstevel@tonic-gate 	 */
4917c478bd9Sstevel@tonic-gate 	if ((fd = contract_open(id, dir, "status", O_RDONLY)) == -1) {
4927c478bd9Sstevel@tonic-gate 		if (errno == ENOENT)
4937c478bd9Sstevel@tonic-gate 			return;
4947c478bd9Sstevel@tonic-gate 		uu_die(gettext("could not open contract status file"));
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	if (errno = ct_status_read(fd, opt_verbose ? CTD_ALL : CTD_COMMON,
4987c478bd9Sstevel@tonic-gate 	    &status))
4997c478bd9Sstevel@tonic-gate 		uu_die(gettext("failed to get contract status for %d"), id);
5007c478bd9Sstevel@tonic-gate 	(void) close(fd);
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	/*
5037c478bd9Sstevel@tonic-gate 	 * Unless otherwise directed, don't display dead contracts.
5047c478bd9Sstevel@tonic-gate 	 */
5057c478bd9Sstevel@tonic-gate 	state = ct_status_get_state(status);
5067c478bd9Sstevel@tonic-gate 	if (!opt_showall && state == CTS_DEAD) {
5077c478bd9Sstevel@tonic-gate 		ct_status_free(status);
5087c478bd9Sstevel@tonic-gate 		return;
5097c478bd9Sstevel@tonic-gate 	}
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	/*
5127c478bd9Sstevel@tonic-gate 	 * If we are only allowed to display certain contract types,
5137c478bd9Sstevel@tonic-gate 	 * perform that filtering here.  We stash a copy of spec so we
5147c478bd9Sstevel@tonic-gate 	 * don't have to recompute it later.
5157c478bd9Sstevel@tonic-gate 	 */
5167c478bd9Sstevel@tonic-gate 	if (types) {
5177c478bd9Sstevel@tonic-gate 		int key = get_type(ct_status_get_type(status));
5187c478bd9Sstevel@tonic-gate 		spec = cttypes[key].verbout;
5197c478bd9Sstevel@tonic-gate 		if (bsearch(&key, types, ntypes, sizeof (int), int_compar) ==
5207c478bd9Sstevel@tonic-gate 		    NULL) {
5217c478bd9Sstevel@tonic-gate 			ct_status_free(status);
5227c478bd9Sstevel@tonic-gate 			return;
5237c478bd9Sstevel@tonic-gate 		}
5247c478bd9Sstevel@tonic-gate 	}
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	/*
5277c478bd9Sstevel@tonic-gate 	 * Precompute those fields which have both textual and
5287c478bd9Sstevel@tonic-gate 	 * numerical values.
5297c478bd9Sstevel@tonic-gate 	 */
5307c478bd9Sstevel@tonic-gate 	if ((state == CTS_OWNED) || (state == CTS_INHERITED))
5317c478bd9Sstevel@tonic-gate 		(void) snprintf(hstr, sizeof (hstr), "%ld",
5327c478bd9Sstevel@tonic-gate 		    ct_status_get_holder(status));
5337c478bd9Sstevel@tonic-gate 	else
5347c478bd9Sstevel@tonic-gate 		(void) snprintf(hstr, sizeof (hstr), "%s", "-");
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	if ((t = ct_status_get_qtime(status)) == -1) {
5377c478bd9Sstevel@tonic-gate 		qstr[0] = nstr[0] = '-';
5387c478bd9Sstevel@tonic-gate 		qstr[1] = nstr[1] = '\0';
5397c478bd9Sstevel@tonic-gate 	} else {
5407c478bd9Sstevel@tonic-gate 		(void) snprintf(qstr, sizeof (qstr), "%d", t);
5417c478bd9Sstevel@tonic-gate 		(void) snprintf(nstr, sizeof (nstr), "%d",
5427c478bd9Sstevel@tonic-gate 		    ct_status_get_ntime(status));
5437c478bd9Sstevel@tonic-gate 	}
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	/*
5467c478bd9Sstevel@tonic-gate 	 * Emit the contract's status.
5477c478bd9Sstevel@tonic-gate 	 */
5487c478bd9Sstevel@tonic-gate 	(void) printf("%-7ld %-7ld %-7s %-7s %-7s %-7d %-7s %-8s\n",
5497c478bd9Sstevel@tonic-gate 	    ct_status_get_id(status),
5507c478bd9Sstevel@tonic-gate 	    ct_status_get_zoneid(status),
5517c478bd9Sstevel@tonic-gate 	    ct_status_get_type(status),
5527c478bd9Sstevel@tonic-gate 	    (state == CTS_OWNED) ? "owned" :
5537c478bd9Sstevel@tonic-gate 	    (state == CTS_INHERITED) ? "inherit" :
5547c478bd9Sstevel@tonic-gate 	    (state == CTS_ORPHAN) ? "orphan" : "dead", hstr,
5557c478bd9Sstevel@tonic-gate 	    ct_status_get_nevents(status), qstr, nstr);
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	/*
5587c478bd9Sstevel@tonic-gate 	 * Emit verbose status information, if requested.  If we
5597c478bd9Sstevel@tonic-gate 	 * weren't provided a verbose output spec or didn't compute it
5607c478bd9Sstevel@tonic-gate 	 * earlier, do it now.
5617c478bd9Sstevel@tonic-gate 	 */
5627c478bd9Sstevel@tonic-gate 	if (opt_verbose) {
5637c478bd9Sstevel@tonic-gate 		if (spec == NULL)
5647c478bd9Sstevel@tonic-gate 			spec = cttypes[get_type(ct_status_get_type(status))].
5657c478bd9Sstevel@tonic-gate 			    verbout;
5667c478bd9Sstevel@tonic-gate 		print_verbose(status, spec, vcommon);
5677c478bd9Sstevel@tonic-gate 	}
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	ct_status_free(status);
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate /*
5737c478bd9Sstevel@tonic-gate  * scan_type
5747c478bd9Sstevel@tonic-gate  *
5757c478bd9Sstevel@tonic-gate  * Display all contracts of the requested type.
5767c478bd9Sstevel@tonic-gate  */
5777c478bd9Sstevel@tonic-gate static void
5787c478bd9Sstevel@tonic-gate scan_type(int typeno)
5797c478bd9Sstevel@tonic-gate {
5807c478bd9Sstevel@tonic-gate 	DIR *dir;
5817c478bd9Sstevel@tonic-gate 	struct dirent64 *de;
5827c478bd9Sstevel@tonic-gate 	char path[PATH_MAX];
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	verbout_t *vo = cttypes[typeno].verbout;
5857c478bd9Sstevel@tonic-gate 	const char *type = cttypes[typeno].name;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	if (snprintf(path, PATH_MAX, CTFS_ROOT "/%s", type) >= PATH_MAX ||
5887c478bd9Sstevel@tonic-gate 	    (dir = opendir(path)) == NULL)
5897c478bd9Sstevel@tonic-gate 		uu_die(gettext("bad contract type: %s\n"), type);
5907c478bd9Sstevel@tonic-gate 	while ((de = readdir64(dir)) != NULL) {
5917c478bd9Sstevel@tonic-gate 		/*
5927c478bd9Sstevel@tonic-gate 		 * Eliminate special files (e.g. '.', '..').
5937c478bd9Sstevel@tonic-gate 		 */
5947c478bd9Sstevel@tonic-gate 		if (de->d_name[0] < '0' || de->d_name[0] > '9')
5957c478bd9Sstevel@tonic-gate 			continue;
5967c478bd9Sstevel@tonic-gate 		print_contract(type, mystrtoul(de->d_name), vo, NULL, 0);
5977c478bd9Sstevel@tonic-gate 	}
5987c478bd9Sstevel@tonic-gate 	(void) closedir(dir);
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate /*
6027c478bd9Sstevel@tonic-gate  * scan_ids
6037c478bd9Sstevel@tonic-gate  *
6047c478bd9Sstevel@tonic-gate  * Display all contracts with the requested IDs.
6057c478bd9Sstevel@tonic-gate  */
6067c478bd9Sstevel@tonic-gate static void
6077c478bd9Sstevel@tonic-gate scan_ids(ctid_t *ids, int nids)
6087c478bd9Sstevel@tonic-gate {
6097c478bd9Sstevel@tonic-gate 	int i;
6107c478bd9Sstevel@tonic-gate 	for (i = 0; i < nids; i++)
6117c478bd9Sstevel@tonic-gate 		print_contract("all", ids[i], NULL, NULL, 0);
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate /*
6157c478bd9Sstevel@tonic-gate  * scan_all
6167c478bd9Sstevel@tonic-gate  *
6177c478bd9Sstevel@tonic-gate  * Display the union of the requested IDs and types.  So that the
6187c478bd9Sstevel@tonic-gate  * output is sorted by contract ID, it takes the slow road by testing
6197c478bd9Sstevel@tonic-gate  * each entry in /system/contract/all against its criteria.  Used when
6207c478bd9Sstevel@tonic-gate  * the number of types is greater than 1, when we have a mixture of
6217c478bd9Sstevel@tonic-gate  * types and ids, or no lists were provided at all.
6227c478bd9Sstevel@tonic-gate  */
6237c478bd9Sstevel@tonic-gate static void
6247c478bd9Sstevel@tonic-gate scan_all(int *types, int ntypes, ctid_t *ids, int nids)
6257c478bd9Sstevel@tonic-gate {
6267c478bd9Sstevel@tonic-gate 	DIR *dir;
6277c478bd9Sstevel@tonic-gate 	struct dirent64 *de;
6287c478bd9Sstevel@tonic-gate 	const char *path = CTFS_ROOT "/all";
6297c478bd9Sstevel@tonic-gate 	int key, test;
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	if ((dir = opendir(path)) == NULL)
6327c478bd9Sstevel@tonic-gate 		uu_die(gettext("could not open %s"), path);
6337c478bd9Sstevel@tonic-gate 	while ((de = readdir64(dir)) != NULL) {
6347c478bd9Sstevel@tonic-gate 		/*
6357c478bd9Sstevel@tonic-gate 		 * Eliminate special files (e.g. '.', '..').
6367c478bd9Sstevel@tonic-gate 		 */
6377c478bd9Sstevel@tonic-gate 		if (de->d_name[0] < '0' || de->d_name[0] > '9')
6387c478bd9Sstevel@tonic-gate 			continue;
6397c478bd9Sstevel@tonic-gate 		key = mystrtoul(de->d_name);
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 		/*
6427c478bd9Sstevel@tonic-gate 		 * If we are given IDs to look at and this contract
6437c478bd9Sstevel@tonic-gate 		 * isn't in the ID list, or if we weren't given a list
6447c478bd9Sstevel@tonic-gate 		 * if IDs but were given a list of types, provide the
6457c478bd9Sstevel@tonic-gate 		 * list of acceptable types to print_contract.
6467c478bd9Sstevel@tonic-gate 		 */
6477c478bd9Sstevel@tonic-gate 		test = nids ? (bsearch(&key, ids, nids, sizeof (int),
6487c478bd9Sstevel@tonic-gate 		    int_compar) == NULL) : (ntypes != 0);
6497c478bd9Sstevel@tonic-gate 		print_contract("all", key, NULL, (test ? types : NULL), ntypes);
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 	(void) closedir(dir);
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate /*
6557c478bd9Sstevel@tonic-gate  * walk_args
6567c478bd9Sstevel@tonic-gate  *
6577c478bd9Sstevel@tonic-gate  * Apply fp to each token in the comma- or space- separated argument
6587c478bd9Sstevel@tonic-gate  * string str and store the results in the array starting at results.
6597c478bd9Sstevel@tonic-gate  */
6607c478bd9Sstevel@tonic-gate static int
6617c478bd9Sstevel@tonic-gate walk_args(const char *str, int (*fp)(const char *), int *results)
6627c478bd9Sstevel@tonic-gate {
6637c478bd9Sstevel@tonic-gate 	char *copy, *token;
6647c478bd9Sstevel@tonic-gate 	int count = 0;
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	if ((copy = strdup(str)) == NULL)
6677c478bd9Sstevel@tonic-gate 		uu_die(gettext("strdup() failed"));
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	token = strtok(copy, ", ");
6707c478bd9Sstevel@tonic-gate 	if (token == NULL) {
6717c478bd9Sstevel@tonic-gate 		free(copy);
6727c478bd9Sstevel@tonic-gate 		return (0);
6737c478bd9Sstevel@tonic-gate 	}
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	do {
6767c478bd9Sstevel@tonic-gate 		if (fp)
6777c478bd9Sstevel@tonic-gate 			*(results++) = fp(token);
6787c478bd9Sstevel@tonic-gate 		count++;
6797c478bd9Sstevel@tonic-gate 	} while (token = strtok(NULL, ", "));
6807c478bd9Sstevel@tonic-gate 	free(copy);
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	return (count);
6837c478bd9Sstevel@tonic-gate }
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate /*
6867c478bd9Sstevel@tonic-gate  * parse
6877c478bd9Sstevel@tonic-gate  *
6887c478bd9Sstevel@tonic-gate  * Parse the comma- or space- separated string str, using fp to covert
6897c478bd9Sstevel@tonic-gate  * the tokens to integers.  Append the list of integers to the array
6907c478bd9Sstevel@tonic-gate  * pointed to by *idps, growing the array if necessary.
6917c478bd9Sstevel@tonic-gate  */
6927c478bd9Sstevel@tonic-gate static int
6937c478bd9Sstevel@tonic-gate parse(const char *str, int **idsp, int nids, int (*fp)(const char *fp))
6947c478bd9Sstevel@tonic-gate {
6957c478bd9Sstevel@tonic-gate 	int count;
6967c478bd9Sstevel@tonic-gate 	int *array;
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	count = walk_args(str, NULL, NULL);
6997c478bd9Sstevel@tonic-gate 	if (count == 0)
7007c478bd9Sstevel@tonic-gate 		return (0);
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	if ((array = calloc(nids + count, sizeof (int))) == NULL)
7037c478bd9Sstevel@tonic-gate 		uu_die(gettext("calloc() failed"));
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	if (*idsp) {
7067c478bd9Sstevel@tonic-gate 		(void) memcpy(array, *idsp, nids * sizeof (int));
7077c478bd9Sstevel@tonic-gate 		free(*idsp);
7087c478bd9Sstevel@tonic-gate 	}
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	(void) walk_args(str, fp, array + nids);
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	*idsp = array;
7137c478bd9Sstevel@tonic-gate 	return (count + nids);
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate /*
7177c478bd9Sstevel@tonic-gate  * parse_ids
7187c478bd9Sstevel@tonic-gate  *
7197c478bd9Sstevel@tonic-gate  * Extract a list of ids from the comma- or space- separated string str
7207c478bd9Sstevel@tonic-gate  * and append them to the array *idsp, growing it if necessary.
7217c478bd9Sstevel@tonic-gate  */
7227c478bd9Sstevel@tonic-gate static int
7237c478bd9Sstevel@tonic-gate parse_ids(const char *arg, int **idsp, int nids)
7247c478bd9Sstevel@tonic-gate {
7257c478bd9Sstevel@tonic-gate 	return (parse(arg, idsp, nids, mystrtoul));
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate /*
7297c478bd9Sstevel@tonic-gate  * parse_types
7307c478bd9Sstevel@tonic-gate  *
7317c478bd9Sstevel@tonic-gate  * Extract a list of types from the comma- or space- separated string
7327c478bd9Sstevel@tonic-gate  * str and append them to the array *idsp, growing it if necessary.
7337c478bd9Sstevel@tonic-gate  */
7347c478bd9Sstevel@tonic-gate static int
7357c478bd9Sstevel@tonic-gate parse_types(const char *arg, int **typesp, int ntypes)
7367c478bd9Sstevel@tonic-gate {
7377c478bd9Sstevel@tonic-gate 	return (parse(arg, typesp, ntypes, get_type));
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate /*
7417c478bd9Sstevel@tonic-gate  * compact
7427c478bd9Sstevel@tonic-gate  *
7437c478bd9Sstevel@tonic-gate  * Sorts and removes duplicates from array.  Initial size of array is
7447c478bd9Sstevel@tonic-gate  * in *size; final size is stored in *size.
7457c478bd9Sstevel@tonic-gate  */
7467c478bd9Sstevel@tonic-gate static void
7477c478bd9Sstevel@tonic-gate compact(int *array, int *size)
7487c478bd9Sstevel@tonic-gate {
7497c478bd9Sstevel@tonic-gate 	int i, j, last = -1;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	qsort(array, *size, sizeof (int), int_compar);
7527c478bd9Sstevel@tonic-gate 	for (i = j = 0; i < *size; i++) {
7537c478bd9Sstevel@tonic-gate 		if (array[i] != last) {
7547c478bd9Sstevel@tonic-gate 			last = array[i];
7557c478bd9Sstevel@tonic-gate 			array[j++] = array[i];
7567c478bd9Sstevel@tonic-gate 		}
7577c478bd9Sstevel@tonic-gate 	}
7587c478bd9Sstevel@tonic-gate 	*size = j;
7597c478bd9Sstevel@tonic-gate }
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate int
7627c478bd9Sstevel@tonic-gate main(int argc, char **argv)
7637c478bd9Sstevel@tonic-gate {
7647c478bd9Sstevel@tonic-gate 	unsigned int interval = 0, count = 1;
7657c478bd9Sstevel@tonic-gate 	ctid_t	*ids = NULL;
7667c478bd9Sstevel@tonic-gate 	int	*types = NULL;
7677c478bd9Sstevel@tonic-gate 	int	nids = 0, ntypes = 0;
7687c478bd9Sstevel@tonic-gate 	int	i, s;
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
7717c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	(void) uu_setpname(argv[0]);
7747c478bd9Sstevel@tonic-gate 
775*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 	while ((s = getopt(argc, argv, "ai:T:t:v")) != EOF) {
7767c478bd9Sstevel@tonic-gate 		switch (s) {
7777c478bd9Sstevel@tonic-gate 		case 'a':
7787c478bd9Sstevel@tonic-gate 			opt_showall = 1;
7797c478bd9Sstevel@tonic-gate 			break;
7807c478bd9Sstevel@tonic-gate 		case 'i':
7817c478bd9Sstevel@tonic-gate 			nids = parse_ids(optarg, (int **)&ids, nids);
7827c478bd9Sstevel@tonic-gate 			break;
783*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 		case 'T':
784*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 			if (optarg) {
785*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 				if (*optarg == 'u')
786*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 					timestamp_fmt = UDATE;
787*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 				else if (*optarg == 'd')
788*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 					timestamp_fmt = DDATE;
789*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 				else
790*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 					usage();
791*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 			} else {
792*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 				usage();
793*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 			}
794*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 			break;
7957c478bd9Sstevel@tonic-gate 		case 't':
7967c478bd9Sstevel@tonic-gate 			ntypes = parse_types(optarg, &types, ntypes);
7977c478bd9Sstevel@tonic-gate 			break;
7987c478bd9Sstevel@tonic-gate 		case 'v':
7997c478bd9Sstevel@tonic-gate 			opt_verbose = 1;
8007c478bd9Sstevel@tonic-gate 			break;
8017c478bd9Sstevel@tonic-gate 		default:
8027c478bd9Sstevel@tonic-gate 			usage();
8037c478bd9Sstevel@tonic-gate 		}
8047c478bd9Sstevel@tonic-gate 	}
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	argc -= optind;
8077c478bd9Sstevel@tonic-gate 	argv += optind;
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	if (argc > 2 || argc < 0)
8107c478bd9Sstevel@tonic-gate 		usage();
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	if (argc > 0) {
8137c478bd9Sstevel@tonic-gate 		interval = mystrtoul(argv[0]);
8147c478bd9Sstevel@tonic-gate 		count = 0;
8157c478bd9Sstevel@tonic-gate 	}
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	if (argc > 1) {
8187c478bd9Sstevel@tonic-gate 		count = mystrtoul(argv[1]);
8197c478bd9Sstevel@tonic-gate 		if (count == 0)
8207c478bd9Sstevel@tonic-gate 			return (0);
8217c478bd9Sstevel@tonic-gate 	}
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	if (nids)
8247c478bd9Sstevel@tonic-gate 		compact((int *)ids, &nids);
8257c478bd9Sstevel@tonic-gate 	if (ntypes)
8267c478bd9Sstevel@tonic-gate 		compact(types, &ntypes);
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	for (i = 0; count == 0 || i < count; i++) {
8297c478bd9Sstevel@tonic-gate 		if (i)
8307c478bd9Sstevel@tonic-gate 			(void) sleep(interval);
831*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 		if (timestamp_fmt != NODATE)
832*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 			print_timestamp(timestamp_fmt);
8337c478bd9Sstevel@tonic-gate 		print_header();
8347c478bd9Sstevel@tonic-gate 		if (nids && ntypes)
8357c478bd9Sstevel@tonic-gate 			scan_all(types, ntypes, ids, nids);
8367c478bd9Sstevel@tonic-gate 		else if (ntypes == 1)
8377c478bd9Sstevel@tonic-gate 			scan_type(*types);
8387c478bd9Sstevel@tonic-gate 		else if (nids)
8397c478bd9Sstevel@tonic-gate 			scan_ids(ids, nids);
8407c478bd9Sstevel@tonic-gate 		else
8417c478bd9Sstevel@tonic-gate 			scan_all(types, ntypes, ids, nids);
8427c478bd9Sstevel@tonic-gate 	}
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	return (0);
8457c478bd9Sstevel@tonic-gate }
846