4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2013, Joyent, Inc. All rights reserved.
25 * Copyright 2016 RackTop Systems.
26 * Copyright (c) 2016 by Delphix. All rights reserved.
27 * Copyright 2017 OmniOS Community Edition (OmniOSce) Association.
31 * This is the main implementation file for the low-level repository
35 #include "lowlevel_impl.h"
37 #include "repcache_protocol.h"
55 #include <sys/sysmacros.h>
56 #include <libzonecfg.h>
60 #define ENV_SCF_DEBUG "LIBSCF_DEBUG"
61 #define ENV_SCF_DOORPATH "LIBSCF_DOORPATH"
63 static uint32_t default_debug
= 0;
64 static const char *default_door_path
= REPOSITORY_DOOR_NAME
;
66 #define CALL_FAILED -1
67 #define RESULT_TOO_BIG -2
70 static pthread_mutex_t lowlevel_init_lock
;
71 static int32_t lowlevel_inited
;
73 static uu_list_pool_t
*tran_entry_pool
;
74 static uu_list_pool_t
*datael_pool
;
75 static uu_list_pool_t
*iter_pool
;
78 * base32[] index32[] are used in base32 encoding and decoding.
80 static char base32
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
81 static char index32
[128] = {
82 -1, -1, -1, -1, -1, -1, -1, -1, /* 0-7 */
83 -1, -1, -1, -1, -1, -1, -1, -1, /* 8-15 */
84 -1, -1, -1, -1, -1, -1, -1, -1, /* 16-23 */
85 -1, -1, -1, -1, -1, -1, -1, -1, /* 24-31 */
86 -1, -1, -1, -1, -1, -1, -1, -1, /* 32-39 */
87 -1, -1, -1, -1, -1, -1, -1, -1, /* 40-47 */
88 -1, -1, 26, 27, 28, 29, 30, 31, /* 48-55 */
89 -1, -1, -1, -1, -1, -1, -1, -1, /* 56-63 */
90 -1, 0, 1, 2, 3, 4, 5, 6, /* 64-71 */
91 7, 8, 9, 10, 11, 12, 13, 14, /* 72-79 */
92 15, 16, 17, 18, 19, 20, 21, 22, /* 80-87 */
93 23, 24, 25, -1, -1, -1, -1, -1, /* 88-95 */
94 -1, -1, -1, -1, -1, -1, -1, -1, /* 96-103 */
95 -1, -1, -1, -1, -1, -1, -1, -1, /* 104-111 */
96 -1, -1, -1, -1, -1, -1, -1, -1, /* 112-119 */
97 -1, -1, -1, -1, -1, -1, -1, -1 /* 120-127 */
100 #define DECODE32_GS (8) /* scf_decode32 group size */
102 #define assert_nolint(x) assert(x)
104 static void scf_iter_reset_locked(scf_iter_t
*iter
);
105 static void scf_value_reset_locked(scf_value_t
*val
, int and_destroy
);
107 #define TYPE_VALUE (-100)
110 * Hold and release subhandles. We only allow one thread access to the
111 * subhandles at a time, and it can use any subset, grabbing and releasing
112 * them in any order. The only restrictions are that you cannot hold an
113 * already-held subhandle, and all subhandles must be released before
114 * returning to the original caller.
117 handle_hold_subhandles(scf_handle_t
*h
, int mask
)
119 assert(mask
!= 0 && (mask
& ~RH_HOLD_ALL
) == 0);
121 (void) pthread_mutex_lock(&h
->rh_lock
);
122 while (h
->rh_hold_flags
!= 0 && h
->rh_holder
!= pthread_self()) {
125 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
,
127 (void) pthread_cond_wait(&h
->rh_cv
, &h
->rh_lock
);
128 (void) pthread_setcancelstate(cancel_state
, NULL
);
130 if (h
->rh_hold_flags
== 0)
131 h
->rh_holder
= pthread_self();
132 assert(!(h
->rh_hold_flags
& mask
));
133 h
->rh_hold_flags
|= mask
;
134 (void) pthread_mutex_unlock(&h
->rh_lock
);
138 handle_rele_subhandles(scf_handle_t
*h
, int mask
)
140 assert(mask
!= 0 && (mask
& ~RH_HOLD_ALL
) == 0);
142 (void) pthread_mutex_lock(&h
->rh_lock
);
143 assert(h
->rh_holder
== pthread_self());
144 assert((h
->rh_hold_flags
& mask
));
146 h
->rh_hold_flags
&= ~mask
;
147 if (h
->rh_hold_flags
== 0)
148 (void) pthread_cond_signal(&h
->rh_cv
);
149 (void) pthread_mutex_unlock(&h
->rh_lock
);
152 #define HOLD_HANDLE(h, flag, field) \
153 (handle_hold_subhandles((h), (flag)), (h)->field)
155 #define RELE_HANDLE(h, flag) \
156 (handle_rele_subhandles((h), (flag)))
159 * convenience macros, for functions that only need a one or two handles at
162 #define HANDLE_HOLD_ITER(h) HOLD_HANDLE((h), RH_HOLD_ITER, rh_iter)
163 #define HANDLE_HOLD_SCOPE(h) HOLD_HANDLE((h), RH_HOLD_SCOPE, rh_scope)
164 #define HANDLE_HOLD_SERVICE(h) HOLD_HANDLE((h), RH_HOLD_SERVICE, rh_service)
165 #define HANDLE_HOLD_INSTANCE(h) HOLD_HANDLE((h), RH_HOLD_INSTANCE, rh_instance)
166 #define HANDLE_HOLD_SNAPSHOT(h) HOLD_HANDLE((h), RH_HOLD_SNAPSHOT, rh_snapshot)
167 #define HANDLE_HOLD_SNAPLVL(h) HOLD_HANDLE((h), RH_HOLD_SNAPLVL, rh_snaplvl)
168 #define HANDLE_HOLD_PG(h) HOLD_HANDLE((h), RH_HOLD_PG, rh_pg)
169 #define HANDLE_HOLD_PROPERTY(h) HOLD_HANDLE((h), RH_HOLD_PROPERTY, rh_property)
170 #define HANDLE_HOLD_VALUE(h) HOLD_HANDLE((h), RH_HOLD_VALUE, rh_value)
172 #define HANDLE_RELE_ITER(h) RELE_HANDLE((h), RH_HOLD_ITER)
173 #define HANDLE_RELE_SCOPE(h) RELE_HANDLE((h), RH_HOLD_SCOPE)
174 #define HANDLE_RELE_SERVICE(h) RELE_HANDLE((h), RH_HOLD_SERVICE)
175 #define HANDLE_RELE_INSTANCE(h) RELE_HANDLE((h), RH_HOLD_INSTANCE)
176 #define HANDLE_RELE_SNAPSHOT(h) RELE_HANDLE((h), RH_HOLD_SNAPSHOT)
177 #define HANDLE_RELE_SNAPLVL(h) RELE_HANDLE((h), RH_HOLD_SNAPLVL)
178 #define HANDLE_RELE_PG(h) RELE_HANDLE((h), RH_HOLD_PG)
179 #define HANDLE_RELE_PROPERTY(h) RELE_HANDLE((h), RH_HOLD_PROPERTY)
180 #define HANDLE_RELE_VALUE(h) RELE_HANDLE((h), RH_HOLD_VALUE)
184 transaction_entry_compare(const void *l_arg
, const void *r_arg
, void *private)
187 ((scf_transaction_entry_t
*)l_arg
)->entry_property
;
189 ((scf_transaction_entry_t
*)r_arg
)->entry_property
;
193 ret
= strcmp(l_prop
, r_prop
);
202 datael_compare(const void *l_arg
, const void *r_arg
, void *private)
204 uint32_t l_id
= ((scf_datael_t
*)l_arg
)->rd_entity
;
205 uint32_t r_id
= (r_arg
!= NULL
) ? ((scf_datael_t
*)r_arg
)->rd_entity
:
206 *(uint32_t *)private;
216 iter_compare(const void *l_arg
, const void *r_arg
, void *private)
218 uint32_t l_id
= ((scf_iter_t
*)l_arg
)->iter_id
;
219 uint32_t r_id
= (r_arg
!= NULL
) ? ((scf_iter_t
*)r_arg
)->iter_id
:
220 *(uint32_t *)private;
233 const char *door_path
;
235 (void) pthread_mutex_lock(&lowlevel_init_lock
);
236 if (lowlevel_inited
== 0) {
238 (debug
= getenv(ENV_SCF_DEBUG
)) != NULL
&& debug
[0] != 0 &&
239 uu_strtoint(debug
, &default_debug
, sizeof (default_debug
),
241 (void) fprintf(stderr
, "LIBSCF: $%s (%s): %s",
242 ENV_SCF_DEBUG
, debug
,
243 uu_strerror(uu_error()));
247 (door_path
= getenv(ENV_SCF_DOORPATH
)) != NULL
&&
249 default_door_path
= strdup(door_path
);
250 if (default_door_path
== NULL
)
251 default_door_path
= door_path
;
254 datael_pool
= uu_list_pool_create("SUNW,libscf_datael",
255 sizeof (scf_datael_t
), offsetof(scf_datael_t
, rd_node
),
256 datael_compare
, UU_LIST_POOL_DEBUG
);
258 iter_pool
= uu_list_pool_create("SUNW,libscf_iter",
259 sizeof (scf_iter_t
), offsetof(scf_iter_t
, iter_node
),
260 iter_compare
, UU_LIST_POOL_DEBUG
);
262 assert_nolint(offsetof(scf_transaction_entry_t
,
263 entry_property
) == 0);
264 tran_entry_pool
= uu_list_pool_create(
265 "SUNW,libscf_transaction_entity",
266 sizeof (scf_transaction_entry_t
),
267 offsetof(scf_transaction_entry_t
, entry_link
),
268 transaction_entry_compare
, UU_LIST_POOL_DEBUG
);
270 if (datael_pool
== NULL
|| iter_pool
== NULL
||
271 tran_entry_pool
== NULL
) {
272 lowlevel_inited
= -1;
276 if (!scf_setup_error()) {
277 lowlevel_inited
= -1;
283 (void) pthread_mutex_unlock(&lowlevel_init_lock
);
284 if (lowlevel_inited
> 0)
289 static const struct {
291 rep_protocol_value_type_t ti_proto_type
;
293 } scf_type_info
[] = {
294 {SCF_TYPE_BOOLEAN
, REP_PROTOCOL_TYPE_BOOLEAN
,
295 SCF_TYPE_STRING_BOOLEAN
},
296 {SCF_TYPE_COUNT
, REP_PROTOCOL_TYPE_COUNT
,
297 SCF_TYPE_STRING_COUNT
},
298 {SCF_TYPE_INTEGER
, REP_PROTOCOL_TYPE_INTEGER
,
299 SCF_TYPE_STRING_INTEGER
},
300 {SCF_TYPE_TIME
, REP_PROTOCOL_TYPE_TIME
,
301 SCF_TYPE_STRING_TIME
},
302 {SCF_TYPE_ASTRING
, REP_PROTOCOL_TYPE_STRING
,
303 SCF_TYPE_STRING_ASTRING
},
304 {SCF_TYPE_OPAQUE
, REP_PROTOCOL_TYPE_OPAQUE
,
305 SCF_TYPE_STRING_OPAQUE
},
306 {SCF_TYPE_USTRING
, REP_PROTOCOL_SUBTYPE_USTRING
,
307 SCF_TYPE_STRING_USTRING
},
308 {SCF_TYPE_URI
, REP_PROTOCOL_SUBTYPE_URI
,
309 SCF_TYPE_STRING_URI
},
310 {SCF_TYPE_FMRI
, REP_PROTOCOL_SUBTYPE_FMRI
,
311 SCF_TYPE_STRING_FMRI
},
312 {SCF_TYPE_HOST
, REP_PROTOCOL_SUBTYPE_HOST
,
313 SCF_TYPE_STRING_HOST
},
314 {SCF_TYPE_HOSTNAME
, REP_PROTOCOL_SUBTYPE_HOSTNAME
,
315 SCF_TYPE_STRING_HOSTNAME
},
316 {SCF_TYPE_NET_ADDR
, REP_PROTOCOL_SUBTYPE_NETADDR
,
317 SCF_TYPE_STRING_NET_ADDR
},
318 {SCF_TYPE_NET_ADDR_V4
, REP_PROTOCOL_SUBTYPE_NETADDR_V4
,
319 SCF_TYPE_STRING_NET_ADDR_V4
},
320 {SCF_TYPE_NET_ADDR_V6
, REP_PROTOCOL_SUBTYPE_NETADDR_V6
,
321 SCF_TYPE_STRING_NET_ADDR_V6
}
324 #define SCF_TYPE_INFO_COUNT (sizeof (scf_type_info) / sizeof (*scf_type_info))
325 static rep_protocol_value_type_t
326 scf_type_to_protocol_type(scf_type_t t
)
330 for (i
= 0; i
< SCF_TYPE_INFO_COUNT
; i
++)
331 if (scf_type_info
[i
].ti_type
== t
)
332 return (scf_type_info
[i
].ti_proto_type
);
334 return (REP_PROTOCOL_TYPE_INVALID
);
338 scf_protocol_type_to_type(rep_protocol_value_type_t t
)
342 for (i
= 0; i
< SCF_TYPE_INFO_COUNT
; i
++)
343 if (scf_type_info
[i
].ti_proto_type
== t
)
344 return (scf_type_info
[i
].ti_type
);
346 return (SCF_TYPE_INVALID
);
350 scf_type_to_string(scf_type_t ty
)
354 for (i
= 0; i
< SCF_TYPE_INFO_COUNT
; i
++)
355 if (scf_type_info
[i
].ti_type
== ty
)
356 return (scf_type_info
[i
].ti_name
);
362 scf_string_to_type(const char *name
)
366 for (i
= 0; i
< sizeof (scf_type_info
) / sizeof (*scf_type_info
); i
++)
367 if (strcmp(scf_type_info
[i
].ti_name
, name
) == 0)
368 return (scf_type_info
[i
].ti_type
);
370 return (SCF_TYPE_INVALID
);
374 scf_type_base_type(scf_type_t type
, scf_type_t
*out
)
376 rep_protocol_value_type_t t
= scf_type_to_protocol_type(type
);
377 if (t
== REP_PROTOCOL_TYPE_INVALID
)
378 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
380 *out
= scf_protocol_type_to_type(scf_proto_underlying_type(t
));
381 return (SCF_SUCCESS
);
385 * Convert a protocol error code into an SCF_ERROR_* code.
388 proto_error(rep_protocol_responseid_t e
)
391 case REP_PROTOCOL_FAIL_MISORDERED
:
392 case REP_PROTOCOL_FAIL_UNKNOWN_ID
:
393 case REP_PROTOCOL_FAIL_INVALID_TYPE
:
394 case REP_PROTOCOL_FAIL_TRUNCATED
:
395 case REP_PROTOCOL_FAIL_TYPE_MISMATCH
:
396 case REP_PROTOCOL_FAIL_NOT_APPLICABLE
:
397 case REP_PROTOCOL_FAIL_UNKNOWN
:
398 return (SCF_ERROR_INTERNAL
);
400 case REP_PROTOCOL_FAIL_BAD_TX
:
401 return (SCF_ERROR_INVALID_ARGUMENT
);
402 case REP_PROTOCOL_FAIL_BAD_REQUEST
:
403 return (SCF_ERROR_INVALID_ARGUMENT
);
404 case REP_PROTOCOL_FAIL_NO_RESOURCES
:
405 return (SCF_ERROR_NO_RESOURCES
);
406 case REP_PROTOCOL_FAIL_NOT_FOUND
:
407 return (SCF_ERROR_NOT_FOUND
);
408 case REP_PROTOCOL_FAIL_DELETED
:
409 return (SCF_ERROR_DELETED
);
410 case REP_PROTOCOL_FAIL_NOT_SET
:
411 return (SCF_ERROR_NOT_SET
);
412 case REP_PROTOCOL_FAIL_EXISTS
:
413 return (SCF_ERROR_EXISTS
);
414 case REP_PROTOCOL_FAIL_DUPLICATE_ID
:
415 return (SCF_ERROR_EXISTS
);
416 case REP_PROTOCOL_FAIL_PERMISSION_DENIED
:
417 return (SCF_ERROR_PERMISSION_DENIED
);
418 case REP_PROTOCOL_FAIL_BACKEND_ACCESS
:
419 return (SCF_ERROR_BACKEND_ACCESS
);
420 case REP_PROTOCOL_FAIL_BACKEND_READONLY
:
421 return (SCF_ERROR_BACKEND_READONLY
);
423 case REP_PROTOCOL_SUCCESS
:
424 case REP_PROTOCOL_DONE
:
425 case REP_PROTOCOL_FAIL_NOT_LATEST
: /* TX code should handle this */
428 uu_warn("%s:%d: Bad error code %d passed to proto_error().\n",
429 __FILE__
, __LINE__
, e
);
437 scf_limit(uint32_t limit
)
440 case SCF_LIMIT_MAX_NAME_LENGTH
:
441 case SCF_LIMIT_MAX_PG_TYPE_LENGTH
:
442 return (REP_PROTOCOL_NAME_LEN
- 1);
443 case SCF_LIMIT_MAX_VALUE_LENGTH
:
444 return (REP_PROTOCOL_VALUE_LEN
- 1);
445 case SCF_LIMIT_MAX_FMRI_LENGTH
:
446 return (SCF_FMRI_PREFIX_MAX_LEN
+
447 sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1 +
448 sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1 +
449 sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1 +
450 sizeof (SCF_FMRI_INSTANCE_PREFIX
) - 1 +
451 sizeof (SCF_FMRI_PROPERTYGRP_PREFIX
) - 1 +
452 sizeof (SCF_FMRI_PROPERTY_PREFIX
) - 1 +
453 5 * (REP_PROTOCOL_NAME_LEN
- 1));
455 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
460 scf_opaque_decode(char *out_arg
, const char *in
, size_t max_out
)
465 while (max_out
> 0 && (a
= in
[0]) != 0 && (b
= in
[1]) != 0) {
468 if (a
>= '0' && a
<= '9')
470 else if (a
>= 'a' && a
<= 'f')
472 else if (a
>= 'A' && a
<= 'F')
477 if (b
>= '0' && b
<= '9')
479 else if (b
>= 'a' && b
<= 'f')
481 else if (b
>= 'A' && b
<= 'F')
486 *out
++ = (a
<< 4) | b
;
490 return (out
- out_arg
);
494 scf_opaque_encode(char *out_arg
, const char *in_arg
, size_t in_sz
)
496 uint8_t *in
= (uint8_t *)in_arg
;
497 uint8_t *end
= in
+ in_sz
;
506 uint8_t a
= (c
& 0xf0) >> 4;
507 uint8_t b
= (c
& 0x0f);
512 *out
++ = a
+ 'a' - 10;
517 *out
++ = b
+ 'a' - 10;
522 return (out
- out_arg
);
526 handle_do_close(scf_handle_t
*h
)
528 assert(MUTEX_HELD(&h
->rh_lock
));
529 assert(h
->rh_doorfd
!= -1);
532 * if there are any active FD users, we just move the FD over
533 * to rh_doorfd_old -- they'll close it when they finish.
535 if (h
->rh_fd_users
> 0) {
536 h
->rh_doorfd_old
= h
->rh_doorfd
;
539 assert(h
->rh_doorfd_old
== -1);
540 (void) close(h
->rh_doorfd
);
546 * Check if a handle is currently bound. fork()ing implicitly unbinds
547 * the handle in the child.
550 handle_is_bound(scf_handle_t
*h
)
552 assert(MUTEX_HELD(&h
->rh_lock
));
554 if (h
->rh_doorfd
== -1)
557 if (getpid() == h
->rh_doorpid
)
560 /* forked since our last bind -- initiate handle close */
566 handle_has_server_locked(scf_handle_t
*h
)
569 assert(MUTEX_HELD(&h
->rh_lock
));
571 return (handle_is_bound(h
) && door_info(h
->rh_doorfd
, &i
) != -1 &&
576 handle_has_server(scf_handle_t
*h
)
580 (void) pthread_mutex_lock(&h
->rh_lock
);
581 ret
= handle_has_server_locked(h
);
582 (void) pthread_mutex_unlock(&h
->rh_lock
);
588 * This makes a door request on the client door associated with handle h.
589 * It will automatically retry calls which fail on EINTR. If h is not bound,
590 * returns NOT_BOUND. If the door call fails or the server response is too
591 * small, returns CALL_FAILED. If the server response is too big, truncates the
592 * response and returns RESULT_TOO_BIG. Otherwise, the size of the result is
596 make_door_call(scf_handle_t
*h
, const void *req
, size_t req_sz
,
597 void *res
, size_t res_sz
)
602 assert(MUTEX_HELD(&h
->rh_lock
));
604 if (!handle_is_bound(h
)) {
608 arg
.data_ptr
= (void *)req
;
609 arg
.data_size
= req_sz
;
615 while ((r
= door_call(h
->rh_doorfd
, &arg
)) < 0) {
621 return (CALL_FAILED
);
624 if (arg
.desc_num
> 0) {
625 while (arg
.desc_num
> 0) {
626 if (arg
.desc_ptr
->d_attributes
& DOOR_DESCRIPTOR
) {
627 int cfd
= arg
.desc_ptr
->d_data
.d_desc
.d_id
;
634 if (arg
.data_ptr
!= res
&& arg
.data_size
> 0)
635 (void) memmove(res
, arg
.data_ptr
, MIN(arg
.data_size
, res_sz
));
638 (void) munmap(arg
.rbuf
, arg
.rsize
);
640 if (arg
.data_size
> res_sz
)
641 return (RESULT_TOO_BIG
);
643 if (arg
.data_size
< sizeof (uint32_t))
644 return (CALL_FAILED
);
646 return (arg
.data_size
);
650 * Should only be used when r < 0.
652 #define DOOR_ERRORS_BLOCK(r) { \
655 return (scf_set_error(SCF_ERROR_NOT_BOUND)); \
658 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN)); \
660 case RESULT_TOO_BIG: \
661 return (scf_set_error(SCF_ERROR_INTERNAL)); \
664 assert(r == NOT_BOUND || r == CALL_FAILED || \
665 r == RESULT_TOO_BIG); \
671 * Like make_door_call(), but takes an fd instead of a handle, and expects
672 * a single file descriptor, returned via res_fd.
674 * If no file descriptor is returned, *res_fd == -1.
677 make_door_call_retfd(int fd
, const void *req
, size_t req_sz
, void *res
,
678 size_t res_sz
, int *res_fd
)
689 arg
.data_ptr
= (void *)req
;
690 arg
.data_size
= req_sz
;
694 arg
.rsize
= sizeof (rbuf
);
696 while ((r
= door_call(fd
, &arg
)) < 0) {
702 return (CALL_FAILED
);
704 if (arg
.desc_num
> 1) {
705 while (arg
.desc_num
> 0) {
706 if (arg
.desc_ptr
->d_attributes
& DOOR_DESCRIPTOR
) {
708 arg
.desc_ptr
->d_data
.d_desc
.d_descriptor
;
715 if (arg
.desc_num
== 1 && arg
.desc_ptr
->d_attributes
& DOOR_DESCRIPTOR
)
716 *res_fd
= arg
.desc_ptr
->d_data
.d_desc
.d_descriptor
;
718 if (arg
.data_size
> 0)
719 (void) memmove(res
, arg
.data_ptr
, MIN(arg
.data_size
, res_sz
));
721 if (arg
.rbuf
!= rbuf
)
722 (void) munmap(arg
.rbuf
, arg
.rsize
);
724 if (arg
.data_size
> res_sz
)
725 return (RESULT_TOO_BIG
);
727 if (arg
.data_size
< sizeof (uint32_t))
728 return (CALL_FAILED
);
730 return (arg
.data_size
);
739 scf_handle_create(scf_version_t v
)
745 * This will need to be revisited when we bump SCF_VERSION
747 if (v
!= SCF_VERSION
) {
748 (void) scf_set_error(SCF_ERROR_VERSION_MISMATCH
);
752 if (!lowlevel_init()) {
753 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
757 ret
= uu_zalloc(sizeof (*ret
));
759 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
763 ret
->rh_dataels
= uu_list_create(datael_pool
, ret
, 0);
764 ret
->rh_iters
= uu_list_create(iter_pool
, ret
, 0);
765 if (ret
->rh_dataels
== NULL
|| ret
->rh_iters
== NULL
) {
766 if (ret
->rh_dataels
!= NULL
)
767 uu_list_destroy(ret
->rh_dataels
);
768 if (ret
->rh_iters
!= NULL
)
769 uu_list_destroy(ret
->rh_iters
);
771 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
776 ret
->rh_doorfd_old
= -1;
777 (void) pthread_mutex_init(&ret
->rh_lock
, NULL
);
779 handle_hold_subhandles(ret
, RH_HOLD_ALL
);
781 failed
= ((ret
->rh_iter
= scf_iter_create(ret
)) == NULL
||
782 (ret
->rh_scope
= scf_scope_create(ret
)) == NULL
||
783 (ret
->rh_service
= scf_service_create(ret
)) == NULL
||
784 (ret
->rh_instance
= scf_instance_create(ret
)) == NULL
||
785 (ret
->rh_snapshot
= scf_snapshot_create(ret
)) == NULL
||
786 (ret
->rh_snaplvl
= scf_snaplevel_create(ret
)) == NULL
||
787 (ret
->rh_pg
= scf_pg_create(ret
)) == NULL
||
788 (ret
->rh_property
= scf_property_create(ret
)) == NULL
||
789 (ret
->rh_value
= scf_value_create(ret
)) == NULL
);
792 * these subhandles count as internal references, not external ones.
794 ret
->rh_intrefs
= ret
->rh_extrefs
;
796 handle_rele_subhandles(ret
, RH_HOLD_ALL
);
799 scf_handle_destroy(ret
);
800 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
804 scf_value_set_count(ret
->rh_value
, default_debug
);
805 (void) scf_handle_decorate(ret
, "debug", ret
->rh_value
);
813 * _NO_SERVER - server door could not be open()ed
816 * _VERSION_MISMATCH - server returned bad file descriptor
817 * server claimed bad request
818 * server reported version mismatch
819 * server refused with unknown reason
821 * _NO_RESOURCES - server is out of memory
823 * _INTERNAL - could not set up entities or iters
824 * server response too big
827 _scf_handle_create_and_bind(scf_version_t ver
)
831 h
= scf_handle_create(ver
);
835 if (scf_handle_bind(h
) == -1) {
836 scf_handle_destroy(h
);
843 scf_handle_decorate(scf_handle_t
*handle
, const char *name
, scf_value_t
*v
)
845 if (v
!= SCF_DECORATE_CLEAR
&& handle
!= v
->value_handle
)
846 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
848 (void) pthread_mutex_lock(&handle
->rh_lock
);
849 if (handle_is_bound(handle
)) {
850 (void) pthread_mutex_unlock(&handle
->rh_lock
);
851 return (scf_set_error(SCF_ERROR_IN_USE
));
853 (void) pthread_mutex_unlock(&handle
->rh_lock
);
855 if (strcmp(name
, "debug") == 0) {
856 if (v
== SCF_DECORATE_CLEAR
) {
857 (void) pthread_mutex_lock(&handle
->rh_lock
);
858 handle
->rh_debug
= 0;
859 (void) pthread_mutex_unlock(&handle
->rh_lock
);
862 if (scf_value_get_count(v
, &val
) < 0)
863 return (-1); /* error already set */
865 (void) pthread_mutex_lock(&handle
->rh_lock
);
866 handle
->rh_debug
= (uid_t
)val
;
867 (void) pthread_mutex_unlock(&handle
->rh_lock
);
871 if (strcmp(name
, "door_path") == 0) {
872 char name
[sizeof (handle
->rh_doorpath
)];
874 if (v
== SCF_DECORATE_CLEAR
) {
875 (void) pthread_mutex_lock(&handle
->rh_lock
);
876 handle
->rh_doorpath
[0] = 0;
877 (void) pthread_mutex_unlock(&handle
->rh_lock
);
881 if ((len
= scf_value_get_astring(v
, name
,
882 sizeof (name
))) < 0) {
883 return (-1); /* error already set */
885 if (len
== 0 || len
>= sizeof (name
)) {
886 return (scf_set_error(
887 SCF_ERROR_INVALID_ARGUMENT
));
889 (void) pthread_mutex_lock(&handle
->rh_lock
);
890 (void) strlcpy(handle
->rh_doorpath
, name
,
891 sizeof (handle
->rh_doorpath
));
892 (void) pthread_mutex_unlock(&handle
->rh_lock
);
897 if (strcmp(name
, "zone") == 0) {
898 char zone
[MAXPATHLEN
], root
[MAXPATHLEN
], door
[MAXPATHLEN
];
899 static int (*zone_get_rootpath
)(char *, char *, size_t);
903 * In order to be able to set the zone on a handle, we want
904 * to determine the zone's path, which requires us to call into
905 * libzonecfg -- but libzonecfg.so links against libscf.so so
906 * we must not explicitly link to it. To circumvent the
907 * circular dependency, we will pull it in here via dlopen().
909 if (zone_get_rootpath
== NULL
) {
910 void *dl
= dlopen("libzonecfg.so.1", RTLD_LAZY
), *sym
;
913 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
915 if ((sym
= dlsym(dl
, "zone_get_rootpath")) == NULL
) {
917 return (scf_set_error(SCF_ERROR_INTERNAL
));
920 zone_get_rootpath
= (int(*)(char *, char *, size_t))sym
;
923 if (v
== SCF_DECORATE_CLEAR
) {
924 (void) pthread_mutex_lock(&handle
->rh_lock
);
925 handle
->rh_doorpath
[0] = 0;
926 (void) pthread_mutex_unlock(&handle
->rh_lock
);
931 if ((len
= scf_value_get_astring(v
, zone
, sizeof (zone
))) < 0)
934 if (len
== 0 || len
>= sizeof (zone
))
935 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
937 if (zone_get_rootpath(zone
, root
, sizeof (root
)) != Z_OK
) {
938 if (strcmp(zone
, GLOBAL_ZONENAME
) == 0) {
941 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
945 if (snprintf(door
, sizeof (door
), "%s/%s", root
,
946 default_door_path
) >= sizeof (door
))
947 return (scf_set_error(SCF_ERROR_INTERNAL
));
949 (void) pthread_mutex_lock(&handle
->rh_lock
);
950 (void) strlcpy(handle
->rh_doorpath
, door
,
951 sizeof (handle
->rh_doorpath
));
952 (void) pthread_mutex_unlock(&handle
->rh_lock
);
957 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
961 * fails with INVALID_ARGUMENT and HANDLE_MISMATCH.
964 _scf_handle_decorations(scf_handle_t
*handle
, scf_decoration_func
*f
,
965 scf_value_t
*v
, void *data
)
967 scf_decoration_info_t i
;
968 char name
[sizeof (handle
->rh_doorpath
)];
971 if (f
== NULL
|| v
== NULL
)
972 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
974 if (v
->value_handle
!= handle
)
975 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
977 i
.sdi_name
= (const char *)"debug";
978 i
.sdi_type
= SCF_TYPE_COUNT
;
979 (void) pthread_mutex_lock(&handle
->rh_lock
);
980 debug
= handle
->rh_debug
;
981 (void) pthread_mutex_unlock(&handle
->rh_lock
);
983 scf_value_set_count(v
, debug
);
986 i
.sdi_value
= SCF_DECORATE_CLEAR
;
989 if ((*f
)(&i
, data
) == 0)
992 i
.sdi_name
= (const char *)"door_path";
993 i
.sdi_type
= SCF_TYPE_ASTRING
;
994 (void) pthread_mutex_lock(&handle
->rh_lock
);
995 (void) strlcpy(name
, handle
->rh_doorpath
, sizeof (name
));
996 (void) pthread_mutex_unlock(&handle
->rh_lock
);
998 (void) scf_value_set_astring(v
, name
);
1001 i
.sdi_value
= SCF_DECORATE_CLEAR
;
1004 if ((*f
)(&i
, data
) == 0)
1011 * Fails if handle is not bound.
1014 handle_unbind_unlocked(scf_handle_t
*handle
)
1016 rep_protocol_request_t request
;
1017 rep_protocol_response_t response
;
1019 if (!handle_is_bound(handle
))
1022 request
.rpr_request
= REP_PROTOCOL_CLOSE
;
1024 (void) make_door_call(handle
, &request
, sizeof (request
),
1025 &response
, sizeof (response
));
1027 handle_do_close(handle
);
1029 return (SCF_SUCCESS
);
1034 * _HANDLE_DESTROYED - dp's handle has been destroyed
1035 * _INTERNAL - server response too big
1036 * entity already set up with different type
1037 * _NO_RESOURCES - server out of memory
1040 datael_attach(scf_datael_t
*dp
)
1042 scf_handle_t
*h
= dp
->rd_handle
;
1044 struct rep_protocol_entity_setup request
;
1045 rep_protocol_response_t response
;
1048 assert(MUTEX_HELD(&h
->rh_lock
));
1050 dp
->rd_reset
= 0; /* setup implicitly resets */
1052 if (h
->rh_flags
& HANDLE_DEAD
)
1053 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
1055 if (!handle_is_bound(h
))
1056 return (SCF_SUCCESS
); /* nothing to do */
1058 request
.rpr_request
= REP_PROTOCOL_ENTITY_SETUP
;
1059 request
.rpr_entityid
= dp
->rd_entity
;
1060 request
.rpr_entitytype
= dp
->rd_type
;
1062 r
= make_door_call(h
, &request
, sizeof (request
),
1063 &response
, sizeof (response
));
1065 if (r
== NOT_BOUND
|| r
== CALL_FAILED
)
1066 return (SCF_SUCCESS
);
1067 if (r
== RESULT_TOO_BIG
)
1068 return (scf_set_error(SCF_ERROR_INTERNAL
));
1070 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1071 return (scf_set_error(proto_error(response
.rpr_response
)));
1073 return (SCF_SUCCESS
);
1078 * _HANDLE_DESTROYED - iter's handle has been destroyed
1079 * _INTERNAL - server response too big
1080 * iter already existed
1084 iter_attach(scf_iter_t
*iter
)
1086 scf_handle_t
*h
= iter
->iter_handle
;
1087 struct rep_protocol_iter_request request
;
1088 struct rep_protocol_response response
;
1091 assert(MUTEX_HELD(&h
->rh_lock
));
1093 if (h
->rh_flags
& HANDLE_DEAD
)
1094 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
1096 if (!handle_is_bound(h
))
1097 return (SCF_SUCCESS
); /* nothing to do */
1099 request
.rpr_request
= REP_PROTOCOL_ITER_SETUP
;
1100 request
.rpr_iterid
= iter
->iter_id
;
1102 r
= make_door_call(h
, &request
, sizeof (request
),
1103 &response
, sizeof (response
));
1105 if (r
== NOT_BOUND
|| r
== CALL_FAILED
)
1106 return (SCF_SUCCESS
);
1107 if (r
== RESULT_TOO_BIG
)
1108 return (scf_set_error(SCF_ERROR_INTERNAL
));
1110 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1111 return (scf_set_error(proto_error(response
.rpr_response
)));
1113 return (SCF_SUCCESS
);
1118 * _IN_USE - handle already bound
1119 * _NO_SERVER - server door could not be open()ed
1121 * door_info() failed
1122 * _VERSION_MISMATCH - server returned bad file descriptor
1123 * server claimed bad request
1124 * server reported version mismatch
1125 * server refused with unknown reason
1127 * _NO_RESOURCES - server is out of memory
1128 * _PERMISSION_DENIED
1129 * _INTERNAL - could not set up entities or iters
1130 * server response too big
1132 * perhaps this should try multiple times.
1135 scf_handle_bind(scf_handle_t
*handle
)
1144 repository_door_request_t request
;
1145 repository_door_response_t response
;
1146 const char *door_name
= default_door_path
;
1148 (void) pthread_mutex_lock(&handle
->rh_lock
);
1149 if (handle_is_bound(handle
)) {
1150 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1151 return (scf_set_error(SCF_ERROR_IN_USE
));
1154 /* wait until any active fd users have cleared out */
1155 while (handle
->rh_fd_users
> 0) {
1158 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
,
1160 (void) pthread_cond_wait(&handle
->rh_cv
, &handle
->rh_lock
);
1161 (void) pthread_setcancelstate(cancel_state
, NULL
);
1164 /* check again, since we had to drop the lock */
1165 if (handle_is_bound(handle
)) {
1166 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1167 return (scf_set_error(SCF_ERROR_IN_USE
));
1170 assert(handle
->rh_doorfd
== -1 && handle
->rh_doorfd_old
== -1);
1172 if (handle
->rh_doorpath
[0] != 0)
1173 door_name
= handle
->rh_doorpath
;
1175 fd
= open(door_name
, O_RDONLY
, 0);
1177 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1178 return (scf_set_error(SCF_ERROR_NO_SERVER
));
1181 request
.rdr_version
= REPOSITORY_DOOR_VERSION
;
1182 request
.rdr_request
= REPOSITORY_DOOR_REQUEST_CONNECT
;
1183 request
.rdr_flags
= handle
->rh_flags
;
1184 request
.rdr_debug
= handle
->rh_debug
;
1188 res
= make_door_call_retfd(fd
, &request
, sizeof (request
),
1189 &response
, sizeof (response
), &handle
->rh_doorfd
);
1194 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1196 assert(res
!= NOT_BOUND
);
1197 if (res
== CALL_FAILED
)
1198 return (scf_set_error(SCF_ERROR_NO_SERVER
));
1199 assert(res
== RESULT_TOO_BIG
);
1200 return (scf_set_error(SCF_ERROR_INTERNAL
));
1203 if (handle
->rh_doorfd
< 0) {
1204 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1206 switch (response
.rdr_status
) {
1207 case REPOSITORY_DOOR_SUCCESS
:
1208 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1210 case REPOSITORY_DOOR_FAIL_BAD_REQUEST
:
1211 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1213 case REPOSITORY_DOOR_FAIL_VERSION_MISMATCH
:
1214 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1216 case REPOSITORY_DOOR_FAIL_BAD_FLAG
:
1217 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1219 case REPOSITORY_DOOR_FAIL_NO_RESOURCES
:
1220 return (scf_set_error(SCF_ERROR_NO_RESOURCES
));
1222 case REPOSITORY_DOOR_FAIL_PERMISSION_DENIED
:
1223 return (scf_set_error(SCF_ERROR_PERMISSION_DENIED
));
1226 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1230 (void) fcntl(handle
->rh_doorfd
, F_SETFD
, FD_CLOEXEC
);
1232 if (door_info(handle
->rh_doorfd
, &info
) < 0) {
1233 (void) close(handle
->rh_doorfd
);
1234 handle
->rh_doorfd
= -1;
1236 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1237 return (scf_set_error(SCF_ERROR_NO_SERVER
));
1240 handle
->rh_doorpid
= pid
;
1241 handle
->rh_doorid
= info
.di_uniquifier
;
1244 * Now, re-attach everything
1246 for (el
= uu_list_first(handle
->rh_dataels
); el
!= NULL
;
1247 el
= uu_list_next(handle
->rh_dataels
, el
)) {
1248 if (datael_attach(el
) == -1) {
1249 assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED
);
1250 (void) handle_unbind_unlocked(handle
);
1251 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1256 for (iter
= uu_list_first(handle
->rh_iters
); iter
!= NULL
;
1257 iter
= uu_list_next(handle
->rh_iters
, iter
)) {
1258 if (iter_attach(iter
) == -1) {
1259 assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED
);
1260 (void) handle_unbind_unlocked(handle
);
1261 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1265 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1266 return (SCF_SUCCESS
);
1270 scf_handle_unbind(scf_handle_t
*handle
)
1273 (void) pthread_mutex_lock(&handle
->rh_lock
);
1274 ret
= handle_unbind_unlocked(handle
);
1275 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1276 return (ret
== SCF_SUCCESS
? ret
: scf_set_error(SCF_ERROR_NOT_BOUND
));
1279 static scf_handle_t
*
1280 handle_get(scf_handle_t
*h
)
1282 (void) pthread_mutex_lock(&h
->rh_lock
);
1283 if (h
->rh_flags
& HANDLE_DEAD
) {
1284 (void) pthread_mutex_unlock(&h
->rh_lock
);
1285 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED
);
1288 (void) pthread_mutex_unlock(&h
->rh_lock
);
1293 * Called when an object is removed from the handle. On the last remove,
1294 * cleans up and frees the handle.
1297 handle_unrefed(scf_handle_t
*handle
)
1303 scf_instance_t
*inst
;
1304 scf_snapshot_t
*snap
;
1305 scf_snaplevel_t
*snaplvl
;
1306 scf_propertygroup_t
*pg
;
1307 scf_property_t
*prop
;
1309 assert(MUTEX_HELD(&handle
->rh_lock
));
1312 * Don't do anything if the handle has not yet been destroyed, there
1313 * are still external references, or we're already doing unrefed
1316 if (!(handle
->rh_flags
& HANDLE_DEAD
) ||
1317 handle
->rh_extrefs
> 0 ||
1318 handle
->rh_fd_users
> 0 ||
1319 (handle
->rh_flags
& HANDLE_UNREFED
)) {
1320 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1324 handle
->rh_flags
|= HANDLE_UNREFED
;
1327 * Now that we know that there are no external references, and the
1328 * HANDLE_DEAD flag keeps new ones from appearing, we can clean up
1329 * our subhandles and destroy the handle completely.
1331 assert(handle
->rh_intrefs
>= 0);
1332 handle
->rh_extrefs
= handle
->rh_intrefs
;
1333 handle
->rh_intrefs
= 0;
1334 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1336 handle_hold_subhandles(handle
, RH_HOLD_ALL
);
1338 iter
= handle
->rh_iter
;
1339 sc
= handle
->rh_scope
;
1340 svc
= handle
->rh_service
;
1341 inst
= handle
->rh_instance
;
1342 snap
= handle
->rh_snapshot
;
1343 snaplvl
= handle
->rh_snaplvl
;
1345 prop
= handle
->rh_property
;
1346 v
= handle
->rh_value
;
1348 handle
->rh_iter
= NULL
;
1349 handle
->rh_scope
= NULL
;
1350 handle
->rh_service
= NULL
;
1351 handle
->rh_instance
= NULL
;
1352 handle
->rh_snapshot
= NULL
;
1353 handle
->rh_snaplvl
= NULL
;
1354 handle
->rh_pg
= NULL
;
1355 handle
->rh_property
= NULL
;
1356 handle
->rh_value
= NULL
;
1359 scf_iter_destroy(iter
);
1361 scf_scope_destroy(sc
);
1363 scf_service_destroy(svc
);
1365 scf_instance_destroy(inst
);
1367 scf_snapshot_destroy(snap
);
1368 if (snaplvl
!= NULL
)
1369 scf_snaplevel_destroy(snaplvl
);
1373 scf_property_destroy(prop
);
1375 scf_value_destroy(v
);
1377 (void) pthread_mutex_lock(&handle
->rh_lock
);
1379 /* there should be no outstanding children at this point */
1380 assert(handle
->rh_extrefs
== 0);
1381 assert(handle
->rh_intrefs
== 0);
1382 assert(handle
->rh_values
== 0);
1383 assert(handle
->rh_entries
== 0);
1384 assert(uu_list_numnodes(handle
->rh_dataels
) == 0);
1385 assert(uu_list_numnodes(handle
->rh_iters
) == 0);
1387 uu_list_destroy(handle
->rh_dataels
);
1388 uu_list_destroy(handle
->rh_iters
);
1389 handle
->rh_dataels
= NULL
;
1390 handle
->rh_iters
= NULL
;
1391 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1393 (void) pthread_mutex_destroy(&handle
->rh_lock
);
1399 scf_handle_destroy(scf_handle_t
*handle
)
1404 (void) pthread_mutex_lock(&handle
->rh_lock
);
1405 if (handle
->rh_flags
& HANDLE_DEAD
) {
1407 * This is an error (you are not allowed to reference the
1408 * handle after it is destroyed), but we can't report it.
1410 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1413 handle
->rh_flags
|= HANDLE_DEAD
;
1414 (void) handle_unbind_unlocked(handle
);
1415 handle_unrefed(handle
);
1419 scf_myname(scf_handle_t
*h
, char *out
, size_t len
)
1423 if (!handle_has_server(h
))
1424 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
1426 cp
= getenv("SMF_FMRI");
1428 return (scf_set_error(SCF_ERROR_NOT_SET
));
1430 return (strlcpy(out
, cp
, len
));
1434 handle_alloc_entityid(scf_handle_t
*h
)
1438 assert(MUTEX_HELD(&h
->rh_lock
));
1440 if (uu_list_numnodes(h
->rh_dataels
) == UINT32_MAX
)
1441 return (0); /* no ids available */
1444 * The following loop assumes that there are not a huge number of
1445 * outstanding entities when we've wrapped. If that ends up not
1446 * being the case, the O(N^2) nature of this search will hurt a lot,
1447 * and the data structure should be switched to an AVL tree.
1449 nextid
= h
->rh_nextentity
+ 1;
1455 h
->rh_flags
|= HANDLE_WRAPPED_ENTITY
;
1457 if (!(h
->rh_flags
& HANDLE_WRAPPED_ENTITY
))
1460 cur
= uu_list_find(h
->rh_dataels
, NULL
, &nextid
, NULL
);
1462 break; /* not in use */
1464 if (nextid
== h
->rh_nextentity
)
1465 return (0); /* wrapped around; no ids available */
1469 h
->rh_nextentity
= nextid
;
1474 handle_alloc_iterid(scf_handle_t
*h
)
1478 assert(MUTEX_HELD(&h
->rh_lock
));
1480 if (uu_list_numnodes(h
->rh_iters
) == UINT32_MAX
)
1481 return (0); /* no ids available */
1483 /* see the comment in handle_alloc_entityid */
1484 nextid
= h
->rh_nextiter
+ 1;
1490 h
->rh_flags
|= HANDLE_WRAPPED_ITER
;
1492 if (!(h
->rh_flags
& HANDLE_WRAPPED_ITER
))
1493 break; /* not yet wrapped */
1495 cur
= uu_list_find(h
->rh_iters
, NULL
, &nextid
, NULL
);
1497 break; /* not in use */
1499 if (nextid
== h
->rh_nextiter
)
1500 return (0); /* wrapped around; no ids available */
1504 h
->rh_nextiter
= nextid
;
1509 handle_next_changeid(scf_handle_t
*handle
)
1513 assert(MUTEX_HELD(&handle
->rh_lock
));
1515 nextid
= ++handle
->rh_nextchangeid
;
1517 nextid
= ++handle
->rh_nextchangeid
;
1523 * _INVALID_ARGUMENT - h is NULL
1525 * _INTERNAL - server response too big
1526 * entity already set up with different type
1530 datael_init(scf_datael_t
*dp
, scf_handle_t
*h
, uint32_t type
)
1535 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1537 uu_list_node_init(dp
, &dp
->rd_node
, datael_pool
);
1543 (void) pthread_mutex_lock(&h
->rh_lock
);
1544 if (h
->rh_flags
& HANDLE_DEAD
) {
1546 * we're in undefined territory (the user cannot use a handle
1547 * directly after it has been destroyed), but we don't want
1548 * to allow any new references to happen, so we fail here.
1550 (void) pthread_mutex_unlock(&h
->rh_lock
);
1551 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
1553 dp
->rd_entity
= handle_alloc_entityid(h
);
1554 if (dp
->rd_entity
== 0) {
1555 (void) pthread_mutex_unlock(&h
->rh_lock
);
1556 uu_list_node_fini(dp
, &dp
->rd_node
, datael_pool
);
1557 return (scf_set_error(SCF_ERROR_NO_MEMORY
));
1560 ret
= datael_attach(dp
);
1562 (void) uu_list_insert_before(h
->rh_dataels
, NULL
, dp
);
1565 uu_list_node_fini(dp
, &dp
->rd_node
, datael_pool
);
1567 (void) pthread_mutex_unlock(&h
->rh_lock
);
1573 datael_destroy(scf_datael_t
*dp
)
1575 scf_handle_t
*h
= dp
->rd_handle
;
1577 struct rep_protocol_entity_teardown request
;
1578 rep_protocol_response_t response
;
1580 (void) pthread_mutex_lock(&h
->rh_lock
);
1581 uu_list_remove(h
->rh_dataels
, dp
);
1584 if (handle_is_bound(h
)) {
1585 request
.rpr_request
= REP_PROTOCOL_ENTITY_TEARDOWN
;
1586 request
.rpr_entityid
= dp
->rd_entity
;
1588 (void) make_door_call(h
, &request
, sizeof (request
),
1589 &response
, sizeof (response
));
1591 handle_unrefed(h
); /* drops h->rh_lock */
1593 dp
->rd_handle
= NULL
;
1596 static scf_handle_t
*
1597 datael_handle(const scf_datael_t
*dp
)
1599 return (handle_get(dp
->rd_handle
));
1603 * We delay ENTITY_RESETs until right before the entity is used. By doing
1604 * them lazily, we remove quite a few unnecessary calls.
1607 datael_do_reset_locked(scf_datael_t
*dp
)
1609 scf_handle_t
*h
= dp
->rd_handle
;
1611 struct rep_protocol_entity_reset request
;
1612 rep_protocol_response_t response
;
1614 assert(MUTEX_HELD(&h
->rh_lock
));
1616 request
.rpr_request
= REP_PROTOCOL_ENTITY_RESET
;
1617 request
.rpr_entityid
= dp
->rd_entity
;
1619 (void) make_door_call(h
, &request
, sizeof (request
),
1620 &response
, sizeof (response
));
1626 datael_reset_locked(scf_datael_t
*dp
)
1628 assert(MUTEX_HELD(&dp
->rd_handle
->rh_lock
));
1633 datael_reset(scf_datael_t
*dp
)
1635 scf_handle_t
*h
= dp
->rd_handle
;
1637 (void) pthread_mutex_lock(&h
->rh_lock
);
1639 (void) pthread_mutex_unlock(&h
->rh_lock
);
1643 datael_finish_reset(const scf_datael_t
*dp_arg
)
1645 scf_datael_t
*dp
= (scf_datael_t
*)dp_arg
;
1648 datael_do_reset_locked(dp
);
1652 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
1653 * big, bad entity id, request not applicable to entity, name too long for
1654 * buffer), _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED (snaplevel is not of an
1658 datael_get_name(const scf_datael_t
*dp
, char *buf
, size_t size
, uint32_t type
)
1660 scf_handle_t
*h
= dp
->rd_handle
;
1662 struct rep_protocol_entity_name request
;
1663 struct rep_protocol_name_response response
;
1666 (void) pthread_mutex_lock(&h
->rh_lock
);
1667 request
.rpr_request
= REP_PROTOCOL_ENTITY_NAME
;
1668 request
.rpr_entityid
= dp
->rd_entity
;
1669 request
.rpr_answertype
= type
;
1671 datael_finish_reset(dp
);
1672 r
= make_door_call(h
, &request
, sizeof (request
),
1673 &response
, sizeof (response
));
1674 (void) pthread_mutex_unlock(&h
->rh_lock
);
1677 DOOR_ERRORS_BLOCK(r
);
1679 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
1680 assert(response
.rpr_response
!= REP_PROTOCOL_FAIL_BAD_REQUEST
);
1681 if (response
.rpr_response
== REP_PROTOCOL_FAIL_NOT_FOUND
)
1682 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
));
1683 return (scf_set_error(proto_error(response
.rpr_response
)));
1685 return (strlcpy(buf
, response
.rpr_name
, size
));
1689 * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
1690 * (server response too big, bad element id), _EXISTS (elements have same id),
1691 * _NOT_SET, _DELETED, _CONSTRAINT_VIOLATED, _NOT_FOUND (scope has no parent),
1695 datael_get_parent(const scf_datael_t
*dp
, scf_datael_t
*pp
)
1697 scf_handle_t
*h
= dp
->rd_handle
;
1699 struct rep_protocol_entity_parent request
;
1700 struct rep_protocol_response response
;
1704 if (h
!= pp
->rd_handle
)
1705 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
1707 (void) pthread_mutex_lock(&h
->rh_lock
);
1708 request
.rpr_request
= REP_PROTOCOL_ENTITY_GET_PARENT
;
1709 request
.rpr_entityid
= dp
->rd_entity
;
1710 request
.rpr_outid
= pp
->rd_entity
;
1712 datael_finish_reset(dp
);
1713 datael_finish_reset(pp
);
1714 r
= make_door_call(h
, &request
, sizeof (request
),
1715 &response
, sizeof (response
));
1716 (void) pthread_mutex_unlock(&h
->rh_lock
);
1719 DOOR_ERRORS_BLOCK(r
);
1721 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
1722 if (response
.rpr_response
== REP_PROTOCOL_FAIL_TYPE_MISMATCH
)
1723 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
));
1724 return (scf_set_error(proto_error(response
.rpr_response
)));
1727 return (SCF_SUCCESS
);
1731 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1732 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1733 * too big, bad id, iter already exists, element cannot have children of type,
1734 * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1735 * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1736 * _BACKEND_ACCESS, _NOT_FOUND.
1739 datael_get_child_composed_locked(const scf_datael_t
*dp
, const char *name
,
1740 uint32_t type
, scf_datael_t
*out
, scf_iter_t
*iter
)
1742 struct rep_protocol_iter_start request
;
1743 struct rep_protocol_iter_read read_request
;
1744 struct rep_protocol_response response
;
1746 scf_handle_t
*h
= dp
->rd_handle
;
1749 if (h
!= out
->rd_handle
)
1750 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
1752 if (out
->rd_type
!= type
)
1753 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1755 assert(MUTEX_HELD(&h
->rh_lock
));
1756 assert(iter
!= NULL
);
1758 scf_iter_reset_locked(iter
);
1759 iter
->iter_type
= type
;
1761 request
.rpr_request
= REP_PROTOCOL_ITER_START
;
1762 request
.rpr_iterid
= iter
->iter_id
;
1763 request
.rpr_entity
= dp
->rd_entity
;
1764 request
.rpr_itertype
= type
;
1765 request
.rpr_flags
= RP_ITER_START_EXACT
| RP_ITER_START_COMPOSED
;
1767 if (name
== NULL
|| strlcpy(request
.rpr_pattern
, name
,
1768 sizeof (request
.rpr_pattern
)) >= sizeof (request
.rpr_pattern
)) {
1769 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1772 datael_finish_reset(dp
);
1773 datael_finish_reset(out
);
1776 * We hold the handle lock across both door calls, so that they
1779 r
= make_door_call(h
, &request
, sizeof (request
),
1780 &response
, sizeof (response
));
1783 DOOR_ERRORS_BLOCK(r
);
1785 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1786 return (scf_set_error(proto_error(response
.rpr_response
)));
1788 iter
->iter_sequence
++;
1790 read_request
.rpr_request
= REP_PROTOCOL_ITER_READ
;
1791 read_request
.rpr_iterid
= iter
->iter_id
;
1792 read_request
.rpr_sequence
= iter
->iter_sequence
;
1793 read_request
.rpr_entityid
= out
->rd_entity
;
1795 r
= make_door_call(h
, &read_request
, sizeof (read_request
),
1796 &response
, sizeof (response
));
1798 scf_iter_reset_locked(iter
);
1801 DOOR_ERRORS_BLOCK(r
);
1803 if (response
.rpr_response
== REP_PROTOCOL_DONE
) {
1804 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
1807 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
1808 if (response
.rpr_response
== REP_PROTOCOL_FAIL_NOT_SET
||
1809 response
.rpr_response
== REP_PROTOCOL_FAIL_BAD_REQUEST
)
1810 return (scf_set_error(SCF_ERROR_INTERNAL
));
1811 return (scf_set_error(proto_error(response
.rpr_response
)));
1818 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1819 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1820 * too big, bad id, element cannot have children of type, type is invalid),
1821 * _NOT_SET, _DELETED, _NO_RESOURCES, _BACKEND_ACCESS.
1824 datael_get_child_locked(const scf_datael_t
*dp
, const char *name
,
1825 uint32_t type
, scf_datael_t
*out
)
1827 struct rep_protocol_entity_get_child request
;
1828 struct rep_protocol_response response
;
1830 scf_handle_t
*h
= dp
->rd_handle
;
1833 if (h
!= out
->rd_handle
)
1834 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
1836 if (out
->rd_type
!= type
)
1837 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1839 assert(MUTEX_HELD(&h
->rh_lock
));
1841 request
.rpr_request
= REP_PROTOCOL_ENTITY_GET_CHILD
;
1842 request
.rpr_entityid
= dp
->rd_entity
;
1843 request
.rpr_childid
= out
->rd_entity
;
1845 if (name
== NULL
|| strlcpy(request
.rpr_name
, name
,
1846 sizeof (request
.rpr_name
)) >= sizeof (request
.rpr_name
)) {
1847 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1850 datael_finish_reset(dp
);
1851 datael_finish_reset(out
);
1853 r
= make_door_call(h
, &request
, sizeof (request
),
1854 &response
, sizeof (response
));
1857 DOOR_ERRORS_BLOCK(r
);
1859 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1860 return (scf_set_error(proto_error(response
.rpr_response
)));
1865 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1866 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1867 * too big, bad id, iter already exists, element cannot have children of type,
1868 * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1869 * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1870 * _BACKEND_ACCESS, _NOT_FOUND.
1873 datael_get_child(const scf_datael_t
*dp
, const char *name
, uint32_t type
,
1874 scf_datael_t
*out
, boolean_t composed
)
1876 scf_handle_t
*h
= dp
->rd_handle
;
1880 scf_iter_t
*iter
= NULL
;
1883 iter
= HANDLE_HOLD_ITER(h
);
1887 case REP_PROTOCOL_ENTITY_SERVICE
:
1888 out
= &HANDLE_HOLD_SERVICE(h
)->rd_d
;
1889 held
= RH_HOLD_SERVICE
;
1892 case REP_PROTOCOL_ENTITY_INSTANCE
:
1893 out
= &HANDLE_HOLD_INSTANCE(h
)->rd_d
;
1894 held
= RH_HOLD_INSTANCE
;
1897 case REP_PROTOCOL_ENTITY_SNAPSHOT
:
1898 out
= &HANDLE_HOLD_SNAPSHOT(h
)->rd_d
;
1899 held
= RH_HOLD_SNAPSHOT
;
1902 case REP_PROTOCOL_ENTITY_SNAPLEVEL
:
1903 out
= &HANDLE_HOLD_SNAPLVL(h
)->rd_d
;
1904 held
= RH_HOLD_SNAPLVL
;
1907 case REP_PROTOCOL_ENTITY_PROPERTYGRP
:
1908 out
= &HANDLE_HOLD_PG(h
)->rd_d
;
1912 case REP_PROTOCOL_ENTITY_PROPERTY
:
1913 out
= &HANDLE_HOLD_PROPERTY(h
)->rd_d
;
1914 held
= RH_HOLD_PROPERTY
;
1923 (void) pthread_mutex_lock(&h
->rh_lock
);
1925 ret
= datael_get_child_composed_locked(dp
, name
, type
, out
,
1928 ret
= datael_get_child_locked(dp
, name
, type
, out
);
1929 (void) pthread_mutex_unlock(&h
->rh_lock
);
1932 HANDLE_RELE_ITER(h
);
1935 handle_rele_subhandles(h
, held
);
1943 * _INVALID_ARGUMENT - name is too long
1946 * cannot create children for dp's type of node
1947 * _NOT_BOUND - handle is not bound
1948 * _CONNECTION_BROKEN - server is not reachable
1949 * _INTERNAL - server response too big
1950 * dp or cp has unknown id
1951 * type is _PROPERTYGRP
1953 * dp cannot have children of type type
1954 * database is corrupt
1955 * _EXISTS - dp & cp have the same id
1956 * _EXISTS - child already exists
1957 * _DELETED - dp has been deleted
1958 * _NOT_SET - dp is reset
1960 * _PERMISSION_DENIED
1965 datael_add_child(const scf_datael_t
*dp
, const char *name
, uint32_t type
,
1968 scf_handle_t
*h
= dp
->rd_handle
;
1970 struct rep_protocol_entity_create_child request
;
1971 struct rep_protocol_response response
;
1977 case REP_PROTOCOL_ENTITY_SCOPE
:
1978 cp
= &HANDLE_HOLD_SCOPE(h
)->rd_d
;
1979 held
= RH_HOLD_SCOPE
;
1981 case REP_PROTOCOL_ENTITY_SERVICE
:
1982 cp
= &HANDLE_HOLD_SERVICE(h
)->rd_d
;
1983 held
= RH_HOLD_SERVICE
;
1985 case REP_PROTOCOL_ENTITY_INSTANCE
:
1986 cp
= &HANDLE_HOLD_INSTANCE(h
)->rd_d
;
1987 held
= RH_HOLD_INSTANCE
;
1989 case REP_PROTOCOL_ENTITY_SNAPSHOT
:
1994 assert(h
== cp
->rd_handle
);
1996 } else if (h
!= cp
->rd_handle
) {
1997 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2000 if (strlcpy(request
.rpr_name
, name
, sizeof (request
.rpr_name
)) >=
2001 sizeof (request
.rpr_name
)) {
2002 r
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2006 (void) pthread_mutex_lock(&h
->rh_lock
);
2007 request
.rpr_request
= REP_PROTOCOL_ENTITY_CREATE_CHILD
;
2008 request
.rpr_entityid
= dp
->rd_entity
;
2009 request
.rpr_childtype
= type
;
2010 request
.rpr_childid
= cp
->rd_entity
;
2012 datael_finish_reset(dp
);
2013 request
.rpr_changeid
= handle_next_changeid(h
);
2014 r
= make_door_call(h
, &request
, sizeof (request
),
2015 &response
, sizeof (response
));
2016 (void) pthread_mutex_unlock(&h
->rh_lock
);
2019 handle_rele_subhandles(h
, held
);
2022 DOOR_ERRORS_BLOCK(r
);
2024 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2025 return (scf_set_error(proto_error(response
.rpr_response
)));
2027 return (SCF_SUCCESS
);
2031 handle_rele_subhandles(h
, held
);
2036 datael_add_pg(const scf_datael_t
*dp
, const char *name
, const char *type
,
2037 uint32_t flags
, scf_datael_t
*cp
)
2039 scf_handle_t
*h
= dp
->rd_handle
;
2041 struct rep_protocol_entity_create_pg request
;
2042 struct rep_protocol_response response
;
2045 int holding_els
= 0;
2049 cp
= &HANDLE_HOLD_PG(h
)->rd_d
;
2050 assert(h
== cp
->rd_handle
);
2052 } else if (h
!= cp
->rd_handle
) {
2053 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2056 request
.rpr_request
= REP_PROTOCOL_ENTITY_CREATE_PG
;
2058 if (name
== NULL
|| strlcpy(request
.rpr_name
, name
,
2059 sizeof (request
.rpr_name
)) > sizeof (request
.rpr_name
)) {
2060 r
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2064 if (type
== NULL
|| strlcpy(request
.rpr_type
, type
,
2065 sizeof (request
.rpr_type
)) > sizeof (request
.rpr_type
)) {
2066 r
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2070 (void) pthread_mutex_lock(&h
->rh_lock
);
2071 request
.rpr_entityid
= dp
->rd_entity
;
2072 request
.rpr_childid
= cp
->rd_entity
;
2073 request
.rpr_flags
= flags
;
2075 datael_finish_reset(dp
);
2076 datael_finish_reset(cp
);
2077 request
.rpr_changeid
= handle_next_changeid(h
);
2078 r
= make_door_call(h
, &request
, sizeof (request
),
2079 &response
, sizeof (response
));
2080 (void) pthread_mutex_unlock(&h
->rh_lock
);
2086 DOOR_ERRORS_BLOCK(r
);
2088 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2089 return (scf_set_error(proto_error(response
.rpr_response
)));
2091 return (SCF_SUCCESS
);
2100 datael_delete(const scf_datael_t
*dp
)
2102 scf_handle_t
*h
= dp
->rd_handle
;
2104 struct rep_protocol_entity_delete request
;
2105 struct rep_protocol_response response
;
2108 (void) pthread_mutex_lock(&h
->rh_lock
);
2109 request
.rpr_request
= REP_PROTOCOL_ENTITY_DELETE
;
2110 request
.rpr_entityid
= dp
->rd_entity
;
2112 datael_finish_reset(dp
);
2113 request
.rpr_changeid
= handle_next_changeid(h
);
2114 r
= make_door_call(h
, &request
, sizeof (request
),
2115 &response
, sizeof (response
));
2116 (void) pthread_mutex_unlock(&h
->rh_lock
);
2119 DOOR_ERRORS_BLOCK(r
);
2121 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2122 return (scf_set_error(proto_error(response
.rpr_response
)));
2124 return (SCF_SUCCESS
);
2129 * _INVALID_ARGUMENT - h is NULL
2131 * _HANDLE_DESTROYED - h has been destroyed
2132 * _INTERNAL - server response too big
2133 * iter already exists
2137 scf_iter_create(scf_handle_t
*h
)
2142 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2146 iter
= uu_zalloc(sizeof (*iter
));
2148 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2152 uu_list_node_init(iter
, &iter
->iter_node
, iter_pool
);
2153 iter
->iter_handle
= h
;
2154 iter
->iter_sequence
= 1;
2155 iter
->iter_type
= REP_PROTOCOL_ENTITY_NONE
;
2157 (void) pthread_mutex_lock(&h
->rh_lock
);
2158 iter
->iter_id
= handle_alloc_iterid(h
);
2159 if (iter
->iter_id
== 0) {
2160 (void) pthread_mutex_unlock(&h
->rh_lock
);
2161 uu_list_node_fini(iter
, &iter
->iter_node
, iter_pool
);
2162 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2166 if (iter_attach(iter
) == -1) {
2167 uu_list_node_fini(iter
, &iter
->iter_node
, iter_pool
);
2168 (void) pthread_mutex_unlock(&h
->rh_lock
);
2172 (void) uu_list_insert_before(h
->rh_iters
, NULL
, iter
);
2174 (void) pthread_mutex_unlock(&h
->rh_lock
);
2179 scf_iter_handle(const scf_iter_t
*iter
)
2181 return (handle_get(iter
->iter_handle
));
2185 scf_iter_reset_locked(scf_iter_t
*iter
)
2187 struct rep_protocol_iter_request request
;
2188 struct rep_protocol_response response
;
2190 request
.rpr_request
= REP_PROTOCOL_ITER_RESET
;
2191 request
.rpr_iterid
= iter
->iter_id
;
2193 assert(MUTEX_HELD(&iter
->iter_handle
->rh_lock
));
2195 (void) make_door_call(iter
->iter_handle
,
2196 &request
, sizeof (request
), &response
, sizeof (response
));
2198 iter
->iter_type
= REP_PROTOCOL_ENTITY_NONE
;
2199 iter
->iter_sequence
= 1;
2203 scf_iter_reset(scf_iter_t
*iter
)
2205 (void) pthread_mutex_lock(&iter
->iter_handle
->rh_lock
);
2206 scf_iter_reset_locked(iter
);
2207 (void) pthread_mutex_unlock(&iter
->iter_handle
->rh_lock
);
2211 scf_iter_destroy(scf_iter_t
*iter
)
2213 scf_handle_t
*handle
;
2215 struct rep_protocol_iter_request request
;
2216 struct rep_protocol_response response
;
2221 handle
= iter
->iter_handle
;
2223 (void) pthread_mutex_lock(&handle
->rh_lock
);
2224 request
.rpr_request
= REP_PROTOCOL_ITER_TEARDOWN
;
2225 request
.rpr_iterid
= iter
->iter_id
;
2227 (void) make_door_call(handle
, &request
, sizeof (request
),
2228 &response
, sizeof (response
));
2230 uu_list_remove(handle
->rh_iters
, iter
);
2231 --handle
->rh_extrefs
;
2232 handle_unrefed(handle
); /* drops h->rh_lock */
2233 iter
->iter_handle
= NULL
;
2235 uu_list_node_fini(iter
, &iter
->iter_node
, iter_pool
);
2240 handle_get_local_scope_locked(scf_handle_t
*handle
, scf_scope_t
*out
)
2242 struct rep_protocol_entity_get request
;
2243 struct rep_protocol_name_response response
;
2246 assert(MUTEX_HELD(&handle
->rh_lock
));
2248 if (handle
!= out
->rd_d
.rd_handle
)
2249 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2251 request
.rpr_request
= REP_PROTOCOL_ENTITY_GET
;
2252 request
.rpr_entityid
= out
->rd_d
.rd_entity
;
2253 request
.rpr_object
= RP_ENTITY_GET_MOST_LOCAL_SCOPE
;
2255 datael_finish_reset(&out
->rd_d
);
2256 r
= make_door_call(handle
, &request
, sizeof (request
),
2257 &response
, sizeof (response
));
2260 DOOR_ERRORS_BLOCK(r
);
2262 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2263 return (scf_set_error(proto_error(response
.rpr_response
)));
2265 return (SCF_SUCCESS
);
2269 scf_iter_handle_scopes(scf_iter_t
*iter
, const scf_handle_t
*handle
)
2271 scf_handle_t
*h
= iter
->iter_handle
;
2273 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2275 (void) pthread_mutex_lock(&h
->rh_lock
);
2276 scf_iter_reset_locked(iter
);
2278 if (!handle_is_bound(h
)) {
2279 (void) pthread_mutex_unlock(&h
->rh_lock
);
2280 return (scf_set_error(SCF_ERROR_NOT_BOUND
));
2283 if (!handle_has_server_locked(h
)) {
2284 (void) pthread_mutex_unlock(&h
->rh_lock
);
2285 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
2288 iter
->iter_type
= REP_PROTOCOL_ENTITY_SCOPE
;
2289 iter
->iter_sequence
= 1;
2290 (void) pthread_mutex_unlock(&h
->rh_lock
);
2295 scf_iter_next_scope(scf_iter_t
*iter
, scf_scope_t
*out
)
2298 scf_handle_t
*h
= iter
->iter_handle
;
2300 if (h
!= out
->rd_d
.rd_handle
)
2301 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2303 (void) pthread_mutex_lock(&h
->rh_lock
);
2304 if (iter
->iter_type
== REP_PROTOCOL_ENTITY_NONE
) {
2305 (void) pthread_mutex_unlock(&h
->rh_lock
);
2306 return (scf_set_error(SCF_ERROR_NOT_SET
));
2308 if (iter
->iter_type
!= REP_PROTOCOL_ENTITY_SCOPE
) {
2309 (void) pthread_mutex_unlock(&h
->rh_lock
);
2310 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
2312 if (iter
->iter_sequence
== 1) {
2313 if ((ret
= handle_get_local_scope_locked(h
, out
)) ==
2315 iter
->iter_sequence
++;
2319 datael_reset_locked(&out
->rd_d
);
2322 (void) pthread_mutex_unlock(&h
->rh_lock
);
2327 scf_handle_get_scope(scf_handle_t
*h
, const char *name
, scf_scope_t
*out
)
2331 if (h
!= out
->rd_d
.rd_handle
)
2332 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2334 (void) pthread_mutex_lock(&h
->rh_lock
);
2335 if (strcmp(name
, SCF_SCOPE_LOCAL
) == 0) {
2336 ret
= handle_get_local_scope_locked(h
, out
);
2338 datael_reset_locked(&out
->rd_d
);
2339 if (uu_check_name(name
, 0) == -1)
2340 ret
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2342 ret
= scf_set_error(SCF_ERROR_NOT_FOUND
);
2344 (void) pthread_mutex_unlock(&h
->rh_lock
);
2349 datael_setup_iter(scf_iter_t
*iter
, const scf_datael_t
*dp
, uint32_t res_type
,
2352 scf_handle_t
*h
= dp
->rd_handle
;
2354 struct rep_protocol_iter_start request
;
2355 struct rep_protocol_response response
;
2359 if (h
!= iter
->iter_handle
)
2360 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2362 (void) pthread_mutex_lock(&h
->rh_lock
);
2363 scf_iter_reset_locked(iter
);
2364 iter
->iter_type
= res_type
;
2366 request
.rpr_request
= REP_PROTOCOL_ITER_START
;
2367 request
.rpr_iterid
= iter
->iter_id
;
2368 request
.rpr_entity
= dp
->rd_entity
;
2369 request
.rpr_itertype
= res_type
;
2370 request
.rpr_flags
= RP_ITER_START_ALL
|
2371 (composed
? RP_ITER_START_COMPOSED
: 0);
2372 request
.rpr_pattern
[0] = 0;
2374 datael_finish_reset(dp
);
2375 r
= make_door_call(h
, &request
, sizeof (request
),
2376 &response
, sizeof (response
));
2379 (void) pthread_mutex_unlock(&h
->rh_lock
);
2380 DOOR_ERRORS_BLOCK(r
);
2382 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
2383 (void) pthread_mutex_unlock(&h
->rh_lock
);
2384 return (scf_set_error(proto_error(response
.rpr_response
)));
2386 iter
->iter_sequence
++;
2387 (void) pthread_mutex_unlock(&h
->rh_lock
);
2388 return (SCF_SUCCESS
);
2392 datael_setup_iter_pgtyped(scf_iter_t
*iter
, const scf_datael_t
*dp
,
2393 const char *pgtype
, boolean_t composed
)
2395 scf_handle_t
*h
= dp
->rd_handle
;
2397 struct rep_protocol_iter_start request
;
2398 struct rep_protocol_response response
;
2402 if (h
!= iter
->iter_handle
)
2403 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2405 if (pgtype
== NULL
|| strlcpy(request
.rpr_pattern
, pgtype
,
2406 sizeof (request
.rpr_pattern
)) >= sizeof (request
.rpr_pattern
)) {
2407 scf_iter_reset(iter
);
2408 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
2411 (void) pthread_mutex_lock(&h
->rh_lock
);
2412 request
.rpr_request
= REP_PROTOCOL_ITER_START
;
2413 request
.rpr_iterid
= iter
->iter_id
;
2414 request
.rpr_entity
= dp
->rd_entity
;
2415 request
.rpr_itertype
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
2416 request
.rpr_flags
= RP_ITER_START_PGTYPE
|
2417 (composed
? RP_ITER_START_COMPOSED
: 0);
2419 datael_finish_reset(dp
);
2420 scf_iter_reset_locked(iter
);
2421 iter
->iter_type
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
2423 r
= make_door_call(h
, &request
, sizeof (request
),
2424 &response
, sizeof (response
));
2427 (void) pthread_mutex_unlock(&h
->rh_lock
);
2429 DOOR_ERRORS_BLOCK(r
);
2431 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
2432 (void) pthread_mutex_unlock(&h
->rh_lock
);
2433 return (scf_set_error(proto_error(response
.rpr_response
)));
2435 iter
->iter_sequence
++;
2436 (void) pthread_mutex_unlock(&h
->rh_lock
);
2437 return (SCF_SUCCESS
);
2441 datael_iter_next(scf_iter_t
*iter
, scf_datael_t
*out
)
2443 scf_handle_t
*h
= iter
->iter_handle
;
2445 struct rep_protocol_iter_read request
;
2446 struct rep_protocol_response response
;
2449 if (h
!= out
->rd_handle
)
2450 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2452 (void) pthread_mutex_lock(&h
->rh_lock
);
2453 if (iter
->iter_type
== REP_PROTOCOL_ENTITY_NONE
||
2454 iter
->iter_sequence
== 1) {
2455 (void) pthread_mutex_unlock(&h
->rh_lock
);
2456 return (scf_set_error(SCF_ERROR_NOT_SET
));
2459 if (out
->rd_type
!= iter
->iter_type
) {
2460 (void) pthread_mutex_unlock(&h
->rh_lock
);
2461 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
2464 request
.rpr_request
= REP_PROTOCOL_ITER_READ
;
2465 request
.rpr_iterid
= iter
->iter_id
;
2466 request
.rpr_sequence
= iter
->iter_sequence
;
2467 request
.rpr_entityid
= out
->rd_entity
;
2469 datael_finish_reset(out
);
2470 r
= make_door_call(h
, &request
, sizeof (request
),
2471 &response
, sizeof (response
));
2474 (void) pthread_mutex_unlock(&h
->rh_lock
);
2475 DOOR_ERRORS_BLOCK(r
);
2478 if (response
.rpr_response
== REP_PROTOCOL_DONE
) {
2479 (void) pthread_mutex_unlock(&h
->rh_lock
);
2482 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
2483 (void) pthread_mutex_unlock(&h
->rh_lock
);
2484 return (scf_set_error(proto_error(response
.rpr_response
)));
2486 iter
->iter_sequence
++;
2487 (void) pthread_mutex_unlock(&h
->rh_lock
);
2493 scf_iter_scope_services(scf_iter_t
*iter
, const scf_scope_t
*s
)
2495 return (datael_setup_iter(iter
, &s
->rd_d
,
2496 REP_PROTOCOL_ENTITY_SERVICE
, 0));
2500 scf_iter_next_service(scf_iter_t
*iter
, scf_service_t
*out
)
2502 return (datael_iter_next(iter
, &out
->rd_d
));
2506 scf_iter_service_instances(scf_iter_t
*iter
, const scf_service_t
*svc
)
2508 return (datael_setup_iter(iter
, &svc
->rd_d
,
2509 REP_PROTOCOL_ENTITY_INSTANCE
, 0));
2513 scf_iter_next_instance(scf_iter_t
*iter
, scf_instance_t
*out
)
2515 return (datael_iter_next(iter
, &out
->rd_d
));
2519 scf_iter_service_pgs(scf_iter_t
*iter
, const scf_service_t
*svc
)
2521 return (datael_setup_iter(iter
, &svc
->rd_d
,
2522 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 0));
2526 scf_iter_service_pgs_typed(scf_iter_t
*iter
, const scf_service_t
*svc
,
2529 return (datael_setup_iter_pgtyped(iter
, &svc
->rd_d
, type
, 0));
2533 scf_iter_instance_snapshots(scf_iter_t
*iter
, const scf_instance_t
*inst
)
2535 return (datael_setup_iter(iter
, &inst
->rd_d
,
2536 REP_PROTOCOL_ENTITY_SNAPSHOT
, 0));
2540 scf_iter_next_snapshot(scf_iter_t
*iter
, scf_snapshot_t
*out
)
2542 return (datael_iter_next(iter
, &out
->rd_d
));
2546 scf_iter_instance_pgs(scf_iter_t
*iter
, const scf_instance_t
*inst
)
2548 return (datael_setup_iter(iter
, &inst
->rd_d
,
2549 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 0));
2553 scf_iter_instance_pgs_typed(scf_iter_t
*iter
, const scf_instance_t
*inst
,
2556 return (datael_setup_iter_pgtyped(iter
, &inst
->rd_d
, type
, 0));
2560 scf_iter_instance_pgs_composed(scf_iter_t
*iter
, const scf_instance_t
*inst
,
2561 const scf_snapshot_t
*snap
)
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(iter
, snap
? &snap
->rd_d
: &inst
->rd_d
,
2567 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 1));
2571 scf_iter_instance_pgs_typed_composed(scf_iter_t
*iter
,
2572 const scf_instance_t
*inst
, const scf_snapshot_t
*snap
, const char *type
)
2574 if (snap
!= NULL
&& inst
->rd_d
.rd_handle
!= snap
->rd_d
.rd_handle
)
2575 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2577 return (datael_setup_iter_pgtyped(iter
,
2578 snap
? &snap
->rd_d
: &inst
->rd_d
, type
, 1));
2582 scf_iter_snaplevel_pgs(scf_iter_t
*iter
, const scf_snaplevel_t
*inst
)
2584 return (datael_setup_iter(iter
, &inst
->rd_d
,
2585 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 0));
2589 scf_iter_snaplevel_pgs_typed(scf_iter_t
*iter
, const scf_snaplevel_t
*inst
,
2592 return (datael_setup_iter_pgtyped(iter
, &inst
->rd_d
, type
, 0));
2596 scf_iter_next_pg(scf_iter_t
*iter
, scf_propertygroup_t
*out
)
2598 return (datael_iter_next(iter
, &out
->rd_d
));
2602 scf_iter_pg_properties(scf_iter_t
*iter
, const scf_propertygroup_t
*pg
)
2604 return (datael_setup_iter(iter
, &pg
->rd_d
,
2605 REP_PROTOCOL_ENTITY_PROPERTY
, 0));
2609 scf_iter_next_property(scf_iter_t
*iter
, scf_property_t
*out
)
2611 return (datael_iter_next(iter
, &out
->rd_d
));
2616 * _INVALID_ARGUMENT - handle is NULL
2617 * _INTERNAL - server response too big
2618 * entity already set up with different type
2623 scf_scope_create(scf_handle_t
*handle
)
2627 ret
= uu_zalloc(sizeof (*ret
));
2629 if (datael_init(&ret
->rd_d
, handle
,
2630 REP_PROTOCOL_ENTITY_SCOPE
) == -1) {
2635 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2642 scf_scope_handle(const scf_scope_t
*val
)
2644 return (datael_handle(&val
->rd_d
));
2648 scf_scope_destroy(scf_scope_t
*val
)
2653 datael_destroy(&val
->rd_d
);
2658 scf_scope_get_name(const scf_scope_t
*rep
, char *out
, size_t len
)
2660 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2665 scf_scope_get_parent(const scf_scope_t
*child
, scf_scope_t
*parent
)
2669 /* fake up the side-effects */
2670 datael_reset(&parent
->rd_d
);
2671 if (scf_scope_get_name(child
, name
, sizeof (name
)) < 0)
2673 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
2677 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2678 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2681 scf_service_create(scf_handle_t
*handle
)
2684 ret
= uu_zalloc(sizeof (*ret
));
2686 if (datael_init(&ret
->rd_d
, handle
,
2687 REP_PROTOCOL_ENTITY_SERVICE
) == -1) {
2692 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2704 * _CONNECTION_BROKEN
2710 * _PERMISSION_DENIED
2715 scf_scope_add_service(const scf_scope_t
*scope
, const char *name
,
2718 return (datael_add_child(&scope
->rd_d
, name
,
2719 REP_PROTOCOL_ENTITY_SERVICE
, (svc
!= NULL
)? &svc
->rd_d
: NULL
));
2723 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2724 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2725 * _BACKEND_ACCESS, _NOT_FOUND.
2728 scf_scope_get_service(const scf_scope_t
*s
, const char *name
,
2731 return (datael_get_child(&s
->rd_d
, name
, REP_PROTOCOL_ENTITY_SERVICE
,
2732 svc
? &svc
->rd_d
: NULL
, 0));
2736 scf_service_handle(const scf_service_t
*val
)
2738 return (datael_handle(&val
->rd_d
));
2742 scf_service_delete(scf_service_t
*svc
)
2744 return (datael_delete(&svc
->rd_d
));
2748 scf_instance_delete(scf_instance_t
*inst
)
2750 return (datael_delete(&inst
->rd_d
));
2754 scf_pg_delete(scf_propertygroup_t
*pg
)
2756 return (datael_delete(&pg
->rd_d
));
2760 _scf_snapshot_delete(scf_snapshot_t
*snap
)
2762 return (datael_delete(&snap
->rd_d
));
2770 * _CONNECTION_BROKEN
2776 * _PERMISSION_DENIED
2781 scf_service_add_instance(const scf_service_t
*svc
, const char *name
,
2782 scf_instance_t
*instance
)
2784 return (datael_add_child(&svc
->rd_d
, name
,
2785 REP_PROTOCOL_ENTITY_INSTANCE
,
2786 (instance
!= NULL
)? &instance
->rd_d
: NULL
));
2791 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2792 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2793 * _BACKEND_ACCESS, _NOT_FOUND.
2796 scf_service_get_instance(const scf_service_t
*svc
, const char *name
,
2797 scf_instance_t
*inst
)
2799 return (datael_get_child(&svc
->rd_d
, name
, REP_PROTOCOL_ENTITY_INSTANCE
,
2800 inst
? &inst
->rd_d
: NULL
, 0));
2804 scf_service_add_pg(const scf_service_t
*svc
, const char *name
,
2805 const char *type
, uint32_t flags
, scf_propertygroup_t
*pg
)
2807 return (datael_add_pg(&svc
->rd_d
, name
, type
, flags
,
2808 (pg
!= NULL
)?&pg
->rd_d
: NULL
));
2812 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2813 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2814 * _BACKEND_ACCESS, _NOT_FOUND.
2817 scf_service_get_pg(const scf_service_t
*svc
, const char *name
,
2818 scf_propertygroup_t
*pg
)
2820 return (datael_get_child(&svc
->rd_d
, name
,
2821 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 0));
2825 scf_instance_add_pg(const scf_instance_t
*inst
, const char *name
,
2826 const char *type
, uint32_t flags
, scf_propertygroup_t
*pg
)
2828 return (datael_add_pg(&inst
->rd_d
, name
, type
, flags
,
2829 (pg
!= NULL
)?&pg
->rd_d
: NULL
));
2833 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2834 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2835 * _BACKEND_ACCESS, _NOT_FOUND.
2838 scf_instance_get_snapshot(const scf_instance_t
*inst
, const char *name
,
2841 return (datael_get_child(&inst
->rd_d
, name
,
2842 REP_PROTOCOL_ENTITY_SNAPSHOT
, pg
? &pg
->rd_d
: NULL
, 0));
2846 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2847 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2848 * _BACKEND_ACCESS, _NOT_FOUND.
2851 scf_instance_get_pg(const scf_instance_t
*inst
, const char *name
,
2852 scf_propertygroup_t
*pg
)
2854 return (datael_get_child(&inst
->rd_d
, name
,
2855 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 0));
2859 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2860 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2861 * _BACKEND_ACCESS, _NOT_FOUND.
2864 scf_instance_get_pg_composed(const scf_instance_t
*inst
,
2865 const scf_snapshot_t
*snap
, const char *name
, scf_propertygroup_t
*pg
)
2867 if (snap
!= NULL
&& inst
->rd_d
.rd_handle
!= snap
->rd_d
.rd_handle
)
2868 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2870 return (datael_get_child(snap
? &snap
->rd_d
: &inst
->rd_d
, name
,
2871 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 1));
2875 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2876 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2877 * _BACKEND_ACCESS, _NOT_FOUND.
2880 scf_pg_get_property(const scf_propertygroup_t
*pg
, const char *name
,
2881 scf_property_t
*prop
)
2883 return (datael_get_child(&pg
->rd_d
, name
, REP_PROTOCOL_ENTITY_PROPERTY
,
2884 prop
? &prop
->rd_d
: NULL
, 0));
2888 scf_service_destroy(scf_service_t
*val
)
2893 datael_destroy(&val
->rd_d
);
2898 scf_service_get_name(const scf_service_t
*rep
, char *out
, size_t len
)
2900 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2904 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2905 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2908 scf_instance_create(scf_handle_t
*handle
)
2910 scf_instance_t
*ret
;
2912 ret
= uu_zalloc(sizeof (*ret
));
2914 if (datael_init(&ret
->rd_d
, handle
,
2915 REP_PROTOCOL_ENTITY_INSTANCE
) == -1) {
2920 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2927 scf_instance_handle(const scf_instance_t
*val
)
2929 return (datael_handle(&val
->rd_d
));
2933 scf_instance_destroy(scf_instance_t
*val
)
2938 datael_destroy(&val
->rd_d
);
2943 scf_instance_get_name(const scf_instance_t
*rep
, char *out
, size_t len
)
2945 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2949 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2950 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2953 scf_snapshot_create(scf_handle_t
*handle
)
2955 scf_snapshot_t
*ret
;
2957 ret
= uu_zalloc(sizeof (*ret
));
2959 if (datael_init(&ret
->rd_d
, handle
,
2960 REP_PROTOCOL_ENTITY_SNAPSHOT
) == -1) {
2965 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2972 scf_snapshot_handle(const scf_snapshot_t
*val
)
2974 return (datael_handle(&val
->rd_d
));
2978 scf_snapshot_destroy(scf_snapshot_t
*val
)
2983 datael_destroy(&val
->rd_d
);
2988 scf_snapshot_get_name(const scf_snapshot_t
*rep
, char *out
, size_t len
)
2990 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2994 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2995 * (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY.
2998 scf_snaplevel_create(scf_handle_t
*handle
)
3000 scf_snaplevel_t
*ret
;
3002 ret
= uu_zalloc(sizeof (*ret
));
3004 if (datael_init(&ret
->rd_d
, handle
,
3005 REP_PROTOCOL_ENTITY_SNAPLEVEL
) == -1) {
3010 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3017 scf_snaplevel_handle(const scf_snaplevel_t
*val
)
3019 return (datael_handle(&val
->rd_d
));
3023 scf_snaplevel_destroy(scf_snaplevel_t
*val
)
3028 datael_destroy(&val
->rd_d
);
3033 scf_snaplevel_get_scope_name(const scf_snaplevel_t
*rep
, char *out
, size_t len
)
3035 return (datael_get_name(&rep
->rd_d
, out
, len
,
3036 RP_ENTITY_NAME_SNAPLEVEL_SCOPE
));
3040 scf_snaplevel_get_service_name(const scf_snaplevel_t
*rep
, char *out
,
3043 return (datael_get_name(&rep
->rd_d
, out
, len
,
3044 RP_ENTITY_NAME_SNAPLEVEL_SERVICE
));
3048 scf_snaplevel_get_instance_name(const scf_snaplevel_t
*rep
, char *out
,
3051 return (datael_get_name(&rep
->rd_d
, out
, len
,
3052 RP_ENTITY_NAME_SNAPLEVEL_INSTANCE
));
3056 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3057 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3058 * _BACKEND_ACCESS, _NOT_FOUND.
3061 scf_snaplevel_get_pg(const scf_snaplevel_t
*snap
, const char *name
,
3062 scf_propertygroup_t
*pg
)
3064 return (datael_get_child(&snap
->rd_d
, name
,
3065 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 0));
3069 snaplevel_next(const scf_datael_t
*src
, scf_snaplevel_t
*dst_arg
)
3071 scf_handle_t
*h
= src
->rd_handle
;
3072 scf_snaplevel_t
*dst
= dst_arg
;
3073 struct rep_protocol_entity_pair request
;
3074 struct rep_protocol_response response
;
3078 if (h
!= dst
->rd_d
.rd_handle
)
3079 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3081 if (src
== &dst
->rd_d
) {
3083 dst
= HANDLE_HOLD_SNAPLVL(h
);
3085 (void) pthread_mutex_lock(&h
->rh_lock
);
3086 request
.rpr_request
= REP_PROTOCOL_NEXT_SNAPLEVEL
;
3087 request
.rpr_entity_src
= src
->rd_entity
;
3088 request
.rpr_entity_dst
= dst
->rd_d
.rd_entity
;
3090 datael_finish_reset(src
);
3091 datael_finish_reset(&dst
->rd_d
);
3092 r
= make_door_call(h
, &request
, sizeof (request
),
3093 &response
, sizeof (response
));
3095 * if we succeeded, we need to swap dst and dst_arg's identity. We
3096 * take advantage of the fact that the only in-library knowledge is
3099 if (dups
&& r
>= 0 &&
3100 (response
.rpr_response
== REP_PROTOCOL_SUCCESS
||
3101 response
.rpr_response
== REP_PROTOCOL_DONE
)) {
3102 int entity
= dst
->rd_d
.rd_entity
;
3104 dst
->rd_d
.rd_entity
= dst_arg
->rd_d
.rd_entity
;
3105 dst_arg
->rd_d
.rd_entity
= entity
;
3107 (void) pthread_mutex_unlock(&h
->rh_lock
);
3110 HANDLE_RELE_SNAPLVL(h
);
3113 DOOR_ERRORS_BLOCK(r
);
3115 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
3116 response
.rpr_response
!= REP_PROTOCOL_DONE
) {
3117 return (scf_set_error(proto_error(response
.rpr_response
)));
3120 return (response
.rpr_response
== REP_PROTOCOL_SUCCESS
) ?
3121 SCF_SUCCESS
: SCF_COMPLETE
;
3124 int scf_snapshot_get_base_snaplevel(const scf_snapshot_t
*base
,
3125 scf_snaplevel_t
*out
)
3127 return (snaplevel_next(&base
->rd_d
, out
));
3130 int scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t
*base
,
3131 scf_snaplevel_t
*out
)
3133 return (snaplevel_next(&base
->rd_d
, out
));
3137 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3138 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3140 scf_propertygroup_t
*
3141 scf_pg_create(scf_handle_t
*handle
)
3143 scf_propertygroup_t
*ret
;
3144 ret
= uu_zalloc(sizeof (*ret
));
3146 if (datael_init(&ret
->rd_d
, handle
,
3147 REP_PROTOCOL_ENTITY_PROPERTYGRP
) == -1) {
3152 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3159 scf_pg_handle(const scf_propertygroup_t
*val
)
3161 return (datael_handle(&val
->rd_d
));
3165 scf_pg_destroy(scf_propertygroup_t
*val
)
3170 datael_destroy(&val
->rd_d
);
3175 scf_pg_get_name(const scf_propertygroup_t
*pg
, char *out
, size_t len
)
3177 return (datael_get_name(&pg
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
3181 scf_pg_get_type(const scf_propertygroup_t
*pg
, char *out
, size_t len
)
3183 return (datael_get_name(&pg
->rd_d
, out
, len
, RP_ENTITY_NAME_PGTYPE
));
3187 scf_pg_get_flags(const scf_propertygroup_t
*pg
, uint32_t *out
)
3189 char buf
[REP_PROTOCOL_NAME_LEN
];
3192 res
= datael_get_name(&pg
->rd_d
, buf
, sizeof (buf
),
3193 RP_ENTITY_NAME_PGFLAGS
);
3198 if (uu_strtouint(buf
, out
, sizeof (*out
), 0, 0, UINT32_MAX
) == -1)
3199 return (scf_set_error(SCF_ERROR_INTERNAL
));
3205 datael_update(scf_datael_t
*dp
)
3207 scf_handle_t
*h
= dp
->rd_handle
;
3209 struct rep_protocol_entity_update request
;
3210 struct rep_protocol_response response
;
3214 (void) pthread_mutex_lock(&h
->rh_lock
);
3215 request
.rpr_request
= REP_PROTOCOL_ENTITY_UPDATE
;
3216 request
.rpr_entityid
= dp
->rd_entity
;
3218 datael_finish_reset(dp
);
3219 request
.rpr_changeid
= handle_next_changeid(h
);
3221 r
= make_door_call(h
, &request
, sizeof (request
),
3222 &response
, sizeof (response
));
3223 (void) pthread_mutex_unlock(&h
->rh_lock
);
3226 DOOR_ERRORS_BLOCK(r
);
3229 * This should never happen but if it does something has
3230 * gone terribly wrong and we should abort.
3232 if (response
.rpr_response
== REP_PROTOCOL_FAIL_BAD_REQUEST
)
3235 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
3236 response
.rpr_response
!= REP_PROTOCOL_DONE
) {
3237 return (scf_set_error(proto_error(response
.rpr_response
)));
3240 return (response
.rpr_response
== REP_PROTOCOL_SUCCESS
) ?
3241 SCF_SUCCESS
: SCF_COMPLETE
;
3245 scf_pg_update(scf_propertygroup_t
*pg
)
3247 return (datael_update(&pg
->rd_d
));
3251 scf_snapshot_update(scf_snapshot_t
*snap
)
3253 return (datael_update(&snap
->rd_d
));
3257 _scf_pg_wait(scf_propertygroup_t
*pg
, int timeout
)
3259 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
3261 struct rep_protocol_propertygrp_request request
;
3262 struct rep_protocol_response response
;
3264 struct pollfd pollfd
;
3268 (void) pthread_mutex_lock(&h
->rh_lock
);
3269 request
.rpr_request
= REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT
;
3270 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
3272 datael_finish_reset(&pg
->rd_d
);
3273 if (!handle_is_bound(h
)) {
3274 (void) pthread_mutex_unlock(&h
->rh_lock
);
3275 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
3277 r
= make_door_call_retfd(h
->rh_doorfd
, &request
, sizeof (request
),
3278 &response
, sizeof (response
), &pollfd
.fd
);
3279 (void) pthread_mutex_unlock(&h
->rh_lock
);
3282 DOOR_ERRORS_BLOCK(r
);
3284 assert((response
.rpr_response
== REP_PROTOCOL_SUCCESS
) ==
3287 if (response
.rpr_response
== REP_PROTOCOL_FAIL_NOT_LATEST
)
3288 return (SCF_SUCCESS
);
3290 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3291 return (scf_set_error(proto_error(response
.rpr_response
)));
3296 r
= poll(&pollfd
, 1, timeout
* MILLISEC
);
3298 (void) close(pollfd
.fd
);
3299 return (pollfd
.revents
? SCF_SUCCESS
: SCF_COMPLETE
);
3303 scf_notify_add_pattern(scf_handle_t
*h
, int type
, const char *name
)
3305 struct rep_protocol_notify_request request
;
3306 struct rep_protocol_response response
;
3309 (void) pthread_mutex_lock(&h
->rh_lock
);
3310 request
.rpr_request
= REP_PROTOCOL_CLIENT_ADD_NOTIFY
;
3311 request
.rpr_type
= type
;
3312 (void) strlcpy(request
.rpr_pattern
, name
, sizeof (request
.rpr_pattern
));
3314 r
= make_door_call(h
, &request
, sizeof (request
),
3315 &response
, sizeof (response
));
3316 (void) pthread_mutex_unlock(&h
->rh_lock
);
3319 DOOR_ERRORS_BLOCK(r
);
3321 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3322 return (scf_set_error(proto_error(response
.rpr_response
)));
3324 return (SCF_SUCCESS
);
3328 _scf_notify_add_pgname(scf_handle_t
*h
, const char *name
)
3330 return (scf_notify_add_pattern(h
, REP_PROTOCOL_NOTIFY_PGNAME
, name
));
3334 _scf_notify_add_pgtype(scf_handle_t
*h
, const char *type
)
3336 return (scf_notify_add_pattern(h
, REP_PROTOCOL_NOTIFY_PGTYPE
, type
));
3340 _scf_notify_wait(scf_propertygroup_t
*pg
, char *out
, size_t sz
)
3342 struct rep_protocol_wait_request request
;
3343 struct rep_protocol_fmri_response response
;
3345 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
3350 (void) pthread_mutex_lock(&h
->rh_lock
);
3351 datael_finish_reset(&pg
->rd_d
);
3352 if (!handle_is_bound(h
)) {
3353 (void) pthread_mutex_unlock(&h
->rh_lock
);
3354 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
3358 assert(h
->rh_fd_users
> 0);
3360 request
.rpr_request
= REP_PROTOCOL_CLIENT_WAIT
;
3361 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
3362 (void) pthread_mutex_unlock(&h
->rh_lock
);
3364 r
= make_door_call_retfd(fd
, &request
, sizeof (request
),
3365 &response
, sizeof (response
), &dummy
);
3367 (void) pthread_mutex_lock(&h
->rh_lock
);
3368 assert(h
->rh_fd_users
> 0);
3369 if (--h
->rh_fd_users
== 0) {
3370 (void) pthread_cond_broadcast(&h
->rh_cv
);
3372 * check for a delayed close, now that there are no other
3375 if (h
->rh_doorfd_old
!= -1) {
3376 assert(h
->rh_doorfd
== -1);
3377 assert(fd
== h
->rh_doorfd_old
);
3378 (void) close(h
->rh_doorfd_old
);
3379 h
->rh_doorfd_old
= -1;
3382 handle_unrefed(h
); /* drops h->rh_lock */
3385 DOOR_ERRORS_BLOCK(r
);
3387 if (response
.rpr_response
== REP_PROTOCOL_DONE
)
3388 return (scf_set_error(SCF_ERROR_NOT_SET
));
3390 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3391 return (scf_set_error(proto_error(response
.rpr_response
)));
3393 /* the following will be non-zero for delete notifications */
3394 return (strlcpy(out
, response
.rpr_fmri
, sz
));
3398 _scf_snapshot_take(scf_instance_t
*inst
, const char *name
,
3399 scf_snapshot_t
*snap
, int flags
)
3401 scf_handle_t
*h
= inst
->rd_d
.rd_handle
;
3403 struct rep_protocol_snapshot_take request
;
3404 struct rep_protocol_response response
;
3408 if (h
!= snap
->rd_d
.rd_handle
)
3409 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3411 if (strlcpy(request
.rpr_name
, (name
!= NULL
)? name
: "",
3412 sizeof (request
.rpr_name
)) >= sizeof (request
.rpr_name
))
3413 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3415 (void) pthread_mutex_lock(&h
->rh_lock
);
3416 request
.rpr_request
= REP_PROTOCOL_SNAPSHOT_TAKE
;
3417 request
.rpr_entityid_src
= inst
->rd_d
.rd_entity
;
3418 request
.rpr_entityid_dest
= snap
->rd_d
.rd_entity
;
3419 request
.rpr_flags
= flags
;
3421 datael_finish_reset(&inst
->rd_d
);
3422 datael_finish_reset(&snap
->rd_d
);
3424 r
= make_door_call(h
, &request
, sizeof (request
),
3425 &response
, sizeof (response
));
3426 (void) pthread_mutex_unlock(&h
->rh_lock
);
3429 DOOR_ERRORS_BLOCK(r
);
3431 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3432 return (scf_set_error(proto_error(response
.rpr_response
)));
3434 return (SCF_SUCCESS
);
3438 _scf_snapshot_take_new_named(scf_instance_t
*inst
,
3439 const char *svcname
, const char *instname
, const char *snapname
,
3440 scf_snapshot_t
*snap
)
3442 scf_handle_t
*h
= inst
->rd_d
.rd_handle
;
3444 struct rep_protocol_snapshot_take_named request
;
3445 struct rep_protocol_response response
;
3449 if (h
!= snap
->rd_d
.rd_handle
)
3450 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3452 if (strlcpy(request
.rpr_svcname
, svcname
,
3453 sizeof (request
.rpr_svcname
)) >= sizeof (request
.rpr_svcname
))
3454 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3456 if (strlcpy(request
.rpr_instname
, instname
,
3457 sizeof (request
.rpr_instname
)) >= sizeof (request
.rpr_instname
))
3458 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3460 if (strlcpy(request
.rpr_name
, snapname
,
3461 sizeof (request
.rpr_name
)) >= sizeof (request
.rpr_name
))
3462 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3464 (void) pthread_mutex_lock(&h
->rh_lock
);
3465 request
.rpr_request
= REP_PROTOCOL_SNAPSHOT_TAKE_NAMED
;
3466 request
.rpr_entityid_src
= inst
->rd_d
.rd_entity
;
3467 request
.rpr_entityid_dest
= snap
->rd_d
.rd_entity
;
3469 datael_finish_reset(&inst
->rd_d
);
3470 datael_finish_reset(&snap
->rd_d
);
3472 r
= make_door_call(h
, &request
, sizeof (request
),
3473 &response
, sizeof (response
));
3474 (void) pthread_mutex_unlock(&h
->rh_lock
);
3477 DOOR_ERRORS_BLOCK(r
);
3479 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
3480 assert(response
.rpr_response
!=
3481 REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
3482 return (scf_set_error(proto_error(response
.rpr_response
)));
3485 return (SCF_SUCCESS
);
3489 _scf_snapshot_take_new(scf_instance_t
*inst
, const char *name
,
3490 scf_snapshot_t
*snap
)
3492 return (_scf_snapshot_take(inst
, name
, snap
, REP_SNAPSHOT_NEW
));
3496 _scf_snapshot_take_attach(scf_instance_t
*inst
, scf_snapshot_t
*snap
)
3498 return (_scf_snapshot_take(inst
, NULL
, snap
, REP_SNAPSHOT_ATTACH
));
3502 _scf_snapshot_attach(scf_snapshot_t
*src
, scf_snapshot_t
*dest
)
3504 scf_handle_t
*h
= dest
->rd_d
.rd_handle
;
3506 struct rep_protocol_snapshot_attach request
;
3507 struct rep_protocol_response response
;
3511 if (h
!= src
->rd_d
.rd_handle
)
3512 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3514 (void) pthread_mutex_lock(&h
->rh_lock
);
3515 request
.rpr_request
= REP_PROTOCOL_SNAPSHOT_ATTACH
;
3516 request
.rpr_entityid_src
= src
->rd_d
.rd_entity
;
3517 request
.rpr_entityid_dest
= dest
->rd_d
.rd_entity
;
3519 datael_finish_reset(&src
->rd_d
);
3520 datael_finish_reset(&dest
->rd_d
);
3522 r
= make_door_call(h
, &request
, sizeof (request
),
3523 &response
, sizeof (response
));
3524 (void) pthread_mutex_unlock(&h
->rh_lock
);
3527 DOOR_ERRORS_BLOCK(r
);
3529 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3530 return (scf_set_error(proto_error(response
.rpr_response
)));
3532 return (SCF_SUCCESS
);
3536 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3537 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3540 scf_property_create(scf_handle_t
*handle
)
3542 scf_property_t
*ret
;
3543 ret
= uu_zalloc(sizeof (*ret
));
3545 if (datael_init(&ret
->rd_d
, handle
,
3546 REP_PROTOCOL_ENTITY_PROPERTY
) == -1) {
3551 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3558 scf_property_handle(const scf_property_t
*val
)
3560 return (datael_handle(&val
->rd_d
));
3564 scf_property_destroy(scf_property_t
*val
)
3569 datael_destroy(&val
->rd_d
);
3574 property_type_locked(const scf_property_t
*prop
,
3575 rep_protocol_value_type_t
*out
)
3577 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
3579 struct rep_protocol_property_request request
;
3580 struct rep_protocol_integer_response response
;
3584 assert(MUTEX_HELD(&h
->rh_lock
));
3586 request
.rpr_request
= REP_PROTOCOL_PROPERTY_GET_TYPE
;
3587 request
.rpr_entityid
= prop
->rd_d
.rd_entity
;
3589 datael_finish_reset(&prop
->rd_d
);
3590 r
= make_door_call(h
, &request
, sizeof (request
),
3591 &response
, sizeof (response
));
3594 DOOR_ERRORS_BLOCK(r
);
3596 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
||
3597 r
< sizeof (response
)) {
3598 return (scf_set_error(proto_error(response
.rpr_response
)));
3600 *out
= response
.rpr_value
;
3601 return (SCF_SUCCESS
);
3605 scf_property_type(const scf_property_t
*prop
, scf_type_t
*out
)
3607 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
3608 rep_protocol_value_type_t out_raw
;
3611 (void) pthread_mutex_lock(&h
->rh_lock
);
3612 ret
= property_type_locked(prop
, &out_raw
);
3613 (void) pthread_mutex_unlock(&h
->rh_lock
);
3615 if (ret
== SCF_SUCCESS
)
3616 *out
= scf_protocol_type_to_type(out_raw
);
3622 scf_property_is_type(const scf_property_t
*prop
, scf_type_t base_arg
)
3624 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
3625 rep_protocol_value_type_t base
= scf_type_to_protocol_type(base_arg
);
3626 rep_protocol_value_type_t type
;
3629 if (base
== REP_PROTOCOL_TYPE_INVALID
)
3630 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3632 (void) pthread_mutex_lock(&h
->rh_lock
);
3633 ret
= property_type_locked(prop
, &type
);
3634 (void) pthread_mutex_unlock(&h
->rh_lock
);
3636 if (ret
== SCF_SUCCESS
) {
3637 if (!scf_is_compatible_protocol_type(base
, type
))
3638 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
3644 scf_is_compatible_type(scf_type_t base_arg
, scf_type_t type_arg
)
3646 rep_protocol_value_type_t base
= scf_type_to_protocol_type(base_arg
);
3647 rep_protocol_value_type_t type
= scf_type_to_protocol_type(type_arg
);
3649 if (base
== REP_PROTOCOL_TYPE_INVALID
||
3650 type
== REP_PROTOCOL_TYPE_INVALID
)
3651 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3653 if (!scf_is_compatible_protocol_type(base
, type
))
3654 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
3656 return (SCF_SUCCESS
);
3660 scf_property_get_name(const scf_property_t
*prop
, char *out
, size_t len
)
3662 return (datael_get_name(&prop
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
3666 * transaction functions
3670 * Fails with _NO_MEMORY, _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED,
3671 * _INTERNAL (bad server response or id in use), or _NO_RESOURCES.
3674 scf_transaction_create(scf_handle_t
*handle
)
3676 scf_transaction_t
*ret
;
3678 ret
= uu_zalloc(sizeof (scf_transaction_t
));
3680 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3683 if (datael_init(&ret
->tran_pg
.rd_d
, handle
,
3684 REP_PROTOCOL_ENTITY_PROPERTYGRP
) == -1) {
3686 return (NULL
); /* error already set */
3688 ret
->tran_state
= TRAN_STATE_NEW
;
3689 ret
->tran_props
= uu_list_create(tran_entry_pool
, ret
, UU_LIST_SORTED
);
3690 if (ret
->tran_props
== NULL
) {
3691 datael_destroy(&ret
->tran_pg
.rd_d
);
3693 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3701 scf_transaction_handle(const scf_transaction_t
*val
)
3703 return (handle_get(val
->tran_pg
.rd_d
.rd_handle
));
3707 scf_transaction_start(scf_transaction_t
*tran
, scf_propertygroup_t
*pg
)
3709 scf_handle_t
*h
= tran
->tran_pg
.rd_d
.rd_handle
;
3711 struct rep_protocol_transaction_start request
;
3712 struct rep_protocol_response response
;
3715 if (h
!= pg
->rd_d
.rd_handle
)
3716 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3718 (void) pthread_mutex_lock(&h
->rh_lock
);
3719 if (tran
->tran_state
!= TRAN_STATE_NEW
) {
3720 (void) pthread_mutex_unlock(&h
->rh_lock
);
3721 return (scf_set_error(SCF_ERROR_IN_USE
));
3723 request
.rpr_request
= REP_PROTOCOL_PROPERTYGRP_TX_START
;
3724 request
.rpr_entityid_tx
= tran
->tran_pg
.rd_d
.rd_entity
;
3725 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
3727 datael_finish_reset(&tran
->tran_pg
.rd_d
);
3728 datael_finish_reset(&pg
->rd_d
);
3730 r
= make_door_call(h
, &request
, sizeof (request
),
3731 &response
, sizeof (response
));
3734 (void) pthread_mutex_unlock(&h
->rh_lock
);
3735 DOOR_ERRORS_BLOCK(r
);
3738 /* r < sizeof (response) cannot happen because sizeof (response) == 4 */
3740 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
||
3741 r
< sizeof (response
)) {
3742 (void) pthread_mutex_unlock(&h
->rh_lock
);
3743 return (scf_set_error(proto_error(response
.rpr_response
)));
3746 tran
->tran_state
= TRAN_STATE_SETUP
;
3747 tran
->tran_invalid
= 0;
3748 (void) pthread_mutex_unlock(&h
->rh_lock
);
3749 return (SCF_SUCCESS
);
3753 entry_invalidate(scf_transaction_entry_t
*cur
, int and_destroy
,
3754 int and_reset_value
)
3756 scf_value_t
*v
, *next
;
3757 scf_transaction_t
*tx
;
3758 scf_handle_t
*h
= cur
->entry_handle
;
3760 assert(MUTEX_HELD(&h
->rh_lock
));
3762 if ((tx
= cur
->entry_tx
) != NULL
) {
3763 tx
->tran_invalid
= 1;
3764 uu_list_remove(tx
->tran_props
, cur
);
3765 cur
->entry_tx
= NULL
;
3768 cur
->entry_property
= NULL
;
3769 cur
->entry_state
= ENTRY_STATE_INVALID
;
3770 cur
->entry_action
= REP_PROTOCOL_TX_ENTRY_INVALID
;
3771 cur
->entry_type
= REP_PROTOCOL_TYPE_INVALID
;
3773 for (v
= cur
->entry_head
; v
!= NULL
; v
= next
) {
3774 next
= v
->value_next
;
3776 v
->value_next
= NULL
;
3777 if (and_destroy
|| and_reset_value
)
3778 scf_value_reset_locked(v
, and_destroy
);
3780 cur
->entry_head
= NULL
;
3781 cur
->entry_tail
= NULL
;
3785 entry_destroy_locked(scf_transaction_entry_t
*entry
)
3787 scf_handle_t
*h
= entry
->entry_handle
;
3789 assert(MUTEX_HELD(&h
->rh_lock
));
3791 entry_invalidate(entry
, 0, 0);
3793 entry
->entry_handle
= NULL
;
3794 assert(h
->rh_entries
> 0);
3797 uu_list_node_fini(entry
, &entry
->entry_link
, tran_entry_pool
);
3802 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3803 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3804 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3807 transaction_add(scf_transaction_t
*tran
, scf_transaction_entry_t
*entry
,
3808 enum rep_protocol_transaction_action action
,
3809 const char *prop
, rep_protocol_value_type_t type
)
3811 scf_handle_t
*h
= tran
->tran_pg
.rd_d
.rd_handle
;
3812 scf_transaction_entry_t
*old
;
3813 scf_property_t
*prop_p
;
3814 rep_protocol_value_type_t oldtype
;
3815 scf_error_t error
= SCF_ERROR_NONE
;
3817 uu_list_index_t idx
;
3819 if (h
!= entry
->entry_handle
)
3820 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3822 if (action
== REP_PROTOCOL_TX_ENTRY_DELETE
)
3823 assert(type
== REP_PROTOCOL_TYPE_INVALID
);
3824 else if (type
== REP_PROTOCOL_TYPE_INVALID
)
3825 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3827 prop_p
= HANDLE_HOLD_PROPERTY(h
);
3829 (void) pthread_mutex_lock(&h
->rh_lock
);
3830 if (tran
->tran_state
!= TRAN_STATE_SETUP
) {
3831 error
= SCF_ERROR_NOT_SET
;
3834 if (tran
->tran_invalid
) {
3835 error
= SCF_ERROR_NOT_SET
;
3839 if (entry
->entry_state
!= ENTRY_STATE_INVALID
)
3840 entry_invalidate(entry
, 0, 0);
3842 old
= uu_list_find(tran
->tran_props
, &prop
, NULL
, &idx
);
3844 error
= SCF_ERROR_IN_USE
;
3848 ret
= datael_get_child_locked(&tran
->tran_pg
.rd_d
, prop
,
3849 REP_PROTOCOL_ENTITY_PROPERTY
, &prop_p
->rd_d
);
3850 if (ret
== -1 && (error
= scf_error()) != SCF_ERROR_NOT_FOUND
) {
3855 case REP_PROTOCOL_TX_ENTRY_DELETE
:
3857 error
= SCF_ERROR_NOT_FOUND
;
3861 case REP_PROTOCOL_TX_ENTRY_NEW
:
3863 error
= SCF_ERROR_EXISTS
;
3868 case REP_PROTOCOL_TX_ENTRY_CLEAR
:
3869 case REP_PROTOCOL_TX_ENTRY_REPLACE
:
3871 error
= SCF_ERROR_NOT_FOUND
;
3874 if (action
== REP_PROTOCOL_TX_ENTRY_CLEAR
) {
3875 if (property_type_locked(prop_p
, &oldtype
) == -1) {
3876 error
= scf_error();
3879 if (oldtype
!= type
) {
3880 error
= SCF_ERROR_TYPE_MISMATCH
;
3890 (void) strlcpy(entry
->entry_namebuf
, prop
,
3891 sizeof (entry
->entry_namebuf
));
3892 entry
->entry_property
= entry
->entry_namebuf
;
3893 entry
->entry_action
= action
;
3894 entry
->entry_type
= type
;
3896 entry
->entry_state
= ENTRY_STATE_IN_TX_ACTION
;
3897 entry
->entry_tx
= tran
;
3898 uu_list_insert(tran
->tran_props
, entry
, idx
);
3900 (void) pthread_mutex_unlock(&h
->rh_lock
);
3902 HANDLE_RELE_PROPERTY(h
);
3904 return (SCF_SUCCESS
);
3907 (void) pthread_mutex_unlock(&h
->rh_lock
);
3909 HANDLE_RELE_PROPERTY(h
);
3911 return (scf_set_error(error
));
3915 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3916 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3917 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3920 scf_transaction_property_new(scf_transaction_t
*tx
,
3921 scf_transaction_entry_t
*entry
, const char *prop
, scf_type_t type
)
3923 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_NEW
,
3924 prop
, scf_type_to_protocol_type(type
)));
3928 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3929 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3930 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3933 scf_transaction_property_change(scf_transaction_t
*tx
,
3934 scf_transaction_entry_t
*entry
, const char *prop
, scf_type_t type
)
3936 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_CLEAR
,
3937 prop
, scf_type_to_protocol_type(type
)));
3941 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3942 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3943 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3946 scf_transaction_property_change_type(scf_transaction_t
*tx
,
3947 scf_transaction_entry_t
*entry
, const char *prop
, scf_type_t type
)
3949 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_REPLACE
,
3950 prop
, scf_type_to_protocol_type(type
)));
3954 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3955 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3956 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3959 scf_transaction_property_delete(scf_transaction_t
*tx
,
3960 scf_transaction_entry_t
*entry
, const char *prop
)
3962 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_DELETE
,
3963 prop
, REP_PROTOCOL_TYPE_INVALID
));
3966 #define BAD_SIZE (-1UL)
3969 commit_value(caddr_t data
, scf_value_t
*val
, rep_protocol_value_type_t t
)
3973 assert(val
->value_type
== t
);
3975 if (t
== REP_PROTOCOL_TYPE_OPAQUE
) {
3976 len
= scf_opaque_encode(data
, val
->value_value
,
3980 len
= strlcpy(data
, val
->value_value
,
3981 REP_PROTOCOL_VALUE_LEN
);
3983 len
= strlen(val
->value_value
);
3984 if (len
>= REP_PROTOCOL_VALUE_LEN
)
3987 return (len
+ 1); /* count the '\0' */
3991 commit_process(scf_transaction_entry_t
*cur
,
3992 struct rep_protocol_transaction_cmd
*out
)
3997 caddr_t data
= (caddr_t
)out
->rptc_data
;
4001 len
= strlcpy(data
, cur
->entry_property
, REP_PROTOCOL_NAME_LEN
);
4003 out
->rptc_action
= cur
->entry_action
;
4004 out
->rptc_type
= cur
->entry_type
;
4005 out
->rptc_name_len
= len
+ 1;
4007 len
= strlen(cur
->entry_property
);
4010 if (len
>= REP_PROTOCOL_NAME_LEN
)
4013 len
= TX_SIZE(len
+ 1);
4016 val_data
= data
+ len
;
4018 for (child
= cur
->entry_head
; child
!= NULL
;
4019 child
= child
->value_next
) {
4020 assert(cur
->entry_action
!= REP_PROTOCOL_TX_ENTRY_DELETE
);
4022 len
= commit_value(val_data
+ sizeof (uint32_t), child
,
4024 /* LINTED alignment */
4025 *(uint32_t *)val_data
= len
;
4027 len
= commit_value(NULL
, child
, cur
->entry_type
);
4029 if (len
== BAD_SIZE
)
4032 len
+= sizeof (uint32_t);
4039 assert(val_data
- data
== sz
);
4042 out
->rptc_size
= REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz
);
4044 return (REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz
));
4048 scf_transaction_commit(scf_transaction_t
*tran
)
4050 scf_handle_t
*h
= tran
->tran_pg
.rd_d
.rd_handle
;
4052 struct rep_protocol_transaction_commit
*request
;
4053 struct rep_protocol_response response
;
4055 scf_transaction_entry_t
*cur
;
4057 size_t request_size
;
4061 (void) pthread_mutex_lock(&h
->rh_lock
);
4062 if (tran
->tran_state
!= TRAN_STATE_SETUP
||
4063 tran
->tran_invalid
) {
4064 (void) pthread_mutex_unlock(&h
->rh_lock
);
4065 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4069 for (cur
= uu_list_first(tran
->tran_props
); cur
!= NULL
;
4070 cur
= uu_list_next(tran
->tran_props
, cur
)) {
4071 size
= commit_process(cur
, NULL
);
4072 if (size
== BAD_SIZE
) {
4073 (void) pthread_mutex_unlock(&h
->rh_lock
);
4074 return (scf_set_error(SCF_ERROR_INTERNAL
));
4076 assert(TX_SIZE(size
) == size
);
4080 request_size
= REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(total
);
4081 request
= alloca(request_size
);
4082 (void) memset(request
, '\0', request_size
);
4083 request
->rpr_request
= REP_PROTOCOL_PROPERTYGRP_TX_COMMIT
;
4084 request
->rpr_entityid
= tran
->tran_pg
.rd_d
.rd_entity
;
4085 request
->rpr_size
= request_size
;
4086 cmd
= (uintptr_t)request
->rpr_cmd
;
4088 datael_finish_reset(&tran
->tran_pg
.rd_d
);
4091 for (cur
= uu_list_first(tran
->tran_props
); cur
!= NULL
;
4092 cur
= uu_list_next(tran
->tran_props
, cur
)) {
4093 size
= commit_process(cur
, (void *)cmd
);
4094 if (size
== BAD_SIZE
) {
4095 (void) pthread_mutex_unlock(&h
->rh_lock
);
4096 return (scf_set_error(SCF_ERROR_INTERNAL
));
4101 assert(new_total
== total
);
4103 r
= make_door_call(h
, request
, request_size
,
4104 &response
, sizeof (response
));
4107 (void) pthread_mutex_unlock(&h
->rh_lock
);
4108 DOOR_ERRORS_BLOCK(r
);
4111 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
4112 response
.rpr_response
!= REP_PROTOCOL_FAIL_NOT_LATEST
) {
4113 (void) pthread_mutex_unlock(&h
->rh_lock
);
4114 return (scf_set_error(proto_error(response
.rpr_response
)));
4117 tran
->tran_state
= TRAN_STATE_COMMITTED
;
4118 (void) pthread_mutex_unlock(&h
->rh_lock
);
4119 return (response
.rpr_response
== REP_PROTOCOL_SUCCESS
);
4123 transaction_reset(scf_transaction_t
*tran
)
4125 assert(MUTEX_HELD(&tran
->tran_pg
.rd_d
.rd_handle
->rh_lock
));
4127 tran
->tran_state
= TRAN_STATE_NEW
;
4128 datael_reset_locked(&tran
->tran_pg
.rd_d
);
4132 scf_transaction_reset_impl(scf_transaction_t
*tran
, int and_destroy
,
4133 int and_reset_value
)
4135 scf_transaction_entry_t
*cur
;
4138 (void) pthread_mutex_lock(&tran
->tran_pg
.rd_d
.rd_handle
->rh_lock
);
4140 while ((cur
= uu_list_teardown(tran
->tran_props
, &cookie
)) != NULL
) {
4141 cur
->entry_tx
= NULL
;
4143 assert(cur
->entry_state
== ENTRY_STATE_IN_TX_ACTION
);
4144 cur
->entry_state
= ENTRY_STATE_INVALID
;
4146 entry_invalidate(cur
, and_destroy
, and_reset_value
);
4148 entry_destroy_locked(cur
);
4150 transaction_reset(tran
);
4151 handle_unrefed(tran
->tran_pg
.rd_d
.rd_handle
);
4155 scf_transaction_reset(scf_transaction_t
*tran
)
4157 scf_transaction_reset_impl(tran
, 0, 0);
4161 scf_transaction_reset_all(scf_transaction_t
*tran
)
4163 scf_transaction_reset_impl(tran
, 0, 1);
4167 scf_transaction_destroy(scf_transaction_t
*val
)
4172 scf_transaction_reset(val
);
4174 datael_destroy(&val
->tran_pg
.rd_d
);
4176 uu_list_destroy(val
->tran_props
);
4181 scf_transaction_destroy_children(scf_transaction_t
*tran
)
4186 scf_transaction_reset_impl(tran
, 1, 0);
4189 scf_transaction_entry_t
*
4190 scf_entry_create(scf_handle_t
*h
)
4192 scf_transaction_entry_t
*ret
;
4195 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
4199 ret
= uu_zalloc(sizeof (scf_transaction_entry_t
));
4201 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
4204 ret
->entry_action
= REP_PROTOCOL_TX_ENTRY_INVALID
;
4205 ret
->entry_handle
= h
;
4207 (void) pthread_mutex_lock(&h
->rh_lock
);
4208 if (h
->rh_flags
& HANDLE_DEAD
) {
4209 (void) pthread_mutex_unlock(&h
->rh_lock
);
4211 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED
);
4216 (void) pthread_mutex_unlock(&h
->rh_lock
);
4218 uu_list_node_init(ret
, &ret
->entry_link
, tran_entry_pool
);
4224 scf_entry_handle(const scf_transaction_entry_t
*val
)
4226 return (handle_get(val
->entry_handle
));
4230 scf_entry_reset(scf_transaction_entry_t
*entry
)
4232 scf_handle_t
*h
= entry
->entry_handle
;
4234 (void) pthread_mutex_lock(&h
->rh_lock
);
4235 entry_invalidate(entry
, 0, 0);
4236 (void) pthread_mutex_unlock(&h
->rh_lock
);
4240 scf_entry_destroy_children(scf_transaction_entry_t
*entry
)
4242 scf_handle_t
*h
= entry
->entry_handle
;
4244 (void) pthread_mutex_lock(&h
->rh_lock
);
4245 entry_invalidate(entry
, 1, 0);
4246 handle_unrefed(h
); /* drops h->rh_lock */
4250 scf_entry_destroy(scf_transaction_entry_t
*entry
)
4257 h
= entry
->entry_handle
;
4259 (void) pthread_mutex_lock(&h
->rh_lock
);
4260 entry_destroy_locked(entry
);
4261 handle_unrefed(h
); /* drops h->rh_lock */
4267 * _NOT_SET - has not been added to a transaction
4268 * _INTERNAL - entry is corrupt
4269 * _INVALID_ARGUMENT - entry's transaction is not started or corrupt
4270 * entry is set to delete a property
4271 * v is reset or corrupt
4272 * _TYPE_MISMATCH - entry & v's types aren't compatible
4273 * _IN_USE - v has been added to another entry
4276 scf_entry_add_value(scf_transaction_entry_t
*entry
, scf_value_t
*v
)
4278 scf_handle_t
*h
= entry
->entry_handle
;
4280 if (h
!= v
->value_handle
)
4281 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
4283 (void) pthread_mutex_lock(&h
->rh_lock
);
4285 if (entry
->entry_state
== ENTRY_STATE_INVALID
) {
4286 (void) pthread_mutex_unlock(&h
->rh_lock
);
4287 return (scf_set_error(SCF_ERROR_NOT_SET
));
4290 if (entry
->entry_state
!= ENTRY_STATE_IN_TX_ACTION
) {
4291 (void) pthread_mutex_unlock(&h
->rh_lock
);
4292 return (scf_set_error(SCF_ERROR_INTERNAL
));
4295 if (entry
->entry_tx
->tran_state
!= TRAN_STATE_SETUP
) {
4296 (void) pthread_mutex_unlock(&h
->rh_lock
);
4297 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4300 if (entry
->entry_action
== REP_PROTOCOL_TX_ENTRY_DELETE
) {
4301 (void) pthread_mutex_unlock(&h
->rh_lock
);
4302 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4305 if (v
->value_type
== REP_PROTOCOL_TYPE_INVALID
) {
4306 (void) pthread_mutex_unlock(&h
->rh_lock
);
4307 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4310 if (!scf_is_compatible_protocol_type(entry
->entry_type
,
4312 (void) pthread_mutex_unlock(&h
->rh_lock
);
4313 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
4316 if (v
->value_tx
!= NULL
) {
4317 (void) pthread_mutex_unlock(&h
->rh_lock
);
4318 return (scf_set_error(SCF_ERROR_IN_USE
));
4321 v
->value_tx
= entry
;
4322 v
->value_next
= NULL
;
4323 if (entry
->entry_head
== NULL
) {
4324 entry
->entry_head
= v
;
4325 entry
->entry_tail
= v
;
4327 entry
->entry_tail
->value_next
= v
;
4328 entry
->entry_tail
= v
;
4331 (void) pthread_mutex_unlock(&h
->rh_lock
);
4333 return (SCF_SUCCESS
);
4340 scf_value_create(scf_handle_t
*h
)
4345 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
4349 ret
= uu_zalloc(sizeof (*ret
));
4351 ret
->value_type
= REP_PROTOCOL_TYPE_INVALID
;
4352 ret
->value_handle
= h
;
4353 (void) pthread_mutex_lock(&h
->rh_lock
);
4354 if (h
->rh_flags
& HANDLE_DEAD
) {
4355 (void) pthread_mutex_unlock(&h
->rh_lock
);
4357 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED
);
4362 (void) pthread_mutex_unlock(&h
->rh_lock
);
4364 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
4371 scf_value_reset_locked(scf_value_t
*val
, int and_destroy
)
4374 scf_transaction_entry_t
*te
;
4376 scf_handle_t
*h
= val
->value_handle
;
4377 assert(MUTEX_HELD(&h
->rh_lock
));
4378 if (val
->value_tx
!= NULL
) {
4380 te
->entry_tx
->tran_invalid
= 1;
4382 val
->value_tx
= NULL
;
4384 for (curp
= &te
->entry_head
; *curp
!= NULL
;
4385 curp
= &(*curp
)->value_next
) {
4387 *curp
= val
->value_next
;
4392 assert(curp
== NULL
);
4394 val
->value_type
= REP_PROTOCOL_TYPE_INVALID
;
4397 val
->value_handle
= NULL
;
4398 assert(h
->rh_values
> 0);
4406 scf_value_reset(scf_value_t
*val
)
4408 scf_handle_t
*h
= val
->value_handle
;
4410 (void) pthread_mutex_lock(&h
->rh_lock
);
4411 scf_value_reset_locked(val
, 0);
4412 (void) pthread_mutex_unlock(&h
->rh_lock
);
4416 scf_value_handle(const scf_value_t
*val
)
4418 return (handle_get(val
->value_handle
));
4422 scf_value_destroy(scf_value_t
*val
)
4429 h
= val
->value_handle
;
4431 (void) pthread_mutex_lock(&h
->rh_lock
);
4432 scf_value_reset_locked(val
, 1);
4433 handle_unrefed(h
); /* drops h->rh_lock */
4437 scf_value_base_type(const scf_value_t
*val
)
4439 rep_protocol_value_type_t t
, cur
;
4440 scf_handle_t
*h
= val
->value_handle
;
4442 (void) pthread_mutex_lock(&h
->rh_lock
);
4443 t
= val
->value_type
;
4444 (void) pthread_mutex_unlock(&h
->rh_lock
);
4447 cur
= scf_proto_underlying_type(t
);
4453 return (scf_protocol_type_to_type(t
));
4457 scf_value_type(const scf_value_t
*val
)
4459 rep_protocol_value_type_t t
;
4460 scf_handle_t
*h
= val
->value_handle
;
4462 (void) pthread_mutex_lock(&h
->rh_lock
);
4463 t
= val
->value_type
;
4464 (void) pthread_mutex_unlock(&h
->rh_lock
);
4466 return (scf_protocol_type_to_type(t
));
4470 scf_value_is_type(const scf_value_t
*val
, scf_type_t base_arg
)
4472 rep_protocol_value_type_t t
;
4473 rep_protocol_value_type_t base
= scf_type_to_protocol_type(base_arg
);
4474 scf_handle_t
*h
= val
->value_handle
;
4476 (void) pthread_mutex_lock(&h
->rh_lock
);
4477 t
= val
->value_type
;
4478 (void) pthread_mutex_unlock(&h
->rh_lock
);
4480 if (t
== REP_PROTOCOL_TYPE_INVALID
)
4481 return (scf_set_error(SCF_ERROR_NOT_SET
));
4482 if (base
== REP_PROTOCOL_TYPE_INVALID
)
4483 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4484 if (!scf_is_compatible_protocol_type(base
, t
))
4485 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
4487 return (SCF_SUCCESS
);
4492 * _NOT_SET - val is reset
4493 * _TYPE_MISMATCH - val's type is not compatible with t
4496 scf_value_check_type(const scf_value_t
*val
, rep_protocol_value_type_t t
)
4498 if (val
->value_type
== REP_PROTOCOL_TYPE_INVALID
) {
4499 (void) scf_set_error(SCF_ERROR_NOT_SET
);
4502 if (!scf_is_compatible_protocol_type(t
, val
->value_type
)) {
4503 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH
);
4511 * _NOT_SET - val is reset
4512 * _TYPE_MISMATCH - val is not _TYPE_BOOLEAN
4515 scf_value_get_boolean(const scf_value_t
*val
, uint8_t *out
)
4518 scf_handle_t
*h
= val
->value_handle
;
4521 (void) pthread_mutex_lock(&h
->rh_lock
);
4522 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_BOOLEAN
)) {
4523 (void) pthread_mutex_unlock(&h
->rh_lock
);
4527 c
= val
->value_value
[0];
4528 assert((c
== '0' || c
== '1') && val
->value_value
[1] == 0);
4531 (void) pthread_mutex_unlock(&h
->rh_lock
);
4534 return (SCF_SUCCESS
);
4538 scf_value_get_count(const scf_value_t
*val
, uint64_t *out
)
4540 scf_handle_t
*h
= val
->value_handle
;
4543 (void) pthread_mutex_lock(&h
->rh_lock
);
4544 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_COUNT
)) {
4545 (void) pthread_mutex_unlock(&h
->rh_lock
);
4549 o
= strtoull(val
->value_value
, NULL
, 10);
4550 (void) pthread_mutex_unlock(&h
->rh_lock
);
4553 return (SCF_SUCCESS
);
4557 scf_value_get_integer(const scf_value_t
*val
, int64_t *out
)
4559 scf_handle_t
*h
= val
->value_handle
;
4562 (void) pthread_mutex_lock(&h
->rh_lock
);
4563 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_INTEGER
)) {
4564 (void) pthread_mutex_unlock(&h
->rh_lock
);
4568 o
= strtoll(val
->value_value
, NULL
, 10);
4569 (void) pthread_mutex_unlock(&h
->rh_lock
);
4572 return (SCF_SUCCESS
);
4576 scf_value_get_time(const scf_value_t
*val
, int64_t *sec_out
, int32_t *nsec_out
)
4578 scf_handle_t
*h
= val
->value_handle
;
4583 (void) pthread_mutex_lock(&h
->rh_lock
);
4584 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_TIME
)) {
4585 (void) pthread_mutex_unlock(&h
->rh_lock
);
4589 os
= strtoll(val
->value_value
, &p
, 10);
4591 ons
= strtoul(p
+ 1, NULL
, 10);
4594 (void) pthread_mutex_unlock(&h
->rh_lock
);
4595 if (sec_out
!= NULL
)
4597 if (nsec_out
!= NULL
)
4600 return (SCF_SUCCESS
);
4605 * _NOT_SET - val is reset
4606 * _TYPE_MISMATCH - val's type is not compatible with _TYPE_STRING.
4609 scf_value_get_astring(const scf_value_t
*val
, char *out
, size_t len
)
4612 scf_handle_t
*h
= val
->value_handle
;
4614 (void) pthread_mutex_lock(&h
->rh_lock
);
4615 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_STRING
)) {
4616 (void) pthread_mutex_unlock(&h
->rh_lock
);
4617 return ((ssize_t
)-1);
4619 ret
= (ssize_t
)strlcpy(out
, val
->value_value
, len
);
4620 (void) pthread_mutex_unlock(&h
->rh_lock
);
4625 scf_value_get_ustring(const scf_value_t
*val
, char *out
, size_t len
)
4628 scf_handle_t
*h
= val
->value_handle
;
4630 (void) pthread_mutex_lock(&h
->rh_lock
);
4631 if (!scf_value_check_type(val
, REP_PROTOCOL_SUBTYPE_USTRING
)) {
4632 (void) pthread_mutex_unlock(&h
->rh_lock
);
4633 return ((ssize_t
)-1);
4635 ret
= (ssize_t
)strlcpy(out
, val
->value_value
, len
);
4636 (void) pthread_mutex_unlock(&h
->rh_lock
);
4641 scf_value_get_opaque(const scf_value_t
*v
, void *out
, size_t len
)
4644 scf_handle_t
*h
= v
->value_handle
;
4646 (void) pthread_mutex_lock(&h
->rh_lock
);
4647 if (!scf_value_check_type(v
, REP_PROTOCOL_TYPE_OPAQUE
)) {
4648 (void) pthread_mutex_unlock(&h
->rh_lock
);
4649 return ((ssize_t
)-1);
4651 if (len
> v
->value_size
)
4652 len
= v
->value_size
;
4655 (void) memcpy(out
, v
->value_value
, len
);
4656 (void) pthread_mutex_unlock(&h
->rh_lock
);
4661 scf_value_set_boolean(scf_value_t
*v
, uint8_t new)
4663 scf_handle_t
*h
= v
->value_handle
;
4665 (void) pthread_mutex_lock(&h
->rh_lock
);
4666 scf_value_reset_locked(v
, 0);
4667 v
->value_type
= REP_PROTOCOL_TYPE_BOOLEAN
;
4668 (void) sprintf(v
->value_value
, "%d", (new != 0));
4669 (void) pthread_mutex_unlock(&h
->rh_lock
);
4673 scf_value_set_count(scf_value_t
*v
, uint64_t new)
4675 scf_handle_t
*h
= v
->value_handle
;
4677 (void) pthread_mutex_lock(&h
->rh_lock
);
4678 scf_value_reset_locked(v
, 0);
4679 v
->value_type
= REP_PROTOCOL_TYPE_COUNT
;
4680 (void) sprintf(v
->value_value
, "%llu", (unsigned long long)new);
4681 (void) pthread_mutex_unlock(&h
->rh_lock
);
4685 scf_value_set_integer(scf_value_t
*v
, int64_t new)
4687 scf_handle_t
*h
= v
->value_handle
;
4689 (void) pthread_mutex_lock(&h
->rh_lock
);
4690 scf_value_reset_locked(v
, 0);
4691 v
->value_type
= REP_PROTOCOL_TYPE_INTEGER
;
4692 (void) sprintf(v
->value_value
, "%lld", (long long)new);
4693 (void) pthread_mutex_unlock(&h
->rh_lock
);
4697 scf_value_set_time(scf_value_t
*v
, int64_t new_sec
, int32_t new_nsec
)
4699 scf_handle_t
*h
= v
->value_handle
;
4701 (void) pthread_mutex_lock(&h
->rh_lock
);
4702 scf_value_reset_locked(v
, 0);
4703 if (new_nsec
< 0 || new_nsec
>= NANOSEC
) {
4704 (void) pthread_mutex_unlock(&h
->rh_lock
);
4705 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4707 v
->value_type
= REP_PROTOCOL_TYPE_TIME
;
4709 (void) sprintf(v
->value_value
, "%lld", (long long)new_sec
);
4711 (void) sprintf(v
->value_value
, "%lld.%09u", (long long)new_sec
,
4712 (unsigned)new_nsec
);
4713 (void) pthread_mutex_unlock(&h
->rh_lock
);
4718 scf_value_set_astring(scf_value_t
*v
, const char *new)
4720 scf_handle_t
*h
= v
->value_handle
;
4722 (void) pthread_mutex_lock(&h
->rh_lock
);
4723 scf_value_reset_locked(v
, 0);
4724 if (!scf_validate_encoded_value(REP_PROTOCOL_TYPE_STRING
, new)) {
4725 (void) pthread_mutex_unlock(&h
->rh_lock
);
4726 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4728 if (strlcpy(v
->value_value
, new, sizeof (v
->value_value
)) >=
4729 sizeof (v
->value_value
)) {
4730 (void) pthread_mutex_unlock(&h
->rh_lock
);
4731 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4733 v
->value_type
= REP_PROTOCOL_TYPE_STRING
;
4734 (void) pthread_mutex_unlock(&h
->rh_lock
);
4739 scf_value_set_ustring(scf_value_t
*v
, const char *new)
4741 scf_handle_t
*h
= v
->value_handle
;
4743 (void) pthread_mutex_lock(&h
->rh_lock
);
4744 scf_value_reset_locked(v
, 0);
4745 if (!scf_validate_encoded_value(REP_PROTOCOL_SUBTYPE_USTRING
, new)) {
4746 (void) pthread_mutex_unlock(&h
->rh_lock
);
4747 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4749 if (strlcpy(v
->value_value
, new, sizeof (v
->value_value
)) >=
4750 sizeof (v
->value_value
)) {
4751 (void) pthread_mutex_unlock(&h
->rh_lock
);
4752 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4754 v
->value_type
= REP_PROTOCOL_SUBTYPE_USTRING
;
4755 (void) pthread_mutex_unlock(&h
->rh_lock
);
4760 scf_value_set_opaque(scf_value_t
*v
, const void *new, size_t len
)
4762 scf_handle_t
*h
= v
->value_handle
;
4764 (void) pthread_mutex_lock(&h
->rh_lock
);
4765 scf_value_reset_locked(v
, 0);
4766 if (len
> sizeof (v
->value_value
)) {
4767 (void) pthread_mutex_unlock(&h
->rh_lock
);
4768 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4770 (void) memcpy(v
->value_value
, new, len
);
4771 v
->value_size
= len
;
4772 v
->value_type
= REP_PROTOCOL_TYPE_OPAQUE
;
4773 (void) pthread_mutex_unlock(&h
->rh_lock
);
4779 * _NOT_SET - v_arg is reset
4780 * _INTERNAL - v_arg is corrupt
4782 * If t is not _TYPE_INVALID, fails with
4783 * _TYPE_MISMATCH - v_arg's type is not compatible with t
4786 scf_value_get_as_string_common(const scf_value_t
*v_arg
,
4787 rep_protocol_value_type_t t
, char *buf
, size_t bufsz
)
4789 scf_handle_t
*h
= v_arg
->value_handle
;
4791 scf_value_t
*v
= &v_s
;
4795 (void) pthread_mutex_lock(&h
->rh_lock
);
4796 if (t
!= REP_PROTOCOL_TYPE_INVALID
&& !scf_value_check_type(v_arg
, t
)) {
4797 (void) pthread_mutex_unlock(&h
->rh_lock
);
4801 v_s
= *v_arg
; /* copy locally so we can unlock */
4802 h
->rh_values
++; /* keep the handle from going away */
4804 (void) pthread_mutex_unlock(&h
->rh_lock
);
4807 switch (REP_PROTOCOL_BASE_TYPE(v
->value_type
)) {
4808 case REP_PROTOCOL_TYPE_BOOLEAN
:
4809 r
= scf_value_get_boolean(v
, &b
);
4810 assert(r
== SCF_SUCCESS
);
4812 r
= strlcpy(buf
, b
? "true" : "false", bufsz
);
4815 case REP_PROTOCOL_TYPE_COUNT
:
4816 case REP_PROTOCOL_TYPE_INTEGER
:
4817 case REP_PROTOCOL_TYPE_TIME
:
4818 case REP_PROTOCOL_TYPE_STRING
:
4819 r
= strlcpy(buf
, v
->value_value
, bufsz
);
4822 case REP_PROTOCOL_TYPE_OPAQUE
:
4824 * Note that we only write out full hex bytes -- if they're
4825 * short, and bufsz is even, we'll only fill (bufsz - 2) bytes
4829 (void) scf_opaque_encode(buf
, v
->value_value
,
4830 MIN(v
->value_size
, (bufsz
- 1)/2));
4831 r
= (v
->value_size
* 2);
4834 case REP_PROTOCOL_TYPE_INVALID
:
4835 r
= scf_set_error(SCF_ERROR_NOT_SET
);
4839 r
= (scf_set_error(SCF_ERROR_INTERNAL
));
4843 (void) pthread_mutex_lock(&h
->rh_lock
);
4852 scf_value_get_as_string(const scf_value_t
*v
, char *buf
, size_t bufsz
)
4854 return (scf_value_get_as_string_common(v
, REP_PROTOCOL_TYPE_INVALID
,
4859 scf_value_get_as_string_typed(const scf_value_t
*v
, scf_type_t type
,
4860 char *buf
, size_t bufsz
)
4862 rep_protocol_value_type_t ty
= scf_type_to_protocol_type(type
);
4863 if (ty
== REP_PROTOCOL_TYPE_INVALID
)
4864 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4866 return (scf_value_get_as_string_common(v
, ty
, buf
, bufsz
));
4870 scf_value_set_from_string(scf_value_t
*v
, scf_type_t type
, const char *str
)
4872 scf_handle_t
*h
= v
->value_handle
;
4873 rep_protocol_value_type_t ty
;
4876 case SCF_TYPE_BOOLEAN
: {
4879 if (strcmp(str
, "true") == 0 || strcmp(str
, "t") == 0 ||
4880 strcmp(str
, "1") == 0)
4882 else if (strcmp(str
, "false") == 0 ||
4883 strcmp(str
, "f") == 0 || strcmp(str
, "0") == 0)
4889 scf_value_set_boolean(v
, b
);
4893 case SCF_TYPE_COUNT
: {
4898 c
= strtoull(str
, &endp
, 0);
4900 if (errno
!= 0 || endp
== str
|| *endp
!= '\0')
4903 scf_value_set_count(v
, c
);
4907 case SCF_TYPE_INTEGER
: {
4912 i
= strtoll(str
, &endp
, 0);
4914 if (errno
!= 0 || endp
== str
|| *endp
!= '\0')
4917 scf_value_set_integer(v
, i
);
4921 case SCF_TYPE_TIME
: {
4924 char *endp
, *ns_str
;
4928 s
= strtoll(str
, &endp
, 10);
4929 if (errno
!= 0 || endp
== str
||
4930 (*endp
!= '\0' && *endp
!= '.'))
4935 len
= strlen(ns_str
);
4936 if (len
== 0 || len
> 9)
4939 ns
= strtoul(ns_str
, &endp
, 10);
4940 if (errno
!= 0 || endp
== ns_str
|| *endp
!= '\0')
4945 assert(ns
< NANOSEC
);
4948 return (scf_value_set_time(v
, s
, ns
));
4951 case SCF_TYPE_ASTRING
:
4952 case SCF_TYPE_USTRING
:
4953 case SCF_TYPE_OPAQUE
:
4957 case SCF_TYPE_HOSTNAME
:
4958 case SCF_TYPE_NET_ADDR
:
4959 case SCF_TYPE_NET_ADDR_V4
:
4960 case SCF_TYPE_NET_ADDR_V6
:
4961 ty
= scf_type_to_protocol_type(type
);
4963 (void) pthread_mutex_lock(&h
->rh_lock
);
4964 scf_value_reset_locked(v
, 0);
4965 if (type
== SCF_TYPE_OPAQUE
) {
4966 v
->value_size
= scf_opaque_decode(v
->value_value
,
4967 str
, sizeof (v
->value_value
));
4968 if (!scf_validate_encoded_value(ty
, str
)) {
4969 (void) pthread_mutex_lock(&h
->rh_lock
);
4973 (void) strlcpy(v
->value_value
, str
,
4974 sizeof (v
->value_value
));
4975 if (!scf_validate_encoded_value(ty
, v
->value_value
)) {
4976 (void) pthread_mutex_lock(&h
->rh_lock
);
4981 (void) pthread_mutex_unlock(&h
->rh_lock
);
4982 return (SCF_SUCCESS
);
4984 case REP_PROTOCOL_TYPE_INVALID
:
4987 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
4991 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4995 scf_iter_property_values(scf_iter_t
*iter
, const scf_property_t
*prop
)
4997 return (datael_setup_iter(iter
, &prop
->rd_d
,
4998 REP_PROTOCOL_ENTITY_VALUE
, 0));
5002 scf_iter_next_value(scf_iter_t
*iter
, scf_value_t
*v
)
5004 scf_handle_t
*h
= iter
->iter_handle
;
5006 struct rep_protocol_iter_read_value request
;
5007 struct rep_protocol_value_response response
;
5011 if (h
!= v
->value_handle
)
5012 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5014 (void) pthread_mutex_lock(&h
->rh_lock
);
5016 scf_value_reset_locked(v
, 0);
5018 if (iter
->iter_type
== REP_PROTOCOL_ENTITY_NONE
) {
5019 (void) pthread_mutex_unlock(&h
->rh_lock
);
5020 return (scf_set_error(SCF_ERROR_NOT_SET
));
5023 if (iter
->iter_type
!= REP_PROTOCOL_ENTITY_VALUE
) {
5024 (void) pthread_mutex_unlock(&h
->rh_lock
);
5025 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5028 request
.rpr_request
= REP_PROTOCOL_ITER_READ_VALUE
;
5029 request
.rpr_iterid
= iter
->iter_id
;
5030 request
.rpr_sequence
= iter
->iter_sequence
;
5032 r
= make_door_call(h
, &request
, sizeof (request
),
5033 &response
, sizeof (response
));
5036 (void) pthread_mutex_unlock(&h
->rh_lock
);
5037 DOOR_ERRORS_BLOCK(r
);
5040 if (response
.rpr_response
== REP_PROTOCOL_DONE
) {
5041 (void) pthread_mutex_unlock(&h
->rh_lock
);
5044 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
5045 (void) pthread_mutex_unlock(&h
->rh_lock
);
5046 return (scf_set_error(proto_error(response
.rpr_response
)));
5048 iter
->iter_sequence
++;
5050 v
->value_type
= response
.rpr_type
;
5052 assert(scf_validate_encoded_value(response
.rpr_type
,
5053 response
.rpr_value
));
5055 if (v
->value_type
!= REP_PROTOCOL_TYPE_OPAQUE
) {
5056 (void) strlcpy(v
->value_value
, response
.rpr_value
,
5057 sizeof (v
->value_value
));
5059 v
->value_size
= scf_opaque_decode(v
->value_value
,
5060 response
.rpr_value
, sizeof (v
->value_value
));
5062 (void) pthread_mutex_unlock(&h
->rh_lock
);
5068 scf_property_get_value(const scf_property_t
*prop
, scf_value_t
*v
)
5070 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
5071 struct rep_protocol_property_request request
;
5072 struct rep_protocol_value_response response
;
5075 if (h
!= v
->value_handle
)
5076 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5078 (void) pthread_mutex_lock(&h
->rh_lock
);
5080 request
.rpr_request
= REP_PROTOCOL_PROPERTY_GET_VALUE
;
5081 request
.rpr_entityid
= prop
->rd_d
.rd_entity
;
5083 scf_value_reset_locked(v
, 0);
5084 datael_finish_reset(&prop
->rd_d
);
5086 r
= make_door_call(h
, &request
, sizeof (request
),
5087 &response
, sizeof (response
));
5090 (void) pthread_mutex_unlock(&h
->rh_lock
);
5091 DOOR_ERRORS_BLOCK(r
);
5094 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
5095 response
.rpr_response
!= REP_PROTOCOL_FAIL_TRUNCATED
) {
5096 (void) pthread_mutex_unlock(&h
->rh_lock
);
5097 assert(response
.rpr_response
!=
5098 REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
5099 return (scf_set_error(proto_error(response
.rpr_response
)));
5102 v
->value_type
= response
.rpr_type
;
5103 if (v
->value_type
!= REP_PROTOCOL_TYPE_OPAQUE
) {
5104 (void) strlcpy(v
->value_value
, response
.rpr_value
,
5105 sizeof (v
->value_value
));
5107 v
->value_size
= scf_opaque_decode(v
->value_value
,
5108 response
.rpr_value
, sizeof (v
->value_value
));
5110 (void) pthread_mutex_unlock(&h
->rh_lock
);
5111 return ((response
.rpr_response
== REP_PROTOCOL_SUCCESS
)?
5112 SCF_SUCCESS
: scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
));
5116 scf_pg_get_parent_service(const scf_propertygroup_t
*pg
, scf_service_t
*svc
)
5118 return (datael_get_parent(&pg
->rd_d
, &svc
->rd_d
));
5122 scf_pg_get_parent_instance(const scf_propertygroup_t
*pg
, scf_instance_t
*inst
)
5124 return (datael_get_parent(&pg
->rd_d
, &inst
->rd_d
));
5128 scf_pg_get_parent_snaplevel(const scf_propertygroup_t
*pg
,
5129 scf_snaplevel_t
*level
)
5131 return (datael_get_parent(&pg
->rd_d
, &level
->rd_d
));
5135 scf_service_get_parent(const scf_service_t
*svc
, scf_scope_t
*s
)
5137 return (datael_get_parent(&svc
->rd_d
, &s
->rd_d
));
5141 scf_instance_get_parent(const scf_instance_t
*inst
, scf_service_t
*svc
)
5143 return (datael_get_parent(&inst
->rd_d
, &svc
->rd_d
));
5147 scf_snapshot_get_parent(const scf_snapshot_t
*inst
, scf_instance_t
*svc
)
5149 return (datael_get_parent(&inst
->rd_d
, &svc
->rd_d
));
5153 scf_snaplevel_get_parent(const scf_snaplevel_t
*inst
, scf_snapshot_t
*svc
)
5155 return (datael_get_parent(&inst
->rd_d
, &svc
->rd_d
));
5161 * Note: In the scf_parse_svc_fmri(), scf_parse_file_fmri() and
5162 * scf_parse_fmri(), fmri isn't const because that would require
5163 * allocating memory. Also, note that scope, at least, is not necessarily
5164 * in the passed in fmri.
5168 scf_parse_svc_fmri(char *fmri
, const char **scope
, const char **service
,
5169 const char **instance
, const char **propertygroup
, const char **property
)
5171 char *s
, *e
, *te
, *tpg
;
5172 char *my_s
= NULL
, *my_i
= NULL
, *my_pg
= NULL
, *my_p
= NULL
;
5176 if (service
!= NULL
)
5178 if (instance
!= NULL
)
5180 if (propertygroup
!= NULL
)
5181 *propertygroup
= NULL
;
5182 if (property
!= NULL
)
5186 e
= strchr(s
, '\0');
5188 if (strncmp(s
, SCF_FMRI_SVC_PREFIX
,
5189 sizeof (SCF_FMRI_SVC_PREFIX
) - 1) == 0)
5190 s
+= sizeof (SCF_FMRI_SVC_PREFIX
) - 1;
5192 if (strncmp(s
, SCF_FMRI_SCOPE_PREFIX
,
5193 sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1) == 0) {
5196 s
+= sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1;
5197 te
= strstr(s
, SCF_FMRI_SERVICE_PREFIX
);
5206 s
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5208 /* If the scope ends with the suffix, remove it. */
5209 te
= strstr(my_scope
, SCF_FMRI_SCOPE_SUFFIX
);
5210 if (te
!= NULL
&& te
[sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1] == 0)
5213 /* Validate the scope. */
5214 if (my_scope
[0] == '\0')
5215 my_scope
= SCF_FMRI_LOCAL_SCOPE
;
5216 else if (uu_check_name(my_scope
, 0) == -1) {
5217 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5224 *scope
= SCF_FMRI_LOCAL_SCOPE
;
5228 if (strncmp(s
, SCF_FMRI_SERVICE_PREFIX
,
5229 sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1) == 0)
5230 s
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5233 * Can't validate service here because it might not be null
5239 tpg
= strstr(s
, SCF_FMRI_PROPERTYGRP_PREFIX
);
5240 te
= strstr(s
, SCF_FMRI_INSTANCE_PREFIX
);
5241 if (te
!= NULL
&& (tpg
== NULL
|| te
< tpg
)) {
5243 te
+= sizeof (SCF_FMRI_INSTANCE_PREFIX
) - 1;
5245 /* Can't validate instance here either. */
5248 te
= strstr(s
, SCF_FMRI_PROPERTYGRP_PREFIX
);
5255 te
+= sizeof (SCF_FMRI_PROPERTYGRP_PREFIX
) - 1;
5258 te
= strstr(s
, SCF_FMRI_PROPERTY_PREFIX
);
5261 te
+= sizeof (SCF_FMRI_PROPERTY_PREFIX
) - 1;
5269 if (uu_check_name(my_s
, UU_NAME_DOMAIN
| UU_NAME_PATH
) == -1)
5270 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5272 if (service
!= NULL
)
5277 if (uu_check_name(my_i
, UU_NAME_DOMAIN
) == -1)
5278 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5280 if (instance
!= NULL
)
5284 if (my_pg
!= NULL
) {
5285 if (uu_check_name(my_pg
, UU_NAME_DOMAIN
) == -1)
5286 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5288 if (propertygroup
!= NULL
)
5289 *propertygroup
= my_pg
;
5293 if (uu_check_name(my_p
, UU_NAME_DOMAIN
) == -1)
5294 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5296 if (property
!= NULL
)
5304 scf_parse_file_fmri(char *fmri
, const char **scope
, const char **path
)
5312 e
= strchr(s
, '\0');
5314 if (strncmp(s
, SCF_FMRI_FILE_PREFIX
,
5315 sizeof (SCF_FMRI_FILE_PREFIX
) - 1) == 0)
5316 s
+= sizeof (SCF_FMRI_FILE_PREFIX
) - 1;
5318 if (strncmp(s
, SCF_FMRI_SCOPE_PREFIX
,
5319 sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1) == 0) {
5322 s
+= sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1;
5323 te
= strstr(s
, SCF_FMRI_SERVICE_PREFIX
);
5332 /* Validate the scope. */
5333 if (my_scope
[0] != '\0' &&
5334 strcmp(my_scope
, SCF_FMRI_LOCAL_SCOPE
) != 0) {
5335 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5342 * FMRI paths must be absolute
5345 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5348 s
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5351 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5354 * If the user requests it, return the full path of the file.
5366 scf_parse_fmri(char *fmri
, int *type
, const char **scope
, const char **service
,
5367 const char **instance
, const char **propertygroup
, const char **property
)
5369 if (strncmp(fmri
, SCF_FMRI_SVC_PREFIX
,
5370 sizeof (SCF_FMRI_SVC_PREFIX
) - 1) == 0) {
5372 *type
= SCF_FMRI_TYPE_SVC
;
5373 return (scf_parse_svc_fmri(fmri
, scope
, service
, instance
,
5374 propertygroup
, property
));
5375 } else if (strncmp(fmri
, SCF_FMRI_FILE_PREFIX
,
5376 sizeof (SCF_FMRI_FILE_PREFIX
) - 1) == 0) {
5378 *type
= SCF_FMRI_TYPE_FILE
;
5379 return (scf_parse_file_fmri(fmri
, scope
, NULL
));
5382 * Parse as a svc if the fmri type is not explicitly
5386 *type
= SCF_FMRI_TYPE_SVC
;
5387 return (scf_parse_svc_fmri(fmri
, scope
, service
, instance
,
5388 propertygroup
, property
));
5393 * Fails with _INVALID_ARGUMENT. fmri and buf may be equal.
5396 scf_canonify_fmri(const char *fmri
, char *buf
, size_t bufsz
)
5398 const char *scope
, *service
, *instance
, *pg
, *property
;
5399 char local
[6 * REP_PROTOCOL_NAME_LEN
];
5403 if (strlcpy(local
, fmri
, sizeof (local
)) >= sizeof (local
)) {
5404 /* Should this be CONSTRAINT_VIOLATED? */
5405 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
5410 r
= scf_parse_svc_fmri(local
, &scope
, &service
, &instance
, &pg
,
5415 len
= strlcpy(buf
, "svc:/", bufsz
);
5417 if (scope
!= NULL
&& strcmp(scope
, SCF_SCOPE_LOCAL
) != 0) {
5418 len
+= strlcat(buf
, "/", bufsz
);
5419 len
+= strlcat(buf
, scope
, bufsz
);
5423 len
+= strlcat(buf
, service
, bufsz
);
5426 len
+= strlcat(buf
, ":", bufsz
);
5427 len
+= strlcat(buf
, instance
, bufsz
);
5431 len
+= strlcat(buf
, "/:properties/", bufsz
);
5432 len
+= strlcat(buf
, pg
, bufsz
);
5436 len
+= strlcat(buf
, "/", bufsz
);
5437 len
+= strlcat(buf
, property
, bufsz
);
5444 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _CONSTRAINT_VIOLATED,
5445 * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED,
5446 * _NO_RESOURCES, _BACKEND_ACCESS.
5449 scf_handle_decode_fmri(scf_handle_t
*h
, const char *fmri
, scf_scope_t
*sc
,
5450 scf_service_t
*svc
, scf_instance_t
*inst
, scf_propertygroup_t
*pg
,
5451 scf_property_t
*prop
, int flags
)
5453 const char *scope
, *service
, *instance
, *propertygroup
, *property
;
5455 char local
[6 * REP_PROTOCOL_NAME_LEN
];
5457 const uint32_t holds
= RH_HOLD_SCOPE
| RH_HOLD_SERVICE
|
5458 RH_HOLD_INSTANCE
| RH_HOLD_PG
| RH_HOLD_PROPERTY
;
5461 * verify that all handles match
5463 if ((sc
!= NULL
&& h
!= sc
->rd_d
.rd_handle
) ||
5464 (svc
!= NULL
&& h
!= svc
->rd_d
.rd_handle
) ||
5465 (inst
!= NULL
&& h
!= inst
->rd_d
.rd_handle
) ||
5466 (pg
!= NULL
&& h
!= pg
->rd_d
.rd_handle
) ||
5467 (prop
!= NULL
&& h
!= prop
->rd_d
.rd_handle
))
5468 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5470 if (strlcpy(local
, fmri
, sizeof (local
)) >= sizeof (local
)) {
5471 ret
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
5476 * We can simply return from an error in parsing, because
5477 * scf_parse_fmri sets the error code correctly.
5479 if (scf_parse_svc_fmri(local
, &scope
, &service
, &instance
,
5480 &propertygroup
, &property
) == -1) {
5486 * the FMRI looks valid at this point -- do constraint checks.
5489 if (instance
!= NULL
&& (flags
& SCF_DECODE_FMRI_REQUIRE_NO_INSTANCE
)) {
5490 ret
= scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
);
5493 if (instance
== NULL
&& (flags
& SCF_DECODE_FMRI_REQUIRE_INSTANCE
)) {
5494 ret
= scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
);
5499 last
= REP_PROTOCOL_ENTITY_PROPERTY
;
5500 else if (pg
!= NULL
)
5501 last
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
5502 else if (inst
!= NULL
)
5503 last
= REP_PROTOCOL_ENTITY_INSTANCE
;
5504 else if (svc
!= NULL
)
5505 last
= REP_PROTOCOL_ENTITY_SERVICE
;
5506 else if (sc
!= NULL
)
5507 last
= REP_PROTOCOL_ENTITY_SCOPE
;
5509 last
= REP_PROTOCOL_ENTITY_NONE
;
5511 if (flags
& SCF_DECODE_FMRI_EXACT
) {
5514 if (property
!= NULL
)
5515 last_fmri
= REP_PROTOCOL_ENTITY_PROPERTY
;
5516 else if (propertygroup
!= NULL
)
5517 last_fmri
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
5518 else if (instance
!= NULL
)
5519 last_fmri
= REP_PROTOCOL_ENTITY_INSTANCE
;
5520 else if (service
!= NULL
)
5521 last_fmri
= REP_PROTOCOL_ENTITY_SERVICE
;
5522 else if (scope
!= NULL
)
5523 last_fmri
= REP_PROTOCOL_ENTITY_SCOPE
;
5525 last_fmri
= REP_PROTOCOL_ENTITY_NONE
;
5527 if (last
!= last_fmri
) {
5528 ret
= scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
);
5533 if ((flags
& SCF_DECODE_FMRI_TRUNCATE
) &&
5534 last
== REP_PROTOCOL_ENTITY_NONE
) {
5535 ret
= 0; /* nothing to do */
5539 if (!(flags
& SCF_DECODE_FMRI_TRUNCATE
))
5540 last
= REP_PROTOCOL_ENTITY_NONE
; /* never stop */
5543 * passed the constraint checks -- try to grab the thing itself.
5546 handle_hold_subhandles(h
, holds
);
5550 datael_reset(&sc
->rd_d
);
5553 svc
= h
->rh_service
;
5555 datael_reset(&svc
->rd_d
);
5558 inst
= h
->rh_instance
;
5560 datael_reset(&inst
->rd_d
);
5565 datael_reset(&pg
->rd_d
);
5568 prop
= h
->rh_property
;
5570 datael_reset(&prop
->rd_d
);
5573 * We only support local scopes, but we check *after* getting
5574 * the local scope, so that any repository-related errors take
5577 if (scf_handle_get_scope(h
, SCF_SCOPE_LOCAL
, sc
) == -1) {
5578 handle_rele_subhandles(h
, holds
);
5583 if (scope
!= NULL
&& strcmp(scope
, SCF_FMRI_LOCAL_SCOPE
) != 0) {
5584 handle_rele_subhandles(h
, holds
);
5585 ret
= scf_set_error(SCF_ERROR_NOT_FOUND
);
5590 if (service
== NULL
|| last
== REP_PROTOCOL_ENTITY_SCOPE
) {
5591 handle_rele_subhandles(h
, holds
);
5595 if (scf_scope_get_service(sc
, service
, svc
) == -1) {
5596 handle_rele_subhandles(h
, holds
);
5598 assert(scf_error() != SCF_ERROR_NOT_SET
);
5599 if (scf_error() == SCF_ERROR_DELETED
)
5600 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5604 if (last
== REP_PROTOCOL_ENTITY_SERVICE
) {
5605 handle_rele_subhandles(h
, holds
);
5609 if (instance
== NULL
) {
5610 if (propertygroup
== NULL
||
5611 last
== REP_PROTOCOL_ENTITY_INSTANCE
) {
5612 handle_rele_subhandles(h
, holds
);
5616 if (scf_service_get_pg(svc
, propertygroup
, pg
) == -1) {
5617 handle_rele_subhandles(h
, holds
);
5619 assert(scf_error() != SCF_ERROR_NOT_SET
);
5620 if (scf_error() == SCF_ERROR_DELETED
)
5621 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5625 if (scf_service_get_instance(svc
, instance
, inst
) == -1) {
5626 handle_rele_subhandles(h
, holds
);
5628 assert(scf_error() != SCF_ERROR_NOT_SET
);
5629 if (scf_error() == SCF_ERROR_DELETED
)
5630 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5634 if (propertygroup
== NULL
||
5635 last
== REP_PROTOCOL_ENTITY_INSTANCE
) {
5636 handle_rele_subhandles(h
, holds
);
5640 if (scf_instance_get_pg(inst
, propertygroup
, pg
) == -1) {
5641 handle_rele_subhandles(h
, holds
);
5643 assert(scf_error() != SCF_ERROR_NOT_SET
);
5644 if (scf_error() == SCF_ERROR_DELETED
)
5645 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5650 if (property
== NULL
|| last
== REP_PROTOCOL_ENTITY_PROPERTYGRP
) {
5651 handle_rele_subhandles(h
, holds
);
5655 if (scf_pg_get_property(pg
, property
, prop
) == -1) {
5656 handle_rele_subhandles(h
, holds
);
5658 assert(scf_error() != SCF_ERROR_NOT_SET
);
5659 if (scf_error() == SCF_ERROR_DELETED
)
5660 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5664 handle_rele_subhandles(h
, holds
);
5669 datael_reset(&sc
->rd_d
);
5671 datael_reset(&svc
->rd_d
);
5673 datael_reset(&inst
->rd_d
);
5675 datael_reset(&pg
->rd_d
);
5677 datael_reset(&prop
->rd_d
);
5683 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5684 * big, bad entity id, request not applicable to entity, name too long for
5685 * buffer), _NOT_SET, or _DELETED.
5688 scf_scope_to_fmri(const scf_scope_t
*scope
, char *out
, size_t sz
)
5692 char tmp
[REP_PROTOCOL_NAME_LEN
];
5694 r
= scf_scope_get_name(scope
, tmp
, sizeof (tmp
));
5699 len
= strlcpy(out
, SCF_FMRI_SVC_PREFIX
, sz
);
5700 if (strcmp(tmp
, SCF_FMRI_LOCAL_SCOPE
) != 0) {
5702 return (len
+ r
+ sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1);
5704 len
= strlcat(out
, tmp
, sz
);
5706 return (len
+ sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1);
5708 SCF_FMRI_SCOPE_SUFFIX SCF_FMRI_SERVICE_PREFIX
, sz
);
5715 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5716 * big, bad element id, bad ids, bad types, scope has no parent, request not
5717 * applicable to entity, name too long), _NOT_SET, _DELETED,
5720 scf_service_to_fmri(const scf_service_t
*svc
, char *out
, size_t sz
)
5722 scf_handle_t
*h
= svc
->rd_d
.rd_handle
;
5723 scf_scope_t
*scope
= HANDLE_HOLD_SCOPE(h
);
5726 char tmp
[REP_PROTOCOL_NAME_LEN
];
5728 r
= datael_get_parent(&svc
->rd_d
, &scope
->rd_d
);
5729 if (r
!= SCF_SUCCESS
) {
5730 HANDLE_RELE_SCOPE(h
);
5732 assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH
);
5735 if (out
!= NULL
&& sz
> 0)
5736 len
= scf_scope_to_fmri(scope
, out
, sz
);
5738 len
= scf_scope_to_fmri(scope
, tmp
, 2);
5740 HANDLE_RELE_SCOPE(h
);
5745 if (out
== NULL
|| len
>= sz
)
5746 len
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5748 len
= strlcat(out
, SCF_FMRI_SERVICE_PREFIX
, sz
);
5750 r
= scf_service_get_name(svc
, tmp
, sizeof (tmp
));
5754 if (out
== NULL
|| len
>= sz
)
5757 len
= strlcat(out
, tmp
, sz
);
5763 scf_instance_to_fmri(const scf_instance_t
*inst
, char *out
, size_t sz
)
5765 scf_handle_t
*h
= inst
->rd_d
.rd_handle
;
5766 scf_service_t
*svc
= HANDLE_HOLD_SERVICE(h
);
5769 char tmp
[REP_PROTOCOL_NAME_LEN
];
5771 r
= datael_get_parent(&inst
->rd_d
, &svc
->rd_d
);
5772 if (r
!= SCF_SUCCESS
) {
5773 HANDLE_RELE_SERVICE(h
);
5777 len
= scf_service_to_fmri(svc
, out
, sz
);
5779 HANDLE_RELE_SERVICE(h
);
5785 len
+= sizeof (SCF_FMRI_INSTANCE_PREFIX
) - 1;
5787 len
= strlcat(out
, SCF_FMRI_INSTANCE_PREFIX
, sz
);
5789 r
= scf_instance_get_name(inst
, tmp
, sizeof (tmp
));
5796 len
= strlcat(out
, tmp
, sz
);
5802 scf_pg_to_fmri(const scf_propertygroup_t
*pg
, char *out
, size_t sz
)
5804 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
5806 struct rep_protocol_entity_parent_type request
;
5807 struct rep_protocol_integer_response response
;
5809 char tmp
[REP_PROTOCOL_NAME_LEN
];
5812 (void) pthread_mutex_lock(&h
->rh_lock
);
5813 request
.rpr_request
= REP_PROTOCOL_ENTITY_PARENT_TYPE
;
5814 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
5816 datael_finish_reset(&pg
->rd_d
);
5817 r
= make_door_call(h
, &request
, sizeof (request
),
5818 &response
, sizeof (response
));
5819 (void) pthread_mutex_unlock(&h
->rh_lock
);
5822 DOOR_ERRORS_BLOCK(r
);
5824 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
||
5825 r
< sizeof (response
)) {
5826 return (scf_set_error(proto_error(response
.rpr_response
)));
5829 switch (response
.rpr_value
) {
5830 case REP_PROTOCOL_ENTITY_SERVICE
: {
5833 svc
= HANDLE_HOLD_SERVICE(h
);
5835 r
= datael_get_parent(&pg
->rd_d
, &svc
->rd_d
);
5837 if (r
== SCF_SUCCESS
)
5838 len
= scf_service_to_fmri(svc
, out
, sz
);
5840 HANDLE_RELE_SERVICE(h
);
5844 case REP_PROTOCOL_ENTITY_INSTANCE
: {
5845 scf_instance_t
*inst
;
5847 inst
= HANDLE_HOLD_INSTANCE(h
);
5849 r
= datael_get_parent(&pg
->rd_d
, &inst
->rd_d
);
5851 if (r
== SCF_SUCCESS
)
5852 len
= scf_instance_to_fmri(inst
, out
, sz
);
5854 HANDLE_RELE_INSTANCE(h
);
5858 case REP_PROTOCOL_ENTITY_SNAPLEVEL
: {
5859 scf_instance_t
*inst
= HANDLE_HOLD_INSTANCE(h
);
5860 scf_snapshot_t
*snap
= HANDLE_HOLD_SNAPSHOT(h
);
5861 scf_snaplevel_t
*level
= HANDLE_HOLD_SNAPLVL(h
);
5863 r
= datael_get_parent(&pg
->rd_d
, &level
->rd_d
);
5865 if (r
== SCF_SUCCESS
)
5866 r
= datael_get_parent(&level
->rd_d
, &snap
->rd_d
);
5868 if (r
== SCF_SUCCESS
)
5869 r
= datael_get_parent(&snap
->rd_d
, &inst
->rd_d
);
5871 if (r
== SCF_SUCCESS
)
5872 len
= scf_instance_to_fmri(inst
, out
, sz
);
5874 HANDLE_RELE_INSTANCE(h
);
5875 HANDLE_RELE_SNAPSHOT(h
);
5876 HANDLE_RELE_SNAPLVL(h
);
5881 return (scf_set_error(SCF_ERROR_INTERNAL
));
5884 if (r
!= SCF_SUCCESS
)
5888 len
+= sizeof (SCF_FMRI_PROPERTYGRP_PREFIX
) - 1;
5890 len
= strlcat(out
, SCF_FMRI_PROPERTYGRP_PREFIX
, sz
);
5892 r
= scf_pg_get_name(pg
, tmp
, sizeof (tmp
));
5900 len
= strlcat(out
, tmp
, sz
);
5906 scf_property_to_fmri(const scf_property_t
*prop
, char *out
, size_t sz
)
5908 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
5909 scf_propertygroup_t
*pg
= HANDLE_HOLD_PG(h
);
5911 char tmp
[REP_PROTOCOL_NAME_LEN
];
5915 r
= datael_get_parent(&prop
->rd_d
, &pg
->rd_d
);
5916 if (r
!= SCF_SUCCESS
) {
5921 len
= scf_pg_to_fmri(pg
, out
, sz
);
5926 len
+= sizeof (SCF_FMRI_PROPERTY_PREFIX
) - 1;
5928 len
= strlcat(out
, SCF_FMRI_PROPERTY_PREFIX
, sz
);
5930 r
= scf_property_get_name(prop
, tmp
, sizeof (tmp
));
5938 len
= strlcat(out
, tmp
, sz
);
5944 * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
5945 * (server response too big, bad entity id, request not applicable to entity,
5946 * name too long for buffer, bad element id, iter already exists, element
5947 * cannot have children of type, type is invalid, iter was reset, sequence
5948 * was bad, iter walks values, iter does not walk type entities),
5949 * _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED,
5950 * _NOT_FOUND (scope has no parent), _INVALID_ARGUMENT, _NO_RESOURCES,
5954 scf_pg_get_underlying_pg(const scf_propertygroup_t
*pg
,
5955 scf_propertygroup_t
*out
)
5957 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
5959 scf_instance_t
*inst
;
5961 char me
[REP_PROTOCOL_NAME_LEN
];
5964 if (h
!= out
->rd_d
.rd_handle
)
5965 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5967 r
= scf_pg_get_name(pg
, me
, sizeof (me
));
5972 svc
= HANDLE_HOLD_SERVICE(h
);
5973 inst
= HANDLE_HOLD_INSTANCE(h
);
5975 r
= datael_get_parent(&pg
->rd_d
, &inst
->rd_d
);
5977 if (r
== SCF_SUCCESS
) {
5978 r
= datael_get_parent(&inst
->rd_d
, &svc
->rd_d
);
5979 if (r
!= SCF_SUCCESS
) {
5982 r
= scf_service_get_pg(svc
, me
, out
);
5984 r
= scf_set_error(SCF_ERROR_NOT_FOUND
);
5988 HANDLE_RELE_SERVICE(h
);
5989 HANDLE_RELE_INSTANCE(h
);
5993 #define LEGACY_SCHEME "lrc:"
5994 #define LEGACY_UNKNOWN "unknown"
5997 * Implementation of scf_walk_fmri()
5999 * This is a little tricky due to the many-to-many relationship between patterns
6000 * and matches. We need to be able to satisfy the following requirements:
6002 * 1) Detect patterns which match more than one FMRI, and be able to
6003 * report which FMRIs have been matched.
6004 * 2) Detect patterns which have not matched any FMRIs
6005 * 3) Visit each matching FMRI exactly once across all patterns
6006 * 4) Ignore FMRIs which have only been matched due to multiply-matching
6009 * We maintain an array of scf_pattern_t structures, one for each argument, and
6010 * maintain a linked list of scf_match_t structures for each one. We first
6011 * qualify each pattern's type:
6013 * PATTERN_INVALID The argument is invalid (too long).
6015 * PATTERN_EXACT The pattern is a complete FMRI. The list of
6016 * matches contains only a single entry.
6018 * PATTERN_GLOB The pattern will be matched against all
6019 * FMRIs via fnmatch() in the second phase.
6020 * Matches will be added to the pattern's list
6021 * as they are found.
6023 * PATTERN_PARTIAL Everything else. We will assume that this is
6024 * an abbreviated FMRI, and match according to
6025 * our abbreviated FMRI rules. Matches will be
6026 * added to the pattern's list as they are found.
6028 * The first pass searches for arguments that are complete FMRIs. These are
6029 * classified as EXACT patterns and do not necessitate searching the entire
6032 * Once this is done, if we have any GLOB or PARTIAL patterns (or if no
6033 * arguments were given), we iterate over all services and instances in the
6034 * repository, looking for matches.
6036 * When a match is found, we add the match to the pattern's list. We also enter
6037 * the match into a hash table, resulting in something like this:
6039 * scf_pattern_t scf_match_t
6040 * +---------------+ +-------+ +-------+
6041 * | pattern 'foo' |----->| match |---->| match |
6042 * +---------------+ +-------+ +-------+
6044 * scf_match_key_t | |
6045 * +--------------+ | |
6046 * | FMRI bar/foo |<----+ |
6047 * +--------------+ |
6048 * | FMRI baz/foo |<------------------+
6051 * Once we have all of this set up, we do one pass to report patterns matching
6052 * multiple FMRIs (if SCF_WALK_MULTIPLE is not set) and patterns for which no
6055 * Finally, we walk through all valid patterns, and for each match, if we
6056 * haven't already seen the match (as recorded in the hash table), then we
6057 * execute the callback.
6060 struct scf_matchkey
;
6066 typedef struct scf_matchkey
{
6067 char *sk_fmri
; /* Matching FMRI */
6068 char *sk_legacy
; /* Legacy name */
6069 int sk_seen
; /* If we've been seen */
6070 struct scf_matchkey
*sk_next
; /* Next in hash chain */
6076 typedef struct scf_match
{
6077 scf_matchkey_t
*sm_key
;
6078 struct scf_match
*sm_next
;
6081 #define WALK_HTABLE_SIZE 123
6086 * Given an FMRI and a hash table, returns the scf_matchkey_t corresponding to
6087 * this FMRI. If the FMRI does not exist, it is added to the hash table. If a
6088 * new entry cannot be allocated due to lack of memory, NULL is returned.
6090 static scf_matchkey_t
*
6091 scf_get_key(scf_matchkey_t
**htable
, const char *fmri
, const char *legacy
)
6095 scf_matchkey_t
*key
;
6097 k
= strstr(fmri
, ":/");
6102 * Generic hash function from kernel/os/modhash.c.
6104 for (p
= k
; *p
!= '\0'; ++p
) {
6106 if ((g
= (h
& 0xf0000000)) != 0) {
6112 h
%= WALK_HTABLE_SIZE
;
6115 * Search for an existing key
6117 for (key
= htable
[h
]; key
!= NULL
; key
= key
->sk_next
) {
6118 if (strcmp(key
->sk_fmri
, fmri
) == 0)
6122 if ((key
= calloc(sizeof (scf_matchkey_t
), 1)) == NULL
)
6126 * Add new key to hash table.
6128 if ((key
->sk_fmri
= strdup(fmri
)) == NULL
) {
6133 if (legacy
== NULL
) {
6134 key
->sk_legacy
= NULL
;
6135 } else if ((key
->sk_legacy
= strdup(legacy
)) == NULL
) {
6141 key
->sk_next
= htable
[h
];
6148 * Given an FMRI, insert it into the pattern's list appropriately.
6149 * svc_explicit indicates whether matching services should take
6150 * precedence over matching instances.
6153 scf_add_match(scf_matchkey_t
**htable
, const char *fmri
, const char *legacy
,
6154 scf_pattern_t
*pattern
, int svc_explicit
)
6159 * If svc_explicit is set, enforce the constaint that matching
6160 * instances take precedence over matching services. Otherwise,
6161 * matching services take precedence over matching instances.
6164 scf_match_t
*next
, *prev
;
6166 * If we match an instance, check to see if we must remove
6167 * any matching services (for SCF_WALK_EXPLICIT).
6169 for (prev
= match
= pattern
->sp_matches
; match
!= NULL
;
6171 size_t len
= strlen(match
->sm_key
->sk_fmri
);
6172 next
= match
->sm_next
;
6173 if (strncmp(match
->sm_key
->sk_fmri
, fmri
, len
) == 0 &&
6176 pattern
->sp_matches
= match
->sm_next
;
6178 prev
->sm_next
= match
->sm_next
;
6179 pattern
->sp_matchcount
--;
6186 * If we've matched a service don't add any instances (for
6187 * SCF_WALK_SERVICE).
6189 for (match
= pattern
->sp_matches
; match
!= NULL
;
6190 match
= match
->sm_next
) {
6191 size_t len
= strlen(match
->sm_key
->sk_fmri
);
6192 if (strncmp(match
->sm_key
->sk_fmri
, fmri
, len
) == 0 &&
6198 if ((match
= malloc(sizeof (scf_match_t
))) == NULL
)
6199 return (SCF_ERROR_NO_MEMORY
);
6201 if ((match
->sm_key
= scf_get_key(htable
, fmri
, legacy
)) == NULL
) {
6203 return (SCF_ERROR_NO_MEMORY
);
6206 match
->sm_next
= pattern
->sp_matches
;
6207 pattern
->sp_matches
= match
;
6208 pattern
->sp_matchcount
++;
6214 * Returns 1 if the fmri matches the given pattern, 0 otherwise.
6217 scf_cmp_pattern(char *fmri
, scf_pattern_t
*pattern
)
6221 if (pattern
->sp_type
== PATTERN_GLOB
) {
6222 if (fnmatch(pattern
->sp_arg
, fmri
, 0) == 0)
6224 } else if (pattern
->sp_type
== PATTERN_PARTIAL
&&
6225 (tmp
= strstr(fmri
, pattern
->sp_arg
)) != NULL
) {
6227 * We only allow partial matches anchored on the end of
6228 * a service or instance, and beginning on an element
6231 if (tmp
!= fmri
&& tmp
[-1] != '/' && tmp
[-1] != ':' &&
6234 tmp
+= strlen(pattern
->sp_arg
);
6235 if (tmp
!= fmri
+ strlen(fmri
) && tmp
[0] != ':' &&
6240 * If the user has supplied a short pattern that matches
6241 * 'svc:/' or 'lrc:/', ignore it.
6243 if (tmp
<= fmri
+ 4)
6253 * Attempts to match the given FMRI against a set of patterns, keeping track of
6257 scf_pattern_match(scf_matchkey_t
**htable
, char *fmri
, const char *legacy
,
6258 int npattern
, scf_pattern_t
*pattern
, int svc_explicit
)
6263 for (i
= 0; i
< npattern
; i
++) {
6264 if (scf_cmp_pattern(fmri
, &pattern
[i
]) &&
6265 (ret
= scf_add_match(htable
, fmri
,
6266 legacy
, &pattern
[i
], svc_explicit
)) != 0)
6274 * Construct an error message from a provided format string and include all
6275 * of the matched FMRIs.
6278 scf_multiple_match_error(scf_pattern_t
*pattern
, const char *format
)
6285 * Note that strlen(format) includes the length of '%s', which
6286 * accounts for the terminating null byte.
6288 assert(strstr(format
, "%s") != NULL
);
6289 len
= strlen(format
) + strlen(pattern
->sp_arg
);
6290 for (match
= pattern
->sp_matches
; match
!= NULL
;
6291 match
= match
->sm_next
)
6292 len
+= strlen(match
->sm_key
->sk_fmri
) + 2;
6294 if ((msg
= malloc(len
)) == NULL
)
6297 (void) snprintf(msg
, len
, format
, pattern
->sp_arg
);
6299 for (match
= pattern
->sp_matches
; match
!= NULL
;
6300 match
= match
->sm_next
) {
6302 off
+= snprintf(msg
+ off
, len
- off
, "\t%s\n",
6303 match
->sm_key
->sk_fmri
);
6310 * Fails with _INVALID_ARGUMENT, _HANDLE_DESTROYED, _INTERNAL (bad server
6311 * response or id in use), _NO_MEMORY, _HANDLE_MISMATCH, _CONSTRAINT_VIOLATED,
6312 * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _NOT_SET, _DELETED,
6313 * _NO_RESOURCES, _BACKEND_ACCESS, _TYPE_MISMATCH.
6316 scf_walk_fmri(scf_handle_t
*h
, int argc
, char **argv
, int flags
,
6317 scf_walk_callback callback
, void *data
, int *err
,
6318 void (*errfunc
)(const char *, ...))
6320 scf_pattern_t
*pattern
= NULL
;
6323 ssize_t max_fmri_length
;
6324 scf_service_t
*svc
= NULL
;
6325 scf_instance_t
*inst
= NULL
;
6326 scf_iter_t
*iter
= NULL
, *sciter
= NULL
, *siter
= NULL
;
6327 scf_scope_t
*scope
= NULL
;
6328 scf_propertygroup_t
*pg
= NULL
;
6329 scf_property_t
*prop
= NULL
;
6330 scf_value_t
*value
= NULL
;
6332 scf_matchkey_t
**htable
= NULL
;
6333 int pattern_search
= 0;
6334 ssize_t max_name_length
;
6335 char *pgname
= NULL
;
6336 scf_walkinfo_t info
;
6339 if (flags
& SCF_WALK_EXPLICIT
)
6340 assert(flags
& SCF_WALK_SERVICE
);
6341 if (flags
& SCF_WALK_NOINSTANCE
)
6342 assert(flags
& SCF_WALK_SERVICE
);
6343 if (flags
& SCF_WALK_PROPERTY
)
6344 assert(!(flags
& SCF_WALK_LEGACY
));
6348 * Setup initial variables
6350 max_fmri_length
= scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH
);
6351 assert(max_fmri_length
!= -1);
6352 max_name_length
= scf_limit(SCF_LIMIT_MAX_NAME_LENGTH
);
6353 assert(max_name_length
!= -1);
6355 if ((fmri
= malloc(max_fmri_length
+ 1)) == NULL
||
6356 (pgname
= malloc(max_name_length
+ 1)) == NULL
) {
6357 ret
= SCF_ERROR_NO_MEMORY
;
6363 } else if ((pattern
= calloc(argc
, sizeof (scf_pattern_t
)))
6365 ret
= SCF_ERROR_NO_MEMORY
;
6369 if ((htable
= calloc(WALK_HTABLE_SIZE
, sizeof (void *))) == NULL
) {
6370 ret
= SCF_ERROR_NO_MEMORY
;
6374 if ((inst
= scf_instance_create(h
)) == NULL
||
6375 (svc
= scf_service_create(h
)) == NULL
||
6376 (iter
= scf_iter_create(h
)) == NULL
||
6377 (sciter
= scf_iter_create(h
)) == NULL
||
6378 (siter
= scf_iter_create(h
)) == NULL
||
6379 (scope
= scf_scope_create(h
)) == NULL
||
6380 (pg
= scf_pg_create(h
)) == NULL
||
6381 (prop
= scf_property_create(h
)) == NULL
||
6382 (value
= scf_value_create(h
)) == NULL
) {
6388 * For each fmri given, we first check to see if it's a full service,
6389 * instance, property group, or property FMRI. This avoids having to do
6390 * the (rather expensive) walk of all instances. Any element which does
6391 * not match a full fmri is identified as a globbed pattern or a partial
6392 * fmri and stored in a private array when walking instances.
6394 for (i
= 0; i
< argc
; i
++) {
6395 const char *scope_name
, *svc_name
, *inst_name
, *pg_name
;
6396 const char *prop_name
;
6398 if (strlen(argv
[i
]) > max_fmri_length
) {
6399 errfunc(scf_get_msg(SCF_MSG_ARGTOOLONG
), argv
[i
]);
6401 *err
= UU_EXIT_FATAL
;
6405 (void) strcpy(fmri
, argv
[i
]);
6406 if (scf_parse_svc_fmri(fmri
, &scope_name
, &svc_name
, &inst_name
,
6407 &pg_name
, &prop_name
) != SCF_SUCCESS
)
6411 * If the user has specified SCF_WALK_PROPERTY, allow property
6412 * groups and properties.
6414 if (pg_name
!= NULL
|| prop_name
!= NULL
) {
6415 if (!(flags
& SCF_WALK_PROPERTY
))
6418 if (scf_handle_decode_fmri(h
, argv
[i
], NULL
, NULL
,
6419 NULL
, pg
, prop
, 0) != 0)
6422 if (scf_pg_get_name(pg
, NULL
, 0) < 0 &&
6423 scf_property_get_name(prop
, NULL
, 0) < 0)
6426 if (scf_canonify_fmri(argv
[i
], fmri
, max_fmri_length
)
6429 * scf_parse_fmri() should have caught this.
6434 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6435 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6438 if ((pattern
[i
].sp_arg
= strdup(argv
[i
])) == NULL
) {
6439 ret
= SCF_ERROR_NO_MEMORY
;
6442 pattern
[i
].sp_type
= PATTERN_EXACT
;
6446 * We need at least a service name
6448 if (scope_name
== NULL
|| svc_name
== NULL
)
6452 * If we have a fully qualified instance, add it to our list of
6455 if (inst_name
!= NULL
) {
6456 if (flags
& SCF_WALK_NOINSTANCE
)
6459 if (scf_handle_decode_fmri(h
, argv
[i
], NULL
, NULL
,
6460 inst
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != 0)
6463 if (scf_canonify_fmri(argv
[i
], fmri
, max_fmri_length
)
6467 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6468 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6471 if ((pattern
[i
].sp_arg
= strdup(argv
[i
])) == NULL
) {
6472 ret
= SCF_ERROR_NO_MEMORY
;
6475 pattern
[i
].sp_type
= PATTERN_EXACT
;
6480 if (scf_handle_decode_fmri(h
, argv
[i
], NULL
, svc
,
6481 NULL
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) !=
6486 * If the user allows for bare services, then simply
6487 * pass this service on.
6489 if (flags
& SCF_WALK_SERVICE
) {
6490 if (scf_service_to_fmri(svc
, fmri
,
6491 max_fmri_length
+ 1) <= 0) {
6496 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6497 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6500 if ((pattern
[i
].sp_arg
= strdup(argv
[i
]))
6502 ret
= SCF_ERROR_NO_MEMORY
;
6505 pattern
[i
].sp_type
= PATTERN_EXACT
;
6509 if (flags
& SCF_WALK_NOINSTANCE
)
6513 * Otherwise, iterate over all instances in the service.
6515 if (scf_iter_service_instances(iter
, svc
) !=
6522 ret
= scf_iter_next_instance(iter
, inst
);
6530 if (scf_instance_to_fmri(inst
, fmri
,
6531 max_fmri_length
+ 1) == -1)
6534 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6535 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6539 if ((pattern
[i
].sp_arg
= strdup(argv
[i
])) == NULL
) {
6540 ret
= SCF_ERROR_NO_MEMORY
;
6543 pattern
[i
].sp_type
= PATTERN_EXACT
;
6550 * If we got here because of a fatal error, bail out
6553 if (scf_error() == SCF_ERROR_CONNECTION_BROKEN
) {
6559 * At this point we failed to interpret the argument as a
6560 * complete fmri, so mark it as a partial or globbed FMRI for
6563 if (strpbrk(argv
[i
], "*?[") != NULL
) {
6565 * Prepend svc:/ to patterns which don't begin with * or
6568 pattern
[i
].sp_type
= PATTERN_GLOB
;
6569 if (argv
[i
][0] == '*' ||
6570 (strlen(argv
[i
]) >= 4 && argv
[i
][3] == ':'))
6571 pattern
[i
].sp_arg
= strdup(argv
[i
]);
6573 pattern
[i
].sp_arg
= malloc(strlen(argv
[i
]) + 6);
6574 if (pattern
[i
].sp_arg
!= NULL
)
6575 (void) snprintf(pattern
[i
].sp_arg
,
6576 strlen(argv
[i
]) + 6, "svc:/%s",
6580 pattern
[i
].sp_type
= PATTERN_PARTIAL
;
6581 pattern
[i
].sp_arg
= strdup(argv
[i
]);
6584 if (pattern
[i
].sp_arg
== NULL
) {
6585 ret
= SCF_ERROR_NO_MEMORY
;
6590 if (pattern_search
|| argc
== 0) {
6592 * We have a set of patterns to search for. Iterate over all
6593 * instances and legacy services searching for matches.
6595 if (scf_handle_get_local_scope(h
, scope
) != 0) {
6600 if (scf_iter_scope_services(sciter
, scope
) != 0) {
6606 ret
= scf_iter_next_service(sciter
, svc
);
6614 if (flags
& SCF_WALK_SERVICE
) {
6616 * If the user is requesting bare services, try
6617 * to match the service first.
6619 if (scf_service_to_fmri(svc
, fmri
,
6620 max_fmri_length
+ 1) < 0) {
6632 if ((ret
= callback(data
, &info
)) != 0)
6635 } else if ((ret
= scf_pattern_match(htable
,
6636 fmri
, NULL
, argc
, pattern
,
6637 flags
& SCF_WALK_EXPLICIT
)) != 0) {
6642 if (flags
& SCF_WALK_NOINSTANCE
)
6646 * Iterate over all instances in the service.
6648 if (scf_iter_service_instances(siter
, svc
) != 0) {
6649 if (scf_error() != SCF_ERROR_DELETED
) {
6657 ret
= scf_iter_next_instance(siter
, inst
);
6661 if (scf_error() != SCF_ERROR_DELETED
) {
6668 if (scf_instance_to_fmri(inst
, fmri
,
6669 max_fmri_length
+ 1) < 0) {
6675 * Without arguments, execute the callback
6685 if ((ret
= callback(data
, &info
)) != 0)
6687 } else if ((ret
= scf_pattern_match(htable
,
6688 fmri
, NULL
, argc
, pattern
,
6689 flags
& SCF_WALK_EXPLICIT
)) != 0) {
6696 * Search legacy services
6698 if ((flags
& SCF_WALK_LEGACY
)) {
6699 if (scf_scope_get_service(scope
, SCF_LEGACY_SERVICE
,
6701 if (scf_error() != SCF_ERROR_NOT_FOUND
) {
6709 if (scf_iter_service_pgs_typed(iter
, svc
,
6710 SCF_GROUP_FRAMEWORK
) != SCF_SUCCESS
) {
6715 (void) strcpy(fmri
, LEGACY_SCHEME
);
6718 ret
= scf_iter_next_pg(iter
, pg
);
6726 if (scf_pg_get_property(pg
,
6727 SCF_LEGACY_PROPERTY_NAME
, prop
) == -1) {
6729 if (ret
== SCF_ERROR_DELETED
||
6730 ret
== SCF_ERROR_NOT_FOUND
) {
6737 if (scf_property_is_type(prop
, SCF_TYPE_ASTRING
)
6739 if (scf_error() == SCF_ERROR_DELETED
)
6745 if (scf_property_get_value(prop
, value
) !=
6749 if (scf_value_get_astring(value
,
6750 fmri
+ sizeof (LEGACY_SCHEME
) - 1,
6751 max_fmri_length
+ 2 -
6752 sizeof (LEGACY_SCHEME
)) <= 0)
6755 if (scf_pg_get_name(pg
, pgname
,
6756 max_name_length
+ 1) <= 0) {
6757 if (scf_error() == SCF_ERROR_DELETED
)
6770 if ((ret
= callback(data
, &info
)) != 0)
6772 } else if ((ret
= scf_pattern_match(htable
,
6773 fmri
, pgname
, argc
, pattern
,
6774 flags
& SCF_WALK_EXPLICIT
)) != 0)
6787 * Check all patterns, and see if we have that any that didn't match
6788 * or any that matched multiple instances. For svcprop, add up the
6789 * total number of matching keys.
6792 for (i
= 0; i
< argc
; i
++) {
6795 if (pattern
[i
].sp_type
== PATTERN_INVALID
)
6797 if (pattern
[i
].sp_matchcount
== 0) {
6800 * Provide a useful error message based on the argument
6801 * and the type of entity requested.
6803 if (!(flags
& SCF_WALK_LEGACY
) &&
6804 strncmp(pattern
[i
].sp_arg
, "lrc:/", 5) == 0)
6805 msgid
= SCF_MSG_PATTERN_LEGACY
;
6806 else if (flags
& SCF_WALK_PROPERTY
)
6807 msgid
= SCF_MSG_PATTERN_NOENTITY
;
6808 else if (flags
& SCF_WALK_NOINSTANCE
)
6809 msgid
= SCF_MSG_PATTERN_NOSERVICE
;
6810 else if (flags
& SCF_WALK_SERVICE
)
6811 msgid
= SCF_MSG_PATTERN_NOINSTSVC
;
6813 msgid
= SCF_MSG_PATTERN_NOINSTANCE
;
6815 errfunc(scf_get_msg(msgid
), pattern
[i
].sp_arg
);
6817 *err
= UU_EXIT_FATAL
;
6818 } else if (!(flags
& SCF_WALK_MULTIPLE
) &&
6819 pattern
[i
].sp_matchcount
> 1) {
6822 msg
= scf_multiple_match_error(&pattern
[i
],
6823 scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH
));
6826 ret
= SCF_ERROR_NO_MEMORY
;
6833 *err
= UU_EXIT_FATAL
;
6838 * Set matchcount to 0 so the callback is not
6839 * performed for this pattern.
6841 pattern
[i
].sp_matchcount
= 0;
6843 } else if ((flags
& SCF_WALK_UNIPARTIAL
) &&
6844 pattern
[i
].sp_type
== PATTERN_PARTIAL
&&
6845 pattern
[i
].sp_matchcount
> 1) {
6848 msg
= scf_multiple_match_error(&pattern
[i
],
6849 scf_get_msg(SCF_MSG_PATTERN_MULTIPARTIAL
));
6852 ret
= SCF_ERROR_NO_MEMORY
;
6859 *err
= UU_EXIT_FATAL
;
6864 * Set matchcount to 0 so the callback is not
6865 * performed for this pattern.
6867 pattern
[i
].sp_matchcount
= 0;
6870 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6871 match
= match
->sm_next
) {
6872 if (!match
->sm_key
->sk_seen
)
6874 match
->sm_key
->sk_seen
= 1;
6880 * Clear 'sk_seen' for all keys.
6882 for (i
= 0; i
< WALK_HTABLE_SIZE
; i
++) {
6883 scf_matchkey_t
*key
;
6884 for (key
= htable
[i
]; key
!= NULL
; key
= key
->sk_next
)
6889 * Iterate over all the FMRIs in our hash table and execute the
6892 for (i
= 0; i
< argc
; i
++) {
6894 scf_matchkey_t
*key
;
6897 * Ignore patterns which didn't match anything or
6898 * for which the matchcount has been set to 0 due to an
6899 * error detected above.
6901 if (pattern
[i
].sp_matchcount
== 0)
6904 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6905 match
= match
->sm_next
) {
6907 key
= match
->sm_key
;
6913 if (key
->sk_legacy
!= NULL
) {
6914 if (scf_scope_get_service(scope
,
6915 "smf/legacy_run", svc
) != 0) {
6920 if (scf_service_get_pg(svc
, key
->sk_legacy
,
6924 info
.fmri
= key
->sk_fmri
;
6930 if ((ret
= callback(data
, &info
)) != 0)
6933 if (scf_handle_decode_fmri(h
, key
->sk_fmri
,
6934 scope
, svc
, inst
, pg
, prop
, 0) !=
6938 info
.fmri
= key
->sk_fmri
;
6941 if (scf_instance_get_name(inst
, NULL
, 0) < 0) {
6943 SCF_ERROR_CONNECTION_BROKEN
) {
6951 if (scf_pg_get_name(pg
, NULL
, 0) < 0) {
6953 SCF_ERROR_CONNECTION_BROKEN
) {
6961 if (scf_property_get_name(prop
, NULL
, 0) < 0) {
6963 SCF_ERROR_CONNECTION_BROKEN
) {
6972 if ((ret
= callback(data
, &info
)) != 0)
6980 scf_matchkey_t
*key
, *next
;
6982 for (i
= 0; i
< WALK_HTABLE_SIZE
; i
++) {
6984 for (key
= htable
[i
]; key
!= NULL
;
6987 next
= key
->sk_next
;
6990 free(key
->sk_legacy
);
6996 if (pattern
!= NULL
) {
6997 for (i
= 0; i
< argc
; i
++) {
6998 scf_match_t
*match
, *next
;
7000 free(pattern
[i
].sp_arg
);
7002 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
7005 next
= match
->sm_next
;
7016 scf_value_destroy(value
);
7017 scf_property_destroy(prop
);
7019 scf_scope_destroy(scope
);
7020 scf_iter_destroy(siter
);
7021 scf_iter_destroy(sciter
);
7022 scf_iter_destroy(iter
);
7023 scf_instance_destroy(inst
);
7024 scf_service_destroy(svc
);
7030 * scf_encode32() is an implementation of Base32 encoding as described in
7031 * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
7032 * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648. The
7033 * input stream is divided into groups of 5 characters (40 bits). Each
7034 * group is encoded into 8 output characters where each output character
7035 * represents 5 bits of input.
7037 * If the input is not an even multiple of 5 characters, the output will be
7038 * padded so that the output is an even multiple of 8 characters. The
7039 * standard specifies that the pad character is '='. Unfortunately, '=' is
7040 * not a legal character in SMF property names. Thus, the caller can
7041 * specify an alternate pad character with the pad argument. If pad is 0,
7042 * scf_encode32() will use '='. Note that use of anything other than '='
7043 * produces output that is not in conformance with RFC 4648. It is
7044 * suitable, however, for internal use of SMF software. When the encoded
7045 * data is used as part of an SMF property name, SCF_ENCODE32_PAD should be
7046 * used as the pad character.
7049 * input - Address of the buffer to be encoded.
7050 * inlen - Number of characters at input.
7051 * output - Address of the buffer to receive the encoded data.
7052 * outmax - Size of the buffer at output.
7053 * outlen - If it is not NULL, outlen receives the number of
7054 * bytes placed in output.
7055 * pad - Alternate padding character.
7058 * 0 Buffer was successfully encoded.
7059 * -1 Indicates output buffer too small, or pad is one of the
7060 * standard encoding characters.
7063 scf_encode32(const char *input
, size_t inlen
, char *output
, size_t outmax
,
7064 size_t *outlen
, char pad
)
7066 uint_t group_size
= 5;
7068 const unsigned char *in
= (const unsigned char *)input
;
7070 uchar_t
*out
= (uchar_t
*)output
;
7074 /* Verify that there is enough room for the output. */
7075 olen
= ((inlen
+ (group_size
- 1)) / group_size
) * 8;
7081 /* If caller did not provide pad character, use the default. */
7086 * Make sure that caller's pad is not one of the encoding
7089 for (i
= 0; i
< sizeof (base32
) - 1; i
++) {
7090 if (pad
== base32
[i
])
7095 /* Process full groups capturing 5 bits per output character. */
7096 for (; inlen
>= group_size
; in
+= group_size
, inlen
-= group_size
) {
7098 * The comments in this section number the bits in an
7099 * 8 bit byte 0 to 7. The high order bit is bit 7 and
7100 * the low order bit is bit 0.
7103 /* top 5 bits (7-3) from in[0] */
7104 *out
++ = base32
[in
[0] >> 3];
7105 /* bits 2-0 from in[0] and top 2 (7-6) from in[1] */
7106 *out
++ = base32
[((in
[0] << 2) & 0x1c) | (in
[1] >> 6)];
7107 /* 5 bits (5-1) from in[1] */
7108 *out
++ = base32
[(in
[1] >> 1) & 0x1f];
7109 /* low bit (0) from in[1] and top 4 (7-4) from in[2] */
7110 *out
++ = base32
[((in
[1] << 4) & 0x10) | ((in
[2] >> 4) & 0xf)];
7111 /* low 4 (3-0) from in[2] and top bit (7) from in[3] */
7112 *out
++ = base32
[((in
[2] << 1) & 0x1e) | (in
[3] >> 7)];
7113 /* 5 bits (6-2) from in[3] */
7114 *out
++ = base32
[(in
[3] >> 2) & 0x1f];
7115 /* low 2 (1-0) from in[3] and top 3 (7-5) from in[4] */
7116 *out
++ = base32
[((in
[3] << 3) & 0x18) | (in
[4] >> 5)];
7117 /* low 5 (4-0) from in[4] */
7118 *out
++ = base32
[in
[4] & 0x1f];
7121 /* Take care of final input bytes. */
7124 /* top 5 bits (7-3) from in[0] */
7125 *out
++ = base32
[in
[0] >> 3];
7127 * low 3 (2-0) from in[0] and top 2 (7-6) from in[1] if
7130 oval
= (in
[0] << 2) & 0x1c;
7132 *out
++ = base32
[oval
];
7137 *out
++ = base32
[oval
];
7138 /* 5 bits (5-1) from in[1] */
7139 *out
++ = base32
[(in
[1] >> 1) & 0x1f];
7141 * low bit (0) from in[1] and top 4 (7-4) from in[2] if
7144 oval
= (in
[1] << 4) & 0x10;
7146 *out
++ = base32
[oval
];
7151 *out
++ = base32
[oval
];
7153 * low 4 (3-0) from in[2] and top 1 (7) from in[3] if
7156 oval
= (in
[2] << 1) & 0x1e;
7158 *out
++ = base32
[oval
];
7163 *out
++ = base32
[oval
];
7164 /* 5 bits (6-2) from in[3] */
7165 *out
++ = base32
[(in
[3] >> 2) & 0x1f];
7166 /* low 2 bits (1-0) from in[3] */
7167 *out
++ = base32
[(in
[3] << 3) & 0x18];
7172 * Pad the output so that it is a multiple of 8 bytes.
7174 for (; pad_count
> 0; pad_count
--) {
7179 * Null terminate the output if there is enough room.
7188 * scf_decode32() is an implementation of Base32 decoding as described in
7189 * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
7190 * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648. The
7191 * input stream is divided into groups of 8 encoded characters. Each
7192 * encoded character represents 5 bits of data. Thus, the 8 encoded
7193 * characters are used to produce 40 bits or 5 bytes of unencoded data in
7196 * If the encoder did not have enough data to generate a mulitple of 8
7197 * characters of encoded data, it used a pad character to get to the 8
7198 * character boundry. The standard specifies that the pad character is '='.
7199 * Unfortunately, '=' is not a legal character in SMF property names.
7200 * Thus, the caller can specify an alternate pad character with the pad
7201 * argument. If pad is 0, scf_decode32() will use '='. Note that use of
7202 * anything other than '=' is not in conformance with RFC 4648. It is
7203 * suitable, however, for internal use of SMF software. When the encoded
7204 * data is used in SMF property names, SCF_ENCODE32_PAD should be used as
7205 * the pad character.
7208 * in - Buffer of encoded characters.
7209 * inlen - Number of characters at in.
7210 * outbuf - Buffer to receive the decoded bytes. It can be the
7211 * same buffer as in.
7212 * outmax - Size of the buffer at outbuf.
7213 * outlen - If it is not NULL, outlen receives the number of
7214 * bytes placed in output.
7215 * pad - Alternate padding character.
7218 * 0 Buffer was successfully decoded.
7219 * -1 Indicates an invalid input character, output buffer too
7220 * small, or pad is one of the standard encoding characters.
7223 scf_decode32(const char *in
, size_t inlen
, char *outbuf
, size_t outmax
,
7224 size_t *outlen
, char pad
)
7226 char *bufend
= outbuf
+ outmax
;
7229 uint32_t g
[DECODE32_GS
];
7233 boolean_t pad_seen
= B_FALSE
;
7235 /* If caller did not provide pad character, use the default. */
7240 * Make sure that caller's pad is not one of the encoding
7243 for (i
= 0; i
< sizeof (base32
) - 1; i
++) {
7244 if (pad
== base32
[i
])
7250 while ((i
< inlen
) && (out
< bufend
)) {
7251 /* Get a group of input characters. */
7252 for (j
= 0, count
= 0;
7253 (j
< DECODE32_GS
) && (i
< inlen
);
7257 * RFC 4648 allows for the encoded data to be split
7258 * into multiple lines, so skip carriage returns
7261 if ((c
== '\r') || (c
== '\n'))
7263 if ((pad_seen
== B_TRUE
) && (c
!= pad
)) {
7264 /* Group not completed by pads */
7267 if ((c
< 0) || (c
>= sizeof (index32
))) {
7268 /* Illegal character. */
7275 if ((g
[j
++] = index32
[c
]) == 0xff) {
7276 /* Illegal character */
7282 /* Pack the group into five 8 bit bytes. */
7283 if ((count
>= 2) && (out
< bufend
)) {
7286 * 5 bits (7-3) from g[0]
7287 * 3 bits (2-0) from g[1] (4-2)
7289 *out
++ = (g
[0] << 3) | ((g
[1] >> 2) & 0x7);
7291 if ((count
>= 4) && (out
< bufend
)) {
7294 * 2 bits (7-6) from g[1] (1-0)
7295 * 5 bits (5-1) from g[2] (4-0)
7296 * 1 bit (0) from g[3] (4)
7298 *out
++ = (g
[1] << 6) | (g
[2] << 1) | \
7299 ((g
[3] >> 4) & 0x1);
7301 if ((count
>= 5) && (out
< bufend
)) {
7304 * 4 bits (7-4) from g[3] (3-0)
7305 * 4 bits (3-0) from g[4] (4-1)
7307 *out
++ = (g
[3] << 4) | ((g
[4] >> 1) & 0xf);
7309 if ((count
>= 7) && (out
< bufend
)) {
7312 * 1 bit (7) from g[4] (0)
7313 * 5 bits (6-2) from g[5] (4-0)
7314 * 2 bits (0-1) from g[6] (4-3)
7316 *out
++ = (g
[4] << 7) | (g
[5] << 2) |
7317 ((g
[6] >> 3) & 0x3);
7319 if ((count
== 8) && (out
< bufend
)) {
7322 * 3 bits (7-5) from g[6] (2-0)
7323 * 5 bits (4-0) from g[7] (4-0)
7325 *out
++ = (g
[6] << 5) | g
[7];
7329 /* Did not process all input characters. */
7333 *outlen
= out
- outbuf
;
7334 /* Null terminate the output if there is room. */
7342 * _scf_request_backup: a simple wrapper routine
7345 _scf_request_backup(scf_handle_t
*h
, const char *name
)
7347 struct rep_protocol_backup_request request
;
7348 struct rep_protocol_response response
;
7352 if (strlcpy(request
.rpr_name
, name
, sizeof (request
.rpr_name
)) >=
7353 sizeof (request
.rpr_name
))
7354 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
7356 (void) pthread_mutex_lock(&h
->rh_lock
);
7357 request
.rpr_request
= REP_PROTOCOL_BACKUP
;
7358 request
.rpr_changeid
= handle_next_changeid(h
);
7360 r
= make_door_call(h
, &request
, sizeof (request
),
7361 &response
, sizeof (response
));
7362 (void) pthread_mutex_unlock(&h
->rh_lock
);
7365 DOOR_ERRORS_BLOCK(r
);
7368 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
7369 return (scf_set_error(proto_error(response
.rpr_response
)));
7370 return (SCF_SUCCESS
);
7374 * Request svc.configd daemon to switch repository database.
7378 * _NOT_BOUND handle is not bound
7379 * _CONNECTION_BROKEN server is not reachable
7380 * _INTERNAL file operation error
7381 * the server response is too big
7382 * _PERMISSION_DENIED not enough privileges to do request
7383 * _BACKEND_READONLY backend is not writable
7384 * _BACKEND_ACCESS backend access fails
7385 * _NO_RESOURCES svc.configd is out of memory
7388 _scf_repository_switch(scf_handle_t
*h
, int scf_sw
)
7390 struct rep_protocol_switch_request request
;
7391 struct rep_protocol_response response
;
7395 * Setup request protocol and make door call
7396 * Hold rh_lock lock before handle_next_changeid call
7398 (void) pthread_mutex_lock(&h
->rh_lock
);
7400 request
.rpr_flag
= scf_sw
;
7401 request
.rpr_request
= REP_PROTOCOL_SWITCH
;
7402 request
.rpr_changeid
= handle_next_changeid(h
);
7404 r
= make_door_call(h
, &request
, sizeof (request
),
7405 &response
, sizeof (response
));
7407 (void) pthread_mutex_unlock(&h
->rh_lock
);
7410 DOOR_ERRORS_BLOCK(r
);
7414 * Pass protocol error up
7416 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
7417 return (scf_set_error(proto_error(response
.rpr_response
)));
7419 return (SCF_SUCCESS
);
7423 _scf_pg_is_read_protected(const scf_propertygroup_t
*pg
, boolean_t
*out
)
7425 char buf
[REP_PROTOCOL_NAME_LEN
];
7428 res
= datael_get_name(&pg
->rd_d
, buf
, sizeof (buf
),
7429 RP_ENTITY_NAME_PGREADPROT
);
7434 if (uu_strtouint(buf
, out
, sizeof (*out
), 0, 0, 1) == -1)
7435 return (scf_set_error(SCF_ERROR_INTERNAL
));
7436 return (SCF_SUCCESS
);
7440 * _scf_set_annotation: a wrapper to set the annotation fields for SMF
7441 * security auditing.
7443 * Fails with following in scf_error_key thread specific data:
7444 * _INVALID_ARGUMENT - operation or file too large
7446 * _CONNECTION_BROKEN
7451 _scf_set_annotation(scf_handle_t
*h
, const char *operation
, const char *file
)
7453 struct rep_protocol_annotation request
;
7454 struct rep_protocol_response response
;
7459 /* We can't do anything if the handle is destroyed. */
7460 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
7463 request
.rpr_request
= REP_PROTOCOL_SET_AUDIT_ANNOTATION
;
7464 copied
= strlcpy(request
.rpr_operation
,
7465 (operation
== NULL
) ? "" : operation
,
7466 sizeof (request
.rpr_operation
));
7467 if (copied
>= sizeof (request
.rpr_operation
))
7468 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
7470 copied
= strlcpy(request
.rpr_file
,
7471 (file
== NULL
) ? "" : file
,
7472 sizeof (request
.rpr_file
));
7473 if (copied
>= sizeof (request
.rpr_file
))
7474 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
7476 (void) pthread_mutex_lock(&h
->rh_lock
);
7477 r
= make_door_call(h
, &request
, sizeof (request
),
7478 &response
, sizeof (response
));
7479 (void) pthread_mutex_unlock(&h
->rh_lock
);
7482 DOOR_ERRORS_BLOCK(r
);
7485 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
7486 return (scf_set_error(proto_error(response
.rpr_response
)));