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 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #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 * Internal private function that creates and binds a handle.
63 h
= scf_handle_create(SCF_VERSION
);
67 if (scf_handle_bind(h
) == -1) {
68 scf_handle_destroy(h
);
75 scf_simple_handle_destroy(scf_simple_handle_t
*simple_h
)
80 scf_pg_destroy(simple_h
->running_pg
);
81 scf_pg_destroy(simple_h
->editing_pg
);
82 scf_snapshot_destroy(simple_h
->snap
);
83 scf_instance_destroy(simple_h
->inst
);
84 scf_handle_destroy(simple_h
->h
);
89 * Given a base service FMRI and the names of a property group and property,
90 * assemble_fmri() merges them into a property FMRI. Note that if the base
91 * FMRI is NULL, assemble_fmri() gets the base FMRI from scf_myname().
95 assemble_fmri(scf_handle_t
*h
, const char *base
, const char *pg
,
98 size_t fmri_sz
, pglen
;
103 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
108 pglen
= strlen(SCF_PG_APP_DEFAULT
);
113 if ((baselen
= scf_myname(h
, NULL
, 0)) == -1)
116 baselen
= strlen(base
);
119 fmri_sz
= baselen
+ sizeof (SCF_FMRI_PROPERTYGRP_PREFIX
) - 1 +
120 pglen
+ sizeof (SCF_FMRI_PROPERTY_PREFIX
) - 1 +
123 if ((fmri_buf
= malloc(fmri_sz
)) == NULL
) {
124 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
129 if (scf_myname(h
, fmri_buf
, fmri_sz
) == -1) {
134 (void) strcpy(fmri_buf
, base
);
137 (void) strcat(fmri_buf
, SCF_FMRI_PROPERTYGRP_PREFIX
);
140 (void) strcat(fmri_buf
, SCF_PG_APP_DEFAULT
);
142 (void) strcat(fmri_buf
, pg
);
144 (void) strcat(fmri_buf
, SCF_FMRI_PROPERTY_PREFIX
);
145 (void) strcat(fmri_buf
, prop
);
150 * Given a property, this function allocates and fills an scf_simple_prop_t
151 * with the data it contains.
154 static scf_simple_prop_t
*
155 fill_prop(scf_property_t
*prop
, const char *pgname
, const char *propname
,
158 scf_simple_prop_t
*ret
;
162 ssize_t valsize
, numvals
;
163 union scf_simple_prop_val
*vallist
= NULL
, *vallist_backup
= NULL
;
165 if ((ret
= malloc(sizeof (*ret
))) == NULL
) {
166 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
175 ret
->pr_pgname
= strdup(SCF_PG_APP_DEFAULT
);
177 ret
->pr_pgname
= strdup(pgname
);
179 if (ret
->pr_pgname
== NULL
) {
180 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
185 if ((ret
->pr_propname
= strdup(propname
)) == NULL
) {
186 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
187 free(ret
->pr_pgname
);
192 if (scf_property_type(prop
, &ret
->pr_type
) == -1)
195 if ((iter
= scf_iter_create(h
)) == NULL
)
197 if ((val
= scf_value_create(h
)) == NULL
) {
198 scf_iter_destroy(iter
);
202 if (scf_iter_property_values(iter
, prop
) == -1)
205 for (numvals
= 0; (iterret
= scf_iter_next_value(iter
, val
)) == 1;
207 vallist_backup
= vallist
;
208 if ((vallist
= realloc(vallist
, (numvals
+ 1) *
209 sizeof (*vallist
))) == NULL
) {
210 vallist
= vallist_backup
;
214 switch (ret
->pr_type
) {
215 case SCF_TYPE_BOOLEAN
:
216 if (scf_value_get_boolean(val
,
217 &vallist
[numvals
].pv_bool
) == -1)
222 if (scf_value_get_count(val
,
223 &vallist
[numvals
].pv_uint
) == -1)
227 case SCF_TYPE_INTEGER
:
228 if (scf_value_get_integer(val
,
229 &vallist
[numvals
].pv_int
) == -1)
234 if (scf_value_get_time(val
,
235 &vallist
[numvals
].pv_time
.t_sec
,
236 &vallist
[numvals
].pv_time
.t_nsec
) == -1)
240 case SCF_TYPE_ASTRING
:
241 vallist
[numvals
].pv_str
= NULL
;
242 if ((valsize
= scf_value_get_astring(val
, NULL
, 0)) ==
245 if ((vallist
[numvals
].pv_str
= malloc(valsize
+1)) ==
247 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
250 if (scf_value_get_astring(val
,
251 vallist
[numvals
].pv_str
, valsize
+1) == -1) {
252 free(vallist
[numvals
].pv_str
);
257 case SCF_TYPE_USTRING
:
259 case SCF_TYPE_HOSTNAME
:
260 case SCF_TYPE_NET_ADDR_V4
:
261 case SCF_TYPE_NET_ADDR_V6
:
264 vallist
[numvals
].pv_str
= NULL
;
265 if ((valsize
= scf_value_get_ustring(val
, NULL
, 0)) ==
268 if ((vallist
[numvals
].pv_str
= malloc(valsize
+1)) ==
270 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
273 if (scf_value_get_ustring(val
,
274 vallist
[numvals
].pv_str
, valsize
+1) == -1) {
275 free(vallist
[numvals
].pv_str
);
280 case SCF_TYPE_OPAQUE
:
281 vallist
[numvals
].pv_opaque
.o_value
= NULL
;
282 if ((valsize
= scf_value_get_opaque(val
, NULL
, 0)) ==
285 if ((vallist
[numvals
].pv_opaque
.o_value
=
286 malloc(valsize
)) == NULL
) {
287 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
290 vallist
[numvals
].pv_opaque
.o_size
= valsize
;
291 if (scf_value_get_opaque(val
,
292 vallist
[numvals
].pv_opaque
.o_value
,
294 free(vallist
[numvals
].pv_opaque
.o_value
);
300 (void) scf_set_error(SCF_ERROR_INTERNAL
);
307 int err
= scf_error();
308 if (err
!= SCF_ERROR_CONNECTION_BROKEN
&&
309 err
!= SCF_ERROR_PERMISSION_DENIED
)
310 (void) scf_set_error(SCF_ERROR_INTERNAL
);
314 ret
->pr_vallist
= vallist
;
315 ret
->pr_numvalues
= numvals
;
317 scf_iter_destroy(iter
);
318 (void) scf_value_destroy(val
);
323 * Exit point for a successful call. Below this line are exit points
324 * for failures at various stages during the function.
331 switch (ret
->pr_type
) {
332 case SCF_TYPE_ASTRING
:
333 case SCF_TYPE_USTRING
:
335 case SCF_TYPE_HOSTNAME
:
336 case SCF_TYPE_NET_ADDR_V4
:
337 case SCF_TYPE_NET_ADDR_V6
:
339 case SCF_TYPE_FMRI
: {
340 for (i
= 0; i
< numvals
; i
++) {
341 free(vallist
[i
].pv_str
);
345 case SCF_TYPE_OPAQUE
: {
346 for (i
= 0; i
< numvals
; i
++) {
347 free(vallist
[i
].pv_opaque
.o_value
);
358 scf_iter_destroy(iter
);
359 (void) scf_value_destroy(val
);
362 free(ret
->pr_pgname
);
363 free(ret
->pr_propname
);
369 * insert_app_props iterates over a property iterator, getting all the
370 * properties from a property group, and adding or overwriting them into
371 * a simple_app_props_t. This is used by scf_simple_app_props_get to provide
372 * service/instance composition while filling the app_props_t.
373 * insert_app_props iterates over a single property group.
377 insert_app_props(scf_iter_t
*propiter
, char *pgname
, char *propname
, struct
378 scf_simple_pg
*thispg
, scf_property_t
*prop
, size_t namelen
,
381 scf_simple_prop_t
*thisprop
, *prevprop
, *newprop
;
385 while ((propiter_ret
= scf_iter_next_property(propiter
, prop
)) == 1) {
387 if (scf_property_get_name(prop
, propname
, namelen
) < 0) {
388 if (scf_error() == SCF_ERROR_NOT_SET
)
389 (void) scf_set_error(SCF_ERROR_INTERNAL
);
393 thisprop
= thispg
->pg_proplist
;
394 prevprop
= thispg
->pg_proplist
;
397 while ((thisprop
!= NULL
) && (!found
)) {
398 if (strcmp(thisprop
->pr_propname
, propname
) == 0) {
400 if ((newprop
= fill_prop(prop
, pgname
,
401 propname
, h
)) == NULL
)
404 if (thisprop
== thispg
->pg_proplist
)
405 thispg
->pg_proplist
= newprop
;
407 prevprop
->pr_next
= newprop
;
409 newprop
->pr_pg
= thispg
;
410 newprop
->pr_next
= thisprop
->pr_next
;
411 scf_simple_prop_free(thisprop
);
414 if (thisprop
!= thispg
->pg_proplist
)
415 prevprop
= prevprop
->pr_next
;
416 thisprop
= thisprop
->pr_next
;
421 if ((newprop
= fill_prop(prop
, pgname
, propname
, h
)) ==
425 if (thispg
->pg_proplist
== NULL
)
426 thispg
->pg_proplist
= newprop
;
428 prevprop
->pr_next
= newprop
;
430 newprop
->pr_pg
= thispg
;
434 if (propiter_ret
== -1) {
435 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
436 (void) scf_set_error(SCF_ERROR_INTERNAL
);
445 * Sets up e in tx to set pname's values. Returns 0 on success or -1 on
446 * failure, with scf_error() set to
447 * SCF_ERROR_HANDLE_MISMATCH - tx & e are derived from different handles
448 * SCF_ERROR_INVALID_ARGUMENT - pname or ty are invalid
449 * SCF_ERROR_NOT_BOUND - handle is not bound
450 * SCF_ERROR_CONNECTION_BROKEN - connection was broken
451 * SCF_ERROR_NOT_SET - tx has not been started
452 * SCF_ERROR_DELETED - the pg tx was started on was deleted
455 transaction_property_set(scf_transaction_t
*tx
, scf_transaction_entry_t
*e
,
456 const char *pname
, scf_type_t ty
)
459 if (scf_transaction_property_change_type(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_NOT_FOUND
:
476 if (scf_transaction_property_new(tx
, e
, pname
, ty
) == 0)
479 switch (scf_error()) {
480 case SCF_ERROR_HANDLE_MISMATCH
:
481 case SCF_ERROR_INVALID_ARGUMENT
:
482 case SCF_ERROR_NOT_BOUND
:
483 case SCF_ERROR_CONNECTION_BROKEN
:
484 case SCF_ERROR_NOT_SET
:
485 case SCF_ERROR_DELETED
:
489 case SCF_ERROR_EXISTS
:
496 get_inst_enabled(const scf_instance_t
*inst
, const char *pgname
)
498 scf_propertygroup_t
*gpg
= NULL
;
499 scf_property_t
*eprop
= NULL
;
500 scf_value_t
*v
= NULL
;
501 scf_handle_t
*h
= NULL
;
505 if ((h
= scf_instance_handle(inst
)) == NULL
)
508 if ((gpg
= scf_pg_create(h
)) == NULL
||
509 (eprop
= scf_property_create(h
)) == NULL
||
510 (v
= scf_value_create(h
)) == NULL
)
513 if (scf_instance_get_pg(inst
, pgname
, gpg
) ||
514 scf_pg_get_property(gpg
, SCF_PROPERTY_ENABLED
, eprop
) ||
515 scf_property_get_value(eprop
, v
) ||
516 scf_value_get_boolean(v
, &enabled
))
522 scf_property_destroy(eprop
);
523 scf_value_destroy(v
);
528 * set_inst_enabled() is a "master" enable/disable call that takes the
529 * instance and the desired state for the enabled bit in the instance's
530 * named property group. If the group doesn't exist, it's created with the
531 * given flags. Called by smf_{dis,en}able_instance().
534 set_inst_enabled(const scf_instance_t
*inst
, uint8_t desired
,
535 const char *pgname
, uint32_t pgflags
)
537 scf_transaction_t
*tx
= NULL
;
538 scf_transaction_entry_t
*ent
= NULL
;
539 scf_propertygroup_t
*gpg
= NULL
;
540 scf_property_t
*eprop
= NULL
;
541 scf_value_t
*v
= NULL
;
542 scf_handle_t
*h
= NULL
;
547 if ((h
= scf_instance_handle(inst
)) == NULL
)
550 if ((gpg
= scf_pg_create(h
)) == NULL
||
551 (eprop
= scf_property_create(h
)) == NULL
||
552 (v
= scf_value_create(h
)) == NULL
||
553 (tx
= scf_transaction_create(h
)) == NULL
||
554 (ent
= scf_entry_create(h
)) == NULL
)
558 if (scf_instance_get_pg(inst
, SCF_PG_GENERAL
, gpg
) == -1) {
559 if (scf_error() != SCF_ERROR_NOT_FOUND
)
562 if (scf_instance_add_pg(inst
, SCF_PG_GENERAL
,
563 SCF_GROUP_FRAMEWORK
, SCF_PG_GENERAL_FLAGS
, gpg
) == -1) {
564 if (scf_error() != SCF_ERROR_EXISTS
)
570 if (strcmp(pgname
, SCF_PG_GENERAL
) != 0) {
572 if (scf_instance_get_pg(inst
, pgname
, gpg
) == -1) {
573 if (scf_error() != SCF_ERROR_NOT_FOUND
)
576 if (scf_instance_add_pg(inst
, pgname
,
577 SCF_GROUP_FRAMEWORK
, pgflags
, gpg
) == -1) {
578 if (scf_error() != SCF_ERROR_EXISTS
)
585 if (scf_pg_get_property(gpg
, SCF_PROPERTY_ENABLED
, eprop
) == -1) {
586 if (scf_error() != SCF_ERROR_NOT_FOUND
)
593 * If it's already set the way we want, forgo the transaction.
595 if (scf_property_get_value(eprop
, v
) == -1) {
596 switch (scf_error()) {
597 case SCF_ERROR_CONSTRAINT_VIOLATED
:
598 case SCF_ERROR_NOT_FOUND
:
599 /* Misconfigured, so set anyway. */
606 if (scf_value_get_boolean(v
, &b
) == -1) {
607 if (scf_error() != SCF_ERROR_TYPE_MISMATCH
)
618 if (scf_transaction_start(tx
, gpg
) == -1)
621 if (transaction_property_set(tx
, ent
, SCF_PROPERTY_ENABLED
,
622 SCF_TYPE_BOOLEAN
) != 0) {
623 switch (scf_error()) {
624 case SCF_ERROR_CONNECTION_BROKEN
:
625 case SCF_ERROR_DELETED
:
629 case SCF_ERROR_HANDLE_MISMATCH
:
630 case SCF_ERROR_INVALID_ARGUMENT
:
631 case SCF_ERROR_NOT_BOUND
:
632 case SCF_ERROR_NOT_SET
:
633 bad_error("transaction_property_set",
638 scf_value_set_boolean(v
, desired
);
639 if (scf_entry_add_value(ent
, v
) == -1)
642 committed
= scf_transaction_commit(tx
);
646 scf_transaction_reset(tx
);
648 if (committed
== 0) { /* out-of-sync */
649 if (scf_pg_update(gpg
) == -1)
652 } while (committed
== 0);
657 scf_value_destroy(v
);
658 scf_entry_destroy(ent
);
659 scf_transaction_destroy(tx
);
660 scf_property_destroy(eprop
);
667 delete_inst_enabled(const scf_instance_t
*inst
, const char *pgname
)
669 scf_transaction_t
*tx
= NULL
;
670 scf_transaction_entry_t
*ent
= NULL
;
671 scf_propertygroup_t
*gpg
= NULL
;
672 scf_handle_t
*h
= NULL
;
676 if ((h
= scf_instance_handle(inst
)) == NULL
)
679 if ((gpg
= scf_pg_create(h
)) == NULL
||
680 (tx
= scf_transaction_create(h
)) == NULL
||
681 (ent
= scf_entry_create(h
)) == NULL
)
684 if (scf_instance_get_pg(inst
, pgname
, gpg
) != 0)
687 if (scf_transaction_start(tx
, gpg
) == -1 ||
688 scf_transaction_property_delete(tx
, ent
,
689 SCF_PROPERTY_ENABLED
) == -1 ||
690 (committed
= scf_transaction_commit(tx
)) == -1)
693 scf_transaction_reset(tx
);
695 if (committed
== 0 && scf_pg_update(gpg
) == -1)
697 } while (committed
== 0);
703 switch (scf_error()) {
704 case SCF_ERROR_DELETED
:
705 case SCF_ERROR_NOT_FOUND
:
711 scf_entry_destroy(ent
);
712 scf_transaction_destroy(tx
);
719 * Returns 0 on success or -1 on failure. On failure leaves scf_error() set to
720 * SCF_ERROR_HANDLE_DESTROYED - inst's handle has been destroyed
721 * SCF_ERROR_NOT_BOUND - inst's handle is not bound
722 * SCF_ERROR_CONNECTION_BROKEN - the repository connection was broken
723 * SCF_ERROR_NOT_SET - inst is not set
724 * SCF_ERROR_DELETED - inst was deleted
725 * SCF_ERROR_PERMISSION_DENIED
726 * SCF_ERROR_BACKEND_ACCESS
727 * SCF_ERROR_BACKEND_READONLY
730 set_inst_action_inst(scf_instance_t
*inst
, const char *action
)
733 scf_transaction_t
*tx
= NULL
;
734 scf_transaction_entry_t
*ent
= NULL
;
735 scf_propertygroup_t
*pg
= NULL
;
736 scf_property_t
*prop
= NULL
;
737 scf_value_t
*v
= NULL
;
742 if ((h
= scf_instance_handle(inst
)) == NULL
||
743 (pg
= scf_pg_create(h
)) == NULL
||
744 (prop
= scf_property_create(h
)) == NULL
||
745 (v
= scf_value_create(h
)) == NULL
||
746 (tx
= scf_transaction_create(h
)) == NULL
||
747 (ent
= scf_entry_create(h
)) == NULL
)
751 if (scf_instance_get_pg(inst
, SCF_PG_RESTARTER_ACTIONS
, pg
) == -1) {
752 switch (scf_error()) {
753 case SCF_ERROR_NOT_BOUND
:
754 case SCF_ERROR_CONNECTION_BROKEN
:
755 case SCF_ERROR_NOT_SET
:
756 case SCF_ERROR_DELETED
:
760 case SCF_ERROR_NOT_FOUND
:
763 case SCF_ERROR_HANDLE_MISMATCH
:
764 case SCF_ERROR_INVALID_ARGUMENT
:
765 bad_error("scf_instance_get_pg", scf_error());
768 /* Try creating the restarter_actions property group. */
770 if (scf_instance_add_pg(inst
, SCF_PG_RESTARTER_ACTIONS
,
771 SCF_PG_RESTARTER_ACTIONS_TYPE
,
772 SCF_PG_RESTARTER_ACTIONS_FLAGS
, pg
) == -1) {
773 switch (scf_error()) {
774 case SCF_ERROR_NOT_BOUND
:
775 case SCF_ERROR_CONNECTION_BROKEN
:
776 case SCF_ERROR_NOT_SET
:
777 case SCF_ERROR_DELETED
:
778 case SCF_ERROR_PERMISSION_DENIED
:
779 case SCF_ERROR_BACKEND_ACCESS
:
780 case SCF_ERROR_BACKEND_READONLY
:
784 case SCF_ERROR_EXISTS
:
787 case SCF_ERROR_HANDLE_MISMATCH
:
788 case SCF_ERROR_INVALID_ARGUMENT
:
789 bad_error("scf_instance_add_pg", scf_error());
795 timestamp
= gethrtime();
797 if (scf_pg_get_property(pg
, action
, prop
) != 0) {
798 switch (scf_error()) {
799 case SCF_ERROR_CONNECTION_BROKEN
:
803 case SCF_ERROR_DELETED
:
806 case SCF_ERROR_NOT_FOUND
:
809 case SCF_ERROR_HANDLE_MISMATCH
:
810 case SCF_ERROR_INVALID_ARGUMENT
:
811 case SCF_ERROR_NOT_BOUND
:
812 case SCF_ERROR_NOT_SET
:
813 bad_error("scf_pg_get_property", scf_error());
815 } else if (scf_property_get_value(prop
, v
) != 0) {
816 switch (scf_error()) {
817 case SCF_ERROR_CONNECTION_BROKEN
:
821 case SCF_ERROR_DELETED
:
824 case SCF_ERROR_CONSTRAINT_VIOLATED
:
825 case SCF_ERROR_NOT_FOUND
:
828 case SCF_ERROR_HANDLE_MISMATCH
:
829 case SCF_ERROR_NOT_BOUND
:
830 case SCF_ERROR_NOT_SET
:
831 bad_error("scf_property_get_value",
834 } else if (scf_value_get_integer(v
, &t
) != 0) {
835 bad_error("scf_value_get_integer", scf_error());
836 } else if (t
> timestamp
) {
840 if (scf_transaction_start(tx
, pg
) == -1) {
841 switch (scf_error()) {
842 case SCF_ERROR_NOT_BOUND
:
843 case SCF_ERROR_CONNECTION_BROKEN
:
844 case SCF_ERROR_PERMISSION_DENIED
:
845 case SCF_ERROR_BACKEND_ACCESS
:
846 case SCF_ERROR_BACKEND_READONLY
:
850 case SCF_ERROR_DELETED
:
853 case SCF_ERROR_HANDLE_MISMATCH
:
854 case SCF_ERROR_NOT_SET
:
855 case SCF_ERROR_IN_USE
:
856 bad_error("scf_transaction_start", scf_error());
860 if (transaction_property_set(tx
, ent
, action
,
861 SCF_TYPE_INTEGER
) != 0) {
862 switch (scf_error()) {
863 case SCF_ERROR_NOT_BOUND
:
864 case SCF_ERROR_CONNECTION_BROKEN
:
865 case SCF_ERROR_DELETED
:
869 case SCF_ERROR_HANDLE_MISMATCH
:
870 case SCF_ERROR_INVALID_ARGUMENT
:
871 case SCF_ERROR_NOT_SET
:
872 bad_error("transaction_property_set",
877 scf_value_set_integer(v
, timestamp
);
878 if (scf_entry_add_value(ent
, v
) == -1)
879 bad_error("scf_entry_add_value", scf_error());
881 trans
= scf_transaction_commit(tx
);
886 switch (scf_error()) {
887 case SCF_ERROR_CONNECTION_BROKEN
:
888 case SCF_ERROR_PERMISSION_DENIED
:
889 case SCF_ERROR_BACKEND_ACCESS
:
890 case SCF_ERROR_BACKEND_READONLY
:
894 case SCF_ERROR_DELETED
:
895 scf_transaction_reset(tx
);
898 case SCF_ERROR_INVALID_ARGUMENT
:
899 case SCF_ERROR_NOT_BOUND
:
900 case SCF_ERROR_NOT_SET
:
901 bad_error("scf_transaction_commit",
906 scf_transaction_reset(tx
);
907 if (scf_pg_update(pg
) == -1) {
908 switch (scf_error()) {
909 case SCF_ERROR_CONNECTION_BROKEN
:
913 case SCF_ERROR_DELETED
:
916 case SCF_ERROR_NOT_SET
:
917 case SCF_ERROR_NOT_BOUND
:
918 bad_error("scf_pg_update", scf_error());
926 scf_value_destroy(v
);
927 scf_entry_destroy(ent
);
928 scf_transaction_destroy(tx
);
929 scf_property_destroy(prop
);
935 set_inst_action(const char *fmri
, const char *action
)
938 scf_instance_t
*inst
;
945 inst
= scf_instance_create(h
);
948 if (scf_handle_decode_fmri(h
, fmri
, NULL
, NULL
, inst
, NULL
,
949 NULL
, SCF_DECODE_FMRI_EXACT
) == 0) {
950 ret
= set_inst_action_inst(inst
, action
);
951 if (ret
== -1 && scf_error() == SCF_ERROR_DELETED
)
952 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
954 switch (scf_error()) {
955 case SCF_ERROR_CONSTRAINT_VIOLATED
:
956 (void) scf_set_error(
957 SCF_ERROR_INVALID_ARGUMENT
);
959 case SCF_ERROR_DELETED
:
960 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
965 scf_instance_destroy(inst
);
968 scf_handle_destroy(h
);
975 * get_inst_state() gets the state string from an instance, and returns
976 * the SCF_STATE_* constant that coincides with the instance's current state.
980 get_inst_state(scf_instance_t
*inst
, scf_handle_t
*h
)
982 scf_propertygroup_t
*pg
= NULL
;
983 scf_property_t
*prop
= NULL
;
984 scf_value_t
*val
= NULL
;
985 char state
[MAX_SCF_STATE_STRING_SZ
];
988 if (((pg
= scf_pg_create(h
)) == NULL
) ||
989 ((prop
= scf_property_create(h
)) == NULL
) ||
990 ((val
= scf_value_create(h
)) == NULL
))
993 /* Pull the state property from the instance */
995 if (scf_instance_get_pg(inst
, SCF_PG_RESTARTER
, pg
) == -1 ||
996 scf_pg_get_property(pg
, SCF_PROPERTY_STATE
, prop
) == -1 ||
997 scf_property_get_value(prop
, val
) == -1) {
998 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
999 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1003 if (scf_value_get_astring(val
, state
, sizeof (state
)) <= 0) {
1004 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1008 if (strcmp(state
, SCF_STATE_STRING_UNINIT
) == 0) {
1009 ret
= SCF_STATE_UNINIT
;
1010 } else if (strcmp(state
, SCF_STATE_STRING_MAINT
) == 0) {
1011 ret
= SCF_STATE_MAINT
;
1012 } else if (strcmp(state
, SCF_STATE_STRING_OFFLINE
) == 0) {
1013 ret
= SCF_STATE_OFFLINE
;
1014 } else if (strcmp(state
, SCF_STATE_STRING_DISABLED
) == 0) {
1015 ret
= SCF_STATE_DISABLED
;
1016 } else if (strcmp(state
, SCF_STATE_STRING_ONLINE
) == 0) {
1017 ret
= SCF_STATE_ONLINE
;
1018 } else if (strcmp(state
, SCF_STATE_STRING_DEGRADED
) == 0) {
1019 ret
= SCF_STATE_DEGRADED
;
1024 scf_property_destroy(prop
);
1025 (void) scf_value_destroy(val
);
1031 * Sets an instance to be enabled or disabled after reboot, using the
1032 * temporary (overriding) general_ovr property group to reflect the
1033 * present state, if it is different.
1036 set_inst_enabled_atboot(scf_instance_t
*inst
, uint8_t desired
)
1042 if ((persistent
= get_inst_enabled(inst
, SCF_PG_GENERAL
)) < 0) {
1043 if (scf_error() != SCF_ERROR_NOT_FOUND
)
1045 persistent
= B_FALSE
;
1047 if ((enabled
= get_inst_enabled(inst
, SCF_PG_GENERAL_OVR
)) < 0) {
1048 enabled
= persistent
;
1049 if (persistent
!= desired
) {
1051 * Temporarily store the present enabled state.
1053 if (set_inst_enabled(inst
, persistent
,
1054 SCF_PG_GENERAL_OVR
, SCF_PG_GENERAL_OVR_FLAGS
))
1058 if (persistent
!= desired
)
1059 if (set_inst_enabled(inst
, desired
, SCF_PG_GENERAL
,
1060 SCF_PG_GENERAL_FLAGS
))
1062 if (enabled
== desired
)
1063 ret
= delete_inst_enabled(inst
, SCF_PG_GENERAL_OVR
);
1072 set_inst_enabled_flags(const char *fmri
, int flags
, uint8_t desired
)
1076 scf_instance_t
*inst
;
1078 if (flags
& ~(SMF_TEMPORARY
| SMF_AT_NEXT_BOOT
) ||
1079 flags
& SMF_TEMPORARY
&& flags
& SMF_AT_NEXT_BOOT
) {
1080 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
1084 if ((h
= handle_create()) == NULL
)
1087 if ((inst
= scf_instance_create(h
)) == NULL
) {
1088 scf_handle_destroy(h
);
1092 if (scf_handle_decode_fmri(h
, fmri
, NULL
, NULL
, inst
, NULL
, NULL
,
1093 SCF_DECODE_FMRI_EXACT
) == -1) {
1094 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED
)
1095 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
1099 if (flags
& SMF_AT_NEXT_BOOT
) {
1100 ret
= set_inst_enabled_atboot(inst
, desired
);
1102 if (set_inst_enabled(inst
, desired
, flags
& SMF_TEMPORARY
?
1103 SCF_PG_GENERAL_OVR
: SCF_PG_GENERAL
, flags
& SMF_TEMPORARY
?
1104 SCF_PG_GENERAL_OVR_FLAGS
: SCF_PG_GENERAL_FLAGS
))
1108 * Make the persistent value effective by deleting the
1111 if (flags
& SMF_TEMPORARY
)
1114 ret
= delete_inst_enabled(inst
, SCF_PG_GENERAL_OVR
);
1118 scf_instance_destroy(inst
);
1119 scf_handle_destroy(h
);
1120 if (ret
== -1 && scf_error() == SCF_ERROR_DELETED
)
1121 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
1126 * Create and return a pg from the instance associated with the given handle.
1127 * This function is only called in scf_transaction_setup and
1128 * scf_transaction_restart where the h->rh_instance pointer is properly filled
1129 * in by scf_general_setup_pg().
1131 static scf_propertygroup_t
*
1132 get_instance_pg(scf_simple_handle_t
*simple_h
)
1134 scf_propertygroup_t
*ret_pg
= scf_pg_create(simple_h
->h
);
1138 if (ret_pg
== NULL
) {
1142 namelen
= scf_limit(SCF_LIMIT_MAX_NAME_LENGTH
) + 1;
1143 assert(namelen
> 0);
1145 if ((pg_name
= malloc(namelen
)) == NULL
) {
1146 if (scf_error() == SCF_ERROR_NOT_SET
) {
1147 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1152 if (scf_pg_get_name(simple_h
->running_pg
, pg_name
, namelen
) < 0) {
1153 if (scf_error() == SCF_ERROR_NOT_SET
) {
1154 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1159 /* Get pg from instance */
1160 if (scf_instance_get_pg(simple_h
->inst
, pg_name
, ret_pg
) == -1) {
1168 smf_enable_instance(const char *fmri
, int flags
)
1170 return (set_inst_enabled_flags(fmri
, flags
, B_TRUE
));
1174 smf_disable_instance(const char *fmri
, int flags
)
1176 return (set_inst_enabled_flags(fmri
, flags
, B_FALSE
));
1180 _smf_refresh_instance_i(scf_instance_t
*inst
)
1182 return (set_inst_action_inst(inst
, SCF_PROPERTY_REFRESH
));
1186 smf_refresh_instance(const char *instance
)
1188 return (set_inst_action(instance
, SCF_PROPERTY_REFRESH
));
1192 smf_restart_instance(const char *instance
)
1194 return (set_inst_action(instance
, SCF_PROPERTY_RESTART
));
1198 smf_maintain_instance(const char *instance
, int flags
)
1200 if (flags
& SMF_TEMPORARY
)
1201 return (set_inst_action(instance
,
1202 (flags
& SMF_IMMEDIATE
) ?
1203 SCF_PROPERTY_MAINT_ON_IMMTEMP
:
1204 SCF_PROPERTY_MAINT_ON_TEMPORARY
));
1206 return (set_inst_action(instance
,
1207 (flags
& SMF_IMMEDIATE
) ?
1208 SCF_PROPERTY_MAINT_ON_IMMEDIATE
:
1209 SCF_PROPERTY_MAINT_ON
));
1213 smf_degrade_instance(const char *instance
, int flags
)
1215 scf_simple_prop_t
*prop
;
1216 const char *state_str
;
1218 if (flags
& SMF_TEMPORARY
)
1219 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1221 if ((prop
= scf_simple_prop_get(NULL
, instance
, SCF_PG_RESTARTER
,
1222 SCF_PROPERTY_STATE
)) == NULL
)
1223 return (SCF_FAILED
);
1225 if ((state_str
= scf_simple_prop_next_astring(prop
)) == NULL
) {
1226 scf_simple_prop_free(prop
);
1227 return (SCF_FAILED
);
1230 if (strcmp(state_str
, SCF_STATE_STRING_ONLINE
) != 0) {
1231 scf_simple_prop_free(prop
);
1232 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
));
1234 scf_simple_prop_free(prop
);
1236 return (set_inst_action(instance
, (flags
& SMF_IMMEDIATE
) ?
1237 SCF_PROPERTY_DEGRADE_IMMEDIATE
: SCF_PROPERTY_DEGRADED
));
1241 smf_restore_instance(const char *instance
)
1243 scf_simple_prop_t
*prop
;
1244 const char *state_str
;
1247 if ((prop
= scf_simple_prop_get(NULL
, instance
, SCF_PG_RESTARTER
,
1248 SCF_PROPERTY_STATE
)) == NULL
)
1249 return (SCF_FAILED
);
1251 if ((state_str
= scf_simple_prop_next_astring(prop
)) == NULL
) {
1252 scf_simple_prop_free(prop
);
1253 return (SCF_FAILED
);
1256 if (strcmp(state_str
, SCF_STATE_STRING_MAINT
) == 0) {
1257 ret
= set_inst_action(instance
, SCF_PROPERTY_MAINT_OFF
);
1258 } else if (strcmp(state_str
, SCF_STATE_STRING_DEGRADED
) == 0) {
1259 ret
= set_inst_action(instance
, SCF_PROPERTY_RESTORE
);
1261 ret
= scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
);
1264 scf_simple_prop_free(prop
);
1269 smf_get_state(const char *instance
)
1271 scf_simple_prop_t
*prop
;
1272 const char *state_str
;
1275 if ((prop
= scf_simple_prop_get(NULL
, instance
, SCF_PG_RESTARTER
,
1276 SCF_PROPERTY_STATE
)) == NULL
)
1279 if ((state_str
= scf_simple_prop_next_astring(prop
)) == NULL
) {
1280 scf_simple_prop_free(prop
);
1284 if ((ret
= strdup(state_str
)) == NULL
)
1285 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1287 scf_simple_prop_free(prop
);
1292 * scf_general_pg_setup(fmri, pg_name)
1293 * Create a scf_simple_handle_t and fill in the instance, snapshot, and
1294 * property group fields associated with the given fmri and property group
1298 * Null on error with scf_error set to:
1299 * SCF_ERROR_HANDLE_MISMATCH,
1300 * SCF_ERROR_INVALID_ARGUMENT,
1301 * SCF_ERROR_CONSTRAINT_VIOLATED,
1302 * SCF_ERROR_NOT_FOUND,
1303 * SCF_ERROR_NOT_SET,
1304 * SCF_ERROR_DELETED,
1305 * SCF_ERROR_NOT_BOUND,
1306 * SCF_ERROR_CONNECTION_BROKEN,
1307 * SCF_ERROR_INTERNAL,
1308 * SCF_ERROR_NO_RESOURCES,
1309 * SCF_ERROR_BACKEND_ACCESS
1311 scf_simple_handle_t
*
1312 scf_general_pg_setup(const char *fmri
, const char *pg_name
)
1314 scf_simple_handle_t
*ret
;
1316 ret
= uu_zalloc(sizeof (*ret
));
1318 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1322 ret
->h
= handle_create();
1323 ret
->inst
= scf_instance_create(ret
->h
);
1324 ret
->snap
= scf_snapshot_create(ret
->h
);
1325 ret
->running_pg
= scf_pg_create(ret
->h
);
1328 if ((ret
->h
== NULL
) || (ret
->inst
== NULL
) ||
1329 (ret
->snap
== NULL
) || (ret
->running_pg
== NULL
)) {
1333 if (scf_handle_decode_fmri(ret
->h
, fmri
, NULL
, NULL
, ret
->inst
,
1334 NULL
, NULL
, NULL
) == -1) {
1338 if ((scf_instance_get_snapshot(ret
->inst
, "running", ret
->snap
))
1343 if (scf_instance_get_pg_composed(ret
->inst
, ret
->snap
, pg_name
,
1344 ret
->running_pg
) != 0) {
1351 scf_simple_handle_destroy(ret
);
1356 * scf_transaction_setup(h)
1357 * creates and starts the transaction
1359 * transaction on success
1360 * NULL on failure with scf_error set to:
1361 * SCF_ERROR_NO_MEMORY,
1362 * SCF_ERROR_INVALID_ARGUMENT,
1363 * SCF_ERROR_HANDLE_DESTROYED,
1364 * SCF_ERROR_INTERNAL,
1365 * SCF_ERROR_NO_RESOURCES,
1366 * SCF_ERROR_NOT_BOUND,
1367 * SCF_ERROR_CONNECTION_BROKEN,
1368 * SCF_ERROR_NOT_SET,
1369 * SCF_ERROR_DELETED,
1370 * SCF_ERROR_CONSTRAINT_VIOLATED,
1371 * SCF_ERROR_HANDLE_MISMATCH,
1372 * SCF_ERROR_BACKEND_ACCESS,
1376 scf_transaction_setup(scf_simple_handle_t
*simple_h
)
1378 scf_transaction_t
*tx
= NULL
;
1380 if ((tx
= scf_transaction_create(simple_h
->h
)) == NULL
) {
1384 if ((simple_h
->editing_pg
= get_instance_pg(simple_h
)) == NULL
) {
1388 if (scf_transaction_start(tx
, simple_h
->editing_pg
) == -1) {
1389 scf_pg_destroy(simple_h
->editing_pg
);
1390 simple_h
->editing_pg
= NULL
;
1398 scf_transaction_restart(scf_simple_handle_t
*simple_h
, scf_transaction_t
*tx
)
1400 scf_transaction_reset(tx
);
1402 if (scf_pg_update(simple_h
->editing_pg
) == -1) {
1403 return (SCF_FAILED
);
1406 if (scf_transaction_start(tx
, simple_h
->editing_pg
) == -1) {
1407 return (SCF_FAILED
);
1410 return (SCF_SUCCESS
);
1414 * scf_read_count_property(scf_simple_handle_t *simple_h, char *prop_name,
1415 * uint64_t *ret_count)
1417 * For the given property name, return the count value.
1420 * SCF_FAILED on failure with scf_error() set to:
1421 * SCF_ERROR_HANDLE_DESTROYED
1422 * SCF_ERROR_INTERNAL
1423 * SCF_ERROR_NO_RESOURCES
1424 * SCF_ERROR_NO_MEMORY
1425 * SCF_ERROR_HANDLE_MISMATCH
1426 * SCF_ERROR_INVALID_ARGUMENT
1427 * SCF_ERROR_NOT_BOUND
1428 * SCF_ERROR_CONNECTION_BROKEN
1431 * SCF_ERROR_BACKEND_ACCESS
1432 * SCF_ERROR_CONSTRAINT_VIOLATED
1433 * SCF_ERROR_TYPE_MISMATCH
1436 scf_read_count_property(
1437 scf_simple_handle_t
*simple_h
,
1439 uint64_t *ret_count
)
1441 scf_property_t
*prop
= scf_property_create(simple_h
->h
);
1442 scf_value_t
*val
= scf_value_create(simple_h
->h
);
1443 int ret
= SCF_FAILED
;
1445 if ((val
== NULL
) || (prop
== NULL
)) {
1450 * Get the property struct that goes with this property group and
1453 if (scf_pg_get_property(simple_h
->running_pg
, prop_name
, prop
) != 0) {
1457 /* Get the value structure */
1458 if (scf_property_get_value(prop
, val
) == -1) {
1463 * Now get the count value.
1465 if (scf_value_get_count(val
, ret_count
) == -1) {
1472 scf_property_destroy(prop
);
1473 scf_value_destroy(val
);
1478 * scf_trans_add_count_property(trans, propname, count, create_flag)
1480 * Set a count property transaction entry into the pending SMF transaction.
1481 * The transaction is created and committed outside of this function.
1484 * SCF_FAILED on failure with scf_error() set to:
1485 * SCF_ERROR_HANDLE_DESTROYED,
1486 * SCF_ERROR_INVALID_ARGUMENT,
1487 * SCF_ERROR_NO_MEMORY,
1488 * SCF_ERROR_HANDLE_MISMATCH,
1489 * SCF_ERROR_NOT_SET,
1491 * SCF_ERROR_NOT_FOUND,
1493 * SCF_ERROR_TYPE_MISMATCH,
1494 * SCF_ERROR_NOT_BOUND,
1495 * SCF_ERROR_CONNECTION_BROKEN,
1496 * SCF_ERROR_INTERNAL,
1497 * SCF_ERROR_DELETED,
1498 * SCF_ERROR_NO_RESOURCES,
1499 * SCF_ERROR_BACKEND_ACCESS
1502 scf_set_count_property(
1503 scf_transaction_t
*trans
,
1506 boolean_t create_flag
)
1508 scf_handle_t
*handle
= scf_transaction_handle(trans
);
1509 scf_value_t
*value
= scf_value_create(handle
);
1510 scf_transaction_entry_t
*entry
= scf_entry_create(handle
);
1512 if ((value
== NULL
) || (entry
== NULL
)) {
1513 return (SCF_FAILED
);
1517 * Property must be set in transaction and won't take
1518 * effect until the transaction is committed.
1520 * Attempt to change the current value. However, create new property
1521 * if it doesn't exist and the create flag is set.
1523 if (scf_transaction_property_change(trans
, entry
, propname
,
1524 SCF_TYPE_COUNT
) == 0) {
1525 scf_value_set_count(value
, count
);
1526 if (scf_entry_add_value(entry
, value
) == 0) {
1527 return (SCF_SUCCESS
);
1530 if ((create_flag
== B_TRUE
) &&
1531 (scf_error() == SCF_ERROR_NOT_FOUND
)) {
1532 if (scf_transaction_property_new(trans
, entry
, propname
,
1533 SCF_TYPE_COUNT
) == 0) {
1534 scf_value_set_count(value
, count
);
1535 if (scf_entry_add_value(entry
, value
) == 0) {
1536 return (SCF_SUCCESS
);
1543 * cleanup if there were any errors that didn't leave these
1544 * values where they would be cleaned up later.
1547 scf_value_destroy(value
);
1549 scf_entry_destroy(entry
);
1550 return (SCF_FAILED
);
1554 scf_simple_walk_instances(uint_t state_flags
, void *private,
1555 int (*inst_callback
)(scf_handle_t
*, scf_instance_t
*, void *))
1557 scf_scope_t
*scope
= NULL
;
1558 scf_service_t
*svc
= NULL
;
1559 scf_instance_t
*inst
= NULL
;
1560 scf_iter_t
*svc_iter
= NULL
, *inst_iter
= NULL
;
1561 scf_handle_t
*h
= NULL
;
1562 int ret
= SCF_FAILED
;
1563 int svc_iter_ret
, inst_iter_ret
;
1566 if ((h
= handle_create()) == NULL
)
1569 if (((scope
= scf_scope_create(h
)) == NULL
) ||
1570 ((svc
= scf_service_create(h
)) == NULL
) ||
1571 ((inst
= scf_instance_create(h
)) == NULL
) ||
1572 ((svc_iter
= scf_iter_create(h
)) == NULL
) ||
1573 ((inst_iter
= scf_iter_create(h
)) == NULL
))
1577 * Get the local scope, and set up nested iteration through every
1578 * local service, and every instance of every service.
1581 if ((scf_handle_get_local_scope(h
, scope
) != SCF_SUCCESS
) ||
1582 (scf_iter_scope_services(svc_iter
, scope
) != SCF_SUCCESS
))
1585 while ((svc_iter_ret
= scf_iter_next_service(svc_iter
, svc
)) > 0) {
1587 if ((scf_iter_service_instances(inst_iter
, svc
)) !=
1591 while ((inst_iter_ret
=
1592 scf_iter_next_instance(inst_iter
, inst
)) > 0) {
1594 * If get_inst_state fails from an internal error,
1595 * IE, being unable to get the property group or
1596 * property containing the state of the instance,
1597 * we continue instead of failing, as this might just
1598 * be an improperly configured instance.
1600 if ((inst_state
= get_inst_state(inst
, h
)) == -1) {
1601 if (scf_error() == SCF_ERROR_INTERNAL
) {
1608 if ((uint_t
)inst_state
& state_flags
) {
1609 if (inst_callback(h
, inst
, private) !=
1611 (void) scf_set_error(
1612 SCF_ERROR_CALLBACK_FAILED
);
1618 if (inst_iter_ret
== -1)
1620 scf_iter_reset(inst_iter
);
1623 if (svc_iter_ret
!= -1)
1627 scf_scope_destroy(scope
);
1628 scf_service_destroy(svc
);
1629 scf_instance_destroy(inst
);
1630 scf_iter_destroy(svc_iter
);
1631 scf_iter_destroy(inst_iter
);
1632 scf_handle_destroy(h
);
1639 scf_simple_prop_get(scf_handle_t
*hin
, const char *instance
, const char *pgname
,
1640 const char *propname
)
1642 char *fmri_buf
, *svcfmri
= NULL
;
1644 scf_property_t
*prop
= NULL
;
1645 scf_service_t
*svc
= NULL
;
1646 scf_simple_prop_t
*ret
;
1647 scf_handle_t
*h
= NULL
;
1648 boolean_t local_h
= B_TRUE
;
1650 /* If the user passed in a handle, use it. */
1656 if (local_h
&& ((h
= handle_create()) == NULL
))
1659 if ((fmri_buf
= assemble_fmri(h
, instance
, pgname
, propname
)) == NULL
) {
1661 scf_handle_destroy(h
);
1665 if ((svc
= scf_service_create(h
)) == NULL
||
1666 (prop
= scf_property_create(h
)) == NULL
)
1668 if (scf_handle_decode_fmri(h
, fmri_buf
, NULL
, NULL
, NULL
, NULL
, prop
,
1669 SCF_DECODE_FMRI_REQUIRE_INSTANCE
) == -1) {
1670 switch (scf_error()) {
1672 * If the property isn't found in the instance, we grab the
1673 * underlying service, create an FMRI out of it, and then
1674 * query the datastore again at the service level for the
1677 case SCF_ERROR_NOT_FOUND
:
1678 if (scf_handle_decode_fmri(h
, fmri_buf
, NULL
, svc
,
1679 NULL
, NULL
, NULL
, SCF_DECODE_FMRI_TRUNCATE
) == -1)
1682 fmri_sz
= scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH
) + 1;
1683 assert(fmri_sz
> 0);
1685 if (scf_service_to_fmri(svc
, fmri_buf
, fmri_sz
) == -1)
1687 if ((svcfmri
= assemble_fmri(h
, fmri_buf
, pgname
,
1690 if (scf_handle_decode_fmri(h
, svcfmri
, NULL
, NULL
,
1691 NULL
, NULL
, prop
, 0) == -1) {
1697 case SCF_ERROR_CONSTRAINT_VIOLATED
:
1698 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
1704 * At this point, we've successfully pulled the property from the
1705 * datastore, and simply need to copy its innards into an
1706 * scf_simple_prop_t.
1708 if ((ret
= fill_prop(prop
, pgname
, propname
, h
)) == NULL
)
1711 scf_service_destroy(svc
);
1712 scf_property_destroy(prop
);
1715 scf_handle_destroy(h
);
1719 * Exit point for a successful call. Below this line are exit points
1720 * for failures at various stages during the function.
1724 scf_service_destroy(svc
);
1725 scf_property_destroy(prop
);
1729 scf_handle_destroy(h
);
1735 scf_simple_prop_free(scf_simple_prop_t
*prop
)
1742 free(prop
->pr_propname
);
1743 free(prop
->pr_pgname
);
1744 switch (prop
->pr_type
) {
1745 case SCF_TYPE_OPAQUE
: {
1746 for (i
= 0; i
< prop
->pr_numvalues
; i
++) {
1747 free(prop
->pr_vallist
[i
].pv_opaque
.o_value
);
1751 case SCF_TYPE_ASTRING
:
1752 case SCF_TYPE_USTRING
:
1754 case SCF_TYPE_HOSTNAME
:
1755 case SCF_TYPE_NET_ADDR_V4
:
1756 case SCF_TYPE_NET_ADDR_V6
:
1758 case SCF_TYPE_FMRI
: {
1759 for (i
= 0; i
< prop
->pr_numvalues
; i
++) {
1760 free(prop
->pr_vallist
[i
].pv_str
);
1767 free(prop
->pr_vallist
);
1772 scf_simple_app_props_t
*
1773 scf_simple_app_props_get(scf_handle_t
*hin
, const char *inst_fmri
)
1775 scf_instance_t
*inst
= NULL
;
1776 scf_service_t
*svc
= NULL
;
1777 scf_propertygroup_t
*pg
= NULL
;
1778 scf_property_t
*prop
= NULL
;
1779 scf_simple_app_props_t
*ret
= NULL
;
1780 scf_iter_t
*pgiter
= NULL
, *propiter
= NULL
;
1781 struct scf_simple_pg
*thispg
= NULL
, *nextpg
;
1782 scf_simple_prop_t
*thisprop
, *nextprop
;
1783 scf_handle_t
*h
= NULL
;
1784 int pgiter_ret
, propiter_ret
;
1786 char *propname
= NULL
, *pgname
= NULL
, *sys_fmri
;
1788 boolean_t local_h
= B_TRUE
;
1790 /* If the user passed in a handle, use it. */
1796 if (local_h
&& ((h
= handle_create()) == NULL
))
1799 if (inst_fmri
== NULL
) {
1800 if ((namelen
= scf_myname(h
, NULL
, 0)) == -1) {
1802 scf_handle_destroy(h
);
1805 if ((sys_fmri
= malloc(namelen
+ 1)) == NULL
) {
1807 scf_handle_destroy(h
);
1808 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1811 if (scf_myname(h
, sys_fmri
, namelen
+ 1) == -1) {
1813 scf_handle_destroy(h
);
1818 if ((sys_fmri
= strdup(inst_fmri
)) == NULL
) {
1820 scf_handle_destroy(h
);
1821 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1826 namelen
= scf_limit(SCF_LIMIT_MAX_NAME_LENGTH
) + 1;
1827 assert(namelen
> 0);
1829 if ((inst
= scf_instance_create(h
)) == NULL
||
1830 (svc
= scf_service_create(h
)) == NULL
||
1831 (pgiter
= scf_iter_create(h
)) == NULL
||
1832 (propiter
= scf_iter_create(h
)) == NULL
||
1833 (pg
= scf_pg_create(h
)) == NULL
||
1834 (prop
= scf_property_create(h
)) == NULL
)
1837 if (scf_handle_decode_fmri(h
, sys_fmri
, NULL
, svc
, inst
, NULL
, NULL
,
1838 SCF_DECODE_FMRI_REQUIRE_INSTANCE
) == -1) {
1839 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED
)
1840 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
1844 if ((ret
= malloc(sizeof (*ret
))) == NULL
||
1845 (thispg
= malloc(sizeof (*thispg
))) == NULL
||
1846 (propname
= malloc(namelen
)) == NULL
||
1847 (pgname
= malloc(namelen
)) == NULL
) {
1850 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1854 ret
->ap_fmri
= sys_fmri
;
1855 thispg
->pg_name
= NULL
;
1856 thispg
->pg_proplist
= NULL
;
1857 thispg
->pg_next
= NULL
;
1858 ret
->ap_pglist
= thispg
;
1860 if (scf_iter_service_pgs_typed(pgiter
, svc
, SCF_GROUP_APPLICATION
) !=
1862 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1863 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1867 while ((pgiter_ret
= scf_iter_next_pg(pgiter
, pg
)) == 1) {
1868 if (thispg
->pg_name
!= NULL
) {
1869 if ((nextpg
= malloc(sizeof (*nextpg
))) == NULL
) {
1870 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1873 nextpg
->pg_name
= NULL
;
1874 nextpg
->pg_next
= NULL
;
1875 nextpg
->pg_proplist
= NULL
;
1876 thispg
->pg_next
= nextpg
;
1879 /* This is the first iteration */
1883 if ((nextpg
->pg_name
= malloc(namelen
)) == NULL
) {
1884 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
1888 if (scf_pg_get_name(pg
, nextpg
->pg_name
, namelen
) < 0) {
1889 if (scf_error() == SCF_ERROR_NOT_SET
)
1890 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1896 scf_iter_reset(propiter
);
1898 if (scf_iter_pg_properties(propiter
, pg
) != 0) {
1899 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1900 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1904 while ((propiter_ret
= scf_iter_next_property(propiter
, prop
))
1906 if (scf_property_get_name(prop
, propname
, namelen
) <
1908 if (scf_error() == SCF_ERROR_NOT_SET
)
1909 (void) scf_set_error(
1910 SCF_ERROR_INTERNAL
);
1913 if (thisprop
!= NULL
) {
1914 if ((nextprop
= fill_prop(prop
,
1915 nextpg
->pg_name
, propname
, h
)) == NULL
)
1917 thisprop
->pr_next
= nextprop
;
1918 thisprop
= nextprop
;
1920 /* This is the first iteration */
1921 if ((thisprop
= fill_prop(prop
,
1922 nextpg
->pg_name
, propname
, h
)) == NULL
)
1924 nextpg
->pg_proplist
= thisprop
;
1925 nextprop
= thisprop
;
1927 nextprop
->pr_pg
= nextpg
;
1928 nextprop
->pr_next
= NULL
;
1931 if (propiter_ret
== -1) {
1932 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1933 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1938 if (pgiter_ret
== -1) {
1939 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1940 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1945 * At this point, we've filled the scf_simple_app_props_t with all the
1946 * properties at the service level. Now we iterate over all the
1947 * properties at the instance level, overwriting any duplicate
1948 * properties, in order to provide service/instance composition.
1951 scf_iter_reset(pgiter
);
1952 scf_iter_reset(propiter
);
1954 if (scf_iter_instance_pgs_typed(pgiter
, inst
, SCF_GROUP_APPLICATION
)
1956 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1957 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1961 while ((pgiter_ret
= scf_iter_next_pg(pgiter
, pg
)) == 1) {
1963 thispg
= ret
->ap_pglist
;
1967 * Find either the end of the list, so we can append the
1968 * property group, or an existing property group that matches
1969 * it, so we can insert/overwrite its properties.
1972 if (scf_pg_get_name(pg
, pgname
, namelen
) < 0) {
1973 if (scf_error() == SCF_ERROR_NOT_SET
)
1974 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1978 while ((thispg
!= NULL
) && (thispg
->pg_name
!= NULL
)) {
1979 if (strcmp(thispg
->pg_name
, pgname
) == 0) {
1983 if (thispg
->pg_next
== NULL
)
1986 thispg
= thispg
->pg_next
;
1989 scf_iter_reset(propiter
);
1991 if (scf_iter_pg_properties(propiter
, pg
) != 0) {
1992 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
1993 (void) scf_set_error(SCF_ERROR_INTERNAL
);
1999 * insert_app_props inserts or overwrites the
2000 * properties in thispg.
2003 if (insert_app_props(propiter
, pgname
, propname
,
2004 thispg
, prop
, namelen
, h
) == -1)
2009 * If the property group wasn't found, we're adding
2010 * a newly allocated property group to the end of the
2014 if ((nextpg
= malloc(sizeof (*nextpg
))) == NULL
) {
2015 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2018 nextpg
->pg_next
= NULL
;
2019 nextpg
->pg_proplist
= NULL
;
2022 if ((nextpg
->pg_name
= strdup(pgname
)) == NULL
) {
2023 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2028 if (thispg
->pg_name
== NULL
) {
2030 ret
->ap_pglist
= nextpg
;
2032 thispg
->pg_next
= nextpg
;
2035 while ((propiter_ret
=
2036 scf_iter_next_property(propiter
, prop
)) == 1) {
2037 if (scf_property_get_name(prop
, propname
,
2039 if (scf_error() == SCF_ERROR_NOT_SET
)
2040 (void) scf_set_error(
2041 SCF_ERROR_INTERNAL
);
2044 if (thisprop
!= NULL
) {
2045 if ((nextprop
= fill_prop(prop
,
2046 pgname
, propname
, h
)) ==
2049 thisprop
->pr_next
= nextprop
;
2050 thisprop
= nextprop
;
2052 /* This is the first iteration */
2053 if ((thisprop
= fill_prop(prop
,
2054 pgname
, propname
, h
)) ==
2057 nextpg
->pg_proplist
= thisprop
;
2058 nextprop
= thisprop
;
2060 nextprop
->pr_pg
= nextpg
;
2061 nextprop
->pr_next
= NULL
;
2064 if (propiter_ret
== -1) {
2065 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
2066 (void) scf_set_error(
2067 SCF_ERROR_INTERNAL
);
2074 if (pgiter_ret
== -1) {
2075 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN
)
2076 (void) scf_set_error(SCF_ERROR_INTERNAL
);
2080 scf_iter_destroy(pgiter
);
2081 scf_iter_destroy(propiter
);
2083 scf_property_destroy(prop
);
2084 scf_instance_destroy(inst
);
2085 scf_service_destroy(svc
);
2089 scf_handle_destroy(h
);
2091 if (ret
->ap_pglist
->pg_name
== NULL
)
2097 * Exit point for a successful call. Below this line are exit points
2098 * for failures at various stages during the function.
2102 scf_simple_app_props_free(ret
);
2105 scf_iter_destroy(pgiter
);
2106 scf_iter_destroy(propiter
);
2108 scf_property_destroy(prop
);
2109 scf_instance_destroy(inst
);
2110 scf_service_destroy(svc
);
2114 scf_handle_destroy(h
);
2120 scf_simple_app_props_free(scf_simple_app_props_t
*propblock
)
2122 struct scf_simple_pg
*pgthis
, *pgnext
;
2123 scf_simple_prop_t
*propthis
, *propnext
;
2125 if ((propblock
== NULL
) || (propblock
->ap_pglist
== NULL
))
2128 for (pgthis
= propblock
->ap_pglist
; pgthis
!= NULL
; pgthis
= pgnext
) {
2129 pgnext
= pgthis
->pg_next
;
2131 propthis
= pgthis
->pg_proplist
;
2133 while (propthis
!= NULL
) {
2134 propnext
= propthis
->pr_next
;
2135 scf_simple_prop_free(propthis
);
2136 propthis
= propnext
;
2139 free(pgthis
->pg_name
);
2143 free(propblock
->ap_fmri
);
2147 const scf_simple_prop_t
*
2148 scf_simple_app_props_next(const scf_simple_app_props_t
*propblock
,
2149 scf_simple_prop_t
*last
)
2151 struct scf_simple_pg
*this;
2153 if (propblock
== NULL
) {
2154 (void) scf_set_error(SCF_ERROR_NOT_SET
);
2158 this = propblock
->ap_pglist
;
2161 * We're looking for the first property in this block if last is
2166 /* An empty pglist is legal, it just means no properties */
2168 (void) scf_set_error(SCF_ERROR_NONE
);
2172 * Walk until we find a pg with a property in it, or we run
2173 * out of property groups.
2175 while ((this->pg_proplist
== NULL
) && (this->pg_next
!= NULL
))
2176 this = this->pg_next
;
2178 if (this->pg_proplist
== NULL
) {
2179 (void) scf_set_error(SCF_ERROR_NONE
);
2183 return (this->pg_proplist
);
2187 * If last isn't NULL, then return the next prop in the property group,
2188 * or walk the property groups until we find another property, or
2189 * run out of property groups.
2191 if (last
->pr_next
!= NULL
)
2192 return (last
->pr_next
);
2194 if (last
->pr_pg
->pg_next
== NULL
) {
2195 (void) scf_set_error(SCF_ERROR_NONE
);
2199 this = last
->pr_pg
->pg_next
;
2201 while ((this->pg_proplist
== NULL
) && (this->pg_next
!= NULL
))
2202 this = this->pg_next
;
2204 if (this->pg_proplist
== NULL
) {
2205 (void) scf_set_error(SCF_ERROR_NONE
);
2209 return (this->pg_proplist
);
2212 const scf_simple_prop_t
*
2213 scf_simple_app_props_search(const scf_simple_app_props_t
*propblock
,
2214 const char *pgname
, const char *propname
)
2216 struct scf_simple_pg
*pg
;
2217 scf_simple_prop_t
*prop
;
2219 if ((propblock
== NULL
) || (propname
== NULL
)) {
2220 (void) scf_set_error(SCF_ERROR_NOT_SET
);
2224 pg
= propblock
->ap_pglist
;
2227 * If pgname is NULL, we're searching the default application
2228 * property group, otherwise we look for the specified group.
2230 if (pgname
== NULL
) {
2231 while ((pg
!= NULL
) &&
2232 (strcmp(SCF_PG_APP_DEFAULT
, pg
->pg_name
) != 0))
2235 while ((pg
!= NULL
) && (strcmp(pgname
, pg
->pg_name
) != 0))
2240 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
2244 prop
= pg
->pg_proplist
;
2246 while ((prop
!= NULL
) && (strcmp(propname
, prop
->pr_propname
) != 0))
2247 prop
= prop
->pr_next
;
2250 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
2258 scf_simple_prop_next_reset(scf_simple_prop_t
*prop
)
2266 scf_simple_prop_numvalues(const scf_simple_prop_t
*prop
)
2269 return (scf_set_error(SCF_ERROR_NOT_SET
));
2271 return (prop
->pr_numvalues
);
2276 scf_simple_prop_type(const scf_simple_prop_t
*prop
)
2279 return (scf_set_error(SCF_ERROR_NOT_SET
));
2281 return (prop
->pr_type
);
2286 scf_simple_prop_name(const scf_simple_prop_t
*prop
)
2288 if ((prop
== NULL
) || (prop
->pr_propname
== NULL
)) {
2289 (void) scf_set_error(SCF_ERROR_NOT_SET
);
2293 return (prop
->pr_propname
);
2298 scf_simple_prop_pgname(const scf_simple_prop_t
*prop
)
2300 if ((prop
== NULL
) || (prop
->pr_pgname
== NULL
)) {
2301 (void) scf_set_error(SCF_ERROR_NOT_SET
);
2305 return (prop
->pr_pgname
);
2309 static union scf_simple_prop_val
*
2310 scf_next_val(scf_simple_prop_t
*prop
, scf_type_t type
)
2313 (void) scf_set_error(SCF_ERROR_NOT_SET
);
2317 switch (prop
->pr_type
) {
2318 case SCF_TYPE_USTRING
:
2320 case SCF_TYPE_HOSTNAME
:
2321 case SCF_TYPE_NET_ADDR_V4
:
2322 case SCF_TYPE_NET_ADDR_V6
:
2324 case SCF_TYPE_FMRI
: {
2325 if (type
!= SCF_TYPE_USTRING
) {
2326 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH
);
2332 if (type
!= prop
->pr_type
) {
2333 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH
);
2340 if (prop
->pr_iter
>= prop
->pr_numvalues
) {
2341 (void) scf_set_error(SCF_ERROR_NONE
);
2345 return (&prop
->pr_vallist
[prop
->pr_iter
++]);
2350 scf_simple_prop_next_boolean(scf_simple_prop_t
*prop
)
2352 union scf_simple_prop_val
*ret
;
2354 ret
= scf_next_val(prop
, SCF_TYPE_BOOLEAN
);
2359 return (&ret
->pv_bool
);
2364 scf_simple_prop_next_count(scf_simple_prop_t
*prop
)
2366 union scf_simple_prop_val
*ret
;
2368 ret
= scf_next_val(prop
, SCF_TYPE_COUNT
);
2373 return (&ret
->pv_uint
);
2378 scf_simple_prop_next_integer(scf_simple_prop_t
*prop
)
2380 union scf_simple_prop_val
*ret
;
2382 ret
= scf_next_val(prop
, SCF_TYPE_INTEGER
);
2387 return (&ret
->pv_int
);
2391 scf_simple_prop_next_time(scf_simple_prop_t
*prop
, int32_t *nsec
)
2393 union scf_simple_prop_val
*ret
;
2395 ret
= scf_next_val(prop
, SCF_TYPE_TIME
);
2401 *nsec
= ret
->pv_time
.t_nsec
;
2403 return (&ret
->pv_time
.t_sec
);
2407 scf_simple_prop_next_astring(scf_simple_prop_t
*prop
)
2409 union scf_simple_prop_val
*ret
;
2411 ret
= scf_next_val(prop
, SCF_TYPE_ASTRING
);
2416 return (ret
->pv_str
);
2420 scf_simple_prop_next_ustring(scf_simple_prop_t
*prop
)
2422 union scf_simple_prop_val
*ret
;
2424 ret
= scf_next_val(prop
, SCF_TYPE_USTRING
);
2429 return (ret
->pv_str
);
2433 scf_simple_prop_next_opaque(scf_simple_prop_t
*prop
, size_t *length
)
2435 union scf_simple_prop_val
*ret
;
2437 ret
= scf_next_val(prop
, SCF_TYPE_OPAQUE
);
2444 *length
= ret
->pv_opaque
.o_size
;
2445 return (ret
->pv_opaque
.o_value
);
2449 * Generate a filename based on the fmri and the given name and return
2450 * it in the buffer of MAXPATHLEN provided by the caller.
2451 * If temp_filename is non-zero, also generate a temporary, unique filename
2452 * and return it in the temp buffer of MAXPATHLEN provided by the caller.
2453 * The path to the generated pathname is also created.
2454 * Given fmri should begin with a scheme such as "svc:".
2457 * -1 if filename would exceed MAXPATHLEN or
2458 * -2 if unable to create directory to filename path
2461 gen_filenms_from_fmri(const char *fmri
, const char *name
, char *filename
,
2462 char *temp_filename
)
2466 len
= strlen(SMF_SPEEDY_FILES_PATH
);
2467 len
+= strlen(fmri
);
2468 len
+= 2; /* for slash and null */
2469 len
+= strlen(name
);
2470 len
+= 6; /* For X's needed for mkstemp */
2472 if (len
> MAXPATHLEN
)
2475 /* Construct directory name first - speedy path ends in slash */
2476 (void) strcpy(filename
, SMF_SPEEDY_FILES_PATH
);
2477 (void) strcat(filename
, fmri
);
2478 if (mkdirp(filename
, 0755) == -1) {
2480 if (errno
!= EEXIST
)
2484 (void) strcat(filename
, "/");
2485 (void) strcat(filename
, name
);
2487 if (temp_filename
) {
2488 (void) strcpy(temp_filename
, filename
);
2489 (void) strcat(temp_filename
, "XXXXXX");
2496 scf_true_base_type(scf_type_t type
)
2498 scf_type_t base
= type
;
2502 (void) scf_type_base_type(type
, &base
);
2503 } while (base
!= type
);
2509 * Convenience routine which frees all strings and opaque data
2510 * allocated by scf_read_propvec.
2512 * Like free(3C), this function preserves the value of errno.
2515 scf_clean_propvec(scf_propvec_t
*propvec
)
2517 int saved_errno
= errno
;
2518 scf_propvec_t
*prop
;
2520 for (prop
= propvec
; prop
->pv_prop
!= NULL
; prop
++) {
2521 assert(prop
->pv_type
!= SCF_TYPE_INVALID
);
2522 if (prop
->pv_type
== SCF_TYPE_OPAQUE
) {
2523 scf_opaque_t
*o
= prop
->pv_ptr
;
2525 if (o
->so_addr
!= NULL
)
2527 } else if (scf_true_base_type(prop
->pv_type
) ==
2529 if (*(char **)prop
->pv_ptr
!= NULL
)
2530 free(*(char **)prop
->pv_ptr
);
2534 errno
= saved_errno
;
2538 count_props(scf_propvec_t
*props
)
2542 for (; props
->pv_prop
!= NULL
; props
++)
2548 * Reads a vector of properties from the specified fmri/property group.
2549 * If 'running' is true, reads from the running snapshot instead of the
2552 * For string types, a buffer is allocated using malloc(3C) to hold the
2553 * zero-terminated string, a pointer to which is stored in the
2554 * caller-provided char **. It is the caller's responsbility to free
2555 * this string. To simplify error handling, unread strings are
2556 * initialized to NULL.
2558 * For opaque types, a buffer is allocated using malloc(3C) to hold the
2559 * opaque data. A pointer to this buffer and its size are stored in
2560 * the caller-provided scf_opaque_t. It is the caller's responsibility
2561 * to free this buffer. To simplify error handling, the address fields
2562 * for unread opaque data are initialized to NULL.
2564 * All other data is stored directly in caller-provided variables or
2567 * If this function fails to read a specific property, *badprop is set
2568 * to point at that property's entry in the properties array.
2570 * On all failures, all memory allocated by this function is freed.
2573 scf_read_propvec(const char *fmri
, const char *pgname
, boolean_t running
,
2574 scf_propvec_t
*properties
, scf_propvec_t
**badprop
)
2576 scf_handle_t
*h
= handle_create();
2577 scf_service_t
*s
= scf_service_create(h
);
2578 scf_instance_t
*i
= scf_instance_create(h
);
2579 scf_snapshot_t
*snap
= running
? scf_snapshot_create(h
) : NULL
;
2580 scf_propertygroup_t
*pg
= scf_pg_create(h
);
2581 scf_property_t
*p
= scf_property_create(h
);
2582 scf_value_t
*v
= scf_value_create(h
);
2583 boolean_t instance
= B_TRUE
;
2584 scf_propvec_t
*prop
;
2587 if (h
== NULL
|| s
== NULL
|| i
== NULL
|| (running
&& snap
== NULL
) ||
2588 pg
== NULL
|| p
== NULL
|| v
== NULL
)
2591 if (scf_handle_decode_fmri(h
, fmri
, NULL
, s
, i
, NULL
, NULL
, 0) == -1)
2594 if (scf_instance_to_fmri(i
, NULL
, 0) == -1) {
2595 if (scf_error() != SCF_ERROR_NOT_SET
)
2602 error
= SCF_ERROR_TYPE_MISMATCH
;
2606 if (scf_instance_get_snapshot(i
, "running", snap
) !=
2611 if ((instance
? scf_instance_get_pg_composed(i
, snap
, pgname
, pg
) :
2612 scf_service_get_pg(s
, pgname
, pg
)) == -1)
2615 for (prop
= properties
; prop
->pv_prop
!= NULL
; prop
++) {
2616 if (prop
->pv_type
== SCF_TYPE_OPAQUE
)
2617 ((scf_opaque_t
*)prop
->pv_ptr
)->so_addr
= NULL
;
2618 else if (scf_true_base_type(prop
->pv_type
) == SCF_TYPE_ASTRING
)
2619 *((char **)prop
->pv_ptr
) = NULL
;
2622 for (prop
= properties
; prop
->pv_prop
!= NULL
; prop
++) {
2625 if (scf_pg_get_property(pg
, prop
->pv_prop
, p
) == -1 ||
2626 scf_property_get_value(p
, v
) == -1) {
2630 switch (prop
->pv_type
) {
2631 case SCF_TYPE_BOOLEAN
: {
2634 ret
= scf_value_get_boolean(v
, &b
);
2637 if (prop
->pv_aux
!= 0) {
2638 uint64_t *bits
= prop
->pv_ptr
;
2639 *bits
= b
? (*bits
| prop
->pv_aux
) :
2640 (*bits
& ~prop
->pv_aux
);
2642 boolean_t
*bool = prop
->pv_ptr
;
2643 *bool = b
? B_TRUE
: B_FALSE
;
2647 case SCF_TYPE_COUNT
:
2648 ret
= scf_value_get_count(v
, prop
->pv_ptr
);
2650 case SCF_TYPE_INTEGER
:
2651 ret
= scf_value_get_integer(v
, prop
->pv_ptr
);
2653 case SCF_TYPE_TIME
: {
2654 scf_time_t
*time
= prop
->pv_ptr
;
2656 ret
= scf_value_get_time(v
, &time
->t_seconds
,
2660 case SCF_TYPE_OPAQUE
: {
2661 scf_opaque_t
*opaque
= prop
->pv_ptr
;
2662 ssize_t size
= scf_value_get_opaque(v
, NULL
, 0);
2668 if ((opaque
->so_addr
= malloc(size
)) == NULL
) {
2669 error
= SCF_ERROR_NO_MEMORY
;
2672 opaque
->so_size
= size
;
2673 ret
= scf_value_get_opaque(v
, opaque
->so_addr
, size
);
2680 assert(scf_true_base_type(prop
->pv_type
) ==
2683 size
= scf_value_get_astring(v
, NULL
, 0);
2688 if ((s
= malloc(++size
)) == NULL
) {
2689 error
= SCF_ERROR_NO_MEMORY
;
2692 ret
= scf_value_get_astring(v
, s
, size
);
2693 *(char **)prop
->pv_ptr
= s
;
2707 error
= scf_error();
2708 scf_clean_propvec(properties
);
2712 scf_snapshot_destroy(snap
);
2713 scf_instance_destroy(i
);
2714 scf_service_destroy(s
);
2715 scf_handle_destroy(h
);
2718 (void) scf_set_error(error
);
2719 return (SCF_FAILED
);
2722 return (SCF_SUCCESS
);
2726 * Writes a vector of properties to the specified fmri/property group.
2728 * If this function fails to write a specific property, *badprop is set
2729 * to point at that property's entry in the properties array.
2731 * One significant difference between this function and the
2732 * scf_read_propvec function is that for string types, pv_ptr is a
2733 * char *, not a char **. This means that you can't write a propvec
2734 * you just read, but makes other uses (hopefully the majority) simpler.
2737 scf_write_propvec(const char *fmri
, const char *pgname
,
2738 scf_propvec_t
*properties
, scf_propvec_t
**badprop
)
2740 scf_handle_t
*h
= handle_create();
2741 scf_service_t
*s
= scf_service_create(h
);
2742 scf_instance_t
*inst
= scf_instance_create(h
);
2743 scf_snapshot_t
*snap
= scf_snapshot_create(h
);
2744 scf_propertygroup_t
*pg
= scf_pg_create(h
);
2745 scf_property_t
*p
= scf_property_create(h
);
2746 scf_transaction_t
*tx
= scf_transaction_create(h
);
2747 scf_value_t
**v
= NULL
;
2748 scf_transaction_entry_t
**e
= NULL
;
2749 boolean_t instance
= B_TRUE
;
2751 scf_propvec_t
*prop
;
2754 n
= count_props(properties
);
2755 v
= calloc(n
, sizeof (scf_value_t
*));
2756 e
= calloc(n
, sizeof (scf_transaction_entry_t
*));
2758 if (v
== NULL
|| e
== NULL
) {
2759 error
= SCF_ERROR_NO_MEMORY
;
2763 if (h
== NULL
|| s
== NULL
|| inst
== NULL
|| pg
== NULL
|| p
== NULL
||
2767 for (i
= 0; i
< n
; i
++) {
2768 v
[i
] = scf_value_create(h
);
2769 e
[i
] = scf_entry_create(h
);
2770 if (v
[i
] == NULL
|| e
[i
] == NULL
)
2774 if (scf_handle_decode_fmri(h
, fmri
, NULL
, s
, inst
, NULL
, NULL
, 0)
2778 if (scf_instance_to_fmri(inst
, NULL
, 0) == -1) {
2779 if (scf_error() != SCF_ERROR_NOT_SET
)
2784 if ((instance
? scf_instance_get_pg(inst
, pgname
, pg
) :
2785 scf_service_get_pg(s
, pgname
, pg
)) == -1)
2789 if (scf_transaction_start(tx
, pg
) == -1)
2792 for (prop
= properties
, i
= 0; prop
->pv_prop
!= NULL
; prop
++, i
++) {
2793 ret
= scf_transaction_property_change(tx
, e
[i
], prop
->pv_prop
,
2795 if (ret
== -1 && scf_error() == SCF_ERROR_NOT_FOUND
)
2796 ret
= scf_transaction_property_new(tx
, e
[i
],
2797 prop
->pv_prop
, prop
->pv_type
);
2804 switch (prop
->pv_type
) {
2805 case SCF_TYPE_BOOLEAN
: {
2806 boolean_t b
= (prop
->pv_aux
!= 0) ?
2807 (*(uint64_t *)prop
->pv_ptr
& prop
->pv_aux
) != 0 :
2808 *(boolean_t
*)prop
->pv_ptr
;
2810 scf_value_set_boolean(v
[i
], b
? 1 : 0);
2813 case SCF_TYPE_COUNT
:
2814 scf_value_set_count(v
[i
], *(uint64_t *)prop
->pv_ptr
);
2816 case SCF_TYPE_INTEGER
:
2817 scf_value_set_integer(v
[i
], *(int64_t *)prop
->pv_ptr
);
2819 case SCF_TYPE_TIME
: {
2820 scf_time_t
*time
= prop
->pv_ptr
;
2822 ret
= scf_value_set_time(v
[i
], time
->t_seconds
,
2826 case SCF_TYPE_OPAQUE
: {
2827 scf_opaque_t
*opaque
= prop
->pv_ptr
;
2829 ret
= scf_value_set_opaque(v
[i
], opaque
->so_addr
,
2833 case SCF_TYPE_ASTRING
:
2834 ret
= scf_value_set_astring(v
[i
],
2835 (const char *)prop
->pv_ptr
);
2838 ret
= scf_value_set_from_string(v
[i
], prop
->pv_type
,
2839 (const char *)prop
->pv_ptr
);
2842 if (ret
== -1 || scf_entry_add_value(e
[i
], v
[i
]) == -1) {
2848 ret
= scf_transaction_commit(tx
);
2852 if (ret
== 0 && scf_pg_update(pg
) != -1) {
2853 scf_transaction_reset(tx
);
2858 error
= scf_error();
2862 for (i
= 0; i
< n
; i
++)
2863 scf_value_destroy(v
[i
]);
2868 for (i
= 0; i
< n
; i
++)
2869 scf_entry_destroy(e
[i
]);
2873 scf_transaction_destroy(tx
);
2874 scf_property_destroy(p
);
2876 scf_snapshot_destroy(snap
);
2877 scf_instance_destroy(inst
);
2878 scf_service_destroy(s
);
2879 scf_handle_destroy(h
);
2882 (void) scf_set_error(error
);
2883 return (SCF_FAILED
);
2886 return (SCF_SUCCESS
);
2892 * ECONNABORTED - repository connection broken
2893 * ECANCELED - inst was deleted
2900 scf_instance_delete_prop(scf_instance_t
*inst
, const char *pgname
,
2904 scf_propertygroup_t
*pg
;
2905 scf_transaction_t
*tx
;
2906 scf_transaction_entry_t
*e
;
2907 int error
= 0, ret
= 1, r
;
2909 h
= scf_instance_handle(inst
);
2911 if ((pg
= scf_pg_create(h
)) == NULL
) {
2915 if (scf_instance_get_pg(inst
, pgname
, pg
) != 0) {
2916 error
= scf_error();
2919 case SCF_ERROR_NOT_FOUND
:
2920 return (SCF_SUCCESS
);
2922 case SCF_ERROR_DELETED
:
2925 case SCF_ERROR_CONNECTION_BROKEN
:
2927 return (ECONNABORTED
);
2929 case SCF_ERROR_NOT_SET
:
2930 bad_error("scf_instance_get_pg", scf_error());
2934 tx
= scf_transaction_create(h
);
2935 e
= scf_entry_create(h
);
2936 if (tx
== NULL
|| e
== NULL
) {
2942 if (scf_transaction_start(tx
, pg
) != 0) {
2946 if (scf_transaction_property_delete(tx
, e
, pname
) != 0) {
2950 if ((r
= scf_transaction_commit(tx
)) == 1) {
2959 scf_transaction_reset(tx
);
2960 if (scf_pg_update(pg
) == -1) {
2966 switch (scf_error()) {
2967 case SCF_ERROR_DELETED
:
2968 case SCF_ERROR_NOT_FOUND
:
2972 case SCF_ERROR_PERMISSION_DENIED
:
2976 case SCF_ERROR_BACKEND_ACCESS
:
2980 case SCF_ERROR_BACKEND_READONLY
:
2984 case SCF_ERROR_CONNECTION_BROKEN
:
2989 case SCF_ERROR_HANDLE_MISMATCH
:
2990 case SCF_ERROR_INVALID_ARGUMENT
:
2991 case SCF_ERROR_NOT_BOUND
:
2992 case SCF_ERROR_NOT_SET
:
2993 bad_error("scf_instance_delete_prop", scf_error());
2997 scf_transaction_destroy(tx
);
2998 scf_entry_destroy(e
);