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 (c) 2011, Joyent, Inc. All rights reserved.
28 * This is the main implementation file for the low-level repository
32 #include "lowlevel_impl.h"
34 #include "repcache_protocol.h"
52 #include <sys/sysmacros.h>
53 #include <libzonecfg.h>
57 #define ENV_SCF_DEBUG "LIBSCF_DEBUG"
58 #define ENV_SCF_DOORPATH "LIBSCF_DOORPATH"
60 static uint32_t default_debug
= 0;
61 static const char *default_door_path
= REPOSITORY_DOOR_NAME
;
63 #define CALL_FAILED -1
64 #define RESULT_TOO_BIG -2
67 static pthread_mutex_t lowlevel_init_lock
;
68 static int32_t lowlevel_inited
;
70 static uu_list_pool_t
*tran_entry_pool
;
71 static uu_list_pool_t
*datael_pool
;
72 static uu_list_pool_t
*iter_pool
;
75 * base32[] index32[] are used in base32 encoding and decoding.
77 static char base32
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
78 static char index32
[128] = {
79 -1, -1, -1, -1, -1, -1, -1, -1, /* 0-7 */
80 -1, -1, -1, -1, -1, -1, -1, -1, /* 8-15 */
81 -1, -1, -1, -1, -1, -1, -1, -1, /* 16-23 */
82 -1, -1, -1, -1, -1, -1, -1, -1, /* 24-31 */
83 -1, -1, -1, -1, -1, -1, -1, -1, /* 32-39 */
84 -1, -1, -1, -1, -1, -1, -1, -1, /* 40-47 */
85 -1, -1, 26, 27, 28, 29, 30, 31, /* 48-55 */
86 -1, -1, -1, -1, -1, -1, -1, -1, /* 56-63 */
87 -1, 0, 1, 2, 3, 4, 5, 6, /* 64-71 */
88 7, 8, 9, 10, 11, 12, 13, 14, /* 72-79 */
89 15, 16, 17, 18, 19, 20, 21, 22, /* 80-87 */
90 23, 24, 25, -1, -1, -1, -1, -1, /* 88-95 */
91 -1, -1, -1, -1, -1, -1, -1, -1, /* 96-103 */
92 -1, -1, -1, -1, -1, -1, -1, -1, /* 104-111 */
93 -1, -1, -1, -1, -1, -1, -1, -1, /* 112-119 */
94 -1, -1, -1, -1, -1, -1, -1, -1 /* 120-127 */
97 #define DECODE32_GS (8) /* scf_decode32 group size */
100 #define assert_nolint(x) (void)0
102 #define assert_nolint(x) assert(x)
105 static void scf_iter_reset_locked(scf_iter_t
*iter
);
106 static void scf_value_reset_locked(scf_value_t
*val
, int and_destroy
);
108 #define TYPE_VALUE (-100)
111 * Hold and release subhandles. We only allow one thread access to the
112 * subhandles at a time, and he can use any subset, grabbing and releasing
113 * them in any order. The only restrictions are that you cannot hold an
114 * already-held subhandle, and all subhandles must be released before
115 * returning to the original caller.
118 handle_hold_subhandles(scf_handle_t
*h
, int mask
)
120 assert(mask
!= 0 && (mask
& ~RH_HOLD_ALL
) == 0);
122 (void) pthread_mutex_lock(&h
->rh_lock
);
123 while (h
->rh_hold_flags
!= 0 && h
->rh_holder
!= pthread_self()) {
126 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
,
128 (void) pthread_cond_wait(&h
->rh_cv
, &h
->rh_lock
);
129 (void) pthread_setcancelstate(cancel_state
, NULL
);
131 if (h
->rh_hold_flags
== 0)
132 h
->rh_holder
= pthread_self();
133 assert(!(h
->rh_hold_flags
& mask
));
134 h
->rh_hold_flags
|= mask
;
135 (void) pthread_mutex_unlock(&h
->rh_lock
);
139 handle_rele_subhandles(scf_handle_t
*h
, int mask
)
141 assert(mask
!= 0 && (mask
& ~RH_HOLD_ALL
) == 0);
143 (void) pthread_mutex_lock(&h
->rh_lock
);
144 assert(h
->rh_holder
== pthread_self());
145 assert((h
->rh_hold_flags
& mask
));
147 h
->rh_hold_flags
&= ~mask
;
148 if (h
->rh_hold_flags
== 0)
149 (void) pthread_cond_signal(&h
->rh_cv
);
150 (void) pthread_mutex_unlock(&h
->rh_lock
);
153 #define HOLD_HANDLE(h, flag, field) \
154 (handle_hold_subhandles((h), (flag)), (h)->field)
156 #define RELE_HANDLE(h, flag) \
157 (handle_rele_subhandles((h), (flag)))
160 * convenience macros, for functions that only need a one or two handles at
163 #define HANDLE_HOLD_ITER(h) HOLD_HANDLE((h), RH_HOLD_ITER, rh_iter)
164 #define HANDLE_HOLD_SCOPE(h) HOLD_HANDLE((h), RH_HOLD_SCOPE, rh_scope)
165 #define HANDLE_HOLD_SERVICE(h) HOLD_HANDLE((h), RH_HOLD_SERVICE, rh_service)
166 #define HANDLE_HOLD_INSTANCE(h) HOLD_HANDLE((h), RH_HOLD_INSTANCE, rh_instance)
167 #define HANDLE_HOLD_SNAPSHOT(h) HOLD_HANDLE((h), RH_HOLD_SNAPSHOT, rh_snapshot)
168 #define HANDLE_HOLD_SNAPLVL(h) HOLD_HANDLE((h), RH_HOLD_SNAPLVL, rh_snaplvl)
169 #define HANDLE_HOLD_PG(h) HOLD_HANDLE((h), RH_HOLD_PG, rh_pg)
170 #define HANDLE_HOLD_PROPERTY(h) HOLD_HANDLE((h), RH_HOLD_PROPERTY, rh_property)
171 #define HANDLE_HOLD_VALUE(h) HOLD_HANDLE((h), RH_HOLD_VALUE, rh_value)
173 #define HANDLE_RELE_ITER(h) RELE_HANDLE((h), RH_HOLD_ITER)
174 #define HANDLE_RELE_SCOPE(h) RELE_HANDLE((h), RH_HOLD_SCOPE)
175 #define HANDLE_RELE_SERVICE(h) RELE_HANDLE((h), RH_HOLD_SERVICE)
176 #define HANDLE_RELE_INSTANCE(h) RELE_HANDLE((h), RH_HOLD_INSTANCE)
177 #define HANDLE_RELE_SNAPSHOT(h) RELE_HANDLE((h), RH_HOLD_SNAPSHOT)
178 #define HANDLE_RELE_SNAPLVL(h) RELE_HANDLE((h), RH_HOLD_SNAPLVL)
179 #define HANDLE_RELE_PG(h) RELE_HANDLE((h), RH_HOLD_PG)
180 #define HANDLE_RELE_PROPERTY(h) RELE_HANDLE((h), RH_HOLD_PROPERTY)
181 #define HANDLE_RELE_VALUE(h) RELE_HANDLE((h), RH_HOLD_VALUE)
185 transaction_entry_compare(const void *l_arg
, const void *r_arg
, void *private)
188 ((scf_transaction_entry_t
*)l_arg
)->entry_property
;
190 ((scf_transaction_entry_t
*)r_arg
)->entry_property
;
194 ret
= strcmp(l_prop
, r_prop
);
203 datael_compare(const void *l_arg
, const void *r_arg
, void *private)
205 uint32_t l_id
= ((scf_datael_t
*)l_arg
)->rd_entity
;
206 uint32_t r_id
= (r_arg
!= NULL
) ? ((scf_datael_t
*)r_arg
)->rd_entity
:
207 *(uint32_t *)private;
217 iter_compare(const void *l_arg
, const void *r_arg
, void *private)
219 uint32_t l_id
= ((scf_iter_t
*)l_arg
)->iter_id
;
220 uint32_t r_id
= (r_arg
!= NULL
) ? ((scf_iter_t
*)r_arg
)->iter_id
:
221 *(uint32_t *)private;
234 const char *door_path
;
236 (void) pthread_mutex_lock(&lowlevel_init_lock
);
237 if (lowlevel_inited
== 0) {
239 (debug
= getenv(ENV_SCF_DEBUG
)) != NULL
&& debug
[0] != 0 &&
240 uu_strtoint(debug
, &default_debug
, sizeof (default_debug
),
242 (void) fprintf(stderr
, "LIBSCF: $%s (%s): %s",
243 ENV_SCF_DEBUG
, debug
,
244 uu_strerror(uu_error()));
248 (door_path
= getenv(ENV_SCF_DOORPATH
)) != NULL
&&
250 default_door_path
= strdup(door_path
);
251 if (default_door_path
== NULL
)
252 default_door_path
= door_path
;
255 datael_pool
= uu_list_pool_create("SUNW,libscf_datael",
256 sizeof (scf_datael_t
), offsetof(scf_datael_t
, rd_node
),
257 datael_compare
, UU_LIST_POOL_DEBUG
);
259 iter_pool
= uu_list_pool_create("SUNW,libscf_iter",
260 sizeof (scf_iter_t
), offsetof(scf_iter_t
, iter_node
),
261 iter_compare
, UU_LIST_POOL_DEBUG
);
263 assert_nolint(offsetof(scf_transaction_entry_t
,
264 entry_property
) == 0);
265 tran_entry_pool
= uu_list_pool_create(
266 "SUNW,libscf_transaction_entity",
267 sizeof (scf_transaction_entry_t
),
268 offsetof(scf_transaction_entry_t
, entry_link
),
269 transaction_entry_compare
, UU_LIST_POOL_DEBUG
);
271 if (datael_pool
== NULL
|| iter_pool
== NULL
||
272 tran_entry_pool
== NULL
) {
273 lowlevel_inited
= -1;
277 if (!scf_setup_error()) {
278 lowlevel_inited
= -1;
284 (void) pthread_mutex_unlock(&lowlevel_init_lock
);
285 if (lowlevel_inited
> 0)
290 static const struct {
292 rep_protocol_value_type_t ti_proto_type
;
294 } scf_type_info
[] = {
295 {SCF_TYPE_BOOLEAN
, REP_PROTOCOL_TYPE_BOOLEAN
, "boolean"},
296 {SCF_TYPE_COUNT
, REP_PROTOCOL_TYPE_COUNT
, "count"},
297 {SCF_TYPE_INTEGER
, REP_PROTOCOL_TYPE_INTEGER
, "integer"},
298 {SCF_TYPE_TIME
, REP_PROTOCOL_TYPE_TIME
, "time"},
299 {SCF_TYPE_ASTRING
, REP_PROTOCOL_TYPE_STRING
, "astring"},
300 {SCF_TYPE_OPAQUE
, REP_PROTOCOL_TYPE_OPAQUE
, "opaque"},
301 {SCF_TYPE_USTRING
, REP_PROTOCOL_SUBTYPE_USTRING
, "ustring"},
302 {SCF_TYPE_URI
, REP_PROTOCOL_SUBTYPE_URI
, "uri"},
303 {SCF_TYPE_FMRI
, REP_PROTOCOL_SUBTYPE_FMRI
, "fmri"},
304 {SCF_TYPE_HOST
, REP_PROTOCOL_SUBTYPE_HOST
, "host"},
305 {SCF_TYPE_HOSTNAME
, REP_PROTOCOL_SUBTYPE_HOSTNAME
, "hostname"},
306 {SCF_TYPE_NET_ADDR
, REP_PROTOCOL_SUBTYPE_NETADDR
, "net_address"},
307 {SCF_TYPE_NET_ADDR_V4
, REP_PROTOCOL_SUBTYPE_NETADDR_V4
,
309 {SCF_TYPE_NET_ADDR_V6
, REP_PROTOCOL_SUBTYPE_NETADDR_V6
,
313 #define SCF_TYPE_INFO_COUNT (sizeof (scf_type_info) / sizeof (*scf_type_info))
314 static rep_protocol_value_type_t
315 scf_type_to_protocol_type(scf_type_t t
)
319 for (i
= 0; i
< SCF_TYPE_INFO_COUNT
; i
++)
320 if (scf_type_info
[i
].ti_type
== t
)
321 return (scf_type_info
[i
].ti_proto_type
);
323 return (REP_PROTOCOL_TYPE_INVALID
);
327 scf_protocol_type_to_type(rep_protocol_value_type_t t
)
331 for (i
= 0; i
< SCF_TYPE_INFO_COUNT
; i
++)
332 if (scf_type_info
[i
].ti_proto_type
== t
)
333 return (scf_type_info
[i
].ti_type
);
335 return (SCF_TYPE_INVALID
);
339 scf_type_to_string(scf_type_t ty
)
343 for (i
= 0; i
< SCF_TYPE_INFO_COUNT
; i
++)
344 if (scf_type_info
[i
].ti_type
== ty
)
345 return (scf_type_info
[i
].ti_name
);
351 scf_string_to_type(const char *name
)
355 for (i
= 0; i
< sizeof (scf_type_info
) / sizeof (*scf_type_info
); i
++)
356 if (strcmp(scf_type_info
[i
].ti_name
, name
) == 0)
357 return (scf_type_info
[i
].ti_type
);
359 return (SCF_TYPE_INVALID
);
363 scf_type_base_type(scf_type_t type
, scf_type_t
*out
)
365 rep_protocol_value_type_t t
= scf_type_to_protocol_type(type
);
366 if (t
== REP_PROTOCOL_TYPE_INVALID
)
367 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
369 *out
= scf_protocol_type_to_type(scf_proto_underlying_type(t
));
370 return (SCF_SUCCESS
);
374 * Convert a protocol error code into an SCF_ERROR_* code.
377 proto_error(rep_protocol_responseid_t e
)
380 case REP_PROTOCOL_FAIL_MISORDERED
:
381 case REP_PROTOCOL_FAIL_UNKNOWN_ID
:
382 case REP_PROTOCOL_FAIL_INVALID_TYPE
:
383 case REP_PROTOCOL_FAIL_TRUNCATED
:
384 case REP_PROTOCOL_FAIL_TYPE_MISMATCH
:
385 case REP_PROTOCOL_FAIL_NOT_APPLICABLE
:
386 case REP_PROTOCOL_FAIL_UNKNOWN
:
387 return (SCF_ERROR_INTERNAL
);
389 case REP_PROTOCOL_FAIL_BAD_TX
:
390 return (SCF_ERROR_INVALID_ARGUMENT
);
391 case REP_PROTOCOL_FAIL_BAD_REQUEST
:
392 return (SCF_ERROR_INVALID_ARGUMENT
);
393 case REP_PROTOCOL_FAIL_NO_RESOURCES
:
394 return (SCF_ERROR_NO_RESOURCES
);
395 case REP_PROTOCOL_FAIL_NOT_FOUND
:
396 return (SCF_ERROR_NOT_FOUND
);
397 case REP_PROTOCOL_FAIL_DELETED
:
398 return (SCF_ERROR_DELETED
);
399 case REP_PROTOCOL_FAIL_NOT_SET
:
400 return (SCF_ERROR_NOT_SET
);
401 case REP_PROTOCOL_FAIL_EXISTS
:
402 return (SCF_ERROR_EXISTS
);
403 case REP_PROTOCOL_FAIL_DUPLICATE_ID
:
404 return (SCF_ERROR_EXISTS
);
405 case REP_PROTOCOL_FAIL_PERMISSION_DENIED
:
406 return (SCF_ERROR_PERMISSION_DENIED
);
407 case REP_PROTOCOL_FAIL_BACKEND_ACCESS
:
408 return (SCF_ERROR_BACKEND_ACCESS
);
409 case REP_PROTOCOL_FAIL_BACKEND_READONLY
:
410 return (SCF_ERROR_BACKEND_READONLY
);
412 case REP_PROTOCOL_SUCCESS
:
413 case REP_PROTOCOL_DONE
:
414 case REP_PROTOCOL_FAIL_NOT_LATEST
: /* TX code should handle this */
417 uu_warn("%s:%d: Bad error code %d passed to proto_error().\n",
418 __FILE__
, __LINE__
, e
);
426 scf_limit(uint32_t limit
)
429 case SCF_LIMIT_MAX_NAME_LENGTH
:
430 case SCF_LIMIT_MAX_PG_TYPE_LENGTH
:
431 return (REP_PROTOCOL_NAME_LEN
- 1);
432 case SCF_LIMIT_MAX_VALUE_LENGTH
:
433 return (REP_PROTOCOL_VALUE_LEN
- 1);
434 case SCF_LIMIT_MAX_FMRI_LENGTH
:
435 return (SCF_FMRI_PREFIX_MAX_LEN
+
436 sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1 +
437 sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1 +
438 sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1 +
439 sizeof (SCF_FMRI_INSTANCE_PREFIX
) - 1 +
440 sizeof (SCF_FMRI_PROPERTYGRP_PREFIX
) - 1 +
441 sizeof (SCF_FMRI_PROPERTY_PREFIX
) - 1 +
442 5 * (REP_PROTOCOL_NAME_LEN
- 1));
444 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
449 scf_opaque_decode(char *out_arg
, const char *in
, size_t max_out
)
454 while (max_out
> 0 && (a
= in
[0]) != 0 && (b
= in
[1]) != 0) {
457 if (a
>= '0' && a
<= '9')
459 else if (a
>= 'a' && a
<= 'f')
461 else if (a
>= 'A' && a
<= 'F')
466 if (b
>= '0' && b
<= '9')
468 else if (b
>= 'a' && b
<= 'f')
470 else if (b
>= 'A' && b
<= 'F')
475 *out
++ = (a
<< 4) | b
;
479 return (out
- out_arg
);
483 scf_opaque_encode(char *out_arg
, const char *in_arg
, size_t in_sz
)
485 uint8_t *in
= (uint8_t *)in_arg
;
486 uint8_t *end
= in
+ in_sz
;
495 uint8_t a
= (c
& 0xf0) >> 4;
496 uint8_t b
= (c
& 0x0f);
501 *out
++ = a
+ 'a' - 10;
506 *out
++ = b
+ 'a' - 10;
511 return (out
- out_arg
);
515 handle_do_close(scf_handle_t
*h
)
517 assert(MUTEX_HELD(&h
->rh_lock
));
518 assert(h
->rh_doorfd
!= -1);
521 * if there are any active FD users, we just move the FD over
522 * to rh_doorfd_old -- they'll close it when they finish.
524 if (h
->rh_fd_users
> 0) {
525 h
->rh_doorfd_old
= h
->rh_doorfd
;
528 assert(h
->rh_doorfd_old
== -1);
529 (void) close(h
->rh_doorfd
);
535 * Check if a handle is currently bound. fork()ing implicitly unbinds
536 * the handle in the child.
539 handle_is_bound(scf_handle_t
*h
)
541 assert(MUTEX_HELD(&h
->rh_lock
));
543 if (h
->rh_doorfd
== -1)
546 if (getpid() == h
->rh_doorpid
)
549 /* forked since our last bind -- initiate handle close */
555 handle_has_server_locked(scf_handle_t
*h
)
558 assert(MUTEX_HELD(&h
->rh_lock
));
560 return (handle_is_bound(h
) && door_info(h
->rh_doorfd
, &i
) != -1 &&
565 handle_has_server(scf_handle_t
*h
)
569 (void) pthread_mutex_lock(&h
->rh_lock
);
570 ret
= handle_has_server_locked(h
);
571 (void) pthread_mutex_unlock(&h
->rh_lock
);
577 * This makes a door request on the client door associated with handle h.
578 * It will automatically retry calls which fail on EINTR. If h is not bound,
579 * returns NOT_BOUND. If the door call fails or the server response is too
580 * small, returns CALL_FAILED. If the server response is too big, truncates the
581 * response and returns RESULT_TOO_BIG. Otherwise, the size of the result is
585 make_door_call(scf_handle_t
*h
, const void *req
, size_t req_sz
,
586 void *res
, size_t res_sz
)
591 assert(MUTEX_HELD(&h
->rh_lock
));
593 if (!handle_is_bound(h
)) {
597 arg
.data_ptr
= (void *)req
;
598 arg
.data_size
= req_sz
;
604 while ((r
= door_call(h
->rh_doorfd
, &arg
)) < 0) {
610 return (CALL_FAILED
);
613 if (arg
.desc_num
> 0) {
614 while (arg
.desc_num
> 0) {
615 if (arg
.desc_ptr
->d_attributes
& DOOR_DESCRIPTOR
) {
616 int cfd
= arg
.desc_ptr
->d_data
.d_desc
.d_id
;
623 if (arg
.data_ptr
!= res
&& arg
.data_size
> 0)
624 (void) memmove(res
, arg
.data_ptr
, MIN(arg
.data_size
, res_sz
));
627 (void) munmap(arg
.rbuf
, arg
.rsize
);
629 if (arg
.data_size
> res_sz
)
630 return (RESULT_TOO_BIG
);
632 if (arg
.data_size
< sizeof (uint32_t))
633 return (CALL_FAILED
);
635 return (arg
.data_size
);
639 * Should only be used when r < 0.
641 #define DOOR_ERRORS_BLOCK(r) { \
644 return (scf_set_error(SCF_ERROR_NOT_BOUND)); \
647 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN)); \
649 case RESULT_TOO_BIG: \
650 return (scf_set_error(SCF_ERROR_INTERNAL)); \
653 assert(r == NOT_BOUND || r == CALL_FAILED || \
654 r == RESULT_TOO_BIG); \
660 * Like make_door_call(), but takes an fd instead of a handle, and expects
661 * a single file descriptor, returned via res_fd.
663 * If no file descriptor is returned, *res_fd == -1.
666 make_door_call_retfd(int fd
, const void *req
, size_t req_sz
, void *res
,
667 size_t res_sz
, int *res_fd
)
678 arg
.data_ptr
= (void *)req
;
679 arg
.data_size
= req_sz
;
683 arg
.rsize
= sizeof (rbuf
);
685 while ((r
= door_call(fd
, &arg
)) < 0) {
691 return (CALL_FAILED
);
693 if (arg
.desc_num
> 1) {
694 while (arg
.desc_num
> 0) {
695 if (arg
.desc_ptr
->d_attributes
& DOOR_DESCRIPTOR
) {
697 arg
.desc_ptr
->d_data
.d_desc
.d_descriptor
;
704 if (arg
.desc_num
== 1 && arg
.desc_ptr
->d_attributes
& DOOR_DESCRIPTOR
)
705 *res_fd
= arg
.desc_ptr
->d_data
.d_desc
.d_descriptor
;
707 if (arg
.data_size
> 0)
708 (void) memmove(res
, arg
.data_ptr
, MIN(arg
.data_size
, res_sz
));
710 if (arg
.rbuf
!= rbuf
)
711 (void) munmap(arg
.rbuf
, arg
.rsize
);
713 if (arg
.data_size
> res_sz
)
714 return (RESULT_TOO_BIG
);
716 if (arg
.data_size
< sizeof (uint32_t))
717 return (CALL_FAILED
);
719 return (arg
.data_size
);
728 scf_handle_create(scf_version_t v
)
734 * This will need to be revisited when we bump SCF_VERSION
736 if (v
!= SCF_VERSION
) {
737 (void) scf_set_error(SCF_ERROR_VERSION_MISMATCH
);
741 if (!lowlevel_init()) {
742 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
746 ret
= uu_zalloc(sizeof (*ret
));
748 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
752 ret
->rh_dataels
= uu_list_create(datael_pool
, ret
, 0);
753 ret
->rh_iters
= uu_list_create(iter_pool
, ret
, 0);
754 if (ret
->rh_dataels
== NULL
|| ret
->rh_iters
== NULL
) {
755 if (ret
->rh_dataels
!= NULL
)
756 uu_list_destroy(ret
->rh_dataels
);
757 if (ret
->rh_iters
!= NULL
)
758 uu_list_destroy(ret
->rh_iters
);
760 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
765 ret
->rh_doorfd_old
= -1;
766 (void) pthread_mutex_init(&ret
->rh_lock
, NULL
);
768 handle_hold_subhandles(ret
, RH_HOLD_ALL
);
770 failed
= ((ret
->rh_iter
= scf_iter_create(ret
)) == NULL
||
771 (ret
->rh_scope
= scf_scope_create(ret
)) == NULL
||
772 (ret
->rh_service
= scf_service_create(ret
)) == NULL
||
773 (ret
->rh_instance
= scf_instance_create(ret
)) == NULL
||
774 (ret
->rh_snapshot
= scf_snapshot_create(ret
)) == NULL
||
775 (ret
->rh_snaplvl
= scf_snaplevel_create(ret
)) == NULL
||
776 (ret
->rh_pg
= scf_pg_create(ret
)) == NULL
||
777 (ret
->rh_property
= scf_property_create(ret
)) == NULL
||
778 (ret
->rh_value
= scf_value_create(ret
)) == NULL
);
781 * these subhandles count as internal references, not external ones.
783 ret
->rh_intrefs
= ret
->rh_extrefs
;
785 handle_rele_subhandles(ret
, RH_HOLD_ALL
);
788 scf_handle_destroy(ret
);
789 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
793 scf_value_set_count(ret
->rh_value
, default_debug
);
794 (void) scf_handle_decorate(ret
, "debug", ret
->rh_value
);
802 * _NO_SERVER - server door could not be open()ed
805 * _VERSION_MISMATCH - server returned bad file descriptor
806 * server claimed bad request
807 * server reported version mismatch
808 * server refused with unknown reason
810 * _NO_RESOURCES - server is out of memory
812 * _INTERNAL - could not set up entities or iters
813 * server response too big
816 _scf_handle_create_and_bind(scf_version_t ver
)
820 h
= scf_handle_create(ver
);
824 if (scf_handle_bind(h
) == -1) {
825 scf_handle_destroy(h
);
832 scf_handle_decorate(scf_handle_t
*handle
, const char *name
, scf_value_t
*v
)
834 if (v
!= SCF_DECORATE_CLEAR
&& handle
!= v
->value_handle
)
835 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
837 (void) pthread_mutex_lock(&handle
->rh_lock
);
838 if (handle_is_bound(handle
)) {
839 (void) pthread_mutex_unlock(&handle
->rh_lock
);
840 return (scf_set_error(SCF_ERROR_IN_USE
));
842 (void) pthread_mutex_unlock(&handle
->rh_lock
);
844 if (strcmp(name
, "debug") == 0) {
845 if (v
== SCF_DECORATE_CLEAR
) {
846 (void) pthread_mutex_lock(&handle
->rh_lock
);
847 handle
->rh_debug
= 0;
848 (void) pthread_mutex_unlock(&handle
->rh_lock
);
851 if (scf_value_get_count(v
, &val
) < 0)
852 return (-1); /* error already set */
854 (void) pthread_mutex_lock(&handle
->rh_lock
);
855 handle
->rh_debug
= (uid_t
)val
;
856 (void) pthread_mutex_unlock(&handle
->rh_lock
);
860 if (strcmp(name
, "door_path") == 0) {
861 char name
[sizeof (handle
->rh_doorpath
)];
863 if (v
== SCF_DECORATE_CLEAR
) {
864 (void) pthread_mutex_lock(&handle
->rh_lock
);
865 handle
->rh_doorpath
[0] = 0;
866 (void) pthread_mutex_unlock(&handle
->rh_lock
);
870 if ((len
= scf_value_get_astring(v
, name
,
871 sizeof (name
))) < 0) {
872 return (-1); /* error already set */
874 if (len
== 0 || len
>= sizeof (name
)) {
875 return (scf_set_error(
876 SCF_ERROR_INVALID_ARGUMENT
));
878 (void) pthread_mutex_lock(&handle
->rh_lock
);
879 (void) strlcpy(handle
->rh_doorpath
, name
,
880 sizeof (handle
->rh_doorpath
));
881 (void) pthread_mutex_unlock(&handle
->rh_lock
);
886 if (strcmp(name
, "zone") == 0) {
887 char zone
[MAXPATHLEN
], root
[MAXPATHLEN
], door
[MAXPATHLEN
];
888 static int (*zone_get_rootpath
)(char *, char *, size_t);
892 * In order to be able to set the zone on a handle, we want
893 * to determine the zone's path, which requires us to call into
894 * libzonecfg -- but libzonecfg.so links against libscf.so so
895 * we must not explicitly link to it. To circumvent the
896 * circular dependency, we will pull it in here via dlopen().
898 if (zone_get_rootpath
== NULL
) {
899 void *dl
= dlopen("libzonecfg.so.1", RTLD_LAZY
), *sym
;
902 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
904 if ((sym
= dlsym(dl
, "zone_get_rootpath")) == NULL
) {
906 return (scf_set_error(SCF_ERROR_INTERNAL
));
909 zone_get_rootpath
= (int(*)(char *, char *, size_t))sym
;
912 if (v
== SCF_DECORATE_CLEAR
) {
913 (void) pthread_mutex_lock(&handle
->rh_lock
);
914 handle
->rh_doorpath
[0] = 0;
915 (void) pthread_mutex_unlock(&handle
->rh_lock
);
920 if ((len
= scf_value_get_astring(v
, zone
, sizeof (zone
))) < 0)
923 if (len
== 0 || len
>= sizeof (zone
))
924 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
926 if (zone_get_rootpath(zone
, root
, sizeof (root
)) != Z_OK
) {
927 if (strcmp(zone
, GLOBAL_ZONENAME
) == 0) {
930 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
934 if (snprintf(door
, sizeof (door
), "%s/%s", root
,
935 default_door_path
) >= sizeof (door
))
936 return (scf_set_error(SCF_ERROR_INTERNAL
));
938 (void) pthread_mutex_lock(&handle
->rh_lock
);
939 (void) strlcpy(handle
->rh_doorpath
, door
,
940 sizeof (handle
->rh_doorpath
));
941 (void) pthread_mutex_unlock(&handle
->rh_lock
);
946 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
950 * fails with INVALID_ARGUMENT and HANDLE_MISMATCH.
953 _scf_handle_decorations(scf_handle_t
*handle
, scf_decoration_func
*f
,
954 scf_value_t
*v
, void *data
)
956 scf_decoration_info_t i
;
957 char name
[sizeof (handle
->rh_doorpath
)];
960 if (f
== NULL
|| v
== NULL
)
961 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
963 if (v
->value_handle
!= handle
)
964 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
966 i
.sdi_name
= (const char *)"debug";
967 i
.sdi_type
= SCF_TYPE_COUNT
;
968 (void) pthread_mutex_lock(&handle
->rh_lock
);
969 debug
= handle
->rh_debug
;
970 (void) pthread_mutex_unlock(&handle
->rh_lock
);
972 scf_value_set_count(v
, debug
);
975 i
.sdi_value
= SCF_DECORATE_CLEAR
;
978 if ((*f
)(&i
, data
) == 0)
981 i
.sdi_name
= (const char *)"door_path";
982 i
.sdi_type
= SCF_TYPE_ASTRING
;
983 (void) pthread_mutex_lock(&handle
->rh_lock
);
984 (void) strlcpy(name
, handle
->rh_doorpath
, sizeof (name
));
985 (void) pthread_mutex_unlock(&handle
->rh_lock
);
987 (void) scf_value_set_astring(v
, name
);
990 i
.sdi_value
= SCF_DECORATE_CLEAR
;
993 if ((*f
)(&i
, data
) == 0)
1000 * Fails if handle is not bound.
1003 handle_unbind_unlocked(scf_handle_t
*handle
)
1005 rep_protocol_request_t request
;
1006 rep_protocol_response_t response
;
1008 if (!handle_is_bound(handle
))
1011 request
.rpr_request
= REP_PROTOCOL_CLOSE
;
1013 (void) make_door_call(handle
, &request
, sizeof (request
),
1014 &response
, sizeof (response
));
1016 handle_do_close(handle
);
1018 return (SCF_SUCCESS
);
1023 * _HANDLE_DESTROYED - dp's handle has been destroyed
1024 * _INTERNAL - server response too big
1025 * entity already set up with different type
1026 * _NO_RESOURCES - server out of memory
1029 datael_attach(scf_datael_t
*dp
)
1031 scf_handle_t
*h
= dp
->rd_handle
;
1033 struct rep_protocol_entity_setup request
;
1034 rep_protocol_response_t response
;
1037 assert(MUTEX_HELD(&h
->rh_lock
));
1039 dp
->rd_reset
= 0; /* setup implicitly resets */
1041 if (h
->rh_flags
& HANDLE_DEAD
)
1042 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
1044 if (!handle_is_bound(h
))
1045 return (SCF_SUCCESS
); /* nothing to do */
1047 request
.rpr_request
= REP_PROTOCOL_ENTITY_SETUP
;
1048 request
.rpr_entityid
= dp
->rd_entity
;
1049 request
.rpr_entitytype
= dp
->rd_type
;
1051 r
= make_door_call(h
, &request
, sizeof (request
),
1052 &response
, sizeof (response
));
1054 if (r
== NOT_BOUND
|| r
== CALL_FAILED
)
1055 return (SCF_SUCCESS
);
1056 if (r
== RESULT_TOO_BIG
)
1057 return (scf_set_error(SCF_ERROR_INTERNAL
));
1059 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1060 return (scf_set_error(proto_error(response
.rpr_response
)));
1062 return (SCF_SUCCESS
);
1067 * _HANDLE_DESTROYED - iter's handle has been destroyed
1068 * _INTERNAL - server response too big
1069 * iter already existed
1073 iter_attach(scf_iter_t
*iter
)
1075 scf_handle_t
*h
= iter
->iter_handle
;
1076 struct rep_protocol_iter_request request
;
1077 struct rep_protocol_response response
;
1080 assert(MUTEX_HELD(&h
->rh_lock
));
1082 if (h
->rh_flags
& HANDLE_DEAD
)
1083 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
1085 if (!handle_is_bound(h
))
1086 return (SCF_SUCCESS
); /* nothing to do */
1088 request
.rpr_request
= REP_PROTOCOL_ITER_SETUP
;
1089 request
.rpr_iterid
= iter
->iter_id
;
1091 r
= make_door_call(h
, &request
, sizeof (request
),
1092 &response
, sizeof (response
));
1094 if (r
== NOT_BOUND
|| r
== CALL_FAILED
)
1095 return (SCF_SUCCESS
);
1096 if (r
== RESULT_TOO_BIG
)
1097 return (scf_set_error(SCF_ERROR_INTERNAL
));
1099 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1100 return (scf_set_error(proto_error(response
.rpr_response
)));
1102 return (SCF_SUCCESS
);
1107 * _IN_USE - handle already bound
1108 * _NO_SERVER - server door could not be open()ed
1110 * door_info() failed
1111 * _VERSION_MISMATCH - server returned bad file descriptor
1112 * server claimed bad request
1113 * server reported version mismatch
1114 * server refused with unknown reason
1116 * _NO_RESOURCES - server is out of memory
1117 * _PERMISSION_DENIED
1118 * _INTERNAL - could not set up entities or iters
1119 * server response too big
1121 * perhaps this should try multiple times.
1124 scf_handle_bind(scf_handle_t
*handle
)
1133 repository_door_request_t request
;
1134 repository_door_response_t response
;
1135 const char *door_name
= default_door_path
;
1137 (void) pthread_mutex_lock(&handle
->rh_lock
);
1138 if (handle_is_bound(handle
)) {
1139 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1140 return (scf_set_error(SCF_ERROR_IN_USE
));
1143 /* wait until any active fd users have cleared out */
1144 while (handle
->rh_fd_users
> 0) {
1147 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
,
1149 (void) pthread_cond_wait(&handle
->rh_cv
, &handle
->rh_lock
);
1150 (void) pthread_setcancelstate(cancel_state
, NULL
);
1153 /* check again, since we had to drop the lock */
1154 if (handle_is_bound(handle
)) {
1155 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1156 return (scf_set_error(SCF_ERROR_IN_USE
));
1159 assert(handle
->rh_doorfd
== -1 && handle
->rh_doorfd_old
== -1);
1161 if (handle
->rh_doorpath
[0] != 0)
1162 door_name
= handle
->rh_doorpath
;
1164 fd
= open(door_name
, O_RDONLY
, 0);
1166 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1167 return (scf_set_error(SCF_ERROR_NO_SERVER
));
1170 request
.rdr_version
= REPOSITORY_DOOR_VERSION
;
1171 request
.rdr_request
= REPOSITORY_DOOR_REQUEST_CONNECT
;
1172 request
.rdr_flags
= handle
->rh_flags
;
1173 request
.rdr_debug
= handle
->rh_debug
;
1177 res
= make_door_call_retfd(fd
, &request
, sizeof (request
),
1178 &response
, sizeof (response
), &handle
->rh_doorfd
);
1183 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1185 assert(res
!= NOT_BOUND
);
1186 if (res
== CALL_FAILED
)
1187 return (scf_set_error(SCF_ERROR_NO_SERVER
));
1188 assert(res
== RESULT_TOO_BIG
);
1189 return (scf_set_error(SCF_ERROR_INTERNAL
));
1192 if (handle
->rh_doorfd
< 0) {
1193 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1195 switch (response
.rdr_status
) {
1196 case REPOSITORY_DOOR_SUCCESS
:
1197 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1199 case REPOSITORY_DOOR_FAIL_BAD_REQUEST
:
1200 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1202 case REPOSITORY_DOOR_FAIL_VERSION_MISMATCH
:
1203 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1205 case REPOSITORY_DOOR_FAIL_BAD_FLAG
:
1206 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1208 case REPOSITORY_DOOR_FAIL_NO_RESOURCES
:
1209 return (scf_set_error(SCF_ERROR_NO_RESOURCES
));
1211 case REPOSITORY_DOOR_FAIL_PERMISSION_DENIED
:
1212 return (scf_set_error(SCF_ERROR_PERMISSION_DENIED
));
1215 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1219 (void) fcntl(handle
->rh_doorfd
, F_SETFD
, FD_CLOEXEC
);
1221 if (door_info(handle
->rh_doorfd
, &info
) < 0) {
1222 (void) close(handle
->rh_doorfd
);
1223 handle
->rh_doorfd
= -1;
1225 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1226 return (scf_set_error(SCF_ERROR_NO_SERVER
));
1229 handle
->rh_doorpid
= pid
;
1230 handle
->rh_doorid
= info
.di_uniquifier
;
1233 * Now, re-attach everything
1235 for (el
= uu_list_first(handle
->rh_dataels
); el
!= NULL
;
1236 el
= uu_list_next(handle
->rh_dataels
, el
)) {
1237 if (datael_attach(el
) == -1) {
1238 assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED
);
1239 (void) handle_unbind_unlocked(handle
);
1240 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1245 for (iter
= uu_list_first(handle
->rh_iters
); iter
!= NULL
;
1246 iter
= uu_list_next(handle
->rh_iters
, iter
)) {
1247 if (iter_attach(iter
) == -1) {
1248 assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED
);
1249 (void) handle_unbind_unlocked(handle
);
1250 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1254 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1255 return (SCF_SUCCESS
);
1259 scf_handle_unbind(scf_handle_t
*handle
)
1262 (void) pthread_mutex_lock(&handle
->rh_lock
);
1263 ret
= handle_unbind_unlocked(handle
);
1264 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1265 return (ret
== SCF_SUCCESS
? ret
: scf_set_error(SCF_ERROR_NOT_BOUND
));
1268 static scf_handle_t
*
1269 handle_get(scf_handle_t
*h
)
1271 (void) pthread_mutex_lock(&h
->rh_lock
);
1272 if (h
->rh_flags
& HANDLE_DEAD
) {
1273 (void) pthread_mutex_unlock(&h
->rh_lock
);
1274 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED
);
1277 (void) pthread_mutex_unlock(&h
->rh_lock
);
1282 * Called when an object is removed from the handle. On the last remove,
1283 * cleans up and frees the handle.
1286 handle_unrefed(scf_handle_t
*handle
)
1292 scf_instance_t
*inst
;
1293 scf_snapshot_t
*snap
;
1294 scf_snaplevel_t
*snaplvl
;
1295 scf_propertygroup_t
*pg
;
1296 scf_property_t
*prop
;
1298 assert(MUTEX_HELD(&handle
->rh_lock
));
1301 * Don't do anything if the handle has not yet been destroyed, there
1302 * are still external references, or we're already doing unrefed
1305 if (!(handle
->rh_flags
& HANDLE_DEAD
) ||
1306 handle
->rh_extrefs
> 0 ||
1307 handle
->rh_fd_users
> 0 ||
1308 (handle
->rh_flags
& HANDLE_UNREFED
)) {
1309 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1313 handle
->rh_flags
|= HANDLE_UNREFED
;
1316 * Now that we know that there are no external references, and the
1317 * HANDLE_DEAD flag keeps new ones from appearing, we can clean up
1318 * our subhandles and destroy the handle completely.
1320 assert(handle
->rh_intrefs
>= 0);
1321 handle
->rh_extrefs
= handle
->rh_intrefs
;
1322 handle
->rh_intrefs
= 0;
1323 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1325 handle_hold_subhandles(handle
, RH_HOLD_ALL
);
1327 iter
= handle
->rh_iter
;
1328 sc
= handle
->rh_scope
;
1329 svc
= handle
->rh_service
;
1330 inst
= handle
->rh_instance
;
1331 snap
= handle
->rh_snapshot
;
1332 snaplvl
= handle
->rh_snaplvl
;
1334 prop
= handle
->rh_property
;
1335 v
= handle
->rh_value
;
1337 handle
->rh_iter
= NULL
;
1338 handle
->rh_scope
= NULL
;
1339 handle
->rh_service
= NULL
;
1340 handle
->rh_instance
= NULL
;
1341 handle
->rh_snapshot
= NULL
;
1342 handle
->rh_snaplvl
= NULL
;
1343 handle
->rh_pg
= NULL
;
1344 handle
->rh_property
= NULL
;
1345 handle
->rh_value
= NULL
;
1348 scf_iter_destroy(iter
);
1350 scf_scope_destroy(sc
);
1352 scf_service_destroy(svc
);
1354 scf_instance_destroy(inst
);
1356 scf_snapshot_destroy(snap
);
1357 if (snaplvl
!= NULL
)
1358 scf_snaplevel_destroy(snaplvl
);
1362 scf_property_destroy(prop
);
1364 scf_value_destroy(v
);
1366 (void) pthread_mutex_lock(&handle
->rh_lock
);
1368 /* there should be no outstanding children at this point */
1369 assert(handle
->rh_extrefs
== 0);
1370 assert(handle
->rh_intrefs
== 0);
1371 assert(handle
->rh_values
== 0);
1372 assert(handle
->rh_entries
== 0);
1373 assert(uu_list_numnodes(handle
->rh_dataels
) == 0);
1374 assert(uu_list_numnodes(handle
->rh_iters
) == 0);
1376 uu_list_destroy(handle
->rh_dataels
);
1377 uu_list_destroy(handle
->rh_iters
);
1378 handle
->rh_dataels
= NULL
;
1379 handle
->rh_iters
= NULL
;
1380 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1382 (void) pthread_mutex_destroy(&handle
->rh_lock
);
1388 scf_handle_destroy(scf_handle_t
*handle
)
1393 (void) pthread_mutex_lock(&handle
->rh_lock
);
1394 if (handle
->rh_flags
& HANDLE_DEAD
) {
1396 * This is an error (you are not allowed to reference the
1397 * handle after it is destroyed), but we can't report it.
1399 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1402 handle
->rh_flags
|= HANDLE_DEAD
;
1403 (void) handle_unbind_unlocked(handle
);
1404 handle_unrefed(handle
);
1408 scf_myname(scf_handle_t
*h
, char *out
, size_t len
)
1412 if (!handle_has_server(h
))
1413 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
1415 cp
= getenv("SMF_FMRI");
1417 return (scf_set_error(SCF_ERROR_NOT_SET
));
1419 return (strlcpy(out
, cp
, len
));
1423 handle_alloc_entityid(scf_handle_t
*h
)
1427 assert(MUTEX_HELD(&h
->rh_lock
));
1429 if (uu_list_numnodes(h
->rh_dataels
) == UINT32_MAX
)
1430 return (0); /* no ids available */
1433 * The following loop assumes that there are not a huge number of
1434 * outstanding entities when we've wrapped. If that ends up not
1435 * being the case, the O(N^2) nature of this search will hurt a lot,
1436 * and the data structure should be switched to an AVL tree.
1438 nextid
= h
->rh_nextentity
+ 1;
1444 h
->rh_flags
|= HANDLE_WRAPPED_ENTITY
;
1446 if (!(h
->rh_flags
& HANDLE_WRAPPED_ENTITY
))
1449 cur
= uu_list_find(h
->rh_dataels
, NULL
, &nextid
, NULL
);
1451 break; /* not in use */
1453 if (nextid
== h
->rh_nextentity
)
1454 return (0); /* wrapped around; no ids available */
1458 h
->rh_nextentity
= nextid
;
1463 handle_alloc_iterid(scf_handle_t
*h
)
1467 assert(MUTEX_HELD(&h
->rh_lock
));
1469 if (uu_list_numnodes(h
->rh_iters
) == UINT32_MAX
)
1470 return (0); /* no ids available */
1472 /* see the comment in handle_alloc_entityid */
1473 nextid
= h
->rh_nextiter
+ 1;
1479 h
->rh_flags
|= HANDLE_WRAPPED_ITER
;
1481 if (!(h
->rh_flags
& HANDLE_WRAPPED_ITER
))
1482 break; /* not yet wrapped */
1484 cur
= uu_list_find(h
->rh_iters
, NULL
, &nextid
, NULL
);
1486 break; /* not in use */
1488 if (nextid
== h
->rh_nextiter
)
1489 return (0); /* wrapped around; no ids available */
1493 h
->rh_nextiter
= nextid
;
1498 handle_next_changeid(scf_handle_t
*handle
)
1502 assert(MUTEX_HELD(&handle
->rh_lock
));
1504 nextid
= ++handle
->rh_nextchangeid
;
1506 nextid
= ++handle
->rh_nextchangeid
;
1512 * _INVALID_ARGUMENT - h is NULL
1514 * _INTERNAL - server response too big
1515 * entity already set up with different type
1519 datael_init(scf_datael_t
*dp
, scf_handle_t
*h
, uint32_t type
)
1524 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1526 uu_list_node_init(dp
, &dp
->rd_node
, datael_pool
);
1532 (void) pthread_mutex_lock(&h
->rh_lock
);
1533 if (h
->rh_flags
& HANDLE_DEAD
) {
1535 * we're in undefined territory (the user cannot use a handle
1536 * directly after it has been destroyed), but we don't want
1537 * to allow any new references to happen, so we fail here.
1539 (void) pthread_mutex_unlock(&h
->rh_lock
);
1540 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
1542 dp
->rd_entity
= handle_alloc_entityid(h
);
1543 if (dp
->rd_entity
== 0) {
1544 (void) pthread_mutex_unlock(&h
->rh_lock
);
1545 uu_list_node_fini(dp
, &dp
->rd_node
, datael_pool
);
1546 return (scf_set_error(SCF_ERROR_NO_MEMORY
));
1549 ret
= datael_attach(dp
);
1551 (void) uu_list_insert_before(h
->rh_dataels
, NULL
, dp
);
1554 uu_list_node_fini(dp
, &dp
->rd_node
, datael_pool
);
1556 (void) pthread_mutex_unlock(&h
->rh_lock
);
1562 datael_destroy(scf_datael_t
*dp
)
1564 scf_handle_t
*h
= dp
->rd_handle
;
1566 struct rep_protocol_entity_teardown request
;
1567 rep_protocol_response_t response
;
1569 (void) pthread_mutex_lock(&h
->rh_lock
);
1570 uu_list_remove(h
->rh_dataels
, dp
);
1573 if (handle_is_bound(h
)) {
1574 request
.rpr_request
= REP_PROTOCOL_ENTITY_TEARDOWN
;
1575 request
.rpr_entityid
= dp
->rd_entity
;
1577 (void) make_door_call(h
, &request
, sizeof (request
),
1578 &response
, sizeof (response
));
1580 handle_unrefed(h
); /* drops h->rh_lock */
1582 dp
->rd_handle
= NULL
;
1585 static scf_handle_t
*
1586 datael_handle(const scf_datael_t
*dp
)
1588 return (handle_get(dp
->rd_handle
));
1592 * We delay ENTITY_RESETs until right before the entity is used. By doing
1593 * them lazily, we remove quite a few unnecessary calls.
1596 datael_do_reset_locked(scf_datael_t
*dp
)
1598 scf_handle_t
*h
= dp
->rd_handle
;
1600 struct rep_protocol_entity_reset request
;
1601 rep_protocol_response_t response
;
1603 assert(MUTEX_HELD(&h
->rh_lock
));
1605 request
.rpr_request
= REP_PROTOCOL_ENTITY_RESET
;
1606 request
.rpr_entityid
= dp
->rd_entity
;
1608 (void) make_door_call(h
, &request
, sizeof (request
),
1609 &response
, sizeof (response
));
1615 datael_reset_locked(scf_datael_t
*dp
)
1617 assert(MUTEX_HELD(&dp
->rd_handle
->rh_lock
));
1622 datael_reset(scf_datael_t
*dp
)
1624 scf_handle_t
*h
= dp
->rd_handle
;
1626 (void) pthread_mutex_lock(&h
->rh_lock
);
1628 (void) pthread_mutex_unlock(&h
->rh_lock
);
1632 datael_finish_reset(const scf_datael_t
*dp_arg
)
1634 scf_datael_t
*dp
= (scf_datael_t
*)dp_arg
;
1637 datael_do_reset_locked(dp
);
1641 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
1642 * big, bad entity id, request not applicable to entity, name too long for
1643 * buffer), _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED (snaplevel is not of an
1647 datael_get_name(const scf_datael_t
*dp
, char *buf
, size_t size
, uint32_t type
)
1649 scf_handle_t
*h
= dp
->rd_handle
;
1651 struct rep_protocol_entity_name request
;
1652 struct rep_protocol_name_response response
;
1655 (void) pthread_mutex_lock(&h
->rh_lock
);
1656 request
.rpr_request
= REP_PROTOCOL_ENTITY_NAME
;
1657 request
.rpr_entityid
= dp
->rd_entity
;
1658 request
.rpr_answertype
= type
;
1660 datael_finish_reset(dp
);
1661 r
= make_door_call(h
, &request
, sizeof (request
),
1662 &response
, sizeof (response
));
1663 (void) pthread_mutex_unlock(&h
->rh_lock
);
1666 DOOR_ERRORS_BLOCK(r
);
1668 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
1669 assert(response
.rpr_response
!= REP_PROTOCOL_FAIL_BAD_REQUEST
);
1670 if (response
.rpr_response
== REP_PROTOCOL_FAIL_NOT_FOUND
)
1671 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
));
1672 return (scf_set_error(proto_error(response
.rpr_response
)));
1674 return (strlcpy(buf
, response
.rpr_name
, size
));
1678 * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
1679 * (server response too big, bad element id), _EXISTS (elements have same id),
1680 * _NOT_SET, _DELETED, _CONSTRAINT_VIOLATED, _NOT_FOUND (scope has no parent),
1684 datael_get_parent(const scf_datael_t
*dp
, scf_datael_t
*pp
)
1686 scf_handle_t
*h
= dp
->rd_handle
;
1688 struct rep_protocol_entity_parent request
;
1689 struct rep_protocol_response response
;
1693 if (h
!= pp
->rd_handle
)
1694 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
1696 (void) pthread_mutex_lock(&h
->rh_lock
);
1697 request
.rpr_request
= REP_PROTOCOL_ENTITY_GET_PARENT
;
1698 request
.rpr_entityid
= dp
->rd_entity
;
1699 request
.rpr_outid
= pp
->rd_entity
;
1701 datael_finish_reset(dp
);
1702 datael_finish_reset(pp
);
1703 r
= make_door_call(h
, &request
, sizeof (request
),
1704 &response
, sizeof (response
));
1705 (void) pthread_mutex_unlock(&h
->rh_lock
);
1708 DOOR_ERRORS_BLOCK(r
);
1710 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
1711 if (response
.rpr_response
== REP_PROTOCOL_FAIL_TYPE_MISMATCH
)
1712 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
));
1713 return (scf_set_error(proto_error(response
.rpr_response
)));
1716 return (SCF_SUCCESS
);
1720 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1721 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1722 * too big, bad id, iter already exists, element cannot have children of type,
1723 * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1724 * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1725 * _BACKEND_ACCESS, _NOT_FOUND.
1728 datael_get_child_composed_locked(const scf_datael_t
*dp
, const char *name
,
1729 uint32_t type
, scf_datael_t
*out
, scf_iter_t
*iter
)
1731 struct rep_protocol_iter_start request
;
1732 struct rep_protocol_iter_read read_request
;
1733 struct rep_protocol_response response
;
1735 scf_handle_t
*h
= dp
->rd_handle
;
1738 if (h
!= out
->rd_handle
)
1739 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
1741 if (out
->rd_type
!= type
)
1742 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1744 assert(MUTEX_HELD(&h
->rh_lock
));
1745 assert(iter
!= NULL
);
1747 scf_iter_reset_locked(iter
);
1748 iter
->iter_type
= type
;
1750 request
.rpr_request
= REP_PROTOCOL_ITER_START
;
1751 request
.rpr_iterid
= iter
->iter_id
;
1752 request
.rpr_entity
= dp
->rd_entity
;
1753 request
.rpr_itertype
= type
;
1754 request
.rpr_flags
= RP_ITER_START_EXACT
| RP_ITER_START_COMPOSED
;
1756 if (name
== NULL
|| strlcpy(request
.rpr_pattern
, name
,
1757 sizeof (request
.rpr_pattern
)) >= sizeof (request
.rpr_pattern
)) {
1758 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1761 datael_finish_reset(dp
);
1762 datael_finish_reset(out
);
1765 * We hold the handle lock across both door calls, so that they
1768 r
= make_door_call(h
, &request
, sizeof (request
),
1769 &response
, sizeof (response
));
1772 DOOR_ERRORS_BLOCK(r
);
1774 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1775 return (scf_set_error(proto_error(response
.rpr_response
)));
1777 iter
->iter_sequence
++;
1779 read_request
.rpr_request
= REP_PROTOCOL_ITER_READ
;
1780 read_request
.rpr_iterid
= iter
->iter_id
;
1781 read_request
.rpr_sequence
= iter
->iter_sequence
;
1782 read_request
.rpr_entityid
= out
->rd_entity
;
1784 r
= make_door_call(h
, &read_request
, sizeof (read_request
),
1785 &response
, sizeof (response
));
1787 scf_iter_reset_locked(iter
);
1790 DOOR_ERRORS_BLOCK(r
);
1792 if (response
.rpr_response
== REP_PROTOCOL_DONE
) {
1793 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
1796 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
1797 if (response
.rpr_response
== REP_PROTOCOL_FAIL_NOT_SET
||
1798 response
.rpr_response
== REP_PROTOCOL_FAIL_BAD_REQUEST
)
1799 return (scf_set_error(SCF_ERROR_INTERNAL
));
1800 return (scf_set_error(proto_error(response
.rpr_response
)));
1807 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1808 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1809 * too big, bad id, element cannot have children of type, type is invalid),
1810 * _NOT_SET, _DELETED, _NO_RESOURCES, _BACKEND_ACCESS.
1813 datael_get_child_locked(const scf_datael_t
*dp
, const char *name
,
1814 uint32_t type
, scf_datael_t
*out
)
1816 struct rep_protocol_entity_get_child request
;
1817 struct rep_protocol_response response
;
1819 scf_handle_t
*h
= dp
->rd_handle
;
1822 if (h
!= out
->rd_handle
)
1823 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
1825 if (out
->rd_type
!= type
)
1826 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1828 assert(MUTEX_HELD(&h
->rh_lock
));
1830 request
.rpr_request
= REP_PROTOCOL_ENTITY_GET_CHILD
;
1831 request
.rpr_entityid
= dp
->rd_entity
;
1832 request
.rpr_childid
= out
->rd_entity
;
1834 if (name
== NULL
|| strlcpy(request
.rpr_name
, name
,
1835 sizeof (request
.rpr_name
)) >= sizeof (request
.rpr_name
)) {
1836 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1839 datael_finish_reset(dp
);
1840 datael_finish_reset(out
);
1842 r
= make_door_call(h
, &request
, sizeof (request
),
1843 &response
, sizeof (response
));
1846 DOOR_ERRORS_BLOCK(r
);
1848 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1849 return (scf_set_error(proto_error(response
.rpr_response
)));
1854 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1855 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1856 * too big, bad id, iter already exists, element cannot have children of type,
1857 * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1858 * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1859 * _BACKEND_ACCESS, _NOT_FOUND.
1862 datael_get_child(const scf_datael_t
*dp
, const char *name
, uint32_t type
,
1863 scf_datael_t
*out
, boolean_t composed
)
1865 scf_handle_t
*h
= dp
->rd_handle
;
1869 scf_iter_t
*iter
= NULL
;
1872 iter
= HANDLE_HOLD_ITER(h
);
1876 case REP_PROTOCOL_ENTITY_SERVICE
:
1877 out
= &HANDLE_HOLD_SERVICE(h
)->rd_d
;
1878 held
= RH_HOLD_SERVICE
;
1881 case REP_PROTOCOL_ENTITY_INSTANCE
:
1882 out
= &HANDLE_HOLD_INSTANCE(h
)->rd_d
;
1883 held
= RH_HOLD_INSTANCE
;
1886 case REP_PROTOCOL_ENTITY_SNAPSHOT
:
1887 out
= &HANDLE_HOLD_SNAPSHOT(h
)->rd_d
;
1888 held
= RH_HOLD_SNAPSHOT
;
1891 case REP_PROTOCOL_ENTITY_SNAPLEVEL
:
1892 out
= &HANDLE_HOLD_SNAPLVL(h
)->rd_d
;
1893 held
= RH_HOLD_SNAPLVL
;
1896 case REP_PROTOCOL_ENTITY_PROPERTYGRP
:
1897 out
= &HANDLE_HOLD_PG(h
)->rd_d
;
1901 case REP_PROTOCOL_ENTITY_PROPERTY
:
1902 out
= &HANDLE_HOLD_PROPERTY(h
)->rd_d
;
1903 held
= RH_HOLD_PROPERTY
;
1912 (void) pthread_mutex_lock(&h
->rh_lock
);
1914 ret
= datael_get_child_composed_locked(dp
, name
, type
, out
,
1917 ret
= datael_get_child_locked(dp
, name
, type
, out
);
1918 (void) pthread_mutex_unlock(&h
->rh_lock
);
1921 HANDLE_RELE_ITER(h
);
1924 handle_rele_subhandles(h
, held
);
1932 * _INVALID_ARGUMENT - name is too long
1935 * cannot create children for dp's type of node
1936 * _NOT_BOUND - handle is not bound
1937 * _CONNECTION_BROKEN - server is not reachable
1938 * _INTERNAL - server response too big
1939 * dp or cp has unknown id
1940 * type is _PROPERTYGRP
1942 * dp cannot have children of type type
1943 * database is corrupt
1944 * _EXISTS - dp & cp have the same id
1945 * _EXISTS - child already exists
1946 * _DELETED - dp has been deleted
1947 * _NOT_SET - dp is reset
1949 * _PERMISSION_DENIED
1954 datael_add_child(const scf_datael_t
*dp
, const char *name
, uint32_t type
,
1957 scf_handle_t
*h
= dp
->rd_handle
;
1959 struct rep_protocol_entity_create_child request
;
1960 struct rep_protocol_response response
;
1966 case REP_PROTOCOL_ENTITY_SCOPE
:
1967 cp
= &HANDLE_HOLD_SCOPE(h
)->rd_d
;
1968 held
= RH_HOLD_SCOPE
;
1970 case REP_PROTOCOL_ENTITY_SERVICE
:
1971 cp
= &HANDLE_HOLD_SERVICE(h
)->rd_d
;
1972 held
= RH_HOLD_SERVICE
;
1974 case REP_PROTOCOL_ENTITY_INSTANCE
:
1975 cp
= &HANDLE_HOLD_INSTANCE(h
)->rd_d
;
1976 held
= RH_HOLD_INSTANCE
;
1978 case REP_PROTOCOL_ENTITY_SNAPSHOT
:
1983 assert(h
== cp
->rd_handle
);
1985 } else if (h
!= cp
->rd_handle
) {
1986 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
1989 if (strlcpy(request
.rpr_name
, name
, sizeof (request
.rpr_name
)) >=
1990 sizeof (request
.rpr_name
)) {
1991 r
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
1995 (void) pthread_mutex_lock(&h
->rh_lock
);
1996 request
.rpr_request
= REP_PROTOCOL_ENTITY_CREATE_CHILD
;
1997 request
.rpr_entityid
= dp
->rd_entity
;
1998 request
.rpr_childtype
= type
;
1999 request
.rpr_childid
= cp
->rd_entity
;
2001 datael_finish_reset(dp
);
2002 request
.rpr_changeid
= handle_next_changeid(h
);
2003 r
= make_door_call(h
, &request
, sizeof (request
),
2004 &response
, sizeof (response
));
2005 (void) pthread_mutex_unlock(&h
->rh_lock
);
2008 handle_rele_subhandles(h
, held
);
2011 DOOR_ERRORS_BLOCK(r
);
2013 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2014 return (scf_set_error(proto_error(response
.rpr_response
)));
2016 return (SCF_SUCCESS
);
2020 handle_rele_subhandles(h
, held
);
2025 datael_add_pg(const scf_datael_t
*dp
, const char *name
, const char *type
,
2026 uint32_t flags
, scf_datael_t
*cp
)
2028 scf_handle_t
*h
= dp
->rd_handle
;
2030 struct rep_protocol_entity_create_pg request
;
2031 struct rep_protocol_response response
;
2034 int holding_els
= 0;
2038 cp
= &HANDLE_HOLD_PG(h
)->rd_d
;
2039 assert(h
== cp
->rd_handle
);
2041 } else if (h
!= cp
->rd_handle
) {
2042 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2045 request
.rpr_request
= REP_PROTOCOL_ENTITY_CREATE_PG
;
2047 if (name
== NULL
|| strlcpy(request
.rpr_name
, name
,
2048 sizeof (request
.rpr_name
)) > sizeof (request
.rpr_name
)) {
2049 r
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2053 if (type
== NULL
|| strlcpy(request
.rpr_type
, type
,
2054 sizeof (request
.rpr_type
)) > sizeof (request
.rpr_type
)) {
2055 r
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2059 (void) pthread_mutex_lock(&h
->rh_lock
);
2060 request
.rpr_entityid
= dp
->rd_entity
;
2061 request
.rpr_childid
= cp
->rd_entity
;
2062 request
.rpr_flags
= flags
;
2064 datael_finish_reset(dp
);
2065 datael_finish_reset(cp
);
2066 request
.rpr_changeid
= handle_next_changeid(h
);
2067 r
= make_door_call(h
, &request
, sizeof (request
),
2068 &response
, sizeof (response
));
2069 (void) pthread_mutex_unlock(&h
->rh_lock
);
2075 DOOR_ERRORS_BLOCK(r
);
2077 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2078 return (scf_set_error(proto_error(response
.rpr_response
)));
2080 return (SCF_SUCCESS
);
2089 datael_delete(const scf_datael_t
*dp
)
2091 scf_handle_t
*h
= dp
->rd_handle
;
2093 struct rep_protocol_entity_delete request
;
2094 struct rep_protocol_response response
;
2097 (void) pthread_mutex_lock(&h
->rh_lock
);
2098 request
.rpr_request
= REP_PROTOCOL_ENTITY_DELETE
;
2099 request
.rpr_entityid
= dp
->rd_entity
;
2101 datael_finish_reset(dp
);
2102 request
.rpr_changeid
= handle_next_changeid(h
);
2103 r
= make_door_call(h
, &request
, sizeof (request
),
2104 &response
, sizeof (response
));
2105 (void) pthread_mutex_unlock(&h
->rh_lock
);
2108 DOOR_ERRORS_BLOCK(r
);
2110 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2111 return (scf_set_error(proto_error(response
.rpr_response
)));
2113 return (SCF_SUCCESS
);
2118 * _INVALID_ARGUMENT - h is NULL
2120 * _HANDLE_DESTROYED - h has been destroyed
2121 * _INTERNAL - server response too big
2122 * iter already exists
2126 scf_iter_create(scf_handle_t
*h
)
2131 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2135 iter
= uu_zalloc(sizeof (*iter
));
2137 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2141 uu_list_node_init(iter
, &iter
->iter_node
, iter_pool
);
2142 iter
->iter_handle
= h
;
2143 iter
->iter_sequence
= 1;
2144 iter
->iter_type
= REP_PROTOCOL_ENTITY_NONE
;
2146 (void) pthread_mutex_lock(&h
->rh_lock
);
2147 iter
->iter_id
= handle_alloc_iterid(h
);
2148 if (iter
->iter_id
== 0) {
2149 (void) pthread_mutex_unlock(&h
->rh_lock
);
2150 uu_list_node_fini(iter
, &iter
->iter_node
, iter_pool
);
2151 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2155 if (iter_attach(iter
) == -1) {
2156 uu_list_node_fini(iter
, &iter
->iter_node
, iter_pool
);
2157 (void) pthread_mutex_unlock(&h
->rh_lock
);
2161 (void) uu_list_insert_before(h
->rh_iters
, NULL
, iter
);
2163 (void) pthread_mutex_unlock(&h
->rh_lock
);
2168 scf_iter_handle(const scf_iter_t
*iter
)
2170 return (handle_get(iter
->iter_handle
));
2174 scf_iter_reset_locked(scf_iter_t
*iter
)
2176 struct rep_protocol_iter_request request
;
2177 struct rep_protocol_response response
;
2179 request
.rpr_request
= REP_PROTOCOL_ITER_RESET
;
2180 request
.rpr_iterid
= iter
->iter_id
;
2182 assert(MUTEX_HELD(&iter
->iter_handle
->rh_lock
));
2184 (void) make_door_call(iter
->iter_handle
,
2185 &request
, sizeof (request
), &response
, sizeof (response
));
2187 iter
->iter_type
= REP_PROTOCOL_ENTITY_NONE
;
2188 iter
->iter_sequence
= 1;
2192 scf_iter_reset(scf_iter_t
*iter
)
2194 (void) pthread_mutex_lock(&iter
->iter_handle
->rh_lock
);
2195 scf_iter_reset_locked(iter
);
2196 (void) pthread_mutex_unlock(&iter
->iter_handle
->rh_lock
);
2200 scf_iter_destroy(scf_iter_t
*iter
)
2202 scf_handle_t
*handle
;
2204 struct rep_protocol_iter_request request
;
2205 struct rep_protocol_response response
;
2210 handle
= iter
->iter_handle
;
2212 (void) pthread_mutex_lock(&handle
->rh_lock
);
2213 request
.rpr_request
= REP_PROTOCOL_ITER_TEARDOWN
;
2214 request
.rpr_iterid
= iter
->iter_id
;
2216 (void) make_door_call(handle
, &request
, sizeof (request
),
2217 &response
, sizeof (response
));
2219 uu_list_remove(handle
->rh_iters
, iter
);
2220 --handle
->rh_extrefs
;
2221 handle_unrefed(handle
); /* drops h->rh_lock */
2222 iter
->iter_handle
= NULL
;
2224 uu_list_node_fini(iter
, &iter
->iter_node
, iter_pool
);
2229 handle_get_local_scope_locked(scf_handle_t
*handle
, scf_scope_t
*out
)
2231 struct rep_protocol_entity_get request
;
2232 struct rep_protocol_name_response response
;
2235 assert(MUTEX_HELD(&handle
->rh_lock
));
2237 if (handle
!= out
->rd_d
.rd_handle
)
2238 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2240 request
.rpr_request
= REP_PROTOCOL_ENTITY_GET
;
2241 request
.rpr_entityid
= out
->rd_d
.rd_entity
;
2242 request
.rpr_object
= RP_ENTITY_GET_MOST_LOCAL_SCOPE
;
2244 datael_finish_reset(&out
->rd_d
);
2245 r
= make_door_call(handle
, &request
, sizeof (request
),
2246 &response
, sizeof (response
));
2249 DOOR_ERRORS_BLOCK(r
);
2251 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2252 return (scf_set_error(proto_error(response
.rpr_response
)));
2254 return (SCF_SUCCESS
);
2258 scf_iter_handle_scopes(scf_iter_t
*iter
, const scf_handle_t
*handle
)
2260 scf_handle_t
*h
= iter
->iter_handle
;
2262 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2264 (void) pthread_mutex_lock(&h
->rh_lock
);
2265 scf_iter_reset_locked(iter
);
2267 if (!handle_is_bound(h
)) {
2268 (void) pthread_mutex_unlock(&h
->rh_lock
);
2269 return (scf_set_error(SCF_ERROR_NOT_BOUND
));
2272 if (!handle_has_server_locked(h
)) {
2273 (void) pthread_mutex_unlock(&h
->rh_lock
);
2274 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
2277 iter
->iter_type
= REP_PROTOCOL_ENTITY_SCOPE
;
2278 iter
->iter_sequence
= 1;
2279 (void) pthread_mutex_unlock(&h
->rh_lock
);
2284 scf_iter_next_scope(scf_iter_t
*iter
, scf_scope_t
*out
)
2287 scf_handle_t
*h
= iter
->iter_handle
;
2289 if (h
!= out
->rd_d
.rd_handle
)
2290 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2292 (void) pthread_mutex_lock(&h
->rh_lock
);
2293 if (iter
->iter_type
== REP_PROTOCOL_ENTITY_NONE
) {
2294 (void) pthread_mutex_unlock(&h
->rh_lock
);
2295 return (scf_set_error(SCF_ERROR_NOT_SET
));
2297 if (iter
->iter_type
!= REP_PROTOCOL_ENTITY_SCOPE
) {
2298 (void) pthread_mutex_unlock(&h
->rh_lock
);
2299 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
2301 if (iter
->iter_sequence
== 1) {
2302 if ((ret
= handle_get_local_scope_locked(h
, out
)) ==
2304 iter
->iter_sequence
++;
2308 datael_reset_locked(&out
->rd_d
);
2311 (void) pthread_mutex_unlock(&h
->rh_lock
);
2316 scf_handle_get_scope(scf_handle_t
*h
, const char *name
, scf_scope_t
*out
)
2320 if (h
!= out
->rd_d
.rd_handle
)
2321 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2323 (void) pthread_mutex_lock(&h
->rh_lock
);
2324 if (strcmp(name
, SCF_SCOPE_LOCAL
) == 0) {
2325 ret
= handle_get_local_scope_locked(h
, out
);
2327 datael_reset_locked(&out
->rd_d
);
2328 if (uu_check_name(name
, 0) == -1)
2329 ret
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2331 ret
= scf_set_error(SCF_ERROR_NOT_FOUND
);
2333 (void) pthread_mutex_unlock(&h
->rh_lock
);
2338 datael_setup_iter(scf_iter_t
*iter
, const scf_datael_t
*dp
, uint32_t res_type
,
2341 scf_handle_t
*h
= dp
->rd_handle
;
2343 struct rep_protocol_iter_start request
;
2344 struct rep_protocol_response response
;
2348 if (h
!= iter
->iter_handle
)
2349 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2351 (void) pthread_mutex_lock(&h
->rh_lock
);
2352 scf_iter_reset_locked(iter
);
2353 iter
->iter_type
= res_type
;
2355 request
.rpr_request
= REP_PROTOCOL_ITER_START
;
2356 request
.rpr_iterid
= iter
->iter_id
;
2357 request
.rpr_entity
= dp
->rd_entity
;
2358 request
.rpr_itertype
= res_type
;
2359 request
.rpr_flags
= RP_ITER_START_ALL
|
2360 (composed
? RP_ITER_START_COMPOSED
: 0);
2361 request
.rpr_pattern
[0] = 0;
2363 datael_finish_reset(dp
);
2364 r
= make_door_call(h
, &request
, sizeof (request
),
2365 &response
, sizeof (response
));
2368 (void) pthread_mutex_unlock(&h
->rh_lock
);
2369 DOOR_ERRORS_BLOCK(r
);
2371 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
2372 (void) pthread_mutex_unlock(&h
->rh_lock
);
2373 return (scf_set_error(proto_error(response
.rpr_response
)));
2375 iter
->iter_sequence
++;
2376 (void) pthread_mutex_unlock(&h
->rh_lock
);
2377 return (SCF_SUCCESS
);
2381 datael_setup_iter_pgtyped(scf_iter_t
*iter
, const scf_datael_t
*dp
,
2382 const char *pgtype
, boolean_t composed
)
2384 scf_handle_t
*h
= dp
->rd_handle
;
2386 struct rep_protocol_iter_start request
;
2387 struct rep_protocol_response response
;
2391 if (h
!= iter
->iter_handle
)
2392 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2394 if (pgtype
== NULL
|| strlcpy(request
.rpr_pattern
, pgtype
,
2395 sizeof (request
.rpr_pattern
)) >= sizeof (request
.rpr_pattern
)) {
2396 scf_iter_reset(iter
);
2397 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
2400 (void) pthread_mutex_lock(&h
->rh_lock
);
2401 request
.rpr_request
= REP_PROTOCOL_ITER_START
;
2402 request
.rpr_iterid
= iter
->iter_id
;
2403 request
.rpr_entity
= dp
->rd_entity
;
2404 request
.rpr_itertype
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
2405 request
.rpr_flags
= RP_ITER_START_PGTYPE
|
2406 (composed
? RP_ITER_START_COMPOSED
: 0);
2408 datael_finish_reset(dp
);
2409 scf_iter_reset_locked(iter
);
2410 iter
->iter_type
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
2412 r
= make_door_call(h
, &request
, sizeof (request
),
2413 &response
, sizeof (response
));
2416 (void) pthread_mutex_unlock(&h
->rh_lock
);
2418 DOOR_ERRORS_BLOCK(r
);
2420 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
2421 (void) pthread_mutex_unlock(&h
->rh_lock
);
2422 return (scf_set_error(proto_error(response
.rpr_response
)));
2424 iter
->iter_sequence
++;
2425 (void) pthread_mutex_unlock(&h
->rh_lock
);
2426 return (SCF_SUCCESS
);
2430 datael_iter_next(scf_iter_t
*iter
, scf_datael_t
*out
)
2432 scf_handle_t
*h
= iter
->iter_handle
;
2434 struct rep_protocol_iter_read request
;
2435 struct rep_protocol_response response
;
2438 if (h
!= out
->rd_handle
)
2439 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2441 (void) pthread_mutex_lock(&h
->rh_lock
);
2442 if (iter
->iter_type
== REP_PROTOCOL_ENTITY_NONE
||
2443 iter
->iter_sequence
== 1) {
2444 (void) pthread_mutex_unlock(&h
->rh_lock
);
2445 return (scf_set_error(SCF_ERROR_NOT_SET
));
2448 if (out
->rd_type
!= iter
->iter_type
) {
2449 (void) pthread_mutex_unlock(&h
->rh_lock
);
2450 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
2453 request
.rpr_request
= REP_PROTOCOL_ITER_READ
;
2454 request
.rpr_iterid
= iter
->iter_id
;
2455 request
.rpr_sequence
= iter
->iter_sequence
;
2456 request
.rpr_entityid
= out
->rd_entity
;
2458 datael_finish_reset(out
);
2459 r
= make_door_call(h
, &request
, sizeof (request
),
2460 &response
, sizeof (response
));
2463 (void) pthread_mutex_unlock(&h
->rh_lock
);
2464 DOOR_ERRORS_BLOCK(r
);
2467 if (response
.rpr_response
== REP_PROTOCOL_DONE
) {
2468 (void) pthread_mutex_unlock(&h
->rh_lock
);
2471 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
2472 (void) pthread_mutex_unlock(&h
->rh_lock
);
2473 return (scf_set_error(proto_error(response
.rpr_response
)));
2475 iter
->iter_sequence
++;
2476 (void) pthread_mutex_unlock(&h
->rh_lock
);
2482 scf_iter_scope_services(scf_iter_t
*iter
, const scf_scope_t
*s
)
2484 return (datael_setup_iter(iter
, &s
->rd_d
,
2485 REP_PROTOCOL_ENTITY_SERVICE
, 0));
2489 scf_iter_next_service(scf_iter_t
*iter
, scf_service_t
*out
)
2491 return (datael_iter_next(iter
, &out
->rd_d
));
2495 scf_iter_service_instances(scf_iter_t
*iter
, const scf_service_t
*svc
)
2497 return (datael_setup_iter(iter
, &svc
->rd_d
,
2498 REP_PROTOCOL_ENTITY_INSTANCE
, 0));
2502 scf_iter_next_instance(scf_iter_t
*iter
, scf_instance_t
*out
)
2504 return (datael_iter_next(iter
, &out
->rd_d
));
2508 scf_iter_service_pgs(scf_iter_t
*iter
, const scf_service_t
*svc
)
2510 return (datael_setup_iter(iter
, &svc
->rd_d
,
2511 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 0));
2515 scf_iter_service_pgs_typed(scf_iter_t
*iter
, const scf_service_t
*svc
,
2518 return (datael_setup_iter_pgtyped(iter
, &svc
->rd_d
, type
, 0));
2522 scf_iter_instance_snapshots(scf_iter_t
*iter
, const scf_instance_t
*inst
)
2524 return (datael_setup_iter(iter
, &inst
->rd_d
,
2525 REP_PROTOCOL_ENTITY_SNAPSHOT
, 0));
2529 scf_iter_next_snapshot(scf_iter_t
*iter
, scf_snapshot_t
*out
)
2531 return (datael_iter_next(iter
, &out
->rd_d
));
2535 scf_iter_instance_pgs(scf_iter_t
*iter
, const scf_instance_t
*inst
)
2537 return (datael_setup_iter(iter
, &inst
->rd_d
,
2538 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 0));
2542 scf_iter_instance_pgs_typed(scf_iter_t
*iter
, const scf_instance_t
*inst
,
2545 return (datael_setup_iter_pgtyped(iter
, &inst
->rd_d
, type
, 0));
2549 scf_iter_instance_pgs_composed(scf_iter_t
*iter
, const scf_instance_t
*inst
,
2550 const scf_snapshot_t
*snap
)
2552 if (snap
!= NULL
&& inst
->rd_d
.rd_handle
!= snap
->rd_d
.rd_handle
)
2553 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2555 return (datael_setup_iter(iter
, snap
? &snap
->rd_d
: &inst
->rd_d
,
2556 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 1));
2560 scf_iter_instance_pgs_typed_composed(scf_iter_t
*iter
,
2561 const scf_instance_t
*inst
, const scf_snapshot_t
*snap
, const char *type
)
2563 if (snap
!= NULL
&& inst
->rd_d
.rd_handle
!= snap
->rd_d
.rd_handle
)
2564 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2566 return (datael_setup_iter_pgtyped(iter
,
2567 snap
? &snap
->rd_d
: &inst
->rd_d
, type
, 1));
2571 scf_iter_snaplevel_pgs(scf_iter_t
*iter
, const scf_snaplevel_t
*inst
)
2573 return (datael_setup_iter(iter
, &inst
->rd_d
,
2574 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 0));
2578 scf_iter_snaplevel_pgs_typed(scf_iter_t
*iter
, const scf_snaplevel_t
*inst
,
2581 return (datael_setup_iter_pgtyped(iter
, &inst
->rd_d
, type
, 0));
2585 scf_iter_next_pg(scf_iter_t
*iter
, scf_propertygroup_t
*out
)
2587 return (datael_iter_next(iter
, &out
->rd_d
));
2591 scf_iter_pg_properties(scf_iter_t
*iter
, const scf_propertygroup_t
*pg
)
2593 return (datael_setup_iter(iter
, &pg
->rd_d
,
2594 REP_PROTOCOL_ENTITY_PROPERTY
, 0));
2598 scf_iter_next_property(scf_iter_t
*iter
, scf_property_t
*out
)
2600 return (datael_iter_next(iter
, &out
->rd_d
));
2605 * _INVALID_ARGUMENT - handle is NULL
2606 * _INTERNAL - server response too big
2607 * entity already set up with different type
2612 scf_scope_create(scf_handle_t
*handle
)
2616 ret
= uu_zalloc(sizeof (*ret
));
2618 if (datael_init(&ret
->rd_d
, handle
,
2619 REP_PROTOCOL_ENTITY_SCOPE
) == -1) {
2624 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2631 scf_scope_handle(const scf_scope_t
*val
)
2633 return (datael_handle(&val
->rd_d
));
2637 scf_scope_destroy(scf_scope_t
*val
)
2642 datael_destroy(&val
->rd_d
);
2647 scf_scope_get_name(const scf_scope_t
*rep
, char *out
, size_t len
)
2649 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2654 scf_scope_get_parent(const scf_scope_t
*child
, scf_scope_t
*parent
)
2658 /* fake up the side-effects */
2659 datael_reset(&parent
->rd_d
);
2660 if (scf_scope_get_name(child
, name
, sizeof (name
)) < 0)
2662 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
2666 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2667 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2670 scf_service_create(scf_handle_t
*handle
)
2673 ret
= uu_zalloc(sizeof (*ret
));
2675 if (datael_init(&ret
->rd_d
, handle
,
2676 REP_PROTOCOL_ENTITY_SERVICE
) == -1) {
2681 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2693 * _CONNECTION_BROKEN
2699 * _PERMISSION_DENIED
2704 scf_scope_add_service(const scf_scope_t
*scope
, const char *name
,
2707 return (datael_add_child(&scope
->rd_d
, name
,
2708 REP_PROTOCOL_ENTITY_SERVICE
, (svc
!= NULL
)? &svc
->rd_d
: NULL
));
2712 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2713 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2714 * _BACKEND_ACCESS, _NOT_FOUND.
2717 scf_scope_get_service(const scf_scope_t
*s
, const char *name
,
2720 return (datael_get_child(&s
->rd_d
, name
, REP_PROTOCOL_ENTITY_SERVICE
,
2721 svc
? &svc
->rd_d
: NULL
, 0));
2725 scf_service_handle(const scf_service_t
*val
)
2727 return (datael_handle(&val
->rd_d
));
2731 scf_service_delete(scf_service_t
*svc
)
2733 return (datael_delete(&svc
->rd_d
));
2737 scf_instance_delete(scf_instance_t
*inst
)
2739 return (datael_delete(&inst
->rd_d
));
2743 scf_pg_delete(scf_propertygroup_t
*pg
)
2745 return (datael_delete(&pg
->rd_d
));
2749 _scf_snapshot_delete(scf_snapshot_t
*snap
)
2751 return (datael_delete(&snap
->rd_d
));
2759 * _CONNECTION_BROKEN
2765 * _PERMISSION_DENIED
2770 scf_service_add_instance(const scf_service_t
*svc
, const char *name
,
2771 scf_instance_t
*instance
)
2773 return (datael_add_child(&svc
->rd_d
, name
,
2774 REP_PROTOCOL_ENTITY_INSTANCE
,
2775 (instance
!= NULL
)? &instance
->rd_d
: NULL
));
2780 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2781 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2782 * _BACKEND_ACCESS, _NOT_FOUND.
2785 scf_service_get_instance(const scf_service_t
*svc
, const char *name
,
2786 scf_instance_t
*inst
)
2788 return (datael_get_child(&svc
->rd_d
, name
, REP_PROTOCOL_ENTITY_INSTANCE
,
2789 inst
? &inst
->rd_d
: NULL
, 0));
2793 scf_service_add_pg(const scf_service_t
*svc
, const char *name
,
2794 const char *type
, uint32_t flags
, scf_propertygroup_t
*pg
)
2796 return (datael_add_pg(&svc
->rd_d
, name
, type
, flags
,
2797 (pg
!= NULL
)?&pg
->rd_d
: NULL
));
2801 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2802 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2803 * _BACKEND_ACCESS, _NOT_FOUND.
2806 scf_service_get_pg(const scf_service_t
*svc
, const char *name
,
2807 scf_propertygroup_t
*pg
)
2809 return (datael_get_child(&svc
->rd_d
, name
,
2810 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 0));
2814 scf_instance_add_pg(const scf_instance_t
*inst
, const char *name
,
2815 const char *type
, uint32_t flags
, scf_propertygroup_t
*pg
)
2817 return (datael_add_pg(&inst
->rd_d
, name
, type
, flags
,
2818 (pg
!= NULL
)?&pg
->rd_d
: NULL
));
2822 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2823 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2824 * _BACKEND_ACCESS, _NOT_FOUND.
2827 scf_instance_get_snapshot(const scf_instance_t
*inst
, const char *name
,
2830 return (datael_get_child(&inst
->rd_d
, name
,
2831 REP_PROTOCOL_ENTITY_SNAPSHOT
, pg
? &pg
->rd_d
: NULL
, 0));
2835 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2836 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2837 * _BACKEND_ACCESS, _NOT_FOUND.
2840 scf_instance_get_pg(const scf_instance_t
*inst
, const char *name
,
2841 scf_propertygroup_t
*pg
)
2843 return (datael_get_child(&inst
->rd_d
, name
,
2844 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 0));
2848 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2849 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2850 * _BACKEND_ACCESS, _NOT_FOUND.
2853 scf_instance_get_pg_composed(const scf_instance_t
*inst
,
2854 const scf_snapshot_t
*snap
, const char *name
, scf_propertygroup_t
*pg
)
2856 if (snap
!= NULL
&& inst
->rd_d
.rd_handle
!= snap
->rd_d
.rd_handle
)
2857 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2859 return (datael_get_child(snap
? &snap
->rd_d
: &inst
->rd_d
, name
,
2860 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 1));
2864 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2865 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2866 * _BACKEND_ACCESS, _NOT_FOUND.
2869 scf_pg_get_property(const scf_propertygroup_t
*pg
, const char *name
,
2870 scf_property_t
*prop
)
2872 return (datael_get_child(&pg
->rd_d
, name
, REP_PROTOCOL_ENTITY_PROPERTY
,
2873 prop
? &prop
->rd_d
: NULL
, 0));
2877 scf_service_destroy(scf_service_t
*val
)
2882 datael_destroy(&val
->rd_d
);
2887 scf_service_get_name(const scf_service_t
*rep
, char *out
, size_t len
)
2889 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2893 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2894 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2897 scf_instance_create(scf_handle_t
*handle
)
2899 scf_instance_t
*ret
;
2901 ret
= uu_zalloc(sizeof (*ret
));
2903 if (datael_init(&ret
->rd_d
, handle
,
2904 REP_PROTOCOL_ENTITY_INSTANCE
) == -1) {
2909 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2916 scf_instance_handle(const scf_instance_t
*val
)
2918 return (datael_handle(&val
->rd_d
));
2922 scf_instance_destroy(scf_instance_t
*val
)
2927 datael_destroy(&val
->rd_d
);
2932 scf_instance_get_name(const scf_instance_t
*rep
, char *out
, size_t len
)
2934 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2938 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2939 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2942 scf_snapshot_create(scf_handle_t
*handle
)
2944 scf_snapshot_t
*ret
;
2946 ret
= uu_zalloc(sizeof (*ret
));
2948 if (datael_init(&ret
->rd_d
, handle
,
2949 REP_PROTOCOL_ENTITY_SNAPSHOT
) == -1) {
2954 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2961 scf_snapshot_handle(const scf_snapshot_t
*val
)
2963 return (datael_handle(&val
->rd_d
));
2967 scf_snapshot_destroy(scf_snapshot_t
*val
)
2972 datael_destroy(&val
->rd_d
);
2977 scf_snapshot_get_name(const scf_snapshot_t
*rep
, char *out
, size_t len
)
2979 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2983 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2984 * (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY.
2987 scf_snaplevel_create(scf_handle_t
*handle
)
2989 scf_snaplevel_t
*ret
;
2991 ret
= uu_zalloc(sizeof (*ret
));
2993 if (datael_init(&ret
->rd_d
, handle
,
2994 REP_PROTOCOL_ENTITY_SNAPLEVEL
) == -1) {
2999 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3006 scf_snaplevel_handle(const scf_snaplevel_t
*val
)
3008 return (datael_handle(&val
->rd_d
));
3012 scf_snaplevel_destroy(scf_snaplevel_t
*val
)
3017 datael_destroy(&val
->rd_d
);
3022 scf_snaplevel_get_scope_name(const scf_snaplevel_t
*rep
, char *out
, size_t len
)
3024 return (datael_get_name(&rep
->rd_d
, out
, len
,
3025 RP_ENTITY_NAME_SNAPLEVEL_SCOPE
));
3029 scf_snaplevel_get_service_name(const scf_snaplevel_t
*rep
, char *out
,
3032 return (datael_get_name(&rep
->rd_d
, out
, len
,
3033 RP_ENTITY_NAME_SNAPLEVEL_SERVICE
));
3037 scf_snaplevel_get_instance_name(const scf_snaplevel_t
*rep
, char *out
,
3040 return (datael_get_name(&rep
->rd_d
, out
, len
,
3041 RP_ENTITY_NAME_SNAPLEVEL_INSTANCE
));
3045 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3046 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3047 * _BACKEND_ACCESS, _NOT_FOUND.
3050 scf_snaplevel_get_pg(const scf_snaplevel_t
*snap
, const char *name
,
3051 scf_propertygroup_t
*pg
)
3053 return (datael_get_child(&snap
->rd_d
, name
,
3054 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 0));
3058 snaplevel_next(const scf_datael_t
*src
, scf_snaplevel_t
*dst_arg
)
3060 scf_handle_t
*h
= src
->rd_handle
;
3061 scf_snaplevel_t
*dst
= dst_arg
;
3062 struct rep_protocol_entity_pair request
;
3063 struct rep_protocol_response response
;
3067 if (h
!= dst
->rd_d
.rd_handle
)
3068 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3070 if (src
== &dst
->rd_d
) {
3072 dst
= HANDLE_HOLD_SNAPLVL(h
);
3074 (void) pthread_mutex_lock(&h
->rh_lock
);
3075 request
.rpr_request
= REP_PROTOCOL_NEXT_SNAPLEVEL
;
3076 request
.rpr_entity_src
= src
->rd_entity
;
3077 request
.rpr_entity_dst
= dst
->rd_d
.rd_entity
;
3079 datael_finish_reset(src
);
3080 datael_finish_reset(&dst
->rd_d
);
3081 r
= make_door_call(h
, &request
, sizeof (request
),
3082 &response
, sizeof (response
));
3084 * if we succeeded, we need to swap dst and dst_arg's identity. We
3085 * take advantage of the fact that the only in-library knowledge is
3088 if (dups
&& r
>= 0 &&
3089 (response
.rpr_response
== REP_PROTOCOL_SUCCESS
||
3090 response
.rpr_response
== REP_PROTOCOL_DONE
)) {
3091 int entity
= dst
->rd_d
.rd_entity
;
3093 dst
->rd_d
.rd_entity
= dst_arg
->rd_d
.rd_entity
;
3094 dst_arg
->rd_d
.rd_entity
= entity
;
3096 (void) pthread_mutex_unlock(&h
->rh_lock
);
3099 HANDLE_RELE_SNAPLVL(h
);
3102 DOOR_ERRORS_BLOCK(r
);
3104 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
3105 response
.rpr_response
!= REP_PROTOCOL_DONE
) {
3106 return (scf_set_error(proto_error(response
.rpr_response
)));
3109 return (response
.rpr_response
== REP_PROTOCOL_SUCCESS
) ?
3110 SCF_SUCCESS
: SCF_COMPLETE
;
3113 int scf_snapshot_get_base_snaplevel(const scf_snapshot_t
*base
,
3114 scf_snaplevel_t
*out
)
3116 return (snaplevel_next(&base
->rd_d
, out
));
3119 int scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t
*base
,
3120 scf_snaplevel_t
*out
)
3122 return (snaplevel_next(&base
->rd_d
, out
));
3126 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3127 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3129 scf_propertygroup_t
*
3130 scf_pg_create(scf_handle_t
*handle
)
3132 scf_propertygroup_t
*ret
;
3133 ret
= uu_zalloc(sizeof (*ret
));
3135 if (datael_init(&ret
->rd_d
, handle
,
3136 REP_PROTOCOL_ENTITY_PROPERTYGRP
) == -1) {
3141 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3148 scf_pg_handle(const scf_propertygroup_t
*val
)
3150 return (datael_handle(&val
->rd_d
));
3154 scf_pg_destroy(scf_propertygroup_t
*val
)
3159 datael_destroy(&val
->rd_d
);
3164 scf_pg_get_name(const scf_propertygroup_t
*pg
, char *out
, size_t len
)
3166 return (datael_get_name(&pg
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
3170 scf_pg_get_type(const scf_propertygroup_t
*pg
, char *out
, size_t len
)
3172 return (datael_get_name(&pg
->rd_d
, out
, len
, RP_ENTITY_NAME_PGTYPE
));
3176 scf_pg_get_flags(const scf_propertygroup_t
*pg
, uint32_t *out
)
3178 char buf
[REP_PROTOCOL_NAME_LEN
];
3181 res
= datael_get_name(&pg
->rd_d
, buf
, sizeof (buf
),
3182 RP_ENTITY_NAME_PGFLAGS
);
3187 if (uu_strtouint(buf
, out
, sizeof (*out
), 0, 0, UINT32_MAX
) == -1)
3188 return (scf_set_error(SCF_ERROR_INTERNAL
));
3194 datael_update(scf_datael_t
*dp
)
3196 scf_handle_t
*h
= dp
->rd_handle
;
3198 struct rep_protocol_entity_update request
;
3199 struct rep_protocol_response response
;
3203 (void) pthread_mutex_lock(&h
->rh_lock
);
3204 request
.rpr_request
= REP_PROTOCOL_ENTITY_UPDATE
;
3205 request
.rpr_entityid
= dp
->rd_entity
;
3207 datael_finish_reset(dp
);
3208 request
.rpr_changeid
= handle_next_changeid(h
);
3210 r
= make_door_call(h
, &request
, sizeof (request
),
3211 &response
, sizeof (response
));
3212 (void) pthread_mutex_unlock(&h
->rh_lock
);
3215 DOOR_ERRORS_BLOCK(r
);
3218 * This should never happen but if it does something has
3219 * gone terribly wrong and we should abort.
3221 if (response
.rpr_response
== REP_PROTOCOL_FAIL_BAD_REQUEST
)
3224 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
3225 response
.rpr_response
!= REP_PROTOCOL_DONE
) {
3226 return (scf_set_error(proto_error(response
.rpr_response
)));
3229 return (response
.rpr_response
== REP_PROTOCOL_SUCCESS
) ?
3230 SCF_SUCCESS
: SCF_COMPLETE
;
3234 scf_pg_update(scf_propertygroup_t
*pg
)
3236 return (datael_update(&pg
->rd_d
));
3240 scf_snapshot_update(scf_snapshot_t
*snap
)
3242 return (datael_update(&snap
->rd_d
));
3246 _scf_pg_wait(scf_propertygroup_t
*pg
, int timeout
)
3248 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
3250 struct rep_protocol_propertygrp_request request
;
3251 struct rep_protocol_response response
;
3253 struct pollfd pollfd
;
3257 (void) pthread_mutex_lock(&h
->rh_lock
);
3258 request
.rpr_request
= REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT
;
3259 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
3261 datael_finish_reset(&pg
->rd_d
);
3262 if (!handle_is_bound(h
)) {
3263 (void) pthread_mutex_unlock(&h
->rh_lock
);
3264 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
3266 r
= make_door_call_retfd(h
->rh_doorfd
, &request
, sizeof (request
),
3267 &response
, sizeof (response
), &pollfd
.fd
);
3268 (void) pthread_mutex_unlock(&h
->rh_lock
);
3271 DOOR_ERRORS_BLOCK(r
);
3273 assert((response
.rpr_response
== REP_PROTOCOL_SUCCESS
) ==
3276 if (response
.rpr_response
== REP_PROTOCOL_FAIL_NOT_LATEST
)
3277 return (SCF_SUCCESS
);
3279 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3280 return (scf_set_error(proto_error(response
.rpr_response
)));
3285 r
= poll(&pollfd
, 1, timeout
* MILLISEC
);
3287 (void) close(pollfd
.fd
);
3288 return (pollfd
.revents
? SCF_SUCCESS
: SCF_COMPLETE
);
3292 scf_notify_add_pattern(scf_handle_t
*h
, int type
, const char *name
)
3294 struct rep_protocol_notify_request request
;
3295 struct rep_protocol_response response
;
3298 (void) pthread_mutex_lock(&h
->rh_lock
);
3299 request
.rpr_request
= REP_PROTOCOL_CLIENT_ADD_NOTIFY
;
3300 request
.rpr_type
= type
;
3301 (void) strlcpy(request
.rpr_pattern
, name
, sizeof (request
.rpr_pattern
));
3303 r
= make_door_call(h
, &request
, sizeof (request
),
3304 &response
, sizeof (response
));
3305 (void) pthread_mutex_unlock(&h
->rh_lock
);
3308 DOOR_ERRORS_BLOCK(r
);
3310 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3311 return (scf_set_error(proto_error(response
.rpr_response
)));
3313 return (SCF_SUCCESS
);
3317 _scf_notify_add_pgname(scf_handle_t
*h
, const char *name
)
3319 return (scf_notify_add_pattern(h
, REP_PROTOCOL_NOTIFY_PGNAME
, name
));
3323 _scf_notify_add_pgtype(scf_handle_t
*h
, const char *type
)
3325 return (scf_notify_add_pattern(h
, REP_PROTOCOL_NOTIFY_PGTYPE
, type
));
3329 _scf_notify_wait(scf_propertygroup_t
*pg
, char *out
, size_t sz
)
3331 struct rep_protocol_wait_request request
;
3332 struct rep_protocol_fmri_response response
;
3334 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
3339 (void) pthread_mutex_lock(&h
->rh_lock
);
3340 datael_finish_reset(&pg
->rd_d
);
3341 if (!handle_is_bound(h
)) {
3342 (void) pthread_mutex_unlock(&h
->rh_lock
);
3343 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
3347 assert(h
->rh_fd_users
> 0);
3349 request
.rpr_request
= REP_PROTOCOL_CLIENT_WAIT
;
3350 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
3351 (void) pthread_mutex_unlock(&h
->rh_lock
);
3353 r
= make_door_call_retfd(fd
, &request
, sizeof (request
),
3354 &response
, sizeof (response
), &dummy
);
3356 (void) pthread_mutex_lock(&h
->rh_lock
);
3357 assert(h
->rh_fd_users
> 0);
3358 if (--h
->rh_fd_users
== 0) {
3359 (void) pthread_cond_broadcast(&h
->rh_cv
);
3361 * check for a delayed close, now that there are no other
3364 if (h
->rh_doorfd_old
!= -1) {
3365 assert(h
->rh_doorfd
== -1);
3366 assert(fd
== h
->rh_doorfd_old
);
3367 (void) close(h
->rh_doorfd_old
);
3368 h
->rh_doorfd_old
= -1;
3371 handle_unrefed(h
); /* drops h->rh_lock */
3374 DOOR_ERRORS_BLOCK(r
);
3376 if (response
.rpr_response
== REP_PROTOCOL_DONE
)
3377 return (scf_set_error(SCF_ERROR_NOT_SET
));
3379 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3380 return (scf_set_error(proto_error(response
.rpr_response
)));
3382 /* the following will be non-zero for delete notifications */
3383 return (strlcpy(out
, response
.rpr_fmri
, sz
));
3387 _scf_snapshot_take(scf_instance_t
*inst
, const char *name
,
3388 scf_snapshot_t
*snap
, int flags
)
3390 scf_handle_t
*h
= inst
->rd_d
.rd_handle
;
3392 struct rep_protocol_snapshot_take request
;
3393 struct rep_protocol_response response
;
3397 if (h
!= snap
->rd_d
.rd_handle
)
3398 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3400 if (strlcpy(request
.rpr_name
, (name
!= NULL
)? name
: "",
3401 sizeof (request
.rpr_name
)) >= sizeof (request
.rpr_name
))
3402 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3404 (void) pthread_mutex_lock(&h
->rh_lock
);
3405 request
.rpr_request
= REP_PROTOCOL_SNAPSHOT_TAKE
;
3406 request
.rpr_entityid_src
= inst
->rd_d
.rd_entity
;
3407 request
.rpr_entityid_dest
= snap
->rd_d
.rd_entity
;
3408 request
.rpr_flags
= flags
;
3410 datael_finish_reset(&inst
->rd_d
);
3411 datael_finish_reset(&snap
->rd_d
);
3413 r
= make_door_call(h
, &request
, sizeof (request
),
3414 &response
, sizeof (response
));
3415 (void) pthread_mutex_unlock(&h
->rh_lock
);
3418 DOOR_ERRORS_BLOCK(r
);
3420 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3421 return (scf_set_error(proto_error(response
.rpr_response
)));
3423 return (SCF_SUCCESS
);
3427 _scf_snapshot_take_new_named(scf_instance_t
*inst
,
3428 const char *svcname
, const char *instname
, const char *snapname
,
3429 scf_snapshot_t
*snap
)
3431 scf_handle_t
*h
= inst
->rd_d
.rd_handle
;
3433 struct rep_protocol_snapshot_take_named request
;
3434 struct rep_protocol_response response
;
3438 if (h
!= snap
->rd_d
.rd_handle
)
3439 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3441 if (strlcpy(request
.rpr_svcname
, svcname
,
3442 sizeof (request
.rpr_svcname
)) >= sizeof (request
.rpr_svcname
))
3443 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3445 if (strlcpy(request
.rpr_instname
, instname
,
3446 sizeof (request
.rpr_instname
)) >= sizeof (request
.rpr_instname
))
3447 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3449 if (strlcpy(request
.rpr_name
, snapname
,
3450 sizeof (request
.rpr_name
)) >= sizeof (request
.rpr_name
))
3451 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3453 (void) pthread_mutex_lock(&h
->rh_lock
);
3454 request
.rpr_request
= REP_PROTOCOL_SNAPSHOT_TAKE_NAMED
;
3455 request
.rpr_entityid_src
= inst
->rd_d
.rd_entity
;
3456 request
.rpr_entityid_dest
= snap
->rd_d
.rd_entity
;
3458 datael_finish_reset(&inst
->rd_d
);
3459 datael_finish_reset(&snap
->rd_d
);
3461 r
= make_door_call(h
, &request
, sizeof (request
),
3462 &response
, sizeof (response
));
3463 (void) pthread_mutex_unlock(&h
->rh_lock
);
3466 DOOR_ERRORS_BLOCK(r
);
3468 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
3469 assert(response
.rpr_response
!=
3470 REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
3471 return (scf_set_error(proto_error(response
.rpr_response
)));
3474 return (SCF_SUCCESS
);
3478 _scf_snapshot_take_new(scf_instance_t
*inst
, const char *name
,
3479 scf_snapshot_t
*snap
)
3481 return (_scf_snapshot_take(inst
, name
, snap
, REP_SNAPSHOT_NEW
));
3485 _scf_snapshot_take_attach(scf_instance_t
*inst
, scf_snapshot_t
*snap
)
3487 return (_scf_snapshot_take(inst
, NULL
, snap
, REP_SNAPSHOT_ATTACH
));
3491 _scf_snapshot_attach(scf_snapshot_t
*src
, scf_snapshot_t
*dest
)
3493 scf_handle_t
*h
= dest
->rd_d
.rd_handle
;
3495 struct rep_protocol_snapshot_attach request
;
3496 struct rep_protocol_response response
;
3500 if (h
!= src
->rd_d
.rd_handle
)
3501 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3503 (void) pthread_mutex_lock(&h
->rh_lock
);
3504 request
.rpr_request
= REP_PROTOCOL_SNAPSHOT_ATTACH
;
3505 request
.rpr_entityid_src
= src
->rd_d
.rd_entity
;
3506 request
.rpr_entityid_dest
= dest
->rd_d
.rd_entity
;
3508 datael_finish_reset(&src
->rd_d
);
3509 datael_finish_reset(&dest
->rd_d
);
3511 r
= make_door_call(h
, &request
, sizeof (request
),
3512 &response
, sizeof (response
));
3513 (void) pthread_mutex_unlock(&h
->rh_lock
);
3516 DOOR_ERRORS_BLOCK(r
);
3518 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3519 return (scf_set_error(proto_error(response
.rpr_response
)));
3521 return (SCF_SUCCESS
);
3525 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3526 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3529 scf_property_create(scf_handle_t
*handle
)
3531 scf_property_t
*ret
;
3532 ret
= uu_zalloc(sizeof (*ret
));
3534 if (datael_init(&ret
->rd_d
, handle
,
3535 REP_PROTOCOL_ENTITY_PROPERTY
) == -1) {
3540 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3547 scf_property_handle(const scf_property_t
*val
)
3549 return (datael_handle(&val
->rd_d
));
3553 scf_property_destroy(scf_property_t
*val
)
3558 datael_destroy(&val
->rd_d
);
3563 property_type_locked(const scf_property_t
*prop
,
3564 rep_protocol_value_type_t
*out
)
3566 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
3568 struct rep_protocol_property_request request
;
3569 struct rep_protocol_integer_response response
;
3573 assert(MUTEX_HELD(&h
->rh_lock
));
3575 request
.rpr_request
= REP_PROTOCOL_PROPERTY_GET_TYPE
;
3576 request
.rpr_entityid
= prop
->rd_d
.rd_entity
;
3578 datael_finish_reset(&prop
->rd_d
);
3579 r
= make_door_call(h
, &request
, sizeof (request
),
3580 &response
, sizeof (response
));
3583 DOOR_ERRORS_BLOCK(r
);
3585 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
||
3586 r
< sizeof (response
)) {
3587 return (scf_set_error(proto_error(response
.rpr_response
)));
3589 *out
= response
.rpr_value
;
3590 return (SCF_SUCCESS
);
3594 scf_property_type(const scf_property_t
*prop
, scf_type_t
*out
)
3596 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
3597 rep_protocol_value_type_t out_raw
;
3600 (void) pthread_mutex_lock(&h
->rh_lock
);
3601 ret
= property_type_locked(prop
, &out_raw
);
3602 (void) pthread_mutex_unlock(&h
->rh_lock
);
3604 if (ret
== SCF_SUCCESS
)
3605 *out
= scf_protocol_type_to_type(out_raw
);
3611 scf_property_is_type(const scf_property_t
*prop
, scf_type_t base_arg
)
3613 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
3614 rep_protocol_value_type_t base
= scf_type_to_protocol_type(base_arg
);
3615 rep_protocol_value_type_t type
;
3618 if (base
== REP_PROTOCOL_TYPE_INVALID
)
3619 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3621 (void) pthread_mutex_lock(&h
->rh_lock
);
3622 ret
= property_type_locked(prop
, &type
);
3623 (void) pthread_mutex_unlock(&h
->rh_lock
);
3625 if (ret
== SCF_SUCCESS
) {
3626 if (!scf_is_compatible_protocol_type(base
, type
))
3627 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
3633 scf_is_compatible_type(scf_type_t base_arg
, scf_type_t type_arg
)
3635 rep_protocol_value_type_t base
= scf_type_to_protocol_type(base_arg
);
3636 rep_protocol_value_type_t type
= scf_type_to_protocol_type(type_arg
);
3638 if (base
== REP_PROTOCOL_TYPE_INVALID
||
3639 type
== REP_PROTOCOL_TYPE_INVALID
)
3640 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3642 if (!scf_is_compatible_protocol_type(base
, type
))
3643 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
3645 return (SCF_SUCCESS
);
3649 scf_property_get_name(const scf_property_t
*prop
, char *out
, size_t len
)
3651 return (datael_get_name(&prop
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
3655 * transaction functions
3659 * Fails with _NO_MEMORY, _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED,
3660 * _INTERNAL (bad server response or id in use), or _NO_RESOURCES.
3663 scf_transaction_create(scf_handle_t
*handle
)
3665 scf_transaction_t
*ret
;
3667 ret
= uu_zalloc(sizeof (scf_transaction_t
));
3669 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3672 if (datael_init(&ret
->tran_pg
.rd_d
, handle
,
3673 REP_PROTOCOL_ENTITY_PROPERTYGRP
) == -1) {
3675 return (NULL
); /* error already set */
3677 ret
->tran_state
= TRAN_STATE_NEW
;
3678 ret
->tran_props
= uu_list_create(tran_entry_pool
, ret
, UU_LIST_SORTED
);
3679 if (ret
->tran_props
== NULL
) {
3680 datael_destroy(&ret
->tran_pg
.rd_d
);
3682 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3690 scf_transaction_handle(const scf_transaction_t
*val
)
3692 return (handle_get(val
->tran_pg
.rd_d
.rd_handle
));
3696 scf_transaction_start(scf_transaction_t
*tran
, scf_propertygroup_t
*pg
)
3698 scf_handle_t
*h
= tran
->tran_pg
.rd_d
.rd_handle
;
3700 struct rep_protocol_transaction_start request
;
3701 struct rep_protocol_response response
;
3704 if (h
!= pg
->rd_d
.rd_handle
)
3705 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3707 (void) pthread_mutex_lock(&h
->rh_lock
);
3708 if (tran
->tran_state
!= TRAN_STATE_NEW
) {
3709 (void) pthread_mutex_unlock(&h
->rh_lock
);
3710 return (scf_set_error(SCF_ERROR_IN_USE
));
3712 request
.rpr_request
= REP_PROTOCOL_PROPERTYGRP_TX_START
;
3713 request
.rpr_entityid_tx
= tran
->tran_pg
.rd_d
.rd_entity
;
3714 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
3716 datael_finish_reset(&tran
->tran_pg
.rd_d
);
3717 datael_finish_reset(&pg
->rd_d
);
3719 r
= make_door_call(h
, &request
, sizeof (request
),
3720 &response
, sizeof (response
));
3723 (void) pthread_mutex_unlock(&h
->rh_lock
);
3724 DOOR_ERRORS_BLOCK(r
);
3727 /* r < sizeof (response) cannot happen because sizeof (response) == 4 */
3729 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
||
3730 r
< sizeof (response
)) {
3731 (void) pthread_mutex_unlock(&h
->rh_lock
);
3732 return (scf_set_error(proto_error(response
.rpr_response
)));
3735 tran
->tran_state
= TRAN_STATE_SETUP
;
3736 tran
->tran_invalid
= 0;
3737 (void) pthread_mutex_unlock(&h
->rh_lock
);
3738 return (SCF_SUCCESS
);
3742 entry_invalidate(scf_transaction_entry_t
*cur
, int and_destroy
,
3743 int and_reset_value
)
3745 scf_value_t
*v
, *next
;
3746 scf_transaction_t
*tx
;
3747 scf_handle_t
*h
= cur
->entry_handle
;
3749 assert(MUTEX_HELD(&h
->rh_lock
));
3751 if ((tx
= cur
->entry_tx
) != NULL
) {
3752 tx
->tran_invalid
= 1;
3753 uu_list_remove(tx
->tran_props
, cur
);
3754 cur
->entry_tx
= NULL
;
3757 cur
->entry_property
= NULL
;
3758 cur
->entry_state
= ENTRY_STATE_INVALID
;
3759 cur
->entry_action
= REP_PROTOCOL_TX_ENTRY_INVALID
;
3760 cur
->entry_type
= REP_PROTOCOL_TYPE_INVALID
;
3762 for (v
= cur
->entry_head
; v
!= NULL
; v
= next
) {
3763 next
= v
->value_next
;
3765 v
->value_next
= NULL
;
3766 if (and_destroy
|| and_reset_value
)
3767 scf_value_reset_locked(v
, and_destroy
);
3769 cur
->entry_head
= NULL
;
3770 cur
->entry_tail
= NULL
;
3774 entry_destroy_locked(scf_transaction_entry_t
*entry
)
3776 scf_handle_t
*h
= entry
->entry_handle
;
3778 assert(MUTEX_HELD(&h
->rh_lock
));
3780 entry_invalidate(entry
, 0, 0);
3782 entry
->entry_handle
= NULL
;
3783 assert(h
->rh_entries
> 0);
3786 uu_list_node_fini(entry
, &entry
->entry_link
, tran_entry_pool
);
3791 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3792 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3793 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3796 transaction_add(scf_transaction_t
*tran
, scf_transaction_entry_t
*entry
,
3797 enum rep_protocol_transaction_action action
,
3798 const char *prop
, rep_protocol_value_type_t type
)
3800 scf_handle_t
*h
= tran
->tran_pg
.rd_d
.rd_handle
;
3801 scf_transaction_entry_t
*old
;
3802 scf_property_t
*prop_p
;
3803 rep_protocol_value_type_t oldtype
;
3804 scf_error_t error
= SCF_ERROR_NONE
;
3806 uu_list_index_t idx
;
3808 if (h
!= entry
->entry_handle
)
3809 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3811 if (action
== REP_PROTOCOL_TX_ENTRY_DELETE
)
3812 assert(type
== REP_PROTOCOL_TYPE_INVALID
);
3813 else if (type
== REP_PROTOCOL_TYPE_INVALID
)
3814 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3816 prop_p
= HANDLE_HOLD_PROPERTY(h
);
3818 (void) pthread_mutex_lock(&h
->rh_lock
);
3819 if (tran
->tran_state
!= TRAN_STATE_SETUP
) {
3820 error
= SCF_ERROR_NOT_SET
;
3823 if (tran
->tran_invalid
) {
3824 error
= SCF_ERROR_NOT_SET
;
3828 if (entry
->entry_state
!= ENTRY_STATE_INVALID
)
3829 entry_invalidate(entry
, 0, 0);
3831 old
= uu_list_find(tran
->tran_props
, &prop
, NULL
, &idx
);
3833 error
= SCF_ERROR_IN_USE
;
3837 ret
= datael_get_child_locked(&tran
->tran_pg
.rd_d
, prop
,
3838 REP_PROTOCOL_ENTITY_PROPERTY
, &prop_p
->rd_d
);
3839 if (ret
== -1 && (error
= scf_error()) != SCF_ERROR_NOT_FOUND
) {
3844 case REP_PROTOCOL_TX_ENTRY_DELETE
:
3846 error
= SCF_ERROR_NOT_FOUND
;
3850 case REP_PROTOCOL_TX_ENTRY_NEW
:
3852 error
= SCF_ERROR_EXISTS
;
3857 case REP_PROTOCOL_TX_ENTRY_CLEAR
:
3858 case REP_PROTOCOL_TX_ENTRY_REPLACE
:
3860 error
= SCF_ERROR_NOT_FOUND
;
3863 if (action
== REP_PROTOCOL_TX_ENTRY_CLEAR
) {
3864 if (property_type_locked(prop_p
, &oldtype
) == -1) {
3865 error
= scf_error();
3868 if (oldtype
!= type
) {
3869 error
= SCF_ERROR_TYPE_MISMATCH
;
3879 (void) strlcpy(entry
->entry_namebuf
, prop
,
3880 sizeof (entry
->entry_namebuf
));
3881 entry
->entry_property
= entry
->entry_namebuf
;
3882 entry
->entry_action
= action
;
3883 entry
->entry_type
= type
;
3885 entry
->entry_state
= ENTRY_STATE_IN_TX_ACTION
;
3886 entry
->entry_tx
= tran
;
3887 uu_list_insert(tran
->tran_props
, entry
, idx
);
3889 (void) pthread_mutex_unlock(&h
->rh_lock
);
3891 HANDLE_RELE_PROPERTY(h
);
3893 return (SCF_SUCCESS
);
3896 (void) pthread_mutex_unlock(&h
->rh_lock
);
3898 HANDLE_RELE_PROPERTY(h
);
3900 return (scf_set_error(error
));
3904 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3905 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3906 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3909 scf_transaction_property_new(scf_transaction_t
*tx
,
3910 scf_transaction_entry_t
*entry
, const char *prop
, scf_type_t type
)
3912 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_NEW
,
3913 prop
, scf_type_to_protocol_type(type
)));
3917 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3918 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3919 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3922 scf_transaction_property_change(scf_transaction_t
*tx
,
3923 scf_transaction_entry_t
*entry
, const char *prop
, scf_type_t type
)
3925 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_CLEAR
,
3926 prop
, scf_type_to_protocol_type(type
)));
3930 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3931 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3932 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3935 scf_transaction_property_change_type(scf_transaction_t
*tx
,
3936 scf_transaction_entry_t
*entry
, const char *prop
, scf_type_t type
)
3938 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_REPLACE
,
3939 prop
, scf_type_to_protocol_type(type
)));
3943 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3944 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3945 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3948 scf_transaction_property_delete(scf_transaction_t
*tx
,
3949 scf_transaction_entry_t
*entry
, const char *prop
)
3951 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_DELETE
,
3952 prop
, REP_PROTOCOL_TYPE_INVALID
));
3955 #define BAD_SIZE (-1UL)
3958 commit_value(caddr_t data
, scf_value_t
*val
, rep_protocol_value_type_t t
)
3962 assert(val
->value_type
== t
);
3964 if (t
== REP_PROTOCOL_TYPE_OPAQUE
) {
3965 len
= scf_opaque_encode(data
, val
->value_value
,
3969 len
= strlcpy(data
, val
->value_value
,
3970 REP_PROTOCOL_VALUE_LEN
);
3972 len
= strlen(val
->value_value
);
3973 if (len
>= REP_PROTOCOL_VALUE_LEN
)
3976 return (len
+ 1); /* count the '\0' */
3980 commit_process(scf_transaction_entry_t
*cur
,
3981 struct rep_protocol_transaction_cmd
*out
)
3986 caddr_t data
= (caddr_t
)out
->rptc_data
;
3990 len
= strlcpy(data
, cur
->entry_property
, REP_PROTOCOL_NAME_LEN
);
3992 out
->rptc_action
= cur
->entry_action
;
3993 out
->rptc_type
= cur
->entry_type
;
3994 out
->rptc_name_len
= len
+ 1;
3996 len
= strlen(cur
->entry_property
);
3999 if (len
>= REP_PROTOCOL_NAME_LEN
)
4002 len
= TX_SIZE(len
+ 1);
4005 val_data
= data
+ len
;
4007 for (child
= cur
->entry_head
; child
!= NULL
;
4008 child
= child
->value_next
) {
4009 assert(cur
->entry_action
!= REP_PROTOCOL_TX_ENTRY_DELETE
);
4011 len
= commit_value(val_data
+ sizeof (uint32_t), child
,
4013 /* LINTED alignment */
4014 *(uint32_t *)val_data
= len
;
4016 len
= commit_value(NULL
, child
, cur
->entry_type
);
4018 if (len
== BAD_SIZE
)
4021 len
+= sizeof (uint32_t);
4028 assert(val_data
- data
== sz
);
4031 out
->rptc_size
= REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz
);
4033 return (REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz
));
4037 scf_transaction_commit(scf_transaction_t
*tran
)
4039 scf_handle_t
*h
= tran
->tran_pg
.rd_d
.rd_handle
;
4041 struct rep_protocol_transaction_commit
*request
;
4042 struct rep_protocol_response response
;
4044 scf_transaction_entry_t
*cur
;
4046 size_t request_size
;
4050 (void) pthread_mutex_lock(&h
->rh_lock
);
4051 if (tran
->tran_state
!= TRAN_STATE_SETUP
||
4052 tran
->tran_invalid
) {
4053 (void) pthread_mutex_unlock(&h
->rh_lock
);
4054 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4058 for (cur
= uu_list_first(tran
->tran_props
); cur
!= NULL
;
4059 cur
= uu_list_next(tran
->tran_props
, cur
)) {
4060 size
= commit_process(cur
, NULL
);
4061 if (size
== BAD_SIZE
) {
4062 (void) pthread_mutex_unlock(&h
->rh_lock
);
4063 return (scf_set_error(SCF_ERROR_INTERNAL
));
4065 assert(TX_SIZE(size
) == size
);
4069 request_size
= REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(total
);
4070 request
= alloca(request_size
);
4071 (void) memset(request
, '\0', request_size
);
4072 request
->rpr_request
= REP_PROTOCOL_PROPERTYGRP_TX_COMMIT
;
4073 request
->rpr_entityid
= tran
->tran_pg
.rd_d
.rd_entity
;
4074 request
->rpr_size
= request_size
;
4075 cmd
= (uintptr_t)request
->rpr_cmd
;
4077 datael_finish_reset(&tran
->tran_pg
.rd_d
);
4080 for (cur
= uu_list_first(tran
->tran_props
); cur
!= NULL
;
4081 cur
= uu_list_next(tran
->tran_props
, cur
)) {
4082 size
= commit_process(cur
, (void *)cmd
);
4083 if (size
== BAD_SIZE
) {
4084 (void) pthread_mutex_unlock(&h
->rh_lock
);
4085 return (scf_set_error(SCF_ERROR_INTERNAL
));
4090 assert(new_total
== total
);
4092 r
= make_door_call(h
, request
, request_size
,
4093 &response
, sizeof (response
));
4096 (void) pthread_mutex_unlock(&h
->rh_lock
);
4097 DOOR_ERRORS_BLOCK(r
);
4100 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
4101 response
.rpr_response
!= REP_PROTOCOL_FAIL_NOT_LATEST
) {
4102 (void) pthread_mutex_unlock(&h
->rh_lock
);
4103 return (scf_set_error(proto_error(response
.rpr_response
)));
4106 tran
->tran_state
= TRAN_STATE_COMMITTED
;
4107 (void) pthread_mutex_unlock(&h
->rh_lock
);
4108 return (response
.rpr_response
== REP_PROTOCOL_SUCCESS
);
4112 transaction_reset(scf_transaction_t
*tran
)
4114 assert(MUTEX_HELD(&tran
->tran_pg
.rd_d
.rd_handle
->rh_lock
));
4116 tran
->tran_state
= TRAN_STATE_NEW
;
4117 datael_reset_locked(&tran
->tran_pg
.rd_d
);
4121 scf_transaction_reset_impl(scf_transaction_t
*tran
, int and_destroy
,
4122 int and_reset_value
)
4124 scf_transaction_entry_t
*cur
;
4127 (void) pthread_mutex_lock(&tran
->tran_pg
.rd_d
.rd_handle
->rh_lock
);
4129 while ((cur
= uu_list_teardown(tran
->tran_props
, &cookie
)) != NULL
) {
4130 cur
->entry_tx
= NULL
;
4132 assert(cur
->entry_state
== ENTRY_STATE_IN_TX_ACTION
);
4133 cur
->entry_state
= ENTRY_STATE_INVALID
;
4135 entry_invalidate(cur
, and_destroy
, and_reset_value
);
4137 entry_destroy_locked(cur
);
4139 transaction_reset(tran
);
4140 handle_unrefed(tran
->tran_pg
.rd_d
.rd_handle
);
4144 scf_transaction_reset(scf_transaction_t
*tran
)
4146 scf_transaction_reset_impl(tran
, 0, 0);
4150 scf_transaction_reset_all(scf_transaction_t
*tran
)
4152 scf_transaction_reset_impl(tran
, 0, 1);
4156 scf_transaction_destroy(scf_transaction_t
*val
)
4161 scf_transaction_reset(val
);
4163 datael_destroy(&val
->tran_pg
.rd_d
);
4165 uu_list_destroy(val
->tran_props
);
4170 scf_transaction_destroy_children(scf_transaction_t
*tran
)
4175 scf_transaction_reset_impl(tran
, 1, 0);
4178 scf_transaction_entry_t
*
4179 scf_entry_create(scf_handle_t
*h
)
4181 scf_transaction_entry_t
*ret
;
4184 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
4188 ret
= uu_zalloc(sizeof (scf_transaction_entry_t
));
4190 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
4193 ret
->entry_action
= REP_PROTOCOL_TX_ENTRY_INVALID
;
4194 ret
->entry_handle
= h
;
4196 (void) pthread_mutex_lock(&h
->rh_lock
);
4197 if (h
->rh_flags
& HANDLE_DEAD
) {
4198 (void) pthread_mutex_unlock(&h
->rh_lock
);
4200 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED
);
4205 (void) pthread_mutex_unlock(&h
->rh_lock
);
4207 uu_list_node_init(ret
, &ret
->entry_link
, tran_entry_pool
);
4213 scf_entry_handle(const scf_transaction_entry_t
*val
)
4215 return (handle_get(val
->entry_handle
));
4219 scf_entry_reset(scf_transaction_entry_t
*entry
)
4221 scf_handle_t
*h
= entry
->entry_handle
;
4223 (void) pthread_mutex_lock(&h
->rh_lock
);
4224 entry_invalidate(entry
, 0, 0);
4225 (void) pthread_mutex_unlock(&h
->rh_lock
);
4229 scf_entry_destroy_children(scf_transaction_entry_t
*entry
)
4231 scf_handle_t
*h
= entry
->entry_handle
;
4233 (void) pthread_mutex_lock(&h
->rh_lock
);
4234 entry_invalidate(entry
, 1, 0);
4235 handle_unrefed(h
); /* drops h->rh_lock */
4239 scf_entry_destroy(scf_transaction_entry_t
*entry
)
4246 h
= entry
->entry_handle
;
4248 (void) pthread_mutex_lock(&h
->rh_lock
);
4249 entry_destroy_locked(entry
);
4250 handle_unrefed(h
); /* drops h->rh_lock */
4256 * _NOT_SET - has not been added to a transaction
4257 * _INTERNAL - entry is corrupt
4258 * _INVALID_ARGUMENT - entry's transaction is not started or corrupt
4259 * entry is set to delete a property
4260 * v is reset or corrupt
4261 * _TYPE_MISMATCH - entry & v's types aren't compatible
4262 * _IN_USE - v has been added to another entry
4265 scf_entry_add_value(scf_transaction_entry_t
*entry
, scf_value_t
*v
)
4267 scf_handle_t
*h
= entry
->entry_handle
;
4269 if (h
!= v
->value_handle
)
4270 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
4272 (void) pthread_mutex_lock(&h
->rh_lock
);
4274 if (entry
->entry_state
== ENTRY_STATE_INVALID
) {
4275 (void) pthread_mutex_unlock(&h
->rh_lock
);
4276 return (scf_set_error(SCF_ERROR_NOT_SET
));
4279 if (entry
->entry_state
!= ENTRY_STATE_IN_TX_ACTION
) {
4280 (void) pthread_mutex_unlock(&h
->rh_lock
);
4281 return (scf_set_error(SCF_ERROR_INTERNAL
));
4284 if (entry
->entry_tx
->tran_state
!= TRAN_STATE_SETUP
) {
4285 (void) pthread_mutex_unlock(&h
->rh_lock
);
4286 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4289 if (entry
->entry_action
== REP_PROTOCOL_TX_ENTRY_DELETE
) {
4290 (void) pthread_mutex_unlock(&h
->rh_lock
);
4291 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4294 if (v
->value_type
== REP_PROTOCOL_TYPE_INVALID
) {
4295 (void) pthread_mutex_unlock(&h
->rh_lock
);
4296 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4299 if (!scf_is_compatible_protocol_type(entry
->entry_type
,
4301 (void) pthread_mutex_unlock(&h
->rh_lock
);
4302 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
4305 if (v
->value_tx
!= NULL
) {
4306 (void) pthread_mutex_unlock(&h
->rh_lock
);
4307 return (scf_set_error(SCF_ERROR_IN_USE
));
4310 v
->value_tx
= entry
;
4311 v
->value_next
= NULL
;
4312 if (entry
->entry_head
== NULL
) {
4313 entry
->entry_head
= v
;
4314 entry
->entry_tail
= v
;
4316 entry
->entry_tail
->value_next
= v
;
4317 entry
->entry_tail
= v
;
4320 (void) pthread_mutex_unlock(&h
->rh_lock
);
4322 return (SCF_SUCCESS
);
4329 scf_value_create(scf_handle_t
*h
)
4334 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
4338 ret
= uu_zalloc(sizeof (*ret
));
4340 ret
->value_type
= REP_PROTOCOL_TYPE_INVALID
;
4341 ret
->value_handle
= h
;
4342 (void) pthread_mutex_lock(&h
->rh_lock
);
4343 if (h
->rh_flags
& HANDLE_DEAD
) {
4344 (void) pthread_mutex_unlock(&h
->rh_lock
);
4346 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED
);
4351 (void) pthread_mutex_unlock(&h
->rh_lock
);
4353 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
4360 scf_value_reset_locked(scf_value_t
*val
, int and_destroy
)
4363 scf_transaction_entry_t
*te
;
4365 scf_handle_t
*h
= val
->value_handle
;
4366 assert(MUTEX_HELD(&h
->rh_lock
));
4367 if (val
->value_tx
!= NULL
) {
4369 te
->entry_tx
->tran_invalid
= 1;
4371 val
->value_tx
= NULL
;
4373 for (curp
= &te
->entry_head
; *curp
!= NULL
;
4374 curp
= &(*curp
)->value_next
) {
4376 *curp
= val
->value_next
;
4381 assert(curp
== NULL
);
4383 val
->value_type
= REP_PROTOCOL_TYPE_INVALID
;
4386 val
->value_handle
= NULL
;
4387 assert(h
->rh_values
> 0);
4395 scf_value_reset(scf_value_t
*val
)
4397 scf_handle_t
*h
= val
->value_handle
;
4399 (void) pthread_mutex_lock(&h
->rh_lock
);
4400 scf_value_reset_locked(val
, 0);
4401 (void) pthread_mutex_unlock(&h
->rh_lock
);
4405 scf_value_handle(const scf_value_t
*val
)
4407 return (handle_get(val
->value_handle
));
4411 scf_value_destroy(scf_value_t
*val
)
4418 h
= val
->value_handle
;
4420 (void) pthread_mutex_lock(&h
->rh_lock
);
4421 scf_value_reset_locked(val
, 1);
4422 handle_unrefed(h
); /* drops h->rh_lock */
4426 scf_value_base_type(const scf_value_t
*val
)
4428 rep_protocol_value_type_t t
, cur
;
4429 scf_handle_t
*h
= val
->value_handle
;
4431 (void) pthread_mutex_lock(&h
->rh_lock
);
4432 t
= val
->value_type
;
4433 (void) pthread_mutex_unlock(&h
->rh_lock
);
4436 cur
= scf_proto_underlying_type(t
);
4442 return (scf_protocol_type_to_type(t
));
4446 scf_value_type(const scf_value_t
*val
)
4448 rep_protocol_value_type_t t
;
4449 scf_handle_t
*h
= val
->value_handle
;
4451 (void) pthread_mutex_lock(&h
->rh_lock
);
4452 t
= val
->value_type
;
4453 (void) pthread_mutex_unlock(&h
->rh_lock
);
4455 return (scf_protocol_type_to_type(t
));
4459 scf_value_is_type(const scf_value_t
*val
, scf_type_t base_arg
)
4461 rep_protocol_value_type_t t
;
4462 rep_protocol_value_type_t base
= scf_type_to_protocol_type(base_arg
);
4463 scf_handle_t
*h
= val
->value_handle
;
4465 (void) pthread_mutex_lock(&h
->rh_lock
);
4466 t
= val
->value_type
;
4467 (void) pthread_mutex_unlock(&h
->rh_lock
);
4469 if (t
== REP_PROTOCOL_TYPE_INVALID
)
4470 return (scf_set_error(SCF_ERROR_NOT_SET
));
4471 if (base
== REP_PROTOCOL_TYPE_INVALID
)
4472 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4473 if (!scf_is_compatible_protocol_type(base
, t
))
4474 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
4476 return (SCF_SUCCESS
);
4481 * _NOT_SET - val is reset
4482 * _TYPE_MISMATCH - val's type is not compatible with t
4485 scf_value_check_type(const scf_value_t
*val
, rep_protocol_value_type_t t
)
4487 if (val
->value_type
== REP_PROTOCOL_TYPE_INVALID
) {
4488 (void) scf_set_error(SCF_ERROR_NOT_SET
);
4491 if (!scf_is_compatible_protocol_type(t
, val
->value_type
)) {
4492 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH
);
4500 * _NOT_SET - val is reset
4501 * _TYPE_MISMATCH - val is not _TYPE_BOOLEAN
4504 scf_value_get_boolean(const scf_value_t
*val
, uint8_t *out
)
4507 scf_handle_t
*h
= val
->value_handle
;
4510 (void) pthread_mutex_lock(&h
->rh_lock
);
4511 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_BOOLEAN
)) {
4512 (void) pthread_mutex_unlock(&h
->rh_lock
);
4516 c
= val
->value_value
[0];
4517 assert((c
== '0' || c
== '1') && val
->value_value
[1] == 0);
4520 (void) pthread_mutex_unlock(&h
->rh_lock
);
4523 return (SCF_SUCCESS
);
4527 scf_value_get_count(const scf_value_t
*val
, uint64_t *out
)
4529 scf_handle_t
*h
= val
->value_handle
;
4532 (void) pthread_mutex_lock(&h
->rh_lock
);
4533 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_COUNT
)) {
4534 (void) pthread_mutex_unlock(&h
->rh_lock
);
4538 o
= strtoull(val
->value_value
, NULL
, 10);
4539 (void) pthread_mutex_unlock(&h
->rh_lock
);
4542 return (SCF_SUCCESS
);
4546 scf_value_get_integer(const scf_value_t
*val
, int64_t *out
)
4548 scf_handle_t
*h
= val
->value_handle
;
4551 (void) pthread_mutex_lock(&h
->rh_lock
);
4552 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_INTEGER
)) {
4553 (void) pthread_mutex_unlock(&h
->rh_lock
);
4557 o
= strtoll(val
->value_value
, NULL
, 10);
4558 (void) pthread_mutex_unlock(&h
->rh_lock
);
4561 return (SCF_SUCCESS
);
4565 scf_value_get_time(const scf_value_t
*val
, int64_t *sec_out
, int32_t *nsec_out
)
4567 scf_handle_t
*h
= val
->value_handle
;
4572 (void) pthread_mutex_lock(&h
->rh_lock
);
4573 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_TIME
)) {
4574 (void) pthread_mutex_unlock(&h
->rh_lock
);
4578 os
= strtoll(val
->value_value
, &p
, 10);
4580 ons
= strtoul(p
+ 1, NULL
, 10);
4583 (void) pthread_mutex_unlock(&h
->rh_lock
);
4584 if (sec_out
!= NULL
)
4586 if (nsec_out
!= NULL
)
4589 return (SCF_SUCCESS
);
4594 * _NOT_SET - val is reset
4595 * _TYPE_MISMATCH - val's type is not compatible with _TYPE_STRING.
4598 scf_value_get_astring(const scf_value_t
*val
, char *out
, size_t len
)
4601 scf_handle_t
*h
= val
->value_handle
;
4603 (void) pthread_mutex_lock(&h
->rh_lock
);
4604 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_STRING
)) {
4605 (void) pthread_mutex_unlock(&h
->rh_lock
);
4606 return ((ssize_t
)-1);
4608 ret
= (ssize_t
)strlcpy(out
, val
->value_value
, len
);
4609 (void) pthread_mutex_unlock(&h
->rh_lock
);
4614 scf_value_get_ustring(const scf_value_t
*val
, char *out
, size_t len
)
4617 scf_handle_t
*h
= val
->value_handle
;
4619 (void) pthread_mutex_lock(&h
->rh_lock
);
4620 if (!scf_value_check_type(val
, REP_PROTOCOL_SUBTYPE_USTRING
)) {
4621 (void) pthread_mutex_unlock(&h
->rh_lock
);
4622 return ((ssize_t
)-1);
4624 ret
= (ssize_t
)strlcpy(out
, val
->value_value
, len
);
4625 (void) pthread_mutex_unlock(&h
->rh_lock
);
4630 scf_value_get_opaque(const scf_value_t
*v
, void *out
, size_t len
)
4633 scf_handle_t
*h
= v
->value_handle
;
4635 (void) pthread_mutex_lock(&h
->rh_lock
);
4636 if (!scf_value_check_type(v
, REP_PROTOCOL_TYPE_OPAQUE
)) {
4637 (void) pthread_mutex_unlock(&h
->rh_lock
);
4638 return ((ssize_t
)-1);
4640 if (len
> v
->value_size
)
4641 len
= v
->value_size
;
4644 (void) memcpy(out
, v
->value_value
, len
);
4645 (void) pthread_mutex_unlock(&h
->rh_lock
);
4650 scf_value_set_boolean(scf_value_t
*v
, uint8_t new)
4652 scf_handle_t
*h
= v
->value_handle
;
4654 (void) pthread_mutex_lock(&h
->rh_lock
);
4655 scf_value_reset_locked(v
, 0);
4656 v
->value_type
= REP_PROTOCOL_TYPE_BOOLEAN
;
4657 (void) sprintf(v
->value_value
, "%d", (new != 0));
4658 (void) pthread_mutex_unlock(&h
->rh_lock
);
4662 scf_value_set_count(scf_value_t
*v
, uint64_t new)
4664 scf_handle_t
*h
= v
->value_handle
;
4666 (void) pthread_mutex_lock(&h
->rh_lock
);
4667 scf_value_reset_locked(v
, 0);
4668 v
->value_type
= REP_PROTOCOL_TYPE_COUNT
;
4669 (void) sprintf(v
->value_value
, "%llu", (unsigned long long)new);
4670 (void) pthread_mutex_unlock(&h
->rh_lock
);
4674 scf_value_set_integer(scf_value_t
*v
, int64_t new)
4676 scf_handle_t
*h
= v
->value_handle
;
4678 (void) pthread_mutex_lock(&h
->rh_lock
);
4679 scf_value_reset_locked(v
, 0);
4680 v
->value_type
= REP_PROTOCOL_TYPE_INTEGER
;
4681 (void) sprintf(v
->value_value
, "%lld", (long long)new);
4682 (void) pthread_mutex_unlock(&h
->rh_lock
);
4686 scf_value_set_time(scf_value_t
*v
, int64_t new_sec
, int32_t new_nsec
)
4688 scf_handle_t
*h
= v
->value_handle
;
4690 (void) pthread_mutex_lock(&h
->rh_lock
);
4691 scf_value_reset_locked(v
, 0);
4692 if (new_nsec
< 0 || new_nsec
>= NANOSEC
) {
4693 (void) pthread_mutex_unlock(&h
->rh_lock
);
4694 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4696 v
->value_type
= REP_PROTOCOL_TYPE_TIME
;
4698 (void) sprintf(v
->value_value
, "%lld", (long long)new_sec
);
4700 (void) sprintf(v
->value_value
, "%lld.%09u", (long long)new_sec
,
4701 (unsigned)new_nsec
);
4702 (void) pthread_mutex_unlock(&h
->rh_lock
);
4707 scf_value_set_astring(scf_value_t
*v
, const char *new)
4709 scf_handle_t
*h
= v
->value_handle
;
4711 (void) pthread_mutex_lock(&h
->rh_lock
);
4712 scf_value_reset_locked(v
, 0);
4713 if (!scf_validate_encoded_value(REP_PROTOCOL_TYPE_STRING
, new)) {
4714 (void) pthread_mutex_unlock(&h
->rh_lock
);
4715 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4717 if (strlcpy(v
->value_value
, new, sizeof (v
->value_value
)) >=
4718 sizeof (v
->value_value
)) {
4719 (void) pthread_mutex_unlock(&h
->rh_lock
);
4720 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4722 v
->value_type
= REP_PROTOCOL_TYPE_STRING
;
4723 (void) pthread_mutex_unlock(&h
->rh_lock
);
4728 scf_value_set_ustring(scf_value_t
*v
, const char *new)
4730 scf_handle_t
*h
= v
->value_handle
;
4732 (void) pthread_mutex_lock(&h
->rh_lock
);
4733 scf_value_reset_locked(v
, 0);
4734 if (!scf_validate_encoded_value(REP_PROTOCOL_SUBTYPE_USTRING
, new)) {
4735 (void) pthread_mutex_unlock(&h
->rh_lock
);
4736 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4738 if (strlcpy(v
->value_value
, new, sizeof (v
->value_value
)) >=
4739 sizeof (v
->value_value
)) {
4740 (void) pthread_mutex_unlock(&h
->rh_lock
);
4741 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4743 v
->value_type
= REP_PROTOCOL_SUBTYPE_USTRING
;
4744 (void) pthread_mutex_unlock(&h
->rh_lock
);
4749 scf_value_set_opaque(scf_value_t
*v
, const void *new, size_t len
)
4751 scf_handle_t
*h
= v
->value_handle
;
4753 (void) pthread_mutex_lock(&h
->rh_lock
);
4754 scf_value_reset_locked(v
, 0);
4755 if (len
> sizeof (v
->value_value
)) {
4756 (void) pthread_mutex_unlock(&h
->rh_lock
);
4757 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4759 (void) memcpy(v
->value_value
, new, len
);
4760 v
->value_size
= len
;
4761 v
->value_type
= REP_PROTOCOL_TYPE_OPAQUE
;
4762 (void) pthread_mutex_unlock(&h
->rh_lock
);
4768 * _NOT_SET - v_arg is reset
4769 * _INTERNAL - v_arg is corrupt
4771 * If t is not _TYPE_INVALID, fails with
4772 * _TYPE_MISMATCH - v_arg's type is not compatible with t
4775 scf_value_get_as_string_common(const scf_value_t
*v_arg
,
4776 rep_protocol_value_type_t t
, char *buf
, size_t bufsz
)
4778 scf_handle_t
*h
= v_arg
->value_handle
;
4780 scf_value_t
*v
= &v_s
;
4784 (void) pthread_mutex_lock(&h
->rh_lock
);
4785 if (t
!= REP_PROTOCOL_TYPE_INVALID
&& !scf_value_check_type(v_arg
, t
)) {
4786 (void) pthread_mutex_unlock(&h
->rh_lock
);
4790 v_s
= *v_arg
; /* copy locally so we can unlock */
4791 h
->rh_values
++; /* keep the handle from going away */
4793 (void) pthread_mutex_unlock(&h
->rh_lock
);
4796 switch (REP_PROTOCOL_BASE_TYPE(v
->value_type
)) {
4797 case REP_PROTOCOL_TYPE_BOOLEAN
:
4798 r
= scf_value_get_boolean(v
, &b
);
4799 assert(r
== SCF_SUCCESS
);
4801 r
= strlcpy(buf
, b
? "true" : "false", bufsz
);
4804 case REP_PROTOCOL_TYPE_COUNT
:
4805 case REP_PROTOCOL_TYPE_INTEGER
:
4806 case REP_PROTOCOL_TYPE_TIME
:
4807 case REP_PROTOCOL_TYPE_STRING
:
4808 r
= strlcpy(buf
, v
->value_value
, bufsz
);
4811 case REP_PROTOCOL_TYPE_OPAQUE
:
4813 * Note that we only write out full hex bytes -- if they're
4814 * short, and bufsz is even, we'll only fill (bufsz - 2) bytes
4818 (void) scf_opaque_encode(buf
, v
->value_value
,
4819 MIN(v
->value_size
, (bufsz
- 1)/2));
4820 r
= (v
->value_size
* 2);
4823 case REP_PROTOCOL_TYPE_INVALID
:
4824 r
= scf_set_error(SCF_ERROR_NOT_SET
);
4828 r
= (scf_set_error(SCF_ERROR_INTERNAL
));
4832 (void) pthread_mutex_lock(&h
->rh_lock
);
4841 scf_value_get_as_string(const scf_value_t
*v
, char *buf
, size_t bufsz
)
4843 return (scf_value_get_as_string_common(v
, REP_PROTOCOL_TYPE_INVALID
,
4848 scf_value_get_as_string_typed(const scf_value_t
*v
, scf_type_t type
,
4849 char *buf
, size_t bufsz
)
4851 rep_protocol_value_type_t ty
= scf_type_to_protocol_type(type
);
4852 if (ty
== REP_PROTOCOL_TYPE_INVALID
)
4853 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4855 return (scf_value_get_as_string_common(v
, ty
, buf
, bufsz
));
4859 scf_value_set_from_string(scf_value_t
*v
, scf_type_t type
, const char *str
)
4861 scf_handle_t
*h
= v
->value_handle
;
4862 rep_protocol_value_type_t ty
;
4865 case SCF_TYPE_BOOLEAN
: {
4868 if (strcmp(str
, "true") == 0 || strcmp(str
, "t") == 0 ||
4869 strcmp(str
, "1") == 0)
4871 else if (strcmp(str
, "false") == 0 ||
4872 strcmp(str
, "f") == 0 || strcmp(str
, "0") == 0)
4878 scf_value_set_boolean(v
, b
);
4882 case SCF_TYPE_COUNT
: {
4887 c
= strtoull(str
, &endp
, 0);
4889 if (errno
!= 0 || endp
== str
|| *endp
!= '\0')
4892 scf_value_set_count(v
, c
);
4896 case SCF_TYPE_INTEGER
: {
4901 i
= strtoll(str
, &endp
, 0);
4903 if (errno
!= 0 || endp
== str
|| *endp
!= '\0')
4906 scf_value_set_integer(v
, i
);
4910 case SCF_TYPE_TIME
: {
4913 char *endp
, *ns_str
;
4917 s
= strtoll(str
, &endp
, 10);
4918 if (errno
!= 0 || endp
== str
||
4919 (*endp
!= '\0' && *endp
!= '.'))
4924 len
= strlen(ns_str
);
4925 if (len
== 0 || len
> 9)
4928 ns
= strtoul(ns_str
, &endp
, 10);
4929 if (errno
!= 0 || endp
== ns_str
|| *endp
!= '\0')
4934 assert(ns
< NANOSEC
);
4937 return (scf_value_set_time(v
, s
, ns
));
4940 case SCF_TYPE_ASTRING
:
4941 case SCF_TYPE_USTRING
:
4942 case SCF_TYPE_OPAQUE
:
4946 case SCF_TYPE_HOSTNAME
:
4947 case SCF_TYPE_NET_ADDR
:
4948 case SCF_TYPE_NET_ADDR_V4
:
4949 case SCF_TYPE_NET_ADDR_V6
:
4950 ty
= scf_type_to_protocol_type(type
);
4952 (void) pthread_mutex_lock(&h
->rh_lock
);
4953 scf_value_reset_locked(v
, 0);
4954 if (type
== SCF_TYPE_OPAQUE
) {
4955 v
->value_size
= scf_opaque_decode(v
->value_value
,
4956 str
, sizeof (v
->value_value
));
4957 if (!scf_validate_encoded_value(ty
, str
)) {
4958 (void) pthread_mutex_lock(&h
->rh_lock
);
4962 (void) strlcpy(v
->value_value
, str
,
4963 sizeof (v
->value_value
));
4964 if (!scf_validate_encoded_value(ty
, v
->value_value
)) {
4965 (void) pthread_mutex_lock(&h
->rh_lock
);
4970 (void) pthread_mutex_unlock(&h
->rh_lock
);
4971 return (SCF_SUCCESS
);
4973 case REP_PROTOCOL_TYPE_INVALID
:
4976 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
4980 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4984 scf_iter_property_values(scf_iter_t
*iter
, const scf_property_t
*prop
)
4986 return (datael_setup_iter(iter
, &prop
->rd_d
,
4987 REP_PROTOCOL_ENTITY_VALUE
, 0));
4991 scf_iter_next_value(scf_iter_t
*iter
, scf_value_t
*v
)
4993 scf_handle_t
*h
= iter
->iter_handle
;
4995 struct rep_protocol_iter_read_value request
;
4996 struct rep_protocol_value_response response
;
5000 if (h
!= v
->value_handle
)
5001 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5003 (void) pthread_mutex_lock(&h
->rh_lock
);
5005 scf_value_reset_locked(v
, 0);
5007 if (iter
->iter_type
== REP_PROTOCOL_ENTITY_NONE
) {
5008 (void) pthread_mutex_unlock(&h
->rh_lock
);
5009 return (scf_set_error(SCF_ERROR_NOT_SET
));
5012 if (iter
->iter_type
!= REP_PROTOCOL_ENTITY_VALUE
) {
5013 (void) pthread_mutex_unlock(&h
->rh_lock
);
5014 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5017 request
.rpr_request
= REP_PROTOCOL_ITER_READ_VALUE
;
5018 request
.rpr_iterid
= iter
->iter_id
;
5019 request
.rpr_sequence
= iter
->iter_sequence
;
5021 r
= make_door_call(h
, &request
, sizeof (request
),
5022 &response
, sizeof (response
));
5025 (void) pthread_mutex_unlock(&h
->rh_lock
);
5026 DOOR_ERRORS_BLOCK(r
);
5029 if (response
.rpr_response
== REP_PROTOCOL_DONE
) {
5030 (void) pthread_mutex_unlock(&h
->rh_lock
);
5033 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
5034 (void) pthread_mutex_unlock(&h
->rh_lock
);
5035 return (scf_set_error(proto_error(response
.rpr_response
)));
5037 iter
->iter_sequence
++;
5039 v
->value_type
= response
.rpr_type
;
5041 assert(scf_validate_encoded_value(response
.rpr_type
,
5042 response
.rpr_value
));
5044 if (v
->value_type
!= REP_PROTOCOL_TYPE_OPAQUE
) {
5045 (void) strlcpy(v
->value_value
, response
.rpr_value
,
5046 sizeof (v
->value_value
));
5048 v
->value_size
= scf_opaque_decode(v
->value_value
,
5049 response
.rpr_value
, sizeof (v
->value_value
));
5051 (void) pthread_mutex_unlock(&h
->rh_lock
);
5057 scf_property_get_value(const scf_property_t
*prop
, scf_value_t
*v
)
5059 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
5060 struct rep_protocol_property_request request
;
5061 struct rep_protocol_value_response response
;
5064 if (h
!= v
->value_handle
)
5065 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5067 (void) pthread_mutex_lock(&h
->rh_lock
);
5069 request
.rpr_request
= REP_PROTOCOL_PROPERTY_GET_VALUE
;
5070 request
.rpr_entityid
= prop
->rd_d
.rd_entity
;
5072 scf_value_reset_locked(v
, 0);
5073 datael_finish_reset(&prop
->rd_d
);
5075 r
= make_door_call(h
, &request
, sizeof (request
),
5076 &response
, sizeof (response
));
5079 (void) pthread_mutex_unlock(&h
->rh_lock
);
5080 DOOR_ERRORS_BLOCK(r
);
5083 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
5084 response
.rpr_response
!= REP_PROTOCOL_FAIL_TRUNCATED
) {
5085 (void) pthread_mutex_unlock(&h
->rh_lock
);
5086 assert(response
.rpr_response
!=
5087 REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
5088 return (scf_set_error(proto_error(response
.rpr_response
)));
5091 v
->value_type
= response
.rpr_type
;
5092 if (v
->value_type
!= REP_PROTOCOL_TYPE_OPAQUE
) {
5093 (void) strlcpy(v
->value_value
, response
.rpr_value
,
5094 sizeof (v
->value_value
));
5096 v
->value_size
= scf_opaque_decode(v
->value_value
,
5097 response
.rpr_value
, sizeof (v
->value_value
));
5099 (void) pthread_mutex_unlock(&h
->rh_lock
);
5100 return ((response
.rpr_response
== REP_PROTOCOL_SUCCESS
)?
5101 SCF_SUCCESS
: scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
));
5105 scf_pg_get_parent_service(const scf_propertygroup_t
*pg
, scf_service_t
*svc
)
5107 return (datael_get_parent(&pg
->rd_d
, &svc
->rd_d
));
5111 scf_pg_get_parent_instance(const scf_propertygroup_t
*pg
, scf_instance_t
*inst
)
5113 return (datael_get_parent(&pg
->rd_d
, &inst
->rd_d
));
5117 scf_pg_get_parent_snaplevel(const scf_propertygroup_t
*pg
,
5118 scf_snaplevel_t
*level
)
5120 return (datael_get_parent(&pg
->rd_d
, &level
->rd_d
));
5124 scf_service_get_parent(const scf_service_t
*svc
, scf_scope_t
*s
)
5126 return (datael_get_parent(&svc
->rd_d
, &s
->rd_d
));
5130 scf_instance_get_parent(const scf_instance_t
*inst
, scf_service_t
*svc
)
5132 return (datael_get_parent(&inst
->rd_d
, &svc
->rd_d
));
5136 scf_snapshot_get_parent(const scf_snapshot_t
*inst
, scf_instance_t
*svc
)
5138 return (datael_get_parent(&inst
->rd_d
, &svc
->rd_d
));
5142 scf_snaplevel_get_parent(const scf_snaplevel_t
*inst
, scf_snapshot_t
*svc
)
5144 return (datael_get_parent(&inst
->rd_d
, &svc
->rd_d
));
5150 * Note: In the scf_parse_svc_fmri(), scf_parse_file_fmri() and
5151 * scf_parse_fmri(), fmri isn't const because that would require
5152 * allocating memory. Also, note that scope, at least, is not necessarily
5153 * in the passed in fmri.
5157 scf_parse_svc_fmri(char *fmri
, const char **scope
, const char **service
,
5158 const char **instance
, const char **propertygroup
, const char **property
)
5160 char *s
, *e
, *te
, *tpg
;
5161 char *my_s
= NULL
, *my_i
= NULL
, *my_pg
= NULL
, *my_p
= NULL
;
5165 if (service
!= NULL
)
5167 if (instance
!= NULL
)
5169 if (propertygroup
!= NULL
)
5170 *propertygroup
= NULL
;
5171 if (property
!= NULL
)
5175 e
= strchr(s
, '\0');
5177 if (strncmp(s
, SCF_FMRI_SVC_PREFIX
,
5178 sizeof (SCF_FMRI_SVC_PREFIX
) - 1) == 0)
5179 s
+= sizeof (SCF_FMRI_SVC_PREFIX
) - 1;
5181 if (strncmp(s
, SCF_FMRI_SCOPE_PREFIX
,
5182 sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1) == 0) {
5185 s
+= sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1;
5186 te
= strstr(s
, SCF_FMRI_SERVICE_PREFIX
);
5195 s
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5197 /* If the scope ends with the suffix, remove it. */
5198 te
= strstr(my_scope
, SCF_FMRI_SCOPE_SUFFIX
);
5199 if (te
!= NULL
&& te
[sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1] == 0)
5202 /* Validate the scope. */
5203 if (my_scope
[0] == '\0')
5204 my_scope
= SCF_FMRI_LOCAL_SCOPE
;
5205 else if (uu_check_name(my_scope
, 0) == -1) {
5206 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5213 *scope
= SCF_FMRI_LOCAL_SCOPE
;
5217 if (strncmp(s
, SCF_FMRI_SERVICE_PREFIX
,
5218 sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1) == 0)
5219 s
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5222 * Can't validate service here because it might not be null
5228 tpg
= strstr(s
, SCF_FMRI_PROPERTYGRP_PREFIX
);
5229 te
= strstr(s
, SCF_FMRI_INSTANCE_PREFIX
);
5230 if (te
!= NULL
&& (tpg
== NULL
|| te
< tpg
)) {
5232 te
+= sizeof (SCF_FMRI_INSTANCE_PREFIX
) - 1;
5234 /* Can't validate instance here either. */
5237 te
= strstr(s
, SCF_FMRI_PROPERTYGRP_PREFIX
);
5244 te
+= sizeof (SCF_FMRI_PROPERTYGRP_PREFIX
) - 1;
5247 te
= strstr(s
, SCF_FMRI_PROPERTY_PREFIX
);
5250 te
+= sizeof (SCF_FMRI_PROPERTY_PREFIX
) - 1;
5258 if (uu_check_name(my_s
, UU_NAME_DOMAIN
| UU_NAME_PATH
) == -1)
5259 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5261 if (service
!= NULL
)
5266 if (uu_check_name(my_i
, UU_NAME_DOMAIN
) == -1)
5267 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5269 if (instance
!= NULL
)
5273 if (my_pg
!= NULL
) {
5274 if (uu_check_name(my_pg
, UU_NAME_DOMAIN
) == -1)
5275 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5277 if (propertygroup
!= NULL
)
5278 *propertygroup
= my_pg
;
5282 if (uu_check_name(my_p
, UU_NAME_DOMAIN
) == -1)
5283 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5285 if (property
!= NULL
)
5293 scf_parse_file_fmri(char *fmri
, const char **scope
, const char **path
)
5301 e
= strchr(s
, '\0');
5303 if (strncmp(s
, SCF_FMRI_FILE_PREFIX
,
5304 sizeof (SCF_FMRI_FILE_PREFIX
) - 1) == 0)
5305 s
+= sizeof (SCF_FMRI_FILE_PREFIX
) - 1;
5307 if (strncmp(s
, SCF_FMRI_SCOPE_PREFIX
,
5308 sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1) == 0) {
5311 s
+= sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1;
5312 te
= strstr(s
, SCF_FMRI_SERVICE_PREFIX
);
5321 /* Validate the scope. */
5322 if (my_scope
[0] != '\0' &&
5323 strcmp(my_scope
, SCF_FMRI_LOCAL_SCOPE
) != 0) {
5324 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5331 * FMRI paths must be absolute
5334 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5337 s
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5340 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5343 * If the user requests it, return the full path of the file.
5355 scf_parse_fmri(char *fmri
, int *type
, const char **scope
, const char **service
,
5356 const char **instance
, const char **propertygroup
, const char **property
)
5358 if (strncmp(fmri
, SCF_FMRI_SVC_PREFIX
,
5359 sizeof (SCF_FMRI_SVC_PREFIX
) - 1) == 0) {
5361 *type
= SCF_FMRI_TYPE_SVC
;
5362 return (scf_parse_svc_fmri(fmri
, scope
, service
, instance
,
5363 propertygroup
, property
));
5364 } else if (strncmp(fmri
, SCF_FMRI_FILE_PREFIX
,
5365 sizeof (SCF_FMRI_FILE_PREFIX
) - 1) == 0) {
5367 *type
= SCF_FMRI_TYPE_FILE
;
5368 return (scf_parse_file_fmri(fmri
, scope
, NULL
));
5371 * Parse as a svc if the fmri type is not explicitly
5375 *type
= SCF_FMRI_TYPE_SVC
;
5376 return (scf_parse_svc_fmri(fmri
, scope
, service
, instance
,
5377 propertygroup
, property
));
5382 * Fails with _INVALID_ARGUMENT. fmri and buf may be equal.
5385 scf_canonify_fmri(const char *fmri
, char *buf
, size_t bufsz
)
5387 const char *scope
, *service
, *instance
, *pg
, *property
;
5388 char local
[6 * REP_PROTOCOL_NAME_LEN
];
5392 if (strlcpy(local
, fmri
, sizeof (local
)) >= sizeof (local
)) {
5393 /* Should this be CONSTRAINT_VIOLATED? */
5394 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
5399 r
= scf_parse_svc_fmri(local
, &scope
, &service
, &instance
, &pg
,
5404 len
= strlcpy(buf
, "svc:/", bufsz
);
5406 if (scope
!= NULL
&& strcmp(scope
, SCF_SCOPE_LOCAL
) != 0) {
5407 len
+= strlcat(buf
, "/", bufsz
);
5408 len
+= strlcat(buf
, scope
, bufsz
);
5412 len
+= strlcat(buf
, service
, bufsz
);
5415 len
+= strlcat(buf
, ":", bufsz
);
5416 len
+= strlcat(buf
, instance
, bufsz
);
5420 len
+= strlcat(buf
, "/:properties/", bufsz
);
5421 len
+= strlcat(buf
, pg
, bufsz
);
5425 len
+= strlcat(buf
, "/", bufsz
);
5426 len
+= strlcat(buf
, property
, bufsz
);
5433 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _CONSTRAINT_VIOLATED,
5434 * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED,
5435 * _NO_RESOURCES, _BACKEND_ACCESS.
5438 scf_handle_decode_fmri(scf_handle_t
*h
, const char *fmri
, scf_scope_t
*sc
,
5439 scf_service_t
*svc
, scf_instance_t
*inst
, scf_propertygroup_t
*pg
,
5440 scf_property_t
*prop
, int flags
)
5442 const char *scope
, *service
, *instance
, *propertygroup
, *property
;
5444 char local
[6 * REP_PROTOCOL_NAME_LEN
];
5446 const uint32_t holds
= RH_HOLD_SCOPE
| RH_HOLD_SERVICE
|
5447 RH_HOLD_INSTANCE
| RH_HOLD_PG
| RH_HOLD_PROPERTY
;
5450 * verify that all handles match
5452 if ((sc
!= NULL
&& h
!= sc
->rd_d
.rd_handle
) ||
5453 (svc
!= NULL
&& h
!= svc
->rd_d
.rd_handle
) ||
5454 (inst
!= NULL
&& h
!= inst
->rd_d
.rd_handle
) ||
5455 (pg
!= NULL
&& h
!= pg
->rd_d
.rd_handle
) ||
5456 (prop
!= NULL
&& h
!= prop
->rd_d
.rd_handle
))
5457 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5459 if (strlcpy(local
, fmri
, sizeof (local
)) >= sizeof (local
)) {
5460 ret
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
5465 * We can simply return from an error in parsing, because
5466 * scf_parse_fmri sets the error code correctly.
5468 if (scf_parse_svc_fmri(local
, &scope
, &service
, &instance
,
5469 &propertygroup
, &property
) == -1) {
5475 * the FMRI looks valid at this point -- do constraint checks.
5478 if (instance
!= NULL
&& (flags
& SCF_DECODE_FMRI_REQUIRE_NO_INSTANCE
)) {
5479 ret
= scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
);
5482 if (instance
== NULL
&& (flags
& SCF_DECODE_FMRI_REQUIRE_INSTANCE
)) {
5483 ret
= scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
);
5488 last
= REP_PROTOCOL_ENTITY_PROPERTY
;
5489 else if (pg
!= NULL
)
5490 last
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
5491 else if (inst
!= NULL
)
5492 last
= REP_PROTOCOL_ENTITY_INSTANCE
;
5493 else if (svc
!= NULL
)
5494 last
= REP_PROTOCOL_ENTITY_SERVICE
;
5495 else if (sc
!= NULL
)
5496 last
= REP_PROTOCOL_ENTITY_SCOPE
;
5498 last
= REP_PROTOCOL_ENTITY_NONE
;
5500 if (flags
& SCF_DECODE_FMRI_EXACT
) {
5503 if (property
!= NULL
)
5504 last_fmri
= REP_PROTOCOL_ENTITY_PROPERTY
;
5505 else if (propertygroup
!= NULL
)
5506 last_fmri
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
5507 else if (instance
!= NULL
)
5508 last_fmri
= REP_PROTOCOL_ENTITY_INSTANCE
;
5509 else if (service
!= NULL
)
5510 last_fmri
= REP_PROTOCOL_ENTITY_SERVICE
;
5511 else if (scope
!= NULL
)
5512 last_fmri
= REP_PROTOCOL_ENTITY_SCOPE
;
5514 last_fmri
= REP_PROTOCOL_ENTITY_NONE
;
5516 if (last
!= last_fmri
) {
5517 ret
= scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
);
5522 if ((flags
& SCF_DECODE_FMRI_TRUNCATE
) &&
5523 last
== REP_PROTOCOL_ENTITY_NONE
) {
5524 ret
= 0; /* nothing to do */
5528 if (!(flags
& SCF_DECODE_FMRI_TRUNCATE
))
5529 last
= REP_PROTOCOL_ENTITY_NONE
; /* never stop */
5532 * passed the constraint checks -- try to grab the thing itself.
5535 handle_hold_subhandles(h
, holds
);
5539 datael_reset(&sc
->rd_d
);
5542 svc
= h
->rh_service
;
5544 datael_reset(&svc
->rd_d
);
5547 inst
= h
->rh_instance
;
5549 datael_reset(&inst
->rd_d
);
5554 datael_reset(&pg
->rd_d
);
5557 prop
= h
->rh_property
;
5559 datael_reset(&prop
->rd_d
);
5562 * We only support local scopes, but we check *after* getting
5563 * the local scope, so that any repository-related errors take
5566 if (scf_handle_get_scope(h
, SCF_SCOPE_LOCAL
, sc
) == -1) {
5567 handle_rele_subhandles(h
, holds
);
5572 if (scope
!= NULL
&& strcmp(scope
, SCF_FMRI_LOCAL_SCOPE
) != 0) {
5573 handle_rele_subhandles(h
, holds
);
5574 ret
= scf_set_error(SCF_ERROR_NOT_FOUND
);
5579 if (service
== NULL
|| last
== REP_PROTOCOL_ENTITY_SCOPE
) {
5580 handle_rele_subhandles(h
, holds
);
5584 if (scf_scope_get_service(sc
, service
, svc
) == -1) {
5585 handle_rele_subhandles(h
, holds
);
5587 assert(scf_error() != SCF_ERROR_NOT_SET
);
5588 if (scf_error() == SCF_ERROR_DELETED
)
5589 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5593 if (last
== REP_PROTOCOL_ENTITY_SERVICE
) {
5594 handle_rele_subhandles(h
, holds
);
5598 if (instance
== NULL
) {
5599 if (propertygroup
== NULL
||
5600 last
== REP_PROTOCOL_ENTITY_INSTANCE
) {
5601 handle_rele_subhandles(h
, holds
);
5605 if (scf_service_get_pg(svc
, propertygroup
, pg
) == -1) {
5606 handle_rele_subhandles(h
, holds
);
5608 assert(scf_error() != SCF_ERROR_NOT_SET
);
5609 if (scf_error() == SCF_ERROR_DELETED
)
5610 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5614 if (scf_service_get_instance(svc
, instance
, inst
) == -1) {
5615 handle_rele_subhandles(h
, holds
);
5617 assert(scf_error() != SCF_ERROR_NOT_SET
);
5618 if (scf_error() == SCF_ERROR_DELETED
)
5619 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5623 if (propertygroup
== NULL
||
5624 last
== REP_PROTOCOL_ENTITY_INSTANCE
) {
5625 handle_rele_subhandles(h
, holds
);
5629 if (scf_instance_get_pg(inst
, propertygroup
, pg
) == -1) {
5630 handle_rele_subhandles(h
, holds
);
5632 assert(scf_error() != SCF_ERROR_NOT_SET
);
5633 if (scf_error() == SCF_ERROR_DELETED
)
5634 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5639 if (property
== NULL
|| last
== REP_PROTOCOL_ENTITY_PROPERTYGRP
) {
5640 handle_rele_subhandles(h
, holds
);
5644 if (scf_pg_get_property(pg
, property
, prop
) == -1) {
5645 handle_rele_subhandles(h
, holds
);
5647 assert(scf_error() != SCF_ERROR_NOT_SET
);
5648 if (scf_error() == SCF_ERROR_DELETED
)
5649 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5653 handle_rele_subhandles(h
, holds
);
5658 datael_reset(&sc
->rd_d
);
5660 datael_reset(&svc
->rd_d
);
5662 datael_reset(&inst
->rd_d
);
5664 datael_reset(&pg
->rd_d
);
5666 datael_reset(&prop
->rd_d
);
5672 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5673 * big, bad entity id, request not applicable to entity, name too long for
5674 * buffer), _NOT_SET, or _DELETED.
5677 scf_scope_to_fmri(const scf_scope_t
*scope
, char *out
, size_t sz
)
5681 char tmp
[REP_PROTOCOL_NAME_LEN
];
5683 r
= scf_scope_get_name(scope
, tmp
, sizeof (tmp
));
5688 len
= strlcpy(out
, SCF_FMRI_SVC_PREFIX
, sz
);
5689 if (strcmp(tmp
, SCF_FMRI_LOCAL_SCOPE
) != 0) {
5691 return (len
+ r
+ sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1);
5693 len
= strlcat(out
, tmp
, sz
);
5695 return (len
+ sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1);
5697 SCF_FMRI_SCOPE_SUFFIX SCF_FMRI_SERVICE_PREFIX
, sz
);
5704 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5705 * big, bad element id, bad ids, bad types, scope has no parent, request not
5706 * applicable to entity, name too long), _NOT_SET, _DELETED,
5709 scf_service_to_fmri(const scf_service_t
*svc
, char *out
, size_t sz
)
5711 scf_handle_t
*h
= svc
->rd_d
.rd_handle
;
5712 scf_scope_t
*scope
= HANDLE_HOLD_SCOPE(h
);
5715 char tmp
[REP_PROTOCOL_NAME_LEN
];
5717 r
= datael_get_parent(&svc
->rd_d
, &scope
->rd_d
);
5718 if (r
!= SCF_SUCCESS
) {
5719 HANDLE_RELE_SCOPE(h
);
5721 assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH
);
5724 if (out
!= NULL
&& sz
> 0)
5725 len
= scf_scope_to_fmri(scope
, out
, sz
);
5727 len
= scf_scope_to_fmri(scope
, tmp
, 2);
5729 HANDLE_RELE_SCOPE(h
);
5734 if (out
== NULL
|| len
>= sz
)
5735 len
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5737 len
= strlcat(out
, SCF_FMRI_SERVICE_PREFIX
, sz
);
5739 r
= scf_service_get_name(svc
, tmp
, sizeof (tmp
));
5743 if (out
== NULL
|| len
>= sz
)
5746 len
= strlcat(out
, tmp
, sz
);
5752 scf_instance_to_fmri(const scf_instance_t
*inst
, char *out
, size_t sz
)
5754 scf_handle_t
*h
= inst
->rd_d
.rd_handle
;
5755 scf_service_t
*svc
= HANDLE_HOLD_SERVICE(h
);
5758 char tmp
[REP_PROTOCOL_NAME_LEN
];
5760 r
= datael_get_parent(&inst
->rd_d
, &svc
->rd_d
);
5761 if (r
!= SCF_SUCCESS
) {
5762 HANDLE_RELE_SERVICE(h
);
5766 len
= scf_service_to_fmri(svc
, out
, sz
);
5768 HANDLE_RELE_SERVICE(h
);
5774 len
+= sizeof (SCF_FMRI_INSTANCE_PREFIX
) - 1;
5776 len
= strlcat(out
, SCF_FMRI_INSTANCE_PREFIX
, sz
);
5778 r
= scf_instance_get_name(inst
, tmp
, sizeof (tmp
));
5785 len
= strlcat(out
, tmp
, sz
);
5791 scf_pg_to_fmri(const scf_propertygroup_t
*pg
, char *out
, size_t sz
)
5793 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
5795 struct rep_protocol_entity_parent_type request
;
5796 struct rep_protocol_integer_response response
;
5798 char tmp
[REP_PROTOCOL_NAME_LEN
];
5801 (void) pthread_mutex_lock(&h
->rh_lock
);
5802 request
.rpr_request
= REP_PROTOCOL_ENTITY_PARENT_TYPE
;
5803 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
5805 datael_finish_reset(&pg
->rd_d
);
5806 r
= make_door_call(h
, &request
, sizeof (request
),
5807 &response
, sizeof (response
));
5808 (void) pthread_mutex_unlock(&h
->rh_lock
);
5811 DOOR_ERRORS_BLOCK(r
);
5813 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
||
5814 r
< sizeof (response
)) {
5815 return (scf_set_error(proto_error(response
.rpr_response
)));
5818 switch (response
.rpr_value
) {
5819 case REP_PROTOCOL_ENTITY_SERVICE
: {
5822 svc
= HANDLE_HOLD_SERVICE(h
);
5824 r
= datael_get_parent(&pg
->rd_d
, &svc
->rd_d
);
5826 if (r
== SCF_SUCCESS
)
5827 len
= scf_service_to_fmri(svc
, out
, sz
);
5829 HANDLE_RELE_SERVICE(h
);
5833 case REP_PROTOCOL_ENTITY_INSTANCE
: {
5834 scf_instance_t
*inst
;
5836 inst
= HANDLE_HOLD_INSTANCE(h
);
5838 r
= datael_get_parent(&pg
->rd_d
, &inst
->rd_d
);
5840 if (r
== SCF_SUCCESS
)
5841 len
= scf_instance_to_fmri(inst
, out
, sz
);
5843 HANDLE_RELE_INSTANCE(h
);
5847 case REP_PROTOCOL_ENTITY_SNAPLEVEL
: {
5848 scf_instance_t
*inst
= HANDLE_HOLD_INSTANCE(h
);
5849 scf_snapshot_t
*snap
= HANDLE_HOLD_SNAPSHOT(h
);
5850 scf_snaplevel_t
*level
= HANDLE_HOLD_SNAPLVL(h
);
5852 r
= datael_get_parent(&pg
->rd_d
, &level
->rd_d
);
5854 if (r
== SCF_SUCCESS
)
5855 r
= datael_get_parent(&level
->rd_d
, &snap
->rd_d
);
5857 if (r
== SCF_SUCCESS
)
5858 r
= datael_get_parent(&snap
->rd_d
, &inst
->rd_d
);
5860 if (r
== SCF_SUCCESS
)
5861 len
= scf_instance_to_fmri(inst
, out
, sz
);
5863 HANDLE_RELE_INSTANCE(h
);
5864 HANDLE_RELE_SNAPSHOT(h
);
5865 HANDLE_RELE_SNAPLVL(h
);
5870 return (scf_set_error(SCF_ERROR_INTERNAL
));
5873 if (r
!= SCF_SUCCESS
)
5877 len
+= sizeof (SCF_FMRI_PROPERTYGRP_PREFIX
) - 1;
5879 len
= strlcat(out
, SCF_FMRI_PROPERTYGRP_PREFIX
, sz
);
5881 r
= scf_pg_get_name(pg
, tmp
, sizeof (tmp
));
5889 len
= strlcat(out
, tmp
, sz
);
5895 scf_property_to_fmri(const scf_property_t
*prop
, char *out
, size_t sz
)
5897 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
5898 scf_propertygroup_t
*pg
= HANDLE_HOLD_PG(h
);
5900 char tmp
[REP_PROTOCOL_NAME_LEN
];
5904 r
= datael_get_parent(&prop
->rd_d
, &pg
->rd_d
);
5905 if (r
!= SCF_SUCCESS
) {
5910 len
= scf_pg_to_fmri(pg
, out
, sz
);
5915 len
+= sizeof (SCF_FMRI_PROPERTY_PREFIX
) - 1;
5917 len
= strlcat(out
, SCF_FMRI_PROPERTY_PREFIX
, sz
);
5919 r
= scf_property_get_name(prop
, tmp
, sizeof (tmp
));
5927 len
= strlcat(out
, tmp
, sz
);
5933 * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
5934 * (server response too big, bad entity id, request not applicable to entity,
5935 * name too long for buffer, bad element id, iter already exists, element
5936 * cannot have children of type, type is invalid, iter was reset, sequence
5937 * was bad, iter walks values, iter does not walk type entities),
5938 * _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED,
5939 * _NOT_FOUND (scope has no parent), _INVALID_ARGUMENT, _NO_RESOURCES,
5943 scf_pg_get_underlying_pg(const scf_propertygroup_t
*pg
,
5944 scf_propertygroup_t
*out
)
5946 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
5948 scf_instance_t
*inst
;
5950 char me
[REP_PROTOCOL_NAME_LEN
];
5953 if (h
!= out
->rd_d
.rd_handle
)
5954 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5956 r
= scf_pg_get_name(pg
, me
, sizeof (me
));
5961 svc
= HANDLE_HOLD_SERVICE(h
);
5962 inst
= HANDLE_HOLD_INSTANCE(h
);
5964 r
= datael_get_parent(&pg
->rd_d
, &inst
->rd_d
);
5966 if (r
== SCF_SUCCESS
) {
5967 r
= datael_get_parent(&inst
->rd_d
, &svc
->rd_d
);
5968 if (r
!= SCF_SUCCESS
) {
5971 r
= scf_service_get_pg(svc
, me
, out
);
5973 r
= scf_set_error(SCF_ERROR_NOT_FOUND
);
5977 HANDLE_RELE_SERVICE(h
);
5978 HANDLE_RELE_INSTANCE(h
);
5982 #define LEGACY_SCHEME "lrc:"
5983 #define LEGACY_UNKNOWN "unknown"
5986 * Implementation of scf_walk_fmri()
5988 * This is a little tricky due to the many-to-many relationship between patterns
5989 * and matches. We need to be able to satisfy the following requirements:
5991 * 1) Detect patterns which match more than one FMRI, and be able to
5992 * report which FMRIs have been matched.
5993 * 2) Detect patterns which have not matched any FMRIs
5994 * 3) Visit each matching FMRI exactly once across all patterns
5995 * 4) Ignore FMRIs which have only been matched due to multiply-matching
5998 * We maintain an array of scf_pattern_t structures, one for each argument, and
5999 * maintain a linked list of scf_match_t structures for each one. We first
6000 * qualify each pattern's type:
6002 * PATTERN_INVALID The argument is invalid (too long).
6004 * PATTERN_EXACT The pattern is a complete FMRI. The list of
6005 * matches contains only a single entry.
6007 * PATTERN_GLOB The pattern will be matched against all
6008 * FMRIs via fnmatch() in the second phase.
6009 * Matches will be added to the pattern's list
6010 * as they are found.
6012 * PATTERN_PARTIAL Everything else. We will assume that this is
6013 * an abbreviated FMRI, and match according to
6014 * our abbreviated FMRI rules. Matches will be
6015 * added to the pattern's list as they are found.
6017 * The first pass searches for arguments that are complete FMRIs. These are
6018 * classified as EXACT patterns and do not necessitate searching the entire
6021 * Once this is done, if we have any GLOB or PARTIAL patterns (or if no
6022 * arguments were given), we iterate over all services and instances in the
6023 * repository, looking for matches.
6025 * When a match is found, we add the match to the pattern's list. We also enter
6026 * the match into a hash table, resulting in something like this:
6028 * scf_pattern_t scf_match_t
6029 * +---------------+ +-------+ +-------+
6030 * | pattern 'foo' |----->| match |---->| match |
6031 * +---------------+ +-------+ +-------+
6033 * scf_match_key_t | |
6034 * +--------------+ | |
6035 * | FMRI bar/foo |<----+ |
6036 * +--------------+ |
6037 * | FMRI baz/foo |<------------------+
6040 * Once we have all of this set up, we do one pass to report patterns matching
6041 * multiple FMRIs (if SCF_WALK_MULTIPLE is not set) and patterns for which no
6044 * Finally, we walk through all valid patterns, and for each match, if we
6045 * haven't already seen the match (as recorded in the hash table), then we
6046 * execute the callback.
6049 struct scf_matchkey
;
6055 typedef struct scf_matchkey
{
6056 char *sk_fmri
; /* Matching FMRI */
6057 char *sk_legacy
; /* Legacy name */
6058 int sk_seen
; /* If we've been seen */
6059 struct scf_matchkey
*sk_next
; /* Next in hash chain */
6065 typedef struct scf_match
{
6066 scf_matchkey_t
*sm_key
;
6067 struct scf_match
*sm_next
;
6070 #define WALK_HTABLE_SIZE 123
6075 * Given an FMRI and a hash table, returns the scf_matchkey_t corresponding to
6076 * this FMRI. If the FMRI does not exist, it is added to the hash table. If a
6077 * new entry cannot be allocated due to lack of memory, NULL is returned.
6079 static scf_matchkey_t
*
6080 scf_get_key(scf_matchkey_t
**htable
, const char *fmri
, const char *legacy
)
6084 scf_matchkey_t
*key
;
6086 k
= strstr(fmri
, ":/");
6091 * Generic hash function from uts/common/os/modhash.c.
6093 for (p
= k
; *p
!= '\0'; ++p
) {
6095 if ((g
= (h
& 0xf0000000)) != 0) {
6101 h
%= WALK_HTABLE_SIZE
;
6104 * Search for an existing key
6106 for (key
= htable
[h
]; key
!= NULL
; key
= key
->sk_next
) {
6107 if (strcmp(key
->sk_fmri
, fmri
) == 0)
6111 if ((key
= calloc(sizeof (scf_matchkey_t
), 1)) == NULL
)
6115 * Add new key to hash table.
6117 if ((key
->sk_fmri
= strdup(fmri
)) == NULL
) {
6122 if (legacy
== NULL
) {
6123 key
->sk_legacy
= NULL
;
6124 } else if ((key
->sk_legacy
= strdup(legacy
)) == NULL
) {
6130 key
->sk_next
= htable
[h
];
6137 * Given an FMRI, insert it into the pattern's list appropriately.
6138 * svc_explicit indicates whether matching services should take
6139 * precedence over matching instances.
6142 scf_add_match(scf_matchkey_t
**htable
, const char *fmri
, const char *legacy
,
6143 scf_pattern_t
*pattern
, int svc_explicit
)
6148 * If svc_explicit is set, enforce the constaint that matching
6149 * instances take precedence over matching services. Otherwise,
6150 * matching services take precedence over matching instances.
6153 scf_match_t
*next
, *prev
;
6155 * If we match an instance, check to see if we must remove
6156 * any matching services (for SCF_WALK_EXPLICIT).
6158 for (prev
= match
= pattern
->sp_matches
; match
!= NULL
;
6160 size_t len
= strlen(match
->sm_key
->sk_fmri
);
6161 next
= match
->sm_next
;
6162 if (strncmp(match
->sm_key
->sk_fmri
, fmri
, len
) == 0 &&
6165 pattern
->sp_matches
= match
->sm_next
;
6167 prev
->sm_next
= match
->sm_next
;
6168 pattern
->sp_matchcount
--;
6175 * If we've matched a service don't add any instances (for
6176 * SCF_WALK_SERVICE).
6178 for (match
= pattern
->sp_matches
; match
!= NULL
;
6179 match
= match
->sm_next
) {
6180 size_t len
= strlen(match
->sm_key
->sk_fmri
);
6181 if (strncmp(match
->sm_key
->sk_fmri
, fmri
, len
) == 0 &&
6187 if ((match
= malloc(sizeof (scf_match_t
))) == NULL
)
6188 return (SCF_ERROR_NO_MEMORY
);
6190 if ((match
->sm_key
= scf_get_key(htable
, fmri
, legacy
)) == NULL
) {
6192 return (SCF_ERROR_NO_MEMORY
);
6195 match
->sm_next
= pattern
->sp_matches
;
6196 pattern
->sp_matches
= match
;
6197 pattern
->sp_matchcount
++;
6203 * Returns 1 if the fmri matches the given pattern, 0 otherwise.
6206 scf_cmp_pattern(char *fmri
, scf_pattern_t
*pattern
)
6210 if (pattern
->sp_type
== PATTERN_GLOB
) {
6211 if (fnmatch(pattern
->sp_arg
, fmri
, 0) == 0)
6213 } else if (pattern
->sp_type
== PATTERN_PARTIAL
&&
6214 (tmp
= strstr(fmri
, pattern
->sp_arg
)) != NULL
) {
6216 * We only allow partial matches anchored on the end of
6217 * a service or instance, and beginning on an element
6220 if (tmp
!= fmri
&& tmp
[-1] != '/' && tmp
[-1] != ':' &&
6223 tmp
+= strlen(pattern
->sp_arg
);
6224 if (tmp
!= fmri
+ strlen(fmri
) && tmp
[0] != ':' &&
6229 * If the user has supplied a short pattern that matches
6230 * 'svc:/' or 'lrc:/', ignore it.
6232 if (tmp
<= fmri
+ 4)
6242 * Attempts to match the given FMRI against a set of patterns, keeping track of
6246 scf_pattern_match(scf_matchkey_t
**htable
, char *fmri
, const char *legacy
,
6247 int npattern
, scf_pattern_t
*pattern
, int svc_explicit
)
6252 for (i
= 0; i
< npattern
; i
++) {
6253 if (scf_cmp_pattern(fmri
, &pattern
[i
]) &&
6254 (ret
= scf_add_match(htable
, fmri
,
6255 legacy
, &pattern
[i
], svc_explicit
)) != 0)
6263 * Fails with _INVALID_ARGUMENT, _HANDLE_DESTROYED, _INTERNAL (bad server
6264 * response or id in use), _NO_MEMORY, _HANDLE_MISMATCH, _CONSTRAINT_VIOLATED,
6265 * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _NOT_SET, _DELETED,
6266 * _NO_RESOURCES, _BACKEND_ACCESS, _TYPE_MISMATCH.
6269 scf_walk_fmri(scf_handle_t
*h
, int argc
, char **argv
, int flags
,
6270 scf_walk_callback callback
, void *data
, int *err
,
6271 void (*errfunc
)(const char *, ...))
6273 scf_pattern_t
*pattern
= NULL
;
6276 ssize_t max_fmri_length
;
6277 scf_service_t
*svc
= NULL
;
6278 scf_instance_t
*inst
= NULL
;
6279 scf_iter_t
*iter
= NULL
, *sciter
= NULL
, *siter
= NULL
;
6280 scf_scope_t
*scope
= NULL
;
6281 scf_propertygroup_t
*pg
= NULL
;
6282 scf_property_t
*prop
= NULL
;
6283 scf_value_t
*value
= NULL
;
6285 scf_matchkey_t
**htable
= NULL
;
6286 int pattern_search
= 0;
6287 ssize_t max_name_length
;
6288 char *pgname
= NULL
;
6289 scf_walkinfo_t info
;
6292 if (flags
& SCF_WALK_EXPLICIT
)
6293 assert(flags
& SCF_WALK_SERVICE
);
6294 if (flags
& SCF_WALK_NOINSTANCE
)
6295 assert(flags
& SCF_WALK_SERVICE
);
6296 if (flags
& SCF_WALK_PROPERTY
)
6297 assert(!(flags
& SCF_WALK_LEGACY
));
6301 * Setup initial variables
6303 max_fmri_length
= scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH
);
6304 assert(max_fmri_length
!= -1);
6305 max_name_length
= scf_limit(SCF_LIMIT_MAX_NAME_LENGTH
);
6306 assert(max_name_length
!= -1);
6308 if ((fmri
= malloc(max_fmri_length
+ 1)) == NULL
||
6309 (pgname
= malloc(max_name_length
+ 1)) == NULL
) {
6310 ret
= SCF_ERROR_NO_MEMORY
;
6316 } else if ((pattern
= calloc(argc
, sizeof (scf_pattern_t
)))
6318 ret
= SCF_ERROR_NO_MEMORY
;
6322 if ((htable
= calloc(WALK_HTABLE_SIZE
, sizeof (void *))) == NULL
) {
6323 ret
= SCF_ERROR_NO_MEMORY
;
6327 if ((inst
= scf_instance_create(h
)) == NULL
||
6328 (svc
= scf_service_create(h
)) == NULL
||
6329 (iter
= scf_iter_create(h
)) == NULL
||
6330 (sciter
= scf_iter_create(h
)) == NULL
||
6331 (siter
= scf_iter_create(h
)) == NULL
||
6332 (scope
= scf_scope_create(h
)) == NULL
||
6333 (pg
= scf_pg_create(h
)) == NULL
||
6334 (prop
= scf_property_create(h
)) == NULL
||
6335 (value
= scf_value_create(h
)) == NULL
) {
6341 * For each fmri given, we first check to see if it's a full service,
6342 * instance, property group, or property FMRI. This avoids having to do
6343 * the (rather expensive) walk of all instances. Any element which does
6344 * not match a full fmri is identified as a globbed pattern or a partial
6345 * fmri and stored in a private array when walking instances.
6347 for (i
= 0; i
< argc
; i
++) {
6348 const char *scope_name
, *svc_name
, *inst_name
, *pg_name
;
6349 const char *prop_name
;
6351 if (strlen(argv
[i
]) > max_fmri_length
) {
6352 errfunc(scf_get_msg(SCF_MSG_ARGTOOLONG
), argv
[i
]);
6354 *err
= UU_EXIT_FATAL
;
6358 (void) strcpy(fmri
, argv
[i
]);
6359 if (scf_parse_svc_fmri(fmri
, &scope_name
, &svc_name
, &inst_name
,
6360 &pg_name
, &prop_name
) != SCF_SUCCESS
)
6364 * If the user has specified SCF_WALK_PROPERTY, allow property
6365 * groups and properties.
6367 if (pg_name
!= NULL
|| prop_name
!= NULL
) {
6368 if (!(flags
& SCF_WALK_PROPERTY
))
6371 if (scf_handle_decode_fmri(h
, argv
[i
], NULL
, NULL
,
6372 NULL
, pg
, prop
, 0) != 0)
6375 if (scf_pg_get_name(pg
, NULL
, 0) < 0 &&
6376 scf_property_get_name(prop
, NULL
, 0) < 0)
6379 if (scf_canonify_fmri(argv
[i
], fmri
, max_fmri_length
)
6382 * scf_parse_fmri() should have caught this.
6387 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6388 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6391 if ((pattern
[i
].sp_arg
= strdup(argv
[i
])) == NULL
) {
6392 ret
= SCF_ERROR_NO_MEMORY
;
6395 pattern
[i
].sp_type
= PATTERN_EXACT
;
6399 * We need at least a service name
6401 if (scope_name
== NULL
|| svc_name
== NULL
)
6405 * If we have a fully qualified instance, add it to our list of
6408 if (inst_name
!= NULL
) {
6409 if (flags
& SCF_WALK_NOINSTANCE
)
6412 if (scf_handle_decode_fmri(h
, argv
[i
], NULL
, NULL
,
6413 inst
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != 0)
6416 if (scf_canonify_fmri(argv
[i
], fmri
, max_fmri_length
)
6420 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6421 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6424 if ((pattern
[i
].sp_arg
= strdup(argv
[i
])) == NULL
) {
6425 ret
= SCF_ERROR_NO_MEMORY
;
6428 pattern
[i
].sp_type
= PATTERN_EXACT
;
6433 if (scf_handle_decode_fmri(h
, argv
[i
], NULL
, svc
,
6434 NULL
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) !=
6439 * If the user allows for bare services, then simply
6440 * pass this service on.
6442 if (flags
& SCF_WALK_SERVICE
) {
6443 if (scf_service_to_fmri(svc
, fmri
,
6444 max_fmri_length
+ 1) <= 0) {
6449 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6450 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6453 if ((pattern
[i
].sp_arg
= strdup(argv
[i
]))
6455 ret
= SCF_ERROR_NO_MEMORY
;
6458 pattern
[i
].sp_type
= PATTERN_EXACT
;
6462 if (flags
& SCF_WALK_NOINSTANCE
)
6466 * Otherwise, iterate over all instances in the service.
6468 if (scf_iter_service_instances(iter
, svc
) !=
6475 ret
= scf_iter_next_instance(iter
, inst
);
6483 if (scf_instance_to_fmri(inst
, fmri
,
6484 max_fmri_length
+ 1) == -1)
6487 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6488 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6492 if ((pattern
[i
].sp_arg
= strdup(argv
[i
])) == NULL
) {
6493 ret
= SCF_ERROR_NO_MEMORY
;
6496 pattern
[i
].sp_type
= PATTERN_EXACT
;
6503 * If we got here because of a fatal error, bail out
6506 if (scf_error() == SCF_ERROR_CONNECTION_BROKEN
) {
6512 * At this point we failed to interpret the argument as a
6513 * complete fmri, so mark it as a partial or globbed FMRI for
6516 if (strpbrk(argv
[i
], "*?[") != NULL
) {
6518 * Prepend svc:/ to patterns which don't begin with * or
6521 pattern
[i
].sp_type
= PATTERN_GLOB
;
6522 if (argv
[i
][0] == '*' ||
6523 (strlen(argv
[i
]) >= 4 && argv
[i
][3] == ':'))
6524 pattern
[i
].sp_arg
= strdup(argv
[i
]);
6526 pattern
[i
].sp_arg
= malloc(strlen(argv
[i
]) + 6);
6527 if (pattern
[i
].sp_arg
!= NULL
)
6528 (void) snprintf(pattern
[i
].sp_arg
,
6529 strlen(argv
[i
]) + 6, "svc:/%s",
6533 pattern
[i
].sp_type
= PATTERN_PARTIAL
;
6534 pattern
[i
].sp_arg
= strdup(argv
[i
]);
6537 if (pattern
[i
].sp_arg
== NULL
) {
6538 ret
= SCF_ERROR_NO_MEMORY
;
6543 if (pattern_search
|| argc
== 0) {
6545 * We have a set of patterns to search for. Iterate over all
6546 * instances and legacy services searching for matches.
6548 if (scf_handle_get_local_scope(h
, scope
) != 0) {
6553 if (scf_iter_scope_services(sciter
, scope
) != 0) {
6559 ret
= scf_iter_next_service(sciter
, svc
);
6567 if (flags
& SCF_WALK_SERVICE
) {
6569 * If the user is requesting bare services, try
6570 * to match the service first.
6572 if (scf_service_to_fmri(svc
, fmri
,
6573 max_fmri_length
+ 1) < 0) {
6585 if ((ret
= callback(data
, &info
)) != 0)
6588 } else if ((ret
= scf_pattern_match(htable
,
6589 fmri
, NULL
, argc
, pattern
,
6590 flags
& SCF_WALK_EXPLICIT
)) != 0) {
6595 if (flags
& SCF_WALK_NOINSTANCE
)
6599 * Iterate over all instances in the service.
6601 if (scf_iter_service_instances(siter
, svc
) != 0) {
6602 if (scf_error() != SCF_ERROR_DELETED
) {
6610 ret
= scf_iter_next_instance(siter
, inst
);
6614 if (scf_error() != SCF_ERROR_DELETED
) {
6621 if (scf_instance_to_fmri(inst
, fmri
,
6622 max_fmri_length
+ 1) < 0) {
6628 * Without arguments, execute the callback
6638 if ((ret
= callback(data
, &info
)) != 0)
6640 } else if ((ret
= scf_pattern_match(htable
,
6641 fmri
, NULL
, argc
, pattern
,
6642 flags
& SCF_WALK_EXPLICIT
)) != 0) {
6649 * Search legacy services
6651 if ((flags
& SCF_WALK_LEGACY
)) {
6652 if (scf_scope_get_service(scope
, SCF_LEGACY_SERVICE
,
6654 if (scf_error() != SCF_ERROR_NOT_FOUND
) {
6662 if (scf_iter_service_pgs_typed(iter
, svc
,
6663 SCF_GROUP_FRAMEWORK
) != SCF_SUCCESS
) {
6668 (void) strcpy(fmri
, LEGACY_SCHEME
);
6671 ret
= scf_iter_next_pg(iter
, pg
);
6679 if (scf_pg_get_property(pg
,
6680 SCF_LEGACY_PROPERTY_NAME
, prop
) == -1) {
6682 if (ret
== SCF_ERROR_DELETED
||
6683 ret
== SCF_ERROR_NOT_FOUND
) {
6690 if (scf_property_is_type(prop
, SCF_TYPE_ASTRING
)
6692 if (scf_error() == SCF_ERROR_DELETED
)
6698 if (scf_property_get_value(prop
, value
) !=
6702 if (scf_value_get_astring(value
,
6703 fmri
+ sizeof (LEGACY_SCHEME
) - 1,
6704 max_fmri_length
+ 2 -
6705 sizeof (LEGACY_SCHEME
)) <= 0)
6708 if (scf_pg_get_name(pg
, pgname
,
6709 max_name_length
+ 1) <= 0) {
6710 if (scf_error() == SCF_ERROR_DELETED
)
6723 if ((ret
= callback(data
, &info
)) != 0)
6725 } else if ((ret
= scf_pattern_match(htable
,
6726 fmri
, pgname
, argc
, pattern
,
6727 flags
& SCF_WALK_EXPLICIT
)) != 0)
6740 * Check all patterns, and see if we have that any that didn't match
6741 * or any that matched multiple instances. For svcprop, add up the
6742 * total number of matching keys.
6745 for (i
= 0; i
< argc
; i
++) {
6748 if (pattern
[i
].sp_type
== PATTERN_INVALID
)
6750 if (pattern
[i
].sp_matchcount
== 0) {
6753 * Provide a useful error message based on the argument
6754 * and the type of entity requested.
6756 if (!(flags
& SCF_WALK_LEGACY
) &&
6757 strncmp(pattern
[i
].sp_arg
, "lrc:/", 5) == 0)
6758 msgid
= SCF_MSG_PATTERN_LEGACY
;
6759 else if (flags
& SCF_WALK_PROPERTY
)
6760 msgid
= SCF_MSG_PATTERN_NOENTITY
;
6761 else if (flags
& SCF_WALK_NOINSTANCE
)
6762 msgid
= SCF_MSG_PATTERN_NOSERVICE
;
6763 else if (flags
& SCF_WALK_SERVICE
)
6764 msgid
= SCF_MSG_PATTERN_NOINSTSVC
;
6766 msgid
= SCF_MSG_PATTERN_NOINSTANCE
;
6768 errfunc(scf_get_msg(msgid
), pattern
[i
].sp_arg
);
6770 *err
= UU_EXIT_FATAL
;
6771 } else if (!(flags
& SCF_WALK_MULTIPLE
) &&
6772 pattern
[i
].sp_matchcount
> 1) {
6777 * Construct a message with all possible FMRIs before
6778 * passing off to error handling function.
6780 * Note that strlen(scf_get_msg(...)) includes the
6781 * length of '%s', which accounts for the terminating
6784 len
= strlen(scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH
)) +
6785 strlen(pattern
[i
].sp_arg
);
6786 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6787 match
= match
->sm_next
) {
6788 len
+= strlen(match
->sm_key
->sk_fmri
) + 2;
6790 if ((msg
= malloc(len
)) == NULL
) {
6791 ret
= SCF_ERROR_NO_MEMORY
;
6795 /* LINTED - format argument */
6796 (void) snprintf(msg
, len
,
6797 scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH
),
6800 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6801 match
= match
->sm_next
) {
6802 off
+= snprintf(msg
+ off
, len
- off
, "\t%s\n",
6803 match
->sm_key
->sk_fmri
);
6808 *err
= UU_EXIT_FATAL
;
6812 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6813 match
= match
->sm_next
) {
6814 if (!match
->sm_key
->sk_seen
)
6816 match
->sm_key
->sk_seen
= 1;
6822 * Clear 'sk_seen' for all keys.
6824 for (i
= 0; i
< WALK_HTABLE_SIZE
; i
++) {
6825 scf_matchkey_t
*key
;
6826 for (key
= htable
[i
]; key
!= NULL
; key
= key
->sk_next
)
6831 * Iterate over all the FMRIs in our hash table and execute the
6834 for (i
= 0; i
< argc
; i
++) {
6836 scf_matchkey_t
*key
;
6839 * Ignore patterns which didn't match anything or matched too
6842 if (pattern
[i
].sp_matchcount
== 0 ||
6843 (!(flags
& SCF_WALK_MULTIPLE
) &&
6844 pattern
[i
].sp_matchcount
> 1))
6847 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6848 match
= match
->sm_next
) {
6850 key
= match
->sm_key
;
6856 if (key
->sk_legacy
!= NULL
) {
6857 if (scf_scope_get_service(scope
,
6858 "smf/legacy_run", svc
) != 0) {
6863 if (scf_service_get_pg(svc
, key
->sk_legacy
,
6867 info
.fmri
= key
->sk_fmri
;
6873 if ((ret
= callback(data
, &info
)) != 0)
6876 if (scf_handle_decode_fmri(h
, key
->sk_fmri
,
6877 scope
, svc
, inst
, pg
, prop
, 0) !=
6881 info
.fmri
= key
->sk_fmri
;
6884 if (scf_instance_get_name(inst
, NULL
, 0) < 0) {
6886 SCF_ERROR_CONNECTION_BROKEN
) {
6894 if (scf_pg_get_name(pg
, NULL
, 0) < 0) {
6896 SCF_ERROR_CONNECTION_BROKEN
) {
6904 if (scf_property_get_name(prop
, NULL
, 0) < 0) {
6906 SCF_ERROR_CONNECTION_BROKEN
) {
6915 if ((ret
= callback(data
, &info
)) != 0)
6923 scf_matchkey_t
*key
, *next
;
6925 for (i
= 0; i
< WALK_HTABLE_SIZE
; i
++) {
6927 for (key
= htable
[i
]; key
!= NULL
;
6930 next
= key
->sk_next
;
6932 if (key
->sk_fmri
!= NULL
)
6934 if (key
->sk_legacy
!= NULL
)
6935 free(key
->sk_legacy
);
6941 if (pattern
!= NULL
) {
6942 for (i
= 0; i
< argc
; i
++) {
6943 scf_match_t
*match
, *next
;
6945 if (pattern
[i
].sp_arg
!= NULL
)
6946 free(pattern
[i
].sp_arg
);
6948 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6951 next
= match
->sm_next
;
6962 scf_value_destroy(value
);
6963 scf_property_destroy(prop
);
6965 scf_scope_destroy(scope
);
6966 scf_iter_destroy(siter
);
6967 scf_iter_destroy(sciter
);
6968 scf_iter_destroy(iter
);
6969 scf_instance_destroy(inst
);
6970 scf_service_destroy(svc
);
6976 * scf_encode32() is an implementation of Base32 encoding as described in
6977 * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
6978 * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648. The
6979 * input stream is divided into groups of 5 characters (40 bits). Each
6980 * group is encoded into 8 output characters where each output character
6981 * represents 5 bits of input.
6983 * If the input is not an even multiple of 5 characters, the output will be
6984 * padded so that the output is an even multiple of 8 characters. The
6985 * standard specifies that the pad character is '='. Unfortunately, '=' is
6986 * not a legal character in SMF property names. Thus, the caller can
6987 * specify an alternate pad character with the pad argument. If pad is 0,
6988 * scf_encode32() will use '='. Note that use of anything other than '='
6989 * produces output that is not in conformance with RFC 4648. It is
6990 * suitable, however, for internal use of SMF software. When the encoded
6991 * data is used as part of an SMF property name, SCF_ENCODE32_PAD should be
6992 * used as the pad character.
6995 * input - Address of the buffer to be encoded.
6996 * inlen - Number of characters at input.
6997 * output - Address of the buffer to receive the encoded data.
6998 * outmax - Size of the buffer at output.
6999 * outlen - If it is not NULL, outlen receives the number of
7000 * bytes placed in output.
7001 * pad - Alternate padding character.
7004 * 0 Buffer was successfully encoded.
7005 * -1 Indicates output buffer too small, or pad is one of the
7006 * standard encoding characters.
7009 scf_encode32(const char *input
, size_t inlen
, char *output
, size_t outmax
,
7010 size_t *outlen
, char pad
)
7012 uint_t group_size
= 5;
7014 const unsigned char *in
= (const unsigned char *)input
;
7016 uchar_t
*out
= (uchar_t
*)output
;
7020 /* Verify that there is enough room for the output. */
7021 olen
= ((inlen
+ (group_size
- 1)) / group_size
) * 8;
7027 /* If caller did not provide pad character, use the default. */
7032 * Make sure that caller's pad is not one of the encoding
7035 for (i
= 0; i
< sizeof (base32
) - 1; i
++) {
7036 if (pad
== base32
[i
])
7041 /* Process full groups capturing 5 bits per output character. */
7042 for (; inlen
>= group_size
; in
+= group_size
, inlen
-= group_size
) {
7044 * The comments in this section number the bits in an
7045 * 8 bit byte 0 to 7. The high order bit is bit 7 and
7046 * the low order bit is bit 0.
7049 /* top 5 bits (7-3) from in[0] */
7050 *out
++ = base32
[in
[0] >> 3];
7051 /* bits 2-0 from in[0] and top 2 (7-6) from in[1] */
7052 *out
++ = base32
[((in
[0] << 2) & 0x1c) | (in
[1] >> 6)];
7053 /* 5 bits (5-1) from in[1] */
7054 *out
++ = base32
[(in
[1] >> 1) & 0x1f];
7055 /* low bit (0) from in[1] and top 4 (7-4) from in[2] */
7056 *out
++ = base32
[((in
[1] << 4) & 0x10) | ((in
[2] >> 4) & 0xf)];
7057 /* low 4 (3-0) from in[2] and top bit (7) from in[3] */
7058 *out
++ = base32
[((in
[2] << 1) & 0x1e) | (in
[3] >> 7)];
7059 /* 5 bits (6-2) from in[3] */
7060 *out
++ = base32
[(in
[3] >> 2) & 0x1f];
7061 /* low 2 (1-0) from in[3] and top 3 (7-5) from in[4] */
7062 *out
++ = base32
[((in
[3] << 3) & 0x18) | (in
[4] >> 5)];
7063 /* low 5 (4-0) from in[4] */
7064 *out
++ = base32
[in
[4] & 0x1f];
7067 /* Take care of final input bytes. */
7070 /* top 5 bits (7-3) from in[0] */
7071 *out
++ = base32
[in
[0] >> 3];
7073 * low 3 (2-0) from in[0] and top 2 (7-6) from in[1] if
7076 oval
= (in
[0] << 2) & 0x1c;
7078 *out
++ = base32
[oval
];
7083 *out
++ = base32
[oval
];
7084 /* 5 bits (5-1) from in[1] */
7085 *out
++ = base32
[(in
[1] >> 1) & 0x1f];
7087 * low bit (0) from in[1] and top 4 (7-4) from in[2] if
7090 oval
= (in
[1] << 4) & 0x10;
7092 *out
++ = base32
[oval
];
7097 *out
++ = base32
[oval
];
7099 * low 4 (3-0) from in[2] and top 1 (7) from in[3] if
7102 oval
= (in
[2] << 1) & 0x1e;
7104 *out
++ = base32
[oval
];
7109 *out
++ = base32
[oval
];
7110 /* 5 bits (6-2) from in[3] */
7111 *out
++ = base32
[(in
[3] >> 2) & 0x1f];
7112 /* low 2 bits (1-0) from in[3] */
7113 *out
++ = base32
[(in
[3] << 3) & 0x18];
7118 * Pad the output so that it is a multiple of 8 bytes.
7120 for (; pad_count
> 0; pad_count
--) {
7125 * Null terminate the output if there is enough room.
7134 * scf_decode32() is an implementation of Base32 decoding as described in
7135 * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
7136 * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648. The
7137 * input stream is divided into groups of 8 encoded characters. Each
7138 * encoded character represents 5 bits of data. Thus, the 8 encoded
7139 * characters are used to produce 40 bits or 5 bytes of unencoded data in
7142 * If the encoder did not have enough data to generate a mulitple of 8
7143 * characters of encoded data, it used a pad character to get to the 8
7144 * character boundry. The standard specifies that the pad character is '='.
7145 * Unfortunately, '=' is not a legal character in SMF property names.
7146 * Thus, the caller can specify an alternate pad character with the pad
7147 * argument. If pad is 0, scf_decode32() will use '='. Note that use of
7148 * anything other than '=' is not in conformance with RFC 4648. It is
7149 * suitable, however, for internal use of SMF software. When the encoded
7150 * data is used in SMF property names, SCF_ENCODE32_PAD should be used as
7151 * the pad character.
7154 * in - Buffer of encoded characters.
7155 * inlen - Number of characters at in.
7156 * outbuf - Buffer to receive the decoded bytes. It can be the
7157 * same buffer as in.
7158 * outmax - Size of the buffer at outbuf.
7159 * outlen - If it is not NULL, outlen receives the number of
7160 * bytes placed in output.
7161 * pad - Alternate padding character.
7164 * 0 Buffer was successfully decoded.
7165 * -1 Indicates an invalid input character, output buffer too
7166 * small, or pad is one of the standard encoding characters.
7169 scf_decode32(const char *in
, size_t inlen
, char *outbuf
, size_t outmax
,
7170 size_t *outlen
, char pad
)
7172 char *bufend
= outbuf
+ outmax
;
7175 uint32_t g
[DECODE32_GS
];
7179 boolean_t pad_seen
= B_FALSE
;
7181 /* If caller did not provide pad character, use the default. */
7186 * Make sure that caller's pad is not one of the encoding
7189 for (i
= 0; i
< sizeof (base32
) - 1; i
++) {
7190 if (pad
== base32
[i
])
7196 while ((i
< inlen
) && (out
< bufend
)) {
7197 /* Get a group of input characters. */
7198 for (j
= 0, count
= 0;
7199 (j
< DECODE32_GS
) && (i
< inlen
);
7203 * RFC 4648 allows for the encoded data to be split
7204 * into multiple lines, so skip carriage returns
7207 if ((c
== '\r') || (c
== '\n'))
7209 if ((pad_seen
== B_TRUE
) && (c
!= pad
)) {
7210 /* Group not completed by pads */
7213 if ((c
< 0) || (c
>= sizeof (index32
))) {
7214 /* Illegal character. */
7221 if ((g
[j
++] = index32
[c
]) == 0xff) {
7222 /* Illegal character */
7228 /* Pack the group into five 8 bit bytes. */
7229 if ((count
>= 2) && (out
< bufend
)) {
7232 * 5 bits (7-3) from g[0]
7233 * 3 bits (2-0) from g[1] (4-2)
7235 *out
++ = (g
[0] << 3) | ((g
[1] >> 2) & 0x7);
7237 if ((count
>= 4) && (out
< bufend
)) {
7240 * 2 bits (7-6) from g[1] (1-0)
7241 * 5 bits (5-1) from g[2] (4-0)
7242 * 1 bit (0) from g[3] (4)
7244 *out
++ = (g
[1] << 6) | (g
[2] << 1) | \
7245 ((g
[3] >> 4) & 0x1);
7247 if ((count
>= 5) && (out
< bufend
)) {
7250 * 4 bits (7-4) from g[3] (3-0)
7251 * 4 bits (3-0) from g[4] (4-1)
7253 *out
++ = (g
[3] << 4) | ((g
[4] >> 1) & 0xf);
7255 if ((count
>= 7) && (out
< bufend
)) {
7258 * 1 bit (7) from g[4] (0)
7259 * 5 bits (6-2) from g[5] (4-0)
7260 * 2 bits (0-1) from g[6] (4-3)
7262 *out
++ = (g
[4] << 7) | (g
[5] << 2) |
7263 ((g
[6] >> 3) & 0x3);
7265 if ((count
== 8) && (out
< bufend
)) {
7268 * 3 bits (7-5) from g[6] (2-0)
7269 * 5 bits (4-0) from g[7] (4-0)
7271 *out
++ = (g
[6] << 5) | g
[7];
7275 /* Did not process all input characters. */
7279 *outlen
= out
- outbuf
;
7280 /* Null terminate the output if there is room. */
7288 * _scf_request_backup: a simple wrapper routine
7291 _scf_request_backup(scf_handle_t
*h
, const char *name
)
7293 struct rep_protocol_backup_request request
;
7294 struct rep_protocol_response response
;
7298 if (strlcpy(request
.rpr_name
, name
, sizeof (request
.rpr_name
)) >=
7299 sizeof (request
.rpr_name
))
7300 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
7302 (void) pthread_mutex_lock(&h
->rh_lock
);
7303 request
.rpr_request
= REP_PROTOCOL_BACKUP
;
7304 request
.rpr_changeid
= handle_next_changeid(h
);
7306 r
= make_door_call(h
, &request
, sizeof (request
),
7307 &response
, sizeof (response
));
7308 (void) pthread_mutex_unlock(&h
->rh_lock
);
7311 DOOR_ERRORS_BLOCK(r
);
7314 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
7315 return (scf_set_error(proto_error(response
.rpr_response
)));
7316 return (SCF_SUCCESS
);
7320 * Request svc.configd daemon to switch repository database.
7324 * _NOT_BOUND handle is not bound
7325 * _CONNECTION_BROKEN server is not reachable
7326 * _INTERNAL file operation error
7327 * the server response is too big
7328 * _PERMISSION_DENIED not enough privileges to do request
7329 * _BACKEND_READONLY backend is not writable
7330 * _BACKEND_ACCESS backend access fails
7331 * _NO_RESOURCES svc.configd is out of memory
7334 _scf_repository_switch(scf_handle_t
*h
, int scf_sw
)
7336 struct rep_protocol_switch_request request
;
7337 struct rep_protocol_response response
;
7341 * Setup request protocol and make door call
7342 * Hold rh_lock lock before handle_next_changeid call
7344 (void) pthread_mutex_lock(&h
->rh_lock
);
7346 request
.rpr_flag
= scf_sw
;
7347 request
.rpr_request
= REP_PROTOCOL_SWITCH
;
7348 request
.rpr_changeid
= handle_next_changeid(h
);
7350 r
= make_door_call(h
, &request
, sizeof (request
),
7351 &response
, sizeof (response
));
7353 (void) pthread_mutex_unlock(&h
->rh_lock
);
7356 DOOR_ERRORS_BLOCK(r
);
7360 * Pass protocol error up
7362 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
7363 return (scf_set_error(proto_error(response
.rpr_response
)));
7365 return (SCF_SUCCESS
);
7369 _scf_pg_is_read_protected(const scf_propertygroup_t
*pg
, boolean_t
*out
)
7371 char buf
[REP_PROTOCOL_NAME_LEN
];
7374 res
= datael_get_name(&pg
->rd_d
, buf
, sizeof (buf
),
7375 RP_ENTITY_NAME_PGREADPROT
);
7380 if (uu_strtouint(buf
, out
, sizeof (*out
), 0, 0, 1) == -1)
7381 return (scf_set_error(SCF_ERROR_INTERNAL
));
7382 return (SCF_SUCCESS
);
7386 * _scf_set_annotation: a wrapper to set the annotation fields for SMF
7387 * security auditing.
7389 * Fails with following in scf_error_key thread specific data:
7390 * _INVALID_ARGUMENT - operation or file too large
7392 * _CONNECTION_BROKEN
7397 _scf_set_annotation(scf_handle_t
*h
, const char *operation
, const char *file
)
7399 struct rep_protocol_annotation request
;
7400 struct rep_protocol_response response
;
7405 /* We can't do anything if the handle is destroyed. */
7406 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
7409 request
.rpr_request
= REP_PROTOCOL_SET_AUDIT_ANNOTATION
;
7410 copied
= strlcpy(request
.rpr_operation
,
7411 (operation
== NULL
) ? "" : operation
,
7412 sizeof (request
.rpr_operation
));
7413 if (copied
>= sizeof (request
.rpr_operation
))
7414 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
7416 copied
= strlcpy(request
.rpr_file
,
7417 (file
== NULL
) ? "" : file
,
7418 sizeof (request
.rpr_file
));
7419 if (copied
>= sizeof (request
.rpr_file
))
7420 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
7422 (void) pthread_mutex_lock(&h
->rh_lock
);
7423 r
= make_door_call(h
, &request
, sizeof (request
),
7424 &response
, sizeof (response
));
7425 (void) pthread_mutex_unlock(&h
->rh_lock
);
7428 DOOR_ERRORS_BLOCK(r
);
7431 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
7432 return (scf_set_error(proto_error(response
.rpr_response
)));