xref: /illumos-gate/usr/src/cmd/cmd-inet/lib/nwamd/util.c (revision 3773ed2d)
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 /*
236ba597c5SAnurag S. Maskey  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24d71dbb73Sjbeck  * Use is subject to license terms.
25d71dbb73Sjbeck  */
26d71dbb73Sjbeck 
27d71dbb73Sjbeck /*
286ba597c5SAnurag S. Maskey  * util.c contains a set of miscellaneous utility functions which,
296ba597c5SAnurag S. Maskey  * among other things:
30d71dbb73Sjbeck  * - start a child process
31d71dbb73Sjbeck  * - look up the zone name
326ba597c5SAnurag S. Maskey  * - look up/set SMF properties
336ba597c5SAnurag S. Maskey  * - drop/escalate privs
34d71dbb73Sjbeck  */
35d71dbb73Sjbeck 
366ba597c5SAnurag S. Maskey #include <assert.h>
376ba597c5SAnurag S. Maskey #include <errno.h>
386ba597c5SAnurag S. Maskey #include <inetcfg.h>
396ba597c5SAnurag S. Maskey #include <libdllink.h>
406ba597c5SAnurag S. Maskey #include <limits.h>
416ba597c5SAnurag S. Maskey #include <libscf.h>
426ba597c5SAnurag S. Maskey #include <net/if.h>
436ba597c5SAnurag S. Maskey #include <pthread.h>
446ba597c5SAnurag S. Maskey #include <pwd.h>
456ba597c5SAnurag S. Maskey #include <spawn.h>
46d71dbb73Sjbeck #include <stdarg.h>
47d71dbb73Sjbeck #include <stdio.h>
48d71dbb73Sjbeck #include <stdlib.h>
49d71dbb73Sjbeck #include <string.h>
506ba597c5SAnurag S. Maskey #include <strings.h>
51d71dbb73Sjbeck #include <stropts.h>
52d71dbb73Sjbeck #include <sys/socket.h>
536ba597c5SAnurag S. Maskey #include <sys/sockio.h>
546ba597c5SAnurag S. Maskey #include <sys/types.h>
556ba597c5SAnurag S. Maskey #include <unistd.h>
56d71dbb73Sjbeck #include <wait.h>
57d71dbb73Sjbeck #include <zone.h>
58d71dbb73Sjbeck 
596ba597c5SAnurag S. Maskey #include "util.h"
606ba597c5SAnurag S. Maskey #include "llp.h"
61d71dbb73Sjbeck 
62d71dbb73Sjbeck extern char **environ;
636ba597c5SAnurag S. Maskey extern sigset_t original_sigmask;
64d71dbb73Sjbeck 
656ba597c5SAnurag S. Maskey /*
666ba597c5SAnurag S. Maskey  * A holder for all the resources needed to get a property value
676ba597c5SAnurag S. Maskey  * using libscf.
686ba597c5SAnurag S. Maskey  */
696ba597c5SAnurag S. Maskey typedef struct scf_resources {
706ba597c5SAnurag S. Maskey 	scf_handle_t *sr_handle;
716ba597c5SAnurag S. Maskey 	scf_instance_t *sr_inst;
726ba597c5SAnurag S. Maskey 	scf_snapshot_t *sr_snap;
736ba597c5SAnurag S. Maskey 	scf_propertygroup_t *sr_pg;
746ba597c5SAnurag S. Maskey 	scf_property_t *sr_prop;
756ba597c5SAnurag S. Maskey 	scf_value_t *sr_val;
766ba597c5SAnurag S. Maskey 	scf_transaction_t *sr_tx;
776ba597c5SAnurag S. Maskey 	scf_transaction_entry_t *sr_ent;
786ba597c5SAnurag S. Maskey } scf_resources_t;
796ba597c5SAnurag S. Maskey 
806ba597c5SAnurag S. Maskey static pthread_mutex_t uid_mutex = PTHREAD_MUTEX_INITIALIZER;
816ba597c5SAnurag S. Maskey static uid_t uid;
826ba597c5SAnurag S. Maskey static int uid_cnt;
83d71dbb73Sjbeck 
846ba597c5SAnurag S. Maskey void
8538f140aaSMichael Hunter nwamd_escalate(void) {
8638f140aaSMichael Hunter 	priv_set_t *priv_set;
8738f140aaSMichael Hunter 	priv_set = priv_str_to_set("zone", ",", NULL);
8838f140aaSMichael Hunter 
8938f140aaSMichael Hunter 	if (priv_set == NULL)
9038f140aaSMichael Hunter 		pfail("creating privilege set: %s", strerror(errno));
9138f140aaSMichael Hunter 
926ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&uid_mutex);
936ba597c5SAnurag S. Maskey 	if (uid == 0)
946ba597c5SAnurag S. Maskey 		uid = getuid();
956ba597c5SAnurag S. Maskey 	if (uid_cnt++ == 0) {
9638f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) {
9738f140aaSMichael Hunter 			priv_freeset(priv_set);
9838f140aaSMichael Hunter 			pfail("setppriv effective: %s", strerror(errno));
9938f140aaSMichael Hunter 		}
1006ba597c5SAnurag S. Maskey 		if (setuid(0) == -1)
1016ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "setuid(0) failed %s", strerror(errno));
102d71dbb73Sjbeck 	}
1036ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&uid_mutex);
10438f140aaSMichael Hunter 
10538f140aaSMichael Hunter 	priv_freeset(priv_set);
106d71dbb73Sjbeck }
107d71dbb73Sjbeck 
108b00044a2SJames Carlson void
10938f140aaSMichael Hunter nwamd_deescalate(void) {
1106ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&uid_mutex);
111*3773ed2dSAnurag S. Maskey 
1126ba597c5SAnurag S. Maskey 	assert(uid_cnt > 0);
1136ba597c5SAnurag S. Maskey 	if (--uid_cnt == 0) {
114*3773ed2dSAnurag S. Maskey 		priv_set_t *priv_set, *allpriv_set;
115*3773ed2dSAnurag S. Maskey 
1166ba597c5SAnurag S. Maskey 		if (setuid(uid) == -1)
1176ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "setuid(%d) failed %s", uid,
1186ba597c5SAnurag S. Maskey 			    strerror(errno));
11938f140aaSMichael Hunter 
12038f140aaSMichael Hunter 		/* build up our minimal set of privs. */
12138f140aaSMichael Hunter 		priv_set = priv_str_to_set("basic", ",", NULL);
12238f140aaSMichael Hunter 		allpriv_set = priv_str_to_set("zone", ",", NULL);
12338f140aaSMichael Hunter 		if (priv_set == NULL || allpriv_set == NULL)
12438f140aaSMichael Hunter 			pfail("converting privilege sets: %s", strerror(errno));
12538f140aaSMichael Hunter 
12638f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_FILE_CHOWN_SELF);
12738f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_FILE_DAC_READ);
12838f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_FILE_DAC_WRITE);
12938f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_NET_RAWACCESS);
13038f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_NET_PRIVADDR);
13138f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_PROC_AUDIT);
13238f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_PROC_OWNER);
13338f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_PROC_SETID);
13438f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_CONFIG);
13538f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_IP_CONFIG);
13638f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_IPC_CONFIG);
13738f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_MOUNT);
13838f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_NET_CONFIG);
13938f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_RES_CONFIG);
14038f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_RESOURCE);
14138f140aaSMichael Hunter 
14238f140aaSMichael Hunter 		/*
14338f140aaSMichael Hunter 		 * Since our zone might not have all these privs,
14438f140aaSMichael Hunter 		 * just ask for those that are available.
14538f140aaSMichael Hunter 		 */
14638f140aaSMichael Hunter 		priv_intersect(allpriv_set, priv_set);
14738f140aaSMichael Hunter 
14838f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_INHERITABLE, priv_set) == -1) {
14938f140aaSMichael Hunter 			priv_freeset(allpriv_set);
15038f140aaSMichael Hunter 			priv_freeset(priv_set);
15138f140aaSMichael Hunter 			pfail("setppriv inheritable: %s", strerror(errno));
15238f140aaSMichael Hunter 		}
15338f140aaSMichael Hunter 		/*
15438f140aaSMichael Hunter 		 * Need to ensure permitted set contains all privs so we can
15538f140aaSMichael Hunter 		 * escalate later.
15638f140aaSMichael Hunter 		 */
15738f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_PERMITTED, allpriv_set) == -1) {
15838f140aaSMichael Hunter 			priv_freeset(allpriv_set);
15938f140aaSMichael Hunter 			priv_freeset(priv_set);
16038f140aaSMichael Hunter 			pfail("setppriv permitted: %s", strerror(errno));
16138f140aaSMichael Hunter 		}
16238f140aaSMichael Hunter 		/*
16338f140aaSMichael Hunter 		 * We need to find a smaller set of privs that are important to
16438f140aaSMichael Hunter 		 * us.  Otherwise we really are not gaining much by doing this.
16538f140aaSMichael Hunter 		 */
16638f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) {
16738f140aaSMichael Hunter 			priv_freeset(allpriv_set);
16838f140aaSMichael Hunter 			priv_freeset(priv_set);
16938f140aaSMichael Hunter 			pfail("setppriv effective: %s", strerror(errno));
17038f140aaSMichael Hunter 		}
171*3773ed2dSAnurag S. Maskey 
172*3773ed2dSAnurag S. Maskey 		priv_freeset(priv_set);
173*3773ed2dSAnurag S. Maskey 		priv_freeset(allpriv_set);
1746ba597c5SAnurag S. Maskey 	}
1756ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&uid_mutex);
176b00044a2SJames Carlson }
177b00044a2SJames Carlson 
178d71dbb73Sjbeck /*
179d71dbb73Sjbeck  *
180d71dbb73Sjbeck  * This starts a child process determined by command.  If command contains a
181d71dbb73Sjbeck  * slash then it is assumed to be a full path; otherwise the path is searched
182d71dbb73Sjbeck  * for an executable file with the name command.  Command is also used as
183d71dbb73Sjbeck  * argv[0] of the new process.  The rest of the arguments of the function
184d71dbb73Sjbeck  * up to the first NULL make up pointers to arguments of the new process.
185d71dbb73Sjbeck  *
186d71dbb73Sjbeck  * This function returns child exit status on success and -1 on failure.
187d71dbb73Sjbeck  *
188d71dbb73Sjbeck  * NOTE: original_sigmask must be set before this function is called.
189d71dbb73Sjbeck  */
190d71dbb73Sjbeck int
1916ba597c5SAnurag S. Maskey nwamd_start_childv(const char *command, char const * const *argv)
192d71dbb73Sjbeck {
193d71dbb73Sjbeck 	posix_spawnattr_t attr;
194d71dbb73Sjbeck 	sigset_t fullset;
195d71dbb73Sjbeck 	int i, rc, status, n;
196d71dbb73Sjbeck 	pid_t pid;
197d71dbb73Sjbeck 	char vbuf[1024];
198d71dbb73Sjbeck 
199d71dbb73Sjbeck 	vbuf[0] = 0;
200d71dbb73Sjbeck 	n = sizeof (vbuf);
201d71dbb73Sjbeck 	for (i = 1; argv[i] != NULL && n > 2; i++) {
202d71dbb73Sjbeck 		n -= strlcat(vbuf, " ", n);
203d71dbb73Sjbeck 		n -= strlcat(vbuf, argv[i], n);
204d71dbb73Sjbeck 	}
205d71dbb73Sjbeck 	if (argv[i] != NULL || n < 0)
2066ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_start_childv can't log full arg vector");
207d71dbb73Sjbeck 
208d71dbb73Sjbeck 	if ((rc = posix_spawnattr_init(&attr)) != 0) {
2096ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "posix_spawnattr_init %d %s\n",
2106ba597c5SAnurag S. Maskey 		    rc, strerror(rc));
211d71dbb73Sjbeck 		return (-1);
212d71dbb73Sjbeck 	}
213d71dbb73Sjbeck 	(void) sigfillset(&fullset);
214d71dbb73Sjbeck 	if ((rc = posix_spawnattr_setsigdefault(&attr, &fullset)) != 0) {
2156ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "setsigdefault %d %s\n", rc, strerror(rc));
216d71dbb73Sjbeck 		return (-1);
217d71dbb73Sjbeck 	}
218d71dbb73Sjbeck 	if ((rc = posix_spawnattr_setsigmask(&attr, &original_sigmask)) != 0) {
2196ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "setsigmask %d %s\n", rc, strerror(rc));
220d71dbb73Sjbeck 		return (-1);
221d71dbb73Sjbeck 	}
222d71dbb73Sjbeck 	if ((rc = posix_spawnattr_setflags(&attr,
223d71dbb73Sjbeck 	    POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK)) != 0) {
2246ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "setflags %d %s\n", rc, strerror(rc));
225d71dbb73Sjbeck 		return (-1);
226d71dbb73Sjbeck 	}
227d71dbb73Sjbeck 
228d71dbb73Sjbeck 	if ((rc = posix_spawnp(&pid, command, NULL, &attr, (char * const *)argv,
229d71dbb73Sjbeck 	    environ)) > 0) {
2306ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "posix_spawnp failed errno %d", rc);
231d71dbb73Sjbeck 		return (-1);
232d71dbb73Sjbeck 	}
233d71dbb73Sjbeck 
234d71dbb73Sjbeck 	if ((rc = posix_spawnattr_destroy(&attr)) != 0) {
2356ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "posix_spawn_attr_destroy %d %s\n",
2366ba597c5SAnurag S. Maskey 		    rc, strerror(rc));
237d71dbb73Sjbeck 		return (-1);
238d71dbb73Sjbeck 	}
239d71dbb73Sjbeck 
240d71dbb73Sjbeck 	(void) waitpid(pid, &status, 0);
241d71dbb73Sjbeck 	if (WIFSIGNALED(status) || WIFSTOPPED(status)) {
242d71dbb73Sjbeck 		i = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status);
2436ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "'%s%s' %s with signal %d (%s)", command, vbuf,
244d71dbb73Sjbeck 		    (WIFSIGNALED(status) ? "terminated" : "stopped"), i,
245d71dbb73Sjbeck 		    strsignal(i));
246d71dbb73Sjbeck 		return (-2);
247d71dbb73Sjbeck 	} else {
2486ba597c5SAnurag S. Maskey 		nlog(LOG_INFO, "'%s%s' completed normally: %d", command, vbuf,
249d71dbb73Sjbeck 		    WEXITSTATUS(status));
250d71dbb73Sjbeck 		return (WEXITSTATUS(status));
251d71dbb73Sjbeck 	}
252d71dbb73Sjbeck }
253d71dbb73Sjbeck 
2546ba597c5SAnurag S. Maskey /*
2556ba597c5SAnurag S. Maskey  * For global zone, check if the link is used by a non-global
2566ba597c5SAnurag S. Maskey  * zone, note that the non-global zones doesn't need this check,
2576ba597c5SAnurag S. Maskey  * because zoneadm has taken care of this when the zone boots.
2586ba597c5SAnurag S. Maskey  * In the global zone, we ignore events for local-zone-owned links
2596ba597c5SAnurag S. Maskey  * since these are taken care of by the local zone's network
2606ba597c5SAnurag S. Maskey  * configuration services.
2616ba597c5SAnurag S. Maskey  */
2626ba597c5SAnurag S. Maskey boolean_t
2636ba597c5SAnurag S. Maskey nwamd_link_belongs_to_this_zone(const char *linkname)
264d71dbb73Sjbeck {
2656ba597c5SAnurag S. Maskey 	zoneid_t zoneid;
2666ba597c5SAnurag S. Maskey 	char zonename[ZONENAME_MAX];
2676ba597c5SAnurag S. Maskey 	int ret;
2686ba597c5SAnurag S. Maskey 
2696ba597c5SAnurag S. Maskey 	zoneid = getzoneid();
2706ba597c5SAnurag S. Maskey 	if (zoneid == GLOBAL_ZONEID) {
2716ba597c5SAnurag S. Maskey 		datalink_id_t linkid;
2726ba597c5SAnurag S. Maskey 		dladm_status_t status;
2736ba597c5SAnurag S. Maskey 		char errstr[DLADM_STRSIZE];
2746ba597c5SAnurag S. Maskey 
2756ba597c5SAnurag S. Maskey 		if ((status = dladm_name2info(dld_handle, linkname, &linkid,
2766ba597c5SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
2776ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: "
2786ba597c5SAnurag S. Maskey 			    "could not get linkid for %s: %s",
2796ba597c5SAnurag S. Maskey 			    linkname, dladm_status2str(status, errstr));
2806ba597c5SAnurag S. Maskey 			return (B_FALSE);
2816ba597c5SAnurag S. Maskey 		}
2826ba597c5SAnurag S. Maskey 		zoneid = ALL_ZONES;
2836ba597c5SAnurag S. Maskey 		ret = zone_check_datalink(&zoneid, linkid);
2846ba597c5SAnurag S. Maskey 		if (ret == 0) {
2856ba597c5SAnurag S. Maskey 			(void) getzonenamebyid(zoneid, zonename, ZONENAME_MAX);
2866ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: "
2876ba597c5SAnurag S. Maskey 			    "%s is used by non-global zone: %s",
2886ba597c5SAnurag S. Maskey 			    linkname, zonename);
2896ba597c5SAnurag S. Maskey 			return (B_FALSE);
290d71dbb73Sjbeck 		}
2916ba597c5SAnurag S. Maskey 	}
2926ba597c5SAnurag S. Maskey 	return (B_TRUE);
2936ba597c5SAnurag S. Maskey }
294d71dbb73Sjbeck 
2956ba597c5SAnurag S. Maskey /*
2966ba597c5SAnurag S. Maskey  * Inputs:
2976ba597c5SAnurag S. Maskey  *   res is a pointer to the scf_resources_t to be released.
2986ba597c5SAnurag S. Maskey  */
2996ba597c5SAnurag S. Maskey static void
3006ba597c5SAnurag S. Maskey release_scf_resources(scf_resources_t *res)
3016ba597c5SAnurag S. Maskey {
3026ba597c5SAnurag S. Maskey 	scf_entry_destroy(res->sr_ent);
3036ba597c5SAnurag S. Maskey 	scf_transaction_destroy(res->sr_tx);
3046ba597c5SAnurag S. Maskey 	scf_value_destroy(res->sr_val);
3056ba597c5SAnurag S. Maskey 	scf_property_destroy(res->sr_prop);
3066ba597c5SAnurag S. Maskey 	scf_pg_destroy(res->sr_pg);
3076ba597c5SAnurag S. Maskey 	scf_snapshot_destroy(res->sr_snap);
3086ba597c5SAnurag S. Maskey 	scf_instance_destroy(res->sr_inst);
3096ba597c5SAnurag S. Maskey 	(void) scf_handle_unbind(res->sr_handle);
3106ba597c5SAnurag S. Maskey 	scf_handle_destroy(res->sr_handle);
3116ba597c5SAnurag S. Maskey }
312d71dbb73Sjbeck 
313d71dbb73Sjbeck /*
3146ba597c5SAnurag S. Maskey  * Inputs:
3156ba597c5SAnurag S. Maskey  *   fmri is the instance to look up
3166ba597c5SAnurag S. Maskey  * Outputs:
3176ba597c5SAnurag S. Maskey  *   res is a pointer to an scf_resources_t.  This is an internal
3186ba597c5SAnurag S. Maskey  *   structure that holds all the handles needed to get a specific
3196ba597c5SAnurag S. Maskey  *   property from the running snapshot; on a successful return it
3206ba597c5SAnurag S. Maskey  *   contains the scf_value_t that should be passed to the desired
3216ba597c5SAnurag S. Maskey  *   scf_value_get_foo() function, and must be freed after use by
3226ba597c5SAnurag S. Maskey  *   calling release_scf_resources().  On a failure return, any
3236ba597c5SAnurag S. Maskey  *   resources that may have been assigned to res are released, so
3246ba597c5SAnurag S. Maskey  *   the caller does not need to do any cleanup in the failure case.
3256ba597c5SAnurag S. Maskey  * Returns:
3266ba597c5SAnurag S. Maskey  *    0 on success
3276ba597c5SAnurag S. Maskey  *   -1 on failure
328d71dbb73Sjbeck  */
3296ba597c5SAnurag S. Maskey 
3306ba597c5SAnurag S. Maskey static int
3316ba597c5SAnurag S. Maskey create_scf_resources(const char *fmri, scf_resources_t *res)
3326ba597c5SAnurag S. Maskey {
3336ba597c5SAnurag S. Maskey 	res->sr_tx = NULL;
3346ba597c5SAnurag S. Maskey 	res->sr_ent = NULL;
3356ba597c5SAnurag S. Maskey 	res->sr_inst = NULL;
3366ba597c5SAnurag S. Maskey 	res->sr_snap = NULL;
3376ba597c5SAnurag S. Maskey 	res->sr_pg = NULL;
3386ba597c5SAnurag S. Maskey 	res->sr_prop = NULL;
3396ba597c5SAnurag S. Maskey 	res->sr_val = NULL;
3406ba597c5SAnurag S. Maskey 
3416ba597c5SAnurag S. Maskey 	if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL) {
3426ba597c5SAnurag S. Maskey 		return (-1);
3436ba597c5SAnurag S. Maskey 	}
3446ba597c5SAnurag S. Maskey 
3456ba597c5SAnurag S. Maskey 	if (scf_handle_bind(res->sr_handle) != 0) {
3466ba597c5SAnurag S. Maskey 		scf_handle_destroy(res->sr_handle);
3476ba597c5SAnurag S. Maskey 		return (-1);
3486ba597c5SAnurag S. Maskey 	}
3496ba597c5SAnurag S. Maskey 	if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL) {
3506ba597c5SAnurag S. Maskey 		goto failure;
3516ba597c5SAnurag S. Maskey 	}
3526ba597c5SAnurag S. Maskey 	if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL,
3536ba597c5SAnurag S. Maskey 	    res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
3546ba597c5SAnurag S. Maskey 		goto failure;
3556ba597c5SAnurag S. Maskey 	}
3566ba597c5SAnurag S. Maskey 	if ((res->sr_snap = scf_snapshot_create(res->sr_handle)) == NULL) {
3576ba597c5SAnurag S. Maskey 		goto failure;
3586ba597c5SAnurag S. Maskey 	}
3596ba597c5SAnurag S. Maskey 	if (scf_instance_get_snapshot(res->sr_inst, "running",
3606ba597c5SAnurag S. Maskey 	    res->sr_snap) != 0) {
3616ba597c5SAnurag S. Maskey 		goto failure;
3626ba597c5SAnurag S. Maskey 	}
3636ba597c5SAnurag S. Maskey 	if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
3646ba597c5SAnurag S. Maskey 		goto failure;
3656ba597c5SAnurag S. Maskey 	}
3666ba597c5SAnurag S. Maskey 	if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL) {
3676ba597c5SAnurag S. Maskey 		goto failure;
3686ba597c5SAnurag S. Maskey 	}
3696ba597c5SAnurag S. Maskey 	if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL) {
3706ba597c5SAnurag S. Maskey 		goto failure;
3716ba597c5SAnurag S. Maskey 	}
3726ba597c5SAnurag S. Maskey 	if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL) {
3736ba597c5SAnurag S. Maskey 		goto failure;
3746ba597c5SAnurag S. Maskey 	}
3756ba597c5SAnurag S. Maskey 	if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL) {
3766ba597c5SAnurag S. Maskey 		goto failure;
3776ba597c5SAnurag S. Maskey 	}
3786ba597c5SAnurag S. Maskey 	return (0);
3796ba597c5SAnurag S. Maskey 
3806ba597c5SAnurag S. Maskey failure:
3816ba597c5SAnurag S. Maskey 	nlog(LOG_ERR, "create_scf_resources failed: %s",
3826ba597c5SAnurag S. Maskey 	    scf_strerror(scf_error()));
3836ba597c5SAnurag S. Maskey 	release_scf_resources(res);
3846ba597c5SAnurag S. Maskey 	return (-1);
3856ba597c5SAnurag S. Maskey }
3866ba597c5SAnurag S. Maskey 
3876ba597c5SAnurag S. Maskey /*
3886ba597c5SAnurag S. Maskey  * Inputs:
3896ba597c5SAnurag S. Maskey  *   fmri is the instance to look up
3906ba597c5SAnurag S. Maskey  *   pg is the property group to look up
3916ba597c5SAnurag S. Maskey  *   prop is the property within that group to look up
3926ba597c5SAnurag S. Maskey  *   running specifies if running snapshot is to be used
3936ba597c5SAnurag S. Maskey  * Outputs:
3946ba597c5SAnurag S. Maskey  *   res is a pointer to an scf_resources_t.  This is an internal
3956ba597c5SAnurag S. Maskey  *   structure that holds all the handles needed to get a specific
3966ba597c5SAnurag S. Maskey  *   property from the running snapshot; on a successful return it
3976ba597c5SAnurag S. Maskey  *   contains the scf_value_t that should be passed to the desired
3986ba597c5SAnurag S. Maskey  *   scf_value_get_foo() function, and must be freed after use by
3996ba597c5SAnurag S. Maskey  *   calling release_scf_resources().  On a failure return, any
4006ba597c5SAnurag S. Maskey  *   resources that may have been assigned to res are released, so
4016ba597c5SAnurag S. Maskey  *   the caller does not need to do any cleanup in the failure case.
4026ba597c5SAnurag S. Maskey  * Returns:
4036ba597c5SAnurag S. Maskey  *    0 on success
4046ba597c5SAnurag S. Maskey  *   -1 on failure
4056ba597c5SAnurag S. Maskey  */
4066ba597c5SAnurag S. Maskey static int
4076ba597c5SAnurag S. Maskey get_property_value(const char *fmri, const char *pg, const char *prop,
4086ba597c5SAnurag S. Maskey     boolean_t running, scf_resources_t *res)
409d71dbb73Sjbeck {
4106ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, res) != 0)
4116ba597c5SAnurag S. Maskey 		return (-1);
4126ba597c5SAnurag S. Maskey 
4136ba597c5SAnurag S. Maskey 	if (scf_instance_get_pg_composed(res->sr_inst,
4146ba597c5SAnurag S. Maskey 	    running ? res->sr_snap : NULL, pg, res->sr_pg) != 0) {
4156ba597c5SAnurag S. Maskey 		goto failure;
4166ba597c5SAnurag S. Maskey 	}
4176ba597c5SAnurag S. Maskey 	if (scf_pg_get_property(res->sr_pg, prop, res->sr_prop) != 0) {
4186ba597c5SAnurag S. Maskey 		goto failure;
4196ba597c5SAnurag S. Maskey 	}
4206ba597c5SAnurag S. Maskey 	if (scf_property_get_value(res->sr_prop, res->sr_val) != 0) {
4216ba597c5SAnurag S. Maskey 		goto failure;
4226ba597c5SAnurag S. Maskey 	}
4236ba597c5SAnurag S. Maskey 	return (0);
424d71dbb73Sjbeck 
4256ba597c5SAnurag S. Maskey failure:
4266ba597c5SAnurag S. Maskey 	release_scf_resources(res);
4276ba597c5SAnurag S. Maskey 	return (-1);
428d71dbb73Sjbeck }
429d71dbb73Sjbeck 
4306ba597c5SAnurag S. Maskey /*
4316ba597c5SAnurag S. Maskey  * Inputs:
4326ba597c5SAnurag S. Maskey  *   lfmri is the instance fmri to look up
4336ba597c5SAnurag S. Maskey  *   lpg is the property group to look up
4346ba597c5SAnurag S. Maskey  *   lprop is the property within that group to look up
4356ba597c5SAnurag S. Maskey  * Outputs:
4366ba597c5SAnurag S. Maskey  *   answer is a pointer to the property value
4376ba597c5SAnurag S. Maskey  * Returns:
4386ba597c5SAnurag S. Maskey  *    0 on success
4396ba597c5SAnurag S. Maskey  *   -1 on failure
4406ba597c5SAnurag S. Maskey  * If successful, the property value is retured in *answer.
4416ba597c5SAnurag S. Maskey  * Otherwise, *answer is undefined, and it is up to the caller to decide
4426ba597c5SAnurag S. Maskey  * how to handle that case.
4436ba597c5SAnurag S. Maskey  */
4446ba597c5SAnurag S. Maskey int
4456ba597c5SAnurag S. Maskey nwamd_lookup_boolean_property(const char *lfmri, const char *lpg,
4466ba597c5SAnurag S. Maskey     const char *lprop, boolean_t *answer)
4476ba597c5SAnurag S. Maskey {
4486ba597c5SAnurag S. Maskey 	int result = -1;
4496ba597c5SAnurag S. Maskey 	scf_resources_t res;
4506ba597c5SAnurag S. Maskey 	uint8_t prop_val;
4516ba597c5SAnurag S. Maskey 
4526ba597c5SAnurag S. Maskey 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
4536ba597c5SAnurag S. Maskey 
4546ba597c5SAnurag S. Maskey 		/*
4556ba597c5SAnurag S. Maskey 		 * an error was already logged by get_property_value,
4566ba597c5SAnurag S. Maskey 		 * and it released any resources assigned to res before
4576ba597c5SAnurag S. Maskey 		 * returning.
4586ba597c5SAnurag S. Maskey 		 */
4596ba597c5SAnurag S. Maskey 		return (result);
4606ba597c5SAnurag S. Maskey 	}
4616ba597c5SAnurag S. Maskey 	if (scf_value_get_boolean(res.sr_val, &prop_val) != 0) {
4626ba597c5SAnurag S. Maskey 		goto cleanup;
4636ba597c5SAnurag S. Maskey 	}
4646ba597c5SAnurag S. Maskey 	*answer = (boolean_t)prop_val;
4656ba597c5SAnurag S. Maskey 	result = 0;
4666ba597c5SAnurag S. Maskey cleanup:
4676ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
4686ba597c5SAnurag S. Maskey 	return (result);
4696ba597c5SAnurag S. Maskey }
4706ba597c5SAnurag S. Maskey 
4716ba597c5SAnurag S. Maskey /*
4726ba597c5SAnurag S. Maskey  * Inputs:
4736ba597c5SAnurag S. Maskey  *   lfmri is the instance fmri to look up
4746ba597c5SAnurag S. Maskey  *   lpg is the property group to look up
4756ba597c5SAnurag S. Maskey  *   lprop is the property within that group to look up
4766ba597c5SAnurag S. Maskey  *   buf is the place to put the answer
4776ba597c5SAnurag S. Maskey  *   bufsz is the size of buf
4786ba597c5SAnurag S. Maskey  * Outputs:
4796ba597c5SAnurag S. Maskey  *
4806ba597c5SAnurag S. Maskey  * Returns:
4816ba597c5SAnurag S. Maskey  *    0 on success
4826ba597c5SAnurag S. Maskey  *   -1 on failure
4836ba597c5SAnurag S. Maskey  * If successful, the property value is retured in buf.
4846ba597c5SAnurag S. Maskey  * Otherwise, buf is undefined, and it is up to the caller to decide
4856ba597c5SAnurag S. Maskey  * how to handle that case.
4866ba597c5SAnurag S. Maskey  */
4876ba597c5SAnurag S. Maskey int
4886ba597c5SAnurag S. Maskey nwamd_lookup_string_property(const char *lfmri, const char *lpg,
4896ba597c5SAnurag S. Maskey     const char *lprop, char *buf, size_t bufsz)
490d71dbb73Sjbeck {
4916ba597c5SAnurag S. Maskey 	int result = -1;
4926ba597c5SAnurag S. Maskey 	scf_resources_t res;
4936ba597c5SAnurag S. Maskey 
4946ba597c5SAnurag S. Maskey 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
4956ba597c5SAnurag S. Maskey 		/*
4966ba597c5SAnurag S. Maskey 		 * The above function fails when trying to get a
4976ba597c5SAnurag S. Maskey 		 * non-persistent property group from the running snapshot.
4986ba597c5SAnurag S. Maskey 		 * Try going for the non-running snapshot.
4996ba597c5SAnurag S. Maskey 		 */
5006ba597c5SAnurag S. Maskey 		if (get_property_value(lfmri, lpg, lprop, B_FALSE, &res) != 0) {
5016ba597c5SAnurag S. Maskey 			/*
5026ba597c5SAnurag S. Maskey 			 * an error was already logged by get_property_value,
5036ba597c5SAnurag S. Maskey 			 * and it released any resources assigned to res before
5046ba597c5SAnurag S. Maskey 			 * returning.
5056ba597c5SAnurag S. Maskey 			 */
5066ba597c5SAnurag S. Maskey 			return (result);
5076ba597c5SAnurag S. Maskey 		}
5086ba597c5SAnurag S. Maskey 	}
5096ba597c5SAnurag S. Maskey 	if (scf_value_get_astring(res.sr_val, buf, bufsz) == 0)
5106ba597c5SAnurag S. Maskey 		goto cleanup;
5116ba597c5SAnurag S. Maskey 
5126ba597c5SAnurag S. Maskey 	result = 0;
5136ba597c5SAnurag S. Maskey cleanup:
5146ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
5156ba597c5SAnurag S. Maskey 	return (result);
5166ba597c5SAnurag S. Maskey }
517d71dbb73Sjbeck 
5186ba597c5SAnurag S. Maskey /*
5196ba597c5SAnurag S. Maskey  * Inputs:
5206ba597c5SAnurag S. Maskey  *   lfmri is the instance fmri to look up
5216ba597c5SAnurag S. Maskey  *   lpg is the property group to look up
5226ba597c5SAnurag S. Maskey  *   lprop is the property within that group to look up
5236ba597c5SAnurag S. Maskey  * Outputs:
5246ba597c5SAnurag S. Maskey  *   answer is a pointer to the property value
5256ba597c5SAnurag S. Maskey  * Returns:
5266ba597c5SAnurag S. Maskey  *    0 on success
5276ba597c5SAnurag S. Maskey  *   -1 on failure
5286ba597c5SAnurag S. Maskey  * If successful, the property value is retured in *answer.
5296ba597c5SAnurag S. Maskey  * Otherwise, *answer is undefined, and it is up to the caller to decide
5306ba597c5SAnurag S. Maskey  * how to handle that case.
5316ba597c5SAnurag S. Maskey  */
5326ba597c5SAnurag S. Maskey int
5336ba597c5SAnurag S. Maskey nwamd_lookup_count_property(const char *lfmri, const char *lpg,
5346ba597c5SAnurag S. Maskey     const char *lprop, uint64_t *answer)
5356ba597c5SAnurag S. Maskey {
5366ba597c5SAnurag S. Maskey 	int result = -1;
5376ba597c5SAnurag S. Maskey 	scf_resources_t res;
5386ba597c5SAnurag S. Maskey 
5396ba597c5SAnurag S. Maskey 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
5406ba597c5SAnurag S. Maskey 
5416ba597c5SAnurag S. Maskey 		/*
5426ba597c5SAnurag S. Maskey 		 * an error was already logged by get_property_value,
5436ba597c5SAnurag S. Maskey 		 * and it released any resources assigned to res before
5446ba597c5SAnurag S. Maskey 		 * returning.
5456ba597c5SAnurag S. Maskey 		 */
5466ba597c5SAnurag S. Maskey 		return (result);
5476ba597c5SAnurag S. Maskey 	}
5486ba597c5SAnurag S. Maskey 	if (scf_value_get_count(res.sr_val, answer) != 0) {
5496ba597c5SAnurag S. Maskey 		goto cleanup;
5506ba597c5SAnurag S. Maskey 	}
5516ba597c5SAnurag S. Maskey 	result = 0;
5526ba597c5SAnurag S. Maskey cleanup:
5536ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
5546ba597c5SAnurag S. Maskey 	return (result);
5556ba597c5SAnurag S. Maskey }
5566ba597c5SAnurag S. Maskey 
5576ba597c5SAnurag S. Maskey static int
5586ba597c5SAnurag S. Maskey set_property_value(scf_resources_t *res, const char *propname,
5596ba597c5SAnurag S. Maskey     scf_type_t proptype)
5606ba597c5SAnurag S. Maskey {
5616ba597c5SAnurag S. Maskey 	int result = -1;
5626ba597c5SAnurag S. Maskey 	boolean_t new;
5636ba597c5SAnurag S. Maskey 
5646ba597c5SAnurag S. Maskey retry:
5656ba597c5SAnurag S. Maskey 	new = (scf_pg_get_property(res->sr_pg, propname, res->sr_prop) != 0);
5666ba597c5SAnurag S. Maskey 
5676ba597c5SAnurag S. Maskey 	if (scf_transaction_start(res->sr_tx, res->sr_pg) == -1) {
5686ba597c5SAnurag S. Maskey 		goto failure;
5696ba597c5SAnurag S. Maskey 	}
5706ba597c5SAnurag S. Maskey 	if (new) {
5716ba597c5SAnurag S. Maskey 		if (scf_transaction_property_new(res->sr_tx, res->sr_ent,
5726ba597c5SAnurag S. Maskey 		    propname, proptype) == -1) {
5736ba597c5SAnurag S. Maskey 			goto failure;
5746ba597c5SAnurag S. Maskey 		}
5756ba597c5SAnurag S. Maskey 	} else {
5766ba597c5SAnurag S. Maskey 		if (scf_transaction_property_change(res->sr_tx, res->sr_ent,
5776ba597c5SAnurag S. Maskey 		    propname, proptype) == -1) {
5786ba597c5SAnurag S. Maskey 			goto failure;
5796ba597c5SAnurag S. Maskey 		}
5806ba597c5SAnurag S. Maskey 	}
5816ba597c5SAnurag S. Maskey 
5826ba597c5SAnurag S. Maskey 	if (scf_entry_add_value(res->sr_ent, res->sr_val) != 0) {
5836ba597c5SAnurag S. Maskey 		goto failure;
5846ba597c5SAnurag S. Maskey 	}
5856ba597c5SAnurag S. Maskey 
5866ba597c5SAnurag S. Maskey 	result = scf_transaction_commit(res->sr_tx);
5876ba597c5SAnurag S. Maskey 	if (result == 0) {
5886ba597c5SAnurag S. Maskey 		scf_transaction_reset(res->sr_tx);
5896ba597c5SAnurag S. Maskey 		if (scf_pg_update(res->sr_pg) == -1) {
5906ba597c5SAnurag S. Maskey 			goto failure;
5916ba597c5SAnurag S. Maskey 		}
5926ba597c5SAnurag S. Maskey 		nlog(LOG_INFO, "set_property_value: transaction commit failed "
5936ba597c5SAnurag S. Maskey 		    "for %s; retrying", propname);
5946ba597c5SAnurag S. Maskey 		goto retry;
5956ba597c5SAnurag S. Maskey 	}
5966ba597c5SAnurag S. Maskey 	if (result == -1)
5976ba597c5SAnurag S. Maskey 		goto failure;
5986ba597c5SAnurag S. Maskey 	return (0);
5996ba597c5SAnurag S. Maskey 
6006ba597c5SAnurag S. Maskey failure:
6016ba597c5SAnurag S. Maskey 	return (-1);
6026ba597c5SAnurag S. Maskey }
6036ba597c5SAnurag S. Maskey 
6046ba597c5SAnurag S. Maskey int
6056ba597c5SAnurag S. Maskey nwamd_set_count_property(const char *fmri, const char *pg, const char *prop,
6066ba597c5SAnurag S. Maskey     uint64_t count)
6076ba597c5SAnurag S. Maskey {
6086ba597c5SAnurag S. Maskey 	scf_resources_t res;
6096ba597c5SAnurag S. Maskey 
6106ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, &res) != 0)
6116ba597c5SAnurag S. Maskey 		return (-1);
6126ba597c5SAnurag S. Maskey 
6136ba597c5SAnurag S. Maskey 	if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION,
6146ba597c5SAnurag S. Maskey 	    SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) {
6156ba597c5SAnurag S. Maskey 		if (scf_error() != SCF_ERROR_EXISTS)
6166ba597c5SAnurag S. Maskey 			goto failure;
6176ba597c5SAnurag S. Maskey 		if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg,
6186ba597c5SAnurag S. Maskey 		    res.sr_pg) != 0)
6196ba597c5SAnurag S. Maskey 			goto failure;
6206ba597c5SAnurag S. Maskey 	}
6216ba597c5SAnurag S. Maskey 
6226ba597c5SAnurag S. Maskey 	scf_value_set_count(res.sr_val, (uint64_t)count);
6236ba597c5SAnurag S. Maskey 
6246ba597c5SAnurag S. Maskey 	if (set_property_value(&res, prop, SCF_TYPE_COUNT) != 0)
6256ba597c5SAnurag S. Maskey 		goto failure;
6266ba597c5SAnurag S. Maskey 
6276ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
6286ba597c5SAnurag S. Maskey 	return (0);
6296ba597c5SAnurag S. Maskey 
6306ba597c5SAnurag S. Maskey failure:
6316ba597c5SAnurag S. Maskey 	nlog(LOG_INFO, "nwamd_set_count_property: scf failure %s while "
6326ba597c5SAnurag S. Maskey 	    "setting %s", scf_strerror(scf_error()), prop);
6336ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
6346ba597c5SAnurag S. Maskey 	return (-1);
6356ba597c5SAnurag S. Maskey }
6366ba597c5SAnurag S. Maskey 
6376ba597c5SAnurag S. Maskey int
6386ba597c5SAnurag S. Maskey nwamd_set_string_property(const char *fmri, const char *pg, const char *prop,
6396ba597c5SAnurag S. Maskey     const char *str)
6406ba597c5SAnurag S. Maskey {
6416ba597c5SAnurag S. Maskey 	scf_resources_t res;
6426ba597c5SAnurag S. Maskey 
6436ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, &res) != 0)
6446ba597c5SAnurag S. Maskey 		return (-1);
6456ba597c5SAnurag S. Maskey 
6466ba597c5SAnurag S. Maskey 	if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION,
6476ba597c5SAnurag S. Maskey 	    SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) {
6486ba597c5SAnurag S. Maskey 		if (scf_error() != SCF_ERROR_EXISTS)
6496ba597c5SAnurag S. Maskey 			goto failure;
6506ba597c5SAnurag S. Maskey 		if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg,
6516ba597c5SAnurag S. Maskey 		    res.sr_pg) != 0)
6526ba597c5SAnurag S. Maskey 			goto failure;
6536ba597c5SAnurag S. Maskey 	}
6546ba597c5SAnurag S. Maskey 
6556ba597c5SAnurag S. Maskey 	if (scf_value_set_astring(res.sr_val, str) != 0)
6566ba597c5SAnurag S. Maskey 		goto failure;
6576ba597c5SAnurag S. Maskey 
6586ba597c5SAnurag S. Maskey 	if (set_property_value(&res, prop, SCF_TYPE_ASTRING) != 0)
6596ba597c5SAnurag S. Maskey 		goto failure;
6606ba597c5SAnurag S. Maskey 
6616ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
6626ba597c5SAnurag S. Maskey 	return (0);
6636ba597c5SAnurag S. Maskey 
6646ba597c5SAnurag S. Maskey failure:
6656ba597c5SAnurag S. Maskey 	nlog(LOG_INFO, "nwamd_set_string_property: scf failure %s while "
6666ba597c5SAnurag S. Maskey 	    "setting %s", scf_strerror(scf_error()), prop);
6676ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
6686ba597c5SAnurag S. Maskey 	return (-1);
6696ba597c5SAnurag S. Maskey }
6706ba597c5SAnurag S. Maskey 
6716ba597c5SAnurag S. Maskey /*
6726ba597c5SAnurag S. Maskey  * Deletes property prop from property group pg in SMF instance fmri.
6736ba597c5SAnurag S. Maskey  * Returns 0 on success, -1 on failure.
6746ba597c5SAnurag S. Maskey  */
6756ba597c5SAnurag S. Maskey int
6766ba597c5SAnurag S. Maskey nwamd_delete_scf_property(const char *fmri, const char *pg, const char *prop)
6776ba597c5SAnurag S. Maskey {
6786ba597c5SAnurag S. Maskey 	scf_resources_t res;
6796ba597c5SAnurag S. Maskey 	int result = -1;
6806ba597c5SAnurag S. Maskey 
6816ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, &res) != 0)
6826ba597c5SAnurag S. Maskey 		return (-1);
6836ba597c5SAnurag S. Maskey 
6846ba597c5SAnurag S. Maskey 	if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION,
6856ba597c5SAnurag S. Maskey 	    SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) {
6866ba597c5SAnurag S. Maskey 		if (scf_error() != SCF_ERROR_EXISTS)
6876ba597c5SAnurag S. Maskey 			goto failure;
6886ba597c5SAnurag S. Maskey 		if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg,
6896ba597c5SAnurag S. Maskey 		    res.sr_pg) != 0)
6906ba597c5SAnurag S. Maskey 			goto failure;
6916ba597c5SAnurag S. Maskey 	}
6926ba597c5SAnurag S. Maskey 
6936ba597c5SAnurag S. Maskey 	if (scf_pg_get_property(res.sr_pg, prop, res.sr_prop) != 0)
6946ba597c5SAnurag S. Maskey 		goto failure;
6956ba597c5SAnurag S. Maskey retry:
6966ba597c5SAnurag S. Maskey 	if (scf_transaction_start(res.sr_tx, res.sr_pg) == -1)
6976ba597c5SAnurag S. Maskey 		goto failure;
6986ba597c5SAnurag S. Maskey 
6996ba597c5SAnurag S. Maskey 	if (scf_transaction_property_delete(res.sr_tx, res.sr_ent, prop) == -1)
7006ba597c5SAnurag S. Maskey 		goto failure;
7016ba597c5SAnurag S. Maskey 
7026ba597c5SAnurag S. Maskey 	result = scf_transaction_commit(res.sr_tx);
7036ba597c5SAnurag S. Maskey 	if (result == 0) {
7046ba597c5SAnurag S. Maskey 		scf_transaction_reset(res.sr_tx);
7056ba597c5SAnurag S. Maskey 		if (scf_pg_update(res.sr_pg) == -1)
7066ba597c5SAnurag S. Maskey 			goto failure;
7076ba597c5SAnurag S. Maskey 		goto retry;
7086ba597c5SAnurag S. Maskey 	}
7096ba597c5SAnurag S. Maskey 	if (result == -1)
7106ba597c5SAnurag S. Maskey 		goto failure;
7116ba597c5SAnurag S. Maskey 
7126ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
7136ba597c5SAnurag S. Maskey 	return (0);
7146ba597c5SAnurag S. Maskey failure:
7156ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
7166ba597c5SAnurag S. Maskey 	return (-1);
717d71dbb73Sjbeck }
718