xref: /illumos-gate/usr/src/lib/libscf/common/notify_params.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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  */
34 static 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  */
52 static 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  */
69 static int
70 check_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  */
84 static 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  */
108 static boolean_t
109 is_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  */
126 static size_t
127 base_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  */
154 static char *
155 class_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 
180 error:
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  */
190 static int
191 get_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;
227 out:
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  */
240 static int
241 get_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  */
282 static int
283 del_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 
302 static scf_type_t
303 get_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 
342 static int
343 add_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 
353 static int
354 add_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 
366 static int
367 add_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 
379 static int
380 add_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 
392 static int
393 add_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 
408 static int
409 get_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  */
644 static int
645 prep_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  */
674 static int
675 notify_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 
805 cleanup:
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  */
833 static int
834 decode_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  */
858 static int
859 get_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  */
881 static void **
882 get_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  */
905 static int
906 get_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  */
939 static int
940 values_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 
1012 error:
1013 	v->value_count = count;
1014 	scf_values_destroy(v);
1015 
1016 cleanup:
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  */
1040 static int
1041 add_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;
1143 cleanup:
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  */
1171 static int
1172 get_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  */
1197 static uint_t
1198 num_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  */
1221 static int32_t
1222 class_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  */
1263 int
1264 smf_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;
1369 cleanup:
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  */
1393 int
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 
1479 cleanup:
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  */
1507 static int
1508 get_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  */
1527 static int
1528 get_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;
1556 out:
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  */
1575 int
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 
1673 cleanup:
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  */
1701 int
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 
1772 cleanup:
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  */
1812 int
1813 smf_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 
1854 cleanup:
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  */
1876 int
1877 smf_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 
1970 cleanup:
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