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.
27 #include "libscf_impl.h"
34 #include <sys/param.h>
38 #include "midlevel_impl.h"
39 #include "lowlevel_impl.h"
42 #define bad_error(func, err) { \
43 uu_warn("%s:%d: %s failed with unexpected error %d. Aborting.\n", \
44 __FILE__, __LINE__, func, err); \
48 #define bad_error(func, err) abort()
51 /* Path to speedy files area must end with a slash */
52 #define SMF_SPEEDY_FILES_PATH "/etc/svc/volatile/"
55 scf_simple_handle_destroy(scf_simple_handle_t
*simple_h
)
60 scf_pg_destroy(simple_h
->running_pg
);
61 scf_pg_destroy(simple_h
->editing_pg
);
62 scf_snapshot_destroy(simple_h
->snap
);
63 scf_instance_destroy(simple_h
->inst
);
64 scf_handle_destroy(simple_h
->h
);
69 * Given a base service FMRI and the names of a property group and property,
70 * assemble_fmri() merges them into a property FMRI. Note that if the base
71 * FMRI is NULL, assemble_fmri() gets the base FMRI from scf_myname().
75 assemble_fmri(scf_handle_t
*h
, const char *base
, const char *pg
,
78 size_t fmri_sz
, pglen
;
83 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
88 pglen
= strlen(SCF_PG_APP_DEFAULT
);
93 if ((baselen
= scf_myname(h
, NULL
, 0)) == -1)
96 baselen
= strlen(base
);
99 fmri_sz
= baselen
+ sizeof (SCF_FMRI_PROPERTYGRP_PREFIX
) - 1 +
100 pglen
+ sizeof (SCF_FMRI_PROPERTY_PREFIX
) - 1 +
103 if ((fmri_buf
= malloc(fmri_sz
)) == NULL
) {
104 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
109 if (scf_myname(h
, fmri_buf
, fmri_sz
) == -1) {
114 (void) strcpy(fmri_buf
, base
);
117 (void) strcat(fmri_buf
, SCF_FMRI_PROPERTYGRP_PREFIX
);
120 (void) strcat(fmri_buf
, SCF_PG_APP_DEFAULT
);
122 (void) strcat(fmri_buf
, pg
);
124 (void) strcat(fmri_buf
, SCF_FMRI_PROPERTY_PREFIX
);
125 (void) strcat(fmri_buf
, prop
);
130 * Given a property, this function allocates and fills an scf_simple_prop_t
131 * with the data it contains.
134 static scf_simple_prop_t
*
135 fill_prop(scf_property_t
*prop
, const char *pgname
, const char *propname
,
138 scf_simple_prop_t
*ret
;
142 ssize_t valsize
, numvals
;
143 union scf_simple_prop_val
*vallist
= NULL
, *vallist_backup
= NULL
;
145 if ((ret
= malloc(sizeof (*ret
))) == NULL
) {
146 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
155 ret
->pr_pgname
= strdup(SCF_PG_APP_DEFAULT
);
157 ret
->pr_pgname
= strdup(pgname
);
159 if (ret
->pr_pgname
== NULL
) {
160 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
165 if ((ret
->pr_propname
= strdup(propname
)) == NULL
) {
166 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
167 free(ret
->pr_pgname
);
172 if (scf_property_type(prop
, &ret
->pr_type
) == -1)
175 if ((iter
= scf_iter_create(h
)) == NULL
)
177 if ((val
= scf_value_create(h
)) == NULL
) {
178 scf_iter_destroy(iter
);
182 if (scf_iter_property_values(iter
, prop
) == -1)
185 for (numvals
= 0; (iterret
= scf_iter_next_value(iter
, val
)) == 1;
187 vallist_backup
= vallist
;
188 if ((vallist
= reallocarray(vallist
, numvals
+ 1,
189 sizeof (*vallist
))) == NULL
) {
190 vallist
= vallist_backup
;
194 switch (ret
->pr_type
) {
195 case SCF_TYPE_BOOLEAN
:
196 if (scf_value_get_boolean(val
,
197 &vallist
[numvals
].pv_bool
) == -1)
202 if (scf_value_get_count(val
,
203 &vallist
[numvals
].pv_uint
) == -1)
207 case SCF_TYPE_INTEGER
:
208 if (scf_value_get_integer(val
,
209 &vallist
[numvals
].pv_int
) == -1)
214 if (scf_value_get_time(val
,
215 &vallist
[numvals
].pv_time
.t_sec
,
216 &vallist
[numvals
].pv_time
.t_nsec
) == -1)
220 case SCF_TYPE_ASTRING
:
221 vallist
[numvals
].pv_str
= NULL
;
222 if ((valsize
= scf_value_get_astring(val
, NULL
, 0)) ==
225 if ((vallist
[numvals
].pv_str
= malloc(valsize
+1)) ==
227 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
230 if (scf_value_get_astring(val
,
231 vallist
[numvals
].pv_str
, valsize
+1) == -1) {
232 free(vallist
[numvals
].pv_str
);
237 case SCF_TYPE_USTRING
:
239 case SCF_TYPE_HOSTNAME
:
240 case SCF_TYPE_NET_ADDR
:
241 case SCF_TYPE_NET_ADDR_V4
:
242 case SCF_TYPE_NET_ADDR_V6
:
245 vallist
[numvals
].pv_str
= NULL
;
246 if ((valsize
= scf_value_get_ustring(val
, NULL
, 0)) ==
249 if ((vallist
[numvals
].pv_str
= malloc(valsize
+1)) ==
251 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
254 if (scf_value_get_ustring(val
,
255 vallist
[numvals
].pv_str
, valsize
+1) == -1) {
256 free(vallist
[numvals
].pv_str
);
261 case SCF_TYPE_OPAQUE
:
262 vallist
[numvals
].pv_opaque
.o_value
= NULL
;
263 if ((valsize
= scf_value_get_opaque(val
, NULL
, 0)) ==
266 if ((vallist
[numvals
].pv_opaque
.o_value
=
267 malloc(valsize
)) == NULL
) {
268 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
271 vallist
[numvals
].pv_opaque
.o_size
= valsize
;
272 if (scf_value_get_opaque(val
,
273 vallist
[numvals
].pv_opaque
.o_value
,
275 free(vallist
[numvals
].pv_opaque
.o_value
);
281 (void) scf_set_error(SCF_ERROR_INTERNAL
);
288 int err
= scf_error();
289 if (err
!= SCF_ERROR_CONNECTION_BROKEN
&&
290 err
!= SCF_ERROR_PERMISSION_DENIED
)
291 (void) scf_set_error(SCF_ERROR_INTERNAL
);
295 ret
->pr_vallist
= vallist
;
296 ret
->pr_numvalues
= numvals
;
298 scf_iter_destroy(iter
);
299 (void) scf_value_destroy(val
);
304 * Exit point for a successful call. Below this line are exit points
305 * for failures at various stages during the function.
312 switch (ret
->pr_type
) {
313 case SCF_TYPE_ASTRING
:
314 case SCF_TYPE_USTRING
:
316 case SCF_TYPE_HOSTNAME
:
317 case SCF_TYPE_NET_ADDR
:
318 case SCF_TYPE_NET_ADDR_V4
:
319 case SCF_TYPE_NET_ADDR_V6
:
321 case SCF_TYPE_FMRI
: {
322 for (i
= 0; i
< numvals
; i
++) {
323 free(vallist
[i
].pv_str
);
327 case SCF_TYPE_OPAQUE
: {
328 for (i
= 0; i
< numvals
; i
++) {
329 free(vallist
[i
].pv_opaque
.o_value
);
340 scf_iter_destroy(iter
);
341 (void) scf_value_destroy(val
);
344 free(ret
->pr_pgname
);
345 free(ret
->pr_propname
);
351 * insert_app_props iterates over a property iterator, getting all the
352 * properties from a property group, and adding or overwriting them into
353 * a simple_app_props_t. This is used by scf_simple_app_props_get to provide
354 * service/instance composition while filling the app_props_t.
355 * insert_app_props iterates over a single property group.
359 insert_app_props(scf_iter_t
*propiter
, char *pgname
, char *propname
, struct
360 scf_simple_pg
*thispg
, scf_property_t
*prop
, size_t namelen
,
363 scf_simple_prop_t
*thisprop
, *prevprop
, *newprop
;
367 while ((propiter_ret
= scf_iter_next_property(propiter
, prop
)) == 1) {
369 if (scf_property_get_name(prop
, propname
, namelen
) < 0) {
370 if (scf_error() == SCF_ERROR_NOT_SET
)
371 (void) scf_set_error(SCF_ERROR_INTERNAL
);
375 thisprop
= thispg
->pg_proplist
;
376 prevprop
= thispg
->pg_proplist
;
379 while ((thisprop
!= NULL
) && (!found
)) {
380 if (strcmp(thisprop
->pr_propname
, propname
) == 0) {
382 if ((newprop
= fill_prop(prop
, pgname
,
383 propname
, h
)) == NULL
)
386 if (thisprop
== thispg
->pg_proplist
)
387 thispg
->pg_proplist
= newprop
;
389 prevprop
->pr_next
= newprop
;
391 newprop
->pr_pg
= thispg
;
392 newprop
->pr_next
= thisprop
->pr_next
;
393 scf_simple_prop_free(thisprop
);
396 if (thisprop
!= thispg
->pg_proplist
)
397 prevprop
= prevprop
->pr_next
;
398 thisprop
= thisprop
->pr_next
;
403 if ((newprop
= fill_prop(prop
, pgname
, propname
, h
)) ==
407 if (thispg
->pg_proplist
== NULL
)
408 thispg
->pg_proplist
= newprop
;
410 prevprop
->pr_next
= newprop
;
412 newprop
->pr_pg
= thispg
;
416 if (propiter_ret
== -1) {
417 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
418 (void) scf_set_error(SCF_ERROR_INTERNAL
);
427 * Sets up e in tx to set pname's values. Returns 0 on success or -1 on
428 * failure, with scf_error() set to
429 * SCF_ERROR_HANDLE_MISMATCH - tx & e are derived from different handles
430 * SCF_ERROR_INVALID_ARGUMENT - pname or ty are invalid
431 * SCF_ERROR_NOT_BOUND - handle is not bound
432 * SCF_ERROR_CONNECTION_BROKEN - connection was broken
433 * SCF_ERROR_NOT_SET - tx has not been started
434 * SCF_ERROR_DELETED - the pg tx was started on was deleted
437 transaction_property_set(scf_transaction_t
*tx
, scf_transaction_entry_t
*e
,
438 const char *pname
, scf_type_t ty
)
441 if (scf_transaction_property_change_type(tx
, e
, pname
, ty
) == 0)
444 switch (scf_error()) {
445 case SCF_ERROR_HANDLE_MISMATCH
:
446 case SCF_ERROR_INVALID_ARGUMENT
:
447 case SCF_ERROR_NOT_BOUND
:
448 case SCF_ERROR_CONNECTION_BROKEN
:
449 case SCF_ERROR_NOT_SET
:
450 case SCF_ERROR_DELETED
:
454 case SCF_ERROR_NOT_FOUND
:
458 if (scf_transaction_property_new(tx
, e
, pname
, ty
) == 0)
461 switch (scf_error()) {
462 case SCF_ERROR_HANDLE_MISMATCH
:
463 case SCF_ERROR_INVALID_ARGUMENT
:
464 case SCF_ERROR_NOT_BOUND
:
465 case SCF_ERROR_CONNECTION_BROKEN
:
466 case SCF_ERROR_NOT_SET
:
467 case SCF_ERROR_DELETED
:
471 case SCF_ERROR_EXISTS
:
478 get_inst_enabled(const scf_instance_t
*inst
, const char *pgname
)
480 scf_propertygroup_t
*gpg
= NULL
;
481 scf_property_t
*eprop
= NULL
;
482 scf_value_t
*v
= NULL
;
483 scf_handle_t
*h
= NULL
;
487 if ((h
= scf_instance_handle(inst
)) == NULL
)
490 if ((gpg
= scf_pg_create(h
)) == NULL
||
491 (eprop
= scf_property_create(h
)) == NULL
||
492 (v
= scf_value_create(h
)) == NULL
)
495 if (scf_instance_get_pg(inst
, pgname
, gpg
) ||
496 scf_pg_get_property(gpg
, SCF_PROPERTY_ENABLED
, eprop
) ||
497 scf_property_get_value(eprop
, v
) ||
498 scf_value_get_boolean(v
, &enabled
))
504 scf_property_destroy(eprop
);
505 scf_value_destroy(v
);
510 * set_inst_enabled() is a "master" enable/disable call that takes the
511 * instance and the desired state for the enabled bit in the instance's
512 * named property group. If the group doesn't exist, it's created with the
513 * given flags. Called by smf_{dis,en}able_instance().
516 set_inst_enabled(const scf_instance_t
*inst
, uint8_t desired
,
517 const char *pgname
, uint32_t pgflags
)
519 scf_transaction_t
*tx
= NULL
;
520 scf_transaction_entry_t
*ent
= NULL
;
521 scf_propertygroup_t
*gpg
= NULL
;
522 scf_property_t
*eprop
= NULL
;
523 scf_value_t
*v
= NULL
;
524 scf_handle_t
*h
= NULL
;
529 if ((h
= scf_instance_handle(inst
)) == NULL
)
532 if ((gpg
= scf_pg_create(h
)) == NULL
||
533 (eprop
= scf_property_create(h
)) == NULL
||
534 (v
= scf_value_create(h
)) == NULL
||
535 (tx
= scf_transaction_create(h
)) == NULL
||
536 (ent
= scf_entry_create(h
)) == NULL
)
540 if (scf_instance_get_pg(inst
, SCF_PG_GENERAL
, gpg
) == -1) {
541 if (scf_error() != SCF_ERROR_NOT_FOUND
)
544 if (scf_instance_add_pg(inst
, SCF_PG_GENERAL
,
545 SCF_GROUP_FRAMEWORK
, SCF_PG_GENERAL_FLAGS
, gpg
) == -1) {
546 if (scf_error() != SCF_ERROR_EXISTS
)
552 if (strcmp(pgname
, SCF_PG_GENERAL
) != 0) {
554 if (scf_instance_get_pg(inst
, pgname
, gpg
) == -1) {
555 if (scf_error() != SCF_ERROR_NOT_FOUND
)
558 if (scf_instance_add_pg(inst
, pgname
,
559 SCF_GROUP_FRAMEWORK
, pgflags
, gpg
) == -1) {
560 if (scf_error() != SCF_ERROR_EXISTS
)
567 if (scf_pg_get_property(gpg
, SCF_PROPERTY_ENABLED
, eprop
) == -1) {
568 if (scf_error() != SCF_ERROR_NOT_FOUND
)
575 * If it's already set the way we want, forgo the transaction.
577 if (scf_property_get_value(eprop
, v
) == -1) {
578 switch (scf_error()) {
579 case SCF_ERROR_CONSTRAINT_VIOLATED
:
580 case SCF_ERROR_NOT_FOUND
:
581 /* Misconfigured, so set anyway. */
588 if (scf_value_get_boolean(v
, &b
) == -1) {
589 if (scf_error() != SCF_ERROR_TYPE_MISMATCH
)
600 if (scf_transaction_start(tx
, gpg
) == -1)
603 if (transaction_property_set(tx
, ent
, SCF_PROPERTY_ENABLED
,
604 SCF_TYPE_BOOLEAN
) != 0) {
605 switch (scf_error()) {
606 case SCF_ERROR_CONNECTION_BROKEN
:
607 case SCF_ERROR_DELETED
:
611 case SCF_ERROR_HANDLE_MISMATCH
:
612 case SCF_ERROR_INVALID_ARGUMENT
:
613 case SCF_ERROR_NOT_BOUND
:
614 case SCF_ERROR_NOT_SET
:
615 bad_error("transaction_property_set",
620 scf_value_set_boolean(v
, desired
);
621 if (scf_entry_add_value(ent
, v
) == -1)
624 committed
= scf_transaction_commit(tx
);
628 scf_transaction_reset(tx
);
630 if (committed
== 0) { /* out-of-sync */
631 if (scf_pg_update(gpg
) == -1)
634 } while (committed
== 0);
639 scf_value_destroy(v
);
640 scf_entry_destroy(ent
);
641 scf_transaction_destroy(tx
);
642 scf_property_destroy(eprop
);
649 delete_inst_enabled(const scf_instance_t
*inst
, const char *pgname
)
651 scf_transaction_t
*tx
= NULL
;
652 scf_transaction_entry_t
*ent
= NULL
;
653 scf_propertygroup_t
*gpg
= NULL
;
654 scf_handle_t
*h
= NULL
;
658 if ((h
= scf_instance_handle(inst
)) == NULL
)
661 if ((gpg
= scf_pg_create(h
)) == NULL
||
662 (tx
= scf_transaction_create(h
)) == NULL
||
663 (ent
= scf_entry_create(h
)) == NULL
)
666 if (scf_instance_get_pg(inst
, pgname
, gpg
) != 0)
669 if (scf_transaction_start(tx
, gpg
) == -1 ||
670 scf_transaction_property_delete(tx
, ent
,
671 SCF_PROPERTY_ENABLED
) == -1 ||
672 (committed
= scf_transaction_commit(tx
)) == -1)
675 scf_transaction_reset(tx
);
677 if (committed
== 0 && scf_pg_update(gpg
) == -1)
679 } while (committed
== 0);
685 switch (scf_error()) {
686 case SCF_ERROR_DELETED
:
687 case SCF_ERROR_NOT_FOUND
:
693 scf_entry_destroy(ent
);
694 scf_transaction_destroy(tx
);
701 * Returns 0 on success or -1 on failure. On failure leaves scf_error() set to
702 * SCF_ERROR_HANDLE_DESTROYED - inst's handle has been destroyed
703 * SCF_ERROR_NOT_BOUND - inst's handle is not bound
704 * SCF_ERROR_CONNECTION_BROKEN - the repository connection was broken
705 * SCF_ERROR_NOT_SET - inst is not set
706 * SCF_ERROR_DELETED - inst was deleted
707 * SCF_ERROR_PERMISSION_DENIED
708 * SCF_ERROR_BACKEND_ACCESS
709 * SCF_ERROR_BACKEND_READONLY
712 set_inst_action_inst(scf_instance_t
*inst
, const char *action
)
715 scf_transaction_t
*tx
= NULL
;
716 scf_transaction_entry_t
*ent
= NULL
;
717 scf_propertygroup_t
*pg
= NULL
;
718 scf_property_t
*prop
= NULL
;
719 scf_value_t
*v
= NULL
;
724 if ((h
= scf_instance_handle(inst
)) == NULL
||
725 (pg
= scf_pg_create(h
)) == NULL
||
726 (prop
= scf_property_create(h
)) == NULL
||
727 (v
= scf_value_create(h
)) == NULL
||
728 (tx
= scf_transaction_create(h
)) == NULL
||
729 (ent
= scf_entry_create(h
)) == NULL
)
733 if (scf_instance_get_pg(inst
, SCF_PG_RESTARTER_ACTIONS
, pg
) == -1) {
734 switch (scf_error()) {
735 case SCF_ERROR_NOT_BOUND
:
736 case SCF_ERROR_CONNECTION_BROKEN
:
737 case SCF_ERROR_NOT_SET
:
738 case SCF_ERROR_DELETED
:
742 case SCF_ERROR_NOT_FOUND
:
745 case SCF_ERROR_HANDLE_MISMATCH
:
746 case SCF_ERROR_INVALID_ARGUMENT
:
747 bad_error("scf_instance_get_pg", scf_error());
750 /* Try creating the restarter_actions property group. */
752 if (scf_instance_add_pg(inst
, SCF_PG_RESTARTER_ACTIONS
,
753 SCF_PG_RESTARTER_ACTIONS_TYPE
,
754 SCF_PG_RESTARTER_ACTIONS_FLAGS
, pg
) == -1) {
755 switch (scf_error()) {
756 case SCF_ERROR_NOT_BOUND
:
757 case SCF_ERROR_CONNECTION_BROKEN
:
758 case SCF_ERROR_NOT_SET
:
759 case SCF_ERROR_DELETED
:
760 case SCF_ERROR_PERMISSION_DENIED
:
761 case SCF_ERROR_BACKEND_ACCESS
:
762 case SCF_ERROR_BACKEND_READONLY
:
766 case SCF_ERROR_EXISTS
:
769 case SCF_ERROR_HANDLE_MISMATCH
:
770 case SCF_ERROR_INVALID_ARGUMENT
:
771 bad_error("scf_instance_add_pg", scf_error());
777 timestamp
= gethrtime();
779 if (scf_pg_get_property(pg
, action
, prop
) != 0) {
780 switch (scf_error()) {
781 case SCF_ERROR_CONNECTION_BROKEN
:
785 case SCF_ERROR_DELETED
:
788 case SCF_ERROR_NOT_FOUND
:
791 case SCF_ERROR_HANDLE_MISMATCH
:
792 case SCF_ERROR_INVALID_ARGUMENT
:
793 case SCF_ERROR_NOT_BOUND
:
794 case SCF_ERROR_NOT_SET
:
795 bad_error("scf_pg_get_property", scf_error());
797 } else if (scf_property_get_value(prop
, v
) != 0) {
798 switch (scf_error()) {
799 case SCF_ERROR_CONNECTION_BROKEN
:
803 case SCF_ERROR_DELETED
:
806 case SCF_ERROR_CONSTRAINT_VIOLATED
:
807 case SCF_ERROR_NOT_FOUND
:
810 case SCF_ERROR_HANDLE_MISMATCH
:
811 case SCF_ERROR_NOT_BOUND
:
812 case SCF_ERROR_NOT_SET
:
813 bad_error("scf_property_get_value",
816 } else if (scf_value_get_integer(v
, &t
) != 0) {
817 bad_error("scf_value_get_integer", scf_error());
818 } else if (t
> timestamp
) {
822 if (scf_transaction_start(tx
, pg
) == -1) {
823 switch (scf_error()) {
824 case SCF_ERROR_NOT_BOUND
:
825 case SCF_ERROR_CONNECTION_BROKEN
:
826 case SCF_ERROR_PERMISSION_DENIED
:
827 case SCF_ERROR_BACKEND_ACCESS
:
828 case SCF_ERROR_BACKEND_READONLY
:
832 case SCF_ERROR_DELETED
:
835 case SCF_ERROR_HANDLE_MISMATCH
:
836 case SCF_ERROR_NOT_SET
:
837 case SCF_ERROR_IN_USE
:
838 bad_error("scf_transaction_start", scf_error());
842 if (transaction_property_set(tx
, ent
, action
,
843 SCF_TYPE_INTEGER
) != 0) {
844 switch (scf_error()) {
845 case SCF_ERROR_NOT_BOUND
:
846 case SCF_ERROR_CONNECTION_BROKEN
:
847 case SCF_ERROR_DELETED
:
851 case SCF_ERROR_HANDLE_MISMATCH
:
852 case SCF_ERROR_INVALID_ARGUMENT
:
853 case SCF_ERROR_NOT_SET
:
854 bad_error("transaction_property_set",
859 scf_value_set_integer(v
, timestamp
);
860 if (scf_entry_add_value(ent
, v
) == -1)
861 bad_error("scf_entry_add_value", scf_error());
863 trans
= scf_transaction_commit(tx
);
868 switch (scf_error()) {
869 case SCF_ERROR_CONNECTION_BROKEN
:
870 case SCF_ERROR_PERMISSION_DENIED
:
871 case SCF_ERROR_BACKEND_ACCESS
:
872 case SCF_ERROR_BACKEND_READONLY
:
876 case SCF_ERROR_DELETED
:
877 scf_transaction_reset(tx
);
880 case SCF_ERROR_INVALID_ARGUMENT
:
881 case SCF_ERROR_NOT_BOUND
:
882 case SCF_ERROR_NOT_SET
:
883 bad_error("scf_transaction_commit",
888 scf_transaction_reset(tx
);
889 if (scf_pg_update(pg
) == -1) {
890 switch (scf_error()) {
891 case SCF_ERROR_CONNECTION_BROKEN
:
895 case SCF_ERROR_DELETED
:
898 case SCF_ERROR_NOT_SET
:
899 case SCF_ERROR_NOT_BOUND
:
900 bad_error("scf_pg_update", scf_error());
908 scf_value_destroy(v
);
909 scf_entry_destroy(ent
);
910 scf_transaction_destroy(tx
);
911 scf_property_destroy(prop
);
917 set_inst_action(const char *fmri
, const char *action
)
920 scf_instance_t
*inst
;
923 h
= _scf_handle_create_and_bind(SCF_VERSION
);
927 inst
= scf_instance_create(h
);
930 if (scf_handle_decode_fmri(h
, fmri
, NULL
, NULL
, inst
, NULL
,
931 NULL
, SCF_DECODE_FMRI_EXACT
) == 0) {
932 ret
= set_inst_action_inst(inst
, action
);
933 if (ret
== -1 && scf_error() == SCF_ERROR_DELETED
)
934 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
936 switch (scf_error()) {
937 case SCF_ERROR_CONSTRAINT_VIOLATED
:
938 (void) scf_set_error(
939 SCF_ERROR_INVALID_ARGUMENT
);
941 case SCF_ERROR_DELETED
:
942 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
947 scf_instance_destroy(inst
);
950 scf_handle_destroy(h
);
957 * get_inst_state() gets the state string from an instance, and returns
958 * the SCF_STATE_* constant that coincides with the instance's current state.
962 get_inst_state(scf_instance_t
*inst
, scf_handle_t
*h
)
964 scf_propertygroup_t
*pg
= NULL
;
965 scf_property_t
*prop
= NULL
;
966 scf_value_t
*val
= NULL
;
967 char state
[MAX_SCF_STATE_STRING_SZ
];
970 if (((pg
= scf_pg_create(h
)) == NULL
) ||
971 ((prop
= scf_property_create(h
)) == NULL
) ||
972 ((val
= scf_value_create(h
)) == NULL
))
975 /* Pull the state property from the instance */
977 if (scf_instance_get_pg(inst
, SCF_PG_RESTARTER
, pg
) == -1 ||
978 scf_pg_get_property(pg
, SCF_PROPERTY_STATE
, prop
) == -1 ||
979 scf_property_get_value(prop
, val
) == -1) {
980 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
981 (void) scf_set_error(SCF_ERROR_INTERNAL
);
985 if (scf_value_get_astring(val
, state
, sizeof (state
)) <= 0) {
986 (void) scf_set_error(SCF_ERROR_INTERNAL
);
990 if (strcmp(state
, SCF_STATE_STRING_UNINIT
) == 0) {
991 ret
= SCF_STATE_UNINIT
;
992 } else if (strcmp(state
, SCF_STATE_STRING_MAINT
) == 0) {
993 ret
= SCF_STATE_MAINT
;
994 } else if (strcmp(state
, SCF_STATE_STRING_OFFLINE
) == 0) {
995 ret
= SCF_STATE_OFFLINE
;
996 } else if (strcmp(state
, SCF_STATE_STRING_DISABLED
) == 0) {
997 ret
= SCF_STATE_DISABLED
;
998 } else if (strcmp(state
, SCF_STATE_STRING_ONLINE
) == 0) {
999 ret
= SCF_STATE_ONLINE
;
1000 } else if (strcmp(state
, SCF_STATE_STRING_DEGRADED
) == 0) {
1001 ret
= SCF_STATE_DEGRADED
;
1006 scf_property_destroy(prop
);
1007 (void) scf_value_destroy(val
);
1013 * Sets an instance to be enabled or disabled after reboot, using the
1014 * temporary (overriding) general_ovr property group to reflect the
1015 * present state, if it is different.
1018 set_inst_enabled_atboot(scf_instance_t
*inst
, uint8_t desired
)
1024 if ((persistent
= get_inst_enabled(inst
, SCF_PG_GENERAL
)) < 0) {
1025 if (scf_error() != SCF_ERROR_NOT_FOUND
)
1027 persistent
= B_FALSE
;
1029 if ((enabled
= get_inst_enabled(inst
, SCF_PG_GENERAL_OVR
)) < 0) {
1030 enabled
= persistent
;
1031 if (persistent
!= desired
) {
1033 * Temporarily store the present enabled state.
1035 if (set_inst_enabled(inst
, persistent
,
1036 SCF_PG_GENERAL_OVR
, SCF_PG_GENERAL_OVR_FLAGS
))
1040 if (persistent
!= desired
)
1041 if (set_inst_enabled(inst
, desired
, SCF_PG_GENERAL
,
1042 SCF_PG_GENERAL_FLAGS
))
1044 if (enabled
== desired
)
1045 ret
= delete_inst_enabled(inst
, SCF_PG_GENERAL_OVR
);
1054 set_inst_enabled_flags(const char *fmri
, int flags
, uint8_t desired
)
1058 scf_instance_t
*inst
;
1060 if (flags
& ~(SMF_TEMPORARY
| SMF_AT_NEXT_BOOT
) ||
1061 flags
& SMF_TEMPORARY
&& flags
& SMF_AT_NEXT_BOOT
) {
1062 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
1066 if ((h
= _scf_handle_create_and_bind(SCF_VERSION
)) == NULL
)
1069 if ((inst
= scf_instance_create(h
)) == NULL
) {
1070 scf_handle_destroy(h
);
1074 if (scf_handle_decode_fmri(h
, fmri
, NULL
, NULL
, inst
, NULL
, NULL
,
1075 SCF_DECODE_FMRI_EXACT
) == -1) {
1076 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED
)
1077 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
1081 if (flags
& SMF_AT_NEXT_BOOT
) {
1082 ret
= set_inst_enabled_atboot(inst
, desired
);
1084 if (set_inst_enabled(inst
, desired
, flags
& SMF_TEMPORARY
?
1085 SCF_PG_GENERAL_OVR
: SCF_PG_GENERAL
, flags
& SMF_TEMPORARY
?
1086 SCF_PG_GENERAL_OVR_FLAGS
: SCF_PG_GENERAL_FLAGS
))
1090 * Make the persistent value effective by deleting the
1093 if (flags
& SMF_TEMPORARY
)
1096 ret
= delete_inst_enabled(inst
, SCF_PG_GENERAL_OVR
);
1100 scf_instance_destroy(inst
);
1101 scf_handle_destroy(h
);
1102 if (ret
== -1 && scf_error() == SCF_ERROR_DELETED
)
1103 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
1108 * Create and return a pg from the instance associated with the given handle.
1109 * This function is only called in scf_transaction_setup and
1110 * scf_transaction_restart where the h->rh_instance pointer is properly filled
1111 * in by scf_general_setup_pg().
1113 static scf_propertygroup_t
*
1114 get_instance_pg(scf_simple_handle_t
*simple_h
)
1116 scf_propertygroup_t
*ret_pg
= scf_pg_create(simple_h
->h
);
1120 if (ret_pg
== NULL
) {
1124 namelen
= scf_limit(SCF_LIMIT_MAX_NAME_LENGTH
) + 1;
1125 assert(namelen
> 0);
1127 if ((pg_name
= malloc(namelen
)) == NULL
) {
1128 if (scf_error() == SCF_ERROR_NOT_SET
) {
1129 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1134 if (scf_pg_get_name(simple_h
->running_pg
, pg_name
, namelen
) < 0) {
1135 if (scf_error() == SCF_ERROR_NOT_SET
) {
1136 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1141 /* Get pg from instance */
1142 if (scf_instance_get_pg(simple_h
->inst
, pg_name
, ret_pg
) == -1) {
1150 smf_enable_instance(const char *fmri
, int flags
)
1152 return (set_inst_enabled_flags(fmri
, flags
, B_TRUE
));
1156 smf_disable_instance(const char *fmri
, int flags
)
1158 return (set_inst_enabled_flags(fmri
, flags
, B_FALSE
));
1162 _smf_refresh_instance_i(scf_instance_t
*inst
)
1164 return (set_inst_action_inst(inst
, SCF_PROPERTY_REFRESH
));
1168 _smf_refresh_all_instances(scf_service_t
*s
)
1170 scf_handle_t
*h
= scf_service_handle(s
);
1171 scf_instance_t
*i
= scf_instance_create(h
);
1172 scf_iter_t
*it
= scf_iter_create(h
);
1175 if (h
== NULL
|| i
== NULL
|| it
== NULL
)
1178 if (scf_iter_service_instances(it
, s
) != 0)
1181 while ((err
= scf_iter_next_instance(it
, i
)) == 1)
1182 if (_smf_refresh_instance_i(i
) != 0)
1190 scf_instance_destroy(i
);
1191 scf_iter_destroy(it
);
1197 smf_refresh_instance(const char *instance
)
1199 return (set_inst_action(instance
, SCF_PROPERTY_REFRESH
));
1203 smf_restart_instance(const char *instance
)
1205 return (set_inst_action(instance
, SCF_PROPERTY_RESTART
));
1209 smf_maintain_instance(const char *instance
, int flags
)
1211 if (flags
& SMF_TEMPORARY
)
1212 return (set_inst_action(instance
,
1213 (flags
& SMF_IMMEDIATE
) ?
1214 SCF_PROPERTY_MAINT_ON_IMMTEMP
:
1215 SCF_PROPERTY_MAINT_ON_TEMPORARY
));
1217 return (set_inst_action(instance
,
1218 (flags
& SMF_IMMEDIATE
) ?
1219 SCF_PROPERTY_MAINT_ON_IMMEDIATE
:
1220 SCF_PROPERTY_MAINT_ON
));
1224 smf_degrade_instance(const char *instance
, int flags
)
1226 scf_simple_prop_t
*prop
;
1227 const char *state_str
;
1229 if (flags
& SMF_TEMPORARY
)
1230 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1232 if ((prop
= scf_simple_prop_get(NULL
, instance
, SCF_PG_RESTARTER
,
1233 SCF_PROPERTY_STATE
)) == NULL
)
1234 return (SCF_FAILED
);
1236 if ((state_str
= scf_simple_prop_next_astring(prop
)) == NULL
) {
1237 scf_simple_prop_free(prop
);
1238 return (SCF_FAILED
);
1241 if (strcmp(state_str
, SCF_STATE_STRING_ONLINE
) != 0) {
1242 scf_simple_prop_free(prop
);
1243 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
));
1245 scf_simple_prop_free(prop
);
1247 return (set_inst_action(instance
, (flags
& SMF_IMMEDIATE
) ?
1248 SCF_PROPERTY_DEGRADE_IMMEDIATE
: SCF_PROPERTY_DEGRADED
));
1252 smf_restore_instance(const char *instance
)
1254 scf_simple_prop_t
*prop
;
1255 const char *state_str
;
1258 if ((prop
= scf_simple_prop_get(NULL
, instance
, SCF_PG_RESTARTER
,
1259 SCF_PROPERTY_STATE
)) == NULL
)
1260 return (SCF_FAILED
);
1262 if ((state_str
= scf_simple_prop_next_astring(prop
)) == NULL
) {
1263 scf_simple_prop_free(prop
);
1264 return (SCF_FAILED
);
1267 if (strcmp(state_str
, SCF_STATE_STRING_MAINT
) == 0) {
1268 ret
= set_inst_action(instance
, SCF_PROPERTY_MAINT_OFF
);
1269 } else if (strcmp(state_str
, SCF_STATE_STRING_DEGRADED
) == 0) {
1270 ret
= set_inst_action(instance
, SCF_PROPERTY_RESTORE
);
1272 ret
= scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
);
1275 scf_simple_prop_free(prop
);
1280 smf_get_state(const char *instance
)
1282 scf_simple_prop_t
*prop
;
1283 const char *state_str
;
1286 if ((prop
= scf_simple_prop_get(NULL
, instance
, SCF_PG_RESTARTER
,
1287 SCF_PROPERTY_STATE
)) == NULL
)
1290 if ((state_str
= scf_simple_prop_next_astring(prop
)) == NULL
) {
1291 scf_simple_prop_free(prop
);
1295 if ((ret
= strdup(state_str
)) == NULL
)
1296 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1298 scf_simple_prop_free(prop
);
1303 * scf_general_pg_setup(fmri, pg_name)
1304 * Create a scf_simple_handle_t and fill in the instance, snapshot, and
1305 * property group fields associated with the given fmri and property group
1309 * Null on error with scf_error set to:
1310 * SCF_ERROR_HANDLE_MISMATCH,
1311 * SCF_ERROR_INVALID_ARGUMENT,
1312 * SCF_ERROR_CONSTRAINT_VIOLATED,
1313 * SCF_ERROR_NOT_FOUND,
1314 * SCF_ERROR_NOT_SET,
1315 * SCF_ERROR_DELETED,
1316 * SCF_ERROR_NOT_BOUND,
1317 * SCF_ERROR_CONNECTION_BROKEN,
1318 * SCF_ERROR_INTERNAL,
1319 * SCF_ERROR_NO_RESOURCES,
1320 * SCF_ERROR_BACKEND_ACCESS
1322 scf_simple_handle_t
*
1323 scf_general_pg_setup(const char *fmri
, const char *pg_name
)
1325 scf_simple_handle_t
*ret
;
1327 ret
= uu_zalloc(sizeof (*ret
));
1329 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1333 ret
->h
= _scf_handle_create_and_bind(SCF_VERSION
);
1334 ret
->inst
= scf_instance_create(ret
->h
);
1335 ret
->snap
= scf_snapshot_create(ret
->h
);
1336 ret
->running_pg
= scf_pg_create(ret
->h
);
1339 if ((ret
->h
== NULL
) || (ret
->inst
== NULL
) ||
1340 (ret
->snap
== NULL
) || (ret
->running_pg
== NULL
)) {
1344 if (scf_handle_decode_fmri(ret
->h
, fmri
, NULL
, NULL
, ret
->inst
,
1345 NULL
, NULL
, 0) == -1) {
1349 if ((scf_instance_get_snapshot(ret
->inst
, "running", ret
->snap
))
1354 if (scf_instance_get_pg_composed(ret
->inst
, ret
->snap
, pg_name
,
1355 ret
->running_pg
) != 0) {
1362 scf_simple_handle_destroy(ret
);
1367 * scf_transaction_setup(h)
1368 * creates and starts the transaction
1370 * transaction on success
1371 * NULL on failure with scf_error set to:
1372 * SCF_ERROR_NO_MEMORY,
1373 * SCF_ERROR_INVALID_ARGUMENT,
1374 * SCF_ERROR_HANDLE_DESTROYED,
1375 * SCF_ERROR_INTERNAL,
1376 * SCF_ERROR_NO_RESOURCES,
1377 * SCF_ERROR_NOT_BOUND,
1378 * SCF_ERROR_CONNECTION_BROKEN,
1379 * SCF_ERROR_NOT_SET,
1380 * SCF_ERROR_DELETED,
1381 * SCF_ERROR_CONSTRAINT_VIOLATED,
1382 * SCF_ERROR_HANDLE_MISMATCH,
1383 * SCF_ERROR_BACKEND_ACCESS,
1387 scf_transaction_setup(scf_simple_handle_t
*simple_h
)
1389 scf_transaction_t
*tx
= NULL
;
1391 if ((tx
= scf_transaction_create(simple_h
->h
)) == NULL
) {
1395 if ((simple_h
->editing_pg
= get_instance_pg(simple_h
)) == NULL
) {
1399 if (scf_transaction_start(tx
, simple_h
->editing_pg
) == -1) {
1400 scf_pg_destroy(simple_h
->editing_pg
);
1401 simple_h
->editing_pg
= NULL
;
1409 scf_transaction_restart(scf_simple_handle_t
*simple_h
, scf_transaction_t
*tx
)
1411 scf_transaction_reset(tx
);
1413 if (scf_pg_update(simple_h
->editing_pg
) == -1) {
1414 return (SCF_FAILED
);
1417 if (scf_transaction_start(tx
, simple_h
->editing_pg
) == -1) {
1418 return (SCF_FAILED
);
1421 return (SCF_SUCCESS
);
1425 * scf_read_count_property(scf_simple_handle_t *simple_h, char *prop_name,
1426 * uint64_t *ret_count)
1428 * For the given property name, return the count value.
1431 * SCF_FAILED on failure with scf_error() set to:
1432 * SCF_ERROR_HANDLE_DESTROYED
1433 * SCF_ERROR_INTERNAL
1434 * SCF_ERROR_NO_RESOURCES
1435 * SCF_ERROR_NO_MEMORY
1436 * SCF_ERROR_HANDLE_MISMATCH
1437 * SCF_ERROR_INVALID_ARGUMENT
1438 * SCF_ERROR_NOT_BOUND
1439 * SCF_ERROR_CONNECTION_BROKEN
1442 * SCF_ERROR_BACKEND_ACCESS
1443 * SCF_ERROR_CONSTRAINT_VIOLATED
1444 * SCF_ERROR_TYPE_MISMATCH
1447 scf_read_count_property(
1448 scf_simple_handle_t
*simple_h
,
1450 uint64_t *ret_count
)
1452 scf_property_t
*prop
= scf_property_create(simple_h
->h
);
1453 scf_value_t
*val
= scf_value_create(simple_h
->h
);
1454 int ret
= SCF_FAILED
;
1456 if ((val
== NULL
) || (prop
== NULL
)) {
1461 * Get the property struct that goes with this property group and
1464 if (scf_pg_get_property(simple_h
->running_pg
, prop_name
, prop
) != 0) {
1468 /* Get the value structure */
1469 if (scf_property_get_value(prop
, val
) == -1) {
1474 * Now get the count value.
1476 if (scf_value_get_count(val
, ret_count
) == -1) {
1483 scf_property_destroy(prop
);
1484 scf_value_destroy(val
);
1489 * scf_trans_add_count_property(trans, propname, count, create_flag)
1491 * Set a count property transaction entry into the pending SMF transaction.
1492 * The transaction is created and committed outside of this function.
1495 * SCF_FAILED on failure with scf_error() set to:
1496 * SCF_ERROR_HANDLE_DESTROYED,
1497 * SCF_ERROR_INVALID_ARGUMENT,
1498 * SCF_ERROR_NO_MEMORY,
1499 * SCF_ERROR_HANDLE_MISMATCH,
1500 * SCF_ERROR_NOT_SET,
1502 * SCF_ERROR_NOT_FOUND,
1504 * SCF_ERROR_TYPE_MISMATCH,
1505 * SCF_ERROR_NOT_BOUND,
1506 * SCF_ERROR_CONNECTION_BROKEN,
1507 * SCF_ERROR_INTERNAL,
1508 * SCF_ERROR_DELETED,
1509 * SCF_ERROR_NO_RESOURCES,
1510 * SCF_ERROR_BACKEND_ACCESS
1513 scf_set_count_property(
1514 scf_transaction_t
*trans
,
1517 boolean_t create_flag
)
1519 scf_handle_t
*handle
= scf_transaction_handle(trans
);
1520 scf_value_t
*value
= scf_value_create(handle
);
1521 scf_transaction_entry_t
*entry
= scf_entry_create(handle
);
1523 if ((value
== NULL
) || (entry
== NULL
)) {
1524 return (SCF_FAILED
);
1528 * Property must be set in transaction and won't take
1529 * effect until the transaction is committed.
1531 * Attempt to change the current value. However, create new property
1532 * if it doesn't exist and the create flag is set.
1534 if (scf_transaction_property_change(trans
, entry
, propname
,
1535 SCF_TYPE_COUNT
) == 0) {
1536 scf_value_set_count(value
, count
);
1537 if (scf_entry_add_value(entry
, value
) == 0) {
1538 return (SCF_SUCCESS
);
1541 if ((create_flag
== B_TRUE
) &&
1542 (scf_error() == SCF_ERROR_NOT_FOUND
)) {
1543 if (scf_transaction_property_new(trans
, entry
, propname
,
1544 SCF_TYPE_COUNT
) == 0) {
1545 scf_value_set_count(value
, count
);
1546 if (scf_entry_add_value(entry
, value
) == 0) {
1547 return (SCF_SUCCESS
);
1554 * cleanup if there were any errors that didn't leave these
1555 * values where they would be cleaned up later.
1558 scf_value_destroy(value
);
1560 scf_entry_destroy(entry
);
1561 return (SCF_FAILED
);
1565 scf_simple_walk_instances(uint_t state_flags
, void *private,
1566 int (*inst_callback
)(scf_handle_t
*, scf_instance_t
*, void *))
1568 scf_scope_t
*scope
= NULL
;
1569 scf_service_t
*svc
= NULL
;
1570 scf_instance_t
*inst
= NULL
;
1571 scf_iter_t
*svc_iter
= NULL
, *inst_iter
= NULL
;
1572 scf_handle_t
*h
= NULL
;
1573 int ret
= SCF_FAILED
;
1574 int svc_iter_ret
, inst_iter_ret
;
1577 if ((h
= _scf_handle_create_and_bind(SCF_VERSION
)) == NULL
)
1580 if (((scope
= scf_scope_create(h
)) == NULL
) ||
1581 ((svc
= scf_service_create(h
)) == NULL
) ||
1582 ((inst
= scf_instance_create(h
)) == NULL
) ||
1583 ((svc_iter
= scf_iter_create(h
)) == NULL
) ||
1584 ((inst_iter
= scf_iter_create(h
)) == NULL
))
1588 * Get the local scope, and set up nested iteration through every
1589 * local service, and every instance of every service.
1592 if ((scf_handle_get_local_scope(h
, scope
) != SCF_SUCCESS
) ||
1593 (scf_iter_scope_services(svc_iter
, scope
) != SCF_SUCCESS
))
1596 while ((svc_iter_ret
= scf_iter_next_service(svc_iter
, svc
)) > 0) {
1598 if ((scf_iter_service_instances(inst_iter
, svc
)) !=
1602 while ((inst_iter_ret
=
1603 scf_iter_next_instance(inst_iter
, inst
)) > 0) {
1605 * If get_inst_state fails from an internal error,
1606 * IE, being unable to get the property group or
1607 * property containing the state of the instance,
1608 * we continue instead of failing, as this might just
1609 * be an improperly configured instance.
1611 if ((inst_state
= get_inst_state(inst
, h
)) == -1) {
1612 if (scf_error() == SCF_ERROR_INTERNAL
) {
1619 if ((uint_t
)inst_state
& state_flags
) {
1620 if (inst_callback(h
, inst
, private) !=
1622 (void) scf_set_error(
1623 SCF_ERROR_CALLBACK_FAILED
);
1629 if (inst_iter_ret
== -1)
1631 scf_iter_reset(inst_iter
);
1634 if (svc_iter_ret
!= -1)
1638 scf_scope_destroy(scope
);
1639 scf_service_destroy(svc
);
1640 scf_instance_destroy(inst
);
1641 scf_iter_destroy(svc_iter
);
1642 scf_iter_destroy(inst_iter
);
1643 scf_handle_destroy(h
);
1650 scf_simple_prop_get(scf_handle_t
*hin
, const char *instance
, const char *pgname
,
1651 const char *propname
)
1653 char *fmri_buf
, *svcfmri
= NULL
;
1655 scf_property_t
*prop
= NULL
;
1656 scf_service_t
*svc
= NULL
;
1657 scf_simple_prop_t
*ret
;
1658 scf_handle_t
*h
= NULL
;
1659 boolean_t local_h
= B_TRUE
;
1661 /* If the user passed in a handle, use it. */
1667 if (local_h
&& ((h
= _scf_handle_create_and_bind(SCF_VERSION
)) == NULL
))
1670 if ((fmri_buf
= assemble_fmri(h
, instance
, pgname
, propname
)) == NULL
) {
1672 scf_handle_destroy(h
);
1676 if ((svc
= scf_service_create(h
)) == NULL
||
1677 (prop
= scf_property_create(h
)) == NULL
)
1679 if (scf_handle_decode_fmri(h
, fmri_buf
, NULL
, NULL
, NULL
, NULL
, prop
,
1680 SCF_DECODE_FMRI_REQUIRE_INSTANCE
) == -1) {
1681 switch (scf_error()) {
1683 * If the property isn't found in the instance, we grab the
1684 * underlying service, create an FMRI out of it, and then
1685 * query the datastore again at the service level for the
1688 case SCF_ERROR_NOT_FOUND
:
1689 if (scf_handle_decode_fmri(h
, fmri_buf
, NULL
, svc
,
1690 NULL
, NULL
, NULL
, SCF_DECODE_FMRI_TRUNCATE
) == -1)
1693 fmri_sz
= scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH
) + 1;
1694 assert(fmri_sz
> 0);
1696 if (scf_service_to_fmri(svc
, fmri_buf
, fmri_sz
) == -1)
1698 if ((svcfmri
= assemble_fmri(h
, fmri_buf
, pgname
,
1701 if (scf_handle_decode_fmri(h
, svcfmri
, NULL
, NULL
,
1702 NULL
, NULL
, prop
, 0) == -1) {
1708 case SCF_ERROR_CONSTRAINT_VIOLATED
:
1709 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
1715 * At this point, we've successfully pulled the property from the
1716 * datastore, and simply need to copy its innards into an
1717 * scf_simple_prop_t.
1719 if ((ret
= fill_prop(prop
, pgname
, propname
, h
)) == NULL
)
1722 scf_service_destroy(svc
);
1723 scf_property_destroy(prop
);
1726 scf_handle_destroy(h
);
1730 * Exit point for a successful call. Below this line are exit points
1731 * for failures at various stages during the function.
1735 scf_service_destroy(svc
);
1736 scf_property_destroy(prop
);
1740 scf_handle_destroy(h
);
1746 scf_simple_prop_free(scf_simple_prop_t
*prop
)
1753 free(prop
->pr_propname
);
1754 free(prop
->pr_pgname
);
1755 switch (prop
->pr_type
) {
1756 case SCF_TYPE_OPAQUE
: {
1757 for (i
= 0; i
< prop
->pr_numvalues
; i
++) {
1758 free(prop
->pr_vallist
[i
].pv_opaque
.o_value
);
1762 case SCF_TYPE_ASTRING
:
1763 case SCF_TYPE_USTRING
:
1765 case SCF_TYPE_HOSTNAME
:
1766 case SCF_TYPE_NET_ADDR
:
1767 case SCF_TYPE_NET_ADDR_V4
:
1768 case SCF_TYPE_NET_ADDR_V6
:
1770 case SCF_TYPE_FMRI
: {
1771 for (i
= 0; i
< prop
->pr_numvalues
; i
++) {
1772 free(prop
->pr_vallist
[i
].pv_str
);
1779 free(prop
->pr_vallist
);
1784 scf_simple_app_props_t
*
1785 scf_simple_app_props_get(scf_handle_t
*hin
, const char *inst_fmri
)
1787 scf_instance_t
*inst
= NULL
;
1788 scf_service_t
*svc
= NULL
;
1789 scf_propertygroup_t
*pg
= NULL
;
1790 scf_property_t
*prop
= NULL
;
1791 scf_simple_app_props_t
*ret
= NULL
;
1792 scf_iter_t
*pgiter
= NULL
, *propiter
= NULL
;
1793 struct scf_simple_pg
*thispg
= NULL
, *nextpg
;
1794 scf_simple_prop_t
*thisprop
, *nextprop
;
1795 scf_handle_t
*h
= NULL
;
1796 int pgiter_ret
, propiter_ret
;
1798 char *propname
= NULL
, *pgname
= NULL
, *sys_fmri
;
1800 boolean_t local_h
= B_TRUE
;
1802 /* If the user passed in a handle, use it. */
1808 if (local_h
&& ((h
= _scf_handle_create_and_bind(SCF_VERSION
)) == NULL
))
1811 if (inst_fmri
== NULL
) {
1812 if ((namelen
= scf_myname(h
, NULL
, 0)) == -1) {
1814 scf_handle_destroy(h
);
1817 if ((sys_fmri
= malloc(namelen
+ 1)) == NULL
) {
1819 scf_handle_destroy(h
);
1820 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1823 if (scf_myname(h
, sys_fmri
, namelen
+ 1) == -1) {
1825 scf_handle_destroy(h
);
1830 if ((sys_fmri
= strdup(inst_fmri
)) == NULL
) {
1832 scf_handle_destroy(h
);
1833 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1838 namelen
= scf_limit(SCF_LIMIT_MAX_NAME_LENGTH
) + 1;
1839 assert(namelen
> 0);
1841 if ((inst
= scf_instance_create(h
)) == NULL
||
1842 (svc
= scf_service_create(h
)) == NULL
||
1843 (pgiter
= scf_iter_create(h
)) == NULL
||
1844 (propiter
= scf_iter_create(h
)) == NULL
||
1845 (pg
= scf_pg_create(h
)) == NULL
||
1846 (prop
= scf_property_create(h
)) == NULL
) {
1851 if (scf_handle_decode_fmri(h
, sys_fmri
, NULL
, svc
, inst
, NULL
, NULL
,
1852 SCF_DECODE_FMRI_REQUIRE_INSTANCE
) == -1) {
1854 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED
)
1855 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
1859 if ((ret
= malloc(sizeof (*ret
))) == NULL
||
1860 (thispg
= malloc(sizeof (*thispg
))) == NULL
||
1861 (propname
= malloc(namelen
)) == NULL
||
1862 (pgname
= malloc(namelen
)) == NULL
) {
1866 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1870 ret
->ap_fmri
= sys_fmri
;
1871 thispg
->pg_name
= NULL
;
1872 thispg
->pg_proplist
= NULL
;
1873 thispg
->pg_next
= NULL
;
1874 ret
->ap_pglist
= thispg
;
1876 if (scf_iter_service_pgs_typed(pgiter
, svc
, SCF_GROUP_APPLICATION
) !=
1878 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1879 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1883 while ((pgiter_ret
= scf_iter_next_pg(pgiter
, pg
)) == 1) {
1884 if (thispg
->pg_name
!= NULL
) {
1885 if ((nextpg
= malloc(sizeof (*nextpg
))) == NULL
) {
1886 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1889 nextpg
->pg_name
= NULL
;
1890 nextpg
->pg_next
= NULL
;
1891 nextpg
->pg_proplist
= NULL
;
1892 thispg
->pg_next
= nextpg
;
1895 /* This is the first iteration */
1899 if ((nextpg
->pg_name
= malloc(namelen
)) == NULL
) {
1900 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1904 if (scf_pg_get_name(pg
, nextpg
->pg_name
, namelen
) < 0) {
1905 if (scf_error() == SCF_ERROR_NOT_SET
)
1906 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1912 scf_iter_reset(propiter
);
1914 if (scf_iter_pg_properties(propiter
, pg
) != 0) {
1915 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1916 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1920 while ((propiter_ret
= scf_iter_next_property(propiter
, prop
))
1922 if (scf_property_get_name(prop
, propname
, namelen
) <
1924 if (scf_error() == SCF_ERROR_NOT_SET
)
1925 (void) scf_set_error(
1926 SCF_ERROR_INTERNAL
);
1929 if (thisprop
!= NULL
) {
1930 if ((nextprop
= fill_prop(prop
,
1931 nextpg
->pg_name
, propname
, h
)) == NULL
)
1933 thisprop
->pr_next
= nextprop
;
1934 thisprop
= nextprop
;
1936 /* This is the first iteration */
1937 if ((thisprop
= fill_prop(prop
,
1938 nextpg
->pg_name
, propname
, h
)) == NULL
)
1940 nextpg
->pg_proplist
= thisprop
;
1941 nextprop
= thisprop
;
1943 nextprop
->pr_pg
= nextpg
;
1944 nextprop
->pr_next
= NULL
;
1947 if (propiter_ret
== -1) {
1948 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1949 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1954 if (pgiter_ret
== -1) {
1955 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1956 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1961 * At this point, we've filled the scf_simple_app_props_t with all the
1962 * properties at the service level. Now we iterate over all the
1963 * properties at the instance level, overwriting any duplicate
1964 * properties, in order to provide service/instance composition.
1967 scf_iter_reset(pgiter
);
1968 scf_iter_reset(propiter
);
1970 if (scf_iter_instance_pgs_typed(pgiter
, inst
, SCF_GROUP_APPLICATION
)
1972 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1973 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1977 while ((pgiter_ret
= scf_iter_next_pg(pgiter
, pg
)) == 1) {
1979 thispg
= ret
->ap_pglist
;
1983 * Find either the end of the list, so we can append the
1984 * property group, or an existing property group that matches
1985 * it, so we can insert/overwrite its properties.
1988 if (scf_pg_get_name(pg
, pgname
, namelen
) < 0) {
1989 if (scf_error() == SCF_ERROR_NOT_SET
)
1990 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1994 while ((thispg
!= NULL
) && (thispg
->pg_name
!= NULL
)) {
1995 if (strcmp(thispg
->pg_name
, pgname
) == 0) {
1999 if (thispg
->pg_next
== NULL
)
2002 thispg
= thispg
->pg_next
;
2005 scf_iter_reset(propiter
);
2007 if (scf_iter_pg_properties(propiter
, pg
) != 0) {
2008 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
2009 (void) scf_set_error(SCF_ERROR_INTERNAL
);
2015 * insert_app_props inserts or overwrites the
2016 * properties in thispg.
2019 if (insert_app_props(propiter
, pgname
, propname
,
2020 thispg
, prop
, namelen
, h
) == -1)
2025 * If the property group wasn't found, we're adding
2026 * a newly allocated property group to the end of the
2030 if ((nextpg
= malloc(sizeof (*nextpg
))) == NULL
) {
2031 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2034 nextpg
->pg_next
= NULL
;
2035 nextpg
->pg_proplist
= NULL
;
2038 if ((nextpg
->pg_name
= strdup(pgname
)) == NULL
) {
2039 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2044 if (thispg
->pg_name
== NULL
) {
2046 ret
->ap_pglist
= nextpg
;
2048 thispg
->pg_next
= nextpg
;
2051 while ((propiter_ret
=
2052 scf_iter_next_property(propiter
, prop
)) == 1) {
2053 if (scf_property_get_name(prop
, propname
,
2055 if (scf_error() == SCF_ERROR_NOT_SET
)
2056 (void) scf_set_error(
2057 SCF_ERROR_INTERNAL
);
2060 if (thisprop
!= NULL
) {
2061 if ((nextprop
= fill_prop(prop
,
2062 pgname
, propname
, h
)) ==
2065 thisprop
->pr_next
= nextprop
;
2066 thisprop
= nextprop
;
2068 /* This is the first iteration */
2069 if ((thisprop
= fill_prop(prop
,
2070 pgname
, propname
, h
)) ==
2073 nextpg
->pg_proplist
= thisprop
;
2074 nextprop
= thisprop
;
2076 nextprop
->pr_pg
= nextpg
;
2077 nextprop
->pr_next
= NULL
;
2080 if (propiter_ret
== -1) {
2081 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
2082 (void) scf_set_error(
2083 SCF_ERROR_INTERNAL
);
2090 if (pgiter_ret
== -1) {
2091 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
2092 (void) scf_set_error(SCF_ERROR_INTERNAL
);
2096 if (ret
->ap_pglist
->pg_name
== NULL
)
2099 scf_iter_destroy(pgiter
);
2100 scf_iter_destroy(propiter
);
2102 scf_property_destroy(prop
);
2103 scf_instance_destroy(inst
);
2104 scf_service_destroy(svc
);
2108 scf_handle_destroy(h
);
2113 * Exit point for a successful call. Below this line are exit points
2114 * for failures at various stages during the function.
2118 scf_simple_app_props_free(ret
);
2121 scf_iter_destroy(pgiter
);
2122 scf_iter_destroy(propiter
);
2124 scf_property_destroy(prop
);
2125 scf_instance_destroy(inst
);
2126 scf_service_destroy(svc
);
2130 scf_handle_destroy(h
);
2136 scf_simple_app_props_free(scf_simple_app_props_t
*propblock
)
2138 struct scf_simple_pg
*pgthis
, *pgnext
;
2139 scf_simple_prop_t
*propthis
, *propnext
;
2141 if ((propblock
== NULL
) || (propblock
->ap_pglist
== NULL
))
2144 for (pgthis
= propblock
->ap_pglist
; pgthis
!= NULL
; pgthis
= pgnext
) {
2145 pgnext
= pgthis
->pg_next
;
2147 propthis
= pgthis
->pg_proplist
;
2149 while (propthis
!= NULL
) {
2150 propnext
= propthis
->pr_next
;
2151 scf_simple_prop_free(propthis
);
2152 propthis
= propnext
;
2155 free(pgthis
->pg_name
);
2159 free(propblock
->ap_fmri
);
2163 const scf_simple_prop_t
*
2164 scf_simple_app_props_next(const scf_simple_app_props_t
*propblock
,
2165 scf_simple_prop_t
*last
)
2167 struct scf_simple_pg
*this;
2169 if (propblock
== NULL
) {
2170 (void) scf_set_error(SCF_ERROR_NOT_SET
);
2174 this = propblock
->ap_pglist
;
2177 * We're looking for the first property in this block if last is
2182 /* An empty pglist is legal, it just means no properties */
2184 (void) scf_set_error(SCF_ERROR_NONE
);
2188 * Walk until we find a pg with a property in it, or we run
2189 * out of property groups.
2191 while ((this->pg_proplist
== NULL
) && (this->pg_next
!= NULL
))
2192 this = this->pg_next
;
2194 if (this->pg_proplist
== NULL
) {
2195 (void) scf_set_error(SCF_ERROR_NONE
);
2199 return (this->pg_proplist
);
2203 * If last isn't NULL, then return the next prop in the property group,
2204 * or walk the property groups until we find another property, or
2205 * run out of property groups.
2207 if (last
->pr_next
!= NULL
)
2208 return (last
->pr_next
);
2210 if (last
->pr_pg
->pg_next
== NULL
) {
2211 (void) scf_set_error(SCF_ERROR_NONE
);
2215 this = last
->pr_pg
->pg_next
;
2217 while ((this->pg_proplist
== NULL
) && (this->pg_next
!= NULL
))
2218 this = this->pg_next
;
2220 if (this->pg_proplist
== NULL
) {
2221 (void) scf_set_error(SCF_ERROR_NONE
);
2225 return (this->pg_proplist
);
2228 const scf_simple_prop_t
*
2229 scf_simple_app_props_search(const scf_simple_app_props_t
*propblock
,
2230 const char *pgname
, const char *propname
)
2232 struct scf_simple_pg
*pg
;
2233 scf_simple_prop_t
*prop
;
2235 if ((propblock
== NULL
) || (propname
== NULL
)) {
2236 (void) scf_set_error(SCF_ERROR_NOT_SET
);
2240 pg
= propblock
->ap_pglist
;
2243 * If pgname is NULL, we're searching the default application
2244 * property group, otherwise we look for the specified group.
2246 if (pgname
== NULL
) {
2247 while ((pg
!= NULL
) &&
2248 (strcmp(SCF_PG_APP_DEFAULT
, pg
->pg_name
) != 0))
2251 while ((pg
!= NULL
) && (strcmp(pgname
, pg
->pg_name
) != 0))
2256 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
2260 prop
= pg
->pg_proplist
;
2262 while ((prop
!= NULL
) && (strcmp(propname
, prop
->pr_propname
) != 0))
2263 prop
= prop
->pr_next
;
2266 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
2274 scf_simple_prop_next_reset(scf_simple_prop_t
*prop
)
2282 scf_simple_prop_numvalues(const scf_simple_prop_t
*prop
)
2285 return (scf_set_error(SCF_ERROR_NOT_SET
));
2287 return (prop
->pr_numvalues
);
2292 scf_simple_prop_type(const scf_simple_prop_t
*prop
)
2295 return (scf_set_error(SCF_ERROR_NOT_SET
));
2297 return (prop
->pr_type
);
2302 scf_simple_prop_name(const scf_simple_prop_t
*prop
)
2304 if ((prop
== NULL
) || (prop
->pr_propname
== NULL
)) {
2305 (void) scf_set_error(SCF_ERROR_NOT_SET
);
2309 return (prop
->pr_propname
);
2314 scf_simple_prop_pgname(const scf_simple_prop_t
*prop
)
2316 if ((prop
== NULL
) || (prop
->pr_pgname
== NULL
)) {
2317 (void) scf_set_error(SCF_ERROR_NOT_SET
);
2321 return (prop
->pr_pgname
);
2325 static union scf_simple_prop_val
*
2326 scf_next_val(scf_simple_prop_t
*prop
, scf_type_t type
)
2329 (void) scf_set_error(SCF_ERROR_NOT_SET
);
2333 switch (prop
->pr_type
) {
2334 case SCF_TYPE_USTRING
:
2336 case SCF_TYPE_HOSTNAME
:
2337 case SCF_TYPE_NET_ADDR
:
2338 case SCF_TYPE_NET_ADDR_V4
:
2339 case SCF_TYPE_NET_ADDR_V6
:
2341 case SCF_TYPE_FMRI
: {
2342 if (type
!= SCF_TYPE_USTRING
) {
2343 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH
);
2349 if (type
!= prop
->pr_type
) {
2350 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH
);
2357 if (prop
->pr_iter
>= prop
->pr_numvalues
) {
2358 (void) scf_set_error(SCF_ERROR_NONE
);
2362 return (&prop
->pr_vallist
[prop
->pr_iter
++]);
2367 scf_simple_prop_next_boolean(scf_simple_prop_t
*prop
)
2369 union scf_simple_prop_val
*ret
;
2371 ret
= scf_next_val(prop
, SCF_TYPE_BOOLEAN
);
2376 return (&ret
->pv_bool
);
2381 scf_simple_prop_next_count(scf_simple_prop_t
*prop
)
2383 union scf_simple_prop_val
*ret
;
2385 ret
= scf_next_val(prop
, SCF_TYPE_COUNT
);
2390 return (&ret
->pv_uint
);
2395 scf_simple_prop_next_integer(scf_simple_prop_t
*prop
)
2397 union scf_simple_prop_val
*ret
;
2399 ret
= scf_next_val(prop
, SCF_TYPE_INTEGER
);
2404 return (&ret
->pv_int
);
2408 scf_simple_prop_next_time(scf_simple_prop_t
*prop
, int32_t *nsec
)
2410 union scf_simple_prop_val
*ret
;
2412 ret
= scf_next_val(prop
, SCF_TYPE_TIME
);
2418 *nsec
= ret
->pv_time
.t_nsec
;
2420 return (&ret
->pv_time
.t_sec
);
2424 scf_simple_prop_next_astring(scf_simple_prop_t
*prop
)
2426 union scf_simple_prop_val
*ret
;
2428 ret
= scf_next_val(prop
, SCF_TYPE_ASTRING
);
2433 return (ret
->pv_str
);
2437 scf_simple_prop_next_ustring(scf_simple_prop_t
*prop
)
2439 union scf_simple_prop_val
*ret
;
2441 ret
= scf_next_val(prop
, SCF_TYPE_USTRING
);
2446 return (ret
->pv_str
);
2450 scf_simple_prop_next_opaque(scf_simple_prop_t
*prop
, size_t *length
)
2452 union scf_simple_prop_val
*ret
;
2454 ret
= scf_next_val(prop
, SCF_TYPE_OPAQUE
);
2461 *length
= ret
->pv_opaque
.o_size
;
2462 return (ret
->pv_opaque
.o_value
);
2466 * Generate a filename based on the fmri and the given name and return
2467 * it in the buffer of MAXPATHLEN provided by the caller.
2468 * If temp_filename is non-zero, also generate a temporary, unique filename
2469 * and return it in the temp buffer of MAXPATHLEN provided by the caller.
2470 * The path to the generated pathname is also created.
2471 * Given fmri should begin with a scheme such as "svc:".
2474 * -1 if filename would exceed MAXPATHLEN or
2475 * -2 if unable to create directory to filename path
2478 gen_filenms_from_fmri(const char *fmri
, const char *name
, char *filename
,
2479 char *temp_filename
)
2483 len
= strlen(SMF_SPEEDY_FILES_PATH
);
2484 len
+= strlen(fmri
);
2485 len
+= 2; /* for slash and null */
2486 len
+= strlen(name
);
2487 len
+= 6; /* For X's needed for mkstemp */
2489 if (len
> MAXPATHLEN
)
2492 /* Construct directory name first - speedy path ends in slash */
2493 (void) strcpy(filename
, SMF_SPEEDY_FILES_PATH
);
2494 (void) strcat(filename
, fmri
);
2495 if (mkdirp(filename
, 0755) == -1) {
2497 if (errno
!= EEXIST
)
2501 (void) strcat(filename
, "/");
2502 (void) strcat(filename
, name
);
2504 if (temp_filename
) {
2505 (void) strcpy(temp_filename
, filename
);
2506 (void) strcat(temp_filename
, "XXXXXX");
2513 scf_true_base_type(scf_type_t type
)
2515 scf_type_t base
= type
;
2519 (void) scf_type_base_type(type
, &base
);
2520 } while (base
!= type
);
2526 * Convenience routine which frees all strings and opaque data
2527 * allocated by scf_read_propvec.
2529 * Like free(3C), this function preserves the value of errno.
2532 scf_clean_propvec(scf_propvec_t
*propvec
)
2534 int saved_errno
= errno
;
2535 scf_propvec_t
*prop
;
2537 for (prop
= propvec
; prop
->pv_prop
!= NULL
; prop
++) {
2538 assert(prop
->pv_type
!= SCF_TYPE_INVALID
);
2539 if (prop
->pv_type
== SCF_TYPE_OPAQUE
) {
2540 scf_opaque_t
*o
= prop
->pv_ptr
;
2543 } else if (scf_true_base_type(prop
->pv_type
) ==
2545 free(*(char **)prop
->pv_ptr
);
2549 errno
= saved_errno
;
2553 count_props(scf_propvec_t
*props
)
2557 for (; props
->pv_prop
!= NULL
; props
++)
2563 * Reads a vector of properties from the specified fmri/property group.
2564 * If 'running' is true, reads from the running snapshot instead of the
2567 * For string types, a buffer is allocated using malloc(3C) to hold the
2568 * zero-terminated string, a pointer to which is stored in the
2569 * caller-provided char **. It is the caller's responsbility to free
2570 * this string. To simplify error handling, unread strings are
2571 * initialized to NULL.
2573 * For opaque types, a buffer is allocated using malloc(3C) to hold the
2574 * opaque data. A pointer to this buffer and its size are stored in
2575 * the caller-provided scf_opaque_t. It is the caller's responsibility
2576 * to free this buffer. To simplify error handling, the address fields
2577 * for unread opaque data are initialized to NULL.
2579 * All other data is stored directly in caller-provided variables or
2582 * If this function fails to read a specific property, *badprop is set
2583 * to point at that property's entry in the properties array.
2585 * On all failures, all memory allocated by this function is freed.
2588 scf_read_propvec(const char *fmri
, const char *pgname
, boolean_t running
,
2589 scf_propvec_t
*properties
, scf_propvec_t
**badprop
)
2591 scf_handle_t
*h
= _scf_handle_create_and_bind(SCF_VERSION
);
2592 scf_service_t
*s
= scf_service_create(h
);
2593 scf_instance_t
*i
= scf_instance_create(h
);
2594 scf_snapshot_t
*snap
= running
? scf_snapshot_create(h
) : NULL
;
2595 scf_propertygroup_t
*pg
= scf_pg_create(h
);
2596 scf_property_t
*p
= scf_property_create(h
);
2597 scf_value_t
*v
= scf_value_create(h
);
2598 boolean_t instance
= B_TRUE
;
2599 scf_propvec_t
*prop
;
2602 if (h
== NULL
|| s
== NULL
|| i
== NULL
|| (running
&& snap
== NULL
) ||
2603 pg
== NULL
|| p
== NULL
|| v
== NULL
)
2606 if (scf_handle_decode_fmri(h
, fmri
, NULL
, s
, i
, NULL
, NULL
, 0) == -1)
2609 if (scf_instance_to_fmri(i
, NULL
, 0) == -1) {
2610 if (scf_error() != SCF_ERROR_NOT_SET
)
2617 error
= SCF_ERROR_TYPE_MISMATCH
;
2621 if (scf_instance_get_snapshot(i
, "running", snap
) !=
2626 if ((instance
? scf_instance_get_pg_composed(i
, snap
, pgname
, pg
) :
2627 scf_service_get_pg(s
, pgname
, pg
)) == -1)
2630 for (prop
= properties
; prop
->pv_prop
!= NULL
; prop
++) {
2631 if (prop
->pv_type
== SCF_TYPE_OPAQUE
)
2632 ((scf_opaque_t
*)prop
->pv_ptr
)->so_addr
= NULL
;
2633 else if (scf_true_base_type(prop
->pv_type
) == SCF_TYPE_ASTRING
)
2634 *((char **)prop
->pv_ptr
) = NULL
;
2637 for (prop
= properties
; prop
->pv_prop
!= NULL
; prop
++) {
2640 if (scf_pg_get_property(pg
, prop
->pv_prop
, p
) == -1 ||
2641 scf_property_get_value(p
, v
) == -1) {
2645 switch (prop
->pv_type
) {
2646 case SCF_TYPE_BOOLEAN
: {
2649 ret
= scf_value_get_boolean(v
, &b
);
2652 if (prop
->pv_aux
!= 0) {
2653 uint64_t *bits
= prop
->pv_ptr
;
2654 *bits
= b
? (*bits
| prop
->pv_aux
) :
2655 (*bits
& ~prop
->pv_aux
);
2657 boolean_t
*bool = prop
->pv_ptr
;
2658 *bool = b
? B_TRUE
: B_FALSE
;
2662 case SCF_TYPE_COUNT
:
2663 ret
= scf_value_get_count(v
, prop
->pv_ptr
);
2665 case SCF_TYPE_INTEGER
:
2666 ret
= scf_value_get_integer(v
, prop
->pv_ptr
);
2668 case SCF_TYPE_TIME
: {
2669 scf_time_t
*time
= prop
->pv_ptr
;
2671 ret
= scf_value_get_time(v
, &time
->t_seconds
,
2675 case SCF_TYPE_OPAQUE
: {
2676 scf_opaque_t
*opaque
= prop
->pv_ptr
;
2677 ssize_t size
= scf_value_get_opaque(v
, NULL
, 0);
2683 if ((opaque
->so_addr
= malloc(size
)) == NULL
) {
2684 error
= SCF_ERROR_NO_MEMORY
;
2687 opaque
->so_size
= size
;
2688 ret
= scf_value_get_opaque(v
, opaque
->so_addr
, size
);
2695 assert(scf_true_base_type(prop
->pv_type
) ==
2698 size
= scf_value_get_astring(v
, NULL
, 0);
2703 if ((s
= malloc(++size
)) == NULL
) {
2704 error
= SCF_ERROR_NO_MEMORY
;
2707 ret
= scf_value_get_astring(v
, s
, size
);
2708 *(char **)prop
->pv_ptr
= s
;
2722 error
= scf_error();
2723 scf_clean_propvec(properties
);
2726 scf_value_destroy(v
);
2727 scf_property_destroy(p
);
2729 scf_snapshot_destroy(snap
);
2730 scf_instance_destroy(i
);
2731 scf_service_destroy(s
);
2732 scf_handle_destroy(h
);
2735 (void) scf_set_error(error
);
2736 return (SCF_FAILED
);
2739 return (SCF_SUCCESS
);
2743 * Writes a vector of properties to the specified fmri/property group.
2745 * If this function fails to write a specific property, *badprop is set
2746 * to point at that property's entry in the properties array.
2748 * One significant difference between this function and the
2749 * scf_read_propvec function is that for string types, pv_ptr is a
2750 * char *, not a char **. This means that you can't write a propvec
2751 * you just read, but makes other uses (hopefully the majority) simpler.
2754 scf_write_propvec(const char *fmri
, const char *pgname
,
2755 scf_propvec_t
*properties
, scf_propvec_t
**badprop
)
2757 scf_handle_t
*h
= _scf_handle_create_and_bind(SCF_VERSION
);
2758 scf_service_t
*s
= scf_service_create(h
);
2759 scf_instance_t
*inst
= scf_instance_create(h
);
2760 scf_snapshot_t
*snap
= scf_snapshot_create(h
);
2761 scf_propertygroup_t
*pg
= scf_pg_create(h
);
2762 scf_property_t
*p
= scf_property_create(h
);
2763 scf_transaction_t
*tx
= scf_transaction_create(h
);
2764 scf_value_t
**v
= NULL
;
2765 scf_transaction_entry_t
**e
= NULL
;
2766 boolean_t instance
= B_TRUE
;
2768 scf_propvec_t
*prop
;
2771 n
= count_props(properties
);
2772 v
= calloc(n
, sizeof (scf_value_t
*));
2773 e
= calloc(n
, sizeof (scf_transaction_entry_t
*));
2775 if (v
== NULL
|| e
== NULL
) {
2776 error
= SCF_ERROR_NO_MEMORY
;
2780 if (h
== NULL
|| s
== NULL
|| inst
== NULL
|| pg
== NULL
|| p
== NULL
||
2784 for (i
= 0; i
< n
; i
++) {
2785 v
[i
] = scf_value_create(h
);
2786 e
[i
] = scf_entry_create(h
);
2787 if (v
[i
] == NULL
|| e
[i
] == NULL
)
2791 if (scf_handle_decode_fmri(h
, fmri
, NULL
, s
, inst
, NULL
, NULL
, 0)
2795 if (scf_instance_to_fmri(inst
, NULL
, 0) == -1) {
2796 if (scf_error() != SCF_ERROR_NOT_SET
)
2801 if ((instance
? scf_instance_get_pg(inst
, pgname
, pg
) :
2802 scf_service_get_pg(s
, pgname
, pg
)) == -1)
2806 if (scf_transaction_start(tx
, pg
) == -1)
2809 for (prop
= properties
, i
= 0; prop
->pv_prop
!= NULL
; prop
++, i
++) {
2810 ret
= scf_transaction_property_change(tx
, e
[i
], prop
->pv_prop
,
2812 if (ret
== -1 && scf_error() == SCF_ERROR_NOT_FOUND
)
2813 ret
= scf_transaction_property_new(tx
, e
[i
],
2814 prop
->pv_prop
, prop
->pv_type
);
2821 switch (prop
->pv_type
) {
2822 case SCF_TYPE_BOOLEAN
: {
2823 boolean_t b
= (prop
->pv_aux
!= 0) ?
2824 (*(uint64_t *)prop
->pv_ptr
& prop
->pv_aux
) != 0 :
2825 *(boolean_t
*)prop
->pv_ptr
;
2827 scf_value_set_boolean(v
[i
], b
? 1 : 0);
2830 case SCF_TYPE_COUNT
:
2831 scf_value_set_count(v
[i
], *(uint64_t *)prop
->pv_ptr
);
2833 case SCF_TYPE_INTEGER
:
2834 scf_value_set_integer(v
[i
], *(int64_t *)prop
->pv_ptr
);
2836 case SCF_TYPE_TIME
: {
2837 scf_time_t
*time
= prop
->pv_ptr
;
2839 ret
= scf_value_set_time(v
[i
], time
->t_seconds
,
2843 case SCF_TYPE_OPAQUE
: {
2844 scf_opaque_t
*opaque
= prop
->pv_ptr
;
2846 ret
= scf_value_set_opaque(v
[i
], opaque
->so_addr
,
2850 case SCF_TYPE_ASTRING
:
2851 ret
= scf_value_set_astring(v
[i
],
2852 (const char *)prop
->pv_ptr
);
2855 ret
= scf_value_set_from_string(v
[i
], prop
->pv_type
,
2856 (const char *)prop
->pv_ptr
);
2859 if (ret
== -1 || scf_entry_add_value(e
[i
], v
[i
]) == -1) {
2865 ret
= scf_transaction_commit(tx
);
2869 if (ret
== 0 && scf_pg_update(pg
) != -1) {
2870 scf_transaction_reset(tx
);
2875 error
= scf_error();
2879 for (i
= 0; i
< n
; i
++)
2880 scf_value_destroy(v
[i
]);
2885 for (i
= 0; i
< n
; i
++)
2886 scf_entry_destroy(e
[i
]);
2890 scf_transaction_destroy(tx
);
2891 scf_property_destroy(p
);
2893 scf_snapshot_destroy(snap
);
2894 scf_instance_destroy(inst
);
2895 scf_service_destroy(s
);
2896 scf_handle_destroy(h
);
2899 (void) scf_set_error(error
);
2900 return (SCF_FAILED
);
2903 return (SCF_SUCCESS
);
2909 * ECONNABORTED - repository connection broken
2910 * ECANCELED - inst was deleted
2917 scf_instance_delete_prop(scf_instance_t
*inst
, const char *pgname
,
2921 scf_propertygroup_t
*pg
;
2922 scf_transaction_t
*tx
;
2923 scf_transaction_entry_t
*e
;
2924 int error
= 0, ret
= 1, r
;
2926 h
= scf_instance_handle(inst
);
2928 if ((pg
= scf_pg_create(h
)) == NULL
) {
2932 if (scf_instance_get_pg(inst
, pgname
, pg
) != 0) {
2933 error
= scf_error();
2936 case SCF_ERROR_NOT_FOUND
:
2937 return (SCF_SUCCESS
);
2939 case SCF_ERROR_DELETED
:
2942 case SCF_ERROR_CONNECTION_BROKEN
:
2944 return (ECONNABORTED
);
2946 case SCF_ERROR_NOT_SET
:
2947 bad_error("scf_instance_get_pg", scf_error());
2951 tx
= scf_transaction_create(h
);
2952 e
= scf_entry_create(h
);
2953 if (tx
== NULL
|| e
== NULL
) {
2959 if (scf_transaction_start(tx
, pg
) != 0) {
2963 if (scf_transaction_property_delete(tx
, e
, pname
) != 0) {
2967 if ((r
= scf_transaction_commit(tx
)) == 1) {
2976 scf_transaction_reset(tx
);
2977 if (scf_pg_update(pg
) == -1) {
2983 switch (scf_error()) {
2984 case SCF_ERROR_DELETED
:
2985 case SCF_ERROR_NOT_FOUND
:
2989 case SCF_ERROR_PERMISSION_DENIED
:
2993 case SCF_ERROR_BACKEND_ACCESS
:
2997 case SCF_ERROR_BACKEND_READONLY
:
3001 case SCF_ERROR_CONNECTION_BROKEN
:
3006 case SCF_ERROR_HANDLE_MISMATCH
:
3007 case SCF_ERROR_INVALID_ARGUMENT
:
3008 case SCF_ERROR_NOT_BOUND
:
3009 case SCF_ERROR_NOT_SET
:
3010 bad_error("scf_instance_delete_prop", scf_error());
3014 scf_transaction_destroy(tx
);
3015 scf_entry_destroy(e
);
3022 * Check the "application/auto_enable" property for the passed FMRI.
3023 * scf_simple_prop_get() should find the property on an instance
3024 * or on the service FMRI. The routine returns:
3025 * -1: inconclusive (likely no such property or FMRI)
3026 * 0: auto_enable is false
3027 * 1: auto_enable is true
3030 is_auto_enabled(char *fmri
)
3032 scf_simple_prop_t
*prop
;
3036 prop
= scf_simple_prop_get(NULL
, fmri
, SCF_GROUP_APPLICATION
,
3040 ret
= scf_simple_prop_next_boolean(prop
);
3041 retval
= (*ret
!= 0);
3042 scf_simple_prop_free(prop
);
3047 * Check an array of services and enable any that don't have the
3048 * "application/auto_enable" property set to "false", which is
3049 * the interface to turn off this behaviour (see PSARC 2004/739).
3052 _check_services(char **svcs
)
3056 for (; *svcs
; svcs
++) {
3057 if (is_auto_enabled(*svcs
) == 0)
3059 if ((s
= smf_get_state(*svcs
)) != NULL
) {
3060 if (strcmp(SCF_STATE_STRING_DISABLED
, s
) == 0)
3061 (void) smf_enable_instance(*svcs
,
3070 str_compare(const char *s1
, const char *s2
, size_t n
)
3072 return (strcmp(s1
, s2
));
3076 str_n_compare(const char *s1
, const char *s2
, size_t n
)
3078 return (strncmp(s1
, s2
, n
));
3082 state_from_string(const char *state
, size_t l
)
3084 int (*str_cmp
)(const char *, const char *, size_t);
3087 str_cmp
= str_compare
;
3089 str_cmp
= str_n_compare
;
3091 if (str_cmp(SCF_STATE_STRING_UNINIT
, state
, l
) == 0)
3092 return (SCF_STATE_UNINIT
);
3093 else if (str_cmp(SCF_STATE_STRING_MAINT
, state
, l
) == 0)
3094 return (SCF_STATE_MAINT
);
3095 else if (str_cmp(SCF_STATE_STRING_OFFLINE
, state
, l
) == 0)
3096 return (SCF_STATE_OFFLINE
);
3097 else if (str_cmp(SCF_STATE_STRING_DISABLED
, state
, l
) == 0)
3098 return (SCF_STATE_DISABLED
);
3099 else if (str_cmp(SCF_STATE_STRING_ONLINE
, state
, l
) == 0)
3100 return (SCF_STATE_ONLINE
);
3101 else if (str_cmp(SCF_STATE_STRING_DEGRADED
, state
, l
) == 0)
3102 return (SCF_STATE_DEGRADED
);
3103 else if (str_cmp("all", state
, l
) == 0)
3104 return (SCF_STATE_ALL
);
3110 * int32_t smf_state_from_string()
3111 * return the value of the macro SCF_STATE_* for the corresponding state
3112 * it returns SCF_STATE_ALL if "all" is passed. -1 if the string passed doesn't
3113 * correspond to any valid state.
3116 smf_state_from_string(const char *state
)
3118 return (state_from_string(state
, 0));
3122 * smf_state_to_string()
3123 * Takes an int32_t representing an SMF state and returns
3124 * the corresponding string. The string is read only and need not to be
3126 * returns NULL on invalid input.
3129 smf_state_to_string(int32_t s
)
3132 case SCF_STATE_UNINIT
:
3133 return (SCF_STATE_STRING_UNINIT
);
3134 case SCF_STATE_MAINT
:
3135 return (SCF_STATE_STRING_MAINT
);
3136 case SCF_STATE_OFFLINE
:
3137 return (SCF_STATE_STRING_OFFLINE
);
3138 case SCF_STATE_DISABLED
:
3139 return (SCF_STATE_STRING_DISABLED
);
3140 case SCF_STATE_ONLINE
:
3141 return (SCF_STATE_STRING_ONLINE
);
3142 case SCF_STATE_DEGRADED
:
3143 return (SCF_STATE_STRING_DEGRADED
);