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