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 */
102 #define assert_nolint(x) (void)0
104 #define assert_nolint(x) assert(x)
107 static void scf_iter_reset_locked(scf_iter_t
*iter
);
108 static void scf_value_reset_locked(scf_value_t
*val
, int and_destroy
);
110 #define TYPE_VALUE (-100)
113 * Hold and release subhandles. We only allow one thread access to the
114 * subhandles at a time, and it can use any subset, grabbing and releasing
115 * them in any order. The only restrictions are that you cannot hold an
116 * already-held subhandle, and all subhandles must be released before
117 * returning to the original caller.
120 handle_hold_subhandles(scf_handle_t
*h
, int mask
)
122 assert(mask
!= 0 && (mask
& ~RH_HOLD_ALL
) == 0);
124 (void) pthread_mutex_lock(&h
->rh_lock
);
125 while (h
->rh_hold_flags
!= 0 && h
->rh_holder
!= pthread_self()) {
128 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
,
130 (void) pthread_cond_wait(&h
->rh_cv
, &h
->rh_lock
);
131 (void) pthread_setcancelstate(cancel_state
, NULL
);
133 if (h
->rh_hold_flags
== 0)
134 h
->rh_holder
= pthread_self();
135 assert(!(h
->rh_hold_flags
& mask
));
136 h
->rh_hold_flags
|= mask
;
137 (void) pthread_mutex_unlock(&h
->rh_lock
);
141 handle_rele_subhandles(scf_handle_t
*h
, int mask
)
143 assert(mask
!= 0 && (mask
& ~RH_HOLD_ALL
) == 0);
145 (void) pthread_mutex_lock(&h
->rh_lock
);
146 assert(h
->rh_holder
== pthread_self());
147 assert((h
->rh_hold_flags
& mask
));
149 h
->rh_hold_flags
&= ~mask
;
150 if (h
->rh_hold_flags
== 0)
151 (void) pthread_cond_signal(&h
->rh_cv
);
152 (void) pthread_mutex_unlock(&h
->rh_lock
);
155 #define HOLD_HANDLE(h, flag, field) \
156 (handle_hold_subhandles((h), (flag)), (h)->field)
158 #define RELE_HANDLE(h, flag) \
159 (handle_rele_subhandles((h), (flag)))
162 * convenience macros, for functions that only need a one or two handles at
165 #define HANDLE_HOLD_ITER(h) HOLD_HANDLE((h), RH_HOLD_ITER, rh_iter)
166 #define HANDLE_HOLD_SCOPE(h) HOLD_HANDLE((h), RH_HOLD_SCOPE, rh_scope)
167 #define HANDLE_HOLD_SERVICE(h) HOLD_HANDLE((h), RH_HOLD_SERVICE, rh_service)
168 #define HANDLE_HOLD_INSTANCE(h) HOLD_HANDLE((h), RH_HOLD_INSTANCE, rh_instance)
169 #define HANDLE_HOLD_SNAPSHOT(h) HOLD_HANDLE((h), RH_HOLD_SNAPSHOT, rh_snapshot)
170 #define HANDLE_HOLD_SNAPLVL(h) HOLD_HANDLE((h), RH_HOLD_SNAPLVL, rh_snaplvl)
171 #define HANDLE_HOLD_PG(h) HOLD_HANDLE((h), RH_HOLD_PG, rh_pg)
172 #define HANDLE_HOLD_PROPERTY(h) HOLD_HANDLE((h), RH_HOLD_PROPERTY, rh_property)
173 #define HANDLE_HOLD_VALUE(h) HOLD_HANDLE((h), RH_HOLD_VALUE, rh_value)
175 #define HANDLE_RELE_ITER(h) RELE_HANDLE((h), RH_HOLD_ITER)
176 #define HANDLE_RELE_SCOPE(h) RELE_HANDLE((h), RH_HOLD_SCOPE)
177 #define HANDLE_RELE_SERVICE(h) RELE_HANDLE((h), RH_HOLD_SERVICE)
178 #define HANDLE_RELE_INSTANCE(h) RELE_HANDLE((h), RH_HOLD_INSTANCE)
179 #define HANDLE_RELE_SNAPSHOT(h) RELE_HANDLE((h), RH_HOLD_SNAPSHOT)
180 #define HANDLE_RELE_SNAPLVL(h) RELE_HANDLE((h), RH_HOLD_SNAPLVL)
181 #define HANDLE_RELE_PG(h) RELE_HANDLE((h), RH_HOLD_PG)
182 #define HANDLE_RELE_PROPERTY(h) RELE_HANDLE((h), RH_HOLD_PROPERTY)
183 #define HANDLE_RELE_VALUE(h) RELE_HANDLE((h), RH_HOLD_VALUE)
187 transaction_entry_compare(const void *l_arg
, const void *r_arg
, void *private)
190 ((scf_transaction_entry_t
*)l_arg
)->entry_property
;
192 ((scf_transaction_entry_t
*)r_arg
)->entry_property
;
196 ret
= strcmp(l_prop
, r_prop
);
205 datael_compare(const void *l_arg
, const void *r_arg
, void *private)
207 uint32_t l_id
= ((scf_datael_t
*)l_arg
)->rd_entity
;
208 uint32_t r_id
= (r_arg
!= NULL
) ? ((scf_datael_t
*)r_arg
)->rd_entity
:
209 *(uint32_t *)private;
219 iter_compare(const void *l_arg
, const void *r_arg
, void *private)
221 uint32_t l_id
= ((scf_iter_t
*)l_arg
)->iter_id
;
222 uint32_t r_id
= (r_arg
!= NULL
) ? ((scf_iter_t
*)r_arg
)->iter_id
:
223 *(uint32_t *)private;
236 const char *door_path
;
238 (void) pthread_mutex_lock(&lowlevel_init_lock
);
239 if (lowlevel_inited
== 0) {
241 (debug
= getenv(ENV_SCF_DEBUG
)) != NULL
&& debug
[0] != 0 &&
242 uu_strtoint(debug
, &default_debug
, sizeof (default_debug
),
244 (void) fprintf(stderr
, "LIBSCF: $%s (%s): %s",
245 ENV_SCF_DEBUG
, debug
,
246 uu_strerror(uu_error()));
250 (door_path
= getenv(ENV_SCF_DOORPATH
)) != NULL
&&
252 default_door_path
= strdup(door_path
);
253 if (default_door_path
== NULL
)
254 default_door_path
= door_path
;
257 datael_pool
= uu_list_pool_create("SUNW,libscf_datael",
258 sizeof (scf_datael_t
), offsetof(scf_datael_t
, rd_node
),
259 datael_compare
, UU_LIST_POOL_DEBUG
);
261 iter_pool
= uu_list_pool_create("SUNW,libscf_iter",
262 sizeof (scf_iter_t
), offsetof(scf_iter_t
, iter_node
),
263 iter_compare
, UU_LIST_POOL_DEBUG
);
265 assert_nolint(offsetof(scf_transaction_entry_t
,
266 entry_property
) == 0);
267 tran_entry_pool
= uu_list_pool_create(
268 "SUNW,libscf_transaction_entity",
269 sizeof (scf_transaction_entry_t
),
270 offsetof(scf_transaction_entry_t
, entry_link
),
271 transaction_entry_compare
, UU_LIST_POOL_DEBUG
);
273 if (datael_pool
== NULL
|| iter_pool
== NULL
||
274 tran_entry_pool
== NULL
) {
275 lowlevel_inited
= -1;
279 if (!scf_setup_error()) {
280 lowlevel_inited
= -1;
286 (void) pthread_mutex_unlock(&lowlevel_init_lock
);
287 if (lowlevel_inited
> 0)
292 static const struct {
294 rep_protocol_value_type_t ti_proto_type
;
296 } scf_type_info
[] = {
297 {SCF_TYPE_BOOLEAN
, REP_PROTOCOL_TYPE_BOOLEAN
,
298 SCF_TYPE_STRING_BOOLEAN
},
299 {SCF_TYPE_COUNT
, REP_PROTOCOL_TYPE_COUNT
,
300 SCF_TYPE_STRING_COUNT
},
301 {SCF_TYPE_INTEGER
, REP_PROTOCOL_TYPE_INTEGER
,
302 SCF_TYPE_STRING_INTEGER
},
303 {SCF_TYPE_TIME
, REP_PROTOCOL_TYPE_TIME
,
304 SCF_TYPE_STRING_TIME
},
305 {SCF_TYPE_ASTRING
, REP_PROTOCOL_TYPE_STRING
,
306 SCF_TYPE_STRING_ASTRING
},
307 {SCF_TYPE_OPAQUE
, REP_PROTOCOL_TYPE_OPAQUE
,
308 SCF_TYPE_STRING_OPAQUE
},
309 {SCF_TYPE_USTRING
, REP_PROTOCOL_SUBTYPE_USTRING
,
310 SCF_TYPE_STRING_USTRING
},
311 {SCF_TYPE_URI
, REP_PROTOCOL_SUBTYPE_URI
,
312 SCF_TYPE_STRING_URI
},
313 {SCF_TYPE_FMRI
, REP_PROTOCOL_SUBTYPE_FMRI
,
314 SCF_TYPE_STRING_FMRI
},
315 {SCF_TYPE_HOST
, REP_PROTOCOL_SUBTYPE_HOST
,
316 SCF_TYPE_STRING_HOST
},
317 {SCF_TYPE_HOSTNAME
, REP_PROTOCOL_SUBTYPE_HOSTNAME
,
318 SCF_TYPE_STRING_HOSTNAME
},
319 {SCF_TYPE_NET_ADDR
, REP_PROTOCOL_SUBTYPE_NETADDR
,
320 SCF_TYPE_STRING_NET_ADDR
},
321 {SCF_TYPE_NET_ADDR_V4
, REP_PROTOCOL_SUBTYPE_NETADDR_V4
,
322 SCF_TYPE_STRING_NET_ADDR_V4
},
323 {SCF_TYPE_NET_ADDR_V6
, REP_PROTOCOL_SUBTYPE_NETADDR_V6
,
324 SCF_TYPE_STRING_NET_ADDR_V6
}
327 #define SCF_TYPE_INFO_COUNT (sizeof (scf_type_info) / sizeof (*scf_type_info))
328 static rep_protocol_value_type_t
329 scf_type_to_protocol_type(scf_type_t t
)
333 for (i
= 0; i
< SCF_TYPE_INFO_COUNT
; i
++)
334 if (scf_type_info
[i
].ti_type
== t
)
335 return (scf_type_info
[i
].ti_proto_type
);
337 return (REP_PROTOCOL_TYPE_INVALID
);
341 scf_protocol_type_to_type(rep_protocol_value_type_t t
)
345 for (i
= 0; i
< SCF_TYPE_INFO_COUNT
; i
++)
346 if (scf_type_info
[i
].ti_proto_type
== t
)
347 return (scf_type_info
[i
].ti_type
);
349 return (SCF_TYPE_INVALID
);
353 scf_type_to_string(scf_type_t ty
)
357 for (i
= 0; i
< SCF_TYPE_INFO_COUNT
; i
++)
358 if (scf_type_info
[i
].ti_type
== ty
)
359 return (scf_type_info
[i
].ti_name
);
365 scf_string_to_type(const char *name
)
369 for (i
= 0; i
< sizeof (scf_type_info
) / sizeof (*scf_type_info
); i
++)
370 if (strcmp(scf_type_info
[i
].ti_name
, name
) == 0)
371 return (scf_type_info
[i
].ti_type
);
373 return (SCF_TYPE_INVALID
);
377 scf_type_base_type(scf_type_t type
, scf_type_t
*out
)
379 rep_protocol_value_type_t t
= scf_type_to_protocol_type(type
);
380 if (t
== REP_PROTOCOL_TYPE_INVALID
)
381 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
383 *out
= scf_protocol_type_to_type(scf_proto_underlying_type(t
));
384 return (SCF_SUCCESS
);
388 * Convert a protocol error code into an SCF_ERROR_* code.
391 proto_error(rep_protocol_responseid_t e
)
394 case REP_PROTOCOL_FAIL_MISORDERED
:
395 case REP_PROTOCOL_FAIL_UNKNOWN_ID
:
396 case REP_PROTOCOL_FAIL_INVALID_TYPE
:
397 case REP_PROTOCOL_FAIL_TRUNCATED
:
398 case REP_PROTOCOL_FAIL_TYPE_MISMATCH
:
399 case REP_PROTOCOL_FAIL_NOT_APPLICABLE
:
400 case REP_PROTOCOL_FAIL_UNKNOWN
:
401 return (SCF_ERROR_INTERNAL
);
403 case REP_PROTOCOL_FAIL_BAD_TX
:
404 return (SCF_ERROR_INVALID_ARGUMENT
);
405 case REP_PROTOCOL_FAIL_BAD_REQUEST
:
406 return (SCF_ERROR_INVALID_ARGUMENT
);
407 case REP_PROTOCOL_FAIL_NO_RESOURCES
:
408 return (SCF_ERROR_NO_RESOURCES
);
409 case REP_PROTOCOL_FAIL_NOT_FOUND
:
410 return (SCF_ERROR_NOT_FOUND
);
411 case REP_PROTOCOL_FAIL_DELETED
:
412 return (SCF_ERROR_DELETED
);
413 case REP_PROTOCOL_FAIL_NOT_SET
:
414 return (SCF_ERROR_NOT_SET
);
415 case REP_PROTOCOL_FAIL_EXISTS
:
416 return (SCF_ERROR_EXISTS
);
417 case REP_PROTOCOL_FAIL_DUPLICATE_ID
:
418 return (SCF_ERROR_EXISTS
);
419 case REP_PROTOCOL_FAIL_PERMISSION_DENIED
:
420 return (SCF_ERROR_PERMISSION_DENIED
);
421 case REP_PROTOCOL_FAIL_BACKEND_ACCESS
:
422 return (SCF_ERROR_BACKEND_ACCESS
);
423 case REP_PROTOCOL_FAIL_BACKEND_READONLY
:
424 return (SCF_ERROR_BACKEND_READONLY
);
426 case REP_PROTOCOL_SUCCESS
:
427 case REP_PROTOCOL_DONE
:
428 case REP_PROTOCOL_FAIL_NOT_LATEST
: /* TX code should handle this */
431 uu_warn("%s:%d: Bad error code %d passed to proto_error().\n",
432 __FILE__
, __LINE__
, e
);
440 scf_limit(uint32_t limit
)
443 case SCF_LIMIT_MAX_NAME_LENGTH
:
444 case SCF_LIMIT_MAX_PG_TYPE_LENGTH
:
445 return (REP_PROTOCOL_NAME_LEN
- 1);
446 case SCF_LIMIT_MAX_VALUE_LENGTH
:
447 return (REP_PROTOCOL_VALUE_LEN
- 1);
448 case SCF_LIMIT_MAX_FMRI_LENGTH
:
449 return (SCF_FMRI_PREFIX_MAX_LEN
+
450 sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1 +
451 sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1 +
452 sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1 +
453 sizeof (SCF_FMRI_INSTANCE_PREFIX
) - 1 +
454 sizeof (SCF_FMRI_PROPERTYGRP_PREFIX
) - 1 +
455 sizeof (SCF_FMRI_PROPERTY_PREFIX
) - 1 +
456 5 * (REP_PROTOCOL_NAME_LEN
- 1));
458 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
463 scf_opaque_decode(char *out_arg
, const char *in
, size_t max_out
)
468 while (max_out
> 0 && (a
= in
[0]) != 0 && (b
= in
[1]) != 0) {
471 if (a
>= '0' && a
<= '9')
473 else if (a
>= 'a' && a
<= 'f')
475 else if (a
>= 'A' && a
<= 'F')
480 if (b
>= '0' && b
<= '9')
482 else if (b
>= 'a' && b
<= 'f')
484 else if (b
>= 'A' && b
<= 'F')
489 *out
++ = (a
<< 4) | b
;
493 return (out
- out_arg
);
497 scf_opaque_encode(char *out_arg
, const char *in_arg
, size_t in_sz
)
499 uint8_t *in
= (uint8_t *)in_arg
;
500 uint8_t *end
= in
+ in_sz
;
509 uint8_t a
= (c
& 0xf0) >> 4;
510 uint8_t b
= (c
& 0x0f);
515 *out
++ = a
+ 'a' - 10;
520 *out
++ = b
+ 'a' - 10;
525 return (out
- out_arg
);
529 handle_do_close(scf_handle_t
*h
)
531 assert(MUTEX_HELD(&h
->rh_lock
));
532 assert(h
->rh_doorfd
!= -1);
535 * if there are any active FD users, we just move the FD over
536 * to rh_doorfd_old -- they'll close it when they finish.
538 if (h
->rh_fd_users
> 0) {
539 h
->rh_doorfd_old
= h
->rh_doorfd
;
542 assert(h
->rh_doorfd_old
== -1);
543 (void) close(h
->rh_doorfd
);
549 * Check if a handle is currently bound. fork()ing implicitly unbinds
550 * the handle in the child.
553 handle_is_bound(scf_handle_t
*h
)
555 assert(MUTEX_HELD(&h
->rh_lock
));
557 if (h
->rh_doorfd
== -1)
560 if (getpid() == h
->rh_doorpid
)
563 /* forked since our last bind -- initiate handle close */
569 handle_has_server_locked(scf_handle_t
*h
)
572 assert(MUTEX_HELD(&h
->rh_lock
));
574 return (handle_is_bound(h
) && door_info(h
->rh_doorfd
, &i
) != -1 &&
579 handle_has_server(scf_handle_t
*h
)
583 (void) pthread_mutex_lock(&h
->rh_lock
);
584 ret
= handle_has_server_locked(h
);
585 (void) pthread_mutex_unlock(&h
->rh_lock
);
591 * This makes a door request on the client door associated with handle h.
592 * It will automatically retry calls which fail on EINTR. If h is not bound,
593 * returns NOT_BOUND. If the door call fails or the server response is too
594 * small, returns CALL_FAILED. If the server response is too big, truncates the
595 * response and returns RESULT_TOO_BIG. Otherwise, the size of the result is
599 make_door_call(scf_handle_t
*h
, const void *req
, size_t req_sz
,
600 void *res
, size_t res_sz
)
605 assert(MUTEX_HELD(&h
->rh_lock
));
607 if (!handle_is_bound(h
)) {
611 arg
.data_ptr
= (void *)req
;
612 arg
.data_size
= req_sz
;
618 while ((r
= door_call(h
->rh_doorfd
, &arg
)) < 0) {
624 return (CALL_FAILED
);
627 if (arg
.desc_num
> 0) {
628 while (arg
.desc_num
> 0) {
629 if (arg
.desc_ptr
->d_attributes
& DOOR_DESCRIPTOR
) {
630 int cfd
= arg
.desc_ptr
->d_data
.d_desc
.d_id
;
637 if (arg
.data_ptr
!= res
&& arg
.data_size
> 0)
638 (void) memmove(res
, arg
.data_ptr
, MIN(arg
.data_size
, res_sz
));
641 (void) munmap(arg
.rbuf
, arg
.rsize
);
643 if (arg
.data_size
> res_sz
)
644 return (RESULT_TOO_BIG
);
646 if (arg
.data_size
< sizeof (uint32_t))
647 return (CALL_FAILED
);
649 return (arg
.data_size
);
653 * Should only be used when r < 0.
655 #define DOOR_ERRORS_BLOCK(r) { \
658 return (scf_set_error(SCF_ERROR_NOT_BOUND)); \
661 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN)); \
663 case RESULT_TOO_BIG: \
664 return (scf_set_error(SCF_ERROR_INTERNAL)); \
667 assert(r == NOT_BOUND || r == CALL_FAILED || \
668 r == RESULT_TOO_BIG); \
674 * Like make_door_call(), but takes an fd instead of a handle, and expects
675 * a single file descriptor, returned via res_fd.
677 * If no file descriptor is returned, *res_fd == -1.
680 make_door_call_retfd(int fd
, const void *req
, size_t req_sz
, void *res
,
681 size_t res_sz
, int *res_fd
)
692 arg
.data_ptr
= (void *)req
;
693 arg
.data_size
= req_sz
;
697 arg
.rsize
= sizeof (rbuf
);
699 while ((r
= door_call(fd
, &arg
)) < 0) {
705 return (CALL_FAILED
);
707 if (arg
.desc_num
> 1) {
708 while (arg
.desc_num
> 0) {
709 if (arg
.desc_ptr
->d_attributes
& DOOR_DESCRIPTOR
) {
711 arg
.desc_ptr
->d_data
.d_desc
.d_descriptor
;
718 if (arg
.desc_num
== 1 && arg
.desc_ptr
->d_attributes
& DOOR_DESCRIPTOR
)
719 *res_fd
= arg
.desc_ptr
->d_data
.d_desc
.d_descriptor
;
721 if (arg
.data_size
> 0)
722 (void) memmove(res
, arg
.data_ptr
, MIN(arg
.data_size
, res_sz
));
724 if (arg
.rbuf
!= rbuf
)
725 (void) munmap(arg
.rbuf
, arg
.rsize
);
727 if (arg
.data_size
> res_sz
)
728 return (RESULT_TOO_BIG
);
730 if (arg
.data_size
< sizeof (uint32_t))
731 return (CALL_FAILED
);
733 return (arg
.data_size
);
742 scf_handle_create(scf_version_t v
)
748 * This will need to be revisited when we bump SCF_VERSION
750 if (v
!= SCF_VERSION
) {
751 (void) scf_set_error(SCF_ERROR_VERSION_MISMATCH
);
755 if (!lowlevel_init()) {
756 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
760 ret
= uu_zalloc(sizeof (*ret
));
762 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
766 ret
->rh_dataels
= uu_list_create(datael_pool
, ret
, 0);
767 ret
->rh_iters
= uu_list_create(iter_pool
, ret
, 0);
768 if (ret
->rh_dataels
== NULL
|| ret
->rh_iters
== NULL
) {
769 if (ret
->rh_dataels
!= NULL
)
770 uu_list_destroy(ret
->rh_dataels
);
771 if (ret
->rh_iters
!= NULL
)
772 uu_list_destroy(ret
->rh_iters
);
774 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
779 ret
->rh_doorfd_old
= -1;
780 (void) pthread_mutex_init(&ret
->rh_lock
, NULL
);
782 handle_hold_subhandles(ret
, RH_HOLD_ALL
);
784 failed
= ((ret
->rh_iter
= scf_iter_create(ret
)) == NULL
||
785 (ret
->rh_scope
= scf_scope_create(ret
)) == NULL
||
786 (ret
->rh_service
= scf_service_create(ret
)) == NULL
||
787 (ret
->rh_instance
= scf_instance_create(ret
)) == NULL
||
788 (ret
->rh_snapshot
= scf_snapshot_create(ret
)) == NULL
||
789 (ret
->rh_snaplvl
= scf_snaplevel_create(ret
)) == NULL
||
790 (ret
->rh_pg
= scf_pg_create(ret
)) == NULL
||
791 (ret
->rh_property
= scf_property_create(ret
)) == NULL
||
792 (ret
->rh_value
= scf_value_create(ret
)) == NULL
);
795 * these subhandles count as internal references, not external ones.
797 ret
->rh_intrefs
= ret
->rh_extrefs
;
799 handle_rele_subhandles(ret
, RH_HOLD_ALL
);
802 scf_handle_destroy(ret
);
803 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
807 scf_value_set_count(ret
->rh_value
, default_debug
);
808 (void) scf_handle_decorate(ret
, "debug", ret
->rh_value
);
816 * _NO_SERVER - server door could not be open()ed
819 * _VERSION_MISMATCH - server returned bad file descriptor
820 * server claimed bad request
821 * server reported version mismatch
822 * server refused with unknown reason
824 * _NO_RESOURCES - server is out of memory
826 * _INTERNAL - could not set up entities or iters
827 * server response too big
830 _scf_handle_create_and_bind(scf_version_t ver
)
834 h
= scf_handle_create(ver
);
838 if (scf_handle_bind(h
) == -1) {
839 scf_handle_destroy(h
);
846 scf_handle_decorate(scf_handle_t
*handle
, const char *name
, scf_value_t
*v
)
848 if (v
!= SCF_DECORATE_CLEAR
&& handle
!= v
->value_handle
)
849 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
851 (void) pthread_mutex_lock(&handle
->rh_lock
);
852 if (handle_is_bound(handle
)) {
853 (void) pthread_mutex_unlock(&handle
->rh_lock
);
854 return (scf_set_error(SCF_ERROR_IN_USE
));
856 (void) pthread_mutex_unlock(&handle
->rh_lock
);
858 if (strcmp(name
, "debug") == 0) {
859 if (v
== SCF_DECORATE_CLEAR
) {
860 (void) pthread_mutex_lock(&handle
->rh_lock
);
861 handle
->rh_debug
= 0;
862 (void) pthread_mutex_unlock(&handle
->rh_lock
);
865 if (scf_value_get_count(v
, &val
) < 0)
866 return (-1); /* error already set */
868 (void) pthread_mutex_lock(&handle
->rh_lock
);
869 handle
->rh_debug
= (uid_t
)val
;
870 (void) pthread_mutex_unlock(&handle
->rh_lock
);
874 if (strcmp(name
, "door_path") == 0) {
875 char name
[sizeof (handle
->rh_doorpath
)];
877 if (v
== SCF_DECORATE_CLEAR
) {
878 (void) pthread_mutex_lock(&handle
->rh_lock
);
879 handle
->rh_doorpath
[0] = 0;
880 (void) pthread_mutex_unlock(&handle
->rh_lock
);
884 if ((len
= scf_value_get_astring(v
, name
,
885 sizeof (name
))) < 0) {
886 return (-1); /* error already set */
888 if (len
== 0 || len
>= sizeof (name
)) {
889 return (scf_set_error(
890 SCF_ERROR_INVALID_ARGUMENT
));
892 (void) pthread_mutex_lock(&handle
->rh_lock
);
893 (void) strlcpy(handle
->rh_doorpath
, name
,
894 sizeof (handle
->rh_doorpath
));
895 (void) pthread_mutex_unlock(&handle
->rh_lock
);
900 if (strcmp(name
, "zone") == 0) {
901 char zone
[MAXPATHLEN
], root
[MAXPATHLEN
], door
[MAXPATHLEN
];
902 static int (*zone_get_rootpath
)(char *, char *, size_t);
906 * In order to be able to set the zone on a handle, we want
907 * to determine the zone's path, which requires us to call into
908 * libzonecfg -- but libzonecfg.so links against libscf.so so
909 * we must not explicitly link to it. To circumvent the
910 * circular dependency, we will pull it in here via dlopen().
912 if (zone_get_rootpath
== NULL
) {
913 void *dl
= dlopen("libzonecfg.so.1", RTLD_LAZY
), *sym
;
916 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
918 if ((sym
= dlsym(dl
, "zone_get_rootpath")) == NULL
) {
920 return (scf_set_error(SCF_ERROR_INTERNAL
));
923 zone_get_rootpath
= (int(*)(char *, char *, size_t))sym
;
926 if (v
== SCF_DECORATE_CLEAR
) {
927 (void) pthread_mutex_lock(&handle
->rh_lock
);
928 handle
->rh_doorpath
[0] = 0;
929 (void) pthread_mutex_unlock(&handle
->rh_lock
);
934 if ((len
= scf_value_get_astring(v
, zone
, sizeof (zone
))) < 0)
937 if (len
== 0 || len
>= sizeof (zone
))
938 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
940 if (zone_get_rootpath(zone
, root
, sizeof (root
)) != Z_OK
) {
941 if (strcmp(zone
, GLOBAL_ZONENAME
) == 0) {
944 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
948 if (snprintf(door
, sizeof (door
), "%s/%s", root
,
949 default_door_path
) >= sizeof (door
))
950 return (scf_set_error(SCF_ERROR_INTERNAL
));
952 (void) pthread_mutex_lock(&handle
->rh_lock
);
953 (void) strlcpy(handle
->rh_doorpath
, door
,
954 sizeof (handle
->rh_doorpath
));
955 (void) pthread_mutex_unlock(&handle
->rh_lock
);
960 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
964 * fails with INVALID_ARGUMENT and HANDLE_MISMATCH.
967 _scf_handle_decorations(scf_handle_t
*handle
, scf_decoration_func
*f
,
968 scf_value_t
*v
, void *data
)
970 scf_decoration_info_t i
;
971 char name
[sizeof (handle
->rh_doorpath
)];
974 if (f
== NULL
|| v
== NULL
)
975 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
977 if (v
->value_handle
!= handle
)
978 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
980 i
.sdi_name
= (const char *)"debug";
981 i
.sdi_type
= SCF_TYPE_COUNT
;
982 (void) pthread_mutex_lock(&handle
->rh_lock
);
983 debug
= handle
->rh_debug
;
984 (void) pthread_mutex_unlock(&handle
->rh_lock
);
986 scf_value_set_count(v
, debug
);
989 i
.sdi_value
= SCF_DECORATE_CLEAR
;
992 if ((*f
)(&i
, data
) == 0)
995 i
.sdi_name
= (const char *)"door_path";
996 i
.sdi_type
= SCF_TYPE_ASTRING
;
997 (void) pthread_mutex_lock(&handle
->rh_lock
);
998 (void) strlcpy(name
, handle
->rh_doorpath
, sizeof (name
));
999 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1001 (void) scf_value_set_astring(v
, name
);
1004 i
.sdi_value
= SCF_DECORATE_CLEAR
;
1007 if ((*f
)(&i
, data
) == 0)
1014 * Fails if handle is not bound.
1017 handle_unbind_unlocked(scf_handle_t
*handle
)
1019 rep_protocol_request_t request
;
1020 rep_protocol_response_t response
;
1022 if (!handle_is_bound(handle
))
1025 request
.rpr_request
= REP_PROTOCOL_CLOSE
;
1027 (void) make_door_call(handle
, &request
, sizeof (request
),
1028 &response
, sizeof (response
));
1030 handle_do_close(handle
);
1032 return (SCF_SUCCESS
);
1037 * _HANDLE_DESTROYED - dp's handle has been destroyed
1038 * _INTERNAL - server response too big
1039 * entity already set up with different type
1040 * _NO_RESOURCES - server out of memory
1043 datael_attach(scf_datael_t
*dp
)
1045 scf_handle_t
*h
= dp
->rd_handle
;
1047 struct rep_protocol_entity_setup request
;
1048 rep_protocol_response_t response
;
1051 assert(MUTEX_HELD(&h
->rh_lock
));
1053 dp
->rd_reset
= 0; /* setup implicitly resets */
1055 if (h
->rh_flags
& HANDLE_DEAD
)
1056 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
1058 if (!handle_is_bound(h
))
1059 return (SCF_SUCCESS
); /* nothing to do */
1061 request
.rpr_request
= REP_PROTOCOL_ENTITY_SETUP
;
1062 request
.rpr_entityid
= dp
->rd_entity
;
1063 request
.rpr_entitytype
= dp
->rd_type
;
1065 r
= make_door_call(h
, &request
, sizeof (request
),
1066 &response
, sizeof (response
));
1068 if (r
== NOT_BOUND
|| r
== CALL_FAILED
)
1069 return (SCF_SUCCESS
);
1070 if (r
== RESULT_TOO_BIG
)
1071 return (scf_set_error(SCF_ERROR_INTERNAL
));
1073 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1074 return (scf_set_error(proto_error(response
.rpr_response
)));
1076 return (SCF_SUCCESS
);
1081 * _HANDLE_DESTROYED - iter's handle has been destroyed
1082 * _INTERNAL - server response too big
1083 * iter already existed
1087 iter_attach(scf_iter_t
*iter
)
1089 scf_handle_t
*h
= iter
->iter_handle
;
1090 struct rep_protocol_iter_request request
;
1091 struct rep_protocol_response response
;
1094 assert(MUTEX_HELD(&h
->rh_lock
));
1096 if (h
->rh_flags
& HANDLE_DEAD
)
1097 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
1099 if (!handle_is_bound(h
))
1100 return (SCF_SUCCESS
); /* nothing to do */
1102 request
.rpr_request
= REP_PROTOCOL_ITER_SETUP
;
1103 request
.rpr_iterid
= iter
->iter_id
;
1105 r
= make_door_call(h
, &request
, sizeof (request
),
1106 &response
, sizeof (response
));
1108 if (r
== NOT_BOUND
|| r
== CALL_FAILED
)
1109 return (SCF_SUCCESS
);
1110 if (r
== RESULT_TOO_BIG
)
1111 return (scf_set_error(SCF_ERROR_INTERNAL
));
1113 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1114 return (scf_set_error(proto_error(response
.rpr_response
)));
1116 return (SCF_SUCCESS
);
1121 * _IN_USE - handle already bound
1122 * _NO_SERVER - server door could not be open()ed
1124 * door_info() failed
1125 * _VERSION_MISMATCH - server returned bad file descriptor
1126 * server claimed bad request
1127 * server reported version mismatch
1128 * server refused with unknown reason
1130 * _NO_RESOURCES - server is out of memory
1131 * _PERMISSION_DENIED
1132 * _INTERNAL - could not set up entities or iters
1133 * server response too big
1135 * perhaps this should try multiple times.
1138 scf_handle_bind(scf_handle_t
*handle
)
1147 repository_door_request_t request
;
1148 repository_door_response_t response
;
1149 const char *door_name
= default_door_path
;
1151 (void) pthread_mutex_lock(&handle
->rh_lock
);
1152 if (handle_is_bound(handle
)) {
1153 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1154 return (scf_set_error(SCF_ERROR_IN_USE
));
1157 /* wait until any active fd users have cleared out */
1158 while (handle
->rh_fd_users
> 0) {
1161 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
,
1163 (void) pthread_cond_wait(&handle
->rh_cv
, &handle
->rh_lock
);
1164 (void) pthread_setcancelstate(cancel_state
, NULL
);
1167 /* check again, since we had to drop the lock */
1168 if (handle_is_bound(handle
)) {
1169 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1170 return (scf_set_error(SCF_ERROR_IN_USE
));
1173 assert(handle
->rh_doorfd
== -1 && handle
->rh_doorfd_old
== -1);
1175 if (handle
->rh_doorpath
[0] != 0)
1176 door_name
= handle
->rh_doorpath
;
1178 fd
= open(door_name
, O_RDONLY
, 0);
1180 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1181 return (scf_set_error(SCF_ERROR_NO_SERVER
));
1184 request
.rdr_version
= REPOSITORY_DOOR_VERSION
;
1185 request
.rdr_request
= REPOSITORY_DOOR_REQUEST_CONNECT
;
1186 request
.rdr_flags
= handle
->rh_flags
;
1187 request
.rdr_debug
= handle
->rh_debug
;
1191 res
= make_door_call_retfd(fd
, &request
, sizeof (request
),
1192 &response
, sizeof (response
), &handle
->rh_doorfd
);
1197 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1199 assert(res
!= NOT_BOUND
);
1200 if (res
== CALL_FAILED
)
1201 return (scf_set_error(SCF_ERROR_NO_SERVER
));
1202 assert(res
== RESULT_TOO_BIG
);
1203 return (scf_set_error(SCF_ERROR_INTERNAL
));
1206 if (handle
->rh_doorfd
< 0) {
1207 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1209 switch (response
.rdr_status
) {
1210 case REPOSITORY_DOOR_SUCCESS
:
1211 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1213 case REPOSITORY_DOOR_FAIL_BAD_REQUEST
:
1214 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1216 case REPOSITORY_DOOR_FAIL_VERSION_MISMATCH
:
1217 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1219 case REPOSITORY_DOOR_FAIL_BAD_FLAG
:
1220 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1222 case REPOSITORY_DOOR_FAIL_NO_RESOURCES
:
1223 return (scf_set_error(SCF_ERROR_NO_RESOURCES
));
1225 case REPOSITORY_DOOR_FAIL_PERMISSION_DENIED
:
1226 return (scf_set_error(SCF_ERROR_PERMISSION_DENIED
));
1229 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH
));
1233 (void) fcntl(handle
->rh_doorfd
, F_SETFD
, FD_CLOEXEC
);
1235 if (door_info(handle
->rh_doorfd
, &info
) < 0) {
1236 (void) close(handle
->rh_doorfd
);
1237 handle
->rh_doorfd
= -1;
1239 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1240 return (scf_set_error(SCF_ERROR_NO_SERVER
));
1243 handle
->rh_doorpid
= pid
;
1244 handle
->rh_doorid
= info
.di_uniquifier
;
1247 * Now, re-attach everything
1249 for (el
= uu_list_first(handle
->rh_dataels
); el
!= NULL
;
1250 el
= uu_list_next(handle
->rh_dataels
, el
)) {
1251 if (datael_attach(el
) == -1) {
1252 assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED
);
1253 (void) handle_unbind_unlocked(handle
);
1254 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1259 for (iter
= uu_list_first(handle
->rh_iters
); iter
!= NULL
;
1260 iter
= uu_list_next(handle
->rh_iters
, iter
)) {
1261 if (iter_attach(iter
) == -1) {
1262 assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED
);
1263 (void) handle_unbind_unlocked(handle
);
1264 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1268 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1269 return (SCF_SUCCESS
);
1273 scf_handle_unbind(scf_handle_t
*handle
)
1276 (void) pthread_mutex_lock(&handle
->rh_lock
);
1277 ret
= handle_unbind_unlocked(handle
);
1278 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1279 return (ret
== SCF_SUCCESS
? ret
: scf_set_error(SCF_ERROR_NOT_BOUND
));
1282 static scf_handle_t
*
1283 handle_get(scf_handle_t
*h
)
1285 (void) pthread_mutex_lock(&h
->rh_lock
);
1286 if (h
->rh_flags
& HANDLE_DEAD
) {
1287 (void) pthread_mutex_unlock(&h
->rh_lock
);
1288 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED
);
1291 (void) pthread_mutex_unlock(&h
->rh_lock
);
1296 * Called when an object is removed from the handle. On the last remove,
1297 * cleans up and frees the handle.
1300 handle_unrefed(scf_handle_t
*handle
)
1306 scf_instance_t
*inst
;
1307 scf_snapshot_t
*snap
;
1308 scf_snaplevel_t
*snaplvl
;
1309 scf_propertygroup_t
*pg
;
1310 scf_property_t
*prop
;
1312 assert(MUTEX_HELD(&handle
->rh_lock
));
1315 * Don't do anything if the handle has not yet been destroyed, there
1316 * are still external references, or we're already doing unrefed
1319 if (!(handle
->rh_flags
& HANDLE_DEAD
) ||
1320 handle
->rh_extrefs
> 0 ||
1321 handle
->rh_fd_users
> 0 ||
1322 (handle
->rh_flags
& HANDLE_UNREFED
)) {
1323 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1327 handle
->rh_flags
|= HANDLE_UNREFED
;
1330 * Now that we know that there are no external references, and the
1331 * HANDLE_DEAD flag keeps new ones from appearing, we can clean up
1332 * our subhandles and destroy the handle completely.
1334 assert(handle
->rh_intrefs
>= 0);
1335 handle
->rh_extrefs
= handle
->rh_intrefs
;
1336 handle
->rh_intrefs
= 0;
1337 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1339 handle_hold_subhandles(handle
, RH_HOLD_ALL
);
1341 iter
= handle
->rh_iter
;
1342 sc
= handle
->rh_scope
;
1343 svc
= handle
->rh_service
;
1344 inst
= handle
->rh_instance
;
1345 snap
= handle
->rh_snapshot
;
1346 snaplvl
= handle
->rh_snaplvl
;
1348 prop
= handle
->rh_property
;
1349 v
= handle
->rh_value
;
1351 handle
->rh_iter
= NULL
;
1352 handle
->rh_scope
= NULL
;
1353 handle
->rh_service
= NULL
;
1354 handle
->rh_instance
= NULL
;
1355 handle
->rh_snapshot
= NULL
;
1356 handle
->rh_snaplvl
= NULL
;
1357 handle
->rh_pg
= NULL
;
1358 handle
->rh_property
= NULL
;
1359 handle
->rh_value
= NULL
;
1362 scf_iter_destroy(iter
);
1364 scf_scope_destroy(sc
);
1366 scf_service_destroy(svc
);
1368 scf_instance_destroy(inst
);
1370 scf_snapshot_destroy(snap
);
1371 if (snaplvl
!= NULL
)
1372 scf_snaplevel_destroy(snaplvl
);
1376 scf_property_destroy(prop
);
1378 scf_value_destroy(v
);
1380 (void) pthread_mutex_lock(&handle
->rh_lock
);
1382 /* there should be no outstanding children at this point */
1383 assert(handle
->rh_extrefs
== 0);
1384 assert(handle
->rh_intrefs
== 0);
1385 assert(handle
->rh_values
== 0);
1386 assert(handle
->rh_entries
== 0);
1387 assert(uu_list_numnodes(handle
->rh_dataels
) == 0);
1388 assert(uu_list_numnodes(handle
->rh_iters
) == 0);
1390 uu_list_destroy(handle
->rh_dataels
);
1391 uu_list_destroy(handle
->rh_iters
);
1392 handle
->rh_dataels
= NULL
;
1393 handle
->rh_iters
= NULL
;
1394 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1396 (void) pthread_mutex_destroy(&handle
->rh_lock
);
1402 scf_handle_destroy(scf_handle_t
*handle
)
1407 (void) pthread_mutex_lock(&handle
->rh_lock
);
1408 if (handle
->rh_flags
& HANDLE_DEAD
) {
1410 * This is an error (you are not allowed to reference the
1411 * handle after it is destroyed), but we can't report it.
1413 (void) pthread_mutex_unlock(&handle
->rh_lock
);
1416 handle
->rh_flags
|= HANDLE_DEAD
;
1417 (void) handle_unbind_unlocked(handle
);
1418 handle_unrefed(handle
);
1422 scf_myname(scf_handle_t
*h
, char *out
, size_t len
)
1426 if (!handle_has_server(h
))
1427 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
1429 cp
= getenv("SMF_FMRI");
1431 return (scf_set_error(SCF_ERROR_NOT_SET
));
1433 return (strlcpy(out
, cp
, len
));
1437 handle_alloc_entityid(scf_handle_t
*h
)
1441 assert(MUTEX_HELD(&h
->rh_lock
));
1443 if (uu_list_numnodes(h
->rh_dataels
) == UINT32_MAX
)
1444 return (0); /* no ids available */
1447 * The following loop assumes that there are not a huge number of
1448 * outstanding entities when we've wrapped. If that ends up not
1449 * being the case, the O(N^2) nature of this search will hurt a lot,
1450 * and the data structure should be switched to an AVL tree.
1452 nextid
= h
->rh_nextentity
+ 1;
1458 h
->rh_flags
|= HANDLE_WRAPPED_ENTITY
;
1460 if (!(h
->rh_flags
& HANDLE_WRAPPED_ENTITY
))
1463 cur
= uu_list_find(h
->rh_dataels
, NULL
, &nextid
, NULL
);
1465 break; /* not in use */
1467 if (nextid
== h
->rh_nextentity
)
1468 return (0); /* wrapped around; no ids available */
1472 h
->rh_nextentity
= nextid
;
1477 handle_alloc_iterid(scf_handle_t
*h
)
1481 assert(MUTEX_HELD(&h
->rh_lock
));
1483 if (uu_list_numnodes(h
->rh_iters
) == UINT32_MAX
)
1484 return (0); /* no ids available */
1486 /* see the comment in handle_alloc_entityid */
1487 nextid
= h
->rh_nextiter
+ 1;
1493 h
->rh_flags
|= HANDLE_WRAPPED_ITER
;
1495 if (!(h
->rh_flags
& HANDLE_WRAPPED_ITER
))
1496 break; /* not yet wrapped */
1498 cur
= uu_list_find(h
->rh_iters
, NULL
, &nextid
, NULL
);
1500 break; /* not in use */
1502 if (nextid
== h
->rh_nextiter
)
1503 return (0); /* wrapped around; no ids available */
1507 h
->rh_nextiter
= nextid
;
1512 handle_next_changeid(scf_handle_t
*handle
)
1516 assert(MUTEX_HELD(&handle
->rh_lock
));
1518 nextid
= ++handle
->rh_nextchangeid
;
1520 nextid
= ++handle
->rh_nextchangeid
;
1526 * _INVALID_ARGUMENT - h is NULL
1528 * _INTERNAL - server response too big
1529 * entity already set up with different type
1533 datael_init(scf_datael_t
*dp
, scf_handle_t
*h
, uint32_t type
)
1538 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1540 uu_list_node_init(dp
, &dp
->rd_node
, datael_pool
);
1546 (void) pthread_mutex_lock(&h
->rh_lock
);
1547 if (h
->rh_flags
& HANDLE_DEAD
) {
1549 * we're in undefined territory (the user cannot use a handle
1550 * directly after it has been destroyed), but we don't want
1551 * to allow any new references to happen, so we fail here.
1553 (void) pthread_mutex_unlock(&h
->rh_lock
);
1554 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
1556 dp
->rd_entity
= handle_alloc_entityid(h
);
1557 if (dp
->rd_entity
== 0) {
1558 (void) pthread_mutex_unlock(&h
->rh_lock
);
1559 uu_list_node_fini(dp
, &dp
->rd_node
, datael_pool
);
1560 return (scf_set_error(SCF_ERROR_NO_MEMORY
));
1563 ret
= datael_attach(dp
);
1565 (void) uu_list_insert_before(h
->rh_dataels
, NULL
, dp
);
1568 uu_list_node_fini(dp
, &dp
->rd_node
, datael_pool
);
1570 (void) pthread_mutex_unlock(&h
->rh_lock
);
1576 datael_destroy(scf_datael_t
*dp
)
1578 scf_handle_t
*h
= dp
->rd_handle
;
1580 struct rep_protocol_entity_teardown request
;
1581 rep_protocol_response_t response
;
1583 (void) pthread_mutex_lock(&h
->rh_lock
);
1584 uu_list_remove(h
->rh_dataels
, dp
);
1587 if (handle_is_bound(h
)) {
1588 request
.rpr_request
= REP_PROTOCOL_ENTITY_TEARDOWN
;
1589 request
.rpr_entityid
= dp
->rd_entity
;
1591 (void) make_door_call(h
, &request
, sizeof (request
),
1592 &response
, sizeof (response
));
1594 handle_unrefed(h
); /* drops h->rh_lock */
1596 dp
->rd_handle
= NULL
;
1599 static scf_handle_t
*
1600 datael_handle(const scf_datael_t
*dp
)
1602 return (handle_get(dp
->rd_handle
));
1606 * We delay ENTITY_RESETs until right before the entity is used. By doing
1607 * them lazily, we remove quite a few unnecessary calls.
1610 datael_do_reset_locked(scf_datael_t
*dp
)
1612 scf_handle_t
*h
= dp
->rd_handle
;
1614 struct rep_protocol_entity_reset request
;
1615 rep_protocol_response_t response
;
1617 assert(MUTEX_HELD(&h
->rh_lock
));
1619 request
.rpr_request
= REP_PROTOCOL_ENTITY_RESET
;
1620 request
.rpr_entityid
= dp
->rd_entity
;
1622 (void) make_door_call(h
, &request
, sizeof (request
),
1623 &response
, sizeof (response
));
1629 datael_reset_locked(scf_datael_t
*dp
)
1631 assert(MUTEX_HELD(&dp
->rd_handle
->rh_lock
));
1636 datael_reset(scf_datael_t
*dp
)
1638 scf_handle_t
*h
= dp
->rd_handle
;
1640 (void) pthread_mutex_lock(&h
->rh_lock
);
1642 (void) pthread_mutex_unlock(&h
->rh_lock
);
1646 datael_finish_reset(const scf_datael_t
*dp_arg
)
1648 scf_datael_t
*dp
= (scf_datael_t
*)dp_arg
;
1651 datael_do_reset_locked(dp
);
1655 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
1656 * big, bad entity id, request not applicable to entity, name too long for
1657 * buffer), _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED (snaplevel is not of an
1661 datael_get_name(const scf_datael_t
*dp
, char *buf
, size_t size
, uint32_t type
)
1663 scf_handle_t
*h
= dp
->rd_handle
;
1665 struct rep_protocol_entity_name request
;
1666 struct rep_protocol_name_response response
;
1669 (void) pthread_mutex_lock(&h
->rh_lock
);
1670 request
.rpr_request
= REP_PROTOCOL_ENTITY_NAME
;
1671 request
.rpr_entityid
= dp
->rd_entity
;
1672 request
.rpr_answertype
= type
;
1674 datael_finish_reset(dp
);
1675 r
= make_door_call(h
, &request
, sizeof (request
),
1676 &response
, sizeof (response
));
1677 (void) pthread_mutex_unlock(&h
->rh_lock
);
1680 DOOR_ERRORS_BLOCK(r
);
1682 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
1683 assert(response
.rpr_response
!= REP_PROTOCOL_FAIL_BAD_REQUEST
);
1684 if (response
.rpr_response
== REP_PROTOCOL_FAIL_NOT_FOUND
)
1685 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
));
1686 return (scf_set_error(proto_error(response
.rpr_response
)));
1688 return (strlcpy(buf
, response
.rpr_name
, size
));
1692 * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
1693 * (server response too big, bad element id), _EXISTS (elements have same id),
1694 * _NOT_SET, _DELETED, _CONSTRAINT_VIOLATED, _NOT_FOUND (scope has no parent),
1698 datael_get_parent(const scf_datael_t
*dp
, scf_datael_t
*pp
)
1700 scf_handle_t
*h
= dp
->rd_handle
;
1702 struct rep_protocol_entity_parent request
;
1703 struct rep_protocol_response response
;
1707 if (h
!= pp
->rd_handle
)
1708 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
1710 (void) pthread_mutex_lock(&h
->rh_lock
);
1711 request
.rpr_request
= REP_PROTOCOL_ENTITY_GET_PARENT
;
1712 request
.rpr_entityid
= dp
->rd_entity
;
1713 request
.rpr_outid
= pp
->rd_entity
;
1715 datael_finish_reset(dp
);
1716 datael_finish_reset(pp
);
1717 r
= make_door_call(h
, &request
, sizeof (request
),
1718 &response
, sizeof (response
));
1719 (void) pthread_mutex_unlock(&h
->rh_lock
);
1722 DOOR_ERRORS_BLOCK(r
);
1724 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
1725 if (response
.rpr_response
== REP_PROTOCOL_FAIL_TYPE_MISMATCH
)
1726 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
));
1727 return (scf_set_error(proto_error(response
.rpr_response
)));
1730 return (SCF_SUCCESS
);
1734 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1735 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1736 * too big, bad id, iter already exists, element cannot have children of type,
1737 * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1738 * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1739 * _BACKEND_ACCESS, _NOT_FOUND.
1742 datael_get_child_composed_locked(const scf_datael_t
*dp
, const char *name
,
1743 uint32_t type
, scf_datael_t
*out
, scf_iter_t
*iter
)
1745 struct rep_protocol_iter_start request
;
1746 struct rep_protocol_iter_read read_request
;
1747 struct rep_protocol_response response
;
1749 scf_handle_t
*h
= dp
->rd_handle
;
1752 if (h
!= out
->rd_handle
)
1753 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
1755 if (out
->rd_type
!= type
)
1756 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1758 assert(MUTEX_HELD(&h
->rh_lock
));
1759 assert(iter
!= NULL
);
1761 scf_iter_reset_locked(iter
);
1762 iter
->iter_type
= type
;
1764 request
.rpr_request
= REP_PROTOCOL_ITER_START
;
1765 request
.rpr_iterid
= iter
->iter_id
;
1766 request
.rpr_entity
= dp
->rd_entity
;
1767 request
.rpr_itertype
= type
;
1768 request
.rpr_flags
= RP_ITER_START_EXACT
| RP_ITER_START_COMPOSED
;
1770 if (name
== NULL
|| strlcpy(request
.rpr_pattern
, name
,
1771 sizeof (request
.rpr_pattern
)) >= sizeof (request
.rpr_pattern
)) {
1772 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1775 datael_finish_reset(dp
);
1776 datael_finish_reset(out
);
1779 * We hold the handle lock across both door calls, so that they
1782 r
= make_door_call(h
, &request
, sizeof (request
),
1783 &response
, sizeof (response
));
1786 DOOR_ERRORS_BLOCK(r
);
1788 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1789 return (scf_set_error(proto_error(response
.rpr_response
)));
1791 iter
->iter_sequence
++;
1793 read_request
.rpr_request
= REP_PROTOCOL_ITER_READ
;
1794 read_request
.rpr_iterid
= iter
->iter_id
;
1795 read_request
.rpr_sequence
= iter
->iter_sequence
;
1796 read_request
.rpr_entityid
= out
->rd_entity
;
1798 r
= make_door_call(h
, &read_request
, sizeof (read_request
),
1799 &response
, sizeof (response
));
1801 scf_iter_reset_locked(iter
);
1804 DOOR_ERRORS_BLOCK(r
);
1806 if (response
.rpr_response
== REP_PROTOCOL_DONE
) {
1807 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
1810 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
1811 if (response
.rpr_response
== REP_PROTOCOL_FAIL_NOT_SET
||
1812 response
.rpr_response
== REP_PROTOCOL_FAIL_BAD_REQUEST
)
1813 return (scf_set_error(SCF_ERROR_INTERNAL
));
1814 return (scf_set_error(proto_error(response
.rpr_response
)));
1821 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1822 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1823 * too big, bad id, element cannot have children of type, type is invalid),
1824 * _NOT_SET, _DELETED, _NO_RESOURCES, _BACKEND_ACCESS.
1827 datael_get_child_locked(const scf_datael_t
*dp
, const char *name
,
1828 uint32_t type
, scf_datael_t
*out
)
1830 struct rep_protocol_entity_get_child request
;
1831 struct rep_protocol_response response
;
1833 scf_handle_t
*h
= dp
->rd_handle
;
1836 if (h
!= out
->rd_handle
)
1837 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
1839 if (out
->rd_type
!= type
)
1840 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1842 assert(MUTEX_HELD(&h
->rh_lock
));
1844 request
.rpr_request
= REP_PROTOCOL_ENTITY_GET_CHILD
;
1845 request
.rpr_entityid
= dp
->rd_entity
;
1846 request
.rpr_childid
= out
->rd_entity
;
1848 if (name
== NULL
|| strlcpy(request
.rpr_name
, name
,
1849 sizeof (request
.rpr_name
)) >= sizeof (request
.rpr_name
)) {
1850 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
1853 datael_finish_reset(dp
);
1854 datael_finish_reset(out
);
1856 r
= make_door_call(h
, &request
, sizeof (request
),
1857 &response
, sizeof (response
));
1860 DOOR_ERRORS_BLOCK(r
);
1862 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
1863 return (scf_set_error(proto_error(response
.rpr_response
)));
1868 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1869 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1870 * too big, bad id, iter already exists, element cannot have children of type,
1871 * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1872 * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1873 * _BACKEND_ACCESS, _NOT_FOUND.
1876 datael_get_child(const scf_datael_t
*dp
, const char *name
, uint32_t type
,
1877 scf_datael_t
*out
, boolean_t composed
)
1879 scf_handle_t
*h
= dp
->rd_handle
;
1883 scf_iter_t
*iter
= NULL
;
1886 iter
= HANDLE_HOLD_ITER(h
);
1890 case REP_PROTOCOL_ENTITY_SERVICE
:
1891 out
= &HANDLE_HOLD_SERVICE(h
)->rd_d
;
1892 held
= RH_HOLD_SERVICE
;
1895 case REP_PROTOCOL_ENTITY_INSTANCE
:
1896 out
= &HANDLE_HOLD_INSTANCE(h
)->rd_d
;
1897 held
= RH_HOLD_INSTANCE
;
1900 case REP_PROTOCOL_ENTITY_SNAPSHOT
:
1901 out
= &HANDLE_HOLD_SNAPSHOT(h
)->rd_d
;
1902 held
= RH_HOLD_SNAPSHOT
;
1905 case REP_PROTOCOL_ENTITY_SNAPLEVEL
:
1906 out
= &HANDLE_HOLD_SNAPLVL(h
)->rd_d
;
1907 held
= RH_HOLD_SNAPLVL
;
1910 case REP_PROTOCOL_ENTITY_PROPERTYGRP
:
1911 out
= &HANDLE_HOLD_PG(h
)->rd_d
;
1915 case REP_PROTOCOL_ENTITY_PROPERTY
:
1916 out
= &HANDLE_HOLD_PROPERTY(h
)->rd_d
;
1917 held
= RH_HOLD_PROPERTY
;
1926 (void) pthread_mutex_lock(&h
->rh_lock
);
1928 ret
= datael_get_child_composed_locked(dp
, name
, type
, out
,
1931 ret
= datael_get_child_locked(dp
, name
, type
, out
);
1932 (void) pthread_mutex_unlock(&h
->rh_lock
);
1935 HANDLE_RELE_ITER(h
);
1938 handle_rele_subhandles(h
, held
);
1946 * _INVALID_ARGUMENT - name is too long
1949 * cannot create children for dp's type of node
1950 * _NOT_BOUND - handle is not bound
1951 * _CONNECTION_BROKEN - server is not reachable
1952 * _INTERNAL - server response too big
1953 * dp or cp has unknown id
1954 * type is _PROPERTYGRP
1956 * dp cannot have children of type type
1957 * database is corrupt
1958 * _EXISTS - dp & cp have the same id
1959 * _EXISTS - child already exists
1960 * _DELETED - dp has been deleted
1961 * _NOT_SET - dp is reset
1963 * _PERMISSION_DENIED
1968 datael_add_child(const scf_datael_t
*dp
, const char *name
, uint32_t type
,
1971 scf_handle_t
*h
= dp
->rd_handle
;
1973 struct rep_protocol_entity_create_child request
;
1974 struct rep_protocol_response response
;
1980 case REP_PROTOCOL_ENTITY_SCOPE
:
1981 cp
= &HANDLE_HOLD_SCOPE(h
)->rd_d
;
1982 held
= RH_HOLD_SCOPE
;
1984 case REP_PROTOCOL_ENTITY_SERVICE
:
1985 cp
= &HANDLE_HOLD_SERVICE(h
)->rd_d
;
1986 held
= RH_HOLD_SERVICE
;
1988 case REP_PROTOCOL_ENTITY_INSTANCE
:
1989 cp
= &HANDLE_HOLD_INSTANCE(h
)->rd_d
;
1990 held
= RH_HOLD_INSTANCE
;
1992 case REP_PROTOCOL_ENTITY_SNAPSHOT
:
1997 assert(h
== cp
->rd_handle
);
1999 } else if (h
!= cp
->rd_handle
) {
2000 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2003 if (strlcpy(request
.rpr_name
, name
, sizeof (request
.rpr_name
)) >=
2004 sizeof (request
.rpr_name
)) {
2005 r
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2009 (void) pthread_mutex_lock(&h
->rh_lock
);
2010 request
.rpr_request
= REP_PROTOCOL_ENTITY_CREATE_CHILD
;
2011 request
.rpr_entityid
= dp
->rd_entity
;
2012 request
.rpr_childtype
= type
;
2013 request
.rpr_childid
= cp
->rd_entity
;
2015 datael_finish_reset(dp
);
2016 request
.rpr_changeid
= handle_next_changeid(h
);
2017 r
= make_door_call(h
, &request
, sizeof (request
),
2018 &response
, sizeof (response
));
2019 (void) pthread_mutex_unlock(&h
->rh_lock
);
2022 handle_rele_subhandles(h
, held
);
2025 DOOR_ERRORS_BLOCK(r
);
2027 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2028 return (scf_set_error(proto_error(response
.rpr_response
)));
2030 return (SCF_SUCCESS
);
2034 handle_rele_subhandles(h
, held
);
2039 datael_add_pg(const scf_datael_t
*dp
, const char *name
, const char *type
,
2040 uint32_t flags
, scf_datael_t
*cp
)
2042 scf_handle_t
*h
= dp
->rd_handle
;
2044 struct rep_protocol_entity_create_pg request
;
2045 struct rep_protocol_response response
;
2048 int holding_els
= 0;
2052 cp
= &HANDLE_HOLD_PG(h
)->rd_d
;
2053 assert(h
== cp
->rd_handle
);
2055 } else if (h
!= cp
->rd_handle
) {
2056 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2059 request
.rpr_request
= REP_PROTOCOL_ENTITY_CREATE_PG
;
2061 if (name
== NULL
|| strlcpy(request
.rpr_name
, name
,
2062 sizeof (request
.rpr_name
)) > sizeof (request
.rpr_name
)) {
2063 r
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2067 if (type
== NULL
|| strlcpy(request
.rpr_type
, type
,
2068 sizeof (request
.rpr_type
)) > sizeof (request
.rpr_type
)) {
2069 r
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2073 (void) pthread_mutex_lock(&h
->rh_lock
);
2074 request
.rpr_entityid
= dp
->rd_entity
;
2075 request
.rpr_childid
= cp
->rd_entity
;
2076 request
.rpr_flags
= flags
;
2078 datael_finish_reset(dp
);
2079 datael_finish_reset(cp
);
2080 request
.rpr_changeid
= handle_next_changeid(h
);
2081 r
= make_door_call(h
, &request
, sizeof (request
),
2082 &response
, sizeof (response
));
2083 (void) pthread_mutex_unlock(&h
->rh_lock
);
2089 DOOR_ERRORS_BLOCK(r
);
2091 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2092 return (scf_set_error(proto_error(response
.rpr_response
)));
2094 return (SCF_SUCCESS
);
2103 datael_delete(const scf_datael_t
*dp
)
2105 scf_handle_t
*h
= dp
->rd_handle
;
2107 struct rep_protocol_entity_delete request
;
2108 struct rep_protocol_response response
;
2111 (void) pthread_mutex_lock(&h
->rh_lock
);
2112 request
.rpr_request
= REP_PROTOCOL_ENTITY_DELETE
;
2113 request
.rpr_entityid
= dp
->rd_entity
;
2115 datael_finish_reset(dp
);
2116 request
.rpr_changeid
= handle_next_changeid(h
);
2117 r
= make_door_call(h
, &request
, sizeof (request
),
2118 &response
, sizeof (response
));
2119 (void) pthread_mutex_unlock(&h
->rh_lock
);
2122 DOOR_ERRORS_BLOCK(r
);
2124 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2125 return (scf_set_error(proto_error(response
.rpr_response
)));
2127 return (SCF_SUCCESS
);
2132 * _INVALID_ARGUMENT - h is NULL
2134 * _HANDLE_DESTROYED - h has been destroyed
2135 * _INTERNAL - server response too big
2136 * iter already exists
2140 scf_iter_create(scf_handle_t
*h
)
2145 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2149 iter
= uu_zalloc(sizeof (*iter
));
2151 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2155 uu_list_node_init(iter
, &iter
->iter_node
, iter_pool
);
2156 iter
->iter_handle
= h
;
2157 iter
->iter_sequence
= 1;
2158 iter
->iter_type
= REP_PROTOCOL_ENTITY_NONE
;
2160 (void) pthread_mutex_lock(&h
->rh_lock
);
2161 iter
->iter_id
= handle_alloc_iterid(h
);
2162 if (iter
->iter_id
== 0) {
2163 (void) pthread_mutex_unlock(&h
->rh_lock
);
2164 uu_list_node_fini(iter
, &iter
->iter_node
, iter_pool
);
2165 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2169 if (iter_attach(iter
) == -1) {
2170 uu_list_node_fini(iter
, &iter
->iter_node
, iter_pool
);
2171 (void) pthread_mutex_unlock(&h
->rh_lock
);
2175 (void) uu_list_insert_before(h
->rh_iters
, NULL
, iter
);
2177 (void) pthread_mutex_unlock(&h
->rh_lock
);
2182 scf_iter_handle(const scf_iter_t
*iter
)
2184 return (handle_get(iter
->iter_handle
));
2188 scf_iter_reset_locked(scf_iter_t
*iter
)
2190 struct rep_protocol_iter_request request
;
2191 struct rep_protocol_response response
;
2193 request
.rpr_request
= REP_PROTOCOL_ITER_RESET
;
2194 request
.rpr_iterid
= iter
->iter_id
;
2196 assert(MUTEX_HELD(&iter
->iter_handle
->rh_lock
));
2198 (void) make_door_call(iter
->iter_handle
,
2199 &request
, sizeof (request
), &response
, sizeof (response
));
2201 iter
->iter_type
= REP_PROTOCOL_ENTITY_NONE
;
2202 iter
->iter_sequence
= 1;
2206 scf_iter_reset(scf_iter_t
*iter
)
2208 (void) pthread_mutex_lock(&iter
->iter_handle
->rh_lock
);
2209 scf_iter_reset_locked(iter
);
2210 (void) pthread_mutex_unlock(&iter
->iter_handle
->rh_lock
);
2214 scf_iter_destroy(scf_iter_t
*iter
)
2216 scf_handle_t
*handle
;
2218 struct rep_protocol_iter_request request
;
2219 struct rep_protocol_response response
;
2224 handle
= iter
->iter_handle
;
2226 (void) pthread_mutex_lock(&handle
->rh_lock
);
2227 request
.rpr_request
= REP_PROTOCOL_ITER_TEARDOWN
;
2228 request
.rpr_iterid
= iter
->iter_id
;
2230 (void) make_door_call(handle
, &request
, sizeof (request
),
2231 &response
, sizeof (response
));
2233 uu_list_remove(handle
->rh_iters
, iter
);
2234 --handle
->rh_extrefs
;
2235 handle_unrefed(handle
); /* drops h->rh_lock */
2236 iter
->iter_handle
= NULL
;
2238 uu_list_node_fini(iter
, &iter
->iter_node
, iter_pool
);
2243 handle_get_local_scope_locked(scf_handle_t
*handle
, scf_scope_t
*out
)
2245 struct rep_protocol_entity_get request
;
2246 struct rep_protocol_name_response response
;
2249 assert(MUTEX_HELD(&handle
->rh_lock
));
2251 if (handle
!= out
->rd_d
.rd_handle
)
2252 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2254 request
.rpr_request
= REP_PROTOCOL_ENTITY_GET
;
2255 request
.rpr_entityid
= out
->rd_d
.rd_entity
;
2256 request
.rpr_object
= RP_ENTITY_GET_MOST_LOCAL_SCOPE
;
2258 datael_finish_reset(&out
->rd_d
);
2259 r
= make_door_call(handle
, &request
, sizeof (request
),
2260 &response
, sizeof (response
));
2263 DOOR_ERRORS_BLOCK(r
);
2265 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
2266 return (scf_set_error(proto_error(response
.rpr_response
)));
2268 return (SCF_SUCCESS
);
2272 scf_iter_handle_scopes(scf_iter_t
*iter
, const scf_handle_t
*handle
)
2274 scf_handle_t
*h
= iter
->iter_handle
;
2276 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2278 (void) pthread_mutex_lock(&h
->rh_lock
);
2279 scf_iter_reset_locked(iter
);
2281 if (!handle_is_bound(h
)) {
2282 (void) pthread_mutex_unlock(&h
->rh_lock
);
2283 return (scf_set_error(SCF_ERROR_NOT_BOUND
));
2286 if (!handle_has_server_locked(h
)) {
2287 (void) pthread_mutex_unlock(&h
->rh_lock
);
2288 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
2291 iter
->iter_type
= REP_PROTOCOL_ENTITY_SCOPE
;
2292 iter
->iter_sequence
= 1;
2293 (void) pthread_mutex_unlock(&h
->rh_lock
);
2298 scf_iter_next_scope(scf_iter_t
*iter
, scf_scope_t
*out
)
2301 scf_handle_t
*h
= iter
->iter_handle
;
2303 if (h
!= out
->rd_d
.rd_handle
)
2304 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2306 (void) pthread_mutex_lock(&h
->rh_lock
);
2307 if (iter
->iter_type
== REP_PROTOCOL_ENTITY_NONE
) {
2308 (void) pthread_mutex_unlock(&h
->rh_lock
);
2309 return (scf_set_error(SCF_ERROR_NOT_SET
));
2311 if (iter
->iter_type
!= REP_PROTOCOL_ENTITY_SCOPE
) {
2312 (void) pthread_mutex_unlock(&h
->rh_lock
);
2313 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
2315 if (iter
->iter_sequence
== 1) {
2316 if ((ret
= handle_get_local_scope_locked(h
, out
)) ==
2318 iter
->iter_sequence
++;
2322 datael_reset_locked(&out
->rd_d
);
2325 (void) pthread_mutex_unlock(&h
->rh_lock
);
2330 scf_handle_get_scope(scf_handle_t
*h
, const char *name
, scf_scope_t
*out
)
2334 if (h
!= out
->rd_d
.rd_handle
)
2335 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2337 (void) pthread_mutex_lock(&h
->rh_lock
);
2338 if (strcmp(name
, SCF_SCOPE_LOCAL
) == 0) {
2339 ret
= handle_get_local_scope_locked(h
, out
);
2341 datael_reset_locked(&out
->rd_d
);
2342 if (uu_check_name(name
, 0) == -1)
2343 ret
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
2345 ret
= scf_set_error(SCF_ERROR_NOT_FOUND
);
2347 (void) pthread_mutex_unlock(&h
->rh_lock
);
2352 datael_setup_iter(scf_iter_t
*iter
, const scf_datael_t
*dp
, uint32_t res_type
,
2355 scf_handle_t
*h
= dp
->rd_handle
;
2357 struct rep_protocol_iter_start request
;
2358 struct rep_protocol_response response
;
2362 if (h
!= iter
->iter_handle
)
2363 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2365 (void) pthread_mutex_lock(&h
->rh_lock
);
2366 scf_iter_reset_locked(iter
);
2367 iter
->iter_type
= res_type
;
2369 request
.rpr_request
= REP_PROTOCOL_ITER_START
;
2370 request
.rpr_iterid
= iter
->iter_id
;
2371 request
.rpr_entity
= dp
->rd_entity
;
2372 request
.rpr_itertype
= res_type
;
2373 request
.rpr_flags
= RP_ITER_START_ALL
|
2374 (composed
? RP_ITER_START_COMPOSED
: 0);
2375 request
.rpr_pattern
[0] = 0;
2377 datael_finish_reset(dp
);
2378 r
= make_door_call(h
, &request
, sizeof (request
),
2379 &response
, sizeof (response
));
2382 (void) pthread_mutex_unlock(&h
->rh_lock
);
2383 DOOR_ERRORS_BLOCK(r
);
2385 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
2386 (void) pthread_mutex_unlock(&h
->rh_lock
);
2387 return (scf_set_error(proto_error(response
.rpr_response
)));
2389 iter
->iter_sequence
++;
2390 (void) pthread_mutex_unlock(&h
->rh_lock
);
2391 return (SCF_SUCCESS
);
2395 datael_setup_iter_pgtyped(scf_iter_t
*iter
, const scf_datael_t
*dp
,
2396 const char *pgtype
, boolean_t composed
)
2398 scf_handle_t
*h
= dp
->rd_handle
;
2400 struct rep_protocol_iter_start request
;
2401 struct rep_protocol_response response
;
2405 if (h
!= iter
->iter_handle
)
2406 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2408 if (pgtype
== NULL
|| strlcpy(request
.rpr_pattern
, pgtype
,
2409 sizeof (request
.rpr_pattern
)) >= sizeof (request
.rpr_pattern
)) {
2410 scf_iter_reset(iter
);
2411 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
2414 (void) pthread_mutex_lock(&h
->rh_lock
);
2415 request
.rpr_request
= REP_PROTOCOL_ITER_START
;
2416 request
.rpr_iterid
= iter
->iter_id
;
2417 request
.rpr_entity
= dp
->rd_entity
;
2418 request
.rpr_itertype
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
2419 request
.rpr_flags
= RP_ITER_START_PGTYPE
|
2420 (composed
? RP_ITER_START_COMPOSED
: 0);
2422 datael_finish_reset(dp
);
2423 scf_iter_reset_locked(iter
);
2424 iter
->iter_type
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
2426 r
= make_door_call(h
, &request
, sizeof (request
),
2427 &response
, sizeof (response
));
2430 (void) pthread_mutex_unlock(&h
->rh_lock
);
2432 DOOR_ERRORS_BLOCK(r
);
2434 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
2435 (void) pthread_mutex_unlock(&h
->rh_lock
);
2436 return (scf_set_error(proto_error(response
.rpr_response
)));
2438 iter
->iter_sequence
++;
2439 (void) pthread_mutex_unlock(&h
->rh_lock
);
2440 return (SCF_SUCCESS
);
2444 datael_iter_next(scf_iter_t
*iter
, scf_datael_t
*out
)
2446 scf_handle_t
*h
= iter
->iter_handle
;
2448 struct rep_protocol_iter_read request
;
2449 struct rep_protocol_response response
;
2452 if (h
!= out
->rd_handle
)
2453 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2455 (void) pthread_mutex_lock(&h
->rh_lock
);
2456 if (iter
->iter_type
== REP_PROTOCOL_ENTITY_NONE
||
2457 iter
->iter_sequence
== 1) {
2458 (void) pthread_mutex_unlock(&h
->rh_lock
);
2459 return (scf_set_error(SCF_ERROR_NOT_SET
));
2462 if (out
->rd_type
!= iter
->iter_type
) {
2463 (void) pthread_mutex_unlock(&h
->rh_lock
);
2464 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
2467 request
.rpr_request
= REP_PROTOCOL_ITER_READ
;
2468 request
.rpr_iterid
= iter
->iter_id
;
2469 request
.rpr_sequence
= iter
->iter_sequence
;
2470 request
.rpr_entityid
= out
->rd_entity
;
2472 datael_finish_reset(out
);
2473 r
= make_door_call(h
, &request
, sizeof (request
),
2474 &response
, sizeof (response
));
2477 (void) pthread_mutex_unlock(&h
->rh_lock
);
2478 DOOR_ERRORS_BLOCK(r
);
2481 if (response
.rpr_response
== REP_PROTOCOL_DONE
) {
2482 (void) pthread_mutex_unlock(&h
->rh_lock
);
2485 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
2486 (void) pthread_mutex_unlock(&h
->rh_lock
);
2487 return (scf_set_error(proto_error(response
.rpr_response
)));
2489 iter
->iter_sequence
++;
2490 (void) pthread_mutex_unlock(&h
->rh_lock
);
2496 scf_iter_scope_services(scf_iter_t
*iter
, const scf_scope_t
*s
)
2498 return (datael_setup_iter(iter
, &s
->rd_d
,
2499 REP_PROTOCOL_ENTITY_SERVICE
, 0));
2503 scf_iter_next_service(scf_iter_t
*iter
, scf_service_t
*out
)
2505 return (datael_iter_next(iter
, &out
->rd_d
));
2509 scf_iter_service_instances(scf_iter_t
*iter
, const scf_service_t
*svc
)
2511 return (datael_setup_iter(iter
, &svc
->rd_d
,
2512 REP_PROTOCOL_ENTITY_INSTANCE
, 0));
2516 scf_iter_next_instance(scf_iter_t
*iter
, scf_instance_t
*out
)
2518 return (datael_iter_next(iter
, &out
->rd_d
));
2522 scf_iter_service_pgs(scf_iter_t
*iter
, const scf_service_t
*svc
)
2524 return (datael_setup_iter(iter
, &svc
->rd_d
,
2525 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 0));
2529 scf_iter_service_pgs_typed(scf_iter_t
*iter
, const scf_service_t
*svc
,
2532 return (datael_setup_iter_pgtyped(iter
, &svc
->rd_d
, type
, 0));
2536 scf_iter_instance_snapshots(scf_iter_t
*iter
, const scf_instance_t
*inst
)
2538 return (datael_setup_iter(iter
, &inst
->rd_d
,
2539 REP_PROTOCOL_ENTITY_SNAPSHOT
, 0));
2543 scf_iter_next_snapshot(scf_iter_t
*iter
, scf_snapshot_t
*out
)
2545 return (datael_iter_next(iter
, &out
->rd_d
));
2549 scf_iter_instance_pgs(scf_iter_t
*iter
, const scf_instance_t
*inst
)
2551 return (datael_setup_iter(iter
, &inst
->rd_d
,
2552 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 0));
2556 scf_iter_instance_pgs_typed(scf_iter_t
*iter
, const scf_instance_t
*inst
,
2559 return (datael_setup_iter_pgtyped(iter
, &inst
->rd_d
, type
, 0));
2563 scf_iter_instance_pgs_composed(scf_iter_t
*iter
, const scf_instance_t
*inst
,
2564 const scf_snapshot_t
*snap
)
2566 if (snap
!= NULL
&& inst
->rd_d
.rd_handle
!= snap
->rd_d
.rd_handle
)
2567 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2569 return (datael_setup_iter(iter
, snap
? &snap
->rd_d
: &inst
->rd_d
,
2570 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 1));
2574 scf_iter_instance_pgs_typed_composed(scf_iter_t
*iter
,
2575 const scf_instance_t
*inst
, const scf_snapshot_t
*snap
, const char *type
)
2577 if (snap
!= NULL
&& inst
->rd_d
.rd_handle
!= snap
->rd_d
.rd_handle
)
2578 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2580 return (datael_setup_iter_pgtyped(iter
,
2581 snap
? &snap
->rd_d
: &inst
->rd_d
, type
, 1));
2585 scf_iter_snaplevel_pgs(scf_iter_t
*iter
, const scf_snaplevel_t
*inst
)
2587 return (datael_setup_iter(iter
, &inst
->rd_d
,
2588 REP_PROTOCOL_ENTITY_PROPERTYGRP
, 0));
2592 scf_iter_snaplevel_pgs_typed(scf_iter_t
*iter
, const scf_snaplevel_t
*inst
,
2595 return (datael_setup_iter_pgtyped(iter
, &inst
->rd_d
, type
, 0));
2599 scf_iter_next_pg(scf_iter_t
*iter
, scf_propertygroup_t
*out
)
2601 return (datael_iter_next(iter
, &out
->rd_d
));
2605 scf_iter_pg_properties(scf_iter_t
*iter
, const scf_propertygroup_t
*pg
)
2607 return (datael_setup_iter(iter
, &pg
->rd_d
,
2608 REP_PROTOCOL_ENTITY_PROPERTY
, 0));
2612 scf_iter_next_property(scf_iter_t
*iter
, scf_property_t
*out
)
2614 return (datael_iter_next(iter
, &out
->rd_d
));
2619 * _INVALID_ARGUMENT - handle is NULL
2620 * _INTERNAL - server response too big
2621 * entity already set up with different type
2626 scf_scope_create(scf_handle_t
*handle
)
2630 ret
= uu_zalloc(sizeof (*ret
));
2632 if (datael_init(&ret
->rd_d
, handle
,
2633 REP_PROTOCOL_ENTITY_SCOPE
) == -1) {
2638 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2645 scf_scope_handle(const scf_scope_t
*val
)
2647 return (datael_handle(&val
->rd_d
));
2651 scf_scope_destroy(scf_scope_t
*val
)
2656 datael_destroy(&val
->rd_d
);
2661 scf_scope_get_name(const scf_scope_t
*rep
, char *out
, size_t len
)
2663 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2668 scf_scope_get_parent(const scf_scope_t
*child
, scf_scope_t
*parent
)
2672 /* fake up the side-effects */
2673 datael_reset(&parent
->rd_d
);
2674 if (scf_scope_get_name(child
, name
, sizeof (name
)) < 0)
2676 return (scf_set_error(SCF_ERROR_NOT_FOUND
));
2680 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2681 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2684 scf_service_create(scf_handle_t
*handle
)
2687 ret
= uu_zalloc(sizeof (*ret
));
2689 if (datael_init(&ret
->rd_d
, handle
,
2690 REP_PROTOCOL_ENTITY_SERVICE
) == -1) {
2695 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2707 * _CONNECTION_BROKEN
2713 * _PERMISSION_DENIED
2718 scf_scope_add_service(const scf_scope_t
*scope
, const char *name
,
2721 return (datael_add_child(&scope
->rd_d
, name
,
2722 REP_PROTOCOL_ENTITY_SERVICE
, (svc
!= NULL
)? &svc
->rd_d
: NULL
));
2726 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2727 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2728 * _BACKEND_ACCESS, _NOT_FOUND.
2731 scf_scope_get_service(const scf_scope_t
*s
, const char *name
,
2734 return (datael_get_child(&s
->rd_d
, name
, REP_PROTOCOL_ENTITY_SERVICE
,
2735 svc
? &svc
->rd_d
: NULL
, 0));
2739 scf_service_handle(const scf_service_t
*val
)
2741 return (datael_handle(&val
->rd_d
));
2745 scf_service_delete(scf_service_t
*svc
)
2747 return (datael_delete(&svc
->rd_d
));
2751 scf_instance_delete(scf_instance_t
*inst
)
2753 return (datael_delete(&inst
->rd_d
));
2757 scf_pg_delete(scf_propertygroup_t
*pg
)
2759 return (datael_delete(&pg
->rd_d
));
2763 _scf_snapshot_delete(scf_snapshot_t
*snap
)
2765 return (datael_delete(&snap
->rd_d
));
2773 * _CONNECTION_BROKEN
2779 * _PERMISSION_DENIED
2784 scf_service_add_instance(const scf_service_t
*svc
, const char *name
,
2785 scf_instance_t
*instance
)
2787 return (datael_add_child(&svc
->rd_d
, name
,
2788 REP_PROTOCOL_ENTITY_INSTANCE
,
2789 (instance
!= NULL
)? &instance
->rd_d
: NULL
));
2794 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2795 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2796 * _BACKEND_ACCESS, _NOT_FOUND.
2799 scf_service_get_instance(const scf_service_t
*svc
, const char *name
,
2800 scf_instance_t
*inst
)
2802 return (datael_get_child(&svc
->rd_d
, name
, REP_PROTOCOL_ENTITY_INSTANCE
,
2803 inst
? &inst
->rd_d
: NULL
, 0));
2807 scf_service_add_pg(const scf_service_t
*svc
, const char *name
,
2808 const char *type
, uint32_t flags
, scf_propertygroup_t
*pg
)
2810 return (datael_add_pg(&svc
->rd_d
, name
, type
, flags
,
2811 (pg
!= NULL
)?&pg
->rd_d
: NULL
));
2815 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2816 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2817 * _BACKEND_ACCESS, _NOT_FOUND.
2820 scf_service_get_pg(const scf_service_t
*svc
, const char *name
,
2821 scf_propertygroup_t
*pg
)
2823 return (datael_get_child(&svc
->rd_d
, name
,
2824 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 0));
2828 scf_instance_add_pg(const scf_instance_t
*inst
, const char *name
,
2829 const char *type
, uint32_t flags
, scf_propertygroup_t
*pg
)
2831 return (datael_add_pg(&inst
->rd_d
, name
, type
, flags
,
2832 (pg
!= NULL
)?&pg
->rd_d
: NULL
));
2836 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2837 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2838 * _BACKEND_ACCESS, _NOT_FOUND.
2841 scf_instance_get_snapshot(const scf_instance_t
*inst
, const char *name
,
2844 return (datael_get_child(&inst
->rd_d
, name
,
2845 REP_PROTOCOL_ENTITY_SNAPSHOT
, pg
? &pg
->rd_d
: NULL
, 0));
2849 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2850 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2851 * _BACKEND_ACCESS, _NOT_FOUND.
2854 scf_instance_get_pg(const scf_instance_t
*inst
, const char *name
,
2855 scf_propertygroup_t
*pg
)
2857 return (datael_get_child(&inst
->rd_d
, name
,
2858 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 0));
2862 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2863 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2864 * _BACKEND_ACCESS, _NOT_FOUND.
2867 scf_instance_get_pg_composed(const scf_instance_t
*inst
,
2868 const scf_snapshot_t
*snap
, const char *name
, scf_propertygroup_t
*pg
)
2870 if (snap
!= NULL
&& inst
->rd_d
.rd_handle
!= snap
->rd_d
.rd_handle
)
2871 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
2873 return (datael_get_child(snap
? &snap
->rd_d
: &inst
->rd_d
, name
,
2874 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 1));
2878 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2879 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2880 * _BACKEND_ACCESS, _NOT_FOUND.
2883 scf_pg_get_property(const scf_propertygroup_t
*pg
, const char *name
,
2884 scf_property_t
*prop
)
2886 return (datael_get_child(&pg
->rd_d
, name
, REP_PROTOCOL_ENTITY_PROPERTY
,
2887 prop
? &prop
->rd_d
: NULL
, 0));
2891 scf_service_destroy(scf_service_t
*val
)
2896 datael_destroy(&val
->rd_d
);
2901 scf_service_get_name(const scf_service_t
*rep
, char *out
, size_t len
)
2903 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2907 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2908 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2911 scf_instance_create(scf_handle_t
*handle
)
2913 scf_instance_t
*ret
;
2915 ret
= uu_zalloc(sizeof (*ret
));
2917 if (datael_init(&ret
->rd_d
, handle
,
2918 REP_PROTOCOL_ENTITY_INSTANCE
) == -1) {
2923 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2930 scf_instance_handle(const scf_instance_t
*val
)
2932 return (datael_handle(&val
->rd_d
));
2936 scf_instance_destroy(scf_instance_t
*val
)
2941 datael_destroy(&val
->rd_d
);
2946 scf_instance_get_name(const scf_instance_t
*rep
, char *out
, size_t len
)
2948 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2952 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2953 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2956 scf_snapshot_create(scf_handle_t
*handle
)
2958 scf_snapshot_t
*ret
;
2960 ret
= uu_zalloc(sizeof (*ret
));
2962 if (datael_init(&ret
->rd_d
, handle
,
2963 REP_PROTOCOL_ENTITY_SNAPSHOT
) == -1) {
2968 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
2975 scf_snapshot_handle(const scf_snapshot_t
*val
)
2977 return (datael_handle(&val
->rd_d
));
2981 scf_snapshot_destroy(scf_snapshot_t
*val
)
2986 datael_destroy(&val
->rd_d
);
2991 scf_snapshot_get_name(const scf_snapshot_t
*rep
, char *out
, size_t len
)
2993 return (datael_get_name(&rep
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
2997 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2998 * (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY.
3001 scf_snaplevel_create(scf_handle_t
*handle
)
3003 scf_snaplevel_t
*ret
;
3005 ret
= uu_zalloc(sizeof (*ret
));
3007 if (datael_init(&ret
->rd_d
, handle
,
3008 REP_PROTOCOL_ENTITY_SNAPLEVEL
) == -1) {
3013 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3020 scf_snaplevel_handle(const scf_snaplevel_t
*val
)
3022 return (datael_handle(&val
->rd_d
));
3026 scf_snaplevel_destroy(scf_snaplevel_t
*val
)
3031 datael_destroy(&val
->rd_d
);
3036 scf_snaplevel_get_scope_name(const scf_snaplevel_t
*rep
, char *out
, size_t len
)
3038 return (datael_get_name(&rep
->rd_d
, out
, len
,
3039 RP_ENTITY_NAME_SNAPLEVEL_SCOPE
));
3043 scf_snaplevel_get_service_name(const scf_snaplevel_t
*rep
, char *out
,
3046 return (datael_get_name(&rep
->rd_d
, out
, len
,
3047 RP_ENTITY_NAME_SNAPLEVEL_SERVICE
));
3051 scf_snaplevel_get_instance_name(const scf_snaplevel_t
*rep
, char *out
,
3054 return (datael_get_name(&rep
->rd_d
, out
, len
,
3055 RP_ENTITY_NAME_SNAPLEVEL_INSTANCE
));
3059 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3060 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3061 * _BACKEND_ACCESS, _NOT_FOUND.
3064 scf_snaplevel_get_pg(const scf_snaplevel_t
*snap
, const char *name
,
3065 scf_propertygroup_t
*pg
)
3067 return (datael_get_child(&snap
->rd_d
, name
,
3068 REP_PROTOCOL_ENTITY_PROPERTYGRP
, pg
? &pg
->rd_d
: NULL
, 0));
3072 snaplevel_next(const scf_datael_t
*src
, scf_snaplevel_t
*dst_arg
)
3074 scf_handle_t
*h
= src
->rd_handle
;
3075 scf_snaplevel_t
*dst
= dst_arg
;
3076 struct rep_protocol_entity_pair request
;
3077 struct rep_protocol_response response
;
3081 if (h
!= dst
->rd_d
.rd_handle
)
3082 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3084 if (src
== &dst
->rd_d
) {
3086 dst
= HANDLE_HOLD_SNAPLVL(h
);
3088 (void) pthread_mutex_lock(&h
->rh_lock
);
3089 request
.rpr_request
= REP_PROTOCOL_NEXT_SNAPLEVEL
;
3090 request
.rpr_entity_src
= src
->rd_entity
;
3091 request
.rpr_entity_dst
= dst
->rd_d
.rd_entity
;
3093 datael_finish_reset(src
);
3094 datael_finish_reset(&dst
->rd_d
);
3095 r
= make_door_call(h
, &request
, sizeof (request
),
3096 &response
, sizeof (response
));
3098 * if we succeeded, we need to swap dst and dst_arg's identity. We
3099 * take advantage of the fact that the only in-library knowledge is
3102 if (dups
&& r
>= 0 &&
3103 (response
.rpr_response
== REP_PROTOCOL_SUCCESS
||
3104 response
.rpr_response
== REP_PROTOCOL_DONE
)) {
3105 int entity
= dst
->rd_d
.rd_entity
;
3107 dst
->rd_d
.rd_entity
= dst_arg
->rd_d
.rd_entity
;
3108 dst_arg
->rd_d
.rd_entity
= entity
;
3110 (void) pthread_mutex_unlock(&h
->rh_lock
);
3113 HANDLE_RELE_SNAPLVL(h
);
3116 DOOR_ERRORS_BLOCK(r
);
3118 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
3119 response
.rpr_response
!= REP_PROTOCOL_DONE
) {
3120 return (scf_set_error(proto_error(response
.rpr_response
)));
3123 return (response
.rpr_response
== REP_PROTOCOL_SUCCESS
) ?
3124 SCF_SUCCESS
: SCF_COMPLETE
;
3127 int scf_snapshot_get_base_snaplevel(const scf_snapshot_t
*base
,
3128 scf_snaplevel_t
*out
)
3130 return (snaplevel_next(&base
->rd_d
, out
));
3133 int scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t
*base
,
3134 scf_snaplevel_t
*out
)
3136 return (snaplevel_next(&base
->rd_d
, out
));
3140 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3141 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3143 scf_propertygroup_t
*
3144 scf_pg_create(scf_handle_t
*handle
)
3146 scf_propertygroup_t
*ret
;
3147 ret
= uu_zalloc(sizeof (*ret
));
3149 if (datael_init(&ret
->rd_d
, handle
,
3150 REP_PROTOCOL_ENTITY_PROPERTYGRP
) == -1) {
3155 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3162 scf_pg_handle(const scf_propertygroup_t
*val
)
3164 return (datael_handle(&val
->rd_d
));
3168 scf_pg_destroy(scf_propertygroup_t
*val
)
3173 datael_destroy(&val
->rd_d
);
3178 scf_pg_get_name(const scf_propertygroup_t
*pg
, char *out
, size_t len
)
3180 return (datael_get_name(&pg
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
3184 scf_pg_get_type(const scf_propertygroup_t
*pg
, char *out
, size_t len
)
3186 return (datael_get_name(&pg
->rd_d
, out
, len
, RP_ENTITY_NAME_PGTYPE
));
3190 scf_pg_get_flags(const scf_propertygroup_t
*pg
, uint32_t *out
)
3192 char buf
[REP_PROTOCOL_NAME_LEN
];
3195 res
= datael_get_name(&pg
->rd_d
, buf
, sizeof (buf
),
3196 RP_ENTITY_NAME_PGFLAGS
);
3201 if (uu_strtouint(buf
, out
, sizeof (*out
), 0, 0, UINT32_MAX
) == -1)
3202 return (scf_set_error(SCF_ERROR_INTERNAL
));
3208 datael_update(scf_datael_t
*dp
)
3210 scf_handle_t
*h
= dp
->rd_handle
;
3212 struct rep_protocol_entity_update request
;
3213 struct rep_protocol_response response
;
3217 (void) pthread_mutex_lock(&h
->rh_lock
);
3218 request
.rpr_request
= REP_PROTOCOL_ENTITY_UPDATE
;
3219 request
.rpr_entityid
= dp
->rd_entity
;
3221 datael_finish_reset(dp
);
3222 request
.rpr_changeid
= handle_next_changeid(h
);
3224 r
= make_door_call(h
, &request
, sizeof (request
),
3225 &response
, sizeof (response
));
3226 (void) pthread_mutex_unlock(&h
->rh_lock
);
3229 DOOR_ERRORS_BLOCK(r
);
3232 * This should never happen but if it does something has
3233 * gone terribly wrong and we should abort.
3235 if (response
.rpr_response
== REP_PROTOCOL_FAIL_BAD_REQUEST
)
3238 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
3239 response
.rpr_response
!= REP_PROTOCOL_DONE
) {
3240 return (scf_set_error(proto_error(response
.rpr_response
)));
3243 return (response
.rpr_response
== REP_PROTOCOL_SUCCESS
) ?
3244 SCF_SUCCESS
: SCF_COMPLETE
;
3248 scf_pg_update(scf_propertygroup_t
*pg
)
3250 return (datael_update(&pg
->rd_d
));
3254 scf_snapshot_update(scf_snapshot_t
*snap
)
3256 return (datael_update(&snap
->rd_d
));
3260 _scf_pg_wait(scf_propertygroup_t
*pg
, int timeout
)
3262 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
3264 struct rep_protocol_propertygrp_request request
;
3265 struct rep_protocol_response response
;
3267 struct pollfd pollfd
;
3271 (void) pthread_mutex_lock(&h
->rh_lock
);
3272 request
.rpr_request
= REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT
;
3273 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
3275 datael_finish_reset(&pg
->rd_d
);
3276 if (!handle_is_bound(h
)) {
3277 (void) pthread_mutex_unlock(&h
->rh_lock
);
3278 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
3280 r
= make_door_call_retfd(h
->rh_doorfd
, &request
, sizeof (request
),
3281 &response
, sizeof (response
), &pollfd
.fd
);
3282 (void) pthread_mutex_unlock(&h
->rh_lock
);
3285 DOOR_ERRORS_BLOCK(r
);
3287 assert((response
.rpr_response
== REP_PROTOCOL_SUCCESS
) ==
3290 if (response
.rpr_response
== REP_PROTOCOL_FAIL_NOT_LATEST
)
3291 return (SCF_SUCCESS
);
3293 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3294 return (scf_set_error(proto_error(response
.rpr_response
)));
3299 r
= poll(&pollfd
, 1, timeout
* MILLISEC
);
3301 (void) close(pollfd
.fd
);
3302 return (pollfd
.revents
? SCF_SUCCESS
: SCF_COMPLETE
);
3306 scf_notify_add_pattern(scf_handle_t
*h
, int type
, const char *name
)
3308 struct rep_protocol_notify_request request
;
3309 struct rep_protocol_response response
;
3312 (void) pthread_mutex_lock(&h
->rh_lock
);
3313 request
.rpr_request
= REP_PROTOCOL_CLIENT_ADD_NOTIFY
;
3314 request
.rpr_type
= type
;
3315 (void) strlcpy(request
.rpr_pattern
, name
, sizeof (request
.rpr_pattern
));
3317 r
= make_door_call(h
, &request
, sizeof (request
),
3318 &response
, sizeof (response
));
3319 (void) pthread_mutex_unlock(&h
->rh_lock
);
3322 DOOR_ERRORS_BLOCK(r
);
3324 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3325 return (scf_set_error(proto_error(response
.rpr_response
)));
3327 return (SCF_SUCCESS
);
3331 _scf_notify_add_pgname(scf_handle_t
*h
, const char *name
)
3333 return (scf_notify_add_pattern(h
, REP_PROTOCOL_NOTIFY_PGNAME
, name
));
3337 _scf_notify_add_pgtype(scf_handle_t
*h
, const char *type
)
3339 return (scf_notify_add_pattern(h
, REP_PROTOCOL_NOTIFY_PGTYPE
, type
));
3343 _scf_notify_wait(scf_propertygroup_t
*pg
, char *out
, size_t sz
)
3345 struct rep_protocol_wait_request request
;
3346 struct rep_protocol_fmri_response response
;
3348 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
3353 (void) pthread_mutex_lock(&h
->rh_lock
);
3354 datael_finish_reset(&pg
->rd_d
);
3355 if (!handle_is_bound(h
)) {
3356 (void) pthread_mutex_unlock(&h
->rh_lock
);
3357 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN
));
3361 assert(h
->rh_fd_users
> 0);
3363 request
.rpr_request
= REP_PROTOCOL_CLIENT_WAIT
;
3364 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
3365 (void) pthread_mutex_unlock(&h
->rh_lock
);
3367 r
= make_door_call_retfd(fd
, &request
, sizeof (request
),
3368 &response
, sizeof (response
), &dummy
);
3370 (void) pthread_mutex_lock(&h
->rh_lock
);
3371 assert(h
->rh_fd_users
> 0);
3372 if (--h
->rh_fd_users
== 0) {
3373 (void) pthread_cond_broadcast(&h
->rh_cv
);
3375 * check for a delayed close, now that there are no other
3378 if (h
->rh_doorfd_old
!= -1) {
3379 assert(h
->rh_doorfd
== -1);
3380 assert(fd
== h
->rh_doorfd_old
);
3381 (void) close(h
->rh_doorfd_old
);
3382 h
->rh_doorfd_old
= -1;
3385 handle_unrefed(h
); /* drops h->rh_lock */
3388 DOOR_ERRORS_BLOCK(r
);
3390 if (response
.rpr_response
== REP_PROTOCOL_DONE
)
3391 return (scf_set_error(SCF_ERROR_NOT_SET
));
3393 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3394 return (scf_set_error(proto_error(response
.rpr_response
)));
3396 /* the following will be non-zero for delete notifications */
3397 return (strlcpy(out
, response
.rpr_fmri
, sz
));
3401 _scf_snapshot_take(scf_instance_t
*inst
, const char *name
,
3402 scf_snapshot_t
*snap
, int flags
)
3404 scf_handle_t
*h
= inst
->rd_d
.rd_handle
;
3406 struct rep_protocol_snapshot_take request
;
3407 struct rep_protocol_response response
;
3411 if (h
!= snap
->rd_d
.rd_handle
)
3412 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3414 if (strlcpy(request
.rpr_name
, (name
!= NULL
)? name
: "",
3415 sizeof (request
.rpr_name
)) >= sizeof (request
.rpr_name
))
3416 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3418 (void) pthread_mutex_lock(&h
->rh_lock
);
3419 request
.rpr_request
= REP_PROTOCOL_SNAPSHOT_TAKE
;
3420 request
.rpr_entityid_src
= inst
->rd_d
.rd_entity
;
3421 request
.rpr_entityid_dest
= snap
->rd_d
.rd_entity
;
3422 request
.rpr_flags
= flags
;
3424 datael_finish_reset(&inst
->rd_d
);
3425 datael_finish_reset(&snap
->rd_d
);
3427 r
= make_door_call(h
, &request
, sizeof (request
),
3428 &response
, sizeof (response
));
3429 (void) pthread_mutex_unlock(&h
->rh_lock
);
3432 DOOR_ERRORS_BLOCK(r
);
3434 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3435 return (scf_set_error(proto_error(response
.rpr_response
)));
3437 return (SCF_SUCCESS
);
3441 _scf_snapshot_take_new_named(scf_instance_t
*inst
,
3442 const char *svcname
, const char *instname
, const char *snapname
,
3443 scf_snapshot_t
*snap
)
3445 scf_handle_t
*h
= inst
->rd_d
.rd_handle
;
3447 struct rep_protocol_snapshot_take_named request
;
3448 struct rep_protocol_response response
;
3452 if (h
!= snap
->rd_d
.rd_handle
)
3453 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3455 if (strlcpy(request
.rpr_svcname
, svcname
,
3456 sizeof (request
.rpr_svcname
)) >= sizeof (request
.rpr_svcname
))
3457 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3459 if (strlcpy(request
.rpr_instname
, instname
,
3460 sizeof (request
.rpr_instname
)) >= sizeof (request
.rpr_instname
))
3461 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3463 if (strlcpy(request
.rpr_name
, snapname
,
3464 sizeof (request
.rpr_name
)) >= sizeof (request
.rpr_name
))
3465 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3467 (void) pthread_mutex_lock(&h
->rh_lock
);
3468 request
.rpr_request
= REP_PROTOCOL_SNAPSHOT_TAKE_NAMED
;
3469 request
.rpr_entityid_src
= inst
->rd_d
.rd_entity
;
3470 request
.rpr_entityid_dest
= snap
->rd_d
.rd_entity
;
3472 datael_finish_reset(&inst
->rd_d
);
3473 datael_finish_reset(&snap
->rd_d
);
3475 r
= make_door_call(h
, &request
, sizeof (request
),
3476 &response
, sizeof (response
));
3477 (void) pthread_mutex_unlock(&h
->rh_lock
);
3480 DOOR_ERRORS_BLOCK(r
);
3482 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
3483 assert(response
.rpr_response
!=
3484 REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
3485 return (scf_set_error(proto_error(response
.rpr_response
)));
3488 return (SCF_SUCCESS
);
3492 _scf_snapshot_take_new(scf_instance_t
*inst
, const char *name
,
3493 scf_snapshot_t
*snap
)
3495 return (_scf_snapshot_take(inst
, name
, snap
, REP_SNAPSHOT_NEW
));
3499 _scf_snapshot_take_attach(scf_instance_t
*inst
, scf_snapshot_t
*snap
)
3501 return (_scf_snapshot_take(inst
, NULL
, snap
, REP_SNAPSHOT_ATTACH
));
3505 _scf_snapshot_attach(scf_snapshot_t
*src
, scf_snapshot_t
*dest
)
3507 scf_handle_t
*h
= dest
->rd_d
.rd_handle
;
3509 struct rep_protocol_snapshot_attach request
;
3510 struct rep_protocol_response response
;
3514 if (h
!= src
->rd_d
.rd_handle
)
3515 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3517 (void) pthread_mutex_lock(&h
->rh_lock
);
3518 request
.rpr_request
= REP_PROTOCOL_SNAPSHOT_ATTACH
;
3519 request
.rpr_entityid_src
= src
->rd_d
.rd_entity
;
3520 request
.rpr_entityid_dest
= dest
->rd_d
.rd_entity
;
3522 datael_finish_reset(&src
->rd_d
);
3523 datael_finish_reset(&dest
->rd_d
);
3525 r
= make_door_call(h
, &request
, sizeof (request
),
3526 &response
, sizeof (response
));
3527 (void) pthread_mutex_unlock(&h
->rh_lock
);
3530 DOOR_ERRORS_BLOCK(r
);
3532 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
3533 return (scf_set_error(proto_error(response
.rpr_response
)));
3535 return (SCF_SUCCESS
);
3539 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3540 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3543 scf_property_create(scf_handle_t
*handle
)
3545 scf_property_t
*ret
;
3546 ret
= uu_zalloc(sizeof (*ret
));
3548 if (datael_init(&ret
->rd_d
, handle
,
3549 REP_PROTOCOL_ENTITY_PROPERTY
) == -1) {
3554 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3561 scf_property_handle(const scf_property_t
*val
)
3563 return (datael_handle(&val
->rd_d
));
3567 scf_property_destroy(scf_property_t
*val
)
3572 datael_destroy(&val
->rd_d
);
3577 property_type_locked(const scf_property_t
*prop
,
3578 rep_protocol_value_type_t
*out
)
3580 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
3582 struct rep_protocol_property_request request
;
3583 struct rep_protocol_integer_response response
;
3587 assert(MUTEX_HELD(&h
->rh_lock
));
3589 request
.rpr_request
= REP_PROTOCOL_PROPERTY_GET_TYPE
;
3590 request
.rpr_entityid
= prop
->rd_d
.rd_entity
;
3592 datael_finish_reset(&prop
->rd_d
);
3593 r
= make_door_call(h
, &request
, sizeof (request
),
3594 &response
, sizeof (response
));
3597 DOOR_ERRORS_BLOCK(r
);
3599 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
||
3600 r
< sizeof (response
)) {
3601 return (scf_set_error(proto_error(response
.rpr_response
)));
3603 *out
= response
.rpr_value
;
3604 return (SCF_SUCCESS
);
3608 scf_property_type(const scf_property_t
*prop
, scf_type_t
*out
)
3610 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
3611 rep_protocol_value_type_t out_raw
;
3614 (void) pthread_mutex_lock(&h
->rh_lock
);
3615 ret
= property_type_locked(prop
, &out_raw
);
3616 (void) pthread_mutex_unlock(&h
->rh_lock
);
3618 if (ret
== SCF_SUCCESS
)
3619 *out
= scf_protocol_type_to_type(out_raw
);
3625 scf_property_is_type(const scf_property_t
*prop
, scf_type_t base_arg
)
3627 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
3628 rep_protocol_value_type_t base
= scf_type_to_protocol_type(base_arg
);
3629 rep_protocol_value_type_t type
;
3632 if (base
== REP_PROTOCOL_TYPE_INVALID
)
3633 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3635 (void) pthread_mutex_lock(&h
->rh_lock
);
3636 ret
= property_type_locked(prop
, &type
);
3637 (void) pthread_mutex_unlock(&h
->rh_lock
);
3639 if (ret
== SCF_SUCCESS
) {
3640 if (!scf_is_compatible_protocol_type(base
, type
))
3641 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
3647 scf_is_compatible_type(scf_type_t base_arg
, scf_type_t type_arg
)
3649 rep_protocol_value_type_t base
= scf_type_to_protocol_type(base_arg
);
3650 rep_protocol_value_type_t type
= scf_type_to_protocol_type(type_arg
);
3652 if (base
== REP_PROTOCOL_TYPE_INVALID
||
3653 type
== REP_PROTOCOL_TYPE_INVALID
)
3654 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3656 if (!scf_is_compatible_protocol_type(base
, type
))
3657 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
3659 return (SCF_SUCCESS
);
3663 scf_property_get_name(const scf_property_t
*prop
, char *out
, size_t len
)
3665 return (datael_get_name(&prop
->rd_d
, out
, len
, RP_ENTITY_NAME_NAME
));
3669 * transaction functions
3673 * Fails with _NO_MEMORY, _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED,
3674 * _INTERNAL (bad server response or id in use), or _NO_RESOURCES.
3677 scf_transaction_create(scf_handle_t
*handle
)
3679 scf_transaction_t
*ret
;
3681 ret
= uu_zalloc(sizeof (scf_transaction_t
));
3683 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3686 if (datael_init(&ret
->tran_pg
.rd_d
, handle
,
3687 REP_PROTOCOL_ENTITY_PROPERTYGRP
) == -1) {
3689 return (NULL
); /* error already set */
3691 ret
->tran_state
= TRAN_STATE_NEW
;
3692 ret
->tran_props
= uu_list_create(tran_entry_pool
, ret
, UU_LIST_SORTED
);
3693 if (ret
->tran_props
== NULL
) {
3694 datael_destroy(&ret
->tran_pg
.rd_d
);
3696 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
3704 scf_transaction_handle(const scf_transaction_t
*val
)
3706 return (handle_get(val
->tran_pg
.rd_d
.rd_handle
));
3710 scf_transaction_start(scf_transaction_t
*tran
, scf_propertygroup_t
*pg
)
3712 scf_handle_t
*h
= tran
->tran_pg
.rd_d
.rd_handle
;
3714 struct rep_protocol_transaction_start request
;
3715 struct rep_protocol_response response
;
3718 if (h
!= pg
->rd_d
.rd_handle
)
3719 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3721 (void) pthread_mutex_lock(&h
->rh_lock
);
3722 if (tran
->tran_state
!= TRAN_STATE_NEW
) {
3723 (void) pthread_mutex_unlock(&h
->rh_lock
);
3724 return (scf_set_error(SCF_ERROR_IN_USE
));
3726 request
.rpr_request
= REP_PROTOCOL_PROPERTYGRP_TX_START
;
3727 request
.rpr_entityid_tx
= tran
->tran_pg
.rd_d
.rd_entity
;
3728 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
3730 datael_finish_reset(&tran
->tran_pg
.rd_d
);
3731 datael_finish_reset(&pg
->rd_d
);
3733 r
= make_door_call(h
, &request
, sizeof (request
),
3734 &response
, sizeof (response
));
3737 (void) pthread_mutex_unlock(&h
->rh_lock
);
3738 DOOR_ERRORS_BLOCK(r
);
3741 /* r < sizeof (response) cannot happen because sizeof (response) == 4 */
3743 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
||
3744 r
< sizeof (response
)) {
3745 (void) pthread_mutex_unlock(&h
->rh_lock
);
3746 return (scf_set_error(proto_error(response
.rpr_response
)));
3749 tran
->tran_state
= TRAN_STATE_SETUP
;
3750 tran
->tran_invalid
= 0;
3751 (void) pthread_mutex_unlock(&h
->rh_lock
);
3752 return (SCF_SUCCESS
);
3756 entry_invalidate(scf_transaction_entry_t
*cur
, int and_destroy
,
3757 int and_reset_value
)
3759 scf_value_t
*v
, *next
;
3760 scf_transaction_t
*tx
;
3761 scf_handle_t
*h
= cur
->entry_handle
;
3763 assert(MUTEX_HELD(&h
->rh_lock
));
3765 if ((tx
= cur
->entry_tx
) != NULL
) {
3766 tx
->tran_invalid
= 1;
3767 uu_list_remove(tx
->tran_props
, cur
);
3768 cur
->entry_tx
= NULL
;
3771 cur
->entry_property
= NULL
;
3772 cur
->entry_state
= ENTRY_STATE_INVALID
;
3773 cur
->entry_action
= REP_PROTOCOL_TX_ENTRY_INVALID
;
3774 cur
->entry_type
= REP_PROTOCOL_TYPE_INVALID
;
3776 for (v
= cur
->entry_head
; v
!= NULL
; v
= next
) {
3777 next
= v
->value_next
;
3779 v
->value_next
= NULL
;
3780 if (and_destroy
|| and_reset_value
)
3781 scf_value_reset_locked(v
, and_destroy
);
3783 cur
->entry_head
= NULL
;
3784 cur
->entry_tail
= NULL
;
3788 entry_destroy_locked(scf_transaction_entry_t
*entry
)
3790 scf_handle_t
*h
= entry
->entry_handle
;
3792 assert(MUTEX_HELD(&h
->rh_lock
));
3794 entry_invalidate(entry
, 0, 0);
3796 entry
->entry_handle
= NULL
;
3797 assert(h
->rh_entries
> 0);
3800 uu_list_node_fini(entry
, &entry
->entry_link
, tran_entry_pool
);
3805 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3806 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3807 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3810 transaction_add(scf_transaction_t
*tran
, scf_transaction_entry_t
*entry
,
3811 enum rep_protocol_transaction_action action
,
3812 const char *prop
, rep_protocol_value_type_t type
)
3814 scf_handle_t
*h
= tran
->tran_pg
.rd_d
.rd_handle
;
3815 scf_transaction_entry_t
*old
;
3816 scf_property_t
*prop_p
;
3817 rep_protocol_value_type_t oldtype
;
3818 scf_error_t error
= SCF_ERROR_NONE
;
3820 uu_list_index_t idx
;
3822 if (h
!= entry
->entry_handle
)
3823 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
3825 if (action
== REP_PROTOCOL_TX_ENTRY_DELETE
)
3826 assert(type
== REP_PROTOCOL_TYPE_INVALID
);
3827 else if (type
== REP_PROTOCOL_TYPE_INVALID
)
3828 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
3830 prop_p
= HANDLE_HOLD_PROPERTY(h
);
3832 (void) pthread_mutex_lock(&h
->rh_lock
);
3833 if (tran
->tran_state
!= TRAN_STATE_SETUP
) {
3834 error
= SCF_ERROR_NOT_SET
;
3837 if (tran
->tran_invalid
) {
3838 error
= SCF_ERROR_NOT_SET
;
3842 if (entry
->entry_state
!= ENTRY_STATE_INVALID
)
3843 entry_invalidate(entry
, 0, 0);
3845 old
= uu_list_find(tran
->tran_props
, &prop
, NULL
, &idx
);
3847 error
= SCF_ERROR_IN_USE
;
3851 ret
= datael_get_child_locked(&tran
->tran_pg
.rd_d
, prop
,
3852 REP_PROTOCOL_ENTITY_PROPERTY
, &prop_p
->rd_d
);
3853 if (ret
== -1 && (error
= scf_error()) != SCF_ERROR_NOT_FOUND
) {
3858 case REP_PROTOCOL_TX_ENTRY_DELETE
:
3860 error
= SCF_ERROR_NOT_FOUND
;
3864 case REP_PROTOCOL_TX_ENTRY_NEW
:
3866 error
= SCF_ERROR_EXISTS
;
3871 case REP_PROTOCOL_TX_ENTRY_CLEAR
:
3872 case REP_PROTOCOL_TX_ENTRY_REPLACE
:
3874 error
= SCF_ERROR_NOT_FOUND
;
3877 if (action
== REP_PROTOCOL_TX_ENTRY_CLEAR
) {
3878 if (property_type_locked(prop_p
, &oldtype
) == -1) {
3879 error
= scf_error();
3882 if (oldtype
!= type
) {
3883 error
= SCF_ERROR_TYPE_MISMATCH
;
3893 (void) strlcpy(entry
->entry_namebuf
, prop
,
3894 sizeof (entry
->entry_namebuf
));
3895 entry
->entry_property
= entry
->entry_namebuf
;
3896 entry
->entry_action
= action
;
3897 entry
->entry_type
= type
;
3899 entry
->entry_state
= ENTRY_STATE_IN_TX_ACTION
;
3900 entry
->entry_tx
= tran
;
3901 uu_list_insert(tran
->tran_props
, entry
, idx
);
3903 (void) pthread_mutex_unlock(&h
->rh_lock
);
3905 HANDLE_RELE_PROPERTY(h
);
3907 return (SCF_SUCCESS
);
3910 (void) pthread_mutex_unlock(&h
->rh_lock
);
3912 HANDLE_RELE_PROPERTY(h
);
3914 return (scf_set_error(error
));
3918 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3919 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3920 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3923 scf_transaction_property_new(scf_transaction_t
*tx
,
3924 scf_transaction_entry_t
*entry
, const char *prop
, scf_type_t type
)
3926 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_NEW
,
3927 prop
, scf_type_to_protocol_type(type
)));
3931 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3932 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3933 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3936 scf_transaction_property_change(scf_transaction_t
*tx
,
3937 scf_transaction_entry_t
*entry
, const char *prop
, scf_type_t type
)
3939 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_CLEAR
,
3940 prop
, scf_type_to_protocol_type(type
)));
3944 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3945 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3946 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3949 scf_transaction_property_change_type(scf_transaction_t
*tx
,
3950 scf_transaction_entry_t
*entry
, const char *prop
, scf_type_t type
)
3952 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_REPLACE
,
3953 prop
, scf_type_to_protocol_type(type
)));
3957 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3958 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3959 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3962 scf_transaction_property_delete(scf_transaction_t
*tx
,
3963 scf_transaction_entry_t
*entry
, const char *prop
)
3965 return (transaction_add(tx
, entry
, REP_PROTOCOL_TX_ENTRY_DELETE
,
3966 prop
, REP_PROTOCOL_TYPE_INVALID
));
3969 #define BAD_SIZE (-1UL)
3972 commit_value(caddr_t data
, scf_value_t
*val
, rep_protocol_value_type_t t
)
3976 assert(val
->value_type
== t
);
3978 if (t
== REP_PROTOCOL_TYPE_OPAQUE
) {
3979 len
= scf_opaque_encode(data
, val
->value_value
,
3983 len
= strlcpy(data
, val
->value_value
,
3984 REP_PROTOCOL_VALUE_LEN
);
3986 len
= strlen(val
->value_value
);
3987 if (len
>= REP_PROTOCOL_VALUE_LEN
)
3990 return (len
+ 1); /* count the '\0' */
3994 commit_process(scf_transaction_entry_t
*cur
,
3995 struct rep_protocol_transaction_cmd
*out
)
4000 caddr_t data
= (caddr_t
)out
->rptc_data
;
4004 len
= strlcpy(data
, cur
->entry_property
, REP_PROTOCOL_NAME_LEN
);
4006 out
->rptc_action
= cur
->entry_action
;
4007 out
->rptc_type
= cur
->entry_type
;
4008 out
->rptc_name_len
= len
+ 1;
4010 len
= strlen(cur
->entry_property
);
4013 if (len
>= REP_PROTOCOL_NAME_LEN
)
4016 len
= TX_SIZE(len
+ 1);
4019 val_data
= data
+ len
;
4021 for (child
= cur
->entry_head
; child
!= NULL
;
4022 child
= child
->value_next
) {
4023 assert(cur
->entry_action
!= REP_PROTOCOL_TX_ENTRY_DELETE
);
4025 len
= commit_value(val_data
+ sizeof (uint32_t), child
,
4027 /* LINTED alignment */
4028 *(uint32_t *)val_data
= len
;
4030 len
= commit_value(NULL
, child
, cur
->entry_type
);
4032 if (len
== BAD_SIZE
)
4035 len
+= sizeof (uint32_t);
4042 assert(val_data
- data
== sz
);
4045 out
->rptc_size
= REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz
);
4047 return (REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz
));
4051 scf_transaction_commit(scf_transaction_t
*tran
)
4053 scf_handle_t
*h
= tran
->tran_pg
.rd_d
.rd_handle
;
4055 struct rep_protocol_transaction_commit
*request
;
4056 struct rep_protocol_response response
;
4058 scf_transaction_entry_t
*cur
;
4060 size_t request_size
;
4064 (void) pthread_mutex_lock(&h
->rh_lock
);
4065 if (tran
->tran_state
!= TRAN_STATE_SETUP
||
4066 tran
->tran_invalid
) {
4067 (void) pthread_mutex_unlock(&h
->rh_lock
);
4068 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4072 for (cur
= uu_list_first(tran
->tran_props
); cur
!= NULL
;
4073 cur
= uu_list_next(tran
->tran_props
, cur
)) {
4074 size
= commit_process(cur
, NULL
);
4075 if (size
== BAD_SIZE
) {
4076 (void) pthread_mutex_unlock(&h
->rh_lock
);
4077 return (scf_set_error(SCF_ERROR_INTERNAL
));
4079 assert(TX_SIZE(size
) == size
);
4083 request_size
= REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(total
);
4084 request
= alloca(request_size
);
4085 (void) memset(request
, '\0', request_size
);
4086 request
->rpr_request
= REP_PROTOCOL_PROPERTYGRP_TX_COMMIT
;
4087 request
->rpr_entityid
= tran
->tran_pg
.rd_d
.rd_entity
;
4088 request
->rpr_size
= request_size
;
4089 cmd
= (uintptr_t)request
->rpr_cmd
;
4091 datael_finish_reset(&tran
->tran_pg
.rd_d
);
4094 for (cur
= uu_list_first(tran
->tran_props
); cur
!= NULL
;
4095 cur
= uu_list_next(tran
->tran_props
, cur
)) {
4096 size
= commit_process(cur
, (void *)cmd
);
4097 if (size
== BAD_SIZE
) {
4098 (void) pthread_mutex_unlock(&h
->rh_lock
);
4099 return (scf_set_error(SCF_ERROR_INTERNAL
));
4104 assert(new_total
== total
);
4106 r
= make_door_call(h
, request
, request_size
,
4107 &response
, sizeof (response
));
4110 (void) pthread_mutex_unlock(&h
->rh_lock
);
4111 DOOR_ERRORS_BLOCK(r
);
4114 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
4115 response
.rpr_response
!= REP_PROTOCOL_FAIL_NOT_LATEST
) {
4116 (void) pthread_mutex_unlock(&h
->rh_lock
);
4117 return (scf_set_error(proto_error(response
.rpr_response
)));
4120 tran
->tran_state
= TRAN_STATE_COMMITTED
;
4121 (void) pthread_mutex_unlock(&h
->rh_lock
);
4122 return (response
.rpr_response
== REP_PROTOCOL_SUCCESS
);
4126 transaction_reset(scf_transaction_t
*tran
)
4128 assert(MUTEX_HELD(&tran
->tran_pg
.rd_d
.rd_handle
->rh_lock
));
4130 tran
->tran_state
= TRAN_STATE_NEW
;
4131 datael_reset_locked(&tran
->tran_pg
.rd_d
);
4135 scf_transaction_reset_impl(scf_transaction_t
*tran
, int and_destroy
,
4136 int and_reset_value
)
4138 scf_transaction_entry_t
*cur
;
4141 (void) pthread_mutex_lock(&tran
->tran_pg
.rd_d
.rd_handle
->rh_lock
);
4143 while ((cur
= uu_list_teardown(tran
->tran_props
, &cookie
)) != NULL
) {
4144 cur
->entry_tx
= NULL
;
4146 assert(cur
->entry_state
== ENTRY_STATE_IN_TX_ACTION
);
4147 cur
->entry_state
= ENTRY_STATE_INVALID
;
4149 entry_invalidate(cur
, and_destroy
, and_reset_value
);
4151 entry_destroy_locked(cur
);
4153 transaction_reset(tran
);
4154 handle_unrefed(tran
->tran_pg
.rd_d
.rd_handle
);
4158 scf_transaction_reset(scf_transaction_t
*tran
)
4160 scf_transaction_reset_impl(tran
, 0, 0);
4164 scf_transaction_reset_all(scf_transaction_t
*tran
)
4166 scf_transaction_reset_impl(tran
, 0, 1);
4170 scf_transaction_destroy(scf_transaction_t
*val
)
4175 scf_transaction_reset(val
);
4177 datael_destroy(&val
->tran_pg
.rd_d
);
4179 uu_list_destroy(val
->tran_props
);
4184 scf_transaction_destroy_children(scf_transaction_t
*tran
)
4189 scf_transaction_reset_impl(tran
, 1, 0);
4192 scf_transaction_entry_t
*
4193 scf_entry_create(scf_handle_t
*h
)
4195 scf_transaction_entry_t
*ret
;
4198 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
4202 ret
= uu_zalloc(sizeof (scf_transaction_entry_t
));
4204 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
4207 ret
->entry_action
= REP_PROTOCOL_TX_ENTRY_INVALID
;
4208 ret
->entry_handle
= h
;
4210 (void) pthread_mutex_lock(&h
->rh_lock
);
4211 if (h
->rh_flags
& HANDLE_DEAD
) {
4212 (void) pthread_mutex_unlock(&h
->rh_lock
);
4214 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED
);
4219 (void) pthread_mutex_unlock(&h
->rh_lock
);
4221 uu_list_node_init(ret
, &ret
->entry_link
, tran_entry_pool
);
4227 scf_entry_handle(const scf_transaction_entry_t
*val
)
4229 return (handle_get(val
->entry_handle
));
4233 scf_entry_reset(scf_transaction_entry_t
*entry
)
4235 scf_handle_t
*h
= entry
->entry_handle
;
4237 (void) pthread_mutex_lock(&h
->rh_lock
);
4238 entry_invalidate(entry
, 0, 0);
4239 (void) pthread_mutex_unlock(&h
->rh_lock
);
4243 scf_entry_destroy_children(scf_transaction_entry_t
*entry
)
4245 scf_handle_t
*h
= entry
->entry_handle
;
4247 (void) pthread_mutex_lock(&h
->rh_lock
);
4248 entry_invalidate(entry
, 1, 0);
4249 handle_unrefed(h
); /* drops h->rh_lock */
4253 scf_entry_destroy(scf_transaction_entry_t
*entry
)
4260 h
= entry
->entry_handle
;
4262 (void) pthread_mutex_lock(&h
->rh_lock
);
4263 entry_destroy_locked(entry
);
4264 handle_unrefed(h
); /* drops h->rh_lock */
4270 * _NOT_SET - has not been added to a transaction
4271 * _INTERNAL - entry is corrupt
4272 * _INVALID_ARGUMENT - entry's transaction is not started or corrupt
4273 * entry is set to delete a property
4274 * v is reset or corrupt
4275 * _TYPE_MISMATCH - entry & v's types aren't compatible
4276 * _IN_USE - v has been added to another entry
4279 scf_entry_add_value(scf_transaction_entry_t
*entry
, scf_value_t
*v
)
4281 scf_handle_t
*h
= entry
->entry_handle
;
4283 if (h
!= v
->value_handle
)
4284 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
4286 (void) pthread_mutex_lock(&h
->rh_lock
);
4288 if (entry
->entry_state
== ENTRY_STATE_INVALID
) {
4289 (void) pthread_mutex_unlock(&h
->rh_lock
);
4290 return (scf_set_error(SCF_ERROR_NOT_SET
));
4293 if (entry
->entry_state
!= ENTRY_STATE_IN_TX_ACTION
) {
4294 (void) pthread_mutex_unlock(&h
->rh_lock
);
4295 return (scf_set_error(SCF_ERROR_INTERNAL
));
4298 if (entry
->entry_tx
->tran_state
!= TRAN_STATE_SETUP
) {
4299 (void) pthread_mutex_unlock(&h
->rh_lock
);
4300 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4303 if (entry
->entry_action
== REP_PROTOCOL_TX_ENTRY_DELETE
) {
4304 (void) pthread_mutex_unlock(&h
->rh_lock
);
4305 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4308 if (v
->value_type
== REP_PROTOCOL_TYPE_INVALID
) {
4309 (void) pthread_mutex_unlock(&h
->rh_lock
);
4310 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4313 if (!scf_is_compatible_protocol_type(entry
->entry_type
,
4315 (void) pthread_mutex_unlock(&h
->rh_lock
);
4316 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
4319 if (v
->value_tx
!= NULL
) {
4320 (void) pthread_mutex_unlock(&h
->rh_lock
);
4321 return (scf_set_error(SCF_ERROR_IN_USE
));
4324 v
->value_tx
= entry
;
4325 v
->value_next
= NULL
;
4326 if (entry
->entry_head
== NULL
) {
4327 entry
->entry_head
= v
;
4328 entry
->entry_tail
= v
;
4330 entry
->entry_tail
->value_next
= v
;
4331 entry
->entry_tail
= v
;
4334 (void) pthread_mutex_unlock(&h
->rh_lock
);
4336 return (SCF_SUCCESS
);
4343 scf_value_create(scf_handle_t
*h
)
4348 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
4352 ret
= uu_zalloc(sizeof (*ret
));
4354 ret
->value_type
= REP_PROTOCOL_TYPE_INVALID
;
4355 ret
->value_handle
= h
;
4356 (void) pthread_mutex_lock(&h
->rh_lock
);
4357 if (h
->rh_flags
& HANDLE_DEAD
) {
4358 (void) pthread_mutex_unlock(&h
->rh_lock
);
4360 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED
);
4365 (void) pthread_mutex_unlock(&h
->rh_lock
);
4367 (void) scf_set_error(SCF_ERROR_NO_MEMORY
);
4374 scf_value_reset_locked(scf_value_t
*val
, int and_destroy
)
4377 scf_transaction_entry_t
*te
;
4379 scf_handle_t
*h
= val
->value_handle
;
4380 assert(MUTEX_HELD(&h
->rh_lock
));
4381 if (val
->value_tx
!= NULL
) {
4383 te
->entry_tx
->tran_invalid
= 1;
4385 val
->value_tx
= NULL
;
4387 for (curp
= &te
->entry_head
; *curp
!= NULL
;
4388 curp
= &(*curp
)->value_next
) {
4390 *curp
= val
->value_next
;
4395 assert(curp
== NULL
);
4397 val
->value_type
= REP_PROTOCOL_TYPE_INVALID
;
4400 val
->value_handle
= NULL
;
4401 assert(h
->rh_values
> 0);
4409 scf_value_reset(scf_value_t
*val
)
4411 scf_handle_t
*h
= val
->value_handle
;
4413 (void) pthread_mutex_lock(&h
->rh_lock
);
4414 scf_value_reset_locked(val
, 0);
4415 (void) pthread_mutex_unlock(&h
->rh_lock
);
4419 scf_value_handle(const scf_value_t
*val
)
4421 return (handle_get(val
->value_handle
));
4425 scf_value_destroy(scf_value_t
*val
)
4432 h
= val
->value_handle
;
4434 (void) pthread_mutex_lock(&h
->rh_lock
);
4435 scf_value_reset_locked(val
, 1);
4436 handle_unrefed(h
); /* drops h->rh_lock */
4440 scf_value_base_type(const scf_value_t
*val
)
4442 rep_protocol_value_type_t t
, cur
;
4443 scf_handle_t
*h
= val
->value_handle
;
4445 (void) pthread_mutex_lock(&h
->rh_lock
);
4446 t
= val
->value_type
;
4447 (void) pthread_mutex_unlock(&h
->rh_lock
);
4450 cur
= scf_proto_underlying_type(t
);
4456 return (scf_protocol_type_to_type(t
));
4460 scf_value_type(const scf_value_t
*val
)
4462 rep_protocol_value_type_t t
;
4463 scf_handle_t
*h
= val
->value_handle
;
4465 (void) pthread_mutex_lock(&h
->rh_lock
);
4466 t
= val
->value_type
;
4467 (void) pthread_mutex_unlock(&h
->rh_lock
);
4469 return (scf_protocol_type_to_type(t
));
4473 scf_value_is_type(const scf_value_t
*val
, scf_type_t base_arg
)
4475 rep_protocol_value_type_t t
;
4476 rep_protocol_value_type_t base
= scf_type_to_protocol_type(base_arg
);
4477 scf_handle_t
*h
= val
->value_handle
;
4479 (void) pthread_mutex_lock(&h
->rh_lock
);
4480 t
= val
->value_type
;
4481 (void) pthread_mutex_unlock(&h
->rh_lock
);
4483 if (t
== REP_PROTOCOL_TYPE_INVALID
)
4484 return (scf_set_error(SCF_ERROR_NOT_SET
));
4485 if (base
== REP_PROTOCOL_TYPE_INVALID
)
4486 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4487 if (!scf_is_compatible_protocol_type(base
, t
))
4488 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
4490 return (SCF_SUCCESS
);
4495 * _NOT_SET - val is reset
4496 * _TYPE_MISMATCH - val's type is not compatible with t
4499 scf_value_check_type(const scf_value_t
*val
, rep_protocol_value_type_t t
)
4501 if (val
->value_type
== REP_PROTOCOL_TYPE_INVALID
) {
4502 (void) scf_set_error(SCF_ERROR_NOT_SET
);
4505 if (!scf_is_compatible_protocol_type(t
, val
->value_type
)) {
4506 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH
);
4514 * _NOT_SET - val is reset
4515 * _TYPE_MISMATCH - val is not _TYPE_BOOLEAN
4518 scf_value_get_boolean(const scf_value_t
*val
, uint8_t *out
)
4521 scf_handle_t
*h
= val
->value_handle
;
4524 (void) pthread_mutex_lock(&h
->rh_lock
);
4525 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_BOOLEAN
)) {
4526 (void) pthread_mutex_unlock(&h
->rh_lock
);
4530 c
= val
->value_value
[0];
4531 assert((c
== '0' || c
== '1') && val
->value_value
[1] == 0);
4534 (void) pthread_mutex_unlock(&h
->rh_lock
);
4537 return (SCF_SUCCESS
);
4541 scf_value_get_count(const scf_value_t
*val
, uint64_t *out
)
4543 scf_handle_t
*h
= val
->value_handle
;
4546 (void) pthread_mutex_lock(&h
->rh_lock
);
4547 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_COUNT
)) {
4548 (void) pthread_mutex_unlock(&h
->rh_lock
);
4552 o
= strtoull(val
->value_value
, NULL
, 10);
4553 (void) pthread_mutex_unlock(&h
->rh_lock
);
4556 return (SCF_SUCCESS
);
4560 scf_value_get_integer(const scf_value_t
*val
, int64_t *out
)
4562 scf_handle_t
*h
= val
->value_handle
;
4565 (void) pthread_mutex_lock(&h
->rh_lock
);
4566 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_INTEGER
)) {
4567 (void) pthread_mutex_unlock(&h
->rh_lock
);
4571 o
= strtoll(val
->value_value
, NULL
, 10);
4572 (void) pthread_mutex_unlock(&h
->rh_lock
);
4575 return (SCF_SUCCESS
);
4579 scf_value_get_time(const scf_value_t
*val
, int64_t *sec_out
, int32_t *nsec_out
)
4581 scf_handle_t
*h
= val
->value_handle
;
4586 (void) pthread_mutex_lock(&h
->rh_lock
);
4587 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_TIME
)) {
4588 (void) pthread_mutex_unlock(&h
->rh_lock
);
4592 os
= strtoll(val
->value_value
, &p
, 10);
4594 ons
= strtoul(p
+ 1, NULL
, 10);
4597 (void) pthread_mutex_unlock(&h
->rh_lock
);
4598 if (sec_out
!= NULL
)
4600 if (nsec_out
!= NULL
)
4603 return (SCF_SUCCESS
);
4608 * _NOT_SET - val is reset
4609 * _TYPE_MISMATCH - val's type is not compatible with _TYPE_STRING.
4612 scf_value_get_astring(const scf_value_t
*val
, char *out
, size_t len
)
4615 scf_handle_t
*h
= val
->value_handle
;
4617 (void) pthread_mutex_lock(&h
->rh_lock
);
4618 if (!scf_value_check_type(val
, REP_PROTOCOL_TYPE_STRING
)) {
4619 (void) pthread_mutex_unlock(&h
->rh_lock
);
4620 return ((ssize_t
)-1);
4622 ret
= (ssize_t
)strlcpy(out
, val
->value_value
, len
);
4623 (void) pthread_mutex_unlock(&h
->rh_lock
);
4628 scf_value_get_ustring(const scf_value_t
*val
, char *out
, size_t len
)
4631 scf_handle_t
*h
= val
->value_handle
;
4633 (void) pthread_mutex_lock(&h
->rh_lock
);
4634 if (!scf_value_check_type(val
, REP_PROTOCOL_SUBTYPE_USTRING
)) {
4635 (void) pthread_mutex_unlock(&h
->rh_lock
);
4636 return ((ssize_t
)-1);
4638 ret
= (ssize_t
)strlcpy(out
, val
->value_value
, len
);
4639 (void) pthread_mutex_unlock(&h
->rh_lock
);
4644 scf_value_get_opaque(const scf_value_t
*v
, void *out
, size_t len
)
4647 scf_handle_t
*h
= v
->value_handle
;
4649 (void) pthread_mutex_lock(&h
->rh_lock
);
4650 if (!scf_value_check_type(v
, REP_PROTOCOL_TYPE_OPAQUE
)) {
4651 (void) pthread_mutex_unlock(&h
->rh_lock
);
4652 return ((ssize_t
)-1);
4654 if (len
> v
->value_size
)
4655 len
= v
->value_size
;
4658 (void) memcpy(out
, v
->value_value
, len
);
4659 (void) pthread_mutex_unlock(&h
->rh_lock
);
4664 scf_value_set_boolean(scf_value_t
*v
, uint8_t new)
4666 scf_handle_t
*h
= v
->value_handle
;
4668 (void) pthread_mutex_lock(&h
->rh_lock
);
4669 scf_value_reset_locked(v
, 0);
4670 v
->value_type
= REP_PROTOCOL_TYPE_BOOLEAN
;
4671 (void) sprintf(v
->value_value
, "%d", (new != 0));
4672 (void) pthread_mutex_unlock(&h
->rh_lock
);
4676 scf_value_set_count(scf_value_t
*v
, uint64_t new)
4678 scf_handle_t
*h
= v
->value_handle
;
4680 (void) pthread_mutex_lock(&h
->rh_lock
);
4681 scf_value_reset_locked(v
, 0);
4682 v
->value_type
= REP_PROTOCOL_TYPE_COUNT
;
4683 (void) sprintf(v
->value_value
, "%llu", (unsigned long long)new);
4684 (void) pthread_mutex_unlock(&h
->rh_lock
);
4688 scf_value_set_integer(scf_value_t
*v
, int64_t new)
4690 scf_handle_t
*h
= v
->value_handle
;
4692 (void) pthread_mutex_lock(&h
->rh_lock
);
4693 scf_value_reset_locked(v
, 0);
4694 v
->value_type
= REP_PROTOCOL_TYPE_INTEGER
;
4695 (void) sprintf(v
->value_value
, "%lld", (long long)new);
4696 (void) pthread_mutex_unlock(&h
->rh_lock
);
4700 scf_value_set_time(scf_value_t
*v
, int64_t new_sec
, int32_t new_nsec
)
4702 scf_handle_t
*h
= v
->value_handle
;
4704 (void) pthread_mutex_lock(&h
->rh_lock
);
4705 scf_value_reset_locked(v
, 0);
4706 if (new_nsec
< 0 || new_nsec
>= NANOSEC
) {
4707 (void) pthread_mutex_unlock(&h
->rh_lock
);
4708 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4710 v
->value_type
= REP_PROTOCOL_TYPE_TIME
;
4712 (void) sprintf(v
->value_value
, "%lld", (long long)new_sec
);
4714 (void) sprintf(v
->value_value
, "%lld.%09u", (long long)new_sec
,
4715 (unsigned)new_nsec
);
4716 (void) pthread_mutex_unlock(&h
->rh_lock
);
4721 scf_value_set_astring(scf_value_t
*v
, const char *new)
4723 scf_handle_t
*h
= v
->value_handle
;
4725 (void) pthread_mutex_lock(&h
->rh_lock
);
4726 scf_value_reset_locked(v
, 0);
4727 if (!scf_validate_encoded_value(REP_PROTOCOL_TYPE_STRING
, new)) {
4728 (void) pthread_mutex_unlock(&h
->rh_lock
);
4729 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4731 if (strlcpy(v
->value_value
, new, sizeof (v
->value_value
)) >=
4732 sizeof (v
->value_value
)) {
4733 (void) pthread_mutex_unlock(&h
->rh_lock
);
4734 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4736 v
->value_type
= REP_PROTOCOL_TYPE_STRING
;
4737 (void) pthread_mutex_unlock(&h
->rh_lock
);
4742 scf_value_set_ustring(scf_value_t
*v
, const char *new)
4744 scf_handle_t
*h
= v
->value_handle
;
4746 (void) pthread_mutex_lock(&h
->rh_lock
);
4747 scf_value_reset_locked(v
, 0);
4748 if (!scf_validate_encoded_value(REP_PROTOCOL_SUBTYPE_USTRING
, new)) {
4749 (void) pthread_mutex_unlock(&h
->rh_lock
);
4750 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4752 if (strlcpy(v
->value_value
, new, sizeof (v
->value_value
)) >=
4753 sizeof (v
->value_value
)) {
4754 (void) pthread_mutex_unlock(&h
->rh_lock
);
4755 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4757 v
->value_type
= REP_PROTOCOL_SUBTYPE_USTRING
;
4758 (void) pthread_mutex_unlock(&h
->rh_lock
);
4763 scf_value_set_opaque(scf_value_t
*v
, const void *new, size_t len
)
4765 scf_handle_t
*h
= v
->value_handle
;
4767 (void) pthread_mutex_lock(&h
->rh_lock
);
4768 scf_value_reset_locked(v
, 0);
4769 if (len
> sizeof (v
->value_value
)) {
4770 (void) pthread_mutex_unlock(&h
->rh_lock
);
4771 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4773 (void) memcpy(v
->value_value
, new, len
);
4774 v
->value_size
= len
;
4775 v
->value_type
= REP_PROTOCOL_TYPE_OPAQUE
;
4776 (void) pthread_mutex_unlock(&h
->rh_lock
);
4782 * _NOT_SET - v_arg is reset
4783 * _INTERNAL - v_arg is corrupt
4785 * If t is not _TYPE_INVALID, fails with
4786 * _TYPE_MISMATCH - v_arg's type is not compatible with t
4789 scf_value_get_as_string_common(const scf_value_t
*v_arg
,
4790 rep_protocol_value_type_t t
, char *buf
, size_t bufsz
)
4792 scf_handle_t
*h
= v_arg
->value_handle
;
4794 scf_value_t
*v
= &v_s
;
4798 (void) pthread_mutex_lock(&h
->rh_lock
);
4799 if (t
!= REP_PROTOCOL_TYPE_INVALID
&& !scf_value_check_type(v_arg
, t
)) {
4800 (void) pthread_mutex_unlock(&h
->rh_lock
);
4804 v_s
= *v_arg
; /* copy locally so we can unlock */
4805 h
->rh_values
++; /* keep the handle from going away */
4807 (void) pthread_mutex_unlock(&h
->rh_lock
);
4810 switch (REP_PROTOCOL_BASE_TYPE(v
->value_type
)) {
4811 case REP_PROTOCOL_TYPE_BOOLEAN
:
4812 r
= scf_value_get_boolean(v
, &b
);
4813 assert(r
== SCF_SUCCESS
);
4815 r
= strlcpy(buf
, b
? "true" : "false", bufsz
);
4818 case REP_PROTOCOL_TYPE_COUNT
:
4819 case REP_PROTOCOL_TYPE_INTEGER
:
4820 case REP_PROTOCOL_TYPE_TIME
:
4821 case REP_PROTOCOL_TYPE_STRING
:
4822 r
= strlcpy(buf
, v
->value_value
, bufsz
);
4825 case REP_PROTOCOL_TYPE_OPAQUE
:
4827 * Note that we only write out full hex bytes -- if they're
4828 * short, and bufsz is even, we'll only fill (bufsz - 2) bytes
4832 (void) scf_opaque_encode(buf
, v
->value_value
,
4833 MIN(v
->value_size
, (bufsz
- 1)/2));
4834 r
= (v
->value_size
* 2);
4837 case REP_PROTOCOL_TYPE_INVALID
:
4838 r
= scf_set_error(SCF_ERROR_NOT_SET
);
4842 r
= (scf_set_error(SCF_ERROR_INTERNAL
));
4846 (void) pthread_mutex_lock(&h
->rh_lock
);
4855 scf_value_get_as_string(const scf_value_t
*v
, char *buf
, size_t bufsz
)
4857 return (scf_value_get_as_string_common(v
, REP_PROTOCOL_TYPE_INVALID
,
4862 scf_value_get_as_string_typed(const scf_value_t
*v
, scf_type_t type
,
4863 char *buf
, size_t bufsz
)
4865 rep_protocol_value_type_t ty
= scf_type_to_protocol_type(type
);
4866 if (ty
== REP_PROTOCOL_TYPE_INVALID
)
4867 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4869 return (scf_value_get_as_string_common(v
, ty
, buf
, bufsz
));
4873 scf_value_set_from_string(scf_value_t
*v
, scf_type_t type
, const char *str
)
4875 scf_handle_t
*h
= v
->value_handle
;
4876 rep_protocol_value_type_t ty
;
4879 case SCF_TYPE_BOOLEAN
: {
4882 if (strcmp(str
, "true") == 0 || strcmp(str
, "t") == 0 ||
4883 strcmp(str
, "1") == 0)
4885 else if (strcmp(str
, "false") == 0 ||
4886 strcmp(str
, "f") == 0 || strcmp(str
, "0") == 0)
4892 scf_value_set_boolean(v
, b
);
4896 case SCF_TYPE_COUNT
: {
4901 c
= strtoull(str
, &endp
, 0);
4903 if (errno
!= 0 || endp
== str
|| *endp
!= '\0')
4906 scf_value_set_count(v
, c
);
4910 case SCF_TYPE_INTEGER
: {
4915 i
= strtoll(str
, &endp
, 0);
4917 if (errno
!= 0 || endp
== str
|| *endp
!= '\0')
4920 scf_value_set_integer(v
, i
);
4924 case SCF_TYPE_TIME
: {
4927 char *endp
, *ns_str
;
4931 s
= strtoll(str
, &endp
, 10);
4932 if (errno
!= 0 || endp
== str
||
4933 (*endp
!= '\0' && *endp
!= '.'))
4938 len
= strlen(ns_str
);
4939 if (len
== 0 || len
> 9)
4942 ns
= strtoul(ns_str
, &endp
, 10);
4943 if (errno
!= 0 || endp
== ns_str
|| *endp
!= '\0')
4948 assert(ns
< NANOSEC
);
4951 return (scf_value_set_time(v
, s
, ns
));
4954 case SCF_TYPE_ASTRING
:
4955 case SCF_TYPE_USTRING
:
4956 case SCF_TYPE_OPAQUE
:
4960 case SCF_TYPE_HOSTNAME
:
4961 case SCF_TYPE_NET_ADDR
:
4962 case SCF_TYPE_NET_ADDR_V4
:
4963 case SCF_TYPE_NET_ADDR_V6
:
4964 ty
= scf_type_to_protocol_type(type
);
4966 (void) pthread_mutex_lock(&h
->rh_lock
);
4967 scf_value_reset_locked(v
, 0);
4968 if (type
== SCF_TYPE_OPAQUE
) {
4969 v
->value_size
= scf_opaque_decode(v
->value_value
,
4970 str
, sizeof (v
->value_value
));
4971 if (!scf_validate_encoded_value(ty
, str
)) {
4972 (void) pthread_mutex_lock(&h
->rh_lock
);
4976 (void) strlcpy(v
->value_value
, str
,
4977 sizeof (v
->value_value
));
4978 if (!scf_validate_encoded_value(ty
, v
->value_value
)) {
4979 (void) pthread_mutex_lock(&h
->rh_lock
);
4984 (void) pthread_mutex_unlock(&h
->rh_lock
);
4985 return (SCF_SUCCESS
);
4987 case REP_PROTOCOL_TYPE_INVALID
:
4990 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH
));
4994 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
4998 scf_iter_property_values(scf_iter_t
*iter
, const scf_property_t
*prop
)
5000 return (datael_setup_iter(iter
, &prop
->rd_d
,
5001 REP_PROTOCOL_ENTITY_VALUE
, 0));
5005 scf_iter_next_value(scf_iter_t
*iter
, scf_value_t
*v
)
5007 scf_handle_t
*h
= iter
->iter_handle
;
5009 struct rep_protocol_iter_read_value request
;
5010 struct rep_protocol_value_response response
;
5014 if (h
!= v
->value_handle
)
5015 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5017 (void) pthread_mutex_lock(&h
->rh_lock
);
5019 scf_value_reset_locked(v
, 0);
5021 if (iter
->iter_type
== REP_PROTOCOL_ENTITY_NONE
) {
5022 (void) pthread_mutex_unlock(&h
->rh_lock
);
5023 return (scf_set_error(SCF_ERROR_NOT_SET
));
5026 if (iter
->iter_type
!= REP_PROTOCOL_ENTITY_VALUE
) {
5027 (void) pthread_mutex_unlock(&h
->rh_lock
);
5028 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5031 request
.rpr_request
= REP_PROTOCOL_ITER_READ_VALUE
;
5032 request
.rpr_iterid
= iter
->iter_id
;
5033 request
.rpr_sequence
= iter
->iter_sequence
;
5035 r
= make_door_call(h
, &request
, sizeof (request
),
5036 &response
, sizeof (response
));
5039 (void) pthread_mutex_unlock(&h
->rh_lock
);
5040 DOOR_ERRORS_BLOCK(r
);
5043 if (response
.rpr_response
== REP_PROTOCOL_DONE
) {
5044 (void) pthread_mutex_unlock(&h
->rh_lock
);
5047 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
) {
5048 (void) pthread_mutex_unlock(&h
->rh_lock
);
5049 return (scf_set_error(proto_error(response
.rpr_response
)));
5051 iter
->iter_sequence
++;
5053 v
->value_type
= response
.rpr_type
;
5055 assert(scf_validate_encoded_value(response
.rpr_type
,
5056 response
.rpr_value
));
5058 if (v
->value_type
!= REP_PROTOCOL_TYPE_OPAQUE
) {
5059 (void) strlcpy(v
->value_value
, response
.rpr_value
,
5060 sizeof (v
->value_value
));
5062 v
->value_size
= scf_opaque_decode(v
->value_value
,
5063 response
.rpr_value
, sizeof (v
->value_value
));
5065 (void) pthread_mutex_unlock(&h
->rh_lock
);
5071 scf_property_get_value(const scf_property_t
*prop
, scf_value_t
*v
)
5073 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
5074 struct rep_protocol_property_request request
;
5075 struct rep_protocol_value_response response
;
5078 if (h
!= v
->value_handle
)
5079 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5081 (void) pthread_mutex_lock(&h
->rh_lock
);
5083 request
.rpr_request
= REP_PROTOCOL_PROPERTY_GET_VALUE
;
5084 request
.rpr_entityid
= prop
->rd_d
.rd_entity
;
5086 scf_value_reset_locked(v
, 0);
5087 datael_finish_reset(&prop
->rd_d
);
5089 r
= make_door_call(h
, &request
, sizeof (request
),
5090 &response
, sizeof (response
));
5093 (void) pthread_mutex_unlock(&h
->rh_lock
);
5094 DOOR_ERRORS_BLOCK(r
);
5097 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
&&
5098 response
.rpr_response
!= REP_PROTOCOL_FAIL_TRUNCATED
) {
5099 (void) pthread_mutex_unlock(&h
->rh_lock
);
5100 assert(response
.rpr_response
!=
5101 REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
5102 return (scf_set_error(proto_error(response
.rpr_response
)));
5105 v
->value_type
= response
.rpr_type
;
5106 if (v
->value_type
!= REP_PROTOCOL_TYPE_OPAQUE
) {
5107 (void) strlcpy(v
->value_value
, response
.rpr_value
,
5108 sizeof (v
->value_value
));
5110 v
->value_size
= scf_opaque_decode(v
->value_value
,
5111 response
.rpr_value
, sizeof (v
->value_value
));
5113 (void) pthread_mutex_unlock(&h
->rh_lock
);
5114 return ((response
.rpr_response
== REP_PROTOCOL_SUCCESS
)?
5115 SCF_SUCCESS
: scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
));
5119 scf_pg_get_parent_service(const scf_propertygroup_t
*pg
, scf_service_t
*svc
)
5121 return (datael_get_parent(&pg
->rd_d
, &svc
->rd_d
));
5125 scf_pg_get_parent_instance(const scf_propertygroup_t
*pg
, scf_instance_t
*inst
)
5127 return (datael_get_parent(&pg
->rd_d
, &inst
->rd_d
));
5131 scf_pg_get_parent_snaplevel(const scf_propertygroup_t
*pg
,
5132 scf_snaplevel_t
*level
)
5134 return (datael_get_parent(&pg
->rd_d
, &level
->rd_d
));
5138 scf_service_get_parent(const scf_service_t
*svc
, scf_scope_t
*s
)
5140 return (datael_get_parent(&svc
->rd_d
, &s
->rd_d
));
5144 scf_instance_get_parent(const scf_instance_t
*inst
, scf_service_t
*svc
)
5146 return (datael_get_parent(&inst
->rd_d
, &svc
->rd_d
));
5150 scf_snapshot_get_parent(const scf_snapshot_t
*inst
, scf_instance_t
*svc
)
5152 return (datael_get_parent(&inst
->rd_d
, &svc
->rd_d
));
5156 scf_snaplevel_get_parent(const scf_snaplevel_t
*inst
, scf_snapshot_t
*svc
)
5158 return (datael_get_parent(&inst
->rd_d
, &svc
->rd_d
));
5164 * Note: In the scf_parse_svc_fmri(), scf_parse_file_fmri() and
5165 * scf_parse_fmri(), fmri isn't const because that would require
5166 * allocating memory. Also, note that scope, at least, is not necessarily
5167 * in the passed in fmri.
5171 scf_parse_svc_fmri(char *fmri
, const char **scope
, const char **service
,
5172 const char **instance
, const char **propertygroup
, const char **property
)
5174 char *s
, *e
, *te
, *tpg
;
5175 char *my_s
= NULL
, *my_i
= NULL
, *my_pg
= NULL
, *my_p
= NULL
;
5179 if (service
!= NULL
)
5181 if (instance
!= NULL
)
5183 if (propertygroup
!= NULL
)
5184 *propertygroup
= NULL
;
5185 if (property
!= NULL
)
5189 e
= strchr(s
, '\0');
5191 if (strncmp(s
, SCF_FMRI_SVC_PREFIX
,
5192 sizeof (SCF_FMRI_SVC_PREFIX
) - 1) == 0)
5193 s
+= sizeof (SCF_FMRI_SVC_PREFIX
) - 1;
5195 if (strncmp(s
, SCF_FMRI_SCOPE_PREFIX
,
5196 sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1) == 0) {
5199 s
+= sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1;
5200 te
= strstr(s
, SCF_FMRI_SERVICE_PREFIX
);
5209 s
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5211 /* If the scope ends with the suffix, remove it. */
5212 te
= strstr(my_scope
, SCF_FMRI_SCOPE_SUFFIX
);
5213 if (te
!= NULL
&& te
[sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1] == 0)
5216 /* Validate the scope. */
5217 if (my_scope
[0] == '\0')
5218 my_scope
= SCF_FMRI_LOCAL_SCOPE
;
5219 else if (uu_check_name(my_scope
, 0) == -1) {
5220 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5227 *scope
= SCF_FMRI_LOCAL_SCOPE
;
5231 if (strncmp(s
, SCF_FMRI_SERVICE_PREFIX
,
5232 sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1) == 0)
5233 s
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5236 * Can't validate service here because it might not be null
5242 tpg
= strstr(s
, SCF_FMRI_PROPERTYGRP_PREFIX
);
5243 te
= strstr(s
, SCF_FMRI_INSTANCE_PREFIX
);
5244 if (te
!= NULL
&& (tpg
== NULL
|| te
< tpg
)) {
5246 te
+= sizeof (SCF_FMRI_INSTANCE_PREFIX
) - 1;
5248 /* Can't validate instance here either. */
5251 te
= strstr(s
, SCF_FMRI_PROPERTYGRP_PREFIX
);
5258 te
+= sizeof (SCF_FMRI_PROPERTYGRP_PREFIX
) - 1;
5261 te
= strstr(s
, SCF_FMRI_PROPERTY_PREFIX
);
5264 te
+= sizeof (SCF_FMRI_PROPERTY_PREFIX
) - 1;
5272 if (uu_check_name(my_s
, UU_NAME_DOMAIN
| UU_NAME_PATH
) == -1)
5273 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5275 if (service
!= NULL
)
5280 if (uu_check_name(my_i
, UU_NAME_DOMAIN
) == -1)
5281 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5283 if (instance
!= NULL
)
5287 if (my_pg
!= NULL
) {
5288 if (uu_check_name(my_pg
, UU_NAME_DOMAIN
) == -1)
5289 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5291 if (propertygroup
!= NULL
)
5292 *propertygroup
= my_pg
;
5296 if (uu_check_name(my_p
, UU_NAME_DOMAIN
) == -1)
5297 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5299 if (property
!= NULL
)
5307 scf_parse_file_fmri(char *fmri
, const char **scope
, const char **path
)
5315 e
= strchr(s
, '\0');
5317 if (strncmp(s
, SCF_FMRI_FILE_PREFIX
,
5318 sizeof (SCF_FMRI_FILE_PREFIX
) - 1) == 0)
5319 s
+= sizeof (SCF_FMRI_FILE_PREFIX
) - 1;
5321 if (strncmp(s
, SCF_FMRI_SCOPE_PREFIX
,
5322 sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1) == 0) {
5325 s
+= sizeof (SCF_FMRI_SCOPE_PREFIX
) - 1;
5326 te
= strstr(s
, SCF_FMRI_SERVICE_PREFIX
);
5335 /* Validate the scope. */
5336 if (my_scope
[0] != '\0' &&
5337 strcmp(my_scope
, SCF_FMRI_LOCAL_SCOPE
) != 0) {
5338 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5345 * FMRI paths must be absolute
5348 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5351 s
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5354 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
5357 * If the user requests it, return the full path of the file.
5369 scf_parse_fmri(char *fmri
, int *type
, const char **scope
, const char **service
,
5370 const char **instance
, const char **propertygroup
, const char **property
)
5372 if (strncmp(fmri
, SCF_FMRI_SVC_PREFIX
,
5373 sizeof (SCF_FMRI_SVC_PREFIX
) - 1) == 0) {
5375 *type
= SCF_FMRI_TYPE_SVC
;
5376 return (scf_parse_svc_fmri(fmri
, scope
, service
, instance
,
5377 propertygroup
, property
));
5378 } else if (strncmp(fmri
, SCF_FMRI_FILE_PREFIX
,
5379 sizeof (SCF_FMRI_FILE_PREFIX
) - 1) == 0) {
5381 *type
= SCF_FMRI_TYPE_FILE
;
5382 return (scf_parse_file_fmri(fmri
, scope
, NULL
));
5385 * Parse as a svc if the fmri type is not explicitly
5389 *type
= SCF_FMRI_TYPE_SVC
;
5390 return (scf_parse_svc_fmri(fmri
, scope
, service
, instance
,
5391 propertygroup
, property
));
5396 * Fails with _INVALID_ARGUMENT. fmri and buf may be equal.
5399 scf_canonify_fmri(const char *fmri
, char *buf
, size_t bufsz
)
5401 const char *scope
, *service
, *instance
, *pg
, *property
;
5402 char local
[6 * REP_PROTOCOL_NAME_LEN
];
5406 if (strlcpy(local
, fmri
, sizeof (local
)) >= sizeof (local
)) {
5407 /* Should this be CONSTRAINT_VIOLATED? */
5408 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
5413 r
= scf_parse_svc_fmri(local
, &scope
, &service
, &instance
, &pg
,
5418 len
= strlcpy(buf
, "svc:/", bufsz
);
5420 if (scope
!= NULL
&& strcmp(scope
, SCF_SCOPE_LOCAL
) != 0) {
5421 len
+= strlcat(buf
, "/", bufsz
);
5422 len
+= strlcat(buf
, scope
, bufsz
);
5426 len
+= strlcat(buf
, service
, bufsz
);
5429 len
+= strlcat(buf
, ":", bufsz
);
5430 len
+= strlcat(buf
, instance
, bufsz
);
5434 len
+= strlcat(buf
, "/:properties/", bufsz
);
5435 len
+= strlcat(buf
, pg
, bufsz
);
5439 len
+= strlcat(buf
, "/", bufsz
);
5440 len
+= strlcat(buf
, property
, bufsz
);
5447 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _CONSTRAINT_VIOLATED,
5448 * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED,
5449 * _NO_RESOURCES, _BACKEND_ACCESS.
5452 scf_handle_decode_fmri(scf_handle_t
*h
, const char *fmri
, scf_scope_t
*sc
,
5453 scf_service_t
*svc
, scf_instance_t
*inst
, scf_propertygroup_t
*pg
,
5454 scf_property_t
*prop
, int flags
)
5456 const char *scope
, *service
, *instance
, *propertygroup
, *property
;
5458 char local
[6 * REP_PROTOCOL_NAME_LEN
];
5460 const uint32_t holds
= RH_HOLD_SCOPE
| RH_HOLD_SERVICE
|
5461 RH_HOLD_INSTANCE
| RH_HOLD_PG
| RH_HOLD_PROPERTY
;
5464 * verify that all handles match
5466 if ((sc
!= NULL
&& h
!= sc
->rd_d
.rd_handle
) ||
5467 (svc
!= NULL
&& h
!= svc
->rd_d
.rd_handle
) ||
5468 (inst
!= NULL
&& h
!= inst
->rd_d
.rd_handle
) ||
5469 (pg
!= NULL
&& h
!= pg
->rd_d
.rd_handle
) ||
5470 (prop
!= NULL
&& h
!= prop
->rd_d
.rd_handle
))
5471 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5473 if (strlcpy(local
, fmri
, sizeof (local
)) >= sizeof (local
)) {
5474 ret
= scf_set_error(SCF_ERROR_INVALID_ARGUMENT
);
5479 * We can simply return from an error in parsing, because
5480 * scf_parse_fmri sets the error code correctly.
5482 if (scf_parse_svc_fmri(local
, &scope
, &service
, &instance
,
5483 &propertygroup
, &property
) == -1) {
5489 * the FMRI looks valid at this point -- do constraint checks.
5492 if (instance
!= NULL
&& (flags
& SCF_DECODE_FMRI_REQUIRE_NO_INSTANCE
)) {
5493 ret
= scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
);
5496 if (instance
== NULL
&& (flags
& SCF_DECODE_FMRI_REQUIRE_INSTANCE
)) {
5497 ret
= scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
);
5502 last
= REP_PROTOCOL_ENTITY_PROPERTY
;
5503 else if (pg
!= NULL
)
5504 last
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
5505 else if (inst
!= NULL
)
5506 last
= REP_PROTOCOL_ENTITY_INSTANCE
;
5507 else if (svc
!= NULL
)
5508 last
= REP_PROTOCOL_ENTITY_SERVICE
;
5509 else if (sc
!= NULL
)
5510 last
= REP_PROTOCOL_ENTITY_SCOPE
;
5512 last
= REP_PROTOCOL_ENTITY_NONE
;
5514 if (flags
& SCF_DECODE_FMRI_EXACT
) {
5517 if (property
!= NULL
)
5518 last_fmri
= REP_PROTOCOL_ENTITY_PROPERTY
;
5519 else if (propertygroup
!= NULL
)
5520 last_fmri
= REP_PROTOCOL_ENTITY_PROPERTYGRP
;
5521 else if (instance
!= NULL
)
5522 last_fmri
= REP_PROTOCOL_ENTITY_INSTANCE
;
5523 else if (service
!= NULL
)
5524 last_fmri
= REP_PROTOCOL_ENTITY_SERVICE
;
5525 else if (scope
!= NULL
)
5526 last_fmri
= REP_PROTOCOL_ENTITY_SCOPE
;
5528 last_fmri
= REP_PROTOCOL_ENTITY_NONE
;
5530 if (last
!= last_fmri
) {
5531 ret
= scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED
);
5536 if ((flags
& SCF_DECODE_FMRI_TRUNCATE
) &&
5537 last
== REP_PROTOCOL_ENTITY_NONE
) {
5538 ret
= 0; /* nothing to do */
5542 if (!(flags
& SCF_DECODE_FMRI_TRUNCATE
))
5543 last
= REP_PROTOCOL_ENTITY_NONE
; /* never stop */
5546 * passed the constraint checks -- try to grab the thing itself.
5549 handle_hold_subhandles(h
, holds
);
5553 datael_reset(&sc
->rd_d
);
5556 svc
= h
->rh_service
;
5558 datael_reset(&svc
->rd_d
);
5561 inst
= h
->rh_instance
;
5563 datael_reset(&inst
->rd_d
);
5568 datael_reset(&pg
->rd_d
);
5571 prop
= h
->rh_property
;
5573 datael_reset(&prop
->rd_d
);
5576 * We only support local scopes, but we check *after* getting
5577 * the local scope, so that any repository-related errors take
5580 if (scf_handle_get_scope(h
, SCF_SCOPE_LOCAL
, sc
) == -1) {
5581 handle_rele_subhandles(h
, holds
);
5586 if (scope
!= NULL
&& strcmp(scope
, SCF_FMRI_LOCAL_SCOPE
) != 0) {
5587 handle_rele_subhandles(h
, holds
);
5588 ret
= scf_set_error(SCF_ERROR_NOT_FOUND
);
5593 if (service
== NULL
|| last
== REP_PROTOCOL_ENTITY_SCOPE
) {
5594 handle_rele_subhandles(h
, holds
);
5598 if (scf_scope_get_service(sc
, service
, svc
) == -1) {
5599 handle_rele_subhandles(h
, holds
);
5601 assert(scf_error() != SCF_ERROR_NOT_SET
);
5602 if (scf_error() == SCF_ERROR_DELETED
)
5603 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5607 if (last
== REP_PROTOCOL_ENTITY_SERVICE
) {
5608 handle_rele_subhandles(h
, holds
);
5612 if (instance
== NULL
) {
5613 if (propertygroup
== NULL
||
5614 last
== REP_PROTOCOL_ENTITY_INSTANCE
) {
5615 handle_rele_subhandles(h
, holds
);
5619 if (scf_service_get_pg(svc
, propertygroup
, pg
) == -1) {
5620 handle_rele_subhandles(h
, holds
);
5622 assert(scf_error() != SCF_ERROR_NOT_SET
);
5623 if (scf_error() == SCF_ERROR_DELETED
)
5624 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5628 if (scf_service_get_instance(svc
, instance
, inst
) == -1) {
5629 handle_rele_subhandles(h
, holds
);
5631 assert(scf_error() != SCF_ERROR_NOT_SET
);
5632 if (scf_error() == SCF_ERROR_DELETED
)
5633 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5637 if (propertygroup
== NULL
||
5638 last
== REP_PROTOCOL_ENTITY_INSTANCE
) {
5639 handle_rele_subhandles(h
, holds
);
5643 if (scf_instance_get_pg(inst
, propertygroup
, pg
) == -1) {
5644 handle_rele_subhandles(h
, holds
);
5646 assert(scf_error() != SCF_ERROR_NOT_SET
);
5647 if (scf_error() == SCF_ERROR_DELETED
)
5648 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5653 if (property
== NULL
|| last
== REP_PROTOCOL_ENTITY_PROPERTYGRP
) {
5654 handle_rele_subhandles(h
, holds
);
5658 if (scf_pg_get_property(pg
, property
, prop
) == -1) {
5659 handle_rele_subhandles(h
, holds
);
5661 assert(scf_error() != SCF_ERROR_NOT_SET
);
5662 if (scf_error() == SCF_ERROR_DELETED
)
5663 (void) scf_set_error(SCF_ERROR_NOT_FOUND
);
5667 handle_rele_subhandles(h
, holds
);
5672 datael_reset(&sc
->rd_d
);
5674 datael_reset(&svc
->rd_d
);
5676 datael_reset(&inst
->rd_d
);
5678 datael_reset(&pg
->rd_d
);
5680 datael_reset(&prop
->rd_d
);
5686 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5687 * big, bad entity id, request not applicable to entity, name too long for
5688 * buffer), _NOT_SET, or _DELETED.
5691 scf_scope_to_fmri(const scf_scope_t
*scope
, char *out
, size_t sz
)
5695 char tmp
[REP_PROTOCOL_NAME_LEN
];
5697 r
= scf_scope_get_name(scope
, tmp
, sizeof (tmp
));
5702 len
= strlcpy(out
, SCF_FMRI_SVC_PREFIX
, sz
);
5703 if (strcmp(tmp
, SCF_FMRI_LOCAL_SCOPE
) != 0) {
5705 return (len
+ r
+ sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1);
5707 len
= strlcat(out
, tmp
, sz
);
5709 return (len
+ sizeof (SCF_FMRI_SCOPE_SUFFIX
) - 1);
5711 SCF_FMRI_SCOPE_SUFFIX SCF_FMRI_SERVICE_PREFIX
, sz
);
5718 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5719 * big, bad element id, bad ids, bad types, scope has no parent, request not
5720 * applicable to entity, name too long), _NOT_SET, _DELETED,
5723 scf_service_to_fmri(const scf_service_t
*svc
, char *out
, size_t sz
)
5725 scf_handle_t
*h
= svc
->rd_d
.rd_handle
;
5726 scf_scope_t
*scope
= HANDLE_HOLD_SCOPE(h
);
5729 char tmp
[REP_PROTOCOL_NAME_LEN
];
5731 r
= datael_get_parent(&svc
->rd_d
, &scope
->rd_d
);
5732 if (r
!= SCF_SUCCESS
) {
5733 HANDLE_RELE_SCOPE(h
);
5735 assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH
);
5738 if (out
!= NULL
&& sz
> 0)
5739 len
= scf_scope_to_fmri(scope
, out
, sz
);
5741 len
= scf_scope_to_fmri(scope
, tmp
, 2);
5743 HANDLE_RELE_SCOPE(h
);
5748 if (out
== NULL
|| len
>= sz
)
5749 len
+= sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1;
5751 len
= strlcat(out
, SCF_FMRI_SERVICE_PREFIX
, sz
);
5753 r
= scf_service_get_name(svc
, tmp
, sizeof (tmp
));
5757 if (out
== NULL
|| len
>= sz
)
5760 len
= strlcat(out
, tmp
, sz
);
5766 scf_instance_to_fmri(const scf_instance_t
*inst
, char *out
, size_t sz
)
5768 scf_handle_t
*h
= inst
->rd_d
.rd_handle
;
5769 scf_service_t
*svc
= HANDLE_HOLD_SERVICE(h
);
5772 char tmp
[REP_PROTOCOL_NAME_LEN
];
5774 r
= datael_get_parent(&inst
->rd_d
, &svc
->rd_d
);
5775 if (r
!= SCF_SUCCESS
) {
5776 HANDLE_RELE_SERVICE(h
);
5780 len
= scf_service_to_fmri(svc
, out
, sz
);
5782 HANDLE_RELE_SERVICE(h
);
5788 len
+= sizeof (SCF_FMRI_INSTANCE_PREFIX
) - 1;
5790 len
= strlcat(out
, SCF_FMRI_INSTANCE_PREFIX
, sz
);
5792 r
= scf_instance_get_name(inst
, tmp
, sizeof (tmp
));
5799 len
= strlcat(out
, tmp
, sz
);
5805 scf_pg_to_fmri(const scf_propertygroup_t
*pg
, char *out
, size_t sz
)
5807 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
5809 struct rep_protocol_entity_parent_type request
;
5810 struct rep_protocol_integer_response response
;
5812 char tmp
[REP_PROTOCOL_NAME_LEN
];
5815 (void) pthread_mutex_lock(&h
->rh_lock
);
5816 request
.rpr_request
= REP_PROTOCOL_ENTITY_PARENT_TYPE
;
5817 request
.rpr_entityid
= pg
->rd_d
.rd_entity
;
5819 datael_finish_reset(&pg
->rd_d
);
5820 r
= make_door_call(h
, &request
, sizeof (request
),
5821 &response
, sizeof (response
));
5822 (void) pthread_mutex_unlock(&h
->rh_lock
);
5825 DOOR_ERRORS_BLOCK(r
);
5827 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
||
5828 r
< sizeof (response
)) {
5829 return (scf_set_error(proto_error(response
.rpr_response
)));
5832 switch (response
.rpr_value
) {
5833 case REP_PROTOCOL_ENTITY_SERVICE
: {
5836 svc
= HANDLE_HOLD_SERVICE(h
);
5838 r
= datael_get_parent(&pg
->rd_d
, &svc
->rd_d
);
5840 if (r
== SCF_SUCCESS
)
5841 len
= scf_service_to_fmri(svc
, out
, sz
);
5843 HANDLE_RELE_SERVICE(h
);
5847 case REP_PROTOCOL_ENTITY_INSTANCE
: {
5848 scf_instance_t
*inst
;
5850 inst
= HANDLE_HOLD_INSTANCE(h
);
5852 r
= datael_get_parent(&pg
->rd_d
, &inst
->rd_d
);
5854 if (r
== SCF_SUCCESS
)
5855 len
= scf_instance_to_fmri(inst
, out
, sz
);
5857 HANDLE_RELE_INSTANCE(h
);
5861 case REP_PROTOCOL_ENTITY_SNAPLEVEL
: {
5862 scf_instance_t
*inst
= HANDLE_HOLD_INSTANCE(h
);
5863 scf_snapshot_t
*snap
= HANDLE_HOLD_SNAPSHOT(h
);
5864 scf_snaplevel_t
*level
= HANDLE_HOLD_SNAPLVL(h
);
5866 r
= datael_get_parent(&pg
->rd_d
, &level
->rd_d
);
5868 if (r
== SCF_SUCCESS
)
5869 r
= datael_get_parent(&level
->rd_d
, &snap
->rd_d
);
5871 if (r
== SCF_SUCCESS
)
5872 r
= datael_get_parent(&snap
->rd_d
, &inst
->rd_d
);
5874 if (r
== SCF_SUCCESS
)
5875 len
= scf_instance_to_fmri(inst
, out
, sz
);
5877 HANDLE_RELE_INSTANCE(h
);
5878 HANDLE_RELE_SNAPSHOT(h
);
5879 HANDLE_RELE_SNAPLVL(h
);
5884 return (scf_set_error(SCF_ERROR_INTERNAL
));
5887 if (r
!= SCF_SUCCESS
)
5891 len
+= sizeof (SCF_FMRI_PROPERTYGRP_PREFIX
) - 1;
5893 len
= strlcat(out
, SCF_FMRI_PROPERTYGRP_PREFIX
, sz
);
5895 r
= scf_pg_get_name(pg
, tmp
, sizeof (tmp
));
5903 len
= strlcat(out
, tmp
, sz
);
5909 scf_property_to_fmri(const scf_property_t
*prop
, char *out
, size_t sz
)
5911 scf_handle_t
*h
= prop
->rd_d
.rd_handle
;
5912 scf_propertygroup_t
*pg
= HANDLE_HOLD_PG(h
);
5914 char tmp
[REP_PROTOCOL_NAME_LEN
];
5918 r
= datael_get_parent(&prop
->rd_d
, &pg
->rd_d
);
5919 if (r
!= SCF_SUCCESS
) {
5924 len
= scf_pg_to_fmri(pg
, out
, sz
);
5929 len
+= sizeof (SCF_FMRI_PROPERTY_PREFIX
) - 1;
5931 len
= strlcat(out
, SCF_FMRI_PROPERTY_PREFIX
, sz
);
5933 r
= scf_property_get_name(prop
, tmp
, sizeof (tmp
));
5941 len
= strlcat(out
, tmp
, sz
);
5947 * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
5948 * (server response too big, bad entity id, request not applicable to entity,
5949 * name too long for buffer, bad element id, iter already exists, element
5950 * cannot have children of type, type is invalid, iter was reset, sequence
5951 * was bad, iter walks values, iter does not walk type entities),
5952 * _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED,
5953 * _NOT_FOUND (scope has no parent), _INVALID_ARGUMENT, _NO_RESOURCES,
5957 scf_pg_get_underlying_pg(const scf_propertygroup_t
*pg
,
5958 scf_propertygroup_t
*out
)
5960 scf_handle_t
*h
= pg
->rd_d
.rd_handle
;
5962 scf_instance_t
*inst
;
5964 char me
[REP_PROTOCOL_NAME_LEN
];
5967 if (h
!= out
->rd_d
.rd_handle
)
5968 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH
));
5970 r
= scf_pg_get_name(pg
, me
, sizeof (me
));
5975 svc
= HANDLE_HOLD_SERVICE(h
);
5976 inst
= HANDLE_HOLD_INSTANCE(h
);
5978 r
= datael_get_parent(&pg
->rd_d
, &inst
->rd_d
);
5980 if (r
== SCF_SUCCESS
) {
5981 r
= datael_get_parent(&inst
->rd_d
, &svc
->rd_d
);
5982 if (r
!= SCF_SUCCESS
) {
5985 r
= scf_service_get_pg(svc
, me
, out
);
5987 r
= scf_set_error(SCF_ERROR_NOT_FOUND
);
5991 HANDLE_RELE_SERVICE(h
);
5992 HANDLE_RELE_INSTANCE(h
);
5996 #define LEGACY_SCHEME "lrc:"
5997 #define LEGACY_UNKNOWN "unknown"
6000 * Implementation of scf_walk_fmri()
6002 * This is a little tricky due to the many-to-many relationship between patterns
6003 * and matches. We need to be able to satisfy the following requirements:
6005 * 1) Detect patterns which match more than one FMRI, and be able to
6006 * report which FMRIs have been matched.
6007 * 2) Detect patterns which have not matched any FMRIs
6008 * 3) Visit each matching FMRI exactly once across all patterns
6009 * 4) Ignore FMRIs which have only been matched due to multiply-matching
6012 * We maintain an array of scf_pattern_t structures, one for each argument, and
6013 * maintain a linked list of scf_match_t structures for each one. We first
6014 * qualify each pattern's type:
6016 * PATTERN_INVALID The argument is invalid (too long).
6018 * PATTERN_EXACT The pattern is a complete FMRI. The list of
6019 * matches contains only a single entry.
6021 * PATTERN_GLOB The pattern will be matched against all
6022 * FMRIs via fnmatch() in the second phase.
6023 * Matches will be added to the pattern's list
6024 * as they are found.
6026 * PATTERN_PARTIAL Everything else. We will assume that this is
6027 * an abbreviated FMRI, and match according to
6028 * our abbreviated FMRI rules. Matches will be
6029 * added to the pattern's list as they are found.
6031 * The first pass searches for arguments that are complete FMRIs. These are
6032 * classified as EXACT patterns and do not necessitate searching the entire
6035 * Once this is done, if we have any GLOB or PARTIAL patterns (or if no
6036 * arguments were given), we iterate over all services and instances in the
6037 * repository, looking for matches.
6039 * When a match is found, we add the match to the pattern's list. We also enter
6040 * the match into a hash table, resulting in something like this:
6042 * scf_pattern_t scf_match_t
6043 * +---------------+ +-------+ +-------+
6044 * | pattern 'foo' |----->| match |---->| match |
6045 * +---------------+ +-------+ +-------+
6047 * scf_match_key_t | |
6048 * +--------------+ | |
6049 * | FMRI bar/foo |<----+ |
6050 * +--------------+ |
6051 * | FMRI baz/foo |<------------------+
6054 * Once we have all of this set up, we do one pass to report patterns matching
6055 * multiple FMRIs (if SCF_WALK_MULTIPLE is not set) and patterns for which no
6058 * Finally, we walk through all valid patterns, and for each match, if we
6059 * haven't already seen the match (as recorded in the hash table), then we
6060 * execute the callback.
6063 struct scf_matchkey
;
6069 typedef struct scf_matchkey
{
6070 char *sk_fmri
; /* Matching FMRI */
6071 char *sk_legacy
; /* Legacy name */
6072 int sk_seen
; /* If we've been seen */
6073 struct scf_matchkey
*sk_next
; /* Next in hash chain */
6079 typedef struct scf_match
{
6080 scf_matchkey_t
*sm_key
;
6081 struct scf_match
*sm_next
;
6084 #define WALK_HTABLE_SIZE 123
6089 * Given an FMRI and a hash table, returns the scf_matchkey_t corresponding to
6090 * this FMRI. If the FMRI does not exist, it is added to the hash table. If a
6091 * new entry cannot be allocated due to lack of memory, NULL is returned.
6093 static scf_matchkey_t
*
6094 scf_get_key(scf_matchkey_t
**htable
, const char *fmri
, const char *legacy
)
6098 scf_matchkey_t
*key
;
6100 k
= strstr(fmri
, ":/");
6105 * Generic hash function from uts/common/os/modhash.c.
6107 for (p
= k
; *p
!= '\0'; ++p
) {
6109 if ((g
= (h
& 0xf0000000)) != 0) {
6115 h
%= WALK_HTABLE_SIZE
;
6118 * Search for an existing key
6120 for (key
= htable
[h
]; key
!= NULL
; key
= key
->sk_next
) {
6121 if (strcmp(key
->sk_fmri
, fmri
) == 0)
6125 if ((key
= calloc(sizeof (scf_matchkey_t
), 1)) == NULL
)
6129 * Add new key to hash table.
6131 if ((key
->sk_fmri
= strdup(fmri
)) == NULL
) {
6136 if (legacy
== NULL
) {
6137 key
->sk_legacy
= NULL
;
6138 } else if ((key
->sk_legacy
= strdup(legacy
)) == NULL
) {
6144 key
->sk_next
= htable
[h
];
6151 * Given an FMRI, insert it into the pattern's list appropriately.
6152 * svc_explicit indicates whether matching services should take
6153 * precedence over matching instances.
6156 scf_add_match(scf_matchkey_t
**htable
, const char *fmri
, const char *legacy
,
6157 scf_pattern_t
*pattern
, int svc_explicit
)
6162 * If svc_explicit is set, enforce the constaint that matching
6163 * instances take precedence over matching services. Otherwise,
6164 * matching services take precedence over matching instances.
6167 scf_match_t
*next
, *prev
;
6169 * If we match an instance, check to see if we must remove
6170 * any matching services (for SCF_WALK_EXPLICIT).
6172 for (prev
= match
= pattern
->sp_matches
; match
!= NULL
;
6174 size_t len
= strlen(match
->sm_key
->sk_fmri
);
6175 next
= match
->sm_next
;
6176 if (strncmp(match
->sm_key
->sk_fmri
, fmri
, len
) == 0 &&
6179 pattern
->sp_matches
= match
->sm_next
;
6181 prev
->sm_next
= match
->sm_next
;
6182 pattern
->sp_matchcount
--;
6189 * If we've matched a service don't add any instances (for
6190 * SCF_WALK_SERVICE).
6192 for (match
= pattern
->sp_matches
; match
!= NULL
;
6193 match
= match
->sm_next
) {
6194 size_t len
= strlen(match
->sm_key
->sk_fmri
);
6195 if (strncmp(match
->sm_key
->sk_fmri
, fmri
, len
) == 0 &&
6201 if ((match
= malloc(sizeof (scf_match_t
))) == NULL
)
6202 return (SCF_ERROR_NO_MEMORY
);
6204 if ((match
->sm_key
= scf_get_key(htable
, fmri
, legacy
)) == NULL
) {
6206 return (SCF_ERROR_NO_MEMORY
);
6209 match
->sm_next
= pattern
->sp_matches
;
6210 pattern
->sp_matches
= match
;
6211 pattern
->sp_matchcount
++;
6217 * Returns 1 if the fmri matches the given pattern, 0 otherwise.
6220 scf_cmp_pattern(char *fmri
, scf_pattern_t
*pattern
)
6224 if (pattern
->sp_type
== PATTERN_GLOB
) {
6225 if (fnmatch(pattern
->sp_arg
, fmri
, 0) == 0)
6227 } else if (pattern
->sp_type
== PATTERN_PARTIAL
&&
6228 (tmp
= strstr(fmri
, pattern
->sp_arg
)) != NULL
) {
6230 * We only allow partial matches anchored on the end of
6231 * a service or instance, and beginning on an element
6234 if (tmp
!= fmri
&& tmp
[-1] != '/' && tmp
[-1] != ':' &&
6237 tmp
+= strlen(pattern
->sp_arg
);
6238 if (tmp
!= fmri
+ strlen(fmri
) && tmp
[0] != ':' &&
6243 * If the user has supplied a short pattern that matches
6244 * 'svc:/' or 'lrc:/', ignore it.
6246 if (tmp
<= fmri
+ 4)
6256 * Attempts to match the given FMRI against a set of patterns, keeping track of
6260 scf_pattern_match(scf_matchkey_t
**htable
, char *fmri
, const char *legacy
,
6261 int npattern
, scf_pattern_t
*pattern
, int svc_explicit
)
6266 for (i
= 0; i
< npattern
; i
++) {
6267 if (scf_cmp_pattern(fmri
, &pattern
[i
]) &&
6268 (ret
= scf_add_match(htable
, fmri
,
6269 legacy
, &pattern
[i
], svc_explicit
)) != 0)
6277 * Fails with _INVALID_ARGUMENT, _HANDLE_DESTROYED, _INTERNAL (bad server
6278 * response or id in use), _NO_MEMORY, _HANDLE_MISMATCH, _CONSTRAINT_VIOLATED,
6279 * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _NOT_SET, _DELETED,
6280 * _NO_RESOURCES, _BACKEND_ACCESS, _TYPE_MISMATCH.
6283 scf_walk_fmri(scf_handle_t
*h
, int argc
, char **argv
, int flags
,
6284 scf_walk_callback callback
, void *data
, int *err
,
6285 void (*errfunc
)(const char *, ...))
6287 scf_pattern_t
*pattern
= NULL
;
6290 ssize_t max_fmri_length
;
6291 scf_service_t
*svc
= NULL
;
6292 scf_instance_t
*inst
= NULL
;
6293 scf_iter_t
*iter
= NULL
, *sciter
= NULL
, *siter
= NULL
;
6294 scf_scope_t
*scope
= NULL
;
6295 scf_propertygroup_t
*pg
= NULL
;
6296 scf_property_t
*prop
= NULL
;
6297 scf_value_t
*value
= NULL
;
6299 scf_matchkey_t
**htable
= NULL
;
6300 int pattern_search
= 0;
6301 ssize_t max_name_length
;
6302 char *pgname
= NULL
;
6303 scf_walkinfo_t info
;
6304 boolean_t partial_fmri
= B_FALSE
;
6305 boolean_t wildcard_fmri
= B_FALSE
;
6308 if (flags
& SCF_WALK_EXPLICIT
)
6309 assert(flags
& SCF_WALK_SERVICE
);
6310 if (flags
& SCF_WALK_NOINSTANCE
)
6311 assert(flags
& SCF_WALK_SERVICE
);
6312 if (flags
& SCF_WALK_PROPERTY
)
6313 assert(!(flags
& SCF_WALK_LEGACY
));
6317 * Setup initial variables
6319 max_fmri_length
= scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH
);
6320 assert(max_fmri_length
!= -1);
6321 max_name_length
= scf_limit(SCF_LIMIT_MAX_NAME_LENGTH
);
6322 assert(max_name_length
!= -1);
6324 if ((fmri
= malloc(max_fmri_length
+ 1)) == NULL
||
6325 (pgname
= malloc(max_name_length
+ 1)) == NULL
) {
6326 ret
= SCF_ERROR_NO_MEMORY
;
6332 } else if ((pattern
= calloc(argc
, sizeof (scf_pattern_t
)))
6334 ret
= SCF_ERROR_NO_MEMORY
;
6338 if ((htable
= calloc(WALK_HTABLE_SIZE
, sizeof (void *))) == NULL
) {
6339 ret
= SCF_ERROR_NO_MEMORY
;
6343 if ((inst
= scf_instance_create(h
)) == NULL
||
6344 (svc
= scf_service_create(h
)) == NULL
||
6345 (iter
= scf_iter_create(h
)) == NULL
||
6346 (sciter
= scf_iter_create(h
)) == NULL
||
6347 (siter
= scf_iter_create(h
)) == NULL
||
6348 (scope
= scf_scope_create(h
)) == NULL
||
6349 (pg
= scf_pg_create(h
)) == NULL
||
6350 (prop
= scf_property_create(h
)) == NULL
||
6351 (value
= scf_value_create(h
)) == NULL
) {
6357 * For each fmri given, we first check to see if it's a full service,
6358 * instance, property group, or property FMRI. This avoids having to do
6359 * the (rather expensive) walk of all instances. Any element which does
6360 * not match a full fmri is identified as a globbed pattern or a partial
6361 * fmri and stored in a private array when walking instances.
6363 for (i
= 0; i
< argc
; i
++) {
6364 const char *scope_name
, *svc_name
, *inst_name
, *pg_name
;
6365 const char *prop_name
;
6367 if (strlen(argv
[i
]) > max_fmri_length
) {
6368 errfunc(scf_get_msg(SCF_MSG_ARGTOOLONG
), argv
[i
]);
6370 *err
= UU_EXIT_FATAL
;
6374 (void) strcpy(fmri
, argv
[i
]);
6375 if (scf_parse_svc_fmri(fmri
, &scope_name
, &svc_name
, &inst_name
,
6376 &pg_name
, &prop_name
) != SCF_SUCCESS
)
6380 * If the user has specified SCF_WALK_PROPERTY, allow property
6381 * groups and properties.
6383 if (pg_name
!= NULL
|| prop_name
!= NULL
) {
6384 if (!(flags
& SCF_WALK_PROPERTY
))
6387 if (scf_handle_decode_fmri(h
, argv
[i
], NULL
, NULL
,
6388 NULL
, pg
, prop
, 0) != 0)
6391 if (scf_pg_get_name(pg
, NULL
, 0) < 0 &&
6392 scf_property_get_name(prop
, NULL
, 0) < 0)
6395 if (scf_canonify_fmri(argv
[i
], fmri
, max_fmri_length
)
6398 * scf_parse_fmri() should have caught this.
6403 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6404 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6407 if ((pattern
[i
].sp_arg
= strdup(argv
[i
])) == NULL
) {
6408 ret
= SCF_ERROR_NO_MEMORY
;
6411 pattern
[i
].sp_type
= PATTERN_EXACT
;
6415 * We need at least a service name
6417 if (scope_name
== NULL
|| svc_name
== NULL
)
6421 * If we have a fully qualified instance, add it to our list of
6424 if (inst_name
!= NULL
) {
6425 if (flags
& SCF_WALK_NOINSTANCE
)
6428 if (scf_handle_decode_fmri(h
, argv
[i
], NULL
, NULL
,
6429 inst
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != 0)
6432 if (scf_canonify_fmri(argv
[i
], fmri
, max_fmri_length
)
6436 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6437 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6440 if ((pattern
[i
].sp_arg
= strdup(argv
[i
])) == NULL
) {
6441 ret
= SCF_ERROR_NO_MEMORY
;
6444 pattern
[i
].sp_type
= PATTERN_EXACT
;
6449 if (scf_handle_decode_fmri(h
, argv
[i
], NULL
, svc
,
6450 NULL
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) !=
6455 * If the user allows for bare services, then simply
6456 * pass this service on.
6458 if (flags
& SCF_WALK_SERVICE
) {
6459 if (scf_service_to_fmri(svc
, fmri
,
6460 max_fmri_length
+ 1) <= 0) {
6465 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6466 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6469 if ((pattern
[i
].sp_arg
= strdup(argv
[i
]))
6471 ret
= SCF_ERROR_NO_MEMORY
;
6474 pattern
[i
].sp_type
= PATTERN_EXACT
;
6478 if (flags
& SCF_WALK_NOINSTANCE
)
6482 * Otherwise, iterate over all instances in the service.
6484 if (scf_iter_service_instances(iter
, svc
) !=
6491 ret
= scf_iter_next_instance(iter
, inst
);
6499 if (scf_instance_to_fmri(inst
, fmri
,
6500 max_fmri_length
+ 1) == -1)
6503 if ((ret
= scf_add_match(htable
, fmri
, NULL
,
6504 &pattern
[i
], flags
& SCF_WALK_EXPLICIT
)) != 0)
6508 if ((pattern
[i
].sp_arg
= strdup(argv
[i
])) == NULL
) {
6509 ret
= SCF_ERROR_NO_MEMORY
;
6512 pattern
[i
].sp_type
= PATTERN_EXACT
;
6513 partial_fmri
= B_TRUE
; /* we just iterated all instances */
6520 * If we got here because of a fatal error, bail out
6523 if (scf_error() == SCF_ERROR_CONNECTION_BROKEN
) {
6529 * At this point we failed to interpret the argument as a
6530 * complete fmri, so mark it as a partial or globbed FMRI for
6533 if (strpbrk(argv
[i
], "*?[") != NULL
) {
6535 * Prepend svc:/ to patterns which don't begin with * or
6538 wildcard_fmri
= B_TRUE
;
6539 pattern
[i
].sp_type
= PATTERN_GLOB
;
6540 if (argv
[i
][0] == '*' ||
6541 (strlen(argv
[i
]) >= 4 && argv
[i
][3] == ':'))
6542 pattern
[i
].sp_arg
= strdup(argv
[i
]);
6544 pattern
[i
].sp_arg
= malloc(strlen(argv
[i
]) + 6);
6545 if (pattern
[i
].sp_arg
!= NULL
)
6546 (void) snprintf(pattern
[i
].sp_arg
,
6547 strlen(argv
[i
]) + 6, "svc:/%s",
6551 partial_fmri
= B_TRUE
;
6552 pattern
[i
].sp_type
= PATTERN_PARTIAL
;
6553 pattern
[i
].sp_arg
= strdup(argv
[i
]);
6556 if (pattern
[i
].sp_arg
== NULL
) {
6557 ret
= SCF_ERROR_NO_MEMORY
;
6562 if (pattern_search
|| argc
== 0) {
6564 * We have a set of patterns to search for. Iterate over all
6565 * instances and legacy services searching for matches.
6567 if (scf_handle_get_local_scope(h
, scope
) != 0) {
6572 if (scf_iter_scope_services(sciter
, scope
) != 0) {
6578 ret
= scf_iter_next_service(sciter
, svc
);
6586 if (flags
& SCF_WALK_SERVICE
) {
6588 * If the user is requesting bare services, try
6589 * to match the service first.
6591 if (scf_service_to_fmri(svc
, fmri
,
6592 max_fmri_length
+ 1) < 0) {
6604 if ((ret
= callback(data
, &info
)) != 0)
6607 } else if ((ret
= scf_pattern_match(htable
,
6608 fmri
, NULL
, argc
, pattern
,
6609 flags
& SCF_WALK_EXPLICIT
)) != 0) {
6614 if (flags
& SCF_WALK_NOINSTANCE
)
6618 * Iterate over all instances in the service.
6620 if (scf_iter_service_instances(siter
, svc
) != 0) {
6621 if (scf_error() != SCF_ERROR_DELETED
) {
6629 ret
= scf_iter_next_instance(siter
, inst
);
6633 if (scf_error() != SCF_ERROR_DELETED
) {
6640 if (scf_instance_to_fmri(inst
, fmri
,
6641 max_fmri_length
+ 1) < 0) {
6647 * Without arguments, execute the callback
6657 if ((ret
= callback(data
, &info
)) != 0)
6659 } else if ((ret
= scf_pattern_match(htable
,
6660 fmri
, NULL
, argc
, pattern
,
6661 flags
& SCF_WALK_EXPLICIT
)) != 0) {
6668 * Search legacy services
6670 if ((flags
& SCF_WALK_LEGACY
)) {
6671 if (scf_scope_get_service(scope
, SCF_LEGACY_SERVICE
,
6673 if (scf_error() != SCF_ERROR_NOT_FOUND
) {
6681 if (scf_iter_service_pgs_typed(iter
, svc
,
6682 SCF_GROUP_FRAMEWORK
) != SCF_SUCCESS
) {
6687 (void) strcpy(fmri
, LEGACY_SCHEME
);
6690 ret
= scf_iter_next_pg(iter
, pg
);
6698 if (scf_pg_get_property(pg
,
6699 SCF_LEGACY_PROPERTY_NAME
, prop
) == -1) {
6701 if (ret
== SCF_ERROR_DELETED
||
6702 ret
== SCF_ERROR_NOT_FOUND
) {
6709 if (scf_property_is_type(prop
, SCF_TYPE_ASTRING
)
6711 if (scf_error() == SCF_ERROR_DELETED
)
6717 if (scf_property_get_value(prop
, value
) !=
6721 if (scf_value_get_astring(value
,
6722 fmri
+ sizeof (LEGACY_SCHEME
) - 1,
6723 max_fmri_length
+ 2 -
6724 sizeof (LEGACY_SCHEME
)) <= 0)
6727 if (scf_pg_get_name(pg
, pgname
,
6728 max_name_length
+ 1) <= 0) {
6729 if (scf_error() == SCF_ERROR_DELETED
)
6742 if ((ret
= callback(data
, &info
)) != 0)
6744 } else if ((ret
= scf_pattern_match(htable
,
6745 fmri
, pgname
, argc
, pattern
,
6746 flags
& SCF_WALK_EXPLICIT
)) != 0)
6759 * Check all patterns, and see if we have that any that didn't match
6760 * or any that matched multiple instances. For svcprop, add up the
6761 * total number of matching keys.
6764 for (i
= 0; i
< argc
; i
++) {
6767 if (pattern
[i
].sp_type
== PATTERN_INVALID
)
6769 if (pattern
[i
].sp_matchcount
== 0) {
6772 * Provide a useful error message based on the argument
6773 * and the type of entity requested.
6775 if (!(flags
& SCF_WALK_LEGACY
) &&
6776 strncmp(pattern
[i
].sp_arg
, "lrc:/", 5) == 0)
6777 msgid
= SCF_MSG_PATTERN_LEGACY
;
6778 else if (flags
& SCF_WALK_PROPERTY
)
6779 msgid
= SCF_MSG_PATTERN_NOENTITY
;
6780 else if (flags
& SCF_WALK_NOINSTANCE
)
6781 msgid
= SCF_MSG_PATTERN_NOSERVICE
;
6782 else if (flags
& SCF_WALK_SERVICE
)
6783 msgid
= SCF_MSG_PATTERN_NOINSTSVC
;
6785 msgid
= SCF_MSG_PATTERN_NOINSTANCE
;
6787 errfunc(scf_get_msg(msgid
), pattern
[i
].sp_arg
);
6789 *err
= UU_EXIT_FATAL
;
6790 } else if (!(flags
& SCF_WALK_MULTIPLE
) &&
6791 pattern
[i
].sp_matchcount
> 1) {
6796 * Construct a message with all possible FMRIs before
6797 * passing off to error handling function.
6799 * Note that strlen(scf_get_msg(...)) includes the
6800 * length of '%s', which accounts for the terminating
6803 len
= strlen(scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH
)) +
6804 strlen(pattern
[i
].sp_arg
);
6805 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6806 match
= match
->sm_next
) {
6807 len
+= strlen(match
->sm_key
->sk_fmri
) + 2;
6809 if ((msg
= malloc(len
)) == NULL
) {
6810 ret
= SCF_ERROR_NO_MEMORY
;
6814 /* LINTED - format argument */
6815 (void) snprintf(msg
, len
,
6816 scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH
),
6819 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6820 match
= match
->sm_next
) {
6821 off
+= snprintf(msg
+ off
, len
- off
, "\t%s\n",
6822 match
->sm_key
->sk_fmri
);
6827 *err
= UU_EXIT_FATAL
;
6831 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6832 match
= match
->sm_next
) {
6833 if (!match
->sm_key
->sk_seen
)
6835 match
->sm_key
->sk_seen
= 1;
6840 if (flags
& SCF_WALK_UNIPARTIAL
&& info
.count
> 1) {
6842 * If the SCF_WALK_UNIPARTIAL flag was passed in and we have
6843 * more than one fmri, then this is an error if we matched
6844 * because of a partial fmri parameter, unless we also matched
6845 * more than one fmri because of wildcards in the parameters.
6846 * That is, the presence of wildcards indicates that it is ok
6847 * to match more than one fmri in this case.
6848 * For example, a parameter of 'foo' that matches more than
6849 * one fmri is an error, but parameters of 'foo *bar*' that
6850 * matches more than one is fine.
6852 if (partial_fmri
&& !wildcard_fmri
) {
6853 errfunc(scf_get_msg(SCF_MSG_PATTERN_MULTIPARTIAL
));
6855 *err
= UU_EXIT_FATAL
;
6861 * Clear 'sk_seen' for all keys.
6863 for (i
= 0; i
< WALK_HTABLE_SIZE
; i
++) {
6864 scf_matchkey_t
*key
;
6865 for (key
= htable
[i
]; key
!= NULL
; key
= key
->sk_next
)
6870 * Iterate over all the FMRIs in our hash table and execute the
6873 for (i
= 0; i
< argc
; i
++) {
6875 scf_matchkey_t
*key
;
6878 * Ignore patterns which didn't match anything or matched too
6881 if (pattern
[i
].sp_matchcount
== 0 ||
6882 (!(flags
& SCF_WALK_MULTIPLE
) &&
6883 pattern
[i
].sp_matchcount
> 1))
6886 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6887 match
= match
->sm_next
) {
6889 key
= match
->sm_key
;
6895 if (key
->sk_legacy
!= NULL
) {
6896 if (scf_scope_get_service(scope
,
6897 "smf/legacy_run", svc
) != 0) {
6902 if (scf_service_get_pg(svc
, key
->sk_legacy
,
6906 info
.fmri
= key
->sk_fmri
;
6912 if ((ret
= callback(data
, &info
)) != 0)
6915 if (scf_handle_decode_fmri(h
, key
->sk_fmri
,
6916 scope
, svc
, inst
, pg
, prop
, 0) !=
6920 info
.fmri
= key
->sk_fmri
;
6923 if (scf_instance_get_name(inst
, NULL
, 0) < 0) {
6925 SCF_ERROR_CONNECTION_BROKEN
) {
6933 if (scf_pg_get_name(pg
, NULL
, 0) < 0) {
6935 SCF_ERROR_CONNECTION_BROKEN
) {
6943 if (scf_property_get_name(prop
, NULL
, 0) < 0) {
6945 SCF_ERROR_CONNECTION_BROKEN
) {
6954 if ((ret
= callback(data
, &info
)) != 0)
6962 scf_matchkey_t
*key
, *next
;
6964 for (i
= 0; i
< WALK_HTABLE_SIZE
; i
++) {
6966 for (key
= htable
[i
]; key
!= NULL
;
6969 next
= key
->sk_next
;
6971 if (key
->sk_fmri
!= NULL
)
6973 if (key
->sk_legacy
!= NULL
)
6974 free(key
->sk_legacy
);
6980 if (pattern
!= NULL
) {
6981 for (i
= 0; i
< argc
; i
++) {
6982 scf_match_t
*match
, *next
;
6984 if (pattern
[i
].sp_arg
!= NULL
)
6985 free(pattern
[i
].sp_arg
);
6987 for (match
= pattern
[i
].sp_matches
; match
!= NULL
;
6990 next
= match
->sm_next
;
7001 scf_value_destroy(value
);
7002 scf_property_destroy(prop
);
7004 scf_scope_destroy(scope
);
7005 scf_iter_destroy(siter
);
7006 scf_iter_destroy(sciter
);
7007 scf_iter_destroy(iter
);
7008 scf_instance_destroy(inst
);
7009 scf_service_destroy(svc
);
7015 * scf_encode32() is an implementation of Base32 encoding as described in
7016 * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
7017 * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648. The
7018 * input stream is divided into groups of 5 characters (40 bits). Each
7019 * group is encoded into 8 output characters where each output character
7020 * represents 5 bits of input.
7022 * If the input is not an even multiple of 5 characters, the output will be
7023 * padded so that the output is an even multiple of 8 characters. The
7024 * standard specifies that the pad character is '='. Unfortunately, '=' is
7025 * not a legal character in SMF property names. Thus, the caller can
7026 * specify an alternate pad character with the pad argument. If pad is 0,
7027 * scf_encode32() will use '='. Note that use of anything other than '='
7028 * produces output that is not in conformance with RFC 4648. It is
7029 * suitable, however, for internal use of SMF software. When the encoded
7030 * data is used as part of an SMF property name, SCF_ENCODE32_PAD should be
7031 * used as the pad character.
7034 * input - Address of the buffer to be encoded.
7035 * inlen - Number of characters at input.
7036 * output - Address of the buffer to receive the encoded data.
7037 * outmax - Size of the buffer at output.
7038 * outlen - If it is not NULL, outlen receives the number of
7039 * bytes placed in output.
7040 * pad - Alternate padding character.
7043 * 0 Buffer was successfully encoded.
7044 * -1 Indicates output buffer too small, or pad is one of the
7045 * standard encoding characters.
7048 scf_encode32(const char *input
, size_t inlen
, char *output
, size_t outmax
,
7049 size_t *outlen
, char pad
)
7051 uint_t group_size
= 5;
7053 const unsigned char *in
= (const unsigned char *)input
;
7055 uchar_t
*out
= (uchar_t
*)output
;
7059 /* Verify that there is enough room for the output. */
7060 olen
= ((inlen
+ (group_size
- 1)) / group_size
) * 8;
7066 /* If caller did not provide pad character, use the default. */
7071 * Make sure that caller's pad is not one of the encoding
7074 for (i
= 0; i
< sizeof (base32
) - 1; i
++) {
7075 if (pad
== base32
[i
])
7080 /* Process full groups capturing 5 bits per output character. */
7081 for (; inlen
>= group_size
; in
+= group_size
, inlen
-= group_size
) {
7083 * The comments in this section number the bits in an
7084 * 8 bit byte 0 to 7. The high order bit is bit 7 and
7085 * the low order bit is bit 0.
7088 /* top 5 bits (7-3) from in[0] */
7089 *out
++ = base32
[in
[0] >> 3];
7090 /* bits 2-0 from in[0] and top 2 (7-6) from in[1] */
7091 *out
++ = base32
[((in
[0] << 2) & 0x1c) | (in
[1] >> 6)];
7092 /* 5 bits (5-1) from in[1] */
7093 *out
++ = base32
[(in
[1] >> 1) & 0x1f];
7094 /* low bit (0) from in[1] and top 4 (7-4) from in[2] */
7095 *out
++ = base32
[((in
[1] << 4) & 0x10) | ((in
[2] >> 4) & 0xf)];
7096 /* low 4 (3-0) from in[2] and top bit (7) from in[3] */
7097 *out
++ = base32
[((in
[2] << 1) & 0x1e) | (in
[3] >> 7)];
7098 /* 5 bits (6-2) from in[3] */
7099 *out
++ = base32
[(in
[3] >> 2) & 0x1f];
7100 /* low 2 (1-0) from in[3] and top 3 (7-5) from in[4] */
7101 *out
++ = base32
[((in
[3] << 3) & 0x18) | (in
[4] >> 5)];
7102 /* low 5 (4-0) from in[4] */
7103 *out
++ = base32
[in
[4] & 0x1f];
7106 /* Take care of final input bytes. */
7109 /* top 5 bits (7-3) from in[0] */
7110 *out
++ = base32
[in
[0] >> 3];
7112 * low 3 (2-0) from in[0] and top 2 (7-6) from in[1] if
7115 oval
= (in
[0] << 2) & 0x1c;
7117 *out
++ = base32
[oval
];
7122 *out
++ = base32
[oval
];
7123 /* 5 bits (5-1) from in[1] */
7124 *out
++ = base32
[(in
[1] >> 1) & 0x1f];
7126 * low bit (0) from in[1] and top 4 (7-4) from in[2] if
7129 oval
= (in
[1] << 4) & 0x10;
7131 *out
++ = base32
[oval
];
7136 *out
++ = base32
[oval
];
7138 * low 4 (3-0) from in[2] and top 1 (7) from in[3] if
7141 oval
= (in
[2] << 1) & 0x1e;
7143 *out
++ = base32
[oval
];
7148 *out
++ = base32
[oval
];
7149 /* 5 bits (6-2) from in[3] */
7150 *out
++ = base32
[(in
[3] >> 2) & 0x1f];
7151 /* low 2 bits (1-0) from in[3] */
7152 *out
++ = base32
[(in
[3] << 3) & 0x18];
7157 * Pad the output so that it is a multiple of 8 bytes.
7159 for (; pad_count
> 0; pad_count
--) {
7164 * Null terminate the output if there is enough room.
7173 * scf_decode32() is an implementation of Base32 decoding as described in
7174 * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
7175 * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648. The
7176 * input stream is divided into groups of 8 encoded characters. Each
7177 * encoded character represents 5 bits of data. Thus, the 8 encoded
7178 * characters are used to produce 40 bits or 5 bytes of unencoded data in
7181 * If the encoder did not have enough data to generate a mulitple of 8
7182 * characters of encoded data, it used a pad character to get to the 8
7183 * character boundry. The standard specifies that the pad character is '='.
7184 * Unfortunately, '=' is not a legal character in SMF property names.
7185 * Thus, the caller can specify an alternate pad character with the pad
7186 * argument. If pad is 0, scf_decode32() will use '='. Note that use of
7187 * anything other than '=' is not in conformance with RFC 4648. It is
7188 * suitable, however, for internal use of SMF software. When the encoded
7189 * data is used in SMF property names, SCF_ENCODE32_PAD should be used as
7190 * the pad character.
7193 * in - Buffer of encoded characters.
7194 * inlen - Number of characters at in.
7195 * outbuf - Buffer to receive the decoded bytes. It can be the
7196 * same buffer as in.
7197 * outmax - Size of the buffer at outbuf.
7198 * outlen - If it is not NULL, outlen receives the number of
7199 * bytes placed in output.
7200 * pad - Alternate padding character.
7203 * 0 Buffer was successfully decoded.
7204 * -1 Indicates an invalid input character, output buffer too
7205 * small, or pad is one of the standard encoding characters.
7208 scf_decode32(const char *in
, size_t inlen
, char *outbuf
, size_t outmax
,
7209 size_t *outlen
, char pad
)
7211 char *bufend
= outbuf
+ outmax
;
7214 uint32_t g
[DECODE32_GS
];
7218 boolean_t pad_seen
= B_FALSE
;
7220 /* If caller did not provide pad character, use the default. */
7225 * Make sure that caller's pad is not one of the encoding
7228 for (i
= 0; i
< sizeof (base32
) - 1; i
++) {
7229 if (pad
== base32
[i
])
7235 while ((i
< inlen
) && (out
< bufend
)) {
7236 /* Get a group of input characters. */
7237 for (j
= 0, count
= 0;
7238 (j
< DECODE32_GS
) && (i
< inlen
);
7242 * RFC 4648 allows for the encoded data to be split
7243 * into multiple lines, so skip carriage returns
7246 if ((c
== '\r') || (c
== '\n'))
7248 if ((pad_seen
== B_TRUE
) && (c
!= pad
)) {
7249 /* Group not completed by pads */
7252 if ((c
< 0) || (c
>= sizeof (index32
))) {
7253 /* Illegal character. */
7260 if ((g
[j
++] = index32
[c
]) == 0xff) {
7261 /* Illegal character */
7267 /* Pack the group into five 8 bit bytes. */
7268 if ((count
>= 2) && (out
< bufend
)) {
7271 * 5 bits (7-3) from g[0]
7272 * 3 bits (2-0) from g[1] (4-2)
7274 *out
++ = (g
[0] << 3) | ((g
[1] >> 2) & 0x7);
7276 if ((count
>= 4) && (out
< bufend
)) {
7279 * 2 bits (7-6) from g[1] (1-0)
7280 * 5 bits (5-1) from g[2] (4-0)
7281 * 1 bit (0) from g[3] (4)
7283 *out
++ = (g
[1] << 6) | (g
[2] << 1) | \
7284 ((g
[3] >> 4) & 0x1);
7286 if ((count
>= 5) && (out
< bufend
)) {
7289 * 4 bits (7-4) from g[3] (3-0)
7290 * 4 bits (3-0) from g[4] (4-1)
7292 *out
++ = (g
[3] << 4) | ((g
[4] >> 1) & 0xf);
7294 if ((count
>= 7) && (out
< bufend
)) {
7297 * 1 bit (7) from g[4] (0)
7298 * 5 bits (6-2) from g[5] (4-0)
7299 * 2 bits (0-1) from g[6] (4-3)
7301 *out
++ = (g
[4] << 7) | (g
[5] << 2) |
7302 ((g
[6] >> 3) & 0x3);
7304 if ((count
== 8) && (out
< bufend
)) {
7307 * 3 bits (7-5) from g[6] (2-0)
7308 * 5 bits (4-0) from g[7] (4-0)
7310 *out
++ = (g
[6] << 5) | g
[7];
7314 /* Did not process all input characters. */
7318 *outlen
= out
- outbuf
;
7319 /* Null terminate the output if there is room. */
7327 * _scf_request_backup: a simple wrapper routine
7330 _scf_request_backup(scf_handle_t
*h
, const char *name
)
7332 struct rep_protocol_backup_request request
;
7333 struct rep_protocol_response response
;
7337 if (strlcpy(request
.rpr_name
, name
, sizeof (request
.rpr_name
)) >=
7338 sizeof (request
.rpr_name
))
7339 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
7341 (void) pthread_mutex_lock(&h
->rh_lock
);
7342 request
.rpr_request
= REP_PROTOCOL_BACKUP
;
7343 request
.rpr_changeid
= handle_next_changeid(h
);
7345 r
= make_door_call(h
, &request
, sizeof (request
),
7346 &response
, sizeof (response
));
7347 (void) pthread_mutex_unlock(&h
->rh_lock
);
7350 DOOR_ERRORS_BLOCK(r
);
7353 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
7354 return (scf_set_error(proto_error(response
.rpr_response
)));
7355 return (SCF_SUCCESS
);
7359 * Request svc.configd daemon to switch repository database.
7363 * _NOT_BOUND handle is not bound
7364 * _CONNECTION_BROKEN server is not reachable
7365 * _INTERNAL file operation error
7366 * the server response is too big
7367 * _PERMISSION_DENIED not enough privileges to do request
7368 * _BACKEND_READONLY backend is not writable
7369 * _BACKEND_ACCESS backend access fails
7370 * _NO_RESOURCES svc.configd is out of memory
7373 _scf_repository_switch(scf_handle_t
*h
, int scf_sw
)
7375 struct rep_protocol_switch_request request
;
7376 struct rep_protocol_response response
;
7380 * Setup request protocol and make door call
7381 * Hold rh_lock lock before handle_next_changeid call
7383 (void) pthread_mutex_lock(&h
->rh_lock
);
7385 request
.rpr_flag
= scf_sw
;
7386 request
.rpr_request
= REP_PROTOCOL_SWITCH
;
7387 request
.rpr_changeid
= handle_next_changeid(h
);
7389 r
= make_door_call(h
, &request
, sizeof (request
),
7390 &response
, sizeof (response
));
7392 (void) pthread_mutex_unlock(&h
->rh_lock
);
7395 DOOR_ERRORS_BLOCK(r
);
7399 * Pass protocol error up
7401 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
7402 return (scf_set_error(proto_error(response
.rpr_response
)));
7404 return (SCF_SUCCESS
);
7408 _scf_pg_is_read_protected(const scf_propertygroup_t
*pg
, boolean_t
*out
)
7410 char buf
[REP_PROTOCOL_NAME_LEN
];
7413 res
= datael_get_name(&pg
->rd_d
, buf
, sizeof (buf
),
7414 RP_ENTITY_NAME_PGREADPROT
);
7419 if (uu_strtouint(buf
, out
, sizeof (*out
), 0, 0, 1) == -1)
7420 return (scf_set_error(SCF_ERROR_INTERNAL
));
7421 return (SCF_SUCCESS
);
7425 * _scf_set_annotation: a wrapper to set the annotation fields for SMF
7426 * security auditing.
7428 * Fails with following in scf_error_key thread specific data:
7429 * _INVALID_ARGUMENT - operation or file too large
7431 * _CONNECTION_BROKEN
7436 _scf_set_annotation(scf_handle_t
*h
, const char *operation
, const char *file
)
7438 struct rep_protocol_annotation request
;
7439 struct rep_protocol_response response
;
7444 /* We can't do anything if the handle is destroyed. */
7445 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED
));
7448 request
.rpr_request
= REP_PROTOCOL_SET_AUDIT_ANNOTATION
;
7449 copied
= strlcpy(request
.rpr_operation
,
7450 (operation
== NULL
) ? "" : operation
,
7451 sizeof (request
.rpr_operation
));
7452 if (copied
>= sizeof (request
.rpr_operation
))
7453 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
7455 copied
= strlcpy(request
.rpr_file
,
7456 (file
== NULL
) ? "" : file
,
7457 sizeof (request
.rpr_file
));
7458 if (copied
>= sizeof (request
.rpr_file
))
7459 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT
));
7461 (void) pthread_mutex_lock(&h
->rh_lock
);
7462 r
= make_door_call(h
, &request
, sizeof (request
),
7463 &response
, sizeof (response
));
7464 (void) pthread_mutex_unlock(&h
->rh_lock
);
7467 DOOR_ERRORS_BLOCK(r
);
7470 if (response
.rpr_response
!= REP_PROTOCOL_SUCCESS
)
7471 return (scf_set_error(proto_error(response
.rpr_response
)));