xref: /illumos-gate/usr/src/cmd/cmd-inet/lib/nwamd/util.c (revision 38f140aa)
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
85*38f140aaSMichael Hunter nwamd_escalate(void) {
86*38f140aaSMichael Hunter 	priv_set_t *priv_set;
87*38f140aaSMichael Hunter 	priv_set = priv_str_to_set("zone", ",", NULL);
88*38f140aaSMichael Hunter 
89*38f140aaSMichael Hunter 	if (priv_set == NULL)
90*38f140aaSMichael Hunter 		pfail("creating privilege set: %s", strerror(errno));
91*38f140aaSMichael 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) {
96*38f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) {
97*38f140aaSMichael Hunter 			priv_freeset(priv_set);
98*38f140aaSMichael Hunter 			pfail("setppriv effective: %s", strerror(errno));
99*38f140aaSMichael 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);
104*38f140aaSMichael Hunter 
105*38f140aaSMichael Hunter 	priv_freeset(priv_set);
106d71dbb73Sjbeck }
107d71dbb73Sjbeck 
108b00044a2SJames Carlson void
109*38f140aaSMichael Hunter nwamd_deescalate(void) {
110*38f140aaSMichael Hunter 	priv_set_t *priv_set, *allpriv_set;
111*38f140aaSMichael Hunter 
1126ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&uid_mutex);
1136ba597c5SAnurag S. Maskey 	assert(uid_cnt > 0);
1146ba597c5SAnurag S. Maskey 	if (--uid_cnt == 0) {
1156ba597c5SAnurag S. Maskey 		if (setuid(uid) == -1)
1166ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "setuid(%d) failed %s", uid,
1176ba597c5SAnurag S. Maskey 			    strerror(errno));
118*38f140aaSMichael Hunter 
119*38f140aaSMichael Hunter 		/* build up our minimal set of privs. */
120*38f140aaSMichael Hunter 		priv_set = priv_str_to_set("basic", ",", NULL);
121*38f140aaSMichael Hunter 		allpriv_set = priv_str_to_set("zone", ",", NULL);
122*38f140aaSMichael Hunter 		if (priv_set == NULL || allpriv_set == NULL)
123*38f140aaSMichael Hunter 			pfail("converting privilege sets: %s", strerror(errno));
124*38f140aaSMichael Hunter 
125*38f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_FILE_CHOWN_SELF);
126*38f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_FILE_DAC_READ);
127*38f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_FILE_DAC_WRITE);
128*38f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_NET_RAWACCESS);
129*38f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_NET_PRIVADDR);
130*38f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_PROC_AUDIT);
131*38f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_PROC_OWNER);
132*38f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_PROC_SETID);
133*38f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_CONFIG);
134*38f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_IP_CONFIG);
135*38f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_IPC_CONFIG);
136*38f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_MOUNT);
137*38f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_NET_CONFIG);
138*38f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_RES_CONFIG);
139*38f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_RESOURCE);
140*38f140aaSMichael Hunter 
141*38f140aaSMichael Hunter 		/*
142*38f140aaSMichael Hunter 		 * Since our zone might not have all these privs,
143*38f140aaSMichael Hunter 		 * just ask for those that are available.
144*38f140aaSMichael Hunter 		 */
145*38f140aaSMichael Hunter 		priv_intersect(allpriv_set, priv_set);
146*38f140aaSMichael Hunter 
147*38f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_INHERITABLE, priv_set) == -1) {
148*38f140aaSMichael Hunter 			priv_freeset(allpriv_set);
149*38f140aaSMichael Hunter 			priv_freeset(priv_set);
150*38f140aaSMichael Hunter 			pfail("setppriv inheritable: %s", strerror(errno));
151*38f140aaSMichael Hunter 		}
152*38f140aaSMichael Hunter 		/*
153*38f140aaSMichael Hunter 		 * Need to ensure permitted set contains all privs so we can
154*38f140aaSMichael Hunter 		 * escalate later.
155*38f140aaSMichael Hunter 		 */
156*38f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_PERMITTED, allpriv_set) == -1) {
157*38f140aaSMichael Hunter 			priv_freeset(allpriv_set);
158*38f140aaSMichael Hunter 			priv_freeset(priv_set);
159*38f140aaSMichael Hunter 			pfail("setppriv permitted: %s", strerror(errno));
160*38f140aaSMichael Hunter 		}
161*38f140aaSMichael Hunter 		/*
162*38f140aaSMichael Hunter 		 * We need to find a smaller set of privs that are important to
163*38f140aaSMichael Hunter 		 * us.  Otherwise we really are not gaining much by doing this.
164*38f140aaSMichael Hunter 		 */
165*38f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) {
166*38f140aaSMichael Hunter 			priv_freeset(allpriv_set);
167*38f140aaSMichael Hunter 			priv_freeset(priv_set);
168*38f140aaSMichael Hunter 			pfail("setppriv effective: %s", strerror(errno));
169*38f140aaSMichael Hunter 		}
1706ba597c5SAnurag S. Maskey 	}
1716ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&uid_mutex);
172*38f140aaSMichael Hunter 
173*38f140aaSMichael Hunter 	priv_freeset(priv_set);
174*38f140aaSMichael Hunter 	priv_freeset(allpriv_set);
175b00044a2SJames Carlson }
176b00044a2SJames Carlson 
177d71dbb73Sjbeck /*
178d71dbb73Sjbeck  *
179d71dbb73Sjbeck  * This starts a child process determined by command.  If command contains a
180d71dbb73Sjbeck  * slash then it is assumed to be a full path; otherwise the path is searched
181d71dbb73Sjbeck  * for an executable file with the name command.  Command is also used as
182d71dbb73Sjbeck  * argv[0] of the new process.  The rest of the arguments of the function
183d71dbb73Sjbeck  * up to the first NULL make up pointers to arguments of the new process.
184d71dbb73Sjbeck  *
185d71dbb73Sjbeck  * This function returns child exit status on success and -1 on failure.
186d71dbb73Sjbeck  *
187d71dbb73Sjbeck  * NOTE: original_sigmask must be set before this function is called.
188d71dbb73Sjbeck  */
189d71dbb73Sjbeck int
1906ba597c5SAnurag S. Maskey nwamd_start_childv(const char *command, char const * const *argv)
191d71dbb73Sjbeck {
192d71dbb73Sjbeck 	posix_spawnattr_t attr;
193d71dbb73Sjbeck 	sigset_t fullset;
194d71dbb73Sjbeck 	int i, rc, status, n;
195d71dbb73Sjbeck 	pid_t pid;
196d71dbb73Sjbeck 	char vbuf[1024];
197d71dbb73Sjbeck 
198d71dbb73Sjbeck 	vbuf[0] = 0;
199d71dbb73Sjbeck 	n = sizeof (vbuf);
200d71dbb73Sjbeck 	for (i = 1; argv[i] != NULL && n > 2; i++) {
201d71dbb73Sjbeck 		n -= strlcat(vbuf, " ", n);
202d71dbb73Sjbeck 		n -= strlcat(vbuf, argv[i], n);
203d71dbb73Sjbeck 	}
204d71dbb73Sjbeck 	if (argv[i] != NULL || n < 0)
2056ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_start_childv can't log full arg vector");
206d71dbb73Sjbeck 
207d71dbb73Sjbeck 	if ((rc = posix_spawnattr_init(&attr)) != 0) {
2086ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "posix_spawnattr_init %d %s\n",
2096ba597c5SAnurag S. Maskey 		    rc, strerror(rc));
210d71dbb73Sjbeck 		return (-1);
211d71dbb73Sjbeck 	}
212d71dbb73Sjbeck 	(void) sigfillset(&fullset);
213d71dbb73Sjbeck 	if ((rc = posix_spawnattr_setsigdefault(&attr, &fullset)) != 0) {
2146ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "setsigdefault %d %s\n", rc, strerror(rc));
215d71dbb73Sjbeck 		return (-1);
216d71dbb73Sjbeck 	}
217d71dbb73Sjbeck 	if ((rc = posix_spawnattr_setsigmask(&attr, &original_sigmask)) != 0) {
2186ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "setsigmask %d %s\n", rc, strerror(rc));
219d71dbb73Sjbeck 		return (-1);
220d71dbb73Sjbeck 	}
221d71dbb73Sjbeck 	if ((rc = posix_spawnattr_setflags(&attr,
222d71dbb73Sjbeck 	    POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK)) != 0) {
2236ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "setflags %d %s\n", rc, strerror(rc));
224d71dbb73Sjbeck 		return (-1);
225d71dbb73Sjbeck 	}
226d71dbb73Sjbeck 
227d71dbb73Sjbeck 	if ((rc = posix_spawnp(&pid, command, NULL, &attr, (char * const *)argv,
228d71dbb73Sjbeck 	    environ)) > 0) {
2296ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "posix_spawnp failed errno %d", rc);
230d71dbb73Sjbeck 		return (-1);
231d71dbb73Sjbeck 	}
232d71dbb73Sjbeck 
233d71dbb73Sjbeck 	if ((rc = posix_spawnattr_destroy(&attr)) != 0) {
2346ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "posix_spawn_attr_destroy %d %s\n",
2356ba597c5SAnurag S. Maskey 		    rc, strerror(rc));
236d71dbb73Sjbeck 		return (-1);
237d71dbb73Sjbeck 	}
238d71dbb73Sjbeck 
239d71dbb73Sjbeck 	(void) waitpid(pid, &status, 0);
240d71dbb73Sjbeck 	if (WIFSIGNALED(status) || WIFSTOPPED(status)) {
241d71dbb73Sjbeck 		i = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status);
2426ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "'%s%s' %s with signal %d (%s)", command, vbuf,
243d71dbb73Sjbeck 		    (WIFSIGNALED(status) ? "terminated" : "stopped"), i,
244d71dbb73Sjbeck 		    strsignal(i));
245d71dbb73Sjbeck 		return (-2);
246d71dbb73Sjbeck 	} else {
2476ba597c5SAnurag S. Maskey 		nlog(LOG_INFO, "'%s%s' completed normally: %d", command, vbuf,
248d71dbb73Sjbeck 		    WEXITSTATUS(status));
249d71dbb73Sjbeck 		return (WEXITSTATUS(status));
250d71dbb73Sjbeck 	}
251d71dbb73Sjbeck }
252d71dbb73Sjbeck 
2536ba597c5SAnurag S. Maskey /*
2546ba597c5SAnurag S. Maskey  * For global zone, check if the link is used by a non-global
2556ba597c5SAnurag S. Maskey  * zone, note that the non-global zones doesn't need this check,
2566ba597c5SAnurag S. Maskey  * because zoneadm has taken care of this when the zone boots.
2576ba597c5SAnurag S. Maskey  * In the global zone, we ignore events for local-zone-owned links
2586ba597c5SAnurag S. Maskey  * since these are taken care of by the local zone's network
2596ba597c5SAnurag S. Maskey  * configuration services.
2606ba597c5SAnurag S. Maskey  */
2616ba597c5SAnurag S. Maskey boolean_t
2626ba597c5SAnurag S. Maskey nwamd_link_belongs_to_this_zone(const char *linkname)
263d71dbb73Sjbeck {
2646ba597c5SAnurag S. Maskey 	zoneid_t zoneid;
2656ba597c5SAnurag S. Maskey 	char zonename[ZONENAME_MAX];
2666ba597c5SAnurag S. Maskey 	int ret;
2676ba597c5SAnurag S. Maskey 
2686ba597c5SAnurag S. Maskey 	zoneid = getzoneid();
2696ba597c5SAnurag S. Maskey 	if (zoneid == GLOBAL_ZONEID) {
2706ba597c5SAnurag S. Maskey 		datalink_id_t linkid;
2716ba597c5SAnurag S. Maskey 		dladm_status_t status;
2726ba597c5SAnurag S. Maskey 		char errstr[DLADM_STRSIZE];
2736ba597c5SAnurag S. Maskey 
2746ba597c5SAnurag S. Maskey 		if ((status = dladm_name2info(dld_handle, linkname, &linkid,
2756ba597c5SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
2766ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: "
2776ba597c5SAnurag S. Maskey 			    "could not get linkid for %s: %s",
2786ba597c5SAnurag S. Maskey 			    linkname, dladm_status2str(status, errstr));
2796ba597c5SAnurag S. Maskey 			return (B_FALSE);
2806ba597c5SAnurag S. Maskey 		}
2816ba597c5SAnurag S. Maskey 		zoneid = ALL_ZONES;
2826ba597c5SAnurag S. Maskey 		ret = zone_check_datalink(&zoneid, linkid);
2836ba597c5SAnurag S. Maskey 		if (ret == 0) {
2846ba597c5SAnurag S. Maskey 			(void) getzonenamebyid(zoneid, zonename, ZONENAME_MAX);
2856ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: "
2866ba597c5SAnurag S. Maskey 			    "%s is used by non-global zone: %s",
2876ba597c5SAnurag S. Maskey 			    linkname, zonename);
2886ba597c5SAnurag S. Maskey 			return (B_FALSE);
289d71dbb73Sjbeck 		}
2906ba597c5SAnurag S. Maskey 	}
2916ba597c5SAnurag S. Maskey 	return (B_TRUE);
2926ba597c5SAnurag S. Maskey }
293d71dbb73Sjbeck 
2946ba597c5SAnurag S. Maskey /*
2956ba597c5SAnurag S. Maskey  * Inputs:
2966ba597c5SAnurag S. Maskey  *   res is a pointer to the scf_resources_t to be released.
2976ba597c5SAnurag S. Maskey  */
2986ba597c5SAnurag S. Maskey static void
2996ba597c5SAnurag S. Maskey release_scf_resources(scf_resources_t *res)
3006ba597c5SAnurag S. Maskey {
3016ba597c5SAnurag S. Maskey 	scf_entry_destroy(res->sr_ent);
3026ba597c5SAnurag S. Maskey 	scf_transaction_destroy(res->sr_tx);
3036ba597c5SAnurag S. Maskey 	scf_value_destroy(res->sr_val);
3046ba597c5SAnurag S. Maskey 	scf_property_destroy(res->sr_prop);
3056ba597c5SAnurag S. Maskey 	scf_pg_destroy(res->sr_pg);
3066ba597c5SAnurag S. Maskey 	scf_snapshot_destroy(res->sr_snap);
3076ba597c5SAnurag S. Maskey 	scf_instance_destroy(res->sr_inst);
3086ba597c5SAnurag S. Maskey 	(void) scf_handle_unbind(res->sr_handle);
3096ba597c5SAnurag S. Maskey 	scf_handle_destroy(res->sr_handle);
3106ba597c5SAnurag S. Maskey }
311d71dbb73Sjbeck 
312d71dbb73Sjbeck /*
3136ba597c5SAnurag S. Maskey  * Inputs:
3146ba597c5SAnurag S. Maskey  *   fmri is the instance to look up
3156ba597c5SAnurag S. Maskey  * Outputs:
3166ba597c5SAnurag S. Maskey  *   res is a pointer to an scf_resources_t.  This is an internal
3176ba597c5SAnurag S. Maskey  *   structure that holds all the handles needed to get a specific
3186ba597c5SAnurag S. Maskey  *   property from the running snapshot; on a successful return it
3196ba597c5SAnurag S. Maskey  *   contains the scf_value_t that should be passed to the desired
3206ba597c5SAnurag S. Maskey  *   scf_value_get_foo() function, and must be freed after use by
3216ba597c5SAnurag S. Maskey  *   calling release_scf_resources().  On a failure return, any
3226ba597c5SAnurag S. Maskey  *   resources that may have been assigned to res are released, so
3236ba597c5SAnurag S. Maskey  *   the caller does not need to do any cleanup in the failure case.
3246ba597c5SAnurag S. Maskey  * Returns:
3256ba597c5SAnurag S. Maskey  *    0 on success
3266ba597c5SAnurag S. Maskey  *   -1 on failure
327d71dbb73Sjbeck  */
3286ba597c5SAnurag S. Maskey 
3296ba597c5SAnurag S. Maskey static int
3306ba597c5SAnurag S. Maskey create_scf_resources(const char *fmri, scf_resources_t *res)
3316ba597c5SAnurag S. Maskey {
3326ba597c5SAnurag S. Maskey 	res->sr_tx = NULL;
3336ba597c5SAnurag S. Maskey 	res->sr_ent = NULL;
3346ba597c5SAnurag S. Maskey 	res->sr_inst = NULL;
3356ba597c5SAnurag S. Maskey 	res->sr_snap = NULL;
3366ba597c5SAnurag S. Maskey 	res->sr_pg = NULL;
3376ba597c5SAnurag S. Maskey 	res->sr_prop = NULL;
3386ba597c5SAnurag S. Maskey 	res->sr_val = NULL;
3396ba597c5SAnurag S. Maskey 
3406ba597c5SAnurag S. Maskey 	if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL) {
3416ba597c5SAnurag S. Maskey 		return (-1);
3426ba597c5SAnurag S. Maskey 	}
3436ba597c5SAnurag S. Maskey 
3446ba597c5SAnurag S. Maskey 	if (scf_handle_bind(res->sr_handle) != 0) {
3456ba597c5SAnurag S. Maskey 		scf_handle_destroy(res->sr_handle);
3466ba597c5SAnurag S. Maskey 		return (-1);
3476ba597c5SAnurag S. Maskey 	}
3486ba597c5SAnurag S. Maskey 	if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL) {
3496ba597c5SAnurag S. Maskey 		goto failure;
3506ba597c5SAnurag S. Maskey 	}
3516ba597c5SAnurag S. Maskey 	if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL,
3526ba597c5SAnurag S. Maskey 	    res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
3536ba597c5SAnurag S. Maskey 		goto failure;
3546ba597c5SAnurag S. Maskey 	}
3556ba597c5SAnurag S. Maskey 	if ((res->sr_snap = scf_snapshot_create(res->sr_handle)) == NULL) {
3566ba597c5SAnurag S. Maskey 		goto failure;
3576ba597c5SAnurag S. Maskey 	}
3586ba597c5SAnurag S. Maskey 	if (scf_instance_get_snapshot(res->sr_inst, "running",
3596ba597c5SAnurag S. Maskey 	    res->sr_snap) != 0) {
3606ba597c5SAnurag S. Maskey 		goto failure;
3616ba597c5SAnurag S. Maskey 	}
3626ba597c5SAnurag S. Maskey 	if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
3636ba597c5SAnurag S. Maskey 		goto failure;
3646ba597c5SAnurag S. Maskey 	}
3656ba597c5SAnurag S. Maskey 	if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL) {
3666ba597c5SAnurag S. Maskey 		goto failure;
3676ba597c5SAnurag S. Maskey 	}
3686ba597c5SAnurag S. Maskey 	if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL) {
3696ba597c5SAnurag S. Maskey 		goto failure;
3706ba597c5SAnurag S. Maskey 	}
3716ba597c5SAnurag S. Maskey 	if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL) {
3726ba597c5SAnurag S. Maskey 		goto failure;
3736ba597c5SAnurag S. Maskey 	}
3746ba597c5SAnurag S. Maskey 	if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL) {
3756ba597c5SAnurag S. Maskey 		goto failure;
3766ba597c5SAnurag S. Maskey 	}
3776ba597c5SAnurag S. Maskey 	return (0);
3786ba597c5SAnurag S. Maskey 
3796ba597c5SAnurag S. Maskey failure:
3806ba597c5SAnurag S. Maskey 	nlog(LOG_ERR, "create_scf_resources failed: %s",
3816ba597c5SAnurag S. Maskey 	    scf_strerror(scf_error()));
3826ba597c5SAnurag S. Maskey 	release_scf_resources(res);
3836ba597c5SAnurag S. Maskey 	return (-1);
3846ba597c5SAnurag S. Maskey }
3856ba597c5SAnurag S. Maskey 
3866ba597c5SAnurag S. Maskey /*
3876ba597c5SAnurag S. Maskey  * Inputs:
3886ba597c5SAnurag S. Maskey  *   fmri is the instance to look up
3896ba597c5SAnurag S. Maskey  *   pg is the property group to look up
3906ba597c5SAnurag S. Maskey  *   prop is the property within that group to look up
3916ba597c5SAnurag S. Maskey  *   running specifies if running snapshot is to be used
3926ba597c5SAnurag S. Maskey  * Outputs:
3936ba597c5SAnurag S. Maskey  *   res is a pointer to an scf_resources_t.  This is an internal
3946ba597c5SAnurag S. Maskey  *   structure that holds all the handles needed to get a specific
3956ba597c5SAnurag S. Maskey  *   property from the running snapshot; on a successful return it
3966ba597c5SAnurag S. Maskey  *   contains the scf_value_t that should be passed to the desired
3976ba597c5SAnurag S. Maskey  *   scf_value_get_foo() function, and must be freed after use by
3986ba597c5SAnurag S. Maskey  *   calling release_scf_resources().  On a failure return, any
3996ba597c5SAnurag S. Maskey  *   resources that may have been assigned to res are released, so
4006ba597c5SAnurag S. Maskey  *   the caller does not need to do any cleanup in the failure case.
4016ba597c5SAnurag S. Maskey  * Returns:
4026ba597c5SAnurag S. Maskey  *    0 on success
4036ba597c5SAnurag S. Maskey  *   -1 on failure
4046ba597c5SAnurag S. Maskey  */
4056ba597c5SAnurag S. Maskey static int
4066ba597c5SAnurag S. Maskey get_property_value(const char *fmri, const char *pg, const char *prop,
4076ba597c5SAnurag S. Maskey     boolean_t running, scf_resources_t *res)
408d71dbb73Sjbeck {
4096ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, res) != 0)
4106ba597c5SAnurag S. Maskey 		return (-1);
4116ba597c5SAnurag S. Maskey 
4126ba597c5SAnurag S. Maskey 	if (scf_instance_get_pg_composed(res->sr_inst,
4136ba597c5SAnurag S. Maskey 	    running ? res->sr_snap : NULL, pg, res->sr_pg) != 0) {
4146ba597c5SAnurag S. Maskey 		goto failure;
4156ba597c5SAnurag S. Maskey 	}
4166ba597c5SAnurag S. Maskey 	if (scf_pg_get_property(res->sr_pg, prop, res->sr_prop) != 0) {
4176ba597c5SAnurag S. Maskey 		goto failure;
4186ba597c5SAnurag S. Maskey 	}
4196ba597c5SAnurag S. Maskey 	if (scf_property_get_value(res->sr_prop, res->sr_val) != 0) {
4206ba597c5SAnurag S. Maskey 		goto failure;
4216ba597c5SAnurag S. Maskey 	}
4226ba597c5SAnurag S. Maskey 	return (0);
423d71dbb73Sjbeck 
4246ba597c5SAnurag S. Maskey failure:
4256ba597c5SAnurag S. Maskey 	release_scf_resources(res);
4266ba597c5SAnurag S. Maskey 	return (-1);
427d71dbb73Sjbeck }
428d71dbb73Sjbeck 
4296ba597c5SAnurag S. Maskey /*
4306ba597c5SAnurag S. Maskey  * Inputs:
4316ba597c5SAnurag S. Maskey  *   lfmri is the instance fmri to look up
4326ba597c5SAnurag S. Maskey  *   lpg is the property group to look up
4336ba597c5SAnurag S. Maskey  *   lprop is the property within that group to look up
4346ba597c5SAnurag S. Maskey  * Outputs:
4356ba597c5SAnurag S. Maskey  *   answer is a pointer to the property value
4366ba597c5SAnurag S. Maskey  * Returns:
4376ba597c5SAnurag S. Maskey  *    0 on success
4386ba597c5SAnurag S. Maskey  *   -1 on failure
4396ba597c5SAnurag S. Maskey  * If successful, the property value is retured in *answer.
4406ba597c5SAnurag S. Maskey  * Otherwise, *answer is undefined, and it is up to the caller to decide
4416ba597c5SAnurag S. Maskey  * how to handle that case.
4426ba597c5SAnurag S. Maskey  */
4436ba597c5SAnurag S. Maskey int
4446ba597c5SAnurag S. Maskey nwamd_lookup_boolean_property(const char *lfmri, const char *lpg,
4456ba597c5SAnurag S. Maskey     const char *lprop, boolean_t *answer)
4466ba597c5SAnurag S. Maskey {
4476ba597c5SAnurag S. Maskey 	int result = -1;
4486ba597c5SAnurag S. Maskey 	scf_resources_t res;
4496ba597c5SAnurag S. Maskey 	uint8_t prop_val;
4506ba597c5SAnurag S. Maskey 
4516ba597c5SAnurag S. Maskey 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
4526ba597c5SAnurag S. Maskey 
4536ba597c5SAnurag S. Maskey 		/*
4546ba597c5SAnurag S. Maskey 		 * an error was already logged by get_property_value,
4556ba597c5SAnurag S. Maskey 		 * and it released any resources assigned to res before
4566ba597c5SAnurag S. Maskey 		 * returning.
4576ba597c5SAnurag S. Maskey 		 */
4586ba597c5SAnurag S. Maskey 		return (result);
4596ba597c5SAnurag S. Maskey 	}
4606ba597c5SAnurag S. Maskey 	if (scf_value_get_boolean(res.sr_val, &prop_val) != 0) {
4616ba597c5SAnurag S. Maskey 		goto cleanup;
4626ba597c5SAnurag S. Maskey 	}
4636ba597c5SAnurag S. Maskey 	*answer = (boolean_t)prop_val;
4646ba597c5SAnurag S. Maskey 	result = 0;
4656ba597c5SAnurag S. Maskey cleanup:
4666ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
4676ba597c5SAnurag S. Maskey 	return (result);
4686ba597c5SAnurag S. Maskey }
4696ba597c5SAnurag S. Maskey 
4706ba597c5SAnurag S. Maskey /*
4716ba597c5SAnurag S. Maskey  * Inputs:
4726ba597c5SAnurag S. Maskey  *   lfmri is the instance fmri to look up
4736ba597c5SAnurag S. Maskey  *   lpg is the property group to look up
4746ba597c5SAnurag S. Maskey  *   lprop is the property within that group to look up
4756ba597c5SAnurag S. Maskey  *   buf is the place to put the answer
4766ba597c5SAnurag S. Maskey  *   bufsz is the size of buf
4776ba597c5SAnurag S. Maskey  * Outputs:
4786ba597c5SAnurag S. Maskey  *
4796ba597c5SAnurag S. Maskey  * Returns:
4806ba597c5SAnurag S. Maskey  *    0 on success
4816ba597c5SAnurag S. Maskey  *   -1 on failure
4826ba597c5SAnurag S. Maskey  * If successful, the property value is retured in buf.
4836ba597c5SAnurag S. Maskey  * Otherwise, buf is undefined, and it is up to the caller to decide
4846ba597c5SAnurag S. Maskey  * how to handle that case.
4856ba597c5SAnurag S. Maskey  */
4866ba597c5SAnurag S. Maskey int
4876ba597c5SAnurag S. Maskey nwamd_lookup_string_property(const char *lfmri, const char *lpg,
4886ba597c5SAnurag S. Maskey     const char *lprop, char *buf, size_t bufsz)
489d71dbb73Sjbeck {
4906ba597c5SAnurag S. Maskey 	int result = -1;
4916ba597c5SAnurag S. Maskey 	scf_resources_t res;
4926ba597c5SAnurag S. Maskey 
4936ba597c5SAnurag S. Maskey 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
4946ba597c5SAnurag S. Maskey 		/*
4956ba597c5SAnurag S. Maskey 		 * The above function fails when trying to get a
4966ba597c5SAnurag S. Maskey 		 * non-persistent property group from the running snapshot.
4976ba597c5SAnurag S. Maskey 		 * Try going for the non-running snapshot.
4986ba597c5SAnurag S. Maskey 		 */
4996ba597c5SAnurag S. Maskey 		if (get_property_value(lfmri, lpg, lprop, B_FALSE, &res) != 0) {
5006ba597c5SAnurag S. Maskey 			/*
5016ba597c5SAnurag S. Maskey 			 * an error was already logged by get_property_value,
5026ba597c5SAnurag S. Maskey 			 * and it released any resources assigned to res before
5036ba597c5SAnurag S. Maskey 			 * returning.
5046ba597c5SAnurag S. Maskey 			 */
5056ba597c5SAnurag S. Maskey 			return (result);
5066ba597c5SAnurag S. Maskey 		}
5076ba597c5SAnurag S. Maskey 	}
5086ba597c5SAnurag S. Maskey 	if (scf_value_get_astring(res.sr_val, buf, bufsz) == 0)
5096ba597c5SAnurag S. Maskey 		goto cleanup;
5106ba597c5SAnurag S. Maskey 
5116ba597c5SAnurag S. Maskey 	result = 0;
5126ba597c5SAnurag S. Maskey cleanup:
5136ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
5146ba597c5SAnurag S. Maskey 	return (result);
5156ba597c5SAnurag S. Maskey }
516d71dbb73Sjbeck 
5176ba597c5SAnurag S. Maskey /*
5186ba597c5SAnurag S. Maskey  * Inputs:
5196ba597c5SAnurag S. Maskey  *   lfmri is the instance fmri to look up
5206ba597c5SAnurag S. Maskey  *   lpg is the property group to look up
5216ba597c5SAnurag S. Maskey  *   lprop is the property within that group to look up
5226ba597c5SAnurag S. Maskey  * Outputs:
5236ba597c5SAnurag S. Maskey  *   answer is a pointer to the property value
5246ba597c5SAnurag S. Maskey  * Returns:
5256ba597c5SAnurag S. Maskey  *    0 on success
5266ba597c5SAnurag S. Maskey  *   -1 on failure
5276ba597c5SAnurag S. Maskey  * If successful, the property value is retured in *answer.
5286ba597c5SAnurag S. Maskey  * Otherwise, *answer is undefined, and it is up to the caller to decide
5296ba597c5SAnurag S. Maskey  * how to handle that case.
5306ba597c5SAnurag S. Maskey  */
5316ba597c5SAnurag S. Maskey int
5326ba597c5SAnurag S. Maskey nwamd_lookup_count_property(const char *lfmri, const char *lpg,
5336ba597c5SAnurag S. Maskey     const char *lprop, uint64_t *answer)
5346ba597c5SAnurag S. Maskey {
5356ba597c5SAnurag S. Maskey 	int result = -1;
5366ba597c5SAnurag S. Maskey 	scf_resources_t res;
5376ba597c5SAnurag S. Maskey 
5386ba597c5SAnurag S. Maskey 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
5396ba597c5SAnurag S. Maskey 
5406ba597c5SAnurag S. Maskey 		/*
5416ba597c5SAnurag S. Maskey 		 * an error was already logged by get_property_value,
5426ba597c5SAnurag S. Maskey 		 * and it released any resources assigned to res before
5436ba597c5SAnurag S. Maskey 		 * returning.
5446ba597c5SAnurag S. Maskey 		 */
5456ba597c5SAnurag S. Maskey 		return (result);
5466ba597c5SAnurag S. Maskey 	}
5476ba597c5SAnurag S. Maskey 	if (scf_value_get_count(res.sr_val, answer) != 0) {
5486ba597c5SAnurag S. Maskey 		goto cleanup;
5496ba597c5SAnurag S. Maskey 	}
5506ba597c5SAnurag S. Maskey 	result = 0;
5516ba597c5SAnurag S. Maskey cleanup:
5526ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
5536ba597c5SAnurag S. Maskey 	return (result);
5546ba597c5SAnurag S. Maskey }
5556ba597c5SAnurag S. Maskey 
5566ba597c5SAnurag S. Maskey static int
5576ba597c5SAnurag S. Maskey set_property_value(scf_resources_t *res, const char *propname,
5586ba597c5SAnurag S. Maskey     scf_type_t proptype)
5596ba597c5SAnurag S. Maskey {
5606ba597c5SAnurag S. Maskey 	int result = -1;
5616ba597c5SAnurag S. Maskey 	boolean_t new;
5626ba597c5SAnurag S. Maskey 
5636ba597c5SAnurag S. Maskey retry:
5646ba597c5SAnurag S. Maskey 	new = (scf_pg_get_property(res->sr_pg, propname, res->sr_prop) != 0);
5656ba597c5SAnurag S. Maskey 
5666ba597c5SAnurag S. Maskey 	if (scf_transaction_start(res->sr_tx, res->sr_pg) == -1) {
5676ba597c5SAnurag S. Maskey 		goto failure;
5686ba597c5SAnurag S. Maskey 	}
5696ba597c5SAnurag S. Maskey 	if (new) {
5706ba597c5SAnurag S. Maskey 		if (scf_transaction_property_new(res->sr_tx, res->sr_ent,
5716ba597c5SAnurag S. Maskey 		    propname, proptype) == -1) {
5726ba597c5SAnurag S. Maskey 			goto failure;
5736ba597c5SAnurag S. Maskey 		}
5746ba597c5SAnurag S. Maskey 	} else {
5756ba597c5SAnurag S. Maskey 		if (scf_transaction_property_change(res->sr_tx, res->sr_ent,
5766ba597c5SAnurag S. Maskey 		    propname, proptype) == -1) {
5776ba597c5SAnurag S. Maskey 			goto failure;
5786ba597c5SAnurag S. Maskey 		}
5796ba597c5SAnurag S. Maskey 	}
5806ba597c5SAnurag S. Maskey 
5816ba597c5SAnurag S. Maskey 	if (scf_entry_add_value(res->sr_ent, res->sr_val) != 0) {
5826ba597c5SAnurag S. Maskey 		goto failure;
5836ba597c5SAnurag S. Maskey 	}
5846ba597c5SAnurag S. Maskey 
5856ba597c5SAnurag S. Maskey 	result = scf_transaction_commit(res->sr_tx);
5866ba597c5SAnurag S. Maskey 	if (result == 0) {
5876ba597c5SAnurag S. Maskey 		scf_transaction_reset(res->sr_tx);
5886ba597c5SAnurag S. Maskey 		if (scf_pg_update(res->sr_pg) == -1) {
5896ba597c5SAnurag S. Maskey 			goto failure;
5906ba597c5SAnurag S. Maskey 		}
5916ba597c5SAnurag S. Maskey 		nlog(LOG_INFO, "set_property_value: transaction commit failed "
5926ba597c5SAnurag S. Maskey 		    "for %s; retrying", propname);
5936ba597c5SAnurag S. Maskey 		goto retry;
5946ba597c5SAnurag S. Maskey 	}
5956ba597c5SAnurag S. Maskey 	if (result == -1)
5966ba597c5SAnurag S. Maskey 		goto failure;
5976ba597c5SAnurag S. Maskey 	return (0);
5986ba597c5SAnurag S. Maskey 
5996ba597c5SAnurag S. Maskey failure:
6006ba597c5SAnurag S. Maskey 	return (-1);
6016ba597c5SAnurag S. Maskey }
6026ba597c5SAnurag S. Maskey 
6036ba597c5SAnurag S. Maskey int
6046ba597c5SAnurag S. Maskey nwamd_set_count_property(const char *fmri, const char *pg, const char *prop,
6056ba597c5SAnurag S. Maskey     uint64_t count)
6066ba597c5SAnurag S. Maskey {
6076ba597c5SAnurag S. Maskey 	scf_resources_t res;
6086ba597c5SAnurag S. Maskey 
6096ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, &res) != 0)
6106ba597c5SAnurag S. Maskey 		return (-1);
6116ba597c5SAnurag S. Maskey 
6126ba597c5SAnurag S. Maskey 	if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION,
6136ba597c5SAnurag S. Maskey 	    SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) {
6146ba597c5SAnurag S. Maskey 		if (scf_error() != SCF_ERROR_EXISTS)
6156ba597c5SAnurag S. Maskey 			goto failure;
6166ba597c5SAnurag S. Maskey 		if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg,
6176ba597c5SAnurag S. Maskey 		    res.sr_pg) != 0)
6186ba597c5SAnurag S. Maskey 			goto failure;
6196ba597c5SAnurag S. Maskey 	}
6206ba597c5SAnurag S. Maskey 
6216ba597c5SAnurag S. Maskey 	scf_value_set_count(res.sr_val, (uint64_t)count);
6226ba597c5SAnurag S. Maskey 
6236ba597c5SAnurag S. Maskey 	if (set_property_value(&res, prop, SCF_TYPE_COUNT) != 0)
6246ba597c5SAnurag S. Maskey 		goto failure;
6256ba597c5SAnurag S. Maskey 
6266ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
6276ba597c5SAnurag S. Maskey 	return (0);
6286ba597c5SAnurag S. Maskey 
6296ba597c5SAnurag S. Maskey failure:
6306ba597c5SAnurag S. Maskey 	nlog(LOG_INFO, "nwamd_set_count_property: scf failure %s while "
6316ba597c5SAnurag S. Maskey 	    "setting %s", scf_strerror(scf_error()), prop);
6326ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
6336ba597c5SAnurag S. Maskey 	return (-1);
6346ba597c5SAnurag S. Maskey }
6356ba597c5SAnurag S. Maskey 
6366ba597c5SAnurag S. Maskey int
6376ba597c5SAnurag S. Maskey nwamd_set_string_property(const char *fmri, const char *pg, const char *prop,
6386ba597c5SAnurag S. Maskey     const char *str)
6396ba597c5SAnurag S. Maskey {
6406ba597c5SAnurag S. Maskey 	scf_resources_t res;
6416ba597c5SAnurag S. Maskey 
6426ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, &res) != 0)
6436ba597c5SAnurag S. Maskey 		return (-1);
6446ba597c5SAnurag S. Maskey 
6456ba597c5SAnurag S. Maskey 	if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION,
6466ba597c5SAnurag S. Maskey 	    SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) {
6476ba597c5SAnurag S. Maskey 		if (scf_error() != SCF_ERROR_EXISTS)
6486ba597c5SAnurag S. Maskey 			goto failure;
6496ba597c5SAnurag S. Maskey 		if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg,
6506ba597c5SAnurag S. Maskey 		    res.sr_pg) != 0)
6516ba597c5SAnurag S. Maskey 			goto failure;
6526ba597c5SAnurag S. Maskey 	}
6536ba597c5SAnurag S. Maskey 
6546ba597c5SAnurag S. Maskey 	if (scf_value_set_astring(res.sr_val, str) != 0)
6556ba597c5SAnurag S. Maskey 		goto failure;
6566ba597c5SAnurag S. Maskey 
6576ba597c5SAnurag S. Maskey 	if (set_property_value(&res, prop, SCF_TYPE_ASTRING) != 0)
6586ba597c5SAnurag S. Maskey 		goto failure;
6596ba597c5SAnurag S. Maskey 
6606ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
6616ba597c5SAnurag S. Maskey 	return (0);
6626ba597c5SAnurag S. Maskey 
6636ba597c5SAnurag S. Maskey failure:
6646ba597c5SAnurag S. Maskey 	nlog(LOG_INFO, "nwamd_set_string_property: scf failure %s while "
6656ba597c5SAnurag S. Maskey 	    "setting %s", scf_strerror(scf_error()), prop);
6666ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
6676ba597c5SAnurag S. Maskey 	return (-1);
6686ba597c5SAnurag S. Maskey }
6696ba597c5SAnurag S. Maskey 
6706ba597c5SAnurag S. Maskey /*
6716ba597c5SAnurag S. Maskey  * Deletes property prop from property group pg in SMF instance fmri.
6726ba597c5SAnurag S. Maskey  * Returns 0 on success, -1 on failure.
6736ba597c5SAnurag S. Maskey  */
6746ba597c5SAnurag S. Maskey int
6756ba597c5SAnurag S. Maskey nwamd_delete_scf_property(const char *fmri, const char *pg, const char *prop)
6766ba597c5SAnurag S. Maskey {
6776ba597c5SAnurag S. Maskey 	scf_resources_t res;
6786ba597c5SAnurag S. Maskey 	int result = -1;
6796ba597c5SAnurag S. Maskey 
6806ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, &res) != 0)
6816ba597c5SAnurag S. Maskey 		return (-1);
6826ba597c5SAnurag S. Maskey 
6836ba597c5SAnurag S. Maskey 	if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION,
6846ba597c5SAnurag S. Maskey 	    SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) {
6856ba597c5SAnurag S. Maskey 		if (scf_error() != SCF_ERROR_EXISTS)
6866ba597c5SAnurag S. Maskey 			goto failure;
6876ba597c5SAnurag S. Maskey 		if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg,
6886ba597c5SAnurag S. Maskey 		    res.sr_pg) != 0)
6896ba597c5SAnurag S. Maskey 			goto failure;
6906ba597c5SAnurag S. Maskey 	}
6916ba597c5SAnurag S. Maskey 
6926ba597c5SAnurag S. Maskey 	if (scf_pg_get_property(res.sr_pg, prop, res.sr_prop) != 0)
6936ba597c5SAnurag S. Maskey 		goto failure;
6946ba597c5SAnurag S. Maskey retry:
6956ba597c5SAnurag S. Maskey 	if (scf_transaction_start(res.sr_tx, res.sr_pg) == -1)
6966ba597c5SAnurag S. Maskey 		goto failure;
6976ba597c5SAnurag S. Maskey 
6986ba597c5SAnurag S. Maskey 	if (scf_transaction_property_delete(res.sr_tx, res.sr_ent, prop) == -1)
6996ba597c5SAnurag S. Maskey 		goto failure;
7006ba597c5SAnurag S. Maskey 
7016ba597c5SAnurag S. Maskey 	result = scf_transaction_commit(res.sr_tx);
7026ba597c5SAnurag S. Maskey 	if (result == 0) {
7036ba597c5SAnurag S. Maskey 		scf_transaction_reset(res.sr_tx);
7046ba597c5SAnurag S. Maskey 		if (scf_pg_update(res.sr_pg) == -1)
7056ba597c5SAnurag S. Maskey 			goto failure;
7066ba597c5SAnurag S. Maskey 		goto retry;
7076ba597c5SAnurag S. Maskey 	}
7086ba597c5SAnurag S. Maskey 	if (result == -1)
7096ba597c5SAnurag S. Maskey 		goto failure;
7106ba597c5SAnurag S. Maskey 
7116ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
7126ba597c5SAnurag S. Maskey 	return (0);
7136ba597c5SAnurag S. Maskey failure:
7146ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
7156ba597c5SAnurag S. Maskey 	return (-1);
716d71dbb73Sjbeck }
717