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.
30 * This is the main implementation file for the low-level repository
34 #include "lowlevel_impl.h"
36 #include "repcache_protocol.h"
54 #include <sys/sysmacros.h>
55 #include <libzonecfg.h>
59 #define ENV_SCF_DEBUG "LIBSCF_DEBUG"
60 #define ENV_SCF_DOORPATH "LIBSCF_DOORPATH"
62 static uint32_t default_debug
= 0;
63 static const char *default_door_path
= REPOSITORY_DOOR_NAME
;
65 #define CALL_FAILED -1
66 #define RESULT_TOO_BIG -2
69 static pthread_mutex_t lowlevel_init_lock
;
70 static int32_t lowlevel_inited
;
72 static uu_list_pool_t
*tran_entry_pool
;
73 static uu_list_pool_t
*datael_pool
;
74 static uu_list_pool_t
*iter_pool
;
77 * base32[] index32[] are used in base32 encoding and decoding.
79 static char base32
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
80 static char index32
[128] = {
81 -1, -1, -1, -1, -1, -1, -1, -1, /* 0-7 */
82 -1, -1, -1, -1, -1, -1, -1, -1, /* 8-15 */
83 -1, -1, -1, -1, -1, -1, -1, -1, /* 16-23 */
84 -1, -1, -1, -1, -1, -1, -1, -1, /* 24-31 */
85 -1, -1, -1, -1, -1, -1, -1, -1, /* 32-39 */
86 -1, -1, -1, -1, -1, -1, -1, -1, /* 40-47 */
87 -1, -1, 26, 27, 28, 29, 30, 31, /* 48-55 */
88 -1, -1, -1, -1, -1, -1, -1, -1, /* 56-63 */
89 -1, 0, 1, 2, 3, 4, 5, 6, /* 64-71 */
90 7, 8, 9, 10, 11, 12, 13, 14, /* 72-79 */
91 15, 16, 17, 18, 19, 20, 21, 22, /* 80-87 */
92 23, 24, 25, -1, -1, -1, -1, -1, /* 88-95 */
93 -1, -1, -1, -1, -1, -1, -1, -1, /* 96-103 */
94 -1, -1, -1, -1, -1, -1, -1, -1, /* 104-111 */
95 -1, -1, -1, -1, -1, -1, -1, -1, /* 112-119 */
96 -1, -1, -1, -1, -1, -1, -1, -1 /* 120-127 */
99 #define DECODE32_GS (8) /* scf_decode32 group size */
101 #define assert_nolint(x) assert(x)
103 static void scf_iter_reset_locked(scf_iter_t
*iter
);
104 static void scf_value_reset_locked(scf_value_t
*val
, int and_destroy
);
106 #define TYPE_VALUE (-100)
109 * Hold and release subhandles. We only allow one thread access to the
110 * subhandles at a time, and it can use any subset, grabbing and releasing
111 * them in any order. The only restrictions are that you cannot hold an
112 * already-held subhandle, and all subhandles must be released before
113 * returning to the original caller.
116 handle_hold_subhandles(scf_handle_t
*h
, int mask
)
118 assert(mask
!= 0 && (mask
& ~RH_HOLD_ALL
) == 0);
120 (void) pthread_mutex_lock(&h
->rh_lock
);
121 while (h
->rh_hold_flags
!= 0 && h
->rh_holder
!= pthread_self()) {
124 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
,
126 (void) pthread_cond_wait(&h
->rh_cv
, &h
->rh_lock
);
127 (void) pthread_setcancelstate(cancel_state
, NULL
);
129 if (h
->rh_hold_flags
== 0)
130 h
->rh_holder
= pthread_self();
131 assert(!(h
->rh_hold_flags
& mask
));
132 h
->rh_hold_flags
|= mask
;
133 (void) pthread_mutex_unlock(&h
->rh_lock
);
137 handle_rele_subhandles(scf_handle_t
*h
, int mask
)
139 assert(mask
!= 0 && (mask
& ~RH_HOLD_ALL
) == 0);
141 (void) pthread_mutex_lock(&h
->rh_lock
);
142 assert(h
->rh_holder
== pthread_self());
143 assert((h
->rh_hold_flags
& mask
));
145 h
->rh_hold_flags
&= ~mask
;
146 if (h
->rh_hold_flags
== 0)
147 (void) pthread_cond_signal(&h
->rh_cv
);
148 (void) pthread_mutex_unlock(&h
->rh_lock
);
151 #define HOLD_HANDLE(h, flag, field) \
152 (handle_hold_subhandles((h), (flag)), (h)->field)
154 #define RELE_HANDLE(h, flag) \
155 (handle_rele_subhandles((h), (flag)))
158 * convenience macros, for functions that only need a one or two handles at
161 #define HANDLE_HOLD_ITER(h) HOLD_HANDLE((h), RH_HOLD_ITER, rh_iter)
162 #define HANDLE_HOLD_SCOPE(h) HOLD_HANDLE((h), RH_HOLD_SCOPE, rh_scope)
163 #define HANDLE_HOLD_SERVICE(h) HOLD_HANDLE((h), RH_HOLD_SERVICE, rh_service)
164 #define HANDLE_HOLD_INSTANCE(h) HOLD_HANDLE((h), RH_HOLD_INSTANCE, rh_instance)
165 #define HANDLE_HOLD_SNAPSHOT(h) HOLD_HANDLE((h), RH_HOLD_SNAPSHOT, rh_snapshot)
166 #define HANDLE_HOLD_SNAPLVL(h) HOLD_HANDLE((h), RH_HOLD_SNAPLVL, rh_snaplvl)
167 #define HANDLE_HOLD_PG(h) HOLD_HANDLE((h), RH_HOLD_PG, rh_pg)
168 #define HANDLE_HOLD_PROPERTY(h) HOLD_HANDLE((h), RH_HOLD_PROPERTY, rh_property)
169 #define HANDLE_HOLD_VALUE(h) HOLD_HANDLE((h), RH_HOLD_VALUE, rh_value)
171 #define HANDLE_RELE_ITER(h) RELE_HANDLE((h), RH_HOLD_ITER)
172 #define HANDLE_RELE_SCOPE(h) RELE_HANDLE((h), RH_HOLD_SCOPE)
173 #define HANDLE_RELE_SERVICE(h) RELE_HANDLE((h), RH_HOLD_SERVICE)
174 #define HANDLE_RELE_INSTANCE(h) RELE_HANDLE((h), RH_HOLD_INSTANCE)
175 #define HANDLE_RELE_SNAPSHOT(h) RELE_HANDLE((h), RH_HOLD_SNAPSHOT)
176 #define HANDLE_RELE_SNAPLVL(h) RELE_HANDLE((h), RH_HOLD_SNAPLVL)
177 #define HANDLE_RELE_PG(h) RELE_HANDLE((h), RH_HOLD_PG)
178 #define HANDLE_RELE_PROPERTY(h) RELE_HANDLE((h), RH_HOLD_PROPERTY)
179 #define HANDLE_RELE_VALUE(h) RELE_HANDLE((h), RH_HOLD_VALUE)
183 transaction_entry_compare(const void *l_arg
, const void *r_arg
, void *private)
186 ((scf_transaction_entry_t
*)l_arg
)->entry_property
;
188 ((scf_transaction_entry_t
*)r_arg
)->entry_property
;
192 ret
= strcmp(l_prop
, r_prop
);
201 datael_compare(const void *l_arg
, const void *r_arg
, void *private)
203 uint32_t l_id
= ((scf_datael_t
*)l_arg
)->rd_entity
;
204 uint32_t r_id
= (r_arg
!= NULL
) ? ((scf_datael_t
*)r_arg
)->rd_entity
:
205 *(uint32_t *)private;
215 iter_compare(const void *l_arg
, const void *r_arg
, void *private)
217 uint32_t l_id
= ((scf_iter_t
*)l_arg
)->iter_id
;
218 uint32_t r_id
= (r_arg
!= NULL
) ? ((scf_iter_t
*)r_arg
)->iter_id
:
219 *(uint32_t *)private;
232 const char *door_path
;
234 (void) pthread_mutex_lock(&lowlevel_init_lock
);
235 if (lowlevel_inited
== 0) {
237 (debug
= getenv(ENV_SCF_DEBUG
)) != NULL
&& debug
[0] != 0 &&
238 uu_strtoint(debug
, &default_debug
, sizeof (default_debug
),
240 (void) fprintf(stderr
, "LIBSCF: $%s (%s): %s",
241 ENV_SCF_DEBUG
, debug
,
242 uu_strerror(uu_error()));
246 (door_path
= getenv(ENV_SCF_DOORPATH
)) != NULL
&&
248 default_door_path
= strdup(door_path
);
249 if (default_door_path
== NULL
)
250 default_door_path
= door_path
;
253 datael_pool
= uu_list_pool_create("SUNW,libscf_datael",
254 sizeof (scf_datael_t
), offsetof(scf_datael_t
, rd_node
),
255 datael_compare
, UU_LIST_POOL_DEBUG
);
257 iter_pool
= uu_list_pool_create("SUNW,libscf_iter",
258 sizeof (scf_iter_t
), offsetof(scf_iter_t
, iter_node
),
259 iter_compare
, UU_LIST_POOL_DEBUG
);
261 assert_nolint(offsetof(scf_transaction_entry_t
,
262 entry_property
) == 0);
263 tran_entry_pool
= uu_list_pool_create(
264 "SUNW,libscf_transaction_entity",
265 sizeof (scf_transaction_entry_t
),
266 offsetof(scf_transaction_entry_t
, entry_link
),
267 transaction_entry_compare
, UU_LIST_POOL_DEBUG
);
269 if (datael_pool
== NULL
|| iter_pool
== NULL
||
270 tran_entry_pool
== NULL
) {
271 lowlevel_inited
= -1;
275 if (!scf_setup_error()) {
276 lowlevel_inited
= -1;
282 (void) pthread_mutex_unlock(&lowlevel_init_lock
);
283 if (lowlevel_inited
> 0)
288 static const struct {
290 rep_protocol_value_type_t ti_proto_type
;
292 } scf_type_info
[] = {
293 {SCF_TYPE_BOOLEAN
, REP_PROTOCOL_TYPE_BOOLEAN
,
294 SCF_TYPE_STRING_BOOLEAN
},
295 {SCF_TYPE_COUNT
, REP_PROTOCOL_TYPE_COUNT
,
296 SCF_TYPE_STRING_COUNT
},
297 {SCF_TYPE_INTEGER
, REP_PROTOCOL_TYPE_INTEGER
,
298 SCF_TYPE_STRING_INTEGER
},
299 {SCF_TYPE_TIME
, REP_PROTOCOL_TYPE_TIME
,
300 SCF_TYPE_STRING_TIME
},
301 {SCF_TYPE_ASTRING
, REP_PROTOCOL_TYPE_STRING
,
302 SCF_TYPE_STRING_ASTRING
},
303 {SCF_TYPE_OPAQUE
, REP_PROTOCOL_TYPE_OPAQUE
,
304 SCF_TYPE_STRING_OPAQUE
},
305 {SCF_TYPE_USTRING
, REP_PROTOCOL_SUBTYPE_USTRING
,
306 SCF_TYPE_STRING_USTRING
},
307 {SCF_TYPE_URI
, REP_PROTOCOL_SUBTYPE_URI
,
308 SCF_TYPE_STRING_URI
},
309 {SCF_TYPE_FMRI
, REP_PROTOCOL_SUBTYPE_FMRI
,
310 SCF_TYPE_STRING_FMRI
},
311 {SCF_TYPE_HOST
, REP_PROTOCOL_SUBTYPE_HOST
,
312 SCF_TYPE_STRING_HOST
},
313 {SCF_TYPE_HOSTNAME
, REP_PROTOCOL_SUBTYPE_HOSTNAME
,
314 SCF_TYPE_STRING_HOSTNAME
},
315 {SCF_TYPE_NET_ADDR
, REP_PROTOCOL_SUBTYPE_NETADDR
,
316 SCF_TYPE_STRING_NET_ADDR
},
317 {SCF_TYPE_NET_ADDR_V4
, REP_PROTOCOL_SUBTYPE_NETADDR_V4
,
318 SCF_TYPE_STRING_NET_ADDR_V4
},
319 {SCF_TYPE_NET_ADDR_V6
, REP_PROTOCOL_SUBTYPE_NETADDR_V6
,
320 SCF_TYPE_STRING_NET_ADDR_V6
}
323 #define SCF_TYPE_INFO_COUNT (sizeof (scf_type_info) / sizeof (*scf_type_info))
324 static rep_protocol_value_type_t
325 scf_type_to_protocol_type(scf_type_t t
)
329 for (i
= 0; i
< SCF_TYPE_INFO_COUNT
; i
++)
330 if (scf_type_info
[i
].ti_type
== t
)
331 return (scf_type_info
[i
].ti_proto_type
);
333 return (REP_PROTOCOL_TYPE_INVALID
);
337 scf_protocol_type_to_type(rep_protocol_value_type_t t
)
341 for (i
= 0; i
< SCF_TYPE_INFO_COUNT
; i
++)
342 if (scf_type_info
[i
].ti_proto_type
== t
)
343 return (scf_type_info
[i
].ti_type
);
345 return (SCF_TYPE_INVALID
);
349 scf_type_to_string(scf_type_t ty
)
353 for (i
= 0; i
< SCF_TYPE_INFO_COUNT
; i
++)
354 if (scf_type_info
[i
].ti_type
== ty
)
355 return (scf_type_info
[i
].ti_name
);
361 scf_string_to_type(const char *name
)
365 for (i
= 0; i
< sizeof (scf_type_info
) / sizeof (*scf_type_info
); i
++)
366 if (strcmp(scf_type_info
[i
].ti_name
, name
) == 0)
367 return (scf_type_info
[i
].ti_type
);
369 return (SCF_TYPE_INVALID
);
373 scf_type_base_type(scf_type_t type
, scf_type_t
*out
)
375 rep_protocol_value_type_t t
= scf_type_to_protocol_type(type
);
376 if (t
== REP_PROTOCOL_TYPE_INVALID
)
377 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
379 *out
= scf_protocol_type_to_type(scf_proto_underlying_type(t
));
380 return (SCF_SUCCESS
);
384 * Convert a protocol error code into an SCF_ERROR_* code.
387 proto_error(rep_protocol_responseid_t e
)
390 case REP_PROTOCOL_FAIL_MISORDERED
:
391 case REP_PROTOCOL_FAIL_UNKNOWN_ID
:
392 case REP_PROTOCOL_FAIL_INVALID_TYPE
:
393 case REP_PROTOCOL_FAIL_TRUNCATED
:
394 case REP_PROTOCOL_FAIL_TYPE_MISMATCH
:
395 case REP_PROTOCOL_FAIL_NOT_APPLICABLE
:
396 case REP_PROTOCOL_FAIL_UNKNOWN
:
397 return (SCF_ERROR_INTERNAL
);
399 case REP_PROTOCOL_FAIL_BAD_TX
:
400 return (SCF_ERROR_INVALID_ARGUMENT
);
401 case REP_PROTOCOL_FAIL_BAD_REQUEST
:
402 return (SCF_ERROR_INVALID_ARGUMENT
);
403 case REP_PROTOCOL_FAIL_NO_RESOURCES
:
404 return (SCF_ERROR_NO_RESOURCES
);
405 case REP_PROTOCOL_FAIL_NOT_FOUND
:
406 return (SCF_ERROR_NOT_FOUND
);
407 case REP_PROTOCOL_FAIL_DELETED
:
408 return (SCF_ERROR_DELETED
);
409 case REP_PROTOCOL_FAIL_NOT_SET
:
410 return (SCF_ERROR_NOT_SET
);
411 case REP_PROTOCOL_FAIL_EXISTS
:
412 return (SCF_ERROR_EXISTS
);
413 case REP_PROTOCOL_FAIL_DUPLICATE_ID
:
414 return (SCF_ERROR_EXISTS
);
415 case REP_PROTOCOL_FAIL_PERMISSION_DENIED
:
416 return (SCF_ERROR_PERMISSION_DENIED
);
417 case REP_PROTOCOL_FAIL_BACKEND_ACCESS
:
418 return (SCF_ERROR_BACKEND_ACCESS
);
419 case REP_PROTOCOL_FAIL_BACKEND_READONLY
:
420 return (SCF_ERROR_BACKEND_READONLY
);
422 case REP_PROTOCOL_SUCCESS
:
423 case REP_PROTOCOL_DONE
:
424 case REP_PROTOCOL_FAIL_NOT_LATEST
: /* TX code should handle this */
427 uu_warn("%s:%d: Bad error code %d passed to proto_error().\n",
428 __FILE__
, __LINE__
, e
);
436 scf_limit(uint32_t limit
)
439 case SCF_LIMIT_MAX_NAME_LENGTH
:
440 case SCF_LIMIT_MAX_PG_TYPE_LENGTH
:
441 return (REP_PROTOCOL_NAME_LEN
- 1);
442 case SCF_LIMIT_MAX_VALUE_LENGTH
:
443 return (REP_PROTOCOL_VALUE_LEN
- 1);
444 case SCF_LIMIT_MAX_FMRI_LENGTH
:
445 return (SCF_FMRI_PREFIX_MAX_LEN
+
446 sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1 +
447 sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1 +
448 sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1 +
449 sizeof (SCF_FMRI_INSTANCE_PREFIX
) - 1 +
450 sizeof (SCF_FMRI_PROPERTYGRP_PREFIX
) - 1 +
451 sizeof (SCF_FMRI_PROPERTY_PREFIX
) - 1 +
452 5 * (REP_PROTOCOL_NAME_LEN
- 1));
454 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
459 scf_opaque_decode(char *out_arg
, const char *in
, size_t max_out
)
464 while (max_out
> 0 && (a
= in
[0]) != 0 && (b
= in
[1]) != 0) {
467 if (a
>= '0' && a
<= '9')
469 else if (a
>= 'a' && a
<= 'f')
471 else if (a
>= 'A' && a
<= 'F')
476 if (b
>= '0' && b
<= '9')
478 else if (b
>= 'a' && b
<= 'f')
480 else if (b
>= 'A' && b
<= 'F')
485 *out
++ = (a
<< 4) | b
;
489 return (out
- out_arg
);
493 scf_opaque_encode(char *out_arg
, const char *in_arg
, size_t in_sz
)
495 uint8_t *in
= (uint8_t *)in_arg
;
496 uint8_t *end
= in
+ in_sz
;
505 uint8_t a
= (c
& 0xf0) >> 4;
506 uint8_t b
= (c
& 0x0f);
511 *out
++ = a
+ 'a' - 10;
516 *out
++ = b
+ 'a' - 10;
521 return (out
- out_arg
);
525 handle_do_close(scf_handle_t
*h
)
527 assert(MUTEX_HELD(&h
->rh_lock
));
528 assert(h
->rh_doorfd
!= -1);
531 * if there are any active FD users, we just move the FD over
532 * to rh_doorfd_old -- they'll close it when they finish.
534 if (h
->rh_fd_users
> 0) {
535 h
->rh_doorfd_old
= h
->rh_doorfd
;
538 assert(h
->rh_doorfd_old
== -1);
539 (void) close(h
->rh_doorfd
);
545 * Check if a handle is currently bound. fork()ing implicitly unbinds
546 * the handle in the child.
549 handle_is_bound(scf_handle_t
*h
)
551 assert(MUTEX_HELD(&h
->rh_lock
));
553 if (h
->rh_doorfd
== -1)
556 if (getpid() == h
->rh_doorpid
)
559 /* forked since our last bind -- initiate handle close */
565 handle_has_server_locked(scf_handle_t
*h
)
568 assert(MUTEX_HELD(&h
->rh_lock
));
570 return (handle_is_bound(h
) && door_info(h
->rh_doorfd
, &i
) != -1 &&
575 handle_has_server(scf_handle_t
*h
)
579 (void) pthread_mutex_lock(&h
->rh_lock
);
580 ret
= handle_has_server_locked(h
);
581 (void) pthread_mutex_unlock(&h
->rh_lock
);
587 * This makes a door request on the client door associated with handle h.
588 * It will automatically retry calls which fail on EINTR. If h is not bound,
589 * returns NOT_BOUND. If the door call fails or the server response is too
590 * small, returns CALL_FAILED. If the server response is too big, truncates the
591 * response and returns RESULT_TOO_BIG. Otherwise, the size of the result is
595 make_door_call(scf_handle_t
*h
, const void *req
, size_t req_sz
,
596 void *res
, size_t res_sz
)
601 assert(MUTEX_HELD(&h
->rh_lock
));
603 if (!handle_is_bound(h
)) {
607 arg
.data_ptr
= (void *)req
;
608 arg
.data_size
= req_sz
;
614 while ((r
= door_call(h
->rh_doorfd
, &arg
)) < 0) {
620 return (CALL_FAILED
);
623 if (arg
.desc_num
> 0) {
624 while (arg
.desc_num
> 0) {
625 if (arg
.desc_ptr
->d_attributes
& DOOR_DESCRIPTOR
) {
626 int cfd
= arg
.desc_ptr
->d_data
.d_desc
.d_id
;
633 if (arg
.data_ptr
!= res
&& arg
.data_size
> 0)
634 (void) memmove(res
, arg
.data_ptr
, MIN(arg
.data_size
, res_sz
));
637 (void) munmap(arg
.rbuf
, arg
.rsize
);
639 if (arg
.data_size
> res_sz
)
640 return (RESULT_TOO_BIG
);
642 if (arg
.data_size
< sizeof (uint32_t))
643 return (CALL_FAILED
);
645 return (arg
.data_size
);
649 * Should only be used when r < 0.
651 #define DOOR_ERRORS_BLOCK(r) { \
654 return (scf_set_error(SCF_ERROR_NOT_BOUND)); \
657 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN)); \
659 case RESULT_TOO_BIG: \
660 return (scf_set_error(SCF_ERROR_INTERNAL)); \
663 assert(r == NOT_BOUND || r == CALL_FAILED || \
664 r == RESULT_TOO_BIG); \
670 * Like make_door_call(), but takes an fd instead of a handle, and expects
671 * a single file descriptor, returned via res_fd.
673 * If no file descriptor is returned, *res_fd == -1.
676 make_door_call_retfd(int fd
, const void *req
, size_t req_sz
, void *res
,
677 size_t res_sz
, int *res_fd
)
688 arg
.data_ptr
= (void *)req
;
689 arg
.data_size
= req_sz
;
693 arg
.rsize
= sizeof (rbuf
);
695 while ((r
= door_call(fd
, &arg
)) < 0) {
701 return (CALL_FAILED
);
703 if (arg
.desc_num
> 1) {
704 while (arg
.desc_num
> 0) {
705 if (arg
.desc_ptr
->d_attributes
& DOOR_DESCRIPTOR
) {
707 arg
.desc_ptr
->d_data
.d_desc
.d_descriptor
;
714 if (arg
.desc_num
== 1 && arg
.desc_ptr
->d_attributes
& DOOR_DESCRIPTOR
)
715 *res_fd
= arg
.desc_ptr
->d_data
.d_desc
.d_descriptor
;
717 if (arg
.data_size
> 0)
718 (void) memmove(res
, arg
.data_ptr
, MIN(arg
.data_size
, res_sz
));
720 if (arg
.rbuf
!= rbuf
)
721 (void) munmap(arg
.rbuf
, arg
.rsize
);
723 if (arg
.data_size
> res_sz
)
724 return (RESULT_TOO_BIG
);
726 if (arg
.data_size
< sizeof (uint32_t))
727 return (CALL_FAILED
);
729 return (arg
.data_size
);
738 scf_handle_create(scf_version_t v
)
744 * This will need to be revisited when we bump SCF_VERSION
746 if (v
!= SCF_VERSION
) {
747 (void) scf_set_error(SCF_ERROR_VERSION_MISMATCH
);
751 if (!lowlevel_init()) {
752 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
756 ret
= uu_zalloc(sizeof (*ret
));
758 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
762 ret
->rh_dataels
= uu_list_create(datael_pool
, ret
, 0);
763 ret
->rh_iters
= uu_list_create(iter_pool
, ret
, 0);
764 if (ret
->rh_dataels
== NULL
|| ret
->rh_iters
== NULL
) {
765 if (ret
->rh_dataels
!= NULL
)
766 uu_list_destroy(ret
->rh_dataels
);
767 if (ret
->rh_iters
!= NULL
)
768 uu_list_destroy(ret
->rh_iters
);
770 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
775 ret
->rh_doorfd_old
= -1;
776 (void) pthread_mutex_init(&ret
->rh_lock
, NULL
);
778 handle_hold_subhandles(ret
, RH_HOLD_ALL
);
780 failed
= ((ret
->rh_iter
= scf_iter_create(ret
)) == NULL
||
781 (ret
->rh_scope
= scf_scope_create(ret
)) == NULL
||
782 (ret
->rh_service
= scf_service_create(ret
)) == NULL
||
783 (ret
->rh_instance
= scf_instance_create(ret
)) == NULL
||
784 (ret
->rh_snapshot
= scf_snapshot_create(ret
)) == NULL
||
785 (ret
->rh_snaplvl
= scf_snaplevel_create(ret
)) == NULL
||
786 (ret
->rh_pg
= scf_pg_create(ret
)) == NULL
||
787 (ret
->rh_property
= scf_property_create(ret
)) == NULL
||
788 (ret
->rh_value
= scf_value_create(ret
)) == NULL
);
791 * these subhandles count as internal references, not external ones.
793 ret
->rh_intrefs
= ret
->rh_extrefs
;
795 handle_rele_subhandles(ret
, RH_HOLD_ALL
);
798 scf_handle_destroy(ret
);
799 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
803 scf_value_set_count(ret
->rh_value
, default_debug
);
804 (void) scf_handle_decorate(ret
, "debug", ret
->rh_value
);
812 * _NO_SERVER - server door could not be open()ed
815 * _VERSION_MISMATCH - server returned bad file descriptor
816 * server claimed bad request
817 * server reported version mismatch
818 * server refused with unknown reason
820 * _NO_RESOURCES - server is out of memory
822 * _INTERNAL - could not set up entities or iters
823 * server response too big
826 _scf_handle_create_and_bind(scf_version_t ver
)
830 h
= scf_handle_create(ver
);
834 if (scf_handle_bind(h
) == -1) {
835 scf_handle_destroy(h
);
842 scf_handle_decorate(scf_handle_t
*handle
, const char *name
, scf_value_t
*v
)
844 if (v
!= SCF_DECORATE_CLEAR
&& handle
!= v
->value_handle
)
845 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
847 (void) pthread_mutex_lock(&handle
->rh_lock
);
848 if (handle_is_bound(handle
)) {
849 (void) pthread_mutex_unlock(&handle
->rh_lock
);
850 return (scf_set_error(SCF_ERROR_IN_USE
));
852 (void) pthread_mutex_unlock(&handle
->rh_lock
);
854 if (strcmp(name
, "debug") == 0) {
855 if (v
== SCF_DECORATE_CLEAR
) {
856 (void) pthread_mutex_lock(&handle
->rh_lock
);
857 handle
->rh_debug
= 0;
858 (void) pthread_mutex_unlock(&handle
->rh_lock
);
861 if (scf_value_get_count(v
, &val
) < 0)
862 return (-1); /* error already set */
864 (void) pthread_mutex_lock(&handle
->rh_lock
);
865 handle
->rh_debug
= (uid_t
)val
;
866 (void) pthread_mutex_unlock(&handle
->rh_lock
);
870 if (strcmp(name
, "door_path") == 0) {
871 char name
[sizeof (handle
->rh_doorpath
)];
873 if (v
== SCF_DECORATE_CLEAR
) {
874 (void) pthread_mutex_lock(&handle
->rh_lock
);
875 handle
->rh_doorpath
[0] = 0;
876 (void) pthread_mutex_unlock(&handle
->rh_lock
);
880 if ((len
= scf_value_get_astring(v
, name
,
881 sizeof (name
))) < 0) {
882 return (-1); /* error already set */
884 if (len
== 0 || len
>= sizeof (name
)) {
885 return (scf_set_error(
886 SCF_ERROR_INVALID_ARGUMENT
));
888 (void) pthread_mutex_lock(&handle
->rh_lock
);
889 (void) strlcpy(handle
->rh_doorpath
, name
,
890 sizeof (handle
->rh_doorpath
));
891 (void) pthread_mutex_unlock(&handle
->rh_lock
);
896 if (strcmp(name
, "zone") == 0) {
897 char zone
[MAXPATHLEN
], root
[MAXPATHLEN
], door
[MAXPATHLEN
];
898 static int (*zone_get_rootpath
)(char *, char *, size_t);
902 * In order to be able to set the zone on a handle, we want
903 * to determine the zone's path, which requires us to call into
904 * libzonecfg -- but libzonecfg.so links against libscf.so so
905 * we must not explicitly link to it. To circumvent the
906 * circular dependency, we will pull it in here via dlopen().
908 if (zone_get_rootpath
== NULL
) {
909 void *dl
= dlopen("libzonecfg.so.1", RTLD_LAZY
), *sym
;
912 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
914 if ((sym
= dlsym(dl
, "zone_get_rootpath")) == NULL
) {
916 return (scf_set_error(SCF_ERROR_INTERNAL
));
919 zone_get_rootpath
= (int(*)(char *, char *, size_t))sym
;
922 if (v
== SCF_DECORATE_CLEAR
) {
923 (void) pthread_mutex_lock(&handle
->rh_lock
);
924 handle
->rh_doorpath
[0] = 0;
925 (void) pthread_mutex_unlock(&handle
->rh_lock
);
930 if ((len
= scf_value_get_astring(v
, zone
, sizeof (zone
))) < 0)
933 if (len
== 0 || len
>= sizeof (zone
))
934 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
936 if (zone_get_rootpath(zone
, root
, sizeof (root
)) != Z_OK
) {
937 if (strcmp(zone
, GLOBAL_ZONENAME
) == 0) {
940 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
944 if (snprintf(door
, sizeof (door
), "%s/%s", root
,
945 default_door_path
) >= sizeof (door
))
946 return (scf_set_error(SCF_ERROR_INTERNAL
));
948 (void) pthread_mutex_lock(&handle
->rh_lock
);
949 (void) strlcpy(handle
->rh_doorpath
, door
,
950 sizeof (handle
->rh_doorpath
));
951 (void) pthread_mutex_unlock(&handle
->rh_lock
);
956 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
960 * fails with INVALID_ARGUMENT and HANDLE_MISMATCH.
963 _scf_handle_decorations(scf_handle_t
*handle
, scf_decoration_func
*f
,
964 scf_value_t
*v
, void *data
)
966 scf_decoration_info_t i
;
967 char name
[sizeof (handle
->rh_doorpath
)];
970 if (f
== NULL
|| v
== NULL
)
971 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
973 if (v
->value_handle
!= handle
)
974 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
976 i
.sdi_name
= (const char *)"debug";
977 i
.sdi_type
= SCF_TYPE_COUNT
;
978 (void) pthread_mutex_lock(&handle
->rh_lock
);
979 debug
= handle
->rh_debug
;
980 (void) pthread_mutex_unlock(&handle
->rh_lock
);
982 scf_value_set_count(v
, debug
);
985 i
.sdi_value
= SCF_DECORATE_CLEAR
;
988 if ((*f
)(&i
, data
) == 0)
991 i
.sdi_name
= (const char *)"door_path";
992 i
.sdi_type
= SCF_TYPE_ASTRING
;
993 (void) pthread_mutex_lock(&handle
->rh_lock
);
994 (void) strlcpy(name
, handle
->rh_doorpath
, sizeof (name
));
995 (void) pthread_mutex_unlock(&handle
->rh_lock
);
997 (void) scf_value_set_astring(v
, name
);
1000 i
.sdi_value
= SCF_DECORATE_CLEAR
;
1003 if ((*f
)(&i
, data
) == 0)
1010 * Fails if handle is not bound.
1013 handle_unbind_unlocked(scf_handle_t
*handle
)
1015 rep_protocol_request_t request
;
1016 rep_protocol_response_t response
;
1018 if (!handle_is_bound(handle
))
1021 request
.rpr_request
= REP_PROTOCOL_CLOSE
;
1023 (void) make_door_call(handle
, &request
, sizeof (request
),
1024 &response
, sizeof (response
));
1026 handle_do_close(handle
);
1028 return (SCF_SUCCESS
);
1033 * _HANDLE_DESTROYED - dp's handle has been destroyed
1034 * _INTERNAL - server response too big
1035 * entity already set up with different type
1036 * _NO_RESOURCES - server out of memory
1039 datael_attach(scf_datael_t
*dp
)
1041 scf_handle_t
*h
= dp
->rd_handle
;
1043 struct rep_protocol_entity_setup request
;
1044 rep_protocol_response_t response
;
1047 assert(MUTEX_HELD(&h
->rh_lock
));
1049 dp
->rd_reset
= 0; /* setup implicitly resets */
1051 if (h
->rh_flags
& HANDLE_DEAD
)
1052 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
1054 if (!handle_is_bound(h
))
1055 return (SCF_SUCCESS
); /* nothing to do */
1057 request
.rpr_request
= REP_PROTOCOL_ENTITY_SETUP
;
1058 request
.rpr_entityid
= dp
->rd_entity
;
1059 request
.rpr_entitytype
= dp
->rd_type
;
1061 r
= make_door_call(h
, &request
, sizeof (request
),
1062 &response
, sizeof (response
));
1064 if (r
== NOT_BOUND
|| r
== CALL_FAILED
)
1065 return (SCF_SUCCESS
);
1066 if (r
== RESULT_TOO_BIG
)
1067 return (scf_set_error(SCF_ERROR_INTERNAL
));
1069 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1070 return (scf_set_error(proto_error(response
.rpr_response
)));
1072 return (SCF_SUCCESS
);
1077 * _HANDLE_DESTROYED - iter's handle has been destroyed
1078 * _INTERNAL - server response too big
1079 * iter already existed
1083 iter_attach(scf_iter_t
*iter
)
1085 scf_handle_t
*h
= iter
->iter_handle
;
1086 struct rep_protocol_iter_request request
;
1087 struct rep_protocol_response response
;
1090 assert(MUTEX_HELD(&h
->rh_lock
));
1092 if (h
->rh_flags
& HANDLE_DEAD
)
1093 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
1095 if (!handle_is_bound(h
))
1096 return (SCF_SUCCESS
); /* nothing to do */
1098 request
.rpr_request
= REP_PROTOCOL_ITER_SETUP
;
1099 request
.rpr_iterid
= iter
->iter_id
;
1101 r
= make_door_call(h
, &request
, sizeof (request
),
1102 &response
, sizeof (response
));
1104 if (r
== NOT_BOUND
|| r
== CALL_FAILED
)
1105 return (SCF_SUCCESS
);
1106 if (r
== RESULT_TOO_BIG
)
1107 return (scf_set_error(SCF_ERROR_INTERNAL
));
1109 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1110 return (scf_set_error(proto_error(response
.rpr_response
)));
1112 return (SCF_SUCCESS
);
1117 * _IN_USE - handle already bound
1118 * _NO_SERVER - server door could not be open()ed
1120 * door_info() failed
1121 * _VERSION_MISMATCH - server returned bad file descriptor
1122 * server claimed bad request
1123 * server reported version mismatch
1124 * server refused with unknown reason
1126 * _NO_RESOURCES - server is out of memory
1127 * _PERMISSION_DENIED
1128 * _INTERNAL - could not set up entities or iters
1129 * server response too big
1131 * perhaps this should try multiple times.
1134 scf_handle_bind(scf_handle_t
*handle
)
1143 repository_door_request_t request
;
1144 repository_door_response_t response
;
1145 const char *door_name
= default_door_path
;
1147 (void) pthread_mutex_lock(&handle
->rh_lock
);
1148 if (handle_is_bound(handle
)) {
1149 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1150 return (scf_set_error(SCF_ERROR_IN_USE
));
1153 /* wait until any active fd users have cleared out */
1154 while (handle
->rh_fd_users
> 0) {
1157 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
,
1159 (void) pthread_cond_wait(&handle
->rh_cv
, &handle
->rh_lock
);
1160 (void) pthread_setcancelstate(cancel_state
, NULL
);
1163 /* check again, since we had to drop the lock */
1164 if (handle_is_bound(handle
)) {
1165 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1166 return (scf_set_error(SCF_ERROR_IN_USE
));
1169 assert(handle
->rh_doorfd
== -1 && handle
->rh_doorfd_old
== -1);
1171 if (handle
->rh_doorpath
[0] != 0)
1172 door_name
= handle
->rh_doorpath
;
1174 fd
= open(door_name
, O_RDONLY
, 0);
1176 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1177 return (scf_set_error(SCF_ERROR_NO_SERVER
));
1180 request
.rdr_version
= REPOSITORY_DOOR_VERSION
;
1181 request
.rdr_request
= REPOSITORY_DOOR_REQUEST_CONNECT
;
1182 request
.rdr_flags
= handle
->rh_flags
;
1183 request
.rdr_debug
= handle
->rh_debug
;
1187 res
= make_door_call_retfd(fd
, &request
, sizeof (request
),
1188 &response
, sizeof (response
), &handle
->rh_doorfd
);
1193 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1195 assert(res
!= NOT_BOUND
);
1196 if (res
== CALL_FAILED
)
1197 return (scf_set_error(SCF_ERROR_NO_SERVER
));
1198 assert(res
== RESULT_TOO_BIG
);
1199 return (scf_set_error(SCF_ERROR_INTERNAL
));
1202 if (handle
->rh_doorfd
< 0) {
1203 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1205 switch (response
.rdr_status
) {
1206 case REPOSITORY_DOOR_SUCCESS
:
1207 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1209 case REPOSITORY_DOOR_FAIL_BAD_REQUEST
:
1210 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1212 case REPOSITORY_DOOR_FAIL_VERSION_MISMATCH
:
1213 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1215 case REPOSITORY_DOOR_FAIL_BAD_FLAG
:
1216 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1218 case REPOSITORY_DOOR_FAIL_NO_RESOURCES
:
1219 return (scf_set_error(SCF_ERROR_NO_RESOURCES
));
1221 case REPOSITORY_DOOR_FAIL_PERMISSION_DENIED
:
1222 return (scf_set_error(SCF_ERROR_PERMISSION_DENIED
));
1225 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1229 (void) fcntl(handle
->rh_doorfd
, F_SETFD
, FD_CLOEXEC
);
1231 if (door_info(handle
->rh_doorfd
, &info
) < 0) {
1232 (void) close(handle
->rh_doorfd
);
1233 handle
->rh_doorfd
= -1;
1235 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1236 return (scf_set_error(SCF_ERROR_NO_SERVER
));
1239 handle
->rh_doorpid
= pid
;
1240 handle
->rh_doorid
= info
.di_uniquifier
;
1243 * Now, re-attach everything
1245 for (el
= uu_list_first(handle
->rh_dataels
); el
!= NULL
;
1246 el
= uu_list_next(handle
->rh_dataels
, el
)) {
1247 if (datael_attach(el
) == -1) {
1248 assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED
);
1249 (void) handle_unbind_unlocked(handle
);
1250 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1255 for (iter
= uu_list_first(handle
->rh_iters
); iter
!= NULL
;
1256 iter
= uu_list_next(handle
->rh_iters
, iter
)) {
1257 if (iter_attach(iter
) == -1) {
1258 assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED
);
1259 (void) handle_unbind_unlocked(handle
);
1260 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1264 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1265 return (SCF_SUCCESS
);
1269 scf_handle_unbind(scf_handle_t
*handle
)
1272 (void) pthread_mutex_lock(&handle
->rh_lock
);
1273 ret
= handle_unbind_unlocked(handle
);
1274 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1275 return (ret
== SCF_SUCCESS
? ret
: scf_set_error(SCF_ERROR_NOT_BOUND
));
1278 static scf_handle_t
*
1279 handle_get(scf_handle_t
*h
)
1281 (void) pthread_mutex_lock(&h
->rh_lock
);
1282 if (h
->rh_flags
& HANDLE_DEAD
) {
1283 (void) pthread_mutex_unlock(&h
->rh_lock
);
1284 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED
);
1287 (void) pthread_mutex_unlock(&h
->rh_lock
);
1292 * Called when an object is removed from the handle. On the last remove,
1293 * cleans up and frees the handle.
1296 handle_unrefed(scf_handle_t
*handle
)
1302 scf_instance_t
*inst
;
1303 scf_snapshot_t
*snap
;
1304 scf_snaplevel_t
*snaplvl
;
1305 scf_propertygroup_t
*pg
;
1306 scf_property_t
*prop
;
1308 assert(MUTEX_HELD(&handle
->rh_lock
));
1311 * Don't do anything if the handle has not yet been destroyed, there
1312 * are still external references, or we're already doing unrefed
1315 if (!(handle
->rh_flags
& HANDLE_DEAD
) ||
1316 handle
->rh_extrefs
> 0 ||
1317 handle
->rh_fd_users
> 0 ||
1318 (handle
->rh_flags
& HANDLE_UNREFED
)) {
1319 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1323 handle
->rh_flags
|= HANDLE_UNREFED
;
1326 * Now that we know that there are no external references, and the
1327 * HANDLE_DEAD flag keeps new ones from appearing, we can clean up
1328 * our subhandles and destroy the handle completely.
1330 assert(handle
->rh_intrefs
>= 0);
1331 handle
->rh_extrefs
= handle
->rh_intrefs
;
1332 handle
->rh_intrefs
= 0;
1333 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1335 handle_hold_subhandles(handle
, RH_HOLD_ALL
);
1337 iter
= handle
->rh_iter
;
1338 sc
= handle
->rh_scope
;
1339 svc
= handle
->rh_service
;
1340 inst
= handle
->rh_instance
;
1341 snap
= handle
->rh_snapshot
;
1342 snaplvl
= handle
->rh_snaplvl
;
1344 prop
= handle
->rh_property
;
1345 v
= handle
->rh_value
;
1347 handle
->rh_iter
= NULL
;
1348 handle
->rh_scope
= NULL
;
1349 handle
->rh_service
= NULL
;
1350 handle
->rh_instance
= NULL
;
1351 handle
->rh_snapshot
= NULL
;
1352 handle
->rh_snaplvl
= NULL
;
1353 handle
->rh_pg
= NULL
;
1354 handle
->rh_property
= NULL
;
1355 handle
->rh_value
= NULL
;
1358 scf_iter_destroy(iter
);
1360 scf_scope_destroy(sc
);
1362 scf_service_destroy(svc
);
1364 scf_instance_destroy(inst
);
1366 scf_snapshot_destroy(snap
);
1367 if (snaplvl
!= NULL
)
1368 scf_snaplevel_destroy(snaplvl
);
1372 scf_property_destroy(prop
);
1374 scf_value_destroy(v
);
1376 (void) pthread_mutex_lock(&handle
->rh_lock
);
1378 /* there should be no outstanding children at this point */
1379 assert(handle
->rh_extrefs
== 0);
1380 assert(handle
->rh_intrefs
== 0);
1381 assert(handle
->rh_values
== 0);
1382 assert(handle
->rh_entries
== 0);
1383 assert(uu_list_numnodes(handle
->rh_dataels
) == 0);
1384 assert(uu_list_numnodes(handle
->rh_iters
) == 0);
1386 uu_list_destroy(handle
->rh_dataels
);
1387 uu_list_destroy(handle
->rh_iters
);
1388 handle
->rh_dataels
= NULL
;
1389 handle
->rh_iters
= NULL
;
1390 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1392 (void) pthread_mutex_destroy(&handle
->rh_lock
);
1398 scf_handle_destroy(scf_handle_t
*handle
)
1403 (void) pthread_mutex_lock(&handle
->rh_lock
);
1404 if (handle
->rh_flags
& HANDLE_DEAD
) {
1406 * This is an error (you are not allowed to reference the
1407 * handle after it is destroyed), but we can't report it.
1409 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1412 handle
->rh_flags
|= HANDLE_DEAD
;
1413 (void) handle_unbind_unlocked(handle
);
1414 handle_unrefed(handle
);
1418 scf_myname(scf_handle_t
*h
, char *out
, size_t len
)
1422 if (!handle_has_server(h
))
1423 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
1425 cp
= getenv("SMF_FMRI");
1427 return (scf_set_error(SCF_ERROR_NOT_SET
));
1429 return (strlcpy(out
, cp
, len
));
1433 handle_alloc_entityid(scf_handle_t
*h
)
1437 assert(MUTEX_HELD(&h
->rh_lock
));
1439 if (uu_list_numnodes(h
->rh_dataels
) == UINT32_MAX
)
1440 return (0); /* no ids available */
1443 * The following loop assumes that there are not a huge number of
1444 * outstanding entities when we've wrapped. If that ends up not
1445 * being the case, the O(N^2) nature of this search will hurt a lot,
1446 * and the data structure should be switched to an AVL tree.
1448 nextid
= h
->rh_nextentity
+ 1;
1454 h
->rh_flags
|= HANDLE_WRAPPED_ENTITY
;
1456 if (!(h
->rh_flags
& HANDLE_WRAPPED_ENTITY
))
1459 cur
= uu_list_find(h
->rh_dataels
, NULL
, &nextid
, NULL
);
1461 break; /* not in use */
1463 if (nextid
== h
->rh_nextentity
)
1464 return (0); /* wrapped around; no ids available */
1468 h
->rh_nextentity
= nextid
;
1473 handle_alloc_iterid(scf_handle_t
*h
)
1477 assert(MUTEX_HELD(&h
->rh_lock
));
1479 if (uu_list_numnodes(h
->rh_iters
) == UINT32_MAX
)
1480 return (0); /* no ids available */
1482 /* see the comment in handle_alloc_entityid */
1483 nextid
= h
->rh_nextiter
+ 1;
1489 h
->rh_flags
|= HANDLE_WRAPPED_ITER
;
1491 if (!(h
->rh_flags
& HANDLE_WRAPPED_ITER
))
1492 break; /* not yet wrapped */
1494 cur
= uu_list_find(h
->rh_iters
, NULL
, &nextid
, NULL
);
1496 break; /* not in use */
1498 if (nextid
== h
->rh_nextiter
)
1499 return (0); /* wrapped around; no ids available */
1503 h
->rh_nextiter
= nextid
;
1508 handle_next_changeid(scf_handle_t
*handle
)
1512 assert(MUTEX_HELD(&handle
->rh_lock
));
1514 nextid
= ++handle
->rh_nextchangeid
;
1516 nextid
= ++handle
->rh_nextchangeid
;
1522 * _INVALID_ARGUMENT - h is NULL
1524 * _INTERNAL - server response too big
1525 * entity already set up with different type
1529 datael_init(scf_datael_t
*dp
, scf_handle_t
*h
, uint32_t type
)
1534 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1536 uu_list_node_init(dp
, &dp
->rd_node
, datael_pool
);
1542 (void) pthread_mutex_lock(&h
->rh_lock
);
1543 if (h
->rh_flags
& HANDLE_DEAD
) {
1545 * we're in undefined territory (the user cannot use a handle
1546 * directly after it has been destroyed), but we don't want
1547 * to allow any new references to happen, so we fail here.
1549 (void) pthread_mutex_unlock(&h
->rh_lock
);
1550 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
1552 dp
->rd_entity
= handle_alloc_entityid(h
);
1553 if (dp
->rd_entity
== 0) {
1554 (void) pthread_mutex_unlock(&h
->rh_lock
);
1555 uu_list_node_fini(dp
, &dp
->rd_node
, datael_pool
);
1556 return (scf_set_error(SCF_ERROR_NO_MEMORY
));
1559 ret
= datael_attach(dp
);
1561 (void) uu_list_insert_before(h
->rh_dataels
, NULL
, dp
);
1564 uu_list_node_fini(dp
, &dp
->rd_node
, datael_pool
);
1566 (void) pthread_mutex_unlock(&h
->rh_lock
);
1572 datael_destroy(scf_datael_t
*dp
)
1574 scf_handle_t
*h
= dp
->rd_handle
;
1576 struct rep_protocol_entity_teardown request
;
1577 rep_protocol_response_t response
;
1579 (void) pthread_mutex_lock(&h
->rh_lock
);
1580 uu_list_remove(h
->rh_dataels
, dp
);
1583 if (handle_is_bound(h
)) {
1584 request
.rpr_request
= REP_PROTOCOL_ENTITY_TEARDOWN
;
1585 request
.rpr_entityid
= dp
->rd_entity
;
1587 (void) make_door_call(h
, &request
, sizeof (request
),
1588 &response
, sizeof (response
));
1590 handle_unrefed(h
); /* drops h->rh_lock */
1592 dp
->rd_handle
= NULL
;
1595 static scf_handle_t
*
1596 datael_handle(const scf_datael_t
*dp
)
1598 return (handle_get(dp
->rd_handle
));
1602 * We delay ENTITY_RESETs until right before the entity is used. By doing
1603 * them lazily, we remove quite a few unnecessary calls.
1606 datael_do_reset_locked(scf_datael_t
*dp
)
1608 scf_handle_t
*h
= dp
->rd_handle
;
1610 struct rep_protocol_entity_reset request
;
1611 rep_protocol_response_t response
;
1613 assert(MUTEX_HELD(&h
->rh_lock
));
1615 request
.rpr_request
= REP_PROTOCOL_ENTITY_RESET
;
1616 request
.rpr_entityid
= dp
->rd_entity
;
1618 (void) make_door_call(h
, &request
, sizeof (request
),
1619 &response
, sizeof (response
));
1625 datael_reset_locked(scf_datael_t
*dp
)
1627 assert(MUTEX_HELD(&dp
->rd_handle
->rh_lock
));
1632 datael_reset(scf_datael_t
*dp
)
1634 scf_handle_t
*h
= dp
->rd_handle
;
1636 (void) pthread_mutex_lock(&h
->rh_lock
);
1638 (void) pthread_mutex_unlock(&h
->rh_lock
);
1642 datael_finish_reset(const scf_datael_t
*dp_arg
)
1644 scf_datael_t
*dp
= (scf_datael_t
*)dp_arg
;
1647 datael_do_reset_locked(dp
);
1651 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
1652 * big, bad entity id, request not applicable to entity, name too long for
1653 * buffer), _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED (snaplevel is not of an
1657 datael_get_name(const scf_datael_t
*dp
, char *buf
, size_t size
, uint32_t type
)
1659 scf_handle_t
*h
= dp
->rd_handle
;
1661 struct rep_protocol_entity_name request
;
1662 struct rep_protocol_name_response response
;
1665 (void) pthread_mutex_lock(&h
->rh_lock
);
1666 request
.rpr_request
= REP_PROTOCOL_ENTITY_NAME
;
1667 request
.rpr_entityid
= dp
->rd_entity
;
1668 request
.rpr_answertype
= type
;
1670 datael_finish_reset(dp
);
1671 r
= make_door_call(h
, &request
, sizeof (request
),
1672 &response
, sizeof (response
));
1673 (void) pthread_mutex_unlock(&h
->rh_lock
);
1676 DOOR_ERRORS_BLOCK(r
);
1678 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
1679 assert(response
.rpr_response
!= REP_PROTOCOL_FAIL_BAD_REQUEST
);
1680 if (response
.rpr_response
== REP_PROTOCOL_FAIL_NOT_FOUND
)
1681 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
));
1682 return (scf_set_error(proto_error(response
.rpr_response
)));
1684 return (strlcpy(buf
, response
.rpr_name
, size
));
1688 * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
1689 * (server response too big, bad element id), _EXISTS (elements have same id),
1690 * _NOT_SET, _DELETED, _CONSTRAINT_VIOLATED, _NOT_FOUND (scope has no parent),
1694 datael_get_parent(const scf_datael_t
*dp
, scf_datael_t
*pp
)
1696 scf_handle_t
*h
= dp
->rd_handle
;
1698 struct rep_protocol_entity_parent request
;
1699 struct rep_protocol_response response
;
1703 if (h
!= pp
->rd_handle
)
1704 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
1706 (void) pthread_mutex_lock(&h
->rh_lock
);
1707 request
.rpr_request
= REP_PROTOCOL_ENTITY_GET_PARENT
;
1708 request
.rpr_entityid
= dp
->rd_entity
;
1709 request
.rpr_outid
= pp
->rd_entity
;
1711 datael_finish_reset(dp
);
1712 datael_finish_reset(pp
);
1713 r
= make_door_call(h
, &request
, sizeof (request
),
1714 &response
, sizeof (response
));
1715 (void) pthread_mutex_unlock(&h
->rh_lock
);
1718 DOOR_ERRORS_BLOCK(r
);
1720 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
1721 if (response
.rpr_response
== REP_PROTOCOL_FAIL_TYPE_MISMATCH
)
1722 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
));
1723 return (scf_set_error(proto_error(response
.rpr_response
)));
1726 return (SCF_SUCCESS
);
1730 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1731 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1732 * too big, bad id, iter already exists, element cannot have children of type,
1733 * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1734 * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1735 * _BACKEND_ACCESS, _NOT_FOUND.
1738 datael_get_child_composed_locked(const scf_datael_t
*dp
, const char *name
,
1739 uint32_t type
, scf_datael_t
*out
, scf_iter_t
*iter
)
1741 struct rep_protocol_iter_start request
;
1742 struct rep_protocol_iter_read read_request
;
1743 struct rep_protocol_response response
;
1745 scf_handle_t
*h
= dp
->rd_handle
;
1748 if (h
!= out
->rd_handle
)
1749 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
1751 if (out
->rd_type
!= type
)
1752 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1754 assert(MUTEX_HELD(&h
->rh_lock
));
1755 assert(iter
!= NULL
);
1757 scf_iter_reset_locked(iter
);
1758 iter
->iter_type
= type
;
1760 request
.rpr_request
= REP_PROTOCOL_ITER_START
;
1761 request
.rpr_iterid
= iter
->iter_id
;
1762 request
.rpr_entity
= dp
->rd_entity
;
1763 request
.rpr_itertype
= type
;
1764 request
.rpr_flags
= RP_ITER_START_EXACT
| RP_ITER_START_COMPOSED
;
1766 if (name
== NULL
|| strlcpy(request
.rpr_pattern
, name
,
1767 sizeof (request
.rpr_pattern
)) >= sizeof (request
.rpr_pattern
)) {
1768 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1771 datael_finish_reset(dp
);
1772 datael_finish_reset(out
);
1775 * We hold the handle lock across both door calls, so that they
1778 r
= make_door_call(h
, &request
, sizeof (request
),
1779 &response
, sizeof (response
));
1782 DOOR_ERRORS_BLOCK(r
);
1784 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1785 return (scf_set_error(proto_error(response
.rpr_response
)));
1787 iter
->iter_sequence
++;
1789 read_request
.rpr_request
= REP_PROTOCOL_ITER_READ
;
1790 read_request
.rpr_iterid
= iter
->iter_id
;
1791 read_request
.rpr_sequence
= iter
->iter_sequence
;
1792 read_request
.rpr_entityid
= out
->rd_entity
;
1794 r
= make_door_call(h
, &read_request
, sizeof (read_request
),
1795 &response
, sizeof (response
));
1797 scf_iter_reset_locked(iter
);
1800 DOOR_ERRORS_BLOCK(r
);
1802 if (response
.rpr_response
== REP_PROTOCOL_DONE
) {
1803 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
1806 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
1807 if (response
.rpr_response
== REP_PROTOCOL_FAIL_NOT_SET
||
1808 response
.rpr_response
== REP_PROTOCOL_FAIL_BAD_REQUEST
)
1809 return (scf_set_error(SCF_ERROR_INTERNAL
));
1810 return (scf_set_error(proto_error(response
.rpr_response
)));
1817 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1818 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1819 * too big, bad id, element cannot have children of type, type is invalid),
1820 * _NOT_SET, _DELETED, _NO_RESOURCES, _BACKEND_ACCESS.
1823 datael_get_child_locked(const scf_datael_t
*dp
, const char *name
,
1824 uint32_t type
, scf_datael_t
*out
)
1826 struct rep_protocol_entity_get_child request
;
1827 struct rep_protocol_response response
;
1829 scf_handle_t
*h
= dp
->rd_handle
;
1832 if (h
!= out
->rd_handle
)
1833 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
1835 if (out
->rd_type
!= type
)
1836 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1838 assert(MUTEX_HELD(&h
->rh_lock
));
1840 request
.rpr_request
= REP_PROTOCOL_ENTITY_GET_CHILD
;
1841 request
.rpr_entityid
= dp
->rd_entity
;
1842 request
.rpr_childid
= out
->rd_entity
;
1844 if (name
== NULL
|| strlcpy(request
.rpr_name
, name
,
1845 sizeof (request
.rpr_name
)) >= sizeof (request
.rpr_name
)) {
1846 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1849 datael_finish_reset(dp
);
1850 datael_finish_reset(out
);
1852 r
= make_door_call(h
, &request
, sizeof (request
),
1853 &response
, sizeof (response
));
1856 DOOR_ERRORS_BLOCK(r
);
1858 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1859 return (scf_set_error(proto_error(response
.rpr_response
)));
1864 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1865 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1866 * too big, bad id, iter already exists, element cannot have children of type,
1867 * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1868 * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1869 * _BACKEND_ACCESS, _NOT_FOUND.
1872 datael_get_child(const scf_datael_t
*dp
, const char *name
, uint32_t type
,
1873 scf_datael_t
*out
, boolean_t composed
)
1875 scf_handle_t
*h
= dp
->rd_handle
;
1879 scf_iter_t
*iter
= NULL
;
1882 iter
= HANDLE_HOLD_ITER(h
);
1886 case REP_PROTOCOL_ENTITY_SERVICE
:
1887 out
= &HANDLE_HOLD_SERVICE(h
)->rd_d
;
1888 held
= RH_HOLD_SERVICE
;
1891 case REP_PROTOCOL_ENTITY_INSTANCE
:
1892 out
= &HANDLE_HOLD_INSTANCE(h
)->rd_d
;
1893 held
= RH_HOLD_INSTANCE
;
1896 case REP_PROTOCOL_ENTITY_SNAPSHOT
:
1897 out
= &HANDLE_HOLD_SNAPSHOT(h
)->rd_d
;
1898 held
= RH_HOLD_SNAPSHOT
;
1901 case REP_PROTOCOL_ENTITY_SNAPLEVEL
:
1902 out
= &HANDLE_HOLD_SNAPLVL(h
)->rd_d
;
1903 held
= RH_HOLD_SNAPLVL
;
1906 case REP_PROTOCOL_ENTITY_PROPERTYGRP
:
1907 out
= &HANDLE_HOLD_PG(h
)->rd_d
;
1911 case REP_PROTOCOL_ENTITY_PROPERTY
:
1912 out
= &HANDLE_HOLD_PROPERTY(h
)->rd_d
;
1913 held
= RH_HOLD_PROPERTY
;
1922 (void) pthread_mutex_lock(&h
->rh_lock
);
1924 ret
= datael_get_child_composed_locked(dp
, name
, type
, out
,
1927 ret
= datael_get_child_locked(dp
, name
, type
, out
);
1928 (void) pthread_mutex_unlock(&h
->rh_lock
);
1931 HANDLE_RELE_ITER(h
);
1934 handle_rele_subhandles(h
, held
);
1942 * _INVALID_ARGUMENT - name is too long
1945 * cannot create children for dp's type of node
1946 * _NOT_BOUND - handle is not bound
1947 * _CONNECTION_BROKEN - server is not reachable
1948 * _INTERNAL - server response too big
1949 * dp or cp has unknown id
1950 * type is _PROPERTYGRP
1952 * dp cannot have children of type type
1953 * database is corrupt
1954 * _EXISTS - dp & cp have the same id
1955 * _EXISTS - child already exists
1956 * _DELETED - dp has been deleted
1957 * _NOT_SET - dp is reset
1959 * _PERMISSION_DENIED
1964 datael_add_child(const scf_datael_t
*dp
, const char *name
, uint32_t type
,
1967 scf_handle_t
*h
= dp
->rd_handle
;
1969 struct rep_protocol_entity_create_child request
;
1970 struct rep_protocol_response response
;
1976 case REP_PROTOCOL_ENTITY_SCOPE
:
1977 cp
= &HANDLE_HOLD_SCOPE(h
)->rd_d
;
1978 held
= RH_HOLD_SCOPE
;
1980 case REP_PROTOCOL_ENTITY_SERVICE
:
1981 cp
= &HANDLE_HOLD_SERVICE(h
)->rd_d
;
1982 held
= RH_HOLD_SERVICE
;
1984 case REP_PROTOCOL_ENTITY_INSTANCE
:
1985 cp
= &HANDLE_HOLD_INSTANCE(h
)->rd_d
;
1986 held
= RH_HOLD_INSTANCE
;
1988 case REP_PROTOCOL_ENTITY_SNAPSHOT
:
1993 assert(h
== cp
->rd_handle
);
1995 } else if (h
!= cp
->rd_handle
) {
1996 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
1999 if (strlcpy(request
.rpr_name
, name
, sizeof (request
.rpr_name
)) >=
2000 sizeof (request
.rpr_name
)) {
2001 r
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2005 (void) pthread_mutex_lock(&h
->rh_lock
);
2006 request
.rpr_request
= REP_PROTOCOL_ENTITY_CREATE_CHILD
;
2007 request
.rpr_entityid
= dp
->rd_entity
;
2008 request
.rpr_childtype
= type
;
2009 request
.rpr_childid
= cp
->rd_entity
;
2011 datael_finish_reset(dp
);
2012 request
.rpr_changeid
= handle_next_changeid(h
);
2013 r
= make_door_call(h
, &request
, sizeof (request
),
2014 &response
, sizeof (response
));
2015 (void) pthread_mutex_unlock(&h
->rh_lock
);
2018 handle_rele_subhandles(h
, held
);
2021 DOOR_ERRORS_BLOCK(r
);
2023 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2024 return (scf_set_error(proto_error(response
.rpr_response
)));
2026 return (SCF_SUCCESS
);
2030 handle_rele_subhandles(h
, held
);
2035 datael_add_pg(const scf_datael_t
*dp
, const char *name
, const char *type
,
2036 uint32_t flags
, scf_datael_t
*cp
)
2038 scf_handle_t
*h
= dp
->rd_handle
;
2040 struct rep_protocol_entity_create_pg request
;
2041 struct rep_protocol_response response
;
2044 int holding_els
= 0;
2048 cp
= &HANDLE_HOLD_PG(h
)->rd_d
;
2049 assert(h
== cp
->rd_handle
);
2051 } else if (h
!= cp
->rd_handle
) {
2052 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2055 request
.rpr_request
= REP_PROTOCOL_ENTITY_CREATE_PG
;
2057 if (name
== NULL
|| strlcpy(request
.rpr_name
, name
,
2058 sizeof (request
.rpr_name
)) > sizeof (request
.rpr_name
)) {
2059 r
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2063 if (type
== NULL
|| strlcpy(request
.rpr_type
, type
,
2064 sizeof (request
.rpr_type
)) > sizeof (request
.rpr_type
)) {
2065 r
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2069 (void) pthread_mutex_lock(&h
->rh_lock
);
2070 request
.rpr_entityid
= dp
->rd_entity
;
2071 request
.rpr_childid
= cp
->rd_entity
;
2072 request
.rpr_flags
= flags
;
2074 datael_finish_reset(dp
);
2075 datael_finish_reset(cp
);
2076 request
.rpr_changeid
= handle_next_changeid(h
);
2077 r
= make_door_call(h
, &request
, sizeof (request
),
2078 &response
, sizeof (response
));
2079 (void) pthread_mutex_unlock(&h
->rh_lock
);
2085 DOOR_ERRORS_BLOCK(r
);
2087 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2088 return (scf_set_error(proto_error(response
.rpr_response
)));
2090 return (SCF_SUCCESS
);
2099 datael_delete(const scf_datael_t
*dp
)
2101 scf_handle_t
*h
= dp
->rd_handle
;
2103 struct rep_protocol_entity_delete request
;
2104 struct rep_protocol_response response
;
2107 (void) pthread_mutex_lock(&h
->rh_lock
);
2108 request
.rpr_request
= REP_PROTOCOL_ENTITY_DELETE
;
2109 request
.rpr_entityid
= dp
->rd_entity
;
2111 datael_finish_reset(dp
);
2112 request
.rpr_changeid
= handle_next_changeid(h
);
2113 r
= make_door_call(h
, &request
, sizeof (request
),
2114 &response
, sizeof (response
));
2115 (void) pthread_mutex_unlock(&h
->rh_lock
);
2118 DOOR_ERRORS_BLOCK(r
);
2120 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2121 return (scf_set_error(proto_error(response
.rpr_response
)));
2123 return (SCF_SUCCESS
);
2128 * _INVALID_ARGUMENT - h is NULL
2130 * _HANDLE_DESTROYED - h has been destroyed
2131 * _INTERNAL - server response too big
2132 * iter already exists
2136 scf_iter_create(scf_handle_t
*h
)
2141 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2145 iter
= uu_zalloc(sizeof (*iter
));
2147 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2151 uu_list_node_init(iter
, &iter
->iter_node
, iter_pool
);
2152 iter
->iter_handle
= h
;
2153 iter
->iter_sequence
= 1;
2154 iter
->iter_type
= REP_PROTOCOL_ENTITY_NONE
;
2156 (void) pthread_mutex_lock(&h
->rh_lock
);
2157 iter
->iter_id
= handle_alloc_iterid(h
);
2158 if (iter
->iter_id
== 0) {
2159 (void) pthread_mutex_unlock(&h
->rh_lock
);
2160 uu_list_node_fini(iter
, &iter
->iter_node
, iter_pool
);
2161 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2165 if (iter_attach(iter
) == -1) {
2166 uu_list_node_fini(iter
, &iter
->iter_node
, iter_pool
);
2167 (void) pthread_mutex_unlock(&h
->rh_lock
);
2171 (void) uu_list_insert_before(h
->rh_iters
, NULL
, iter
);
2173 (void) pthread_mutex_unlock(&h
->rh_lock
);
2178 scf_iter_handle(const scf_iter_t
*iter
)
2180 return (handle_get(iter
->iter_handle
));
2184 scf_iter_reset_locked(scf_iter_t
*iter
)
2186 struct rep_protocol_iter_request request
;
2187 struct rep_protocol_response response
;
2189 request
.rpr_request
= REP_PROTOCOL_ITER_RESET
;
2190 request
.rpr_iterid
= iter
->iter_id
;
2192 assert(MUTEX_HELD(&iter
->iter_handle
->rh_lock
));
2194 (void) make_door_call(iter
->iter_handle
,
2195 &request
, sizeof (request
), &response
, sizeof (response
));
2197 iter
->iter_type
= REP_PROTOCOL_ENTITY_NONE
;
2198 iter
->iter_sequence
= 1;
2202 scf_iter_reset(scf_iter_t
*iter
)
2204 (void) pthread_mutex_lock(&iter
->iter_handle
->rh_lock
);
2205 scf_iter_reset_locked(iter
);
2206 (void) pthread_mutex_unlock(&iter
->iter_handle
->rh_lock
);
2210 scf_iter_destroy(scf_iter_t
*iter
)
2212 scf_handle_t
*handle
;
2214 struct rep_protocol_iter_request request
;
2215 struct rep_protocol_response response
;
2220 handle
= iter
->iter_handle
;
2222 (void) pthread_mutex_lock(&handle
->rh_lock
);
2223 request
.rpr_request
= REP_PROTOCOL_ITER_TEARDOWN
;
2224 request
.rpr_iterid
= iter
->iter_id
;
2226 (void) make_door_call(handle
, &request
, sizeof (request
),
2227 &response
, sizeof (response
));
2229 uu_list_remove(handle
->rh_iters
, iter
);
2230 --handle
->rh_extrefs
;
2231 handle_unrefed(handle
); /* drops h->rh_lock */
2232 iter
->iter_handle
= NULL
;
2234 uu_list_node_fini(iter
, &iter
->iter_node
, iter_pool
);
2239 handle_get_local_scope_locked(scf_handle_t
*handle
, scf_scope_t
*out
)
2241 struct rep_protocol_entity_get request
;
2242 struct rep_protocol_name_response response
;
2245 assert(MUTEX_HELD(&handle
->rh_lock
));
2247 if (handle
!= out
->rd_d
.rd_handle
)
2248 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2250 request
.rpr_request
= REP_PROTOCOL_ENTITY_GET
;
2251 request
.rpr_entityid
= out
->rd_d
.rd_entity
;
2252 request
.rpr_object
= RP_ENTITY_GET_MOST_LOCAL_SCOPE
;
2254 datael_finish_reset(&out
->rd_d
);
2255 r
= make_door_call(handle
, &request
, sizeof (request
),
2256 &response
, sizeof (response
));
2259 DOOR_ERRORS_BLOCK(r
);
2261 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2262 return (scf_set_error(proto_error(response
.rpr_response
)));
2264 return (SCF_SUCCESS
);
2268 scf_iter_handle_scopes(scf_iter_t
*iter
, const scf_handle_t
*handle
)
2270 scf_handle_t
*h
= iter
->iter_handle
;
2272 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2274 (void) pthread_mutex_lock(&h
->rh_lock
);
2275 scf_iter_reset_locked(iter
);
2277 if (!handle_is_bound(h
)) {
2278 (void) pthread_mutex_unlock(&h
->rh_lock
);
2279 return (scf_set_error(SCF_ERROR_NOT_BOUND
));
2282 if (!handle_has_server_locked(h
)) {
2283 (void) pthread_mutex_unlock(&h
->rh_lock
);
2284 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
2287 iter
->iter_type
= REP_PROTOCOL_ENTITY_SCOPE
;
2288 iter
->iter_sequence
= 1;
2289 (void) pthread_mutex_unlock(&h
->rh_lock
);
2294 scf_iter_next_scope(scf_iter_t
*iter
, scf_scope_t
*out
)
2297 scf_handle_t
*h
= iter
->iter_handle
;
2299 if (h
!= out
->rd_d
.rd_handle
)
2300 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2302 (void) pthread_mutex_lock(&h
->rh_lock
);
2303 if (iter
->iter_type
== REP_PROTOCOL_ENTITY_NONE
) {
2304 (void) pthread_mutex_unlock(&h
->rh_lock
);
2305 return (scf_set_error(SCF_ERROR_NOT_SET
));
2307 if (iter
->iter_type
!= REP_PROTOCOL_ENTITY_SCOPE
) {
2308 (void) pthread_mutex_unlock(&h
->rh_lock
);
2309 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
2311 if (iter
->iter_sequence
== 1) {
2312 if ((ret
= handle_get_local_scope_locked(h
, out
)) ==
2314 iter
->iter_sequence
++;
2318 datael_reset_locked(&out
->rd_d
);
2321 (void) pthread_mutex_unlock(&h
->rh_lock
);
2326 scf_handle_get_scope(scf_handle_t
*h
, const char *name
, scf_scope_t
*out
)
2330 if (h
!= out
->rd_d
.rd_handle
)
2331 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2333 (void) pthread_mutex_lock(&h
->rh_lock
);
2334 if (strcmp(name
, SCF_SCOPE_LOCAL
) == 0) {
2335 ret
= handle_get_local_scope_locked(h
, out
);
2337 datael_reset_locked(&out
->rd_d
);
2338 if (uu_check_name(name
, 0) == -1)
2339 ret
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2341 ret
= scf_set_error(SCF_ERROR_NOT_FOUND
);
2343 (void) pthread_mutex_unlock(&h
->rh_lock
);
2348 datael_setup_iter(scf_iter_t
*iter
, const scf_datael_t
*dp
, uint32_t res_type
,
2351 scf_handle_t
*h
= dp
->rd_handle
;
2353 struct rep_protocol_iter_start request
;
2354 struct rep_protocol_response response
;
2358 if (h
!= iter
->iter_handle
)
2359 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2361 (void) pthread_mutex_lock(&h
->rh_lock
);
2362 scf_iter_reset_locked(iter
);
2363 iter
->iter_type
= res_type
;
2365 request
.rpr_request
= REP_PROTOCOL_ITER_START
;
2366 request
.rpr_iterid
= iter
->iter_id
;
2367 request
.rpr_entity
= dp
->rd_entity
;
2368 request
.rpr_itertype
= res_type
;
2369 request
.rpr_flags
= RP_ITER_START_ALL
|
2370 (composed
? RP_ITER_START_COMPOSED
: 0);
2371 request
.rpr_pattern
[0] = 0;
2373 datael_finish_reset(dp
);
2374 r
= make_door_call(h
, &request
, sizeof (request
),
2375 &response
, sizeof (response
));
2378 (void) pthread_mutex_unlock(&h
->rh_lock
);
2379 DOOR_ERRORS_BLOCK(r
);
2381 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
2382 (void) pthread_mutex_unlock(&h
->rh_lock
);
2383 return (scf_set_error(proto_error(response
.rpr_response
)));
2385 iter
->iter_sequence
++;
2386 (void) pthread_mutex_unlock(&h
->rh_lock
);
2387 return (SCF_SUCCESS
);
2391 datael_setup_iter_pgtyped(scf_iter_t
*iter
, const scf_datael_t
*dp
,
2392 const char *pgtype
, boolean_t composed
)
2394 scf_handle_t
*h
= dp
->rd_handle
;
2396 struct rep_protocol_iter_start request
;
2397 struct rep_protocol_response response
;
2401 if (h
!= iter
->iter_handle
)
2402 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2404 if (pgtype
== NULL
|| strlcpy(request
.rpr_pattern
, pgtype
,
2405 sizeof (request
.rpr_pattern
)) >= sizeof (request
.rpr_pattern
)) {
2406 scf_iter_reset(iter
);
2407 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
2410 (void) pthread_mutex_lock(&h
->rh_lock
);
2411 request
.rpr_request
= REP_PROTOCOL_ITER_START
;
2412 request
.rpr_iterid
= iter
->iter_id
;
2413 request
.rpr_entity
= dp
->rd_entity
;
2414 request
.rpr_itertype
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
2415 request
.rpr_flags
= RP_ITER_START_PGTYPE
|
2416 (composed
? RP_ITER_START_COMPOSED
: 0);
2418 datael_finish_reset(dp
);
2419 scf_iter_reset_locked(iter
);
2420 iter
->iter_type
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
2422 r
= make_door_call(h
, &request
, sizeof (request
),
2423 &response
, sizeof (response
));
2426 (void) pthread_mutex_unlock(&h
->rh_lock
);
2428 DOOR_ERRORS_BLOCK(r
);
2430 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
2431 (void) pthread_mutex_unlock(&h
->rh_lock
);
2432 return (scf_set_error(proto_error(response
.rpr_response
)));
2434 iter
->iter_sequence
++;
2435 (void) pthread_mutex_unlock(&h
->rh_lock
);
2436 return (SCF_SUCCESS
);
2440 datael_iter_next(scf_iter_t
*iter
, scf_datael_t
*out
)
2442 scf_handle_t
*h
= iter
->iter_handle
;
2444 struct rep_protocol_iter_read request
;
2445 struct rep_protocol_response response
;
2448 if (h
!= out
->rd_handle
)
2449 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2451 (void) pthread_mutex_lock(&h
->rh_lock
);
2452 if (iter
->iter_type
== REP_PROTOCOL_ENTITY_NONE
||
2453 iter
->iter_sequence
== 1) {
2454 (void) pthread_mutex_unlock(&h
->rh_lock
);
2455 return (scf_set_error(SCF_ERROR_NOT_SET
));
2458 if (out
->rd_type
!= iter
->iter_type
) {
2459 (void) pthread_mutex_unlock(&h
->rh_lock
);
2460 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
2463 request
.rpr_request
= REP_PROTOCOL_ITER_READ
;
2464 request
.rpr_iterid
= iter
->iter_id
;
2465 request
.rpr_sequence
= iter
->iter_sequence
;
2466 request
.rpr_entityid
= out
->rd_entity
;
2468 datael_finish_reset(out
);
2469 r
= make_door_call(h
, &request
, sizeof (request
),
2470 &response
, sizeof (response
));
2473 (void) pthread_mutex_unlock(&h
->rh_lock
);
2474 DOOR_ERRORS_BLOCK(r
);
2477 if (response
.rpr_response
== REP_PROTOCOL_DONE
) {
2478 (void) pthread_mutex_unlock(&h
->rh_lock
);
2481 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
2482 (void) pthread_mutex_unlock(&h
->rh_lock
);
2483 return (scf_set_error(proto_error(response
.rpr_response
)));
2485 iter
->iter_sequence
++;
2486 (void) pthread_mutex_unlock(&h
->rh_lock
);
2492 scf_iter_scope_services(scf_iter_t
*iter
, const scf_scope_t
*s
)
2494 return (datael_setup_iter(iter
, &s
->rd_d
,
2495 REP_PROTOCOL_ENTITY_SERVICE
, 0));
2499 scf_iter_next_service(scf_iter_t
*iter
, scf_service_t
*out
)
2501 return (datael_iter_next(iter
, &out
->rd_d
));
2505 scf_iter_service_instances(scf_iter_t
*iter
, const scf_service_t
*svc
)
2507 return (datael_setup_iter(iter
, &svc
->rd_d
,
2508 REP_PROTOCOL_ENTITY_INSTANCE
, 0));
2512 scf_iter_next_instance(scf_iter_t
*iter
, scf_instance_t
*out
)
2514 return (datael_iter_next(iter
, &out
->rd_d
));
2518 scf_iter_service_pgs(scf_iter_t
*iter
, const scf_service_t
*svc
)
2520 return (datael_setup_iter(iter
, &svc
->rd_d
,
2521 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 0));
2525 scf_iter_service_pgs_typed(scf_iter_t
*iter
, const scf_service_t
*svc
,
2528 return (datael_setup_iter_pgtyped(iter
, &svc
->rd_d
, type
, 0));
2532 scf_iter_instance_snapshots(scf_iter_t
*iter
, const scf_instance_t
*inst
)
2534 return (datael_setup_iter(iter
, &inst
->rd_d
,
2535 REP_PROTOCOL_ENTITY_SNAPSHOT
, 0));
2539 scf_iter_next_snapshot(scf_iter_t
*iter
, scf_snapshot_t
*out
)
2541 return (datael_iter_next(iter
, &out
->rd_d
));
2545 scf_iter_instance_pgs(scf_iter_t
*iter
, const scf_instance_t
*inst
)
2547 return (datael_setup_iter(iter
, &inst
->rd_d
,
2548 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 0));
2552 scf_iter_instance_pgs_typed(scf_iter_t
*iter
, const scf_instance_t
*inst
,
2555 return (datael_setup_iter_pgtyped(iter
, &inst
->rd_d
, type
, 0));
2559 scf_iter_instance_pgs_composed(scf_iter_t
*iter
, const scf_instance_t
*inst
,
2560 const scf_snapshot_t
*snap
)
2562 if (snap
!= NULL
&& inst
->rd_d
.rd_handle
!= snap
->rd_d
.rd_handle
)
2563 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2565 return (datael_setup_iter(iter
, snap
? &snap
->rd_d
: &inst
->rd_d
,
2566 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 1));
2570 scf_iter_instance_pgs_typed_composed(scf_iter_t
*iter
,
2571 const scf_instance_t
*inst
, const scf_snapshot_t
*snap
, const char *type
)
2573 if (snap
!= NULL
&& inst
->rd_d
.rd_handle
!= snap
->rd_d
.rd_handle
)
2574 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2576 return (datael_setup_iter_pgtyped(iter
,
2577 snap
? &snap
->rd_d
: &inst
->rd_d
, type
, 1));
2581 scf_iter_snaplevel_pgs(scf_iter_t
*iter
, const scf_snaplevel_t
*inst
)
2583 return (datael_setup_iter(iter
, &inst
->rd_d
,
2584 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 0));
2588 scf_iter_snaplevel_pgs_typed(scf_iter_t
*iter
, const scf_snaplevel_t
*inst
,
2591 return (datael_setup_iter_pgtyped(iter
, &inst
->rd_d
, type
, 0));
2595 scf_iter_next_pg(scf_iter_t
*iter
, scf_propertygroup_t
*out
)
2597 return (datael_iter_next(iter
, &out
->rd_d
));
2601 scf_iter_pg_properties(scf_iter_t
*iter
, const scf_propertygroup_t
*pg
)
2603 return (datael_setup_iter(iter
, &pg
->rd_d
,
2604 REP_PROTOCOL_ENTITY_PROPERTY
, 0));
2608 scf_iter_next_property(scf_iter_t
*iter
, scf_property_t
*out
)
2610 return (datael_iter_next(iter
, &out
->rd_d
));
2615 * _INVALID_ARGUMENT - handle is NULL
2616 * _INTERNAL - server response too big
2617 * entity already set up with different type
2622 scf_scope_create(scf_handle_t
*handle
)
2626 ret
= uu_zalloc(sizeof (*ret
));
2628 if (datael_init(&ret
->rd_d
, handle
,
2629 REP_PROTOCOL_ENTITY_SCOPE
) == -1) {
2634 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2641 scf_scope_handle(const scf_scope_t
*val
)
2643 return (datael_handle(&val
->rd_d
));
2647 scf_scope_destroy(scf_scope_t
*val
)
2652 datael_destroy(&val
->rd_d
);
2657 scf_scope_get_name(const scf_scope_t
*rep
, char *out
, size_t len
)
2659 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2664 scf_scope_get_parent(const scf_scope_t
*child
, scf_scope_t
*parent
)
2668 /* fake up the side-effects */
2669 datael_reset(&parent
->rd_d
);
2670 if (scf_scope_get_name(child
, name
, sizeof (name
)) < 0)
2672 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
2676 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2677 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2680 scf_service_create(scf_handle_t
*handle
)
2683 ret
= uu_zalloc(sizeof (*ret
));
2685 if (datael_init(&ret
->rd_d
, handle
,
2686 REP_PROTOCOL_ENTITY_SERVICE
) == -1) {
2691 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2703 * _CONNECTION_BROKEN
2709 * _PERMISSION_DENIED
2714 scf_scope_add_service(const scf_scope_t
*scope
, const char *name
,
2717 return (datael_add_child(&scope
->rd_d
, name
,
2718 REP_PROTOCOL_ENTITY_SERVICE
, (svc
!= NULL
)? &svc
->rd_d
: NULL
));
2722 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2723 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2724 * _BACKEND_ACCESS, _NOT_FOUND.
2727 scf_scope_get_service(const scf_scope_t
*s
, const char *name
,
2730 return (datael_get_child(&s
->rd_d
, name
, REP_PROTOCOL_ENTITY_SERVICE
,
2731 svc
? &svc
->rd_d
: NULL
, 0));
2735 scf_service_handle(const scf_service_t
*val
)
2737 return (datael_handle(&val
->rd_d
));
2741 scf_service_delete(scf_service_t
*svc
)
2743 return (datael_delete(&svc
->rd_d
));
2747 scf_instance_delete(scf_instance_t
*inst
)
2749 return (datael_delete(&inst
->rd_d
));
2753 scf_pg_delete(scf_propertygroup_t
*pg
)
2755 return (datael_delete(&pg
->rd_d
));
2759 _scf_snapshot_delete(scf_snapshot_t
*snap
)
2761 return (datael_delete(&snap
->rd_d
));
2769 * _CONNECTION_BROKEN
2775 * _PERMISSION_DENIED
2780 scf_service_add_instance(const scf_service_t
*svc
, const char *name
,
2781 scf_instance_t
*instance
)
2783 return (datael_add_child(&svc
->rd_d
, name
,
2784 REP_PROTOCOL_ENTITY_INSTANCE
,
2785 (instance
!= NULL
)? &instance
->rd_d
: NULL
));
2790 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2791 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2792 * _BACKEND_ACCESS, _NOT_FOUND.
2795 scf_service_get_instance(const scf_service_t
*svc
, const char *name
,
2796 scf_instance_t
*inst
)
2798 return (datael_get_child(&svc
->rd_d
, name
, REP_PROTOCOL_ENTITY_INSTANCE
,
2799 inst
? &inst
->rd_d
: NULL
, 0));
2803 scf_service_add_pg(const scf_service_t
*svc
, const char *name
,
2804 const char *type
, uint32_t flags
, scf_propertygroup_t
*pg
)
2806 return (datael_add_pg(&svc
->rd_d
, name
, type
, flags
,
2807 (pg
!= NULL
)?&pg
->rd_d
: NULL
));
2811 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2812 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2813 * _BACKEND_ACCESS, _NOT_FOUND.
2816 scf_service_get_pg(const scf_service_t
*svc
, const char *name
,
2817 scf_propertygroup_t
*pg
)
2819 return (datael_get_child(&svc
->rd_d
, name
,
2820 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 0));
2824 scf_instance_add_pg(const scf_instance_t
*inst
, const char *name
,
2825 const char *type
, uint32_t flags
, scf_propertygroup_t
*pg
)
2827 return (datael_add_pg(&inst
->rd_d
, name
, type
, flags
,
2828 (pg
!= NULL
)?&pg
->rd_d
: NULL
));
2832 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2833 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2834 * _BACKEND_ACCESS, _NOT_FOUND.
2837 scf_instance_get_snapshot(const scf_instance_t
*inst
, const char *name
,
2840 return (datael_get_child(&inst
->rd_d
, name
,
2841 REP_PROTOCOL_ENTITY_SNAPSHOT
, pg
? &pg
->rd_d
: NULL
, 0));
2845 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2846 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2847 * _BACKEND_ACCESS, _NOT_FOUND.
2850 scf_instance_get_pg(const scf_instance_t
*inst
, const char *name
,
2851 scf_propertygroup_t
*pg
)
2853 return (datael_get_child(&inst
->rd_d
, name
,
2854 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 0));
2858 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2859 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2860 * _BACKEND_ACCESS, _NOT_FOUND.
2863 scf_instance_get_pg_composed(const scf_instance_t
*inst
,
2864 const scf_snapshot_t
*snap
, const char *name
, scf_propertygroup_t
*pg
)
2866 if (snap
!= NULL
&& inst
->rd_d
.rd_handle
!= snap
->rd_d
.rd_handle
)
2867 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2869 return (datael_get_child(snap
? &snap
->rd_d
: &inst
->rd_d
, name
,
2870 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 1));
2874 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2875 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2876 * _BACKEND_ACCESS, _NOT_FOUND.
2879 scf_pg_get_property(const scf_propertygroup_t
*pg
, const char *name
,
2880 scf_property_t
*prop
)
2882 return (datael_get_child(&pg
->rd_d
, name
, REP_PROTOCOL_ENTITY_PROPERTY
,
2883 prop
? &prop
->rd_d
: NULL
, 0));
2887 scf_service_destroy(scf_service_t
*val
)
2892 datael_destroy(&val
->rd_d
);
2897 scf_service_get_name(const scf_service_t
*rep
, char *out
, size_t len
)
2899 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2903 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2904 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2907 scf_instance_create(scf_handle_t
*handle
)
2909 scf_instance_t
*ret
;
2911 ret
= uu_zalloc(sizeof (*ret
));
2913 if (datael_init(&ret
->rd_d
, handle
,
2914 REP_PROTOCOL_ENTITY_INSTANCE
) == -1) {
2919 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2926 scf_instance_handle(const scf_instance_t
*val
)
2928 return (datael_handle(&val
->rd_d
));
2932 scf_instance_destroy(scf_instance_t
*val
)
2937 datael_destroy(&val
->rd_d
);
2942 scf_instance_get_name(const scf_instance_t
*rep
, char *out
, size_t len
)
2944 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2948 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2949 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2952 scf_snapshot_create(scf_handle_t
*handle
)
2954 scf_snapshot_t
*ret
;
2956 ret
= uu_zalloc(sizeof (*ret
));
2958 if (datael_init(&ret
->rd_d
, handle
,
2959 REP_PROTOCOL_ENTITY_SNAPSHOT
) == -1) {
2964 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2971 scf_snapshot_handle(const scf_snapshot_t
*val
)
2973 return (datael_handle(&val
->rd_d
));
2977 scf_snapshot_destroy(scf_snapshot_t
*val
)
2982 datael_destroy(&val
->rd_d
);
2987 scf_snapshot_get_name(const scf_snapshot_t
*rep
, char *out
, size_t len
)
2989 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2993 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2994 * (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY.
2997 scf_snaplevel_create(scf_handle_t
*handle
)
2999 scf_snaplevel_t
*ret
;
3001 ret
= uu_zalloc(sizeof (*ret
));
3003 if (datael_init(&ret
->rd_d
, handle
,
3004 REP_PROTOCOL_ENTITY_SNAPLEVEL
) == -1) {
3009 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3016 scf_snaplevel_handle(const scf_snaplevel_t
*val
)
3018 return (datael_handle(&val
->rd_d
));
3022 scf_snaplevel_destroy(scf_snaplevel_t
*val
)
3027 datael_destroy(&val
->rd_d
);
3032 scf_snaplevel_get_scope_name(const scf_snaplevel_t
*rep
, char *out
, size_t len
)
3034 return (datael_get_name(&rep
->rd_d
, out
, len
,
3035 RP_ENTITY_NAME_SNAPLEVEL_SCOPE
));
3039 scf_snaplevel_get_service_name(const scf_snaplevel_t
*rep
, char *out
,
3042 return (datael_get_name(&rep
->rd_d
, out
, len
,
3043 RP_ENTITY_NAME_SNAPLEVEL_SERVICE
));
3047 scf_snaplevel_get_instance_name(const scf_snaplevel_t
*rep
, char *out
,
3050 return (datael_get_name(&rep
->rd_d
, out
, len
,
3051 RP_ENTITY_NAME_SNAPLEVEL_INSTANCE
));
3055 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3056 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3057 * _BACKEND_ACCESS, _NOT_FOUND.
3060 scf_snaplevel_get_pg(const scf_snaplevel_t
*snap
, const char *name
,
3061 scf_propertygroup_t
*pg
)
3063 return (datael_get_child(&snap
->rd_d
, name
,
3064 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 0));
3068 snaplevel_next(const scf_datael_t
*src
, scf_snaplevel_t
*dst_arg
)
3070 scf_handle_t
*h
= src
->rd_handle
;
3071 scf_snaplevel_t
*dst
= dst_arg
;
3072 struct rep_protocol_entity_pair request
;
3073 struct rep_protocol_response response
;
3077 if (h
!= dst
->rd_d
.rd_handle
)
3078 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3080 if (src
== &dst
->rd_d
) {
3082 dst
= HANDLE_HOLD_SNAPLVL(h
);
3084 (void) pthread_mutex_lock(&h
->rh_lock
);
3085 request
.rpr_request
= REP_PROTOCOL_NEXT_SNAPLEVEL
;
3086 request
.rpr_entity_src
= src
->rd_entity
;
3087 request
.rpr_entity_dst
= dst
->rd_d
.rd_entity
;
3089 datael_finish_reset(src
);
3090 datael_finish_reset(&dst
->rd_d
);
3091 r
= make_door_call(h
, &request
, sizeof (request
),
3092 &response
, sizeof (response
));
3094 * if we succeeded, we need to swap dst and dst_arg's identity. We
3095 * take advantage of the fact that the only in-library knowledge is
3098 if (dups
&& r
>= 0 &&
3099 (response
.rpr_response
== REP_PROTOCOL_SUCCESS
||
3100 response
.rpr_response
== REP_PROTOCOL_DONE
)) {
3101 int entity
= dst
->rd_d
.rd_entity
;
3103 dst
->rd_d
.rd_entity
= dst_arg
->rd_d
.rd_entity
;
3104 dst_arg
->rd_d
.rd_entity
= entity
;
3106 (void) pthread_mutex_unlock(&h
->rh_lock
);
3109 HANDLE_RELE_SNAPLVL(h
);
3112 DOOR_ERRORS_BLOCK(r
);
3114 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
3115 response
.rpr_response
!= REP_PROTOCOL_DONE
) {
3116 return (scf_set_error(proto_error(response
.rpr_response
)));
3119 return (response
.rpr_response
== REP_PROTOCOL_SUCCESS
) ?
3120 SCF_SUCCESS
: SCF_COMPLETE
;
3123 int scf_snapshot_get_base_snaplevel(const scf_snapshot_t
*base
,
3124 scf_snaplevel_t
*out
)
3126 return (snaplevel_next(&base
->rd_d
, out
));
3129 int scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t
*base
,
3130 scf_snaplevel_t
*out
)
3132 return (snaplevel_next(&base
->rd_d
, out
));
3136 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3137 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3139 scf_propertygroup_t
*
3140 scf_pg_create(scf_handle_t
*handle
)
3142 scf_propertygroup_t
*ret
;
3143 ret
= uu_zalloc(sizeof (*ret
));
3145 if (datael_init(&ret
->rd_d
, handle
,
3146 REP_PROTOCOL_ENTITY_PROPERTYGRP
) == -1) {
3151 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3158 scf_pg_handle(const scf_propertygroup_t
*val
)
3160 return (datael_handle(&val
->rd_d
));
3164 scf_pg_destroy(scf_propertygroup_t
*val
)
3169 datael_destroy(&val
->rd_d
);
3174 scf_pg_get_name(const scf_propertygroup_t
*pg
, char *out
, size_t len
)
3176 return (datael_get_name(&pg
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
3180 scf_pg_get_type(const scf_propertygroup_t
*pg
, char *out
, size_t len
)
3182 return (datael_get_name(&pg
->rd_d
, out
, len
, RP_ENTITY_NAME_PGTYPE
));
3186 scf_pg_get_flags(const scf_propertygroup_t
*pg
, uint32_t *out
)
3188 char buf
[REP_PROTOCOL_NAME_LEN
];
3191 res
= datael_get_name(&pg
->rd_d
, buf
, sizeof (buf
),
3192 RP_ENTITY_NAME_PGFLAGS
);
3197 if (uu_strtouint(buf
, out
, sizeof (*out
), 0, 0, UINT32_MAX
) == -1)
3198 return (scf_set_error(SCF_ERROR_INTERNAL
));
3204 datael_update(scf_datael_t
*dp
)
3206 scf_handle_t
*h
= dp
->rd_handle
;
3208 struct rep_protocol_entity_update request
;
3209 struct rep_protocol_response response
;
3213 (void) pthread_mutex_lock(&h
->rh_lock
);
3214 request
.rpr_request
= REP_PROTOCOL_ENTITY_UPDATE
;
3215 request
.rpr_entityid
= dp
->rd_entity
;
3217 datael_finish_reset(dp
);
3218 request
.rpr_changeid
= handle_next_changeid(h
);
3220 r
= make_door_call(h
, &request
, sizeof (request
),
3221 &response
, sizeof (response
));
3222 (void) pthread_mutex_unlock(&h
->rh_lock
);
3225 DOOR_ERRORS_BLOCK(r
);
3228 * This should never happen but if it does something has
3229 * gone terribly wrong and we should abort.
3231 if (response
.rpr_response
== REP_PROTOCOL_FAIL_BAD_REQUEST
)
3234 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
3235 response
.rpr_response
!= REP_PROTOCOL_DONE
) {
3236 return (scf_set_error(proto_error(response
.rpr_response
)));
3239 return (response
.rpr_response
== REP_PROTOCOL_SUCCESS
) ?
3240 SCF_SUCCESS
: SCF_COMPLETE
;
3244 scf_pg_update(scf_propertygroup_t
*pg
)
3246 return (datael_update(&pg
->rd_d
));
3250 scf_snapshot_update(scf_snapshot_t
*snap
)
3252 return (datael_update(&snap
->rd_d
));
3256 _scf_pg_wait(scf_propertygroup_t
*pg
, int timeout
)
3258 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
3260 struct rep_protocol_propertygrp_request request
;
3261 struct rep_protocol_response response
;
3263 struct pollfd pollfd
;
3267 (void) pthread_mutex_lock(&h
->rh_lock
);
3268 request
.rpr_request
= REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT
;
3269 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
3271 datael_finish_reset(&pg
->rd_d
);
3272 if (!handle_is_bound(h
)) {
3273 (void) pthread_mutex_unlock(&h
->rh_lock
);
3274 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
3276 r
= make_door_call_retfd(h
->rh_doorfd
, &request
, sizeof (request
),
3277 &response
, sizeof (response
), &pollfd
.fd
);
3278 (void) pthread_mutex_unlock(&h
->rh_lock
);
3281 DOOR_ERRORS_BLOCK(r
);
3283 assert((response
.rpr_response
== REP_PROTOCOL_SUCCESS
) ==
3286 if (response
.rpr_response
== REP_PROTOCOL_FAIL_NOT_LATEST
)
3287 return (SCF_SUCCESS
);
3289 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3290 return (scf_set_error(proto_error(response
.rpr_response
)));
3295 r
= poll(&pollfd
, 1, timeout
* MILLISEC
);
3297 (void) close(pollfd
.fd
);
3298 return (pollfd
.revents
? SCF_SUCCESS
: SCF_COMPLETE
);
3302 scf_notify_add_pattern(scf_handle_t
*h
, int type
, const char *name
)
3304 struct rep_protocol_notify_request request
;
3305 struct rep_protocol_response response
;
3308 (void) pthread_mutex_lock(&h
->rh_lock
);
3309 request
.rpr_request
= REP_PROTOCOL_CLIENT_ADD_NOTIFY
;
3310 request
.rpr_type
= type
;
3311 (void) strlcpy(request
.rpr_pattern
, name
, sizeof (request
.rpr_pattern
));
3313 r
= make_door_call(h
, &request
, sizeof (request
),
3314 &response
, sizeof (response
));
3315 (void) pthread_mutex_unlock(&h
->rh_lock
);
3318 DOOR_ERRORS_BLOCK(r
);
3320 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3321 return (scf_set_error(proto_error(response
.rpr_response
)));
3323 return (SCF_SUCCESS
);
3327 _scf_notify_add_pgname(scf_handle_t
*h
, const char *name
)
3329 return (scf_notify_add_pattern(h
, REP_PROTOCOL_NOTIFY_PGNAME
, name
));
3333 _scf_notify_add_pgtype(scf_handle_t
*h
, const char *type
)
3335 return (scf_notify_add_pattern(h
, REP_PROTOCOL_NOTIFY_PGTYPE
, type
));
3339 _scf_notify_wait(scf_propertygroup_t
*pg
, char *out
, size_t sz
)
3341 struct rep_protocol_wait_request request
;
3342 struct rep_protocol_fmri_response response
;
3344 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
3349 (void) pthread_mutex_lock(&h
->rh_lock
);
3350 datael_finish_reset(&pg
->rd_d
);
3351 if (!handle_is_bound(h
)) {
3352 (void) pthread_mutex_unlock(&h
->rh_lock
);
3353 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
3357 assert(h
->rh_fd_users
> 0);
3359 request
.rpr_request
= REP_PROTOCOL_CLIENT_WAIT
;
3360 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
3361 (void) pthread_mutex_unlock(&h
->rh_lock
);
3363 r
= make_door_call_retfd(fd
, &request
, sizeof (request
),
3364 &response
, sizeof (response
), &dummy
);
3366 (void) pthread_mutex_lock(&h
->rh_lock
);
3367 assert(h
->rh_fd_users
> 0);
3368 if (--h
->rh_fd_users
== 0) {
3369 (void) pthread_cond_broadcast(&h
->rh_cv
);
3371 * check for a delayed close, now that there are no other
3374 if (h
->rh_doorfd_old
!= -1) {
3375 assert(h
->rh_doorfd
== -1);
3376 assert(fd
== h
->rh_doorfd_old
);
3377 (void) close(h
->rh_doorfd_old
);
3378 h
->rh_doorfd_old
= -1;
3381 handle_unrefed(h
); /* drops h->rh_lock */
3384 DOOR_ERRORS_BLOCK(r
);
3386 if (response
.rpr_response
== REP_PROTOCOL_DONE
)
3387 return (scf_set_error(SCF_ERROR_NOT_SET
));
3389 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3390 return (scf_set_error(proto_error(response
.rpr_response
)));
3392 /* the following will be non-zero for delete notifications */
3393 return (strlcpy(out
, response
.rpr_fmri
, sz
));
3397 _scf_snapshot_take(scf_instance_t
*inst
, const char *name
,
3398 scf_snapshot_t
*snap
, int flags
)
3400 scf_handle_t
*h
= inst
->rd_d
.rd_handle
;
3402 struct rep_protocol_snapshot_take request
;
3403 struct rep_protocol_response response
;
3407 if (h
!= snap
->rd_d
.rd_handle
)
3408 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3410 if (strlcpy(request
.rpr_name
, (name
!= NULL
)? name
: "",
3411 sizeof (request
.rpr_name
)) >= sizeof (request
.rpr_name
))
3412 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3414 (void) pthread_mutex_lock(&h
->rh_lock
);
3415 request
.rpr_request
= REP_PROTOCOL_SNAPSHOT_TAKE
;
3416 request
.rpr_entityid_src
= inst
->rd_d
.rd_entity
;
3417 request
.rpr_entityid_dest
= snap
->rd_d
.rd_entity
;
3418 request
.rpr_flags
= flags
;
3420 datael_finish_reset(&inst
->rd_d
);
3421 datael_finish_reset(&snap
->rd_d
);
3423 r
= make_door_call(h
, &request
, sizeof (request
),
3424 &response
, sizeof (response
));
3425 (void) pthread_mutex_unlock(&h
->rh_lock
);
3428 DOOR_ERRORS_BLOCK(r
);
3430 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3431 return (scf_set_error(proto_error(response
.rpr_response
)));
3433 return (SCF_SUCCESS
);
3437 _scf_snapshot_take_new_named(scf_instance_t
*inst
,
3438 const char *svcname
, const char *instname
, const char *snapname
,
3439 scf_snapshot_t
*snap
)
3441 scf_handle_t
*h
= inst
->rd_d
.rd_handle
;
3443 struct rep_protocol_snapshot_take_named request
;
3444 struct rep_protocol_response response
;
3448 if (h
!= snap
->rd_d
.rd_handle
)
3449 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3451 if (strlcpy(request
.rpr_svcname
, svcname
,
3452 sizeof (request
.rpr_svcname
)) >= sizeof (request
.rpr_svcname
))
3453 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3455 if (strlcpy(request
.rpr_instname
, instname
,
3456 sizeof (request
.rpr_instname
)) >= sizeof (request
.rpr_instname
))
3457 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3459 if (strlcpy(request
.rpr_name
, snapname
,
3460 sizeof (request
.rpr_name
)) >= sizeof (request
.rpr_name
))
3461 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3463 (void) pthread_mutex_lock(&h
->rh_lock
);
3464 request
.rpr_request
= REP_PROTOCOL_SNAPSHOT_TAKE_NAMED
;
3465 request
.rpr_entityid_src
= inst
->rd_d
.rd_entity
;
3466 request
.rpr_entityid_dest
= snap
->rd_d
.rd_entity
;
3468 datael_finish_reset(&inst
->rd_d
);
3469 datael_finish_reset(&snap
->rd_d
);
3471 r
= make_door_call(h
, &request
, sizeof (request
),
3472 &response
, sizeof (response
));
3473 (void) pthread_mutex_unlock(&h
->rh_lock
);
3476 DOOR_ERRORS_BLOCK(r
);
3478 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
3479 assert(response
.rpr_response
!=
3480 REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
3481 return (scf_set_error(proto_error(response
.rpr_response
)));
3484 return (SCF_SUCCESS
);
3488 _scf_snapshot_take_new(scf_instance_t
*inst
, const char *name
,
3489 scf_snapshot_t
*snap
)
3491 return (_scf_snapshot_take(inst
, name
, snap
, REP_SNAPSHOT_NEW
));
3495 _scf_snapshot_take_attach(scf_instance_t
*inst
, scf_snapshot_t
*snap
)
3497 return (_scf_snapshot_take(inst
, NULL
, snap
, REP_SNAPSHOT_ATTACH
));
3501 _scf_snapshot_attach(scf_snapshot_t
*src
, scf_snapshot_t
*dest
)
3503 scf_handle_t
*h
= dest
->rd_d
.rd_handle
;
3505 struct rep_protocol_snapshot_attach request
;
3506 struct rep_protocol_response response
;
3510 if (h
!= src
->rd_d
.rd_handle
)
3511 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3513 (void) pthread_mutex_lock(&h
->rh_lock
);
3514 request
.rpr_request
= REP_PROTOCOL_SNAPSHOT_ATTACH
;
3515 request
.rpr_entityid_src
= src
->rd_d
.rd_entity
;
3516 request
.rpr_entityid_dest
= dest
->rd_d
.rd_entity
;
3518 datael_finish_reset(&src
->rd_d
);
3519 datael_finish_reset(&dest
->rd_d
);
3521 r
= make_door_call(h
, &request
, sizeof (request
),
3522 &response
, sizeof (response
));
3523 (void) pthread_mutex_unlock(&h
->rh_lock
);
3526 DOOR_ERRORS_BLOCK(r
);
3528 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3529 return (scf_set_error(proto_error(response
.rpr_response
)));
3531 return (SCF_SUCCESS
);
3535 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3536 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3539 scf_property_create(scf_handle_t
*handle
)
3541 scf_property_t
*ret
;
3542 ret
= uu_zalloc(sizeof (*ret
));
3544 if (datael_init(&ret
->rd_d
, handle
,
3545 REP_PROTOCOL_ENTITY_PROPERTY
) == -1) {
3550 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3557 scf_property_handle(const scf_property_t
*val
)
3559 return (datael_handle(&val
->rd_d
));
3563 scf_property_destroy(scf_property_t
*val
)
3568 datael_destroy(&val
->rd_d
);
3573 property_type_locked(const scf_property_t
*prop
,
3574 rep_protocol_value_type_t
*out
)
3576 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
3578 struct rep_protocol_property_request request
;
3579 struct rep_protocol_integer_response response
;
3583 assert(MUTEX_HELD(&h
->rh_lock
));
3585 request
.rpr_request
= REP_PROTOCOL_PROPERTY_GET_TYPE
;
3586 request
.rpr_entityid
= prop
->rd_d
.rd_entity
;
3588 datael_finish_reset(&prop
->rd_d
);
3589 r
= make_door_call(h
, &request
, sizeof (request
),
3590 &response
, sizeof (response
));
3593 DOOR_ERRORS_BLOCK(r
);
3595 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
||
3596 r
< sizeof (response
)) {
3597 return (scf_set_error(proto_error(response
.rpr_response
)));
3599 *out
= response
.rpr_value
;
3600 return (SCF_SUCCESS
);
3604 scf_property_type(const scf_property_t
*prop
, scf_type_t
*out
)
3606 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
3607 rep_protocol_value_type_t out_raw
;
3610 (void) pthread_mutex_lock(&h
->rh_lock
);
3611 ret
= property_type_locked(prop
, &out_raw
);
3612 (void) pthread_mutex_unlock(&h
->rh_lock
);
3614 if (ret
== SCF_SUCCESS
)
3615 *out
= scf_protocol_type_to_type(out_raw
);
3621 scf_property_is_type(const scf_property_t
*prop
, scf_type_t base_arg
)
3623 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
3624 rep_protocol_value_type_t base
= scf_type_to_protocol_type(base_arg
);
3625 rep_protocol_value_type_t type
;
3628 if (base
== REP_PROTOCOL_TYPE_INVALID
)
3629 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3631 (void) pthread_mutex_lock(&h
->rh_lock
);
3632 ret
= property_type_locked(prop
, &type
);
3633 (void) pthread_mutex_unlock(&h
->rh_lock
);
3635 if (ret
== SCF_SUCCESS
) {
3636 if (!scf_is_compatible_protocol_type(base
, type
))
3637 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
3643 scf_is_compatible_type(scf_type_t base_arg
, scf_type_t type_arg
)
3645 rep_protocol_value_type_t base
= scf_type_to_protocol_type(base_arg
);
3646 rep_protocol_value_type_t type
= scf_type_to_protocol_type(type_arg
);
3648 if (base
== REP_PROTOCOL_TYPE_INVALID
||
3649 type
== REP_PROTOCOL_TYPE_INVALID
)
3650 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3652 if (!scf_is_compatible_protocol_type(base
, type
))
3653 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
3655 return (SCF_SUCCESS
);
3659 scf_property_get_name(const scf_property_t
*prop
, char *out
, size_t len
)
3661 return (datael_get_name(&prop
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
3665 * transaction functions
3669 * Fails with _NO_MEMORY, _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED,
3670 * _INTERNAL (bad server response or id in use), or _NO_RESOURCES.
3673 scf_transaction_create(scf_handle_t
*handle
)
3675 scf_transaction_t
*ret
;
3677 ret
= uu_zalloc(sizeof (scf_transaction_t
));
3679 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3682 if (datael_init(&ret
->tran_pg
.rd_d
, handle
,
3683 REP_PROTOCOL_ENTITY_PROPERTYGRP
) == -1) {
3685 return (NULL
); /* error already set */
3687 ret
->tran_state
= TRAN_STATE_NEW
;
3688 ret
->tran_props
= uu_list_create(tran_entry_pool
, ret
, UU_LIST_SORTED
);
3689 if (ret
->tran_props
== NULL
) {
3690 datael_destroy(&ret
->tran_pg
.rd_d
);
3692 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3700 scf_transaction_handle(const scf_transaction_t
*val
)
3702 return (handle_get(val
->tran_pg
.rd_d
.rd_handle
));
3706 scf_transaction_start(scf_transaction_t
*tran
, scf_propertygroup_t
*pg
)
3708 scf_handle_t
*h
= tran
->tran_pg
.rd_d
.rd_handle
;
3710 struct rep_protocol_transaction_start request
;
3711 struct rep_protocol_response response
;
3714 if (h
!= pg
->rd_d
.rd_handle
)
3715 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3717 (void) pthread_mutex_lock(&h
->rh_lock
);
3718 if (tran
->tran_state
!= TRAN_STATE_NEW
) {
3719 (void) pthread_mutex_unlock(&h
->rh_lock
);
3720 return (scf_set_error(SCF_ERROR_IN_USE
));
3722 request
.rpr_request
= REP_PROTOCOL_PROPERTYGRP_TX_START
;
3723 request
.rpr_entityid_tx
= tran
->tran_pg
.rd_d
.rd_entity
;
3724 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
3726 datael_finish_reset(&tran
->tran_pg
.rd_d
);
3727 datael_finish_reset(&pg
->rd_d
);
3729 r
= make_door_call(h
, &request
, sizeof (request
),
3730 &response
, sizeof (response
));
3733 (void) pthread_mutex_unlock(&h
->rh_lock
);
3734 DOOR_ERRORS_BLOCK(r
);
3737 /* r < sizeof (response) cannot happen because sizeof (response) == 4 */
3739 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
||
3740 r
< sizeof (response
)) {
3741 (void) pthread_mutex_unlock(&h
->rh_lock
);
3742 return (scf_set_error(proto_error(response
.rpr_response
)));
3745 tran
->tran_state
= TRAN_STATE_SETUP
;
3746 tran
->tran_invalid
= 0;
3747 (void) pthread_mutex_unlock(&h
->rh_lock
);
3748 return (SCF_SUCCESS
);
3752 entry_invalidate(scf_transaction_entry_t
*cur
, int and_destroy
,
3753 int and_reset_value
)
3755 scf_value_t
*v
, *next
;
3756 scf_transaction_t
*tx
;
3757 scf_handle_t
*h
= cur
->entry_handle
;
3759 assert(MUTEX_HELD(&h
->rh_lock
));
3761 if ((tx
= cur
->entry_tx
) != NULL
) {
3762 tx
->tran_invalid
= 1;
3763 uu_list_remove(tx
->tran_props
, cur
);
3764 cur
->entry_tx
= NULL
;
3767 cur
->entry_property
= NULL
;
3768 cur
->entry_state
= ENTRY_STATE_INVALID
;
3769 cur
->entry_action
= REP_PROTOCOL_TX_ENTRY_INVALID
;
3770 cur
->entry_type
= REP_PROTOCOL_TYPE_INVALID
;
3772 for (v
= cur
->entry_head
; v
!= NULL
; v
= next
) {
3773 next
= v
->value_next
;
3775 v
->value_next
= NULL
;
3776 if (and_destroy
|| and_reset_value
)
3777 scf_value_reset_locked(v
, and_destroy
);
3779 cur
->entry_head
= NULL
;
3780 cur
->entry_tail
= NULL
;
3784 entry_destroy_locked(scf_transaction_entry_t
*entry
)
3786 scf_handle_t
*h
= entry
->entry_handle
;
3788 assert(MUTEX_HELD(&h
->rh_lock
));
3790 entry_invalidate(entry
, 0, 0);
3792 entry
->entry_handle
= NULL
;
3793 assert(h
->rh_entries
> 0);
3796 uu_list_node_fini(entry
, &entry
->entry_link
, tran_entry_pool
);
3801 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3802 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3803 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3806 transaction_add(scf_transaction_t
*tran
, scf_transaction_entry_t
*entry
,
3807 enum rep_protocol_transaction_action action
,
3808 const char *prop
, rep_protocol_value_type_t type
)
3810 scf_handle_t
*h
= tran
->tran_pg
.rd_d
.rd_handle
;
3811 scf_transaction_entry_t
*old
;
3812 scf_property_t
*prop_p
;
3813 rep_protocol_value_type_t oldtype
;
3814 scf_error_t error
= SCF_ERROR_NONE
;
3816 uu_list_index_t idx
;
3818 if (h
!= entry
->entry_handle
)
3819 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3821 if (action
== REP_PROTOCOL_TX_ENTRY_DELETE
)
3822 assert(type
== REP_PROTOCOL_TYPE_INVALID
);
3823 else if (type
== REP_PROTOCOL_TYPE_INVALID
)
3824 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3826 prop_p
= HANDLE_HOLD_PROPERTY(h
);
3828 (void) pthread_mutex_lock(&h
->rh_lock
);
3829 if (tran
->tran_state
!= TRAN_STATE_SETUP
) {
3830 error
= SCF_ERROR_NOT_SET
;
3833 if (tran
->tran_invalid
) {
3834 error
= SCF_ERROR_NOT_SET
;
3838 if (entry
->entry_state
!= ENTRY_STATE_INVALID
)
3839 entry_invalidate(entry
, 0, 0);
3841 old
= uu_list_find(tran
->tran_props
, &prop
, NULL
, &idx
);
3843 error
= SCF_ERROR_IN_USE
;
3847 ret
= datael_get_child_locked(&tran
->tran_pg
.rd_d
, prop
,
3848 REP_PROTOCOL_ENTITY_PROPERTY
, &prop_p
->rd_d
);
3849 if (ret
== -1 && (error
= scf_error()) != SCF_ERROR_NOT_FOUND
) {
3854 case REP_PROTOCOL_TX_ENTRY_DELETE
:
3856 error
= SCF_ERROR_NOT_FOUND
;
3860 case REP_PROTOCOL_TX_ENTRY_NEW
:
3862 error
= SCF_ERROR_EXISTS
;
3867 case REP_PROTOCOL_TX_ENTRY_CLEAR
:
3868 case REP_PROTOCOL_TX_ENTRY_REPLACE
:
3870 error
= SCF_ERROR_NOT_FOUND
;
3873 if (action
== REP_PROTOCOL_TX_ENTRY_CLEAR
) {
3874 if (property_type_locked(prop_p
, &oldtype
) == -1) {
3875 error
= scf_error();
3878 if (oldtype
!= type
) {
3879 error
= SCF_ERROR_TYPE_MISMATCH
;
3889 (void) strlcpy(entry
->entry_namebuf
, prop
,
3890 sizeof (entry
->entry_namebuf
));
3891 entry
->entry_property
= entry
->entry_namebuf
;
3892 entry
->entry_action
= action
;
3893 entry
->entry_type
= type
;
3895 entry
->entry_state
= ENTRY_STATE_IN_TX_ACTION
;
3896 entry
->entry_tx
= tran
;
3897 uu_list_insert(tran
->tran_props
, entry
, idx
);
3899 (void) pthread_mutex_unlock(&h
->rh_lock
);
3901 HANDLE_RELE_PROPERTY(h
);
3903 return (SCF_SUCCESS
);
3906 (void) pthread_mutex_unlock(&h
->rh_lock
);
3908 HANDLE_RELE_PROPERTY(h
);
3910 return (scf_set_error(error
));
3914 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3915 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3916 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3919 scf_transaction_property_new(scf_transaction_t
*tx
,
3920 scf_transaction_entry_t
*entry
, const char *prop
, scf_type_t type
)
3922 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_NEW
,
3923 prop
, scf_type_to_protocol_type(type
)));
3927 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3928 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3929 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3932 scf_transaction_property_change(scf_transaction_t
*tx
,
3933 scf_transaction_entry_t
*entry
, const char *prop
, scf_type_t type
)
3935 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_CLEAR
,
3936 prop
, scf_type_to_protocol_type(type
)));
3940 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3941 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3942 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3945 scf_transaction_property_change_type(scf_transaction_t
*tx
,
3946 scf_transaction_entry_t
*entry
, const char *prop
, scf_type_t type
)
3948 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_REPLACE
,
3949 prop
, scf_type_to_protocol_type(type
)));
3953 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3954 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3955 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3958 scf_transaction_property_delete(scf_transaction_t
*tx
,
3959 scf_transaction_entry_t
*entry
, const char *prop
)
3961 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_DELETE
,
3962 prop
, REP_PROTOCOL_TYPE_INVALID
));
3965 #define BAD_SIZE (-1UL)
3968 commit_value(caddr_t data
, scf_value_t
*val
, rep_protocol_value_type_t t
)
3972 assert(val
->value_type
== t
);
3974 if (t
== REP_PROTOCOL_TYPE_OPAQUE
) {
3975 len
= scf_opaque_encode(data
, val
->value_value
,
3979 len
= strlcpy(data
, val
->value_value
,
3980 REP_PROTOCOL_VALUE_LEN
);
3982 len
= strlen(val
->value_value
);
3983 if (len
>= REP_PROTOCOL_VALUE_LEN
)
3986 return (len
+ 1); /* count the '\0' */
3990 commit_process(scf_transaction_entry_t
*cur
,
3991 struct rep_protocol_transaction_cmd
*out
)
3996 caddr_t data
= (caddr_t
)out
->rptc_data
;
4000 len
= strlcpy(data
, cur
->entry_property
, REP_PROTOCOL_NAME_LEN
);
4002 out
->rptc_action
= cur
->entry_action
;
4003 out
->rptc_type
= cur
->entry_type
;
4004 out
->rptc_name_len
= len
+ 1;
4006 len
= strlen(cur
->entry_property
);
4009 if (len
>= REP_PROTOCOL_NAME_LEN
)
4012 len
= TX_SIZE(len
+ 1);
4015 val_data
= data
+ len
;
4017 for (child
= cur
->entry_head
; child
!= NULL
;
4018 child
= child
->value_next
) {
4019 assert(cur
->entry_action
!= REP_PROTOCOL_TX_ENTRY_DELETE
);
4021 len
= commit_value(val_data
+ sizeof (uint32_t), child
,
4023 /* LINTED alignment */
4024 *(uint32_t *)val_data
= len
;
4026 len
= commit_value(NULL
, child
, cur
->entry_type
);
4028 if (len
== BAD_SIZE
)
4031 len
+= sizeof (uint32_t);
4038 assert(val_data
- data
== sz
);
4041 out
->rptc_size
= REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz
);
4043 return (REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz
));
4047 scf_transaction_commit(scf_transaction_t
*tran
)
4049 scf_handle_t
*h
= tran
->tran_pg
.rd_d
.rd_handle
;
4051 struct rep_protocol_transaction_commit
*request
;
4052 struct rep_protocol_response response
;
4054 scf_transaction_entry_t
*cur
;
4056 size_t request_size
;
4060 (void) pthread_mutex_lock(&h
->rh_lock
);
4061 if (tran
->tran_state
!= TRAN_STATE_SETUP
||
4062 tran
->tran_invalid
) {
4063 (void) pthread_mutex_unlock(&h
->rh_lock
);
4064 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4068 for (cur
= uu_list_first(tran
->tran_props
); cur
!= NULL
;
4069 cur
= uu_list_next(tran
->tran_props
, cur
)) {
4070 size
= commit_process(cur
, NULL
);
4071 if (size
== BAD_SIZE
) {
4072 (void) pthread_mutex_unlock(&h
->rh_lock
);
4073 return (scf_set_error(SCF_ERROR_INTERNAL
));
4075 assert(TX_SIZE(size
) == size
);
4079 request_size
= REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(total
);
4080 request
= alloca(request_size
);
4081 (void) memset(request
, '\0', request_size
);
4082 request
->rpr_request
= REP_PROTOCOL_PROPERTYGRP_TX_COMMIT
;
4083 request
->rpr_entityid
= tran
->tran_pg
.rd_d
.rd_entity
;
4084 request
->rpr_size
= request_size
;
4085 cmd
= (uintptr_t)request
->rpr_cmd
;
4087 datael_finish_reset(&tran
->tran_pg
.rd_d
);
4090 for (cur
= uu_list_first(tran
->tran_props
); cur
!= NULL
;
4091 cur
= uu_list_next(tran
->tran_props
, cur
)) {
4092 size
= commit_process(cur
, (void *)cmd
);
4093 if (size
== BAD_SIZE
) {
4094 (void) pthread_mutex_unlock(&h
->rh_lock
);
4095 return (scf_set_error(SCF_ERROR_INTERNAL
));
4100 assert(new_total
== total
);
4102 r
= make_door_call(h
, request
, request_size
,
4103 &response
, sizeof (response
));
4106 (void) pthread_mutex_unlock(&h
->rh_lock
);
4107 DOOR_ERRORS_BLOCK(r
);
4110 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
4111 response
.rpr_response
!= REP_PROTOCOL_FAIL_NOT_LATEST
) {
4112 (void) pthread_mutex_unlock(&h
->rh_lock
);
4113 return (scf_set_error(proto_error(response
.rpr_response
)));
4116 tran
->tran_state
= TRAN_STATE_COMMITTED
;
4117 (void) pthread_mutex_unlock(&h
->rh_lock
);
4118 return (response
.rpr_response
== REP_PROTOCOL_SUCCESS
);
4122 transaction_reset(scf_transaction_t
*tran
)
4124 assert(MUTEX_HELD(&tran
->tran_pg
.rd_d
.rd_handle
->rh_lock
));
4126 tran
->tran_state
= TRAN_STATE_NEW
;
4127 datael_reset_locked(&tran
->tran_pg
.rd_d
);
4131 scf_transaction_reset_impl(scf_transaction_t
*tran
, int and_destroy
,
4132 int and_reset_value
)
4134 scf_transaction_entry_t
*cur
;
4137 (void) pthread_mutex_lock(&tran
->tran_pg
.rd_d
.rd_handle
->rh_lock
);
4139 while ((cur
= uu_list_teardown(tran
->tran_props
, &cookie
)) != NULL
) {
4140 cur
->entry_tx
= NULL
;
4142 assert(cur
->entry_state
== ENTRY_STATE_IN_TX_ACTION
);
4143 cur
->entry_state
= ENTRY_STATE_INVALID
;
4145 entry_invalidate(cur
, and_destroy
, and_reset_value
);
4147 entry_destroy_locked(cur
);
4149 transaction_reset(tran
);
4150 handle_unrefed(tran
->tran_pg
.rd_d
.rd_handle
);
4154 scf_transaction_reset(scf_transaction_t
*tran
)
4156 scf_transaction_reset_impl(tran
, 0, 0);
4160 scf_transaction_reset_all(scf_transaction_t
*tran
)
4162 scf_transaction_reset_impl(tran
, 0, 1);
4166 scf_transaction_destroy(scf_transaction_t
*val
)
4171 scf_transaction_reset(val
);
4173 datael_destroy(&val
->tran_pg
.rd_d
);
4175 uu_list_destroy(val
->tran_props
);
4180 scf_transaction_destroy_children(scf_transaction_t
*tran
)
4185 scf_transaction_reset_impl(tran
, 1, 0);
4188 scf_transaction_entry_t
*
4189 scf_entry_create(scf_handle_t
*h
)
4191 scf_transaction_entry_t
*ret
;
4194 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
4198 ret
= uu_zalloc(sizeof (scf_transaction_entry_t
));
4200 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
4203 ret
->entry_action
= REP_PROTOCOL_TX_ENTRY_INVALID
;
4204 ret
->entry_handle
= h
;
4206 (void) pthread_mutex_lock(&h
->rh_lock
);
4207 if (h
->rh_flags
& HANDLE_DEAD
) {
4208 (void) pthread_mutex_unlock(&h
->rh_lock
);
4210 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED
);
4215 (void) pthread_mutex_unlock(&h
->rh_lock
);
4217 uu_list_node_init(ret
, &ret
->entry_link
, tran_entry_pool
);
4223 scf_entry_handle(const scf_transaction_entry_t
*val
)
4225 return (handle_get(val
->entry_handle
));
4229 scf_entry_reset(scf_transaction_entry_t
*entry
)
4231 scf_handle_t
*h
= entry
->entry_handle
;
4233 (void) pthread_mutex_lock(&h
->rh_lock
);
4234 entry_invalidate(entry
, 0, 0);
4235 (void) pthread_mutex_unlock(&h
->rh_lock
);
4239 scf_entry_destroy_children(scf_transaction_entry_t
*entry
)
4241 scf_handle_t
*h
= entry
->entry_handle
;
4243 (void) pthread_mutex_lock(&h
->rh_lock
);
4244 entry_invalidate(entry
, 1, 0);
4245 handle_unrefed(h
); /* drops h->rh_lock */
4249 scf_entry_destroy(scf_transaction_entry_t
*entry
)
4256 h
= entry
->entry_handle
;
4258 (void) pthread_mutex_lock(&h
->rh_lock
);
4259 entry_destroy_locked(entry
);
4260 handle_unrefed(h
); /* drops h->rh_lock */
4266 * _NOT_SET - has not been added to a transaction
4267 * _INTERNAL - entry is corrupt
4268 * _INVALID_ARGUMENT - entry's transaction is not started or corrupt
4269 * entry is set to delete a property
4270 * v is reset or corrupt
4271 * _TYPE_MISMATCH - entry & v's types aren't compatible
4272 * _IN_USE - v has been added to another entry
4275 scf_entry_add_value(scf_transaction_entry_t
*entry
, scf_value_t
*v
)
4277 scf_handle_t
*h
= entry
->entry_handle
;
4279 if (h
!= v
->value_handle
)
4280 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
4282 (void) pthread_mutex_lock(&h
->rh_lock
);
4284 if (entry
->entry_state
== ENTRY_STATE_INVALID
) {
4285 (void) pthread_mutex_unlock(&h
->rh_lock
);
4286 return (scf_set_error(SCF_ERROR_NOT_SET
));
4289 if (entry
->entry_state
!= ENTRY_STATE_IN_TX_ACTION
) {
4290 (void) pthread_mutex_unlock(&h
->rh_lock
);
4291 return (scf_set_error(SCF_ERROR_INTERNAL
));
4294 if (entry
->entry_tx
->tran_state
!= TRAN_STATE_SETUP
) {
4295 (void) pthread_mutex_unlock(&h
->rh_lock
);
4296 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4299 if (entry
->entry_action
== REP_PROTOCOL_TX_ENTRY_DELETE
) {
4300 (void) pthread_mutex_unlock(&h
->rh_lock
);
4301 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4304 if (v
->value_type
== REP_PROTOCOL_TYPE_INVALID
) {
4305 (void) pthread_mutex_unlock(&h
->rh_lock
);
4306 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4309 if (!scf_is_compatible_protocol_type(entry
->entry_type
,
4311 (void) pthread_mutex_unlock(&h
->rh_lock
);
4312 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
4315 if (v
->value_tx
!= NULL
) {
4316 (void) pthread_mutex_unlock(&h
->rh_lock
);
4317 return (scf_set_error(SCF_ERROR_IN_USE
));
4320 v
->value_tx
= entry
;
4321 v
->value_next
= NULL
;
4322 if (entry
->entry_head
== NULL
) {
4323 entry
->entry_head
= v
;
4324 entry
->entry_tail
= v
;
4326 entry
->entry_tail
->value_next
= v
;
4327 entry
->entry_tail
= v
;
4330 (void) pthread_mutex_unlock(&h
->rh_lock
);
4332 return (SCF_SUCCESS
);
4339 scf_value_create(scf_handle_t
*h
)
4344 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
4348 ret
= uu_zalloc(sizeof (*ret
));
4350 ret
->value_type
= REP_PROTOCOL_TYPE_INVALID
;
4351 ret
->value_handle
= h
;
4352 (void) pthread_mutex_lock(&h
->rh_lock
);
4353 if (h
->rh_flags
& HANDLE_DEAD
) {
4354 (void) pthread_mutex_unlock(&h
->rh_lock
);
4356 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED
);
4361 (void) pthread_mutex_unlock(&h
->rh_lock
);
4363 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
4370 scf_value_reset_locked(scf_value_t
*val
, int and_destroy
)
4373 scf_transaction_entry_t
*te
;
4375 scf_handle_t
*h
= val
->value_handle
;
4376 assert(MUTEX_HELD(&h
->rh_lock
));
4377 if (val
->value_tx
!= NULL
) {
4379 te
->entry_tx
->tran_invalid
= 1;
4381 val
->value_tx
= NULL
;
4383 for (curp
= &te
->entry_head
; *curp
!= NULL
;
4384 curp
= &(*curp
)->value_next
) {
4386 *curp
= val
->value_next
;
4391 assert(curp
== NULL
);
4393 val
->value_type
= REP_PROTOCOL_TYPE_INVALID
;
4396 val
->value_handle
= NULL
;
4397 assert(h
->rh_values
> 0);
4405 scf_value_reset(scf_value_t
*val
)
4407 scf_handle_t
*h
= val
->value_handle
;
4409 (void) pthread_mutex_lock(&h
->rh_lock
);
4410 scf_value_reset_locked(val
, 0);
4411 (void) pthread_mutex_unlock(&h
->rh_lock
);
4415 scf_value_handle(const scf_value_t
*val
)
4417 return (handle_get(val
->value_handle
));
4421 scf_value_destroy(scf_value_t
*val
)
4428 h
= val
->value_handle
;
4430 (void) pthread_mutex_lock(&h
->rh_lock
);
4431 scf_value_reset_locked(val
, 1);
4432 handle_unrefed(h
); /* drops h->rh_lock */
4436 scf_value_base_type(const scf_value_t
*val
)
4438 rep_protocol_value_type_t t
, cur
;
4439 scf_handle_t
*h
= val
->value_handle
;
4441 (void) pthread_mutex_lock(&h
->rh_lock
);
4442 t
= val
->value_type
;
4443 (void) pthread_mutex_unlock(&h
->rh_lock
);
4446 cur
= scf_proto_underlying_type(t
);
4452 return (scf_protocol_type_to_type(t
));
4456 scf_value_type(const scf_value_t
*val
)
4458 rep_protocol_value_type_t t
;
4459 scf_handle_t
*h
= val
->value_handle
;
4461 (void) pthread_mutex_lock(&h
->rh_lock
);
4462 t
= val
->value_type
;
4463 (void) pthread_mutex_unlock(&h
->rh_lock
);
4465 return (scf_protocol_type_to_type(t
));
4469 scf_value_is_type(const scf_value_t
*val
, scf_type_t base_arg
)
4471 rep_protocol_value_type_t t
;
4472 rep_protocol_value_type_t base
= scf_type_to_protocol_type(base_arg
);
4473 scf_handle_t
*h
= val
->value_handle
;
4475 (void) pthread_mutex_lock(&h
->rh_lock
);
4476 t
= val
->value_type
;
4477 (void) pthread_mutex_unlock(&h
->rh_lock
);
4479 if (t
== REP_PROTOCOL_TYPE_INVALID
)
4480 return (scf_set_error(SCF_ERROR_NOT_SET
));
4481 if (base
== REP_PROTOCOL_TYPE_INVALID
)
4482 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4483 if (!scf_is_compatible_protocol_type(base
, t
))
4484 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
4486 return (SCF_SUCCESS
);
4491 * _NOT_SET - val is reset
4492 * _TYPE_MISMATCH - val's type is not compatible with t
4495 scf_value_check_type(const scf_value_t
*val
, rep_protocol_value_type_t t
)
4497 if (val
->value_type
== REP_PROTOCOL_TYPE_INVALID
) {
4498 (void) scf_set_error(SCF_ERROR_NOT_SET
);
4501 if (!scf_is_compatible_protocol_type(t
, val
->value_type
)) {
4502 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH
);
4510 * _NOT_SET - val is reset
4511 * _TYPE_MISMATCH - val is not _TYPE_BOOLEAN
4514 scf_value_get_boolean(const scf_value_t
*val
, uint8_t *out
)
4517 scf_handle_t
*h
= val
->value_handle
;
4520 (void) pthread_mutex_lock(&h
->rh_lock
);
4521 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_BOOLEAN
)) {
4522 (void) pthread_mutex_unlock(&h
->rh_lock
);
4526 c
= val
->value_value
[0];
4527 assert((c
== '0' || c
== '1') && val
->value_value
[1] == 0);
4530 (void) pthread_mutex_unlock(&h
->rh_lock
);
4533 return (SCF_SUCCESS
);
4537 scf_value_get_count(const scf_value_t
*val
, uint64_t *out
)
4539 scf_handle_t
*h
= val
->value_handle
;
4542 (void) pthread_mutex_lock(&h
->rh_lock
);
4543 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_COUNT
)) {
4544 (void) pthread_mutex_unlock(&h
->rh_lock
);
4548 o
= strtoull(val
->value_value
, NULL
, 10);
4549 (void) pthread_mutex_unlock(&h
->rh_lock
);
4552 return (SCF_SUCCESS
);
4556 scf_value_get_integer(const scf_value_t
*val
, int64_t *out
)
4558 scf_handle_t
*h
= val
->value_handle
;
4561 (void) pthread_mutex_lock(&h
->rh_lock
);
4562 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_INTEGER
)) {
4563 (void) pthread_mutex_unlock(&h
->rh_lock
);
4567 o
= strtoll(val
->value_value
, NULL
, 10);
4568 (void) pthread_mutex_unlock(&h
->rh_lock
);
4571 return (SCF_SUCCESS
);
4575 scf_value_get_time(const scf_value_t
*val
, int64_t *sec_out
, int32_t *nsec_out
)
4577 scf_handle_t
*h
= val
->value_handle
;
4582 (void) pthread_mutex_lock(&h
->rh_lock
);
4583 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_TIME
)) {
4584 (void) pthread_mutex_unlock(&h
->rh_lock
);
4588 os
= strtoll(val
->value_value
, &p
, 10);
4590 ons
= strtoul(p
+ 1, NULL
, 10);
4593 (void) pthread_mutex_unlock(&h
->rh_lock
);
4594 if (sec_out
!= NULL
)
4596 if (nsec_out
!= NULL
)
4599 return (SCF_SUCCESS
);
4604 * _NOT_SET - val is reset
4605 * _TYPE_MISMATCH - val's type is not compatible with _TYPE_STRING.
4608 scf_value_get_astring(const scf_value_t
*val
, char *out
, size_t len
)
4611 scf_handle_t
*h
= val
->value_handle
;
4613 (void) pthread_mutex_lock(&h
->rh_lock
);
4614 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_STRING
)) {
4615 (void) pthread_mutex_unlock(&h
->rh_lock
);
4616 return ((ssize_t
)-1);
4618 ret
= (ssize_t
)strlcpy(out
, val
->value_value
, len
);
4619 (void) pthread_mutex_unlock(&h
->rh_lock
);
4624 scf_value_get_ustring(const scf_value_t
*val
, char *out
, size_t len
)
4627 scf_handle_t
*h
= val
->value_handle
;
4629 (void) pthread_mutex_lock(&h
->rh_lock
);
4630 if (!scf_value_check_type(val
, REP_PROTOCOL_SUBTYPE_USTRING
)) {
4631 (void) pthread_mutex_unlock(&h
->rh_lock
);
4632 return ((ssize_t
)-1);
4634 ret
= (ssize_t
)strlcpy(out
, val
->value_value
, len
);
4635 (void) pthread_mutex_unlock(&h
->rh_lock
);
4640 scf_value_get_opaque(const scf_value_t
*v
, void *out
, size_t len
)
4643 scf_handle_t
*h
= v
->value_handle
;
4645 (void) pthread_mutex_lock(&h
->rh_lock
);
4646 if (!scf_value_check_type(v
, REP_PROTOCOL_TYPE_OPAQUE
)) {
4647 (void) pthread_mutex_unlock(&h
->rh_lock
);
4648 return ((ssize_t
)-1);
4650 if (len
> v
->value_size
)
4651 len
= v
->value_size
;
4654 (void) memcpy(out
, v
->value_value
, len
);
4655 (void) pthread_mutex_unlock(&h
->rh_lock
);
4660 scf_value_set_boolean(scf_value_t
*v
, uint8_t new)
4662 scf_handle_t
*h
= v
->value_handle
;
4664 (void) pthread_mutex_lock(&h
->rh_lock
);
4665 scf_value_reset_locked(v
, 0);
4666 v
->value_type
= REP_PROTOCOL_TYPE_BOOLEAN
;
4667 (void) sprintf(v
->value_value
, "%d", (new != 0));
4668 (void) pthread_mutex_unlock(&h
->rh_lock
);
4672 scf_value_set_count(scf_value_t
*v
, uint64_t new)
4674 scf_handle_t
*h
= v
->value_handle
;
4676 (void) pthread_mutex_lock(&h
->rh_lock
);
4677 scf_value_reset_locked(v
, 0);
4678 v
->value_type
= REP_PROTOCOL_TYPE_COUNT
;
4679 (void) sprintf(v
->value_value
, "%llu", (unsigned long long)new);
4680 (void) pthread_mutex_unlock(&h
->rh_lock
);
4684 scf_value_set_integer(scf_value_t
*v
, int64_t new)
4686 scf_handle_t
*h
= v
->value_handle
;
4688 (void) pthread_mutex_lock(&h
->rh_lock
);
4689 scf_value_reset_locked(v
, 0);
4690 v
->value_type
= REP_PROTOCOL_TYPE_INTEGER
;
4691 (void) sprintf(v
->value_value
, "%lld", (long long)new);
4692 (void) pthread_mutex_unlock(&h
->rh_lock
);
4696 scf_value_set_time(scf_value_t
*v
, int64_t new_sec
, int32_t new_nsec
)
4698 scf_handle_t
*h
= v
->value_handle
;
4700 (void) pthread_mutex_lock(&h
->rh_lock
);
4701 scf_value_reset_locked(v
, 0);
4702 if (new_nsec
< 0 || new_nsec
>= NANOSEC
) {
4703 (void) pthread_mutex_unlock(&h
->rh_lock
);
4704 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4706 v
->value_type
= REP_PROTOCOL_TYPE_TIME
;
4708 (void) sprintf(v
->value_value
, "%lld", (long long)new_sec
);
4710 (void) sprintf(v
->value_value
, "%lld.%09u", (long long)new_sec
,
4711 (unsigned)new_nsec
);
4712 (void) pthread_mutex_unlock(&h
->rh_lock
);
4717 scf_value_set_astring(scf_value_t
*v
, const char *new)
4719 scf_handle_t
*h
= v
->value_handle
;
4721 (void) pthread_mutex_lock(&h
->rh_lock
);
4722 scf_value_reset_locked(v
, 0);
4723 if (!scf_validate_encoded_value(REP_PROTOCOL_TYPE_STRING
, new)) {
4724 (void) pthread_mutex_unlock(&h
->rh_lock
);
4725 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4727 if (strlcpy(v
->value_value
, new, sizeof (v
->value_value
)) >=
4728 sizeof (v
->value_value
)) {
4729 (void) pthread_mutex_unlock(&h
->rh_lock
);
4730 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4732 v
->value_type
= REP_PROTOCOL_TYPE_STRING
;
4733 (void) pthread_mutex_unlock(&h
->rh_lock
);
4738 scf_value_set_ustring(scf_value_t
*v
, const char *new)
4740 scf_handle_t
*h
= v
->value_handle
;
4742 (void) pthread_mutex_lock(&h
->rh_lock
);
4743 scf_value_reset_locked(v
, 0);
4744 if (!scf_validate_encoded_value(REP_PROTOCOL_SUBTYPE_USTRING
, new)) {
4745 (void) pthread_mutex_unlock(&h
->rh_lock
);
4746 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4748 if (strlcpy(v
->value_value
, new, sizeof (v
->value_value
)) >=
4749 sizeof (v
->value_value
)) {
4750 (void) pthread_mutex_unlock(&h
->rh_lock
);
4751 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4753 v
->value_type
= REP_PROTOCOL_SUBTYPE_USTRING
;
4754 (void) pthread_mutex_unlock(&h
->rh_lock
);
4759 scf_value_set_opaque(scf_value_t
*v
, const void *new, size_t len
)
4761 scf_handle_t
*h
= v
->value_handle
;
4763 (void) pthread_mutex_lock(&h
->rh_lock
);
4764 scf_value_reset_locked(v
, 0);
4765 if (len
> sizeof (v
->value_value
)) {
4766 (void) pthread_mutex_unlock(&h
->rh_lock
);
4767 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4769 (void) memcpy(v
->value_value
, new, len
);
4770 v
->value_size
= len
;
4771 v
->value_type
= REP_PROTOCOL_TYPE_OPAQUE
;
4772 (void) pthread_mutex_unlock(&h
->rh_lock
);
4778 * _NOT_SET - v_arg is reset
4779 * _INTERNAL - v_arg is corrupt
4781 * If t is not _TYPE_INVALID, fails with
4782 * _TYPE_MISMATCH - v_arg's type is not compatible with t
4785 scf_value_get_as_string_common(const scf_value_t
*v_arg
,
4786 rep_protocol_value_type_t t
, char *buf
, size_t bufsz
)
4788 scf_handle_t
*h
= v_arg
->value_handle
;
4790 scf_value_t
*v
= &v_s
;
4794 (void) pthread_mutex_lock(&h
->rh_lock
);
4795 if (t
!= REP_PROTOCOL_TYPE_INVALID
&& !scf_value_check_type(v_arg
, t
)) {
4796 (void) pthread_mutex_unlock(&h
->rh_lock
);
4800 v_s
= *v_arg
; /* copy locally so we can unlock */
4801 h
->rh_values
++; /* keep the handle from going away */
4803 (void) pthread_mutex_unlock(&h
->rh_lock
);
4806 switch (REP_PROTOCOL_BASE_TYPE(v
->value_type
)) {
4807 case REP_PROTOCOL_TYPE_BOOLEAN
:
4808 r
= scf_value_get_boolean(v
, &b
);
4809 assert(r
== SCF_SUCCESS
);
4811 r
= strlcpy(buf
, b
? "true" : "false", bufsz
);
4814 case REP_PROTOCOL_TYPE_COUNT
:
4815 case REP_PROTOCOL_TYPE_INTEGER
:
4816 case REP_PROTOCOL_TYPE_TIME
:
4817 case REP_PROTOCOL_TYPE_STRING
:
4818 r
= strlcpy(buf
, v
->value_value
, bufsz
);
4821 case REP_PROTOCOL_TYPE_OPAQUE
:
4823 * Note that we only write out full hex bytes -- if they're
4824 * short, and bufsz is even, we'll only fill (bufsz - 2) bytes
4828 (void) scf_opaque_encode(buf
, v
->value_value
,
4829 MIN(v
->value_size
, (bufsz
- 1)/2));
4830 r
= (v
->value_size
* 2);
4833 case REP_PROTOCOL_TYPE_INVALID
:
4834 r
= scf_set_error(SCF_ERROR_NOT_SET
);
4838 r
= (scf_set_error(SCF_ERROR_INTERNAL
));
4842 (void) pthread_mutex_lock(&h
->rh_lock
);
4851 scf_value_get_as_string(const scf_value_t
*v
, char *buf
, size_t bufsz
)
4853 return (scf_value_get_as_string_common(v
, REP_PROTOCOL_TYPE_INVALID
,
4858 scf_value_get_as_string_typed(const scf_value_t
*v
, scf_type_t type
,
4859 char *buf
, size_t bufsz
)
4861 rep_protocol_value_type_t ty
= scf_type_to_protocol_type(type
);
4862 if (ty
== REP_PROTOCOL_TYPE_INVALID
)
4863 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4865 return (scf_value_get_as_string_common(v
, ty
, buf
, bufsz
));
4869 scf_value_set_from_string(scf_value_t
*v
, scf_type_t type
, const char *str
)
4871 scf_handle_t
*h
= v
->value_handle
;
4872 rep_protocol_value_type_t ty
;
4875 case SCF_TYPE_BOOLEAN
: {
4878 if (strcmp(str
, "true") == 0 || strcmp(str
, "t") == 0 ||
4879 strcmp(str
, "1") == 0)
4881 else if (strcmp(str
, "false") == 0 ||
4882 strcmp(str
, "f") == 0 || strcmp(str
, "0") == 0)
4888 scf_value_set_boolean(v
, b
);
4892 case SCF_TYPE_COUNT
: {
4897 c
= strtoull(str
, &endp
, 0);
4899 if (errno
!= 0 || endp
== str
|| *endp
!= '\0')
4902 scf_value_set_count(v
, c
);
4906 case SCF_TYPE_INTEGER
: {
4911 i
= strtoll(str
, &endp
, 0);
4913 if (errno
!= 0 || endp
== str
|| *endp
!= '\0')
4916 scf_value_set_integer(v
, i
);
4920 case SCF_TYPE_TIME
: {
4923 char *endp
, *ns_str
;
4927 s
= strtoll(str
, &endp
, 10);
4928 if (errno
!= 0 || endp
== str
||
4929 (*endp
!= '\0' && *endp
!= '.'))
4934 len
= strlen(ns_str
);
4935 if (len
== 0 || len
> 9)
4938 ns
= strtoul(ns_str
, &endp
, 10);
4939 if (errno
!= 0 || endp
== ns_str
|| *endp
!= '\0')
4944 assert(ns
< NANOSEC
);
4947 return (scf_value_set_time(v
, s
, ns
));
4950 case SCF_TYPE_ASTRING
:
4951 case SCF_TYPE_USTRING
:
4952 case SCF_TYPE_OPAQUE
:
4956 case SCF_TYPE_HOSTNAME
:
4957 case SCF_TYPE_NET_ADDR
:
4958 case SCF_TYPE_NET_ADDR_V4
:
4959 case SCF_TYPE_NET_ADDR_V6
:
4960 ty
= scf_type_to_protocol_type(type
);
4962 (void) pthread_mutex_lock(&h
->rh_lock
);
4963 scf_value_reset_locked(v
, 0);
4964 if (type
== SCF_TYPE_OPAQUE
) {
4965 v
->value_size
= scf_opaque_decode(v
->value_value
,
4966 str
, sizeof (v
->value_value
));
4967 if (!scf_validate_encoded_value(ty
, str
)) {
4968 (void) pthread_mutex_lock(&h
->rh_lock
);
4972 (void) strlcpy(v
->value_value
, str
,
4973 sizeof (v
->value_value
));
4974 if (!scf_validate_encoded_value(ty
, v
->value_value
)) {
4975 (void) pthread_mutex_lock(&h
->rh_lock
);
4980 (void) pthread_mutex_unlock(&h
->rh_lock
);
4981 return (SCF_SUCCESS
);
4983 case REP_PROTOCOL_TYPE_INVALID
:
4986 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
4990 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4994 scf_iter_property_values(scf_iter_t
*iter
, const scf_property_t
*prop
)
4996 return (datael_setup_iter(iter
, &prop
->rd_d
,
4997 REP_PROTOCOL_ENTITY_VALUE
, 0));
5001 scf_iter_next_value(scf_iter_t
*iter
, scf_value_t
*v
)
5003 scf_handle_t
*h
= iter
->iter_handle
;
5005 struct rep_protocol_iter_read_value request
;
5006 struct rep_protocol_value_response response
;
5010 if (h
!= v
->value_handle
)
5011 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5013 (void) pthread_mutex_lock(&h
->rh_lock
);
5015 scf_value_reset_locked(v
, 0);
5017 if (iter
->iter_type
== REP_PROTOCOL_ENTITY_NONE
) {
5018 (void) pthread_mutex_unlock(&h
->rh_lock
);
5019 return (scf_set_error(SCF_ERROR_NOT_SET
));
5022 if (iter
->iter_type
!= REP_PROTOCOL_ENTITY_VALUE
) {
5023 (void) pthread_mutex_unlock(&h
->rh_lock
);
5024 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5027 request
.rpr_request
= REP_PROTOCOL_ITER_READ_VALUE
;
5028 request
.rpr_iterid
= iter
->iter_id
;
5029 request
.rpr_sequence
= iter
->iter_sequence
;
5031 r
= make_door_call(h
, &request
, sizeof (request
),
5032 &response
, sizeof (response
));
5035 (void) pthread_mutex_unlock(&h
->rh_lock
);
5036 DOOR_ERRORS_BLOCK(r
);
5039 if (response
.rpr_response
== REP_PROTOCOL_DONE
) {
5040 (void) pthread_mutex_unlock(&h
->rh_lock
);
5043 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
5044 (void) pthread_mutex_unlock(&h
->rh_lock
);
5045 return (scf_set_error(proto_error(response
.rpr_response
)));
5047 iter
->iter_sequence
++;
5049 v
->value_type
= response
.rpr_type
;
5051 assert(scf_validate_encoded_value(response
.rpr_type
,
5052 response
.rpr_value
));
5054 if (v
->value_type
!= REP_PROTOCOL_TYPE_OPAQUE
) {
5055 (void) strlcpy(v
->value_value
, response
.rpr_value
,
5056 sizeof (v
->value_value
));
5058 v
->value_size
= scf_opaque_decode(v
->value_value
,
5059 response
.rpr_value
, sizeof (v
->value_value
));
5061 (void) pthread_mutex_unlock(&h
->rh_lock
);
5067 scf_property_get_value(const scf_property_t
*prop
, scf_value_t
*v
)
5069 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
5070 struct rep_protocol_property_request request
;
5071 struct rep_protocol_value_response response
;
5074 if (h
!= v
->value_handle
)
5075 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5077 (void) pthread_mutex_lock(&h
->rh_lock
);
5079 request
.rpr_request
= REP_PROTOCOL_PROPERTY_GET_VALUE
;
5080 request
.rpr_entityid
= prop
->rd_d
.rd_entity
;
5082 scf_value_reset_locked(v
, 0);
5083 datael_finish_reset(&prop
->rd_d
);
5085 r
= make_door_call(h
, &request
, sizeof (request
),
5086 &response
, sizeof (response
));
5089 (void) pthread_mutex_unlock(&h
->rh_lock
);
5090 DOOR_ERRORS_BLOCK(r
);
5093 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
5094 response
.rpr_response
!= REP_PROTOCOL_FAIL_TRUNCATED
) {
5095 (void) pthread_mutex_unlock(&h
->rh_lock
);
5096 assert(response
.rpr_response
!=
5097 REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
5098 return (scf_set_error(proto_error(response
.rpr_response
)));
5101 v
->value_type
= response
.rpr_type
;
5102 if (v
->value_type
!= REP_PROTOCOL_TYPE_OPAQUE
) {
5103 (void) strlcpy(v
->value_value
, response
.rpr_value
,
5104 sizeof (v
->value_value
));
5106 v
->value_size
= scf_opaque_decode(v
->value_value
,
5107 response
.rpr_value
, sizeof (v
->value_value
));
5109 (void) pthread_mutex_unlock(&h
->rh_lock
);
5110 return ((response
.rpr_response
== REP_PROTOCOL_SUCCESS
)?
5111 SCF_SUCCESS
: scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
));
5115 scf_pg_get_parent_service(const scf_propertygroup_t
*pg
, scf_service_t
*svc
)
5117 return (datael_get_parent(&pg
->rd_d
, &svc
->rd_d
));
5121 scf_pg_get_parent_instance(const scf_propertygroup_t
*pg
, scf_instance_t
*inst
)
5123 return (datael_get_parent(&pg
->rd_d
, &inst
->rd_d
));
5127 scf_pg_get_parent_snaplevel(const scf_propertygroup_t
*pg
,
5128 scf_snaplevel_t
*level
)
5130 return (datael_get_parent(&pg
->rd_d
, &level
->rd_d
));
5134 scf_service_get_parent(const scf_service_t
*svc
, scf_scope_t
*s
)
5136 return (datael_get_parent(&svc
->rd_d
, &s
->rd_d
));
5140 scf_instance_get_parent(const scf_instance_t
*inst
, scf_service_t
*svc
)
5142 return (datael_get_parent(&inst
->rd_d
, &svc
->rd_d
));
5146 scf_snapshot_get_parent(const scf_snapshot_t
*inst
, scf_instance_t
*svc
)
5148 return (datael_get_parent(&inst
->rd_d
, &svc
->rd_d
));
5152 scf_snaplevel_get_parent(const scf_snaplevel_t
*inst
, scf_snapshot_t
*svc
)
5154 return (datael_get_parent(&inst
->rd_d
, &svc
->rd_d
));
5160 * Note: In the scf_parse_svc_fmri(), scf_parse_file_fmri() and
5161 * scf_parse_fmri(), fmri isn't const because that would require
5162 * allocating memory. Also, note that scope, at least, is not necessarily
5163 * in the passed in fmri.
5167 scf_parse_svc_fmri(char *fmri
, const char **scope
, const char **service
,
5168 const char **instance
, const char **propertygroup
, const char **property
)
5170 char *s
, *e
, *te
, *tpg
;
5171 char *my_s
= NULL
, *my_i
= NULL
, *my_pg
= NULL
, *my_p
= NULL
;
5175 if (service
!= NULL
)
5177 if (instance
!= NULL
)
5179 if (propertygroup
!= NULL
)
5180 *propertygroup
= NULL
;
5181 if (property
!= NULL
)
5185 e
= strchr(s
, '\0');
5187 if (strncmp(s
, SCF_FMRI_SVC_PREFIX
,
5188 sizeof (SCF_FMRI_SVC_PREFIX
) - 1) == 0)
5189 s
+= sizeof (SCF_FMRI_SVC_PREFIX
) - 1;
5191 if (strncmp(s
, SCF_FMRI_SCOPE_PREFIX
,
5192 sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1) == 0) {
5195 s
+= sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1;
5196 te
= strstr(s
, SCF_FMRI_SERVICE_PREFIX
);
5205 s
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5207 /* If the scope ends with the suffix, remove it. */
5208 te
= strstr(my_scope
, SCF_FMRI_SCOPE_SUFFIX
);
5209 if (te
!= NULL
&& te
[sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1] == 0)
5212 /* Validate the scope. */
5213 if (my_scope
[0] == '\0')
5214 my_scope
= SCF_FMRI_LOCAL_SCOPE
;
5215 else if (uu_check_name(my_scope
, 0) == -1) {
5216 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5223 *scope
= SCF_FMRI_LOCAL_SCOPE
;
5227 if (strncmp(s
, SCF_FMRI_SERVICE_PREFIX
,
5228 sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1) == 0)
5229 s
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5232 * Can't validate service here because it might not be null
5238 tpg
= strstr(s
, SCF_FMRI_PROPERTYGRP_PREFIX
);
5239 te
= strstr(s
, SCF_FMRI_INSTANCE_PREFIX
);
5240 if (te
!= NULL
&& (tpg
== NULL
|| te
< tpg
)) {
5242 te
+= sizeof (SCF_FMRI_INSTANCE_PREFIX
) - 1;
5244 /* Can't validate instance here either. */
5247 te
= strstr(s
, SCF_FMRI_PROPERTYGRP_PREFIX
);
5254 te
+= sizeof (SCF_FMRI_PROPERTYGRP_PREFIX
) - 1;
5257 te
= strstr(s
, SCF_FMRI_PROPERTY_PREFIX
);
5260 te
+= sizeof (SCF_FMRI_PROPERTY_PREFIX
) - 1;
5268 if (uu_check_name(my_s
, UU_NAME_DOMAIN
| UU_NAME_PATH
) == -1)
5269 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5271 if (service
!= NULL
)
5276 if (uu_check_name(my_i
, UU_NAME_DOMAIN
) == -1)
5277 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5279 if (instance
!= NULL
)
5283 if (my_pg
!= NULL
) {
5284 if (uu_check_name(my_pg
, UU_NAME_DOMAIN
) == -1)
5285 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5287 if (propertygroup
!= NULL
)
5288 *propertygroup
= my_pg
;
5292 if (uu_check_name(my_p
, UU_NAME_DOMAIN
) == -1)
5293 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5295 if (property
!= NULL
)
5303 scf_parse_file_fmri(char *fmri
, const char **scope
, const char **path
)
5311 e
= strchr(s
, '\0');
5313 if (strncmp(s
, SCF_FMRI_FILE_PREFIX
,
5314 sizeof (SCF_FMRI_FILE_PREFIX
) - 1) == 0)
5315 s
+= sizeof (SCF_FMRI_FILE_PREFIX
) - 1;
5317 if (strncmp(s
, SCF_FMRI_SCOPE_PREFIX
,
5318 sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1) == 0) {
5321 s
+= sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1;
5322 te
= strstr(s
, SCF_FMRI_SERVICE_PREFIX
);
5331 /* Validate the scope. */
5332 if (my_scope
[0] != '\0' &&
5333 strcmp(my_scope
, SCF_FMRI_LOCAL_SCOPE
) != 0) {
5334 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5341 * FMRI paths must be absolute
5344 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5347 s
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5350 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5353 * If the user requests it, return the full path of the file.
5365 scf_parse_fmri(char *fmri
, int *type
, const char **scope
, const char **service
,
5366 const char **instance
, const char **propertygroup
, const char **property
)
5368 if (strncmp(fmri
, SCF_FMRI_SVC_PREFIX
,
5369 sizeof (SCF_FMRI_SVC_PREFIX
) - 1) == 0) {
5371 *type
= SCF_FMRI_TYPE_SVC
;
5372 return (scf_parse_svc_fmri(fmri
, scope
, service
, instance
,
5373 propertygroup
, property
));
5374 } else if (strncmp(fmri
, SCF_FMRI_FILE_PREFIX
,
5375 sizeof (SCF_FMRI_FILE_PREFIX
) - 1) == 0) {
5377 *type
= SCF_FMRI_TYPE_FILE
;
5378 return (scf_parse_file_fmri(fmri
, scope
, NULL
));
5381 * Parse as a svc if the fmri type is not explicitly
5385 *type
= SCF_FMRI_TYPE_SVC
;
5386 return (scf_parse_svc_fmri(fmri
, scope
, service
, instance
,
5387 propertygroup
, property
));
5392 * Fails with _INVALID_ARGUMENT. fmri and buf may be equal.
5395 scf_canonify_fmri(const char *fmri
, char *buf
, size_t bufsz
)
5397 const char *scope
, *service
, *instance
, *pg
, *property
;
5398 char local
[6 * REP_PROTOCOL_NAME_LEN
];
5402 if (strlcpy(local
, fmri
, sizeof (local
)) >= sizeof (local
)) {
5403 /* Should this be CONSTRAINT_VIOLATED? */
5404 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
5409 r
= scf_parse_svc_fmri(local
, &scope
, &service
, &instance
, &pg
,
5414 len
= strlcpy(buf
, "svc:/", bufsz
);
5416 if (scope
!= NULL
&& strcmp(scope
, SCF_SCOPE_LOCAL
) != 0) {
5417 len
+= strlcat(buf
, "/", bufsz
);
5418 len
+= strlcat(buf
, scope
, bufsz
);
5422 len
+= strlcat(buf
, service
, bufsz
);
5425 len
+= strlcat(buf
, ":", bufsz
);
5426 len
+= strlcat(buf
, instance
, bufsz
);
5430 len
+= strlcat(buf
, "/:properties/", bufsz
);
5431 len
+= strlcat(buf
, pg
, bufsz
);
5435 len
+= strlcat(buf
, "/", bufsz
);
5436 len
+= strlcat(buf
, property
, bufsz
);
5443 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _CONSTRAINT_VIOLATED,
5444 * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED,
5445 * _NO_RESOURCES, _BACKEND_ACCESS.
5448 scf_handle_decode_fmri(scf_handle_t
*h
, const char *fmri
, scf_scope_t
*sc
,
5449 scf_service_t
*svc
, scf_instance_t
*inst
, scf_propertygroup_t
*pg
,
5450 scf_property_t
*prop
, int flags
)
5452 const char *scope
, *service
, *instance
, *propertygroup
, *property
;
5454 char local
[6 * REP_PROTOCOL_NAME_LEN
];
5456 const uint32_t holds
= RH_HOLD_SCOPE
| RH_HOLD_SERVICE
|
5457 RH_HOLD_INSTANCE
| RH_HOLD_PG
| RH_HOLD_PROPERTY
;
5460 * verify that all handles match
5462 if ((sc
!= NULL
&& h
!= sc
->rd_d
.rd_handle
) ||
5463 (svc
!= NULL
&& h
!= svc
->rd_d
.rd_handle
) ||
5464 (inst
!= NULL
&& h
!= inst
->rd_d
.rd_handle
) ||
5465 (pg
!= NULL
&& h
!= pg
->rd_d
.rd_handle
) ||
5466 (prop
!= NULL
&& h
!= prop
->rd_d
.rd_handle
))
5467 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5469 if (strlcpy(local
, fmri
, sizeof (local
)) >= sizeof (local
)) {
5470 ret
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
5475 * We can simply return from an error in parsing, because
5476 * scf_parse_fmri sets the error code correctly.
5478 if (scf_parse_svc_fmri(local
, &scope
, &service
, &instance
,
5479 &propertygroup
, &property
) == -1) {
5485 * the FMRI looks valid at this point -- do constraint checks.
5488 if (instance
!= NULL
&& (flags
& SCF_DECODE_FMRI_REQUIRE_NO_INSTANCE
)) {
5489 ret
= scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
);
5492 if (instance
== NULL
&& (flags
& SCF_DECODE_FMRI_REQUIRE_INSTANCE
)) {
5493 ret
= scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
);
5498 last
= REP_PROTOCOL_ENTITY_PROPERTY
;
5499 else if (pg
!= NULL
)
5500 last
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
5501 else if (inst
!= NULL
)
5502 last
= REP_PROTOCOL_ENTITY_INSTANCE
;
5503 else if (svc
!= NULL
)
5504 last
= REP_PROTOCOL_ENTITY_SERVICE
;
5505 else if (sc
!= NULL
)
5506 last
= REP_PROTOCOL_ENTITY_SCOPE
;
5508 last
= REP_PROTOCOL_ENTITY_NONE
;
5510 if (flags
& SCF_DECODE_FMRI_EXACT
) {
5513 if (property
!= NULL
)
5514 last_fmri
= REP_PROTOCOL_ENTITY_PROPERTY
;
5515 else if (propertygroup
!= NULL
)
5516 last_fmri
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
5517 else if (instance
!= NULL
)
5518 last_fmri
= REP_PROTOCOL_ENTITY_INSTANCE
;
5519 else if (service
!= NULL
)
5520 last_fmri
= REP_PROTOCOL_ENTITY_SERVICE
;
5521 else if (scope
!= NULL
)
5522 last_fmri
= REP_PROTOCOL_ENTITY_SCOPE
;
5524 last_fmri
= REP_PROTOCOL_ENTITY_NONE
;
5526 if (last
!= last_fmri
) {
5527 ret
= scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
);
5532 if ((flags
& SCF_DECODE_FMRI_TRUNCATE
) &&
5533 last
== REP_PROTOCOL_ENTITY_NONE
) {
5534 ret
= 0; /* nothing to do */
5538 if (!(flags
& SCF_DECODE_FMRI_TRUNCATE
))
5539 last
= REP_PROTOCOL_ENTITY_NONE
; /* never stop */
5542 * passed the constraint checks -- try to grab the thing itself.
5545 handle_hold_subhandles(h
, holds
);
5549 datael_reset(&sc
->rd_d
);
5552 svc
= h
->rh_service
;
5554 datael_reset(&svc
->rd_d
);
5557 inst
= h
->rh_instance
;
5559 datael_reset(&inst
->rd_d
);
5564 datael_reset(&pg
->rd_d
);
5567 prop
= h
->rh_property
;
5569 datael_reset(&prop
->rd_d
);
5572 * We only support local scopes, but we check *after* getting
5573 * the local scope, so that any repository-related errors take
5576 if (scf_handle_get_scope(h
, SCF_SCOPE_LOCAL
, sc
) == -1) {
5577 handle_rele_subhandles(h
, holds
);
5582 if (scope
!= NULL
&& strcmp(scope
, SCF_FMRI_LOCAL_SCOPE
) != 0) {
5583 handle_rele_subhandles(h
, holds
);
5584 ret
= scf_set_error(SCF_ERROR_NOT_FOUND
);
5589 if (service
== NULL
|| last
== REP_PROTOCOL_ENTITY_SCOPE
) {
5590 handle_rele_subhandles(h
, holds
);
5594 if (scf_scope_get_service(sc
, service
, svc
) == -1) {
5595 handle_rele_subhandles(h
, holds
);
5597 assert(scf_error() != SCF_ERROR_NOT_SET
);
5598 if (scf_error() == SCF_ERROR_DELETED
)
5599 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5603 if (last
== REP_PROTOCOL_ENTITY_SERVICE
) {
5604 handle_rele_subhandles(h
, holds
);
5608 if (instance
== NULL
) {
5609 if (propertygroup
== NULL
||
5610 last
== REP_PROTOCOL_ENTITY_INSTANCE
) {
5611 handle_rele_subhandles(h
, holds
);
5615 if (scf_service_get_pg(svc
, propertygroup
, pg
) == -1) {
5616 handle_rele_subhandles(h
, holds
);
5618 assert(scf_error() != SCF_ERROR_NOT_SET
);
5619 if (scf_error() == SCF_ERROR_DELETED
)
5620 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5624 if (scf_service_get_instance(svc
, instance
, inst
) == -1) {
5625 handle_rele_subhandles(h
, holds
);
5627 assert(scf_error() != SCF_ERROR_NOT_SET
);
5628 if (scf_error() == SCF_ERROR_DELETED
)
5629 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5633 if (propertygroup
== NULL
||
5634 last
== REP_PROTOCOL_ENTITY_INSTANCE
) {
5635 handle_rele_subhandles(h
, holds
);
5639 if (scf_instance_get_pg(inst
, propertygroup
, pg
) == -1) {
5640 handle_rele_subhandles(h
, holds
);
5642 assert(scf_error() != SCF_ERROR_NOT_SET
);
5643 if (scf_error() == SCF_ERROR_DELETED
)
5644 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5649 if (property
== NULL
|| last
== REP_PROTOCOL_ENTITY_PROPERTYGRP
) {
5650 handle_rele_subhandles(h
, holds
);
5654 if (scf_pg_get_property(pg
, property
, prop
) == -1) {
5655 handle_rele_subhandles(h
, holds
);
5657 assert(scf_error() != SCF_ERROR_NOT_SET
);
5658 if (scf_error() == SCF_ERROR_DELETED
)
5659 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5663 handle_rele_subhandles(h
, holds
);
5668 datael_reset(&sc
->rd_d
);
5670 datael_reset(&svc
->rd_d
);
5672 datael_reset(&inst
->rd_d
);
5674 datael_reset(&pg
->rd_d
);
5676 datael_reset(&prop
->rd_d
);
5682 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5683 * big, bad entity id, request not applicable to entity, name too long for
5684 * buffer), _NOT_SET, or _DELETED.
5687 scf_scope_to_fmri(const scf_scope_t
*scope
, char *out
, size_t sz
)
5691 char tmp
[REP_PROTOCOL_NAME_LEN
];
5693 r
= scf_scope_get_name(scope
, tmp
, sizeof (tmp
));
5698 len
= strlcpy(out
, SCF_FMRI_SVC_PREFIX
, sz
);
5699 if (strcmp(tmp
, SCF_FMRI_LOCAL_SCOPE
) != 0) {
5701 return (len
+ r
+ sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1);
5703 len
= strlcat(out
, tmp
, sz
);
5705 return (len
+ sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1);
5707 SCF_FMRI_SCOPE_SUFFIX SCF_FMRI_SERVICE_PREFIX
, sz
);
5714 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5715 * big, bad element id, bad ids, bad types, scope has no parent, request not
5716 * applicable to entity, name too long), _NOT_SET, _DELETED,
5719 scf_service_to_fmri(const scf_service_t
*svc
, char *out
, size_t sz
)
5721 scf_handle_t
*h
= svc
->rd_d
.rd_handle
;
5722 scf_scope_t
*scope
= HANDLE_HOLD_SCOPE(h
);
5725 char tmp
[REP_PROTOCOL_NAME_LEN
];
5727 r
= datael_get_parent(&svc
->rd_d
, &scope
->rd_d
);
5728 if (r
!= SCF_SUCCESS
) {
5729 HANDLE_RELE_SCOPE(h
);
5731 assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH
);
5734 if (out
!= NULL
&& sz
> 0)
5735 len
= scf_scope_to_fmri(scope
, out
, sz
);
5737 len
= scf_scope_to_fmri(scope
, tmp
, 2);
5739 HANDLE_RELE_SCOPE(h
);
5744 if (out
== NULL
|| len
>= sz
)
5745 len
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5747 len
= strlcat(out
, SCF_FMRI_SERVICE_PREFIX
, sz
);
5749 r
= scf_service_get_name(svc
, tmp
, sizeof (tmp
));
5753 if (out
== NULL
|| len
>= sz
)
5756 len
= strlcat(out
, tmp
, sz
);
5762 scf_instance_to_fmri(const scf_instance_t
*inst
, char *out
, size_t sz
)
5764 scf_handle_t
*h
= inst
->rd_d
.rd_handle
;
5765 scf_service_t
*svc
= HANDLE_HOLD_SERVICE(h
);
5768 char tmp
[REP_PROTOCOL_NAME_LEN
];
5770 r
= datael_get_parent(&inst
->rd_d
, &svc
->rd_d
);
5771 if (r
!= SCF_SUCCESS
) {
5772 HANDLE_RELE_SERVICE(h
);
5776 len
= scf_service_to_fmri(svc
, out
, sz
);
5778 HANDLE_RELE_SERVICE(h
);
5784 len
+= sizeof (SCF_FMRI_INSTANCE_PREFIX
) - 1;
5786 len
= strlcat(out
, SCF_FMRI_INSTANCE_PREFIX
, sz
);
5788 r
= scf_instance_get_name(inst
, tmp
, sizeof (tmp
));
5795 len
= strlcat(out
, tmp
, sz
);
5801 scf_pg_to_fmri(const scf_propertygroup_t
*pg
, char *out
, size_t sz
)
5803 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
5805 struct rep_protocol_entity_parent_type request
;
5806 struct rep_protocol_integer_response response
;
5808 char tmp
[REP_PROTOCOL_NAME_LEN
];
5811 (void) pthread_mutex_lock(&h
->rh_lock
);
5812 request
.rpr_request
= REP_PROTOCOL_ENTITY_PARENT_TYPE
;
5813 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
5815 datael_finish_reset(&pg
->rd_d
);
5816 r
= make_door_call(h
, &request
, sizeof (request
),
5817 &response
, sizeof (response
));
5818 (void) pthread_mutex_unlock(&h
->rh_lock
);
5821 DOOR_ERRORS_BLOCK(r
);
5823 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
||
5824 r
< sizeof (response
)) {
5825 return (scf_set_error(proto_error(response
.rpr_response
)));
5828 switch (response
.rpr_value
) {
5829 case REP_PROTOCOL_ENTITY_SERVICE
: {
5832 svc
= HANDLE_HOLD_SERVICE(h
);
5834 r
= datael_get_parent(&pg
->rd_d
, &svc
->rd_d
);
5836 if (r
== SCF_SUCCESS
)
5837 len
= scf_service_to_fmri(svc
, out
, sz
);
5839 HANDLE_RELE_SERVICE(h
);
5843 case REP_PROTOCOL_ENTITY_INSTANCE
: {
5844 scf_instance_t
*inst
;
5846 inst
= HANDLE_HOLD_INSTANCE(h
);
5848 r
= datael_get_parent(&pg
->rd_d
, &inst
->rd_d
);
5850 if (r
== SCF_SUCCESS
)
5851 len
= scf_instance_to_fmri(inst
, out
, sz
);
5853 HANDLE_RELE_INSTANCE(h
);
5857 case REP_PROTOCOL_ENTITY_SNAPLEVEL
: {
5858 scf_instance_t
*inst
= HANDLE_HOLD_INSTANCE(h
);
5859 scf_snapshot_t
*snap
= HANDLE_HOLD_SNAPSHOT(h
);
5860 scf_snaplevel_t
*level
= HANDLE_HOLD_SNAPLVL(h
);
5862 r
= datael_get_parent(&pg
->rd_d
, &level
->rd_d
);
5864 if (r
== SCF_SUCCESS
)
5865 r
= datael_get_parent(&level
->rd_d
, &snap
->rd_d
);
5867 if (r
== SCF_SUCCESS
)
5868 r
= datael_get_parent(&snap
->rd_d
, &inst
->rd_d
);
5870 if (r
== SCF_SUCCESS
)
5871 len
= scf_instance_to_fmri(inst
, out
, sz
);
5873 HANDLE_RELE_INSTANCE(h
);
5874 HANDLE_RELE_SNAPSHOT(h
);
5875 HANDLE_RELE_SNAPLVL(h
);
5880 return (scf_set_error(SCF_ERROR_INTERNAL
));
5883 if (r
!= SCF_SUCCESS
)
5887 len
+= sizeof (SCF_FMRI_PROPERTYGRP_PREFIX
) - 1;
5889 len
= strlcat(out
, SCF_FMRI_PROPERTYGRP_PREFIX
, sz
);
5891 r
= scf_pg_get_name(pg
, tmp
, sizeof (tmp
));
5899 len
= strlcat(out
, tmp
, sz
);
5905 scf_property_to_fmri(const scf_property_t
*prop
, char *out
, size_t sz
)
5907 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
5908 scf_propertygroup_t
*pg
= HANDLE_HOLD_PG(h
);
5910 char tmp
[REP_PROTOCOL_NAME_LEN
];
5914 r
= datael_get_parent(&prop
->rd_d
, &pg
->rd_d
);
5915 if (r
!= SCF_SUCCESS
) {
5920 len
= scf_pg_to_fmri(pg
, out
, sz
);
5925 len
+= sizeof (SCF_FMRI_PROPERTY_PREFIX
) - 1;
5927 len
= strlcat(out
, SCF_FMRI_PROPERTY_PREFIX
, sz
);
5929 r
= scf_property_get_name(prop
, tmp
, sizeof (tmp
));
5937 len
= strlcat(out
, tmp
, sz
);
5943 * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
5944 * (server response too big, bad entity id, request not applicable to entity,
5945 * name too long for buffer, bad element id, iter already exists, element
5946 * cannot have children of type, type is invalid, iter was reset, sequence
5947 * was bad, iter walks values, iter does not walk type entities),
5948 * _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED,
5949 * _NOT_FOUND (scope has no parent), _INVALID_ARGUMENT, _NO_RESOURCES,
5953 scf_pg_get_underlying_pg(const scf_propertygroup_t
*pg
,
5954 scf_propertygroup_t
*out
)
5956 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
5958 scf_instance_t
*inst
;
5960 char me
[REP_PROTOCOL_NAME_LEN
];
5963 if (h
!= out
->rd_d
.rd_handle
)
5964 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5966 r
= scf_pg_get_name(pg
, me
, sizeof (me
));
5971 svc
= HANDLE_HOLD_SERVICE(h
);
5972 inst
= HANDLE_HOLD_INSTANCE(h
);
5974 r
= datael_get_parent(&pg
->rd_d
, &inst
->rd_d
);
5976 if (r
== SCF_SUCCESS
) {
5977 r
= datael_get_parent(&inst
->rd_d
, &svc
->rd_d
);
5978 if (r
!= SCF_SUCCESS
) {
5981 r
= scf_service_get_pg(svc
, me
, out
);
5983 r
= scf_set_error(SCF_ERROR_NOT_FOUND
);
5987 HANDLE_RELE_SERVICE(h
);
5988 HANDLE_RELE_INSTANCE(h
);
5992 #define LEGACY_SCHEME "lrc:"
5993 #define LEGACY_UNKNOWN "unknown"
5996 * Implementation of scf_walk_fmri()
5998 * This is a little tricky due to the many-to-many relationship between patterns
5999 * and matches. We need to be able to satisfy the following requirements:
6001 * 1) Detect patterns which match more than one FMRI, and be able to
6002 * report which FMRIs have been matched.
6003 * 2) Detect patterns which have not matched any FMRIs
6004 * 3) Visit each matching FMRI exactly once across all patterns
6005 * 4) Ignore FMRIs which have only been matched due to multiply-matching
6008 * We maintain an array of scf_pattern_t structures, one for each argument, and
6009 * maintain a linked list of scf_match_t structures for each one. We first
6010 * qualify each pattern's type:
6012 * PATTERN_INVALID The argument is invalid (too long).
6014 * PATTERN_EXACT The pattern is a complete FMRI. The list of
6015 * matches contains only a single entry.
6017 * PATTERN_GLOB The pattern will be matched against all
6018 * FMRIs via fnmatch() in the second phase.
6019 * Matches will be added to the pattern's list
6020 * as they are found.
6022 * PATTERN_PARTIAL Everything else. We will assume that this is
6023 * an abbreviated FMRI, and match according to
6024 * our abbreviated FMRI rules. Matches will be
6025 * added to the pattern's list as they are found.
6027 * The first pass searches for arguments that are complete FMRIs. These are
6028 * classified as EXACT patterns and do not necessitate searching the entire
6031 * Once this is done, if we have any GLOB or PARTIAL patterns (or if no
6032 * arguments were given), we iterate over all services and instances in the
6033 * repository, looking for matches.
6035 * When a match is found, we add the match to the pattern's list. We also enter
6036 * the match into a hash table, resulting in something like this:
6038 * scf_pattern_t scf_match_t
6039 * +---------------+ +-------+ +-------+
6040 * | pattern 'foo' |----->| match |---->| match |
6041 * +---------------+ +-------+ +-------+
6043 * scf_match_key_t | |
6044 * +--------------+ | |
6045 * | FMRI bar/foo |<----+ |
6046 * +--------------+ |
6047 * | FMRI baz/foo |<------------------+
6050 * Once we have all of this set up, we do one pass to report patterns matching
6051 * multiple FMRIs (if SCF_WALK_MULTIPLE is not set) and patterns for which no
6054 * Finally, we walk through all valid patterns, and for each match, if we
6055 * haven't already seen the match (as recorded in the hash table), then we
6056 * execute the callback.
6059 struct scf_matchkey
;
6065 typedef struct scf_matchkey
{
6066 char *sk_fmri
; /* Matching FMRI */
6067 char *sk_legacy
; /* Legacy name */
6068 int sk_seen
; /* If we've been seen */
6069 struct scf_matchkey
*sk_next
; /* Next in hash chain */
6075 typedef struct scf_match
{
6076 scf_matchkey_t
*sm_key
;
6077 struct scf_match
*sm_next
;
6080 #define WALK_HTABLE_SIZE 123
6085 * Given an FMRI and a hash table, returns the scf_matchkey_t corresponding to
6086 * this FMRI. If the FMRI does not exist, it is added to the hash table. If a
6087 * new entry cannot be allocated due to lack of memory, NULL is returned.
6089 static scf_matchkey_t
*
6090 scf_get_key(scf_matchkey_t
**htable
, const char *fmri
, const char *legacy
)
6094 scf_matchkey_t
*key
;
6096 k
= strstr(fmri
, ":/");
6101 * Generic hash function from kernel/os/modhash.c.
6103 for (p
= k
; *p
!= '\0'; ++p
) {
6105 if ((g
= (h
& 0xf0000000)) != 0) {
6111 h
%= WALK_HTABLE_SIZE
;
6114 * Search for an existing key
6116 for (key
= htable
[h
]; key
!= NULL
; key
= key
->sk_next
) {
6117 if (strcmp(key
->sk_fmri
, fmri
) == 0)
6121 if ((key
= calloc(sizeof (scf_matchkey_t
), 1)) == NULL
)
6125 * Add new key to hash table.
6127 if ((key
->sk_fmri
= strdup(fmri
)) == NULL
) {
6132 if (legacy
== NULL
) {
6133 key
->sk_legacy
= NULL
;
6134 } else if ((key
->sk_legacy
= strdup(legacy
)) == NULL
) {
6140 key
->sk_next
= htable
[h
];
6147 * Given an FMRI, insert it into the pattern's list appropriately.
6148 * svc_explicit indicates whether matching services should take
6149 * precedence over matching instances.
6152 scf_add_match(scf_matchkey_t
**htable
, const char *fmri
, const char *legacy
,
6153 scf_pattern_t
*pattern
, int svc_explicit
)
6158 * If svc_explicit is set, enforce the constaint that matching
6159 * instances take precedence over matching services. Otherwise,
6160 * matching services take precedence over matching instances.
6163 scf_match_t
*next
, *prev
;
6165 * If we match an instance, check to see if we must remove
6166 * any matching services (for SCF_WALK_EXPLICIT).
6168 for (prev
= match
= pattern
->sp_matches
; match
!= NULL
;
6170 size_t len
= strlen(match
->sm_key
->sk_fmri
);
6171 next
= match
->sm_next
;
6172 if (strncmp(match
->sm_key
->sk_fmri
, fmri
, len
) == 0 &&
6175 pattern
->sp_matches
= match
->sm_next
;
6177 prev
->sm_next
= match
->sm_next
;
6178 pattern
->sp_matchcount
--;
6185 * If we've matched a service don't add any instances (for
6186 * SCF_WALK_SERVICE).
6188 for (match
= pattern
->sp_matches
; match
!= NULL
;
6189 match
= match
->sm_next
) {
6190 size_t len
= strlen(match
->sm_key
->sk_fmri
);
6191 if (strncmp(match
->sm_key
->sk_fmri
, fmri
, len
) == 0 &&
6197 if ((match
= malloc(sizeof (scf_match_t
))) == NULL
)
6198 return (SCF_ERROR_NO_MEMORY
);
6200 if ((match
->sm_key
= scf_get_key(htable
, fmri
, legacy
)) == NULL
) {
6202 return (SCF_ERROR_NO_MEMORY
);
6205 match
->sm_next
= pattern
->sp_matches
;
6206 pattern
->sp_matches
= match
;
6207 pattern
->sp_matchcount
++;
6213 * Returns 1 if the fmri matches the given pattern, 0 otherwise.
6216 scf_cmp_pattern(char *fmri
, scf_pattern_t
*pattern
)
6220 if (pattern
->sp_type
== PATTERN_GLOB
) {
6221 if (fnmatch(pattern
->sp_arg
, fmri
, 0) == 0)
6223 } else if (pattern
->sp_type
== PATTERN_PARTIAL
&&
6224 (tmp
= strstr(fmri
, pattern
->sp_arg
)) != NULL
) {
6226 * We only allow partial matches anchored on the end of
6227 * a service or instance, and beginning on an element
6230 if (tmp
!= fmri
&& tmp
[-1] != '/' && tmp
[-1] != ':' &&
6233 tmp
+= strlen(pattern
->sp_arg
);
6234 if (tmp
!= fmri
+ strlen(fmri
) && tmp
[0] != ':' &&
6239 * If the user has supplied a short pattern that matches
6240 * 'svc:/' or 'lrc:/', ignore it.
6242 if (tmp
<= fmri
+ 4)
6252 * Attempts to match the given FMRI against a set of patterns, keeping track of
6256 scf_pattern_match(scf_matchkey_t
**htable
, char *fmri
, const char *legacy
,
6257 int npattern
, scf_pattern_t
*pattern
, int svc_explicit
)
6262 for (i
= 0; i
< npattern
; i
++) {
6263 if (scf_cmp_pattern(fmri
, &pattern
[i
]) &&
6264 (ret
= scf_add_match(htable
, fmri
,
6265 legacy
, &pattern
[i
], svc_explicit
)) != 0)
6273 * Fails with _INVALID_ARGUMENT, _HANDLE_DESTROYED, _INTERNAL (bad server
6274 * response or id in use), _NO_MEMORY, _HANDLE_MISMATCH, _CONSTRAINT_VIOLATED,
6275 * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _NOT_SET, _DELETED,
6276 * _NO_RESOURCES, _BACKEND_ACCESS, _TYPE_MISMATCH.
6279 scf_walk_fmri(scf_handle_t
*h
, int argc
, char **argv
, int flags
,
6280 scf_walk_callback callback
, void *data
, int *err
,
6281 void (*errfunc
)(const char *, ...))
6283 scf_pattern_t
*pattern
= NULL
;
6286 ssize_t max_fmri_length
;
6287 scf_service_t
*svc
= NULL
;
6288 scf_instance_t
*inst
= NULL
;
6289 scf_iter_t
*iter
= NULL
, *sciter
= NULL
, *siter
= NULL
;
6290 scf_scope_t
*scope
= NULL
;
6291 scf_propertygroup_t
*pg
= NULL
;
6292 scf_property_t
*prop
= NULL
;
6293 scf_value_t
*value
= NULL
;
6295 scf_matchkey_t
**htable
= NULL
;
6296 int pattern_search
= 0;
6297 ssize_t max_name_length
;
6298 char *pgname
= NULL
;
6299 scf_walkinfo_t info
;
6300 boolean_t partial_fmri
= B_FALSE
;
6301 boolean_t wildcard_fmri
= B_FALSE
;
6304 if (flags
& SCF_WALK_EXPLICIT
)
6305 assert(flags
& SCF_WALK_SERVICE
);
6306 if (flags
& SCF_WALK_NOINSTANCE
)
6307 assert(flags
& SCF_WALK_SERVICE
);
6308 if (flags
& SCF_WALK_PROPERTY
)
6309 assert(!(flags
& SCF_WALK_LEGACY
));
6313 * Setup initial variables
6315 max_fmri_length
= scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH
);
6316 assert(max_fmri_length
!= -1);
6317 max_name_length
= scf_limit(SCF_LIMIT_MAX_NAME_LENGTH
);
6318 assert(max_name_length
!= -1);
6320 if ((fmri
= malloc(max_fmri_length
+ 1)) == NULL
||
6321 (pgname
= malloc(max_name_length
+ 1)) == NULL
) {
6322 ret
= SCF_ERROR_NO_MEMORY
;
6328 } else if ((pattern
= calloc(argc
, sizeof (scf_pattern_t
)))
6330 ret
= SCF_ERROR_NO_MEMORY
;
6334 if ((htable
= calloc(WALK_HTABLE_SIZE
, sizeof (void *))) == NULL
) {
6335 ret
= SCF_ERROR_NO_MEMORY
;
6339 if ((inst
= scf_instance_create(h
)) == NULL
||
6340 (svc
= scf_service_create(h
)) == NULL
||
6341 (iter
= scf_iter_create(h
)) == NULL
||
6342 (sciter
= scf_iter_create(h
)) == NULL
||
6343 (siter
= scf_iter_create(h
)) == NULL
||
6344 (scope
= scf_scope_create(h
)) == NULL
||
6345 (pg
= scf_pg_create(h
)) == NULL
||
6346 (prop
= scf_property_create(h
)) == NULL
||
6347 (value
= scf_value_create(h
)) == NULL
) {
6353 * For each fmri given, we first check to see if it's a full service,
6354 * instance, property group, or property FMRI. This avoids having to do
6355 * the (rather expensive) walk of all instances. Any element which does
6356 * not match a full fmri is identified as a globbed pattern or a partial
6357 * fmri and stored in a private array when walking instances.
6359 for (i
= 0; i
< argc
; i
++) {
6360 const char *scope_name
, *svc_name
, *inst_name
, *pg_name
;
6361 const char *prop_name
;
6363 if (strlen(argv
[i
]) > max_fmri_length
) {
6364 errfunc(scf_get_msg(SCF_MSG_ARGTOOLONG
), argv
[i
]);
6366 *err
= UU_EXIT_FATAL
;
6370 (void) strcpy(fmri
, argv
[i
]);
6371 if (scf_parse_svc_fmri(fmri
, &scope_name
, &svc_name
, &inst_name
,
6372 &pg_name
, &prop_name
) != SCF_SUCCESS
)
6376 * If the user has specified SCF_WALK_PROPERTY, allow property
6377 * groups and properties.
6379 if (pg_name
!= NULL
|| prop_name
!= NULL
) {
6380 if (!(flags
& SCF_WALK_PROPERTY
))
6383 if (scf_handle_decode_fmri(h
, argv
[i
], NULL
, NULL
,
6384 NULL
, pg
, prop
, 0) != 0)
6387 if (scf_pg_get_name(pg
, NULL
, 0) < 0 &&
6388 scf_property_get_name(prop
, NULL
, 0) < 0)
6391 if (scf_canonify_fmri(argv
[i
], fmri
, max_fmri_length
)
6394 * scf_parse_fmri() should have caught this.
6399 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6400 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6403 if ((pattern
[i
].sp_arg
= strdup(argv
[i
])) == NULL
) {
6404 ret
= SCF_ERROR_NO_MEMORY
;
6407 pattern
[i
].sp_type
= PATTERN_EXACT
;
6411 * We need at least a service name
6413 if (scope_name
== NULL
|| svc_name
== NULL
)
6417 * If we have a fully qualified instance, add it to our list of
6420 if (inst_name
!= NULL
) {
6421 if (flags
& SCF_WALK_NOINSTANCE
)
6424 if (scf_handle_decode_fmri(h
, argv
[i
], NULL
, NULL
,
6425 inst
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != 0)
6428 if (scf_canonify_fmri(argv
[i
], fmri
, max_fmri_length
)
6432 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6433 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6436 if ((pattern
[i
].sp_arg
= strdup(argv
[i
])) == NULL
) {
6437 ret
= SCF_ERROR_NO_MEMORY
;
6440 pattern
[i
].sp_type
= PATTERN_EXACT
;
6445 if (scf_handle_decode_fmri(h
, argv
[i
], NULL
, svc
,
6446 NULL
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) !=
6451 * If the user allows for bare services, then simply
6452 * pass this service on.
6454 if (flags
& SCF_WALK_SERVICE
) {
6455 if (scf_service_to_fmri(svc
, fmri
,
6456 max_fmri_length
+ 1) <= 0) {
6461 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6462 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6465 if ((pattern
[i
].sp_arg
= strdup(argv
[i
]))
6467 ret
= SCF_ERROR_NO_MEMORY
;
6470 pattern
[i
].sp_type
= PATTERN_EXACT
;
6474 if (flags
& SCF_WALK_NOINSTANCE
)
6478 * Otherwise, iterate over all instances in the service.
6480 if (scf_iter_service_instances(iter
, svc
) !=
6487 ret
= scf_iter_next_instance(iter
, inst
);
6495 if (scf_instance_to_fmri(inst
, fmri
,
6496 max_fmri_length
+ 1) == -1)
6499 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6500 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6504 if ((pattern
[i
].sp_arg
= strdup(argv
[i
])) == NULL
) {
6505 ret
= SCF_ERROR_NO_MEMORY
;
6508 pattern
[i
].sp_type
= PATTERN_EXACT
;
6509 partial_fmri
= B_TRUE
; /* we just iterated all instances */
6516 * If we got here because of a fatal error, bail out
6519 if (scf_error() == SCF_ERROR_CONNECTION_BROKEN
) {
6525 * At this point we failed to interpret the argument as a
6526 * complete fmri, so mark it as a partial or globbed FMRI for
6529 if (strpbrk(argv
[i
], "*?[") != NULL
) {
6531 * Prepend svc:/ to patterns which don't begin with * or
6534 wildcard_fmri
= B_TRUE
;
6535 pattern
[i
].sp_type
= PATTERN_GLOB
;
6536 if (argv
[i
][0] == '*' ||
6537 (strlen(argv
[i
]) >= 4 && argv
[i
][3] == ':'))
6538 pattern
[i
].sp_arg
= strdup(argv
[i
]);
6540 pattern
[i
].sp_arg
= malloc(strlen(argv
[i
]) + 6);
6541 if (pattern
[i
].sp_arg
!= NULL
)
6542 (void) snprintf(pattern
[i
].sp_arg
,
6543 strlen(argv
[i
]) + 6, "svc:/%s",
6547 partial_fmri
= B_TRUE
;
6548 pattern
[i
].sp_type
= PATTERN_PARTIAL
;
6549 pattern
[i
].sp_arg
= strdup(argv
[i
]);
6552 if (pattern
[i
].sp_arg
== NULL
) {
6553 ret
= SCF_ERROR_NO_MEMORY
;
6558 if (pattern_search
|| argc
== 0) {
6560 * We have a set of patterns to search for. Iterate over all
6561 * instances and legacy services searching for matches.
6563 if (scf_handle_get_local_scope(h
, scope
) != 0) {
6568 if (scf_iter_scope_services(sciter
, scope
) != 0) {
6574 ret
= scf_iter_next_service(sciter
, svc
);
6582 if (flags
& SCF_WALK_SERVICE
) {
6584 * If the user is requesting bare services, try
6585 * to match the service first.
6587 if (scf_service_to_fmri(svc
, fmri
,
6588 max_fmri_length
+ 1) < 0) {
6600 if ((ret
= callback(data
, &info
)) != 0)
6603 } else if ((ret
= scf_pattern_match(htable
,
6604 fmri
, NULL
, argc
, pattern
,
6605 flags
& SCF_WALK_EXPLICIT
)) != 0) {
6610 if (flags
& SCF_WALK_NOINSTANCE
)
6614 * Iterate over all instances in the service.
6616 if (scf_iter_service_instances(siter
, svc
) != 0) {
6617 if (scf_error() != SCF_ERROR_DELETED
) {
6625 ret
= scf_iter_next_instance(siter
, inst
);
6629 if (scf_error() != SCF_ERROR_DELETED
) {
6636 if (scf_instance_to_fmri(inst
, fmri
,
6637 max_fmri_length
+ 1) < 0) {
6643 * Without arguments, execute the callback
6653 if ((ret
= callback(data
, &info
)) != 0)
6655 } else if ((ret
= scf_pattern_match(htable
,
6656 fmri
, NULL
, argc
, pattern
,
6657 flags
& SCF_WALK_EXPLICIT
)) != 0) {
6664 * Search legacy services
6666 if ((flags
& SCF_WALK_LEGACY
)) {
6667 if (scf_scope_get_service(scope
, SCF_LEGACY_SERVICE
,
6669 if (scf_error() != SCF_ERROR_NOT_FOUND
) {
6677 if (scf_iter_service_pgs_typed(iter
, svc
,
6678 SCF_GROUP_FRAMEWORK
) != SCF_SUCCESS
) {
6683 (void) strcpy(fmri
, LEGACY_SCHEME
);
6686 ret
= scf_iter_next_pg(iter
, pg
);
6694 if (scf_pg_get_property(pg
,
6695 SCF_LEGACY_PROPERTY_NAME
, prop
) == -1) {
6697 if (ret
== SCF_ERROR_DELETED
||
6698 ret
== SCF_ERROR_NOT_FOUND
) {
6705 if (scf_property_is_type(prop
, SCF_TYPE_ASTRING
)
6707 if (scf_error() == SCF_ERROR_DELETED
)
6713 if (scf_property_get_value(prop
, value
) !=
6717 if (scf_value_get_astring(value
,
6718 fmri
+ sizeof (LEGACY_SCHEME
) - 1,
6719 max_fmri_length
+ 2 -
6720 sizeof (LEGACY_SCHEME
)) <= 0)
6723 if (scf_pg_get_name(pg
, pgname
,
6724 max_name_length
+ 1) <= 0) {
6725 if (scf_error() == SCF_ERROR_DELETED
)
6738 if ((ret
= callback(data
, &info
)) != 0)
6740 } else if ((ret
= scf_pattern_match(htable
,
6741 fmri
, pgname
, argc
, pattern
,
6742 flags
& SCF_WALK_EXPLICIT
)) != 0)
6755 * Check all patterns, and see if we have that any that didn't match
6756 * or any that matched multiple instances. For svcprop, add up the
6757 * total number of matching keys.
6760 for (i
= 0; i
< argc
; i
++) {
6763 if (pattern
[i
].sp_type
== PATTERN_INVALID
)
6765 if (pattern
[i
].sp_matchcount
== 0) {
6768 * Provide a useful error message based on the argument
6769 * and the type of entity requested.
6771 if (!(flags
& SCF_WALK_LEGACY
) &&
6772 strncmp(pattern
[i
].sp_arg
, "lrc:/", 5) == 0)
6773 msgid
= SCF_MSG_PATTERN_LEGACY
;
6774 else if (flags
& SCF_WALK_PROPERTY
)
6775 msgid
= SCF_MSG_PATTERN_NOENTITY
;
6776 else if (flags
& SCF_WALK_NOINSTANCE
)
6777 msgid
= SCF_MSG_PATTERN_NOSERVICE
;
6778 else if (flags
& SCF_WALK_SERVICE
)
6779 msgid
= SCF_MSG_PATTERN_NOINSTSVC
;
6781 msgid
= SCF_MSG_PATTERN_NOINSTANCE
;
6783 errfunc(scf_get_msg(msgid
), pattern
[i
].sp_arg
);
6785 *err
= UU_EXIT_FATAL
;
6786 } else if (!(flags
& SCF_WALK_MULTIPLE
) &&
6787 pattern
[i
].sp_matchcount
> 1) {
6792 * Construct a message with all possible FMRIs before
6793 * passing off to error handling function.
6795 * Note that strlen(scf_get_msg(...)) includes the
6796 * length of '%s', which accounts for the terminating
6799 len
= strlen(scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH
)) +
6800 strlen(pattern
[i
].sp_arg
);
6801 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6802 match
= match
->sm_next
) {
6803 len
+= strlen(match
->sm_key
->sk_fmri
) + 2;
6805 if ((msg
= malloc(len
)) == NULL
) {
6806 ret
= SCF_ERROR_NO_MEMORY
;
6810 /* LINTED - format argument */
6811 (void) snprintf(msg
, len
,
6812 scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH
),
6815 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6816 match
= match
->sm_next
) {
6817 off
+= snprintf(msg
+ off
, len
- off
, "\t%s\n",
6818 match
->sm_key
->sk_fmri
);
6823 *err
= UU_EXIT_FATAL
;
6827 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6828 match
= match
->sm_next
) {
6829 if (!match
->sm_key
->sk_seen
)
6831 match
->sm_key
->sk_seen
= 1;
6836 if (flags
& SCF_WALK_UNIPARTIAL
&& info
.count
> 1) {
6838 * If the SCF_WALK_UNIPARTIAL flag was passed in and we have
6839 * more than one fmri, then this is an error if we matched
6840 * because of a partial fmri parameter, unless we also matched
6841 * more than one fmri because of wildcards in the parameters.
6842 * That is, the presence of wildcards indicates that it is ok
6843 * to match more than one fmri in this case.
6844 * For example, a parameter of 'foo' that matches more than
6845 * one fmri is an error, but parameters of 'foo *bar*' that
6846 * matches more than one is fine.
6848 if (partial_fmri
&& !wildcard_fmri
) {
6849 errfunc(scf_get_msg(SCF_MSG_PATTERN_MULTIPARTIAL
));
6851 *err
= UU_EXIT_FATAL
;
6857 * Clear 'sk_seen' for all keys.
6859 for (i
= 0; i
< WALK_HTABLE_SIZE
; i
++) {
6860 scf_matchkey_t
*key
;
6861 for (key
= htable
[i
]; key
!= NULL
; key
= key
->sk_next
)
6866 * Iterate over all the FMRIs in our hash table and execute the
6869 for (i
= 0; i
< argc
; i
++) {
6871 scf_matchkey_t
*key
;
6874 * Ignore patterns which didn't match anything or matched too
6877 if (pattern
[i
].sp_matchcount
== 0 ||
6878 (!(flags
& SCF_WALK_MULTIPLE
) &&
6879 pattern
[i
].sp_matchcount
> 1))
6882 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6883 match
= match
->sm_next
) {
6885 key
= match
->sm_key
;
6891 if (key
->sk_legacy
!= NULL
) {
6892 if (scf_scope_get_service(scope
,
6893 "smf/legacy_run", svc
) != 0) {
6898 if (scf_service_get_pg(svc
, key
->sk_legacy
,
6902 info
.fmri
= key
->sk_fmri
;
6908 if ((ret
= callback(data
, &info
)) != 0)
6911 if (scf_handle_decode_fmri(h
, key
->sk_fmri
,
6912 scope
, svc
, inst
, pg
, prop
, 0) !=
6916 info
.fmri
= key
->sk_fmri
;
6919 if (scf_instance_get_name(inst
, NULL
, 0) < 0) {
6921 SCF_ERROR_CONNECTION_BROKEN
) {
6929 if (scf_pg_get_name(pg
, NULL
, 0) < 0) {
6931 SCF_ERROR_CONNECTION_BROKEN
) {
6939 if (scf_property_get_name(prop
, NULL
, 0) < 0) {
6941 SCF_ERROR_CONNECTION_BROKEN
) {
6950 if ((ret
= callback(data
, &info
)) != 0)
6958 scf_matchkey_t
*key
, *next
;
6960 for (i
= 0; i
< WALK_HTABLE_SIZE
; i
++) {
6962 for (key
= htable
[i
]; key
!= NULL
;
6965 next
= key
->sk_next
;
6968 free(key
->sk_legacy
);
6974 if (pattern
!= NULL
) {
6975 for (i
= 0; i
< argc
; i
++) {
6976 scf_match_t
*match
, *next
;
6978 free(pattern
[i
].sp_arg
);
6980 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6983 next
= match
->sm_next
;
6994 scf_value_destroy(value
);
6995 scf_property_destroy(prop
);
6997 scf_scope_destroy(scope
);
6998 scf_iter_destroy(siter
);
6999 scf_iter_destroy(sciter
);
7000 scf_iter_destroy(iter
);
7001 scf_instance_destroy(inst
);
7002 scf_service_destroy(svc
);
7008 * scf_encode32() is an implementation of Base32 encoding as described in
7009 * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
7010 * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648. The
7011 * input stream is divided into groups of 5 characters (40 bits). Each
7012 * group is encoded into 8 output characters where each output character
7013 * represents 5 bits of input.
7015 * If the input is not an even multiple of 5 characters, the output will be
7016 * padded so that the output is an even multiple of 8 characters. The
7017 * standard specifies that the pad character is '='. Unfortunately, '=' is
7018 * not a legal character in SMF property names. Thus, the caller can
7019 * specify an alternate pad character with the pad argument. If pad is 0,
7020 * scf_encode32() will use '='. Note that use of anything other than '='
7021 * produces output that is not in conformance with RFC 4648. It is
7022 * suitable, however, for internal use of SMF software. When the encoded
7023 * data is used as part of an SMF property name, SCF_ENCODE32_PAD should be
7024 * used as the pad character.
7027 * input - Address of the buffer to be encoded.
7028 * inlen - Number of characters at input.
7029 * output - Address of the buffer to receive the encoded data.
7030 * outmax - Size of the buffer at output.
7031 * outlen - If it is not NULL, outlen receives the number of
7032 * bytes placed in output.
7033 * pad - Alternate padding character.
7036 * 0 Buffer was successfully encoded.
7037 * -1 Indicates output buffer too small, or pad is one of the
7038 * standard encoding characters.
7041 scf_encode32(const char *input
, size_t inlen
, char *output
, size_t outmax
,
7042 size_t *outlen
, char pad
)
7044 uint_t group_size
= 5;
7046 const unsigned char *in
= (const unsigned char *)input
;
7048 uchar_t
*out
= (uchar_t
*)output
;
7052 /* Verify that there is enough room for the output. */
7053 olen
= ((inlen
+ (group_size
- 1)) / group_size
) * 8;
7059 /* If caller did not provide pad character, use the default. */
7064 * Make sure that caller's pad is not one of the encoding
7067 for (i
= 0; i
< sizeof (base32
) - 1; i
++) {
7068 if (pad
== base32
[i
])
7073 /* Process full groups capturing 5 bits per output character. */
7074 for (; inlen
>= group_size
; in
+= group_size
, inlen
-= group_size
) {
7076 * The comments in this section number the bits in an
7077 * 8 bit byte 0 to 7. The high order bit is bit 7 and
7078 * the low order bit is bit 0.
7081 /* top 5 bits (7-3) from in[0] */
7082 *out
++ = base32
[in
[0] >> 3];
7083 /* bits 2-0 from in[0] and top 2 (7-6) from in[1] */
7084 *out
++ = base32
[((in
[0] << 2) & 0x1c) | (in
[1] >> 6)];
7085 /* 5 bits (5-1) from in[1] */
7086 *out
++ = base32
[(in
[1] >> 1) & 0x1f];
7087 /* low bit (0) from in[1] and top 4 (7-4) from in[2] */
7088 *out
++ = base32
[((in
[1] << 4) & 0x10) | ((in
[2] >> 4) & 0xf)];
7089 /* low 4 (3-0) from in[2] and top bit (7) from in[3] */
7090 *out
++ = base32
[((in
[2] << 1) & 0x1e) | (in
[3] >> 7)];
7091 /* 5 bits (6-2) from in[3] */
7092 *out
++ = base32
[(in
[3] >> 2) & 0x1f];
7093 /* low 2 (1-0) from in[3] and top 3 (7-5) from in[4] */
7094 *out
++ = base32
[((in
[3] << 3) & 0x18) | (in
[4] >> 5)];
7095 /* low 5 (4-0) from in[4] */
7096 *out
++ = base32
[in
[4] & 0x1f];
7099 /* Take care of final input bytes. */
7102 /* top 5 bits (7-3) from in[0] */
7103 *out
++ = base32
[in
[0] >> 3];
7105 * low 3 (2-0) from in[0] and top 2 (7-6) from in[1] if
7108 oval
= (in
[0] << 2) & 0x1c;
7110 *out
++ = base32
[oval
];
7115 *out
++ = base32
[oval
];
7116 /* 5 bits (5-1) from in[1] */
7117 *out
++ = base32
[(in
[1] >> 1) & 0x1f];
7119 * low bit (0) from in[1] and top 4 (7-4) from in[2] if
7122 oval
= (in
[1] << 4) & 0x10;
7124 *out
++ = base32
[oval
];
7129 *out
++ = base32
[oval
];
7131 * low 4 (3-0) from in[2] and top 1 (7) from in[3] if
7134 oval
= (in
[2] << 1) & 0x1e;
7136 *out
++ = base32
[oval
];
7141 *out
++ = base32
[oval
];
7142 /* 5 bits (6-2) from in[3] */
7143 *out
++ = base32
[(in
[3] >> 2) & 0x1f];
7144 /* low 2 bits (1-0) from in[3] */
7145 *out
++ = base32
[(in
[3] << 3) & 0x18];
7150 * Pad the output so that it is a multiple of 8 bytes.
7152 for (; pad_count
> 0; pad_count
--) {
7157 * Null terminate the output if there is enough room.
7166 * scf_decode32() is an implementation of Base32 decoding as described in
7167 * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
7168 * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648. The
7169 * input stream is divided into groups of 8 encoded characters. Each
7170 * encoded character represents 5 bits of data. Thus, the 8 encoded
7171 * characters are used to produce 40 bits or 5 bytes of unencoded data in
7174 * If the encoder did not have enough data to generate a mulitple of 8
7175 * characters of encoded data, it used a pad character to get to the 8
7176 * character boundry. The standard specifies that the pad character is '='.
7177 * Unfortunately, '=' is not a legal character in SMF property names.
7178 * Thus, the caller can specify an alternate pad character with the pad
7179 * argument. If pad is 0, scf_decode32() will use '='. Note that use of
7180 * anything other than '=' is not in conformance with RFC 4648. It is
7181 * suitable, however, for internal use of SMF software. When the encoded
7182 * data is used in SMF property names, SCF_ENCODE32_PAD should be used as
7183 * the pad character.
7186 * in - Buffer of encoded characters.
7187 * inlen - Number of characters at in.
7188 * outbuf - Buffer to receive the decoded bytes. It can be the
7189 * same buffer as in.
7190 * outmax - Size of the buffer at outbuf.
7191 * outlen - If it is not NULL, outlen receives the number of
7192 * bytes placed in output.
7193 * pad - Alternate padding character.
7196 * 0 Buffer was successfully decoded.
7197 * -1 Indicates an invalid input character, output buffer too
7198 * small, or pad is one of the standard encoding characters.
7201 scf_decode32(const char *in
, size_t inlen
, char *outbuf
, size_t outmax
,
7202 size_t *outlen
, char pad
)
7204 char *bufend
= outbuf
+ outmax
;
7207 uint32_t g
[DECODE32_GS
];
7211 boolean_t pad_seen
= B_FALSE
;
7213 /* If caller did not provide pad character, use the default. */
7218 * Make sure that caller's pad is not one of the encoding
7221 for (i
= 0; i
< sizeof (base32
) - 1; i
++) {
7222 if (pad
== base32
[i
])
7228 while ((i
< inlen
) && (out
< bufend
)) {
7229 /* Get a group of input characters. */
7230 for (j
= 0, count
= 0;
7231 (j
< DECODE32_GS
) && (i
< inlen
);
7235 * RFC 4648 allows for the encoded data to be split
7236 * into multiple lines, so skip carriage returns
7239 if ((c
== '\r') || (c
== '\n'))
7241 if ((pad_seen
== B_TRUE
) && (c
!= pad
)) {
7242 /* Group not completed by pads */
7245 if ((c
< 0) || (c
>= sizeof (index32
))) {
7246 /* Illegal character. */
7253 if ((g
[j
++] = index32
[c
]) == 0xff) {
7254 /* Illegal character */
7260 /* Pack the group into five 8 bit bytes. */
7261 if ((count
>= 2) && (out
< bufend
)) {
7264 * 5 bits (7-3) from g[0]
7265 * 3 bits (2-0) from g[1] (4-2)
7267 *out
++ = (g
[0] << 3) | ((g
[1] >> 2) & 0x7);
7269 if ((count
>= 4) && (out
< bufend
)) {
7272 * 2 bits (7-6) from g[1] (1-0)
7273 * 5 bits (5-1) from g[2] (4-0)
7274 * 1 bit (0) from g[3] (4)
7276 *out
++ = (g
[1] << 6) | (g
[2] << 1) | \
7277 ((g
[3] >> 4) & 0x1);
7279 if ((count
>= 5) && (out
< bufend
)) {
7282 * 4 bits (7-4) from g[3] (3-0)
7283 * 4 bits (3-0) from g[4] (4-1)
7285 *out
++ = (g
[3] << 4) | ((g
[4] >> 1) & 0xf);
7287 if ((count
>= 7) && (out
< bufend
)) {
7290 * 1 bit (7) from g[4] (0)
7291 * 5 bits (6-2) from g[5] (4-0)
7292 * 2 bits (0-1) from g[6] (4-3)
7294 *out
++ = (g
[4] << 7) | (g
[5] << 2) |
7295 ((g
[6] >> 3) & 0x3);
7297 if ((count
== 8) && (out
< bufend
)) {
7300 * 3 bits (7-5) from g[6] (2-0)
7301 * 5 bits (4-0) from g[7] (4-0)
7303 *out
++ = (g
[6] << 5) | g
[7];
7307 /* Did not process all input characters. */
7311 *outlen
= out
- outbuf
;
7312 /* Null terminate the output if there is room. */
7320 * _scf_request_backup: a simple wrapper routine
7323 _scf_request_backup(scf_handle_t
*h
, const char *name
)
7325 struct rep_protocol_backup_request request
;
7326 struct rep_protocol_response response
;
7330 if (strlcpy(request
.rpr_name
, name
, sizeof (request
.rpr_name
)) >=
7331 sizeof (request
.rpr_name
))
7332 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
7334 (void) pthread_mutex_lock(&h
->rh_lock
);
7335 request
.rpr_request
= REP_PROTOCOL_BACKUP
;
7336 request
.rpr_changeid
= handle_next_changeid(h
);
7338 r
= make_door_call(h
, &request
, sizeof (request
),
7339 &response
, sizeof (response
));
7340 (void) pthread_mutex_unlock(&h
->rh_lock
);
7343 DOOR_ERRORS_BLOCK(r
);
7346 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
7347 return (scf_set_error(proto_error(response
.rpr_response
)));
7348 return (SCF_SUCCESS
);
7352 * Request svc.configd daemon to switch repository database.
7356 * _NOT_BOUND handle is not bound
7357 * _CONNECTION_BROKEN server is not reachable
7358 * _INTERNAL file operation error
7359 * the server response is too big
7360 * _PERMISSION_DENIED not enough privileges to do request
7361 * _BACKEND_READONLY backend is not writable
7362 * _BACKEND_ACCESS backend access fails
7363 * _NO_RESOURCES svc.configd is out of memory
7366 _scf_repository_switch(scf_handle_t
*h
, int scf_sw
)
7368 struct rep_protocol_switch_request request
;
7369 struct rep_protocol_response response
;
7373 * Setup request protocol and make door call
7374 * Hold rh_lock lock before handle_next_changeid call
7376 (void) pthread_mutex_lock(&h
->rh_lock
);
7378 request
.rpr_flag
= scf_sw
;
7379 request
.rpr_request
= REP_PROTOCOL_SWITCH
;
7380 request
.rpr_changeid
= handle_next_changeid(h
);
7382 r
= make_door_call(h
, &request
, sizeof (request
),
7383 &response
, sizeof (response
));
7385 (void) pthread_mutex_unlock(&h
->rh_lock
);
7388 DOOR_ERRORS_BLOCK(r
);
7392 * Pass protocol error up
7394 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
7395 return (scf_set_error(proto_error(response
.rpr_response
)));
7397 return (SCF_SUCCESS
);
7401 _scf_pg_is_read_protected(const scf_propertygroup_t
*pg
, boolean_t
*out
)
7403 char buf
[REP_PROTOCOL_NAME_LEN
];
7406 res
= datael_get_name(&pg
->rd_d
, buf
, sizeof (buf
),
7407 RP_ENTITY_NAME_PGREADPROT
);
7412 if (uu_strtouint(buf
, out
, sizeof (*out
), 0, 0, 1) == -1)
7413 return (scf_set_error(SCF_ERROR_INTERNAL
));
7414 return (SCF_SUCCESS
);
7418 * _scf_set_annotation: a wrapper to set the annotation fields for SMF
7419 * security auditing.
7421 * Fails with following in scf_error_key thread specific data:
7422 * _INVALID_ARGUMENT - operation or file too large
7424 * _CONNECTION_BROKEN
7429 _scf_set_annotation(scf_handle_t
*h
, const char *operation
, const char *file
)
7431 struct rep_protocol_annotation request
;
7432 struct rep_protocol_response response
;
7437 /* We can't do anything if the handle is destroyed. */
7438 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
7441 request
.rpr_request
= REP_PROTOCOL_SET_AUDIT_ANNOTATION
;
7442 copied
= strlcpy(request
.rpr_operation
,
7443 (operation
== NULL
) ? "" : operation
,
7444 sizeof (request
.rpr_operation
));
7445 if (copied
>= sizeof (request
.rpr_operation
))
7446 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
7448 copied
= strlcpy(request
.rpr_file
,
7449 (file
== NULL
) ? "" : file
,
7450 sizeof (request
.rpr_file
));
7451 if (copied
>= sizeof (request
.rpr_file
))
7452 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
7454 (void) pthread_mutex_lock(&h
->rh_lock
);
7455 r
= make_door_call(h
, &request
, sizeof (request
),
7456 &response
, sizeof (response
));
7457 (void) pthread_mutex_unlock(&h
->rh_lock
);
7460 DOOR_ERRORS_BLOCK(r
);
7463 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
7464 return (scf_set_error(proto_error(response
.rpr_response
)));