17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
53eae19dwesolows * Common Development and Distribution License (the "License").
63eae19dwesolows * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
213eae19dwesolows
227c478bdstevel@tonic-gate/*
233eae19dwesolows * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
247c478bdstevel@tonic-gate * Use is subject to license terms.
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate
27647f844Bryan Cantrill/*
2844bf619John Levon * Copyright 2019 Joyent, Inc.
29647f844Bryan Cantrill */
307c478bdstevel@tonic-gate
317c478bdstevel@tonic-gate/*
327c478bdstevel@tonic-gate * svcprop - report service configuration properties
337c478bdstevel@tonic-gate */
347c478bdstevel@tonic-gate
357c478bdstevel@tonic-gate#include <locale.h>
367c478bdstevel@tonic-gate#include <libintl.h>
377c478bdstevel@tonic-gate#include <libscf.h>
387c478bdstevel@tonic-gate#include <libscf_priv.h>
397c478bdstevel@tonic-gate#include <libuutil.h>
407c478bdstevel@tonic-gate#include <stddef.h>
417c478bdstevel@tonic-gate#include <stdio.h>
427c478bdstevel@tonic-gate#include <stdlib.h>
437c478bdstevel@tonic-gate#include <unistd.h>
447c478bdstevel@tonic-gate#include <strings.h>
457c478bdstevel@tonic-gate#include <assert.h>
46647f844Bryan Cantrill#include <zone.h>
477c478bdstevel@tonic-gate
487c478bdstevel@tonic-gate#ifndef TEXT_DOMAIN
497c478bdstevel@tonic-gate#define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
507c478bdstevel@tonic-gate#endif /* TEXT_DOMAIN */
517c478bdstevel@tonic-gate
527c478bdstevel@tonic-gate/*
537c478bdstevel@tonic-gate * Error functions.  These can change if the quiet (-q) option is used.
547c478bdstevel@tonic-gate */
557c478bdstevel@tonic-gatestatic void (*warn)(const char *, ...) = uu_warn;
56a5f0d1fToomas Soomestatic __NORETURN void (*die)(const char *, ...) = uu_die;
577c478bdstevel@tonic-gate
587c478bdstevel@tonic-gate/*
597c478bdstevel@tonic-gate * Entity encapsulation.  This allows me to treat services and instances
607c478bdstevel@tonic-gate * similarly, and avoid duplicating process_ent().
617c478bdstevel@tonic-gate */
627c478bdstevel@tonic-gatetypedef struct {
637c478bdstevel@tonic-gate	char type;			/* !=0: service, 0: instance */
647c478bdstevel@tonic-gate	union {
657c478bdstevel@tonic-gate		scf_service_t *svc;
667c478bdstevel@tonic-gate		scf_instance_t *inst;
677c478bdstevel@tonic-gate	} u;
687c478bdstevel@tonic-gate} scf_entityp_t;
697c478bdstevel@tonic-gate
707c478bdstevel@tonic-gate#define	ENT_INSTANCE	0
717c478bdstevel@tonic-gate
727c478bdstevel@tonic-gate#define	SCF_ENTITY_SET_TO_SERVICE(ent, s)	{ ent.type = 1; ent.u.svc = s; }
737c478bdstevel@tonic-gate
747c478bdstevel@tonic-gate#define	SCF_ENTITY_SET_TO_INSTANCE(ent, i)	\
757c478bdstevel@tonic-gate	{ ent.type = ENT_INSTANCE; ent.u.inst = i; }
767c478bdstevel@tonic-gate
777c478bdstevel@tonic-gate#define	scf_entity_get_pg(ent, name, pg) \
787c478bdstevel@tonic-gate	(ent.type ? scf_service_get_pg(ent.u.svc, name, pg) : \
797c478bdstevel@tonic-gate	scf_instance_get_pg(ent.u.inst, name, pg))
807c478bdstevel@tonic-gate
817c478bdstevel@tonic-gate#define	scf_entity_to_fmri(ent, buf, buf_sz) \
827c478bdstevel@tonic-gate	(ent.type ? scf_service_to_fmri(ent.u.svc, buf, buf_sz) : \
837c478bdstevel@tonic-gate	scf_instance_to_fmri(ent.u.inst, buf, buf_sz))
847c478bdstevel@tonic-gate
857c478bdstevel@tonic-gate#define	SCF_ENTITY_TYPE_NAME(ent)	(ent.type ? "service" : "instance")
867c478bdstevel@tonic-gate
877c478bdstevel@tonic-gate/*
887c478bdstevel@tonic-gate * Data structure for -p arguments.  Since they may be name or name/name, we
897c478bdstevel@tonic-gate * just track the components.
907c478bdstevel@tonic-gate */
917c478bdstevel@tonic-gatetypedef struct svcprop_prop_node {
927c478bdstevel@tonic-gate	uu_list_node_t	spn_list_node;
937c478bdstevel@tonic-gate	const char	*spn_comp1;
947c478bdstevel@tonic-gate	const char	*spn_comp2;
957c478bdstevel@tonic-gate} svcprop_prop_node_t;
967c478bdstevel@tonic-gate
977c478bdstevel@tonic-gatestatic uu_list_pool_t	*prop_pool;
987c478bdstevel@tonic-gatestatic uu_list_t	*prop_list;
997c478bdstevel@tonic-gate
1007c478bdstevel@tonic-gatestatic scf_handle_t *hndl;
1017c478bdstevel@tonic-gatestatic ssize_t max_scf_name_length;
1027c478bdstevel@tonic-gatestatic ssize_t max_scf_value_length;
1037c478bdstevel@tonic-gatestatic ssize_t max_scf_fmri_length;
1047c478bdstevel@tonic-gate
1057c478bdstevel@tonic-gate/* Options */
1067c478bdstevel@tonic-gatestatic int quiet = 0;			/* No output. Nothing found, exit(1) */
1077c478bdstevel@tonic-gatestatic int types = 0;			/* Display types of properties. */
1087c478bdstevel@tonic-gatestatic int verbose = 0;			/* Print not found errors to stderr. */
1097c478bdstevel@tonic-gatestatic int fmris = 0;			/* Display full FMRIs for properties. */
1107c478bdstevel@tonic-gatestatic int wait = 0;			/* Wait mode. */
1117c478bdstevel@tonic-gatestatic char *snapshot = "running";	/* Snapshot to use. */
1127c478bdstevel@tonic-gatestatic int Cflag = 0;			/* C option supplied */
1137c478bdstevel@tonic-gatestatic int cflag = 0;			/* c option supplied */
1147c478bdstevel@tonic-gatestatic int sflag = 0;			/* s option supplied */
1157c478bdstevel@tonic-gatestatic int return_code;			/* main's return code */
1167c478bdstevel@tonic-gate
1177c478bdstevel@tonic-gate#define	PRINT_NOPROP_ERRORS	(!quiet || verbose)
1187c478bdstevel@tonic-gate
1197c478bdstevel@tonic-gate/*
1207c478bdstevel@tonic-gate * For unexpected libscf errors.  The ending newline is necessary to keep
1217c478bdstevel@tonic-gate * uu_die() from appending the errno error.
1227c478bdstevel@tonic-gate */
1237c478bdstevel@tonic-gatestatic void
124a5f0d1fToomas Soomescfdie(void)
1257c478bdstevel@tonic-gate{
1267c478bdstevel@tonic-gate	die(gettext("Unexpected libscf error: %s.  Exiting.\n"),
1277c478bdstevel@tonic-gate	    scf_strerror(scf_error()));
1287c478bdstevel@tonic-gate}
1297c478bdstevel@tonic-gate
1307c478bdstevel@tonic-gatestatic void *
1317c478bdstevel@tonic-gatesafe_malloc(size_t sz)
1327c478bdstevel@tonic-gate{
1337c478bdstevel@tonic-gate	void *p;
1347c478bdstevel@tonic-gate
1357c478bdstevel@tonic-gate	p = malloc(sz);
1367c478bdstevel@tonic-gate	if (p == NULL)
1377c478bdstevel@tonic-gate		die(gettext("Could not allocate memory"));
1387c478bdstevel@tonic-gate
1397c478bdstevel@tonic-gate	return (p);
1407c478bdstevel@tonic-gate}
1417c478bdstevel@tonic-gate
1427c478bdstevel@tonic-gatestatic void
143a5f0d1fToomas Soomeusage(void)
1447c478bdstevel@tonic-gate{
1457c478bdstevel@tonic-gate	(void) fprintf(stderr, gettext("Usage: %1$s [-fqtv] "
146647f844Bryan Cantrill	    "[-C | -c | -s snapshot] [-z zone] "
1477c478bdstevel@tonic-gate	    "[-p [name/]name]... \n"
1487c478bdstevel@tonic-gate	    "         {FMRI | pattern}...\n"
149647f844Bryan Cantrill	    "       %1$s -w [-fqtv] [-z zone] [-p [name/]name] "
1507c478bdstevel@tonic-gate	    "{FMRI | pattern}\n"), uu_getpname());
1517c478bdstevel@tonic-gate	exit(UU_EXIT_USAGE);
1527c478bdstevel@tonic-gate}
1537c478bdstevel@tonic-gate
1547c478bdstevel@tonic-gate/*
1557c478bdstevel@tonic-gate * Return an allocated copy of str, with the Bourne shell's metacharacters
1567c478bdstevel@tonic-gate * escaped by '\'.
1577c478bdstevel@tonic-gate *
1587c478bdstevel@tonic-gate * What about unicode?
1597c478bdstevel@tonic-gate */
1607c478bdstevel@tonic-gatestatic char *
1617c478bdstevel@tonic-gatequote_for_shell(const char *str)
1627c478bdstevel@tonic-gate{
1637c478bdstevel@tonic-gate	const char *sp;
1647c478bdstevel@tonic-gate	char *dst, *dp;
1657c478bdstevel@tonic-gate	size_t dst_len;
1667c478bdstevel@tonic-gate
1677c478bdstevel@tonic-gate	const char * const metachars = ";&()|^<>\n \t\\\"\'`";
1687c478bdstevel@tonic-gate
1697c478bdstevel@tonic-gate	if (str[0] == '\0')
1707c478bdstevel@tonic-gate		return (strdup("\"\""));
1717c478bdstevel@tonic-gate
1727c478bdstevel@tonic-gate	dst_len = 0;
1737c478bdstevel@tonic-gate	for (sp = str; *sp != '\0'; ++sp) {
1747c478bdstevel@tonic-gate		++dst_len;
1757c478bdstevel@tonic-gate
1767c478bdstevel@tonic-gate		if (strchr(metachars, *sp) != NULL)
1777c478bdstevel@tonic-gate			++dst_len;
1787c478bdstevel@tonic-gate	}
1797c478bdstevel@tonic-gate
1807c478bdstevel@tonic-gate	if (sp - str == dst_len)
1817c478bdstevel@tonic-gate		return (strdup(str));
1827c478bdstevel@tonic-gate
1837c478bdstevel@tonic-gate	dst = safe_malloc(dst_len + 1);
1847c478bdstevel@tonic-gate
1857c478bdstevel@tonic-gate	for (dp = dst, sp = str; *sp != '\0'; ++dp, ++sp) {
1867c478bdstevel@tonic-gate		if (strchr(metachars, *sp) != NULL)
1877c478bdstevel@tonic-gate			*dp++ = '\\';
1887c478bdstevel@tonic-gate
1897c478bdstevel@tonic-gate		*dp = *sp;
1907c478bdstevel@tonic-gate	}
1917c478bdstevel@tonic-gate	*dp = '\0';
1927c478bdstevel@tonic-gate
1937c478bdstevel@tonic-gate	return (dst);
1947c478bdstevel@tonic-gate}
1957c478bdstevel@tonic-gate
1967c478bdstevel@tonic-gatestatic void
1977c478bdstevel@tonic-gateprint_value(scf_value_t *val)
1987c478bdstevel@tonic-gate{
1997c478bdstevel@tonic-gate	char *buf, *qbuf;
2007c478bdstevel@tonic-gate	ssize_t bufsz, r;
2017c478bdstevel@tonic-gate
2027c478bdstevel@tonic-gate	bufsz = scf_value_get_as_string(val, NULL, 0) + 1;
2037c478bdstevel@tonic-gate	if (bufsz - 1 < 0)
2047c478bdstevel@tonic-gate		scfdie();
2057c478bdstevel@tonic-gate
2067c478bdstevel@tonic-gate	buf = safe_malloc(bufsz);
2077c478bdstevel@tonic-gate
2087c478bdstevel@tonic-gate	r = scf_value_get_as_string(val, buf, bufsz);
2097c478bdstevel@tonic-gate	assert(r + 1 == bufsz);
2107c478bdstevel@tonic-gate
2117c478bdstevel@tonic-gate	qbuf = quote_for_shell(buf);
2127c478bdstevel@tonic-gate	(void) fputs(qbuf, stdout);
2137c478bdstevel@tonic-gate
2147c478bdstevel@tonic-gate	free(qbuf);
2157c478bdstevel@tonic-gate	free(buf);
2167c478bdstevel@tonic-gate}
2177c478bdstevel@tonic-gate
2187c478bdstevel@tonic-gate/*
2197c478bdstevel@tonic-gate * Display a property's values on a line.  If types is true, prepend
2207c478bdstevel@tonic-gate * identification (the FMRI if fmris is true, pg/prop otherwise) and the type
2217c478bdstevel@tonic-gate * of the property.
2227c478bdstevel@tonic-gate */
2237c478bdstevel@tonic-gatestatic void
2247c478bdstevel@tonic-gatedisplay_prop(scf_propertygroup_t *pg, scf_property_t *prop)
2257c478bdstevel@tonic-gate{
2267c478bdstevel@tonic-gate	scf_value_t *val;
2277c478bdstevel@tonic-gate	scf_iter_t *iter;
2283eae19dwesolows	int ret, first, err;
2293eae19dwesolows
2303eae19dwesolows	const char * const permission_denied_emsg =
2313eae19dwesolows	    gettext("Permission denied.\n");
2327c478bdstevel@tonic-gate
2337c478bdstevel@tonic-gate	if (types) {
2347c478bdstevel@tonic-gate		scf_type_t ty;
2357c478bdstevel@tonic-gate		char *buf;
2367c478bdstevel@tonic-gate		size_t buf_sz;
2377c478bdstevel@tonic-gate
2387c478bdstevel@tonic-gate		if (fmris) {
2397c478bdstevel@tonic-gate			buf_sz = max_scf_fmri_length + 1;
2407c478bdstevel@tonic-gate			buf = safe_malloc(buf_sz);
2417c478bdstevel@tonic-gate
2427c478bdstevel@tonic-gate			if (scf_property_to_fmri(prop, buf, buf_sz) == -1)
2437c478bdstevel@tonic-gate				scfdie();
2447c478bdstevel@tonic-gate			(void) fputs(buf, stdout);
2457c478bdstevel@tonic-gate
2467c478bdstevel@tonic-gate			free(buf);
2477c478bdstevel@tonic-gate		} else {
2487c478bdstevel@tonic-gate			buf_sz = max_scf_name_length + 1;
2497c478bdstevel@tonic-gate			buf = safe_malloc(buf_sz);
2507c478bdstevel@tonic-gate
2517c478bdstevel@tonic-gate			if (scf_pg_get_name(pg, buf, buf_sz) < 0)
2527c478bdstevel@tonic-gate				scfdie();
2537c478bdstevel@tonic-gate			(void) fputs(buf, stdout);
2547c478bdstevel@tonic-gate			(void) putchar('/');
2557c478bdstevel@tonic-gate
2567c478bdstevel@tonic-gate			if (scf_property_get_name(prop, buf, buf_sz) < 0)
2577c478bdstevel@tonic-gate				scfdie();
2587c478bdstevel@tonic-gate			(void) fputs(buf, stdout);
2597c478bdstevel@tonic-gate
2607c478bdstevel@tonic-gate			free(buf);
2617c478bdstevel@tonic-gate		}
2627c478bdstevel@tonic-gate
2637c478bdstevel@tonic-gate		(void) putchar(' ');
2647c478bdstevel@tonic-gate
2657c478bdstevel@tonic-gate		if (scf_property_type(prop, &ty) == -1)
2667c478bdstevel@tonic-gate			scfdie();
2677c478bdstevel@tonic-gate		(void) fputs(scf_type_to_string(ty), stdout);
2687c478bdstevel@tonic-gate		(void) putchar(' ');
2697c478bdstevel@tonic-gate	}
2707c478bdstevel@tonic-gate
2717c478bdstevel@tonic-gate	if ((iter = scf_iter_create(hndl)) == NULL ||
2727c478bdstevel@tonic-gate	    (val = scf_value_create(hndl)) == NULL)
2737c478bdstevel@tonic-gate		scfdie();
2747c478bdstevel@tonic-gate
2757c478bdstevel@tonic-gate	if (scf_iter_property_values(iter, prop) == -1)
2767c478bdstevel@tonic-gate		scfdie();
2777c478bdstevel@tonic-gate
2787c478bdstevel@tonic-gate	first = 1;
2797c478bdstevel@tonic-gate	while ((ret = scf_iter_next_value(iter, val)) == 1) {
2807c478bdstevel@tonic-gate		if (first)
2817c478bdstevel@tonic-gate			first = 0;
2827c478bdstevel@tonic-gate		else
2837c478bdstevel@tonic-gate			(void) putchar(' ');
2847c478bdstevel@tonic-gate		print_value(val);
2857c478bdstevel@tonic-gate	}
2863eae19dwesolows	if (ret == -1) {
2873eae19dwesolows		err = scf_error();
2883eae19dwesolows		if (err == SCF_ERROR_PERMISSION_DENIED) {
2893eae19dwesolows			if (uu_list_numnodes(prop_list) > 0)
2903eae19dwesolows				die(permission_denied_emsg);
2913eae19dwesolows		} else {
2923eae19dwesolows			scfdie();
2933eae19dwesolows		}
2943eae19dwesolows	}
2957c478bdstevel@tonic-gate
2967c478bdstevel@tonic-gate	(void) putchar('\n');
2977c478bdstevel@tonic-gate
2987c478bdstevel@tonic-gate	scf_iter_destroy(iter);
2997c478bdstevel@tonic-gate	(void) scf_value_destroy(val);
3007c478bdstevel@tonic-gate}
3017c478bdstevel@tonic-gate
3027c478bdstevel@tonic-gate/*
3037c478bdstevel@tonic-gate * display_prop() all of the properties in the given property group.  Force
3047c478bdstevel@tonic-gate * types to true so identification will be displayed.
3057c478bdstevel@tonic-gate */
3067c478bdstevel@tonic-gatestatic void
3077c478bdstevel@tonic-gatedisplay_pg(scf_propertygroup_t *pg)
3087c478bdstevel@tonic-gate{
3097c478bdstevel@tonic-gate	scf_property_t *prop;
3107c478bdstevel@tonic-gate	scf_iter_t *iter;
3117c478bdstevel@tonic-gate	int ret;
3127c478bdstevel@tonic-gate
3137c478bdstevel@tonic-gate	types = 1;	/* Always display types for whole propertygroups. */
3147c478bdstevel@tonic-gate
3157c478bdstevel@tonic-gate	if ((prop = scf_property_create(hndl)) == NULL ||
3167c478bdstevel@tonic-gate	    (iter = scf_iter_create(hndl)) == NULL)
3177c478bdstevel@tonic-gate		scfdie();
3187c478bdstevel@tonic-gate
3197c478bdstevel@tonic-gate	if (scf_iter_pg_properties(iter, pg) == -1)
3207c478bdstevel@tonic-gate		scfdie();
3217c478bdstevel@tonic-gate
3227c478bdstevel@tonic-gate	while ((ret = scf_iter_next_property(iter, prop)) == 1)
3237c478bdstevel@tonic-gate		display_prop(pg, prop);
3247c478bdstevel@tonic-gate	if (ret == -1)
3257c478bdstevel@tonic-gate		scfdie();
3267c478bdstevel@tonic-gate
3277c478bdstevel@tonic-gate	scf_iter_destroy(iter);
3287c478bdstevel@tonic-gate	scf_property_destroy(prop);
3297c478bdstevel@tonic-gate}
3307c478bdstevel@tonic-gate
3317c478bdstevel@tonic-gate/*
3327c478bdstevel@tonic-gate * Common code to execute when a nonexistant property is encountered.
3337c478bdstevel@tonic-gate */
3347c478bdstevel@tonic-gatestatic void
3357c478bdstevel@tonic-gatenoprop_common_action()
3367c478bdstevel@tonic-gate{
3377c478bdstevel@tonic-gate	if (!PRINT_NOPROP_ERRORS)
3387c478bdstevel@tonic-gate		/* We're not printing errors, so we can cut out early. */
3397c478bdstevel@tonic-gate		exit(UU_EXIT_FATAL);
3407c478bdstevel@tonic-gate
3417c478bdstevel@tonic-gate	return_code = UU_EXIT_FATAL;
3427c478bdstevel@tonic-gate}
3437c478bdstevel@tonic-gate
3447c478bdstevel@tonic-gate/*
3457c478bdstevel@tonic-gate * Iterate the properties of a service or an instance when no snapshot
3467c478bdstevel@tonic-gate * is specified.
3477c478bdstevel@tonic-gate */
3487c478bdstevel@tonic-gatestatic int
3497c478bdstevel@tonic-gatescf_iter_entity_pgs(scf_iter_t *iter, scf_entityp_t ent)
3507c478bdstevel@tonic-gate{
3517c478bdstevel@tonic-gate	int ret = 0;
3527c478bdstevel@tonic-gate
3537c478bdstevel@tonic-gate	if (ent.type) {
3547c478bdstevel@tonic-gate		/*
3557c478bdstevel@tonic-gate		 * If we are displaying properties for a service,
3567c478bdstevel@tonic-gate		 * treat it as though it were a composed, current
3577c478bdstevel@tonic-gate		 * lookup. (implicit cflag) However, if a snapshot
3587c478bdstevel@tonic-gate		 * was specified, fail.
3597c478bdstevel@tonic-gate		 */
3607c478bdstevel@tonic-gate		if (sflag)
3617c478bdstevel@tonic-gate			die(gettext("Only instances have "
3627c478bdstevel@tonic-gate			    "snapshots.\n"));
3637c478bdstevel@tonic-gate		ret = scf_iter_service_pgs(iter, ent.u.svc);
3647c478bdstevel@tonic-gate	} else {
3657c478bdstevel@tonic-gate		if (Cflag)
3667c478bdstevel@tonic-gate			ret = scf_iter_instance_pgs(iter, ent.u.inst);
3677c478bdstevel@tonic-gate		else
3687c478bdstevel@tonic-gate			ret = scf_iter_instance_pgs_composed(iter, ent.u.inst,
3697c478bdstevel@tonic-gate			    NULL);
3707c478bdstevel@tonic-gate	}
3717c478bdstevel@tonic-gate	return (ret);
3727c478bdstevel@tonic-gate}
3737c478bdstevel@tonic-gate
3747c478bdstevel@tonic-gate/*
3757c478bdstevel@tonic-gate * Return a snapshot for the supplied instance and snapshot name.
3767c478bdstevel@tonic-gate */
3777c478bdstevel@tonic-gatestatic scf_snapshot_t *
3787c478bdstevel@tonic-gateget_snapshot(const scf_instance_t *inst, const char *snapshot)
3797c478bdstevel@tonic-gate{
3807c478bdstevel@tonic-gate	scf_snapshot_t *snap = scf_snapshot_create(hndl);
3817c478bdstevel@tonic-gate
3827c478bdstevel@tonic-gate	if (snap == NULL)
3837c478bdstevel@tonic-gate		scfdie();
3847c478bdstevel@tonic-gate
3857c478bdstevel@tonic-gate	if (scf_instance_get_snapshot(inst, snapshot, snap) == -1) {
3867c478bdstevel@tonic-gate		switch (scf_error()) {
3877c478bdstevel@tonic-gate		case SCF_ERROR_INVALID_ARGUMENT:
3887c478bdstevel@tonic-gate			die(gettext("Invalid snapshot name.\n"));
3897c478bdstevel@tonic-gate			/* NOTREACHED */
3907c478bdstevel@tonic-gate
3917c478bdstevel@tonic-gate		case SCF_ERROR_NOT_FOUND:
3927c478bdstevel@tonic-gate			if (sflag == 0) {
3937c478bdstevel@tonic-gate				scf_snapshot_destroy(snap);
3947c478bdstevel@tonic-gate				snap = NULL;
3957c478bdstevel@tonic-gate			} else
3967c478bdstevel@tonic-gate				die(gettext("No such snapshot.\n"));
3977c478bdstevel@tonic-gate			break;
3987c478bdstevel@tonic-gate
3997c478bdstevel@tonic-gate		default:
4007c478bdstevel@tonic-gate			scfdie();
4017c478bdstevel@tonic-gate		}
4027c478bdstevel@tonic-gate	}
4037c478bdstevel@tonic-gate
4047c478bdstevel@tonic-gate	return (snap);
4057c478bdstevel@tonic-gate}
4067c478bdstevel@tonic-gate
4077c478bdstevel@tonic-gate/*
4087c478bdstevel@tonic-gate * Entity (service or instance): If there are -p options,
4097c478bdstevel@tonic-gate * display_{pg,prop}() the named property groups and/or properties.  Otherwise
4107c478bdstevel@tonic-gate * display_pg() all property groups.
4117c478bdstevel@tonic-gate */
4127c478bdstevel@tonic-gatestatic void
4137c478bdstevel@tonic-gateprocess_ent(scf_entityp_t ent)
4147c478bdstevel@tonic-gate{
4157c478bdstevel@tonic-gate	scf_snapshot_t *snap = NULL;
4167c478bdstevel@tonic-gate	scf_propertygroup_t *pg;
4177c478bdstevel@tonic-gate	scf_property_t *prop;
4187c478bdstevel@tonic-gate	scf_iter_t *iter;
4197c478bdstevel@tonic-gate	svcprop_prop_node_t *spn;
4207c478bdstevel@tonic-gate	int ret, err;
4217c478bdstevel@tonic-gate
4227c478bdstevel@tonic-gate	if (uu_list_numnodes(prop_list) == 0) {
4237c478bdstevel@tonic-gate		if (quiet)
4247c478bdstevel@tonic-gate			return;
4257c478bdstevel@tonic-gate
4267c478bdstevel@tonic-gate		if ((pg = scf_pg_create(hndl)) == NULL ||
4277c478bdstevel@tonic-gate		    (iter = scf_iter_create(hndl)) == NULL)
4287c478bdstevel@tonic-gate			scfdie();
4297c478bdstevel@tonic-gate
4307c478bdstevel@tonic-gate		if (cflag || Cflag || ent.type != ENT_INSTANCE) {
4317c478bdstevel@tonic-gate			if (scf_iter_entity_pgs(iter, ent) == -1)
4327c478bdstevel@tonic-gate				scfdie();
4337c478bdstevel@tonic-gate		} else {
4347c478bdstevel@tonic-gate			if (snapshot != NULL)
4357c478bdstevel@tonic-gate				snap = get_snapshot(ent.u.inst, snapshot);
4367c478bdstevel@tonic-gate
4377c478bdstevel@tonic-gate			if (scf_iter_instance_pgs_composed(iter, ent.u.inst,
4387c478bdstevel@tonic-gate			    snap) == -1)
4397c478bdstevel@tonic-gate				scfdie();
4407c478bdstevel@tonic-gate			if (snap)
4417c478bdstevel@tonic-gate				scf_snapshot_destroy(snap);
4427c478bdstevel@tonic-gate		}
4437c478bdstevel@tonic-gate
4447c478bdstevel@tonic-gate		while ((ret = scf_iter_next_pg(iter, pg)) == 1)
4457c478bdstevel@tonic-gate			display_pg(pg);
4467c478bdstevel@tonic-gate		if (ret == -1)
4477c478bdstevel@tonic-gate			scfdie();
4487c478bdstevel@tonic-gate
4497c478bdstevel@tonic-gate		/*
4507c478bdstevel@tonic-gate		 * In normal usage, i.e. against the running snapshot,
4517c478bdstevel@tonic-gate		 * we must iterate over the current non-persistent
4527c478bdstevel@tonic-gate		 * pg's.
4537c478bdstevel@tonic-gate		 */
4547c478bdstevel@tonic-gate		if (sflag == 0 && snap != NULL) {
4557c478bdstevel@tonic-gate			scf_iter_reset(iter);
4567c478bdstevel@tonic-gate			if (scf_iter_instance_pgs_composed(iter, ent.u.inst,
4577c478bdstevel@tonic-gate			    NULL) == -1)
4587c478bdstevel@tonic-gate				scfdie();
4597c478bdstevel@tonic-gate			while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
4607c478bdstevel@tonic-gate				uint32_t flags;
4617c478bdstevel@tonic-gate
4627c478bdstevel@tonic-gate				if (scf_pg_get_flags(pg, &flags) == -1)
4637c478bdstevel@tonic-gate					scfdie();
4647c478bdstevel@tonic-gate				if (flags & SCF_PG_FLAG_NONPERSISTENT)
4657c478bdstevel@tonic-gate					display_pg(pg);
4667c478bdstevel@tonic-gate			}
4677c478bdstevel@tonic-gate		}
4687c478bdstevel@tonic-gate		if (ret == -1)
4697c478bdstevel@tonic-gate			scfdie();
4707c478bdstevel@tonic-gate
4717c478bdstevel@tonic-gate		scf_iter_destroy(iter);
4727c478bdstevel@tonic-gate		scf_pg_destroy(pg);
4737c478bdstevel@tonic-gate
4747c478bdstevel@tonic-gate		return;
4757c478bdstevel@tonic-gate	}
4767c478bdstevel@tonic-gate
4777c478bdstevel@tonic-gate	if ((pg = scf_pg_create(hndl)) == NULL ||
4787c478bdstevel@tonic-gate	    (prop = scf_property_create(hndl)) == NULL)
4797c478bdstevel@tonic-gate		scfdie();
4807c478bdstevel@tonic-gate
4817c478bdstevel@tonic-gate	if (ent.type == ENT_INSTANCE && snapshot != NULL)
4827c478bdstevel@tonic-gate		snap = get_snapshot(ent.u.inst, snapshot);
4837c478bdstevel@tonic-gate
4847c478bdstevel@tonic-gate	for (spn = uu_list_first(prop_list);
4857c478bdstevel@tonic-gate	    spn != NULL;
4867c478bdstevel@tonic-gate	    spn = uu_list_next(prop_list, spn)) {
4877c478bdstevel@tonic-gate		if (ent.type == ENT_INSTANCE) {
4887c478bdstevel@tonic-gate			if (Cflag)
4897c478bdstevel@tonic-gate				ret = scf_instance_get_pg(ent.u.inst,
4907c478bdstevel@tonic-gate				    spn->spn_comp1, pg);
4917c478bdstevel@tonic-gate			else
4927c478bdstevel@tonic-gate				ret = scf_instance_get_pg_composed(ent.u.inst,
4937c478bdstevel@tonic-gate				    snap, spn->spn_comp1, pg);
4947c478bdstevel@tonic-gate			err = scf_error();
4957c478bdstevel@tonic-gate
4967c478bdstevel@tonic-gate			/*
4977c478bdstevel@tonic-gate			 * If we didn't find it in the specified snapshot, use
4987c478bdstevel@tonic-gate			 * the current values if the pg is nonpersistent.
4997c478bdstevel@tonic-gate			 */
5007c478bdstevel@tonic-gate			if (ret == -1 && !Cflag &&snap != NULL && err ==
5017c478bdstevel@tonic-gate			    SCF_ERROR_NOT_FOUND) {
5027c478bdstevel@tonic-gate				ret = scf_instance_get_pg_composed(
5037c478bdstevel@tonic-gate				    ent.u.inst, NULL, spn->spn_comp1,
5047c478bdstevel@tonic-gate				    pg);
5057c478bdstevel@tonic-gate
5067c478bdstevel@tonic-gate				if (ret == 0) {
5077c478bdstevel@tonic-gate					uint32_t flags;
5087c478bdstevel@tonic-gate
5097c478bdstevel@tonic-gate					if (scf_pg_get_flags(pg, &flags) == -1)
5107c478bdstevel@tonic-gate						scfdie();
5117c478bdstevel@tonic-gate					if ((flags & SCF_PG_FLAG_NONPERSISTENT)
5127c478bdstevel@tonic-gate					    == 0) {
5137c478bdstevel@tonic-gate						ret = -1;
5147c478bdstevel@tonic-gate					}
5157c478bdstevel@tonic-gate				}
5167c478bdstevel@tonic-gate			}
5177c478bdstevel@tonic-gate		} else {
5187c478bdstevel@tonic-gate			/*
5197c478bdstevel@tonic-gate			 * If we are displaying properties for a service,
5207c478bdstevel@tonic-gate			 * treat it as though it were a composed, current
5217c478bdstevel@tonic-gate			 * lookup. (implicit cflag) However, if a snapshot
5227c478bdstevel@tonic-gate			 * was specified, fail.
5237c478bdstevel@tonic-gate			 */
5247c478bdstevel@tonic-gate			if (sflag)
5257c478bdstevel@tonic-gate				die(gettext("Only instances have "
5267c478bdstevel@tonic-gate				    "snapshots.\n"));
5277c478bdstevel@tonic-gate			ret = scf_entity_get_pg(ent, spn->spn_comp1, pg);
5287c478bdstevel@tonic-gate			err = scf_error();
5297c478bdstevel@tonic-gate		}
5307c478bdstevel@tonic-gate		if (ret == -1) {
5317c478bdstevel@tonic-gate			if (err != SCF_ERROR_NOT_FOUND)
5327c478bdstevel@tonic-gate				scfdie();
5337c478bdstevel@tonic-gate
5347c478bdstevel@tonic-gate			if (PRINT_NOPROP_ERRORS) {
5357c478bdstevel@tonic-gate				char *buf;
5367c478bdstevel@tonic-gate
5377c478bdstevel@tonic-gate				buf = safe_malloc(max_scf_fmri_length + 1);
5387c478bdstevel@tonic-gate				if (scf_entity_to_fmri(ent, buf,
5397c478bdstevel@tonic-gate				    max_scf_fmri_length + 1) == -1)
5407c478bdstevel@tonic-gate					scfdie();
5417c478bdstevel@tonic-gate
5427c478bdstevel@tonic-gate				uu_warn(gettext("Couldn't find property group "
5437c478bdstevel@tonic-gate				    "`%s' for %s `%s'.\n"), spn->spn_comp1,
5447c478bdstevel@tonic-gate				    SCF_ENTITY_TYPE_NAME(ent), buf);
5457c478bdstevel@tonic-gate
5467c478bdstevel@tonic-gate				free(buf);
5477c478bdstevel@tonic-gate			}
5487c478bdstevel@tonic-gate
5497c478bdstevel@tonic-gate			noprop_common_action();
5507c478bdstevel@tonic-gate
5517c478bdstevel@tonic-gate			continue;
5527c478bdstevel@tonic-gate		}
5537c478bdstevel@tonic-gate
5547c478bdstevel@tonic-gate		if (spn->spn_comp2 == NULL) {
5557c478bdstevel@tonic-gate			if (!quiet)
5567c478bdstevel@tonic-gate				display_pg(pg);
5577c478bdstevel@tonic-gate			continue;
5587c478bdstevel@tonic-gate		}
5597c478bdstevel@tonic-gate
5607c478bdstevel@tonic-gate		if (scf_pg_get_property(pg, spn->spn_comp2, prop) == -1) {
5617c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_NOT_FOUND)
5627c478bdstevel@tonic-gate				scfdie();
5637c478bdstevel@tonic-gate
5647c478bdstevel@tonic-gate			if (PRINT_NOPROP_ERRORS) {
5657c478bdstevel@tonic-gate				char *buf;
5667c478bdstevel@tonic-gate
5677c478bdstevel@tonic-gate				buf = safe_malloc(max_scf_fmri_length + 1);
5687c478bdstevel@tonic-gate				if (scf_entity_to_fmri(ent, buf,
5697c478bdstevel@tonic-gate				    max_scf_fmri_length + 1) == -1)
5707c478bdstevel@tonic-gate					scfdie();
5717c478bdstevel@tonic-gate
5727c478bdstevel@tonic-gate				/* FMRI syntax knowledge */
5737c478bdstevel@tonic-gate				uu_warn(gettext("Couldn't find property "
5747c478bdstevel@tonic-gate				    "`%s/%s' for %s `%s'.\n"), spn->spn_comp1,
5757c478bdstevel@tonic-gate				    spn->spn_comp2, SCF_ENTITY_TYPE_NAME(ent),
5767c478bdstevel@tonic-gate				    buf);
5777c478bdstevel@tonic-gate
5787c478bdstevel@tonic-gate				free(buf);
5797c478bdstevel@tonic-gate			}
5807c478bdstevel@tonic-gate
5817c478bdstevel@tonic-gate			noprop_common_action();
5827c478bdstevel@tonic-gate
5837c478bdstevel@tonic-gate			continue;
5847c478bdstevel@tonic-gate		}
5857c478bdstevel@tonic-gate
5867c478bdstevel@tonic-gate		if (!quiet)
5877c478bdstevel@tonic-gate			display_prop(pg, prop);
5887c478bdstevel@tonic-gate	}
5897c478bdstevel@tonic-gate
5907c478bdstevel@tonic-gate	scf_property_destroy(prop);
5917c478bdstevel@tonic-gate	scf_pg_destroy(pg);
5927c478bdstevel@tonic-gate	if (snap)
5937c478bdstevel@tonic-gate		scf_snapshot_destroy(snap);
5947c478bdstevel@tonic-gate}
5957c478bdstevel@tonic-gate
5967c478bdstevel@tonic-gate/*
5977c478bdstevel@tonic-gate * Without -p options, just call display_pg().  Otherwise display_prop() the
5987c478bdstevel@tonic-gate * named properties of the property group.
5997c478bdstevel@tonic-gate */
6007c478bdstevel@tonic-gatestatic void
6017c478bdstevel@tonic-gateprocess_pg(scf_propertygroup_t *pg)
6027c478bdstevel@tonic-gate{
6037c478bdstevel@tonic-gate	scf_property_t *prop;
6047c478bdstevel@tonic-gate	svcprop_prop_node_t *spn;
6057c478bdstevel@tonic-gate
6067c478bdstevel@tonic-gate	if (uu_list_first(prop_list) == NULL) {
6077c478bdstevel@tonic-gate		if (quiet)
6087c478bdstevel@tonic-gate			return;
6097c478bdstevel@tonic-gate
6107c478bdstevel@tonic-gate		display_pg(pg);
6117c478bdstevel@tonic-gate		return;
6127c478bdstevel@tonic-gate	}
6137c478bdstevel@tonic-gate
6147c478bdstevel@tonic-gate	prop = scf_property_create(hndl);
6157c478bdstevel@tonic-gate	if (prop == NULL)
6167c478bdstevel@tonic-gate		scfdie();
6177c478bdstevel@tonic-gate
6187c478bdstevel@tonic-gate	for (spn = uu_list_first(prop_list);
6197c478bdstevel@tonic-gate	    spn != NULL;
6207c478bdstevel@tonic-gate	    spn = uu_list_next(prop_list, spn)) {
6217c478bdstevel@tonic-gate		if (spn->spn_comp2 != NULL) {
6227c478bdstevel@tonic-gate			char *buf;
6237c478bdstevel@tonic-gate
6247c478bdstevel@tonic-gate			buf = safe_malloc(max_scf_fmri_length + 1);
6257c478bdstevel@tonic-gate			if (scf_pg_to_fmri(pg, buf, max_scf_fmri_length + 1) ==
6267c478bdstevel@tonic-gate			    -1)
6277c478bdstevel@tonic-gate				scfdie();
6287c478bdstevel@tonic-gate
6297c478bdstevel@tonic-gate			uu_xdie(UU_EXIT_USAGE, gettext("-p argument `%s/%s' "
6307c478bdstevel@tonic-gate			    "has too many components for property "
6317c478bdstevel@tonic-gate			    "group `%s'.\n"), spn->spn_comp1, spn->spn_comp2,
6327c478bdstevel@tonic-gate			    buf);
6337c478bdstevel@tonic-gate		}
6347c478bdstevel@tonic-gate
6357c478bdstevel@tonic-gate		if (scf_pg_get_property(pg, spn->spn_comp1, prop) == 0) {
6367c478bdstevel@tonic-gate			if (!quiet)
6377c478bdstevel@tonic-gate				display_prop(pg, prop);
6387c478bdstevel@tonic-gate			continue;
6397c478bdstevel@tonic-gate		}
6407c478bdstevel@tonic-gate
6417c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_NOT_FOUND)
6427c478bdstevel@tonic-gate			scfdie();
6437c478bdstevel@tonic-gate
6447c478bdstevel@tonic-gate		if (PRINT_NOPROP_ERRORS) {
6457c478bdstevel@tonic-gate			char *buf;
6467c478bdstevel@tonic-gate
6477c478bdstevel@tonic-gate			buf = safe_malloc(max_scf_fmri_length + 1);
6487c478bdstevel@tonic-gate			if (scf_pg_to_fmri(pg, buf, max_scf_fmri_length + 1) ==
6497c478bdstevel@tonic-gate			    -1)
6507c478bdstevel@tonic-gate				scfdie();
6517c478bdstevel@tonic-gate
6527c478bdstevel@tonic-gate			uu_warn(gettext("Couldn't find property `%s' in "
6537c478bdstevel@tonic-gate			    "property group `%s'.\n"), spn->spn_comp1, buf);
6547c478bdstevel@tonic-gate
6557c478bdstevel@tonic-gate			free(buf);
6567c478bdstevel@tonic-gate		}
6577c478bdstevel@tonic-gate
6587c478bdstevel@tonic-gate		noprop_common_action();
6597c478bdstevel@tonic-gate	}
6607c478bdstevel@tonic-gate}
6617c478bdstevel@tonic-gate
6627c478bdstevel@tonic-gate/*
6637c478bdstevel@tonic-gate * If there are -p options, show the error.  Otherwise just call
6647c478bdstevel@tonic-gate * display_prop().
6657c478bdstevel@tonic-gate */
6667c478bdstevel@tonic-gatestatic void
6677c478bdstevel@tonic-gateprocess_prop(scf_propertygroup_t *pg, scf_property_t *prop)
6687c478bdstevel@tonic-gate{
6697c478bdstevel@tonic-gate	if (uu_list_first(prop_list) != NULL) {
6707c478bdstevel@tonic-gate		uu_warn(gettext("The -p option cannot be used with property "
6717c478bdstevel@tonic-gate		    "operands.\n"));
6727c478bdstevel@tonic-gate		usage();
6737c478bdstevel@tonic-gate	}
6747c478bdstevel@tonic-gate
6757c478bdstevel@tonic-gate	if (quiet)
6767c478bdstevel@tonic-gate		return;
6777c478bdstevel@tonic-gate
6787c478bdstevel@tonic-gate	display_prop(pg, prop);
6797c478bdstevel@tonic-gate}
6807c478bdstevel@tonic-gate
6817c478bdstevel@tonic-gate/* Decode an operand & dispatch. */
6827c478bdstevel@tonic-gate/* ARGSUSED */
6837c478bdstevel@tonic-gatestatic int
6847c478bdstevel@tonic-gateprocess_fmri(void *unused, scf_walkinfo_t *wip)
6857c478bdstevel@tonic-gate{
6867c478bdstevel@tonic-gate	scf_entityp_t ent;
6877c478bdstevel@tonic-gate
6887c478bdstevel@tonic-gate	/* Multiple matches imply multiple entities. */
6897c478bdstevel@tonic-gate	if (wip->count > 1)
6907c478bdstevel@tonic-gate		types = fmris = 1;
6917c478bdstevel@tonic-gate
6927c478bdstevel@tonic-gate	if (wip->prop != NULL) {
6937c478bdstevel@tonic-gate		process_prop(wip->pg, wip->prop);
6947c478bdstevel@tonic-gate	} else if (wip->pg != NULL) {
6957c478bdstevel@tonic-gate		process_pg(wip->pg);
6967c478bdstevel@tonic-gate	} else if (wip->inst != NULL) {
6977c478bdstevel@tonic-gate		SCF_ENTITY_SET_TO_INSTANCE(ent, wip->inst);
6987c478bdstevel@tonic-gate		process_ent(ent);
6997c478bdstevel@tonic-gate	} else {
7007c478bdstevel@tonic-gate		/* scf_walk_fmri() won't let this happen */
7017c478bdstevel@tonic-gate		assert(wip->svc != NULL);
7027c478bdstevel@tonic-gate		SCF_ENTITY_SET_TO_SERVICE(ent, wip->svc);
7037c478bdstevel@tonic-gate		process_ent(ent);
7047c478bdstevel@tonic-gate	}
7057c478bdstevel@tonic-gate
7067c478bdstevel@tonic-gate	return (0);
7077c478bdstevel@tonic-gate}
7087c478bdstevel@tonic-gate
7097c478bdstevel@tonic-gatestatic void
7107c478bdstevel@tonic-gateadd_prop(char *property)
7117c478bdstevel@tonic-gate{
7127c478bdstevel@tonic-gate	svcprop_prop_node_t *p, *last;
7137c478bdstevel@tonic-gate	char *slash;
7147c478bdstevel@tonic-gate
7157c478bdstevel@tonic-gate	const char * const invalid_component_emsg =
7167c478bdstevel@tonic-gate	    gettext("Invalid component name `%s'.\n");
7177c478bdstevel@tonic-gate
7187c478bdstevel@tonic-gate	/* FMRI syntax knowledge. */
7197c478bdstevel@tonic-gate	slash = strchr(property, '/');
7207c478bdstevel@tonic-gate	if (slash != NULL) {
7217c478bdstevel@tonic-gate		if (strchr(slash + 1, '/') != NULL) {
7227c478bdstevel@tonic-gate			uu_warn(gettext("-p argument `%s' has too many "
7237c478bdstevel@tonic-gate			    "components.\n"), property);
7247c478bdstevel@tonic-gate			usage();
7257c478bdstevel@tonic-gate		}
7267c478bdstevel@tonic-gate	}
7277c478bdstevel@tonic-gate
7287c478bdstevel@tonic-gate	if (slash != NULL)
7297c478bdstevel@tonic-gate		*slash = '\0';
7307c478bdstevel@tonic-gate
7317c478bdstevel@tonic-gate	p = safe_malloc(sizeof (svcprop_prop_node_t));
7327c478bdstevel@tonic-gate	uu_list_node_init(p, &p->spn_list_node, prop_pool);
7337c478bdstevel@tonic-gate
7347c478bdstevel@tonic-gate	p->spn_comp1 = property;
7357c478bdstevel@tonic-gate	p->spn_comp2 = (slash == NULL) ? NULL : slash + 1;
7367c478bdstevel@tonic-gate
7377c478bdstevel@tonic-gate	if (uu_check_name(p->spn_comp1, UU_NAME_DOMAIN) == -1)
7387c478bdstevel@tonic-gate		uu_xdie(UU_EXIT_USAGE, invalid_component_emsg, p->spn_comp1);
7397c478bdstevel@tonic-gate	if (p->spn_comp2 != NULL &&
7407c478bdstevel@tonic-gate	    uu_check_name(p->spn_comp2, UU_NAME_DOMAIN) == -1)
7417c478bdstevel@tonic-gate		uu_xdie(UU_EXIT_USAGE, invalid_component_emsg, p->spn_comp2);
7427c478bdstevel@tonic-gate
7437c478bdstevel@tonic-gate	last = uu_list_last(prop_list);
7447c478bdstevel@tonic-gate	if (last != NULL) {
7457c478bdstevel@tonic-gate		if ((last->spn_comp2 == NULL) ^ (p->spn_comp2 == NULL)) {
7467c478bdstevel@tonic-gate			/*
7477c478bdstevel@tonic-gate			 * The -p options have mixed numbers of components.
7487c478bdstevel@tonic-gate			 * If they both turn out to be valid, then the
7497c478bdstevel@tonic-gate			 * single-component ones will specify property groups,
7507c478bdstevel@tonic-gate			 * so we need to turn on types to keep the output of
7517c478bdstevel@tonic-gate			 * display_prop() consistent with display_pg().
7527c478bdstevel@tonic-gate			 */
7537c478bdstevel@tonic-gate			types = 1;
7547c478bdstevel@tonic-gate		}
7557c478bdstevel@tonic-gate	}
7567c478bdstevel@tonic-gate
7577c478bdstevel@tonic-gate	(void) uu_list_insert_after(prop_list, NULL, p);
7587c478bdstevel@tonic-gate}
7597c478bdstevel@tonic-gate
7607c478bdstevel@tonic-gate
7617c478bdstevel@tonic-gate/*
7627c478bdstevel@tonic-gate * Wait for a property group or property change.
7637c478bdstevel@tonic-gate *
7647c478bdstevel@tonic-gate * Extract a pg and optionally a property name from fmri & prop_list.
7657c478bdstevel@tonic-gate * _scf_pg_wait() for the pg, and display_pg(pg) or display_prop(pg, prop)
7667c478bdstevel@tonic-gate * when it returns.
7677c478bdstevel@tonic-gate */
7687c478bdstevel@tonic-gate/* ARGSUSED */
7697c478bdstevel@tonic-gatestatic int
7707c478bdstevel@tonic-gatedo_wait(void *unused, scf_walkinfo_t *wip)
7717c478bdstevel@tonic-gate{
7727c478bdstevel@tonic-gate	scf_property_t *prop;
7737c478bdstevel@tonic-gate	scf_propertygroup_t *lpg, *pg;
7747c478bdstevel@tonic-gate	const char *propname;
7757c478bdstevel@tonic-gate	svcprop_prop_node_t *p;
7767c478bdstevel@tonic-gate
7777c478bdstevel@tonic-gate	const char *emsg_not_found = gettext("Not found.\n");
7787c478bdstevel@tonic-gate
7797c478bdstevel@tonic-gate	if ((lpg = scf_pg_create(hndl)) == NULL ||
7807c478bdstevel@tonic-gate	    (prop = scf_property_create(hndl)) == NULL)
7817c478bdstevel@tonic-gate		scfdie();
7827c478bdstevel@tonic-gate
7837c478bdstevel@tonic-gate	if (wip->prop != NULL) {
7847c478bdstevel@tonic-gate		if (uu_list_numnodes(prop_list) > 0)
7857c478bdstevel@tonic-gate			uu_xdie(UU_EXIT_USAGE, gettext("-p cannot be used with "
7867c478bdstevel@tonic-gate			    "property FMRIs.\n"));
7877c478bdstevel@tonic-gate		pg = wip->pg;
7887c478bdstevel@tonic-gate
7897c478bdstevel@tonic-gate		assert(strrchr(wip->fmri, '/') != NULL);
7907c478bdstevel@tonic-gate		propname = strrchr(wip->fmri, '/') + 1;
7917c478bdstevel@tonic-gate
7927c478bdstevel@tonic-gate	} else if (wip->pg != NULL) {
7937c478bdstevel@tonic-gate		p = uu_list_first(prop_list);
7947c478bdstevel@tonic-gate
7957c478bdstevel@tonic-gate		if (p != NULL) {
7967c478bdstevel@tonic-gate			if (p->spn_comp2 != NULL)
7977c478bdstevel@tonic-gate				uu_xdie(UU_EXIT_USAGE, gettext("-p argument "
7987c478bdstevel@tonic-gate				    "\"%s/%s\" has too many components for "
7997c478bdstevel@tonic-gate				    "property group %s.\n"),
8007c478bdstevel@tonic-gate				    p->spn_comp1, p->spn_comp2, wip->fmri);
8017c478bdstevel@tonic-gate
8027c478bdstevel@tonic-gate			propname = p->spn_comp1;
8037c478bdstevel@tonic-gate
8047c478bdstevel@tonic-gate			if (scf_pg_get_property(wip->pg, propname, prop) !=
8057c478bdstevel@tonic-gate			    SCF_SUCCESS) {
8067c478bdstevel@tonic-gate				switch (scf_error()) {
8077c478bdstevel@tonic-gate				case SCF_ERROR_INVALID_ARGUMENT:
8087c478bdstevel@tonic-gate					uu_xdie(UU_EXIT_USAGE,
8097c478bdstevel@tonic-gate					    gettext("Invalid property name "
8107c478bdstevel@tonic-gate					    "\"%s\".\n"), propname);
8117c478bdstevel@tonic-gate
8127c478bdstevel@tonic-gate					/* NOTREACHED */
8137c478bdstevel@tonic-gate
8147c478bdstevel@tonic-gate				case SCF_ERROR_NOT_FOUND:
8157c478bdstevel@tonic-gate					die(emsg_not_found);
8167c478bdstevel@tonic-gate
8177c478bdstevel@tonic-gate				default:
8187c478bdstevel@tonic-gate					scfdie();
8197c478bdstevel@tonic-gate				}
8207c478bdstevel@tonic-gate			}
8217c478bdstevel@tonic-gate		} else {
8227c478bdstevel@tonic-gate			propname = NULL;
8237c478bdstevel@tonic-gate		}
8247c478bdstevel@tonic-gate
8257c478bdstevel@tonic-gate		pg = wip->pg;
8267c478bdstevel@tonic-gate
8277c478bdstevel@tonic-gate	} else if (wip->inst != NULL) {
8287c478bdstevel@tonic-gate
8297c478bdstevel@tonic-gate		p = uu_list_first(prop_list);
8307c478bdstevel@tonic-gate		if (p == NULL)
8317c478bdstevel@tonic-gate			uu_xdie(UU_EXIT_USAGE,
8327c478bdstevel@tonic-gate			    gettext("Cannot wait for an instance.\n"));
8337c478bdstevel@tonic-gate
8347c478bdstevel@tonic-gate		if (scf_instance_get_pg(wip->inst, p->spn_comp1, lpg) !=
8357c478bdstevel@tonic-gate		    SCF_SUCCESS) {
8367c478bdstevel@tonic-gate			switch (scf_error()) {
8377c478bdstevel@tonic-gate			case SCF_ERROR_INVALID_ARGUMENT:
8387c478bdstevel@tonic-gate				uu_xdie(UU_EXIT_USAGE, gettext("Invalid "
8397c478bdstevel@tonic-gate				    "property group name \"%s\".\n"),
8407c478bdstevel@tonic-gate				    p->spn_comp1);
841a5f0d1fToomas Soome				/* NOTREACHED */
8427c478bdstevel@tonic-gate
8437c478bdstevel@tonic-gate			case SCF_ERROR_NOT_FOUND:
8447c478bdstevel@tonic-gate				die(emsg_not_found);
8457c478bdstevel@tonic-gate
8467c478bdstevel@tonic-gate			default:
8477c478bdstevel@tonic-gate				scfdie();
8487c478bdstevel@tonic-gate			}
8497c478bdstevel@tonic-gate		}
8507c478bdstevel@tonic-gate
8517c478bdstevel@tonic-gate		propname = p->spn_comp2;
8527c478bdstevel@tonic-gate
8537c478bdstevel@tonic-gate		if (propname != NULL) {
8547c478bdstevel@tonic-gate			if (scf_pg_get_property(lpg, propname, prop) !=
8557c478bdstevel@tonic-gate			    SCF_SUCCESS) {
8567c478bdstevel@tonic-gate				switch (scf_error()) {
8577c478bdstevel@tonic-gate				case SCF_ERROR_INVALID_ARGUMENT:
8587c478bdstevel@tonic-gate					uu_xdie(UU_EXIT_USAGE,
8597c478bdstevel@tonic-gate					    gettext("Invalid property name "
8607c478bdstevel@tonic-gate					    "\"%s\".\n"), propname);
861a5f0d1fToomas Soome					/* NOTREACHED */
8627c478bdstevel@tonic-gate
8637c478bdstevel@tonic-gate				case SCF_ERROR_NOT_FOUND:
8647c478bdstevel@tonic-gate					die(emsg_not_found);
8657c478bdstevel@tonic-gate
8667c478bdstevel@tonic-gate				default:
8677c478bdstevel@tonic-gate					scfdie();
8687c478bdstevel@tonic-gate				}
8697c478bdstevel@tonic-gate			}
8707c478bdstevel@tonic-gate		}
8717c478bdstevel@tonic-gate
8727c478bdstevel@tonic-gate		pg = lpg;
8737c478bdstevel@tonic-gate
8747c478bdstevel@tonic-gate	} else if (wip->svc != NULL) {
8757c478bdstevel@tonic-gate
8767c478bdstevel@tonic-gate		p = uu_list_first(prop_list);
8777c478bdstevel@tonic-gate		if (p == NULL)
8787c478bdstevel@tonic-gate			uu_xdie(UU_EXIT_USAGE,
8797c478bdstevel@tonic-gate			    gettext("Cannot wait for a service.\n"));
8807c478bdstevel@tonic-gate
8817c478bdstevel@tonic-gate		if (scf_service_get_pg(wip->svc, p->spn_comp1, lpg) !=
8827c478bdstevel@tonic-gate		    SCF_SUCCESS) {
8837c478bdstevel@tonic-gate			switch (scf_error()) {
8847c478bdstevel@tonic-gate			case SCF_ERROR_INVALID_ARGUMENT:
8857c478bdstevel@tonic-gate				uu_xdie(UU_EXIT_USAGE, gettext("Invalid "
8867c478bdstevel@tonic-gate				    "property group name \"%s\".\n"),
8877c478bdstevel@tonic-gate				    p->spn_comp1);
888a5f0d1fToomas Soome				/* NOTREACHED */
8897c478bdstevel@tonic-gate
8907c478bdstevel@tonic-gate			case SCF_ERROR_NOT_FOUND:
8917c478bdstevel@tonic-gate				die(emsg_not_found);
8927c478bdstevel@tonic-gate
8937c478bdstevel@tonic-gate			default:
8947c478bdstevel@tonic-gate				scfdie();
8957c478bdstevel@tonic-gate			}
8967c478bdstevel@tonic-gate		}
8977c478bdstevel@tonic-gate
8987c478bdstevel@tonic-gate		propname = p->spn_comp2;
8997c478bdstevel@tonic-gate
9007c478bdstevel@tonic-gate		if (propname != NULL) {
9017c478bdstevel@tonic-gate			if (scf_pg_get_property(lpg, propname, prop) !=
9027c478bdstevel@tonic-gate			    SCF_SUCCESS) {
9037c478bdstevel@tonic-gate				switch (scf_error()) {
9047c478bdstevel@tonic-gate				case SCF_ERROR_INVALID_ARGUMENT:
9057c478bdstevel@tonic-gate					uu_xdie(UU_EXIT_USAGE,
9067c478bdstevel@tonic-gate					    gettext("Invalid property name "
9077c478bdstevel@tonic-gate					    "\"%s\".\n"), propname);
9087c478bdstevel@tonic-gate
9097c478bdstevel@tonic-gate					/* NOTREACHED */
9107c478bdstevel@tonic-gate
9117c478bdstevel@tonic-gate				case SCF_ERROR_NOT_FOUND:
9127c478bdstevel@tonic-gate					die(emsg_not_found);
9137c478bdstevel@tonic-gate
9147c478bdstevel@tonic-gate				default:
9157c478bdstevel@tonic-gate					scfdie();
9167c478bdstevel@tonic-gate				}
9177c478bdstevel@tonic-gate			}
9187c478bdstevel@tonic-gate		}
9197c478bdstevel@tonic-gate
9207c478bdstevel@tonic-gate		pg = lpg;
9217c478bdstevel@tonic-gate
9227c478bdstevel@tonic-gate	} else {
9237c478bdstevel@tonic-gate		uu_xdie(UU_EXIT_USAGE, gettext("FMRI must specify an entity, "
9247c478bdstevel@tonic-gate		    "property group, or property.\n"));
9257c478bdstevel@tonic-gate	}
9267c478bdstevel@tonic-gate
9277c478bdstevel@tonic-gate	for (;;) {
9287c478bdstevel@tonic-gate		int ret;
9297c478bdstevel@tonic-gate
9307c478bdstevel@tonic-gate		ret = _scf_pg_wait(pg, -1);
9317c478bdstevel@tonic-gate		if (ret != SCF_SUCCESS)
9327c478bdstevel@tonic-gate			scfdie();
9337c478bdstevel@tonic-gate
9347c478bdstevel@tonic-gate		ret = scf_pg_update(pg);
9357c478bdstevel@tonic-gate		if (ret < 0) {
9367c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_DELETED)
9377c478bdstevel@tonic-gate				scfdie();
9387c478bdstevel@tonic-gate
9397c478bdstevel@tonic-gate			die(emsg_not_found);
9407c478bdstevel@tonic-gate		}
9417c478bdstevel@tonic-gate		if (ret == SCF_COMPLETE)
9427c478bdstevel@tonic-gate			break;
9437c478bdstevel@tonic-gate	}
9447c478bdstevel@tonic-gate
9457c478bdstevel@tonic-gate	if (propname != NULL) {
9467c478bdstevel@tonic-gate		if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) {
9477c478bdstevel@tonic-gate			if (!quiet)
9487c478bdstevel@tonic-gate				display_prop(pg, prop);
9497c478bdstevel@tonic-gate		} else {
9507c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_NOT_FOUND)
9517c478bdstevel@tonic-gate				scfdie();
9527c478bdstevel@tonic-gate
9537c478bdstevel@tonic-gate			if (PRINT_NOPROP_ERRORS)
9547c478bdstevel@tonic-gate				uu_warn(emsg_not_found);
9557c478bdstevel@tonic-gate
9567c478bdstevel@tonic-gate			return_code = UU_EXIT_FATAL;
9577c478bdstevel@tonic-gate		}
9587c478bdstevel@tonic-gate	} else {
9597c478bdstevel@tonic-gate		if (!quiet)
9607c478bdstevel@tonic-gate			display_pg(pg);
9617c478bdstevel@tonic-gate	}
9627c478bdstevel@tonic-gate
9637c478bdstevel@tonic-gate	scf_property_destroy(prop);
9647c478bdstevel@tonic-gate	scf_pg_destroy(lpg);
9657c478bdstevel@tonic-gate
9667c478bdstevel@tonic-gate	return (0);
9677c478bdstevel@tonic-gate}
9687c478bdstevel@tonic-gate
9697c478bdstevel@tonic-gate/*
9707c478bdstevel@tonic-gate * These functions replace uu_warn() and uu_die() when the quiet (-q) option is
9717c478bdstevel@tonic-gate * used, and silently ignore any output.
9727c478bdstevel@tonic-gate */
9737c478bdstevel@tonic-gate
9747c478bdstevel@tonic-gate/*ARGSUSED*/
9757c478bdstevel@tonic-gatestatic void
9767c478bdstevel@tonic-gatequiet_warn(const char *fmt, ...)
9777c478bdstevel@tonic-gate{
9787c478bdstevel@tonic-gate	/* Do nothing */
9797c478bdstevel@tonic-gate}
9807c478bdstevel@tonic-gate
9817c478bdstevel@tonic-gate/*ARGSUSED*/
982a5f0d1fToomas Soomestatic __NORETURN void
9837c478bdstevel@tonic-gatequiet_die(const char *fmt, ...)
9847c478bdstevel@tonic-gate{
9857c478bdstevel@tonic-gate	exit(UU_EXIT_FATAL);
9867c478bdstevel@tonic-gate}
9877c478bdstevel@tonic-gate
9887c478bdstevel@tonic-gateint
9897c478bdstevel@tonic-gatemain(int argc, char *argv[])
9907c478bdstevel@tonic-gate{
9917c478bdstevel@tonic-gate	int c;
9927c478bdstevel@tonic-gate	scf_walk_callback callback;
9937c478bdstevel@tonic-gate	int flags;
9947c478bdstevel@tonic-gate	int err;
9957c478bdstevel@tonic-gate
9967c478bdstevel@tonic-gate	(void) setlocale(LC_ALL, "");
9977c478bdstevel@tonic-gate	(void) textdomain(TEXT_DOMAIN);
9987c478bdstevel@tonic-gate
9997c478bdstevel@tonic-gate	return_code = UU_EXIT_OK;
10007c478bdstevel@tonic-gate
10017c478bdstevel@tonic-gate	(void) uu_setpname(argv[0]);
10027c478bdstevel@tonic-gate
10037c478bdstevel@tonic-gate	prop_pool = uu_list_pool_create("properties",
10047c478bdstevel@tonic-gate	    sizeof (svcprop_prop_node_t),
10057c478bdstevel@tonic-gate	    offsetof(svcprop_prop_node_t, spn_list_node), NULL, 0);
10067c478bdstevel@tonic-gate	if (prop_pool == NULL)
10077c478bdstevel@tonic-gate		uu_die("%s\n", uu_strerror(uu_error()));
10087c478bdstevel@tonic-gate
10097c478bdstevel@tonic-gate	prop_list = uu_list_create(prop_pool, NULL, 0);
10107c478bdstevel@tonic-gate
1011647f844Bryan Cantrill	hndl = scf_handle_create(SCF_VERSION);
1012647f844Bryan Cantrill	if (hndl == NULL)
1013647f844Bryan Cantrill		scfdie();
1014647f844Bryan Cantrill
1015647f844Bryan Cantrill	while ((c = getopt(argc, argv, "Ccfp:qs:tvwz:")) != -1) {
10167c478bdstevel@tonic-gate		switch (c) {
10177c478bdstevel@tonic-gate		case 'C':
10187c478bdstevel@tonic-gate			if (cflag || sflag || wait)
10197c478bdstevel@tonic-gate				usage();	/* Not with -c, -s or -w */
10207c478bdstevel@tonic-gate			Cflag++;
10217c478bdstevel@tonic-gate			snapshot = NULL;
10227c478bdstevel@tonic-gate			break;
10237c478bdstevel@tonic-gate
10247c478bdstevel@tonic-gate		case 'c':
10257c478bdstevel@tonic-gate			if (Cflag || sflag || wait)
10267c478bdstevel@tonic-gate				usage();	/* Not with -C, -s or -w */
10277c478bdstevel@tonic-gate			cflag++;
10287c478bdstevel@tonic-gate			snapshot = NULL;
10297c478bdstevel@tonic-gate			break;
10307c478bdstevel@tonic-gate
10317c478bdstevel@tonic-gate		case 'f':
10327c478bdstevel@tonic-gate			types = 1;
10337c478bdstevel@tonic-gate			fmris = 1;
10347c478bdstevel@tonic-gate			break;
10357c478bdstevel@tonic-gate
10367c478bdstevel@tonic-gate		case 'p':
10377c478bdstevel@tonic-gate			add_prop(optarg);
10387c478bdstevel@tonic-gate			break;
10397c478bdstevel@tonic-gate
10407c478bdstevel@tonic-gate		case 'q':
10417c478bdstevel@tonic-gate			quiet = 1;
10427c478bdstevel@tonic-gate			warn = quiet_warn;
10437c478bdstevel@tonic-gate			die = quiet_die;
10447c478bdstevel@tonic-gate			break;
10457c478bdstevel@tonic-gate
10467c478bdstevel@tonic-gate		case 's':
10477c478bdstevel@tonic-gate			if (Cflag || cflag || wait)
10487c478bdstevel@tonic-gate				usage();	/* Not with -C, -c or -w */
10497c478bdstevel@tonic-gate			snapshot = optarg;
10507c478bdstevel@tonic-gate			sflag++;
10517c478bdstevel@tonic-gate			break;
10527c478bdstevel@tonic-gate
10537c478bdstevel@tonic-gate		case 't':
10547c478bdstevel@tonic-gate			types = 1;
10557c478bdstevel@tonic-gate			break;
10567c478bdstevel@tonic-gate
10577c478bdstevel@tonic-gate		case 'v':
10587c478bdstevel@tonic-gate			verbose = 1;
10597c478bdstevel@tonic-gate			break;
10607c478bdstevel@tonic-gate
10617c478bdstevel@tonic-gate		case 'w':
10627c478bdstevel@tonic-gate			if (Cflag || cflag || sflag)
10637c478bdstevel@tonic-gate				usage();	/* Not with -C, -c or -s */
10647c478bdstevel@tonic-gate			wait = 1;
10657c478bdstevel@tonic-gate			break;
10667c478bdstevel@tonic-gate
1067647f844Bryan Cantrill		case 'z': {
1068647f844Bryan Cantrill			scf_value_t *zone;
1069647f844Bryan Cantrill			scf_handle_t *h = hndl;
1070647f844Bryan Cantrill
1071647f844Bryan Cantrill			if (getzoneid() != GLOBAL_ZONEID)
1072647f844Bryan Cantrill				uu_die(gettext("svcprop -z may only be used "
1073647f844Bryan Cantrill				    "from the global zone\n"));
1074647f844Bryan Cantrill
1075647f844Bryan Cantrill			if ((zone = scf_value_create(h)) == NULL)
1076647f844Bryan Cantrill				scfdie();
1077647f844Bryan Cantrill
1078647f844Bryan Cantrill			if (scf_value_set_astring(zone, optarg) != SCF_SUCCESS)
1079647f844Bryan Cantrill				scfdie();
1080647f844Bryan Cantrill
1081647f844Bryan Cantrill			if (scf_handle_decorate(h, "zone", zone) != SCF_SUCCESS)
1082647f844Bryan Cantrill				uu_die(gettext("invalid zone '%s'\n"), optarg);
1083647f844Bryan Cantrill
1084647f844Bryan Cantrill			scf_value_destroy(zone);
1085647f844Bryan Cantrill			break;
1086647f844Bryan Cantrill		}
1087647f844Bryan Cantrill
10887c478bdstevel@tonic-gate		case '?':
10897c478bdstevel@tonic-gate			switch (optopt) {
10907c478bdstevel@tonic-gate			case 'p':
10917c478bdstevel@tonic-gate				usage();
10927c478bdstevel@tonic-gate
10937c478bdstevel@tonic-gate			default:
10947c478bdstevel@tonic-gate				break;
10957c478bdstevel@tonic-gate			}
10967c478bdstevel@tonic-gate
10977c478bdstevel@tonic-gate			/* FALLTHROUGH */
10987c478bdstevel@tonic-gate
10997c478bdstevel@tonic-gate		default:
11007c478bdstevel@tonic-gate			usage();
11017c478bdstevel@tonic-gate		}
11027c478bdstevel@tonic-gate	}
11037c478bdstevel@tonic-gate
11047c478bdstevel@tonic-gate	if (optind == argc)
11057c478bdstevel@tonic-gate		usage();
11067c478bdstevel@tonic-gate
11077c478bdstevel@tonic-gate	max_scf_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
11087c478bdstevel@tonic-gate	max_scf_value_length = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
11097c478bdstevel@tonic-gate	max_scf_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
11107c478bdstevel@tonic-gate	if (max_scf_name_length == -1 || max_scf_value_length == -1 ||
11117c478bdstevel@tonic-gate	    max_scf_fmri_length == -1)
11127c478bdstevel@tonic-gate		scfdie();
11137c478bdstevel@tonic-gate
11147c478bdstevel@tonic-gate	if (scf_handle_bind(hndl) == -1)
11157c478bdstevel@tonic-gate		die(gettext("Could not connect to configuration repository: "
11167c478bdstevel@tonic-gate		    "%s.\n"), scf_strerror(scf_error()));
11177c478bdstevel@tonic-gate
11187c478bdstevel@tonic-gate	flags = SCF_WALK_PROPERTY | SCF_WALK_SERVICE | SCF_WALK_EXPLICIT;
11197c478bdstevel@tonic-gate
11207c478bdstevel@tonic-gate	if (wait) {
11217c478bdstevel@tonic-gate		if (uu_list_numnodes(prop_list) > 1)
11227c478bdstevel@tonic-gate			usage();
11237c478bdstevel@tonic-gate
11247c478bdstevel@tonic-gate		if (argc - optind > 1)
11257c478bdstevel@tonic-gate			usage();
11267c478bdstevel@tonic-gate
11277c478bdstevel@tonic-gate		callback = do_wait;
11287c478bdstevel@tonic-gate
11297c478bdstevel@tonic-gate	} else {
11307c478bdstevel@tonic-gate		callback = process_fmri;
11317c478bdstevel@tonic-gate
11327c478bdstevel@tonic-gate		flags |= SCF_WALK_MULTIPLE;
11337c478bdstevel@tonic-gate	}
11347c478bdstevel@tonic-gate
11357c478bdstevel@tonic-gate	if ((err = scf_walk_fmri(hndl, argc - optind, argv + optind, flags,
11367c478bdstevel@tonic-gate	    callback, NULL, &return_code, warn)) != 0) {
11377c478bdstevel@tonic-gate		warn(gettext("failed to iterate over instances: %s\n"),
11387c478bdstevel@tonic-gate		    scf_strerror(err));
11397c478bdstevel@tonic-gate		return_code = UU_EXIT_FATAL;
11407c478bdstevel@tonic-gate	}
11417c478bdstevel@tonic-gate
11427c478bdstevel@tonic-gate	scf_handle_destroy(hndl);
11437c478bdstevel@tonic-gate
11447c478bdstevel@tonic-gate	return (return_code);
11457c478bdstevel@tonic-gate}
1146