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.
27 * This is the client layer for svc.configd. All direct protocol interactions
30 * Essentially, the job of this layer is to turn the idempotent protocol
31 * into a series of non-idempotent calls into the object layer, while
32 * also handling the necessary locking.
37 #include <bsm/adt_event.h>
53 #include "repcache_protocol.h"
55 #define INVALID_CHANGEID (0)
56 #define INVALID_DOORID ((door_id_t)-1)
57 #define INVALID_RESULT ((rep_protocol_responseid_t)INT_MIN)
60 * lint doesn't like constant assertions
63 #define assert_nolint(x) (void)0
65 #define assert_nolint(x) assert(x)
69 * Protects client linkage and the freelist
71 #define CLIENT_HASH_SIZE 64
73 #pragma align 64(client_hash)
74 static client_bucket_t client_hash
[CLIENT_HASH_SIZE
];
76 static uu_avl_pool_t
*entity_pool
;
77 static uu_avl_pool_t
*iter_pool
;
78 static uu_list_pool_t
*client_pool
;
80 #define CLIENT_HASH(id) (&client_hash[((id) & (CLIENT_HASH_SIZE - 1))])
82 uint_t request_log_size
= 1024; /* tunable, before we start */
84 static pthread_mutex_t request_log_lock
= PTHREAD_MUTEX_INITIALIZER
;
85 static uint_t request_log_cur
;
86 request_log_entry_t
*request_log
;
88 static uint32_t client_maxid
;
89 static pthread_mutex_t client_lock
; /* protects client_maxid */
91 static request_log_entry_t
*
94 thread_info_t
*ti
= thread_self();
99 log_enter(request_log_entry_t
*rlp
)
101 if (rlp
->rl_start
!= 0 && request_log
!= NULL
) {
102 request_log_entry_t
*logrlp
;
104 (void) pthread_mutex_lock(&request_log_lock
);
105 assert(request_log_cur
< request_log_size
);
106 logrlp
= &request_log
[request_log_cur
++];
107 if (request_log_cur
== request_log_size
)
109 (void) memcpy(logrlp
, rlp
, sizeof (*rlp
));
110 (void) pthread_mutex_unlock(&request_log_lock
);
115 * Note that the svc.configd dmod will join all of the per-thread log entries
116 * with the main log, so that even if the log is disabled, there is some
117 * information available.
119 static request_log_entry_t
*
120 start_log(uint32_t clientid
)
122 request_log_entry_t
*rlp
= get_log();
126 (void) memset(rlp
, 0, sizeof (*rlp
));
127 rlp
->rl_start
= gethrtime();
128 rlp
->rl_tid
= pthread_self();
129 rlp
->rl_clientid
= clientid
;
137 request_log_entry_t
*rlp
= get_log();
139 rlp
->rl_end
= gethrtime();
143 add_log_ptr(request_log_entry_t
*rlp
, enum rc_ptr_type type
, uint32_t id
,
146 request_log_ptr_t
*rpp
;
151 if (rlp
->rl_num_ptrs
>= MAX_PTRS
)
154 rpp
= &rlp
->rl_ptrs
[rlp
->rl_num_ptrs
++];
155 rpp
->rlp_type
= type
;
160 * For entities, it's useful to have the node pointer at the start
163 if (type
== RC_PTR_TYPE_ENTITY
&& ptr
!= NULL
)
164 rpp
->rlp_data
= ((repcache_entity_t
*)ptr
)->re_node
.rnp_node
;
168 client_is_privileged(void)
170 thread_info_t
*ti
= thread_self();
174 if (ti
->ti_active_client
!= NULL
&&
175 ti
->ti_active_client
->rc_all_auths
)
178 if ((uc
= get_ucred()) == NULL
)
181 return (ucred_is_privileged(uc
));
186 client_compare(const void *lc_arg
, const void *rc_arg
, void *private)
188 uint32_t l_id
= ((const repcache_client_t
*)lc_arg
)->rc_id
;
189 uint32_t r_id
= ((const repcache_client_t
*)rc_arg
)->rc_id
;
200 entity_compare(const void *lc_arg
, const void *rc_arg
, void *private)
202 uint32_t l_id
= ((const repcache_entity_t
*)lc_arg
)->re_id
;
203 uint32_t r_id
= ((const repcache_entity_t
*)rc_arg
)->re_id
;
214 iter_compare(const void *lc_arg
, const void *rc_arg
, void *private)
216 uint32_t l_id
= ((const repcache_iter_t
*)lc_arg
)->ri_id
;
217 uint32_t r_id
= ((const repcache_iter_t
*)rc_arg
)->ri_id
;
227 client_hash_init(void)
231 assert_nolint(offsetof(repcache_entity_t
, re_id
) == 0);
232 entity_pool
= uu_avl_pool_create("repcache_entitys",
233 sizeof (repcache_entity_t
), offsetof(repcache_entity_t
, re_link
),
234 entity_compare
, UU_AVL_POOL_DEBUG
);
236 assert_nolint(offsetof(repcache_iter_t
, ri_id
) == 0);
237 iter_pool
= uu_avl_pool_create("repcache_iters",
238 sizeof (repcache_iter_t
), offsetof(repcache_iter_t
, ri_link
),
239 iter_compare
, UU_AVL_POOL_DEBUG
);
241 assert_nolint(offsetof(repcache_client_t
, rc_id
) == 0);
242 client_pool
= uu_list_pool_create("repcache_clients",
243 sizeof (repcache_client_t
), offsetof(repcache_client_t
, rc_link
),
244 client_compare
, UU_LIST_POOL_DEBUG
);
246 if (entity_pool
== NULL
|| iter_pool
== NULL
|| client_pool
== NULL
)
249 for (x
= 0; x
< CLIENT_HASH_SIZE
; x
++) {
250 uu_list_t
*lp
= uu_list_create(client_pool
, &client_hash
[x
],
255 (void) pthread_mutex_init(&client_hash
[x
].cb_lock
, NULL
);
256 client_hash
[x
].cb_list
= lp
;
262 static repcache_client_t
*
265 repcache_client_t
*cp
;
266 cp
= uu_zalloc(sizeof (*cp
));
270 cp
->rc_entities
= uu_avl_create(entity_pool
, cp
, 0);
271 if (cp
->rc_entities
== NULL
)
274 cp
->rc_iters
= uu_avl_create(iter_pool
, cp
, 0);
275 if (cp
->rc_iters
== NULL
)
278 uu_list_node_init(cp
, &cp
->rc_link
, client_pool
);
281 cp
->rc_doorid
= INVALID_DOORID
;
283 (void) pthread_mutex_init(&cp
->rc_lock
, NULL
);
284 (void) pthread_mutex_init(&cp
->rc_annotate_lock
, NULL
);
286 rc_node_ptr_init(&cp
->rc_notify_ptr
);
291 if (cp
->rc_iters
!= NULL
)
292 uu_avl_destroy(cp
->rc_iters
);
293 if (cp
->rc_entities
!= NULL
)
294 uu_avl_destroy(cp
->rc_entities
);
300 client_free(repcache_client_t
*cp
)
302 assert(cp
->rc_insert_thr
== 0);
303 assert(cp
->rc_refcnt
== 0);
304 assert(cp
->rc_doorfd
== -1);
305 assert(cp
->rc_doorid
== INVALID_DOORID
);
306 assert(uu_avl_first(cp
->rc_entities
) == NULL
);
307 assert(uu_avl_first(cp
->rc_iters
) == NULL
);
308 uu_avl_destroy(cp
->rc_entities
);
309 uu_avl_destroy(cp
->rc_iters
);
310 uu_list_node_fini(cp
, &cp
->rc_link
, client_pool
);
311 (void) pthread_mutex_destroy(&cp
->rc_lock
);
312 (void) pthread_mutex_destroy(&cp
->rc_annotate_lock
);
313 rc_node_ptr_free_mem(&cp
->rc_notify_ptr
);
318 client_insert(repcache_client_t
*cp
)
320 client_bucket_t
*bp
= CLIENT_HASH(cp
->rc_id
);
323 assert(cp
->rc_id
> 0);
325 (void) pthread_mutex_lock(&bp
->cb_lock
);
327 * We assume it does not already exist
329 (void) uu_list_find(bp
->cb_list
, cp
, NULL
, &idx
);
330 uu_list_insert(bp
->cb_list
, cp
, idx
);
332 (void) pthread_mutex_unlock(&bp
->cb_lock
);
335 static repcache_client_t
*
336 client_lookup(uint32_t id
)
338 client_bucket_t
*bp
= CLIENT_HASH(id
);
339 repcache_client_t
*cp
;
341 (void) pthread_mutex_lock(&bp
->cb_lock
);
343 cp
= uu_list_find(bp
->cb_list
, &id
, NULL
, NULL
);
346 * Bump the reference count
349 (void) pthread_mutex_lock(&cp
->rc_lock
);
350 assert(!(cp
->rc_flags
& RC_CLIENT_DEAD
));
352 (void) pthread_mutex_unlock(&cp
->rc_lock
);
354 (void) pthread_mutex_unlock(&bp
->cb_lock
);
360 client_release(repcache_client_t
*cp
)
362 (void) pthread_mutex_lock(&cp
->rc_lock
);
363 assert(cp
->rc_refcnt
> 0);
364 assert(cp
->rc_insert_thr
!= pthread_self());
367 (void) pthread_cond_broadcast(&cp
->rc_cv
);
368 (void) pthread_mutex_unlock(&cp
->rc_lock
);
372 * We only allow one thread to be inserting at a time, to prevent
373 * insert/insert races.
376 client_start_insert(repcache_client_t
*cp
)
378 (void) pthread_mutex_lock(&cp
->rc_lock
);
379 assert(cp
->rc_refcnt
> 0);
381 while (cp
->rc_insert_thr
!= 0) {
382 assert(cp
->rc_insert_thr
!= pthread_self());
383 (void) pthread_cond_wait(&cp
->rc_cv
, &cp
->rc_lock
);
385 cp
->rc_insert_thr
= pthread_self();
386 (void) pthread_mutex_unlock(&cp
->rc_lock
);
390 client_end_insert(repcache_client_t
*cp
)
392 (void) pthread_mutex_lock(&cp
->rc_lock
);
393 assert(cp
->rc_insert_thr
== pthread_self());
394 cp
->rc_insert_thr
= 0;
395 (void) pthread_cond_broadcast(&cp
->rc_cv
);
396 (void) pthread_mutex_unlock(&cp
->rc_lock
);
400 static repcache_entity_t
*
401 entity_alloc(repcache_client_t
*cp
)
403 repcache_entity_t
*ep
= uu_zalloc(sizeof (repcache_entity_t
));
405 uu_avl_node_init(ep
, &ep
->re_link
, entity_pool
);
411 entity_add(repcache_client_t
*cp
, repcache_entity_t
*ep
)
415 (void) pthread_mutex_lock(&cp
->rc_lock
);
416 assert(cp
->rc_insert_thr
== pthread_self());
418 (void) uu_avl_find(cp
->rc_entities
, ep
, NULL
, &idx
);
419 uu_avl_insert(cp
->rc_entities
, ep
, idx
);
421 (void) pthread_mutex_unlock(&cp
->rc_lock
);
424 static repcache_entity_t
*
425 entity_find(repcache_client_t
*cp
, uint32_t id
)
427 repcache_entity_t
*ep
;
429 (void) pthread_mutex_lock(&cp
->rc_lock
);
430 ep
= uu_avl_find(cp
->rc_entities
, &id
, NULL
, NULL
);
432 add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY
, id
, ep
);
433 (void) pthread_mutex_lock(&ep
->re_lock
);
435 (void) pthread_mutex_unlock(&cp
->rc_lock
);
442 * _DUPLICATE_ID - the ids are equal
443 * _UNKNOWN_ID - an id does not designate an active register
446 entity_find2(repcache_client_t
*cp
, uint32_t id1
, repcache_entity_t
**out1
,
447 uint32_t id2
, repcache_entity_t
**out2
)
449 repcache_entity_t
*e1
, *e2
;
450 request_log_entry_t
*rlp
;
453 return (REP_PROTOCOL_FAIL_DUPLICATE_ID
);
455 (void) pthread_mutex_lock(&cp
->rc_lock
);
456 e1
= uu_avl_find(cp
->rc_entities
, &id1
, NULL
, NULL
);
457 e2
= uu_avl_find(cp
->rc_entities
, &id2
, NULL
, NULL
);
458 if (e1
== NULL
|| e2
== NULL
) {
459 (void) pthread_mutex_unlock(&cp
->rc_lock
);
460 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
466 * locks are ordered by id number
469 (void) pthread_mutex_lock(&e1
->re_lock
);
470 (void) pthread_mutex_lock(&e2
->re_lock
);
472 (void) pthread_mutex_lock(&e2
->re_lock
);
473 (void) pthread_mutex_lock(&e1
->re_lock
);
478 (void) pthread_mutex_unlock(&cp
->rc_lock
);
480 if ((rlp
= get_log()) != NULL
) {
481 add_log_ptr(rlp
, RC_PTR_TYPE_ENTITY
, id1
, e1
);
482 add_log_ptr(rlp
, RC_PTR_TYPE_ENTITY
, id2
, e2
);
485 return (REP_PROTOCOL_SUCCESS
);
489 entity_release(repcache_entity_t
*ep
)
491 assert(ep
->re_node
.rnp_node
== NULL
||
492 !MUTEX_HELD(&ep
->re_node
.rnp_node
->rn_lock
));
493 (void) pthread_mutex_unlock(&ep
->re_lock
);
497 entity_destroy(repcache_entity_t
*entity
)
499 (void) pthread_mutex_lock(&entity
->re_lock
);
500 rc_node_clear(&entity
->re_node
, 0);
501 (void) pthread_mutex_unlock(&entity
->re_lock
);
503 uu_avl_node_fini(entity
, &entity
->re_link
, entity_pool
);
504 (void) pthread_mutex_destroy(&entity
->re_lock
);
505 rc_node_ptr_free_mem(&entity
->re_node
);
510 entity_remove(repcache_client_t
*cp
, uint32_t id
)
512 repcache_entity_t
*entity
;
514 (void) pthread_mutex_lock(&cp
->rc_lock
);
515 entity
= uu_avl_find(cp
->rc_entities
, &id
, NULL
, NULL
);
516 if (entity
!= NULL
) {
517 add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY
, id
, entity
);
519 uu_avl_remove(cp
->rc_entities
, entity
);
521 (void) pthread_mutex_unlock(&cp
->rc_lock
);
524 entity_destroy(entity
);
528 entity_cleanup(repcache_client_t
*cp
)
530 repcache_entity_t
*ep
;
533 (void) pthread_mutex_lock(&cp
->rc_lock
);
534 while ((ep
= uu_avl_teardown(cp
->rc_entities
, &cookie
)) != NULL
) {
535 (void) pthread_mutex_unlock(&cp
->rc_lock
);
537 (void) pthread_mutex_lock(&cp
->rc_lock
);
539 (void) pthread_mutex_unlock(&cp
->rc_lock
);
543 static repcache_iter_t
*
544 iter_alloc(repcache_client_t
*cp
)
546 repcache_iter_t
*iter
;
547 iter
= uu_zalloc(sizeof (repcache_iter_t
));
549 uu_avl_node_init(iter
, &iter
->ri_link
, iter_pool
);
554 iter_add(repcache_client_t
*cp
, repcache_iter_t
*iter
)
558 (void) pthread_mutex_lock(&cp
->rc_lock
);
559 assert(cp
->rc_insert_thr
== pthread_self());
561 (void) uu_avl_find(cp
->rc_iters
, iter
, NULL
, &idx
);
562 uu_avl_insert(cp
->rc_iters
, iter
, idx
);
564 (void) pthread_mutex_unlock(&cp
->rc_lock
);
567 static repcache_iter_t
*
568 iter_find(repcache_client_t
*cp
, uint32_t id
)
570 repcache_iter_t
*iter
;
572 (void) pthread_mutex_lock(&cp
->rc_lock
);
574 iter
= uu_avl_find(cp
->rc_iters
, &id
, NULL
, NULL
);
576 add_log_ptr(get_log(), RC_PTR_TYPE_ITER
, id
, iter
);
577 (void) pthread_mutex_lock(&iter
->ri_lock
);
579 (void) pthread_mutex_unlock(&cp
->rc_lock
);
586 * _UNKNOWN_ID - iter_id or entity_id does not designate an active register
589 iter_find_w_entity(repcache_client_t
*cp
, uint32_t iter_id
,
590 repcache_iter_t
**iterp
, uint32_t entity_id
, repcache_entity_t
**epp
)
592 repcache_iter_t
*iter
;
593 repcache_entity_t
*ep
;
594 request_log_entry_t
*rlp
;
596 (void) pthread_mutex_lock(&cp
->rc_lock
);
597 iter
= uu_avl_find(cp
->rc_iters
, &iter_id
, NULL
, NULL
);
598 ep
= uu_avl_find(cp
->rc_entities
, &entity_id
, NULL
, NULL
);
600 assert(iter
== NULL
|| !MUTEX_HELD(&iter
->ri_lock
));
601 assert(ep
== NULL
|| !MUTEX_HELD(&ep
->re_lock
));
603 if (iter
== NULL
|| ep
== NULL
) {
604 (void) pthread_mutex_unlock(&cp
->rc_lock
);
605 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
608 (void) pthread_mutex_lock(&iter
->ri_lock
);
609 (void) pthread_mutex_lock(&ep
->re_lock
);
611 (void) pthread_mutex_unlock(&cp
->rc_lock
);
616 if ((rlp
= get_log()) != NULL
) {
617 add_log_ptr(rlp
, RC_PTR_TYPE_ENTITY
, entity_id
, ep
);
618 add_log_ptr(rlp
, RC_PTR_TYPE_ITER
, iter_id
, iter
);
621 return (REP_PROTOCOL_SUCCESS
);
625 iter_release(repcache_iter_t
*iter
)
627 (void) pthread_mutex_unlock(&iter
->ri_lock
);
631 iter_destroy(repcache_iter_t
*iter
)
633 (void) pthread_mutex_lock(&iter
->ri_lock
);
634 rc_iter_destroy(&iter
->ri_iter
);
635 (void) pthread_mutex_unlock(&iter
->ri_lock
);
637 uu_avl_node_fini(iter
, &iter
->ri_link
, iter_pool
);
638 (void) pthread_mutex_destroy(&iter
->ri_lock
);
643 iter_remove(repcache_client_t
*cp
, uint32_t id
)
645 repcache_iter_t
*iter
;
647 (void) pthread_mutex_lock(&cp
->rc_lock
);
648 iter
= uu_avl_find(cp
->rc_iters
, &id
, NULL
, NULL
);
650 uu_avl_remove(cp
->rc_iters
, iter
);
651 (void) pthread_mutex_unlock(&cp
->rc_lock
);
658 iter_cleanup(repcache_client_t
*cp
)
660 repcache_iter_t
*iter
;
663 (void) pthread_mutex_lock(&cp
->rc_lock
);
664 while ((iter
= uu_avl_teardown(cp
->rc_iters
, &cookie
)) != NULL
) {
665 (void) pthread_mutex_unlock(&cp
->rc_lock
);
667 (void) pthread_mutex_lock(&cp
->rc_lock
);
669 (void) pthread_mutex_unlock(&cp
->rc_lock
);
673 * Ensure that the passed client id is no longer usable, wait for any
674 * outstanding invocations to complete, then destroy the client
678 client_destroy(uint32_t id
)
680 client_bucket_t
*bp
= CLIENT_HASH(id
);
681 repcache_client_t
*cp
;
683 (void) pthread_mutex_lock(&bp
->cb_lock
);
685 cp
= uu_list_find(bp
->cb_list
, &id
, NULL
, NULL
);
688 (void) pthread_mutex_unlock(&bp
->cb_lock
);
692 uu_list_remove(bp
->cb_list
, cp
);
694 (void) pthread_mutex_unlock(&bp
->cb_lock
);
696 /* kick the waiters out */
697 rc_notify_info_fini(&cp
->rc_notify_info
);
699 (void) pthread_mutex_lock(&cp
->rc_lock
);
700 assert(!(cp
->rc_flags
& RC_CLIENT_DEAD
));
701 cp
->rc_flags
|= RC_CLIENT_DEAD
;
703 if (cp
->rc_doorfd
!= -1) {
704 if (door_revoke(cp
->rc_doorfd
) < 0)
705 perror("door_revoke");
707 cp
->rc_doorid
= INVALID_DOORID
;
710 while (cp
->rc_refcnt
> 0)
711 (void) pthread_cond_wait(&cp
->rc_cv
, &cp
->rc_lock
);
713 assert(cp
->rc_insert_thr
== 0 && cp
->rc_notify_thr
== 0);
714 (void) pthread_mutex_unlock(&cp
->rc_lock
);
717 * destroy outstanding objects
723 * clean up notifications
725 rc_pg_notify_fini(&cp
->rc_pg_notify
);
728 * clean up annotations
730 if (cp
->rc_operation
!= NULL
)
731 free((void *)cp
->rc_operation
);
732 if (cp
->rc_file
!= NULL
)
733 free((void *)cp
->rc_file
);
738 (void) adt_end_session(cp
->rc_adt_session
);
745 * _TYPE_MISMATCH - the entity is already set up with a different type
746 * _NO_RESOURCES - out of memory
749 entity_setup(repcache_client_t
*cp
, struct rep_protocol_entity_setup
*rpr
)
751 repcache_entity_t
*ep
;
754 client_start_insert(cp
);
756 if ((ep
= entity_find(cp
, rpr
->rpr_entityid
)) != NULL
) {
760 client_end_insert(cp
);
762 if (type
!= rpr
->rpr_entitytype
)
763 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
764 return (REP_PROTOCOL_SUCCESS
);
767 switch (type
= rpr
->rpr_entitytype
) {
768 case REP_PROTOCOL_ENTITY_SCOPE
:
769 case REP_PROTOCOL_ENTITY_SERVICE
:
770 case REP_PROTOCOL_ENTITY_INSTANCE
:
771 case REP_PROTOCOL_ENTITY_SNAPSHOT
:
772 case REP_PROTOCOL_ENTITY_SNAPLEVEL
:
773 case REP_PROTOCOL_ENTITY_PROPERTYGRP
:
774 case REP_PROTOCOL_ENTITY_PROPERTY
:
777 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
780 ep
= entity_alloc(cp
);
782 client_end_insert(cp
);
783 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
786 ep
->re_id
= rpr
->rpr_entityid
;
787 ep
->re_changeid
= INVALID_CHANGEID
;
790 rc_node_ptr_init(&ep
->re_node
);
793 client_end_insert(cp
);
794 return (REP_PROTOCOL_SUCCESS
);
799 entity_name(repcache_client_t
*cp
, const void *in
, size_t insz
, void *out_arg
,
800 size_t *outsz
, void *arg
)
802 const struct rep_protocol_entity_name
*rpr
= in
;
803 struct rep_protocol_name_response
*out
= out_arg
;
804 repcache_entity_t
*ep
;
805 size_t sz
= sizeof (out
->rpr_name
);
807 assert(*outsz
== sizeof (*out
));
809 ep
= entity_find(cp
, rpr
->rpr_entityid
);
812 out
->rpr_response
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
813 *outsz
= sizeof (out
->rpr_response
);
816 out
->rpr_response
= rc_node_name(&ep
->re_node
, out
->rpr_name
,
817 sz
, rpr
->rpr_answertype
, &sz
);
821 * If we fail, we only return the response code.
822 * If we succeed, we don't return anything after the '\0' in rpr_name.
824 if (out
->rpr_response
!= REP_PROTOCOL_SUCCESS
)
825 *outsz
= sizeof (out
->rpr_response
);
827 *outsz
= offsetof(struct rep_protocol_name_response
,
833 entity_parent_type(repcache_client_t
*cp
, const void *in
, size_t insz
,
834 void *out_arg
, size_t *outsz
, void *arg
)
836 const struct rep_protocol_entity_name
*rpr
= in
;
837 struct rep_protocol_integer_response
*out
= out_arg
;
838 repcache_entity_t
*ep
;
840 assert(*outsz
== sizeof (*out
));
842 ep
= entity_find(cp
, rpr
->rpr_entityid
);
845 out
->rpr_response
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
846 *outsz
= sizeof (out
->rpr_response
);
850 out
->rpr_response
= rc_node_parent_type(&ep
->re_node
, &out
->rpr_value
);
853 if (out
->rpr_response
!= REP_PROTOCOL_SUCCESS
)
854 *outsz
= sizeof (out
->rpr_response
);
859 * _DUPLICATE_ID - the ids are equal
860 * _UNKNOWN_ID - an id does not designate an active register
861 * _INVALID_TYPE - type is invalid
862 * _TYPE_MISMATCH - np doesn't carry children of type type
863 * _DELETED - np has been deleted
864 * _NOT_FOUND - no child with that name/type combo found
869 entity_get_child(repcache_client_t
*cp
,
870 struct rep_protocol_entity_get_child
*rpr
)
872 repcache_entity_t
*parent
, *child
;
875 uint32_t parentid
= rpr
->rpr_entityid
;
876 uint32_t childid
= rpr
->rpr_childid
;
878 result
= entity_find2(cp
, childid
, &child
, parentid
, &parent
);
879 if (result
!= REP_PROTOCOL_SUCCESS
)
882 rpr
->rpr_name
[sizeof (rpr
->rpr_name
) - 1] = 0;
884 result
= rc_node_get_child(&parent
->re_node
, rpr
->rpr_name
,
885 child
->re_type
, &child
->re_node
);
887 entity_release(child
);
888 entity_release(parent
);
894 * Returns _FAIL_DUPLICATE_ID, _FAIL_UNKNOWN_ID, _FAIL_NOT_SET, _FAIL_DELETED,
895 * _FAIL_TYPE_MISMATCH, _FAIL_NOT_FOUND (scope has no parent), or _SUCCESS.
897 * _DUPLICATE_ID - the ids are equal
898 * _UNKNOWN_ID - an id does not designate an active register
899 * _NOT_SET - child is not set
900 * _DELETED - child has been deleted
901 * _TYPE_MISMATCH - child's parent does not match that of the parent register
902 * _NOT_FOUND - child has no parent (and is a scope)
905 entity_get_parent(repcache_client_t
*cp
, struct rep_protocol_entity_parent
*rpr
)
907 repcache_entity_t
*child
, *parent
;
910 uint32_t childid
= rpr
->rpr_entityid
;
911 uint32_t outid
= rpr
->rpr_outid
;
913 result
= entity_find2(cp
, childid
, &child
, outid
, &parent
);
914 if (result
!= REP_PROTOCOL_SUCCESS
)
917 result
= rc_node_get_parent(&child
->re_node
, parent
->re_type
,
920 entity_release(child
);
921 entity_release(parent
);
927 entity_get(repcache_client_t
*cp
, struct rep_protocol_entity_get
*rpr
)
929 repcache_entity_t
*ep
;
932 ep
= entity_find(cp
, rpr
->rpr_entityid
);
935 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
937 switch (rpr
->rpr_object
) {
938 case RP_ENTITY_GET_INVALIDATE
:
939 rc_node_clear(&ep
->re_node
, 0);
940 result
= REP_PROTOCOL_SUCCESS
;
942 case RP_ENTITY_GET_MOST_LOCAL_SCOPE
:
943 result
= rc_local_scope(ep
->re_type
, &ep
->re_node
);
946 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
956 entity_update(repcache_client_t
*cp
, struct rep_protocol_entity_update
*rpr
)
958 repcache_entity_t
*ep
;
961 if (rpr
->rpr_changeid
== INVALID_CHANGEID
)
962 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
964 ep
= entity_find(cp
, rpr
->rpr_entityid
);
967 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
969 if (ep
->re_changeid
== rpr
->rpr_changeid
) {
970 result
= REP_PROTOCOL_DONE
;
972 result
= rc_node_update(&ep
->re_node
);
973 if (result
== REP_PROTOCOL_DONE
)
974 ep
->re_changeid
= rpr
->rpr_changeid
;
983 entity_reset(repcache_client_t
*cp
, struct rep_protocol_entity_reset
*rpr
)
985 repcache_entity_t
*ep
;
987 ep
= entity_find(cp
, rpr
->rpr_entityid
);
989 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
991 rc_node_clear(&ep
->re_node
, 0);
992 ep
->re_txstate
= REPCACHE_TX_INIT
;
995 return (REP_PROTOCOL_SUCCESS
);
1000 * _BAD_REQUEST - request has invalid changeid
1001 * rpr_name is invalid
1002 * cannot create children for parent's type of node
1003 * _DUPLICATE_ID - request has duplicate ids
1004 * _UNKNOWN_ID - request has unknown id
1005 * _DELETED - parent has been deleted
1006 * _NOT_SET - parent is reset
1007 * _NOT_APPLICABLE - rpr_childtype is _PROPERTYGRP
1008 * _INVALID_TYPE - parent is corrupt or rpr_childtype is invalid
1009 * _TYPE_MISMATCH - parent cannot have children of type rpr_childtype
1011 * _PERMISSION_DENIED
1014 * _EXISTS - child already exists
1017 entity_create_child(repcache_client_t
*cp
,
1018 struct rep_protocol_entity_create_child
*rpr
)
1020 repcache_entity_t
*parent
;
1021 repcache_entity_t
*child
;
1023 uint32_t parentid
= rpr
->rpr_entityid
;
1024 uint32_t childid
= rpr
->rpr_childid
;
1028 if (rpr
->rpr_changeid
== INVALID_CHANGEID
)
1029 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1031 result
= entity_find2(cp
, parentid
, &parent
, childid
, &child
);
1032 if (result
!= REP_PROTOCOL_SUCCESS
)
1035 rpr
->rpr_name
[sizeof (rpr
->rpr_name
) - 1] = 0;
1037 if (child
->re_changeid
== rpr
->rpr_changeid
) {
1038 result
= REP_PROTOCOL_SUCCESS
;
1040 result
= rc_node_create_child(&parent
->re_node
,
1041 rpr
->rpr_childtype
, rpr
->rpr_name
, &child
->re_node
);
1042 if (result
== REP_PROTOCOL_SUCCESS
)
1043 child
->re_changeid
= rpr
->rpr_changeid
;
1046 entity_release(parent
);
1047 entity_release(child
);
1053 entity_create_pg(repcache_client_t
*cp
,
1054 struct rep_protocol_entity_create_pg
*rpr
)
1056 repcache_entity_t
*parent
;
1057 repcache_entity_t
*child
;
1059 uint32_t parentid
= rpr
->rpr_entityid
;
1060 uint32_t childid
= rpr
->rpr_childid
;
1064 if (rpr
->rpr_changeid
== INVALID_CHANGEID
)
1065 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1067 result
= entity_find2(cp
, parentid
, &parent
, childid
, &child
);
1068 if (result
!= REP_PROTOCOL_SUCCESS
)
1071 rpr
->rpr_name
[sizeof (rpr
->rpr_name
) - 1] = 0;
1072 rpr
->rpr_type
[sizeof (rpr
->rpr_type
) - 1] = 0;
1074 if (child
->re_changeid
== rpr
->rpr_changeid
) {
1075 result
= REP_PROTOCOL_SUCCESS
;
1077 result
= rc_node_create_child_pg(&parent
->re_node
,
1078 child
->re_type
, rpr
->rpr_name
, rpr
->rpr_type
,
1079 rpr
->rpr_flags
, &child
->re_node
);
1080 if (result
== REP_PROTOCOL_SUCCESS
)
1081 child
->re_changeid
= rpr
->rpr_changeid
;
1084 entity_release(parent
);
1085 entity_release(child
);
1091 entity_delete(repcache_client_t
*cp
,
1092 struct rep_protocol_entity_delete
*rpr
)
1094 repcache_entity_t
*entity
;
1096 uint32_t entityid
= rpr
->rpr_entityid
;
1100 if (rpr
->rpr_changeid
== INVALID_CHANGEID
)
1101 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1103 entity
= entity_find(cp
, entityid
);
1106 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
1108 if (entity
->re_changeid
== rpr
->rpr_changeid
) {
1109 result
= REP_PROTOCOL_SUCCESS
;
1111 result
= rc_node_delete(&entity
->re_node
);
1112 if (result
== REP_PROTOCOL_SUCCESS
)
1113 entity
->re_changeid
= rpr
->rpr_changeid
;
1116 entity_release(entity
);
1121 static rep_protocol_responseid_t
1122 entity_teardown(repcache_client_t
*cp
, struct rep_protocol_entity_teardown
*rpr
)
1124 entity_remove(cp
, rpr
->rpr_entityid
);
1126 return (REP_PROTOCOL_SUCCESS
);
1131 * _MISORDERED - the iterator exists and is not reset
1132 * _NO_RESOURCES - out of memory
1135 iter_setup(repcache_client_t
*cp
, struct rep_protocol_iter_request
*rpr
)
1137 repcache_iter_t
*iter
;
1140 client_start_insert(cp
);
1142 * If the iter already exists, and hasn't been read from,
1143 * we assume the previous call succeeded.
1145 if ((iter
= iter_find(cp
, rpr
->rpr_iterid
)) != NULL
) {
1146 sequence
= iter
->ri_sequence
;
1149 client_end_insert(cp
);
1152 return (REP_PROTOCOL_FAIL_MISORDERED
);
1153 return (REP_PROTOCOL_SUCCESS
);
1156 iter
= iter_alloc(cp
);
1158 client_end_insert(cp
);
1159 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
1162 iter
->ri_id
= rpr
->rpr_iterid
;
1163 iter
->ri_type
= REP_PROTOCOL_TYPE_INVALID
;
1164 iter
->ri_sequence
= 0;
1167 client_end_insert(cp
);
1168 return (REP_PROTOCOL_SUCCESS
);
1174 * _MISORDERED - iterator has already been started
1177 * _TYPE_MISMATCH - entity cannot have type children
1178 * _BAD_REQUEST - rpr_flags is invalid
1179 * rpr_pattern is invalid
1185 iter_start(repcache_client_t
*cp
, struct rep_protocol_iter_start
*rpr
)
1188 repcache_iter_t
*iter
;
1189 repcache_entity_t
*ep
;
1191 result
= iter_find_w_entity(cp
, rpr
->rpr_iterid
, &iter
,
1192 rpr
->rpr_entity
, &ep
);
1194 if (result
!= REP_PROTOCOL_SUCCESS
)
1195 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
1197 if (iter
->ri_sequence
> 1) {
1198 result
= REP_PROTOCOL_FAIL_MISORDERED
;
1202 if (iter
->ri_sequence
== 1) {
1203 result
= REP_PROTOCOL_SUCCESS
;
1207 rpr
->rpr_pattern
[sizeof (rpr
->rpr_pattern
) - 1] = 0;
1209 result
= rc_node_setup_iter(&ep
->re_node
, &iter
->ri_iter
,
1210 rpr
->rpr_itertype
, rpr
->rpr_flags
, rpr
->rpr_pattern
);
1212 if (result
== REP_PROTOCOL_SUCCESS
)
1213 iter
->ri_sequence
++;
1224 * _NOT_SET - iter has not been started
1226 * _BAD_REQUEST - iter walks values
1227 * _TYPE_MISMATCH - iter does not walk type entities
1228 * _DELETED - parent was deleted
1230 * _INVALID_TYPE - type is invalid
1234 * For composed property group iterators, can also return
1235 * _TYPE_MISMATCH - parent cannot have type children
1238 static rep_protocol_responseid_t
1239 iter_read(repcache_client_t
*cp
, struct rep_protocol_iter_read
*rpr
)
1241 rep_protocol_responseid_t result
;
1242 repcache_iter_t
*iter
;
1243 repcache_entity_t
*ep
;
1246 result
= iter_find_w_entity(cp
, rpr
->rpr_iterid
, &iter
,
1247 rpr
->rpr_entityid
, &ep
);
1249 if (result
!= REP_PROTOCOL_SUCCESS
)
1252 sequence
= rpr
->rpr_sequence
;
1254 if (iter
->ri_sequence
== 0) {
1257 return (REP_PROTOCOL_FAIL_NOT_SET
);
1260 if (sequence
== 1) {
1263 return (REP_PROTOCOL_FAIL_MISORDERED
);
1266 if (sequence
== iter
->ri_sequence
) {
1269 return (REP_PROTOCOL_SUCCESS
);
1272 if (sequence
== iter
->ri_sequence
+ 1) {
1273 result
= rc_iter_next(iter
->ri_iter
, &ep
->re_node
,
1276 if (result
== REP_PROTOCOL_SUCCESS
)
1277 iter
->ri_sequence
++;
1287 return (REP_PROTOCOL_FAIL_MISORDERED
);
1292 iter_read_value(repcache_client_t
*cp
, const void *in
, size_t insz
,
1293 void *out_arg
, size_t *outsz
, void *arg
)
1295 const struct rep_protocol_iter_read_value
*rpr
= in
;
1296 struct rep_protocol_value_response
*out
= out_arg
;
1297 rep_protocol_responseid_t result
;
1299 repcache_iter_t
*iter
;
1303 assert(*outsz
== sizeof (*out
));
1305 iter
= iter_find(cp
, rpr
->rpr_iterid
);
1308 result
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1312 sequence
= rpr
->rpr_sequence
;
1314 if (iter
->ri_sequence
== 0) {
1316 result
= REP_PROTOCOL_FAIL_NOT_SET
;
1320 repeat
= (sequence
== iter
->ri_sequence
);
1322 if (sequence
== 1 || (!repeat
&& sequence
!= iter
->ri_sequence
+ 1)) {
1324 result
= REP_PROTOCOL_FAIL_MISORDERED
;
1328 result
= rc_iter_next_value(iter
->ri_iter
, out
, outsz
, repeat
);
1330 if (!repeat
&& result
== REP_PROTOCOL_SUCCESS
)
1331 iter
->ri_sequence
++;
1337 * If we fail, we only return the response code.
1338 * If we succeed, rc_iter_next_value has shortened *outsz
1339 * to only include the value bytes needed.
1341 if (result
!= REP_PROTOCOL_SUCCESS
&& result
!= REP_PROTOCOL_DONE
)
1342 *outsz
= sizeof (out
->rpr_response
);
1344 out
->rpr_response
= result
;
1348 iter_reset(repcache_client_t
*cp
, struct rep_protocol_iter_request
*rpr
)
1350 repcache_iter_t
*iter
= iter_find(cp
, rpr
->rpr_iterid
);
1353 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
1355 if (iter
->ri_sequence
!= 0) {
1356 iter
->ri_sequence
= 0;
1357 rc_iter_destroy(&iter
->ri_iter
);
1360 return (REP_PROTOCOL_SUCCESS
);
1363 static rep_protocol_responseid_t
1364 iter_teardown(repcache_client_t
*cp
, struct rep_protocol_iter_request
*rpr
)
1366 iter_remove(cp
, rpr
->rpr_iterid
);
1368 return (REP_PROTOCOL_SUCCESS
);
1371 static rep_protocol_responseid_t
1372 tx_start(repcache_client_t
*cp
, struct rep_protocol_transaction_start
*rpr
)
1374 repcache_entity_t
*tx
;
1375 repcache_entity_t
*ep
;
1376 rep_protocol_responseid_t result
;
1378 uint32_t txid
= rpr
->rpr_entityid_tx
;
1379 uint32_t epid
= rpr
->rpr_entityid
;
1381 result
= entity_find2(cp
, txid
, &tx
, epid
, &ep
);
1382 if (result
!= REP_PROTOCOL_SUCCESS
)
1385 if (tx
->re_txstate
== REPCACHE_TX_SETUP
) {
1386 result
= REP_PROTOCOL_SUCCESS
;
1389 if (tx
->re_txstate
!= REPCACHE_TX_INIT
) {
1390 result
= REP_PROTOCOL_FAIL_MISORDERED
;
1394 result
= rc_node_setup_tx(&ep
->re_node
, &tx
->re_node
);
1397 if (result
== REP_PROTOCOL_SUCCESS
)
1398 tx
->re_txstate
= REPCACHE_TX_SETUP
;
1400 rc_node_clear(&tx
->re_node
, 0);
1409 tx_commit(repcache_client_t
*cp
, const void *in
, size_t insz
,
1410 void *out_arg
, size_t *outsz
, void *arg
)
1412 struct rep_protocol_response
*out
= out_arg
;
1413 const struct rep_protocol_transaction_commit
*rpr
= in
;
1414 repcache_entity_t
*tx
;
1416 assert(*outsz
== sizeof (*out
));
1417 assert(insz
>= REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE
);
1419 if (rpr
->rpr_size
!= insz
) {
1420 out
->rpr_response
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
1424 tx
= entity_find(cp
, rpr
->rpr_entityid
);
1427 out
->rpr_response
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1431 switch (tx
->re_txstate
) {
1432 case REPCACHE_TX_INIT
:
1433 out
->rpr_response
= REP_PROTOCOL_FAIL_MISORDERED
;
1436 case REPCACHE_TX_SETUP
:
1437 out
->rpr_response
= rc_tx_commit(&tx
->re_node
, rpr
->rpr_cmd
,
1438 insz
- REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE
);
1440 if (out
->rpr_response
== REP_PROTOCOL_SUCCESS
) {
1441 tx
->re_txstate
= REPCACHE_TX_COMMITTED
;
1442 rc_node_clear(&tx
->re_node
, 0);
1446 case REPCACHE_TX_COMMITTED
:
1447 out
->rpr_response
= REP_PROTOCOL_SUCCESS
;
1450 assert(0); /* CAN'T HAPPEN */
1457 static rep_protocol_responseid_t
1458 next_snaplevel(repcache_client_t
*cp
, struct rep_protocol_entity_pair
*rpr
)
1460 repcache_entity_t
*src
;
1461 repcache_entity_t
*dest
;
1463 uint32_t srcid
= rpr
->rpr_entity_src
;
1464 uint32_t destid
= rpr
->rpr_entity_dst
;
1468 result
= entity_find2(cp
, srcid
, &src
, destid
, &dest
);
1469 if (result
!= REP_PROTOCOL_SUCCESS
)
1472 result
= rc_node_next_snaplevel(&src
->re_node
, &dest
->re_node
);
1474 entity_release(src
);
1475 entity_release(dest
);
1480 static rep_protocol_responseid_t
1481 snapshot_take(repcache_client_t
*cp
, struct rep_protocol_snapshot_take
*rpr
)
1483 repcache_entity_t
*src
;
1484 uint32_t srcid
= rpr
->rpr_entityid_src
;
1485 repcache_entity_t
*dest
;
1486 uint32_t destid
= rpr
->rpr_entityid_dest
;
1490 result
= entity_find2(cp
, srcid
, &src
, destid
, &dest
);
1491 if (result
!= REP_PROTOCOL_SUCCESS
)
1494 if (dest
->re_type
!= REP_PROTOCOL_ENTITY_SNAPSHOT
) {
1495 result
= REP_PROTOCOL_FAIL_TYPE_MISMATCH
;
1497 rpr
->rpr_name
[sizeof (rpr
->rpr_name
) - 1] = 0;
1499 if (rpr
->rpr_flags
== REP_SNAPSHOT_NEW
)
1500 result
= rc_snapshot_take_new(&src
->re_node
, NULL
,
1501 NULL
, rpr
->rpr_name
, &dest
->re_node
);
1502 else if (rpr
->rpr_flags
== REP_SNAPSHOT_ATTACH
&&
1503 rpr
->rpr_name
[0] == 0)
1504 result
= rc_snapshot_take_attach(&src
->re_node
,
1507 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
1509 entity_release(src
);
1510 entity_release(dest
);
1515 static rep_protocol_responseid_t
1516 snapshot_take_named(repcache_client_t
*cp
,
1517 struct rep_protocol_snapshot_take_named
*rpr
)
1519 repcache_entity_t
*src
;
1520 uint32_t srcid
= rpr
->rpr_entityid_src
;
1521 repcache_entity_t
*dest
;
1522 uint32_t destid
= rpr
->rpr_entityid_dest
;
1526 result
= entity_find2(cp
, srcid
, &src
, destid
, &dest
);
1527 if (result
!= REP_PROTOCOL_SUCCESS
)
1530 if (dest
->re_type
!= REP_PROTOCOL_ENTITY_SNAPSHOT
) {
1531 result
= REP_PROTOCOL_FAIL_TYPE_MISMATCH
;
1533 rpr
->rpr_svcname
[sizeof (rpr
->rpr_svcname
) - 1] = 0;
1534 rpr
->rpr_instname
[sizeof (rpr
->rpr_instname
) - 1] = 0;
1535 rpr
->rpr_name
[sizeof (rpr
->rpr_name
) - 1] = 0;
1537 result
= rc_snapshot_take_new(&src
->re_node
, rpr
->rpr_svcname
,
1538 rpr
->rpr_instname
, rpr
->rpr_name
, &dest
->re_node
);
1540 entity_release(src
);
1541 entity_release(dest
);
1546 static rep_protocol_responseid_t
1547 snapshot_attach(repcache_client_t
*cp
, struct rep_protocol_snapshot_attach
*rpr
)
1549 repcache_entity_t
*src
;
1550 uint32_t srcid
= rpr
->rpr_entityid_src
;
1551 repcache_entity_t
*dest
;
1552 uint32_t destid
= rpr
->rpr_entityid_dest
;
1556 result
= entity_find2(cp
, srcid
, &src
, destid
, &dest
);
1557 if (result
!= REP_PROTOCOL_SUCCESS
)
1560 result
= rc_snapshot_attach(&src
->re_node
, &dest
->re_node
);
1562 entity_release(src
);
1563 entity_release(dest
);
1570 property_get_type(repcache_client_t
*cp
, const void *in
, size_t insz
,
1571 void *out_arg
, size_t *outsz
, void *arg
)
1573 const struct rep_protocol_property_request
*rpr
= in
;
1574 struct rep_protocol_integer_response
*out
= out_arg
;
1575 repcache_entity_t
*ep
;
1576 rep_protocol_value_type_t t
= 0;
1578 assert(*outsz
== sizeof (*out
));
1580 ep
= entity_find(cp
, rpr
->rpr_entityid
);
1583 out
->rpr_response
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1584 *outsz
= sizeof (out
->rpr_response
);
1588 out
->rpr_response
= rc_node_get_property_type(&ep
->re_node
, &t
);
1592 if (out
->rpr_response
!= REP_PROTOCOL_SUCCESS
)
1593 *outsz
= sizeof (out
->rpr_response
);
1600 * _UNKNOWN_ID - an id does not designate an active register
1601 * _NOT_SET - The property is not set
1602 * _DELETED - The property has been deleted
1603 * _TYPE_MISMATCH - The object is not a property
1604 * _NOT_FOUND - The property has no values.
1607 * _SUCCESS - The property has 1 value.
1608 * _TRUNCATED - The property has >1 value.
1612 property_get_value(repcache_client_t
*cp
, const void *in
, size_t insz
,
1613 void *out_arg
, size_t *outsz
, void *arg
)
1615 const struct rep_protocol_property_request
*rpr
= in
;
1616 struct rep_protocol_value_response
*out
= out_arg
;
1617 repcache_entity_t
*ep
;
1619 assert(*outsz
== sizeof (*out
));
1621 ep
= entity_find(cp
, rpr
->rpr_entityid
);
1623 out
->rpr_response
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1624 *outsz
= sizeof (out
->rpr_response
);
1628 out
->rpr_response
= rc_node_get_property_value(&ep
->re_node
, out
,
1634 * If we fail, we only return the response code.
1635 * If we succeed, rc_node_get_property_value has shortened *outsz
1636 * to only include the value bytes needed.
1638 if (out
->rpr_response
!= REP_PROTOCOL_SUCCESS
&&
1639 out
->rpr_response
!= REP_PROTOCOL_FAIL_TRUNCATED
)
1640 *outsz
= sizeof (out
->rpr_response
);
1643 static rep_protocol_responseid_t
1644 propertygrp_notify(repcache_client_t
*cp
,
1645 struct rep_protocol_propertygrp_request
*rpr
, int *out_fd
)
1650 rep_protocol_responseid_t result
;
1651 repcache_entity_t
*ep
;
1654 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
1659 if ((ep
= entity_find(cp
, rpr
->rpr_entityid
)) == NULL
) {
1660 result
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1665 * While the following can race with other threads setting up a
1666 * notification, the worst that can happen is that our fd has
1667 * already been closed before we return.
1669 result
= rc_pg_notify_setup(&cp
->rc_pg_notify
, &ep
->re_node
,
1674 if (result
!= REP_PROTOCOL_SUCCESS
)
1678 return (REP_PROTOCOL_SUCCESS
);
1682 (void) close(theirs
);
1687 static rep_protocol_responseid_t
1688 client_add_notify(repcache_client_t
*cp
,
1689 struct rep_protocol_notify_request
*rpr
)
1691 rpr
->rpr_pattern
[sizeof (rpr
->rpr_pattern
) - 1] = 0;
1693 switch (rpr
->rpr_type
) {
1694 case REP_PROTOCOL_NOTIFY_PGNAME
:
1695 return (rc_notify_info_add_name(&cp
->rc_notify_info
,
1698 case REP_PROTOCOL_NOTIFY_PGTYPE
:
1699 return (rc_notify_info_add_type(&cp
->rc_notify_info
,
1703 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1709 client_wait(repcache_client_t
*cp
, const void *in
, size_t insz
,
1710 void *out_arg
, size_t *outsz
, void *arg
)
1713 repcache_entity_t
*ep
;
1714 const struct rep_protocol_wait_request
*rpr
= in
;
1715 struct rep_protocol_fmri_response
*out
= out_arg
;
1717 assert(*outsz
== sizeof (*out
));
1719 (void) pthread_mutex_lock(&cp
->rc_lock
);
1720 if (cp
->rc_notify_thr
!= 0) {
1721 (void) pthread_mutex_unlock(&cp
->rc_lock
);
1722 out
->rpr_response
= REP_PROTOCOL_FAIL_EXISTS
;
1723 *outsz
= sizeof (out
->rpr_response
);
1726 cp
->rc_notify_thr
= pthread_self();
1727 (void) pthread_mutex_unlock(&cp
->rc_lock
);
1729 result
= rc_notify_info_wait(&cp
->rc_notify_info
, &cp
->rc_notify_ptr
,
1730 out
->rpr_fmri
, sizeof (out
->rpr_fmri
));
1732 if (result
== REP_PROTOCOL_SUCCESS
) {
1733 if ((ep
= entity_find(cp
, rpr
->rpr_entityid
)) != NULL
) {
1734 if (ep
->re_type
== REP_PROTOCOL_ENTITY_PROPERTYGRP
) {
1735 rc_node_ptr_assign(&ep
->re_node
,
1736 &cp
->rc_notify_ptr
);
1738 result
= REP_PROTOCOL_FAIL_TYPE_MISMATCH
;
1742 result
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1744 rc_node_clear(&cp
->rc_notify_ptr
, 0);
1747 (void) pthread_mutex_lock(&cp
->rc_lock
);
1748 assert(cp
->rc_notify_thr
== pthread_self());
1749 cp
->rc_notify_thr
= 0;
1750 (void) pthread_mutex_unlock(&cp
->rc_lock
);
1752 out
->rpr_response
= result
;
1753 if (result
!= REP_PROTOCOL_SUCCESS
)
1754 *outsz
= sizeof (out
->rpr_response
);
1759 * _PERMISSION_DENIED not enough privileges to do request.
1760 * _BAD_REQUEST name is not valid or reserved
1761 * _TRUNCATED name is too long for current repository path
1762 * _UNKNOWN failed for unknown reason (details written to
1764 * _BACKEND_READONLY backend is not writable
1765 * _NO_RESOURCES out of memory
1766 * _SUCCESS Backup completed successfully.
1768 static rep_protocol_responseid_t
1769 backup_repository(repcache_client_t
*cp
,
1770 struct rep_protocol_backup_request
*rpr
)
1772 rep_protocol_responseid_t result
;
1773 ucred_t
*uc
= get_ucred();
1775 if (!client_is_privileged() && (uc
== NULL
|| ucred_geteuid(uc
) != 0))
1776 return (REP_PROTOCOL_FAIL_PERMISSION_DENIED
);
1778 rpr
->rpr_name
[REP_PROTOCOL_NAME_LEN
- 1] = 0;
1779 if (strcmp(rpr
->rpr_name
, REPOSITORY_BOOT_BACKUP
) == 0)
1780 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1782 (void) pthread_mutex_lock(&cp
->rc_lock
);
1783 if (rpr
->rpr_changeid
!= cp
->rc_changeid
) {
1784 result
= backend_create_backup(rpr
->rpr_name
);
1785 if (result
== REP_PROTOCOL_SUCCESS
)
1786 cp
->rc_changeid
= rpr
->rpr_changeid
;
1788 result
= REP_PROTOCOL_SUCCESS
;
1790 (void) pthread_mutex_unlock(&cp
->rc_lock
);
1796 * This function captures the information that will be used for an
1797 * annotation audit event. Specifically, it captures the operation to be
1798 * performed and the name of the file that is being used. These values are
1799 * copied from the rep_protocol_annotation request at rpr to the client
1800 * structure. If both these values are null, the client is turning
1804 * _NO_RESOURCES - unable to allocate memory
1806 static rep_protocol_responseid_t
1807 set_annotation(repcache_client_t
*cp
, struct rep_protocol_annotation
*rpr
)
1810 const char *file
= NULL
;
1811 const char *old_ptrs
[2];
1812 const char *operation
= NULL
;
1813 rep_protocol_responseid_t rc
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1814 au_asid_t sessionid
;
1816 (void) memset((void *)old_ptrs
, 0, sizeof (old_ptrs
));
1818 /* Copy rpr_operation and rpr_file if they are not empty strings. */
1819 if (rpr
->rpr_operation
[0] != 0) {
1821 * Make sure that client did not send us an unterminated buffer.
1823 rpr
->rpr_operation
[sizeof (rpr
->rpr_operation
) - 1] = 0;
1824 if ((operation
= strdup(rpr
->rpr_operation
)) == NULL
)
1827 if (rpr
->rpr_file
[0] != 0) {
1829 * Make sure that client did not send us an unterminated buffer.
1831 rpr
->rpr_file
[sizeof (rpr
->rpr_file
) - 1] = 0;
1832 if ((file
= strdup(rpr
->rpr_file
)) == NULL
)
1836 (void) pthread_mutex_lock(&cp
->rc_annotate_lock
);
1837 /* Save addresses of memory to free when not locked */
1838 old_ptrs
[0] = cp
->rc_operation
;
1839 old_ptrs
[1] = cp
->rc_file
;
1841 /* Save pointers to annotation strings. */
1842 cp
->rc_operation
= operation
;
1846 * Set annotation flag. Annotations should be turned on if either
1847 * operation or file are not NULL.
1849 cp
->rc_annotate
= (operation
!= NULL
) || (file
!= NULL
);
1850 (void) pthread_mutex_unlock(&cp
->rc_annotate_lock
);
1853 * operation and file pointers are saved in cp, so don't free them
1858 rc
= REP_PROTOCOL_SUCCESS
;
1861 * Native builds are done to create svc.configd-native. This
1862 * program runs only on the Open Solaris build machines to create
1863 * the seed repository. Until the SMF auditing code is distributed
1864 * to the Open Solaris build machines, adt_get_unique_id() in the
1865 * following code is not a global function in libbsm. Hence the
1866 * following conditional compilation.
1868 #ifndef NATIVE_BUILD
1870 * Set the appropriate audit session id.
1872 if (cp
->rc_annotate
) {
1874 * We're starting a group of annotated audit events, so
1875 * create and set an audit session ID for this annotation.
1877 adt_get_auid(cp
->rc_adt_session
, &audit_uid
);
1878 sessionid
= adt_get_unique_id(audit_uid
);
1881 * Annotation is done so restore our client audit session
1884 sessionid
= cp
->rc_adt_sessionid
;
1886 adt_set_asid(cp
->rc_adt_session
, sessionid
);
1887 #endif /* NATIVE_BUILD */
1890 if (operation
!= NULL
)
1891 free((void *)operation
);
1894 free((void *)old_ptrs
[0]);
1895 free((void *)old_ptrs
[1]);
1900 * Determine if an annotation event needs to be generated. If it does
1901 * provide the operation and file name that should be used in the event.
1904 * 0 No annotation event needed or buffers are not large
1905 * enough. Either way an event should not be
1907 * 1 Generate annotation event.
1910 client_annotation_needed(char *operation
, size_t oper_sz
,
1911 char *file
, size_t file_sz
)
1913 thread_info_t
*ti
= thread_self();
1914 repcache_client_t
*cp
= ti
->ti_active_client
;
1917 (void) pthread_mutex_lock(&cp
->rc_annotate_lock
);
1918 if (cp
->rc_annotate
) {
1920 if (cp
->rc_operation
== NULL
) {
1924 if (strlcpy(operation
, cp
->rc_operation
, oper_sz
) >=
1926 /* Buffer overflow, so do not generate event */
1930 if (cp
->rc_file
== NULL
) {
1933 } else if (rc
== 1) {
1934 if (strlcpy(file
, cp
->rc_file
, file_sz
) >= file_sz
) {
1935 /* Buffer overflow, so do not generate event */
1940 (void) pthread_mutex_unlock(&cp
->rc_annotate_lock
);
1945 client_annotation_finished()
1947 thread_info_t
*ti
= thread_self();
1948 repcache_client_t
*cp
= ti
->ti_active_client
;
1950 (void) pthread_mutex_lock(&cp
->rc_annotate_lock
);
1951 cp
->rc_annotate
= 0;
1952 (void) pthread_mutex_unlock(&cp
->rc_annotate_lock
);
1956 start_audit_session(repcache_client_t
*cp
)
1958 ucred_t
*cred
= NULL
;
1959 adt_session_data_t
*session
;
1962 * A NULL session pointer value can legally be used in all
1963 * subsequent calls to adt_* functions.
1965 cp
->rc_adt_session
= NULL
;
1967 if (!adt_audit_state(AUC_AUDITING
))
1970 if (door_ucred(&cred
) != 0) {
1974 syslog(LOG_ERR
, gettext("start_audit_session(): cannot "
1975 "get ucred. %m\n"));
1979 * Door client went away. This is a normal,
1980 * although infrequent event, so there is no need
1981 * to create a syslog message.
1986 bad_error("door_ucred", errno
);
1990 if (adt_start_session(&session
, NULL
, 0) != 0) {
1991 syslog(LOG_ERR
, gettext("start_audit_session(): could not "
1992 "start audit session.\n"));
1996 if (adt_set_from_ucred(session
, cred
, ADT_NEW
) != 0) {
1997 syslog(LOG_ERR
, gettext("start_audit_session(): cannot set "
1998 "audit session data from ucred\n"));
1999 /* Something went wrong. End the session. */
2000 (void) adt_end_session(session
);
2005 /* All went well. Save the session data and session ID */
2006 cp
->rc_adt_session
= session
;
2007 adt_get_asid(session
, &cp
->rc_adt_sessionid
);
2013 * Handle switch client request
2015 * This routine can return:
2017 * _PERMISSION_DENIED not enough privileges to do request.
2018 * _UNKNOWN file operation error (details written to
2020 * _SUCCESS switch operation is completed.
2021 * _BACKEND_ACCESS backend access fails.
2022 * _NO_RESOURCES out of memory.
2023 * _BACKEND_READONLY backend is not writable.
2025 static rep_protocol_responseid_t
2026 repository_switch(repcache_client_t
*cp
,
2027 struct rep_protocol_switch_request
*rpr
)
2029 rep_protocol_responseid_t result
;
2030 ucred_t
*uc
= get_ucred();
2032 if (!client_is_privileged() && (uc
== NULL
||
2033 ucred_geteuid(uc
) != 0)) {
2034 return (REP_PROTOCOL_FAIL_PERMISSION_DENIED
);
2037 (void) pthread_mutex_lock(&cp
->rc_lock
);
2038 if (rpr
->rpr_changeid
!= cp
->rc_changeid
) {
2039 if ((result
= backend_switch(rpr
->rpr_flag
)) ==
2040 REP_PROTOCOL_SUCCESS
)
2041 cp
->rc_changeid
= rpr
->rpr_changeid
;
2043 result
= REP_PROTOCOL_SUCCESS
;
2045 (void) pthread_mutex_unlock(&cp
->rc_lock
);
2050 typedef rep_protocol_responseid_t
protocol_simple_f(repcache_client_t
*cp
,
2055 simple_handler(repcache_client_t
*cp
, const void *in
, size_t insz
,
2056 void *out_arg
, size_t *outsz
, void *arg
)
2058 protocol_simple_f
*f
= (protocol_simple_f
*)arg
;
2059 rep_protocol_response_t
*out
= out_arg
;
2061 assert(*outsz
== sizeof (*out
));
2064 out
->rpr_response
= (*f
)(cp
, in
);
2067 typedef rep_protocol_responseid_t
protocol_simple_fd_f(repcache_client_t
*cp
,
2068 const void *rpr
, int *out_fd
);
2072 simple_fd_handler(repcache_client_t
*cp
, const void *in
, size_t insz
,
2073 void *out_arg
, size_t *outsz
, void *arg
, int *out_fd
)
2075 protocol_simple_fd_f
*f
= (protocol_simple_fd_f
*)arg
;
2076 rep_protocol_response_t
*out
= out_arg
;
2078 assert(*outsz
== sizeof (*out
));
2081 out
->rpr_response
= (*f
)(cp
, in
, out_fd
);
2084 typedef void protocol_handler_f(repcache_client_t
*, const void *in
,
2085 size_t insz
, void *out
, size_t *outsz
, void *arg
);
2087 typedef void protocol_handler_fdret_f(repcache_client_t
*, const void *in
,
2088 size_t insz
, void *out
, size_t *outsz
, void *arg
, int *fd_out
);
2090 #define PROTO(p, f, in) { \
2091 p, #p, simple_handler, (void *)(&f), NULL, \
2092 sizeof (in), sizeof (rep_protocol_response_t), 0 \
2095 #define PROTO_FD_OUT(p, f, in) { \
2096 p, #p, NULL, (void *)(&f), simple_fd_handler, \
2098 sizeof (rep_protocol_response_t), \
2102 #define PROTO_VARIN(p, f, insz) { \
2103 p, #p, &(f), NULL, NULL, \
2104 insz, sizeof (rep_protocol_response_t), \
2105 PROTO_FLAG_VARINPUT \
2108 #define PROTO_UINT_OUT(p, f, in) { \
2109 p, #p, &(f), NULL, NULL, \
2111 sizeof (struct rep_protocol_integer_response), 0 \
2114 #define PROTO_NAME_OUT(p, f, in) { \
2115 p, #p, &(f), NULL, NULL, \
2117 sizeof (struct rep_protocol_name_response), 0 \
2120 #define PROTO_FMRI_OUT(p, f, in) { \
2121 p, #p, &(f), NULL, NULL, \
2123 sizeof (struct rep_protocol_fmri_response), 0 \
2126 #define PROTO_VALUE_OUT(p, f, in) { \
2127 p, #p, &(f), NULL, NULL, \
2129 sizeof (struct rep_protocol_value_response), 0 \
2132 #define PROTO_PANIC(p) { p, #p, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC }
2133 #define PROTO_END() { 0, NULL, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC }
2135 #define PROTO_FLAG_PANIC 0x00000001 /* should never be called */
2136 #define PROTO_FLAG_VARINPUT 0x00000004 /* in_size is minimum size */
2137 #define PROTO_FLAG_RETFD 0x00000008 /* can also return an FD */
2139 #define PROTO_ALL_FLAGS 0x0000000f /* all flags */
2141 static struct protocol_entry
{
2142 enum rep_protocol_requestid pt_request
;
2143 const char *pt_name
;
2144 protocol_handler_f
*pt_handler
;
2146 protocol_handler_fdret_f
*pt_fd_handler
;
2150 } protocol_table
[] = {
2151 PROTO_PANIC(REP_PROTOCOL_CLOSE
), /* special case */
2153 PROTO(REP_PROTOCOL_ENTITY_SETUP
, entity_setup
,
2154 struct rep_protocol_entity_setup
),
2155 PROTO_NAME_OUT(REP_PROTOCOL_ENTITY_NAME
, entity_name
,
2156 struct rep_protocol_entity_name
),
2157 PROTO_UINT_OUT(REP_PROTOCOL_ENTITY_PARENT_TYPE
, entity_parent_type
,
2158 struct rep_protocol_entity_parent_type
),
2159 PROTO(REP_PROTOCOL_ENTITY_GET_CHILD
, entity_get_child
,
2160 struct rep_protocol_entity_get_child
),
2161 PROTO(REP_PROTOCOL_ENTITY_GET_PARENT
, entity_get_parent
,
2162 struct rep_protocol_entity_parent
),
2163 PROTO(REP_PROTOCOL_ENTITY_GET
, entity_get
,
2164 struct rep_protocol_entity_get
),
2165 PROTO(REP_PROTOCOL_ENTITY_UPDATE
, entity_update
,
2166 struct rep_protocol_entity_update
),
2167 PROTO(REP_PROTOCOL_ENTITY_CREATE_CHILD
, entity_create_child
,
2168 struct rep_protocol_entity_create_child
),
2169 PROTO(REP_PROTOCOL_ENTITY_CREATE_PG
, entity_create_pg
,
2170 struct rep_protocol_entity_create_pg
),
2171 PROTO(REP_PROTOCOL_ENTITY_DELETE
, entity_delete
,
2172 struct rep_protocol_entity_delete
),
2173 PROTO(REP_PROTOCOL_ENTITY_RESET
, entity_reset
,
2174 struct rep_protocol_entity_reset
),
2175 PROTO(REP_PROTOCOL_ENTITY_TEARDOWN
, entity_teardown
,
2176 struct rep_protocol_entity_teardown
),
2178 PROTO(REP_PROTOCOL_ITER_SETUP
, iter_setup
,
2179 struct rep_protocol_iter_request
),
2180 PROTO(REP_PROTOCOL_ITER_START
, iter_start
,
2181 struct rep_protocol_iter_start
),
2182 PROTO(REP_PROTOCOL_ITER_READ
, iter_read
,
2183 struct rep_protocol_iter_read
),
2184 PROTO_VALUE_OUT(REP_PROTOCOL_ITER_READ_VALUE
, iter_read_value
,
2185 struct rep_protocol_iter_read_value
),
2186 PROTO(REP_PROTOCOL_ITER_RESET
, iter_reset
,
2187 struct rep_protocol_iter_request
),
2188 PROTO(REP_PROTOCOL_ITER_TEARDOWN
, iter_teardown
,
2189 struct rep_protocol_iter_request
),
2191 PROTO(REP_PROTOCOL_NEXT_SNAPLEVEL
, next_snaplevel
,
2192 struct rep_protocol_entity_pair
),
2194 PROTO(REP_PROTOCOL_SNAPSHOT_TAKE
, snapshot_take
,
2195 struct rep_protocol_snapshot_take
),
2196 PROTO(REP_PROTOCOL_SNAPSHOT_TAKE_NAMED
, snapshot_take_named
,
2197 struct rep_protocol_snapshot_take_named
),
2198 PROTO(REP_PROTOCOL_SNAPSHOT_ATTACH
, snapshot_attach
,
2199 struct rep_protocol_snapshot_attach
),
2201 PROTO_UINT_OUT(REP_PROTOCOL_PROPERTY_GET_TYPE
, property_get_type
,
2202 struct rep_protocol_property_request
),
2203 PROTO_VALUE_OUT(REP_PROTOCOL_PROPERTY_GET_VALUE
, property_get_value
,
2204 struct rep_protocol_property_request
),
2206 PROTO_FD_OUT(REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT
, propertygrp_notify
,
2207 struct rep_protocol_propertygrp_request
),
2208 PROTO(REP_PROTOCOL_PROPERTYGRP_TX_START
, tx_start
,
2209 struct rep_protocol_transaction_start
),
2210 PROTO_VARIN(REP_PROTOCOL_PROPERTYGRP_TX_COMMIT
, tx_commit
,
2211 REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE
),
2213 PROTO(REP_PROTOCOL_CLIENT_ADD_NOTIFY
, client_add_notify
,
2214 struct rep_protocol_notify_request
),
2215 PROTO_FMRI_OUT(REP_PROTOCOL_CLIENT_WAIT
, client_wait
,
2216 struct rep_protocol_wait_request
),
2218 PROTO(REP_PROTOCOL_BACKUP
, backup_repository
,
2219 struct rep_protocol_backup_request
),
2221 PROTO(REP_PROTOCOL_SET_AUDIT_ANNOTATION
, set_annotation
,
2222 struct rep_protocol_annotation
),
2224 PROTO(REP_PROTOCOL_SWITCH
, repository_switch
,
2225 struct rep_protocol_switch_request
),
2230 #undef PROTO_FMRI_OUT
2231 #undef PROTO_NAME_OUT
2232 #undef PROTO_UINT_OUT
2237 * The number of entries, sans PROTO_END()
2239 #define PROTOCOL_ENTRIES \
2240 (sizeof (protocol_table) / sizeof (*protocol_table) - 1)
2242 #define PROTOCOL_PREFIX "REP_PROTOCOL_"
2248 struct protocol_entry
*e
;
2250 if (!client_hash_init())
2253 if (request_log_size
> 0) {
2254 request_log
= uu_zalloc(request_log_size
*
2255 sizeof (request_log_entry_t
));
2259 * update the names to not include REP_PROTOCOL_
2261 for (i
= 0; i
< PROTOCOL_ENTRIES
; i
++) {
2262 e
= &protocol_table
[i
];
2263 assert(strncmp(e
->pt_name
, PROTOCOL_PREFIX
,
2264 strlen(PROTOCOL_PREFIX
)) == 0);
2265 e
->pt_name
+= strlen(PROTOCOL_PREFIX
);
2268 * verify the protocol table is consistent
2270 for (i
= 0; i
< PROTOCOL_ENTRIES
; i
++) {
2271 e
= &protocol_table
[i
];
2272 assert(e
->pt_request
== (REP_PROTOCOL_BASE
+ i
));
2274 assert((e
->pt_flags
& ~PROTO_ALL_FLAGS
) == 0);
2276 if (e
->pt_flags
& PROTO_FLAG_PANIC
)
2277 assert(e
->pt_in_size
== 0 && e
->pt_out_max
== 0 &&
2278 e
->pt_handler
== NULL
);
2280 assert(e
->pt_in_size
!= 0 && e
->pt_out_max
!= 0 &&
2281 (e
->pt_handler
!= NULL
||
2282 e
->pt_fd_handler
!= NULL
));
2284 assert((REP_PROTOCOL_BASE
+ i
) == REP_PROTOCOL_MAX_REQUEST
);
2286 assert(protocol_table
[i
].pt_request
== 0);
2292 client_switcher(void *cookie
, char *argp
, size_t arg_size
, door_desc_t
*desc_in
,
2295 thread_info_t
*ti
= thread_self();
2297 repcache_client_t
*cp
;
2298 uint32_t id
= (uint32_t)cookie
;
2299 enum rep_protocol_requestid request_code
;
2301 rep_protocol_responseid_t result
= INVALID_RESULT
;
2303 struct protocol_entry
*e
;
2305 char *retval
= NULL
;
2310 request_log_entry_t
*rlp
;
2312 rlp
= start_log(id
);
2315 uu_die("can't happen: %d descriptors @%p (cookie %p)",
2316 n_desc
, desc_in
, cookie
);
2318 if (argp
== DOOR_UNREF_DATA
) {
2323 thread_newstate(ti
, TI_CLIENT_CALL
);
2326 * To simplify returning just a result code, we set up for
2329 retval
= (char *)&result
;
2330 retsize
= sizeof (result
);
2332 if (arg_size
< sizeof (request_code
)) {
2333 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
2337 ti
->ti_client_request
= (void *)argp
;
2339 /* LINTED alignment */
2340 request_code
= *(uint32_t *)argp
;
2343 rlp
->rl_request
= request_code
;
2346 * In order to avoid locking problems on removal, we handle the
2347 * "close" case before doing a lookup.
2349 if (request_code
== REP_PROTOCOL_CLOSE
) {
2351 result
= REP_PROTOCOL_SUCCESS
;
2355 cp
= client_lookup(id
);
2364 rlp
->rl_client
= cp
;
2366 ti
->ti_active_client
= cp
;
2368 if (request_code
< REP_PROTOCOL_BASE
||
2369 request_code
>= REP_PROTOCOL_BASE
+ PROTOCOL_ENTRIES
) {
2370 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
2374 e
= &protocol_table
[request_code
- REP_PROTOCOL_BASE
];
2376 assert(!(e
->pt_flags
& PROTO_FLAG_PANIC
));
2378 if (e
->pt_flags
& PROTO_FLAG_VARINPUT
) {
2379 if (arg_size
< e
->pt_in_size
) {
2380 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
2383 } else if (arg_size
!= e
->pt_in_size
) {
2384 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
2388 if (retsize
!= e
->pt_out_max
) {
2389 retsize
= e
->pt_out_max
;
2390 retval
= alloca(retsize
);
2393 if (e
->pt_flags
& PROTO_FLAG_RETFD
)
2394 e
->pt_fd_handler(cp
, argp
, arg_size
, retval
, &retsize
,
2397 e
->pt_handler(cp
, argp
, arg_size
, retval
, &retsize
, e
->pt_arg
);
2400 ti
->ti_active_client
= NULL
;
2405 /* LINTED alignment */
2406 rlp
->rl_response
= *(uint32_t *)retval
;
2410 ti
->ti_client_request
= NULL
;
2411 thread_newstate(ti
, TI_DOOR_RETURN
);
2413 if (retval
== (char *)&result
) {
2414 assert(result
!= INVALID_RESULT
&& retsize
== sizeof (result
));
2416 /* LINTED alignment */
2417 result
= *(uint32_t *)retval
;
2420 desc
.d_attributes
= DOOR_DESCRIPTOR
| DOOR_RELEASE
;
2421 desc
.d_data
.d_desc
.d_descriptor
= retfd
;
2422 (void) door_return(retval
, retsize
, &desc
, 1);
2424 (void) door_return(retval
, retsize
, NULL
, 0);
2428 rlp
->rl_response
= -1;
2432 (void) door_return(NULL
, 0, NULL
, 0);
2436 create_client(pid_t pid
, uint32_t debugflags
, int privileged
, int *out_fd
)
2440 repcache_client_t
*cp
;
2442 struct door_info info
;
2444 int door_flags
= DOOR_UNREF
| DOOR_REFUSE_DESC
;
2445 #ifdef DOOR_NO_CANCEL
2446 door_flags
|= DOOR_NO_CANCEL
;
2449 cp
= client_alloc();
2451 return (REPOSITORY_DOOR_FAIL_NO_RESOURCES
);
2453 (void) pthread_mutex_lock(&client_lock
);
2454 cp
->rc_id
= ++client_maxid
;
2455 (void) pthread_mutex_unlock(&client_lock
);
2457 cp
->rc_all_auths
= privileged
;
2459 cp
->rc_debug
= debugflags
;
2461 start_audit_session(cp
);
2463 cp
->rc_doorfd
= door_create(client_switcher
, (void *)cp
->rc_id
,
2466 if (cp
->rc_doorfd
< 0) {
2468 return (REPOSITORY_DOOR_FAIL_NO_RESOURCES
);
2470 #ifdef DOOR_PARAM_DATA_MIN
2471 (void) door_setparam(cp
->rc_doorfd
, DOOR_PARAM_DATA_MIN
,
2472 sizeof (enum rep_protocol_requestid
));
2475 if ((fd
= dup(cp
->rc_doorfd
)) < 0 ||
2476 door_info(cp
->rc_doorfd
, &info
) < 0) {
2479 (void) door_revoke(cp
->rc_doorfd
);
2482 return (REPOSITORY_DOOR_FAIL_NO_RESOURCES
);
2485 rc_pg_notify_init(&cp
->rc_pg_notify
);
2486 rc_notify_info_init(&cp
->rc_notify_info
);
2490 cp
->rc_doorid
= info
.di_uniquifier
;
2493 return (REPOSITORY_DOOR_SUCCESS
);