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]
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
25 * Copyright 2018 RackTop Systems.
28 #include "libscf_impl.h"
35 #include <sys/param.h>
39 #include "midlevel_impl.h"
40 #include "lowlevel_impl.h"
43 #define bad_error(func, err) { \
44 uu_warn("%s:%d: %s failed with unexpected error %d. Aborting.\n", \
45 __FILE__, __LINE__, func, err); \
49 #define bad_error(func, err) abort()
52 /* Path to speedy files area must end with a slash */
53 #define SMF_SPEEDY_FILES_PATH "/etc/svc/volatile/"
56 scf_simple_handle_destroy(scf_simple_handle_t
*simple_h
)
61 scf_pg_destroy(simple_h
->running_pg
);
62 scf_pg_destroy(simple_h
->editing_pg
);
63 scf_snapshot_destroy(simple_h
->snap
);
64 scf_instance_destroy(simple_h
->inst
);
65 scf_handle_destroy(simple_h
->h
);
70 * Given a base service FMRI and the names of a property group and property,
71 * assemble_fmri() merges them into a property FMRI. Note that if the base
72 * FMRI is NULL, assemble_fmri() gets the base FMRI from scf_myname().
76 assemble_fmri(scf_handle_t
*h
, const char *base
, const char *pg
,
79 size_t fmri_sz
, pglen
;
84 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
89 pglen
= strlen(SCF_PG_APP_DEFAULT
);
94 if ((baselen
= scf_myname(h
, NULL
, 0)) == -1)
97 baselen
= strlen(base
);
100 fmri_sz
= baselen
+ sizeof (SCF_FMRI_PROPERTYGRP_PREFIX
) - 1 +
101 pglen
+ sizeof (SCF_FMRI_PROPERTY_PREFIX
) - 1 +
104 if ((fmri_buf
= malloc(fmri_sz
)) == NULL
) {
105 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
110 if (scf_myname(h
, fmri_buf
, fmri_sz
) == -1) {
115 (void) strcpy(fmri_buf
, base
);
118 (void) strcat(fmri_buf
, SCF_FMRI_PROPERTYGRP_PREFIX
);
121 (void) strcat(fmri_buf
, SCF_PG_APP_DEFAULT
);
123 (void) strcat(fmri_buf
, pg
);
125 (void) strcat(fmri_buf
, SCF_FMRI_PROPERTY_PREFIX
);
126 (void) strcat(fmri_buf
, prop
);
131 * Given a property, this function allocates and fills an scf_simple_prop_t
132 * with the data it contains.
135 static scf_simple_prop_t
*
136 fill_prop(scf_property_t
*prop
, const char *pgname
, const char *propname
,
139 scf_simple_prop_t
*ret
;
143 ssize_t valsize
, numvals
;
144 union scf_simple_prop_val
*vallist
= NULL
, *vallist_backup
= NULL
;
146 if ((ret
= malloc(sizeof (*ret
))) == NULL
) {
147 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
156 ret
->pr_pgname
= strdup(SCF_PG_APP_DEFAULT
);
158 ret
->pr_pgname
= strdup(pgname
);
160 if (ret
->pr_pgname
== NULL
) {
161 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
166 if ((ret
->pr_propname
= strdup(propname
)) == NULL
) {
167 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
168 free(ret
->pr_pgname
);
173 if (scf_property_type(prop
, &ret
->pr_type
) == -1)
176 if ((iter
= scf_iter_create(h
)) == NULL
)
178 if ((val
= scf_value_create(h
)) == NULL
) {
179 scf_iter_destroy(iter
);
183 if (scf_iter_property_values(iter
, prop
) == -1)
186 for (numvals
= 0; (iterret
= scf_iter_next_value(iter
, val
)) == 1;
188 vallist_backup
= vallist
;
189 if ((vallist
= reallocarray(vallist
, numvals
+ 1,
190 sizeof (*vallist
))) == NULL
) {
191 vallist
= vallist_backup
;
195 switch (ret
->pr_type
) {
196 case SCF_TYPE_BOOLEAN
:
197 if (scf_value_get_boolean(val
,
198 &vallist
[numvals
].pv_bool
) == -1)
203 if (scf_value_get_count(val
,
204 &vallist
[numvals
].pv_uint
) == -1)
208 case SCF_TYPE_INTEGER
:
209 if (scf_value_get_integer(val
,
210 &vallist
[numvals
].pv_int
) == -1)
215 if (scf_value_get_time(val
,
216 &vallist
[numvals
].pv_time
.t_sec
,
217 &vallist
[numvals
].pv_time
.t_nsec
) == -1)
221 case SCF_TYPE_ASTRING
:
222 vallist
[numvals
].pv_str
= NULL
;
223 if ((valsize
= scf_value_get_astring(val
, NULL
, 0)) ==
226 if ((vallist
[numvals
].pv_str
= malloc(valsize
+1)) ==
228 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
231 if (scf_value_get_astring(val
,
232 vallist
[numvals
].pv_str
, valsize
+1) == -1) {
233 free(vallist
[numvals
].pv_str
);
238 case SCF_TYPE_USTRING
:
240 case SCF_TYPE_HOSTNAME
:
241 case SCF_TYPE_NET_ADDR
:
242 case SCF_TYPE_NET_ADDR_V4
:
243 case SCF_TYPE_NET_ADDR_V6
:
246 vallist
[numvals
].pv_str
= NULL
;
247 if ((valsize
= scf_value_get_ustring(val
, NULL
, 0)) ==
250 if ((vallist
[numvals
].pv_str
= malloc(valsize
+1)) ==
252 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
255 if (scf_value_get_ustring(val
,
256 vallist
[numvals
].pv_str
, valsize
+1) == -1) {
257 free(vallist
[numvals
].pv_str
);
262 case SCF_TYPE_OPAQUE
:
263 vallist
[numvals
].pv_opaque
.o_value
= NULL
;
264 if ((valsize
= scf_value_get_opaque(val
, NULL
, 0)) ==
267 if ((vallist
[numvals
].pv_opaque
.o_value
=
268 malloc(valsize
)) == NULL
) {
269 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
272 vallist
[numvals
].pv_opaque
.o_size
= valsize
;
273 if (scf_value_get_opaque(val
,
274 vallist
[numvals
].pv_opaque
.o_value
,
276 free(vallist
[numvals
].pv_opaque
.o_value
);
282 (void) scf_set_error(SCF_ERROR_INTERNAL
);
289 int err
= scf_error();
290 if (err
!= SCF_ERROR_CONNECTION_BROKEN
&&
291 err
!= SCF_ERROR_PERMISSION_DENIED
)
292 (void) scf_set_error(SCF_ERROR_INTERNAL
);
296 ret
->pr_vallist
= vallist
;
297 ret
->pr_numvalues
= numvals
;
299 scf_iter_destroy(iter
);
300 (void) scf_value_destroy(val
);
305 * Exit point for a successful call. Below this line are exit points
306 * for failures at various stages during the function.
313 switch (ret
->pr_type
) {
314 case SCF_TYPE_ASTRING
:
315 case SCF_TYPE_USTRING
:
317 case SCF_TYPE_HOSTNAME
:
318 case SCF_TYPE_NET_ADDR
:
319 case SCF_TYPE_NET_ADDR_V4
:
320 case SCF_TYPE_NET_ADDR_V6
:
322 case SCF_TYPE_FMRI
: {
323 for (i
= 0; i
< numvals
; i
++) {
324 free(vallist
[i
].pv_str
);
328 case SCF_TYPE_OPAQUE
: {
329 for (i
= 0; i
< numvals
; i
++) {
330 free(vallist
[i
].pv_opaque
.o_value
);
341 scf_iter_destroy(iter
);
342 (void) scf_value_destroy(val
);
345 free(ret
->pr_pgname
);
346 free(ret
->pr_propname
);
352 * insert_app_props iterates over a property iterator, getting all the
353 * properties from a property group, and adding or overwriting them into
354 * a simple_app_props_t. This is used by scf_simple_app_props_get to provide
355 * service/instance composition while filling the app_props_t.
356 * insert_app_props iterates over a single property group.
360 insert_app_props(scf_iter_t
*propiter
, char *pgname
, char *propname
, struct
361 scf_simple_pg
*thispg
, scf_property_t
*prop
, size_t namelen
,
364 scf_simple_prop_t
*thisprop
, *prevprop
, *newprop
;
368 while ((propiter_ret
= scf_iter_next_property(propiter
, prop
)) == 1) {
370 if (scf_property_get_name(prop
, propname
, namelen
) < 0) {
371 if (scf_error() == SCF_ERROR_NOT_SET
)
372 (void) scf_set_error(SCF_ERROR_INTERNAL
);
376 thisprop
= thispg
->pg_proplist
;
377 prevprop
= thispg
->pg_proplist
;
380 while ((thisprop
!= NULL
) && (!found
)) {
381 if (strcmp(thisprop
->pr_propname
, propname
) == 0) {
383 if ((newprop
= fill_prop(prop
, pgname
,
384 propname
, h
)) == NULL
)
387 if (thisprop
== thispg
->pg_proplist
)
388 thispg
->pg_proplist
= newprop
;
390 prevprop
->pr_next
= newprop
;
392 newprop
->pr_pg
= thispg
;
393 newprop
->pr_next
= thisprop
->pr_next
;
394 scf_simple_prop_free(thisprop
);
397 if (thisprop
!= thispg
->pg_proplist
)
398 prevprop
= prevprop
->pr_next
;
399 thisprop
= thisprop
->pr_next
;
404 if ((newprop
= fill_prop(prop
, pgname
, propname
, h
)) ==
408 if (thispg
->pg_proplist
== NULL
)
409 thispg
->pg_proplist
= newprop
;
411 prevprop
->pr_next
= newprop
;
413 newprop
->pr_pg
= thispg
;
417 if (propiter_ret
== -1) {
418 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
419 (void) scf_set_error(SCF_ERROR_INTERNAL
);
428 * Sets up e in tx to set pname's values. Returns 0 on success or -1 on
429 * failure, with scf_error() set to
430 * SCF_ERROR_HANDLE_MISMATCH - tx & e are derived from different handles
431 * SCF_ERROR_INVALID_ARGUMENT - pname or ty are invalid
432 * SCF_ERROR_NOT_BOUND - handle is not bound
433 * SCF_ERROR_CONNECTION_BROKEN - connection was broken
434 * SCF_ERROR_NOT_SET - tx has not been started
435 * SCF_ERROR_DELETED - the pg tx was started on was deleted
438 transaction_property_set(scf_transaction_t
*tx
, scf_transaction_entry_t
*e
,
439 const char *pname
, scf_type_t ty
)
442 if (scf_transaction_property_change_type(tx
, e
, pname
, ty
) == 0)
445 switch (scf_error()) {
446 case SCF_ERROR_HANDLE_MISMATCH
:
447 case SCF_ERROR_INVALID_ARGUMENT
:
448 case SCF_ERROR_NOT_BOUND
:
449 case SCF_ERROR_CONNECTION_BROKEN
:
450 case SCF_ERROR_NOT_SET
:
451 case SCF_ERROR_DELETED
:
455 case SCF_ERROR_NOT_FOUND
:
459 if (scf_transaction_property_new(tx
, e
, pname
, ty
) == 0)
462 switch (scf_error()) {
463 case SCF_ERROR_HANDLE_MISMATCH
:
464 case SCF_ERROR_INVALID_ARGUMENT
:
465 case SCF_ERROR_NOT_BOUND
:
466 case SCF_ERROR_CONNECTION_BROKEN
:
467 case SCF_ERROR_NOT_SET
:
468 case SCF_ERROR_DELETED
:
472 case SCF_ERROR_EXISTS
:
479 get_inst_enabled(const scf_instance_t
*inst
, const char *pgname
)
481 scf_propertygroup_t
*gpg
= NULL
;
482 scf_property_t
*eprop
= NULL
;
483 scf_value_t
*v
= NULL
;
484 scf_handle_t
*h
= NULL
;
488 if ((h
= scf_instance_handle(inst
)) == NULL
)
491 if ((gpg
= scf_pg_create(h
)) == NULL
||
492 (eprop
= scf_property_create(h
)) == NULL
||
493 (v
= scf_value_create(h
)) == NULL
)
496 if (scf_instance_get_pg(inst
, pgname
, gpg
) ||
497 scf_pg_get_property(gpg
, SCF_PROPERTY_ENABLED
, eprop
) ||
498 scf_property_get_value(eprop
, v
) ||
499 scf_value_get_boolean(v
, &enabled
))
505 scf_property_destroy(eprop
);
506 scf_value_destroy(v
);
511 * set_inst_enabled() is a "master" enable/disable call that takes the
512 * instance and the desired state for the enabled bit in the instance's
513 * named property group. If the group doesn't exist, it's created with the
514 * given flags. Called by smf_{dis,en}able_instance().
517 set_inst_enabled(const scf_instance_t
*inst
, uint8_t desired
,
518 const char *pgname
, uint32_t pgflags
)
520 scf_transaction_t
*tx
= NULL
;
521 scf_transaction_entry_t
*ent
= NULL
;
522 scf_propertygroup_t
*gpg
= NULL
;
523 scf_property_t
*eprop
= NULL
;
524 scf_value_t
*v
= NULL
;
525 scf_handle_t
*h
= NULL
;
530 if ((h
= scf_instance_handle(inst
)) == NULL
)
533 if ((gpg
= scf_pg_create(h
)) == NULL
||
534 (eprop
= scf_property_create(h
)) == NULL
||
535 (v
= scf_value_create(h
)) == NULL
||
536 (tx
= scf_transaction_create(h
)) == NULL
||
537 (ent
= scf_entry_create(h
)) == NULL
)
541 if (scf_instance_get_pg(inst
, SCF_PG_GENERAL
, gpg
) == -1) {
542 if (scf_error() != SCF_ERROR_NOT_FOUND
)
545 if (scf_instance_add_pg(inst
, SCF_PG_GENERAL
,
546 SCF_GROUP_FRAMEWORK
, SCF_PG_GENERAL_FLAGS
, gpg
) == -1) {
547 if (scf_error() != SCF_ERROR_EXISTS
)
553 if (strcmp(pgname
, SCF_PG_GENERAL
) != 0) {
555 if (scf_instance_get_pg(inst
, pgname
, gpg
) == -1) {
556 if (scf_error() != SCF_ERROR_NOT_FOUND
)
559 if (scf_instance_add_pg(inst
, pgname
,
560 SCF_GROUP_FRAMEWORK
, pgflags
, gpg
) == -1) {
561 if (scf_error() != SCF_ERROR_EXISTS
)
568 if (scf_pg_get_property(gpg
, SCF_PROPERTY_ENABLED
, eprop
) == -1) {
569 if (scf_error() != SCF_ERROR_NOT_FOUND
)
576 * If it's already set the way we want, forgo the transaction.
578 if (scf_property_get_value(eprop
, v
) == -1) {
579 switch (scf_error()) {
580 case SCF_ERROR_CONSTRAINT_VIOLATED
:
581 case SCF_ERROR_NOT_FOUND
:
582 /* Misconfigured, so set anyway. */
589 if (scf_value_get_boolean(v
, &b
) == -1) {
590 if (scf_error() != SCF_ERROR_TYPE_MISMATCH
)
601 if (scf_transaction_start(tx
, gpg
) == -1)
604 if (transaction_property_set(tx
, ent
, SCF_PROPERTY_ENABLED
,
605 SCF_TYPE_BOOLEAN
) != 0) {
606 switch (scf_error()) {
607 case SCF_ERROR_CONNECTION_BROKEN
:
608 case SCF_ERROR_DELETED
:
612 case SCF_ERROR_HANDLE_MISMATCH
:
613 case SCF_ERROR_INVALID_ARGUMENT
:
614 case SCF_ERROR_NOT_BOUND
:
615 case SCF_ERROR_NOT_SET
:
616 bad_error("transaction_property_set",
621 scf_value_set_boolean(v
, desired
);
622 if (scf_entry_add_value(ent
, v
) == -1)
625 committed
= scf_transaction_commit(tx
);
629 scf_transaction_reset(tx
);
631 if (committed
== 0) { /* out-of-sync */
632 if (scf_pg_update(gpg
) == -1)
635 } while (committed
== 0);
640 scf_value_destroy(v
);
641 scf_entry_destroy(ent
);
642 scf_transaction_destroy(tx
);
643 scf_property_destroy(eprop
);
650 delete_inst_enabled(const scf_instance_t
*inst
, const char *pgname
)
652 scf_transaction_t
*tx
= NULL
;
653 scf_transaction_entry_t
*ent
= NULL
;
654 scf_propertygroup_t
*gpg
= NULL
;
655 scf_handle_t
*h
= NULL
;
659 if ((h
= scf_instance_handle(inst
)) == NULL
)
662 if ((gpg
= scf_pg_create(h
)) == NULL
||
663 (tx
= scf_transaction_create(h
)) == NULL
||
664 (ent
= scf_entry_create(h
)) == NULL
)
667 if (scf_instance_get_pg(inst
, pgname
, gpg
) != 0)
670 if (scf_transaction_start(tx
, gpg
) == -1 ||
671 scf_transaction_property_delete(tx
, ent
,
672 SCF_PROPERTY_ENABLED
) == -1 ||
673 (committed
= scf_transaction_commit(tx
)) == -1)
676 scf_transaction_reset(tx
);
678 if (committed
== 0 && scf_pg_update(gpg
) == -1)
680 } while (committed
== 0);
686 switch (scf_error()) {
687 case SCF_ERROR_DELETED
:
688 case SCF_ERROR_NOT_FOUND
:
694 scf_entry_destroy(ent
);
695 scf_transaction_destroy(tx
);
702 * Returns 0 on success or -1 on failure. On failure leaves scf_error() set to
703 * SCF_ERROR_HANDLE_DESTROYED - inst's handle has been destroyed
704 * SCF_ERROR_NOT_BOUND - inst's handle is not bound
705 * SCF_ERROR_CONNECTION_BROKEN - the repository connection was broken
706 * SCF_ERROR_NOT_SET - inst is not set
707 * SCF_ERROR_DELETED - inst was deleted
708 * SCF_ERROR_PERMISSION_DENIED
709 * SCF_ERROR_BACKEND_ACCESS
710 * SCF_ERROR_BACKEND_READONLY
713 set_inst_action_inst(scf_instance_t
*inst
, const char *action
)
716 scf_transaction_t
*tx
= NULL
;
717 scf_transaction_entry_t
*ent
= NULL
;
718 scf_propertygroup_t
*pg
= NULL
;
719 scf_property_t
*prop
= NULL
;
720 scf_value_t
*v
= NULL
;
725 if ((h
= scf_instance_handle(inst
)) == NULL
||
726 (pg
= scf_pg_create(h
)) == NULL
||
727 (prop
= scf_property_create(h
)) == NULL
||
728 (v
= scf_value_create(h
)) == NULL
||
729 (tx
= scf_transaction_create(h
)) == NULL
||
730 (ent
= scf_entry_create(h
)) == NULL
)
734 if (scf_instance_get_pg(inst
, SCF_PG_RESTARTER_ACTIONS
, pg
) == -1) {
735 switch (scf_error()) {
736 case SCF_ERROR_NOT_BOUND
:
737 case SCF_ERROR_CONNECTION_BROKEN
:
738 case SCF_ERROR_NOT_SET
:
739 case SCF_ERROR_DELETED
:
743 case SCF_ERROR_NOT_FOUND
:
746 case SCF_ERROR_HANDLE_MISMATCH
:
747 case SCF_ERROR_INVALID_ARGUMENT
:
748 bad_error("scf_instance_get_pg", scf_error());
751 /* Try creating the restarter_actions property group. */
753 if (scf_instance_add_pg(inst
, SCF_PG_RESTARTER_ACTIONS
,
754 SCF_PG_RESTARTER_ACTIONS_TYPE
,
755 SCF_PG_RESTARTER_ACTIONS_FLAGS
, pg
) == -1) {
756 switch (scf_error()) {
757 case SCF_ERROR_NOT_BOUND
:
758 case SCF_ERROR_CONNECTION_BROKEN
:
759 case SCF_ERROR_NOT_SET
:
760 case SCF_ERROR_DELETED
:
761 case SCF_ERROR_PERMISSION_DENIED
:
762 case SCF_ERROR_BACKEND_ACCESS
:
763 case SCF_ERROR_BACKEND_READONLY
:
767 case SCF_ERROR_EXISTS
:
770 case SCF_ERROR_HANDLE_MISMATCH
:
771 case SCF_ERROR_INVALID_ARGUMENT
:
772 bad_error("scf_instance_add_pg", scf_error());
778 timestamp
= gethrtime();
780 if (scf_pg_get_property(pg
, action
, prop
) != 0) {
781 switch (scf_error()) {
782 case SCF_ERROR_CONNECTION_BROKEN
:
786 case SCF_ERROR_DELETED
:
789 case SCF_ERROR_NOT_FOUND
:
792 case SCF_ERROR_HANDLE_MISMATCH
:
793 case SCF_ERROR_INVALID_ARGUMENT
:
794 case SCF_ERROR_NOT_BOUND
:
795 case SCF_ERROR_NOT_SET
:
796 bad_error("scf_pg_get_property", scf_error());
798 } else if (scf_property_get_value(prop
, v
) != 0) {
799 switch (scf_error()) {
800 case SCF_ERROR_CONNECTION_BROKEN
:
804 case SCF_ERROR_DELETED
:
807 case SCF_ERROR_CONSTRAINT_VIOLATED
:
808 case SCF_ERROR_NOT_FOUND
:
811 case SCF_ERROR_HANDLE_MISMATCH
:
812 case SCF_ERROR_NOT_BOUND
:
813 case SCF_ERROR_NOT_SET
:
814 bad_error("scf_property_get_value",
817 } else if (scf_value_get_integer(v
, &t
) != 0) {
818 bad_error("scf_value_get_integer", scf_error());
819 } else if (t
> timestamp
) {
823 if (scf_transaction_start(tx
, pg
) == -1) {
824 switch (scf_error()) {
825 case SCF_ERROR_NOT_BOUND
:
826 case SCF_ERROR_CONNECTION_BROKEN
:
827 case SCF_ERROR_PERMISSION_DENIED
:
828 case SCF_ERROR_BACKEND_ACCESS
:
829 case SCF_ERROR_BACKEND_READONLY
:
833 case SCF_ERROR_DELETED
:
836 case SCF_ERROR_HANDLE_MISMATCH
:
837 case SCF_ERROR_NOT_SET
:
838 case SCF_ERROR_IN_USE
:
839 bad_error("scf_transaction_start", scf_error());
843 if (transaction_property_set(tx
, ent
, action
,
844 SCF_TYPE_INTEGER
) != 0) {
845 switch (scf_error()) {
846 case SCF_ERROR_NOT_BOUND
:
847 case SCF_ERROR_CONNECTION_BROKEN
:
848 case SCF_ERROR_DELETED
:
852 case SCF_ERROR_HANDLE_MISMATCH
:
853 case SCF_ERROR_INVALID_ARGUMENT
:
854 case SCF_ERROR_NOT_SET
:
855 bad_error("transaction_property_set",
860 scf_value_set_integer(v
, timestamp
);
861 if (scf_entry_add_value(ent
, v
) == -1)
862 bad_error("scf_entry_add_value", scf_error());
864 trans
= scf_transaction_commit(tx
);
869 switch (scf_error()) {
870 case SCF_ERROR_CONNECTION_BROKEN
:
871 case SCF_ERROR_PERMISSION_DENIED
:
872 case SCF_ERROR_BACKEND_ACCESS
:
873 case SCF_ERROR_BACKEND_READONLY
:
877 case SCF_ERROR_DELETED
:
878 scf_transaction_reset(tx
);
881 case SCF_ERROR_INVALID_ARGUMENT
:
882 case SCF_ERROR_NOT_BOUND
:
883 case SCF_ERROR_NOT_SET
:
884 bad_error("scf_transaction_commit",
889 scf_transaction_reset(tx
);
890 if (scf_pg_update(pg
) == -1) {
891 switch (scf_error()) {
892 case SCF_ERROR_CONNECTION_BROKEN
:
896 case SCF_ERROR_DELETED
:
899 case SCF_ERROR_NOT_SET
:
900 case SCF_ERROR_NOT_BOUND
:
901 bad_error("scf_pg_update", scf_error());
909 scf_value_destroy(v
);
910 scf_entry_destroy(ent
);
911 scf_transaction_destroy(tx
);
912 scf_property_destroy(prop
);
918 set_inst_action(const char *fmri
, const char *action
)
921 scf_instance_t
*inst
;
924 h
= _scf_handle_create_and_bind(SCF_VERSION
);
928 inst
= scf_instance_create(h
);
931 if (scf_handle_decode_fmri(h
, fmri
, NULL
, NULL
, inst
, NULL
,
932 NULL
, SCF_DECODE_FMRI_EXACT
) == 0) {
933 ret
= set_inst_action_inst(inst
, action
);
934 if (ret
== -1 && scf_error() == SCF_ERROR_DELETED
)
935 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
937 switch (scf_error()) {
938 case SCF_ERROR_CONSTRAINT_VIOLATED
:
939 (void) scf_set_error(
940 SCF_ERROR_INVALID_ARGUMENT
);
942 case SCF_ERROR_DELETED
:
943 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
948 scf_instance_destroy(inst
);
951 scf_handle_destroy(h
);
958 * get_inst_state() gets the state string from an instance, and returns
959 * the SCF_STATE_* constant that coincides with the instance's current state.
963 get_inst_state(scf_instance_t
*inst
, scf_handle_t
*h
)
965 scf_propertygroup_t
*pg
= NULL
;
966 scf_property_t
*prop
= NULL
;
967 scf_value_t
*val
= NULL
;
968 char state
[MAX_SCF_STATE_STRING_SZ
];
971 if (((pg
= scf_pg_create(h
)) == NULL
) ||
972 ((prop
= scf_property_create(h
)) == NULL
) ||
973 ((val
= scf_value_create(h
)) == NULL
))
976 /* Pull the state property from the instance */
978 if (scf_instance_get_pg(inst
, SCF_PG_RESTARTER
, pg
) == -1 ||
979 scf_pg_get_property(pg
, SCF_PROPERTY_STATE
, prop
) == -1 ||
980 scf_property_get_value(prop
, val
) == -1) {
981 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
982 (void) scf_set_error(SCF_ERROR_INTERNAL
);
986 if (scf_value_get_astring(val
, state
, sizeof (state
)) <= 0) {
987 (void) scf_set_error(SCF_ERROR_INTERNAL
);
991 if (strcmp(state
, SCF_STATE_STRING_UNINIT
) == 0) {
992 ret
= SCF_STATE_UNINIT
;
993 } else if (strcmp(state
, SCF_STATE_STRING_MAINT
) == 0) {
994 ret
= SCF_STATE_MAINT
;
995 } else if (strcmp(state
, SCF_STATE_STRING_OFFLINE
) == 0) {
996 ret
= SCF_STATE_OFFLINE
;
997 } else if (strcmp(state
, SCF_STATE_STRING_DISABLED
) == 0) {
998 ret
= SCF_STATE_DISABLED
;
999 } else if (strcmp(state
, SCF_STATE_STRING_ONLINE
) == 0) {
1000 ret
= SCF_STATE_ONLINE
;
1001 } else if (strcmp(state
, SCF_STATE_STRING_DEGRADED
) == 0) {
1002 ret
= SCF_STATE_DEGRADED
;
1007 scf_property_destroy(prop
);
1008 (void) scf_value_destroy(val
);
1014 * Sets an instance to be enabled or disabled after reboot, using the
1015 * temporary (overriding) general_ovr property group to reflect the
1016 * present state, if it is different.
1019 set_inst_enabled_atboot(scf_instance_t
*inst
, uint8_t desired
)
1025 if ((persistent
= get_inst_enabled(inst
, SCF_PG_GENERAL
)) < 0) {
1026 if (scf_error() != SCF_ERROR_NOT_FOUND
)
1028 persistent
= B_FALSE
;
1030 if ((enabled
= get_inst_enabled(inst
, SCF_PG_GENERAL_OVR
)) < 0) {
1031 enabled
= persistent
;
1032 if (persistent
!= desired
) {
1034 * Temporarily store the present enabled state.
1036 if (set_inst_enabled(inst
, persistent
,
1037 SCF_PG_GENERAL_OVR
, SCF_PG_GENERAL_OVR_FLAGS
))
1041 if (persistent
!= desired
)
1042 if (set_inst_enabled(inst
, desired
, SCF_PG_GENERAL
,
1043 SCF_PG_GENERAL_FLAGS
))
1045 if (enabled
== desired
)
1046 ret
= delete_inst_enabled(inst
, SCF_PG_GENERAL_OVR
);
1055 set_inst_enabled_flags(const char *fmri
, int flags
, uint8_t desired
)
1059 scf_instance_t
*inst
;
1061 if (flags
& ~(SMF_TEMPORARY
| SMF_AT_NEXT_BOOT
) ||
1062 flags
& SMF_TEMPORARY
&& flags
& SMF_AT_NEXT_BOOT
) {
1063 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
1067 if ((h
= _scf_handle_create_and_bind(SCF_VERSION
)) == NULL
)
1070 if ((inst
= scf_instance_create(h
)) == NULL
) {
1071 scf_handle_destroy(h
);
1075 if (scf_handle_decode_fmri(h
, fmri
, NULL
, NULL
, inst
, NULL
, NULL
,
1076 SCF_DECODE_FMRI_EXACT
) == -1) {
1077 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED
)
1078 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
1082 if (flags
& SMF_AT_NEXT_BOOT
) {
1083 ret
= set_inst_enabled_atboot(inst
, desired
);
1085 if (set_inst_enabled(inst
, desired
, flags
& SMF_TEMPORARY
?
1086 SCF_PG_GENERAL_OVR
: SCF_PG_GENERAL
, flags
& SMF_TEMPORARY
?
1087 SCF_PG_GENERAL_OVR_FLAGS
: SCF_PG_GENERAL_FLAGS
))
1091 * Make the persistent value effective by deleting the
1094 if (flags
& SMF_TEMPORARY
)
1097 ret
= delete_inst_enabled(inst
, SCF_PG_GENERAL_OVR
);
1101 scf_instance_destroy(inst
);
1102 scf_handle_destroy(h
);
1103 if (ret
== -1 && scf_error() == SCF_ERROR_DELETED
)
1104 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
1109 * Create and return a pg from the instance associated with the given handle.
1110 * This function is only called in scf_transaction_setup and
1111 * scf_transaction_restart where the h->rh_instance pointer is properly filled
1112 * in by scf_general_setup_pg().
1114 static scf_propertygroup_t
*
1115 get_instance_pg(scf_simple_handle_t
*simple_h
)
1117 scf_propertygroup_t
*ret_pg
= scf_pg_create(simple_h
->h
);
1121 if (ret_pg
== NULL
) {
1125 namelen
= scf_limit(SCF_LIMIT_MAX_NAME_LENGTH
) + 1;
1126 assert(namelen
> 0);
1128 if ((pg_name
= malloc(namelen
)) == NULL
) {
1129 if (scf_error() == SCF_ERROR_NOT_SET
) {
1130 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1135 if (scf_pg_get_name(simple_h
->running_pg
, pg_name
, namelen
) < 0) {
1136 if (scf_error() == SCF_ERROR_NOT_SET
) {
1137 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1142 /* Get pg from instance */
1143 if (scf_instance_get_pg(simple_h
->inst
, pg_name
, ret_pg
) == -1) {
1151 smf_enable_instance(const char *fmri
, int flags
)
1153 return (set_inst_enabled_flags(fmri
, flags
, B_TRUE
));
1157 smf_disable_instance(const char *fmri
, int flags
)
1159 return (set_inst_enabled_flags(fmri
, flags
, B_FALSE
));
1163 _smf_refresh_instance_i(scf_instance_t
*inst
)
1165 return (set_inst_action_inst(inst
, SCF_PROPERTY_REFRESH
));
1169 _smf_refresh_all_instances(scf_service_t
*s
)
1171 scf_handle_t
*h
= scf_service_handle(s
);
1172 scf_instance_t
*i
= scf_instance_create(h
);
1173 scf_iter_t
*it
= scf_iter_create(h
);
1176 if (h
== NULL
|| i
== NULL
|| it
== NULL
)
1179 if (scf_iter_service_instances(it
, s
) != 0)
1182 while ((err
= scf_iter_next_instance(it
, i
)) == 1)
1183 if (_smf_refresh_instance_i(i
) != 0)
1191 scf_instance_destroy(i
);
1192 scf_iter_destroy(it
);
1198 smf_refresh_instance(const char *instance
)
1200 return (set_inst_action(instance
, SCF_PROPERTY_REFRESH
));
1204 smf_restart_instance(const char *instance
)
1206 return (set_inst_action(instance
, SCF_PROPERTY_RESTART
));
1210 smf_maintain_instance(const char *instance
, int flags
)
1212 if (flags
& SMF_TEMPORARY
)
1213 return (set_inst_action(instance
,
1214 (flags
& SMF_IMMEDIATE
) ?
1215 SCF_PROPERTY_MAINT_ON_IMMTEMP
:
1216 SCF_PROPERTY_MAINT_ON_TEMPORARY
));
1218 return (set_inst_action(instance
,
1219 (flags
& SMF_IMMEDIATE
) ?
1220 SCF_PROPERTY_MAINT_ON_IMMEDIATE
:
1221 SCF_PROPERTY_MAINT_ON
));
1225 smf_degrade_instance(const char *instance
, int flags
)
1227 scf_simple_prop_t
*prop
;
1228 const char *state_str
;
1230 if (flags
& SMF_TEMPORARY
)
1231 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1233 if ((prop
= scf_simple_prop_get(NULL
, instance
, SCF_PG_RESTARTER
,
1234 SCF_PROPERTY_STATE
)) == NULL
)
1235 return (SCF_FAILED
);
1237 if ((state_str
= scf_simple_prop_next_astring(prop
)) == NULL
) {
1238 scf_simple_prop_free(prop
);
1239 return (SCF_FAILED
);
1242 if (strcmp(state_str
, SCF_STATE_STRING_ONLINE
) != 0) {
1243 scf_simple_prop_free(prop
);
1244 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
));
1246 scf_simple_prop_free(prop
);
1248 return (set_inst_action(instance
, (flags
& SMF_IMMEDIATE
) ?
1249 SCF_PROPERTY_DEGRADE_IMMEDIATE
: SCF_PROPERTY_DEGRADED
));
1253 smf_restore_instance(const char *instance
)
1255 scf_simple_prop_t
*prop
;
1256 const char *state_str
;
1259 if ((prop
= scf_simple_prop_get(NULL
, instance
, SCF_PG_RESTARTER
,
1260 SCF_PROPERTY_STATE
)) == NULL
)
1261 return (SCF_FAILED
);
1263 if ((state_str
= scf_simple_prop_next_astring(prop
)) == NULL
) {
1264 scf_simple_prop_free(prop
);
1265 return (SCF_FAILED
);
1268 if (strcmp(state_str
, SCF_STATE_STRING_MAINT
) == 0) {
1269 ret
= set_inst_action(instance
, SCF_PROPERTY_MAINT_OFF
);
1270 } else if (strcmp(state_str
, SCF_STATE_STRING_DEGRADED
) == 0) {
1271 ret
= set_inst_action(instance
, SCF_PROPERTY_RESTORE
);
1273 ret
= scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
);
1276 scf_simple_prop_free(prop
);
1281 smf_get_state(const char *instance
)
1283 scf_simple_prop_t
*prop
;
1284 const char *state_str
;
1287 if ((prop
= scf_simple_prop_get(NULL
, instance
, SCF_PG_RESTARTER
,
1288 SCF_PROPERTY_STATE
)) == NULL
)
1291 if ((state_str
= scf_simple_prop_next_astring(prop
)) == NULL
) {
1292 scf_simple_prop_free(prop
);
1296 if ((ret
= strdup(state_str
)) == NULL
)
1297 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1299 scf_simple_prop_free(prop
);
1304 * scf_general_pg_setup(fmri, pg_name)
1305 * Create a scf_simple_handle_t and fill in the instance, snapshot, and
1306 * property group fields associated with the given fmri and property group
1310 * Null on error with scf_error set to:
1311 * SCF_ERROR_HANDLE_MISMATCH,
1312 * SCF_ERROR_INVALID_ARGUMENT,
1313 * SCF_ERROR_CONSTRAINT_VIOLATED,
1314 * SCF_ERROR_NOT_FOUND,
1315 * SCF_ERROR_NOT_SET,
1316 * SCF_ERROR_DELETED,
1317 * SCF_ERROR_NOT_BOUND,
1318 * SCF_ERROR_CONNECTION_BROKEN,
1319 * SCF_ERROR_INTERNAL,
1320 * SCF_ERROR_NO_RESOURCES,
1321 * SCF_ERROR_BACKEND_ACCESS
1323 scf_simple_handle_t
*
1324 scf_general_pg_setup(const char *fmri
, const char *pg_name
)
1326 scf_simple_handle_t
*ret
;
1328 ret
= uu_zalloc(sizeof (*ret
));
1330 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1334 ret
->h
= _scf_handle_create_and_bind(SCF_VERSION
);
1335 ret
->inst
= scf_instance_create(ret
->h
);
1336 ret
->snap
= scf_snapshot_create(ret
->h
);
1337 ret
->running_pg
= scf_pg_create(ret
->h
);
1340 if ((ret
->h
== NULL
) || (ret
->inst
== NULL
) ||
1341 (ret
->snap
== NULL
) || (ret
->running_pg
== NULL
)) {
1345 if (scf_handle_decode_fmri(ret
->h
, fmri
, NULL
, NULL
, ret
->inst
,
1346 NULL
, NULL
, 0) == -1) {
1350 if ((scf_instance_get_snapshot(ret
->inst
, "running", ret
->snap
))
1355 if (scf_instance_get_pg_composed(ret
->inst
, ret
->snap
, pg_name
,
1356 ret
->running_pg
) != 0) {
1363 scf_simple_handle_destroy(ret
);
1368 * scf_transaction_setup(h)
1369 * creates and starts the transaction
1371 * transaction on success
1372 * NULL on failure with scf_error set to:
1373 * SCF_ERROR_NO_MEMORY,
1374 * SCF_ERROR_INVALID_ARGUMENT,
1375 * SCF_ERROR_HANDLE_DESTROYED,
1376 * SCF_ERROR_INTERNAL,
1377 * SCF_ERROR_NO_RESOURCES,
1378 * SCF_ERROR_NOT_BOUND,
1379 * SCF_ERROR_CONNECTION_BROKEN,
1380 * SCF_ERROR_NOT_SET,
1381 * SCF_ERROR_DELETED,
1382 * SCF_ERROR_CONSTRAINT_VIOLATED,
1383 * SCF_ERROR_HANDLE_MISMATCH,
1384 * SCF_ERROR_BACKEND_ACCESS,
1388 scf_transaction_setup(scf_simple_handle_t
*simple_h
)
1390 scf_transaction_t
*tx
= NULL
;
1392 if ((tx
= scf_transaction_create(simple_h
->h
)) == NULL
) {
1396 if ((simple_h
->editing_pg
= get_instance_pg(simple_h
)) == NULL
) {
1400 if (scf_transaction_start(tx
, simple_h
->editing_pg
) == -1) {
1401 scf_pg_destroy(simple_h
->editing_pg
);
1402 simple_h
->editing_pg
= NULL
;
1410 scf_transaction_restart(scf_simple_handle_t
*simple_h
, scf_transaction_t
*tx
)
1412 scf_transaction_reset(tx
);
1414 if (scf_pg_update(simple_h
->editing_pg
) == -1) {
1415 return (SCF_FAILED
);
1418 if (scf_transaction_start(tx
, simple_h
->editing_pg
) == -1) {
1419 return (SCF_FAILED
);
1422 return (SCF_SUCCESS
);
1426 * scf_read_count_property(scf_simple_handle_t *simple_h, char *prop_name,
1427 * uint64_t *ret_count)
1429 * For the given property name, return the count value.
1432 * SCF_FAILED on failure with scf_error() set to:
1433 * SCF_ERROR_HANDLE_DESTROYED
1434 * SCF_ERROR_INTERNAL
1435 * SCF_ERROR_NO_RESOURCES
1436 * SCF_ERROR_NO_MEMORY
1437 * SCF_ERROR_HANDLE_MISMATCH
1438 * SCF_ERROR_INVALID_ARGUMENT
1439 * SCF_ERROR_NOT_BOUND
1440 * SCF_ERROR_CONNECTION_BROKEN
1443 * SCF_ERROR_BACKEND_ACCESS
1444 * SCF_ERROR_CONSTRAINT_VIOLATED
1445 * SCF_ERROR_TYPE_MISMATCH
1448 scf_read_count_property(
1449 scf_simple_handle_t
*simple_h
,
1451 uint64_t *ret_count
)
1453 scf_property_t
*prop
= scf_property_create(simple_h
->h
);
1454 scf_value_t
*val
= scf_value_create(simple_h
->h
);
1455 int ret
= SCF_FAILED
;
1457 if ((val
== NULL
) || (prop
== NULL
)) {
1462 * Get the property struct that goes with this property group and
1465 if (scf_pg_get_property(simple_h
->running_pg
, prop_name
, prop
) != 0) {
1469 /* Get the value structure */
1470 if (scf_property_get_value(prop
, val
) == -1) {
1475 * Now get the count value.
1477 if (scf_value_get_count(val
, ret_count
) == -1) {
1484 scf_property_destroy(prop
);
1485 scf_value_destroy(val
);
1490 * scf_trans_add_count_property(trans, propname, count, create_flag)
1492 * Set a count property transaction entry into the pending SMF transaction.
1493 * The transaction is created and committed outside of this function.
1496 * SCF_FAILED on failure with scf_error() set to:
1497 * SCF_ERROR_HANDLE_DESTROYED,
1498 * SCF_ERROR_INVALID_ARGUMENT,
1499 * SCF_ERROR_NO_MEMORY,
1500 * SCF_ERROR_HANDLE_MISMATCH,
1501 * SCF_ERROR_NOT_SET,
1503 * SCF_ERROR_NOT_FOUND,
1505 * SCF_ERROR_TYPE_MISMATCH,
1506 * SCF_ERROR_NOT_BOUND,
1507 * SCF_ERROR_CONNECTION_BROKEN,
1508 * SCF_ERROR_INTERNAL,
1509 * SCF_ERROR_DELETED,
1510 * SCF_ERROR_NO_RESOURCES,
1511 * SCF_ERROR_BACKEND_ACCESS
1514 scf_set_count_property(
1515 scf_transaction_t
*trans
,
1518 boolean_t create_flag
)
1520 scf_handle_t
*handle
= scf_transaction_handle(trans
);
1521 scf_value_t
*value
= scf_value_create(handle
);
1522 scf_transaction_entry_t
*entry
= scf_entry_create(handle
);
1524 if ((value
== NULL
) || (entry
== NULL
)) {
1525 return (SCF_FAILED
);
1529 * Property must be set in transaction and won't take
1530 * effect until the transaction is committed.
1532 * Attempt to change the current value. However, create new property
1533 * if it doesn't exist and the create flag is set.
1535 if (scf_transaction_property_change(trans
, entry
, propname
,
1536 SCF_TYPE_COUNT
) == 0) {
1537 scf_value_set_count(value
, count
);
1538 if (scf_entry_add_value(entry
, value
) == 0) {
1539 return (SCF_SUCCESS
);
1542 if ((create_flag
== B_TRUE
) &&
1543 (scf_error() == SCF_ERROR_NOT_FOUND
)) {
1544 if (scf_transaction_property_new(trans
, entry
, propname
,
1545 SCF_TYPE_COUNT
) == 0) {
1546 scf_value_set_count(value
, count
);
1547 if (scf_entry_add_value(entry
, value
) == 0) {
1548 return (SCF_SUCCESS
);
1555 * cleanup if there were any errors that didn't leave these
1556 * values where they would be cleaned up later.
1559 scf_value_destroy(value
);
1561 scf_entry_destroy(entry
);
1562 return (SCF_FAILED
);
1566 scf_simple_walk_instances(uint_t state_flags
, void *private,
1567 int (*inst_callback
)(scf_handle_t
*, scf_instance_t
*, void *))
1569 scf_scope_t
*scope
= NULL
;
1570 scf_service_t
*svc
= NULL
;
1571 scf_instance_t
*inst
= NULL
;
1572 scf_iter_t
*svc_iter
= NULL
, *inst_iter
= NULL
;
1573 scf_handle_t
*h
= NULL
;
1574 int ret
= SCF_FAILED
;
1575 int svc_iter_ret
, inst_iter_ret
;
1578 if ((h
= _scf_handle_create_and_bind(SCF_VERSION
)) == NULL
)
1581 if (((scope
= scf_scope_create(h
)) == NULL
) ||
1582 ((svc
= scf_service_create(h
)) == NULL
) ||
1583 ((inst
= scf_instance_create(h
)) == NULL
) ||
1584 ((svc_iter
= scf_iter_create(h
)) == NULL
) ||
1585 ((inst_iter
= scf_iter_create(h
)) == NULL
))
1589 * Get the local scope, and set up nested iteration through every
1590 * local service, and every instance of every service.
1593 if ((scf_handle_get_local_scope(h
, scope
) != SCF_SUCCESS
) ||
1594 (scf_iter_scope_services(svc_iter
, scope
) != SCF_SUCCESS
))
1597 while ((svc_iter_ret
= scf_iter_next_service(svc_iter
, svc
)) > 0) {
1599 if ((scf_iter_service_instances(inst_iter
, svc
)) !=
1603 while ((inst_iter_ret
=
1604 scf_iter_next_instance(inst_iter
, inst
)) > 0) {
1606 * If get_inst_state fails from an internal error,
1607 * IE, being unable to get the property group or
1608 * property containing the state of the instance,
1609 * we continue instead of failing, as this might just
1610 * be an improperly configured instance.
1612 if ((inst_state
= get_inst_state(inst
, h
)) == -1) {
1613 if (scf_error() == SCF_ERROR_INTERNAL
) {
1620 if ((uint_t
)inst_state
& state_flags
) {
1621 if (inst_callback(h
, inst
, private) !=
1623 (void) scf_set_error(
1624 SCF_ERROR_CALLBACK_FAILED
);
1630 if (inst_iter_ret
== -1)
1632 scf_iter_reset(inst_iter
);
1635 if (svc_iter_ret
!= -1)
1639 scf_scope_destroy(scope
);
1640 scf_service_destroy(svc
);
1641 scf_instance_destroy(inst
);
1642 scf_iter_destroy(svc_iter
);
1643 scf_iter_destroy(inst_iter
);
1644 scf_handle_destroy(h
);
1651 scf_simple_prop_get(scf_handle_t
*hin
, const char *instance
, const char *pgname
,
1652 const char *propname
)
1654 char *fmri_buf
, *svcfmri
= NULL
;
1656 scf_property_t
*prop
= NULL
;
1657 scf_service_t
*svc
= NULL
;
1658 scf_simple_prop_t
*ret
;
1659 scf_handle_t
*h
= NULL
;
1660 boolean_t local_h
= B_TRUE
;
1662 /* If the user passed in a handle, use it. */
1668 if (local_h
&& ((h
= _scf_handle_create_and_bind(SCF_VERSION
)) == NULL
))
1671 if ((fmri_buf
= assemble_fmri(h
, instance
, pgname
, propname
)) == NULL
) {
1673 scf_handle_destroy(h
);
1677 if ((svc
= scf_service_create(h
)) == NULL
||
1678 (prop
= scf_property_create(h
)) == NULL
)
1680 if (scf_handle_decode_fmri(h
, fmri_buf
, NULL
, NULL
, NULL
, NULL
, prop
,
1681 SCF_DECODE_FMRI_REQUIRE_INSTANCE
) == -1) {
1682 switch (scf_error()) {
1684 * If the property isn't found in the instance, we grab the
1685 * underlying service, create an FMRI out of it, and then
1686 * query the datastore again at the service level for the
1689 case SCF_ERROR_NOT_FOUND
:
1690 if (scf_handle_decode_fmri(h
, fmri_buf
, NULL
, svc
,
1691 NULL
, NULL
, NULL
, SCF_DECODE_FMRI_TRUNCATE
) == -1)
1694 fmri_sz
= scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH
) + 1;
1695 assert(fmri_sz
> 0);
1697 if (scf_service_to_fmri(svc
, fmri_buf
, fmri_sz
) == -1)
1699 if ((svcfmri
= assemble_fmri(h
, fmri_buf
, pgname
,
1702 if (scf_handle_decode_fmri(h
, svcfmri
, NULL
, NULL
,
1703 NULL
, NULL
, prop
, 0) == -1) {
1709 case SCF_ERROR_CONSTRAINT_VIOLATED
:
1710 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
1716 * At this point, we've successfully pulled the property from the
1717 * datastore, and simply need to copy its innards into an
1718 * scf_simple_prop_t.
1720 if ((ret
= fill_prop(prop
, pgname
, propname
, h
)) == NULL
)
1723 scf_service_destroy(svc
);
1724 scf_property_destroy(prop
);
1727 scf_handle_destroy(h
);
1731 * Exit point for a successful call. Below this line are exit points
1732 * for failures at various stages during the function.
1736 scf_service_destroy(svc
);
1737 scf_property_destroy(prop
);
1741 scf_handle_destroy(h
);
1747 scf_simple_prop_free(scf_simple_prop_t
*prop
)
1754 free(prop
->pr_propname
);
1755 free(prop
->pr_pgname
);
1756 switch (prop
->pr_type
) {
1757 case SCF_TYPE_OPAQUE
: {
1758 for (i
= 0; i
< prop
->pr_numvalues
; i
++) {
1759 free(prop
->pr_vallist
[i
].pv_opaque
.o_value
);
1763 case SCF_TYPE_ASTRING
:
1764 case SCF_TYPE_USTRING
:
1766 case SCF_TYPE_HOSTNAME
:
1767 case SCF_TYPE_NET_ADDR
:
1768 case SCF_TYPE_NET_ADDR_V4
:
1769 case SCF_TYPE_NET_ADDR_V6
:
1771 case SCF_TYPE_FMRI
: {
1772 for (i
= 0; i
< prop
->pr_numvalues
; i
++) {
1773 free(prop
->pr_vallist
[i
].pv_str
);
1780 free(prop
->pr_vallist
);
1785 scf_simple_app_props_t
*
1786 scf_simple_app_props_get(scf_handle_t
*hin
, const char *inst_fmri
)
1788 scf_instance_t
*inst
= NULL
;
1789 scf_service_t
*svc
= NULL
;
1790 scf_propertygroup_t
*pg
= NULL
;
1791 scf_property_t
*prop
= NULL
;
1792 scf_simple_app_props_t
*ret
= NULL
;
1793 scf_iter_t
*pgiter
= NULL
, *propiter
= NULL
;
1794 struct scf_simple_pg
*thispg
= NULL
, *nextpg
;
1795 scf_simple_prop_t
*thisprop
, *nextprop
;
1796 scf_handle_t
*h
= NULL
;
1797 int pgiter_ret
, propiter_ret
;
1799 char *propname
= NULL
, *pgname
= NULL
, *sys_fmri
;
1801 boolean_t local_h
= B_TRUE
;
1803 /* If the user passed in a handle, use it. */
1809 if (local_h
&& ((h
= _scf_handle_create_and_bind(SCF_VERSION
)) == NULL
))
1812 if (inst_fmri
== NULL
) {
1813 if ((namelen
= scf_myname(h
, NULL
, 0)) == -1) {
1815 scf_handle_destroy(h
);
1818 if ((sys_fmri
= malloc(namelen
+ 1)) == NULL
) {
1820 scf_handle_destroy(h
);
1821 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1824 if (scf_myname(h
, sys_fmri
, namelen
+ 1) == -1) {
1826 scf_handle_destroy(h
);
1831 if ((sys_fmri
= strdup(inst_fmri
)) == NULL
) {
1833 scf_handle_destroy(h
);
1834 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1839 namelen
= scf_limit(SCF_LIMIT_MAX_NAME_LENGTH
) + 1;
1840 assert(namelen
> 0);
1842 if ((inst
= scf_instance_create(h
)) == NULL
||
1843 (svc
= scf_service_create(h
)) == NULL
||
1844 (pgiter
= scf_iter_create(h
)) == NULL
||
1845 (propiter
= scf_iter_create(h
)) == NULL
||
1846 (pg
= scf_pg_create(h
)) == NULL
||
1847 (prop
= scf_property_create(h
)) == NULL
) {
1852 if (scf_handle_decode_fmri(h
, sys_fmri
, NULL
, svc
, inst
, NULL
, NULL
,
1853 SCF_DECODE_FMRI_REQUIRE_INSTANCE
) == -1) {
1855 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED
)
1856 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
1860 if ((ret
= malloc(sizeof (*ret
))) == NULL
||
1861 (thispg
= malloc(sizeof (*thispg
))) == NULL
||
1862 (propname
= malloc(namelen
)) == NULL
||
1863 (pgname
= malloc(namelen
)) == NULL
) {
1867 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1871 ret
->ap_fmri
= sys_fmri
;
1872 thispg
->pg_name
= NULL
;
1873 thispg
->pg_proplist
= NULL
;
1874 thispg
->pg_next
= NULL
;
1875 ret
->ap_pglist
= thispg
;
1877 if (scf_iter_service_pgs_typed(pgiter
, svc
, SCF_GROUP_APPLICATION
) !=
1879 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1880 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1884 while ((pgiter_ret
= scf_iter_next_pg(pgiter
, pg
)) == 1) {
1885 if (thispg
->pg_name
!= NULL
) {
1886 if ((nextpg
= malloc(sizeof (*nextpg
))) == NULL
) {
1887 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1890 nextpg
->pg_name
= NULL
;
1891 nextpg
->pg_next
= NULL
;
1892 nextpg
->pg_proplist
= NULL
;
1893 thispg
->pg_next
= nextpg
;
1896 /* This is the first iteration */
1900 if ((nextpg
->pg_name
= malloc(namelen
)) == NULL
) {
1901 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1905 if (scf_pg_get_name(pg
, nextpg
->pg_name
, namelen
) < 0) {
1906 if (scf_error() == SCF_ERROR_NOT_SET
)
1907 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1913 scf_iter_reset(propiter
);
1915 if (scf_iter_pg_properties(propiter
, pg
) != 0) {
1916 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1917 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1921 while ((propiter_ret
= scf_iter_next_property(propiter
, prop
))
1923 if (scf_property_get_name(prop
, propname
, namelen
) <
1925 if (scf_error() == SCF_ERROR_NOT_SET
)
1926 (void) scf_set_error(
1927 SCF_ERROR_INTERNAL
);
1930 if (thisprop
!= NULL
) {
1931 if ((nextprop
= fill_prop(prop
,
1932 nextpg
->pg_name
, propname
, h
)) == NULL
)
1934 thisprop
->pr_next
= nextprop
;
1935 thisprop
= nextprop
;
1937 /* This is the first iteration */
1938 if ((thisprop
= fill_prop(prop
,
1939 nextpg
->pg_name
, propname
, h
)) == NULL
)
1941 nextpg
->pg_proplist
= thisprop
;
1942 nextprop
= thisprop
;
1944 nextprop
->pr_pg
= nextpg
;
1945 nextprop
->pr_next
= NULL
;
1948 if (propiter_ret
== -1) {
1949 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1950 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1955 if (pgiter_ret
== -1) {
1956 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1957 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1962 * At this point, we've filled the scf_simple_app_props_t with all the
1963 * properties at the service level. Now we iterate over all the
1964 * properties at the instance level, overwriting any duplicate
1965 * properties, in order to provide service/instance composition.
1968 scf_iter_reset(pgiter
);
1969 scf_iter_reset(propiter
);
1971 if (scf_iter_instance_pgs_typed(pgiter
, inst
, SCF_GROUP_APPLICATION
)
1973 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1974 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1978 while ((pgiter_ret
= scf_iter_next_pg(pgiter
, pg
)) == 1) {
1980 thispg
= ret
->ap_pglist
;
1984 * Find either the end of the list, so we can append the
1985 * property group, or an existing property group that matches
1986 * it, so we can insert/overwrite its properties.
1989 if (scf_pg_get_name(pg
, pgname
, namelen
) < 0) {
1990 if (scf_error() == SCF_ERROR_NOT_SET
)
1991 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1995 while ((thispg
!= NULL
) && (thispg
->pg_name
!= NULL
)) {
1996 if (strcmp(thispg
->pg_name
, pgname
) == 0) {
2000 if (thispg
->pg_next
== NULL
)
2003 thispg
= thispg
->pg_next
;
2006 scf_iter_reset(propiter
);
2008 if (scf_iter_pg_properties(propiter
, pg
) != 0) {
2009 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
2010 (void) scf_set_error(SCF_ERROR_INTERNAL
);
2016 * insert_app_props inserts or overwrites the
2017 * properties in thispg.
2020 if (insert_app_props(propiter
, pgname
, propname
,
2021 thispg
, prop
, namelen
, h
) == -1)
2026 * If the property group wasn't found, we're adding
2027 * a newly allocated property group to the end of the
2031 if ((nextpg
= malloc(sizeof (*nextpg
))) == NULL
) {
2032 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2035 nextpg
->pg_next
= NULL
;
2036 nextpg
->pg_proplist
= NULL
;
2039 if ((nextpg
->pg_name
= strdup(pgname
)) == NULL
) {
2040 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2045 if (thispg
->pg_name
== NULL
) {
2047 ret
->ap_pglist
= nextpg
;
2049 thispg
->pg_next
= nextpg
;
2052 while ((propiter_ret
=
2053 scf_iter_next_property(propiter
, prop
)) == 1) {
2054 if (scf_property_get_name(prop
, propname
,
2056 if (scf_error() == SCF_ERROR_NOT_SET
)
2057 (void) scf_set_error(
2058 SCF_ERROR_INTERNAL
);
2061 if (thisprop
!= NULL
) {
2062 if ((nextprop
= fill_prop(prop
,
2063 pgname
, propname
, h
)) ==
2066 thisprop
->pr_next
= nextprop
;
2067 thisprop
= nextprop
;
2069 /* This is the first iteration */
2070 if ((thisprop
= fill_prop(prop
,
2071 pgname
, propname
, h
)) ==
2074 nextpg
->pg_proplist
= thisprop
;
2075 nextprop
= thisprop
;
2077 nextprop
->pr_pg
= nextpg
;
2078 nextprop
->pr_next
= NULL
;
2081 if (propiter_ret
== -1) {
2082 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
2083 (void) scf_set_error(
2084 SCF_ERROR_INTERNAL
);
2091 if (pgiter_ret
== -1) {
2092 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
2093 (void) scf_set_error(SCF_ERROR_INTERNAL
);
2097 if (ret
->ap_pglist
->pg_name
== NULL
)
2100 scf_iter_destroy(pgiter
);
2101 scf_iter_destroy(propiter
);
2103 scf_property_destroy(prop
);
2104 scf_instance_destroy(inst
);
2105 scf_service_destroy(svc
);
2109 scf_handle_destroy(h
);
2114 * Exit point for a successful call. Below this line are exit points
2115 * for failures at various stages during the function.
2119 scf_simple_app_props_free(ret
);
2122 scf_iter_destroy(pgiter
);
2123 scf_iter_destroy(propiter
);
2125 scf_property_destroy(prop
);
2126 scf_instance_destroy(inst
);
2127 scf_service_destroy(svc
);
2131 scf_handle_destroy(h
);
2137 scf_simple_app_props_free(scf_simple_app_props_t
*propblock
)
2139 struct scf_simple_pg
*pgthis
, *pgnext
;
2140 scf_simple_prop_t
*propthis
, *propnext
;
2142 if ((propblock
== NULL
) || (propblock
->ap_pglist
== NULL
))
2145 for (pgthis
= propblock
->ap_pglist
; pgthis
!= NULL
; pgthis
= pgnext
) {
2146 pgnext
= pgthis
->pg_next
;
2148 propthis
= pgthis
->pg_proplist
;
2150 while (propthis
!= NULL
) {
2151 propnext
= propthis
->pr_next
;
2152 scf_simple_prop_free(propthis
);
2153 propthis
= propnext
;
2156 free(pgthis
->pg_name
);
2160 free(propblock
->ap_fmri
);
2164 const scf_simple_prop_t
*
2165 scf_simple_app_props_next(const scf_simple_app_props_t
*propblock
,
2166 scf_simple_prop_t
*last
)
2168 struct scf_simple_pg
*this;
2170 if (propblock
== NULL
) {
2171 (void) scf_set_error(SCF_ERROR_NOT_SET
);
2175 this = propblock
->ap_pglist
;
2178 * We're looking for the first property in this block if last is
2183 /* An empty pglist is legal, it just means no properties */
2185 (void) scf_set_error(SCF_ERROR_NONE
);
2189 * Walk until we find a pg with a property in it, or we run
2190 * out of property groups.
2192 while ((this->pg_proplist
== NULL
) && (this->pg_next
!= NULL
))
2193 this = this->pg_next
;
2195 if (this->pg_proplist
== NULL
) {
2196 (void) scf_set_error(SCF_ERROR_NONE
);
2200 return (this->pg_proplist
);
2204 * If last isn't NULL, then return the next prop in the property group,
2205 * or walk the property groups until we find another property, or
2206 * run out of property groups.
2208 if (last
->pr_next
!= NULL
)
2209 return (last
->pr_next
);
2211 if (last
->pr_pg
->pg_next
== NULL
) {
2212 (void) scf_set_error(SCF_ERROR_NONE
);
2216 this = last
->pr_pg
->pg_next
;
2218 while ((this->pg_proplist
== NULL
) && (this->pg_next
!= NULL
))
2219 this = this->pg_next
;
2221 if (this->pg_proplist
== NULL
) {
2222 (void) scf_set_error(SCF_ERROR_NONE
);
2226 return (this->pg_proplist
);
2229 const scf_simple_prop_t
*
2230 scf_simple_app_props_search(const scf_simple_app_props_t
*propblock
,
2231 const char *pgname
, const char *propname
)
2233 struct scf_simple_pg
*pg
;
2234 scf_simple_prop_t
*prop
;
2236 if ((propblock
== NULL
) || (propname
== NULL
)) {
2237 (void) scf_set_error(SCF_ERROR_NOT_SET
);
2241 pg
= propblock
->ap_pglist
;
2244 * If pgname is NULL, we're searching the default application
2245 * property group, otherwise we look for the specified group.
2247 if (pgname
== NULL
) {
2248 while ((pg
!= NULL
) &&
2249 (strcmp(SCF_PG_APP_DEFAULT
, pg
->pg_name
) != 0))
2252 while ((pg
!= NULL
) && (strcmp(pgname
, pg
->pg_name
) != 0))
2257 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
2261 prop
= pg
->pg_proplist
;
2263 while ((prop
!= NULL
) && (strcmp(propname
, prop
->pr_propname
) != 0))
2264 prop
= prop
->pr_next
;
2267 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
2275 scf_simple_prop_next_reset(scf_simple_prop_t
*prop
)
2283 scf_simple_prop_numvalues(const scf_simple_prop_t
*prop
)
2286 return (scf_set_error(SCF_ERROR_NOT_SET
));
2288 return (prop
->pr_numvalues
);
2293 scf_simple_prop_type(const scf_simple_prop_t
*prop
)
2296 return (scf_set_error(SCF_ERROR_NOT_SET
));
2298 return (prop
->pr_type
);
2303 scf_simple_prop_name(const scf_simple_prop_t
*prop
)
2305 if ((prop
== NULL
) || (prop
->pr_propname
== NULL
)) {
2306 (void) scf_set_error(SCF_ERROR_NOT_SET
);
2310 return (prop
->pr_propname
);
2315 scf_simple_prop_pgname(const scf_simple_prop_t
*prop
)
2317 if ((prop
== NULL
) || (prop
->pr_pgname
== NULL
)) {
2318 (void) scf_set_error(SCF_ERROR_NOT_SET
);
2322 return (prop
->pr_pgname
);
2326 static union scf_simple_prop_val
*
2327 scf_next_val(scf_simple_prop_t
*prop
, scf_type_t type
)
2330 (void) scf_set_error(SCF_ERROR_NOT_SET
);
2334 switch (prop
->pr_type
) {
2335 case SCF_TYPE_USTRING
:
2337 case SCF_TYPE_HOSTNAME
:
2338 case SCF_TYPE_NET_ADDR
:
2339 case SCF_TYPE_NET_ADDR_V4
:
2340 case SCF_TYPE_NET_ADDR_V6
:
2342 case SCF_TYPE_FMRI
: {
2343 if (type
!= SCF_TYPE_USTRING
) {
2344 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH
);
2350 if (type
!= prop
->pr_type
) {
2351 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH
);
2358 if (prop
->pr_iter
>= prop
->pr_numvalues
) {
2359 (void) scf_set_error(SCF_ERROR_NONE
);
2363 return (&prop
->pr_vallist
[prop
->pr_iter
++]);
2368 scf_simple_prop_next_boolean(scf_simple_prop_t
*prop
)
2370 union scf_simple_prop_val
*ret
;
2372 ret
= scf_next_val(prop
, SCF_TYPE_BOOLEAN
);
2377 return (&ret
->pv_bool
);
2382 scf_simple_prop_next_count(scf_simple_prop_t
*prop
)
2384 union scf_simple_prop_val
*ret
;
2386 ret
= scf_next_val(prop
, SCF_TYPE_COUNT
);
2391 return (&ret
->pv_uint
);
2396 scf_simple_prop_next_integer(scf_simple_prop_t
*prop
)
2398 union scf_simple_prop_val
*ret
;
2400 ret
= scf_next_val(prop
, SCF_TYPE_INTEGER
);
2405 return (&ret
->pv_int
);
2409 scf_simple_prop_next_time(scf_simple_prop_t
*prop
, int32_t *nsec
)
2411 union scf_simple_prop_val
*ret
;
2413 ret
= scf_next_val(prop
, SCF_TYPE_TIME
);
2419 *nsec
= ret
->pv_time
.t_nsec
;
2421 return (&ret
->pv_time
.t_sec
);
2425 scf_simple_prop_next_astring(scf_simple_prop_t
*prop
)
2427 union scf_simple_prop_val
*ret
;
2429 ret
= scf_next_val(prop
, SCF_TYPE_ASTRING
);
2434 return (ret
->pv_str
);
2438 scf_simple_prop_next_ustring(scf_simple_prop_t
*prop
)
2440 union scf_simple_prop_val
*ret
;
2442 ret
= scf_next_val(prop
, SCF_TYPE_USTRING
);
2447 return (ret
->pv_str
);
2451 scf_simple_prop_next_opaque(scf_simple_prop_t
*prop
, size_t *length
)
2453 union scf_simple_prop_val
*ret
;
2455 ret
= scf_next_val(prop
, SCF_TYPE_OPAQUE
);
2462 *length
= ret
->pv_opaque
.o_size
;
2463 return (ret
->pv_opaque
.o_value
);
2467 * Generate a filename based on the fmri and the given name and return
2468 * it in the buffer of MAXPATHLEN provided by the caller.
2469 * If temp_filename is non-zero, also generate a temporary, unique filename
2470 * and return it in the temp buffer of MAXPATHLEN provided by the caller.
2471 * The path to the generated pathname is also created.
2472 * Given fmri should begin with a scheme such as "svc:".
2475 * -1 if filename would exceed MAXPATHLEN or
2476 * -2 if unable to create directory to filename path
2479 gen_filenms_from_fmri(const char *fmri
, const char *name
, char *filename
,
2480 char *temp_filename
)
2484 len
= strlen(SMF_SPEEDY_FILES_PATH
);
2485 len
+= strlen(fmri
);
2486 len
+= 2; /* for slash and null */
2487 len
+= strlen(name
);
2488 len
+= 6; /* For X's needed for mkstemp */
2490 if (len
> MAXPATHLEN
)
2493 /* Construct directory name first - speedy path ends in slash */
2494 (void) strcpy(filename
, SMF_SPEEDY_FILES_PATH
);
2495 (void) strcat(filename
, fmri
);
2496 if (mkdirp(filename
, 0755) == -1) {
2498 if (errno
!= EEXIST
)
2502 (void) strcat(filename
, "/");
2503 (void) strcat(filename
, name
);
2505 if (temp_filename
) {
2506 (void) strcpy(temp_filename
, filename
);
2507 (void) strcat(temp_filename
, "XXXXXX");
2514 scf_true_base_type(scf_type_t type
)
2516 scf_type_t base
= type
;
2520 (void) scf_type_base_type(type
, &base
);
2521 } while (base
!= type
);
2527 * Convenience routine which frees all strings and opaque data
2528 * allocated by scf_read_propvec.
2530 * Like free(3C), this function preserves the value of errno.
2533 scf_clean_propvec(scf_propvec_t
*propvec
)
2535 int saved_errno
= errno
;
2536 scf_propvec_t
*prop
;
2538 for (prop
= propvec
; prop
->pv_prop
!= NULL
; prop
++) {
2539 assert(prop
->pv_type
!= SCF_TYPE_INVALID
);
2540 if (prop
->pv_type
== SCF_TYPE_OPAQUE
) {
2541 scf_opaque_t
*o
= prop
->pv_ptr
;
2544 } else if (scf_true_base_type(prop
->pv_type
) ==
2546 free(*(char **)prop
->pv_ptr
);
2550 errno
= saved_errno
;
2554 count_props(scf_propvec_t
*props
)
2558 for (; props
->pv_prop
!= NULL
; props
++)
2564 * Reads a vector of properties from the specified fmri/property group.
2565 * If 'running' is true, reads from the running snapshot instead of the
2568 * For string types, a buffer is allocated using malloc(3C) to hold the
2569 * zero-terminated string, a pointer to which is stored in the
2570 * caller-provided char **. It is the caller's responsbility to free
2571 * this string. To simplify error handling, unread strings are
2572 * initialized to NULL.
2574 * For opaque types, a buffer is allocated using malloc(3C) to hold the
2575 * opaque data. A pointer to this buffer and its size are stored in
2576 * the caller-provided scf_opaque_t. It is the caller's responsibility
2577 * to free this buffer. To simplify error handling, the address fields
2578 * for unread opaque data are initialized to NULL.
2580 * All other data is stored directly in caller-provided variables or
2583 * If this function fails to read a specific property, *badprop is set
2584 * to point at that property's entry in the properties array.
2586 * On all failures, all memory allocated by this function is freed.
2589 scf_read_propvec(const char *fmri
, const char *pgname
, boolean_t running
,
2590 scf_propvec_t
*properties
, scf_propvec_t
**badprop
)
2592 scf_handle_t
*h
= _scf_handle_create_and_bind(SCF_VERSION
);
2593 scf_service_t
*s
= scf_service_create(h
);
2594 scf_instance_t
*i
= scf_instance_create(h
);
2595 scf_snapshot_t
*snap
= running
? scf_snapshot_create(h
) : NULL
;
2596 scf_propertygroup_t
*pg
= scf_pg_create(h
);
2597 scf_property_t
*p
= scf_property_create(h
);
2598 scf_value_t
*v
= scf_value_create(h
);
2599 boolean_t instance
= B_TRUE
;
2600 scf_propvec_t
*prop
;
2603 for (prop
= properties
; prop
->pv_prop
!= NULL
; prop
++) {
2604 if (prop
->pv_type
== SCF_TYPE_OPAQUE
)
2605 ((scf_opaque_t
*)prop
->pv_ptr
)->so_addr
= NULL
;
2606 else if (scf_true_base_type(prop
->pv_type
) == SCF_TYPE_ASTRING
)
2607 *((char **)prop
->pv_ptr
) = NULL
;
2610 if (h
== NULL
|| s
== NULL
|| i
== NULL
|| (running
&& snap
== NULL
) ||
2611 pg
== NULL
|| p
== NULL
|| v
== NULL
)
2614 if (scf_handle_decode_fmri(h
, fmri
, NULL
, s
, i
, NULL
, NULL
, 0) == -1)
2617 if (scf_instance_to_fmri(i
, NULL
, 0) == -1) {
2618 if (scf_error() != SCF_ERROR_NOT_SET
)
2625 error
= SCF_ERROR_TYPE_MISMATCH
;
2629 if (scf_instance_get_snapshot(i
, "running", snap
) !=
2634 if ((instance
? scf_instance_get_pg_composed(i
, snap
, pgname
, pg
) :
2635 scf_service_get_pg(s
, pgname
, pg
)) == -1)
2638 for (prop
= properties
; prop
->pv_prop
!= NULL
; prop
++) {
2641 if (scf_pg_get_property(pg
, prop
->pv_prop
, p
) == -1 ||
2642 scf_property_get_value(p
, v
) == -1) {
2646 switch (prop
->pv_type
) {
2647 case SCF_TYPE_BOOLEAN
: {
2650 ret
= scf_value_get_boolean(v
, &b
);
2653 if (prop
->pv_aux
!= 0) {
2654 uint64_t *bits
= prop
->pv_ptr
;
2655 *bits
= b
? (*bits
| prop
->pv_aux
) :
2656 (*bits
& ~prop
->pv_aux
);
2658 boolean_t
*bool = prop
->pv_ptr
;
2659 *bool = b
? B_TRUE
: B_FALSE
;
2663 case SCF_TYPE_COUNT
:
2664 ret
= scf_value_get_count(v
, prop
->pv_ptr
);
2666 case SCF_TYPE_INTEGER
:
2667 ret
= scf_value_get_integer(v
, prop
->pv_ptr
);
2669 case SCF_TYPE_TIME
: {
2670 scf_time_t
*time
= prop
->pv_ptr
;
2672 ret
= scf_value_get_time(v
, &time
->t_seconds
,
2676 case SCF_TYPE_OPAQUE
: {
2677 scf_opaque_t
*opaque
= prop
->pv_ptr
;
2678 ssize_t size
= scf_value_get_opaque(v
, NULL
, 0);
2684 if ((opaque
->so_addr
= malloc(size
)) == NULL
) {
2685 error
= SCF_ERROR_NO_MEMORY
;
2688 opaque
->so_size
= size
;
2689 ret
= scf_value_get_opaque(v
, opaque
->so_addr
, size
);
2696 assert(scf_true_base_type(prop
->pv_type
) ==
2699 size
= scf_value_get_astring(v
, NULL
, 0);
2704 if ((s
= malloc(++size
)) == NULL
) {
2705 error
= SCF_ERROR_NO_MEMORY
;
2708 ret
= scf_value_get_astring(v
, s
, size
);
2709 *(char **)prop
->pv_ptr
= s
;
2723 error
= scf_error();
2724 scf_clean_propvec(properties
);
2727 scf_value_destroy(v
);
2728 scf_property_destroy(p
);
2730 scf_snapshot_destroy(snap
);
2731 scf_instance_destroy(i
);
2732 scf_service_destroy(s
);
2733 scf_handle_destroy(h
);
2736 (void) scf_set_error(error
);
2737 return (SCF_FAILED
);
2740 return (SCF_SUCCESS
);
2744 * Writes a vector of properties to the specified fmri/property group.
2746 * If this function fails to write a specific property, *badprop is set
2747 * to point at that property's entry in the properties array.
2749 * One significant difference between this function and the
2750 * scf_read_propvec function is that for string types, pv_ptr is a
2751 * char *, not a char **. This means that you can't write a propvec
2752 * you just read, but makes other uses (hopefully the majority) simpler.
2755 scf_write_propvec(const char *fmri
, const char *pgname
,
2756 scf_propvec_t
*properties
, scf_propvec_t
**badprop
)
2758 scf_handle_t
*h
= _scf_handle_create_and_bind(SCF_VERSION
);
2759 scf_service_t
*s
= scf_service_create(h
);
2760 scf_instance_t
*inst
= scf_instance_create(h
);
2761 scf_snapshot_t
*snap
= scf_snapshot_create(h
);
2762 scf_propertygroup_t
*pg
= scf_pg_create(h
);
2763 scf_property_t
*p
= scf_property_create(h
);
2764 scf_transaction_t
*tx
= scf_transaction_create(h
);
2765 scf_value_t
**v
= NULL
;
2766 scf_transaction_entry_t
**e
= NULL
;
2767 boolean_t instance
= B_TRUE
;
2769 scf_propvec_t
*prop
;
2772 n
= count_props(properties
);
2773 v
= calloc(n
, sizeof (scf_value_t
*));
2774 e
= calloc(n
, sizeof (scf_transaction_entry_t
*));
2776 if (v
== NULL
|| e
== NULL
) {
2777 error
= SCF_ERROR_NO_MEMORY
;
2781 if (h
== NULL
|| s
== NULL
|| inst
== NULL
|| pg
== NULL
|| p
== NULL
||
2785 for (i
= 0; i
< n
; i
++) {
2786 v
[i
] = scf_value_create(h
);
2787 e
[i
] = scf_entry_create(h
);
2788 if (v
[i
] == NULL
|| e
[i
] == NULL
)
2792 if (scf_handle_decode_fmri(h
, fmri
, NULL
, s
, inst
, NULL
, NULL
, 0)
2796 if (scf_instance_to_fmri(inst
, NULL
, 0) == -1) {
2797 if (scf_error() != SCF_ERROR_NOT_SET
)
2802 if ((instance
? scf_instance_get_pg(inst
, pgname
, pg
) :
2803 scf_service_get_pg(s
, pgname
, pg
)) == -1)
2807 if (scf_transaction_start(tx
, pg
) == -1)
2810 for (prop
= properties
, i
= 0; prop
->pv_prop
!= NULL
; prop
++, i
++) {
2811 ret
= scf_transaction_property_change(tx
, e
[i
], prop
->pv_prop
,
2813 if (ret
== -1 && scf_error() == SCF_ERROR_NOT_FOUND
)
2814 ret
= scf_transaction_property_new(tx
, e
[i
],
2815 prop
->pv_prop
, prop
->pv_type
);
2822 switch (prop
->pv_type
) {
2823 case SCF_TYPE_BOOLEAN
: {
2824 boolean_t b
= (prop
->pv_aux
!= 0) ?
2825 (*(uint64_t *)prop
->pv_ptr
& prop
->pv_aux
) != 0 :
2826 *(boolean_t
*)prop
->pv_ptr
;
2828 scf_value_set_boolean(v
[i
], b
? 1 : 0);
2831 case SCF_TYPE_COUNT
:
2832 scf_value_set_count(v
[i
], *(uint64_t *)prop
->pv_ptr
);
2834 case SCF_TYPE_INTEGER
:
2835 scf_value_set_integer(v
[i
], *(int64_t *)prop
->pv_ptr
);
2837 case SCF_TYPE_TIME
: {
2838 scf_time_t
*time
= prop
->pv_ptr
;
2840 ret
= scf_value_set_time(v
[i
], time
->t_seconds
,
2844 case SCF_TYPE_OPAQUE
: {
2845 scf_opaque_t
*opaque
= prop
->pv_ptr
;
2847 ret
= scf_value_set_opaque(v
[i
], opaque
->so_addr
,
2851 case SCF_TYPE_ASTRING
:
2852 ret
= scf_value_set_astring(v
[i
],
2853 (const char *)prop
->pv_ptr
);
2856 ret
= scf_value_set_from_string(v
[i
], prop
->pv_type
,
2857 (const char *)prop
->pv_ptr
);
2860 if (ret
== -1 || scf_entry_add_value(e
[i
], v
[i
]) == -1) {
2866 ret
= scf_transaction_commit(tx
);
2870 if (ret
== 0 && scf_pg_update(pg
) != -1) {
2871 scf_transaction_reset(tx
);
2876 error
= scf_error();
2880 for (i
= 0; i
< n
; i
++)
2881 scf_value_destroy(v
[i
]);
2886 for (i
= 0; i
< n
; i
++)
2887 scf_entry_destroy(e
[i
]);
2891 scf_transaction_destroy(tx
);
2892 scf_property_destroy(p
);
2894 scf_snapshot_destroy(snap
);
2895 scf_instance_destroy(inst
);
2896 scf_service_destroy(s
);
2897 scf_handle_destroy(h
);
2900 (void) scf_set_error(error
);
2901 return (SCF_FAILED
);
2904 return (SCF_SUCCESS
);
2910 * ECONNABORTED - repository connection broken
2911 * ECANCELED - inst was deleted
2918 scf_instance_delete_prop(scf_instance_t
*inst
, const char *pgname
,
2922 scf_propertygroup_t
*pg
;
2923 scf_transaction_t
*tx
;
2924 scf_transaction_entry_t
*e
;
2925 int error
= 0, ret
= 1, r
;
2927 h
= scf_instance_handle(inst
);
2929 if ((pg
= scf_pg_create(h
)) == NULL
) {
2933 if (scf_instance_get_pg(inst
, pgname
, pg
) != 0) {
2934 error
= scf_error();
2937 case SCF_ERROR_NOT_FOUND
:
2938 return (SCF_SUCCESS
);
2940 case SCF_ERROR_DELETED
:
2943 case SCF_ERROR_CONNECTION_BROKEN
:
2945 return (ECONNABORTED
);
2947 case SCF_ERROR_NOT_SET
:
2948 bad_error("scf_instance_get_pg", scf_error());
2952 tx
= scf_transaction_create(h
);
2953 e
= scf_entry_create(h
);
2954 if (tx
== NULL
|| e
== NULL
) {
2960 if (scf_transaction_start(tx
, pg
) != 0) {
2964 if (scf_transaction_property_delete(tx
, e
, pname
) != 0) {
2968 if ((r
= scf_transaction_commit(tx
)) == 1) {
2977 scf_transaction_reset(tx
);
2978 if (scf_pg_update(pg
) == -1) {
2984 switch (scf_error()) {
2985 case SCF_ERROR_DELETED
:
2986 case SCF_ERROR_NOT_FOUND
:
2990 case SCF_ERROR_PERMISSION_DENIED
:
2994 case SCF_ERROR_BACKEND_ACCESS
:
2998 case SCF_ERROR_BACKEND_READONLY
:
3002 case SCF_ERROR_CONNECTION_BROKEN
:
3007 case SCF_ERROR_HANDLE_MISMATCH
:
3008 case SCF_ERROR_INVALID_ARGUMENT
:
3009 case SCF_ERROR_NOT_BOUND
:
3010 case SCF_ERROR_NOT_SET
:
3011 bad_error("scf_instance_delete_prop", scf_error());
3015 scf_transaction_destroy(tx
);
3016 scf_entry_destroy(e
);
3023 * Check the "application/auto_enable" property for the passed FMRI.
3024 * scf_simple_prop_get() should find the property on an instance
3025 * or on the service FMRI. The routine returns:
3026 * -1: inconclusive (likely no such property or FMRI)
3027 * 0: auto_enable is false
3028 * 1: auto_enable is true
3031 is_auto_enabled(char *fmri
)
3033 scf_simple_prop_t
*prop
;
3037 prop
= scf_simple_prop_get(NULL
, fmri
, SCF_GROUP_APPLICATION
,
3041 ret
= scf_simple_prop_next_boolean(prop
);
3042 retval
= (*ret
!= 0);
3043 scf_simple_prop_free(prop
);
3048 * Check an array of services and enable any that don't have the
3049 * "application/auto_enable" property set to "false", which is
3050 * the interface to turn off this behaviour (see PSARC 2004/739).
3053 _check_services(char **svcs
)
3057 for (; *svcs
; svcs
++) {
3058 if (is_auto_enabled(*svcs
) == 0)
3060 if ((s
= smf_get_state(*svcs
)) != NULL
) {
3061 if (strcmp(SCF_STATE_STRING_DISABLED
, s
) == 0)
3062 (void) smf_enable_instance(*svcs
,
3071 str_compare(const char *s1
, const char *s2
, size_t n
)
3073 return (strcmp(s1
, s2
));
3077 str_n_compare(const char *s1
, const char *s2
, size_t n
)
3079 return (strncmp(s1
, s2
, n
));
3083 state_from_string(const char *state
, size_t l
)
3085 int (*str_cmp
)(const char *, const char *, size_t);
3088 str_cmp
= str_compare
;
3090 str_cmp
= str_n_compare
;
3092 if (str_cmp(SCF_STATE_STRING_UNINIT
, state
, l
) == 0)
3093 return (SCF_STATE_UNINIT
);
3094 else if (str_cmp(SCF_STATE_STRING_MAINT
, state
, l
) == 0)
3095 return (SCF_STATE_MAINT
);
3096 else if (str_cmp(SCF_STATE_STRING_OFFLINE
, state
, l
) == 0)
3097 return (SCF_STATE_OFFLINE
);
3098 else if (str_cmp(SCF_STATE_STRING_DISABLED
, state
, l
) == 0)
3099 return (SCF_STATE_DISABLED
);
3100 else if (str_cmp(SCF_STATE_STRING_ONLINE
, state
, l
) == 0)
3101 return (SCF_STATE_ONLINE
);
3102 else if (str_cmp(SCF_STATE_STRING_DEGRADED
, state
, l
) == 0)
3103 return (SCF_STATE_DEGRADED
);
3104 else if (str_cmp("all", state
, l
) == 0)
3105 return (SCF_STATE_ALL
);
3111 * int32_t smf_state_from_string()
3112 * return the value of the macro SCF_STATE_* for the corresponding state
3113 * it returns SCF_STATE_ALL if "all" is passed. -1 if the string passed doesn't
3114 * correspond to any valid state.
3117 smf_state_from_string(const char *state
)
3119 return (state_from_string(state
, 0));
3123 * smf_state_to_string()
3124 * Takes an int32_t representing an SMF state and returns
3125 * the corresponding string. The string is read only and need not to be
3127 * returns NULL on invalid input.
3130 smf_state_to_string(int32_t s
)
3133 case SCF_STATE_UNINIT
:
3134 return (SCF_STATE_STRING_UNINIT
);
3135 case SCF_STATE_MAINT
:
3136 return (SCF_STATE_STRING_MAINT
);
3137 case SCF_STATE_OFFLINE
:
3138 return (SCF_STATE_STRING_OFFLINE
);
3139 case SCF_STATE_DISABLED
:
3140 return (SCF_STATE_STRING_DISABLED
);
3141 case SCF_STATE_ONLINE
:
3142 return (SCF_STATE_STRING_ONLINE
);
3143 case SCF_STATE_DEGRADED
:
3144 return (SCF_STATE_STRING_DEGRADED
);