xref: /titanic_51/usr/src/cmd/cmd-inet/lib/nwamd/util.c (revision f6da83d4178694e7113b71d1e452f15b296f73d8)
1d71dbb73Sjbeck /*
2d71dbb73Sjbeck  * CDDL HEADER START
3d71dbb73Sjbeck  *
4d71dbb73Sjbeck  * The contents of this file are subject to the terms of the
5d71dbb73Sjbeck  * Common Development and Distribution License (the "License").
6d71dbb73Sjbeck  * You may not use this file except in compliance with the License.
7d71dbb73Sjbeck  *
8d71dbb73Sjbeck  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d71dbb73Sjbeck  * or http://www.opensolaris.org/os/licensing.
10d71dbb73Sjbeck  * See the License for the specific language governing permissions
11d71dbb73Sjbeck  * and limitations under the License.
12d71dbb73Sjbeck  *
13d71dbb73Sjbeck  * When distributing Covered Code, include this CDDL HEADER in each
14d71dbb73Sjbeck  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d71dbb73Sjbeck  * If applicable, add the following below this CDDL HEADER, with the
16d71dbb73Sjbeck  * fields enclosed by brackets "[]" replaced with your own identifying
17d71dbb73Sjbeck  * information: Portions Copyright [yyyy] [name of copyright owner]
18d71dbb73Sjbeck  *
19d71dbb73Sjbeck  * CDDL HEADER END
20d71dbb73Sjbeck  */
21d71dbb73Sjbeck 
22d71dbb73Sjbeck /*
23*f6da83d4SAnurag S. Maskey  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24d71dbb73Sjbeck  */
25d71dbb73Sjbeck 
26d71dbb73Sjbeck /*
276ba597c5SAnurag S. Maskey  * util.c contains a set of miscellaneous utility functions which,
286ba597c5SAnurag S. Maskey  * among other things:
29d71dbb73Sjbeck  * - start a child process
30d71dbb73Sjbeck  * - look up the zone name
316ba597c5SAnurag S. Maskey  * - look up/set SMF properties
326ba597c5SAnurag S. Maskey  * - drop/escalate privs
33d71dbb73Sjbeck  */
34d71dbb73Sjbeck 
356ba597c5SAnurag S. Maskey #include <assert.h>
366ba597c5SAnurag S. Maskey #include <errno.h>
376ba597c5SAnurag S. Maskey #include <libdllink.h>
386ba597c5SAnurag S. Maskey #include <limits.h>
396ba597c5SAnurag S. Maskey #include <libscf.h>
406ba597c5SAnurag S. Maskey #include <net/if.h>
416ba597c5SAnurag S. Maskey #include <pthread.h>
426ba597c5SAnurag S. Maskey #include <pwd.h>
436ba597c5SAnurag S. Maskey #include <spawn.h>
44d71dbb73Sjbeck #include <stdarg.h>
45d71dbb73Sjbeck #include <stdio.h>
46d71dbb73Sjbeck #include <stdlib.h>
47d71dbb73Sjbeck #include <string.h>
486ba597c5SAnurag S. Maskey #include <strings.h>
49d71dbb73Sjbeck #include <stropts.h>
50d71dbb73Sjbeck #include <sys/socket.h>
516ba597c5SAnurag S. Maskey #include <sys/sockio.h>
526ba597c5SAnurag S. Maskey #include <sys/types.h>
536ba597c5SAnurag S. Maskey #include <unistd.h>
54d71dbb73Sjbeck #include <wait.h>
55d71dbb73Sjbeck #include <zone.h>
56d71dbb73Sjbeck 
576ba597c5SAnurag S. Maskey #include "util.h"
586ba597c5SAnurag S. Maskey #include "llp.h"
59d71dbb73Sjbeck 
60d71dbb73Sjbeck extern char **environ;
616ba597c5SAnurag S. Maskey extern sigset_t original_sigmask;
62d71dbb73Sjbeck 
63d71dbb73Sjbeck /*
646ba597c5SAnurag S. Maskey  * A holder for all the resources needed to get a property value
656ba597c5SAnurag S. Maskey  * using libscf.
66d71dbb73Sjbeck  */
676ba597c5SAnurag S. Maskey typedef struct scf_resources {
686ba597c5SAnurag S. Maskey 	scf_handle_t *sr_handle;
696ba597c5SAnurag S. Maskey 	scf_instance_t *sr_inst;
706ba597c5SAnurag S. Maskey 	scf_snapshot_t *sr_snap;
716ba597c5SAnurag S. Maskey 	scf_propertygroup_t *sr_pg;
726ba597c5SAnurag S. Maskey 	scf_property_t *sr_prop;
736ba597c5SAnurag S. Maskey 	scf_value_t *sr_val;
746ba597c5SAnurag S. Maskey 	scf_transaction_t *sr_tx;
756ba597c5SAnurag S. Maskey 	scf_transaction_entry_t *sr_ent;
766ba597c5SAnurag S. Maskey } scf_resources_t;
77d71dbb73Sjbeck 
786ba597c5SAnurag S. Maskey static pthread_mutex_t uid_mutex = PTHREAD_MUTEX_INITIALIZER;
796ba597c5SAnurag S. Maskey static uid_t uid;
806ba597c5SAnurag S. Maskey static int uid_cnt;
81d71dbb73Sjbeck 
82b00044a2SJames Carlson void
8338f140aaSMichael Hunter nwamd_escalate(void) {
8438f140aaSMichael Hunter 	priv_set_t *priv_set;
8538f140aaSMichael Hunter 	priv_set = priv_str_to_set("zone", ",", NULL);
8638f140aaSMichael Hunter 
8738f140aaSMichael Hunter 	if (priv_set == NULL)
8838f140aaSMichael Hunter 		pfail("creating privilege set: %s", strerror(errno));
8938f140aaSMichael Hunter 
906ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&uid_mutex);
916ba597c5SAnurag S. Maskey 	if (uid == 0)
926ba597c5SAnurag S. Maskey 		uid = getuid();
936ba597c5SAnurag S. Maskey 	if (uid_cnt++ == 0) {
9438f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) {
9538f140aaSMichael Hunter 			priv_freeset(priv_set);
9638f140aaSMichael Hunter 			pfail("setppriv effective: %s", strerror(errno));
9738f140aaSMichael Hunter 		}
98b00044a2SJames Carlson 	}
996ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&uid_mutex);
10038f140aaSMichael Hunter 
10138f140aaSMichael Hunter 	priv_freeset(priv_set);
1026ba597c5SAnurag S. Maskey }
1036ba597c5SAnurag S. Maskey 
1046ba597c5SAnurag S. Maskey void
10538f140aaSMichael Hunter nwamd_deescalate(void) {
1066ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&uid_mutex);
1073773ed2dSAnurag S. Maskey 
1086ba597c5SAnurag S. Maskey 	assert(uid_cnt > 0);
1096ba597c5SAnurag S. Maskey 	if (--uid_cnt == 0) {
1103773ed2dSAnurag S. Maskey 		priv_set_t *priv_set, *allpriv_set;
1113773ed2dSAnurag S. Maskey 
11238f140aaSMichael Hunter 		/* build up our minimal set of privs. */
11338f140aaSMichael Hunter 		priv_set = priv_str_to_set("basic", ",", NULL);
11438f140aaSMichael Hunter 		allpriv_set = priv_str_to_set("zone", ",", NULL);
11538f140aaSMichael Hunter 		if (priv_set == NULL || allpriv_set == NULL)
11638f140aaSMichael Hunter 			pfail("converting privilege sets: %s", strerror(errno));
11738f140aaSMichael Hunter 
11838f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_FILE_CHOWN_SELF);
11938f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_FILE_DAC_READ);
12038f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_FILE_DAC_WRITE);
12138f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_NET_RAWACCESS);
12238f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_NET_PRIVADDR);
12338f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_PROC_AUDIT);
12438f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_PROC_OWNER);
12538f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_PROC_SETID);
12638f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_CONFIG);
12738f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_IP_CONFIG);
12838f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_IPC_CONFIG);
12938f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_MOUNT);
13038f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_NET_CONFIG);
13138f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_RES_CONFIG);
13238f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_RESOURCE);
13338f140aaSMichael Hunter 
13438f140aaSMichael Hunter 		/*
13538f140aaSMichael Hunter 		 * Since our zone might not have all these privs,
13638f140aaSMichael Hunter 		 * just ask for those that are available.
13738f140aaSMichael Hunter 		 */
13838f140aaSMichael Hunter 		priv_intersect(allpriv_set, priv_set);
13938f140aaSMichael Hunter 
14038f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_INHERITABLE, priv_set) == -1) {
14138f140aaSMichael Hunter 			priv_freeset(allpriv_set);
14238f140aaSMichael Hunter 			priv_freeset(priv_set);
14338f140aaSMichael Hunter 			pfail("setppriv inheritable: %s", strerror(errno));
14438f140aaSMichael Hunter 		}
14538f140aaSMichael Hunter 		/*
14638f140aaSMichael Hunter 		 * Need to ensure permitted set contains all privs so we can
14738f140aaSMichael Hunter 		 * escalate later.
14838f140aaSMichael Hunter 		 */
14938f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_PERMITTED, allpriv_set) == -1) {
15038f140aaSMichael Hunter 			priv_freeset(allpriv_set);
15138f140aaSMichael Hunter 			priv_freeset(priv_set);
15238f140aaSMichael Hunter 			pfail("setppriv permitted: %s", strerror(errno));
15338f140aaSMichael Hunter 		}
15438f140aaSMichael Hunter 		/*
15538f140aaSMichael Hunter 		 * We need to find a smaller set of privs that are important to
15638f140aaSMichael Hunter 		 * us.  Otherwise we really are not gaining much by doing this.
15738f140aaSMichael Hunter 		 */
15838f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) {
15938f140aaSMichael Hunter 			priv_freeset(allpriv_set);
16038f140aaSMichael Hunter 			priv_freeset(priv_set);
16138f140aaSMichael Hunter 			pfail("setppriv effective: %s", strerror(errno));
16238f140aaSMichael Hunter 		}
16338f140aaSMichael Hunter 
16438f140aaSMichael Hunter 		priv_freeset(priv_set);
16538f140aaSMichael Hunter 		priv_freeset(allpriv_set);
166b00044a2SJames Carlson 	}
1673773ed2dSAnurag S. Maskey 	(void) pthread_mutex_unlock(&uid_mutex);
1683773ed2dSAnurag S. Maskey }
169b00044a2SJames Carlson 
170d71dbb73Sjbeck /*
171d71dbb73Sjbeck  *
172d71dbb73Sjbeck  * This starts a child process determined by command.  If command contains a
173d71dbb73Sjbeck  * slash then it is assumed to be a full path; otherwise the path is searched
174d71dbb73Sjbeck  * for an executable file with the name command.  Command is also used as
175d71dbb73Sjbeck  * argv[0] of the new process.  The rest of the arguments of the function
176d71dbb73Sjbeck  * up to the first NULL make up pointers to arguments of the new process.
177d71dbb73Sjbeck  *
178d71dbb73Sjbeck  * This function returns child exit status on success and -1 on failure.
179d71dbb73Sjbeck  *
180d71dbb73Sjbeck  * NOTE: original_sigmask must be set before this function is called.
181d71dbb73Sjbeck  */
182d71dbb73Sjbeck int
1836ba597c5SAnurag S. Maskey nwamd_start_childv(const char *command, char const * const *argv)
184d71dbb73Sjbeck {
185d71dbb73Sjbeck 	posix_spawnattr_t attr;
186d71dbb73Sjbeck 	sigset_t fullset;
187d71dbb73Sjbeck 	int i, rc, status, n;
188d71dbb73Sjbeck 	pid_t pid;
189d71dbb73Sjbeck 	char vbuf[1024];
190d71dbb73Sjbeck 
191d71dbb73Sjbeck 	vbuf[0] = 0;
192d71dbb73Sjbeck 	n = sizeof (vbuf);
193d71dbb73Sjbeck 	for (i = 1; argv[i] != NULL && n > 2; i++) {
194d71dbb73Sjbeck 		n -= strlcat(vbuf, " ", n);
195d71dbb73Sjbeck 		n -= strlcat(vbuf, argv[i], n);
196d71dbb73Sjbeck 	}
197d71dbb73Sjbeck 	if (argv[i] != NULL || n < 0)
1986ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_start_childv can't log full arg vector");
199d71dbb73Sjbeck 
200d71dbb73Sjbeck 	if ((rc = posix_spawnattr_init(&attr)) != 0) {
2016ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "posix_spawnattr_init %d %s\n",
2026ba597c5SAnurag S. Maskey 		    rc, strerror(rc));
203d71dbb73Sjbeck 		return (-1);
204d71dbb73Sjbeck 	}
205d71dbb73Sjbeck 	(void) sigfillset(&fullset);
206d71dbb73Sjbeck 	if ((rc = posix_spawnattr_setsigdefault(&attr, &fullset)) != 0) {
2076ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "setsigdefault %d %s\n", rc, strerror(rc));
208d71dbb73Sjbeck 		return (-1);
209d71dbb73Sjbeck 	}
210d71dbb73Sjbeck 	if ((rc = posix_spawnattr_setsigmask(&attr, &original_sigmask)) != 0) {
2116ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "setsigmask %d %s\n", rc, strerror(rc));
212d71dbb73Sjbeck 		return (-1);
213d71dbb73Sjbeck 	}
214d71dbb73Sjbeck 	if ((rc = posix_spawnattr_setflags(&attr,
215d71dbb73Sjbeck 	    POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK)) != 0) {
2166ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "setflags %d %s\n", rc, strerror(rc));
217d71dbb73Sjbeck 		return (-1);
218d71dbb73Sjbeck 	}
219d71dbb73Sjbeck 
220d71dbb73Sjbeck 	if ((rc = posix_spawnp(&pid, command, NULL, &attr, (char * const *)argv,
221d71dbb73Sjbeck 	    environ)) > 0) {
2226ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "posix_spawnp failed errno %d", rc);
223d71dbb73Sjbeck 		return (-1);
224d71dbb73Sjbeck 	}
225d71dbb73Sjbeck 
226d71dbb73Sjbeck 	if ((rc = posix_spawnattr_destroy(&attr)) != 0) {
2276ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "posix_spawn_attr_destroy %d %s\n",
2286ba597c5SAnurag S. Maskey 		    rc, strerror(rc));
229d71dbb73Sjbeck 		return (-1);
230d71dbb73Sjbeck 	}
231d71dbb73Sjbeck 
232d71dbb73Sjbeck 	(void) waitpid(pid, &status, 0);
233d71dbb73Sjbeck 	if (WIFSIGNALED(status) || WIFSTOPPED(status)) {
234d71dbb73Sjbeck 		i = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status);
2356ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "'%s%s' %s with signal %d (%s)", command, vbuf,
236d71dbb73Sjbeck 		    (WIFSIGNALED(status) ? "terminated" : "stopped"), i,
237d71dbb73Sjbeck 		    strsignal(i));
238d71dbb73Sjbeck 		return (-2);
239d71dbb73Sjbeck 	} else {
2406ba597c5SAnurag S. Maskey 		nlog(LOG_INFO, "'%s%s' completed normally: %d", command, vbuf,
241d71dbb73Sjbeck 		    WEXITSTATUS(status));
242d71dbb73Sjbeck 		return (WEXITSTATUS(status));
243d71dbb73Sjbeck 	}
244d71dbb73Sjbeck }
245d71dbb73Sjbeck 
2466ba597c5SAnurag S. Maskey /*
2476ba597c5SAnurag S. Maskey  * For global zone, check if the link is used by a non-global
2486ba597c5SAnurag S. Maskey  * zone, note that the non-global zones doesn't need this check,
2496ba597c5SAnurag S. Maskey  * because zoneadm has taken care of this when the zone boots.
2506ba597c5SAnurag S. Maskey  * In the global zone, we ignore events for local-zone-owned links
2516ba597c5SAnurag S. Maskey  * since these are taken care of by the local zone's network
2526ba597c5SAnurag S. Maskey  * configuration services.
2536ba597c5SAnurag S. Maskey  */
2546ba597c5SAnurag S. Maskey boolean_t
2556ba597c5SAnurag S. Maskey nwamd_link_belongs_to_this_zone(const char *linkname)
256d71dbb73Sjbeck {
2576ba597c5SAnurag S. Maskey 	zoneid_t zoneid;
2586ba597c5SAnurag S. Maskey 	char zonename[ZONENAME_MAX];
2596ba597c5SAnurag S. Maskey 	int ret;
260d71dbb73Sjbeck 
2616ba597c5SAnurag S. Maskey 	zoneid = getzoneid();
2626ba597c5SAnurag S. Maskey 	if (zoneid == GLOBAL_ZONEID) {
2636ba597c5SAnurag S. Maskey 		datalink_id_t linkid;
2646ba597c5SAnurag S. Maskey 		dladm_status_t status;
2656ba597c5SAnurag S. Maskey 		char errstr[DLADM_STRSIZE];
266d71dbb73Sjbeck 
2676ba597c5SAnurag S. Maskey 		if ((status = dladm_name2info(dld_handle, linkname, &linkid,
2686ba597c5SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
2696ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: "
2706ba597c5SAnurag S. Maskey 			    "could not get linkid for %s: %s",
2716ba597c5SAnurag S. Maskey 			    linkname, dladm_status2str(status, errstr));
2726ba597c5SAnurag S. Maskey 			return (B_FALSE);
2736ba597c5SAnurag S. Maskey 		}
2746ba597c5SAnurag S. Maskey 		zoneid = ALL_ZONES;
2756ba597c5SAnurag S. Maskey 		ret = zone_check_datalink(&zoneid, linkid);
2766ba597c5SAnurag S. Maskey 		if (ret == 0) {
2776ba597c5SAnurag S. Maskey 			(void) getzonenamebyid(zoneid, zonename, ZONENAME_MAX);
2786ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: "
2796ba597c5SAnurag S. Maskey 			    "%s is used by non-global zone: %s",
2806ba597c5SAnurag S. Maskey 			    linkname, zonename);
2816ba597c5SAnurag S. Maskey 			return (B_FALSE);
282d71dbb73Sjbeck 		}
283d71dbb73Sjbeck 	}
2846ba597c5SAnurag S. Maskey 	return (B_TRUE);
285d71dbb73Sjbeck }
286d71dbb73Sjbeck 
2876ba597c5SAnurag S. Maskey /*
2886ba597c5SAnurag S. Maskey  * Inputs:
2896ba597c5SAnurag S. Maskey  *   res is a pointer to the scf_resources_t to be released.
2906ba597c5SAnurag S. Maskey  */
2916ba597c5SAnurag S. Maskey static void
2926ba597c5SAnurag S. Maskey release_scf_resources(scf_resources_t *res)
2936ba597c5SAnurag S. Maskey {
2946ba597c5SAnurag S. Maskey 	scf_entry_destroy(res->sr_ent);
2956ba597c5SAnurag S. Maskey 	scf_transaction_destroy(res->sr_tx);
2966ba597c5SAnurag S. Maskey 	scf_value_destroy(res->sr_val);
2976ba597c5SAnurag S. Maskey 	scf_property_destroy(res->sr_prop);
2986ba597c5SAnurag S. Maskey 	scf_pg_destroy(res->sr_pg);
2996ba597c5SAnurag S. Maskey 	scf_snapshot_destroy(res->sr_snap);
3006ba597c5SAnurag S. Maskey 	scf_instance_destroy(res->sr_inst);
3016ba597c5SAnurag S. Maskey 	(void) scf_handle_unbind(res->sr_handle);
3026ba597c5SAnurag S. Maskey 	scf_handle_destroy(res->sr_handle);
3036ba597c5SAnurag S. Maskey }
3046ba597c5SAnurag S. Maskey 
3056ba597c5SAnurag S. Maskey /*
3066ba597c5SAnurag S. Maskey  * Inputs:
3076ba597c5SAnurag S. Maskey  *   fmri is the instance to look up
3086ba597c5SAnurag S. Maskey  * Outputs:
3096ba597c5SAnurag S. Maskey  *   res is a pointer to an scf_resources_t.  This is an internal
3106ba597c5SAnurag S. Maskey  *   structure that holds all the handles needed to get a specific
3116ba597c5SAnurag S. Maskey  *   property from the running snapshot; on a successful return it
3126ba597c5SAnurag S. Maskey  *   contains the scf_value_t that should be passed to the desired
3136ba597c5SAnurag S. Maskey  *   scf_value_get_foo() function, and must be freed after use by
3146ba597c5SAnurag S. Maskey  *   calling release_scf_resources().  On a failure return, any
3156ba597c5SAnurag S. Maskey  *   resources that may have been assigned to res are released, so
3166ba597c5SAnurag S. Maskey  *   the caller does not need to do any cleanup in the failure case.
3176ba597c5SAnurag S. Maskey  * Returns:
3186ba597c5SAnurag S. Maskey  *    0 on success
3196ba597c5SAnurag S. Maskey  *   -1 on failure
3206ba597c5SAnurag S. Maskey  */
3216ba597c5SAnurag S. Maskey 
3226ba597c5SAnurag S. Maskey static int
3236ba597c5SAnurag S. Maskey create_scf_resources(const char *fmri, scf_resources_t *res)
3246ba597c5SAnurag S. Maskey {
3256ba597c5SAnurag S. Maskey 	res->sr_tx = NULL;
3266ba597c5SAnurag S. Maskey 	res->sr_ent = NULL;
3276ba597c5SAnurag S. Maskey 	res->sr_inst = NULL;
3286ba597c5SAnurag S. Maskey 	res->sr_snap = NULL;
3296ba597c5SAnurag S. Maskey 	res->sr_pg = NULL;
3306ba597c5SAnurag S. Maskey 	res->sr_prop = NULL;
3316ba597c5SAnurag S. Maskey 	res->sr_val = NULL;
3326ba597c5SAnurag S. Maskey 
3336ba597c5SAnurag S. Maskey 	if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL) {
3346ba597c5SAnurag S. Maskey 		return (-1);
3356ba597c5SAnurag S. Maskey 	}
3366ba597c5SAnurag S. Maskey 
3376ba597c5SAnurag S. Maskey 	if (scf_handle_bind(res->sr_handle) != 0) {
3386ba597c5SAnurag S. Maskey 		scf_handle_destroy(res->sr_handle);
3396ba597c5SAnurag S. Maskey 		return (-1);
3406ba597c5SAnurag S. Maskey 	}
3416ba597c5SAnurag S. Maskey 	if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL) {
3426ba597c5SAnurag S. Maskey 		goto failure;
3436ba597c5SAnurag S. Maskey 	}
3446ba597c5SAnurag S. Maskey 	if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL,
3456ba597c5SAnurag S. Maskey 	    res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
3466ba597c5SAnurag S. Maskey 		goto failure;
3476ba597c5SAnurag S. Maskey 	}
3486ba597c5SAnurag S. Maskey 	if ((res->sr_snap = scf_snapshot_create(res->sr_handle)) == NULL) {
3496ba597c5SAnurag S. Maskey 		goto failure;
3506ba597c5SAnurag S. Maskey 	}
3516ba597c5SAnurag S. Maskey 	if (scf_instance_get_snapshot(res->sr_inst, "running",
3526ba597c5SAnurag S. Maskey 	    res->sr_snap) != 0) {
3536ba597c5SAnurag S. Maskey 		goto failure;
3546ba597c5SAnurag S. Maskey 	}
3556ba597c5SAnurag S. Maskey 	if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
3566ba597c5SAnurag S. Maskey 		goto failure;
3576ba597c5SAnurag S. Maskey 	}
3586ba597c5SAnurag S. Maskey 	if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL) {
3596ba597c5SAnurag S. Maskey 		goto failure;
3606ba597c5SAnurag S. Maskey 	}
3616ba597c5SAnurag S. Maskey 	if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL) {
3626ba597c5SAnurag S. Maskey 		goto failure;
3636ba597c5SAnurag S. Maskey 	}
3646ba597c5SAnurag S. Maskey 	if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL) {
3656ba597c5SAnurag S. Maskey 		goto failure;
3666ba597c5SAnurag S. Maskey 	}
3676ba597c5SAnurag S. Maskey 	if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL) {
3686ba597c5SAnurag S. Maskey 		goto failure;
3696ba597c5SAnurag S. Maskey 	}
3706ba597c5SAnurag S. Maskey 	return (0);
3716ba597c5SAnurag S. Maskey 
3726ba597c5SAnurag S. Maskey failure:
3736ba597c5SAnurag S. Maskey 	nlog(LOG_ERR, "create_scf_resources failed: %s",
3746ba597c5SAnurag S. Maskey 	    scf_strerror(scf_error()));
3756ba597c5SAnurag S. Maskey 	release_scf_resources(res);
3766ba597c5SAnurag S. Maskey 	return (-1);
3776ba597c5SAnurag S. Maskey }
3786ba597c5SAnurag S. Maskey 
3796ba597c5SAnurag S. Maskey /*
3806ba597c5SAnurag S. Maskey  * Inputs:
3816ba597c5SAnurag S. Maskey  *   fmri is the instance to look up
3826ba597c5SAnurag S. Maskey  *   pg is the property group to look up
3836ba597c5SAnurag S. Maskey  *   prop is the property within that group to look up
3846ba597c5SAnurag S. Maskey  *   running specifies if running snapshot is to be used
3856ba597c5SAnurag S. Maskey  * Outputs:
3866ba597c5SAnurag S. Maskey  *   res is a pointer to an scf_resources_t.  This is an internal
3876ba597c5SAnurag S. Maskey  *   structure that holds all the handles needed to get a specific
3886ba597c5SAnurag S. Maskey  *   property from the running snapshot; on a successful return it
3896ba597c5SAnurag S. Maskey  *   contains the scf_value_t that should be passed to the desired
3906ba597c5SAnurag S. Maskey  *   scf_value_get_foo() function, and must be freed after use by
3916ba597c5SAnurag S. Maskey  *   calling release_scf_resources().  On a failure return, any
3926ba597c5SAnurag S. Maskey  *   resources that may have been assigned to res are released, so
3936ba597c5SAnurag S. Maskey  *   the caller does not need to do any cleanup in the failure case.
3946ba597c5SAnurag S. Maskey  * Returns:
3956ba597c5SAnurag S. Maskey  *    0 on success
3966ba597c5SAnurag S. Maskey  *   -1 on failure
3976ba597c5SAnurag S. Maskey  */
3986ba597c5SAnurag S. Maskey static int
3996ba597c5SAnurag S. Maskey get_property_value(const char *fmri, const char *pg, const char *prop,
4006ba597c5SAnurag S. Maskey     boolean_t running, scf_resources_t *res)
4016ba597c5SAnurag S. Maskey {
4026ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, res) != 0)
4036ba597c5SAnurag S. Maskey 		return (-1);
4046ba597c5SAnurag S. Maskey 
4056ba597c5SAnurag S. Maskey 	if (scf_instance_get_pg_composed(res->sr_inst,
4066ba597c5SAnurag S. Maskey 	    running ? res->sr_snap : NULL, pg, res->sr_pg) != 0) {
4076ba597c5SAnurag S. Maskey 		goto failure;
4086ba597c5SAnurag S. Maskey 	}
4096ba597c5SAnurag S. Maskey 	if (scf_pg_get_property(res->sr_pg, prop, res->sr_prop) != 0) {
4106ba597c5SAnurag S. Maskey 		goto failure;
4116ba597c5SAnurag S. Maskey 	}
4126ba597c5SAnurag S. Maskey 	if (scf_property_get_value(res->sr_prop, res->sr_val) != 0) {
4136ba597c5SAnurag S. Maskey 		goto failure;
4146ba597c5SAnurag S. Maskey 	}
4156ba597c5SAnurag S. Maskey 	return (0);
4166ba597c5SAnurag S. Maskey 
4176ba597c5SAnurag S. Maskey failure:
4186ba597c5SAnurag S. Maskey 	release_scf_resources(res);
4196ba597c5SAnurag S. Maskey 	return (-1);
4206ba597c5SAnurag S. Maskey }
4216ba597c5SAnurag S. Maskey 
4226ba597c5SAnurag S. Maskey /*
4236ba597c5SAnurag S. Maskey  * Inputs:
4246ba597c5SAnurag S. Maskey  *   lfmri is the instance fmri to look up
4256ba597c5SAnurag S. Maskey  *   lpg is the property group to look up
4266ba597c5SAnurag S. Maskey  *   lprop is the property within that group to look up
4276ba597c5SAnurag S. Maskey  * Outputs:
4286ba597c5SAnurag S. Maskey  *   answer is a pointer to the property value
4296ba597c5SAnurag S. Maskey  * Returns:
4306ba597c5SAnurag S. Maskey  *    0 on success
4316ba597c5SAnurag S. Maskey  *   -1 on failure
4326ba597c5SAnurag S. Maskey  * If successful, the property value is retured in *answer.
4336ba597c5SAnurag S. Maskey  * Otherwise, *answer is undefined, and it is up to the caller to decide
4346ba597c5SAnurag S. Maskey  * how to handle that case.
4356ba597c5SAnurag S. Maskey  */
4366ba597c5SAnurag S. Maskey int
4376ba597c5SAnurag S. Maskey nwamd_lookup_boolean_property(const char *lfmri, const char *lpg,
4386ba597c5SAnurag S. Maskey     const char *lprop, boolean_t *answer)
4396ba597c5SAnurag S. Maskey {
4406ba597c5SAnurag S. Maskey 	int result = -1;
4416ba597c5SAnurag S. Maskey 	scf_resources_t res;
4426ba597c5SAnurag S. Maskey 	uint8_t prop_val;
4436ba597c5SAnurag S. Maskey 
4446ba597c5SAnurag S. Maskey 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
4456ba597c5SAnurag S. Maskey 
4466ba597c5SAnurag S. Maskey 		/*
4476ba597c5SAnurag S. Maskey 		 * an error was already logged by get_property_value,
4486ba597c5SAnurag S. Maskey 		 * and it released any resources assigned to res before
4496ba597c5SAnurag S. Maskey 		 * returning.
4506ba597c5SAnurag S. Maskey 		 */
4516ba597c5SAnurag S. Maskey 		return (result);
4526ba597c5SAnurag S. Maskey 	}
4536ba597c5SAnurag S. Maskey 	if (scf_value_get_boolean(res.sr_val, &prop_val) != 0) {
4546ba597c5SAnurag S. Maskey 		goto cleanup;
4556ba597c5SAnurag S. Maskey 	}
4566ba597c5SAnurag S. Maskey 	*answer = (boolean_t)prop_val;
4576ba597c5SAnurag S. Maskey 	result = 0;
4586ba597c5SAnurag S. Maskey cleanup:
4596ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
4606ba597c5SAnurag S. Maskey 	return (result);
4616ba597c5SAnurag S. Maskey }
4626ba597c5SAnurag S. Maskey 
4636ba597c5SAnurag S. Maskey /*
4646ba597c5SAnurag S. Maskey  * Inputs:
4656ba597c5SAnurag S. Maskey  *   lfmri is the instance fmri to look up
4666ba597c5SAnurag S. Maskey  *   lpg is the property group to look up
4676ba597c5SAnurag S. Maskey  *   lprop is the property within that group to look up
4686ba597c5SAnurag S. Maskey  *   buf is the place to put the answer
4696ba597c5SAnurag S. Maskey  *   bufsz is the size of buf
4706ba597c5SAnurag S. Maskey  * Outputs:
4716ba597c5SAnurag S. Maskey  *
4726ba597c5SAnurag S. Maskey  * Returns:
4736ba597c5SAnurag S. Maskey  *    0 on success
4746ba597c5SAnurag S. Maskey  *   -1 on failure
4756ba597c5SAnurag S. Maskey  * If successful, the property value is retured in buf.
4766ba597c5SAnurag S. Maskey  * Otherwise, buf is undefined, and it is up to the caller to decide
4776ba597c5SAnurag S. Maskey  * how to handle that case.
4786ba597c5SAnurag S. Maskey  */
4796ba597c5SAnurag S. Maskey int
4806ba597c5SAnurag S. Maskey nwamd_lookup_string_property(const char *lfmri, const char *lpg,
4816ba597c5SAnurag S. Maskey     const char *lprop, char *buf, size_t bufsz)
4826ba597c5SAnurag S. Maskey {
4836ba597c5SAnurag S. Maskey 	int result = -1;
4846ba597c5SAnurag S. Maskey 	scf_resources_t res;
4856ba597c5SAnurag S. Maskey 
4866ba597c5SAnurag S. Maskey 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
4876ba597c5SAnurag S. Maskey 		/*
4886ba597c5SAnurag S. Maskey 		 * The above function fails when trying to get a
4896ba597c5SAnurag S. Maskey 		 * non-persistent property group from the running snapshot.
4906ba597c5SAnurag S. Maskey 		 * Try going for the non-running snapshot.
4916ba597c5SAnurag S. Maskey 		 */
4926ba597c5SAnurag S. Maskey 		if (get_property_value(lfmri, lpg, lprop, B_FALSE, &res) != 0) {
4936ba597c5SAnurag S. Maskey 			/*
4946ba597c5SAnurag S. Maskey 			 * an error was already logged by get_property_value,
4956ba597c5SAnurag S. Maskey 			 * and it released any resources assigned to res before
4966ba597c5SAnurag S. Maskey 			 * returning.
4976ba597c5SAnurag S. Maskey 			 */
4986ba597c5SAnurag S. Maskey 			return (result);
4996ba597c5SAnurag S. Maskey 		}
5006ba597c5SAnurag S. Maskey 	}
5016ba597c5SAnurag S. Maskey 	if (scf_value_get_astring(res.sr_val, buf, bufsz) == 0)
5026ba597c5SAnurag S. Maskey 		goto cleanup;
5036ba597c5SAnurag S. Maskey 
5046ba597c5SAnurag S. Maskey 	result = 0;
5056ba597c5SAnurag S. Maskey cleanup:
5066ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
5076ba597c5SAnurag S. Maskey 	return (result);
5086ba597c5SAnurag S. Maskey }
5096ba597c5SAnurag S. Maskey 
5106ba597c5SAnurag S. Maskey /*
5116ba597c5SAnurag S. Maskey  * Inputs:
5126ba597c5SAnurag S. Maskey  *   lfmri is the instance fmri to look up
5136ba597c5SAnurag S. Maskey  *   lpg is the property group to look up
5146ba597c5SAnurag S. Maskey  *   lprop is the property within that group to look up
5156ba597c5SAnurag S. Maskey  * Outputs:
5166ba597c5SAnurag S. Maskey  *   answer is a pointer to the property value
5176ba597c5SAnurag S. Maskey  * Returns:
5186ba597c5SAnurag S. Maskey  *    0 on success
5196ba597c5SAnurag S. Maskey  *   -1 on failure
5206ba597c5SAnurag S. Maskey  * If successful, the property value is retured in *answer.
5216ba597c5SAnurag S. Maskey  * Otherwise, *answer is undefined, and it is up to the caller to decide
5226ba597c5SAnurag S. Maskey  * how to handle that case.
5236ba597c5SAnurag S. Maskey  */
5246ba597c5SAnurag S. Maskey int
5256ba597c5SAnurag S. Maskey nwamd_lookup_count_property(const char *lfmri, const char *lpg,
5266ba597c5SAnurag S. Maskey     const char *lprop, uint64_t *answer)
5276ba597c5SAnurag S. Maskey {
5286ba597c5SAnurag S. Maskey 	int result = -1;
5296ba597c5SAnurag S. Maskey 	scf_resources_t res;
5306ba597c5SAnurag S. Maskey 
5316ba597c5SAnurag S. Maskey 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
5326ba597c5SAnurag S. Maskey 
5336ba597c5SAnurag S. Maskey 		/*
5346ba597c5SAnurag S. Maskey 		 * an error was already logged by get_property_value,
5356ba597c5SAnurag S. Maskey 		 * and it released any resources assigned to res before
5366ba597c5SAnurag S. Maskey 		 * returning.
5376ba597c5SAnurag S. Maskey 		 */
5386ba597c5SAnurag S. Maskey 		return (result);
5396ba597c5SAnurag S. Maskey 	}
5406ba597c5SAnurag S. Maskey 	if (scf_value_get_count(res.sr_val, answer) != 0) {
5416ba597c5SAnurag S. Maskey 		goto cleanup;
5426ba597c5SAnurag S. Maskey 	}
5436ba597c5SAnurag S. Maskey 	result = 0;
5446ba597c5SAnurag S. Maskey cleanup:
5456ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
5466ba597c5SAnurag S. Maskey 	return (result);
5476ba597c5SAnurag S. Maskey }
5486ba597c5SAnurag S. Maskey 
5496ba597c5SAnurag S. Maskey static int
5506ba597c5SAnurag S. Maskey set_property_value(scf_resources_t *res, const char *propname,
5516ba597c5SAnurag S. Maskey     scf_type_t proptype)
5526ba597c5SAnurag S. Maskey {
5536ba597c5SAnurag S. Maskey 	int result = -1;
5546ba597c5SAnurag S. Maskey 	boolean_t new;
5556ba597c5SAnurag S. Maskey 
5566ba597c5SAnurag S. Maskey retry:
5576ba597c5SAnurag S. Maskey 	new = (scf_pg_get_property(res->sr_pg, propname, res->sr_prop) != 0);
5586ba597c5SAnurag S. Maskey 
5596ba597c5SAnurag S. Maskey 	if (scf_transaction_start(res->sr_tx, res->sr_pg) == -1) {
5606ba597c5SAnurag S. Maskey 		goto failure;
5616ba597c5SAnurag S. Maskey 	}
5626ba597c5SAnurag S. Maskey 	if (new) {
5636ba597c5SAnurag S. Maskey 		if (scf_transaction_property_new(res->sr_tx, res->sr_ent,
5646ba597c5SAnurag S. Maskey 		    propname, proptype) == -1) {
5656ba597c5SAnurag S. Maskey 			goto failure;
5666ba597c5SAnurag S. Maskey 		}
5676ba597c5SAnurag S. Maskey 	} else {
5686ba597c5SAnurag S. Maskey 		if (scf_transaction_property_change(res->sr_tx, res->sr_ent,
5696ba597c5SAnurag S. Maskey 		    propname, proptype) == -1) {
5706ba597c5SAnurag S. Maskey 			goto failure;
5716ba597c5SAnurag S. Maskey 		}
5726ba597c5SAnurag S. Maskey 	}
5736ba597c5SAnurag S. Maskey 
5746ba597c5SAnurag S. Maskey 	if (scf_entry_add_value(res->sr_ent, res->sr_val) != 0) {
5756ba597c5SAnurag S. Maskey 		goto failure;
5766ba597c5SAnurag S. Maskey 	}
5776ba597c5SAnurag S. Maskey 
5786ba597c5SAnurag S. Maskey 	result = scf_transaction_commit(res->sr_tx);
5796ba597c5SAnurag S. Maskey 	if (result == 0) {
5806ba597c5SAnurag S. Maskey 		scf_transaction_reset(res->sr_tx);
5816ba597c5SAnurag S. Maskey 		if (scf_pg_update(res->sr_pg) == -1) {
5826ba597c5SAnurag S. Maskey 			goto failure;
5836ba597c5SAnurag S. Maskey 		}
5846ba597c5SAnurag S. Maskey 		nlog(LOG_INFO, "set_property_value: transaction commit failed "
5856ba597c5SAnurag S. Maskey 		    "for %s; retrying", propname);
5866ba597c5SAnurag S. Maskey 		goto retry;
5876ba597c5SAnurag S. Maskey 	}
5886ba597c5SAnurag S. Maskey 	if (result == -1)
5896ba597c5SAnurag S. Maskey 		goto failure;
5906ba597c5SAnurag S. Maskey 	return (0);
5916ba597c5SAnurag S. Maskey 
5926ba597c5SAnurag S. Maskey failure:
5936ba597c5SAnurag S. Maskey 	return (-1);
5946ba597c5SAnurag S. Maskey }
5956ba597c5SAnurag S. Maskey 
5966ba597c5SAnurag S. Maskey int
5976ba597c5SAnurag S. Maskey nwamd_set_count_property(const char *fmri, const char *pg, const char *prop,
5986ba597c5SAnurag S. Maskey     uint64_t count)
5996ba597c5SAnurag S. Maskey {
6006ba597c5SAnurag S. Maskey 	scf_resources_t res;
6016ba597c5SAnurag S. Maskey 
6026ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, &res) != 0)
6036ba597c5SAnurag S. Maskey 		return (-1);
6046ba597c5SAnurag S. Maskey 
6056ba597c5SAnurag S. Maskey 	if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION,
6066ba597c5SAnurag S. Maskey 	    SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) {
6076ba597c5SAnurag S. Maskey 		if (scf_error() != SCF_ERROR_EXISTS)
6086ba597c5SAnurag S. Maskey 			goto failure;
6096ba597c5SAnurag S. Maskey 		if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg,
6106ba597c5SAnurag S. Maskey 		    res.sr_pg) != 0)
6116ba597c5SAnurag S. Maskey 			goto failure;
6126ba597c5SAnurag S. Maskey 	}
6136ba597c5SAnurag S. Maskey 
6146ba597c5SAnurag S. Maskey 	scf_value_set_count(res.sr_val, (uint64_t)count);
6156ba597c5SAnurag S. Maskey 
6166ba597c5SAnurag S. Maskey 	if (set_property_value(&res, prop, SCF_TYPE_COUNT) != 0)
6176ba597c5SAnurag S. Maskey 		goto failure;
6186ba597c5SAnurag S. Maskey 
6196ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
6206ba597c5SAnurag S. Maskey 	return (0);
6216ba597c5SAnurag S. Maskey 
6226ba597c5SAnurag S. Maskey failure:
6236ba597c5SAnurag S. Maskey 	nlog(LOG_INFO, "nwamd_set_count_property: scf failure %s while "
6246ba597c5SAnurag S. Maskey 	    "setting %s", scf_strerror(scf_error()), prop);
6256ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
6266ba597c5SAnurag S. Maskey 	return (-1);
6276ba597c5SAnurag S. Maskey }
6286ba597c5SAnurag S. Maskey 
6296ba597c5SAnurag S. Maskey int
6306ba597c5SAnurag S. Maskey nwamd_set_string_property(const char *fmri, const char *pg, const char *prop,
6316ba597c5SAnurag S. Maskey     const char *str)
6326ba597c5SAnurag S. Maskey {
6336ba597c5SAnurag S. Maskey 	scf_resources_t res;
6346ba597c5SAnurag S. Maskey 
6356ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, &res) != 0)
6366ba597c5SAnurag S. Maskey 		return (-1);
6376ba597c5SAnurag S. Maskey 
6386ba597c5SAnurag S. Maskey 	if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION,
6396ba597c5SAnurag S. Maskey 	    SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) {
6406ba597c5SAnurag S. Maskey 		if (scf_error() != SCF_ERROR_EXISTS)
6416ba597c5SAnurag S. Maskey 			goto failure;
6426ba597c5SAnurag S. Maskey 		if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg,
6436ba597c5SAnurag S. Maskey 		    res.sr_pg) != 0)
6446ba597c5SAnurag S. Maskey 			goto failure;
6456ba597c5SAnurag S. Maskey 	}
6466ba597c5SAnurag S. Maskey 
6476ba597c5SAnurag S. Maskey 	if (scf_value_set_astring(res.sr_val, str) != 0)
6486ba597c5SAnurag S. Maskey 		goto failure;
6496ba597c5SAnurag S. Maskey 
6506ba597c5SAnurag S. Maskey 	if (set_property_value(&res, prop, SCF_TYPE_ASTRING) != 0)
6516ba597c5SAnurag S. Maskey 		goto failure;
6526ba597c5SAnurag S. Maskey 
6536ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
6546ba597c5SAnurag S. Maskey 	return (0);
6556ba597c5SAnurag S. Maskey 
6566ba597c5SAnurag S. Maskey failure:
6576ba597c5SAnurag S. Maskey 	nlog(LOG_INFO, "nwamd_set_string_property: scf failure %s while "
6586ba597c5SAnurag S. Maskey 	    "setting %s", scf_strerror(scf_error()), prop);
6596ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
6606ba597c5SAnurag S. Maskey 	return (-1);
6616ba597c5SAnurag S. Maskey }
6626ba597c5SAnurag S. Maskey 
6636ba597c5SAnurag S. Maskey /*
6646ba597c5SAnurag S. Maskey  * Deletes property prop from property group pg in SMF instance fmri.
6656ba597c5SAnurag S. Maskey  * Returns 0 on success, -1 on failure.
6666ba597c5SAnurag S. Maskey  */
6676ba597c5SAnurag S. Maskey int
6686ba597c5SAnurag S. Maskey nwamd_delete_scf_property(const char *fmri, const char *pg, const char *prop)
6696ba597c5SAnurag S. Maskey {
6706ba597c5SAnurag S. Maskey 	scf_resources_t res;
6716ba597c5SAnurag S. Maskey 	int result = -1;
6726ba597c5SAnurag S. Maskey 
6736ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, &res) != 0)
6746ba597c5SAnurag S. Maskey 		return (-1);
6756ba597c5SAnurag S. Maskey 
6766ba597c5SAnurag S. Maskey 	if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION,
6776ba597c5SAnurag S. Maskey 	    SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) {
6786ba597c5SAnurag S. Maskey 		if (scf_error() != SCF_ERROR_EXISTS)
6796ba597c5SAnurag S. Maskey 			goto failure;
6806ba597c5SAnurag S. Maskey 		if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg,
6816ba597c5SAnurag S. Maskey 		    res.sr_pg) != 0)
6826ba597c5SAnurag S. Maskey 			goto failure;
6836ba597c5SAnurag S. Maskey 	}
6846ba597c5SAnurag S. Maskey 
6856ba597c5SAnurag S. Maskey 	if (scf_pg_get_property(res.sr_pg, prop, res.sr_prop) != 0)
6866ba597c5SAnurag S. Maskey 		goto failure;
6876ba597c5SAnurag S. Maskey retry:
6886ba597c5SAnurag S. Maskey 	if (scf_transaction_start(res.sr_tx, res.sr_pg) == -1)
6896ba597c5SAnurag S. Maskey 		goto failure;
6906ba597c5SAnurag S. Maskey 
6916ba597c5SAnurag S. Maskey 	if (scf_transaction_property_delete(res.sr_tx, res.sr_ent, prop) == -1)
6926ba597c5SAnurag S. Maskey 		goto failure;
6936ba597c5SAnurag S. Maskey 
6946ba597c5SAnurag S. Maskey 	result = scf_transaction_commit(res.sr_tx);
6956ba597c5SAnurag S. Maskey 	if (result == 0) {
6966ba597c5SAnurag S. Maskey 		scf_transaction_reset(res.sr_tx);
6976ba597c5SAnurag S. Maskey 		if (scf_pg_update(res.sr_pg) == -1)
6986ba597c5SAnurag S. Maskey 			goto failure;
6996ba597c5SAnurag S. Maskey 		goto retry;
7006ba597c5SAnurag S. Maskey 	}
7016ba597c5SAnurag S. Maskey 	if (result == -1)
7026ba597c5SAnurag S. Maskey 		goto failure;
7036ba597c5SAnurag S. Maskey 
7046ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
7056ba597c5SAnurag S. Maskey 	return (0);
7066ba597c5SAnurag S. Maskey failure:
7076ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
7086ba597c5SAnurag S. Maskey 	return (-1);
709d71dbb73Sjbeck }
710