dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libscf / common / notify_params.c
blob021d5e52236418411218d01f1b6e1701ac3b6320
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include "libscf_impl.h"
28 #include <assert.h>
29 #include <strings.h>
32 * Errors returned by smf_notify_{del|get|set}_params()
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,
49 * Errors returned by smf_notify_{del|get|set}_params()
50 * Except SCF_ERROR_INVALID_ARGUMENT
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,
66 * Helper function that abort() on unexpected errors.
67 * The expected error set is a zero-terminated array of scf_error_t
69 static int
70 check_scf_error(scf_error_t e, const scf_error_t *errs)
72 if (ismember(e, errs))
73 return (1);
75 assert(0);
76 abort();
78 /*NOTREACHED*/
82 * Mapping of state transition to pgname.
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 }
104 * Check if class matches or is a subclass of SCF_SVC_TRANSITION_CLASS
106 * returns 1, otherwise return 0
108 static boolean_t
109 is_svc_stn(const char *class)
111 int n = strlen(SCF_SVC_TRANSITION_CLASS);
113 if (class && strncmp(class, SCF_SVC_TRANSITION_CLASS, n) == 0)
114 if (class[n] == '\0' || class[n] == '.')
115 return (1);
116 return (0);
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....***"
126 static size_t
127 base_class_len(const char *c)
129 const char *p;
130 size_t n;
132 if ((n = strlen(c)) == 0)
133 return (0);
135 p = c + n;
137 /* get rid of any trailing asterisk */
138 if (*--p == '*')
139 n--;
141 /* make sure the class doesn't end in '.' */
142 while (p >= c && *--p == '.')
143 n--;
145 return (n);
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"
152 * NULL on error
154 static char *
155 class_to_pgname(const char *class)
157 size_t n;
158 ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
159 char *pgname = NULL;
161 n = base_class_len(class);
163 if (n == 0) {
164 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
165 return (NULL);
168 if ((pgname = malloc(sz)) == NULL) {
169 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
170 goto error;
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;
178 return (pgname);
180 error:
181 free(pgname);
182 pgname = NULL;
184 return (pgname);
188 * Get the pg from the running snapshot of the instance (composed or not)
190 static int
191 get_pg(scf_service_t *s, scf_instance_t *i, const char *n,
192 scf_propertygroup_t *pg, int composed)
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;
200 if (h == NULL) {
202 * Use the error stored in scf_e
204 (void) scf_set_error(scf_e);
205 goto out;
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;
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;
221 } else {
222 if (scf_service_get_pg(s, n, pg) != 0)
223 goto out;
226 r = 0;
227 out:
228 scf_snaplevel_destroy(slvl);
229 scf_snapshot_destroy(snap);
231 return (r);
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.
238 * returns 0 on success or -1 on failure
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)
244 int r;
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);
251 if (r == 0)
252 return (0);
253 else if (scf_error() != SCF_ERROR_EXISTS)
254 return (-1);
256 if (s == NULL)
257 r = scf_instance_get_pg(i, n, pg);
258 else
259 r = scf_service_get_pg(s, n, pg);
261 return (r);
265 * Delete the property group form the instance or service.
266 * If service is NULL, use instance, otherwise use only the service.
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
282 static int
283 del_pg(scf_service_t *s, scf_instance_t *i, const char *n,
284 scf_propertygroup_t *pg)
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);
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);
299 return (SCF_SUCCESS);
302 static scf_type_t
303 get_scf_type(nvpair_t *p)
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);
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);
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);
333 case DATA_TYPE_STRING:
334 case DATA_TYPE_STRING_ARRAY:
335 return (SCF_TYPE_ASTRING);
337 default:
338 return (SCF_TYPE_INVALID);
342 static int
343 add_entry(scf_transaction_entry_t *te, scf_value_t *val)
345 if (scf_entry_add_value(te, val) != 0) {
346 scf_value_destroy(val);
347 return (SCF_FAILED);
350 return (SCF_SUCCESS);
353 static int
354 add_boolean_entry(scf_handle_t *h, scf_transaction_entry_t *te, uint8_t v)
356 scf_value_t *val = scf_value_create(h);
358 if (val == NULL)
359 return (SCF_FAILED);
361 scf_value_set_boolean(val, v);
363 return (add_entry(te, val));
366 static int
367 add_count_entry(scf_handle_t *h, scf_transaction_entry_t *te, uint64_t v)
369 scf_value_t *val = scf_value_create(h);
371 if (val == NULL)
372 return (SCF_FAILED);
374 scf_value_set_count(val, v);
376 return (add_entry(te, val));
379 static int
380 add_integer_entry(scf_handle_t *h, scf_transaction_entry_t *te, int64_t v)
382 scf_value_t *val = scf_value_create(h);
384 if (val == NULL)
385 return (SCF_FAILED);
387 scf_value_set_integer(val, v);
389 return (add_entry(te, val));
392 static int
393 add_astring_entry(scf_handle_t *h, scf_transaction_entry_t *te, char *s)
395 scf_value_t *val = scf_value_create(h);
397 if (val == NULL)
398 return (SCF_FAILED);
400 if (scf_value_set_astring(val, s) != 0) {
401 scf_value_destroy(val);
402 return (SCF_FAILED);
405 return (add_entry(te, val));
408 static int
409 get_nvpair_vals(scf_handle_t *h, scf_transaction_entry_t *te, nvpair_t *p)
411 scf_value_t *val = scf_value_create(h);
412 uint_t n = 1;
413 int i;
415 if (val == NULL)
416 return (SCF_FAILED);
418 switch (nvpair_type(p)) {
419 case DATA_TYPE_BOOLEAN:
420 return (add_boolean_entry(h, te, 1));
421 case DATA_TYPE_BOOLEAN_VALUE:
423 boolean_t v;
425 (void) nvpair_value_boolean_value(p, &v);
426 return (add_boolean_entry(h, te, (uint8_t)v));
428 case DATA_TYPE_BOOLEAN_ARRAY:
430 boolean_t *v;
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);
438 return (SCF_SUCCESS);
440 case DATA_TYPE_BYTE:
442 uchar_t v;
444 (void) nvpair_value_byte(p, &v);
445 return (add_count_entry(h, te, v));
447 case DATA_TYPE_UINT8:
449 uint8_t v;
451 (void) nvpair_value_uint8(p, &v);
452 return (add_count_entry(h, te, v));
454 case DATA_TYPE_UINT16:
456 uint16_t v;
458 (void) nvpair_value_uint16(p, &v);
459 return (add_count_entry(h, te, v));
461 case DATA_TYPE_UINT32:
463 uint32_t v;
465 (void) nvpair_value_uint32(p, &v);
466 return (add_count_entry(h, te, v));
468 case DATA_TYPE_UINT64:
470 uint64_t v;
472 (void) nvpair_value_uint64(p, &v);
473 return (add_count_entry(h, te, v));
475 case DATA_TYPE_BYTE_ARRAY:
477 uchar_t *v;
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);
484 return (SCF_SUCCESS);
486 case DATA_TYPE_UINT8_ARRAY:
488 uint8_t *v;
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);
495 return (SCF_SUCCESS);
497 case DATA_TYPE_UINT16_ARRAY:
499 uint16_t *v;
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);
506 return (SCF_SUCCESS);
508 case DATA_TYPE_UINT32_ARRAY:
510 uint32_t *v;
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);
517 return (SCF_SUCCESS);
519 case DATA_TYPE_UINT64_ARRAY:
521 uint64_t *v;
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);
528 return (SCF_SUCCESS);
530 case DATA_TYPE_INT8:
532 int8_t v;
534 (void) nvpair_value_int8(p, &v);
535 return (add_integer_entry(h, te, v));
537 case DATA_TYPE_INT16:
539 int16_t v;
541 (void) nvpair_value_int16(p, &v);
542 return (add_integer_entry(h, te, v));
544 case DATA_TYPE_INT32:
546 int32_t v;
548 (void) nvpair_value_int32(p, &v);
549 return (add_integer_entry(h, te, v));
551 case DATA_TYPE_INT64:
553 int64_t v;
555 (void) nvpair_value_int64(p, &v);
556 return (add_integer_entry(h, te, v));
558 case DATA_TYPE_INT8_ARRAY:
560 int8_t *v;
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);
568 return (SCF_SUCCESS);
570 case DATA_TYPE_INT16_ARRAY:
572 int16_t *v;
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);
580 return (SCF_SUCCESS);
582 case DATA_TYPE_INT32_ARRAY:
584 int32_t *v;
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);
592 return (SCF_SUCCESS);
594 case DATA_TYPE_INT64_ARRAY:
596 int64_t *v;
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);
604 return (SCF_SUCCESS);
606 case DATA_TYPE_STRING:
608 char *str;
610 (void) nvpair_value_string(p, &str);
611 return (add_astring_entry(h, te, str));
613 case DATA_TYPE_STRING_ARRAY:
615 char **v;
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);
623 return (SCF_SUCCESS);
625 default:
626 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
627 return (SCF_FAILED);
630 /*NOTREACHED*/
634 * Add new transaction entry to scf_transaction_t
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
644 static int
645 prep_transaction(scf_transaction_t *tx, scf_transaction_entry_t *te,
646 const char *prop, scf_type_t type)
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);
657 return (SCF_SUCCESS);
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
674 static int
675 notify_set_params(scf_propertygroup_t *pg, nvlist_t *params)
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;
685 if (h == NULL) {
687 * Use the error stored in scf_e
689 (void) scf_set_error(scf_e);
690 goto cleanup;
692 if (tx == NULL)
693 goto cleanup;
695 if (propname == NULL) {
696 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
697 goto cleanup;
700 do {
701 nvpair_t *nvp;
704 * make sure we have the most recent version of the pg
705 * start the transaction
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;
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;
719 /* we ONLY take nvlists here */
720 if (nvpair_type(nvp) != DATA_TYPE_NVLIST) {
721 char *name = nvpair_name(nvp);
724 * if this is output from
725 * smf_notify_get_params() we want to skip
726 * the tset value of the nvlist
728 if (strcmp(name, SCF_NOTIFY_NAME_TSET) == 0)
729 continue;
731 (void) scf_set_error(
732 SCF_ERROR_INVALID_ARGUMENT);
733 goto cleanup;
736 if (nvpair_value_nvlist(nvp, &m) != 0) {
737 (void) scf_set_error(
738 SCF_ERROR_INVALID_ARGUMENT);
739 goto cleanup;
743 * Traverse each mechanism list
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);
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();
763 if (type == SCF_TYPE_INVALID) {
764 (void) scf_set_error(
765 SCF_ERROR_INVALID_ARGUMENT);
766 scf_entry_destroy(te);
767 goto cleanup;
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;
779 if (prep_transaction(tx, te, propname, type) !=
780 SCF_SUCCESS) {
781 scf_entry_destroy(te);
782 goto cleanup;
785 if (get_nvpair_vals(h, te, p) != SCF_SUCCESS) {
786 if (check_scf_error(scf_error(),
787 errs_2)) {
788 goto cleanup;
793 err = scf_transaction_commit(tx);
794 scf_transaction_destroy_children(tx);
795 } while (err == 0);
797 if (err == -1) {
798 if (check_scf_error(scf_error(), errs_2)) {
799 goto cleanup;
803 r = 0;
805 cleanup:
806 scf_transaction_destroy_children(tx);
807 scf_transaction_destroy(tx);
808 free(propname);
810 return (r);
814 * Decode fmri. Populates service OR instance depending on which one is an
815 * exact match to the fmri parameter.
817 * The function destroys and sets the unused entity (service or instance) to
818 * NULL.
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
833 static int
834 decode_fmri(const char *fmri, scf_handle_t *h, scf_service_t **s,
835 scf_instance_t **i)
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);
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);
852 return (SCF_SUCCESS);
856 * Return size in bytes for an SCF_TYPE_*. Not all libscf types are supported
858 static int
859 get_type_size(scf_type_t t)
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);
875 /*NOTREACHED*/
879 * Return a pointer to the array of values according to its type
881 static void **
882 get_v_pointer(scf_values_t *v)
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);
899 /*NOTREACHED*/
903 * Populate scf_values_t value array at position c.
905 static int
906 get_value(scf_value_t *val, scf_values_t *v, int c, char *buf, int sz)
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);
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);
928 return (0);
929 default:
930 return (-1);
933 /*NOTREACHED*/
937 * Populate scf_values_t structure with values from prop
939 static int
940 values_get(scf_property_t *prop, scf_values_t *v)
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;
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;
959 if (h == NULL) {
961 * Use the error stored in scf_e
963 (void) scf_set_error(scf_e);
964 goto cleanup;
966 if (val == NULL || it == NULL)
967 goto cleanup;
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;
974 elem_sz = get_type_size(type);
975 assert(elem_sz > 0);
977 p = get_v_pointer(v);
978 assert(p != NULL);
980 cursz = count = v->value_count;
981 if (scf_iter_property_values(it, prop) != 0) {
982 goto error;
985 while ((err = scf_iter_next_value(it, val)) == 1) {
986 if (count + 1 >= cursz) {
987 void *tmp;
989 /* set initial size or double it */
990 cursz = cursz ? 2 * cursz : 8;
991 if ((tmp = reallocarray(*p, cursz, elem_sz)) == NULL) {
992 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
993 goto error;
995 *p = tmp;
998 if (get_value(val, v, count, buf, sz) != 0)
999 goto error;
1001 count++;
1004 v->value_count = count;
1006 if (err != 0)
1007 goto error;
1009 r = SCF_SUCCESS;
1010 goto cleanup;
1012 error:
1013 v->value_count = count;
1014 scf_values_destroy(v);
1016 cleanup:
1017 free(buf);
1018 scf_iter_destroy(it);
1019 scf_value_destroy(val);
1020 return (r);
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.
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
1040 static int
1041 add_prop_to_nvlist(scf_property_t *p, const char *pname, nvlist_t *nvl,
1042 int array)
1044 scf_values_t vals = { 0 };
1045 scf_type_t type, base_type;
1046 int r = SCF_FAILED;
1047 int err = 0;
1049 if (p == NULL || pname == NULL || *pname == '\0' || nvl == NULL) {
1050 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1051 return (r);
1054 if (scf_property_type(p, &type) != 0)
1055 goto cleanup;
1058 * scf_values_t does not support subtypes of SCF_TYPE_USTRING,
1059 * mapping them all to SCF_TYPE_USTRING
1061 base_type = scf_true_base_type(type);
1062 if (base_type == SCF_TYPE_ASTRING && type != SCF_TYPE_ASTRING)
1063 type = SCF_TYPE_USTRING;
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();
1071 goto cleanup;
1074 switch (vals.value_type) {
1075 case SCF_TYPE_BOOLEAN:
1077 boolean_t *v;
1078 int i;
1079 int n = vals.value_count;
1081 v = calloc(n, sizeof (boolean_t));
1082 if (v == NULL) {
1083 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1084 goto cleanup;
1086 for (i = 0; i < n; ++i)
1087 v[i] = (boolean_t)vals.values.v_boolean[i];
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;
1098 free(v);
1100 break;
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;
1112 break;
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;
1124 break;
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;
1137 default:
1138 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1139 goto cleanup;
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();
1159 return (r);
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.
1167 * Returns SCF_SUCCESS or SCF_FAILED on
1168 * SCF_ERROR_NO_MEMORY
1169 * SCF_ERROR_NOT_FOUND
1171 static int
1172 get_mech_name(const char *name, char **mech, char **val)
1174 char *p;
1175 char *m;
1177 if ((m = strdup(name)) == NULL) {
1178 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1179 return (SCF_FAILED);
1181 if ((p = strchr(m, ',')) == NULL) {
1182 free(m);
1183 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
1184 return (SCF_FAILED);
1186 *p = '\0';
1187 *val = p + 1;
1188 *mech = m;
1190 return (SCF_SUCCESS);
1194 * Return the number of transitions in a transition set.
1195 * If the transition set is invalid, it returns zero.
1197 static uint_t
1198 num_of_transitions(int32_t t)
1200 int i;
1201 int n = 0;
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;
1212 return (n);
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>
1221 static int32_t
1222 class_to_transition(const char *c)
1224 const char *p;
1225 int r = 0;
1226 size_t n;
1228 if (!is_svc_stn(c)) {
1229 return (0);
1233 * if we get here, c is SCF_SVC_TRANSITION_CLASS or longer
1235 p = c + strlen(SCF_SVC_TRANSITION_CLASS);
1236 if (*p == '.')
1237 ++p;
1238 else
1239 return (0);
1241 if ((n = base_class_len(p)) == 0)
1242 return (0);
1244 if ((r = state_from_string(p, n)) == -1)
1245 r = 0;
1247 return (r);
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
1264 smf_notify_set_params(const char *class, nvlist_t *attr)
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;
1280 assert(class != NULL);
1281 if (h == NULL) {
1283 * use saved error if _scf_handle_create_and_bind() fails
1285 (void) scf_set_error(scf_e);
1286 goto cleanup;
1288 if (i == NULL || s == NULL || pg == NULL)
1289 goto cleanup;
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;
1298 if (nvlist_lookup_nvlist(attr, SCF_NOTIFY_PARAMS, &params) != 0) {
1299 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1300 goto cleanup;
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;
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;
1319 if (is_stn) {
1320 tset |= class_to_transition(class);
1322 if (!SCF_TRANS_VALID(tset)) {
1323 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1324 goto cleanup;
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;
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;
1337 if (notify_set_params(pg, params) != 0)
1338 goto cleanup;
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;
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;
1360 if (notify_set_params(pg, params) != 0) {
1361 goto cleanup;
1363 if (_smf_refresh_instance_i(i) != 0 &&
1364 check_scf_error(scf_error(), errs_1))
1365 goto cleanup;
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);
1376 return (r);
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
1394 _scf_notify_get_params(scf_propertygroup_t *pg, nvlist_t *params)
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;
1405 if (h == NULL) {
1407 * Use the error stored in scf_e
1409 (void) scf_set_error(scf_e);
1410 goto cleanup;
1412 if (it == NULL || p == NULL)
1413 goto cleanup;
1415 if (name == NULL) {
1416 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1417 goto cleanup;
1420 if (scf_iter_pg_properties(it, pg) != SCF_SUCCESS) {
1421 if (check_scf_error(scf_error(), errs_1)) {
1422 goto cleanup;
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;
1432 if (scf_property_get_name(p, name, sz) == SCF_FAILED) {
1433 if (check_scf_error(scf_error(), errs_1)) {
1434 goto cleanup;
1438 if (get_mech_name(name, &mech, &val) != SCF_SUCCESS) {
1439 if (scf_error() == SCF_ERROR_NOT_FOUND)
1440 continue;
1441 goto cleanup;
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;
1450 nvl_new = 1;
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;
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;
1467 nvlist_free(nvl);
1470 free(mech);
1473 if (err == 0) {
1474 r = SCF_SUCCESS;
1475 } else if (check_scf_error(scf_error(), errs_2)) {
1476 goto cleanup;
1479 cleanup:
1480 scf_iter_destroy(it);
1481 scf_property_destroy(p);
1482 free(name);
1484 return (r);
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.
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
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)
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);
1516 return (SCF_FAILED);
1520 * Populates nvlist_t params with the source fmri for the pg
1522 * return SCF_SUCCESS or SCF_FAILED on
1523 * SCF_ERROR_DELETED
1524 * SCF_ERROR_CONNECTION_BROKEN
1525 * SCF_ERROR_NO_MEMORY
1527 static int
1528 get_pg_source(scf_propertygroup_t *pg, nvlist_t *params)
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;
1535 if (fmri == NULL) {
1536 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1537 goto out;
1540 if (scf_pg_to_fmri(pg, fmri, sz) == -1) {
1541 if (check_scf_error(scf_error(), errs_1)) {
1542 goto out;
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;
1555 r = SCF_SUCCESS;
1556 out:
1557 free(fmri);
1558 return (r);
1562 * Specialized function to get SMF state transition notification parameters
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
1576 _scf_get_svc_notify_params(const char *fmri, nvlist_t *nvl, int32_t tset,
1577 int getsource, int getglobal)
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;
1592 assert(fmri != NULL && nvl != NULL);
1593 if (h == NULL) {
1595 * use saved error if _scf_handle_create_and_bind() fails
1597 (void) scf_set_error(scf_e);
1598 goto cleanup;
1600 if (s == NULL || i == NULL || g == NULL || pg == NULL)
1601 goto cleanup;
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;
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;
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;
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;
1630 assert(c < nvl_num);
1631 pgname = st_pgnames[j].st_pgname;
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;
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;
1654 ++c;
1657 if (not_found) {
1658 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
1659 goto cleanup;
1662 assert(c == nvl_num);
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;
1671 r = SCF_SUCCESS;
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);
1684 return (r);
1688 * Specialized function to get fma notification parameters
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
1702 _scf_get_fma_notify_params(const char *class, nvlist_t *nvl, int getsource)
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;
1712 if (h == NULL) {
1714 * use saved error if _scf_handle_create_and_bind() fails
1716 (void) scf_set_error(scf_e);
1717 goto cleanup;
1719 if (i == NULL || pg == NULL)
1720 goto cleanup;
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;
1729 if ((pgname = class_to_pgname(class)) == NULL)
1730 goto cleanup;
1732 while (get_pg(NULL, i, pgname, pg, 0) != 0) {
1733 if (scf_error() == SCF_ERROR_NOT_FOUND) {
1734 char *p = strrchr(pgname, '.');
1736 if (p != NULL) {
1737 *p = ',';
1739 * since the resulting string is shorter,
1740 * there is no risk of buffer overflow
1742 (void) strcpy(p + 1, SCF_NOTIFY_PG_POSTFIX);
1743 continue;
1747 if (check_scf_error(scf_error(), errs_1)) {
1748 goto cleanup;
1752 if (nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0) {
1753 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1754 goto cleanup;
1757 if (_scf_notify_get_params(pg, params) != SCF_SUCCESS)
1758 goto cleanup;
1760 if (getsource && get_pg_source(pg, params) != SCF_SUCCESS)
1761 goto cleanup;
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;
1770 r = SCF_SUCCESS;
1772 cleanup:
1773 nvlist_free(params);
1774 scf_pg_destroy(pg);
1775 scf_instance_destroy(i);
1776 scf_handle_destroy(h);
1777 free(pgname);
1779 return (r);
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:
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 * ...
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
1813 smf_notify_get_params(nvlist_t **params, nvlist_t *nvl)
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;
1823 if (params == NULL || nvlist_lookup_string(nvl, "class", &class) != 0) {
1824 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1825 return (r);
1827 if (nvlist_alloc(params, NV_UNIQUE_NAME, 0) != 0) {
1828 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1829 return (r);
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;
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;
1847 tset |= class_to_transition(class);
1849 r = _scf_get_svc_notify_params(fmri, *params, tset, 0, 1);
1850 } else {
1851 r = _scf_get_fma_notify_params(class, *params, 0);
1854 cleanup:
1855 if (r == SCF_FAILED) {
1856 nvlist_free(*params);
1857 *params = NULL;
1860 return (r);
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
1877 smf_notify_del_params(const char *class, const char *fmri, int32_t tset)
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;
1888 if (class == NULL) {
1889 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1890 goto cleanup;
1893 if (h == NULL) {
1895 * use saved error if _scf_handle_create_and_bind() fails
1897 (void) scf_set_error(scf_e);
1898 goto cleanup;
1900 if (s == NULL || i == NULL || pg == NULL)
1901 goto cleanup;
1903 if (is_svc_stn(class)) {
1904 tset |= class_to_transition(class);
1906 if (!SCF_TRANS_VALID(tset) || fmri == NULL) {
1907 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1908 goto cleanup;
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;
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;
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;
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;
1946 } else {
1947 if ((pgname = class_to_pgname(class)) == NULL)
1948 goto cleanup;
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;
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;
1962 if (_smf_refresh_instance_i(i) != 0 &&
1963 check_scf_error(scf_error(), errs_1))
1964 goto cleanup;
1968 r = SCF_SUCCESS;
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);
1977 return (r);