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 2015 RackTop Systems.
28 * This is the client layer for svc.configd. All direct protocol interactions
31 * Essentially, the job of this layer is to turn the idempotent protocol
32 * into a series of non-idempotent calls into the object layer, while
33 * also handling the necessary locking.
38 #include <bsm/adt_event.h>
54 #include "repcache_protocol.h"
56 #define INVALID_CHANGEID (0)
57 #define INVALID_DOORID ((door_id_t)-1)
58 #define INVALID_RESULT ((rep_protocol_responseid_t)INT_MIN)
61 * lint doesn't like constant assertions
64 #define assert_nolint(x) (void)0
66 #define assert_nolint(x) assert(x)
70 * Protects client linkage and the freelist
72 #define CLIENT_HASH_SIZE 64
74 #pragma align 64(client_hash)
75 static client_bucket_t client_hash
[CLIENT_HASH_SIZE
];
77 static uu_avl_pool_t
*entity_pool
;
78 static uu_avl_pool_t
*iter_pool
;
79 static uu_list_pool_t
*client_pool
;
81 #define CLIENT_HASH(id) (&client_hash[((id) & (CLIENT_HASH_SIZE - 1))])
83 uint_t request_log_size
= 1024; /* tunable, before we start */
85 static pthread_mutex_t request_log_lock
= PTHREAD_MUTEX_INITIALIZER
;
86 static uint_t request_log_cur
;
87 request_log_entry_t
*request_log
;
89 static uint32_t client_maxid
;
90 static pthread_mutex_t client_lock
; /* protects client_maxid */
92 static request_log_entry_t
*
95 thread_info_t
*ti
= thread_self();
100 log_enter(request_log_entry_t
*rlp
)
102 if (rlp
->rl_start
!= 0 && request_log
!= NULL
) {
103 request_log_entry_t
*logrlp
;
105 (void) pthread_mutex_lock(&request_log_lock
);
106 assert(request_log_cur
< request_log_size
);
107 logrlp
= &request_log
[request_log_cur
++];
108 if (request_log_cur
== request_log_size
)
110 (void) memcpy(logrlp
, rlp
, sizeof (*rlp
));
111 (void) pthread_mutex_unlock(&request_log_lock
);
116 * Note that the svc.configd dmod will join all of the per-thread log entries
117 * with the main log, so that even if the log is disabled, there is some
118 * information available.
120 static request_log_entry_t
*
121 start_log(uint32_t clientid
)
123 request_log_entry_t
*rlp
= get_log();
127 (void) memset(rlp
, 0, sizeof (*rlp
));
128 rlp
->rl_start
= gethrtime();
129 rlp
->rl_tid
= pthread_self();
130 rlp
->rl_clientid
= clientid
;
138 request_log_entry_t
*rlp
= get_log();
140 rlp
->rl_end
= gethrtime();
144 add_log_ptr(request_log_entry_t
*rlp
, enum rc_ptr_type type
, uint32_t id
,
147 request_log_ptr_t
*rpp
;
152 if (rlp
->rl_num_ptrs
>= MAX_PTRS
)
155 rpp
= &rlp
->rl_ptrs
[rlp
->rl_num_ptrs
++];
156 rpp
->rlp_type
= type
;
161 * For entities, it's useful to have the node pointer at the start
164 if (type
== RC_PTR_TYPE_ENTITY
&& ptr
!= NULL
)
165 rpp
->rlp_data
= ((repcache_entity_t
*)ptr
)->re_node
.rnp_node
;
169 client_is_privileged(void)
171 thread_info_t
*ti
= thread_self();
175 if (ti
->ti_active_client
!= NULL
&&
176 ti
->ti_active_client
->rc_all_auths
)
179 if ((uc
= get_ucred()) == NULL
)
182 return (ucred_is_privileged(uc
));
187 client_compare(const void *lc_arg
, const void *rc_arg
, void *private)
189 uint32_t l_id
= ((const repcache_client_t
*)lc_arg
)->rc_id
;
190 uint32_t r_id
= ((const repcache_client_t
*)rc_arg
)->rc_id
;
201 entity_compare(const void *lc_arg
, const void *rc_arg
, void *private)
203 uint32_t l_id
= ((const repcache_entity_t
*)lc_arg
)->re_id
;
204 uint32_t r_id
= ((const repcache_entity_t
*)rc_arg
)->re_id
;
215 iter_compare(const void *lc_arg
, const void *rc_arg
, void *private)
217 uint32_t l_id
= ((const repcache_iter_t
*)lc_arg
)->ri_id
;
218 uint32_t r_id
= ((const repcache_iter_t
*)rc_arg
)->ri_id
;
228 client_hash_init(void)
232 assert_nolint(offsetof(repcache_entity_t
, re_id
) == 0);
233 entity_pool
= uu_avl_pool_create("repcache_entitys",
234 sizeof (repcache_entity_t
), offsetof(repcache_entity_t
, re_link
),
235 entity_compare
, UU_AVL_POOL_DEBUG
);
237 assert_nolint(offsetof(repcache_iter_t
, ri_id
) == 0);
238 iter_pool
= uu_avl_pool_create("repcache_iters",
239 sizeof (repcache_iter_t
), offsetof(repcache_iter_t
, ri_link
),
240 iter_compare
, UU_AVL_POOL_DEBUG
);
242 assert_nolint(offsetof(repcache_client_t
, rc_id
) == 0);
243 client_pool
= uu_list_pool_create("repcache_clients",
244 sizeof (repcache_client_t
), offsetof(repcache_client_t
, rc_link
),
245 client_compare
, UU_LIST_POOL_DEBUG
);
247 if (entity_pool
== NULL
|| iter_pool
== NULL
|| client_pool
== NULL
)
250 for (x
= 0; x
< CLIENT_HASH_SIZE
; x
++) {
251 uu_list_t
*lp
= uu_list_create(client_pool
, &client_hash
[x
],
256 (void) pthread_mutex_init(&client_hash
[x
].cb_lock
, NULL
);
257 client_hash
[x
].cb_list
= lp
;
263 static repcache_client_t
*
266 repcache_client_t
*cp
;
267 cp
= uu_zalloc(sizeof (*cp
));
271 cp
->rc_entities
= uu_avl_create(entity_pool
, cp
, 0);
272 if (cp
->rc_entities
== NULL
)
275 cp
->rc_iters
= uu_avl_create(iter_pool
, cp
, 0);
276 if (cp
->rc_iters
== NULL
)
279 uu_list_node_init(cp
, &cp
->rc_link
, client_pool
);
282 cp
->rc_doorid
= INVALID_DOORID
;
284 (void) pthread_mutex_init(&cp
->rc_lock
, NULL
);
285 (void) pthread_mutex_init(&cp
->rc_annotate_lock
, NULL
);
287 rc_node_ptr_init(&cp
->rc_notify_ptr
);
292 if (cp
->rc_iters
!= NULL
)
293 uu_avl_destroy(cp
->rc_iters
);
294 if (cp
->rc_entities
!= NULL
)
295 uu_avl_destroy(cp
->rc_entities
);
301 client_free(repcache_client_t
*cp
)
303 assert(cp
->rc_insert_thr
== 0);
304 assert(cp
->rc_refcnt
== 0);
305 assert(cp
->rc_doorfd
== -1);
306 assert(cp
->rc_doorid
== INVALID_DOORID
);
307 assert(uu_avl_first(cp
->rc_entities
) == NULL
);
308 assert(uu_avl_first(cp
->rc_iters
) == NULL
);
309 uu_avl_destroy(cp
->rc_entities
);
310 uu_avl_destroy(cp
->rc_iters
);
311 uu_list_node_fini(cp
, &cp
->rc_link
, client_pool
);
312 (void) pthread_mutex_destroy(&cp
->rc_lock
);
313 (void) pthread_mutex_destroy(&cp
->rc_annotate_lock
);
314 rc_node_ptr_free_mem(&cp
->rc_notify_ptr
);
319 client_insert(repcache_client_t
*cp
)
321 client_bucket_t
*bp
= CLIENT_HASH(cp
->rc_id
);
324 assert(cp
->rc_id
> 0);
326 (void) pthread_mutex_lock(&bp
->cb_lock
);
328 * We assume it does not already exist
330 (void) uu_list_find(bp
->cb_list
, cp
, NULL
, &idx
);
331 uu_list_insert(bp
->cb_list
, cp
, idx
);
333 (void) pthread_mutex_unlock(&bp
->cb_lock
);
336 static repcache_client_t
*
337 client_lookup(uint32_t id
)
339 client_bucket_t
*bp
= CLIENT_HASH(id
);
340 repcache_client_t
*cp
;
342 (void) pthread_mutex_lock(&bp
->cb_lock
);
344 cp
= uu_list_find(bp
->cb_list
, &id
, NULL
, NULL
);
347 * Bump the reference count
350 (void) pthread_mutex_lock(&cp
->rc_lock
);
351 assert(!(cp
->rc_flags
& RC_CLIENT_DEAD
));
353 (void) pthread_mutex_unlock(&cp
->rc_lock
);
355 (void) pthread_mutex_unlock(&bp
->cb_lock
);
361 client_release(repcache_client_t
*cp
)
363 (void) pthread_mutex_lock(&cp
->rc_lock
);
364 assert(cp
->rc_refcnt
> 0);
365 assert(cp
->rc_insert_thr
!= pthread_self());
368 (void) pthread_cond_broadcast(&cp
->rc_cv
);
369 (void) pthread_mutex_unlock(&cp
->rc_lock
);
373 * We only allow one thread to be inserting at a time, to prevent
374 * insert/insert races.
377 client_start_insert(repcache_client_t
*cp
)
379 (void) pthread_mutex_lock(&cp
->rc_lock
);
380 assert(cp
->rc_refcnt
> 0);
382 while (cp
->rc_insert_thr
!= 0) {
383 assert(cp
->rc_insert_thr
!= pthread_self());
384 (void) pthread_cond_wait(&cp
->rc_cv
, &cp
->rc_lock
);
386 cp
->rc_insert_thr
= pthread_self();
387 (void) pthread_mutex_unlock(&cp
->rc_lock
);
391 client_end_insert(repcache_client_t
*cp
)
393 (void) pthread_mutex_lock(&cp
->rc_lock
);
394 assert(cp
->rc_insert_thr
== pthread_self());
395 cp
->rc_insert_thr
= 0;
396 (void) pthread_cond_broadcast(&cp
->rc_cv
);
397 (void) pthread_mutex_unlock(&cp
->rc_lock
);
401 static repcache_entity_t
*
402 entity_alloc(repcache_client_t
*cp
)
404 repcache_entity_t
*ep
= uu_zalloc(sizeof (repcache_entity_t
));
406 uu_avl_node_init(ep
, &ep
->re_link
, entity_pool
);
412 entity_add(repcache_client_t
*cp
, repcache_entity_t
*ep
)
416 (void) pthread_mutex_lock(&cp
->rc_lock
);
417 assert(cp
->rc_insert_thr
== pthread_self());
419 (void) uu_avl_find(cp
->rc_entities
, ep
, NULL
, &idx
);
420 uu_avl_insert(cp
->rc_entities
, ep
, idx
);
422 (void) pthread_mutex_unlock(&cp
->rc_lock
);
425 static repcache_entity_t
*
426 entity_find(repcache_client_t
*cp
, uint32_t id
)
428 repcache_entity_t
*ep
;
430 (void) pthread_mutex_lock(&cp
->rc_lock
);
431 ep
= uu_avl_find(cp
->rc_entities
, &id
, NULL
, NULL
);
433 add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY
, id
, ep
);
434 (void) pthread_mutex_lock(&ep
->re_lock
);
436 (void) pthread_mutex_unlock(&cp
->rc_lock
);
443 * _DUPLICATE_ID - the ids are equal
444 * _UNKNOWN_ID - an id does not designate an active register
447 entity_find2(repcache_client_t
*cp
, uint32_t id1
, repcache_entity_t
**out1
,
448 uint32_t id2
, repcache_entity_t
**out2
)
450 repcache_entity_t
*e1
, *e2
;
451 request_log_entry_t
*rlp
;
454 return (REP_PROTOCOL_FAIL_DUPLICATE_ID
);
456 (void) pthread_mutex_lock(&cp
->rc_lock
);
457 e1
= uu_avl_find(cp
->rc_entities
, &id1
, NULL
, NULL
);
458 e2
= uu_avl_find(cp
->rc_entities
, &id2
, NULL
, NULL
);
459 if (e1
== NULL
|| e2
== NULL
) {
460 (void) pthread_mutex_unlock(&cp
->rc_lock
);
461 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
467 * locks are ordered by id number
470 (void) pthread_mutex_lock(&e1
->re_lock
);
471 (void) pthread_mutex_lock(&e2
->re_lock
);
473 (void) pthread_mutex_lock(&e2
->re_lock
);
474 (void) pthread_mutex_lock(&e1
->re_lock
);
479 (void) pthread_mutex_unlock(&cp
->rc_lock
);
481 if ((rlp
= get_log()) != NULL
) {
482 add_log_ptr(rlp
, RC_PTR_TYPE_ENTITY
, id1
, e1
);
483 add_log_ptr(rlp
, RC_PTR_TYPE_ENTITY
, id2
, e2
);
486 return (REP_PROTOCOL_SUCCESS
);
490 entity_release(repcache_entity_t
*ep
)
492 assert(ep
->re_node
.rnp_node
== NULL
||
493 !MUTEX_HELD(&ep
->re_node
.rnp_node
->rn_lock
));
494 (void) pthread_mutex_unlock(&ep
->re_lock
);
498 entity_destroy(repcache_entity_t
*entity
)
500 (void) pthread_mutex_lock(&entity
->re_lock
);
501 rc_node_clear(&entity
->re_node
, 0);
502 (void) pthread_mutex_unlock(&entity
->re_lock
);
504 uu_avl_node_fini(entity
, &entity
->re_link
, entity_pool
);
505 (void) pthread_mutex_destroy(&entity
->re_lock
);
506 rc_node_ptr_free_mem(&entity
->re_node
);
511 entity_remove(repcache_client_t
*cp
, uint32_t id
)
513 repcache_entity_t
*entity
;
515 (void) pthread_mutex_lock(&cp
->rc_lock
);
516 entity
= uu_avl_find(cp
->rc_entities
, &id
, NULL
, NULL
);
517 if (entity
!= NULL
) {
518 add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY
, id
, entity
);
520 uu_avl_remove(cp
->rc_entities
, entity
);
522 (void) pthread_mutex_unlock(&cp
->rc_lock
);
525 entity_destroy(entity
);
529 entity_cleanup(repcache_client_t
*cp
)
531 repcache_entity_t
*ep
;
534 (void) pthread_mutex_lock(&cp
->rc_lock
);
535 while ((ep
= uu_avl_teardown(cp
->rc_entities
, &cookie
)) != NULL
) {
536 (void) pthread_mutex_unlock(&cp
->rc_lock
);
538 (void) pthread_mutex_lock(&cp
->rc_lock
);
540 (void) pthread_mutex_unlock(&cp
->rc_lock
);
544 static repcache_iter_t
*
545 iter_alloc(repcache_client_t
*cp
)
547 repcache_iter_t
*iter
;
548 iter
= uu_zalloc(sizeof (repcache_iter_t
));
550 uu_avl_node_init(iter
, &iter
->ri_link
, iter_pool
);
555 iter_add(repcache_client_t
*cp
, repcache_iter_t
*iter
)
559 (void) pthread_mutex_lock(&cp
->rc_lock
);
560 assert(cp
->rc_insert_thr
== pthread_self());
562 (void) uu_avl_find(cp
->rc_iters
, iter
, NULL
, &idx
);
563 uu_avl_insert(cp
->rc_iters
, iter
, idx
);
565 (void) pthread_mutex_unlock(&cp
->rc_lock
);
568 static repcache_iter_t
*
569 iter_find(repcache_client_t
*cp
, uint32_t id
)
571 repcache_iter_t
*iter
;
573 (void) pthread_mutex_lock(&cp
->rc_lock
);
575 iter
= uu_avl_find(cp
->rc_iters
, &id
, NULL
, NULL
);
577 add_log_ptr(get_log(), RC_PTR_TYPE_ITER
, id
, iter
);
578 (void) pthread_mutex_lock(&iter
->ri_lock
);
580 (void) pthread_mutex_unlock(&cp
->rc_lock
);
587 * _UNKNOWN_ID - iter_id or entity_id does not designate an active register
590 iter_find_w_entity(repcache_client_t
*cp
, uint32_t iter_id
,
591 repcache_iter_t
**iterp
, uint32_t entity_id
, repcache_entity_t
**epp
)
593 repcache_iter_t
*iter
;
594 repcache_entity_t
*ep
;
595 request_log_entry_t
*rlp
;
597 (void) pthread_mutex_lock(&cp
->rc_lock
);
598 iter
= uu_avl_find(cp
->rc_iters
, &iter_id
, NULL
, NULL
);
599 ep
= uu_avl_find(cp
->rc_entities
, &entity_id
, NULL
, NULL
);
601 assert(iter
== NULL
|| !MUTEX_HELD(&iter
->ri_lock
));
602 assert(ep
== NULL
|| !MUTEX_HELD(&ep
->re_lock
));
604 if (iter
== NULL
|| ep
== NULL
) {
605 (void) pthread_mutex_unlock(&cp
->rc_lock
);
606 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
609 (void) pthread_mutex_lock(&iter
->ri_lock
);
610 (void) pthread_mutex_lock(&ep
->re_lock
);
612 (void) pthread_mutex_unlock(&cp
->rc_lock
);
617 if ((rlp
= get_log()) != NULL
) {
618 add_log_ptr(rlp
, RC_PTR_TYPE_ENTITY
, entity_id
, ep
);
619 add_log_ptr(rlp
, RC_PTR_TYPE_ITER
, iter_id
, iter
);
622 return (REP_PROTOCOL_SUCCESS
);
626 iter_release(repcache_iter_t
*iter
)
628 (void) pthread_mutex_unlock(&iter
->ri_lock
);
632 iter_destroy(repcache_iter_t
*iter
)
634 (void) pthread_mutex_lock(&iter
->ri_lock
);
635 rc_iter_destroy(&iter
->ri_iter
);
636 (void) pthread_mutex_unlock(&iter
->ri_lock
);
638 uu_avl_node_fini(iter
, &iter
->ri_link
, iter_pool
);
639 (void) pthread_mutex_destroy(&iter
->ri_lock
);
644 iter_remove(repcache_client_t
*cp
, uint32_t id
)
646 repcache_iter_t
*iter
;
648 (void) pthread_mutex_lock(&cp
->rc_lock
);
649 iter
= uu_avl_find(cp
->rc_iters
, &id
, NULL
, NULL
);
651 uu_avl_remove(cp
->rc_iters
, iter
);
652 (void) pthread_mutex_unlock(&cp
->rc_lock
);
659 iter_cleanup(repcache_client_t
*cp
)
661 repcache_iter_t
*iter
;
664 (void) pthread_mutex_lock(&cp
->rc_lock
);
665 while ((iter
= uu_avl_teardown(cp
->rc_iters
, &cookie
)) != NULL
) {
666 (void) pthread_mutex_unlock(&cp
->rc_lock
);
668 (void) pthread_mutex_lock(&cp
->rc_lock
);
670 (void) pthread_mutex_unlock(&cp
->rc_lock
);
674 * Ensure that the passed client id is no longer usable, wait for any
675 * outstanding invocations to complete, then destroy the client
679 client_destroy(uint32_t id
)
681 client_bucket_t
*bp
= CLIENT_HASH(id
);
682 repcache_client_t
*cp
;
684 (void) pthread_mutex_lock(&bp
->cb_lock
);
686 cp
= uu_list_find(bp
->cb_list
, &id
, NULL
, NULL
);
689 (void) pthread_mutex_unlock(&bp
->cb_lock
);
693 uu_list_remove(bp
->cb_list
, cp
);
695 (void) pthread_mutex_unlock(&bp
->cb_lock
);
697 /* kick the waiters out */
698 rc_notify_info_fini(&cp
->rc_notify_info
);
700 (void) pthread_mutex_lock(&cp
->rc_lock
);
701 assert(!(cp
->rc_flags
& RC_CLIENT_DEAD
));
702 cp
->rc_flags
|= RC_CLIENT_DEAD
;
704 if (cp
->rc_doorfd
!= -1) {
705 if (door_revoke(cp
->rc_doorfd
) < 0)
706 perror("door_revoke");
708 cp
->rc_doorid
= INVALID_DOORID
;
711 while (cp
->rc_refcnt
> 0)
712 (void) pthread_cond_wait(&cp
->rc_cv
, &cp
->rc_lock
);
714 assert(cp
->rc_insert_thr
== 0 && cp
->rc_notify_thr
== 0);
715 (void) pthread_mutex_unlock(&cp
->rc_lock
);
718 * destroy outstanding objects
724 * clean up notifications
726 rc_pg_notify_fini(&cp
->rc_pg_notify
);
729 * clean up annotations
731 if (cp
->rc_operation
!= NULL
)
732 free((void *)cp
->rc_operation
);
733 if (cp
->rc_file
!= NULL
)
734 free((void *)cp
->rc_file
);
740 (void) adt_end_session(cp
->rc_adt_session
);
748 * _TYPE_MISMATCH - the entity is already set up with a different type
749 * _NO_RESOURCES - out of memory
752 entity_setup(repcache_client_t
*cp
, struct rep_protocol_entity_setup
*rpr
)
754 repcache_entity_t
*ep
;
757 client_start_insert(cp
);
759 if ((ep
= entity_find(cp
, rpr
->rpr_entityid
)) != NULL
) {
763 client_end_insert(cp
);
765 if (type
!= rpr
->rpr_entitytype
)
766 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
767 return (REP_PROTOCOL_SUCCESS
);
770 switch (type
= rpr
->rpr_entitytype
) {
771 case REP_PROTOCOL_ENTITY_SCOPE
:
772 case REP_PROTOCOL_ENTITY_SERVICE
:
773 case REP_PROTOCOL_ENTITY_INSTANCE
:
774 case REP_PROTOCOL_ENTITY_SNAPSHOT
:
775 case REP_PROTOCOL_ENTITY_SNAPLEVEL
:
776 case REP_PROTOCOL_ENTITY_PROPERTYGRP
:
777 case REP_PROTOCOL_ENTITY_PROPERTY
:
780 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
783 ep
= entity_alloc(cp
);
785 client_end_insert(cp
);
786 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
789 ep
->re_id
= rpr
->rpr_entityid
;
790 ep
->re_changeid
= INVALID_CHANGEID
;
793 rc_node_ptr_init(&ep
->re_node
);
796 client_end_insert(cp
);
797 return (REP_PROTOCOL_SUCCESS
);
802 entity_name(repcache_client_t
*cp
, const void *in
, size_t insz
, void *out_arg
,
803 size_t *outsz
, void *arg
)
805 const struct rep_protocol_entity_name
*rpr
= in
;
806 struct rep_protocol_name_response
*out
= out_arg
;
807 repcache_entity_t
*ep
;
808 size_t sz
= sizeof (out
->rpr_name
);
810 assert(*outsz
== sizeof (*out
));
812 ep
= entity_find(cp
, rpr
->rpr_entityid
);
815 out
->rpr_response
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
816 *outsz
= sizeof (out
->rpr_response
);
819 out
->rpr_response
= rc_node_name(&ep
->re_node
, out
->rpr_name
,
820 sz
, rpr
->rpr_answertype
, &sz
);
824 * If we fail, we only return the response code.
825 * If we succeed, we don't return anything after the '\0' in rpr_name.
827 if (out
->rpr_response
!= REP_PROTOCOL_SUCCESS
)
828 *outsz
= sizeof (out
->rpr_response
);
830 *outsz
= offsetof(struct rep_protocol_name_response
,
836 entity_parent_type(repcache_client_t
*cp
, const void *in
, size_t insz
,
837 void *out_arg
, size_t *outsz
, void *arg
)
839 const struct rep_protocol_entity_name
*rpr
= in
;
840 struct rep_protocol_integer_response
*out
= out_arg
;
841 repcache_entity_t
*ep
;
843 assert(*outsz
== sizeof (*out
));
845 ep
= entity_find(cp
, rpr
->rpr_entityid
);
848 out
->rpr_response
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
849 *outsz
= sizeof (out
->rpr_response
);
853 out
->rpr_response
= rc_node_parent_type(&ep
->re_node
, &out
->rpr_value
);
856 if (out
->rpr_response
!= REP_PROTOCOL_SUCCESS
)
857 *outsz
= sizeof (out
->rpr_response
);
862 * _DUPLICATE_ID - the ids are equal
863 * _UNKNOWN_ID - an id does not designate an active register
864 * _INVALID_TYPE - type is invalid
865 * _TYPE_MISMATCH - np doesn't carry children of type type
866 * _DELETED - np has been deleted
867 * _NOT_FOUND - no child with that name/type combo found
872 entity_get_child(repcache_client_t
*cp
,
873 struct rep_protocol_entity_get_child
*rpr
)
875 repcache_entity_t
*parent
, *child
;
878 uint32_t parentid
= rpr
->rpr_entityid
;
879 uint32_t childid
= rpr
->rpr_childid
;
881 result
= entity_find2(cp
, childid
, &child
, parentid
, &parent
);
882 if (result
!= REP_PROTOCOL_SUCCESS
)
885 rpr
->rpr_name
[sizeof (rpr
->rpr_name
) - 1] = 0;
887 result
= rc_node_get_child(&parent
->re_node
, rpr
->rpr_name
,
888 child
->re_type
, &child
->re_node
);
890 entity_release(child
);
891 entity_release(parent
);
897 * Returns _FAIL_DUPLICATE_ID, _FAIL_UNKNOWN_ID, _FAIL_NOT_SET, _FAIL_DELETED,
898 * _FAIL_TYPE_MISMATCH, _FAIL_NOT_FOUND (scope has no parent), or _SUCCESS.
900 * _DUPLICATE_ID - the ids are equal
901 * _UNKNOWN_ID - an id does not designate an active register
902 * _NOT_SET - child is not set
903 * _DELETED - child has been deleted
904 * _TYPE_MISMATCH - child's parent does not match that of the parent register
905 * _NOT_FOUND - child has no parent (and is a scope)
908 entity_get_parent(repcache_client_t
*cp
, struct rep_protocol_entity_parent
*rpr
)
910 repcache_entity_t
*child
, *parent
;
913 uint32_t childid
= rpr
->rpr_entityid
;
914 uint32_t outid
= rpr
->rpr_outid
;
916 result
= entity_find2(cp
, childid
, &child
, outid
, &parent
);
917 if (result
!= REP_PROTOCOL_SUCCESS
)
920 result
= rc_node_get_parent(&child
->re_node
, parent
->re_type
,
923 entity_release(child
);
924 entity_release(parent
);
930 entity_get(repcache_client_t
*cp
, struct rep_protocol_entity_get
*rpr
)
932 repcache_entity_t
*ep
;
935 ep
= entity_find(cp
, rpr
->rpr_entityid
);
938 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
940 switch (rpr
->rpr_object
) {
941 case RP_ENTITY_GET_INVALIDATE
:
942 rc_node_clear(&ep
->re_node
, 0);
943 result
= REP_PROTOCOL_SUCCESS
;
945 case RP_ENTITY_GET_MOST_LOCAL_SCOPE
:
946 result
= rc_local_scope(ep
->re_type
, &ep
->re_node
);
949 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
959 entity_update(repcache_client_t
*cp
, struct rep_protocol_entity_update
*rpr
)
961 repcache_entity_t
*ep
;
964 if (rpr
->rpr_changeid
== INVALID_CHANGEID
)
965 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
967 ep
= entity_find(cp
, rpr
->rpr_entityid
);
970 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
972 if (ep
->re_changeid
== rpr
->rpr_changeid
) {
973 result
= REP_PROTOCOL_DONE
;
975 result
= rc_node_update(&ep
->re_node
);
976 if (result
== REP_PROTOCOL_DONE
)
977 ep
->re_changeid
= rpr
->rpr_changeid
;
986 entity_reset(repcache_client_t
*cp
, struct rep_protocol_entity_reset
*rpr
)
988 repcache_entity_t
*ep
;
990 ep
= entity_find(cp
, rpr
->rpr_entityid
);
992 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
994 rc_node_clear(&ep
->re_node
, 0);
995 ep
->re_txstate
= REPCACHE_TX_INIT
;
998 return (REP_PROTOCOL_SUCCESS
);
1003 * _BAD_REQUEST - request has invalid changeid
1004 * rpr_name is invalid
1005 * cannot create children for parent's type of node
1006 * _DUPLICATE_ID - request has duplicate ids
1007 * _UNKNOWN_ID - request has unknown id
1008 * _DELETED - parent has been deleted
1009 * _NOT_SET - parent is reset
1010 * _NOT_APPLICABLE - rpr_childtype is _PROPERTYGRP
1011 * _INVALID_TYPE - parent is corrupt or rpr_childtype is invalid
1012 * _TYPE_MISMATCH - parent cannot have children of type rpr_childtype
1014 * _PERMISSION_DENIED
1017 * _EXISTS - child already exists
1020 entity_create_child(repcache_client_t
*cp
,
1021 struct rep_protocol_entity_create_child
*rpr
)
1023 repcache_entity_t
*parent
;
1024 repcache_entity_t
*child
;
1026 uint32_t parentid
= rpr
->rpr_entityid
;
1027 uint32_t childid
= rpr
->rpr_childid
;
1031 if (rpr
->rpr_changeid
== INVALID_CHANGEID
)
1032 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1034 result
= entity_find2(cp
, parentid
, &parent
, childid
, &child
);
1035 if (result
!= REP_PROTOCOL_SUCCESS
)
1038 rpr
->rpr_name
[sizeof (rpr
->rpr_name
) - 1] = 0;
1040 if (child
->re_changeid
== rpr
->rpr_changeid
) {
1041 result
= REP_PROTOCOL_SUCCESS
;
1043 result
= rc_node_create_child(&parent
->re_node
,
1044 rpr
->rpr_childtype
, rpr
->rpr_name
, &child
->re_node
);
1045 if (result
== REP_PROTOCOL_SUCCESS
)
1046 child
->re_changeid
= rpr
->rpr_changeid
;
1049 entity_release(parent
);
1050 entity_release(child
);
1056 entity_create_pg(repcache_client_t
*cp
,
1057 struct rep_protocol_entity_create_pg
*rpr
)
1059 repcache_entity_t
*parent
;
1060 repcache_entity_t
*child
;
1062 uint32_t parentid
= rpr
->rpr_entityid
;
1063 uint32_t childid
= rpr
->rpr_childid
;
1067 if (rpr
->rpr_changeid
== INVALID_CHANGEID
)
1068 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1070 result
= entity_find2(cp
, parentid
, &parent
, childid
, &child
);
1071 if (result
!= REP_PROTOCOL_SUCCESS
)
1074 rpr
->rpr_name
[sizeof (rpr
->rpr_name
) - 1] = 0;
1075 rpr
->rpr_type
[sizeof (rpr
->rpr_type
) - 1] = 0;
1077 if (child
->re_changeid
== rpr
->rpr_changeid
) {
1078 result
= REP_PROTOCOL_SUCCESS
;
1080 result
= rc_node_create_child_pg(&parent
->re_node
,
1081 child
->re_type
, rpr
->rpr_name
, rpr
->rpr_type
,
1082 rpr
->rpr_flags
, &child
->re_node
);
1083 if (result
== REP_PROTOCOL_SUCCESS
)
1084 child
->re_changeid
= rpr
->rpr_changeid
;
1087 entity_release(parent
);
1088 entity_release(child
);
1094 entity_delete(repcache_client_t
*cp
,
1095 struct rep_protocol_entity_delete
*rpr
)
1097 repcache_entity_t
*entity
;
1099 uint32_t entityid
= rpr
->rpr_entityid
;
1103 if (rpr
->rpr_changeid
== INVALID_CHANGEID
)
1104 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1106 entity
= entity_find(cp
, entityid
);
1109 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
1111 if (entity
->re_changeid
== rpr
->rpr_changeid
) {
1112 result
= REP_PROTOCOL_SUCCESS
;
1114 result
= rc_node_delete(&entity
->re_node
);
1115 if (result
== REP_PROTOCOL_SUCCESS
)
1116 entity
->re_changeid
= rpr
->rpr_changeid
;
1119 entity_release(entity
);
1124 static rep_protocol_responseid_t
1125 entity_teardown(repcache_client_t
*cp
, struct rep_protocol_entity_teardown
*rpr
)
1127 entity_remove(cp
, rpr
->rpr_entityid
);
1129 return (REP_PROTOCOL_SUCCESS
);
1134 * _MISORDERED - the iterator exists and is not reset
1135 * _NO_RESOURCES - out of memory
1138 iter_setup(repcache_client_t
*cp
, struct rep_protocol_iter_request
*rpr
)
1140 repcache_iter_t
*iter
;
1143 client_start_insert(cp
);
1145 * If the iter already exists, and hasn't been read from,
1146 * we assume the previous call succeeded.
1148 if ((iter
= iter_find(cp
, rpr
->rpr_iterid
)) != NULL
) {
1149 sequence
= iter
->ri_sequence
;
1152 client_end_insert(cp
);
1155 return (REP_PROTOCOL_FAIL_MISORDERED
);
1156 return (REP_PROTOCOL_SUCCESS
);
1159 iter
= iter_alloc(cp
);
1161 client_end_insert(cp
);
1162 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
1165 iter
->ri_id
= rpr
->rpr_iterid
;
1166 iter
->ri_type
= REP_PROTOCOL_TYPE_INVALID
;
1167 iter
->ri_sequence
= 0;
1170 client_end_insert(cp
);
1171 return (REP_PROTOCOL_SUCCESS
);
1177 * _MISORDERED - iterator has already been started
1180 * _TYPE_MISMATCH - entity cannot have type children
1181 * _BAD_REQUEST - rpr_flags is invalid
1182 * rpr_pattern is invalid
1188 iter_start(repcache_client_t
*cp
, struct rep_protocol_iter_start
*rpr
)
1191 repcache_iter_t
*iter
;
1192 repcache_entity_t
*ep
;
1194 result
= iter_find_w_entity(cp
, rpr
->rpr_iterid
, &iter
,
1195 rpr
->rpr_entity
, &ep
);
1197 if (result
!= REP_PROTOCOL_SUCCESS
)
1198 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
1200 if (iter
->ri_sequence
> 1) {
1201 result
= REP_PROTOCOL_FAIL_MISORDERED
;
1205 if (iter
->ri_sequence
== 1) {
1206 result
= REP_PROTOCOL_SUCCESS
;
1210 rpr
->rpr_pattern
[sizeof (rpr
->rpr_pattern
) - 1] = 0;
1212 result
= rc_node_setup_iter(&ep
->re_node
, &iter
->ri_iter
,
1213 rpr
->rpr_itertype
, rpr
->rpr_flags
, rpr
->rpr_pattern
);
1215 if (result
== REP_PROTOCOL_SUCCESS
)
1216 iter
->ri_sequence
++;
1227 * _NOT_SET - iter has not been started
1229 * _BAD_REQUEST - iter walks values
1230 * _TYPE_MISMATCH - iter does not walk type entities
1231 * _DELETED - parent was deleted
1233 * _INVALID_TYPE - type is invalid
1237 * For composed property group iterators, can also return
1238 * _TYPE_MISMATCH - parent cannot have type children
1241 static rep_protocol_responseid_t
1242 iter_read(repcache_client_t
*cp
, struct rep_protocol_iter_read
*rpr
)
1244 rep_protocol_responseid_t result
;
1245 repcache_iter_t
*iter
;
1246 repcache_entity_t
*ep
;
1249 result
= iter_find_w_entity(cp
, rpr
->rpr_iterid
, &iter
,
1250 rpr
->rpr_entityid
, &ep
);
1252 if (result
!= REP_PROTOCOL_SUCCESS
)
1255 sequence
= rpr
->rpr_sequence
;
1257 if (iter
->ri_sequence
== 0) {
1260 return (REP_PROTOCOL_FAIL_NOT_SET
);
1263 if (sequence
== 1) {
1266 return (REP_PROTOCOL_FAIL_MISORDERED
);
1269 if (sequence
== iter
->ri_sequence
) {
1272 return (REP_PROTOCOL_SUCCESS
);
1275 if (sequence
== iter
->ri_sequence
+ 1) {
1276 result
= rc_iter_next(iter
->ri_iter
, &ep
->re_node
,
1279 if (result
== REP_PROTOCOL_SUCCESS
)
1280 iter
->ri_sequence
++;
1290 return (REP_PROTOCOL_FAIL_MISORDERED
);
1295 iter_read_value(repcache_client_t
*cp
, const void *in
, size_t insz
,
1296 void *out_arg
, size_t *outsz
, void *arg
)
1298 const struct rep_protocol_iter_read_value
*rpr
= in
;
1299 struct rep_protocol_value_response
*out
= out_arg
;
1300 rep_protocol_responseid_t result
;
1302 repcache_iter_t
*iter
;
1306 assert(*outsz
== sizeof (*out
));
1308 iter
= iter_find(cp
, rpr
->rpr_iterid
);
1311 result
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1315 sequence
= rpr
->rpr_sequence
;
1317 if (iter
->ri_sequence
== 0) {
1319 result
= REP_PROTOCOL_FAIL_NOT_SET
;
1323 repeat
= (sequence
== iter
->ri_sequence
);
1325 if (sequence
== 1 || (!repeat
&& sequence
!= iter
->ri_sequence
+ 1)) {
1327 result
= REP_PROTOCOL_FAIL_MISORDERED
;
1331 result
= rc_iter_next_value(iter
->ri_iter
, out
, outsz
, repeat
);
1333 if (!repeat
&& result
== REP_PROTOCOL_SUCCESS
)
1334 iter
->ri_sequence
++;
1340 * If we fail, we only return the response code.
1341 * If we succeed, rc_iter_next_value has shortened *outsz
1342 * to only include the value bytes needed.
1344 if (result
!= REP_PROTOCOL_SUCCESS
&& result
!= REP_PROTOCOL_DONE
)
1345 *outsz
= sizeof (out
->rpr_response
);
1347 out
->rpr_response
= result
;
1351 iter_reset(repcache_client_t
*cp
, struct rep_protocol_iter_request
*rpr
)
1353 repcache_iter_t
*iter
= iter_find(cp
, rpr
->rpr_iterid
);
1356 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
1358 if (iter
->ri_sequence
!= 0) {
1359 iter
->ri_sequence
= 0;
1360 rc_iter_destroy(&iter
->ri_iter
);
1363 return (REP_PROTOCOL_SUCCESS
);
1366 static rep_protocol_responseid_t
1367 iter_teardown(repcache_client_t
*cp
, struct rep_protocol_iter_request
*rpr
)
1369 iter_remove(cp
, rpr
->rpr_iterid
);
1371 return (REP_PROTOCOL_SUCCESS
);
1374 static rep_protocol_responseid_t
1375 tx_start(repcache_client_t
*cp
, struct rep_protocol_transaction_start
*rpr
)
1377 repcache_entity_t
*tx
;
1378 repcache_entity_t
*ep
;
1379 rep_protocol_responseid_t result
;
1381 uint32_t txid
= rpr
->rpr_entityid_tx
;
1382 uint32_t epid
= rpr
->rpr_entityid
;
1384 result
= entity_find2(cp
, txid
, &tx
, epid
, &ep
);
1385 if (result
!= REP_PROTOCOL_SUCCESS
)
1388 if (tx
->re_txstate
== REPCACHE_TX_SETUP
) {
1389 result
= REP_PROTOCOL_SUCCESS
;
1392 if (tx
->re_txstate
!= REPCACHE_TX_INIT
) {
1393 result
= REP_PROTOCOL_FAIL_MISORDERED
;
1397 result
= rc_node_setup_tx(&ep
->re_node
, &tx
->re_node
);
1400 if (result
== REP_PROTOCOL_SUCCESS
)
1401 tx
->re_txstate
= REPCACHE_TX_SETUP
;
1403 rc_node_clear(&tx
->re_node
, 0);
1412 tx_commit(repcache_client_t
*cp
, const void *in
, size_t insz
,
1413 void *out_arg
, size_t *outsz
, void *arg
)
1415 struct rep_protocol_response
*out
= out_arg
;
1416 const struct rep_protocol_transaction_commit
*rpr
= in
;
1417 repcache_entity_t
*tx
;
1419 assert(*outsz
== sizeof (*out
));
1420 assert(insz
>= REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE
);
1422 if (rpr
->rpr_size
!= insz
) {
1423 out
->rpr_response
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
1427 tx
= entity_find(cp
, rpr
->rpr_entityid
);
1430 out
->rpr_response
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1434 switch (tx
->re_txstate
) {
1435 case REPCACHE_TX_INIT
:
1436 out
->rpr_response
= REP_PROTOCOL_FAIL_MISORDERED
;
1439 case REPCACHE_TX_SETUP
:
1440 out
->rpr_response
= rc_tx_commit(&tx
->re_node
, rpr
->rpr_cmd
,
1441 insz
- REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE
);
1443 if (out
->rpr_response
== REP_PROTOCOL_SUCCESS
) {
1444 tx
->re_txstate
= REPCACHE_TX_COMMITTED
;
1445 rc_node_clear(&tx
->re_node
, 0);
1449 case REPCACHE_TX_COMMITTED
:
1450 out
->rpr_response
= REP_PROTOCOL_SUCCESS
;
1453 assert(0); /* CAN'T HAPPEN */
1460 static rep_protocol_responseid_t
1461 next_snaplevel(repcache_client_t
*cp
, struct rep_protocol_entity_pair
*rpr
)
1463 repcache_entity_t
*src
;
1464 repcache_entity_t
*dest
;
1466 uint32_t srcid
= rpr
->rpr_entity_src
;
1467 uint32_t destid
= rpr
->rpr_entity_dst
;
1471 result
= entity_find2(cp
, srcid
, &src
, destid
, &dest
);
1472 if (result
!= REP_PROTOCOL_SUCCESS
)
1475 result
= rc_node_next_snaplevel(&src
->re_node
, &dest
->re_node
);
1477 entity_release(src
);
1478 entity_release(dest
);
1483 static rep_protocol_responseid_t
1484 snapshot_take(repcache_client_t
*cp
, struct rep_protocol_snapshot_take
*rpr
)
1486 repcache_entity_t
*src
;
1487 uint32_t srcid
= rpr
->rpr_entityid_src
;
1488 repcache_entity_t
*dest
;
1489 uint32_t destid
= rpr
->rpr_entityid_dest
;
1493 result
= entity_find2(cp
, srcid
, &src
, destid
, &dest
);
1494 if (result
!= REP_PROTOCOL_SUCCESS
)
1497 if (dest
->re_type
!= REP_PROTOCOL_ENTITY_SNAPSHOT
) {
1498 result
= REP_PROTOCOL_FAIL_TYPE_MISMATCH
;
1500 rpr
->rpr_name
[sizeof (rpr
->rpr_name
) - 1] = 0;
1502 if (rpr
->rpr_flags
== REP_SNAPSHOT_NEW
)
1503 result
= rc_snapshot_take_new(&src
->re_node
, NULL
,
1504 NULL
, rpr
->rpr_name
, &dest
->re_node
);
1505 else if (rpr
->rpr_flags
== REP_SNAPSHOT_ATTACH
&&
1506 rpr
->rpr_name
[0] == 0)
1507 result
= rc_snapshot_take_attach(&src
->re_node
,
1510 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
1512 entity_release(src
);
1513 entity_release(dest
);
1518 static rep_protocol_responseid_t
1519 snapshot_take_named(repcache_client_t
*cp
,
1520 struct rep_protocol_snapshot_take_named
*rpr
)
1522 repcache_entity_t
*src
;
1523 uint32_t srcid
= rpr
->rpr_entityid_src
;
1524 repcache_entity_t
*dest
;
1525 uint32_t destid
= rpr
->rpr_entityid_dest
;
1529 result
= entity_find2(cp
, srcid
, &src
, destid
, &dest
);
1530 if (result
!= REP_PROTOCOL_SUCCESS
)
1533 if (dest
->re_type
!= REP_PROTOCOL_ENTITY_SNAPSHOT
) {
1534 result
= REP_PROTOCOL_FAIL_TYPE_MISMATCH
;
1536 rpr
->rpr_svcname
[sizeof (rpr
->rpr_svcname
) - 1] = 0;
1537 rpr
->rpr_instname
[sizeof (rpr
->rpr_instname
) - 1] = 0;
1538 rpr
->rpr_name
[sizeof (rpr
->rpr_name
) - 1] = 0;
1540 result
= rc_snapshot_take_new(&src
->re_node
, rpr
->rpr_svcname
,
1541 rpr
->rpr_instname
, rpr
->rpr_name
, &dest
->re_node
);
1543 entity_release(src
);
1544 entity_release(dest
);
1549 static rep_protocol_responseid_t
1550 snapshot_attach(repcache_client_t
*cp
, struct rep_protocol_snapshot_attach
*rpr
)
1552 repcache_entity_t
*src
;
1553 uint32_t srcid
= rpr
->rpr_entityid_src
;
1554 repcache_entity_t
*dest
;
1555 uint32_t destid
= rpr
->rpr_entityid_dest
;
1559 result
= entity_find2(cp
, srcid
, &src
, destid
, &dest
);
1560 if (result
!= REP_PROTOCOL_SUCCESS
)
1563 result
= rc_snapshot_attach(&src
->re_node
, &dest
->re_node
);
1565 entity_release(src
);
1566 entity_release(dest
);
1573 property_get_type(repcache_client_t
*cp
, const void *in
, size_t insz
,
1574 void *out_arg
, size_t *outsz
, void *arg
)
1576 const struct rep_protocol_property_request
*rpr
= in
;
1577 struct rep_protocol_integer_response
*out
= out_arg
;
1578 repcache_entity_t
*ep
;
1579 rep_protocol_value_type_t t
= 0;
1581 assert(*outsz
== sizeof (*out
));
1583 ep
= entity_find(cp
, rpr
->rpr_entityid
);
1586 out
->rpr_response
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1587 *outsz
= sizeof (out
->rpr_response
);
1591 out
->rpr_response
= rc_node_get_property_type(&ep
->re_node
, &t
);
1595 if (out
->rpr_response
!= REP_PROTOCOL_SUCCESS
)
1596 *outsz
= sizeof (out
->rpr_response
);
1603 * _UNKNOWN_ID - an id does not designate an active register
1604 * _NOT_SET - The property is not set
1605 * _DELETED - The property has been deleted
1606 * _TYPE_MISMATCH - The object is not a property
1607 * _NOT_FOUND - The property has no values.
1610 * _SUCCESS - The property has 1 value.
1611 * _TRUNCATED - The property has >1 value.
1615 property_get_value(repcache_client_t
*cp
, const void *in
, size_t insz
,
1616 void *out_arg
, size_t *outsz
, void *arg
)
1618 const struct rep_protocol_property_request
*rpr
= in
;
1619 struct rep_protocol_value_response
*out
= out_arg
;
1620 repcache_entity_t
*ep
;
1622 assert(*outsz
== sizeof (*out
));
1624 ep
= entity_find(cp
, rpr
->rpr_entityid
);
1626 out
->rpr_response
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1627 *outsz
= sizeof (out
->rpr_response
);
1631 out
->rpr_response
= rc_node_get_property_value(&ep
->re_node
, out
,
1637 * If we fail, we only return the response code.
1638 * If we succeed, rc_node_get_property_value has shortened *outsz
1639 * to only include the value bytes needed.
1641 if (out
->rpr_response
!= REP_PROTOCOL_SUCCESS
&&
1642 out
->rpr_response
!= REP_PROTOCOL_FAIL_TRUNCATED
)
1643 *outsz
= sizeof (out
->rpr_response
);
1646 static rep_protocol_responseid_t
1647 propertygrp_notify(repcache_client_t
*cp
,
1648 struct rep_protocol_propertygrp_request
*rpr
, int *out_fd
)
1653 rep_protocol_responseid_t result
;
1654 repcache_entity_t
*ep
;
1657 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
1662 if ((ep
= entity_find(cp
, rpr
->rpr_entityid
)) == NULL
) {
1663 result
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1668 * While the following can race with other threads setting up a
1669 * notification, the worst that can happen is that our fd has
1670 * already been closed before we return.
1672 result
= rc_pg_notify_setup(&cp
->rc_pg_notify
, &ep
->re_node
,
1677 if (result
!= REP_PROTOCOL_SUCCESS
)
1681 return (REP_PROTOCOL_SUCCESS
);
1685 (void) close(theirs
);
1690 static rep_protocol_responseid_t
1691 client_add_notify(repcache_client_t
*cp
,
1692 struct rep_protocol_notify_request
*rpr
)
1694 rpr
->rpr_pattern
[sizeof (rpr
->rpr_pattern
) - 1] = 0;
1696 switch (rpr
->rpr_type
) {
1697 case REP_PROTOCOL_NOTIFY_PGNAME
:
1698 return (rc_notify_info_add_name(&cp
->rc_notify_info
,
1701 case REP_PROTOCOL_NOTIFY_PGTYPE
:
1702 return (rc_notify_info_add_type(&cp
->rc_notify_info
,
1706 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1712 client_wait(repcache_client_t
*cp
, const void *in
, size_t insz
,
1713 void *out_arg
, size_t *outsz
, void *arg
)
1716 repcache_entity_t
*ep
;
1717 const struct rep_protocol_wait_request
*rpr
= in
;
1718 struct rep_protocol_fmri_response
*out
= out_arg
;
1720 assert(*outsz
== sizeof (*out
));
1722 (void) pthread_mutex_lock(&cp
->rc_lock
);
1723 if (cp
->rc_notify_thr
!= 0) {
1724 (void) pthread_mutex_unlock(&cp
->rc_lock
);
1725 out
->rpr_response
= REP_PROTOCOL_FAIL_EXISTS
;
1726 *outsz
= sizeof (out
->rpr_response
);
1729 cp
->rc_notify_thr
= pthread_self();
1730 (void) pthread_mutex_unlock(&cp
->rc_lock
);
1732 result
= rc_notify_info_wait(&cp
->rc_notify_info
, &cp
->rc_notify_ptr
,
1733 out
->rpr_fmri
, sizeof (out
->rpr_fmri
));
1735 if (result
== REP_PROTOCOL_SUCCESS
) {
1736 if ((ep
= entity_find(cp
, rpr
->rpr_entityid
)) != NULL
) {
1737 if (ep
->re_type
== REP_PROTOCOL_ENTITY_PROPERTYGRP
) {
1738 rc_node_ptr_assign(&ep
->re_node
,
1739 &cp
->rc_notify_ptr
);
1741 result
= REP_PROTOCOL_FAIL_TYPE_MISMATCH
;
1745 result
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1747 rc_node_clear(&cp
->rc_notify_ptr
, 0);
1750 (void) pthread_mutex_lock(&cp
->rc_lock
);
1751 assert(cp
->rc_notify_thr
== pthread_self());
1752 cp
->rc_notify_thr
= 0;
1753 (void) pthread_mutex_unlock(&cp
->rc_lock
);
1755 out
->rpr_response
= result
;
1756 if (result
!= REP_PROTOCOL_SUCCESS
)
1757 *outsz
= sizeof (out
->rpr_response
);
1762 * _PERMISSION_DENIED not enough privileges to do request.
1763 * _BAD_REQUEST name is not valid or reserved
1764 * _TRUNCATED name is too long for current repository path
1765 * _UNKNOWN failed for unknown reason (details written to
1767 * _BACKEND_READONLY backend is not writable
1768 * _NO_RESOURCES out of memory
1769 * _SUCCESS Backup completed successfully.
1771 static rep_protocol_responseid_t
1772 backup_repository(repcache_client_t
*cp
,
1773 struct rep_protocol_backup_request
*rpr
)
1775 rep_protocol_responseid_t result
;
1776 ucred_t
*uc
= get_ucred();
1778 if (!client_is_privileged() && (uc
== NULL
|| ucred_geteuid(uc
) != 0))
1779 return (REP_PROTOCOL_FAIL_PERMISSION_DENIED
);
1781 rpr
->rpr_name
[REP_PROTOCOL_NAME_LEN
- 1] = 0;
1782 if (strcmp(rpr
->rpr_name
, REPOSITORY_BOOT_BACKUP
) == 0)
1783 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1785 (void) pthread_mutex_lock(&cp
->rc_lock
);
1786 if (rpr
->rpr_changeid
!= cp
->rc_changeid
) {
1787 result
= backend_create_backup(rpr
->rpr_name
);
1788 if (result
== REP_PROTOCOL_SUCCESS
)
1789 cp
->rc_changeid
= rpr
->rpr_changeid
;
1791 result
= REP_PROTOCOL_SUCCESS
;
1793 (void) pthread_mutex_unlock(&cp
->rc_lock
);
1799 * This function captures the information that will be used for an
1800 * annotation audit event. Specifically, it captures the operation to be
1801 * performed and the name of the file that is being used. These values are
1802 * copied from the rep_protocol_annotation request at rpr to the client
1803 * structure. If both these values are null, the client is turning
1807 * _NO_RESOURCES - unable to allocate memory
1809 static rep_protocol_responseid_t
1810 set_annotation(repcache_client_t
*cp
, struct rep_protocol_annotation
*rpr
)
1813 const char *file
= NULL
;
1814 const char *old_ptrs
[2];
1815 const char *operation
= NULL
;
1816 rep_protocol_responseid_t rc
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1817 au_asid_t sessionid
;
1819 (void) memset((void *)old_ptrs
, 0, sizeof (old_ptrs
));
1821 /* Copy rpr_operation and rpr_file if they are not empty strings. */
1822 if (rpr
->rpr_operation
[0] != 0) {
1824 * Make sure that client did not send us an unterminated buffer.
1826 rpr
->rpr_operation
[sizeof (rpr
->rpr_operation
) - 1] = 0;
1827 if ((operation
= strdup(rpr
->rpr_operation
)) == NULL
)
1830 if (rpr
->rpr_file
[0] != 0) {
1832 * Make sure that client did not send us an unterminated buffer.
1834 rpr
->rpr_file
[sizeof (rpr
->rpr_file
) - 1] = 0;
1835 if ((file
= strdup(rpr
->rpr_file
)) == NULL
)
1839 (void) pthread_mutex_lock(&cp
->rc_annotate_lock
);
1840 /* Save addresses of memory to free when not locked */
1841 old_ptrs
[0] = cp
->rc_operation
;
1842 old_ptrs
[1] = cp
->rc_file
;
1844 /* Save pointers to annotation strings. */
1845 cp
->rc_operation
= operation
;
1849 * Set annotation flag. Annotations should be turned on if either
1850 * operation or file are not NULL.
1852 cp
->rc_annotate
= (operation
!= NULL
) || (file
!= NULL
);
1853 (void) pthread_mutex_unlock(&cp
->rc_annotate_lock
);
1856 * operation and file pointers are saved in cp, so don't free them
1861 rc
= REP_PROTOCOL_SUCCESS
;
1864 * Native builds are done to create svc.configd-native. This
1865 * program runs only on the Open Solaris build machines to create
1866 * the seed repository. Until the SMF auditing code is distributed
1867 * to the Open Solaris build machines, adt_get_unique_id() in the
1868 * following code is not a global function in libbsm. Hence the
1869 * following conditional compilation.
1871 #ifndef NATIVE_BUILD
1873 * Set the appropriate audit session id.
1875 if (cp
->rc_annotate
) {
1877 * We're starting a group of annotated audit events, so
1878 * create and set an audit session ID for this annotation.
1880 adt_get_auid(cp
->rc_adt_session
, &audit_uid
);
1881 sessionid
= adt_get_unique_id(audit_uid
);
1884 * Annotation is done so restore our client audit session
1887 sessionid
= cp
->rc_adt_sessionid
;
1889 adt_set_asid(cp
->rc_adt_session
, sessionid
);
1890 #endif /* NATIVE_BUILD */
1893 if (operation
!= NULL
)
1894 free((void *)operation
);
1897 free((void *)old_ptrs
[0]);
1898 free((void *)old_ptrs
[1]);
1903 * Determine if an annotation event needs to be generated. If it does
1904 * provide the operation and file name that should be used in the event.
1907 * 0 No annotation event needed or buffers are not large
1908 * enough. Either way an event should not be
1910 * 1 Generate annotation event.
1913 client_annotation_needed(char *operation
, size_t oper_sz
,
1914 char *file
, size_t file_sz
)
1916 thread_info_t
*ti
= thread_self();
1917 repcache_client_t
*cp
= ti
->ti_active_client
;
1920 (void) pthread_mutex_lock(&cp
->rc_annotate_lock
);
1921 if (cp
->rc_annotate
) {
1923 if (cp
->rc_operation
== NULL
) {
1927 if (strlcpy(operation
, cp
->rc_operation
, oper_sz
) >=
1929 /* Buffer overflow, so do not generate event */
1933 if (cp
->rc_file
== NULL
) {
1936 } else if (rc
== 1) {
1937 if (strlcpy(file
, cp
->rc_file
, file_sz
) >= file_sz
) {
1938 /* Buffer overflow, so do not generate event */
1943 (void) pthread_mutex_unlock(&cp
->rc_annotate_lock
);
1948 client_annotation_finished()
1950 thread_info_t
*ti
= thread_self();
1951 repcache_client_t
*cp
= ti
->ti_active_client
;
1953 (void) pthread_mutex_lock(&cp
->rc_annotate_lock
);
1954 cp
->rc_annotate
= 0;
1955 (void) pthread_mutex_unlock(&cp
->rc_annotate_lock
);
1958 #ifndef NATIVE_BUILD
1960 start_audit_session(repcache_client_t
*cp
)
1962 ucred_t
*cred
= NULL
;
1963 adt_session_data_t
*session
;
1966 * A NULL session pointer value can legally be used in all
1967 * subsequent calls to adt_* functions.
1969 cp
->rc_adt_session
= NULL
;
1971 if (!adt_audit_state(AUC_AUDITING
))
1974 if (door_ucred(&cred
) != 0) {
1978 syslog(LOG_ERR
, gettext("start_audit_session(): cannot "
1979 "get ucred. %m\n"));
1983 * Door client went away. This is a normal,
1984 * although infrequent event, so there is no need
1985 * to create a syslog message.
1990 bad_error("door_ucred", errno
);
1994 if (adt_start_session(&session
, NULL
, 0) != 0) {
1995 syslog(LOG_ERR
, gettext("start_audit_session(): could not "
1996 "start audit session.\n"));
2000 if (adt_set_from_ucred(session
, cred
, ADT_NEW
) != 0) {
2001 syslog(LOG_ERR
, gettext("start_audit_session(): cannot set "
2002 "audit session data from ucred\n"));
2003 /* Something went wrong. End the session. */
2004 (void) adt_end_session(session
);
2009 /* All went well. Save the session data and session ID */
2010 cp
->rc_adt_session
= session
;
2011 adt_get_asid(session
, &cp
->rc_adt_sessionid
);
2018 * Handle switch client request
2020 * This routine can return:
2022 * _PERMISSION_DENIED not enough privileges to do request.
2023 * _UNKNOWN file operation error (details written to
2025 * _SUCCESS switch operation is completed.
2026 * _BACKEND_ACCESS backend access fails.
2027 * _NO_RESOURCES out of memory.
2028 * _BACKEND_READONLY backend is not writable.
2030 static rep_protocol_responseid_t
2031 repository_switch(repcache_client_t
*cp
,
2032 struct rep_protocol_switch_request
*rpr
)
2034 rep_protocol_responseid_t result
;
2035 ucred_t
*uc
= get_ucred();
2037 if (!client_is_privileged() && (uc
== NULL
||
2038 ucred_geteuid(uc
) != 0)) {
2039 return (REP_PROTOCOL_FAIL_PERMISSION_DENIED
);
2042 (void) pthread_mutex_lock(&cp
->rc_lock
);
2043 if (rpr
->rpr_changeid
!= cp
->rc_changeid
) {
2044 if ((result
= backend_switch(rpr
->rpr_flag
)) ==
2045 REP_PROTOCOL_SUCCESS
)
2046 cp
->rc_changeid
= rpr
->rpr_changeid
;
2048 result
= REP_PROTOCOL_SUCCESS
;
2050 (void) pthread_mutex_unlock(&cp
->rc_lock
);
2055 typedef rep_protocol_responseid_t
protocol_simple_f(repcache_client_t
*cp
,
2060 simple_handler(repcache_client_t
*cp
, const void *in
, size_t insz
,
2061 void *out_arg
, size_t *outsz
, void *arg
)
2063 protocol_simple_f
*f
= (protocol_simple_f
*)arg
;
2064 rep_protocol_response_t
*out
= out_arg
;
2066 assert(*outsz
== sizeof (*out
));
2069 out
->rpr_response
= (*f
)(cp
, in
);
2072 typedef rep_protocol_responseid_t
protocol_simple_fd_f(repcache_client_t
*cp
,
2073 const void *rpr
, int *out_fd
);
2077 simple_fd_handler(repcache_client_t
*cp
, const void *in
, size_t insz
,
2078 void *out_arg
, size_t *outsz
, void *arg
, int *out_fd
)
2080 protocol_simple_fd_f
*f
= (protocol_simple_fd_f
*)arg
;
2081 rep_protocol_response_t
*out
= out_arg
;
2083 assert(*outsz
== sizeof (*out
));
2086 out
->rpr_response
= (*f
)(cp
, in
, out_fd
);
2089 typedef void protocol_handler_f(repcache_client_t
*, const void *in
,
2090 size_t insz
, void *out
, size_t *outsz
, void *arg
);
2092 typedef void protocol_handler_fdret_f(repcache_client_t
*, const void *in
,
2093 size_t insz
, void *out
, size_t *outsz
, void *arg
, int *fd_out
);
2095 #define PROTO(p, f, in) { \
2096 p, #p, simple_handler, (void *)(&f), NULL, \
2097 sizeof (in), sizeof (rep_protocol_response_t), 0 \
2100 #define PROTO_FD_OUT(p, f, in) { \
2101 p, #p, NULL, (void *)(&f), simple_fd_handler, \
2103 sizeof (rep_protocol_response_t), \
2107 #define PROTO_VARIN(p, f, insz) { \
2108 p, #p, &(f), NULL, NULL, \
2109 insz, sizeof (rep_protocol_response_t), \
2110 PROTO_FLAG_VARINPUT \
2113 #define PROTO_UINT_OUT(p, f, in) { \
2114 p, #p, &(f), NULL, NULL, \
2116 sizeof (struct rep_protocol_integer_response), 0 \
2119 #define PROTO_NAME_OUT(p, f, in) { \
2120 p, #p, &(f), NULL, NULL, \
2122 sizeof (struct rep_protocol_name_response), 0 \
2125 #define PROTO_FMRI_OUT(p, f, in) { \
2126 p, #p, &(f), NULL, NULL, \
2128 sizeof (struct rep_protocol_fmri_response), 0 \
2131 #define PROTO_VALUE_OUT(p, f, in) { \
2132 p, #p, &(f), NULL, NULL, \
2134 sizeof (struct rep_protocol_value_response), 0 \
2137 #define PROTO_PANIC(p) { p, #p, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC }
2138 #define PROTO_END() { 0, NULL, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC }
2140 #define PROTO_FLAG_PANIC 0x00000001 /* should never be called */
2141 #define PROTO_FLAG_VARINPUT 0x00000004 /* in_size is minimum size */
2142 #define PROTO_FLAG_RETFD 0x00000008 /* can also return an FD */
2144 #define PROTO_ALL_FLAGS 0x0000000f /* all flags */
2146 static struct protocol_entry
{
2147 enum rep_protocol_requestid pt_request
;
2148 const char *pt_name
;
2149 protocol_handler_f
*pt_handler
;
2151 protocol_handler_fdret_f
*pt_fd_handler
;
2155 } protocol_table
[] = {
2156 PROTO_PANIC(REP_PROTOCOL_CLOSE
), /* special case */
2158 PROTO(REP_PROTOCOL_ENTITY_SETUP
, entity_setup
,
2159 struct rep_protocol_entity_setup
),
2160 PROTO_NAME_OUT(REP_PROTOCOL_ENTITY_NAME
, entity_name
,
2161 struct rep_protocol_entity_name
),
2162 PROTO_UINT_OUT(REP_PROTOCOL_ENTITY_PARENT_TYPE
, entity_parent_type
,
2163 struct rep_protocol_entity_parent_type
),
2164 PROTO(REP_PROTOCOL_ENTITY_GET_CHILD
, entity_get_child
,
2165 struct rep_protocol_entity_get_child
),
2166 PROTO(REP_PROTOCOL_ENTITY_GET_PARENT
, entity_get_parent
,
2167 struct rep_protocol_entity_parent
),
2168 PROTO(REP_PROTOCOL_ENTITY_GET
, entity_get
,
2169 struct rep_protocol_entity_get
),
2170 PROTO(REP_PROTOCOL_ENTITY_UPDATE
, entity_update
,
2171 struct rep_protocol_entity_update
),
2172 PROTO(REP_PROTOCOL_ENTITY_CREATE_CHILD
, entity_create_child
,
2173 struct rep_protocol_entity_create_child
),
2174 PROTO(REP_PROTOCOL_ENTITY_CREATE_PG
, entity_create_pg
,
2175 struct rep_protocol_entity_create_pg
),
2176 PROTO(REP_PROTOCOL_ENTITY_DELETE
, entity_delete
,
2177 struct rep_protocol_entity_delete
),
2178 PROTO(REP_PROTOCOL_ENTITY_RESET
, entity_reset
,
2179 struct rep_protocol_entity_reset
),
2180 PROTO(REP_PROTOCOL_ENTITY_TEARDOWN
, entity_teardown
,
2181 struct rep_protocol_entity_teardown
),
2183 PROTO(REP_PROTOCOL_ITER_SETUP
, iter_setup
,
2184 struct rep_protocol_iter_request
),
2185 PROTO(REP_PROTOCOL_ITER_START
, iter_start
,
2186 struct rep_protocol_iter_start
),
2187 PROTO(REP_PROTOCOL_ITER_READ
, iter_read
,
2188 struct rep_protocol_iter_read
),
2189 PROTO_VALUE_OUT(REP_PROTOCOL_ITER_READ_VALUE
, iter_read_value
,
2190 struct rep_protocol_iter_read_value
),
2191 PROTO(REP_PROTOCOL_ITER_RESET
, iter_reset
,
2192 struct rep_protocol_iter_request
),
2193 PROTO(REP_PROTOCOL_ITER_TEARDOWN
, iter_teardown
,
2194 struct rep_protocol_iter_request
),
2196 PROTO(REP_PROTOCOL_NEXT_SNAPLEVEL
, next_snaplevel
,
2197 struct rep_protocol_entity_pair
),
2199 PROTO(REP_PROTOCOL_SNAPSHOT_TAKE
, snapshot_take
,
2200 struct rep_protocol_snapshot_take
),
2201 PROTO(REP_PROTOCOL_SNAPSHOT_TAKE_NAMED
, snapshot_take_named
,
2202 struct rep_protocol_snapshot_take_named
),
2203 PROTO(REP_PROTOCOL_SNAPSHOT_ATTACH
, snapshot_attach
,
2204 struct rep_protocol_snapshot_attach
),
2206 PROTO_UINT_OUT(REP_PROTOCOL_PROPERTY_GET_TYPE
, property_get_type
,
2207 struct rep_protocol_property_request
),
2208 PROTO_VALUE_OUT(REP_PROTOCOL_PROPERTY_GET_VALUE
, property_get_value
,
2209 struct rep_protocol_property_request
),
2211 PROTO_FD_OUT(REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT
, propertygrp_notify
,
2212 struct rep_protocol_propertygrp_request
),
2213 PROTO(REP_PROTOCOL_PROPERTYGRP_TX_START
, tx_start
,
2214 struct rep_protocol_transaction_start
),
2215 PROTO_VARIN(REP_PROTOCOL_PROPERTYGRP_TX_COMMIT
, tx_commit
,
2216 REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE
),
2218 PROTO(REP_PROTOCOL_CLIENT_ADD_NOTIFY
, client_add_notify
,
2219 struct rep_protocol_notify_request
),
2220 PROTO_FMRI_OUT(REP_PROTOCOL_CLIENT_WAIT
, client_wait
,
2221 struct rep_protocol_wait_request
),
2223 PROTO(REP_PROTOCOL_BACKUP
, backup_repository
,
2224 struct rep_protocol_backup_request
),
2226 PROTO(REP_PROTOCOL_SET_AUDIT_ANNOTATION
, set_annotation
,
2227 struct rep_protocol_annotation
),
2229 PROTO(REP_PROTOCOL_SWITCH
, repository_switch
,
2230 struct rep_protocol_switch_request
),
2235 #undef PROTO_FMRI_OUT
2236 #undef PROTO_NAME_OUT
2237 #undef PROTO_UINT_OUT
2242 * The number of entries, sans PROTO_END()
2244 #define PROTOCOL_ENTRIES \
2245 (sizeof (protocol_table) / sizeof (*protocol_table) - 1)
2247 #define PROTOCOL_PREFIX "REP_PROTOCOL_"
2253 struct protocol_entry
*e
;
2255 if (!client_hash_init())
2258 if (request_log_size
> 0) {
2259 request_log
= uu_zalloc(request_log_size
*
2260 sizeof (request_log_entry_t
));
2264 * update the names to not include REP_PROTOCOL_
2266 for (i
= 0; i
< PROTOCOL_ENTRIES
; i
++) {
2267 e
= &protocol_table
[i
];
2268 assert(strncmp(e
->pt_name
, PROTOCOL_PREFIX
,
2269 strlen(PROTOCOL_PREFIX
)) == 0);
2270 e
->pt_name
+= strlen(PROTOCOL_PREFIX
);
2273 * verify the protocol table is consistent
2275 for (i
= 0; i
< PROTOCOL_ENTRIES
; i
++) {
2276 e
= &protocol_table
[i
];
2277 assert(e
->pt_request
== (REP_PROTOCOL_BASE
+ i
));
2279 assert((e
->pt_flags
& ~PROTO_ALL_FLAGS
) == 0);
2281 if (e
->pt_flags
& PROTO_FLAG_PANIC
)
2282 assert(e
->pt_in_size
== 0 && e
->pt_out_max
== 0 &&
2283 e
->pt_handler
== NULL
);
2285 assert(e
->pt_in_size
!= 0 && e
->pt_out_max
!= 0 &&
2286 (e
->pt_handler
!= NULL
||
2287 e
->pt_fd_handler
!= NULL
));
2289 assert((REP_PROTOCOL_BASE
+ i
) == REP_PROTOCOL_MAX_REQUEST
);
2291 assert(protocol_table
[i
].pt_request
== 0);
2297 client_switcher(void *cookie
, char *argp
, size_t arg_size
, door_desc_t
*desc_in
,
2300 thread_info_t
*ti
= thread_self();
2302 repcache_client_t
*cp
;
2303 uint32_t id
= (uint32_t)cookie
;
2304 enum rep_protocol_requestid request_code
;
2306 rep_protocol_responseid_t result
= INVALID_RESULT
;
2308 struct protocol_entry
*e
;
2310 char *retval
= NULL
;
2315 request_log_entry_t
*rlp
;
2317 rlp
= start_log(id
);
2320 uu_die("can't happen: %d descriptors @%p (cookie %p)",
2321 n_desc
, desc_in
, cookie
);
2323 if (argp
== DOOR_UNREF_DATA
) {
2328 thread_newstate(ti
, TI_CLIENT_CALL
);
2331 * To simplify returning just a result code, we set up for
2334 retval
= (char *)&result
;
2335 retsize
= sizeof (result
);
2337 if (arg_size
< sizeof (request_code
)) {
2338 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
2342 ti
->ti_client_request
= (void *)argp
;
2344 /* LINTED alignment */
2345 request_code
= *(uint32_t *)argp
;
2348 rlp
->rl_request
= request_code
;
2351 * In order to avoid locking problems on removal, we handle the
2352 * "close" case before doing a lookup.
2354 if (request_code
== REP_PROTOCOL_CLOSE
) {
2356 result
= REP_PROTOCOL_SUCCESS
;
2360 cp
= client_lookup(id
);
2369 rlp
->rl_client
= cp
;
2371 ti
->ti_active_client
= cp
;
2373 if (request_code
< REP_PROTOCOL_BASE
||
2374 request_code
>= REP_PROTOCOL_BASE
+ PROTOCOL_ENTRIES
) {
2375 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
2379 e
= &protocol_table
[request_code
- REP_PROTOCOL_BASE
];
2381 assert(!(e
->pt_flags
& PROTO_FLAG_PANIC
));
2383 if (e
->pt_flags
& PROTO_FLAG_VARINPUT
) {
2384 if (arg_size
< e
->pt_in_size
) {
2385 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
2388 } else if (arg_size
!= e
->pt_in_size
) {
2389 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
2393 if (retsize
!= e
->pt_out_max
) {
2394 retsize
= e
->pt_out_max
;
2395 retval
= alloca(retsize
);
2398 if (e
->pt_flags
& PROTO_FLAG_RETFD
)
2399 e
->pt_fd_handler(cp
, argp
, arg_size
, retval
, &retsize
,
2402 e
->pt_handler(cp
, argp
, arg_size
, retval
, &retsize
, e
->pt_arg
);
2405 ti
->ti_active_client
= NULL
;
2410 /* LINTED alignment */
2411 rlp
->rl_response
= *(uint32_t *)retval
;
2415 ti
->ti_client_request
= NULL
;
2416 thread_newstate(ti
, TI_DOOR_RETURN
);
2418 if (retval
== (char *)&result
) {
2419 assert(result
!= INVALID_RESULT
&& retsize
== sizeof (result
));
2421 /* LINTED alignment */
2422 result
= *(uint32_t *)retval
;
2425 desc
.d_attributes
= DOOR_DESCRIPTOR
| DOOR_RELEASE
;
2426 desc
.d_data
.d_desc
.d_descriptor
= retfd
;
2427 (void) door_return(retval
, retsize
, &desc
, 1);
2429 (void) door_return(retval
, retsize
, NULL
, 0);
2433 rlp
->rl_response
= -1;
2437 (void) door_return(NULL
, 0, NULL
, 0);
2441 create_client(pid_t pid
, uint32_t debugflags
, int privileged
, int *out_fd
)
2445 repcache_client_t
*cp
;
2447 struct door_info info
;
2449 int door_flags
= DOOR_UNREF
| DOOR_REFUSE_DESC
;
2450 #ifdef DOOR_NO_CANCEL
2451 door_flags
|= DOOR_NO_CANCEL
;
2454 cp
= client_alloc();
2456 return (REPOSITORY_DOOR_FAIL_NO_RESOURCES
);
2458 (void) pthread_mutex_lock(&client_lock
);
2459 cp
->rc_id
= ++client_maxid
;
2460 (void) pthread_mutex_unlock(&client_lock
);
2462 cp
->rc_all_auths
= privileged
;
2464 cp
->rc_debug
= debugflags
;
2466 #ifndef NATIVE_BUILD
2467 start_audit_session(cp
);
2470 cp
->rc_doorfd
= door_create(client_switcher
, (void *)cp
->rc_id
,
2473 if (cp
->rc_doorfd
< 0) {
2475 return (REPOSITORY_DOOR_FAIL_NO_RESOURCES
);
2477 #ifdef DOOR_PARAM_DATA_MIN
2478 (void) door_setparam(cp
->rc_doorfd
, DOOR_PARAM_DATA_MIN
,
2479 sizeof (enum rep_protocol_requestid
));
2482 if ((fd
= dup(cp
->rc_doorfd
)) < 0 ||
2483 door_info(cp
->rc_doorfd
, &info
) < 0) {
2486 (void) door_revoke(cp
->rc_doorfd
);
2489 return (REPOSITORY_DOOR_FAIL_NO_RESOURCES
);
2492 rc_pg_notify_init(&cp
->rc_pg_notify
);
2493 rc_notify_info_init(&cp
->rc_notify_info
);
2497 cp
->rc_doorid
= info
.di_uniquifier
;
2500 return (REPOSITORY_DOOR_SUCCESS
);