13938Sjbeck /*
23938Sjbeck  * CDDL HEADER START
33938Sjbeck  *
43938Sjbeck  * The contents of this file are subject to the terms of the
53938Sjbeck  * Common Development and Distribution License (the "License").
63938Sjbeck  * You may not use this file except in compliance with the License.
73938Sjbeck  *
83938Sjbeck  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93938Sjbeck  * or http://www.opensolaris.org/os/licensing.
103938Sjbeck  * See the License for the specific language governing permissions
113938Sjbeck  * and limitations under the License.
123938Sjbeck  *
133938Sjbeck  * When distributing Covered Code, include this CDDL HEADER in each
143938Sjbeck  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153938Sjbeck  * If applicable, add the following below this CDDL HEADER, with the
163938Sjbeck  * fields enclosed by brackets "[]" replaced with your own identifying
173938Sjbeck  * information: Portions Copyright [yyyy] [name of copyright owner]
183938Sjbeck  *
193938Sjbeck  * CDDL HEADER END
203938Sjbeck  */
213938Sjbeck 
223938Sjbeck /*
2311767SAnurag.Maskey@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
243938Sjbeck  * Use is subject to license terms.
253938Sjbeck  */
263938Sjbeck 
273938Sjbeck /*
2811767SAnurag.Maskey@Sun.COM  * util.c contains a set of miscellaneous utility functions which,
2911767SAnurag.Maskey@Sun.COM  * among other things:
303938Sjbeck  * - start a child process
313938Sjbeck  * - look up the zone name
3211767SAnurag.Maskey@Sun.COM  * - look up/set SMF properties
3311767SAnurag.Maskey@Sun.COM  * - drop/escalate privs
343938Sjbeck  */
353938Sjbeck 
3611767SAnurag.Maskey@Sun.COM #include <assert.h>
3711767SAnurag.Maskey@Sun.COM #include <errno.h>
3811767SAnurag.Maskey@Sun.COM #include <inetcfg.h>
3911767SAnurag.Maskey@Sun.COM #include <libdllink.h>
4011767SAnurag.Maskey@Sun.COM #include <limits.h>
4111767SAnurag.Maskey@Sun.COM #include <libscf.h>
4211767SAnurag.Maskey@Sun.COM #include <net/if.h>
4311767SAnurag.Maskey@Sun.COM #include <pthread.h>
4411767SAnurag.Maskey@Sun.COM #include <pwd.h>
4511767SAnurag.Maskey@Sun.COM #include <spawn.h>
463938Sjbeck #include <stdarg.h>
473938Sjbeck #include <stdio.h>
483938Sjbeck #include <stdlib.h>
493938Sjbeck #include <string.h>
5011767SAnurag.Maskey@Sun.COM #include <strings.h>
513938Sjbeck #include <stropts.h>
523938Sjbeck #include <sys/socket.h>
5311767SAnurag.Maskey@Sun.COM #include <sys/sockio.h>
5411767SAnurag.Maskey@Sun.COM #include <sys/types.h>
5511767SAnurag.Maskey@Sun.COM #include <unistd.h>
563938Sjbeck #include <wait.h>
573938Sjbeck #include <zone.h>
583938Sjbeck 
5911767SAnurag.Maskey@Sun.COM #include "util.h"
6011767SAnurag.Maskey@Sun.COM #include "llp.h"
613938Sjbeck 
623938Sjbeck extern char **environ;
6311767SAnurag.Maskey@Sun.COM extern sigset_t original_sigmask;
643938Sjbeck 
6511767SAnurag.Maskey@Sun.COM /*
6611767SAnurag.Maskey@Sun.COM  * A holder for all the resources needed to get a property value
6711767SAnurag.Maskey@Sun.COM  * using libscf.
6811767SAnurag.Maskey@Sun.COM  */
6911767SAnurag.Maskey@Sun.COM typedef struct scf_resources {
7011767SAnurag.Maskey@Sun.COM 	scf_handle_t *sr_handle;
7111767SAnurag.Maskey@Sun.COM 	scf_instance_t *sr_inst;
7211767SAnurag.Maskey@Sun.COM 	scf_snapshot_t *sr_snap;
7311767SAnurag.Maskey@Sun.COM 	scf_propertygroup_t *sr_pg;
7411767SAnurag.Maskey@Sun.COM 	scf_property_t *sr_prop;
7511767SAnurag.Maskey@Sun.COM 	scf_value_t *sr_val;
7611767SAnurag.Maskey@Sun.COM 	scf_transaction_t *sr_tx;
7711767SAnurag.Maskey@Sun.COM 	scf_transaction_entry_t *sr_ent;
7811767SAnurag.Maskey@Sun.COM } scf_resources_t;
7911767SAnurag.Maskey@Sun.COM 
8011767SAnurag.Maskey@Sun.COM static pthread_mutex_t uid_mutex = PTHREAD_MUTEX_INITIALIZER;
8111767SAnurag.Maskey@Sun.COM static uid_t uid;
8211767SAnurag.Maskey@Sun.COM static int uid_cnt;
8311767SAnurag.Maskey@Sun.COM 
843938Sjbeck void
85*11918SMichael.Hunter@Sun.COM nwamd_escalate(void) {
86*11918SMichael.Hunter@Sun.COM 	priv_set_t *priv_set;
87*11918SMichael.Hunter@Sun.COM 	priv_set = priv_str_to_set("zone", ",", NULL);
88*11918SMichael.Hunter@Sun.COM 
89*11918SMichael.Hunter@Sun.COM 	if (priv_set == NULL)
90*11918SMichael.Hunter@Sun.COM 		pfail("creating privilege set: %s", strerror(errno));
91*11918SMichael.Hunter@Sun.COM 
9211767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_lock(&uid_mutex);
9311767SAnurag.Maskey@Sun.COM 	if (uid == 0)
9411767SAnurag.Maskey@Sun.COM 		uid = getuid();
9511767SAnurag.Maskey@Sun.COM 	if (uid_cnt++ == 0) {
96*11918SMichael.Hunter@Sun.COM 		if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) {
97*11918SMichael.Hunter@Sun.COM 			priv_freeset(priv_set);
98*11918SMichael.Hunter@Sun.COM 			pfail("setppriv effective: %s", strerror(errno));
99*11918SMichael.Hunter@Sun.COM 		}
10011767SAnurag.Maskey@Sun.COM 		if (setuid(0) == -1)
10111767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "setuid(0) failed %s", strerror(errno));
1023938Sjbeck 	}
10311767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_unlock(&uid_mutex);
104*11918SMichael.Hunter@Sun.COM 
105*11918SMichael.Hunter@Sun.COM 	priv_freeset(priv_set);
1063938Sjbeck }
1073938Sjbeck 
10811767SAnurag.Maskey@Sun.COM void
109*11918SMichael.Hunter@Sun.COM nwamd_deescalate(void) {
110*11918SMichael.Hunter@Sun.COM 	priv_set_t *priv_set, *allpriv_set;
111*11918SMichael.Hunter@Sun.COM 
11211767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_lock(&uid_mutex);
11311767SAnurag.Maskey@Sun.COM 	assert(uid_cnt > 0);
11411767SAnurag.Maskey@Sun.COM 	if (--uid_cnt == 0) {
11511767SAnurag.Maskey@Sun.COM 		if (setuid(uid) == -1)
11611767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "setuid(%d) failed %s", uid,
11711767SAnurag.Maskey@Sun.COM 			    strerror(errno));
118*11918SMichael.Hunter@Sun.COM 
119*11918SMichael.Hunter@Sun.COM 		/* build up our minimal set of privs. */
120*11918SMichael.Hunter@Sun.COM 		priv_set = priv_str_to_set("basic", ",", NULL);
121*11918SMichael.Hunter@Sun.COM 		allpriv_set = priv_str_to_set("zone", ",", NULL);
122*11918SMichael.Hunter@Sun.COM 		if (priv_set == NULL || allpriv_set == NULL)
123*11918SMichael.Hunter@Sun.COM 			pfail("converting privilege sets: %s", strerror(errno));
124*11918SMichael.Hunter@Sun.COM 
125*11918SMichael.Hunter@Sun.COM 		(void) priv_addset(priv_set, PRIV_FILE_CHOWN_SELF);
126*11918SMichael.Hunter@Sun.COM 		(void) priv_addset(priv_set, PRIV_FILE_DAC_READ);
127*11918SMichael.Hunter@Sun.COM 		(void) priv_addset(priv_set, PRIV_FILE_DAC_WRITE);
128*11918SMichael.Hunter@Sun.COM 		(void) priv_addset(priv_set, PRIV_NET_RAWACCESS);
129*11918SMichael.Hunter@Sun.COM 		(void) priv_addset(priv_set, PRIV_NET_PRIVADDR);
130*11918SMichael.Hunter@Sun.COM 		(void) priv_addset(priv_set, PRIV_PROC_AUDIT);
131*11918SMichael.Hunter@Sun.COM 		(void) priv_addset(priv_set, PRIV_PROC_OWNER);
132*11918SMichael.Hunter@Sun.COM 		(void) priv_addset(priv_set, PRIV_PROC_SETID);
133*11918SMichael.Hunter@Sun.COM 		(void) priv_addset(priv_set, PRIV_SYS_CONFIG);
134*11918SMichael.Hunter@Sun.COM 		(void) priv_addset(priv_set, PRIV_SYS_IP_CONFIG);
135*11918SMichael.Hunter@Sun.COM 		(void) priv_addset(priv_set, PRIV_SYS_IPC_CONFIG);
136*11918SMichael.Hunter@Sun.COM 		(void) priv_addset(priv_set, PRIV_SYS_MOUNT);
137*11918SMichael.Hunter@Sun.COM 		(void) priv_addset(priv_set, PRIV_SYS_NET_CONFIG);
138*11918SMichael.Hunter@Sun.COM 		(void) priv_addset(priv_set, PRIV_SYS_RES_CONFIG);
139*11918SMichael.Hunter@Sun.COM 		(void) priv_addset(priv_set, PRIV_SYS_RESOURCE);
140*11918SMichael.Hunter@Sun.COM 
141*11918SMichael.Hunter@Sun.COM 		/*
142*11918SMichael.Hunter@Sun.COM 		 * Since our zone might not have all these privs,
143*11918SMichael.Hunter@Sun.COM 		 * just ask for those that are available.
144*11918SMichael.Hunter@Sun.COM 		 */
145*11918SMichael.Hunter@Sun.COM 		priv_intersect(allpriv_set, priv_set);
146*11918SMichael.Hunter@Sun.COM 
147*11918SMichael.Hunter@Sun.COM 		if (setppriv(PRIV_SET, PRIV_INHERITABLE, priv_set) == -1) {
148*11918SMichael.Hunter@Sun.COM 			priv_freeset(allpriv_set);
149*11918SMichael.Hunter@Sun.COM 			priv_freeset(priv_set);
150*11918SMichael.Hunter@Sun.COM 			pfail("setppriv inheritable: %s", strerror(errno));
151*11918SMichael.Hunter@Sun.COM 		}
152*11918SMichael.Hunter@Sun.COM 		/*
153*11918SMichael.Hunter@Sun.COM 		 * Need to ensure permitted set contains all privs so we can
154*11918SMichael.Hunter@Sun.COM 		 * escalate later.
155*11918SMichael.Hunter@Sun.COM 		 */
156*11918SMichael.Hunter@Sun.COM 		if (setppriv(PRIV_SET, PRIV_PERMITTED, allpriv_set) == -1) {
157*11918SMichael.Hunter@Sun.COM 			priv_freeset(allpriv_set);
158*11918SMichael.Hunter@Sun.COM 			priv_freeset(priv_set);
159*11918SMichael.Hunter@Sun.COM 			pfail("setppriv permitted: %s", strerror(errno));
160*11918SMichael.Hunter@Sun.COM 		}
161*11918SMichael.Hunter@Sun.COM 		/*
162*11918SMichael.Hunter@Sun.COM 		 * We need to find a smaller set of privs that are important to
163*11918SMichael.Hunter@Sun.COM 		 * us.  Otherwise we really are not gaining much by doing this.
164*11918SMichael.Hunter@Sun.COM 		 */
165*11918SMichael.Hunter@Sun.COM 		if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) {
166*11918SMichael.Hunter@Sun.COM 			priv_freeset(allpriv_set);
167*11918SMichael.Hunter@Sun.COM 			priv_freeset(priv_set);
168*11918SMichael.Hunter@Sun.COM 			pfail("setppriv effective: %s", strerror(errno));
169*11918SMichael.Hunter@Sun.COM 		}
1703938Sjbeck 	}
17111767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_unlock(&uid_mutex);
172*11918SMichael.Hunter@Sun.COM 
173*11918SMichael.Hunter@Sun.COM 	priv_freeset(priv_set);
174*11918SMichael.Hunter@Sun.COM 	priv_freeset(allpriv_set);
1757645Sjames.d.carlson@sun.com }
1767645Sjames.d.carlson@sun.com 
1773938Sjbeck /*
1783938Sjbeck  *
1793938Sjbeck  * This starts a child process determined by command.  If command contains a
1803938Sjbeck  * slash then it is assumed to be a full path; otherwise the path is searched
1813938Sjbeck  * for an executable file with the name command.  Command is also used as
1823938Sjbeck  * argv[0] of the new process.  The rest of the arguments of the function
1833938Sjbeck  * up to the first NULL make up pointers to arguments of the new process.
1843938Sjbeck  *
1853938Sjbeck  * This function returns child exit status on success and -1 on failure.
1863938Sjbeck  *
1873938Sjbeck  * NOTE: original_sigmask must be set before this function is called.
1883938Sjbeck  */
1893938Sjbeck int
19011767SAnurag.Maskey@Sun.COM nwamd_start_childv(const char *command, char const * const *argv)
1913938Sjbeck {
1923938Sjbeck 	posix_spawnattr_t attr;
1933938Sjbeck 	sigset_t fullset;
1943938Sjbeck 	int i, rc, status, n;
1953938Sjbeck 	pid_t pid;
1963938Sjbeck 	char vbuf[1024];
1973938Sjbeck 
1983938Sjbeck 	vbuf[0] = 0;
1993938Sjbeck 	n = sizeof (vbuf);
2003938Sjbeck 	for (i = 1; argv[i] != NULL && n > 2; i++) {
2013938Sjbeck 		n -= strlcat(vbuf, " ", n);
2023938Sjbeck 		n -= strlcat(vbuf, argv[i], n);
2033938Sjbeck 	}
2043938Sjbeck 	if (argv[i] != NULL || n < 0)
20511767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_start_childv can't log full arg vector");
2063938Sjbeck 
2073938Sjbeck 	if ((rc = posix_spawnattr_init(&attr)) != 0) {
20811767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "posix_spawnattr_init %d %s\n",
20911767SAnurag.Maskey@Sun.COM 		    rc, strerror(rc));
2103938Sjbeck 		return (-1);
2113938Sjbeck 	}
2123938Sjbeck 	(void) sigfillset(&fullset);
2133938Sjbeck 	if ((rc = posix_spawnattr_setsigdefault(&attr, &fullset)) != 0) {
21411767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "setsigdefault %d %s\n", rc, strerror(rc));
2153938Sjbeck 		return (-1);
2163938Sjbeck 	}
2173938Sjbeck 	if ((rc = posix_spawnattr_setsigmask(&attr, &original_sigmask)) != 0) {
21811767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "setsigmask %d %s\n", rc, strerror(rc));
2193938Sjbeck 		return (-1);
2203938Sjbeck 	}
2213938Sjbeck 	if ((rc = posix_spawnattr_setflags(&attr,
2223938Sjbeck 	    POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK)) != 0) {
22311767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "setflags %d %s\n", rc, strerror(rc));
2243938Sjbeck 		return (-1);
2253938Sjbeck 	}
2263938Sjbeck 
2273938Sjbeck 	if ((rc = posix_spawnp(&pid, command, NULL, &attr, (char * const *)argv,
2283938Sjbeck 	    environ)) > 0) {
22911767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "posix_spawnp failed errno %d", rc);
2303938Sjbeck 		return (-1);
2313938Sjbeck 	}
2323938Sjbeck 
2333938Sjbeck 	if ((rc = posix_spawnattr_destroy(&attr)) != 0) {
23411767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "posix_spawn_attr_destroy %d %s\n",
23511767SAnurag.Maskey@Sun.COM 		    rc, strerror(rc));
2363938Sjbeck 		return (-1);
2373938Sjbeck 	}
2383938Sjbeck 
2393938Sjbeck 	(void) waitpid(pid, &status, 0);
2403938Sjbeck 	if (WIFSIGNALED(status) || WIFSTOPPED(status)) {
2413938Sjbeck 		i = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status);
24211767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "'%s%s' %s with signal %d (%s)", command, vbuf,
2433938Sjbeck 		    (WIFSIGNALED(status) ? "terminated" : "stopped"), i,
2443938Sjbeck 		    strsignal(i));
2453938Sjbeck 		return (-2);
2463938Sjbeck 	} else {
24711767SAnurag.Maskey@Sun.COM 		nlog(LOG_INFO, "'%s%s' completed normally: %d", command, vbuf,
2483938Sjbeck 		    WEXITSTATUS(status));
2493938Sjbeck 		return (WEXITSTATUS(status));
2503938Sjbeck 	}
2513938Sjbeck }
2523938Sjbeck 
25311767SAnurag.Maskey@Sun.COM /*
25411767SAnurag.Maskey@Sun.COM  * For global zone, check if the link is used by a non-global
25511767SAnurag.Maskey@Sun.COM  * zone, note that the non-global zones doesn't need this check,
25611767SAnurag.Maskey@Sun.COM  * because zoneadm has taken care of this when the zone boots.
25711767SAnurag.Maskey@Sun.COM  * In the global zone, we ignore events for local-zone-owned links
25811767SAnurag.Maskey@Sun.COM  * since these are taken care of by the local zone's network
25911767SAnurag.Maskey@Sun.COM  * configuration services.
26011767SAnurag.Maskey@Sun.COM  */
26111767SAnurag.Maskey@Sun.COM boolean_t
26211767SAnurag.Maskey@Sun.COM nwamd_link_belongs_to_this_zone(const char *linkname)
2633938Sjbeck {
26411767SAnurag.Maskey@Sun.COM 	zoneid_t zoneid;
26511767SAnurag.Maskey@Sun.COM 	char zonename[ZONENAME_MAX];
26611767SAnurag.Maskey@Sun.COM 	int ret;
2673938Sjbeck 
26811767SAnurag.Maskey@Sun.COM 	zoneid = getzoneid();
26911767SAnurag.Maskey@Sun.COM 	if (zoneid == GLOBAL_ZONEID) {
27011767SAnurag.Maskey@Sun.COM 		datalink_id_t linkid;
27111767SAnurag.Maskey@Sun.COM 		dladm_status_t status;
27211767SAnurag.Maskey@Sun.COM 		char errstr[DLADM_STRSIZE];
27311767SAnurag.Maskey@Sun.COM 
27411767SAnurag.Maskey@Sun.COM 		if ((status = dladm_name2info(dld_handle, linkname, &linkid,
27511767SAnurag.Maskey@Sun.COM 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
27611767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: "
27711767SAnurag.Maskey@Sun.COM 			    "could not get linkid for %s: %s",
27811767SAnurag.Maskey@Sun.COM 			    linkname, dladm_status2str(status, errstr));
27911767SAnurag.Maskey@Sun.COM 			return (B_FALSE);
2803938Sjbeck 		}
28111767SAnurag.Maskey@Sun.COM 		zoneid = ALL_ZONES;
28211767SAnurag.Maskey@Sun.COM 		ret = zone_check_datalink(&zoneid, linkid);
28311767SAnurag.Maskey@Sun.COM 		if (ret == 0) {
28411767SAnurag.Maskey@Sun.COM 			(void) getzonenamebyid(zoneid, zonename, ZONENAME_MAX);
28511767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: "
28611767SAnurag.Maskey@Sun.COM 			    "%s is used by non-global zone: %s",
28711767SAnurag.Maskey@Sun.COM 			    linkname, zonename);
28811767SAnurag.Maskey@Sun.COM 			return (B_FALSE);
28911767SAnurag.Maskey@Sun.COM 		}
29011767SAnurag.Maskey@Sun.COM 	}
29111767SAnurag.Maskey@Sun.COM 	return (B_TRUE);
2923938Sjbeck }
2933938Sjbeck 
29411767SAnurag.Maskey@Sun.COM /*
29511767SAnurag.Maskey@Sun.COM  * Inputs:
29611767SAnurag.Maskey@Sun.COM  *   res is a pointer to the scf_resources_t to be released.
29711767SAnurag.Maskey@Sun.COM  */
29811767SAnurag.Maskey@Sun.COM static void
29911767SAnurag.Maskey@Sun.COM release_scf_resources(scf_resources_t *res)
30011767SAnurag.Maskey@Sun.COM {
30111767SAnurag.Maskey@Sun.COM 	scf_entry_destroy(res->sr_ent);
30211767SAnurag.Maskey@Sun.COM 	scf_transaction_destroy(res->sr_tx);
30311767SAnurag.Maskey@Sun.COM 	scf_value_destroy(res->sr_val);
30411767SAnurag.Maskey@Sun.COM 	scf_property_destroy(res->sr_prop);
30511767SAnurag.Maskey@Sun.COM 	scf_pg_destroy(res->sr_pg);
30611767SAnurag.Maskey@Sun.COM 	scf_snapshot_destroy(res->sr_snap);
30711767SAnurag.Maskey@Sun.COM 	scf_instance_destroy(res->sr_inst);
30811767SAnurag.Maskey@Sun.COM 	(void) scf_handle_unbind(res->sr_handle);
30911767SAnurag.Maskey@Sun.COM 	scf_handle_destroy(res->sr_handle);
31011767SAnurag.Maskey@Sun.COM }
31111767SAnurag.Maskey@Sun.COM 
31211767SAnurag.Maskey@Sun.COM /*
31311767SAnurag.Maskey@Sun.COM  * Inputs:
31411767SAnurag.Maskey@Sun.COM  *   fmri is the instance to look up
31511767SAnurag.Maskey@Sun.COM  * Outputs:
31611767SAnurag.Maskey@Sun.COM  *   res is a pointer to an scf_resources_t.  This is an internal
31711767SAnurag.Maskey@Sun.COM  *   structure that holds all the handles needed to get a specific
31811767SAnurag.Maskey@Sun.COM  *   property from the running snapshot; on a successful return it
31911767SAnurag.Maskey@Sun.COM  *   contains the scf_value_t that should be passed to the desired
32011767SAnurag.Maskey@Sun.COM  *   scf_value_get_foo() function, and must be freed after use by
32111767SAnurag.Maskey@Sun.COM  *   calling release_scf_resources().  On a failure return, any
32211767SAnurag.Maskey@Sun.COM  *   resources that may have been assigned to res are released, so
32311767SAnurag.Maskey@Sun.COM  *   the caller does not need to do any cleanup in the failure case.
32411767SAnurag.Maskey@Sun.COM  * Returns:
32511767SAnurag.Maskey@Sun.COM  *    0 on success
32611767SAnurag.Maskey@Sun.COM  *   -1 on failure
32711767SAnurag.Maskey@Sun.COM  */
32811767SAnurag.Maskey@Sun.COM 
32911767SAnurag.Maskey@Sun.COM static int
33011767SAnurag.Maskey@Sun.COM create_scf_resources(const char *fmri, scf_resources_t *res)
3313938Sjbeck {
33211767SAnurag.Maskey@Sun.COM 	res->sr_tx = NULL;
33311767SAnurag.Maskey@Sun.COM 	res->sr_ent = NULL;
33411767SAnurag.Maskey@Sun.COM 	res->sr_inst = NULL;
33511767SAnurag.Maskey@Sun.COM 	res->sr_snap = NULL;
33611767SAnurag.Maskey@Sun.COM 	res->sr_pg = NULL;
33711767SAnurag.Maskey@Sun.COM 	res->sr_prop = NULL;
33811767SAnurag.Maskey@Sun.COM 	res->sr_val = NULL;
33911767SAnurag.Maskey@Sun.COM 
34011767SAnurag.Maskey@Sun.COM 	if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL) {
34111767SAnurag.Maskey@Sun.COM 		return (-1);
34211767SAnurag.Maskey@Sun.COM 	}
34311767SAnurag.Maskey@Sun.COM 
34411767SAnurag.Maskey@Sun.COM 	if (scf_handle_bind(res->sr_handle) != 0) {
34511767SAnurag.Maskey@Sun.COM 		scf_handle_destroy(res->sr_handle);
34611767SAnurag.Maskey@Sun.COM 		return (-1);
34711767SAnurag.Maskey@Sun.COM 	}
34811767SAnurag.Maskey@Sun.COM 	if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL) {
34911767SAnurag.Maskey@Sun.COM 		goto failure;
35011767SAnurag.Maskey@Sun.COM 	}
35111767SAnurag.Maskey@Sun.COM 	if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL,
35211767SAnurag.Maskey@Sun.COM 	    res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
35311767SAnurag.Maskey@Sun.COM 		goto failure;
35411767SAnurag.Maskey@Sun.COM 	}
35511767SAnurag.Maskey@Sun.COM 	if ((res->sr_snap = scf_snapshot_create(res->sr_handle)) == NULL) {
35611767SAnurag.Maskey@Sun.COM 		goto failure;
35711767SAnurag.Maskey@Sun.COM 	}
35811767SAnurag.Maskey@Sun.COM 	if (scf_instance_get_snapshot(res->sr_inst, "running",
35911767SAnurag.Maskey@Sun.COM 	    res->sr_snap) != 0) {
36011767SAnurag.Maskey@Sun.COM 		goto failure;
36111767SAnurag.Maskey@Sun.COM 	}
36211767SAnurag.Maskey@Sun.COM 	if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
36311767SAnurag.Maskey@Sun.COM 		goto failure;
36411767SAnurag.Maskey@Sun.COM 	}
36511767SAnurag.Maskey@Sun.COM 	if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL) {
36611767SAnurag.Maskey@Sun.COM 		goto failure;
36711767SAnurag.Maskey@Sun.COM 	}
36811767SAnurag.Maskey@Sun.COM 	if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL) {
36911767SAnurag.Maskey@Sun.COM 		goto failure;
37011767SAnurag.Maskey@Sun.COM 	}
37111767SAnurag.Maskey@Sun.COM 	if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL) {
37211767SAnurag.Maskey@Sun.COM 		goto failure;
37311767SAnurag.Maskey@Sun.COM 	}
37411767SAnurag.Maskey@Sun.COM 	if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL) {
37511767SAnurag.Maskey@Sun.COM 		goto failure;
37611767SAnurag.Maskey@Sun.COM 	}
37711767SAnurag.Maskey@Sun.COM 	return (0);
37811767SAnurag.Maskey@Sun.COM 
37911767SAnurag.Maskey@Sun.COM failure:
38011767SAnurag.Maskey@Sun.COM 	nlog(LOG_ERR, "create_scf_resources failed: %s",
38111767SAnurag.Maskey@Sun.COM 	    scf_strerror(scf_error()));
38211767SAnurag.Maskey@Sun.COM 	release_scf_resources(res);
38311767SAnurag.Maskey@Sun.COM 	return (-1);
38411767SAnurag.Maskey@Sun.COM }
38511767SAnurag.Maskey@Sun.COM 
38611767SAnurag.Maskey@Sun.COM /*
38711767SAnurag.Maskey@Sun.COM  * Inputs:
38811767SAnurag.Maskey@Sun.COM  *   fmri is the instance to look up
38911767SAnurag.Maskey@Sun.COM  *   pg is the property group to look up
39011767SAnurag.Maskey@Sun.COM  *   prop is the property within that group to look up
39111767SAnurag.Maskey@Sun.COM  *   running specifies if running snapshot is to be used
39211767SAnurag.Maskey@Sun.COM  * Outputs:
39311767SAnurag.Maskey@Sun.COM  *   res is a pointer to an scf_resources_t.  This is an internal
39411767SAnurag.Maskey@Sun.COM  *   structure that holds all the handles needed to get a specific
39511767SAnurag.Maskey@Sun.COM  *   property from the running snapshot; on a successful return it
39611767SAnurag.Maskey@Sun.COM  *   contains the scf_value_t that should be passed to the desired
39711767SAnurag.Maskey@Sun.COM  *   scf_value_get_foo() function, and must be freed after use by
39811767SAnurag.Maskey@Sun.COM  *   calling release_scf_resources().  On a failure return, any
39911767SAnurag.Maskey@Sun.COM  *   resources that may have been assigned to res are released, so
40011767SAnurag.Maskey@Sun.COM  *   the caller does not need to do any cleanup in the failure case.
40111767SAnurag.Maskey@Sun.COM  * Returns:
40211767SAnurag.Maskey@Sun.COM  *    0 on success
40311767SAnurag.Maskey@Sun.COM  *   -1 on failure
40411767SAnurag.Maskey@Sun.COM  */
40511767SAnurag.Maskey@Sun.COM static int
40611767SAnurag.Maskey@Sun.COM get_property_value(const char *fmri, const char *pg, const char *prop,
40711767SAnurag.Maskey@Sun.COM     boolean_t running, scf_resources_t *res)
40811767SAnurag.Maskey@Sun.COM {
40911767SAnurag.Maskey@Sun.COM 	if (create_scf_resources(fmri, res) != 0)
41011767SAnurag.Maskey@Sun.COM 		return (-1);
41111767SAnurag.Maskey@Sun.COM 
41211767SAnurag.Maskey@Sun.COM 	if (scf_instance_get_pg_composed(res->sr_inst,
41311767SAnurag.Maskey@Sun.COM 	    running ? res->sr_snap : NULL, pg, res->sr_pg) != 0) {
41411767SAnurag.Maskey@Sun.COM 		goto failure;
41511767SAnurag.Maskey@Sun.COM 	}
41611767SAnurag.Maskey@Sun.COM 	if (scf_pg_get_property(res->sr_pg, prop, res->sr_prop) != 0) {
41711767SAnurag.Maskey@Sun.COM 		goto failure;
41811767SAnurag.Maskey@Sun.COM 	}
41911767SAnurag.Maskey@Sun.COM 	if (scf_property_get_value(res->sr_prop, res->sr_val) != 0) {
42011767SAnurag.Maskey@Sun.COM 		goto failure;
42111767SAnurag.Maskey@Sun.COM 	}
42211767SAnurag.Maskey@Sun.COM 	return (0);
42311767SAnurag.Maskey@Sun.COM 
42411767SAnurag.Maskey@Sun.COM failure:
42511767SAnurag.Maskey@Sun.COM 	release_scf_resources(res);
42611767SAnurag.Maskey@Sun.COM 	return (-1);
42711767SAnurag.Maskey@Sun.COM }
42811767SAnurag.Maskey@Sun.COM 
42911767SAnurag.Maskey@Sun.COM /*
43011767SAnurag.Maskey@Sun.COM  * Inputs:
43111767SAnurag.Maskey@Sun.COM  *   lfmri is the instance fmri to look up
43211767SAnurag.Maskey@Sun.COM  *   lpg is the property group to look up
43311767SAnurag.Maskey@Sun.COM  *   lprop is the property within that group to look up
43411767SAnurag.Maskey@Sun.COM  * Outputs:
43511767SAnurag.Maskey@Sun.COM  *   answer is a pointer to the property value
43611767SAnurag.Maskey@Sun.COM  * Returns:
43711767SAnurag.Maskey@Sun.COM  *    0 on success
43811767SAnurag.Maskey@Sun.COM  *   -1 on failure
43911767SAnurag.Maskey@Sun.COM  * If successful, the property value is retured in *answer.
44011767SAnurag.Maskey@Sun.COM  * Otherwise, *answer is undefined, and it is up to the caller to decide
44111767SAnurag.Maskey@Sun.COM  * how to handle that case.
44211767SAnurag.Maskey@Sun.COM  */
44311767SAnurag.Maskey@Sun.COM int
44411767SAnurag.Maskey@Sun.COM nwamd_lookup_boolean_property(const char *lfmri, const char *lpg,
44511767SAnurag.Maskey@Sun.COM     const char *lprop, boolean_t *answer)
44611767SAnurag.Maskey@Sun.COM {
44711767SAnurag.Maskey@Sun.COM 	int result = -1;
44811767SAnurag.Maskey@Sun.COM 	scf_resources_t res;
44911767SAnurag.Maskey@Sun.COM 	uint8_t prop_val;
45011767SAnurag.Maskey@Sun.COM 
45111767SAnurag.Maskey@Sun.COM 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
45211767SAnurag.Maskey@Sun.COM 
45311767SAnurag.Maskey@Sun.COM 		/*
45411767SAnurag.Maskey@Sun.COM 		 * an error was already logged by get_property_value,
45511767SAnurag.Maskey@Sun.COM 		 * and it released any resources assigned to res before
45611767SAnurag.Maskey@Sun.COM 		 * returning.
45711767SAnurag.Maskey@Sun.COM 		 */
45811767SAnurag.Maskey@Sun.COM 		return (result);
45911767SAnurag.Maskey@Sun.COM 	}
46011767SAnurag.Maskey@Sun.COM 	if (scf_value_get_boolean(res.sr_val, &prop_val) != 0) {
46111767SAnurag.Maskey@Sun.COM 		goto cleanup;
46211767SAnurag.Maskey@Sun.COM 	}
46311767SAnurag.Maskey@Sun.COM 	*answer = (boolean_t)prop_val;
46411767SAnurag.Maskey@Sun.COM 	result = 0;
46511767SAnurag.Maskey@Sun.COM cleanup:
46611767SAnurag.Maskey@Sun.COM 	release_scf_resources(&res);
46711767SAnurag.Maskey@Sun.COM 	return (result);
46811767SAnurag.Maskey@Sun.COM }
46911767SAnurag.Maskey@Sun.COM 
47011767SAnurag.Maskey@Sun.COM /*
47111767SAnurag.Maskey@Sun.COM  * Inputs:
47211767SAnurag.Maskey@Sun.COM  *   lfmri is the instance fmri to look up
47311767SAnurag.Maskey@Sun.COM  *   lpg is the property group to look up
47411767SAnurag.Maskey@Sun.COM  *   lprop is the property within that group to look up
47511767SAnurag.Maskey@Sun.COM  *   buf is the place to put the answer
47611767SAnurag.Maskey@Sun.COM  *   bufsz is the size of buf
47711767SAnurag.Maskey@Sun.COM  * Outputs:
47811767SAnurag.Maskey@Sun.COM  *
47911767SAnurag.Maskey@Sun.COM  * Returns:
48011767SAnurag.Maskey@Sun.COM  *    0 on success
48111767SAnurag.Maskey@Sun.COM  *   -1 on failure
48211767SAnurag.Maskey@Sun.COM  * If successful, the property value is retured in buf.
48311767SAnurag.Maskey@Sun.COM  * Otherwise, buf is undefined, and it is up to the caller to decide
48411767SAnurag.Maskey@Sun.COM  * how to handle that case.
48511767SAnurag.Maskey@Sun.COM  */
48611767SAnurag.Maskey@Sun.COM int
48711767SAnurag.Maskey@Sun.COM nwamd_lookup_string_property(const char *lfmri, const char *lpg,
48811767SAnurag.Maskey@Sun.COM     const char *lprop, char *buf, size_t bufsz)
48911767SAnurag.Maskey@Sun.COM {
49011767SAnurag.Maskey@Sun.COM 	int result = -1;
49111767SAnurag.Maskey@Sun.COM 	scf_resources_t res;
4923938Sjbeck 
49311767SAnurag.Maskey@Sun.COM 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
49411767SAnurag.Maskey@Sun.COM 		/*
49511767SAnurag.Maskey@Sun.COM 		 * The above function fails when trying to get a
49611767SAnurag.Maskey@Sun.COM 		 * non-persistent property group from the running snapshot.
49711767SAnurag.Maskey@Sun.COM 		 * Try going for the non-running snapshot.
49811767SAnurag.Maskey@Sun.COM 		 */
49911767SAnurag.Maskey@Sun.COM 		if (get_property_value(lfmri, lpg, lprop, B_FALSE, &res) != 0) {
50011767SAnurag.Maskey@Sun.COM 			/*
50111767SAnurag.Maskey@Sun.COM 			 * an error was already logged by get_property_value,
50211767SAnurag.Maskey@Sun.COM 			 * and it released any resources assigned to res before
50311767SAnurag.Maskey@Sun.COM 			 * returning.
50411767SAnurag.Maskey@Sun.COM 			 */
50511767SAnurag.Maskey@Sun.COM 			return (result);
50611767SAnurag.Maskey@Sun.COM 		}
50711767SAnurag.Maskey@Sun.COM 	}
50811767SAnurag.Maskey@Sun.COM 	if (scf_value_get_astring(res.sr_val, buf, bufsz) == 0)
50911767SAnurag.Maskey@Sun.COM 		goto cleanup;
51011767SAnurag.Maskey@Sun.COM 
51111767SAnurag.Maskey@Sun.COM 	result = 0;
51211767SAnurag.Maskey@Sun.COM cleanup:
51311767SAnurag.Maskey@Sun.COM 	release_scf_resources(&res);
51411767SAnurag.Maskey@Sun.COM 	return (result);
51511767SAnurag.Maskey@Sun.COM }
51611767SAnurag.Maskey@Sun.COM 
51711767SAnurag.Maskey@Sun.COM /*
51811767SAnurag.Maskey@Sun.COM  * Inputs:
51911767SAnurag.Maskey@Sun.COM  *   lfmri is the instance fmri to look up
52011767SAnurag.Maskey@Sun.COM  *   lpg is the property group to look up
52111767SAnurag.Maskey@Sun.COM  *   lprop is the property within that group to look up
52211767SAnurag.Maskey@Sun.COM  * Outputs:
52311767SAnurag.Maskey@Sun.COM  *   answer is a pointer to the property value
52411767SAnurag.Maskey@Sun.COM  * Returns:
52511767SAnurag.Maskey@Sun.COM  *    0 on success
52611767SAnurag.Maskey@Sun.COM  *   -1 on failure
52711767SAnurag.Maskey@Sun.COM  * If successful, the property value is retured in *answer.
52811767SAnurag.Maskey@Sun.COM  * Otherwise, *answer is undefined, and it is up to the caller to decide
52911767SAnurag.Maskey@Sun.COM  * how to handle that case.
53011767SAnurag.Maskey@Sun.COM  */
53111767SAnurag.Maskey@Sun.COM int
53211767SAnurag.Maskey@Sun.COM nwamd_lookup_count_property(const char *lfmri, const char *lpg,
53311767SAnurag.Maskey@Sun.COM     const char *lprop, uint64_t *answer)
53411767SAnurag.Maskey@Sun.COM {
53511767SAnurag.Maskey@Sun.COM 	int result = -1;
53611767SAnurag.Maskey@Sun.COM 	scf_resources_t res;
53711767SAnurag.Maskey@Sun.COM 
53811767SAnurag.Maskey@Sun.COM 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
53911767SAnurag.Maskey@Sun.COM 
54011767SAnurag.Maskey@Sun.COM 		/*
54111767SAnurag.Maskey@Sun.COM 		 * an error was already logged by get_property_value,
54211767SAnurag.Maskey@Sun.COM 		 * and it released any resources assigned to res before
54311767SAnurag.Maskey@Sun.COM 		 * returning.
54411767SAnurag.Maskey@Sun.COM 		 */
54511767SAnurag.Maskey@Sun.COM 		return (result);
54611767SAnurag.Maskey@Sun.COM 	}
54711767SAnurag.Maskey@Sun.COM 	if (scf_value_get_count(res.sr_val, answer) != 0) {
54811767SAnurag.Maskey@Sun.COM 		goto cleanup;
54911767SAnurag.Maskey@Sun.COM 	}
55011767SAnurag.Maskey@Sun.COM 	result = 0;
55111767SAnurag.Maskey@Sun.COM cleanup:
55211767SAnurag.Maskey@Sun.COM 	release_scf_resources(&res);
55311767SAnurag.Maskey@Sun.COM 	return (result);
55411767SAnurag.Maskey@Sun.COM }
55511767SAnurag.Maskey@Sun.COM 
55611767SAnurag.Maskey@Sun.COM static int
55711767SAnurag.Maskey@Sun.COM set_property_value(scf_resources_t *res, const char *propname,
55811767SAnurag.Maskey@Sun.COM     scf_type_t proptype)
55911767SAnurag.Maskey@Sun.COM {
56011767SAnurag.Maskey@Sun.COM 	int result = -1;
56111767SAnurag.Maskey@Sun.COM 	boolean_t new;
56211767SAnurag.Maskey@Sun.COM 
56311767SAnurag.Maskey@Sun.COM retry:
56411767SAnurag.Maskey@Sun.COM 	new = (scf_pg_get_property(res->sr_pg, propname, res->sr_prop) != 0);
56511767SAnurag.Maskey@Sun.COM 
56611767SAnurag.Maskey@Sun.COM 	if (scf_transaction_start(res->sr_tx, res->sr_pg) == -1) {
56711767SAnurag.Maskey@Sun.COM 		goto failure;
56811767SAnurag.Maskey@Sun.COM 	}
56911767SAnurag.Maskey@Sun.COM 	if (new) {
57011767SAnurag.Maskey@Sun.COM 		if (scf_transaction_property_new(res->sr_tx, res->sr_ent,
57111767SAnurag.Maskey@Sun.COM 		    propname, proptype) == -1) {
57211767SAnurag.Maskey@Sun.COM 			goto failure;
57311767SAnurag.Maskey@Sun.COM 		}
57411767SAnurag.Maskey@Sun.COM 	} else {
57511767SAnurag.Maskey@Sun.COM 		if (scf_transaction_property_change(res->sr_tx, res->sr_ent,
57611767SAnurag.Maskey@Sun.COM 		    propname, proptype) == -1) {
57711767SAnurag.Maskey@Sun.COM 			goto failure;
57811767SAnurag.Maskey@Sun.COM 		}
57911767SAnurag.Maskey@Sun.COM 	}
58011767SAnurag.Maskey@Sun.COM 
58111767SAnurag.Maskey@Sun.COM 	if (scf_entry_add_value(res->sr_ent, res->sr_val) != 0) {
58211767SAnurag.Maskey@Sun.COM 		goto failure;
58311767SAnurag.Maskey@Sun.COM 	}
58411767SAnurag.Maskey@Sun.COM 
58511767SAnurag.Maskey@Sun.COM 	result = scf_transaction_commit(res->sr_tx);
58611767SAnurag.Maskey@Sun.COM 	if (result == 0) {
58711767SAnurag.Maskey@Sun.COM 		scf_transaction_reset(res->sr_tx);
58811767SAnurag.Maskey@Sun.COM 		if (scf_pg_update(res->sr_pg) == -1) {
58911767SAnurag.Maskey@Sun.COM 			goto failure;
59011767SAnurag.Maskey@Sun.COM 		}
59111767SAnurag.Maskey@Sun.COM 		nlog(LOG_INFO, "set_property_value: transaction commit failed "
59211767SAnurag.Maskey@Sun.COM 		    "for %s; retrying", propname);
59311767SAnurag.Maskey@Sun.COM 		goto retry;
59411767SAnurag.Maskey@Sun.COM 	}
59511767SAnurag.Maskey@Sun.COM 	if (result == -1)
59611767SAnurag.Maskey@Sun.COM 		goto failure;
59711767SAnurag.Maskey@Sun.COM 	return (0);
59811767SAnurag.Maskey@Sun.COM 
59911767SAnurag.Maskey@Sun.COM failure:
60011767SAnurag.Maskey@Sun.COM 	return (-1);
6013938Sjbeck }
60211767SAnurag.Maskey@Sun.COM 
60311767SAnurag.Maskey@Sun.COM int
60411767SAnurag.Maskey@Sun.COM nwamd_set_count_property(const char *fmri, const char *pg, const char *prop,
60511767SAnurag.Maskey@Sun.COM     uint64_t count)
60611767SAnurag.Maskey@Sun.COM {
60711767SAnurag.Maskey@Sun.COM 	scf_resources_t res;
60811767SAnurag.Maskey@Sun.COM 
60911767SAnurag.Maskey@Sun.COM 	if (create_scf_resources(fmri, &res) != 0)
61011767SAnurag.Maskey@Sun.COM 		return (-1);
61111767SAnurag.Maskey@Sun.COM 
61211767SAnurag.Maskey@Sun.COM 	if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION,
61311767SAnurag.Maskey@Sun.COM 	    SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) {
61411767SAnurag.Maskey@Sun.COM 		if (scf_error() != SCF_ERROR_EXISTS)
61511767SAnurag.Maskey@Sun.COM 			goto failure;
61611767SAnurag.Maskey@Sun.COM 		if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg,
61711767SAnurag.Maskey@Sun.COM 		    res.sr_pg) != 0)
61811767SAnurag.Maskey@Sun.COM 			goto failure;
61911767SAnurag.Maskey@Sun.COM 	}
62011767SAnurag.Maskey@Sun.COM 
62111767SAnurag.Maskey@Sun.COM 	scf_value_set_count(res.sr_val, (uint64_t)count);
62211767SAnurag.Maskey@Sun.COM 
62311767SAnurag.Maskey@Sun.COM 	if (set_property_value(&res, prop, SCF_TYPE_COUNT) != 0)
62411767SAnurag.Maskey@Sun.COM 		goto failure;
62511767SAnurag.Maskey@Sun.COM 
62611767SAnurag.Maskey@Sun.COM 	release_scf_resources(&res);
62711767SAnurag.Maskey@Sun.COM 	return (0);
62811767SAnurag.Maskey@Sun.COM 
62911767SAnurag.Maskey@Sun.COM failure:
63011767SAnurag.Maskey@Sun.COM 	nlog(LOG_INFO, "nwamd_set_count_property: scf failure %s while "
63111767SAnurag.Maskey@Sun.COM 	    "setting %s", scf_strerror(scf_error()), prop);
63211767SAnurag.Maskey@Sun.COM 	release_scf_resources(&res);
63311767SAnurag.Maskey@Sun.COM 	return (-1);
63411767SAnurag.Maskey@Sun.COM }
63511767SAnurag.Maskey@Sun.COM 
63611767SAnurag.Maskey@Sun.COM int
63711767SAnurag.Maskey@Sun.COM nwamd_set_string_property(const char *fmri, const char *pg, const char *prop,
63811767SAnurag.Maskey@Sun.COM     const char *str)
63911767SAnurag.Maskey@Sun.COM {
64011767SAnurag.Maskey@Sun.COM 	scf_resources_t res;
64111767SAnurag.Maskey@Sun.COM 
64211767SAnurag.Maskey@Sun.COM 	if (create_scf_resources(fmri, &res) != 0)
64311767SAnurag.Maskey@Sun.COM 		return (-1);
64411767SAnurag.Maskey@Sun.COM 
64511767SAnurag.Maskey@Sun.COM 	if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION,
64611767SAnurag.Maskey@Sun.COM 	    SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) {
64711767SAnurag.Maskey@Sun.COM 		if (scf_error() != SCF_ERROR_EXISTS)
64811767SAnurag.Maskey@Sun.COM 			goto failure;
64911767SAnurag.Maskey@Sun.COM 		if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg,
65011767SAnurag.Maskey@Sun.COM 		    res.sr_pg) != 0)
65111767SAnurag.Maskey@Sun.COM 			goto failure;
65211767SAnurag.Maskey@Sun.COM 	}
65311767SAnurag.Maskey@Sun.COM 
65411767SAnurag.Maskey@Sun.COM 	if (scf_value_set_astring(res.sr_val, str) != 0)
65511767SAnurag.Maskey@Sun.COM 		goto failure;
65611767SAnurag.Maskey@Sun.COM 
65711767SAnurag.Maskey@Sun.COM 	if (set_property_value(&res, prop, SCF_TYPE_ASTRING) != 0)
65811767SAnurag.Maskey@Sun.COM 		goto failure;
65911767SAnurag.Maskey@Sun.COM 
66011767SAnurag.Maskey@Sun.COM 	release_scf_resources(&res);
66111767SAnurag.Maskey@Sun.COM 	return (0);
66211767SAnurag.Maskey@Sun.COM 
66311767SAnurag.Maskey@Sun.COM failure:
66411767SAnurag.Maskey@Sun.COM 	nlog(LOG_INFO, "nwamd_set_string_property: scf failure %s while "
66511767SAnurag.Maskey@Sun.COM 	    "setting %s", scf_strerror(scf_error()), prop);
66611767SAnurag.Maskey@Sun.COM 	release_scf_resources(&res);
66711767SAnurag.Maskey@Sun.COM 	return (-1);
66811767SAnurag.Maskey@Sun.COM }
66911767SAnurag.Maskey@Sun.COM 
67011767SAnurag.Maskey@Sun.COM /*
67111767SAnurag.Maskey@Sun.COM  * Deletes property prop from property group pg in SMF instance fmri.
67211767SAnurag.Maskey@Sun.COM  * Returns 0 on success, -1 on failure.
67311767SAnurag.Maskey@Sun.COM  */
67411767SAnurag.Maskey@Sun.COM int
67511767SAnurag.Maskey@Sun.COM nwamd_delete_scf_property(const char *fmri, const char *pg, const char *prop)
67611767SAnurag.Maskey@Sun.COM {
67711767SAnurag.Maskey@Sun.COM 	scf_resources_t res;
67811767SAnurag.Maskey@Sun.COM 	int result = -1;
67911767SAnurag.Maskey@Sun.COM 
68011767SAnurag.Maskey@Sun.COM 	if (create_scf_resources(fmri, &res) != 0)
68111767SAnurag.Maskey@Sun.COM 		return (-1);
68211767SAnurag.Maskey@Sun.COM 
68311767SAnurag.Maskey@Sun.COM 	if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION,
68411767SAnurag.Maskey@Sun.COM 	    SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) {
68511767SAnurag.Maskey@Sun.COM 		if (scf_error() != SCF_ERROR_EXISTS)
68611767SAnurag.Maskey@Sun.COM 			goto failure;
68711767SAnurag.Maskey@Sun.COM 		if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg,
68811767SAnurag.Maskey@Sun.COM 		    res.sr_pg) != 0)
68911767SAnurag.Maskey@Sun.COM 			goto failure;
69011767SAnurag.Maskey@Sun.COM 	}
69111767SAnurag.Maskey@Sun.COM 
69211767SAnurag.Maskey@Sun.COM 	if (scf_pg_get_property(res.sr_pg, prop, res.sr_prop) != 0)
69311767SAnurag.Maskey@Sun.COM 		goto failure;
69411767SAnurag.Maskey@Sun.COM retry:
69511767SAnurag.Maskey@Sun.COM 	if (scf_transaction_start(res.sr_tx, res.sr_pg) == -1)
69611767SAnurag.Maskey@Sun.COM 		goto failure;
69711767SAnurag.Maskey@Sun.COM 
69811767SAnurag.Maskey@Sun.COM 	if (scf_transaction_property_delete(res.sr_tx, res.sr_ent, prop) == -1)
69911767SAnurag.Maskey@Sun.COM 		goto failure;
70011767SAnurag.Maskey@Sun.COM 
70111767SAnurag.Maskey@Sun.COM 	result = scf_transaction_commit(res.sr_tx);
70211767SAnurag.Maskey@Sun.COM 	if (result == 0) {
70311767SAnurag.Maskey@Sun.COM 		scf_transaction_reset(res.sr_tx);
70411767SAnurag.Maskey@Sun.COM 		if (scf_pg_update(res.sr_pg) == -1)
70511767SAnurag.Maskey@Sun.COM 			goto failure;
70611767SAnurag.Maskey@Sun.COM 		goto retry;
70711767SAnurag.Maskey@Sun.COM 	}
70811767SAnurag.Maskey@Sun.COM 	if (result == -1)
70911767SAnurag.Maskey@Sun.COM 		goto failure;
71011767SAnurag.Maskey@Sun.COM 
71111767SAnurag.Maskey@Sun.COM 	release_scf_resources(&res);
71211767SAnurag.Maskey@Sun.COM 	return (0);
71311767SAnurag.Maskey@Sun.COM failure:
71411767SAnurag.Maskey@Sun.COM 	release_scf_resources(&res);
71511767SAnurag.Maskey@Sun.COM 	return (-1);
71611767SAnurag.Maskey@Sun.COM }
717