xref: /illumos-gate/usr/src/cmd/cmd-inet/lib/nwamd/util.c (revision 6ba597c5)
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*6ba597c5SAnurag S. Maskey  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24d71dbb73Sjbeck  * Use is subject to license terms.
25d71dbb73Sjbeck  */
26d71dbb73Sjbeck 
27d71dbb73Sjbeck /*
28*6ba597c5SAnurag S. Maskey  * util.c contains a set of miscellaneous utility functions which,
29*6ba597c5SAnurag S. Maskey  * among other things:
30d71dbb73Sjbeck  * - start a child process
31d71dbb73Sjbeck  * - look up the zone name
32*6ba597c5SAnurag S. Maskey  * - look up/set SMF properties
33*6ba597c5SAnurag S. Maskey  * - drop/escalate privs
34d71dbb73Sjbeck  */
35d71dbb73Sjbeck 
36*6ba597c5SAnurag S. Maskey #include <assert.h>
37*6ba597c5SAnurag S. Maskey #include <errno.h>
38*6ba597c5SAnurag S. Maskey #include <inetcfg.h>
39*6ba597c5SAnurag S. Maskey #include <libdllink.h>
40*6ba597c5SAnurag S. Maskey #include <limits.h>
41*6ba597c5SAnurag S. Maskey #include <libscf.h>
42*6ba597c5SAnurag S. Maskey #include <net/if.h>
43*6ba597c5SAnurag S. Maskey #include <pthread.h>
44*6ba597c5SAnurag S. Maskey #include <pwd.h>
45*6ba597c5SAnurag S. Maskey #include <spawn.h>
46d71dbb73Sjbeck #include <stdarg.h>
47d71dbb73Sjbeck #include <stdio.h>
48d71dbb73Sjbeck #include <stdlib.h>
49d71dbb73Sjbeck #include <string.h>
50*6ba597c5SAnurag S. Maskey #include <strings.h>
51d71dbb73Sjbeck #include <stropts.h>
52d71dbb73Sjbeck #include <sys/socket.h>
53*6ba597c5SAnurag S. Maskey #include <sys/sockio.h>
54*6ba597c5SAnurag S. Maskey #include <sys/types.h>
55*6ba597c5SAnurag S. Maskey #include <unistd.h>
56d71dbb73Sjbeck #include <wait.h>
57d71dbb73Sjbeck #include <zone.h>
58d71dbb73Sjbeck 
59*6ba597c5SAnurag S. Maskey #include "util.h"
60*6ba597c5SAnurag S. Maskey #include "llp.h"
61d71dbb73Sjbeck 
62d71dbb73Sjbeck extern char **environ;
63*6ba597c5SAnurag S. Maskey extern sigset_t original_sigmask;
64d71dbb73Sjbeck 
65*6ba597c5SAnurag S. Maskey /*
66*6ba597c5SAnurag S. Maskey  * A holder for all the resources needed to get a property value
67*6ba597c5SAnurag S. Maskey  * using libscf.
68*6ba597c5SAnurag S. Maskey  */
69*6ba597c5SAnurag S. Maskey typedef struct scf_resources {
70*6ba597c5SAnurag S. Maskey 	scf_handle_t *sr_handle;
71*6ba597c5SAnurag S. Maskey 	scf_instance_t *sr_inst;
72*6ba597c5SAnurag S. Maskey 	scf_snapshot_t *sr_snap;
73*6ba597c5SAnurag S. Maskey 	scf_propertygroup_t *sr_pg;
74*6ba597c5SAnurag S. Maskey 	scf_property_t *sr_prop;
75*6ba597c5SAnurag S. Maskey 	scf_value_t *sr_val;
76*6ba597c5SAnurag S. Maskey 	scf_transaction_t *sr_tx;
77*6ba597c5SAnurag S. Maskey 	scf_transaction_entry_t *sr_ent;
78*6ba597c5SAnurag S. Maskey } scf_resources_t;
79*6ba597c5SAnurag S. Maskey 
80*6ba597c5SAnurag S. Maskey static pthread_mutex_t uid_mutex = PTHREAD_MUTEX_INITIALIZER;
81*6ba597c5SAnurag S. Maskey static uid_t uid;
82*6ba597c5SAnurag S. Maskey static int uid_cnt;
83d71dbb73Sjbeck 
84*6ba597c5SAnurag S. Maskey void
85*6ba597c5SAnurag S. Maskey nwamd_to_root(void) {
86*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&uid_mutex);
87*6ba597c5SAnurag S. Maskey 	if (uid == 0)
88*6ba597c5SAnurag S. Maskey 		uid = getuid();
89*6ba597c5SAnurag S. Maskey 	if (uid_cnt++ == 0) {
90*6ba597c5SAnurag S. Maskey 		nwamd_escalate_privs();
91*6ba597c5SAnurag S. Maskey 		if (setuid(0) == -1)
92*6ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "setuid(0) failed %s", strerror(errno));
93d71dbb73Sjbeck 	}
94*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&uid_mutex);
95d71dbb73Sjbeck }
96d71dbb73Sjbeck 
97b00044a2SJames Carlson void
98*6ba597c5SAnurag S. Maskey nwamd_from_root(void) {
99*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&uid_mutex);
100*6ba597c5SAnurag S. Maskey 	assert(uid_cnt > 0);
101*6ba597c5SAnurag S. Maskey 	if (--uid_cnt == 0) {
102*6ba597c5SAnurag S. Maskey 		if (setuid(uid) == -1)
103*6ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "setuid(%d) failed %s", uid,
104*6ba597c5SAnurag S. Maskey 			    strerror(errno));
105*6ba597c5SAnurag S. Maskey 		nwamd_drop_unneeded_privs();
106*6ba597c5SAnurag S. Maskey 	}
107*6ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&uid_mutex);
108b00044a2SJames Carlson }
109b00044a2SJames Carlson 
110d71dbb73Sjbeck /*
111d71dbb73Sjbeck  *
112d71dbb73Sjbeck  * This starts a child process determined by command.  If command contains a
113d71dbb73Sjbeck  * slash then it is assumed to be a full path; otherwise the path is searched
114d71dbb73Sjbeck  * for an executable file with the name command.  Command is also used as
115d71dbb73Sjbeck  * argv[0] of the new process.  The rest of the arguments of the function
116d71dbb73Sjbeck  * up to the first NULL make up pointers to arguments of the new process.
117d71dbb73Sjbeck  *
118d71dbb73Sjbeck  * This function returns child exit status on success and -1 on failure.
119d71dbb73Sjbeck  *
120d71dbb73Sjbeck  * NOTE: original_sigmask must be set before this function is called.
121d71dbb73Sjbeck  */
122d71dbb73Sjbeck int
123*6ba597c5SAnurag S. Maskey nwamd_start_childv(const char *command, char const * const *argv)
124d71dbb73Sjbeck {
125d71dbb73Sjbeck 	posix_spawnattr_t attr;
126d71dbb73Sjbeck 	sigset_t fullset;
127d71dbb73Sjbeck 	int i, rc, status, n;
128d71dbb73Sjbeck 	pid_t pid;
129d71dbb73Sjbeck 	char vbuf[1024];
130d71dbb73Sjbeck 
131d71dbb73Sjbeck 	vbuf[0] = 0;
132d71dbb73Sjbeck 	n = sizeof (vbuf);
133d71dbb73Sjbeck 	for (i = 1; argv[i] != NULL && n > 2; i++) {
134d71dbb73Sjbeck 		n -= strlcat(vbuf, " ", n);
135d71dbb73Sjbeck 		n -= strlcat(vbuf, argv[i], n);
136d71dbb73Sjbeck 	}
137d71dbb73Sjbeck 	if (argv[i] != NULL || n < 0)
138*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_start_childv can't log full arg vector");
139d71dbb73Sjbeck 
140d71dbb73Sjbeck 	if ((rc = posix_spawnattr_init(&attr)) != 0) {
141*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "posix_spawnattr_init %d %s\n",
142*6ba597c5SAnurag S. Maskey 		    rc, strerror(rc));
143d71dbb73Sjbeck 		return (-1);
144d71dbb73Sjbeck 	}
145d71dbb73Sjbeck 	(void) sigfillset(&fullset);
146d71dbb73Sjbeck 	if ((rc = posix_spawnattr_setsigdefault(&attr, &fullset)) != 0) {
147*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "setsigdefault %d %s\n", rc, strerror(rc));
148d71dbb73Sjbeck 		return (-1);
149d71dbb73Sjbeck 	}
150d71dbb73Sjbeck 	if ((rc = posix_spawnattr_setsigmask(&attr, &original_sigmask)) != 0) {
151*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "setsigmask %d %s\n", rc, strerror(rc));
152d71dbb73Sjbeck 		return (-1);
153d71dbb73Sjbeck 	}
154d71dbb73Sjbeck 	if ((rc = posix_spawnattr_setflags(&attr,
155d71dbb73Sjbeck 	    POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK)) != 0) {
156*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "setflags %d %s\n", rc, strerror(rc));
157d71dbb73Sjbeck 		return (-1);
158d71dbb73Sjbeck 	}
159d71dbb73Sjbeck 
160d71dbb73Sjbeck 	if ((rc = posix_spawnp(&pid, command, NULL, &attr, (char * const *)argv,
161d71dbb73Sjbeck 	    environ)) > 0) {
162*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "posix_spawnp failed errno %d", rc);
163d71dbb73Sjbeck 		return (-1);
164d71dbb73Sjbeck 	}
165d71dbb73Sjbeck 
166d71dbb73Sjbeck 	if ((rc = posix_spawnattr_destroy(&attr)) != 0) {
167*6ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "posix_spawn_attr_destroy %d %s\n",
168*6ba597c5SAnurag S. Maskey 		    rc, strerror(rc));
169d71dbb73Sjbeck 		return (-1);
170d71dbb73Sjbeck 	}
171d71dbb73Sjbeck 
172d71dbb73Sjbeck 	(void) waitpid(pid, &status, 0);
173d71dbb73Sjbeck 	if (WIFSIGNALED(status) || WIFSTOPPED(status)) {
174d71dbb73Sjbeck 		i = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status);
175*6ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "'%s%s' %s with signal %d (%s)", command, vbuf,
176d71dbb73Sjbeck 		    (WIFSIGNALED(status) ? "terminated" : "stopped"), i,
177d71dbb73Sjbeck 		    strsignal(i));
178d71dbb73Sjbeck 		return (-2);
179d71dbb73Sjbeck 	} else {
180*6ba597c5SAnurag S. Maskey 		nlog(LOG_INFO, "'%s%s' completed normally: %d", command, vbuf,
181d71dbb73Sjbeck 		    WEXITSTATUS(status));
182d71dbb73Sjbeck 		return (WEXITSTATUS(status));
183d71dbb73Sjbeck 	}
184d71dbb73Sjbeck }
185d71dbb73Sjbeck 
186*6ba597c5SAnurag S. Maskey /*
187*6ba597c5SAnurag S. Maskey  * For global zone, check if the link is used by a non-global
188*6ba597c5SAnurag S. Maskey  * zone, note that the non-global zones doesn't need this check,
189*6ba597c5SAnurag S. Maskey  * because zoneadm has taken care of this when the zone boots.
190*6ba597c5SAnurag S. Maskey  * In the global zone, we ignore events for local-zone-owned links
191*6ba597c5SAnurag S. Maskey  * since these are taken care of by the local zone's network
192*6ba597c5SAnurag S. Maskey  * configuration services.
193*6ba597c5SAnurag S. Maskey  */
194*6ba597c5SAnurag S. Maskey boolean_t
195*6ba597c5SAnurag S. Maskey nwamd_link_belongs_to_this_zone(const char *linkname)
196d71dbb73Sjbeck {
197*6ba597c5SAnurag S. Maskey 	zoneid_t zoneid;
198*6ba597c5SAnurag S. Maskey 	char zonename[ZONENAME_MAX];
199*6ba597c5SAnurag S. Maskey 	int ret;
200*6ba597c5SAnurag S. Maskey 
201*6ba597c5SAnurag S. Maskey 	zoneid = getzoneid();
202*6ba597c5SAnurag S. Maskey 	if (zoneid == GLOBAL_ZONEID) {
203*6ba597c5SAnurag S. Maskey 		datalink_id_t linkid;
204*6ba597c5SAnurag S. Maskey 		dladm_status_t status;
205*6ba597c5SAnurag S. Maskey 		char errstr[DLADM_STRSIZE];
206*6ba597c5SAnurag S. Maskey 
207*6ba597c5SAnurag S. Maskey 		if ((status = dladm_name2info(dld_handle, linkname, &linkid,
208*6ba597c5SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
209*6ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: "
210*6ba597c5SAnurag S. Maskey 			    "could not get linkid for %s: %s",
211*6ba597c5SAnurag S. Maskey 			    linkname, dladm_status2str(status, errstr));
212*6ba597c5SAnurag S. Maskey 			return (B_FALSE);
213*6ba597c5SAnurag S. Maskey 		}
214*6ba597c5SAnurag S. Maskey 		zoneid = ALL_ZONES;
215*6ba597c5SAnurag S. Maskey 		ret = zone_check_datalink(&zoneid, linkid);
216*6ba597c5SAnurag S. Maskey 		if (ret == 0) {
217*6ba597c5SAnurag S. Maskey 			(void) getzonenamebyid(zoneid, zonename, ZONENAME_MAX);
218*6ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: "
219*6ba597c5SAnurag S. Maskey 			    "%s is used by non-global zone: %s",
220*6ba597c5SAnurag S. Maskey 			    linkname, zonename);
221*6ba597c5SAnurag S. Maskey 			return (B_FALSE);
222d71dbb73Sjbeck 		}
223*6ba597c5SAnurag S. Maskey 	}
224*6ba597c5SAnurag S. Maskey 	return (B_TRUE);
225*6ba597c5SAnurag S. Maskey }
226d71dbb73Sjbeck 
227*6ba597c5SAnurag S. Maskey void
228*6ba597c5SAnurag S. Maskey nwamd_drop_unneeded_privs(void)
229*6ba597c5SAnurag S. Maskey {
230*6ba597c5SAnurag S. Maskey 	priv_set_t *priv_set, *allpriv_set;
231*6ba597c5SAnurag S. Maskey 
232*6ba597c5SAnurag S. Maskey 	/* build up our minimal set of privs; start with the basic set */
233*6ba597c5SAnurag S. Maskey 	priv_set = priv_str_to_set("basic", ",", NULL);
234*6ba597c5SAnurag S. Maskey 	allpriv_set = priv_str_to_set("zone", ",", NULL);
235*6ba597c5SAnurag S. Maskey 	if (priv_set == NULL || allpriv_set == NULL)
236*6ba597c5SAnurag S. Maskey 		pfail("converting privilege sets: %s", strerror(errno));
237*6ba597c5SAnurag S. Maskey 
238*6ba597c5SAnurag S. Maskey 	(void) priv_addset(priv_set, PRIV_FILE_CHOWN_SELF);
239*6ba597c5SAnurag S. Maskey 	(void) priv_addset(priv_set, PRIV_FILE_DAC_READ);
240*6ba597c5SAnurag S. Maskey 	(void) priv_addset(priv_set, PRIV_FILE_DAC_WRITE);
241*6ba597c5SAnurag S. Maskey 	(void) priv_addset(priv_set, PRIV_NET_RAWACCESS);
242*6ba597c5SAnurag S. Maskey 	(void) priv_addset(priv_set, PRIV_NET_PRIVADDR);
243*6ba597c5SAnurag S. Maskey 	(void) priv_addset(priv_set, PRIV_PROC_AUDIT);
244*6ba597c5SAnurag S. Maskey 	(void) priv_addset(priv_set, PRIV_PROC_OWNER);
245*6ba597c5SAnurag S. Maskey 	(void) priv_addset(priv_set, PRIV_PROC_SETID);
246*6ba597c5SAnurag S. Maskey 	(void) priv_addset(priv_set, PRIV_SYS_CONFIG);
247*6ba597c5SAnurag S. Maskey 	(void) priv_addset(priv_set, PRIV_SYS_IP_CONFIG);
248*6ba597c5SAnurag S. Maskey 	(void) priv_addset(priv_set, PRIV_SYS_IPC_CONFIG);
249*6ba597c5SAnurag S. Maskey 	(void) priv_addset(priv_set, PRIV_SYS_MOUNT);
250*6ba597c5SAnurag S. Maskey 	(void) priv_addset(priv_set, PRIV_SYS_NET_CONFIG);
251*6ba597c5SAnurag S. Maskey 	(void) priv_addset(priv_set, PRIV_SYS_RES_CONFIG);
252*6ba597c5SAnurag S. Maskey 	(void) priv_addset(priv_set, PRIV_SYS_RESOURCE);
253*6ba597c5SAnurag S. Maskey 
254*6ba597c5SAnurag S. Maskey 	/*
255*6ba597c5SAnurag S. Maskey 	 * Since our zone might not have all these privs,
256*6ba597c5SAnurag S. Maskey 	 * just ask for those that are available.
257*6ba597c5SAnurag S. Maskey 	 */
258*6ba597c5SAnurag S. Maskey 	priv_intersect(allpriv_set, priv_set);
259*6ba597c5SAnurag S. Maskey 
260*6ba597c5SAnurag S. Maskey 	if (setppriv(PRIV_SET, PRIV_INHERITABLE, priv_set) == -1) {
261*6ba597c5SAnurag S. Maskey 		priv_freeset(allpriv_set);
262*6ba597c5SAnurag S. Maskey 		priv_freeset(priv_set);
263*6ba597c5SAnurag S. Maskey 		pfail("setppriv inheritable: %s", strerror(errno));
264*6ba597c5SAnurag S. Maskey 	}
265*6ba597c5SAnurag S. Maskey 	/*
266*6ba597c5SAnurag S. Maskey 	 * Need to ensure permitted set contains all privs so we can escalate
267*6ba597c5SAnurag S. Maskey 	 * later.
268*6ba597c5SAnurag S. Maskey 	 */
269*6ba597c5SAnurag S. Maskey 	if (setppriv(PRIV_SET, PRIV_PERMITTED, allpriv_set) == -1) {
270*6ba597c5SAnurag S. Maskey 		priv_freeset(allpriv_set);
271*6ba597c5SAnurag S. Maskey 		priv_freeset(priv_set);
272*6ba597c5SAnurag S. Maskey 		pfail("setppriv permitted: %s", strerror(errno));
273*6ba597c5SAnurag S. Maskey 	}
274*6ba597c5SAnurag S. Maskey 	/*
275*6ba597c5SAnurag S. Maskey 	 * We need to find a smaller set of privs that are important to us.
276*6ba597c5SAnurag S. Maskey 	 * Otherwise we really are not gaining much by doing this.
277*6ba597c5SAnurag S. Maskey 	 */
278*6ba597c5SAnurag S. Maskey 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) {
279*6ba597c5SAnurag S. Maskey 		priv_freeset(allpriv_set);
280*6ba597c5SAnurag S. Maskey 		priv_freeset(priv_set);
281*6ba597c5SAnurag S. Maskey 		pfail("setppriv effective: %s", strerror(errno));
282*6ba597c5SAnurag S. Maskey 	}
283d71dbb73Sjbeck 
284*6ba597c5SAnurag S. Maskey 	priv_freeset(priv_set);
285*6ba597c5SAnurag S. Maskey 	priv_freeset(allpriv_set);
286*6ba597c5SAnurag S. Maskey }
287d71dbb73Sjbeck 
288*6ba597c5SAnurag S. Maskey void
289*6ba597c5SAnurag S. Maskey nwamd_escalate_privs(void)
290*6ba597c5SAnurag S. Maskey {
291*6ba597c5SAnurag S. Maskey 	priv_set_t *priv_set;
292*6ba597c5SAnurag S. Maskey 	priv_set = priv_str_to_set("zone", ",", NULL);
293*6ba597c5SAnurag S. Maskey 	if (priv_set == NULL)
294*6ba597c5SAnurag S. Maskey 		pfail("creating privilege set: %s", strerror(errno));
295*6ba597c5SAnurag S. Maskey 
296*6ba597c5SAnurag S. Maskey 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) {
297*6ba597c5SAnurag S. Maskey 		priv_freeset(priv_set);
298*6ba597c5SAnurag S. Maskey 		pfail("setppriv effective: %s", strerror(errno));
299*6ba597c5SAnurag S. Maskey 	}
300*6ba597c5SAnurag S. Maskey 	priv_freeset(priv_set);
301d71dbb73Sjbeck }
302d71dbb73Sjbeck 
303*6ba597c5SAnurag S. Maskey /*
304*6ba597c5SAnurag S. Maskey  * Inputs:
305*6ba597c5SAnurag S. Maskey  *   res is a pointer to the scf_resources_t to be released.
306*6ba597c5SAnurag S. Maskey  */
307*6ba597c5SAnurag S. Maskey static void
308*6ba597c5SAnurag S. Maskey release_scf_resources(scf_resources_t *res)
309*6ba597c5SAnurag S. Maskey {
310*6ba597c5SAnurag S. Maskey 	scf_entry_destroy(res->sr_ent);
311*6ba597c5SAnurag S. Maskey 	scf_transaction_destroy(res->sr_tx);
312*6ba597c5SAnurag S. Maskey 	scf_value_destroy(res->sr_val);
313*6ba597c5SAnurag S. Maskey 	scf_property_destroy(res->sr_prop);
314*6ba597c5SAnurag S. Maskey 	scf_pg_destroy(res->sr_pg);
315*6ba597c5SAnurag S. Maskey 	scf_snapshot_destroy(res->sr_snap);
316*6ba597c5SAnurag S. Maskey 	scf_instance_destroy(res->sr_inst);
317*6ba597c5SAnurag S. Maskey 	(void) scf_handle_unbind(res->sr_handle);
318*6ba597c5SAnurag S. Maskey 	scf_handle_destroy(res->sr_handle);
319*6ba597c5SAnurag S. Maskey }
320d71dbb73Sjbeck 
321d71dbb73Sjbeck /*
322*6ba597c5SAnurag S. Maskey  * Inputs:
323*6ba597c5SAnurag S. Maskey  *   fmri is the instance to look up
324*6ba597c5SAnurag S. Maskey  * Outputs:
325*6ba597c5SAnurag S. Maskey  *   res is a pointer to an scf_resources_t.  This is an internal
326*6ba597c5SAnurag S. Maskey  *   structure that holds all the handles needed to get a specific
327*6ba597c5SAnurag S. Maskey  *   property from the running snapshot; on a successful return it
328*6ba597c5SAnurag S. Maskey  *   contains the scf_value_t that should be passed to the desired
329*6ba597c5SAnurag S. Maskey  *   scf_value_get_foo() function, and must be freed after use by
330*6ba597c5SAnurag S. Maskey  *   calling release_scf_resources().  On a failure return, any
331*6ba597c5SAnurag S. Maskey  *   resources that may have been assigned to res are released, so
332*6ba597c5SAnurag S. Maskey  *   the caller does not need to do any cleanup in the failure case.
333*6ba597c5SAnurag S. Maskey  * Returns:
334*6ba597c5SAnurag S. Maskey  *    0 on success
335*6ba597c5SAnurag S. Maskey  *   -1 on failure
336d71dbb73Sjbeck  */
337*6ba597c5SAnurag S. Maskey 
338*6ba597c5SAnurag S. Maskey static int
339*6ba597c5SAnurag S. Maskey create_scf_resources(const char *fmri, scf_resources_t *res)
340*6ba597c5SAnurag S. Maskey {
341*6ba597c5SAnurag S. Maskey 	res->sr_tx = NULL;
342*6ba597c5SAnurag S. Maskey 	res->sr_ent = NULL;
343*6ba597c5SAnurag S. Maskey 	res->sr_inst = NULL;
344*6ba597c5SAnurag S. Maskey 	res->sr_snap = NULL;
345*6ba597c5SAnurag S. Maskey 	res->sr_pg = NULL;
346*6ba597c5SAnurag S. Maskey 	res->sr_prop = NULL;
347*6ba597c5SAnurag S. Maskey 	res->sr_val = NULL;
348*6ba597c5SAnurag S. Maskey 
349*6ba597c5SAnurag S. Maskey 	if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL) {
350*6ba597c5SAnurag S. Maskey 		return (-1);
351*6ba597c5SAnurag S. Maskey 	}
352*6ba597c5SAnurag S. Maskey 
353*6ba597c5SAnurag S. Maskey 	if (scf_handle_bind(res->sr_handle) != 0) {
354*6ba597c5SAnurag S. Maskey 		scf_handle_destroy(res->sr_handle);
355*6ba597c5SAnurag S. Maskey 		return (-1);
356*6ba597c5SAnurag S. Maskey 	}
357*6ba597c5SAnurag S. Maskey 	if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL) {
358*6ba597c5SAnurag S. Maskey 		goto failure;
359*6ba597c5SAnurag S. Maskey 	}
360*6ba597c5SAnurag S. Maskey 	if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL,
361*6ba597c5SAnurag S. Maskey 	    res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
362*6ba597c5SAnurag S. Maskey 		goto failure;
363*6ba597c5SAnurag S. Maskey 	}
364*6ba597c5SAnurag S. Maskey 	if ((res->sr_snap = scf_snapshot_create(res->sr_handle)) == NULL) {
365*6ba597c5SAnurag S. Maskey 		goto failure;
366*6ba597c5SAnurag S. Maskey 	}
367*6ba597c5SAnurag S. Maskey 	if (scf_instance_get_snapshot(res->sr_inst, "running",
368*6ba597c5SAnurag S. Maskey 	    res->sr_snap) != 0) {
369*6ba597c5SAnurag S. Maskey 		goto failure;
370*6ba597c5SAnurag S. Maskey 	}
371*6ba597c5SAnurag S. Maskey 	if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
372*6ba597c5SAnurag S. Maskey 		goto failure;
373*6ba597c5SAnurag S. Maskey 	}
374*6ba597c5SAnurag S. Maskey 	if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL) {
375*6ba597c5SAnurag S. Maskey 		goto failure;
376*6ba597c5SAnurag S. Maskey 	}
377*6ba597c5SAnurag S. Maskey 	if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL) {
378*6ba597c5SAnurag S. Maskey 		goto failure;
379*6ba597c5SAnurag S. Maskey 	}
380*6ba597c5SAnurag S. Maskey 	if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL) {
381*6ba597c5SAnurag S. Maskey 		goto failure;
382*6ba597c5SAnurag S. Maskey 	}
383*6ba597c5SAnurag S. Maskey 	if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL) {
384*6ba597c5SAnurag S. Maskey 		goto failure;
385*6ba597c5SAnurag S. Maskey 	}
386*6ba597c5SAnurag S. Maskey 	return (0);
387*6ba597c5SAnurag S. Maskey 
388*6ba597c5SAnurag S. Maskey failure:
389*6ba597c5SAnurag S. Maskey 	nlog(LOG_ERR, "create_scf_resources failed: %s",
390*6ba597c5SAnurag S. Maskey 	    scf_strerror(scf_error()));
391*6ba597c5SAnurag S. Maskey 	release_scf_resources(res);
392*6ba597c5SAnurag S. Maskey 	return (-1);
393*6ba597c5SAnurag S. Maskey }
394*6ba597c5SAnurag S. Maskey 
395*6ba597c5SAnurag S. Maskey /*
396*6ba597c5SAnurag S. Maskey  * Inputs:
397*6ba597c5SAnurag S. Maskey  *   fmri is the instance to look up
398*6ba597c5SAnurag S. Maskey  *   pg is the property group to look up
399*6ba597c5SAnurag S. Maskey  *   prop is the property within that group to look up
400*6ba597c5SAnurag S. Maskey  *   running specifies if running snapshot is to be used
401*6ba597c5SAnurag S. Maskey  * Outputs:
402*6ba597c5SAnurag S. Maskey  *   res is a pointer to an scf_resources_t.  This is an internal
403*6ba597c5SAnurag S. Maskey  *   structure that holds all the handles needed to get a specific
404*6ba597c5SAnurag S. Maskey  *   property from the running snapshot; on a successful return it
405*6ba597c5SAnurag S. Maskey  *   contains the scf_value_t that should be passed to the desired
406*6ba597c5SAnurag S. Maskey  *   scf_value_get_foo() function, and must be freed after use by
407*6ba597c5SAnurag S. Maskey  *   calling release_scf_resources().  On a failure return, any
408*6ba597c5SAnurag S. Maskey  *   resources that may have been assigned to res are released, so
409*6ba597c5SAnurag S. Maskey  *   the caller does not need to do any cleanup in the failure case.
410*6ba597c5SAnurag S. Maskey  * Returns:
411*6ba597c5SAnurag S. Maskey  *    0 on success
412*6ba597c5SAnurag S. Maskey  *   -1 on failure
413*6ba597c5SAnurag S. Maskey  */
414*6ba597c5SAnurag S. Maskey static int
415*6ba597c5SAnurag S. Maskey get_property_value(const char *fmri, const char *pg, const char *prop,
416*6ba597c5SAnurag S. Maskey     boolean_t running, scf_resources_t *res)
417d71dbb73Sjbeck {
418*6ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, res) != 0)
419*6ba597c5SAnurag S. Maskey 		return (-1);
420*6ba597c5SAnurag S. Maskey 
421*6ba597c5SAnurag S. Maskey 	if (scf_instance_get_pg_composed(res->sr_inst,
422*6ba597c5SAnurag S. Maskey 	    running ? res->sr_snap : NULL, pg, res->sr_pg) != 0) {
423*6ba597c5SAnurag S. Maskey 		goto failure;
424*6ba597c5SAnurag S. Maskey 	}
425*6ba597c5SAnurag S. Maskey 	if (scf_pg_get_property(res->sr_pg, prop, res->sr_prop) != 0) {
426*6ba597c5SAnurag S. Maskey 		goto failure;
427*6ba597c5SAnurag S. Maskey 	}
428*6ba597c5SAnurag S. Maskey 	if (scf_property_get_value(res->sr_prop, res->sr_val) != 0) {
429*6ba597c5SAnurag S. Maskey 		goto failure;
430*6ba597c5SAnurag S. Maskey 	}
431*6ba597c5SAnurag S. Maskey 	return (0);
432d71dbb73Sjbeck 
433*6ba597c5SAnurag S. Maskey failure:
434*6ba597c5SAnurag S. Maskey 	release_scf_resources(res);
435*6ba597c5SAnurag S. Maskey 	return (-1);
436d71dbb73Sjbeck }
437d71dbb73Sjbeck 
438*6ba597c5SAnurag S. Maskey /*
439*6ba597c5SAnurag S. Maskey  * Inputs:
440*6ba597c5SAnurag S. Maskey  *   lfmri is the instance fmri to look up
441*6ba597c5SAnurag S. Maskey  *   lpg is the property group to look up
442*6ba597c5SAnurag S. Maskey  *   lprop is the property within that group to look up
443*6ba597c5SAnurag S. Maskey  * Outputs:
444*6ba597c5SAnurag S. Maskey  *   answer is a pointer to the property value
445*6ba597c5SAnurag S. Maskey  * Returns:
446*6ba597c5SAnurag S. Maskey  *    0 on success
447*6ba597c5SAnurag S. Maskey  *   -1 on failure
448*6ba597c5SAnurag S. Maskey  * If successful, the property value is retured in *answer.
449*6ba597c5SAnurag S. Maskey  * Otherwise, *answer is undefined, and it is up to the caller to decide
450*6ba597c5SAnurag S. Maskey  * how to handle that case.
451*6ba597c5SAnurag S. Maskey  */
452*6ba597c5SAnurag S. Maskey int
453*6ba597c5SAnurag S. Maskey nwamd_lookup_boolean_property(const char *lfmri, const char *lpg,
454*6ba597c5SAnurag S. Maskey     const char *lprop, boolean_t *answer)
455*6ba597c5SAnurag S. Maskey {
456*6ba597c5SAnurag S. Maskey 	int result = -1;
457*6ba597c5SAnurag S. Maskey 	scf_resources_t res;
458*6ba597c5SAnurag S. Maskey 	uint8_t prop_val;
459*6ba597c5SAnurag S. Maskey 
460*6ba597c5SAnurag S. Maskey 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
461*6ba597c5SAnurag S. Maskey 
462*6ba597c5SAnurag S. Maskey 		/*
463*6ba597c5SAnurag S. Maskey 		 * an error was already logged by get_property_value,
464*6ba597c5SAnurag S. Maskey 		 * and it released any resources assigned to res before
465*6ba597c5SAnurag S. Maskey 		 * returning.
466*6ba597c5SAnurag S. Maskey 		 */
467*6ba597c5SAnurag S. Maskey 		return (result);
468*6ba597c5SAnurag S. Maskey 	}
469*6ba597c5SAnurag S. Maskey 	if (scf_value_get_boolean(res.sr_val, &prop_val) != 0) {
470*6ba597c5SAnurag S. Maskey 		goto cleanup;
471*6ba597c5SAnurag S. Maskey 	}
472*6ba597c5SAnurag S. Maskey 	*answer = (boolean_t)prop_val;
473*6ba597c5SAnurag S. Maskey 	result = 0;
474*6ba597c5SAnurag S. Maskey cleanup:
475*6ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
476*6ba597c5SAnurag S. Maskey 	return (result);
477*6ba597c5SAnurag S. Maskey }
478*6ba597c5SAnurag S. Maskey 
479*6ba597c5SAnurag S. Maskey /*
480*6ba597c5SAnurag S. Maskey  * Inputs:
481*6ba597c5SAnurag S. Maskey  *   lfmri is the instance fmri to look up
482*6ba597c5SAnurag S. Maskey  *   lpg is the property group to look up
483*6ba597c5SAnurag S. Maskey  *   lprop is the property within that group to look up
484*6ba597c5SAnurag S. Maskey  *   buf is the place to put the answer
485*6ba597c5SAnurag S. Maskey  *   bufsz is the size of buf
486*6ba597c5SAnurag S. Maskey  * Outputs:
487*6ba597c5SAnurag S. Maskey  *
488*6ba597c5SAnurag S. Maskey  * Returns:
489*6ba597c5SAnurag S. Maskey  *    0 on success
490*6ba597c5SAnurag S. Maskey  *   -1 on failure
491*6ba597c5SAnurag S. Maskey  * If successful, the property value is retured in buf.
492*6ba597c5SAnurag S. Maskey  * Otherwise, buf is undefined, and it is up to the caller to decide
493*6ba597c5SAnurag S. Maskey  * how to handle that case.
494*6ba597c5SAnurag S. Maskey  */
495*6ba597c5SAnurag S. Maskey int
496*6ba597c5SAnurag S. Maskey nwamd_lookup_string_property(const char *lfmri, const char *lpg,
497*6ba597c5SAnurag S. Maskey     const char *lprop, char *buf, size_t bufsz)
498d71dbb73Sjbeck {
499*6ba597c5SAnurag S. Maskey 	int result = -1;
500*6ba597c5SAnurag S. Maskey 	scf_resources_t res;
501*6ba597c5SAnurag S. Maskey 
502*6ba597c5SAnurag S. Maskey 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
503*6ba597c5SAnurag S. Maskey 		/*
504*6ba597c5SAnurag S. Maskey 		 * The above function fails when trying to get a
505*6ba597c5SAnurag S. Maskey 		 * non-persistent property group from the running snapshot.
506*6ba597c5SAnurag S. Maskey 		 * Try going for the non-running snapshot.
507*6ba597c5SAnurag S. Maskey 		 */
508*6ba597c5SAnurag S. Maskey 		if (get_property_value(lfmri, lpg, lprop, B_FALSE, &res) != 0) {
509*6ba597c5SAnurag S. Maskey 			/*
510*6ba597c5SAnurag S. Maskey 			 * an error was already logged by get_property_value,
511*6ba597c5SAnurag S. Maskey 			 * and it released any resources assigned to res before
512*6ba597c5SAnurag S. Maskey 			 * returning.
513*6ba597c5SAnurag S. Maskey 			 */
514*6ba597c5SAnurag S. Maskey 			return (result);
515*6ba597c5SAnurag S. Maskey 		}
516*6ba597c5SAnurag S. Maskey 	}
517*6ba597c5SAnurag S. Maskey 	if (scf_value_get_astring(res.sr_val, buf, bufsz) == 0)
518*6ba597c5SAnurag S. Maskey 		goto cleanup;
519*6ba597c5SAnurag S. Maskey 
520*6ba597c5SAnurag S. Maskey 	result = 0;
521*6ba597c5SAnurag S. Maskey cleanup:
522*6ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
523*6ba597c5SAnurag S. Maskey 	return (result);
524*6ba597c5SAnurag S. Maskey }
525d71dbb73Sjbeck 
526*6ba597c5SAnurag S. Maskey /*
527*6ba597c5SAnurag S. Maskey  * Inputs:
528*6ba597c5SAnurag S. Maskey  *   lfmri is the instance fmri to look up
529*6ba597c5SAnurag S. Maskey  *   lpg is the property group to look up
530*6ba597c5SAnurag S. Maskey  *   lprop is the property within that group to look up
531*6ba597c5SAnurag S. Maskey  * Outputs:
532*6ba597c5SAnurag S. Maskey  *   answer is a pointer to the property value
533*6ba597c5SAnurag S. Maskey  * Returns:
534*6ba597c5SAnurag S. Maskey  *    0 on success
535*6ba597c5SAnurag S. Maskey  *   -1 on failure
536*6ba597c5SAnurag S. Maskey  * If successful, the property value is retured in *answer.
537*6ba597c5SAnurag S. Maskey  * Otherwise, *answer is undefined, and it is up to the caller to decide
538*6ba597c5SAnurag S. Maskey  * how to handle that case.
539*6ba597c5SAnurag S. Maskey  */
540*6ba597c5SAnurag S. Maskey int
541*6ba597c5SAnurag S. Maskey nwamd_lookup_count_property(const char *lfmri, const char *lpg,
542*6ba597c5SAnurag S. Maskey     const char *lprop, uint64_t *answer)
543*6ba597c5SAnurag S. Maskey {
544*6ba597c5SAnurag S. Maskey 	int result = -1;
545*6ba597c5SAnurag S. Maskey 	scf_resources_t res;
546*6ba597c5SAnurag S. Maskey 
547*6ba597c5SAnurag S. Maskey 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
548*6ba597c5SAnurag S. Maskey 
549*6ba597c5SAnurag S. Maskey 		/*
550*6ba597c5SAnurag S. Maskey 		 * an error was already logged by get_property_value,
551*6ba597c5SAnurag S. Maskey 		 * and it released any resources assigned to res before
552*6ba597c5SAnurag S. Maskey 		 * returning.
553*6ba597c5SAnurag S. Maskey 		 */
554*6ba597c5SAnurag S. Maskey 		return (result);
555*6ba597c5SAnurag S. Maskey 	}
556*6ba597c5SAnurag S. Maskey 	if (scf_value_get_count(res.sr_val, answer) != 0) {
557*6ba597c5SAnurag S. Maskey 		goto cleanup;
558*6ba597c5SAnurag S. Maskey 	}
559*6ba597c5SAnurag S. Maskey 	result = 0;
560*6ba597c5SAnurag S. Maskey cleanup:
561*6ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
562*6ba597c5SAnurag S. Maskey 	return (result);
563*6ba597c5SAnurag S. Maskey }
564*6ba597c5SAnurag S. Maskey 
565*6ba597c5SAnurag S. Maskey static int
566*6ba597c5SAnurag S. Maskey set_property_value(scf_resources_t *res, const char *propname,
567*6ba597c5SAnurag S. Maskey     scf_type_t proptype)
568*6ba597c5SAnurag S. Maskey {
569*6ba597c5SAnurag S. Maskey 	int result = -1;
570*6ba597c5SAnurag S. Maskey 	boolean_t new;
571*6ba597c5SAnurag S. Maskey 
572*6ba597c5SAnurag S. Maskey retry:
573*6ba597c5SAnurag S. Maskey 	new = (scf_pg_get_property(res->sr_pg, propname, res->sr_prop) != 0);
574*6ba597c5SAnurag S. Maskey 
575*6ba597c5SAnurag S. Maskey 	if (scf_transaction_start(res->sr_tx, res->sr_pg) == -1) {
576*6ba597c5SAnurag S. Maskey 		goto failure;
577*6ba597c5SAnurag S. Maskey 	}
578*6ba597c5SAnurag S. Maskey 	if (new) {
579*6ba597c5SAnurag S. Maskey 		if (scf_transaction_property_new(res->sr_tx, res->sr_ent,
580*6ba597c5SAnurag S. Maskey 		    propname, proptype) == -1) {
581*6ba597c5SAnurag S. Maskey 			goto failure;
582*6ba597c5SAnurag S. Maskey 		}
583*6ba597c5SAnurag S. Maskey 	} else {
584*6ba597c5SAnurag S. Maskey 		if (scf_transaction_property_change(res->sr_tx, res->sr_ent,
585*6ba597c5SAnurag S. Maskey 		    propname, proptype) == -1) {
586*6ba597c5SAnurag S. Maskey 			goto failure;
587*6ba597c5SAnurag S. Maskey 		}
588*6ba597c5SAnurag S. Maskey 	}
589*6ba597c5SAnurag S. Maskey 
590*6ba597c5SAnurag S. Maskey 	if (scf_entry_add_value(res->sr_ent, res->sr_val) != 0) {
591*6ba597c5SAnurag S. Maskey 		goto failure;
592*6ba597c5SAnurag S. Maskey 	}
593*6ba597c5SAnurag S. Maskey 
594*6ba597c5SAnurag S. Maskey 	result = scf_transaction_commit(res->sr_tx);
595*6ba597c5SAnurag S. Maskey 	if (result == 0) {
596*6ba597c5SAnurag S. Maskey 		scf_transaction_reset(res->sr_tx);
597*6ba597c5SAnurag S. Maskey 		if (scf_pg_update(res->sr_pg) == -1) {
598*6ba597c5SAnurag S. Maskey 			goto failure;
599*6ba597c5SAnurag S. Maskey 		}
600*6ba597c5SAnurag S. Maskey 		nlog(LOG_INFO, "set_property_value: transaction commit failed "
601*6ba597c5SAnurag S. Maskey 		    "for %s; retrying", propname);
602*6ba597c5SAnurag S. Maskey 		goto retry;
603*6ba597c5SAnurag S. Maskey 	}
604*6ba597c5SAnurag S. Maskey 	if (result == -1)
605*6ba597c5SAnurag S. Maskey 		goto failure;
606*6ba597c5SAnurag S. Maskey 	return (0);
607*6ba597c5SAnurag S. Maskey 
608*6ba597c5SAnurag S. Maskey failure:
609*6ba597c5SAnurag S. Maskey 	return (-1);
610*6ba597c5SAnurag S. Maskey }
611*6ba597c5SAnurag S. Maskey 
612*6ba597c5SAnurag S. Maskey int
613*6ba597c5SAnurag S. Maskey nwamd_set_count_property(const char *fmri, const char *pg, const char *prop,
614*6ba597c5SAnurag S. Maskey     uint64_t count)
615*6ba597c5SAnurag S. Maskey {
616*6ba597c5SAnurag S. Maskey 	scf_resources_t res;
617*6ba597c5SAnurag S. Maskey 
618*6ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, &res) != 0)
619*6ba597c5SAnurag S. Maskey 		return (-1);
620*6ba597c5SAnurag S. Maskey 
621*6ba597c5SAnurag S. Maskey 	if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION,
622*6ba597c5SAnurag S. Maskey 	    SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) {
623*6ba597c5SAnurag S. Maskey 		if (scf_error() != SCF_ERROR_EXISTS)
624*6ba597c5SAnurag S. Maskey 			goto failure;
625*6ba597c5SAnurag S. Maskey 		if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg,
626*6ba597c5SAnurag S. Maskey 		    res.sr_pg) != 0)
627*6ba597c5SAnurag S. Maskey 			goto failure;
628*6ba597c5SAnurag S. Maskey 	}
629*6ba597c5SAnurag S. Maskey 
630*6ba597c5SAnurag S. Maskey 	scf_value_set_count(res.sr_val, (uint64_t)count);
631*6ba597c5SAnurag S. Maskey 
632*6ba597c5SAnurag S. Maskey 	if (set_property_value(&res, prop, SCF_TYPE_COUNT) != 0)
633*6ba597c5SAnurag S. Maskey 		goto failure;
634*6ba597c5SAnurag S. Maskey 
635*6ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
636*6ba597c5SAnurag S. Maskey 	return (0);
637*6ba597c5SAnurag S. Maskey 
638*6ba597c5SAnurag S. Maskey failure:
639*6ba597c5SAnurag S. Maskey 	nlog(LOG_INFO, "nwamd_set_count_property: scf failure %s while "
640*6ba597c5SAnurag S. Maskey 	    "setting %s", scf_strerror(scf_error()), prop);
641*6ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
642*6ba597c5SAnurag S. Maskey 	return (-1);
643*6ba597c5SAnurag S. Maskey }
644*6ba597c5SAnurag S. Maskey 
645*6ba597c5SAnurag S. Maskey int
646*6ba597c5SAnurag S. Maskey nwamd_set_string_property(const char *fmri, const char *pg, const char *prop,
647*6ba597c5SAnurag S. Maskey     const char *str)
648*6ba597c5SAnurag S. Maskey {
649*6ba597c5SAnurag S. Maskey 	scf_resources_t res;
650*6ba597c5SAnurag S. Maskey 
651*6ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, &res) != 0)
652*6ba597c5SAnurag S. Maskey 		return (-1);
653*6ba597c5SAnurag S. Maskey 
654*6ba597c5SAnurag S. Maskey 	if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION,
655*6ba597c5SAnurag S. Maskey 	    SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) {
656*6ba597c5SAnurag S. Maskey 		if (scf_error() != SCF_ERROR_EXISTS)
657*6ba597c5SAnurag S. Maskey 			goto failure;
658*6ba597c5SAnurag S. Maskey 		if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg,
659*6ba597c5SAnurag S. Maskey 		    res.sr_pg) != 0)
660*6ba597c5SAnurag S. Maskey 			goto failure;
661*6ba597c5SAnurag S. Maskey 	}
662*6ba597c5SAnurag S. Maskey 
663*6ba597c5SAnurag S. Maskey 	if (scf_value_set_astring(res.sr_val, str) != 0)
664*6ba597c5SAnurag S. Maskey 		goto failure;
665*6ba597c5SAnurag S. Maskey 
666*6ba597c5SAnurag S. Maskey 	if (set_property_value(&res, prop, SCF_TYPE_ASTRING) != 0)
667*6ba597c5SAnurag S. Maskey 		goto failure;
668*6ba597c5SAnurag S. Maskey 
669*6ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
670*6ba597c5SAnurag S. Maskey 	return (0);
671*6ba597c5SAnurag S. Maskey 
672*6ba597c5SAnurag S. Maskey failure:
673*6ba597c5SAnurag S. Maskey 	nlog(LOG_INFO, "nwamd_set_string_property: scf failure %s while "
674*6ba597c5SAnurag S. Maskey 	    "setting %s", scf_strerror(scf_error()), prop);
675*6ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
676*6ba597c5SAnurag S. Maskey 	return (-1);
677*6ba597c5SAnurag S. Maskey }
678*6ba597c5SAnurag S. Maskey 
679*6ba597c5SAnurag S. Maskey /*
680*6ba597c5SAnurag S. Maskey  * Deletes property prop from property group pg in SMF instance fmri.
681*6ba597c5SAnurag S. Maskey  * Returns 0 on success, -1 on failure.
682*6ba597c5SAnurag S. Maskey  */
683*6ba597c5SAnurag S. Maskey int
684*6ba597c5SAnurag S. Maskey nwamd_delete_scf_property(const char *fmri, const char *pg, const char *prop)
685*6ba597c5SAnurag S. Maskey {
686*6ba597c5SAnurag S. Maskey 	scf_resources_t res;
687*6ba597c5SAnurag S. Maskey 	int result = -1;
688*6ba597c5SAnurag S. Maskey 
689*6ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, &res) != 0)
690*6ba597c5SAnurag S. Maskey 		return (-1);
691*6ba597c5SAnurag S. Maskey 
692*6ba597c5SAnurag S. Maskey 	if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION,
693*6ba597c5SAnurag S. Maskey 	    SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) {
694*6ba597c5SAnurag S. Maskey 		if (scf_error() != SCF_ERROR_EXISTS)
695*6ba597c5SAnurag S. Maskey 			goto failure;
696*6ba597c5SAnurag S. Maskey 		if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg,
697*6ba597c5SAnurag S. Maskey 		    res.sr_pg) != 0)
698*6ba597c5SAnurag S. Maskey 			goto failure;
699*6ba597c5SAnurag S. Maskey 	}
700*6ba597c5SAnurag S. Maskey 
701*6ba597c5SAnurag S. Maskey 	if (scf_pg_get_property(res.sr_pg, prop, res.sr_prop) != 0)
702*6ba597c5SAnurag S. Maskey 		goto failure;
703*6ba597c5SAnurag S. Maskey retry:
704*6ba597c5SAnurag S. Maskey 	if (scf_transaction_start(res.sr_tx, res.sr_pg) == -1)
705*6ba597c5SAnurag S. Maskey 		goto failure;
706*6ba597c5SAnurag S. Maskey 
707*6ba597c5SAnurag S. Maskey 	if (scf_transaction_property_delete(res.sr_tx, res.sr_ent, prop) == -1)
708*6ba597c5SAnurag S. Maskey 		goto failure;
709*6ba597c5SAnurag S. Maskey 
710*6ba597c5SAnurag S. Maskey 	result = scf_transaction_commit(res.sr_tx);
711*6ba597c5SAnurag S. Maskey 	if (result == 0) {
712*6ba597c5SAnurag S. Maskey 		scf_transaction_reset(res.sr_tx);
713*6ba597c5SAnurag S. Maskey 		if (scf_pg_update(res.sr_pg) == -1)
714*6ba597c5SAnurag S. Maskey 			goto failure;
715*6ba597c5SAnurag S. Maskey 		goto retry;
716*6ba597c5SAnurag S. Maskey 	}
717*6ba597c5SAnurag S. Maskey 	if (result == -1)
718*6ba597c5SAnurag S. Maskey 		goto failure;
719*6ba597c5SAnurag S. Maskey 
720*6ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
721*6ba597c5SAnurag S. Maskey 	return (0);
722*6ba597c5SAnurag S. Maskey failure:
723*6ba597c5SAnurag S. Maskey 	release_scf_resources(&res);
724*6ba597c5SAnurag S. Maskey 	return (-1);
725d71dbb73Sjbeck }
726