1*f6e214c7SGavin Maltby /*
2*f6e214c7SGavin Maltby  * CDDL HEADER START
3*f6e214c7SGavin Maltby  *
4*f6e214c7SGavin Maltby  * The contents of this file are subject to the terms of the
5*f6e214c7SGavin Maltby  * Common Development and Distribution License (the "License").
6*f6e214c7SGavin Maltby  * You may not use this file except in compliance with the License.
7*f6e214c7SGavin Maltby  *
8*f6e214c7SGavin Maltby  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*f6e214c7SGavin Maltby  * or http://www.opensolaris.org/os/licensing.
10*f6e214c7SGavin Maltby  * See the License for the specific language governing permissions
11*f6e214c7SGavin Maltby  * and limitations under the License.
12*f6e214c7SGavin Maltby  *
13*f6e214c7SGavin Maltby  * When distributing Covered Code, include this CDDL HEADER in each
14*f6e214c7SGavin Maltby  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*f6e214c7SGavin Maltby  * If applicable, add the following below this CDDL HEADER, with the
16*f6e214c7SGavin Maltby  * fields enclosed by brackets "[]" replaced with your own identifying
17*f6e214c7SGavin Maltby  * information: Portions Copyright [yyyy] [name of copyright owner]
18*f6e214c7SGavin Maltby  *
19*f6e214c7SGavin Maltby  * CDDL HEADER END
20*f6e214c7SGavin Maltby  */
21*f6e214c7SGavin Maltby 
22*f6e214c7SGavin Maltby /*
23*f6e214c7SGavin Maltby  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24*f6e214c7SGavin Maltby  */
25*f6e214c7SGavin Maltby 
26*f6e214c7SGavin Maltby #include "libscf_impl.h"
27*f6e214c7SGavin Maltby 
28*f6e214c7SGavin Maltby #include <assert.h>
29*f6e214c7SGavin Maltby #include <strings.h>
30*f6e214c7SGavin Maltby 
31*f6e214c7SGavin Maltby /*
32*f6e214c7SGavin Maltby  * Errors returned by smf_notify_{del|get|set}_params()
33*f6e214c7SGavin Maltby  */
34*f6e214c7SGavin Maltby static const scf_error_t errs_1[] = {
35*f6e214c7SGavin Maltby 	SCF_ERROR_BACKEND_ACCESS,
36*f6e214c7SGavin Maltby 	SCF_ERROR_BACKEND_READONLY,
37*f6e214c7SGavin Maltby 	SCF_ERROR_CONNECTION_BROKEN,
38*f6e214c7SGavin Maltby 	SCF_ERROR_DELETED,
39*f6e214c7SGavin Maltby 	SCF_ERROR_INTERNAL,
40*f6e214c7SGavin Maltby 	SCF_ERROR_INVALID_ARGUMENT,
41*f6e214c7SGavin Maltby 	SCF_ERROR_NO_MEMORY,
42*f6e214c7SGavin Maltby 	SCF_ERROR_NO_RESOURCES,
43*f6e214c7SGavin Maltby 	SCF_ERROR_NOT_FOUND,
44*f6e214c7SGavin Maltby 	SCF_ERROR_PERMISSION_DENIED,
45*f6e214c7SGavin Maltby 	0
46*f6e214c7SGavin Maltby };
47*f6e214c7SGavin Maltby 
48*f6e214c7SGavin Maltby /*
49*f6e214c7SGavin Maltby  * Errors returned by smf_notify_{del|get|set}_params()
50*f6e214c7SGavin Maltby  * Except SCF_ERROR_INVALID_ARGUMENT
51*f6e214c7SGavin Maltby  */
52*f6e214c7SGavin Maltby static const scf_error_t errs_2[] = {
53*f6e214c7SGavin Maltby 	SCF_ERROR_BACKEND_ACCESS,
54*f6e214c7SGavin Maltby 	SCF_ERROR_BACKEND_READONLY,
55*f6e214c7SGavin Maltby 	SCF_ERROR_CONNECTION_BROKEN,
56*f6e214c7SGavin Maltby 	SCF_ERROR_DELETED,
57*f6e214c7SGavin Maltby 	SCF_ERROR_INTERNAL,
58*f6e214c7SGavin Maltby 	SCF_ERROR_NO_MEMORY,
59*f6e214c7SGavin Maltby 	SCF_ERROR_NO_RESOURCES,
60*f6e214c7SGavin Maltby 	SCF_ERROR_NOT_FOUND,
61*f6e214c7SGavin Maltby 	SCF_ERROR_PERMISSION_DENIED,
62*f6e214c7SGavin Maltby 	0
63*f6e214c7SGavin Maltby };
64*f6e214c7SGavin Maltby 
65*f6e214c7SGavin Maltby /*
66*f6e214c7SGavin Maltby  * Helper function that abort() on unexpected errors.
67*f6e214c7SGavin Maltby  * The expected error set is a zero-terminated array of scf_error_t
68*f6e214c7SGavin Maltby  */
69*f6e214c7SGavin Maltby static int
70*f6e214c7SGavin Maltby check_scf_error(scf_error_t e, const scf_error_t *errs)
71*f6e214c7SGavin Maltby {
72*f6e214c7SGavin Maltby 	if (ismember(e, errs))
73*f6e214c7SGavin Maltby 		return (1);
74*f6e214c7SGavin Maltby 
75*f6e214c7SGavin Maltby 	assert(0);
76*f6e214c7SGavin Maltby 	abort();
77*f6e214c7SGavin Maltby 
78*f6e214c7SGavin Maltby 	/*NOTREACHED*/
79*f6e214c7SGavin Maltby }
80*f6e214c7SGavin Maltby 
81*f6e214c7SGavin Maltby /*
82*f6e214c7SGavin Maltby  * Mapping of state transition to pgname.
83*f6e214c7SGavin Maltby  */
84*f6e214c7SGavin Maltby static struct st_pgname {
85*f6e214c7SGavin Maltby 	const char	*st_pgname;
86*f6e214c7SGavin Maltby 	int32_t		st_state;
87*f6e214c7SGavin Maltby } st_pgnames[] = {
88*f6e214c7SGavin Maltby 	{ "to-uninitialized", SCF_TRANS(0, SCF_STATE_UNINIT) },
89*f6e214c7SGavin Maltby 	{ "from-uninitialized", SCF_TRANS(SCF_STATE_UNINIT, 0) },
90*f6e214c7SGavin Maltby 	{ "to-maintenance", SCF_TRANS(0, SCF_STATE_MAINT) },
91*f6e214c7SGavin Maltby 	{ "from-maintenance", SCF_TRANS(SCF_STATE_MAINT, 0) },
92*f6e214c7SGavin Maltby 	{ "to-offline", SCF_TRANS(0, SCF_STATE_OFFLINE) },
93*f6e214c7SGavin Maltby 	{ "from-offline", SCF_TRANS(SCF_STATE_OFFLINE, 0) },
94*f6e214c7SGavin Maltby 	{ "to-disabled", SCF_TRANS(0, SCF_STATE_DISABLED) },
95*f6e214c7SGavin Maltby 	{ "from-disabled", SCF_TRANS(SCF_STATE_DISABLED, 0) },
96*f6e214c7SGavin Maltby 	{ "to-online", SCF_TRANS(0, SCF_STATE_ONLINE) },
97*f6e214c7SGavin Maltby 	{ "from-online", SCF_TRANS(SCF_STATE_ONLINE, 0) },
98*f6e214c7SGavin Maltby 	{ "to-degraded", SCF_TRANS(0, SCF_STATE_DEGRADED) },
99*f6e214c7SGavin Maltby 	{ "from-degraded", SCF_TRANS(SCF_STATE_DEGRADED, 0) },
100*f6e214c7SGavin Maltby 	{ NULL, 0 }
101*f6e214c7SGavin Maltby };
102*f6e214c7SGavin Maltby 
103*f6e214c7SGavin Maltby /*
104*f6e214c7SGavin Maltby  * Check if class matches or is a subclass of SCF_SVC_TRANSITION_CLASS
105*f6e214c7SGavin Maltby  *
106*f6e214c7SGavin Maltby  * returns 1, otherwise return 0
107*f6e214c7SGavin Maltby  */
108*f6e214c7SGavin Maltby static boolean_t
109*f6e214c7SGavin Maltby is_svc_stn(const char *class)
110*f6e214c7SGavin Maltby {
111*f6e214c7SGavin Maltby 	int n = strlen(SCF_SVC_TRANSITION_CLASS);
112*f6e214c7SGavin Maltby 
113*f6e214c7SGavin Maltby 	if (class && strncmp(class, SCF_SVC_TRANSITION_CLASS, n) == 0)
114*f6e214c7SGavin Maltby 		if (class[n] == '\0' || class[n] == '.')
115*f6e214c7SGavin Maltby 			return (1);
116*f6e214c7SGavin Maltby 	return (0);
117*f6e214c7SGavin Maltby }
118*f6e214c7SGavin Maltby 
119*f6e214c7SGavin Maltby /*
120*f6e214c7SGavin Maltby  * Return the len of the base class. For instance, "class.class1.class2.*"
121*f6e214c7SGavin Maltby  * will return the length of "class.class1.class2"
122*f6e214c7SGavin Maltby  * This function does not check if the class or base class is valid.
123*f6e214c7SGavin Maltby  * A class such as "class.class1....****" is not valid but will return the
124*f6e214c7SGavin Maltby  * length of "class.class1....***"
125*f6e214c7SGavin Maltby  */
126*f6e214c7SGavin Maltby static size_t
127*f6e214c7SGavin Maltby base_class_len(const char *c)
128*f6e214c7SGavin Maltby {
129*f6e214c7SGavin Maltby 	const char *p;
130*f6e214c7SGavin Maltby 	size_t n;
131*f6e214c7SGavin Maltby 
132*f6e214c7SGavin Maltby 	if ((n = strlen(c)) == 0)
133*f6e214c7SGavin Maltby 		return (0);
134*f6e214c7SGavin Maltby 
135*f6e214c7SGavin Maltby 	p = c + n;
136*f6e214c7SGavin Maltby 
137*f6e214c7SGavin Maltby 	/* get rid of any trailing asterisk */
138*f6e214c7SGavin Maltby 	if (*--p == '*')
139*f6e214c7SGavin Maltby 		n--;
140*f6e214c7SGavin Maltby 
141*f6e214c7SGavin Maltby 	/* make sure the class doesn't end in '.' */
142*f6e214c7SGavin Maltby 	while (p >= c && *--p == '.')
143*f6e214c7SGavin Maltby 		n--;
144*f6e214c7SGavin Maltby 
145*f6e214c7SGavin Maltby 	return (n);
146*f6e214c7SGavin Maltby }
147*f6e214c7SGavin Maltby 
148*f6e214c7SGavin Maltby /*
149*f6e214c7SGavin Maltby  * Allocates and builds the pgname for an FMA dotted class.
150*f6e214c7SGavin Maltby  * The pgname will be of the form "class.class1.class2,SCF_NOTIFY_PG_POSTFIX"
151*f6e214c7SGavin Maltby  *
152*f6e214c7SGavin Maltby  * NULL on error
153*f6e214c7SGavin Maltby  */
154*f6e214c7SGavin Maltby static char *
155*f6e214c7SGavin Maltby class_to_pgname(const char *class)
156*f6e214c7SGavin Maltby {
157*f6e214c7SGavin Maltby 	size_t n;
158*f6e214c7SGavin Maltby 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
159*f6e214c7SGavin Maltby 	char *pgname = NULL;
160*f6e214c7SGavin Maltby 
161*f6e214c7SGavin Maltby 	n = base_class_len(class);
162*f6e214c7SGavin Maltby 
163*f6e214c7SGavin Maltby 	if (n == 0) {
164*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
165*f6e214c7SGavin Maltby 		return (NULL);
166*f6e214c7SGavin Maltby 	}
167*f6e214c7SGavin Maltby 
168*f6e214c7SGavin Maltby 	if ((pgname = malloc(sz)) == NULL) {
169*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
170*f6e214c7SGavin Maltby 		goto error;
171*f6e214c7SGavin Maltby 	}
172*f6e214c7SGavin Maltby 
173*f6e214c7SGavin Maltby 	if (snprintf(pgname, sz, "%.*s,%s", (int)n, class,
174*f6e214c7SGavin Maltby 	    SCF_NOTIFY_PG_POSTFIX) >= sz) {
175*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
176*f6e214c7SGavin Maltby 		goto error;
177*f6e214c7SGavin Maltby 	}
178*f6e214c7SGavin Maltby 	return (pgname);
179*f6e214c7SGavin Maltby 
180*f6e214c7SGavin Maltby error:
181*f6e214c7SGavin Maltby 	free(pgname);
182*f6e214c7SGavin Maltby 	pgname = NULL;
183*f6e214c7SGavin Maltby 
184*f6e214c7SGavin Maltby 	return (pgname);
185*f6e214c7SGavin Maltby }
186*f6e214c7SGavin Maltby 
187*f6e214c7SGavin Maltby /*
188*f6e214c7SGavin Maltby  * Get the pg from the running snapshot of the instance (composed or not)
189*f6e214c7SGavin Maltby  */
190*f6e214c7SGavin Maltby static int
191*f6e214c7SGavin Maltby get_pg(scf_service_t *s, scf_instance_t *i, const char *n,
192*f6e214c7SGavin Maltby     scf_propertygroup_t *pg, int composed)
193*f6e214c7SGavin Maltby {
194*f6e214c7SGavin Maltby 	scf_handle_t	*h = scf_instance_handle(i);
195*f6e214c7SGavin Maltby 	scf_error_t	scf_e = scf_error();
196*f6e214c7SGavin Maltby 	scf_snapshot_t	*snap = scf_snapshot_create(h);
197*f6e214c7SGavin Maltby 	scf_snaplevel_t	*slvl = scf_snaplevel_create(h);
198*f6e214c7SGavin Maltby 	int r = -1;
199*f6e214c7SGavin Maltby 
200*f6e214c7SGavin Maltby 	if (h == NULL) {
201*f6e214c7SGavin Maltby 		/*
202*f6e214c7SGavin Maltby 		 * Use the error stored in scf_e
203*f6e214c7SGavin Maltby 		 */
204*f6e214c7SGavin Maltby 		(void) scf_set_error(scf_e);
205*f6e214c7SGavin Maltby 		goto out;
206*f6e214c7SGavin Maltby 	}
207*f6e214c7SGavin Maltby 	if (s == NULL) {
208*f6e214c7SGavin Maltby 		if (snap == NULL || slvl == NULL)
209*f6e214c7SGavin Maltby 			goto out;
210*f6e214c7SGavin Maltby 		if (scf_instance_get_snapshot(i, "running", snap) != 0)
211*f6e214c7SGavin Maltby 			goto out;
212*f6e214c7SGavin Maltby 
213*f6e214c7SGavin Maltby 		if (composed) {
214*f6e214c7SGavin Maltby 			if (scf_instance_get_pg_composed(i, snap, n, pg) != 0)
215*f6e214c7SGavin Maltby 				goto out;
216*f6e214c7SGavin Maltby 		} else {
217*f6e214c7SGavin Maltby 			if (scf_snapshot_get_base_snaplevel(snap, slvl) != 0 ||
218*f6e214c7SGavin Maltby 			    scf_snaplevel_get_pg(slvl, n, pg) != 0)
219*f6e214c7SGavin Maltby 				goto out;
220*f6e214c7SGavin Maltby 		}
221*f6e214c7SGavin Maltby 	} else {
222*f6e214c7SGavin Maltby 		if (scf_service_get_pg(s, n, pg) != 0)
223*f6e214c7SGavin Maltby 			goto out;
224*f6e214c7SGavin Maltby 	}
225*f6e214c7SGavin Maltby 
226*f6e214c7SGavin Maltby 	r = 0;
227*f6e214c7SGavin Maltby out:
228*f6e214c7SGavin Maltby 	scf_snaplevel_destroy(slvl);
229*f6e214c7SGavin Maltby 	scf_snapshot_destroy(snap);
230*f6e214c7SGavin Maltby 
231*f6e214c7SGavin Maltby 	return (r);
232*f6e214c7SGavin Maltby }
233*f6e214c7SGavin Maltby 
234*f6e214c7SGavin Maltby /*
235*f6e214c7SGavin Maltby  * Add a pg if it does not exist, or get it if it exists.
236*f6e214c7SGavin Maltby  * It operates on the instance if the service parameter is NULL.
237*f6e214c7SGavin Maltby  *
238*f6e214c7SGavin Maltby  * returns 0 on success or -1 on failure
239*f6e214c7SGavin Maltby  */
240*f6e214c7SGavin Maltby static int
241*f6e214c7SGavin Maltby get_or_add_pg(scf_service_t *s, scf_instance_t *i, const char *n, const char *t,
242*f6e214c7SGavin Maltby     uint32_t flags, scf_propertygroup_t *pg)
243*f6e214c7SGavin Maltby {
244*f6e214c7SGavin Maltby 	int r;
245*f6e214c7SGavin Maltby 
246*f6e214c7SGavin Maltby 	if (s == NULL)
247*f6e214c7SGavin Maltby 		r = scf_instance_add_pg(i, n, t, flags, pg);
248*f6e214c7SGavin Maltby 	else
249*f6e214c7SGavin Maltby 		r = scf_service_add_pg(s, n, t, flags, pg);
250*f6e214c7SGavin Maltby 
251*f6e214c7SGavin Maltby 	if (r == 0)
252*f6e214c7SGavin Maltby 		return (0);
253*f6e214c7SGavin Maltby 	else if (scf_error() != SCF_ERROR_EXISTS)
254*f6e214c7SGavin Maltby 		return (-1);
255*f6e214c7SGavin Maltby 
256*f6e214c7SGavin Maltby 	if (s == NULL)
257*f6e214c7SGavin Maltby 		r = scf_instance_get_pg(i, n, pg);
258*f6e214c7SGavin Maltby 	else
259*f6e214c7SGavin Maltby 		r = scf_service_get_pg(s, n, pg);
260*f6e214c7SGavin Maltby 
261*f6e214c7SGavin Maltby 	return (r);
262*f6e214c7SGavin Maltby }
263*f6e214c7SGavin Maltby 
264*f6e214c7SGavin Maltby /*
265*f6e214c7SGavin Maltby  * Delete the property group form the instance or service.
266*f6e214c7SGavin Maltby  * If service is NULL, use instance, otherwise use only the service.
267*f6e214c7SGavin Maltby  *
268*f6e214c7SGavin Maltby  * Return SCF_SUCCESS or SCF_FAILED on
269*f6e214c7SGavin Maltby  * 	SCF_ERROR_BACKEND_ACCESS
270*f6e214c7SGavin Maltby  * 	SCF_ERROR_BACKEND_READONLY
271*f6e214c7SGavin Maltby  * 	SCF_ERROR_CONNECTION_BROKEN
272*f6e214c7SGavin Maltby  * 	SCF_ERROR_DELETED
273*f6e214c7SGavin Maltby  * 	SCF_ERROR_HANDLE_MISMATCH
274*f6e214c7SGavin Maltby  * 	SCF_ERROR_INTERNAL
275*f6e214c7SGavin Maltby  * 	SCF_ERROR_INVALID_ARGUMENT
276*f6e214c7SGavin Maltby  * 	SCF_ERROR_NO_RESOURCES
277*f6e214c7SGavin Maltby  * 	SCF_ERROR_NOT_BOUND
278*f6e214c7SGavin Maltby  * 	SCF_ERROR_NOT_FOUND
279*f6e214c7SGavin Maltby  * 	SCF_ERROR_NOT_SET
280*f6e214c7SGavin Maltby  * 	SCF_ERROR_PERMISSION_DENIED
281*f6e214c7SGavin Maltby  */
282*f6e214c7SGavin Maltby static int
283*f6e214c7SGavin Maltby del_pg(scf_service_t *s, scf_instance_t *i, const char *n,
284*f6e214c7SGavin Maltby     scf_propertygroup_t *pg)
285*f6e214c7SGavin Maltby {
286*f6e214c7SGavin Maltby 	if ((s == NULL ? scf_instance_get_pg(i, n, pg) :
287*f6e214c7SGavin Maltby 	    scf_service_get_pg(s, n, pg)) != SCF_SUCCESS)
288*f6e214c7SGavin Maltby 		if (scf_error() == SCF_ERROR_NOT_FOUND)
289*f6e214c7SGavin Maltby 			return (SCF_SUCCESS);
290*f6e214c7SGavin Maltby 		else
291*f6e214c7SGavin Maltby 			return (SCF_FAILED);
292*f6e214c7SGavin Maltby 
293*f6e214c7SGavin Maltby 	if (scf_pg_delete(pg) != SCF_SUCCESS)
294*f6e214c7SGavin Maltby 		if (scf_error() == SCF_ERROR_DELETED)
295*f6e214c7SGavin Maltby 			return (SCF_SUCCESS);
296*f6e214c7SGavin Maltby 		else
297*f6e214c7SGavin Maltby 			return (SCF_FAILED);
298*f6e214c7SGavin Maltby 
299*f6e214c7SGavin Maltby 	return (SCF_SUCCESS);
300*f6e214c7SGavin Maltby }
301*f6e214c7SGavin Maltby 
302*f6e214c7SGavin Maltby static scf_type_t
303*f6e214c7SGavin Maltby get_scf_type(nvpair_t *p)
304*f6e214c7SGavin Maltby {
305*f6e214c7SGavin Maltby 	switch (nvpair_type(p)) {
306*f6e214c7SGavin Maltby 	case DATA_TYPE_BOOLEAN:
307*f6e214c7SGavin Maltby 	case DATA_TYPE_BOOLEAN_VALUE:
308*f6e214c7SGavin Maltby 	case DATA_TYPE_BOOLEAN_ARRAY:
309*f6e214c7SGavin Maltby 		return (SCF_TYPE_BOOLEAN);
310*f6e214c7SGavin Maltby 
311*f6e214c7SGavin Maltby 	case DATA_TYPE_BYTE:
312*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT8:
313*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT16:
314*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT32:
315*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT64:
316*f6e214c7SGavin Maltby 	case DATA_TYPE_BYTE_ARRAY:
317*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT8_ARRAY:
318*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT16_ARRAY:
319*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT32_ARRAY:
320*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT64_ARRAY:
321*f6e214c7SGavin Maltby 		return (SCF_TYPE_COUNT);
322*f6e214c7SGavin Maltby 
323*f6e214c7SGavin Maltby 	case DATA_TYPE_INT8:
324*f6e214c7SGavin Maltby 	case DATA_TYPE_INT16:
325*f6e214c7SGavin Maltby 	case DATA_TYPE_INT32:
326*f6e214c7SGavin Maltby 	case DATA_TYPE_INT64:
327*f6e214c7SGavin Maltby 	case DATA_TYPE_INT8_ARRAY:
328*f6e214c7SGavin Maltby 	case DATA_TYPE_INT16_ARRAY:
329*f6e214c7SGavin Maltby 	case DATA_TYPE_INT32_ARRAY:
330*f6e214c7SGavin Maltby 	case DATA_TYPE_INT64_ARRAY:
331*f6e214c7SGavin Maltby 		return (SCF_TYPE_INTEGER);
332*f6e214c7SGavin Maltby 
333*f6e214c7SGavin Maltby 	case DATA_TYPE_STRING:
334*f6e214c7SGavin Maltby 	case DATA_TYPE_STRING_ARRAY:
335*f6e214c7SGavin Maltby 		return (SCF_TYPE_ASTRING);
336*f6e214c7SGavin Maltby 
337*f6e214c7SGavin Maltby 	default:
338*f6e214c7SGavin Maltby 		return (SCF_TYPE_INVALID);
339*f6e214c7SGavin Maltby 	}
340*f6e214c7SGavin Maltby }
341*f6e214c7SGavin Maltby 
342*f6e214c7SGavin Maltby static int
343*f6e214c7SGavin Maltby add_entry(scf_transaction_entry_t *te, scf_value_t *val)
344*f6e214c7SGavin Maltby {
345*f6e214c7SGavin Maltby 	if (scf_entry_add_value(te, val) != 0) {
346*f6e214c7SGavin Maltby 		scf_value_destroy(val);
347*f6e214c7SGavin Maltby 		return (SCF_FAILED);
348*f6e214c7SGavin Maltby 	}
349*f6e214c7SGavin Maltby 
350*f6e214c7SGavin Maltby 	return (SCF_SUCCESS);
351*f6e214c7SGavin Maltby }
352*f6e214c7SGavin Maltby 
353*f6e214c7SGavin Maltby static int
354*f6e214c7SGavin Maltby add_boolean_entry(scf_handle_t *h, scf_transaction_entry_t *te, uint8_t v)
355*f6e214c7SGavin Maltby {
356*f6e214c7SGavin Maltby 	scf_value_t *val = scf_value_create(h);
357*f6e214c7SGavin Maltby 
358*f6e214c7SGavin Maltby 	if (val == NULL)
359*f6e214c7SGavin Maltby 		return (SCF_FAILED);
360*f6e214c7SGavin Maltby 
361*f6e214c7SGavin Maltby 	scf_value_set_boolean(val, v);
362*f6e214c7SGavin Maltby 
363*f6e214c7SGavin Maltby 	return (add_entry(te, val));
364*f6e214c7SGavin Maltby }
365*f6e214c7SGavin Maltby 
366*f6e214c7SGavin Maltby static int
367*f6e214c7SGavin Maltby add_count_entry(scf_handle_t *h, scf_transaction_entry_t *te, uint64_t v)
368*f6e214c7SGavin Maltby {
369*f6e214c7SGavin Maltby 	scf_value_t *val = scf_value_create(h);
370*f6e214c7SGavin Maltby 
371*f6e214c7SGavin Maltby 	if (val == NULL)
372*f6e214c7SGavin Maltby 		return (SCF_FAILED);
373*f6e214c7SGavin Maltby 
374*f6e214c7SGavin Maltby 	scf_value_set_count(val, v);
375*f6e214c7SGavin Maltby 
376*f6e214c7SGavin Maltby 	return (add_entry(te, val));
377*f6e214c7SGavin Maltby }
378*f6e214c7SGavin Maltby 
379*f6e214c7SGavin Maltby static int
380*f6e214c7SGavin Maltby add_integer_entry(scf_handle_t *h, scf_transaction_entry_t *te, int64_t v)
381*f6e214c7SGavin Maltby {
382*f6e214c7SGavin Maltby 	scf_value_t *val = scf_value_create(h);
383*f6e214c7SGavin Maltby 
384*f6e214c7SGavin Maltby 	if (val == NULL)
385*f6e214c7SGavin Maltby 		return (SCF_FAILED);
386*f6e214c7SGavin Maltby 
387*f6e214c7SGavin Maltby 	scf_value_set_integer(val, v);
388*f6e214c7SGavin Maltby 
389*f6e214c7SGavin Maltby 	return (add_entry(te, val));
390*f6e214c7SGavin Maltby }
391*f6e214c7SGavin Maltby 
392*f6e214c7SGavin Maltby static int
393*f6e214c7SGavin Maltby add_astring_entry(scf_handle_t *h, scf_transaction_entry_t *te, char *s)
394*f6e214c7SGavin Maltby {
395*f6e214c7SGavin Maltby 	scf_value_t *val = scf_value_create(h);
396*f6e214c7SGavin Maltby 
397*f6e214c7SGavin Maltby 	if (val == NULL)
398*f6e214c7SGavin Maltby 		return (SCF_FAILED);
399*f6e214c7SGavin Maltby 
400*f6e214c7SGavin Maltby 	if (scf_value_set_astring(val, s) != 0) {
401*f6e214c7SGavin Maltby 		scf_value_destroy(val);
402*f6e214c7SGavin Maltby 		return (SCF_FAILED);
403*f6e214c7SGavin Maltby 	}
404*f6e214c7SGavin Maltby 
405*f6e214c7SGavin Maltby 	return (add_entry(te, val));
406*f6e214c7SGavin Maltby }
407*f6e214c7SGavin Maltby 
408*f6e214c7SGavin Maltby static int
409*f6e214c7SGavin Maltby get_nvpair_vals(scf_handle_t *h, scf_transaction_entry_t *te, nvpair_t *p)
410*f6e214c7SGavin Maltby {
411*f6e214c7SGavin Maltby 	scf_value_t *val = scf_value_create(h);
412*f6e214c7SGavin Maltby 	uint_t n = 1;
413*f6e214c7SGavin Maltby 	int i;
414*f6e214c7SGavin Maltby 
415*f6e214c7SGavin Maltby 	if (val == NULL)
416*f6e214c7SGavin Maltby 		return (SCF_FAILED);
417*f6e214c7SGavin Maltby 
418*f6e214c7SGavin Maltby 	switch (nvpair_type(p)) {
419*f6e214c7SGavin Maltby 	case DATA_TYPE_BOOLEAN:
420*f6e214c7SGavin Maltby 		return (add_boolean_entry(h, te, 1));
421*f6e214c7SGavin Maltby 	case DATA_TYPE_BOOLEAN_VALUE:
422*f6e214c7SGavin Maltby 		{
423*f6e214c7SGavin Maltby 			boolean_t v;
424*f6e214c7SGavin Maltby 
425*f6e214c7SGavin Maltby 			(void) nvpair_value_boolean_value(p, &v);
426*f6e214c7SGavin Maltby 			return (add_boolean_entry(h, te, (uint8_t)v));
427*f6e214c7SGavin Maltby 		}
428*f6e214c7SGavin Maltby 	case DATA_TYPE_BOOLEAN_ARRAY:
429*f6e214c7SGavin Maltby 		{
430*f6e214c7SGavin Maltby 			boolean_t *v;
431*f6e214c7SGavin Maltby 
432*f6e214c7SGavin Maltby 			(void) nvpair_value_boolean_array(p, &v, &n);
433*f6e214c7SGavin Maltby 			for (i = 0; i < n; ++i) {
434*f6e214c7SGavin Maltby 				if (add_boolean_entry(h, te, (uint8_t)v[i]) !=
435*f6e214c7SGavin Maltby 				    SCF_SUCCESS)
436*f6e214c7SGavin Maltby 					return (SCF_FAILED);
437*f6e214c7SGavin Maltby 			}
438*f6e214c7SGavin Maltby 			return (SCF_SUCCESS);
439*f6e214c7SGavin Maltby 		}
440*f6e214c7SGavin Maltby 	case DATA_TYPE_BYTE:
441*f6e214c7SGavin Maltby 		{
442*f6e214c7SGavin Maltby 			uchar_t v;
443*f6e214c7SGavin Maltby 
444*f6e214c7SGavin Maltby 			(void) nvpair_value_byte(p, &v);
445*f6e214c7SGavin Maltby 			return (add_count_entry(h, te, v));
446*f6e214c7SGavin Maltby 		}
447*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT8:
448*f6e214c7SGavin Maltby 		{
449*f6e214c7SGavin Maltby 			uint8_t v;
450*f6e214c7SGavin Maltby 
451*f6e214c7SGavin Maltby 			(void) nvpair_value_uint8(p, &v);
452*f6e214c7SGavin Maltby 			return (add_count_entry(h, te, v));
453*f6e214c7SGavin Maltby 		}
454*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT16:
455*f6e214c7SGavin Maltby 		{
456*f6e214c7SGavin Maltby 			uint16_t v;
457*f6e214c7SGavin Maltby 
458*f6e214c7SGavin Maltby 			(void) nvpair_value_uint16(p, &v);
459*f6e214c7SGavin Maltby 			return (add_count_entry(h, te, v));
460*f6e214c7SGavin Maltby 		}
461*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT32:
462*f6e214c7SGavin Maltby 		{
463*f6e214c7SGavin Maltby 			uint32_t v;
464*f6e214c7SGavin Maltby 
465*f6e214c7SGavin Maltby 			(void) nvpair_value_uint32(p, &v);
466*f6e214c7SGavin Maltby 			return (add_count_entry(h, te, v));
467*f6e214c7SGavin Maltby 		}
468*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT64:
469*f6e214c7SGavin Maltby 		{
470*f6e214c7SGavin Maltby 			uint64_t v;
471*f6e214c7SGavin Maltby 
472*f6e214c7SGavin Maltby 			(void) nvpair_value_uint64(p, &v);
473*f6e214c7SGavin Maltby 			return (add_count_entry(h, te, v));
474*f6e214c7SGavin Maltby 		}
475*f6e214c7SGavin Maltby 	case DATA_TYPE_BYTE_ARRAY:
476*f6e214c7SGavin Maltby 		{
477*f6e214c7SGavin Maltby 			uchar_t *v;
478*f6e214c7SGavin Maltby 
479*f6e214c7SGavin Maltby 			(void) nvpair_value_byte_array(p, &v, &n);
480*f6e214c7SGavin Maltby 			for (i = 0; i < n; ++i) {
481*f6e214c7SGavin Maltby 				if (add_count_entry(h, te, v[i]) != SCF_SUCCESS)
482*f6e214c7SGavin Maltby 					return (SCF_FAILED);
483*f6e214c7SGavin Maltby 			}
484*f6e214c7SGavin Maltby 			return (SCF_SUCCESS);
485*f6e214c7SGavin Maltby 		}
486*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT8_ARRAY:
487*f6e214c7SGavin Maltby 		{
488*f6e214c7SGavin Maltby 			uint8_t *v;
489*f6e214c7SGavin Maltby 
490*f6e214c7SGavin Maltby 			(void) nvpair_value_uint8_array(p, &v, &n);
491*f6e214c7SGavin Maltby 			for (i = 0; i < n; ++i) {
492*f6e214c7SGavin Maltby 				if (add_count_entry(h, te, v[i]) != SCF_SUCCESS)
493*f6e214c7SGavin Maltby 					return (SCF_FAILED);
494*f6e214c7SGavin Maltby 			}
495*f6e214c7SGavin Maltby 			return (SCF_SUCCESS);
496*f6e214c7SGavin Maltby 		}
497*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT16_ARRAY:
498*f6e214c7SGavin Maltby 		{
499*f6e214c7SGavin Maltby 			uint16_t *v;
500*f6e214c7SGavin Maltby 
501*f6e214c7SGavin Maltby 			(void) nvpair_value_uint16_array(p, &v, &n);
502*f6e214c7SGavin Maltby 			for (i = 0; i < n; ++i) {
503*f6e214c7SGavin Maltby 				if (add_count_entry(h, te, v[i]) != SCF_SUCCESS)
504*f6e214c7SGavin Maltby 					return (SCF_FAILED);
505*f6e214c7SGavin Maltby 			}
506*f6e214c7SGavin Maltby 			return (SCF_SUCCESS);
507*f6e214c7SGavin Maltby 		}
508*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT32_ARRAY:
509*f6e214c7SGavin Maltby 		{
510*f6e214c7SGavin Maltby 			uint32_t *v;
511*f6e214c7SGavin Maltby 
512*f6e214c7SGavin Maltby 			(void) nvpair_value_uint32_array(p, &v, &n);
513*f6e214c7SGavin Maltby 			for (i = 0; i < n; ++i) {
514*f6e214c7SGavin Maltby 				if (add_count_entry(h, te, v[i]) != SCF_SUCCESS)
515*f6e214c7SGavin Maltby 					return (SCF_FAILED);
516*f6e214c7SGavin Maltby 			}
517*f6e214c7SGavin Maltby 			return (SCF_SUCCESS);
518*f6e214c7SGavin Maltby 		}
519*f6e214c7SGavin Maltby 	case DATA_TYPE_UINT64_ARRAY:
520*f6e214c7SGavin Maltby 		{
521*f6e214c7SGavin Maltby 			uint64_t *v;
522*f6e214c7SGavin Maltby 
523*f6e214c7SGavin Maltby 			(void) nvpair_value_uint64_array(p, &v, &n);
524*f6e214c7SGavin Maltby 			for (i = 0; i < n; ++i) {
525*f6e214c7SGavin Maltby 				if (add_count_entry(h, te, v[i]) != SCF_SUCCESS)
526*f6e214c7SGavin Maltby 					return (SCF_FAILED);
527*f6e214c7SGavin Maltby 			}
528*f6e214c7SGavin Maltby 			return (SCF_SUCCESS);
529*f6e214c7SGavin Maltby 		}
530*f6e214c7SGavin Maltby 	case DATA_TYPE_INT8:
531*f6e214c7SGavin Maltby 		{
532*f6e214c7SGavin Maltby 			int8_t v;
533*f6e214c7SGavin Maltby 
534*f6e214c7SGavin Maltby 			(void) nvpair_value_int8(p, &v);
535*f6e214c7SGavin Maltby 			return (add_integer_entry(h, te, v));
536*f6e214c7SGavin Maltby 		}
537*f6e214c7SGavin Maltby 	case DATA_TYPE_INT16:
538*f6e214c7SGavin Maltby 		{
539*f6e214c7SGavin Maltby 			int16_t v;
540*f6e214c7SGavin Maltby 
541*f6e214c7SGavin Maltby 			(void) nvpair_value_int16(p, &v);
542*f6e214c7SGavin Maltby 			return (add_integer_entry(h, te, v));
543*f6e214c7SGavin Maltby 		}
544*f6e214c7SGavin Maltby 	case DATA_TYPE_INT32:
545*f6e214c7SGavin Maltby 		{
546*f6e214c7SGavin Maltby 			int32_t v;
547*f6e214c7SGavin Maltby 
548*f6e214c7SGavin Maltby 			(void) nvpair_value_int32(p, &v);
549*f6e214c7SGavin Maltby 			return (add_integer_entry(h, te, v));
550*f6e214c7SGavin Maltby 		}
551*f6e214c7SGavin Maltby 	case DATA_TYPE_INT64:
552*f6e214c7SGavin Maltby 		{
553*f6e214c7SGavin Maltby 			int64_t v;
554*f6e214c7SGavin Maltby 
555*f6e214c7SGavin Maltby 			(void) nvpair_value_int64(p, &v);
556*f6e214c7SGavin Maltby 			return (add_integer_entry(h, te, v));
557*f6e214c7SGavin Maltby 		}
558*f6e214c7SGavin Maltby 	case DATA_TYPE_INT8_ARRAY:
559*f6e214c7SGavin Maltby 		{
560*f6e214c7SGavin Maltby 			int8_t *v;
561*f6e214c7SGavin Maltby 
562*f6e214c7SGavin Maltby 			(void) nvpair_value_int8_array(p, &v, &n);
563*f6e214c7SGavin Maltby 			for (i = 0; i < n; ++i) {
564*f6e214c7SGavin Maltby 				if (add_integer_entry(h, te, v[i]) !=
565*f6e214c7SGavin Maltby 				    SCF_SUCCESS)
566*f6e214c7SGavin Maltby 					return (SCF_FAILED);
567*f6e214c7SGavin Maltby 			}
568*f6e214c7SGavin Maltby 			return (SCF_SUCCESS);
569*f6e214c7SGavin Maltby 		}
570*f6e214c7SGavin Maltby 	case DATA_TYPE_INT16_ARRAY:
571*f6e214c7SGavin Maltby 		{
572*f6e214c7SGavin Maltby 			int16_t *v;
573*f6e214c7SGavin Maltby 
574*f6e214c7SGavin Maltby 			(void) nvpair_value_int16_array(p, &v, &n);
575*f6e214c7SGavin Maltby 			for (i = 0; i < n; ++i) {
576*f6e214c7SGavin Maltby 				if (add_integer_entry(h, te, v[i]) !=
577*f6e214c7SGavin Maltby 				    SCF_SUCCESS)
578*f6e214c7SGavin Maltby 					return (SCF_FAILED);
579*f6e214c7SGavin Maltby 			}
580*f6e214c7SGavin Maltby 			return (SCF_SUCCESS);
581*f6e214c7SGavin Maltby 		}
582*f6e214c7SGavin Maltby 	case DATA_TYPE_INT32_ARRAY:
583*f6e214c7SGavin Maltby 		{
584*f6e214c7SGavin Maltby 			int32_t *v;
585*f6e214c7SGavin Maltby 
586*f6e214c7SGavin Maltby 			(void) nvpair_value_int32_array(p, &v, &n);
587*f6e214c7SGavin Maltby 			for (i = 0; i < n; ++i) {
588*f6e214c7SGavin Maltby 				if (add_integer_entry(h, te, v[i]) !=
589*f6e214c7SGavin Maltby 				    SCF_SUCCESS)
590*f6e214c7SGavin Maltby 					return (SCF_FAILED);
591*f6e214c7SGavin Maltby 			}
592*f6e214c7SGavin Maltby 			return (SCF_SUCCESS);
593*f6e214c7SGavin Maltby 		}
594*f6e214c7SGavin Maltby 	case DATA_TYPE_INT64_ARRAY:
595*f6e214c7SGavin Maltby 		{
596*f6e214c7SGavin Maltby 			int64_t *v;
597*f6e214c7SGavin Maltby 
598*f6e214c7SGavin Maltby 			(void) nvpair_value_int64_array(p, &v, &n);
599*f6e214c7SGavin Maltby 			for (i = 0; i < n; ++i) {
600*f6e214c7SGavin Maltby 				if (add_integer_entry(h, te, v[i]) !=
601*f6e214c7SGavin Maltby 				    SCF_SUCCESS)
602*f6e214c7SGavin Maltby 					return (SCF_FAILED);
603*f6e214c7SGavin Maltby 			}
604*f6e214c7SGavin Maltby 			return (SCF_SUCCESS);
605*f6e214c7SGavin Maltby 		}
606*f6e214c7SGavin Maltby 	case DATA_TYPE_STRING:
607*f6e214c7SGavin Maltby 		{
608*f6e214c7SGavin Maltby 			char *str;
609*f6e214c7SGavin Maltby 
610*f6e214c7SGavin Maltby 			(void) nvpair_value_string(p, &str);
611*f6e214c7SGavin Maltby 			return (add_astring_entry(h, te, str));
612*f6e214c7SGavin Maltby 		}
613*f6e214c7SGavin Maltby 	case DATA_TYPE_STRING_ARRAY:
614*f6e214c7SGavin Maltby 		{
615*f6e214c7SGavin Maltby 			char **v;
616*f6e214c7SGavin Maltby 
617*f6e214c7SGavin Maltby 			(void) nvpair_value_string_array(p, &v, &n);
618*f6e214c7SGavin Maltby 			for (i = 0; i < n; ++i) {
619*f6e214c7SGavin Maltby 				if (add_astring_entry(h, te, v[i]) !=
620*f6e214c7SGavin Maltby 				    SCF_SUCCESS)
621*f6e214c7SGavin Maltby 					return (SCF_FAILED);
622*f6e214c7SGavin Maltby 			}
623*f6e214c7SGavin Maltby 			return (SCF_SUCCESS);
624*f6e214c7SGavin Maltby 		}
625*f6e214c7SGavin Maltby 	default:
626*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
627*f6e214c7SGavin Maltby 		return (SCF_FAILED);
628*f6e214c7SGavin Maltby 	}
629*f6e214c7SGavin Maltby 
630*f6e214c7SGavin Maltby 	/*NOTREACHED*/
631*f6e214c7SGavin Maltby }
632*f6e214c7SGavin Maltby 
633*f6e214c7SGavin Maltby /*
634*f6e214c7SGavin Maltby  * Add new transaction entry to scf_transaction_t
635*f6e214c7SGavin Maltby  *
636*f6e214c7SGavin Maltby  * Can fail with
637*f6e214c7SGavin Maltby  *	SCF_ERROR_BACKEND_ACCESS
638*f6e214c7SGavin Maltby  *	SCF_ERROR_CONNECTION_BROKEN
639*f6e214c7SGavin Maltby  *	SCF_ERROR_DELETED
640*f6e214c7SGavin Maltby  *	SCF_ERROR_INTERNAL
641*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_RESOURCES
642*f6e214c7SGavin Maltby  *	SCF_ERROR_NOT_FOUND
643*f6e214c7SGavin Maltby  */
644*f6e214c7SGavin Maltby static int
645*f6e214c7SGavin Maltby prep_transaction(scf_transaction_t *tx, scf_transaction_entry_t *te,
646*f6e214c7SGavin Maltby     const char *prop, scf_type_t type)
647*f6e214c7SGavin Maltby {
648*f6e214c7SGavin Maltby 	if (scf_transaction_property_new(tx, te, prop, type) != SCF_SUCCESS &&
649*f6e214c7SGavin Maltby 	    (scf_error() != SCF_ERROR_EXISTS ||
650*f6e214c7SGavin Maltby 	    scf_transaction_property_change(tx, te, prop, type) !=
651*f6e214c7SGavin Maltby 	    SCF_SUCCESS)) {
652*f6e214c7SGavin Maltby 		if (check_scf_error(scf_error(), errs_2)) {
653*f6e214c7SGavin Maltby 			return (SCF_FAILED);
654*f6e214c7SGavin Maltby 		}
655*f6e214c7SGavin Maltby 	}
656*f6e214c7SGavin Maltby 
657*f6e214c7SGavin Maltby 	return (SCF_SUCCESS);
658*f6e214c7SGavin Maltby }
659*f6e214c7SGavin Maltby 
660*f6e214c7SGavin Maltby /*
661*f6e214c7SGavin Maltby  * notify_set_params()
662*f6e214c7SGavin Maltby  * returns 0 on success or -1 on failure
663*f6e214c7SGavin Maltby  *	SCF_ERROR_BACKEND_ACCESS
664*f6e214c7SGavin Maltby  *	SCF_ERROR_BACKEND_READONLY
665*f6e214c7SGavin Maltby  *	SCF_ERROR_CONNECTION_BROKEN
666*f6e214c7SGavin Maltby  *	SCF_ERROR_DELETED
667*f6e214c7SGavin Maltby  *	SCF_ERROR_INTERNAL
668*f6e214c7SGavin Maltby  *	SCF_ERROR_INVALID_ARGUMENT
669*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_MEMORY
670*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_RESOURCES
671*f6e214c7SGavin Maltby  *	SCF_ERROR_NOT_FOUND
672*f6e214c7SGavin Maltby  *	SCF_ERROR_PERMISSION_DENIED
673*f6e214c7SGavin Maltby  */
674*f6e214c7SGavin Maltby static int
675*f6e214c7SGavin Maltby notify_set_params(scf_propertygroup_t *pg, nvlist_t *params)
676*f6e214c7SGavin Maltby {
677*f6e214c7SGavin Maltby 	scf_handle_t		*h = scf_pg_handle(pg);
678*f6e214c7SGavin Maltby 	scf_error_t		scf_e = scf_error();
679*f6e214c7SGavin Maltby 	scf_transaction_t	*tx = scf_transaction_create(h);
680*f6e214c7SGavin Maltby 	int	bufsz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
681*f6e214c7SGavin Maltby 	char	*propname = malloc(bufsz);
682*f6e214c7SGavin Maltby 	int	r = -1;
683*f6e214c7SGavin Maltby 	int	err;
684*f6e214c7SGavin Maltby 
685*f6e214c7SGavin Maltby 	if (h == NULL) {
686*f6e214c7SGavin Maltby 		/*
687*f6e214c7SGavin Maltby 		 * Use the error stored in scf_e
688*f6e214c7SGavin Maltby 		 */
689*f6e214c7SGavin Maltby 		(void) scf_set_error(scf_e);
690*f6e214c7SGavin Maltby 		goto cleanup;
691*f6e214c7SGavin Maltby 	}
692*f6e214c7SGavin Maltby 	if (tx == NULL)
693*f6e214c7SGavin Maltby 		goto cleanup;
694*f6e214c7SGavin Maltby 
695*f6e214c7SGavin Maltby 	if (propname == NULL) {
696*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
697*f6e214c7SGavin Maltby 		goto cleanup;
698*f6e214c7SGavin Maltby 	}
699*f6e214c7SGavin Maltby 
700*f6e214c7SGavin Maltby 	do {
701*f6e214c7SGavin Maltby 		nvpair_t *nvp;
702*f6e214c7SGavin Maltby 
703*f6e214c7SGavin Maltby 		/*
704*f6e214c7SGavin Maltby 		 * make sure we have the most recent version of the pg
705*f6e214c7SGavin Maltby 		 * start the transaction
706*f6e214c7SGavin Maltby 		 */
707*f6e214c7SGavin Maltby 		if (scf_pg_update(pg) == SCF_FAILED ||
708*f6e214c7SGavin Maltby 		    scf_transaction_start(tx, pg) != SCF_SUCCESS) {
709*f6e214c7SGavin Maltby 			if (check_scf_error(scf_error(), errs_2)) {
710*f6e214c7SGavin Maltby 				goto cleanup;
711*f6e214c7SGavin Maltby 			}
712*f6e214c7SGavin Maltby 		}
713*f6e214c7SGavin Maltby 
714*f6e214c7SGavin Maltby 		for (nvp = nvlist_next_nvpair(params, NULL); nvp != NULL;
715*f6e214c7SGavin Maltby 		    nvp = nvlist_next_nvpair(params, nvp)) {
716*f6e214c7SGavin Maltby 			nvlist_t	*m;
717*f6e214c7SGavin Maltby 			nvpair_t	*p;
718*f6e214c7SGavin Maltby 
719*f6e214c7SGavin Maltby 			/* we ONLY take nvlists here */
720*f6e214c7SGavin Maltby 			if (nvpair_type(nvp) != DATA_TYPE_NVLIST) {
721*f6e214c7SGavin Maltby 				char *name = nvpair_name(nvp);
722*f6e214c7SGavin Maltby 
723*f6e214c7SGavin Maltby 				/*
724*f6e214c7SGavin Maltby 				 * if this is output from
725*f6e214c7SGavin Maltby 				 * smf_notify_get_params() we want to skip
726*f6e214c7SGavin Maltby 				 * the tset value of the nvlist
727*f6e214c7SGavin Maltby 				 */
728*f6e214c7SGavin Maltby 				if (strcmp(name, SCF_NOTIFY_NAME_TSET) == 0)
729*f6e214c7SGavin Maltby 					continue;
730*f6e214c7SGavin Maltby 
731*f6e214c7SGavin Maltby 				(void) scf_set_error(
732*f6e214c7SGavin Maltby 				    SCF_ERROR_INVALID_ARGUMENT);
733*f6e214c7SGavin Maltby 				goto cleanup;
734*f6e214c7SGavin Maltby 			}
735*f6e214c7SGavin Maltby 
736*f6e214c7SGavin Maltby 			if (nvpair_value_nvlist(nvp, &m) != 0) {
737*f6e214c7SGavin Maltby 				(void) scf_set_error(
738*f6e214c7SGavin Maltby 				    SCF_ERROR_INVALID_ARGUMENT);
739*f6e214c7SGavin Maltby 				goto cleanup;
740*f6e214c7SGavin Maltby 			}
741*f6e214c7SGavin Maltby 
742*f6e214c7SGavin Maltby 			/*
743*f6e214c7SGavin Maltby 			 * Traverse each mechanism list
744*f6e214c7SGavin Maltby 			 */
745*f6e214c7SGavin Maltby 			for (p = nvlist_next_nvpair(m, NULL); p != NULL;
746*f6e214c7SGavin Maltby 			    p = nvlist_next_nvpair(m, p)) {
747*f6e214c7SGavin Maltby 				scf_transaction_entry_t *te =
748*f6e214c7SGavin Maltby 				    scf_entry_create(h);
749*f6e214c7SGavin Maltby 				/* map the nvpair type to scf type */
750*f6e214c7SGavin Maltby 				scf_type_t type = get_scf_type(p);
751*f6e214c7SGavin Maltby 
752*f6e214c7SGavin Maltby 				if (te == NULL) {
753*f6e214c7SGavin Maltby 					if (scf_error() !=
754*f6e214c7SGavin Maltby 					    SCF_ERROR_INVALID_ARGUMENT) {
755*f6e214c7SGavin Maltby 						scf_entry_destroy(te);
756*f6e214c7SGavin Maltby 						goto cleanup;
757*f6e214c7SGavin Maltby 					} else {
758*f6e214c7SGavin Maltby 						assert(0);
759*f6e214c7SGavin Maltby 						abort();
760*f6e214c7SGavin Maltby 					}
761*f6e214c7SGavin Maltby 				}
762*f6e214c7SGavin Maltby 
763*f6e214c7SGavin Maltby 				if (type == SCF_TYPE_INVALID) {
764*f6e214c7SGavin Maltby 					(void) scf_set_error(
765*f6e214c7SGavin Maltby 					    SCF_ERROR_INVALID_ARGUMENT);
766*f6e214c7SGavin Maltby 					scf_entry_destroy(te);
767*f6e214c7SGavin Maltby 					goto cleanup;
768*f6e214c7SGavin Maltby 				}
769*f6e214c7SGavin Maltby 
770*f6e214c7SGavin Maltby 				if (snprintf(propname, bufsz, "%s,%s",
771*f6e214c7SGavin Maltby 				    nvpair_name(nvp), nvpair_name(p)) >=
772*f6e214c7SGavin Maltby 				    bufsz) {
773*f6e214c7SGavin Maltby 					(void) scf_set_error(
774*f6e214c7SGavin Maltby 					    SCF_ERROR_INVALID_ARGUMENT);
775*f6e214c7SGavin Maltby 					scf_entry_destroy(te);
776*f6e214c7SGavin Maltby 					goto cleanup;
777*f6e214c7SGavin Maltby 				}
778*f6e214c7SGavin Maltby 
779*f6e214c7SGavin Maltby 				if (prep_transaction(tx, te, propname, type) !=
780*f6e214c7SGavin Maltby 				    SCF_SUCCESS) {
781*f6e214c7SGavin Maltby 					scf_entry_destroy(te);
782*f6e214c7SGavin Maltby 					goto cleanup;
783*f6e214c7SGavin Maltby 				}
784*f6e214c7SGavin Maltby 
785*f6e214c7SGavin Maltby 				if (get_nvpair_vals(h, te, p) != SCF_SUCCESS) {
786*f6e214c7SGavin Maltby 					if (check_scf_error(scf_error(),
787*f6e214c7SGavin Maltby 					    errs_2)) {
788*f6e214c7SGavin Maltby 						goto cleanup;
789*f6e214c7SGavin Maltby 					}
790*f6e214c7SGavin Maltby 				}
791*f6e214c7SGavin Maltby 			}
792*f6e214c7SGavin Maltby 		}
793*f6e214c7SGavin Maltby 		err = scf_transaction_commit(tx);
794*f6e214c7SGavin Maltby 		scf_transaction_destroy_children(tx);
795*f6e214c7SGavin Maltby 	} while (err == 0);
796*f6e214c7SGavin Maltby 
797*f6e214c7SGavin Maltby 	if (err == -1) {
798*f6e214c7SGavin Maltby 		if (check_scf_error(scf_error(), errs_2)) {
799*f6e214c7SGavin Maltby 			goto cleanup;
800*f6e214c7SGavin Maltby 		}
801*f6e214c7SGavin Maltby 	}
802*f6e214c7SGavin Maltby 
803*f6e214c7SGavin Maltby 	r = 0;
804*f6e214c7SGavin Maltby 
805*f6e214c7SGavin Maltby cleanup:
806*f6e214c7SGavin Maltby 	scf_transaction_destroy_children(tx);
807*f6e214c7SGavin Maltby 	scf_transaction_destroy(tx);
808*f6e214c7SGavin Maltby 	free(propname);
809*f6e214c7SGavin Maltby 
810*f6e214c7SGavin Maltby 	return (r);
811*f6e214c7SGavin Maltby }
812*f6e214c7SGavin Maltby 
813*f6e214c7SGavin Maltby /*
814*f6e214c7SGavin Maltby  * Decode fmri. Populates service OR instance depending on which one is an
815*f6e214c7SGavin Maltby  * exact match to the fmri parameter.
816*f6e214c7SGavin Maltby  *
817*f6e214c7SGavin Maltby  * The function destroys and sets the unused entity (service or instance) to
818*f6e214c7SGavin Maltby  * NULL.
819*f6e214c7SGavin Maltby  *
820*f6e214c7SGavin Maltby  * return SCF_SUCCESS or SCF_FAILED on
821*f6e214c7SGavin Maltby  * 	SCF_ERROR_BACKEND_ACCESS
822*f6e214c7SGavin Maltby  * 	SCF_ERROR_CONNECTION_BROKEN
823*f6e214c7SGavin Maltby  * 	SCF_ERROR_CONSTRAINT_VIOLATED
824*f6e214c7SGavin Maltby  * 	SCF_ERROR_DELETED
825*f6e214c7SGavin Maltby  * 	SCF_ERROR_HANDLE_MISMATCH
826*f6e214c7SGavin Maltby  * 	SCF_ERROR_INTERNAL
827*f6e214c7SGavin Maltby  * 	SCF_ERROR_INVALID_ARGUMENT
828*f6e214c7SGavin Maltby  * 	SCF_ERROR_NO_RESOURCES
829*f6e214c7SGavin Maltby  * 	SCF_ERROR_NOT_BOUND
830*f6e214c7SGavin Maltby  * 	SCF_ERROR_NOT_FOUND
831*f6e214c7SGavin Maltby  * 	SCF_ERROR_NOT_SET
832*f6e214c7SGavin Maltby  */
833*f6e214c7SGavin Maltby static int
834*f6e214c7SGavin Maltby decode_fmri(const char *fmri, scf_handle_t *h, scf_service_t **s,
835*f6e214c7SGavin Maltby     scf_instance_t **i)
836*f6e214c7SGavin Maltby {
837*f6e214c7SGavin Maltby 	if (scf_handle_decode_fmri(h, fmri, NULL, *s, NULL, NULL, NULL,
838*f6e214c7SGavin Maltby 	    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
839*f6e214c7SGavin Maltby 		if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
840*f6e214c7SGavin Maltby 			scf_service_destroy(*s);
841*f6e214c7SGavin Maltby 			*s = NULL;
842*f6e214c7SGavin Maltby 		} else {
843*f6e214c7SGavin Maltby 			return (SCF_FAILED);
844*f6e214c7SGavin Maltby 		}
845*f6e214c7SGavin Maltby 	}
846*f6e214c7SGavin Maltby 	if (*s == NULL)
847*f6e214c7SGavin Maltby 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, *i,
848*f6e214c7SGavin Maltby 		    NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
849*f6e214c7SGavin Maltby 			return (SCF_FAILED);
850*f6e214c7SGavin Maltby 	}
851*f6e214c7SGavin Maltby 
852*f6e214c7SGavin Maltby 	return (SCF_SUCCESS);
853*f6e214c7SGavin Maltby }
854*f6e214c7SGavin Maltby 
855*f6e214c7SGavin Maltby /*
856*f6e214c7SGavin Maltby  * Return size in bytes for an SCF_TYPE_*. Not all libscf types are supported
857*f6e214c7SGavin Maltby  */
858*f6e214c7SGavin Maltby static int
859*f6e214c7SGavin Maltby get_type_size(scf_type_t t)
860*f6e214c7SGavin Maltby {
861*f6e214c7SGavin Maltby 	switch (t) {
862*f6e214c7SGavin Maltby 	case SCF_TYPE_BOOLEAN:
863*f6e214c7SGavin Maltby 		return (sizeof (uint8_t));
864*f6e214c7SGavin Maltby 	case SCF_TYPE_COUNT:
865*f6e214c7SGavin Maltby 		return (sizeof (uint64_t));
866*f6e214c7SGavin Maltby 	case SCF_TYPE_INTEGER:
867*f6e214c7SGavin Maltby 		return (sizeof (int64_t));
868*f6e214c7SGavin Maltby 	case SCF_TYPE_ASTRING:
869*f6e214c7SGavin Maltby 	case SCF_TYPE_USTRING:
870*f6e214c7SGavin Maltby 		return (sizeof (void *));
871*f6e214c7SGavin Maltby 	default:
872*f6e214c7SGavin Maltby 		return (-1);
873*f6e214c7SGavin Maltby 	}
874*f6e214c7SGavin Maltby 
875*f6e214c7SGavin Maltby 	/*NOTREACHED*/
876*f6e214c7SGavin Maltby }
877*f6e214c7SGavin Maltby 
878*f6e214c7SGavin Maltby /*
879*f6e214c7SGavin Maltby  * Return a pointer to the array of values according to its type
880*f6e214c7SGavin Maltby  */
881*f6e214c7SGavin Maltby static void **
882*f6e214c7SGavin Maltby get_v_pointer(scf_values_t *v)
883*f6e214c7SGavin Maltby {
884*f6e214c7SGavin Maltby 	switch (v->value_type) {
885*f6e214c7SGavin Maltby 	case SCF_TYPE_BOOLEAN:
886*f6e214c7SGavin Maltby 		return ((void **)&v->values.v_boolean);
887*f6e214c7SGavin Maltby 	case SCF_TYPE_COUNT:
888*f6e214c7SGavin Maltby 		return ((void **)&v->values.v_count);
889*f6e214c7SGavin Maltby 	case SCF_TYPE_INTEGER:
890*f6e214c7SGavin Maltby 		return ((void **)&v->values.v_integer);
891*f6e214c7SGavin Maltby 	case SCF_TYPE_ASTRING:
892*f6e214c7SGavin Maltby 		return ((void **)&v->values.v_astring);
893*f6e214c7SGavin Maltby 	case SCF_TYPE_USTRING:
894*f6e214c7SGavin Maltby 		return ((void **)&v->values.v_ustring);
895*f6e214c7SGavin Maltby 	default:
896*f6e214c7SGavin Maltby 		return (NULL);
897*f6e214c7SGavin Maltby 	}
898*f6e214c7SGavin Maltby 
899*f6e214c7SGavin Maltby 	/*NOTREACHED*/
900*f6e214c7SGavin Maltby }
901*f6e214c7SGavin Maltby 
902*f6e214c7SGavin Maltby /*
903*f6e214c7SGavin Maltby  * Populate scf_values_t value array at position c.
904*f6e214c7SGavin Maltby  */
905*f6e214c7SGavin Maltby static int
906*f6e214c7SGavin Maltby get_value(scf_value_t *val, scf_values_t *v, int c, char *buf, int sz)
907*f6e214c7SGavin Maltby {
908*f6e214c7SGavin Maltby 	switch (v->value_type) {
909*f6e214c7SGavin Maltby 	case SCF_TYPE_BOOLEAN:
910*f6e214c7SGavin Maltby 		return (scf_value_get_boolean(val, v->values.v_boolean + c));
911*f6e214c7SGavin Maltby 	case SCF_TYPE_COUNT:
912*f6e214c7SGavin Maltby 		return (scf_value_get_count(val, v->values.v_count + c));
913*f6e214c7SGavin Maltby 	case SCF_TYPE_INTEGER:
914*f6e214c7SGavin Maltby 		return (scf_value_get_integer(val, v->values.v_integer + c));
915*f6e214c7SGavin Maltby 	case SCF_TYPE_ASTRING:
916*f6e214c7SGavin Maltby 		if (scf_value_get_astring(val, buf, sz) < 0 ||
917*f6e214c7SGavin Maltby 		    (v->values.v_astring[c] = strdup(buf)) == NULL) {
918*f6e214c7SGavin Maltby 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
919*f6e214c7SGavin Maltby 			return (-1);
920*f6e214c7SGavin Maltby 		}
921*f6e214c7SGavin Maltby 		return (0);
922*f6e214c7SGavin Maltby 	case SCF_TYPE_USTRING:
923*f6e214c7SGavin Maltby 		if (scf_value_get_ustring(val, buf, sz) < 0 ||
924*f6e214c7SGavin Maltby 		    (v->values.v_ustring[c] = strdup(buf)) == NULL) {
925*f6e214c7SGavin Maltby 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
926*f6e214c7SGavin Maltby 			return (-1);
927*f6e214c7SGavin Maltby 		}
928*f6e214c7SGavin Maltby 		return (0);
929*f6e214c7SGavin Maltby 	default:
930*f6e214c7SGavin Maltby 		return (-1);
931*f6e214c7SGavin Maltby 	}
932*f6e214c7SGavin Maltby 
933*f6e214c7SGavin Maltby 	/*NOTREACHED*/
934*f6e214c7SGavin Maltby }
935*f6e214c7SGavin Maltby 
936*f6e214c7SGavin Maltby /*
937*f6e214c7SGavin Maltby  * Populate scf_values_t structure with values from prop
938*f6e214c7SGavin Maltby  */
939*f6e214c7SGavin Maltby static int
940*f6e214c7SGavin Maltby values_get(scf_property_t *prop, scf_values_t *v)
941*f6e214c7SGavin Maltby {
942*f6e214c7SGavin Maltby 	scf_handle_t	*h = scf_property_handle(prop);
943*f6e214c7SGavin Maltby 	scf_error_t	scf_e = scf_error();
944*f6e214c7SGavin Maltby 	scf_value_t	*val = scf_value_create(h);
945*f6e214c7SGavin Maltby 	scf_iter_t	*it = scf_iter_create(h);
946*f6e214c7SGavin Maltby 	scf_type_t	type = SCF_TYPE_INVALID;
947*f6e214c7SGavin Maltby 	ssize_t		sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
948*f6e214c7SGavin Maltby 	char		*buf = malloc(sz);
949*f6e214c7SGavin Maltby 	void **p;
950*f6e214c7SGavin Maltby 	int err, elem_sz, count, cursz;
951*f6e214c7SGavin Maltby 	int r = SCF_FAILED;
952*f6e214c7SGavin Maltby 
953*f6e214c7SGavin Maltby 	assert(v != NULL);
954*f6e214c7SGavin Maltby 	assert(v->reserved == NULL);
955*f6e214c7SGavin Maltby 	if (buf == NULL) {
956*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
957*f6e214c7SGavin Maltby 		goto cleanup;
958*f6e214c7SGavin Maltby 	}
959*f6e214c7SGavin Maltby 	if (h == NULL) {
960*f6e214c7SGavin Maltby 		/*
961*f6e214c7SGavin Maltby 		 * Use the error stored in scf_e
962*f6e214c7SGavin Maltby 		 */
963*f6e214c7SGavin Maltby 		(void) scf_set_error(scf_e);
964*f6e214c7SGavin Maltby 		goto cleanup;
965*f6e214c7SGavin Maltby 	}
966*f6e214c7SGavin Maltby 	if (val == NULL || it == NULL)
967*f6e214c7SGavin Maltby 		goto cleanup;
968*f6e214c7SGavin Maltby 
969*f6e214c7SGavin Maltby 	if (scf_property_type(prop, &type) != SCF_SUCCESS)
970*f6e214c7SGavin Maltby 		goto cleanup;
971*f6e214c7SGavin Maltby 	if (scf_property_is_type(prop, v->value_type) != SCF_SUCCESS)
972*f6e214c7SGavin Maltby 		goto error;
973*f6e214c7SGavin Maltby 
974*f6e214c7SGavin Maltby 	elem_sz = get_type_size(type);
975*f6e214c7SGavin Maltby 	assert(elem_sz > 0);
976*f6e214c7SGavin Maltby 
977*f6e214c7SGavin Maltby 	p = get_v_pointer(v);
978*f6e214c7SGavin Maltby 	assert(p != NULL);
979*f6e214c7SGavin Maltby 
980*f6e214c7SGavin Maltby 	cursz = count = v->value_count;
981*f6e214c7SGavin Maltby 	if (scf_iter_property_values(it, prop) != 0) {
982*f6e214c7SGavin Maltby 		goto error;
983*f6e214c7SGavin Maltby 	}
984*f6e214c7SGavin Maltby 
985*f6e214c7SGavin Maltby 	while ((err = scf_iter_next_value(it, val)) == 1) {
986*f6e214c7SGavin Maltby 		if (count + 1 >= cursz) {
987*f6e214c7SGavin Maltby 			void *tmp;
988*f6e214c7SGavin Maltby 
989*f6e214c7SGavin Maltby 			/* set initial size or double it */
990*f6e214c7SGavin Maltby 			cursz = cursz ? 2 * cursz : 8;
991*f6e214c7SGavin Maltby 			if ((tmp = realloc(*p, cursz * elem_sz)) == NULL) {
992*f6e214c7SGavin Maltby 				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
993*f6e214c7SGavin Maltby 				goto error;
994*f6e214c7SGavin Maltby 			}
995*f6e214c7SGavin Maltby 			*p = tmp;
996*f6e214c7SGavin Maltby 		}
997*f6e214c7SGavin Maltby 
998*f6e214c7SGavin Maltby 		if (get_value(val, v, count, buf, sz) != 0)
999*f6e214c7SGavin Maltby 			goto error;
1000*f6e214c7SGavin Maltby 
1001*f6e214c7SGavin Maltby 		count++;
1002*f6e214c7SGavin Maltby 	}
1003*f6e214c7SGavin Maltby 
1004*f6e214c7SGavin Maltby 	v->value_count = count;
1005*f6e214c7SGavin Maltby 
1006*f6e214c7SGavin Maltby 	if (err != 0)
1007*f6e214c7SGavin Maltby 		goto error;
1008*f6e214c7SGavin Maltby 
1009*f6e214c7SGavin Maltby 	r = SCF_SUCCESS;
1010*f6e214c7SGavin Maltby 	goto cleanup;
1011*f6e214c7SGavin Maltby 
1012*f6e214c7SGavin Maltby error:
1013*f6e214c7SGavin Maltby 	v->value_count = count;
1014*f6e214c7SGavin Maltby 	scf_values_destroy(v);
1015*f6e214c7SGavin Maltby 
1016*f6e214c7SGavin Maltby cleanup:
1017*f6e214c7SGavin Maltby 	free(buf);
1018*f6e214c7SGavin Maltby 	scf_iter_destroy(it);
1019*f6e214c7SGavin Maltby 	scf_value_destroy(val);
1020*f6e214c7SGavin Maltby 	return (r);
1021*f6e214c7SGavin Maltby }
1022*f6e214c7SGavin Maltby 
1023*f6e214c7SGavin Maltby /*
1024*f6e214c7SGavin Maltby  * Add values from property p to existing nvlist_t nvl. The data type in the
1025*f6e214c7SGavin Maltby  * nvlist is inferred from the scf_type_t of the property.
1026*f6e214c7SGavin Maltby  *
1027*f6e214c7SGavin Maltby  * Returns SCF_SUCCESS or SCF_FAILED on
1028*f6e214c7SGavin Maltby  *	SCF_ERROR_CONNECTION_BROKEN
1029*f6e214c7SGavin Maltby  *	SCF_ERROR_DELETED
1030*f6e214c7SGavin Maltby  *	SCF_ERROR_HANDLE_DESTROYED
1031*f6e214c7SGavin Maltby  *	SCF_ERROR_HANDLE_MISMATCH
1032*f6e214c7SGavin Maltby  *	SCF_ERROR_INVALID_ARGUMENT
1033*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_MEMORY
1034*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_RESOURCES
1035*f6e214c7SGavin Maltby  *	SCF_ERROR_NOT_BOUND
1036*f6e214c7SGavin Maltby  *	SCF_ERROR_NOT_SET
1037*f6e214c7SGavin Maltby  *	SCF_ERROR_PERMISSION_DENIED
1038*f6e214c7SGavin Maltby  *	SCF_ERROR_TYPE_MISMATCH
1039*f6e214c7SGavin Maltby  */
1040*f6e214c7SGavin Maltby static int
1041*f6e214c7SGavin Maltby add_prop_to_nvlist(scf_property_t *p, const char *pname, nvlist_t *nvl,
1042*f6e214c7SGavin Maltby     int array)
1043*f6e214c7SGavin Maltby {
1044*f6e214c7SGavin Maltby 	scf_values_t	vals = { 0 };
1045*f6e214c7SGavin Maltby 	scf_type_t	type, base_type;
1046*f6e214c7SGavin Maltby 	int r = SCF_FAILED;
1047*f6e214c7SGavin Maltby 	int err = 0;
1048*f6e214c7SGavin Maltby 
1049*f6e214c7SGavin Maltby 	if (p == NULL || pname == NULL || *pname == '\0' || nvl == NULL) {
1050*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1051*f6e214c7SGavin Maltby 		return (r);
1052*f6e214c7SGavin Maltby 	}
1053*f6e214c7SGavin Maltby 
1054*f6e214c7SGavin Maltby 	if (scf_property_type(p, &type) != 0)
1055*f6e214c7SGavin Maltby 		goto cleanup;
1056*f6e214c7SGavin Maltby 
1057*f6e214c7SGavin Maltby 	/*
1058*f6e214c7SGavin Maltby 	 * scf_values_t does not support subtypes of SCF_TYPE_USTRING,
1059*f6e214c7SGavin Maltby 	 * mapping them all to SCF_TYPE_USTRING
1060*f6e214c7SGavin Maltby 	 */
1061*f6e214c7SGavin Maltby 	base_type = scf_true_base_type(type);
1062*f6e214c7SGavin Maltby 	if (base_type == SCF_TYPE_ASTRING && type != SCF_TYPE_ASTRING)
1063*f6e214c7SGavin Maltby 		type = SCF_TYPE_USTRING;
1064*f6e214c7SGavin Maltby 
1065*f6e214c7SGavin Maltby 	vals.value_type = type;
1066*f6e214c7SGavin Maltby 	if (values_get(p, &vals) != SCF_SUCCESS) {
1067*f6e214c7SGavin Maltby 		if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
1068*f6e214c7SGavin Maltby 			assert(0);
1069*f6e214c7SGavin Maltby 			abort();
1070*f6e214c7SGavin Maltby 		}
1071*f6e214c7SGavin Maltby 		goto cleanup;
1072*f6e214c7SGavin Maltby 	}
1073*f6e214c7SGavin Maltby 
1074*f6e214c7SGavin Maltby 	switch (vals.value_type) {
1075*f6e214c7SGavin Maltby 	case SCF_TYPE_BOOLEAN:
1076*f6e214c7SGavin Maltby 		{
1077*f6e214c7SGavin Maltby 			boolean_t *v;
1078*f6e214c7SGavin Maltby 			int i;
1079*f6e214c7SGavin Maltby 			int n = vals.value_count;
1080*f6e214c7SGavin Maltby 
1081*f6e214c7SGavin Maltby 			v = calloc(n, sizeof (boolean_t));
1082*f6e214c7SGavin Maltby 			if (v == NULL) {
1083*f6e214c7SGavin Maltby 				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1084*f6e214c7SGavin Maltby 				goto cleanup;
1085*f6e214c7SGavin Maltby 			}
1086*f6e214c7SGavin Maltby 			for (i = 0; i < n; ++i)
1087*f6e214c7SGavin Maltby 				v[i] = (boolean_t)vals.values.v_boolean[i];
1088*f6e214c7SGavin Maltby 
1089*f6e214c7SGavin Maltby 			if (n == 1 && !array)
1090*f6e214c7SGavin Maltby 				err = nvlist_add_boolean_value(nvl, pname, *v);
1091*f6e214c7SGavin Maltby 			else
1092*f6e214c7SGavin Maltby 				err = nvlist_add_boolean_array(nvl, pname,
1093*f6e214c7SGavin Maltby 				    v, n);
1094*f6e214c7SGavin Maltby 			if (err != 0) {
1095*f6e214c7SGavin Maltby 				free(v);
1096*f6e214c7SGavin Maltby 				goto cleanup;
1097*f6e214c7SGavin Maltby 			}
1098*f6e214c7SGavin Maltby 			free(v);
1099*f6e214c7SGavin Maltby 		}
1100*f6e214c7SGavin Maltby 		break;
1101*f6e214c7SGavin Maltby 
1102*f6e214c7SGavin Maltby 	case SCF_TYPE_COUNT:
1103*f6e214c7SGavin Maltby 		if (vals.value_count == 1 && !array)
1104*f6e214c7SGavin Maltby 			err = nvlist_add_uint64(nvl, pname,
1105*f6e214c7SGavin Maltby 			    *vals.values.v_count);
1106*f6e214c7SGavin Maltby 		else
1107*f6e214c7SGavin Maltby 			err = nvlist_add_uint64_array(nvl, pname,
1108*f6e214c7SGavin Maltby 			    vals.values.v_count, vals.value_count);
1109*f6e214c7SGavin Maltby 		if (err != 0)
1110*f6e214c7SGavin Maltby 			goto cleanup;
1111*f6e214c7SGavin Maltby 
1112*f6e214c7SGavin Maltby 		break;
1113*f6e214c7SGavin Maltby 
1114*f6e214c7SGavin Maltby 	case SCF_TYPE_INTEGER:
1115*f6e214c7SGavin Maltby 		if (vals.value_count == 1 && !array)
1116*f6e214c7SGavin Maltby 			err = nvlist_add_int64(nvl, pname,
1117*f6e214c7SGavin Maltby 			    *vals.values.v_integer);
1118*f6e214c7SGavin Maltby 		else
1119*f6e214c7SGavin Maltby 			err = nvlist_add_int64_array(nvl, pname,
1120*f6e214c7SGavin Maltby 			    vals.values.v_integer, vals.value_count);
1121*f6e214c7SGavin Maltby 		if (err != 0)
1122*f6e214c7SGavin Maltby 			goto cleanup;
1123*f6e214c7SGavin Maltby 
1124*f6e214c7SGavin Maltby 		break;
1125*f6e214c7SGavin Maltby 
1126*f6e214c7SGavin Maltby 	case SCF_TYPE_ASTRING:
1127*f6e214c7SGavin Maltby 		if (vals.value_count == 1 && !array)
1128*f6e214c7SGavin Maltby 			err = nvlist_add_string(nvl, pname,
1129*f6e214c7SGavin Maltby 			    *vals.values.v_astring);
1130*f6e214c7SGavin Maltby 		else
1131*f6e214c7SGavin Maltby 			err = nvlist_add_string_array(nvl, pname,
1132*f6e214c7SGavin Maltby 			    vals.values.v_astring, vals.value_count);
1133*f6e214c7SGavin Maltby 		if (err != 0)
1134*f6e214c7SGavin Maltby 			goto cleanup;
1135*f6e214c7SGavin Maltby 		break;
1136*f6e214c7SGavin Maltby 
1137*f6e214c7SGavin Maltby 	default:
1138*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1139*f6e214c7SGavin Maltby 		goto cleanup;
1140*f6e214c7SGavin Maltby 	}
1141*f6e214c7SGavin Maltby 
1142*f6e214c7SGavin Maltby 	r = SCF_SUCCESS;
1143*f6e214c7SGavin Maltby cleanup:
1144*f6e214c7SGavin Maltby 	scf_values_destroy(&vals);
1145*f6e214c7SGavin Maltby 	switch (err) {
1146*f6e214c7SGavin Maltby 	case 0:
1147*f6e214c7SGavin Maltby 		break;
1148*f6e214c7SGavin Maltby 	case EINVAL:
1149*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1150*f6e214c7SGavin Maltby 		break;
1151*f6e214c7SGavin Maltby 	case ENOMEM:
1152*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1153*f6e214c7SGavin Maltby 		break;
1154*f6e214c7SGavin Maltby 	default:
1155*f6e214c7SGavin Maltby 		/* we should *never* get here */
1156*f6e214c7SGavin Maltby 		abort();
1157*f6e214c7SGavin Maltby 	}
1158*f6e214c7SGavin Maltby 
1159*f6e214c7SGavin Maltby 	return (r);
1160*f6e214c7SGavin Maltby }
1161*f6e214c7SGavin Maltby 
1162*f6e214c7SGavin Maltby /*
1163*f6e214c7SGavin Maltby  * Parse property name "mechanism,parameter" into separate mechanism
1164*f6e214c7SGavin Maltby  * and parameter.  *mech must be freed by caller.  *val points into
1165*f6e214c7SGavin Maltby  * *mech and must not be freed.
1166*f6e214c7SGavin Maltby  *
1167*f6e214c7SGavin Maltby  * Returns SCF_SUCCESS or SCF_FAILED on
1168*f6e214c7SGavin Maltby  * 	SCF_ERROR_NO_MEMORY
1169*f6e214c7SGavin Maltby  * 	SCF_ERROR_NOT_FOUND
1170*f6e214c7SGavin Maltby  */
1171*f6e214c7SGavin Maltby static int
1172*f6e214c7SGavin Maltby get_mech_name(const char *name, char **mech, char **val)
1173*f6e214c7SGavin Maltby {
1174*f6e214c7SGavin Maltby 	char *p;
1175*f6e214c7SGavin Maltby 	char *m;
1176*f6e214c7SGavin Maltby 
1177*f6e214c7SGavin Maltby 	if ((m = strdup(name)) == NULL) {
1178*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1179*f6e214c7SGavin Maltby 		return (SCF_FAILED);
1180*f6e214c7SGavin Maltby 	}
1181*f6e214c7SGavin Maltby 	if ((p = strchr(m, ',')) == NULL) {
1182*f6e214c7SGavin Maltby 		free(m);
1183*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
1184*f6e214c7SGavin Maltby 		return (SCF_FAILED);
1185*f6e214c7SGavin Maltby 	}
1186*f6e214c7SGavin Maltby 	*p = '\0';
1187*f6e214c7SGavin Maltby 	*val = p + 1;
1188*f6e214c7SGavin Maltby 	*mech = m;
1189*f6e214c7SGavin Maltby 
1190*f6e214c7SGavin Maltby 	return (SCF_SUCCESS);
1191*f6e214c7SGavin Maltby }
1192*f6e214c7SGavin Maltby 
1193*f6e214c7SGavin Maltby /*
1194*f6e214c7SGavin Maltby  * Return the number of transitions in a transition set.
1195*f6e214c7SGavin Maltby  * If the transition set is invalid, it returns zero.
1196*f6e214c7SGavin Maltby  */
1197*f6e214c7SGavin Maltby static uint_t
1198*f6e214c7SGavin Maltby num_of_transitions(int32_t t)
1199*f6e214c7SGavin Maltby {
1200*f6e214c7SGavin Maltby 	int i;
1201*f6e214c7SGavin Maltby 	int n = 0;
1202*f6e214c7SGavin Maltby 
1203*f6e214c7SGavin Maltby 	if (SCF_TRANS_VALID(t)) {
1204*f6e214c7SGavin Maltby 		for (i = 0x1; i < SCF_STATE_ALL; i <<= 1) {
1205*f6e214c7SGavin Maltby 			if (i & t)
1206*f6e214c7SGavin Maltby 				++n;
1207*f6e214c7SGavin Maltby 			if (SCF_TRANS_INITIAL_STATE(t) & i)
1208*f6e214c7SGavin Maltby 				++n;
1209*f6e214c7SGavin Maltby 		}
1210*f6e214c7SGavin Maltby 	}
1211*f6e214c7SGavin Maltby 
1212*f6e214c7SGavin Maltby 	return (n);
1213*f6e214c7SGavin Maltby }
1214*f6e214c7SGavin Maltby 
1215*f6e214c7SGavin Maltby /*
1216*f6e214c7SGavin Maltby  * Return the SCF_STATE_* macro value for the state in the FMA classes for
1217*f6e214c7SGavin Maltby  * SMF state transitions. They are of type:
1218*f6e214c7SGavin Maltby  *     SCF_SVC_TRANSITION_CLASS.<state>
1219*f6e214c7SGavin Maltby  *     ireport.os.smf.state-transition.<state>
1220*f6e214c7SGavin Maltby  */
1221*f6e214c7SGavin Maltby static int32_t
1222*f6e214c7SGavin Maltby class_to_transition(const char *c)
1223*f6e214c7SGavin Maltby {
1224*f6e214c7SGavin Maltby 	const char *p;
1225*f6e214c7SGavin Maltby 	int r = 0;
1226*f6e214c7SGavin Maltby 	size_t n;
1227*f6e214c7SGavin Maltby 
1228*f6e214c7SGavin Maltby 	if (!is_svc_stn(c)) {
1229*f6e214c7SGavin Maltby 		return (0);
1230*f6e214c7SGavin Maltby 	}
1231*f6e214c7SGavin Maltby 
1232*f6e214c7SGavin Maltby 	/*
1233*f6e214c7SGavin Maltby 	 * if we get here, c is SCF_SVC_TRANSITION_CLASS or longer
1234*f6e214c7SGavin Maltby 	 */
1235*f6e214c7SGavin Maltby 	p = c + strlen(SCF_SVC_TRANSITION_CLASS);
1236*f6e214c7SGavin Maltby 	if (*p == '.')
1237*f6e214c7SGavin Maltby 		++p;
1238*f6e214c7SGavin Maltby 	else
1239*f6e214c7SGavin Maltby 		return (0);
1240*f6e214c7SGavin Maltby 
1241*f6e214c7SGavin Maltby 	if ((n = base_class_len(p)) == 0)
1242*f6e214c7SGavin Maltby 		return (0);
1243*f6e214c7SGavin Maltby 
1244*f6e214c7SGavin Maltby 	if ((r = state_from_string(p, n)) == -1)
1245*f6e214c7SGavin Maltby 		r = 0;
1246*f6e214c7SGavin Maltby 
1247*f6e214c7SGavin Maltby 	return (r);
1248*f6e214c7SGavin Maltby }
1249*f6e214c7SGavin Maltby 
1250*f6e214c7SGavin Maltby /*
1251*f6e214c7SGavin Maltby  * return SCF_SUCCESS or SCF_FAILED on
1252*f6e214c7SGavin Maltby  *	SCF_ERROR_BACKEND_ACCESS
1253*f6e214c7SGavin Maltby  *	SCF_ERROR_BACKEND_READONLY
1254*f6e214c7SGavin Maltby  *	SCF_ERROR_CONNECTION_BROKEN
1255*f6e214c7SGavin Maltby  *	SCF_ERROR_DELETED
1256*f6e214c7SGavin Maltby  *	SCF_ERROR_INTERNAL
1257*f6e214c7SGavin Maltby  *	SCF_ERROR_INVALID_ARGUMENT
1258*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_MEMORY
1259*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_RESOURCES
1260*f6e214c7SGavin Maltby  *	SCF_ERROR_NOT_FOUND
1261*f6e214c7SGavin Maltby  *	SCF_ERROR_PERMISSION_DENIED
1262*f6e214c7SGavin Maltby  */
1263*f6e214c7SGavin Maltby int
1264*f6e214c7SGavin Maltby smf_notify_set_params(const char *class, nvlist_t *attr)
1265*f6e214c7SGavin Maltby {
1266*f6e214c7SGavin Maltby 	uint32_t	ver;
1267*f6e214c7SGavin Maltby 	int32_t		tset;
1268*f6e214c7SGavin Maltby 	scf_handle_t		*h = _scf_handle_create_and_bind(SCF_VERSION);
1269*f6e214c7SGavin Maltby 	scf_error_t		scf_e = scf_error();
1270*f6e214c7SGavin Maltby 	scf_service_t		*s = scf_service_create(h);
1271*f6e214c7SGavin Maltby 	scf_instance_t		*i = scf_instance_create(h);
1272*f6e214c7SGavin Maltby 	scf_propertygroup_t	*pg = scf_pg_create(h);
1273*f6e214c7SGavin Maltby 	nvlist_t	*params = NULL;
1274*f6e214c7SGavin Maltby 	char		*fmri = (char *)SCF_NOTIFY_PARAMS_INST;
1275*f6e214c7SGavin Maltby 	char		*pgname = NULL;
1276*f6e214c7SGavin Maltby 	int		r = SCF_FAILED;
1277*f6e214c7SGavin Maltby 	boolean_t	is_stn;
1278*f6e214c7SGavin Maltby 	int		 j;
1279*f6e214c7SGavin Maltby 
1280*f6e214c7SGavin Maltby 	assert(class != NULL);
1281*f6e214c7SGavin Maltby 	if (h == NULL) {
1282*f6e214c7SGavin Maltby 		/*
1283*f6e214c7SGavin Maltby 		 * use saved error if _scf_handle_create_and_bind() fails
1284*f6e214c7SGavin Maltby 		 */
1285*f6e214c7SGavin Maltby 		(void) scf_set_error(scf_e);
1286*f6e214c7SGavin Maltby 		goto cleanup;
1287*f6e214c7SGavin Maltby 	}
1288*f6e214c7SGavin Maltby 	if (i == NULL || s == NULL || pg == NULL)
1289*f6e214c7SGavin Maltby 		goto cleanup;
1290*f6e214c7SGavin Maltby 
1291*f6e214c7SGavin Maltby 	/* check version */
1292*f6e214c7SGavin Maltby 	if (nvlist_lookup_uint32(attr, SCF_NOTIFY_NAME_VERSION, &ver) != 0 ||
1293*f6e214c7SGavin Maltby 	    ver != SCF_NOTIFY_PARAMS_VERSION) {
1294*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1295*f6e214c7SGavin Maltby 		goto cleanup;
1296*f6e214c7SGavin Maltby 	}
1297*f6e214c7SGavin Maltby 
1298*f6e214c7SGavin Maltby 	if (nvlist_lookup_nvlist(attr, SCF_NOTIFY_PARAMS, &params) != 0) {
1299*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1300*f6e214c7SGavin Maltby 		goto cleanup;
1301*f6e214c7SGavin Maltby 	}
1302*f6e214c7SGavin Maltby 
1303*f6e214c7SGavin Maltby 	is_stn = is_svc_stn(class);
1304*f6e214c7SGavin Maltby 	/* special case SMF state transition notification */
1305*f6e214c7SGavin Maltby 	if (is_stn &&
1306*f6e214c7SGavin Maltby 	    (nvlist_lookup_string(attr, SCF_NOTIFY_NAME_FMRI, &fmri) != 0 ||
1307*f6e214c7SGavin Maltby 	    nvlist_lookup_int32(attr, SCF_NOTIFY_NAME_TSET, &tset) != 0 ||
1308*f6e214c7SGavin Maltby 	    !SCF_TRANS_VALID(tset))) {
1309*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1310*f6e214c7SGavin Maltby 		goto cleanup;
1311*f6e214c7SGavin Maltby 	}
1312*f6e214c7SGavin Maltby 	if (decode_fmri(fmri, h, &s, &i) != SCF_SUCCESS)
1313*f6e214c7SGavin Maltby 		if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
1314*f6e214c7SGavin Maltby 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1315*f6e214c7SGavin Maltby 		} else if (check_scf_error(scf_error(), errs_1)) {
1316*f6e214c7SGavin Maltby 			goto cleanup;
1317*f6e214c7SGavin Maltby 		}
1318*f6e214c7SGavin Maltby 
1319*f6e214c7SGavin Maltby 	if (is_stn) {
1320*f6e214c7SGavin Maltby 		tset |= class_to_transition(class);
1321*f6e214c7SGavin Maltby 
1322*f6e214c7SGavin Maltby 		if (!SCF_TRANS_VALID(tset)) {
1323*f6e214c7SGavin Maltby 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1324*f6e214c7SGavin Maltby 			goto cleanup;
1325*f6e214c7SGavin Maltby 		}
1326*f6e214c7SGavin Maltby 
1327*f6e214c7SGavin Maltby 		for (j = 0; st_pgnames[j].st_pgname != NULL; ++j) {
1328*f6e214c7SGavin Maltby 			/* if this transition is not in the tset, continue */
1329*f6e214c7SGavin Maltby 			if (!(tset & st_pgnames[j].st_state))
1330*f6e214c7SGavin Maltby 				continue;
1331*f6e214c7SGavin Maltby 
1332*f6e214c7SGavin Maltby 			if (get_or_add_pg(s, i, st_pgnames[j].st_pgname,
1333*f6e214c7SGavin Maltby 			    SCF_NOTIFY_PARAMS_PG_TYPE, 0, pg) != 0 &&
1334*f6e214c7SGavin Maltby 			    check_scf_error(scf_error(), errs_2))
1335*f6e214c7SGavin Maltby 				goto cleanup;
1336*f6e214c7SGavin Maltby 
1337*f6e214c7SGavin Maltby 			if (notify_set_params(pg, params) != 0)
1338*f6e214c7SGavin Maltby 				goto cleanup;
1339*f6e214c7SGavin Maltby 		}
1340*f6e214c7SGavin Maltby 		if (s == NULL) {
1341*f6e214c7SGavin Maltby 			/* We only need to refresh the instance */
1342*f6e214c7SGavin Maltby 			if (_smf_refresh_instance_i(i) != 0 &&
1343*f6e214c7SGavin Maltby 			    check_scf_error(scf_error(), errs_1))
1344*f6e214c7SGavin Maltby 				goto cleanup;
1345*f6e214c7SGavin Maltby 		} else {
1346*f6e214c7SGavin Maltby 			/* We have to refresh all instances in the service */
1347*f6e214c7SGavin Maltby 			if (_smf_refresh_all_instances(s) != 0 &&
1348*f6e214c7SGavin Maltby 			    check_scf_error(scf_error(), errs_1))
1349*f6e214c7SGavin Maltby 				goto cleanup;
1350*f6e214c7SGavin Maltby 		}
1351*f6e214c7SGavin Maltby 	} else {
1352*f6e214c7SGavin Maltby 		if ((pgname = class_to_pgname(class)) == NULL)
1353*f6e214c7SGavin Maltby 			goto cleanup;
1354*f6e214c7SGavin Maltby 		if (get_or_add_pg(s, i, pgname, SCF_GROUP_APPLICATION, 0, pg) !=
1355*f6e214c7SGavin Maltby 		    0) {
1356*f6e214c7SGavin Maltby 			if (check_scf_error(scf_error(), errs_2)) {
1357*f6e214c7SGavin Maltby 				goto cleanup;
1358*f6e214c7SGavin Maltby 			}
1359*f6e214c7SGavin Maltby 		}
1360*f6e214c7SGavin Maltby 		if (notify_set_params(pg, params) != 0) {
1361*f6e214c7SGavin Maltby 			goto cleanup;
1362*f6e214c7SGavin Maltby 		}
1363*f6e214c7SGavin Maltby 		if (_smf_refresh_instance_i(i) != 0 &&
1364*f6e214c7SGavin Maltby 		    check_scf_error(scf_error(), errs_1))
1365*f6e214c7SGavin Maltby 			goto cleanup;
1366*f6e214c7SGavin Maltby 	}
1367*f6e214c7SGavin Maltby 
1368*f6e214c7SGavin Maltby 	r = SCF_SUCCESS;
1369*f6e214c7SGavin Maltby cleanup:
1370*f6e214c7SGavin Maltby 	scf_instance_destroy(i);
1371*f6e214c7SGavin Maltby 	scf_service_destroy(s);
1372*f6e214c7SGavin Maltby 	scf_pg_destroy(pg);
1373*f6e214c7SGavin Maltby 	scf_handle_destroy(h);
1374*f6e214c7SGavin Maltby 	free(pgname);
1375*f6e214c7SGavin Maltby 
1376*f6e214c7SGavin Maltby 	return (r);
1377*f6e214c7SGavin Maltby }
1378*f6e214c7SGavin Maltby 
1379*f6e214c7SGavin Maltby /*
1380*f6e214c7SGavin Maltby  * returns SCF_SUCCESS or SCF_FAILED on
1381*f6e214c7SGavin Maltby  *	SCF_ERROR_CONNECTION_BROKEN
1382*f6e214c7SGavin Maltby  *	SCF_ERROR_DELETED
1383*f6e214c7SGavin Maltby  *	SCF_ERROR_HANDLE_DESTROYED
1384*f6e214c7SGavin Maltby  *	SCF_ERROR_HANDLE_MISMATCH
1385*f6e214c7SGavin Maltby  *	SCF_ERROR_INVALID_ARGUMENT
1386*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_MEMORY
1387*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_RESOURCES
1388*f6e214c7SGavin Maltby  *	SCF_ERROR_NOT_BOUND
1389*f6e214c7SGavin Maltby  *	SCF_ERROR_NOT_FOUND
1390*f6e214c7SGavin Maltby  *	SCF_ERROR_NOT_SET
1391*f6e214c7SGavin Maltby  *	SCF_ERROR_PERMISSION_DENIED
1392*f6e214c7SGavin Maltby  */
1393*f6e214c7SGavin Maltby int
1394*f6e214c7SGavin Maltby _scf_notify_get_params(scf_propertygroup_t *pg, nvlist_t *params)
1395*f6e214c7SGavin Maltby {
1396*f6e214c7SGavin Maltby 	scf_handle_t	*h = scf_pg_handle(pg);
1397*f6e214c7SGavin Maltby 	scf_error_t	scf_e = scf_error();
1398*f6e214c7SGavin Maltby 	scf_property_t	*p = scf_property_create(h);
1399*f6e214c7SGavin Maltby 	scf_iter_t	*it = scf_iter_create(h);
1400*f6e214c7SGavin Maltby 	int sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
1401*f6e214c7SGavin Maltby 	char *name = malloc(sz);
1402*f6e214c7SGavin Maltby 	int r = SCF_FAILED;
1403*f6e214c7SGavin Maltby 	int err;
1404*f6e214c7SGavin Maltby 
1405*f6e214c7SGavin Maltby 	if (h == NULL) {
1406*f6e214c7SGavin Maltby 		/*
1407*f6e214c7SGavin Maltby 		 * Use the error stored in scf_e
1408*f6e214c7SGavin Maltby 		 */
1409*f6e214c7SGavin Maltby 		(void) scf_set_error(scf_e);
1410*f6e214c7SGavin Maltby 		goto cleanup;
1411*f6e214c7SGavin Maltby 	}
1412*f6e214c7SGavin Maltby 	if (it == NULL || p == NULL)
1413*f6e214c7SGavin Maltby 		goto cleanup;
1414*f6e214c7SGavin Maltby 
1415*f6e214c7SGavin Maltby 	if (name == NULL) {
1416*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1417*f6e214c7SGavin Maltby 		goto cleanup;
1418*f6e214c7SGavin Maltby 	}
1419*f6e214c7SGavin Maltby 
1420*f6e214c7SGavin Maltby 	if (scf_iter_pg_properties(it, pg) != SCF_SUCCESS) {
1421*f6e214c7SGavin Maltby 		if (check_scf_error(scf_error(), errs_1)) {
1422*f6e214c7SGavin Maltby 			goto cleanup;
1423*f6e214c7SGavin Maltby 		}
1424*f6e214c7SGavin Maltby 	}
1425*f6e214c7SGavin Maltby 
1426*f6e214c7SGavin Maltby 	while ((err = scf_iter_next_property(it, p)) == 1) {
1427*f6e214c7SGavin Maltby 		nvlist_t *nvl;
1428*f6e214c7SGavin Maltby 		int nvl_new = 0;
1429*f6e214c7SGavin Maltby 		char *mech;
1430*f6e214c7SGavin Maltby 		char *val;
1431*f6e214c7SGavin Maltby 
1432*f6e214c7SGavin Maltby 		if (scf_property_get_name(p, name, sz) == SCF_FAILED) {
1433*f6e214c7SGavin Maltby 			if (check_scf_error(scf_error(), errs_1)) {
1434*f6e214c7SGavin Maltby 				goto cleanup;
1435*f6e214c7SGavin Maltby 			}
1436*f6e214c7SGavin Maltby 		}
1437*f6e214c7SGavin Maltby 
1438*f6e214c7SGavin Maltby 		if (get_mech_name(name, &mech, &val) != SCF_SUCCESS) {
1439*f6e214c7SGavin Maltby 			if (scf_error() == SCF_ERROR_NOT_FOUND)
1440*f6e214c7SGavin Maltby 				continue;
1441*f6e214c7SGavin Maltby 			goto cleanup;
1442*f6e214c7SGavin Maltby 		}
1443*f6e214c7SGavin Maltby 
1444*f6e214c7SGavin Maltby 		if (nvlist_lookup_nvlist(params, mech, &nvl) != 0) {
1445*f6e214c7SGavin Maltby 			if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
1446*f6e214c7SGavin Maltby 				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1447*f6e214c7SGavin Maltby 				free(mech);
1448*f6e214c7SGavin Maltby 				goto cleanup;
1449*f6e214c7SGavin Maltby 			}
1450*f6e214c7SGavin Maltby 			nvl_new = 1;
1451*f6e214c7SGavin Maltby 		}
1452*f6e214c7SGavin Maltby 
1453*f6e214c7SGavin Maltby 		if (add_prop_to_nvlist(p, val, nvl, 1) != SCF_SUCCESS) {
1454*f6e214c7SGavin Maltby 			if (check_scf_error(scf_error(), errs_2)) {
1455*f6e214c7SGavin Maltby 				free(mech);
1456*f6e214c7SGavin Maltby 				nvlist_free(nvl);
1457*f6e214c7SGavin Maltby 				goto cleanup;
1458*f6e214c7SGavin Maltby 			}
1459*f6e214c7SGavin Maltby 		}
1460*f6e214c7SGavin Maltby 		if (nvl_new) {
1461*f6e214c7SGavin Maltby 			if (nvlist_add_nvlist(params, mech, nvl) != 0) {
1462*f6e214c7SGavin Maltby 				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1463*f6e214c7SGavin Maltby 				free(mech);
1464*f6e214c7SGavin Maltby 				nvlist_free(nvl);
1465*f6e214c7SGavin Maltby 				goto cleanup;
1466*f6e214c7SGavin Maltby 			}
1467*f6e214c7SGavin Maltby 			nvlist_free(nvl);
1468*f6e214c7SGavin Maltby 		}
1469*f6e214c7SGavin Maltby 
1470*f6e214c7SGavin Maltby 		free(mech);
1471*f6e214c7SGavin Maltby 	}
1472*f6e214c7SGavin Maltby 
1473*f6e214c7SGavin Maltby 	if (err == 0) {
1474*f6e214c7SGavin Maltby 		r = SCF_SUCCESS;
1475*f6e214c7SGavin Maltby 	} else if (check_scf_error(scf_error(), errs_2)) {
1476*f6e214c7SGavin Maltby 		goto cleanup;
1477*f6e214c7SGavin Maltby 	}
1478*f6e214c7SGavin Maltby 
1479*f6e214c7SGavin Maltby cleanup:
1480*f6e214c7SGavin Maltby 	scf_iter_destroy(it);
1481*f6e214c7SGavin Maltby 	scf_property_destroy(p);
1482*f6e214c7SGavin Maltby 	free(name);
1483*f6e214c7SGavin Maltby 
1484*f6e214c7SGavin Maltby 	return (r);
1485*f6e214c7SGavin Maltby }
1486*f6e214c7SGavin Maltby 
1487*f6e214c7SGavin Maltby /*
1488*f6e214c7SGavin Maltby  * Look up pg containing an SMF state transition parameters. If it cannot find
1489*f6e214c7SGavin Maltby  * the pg in the composed view of the instance, it will look in the global
1490*f6e214c7SGavin Maltby  * instance for the system wide parameters.
1491*f6e214c7SGavin Maltby  * Instance, service and global instance have to be passed by caller.
1492*f6e214c7SGavin Maltby  *
1493*f6e214c7SGavin Maltby  * returns SCF_SUCCESS or SCF_FAILED on
1494*f6e214c7SGavin Maltby  *	SCF_ERROR_BACKEND_ACCESS
1495*f6e214c7SGavin Maltby  *	SCF_ERROR_CONNECTION_BROKEN
1496*f6e214c7SGavin Maltby  *	SCF_ERROR_DELETED
1497*f6e214c7SGavin Maltby  *	SCF_ERROR_HANDLE_DESTROYED
1498*f6e214c7SGavin Maltby  *	SCF_ERROR_HANDLE_MISMATCH
1499*f6e214c7SGavin Maltby  *	SCF_ERROR_INTERNAL
1500*f6e214c7SGavin Maltby  *	SCF_ERROR_INVALID_ARGUMENT
1501*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_MEMORY
1502*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_RESOURCES
1503*f6e214c7SGavin Maltby  *	SCF_ERROR_NOT_BOUND
1504*f6e214c7SGavin Maltby  *	SCF_ERROR_NOT_FOUND
1505*f6e214c7SGavin Maltby  *	SCF_ERROR_NOT_SET
1506*f6e214c7SGavin Maltby  */
1507*f6e214c7SGavin Maltby static int
1508*f6e214c7SGavin Maltby get_stn_pg(scf_service_t *s, scf_instance_t *i, scf_instance_t *g,
1509*f6e214c7SGavin Maltby     const char *pgname, scf_propertygroup_t *pg)
1510*f6e214c7SGavin Maltby {
1511*f6e214c7SGavin Maltby 	if (get_pg(s, i, pgname, pg, 1) == 0 ||
1512*f6e214c7SGavin Maltby 	    scf_error() == SCF_ERROR_NOT_FOUND &&
1513*f6e214c7SGavin Maltby 	    get_pg(NULL, g, pgname, pg, 0) == 0)
1514*f6e214c7SGavin Maltby 		return (SCF_SUCCESS);
1515*f6e214c7SGavin Maltby 
1516*f6e214c7SGavin Maltby 	return (SCF_FAILED);
1517*f6e214c7SGavin Maltby }
1518*f6e214c7SGavin Maltby 
1519*f6e214c7SGavin Maltby /*
1520*f6e214c7SGavin Maltby  * Populates nvlist_t params with the source fmri for the pg
1521*f6e214c7SGavin Maltby  *
1522*f6e214c7SGavin Maltby  * return SCF_SUCCESS or SCF_FAILED on
1523*f6e214c7SGavin Maltby  * 	SCF_ERROR_DELETED
1524*f6e214c7SGavin Maltby  * 	SCF_ERROR_CONNECTION_BROKEN
1525*f6e214c7SGavin Maltby  * 	SCF_ERROR_NO_MEMORY
1526*f6e214c7SGavin Maltby  */
1527*f6e214c7SGavin Maltby static int
1528*f6e214c7SGavin Maltby get_pg_source(scf_propertygroup_t *pg, nvlist_t *params)
1529*f6e214c7SGavin Maltby {
1530*f6e214c7SGavin Maltby 	size_t sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1;
1531*f6e214c7SGavin Maltby 	char *fmri = malloc(sz);
1532*f6e214c7SGavin Maltby 	char *p;
1533*f6e214c7SGavin Maltby 	int r = SCF_FAILED;
1534*f6e214c7SGavin Maltby 
1535*f6e214c7SGavin Maltby 	if (fmri == NULL) {
1536*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1537*f6e214c7SGavin Maltby 		goto out;
1538*f6e214c7SGavin Maltby 	}
1539*f6e214c7SGavin Maltby 
1540*f6e214c7SGavin Maltby 	if (scf_pg_to_fmri(pg, fmri, sz) == -1) {
1541*f6e214c7SGavin Maltby 		if (check_scf_error(scf_error(), errs_1)) {
1542*f6e214c7SGavin Maltby 			goto out;
1543*f6e214c7SGavin Maltby 		}
1544*f6e214c7SGavin Maltby 	}
1545*f6e214c7SGavin Maltby 
1546*f6e214c7SGavin Maltby 	/* get rid of the properties part of the pg source */
1547*f6e214c7SGavin Maltby 	if ((p = strrchr(fmri, ':')) != NULL && p > fmri)
1548*f6e214c7SGavin Maltby 		*(p - 1) = '\0';
1549*f6e214c7SGavin Maltby 	if (nvlist_add_string(params, SCF_NOTIFY_PARAMS_SOURCE_NAME, fmri) !=
1550*f6e214c7SGavin Maltby 	    0) {
1551*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1552*f6e214c7SGavin Maltby 		goto out;
1553*f6e214c7SGavin Maltby 	}
1554*f6e214c7SGavin Maltby 
1555*f6e214c7SGavin Maltby 	r = SCF_SUCCESS;
1556*f6e214c7SGavin Maltby out:
1557*f6e214c7SGavin Maltby 	free(fmri);
1558*f6e214c7SGavin Maltby 	return (r);
1559*f6e214c7SGavin Maltby }
1560*f6e214c7SGavin Maltby 
1561*f6e214c7SGavin Maltby /*
1562*f6e214c7SGavin Maltby  * Specialized function to get SMF state transition notification parameters
1563*f6e214c7SGavin Maltby  *
1564*f6e214c7SGavin Maltby  * return SCF_SUCCESS or SCF_FAILED on
1565*f6e214c7SGavin Maltby  *	SCF_ERROR_BACKEND_ACCESS
1566*f6e214c7SGavin Maltby  *	SCF_ERROR_CONNECTION_BROKEN
1567*f6e214c7SGavin Maltby  *	SCF_ERROR_DELETED
1568*f6e214c7SGavin Maltby  *	SCF_ERROR_INTERNAL
1569*f6e214c7SGavin Maltby  *	SCF_ERROR_INVALID_ARGUMENT
1570*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_MEMORY
1571*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_RESOURCES
1572*f6e214c7SGavin Maltby  *	SCF_ERROR_NOT_FOUND
1573*f6e214c7SGavin Maltby  *	SCF_ERROR_PERMISSION_DENIED
1574*f6e214c7SGavin Maltby  */
1575*f6e214c7SGavin Maltby int
1576*f6e214c7SGavin Maltby _scf_get_svc_notify_params(const char *fmri, nvlist_t *nvl, int32_t tset,
1577*f6e214c7SGavin Maltby     int getsource, int getglobal)
1578*f6e214c7SGavin Maltby {
1579*f6e214c7SGavin Maltby 	scf_handle_t		*h = _scf_handle_create_and_bind(SCF_VERSION);
1580*f6e214c7SGavin Maltby 	scf_error_t		scf_e = scf_error();
1581*f6e214c7SGavin Maltby 	scf_service_t		*s = scf_service_create(h);
1582*f6e214c7SGavin Maltby 	scf_instance_t		*i = scf_instance_create(h);
1583*f6e214c7SGavin Maltby 	scf_instance_t		*g = scf_instance_create(h);
1584*f6e214c7SGavin Maltby 	scf_propertygroup_t	*pg = scf_pg_create(h);
1585*f6e214c7SGavin Maltby 	int r = SCF_FAILED;
1586*f6e214c7SGavin Maltby 	nvlist_t **params = NULL;
1587*f6e214c7SGavin Maltby 	uint_t c, nvl_num = 0;
1588*f6e214c7SGavin Maltby 	int not_found = 1;
1589*f6e214c7SGavin Maltby 	int j;
1590*f6e214c7SGavin Maltby 	const char *pgname;
1591*f6e214c7SGavin Maltby 
1592*f6e214c7SGavin Maltby 	assert(fmri != NULL && nvl != NULL);
1593*f6e214c7SGavin Maltby 	if (h == NULL) {
1594*f6e214c7SGavin Maltby 		/*
1595*f6e214c7SGavin Maltby 		 * use saved error if _scf_handle_create_and_bind() fails
1596*f6e214c7SGavin Maltby 		 */
1597*f6e214c7SGavin Maltby 		(void) scf_set_error(scf_e);
1598*f6e214c7SGavin Maltby 		goto cleanup;
1599*f6e214c7SGavin Maltby 	}
1600*f6e214c7SGavin Maltby 	if (s == NULL || i == NULL || g == NULL || pg == NULL)
1601*f6e214c7SGavin Maltby 		goto cleanup;
1602*f6e214c7SGavin Maltby 
1603*f6e214c7SGavin Maltby 	if (decode_fmri(fmri, h, &s, &i) != SCF_SUCCESS ||
1604*f6e214c7SGavin Maltby 	    scf_handle_decode_fmri(h, SCF_INSTANCE_GLOBAL, NULL, NULL, g, NULL,
1605*f6e214c7SGavin Maltby 	    NULL, SCF_DECODE_FMRI_EXACT) != 0) {
1606*f6e214c7SGavin Maltby 		if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
1607*f6e214c7SGavin Maltby 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1608*f6e214c7SGavin Maltby 		} else if (check_scf_error(scf_error(), errs_1)) {
1609*f6e214c7SGavin Maltby 			goto cleanup;
1610*f6e214c7SGavin Maltby 		}
1611*f6e214c7SGavin Maltby 	}
1612*f6e214c7SGavin Maltby 
1613*f6e214c7SGavin Maltby 	nvl_num = num_of_transitions(tset);
1614*f6e214c7SGavin Maltby 	if ((params = calloc(nvl_num, sizeof (nvlist_t *))) == NULL) {
1615*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1616*f6e214c7SGavin Maltby 		goto cleanup;
1617*f6e214c7SGavin Maltby 	}
1618*f6e214c7SGavin Maltby 
1619*f6e214c7SGavin Maltby 	for (c = 0; c < nvl_num; ++c)
1620*f6e214c7SGavin Maltby 		if (nvlist_alloc(params + c, NV_UNIQUE_NAME, 0) != 0) {
1621*f6e214c7SGavin Maltby 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1622*f6e214c7SGavin Maltby 			goto cleanup;
1623*f6e214c7SGavin Maltby 		}
1624*f6e214c7SGavin Maltby 
1625*f6e214c7SGavin Maltby 	for (c = 0, j = 0; st_pgnames[j].st_pgname != NULL; ++j) {
1626*f6e214c7SGavin Maltby 		/* if this transition is not in the tset, continue */
1627*f6e214c7SGavin Maltby 		if (!(tset & st_pgnames[j].st_state))
1628*f6e214c7SGavin Maltby 			continue;
1629*f6e214c7SGavin Maltby 
1630*f6e214c7SGavin Maltby 		assert(c < nvl_num);
1631*f6e214c7SGavin Maltby 		pgname = st_pgnames[j].st_pgname;
1632*f6e214c7SGavin Maltby 
1633*f6e214c7SGavin Maltby 		if (nvlist_add_int32(params[c], SCF_NOTIFY_NAME_TSET,
1634*f6e214c7SGavin Maltby 		    st_pgnames[j].st_state) != 0) {
1635*f6e214c7SGavin Maltby 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1636*f6e214c7SGavin Maltby 			goto cleanup;
1637*f6e214c7SGavin Maltby 		}
1638*f6e214c7SGavin Maltby 		if ((getglobal ? get_stn_pg(s, i, g, pgname, pg) :
1639*f6e214c7SGavin Maltby 		    get_pg(s, i, pgname, pg, 1)) == SCF_SUCCESS) {
1640*f6e214c7SGavin Maltby 			not_found = 0;
1641*f6e214c7SGavin Maltby 			if (_scf_notify_get_params(pg, params[c]) !=
1642*f6e214c7SGavin Maltby 			    SCF_SUCCESS)
1643*f6e214c7SGavin Maltby 				goto cleanup;
1644*f6e214c7SGavin Maltby 			if (getsource && get_pg_source(pg, params[c]) !=
1645*f6e214c7SGavin Maltby 			    SCF_SUCCESS)
1646*f6e214c7SGavin Maltby 				goto cleanup;
1647*f6e214c7SGavin Maltby 		} else if (scf_error() == SCF_ERROR_NOT_FOUND ||
1648*f6e214c7SGavin Maltby 		    scf_error() == SCF_ERROR_DELETED) {
1649*f6e214c7SGavin Maltby 			/* keep driving */
1650*f6e214c7SGavin Maltby 			/*EMPTY*/
1651*f6e214c7SGavin Maltby 		} else if (check_scf_error(scf_error(), errs_1)) {
1652*f6e214c7SGavin Maltby 			goto cleanup;
1653*f6e214c7SGavin Maltby 		}
1654*f6e214c7SGavin Maltby 		++c;
1655*f6e214c7SGavin Maltby 	}
1656*f6e214c7SGavin Maltby 
1657*f6e214c7SGavin Maltby 	if (not_found) {
1658*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
1659*f6e214c7SGavin Maltby 		goto cleanup;
1660*f6e214c7SGavin Maltby 	}
1661*f6e214c7SGavin Maltby 
1662*f6e214c7SGavin Maltby 	assert(c == nvl_num);
1663*f6e214c7SGavin Maltby 
1664*f6e214c7SGavin Maltby 	if (nvlist_add_nvlist_array(nvl, SCF_NOTIFY_PARAMS, params, nvl_num) !=
1665*f6e214c7SGavin Maltby 	    0 || nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
1666*f6e214c7SGavin Maltby 	    SCF_NOTIFY_PARAMS_VERSION) != 0) {
1667*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1668*f6e214c7SGavin Maltby 		goto cleanup;
1669*f6e214c7SGavin Maltby 	}
1670*f6e214c7SGavin Maltby 
1671*f6e214c7SGavin Maltby 	r = SCF_SUCCESS;
1672*f6e214c7SGavin Maltby 
1673*f6e214c7SGavin Maltby cleanup:
1674*f6e214c7SGavin Maltby 	scf_pg_destroy(pg);
1675*f6e214c7SGavin Maltby 	scf_instance_destroy(i);
1676*f6e214c7SGavin Maltby 	scf_instance_destroy(g);
1677*f6e214c7SGavin Maltby 	scf_service_destroy(s);
1678*f6e214c7SGavin Maltby 	scf_handle_destroy(h);
1679*f6e214c7SGavin Maltby 	if (params != NULL)
1680*f6e214c7SGavin Maltby 		for (c = 0; c < nvl_num; ++c)
1681*f6e214c7SGavin Maltby 			nvlist_free(params[c]);
1682*f6e214c7SGavin Maltby 	free(params);
1683*f6e214c7SGavin Maltby 
1684*f6e214c7SGavin Maltby 	return (r);
1685*f6e214c7SGavin Maltby }
1686*f6e214c7SGavin Maltby 
1687*f6e214c7SGavin Maltby /*
1688*f6e214c7SGavin Maltby  * Specialized function to get fma notification parameters
1689*f6e214c7SGavin Maltby  *
1690*f6e214c7SGavin Maltby  * return SCF_SUCCESS or SCF_FAILED on
1691*f6e214c7SGavin Maltby  *	SCF_ERROR_BACKEND_ACCESS
1692*f6e214c7SGavin Maltby  *	SCF_ERROR_CONNECTION_BROKEN
1693*f6e214c7SGavin Maltby  *	SCF_ERROR_DELETED
1694*f6e214c7SGavin Maltby  *	SCF_ERROR_INTERNAL
1695*f6e214c7SGavin Maltby  *	SCF_ERROR_INVALID_ARGUMENT
1696*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_MEMORY
1697*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_RESOURCES
1698*f6e214c7SGavin Maltby  *	SCF_ERROR_NOT_FOUND
1699*f6e214c7SGavin Maltby  *	SCF_ERROR_PERMISSION_DENIED
1700*f6e214c7SGavin Maltby  */
1701*f6e214c7SGavin Maltby int
1702*f6e214c7SGavin Maltby _scf_get_fma_notify_params(const char *class, nvlist_t *nvl, int getsource)
1703*f6e214c7SGavin Maltby {
1704*f6e214c7SGavin Maltby 	scf_handle_t		*h = _scf_handle_create_and_bind(SCF_VERSION);
1705*f6e214c7SGavin Maltby 	scf_error_t		scf_e = scf_error();
1706*f6e214c7SGavin Maltby 	scf_instance_t		*i = scf_instance_create(h);
1707*f6e214c7SGavin Maltby 	scf_propertygroup_t	*pg = scf_pg_create(h);
1708*f6e214c7SGavin Maltby 	int r = SCF_FAILED;
1709*f6e214c7SGavin Maltby 	nvlist_t *params = NULL;
1710*f6e214c7SGavin Maltby 	char *pgname = NULL;
1711*f6e214c7SGavin Maltby 
1712*f6e214c7SGavin Maltby 	if (h == NULL) {
1713*f6e214c7SGavin Maltby 		/*
1714*f6e214c7SGavin Maltby 		 * use saved error if _scf_handle_create_and_bind() fails
1715*f6e214c7SGavin Maltby 		 */
1716*f6e214c7SGavin Maltby 		(void) scf_set_error(scf_e);
1717*f6e214c7SGavin Maltby 		goto cleanup;
1718*f6e214c7SGavin Maltby 	}
1719*f6e214c7SGavin Maltby 	if (i == NULL || pg == NULL)
1720*f6e214c7SGavin Maltby 		goto cleanup;
1721*f6e214c7SGavin Maltby 
1722*f6e214c7SGavin Maltby 	if (scf_handle_decode_fmri(h, SCF_NOTIFY_PARAMS_INST, NULL, NULL, i,
1723*f6e214c7SGavin Maltby 	    NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1724*f6e214c7SGavin Maltby 		if (check_scf_error(scf_error(), errs_1)) {
1725*f6e214c7SGavin Maltby 			goto cleanup;
1726*f6e214c7SGavin Maltby 		}
1727*f6e214c7SGavin Maltby 	}
1728*f6e214c7SGavin Maltby 
1729*f6e214c7SGavin Maltby 	if ((pgname = class_to_pgname(class)) == NULL)
1730*f6e214c7SGavin Maltby 		goto cleanup;
1731*f6e214c7SGavin Maltby 
1732*f6e214c7SGavin Maltby 	while (get_pg(NULL, i, pgname, pg, 0) != 0) {
1733*f6e214c7SGavin Maltby 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
1734*f6e214c7SGavin Maltby 			char *p = strrchr(pgname, '.');
1735*f6e214c7SGavin Maltby 
1736*f6e214c7SGavin Maltby 			if (p != NULL) {
1737*f6e214c7SGavin Maltby 				*p = ',';
1738*f6e214c7SGavin Maltby 				/*
1739*f6e214c7SGavin Maltby 				 * since the resulting string is shorter,
1740*f6e214c7SGavin Maltby 				 * there is no risk of buffer overflow
1741*f6e214c7SGavin Maltby 				 */
1742*f6e214c7SGavin Maltby 				(void) strcpy(p + 1, SCF_NOTIFY_PG_POSTFIX);
1743*f6e214c7SGavin Maltby 				continue;
1744*f6e214c7SGavin Maltby 			}
1745*f6e214c7SGavin Maltby 		}
1746*f6e214c7SGavin Maltby 
1747*f6e214c7SGavin Maltby 		if (check_scf_error(scf_error(), errs_1)) {
1748*f6e214c7SGavin Maltby 			goto cleanup;
1749*f6e214c7SGavin Maltby 		}
1750*f6e214c7SGavin Maltby 	}
1751*f6e214c7SGavin Maltby 
1752*f6e214c7SGavin Maltby 	if (nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0) {
1753*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1754*f6e214c7SGavin Maltby 		goto cleanup;
1755*f6e214c7SGavin Maltby 	}
1756*f6e214c7SGavin Maltby 
1757*f6e214c7SGavin Maltby 	if (_scf_notify_get_params(pg, params) != SCF_SUCCESS)
1758*f6e214c7SGavin Maltby 		goto cleanup;
1759*f6e214c7SGavin Maltby 
1760*f6e214c7SGavin Maltby 	if (getsource && get_pg_source(pg, params) != SCF_SUCCESS)
1761*f6e214c7SGavin Maltby 		goto cleanup;
1762*f6e214c7SGavin Maltby 
1763*f6e214c7SGavin Maltby 	if (nvlist_add_nvlist_array(nvl, SCF_NOTIFY_PARAMS, &params, 1) != 0 ||
1764*f6e214c7SGavin Maltby 	    nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
1765*f6e214c7SGavin Maltby 	    SCF_NOTIFY_PARAMS_VERSION) != 0) {
1766*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1767*f6e214c7SGavin Maltby 		goto cleanup;
1768*f6e214c7SGavin Maltby 	}
1769*f6e214c7SGavin Maltby 
1770*f6e214c7SGavin Maltby 	r = SCF_SUCCESS;
1771*f6e214c7SGavin Maltby 
1772*f6e214c7SGavin Maltby cleanup:
1773*f6e214c7SGavin Maltby 	if (params)
1774*f6e214c7SGavin Maltby 		nvlist_free(params);
1775*f6e214c7SGavin Maltby 	scf_pg_destroy(pg);
1776*f6e214c7SGavin Maltby 	scf_instance_destroy(i);
1777*f6e214c7SGavin Maltby 	scf_handle_destroy(h);
1778*f6e214c7SGavin Maltby 	free(pgname);
1779*f6e214c7SGavin Maltby 
1780*f6e214c7SGavin Maltby 	return (r);
1781*f6e214c7SGavin Maltby }
1782*f6e214c7SGavin Maltby 
1783*f6e214c7SGavin Maltby /*
1784*f6e214c7SGavin Maltby  * Retrieve the notification parameters for the Event described in the
1785*f6e214c7SGavin Maltby  * input nvlist_t nvl.
1786*f6e214c7SGavin Maltby  * The function will allocate an nvlist_t to store the notification
1787*f6e214c7SGavin Maltby  * parameters. The notification parameters in the output nvlist will have
1788*f6e214c7SGavin Maltby  * the following format:
1789*f6e214c7SGavin Maltby  *
1790*f6e214c7SGavin Maltby  *        version (uint32_t)
1791*f6e214c7SGavin Maltby  *        SCF_NOTIFY_PARAMS (array of embedded nvlists)
1792*f6e214c7SGavin Maltby  *             (start of notify-params[0])
1793*f6e214c7SGavin Maltby  *                  tset (int32_t)
1794*f6e214c7SGavin Maltby  *                  <mechanism-name> (embedded nvlist)
1795*f6e214c7SGavin Maltby  *                       <parameter-name> <parameter-type>
1796*f6e214c7SGavin Maltby  *                       ...
1797*f6e214c7SGavin Maltby  *                  (end <mechanism-name>)
1798*f6e214c7SGavin Maltby  *                  ...
1799*f6e214c7SGavin Maltby  *             (end of notify-params[0])
1800*f6e214c7SGavin Maltby  *             ...
1801*f6e214c7SGavin Maltby  *
1802*f6e214c7SGavin Maltby  * return SCF_SUCCESS or SCF_FAILED on
1803*f6e214c7SGavin Maltby  *	SCF_ERROR_BACKEND_ACCESS
1804*f6e214c7SGavin Maltby  *	SCF_ERROR_CONNECTION_BROKEN
1805*f6e214c7SGavin Maltby  *	SCF_ERROR_DELETED
1806*f6e214c7SGavin Maltby  *	SCF_ERROR_INTERNAL
1807*f6e214c7SGavin Maltby  *	SCF_ERROR_INVALID_ARGUMENT
1808*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_MEMORY
1809*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_RESOURCES
1810*f6e214c7SGavin Maltby  *	SCF_ERROR_NOT_FOUND
1811*f6e214c7SGavin Maltby  *	SCF_ERROR_PERMISSION_DENIED
1812*f6e214c7SGavin Maltby  */
1813*f6e214c7SGavin Maltby int
1814*f6e214c7SGavin Maltby smf_notify_get_params(nvlist_t **params, nvlist_t *nvl)
1815*f6e214c7SGavin Maltby {
1816*f6e214c7SGavin Maltby 	char *class;
1817*f6e214c7SGavin Maltby 	char *from;	/* from state */
1818*f6e214c7SGavin Maltby 	char *to;	/* to state */
1819*f6e214c7SGavin Maltby 	nvlist_t *attr;
1820*f6e214c7SGavin Maltby 	char *fmri;
1821*f6e214c7SGavin Maltby 	int32_t tset = 0;
1822*f6e214c7SGavin Maltby 	int r = SCF_FAILED;
1823*f6e214c7SGavin Maltby 
1824*f6e214c7SGavin Maltby 	if (params == NULL || nvlist_lookup_string(nvl, "class", &class) != 0) {
1825*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1826*f6e214c7SGavin Maltby 		return (r);
1827*f6e214c7SGavin Maltby 	}
1828*f6e214c7SGavin Maltby 	if (nvlist_alloc(params, NV_UNIQUE_NAME, 0) != 0) {
1829*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1830*f6e214c7SGavin Maltby 		return (r);
1831*f6e214c7SGavin Maltby 	}
1832*f6e214c7SGavin Maltby 
1833*f6e214c7SGavin Maltby 	if (is_svc_stn(class)) {
1834*f6e214c7SGavin Maltby 		if (nvlist_lookup_nvlist(nvl, "attr", &attr) != 0 ||
1835*f6e214c7SGavin Maltby 		    nvlist_lookup_string(attr, "svc-string", &fmri) != 0 ||
1836*f6e214c7SGavin Maltby 		    nvlist_lookup_string(attr, "from-state", &from) != 0 ||
1837*f6e214c7SGavin Maltby 		    nvlist_lookup_string(attr, "to-state", &to) != 0) {
1838*f6e214c7SGavin Maltby 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1839*f6e214c7SGavin Maltby 			goto cleanup;
1840*f6e214c7SGavin Maltby 		}
1841*f6e214c7SGavin Maltby 
1842*f6e214c7SGavin Maltby 		tset = SCF_TRANS(smf_state_from_string(from),
1843*f6e214c7SGavin Maltby 		    smf_state_from_string(to));
1844*f6e214c7SGavin Maltby 		if (!SCF_TRANS_VALID(tset)) {
1845*f6e214c7SGavin Maltby 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1846*f6e214c7SGavin Maltby 			goto cleanup;
1847*f6e214c7SGavin Maltby 		}
1848*f6e214c7SGavin Maltby 		tset |= class_to_transition(class);
1849*f6e214c7SGavin Maltby 
1850*f6e214c7SGavin Maltby 		r = _scf_get_svc_notify_params(fmri, *params, tset, 0, 1);
1851*f6e214c7SGavin Maltby 	} else {
1852*f6e214c7SGavin Maltby 		r = _scf_get_fma_notify_params(class, *params, 0);
1853*f6e214c7SGavin Maltby 	}
1854*f6e214c7SGavin Maltby 
1855*f6e214c7SGavin Maltby cleanup:
1856*f6e214c7SGavin Maltby 	if (r == SCF_FAILED) {
1857*f6e214c7SGavin Maltby 		nvlist_free(*params);
1858*f6e214c7SGavin Maltby 		*params = NULL;
1859*f6e214c7SGavin Maltby 	}
1860*f6e214c7SGavin Maltby 
1861*f6e214c7SGavin Maltby 	return (r);
1862*f6e214c7SGavin Maltby }
1863*f6e214c7SGavin Maltby 
1864*f6e214c7SGavin Maltby /*
1865*f6e214c7SGavin Maltby  * return SCF_SUCCESS or SCF_FAILED on
1866*f6e214c7SGavin Maltby  *	SCF_ERROR_BACKEND_ACCESS
1867*f6e214c7SGavin Maltby  *	SCF_ERROR_BACKEND_READONLY
1868*f6e214c7SGavin Maltby  *	SCF_ERROR_CONNECTION_BROKEN
1869*f6e214c7SGavin Maltby  *	SCF_ERROR_DELETED
1870*f6e214c7SGavin Maltby  *	SCF_ERROR_INTERNAL
1871*f6e214c7SGavin Maltby  *	SCF_ERROR_INVALID_ARGUMENT
1872*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_MEMORY
1873*f6e214c7SGavin Maltby  *	SCF_ERROR_NO_RESOURCES
1874*f6e214c7SGavin Maltby  *	SCF_ERROR_NOT_FOUND
1875*f6e214c7SGavin Maltby  *	SCF_ERROR_PERMISSION_DENIED
1876*f6e214c7SGavin Maltby  */
1877*f6e214c7SGavin Maltby int
1878*f6e214c7SGavin Maltby smf_notify_del_params(const char *class, const char *fmri, int32_t tset)
1879*f6e214c7SGavin Maltby {
1880*f6e214c7SGavin Maltby 	scf_handle_t		*h = _scf_handle_create_and_bind(SCF_VERSION);
1881*f6e214c7SGavin Maltby 	scf_error_t		scf_e = scf_error();
1882*f6e214c7SGavin Maltby 	scf_service_t		*s = scf_service_create(h);
1883*f6e214c7SGavin Maltby 	scf_instance_t		*i = scf_instance_create(h);
1884*f6e214c7SGavin Maltby 	scf_propertygroup_t	*pg = scf_pg_create(h);
1885*f6e214c7SGavin Maltby 	int r = SCF_FAILED;
1886*f6e214c7SGavin Maltby 	char *pgname = NULL;
1887*f6e214c7SGavin Maltby 	int j;
1888*f6e214c7SGavin Maltby 
1889*f6e214c7SGavin Maltby 	if (class == NULL) {
1890*f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1891*f6e214c7SGavin Maltby 		goto cleanup;
1892*f6e214c7SGavin Maltby 	}
1893*f6e214c7SGavin Maltby 
1894*f6e214c7SGavin Maltby 	if (h == NULL) {
1895*f6e214c7SGavin Maltby 		/*
1896*f6e214c7SGavin Maltby 		 * use saved error if _scf_handle_create_and_bind() fails
1897*f6e214c7SGavin Maltby 		 */
1898*f6e214c7SGavin Maltby 		(void) scf_set_error(scf_e);
1899*f6e214c7SGavin Maltby 		goto cleanup;
1900*f6e214c7SGavin Maltby 	}
1901*f6e214c7SGavin Maltby 	if (s == NULL || i == NULL || pg == NULL)
1902*f6e214c7SGavin Maltby 		goto cleanup;
1903*f6e214c7SGavin Maltby 
1904*f6e214c7SGavin Maltby 	if (is_svc_stn(class)) {
1905*f6e214c7SGavin Maltby 		tset |= class_to_transition(class);
1906*f6e214c7SGavin Maltby 
1907*f6e214c7SGavin Maltby 		if (!SCF_TRANS_VALID(tset) || fmri == NULL) {
1908*f6e214c7SGavin Maltby 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1909*f6e214c7SGavin Maltby 			goto cleanup;
1910*f6e214c7SGavin Maltby 		}
1911*f6e214c7SGavin Maltby 
1912*f6e214c7SGavin Maltby 		if (decode_fmri(fmri, h, &s, &i) != SCF_SUCCESS) {
1913*f6e214c7SGavin Maltby 			if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
1914*f6e214c7SGavin Maltby 				(void) scf_set_error(
1915*f6e214c7SGavin Maltby 				    SCF_ERROR_INVALID_ARGUMENT);
1916*f6e214c7SGavin Maltby 			if (check_scf_error(scf_error(), errs_1)) {
1917*f6e214c7SGavin Maltby 				goto cleanup;
1918*f6e214c7SGavin Maltby 			}
1919*f6e214c7SGavin Maltby 		}
1920*f6e214c7SGavin Maltby 
1921*f6e214c7SGavin Maltby 		for (j = 0; st_pgnames[j].st_pgname != NULL; ++j) {
1922*f6e214c7SGavin Maltby 			/* if this transition is not in the tset, continue */
1923*f6e214c7SGavin Maltby 			if (!(tset & st_pgnames[j].st_state))
1924*f6e214c7SGavin Maltby 				continue;
1925*f6e214c7SGavin Maltby 
1926*f6e214c7SGavin Maltby 			if (del_pg(s, i, st_pgnames[j].st_pgname, pg) !=
1927*f6e214c7SGavin Maltby 			    SCF_SUCCESS &&
1928*f6e214c7SGavin Maltby 			    scf_error() != SCF_ERROR_DELETED &&
1929*f6e214c7SGavin Maltby 			    scf_error() != SCF_ERROR_NOT_FOUND) {
1930*f6e214c7SGavin Maltby 				if (check_scf_error(scf_error(),
1931*f6e214c7SGavin Maltby 				    errs_1)) {
1932*f6e214c7SGavin Maltby 					goto cleanup;
1933*f6e214c7SGavin Maltby 				}
1934*f6e214c7SGavin Maltby 			}
1935*f6e214c7SGavin Maltby 		}
1936*f6e214c7SGavin Maltby 		if (s == NULL) {
1937*f6e214c7SGavin Maltby 			/* We only need to refresh the instance */
1938*f6e214c7SGavin Maltby 			if (_smf_refresh_instance_i(i) != 0 &&
1939*f6e214c7SGavin Maltby 			    check_scf_error(scf_error(), errs_1))
1940*f6e214c7SGavin Maltby 				goto cleanup;
1941*f6e214c7SGavin Maltby 		} else {
1942*f6e214c7SGavin Maltby 			/* We have to refresh all instances in the service */
1943*f6e214c7SGavin Maltby 			if (_smf_refresh_all_instances(s) != 0 &&
1944*f6e214c7SGavin Maltby 			    check_scf_error(scf_error(), errs_1))
1945*f6e214c7SGavin Maltby 				goto cleanup;
1946*f6e214c7SGavin Maltby 		}
1947*f6e214c7SGavin Maltby 	} else {
1948*f6e214c7SGavin Maltby 		if ((pgname = class_to_pgname(class)) == NULL)
1949*f6e214c7SGavin Maltby 			goto cleanup;
1950*f6e214c7SGavin Maltby 
1951*f6e214c7SGavin Maltby 		if (scf_handle_decode_fmri(h, SCF_NOTIFY_PARAMS_INST, NULL,
1952*f6e214c7SGavin Maltby 		    NULL, i, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
1953*f6e214c7SGavin Maltby 			goto cleanup;
1954*f6e214c7SGavin Maltby 
1955*f6e214c7SGavin Maltby 		if (del_pg(NULL, i, pgname, pg) != SCF_SUCCESS &&
1956*f6e214c7SGavin Maltby 		    scf_error() != SCF_ERROR_DELETED &&
1957*f6e214c7SGavin Maltby 		    scf_error() != SCF_ERROR_NOT_FOUND) {
1958*f6e214c7SGavin Maltby 			if (check_scf_error(scf_error(), errs_1)) {
1959*f6e214c7SGavin Maltby 				goto cleanup;
1960*f6e214c7SGavin Maltby 			}
1961*f6e214c7SGavin Maltby 		}
1962*f6e214c7SGavin Maltby 
1963*f6e214c7SGavin Maltby 		if (_smf_refresh_instance_i(i) != 0 &&
1964*f6e214c7SGavin Maltby 		    check_scf_error(scf_error(), errs_1))
1965*f6e214c7SGavin Maltby 			goto cleanup;
1966*f6e214c7SGavin Maltby 	}
1967*f6e214c7SGavin Maltby 
1968*f6e214c7SGavin Maltby 
1969*f6e214c7SGavin Maltby 	r = SCF_SUCCESS;
1970*f6e214c7SGavin Maltby 
1971*f6e214c7SGavin Maltby cleanup:
1972*f6e214c7SGavin Maltby 	scf_pg_destroy(pg);
1973*f6e214c7SGavin Maltby 	scf_instance_destroy(i);
1974*f6e214c7SGavin Maltby 	scf_service_destroy(s);
1975*f6e214c7SGavin Maltby 	scf_handle_destroy(h);
1976*f6e214c7SGavin Maltby 	free(pgname);
1977*f6e214c7SGavin Maltby 
1978*f6e214c7SGavin Maltby 	return (r);
1979*f6e214c7SGavin Maltby }
1980