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.
34 #include <libscf_priv.h>
39 * Internal representation manipulation routines for svccfg(1)
42 static uu_list_pool_t
*entity_pool
;
43 static uu_list_pool_t
*pgroup_pool
;
44 static uu_list_pool_t
*property_pool
;
45 static uu_list_pool_t
*value_pool
;
49 entity_cmp(const void *a
, const void *b
, void *p
)
51 entity_t
*A
= (entity_t
*)a
;
52 entity_t
*B
= (entity_t
*)b
;
54 return (strcmp(A
->sc_name
, B
->sc_name
));
59 pgroup_cmp(const void *a
, const void *b
, void *p
)
61 pgroup_t
*A
= (pgroup_t
*)a
;
62 pgroup_t
*B
= (pgroup_t
*)b
;
64 return (strcmp(A
->sc_pgroup_name
, B
->sc_pgroup_name
));
69 property_cmp(const void *a
, const void *b
, void *p
)
71 property_t
*A
= (property_t
*)a
;
72 property_t
*B
= (property_t
*)b
;
74 return (strcmp(A
->sc_property_name
, B
->sc_property_name
));
79 value_cmp(const void *a
, const void *b
, void *p
)
84 if (A
->sc_type
!= B
->sc_type
)
85 return (B
->sc_type
- A
->sc_type
);
88 case SCF_TYPE_BOOLEAN
:
90 return (B
->sc_u
.sc_count
- A
->sc_u
.sc_count
);
92 case SCF_TYPE_INTEGER
:
93 return (B
->sc_u
.sc_integer
- A
->sc_u
.sc_integer
);
96 return (strcmp(A
->sc_u
.sc_string
, B
->sc_u
.sc_string
));
103 if ((entity_pool
= uu_list_pool_create("entities", sizeof (entity_t
),
104 offsetof(entity_t
, sc_node
), entity_cmp
, 0)) == NULL
)
105 uu_die(gettext("entity list pool creation failed: %s\n"),
106 uu_strerror(uu_error()));
108 if ((pgroup_pool
= uu_list_pool_create("property_groups",
109 sizeof (pgroup_t
), offsetof(pgroup_t
, sc_node
), pgroup_cmp
, 0)) ==
112 gettext("property group list pool creation failed: %s\n"),
113 uu_strerror(uu_error()));
115 if ((property_pool
= uu_list_pool_create("properties",
116 sizeof (property_t
), offsetof(property_t
, sc_node
), property_cmp
,
118 uu_die(gettext("property list pool creation failed: %s\n"),
119 uu_strerror(uu_error()));
121 if ((value_pool
= uu_list_pool_create("property_values",
122 sizeof (value_t
), offsetof(value_t
, sc_node
), value_cmp
, 0)) ==
125 gettext("property value list pool creation failed: %s\n"),
126 uu_strerror(uu_error()));
131 internal_value_dump(void *v
, void *pvt
)
135 switch (val
->sc_type
) {
136 case SCF_TYPE_BOOLEAN
:
137 (void) printf(" value = %s\n",
138 val
->sc_u
.sc_count
? "true" : "false");
141 (void) printf(" value = %llu\n", val
->sc_u
.sc_count
);
143 case SCF_TYPE_INTEGER
:
144 (void) printf(" value = %lld\n", val
->sc_u
.sc_integer
);
146 case SCF_TYPE_ASTRING
:
149 case SCF_TYPE_HOSTNAME
:
150 case SCF_TYPE_NET_ADDR_V4
:
151 case SCF_TYPE_NET_ADDR_V6
:
152 case SCF_TYPE_OPAQUE
:
155 case SCF_TYPE_USTRING
:
156 (void) printf(" value = %s\n",
157 val
->sc_u
.sc_string
? val
->sc_u
.sc_string
: "(nil)");
160 uu_die(gettext("unknown value type (%d)\n"), val
->sc_type
);
164 return (UU_WALK_NEXT
);
169 internal_property_dump(void *v
, void *pvt
)
173 (void) printf("property\n name = %s\n", p
->sc_property_name
);
174 (void) printf(" type = %d\n", p
->sc_value_type
);
176 (void) uu_list_walk(p
->sc_property_values
, internal_value_dump
,
179 return (UU_WALK_NEXT
);
184 internal_pgroup_dump(void *v
, void *pvt
)
188 (void) printf("pgroup name = %s\n", pg
->sc_pgroup_name
);
189 (void) printf(" type = %s\n", pg
->sc_pgroup_type
);
191 (void) uu_list_walk(pg
->sc_pgroup_props
, internal_property_dump
,
194 return (UU_WALK_NEXT
);
199 internal_instance_dump(void *v
, void *pvt
)
203 (void) printf("instance name = %s\n", i
->sc_name
);
205 (void) uu_list_walk(i
->sc_pgroups
, internal_pgroup_dump
, NULL
,
208 return (UU_WALK_NEXT
);
213 internal_service_dump(void *v
, void *pvt
)
217 (void) printf("service name = %s\n", s
->sc_name
);
218 (void) printf(" type = %x\n", s
->sc_u
.sc_service
.sc_service_type
);
219 (void) printf(" version = %u\n", s
->sc_u
.sc_service
.sc_service_version
);
221 (void) uu_list_walk(s
->sc_pgroups
, internal_pgroup_dump
, NULL
,
224 (void) uu_list_walk(s
->sc_u
.sc_service
.sc_service_instances
,
225 internal_instance_dump
, NULL
, UU_DEFAULT
);
227 return (UU_WALK_NEXT
);
231 internal_dump(bundle_t
*b
)
233 (void) printf("bundle name = %s\n", b
->sc_bundle_name
);
234 (void) printf(" type = %x\n", b
->sc_bundle_type
);
236 (void) uu_list_walk(b
->sc_bundle_services
, internal_service_dump
,
241 internal_bundle_new()
245 if ((b
= uu_zalloc(sizeof (bundle_t
))) == NULL
)
246 uu_die(gettext("couldn't allocate memory"));
248 b
->sc_bundle_type
= SVCCFG_UNKNOWN_BUNDLE
;
249 b
->sc_bundle_services
= uu_list_create(entity_pool
, b
, 0);
250 if (b
->sc_bundle_services
== NULL
) {
251 uu_die(gettext("Unable to create list for bundle services. "
252 "%s\n"), uu_strerror(uu_error()));
259 internal_bundle_free(bundle_t
*b
)
264 while ((service
= uu_list_teardown(b
->sc_bundle_services
, &cookie
)) !=
266 internal_service_free(service
);
272 internal_entity_new(entity_type_t entity
)
276 if ((e
= uu_zalloc(sizeof (entity_t
))) == NULL
)
277 uu_die(gettext("couldn't allocate memory"));
279 uu_list_node_init(e
, &e
->sc_node
, entity_pool
);
281 e
->sc_etype
= entity
;
282 e
->sc_pgroups
= uu_list_create(pgroup_pool
, e
, 0);
283 e
->sc_op
= SVCCFG_OP_NONE
;
284 if (e
->sc_pgroups
== NULL
) {
285 uu_die(gettext("Unable to create list for entity property "
286 "groups. %s\n"), uu_strerror(uu_error()));
293 internal_service_new(const char *name
)
297 s
= internal_entity_new(SVCCFG_SERVICE_OBJECT
);
300 s
->sc_fmri
= uu_msprintf("svc:/%s", name
);
301 if (s
->sc_fmri
== NULL
)
302 uu_die(gettext("couldn't allocate memory"));
304 s
->sc_dependents
= uu_list_create(pgroup_pool
, s
, 0);
305 if (s
->sc_dependents
== NULL
) {
306 uu_die(gettext("Unable to create list for service dependents. "
307 "%s\n"), uu_strerror(uu_error()));
310 s
->sc_u
.sc_service
.sc_service_type
= SVCCFG_UNKNOWN_SERVICE
;
311 s
->sc_u
.sc_service
.sc_service_instances
= uu_list_create(entity_pool
, s
,
313 if (s
->sc_u
.sc_service
.sc_service_instances
== NULL
) {
314 uu_die(gettext("Unable to create list for service instances. "
315 "%s\n"), uu_strerror(uu_error()));
322 internal_service_free(entity_t
*s
)
328 if (s
->sc_u
.sc_service
.sc_restarter
!= NULL
)
329 internal_instance_free(s
->sc_u
.sc_service
.sc_restarter
);
330 if (s
->sc_u
.sc_service
.sc_global
!= NULL
)
331 internal_instance_free(s
->sc_u
.sc_service
.sc_global
);
334 while ((pg
= uu_list_teardown(s
->sc_pgroups
, &cookie
)) != NULL
)
335 internal_pgroup_free(pg
);
338 while ((pg
= uu_list_teardown(s
->sc_dependents
, &cookie
)) != NULL
)
339 internal_pgroup_free(pg
);
342 while ((inst
= uu_list_teardown(s
->sc_u
.sc_service
.sc_service_instances
,
344 internal_instance_free(inst
);
345 uu_free((void *)s
->sc_fmri
);
351 internal_instance_new(const char *name
)
355 i
= internal_entity_new(SVCCFG_INSTANCE_OBJECT
);
357 /* Can't set i->sc_fmri until we're attached to a service. */
358 i
->sc_dependents
= uu_list_create(pgroup_pool
, i
, 0);
359 if (i
->sc_dependents
== NULL
) {
360 uu_die(gettext("Unable to create list for instance "
361 "dependents. %s\n"), uu_strerror(uu_error()));
368 internal_instance_free(entity_t
*i
)
374 rs
= i
->sc_u
.sc_instance
.sc_instance_restarter
;
376 internal_instance_free(rs
);
377 while ((pg
= uu_list_teardown(i
->sc_pgroups
, &cookie
)) != NULL
)
378 internal_pgroup_free(pg
);
381 while ((pg
= uu_list_teardown(i
->sc_dependents
, &cookie
)) != NULL
)
382 internal_pgroup_free(pg
);
383 uu_free((void *)i
->sc_fmri
);
389 internal_pgroup_new()
393 if ((p
= uu_zalloc(sizeof (pgroup_t
))) == NULL
)
394 uu_die(gettext("couldn't allocate memory"));
396 uu_list_node_init(p
, &p
->sc_node
, pgroup_pool
);
398 p
->sc_pgroup_props
= uu_list_create(property_pool
, p
, UU_LIST_SORTED
);
399 if (p
->sc_pgroup_props
== NULL
) {
400 uu_die(gettext("Unable to create list for properties. %s\n"),
401 uu_strerror(uu_error()));
403 p
->sc_pgroup_name
= "<unset>";
404 p
->sc_pgroup_type
= "<unset>";
410 internal_pgroup_free(pgroup_t
*pg
)
416 * Templates validation code should clean up this reference when
417 * the validation is finished.
419 assert(pg
->sc_pgroup_composed
== NULL
);
421 while ((prop
= uu_list_teardown(pg
->sc_pgroup_props
, &cookie
)) != NULL
)
422 internal_property_free(prop
);
428 find_pgroup(uu_list_t
*list
, const char *name
, const char *type
)
432 for (pg
= uu_list_first(list
);
434 pg
= uu_list_next(list
, pg
)) {
435 if (strcmp(pg
->sc_pgroup_name
, name
) != 0)
441 if (strcmp(pg
->sc_pgroup_type
, type
) == 0)
449 internal_dependent_find(entity_t
*e
, const char *name
)
451 return (find_pgroup(e
->sc_dependents
, name
, NULL
));
455 internal_pgroup_find(entity_t
*e
, const char *name
, const char *type
)
457 return (find_pgroup(e
->sc_pgroups
, name
, type
));
461 internal_pgroup_create_common(entity_t
*e
, const char *name
, const char *type
,
466 pg
= internal_pgroup_find(e
, name
, type
);
468 if (unique
== B_TRUE
) {
475 pg
= internal_pgroup_new();
476 (void) internal_attach_pgroup(e
, pg
);
477 pg
->sc_pgroup_name
= strdup(name
);
478 pg
->sc_pgroup_flags
= 0;
480 pg
->sc_pgroup_type
= strdup(type
);
482 est
->sc_miss_type
= B_TRUE
;
483 pg
->sc_pgroup_type
= NULL
;
486 if (pg
->sc_pgroup_name
== NULL
||
487 (e
->sc_op
!= SVCCFG_OP_APPLY
&& pg
->sc_pgroup_type
== NULL
))
488 uu_die(gettext("Could not duplicate string"));
494 internal_pgroup_find_or_create(entity_t
*e
, const char *name
, const char *type
)
496 return (internal_pgroup_create_common(e
, name
, type
, B_FALSE
));
500 internal_pgroup_create_strict(entity_t
*e
, const char *name
, const char *type
)
502 return (internal_pgroup_create_common(e
, name
, type
, B_TRUE
));
506 internal_property_new()
510 if ((p
= uu_zalloc(sizeof (property_t
))) == NULL
)
511 uu_die(gettext("couldn't allocate memory"));
513 uu_list_node_init(p
, &p
->sc_node
, property_pool
);
515 p
->sc_property_values
= uu_list_create(value_pool
, p
, 0);
516 if (p
->sc_property_values
== NULL
) {
517 uu_die(gettext("Unable to create list for property values. "
518 "%s\n"), uu_strerror(uu_error()));
520 p
->sc_property_name
= "<unset>";
522 tmpl_property_init(p
);
528 internal_property_free(property_t
*p
)
533 tmpl_property_fini(p
);
535 while ((val
= uu_list_teardown(p
->sc_property_values
, &cookie
)) !=
537 if (val
->sc_free
!= NULL
)
546 internal_property_find(pgroup_t
*pg
, const char *name
)
550 for (p
= uu_list_first(pg
->sc_pgroup_props
);
552 p
= uu_list_next(pg
->sc_pgroup_props
, p
))
553 if (strcmp(p
->sc_property_name
, name
) == 0)
564 if ((v
= uu_zalloc(sizeof (value_t
))) == NULL
)
565 uu_die(gettext("couldn't allocate memory"));
567 uu_list_node_init(v
, &v
->sc_node
, value_pool
);
573 internal_value_free_str(value_t
*v
)
575 free(v
->sc_u
.sc_string
);
579 internal_property_create(const char *name
, scf_type_t vtype
, uint_t nvals
, ...)
585 p
= internal_property_new();
587 p
->sc_property_name
= (char *)name
;
588 p
->sc_value_type
= vtype
;
590 va_start(args
, nvals
);
591 for (; nvals
> 0; nvals
--) {
593 v
= internal_value_new();
597 case SCF_TYPE_BOOLEAN
:
599 v
->sc_u
.sc_count
= va_arg(args
, uint64_t);
601 case SCF_TYPE_INTEGER
:
602 v
->sc_u
.sc_integer
= va_arg(args
, int64_t);
604 case SCF_TYPE_ASTRING
:
607 case SCF_TYPE_HOSTNAME
:
608 case SCF_TYPE_NET_ADDR_V4
:
609 case SCF_TYPE_NET_ADDR_V6
:
610 case SCF_TYPE_OPAQUE
:
613 case SCF_TYPE_USTRING
:
614 v
->sc_u
.sc_string
= (char *)va_arg(args
, uchar_t
*);
618 uu_die(gettext("unknown property type (%d)\n"), vtype
);
622 internal_attach_value(p
, v
);
630 * Some of these attach functions use uu_list_append() to maintain the
631 * same order across import/export, whereas others are always sorted
632 * anyway, or the order is irrelevant.
636 internal_attach_service(bundle_t
*bndl
, entity_t
*svc
)
638 if (uu_list_find(bndl
->sc_bundle_services
, svc
, NULL
, NULL
) != NULL
) {
639 semerr(gettext("Multiple definitions for service %s in "
640 "bundle %s.\n"), svc
->sc_name
, bndl
->sc_bundle_name
);
644 (void) uu_list_append(bndl
->sc_bundle_services
, svc
);
650 internal_attach_entity(entity_t
*svc
, entity_t
*ent
)
652 if (svc
->sc_etype
!= SVCCFG_SERVICE_OBJECT
)
653 uu_die(gettext("bad entity attach: %s is not a service\n"),
656 if (uu_list_find(svc
->sc_u
.sc_service
.sc_service_instances
, ent
, NULL
,
658 semerr(gettext("Multiple definitions of entity %s in service "
659 "%s.\n"), ent
->sc_name
, svc
->sc_name
);
663 (void) uu_list_prepend(svc
->sc_u
.sc_service
.sc_service_instances
, ent
);
664 ent
->sc_parent
= svc
;
665 ent
->sc_op
= svc
->sc_op
;
666 ent
->sc_fmri
= uu_msprintf("%s:%s", svc
->sc_fmri
, ent
->sc_name
);
667 if (ent
->sc_fmri
== NULL
)
668 uu_die(gettext("couldn't allocate memory"));
674 internal_attach_pgroup(entity_t
*ent
, pgroup_t
*pgrp
)
676 if (uu_list_find(ent
->sc_pgroups
, pgrp
, NULL
, NULL
) != NULL
) {
677 semerr(gettext("Multiple definitions of property group %s in "
678 "entity %s.\n"), pgrp
->sc_pgroup_name
, ent
->sc_name
);
682 (void) uu_list_append(ent
->sc_pgroups
, pgrp
);
684 pgrp
->sc_parent
= ent
;
690 internal_detach_pgroup(entity_t
*ent
, pgroup_t
*pgrp
)
692 uu_list_remove(ent
->sc_pgroups
, pgrp
);
696 internal_attach_dependent(entity_t
*ent
, pgroup_t
*pg
)
698 if (uu_list_find(ent
->sc_dependents
, pg
, NULL
, NULL
) != NULL
) {
699 semerr(gettext("Multiple definitions of dependent %s in "
700 "entity %s.\n"), pg
->sc_pgroup_name
, ent
->sc_name
);
704 (void) uu_list_append(ent
->sc_dependents
, pg
);
714 * -1 - prop already exists in pgrp
717 internal_attach_property(pgroup_t
*pgrp
, property_t
*prop
)
721 if (uu_list_find(pgrp
->sc_pgroup_props
, prop
, NULL
, &idx
) != NULL
) {
722 semerr(gettext("Multiple definitions for property %s in "
723 "property group %s.\n"), prop
->sc_property_name
,
724 pgrp
->sc_pgroup_name
);
728 uu_list_insert(pgrp
->sc_pgroup_props
, prop
, idx
);
734 internal_detach_property(pgroup_t
*pgrp
, property_t
*prop
)
736 uu_list_remove(pgrp
->sc_pgroup_props
, prop
);
740 internal_attach_value(property_t
*prop
, value_t
*val
)
742 (void) uu_list_append(prop
->sc_property_values
, val
);
746 * These functions create an internal representation of a property group
747 * (pgroup_t) from the repository (scf_propertygroup_t). They are used by the
748 * import functions in svccfg_libscf.c .
750 * load_init() must be called first to initialize these globals, and
751 * load_fini() should be called afterwards to destroy them.
754 static char *loadbuf
= NULL
;
755 static size_t loadbuf_sz
;
756 static scf_propertygroup_t
*load_pgroup
= NULL
;
757 static scf_property_t
*load_prop
= NULL
;
758 static scf_value_t
*load_val
= NULL
;
759 static scf_iter_t
*load_propiter
= NULL
, *load_valiter
= NULL
;
760 static scf_iter_t
*load_pgiter
= NULL
;
763 * Initialize the global state for the load_*() routines.
766 * ENOMEM - out of memory
771 loadbuf_sz
= ((max_scf_value_len
> max_scf_pg_type_len
) ?
772 max_scf_value_len
: max_scf_pg_type_len
) + 1;
774 loadbuf
= malloc(loadbuf_sz
);
778 if ((load_prop
= scf_property_create(g_hndl
)) == NULL
||
779 (load_val
= scf_value_create(g_hndl
)) == NULL
||
780 (load_pgroup
= scf_pg_create(g_hndl
)) == NULL
||
781 (load_pgiter
= scf_iter_create(g_hndl
)) == NULL
||
782 (load_propiter
= scf_iter_create(g_hndl
)) == NULL
||
783 (load_valiter
= scf_iter_create(g_hndl
)) == NULL
) {
794 scf_iter_destroy(load_propiter
);
795 load_propiter
= NULL
;
796 scf_iter_destroy(load_valiter
);
798 scf_iter_destroy(load_pgiter
);
800 scf_pg_destroy(load_pgroup
);
802 scf_value_destroy(load_val
);
804 scf_property_destroy(load_prop
);
811 * Create a property_t which represents an scf_property_t. Returns
813 * ECANCELED - prop's pg was deleted
814 * ECONNABORTED - repository disconnected
815 * ENOMEM - out of memory
816 * EACCES - permission denied when reading property
819 load_property(scf_property_t
*prop
, property_t
**ipp
)
826 if (scf_property_get_name(prop
, loadbuf
, loadbuf_sz
) < 0) {
827 switch (scf_error()) {
828 case SCF_ERROR_DELETED
:
831 case SCF_ERROR_CONNECTION_BROKEN
:
832 return (ECONNABORTED
);
834 case SCF_ERROR_NOT_BOUND
:
835 case SCF_ERROR_NOT_SET
:
837 bad_error("scf_property_get_name", scf_error());
841 iprop
= internal_property_new();
842 iprop
->sc_property_name
= strdup(loadbuf
);
843 if (iprop
->sc_property_name
== NULL
) {
844 internal_property_free(iprop
);
849 if (scf_property_type(prop
, &iprop
->sc_value_type
) != 0) {
850 switch (scf_error()) {
851 case SCF_ERROR_DELETED
:
855 case SCF_ERROR_CONNECTION_BROKEN
:
859 case SCF_ERROR_NOT_BOUND
:
860 case SCF_ERROR_NOT_SET
:
862 bad_error("scf_property_type", scf_error());
867 if (scf_iter_property_values(load_valiter
, prop
) != 0) {
868 switch (scf_error()) {
869 case SCF_ERROR_DELETED
:
873 case SCF_ERROR_CONNECTION_BROKEN
:
877 case SCF_ERROR_HANDLE_MISMATCH
:
878 case SCF_ERROR_NOT_BOUND
:
879 case SCF_ERROR_NOT_SET
:
881 bad_error("scf_iter_property_values", scf_error());
888 r
= scf_iter_next_value(load_valiter
, load_val
);
892 switch (scf_error()) {
893 case SCF_ERROR_DELETED
:
897 case SCF_ERROR_CONNECTION_BROKEN
:
901 case SCF_ERROR_PERMISSION_DENIED
:
905 case SCF_ERROR_HANDLE_MISMATCH
:
906 case SCF_ERROR_NOT_BOUND
:
907 case SCF_ERROR_NOT_SET
:
908 case SCF_ERROR_INVALID_ARGUMENT
:
910 bad_error("scf_iter_next_value", scf_error());
914 ival
= internal_value_new();
915 ival
->sc_type
= scf_value_type(load_val
);
916 assert(ival
->sc_type
!= SCF_TYPE_INVALID
);
918 switch (ival
->sc_type
) {
919 case SCF_TYPE_BOOLEAN
: {
922 r
= scf_value_get_boolean(load_val
, &b
);
924 bad_error("scf_value_get_boolean", scf_error());
925 ival
->sc_u
.sc_count
= b
;
930 r
= scf_value_get_count(load_val
, &ival
->sc_u
.sc_count
);
932 bad_error("scf_value_get_count", scf_error());
935 case SCF_TYPE_INTEGER
:
936 r
= scf_value_get_integer(load_val
,
937 &ival
->sc_u
.sc_integer
);
939 bad_error("scf_value_get_integer", scf_error());
943 ssz
= scf_value_get_as_string(load_val
, loadbuf
,
946 bad_error("scf_value_get_as_string",
949 ival
->sc_u
.sc_string
= strdup(loadbuf
);
950 if (ival
->sc_u
.sc_string
== NULL
) {
955 ival
->sc_free
= internal_value_free_str
;
958 internal_attach_value(iprop
, ival
);
965 free(iprop
->sc_property_name
);
966 internal_property_free(iprop
);
973 * ECANCELED - pg was deleted
974 * ECONNABORTED - repository disconnected
975 * ENOMEM - out of memory
978 load_pg_attrs(const scf_propertygroup_t
*pg
, pgroup_t
**ipgp
)
982 ipg
= internal_pgroup_new();
984 if (scf_pg_get_flags(pg
, &ipg
->sc_pgroup_flags
) != 0) {
985 switch (scf_error()) {
986 case SCF_ERROR_DELETED
:
987 internal_pgroup_free(ipg
);
990 case SCF_ERROR_CONNECTION_BROKEN
:
991 internal_pgroup_free(ipg
);
992 return (ECONNABORTED
);
994 case SCF_ERROR_NOT_SET
:
995 case SCF_ERROR_NOT_BOUND
:
997 bad_error("scf_pg_get_name", scf_error());
1001 if (scf_pg_get_name(pg
, loadbuf
, loadbuf_sz
) < 0) {
1002 switch (scf_error()) {
1003 case SCF_ERROR_DELETED
:
1004 internal_pgroup_free(ipg
);
1007 case SCF_ERROR_CONNECTION_BROKEN
:
1008 internal_pgroup_free(ipg
);
1009 return (ECONNABORTED
);
1011 case SCF_ERROR_NOT_SET
:
1012 case SCF_ERROR_NOT_BOUND
:
1014 bad_error("scf_pg_get_name", scf_error());
1018 ipg
->sc_pgroup_name
= strdup(loadbuf
);
1019 if (ipg
->sc_pgroup_name
== NULL
) {
1020 internal_pgroup_free(ipg
);
1024 if (scf_pg_get_type(pg
, loadbuf
, loadbuf_sz
) < 0) {
1025 switch (scf_error()) {
1026 case SCF_ERROR_DELETED
:
1027 free((char *)ipg
->sc_pgroup_name
);
1028 internal_pgroup_free(ipg
);
1031 case SCF_ERROR_CONNECTION_BROKEN
:
1032 free((char *)ipg
->sc_pgroup_name
);
1033 internal_pgroup_free(ipg
);
1034 return (ECONNABORTED
);
1036 case SCF_ERROR_NOT_SET
:
1037 case SCF_ERROR_NOT_BOUND
:
1039 bad_error("scf_pg_get_name", scf_error());
1043 ipg
->sc_pgroup_type
= strdup(loadbuf
);
1044 if (ipg
->sc_pgroup_type
== NULL
) {
1045 free((char *)ipg
->sc_pgroup_name
);
1046 internal_pgroup_free(ipg
);
1055 * Load a property group into a pgroup_t. Returns
1057 * ECANCELED - pg was deleted
1058 * ECONNABORTED - repository disconnected
1059 * EBADF - pg is corrupt (error printed if fmri is given)
1060 * ENOMEM - out of memory
1061 * EACCES - permission denied when reading property
1064 load_pg(const scf_propertygroup_t
*pg
, pgroup_t
**ipgp
, const char *fmri
,
1065 const char *snapname
)
1070 if (scf_iter_pg_properties(load_propiter
, pg
) != 0) {
1071 switch (scf_error()) {
1072 case SCF_ERROR_DELETED
:
1075 case SCF_ERROR_CONNECTION_BROKEN
:
1076 return (ECONNABORTED
);
1078 case SCF_ERROR_HANDLE_MISMATCH
:
1079 case SCF_ERROR_NOT_SET
:
1080 case SCF_ERROR_NOT_BOUND
:
1082 bad_error("scf_iter_pg_properties", scf_error());
1086 r
= load_pg_attrs(pg
, &ipg
);
1097 bad_error("load_pg_attrs", r
);
1103 r
= scf_iter_next_property(load_propiter
, load_prop
);
1107 switch (scf_error()) {
1108 case SCF_ERROR_DELETED
:
1112 case SCF_ERROR_CONNECTION_BROKEN
:
1116 case SCF_ERROR_HANDLE_MISMATCH
:
1117 case SCF_ERROR_NOT_BOUND
:
1118 case SCF_ERROR_NOT_SET
:
1119 case SCF_ERROR_INVALID_ARGUMENT
:
1121 bad_error("scf_iter_next_property",
1126 r
= load_property(load_prop
, &iprop
);
1138 bad_error("load_property", r
);
1141 r
= internal_attach_property(ipg
, iprop
);
1144 if (snapname
== NULL
)
1145 warn(gettext("Property group \"%s\" of "
1146 "%s has multiple definitions of "
1147 "property \"%s\".\n"),
1148 ipg
->sc_pgroup_name
, fmri
,
1149 iprop
->sc_property_name
);
1151 warn(gettext("Property group \"%s\" of "
1152 "the \"%s\" snapshot of %s has "
1153 "multiple definitions of property "
1155 ipg
->sc_pgroup_name
, snapname
, fmri
,
1156 iprop
->sc_property_name
);
1167 internal_pgroup_free(ipg
);
1172 * Load the instance for fmri from the repository into memory. The
1173 * property groups that define the instances pg_patterns and prop_patterns
1176 * Returns 0 on success and non-zero on failure.
1179 load_instance(const char *fmri
, const char *name
, entity_t
**inst_ptr
)
1182 scf_instance_t
*inst
;
1188 assert(inst_ptr
!= NULL
);
1190 if ((inst
= scf_instance_create(g_hndl
)) == NULL
) {
1191 switch (scf_error()) {
1192 case SCF_ERROR_NO_MEMORY
:
1193 case SCF_ERROR_NO_RESOURCES
:
1197 bad_error("scf_instance_create", scf_error());
1200 if (scf_handle_decode_fmri(g_hndl
, fmri
, NULL
, NULL
, inst
, NULL
, NULL
,
1201 SCF_DECODE_FMRI_EXACT
|SCF_DECODE_FMRI_REQUIRE_INSTANCE
) != 0) {
1202 switch (scf_error()) {
1203 case SCF_ERROR_CONNECTION_BROKEN
:
1206 case SCF_ERROR_DELETED
:
1207 case SCF_ERROR_NOT_FOUND
:
1210 case SCF_ERROR_INVALID_ARGUMENT
:
1213 case SCF_ERROR_CONSTRAINT_VIOLATED
:
1217 bad_error("scf_handle_decode_fmri", scf_error());
1220 if (scf_iter_instance_pgs_composed(load_pgiter
, inst
, NULL
) != 0) {
1221 switch (scf_error()) {
1222 case SCF_ERROR_DELETED
:
1225 case SCF_ERROR_CONNECTION_BROKEN
:
1229 bad_error("scf_iter_instance_pgs_composed",
1234 tsize
= scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH
);
1235 type
= uu_zalloc(tsize
);
1242 * Initialize our entity structure.
1244 e
= internal_instance_new(name
);
1249 e
->sc_fmri
= uu_strdup(fmri
);
1250 if (e
->sc_fmri
== NULL
) {
1256 * Walk through the property group's of the instance and capture
1257 * the property groups that are of type
1258 * SCF_GROUP_TEMPLATE_PG_PATTERN and
1259 * SCF_GROUP_TEMPLATE_PROP_PATTERN. In other words grab the
1260 * pg_pattern and prop_pattern property groups.
1262 while ((rc
= scf_iter_next_pg(load_pgiter
, load_pgroup
)) == 1) {
1263 if (scf_pg_get_type(load_pgroup
, type
, tsize
) <= 0) {
1264 switch (scf_error()) {
1265 case SCF_ERROR_DELETED
:
1268 case SCF_ERROR_CONNECTION_BROKEN
:
1272 bad_error("scf_pg_get_type", scf_error());
1276 if ((strcmp(type
, SCF_GROUP_TEMPLATE_PG_PATTERN
) != 0) &&
1277 (strcmp(type
, SCF_GROUP_TEMPLATE_PROP_PATTERN
) != 0)) {
1280 if ((rc
= load_pg(load_pgroup
, &ipg
, fmri
, NULL
)) != 0) {
1288 bad_error("load_pg", rc
);
1292 if (internal_attach_pgroup(e
, ipg
) != 0) {
1298 /* Error in iteration. */
1299 switch (scf_error()) {
1300 case SCF_ERROR_CONNECTION_BROKEN
:
1303 case SCF_ERROR_DELETED
:
1306 case SCF_ERROR_NO_RESOURCES
:
1310 bad_error("scf_iter_next_pg", scf_error());
1316 scf_instance_destroy(inst
);
1323 scf_instance_destroy(inst
);
1325 internal_instance_free(e
);
1330 * These functions compare internal property groups and properties (pgroup_t
1331 * & property_t). They return 1 if the given structures are equal and
1332 * 0 otherwise. Some will report the differences between the two structures.
1333 * They are used by the import functions in svccfg_libscf.c .
1337 prop_equal(property_t
*p1
, property_t
*p2
, const char *fmri
, const char *pgname
,
1342 const char * const values_diff
= gettext("Conflict upgrading %s "
1343 "(property \"%s/%s\" has different values).\n");
1344 const char * const values_diff_new
= gettext("Conflict upgrading %s "
1345 "(new property \"%s/%s\" has different values).\n");
1347 assert((fmri
== NULL
) == (pgname
== NULL
));
1351 * If we find any differences, we'll report conflicts. But
1352 * conflict messages won't make any sense if the names don't
1353 * match. If the caller supplied fmri, assert that the names
1356 assert(strcmp(p1
->sc_property_name
, p2
->sc_property_name
) == 0);
1358 if (strcmp(p1
->sc_property_name
, p2
->sc_property_name
) != 0)
1362 if (p1
->sc_value_type
!= p2
->sc_value_type
) {
1365 warn(gettext("Conflict upgrading %s "
1366 "(new property \"%s/%s\" has different "
1367 "type).\n"), fmri
, pgname
,
1368 p1
->sc_property_name
);
1370 warn(gettext("Conflict upgrading %s "
1371 "(property \"%s/%s\" has different "
1372 "type).\n"), fmri
, pgname
,
1373 p1
->sc_property_name
);
1378 if (uu_list_numnodes(p1
->sc_property_values
) !=
1379 uu_list_numnodes(p2
->sc_property_values
)) {
1381 warn(new ? values_diff_new
: values_diff
, fmri
,
1382 pgname
, p1
->sc_property_name
);
1386 v1
= uu_list_first(p1
->sc_property_values
);
1387 v2
= uu_list_first(p2
->sc_property_values
);
1389 while (v1
!= NULL
) {
1392 if (value_cmp(v1
, v2
, NULL
) != 0) {
1394 warn(new ? values_diff_new
: values_diff
,
1395 fmri
, pgname
, p1
->sc_property_name
);
1399 v1
= uu_list_next(p1
->sc_property_values
, v1
);
1400 v2
= uu_list_next(p2
->sc_property_values
, v2
);
1407 pg_attrs_equal(const pgroup_t
*pg1
, const pgroup_t
*pg2
, const char *fmri
,
1410 if (strcmp(pg1
->sc_pgroup_name
, pg2
->sc_pgroup_name
) != 0) {
1411 assert(fmri
== NULL
);
1415 if (pg1
->sc_pgroup_flags
!= pg2
->sc_pgroup_flags
) {
1418 warn(gettext("Conflict upgrading %s "
1419 "(new property group \"%s\" has different "
1420 "flags).\n"), fmri
, pg1
->sc_pgroup_name
);
1422 warn(gettext("Conflict upgrading %s "
1423 "(property group \"%s\" has different "
1424 "flags).\n"), fmri
, pg1
->sc_pgroup_name
);
1429 if (strcmp(pg1
->sc_pgroup_type
, pg2
->sc_pgroup_type
) != 0) {
1432 warn(gettext("Conflict upgrading %s "
1433 "(new property group \"%s\" has different "
1434 "type).\n"), fmri
, pg1
->sc_pgroup_name
);
1436 warn(gettext("Conflict upgrading %s "
1437 "(property group \"%s\" has different "
1438 "type).\n"), fmri
, pg1
->sc_pgroup_name
);
1447 pg_equal(pgroup_t
*pg1
, pgroup_t
*pg2
)
1449 property_t
*p1
, *p2
;
1451 if (!pg_attrs_equal(pg1
, pg2
, NULL
, 0))
1454 if (uu_list_numnodes(pg1
->sc_pgroup_props
) !=
1455 uu_list_numnodes(pg2
->sc_pgroup_props
))
1458 p1
= uu_list_first(pg1
->sc_pgroup_props
);
1459 p2
= uu_list_first(pg2
->sc_pgroup_props
);
1461 while (p1
!= NULL
) {
1464 if (!prop_equal(p1
, p2
, NULL
, NULL
, 0))
1467 p1
= uu_list_next(pg1
->sc_pgroup_props
, p1
);
1468 p2
= uu_list_next(pg2
->sc_pgroup_props
, p2
);