xref: /titanic_53/usr/src/cmd/svc/svcs/svcs.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  *
22*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
23*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*7c478bd9Sstevel@tonic-gate  */
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate /*
29*7c478bd9Sstevel@tonic-gate  * svcs - display attributes of service instances
30*7c478bd9Sstevel@tonic-gate  *
31*7c478bd9Sstevel@tonic-gate  * We have two output formats and six instance selection mechanisms.  The
32*7c478bd9Sstevel@tonic-gate  * primary output format is a line of attributes (selected by -o), possibly
33*7c478bd9Sstevel@tonic-gate  * followed by process description lines (if -p is specified), for each
34*7c478bd9Sstevel@tonic-gate  * instance selected.  The columns available to display are described by the
35*7c478bd9Sstevel@tonic-gate  * struct column columns array.  The columns to actually display are kept in
36*7c478bd9Sstevel@tonic-gate  * the opt_columns array as indicies into the columns array.  The selection
37*7c478bd9Sstevel@tonic-gate  * mechanisms available for this format are service FMRIs (selects all child
38*7c478bd9Sstevel@tonic-gate  * instances), instance FMRIs, instance FMRI glob patterns, instances with
39*7c478bd9Sstevel@tonic-gate  * a certain restarter (-R), dependencies of instances (-d), and dependents of
40*7c478bd9Sstevel@tonic-gate  * instances (-D).  Since the lines must be sorted (per -sS), we'll just stick
41*7c478bd9Sstevel@tonic-gate  * each into a data structure and print them in order when we're done.  To
42*7c478bd9Sstevel@tonic-gate  * avoid listing the same instance twice (when -d and -D aren't given), we'll
43*7c478bd9Sstevel@tonic-gate  * use a hash table of FMRIs to record that we've listed (added to the tree)
44*7c478bd9Sstevel@tonic-gate  * an instance.
45*7c478bd9Sstevel@tonic-gate  *
46*7c478bd9Sstevel@tonic-gate  * The secondary output format (-l "long") is a paragraph of text for the
47*7c478bd9Sstevel@tonic-gate  * services or instances selected.  Not needing to be sorted, it's implemented
48*7c478bd9Sstevel@tonic-gate  * by just calling print_detailed() for each FMRI given.
49*7c478bd9Sstevel@tonic-gate  */
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #include "svcs.h"
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate /* Get the byteorder macros to ease sorting. */
54*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
55*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
56*7c478bd9Sstevel@tonic-gate #include <inttypes.h>
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate #include <sys/contract.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/ctfs.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate #include <assert.h>
63*7c478bd9Sstevel@tonic-gate #include <ctype.h>
64*7c478bd9Sstevel@tonic-gate #include <errno.h>
65*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
66*7c478bd9Sstevel@tonic-gate #include <fnmatch.h>
67*7c478bd9Sstevel@tonic-gate #include <libcontract.h>
68*7c478bd9Sstevel@tonic-gate #include <libcontract_priv.h>
69*7c478bd9Sstevel@tonic-gate #include <libintl.h>
70*7c478bd9Sstevel@tonic-gate #include <libscf.h>
71*7c478bd9Sstevel@tonic-gate #include <libscf_priv.h>
72*7c478bd9Sstevel@tonic-gate #include <libuutil.h>
73*7c478bd9Sstevel@tonic-gate #include <locale.h>
74*7c478bd9Sstevel@tonic-gate #include <procfs.h>
75*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
76*7c478bd9Sstevel@tonic-gate #include <stdio.h>
77*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
78*7c478bd9Sstevel@tonic-gate #include <strings.h>
79*7c478bd9Sstevel@tonic-gate #include <time.h>
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate #ifndef TEXT_DOMAIN
83*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
84*7c478bd9Sstevel@tonic-gate #endif /* TEXT_DOMAIN */
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate #define	LEGACY_SCHEME	"lrc:"
87*7c478bd9Sstevel@tonic-gate #define	LEGACY_UNKNOWN	"unknown"
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate /* Flags for pg_get_single_val() */
90*7c478bd9Sstevel@tonic-gate #define	EMPTY_OK	0x01
91*7c478bd9Sstevel@tonic-gate #define	MULTI_OK	0x02
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate /*
95*7c478bd9Sstevel@tonic-gate  * An AVL-storable node for output lines and the keys to sort them by.
96*7c478bd9Sstevel@tonic-gate  */
97*7c478bd9Sstevel@tonic-gate struct avl_string {
98*7c478bd9Sstevel@tonic-gate 	uu_avl_node_t	node;
99*7c478bd9Sstevel@tonic-gate 	char		*key;
100*7c478bd9Sstevel@tonic-gate 	char		*str;
101*7c478bd9Sstevel@tonic-gate };
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate /*
104*7c478bd9Sstevel@tonic-gate  * For lists of parsed restarter FMRIs.
105*7c478bd9Sstevel@tonic-gate  */
106*7c478bd9Sstevel@tonic-gate struct pfmri_list {
107*7c478bd9Sstevel@tonic-gate 	const char		*scope;
108*7c478bd9Sstevel@tonic-gate 	const char		*service;
109*7c478bd9Sstevel@tonic-gate 	const char		*instance;
110*7c478bd9Sstevel@tonic-gate 	struct pfmri_list	*next;
111*7c478bd9Sstevel@tonic-gate };
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate /*
115*7c478bd9Sstevel@tonic-gate  * Globals
116*7c478bd9Sstevel@tonic-gate  */
117*7c478bd9Sstevel@tonic-gate scf_handle_t *h;
118*7c478bd9Sstevel@tonic-gate static scf_propertygroup_t *g_pg;
119*7c478bd9Sstevel@tonic-gate static scf_property_t *g_prop;
120*7c478bd9Sstevel@tonic-gate static scf_value_t *g_val;
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate static size_t line_sz;			/* Bytes in the header line. */
123*7c478bd9Sstevel@tonic-gate static size_t sortkey_sz;		/* Bytes in sort keys. */
124*7c478bd9Sstevel@tonic-gate static uu_avl_pool_t *lines_pool;
125*7c478bd9Sstevel@tonic-gate static uu_avl_t *lines;			/* Output lines. */
126*7c478bd9Sstevel@tonic-gate int exit_status;
127*7c478bd9Sstevel@tonic-gate ssize_t max_scf_name_length;
128*7c478bd9Sstevel@tonic-gate ssize_t max_scf_value_length;
129*7c478bd9Sstevel@tonic-gate ssize_t max_scf_fmri_length;
130*7c478bd9Sstevel@tonic-gate static time_t now;
131*7c478bd9Sstevel@tonic-gate static struct pfmri_list *restarters = NULL;
132*7c478bd9Sstevel@tonic-gate static int first_paragraph = 1;		/* For -l mode. */
133*7c478bd9Sstevel@tonic-gate static char *common_name_buf;		/* Sized for maximal length value. */
134*7c478bd9Sstevel@tonic-gate char *locale;				/* Current locale. */
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate /* Options */
137*7c478bd9Sstevel@tonic-gate static int *opt_columns = NULL;		/* Indices into columns to display. */
138*7c478bd9Sstevel@tonic-gate static int opt_cnum = 0;
139*7c478bd9Sstevel@tonic-gate static int opt_processes = 0;		/* Print processes? */
140*7c478bd9Sstevel@tonic-gate static int *opt_sort = NULL;		/* Indices into columns to sort. */
141*7c478bd9Sstevel@tonic-gate static int opt_snum = 0;
142*7c478bd9Sstevel@tonic-gate static int opt_nstate_shown = 0;	/* Will nstate be shown? */
143*7c478bd9Sstevel@tonic-gate static int opt_verbose = 0;
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate /* Minimize string constants. */
146*7c478bd9Sstevel@tonic-gate static const char * const scf_property_state = SCF_PROPERTY_STATE;
147*7c478bd9Sstevel@tonic-gate static const char * const scf_property_next_state = SCF_PROPERTY_NEXT_STATE;
148*7c478bd9Sstevel@tonic-gate static const char * const scf_property_contract = SCF_PROPERTY_CONTRACT;
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate /*
152*7c478bd9Sstevel@tonic-gate  * Utility functions
153*7c478bd9Sstevel@tonic-gate  */
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate /*
156*7c478bd9Sstevel@tonic-gate  * For unexpected libscf errors.  The ending newline is necessary to keep
157*7c478bd9Sstevel@tonic-gate  * uu_die() from appending the errno error.
158*7c478bd9Sstevel@tonic-gate  */
159*7c478bd9Sstevel@tonic-gate #ifndef NDEBUG
160*7c478bd9Sstevel@tonic-gate void
161*7c478bd9Sstevel@tonic-gate do_scfdie(const char *file, int line)
162*7c478bd9Sstevel@tonic-gate {
163*7c478bd9Sstevel@tonic-gate 	uu_die(gettext("%s:%d: Unexpected libscf error: %s.  Exiting.\n"),
164*7c478bd9Sstevel@tonic-gate 	    file, line, scf_strerror(scf_error()));
165*7c478bd9Sstevel@tonic-gate }
166*7c478bd9Sstevel@tonic-gate #else
167*7c478bd9Sstevel@tonic-gate void
168*7c478bd9Sstevel@tonic-gate scfdie(void)
169*7c478bd9Sstevel@tonic-gate {
170*7c478bd9Sstevel@tonic-gate 	uu_die(gettext("Unexpected libscf error: %s.  Exiting.\n"),
171*7c478bd9Sstevel@tonic-gate 	    scf_strerror(scf_error()));
172*7c478bd9Sstevel@tonic-gate }
173*7c478bd9Sstevel@tonic-gate #endif
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate void *
176*7c478bd9Sstevel@tonic-gate safe_malloc(size_t sz)
177*7c478bd9Sstevel@tonic-gate {
178*7c478bd9Sstevel@tonic-gate 	void *ptr;
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	ptr = malloc(sz);
181*7c478bd9Sstevel@tonic-gate 	if (ptr == NULL)
182*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("Out of memory"));
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate 	return (ptr);
185*7c478bd9Sstevel@tonic-gate }
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate char *
188*7c478bd9Sstevel@tonic-gate safe_strdup(const char *str)
189*7c478bd9Sstevel@tonic-gate {
190*7c478bd9Sstevel@tonic-gate 	char *cp;
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 	cp = strdup(str);
193*7c478bd9Sstevel@tonic-gate 	if (cp == NULL)
194*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("Out of memory.\n"));
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	return (cp);
197*7c478bd9Sstevel@tonic-gate }
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate static void
200*7c478bd9Sstevel@tonic-gate sanitize_locale(char *locale)
201*7c478bd9Sstevel@tonic-gate {
202*7c478bd9Sstevel@tonic-gate 	for (; *locale != '\0'; locale++)
203*7c478bd9Sstevel@tonic-gate 		if (!isalnum(*locale))
204*7c478bd9Sstevel@tonic-gate 			*locale = '_';
205*7c478bd9Sstevel@tonic-gate }
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate /*
208*7c478bd9Sstevel@tonic-gate  * FMRI hashtable.  For uniquifing listings.
209*7c478bd9Sstevel@tonic-gate  */
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate struct ht_elem {
212*7c478bd9Sstevel@tonic-gate 	const char	*fmri;
213*7c478bd9Sstevel@tonic-gate 	struct ht_elem	*next;
214*7c478bd9Sstevel@tonic-gate };
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate static struct ht_elem	**ht_buckets;
217*7c478bd9Sstevel@tonic-gate static uint_t		ht_buckets_num;
218*7c478bd9Sstevel@tonic-gate static uint_t		ht_num;
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate static void
221*7c478bd9Sstevel@tonic-gate ht_init()
222*7c478bd9Sstevel@tonic-gate {
223*7c478bd9Sstevel@tonic-gate 	ht_buckets_num = 8;
224*7c478bd9Sstevel@tonic-gate 	ht_buckets = safe_malloc(sizeof (*ht_buckets) * ht_buckets_num);
225*7c478bd9Sstevel@tonic-gate 	bzero(ht_buckets, sizeof (*ht_buckets) * ht_buckets_num);
226*7c478bd9Sstevel@tonic-gate 	ht_num = 0;
227*7c478bd9Sstevel@tonic-gate }
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate static uint_t
230*7c478bd9Sstevel@tonic-gate ht_hash_fmri(const char *fmri)
231*7c478bd9Sstevel@tonic-gate {
232*7c478bd9Sstevel@tonic-gate 	uint_t h = 0, g;
233*7c478bd9Sstevel@tonic-gate 	const char *p, *k;
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	/* All FMRIs begin with svc:/, so skip that part. */
236*7c478bd9Sstevel@tonic-gate 	assert(strncmp(fmri, "svc:/", sizeof ("svc:/") - 1) == 0);
237*7c478bd9Sstevel@tonic-gate 	k = fmri + sizeof ("svc:/") - 1;
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	/*
240*7c478bd9Sstevel@tonic-gate 	 * Generic hash function from uts/common/os/modhash.c.
241*7c478bd9Sstevel@tonic-gate 	 */
242*7c478bd9Sstevel@tonic-gate 	for (p = k; *p != '\0'; ++p) {
243*7c478bd9Sstevel@tonic-gate 		h = (h << 4) + *p;
244*7c478bd9Sstevel@tonic-gate 		if ((g = (h & 0xf0000000)) != 0) {
245*7c478bd9Sstevel@tonic-gate 			h ^= (g >> 24);
246*7c478bd9Sstevel@tonic-gate 			h ^= g;
247*7c478bd9Sstevel@tonic-gate 		}
248*7c478bd9Sstevel@tonic-gate 	}
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	return (h);
251*7c478bd9Sstevel@tonic-gate }
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate static void
254*7c478bd9Sstevel@tonic-gate ht_grow()
255*7c478bd9Sstevel@tonic-gate {
256*7c478bd9Sstevel@tonic-gate 	uint_t new_ht_buckets_num;
257*7c478bd9Sstevel@tonic-gate 	struct ht_elem **new_ht_buckets;
258*7c478bd9Sstevel@tonic-gate 	int i;
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 	new_ht_buckets_num = ht_buckets_num * 2;
261*7c478bd9Sstevel@tonic-gate 	assert(new_ht_buckets_num > ht_buckets_num);
262*7c478bd9Sstevel@tonic-gate 	new_ht_buckets =
263*7c478bd9Sstevel@tonic-gate 	    safe_malloc(sizeof (*new_ht_buckets) * new_ht_buckets_num);
264*7c478bd9Sstevel@tonic-gate 	bzero(new_ht_buckets, sizeof (*new_ht_buckets) * new_ht_buckets_num);
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ht_buckets_num; ++i) {
267*7c478bd9Sstevel@tonic-gate 		struct ht_elem *elem, *next;
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 		for (elem = ht_buckets[i]; elem != NULL; elem = next) {
270*7c478bd9Sstevel@tonic-gate 			uint_t h;
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 			next = elem->next;
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 			h = ht_hash_fmri(elem->fmri);
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 			elem->next =
277*7c478bd9Sstevel@tonic-gate 			    new_ht_buckets[h & (new_ht_buckets_num - 1)];
278*7c478bd9Sstevel@tonic-gate 			new_ht_buckets[h & (new_ht_buckets_num - 1)] = elem;
279*7c478bd9Sstevel@tonic-gate 		}
280*7c478bd9Sstevel@tonic-gate 	}
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	free(ht_buckets);
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	ht_buckets = new_ht_buckets;
285*7c478bd9Sstevel@tonic-gate 	ht_buckets_num = new_ht_buckets_num;
286*7c478bd9Sstevel@tonic-gate }
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate /*
289*7c478bd9Sstevel@tonic-gate  * Add an FMRI to the hash table.  Returns 1 if it was already there,
290*7c478bd9Sstevel@tonic-gate  * 0 otherwise.
291*7c478bd9Sstevel@tonic-gate  */
292*7c478bd9Sstevel@tonic-gate static int
293*7c478bd9Sstevel@tonic-gate ht_add(const char *fmri)
294*7c478bd9Sstevel@tonic-gate {
295*7c478bd9Sstevel@tonic-gate 	uint_t h;
296*7c478bd9Sstevel@tonic-gate 	struct ht_elem *elem;
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 	h = ht_hash_fmri(fmri);
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	elem = ht_buckets[h & (ht_buckets_num - 1)];
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	for (; elem != NULL; elem = elem->next) {
303*7c478bd9Sstevel@tonic-gate 		if (strcmp(elem->fmri, fmri) == 0)
304*7c478bd9Sstevel@tonic-gate 			return (1);
305*7c478bd9Sstevel@tonic-gate 	}
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 	/* Grow when average chain length is over 3. */
308*7c478bd9Sstevel@tonic-gate 	if (ht_num > 3 * ht_buckets_num)
309*7c478bd9Sstevel@tonic-gate 		ht_grow();
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	++ht_num;
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 	elem = safe_malloc(sizeof (*elem));
314*7c478bd9Sstevel@tonic-gate 	elem->fmri = strdup(fmri);
315*7c478bd9Sstevel@tonic-gate 	elem->next = ht_buckets[h & (ht_buckets_num - 1)];
316*7c478bd9Sstevel@tonic-gate 	ht_buckets[h & (ht_buckets_num - 1)] = elem;
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	return (0);
319*7c478bd9Sstevel@tonic-gate }
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate /*
324*7c478bd9Sstevel@tonic-gate  * Convenience libscf wrapper functions.
325*7c478bd9Sstevel@tonic-gate  */
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate /*
328*7c478bd9Sstevel@tonic-gate  * Get the single value of the named property in the given property group,
329*7c478bd9Sstevel@tonic-gate  * which must have type ty, and put it in *vp.  If ty is SCF_TYPE_ASTRING, vp
330*7c478bd9Sstevel@tonic-gate  * is taken to be a char **, and sz is the size of the buffer.  sz is unused
331*7c478bd9Sstevel@tonic-gate  * otherwise.  Return 0 on success, -1 if the property doesn't exist, has the
332*7c478bd9Sstevel@tonic-gate  * wrong type, or doesn't have a single value.  If flags has EMPTY_OK, don't
333*7c478bd9Sstevel@tonic-gate  * complain if the property has no values (but return nonzero).  If flags has
334*7c478bd9Sstevel@tonic-gate  * MULTI_OK and the property has multiple values, succeed with E2BIG.
335*7c478bd9Sstevel@tonic-gate  */
336*7c478bd9Sstevel@tonic-gate int
337*7c478bd9Sstevel@tonic-gate pg_get_single_val(scf_propertygroup_t *pg, const char *propname, scf_type_t ty,
338*7c478bd9Sstevel@tonic-gate     void *vp, size_t sz, uint_t flags)
339*7c478bd9Sstevel@tonic-gate {
340*7c478bd9Sstevel@tonic-gate 	char *buf;
341*7c478bd9Sstevel@tonic-gate 	size_t buf_sz;
342*7c478bd9Sstevel@tonic-gate 	int ret = -1, r;
343*7c478bd9Sstevel@tonic-gate 	boolean_t multi = B_FALSE;
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	assert((flags & ~(EMPTY_OK | MULTI_OK)) == 0);
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, propname, g_prop) == -1) {
348*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
349*7c478bd9Sstevel@tonic-gate 			scfdie();
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 		goto out;
352*7c478bd9Sstevel@tonic-gate 	}
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	if (scf_property_is_type(g_prop, ty) != SCF_SUCCESS) {
355*7c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_TYPE_MISMATCH)
356*7c478bd9Sstevel@tonic-gate 			goto misconfigured;
357*7c478bd9Sstevel@tonic-gate 		scfdie();
358*7c478bd9Sstevel@tonic-gate 	}
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	if (scf_property_get_value(g_prop, g_val) != SCF_SUCCESS) {
361*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
362*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
363*7c478bd9Sstevel@tonic-gate 			if (flags & EMPTY_OK)
364*7c478bd9Sstevel@tonic-gate 				goto out;
365*7c478bd9Sstevel@tonic-gate 			goto misconfigured;
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
368*7c478bd9Sstevel@tonic-gate 			if (flags & MULTI_OK) {
369*7c478bd9Sstevel@tonic-gate 				multi = B_TRUE;
370*7c478bd9Sstevel@tonic-gate 				break;
371*7c478bd9Sstevel@tonic-gate 			}
372*7c478bd9Sstevel@tonic-gate 			goto misconfigured;
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 		default:
375*7c478bd9Sstevel@tonic-gate 			scfdie();
376*7c478bd9Sstevel@tonic-gate 		}
377*7c478bd9Sstevel@tonic-gate 	}
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	switch (ty) {
380*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_ASTRING:
381*7c478bd9Sstevel@tonic-gate 		r = scf_value_get_astring(g_val, vp, sz) > 0 ? SCF_SUCCESS : -1;
382*7c478bd9Sstevel@tonic-gate 		break;
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_BOOLEAN:
385*7c478bd9Sstevel@tonic-gate 		r = scf_value_get_boolean(g_val, (uint8_t *)vp);
386*7c478bd9Sstevel@tonic-gate 		break;
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_COUNT:
389*7c478bd9Sstevel@tonic-gate 		r = scf_value_get_count(g_val, (uint64_t *)vp);
390*7c478bd9Sstevel@tonic-gate 		break;
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_INTEGER:
393*7c478bd9Sstevel@tonic-gate 		r = scf_value_get_integer(g_val, (int64_t *)vp);
394*7c478bd9Sstevel@tonic-gate 		break;
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_TIME: {
397*7c478bd9Sstevel@tonic-gate 		int64_t sec;
398*7c478bd9Sstevel@tonic-gate 		int32_t ns;
399*7c478bd9Sstevel@tonic-gate 		r = scf_value_get_time(g_val, &sec, &ns);
400*7c478bd9Sstevel@tonic-gate 		((struct timeval *)vp)->tv_sec = sec;
401*7c478bd9Sstevel@tonic-gate 		((struct timeval *)vp)->tv_usec = ns / 1000;
402*7c478bd9Sstevel@tonic-gate 		break;
403*7c478bd9Sstevel@tonic-gate 	}
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	case SCF_TYPE_USTRING:
406*7c478bd9Sstevel@tonic-gate 		r = scf_value_get_ustring(g_val, vp, sz) > 0 ? SCF_SUCCESS : -1;
407*7c478bd9Sstevel@tonic-gate 		break;
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 	default:
410*7c478bd9Sstevel@tonic-gate #ifndef NDEBUG
411*7c478bd9Sstevel@tonic-gate 		uu_warn("%s:%d: Unknown type %d.\n", __FILE__, __LINE__, ty);
412*7c478bd9Sstevel@tonic-gate #endif
413*7c478bd9Sstevel@tonic-gate 		abort();
414*7c478bd9Sstevel@tonic-gate 	}
415*7c478bd9Sstevel@tonic-gate 	if (r != SCF_SUCCESS)
416*7c478bd9Sstevel@tonic-gate 		scfdie();
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 	ret = multi ? E2BIG : 0;
419*7c478bd9Sstevel@tonic-gate 	goto out;
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate misconfigured:
422*7c478bd9Sstevel@tonic-gate 	buf_sz = max_scf_fmri_length + 1;
423*7c478bd9Sstevel@tonic-gate 	buf = safe_malloc(buf_sz);
424*7c478bd9Sstevel@tonic-gate 	if (scf_property_to_fmri(g_prop, buf, buf_sz) == -1)
425*7c478bd9Sstevel@tonic-gate 		scfdie();
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	uu_warn(gettext("Property \"%s\" is misconfigured.\n"), buf);
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	free(buf);
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate out:
432*7c478bd9Sstevel@tonic-gate 	return (ret);
433*7c478bd9Sstevel@tonic-gate }
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate static scf_snapshot_t *
436*7c478bd9Sstevel@tonic-gate get_running_snapshot(scf_instance_t *inst)
437*7c478bd9Sstevel@tonic-gate {
438*7c478bd9Sstevel@tonic-gate 	scf_snapshot_t *snap;
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 	snap = scf_snapshot_create(h);
441*7c478bd9Sstevel@tonic-gate 	if (snap == NULL)
442*7c478bd9Sstevel@tonic-gate 		scfdie();
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_snapshot(inst, "running", snap) == 0)
445*7c478bd9Sstevel@tonic-gate 		return (snap);
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	if (scf_error() != SCF_ERROR_NOT_FOUND)
448*7c478bd9Sstevel@tonic-gate 		scfdie();
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	scf_snapshot_destroy(snap);
451*7c478bd9Sstevel@tonic-gate 	return (NULL);
452*7c478bd9Sstevel@tonic-gate }
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate /*
455*7c478bd9Sstevel@tonic-gate  * As pg_get_single_val(), except look the property group up in an
456*7c478bd9Sstevel@tonic-gate  * instance.  If "use_running" is set, and the running snapshot exists,
457*7c478bd9Sstevel@tonic-gate  * do a composed lookup there.  Otherwise, do an (optionally composed)
458*7c478bd9Sstevel@tonic-gate  * lookup on the current values.  Note that lookups using snapshots are
459*7c478bd9Sstevel@tonic-gate  * always composed.
460*7c478bd9Sstevel@tonic-gate  */
461*7c478bd9Sstevel@tonic-gate int
462*7c478bd9Sstevel@tonic-gate inst_get_single_val(scf_instance_t *inst, const char *pgname,
463*7c478bd9Sstevel@tonic-gate     const char *propname, scf_type_t ty, void *vp, size_t sz, uint_t flags,
464*7c478bd9Sstevel@tonic-gate     int use_running, int composed)
465*7c478bd9Sstevel@tonic-gate {
466*7c478bd9Sstevel@tonic-gate 	scf_snapshot_t *snap = NULL;
467*7c478bd9Sstevel@tonic-gate 	int r;
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	if (use_running)
470*7c478bd9Sstevel@tonic-gate 		snap = get_running_snapshot(inst);
471*7c478bd9Sstevel@tonic-gate 	if (composed || use_running)
472*7c478bd9Sstevel@tonic-gate 		r = scf_instance_get_pg_composed(inst, snap, pgname, g_pg);
473*7c478bd9Sstevel@tonic-gate 	else
474*7c478bd9Sstevel@tonic-gate 		r = scf_instance_get_pg(inst, pgname, g_pg);
475*7c478bd9Sstevel@tonic-gate 	if (snap)
476*7c478bd9Sstevel@tonic-gate 		scf_snapshot_destroy(snap);
477*7c478bd9Sstevel@tonic-gate 	if (r == -1)
478*7c478bd9Sstevel@tonic-gate 		return (-1);
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	r = pg_get_single_val(g_pg, propname, ty, vp, sz, flags);
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	return (r);
483*7c478bd9Sstevel@tonic-gate }
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate static int
486*7c478bd9Sstevel@tonic-gate instance_enabled(scf_instance_t *inst, boolean_t temp)
487*7c478bd9Sstevel@tonic-gate {
488*7c478bd9Sstevel@tonic-gate 	uint8_t b;
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	if (inst_get_single_val(inst,
491*7c478bd9Sstevel@tonic-gate 	    temp ? SCF_PG_GENERAL_OVR : SCF_PG_GENERAL, SCF_PROPERTY_ENABLED,
492*7c478bd9Sstevel@tonic-gate 	    SCF_TYPE_BOOLEAN, &b, 0, 0, 0, 0) != 0)
493*7c478bd9Sstevel@tonic-gate 		return (-1);
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	return (b ? 1 : 0);
496*7c478bd9Sstevel@tonic-gate }
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate /*
499*7c478bd9Sstevel@tonic-gate  * Get a string property from the restarter property group of the given
500*7c478bd9Sstevel@tonic-gate  * instance.  Return an empty string on normal problems.
501*7c478bd9Sstevel@tonic-gate  */
502*7c478bd9Sstevel@tonic-gate static void
503*7c478bd9Sstevel@tonic-gate get_restarter_string_prop(scf_instance_t *inst, const char *pname,
504*7c478bd9Sstevel@tonic-gate     char *buf, size_t buf_sz)
505*7c478bd9Sstevel@tonic-gate {
506*7c478bd9Sstevel@tonic-gate 	if (inst_get_single_val(inst, SCF_PG_RESTARTER, pname,
507*7c478bd9Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, buf, buf_sz, 0, 0, 1) != 0)
508*7c478bd9Sstevel@tonic-gate 		*buf = '\0';
509*7c478bd9Sstevel@tonic-gate }
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate static int
512*7c478bd9Sstevel@tonic-gate get_restarter_time_prop(scf_instance_t *inst, const char *pname,
513*7c478bd9Sstevel@tonic-gate     struct timeval *tvp, int ok_if_empty)
514*7c478bd9Sstevel@tonic-gate {
515*7c478bd9Sstevel@tonic-gate 	int r;
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 	r = inst_get_single_val(inst, SCF_PG_RESTARTER, pname, SCF_TYPE_TIME,
518*7c478bd9Sstevel@tonic-gate 	    tvp, NULL, ok_if_empty ? EMPTY_OK : 0, 0, 1);
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 	return (r == 0 ? 0 : -1);
521*7c478bd9Sstevel@tonic-gate }
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate static int
524*7c478bd9Sstevel@tonic-gate get_restarter_count_prop(scf_instance_t *inst, const char *pname, uint64_t *cp,
525*7c478bd9Sstevel@tonic-gate     uint_t flags)
526*7c478bd9Sstevel@tonic-gate {
527*7c478bd9Sstevel@tonic-gate 	return (inst_get_single_val(inst, SCF_PG_RESTARTER, pname,
528*7c478bd9Sstevel@tonic-gate 	    SCF_TYPE_COUNT, cp, 0, flags, 0, 1));
529*7c478bd9Sstevel@tonic-gate }
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate /*
533*7c478bd9Sstevel@tonic-gate  * Generic functions
534*7c478bd9Sstevel@tonic-gate  */
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate static int
537*7c478bd9Sstevel@tonic-gate propvals_to_pids(scf_propertygroup_t *pg, const char *pname, pid_t **pidsp,
538*7c478bd9Sstevel@tonic-gate     uint_t *np, scf_property_t *prop, scf_value_t *val, scf_iter_t *iter)
539*7c478bd9Sstevel@tonic-gate {
540*7c478bd9Sstevel@tonic-gate 	scf_type_t ty;
541*7c478bd9Sstevel@tonic-gate 	int r, fd, err;
542*7c478bd9Sstevel@tonic-gate 	uint64_t c;
543*7c478bd9Sstevel@tonic-gate 	ct_stathdl_t ctst;
544*7c478bd9Sstevel@tonic-gate 	pid_t *pids;
545*7c478bd9Sstevel@tonic-gate 	uint_t m;
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, pname, prop) != 0) {
548*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
549*7c478bd9Sstevel@tonic-gate 			scfdie();
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 		return (ENOENT);
552*7c478bd9Sstevel@tonic-gate 	}
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 	if (scf_property_type(prop, &ty) != 0)
555*7c478bd9Sstevel@tonic-gate 		scfdie();
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	if (ty != SCF_TYPE_COUNT)
558*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 	if (scf_iter_property_values(iter, prop) != 0)
561*7c478bd9Sstevel@tonic-gate 		scfdie();
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 	for (;;) {
564*7c478bd9Sstevel@tonic-gate 		r = scf_iter_next_value(iter, val);
565*7c478bd9Sstevel@tonic-gate 		if (r == -1)
566*7c478bd9Sstevel@tonic-gate 			scfdie();
567*7c478bd9Sstevel@tonic-gate 		if (r == 0)
568*7c478bd9Sstevel@tonic-gate 			break;
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 		if (scf_value_get_count(val, &c) != 0)
571*7c478bd9Sstevel@tonic-gate 			scfdie();
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 		fd = contract_open(c, NULL, "status", O_RDONLY);
574*7c478bd9Sstevel@tonic-gate 		if (fd < 0)
575*7c478bd9Sstevel@tonic-gate 			continue;
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 		err = ct_status_read(fd, CTD_ALL, &ctst);
578*7c478bd9Sstevel@tonic-gate 		if (err != 0) {
579*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Could not read status of contract "
580*7c478bd9Sstevel@tonic-gate 			    "%ld: %s.\n"), c, strerror(err));
581*7c478bd9Sstevel@tonic-gate 			(void) close(fd);
582*7c478bd9Sstevel@tonic-gate 			continue;
583*7c478bd9Sstevel@tonic-gate 		}
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 		r = ct_pr_status_get_members(ctst, &pids, &m);
588*7c478bd9Sstevel@tonic-gate 		assert(r == 0);
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 		if (m == 0) {
591*7c478bd9Sstevel@tonic-gate 			ct_status_free(ctst);
592*7c478bd9Sstevel@tonic-gate 			continue;
593*7c478bd9Sstevel@tonic-gate 		}
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 		*pidsp = realloc(*pidsp, (*np + m) * sizeof (*pidsp));
596*7c478bd9Sstevel@tonic-gate 		if (*pidsp == NULL)
597*7c478bd9Sstevel@tonic-gate 			uu_die(gettext("Out of memory"));
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 		bcopy(pids, *pidsp + *np, m * sizeof (*pids));
600*7c478bd9Sstevel@tonic-gate 		*np += m;
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 		ct_status_free(ctst);
603*7c478bd9Sstevel@tonic-gate 	}
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 	return (0);
606*7c478bd9Sstevel@tonic-gate }
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate static int
609*7c478bd9Sstevel@tonic-gate instance_processes(scf_instance_t *inst, pid_t **pids, uint_t *np)
610*7c478bd9Sstevel@tonic-gate {
611*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
612*7c478bd9Sstevel@tonic-gate 	int ret;
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 	if ((iter = scf_iter_create(h)) == NULL)
615*7c478bd9Sstevel@tonic-gate 		scfdie();
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, g_pg) == 0) {
618*7c478bd9Sstevel@tonic-gate 		*pids = NULL;
619*7c478bd9Sstevel@tonic-gate 		*np = 0;
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 		(void) propvals_to_pids(g_pg, scf_property_contract, pids, np,
622*7c478bd9Sstevel@tonic-gate 		    g_prop, g_val, iter);
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 		(void) propvals_to_pids(g_pg, SCF_PROPERTY_TRANSIENT_CONTRACT,
625*7c478bd9Sstevel@tonic-gate 		    pids, np, g_prop, g_val, iter);
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate 		ret = 0;
628*7c478bd9Sstevel@tonic-gate 	} else {
629*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
630*7c478bd9Sstevel@tonic-gate 			scfdie();
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 		ret = -1;
633*7c478bd9Sstevel@tonic-gate 	}
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate 	return (ret);
638*7c478bd9Sstevel@tonic-gate }
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate static int
641*7c478bd9Sstevel@tonic-gate get_psinfo(pid_t pid, psinfo_t *psip)
642*7c478bd9Sstevel@tonic-gate {
643*7c478bd9Sstevel@tonic-gate 	char path[100];
644*7c478bd9Sstevel@tonic-gate 	int fd;
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "/proc/%lu/psinfo", pid);
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate 	fd = open64(path, O_RDONLY);
649*7c478bd9Sstevel@tonic-gate 	if (fd < 0)
650*7c478bd9Sstevel@tonic-gate 		return (-1);
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 	if (read(fd, psip, sizeof (*psip)) < 0)
653*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("Could not read info for process %lu"), pid);
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate 	return (0);
658*7c478bd9Sstevel@tonic-gate }
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate /*
663*7c478bd9Sstevel@tonic-gate  * Column sprint and sortkey functions
664*7c478bd9Sstevel@tonic-gate  */
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate struct column {
667*7c478bd9Sstevel@tonic-gate 	const char *name;
668*7c478bd9Sstevel@tonic-gate 	int width;
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 	/*
671*7c478bd9Sstevel@tonic-gate 	 * This function should write the value for the column into buf, and
672*7c478bd9Sstevel@tonic-gate 	 * grow or allocate buf accordingly.  It should always write at least
673*7c478bd9Sstevel@tonic-gate 	 * width bytes, blanking unused bytes with spaces.  If the field is
674*7c478bd9Sstevel@tonic-gate 	 * greater than the column width we allow it to overlap other columns.
675*7c478bd9Sstevel@tonic-gate 	 * In particular, it shouldn't write any null bytes.  (Though an extra
676*7c478bd9Sstevel@tonic-gate 	 * null byte past the end is currently tolerated.)  If the property
677*7c478bd9Sstevel@tonic-gate 	 * group is non-NULL, then we are dealing with a legacy service.
678*7c478bd9Sstevel@tonic-gate 	 */
679*7c478bd9Sstevel@tonic-gate 	void (*sprint)(char **, scf_walkinfo_t *);
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate 	int sortkey_width;
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 	/*
684*7c478bd9Sstevel@tonic-gate 	 * This function should write sortkey_width bytes into buf which will
685*7c478bd9Sstevel@tonic-gate 	 * cause memcmp() to sort it properly.  (Unlike sprint() above,
686*7c478bd9Sstevel@tonic-gate 	 * however, an extra null byte may overrun the buffer.)  The second
687*7c478bd9Sstevel@tonic-gate 	 * argument controls whether the results are sorted in forward or
688*7c478bd9Sstevel@tonic-gate 	 * reverse order.
689*7c478bd9Sstevel@tonic-gate 	 */
690*7c478bd9Sstevel@tonic-gate 	void (*get_sortkey)(char *, int, scf_walkinfo_t *);
691*7c478bd9Sstevel@tonic-gate };
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate static void
694*7c478bd9Sstevel@tonic-gate reverse_bytes(char *buf, size_t len)
695*7c478bd9Sstevel@tonic-gate {
696*7c478bd9Sstevel@tonic-gate 	int i;
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; ++i)
699*7c478bd9Sstevel@tonic-gate 		buf[i] = ~buf[i];
700*7c478bd9Sstevel@tonic-gate }
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate /* CTID */
703*7c478bd9Sstevel@tonic-gate #define	CTID_COLUMN_WIDTH		6
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate static void
706*7c478bd9Sstevel@tonic-gate sprint_ctid(char **buf, scf_walkinfo_t *wip)
707*7c478bd9Sstevel@tonic-gate {
708*7c478bd9Sstevel@tonic-gate 	int r;
709*7c478bd9Sstevel@tonic-gate 	uint64_t c;
710*7c478bd9Sstevel@tonic-gate 	size_t newsize = (*buf ? strlen(*buf) : 0) + CTID_COLUMN_WIDTH + 2;
711*7c478bd9Sstevel@tonic-gate 	char *newbuf = safe_malloc(newsize);
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 	if (wip->pg != NULL)
714*7c478bd9Sstevel@tonic-gate 		r = pg_get_single_val(wip->pg, scf_property_contract,
715*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_COUNT, &c, 0, EMPTY_OK | MULTI_OK);
716*7c478bd9Sstevel@tonic-gate 	else
717*7c478bd9Sstevel@tonic-gate 		r = get_restarter_count_prop(wip->inst, scf_property_contract,
718*7c478bd9Sstevel@tonic-gate 		    &c, EMPTY_OK | MULTI_OK);
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 	if (r == 0)
721*7c478bd9Sstevel@tonic-gate 		(void) snprintf(newbuf, newsize, "%s%*lu ",
722*7c478bd9Sstevel@tonic-gate 		    *buf ? *buf : "", CTID_COLUMN_WIDTH, (ctid_t)c);
723*7c478bd9Sstevel@tonic-gate 	else if (r == E2BIG)
724*7c478bd9Sstevel@tonic-gate 		(void) snprintf(newbuf, newsize, "%s%*lu* ",
725*7c478bd9Sstevel@tonic-gate 		    *buf ? *buf : "", CTID_COLUMN_WIDTH - 1, (ctid_t)c);
726*7c478bd9Sstevel@tonic-gate 	else
727*7c478bd9Sstevel@tonic-gate 		(void) snprintf(newbuf, newsize, "%s%*s ",
728*7c478bd9Sstevel@tonic-gate 		    *buf ? *buf : "", CTID_COLUMN_WIDTH, "-");
729*7c478bd9Sstevel@tonic-gate 	if (*buf)
730*7c478bd9Sstevel@tonic-gate 		free(*buf);
731*7c478bd9Sstevel@tonic-gate 	*buf = newbuf;
732*7c478bd9Sstevel@tonic-gate }
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate #define	CTID_SORTKEY_WIDTH		(sizeof (uint64_t))
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate static void
737*7c478bd9Sstevel@tonic-gate sortkey_ctid(char *buf, int reverse, scf_walkinfo_t *wip)
738*7c478bd9Sstevel@tonic-gate {
739*7c478bd9Sstevel@tonic-gate 	int r;
740*7c478bd9Sstevel@tonic-gate 	uint64_t c;
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 	if (wip->pg != NULL)
743*7c478bd9Sstevel@tonic-gate 		r = pg_get_single_val(wip->pg, scf_property_contract,
744*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_COUNT, &c, 0, EMPTY_OK);
745*7c478bd9Sstevel@tonic-gate 	else
746*7c478bd9Sstevel@tonic-gate 		r = get_restarter_count_prop(wip->inst, scf_property_contract,
747*7c478bd9Sstevel@tonic-gate 		    &c, EMPTY_OK);
748*7c478bd9Sstevel@tonic-gate 
749*7c478bd9Sstevel@tonic-gate 	if (r == 0) {
750*7c478bd9Sstevel@tonic-gate 		/*
751*7c478bd9Sstevel@tonic-gate 		 * Use the id itself, but it must be big-endian for this to
752*7c478bd9Sstevel@tonic-gate 		 * work.
753*7c478bd9Sstevel@tonic-gate 		 */
754*7c478bd9Sstevel@tonic-gate 		c = BE_64(c);
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 		bcopy(&c, buf, CTID_SORTKEY_WIDTH);
757*7c478bd9Sstevel@tonic-gate 	} else {
758*7c478bd9Sstevel@tonic-gate 		bzero(buf, CTID_SORTKEY_WIDTH);
759*7c478bd9Sstevel@tonic-gate 	}
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate 	if (reverse)
762*7c478bd9Sstevel@tonic-gate 		reverse_bytes(buf, CTID_SORTKEY_WIDTH);
763*7c478bd9Sstevel@tonic-gate }
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate /* DESC */
766*7c478bd9Sstevel@tonic-gate #define	DESC_COLUMN_WIDTH	100
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate static void
769*7c478bd9Sstevel@tonic-gate sprint_desc(char **buf, scf_walkinfo_t *wip)
770*7c478bd9Sstevel@tonic-gate {
771*7c478bd9Sstevel@tonic-gate 	char *x;
772*7c478bd9Sstevel@tonic-gate 	size_t newsize;
773*7c478bd9Sstevel@tonic-gate 	char *newbuf;
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate 	if (common_name_buf == NULL)
776*7c478bd9Sstevel@tonic-gate 		common_name_buf = safe_malloc(max_scf_value_length + 1);
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 	bzero(common_name_buf, max_scf_value_length + 1);
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate 	if (wip->pg != NULL) {
781*7c478bd9Sstevel@tonic-gate 		common_name_buf[0] = '-';
782*7c478bd9Sstevel@tonic-gate 	} else if (inst_get_single_val(wip->inst, SCF_PG_TM_COMMON_NAME, locale,
783*7c478bd9Sstevel@tonic-gate 	    SCF_TYPE_USTRING, common_name_buf, max_scf_value_length, 0,
784*7c478bd9Sstevel@tonic-gate 	    1, 1) == -1 &&
785*7c478bd9Sstevel@tonic-gate 	    inst_get_single_val(wip->inst, SCF_PG_TM_COMMON_NAME, "C",
786*7c478bd9Sstevel@tonic-gate 	    SCF_TYPE_USTRING, common_name_buf, max_scf_value_length, 0,
787*7c478bd9Sstevel@tonic-gate 	    1, 1) == -1) {
788*7c478bd9Sstevel@tonic-gate 		common_name_buf[0] = '-';
789*7c478bd9Sstevel@tonic-gate 	}
790*7c478bd9Sstevel@tonic-gate 
791*7c478bd9Sstevel@tonic-gate 	/*
792*7c478bd9Sstevel@tonic-gate 	 * Collapse multi-line tm_common_name values into a single line.
793*7c478bd9Sstevel@tonic-gate 	 */
794*7c478bd9Sstevel@tonic-gate 	for (x = common_name_buf; *x != '\0'; x++)
795*7c478bd9Sstevel@tonic-gate 		if (*x == '\n')
796*7c478bd9Sstevel@tonic-gate 			*x = ' ';
797*7c478bd9Sstevel@tonic-gate 
798*7c478bd9Sstevel@tonic-gate 	if (strlen(common_name_buf) > DESC_COLUMN_WIDTH)
799*7c478bd9Sstevel@tonic-gate 		newsize = (*buf ? strlen(*buf) : 0) +
800*7c478bd9Sstevel@tonic-gate 		    strlen(common_name_buf) + 1;
801*7c478bd9Sstevel@tonic-gate 	else
802*7c478bd9Sstevel@tonic-gate 		newsize = (*buf ? strlen(*buf) : 0) + DESC_COLUMN_WIDTH + 1;
803*7c478bd9Sstevel@tonic-gate 	newbuf = safe_malloc(newsize);
804*7c478bd9Sstevel@tonic-gate 	(void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
805*7c478bd9Sstevel@tonic-gate 			DESC_COLUMN_WIDTH, common_name_buf);
806*7c478bd9Sstevel@tonic-gate 	if (*buf)
807*7c478bd9Sstevel@tonic-gate 		free(*buf);
808*7c478bd9Sstevel@tonic-gate 	*buf = newbuf;
809*7c478bd9Sstevel@tonic-gate }
810*7c478bd9Sstevel@tonic-gate 
811*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
812*7c478bd9Sstevel@tonic-gate static void
813*7c478bd9Sstevel@tonic-gate sortkey_desc(char *buf, int reverse, scf_walkinfo_t *wip)
814*7c478bd9Sstevel@tonic-gate {
815*7c478bd9Sstevel@tonic-gate 	bzero(buf, DESC_COLUMN_WIDTH);
816*7c478bd9Sstevel@tonic-gate }
817*7c478bd9Sstevel@tonic-gate 
818*7c478bd9Sstevel@tonic-gate /* State columns (STATE, NSTATE, S, N, SN, STA, NSTA) */
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate static char
821*7c478bd9Sstevel@tonic-gate state_to_char(const char *state)
822*7c478bd9Sstevel@tonic-gate {
823*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0)
824*7c478bd9Sstevel@tonic-gate 		return ('u');
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_OFFLINE) == 0)
827*7c478bd9Sstevel@tonic-gate 		return ('0');
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0)
830*7c478bd9Sstevel@tonic-gate 		return ('1');
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_MAINT) == 0)
833*7c478bd9Sstevel@tonic-gate 		return ('m');
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0)
836*7c478bd9Sstevel@tonic-gate 		return ('d');
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)
839*7c478bd9Sstevel@tonic-gate 		return ('D');
840*7c478bd9Sstevel@tonic-gate 
841*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_LEGACY) == 0)
842*7c478bd9Sstevel@tonic-gate 		return ('L');
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate 	return ('?');
845*7c478bd9Sstevel@tonic-gate }
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate /* Return true if inst is transitioning. */
848*7c478bd9Sstevel@tonic-gate static int
849*7c478bd9Sstevel@tonic-gate transitioning(scf_instance_t *inst)
850*7c478bd9Sstevel@tonic-gate {
851*7c478bd9Sstevel@tonic-gate 	char nstate_name[MAX_SCF_STATE_STRING_SZ];
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 	get_restarter_string_prop(inst, scf_property_next_state, nstate_name,
854*7c478bd9Sstevel@tonic-gate 	    sizeof (nstate_name));
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 	return (state_to_char(nstate_name) != '?');
857*7c478bd9Sstevel@tonic-gate }
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
860*7c478bd9Sstevel@tonic-gate static void
861*7c478bd9Sstevel@tonic-gate sortkey_states(const char *pname, char *buf, int reverse, scf_walkinfo_t *wip)
862*7c478bd9Sstevel@tonic-gate {
863*7c478bd9Sstevel@tonic-gate 	char state_name[MAX_SCF_STATE_STRING_SZ];
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate 	/*
866*7c478bd9Sstevel@tonic-gate 	 * Lower numbers are printed first, so these are arranged from least
867*7c478bd9Sstevel@tonic-gate 	 * interesting ("legacy run") to most interesting (unknown).
868*7c478bd9Sstevel@tonic-gate 	 */
869*7c478bd9Sstevel@tonic-gate 	if (wip->pg == NULL) {
870*7c478bd9Sstevel@tonic-gate 		get_restarter_string_prop(wip->inst, pname, state_name,
871*7c478bd9Sstevel@tonic-gate 		    sizeof (state_name));
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 		if (strcmp(state_name, SCF_STATE_STRING_ONLINE) == 0)
874*7c478bd9Sstevel@tonic-gate 			*buf = 2;
875*7c478bd9Sstevel@tonic-gate 		else if (strcmp(state_name, SCF_STATE_STRING_DEGRADED) == 0)
876*7c478bd9Sstevel@tonic-gate 			*buf = 3;
877*7c478bd9Sstevel@tonic-gate 		else if (strcmp(state_name, SCF_STATE_STRING_OFFLINE) == 0)
878*7c478bd9Sstevel@tonic-gate 			*buf = 4;
879*7c478bd9Sstevel@tonic-gate 		else if (strcmp(state_name, SCF_STATE_STRING_MAINT) == 0)
880*7c478bd9Sstevel@tonic-gate 			*buf = 5;
881*7c478bd9Sstevel@tonic-gate 		else if (strcmp(state_name, SCF_STATE_STRING_DISABLED) == 0)
882*7c478bd9Sstevel@tonic-gate 			*buf = 1;
883*7c478bd9Sstevel@tonic-gate 		else if (strcmp(state_name, SCF_STATE_STRING_UNINIT) == 0)
884*7c478bd9Sstevel@tonic-gate 			*buf = 6;
885*7c478bd9Sstevel@tonic-gate 		else
886*7c478bd9Sstevel@tonic-gate 			*buf = 7;
887*7c478bd9Sstevel@tonic-gate 	} else
888*7c478bd9Sstevel@tonic-gate 		*buf = 0;
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate 	if (reverse)
891*7c478bd9Sstevel@tonic-gate 		*buf = 255 - *buf;
892*7c478bd9Sstevel@tonic-gate }
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate static void
895*7c478bd9Sstevel@tonic-gate sprint_state(char **buf, scf_walkinfo_t *wip)
896*7c478bd9Sstevel@tonic-gate {
897*7c478bd9Sstevel@tonic-gate 	char state_name[MAX_SCF_STATE_STRING_SZ + 1];
898*7c478bd9Sstevel@tonic-gate 	size_t newsize;
899*7c478bd9Sstevel@tonic-gate 	char *newbuf;
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate 	if (wip->pg == NULL) {
902*7c478bd9Sstevel@tonic-gate 		get_restarter_string_prop(wip->inst, scf_property_state,
903*7c478bd9Sstevel@tonic-gate 		    state_name, sizeof (state_name));
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 		/* Don't print blank fields, to ease parsing. */
906*7c478bd9Sstevel@tonic-gate 		if (state_name[0] == '\0') {
907*7c478bd9Sstevel@tonic-gate 			state_name[0] = '-';
908*7c478bd9Sstevel@tonic-gate 			state_name[1] = '\0';
909*7c478bd9Sstevel@tonic-gate 		}
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate 		if (!opt_nstate_shown && transitioning(wip->inst)) {
912*7c478bd9Sstevel@tonic-gate 			/* Append an asterisk if nstate is valid. */
913*7c478bd9Sstevel@tonic-gate 			(void) strcat(state_name, "*");
914*7c478bd9Sstevel@tonic-gate 		}
915*7c478bd9Sstevel@tonic-gate 	} else
916*7c478bd9Sstevel@tonic-gate 		(void) strcpy(state_name, SCF_STATE_STRING_LEGACY);
917*7c478bd9Sstevel@tonic-gate 
918*7c478bd9Sstevel@tonic-gate 	newsize = (*buf ? strlen(*buf) : 0) + MAX_SCF_STATE_STRING_SZ + 2;
919*7c478bd9Sstevel@tonic-gate 	newbuf = safe_malloc(newsize);
920*7c478bd9Sstevel@tonic-gate 	(void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
921*7c478bd9Sstevel@tonic-gate 	    MAX_SCF_STATE_STRING_SZ + 1, state_name);
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 	if (*buf)
924*7c478bd9Sstevel@tonic-gate 		free(*buf);
925*7c478bd9Sstevel@tonic-gate 	*buf = newbuf;
926*7c478bd9Sstevel@tonic-gate }
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate static void
929*7c478bd9Sstevel@tonic-gate sortkey_state(char *buf, int reverse, scf_walkinfo_t *wip)
930*7c478bd9Sstevel@tonic-gate {
931*7c478bd9Sstevel@tonic-gate 	sortkey_states(scf_property_state, buf, reverse, wip);
932*7c478bd9Sstevel@tonic-gate }
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate static void
935*7c478bd9Sstevel@tonic-gate sprint_nstate(char **buf, scf_walkinfo_t *wip)
936*7c478bd9Sstevel@tonic-gate {
937*7c478bd9Sstevel@tonic-gate 	char next_state_name[MAX_SCF_STATE_STRING_SZ];
938*7c478bd9Sstevel@tonic-gate 	boolean_t blank = 0;
939*7c478bd9Sstevel@tonic-gate 	size_t newsize;
940*7c478bd9Sstevel@tonic-gate 	char *newbuf;
941*7c478bd9Sstevel@tonic-gate 
942*7c478bd9Sstevel@tonic-gate 	if (wip->pg == NULL) {
943*7c478bd9Sstevel@tonic-gate 		get_restarter_string_prop(wip->inst, scf_property_next_state,
944*7c478bd9Sstevel@tonic-gate 		    next_state_name, sizeof (next_state_name));
945*7c478bd9Sstevel@tonic-gate 
946*7c478bd9Sstevel@tonic-gate 		/* Don't print blank fields, to ease parsing. */
947*7c478bd9Sstevel@tonic-gate 		if (next_state_name[0] == '\0' ||
948*7c478bd9Sstevel@tonic-gate 		    strcmp(next_state_name, SCF_STATE_STRING_NONE) == 0)
949*7c478bd9Sstevel@tonic-gate 			blank = 1;
950*7c478bd9Sstevel@tonic-gate 	} else
951*7c478bd9Sstevel@tonic-gate 		blank = 1;
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 	if (blank) {
954*7c478bd9Sstevel@tonic-gate 		next_state_name[0] = '-';
955*7c478bd9Sstevel@tonic-gate 		next_state_name[1] = '\0';
956*7c478bd9Sstevel@tonic-gate 	}
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	newsize = (*buf ? strlen(*buf) : 0) + MAX_SCF_STATE_STRING_SZ + 1;
959*7c478bd9Sstevel@tonic-gate 	newbuf = safe_malloc(newsize);
960*7c478bd9Sstevel@tonic-gate 	(void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
961*7c478bd9Sstevel@tonic-gate 	    MAX_SCF_STATE_STRING_SZ - 1, next_state_name);
962*7c478bd9Sstevel@tonic-gate 	if (*buf)
963*7c478bd9Sstevel@tonic-gate 		free(*buf);
964*7c478bd9Sstevel@tonic-gate 	*buf = newbuf;
965*7c478bd9Sstevel@tonic-gate }
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate static void
968*7c478bd9Sstevel@tonic-gate sortkey_nstate(char *buf, int reverse, scf_walkinfo_t *wip)
969*7c478bd9Sstevel@tonic-gate {
970*7c478bd9Sstevel@tonic-gate 	sortkey_states(scf_property_next_state, buf, reverse, wip);
971*7c478bd9Sstevel@tonic-gate }
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate static void
974*7c478bd9Sstevel@tonic-gate sprint_s(char **buf, scf_walkinfo_t *wip)
975*7c478bd9Sstevel@tonic-gate {
976*7c478bd9Sstevel@tonic-gate 	char tmp[3];
977*7c478bd9Sstevel@tonic-gate 	char state_name[MAX_SCF_STATE_STRING_SZ];
978*7c478bd9Sstevel@tonic-gate 	size_t newsize = (*buf ? strlen(*buf) : 0) + 4;
979*7c478bd9Sstevel@tonic-gate 	char *newbuf = safe_malloc(newsize);
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate 	if (wip->pg == NULL) {
982*7c478bd9Sstevel@tonic-gate 		get_restarter_string_prop(wip->inst, scf_property_state,
983*7c478bd9Sstevel@tonic-gate 		    state_name, sizeof (state_name));
984*7c478bd9Sstevel@tonic-gate 		tmp[0] = state_to_char(state_name);
985*7c478bd9Sstevel@tonic-gate 
986*7c478bd9Sstevel@tonic-gate 		if (!opt_nstate_shown && transitioning(wip->inst))
987*7c478bd9Sstevel@tonic-gate 			tmp[1] = '*';
988*7c478bd9Sstevel@tonic-gate 		else
989*7c478bd9Sstevel@tonic-gate 			tmp[1] = ' ';
990*7c478bd9Sstevel@tonic-gate 	} else {
991*7c478bd9Sstevel@tonic-gate 		tmp[0] = 'L';
992*7c478bd9Sstevel@tonic-gate 		tmp[1] = ' ';
993*7c478bd9Sstevel@tonic-gate 	}
994*7c478bd9Sstevel@tonic-gate 	tmp[2] = ' ';
995*7c478bd9Sstevel@tonic-gate 	(void) snprintf(newbuf, newsize, "%s%-*s", *buf ? *buf : "",
996*7c478bd9Sstevel@tonic-gate 	    3, tmp);
997*7c478bd9Sstevel@tonic-gate 	if (*buf)
998*7c478bd9Sstevel@tonic-gate 		free(*buf);
999*7c478bd9Sstevel@tonic-gate 	*buf = newbuf;
1000*7c478bd9Sstevel@tonic-gate }
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate static void
1003*7c478bd9Sstevel@tonic-gate sprint_n(char **buf, scf_walkinfo_t *wip)
1004*7c478bd9Sstevel@tonic-gate {
1005*7c478bd9Sstevel@tonic-gate 	char tmp[2];
1006*7c478bd9Sstevel@tonic-gate 	size_t newsize = (*buf ? strlen(*buf) : 0) + 3;
1007*7c478bd9Sstevel@tonic-gate 	char *newbuf = safe_malloc(newsize);
1008*7c478bd9Sstevel@tonic-gate 	char nstate_name[MAX_SCF_STATE_STRING_SZ];
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 	if (wip->pg == NULL) {
1011*7c478bd9Sstevel@tonic-gate 		get_restarter_string_prop(wip->inst, scf_property_next_state,
1012*7c478bd9Sstevel@tonic-gate 		    nstate_name, sizeof (nstate_name));
1013*7c478bd9Sstevel@tonic-gate 
1014*7c478bd9Sstevel@tonic-gate 		if (strcmp(nstate_name, SCF_STATE_STRING_NONE) == 0)
1015*7c478bd9Sstevel@tonic-gate 			tmp[0] = '-';
1016*7c478bd9Sstevel@tonic-gate 		else
1017*7c478bd9Sstevel@tonic-gate 			tmp[0] = state_to_char(nstate_name);
1018*7c478bd9Sstevel@tonic-gate 	} else
1019*7c478bd9Sstevel@tonic-gate 		tmp[0] = '-';
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 	(void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1022*7c478bd9Sstevel@tonic-gate 	    2, tmp);
1023*7c478bd9Sstevel@tonic-gate 	if (*buf)
1024*7c478bd9Sstevel@tonic-gate 		free(*buf);
1025*7c478bd9Sstevel@tonic-gate 	*buf = newbuf;
1026*7c478bd9Sstevel@tonic-gate }
1027*7c478bd9Sstevel@tonic-gate 
1028*7c478bd9Sstevel@tonic-gate static void
1029*7c478bd9Sstevel@tonic-gate sprint_sn(char **buf, scf_walkinfo_t *wip)
1030*7c478bd9Sstevel@tonic-gate {
1031*7c478bd9Sstevel@tonic-gate 	char tmp[3];
1032*7c478bd9Sstevel@tonic-gate 	size_t newsize = (*buf ? strlen(*buf) : 0) + 4;
1033*7c478bd9Sstevel@tonic-gate 	char *newbuf = safe_malloc(newsize);
1034*7c478bd9Sstevel@tonic-gate 	char nstate_name[MAX_SCF_STATE_STRING_SZ];
1035*7c478bd9Sstevel@tonic-gate 	char state_name[MAX_SCF_STATE_STRING_SZ];
1036*7c478bd9Sstevel@tonic-gate 
1037*7c478bd9Sstevel@tonic-gate 	if (wip->pg == NULL) {
1038*7c478bd9Sstevel@tonic-gate 		get_restarter_string_prop(wip->inst, scf_property_state,
1039*7c478bd9Sstevel@tonic-gate 		    state_name, sizeof (state_name));
1040*7c478bd9Sstevel@tonic-gate 		get_restarter_string_prop(wip->inst, scf_property_next_state,
1041*7c478bd9Sstevel@tonic-gate 		    nstate_name, sizeof (nstate_name));
1042*7c478bd9Sstevel@tonic-gate 		tmp[0] = state_to_char(state_name);
1043*7c478bd9Sstevel@tonic-gate 
1044*7c478bd9Sstevel@tonic-gate 		if (strcmp(nstate_name, SCF_STATE_STRING_NONE) == 0)
1045*7c478bd9Sstevel@tonic-gate 			tmp[1] = '-';
1046*7c478bd9Sstevel@tonic-gate 		else
1047*7c478bd9Sstevel@tonic-gate 			tmp[1] = state_to_char(nstate_name);
1048*7c478bd9Sstevel@tonic-gate 	} else {
1049*7c478bd9Sstevel@tonic-gate 		tmp[0] = 'L';
1050*7c478bd9Sstevel@tonic-gate 		tmp[1] = '-';
1051*7c478bd9Sstevel@tonic-gate 	}
1052*7c478bd9Sstevel@tonic-gate 
1053*7c478bd9Sstevel@tonic-gate 	tmp[2] = ' ';
1054*7c478bd9Sstevel@tonic-gate 	(void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1055*7c478bd9Sstevel@tonic-gate 	    3, tmp);
1056*7c478bd9Sstevel@tonic-gate 	if (*buf)
1057*7c478bd9Sstevel@tonic-gate 		free(*buf);
1058*7c478bd9Sstevel@tonic-gate 	*buf = newbuf;
1059*7c478bd9Sstevel@tonic-gate }
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1062*7c478bd9Sstevel@tonic-gate static void
1063*7c478bd9Sstevel@tonic-gate sortkey_sn(char *buf, int reverse, scf_walkinfo_t *wip)
1064*7c478bd9Sstevel@tonic-gate {
1065*7c478bd9Sstevel@tonic-gate 	sortkey_state(buf, reverse, wip);
1066*7c478bd9Sstevel@tonic-gate 	sortkey_nstate(buf + 1, reverse, wip);
1067*7c478bd9Sstevel@tonic-gate }
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate static const char *
1070*7c478bd9Sstevel@tonic-gate state_abbrev(const char *state)
1071*7c478bd9Sstevel@tonic-gate {
1072*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0)
1073*7c478bd9Sstevel@tonic-gate 		return ("UN");
1074*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_OFFLINE) == 0)
1075*7c478bd9Sstevel@tonic-gate 		return ("OFF");
1076*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0)
1077*7c478bd9Sstevel@tonic-gate 		return ("ON");
1078*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_MAINT) == 0)
1079*7c478bd9Sstevel@tonic-gate 		return ("MNT");
1080*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0)
1081*7c478bd9Sstevel@tonic-gate 		return ("DIS");
1082*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)
1083*7c478bd9Sstevel@tonic-gate 		return ("DGD");
1084*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_LEGACY) == 0)
1085*7c478bd9Sstevel@tonic-gate 		return ("LRC");
1086*7c478bd9Sstevel@tonic-gate 
1087*7c478bd9Sstevel@tonic-gate 	return ("?");
1088*7c478bd9Sstevel@tonic-gate }
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate static void
1091*7c478bd9Sstevel@tonic-gate sprint_sta(char **buf, scf_walkinfo_t *wip)
1092*7c478bd9Sstevel@tonic-gate {
1093*7c478bd9Sstevel@tonic-gate 	char state_name[MAX_SCF_STATE_STRING_SZ];
1094*7c478bd9Sstevel@tonic-gate 	char sta[5];
1095*7c478bd9Sstevel@tonic-gate 	size_t newsize = (*buf ? strlen(*buf) : 0) + 6;
1096*7c478bd9Sstevel@tonic-gate 	char *newbuf = safe_malloc(newsize);
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate 	if (wip->pg == NULL)
1099*7c478bd9Sstevel@tonic-gate 		get_restarter_string_prop(wip->inst, scf_property_state,
1100*7c478bd9Sstevel@tonic-gate 		    state_name, sizeof (state_name));
1101*7c478bd9Sstevel@tonic-gate 	else
1102*7c478bd9Sstevel@tonic-gate 		(void) strcpy(state_name, SCF_STATE_STRING_LEGACY);
1103*7c478bd9Sstevel@tonic-gate 
1104*7c478bd9Sstevel@tonic-gate 	(void) strcpy(sta, state_abbrev(state_name));
1105*7c478bd9Sstevel@tonic-gate 
1106*7c478bd9Sstevel@tonic-gate 	if (wip->pg == NULL && !opt_nstate_shown && transitioning(wip->inst))
1107*7c478bd9Sstevel@tonic-gate 		(void) strcat(sta, "*");
1108*7c478bd9Sstevel@tonic-gate 
1109*7c478bd9Sstevel@tonic-gate 	(void) snprintf(newbuf, newsize, "%s%-4s ", *buf ? *buf : "", sta);
1110*7c478bd9Sstevel@tonic-gate 	if (*buf)
1111*7c478bd9Sstevel@tonic-gate 		free(*buf);
1112*7c478bd9Sstevel@tonic-gate 	*buf = newbuf;
1113*7c478bd9Sstevel@tonic-gate }
1114*7c478bd9Sstevel@tonic-gate 
1115*7c478bd9Sstevel@tonic-gate static void
1116*7c478bd9Sstevel@tonic-gate sprint_nsta(char **buf, scf_walkinfo_t *wip)
1117*7c478bd9Sstevel@tonic-gate {
1118*7c478bd9Sstevel@tonic-gate 	char state_name[MAX_SCF_STATE_STRING_SZ];
1119*7c478bd9Sstevel@tonic-gate 	size_t newsize = (*buf ? strlen(*buf) : 0) + 6;
1120*7c478bd9Sstevel@tonic-gate 	char *newbuf = safe_malloc(newsize);
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 	if (wip->pg == NULL)
1123*7c478bd9Sstevel@tonic-gate 		get_restarter_string_prop(wip->inst, scf_property_next_state,
1124*7c478bd9Sstevel@tonic-gate 		    state_name, sizeof (state_name));
1125*7c478bd9Sstevel@tonic-gate 	else
1126*7c478bd9Sstevel@tonic-gate 		(void) strcpy(state_name, SCF_STATE_STRING_NONE);
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate 	if (strcmp(state_name, SCF_STATE_STRING_NONE) == 0)
1129*7c478bd9Sstevel@tonic-gate 		(void) snprintf(newbuf, newsize, "%s%-4s ", *buf ? *buf : "",
1130*7c478bd9Sstevel@tonic-gate 		    "-");
1131*7c478bd9Sstevel@tonic-gate 	else
1132*7c478bd9Sstevel@tonic-gate 		(void) snprintf(newbuf, newsize, "%s%-4s ", *buf ? *buf : "",
1133*7c478bd9Sstevel@tonic-gate 		    state_abbrev(state_name));
1134*7c478bd9Sstevel@tonic-gate 	if (*buf)
1135*7c478bd9Sstevel@tonic-gate 		free(*buf);
1136*7c478bd9Sstevel@tonic-gate 	*buf = newbuf;
1137*7c478bd9Sstevel@tonic-gate }
1138*7c478bd9Sstevel@tonic-gate 
1139*7c478bd9Sstevel@tonic-gate /* FMRI */
1140*7c478bd9Sstevel@tonic-gate #define	FMRI_COLUMN_WIDTH	50
1141*7c478bd9Sstevel@tonic-gate static void
1142*7c478bd9Sstevel@tonic-gate sprint_fmri(char **buf, scf_walkinfo_t *wip)
1143*7c478bd9Sstevel@tonic-gate {
1144*7c478bd9Sstevel@tonic-gate 	char *fmri_buf = safe_malloc(max_scf_fmri_length + 1);
1145*7c478bd9Sstevel@tonic-gate 	size_t newsize;
1146*7c478bd9Sstevel@tonic-gate 	char *newbuf;
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate 	if (wip->pg == NULL) {
1149*7c478bd9Sstevel@tonic-gate 		if (scf_instance_to_fmri(wip->inst, fmri_buf,
1150*7c478bd9Sstevel@tonic-gate 		    max_scf_fmri_length + 1) == -1)
1151*7c478bd9Sstevel@tonic-gate 			scfdie();
1152*7c478bd9Sstevel@tonic-gate 	} else {
1153*7c478bd9Sstevel@tonic-gate 		(void) strcpy(fmri_buf, LEGACY_SCHEME);
1154*7c478bd9Sstevel@tonic-gate 		if (pg_get_single_val(wip->pg, SCF_LEGACY_PROPERTY_NAME,
1155*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, fmri_buf + sizeof (LEGACY_SCHEME) - 1,
1156*7c478bd9Sstevel@tonic-gate 		    max_scf_fmri_length + 1 - (sizeof (LEGACY_SCHEME) - 1),
1157*7c478bd9Sstevel@tonic-gate 		    0) != 0)
1158*7c478bd9Sstevel@tonic-gate 			(void) strcat(fmri_buf, LEGACY_UNKNOWN);
1159*7c478bd9Sstevel@tonic-gate 	}
1160*7c478bd9Sstevel@tonic-gate 
1161*7c478bd9Sstevel@tonic-gate 	if (strlen(fmri_buf) > FMRI_COLUMN_WIDTH)
1162*7c478bd9Sstevel@tonic-gate 		newsize = (*buf ? strlen(*buf) : 0) + strlen(fmri_buf) + 2;
1163*7c478bd9Sstevel@tonic-gate 	else
1164*7c478bd9Sstevel@tonic-gate 		newsize = (*buf ? strlen(*buf) : 0) + FMRI_COLUMN_WIDTH + 2;
1165*7c478bd9Sstevel@tonic-gate 	newbuf = safe_malloc(newsize);
1166*7c478bd9Sstevel@tonic-gate 	(void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1167*7c478bd9Sstevel@tonic-gate 	    FMRI_COLUMN_WIDTH, fmri_buf);
1168*7c478bd9Sstevel@tonic-gate 	free(fmri_buf);
1169*7c478bd9Sstevel@tonic-gate 	if (*buf)
1170*7c478bd9Sstevel@tonic-gate 		free(*buf);
1171*7c478bd9Sstevel@tonic-gate 	*buf = newbuf;
1172*7c478bd9Sstevel@tonic-gate }
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate static void
1175*7c478bd9Sstevel@tonic-gate sortkey_fmri(char *buf, int reverse, scf_walkinfo_t *wip)
1176*7c478bd9Sstevel@tonic-gate {
1177*7c478bd9Sstevel@tonic-gate 	char *tmp = NULL;
1178*7c478bd9Sstevel@tonic-gate 
1179*7c478bd9Sstevel@tonic-gate 	sprint_fmri(&tmp, wip);
1180*7c478bd9Sstevel@tonic-gate 	bcopy(tmp, buf, FMRI_COLUMN_WIDTH);
1181*7c478bd9Sstevel@tonic-gate 	free(tmp);
1182*7c478bd9Sstevel@tonic-gate 	if (reverse)
1183*7c478bd9Sstevel@tonic-gate 		reverse_bytes(buf, FMRI_COLUMN_WIDTH);
1184*7c478bd9Sstevel@tonic-gate }
1185*7c478bd9Sstevel@tonic-gate 
1186*7c478bd9Sstevel@tonic-gate /* Component columns */
1187*7c478bd9Sstevel@tonic-gate #define	COMPONENT_COLUMN_WIDTH	20
1188*7c478bd9Sstevel@tonic-gate static void
1189*7c478bd9Sstevel@tonic-gate sprint_scope(char **buf, scf_walkinfo_t *wip)
1190*7c478bd9Sstevel@tonic-gate {
1191*7c478bd9Sstevel@tonic-gate 	char *scope_buf = safe_malloc(max_scf_name_length + 1);
1192*7c478bd9Sstevel@tonic-gate 	size_t newsize = (*buf ? strlen(*buf) : 0) + COMPONENT_COLUMN_WIDTH + 2;
1193*7c478bd9Sstevel@tonic-gate 	char *newbuf = safe_malloc(newsize);
1194*7c478bd9Sstevel@tonic-gate 
1195*7c478bd9Sstevel@tonic-gate 	assert(wip->scope != NULL);
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate 	if (scf_scope_get_name(wip->scope, scope_buf, max_scf_name_length) < 0)
1198*7c478bd9Sstevel@tonic-gate 		scfdie();
1199*7c478bd9Sstevel@tonic-gate 
1200*7c478bd9Sstevel@tonic-gate 	(void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1201*7c478bd9Sstevel@tonic-gate 	    COMPONENT_COLUMN_WIDTH, scope_buf);
1202*7c478bd9Sstevel@tonic-gate 	if (*buf)
1203*7c478bd9Sstevel@tonic-gate 		free(*buf);
1204*7c478bd9Sstevel@tonic-gate 	*buf = newbuf;
1205*7c478bd9Sstevel@tonic-gate 	free(scope_buf);
1206*7c478bd9Sstevel@tonic-gate }
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate static void
1209*7c478bd9Sstevel@tonic-gate sortkey_scope(char *buf, int reverse, scf_walkinfo_t *wip)
1210*7c478bd9Sstevel@tonic-gate {
1211*7c478bd9Sstevel@tonic-gate 	char *tmp = NULL;
1212*7c478bd9Sstevel@tonic-gate 
1213*7c478bd9Sstevel@tonic-gate 	sprint_scope(&tmp, wip);
1214*7c478bd9Sstevel@tonic-gate 	bcopy(tmp, buf, COMPONENT_COLUMN_WIDTH);
1215*7c478bd9Sstevel@tonic-gate 	free(tmp);
1216*7c478bd9Sstevel@tonic-gate 	if (reverse)
1217*7c478bd9Sstevel@tonic-gate 		reverse_bytes(buf, COMPONENT_COLUMN_WIDTH);
1218*7c478bd9Sstevel@tonic-gate }
1219*7c478bd9Sstevel@tonic-gate 
1220*7c478bd9Sstevel@tonic-gate static void
1221*7c478bd9Sstevel@tonic-gate sprint_service(char **buf, scf_walkinfo_t *wip)
1222*7c478bd9Sstevel@tonic-gate {
1223*7c478bd9Sstevel@tonic-gate 	char *svc_buf = safe_malloc(max_scf_name_length + 1);
1224*7c478bd9Sstevel@tonic-gate 	char *newbuf;
1225*7c478bd9Sstevel@tonic-gate 	size_t newsize;
1226*7c478bd9Sstevel@tonic-gate 
1227*7c478bd9Sstevel@tonic-gate 	if (wip->pg == NULL) {
1228*7c478bd9Sstevel@tonic-gate 		if (scf_service_get_name(wip->svc, svc_buf,
1229*7c478bd9Sstevel@tonic-gate 		    max_scf_name_length + 1) < 0)
1230*7c478bd9Sstevel@tonic-gate 			scfdie();
1231*7c478bd9Sstevel@tonic-gate 	} else {
1232*7c478bd9Sstevel@tonic-gate 		if (pg_get_single_val(wip->pg, "name", SCF_TYPE_ASTRING,
1233*7c478bd9Sstevel@tonic-gate 		    svc_buf, max_scf_name_length + 1, EMPTY_OK) != 0)
1234*7c478bd9Sstevel@tonic-gate 			(void) strcpy(svc_buf, LEGACY_UNKNOWN);
1235*7c478bd9Sstevel@tonic-gate 	}
1236*7c478bd9Sstevel@tonic-gate 
1237*7c478bd9Sstevel@tonic-gate 
1238*7c478bd9Sstevel@tonic-gate 	if (strlen(svc_buf) > COMPONENT_COLUMN_WIDTH)
1239*7c478bd9Sstevel@tonic-gate 		newsize = (*buf ? strlen(*buf) : 0) + strlen(svc_buf) + 2;
1240*7c478bd9Sstevel@tonic-gate 	else
1241*7c478bd9Sstevel@tonic-gate 		newsize = (*buf ? strlen(*buf) : 0) +
1242*7c478bd9Sstevel@tonic-gate 		    COMPONENT_COLUMN_WIDTH + 2;
1243*7c478bd9Sstevel@tonic-gate 	newbuf = safe_malloc(newsize);
1244*7c478bd9Sstevel@tonic-gate 	(void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1245*7c478bd9Sstevel@tonic-gate 	    COMPONENT_COLUMN_WIDTH, svc_buf);
1246*7c478bd9Sstevel@tonic-gate 	free(svc_buf);
1247*7c478bd9Sstevel@tonic-gate 	if (*buf)
1248*7c478bd9Sstevel@tonic-gate 		free(*buf);
1249*7c478bd9Sstevel@tonic-gate 	*buf = newbuf;
1250*7c478bd9Sstevel@tonic-gate }
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate static void
1253*7c478bd9Sstevel@tonic-gate sortkey_service(char *buf, int reverse, scf_walkinfo_t *wip)
1254*7c478bd9Sstevel@tonic-gate {
1255*7c478bd9Sstevel@tonic-gate 	char *tmp = NULL;
1256*7c478bd9Sstevel@tonic-gate 
1257*7c478bd9Sstevel@tonic-gate 	sprint_service(&tmp, wip);
1258*7c478bd9Sstevel@tonic-gate 	bcopy(tmp, buf, COMPONENT_COLUMN_WIDTH);
1259*7c478bd9Sstevel@tonic-gate 	free(tmp);
1260*7c478bd9Sstevel@tonic-gate 	if (reverse)
1261*7c478bd9Sstevel@tonic-gate 		reverse_bytes(buf, COMPONENT_COLUMN_WIDTH);
1262*7c478bd9Sstevel@tonic-gate }
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate /* INST */
1265*7c478bd9Sstevel@tonic-gate static void
1266*7c478bd9Sstevel@tonic-gate sprint_instance(char **buf, scf_walkinfo_t *wip)
1267*7c478bd9Sstevel@tonic-gate {
1268*7c478bd9Sstevel@tonic-gate 	char *tmp = safe_malloc(max_scf_name_length + 1);
1269*7c478bd9Sstevel@tonic-gate 	size_t newsize = (*buf ? strlen(*buf) : 0) + COMPONENT_COLUMN_WIDTH + 2;
1270*7c478bd9Sstevel@tonic-gate 	char *newbuf = safe_malloc(newsize);
1271*7c478bd9Sstevel@tonic-gate 
1272*7c478bd9Sstevel@tonic-gate 	if (wip->pg == NULL) {
1273*7c478bd9Sstevel@tonic-gate 		if (scf_instance_get_name(wip->inst, tmp,
1274*7c478bd9Sstevel@tonic-gate 		    max_scf_name_length + 1) < 0)
1275*7c478bd9Sstevel@tonic-gate 			scfdie();
1276*7c478bd9Sstevel@tonic-gate 	} else {
1277*7c478bd9Sstevel@tonic-gate 		tmp[0] = '-';
1278*7c478bd9Sstevel@tonic-gate 		tmp[1] = '\0';
1279*7c478bd9Sstevel@tonic-gate 	}
1280*7c478bd9Sstevel@tonic-gate 
1281*7c478bd9Sstevel@tonic-gate 	(void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1282*7c478bd9Sstevel@tonic-gate 	    COMPONENT_COLUMN_WIDTH, tmp);
1283*7c478bd9Sstevel@tonic-gate 	if (*buf)
1284*7c478bd9Sstevel@tonic-gate 		free(*buf);
1285*7c478bd9Sstevel@tonic-gate 	*buf = newbuf;
1286*7c478bd9Sstevel@tonic-gate 	free(tmp);
1287*7c478bd9Sstevel@tonic-gate }
1288*7c478bd9Sstevel@tonic-gate 
1289*7c478bd9Sstevel@tonic-gate static void
1290*7c478bd9Sstevel@tonic-gate sortkey_instance(char *buf, int reverse, scf_walkinfo_t *wip)
1291*7c478bd9Sstevel@tonic-gate {
1292*7c478bd9Sstevel@tonic-gate 	char *tmp = NULL;
1293*7c478bd9Sstevel@tonic-gate 
1294*7c478bd9Sstevel@tonic-gate 	sprint_instance(&tmp, wip);
1295*7c478bd9Sstevel@tonic-gate 	bcopy(tmp, buf, COMPONENT_COLUMN_WIDTH);
1296*7c478bd9Sstevel@tonic-gate 	free(tmp);
1297*7c478bd9Sstevel@tonic-gate 	if (reverse)
1298*7c478bd9Sstevel@tonic-gate 		reverse_bytes(buf, COMPONENT_COLUMN_WIDTH);
1299*7c478bd9Sstevel@tonic-gate }
1300*7c478bd9Sstevel@tonic-gate 
1301*7c478bd9Sstevel@tonic-gate /* STIME */
1302*7c478bd9Sstevel@tonic-gate #define	STIME_COLUMN_WIDTH		8
1303*7c478bd9Sstevel@tonic-gate #define	FORMAT_TIME			"%k:%M:%S"
1304*7c478bd9Sstevel@tonic-gate #define	FORMAT_DATE			"%b_%d  "
1305*7c478bd9Sstevel@tonic-gate #define	FORMAT_YEAR			"%Y    "
1306*7c478bd9Sstevel@tonic-gate 
1307*7c478bd9Sstevel@tonic-gate static void
1308*7c478bd9Sstevel@tonic-gate sprint_stime(char **buf, scf_walkinfo_t *wip)
1309*7c478bd9Sstevel@tonic-gate {
1310*7c478bd9Sstevel@tonic-gate 	int r;
1311*7c478bd9Sstevel@tonic-gate 	struct timeval tv;
1312*7c478bd9Sstevel@tonic-gate 	time_t then;
1313*7c478bd9Sstevel@tonic-gate 	struct tm *tm;
1314*7c478bd9Sstevel@tonic-gate 	char st_buf[STIME_COLUMN_WIDTH + 1];
1315*7c478bd9Sstevel@tonic-gate 	size_t newsize = (*buf ? strlen(*buf) : 0) + STIME_COLUMN_WIDTH + 2;
1316*7c478bd9Sstevel@tonic-gate 	char *newbuf = safe_malloc(newsize);
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate 	if (wip->pg == NULL) {
1319*7c478bd9Sstevel@tonic-gate 		r = get_restarter_time_prop(wip->inst,
1320*7c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_STATE_TIMESTAMP, &tv, 0);
1321*7c478bd9Sstevel@tonic-gate 	} else {
1322*7c478bd9Sstevel@tonic-gate 		r = pg_get_single_val(wip->pg, SCF_PROPERTY_STATE_TIMESTAMP,
1323*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_TIME, &tv, NULL, 0);
1324*7c478bd9Sstevel@tonic-gate 	}
1325*7c478bd9Sstevel@tonic-gate 
1326*7c478bd9Sstevel@tonic-gate 	if (r != 0) {
1327*7c478bd9Sstevel@tonic-gate 		(void) snprintf(newbuf, newsize, "%s%-*s", *buf ? *buf : "",
1328*7c478bd9Sstevel@tonic-gate 		    STIME_COLUMN_WIDTH + 1, "?");
1329*7c478bd9Sstevel@tonic-gate 		return;
1330*7c478bd9Sstevel@tonic-gate 	}
1331*7c478bd9Sstevel@tonic-gate 
1332*7c478bd9Sstevel@tonic-gate 	then = (time_t)tv.tv_sec;
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 	tm = localtime(&then);
1335*7c478bd9Sstevel@tonic-gate 	/*
1336*7c478bd9Sstevel@tonic-gate 	 * Print time if started within the past 24 hours, print date
1337*7c478bd9Sstevel@tonic-gate 	 * if within the past 12 months, print year if started greater than
1338*7c478bd9Sstevel@tonic-gate 	 * 12 months ago.
1339*7c478bd9Sstevel@tonic-gate 	 */
1340*7c478bd9Sstevel@tonic-gate 	if (now - then < 24 * 60 * 60)
1341*7c478bd9Sstevel@tonic-gate 		(void) strftime(st_buf, sizeof (st_buf), gettext(FORMAT_TIME),
1342*7c478bd9Sstevel@tonic-gate 				tm);
1343*7c478bd9Sstevel@tonic-gate 	else if (now - then < 12 * 30 * 24 * 60 * 60)
1344*7c478bd9Sstevel@tonic-gate 		(void) strftime(st_buf, sizeof (st_buf), gettext(FORMAT_DATE),
1345*7c478bd9Sstevel@tonic-gate 				tm);
1346*7c478bd9Sstevel@tonic-gate 	else
1347*7c478bd9Sstevel@tonic-gate 		(void) strftime(st_buf, sizeof (st_buf), gettext(FORMAT_YEAR),
1348*7c478bd9Sstevel@tonic-gate 				tm);
1349*7c478bd9Sstevel@tonic-gate 
1350*7c478bd9Sstevel@tonic-gate 	(void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1351*7c478bd9Sstevel@tonic-gate 	    STIME_COLUMN_WIDTH + 1, st_buf);
1352*7c478bd9Sstevel@tonic-gate 	if (*buf)
1353*7c478bd9Sstevel@tonic-gate 		free(*buf);
1354*7c478bd9Sstevel@tonic-gate 	*buf = newbuf;
1355*7c478bd9Sstevel@tonic-gate }
1356*7c478bd9Sstevel@tonic-gate 
1357*7c478bd9Sstevel@tonic-gate #define	STIME_SORTKEY_WIDTH		(sizeof (uint64_t) + sizeof (uint32_t))
1358*7c478bd9Sstevel@tonic-gate 
1359*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1360*7c478bd9Sstevel@tonic-gate static void
1361*7c478bd9Sstevel@tonic-gate sortkey_stime(char *buf, int reverse, scf_walkinfo_t *wip)
1362*7c478bd9Sstevel@tonic-gate {
1363*7c478bd9Sstevel@tonic-gate 	struct timeval tv;
1364*7c478bd9Sstevel@tonic-gate 	int r;
1365*7c478bd9Sstevel@tonic-gate 
1366*7c478bd9Sstevel@tonic-gate 	if (wip->pg == NULL)
1367*7c478bd9Sstevel@tonic-gate 		r = get_restarter_time_prop(wip->inst,
1368*7c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_STATE_TIMESTAMP, &tv, 0);
1369*7c478bd9Sstevel@tonic-gate 	else
1370*7c478bd9Sstevel@tonic-gate 		r = pg_get_single_val(wip->pg, SCF_PROPERTY_STATE_TIMESTAMP,
1371*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_TIME, &tv, NULL, 0);
1372*7c478bd9Sstevel@tonic-gate 
1373*7c478bd9Sstevel@tonic-gate 	if (r == 0) {
1374*7c478bd9Sstevel@tonic-gate 		int64_t sec;
1375*7c478bd9Sstevel@tonic-gate 		int32_t us;
1376*7c478bd9Sstevel@tonic-gate 
1377*7c478bd9Sstevel@tonic-gate 		/* Stick it straight into the buffer. */
1378*7c478bd9Sstevel@tonic-gate 		sec = tv.tv_sec;
1379*7c478bd9Sstevel@tonic-gate 		us = tv.tv_usec;
1380*7c478bd9Sstevel@tonic-gate 
1381*7c478bd9Sstevel@tonic-gate 		sec = BE_64(sec);
1382*7c478bd9Sstevel@tonic-gate 		us = BE_32(us);
1383*7c478bd9Sstevel@tonic-gate 		bcopy(&sec, buf, sizeof (sec));
1384*7c478bd9Sstevel@tonic-gate 		bcopy(&us, buf + sizeof (sec), sizeof (us));
1385*7c478bd9Sstevel@tonic-gate 	} else {
1386*7c478bd9Sstevel@tonic-gate 		bzero(buf, STIME_SORTKEY_WIDTH);
1387*7c478bd9Sstevel@tonic-gate 	}
1388*7c478bd9Sstevel@tonic-gate 
1389*7c478bd9Sstevel@tonic-gate 	if (reverse)
1390*7c478bd9Sstevel@tonic-gate 		reverse_bytes(buf, STIME_SORTKEY_WIDTH);
1391*7c478bd9Sstevel@tonic-gate }
1392*7c478bd9Sstevel@tonic-gate 
1393*7c478bd9Sstevel@tonic-gate 
1394*7c478bd9Sstevel@tonic-gate /*
1395*7c478bd9Sstevel@tonic-gate  * Information about columns which can be displayed.  If you add something,
1396*7c478bd9Sstevel@tonic-gate  * check MAX_COLUMN_NAME_LENGTH_STR & update description_of_column() below.
1397*7c478bd9Sstevel@tonic-gate  */
1398*7c478bd9Sstevel@tonic-gate static const struct column columns[] = {
1399*7c478bd9Sstevel@tonic-gate 	{ "CTID", CTID_COLUMN_WIDTH, sprint_ctid,
1400*7c478bd9Sstevel@tonic-gate 		CTID_SORTKEY_WIDTH, sortkey_ctid },
1401*7c478bd9Sstevel@tonic-gate 	{ "DESC", DESC_COLUMN_WIDTH, sprint_desc,
1402*7c478bd9Sstevel@tonic-gate 		DESC_COLUMN_WIDTH, sortkey_desc },
1403*7c478bd9Sstevel@tonic-gate 	{ "FMRI", FMRI_COLUMN_WIDTH, sprint_fmri,
1404*7c478bd9Sstevel@tonic-gate 		FMRI_COLUMN_WIDTH, sortkey_fmri },
1405*7c478bd9Sstevel@tonic-gate 	{ "INST", COMPONENT_COLUMN_WIDTH, sprint_instance,
1406*7c478bd9Sstevel@tonic-gate 		COMPONENT_COLUMN_WIDTH, sortkey_instance },
1407*7c478bd9Sstevel@tonic-gate 	{ "N", 1,  sprint_n, 1, sortkey_nstate },
1408*7c478bd9Sstevel@tonic-gate 	{ "NSTA", 4, sprint_nsta, 1, sortkey_nstate },
1409*7c478bd9Sstevel@tonic-gate 	{ "NSTATE", MAX_SCF_STATE_STRING_SZ - 1, sprint_nstate,
1410*7c478bd9Sstevel@tonic-gate 		1, sortkey_nstate },
1411*7c478bd9Sstevel@tonic-gate 	{ "S", 2, sprint_s, 1, sortkey_state },
1412*7c478bd9Sstevel@tonic-gate 	{ "SCOPE", COMPONENT_COLUMN_WIDTH, sprint_scope,
1413*7c478bd9Sstevel@tonic-gate 		COMPONENT_COLUMN_WIDTH, sortkey_scope },
1414*7c478bd9Sstevel@tonic-gate 	{ "SN", 2, sprint_sn, 2, sortkey_sn },
1415*7c478bd9Sstevel@tonic-gate 	{ "SVC", COMPONENT_COLUMN_WIDTH, sprint_service,
1416*7c478bd9Sstevel@tonic-gate 		COMPONENT_COLUMN_WIDTH, sortkey_service },
1417*7c478bd9Sstevel@tonic-gate 	{ "STA", 4, sprint_sta, 1, sortkey_state },
1418*7c478bd9Sstevel@tonic-gate 	{ "STATE", MAX_SCF_STATE_STRING_SZ - 1 + 1, sprint_state,
1419*7c478bd9Sstevel@tonic-gate 		1, sortkey_state },
1420*7c478bd9Sstevel@tonic-gate 	{ "STIME", STIME_COLUMN_WIDTH, sprint_stime,
1421*7c478bd9Sstevel@tonic-gate 		STIME_SORTKEY_WIDTH, sortkey_stime },
1422*7c478bd9Sstevel@tonic-gate };
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate #define	MAX_COLUMN_NAME_LENGTH_STR	"6"
1425*7c478bd9Sstevel@tonic-gate 
1426*7c478bd9Sstevel@tonic-gate static const int ncolumns = sizeof (columns) / sizeof (columns[0]);
1427*7c478bd9Sstevel@tonic-gate 
1428*7c478bd9Sstevel@tonic-gate /*
1429*7c478bd9Sstevel@tonic-gate  * Necessary thanks to gettext() & xgettext.
1430*7c478bd9Sstevel@tonic-gate  */
1431*7c478bd9Sstevel@tonic-gate static const char *
1432*7c478bd9Sstevel@tonic-gate description_of_column(int c)
1433*7c478bd9Sstevel@tonic-gate {
1434*7c478bd9Sstevel@tonic-gate 	const char *s = NULL;
1435*7c478bd9Sstevel@tonic-gate 
1436*7c478bd9Sstevel@tonic-gate 	switch (c) {
1437*7c478bd9Sstevel@tonic-gate 	case 0:
1438*7c478bd9Sstevel@tonic-gate 		s = gettext("contract ID for service (see contract(4))");
1439*7c478bd9Sstevel@tonic-gate 		break;
1440*7c478bd9Sstevel@tonic-gate 	case 1:
1441*7c478bd9Sstevel@tonic-gate 		s = gettext("human-readable description of the service");
1442*7c478bd9Sstevel@tonic-gate 		break;
1443*7c478bd9Sstevel@tonic-gate 	case 2:
1444*7c478bd9Sstevel@tonic-gate 		s = gettext("Fault Managed Resource Identifier for service");
1445*7c478bd9Sstevel@tonic-gate 		break;
1446*7c478bd9Sstevel@tonic-gate 	case 3:
1447*7c478bd9Sstevel@tonic-gate 		s = gettext("portion of the FMRI indicating service instance");
1448*7c478bd9Sstevel@tonic-gate 		break;
1449*7c478bd9Sstevel@tonic-gate 	case 4:
1450*7c478bd9Sstevel@tonic-gate 		s = gettext("abbreviation for next state (if in transition)");
1451*7c478bd9Sstevel@tonic-gate 		break;
1452*7c478bd9Sstevel@tonic-gate 	case 5:
1453*7c478bd9Sstevel@tonic-gate 		s = gettext("abbreviation for next state (if in transition)");
1454*7c478bd9Sstevel@tonic-gate 		break;
1455*7c478bd9Sstevel@tonic-gate 	case 6:
1456*7c478bd9Sstevel@tonic-gate 		s = gettext("name for next state (if in transition)");
1457*7c478bd9Sstevel@tonic-gate 		break;
1458*7c478bd9Sstevel@tonic-gate 	case 7:
1459*7c478bd9Sstevel@tonic-gate 		s = gettext("abbreviation for current state");
1460*7c478bd9Sstevel@tonic-gate 		break;
1461*7c478bd9Sstevel@tonic-gate 	case 8:
1462*7c478bd9Sstevel@tonic-gate 		s = gettext("name for scope associated with service");
1463*7c478bd9Sstevel@tonic-gate 		break;
1464*7c478bd9Sstevel@tonic-gate 	case 9:
1465*7c478bd9Sstevel@tonic-gate 		s = gettext("abbreviation for current state and next state");
1466*7c478bd9Sstevel@tonic-gate 		break;
1467*7c478bd9Sstevel@tonic-gate 	case 10:
1468*7c478bd9Sstevel@tonic-gate 		s = gettext("portion of the FMRI representing service name");
1469*7c478bd9Sstevel@tonic-gate 		break;
1470*7c478bd9Sstevel@tonic-gate 	case 11:
1471*7c478bd9Sstevel@tonic-gate 		s = gettext("abbreviation for current state");
1472*7c478bd9Sstevel@tonic-gate 		break;
1473*7c478bd9Sstevel@tonic-gate 	case 12:
1474*7c478bd9Sstevel@tonic-gate 		s = gettext("name for current state");
1475*7c478bd9Sstevel@tonic-gate 		break;
1476*7c478bd9Sstevel@tonic-gate 	case 13:
1477*7c478bd9Sstevel@tonic-gate 		s = gettext("time of last state change");
1478*7c478bd9Sstevel@tonic-gate 		break;
1479*7c478bd9Sstevel@tonic-gate 	}
1480*7c478bd9Sstevel@tonic-gate 
1481*7c478bd9Sstevel@tonic-gate 	assert(s != NULL);
1482*7c478bd9Sstevel@tonic-gate 	return (s);
1483*7c478bd9Sstevel@tonic-gate }
1484*7c478bd9Sstevel@tonic-gate 
1485*7c478bd9Sstevel@tonic-gate 
1486*7c478bd9Sstevel@tonic-gate static void
1487*7c478bd9Sstevel@tonic-gate print_usage(const char *progname, FILE *f, boolean_t do_exit)
1488*7c478bd9Sstevel@tonic-gate {
1489*7c478bd9Sstevel@tonic-gate 	(void) fprintf(f, gettext(
1490*7c478bd9Sstevel@tonic-gate 	    "Usage: %1$s [-aHpv] [-o col[,col ... ]] [-R restarter] "
1491*7c478bd9Sstevel@tonic-gate 	    "[-sS col] [<service> ...]\n"
1492*7c478bd9Sstevel@tonic-gate 	    "       %1$s -d | -D [-Hpv] [-o col[,col ... ]] [-sS col] "
1493*7c478bd9Sstevel@tonic-gate 	    "[<service> ...]\n"
1494*7c478bd9Sstevel@tonic-gate 	    "       %1$s -l <service> ...\n"
1495*7c478bd9Sstevel@tonic-gate 	    "       %1$s -x [-v] [<service> ...]\n"
1496*7c478bd9Sstevel@tonic-gate 	    "       %1$s -?\n"), progname);
1497*7c478bd9Sstevel@tonic-gate 
1498*7c478bd9Sstevel@tonic-gate 	if (do_exit)
1499*7c478bd9Sstevel@tonic-gate 		exit(UU_EXIT_USAGE);
1500*7c478bd9Sstevel@tonic-gate }
1501*7c478bd9Sstevel@tonic-gate 
1502*7c478bd9Sstevel@tonic-gate #define	argserr(progname)	print_usage(progname, stderr, B_TRUE)
1503*7c478bd9Sstevel@tonic-gate 
1504*7c478bd9Sstevel@tonic-gate static void
1505*7c478bd9Sstevel@tonic-gate print_help(const char *progname)
1506*7c478bd9Sstevel@tonic-gate {
1507*7c478bd9Sstevel@tonic-gate 	int i;
1508*7c478bd9Sstevel@tonic-gate 
1509*7c478bd9Sstevel@tonic-gate 	print_usage(progname, stdout, B_FALSE);
1510*7c478bd9Sstevel@tonic-gate 
1511*7c478bd9Sstevel@tonic-gate 	(void) printf(gettext("\n"
1512*7c478bd9Sstevel@tonic-gate 	"\t-a  list all service instances rather than "
1513*7c478bd9Sstevel@tonic-gate 	"only those that are enabled\n"
1514*7c478bd9Sstevel@tonic-gate 	"\t-d  list dependencies of the specified service(s)\n"
1515*7c478bd9Sstevel@tonic-gate 	"\t-D  list dependents of the specified service(s)\n"
1516*7c478bd9Sstevel@tonic-gate 	"\t-H  omit header line from output\n"
1517*7c478bd9Sstevel@tonic-gate 	"\t-l  list detailed information about the specified service(s)\n"
1518*7c478bd9Sstevel@tonic-gate 	"\t-o  list only the specified columns in the output\n"
1519*7c478bd9Sstevel@tonic-gate 	"\t-p  list process IDs and names associated with each service\n"
1520*7c478bd9Sstevel@tonic-gate 	"\t-R  list only those services with the specified restarter\n"
1521*7c478bd9Sstevel@tonic-gate 	"\t-s  sort output in ascending order by the specified column(s)\n"
1522*7c478bd9Sstevel@tonic-gate 	"\t-S  sort output in descending order by the specified column(s)\n"
1523*7c478bd9Sstevel@tonic-gate 	"\t-v  list verbose information appropriate to the type of output\n"
1524*7c478bd9Sstevel@tonic-gate 	"\t-x  explain the status of services that might require maintenance,\n"
1525*7c478bd9Sstevel@tonic-gate 	"\t    or explain the status of the specified service(s)\n"
1526*7c478bd9Sstevel@tonic-gate 	"\n\t"
1527*7c478bd9Sstevel@tonic-gate 	"Services can be specified using an FMRI, abbreviation, or fnmatch(5)\n"
1528*7c478bd9Sstevel@tonic-gate 	"\tpattern, as shown in these examples for svc:/network/smtp:sendmail\n"
1529*7c478bd9Sstevel@tonic-gate 	"\n"
1530*7c478bd9Sstevel@tonic-gate 	"\t%1$s [opts] svc:/network/smtp:sendmail\n"
1531*7c478bd9Sstevel@tonic-gate 	"\t%1$s [opts] network/smtp:sendmail\n"
1532*7c478bd9Sstevel@tonic-gate 	"\t%1$s [opts] network/*mail\n"
1533*7c478bd9Sstevel@tonic-gate 	"\t%1$s [opts] network/smtp\n"
1534*7c478bd9Sstevel@tonic-gate 	"\t%1$s [opts] smtp:sendmail\n"
1535*7c478bd9Sstevel@tonic-gate 	"\t%1$s [opts] smtp\n"
1536*7c478bd9Sstevel@tonic-gate 	"\t%1$s [opts] sendmail\n"
1537*7c478bd9Sstevel@tonic-gate 	"\n\t"
1538*7c478bd9Sstevel@tonic-gate 	"Columns for output or sorting can be specified using these names:\n"
1539*7c478bd9Sstevel@tonic-gate 	"\n"), progname);
1540*7c478bd9Sstevel@tonic-gate 
1541*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ncolumns; i++) {
1542*7c478bd9Sstevel@tonic-gate 		(void) printf("\t%-" MAX_COLUMN_NAME_LENGTH_STR "s  %s\n",
1543*7c478bd9Sstevel@tonic-gate 		    columns[i].name, description_of_column(i));
1544*7c478bd9Sstevel@tonic-gate 	}
1545*7c478bd9Sstevel@tonic-gate }
1546*7c478bd9Sstevel@tonic-gate 
1547*7c478bd9Sstevel@tonic-gate 
1548*7c478bd9Sstevel@tonic-gate /*
1549*7c478bd9Sstevel@tonic-gate  * A getsubopt()-like function which returns an index into the columns table.
1550*7c478bd9Sstevel@tonic-gate  * On success, *optionp is set to point to the next sub-option, or the
1551*7c478bd9Sstevel@tonic-gate  * terminating null if there are none.
1552*7c478bd9Sstevel@tonic-gate  */
1553*7c478bd9Sstevel@tonic-gate static int
1554*7c478bd9Sstevel@tonic-gate getcolumnopt(char **optionp)
1555*7c478bd9Sstevel@tonic-gate {
1556*7c478bd9Sstevel@tonic-gate 	char *str = *optionp, *cp;
1557*7c478bd9Sstevel@tonic-gate 	int i;
1558*7c478bd9Sstevel@tonic-gate 
1559*7c478bd9Sstevel@tonic-gate 	assert(optionp != NULL);
1560*7c478bd9Sstevel@tonic-gate 	assert(*optionp != NULL);
1561*7c478bd9Sstevel@tonic-gate 
1562*7c478bd9Sstevel@tonic-gate 	cp = strchr(*optionp, ',');
1563*7c478bd9Sstevel@tonic-gate 	if (cp != NULL)
1564*7c478bd9Sstevel@tonic-gate 		*cp = '\0';
1565*7c478bd9Sstevel@tonic-gate 
1566*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ncolumns; ++i) {
1567*7c478bd9Sstevel@tonic-gate 		if (strcasecmp(str, columns[i].name) == 0) {
1568*7c478bd9Sstevel@tonic-gate 			if (cp != NULL)
1569*7c478bd9Sstevel@tonic-gate 				*optionp = cp + 1;
1570*7c478bd9Sstevel@tonic-gate 			else
1571*7c478bd9Sstevel@tonic-gate 				*optionp = strchr(*optionp, '\0');
1572*7c478bd9Sstevel@tonic-gate 
1573*7c478bd9Sstevel@tonic-gate 			return (i);
1574*7c478bd9Sstevel@tonic-gate 		}
1575*7c478bd9Sstevel@tonic-gate 	}
1576*7c478bd9Sstevel@tonic-gate 
1577*7c478bd9Sstevel@tonic-gate 	return (-1);
1578*7c478bd9Sstevel@tonic-gate }
1579*7c478bd9Sstevel@tonic-gate 
1580*7c478bd9Sstevel@tonic-gate static void
1581*7c478bd9Sstevel@tonic-gate print_header()
1582*7c478bd9Sstevel@tonic-gate {
1583*7c478bd9Sstevel@tonic-gate 	int i;
1584*7c478bd9Sstevel@tonic-gate 	char *line_buf, *cp;
1585*7c478bd9Sstevel@tonic-gate 
1586*7c478bd9Sstevel@tonic-gate 	line_buf = safe_malloc(line_sz);
1587*7c478bd9Sstevel@tonic-gate 	cp = line_buf;
1588*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < opt_cnum; ++i) {
1589*7c478bd9Sstevel@tonic-gate 		const struct column * const colp = &columns[opt_columns[i]];
1590*7c478bd9Sstevel@tonic-gate 
1591*7c478bd9Sstevel@tonic-gate 		(void) snprintf(cp, colp->width + 1, "%-*s", colp->width,
1592*7c478bd9Sstevel@tonic-gate 		    colp->name);
1593*7c478bd9Sstevel@tonic-gate 		cp += colp->width;
1594*7c478bd9Sstevel@tonic-gate 		*cp++ = ' ';
1595*7c478bd9Sstevel@tonic-gate 	}
1596*7c478bd9Sstevel@tonic-gate 
1597*7c478bd9Sstevel@tonic-gate 	/* Trim the trailing whitespace */
1598*7c478bd9Sstevel@tonic-gate 	--cp;
1599*7c478bd9Sstevel@tonic-gate 	while (*cp == ' ')
1600*7c478bd9Sstevel@tonic-gate 		--cp;
1601*7c478bd9Sstevel@tonic-gate 	*(cp+1) = '\0';
1602*7c478bd9Sstevel@tonic-gate 	(void) puts(line_buf);
1603*7c478bd9Sstevel@tonic-gate 
1604*7c478bd9Sstevel@tonic-gate 	free(line_buf);
1605*7c478bd9Sstevel@tonic-gate }
1606*7c478bd9Sstevel@tonic-gate 
1607*7c478bd9Sstevel@tonic-gate 
1608*7c478bd9Sstevel@tonic-gate 
1609*7c478bd9Sstevel@tonic-gate /*
1610*7c478bd9Sstevel@tonic-gate  * Long listing (-l) functions.
1611*7c478bd9Sstevel@tonic-gate  */
1612*7c478bd9Sstevel@tonic-gate 
1613*7c478bd9Sstevel@tonic-gate static int
1614*7c478bd9Sstevel@tonic-gate pidcmp(const void *l, const void *r)
1615*7c478bd9Sstevel@tonic-gate {
1616*7c478bd9Sstevel@tonic-gate 	pid_t lp = *(pid_t *)l, rp = *(pid_t *)r;
1617*7c478bd9Sstevel@tonic-gate 
1618*7c478bd9Sstevel@tonic-gate 	if (lp < rp)
1619*7c478bd9Sstevel@tonic-gate 		return (-1);
1620*7c478bd9Sstevel@tonic-gate 	if (lp > rp)
1621*7c478bd9Sstevel@tonic-gate 		return (1);
1622*7c478bd9Sstevel@tonic-gate 	return (0);
1623*7c478bd9Sstevel@tonic-gate }
1624*7c478bd9Sstevel@tonic-gate 
1625*7c478bd9Sstevel@tonic-gate /*
1626*7c478bd9Sstevel@tonic-gate  * This is the strlen() of the longest label ("description"), plus intercolumn
1627*7c478bd9Sstevel@tonic-gate  * space.
1628*7c478bd9Sstevel@tonic-gate  */
1629*7c478bd9Sstevel@tonic-gate #define	DETAILED_WIDTH	(11 + 2)
1630*7c478bd9Sstevel@tonic-gate 
1631*7c478bd9Sstevel@tonic-gate static void
1632*7c478bd9Sstevel@tonic-gate detailed_list_processes(scf_instance_t *inst)
1633*7c478bd9Sstevel@tonic-gate {
1634*7c478bd9Sstevel@tonic-gate 	uint64_t c;
1635*7c478bd9Sstevel@tonic-gate 	pid_t *pids;
1636*7c478bd9Sstevel@tonic-gate 	uint_t i, n;
1637*7c478bd9Sstevel@tonic-gate 	psinfo_t psi;
1638*7c478bd9Sstevel@tonic-gate 
1639*7c478bd9Sstevel@tonic-gate 	if (get_restarter_count_prop(inst, scf_property_contract, &c,
1640*7c478bd9Sstevel@tonic-gate 	    EMPTY_OK) != 0)
1641*7c478bd9Sstevel@tonic-gate 		return;
1642*7c478bd9Sstevel@tonic-gate 
1643*7c478bd9Sstevel@tonic-gate 	if (instance_processes(inst, &pids, &n) != 0)
1644*7c478bd9Sstevel@tonic-gate 		return;
1645*7c478bd9Sstevel@tonic-gate 
1646*7c478bd9Sstevel@tonic-gate 	qsort(pids, n, sizeof (*pids), pidcmp);
1647*7c478bd9Sstevel@tonic-gate 
1648*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; ++i) {
1649*7c478bd9Sstevel@tonic-gate 		(void) printf("%-*s%lu", DETAILED_WIDTH, gettext("process"),
1650*7c478bd9Sstevel@tonic-gate 		    pids[i]);
1651*7c478bd9Sstevel@tonic-gate 
1652*7c478bd9Sstevel@tonic-gate 		if (get_psinfo(pids[i], &psi) == 0)
1653*7c478bd9Sstevel@tonic-gate 			(void) printf(" %.*s", PRARGSZ, psi.pr_psargs);
1654*7c478bd9Sstevel@tonic-gate 
1655*7c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
1656*7c478bd9Sstevel@tonic-gate 	}
1657*7c478bd9Sstevel@tonic-gate 
1658*7c478bd9Sstevel@tonic-gate 	free(pids);
1659*7c478bd9Sstevel@tonic-gate }
1660*7c478bd9Sstevel@tonic-gate 
1661*7c478bd9Sstevel@tonic-gate /*
1662*7c478bd9Sstevel@tonic-gate  * Determines the state of a dependency.  If the FMRI specifies a file, then we
1663*7c478bd9Sstevel@tonic-gate  * fake up a state based on whether we can access the file.
1664*7c478bd9Sstevel@tonic-gate  */
1665*7c478bd9Sstevel@tonic-gate static void
1666*7c478bd9Sstevel@tonic-gate get_fmri_state(char *fmri, char *state, size_t state_sz)
1667*7c478bd9Sstevel@tonic-gate {
1668*7c478bd9Sstevel@tonic-gate 	char *lfmri;
1669*7c478bd9Sstevel@tonic-gate 	const char *svc_name, *inst_name, *pg_name, *path;
1670*7c478bd9Sstevel@tonic-gate 	scf_service_t *svc;
1671*7c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
1672*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
1673*7c478bd9Sstevel@tonic-gate 
1674*7c478bd9Sstevel@tonic-gate 	lfmri = safe_strdup(fmri);
1675*7c478bd9Sstevel@tonic-gate 
1676*7c478bd9Sstevel@tonic-gate 	/*
1677*7c478bd9Sstevel@tonic-gate 	 * Check for file:// dependencies
1678*7c478bd9Sstevel@tonic-gate 	 */
1679*7c478bd9Sstevel@tonic-gate 	if (scf_parse_file_fmri(lfmri, NULL, &path) == SCF_SUCCESS) {
1680*7c478bd9Sstevel@tonic-gate 		struct stat64 statbuf;
1681*7c478bd9Sstevel@tonic-gate 		const char *msg;
1682*7c478bd9Sstevel@tonic-gate 
1683*7c478bd9Sstevel@tonic-gate 		if (stat64(path, &statbuf) == 0)
1684*7c478bd9Sstevel@tonic-gate 			msg = "online";
1685*7c478bd9Sstevel@tonic-gate 		else if (errno == ENOENT)
1686*7c478bd9Sstevel@tonic-gate 			msg = "absent";
1687*7c478bd9Sstevel@tonic-gate 		else
1688*7c478bd9Sstevel@tonic-gate 			msg = "unknown";
1689*7c478bd9Sstevel@tonic-gate 
1690*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(state, msg, state_sz);
1691*7c478bd9Sstevel@tonic-gate 		return;
1692*7c478bd9Sstevel@tonic-gate 	}
1693*7c478bd9Sstevel@tonic-gate 
1694*7c478bd9Sstevel@tonic-gate 	/*
1695*7c478bd9Sstevel@tonic-gate 	 * scf_parse_file_fmri() may have overwritten part of the string, so
1696*7c478bd9Sstevel@tonic-gate 	 * copy it back.
1697*7c478bd9Sstevel@tonic-gate 	 */
1698*7c478bd9Sstevel@tonic-gate 	(void) strcpy(lfmri, fmri);
1699*7c478bd9Sstevel@tonic-gate 
1700*7c478bd9Sstevel@tonic-gate 	if (scf_parse_svc_fmri(lfmri, NULL, &svc_name, &inst_name,
1701*7c478bd9Sstevel@tonic-gate 	    &pg_name, NULL) != SCF_SUCCESS) {
1702*7c478bd9Sstevel@tonic-gate 		free(lfmri);
1703*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(state, "invalid", state_sz);
1704*7c478bd9Sstevel@tonic-gate 		return;
1705*7c478bd9Sstevel@tonic-gate 	}
1706*7c478bd9Sstevel@tonic-gate 
1707*7c478bd9Sstevel@tonic-gate 	free(lfmri);
1708*7c478bd9Sstevel@tonic-gate 
1709*7c478bd9Sstevel@tonic-gate 	if (svc_name == NULL || pg_name != NULL) {
1710*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(state, "invalid", state_sz);
1711*7c478bd9Sstevel@tonic-gate 		return;
1712*7c478bd9Sstevel@tonic-gate 	}
1713*7c478bd9Sstevel@tonic-gate 
1714*7c478bd9Sstevel@tonic-gate 	if (inst_name != NULL) {
1715*7c478bd9Sstevel@tonic-gate 		/* instance: get state */
1716*7c478bd9Sstevel@tonic-gate 		inst = scf_instance_create(h);
1717*7c478bd9Sstevel@tonic-gate 		if (inst == NULL)
1718*7c478bd9Sstevel@tonic-gate 			scfdie();
1719*7c478bd9Sstevel@tonic-gate 
1720*7c478bd9Sstevel@tonic-gate 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1721*7c478bd9Sstevel@tonic-gate 		    NULL, SCF_DECODE_FMRI_EXACT) == SCF_SUCCESS)
1722*7c478bd9Sstevel@tonic-gate 			get_restarter_string_prop(inst, scf_property_state,
1723*7c478bd9Sstevel@tonic-gate 			    state, state_sz);
1724*7c478bd9Sstevel@tonic-gate 		else {
1725*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
1726*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
1727*7c478bd9Sstevel@tonic-gate 				(void) strlcpy(state, "invalid", state_sz);
1728*7c478bd9Sstevel@tonic-gate 				break;
1729*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
1730*7c478bd9Sstevel@tonic-gate 				(void) strlcpy(state, "absent", state_sz);
1731*7c478bd9Sstevel@tonic-gate 				break;
1732*7c478bd9Sstevel@tonic-gate 
1733*7c478bd9Sstevel@tonic-gate 			default:
1734*7c478bd9Sstevel@tonic-gate 				scfdie();
1735*7c478bd9Sstevel@tonic-gate 			}
1736*7c478bd9Sstevel@tonic-gate 		}
1737*7c478bd9Sstevel@tonic-gate 
1738*7c478bd9Sstevel@tonic-gate 		scf_instance_destroy(inst);
1739*7c478bd9Sstevel@tonic-gate 		return;
1740*7c478bd9Sstevel@tonic-gate 	}
1741*7c478bd9Sstevel@tonic-gate 
1742*7c478bd9Sstevel@tonic-gate 	/*
1743*7c478bd9Sstevel@tonic-gate 	 * service: If only one instance, use that state.  Otherwise, say
1744*7c478bd9Sstevel@tonic-gate 	 * "multiple".
1745*7c478bd9Sstevel@tonic-gate 	 */
1746*7c478bd9Sstevel@tonic-gate 	if ((svc = scf_service_create(h)) == NULL ||
1747*7c478bd9Sstevel@tonic-gate 	    (inst = scf_instance_create(h)) == NULL ||
1748*7c478bd9Sstevel@tonic-gate 	    (iter = scf_iter_create(h)) == NULL)
1749*7c478bd9Sstevel@tonic-gate 		scfdie();
1750*7c478bd9Sstevel@tonic-gate 
1751*7c478bd9Sstevel@tonic-gate 	if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1752*7c478bd9Sstevel@tonic-gate 	    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1753*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
1754*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
1755*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(state, "invalid", state_sz);
1756*7c478bd9Sstevel@tonic-gate 			goto out;
1757*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
1758*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(state, "absent", state_sz);
1759*7c478bd9Sstevel@tonic-gate 			goto out;
1760*7c478bd9Sstevel@tonic-gate 
1761*7c478bd9Sstevel@tonic-gate 		default:
1762*7c478bd9Sstevel@tonic-gate 			scfdie();
1763*7c478bd9Sstevel@tonic-gate 		}
1764*7c478bd9Sstevel@tonic-gate 	}
1765*7c478bd9Sstevel@tonic-gate 
1766*7c478bd9Sstevel@tonic-gate 	if (scf_iter_service_instances(iter, svc) != SCF_SUCCESS)
1767*7c478bd9Sstevel@tonic-gate 		scfdie();
1768*7c478bd9Sstevel@tonic-gate 
1769*7c478bd9Sstevel@tonic-gate 	switch (scf_iter_next_instance(iter, inst)) {
1770*7c478bd9Sstevel@tonic-gate 	case 0:
1771*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(state, "absent", state_sz);
1772*7c478bd9Sstevel@tonic-gate 		goto out;
1773*7c478bd9Sstevel@tonic-gate 
1774*7c478bd9Sstevel@tonic-gate 	case 1:
1775*7c478bd9Sstevel@tonic-gate 		break;
1776*7c478bd9Sstevel@tonic-gate 
1777*7c478bd9Sstevel@tonic-gate 	default:
1778*7c478bd9Sstevel@tonic-gate 		scfdie();
1779*7c478bd9Sstevel@tonic-gate 	}
1780*7c478bd9Sstevel@tonic-gate 
1781*7c478bd9Sstevel@tonic-gate 	/* Get the state in case this is the only instance. */
1782*7c478bd9Sstevel@tonic-gate 	get_restarter_string_prop(inst, scf_property_state, state, state_sz);
1783*7c478bd9Sstevel@tonic-gate 
1784*7c478bd9Sstevel@tonic-gate 	switch (scf_iter_next_instance(iter, inst)) {
1785*7c478bd9Sstevel@tonic-gate 	case 0:
1786*7c478bd9Sstevel@tonic-gate 		break;
1787*7c478bd9Sstevel@tonic-gate 
1788*7c478bd9Sstevel@tonic-gate 	case 1:
1789*7c478bd9Sstevel@tonic-gate 		/* Nope, multiple instances. */
1790*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(state, "multiple", state_sz);
1791*7c478bd9Sstevel@tonic-gate 		goto out;
1792*7c478bd9Sstevel@tonic-gate 
1793*7c478bd9Sstevel@tonic-gate 	default:
1794*7c478bd9Sstevel@tonic-gate 		scfdie();
1795*7c478bd9Sstevel@tonic-gate 	}
1796*7c478bd9Sstevel@tonic-gate 
1797*7c478bd9Sstevel@tonic-gate out:
1798*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
1799*7c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
1800*7c478bd9Sstevel@tonic-gate 	scf_service_destroy(svc);
1801*7c478bd9Sstevel@tonic-gate }
1802*7c478bd9Sstevel@tonic-gate 
1803*7c478bd9Sstevel@tonic-gate static void
1804*7c478bd9Sstevel@tonic-gate print_detailed_dependency(scf_propertygroup_t *pg)
1805*7c478bd9Sstevel@tonic-gate {
1806*7c478bd9Sstevel@tonic-gate 	scf_property_t *eprop;
1807*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
1808*7c478bd9Sstevel@tonic-gate 	scf_type_t ty;
1809*7c478bd9Sstevel@tonic-gate 	char *val_buf;
1810*7c478bd9Sstevel@tonic-gate 	int i;
1811*7c478bd9Sstevel@tonic-gate 
1812*7c478bd9Sstevel@tonic-gate 	if ((eprop = scf_property_create(h)) == NULL ||
1813*7c478bd9Sstevel@tonic-gate 	    (iter = scf_iter_create(h)) == NULL)
1814*7c478bd9Sstevel@tonic-gate 		scfdie();
1815*7c478bd9Sstevel@tonic-gate 
1816*7c478bd9Sstevel@tonic-gate 	val_buf = safe_malloc(max_scf_value_length + 1);
1817*7c478bd9Sstevel@tonic-gate 
1818*7c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENTITIES, eprop) !=
1819*7c478bd9Sstevel@tonic-gate 	    SCF_SUCCESS ||
1820*7c478bd9Sstevel@tonic-gate 	    scf_property_type(eprop, &ty) != SCF_SUCCESS ||
1821*7c478bd9Sstevel@tonic-gate 	    ty != SCF_TYPE_FMRI)
1822*7c478bd9Sstevel@tonic-gate 		return;
1823*7c478bd9Sstevel@tonic-gate 
1824*7c478bd9Sstevel@tonic-gate 	(void) printf("%-*s", DETAILED_WIDTH, gettext("dependency"));
1825*7c478bd9Sstevel@tonic-gate 
1826*7c478bd9Sstevel@tonic-gate 	/* Print the grouping */
1827*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING,
1828*7c478bd9Sstevel@tonic-gate 	    val_buf, max_scf_value_length + 1, 0) == 0)
1829*7c478bd9Sstevel@tonic-gate 		(void) fputs(val_buf, stdout);
1830*7c478bd9Sstevel@tonic-gate 	else
1831*7c478bd9Sstevel@tonic-gate 		(void) putchar('?');
1832*7c478bd9Sstevel@tonic-gate 
1833*7c478bd9Sstevel@tonic-gate 	(void) putchar('/');
1834*7c478bd9Sstevel@tonic-gate 
1835*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(pg, SCF_PROPERTY_RESTART_ON, SCF_TYPE_ASTRING,
1836*7c478bd9Sstevel@tonic-gate 	    val_buf, max_scf_value_length + 1, 0) == 0)
1837*7c478bd9Sstevel@tonic-gate 		(void) fputs(val_buf, stdout);
1838*7c478bd9Sstevel@tonic-gate 	else
1839*7c478bd9Sstevel@tonic-gate 		(void) putchar('?');
1840*7c478bd9Sstevel@tonic-gate 
1841*7c478bd9Sstevel@tonic-gate 	/* Print the dependency entities. */
1842*7c478bd9Sstevel@tonic-gate 	if (scf_iter_property_values(iter, eprop) == -1)
1843*7c478bd9Sstevel@tonic-gate 		scfdie();
1844*7c478bd9Sstevel@tonic-gate 
1845*7c478bd9Sstevel@tonic-gate 	while ((i = scf_iter_next_value(iter, g_val)) == 1) {
1846*7c478bd9Sstevel@tonic-gate 		char state[MAX_SCF_STATE_STRING_SZ];
1847*7c478bd9Sstevel@tonic-gate 
1848*7c478bd9Sstevel@tonic-gate 		if (scf_value_get_astring(g_val, val_buf,
1849*7c478bd9Sstevel@tonic-gate 		    max_scf_value_length + 1) < 0)
1850*7c478bd9Sstevel@tonic-gate 			scfdie();
1851*7c478bd9Sstevel@tonic-gate 
1852*7c478bd9Sstevel@tonic-gate 		(void) putchar(' ');
1853*7c478bd9Sstevel@tonic-gate 		(void) fputs(val_buf, stdout);
1854*7c478bd9Sstevel@tonic-gate 
1855*7c478bd9Sstevel@tonic-gate 		/* Print the state. */
1856*7c478bd9Sstevel@tonic-gate 		state[0] = '-';
1857*7c478bd9Sstevel@tonic-gate 		state[1] = '\0';
1858*7c478bd9Sstevel@tonic-gate 
1859*7c478bd9Sstevel@tonic-gate 		get_fmri_state(val_buf, state, sizeof (state));
1860*7c478bd9Sstevel@tonic-gate 
1861*7c478bd9Sstevel@tonic-gate 		(void) printf(" (%s)", state);
1862*7c478bd9Sstevel@tonic-gate 	}
1863*7c478bd9Sstevel@tonic-gate 	if (i == -1)
1864*7c478bd9Sstevel@tonic-gate 		scfdie();
1865*7c478bd9Sstevel@tonic-gate 
1866*7c478bd9Sstevel@tonic-gate 	(void) putchar('\n');
1867*7c478bd9Sstevel@tonic-gate 
1868*7c478bd9Sstevel@tonic-gate 	free(val_buf);
1869*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
1870*7c478bd9Sstevel@tonic-gate 	scf_property_destroy(eprop);
1871*7c478bd9Sstevel@tonic-gate }
1872*7c478bd9Sstevel@tonic-gate 
1873*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1874*7c478bd9Sstevel@tonic-gate static int
1875*7c478bd9Sstevel@tonic-gate print_detailed(void *unused, scf_walkinfo_t *wip)
1876*7c478bd9Sstevel@tonic-gate {
1877*7c478bd9Sstevel@tonic-gate 	scf_snapshot_t *snap;
1878*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *rpg;
1879*7c478bd9Sstevel@tonic-gate 	scf_iter_t *pg_iter;
1880*7c478bd9Sstevel@tonic-gate 
1881*7c478bd9Sstevel@tonic-gate 	char *buf;
1882*7c478bd9Sstevel@tonic-gate 	char *timebuf;
1883*7c478bd9Sstevel@tonic-gate 	size_t tbsz;
1884*7c478bd9Sstevel@tonic-gate 	int ret;
1885*7c478bd9Sstevel@tonic-gate 	uint64_t c;
1886*7c478bd9Sstevel@tonic-gate 	int temp, perm;
1887*7c478bd9Sstevel@tonic-gate 	struct timeval tv;
1888*7c478bd9Sstevel@tonic-gate 	time_t stime;
1889*7c478bd9Sstevel@tonic-gate 	struct tm *tmp;
1890*7c478bd9Sstevel@tonic-gate 
1891*7c478bd9Sstevel@tonic-gate 	const char * const fmt = "%-*s%s\n";
1892*7c478bd9Sstevel@tonic-gate 
1893*7c478bd9Sstevel@tonic-gate 	assert(wip->pg == NULL);
1894*7c478bd9Sstevel@tonic-gate 
1895*7c478bd9Sstevel@tonic-gate 	rpg = scf_pg_create(h);
1896*7c478bd9Sstevel@tonic-gate 	if (rpg == NULL)
1897*7c478bd9Sstevel@tonic-gate 		scfdie();
1898*7c478bd9Sstevel@tonic-gate 
1899*7c478bd9Sstevel@tonic-gate 	if (first_paragraph)
1900*7c478bd9Sstevel@tonic-gate 		first_paragraph = 0;
1901*7c478bd9Sstevel@tonic-gate 	else
1902*7c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
1903*7c478bd9Sstevel@tonic-gate 
1904*7c478bd9Sstevel@tonic-gate 	buf = safe_malloc(max_scf_fmri_length + 1);
1905*7c478bd9Sstevel@tonic-gate 
1906*7c478bd9Sstevel@tonic-gate 	if (scf_instance_to_fmri(wip->inst, buf, max_scf_fmri_length + 1) != -1)
1907*7c478bd9Sstevel@tonic-gate 		(void) printf(fmt, DETAILED_WIDTH, "fmri", buf);
1908*7c478bd9Sstevel@tonic-gate 
1909*7c478bd9Sstevel@tonic-gate 	if (common_name_buf == NULL)
1910*7c478bd9Sstevel@tonic-gate 		common_name_buf = safe_malloc(max_scf_value_length + 1);
1911*7c478bd9Sstevel@tonic-gate 
1912*7c478bd9Sstevel@tonic-gate 	if (inst_get_single_val(wip->inst, SCF_PG_TM_COMMON_NAME, locale,
1913*7c478bd9Sstevel@tonic-gate 	    SCF_TYPE_USTRING, common_name_buf, max_scf_value_length, 0, 1, 1)
1914*7c478bd9Sstevel@tonic-gate 	    == 0)
1915*7c478bd9Sstevel@tonic-gate 		(void) printf(fmt, DETAILED_WIDTH, gettext("name"),
1916*7c478bd9Sstevel@tonic-gate 		    common_name_buf);
1917*7c478bd9Sstevel@tonic-gate 	else if (inst_get_single_val(wip->inst, SCF_PG_TM_COMMON_NAME, "C",
1918*7c478bd9Sstevel@tonic-gate 	    SCF_TYPE_USTRING, common_name_buf, max_scf_value_length, 0, 1, 1)
1919*7c478bd9Sstevel@tonic-gate 	    == 0)
1920*7c478bd9Sstevel@tonic-gate 		(void) printf(fmt, DETAILED_WIDTH, gettext("name"),
1921*7c478bd9Sstevel@tonic-gate 		    common_name_buf);
1922*7c478bd9Sstevel@tonic-gate 
1923*7c478bd9Sstevel@tonic-gate 	/*
1924*7c478bd9Sstevel@tonic-gate 	 * Synthesize an 'enabled' property that hides the enabled_ovr
1925*7c478bd9Sstevel@tonic-gate 	 * implementation from the user.  If the service has been temporarily
1926*7c478bd9Sstevel@tonic-gate 	 * set to a state other than its permanent value, alert the user with
1927*7c478bd9Sstevel@tonic-gate 	 * a '(temporary)' message.
1928*7c478bd9Sstevel@tonic-gate 	 */
1929*7c478bd9Sstevel@tonic-gate 	perm = instance_enabled(wip->inst, B_FALSE);
1930*7c478bd9Sstevel@tonic-gate 	temp = instance_enabled(wip->inst, B_TRUE);
1931*7c478bd9Sstevel@tonic-gate 	if (temp != -1) {
1932*7c478bd9Sstevel@tonic-gate 		if (temp != perm)
1933*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("%-*s%s (temporary)\n"),
1934*7c478bd9Sstevel@tonic-gate 			    DETAILED_WIDTH, gettext("enabled"),
1935*7c478bd9Sstevel@tonic-gate 			    temp ? gettext("true") : gettext("false"));
1936*7c478bd9Sstevel@tonic-gate 		else
1937*7c478bd9Sstevel@tonic-gate 			(void) printf(fmt, DETAILED_WIDTH,
1938*7c478bd9Sstevel@tonic-gate 			    gettext("enabled"), temp ? gettext("true") :
1939*7c478bd9Sstevel@tonic-gate 			    gettext("false"));
1940*7c478bd9Sstevel@tonic-gate 	} else if (perm != -1) {
1941*7c478bd9Sstevel@tonic-gate 		(void) printf(fmt, DETAILED_WIDTH, gettext("enabled"),
1942*7c478bd9Sstevel@tonic-gate 		    perm ? gettext("true") : gettext("false"));
1943*7c478bd9Sstevel@tonic-gate 	}
1944*7c478bd9Sstevel@tonic-gate 
1945*7c478bd9Sstevel@tonic-gate 	/*
1946*7c478bd9Sstevel@tonic-gate 	 * Property values may be longer than max_scf_fmri_length, but these
1947*7c478bd9Sstevel@tonic-gate 	 * shouldn't be, so we'll just reuse buf.  The user can use svcprop if
1948*7c478bd9Sstevel@tonic-gate 	 * he suspects something fishy.
1949*7c478bd9Sstevel@tonic-gate 	 */
1950*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(wip->inst, SCF_PG_RESTARTER, rpg) != 0) {
1951*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
1952*7c478bd9Sstevel@tonic-gate 			scfdie();
1953*7c478bd9Sstevel@tonic-gate 
1954*7c478bd9Sstevel@tonic-gate 		scf_pg_destroy(rpg);
1955*7c478bd9Sstevel@tonic-gate 		rpg = NULL;
1956*7c478bd9Sstevel@tonic-gate 	}
1957*7c478bd9Sstevel@tonic-gate 
1958*7c478bd9Sstevel@tonic-gate 	if (rpg) {
1959*7c478bd9Sstevel@tonic-gate 		if (pg_get_single_val(rpg, scf_property_state, SCF_TYPE_ASTRING,
1960*7c478bd9Sstevel@tonic-gate 		    buf, max_scf_fmri_length + 1, 0) == 0)
1961*7c478bd9Sstevel@tonic-gate 			(void) printf(fmt, DETAILED_WIDTH, gettext("state"),
1962*7c478bd9Sstevel@tonic-gate 			    buf);
1963*7c478bd9Sstevel@tonic-gate 
1964*7c478bd9Sstevel@tonic-gate 		if (pg_get_single_val(rpg, scf_property_next_state,
1965*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, buf, max_scf_fmri_length + 1, 0) == 0)
1966*7c478bd9Sstevel@tonic-gate 			(void) printf(fmt, DETAILED_WIDTH,
1967*7c478bd9Sstevel@tonic-gate 			    gettext("next_state"), buf);
1968*7c478bd9Sstevel@tonic-gate 
1969*7c478bd9Sstevel@tonic-gate 		if (pg_get_single_val(rpg, SCF_PROPERTY_STATE_TIMESTAMP,
1970*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_TIME, &tv, NULL, 0) == 0) {
1971*7c478bd9Sstevel@tonic-gate 			stime = tv.tv_sec;
1972*7c478bd9Sstevel@tonic-gate 			tmp = localtime(&stime);
1973*7c478bd9Sstevel@tonic-gate 			for (tbsz = 50; ; tbsz *= 2) {
1974*7c478bd9Sstevel@tonic-gate 				timebuf = safe_malloc(tbsz);
1975*7c478bd9Sstevel@tonic-gate 				if (strftime(timebuf, tbsz, NULL, tmp) != 0)
1976*7c478bd9Sstevel@tonic-gate 					break;
1977*7c478bd9Sstevel@tonic-gate 				free(timebuf);
1978*7c478bd9Sstevel@tonic-gate 			}
1979*7c478bd9Sstevel@tonic-gate 			(void) printf(fmt, DETAILED_WIDTH,
1980*7c478bd9Sstevel@tonic-gate 			    gettext("state_time"),
1981*7c478bd9Sstevel@tonic-gate 			    timebuf);
1982*7c478bd9Sstevel@tonic-gate 			free(timebuf);
1983*7c478bd9Sstevel@tonic-gate 		}
1984*7c478bd9Sstevel@tonic-gate 
1985*7c478bd9Sstevel@tonic-gate 	}
1986*7c478bd9Sstevel@tonic-gate 
1987*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(rpg, SCF_PROPERTY_ALT_LOGFILE,
1988*7c478bd9Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, buf, max_scf_fmri_length + 1, 0) == 0)
1989*7c478bd9Sstevel@tonic-gate 		(void) printf(fmt, DETAILED_WIDTH, gettext("alt_logfile"),
1990*7c478bd9Sstevel@tonic-gate 		    buf);
1991*7c478bd9Sstevel@tonic-gate 
1992*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(rpg, SCF_PROPERTY_LOGFILE,
1993*7c478bd9Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, buf, max_scf_fmri_length + 1, 0) == 0)
1994*7c478bd9Sstevel@tonic-gate 		(void) printf(fmt, DETAILED_WIDTH, gettext("logfile"), buf);
1995*7c478bd9Sstevel@tonic-gate 
1996*7c478bd9Sstevel@tonic-gate 	if (inst_get_single_val(wip->inst, SCF_PG_GENERAL,
1997*7c478bd9Sstevel@tonic-gate 	    SCF_PROPERTY_RESTARTER, SCF_TYPE_ASTRING, buf,
1998*7c478bd9Sstevel@tonic-gate 	    max_scf_fmri_length + 1, 0, 0, 1) == 0)
1999*7c478bd9Sstevel@tonic-gate 		(void) printf(fmt, DETAILED_WIDTH, gettext("restarter"), buf);
2000*7c478bd9Sstevel@tonic-gate 	else
2001*7c478bd9Sstevel@tonic-gate 		(void) printf(fmt, DETAILED_WIDTH, gettext("restarter"),
2002*7c478bd9Sstevel@tonic-gate 		    SCF_SERVICE_STARTD);
2003*7c478bd9Sstevel@tonic-gate 
2004*7c478bd9Sstevel@tonic-gate 	free(buf);
2005*7c478bd9Sstevel@tonic-gate 
2006*7c478bd9Sstevel@tonic-gate 	if (rpg) {
2007*7c478bd9Sstevel@tonic-gate 		scf_iter_t *iter;
2008*7c478bd9Sstevel@tonic-gate 
2009*7c478bd9Sstevel@tonic-gate 		if ((iter = scf_iter_create(h)) == NULL)
2010*7c478bd9Sstevel@tonic-gate 			scfdie();
2011*7c478bd9Sstevel@tonic-gate 
2012*7c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(rpg, scf_property_contract, g_prop) ==
2013*7c478bd9Sstevel@tonic-gate 		    0) {
2014*7c478bd9Sstevel@tonic-gate 			if (scf_property_is_type(g_prop, SCF_TYPE_COUNT) == 0) {
2015*7c478bd9Sstevel@tonic-gate 				(void) printf("%-*s", DETAILED_WIDTH,
2016*7c478bd9Sstevel@tonic-gate 				    "contract_id");
2017*7c478bd9Sstevel@tonic-gate 
2018*7c478bd9Sstevel@tonic-gate 				if (scf_iter_property_values(iter, g_prop) != 0)
2019*7c478bd9Sstevel@tonic-gate 					scfdie();
2020*7c478bd9Sstevel@tonic-gate 
2021*7c478bd9Sstevel@tonic-gate 				for (;;) {
2022*7c478bd9Sstevel@tonic-gate 					ret = scf_iter_next_value(iter, g_val);
2023*7c478bd9Sstevel@tonic-gate 					if (ret == -1)
2024*7c478bd9Sstevel@tonic-gate 						scfdie();
2025*7c478bd9Sstevel@tonic-gate 					if (ret == 0)
2026*7c478bd9Sstevel@tonic-gate 						break;
2027*7c478bd9Sstevel@tonic-gate 
2028*7c478bd9Sstevel@tonic-gate 					if (scf_value_get_count(g_val, &c) != 0)
2029*7c478bd9Sstevel@tonic-gate 						scfdie();
2030*7c478bd9Sstevel@tonic-gate 					(void) printf("%lu ", (ctid_t)c);
2031*7c478bd9Sstevel@tonic-gate 				}
2032*7c478bd9Sstevel@tonic-gate 
2033*7c478bd9Sstevel@tonic-gate 				(void) putchar('\n');
2034*7c478bd9Sstevel@tonic-gate 			} else {
2035*7c478bd9Sstevel@tonic-gate 				if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
2036*7c478bd9Sstevel@tonic-gate 					scfdie();
2037*7c478bd9Sstevel@tonic-gate 			}
2038*7c478bd9Sstevel@tonic-gate 		} else {
2039*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
2040*7c478bd9Sstevel@tonic-gate 				scfdie();
2041*7c478bd9Sstevel@tonic-gate 		}
2042*7c478bd9Sstevel@tonic-gate 
2043*7c478bd9Sstevel@tonic-gate 		scf_iter_destroy(iter);
2044*7c478bd9Sstevel@tonic-gate 	} else {
2045*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
2046*7c478bd9Sstevel@tonic-gate 			scfdie();
2047*7c478bd9Sstevel@tonic-gate 	}
2048*7c478bd9Sstevel@tonic-gate 
2049*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(rpg);
2050*7c478bd9Sstevel@tonic-gate 
2051*7c478bd9Sstevel@tonic-gate 	/* Dependencies. */
2052*7c478bd9Sstevel@tonic-gate 	if ((pg_iter = scf_iter_create(h)) == NULL)
2053*7c478bd9Sstevel@tonic-gate 		scfdie();
2054*7c478bd9Sstevel@tonic-gate 
2055*7c478bd9Sstevel@tonic-gate 	snap = get_running_snapshot(wip->inst);
2056*7c478bd9Sstevel@tonic-gate 
2057*7c478bd9Sstevel@tonic-gate 	if (scf_iter_instance_pgs_typed_composed(pg_iter, wip->inst, snap,
2058*7c478bd9Sstevel@tonic-gate 	    SCF_GROUP_DEPENDENCY) != SCF_SUCCESS)
2059*7c478bd9Sstevel@tonic-gate 		scfdie();
2060*7c478bd9Sstevel@tonic-gate 
2061*7c478bd9Sstevel@tonic-gate 	while ((ret = scf_iter_next_pg(pg_iter, g_pg)) == 1)
2062*7c478bd9Sstevel@tonic-gate 		print_detailed_dependency(g_pg);
2063*7c478bd9Sstevel@tonic-gate 	if (ret == -1)
2064*7c478bd9Sstevel@tonic-gate 		scfdie();
2065*7c478bd9Sstevel@tonic-gate 
2066*7c478bd9Sstevel@tonic-gate 	scf_snapshot_destroy(snap);
2067*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(pg_iter);
2068*7c478bd9Sstevel@tonic-gate 
2069*7c478bd9Sstevel@tonic-gate 	if (opt_processes)
2070*7c478bd9Sstevel@tonic-gate 		detailed_list_processes(wip->inst);
2071*7c478bd9Sstevel@tonic-gate 
2072*7c478bd9Sstevel@tonic-gate 	return (0);
2073*7c478bd9Sstevel@tonic-gate }
2074*7c478bd9Sstevel@tonic-gate 
2075*7c478bd9Sstevel@tonic-gate /*
2076*7c478bd9Sstevel@tonic-gate  * Append a one-lined description of each process in inst's contract(s) and
2077*7c478bd9Sstevel@tonic-gate  * return the augmented string.
2078*7c478bd9Sstevel@tonic-gate  */
2079*7c478bd9Sstevel@tonic-gate static char *
2080*7c478bd9Sstevel@tonic-gate add_processes(char *line, scf_instance_t *inst, scf_propertygroup_t *lpg)
2081*7c478bd9Sstevel@tonic-gate {
2082*7c478bd9Sstevel@tonic-gate 	pid_t *pids = NULL;
2083*7c478bd9Sstevel@tonic-gate 	uint_t i, n = 0;
2084*7c478bd9Sstevel@tonic-gate 
2085*7c478bd9Sstevel@tonic-gate 	if (lpg == NULL) {
2086*7c478bd9Sstevel@tonic-gate 		if (instance_processes(inst, &pids, &n) != 0)
2087*7c478bd9Sstevel@tonic-gate 			return (line);
2088*7c478bd9Sstevel@tonic-gate 	} else {
2089*7c478bd9Sstevel@tonic-gate 		scf_iter_t *iter;
2090*7c478bd9Sstevel@tonic-gate 
2091*7c478bd9Sstevel@tonic-gate 		if ((iter = scf_iter_create(h)) == NULL)
2092*7c478bd9Sstevel@tonic-gate 			scfdie();
2093*7c478bd9Sstevel@tonic-gate 
2094*7c478bd9Sstevel@tonic-gate 		(void) propvals_to_pids(lpg, scf_property_contract, &pids, &n,
2095*7c478bd9Sstevel@tonic-gate 		    g_prop, g_val, iter);
2096*7c478bd9Sstevel@tonic-gate 
2097*7c478bd9Sstevel@tonic-gate 		scf_iter_destroy(iter);
2098*7c478bd9Sstevel@tonic-gate 	}
2099*7c478bd9Sstevel@tonic-gate 
2100*7c478bd9Sstevel@tonic-gate 	if (n == 0)
2101*7c478bd9Sstevel@tonic-gate 		return (line);
2102*7c478bd9Sstevel@tonic-gate 
2103*7c478bd9Sstevel@tonic-gate 	qsort(pids, n, sizeof (*pids), pidcmp);
2104*7c478bd9Sstevel@tonic-gate 
2105*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; ++i) {
2106*7c478bd9Sstevel@tonic-gate 		char *cp, stime[9];
2107*7c478bd9Sstevel@tonic-gate 		psinfo_t psi;
2108*7c478bd9Sstevel@tonic-gate 		struct tm *tm;
2109*7c478bd9Sstevel@tonic-gate 		int len = 1 + 15 + 8 + 3 + 6 + 1 + PRFNSZ;
2110*7c478bd9Sstevel@tonic-gate 
2111*7c478bd9Sstevel@tonic-gate 		if (get_psinfo(pids[i], &psi) != 0)
2112*7c478bd9Sstevel@tonic-gate 			continue;
2113*7c478bd9Sstevel@tonic-gate 
2114*7c478bd9Sstevel@tonic-gate 		line = realloc(line, strlen(line) + len);
2115*7c478bd9Sstevel@tonic-gate 		if (line == NULL)
2116*7c478bd9Sstevel@tonic-gate 			uu_die(gettext("Out of memory.\n"));
2117*7c478bd9Sstevel@tonic-gate 
2118*7c478bd9Sstevel@tonic-gate 		cp = strchr(line, '\0');
2119*7c478bd9Sstevel@tonic-gate 
2120*7c478bd9Sstevel@tonic-gate 		tm = localtime(&psi.pr_start.tv_sec);
2121*7c478bd9Sstevel@tonic-gate 
2122*7c478bd9Sstevel@tonic-gate 		/*
2123*7c478bd9Sstevel@tonic-gate 		 * Print time if started within the past 24 hours, print date
2124*7c478bd9Sstevel@tonic-gate 		 * if within the past 12 months, print year if started greater
2125*7c478bd9Sstevel@tonic-gate 		 * than 12 months ago.
2126*7c478bd9Sstevel@tonic-gate 		 */
2127*7c478bd9Sstevel@tonic-gate 		if (now - psi.pr_start.tv_sec < 24 * 60 * 60)
2128*7c478bd9Sstevel@tonic-gate 		    (void) strftime(stime, sizeof (stime), gettext(FORMAT_TIME),
2129*7c478bd9Sstevel@tonic-gate 			tm);
2130*7c478bd9Sstevel@tonic-gate 		else if (now - psi.pr_start.tv_sec < 12 * 30 * 24 * 60 * 60)
2131*7c478bd9Sstevel@tonic-gate 		    (void) strftime(stime, sizeof (stime), gettext(FORMAT_DATE),
2132*7c478bd9Sstevel@tonic-gate 			tm);
2133*7c478bd9Sstevel@tonic-gate 		else
2134*7c478bd9Sstevel@tonic-gate 		    (void) strftime(stime, sizeof (stime), gettext(FORMAT_YEAR),
2135*7c478bd9Sstevel@tonic-gate 			tm);
2136*7c478bd9Sstevel@tonic-gate 
2137*7c478bd9Sstevel@tonic-gate 		(void) snprintf(cp, len, "\n               %-8s   %6ld %.*s",
2138*7c478bd9Sstevel@tonic-gate 		    stime, pids[i], PRFNSZ, psi.pr_fname);
2139*7c478bd9Sstevel@tonic-gate 	}
2140*7c478bd9Sstevel@tonic-gate 
2141*7c478bd9Sstevel@tonic-gate 	free(pids);
2142*7c478bd9Sstevel@tonic-gate 
2143*7c478bd9Sstevel@tonic-gate 	return (line);
2144*7c478bd9Sstevel@tonic-gate }
2145*7c478bd9Sstevel@tonic-gate 
2146*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2147*7c478bd9Sstevel@tonic-gate static int
2148*7c478bd9Sstevel@tonic-gate list_instance(void *unused, scf_walkinfo_t *wip)
2149*7c478bd9Sstevel@tonic-gate {
2150*7c478bd9Sstevel@tonic-gate 	struct avl_string *lp;
2151*7c478bd9Sstevel@tonic-gate 	char *cp;
2152*7c478bd9Sstevel@tonic-gate 	int i;
2153*7c478bd9Sstevel@tonic-gate 	uu_avl_index_t idx;
2154*7c478bd9Sstevel@tonic-gate 
2155*7c478bd9Sstevel@tonic-gate 	/*
2156*7c478bd9Sstevel@tonic-gate 	 * If the user has specified a restarter, check for a match first
2157*7c478bd9Sstevel@tonic-gate 	 */
2158*7c478bd9Sstevel@tonic-gate 	if (restarters != NULL) {
2159*7c478bd9Sstevel@tonic-gate 		struct pfmri_list *rest;
2160*7c478bd9Sstevel@tonic-gate 		int match;
2161*7c478bd9Sstevel@tonic-gate 		char *restarter_fmri;
2162*7c478bd9Sstevel@tonic-gate 		const char *scope_name, *svc_name, *inst_name, *pg_name;
2163*7c478bd9Sstevel@tonic-gate 
2164*7c478bd9Sstevel@tonic-gate 		/* legacy services don't have restarters */
2165*7c478bd9Sstevel@tonic-gate 		if (wip->pg != NULL)
2166*7c478bd9Sstevel@tonic-gate 			return (0);
2167*7c478bd9Sstevel@tonic-gate 
2168*7c478bd9Sstevel@tonic-gate 		restarter_fmri = safe_malloc(max_scf_fmri_length + 1);
2169*7c478bd9Sstevel@tonic-gate 
2170*7c478bd9Sstevel@tonic-gate 		if (inst_get_single_val(wip->inst, SCF_PG_GENERAL,
2171*7c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_RESTARTER, SCF_TYPE_ASTRING, restarter_fmri,
2172*7c478bd9Sstevel@tonic-gate 		    max_scf_fmri_length + 1, 0, 0, 1) != 0)
2173*7c478bd9Sstevel@tonic-gate 			(void) strcpy(restarter_fmri, SCF_SERVICE_STARTD);
2174*7c478bd9Sstevel@tonic-gate 
2175*7c478bd9Sstevel@tonic-gate 		if (scf_parse_svc_fmri(restarter_fmri, &scope_name, &svc_name,
2176*7c478bd9Sstevel@tonic-gate 		    &inst_name, &pg_name, NULL) != SCF_SUCCESS) {
2177*7c478bd9Sstevel@tonic-gate 			free(restarter_fmri);
2178*7c478bd9Sstevel@tonic-gate 			return (0);
2179*7c478bd9Sstevel@tonic-gate 		}
2180*7c478bd9Sstevel@tonic-gate 
2181*7c478bd9Sstevel@tonic-gate 		match = 0;
2182*7c478bd9Sstevel@tonic-gate 		for (rest = restarters; rest != NULL; rest = rest->next) {
2183*7c478bd9Sstevel@tonic-gate 			if (strcmp(rest->scope, scope_name) == 0 &&
2184*7c478bd9Sstevel@tonic-gate 			    strcmp(rest->service, svc_name) == 0 &&
2185*7c478bd9Sstevel@tonic-gate 			    strcmp(rest->instance, inst_name) == 0)
2186*7c478bd9Sstevel@tonic-gate 				match = 1;
2187*7c478bd9Sstevel@tonic-gate 		}
2188*7c478bd9Sstevel@tonic-gate 
2189*7c478bd9Sstevel@tonic-gate 		free(restarter_fmri);
2190*7c478bd9Sstevel@tonic-gate 
2191*7c478bd9Sstevel@tonic-gate 		if (!match)
2192*7c478bd9Sstevel@tonic-gate 			return (0);
2193*7c478bd9Sstevel@tonic-gate 	}
2194*7c478bd9Sstevel@tonic-gate 
2195*7c478bd9Sstevel@tonic-gate 	if (wip->pg == NULL && ht_buckets != NULL && ht_add(wip->fmri)) {
2196*7c478bd9Sstevel@tonic-gate 		/* It was already there. */
2197*7c478bd9Sstevel@tonic-gate 		return (0);
2198*7c478bd9Sstevel@tonic-gate 	}
2199*7c478bd9Sstevel@tonic-gate 
2200*7c478bd9Sstevel@tonic-gate 	lp = safe_malloc(sizeof (*lp));
2201*7c478bd9Sstevel@tonic-gate 
2202*7c478bd9Sstevel@tonic-gate 	lp->str = NULL;
2203*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < opt_cnum; ++i) {
2204*7c478bd9Sstevel@tonic-gate 		columns[opt_columns[i]].sprint(&lp->str, wip);
2205*7c478bd9Sstevel@tonic-gate 	}
2206*7c478bd9Sstevel@tonic-gate 	cp = lp->str + strlen(lp->str);
2207*7c478bd9Sstevel@tonic-gate 	cp--;
2208*7c478bd9Sstevel@tonic-gate 	while (*cp == ' ')
2209*7c478bd9Sstevel@tonic-gate 		cp--;
2210*7c478bd9Sstevel@tonic-gate 	*(cp+1) = '\0';
2211*7c478bd9Sstevel@tonic-gate 
2212*7c478bd9Sstevel@tonic-gate 	/* If we're supposed to list the processes, too, do that now. */
2213*7c478bd9Sstevel@tonic-gate 	if (opt_processes)
2214*7c478bd9Sstevel@tonic-gate 		lp->str = add_processes(lp->str, wip->inst, wip->pg);
2215*7c478bd9Sstevel@tonic-gate 
2216*7c478bd9Sstevel@tonic-gate 	/* Create the sort key. */
2217*7c478bd9Sstevel@tonic-gate 	cp = lp->key = safe_malloc(sortkey_sz);
2218*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < opt_snum; ++i) {
2219*7c478bd9Sstevel@tonic-gate 		int j = opt_sort[i] & 0xff;
2220*7c478bd9Sstevel@tonic-gate 
2221*7c478bd9Sstevel@tonic-gate 		assert(columns[j].get_sortkey != NULL);
2222*7c478bd9Sstevel@tonic-gate 		columns[j].get_sortkey(cp, opt_sort[i] & ~0xff, wip);
2223*7c478bd9Sstevel@tonic-gate 		cp += columns[j].sortkey_width;
2224*7c478bd9Sstevel@tonic-gate 	}
2225*7c478bd9Sstevel@tonic-gate 
2226*7c478bd9Sstevel@tonic-gate 	/* Insert into AVL tree. */
2227*7c478bd9Sstevel@tonic-gate 	uu_avl_node_init(lp, &lp->node, lines_pool);
2228*7c478bd9Sstevel@tonic-gate 	(void) uu_avl_find(lines, lp, NULL, &idx);
2229*7c478bd9Sstevel@tonic-gate 	uu_avl_insert(lines, lp, idx);
2230*7c478bd9Sstevel@tonic-gate 
2231*7c478bd9Sstevel@tonic-gate 	return (0);
2232*7c478bd9Sstevel@tonic-gate }
2233*7c478bd9Sstevel@tonic-gate 
2234*7c478bd9Sstevel@tonic-gate static int
2235*7c478bd9Sstevel@tonic-gate list_if_enabled(void *unused, scf_walkinfo_t *wip)
2236*7c478bd9Sstevel@tonic-gate {
2237*7c478bd9Sstevel@tonic-gate 	if (wip->pg != NULL ||
2238*7c478bd9Sstevel@tonic-gate 	    instance_enabled(wip->inst, B_FALSE) == 1 ||
2239*7c478bd9Sstevel@tonic-gate 	    instance_enabled(wip->inst, B_TRUE) == 1)
2240*7c478bd9Sstevel@tonic-gate 		return (list_instance(unused, wip));
2241*7c478bd9Sstevel@tonic-gate 
2242*7c478bd9Sstevel@tonic-gate 	return (0);
2243*7c478bd9Sstevel@tonic-gate }
2244*7c478bd9Sstevel@tonic-gate 
2245*7c478bd9Sstevel@tonic-gate /*
2246*7c478bd9Sstevel@tonic-gate  * Service FMRI selection: Lookup and call list_instance() for the instances.
2247*7c478bd9Sstevel@tonic-gate  * Instance FMRI selection: Lookup and call list_instance().
2248*7c478bd9Sstevel@tonic-gate  *
2249*7c478bd9Sstevel@tonic-gate  * Note: This is shoehorned into a walk_dependencies() callback prototype so
2250*7c478bd9Sstevel@tonic-gate  * it can be used in list_dependencies.
2251*7c478bd9Sstevel@tonic-gate  */
2252*7c478bd9Sstevel@tonic-gate static int
2253*7c478bd9Sstevel@tonic-gate list_svc_or_inst_fmri(void *complain, scf_walkinfo_t *wip)
2254*7c478bd9Sstevel@tonic-gate {
2255*7c478bd9Sstevel@tonic-gate 	char *fmri;
2256*7c478bd9Sstevel@tonic-gate 	const char *svc_name, *inst_name, *pg_name, *save;
2257*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
2258*7c478bd9Sstevel@tonic-gate 	int ret;
2259*7c478bd9Sstevel@tonic-gate 
2260*7c478bd9Sstevel@tonic-gate 	fmri = safe_strdup(wip->fmri);
2261*7c478bd9Sstevel@tonic-gate 
2262*7c478bd9Sstevel@tonic-gate 	if (scf_parse_svc_fmri(fmri, NULL, &svc_name, &inst_name, &pg_name,
2263*7c478bd9Sstevel@tonic-gate 	    NULL) != SCF_SUCCESS) {
2264*7c478bd9Sstevel@tonic-gate 		if (complain)
2265*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("FMRI \"%s\" is invalid.\n"),
2266*7c478bd9Sstevel@tonic-gate 			    wip->fmri);
2267*7c478bd9Sstevel@tonic-gate 		exit_status = UU_EXIT_FATAL;
2268*7c478bd9Sstevel@tonic-gate 		free(fmri);
2269*7c478bd9Sstevel@tonic-gate 		return (0);
2270*7c478bd9Sstevel@tonic-gate 	}
2271*7c478bd9Sstevel@tonic-gate 
2272*7c478bd9Sstevel@tonic-gate 	/*
2273*7c478bd9Sstevel@tonic-gate 	 * Yes, this invalidates *_name, but we only care whether they're NULL
2274*7c478bd9Sstevel@tonic-gate 	 * or not.
2275*7c478bd9Sstevel@tonic-gate 	 */
2276*7c478bd9Sstevel@tonic-gate 	free(fmri);
2277*7c478bd9Sstevel@tonic-gate 
2278*7c478bd9Sstevel@tonic-gate 	if (svc_name == NULL || pg_name != NULL) {
2279*7c478bd9Sstevel@tonic-gate 		if (complain)
2280*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("FMRI \"%s\" does not designate a "
2281*7c478bd9Sstevel@tonic-gate 			    "service or instance.\n"), wip->fmri);
2282*7c478bd9Sstevel@tonic-gate 		return (0);
2283*7c478bd9Sstevel@tonic-gate 	}
2284*7c478bd9Sstevel@tonic-gate 
2285*7c478bd9Sstevel@tonic-gate 	if (inst_name != NULL) {
2286*7c478bd9Sstevel@tonic-gate 		/* instance */
2287*7c478bd9Sstevel@tonic-gate 		if (scf_handle_decode_fmri(h, wip->fmri, wip->scope, wip->svc,
2288*7c478bd9Sstevel@tonic-gate 		    wip->inst, NULL, NULL, 0) != SCF_SUCCESS) {
2289*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
2290*7c478bd9Sstevel@tonic-gate 				scfdie();
2291*7c478bd9Sstevel@tonic-gate 
2292*7c478bd9Sstevel@tonic-gate 			if (complain)
2293*7c478bd9Sstevel@tonic-gate 				uu_warn(gettext(
2294*7c478bd9Sstevel@tonic-gate 				    "Instance \"%s\" does not exist.\n"),
2295*7c478bd9Sstevel@tonic-gate 				    wip->fmri);
2296*7c478bd9Sstevel@tonic-gate 			return (0);
2297*7c478bd9Sstevel@tonic-gate 		}
2298*7c478bd9Sstevel@tonic-gate 
2299*7c478bd9Sstevel@tonic-gate 		return (list_instance(NULL, wip));
2300*7c478bd9Sstevel@tonic-gate 	}
2301*7c478bd9Sstevel@tonic-gate 
2302*7c478bd9Sstevel@tonic-gate 	/* service: Walk the instances. */
2303*7c478bd9Sstevel@tonic-gate 	if (scf_handle_decode_fmri(h, wip->fmri, wip->scope, wip->svc, NULL,
2304*7c478bd9Sstevel@tonic-gate 	    NULL, NULL, 0) != SCF_SUCCESS) {
2305*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
2306*7c478bd9Sstevel@tonic-gate 			scfdie();
2307*7c478bd9Sstevel@tonic-gate 
2308*7c478bd9Sstevel@tonic-gate 		if (complain)
2309*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Service \"%s\" does not exist.\n"),
2310*7c478bd9Sstevel@tonic-gate 			    wip->fmri);
2311*7c478bd9Sstevel@tonic-gate 
2312*7c478bd9Sstevel@tonic-gate 		exit_status = UU_EXIT_FATAL;
2313*7c478bd9Sstevel@tonic-gate 
2314*7c478bd9Sstevel@tonic-gate 		return (0);
2315*7c478bd9Sstevel@tonic-gate 	}
2316*7c478bd9Sstevel@tonic-gate 
2317*7c478bd9Sstevel@tonic-gate 	iter = scf_iter_create(h);
2318*7c478bd9Sstevel@tonic-gate 	if (iter == NULL)
2319*7c478bd9Sstevel@tonic-gate 		scfdie();
2320*7c478bd9Sstevel@tonic-gate 
2321*7c478bd9Sstevel@tonic-gate 	if (scf_iter_service_instances(iter, wip->svc) != SCF_SUCCESS)
2322*7c478bd9Sstevel@tonic-gate 		scfdie();
2323*7c478bd9Sstevel@tonic-gate 
2324*7c478bd9Sstevel@tonic-gate 	if ((fmri = malloc(max_scf_fmri_length + 1)) == NULL) {
2325*7c478bd9Sstevel@tonic-gate 		scf_iter_destroy(iter);
2326*7c478bd9Sstevel@tonic-gate 		exit_status = UU_EXIT_FATAL;
2327*7c478bd9Sstevel@tonic-gate 		return (0);
2328*7c478bd9Sstevel@tonic-gate 	}
2329*7c478bd9Sstevel@tonic-gate 
2330*7c478bd9Sstevel@tonic-gate 	save = wip->fmri;
2331*7c478bd9Sstevel@tonic-gate 	wip->fmri = fmri;
2332*7c478bd9Sstevel@tonic-gate 	while ((ret = scf_iter_next_instance(iter, wip->inst)) == 1) {
2333*7c478bd9Sstevel@tonic-gate 		if (scf_instance_to_fmri(wip->inst, fmri,
2334*7c478bd9Sstevel@tonic-gate 		    max_scf_fmri_length + 1) <= 0)
2335*7c478bd9Sstevel@tonic-gate 			scfdie();
2336*7c478bd9Sstevel@tonic-gate 		(void) list_instance(NULL, wip);
2337*7c478bd9Sstevel@tonic-gate 	}
2338*7c478bd9Sstevel@tonic-gate 	free(fmri);
2339*7c478bd9Sstevel@tonic-gate 	wip->fmri = save;
2340*7c478bd9Sstevel@tonic-gate 	if (ret == -1)
2341*7c478bd9Sstevel@tonic-gate 		scfdie();
2342*7c478bd9Sstevel@tonic-gate 
2343*7c478bd9Sstevel@tonic-gate 	exit_status = UU_EXIT_OK;
2344*7c478bd9Sstevel@tonic-gate 
2345*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
2346*7c478bd9Sstevel@tonic-gate 
2347*7c478bd9Sstevel@tonic-gate 	return (0);
2348*7c478bd9Sstevel@tonic-gate }
2349*7c478bd9Sstevel@tonic-gate 
2350*7c478bd9Sstevel@tonic-gate /*
2351*7c478bd9Sstevel@tonic-gate  * Dependency selection: Straightforward since each instance lists the
2352*7c478bd9Sstevel@tonic-gate  * services it depends on.
2353*7c478bd9Sstevel@tonic-gate  */
2354*7c478bd9Sstevel@tonic-gate 
2355*7c478bd9Sstevel@tonic-gate static void
2356*7c478bd9Sstevel@tonic-gate walk_dependencies(scf_walkinfo_t *wip, scf_walk_callback callback, void *data)
2357*7c478bd9Sstevel@tonic-gate {
2358*7c478bd9Sstevel@tonic-gate 	scf_snapshot_t *snap;
2359*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter, *viter;
2360*7c478bd9Sstevel@tonic-gate 	int ret, vret;
2361*7c478bd9Sstevel@tonic-gate 	char *dep;
2362*7c478bd9Sstevel@tonic-gate 
2363*7c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL);
2364*7c478bd9Sstevel@tonic-gate 
2365*7c478bd9Sstevel@tonic-gate 	if ((iter = scf_iter_create(h)) == NULL ||
2366*7c478bd9Sstevel@tonic-gate 	    (viter = scf_iter_create(h)) == NULL)
2367*7c478bd9Sstevel@tonic-gate 		scfdie();
2368*7c478bd9Sstevel@tonic-gate 
2369*7c478bd9Sstevel@tonic-gate 	snap = get_running_snapshot(wip->inst);
2370*7c478bd9Sstevel@tonic-gate 
2371*7c478bd9Sstevel@tonic-gate 	if (scf_iter_instance_pgs_typed_composed(iter, wip->inst, snap,
2372*7c478bd9Sstevel@tonic-gate 	    SCF_GROUP_DEPENDENCY) != SCF_SUCCESS)
2373*7c478bd9Sstevel@tonic-gate 		scfdie();
2374*7c478bd9Sstevel@tonic-gate 
2375*7c478bd9Sstevel@tonic-gate 	dep = safe_malloc(max_scf_value_length + 1);
2376*7c478bd9Sstevel@tonic-gate 
2377*7c478bd9Sstevel@tonic-gate 	while ((ret = scf_iter_next_pg(iter, g_pg)) == 1) {
2378*7c478bd9Sstevel@tonic-gate 		scf_type_t ty;
2379*7c478bd9Sstevel@tonic-gate 
2380*7c478bd9Sstevel@tonic-gate 		/* Ignore exclude_any dependencies. */
2381*7c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(g_pg, SCF_PROPERTY_GROUPING, g_prop) !=
2382*7c478bd9Sstevel@tonic-gate 		    SCF_SUCCESS) {
2383*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
2384*7c478bd9Sstevel@tonic-gate 				scfdie();
2385*7c478bd9Sstevel@tonic-gate 
2386*7c478bd9Sstevel@tonic-gate 			continue;
2387*7c478bd9Sstevel@tonic-gate 		}
2388*7c478bd9Sstevel@tonic-gate 
2389*7c478bd9Sstevel@tonic-gate 		if (scf_property_type(g_prop, &ty) != SCF_SUCCESS)
2390*7c478bd9Sstevel@tonic-gate 			scfdie();
2391*7c478bd9Sstevel@tonic-gate 
2392*7c478bd9Sstevel@tonic-gate 		if (ty != SCF_TYPE_ASTRING)
2393*7c478bd9Sstevel@tonic-gate 			continue;
2394*7c478bd9Sstevel@tonic-gate 
2395*7c478bd9Sstevel@tonic-gate 		if (scf_property_get_value(g_prop, g_val) != SCF_SUCCESS) {
2396*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
2397*7c478bd9Sstevel@tonic-gate 				scfdie();
2398*7c478bd9Sstevel@tonic-gate 
2399*7c478bd9Sstevel@tonic-gate 			continue;
2400*7c478bd9Sstevel@tonic-gate 		}
2401*7c478bd9Sstevel@tonic-gate 
2402*7c478bd9Sstevel@tonic-gate 		if (scf_value_get_astring(g_val, dep,
2403*7c478bd9Sstevel@tonic-gate 		    max_scf_value_length + 1) < 0)
2404*7c478bd9Sstevel@tonic-gate 			scfdie();
2405*7c478bd9Sstevel@tonic-gate 
2406*7c478bd9Sstevel@tonic-gate 		if (strcmp(dep, SCF_DEP_EXCLUDE_ALL) == 0)
2407*7c478bd9Sstevel@tonic-gate 			continue;
2408*7c478bd9Sstevel@tonic-gate 
2409*7c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(g_pg, SCF_PROPERTY_ENTITIES, g_prop) !=
2410*7c478bd9Sstevel@tonic-gate 		    SCF_SUCCESS) {
2411*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
2412*7c478bd9Sstevel@tonic-gate 				scfdie();
2413*7c478bd9Sstevel@tonic-gate 
2414*7c478bd9Sstevel@tonic-gate 			continue;
2415*7c478bd9Sstevel@tonic-gate 		}
2416*7c478bd9Sstevel@tonic-gate 
2417*7c478bd9Sstevel@tonic-gate 		if (scf_iter_property_values(viter, g_prop) != SCF_SUCCESS)
2418*7c478bd9Sstevel@tonic-gate 			scfdie();
2419*7c478bd9Sstevel@tonic-gate 
2420*7c478bd9Sstevel@tonic-gate 		while ((vret = scf_iter_next_value(viter, g_val)) == 1) {
2421*7c478bd9Sstevel@tonic-gate 			if (scf_value_get_astring(g_val, dep,
2422*7c478bd9Sstevel@tonic-gate 			    max_scf_value_length + 1) < 0)
2423*7c478bd9Sstevel@tonic-gate 				scfdie();
2424*7c478bd9Sstevel@tonic-gate 
2425*7c478bd9Sstevel@tonic-gate 			wip->fmri = dep;
2426*7c478bd9Sstevel@tonic-gate 			if (callback(data, wip) != 0)
2427*7c478bd9Sstevel@tonic-gate 				goto out;
2428*7c478bd9Sstevel@tonic-gate 		}
2429*7c478bd9Sstevel@tonic-gate 		if (vret == -1)
2430*7c478bd9Sstevel@tonic-gate 			scfdie();
2431*7c478bd9Sstevel@tonic-gate 	}
2432*7c478bd9Sstevel@tonic-gate 	if (ret == -1)
2433*7c478bd9Sstevel@tonic-gate 		scfdie();
2434*7c478bd9Sstevel@tonic-gate 
2435*7c478bd9Sstevel@tonic-gate out:
2436*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(viter);
2437*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
2438*7c478bd9Sstevel@tonic-gate 	scf_snapshot_destroy(snap);
2439*7c478bd9Sstevel@tonic-gate }
2440*7c478bd9Sstevel@tonic-gate 
2441*7c478bd9Sstevel@tonic-gate static int
2442*7c478bd9Sstevel@tonic-gate list_dependencies(void *data, scf_walkinfo_t *wip)
2443*7c478bd9Sstevel@tonic-gate {
2444*7c478bd9Sstevel@tonic-gate 	walk_dependencies(wip, list_svc_or_inst_fmri, data);
2445*7c478bd9Sstevel@tonic-gate 	return (0);
2446*7c478bd9Sstevel@tonic-gate }
2447*7c478bd9Sstevel@tonic-gate 
2448*7c478bd9Sstevel@tonic-gate 
2449*7c478bd9Sstevel@tonic-gate /*
2450*7c478bd9Sstevel@tonic-gate  * Dependent selection: The "providing" service's or instance's FMRI is parsed
2451*7c478bd9Sstevel@tonic-gate  * into the provider_* variables, the instances are walked, and any instance
2452*7c478bd9Sstevel@tonic-gate  * which lists an FMRI which parses to these components is selected.  This is
2453*7c478bd9Sstevel@tonic-gate  * inefficient in the face of multiple operands, but that should be uncommon.
2454*7c478bd9Sstevel@tonic-gate  */
2455*7c478bd9Sstevel@tonic-gate 
2456*7c478bd9Sstevel@tonic-gate static char *provider_scope;
2457*7c478bd9Sstevel@tonic-gate static char *provider_svc;
2458*7c478bd9Sstevel@tonic-gate static char *provider_inst;	/* NULL for services */
2459*7c478bd9Sstevel@tonic-gate 
2460*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2461*7c478bd9Sstevel@tonic-gate static int
2462*7c478bd9Sstevel@tonic-gate check_against_provider(void *arg, scf_walkinfo_t *wip)
2463*7c478bd9Sstevel@tonic-gate {
2464*7c478bd9Sstevel@tonic-gate 	char *cfmri;
2465*7c478bd9Sstevel@tonic-gate 	const char *scope_name, *svc_name, *inst_name, *pg_name;
2466*7c478bd9Sstevel@tonic-gate 	int *matchp = arg;
2467*7c478bd9Sstevel@tonic-gate 
2468*7c478bd9Sstevel@tonic-gate 	cfmri = safe_strdup(wip->fmri);
2469*7c478bd9Sstevel@tonic-gate 
2470*7c478bd9Sstevel@tonic-gate 	if (scf_parse_svc_fmri(cfmri, &scope_name, &svc_name, &inst_name,
2471*7c478bd9Sstevel@tonic-gate 	    &pg_name, NULL) != SCF_SUCCESS) {
2472*7c478bd9Sstevel@tonic-gate 		free(cfmri);
2473*7c478bd9Sstevel@tonic-gate 		return (0);
2474*7c478bd9Sstevel@tonic-gate 	}
2475*7c478bd9Sstevel@tonic-gate 
2476*7c478bd9Sstevel@tonic-gate 	if (svc_name == NULL || pg_name != NULL) {
2477*7c478bd9Sstevel@tonic-gate 		free(cfmri);
2478*7c478bd9Sstevel@tonic-gate 		return (0);
2479*7c478bd9Sstevel@tonic-gate 	}
2480*7c478bd9Sstevel@tonic-gate 
2481*7c478bd9Sstevel@tonic-gate 	/*
2482*7c478bd9Sstevel@tonic-gate 	 * If the user has specified an instance, then also match dependencies
2483*7c478bd9Sstevel@tonic-gate 	 * on the service itself.
2484*7c478bd9Sstevel@tonic-gate 	 */
2485*7c478bd9Sstevel@tonic-gate 	*matchp = (strcmp(provider_scope, scope_name) == 0 &&
2486*7c478bd9Sstevel@tonic-gate 	    strcmp(provider_svc, svc_name) == 0 &&
2487*7c478bd9Sstevel@tonic-gate 	    (provider_inst == NULL ? (inst_name == NULL) :
2488*7c478bd9Sstevel@tonic-gate 	    (inst_name == NULL || strcmp(provider_inst, inst_name) == 0)));
2489*7c478bd9Sstevel@tonic-gate 
2490*7c478bd9Sstevel@tonic-gate 	free(cfmri);
2491*7c478bd9Sstevel@tonic-gate 
2492*7c478bd9Sstevel@tonic-gate 	/* Stop on matches. */
2493*7c478bd9Sstevel@tonic-gate 	return (*matchp);
2494*7c478bd9Sstevel@tonic-gate }
2495*7c478bd9Sstevel@tonic-gate 
2496*7c478bd9Sstevel@tonic-gate static int
2497*7c478bd9Sstevel@tonic-gate list_if_dependent(void *unused, scf_walkinfo_t *wip)
2498*7c478bd9Sstevel@tonic-gate {
2499*7c478bd9Sstevel@tonic-gate 	/* Only proceed if this instance depends on provider_*. */
2500*7c478bd9Sstevel@tonic-gate 	int match = 0;
2501*7c478bd9Sstevel@tonic-gate 
2502*7c478bd9Sstevel@tonic-gate 	(void) walk_dependencies(wip, check_against_provider, &match);
2503*7c478bd9Sstevel@tonic-gate 
2504*7c478bd9Sstevel@tonic-gate 	if (match)
2505*7c478bd9Sstevel@tonic-gate 		return (list_instance(unused, wip));
2506*7c478bd9Sstevel@tonic-gate 
2507*7c478bd9Sstevel@tonic-gate 	return (0);
2508*7c478bd9Sstevel@tonic-gate }
2509*7c478bd9Sstevel@tonic-gate 
2510*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2511*7c478bd9Sstevel@tonic-gate static int
2512*7c478bd9Sstevel@tonic-gate list_dependents(void *unused, scf_walkinfo_t *wip)
2513*7c478bd9Sstevel@tonic-gate {
2514*7c478bd9Sstevel@tonic-gate 	char *save;
2515*7c478bd9Sstevel@tonic-gate 	int ret;
2516*7c478bd9Sstevel@tonic-gate 
2517*7c478bd9Sstevel@tonic-gate 	if (scf_scope_get_name(wip->scope, provider_scope,
2518*7c478bd9Sstevel@tonic-gate 	    max_scf_fmri_length) <= 0 ||
2519*7c478bd9Sstevel@tonic-gate 	    scf_service_get_name(wip->svc, provider_svc,
2520*7c478bd9Sstevel@tonic-gate 	    max_scf_fmri_length) <= 0)
2521*7c478bd9Sstevel@tonic-gate 		scfdie();
2522*7c478bd9Sstevel@tonic-gate 
2523*7c478bd9Sstevel@tonic-gate 	save = provider_inst;
2524*7c478bd9Sstevel@tonic-gate 	if (wip->inst == NULL)
2525*7c478bd9Sstevel@tonic-gate 		provider_inst = NULL;
2526*7c478bd9Sstevel@tonic-gate 	else if (scf_instance_get_name(wip->inst, provider_inst,
2527*7c478bd9Sstevel@tonic-gate 	    max_scf_fmri_length) <= 0)
2528*7c478bd9Sstevel@tonic-gate 		scfdie();
2529*7c478bd9Sstevel@tonic-gate 
2530*7c478bd9Sstevel@tonic-gate 	ret = scf_walk_fmri(h, 0, NULL, 0, list_if_dependent, NULL, NULL,
2531*7c478bd9Sstevel@tonic-gate 	    uu_warn);
2532*7c478bd9Sstevel@tonic-gate 
2533*7c478bd9Sstevel@tonic-gate 	provider_inst = save;
2534*7c478bd9Sstevel@tonic-gate 
2535*7c478bd9Sstevel@tonic-gate 	return (ret);
2536*7c478bd9Sstevel@tonic-gate }
2537*7c478bd9Sstevel@tonic-gate 
2538*7c478bd9Sstevel@tonic-gate /*
2539*7c478bd9Sstevel@tonic-gate  * main() & helpers
2540*7c478bd9Sstevel@tonic-gate  */
2541*7c478bd9Sstevel@tonic-gate 
2542*7c478bd9Sstevel@tonic-gate static void
2543*7c478bd9Sstevel@tonic-gate add_sort_column(const char *col, int reverse)
2544*7c478bd9Sstevel@tonic-gate {
2545*7c478bd9Sstevel@tonic-gate 	int i;
2546*7c478bd9Sstevel@tonic-gate 
2547*7c478bd9Sstevel@tonic-gate 	++opt_snum;
2548*7c478bd9Sstevel@tonic-gate 
2549*7c478bd9Sstevel@tonic-gate 	opt_sort = realloc(opt_sort, opt_snum * sizeof (*opt_sort));
2550*7c478bd9Sstevel@tonic-gate 	if (opt_sort == NULL)
2551*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("Too many sort criteria: out of memory.\n"));
2552*7c478bd9Sstevel@tonic-gate 
2553*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ncolumns; ++i) {
2554*7c478bd9Sstevel@tonic-gate 		if (strcasecmp(col, columns[i].name) == 0)
2555*7c478bd9Sstevel@tonic-gate 			break;
2556*7c478bd9Sstevel@tonic-gate 	}
2557*7c478bd9Sstevel@tonic-gate 
2558*7c478bd9Sstevel@tonic-gate 	if (i < ncolumns)
2559*7c478bd9Sstevel@tonic-gate 		opt_sort[opt_snum - 1] = (reverse ? i | 0x100 : i);
2560*7c478bd9Sstevel@tonic-gate 	else
2561*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("Unrecognized sort column \"%s\".\n"), col);
2562*7c478bd9Sstevel@tonic-gate 
2563*7c478bd9Sstevel@tonic-gate 	sortkey_sz += columns[i].sortkey_width;
2564*7c478bd9Sstevel@tonic-gate }
2565*7c478bd9Sstevel@tonic-gate 
2566*7c478bd9Sstevel@tonic-gate static void
2567*7c478bd9Sstevel@tonic-gate add_restarter(const char *fmri)
2568*7c478bd9Sstevel@tonic-gate {
2569*7c478bd9Sstevel@tonic-gate 	char *cfmri;
2570*7c478bd9Sstevel@tonic-gate 	const char *pg_name;
2571*7c478bd9Sstevel@tonic-gate 	struct pfmri_list *rest;
2572*7c478bd9Sstevel@tonic-gate 
2573*7c478bd9Sstevel@tonic-gate 	cfmri = safe_strdup(fmri);
2574*7c478bd9Sstevel@tonic-gate 	rest = safe_malloc(sizeof (*rest));
2575*7c478bd9Sstevel@tonic-gate 
2576*7c478bd9Sstevel@tonic-gate 	if (scf_parse_svc_fmri(cfmri, &rest->scope, &rest->service,
2577*7c478bd9Sstevel@tonic-gate 	    &rest->instance, &pg_name, NULL) != SCF_SUCCESS)
2578*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("Restarter FMRI \"%s\" is invalid.\n"), fmri);
2579*7c478bd9Sstevel@tonic-gate 
2580*7c478bd9Sstevel@tonic-gate 	if (rest->instance == NULL || pg_name != NULL)
2581*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("Restarter FMRI \"%s\" does not designate an "
2582*7c478bd9Sstevel@tonic-gate 		    "instance.\n"), fmri);
2583*7c478bd9Sstevel@tonic-gate 
2584*7c478bd9Sstevel@tonic-gate 	rest->next = restarters;
2585*7c478bd9Sstevel@tonic-gate 	restarters = rest;
2586*7c478bd9Sstevel@tonic-gate 	return;
2587*7c478bd9Sstevel@tonic-gate 
2588*7c478bd9Sstevel@tonic-gate err:
2589*7c478bd9Sstevel@tonic-gate 	free(cfmri);
2590*7c478bd9Sstevel@tonic-gate 	free(rest);
2591*7c478bd9Sstevel@tonic-gate }
2592*7c478bd9Sstevel@tonic-gate 
2593*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
2594*7c478bd9Sstevel@tonic-gate static int
2595*7c478bd9Sstevel@tonic-gate line_cmp(const void *l_arg, const void *r_arg, void *private)
2596*7c478bd9Sstevel@tonic-gate {
2597*7c478bd9Sstevel@tonic-gate 	const struct avl_string *l = l_arg;
2598*7c478bd9Sstevel@tonic-gate 	const struct avl_string *r = r_arg;
2599*7c478bd9Sstevel@tonic-gate 
2600*7c478bd9Sstevel@tonic-gate 	return (memcmp(l->key, r->key, sortkey_sz));
2601*7c478bd9Sstevel@tonic-gate }
2602*7c478bd9Sstevel@tonic-gate 
2603*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
2604*7c478bd9Sstevel@tonic-gate static int
2605*7c478bd9Sstevel@tonic-gate print_line(void *e, void *private)
2606*7c478bd9Sstevel@tonic-gate {
2607*7c478bd9Sstevel@tonic-gate 	struct avl_string *lp = e;
2608*7c478bd9Sstevel@tonic-gate 
2609*7c478bd9Sstevel@tonic-gate 	(void) puts(lp->str);
2610*7c478bd9Sstevel@tonic-gate 
2611*7c478bd9Sstevel@tonic-gate 	return (UU_WALK_NEXT);
2612*7c478bd9Sstevel@tonic-gate }
2613*7c478bd9Sstevel@tonic-gate 
2614*7c478bd9Sstevel@tonic-gate int
2615*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
2616*7c478bd9Sstevel@tonic-gate {
2617*7c478bd9Sstevel@tonic-gate 	char opt, opt_mode;
2618*7c478bd9Sstevel@tonic-gate 	int i, n;
2619*7c478bd9Sstevel@tonic-gate 	char *columns_str = NULL;
2620*7c478bd9Sstevel@tonic-gate 	char *cp;
2621*7c478bd9Sstevel@tonic-gate 	const char *progname;
2622*7c478bd9Sstevel@tonic-gate 	int err;
2623*7c478bd9Sstevel@tonic-gate 
2624*7c478bd9Sstevel@tonic-gate 	int show_all = 0;
2625*7c478bd9Sstevel@tonic-gate 	int show_header = 1;
2626*7c478bd9Sstevel@tonic-gate 
2627*7c478bd9Sstevel@tonic-gate 	const char * const options = "aHpvo:R:s:S:dDl?x";
2628*7c478bd9Sstevel@tonic-gate 
2629*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2630*7c478bd9Sstevel@tonic-gate 
2631*7c478bd9Sstevel@tonic-gate 	locale = setlocale(LC_MESSAGES, "");
2632*7c478bd9Sstevel@tonic-gate 	if (locale) {
2633*7c478bd9Sstevel@tonic-gate 		locale = safe_strdup(locale);
2634*7c478bd9Sstevel@tonic-gate 		sanitize_locale(locale);
2635*7c478bd9Sstevel@tonic-gate 	}
2636*7c478bd9Sstevel@tonic-gate 
2637*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2638*7c478bd9Sstevel@tonic-gate 	progname = uu_setpname(argv[0]);
2639*7c478bd9Sstevel@tonic-gate 
2640*7c478bd9Sstevel@tonic-gate 	exit_status = UU_EXIT_OK;
2641*7c478bd9Sstevel@tonic-gate 
2642*7c478bd9Sstevel@tonic-gate 	max_scf_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
2643*7c478bd9Sstevel@tonic-gate 	max_scf_value_length = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
2644*7c478bd9Sstevel@tonic-gate 	max_scf_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
2645*7c478bd9Sstevel@tonic-gate 
2646*7c478bd9Sstevel@tonic-gate 	if (max_scf_name_length == -1 || max_scf_value_length == -1 ||
2647*7c478bd9Sstevel@tonic-gate 	    max_scf_fmri_length == -1)
2648*7c478bd9Sstevel@tonic-gate 		scfdie();
2649*7c478bd9Sstevel@tonic-gate 
2650*7c478bd9Sstevel@tonic-gate 	now = time(NULL);
2651*7c478bd9Sstevel@tonic-gate 	assert(now != -1);
2652*7c478bd9Sstevel@tonic-gate 
2653*7c478bd9Sstevel@tonic-gate 	/*
2654*7c478bd9Sstevel@tonic-gate 	 * opt_mode is the mode of operation.  0 for plain, 'd' for
2655*7c478bd9Sstevel@tonic-gate 	 * dependencies, 'D' for dependents, and 'l' for detailed (long).  We
2656*7c478bd9Sstevel@tonic-gate 	 * need to know now so we know which options are valid.
2657*7c478bd9Sstevel@tonic-gate 	 */
2658*7c478bd9Sstevel@tonic-gate 	opt_mode = 0;
2659*7c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, options)) != -1) {
2660*7c478bd9Sstevel@tonic-gate 		switch (opt) {
2661*7c478bd9Sstevel@tonic-gate 		case '?':
2662*7c478bd9Sstevel@tonic-gate 			if (optopt == '?') {
2663*7c478bd9Sstevel@tonic-gate 				print_help(progname);
2664*7c478bd9Sstevel@tonic-gate 				return (UU_EXIT_OK);
2665*7c478bd9Sstevel@tonic-gate 			} else {
2666*7c478bd9Sstevel@tonic-gate 				argserr(progname);
2667*7c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
2668*7c478bd9Sstevel@tonic-gate 			}
2669*7c478bd9Sstevel@tonic-gate 
2670*7c478bd9Sstevel@tonic-gate 		case 'd':
2671*7c478bd9Sstevel@tonic-gate 		case 'D':
2672*7c478bd9Sstevel@tonic-gate 		case 'l':
2673*7c478bd9Sstevel@tonic-gate 			if (opt_mode != 0)
2674*7c478bd9Sstevel@tonic-gate 				argserr(progname);
2675*7c478bd9Sstevel@tonic-gate 
2676*7c478bd9Sstevel@tonic-gate 			opt_mode = opt;
2677*7c478bd9Sstevel@tonic-gate 			break;
2678*7c478bd9Sstevel@tonic-gate 
2679*7c478bd9Sstevel@tonic-gate 		case 'x':
2680*7c478bd9Sstevel@tonic-gate 			if (opt_mode != 0)
2681*7c478bd9Sstevel@tonic-gate 				argserr(progname);
2682*7c478bd9Sstevel@tonic-gate 
2683*7c478bd9Sstevel@tonic-gate 			opt_mode = opt;
2684*7c478bd9Sstevel@tonic-gate 			break;
2685*7c478bd9Sstevel@tonic-gate 
2686*7c478bd9Sstevel@tonic-gate 		default:
2687*7c478bd9Sstevel@tonic-gate 			break;
2688*7c478bd9Sstevel@tonic-gate 		}
2689*7c478bd9Sstevel@tonic-gate 	}
2690*7c478bd9Sstevel@tonic-gate 
2691*7c478bd9Sstevel@tonic-gate 	sortkey_sz = 0;
2692*7c478bd9Sstevel@tonic-gate 
2693*7c478bd9Sstevel@tonic-gate 	optind = 1;	/* Reset getopt() */
2694*7c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, options)) != -1) {
2695*7c478bd9Sstevel@tonic-gate 		switch (opt) {
2696*7c478bd9Sstevel@tonic-gate 		case 'a':
2697*7c478bd9Sstevel@tonic-gate 			if (opt_mode != 0)
2698*7c478bd9Sstevel@tonic-gate 				argserr(progname);
2699*7c478bd9Sstevel@tonic-gate 			show_all = 1;
2700*7c478bd9Sstevel@tonic-gate 			break;
2701*7c478bd9Sstevel@tonic-gate 
2702*7c478bd9Sstevel@tonic-gate 		case 'H':
2703*7c478bd9Sstevel@tonic-gate 			if (opt_mode == 'l' || opt_mode == 'x')
2704*7c478bd9Sstevel@tonic-gate 				argserr(progname);
2705*7c478bd9Sstevel@tonic-gate 			show_header = 0;
2706*7c478bd9Sstevel@tonic-gate 			break;
2707*7c478bd9Sstevel@tonic-gate 
2708*7c478bd9Sstevel@tonic-gate 		case 'p':
2709*7c478bd9Sstevel@tonic-gate 			if (opt_mode == 'x')
2710*7c478bd9Sstevel@tonic-gate 				argserr(progname);
2711*7c478bd9Sstevel@tonic-gate 			opt_processes = 1;
2712*7c478bd9Sstevel@tonic-gate 			break;
2713*7c478bd9Sstevel@tonic-gate 
2714*7c478bd9Sstevel@tonic-gate 		case 'v':
2715*7c478bd9Sstevel@tonic-gate 			if (opt_mode == 'l')
2716*7c478bd9Sstevel@tonic-gate 				argserr(progname);
2717*7c478bd9Sstevel@tonic-gate 			opt_verbose = 1;
2718*7c478bd9Sstevel@tonic-gate 			break;
2719*7c478bd9Sstevel@tonic-gate 
2720*7c478bd9Sstevel@tonic-gate 		case 'o':
2721*7c478bd9Sstevel@tonic-gate 			if (opt_mode == 'l' || opt_mode == 'x')
2722*7c478bd9Sstevel@tonic-gate 				argserr(progname);
2723*7c478bd9Sstevel@tonic-gate 			columns_str = optarg;
2724*7c478bd9Sstevel@tonic-gate 			break;
2725*7c478bd9Sstevel@tonic-gate 
2726*7c478bd9Sstevel@tonic-gate 		case 'R':
2727*7c478bd9Sstevel@tonic-gate 			if (opt_mode != 0 || opt_mode == 'x')
2728*7c478bd9Sstevel@tonic-gate 				argserr(progname);
2729*7c478bd9Sstevel@tonic-gate 
2730*7c478bd9Sstevel@tonic-gate 			add_restarter(optarg);
2731*7c478bd9Sstevel@tonic-gate 			break;
2732*7c478bd9Sstevel@tonic-gate 
2733*7c478bd9Sstevel@tonic-gate 		case 's':
2734*7c478bd9Sstevel@tonic-gate 		case 'S':
2735*7c478bd9Sstevel@tonic-gate 			if (opt_mode != 0)
2736*7c478bd9Sstevel@tonic-gate 				argserr(progname);
2737*7c478bd9Sstevel@tonic-gate 
2738*7c478bd9Sstevel@tonic-gate 			add_sort_column(optarg, optopt == 'S');
2739*7c478bd9Sstevel@tonic-gate 			break;
2740*7c478bd9Sstevel@tonic-gate 
2741*7c478bd9Sstevel@tonic-gate 		case 'd':
2742*7c478bd9Sstevel@tonic-gate 		case 'D':
2743*7c478bd9Sstevel@tonic-gate 		case 'l':
2744*7c478bd9Sstevel@tonic-gate 		case 'x':
2745*7c478bd9Sstevel@tonic-gate 			assert(opt_mode == optopt);
2746*7c478bd9Sstevel@tonic-gate 			break;
2747*7c478bd9Sstevel@tonic-gate 
2748*7c478bd9Sstevel@tonic-gate 		case '?':
2749*7c478bd9Sstevel@tonic-gate 			argserr(progname);
2750*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
2751*7c478bd9Sstevel@tonic-gate 
2752*7c478bd9Sstevel@tonic-gate 		default:
2753*7c478bd9Sstevel@tonic-gate 			assert(0);
2754*7c478bd9Sstevel@tonic-gate 			abort();
2755*7c478bd9Sstevel@tonic-gate 		}
2756*7c478bd9Sstevel@tonic-gate 	}
2757*7c478bd9Sstevel@tonic-gate 
2758*7c478bd9Sstevel@tonic-gate 	/*
2759*7c478bd9Sstevel@tonic-gate 	 * -a is only meaningful when given no arguments
2760*7c478bd9Sstevel@tonic-gate 	 */
2761*7c478bd9Sstevel@tonic-gate 	if (show_all && optind != argc)
2762*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext("-a ignored when used with arguments.\n"));
2763*7c478bd9Sstevel@tonic-gate 
2764*7c478bd9Sstevel@tonic-gate 	h = scf_handle_create(SCF_VERSION);
2765*7c478bd9Sstevel@tonic-gate 	if (h == NULL)
2766*7c478bd9Sstevel@tonic-gate 		scfdie();
2767*7c478bd9Sstevel@tonic-gate 
2768*7c478bd9Sstevel@tonic-gate 	if (scf_handle_bind(h) == -1)
2769*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("Could not bind to repository server: %s.  "
2770*7c478bd9Sstevel@tonic-gate 		    "Exiting.\n"), scf_strerror(scf_error()));
2771*7c478bd9Sstevel@tonic-gate 
2772*7c478bd9Sstevel@tonic-gate 	if ((g_pg = scf_pg_create(h)) == NULL ||
2773*7c478bd9Sstevel@tonic-gate 	    (g_prop = scf_property_create(h)) == NULL ||
2774*7c478bd9Sstevel@tonic-gate 	    (g_val = scf_value_create(h)) == NULL)
2775*7c478bd9Sstevel@tonic-gate 		scfdie();
2776*7c478bd9Sstevel@tonic-gate 
2777*7c478bd9Sstevel@tonic-gate 	argc -= optind;
2778*7c478bd9Sstevel@tonic-gate 	argv += optind;
2779*7c478bd9Sstevel@tonic-gate 
2780*7c478bd9Sstevel@tonic-gate 	/*
2781*7c478bd9Sstevel@tonic-gate 	 * If we're in long mode, take care of it now before we deal with the
2782*7c478bd9Sstevel@tonic-gate 	 * sorting and the columns, since we won't use them anyway.
2783*7c478bd9Sstevel@tonic-gate 	 */
2784*7c478bd9Sstevel@tonic-gate 	if (opt_mode == 'l') {
2785*7c478bd9Sstevel@tonic-gate 		if (argc == 0)
2786*7c478bd9Sstevel@tonic-gate 			argserr(progname);
2787*7c478bd9Sstevel@tonic-gate 
2788*7c478bd9Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc, argv, SCF_WALK_MULTIPLE,
2789*7c478bd9Sstevel@tonic-gate 		    print_detailed, NULL, &exit_status, uu_warn)) != 0) {
2790*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
2791*7c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
2792*7c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
2793*7c478bd9Sstevel@tonic-gate 		}
2794*7c478bd9Sstevel@tonic-gate 
2795*7c478bd9Sstevel@tonic-gate 		return (exit_status);
2796*7c478bd9Sstevel@tonic-gate 	}
2797*7c478bd9Sstevel@tonic-gate 
2798*7c478bd9Sstevel@tonic-gate 	if (opt_mode == 'x') {
2799*7c478bd9Sstevel@tonic-gate 		explain(opt_verbose, argc, argv);
2800*7c478bd9Sstevel@tonic-gate 
2801*7c478bd9Sstevel@tonic-gate 		return (exit_status);
2802*7c478bd9Sstevel@tonic-gate 	}
2803*7c478bd9Sstevel@tonic-gate 
2804*7c478bd9Sstevel@tonic-gate 
2805*7c478bd9Sstevel@tonic-gate 	if (opt_snum == 0) {
2806*7c478bd9Sstevel@tonic-gate 		/* Default sort. */
2807*7c478bd9Sstevel@tonic-gate 		add_sort_column("state", 0);
2808*7c478bd9Sstevel@tonic-gate 		add_sort_column("stime", 0);
2809*7c478bd9Sstevel@tonic-gate 		add_sort_column("fmri", 0);
2810*7c478bd9Sstevel@tonic-gate 	}
2811*7c478bd9Sstevel@tonic-gate 
2812*7c478bd9Sstevel@tonic-gate 	if (columns_str == NULL) {
2813*7c478bd9Sstevel@tonic-gate 		if (!opt_verbose)
2814*7c478bd9Sstevel@tonic-gate 			columns_str = safe_strdup("state,stime,fmri");
2815*7c478bd9Sstevel@tonic-gate 		else
2816*7c478bd9Sstevel@tonic-gate 			columns_str =
2817*7c478bd9Sstevel@tonic-gate 			    safe_strdup("state,nstate,stime,ctid,fmri");
2818*7c478bd9Sstevel@tonic-gate 	}
2819*7c478bd9Sstevel@tonic-gate 
2820*7c478bd9Sstevel@tonic-gate 	/* Decode columns_str into opt_columns. */
2821*7c478bd9Sstevel@tonic-gate 	line_sz = 0;
2822*7c478bd9Sstevel@tonic-gate 
2823*7c478bd9Sstevel@tonic-gate 	opt_cnum = 1;
2824*7c478bd9Sstevel@tonic-gate 	for (cp = columns_str; *cp != '\0'; ++cp)
2825*7c478bd9Sstevel@tonic-gate 		if (*cp == ',')
2826*7c478bd9Sstevel@tonic-gate 			++opt_cnum;
2827*7c478bd9Sstevel@tonic-gate 
2828*7c478bd9Sstevel@tonic-gate 	opt_columns = malloc(opt_cnum * sizeof (*opt_columns));
2829*7c478bd9Sstevel@tonic-gate 	if (opt_columns == NULL)
2830*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("Too many columns.\n"));
2831*7c478bd9Sstevel@tonic-gate 
2832*7c478bd9Sstevel@tonic-gate 	for (n = 0; *columns_str != '\0'; ++n) {
2833*7c478bd9Sstevel@tonic-gate 		i = getcolumnopt(&columns_str);
2834*7c478bd9Sstevel@tonic-gate 		if (i == -1)
2835*7c478bd9Sstevel@tonic-gate 			uu_die(gettext("Unknown column \"%s\".\n"),
2836*7c478bd9Sstevel@tonic-gate 			    columns_str);
2837*7c478bd9Sstevel@tonic-gate 
2838*7c478bd9Sstevel@tonic-gate 		if (strcmp(columns[i].name, "N") == 0 ||
2839*7c478bd9Sstevel@tonic-gate 		    strcmp(columns[i].name, "SN") == 0 ||
2840*7c478bd9Sstevel@tonic-gate 		    strcmp(columns[i].name, "NSTA") == 0 ||
2841*7c478bd9Sstevel@tonic-gate 		    strcmp(columns[i].name, "NSTATE") == 0)
2842*7c478bd9Sstevel@tonic-gate 			opt_nstate_shown = 1;
2843*7c478bd9Sstevel@tonic-gate 
2844*7c478bd9Sstevel@tonic-gate 		opt_columns[n] = i;
2845*7c478bd9Sstevel@tonic-gate 		line_sz += columns[i].width + 1;
2846*7c478bd9Sstevel@tonic-gate 	}
2847*7c478bd9Sstevel@tonic-gate 
2848*7c478bd9Sstevel@tonic-gate 
2849*7c478bd9Sstevel@tonic-gate 	if ((lines_pool = uu_avl_pool_create("lines_pool",
2850*7c478bd9Sstevel@tonic-gate 	    sizeof (struct avl_string), offsetof(struct avl_string, node),
2851*7c478bd9Sstevel@tonic-gate 	    line_cmp, UU_AVL_DEBUG)) == NULL ||
2852*7c478bd9Sstevel@tonic-gate 	    (lines = uu_avl_create(lines_pool, NULL, 0)) == NULL)
2853*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("Unexpected libuutil error: %s.  Exiting.\n"),
2854*7c478bd9Sstevel@tonic-gate 		    uu_strerror(uu_error()));
2855*7c478bd9Sstevel@tonic-gate 
2856*7c478bd9Sstevel@tonic-gate 	switch (opt_mode) {
2857*7c478bd9Sstevel@tonic-gate 	case 0:
2858*7c478bd9Sstevel@tonic-gate 		ht_init();
2859*7c478bd9Sstevel@tonic-gate 
2860*7c478bd9Sstevel@tonic-gate 		/* Always show all FMRIs when given arguments or restarters */
2861*7c478bd9Sstevel@tonic-gate 		if (argc != 0 || restarters != NULL)
2862*7c478bd9Sstevel@tonic-gate 			show_all =  1;
2863*7c478bd9Sstevel@tonic-gate 
2864*7c478bd9Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc, argv,
2865*7c478bd9Sstevel@tonic-gate 		    SCF_WALK_MULTIPLE | SCF_WALK_LEGACY,
2866*7c478bd9Sstevel@tonic-gate 		    show_all ? list_instance : list_if_enabled, NULL,
2867*7c478bd9Sstevel@tonic-gate 		    &exit_status, uu_warn)) != 0) {
2868*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
2869*7c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
2870*7c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
2871*7c478bd9Sstevel@tonic-gate 		}
2872*7c478bd9Sstevel@tonic-gate 		break;
2873*7c478bd9Sstevel@tonic-gate 
2874*7c478bd9Sstevel@tonic-gate 	case 'd':
2875*7c478bd9Sstevel@tonic-gate 		if (argc == 0)
2876*7c478bd9Sstevel@tonic-gate 			argserr(progname);
2877*7c478bd9Sstevel@tonic-gate 
2878*7c478bd9Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc, argv,
2879*7c478bd9Sstevel@tonic-gate 		    SCF_WALK_MULTIPLE, list_dependencies, NULL,
2880*7c478bd9Sstevel@tonic-gate 		    &exit_status, uu_warn)) != 0) {
2881*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
2882*7c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
2883*7c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
2884*7c478bd9Sstevel@tonic-gate 		}
2885*7c478bd9Sstevel@tonic-gate 		break;
2886*7c478bd9Sstevel@tonic-gate 
2887*7c478bd9Sstevel@tonic-gate 	case 'D':
2888*7c478bd9Sstevel@tonic-gate 		if (argc == 0)
2889*7c478bd9Sstevel@tonic-gate 			argserr(progname);
2890*7c478bd9Sstevel@tonic-gate 
2891*7c478bd9Sstevel@tonic-gate 		provider_scope = safe_malloc(max_scf_fmri_length);
2892*7c478bd9Sstevel@tonic-gate 		provider_svc = safe_malloc(max_scf_fmri_length);
2893*7c478bd9Sstevel@tonic-gate 		provider_inst = safe_malloc(max_scf_fmri_length);
2894*7c478bd9Sstevel@tonic-gate 
2895*7c478bd9Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc, argv,
2896*7c478bd9Sstevel@tonic-gate 		    SCF_WALK_MULTIPLE | SCF_WALK_SERVICE,
2897*7c478bd9Sstevel@tonic-gate 		    list_dependents, NULL, &exit_status, uu_warn)) != 0) {
2898*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
2899*7c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
2900*7c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
2901*7c478bd9Sstevel@tonic-gate 		}
2902*7c478bd9Sstevel@tonic-gate 
2903*7c478bd9Sstevel@tonic-gate 		free(provider_scope);
2904*7c478bd9Sstevel@tonic-gate 		free(provider_svc);
2905*7c478bd9Sstevel@tonic-gate 		free(provider_inst);
2906*7c478bd9Sstevel@tonic-gate 		break;
2907*7c478bd9Sstevel@tonic-gate 
2908*7c478bd9Sstevel@tonic-gate 	default:
2909*7c478bd9Sstevel@tonic-gate 		assert(0);
2910*7c478bd9Sstevel@tonic-gate 		abort();
2911*7c478bd9Sstevel@tonic-gate 	}
2912*7c478bd9Sstevel@tonic-gate 
2913*7c478bd9Sstevel@tonic-gate 	if (show_header)
2914*7c478bd9Sstevel@tonic-gate 		print_header();
2915*7c478bd9Sstevel@tonic-gate 
2916*7c478bd9Sstevel@tonic-gate 	(void) uu_avl_walk(lines, print_line, NULL, 0);
2917*7c478bd9Sstevel@tonic-gate 
2918*7c478bd9Sstevel@tonic-gate 	return (exit_status);
2919*7c478bd9Sstevel@tonic-gate }
2920