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