xref: /onnv-gate/usr/src/cmd/svc/svcprop/svcprop.c (revision 5040:ff6ebd8761a6)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*5040Swesolows  * Common Development and Distribution License (the "License").
6*5040Swesolows  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*5040Swesolows 
220Sstevel@tonic-gate /*
23*5040Swesolows  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * svcprop - report service configuration properties
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <locale.h>
340Sstevel@tonic-gate #include <libintl.h>
350Sstevel@tonic-gate #include <libscf.h>
360Sstevel@tonic-gate #include <libscf_priv.h>
370Sstevel@tonic-gate #include <libuutil.h>
380Sstevel@tonic-gate #include <stddef.h>
390Sstevel@tonic-gate #include <stdio.h>
400Sstevel@tonic-gate #include <stdlib.h>
410Sstevel@tonic-gate #include <unistd.h>
420Sstevel@tonic-gate #include <strings.h>
430Sstevel@tonic-gate #include <assert.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #ifndef TEXT_DOMAIN
460Sstevel@tonic-gate #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
470Sstevel@tonic-gate #endif /* TEXT_DOMAIN */
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * Error functions.  These can change if the quiet (-q) option is used.
510Sstevel@tonic-gate  */
520Sstevel@tonic-gate static void (*warn)(const char *, ...) = uu_warn;
530Sstevel@tonic-gate static void (*die)(const char *, ...) = uu_die;
540Sstevel@tonic-gate 
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate  * Entity encapsulation.  This allows me to treat services and instances
570Sstevel@tonic-gate  * similarly, and avoid duplicating process_ent().
580Sstevel@tonic-gate  */
590Sstevel@tonic-gate typedef struct {
600Sstevel@tonic-gate 	char type;			/* !=0: service, 0: instance */
610Sstevel@tonic-gate 	union {
620Sstevel@tonic-gate 		scf_service_t *svc;
630Sstevel@tonic-gate 		scf_instance_t *inst;
640Sstevel@tonic-gate 	} u;
650Sstevel@tonic-gate } scf_entityp_t;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate #define	ENT_INSTANCE	0
680Sstevel@tonic-gate 
690Sstevel@tonic-gate #define	SCF_ENTITY_SET_TO_SERVICE(ent, s)	{ ent.type = 1; ent.u.svc = s; }
700Sstevel@tonic-gate 
710Sstevel@tonic-gate #define	SCF_ENTITY_SET_TO_INSTANCE(ent, i)	\
720Sstevel@tonic-gate 	{ ent.type = ENT_INSTANCE; ent.u.inst = i; }
730Sstevel@tonic-gate 
740Sstevel@tonic-gate #define	scf_entity_get_pg(ent, name, pg) \
750Sstevel@tonic-gate 	(ent.type ? scf_service_get_pg(ent.u.svc, name, pg) : \
760Sstevel@tonic-gate 	scf_instance_get_pg(ent.u.inst, name, pg))
770Sstevel@tonic-gate 
780Sstevel@tonic-gate #define	scf_entity_to_fmri(ent, buf, buf_sz) \
790Sstevel@tonic-gate 	(ent.type ? scf_service_to_fmri(ent.u.svc, buf, buf_sz) : \
800Sstevel@tonic-gate 	scf_instance_to_fmri(ent.u.inst, buf, buf_sz))
810Sstevel@tonic-gate 
820Sstevel@tonic-gate #define	SCF_ENTITY_TYPE_NAME(ent)	(ent.type ? "service" : "instance")
830Sstevel@tonic-gate 
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate  * Data structure for -p arguments.  Since they may be name or name/name, we
860Sstevel@tonic-gate  * just track the components.
870Sstevel@tonic-gate  */
880Sstevel@tonic-gate typedef struct svcprop_prop_node {
890Sstevel@tonic-gate 	uu_list_node_t	spn_list_node;
900Sstevel@tonic-gate 	const char	*spn_comp1;
910Sstevel@tonic-gate 	const char	*spn_comp2;
920Sstevel@tonic-gate } svcprop_prop_node_t;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate static uu_list_pool_t	*prop_pool;
950Sstevel@tonic-gate static uu_list_t	*prop_list;
960Sstevel@tonic-gate 
970Sstevel@tonic-gate static scf_handle_t *hndl;
980Sstevel@tonic-gate static ssize_t max_scf_name_length;
990Sstevel@tonic-gate static ssize_t max_scf_value_length;
1000Sstevel@tonic-gate static ssize_t max_scf_fmri_length;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate /* Options */
1030Sstevel@tonic-gate static int quiet = 0;			/* No output. Nothing found, exit(1) */
1040Sstevel@tonic-gate static int types = 0;			/* Display types of properties. */
1050Sstevel@tonic-gate static int verbose = 0;			/* Print not found errors to stderr. */
1060Sstevel@tonic-gate static int fmris = 0;			/* Display full FMRIs for properties. */
1070Sstevel@tonic-gate static int wait = 0;			/* Wait mode. */
1080Sstevel@tonic-gate static char *snapshot = "running";	/* Snapshot to use. */
1090Sstevel@tonic-gate static int Cflag = 0;			/* C option supplied */
1100Sstevel@tonic-gate static int cflag = 0;			/* c option supplied */
1110Sstevel@tonic-gate static int sflag = 0;			/* s option supplied */
1120Sstevel@tonic-gate static int return_code;			/* main's return code */
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate #define	PRINT_NOPROP_ERRORS	(!quiet || verbose)
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate /*
1170Sstevel@tonic-gate  * For unexpected libscf errors.  The ending newline is necessary to keep
1180Sstevel@tonic-gate  * uu_die() from appending the errno error.
1190Sstevel@tonic-gate  */
1200Sstevel@tonic-gate static void
scfdie()1210Sstevel@tonic-gate scfdie()
1220Sstevel@tonic-gate {
1230Sstevel@tonic-gate 	die(gettext("Unexpected libscf error: %s.  Exiting.\n"),
1240Sstevel@tonic-gate 	    scf_strerror(scf_error()));
1250Sstevel@tonic-gate }
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate static void *
safe_malloc(size_t sz)1280Sstevel@tonic-gate safe_malloc(size_t sz)
1290Sstevel@tonic-gate {
1300Sstevel@tonic-gate 	void *p;
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 	p = malloc(sz);
1330Sstevel@tonic-gate 	if (p == NULL)
1340Sstevel@tonic-gate 		die(gettext("Could not allocate memory"));
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	return (p);
1370Sstevel@tonic-gate }
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate static void
usage()1400Sstevel@tonic-gate usage()
1410Sstevel@tonic-gate {
1420Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Usage: %1$s [-fqtv] "
1430Sstevel@tonic-gate 	    "[-C | -c | -s snapshot] "
1440Sstevel@tonic-gate 	    "[-p [name/]name]... \n"
1450Sstevel@tonic-gate 	    "         {FMRI | pattern}...\n"
1460Sstevel@tonic-gate 	    "       %1$s -w [-fqtv] [-p [name/]name] "
1470Sstevel@tonic-gate 	    "{FMRI | pattern}\n"), uu_getpname());
1480Sstevel@tonic-gate 	exit(UU_EXIT_USAGE);
1490Sstevel@tonic-gate }
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate /*
1520Sstevel@tonic-gate  * Return an allocated copy of str, with the Bourne shell's metacharacters
1530Sstevel@tonic-gate  * escaped by '\'.
1540Sstevel@tonic-gate  *
1550Sstevel@tonic-gate  * What about unicode?
1560Sstevel@tonic-gate  */
1570Sstevel@tonic-gate static char *
quote_for_shell(const char * str)1580Sstevel@tonic-gate quote_for_shell(const char *str)
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate 	const char *sp;
1610Sstevel@tonic-gate 	char *dst, *dp;
1620Sstevel@tonic-gate 	size_t dst_len;
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	const char * const metachars = ";&()|^<>\n \t\\\"\'`";
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	if (str[0] == '\0')
1670Sstevel@tonic-gate 		return (strdup("\"\""));
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	dst_len = 0;
1700Sstevel@tonic-gate 	for (sp = str; *sp != '\0'; ++sp) {
1710Sstevel@tonic-gate 		++dst_len;
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 		if (strchr(metachars, *sp) != NULL)
1740Sstevel@tonic-gate 			++dst_len;
1750Sstevel@tonic-gate 	}
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	if (sp - str == dst_len)
1780Sstevel@tonic-gate 		return (strdup(str));
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	dst = safe_malloc(dst_len + 1);
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	for (dp = dst, sp = str; *sp != '\0'; ++dp, ++sp) {
1830Sstevel@tonic-gate 		if (strchr(metachars, *sp) != NULL)
1840Sstevel@tonic-gate 			*dp++ = '\\';
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 		*dp = *sp;
1870Sstevel@tonic-gate 	}
1880Sstevel@tonic-gate 	*dp = '\0';
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	return (dst);
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate static void
print_value(scf_value_t * val)1940Sstevel@tonic-gate print_value(scf_value_t *val)
1950Sstevel@tonic-gate {
1960Sstevel@tonic-gate 	char *buf, *qbuf;
1970Sstevel@tonic-gate 	ssize_t bufsz, r;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	bufsz = scf_value_get_as_string(val, NULL, 0) + 1;
2000Sstevel@tonic-gate 	if (bufsz - 1 < 0)
2010Sstevel@tonic-gate 		scfdie();
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	buf = safe_malloc(bufsz);
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	r = scf_value_get_as_string(val, buf, bufsz);
2060Sstevel@tonic-gate 	assert(r + 1 == bufsz);
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	qbuf = quote_for_shell(buf);
2090Sstevel@tonic-gate 	(void) fputs(qbuf, stdout);
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	free(qbuf);
2120Sstevel@tonic-gate 	free(buf);
2130Sstevel@tonic-gate }
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate /*
2160Sstevel@tonic-gate  * Display a property's values on a line.  If types is true, prepend
2170Sstevel@tonic-gate  * identification (the FMRI if fmris is true, pg/prop otherwise) and the type
2180Sstevel@tonic-gate  * of the property.
2190Sstevel@tonic-gate  */
2200Sstevel@tonic-gate static void
display_prop(scf_propertygroup_t * pg,scf_property_t * prop)2210Sstevel@tonic-gate display_prop(scf_propertygroup_t *pg, scf_property_t *prop)
2220Sstevel@tonic-gate {
2230Sstevel@tonic-gate 	scf_value_t *val;
2240Sstevel@tonic-gate 	scf_iter_t *iter;
225*5040Swesolows 	int ret, first, err;
226*5040Swesolows 
227*5040Swesolows 	const char * const permission_denied_emsg =
228*5040Swesolows 	    gettext("Permission denied.\n");
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	if (types) {
2310Sstevel@tonic-gate 		scf_type_t ty;
2320Sstevel@tonic-gate 		char *buf;
2330Sstevel@tonic-gate 		size_t buf_sz;
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 		if (fmris) {
2360Sstevel@tonic-gate 			buf_sz = max_scf_fmri_length + 1;
2370Sstevel@tonic-gate 			buf = safe_malloc(buf_sz);
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 			if (scf_property_to_fmri(prop, buf, buf_sz) == -1)
2400Sstevel@tonic-gate 				scfdie();
2410Sstevel@tonic-gate 			(void) fputs(buf, stdout);
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 			free(buf);
2440Sstevel@tonic-gate 		} else {
2450Sstevel@tonic-gate 			buf_sz = max_scf_name_length + 1;
2460Sstevel@tonic-gate 			buf = safe_malloc(buf_sz);
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 			if (scf_pg_get_name(pg, buf, buf_sz) < 0)
2490Sstevel@tonic-gate 				scfdie();
2500Sstevel@tonic-gate 			(void) fputs(buf, stdout);
2510Sstevel@tonic-gate 			(void) putchar('/');
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 			if (scf_property_get_name(prop, buf, buf_sz) < 0)
2540Sstevel@tonic-gate 				scfdie();
2550Sstevel@tonic-gate 			(void) fputs(buf, stdout);
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 			free(buf);
2580Sstevel@tonic-gate 		}
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 		(void) putchar(' ');
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 		if (scf_property_type(prop, &ty) == -1)
2630Sstevel@tonic-gate 			scfdie();
2640Sstevel@tonic-gate 		(void) fputs(scf_type_to_string(ty), stdout);
2650Sstevel@tonic-gate 		(void) putchar(' ');
2660Sstevel@tonic-gate 	}
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	if ((iter = scf_iter_create(hndl)) == NULL ||
2690Sstevel@tonic-gate 	    (val = scf_value_create(hndl)) == NULL)
2700Sstevel@tonic-gate 		scfdie();
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	if (scf_iter_property_values(iter, prop) == -1)
2730Sstevel@tonic-gate 		scfdie();
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	first = 1;
2760Sstevel@tonic-gate 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
2770Sstevel@tonic-gate 		if (first)
2780Sstevel@tonic-gate 			first = 0;
2790Sstevel@tonic-gate 		else
2800Sstevel@tonic-gate 			(void) putchar(' ');
2810Sstevel@tonic-gate 		print_value(val);
2820Sstevel@tonic-gate 	}
283*5040Swesolows 	if (ret == -1) {
284*5040Swesolows 		err = scf_error();
285*5040Swesolows 		if (err == SCF_ERROR_PERMISSION_DENIED) {
286*5040Swesolows 			if (uu_list_numnodes(prop_list) > 0)
287*5040Swesolows 				die(permission_denied_emsg);
288*5040Swesolows 		} else {
289*5040Swesolows 			scfdie();
290*5040Swesolows 		}
291*5040Swesolows 	}
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	(void) putchar('\n');
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	scf_iter_destroy(iter);
2960Sstevel@tonic-gate 	(void) scf_value_destroy(val);
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate /*
3000Sstevel@tonic-gate  * display_prop() all of the properties in the given property group.  Force
3010Sstevel@tonic-gate  * types to true so identification will be displayed.
3020Sstevel@tonic-gate  */
3030Sstevel@tonic-gate static void
display_pg(scf_propertygroup_t * pg)3040Sstevel@tonic-gate display_pg(scf_propertygroup_t *pg)
3050Sstevel@tonic-gate {
3060Sstevel@tonic-gate 	scf_property_t *prop;
3070Sstevel@tonic-gate 	scf_iter_t *iter;
3080Sstevel@tonic-gate 	int ret;
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	types = 1;	/* Always display types for whole propertygroups. */
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	if ((prop = scf_property_create(hndl)) == NULL ||
3130Sstevel@tonic-gate 	    (iter = scf_iter_create(hndl)) == NULL)
3140Sstevel@tonic-gate 		scfdie();
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	if (scf_iter_pg_properties(iter, pg) == -1)
3170Sstevel@tonic-gate 		scfdie();
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	while ((ret = scf_iter_next_property(iter, prop)) == 1)
3200Sstevel@tonic-gate 		display_prop(pg, prop);
3210Sstevel@tonic-gate 	if (ret == -1)
3220Sstevel@tonic-gate 		scfdie();
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	scf_iter_destroy(iter);
3250Sstevel@tonic-gate 	scf_property_destroy(prop);
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate /*
3290Sstevel@tonic-gate  * Common code to execute when a nonexistant property is encountered.
3300Sstevel@tonic-gate  */
3310Sstevel@tonic-gate static void
noprop_common_action()3320Sstevel@tonic-gate noprop_common_action()
3330Sstevel@tonic-gate {
3340Sstevel@tonic-gate 	if (!PRINT_NOPROP_ERRORS)
3350Sstevel@tonic-gate 		/* We're not printing errors, so we can cut out early. */
3360Sstevel@tonic-gate 		exit(UU_EXIT_FATAL);
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	return_code = UU_EXIT_FATAL;
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate /*
3420Sstevel@tonic-gate  * Iterate the properties of a service or an instance when no snapshot
3430Sstevel@tonic-gate  * is specified.
3440Sstevel@tonic-gate  */
3450Sstevel@tonic-gate static int
scf_iter_entity_pgs(scf_iter_t * iter,scf_entityp_t ent)3460Sstevel@tonic-gate scf_iter_entity_pgs(scf_iter_t *iter, scf_entityp_t ent)
3470Sstevel@tonic-gate {
3480Sstevel@tonic-gate 	int ret = 0;
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	if (ent.type) {
3510Sstevel@tonic-gate 		/*
3520Sstevel@tonic-gate 		 * If we are displaying properties for a service,
3530Sstevel@tonic-gate 		 * treat it as though it were a composed, current
3540Sstevel@tonic-gate 		 * lookup. (implicit cflag) However, if a snapshot
3550Sstevel@tonic-gate 		 * was specified, fail.
3560Sstevel@tonic-gate 		 */
3570Sstevel@tonic-gate 		if (sflag)
3580Sstevel@tonic-gate 			die(gettext("Only instances have "
3590Sstevel@tonic-gate 			    "snapshots.\n"));
3600Sstevel@tonic-gate 		ret = scf_iter_service_pgs(iter, ent.u.svc);
3610Sstevel@tonic-gate 	} else {
3620Sstevel@tonic-gate 		if (Cflag)
3630Sstevel@tonic-gate 			ret = scf_iter_instance_pgs(iter, ent.u.inst);
3640Sstevel@tonic-gate 		else
3650Sstevel@tonic-gate 			ret = scf_iter_instance_pgs_composed(iter, ent.u.inst,
3660Sstevel@tonic-gate 			    NULL);
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate 	return (ret);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate /*
3720Sstevel@tonic-gate  * Return a snapshot for the supplied instance and snapshot name.
3730Sstevel@tonic-gate  */
3740Sstevel@tonic-gate static scf_snapshot_t *
get_snapshot(const scf_instance_t * inst,const char * snapshot)3750Sstevel@tonic-gate get_snapshot(const scf_instance_t *inst, const char *snapshot)
3760Sstevel@tonic-gate {
3770Sstevel@tonic-gate 	scf_snapshot_t *snap = scf_snapshot_create(hndl);
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	if (snap == NULL)
3800Sstevel@tonic-gate 		scfdie();
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	if (scf_instance_get_snapshot(inst, snapshot, snap) == -1) {
3830Sstevel@tonic-gate 		switch (scf_error()) {
3840Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
3850Sstevel@tonic-gate 			die(gettext("Invalid snapshot name.\n"));
3860Sstevel@tonic-gate 			/* NOTREACHED */
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
3890Sstevel@tonic-gate 			if (sflag == 0) {
3900Sstevel@tonic-gate 				scf_snapshot_destroy(snap);
3910Sstevel@tonic-gate 				snap = NULL;
3920Sstevel@tonic-gate 			} else
3930Sstevel@tonic-gate 				die(gettext("No such snapshot.\n"));
3940Sstevel@tonic-gate 			break;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 		default:
3970Sstevel@tonic-gate 			scfdie();
3980Sstevel@tonic-gate 		}
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	return (snap);
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate /*
4050Sstevel@tonic-gate  * Entity (service or instance): If there are -p options,
4060Sstevel@tonic-gate  * display_{pg,prop}() the named property groups and/or properties.  Otherwise
4070Sstevel@tonic-gate  * display_pg() all property groups.
4080Sstevel@tonic-gate  */
4090Sstevel@tonic-gate static void
process_ent(scf_entityp_t ent)4100Sstevel@tonic-gate process_ent(scf_entityp_t ent)
4110Sstevel@tonic-gate {
4120Sstevel@tonic-gate 	scf_snapshot_t *snap = NULL;
4130Sstevel@tonic-gate 	scf_propertygroup_t *pg;
4140Sstevel@tonic-gate 	scf_property_t *prop;
4150Sstevel@tonic-gate 	scf_iter_t *iter;
4160Sstevel@tonic-gate 	svcprop_prop_node_t *spn;
4170Sstevel@tonic-gate 	int ret, err;
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	if (uu_list_numnodes(prop_list) == 0) {
4200Sstevel@tonic-gate 		if (quiet)
4210Sstevel@tonic-gate 			return;
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 		if ((pg = scf_pg_create(hndl)) == NULL ||
4240Sstevel@tonic-gate 		    (iter = scf_iter_create(hndl)) == NULL)
4250Sstevel@tonic-gate 			scfdie();
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 		if (cflag || Cflag || ent.type != ENT_INSTANCE) {
4280Sstevel@tonic-gate 			if (scf_iter_entity_pgs(iter, ent) == -1)
4290Sstevel@tonic-gate 				scfdie();
4300Sstevel@tonic-gate 		} else {
4310Sstevel@tonic-gate 			if (snapshot != NULL)
4320Sstevel@tonic-gate 				snap = get_snapshot(ent.u.inst, snapshot);
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 			if (scf_iter_instance_pgs_composed(iter, ent.u.inst,
4350Sstevel@tonic-gate 			    snap) == -1)
4360Sstevel@tonic-gate 				scfdie();
4370Sstevel@tonic-gate 			if (snap)
4380Sstevel@tonic-gate 				scf_snapshot_destroy(snap);
4390Sstevel@tonic-gate 		}
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 		while ((ret = scf_iter_next_pg(iter, pg)) == 1)
4420Sstevel@tonic-gate 			display_pg(pg);
4430Sstevel@tonic-gate 		if (ret == -1)
4440Sstevel@tonic-gate 			scfdie();
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 		/*
4470Sstevel@tonic-gate 		 * In normal usage, i.e. against the running snapshot,
4480Sstevel@tonic-gate 		 * we must iterate over the current non-persistent
4490Sstevel@tonic-gate 		 * pg's.
4500Sstevel@tonic-gate 		 */
4510Sstevel@tonic-gate 		if (sflag == 0 && snap != NULL) {
4520Sstevel@tonic-gate 			scf_iter_reset(iter);
4530Sstevel@tonic-gate 			if (scf_iter_instance_pgs_composed(iter, ent.u.inst,
4540Sstevel@tonic-gate 			    NULL) == -1)
4550Sstevel@tonic-gate 				scfdie();
4560Sstevel@tonic-gate 			while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
4570Sstevel@tonic-gate 				uint32_t flags;
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 				if (scf_pg_get_flags(pg, &flags) == -1)
4600Sstevel@tonic-gate 					scfdie();
4610Sstevel@tonic-gate 				if (flags & SCF_PG_FLAG_NONPERSISTENT)
4620Sstevel@tonic-gate 					display_pg(pg);
4630Sstevel@tonic-gate 			}
4640Sstevel@tonic-gate 		}
4650Sstevel@tonic-gate 		if (ret == -1)
4660Sstevel@tonic-gate 			scfdie();
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 		scf_iter_destroy(iter);
4690Sstevel@tonic-gate 		scf_pg_destroy(pg);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 		return;
4720Sstevel@tonic-gate 	}
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	if ((pg = scf_pg_create(hndl)) == NULL ||
4750Sstevel@tonic-gate 	    (prop = scf_property_create(hndl)) == NULL)
4760Sstevel@tonic-gate 		scfdie();
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	if (ent.type == ENT_INSTANCE && snapshot != NULL)
4790Sstevel@tonic-gate 		snap = get_snapshot(ent.u.inst, snapshot);
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	for (spn = uu_list_first(prop_list);
4820Sstevel@tonic-gate 	    spn != NULL;
4830Sstevel@tonic-gate 	    spn = uu_list_next(prop_list, spn)) {
4840Sstevel@tonic-gate 		if (ent.type == ENT_INSTANCE) {
4850Sstevel@tonic-gate 			if (Cflag)
4860Sstevel@tonic-gate 				ret = scf_instance_get_pg(ent.u.inst,
4870Sstevel@tonic-gate 				    spn->spn_comp1, pg);
4880Sstevel@tonic-gate 			else
4890Sstevel@tonic-gate 				ret = scf_instance_get_pg_composed(ent.u.inst,
4900Sstevel@tonic-gate 				    snap, spn->spn_comp1, pg);
4910Sstevel@tonic-gate 			err = scf_error();
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 			/*
4940Sstevel@tonic-gate 			 * If we didn't find it in the specified snapshot, use
4950Sstevel@tonic-gate 			 * the current values if the pg is nonpersistent.
4960Sstevel@tonic-gate 			 */
4970Sstevel@tonic-gate 			if (ret == -1 && !Cflag &&snap != NULL && err ==
4980Sstevel@tonic-gate 			    SCF_ERROR_NOT_FOUND) {
4990Sstevel@tonic-gate 				ret = scf_instance_get_pg_composed(
5000Sstevel@tonic-gate 				    ent.u.inst, NULL, spn->spn_comp1,
5010Sstevel@tonic-gate 				    pg);
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 				if (ret == 0) {
5040Sstevel@tonic-gate 					uint32_t flags;
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 					if (scf_pg_get_flags(pg, &flags) == -1)
5070Sstevel@tonic-gate 						scfdie();
5080Sstevel@tonic-gate 					if ((flags & SCF_PG_FLAG_NONPERSISTENT)
5090Sstevel@tonic-gate 					    == 0) {
5100Sstevel@tonic-gate 						ret = -1;
5110Sstevel@tonic-gate 					}
5120Sstevel@tonic-gate 				}
5130Sstevel@tonic-gate 			}
5140Sstevel@tonic-gate 		} else {
5150Sstevel@tonic-gate 			/*
5160Sstevel@tonic-gate 			 * If we are displaying properties for a service,
5170Sstevel@tonic-gate 			 * treat it as though it were a composed, current
5180Sstevel@tonic-gate 			 * lookup. (implicit cflag) However, if a snapshot
5190Sstevel@tonic-gate 			 * was specified, fail.
5200Sstevel@tonic-gate 			 */
5210Sstevel@tonic-gate 			if (sflag)
5220Sstevel@tonic-gate 				die(gettext("Only instances have "
5230Sstevel@tonic-gate 				    "snapshots.\n"));
5240Sstevel@tonic-gate 			ret = scf_entity_get_pg(ent, spn->spn_comp1, pg);
5250Sstevel@tonic-gate 			err = scf_error();
5260Sstevel@tonic-gate 		}
5270Sstevel@tonic-gate 		if (ret == -1) {
5280Sstevel@tonic-gate 			if (err != SCF_ERROR_NOT_FOUND)
5290Sstevel@tonic-gate 				scfdie();
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 			if (PRINT_NOPROP_ERRORS) {
5320Sstevel@tonic-gate 				char *buf;
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 				buf = safe_malloc(max_scf_fmri_length + 1);
5350Sstevel@tonic-gate 				if (scf_entity_to_fmri(ent, buf,
5360Sstevel@tonic-gate 				    max_scf_fmri_length + 1) == -1)
5370Sstevel@tonic-gate 					scfdie();
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 				uu_warn(gettext("Couldn't find property group "
5400Sstevel@tonic-gate 				    "`%s' for %s `%s'.\n"), spn->spn_comp1,
5410Sstevel@tonic-gate 				    SCF_ENTITY_TYPE_NAME(ent), buf);
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 				free(buf);
5440Sstevel@tonic-gate 			}
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 			noprop_common_action();
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 			continue;
5490Sstevel@tonic-gate 		}
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 		if (spn->spn_comp2 == NULL) {
5520Sstevel@tonic-gate 			if (!quiet)
5530Sstevel@tonic-gate 				display_pg(pg);
5540Sstevel@tonic-gate 			continue;
5550Sstevel@tonic-gate 		}
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 		if (scf_pg_get_property(pg, spn->spn_comp2, prop) == -1) {
5580Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
5590Sstevel@tonic-gate 				scfdie();
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 			if (PRINT_NOPROP_ERRORS) {
5620Sstevel@tonic-gate 				char *buf;
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 				buf = safe_malloc(max_scf_fmri_length + 1);
5650Sstevel@tonic-gate 				if (scf_entity_to_fmri(ent, buf,
5660Sstevel@tonic-gate 				    max_scf_fmri_length + 1) == -1)
5670Sstevel@tonic-gate 					scfdie();
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 				/* FMRI syntax knowledge */
5700Sstevel@tonic-gate 				uu_warn(gettext("Couldn't find property "
5710Sstevel@tonic-gate 				    "`%s/%s' for %s `%s'.\n"), spn->spn_comp1,
5720Sstevel@tonic-gate 				    spn->spn_comp2, SCF_ENTITY_TYPE_NAME(ent),
5730Sstevel@tonic-gate 				    buf);
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 				free(buf);
5760Sstevel@tonic-gate 			}
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 			noprop_common_action();
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 			continue;
5810Sstevel@tonic-gate 		}
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 		if (!quiet)
5840Sstevel@tonic-gate 			display_prop(pg, prop);
5850Sstevel@tonic-gate 	}
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	scf_property_destroy(prop);
5880Sstevel@tonic-gate 	scf_pg_destroy(pg);
5890Sstevel@tonic-gate 	if (snap)
5900Sstevel@tonic-gate 		scf_snapshot_destroy(snap);
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate /*
5940Sstevel@tonic-gate  * Without -p options, just call display_pg().  Otherwise display_prop() the
5950Sstevel@tonic-gate  * named properties of the property group.
5960Sstevel@tonic-gate  */
5970Sstevel@tonic-gate static void
process_pg(scf_propertygroup_t * pg)5980Sstevel@tonic-gate process_pg(scf_propertygroup_t *pg)
5990Sstevel@tonic-gate {
6000Sstevel@tonic-gate 	scf_property_t *prop;
6010Sstevel@tonic-gate 	svcprop_prop_node_t *spn;
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	if (uu_list_first(prop_list) == NULL) {
6040Sstevel@tonic-gate 		if (quiet)
6050Sstevel@tonic-gate 			return;
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 		display_pg(pg);
6080Sstevel@tonic-gate 		return;
6090Sstevel@tonic-gate 	}
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	prop = scf_property_create(hndl);
6120Sstevel@tonic-gate 	if (prop == NULL)
6130Sstevel@tonic-gate 		scfdie();
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	for (spn = uu_list_first(prop_list);
6160Sstevel@tonic-gate 	    spn != NULL;
6170Sstevel@tonic-gate 	    spn = uu_list_next(prop_list, spn)) {
6180Sstevel@tonic-gate 		if (spn->spn_comp2 != NULL) {
6190Sstevel@tonic-gate 			char *buf;
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 			buf = safe_malloc(max_scf_fmri_length + 1);
6220Sstevel@tonic-gate 			if (scf_pg_to_fmri(pg, buf, max_scf_fmri_length + 1) ==
6230Sstevel@tonic-gate 			    -1)
6240Sstevel@tonic-gate 				scfdie();
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 			uu_xdie(UU_EXIT_USAGE, gettext("-p argument `%s/%s' "
6270Sstevel@tonic-gate 			    "has too many components for property "
6280Sstevel@tonic-gate 			    "group `%s'.\n"), spn->spn_comp1, spn->spn_comp2,
6290Sstevel@tonic-gate 			    buf);
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 			free(buf);
6320Sstevel@tonic-gate 		}
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 		if (scf_pg_get_property(pg, spn->spn_comp1, prop) == 0) {
6350Sstevel@tonic-gate 			if (!quiet)
6360Sstevel@tonic-gate 				display_prop(pg, prop);
6370Sstevel@tonic-gate 			continue;
6380Sstevel@tonic-gate 		}
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
6410Sstevel@tonic-gate 			scfdie();
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 		if (PRINT_NOPROP_ERRORS) {
6440Sstevel@tonic-gate 			char *buf;
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 			buf = safe_malloc(max_scf_fmri_length + 1);
6470Sstevel@tonic-gate 			if (scf_pg_to_fmri(pg, buf, max_scf_fmri_length + 1) ==
6480Sstevel@tonic-gate 			    -1)
6490Sstevel@tonic-gate 				scfdie();
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 			uu_warn(gettext("Couldn't find property `%s' in "
6520Sstevel@tonic-gate 			    "property group `%s'.\n"), spn->spn_comp1, buf);
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 			free(buf);
6550Sstevel@tonic-gate 		}
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 		noprop_common_action();
6580Sstevel@tonic-gate 	}
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate /*
6620Sstevel@tonic-gate  * If there are -p options, show the error.  Otherwise just call
6630Sstevel@tonic-gate  * display_prop().
6640Sstevel@tonic-gate  */
6650Sstevel@tonic-gate static void
process_prop(scf_propertygroup_t * pg,scf_property_t * prop)6660Sstevel@tonic-gate process_prop(scf_propertygroup_t *pg, scf_property_t *prop)
6670Sstevel@tonic-gate {
6680Sstevel@tonic-gate 	if (uu_list_first(prop_list) != NULL) {
6690Sstevel@tonic-gate 		uu_warn(gettext("The -p option cannot be used with property "
6700Sstevel@tonic-gate 		    "operands.\n"));
6710Sstevel@tonic-gate 		usage();
6720Sstevel@tonic-gate 	}
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	if (quiet)
6750Sstevel@tonic-gate 		return;
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	display_prop(pg, prop);
6780Sstevel@tonic-gate }
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate /* Decode an operand & dispatch. */
6810Sstevel@tonic-gate /* ARGSUSED */
6820Sstevel@tonic-gate static int
process_fmri(void * unused,scf_walkinfo_t * wip)6830Sstevel@tonic-gate process_fmri(void *unused, scf_walkinfo_t *wip)
6840Sstevel@tonic-gate {
6850Sstevel@tonic-gate 	scf_entityp_t ent;
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	/* Multiple matches imply multiple entities. */
6880Sstevel@tonic-gate 	if (wip->count > 1)
6890Sstevel@tonic-gate 		types = fmris = 1;
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 	if (wip->prop != NULL) {
6920Sstevel@tonic-gate 		process_prop(wip->pg, wip->prop);
6930Sstevel@tonic-gate 	} else if (wip->pg != NULL) {
6940Sstevel@tonic-gate 		process_pg(wip->pg);
6950Sstevel@tonic-gate 	} else if (wip->inst != NULL) {
6960Sstevel@tonic-gate 		SCF_ENTITY_SET_TO_INSTANCE(ent, wip->inst);
6970Sstevel@tonic-gate 		process_ent(ent);
6980Sstevel@tonic-gate 	} else {
6990Sstevel@tonic-gate 		/* scf_walk_fmri() won't let this happen */
7000Sstevel@tonic-gate 		assert(wip->svc != NULL);
7010Sstevel@tonic-gate 		SCF_ENTITY_SET_TO_SERVICE(ent, wip->svc);
7020Sstevel@tonic-gate 		process_ent(ent);
7030Sstevel@tonic-gate 	}
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	return (0);
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate static void
add_prop(char * property)7090Sstevel@tonic-gate add_prop(char *property)
7100Sstevel@tonic-gate {
7110Sstevel@tonic-gate 	svcprop_prop_node_t *p, *last;
7120Sstevel@tonic-gate 	char *slash;
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	const char * const invalid_component_emsg =
7150Sstevel@tonic-gate 	    gettext("Invalid component name `%s'.\n");
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	/* FMRI syntax knowledge. */
7180Sstevel@tonic-gate 	slash = strchr(property, '/');
7190Sstevel@tonic-gate 	if (slash != NULL) {
7200Sstevel@tonic-gate 		if (strchr(slash + 1, '/') != NULL) {
7210Sstevel@tonic-gate 			uu_warn(gettext("-p argument `%s' has too many "
7220Sstevel@tonic-gate 			    "components.\n"), property);
7230Sstevel@tonic-gate 			usage();
7240Sstevel@tonic-gate 		}
7250Sstevel@tonic-gate 	}
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	if (slash != NULL)
7280Sstevel@tonic-gate 		*slash = '\0';
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	p = safe_malloc(sizeof (svcprop_prop_node_t));
7310Sstevel@tonic-gate 	uu_list_node_init(p, &p->spn_list_node, prop_pool);
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	p->spn_comp1 = property;
7340Sstevel@tonic-gate 	p->spn_comp2 = (slash == NULL) ? NULL : slash + 1;
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	if (uu_check_name(p->spn_comp1, UU_NAME_DOMAIN) == -1)
7370Sstevel@tonic-gate 		uu_xdie(UU_EXIT_USAGE, invalid_component_emsg, p->spn_comp1);
7380Sstevel@tonic-gate 	if (p->spn_comp2 != NULL &&
7390Sstevel@tonic-gate 	    uu_check_name(p->spn_comp2, UU_NAME_DOMAIN) == -1)
7400Sstevel@tonic-gate 		uu_xdie(UU_EXIT_USAGE, invalid_component_emsg, p->spn_comp2);
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 	last = uu_list_last(prop_list);
7430Sstevel@tonic-gate 	if (last != NULL) {
7440Sstevel@tonic-gate 		if ((last->spn_comp2 == NULL) ^ (p->spn_comp2 == NULL)) {
7450Sstevel@tonic-gate 			/*
7460Sstevel@tonic-gate 			 * The -p options have mixed numbers of components.
7470Sstevel@tonic-gate 			 * If they both turn out to be valid, then the
7480Sstevel@tonic-gate 			 * single-component ones will specify property groups,
7490Sstevel@tonic-gate 			 * so we need to turn on types to keep the output of
7500Sstevel@tonic-gate 			 * display_prop() consistent with display_pg().
7510Sstevel@tonic-gate 			 */
7520Sstevel@tonic-gate 			types = 1;
7530Sstevel@tonic-gate 		}
7540Sstevel@tonic-gate 	}
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	(void) uu_list_insert_after(prop_list, NULL, p);
7570Sstevel@tonic-gate }
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate /*
7610Sstevel@tonic-gate  * Wait for a property group or property change.
7620Sstevel@tonic-gate  *
7630Sstevel@tonic-gate  * Extract a pg and optionally a property name from fmri & prop_list.
7640Sstevel@tonic-gate  * _scf_pg_wait() for the pg, and display_pg(pg) or display_prop(pg, prop)
7650Sstevel@tonic-gate  * when it returns.
7660Sstevel@tonic-gate  */
7670Sstevel@tonic-gate /* ARGSUSED */
7680Sstevel@tonic-gate static int
do_wait(void * unused,scf_walkinfo_t * wip)7690Sstevel@tonic-gate do_wait(void *unused, scf_walkinfo_t *wip)
7700Sstevel@tonic-gate {
7710Sstevel@tonic-gate 	scf_property_t *prop;
7720Sstevel@tonic-gate 	scf_propertygroup_t *lpg, *pg;
7730Sstevel@tonic-gate 	const char *propname;
7740Sstevel@tonic-gate 	svcprop_prop_node_t *p;
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	const char *emsg_not_found = gettext("Not found.\n");
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	if ((lpg = scf_pg_create(hndl)) == NULL ||
7790Sstevel@tonic-gate 	    (prop = scf_property_create(hndl)) == NULL)
7800Sstevel@tonic-gate 		scfdie();
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	if (wip->prop != NULL) {
7830Sstevel@tonic-gate 		if (uu_list_numnodes(prop_list) > 0)
7840Sstevel@tonic-gate 			uu_xdie(UU_EXIT_USAGE, gettext("-p cannot be used with "
7850Sstevel@tonic-gate 			    "property FMRIs.\n"));
7860Sstevel@tonic-gate 		pg = wip->pg;
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 		assert(strrchr(wip->fmri, '/') != NULL);
7890Sstevel@tonic-gate 		propname = strrchr(wip->fmri, '/') + 1;
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	} else if (wip->pg != NULL) {
7920Sstevel@tonic-gate 		p = uu_list_first(prop_list);
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 		if (p != NULL) {
7950Sstevel@tonic-gate 			if (p->spn_comp2 != NULL)
7960Sstevel@tonic-gate 				uu_xdie(UU_EXIT_USAGE, gettext("-p argument "
7970Sstevel@tonic-gate 				    "\"%s/%s\" has too many components for "
7980Sstevel@tonic-gate 				    "property group %s.\n"),
7990Sstevel@tonic-gate 				    p->spn_comp1, p->spn_comp2, wip->fmri);
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 			propname = p->spn_comp1;
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 			if (scf_pg_get_property(wip->pg, propname, prop) !=
8040Sstevel@tonic-gate 			    SCF_SUCCESS) {
8050Sstevel@tonic-gate 				switch (scf_error()) {
8060Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
8070Sstevel@tonic-gate 					uu_xdie(UU_EXIT_USAGE,
8080Sstevel@tonic-gate 					    gettext("Invalid property name "
8090Sstevel@tonic-gate 					    "\"%s\".\n"), propname);
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 					/* NOTREACHED */
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 				case SCF_ERROR_NOT_FOUND:
8140Sstevel@tonic-gate 					die(emsg_not_found);
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 					/* NOTREACHED */
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 				default:
8190Sstevel@tonic-gate 					scfdie();
8200Sstevel@tonic-gate 				}
8210Sstevel@tonic-gate 			}
8220Sstevel@tonic-gate 		} else {
8230Sstevel@tonic-gate 			propname = NULL;
8240Sstevel@tonic-gate 		}
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 		pg = wip->pg;
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	} else if (wip->inst != NULL) {
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 		p = uu_list_first(prop_list);
8310Sstevel@tonic-gate 		if (p == NULL)
8320Sstevel@tonic-gate 			uu_xdie(UU_EXIT_USAGE,
8330Sstevel@tonic-gate 			    gettext("Cannot wait for an instance.\n"));
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 		if (scf_instance_get_pg(wip->inst, p->spn_comp1, lpg) !=
8360Sstevel@tonic-gate 		    SCF_SUCCESS) {
8370Sstevel@tonic-gate 			switch (scf_error()) {
8380Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
8390Sstevel@tonic-gate 				uu_xdie(UU_EXIT_USAGE, gettext("Invalid "
8400Sstevel@tonic-gate 				    "property group name \"%s\".\n"),
8410Sstevel@tonic-gate 				    p->spn_comp1);
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
8440Sstevel@tonic-gate 				die(emsg_not_found);
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 				/* NOTREACHED */
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 			default:
8490Sstevel@tonic-gate 				scfdie();
8500Sstevel@tonic-gate 			}
8510Sstevel@tonic-gate 		}
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 		propname = p->spn_comp2;
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 		if (propname != NULL) {
8560Sstevel@tonic-gate 			if (scf_pg_get_property(lpg, propname, prop) !=
8570Sstevel@tonic-gate 			    SCF_SUCCESS) {
8580Sstevel@tonic-gate 				switch (scf_error()) {
8590Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
8600Sstevel@tonic-gate 					uu_xdie(UU_EXIT_USAGE,
8610Sstevel@tonic-gate 					    gettext("Invalid property name "
8620Sstevel@tonic-gate 					    "\"%s\".\n"), propname);
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 				case SCF_ERROR_NOT_FOUND:
8650Sstevel@tonic-gate 					die(emsg_not_found);
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 					/* NOTREACHED */
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 				default:
8700Sstevel@tonic-gate 					scfdie();
8710Sstevel@tonic-gate 				}
8720Sstevel@tonic-gate 			}
8730Sstevel@tonic-gate 		}
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 		pg = lpg;
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	} else if (wip->svc != NULL) {
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 		p = uu_list_first(prop_list);
8800Sstevel@tonic-gate 		if (p == NULL)
8810Sstevel@tonic-gate 			uu_xdie(UU_EXIT_USAGE,
8820Sstevel@tonic-gate 			    gettext("Cannot wait for a service.\n"));
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 		if (scf_service_get_pg(wip->svc, p->spn_comp1, lpg) !=
8850Sstevel@tonic-gate 		    SCF_SUCCESS) {
8860Sstevel@tonic-gate 			switch (scf_error()) {
8870Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
8880Sstevel@tonic-gate 				uu_xdie(UU_EXIT_USAGE, gettext("Invalid "
8890Sstevel@tonic-gate 				    "property group name \"%s\".\n"),
8900Sstevel@tonic-gate 				    p->spn_comp1);
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
8930Sstevel@tonic-gate 				die(emsg_not_found);
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 			default:
8960Sstevel@tonic-gate 				scfdie();
8970Sstevel@tonic-gate 			}
8980Sstevel@tonic-gate 		}
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 		propname = p->spn_comp2;
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 		if (propname != NULL) {
9030Sstevel@tonic-gate 			if (scf_pg_get_property(lpg, propname, prop) !=
9040Sstevel@tonic-gate 			    SCF_SUCCESS) {
9050Sstevel@tonic-gate 				switch (scf_error()) {
9060Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
9070Sstevel@tonic-gate 					uu_xdie(UU_EXIT_USAGE,
9080Sstevel@tonic-gate 					    gettext("Invalid property name "
9090Sstevel@tonic-gate 					    "\"%s\".\n"), propname);
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 					/* NOTREACHED */
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 				case SCF_ERROR_NOT_FOUND:
9140Sstevel@tonic-gate 					die(emsg_not_found);
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 					/* NOTREACHED */
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 				default:
9190Sstevel@tonic-gate 					scfdie();
9200Sstevel@tonic-gate 				}
9210Sstevel@tonic-gate 			}
9220Sstevel@tonic-gate 		}
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 		pg = lpg;
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 	} else {
9270Sstevel@tonic-gate 		uu_xdie(UU_EXIT_USAGE, gettext("FMRI must specify an entity, "
9280Sstevel@tonic-gate 		    "property group, or property.\n"));
9290Sstevel@tonic-gate 	}
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	for (;;) {
9320Sstevel@tonic-gate 		int ret;
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 		ret = _scf_pg_wait(pg, -1);
9350Sstevel@tonic-gate 		if (ret != SCF_SUCCESS)
9360Sstevel@tonic-gate 			scfdie();
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 		ret = scf_pg_update(pg);
9390Sstevel@tonic-gate 		if (ret < 0) {
9400Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_DELETED)
9410Sstevel@tonic-gate 				scfdie();
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 			die(emsg_not_found);
9440Sstevel@tonic-gate 		}
9450Sstevel@tonic-gate 		if (ret == SCF_COMPLETE)
9460Sstevel@tonic-gate 			break;
9470Sstevel@tonic-gate 	}
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	if (propname != NULL) {
9500Sstevel@tonic-gate 		if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) {
9510Sstevel@tonic-gate 			if (!quiet)
9520Sstevel@tonic-gate 				display_prop(pg, prop);
9530Sstevel@tonic-gate 		} else {
9540Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
9550Sstevel@tonic-gate 				scfdie();
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 			if (PRINT_NOPROP_ERRORS)
9580Sstevel@tonic-gate 				uu_warn(emsg_not_found);
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 			return_code = UU_EXIT_FATAL;
9610Sstevel@tonic-gate 		}
9620Sstevel@tonic-gate 	} else {
9630Sstevel@tonic-gate 		if (!quiet)
9640Sstevel@tonic-gate 			display_pg(pg);
9650Sstevel@tonic-gate 	}
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	scf_property_destroy(prop);
9680Sstevel@tonic-gate 	scf_pg_destroy(lpg);
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	return (0);
9710Sstevel@tonic-gate }
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate /*
9740Sstevel@tonic-gate  * These functions replace uu_warn() and uu_die() when the quiet (-q) option is
9750Sstevel@tonic-gate  * used, and silently ignore any output.
9760Sstevel@tonic-gate  */
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate /*ARGSUSED*/
9790Sstevel@tonic-gate static void
quiet_warn(const char * fmt,...)9800Sstevel@tonic-gate quiet_warn(const char *fmt, ...)
9810Sstevel@tonic-gate {
9820Sstevel@tonic-gate 	/* Do nothing */
9830Sstevel@tonic-gate }
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate /*ARGSUSED*/
9860Sstevel@tonic-gate static void
quiet_die(const char * fmt,...)9870Sstevel@tonic-gate quiet_die(const char *fmt, ...)
9880Sstevel@tonic-gate {
9890Sstevel@tonic-gate 	exit(UU_EXIT_FATAL);
9900Sstevel@tonic-gate }
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate int
main(int argc,char * argv[])9930Sstevel@tonic-gate main(int argc, char *argv[])
9940Sstevel@tonic-gate {
9950Sstevel@tonic-gate 	int c;
9960Sstevel@tonic-gate 	scf_walk_callback callback;
9970Sstevel@tonic-gate 	int flags;
9980Sstevel@tonic-gate 	int err;
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
10010Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	return_code = UU_EXIT_OK;
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 	(void) uu_setpname(argv[0]);
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	prop_pool = uu_list_pool_create("properties",
10080Sstevel@tonic-gate 	    sizeof (svcprop_prop_node_t),
10090Sstevel@tonic-gate 	    offsetof(svcprop_prop_node_t, spn_list_node), NULL, 0);
10100Sstevel@tonic-gate 	if (prop_pool == NULL)
10110Sstevel@tonic-gate 		uu_die("%s\n", uu_strerror(uu_error()));
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	prop_list = uu_list_create(prop_pool, NULL, 0);
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "Ccfp:qs:tvw")) != -1) {
10160Sstevel@tonic-gate 		switch (c) {
10170Sstevel@tonic-gate 		case 'C':
10180Sstevel@tonic-gate 			if (cflag || sflag || wait)
10190Sstevel@tonic-gate 				usage();	/* Not with -c, -s or -w */
10200Sstevel@tonic-gate 			Cflag++;
10210Sstevel@tonic-gate 			snapshot = NULL;
10220Sstevel@tonic-gate 			break;
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 		case 'c':
10250Sstevel@tonic-gate 			if (Cflag || sflag || wait)
10260Sstevel@tonic-gate 				usage();	/* Not with -C, -s or -w */
10270Sstevel@tonic-gate 			cflag++;
10280Sstevel@tonic-gate 			snapshot = NULL;
10290Sstevel@tonic-gate 			break;
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 		case 'f':
10320Sstevel@tonic-gate 			types = 1;
10330Sstevel@tonic-gate 			fmris = 1;
10340Sstevel@tonic-gate 			break;
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 		case 'p':
10370Sstevel@tonic-gate 			add_prop(optarg);
10380Sstevel@tonic-gate 			break;
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 		case 'q':
10410Sstevel@tonic-gate 			quiet = 1;
10420Sstevel@tonic-gate 			warn = quiet_warn;
10430Sstevel@tonic-gate 			die = quiet_die;
10440Sstevel@tonic-gate 			break;
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 		case 's':
10470Sstevel@tonic-gate 			if (Cflag || cflag || wait)
10480Sstevel@tonic-gate 				usage();	/* Not with -C, -c or -w */
10490Sstevel@tonic-gate 			snapshot = optarg;
10500Sstevel@tonic-gate 			sflag++;
10510Sstevel@tonic-gate 			break;
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 		case 't':
10540Sstevel@tonic-gate 			types = 1;
10550Sstevel@tonic-gate 			break;
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 		case 'v':
10580Sstevel@tonic-gate 			verbose = 1;
10590Sstevel@tonic-gate 			break;
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 		case 'w':
10620Sstevel@tonic-gate 			if (Cflag || cflag || sflag)
10630Sstevel@tonic-gate 				usage();	/* Not with -C, -c or -s */
10640Sstevel@tonic-gate 			wait = 1;
10650Sstevel@tonic-gate 			break;
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 		case '?':
10680Sstevel@tonic-gate 			switch (optopt) {
10690Sstevel@tonic-gate 			case 'p':
10700Sstevel@tonic-gate 				usage();
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 			default:
10730Sstevel@tonic-gate 				break;
10740Sstevel@tonic-gate 			}
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 			/* FALLTHROUGH */
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 		default:
10790Sstevel@tonic-gate 			usage();
10800Sstevel@tonic-gate 		}
10810Sstevel@tonic-gate 	}
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 	if (optind == argc)
10840Sstevel@tonic-gate 		usage();
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 	max_scf_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
10870Sstevel@tonic-gate 	max_scf_value_length = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
10880Sstevel@tonic-gate 	max_scf_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
10890Sstevel@tonic-gate 	if (max_scf_name_length == -1 || max_scf_value_length == -1 ||
10900Sstevel@tonic-gate 	    max_scf_fmri_length == -1)
10910Sstevel@tonic-gate 		scfdie();
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	hndl = scf_handle_create(SCF_VERSION);
10940Sstevel@tonic-gate 	if (hndl == NULL)
10950Sstevel@tonic-gate 		scfdie();
10960Sstevel@tonic-gate 	if (scf_handle_bind(hndl) == -1)
10970Sstevel@tonic-gate 		die(gettext("Could not connect to configuration repository: "
10980Sstevel@tonic-gate 		    "%s.\n"), scf_strerror(scf_error()));
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	flags = SCF_WALK_PROPERTY | SCF_WALK_SERVICE | SCF_WALK_EXPLICIT;
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 	if (wait) {
11030Sstevel@tonic-gate 		if (uu_list_numnodes(prop_list) > 1)
11040Sstevel@tonic-gate 			usage();
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 		if (argc - optind > 1)
11070Sstevel@tonic-gate 			usage();
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 		callback = do_wait;
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	} else {
11120Sstevel@tonic-gate 		callback = process_fmri;
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 		flags |= SCF_WALK_MULTIPLE;
11150Sstevel@tonic-gate 	}
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 	if ((err = scf_walk_fmri(hndl, argc - optind, argv + optind, flags,
11180Sstevel@tonic-gate 	    callback, NULL, &return_code, warn)) != 0) {
11190Sstevel@tonic-gate 		warn(gettext("failed to iterate over instances: %s\n"),
11200Sstevel@tonic-gate 		    scf_strerror(err));
11210Sstevel@tonic-gate 		return_code = UU_EXIT_FATAL;
11220Sstevel@tonic-gate 	}
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate 	scf_handle_destroy(hndl);
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	return (return_code);
11270Sstevel@tonic-gate }
1128