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
63 #define assert_nolint(x) assert(x)
66 * Protects client linkage and the freelist
68 #define CLIENT_HASH_SIZE 64
70 #pragma align 64(client_hash)
71 static client_bucket_t client_hash
[CLIENT_HASH_SIZE
];
73 static uu_avl_pool_t
*entity_pool
;
74 static uu_avl_pool_t
*iter_pool
;
75 static uu_list_pool_t
*client_pool
;
77 #define CLIENT_HASH(id) (&client_hash[((id) & (CLIENT_HASH_SIZE - 1))])
79 uint_t request_log_size
= 1024; /* tunable, before we start */
81 static pthread_mutex_t request_log_lock
= PTHREAD_MUTEX_INITIALIZER
;
82 static uint_t request_log_cur
;
83 request_log_entry_t
*request_log
;
85 static uint32_t client_maxid
;
86 static pthread_mutex_t client_lock
; /* protects client_maxid */
88 static request_log_entry_t
*
91 thread_info_t
*ti
= thread_self();
96 log_enter(request_log_entry_t
*rlp
)
98 if (rlp
->rl_start
!= 0 && request_log
!= NULL
) {
99 request_log_entry_t
*logrlp
;
101 (void) pthread_mutex_lock(&request_log_lock
);
102 assert(request_log_cur
< request_log_size
);
103 logrlp
= &request_log
[request_log_cur
++];
104 if (request_log_cur
== request_log_size
)
106 (void) memcpy(logrlp
, rlp
, sizeof (*rlp
));
107 (void) pthread_mutex_unlock(&request_log_lock
);
112 * Note that the svc.configd dmod will join all of the per-thread log entries
113 * with the main log, so that even if the log is disabled, there is some
114 * information available.
116 static request_log_entry_t
*
117 start_log(uint32_t clientid
)
119 request_log_entry_t
*rlp
= get_log();
123 (void) memset(rlp
, 0, sizeof (*rlp
));
124 rlp
->rl_start
= gethrtime();
125 rlp
->rl_tid
= pthread_self();
126 rlp
->rl_clientid
= clientid
;
134 request_log_entry_t
*rlp
= get_log();
136 rlp
->rl_end
= gethrtime();
140 add_log_ptr(request_log_entry_t
*rlp
, enum rc_ptr_type type
, uint32_t id
,
143 request_log_ptr_t
*rpp
;
148 if (rlp
->rl_num_ptrs
>= MAX_PTRS
)
151 rpp
= &rlp
->rl_ptrs
[rlp
->rl_num_ptrs
++];
152 rpp
->rlp_type
= type
;
157 * For entities, it's useful to have the node pointer at the start
160 if (type
== RC_PTR_TYPE_ENTITY
&& ptr
!= NULL
)
161 rpp
->rlp_data
= ((repcache_entity_t
*)ptr
)->re_node
.rnp_node
;
165 client_is_privileged(void)
167 thread_info_t
*ti
= thread_self();
171 if (ti
->ti_active_client
!= NULL
&&
172 ti
->ti_active_client
->rc_all_auths
)
175 if ((uc
= get_ucred()) == NULL
)
178 return (ucred_is_privileged(uc
));
183 client_compare(const void *lc_arg
, const void *rc_arg
, void *private)
185 uint32_t l_id
= ((const repcache_client_t
*)lc_arg
)->rc_id
;
186 uint32_t r_id
= ((const repcache_client_t
*)rc_arg
)->rc_id
;
197 entity_compare(const void *lc_arg
, const void *rc_arg
, void *private)
199 uint32_t l_id
= ((const repcache_entity_t
*)lc_arg
)->re_id
;
200 uint32_t r_id
= ((const repcache_entity_t
*)rc_arg
)->re_id
;
211 iter_compare(const void *lc_arg
, const void *rc_arg
, void *private)
213 uint32_t l_id
= ((const repcache_iter_t
*)lc_arg
)->ri_id
;
214 uint32_t r_id
= ((const repcache_iter_t
*)rc_arg
)->ri_id
;
224 client_hash_init(void)
228 assert_nolint(offsetof(repcache_entity_t
, re_id
) == 0);
229 entity_pool
= uu_avl_pool_create("repcache_entitys",
230 sizeof (repcache_entity_t
), offsetof(repcache_entity_t
, re_link
),
231 entity_compare
, UU_AVL_POOL_DEBUG
);
233 assert_nolint(offsetof(repcache_iter_t
, ri_id
) == 0);
234 iter_pool
= uu_avl_pool_create("repcache_iters",
235 sizeof (repcache_iter_t
), offsetof(repcache_iter_t
, ri_link
),
236 iter_compare
, UU_AVL_POOL_DEBUG
);
238 assert_nolint(offsetof(repcache_client_t
, rc_id
) == 0);
239 client_pool
= uu_list_pool_create("repcache_clients",
240 sizeof (repcache_client_t
), offsetof(repcache_client_t
, rc_link
),
241 client_compare
, UU_LIST_POOL_DEBUG
);
243 if (entity_pool
== NULL
|| iter_pool
== NULL
|| client_pool
== NULL
)
246 for (x
= 0; x
< CLIENT_HASH_SIZE
; x
++) {
247 uu_list_t
*lp
= uu_list_create(client_pool
, &client_hash
[x
],
252 (void) pthread_mutex_init(&client_hash
[x
].cb_lock
, NULL
);
253 client_hash
[x
].cb_list
= lp
;
259 static repcache_client_t
*
262 repcache_client_t
*cp
;
263 cp
= uu_zalloc(sizeof (*cp
));
267 cp
->rc_entities
= uu_avl_create(entity_pool
, cp
, 0);
268 if (cp
->rc_entities
== NULL
)
271 cp
->rc_iters
= uu_avl_create(iter_pool
, cp
, 0);
272 if (cp
->rc_iters
== NULL
)
275 uu_list_node_init(cp
, &cp
->rc_link
, client_pool
);
278 cp
->rc_doorid
= INVALID_DOORID
;
280 (void) pthread_mutex_init(&cp
->rc_lock
, NULL
);
281 (void) pthread_mutex_init(&cp
->rc_annotate_lock
, NULL
);
283 rc_node_ptr_init(&cp
->rc_notify_ptr
);
288 if (cp
->rc_iters
!= NULL
)
289 uu_avl_destroy(cp
->rc_iters
);
290 if (cp
->rc_entities
!= NULL
)
291 uu_avl_destroy(cp
->rc_entities
);
297 client_free(repcache_client_t
*cp
)
299 assert(cp
->rc_insert_thr
== 0);
300 assert(cp
->rc_refcnt
== 0);
301 assert(cp
->rc_doorfd
== -1);
302 assert(cp
->rc_doorid
== INVALID_DOORID
);
303 assert(uu_avl_first(cp
->rc_entities
) == NULL
);
304 assert(uu_avl_first(cp
->rc_iters
) == NULL
);
305 uu_avl_destroy(cp
->rc_entities
);
306 uu_avl_destroy(cp
->rc_iters
);
307 uu_list_node_fini(cp
, &cp
->rc_link
, client_pool
);
308 (void) pthread_mutex_destroy(&cp
->rc_lock
);
309 (void) pthread_mutex_destroy(&cp
->rc_annotate_lock
);
310 rc_node_ptr_free_mem(&cp
->rc_notify_ptr
);
315 client_insert(repcache_client_t
*cp
)
317 client_bucket_t
*bp
= CLIENT_HASH(cp
->rc_id
);
320 assert(cp
->rc_id
> 0);
322 (void) pthread_mutex_lock(&bp
->cb_lock
);
324 * We assume it does not already exist
326 (void) uu_list_find(bp
->cb_list
, cp
, NULL
, &idx
);
327 uu_list_insert(bp
->cb_list
, cp
, idx
);
329 (void) pthread_mutex_unlock(&bp
->cb_lock
);
332 static repcache_client_t
*
333 client_lookup(uint32_t id
)
335 client_bucket_t
*bp
= CLIENT_HASH(id
);
336 repcache_client_t
*cp
;
338 (void) pthread_mutex_lock(&bp
->cb_lock
);
340 cp
= uu_list_find(bp
->cb_list
, &id
, NULL
, NULL
);
343 * Bump the reference count
346 (void) pthread_mutex_lock(&cp
->rc_lock
);
347 assert(!(cp
->rc_flags
& RC_CLIENT_DEAD
));
349 (void) pthread_mutex_unlock(&cp
->rc_lock
);
351 (void) pthread_mutex_unlock(&bp
->cb_lock
);
357 client_release(repcache_client_t
*cp
)
359 (void) pthread_mutex_lock(&cp
->rc_lock
);
360 assert(cp
->rc_refcnt
> 0);
361 assert(cp
->rc_insert_thr
!= pthread_self());
364 (void) pthread_cond_broadcast(&cp
->rc_cv
);
365 (void) pthread_mutex_unlock(&cp
->rc_lock
);
369 * We only allow one thread to be inserting at a time, to prevent
370 * insert/insert races.
373 client_start_insert(repcache_client_t
*cp
)
375 (void) pthread_mutex_lock(&cp
->rc_lock
);
376 assert(cp
->rc_refcnt
> 0);
378 while (cp
->rc_insert_thr
!= 0) {
379 assert(cp
->rc_insert_thr
!= pthread_self());
380 (void) pthread_cond_wait(&cp
->rc_cv
, &cp
->rc_lock
);
382 cp
->rc_insert_thr
= pthread_self();
383 (void) pthread_mutex_unlock(&cp
->rc_lock
);
387 client_end_insert(repcache_client_t
*cp
)
389 (void) pthread_mutex_lock(&cp
->rc_lock
);
390 assert(cp
->rc_insert_thr
== pthread_self());
391 cp
->rc_insert_thr
= 0;
392 (void) pthread_cond_broadcast(&cp
->rc_cv
);
393 (void) pthread_mutex_unlock(&cp
->rc_lock
);
397 static repcache_entity_t
*
398 entity_alloc(repcache_client_t
*cp
)
400 repcache_entity_t
*ep
= uu_zalloc(sizeof (repcache_entity_t
));
402 uu_avl_node_init(ep
, &ep
->re_link
, entity_pool
);
408 entity_add(repcache_client_t
*cp
, repcache_entity_t
*ep
)
412 (void) pthread_mutex_lock(&cp
->rc_lock
);
413 assert(cp
->rc_insert_thr
== pthread_self());
415 (void) uu_avl_find(cp
->rc_entities
, ep
, NULL
, &idx
);
416 uu_avl_insert(cp
->rc_entities
, ep
, idx
);
418 (void) pthread_mutex_unlock(&cp
->rc_lock
);
421 static repcache_entity_t
*
422 entity_find(repcache_client_t
*cp
, uint32_t id
)
424 repcache_entity_t
*ep
;
426 (void) pthread_mutex_lock(&cp
->rc_lock
);
427 ep
= uu_avl_find(cp
->rc_entities
, &id
, NULL
, NULL
);
429 add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY
, id
, ep
);
430 (void) pthread_mutex_lock(&ep
->re_lock
);
432 (void) pthread_mutex_unlock(&cp
->rc_lock
);
439 * _DUPLICATE_ID - the ids are equal
440 * _UNKNOWN_ID - an id does not designate an active register
443 entity_find2(repcache_client_t
*cp
, uint32_t id1
, repcache_entity_t
**out1
,
444 uint32_t id2
, repcache_entity_t
**out2
)
446 repcache_entity_t
*e1
, *e2
;
447 request_log_entry_t
*rlp
;
450 return (REP_PROTOCOL_FAIL_DUPLICATE_ID
);
452 (void) pthread_mutex_lock(&cp
->rc_lock
);
453 e1
= uu_avl_find(cp
->rc_entities
, &id1
, NULL
, NULL
);
454 e2
= uu_avl_find(cp
->rc_entities
, &id2
, NULL
, NULL
);
455 if (e1
== NULL
|| e2
== NULL
) {
456 (void) pthread_mutex_unlock(&cp
->rc_lock
);
457 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
463 * locks are ordered by id number
466 (void) pthread_mutex_lock(&e1
->re_lock
);
467 (void) pthread_mutex_lock(&e2
->re_lock
);
469 (void) pthread_mutex_lock(&e2
->re_lock
);
470 (void) pthread_mutex_lock(&e1
->re_lock
);
475 (void) pthread_mutex_unlock(&cp
->rc_lock
);
477 if ((rlp
= get_log()) != NULL
) {
478 add_log_ptr(rlp
, RC_PTR_TYPE_ENTITY
, id1
, e1
);
479 add_log_ptr(rlp
, RC_PTR_TYPE_ENTITY
, id2
, e2
);
482 return (REP_PROTOCOL_SUCCESS
);
486 entity_release(repcache_entity_t
*ep
)
488 assert(ep
->re_node
.rnp_node
== NULL
||
489 !MUTEX_HELD(&ep
->re_node
.rnp_node
->rn_lock
));
490 (void) pthread_mutex_unlock(&ep
->re_lock
);
494 entity_destroy(repcache_entity_t
*entity
)
496 (void) pthread_mutex_lock(&entity
->re_lock
);
497 rc_node_clear(&entity
->re_node
, 0);
498 (void) pthread_mutex_unlock(&entity
->re_lock
);
500 uu_avl_node_fini(entity
, &entity
->re_link
, entity_pool
);
501 (void) pthread_mutex_destroy(&entity
->re_lock
);
502 rc_node_ptr_free_mem(&entity
->re_node
);
507 entity_remove(repcache_client_t
*cp
, uint32_t id
)
509 repcache_entity_t
*entity
;
511 (void) pthread_mutex_lock(&cp
->rc_lock
);
512 entity
= uu_avl_find(cp
->rc_entities
, &id
, NULL
, NULL
);
513 if (entity
!= NULL
) {
514 add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY
, id
, entity
);
516 uu_avl_remove(cp
->rc_entities
, entity
);
518 (void) pthread_mutex_unlock(&cp
->rc_lock
);
521 entity_destroy(entity
);
525 entity_cleanup(repcache_client_t
*cp
)
527 repcache_entity_t
*ep
;
530 (void) pthread_mutex_lock(&cp
->rc_lock
);
531 while ((ep
= uu_avl_teardown(cp
->rc_entities
, &cookie
)) != NULL
) {
532 (void) pthread_mutex_unlock(&cp
->rc_lock
);
534 (void) pthread_mutex_lock(&cp
->rc_lock
);
536 (void) pthread_mutex_unlock(&cp
->rc_lock
);
540 static repcache_iter_t
*
541 iter_alloc(repcache_client_t
*cp
)
543 repcache_iter_t
*iter
;
544 iter
= uu_zalloc(sizeof (repcache_iter_t
));
546 uu_avl_node_init(iter
, &iter
->ri_link
, iter_pool
);
551 iter_add(repcache_client_t
*cp
, repcache_iter_t
*iter
)
555 (void) pthread_mutex_lock(&cp
->rc_lock
);
556 assert(cp
->rc_insert_thr
== pthread_self());
558 (void) uu_avl_find(cp
->rc_iters
, iter
, NULL
, &idx
);
559 uu_avl_insert(cp
->rc_iters
, iter
, idx
);
561 (void) pthread_mutex_unlock(&cp
->rc_lock
);
564 static repcache_iter_t
*
565 iter_find(repcache_client_t
*cp
, uint32_t id
)
567 repcache_iter_t
*iter
;
569 (void) pthread_mutex_lock(&cp
->rc_lock
);
571 iter
= uu_avl_find(cp
->rc_iters
, &id
, NULL
, NULL
);
573 add_log_ptr(get_log(), RC_PTR_TYPE_ITER
, id
, iter
);
574 (void) pthread_mutex_lock(&iter
->ri_lock
);
576 (void) pthread_mutex_unlock(&cp
->rc_lock
);
583 * _UNKNOWN_ID - iter_id or entity_id does not designate an active register
586 iter_find_w_entity(repcache_client_t
*cp
, uint32_t iter_id
,
587 repcache_iter_t
**iterp
, uint32_t entity_id
, repcache_entity_t
**epp
)
589 repcache_iter_t
*iter
;
590 repcache_entity_t
*ep
;
591 request_log_entry_t
*rlp
;
593 (void) pthread_mutex_lock(&cp
->rc_lock
);
594 iter
= uu_avl_find(cp
->rc_iters
, &iter_id
, NULL
, NULL
);
595 ep
= uu_avl_find(cp
->rc_entities
, &entity_id
, NULL
, NULL
);
597 assert(iter
== NULL
|| !MUTEX_HELD(&iter
->ri_lock
));
598 assert(ep
== NULL
|| !MUTEX_HELD(&ep
->re_lock
));
600 if (iter
== NULL
|| ep
== NULL
) {
601 (void) pthread_mutex_unlock(&cp
->rc_lock
);
602 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
605 (void) pthread_mutex_lock(&iter
->ri_lock
);
606 (void) pthread_mutex_lock(&ep
->re_lock
);
608 (void) pthread_mutex_unlock(&cp
->rc_lock
);
613 if ((rlp
= get_log()) != NULL
) {
614 add_log_ptr(rlp
, RC_PTR_TYPE_ENTITY
, entity_id
, ep
);
615 add_log_ptr(rlp
, RC_PTR_TYPE_ITER
, iter_id
, iter
);
618 return (REP_PROTOCOL_SUCCESS
);
622 iter_release(repcache_iter_t
*iter
)
624 (void) pthread_mutex_unlock(&iter
->ri_lock
);
628 iter_destroy(repcache_iter_t
*iter
)
630 (void) pthread_mutex_lock(&iter
->ri_lock
);
631 rc_iter_destroy(&iter
->ri_iter
);
632 (void) pthread_mutex_unlock(&iter
->ri_lock
);
634 uu_avl_node_fini(iter
, &iter
->ri_link
, iter_pool
);
635 (void) pthread_mutex_destroy(&iter
->ri_lock
);
640 iter_remove(repcache_client_t
*cp
, uint32_t id
)
642 repcache_iter_t
*iter
;
644 (void) pthread_mutex_lock(&cp
->rc_lock
);
645 iter
= uu_avl_find(cp
->rc_iters
, &id
, NULL
, NULL
);
647 uu_avl_remove(cp
->rc_iters
, iter
);
648 (void) pthread_mutex_unlock(&cp
->rc_lock
);
655 iter_cleanup(repcache_client_t
*cp
)
657 repcache_iter_t
*iter
;
660 (void) pthread_mutex_lock(&cp
->rc_lock
);
661 while ((iter
= uu_avl_teardown(cp
->rc_iters
, &cookie
)) != NULL
) {
662 (void) pthread_mutex_unlock(&cp
->rc_lock
);
664 (void) pthread_mutex_lock(&cp
->rc_lock
);
666 (void) pthread_mutex_unlock(&cp
->rc_lock
);
670 * Ensure that the passed client id is no longer usable, wait for any
671 * outstanding invocations to complete, then destroy the client
675 client_destroy(uint32_t id
)
677 client_bucket_t
*bp
= CLIENT_HASH(id
);
678 repcache_client_t
*cp
;
680 (void) pthread_mutex_lock(&bp
->cb_lock
);
682 cp
= uu_list_find(bp
->cb_list
, &id
, NULL
, NULL
);
685 (void) pthread_mutex_unlock(&bp
->cb_lock
);
689 uu_list_remove(bp
->cb_list
, cp
);
691 (void) pthread_mutex_unlock(&bp
->cb_lock
);
693 /* kick the waiters out */
694 rc_notify_info_fini(&cp
->rc_notify_info
);
696 (void) pthread_mutex_lock(&cp
->rc_lock
);
697 assert(!(cp
->rc_flags
& RC_CLIENT_DEAD
));
698 cp
->rc_flags
|= RC_CLIENT_DEAD
;
700 if (cp
->rc_doorfd
!= -1) {
701 if (door_revoke(cp
->rc_doorfd
) < 0)
702 perror("door_revoke");
704 cp
->rc_doorid
= INVALID_DOORID
;
707 while (cp
->rc_refcnt
> 0)
708 (void) pthread_cond_wait(&cp
->rc_cv
, &cp
->rc_lock
);
710 assert(cp
->rc_insert_thr
== 0 && cp
->rc_notify_thr
== 0);
711 (void) pthread_mutex_unlock(&cp
->rc_lock
);
714 * destroy outstanding objects
720 * clean up notifications
722 rc_pg_notify_fini(&cp
->rc_pg_notify
);
725 * clean up annotations
727 if (cp
->rc_operation
!= NULL
)
728 free((void *)cp
->rc_operation
);
729 if (cp
->rc_file
!= NULL
)
730 free((void *)cp
->rc_file
);
736 (void) adt_end_session(cp
->rc_adt_session
);
744 * _TYPE_MISMATCH - the entity is already set up with a different type
745 * _NO_RESOURCES - out of memory
748 entity_setup(repcache_client_t
*cp
, struct rep_protocol_entity_setup
*rpr
)
750 repcache_entity_t
*ep
;
753 client_start_insert(cp
);
755 if ((ep
= entity_find(cp
, rpr
->rpr_entityid
)) != NULL
) {
759 client_end_insert(cp
);
761 if (type
!= rpr
->rpr_entitytype
)
762 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
763 return (REP_PROTOCOL_SUCCESS
);
766 switch (type
= rpr
->rpr_entitytype
) {
767 case REP_PROTOCOL_ENTITY_SCOPE
:
768 case REP_PROTOCOL_ENTITY_SERVICE
:
769 case REP_PROTOCOL_ENTITY_INSTANCE
:
770 case REP_PROTOCOL_ENTITY_SNAPSHOT
:
771 case REP_PROTOCOL_ENTITY_SNAPLEVEL
:
772 case REP_PROTOCOL_ENTITY_PROPERTYGRP
:
773 case REP_PROTOCOL_ENTITY_PROPERTY
:
776 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
779 ep
= entity_alloc(cp
);
781 client_end_insert(cp
);
782 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
785 ep
->re_id
= rpr
->rpr_entityid
;
786 ep
->re_changeid
= INVALID_CHANGEID
;
789 rc_node_ptr_init(&ep
->re_node
);
792 client_end_insert(cp
);
793 return (REP_PROTOCOL_SUCCESS
);
798 entity_name(repcache_client_t
*cp
, const void *in
, size_t insz
, void *out_arg
,
799 size_t *outsz
, void *arg
)
801 const struct rep_protocol_entity_name
*rpr
= in
;
802 struct rep_protocol_name_response
*out
= out_arg
;
803 repcache_entity_t
*ep
;
804 size_t sz
= sizeof (out
->rpr_name
);
806 assert(*outsz
== sizeof (*out
));
808 ep
= entity_find(cp
, rpr
->rpr_entityid
);
811 out
->rpr_response
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
812 *outsz
= sizeof (out
->rpr_response
);
815 out
->rpr_response
= rc_node_name(&ep
->re_node
, out
->rpr_name
,
816 sz
, rpr
->rpr_answertype
, &sz
);
820 * If we fail, we only return the response code.
821 * If we succeed, we don't return anything after the '\0' in rpr_name.
823 if (out
->rpr_response
!= REP_PROTOCOL_SUCCESS
)
824 *outsz
= sizeof (out
->rpr_response
);
826 *outsz
= offsetof(struct rep_protocol_name_response
,
832 entity_parent_type(repcache_client_t
*cp
, const void *in
, size_t insz
,
833 void *out_arg
, size_t *outsz
, void *arg
)
835 const struct rep_protocol_entity_name
*rpr
= in
;
836 struct rep_protocol_integer_response
*out
= out_arg
;
837 repcache_entity_t
*ep
;
839 assert(*outsz
== sizeof (*out
));
841 ep
= entity_find(cp
, rpr
->rpr_entityid
);
844 out
->rpr_response
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
845 *outsz
= sizeof (out
->rpr_response
);
849 out
->rpr_response
= rc_node_parent_type(&ep
->re_node
, &out
->rpr_value
);
852 if (out
->rpr_response
!= REP_PROTOCOL_SUCCESS
)
853 *outsz
= sizeof (out
->rpr_response
);
858 * _DUPLICATE_ID - the ids are equal
859 * _UNKNOWN_ID - an id does not designate an active register
860 * _INVALID_TYPE - type is invalid
861 * _TYPE_MISMATCH - np doesn't carry children of type type
862 * _DELETED - np has been deleted
863 * _NOT_FOUND - no child with that name/type combo found
868 entity_get_child(repcache_client_t
*cp
,
869 struct rep_protocol_entity_get_child
*rpr
)
871 repcache_entity_t
*parent
, *child
;
874 uint32_t parentid
= rpr
->rpr_entityid
;
875 uint32_t childid
= rpr
->rpr_childid
;
877 result
= entity_find2(cp
, childid
, &child
, parentid
, &parent
);
878 if (result
!= REP_PROTOCOL_SUCCESS
)
881 rpr
->rpr_name
[sizeof (rpr
->rpr_name
) - 1] = 0;
883 result
= rc_node_get_child(&parent
->re_node
, rpr
->rpr_name
,
884 child
->re_type
, &child
->re_node
);
886 entity_release(child
);
887 entity_release(parent
);
893 * Returns _FAIL_DUPLICATE_ID, _FAIL_UNKNOWN_ID, _FAIL_NOT_SET, _FAIL_DELETED,
894 * _FAIL_TYPE_MISMATCH, _FAIL_NOT_FOUND (scope has no parent), or _SUCCESS.
896 * _DUPLICATE_ID - the ids are equal
897 * _UNKNOWN_ID - an id does not designate an active register
898 * _NOT_SET - child is not set
899 * _DELETED - child has been deleted
900 * _TYPE_MISMATCH - child's parent does not match that of the parent register
901 * _NOT_FOUND - child has no parent (and is a scope)
904 entity_get_parent(repcache_client_t
*cp
, struct rep_protocol_entity_parent
*rpr
)
906 repcache_entity_t
*child
, *parent
;
909 uint32_t childid
= rpr
->rpr_entityid
;
910 uint32_t outid
= rpr
->rpr_outid
;
912 result
= entity_find2(cp
, childid
, &child
, outid
, &parent
);
913 if (result
!= REP_PROTOCOL_SUCCESS
)
916 result
= rc_node_get_parent(&child
->re_node
, parent
->re_type
,
919 entity_release(child
);
920 entity_release(parent
);
926 entity_get(repcache_client_t
*cp
, struct rep_protocol_entity_get
*rpr
)
928 repcache_entity_t
*ep
;
931 ep
= entity_find(cp
, rpr
->rpr_entityid
);
934 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
936 switch (rpr
->rpr_object
) {
937 case RP_ENTITY_GET_INVALIDATE
:
938 rc_node_clear(&ep
->re_node
, 0);
939 result
= REP_PROTOCOL_SUCCESS
;
941 case RP_ENTITY_GET_MOST_LOCAL_SCOPE
:
942 result
= rc_local_scope(ep
->re_type
, &ep
->re_node
);
945 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
955 entity_update(repcache_client_t
*cp
, struct rep_protocol_entity_update
*rpr
)
957 repcache_entity_t
*ep
;
960 if (rpr
->rpr_changeid
== INVALID_CHANGEID
)
961 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
963 ep
= entity_find(cp
, rpr
->rpr_entityid
);
966 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
968 if (ep
->re_changeid
== rpr
->rpr_changeid
) {
969 result
= REP_PROTOCOL_DONE
;
971 result
= rc_node_update(&ep
->re_node
);
972 if (result
== REP_PROTOCOL_DONE
)
973 ep
->re_changeid
= rpr
->rpr_changeid
;
982 entity_reset(repcache_client_t
*cp
, struct rep_protocol_entity_reset
*rpr
)
984 repcache_entity_t
*ep
;
986 ep
= entity_find(cp
, rpr
->rpr_entityid
);
988 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
990 rc_node_clear(&ep
->re_node
, 0);
991 ep
->re_txstate
= REPCACHE_TX_INIT
;
994 return (REP_PROTOCOL_SUCCESS
);
999 * _BAD_REQUEST - request has invalid changeid
1000 * rpr_name is invalid
1001 * cannot create children for parent's type of node
1002 * _DUPLICATE_ID - request has duplicate ids
1003 * _UNKNOWN_ID - request has unknown id
1004 * _DELETED - parent has been deleted
1005 * _NOT_SET - parent is reset
1006 * _NOT_APPLICABLE - rpr_childtype is _PROPERTYGRP
1007 * _INVALID_TYPE - parent is corrupt or rpr_childtype is invalid
1008 * _TYPE_MISMATCH - parent cannot have children of type rpr_childtype
1010 * _PERMISSION_DENIED
1013 * _EXISTS - child already exists
1016 entity_create_child(repcache_client_t
*cp
,
1017 struct rep_protocol_entity_create_child
*rpr
)
1019 repcache_entity_t
*parent
;
1020 repcache_entity_t
*child
;
1022 uint32_t parentid
= rpr
->rpr_entityid
;
1023 uint32_t childid
= rpr
->rpr_childid
;
1027 if (rpr
->rpr_changeid
== INVALID_CHANGEID
)
1028 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1030 result
= entity_find2(cp
, parentid
, &parent
, childid
, &child
);
1031 if (result
!= REP_PROTOCOL_SUCCESS
)
1034 rpr
->rpr_name
[sizeof (rpr
->rpr_name
) - 1] = 0;
1036 if (child
->re_changeid
== rpr
->rpr_changeid
) {
1037 result
= REP_PROTOCOL_SUCCESS
;
1039 result
= rc_node_create_child(&parent
->re_node
,
1040 rpr
->rpr_childtype
, rpr
->rpr_name
, &child
->re_node
);
1041 if (result
== REP_PROTOCOL_SUCCESS
)
1042 child
->re_changeid
= rpr
->rpr_changeid
;
1045 entity_release(parent
);
1046 entity_release(child
);
1052 entity_create_pg(repcache_client_t
*cp
,
1053 struct rep_protocol_entity_create_pg
*rpr
)
1055 repcache_entity_t
*parent
;
1056 repcache_entity_t
*child
;
1058 uint32_t parentid
= rpr
->rpr_entityid
;
1059 uint32_t childid
= rpr
->rpr_childid
;
1063 if (rpr
->rpr_changeid
== INVALID_CHANGEID
)
1064 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1066 result
= entity_find2(cp
, parentid
, &parent
, childid
, &child
);
1067 if (result
!= REP_PROTOCOL_SUCCESS
)
1070 rpr
->rpr_name
[sizeof (rpr
->rpr_name
) - 1] = 0;
1071 rpr
->rpr_type
[sizeof (rpr
->rpr_type
) - 1] = 0;
1073 if (child
->re_changeid
== rpr
->rpr_changeid
) {
1074 result
= REP_PROTOCOL_SUCCESS
;
1076 result
= rc_node_create_child_pg(&parent
->re_node
,
1077 child
->re_type
, rpr
->rpr_name
, rpr
->rpr_type
,
1078 rpr
->rpr_flags
, &child
->re_node
);
1079 if (result
== REP_PROTOCOL_SUCCESS
)
1080 child
->re_changeid
= rpr
->rpr_changeid
;
1083 entity_release(parent
);
1084 entity_release(child
);
1090 entity_delete(repcache_client_t
*cp
,
1091 struct rep_protocol_entity_delete
*rpr
)
1093 repcache_entity_t
*entity
;
1095 uint32_t entityid
= rpr
->rpr_entityid
;
1099 if (rpr
->rpr_changeid
== INVALID_CHANGEID
)
1100 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1102 entity
= entity_find(cp
, entityid
);
1105 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
1107 if (entity
->re_changeid
== rpr
->rpr_changeid
) {
1108 result
= REP_PROTOCOL_SUCCESS
;
1110 result
= rc_node_delete(&entity
->re_node
);
1111 if (result
== REP_PROTOCOL_SUCCESS
)
1112 entity
->re_changeid
= rpr
->rpr_changeid
;
1115 entity_release(entity
);
1120 static rep_protocol_responseid_t
1121 entity_teardown(repcache_client_t
*cp
, struct rep_protocol_entity_teardown
*rpr
)
1123 entity_remove(cp
, rpr
->rpr_entityid
);
1125 return (REP_PROTOCOL_SUCCESS
);
1130 * _MISORDERED - the iterator exists and is not reset
1131 * _NO_RESOURCES - out of memory
1134 iter_setup(repcache_client_t
*cp
, struct rep_protocol_iter_request
*rpr
)
1136 repcache_iter_t
*iter
;
1139 client_start_insert(cp
);
1141 * If the iter already exists, and hasn't been read from,
1142 * we assume the previous call succeeded.
1144 if ((iter
= iter_find(cp
, rpr
->rpr_iterid
)) != NULL
) {
1145 sequence
= iter
->ri_sequence
;
1148 client_end_insert(cp
);
1151 return (REP_PROTOCOL_FAIL_MISORDERED
);
1152 return (REP_PROTOCOL_SUCCESS
);
1155 iter
= iter_alloc(cp
);
1157 client_end_insert(cp
);
1158 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
1161 iter
->ri_id
= rpr
->rpr_iterid
;
1162 iter
->ri_type
= REP_PROTOCOL_TYPE_INVALID
;
1163 iter
->ri_sequence
= 0;
1166 client_end_insert(cp
);
1167 return (REP_PROTOCOL_SUCCESS
);
1173 * _MISORDERED - iterator has already been started
1176 * _TYPE_MISMATCH - entity cannot have type children
1177 * _BAD_REQUEST - rpr_flags is invalid
1178 * rpr_pattern is invalid
1184 iter_start(repcache_client_t
*cp
, struct rep_protocol_iter_start
*rpr
)
1187 repcache_iter_t
*iter
;
1188 repcache_entity_t
*ep
;
1190 result
= iter_find_w_entity(cp
, rpr
->rpr_iterid
, &iter
,
1191 rpr
->rpr_entity
, &ep
);
1193 if (result
!= REP_PROTOCOL_SUCCESS
)
1194 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
1196 if (iter
->ri_sequence
> 1) {
1197 result
= REP_PROTOCOL_FAIL_MISORDERED
;
1201 if (iter
->ri_sequence
== 1) {
1202 result
= REP_PROTOCOL_SUCCESS
;
1206 rpr
->rpr_pattern
[sizeof (rpr
->rpr_pattern
) - 1] = 0;
1208 result
= rc_node_setup_iter(&ep
->re_node
, &iter
->ri_iter
,
1209 rpr
->rpr_itertype
, rpr
->rpr_flags
, rpr
->rpr_pattern
);
1211 if (result
== REP_PROTOCOL_SUCCESS
)
1212 iter
->ri_sequence
++;
1223 * _NOT_SET - iter has not been started
1225 * _BAD_REQUEST - iter walks values
1226 * _TYPE_MISMATCH - iter does not walk type entities
1227 * _DELETED - parent was deleted
1229 * _INVALID_TYPE - type is invalid
1233 * For composed property group iterators, can also return
1234 * _TYPE_MISMATCH - parent cannot have type children
1237 static rep_protocol_responseid_t
1238 iter_read(repcache_client_t
*cp
, struct rep_protocol_iter_read
*rpr
)
1240 rep_protocol_responseid_t result
;
1241 repcache_iter_t
*iter
;
1242 repcache_entity_t
*ep
;
1245 result
= iter_find_w_entity(cp
, rpr
->rpr_iterid
, &iter
,
1246 rpr
->rpr_entityid
, &ep
);
1248 if (result
!= REP_PROTOCOL_SUCCESS
)
1251 sequence
= rpr
->rpr_sequence
;
1253 if (iter
->ri_sequence
== 0) {
1256 return (REP_PROTOCOL_FAIL_NOT_SET
);
1259 if (sequence
== 1) {
1262 return (REP_PROTOCOL_FAIL_MISORDERED
);
1265 if (sequence
== iter
->ri_sequence
) {
1268 return (REP_PROTOCOL_SUCCESS
);
1271 if (sequence
== iter
->ri_sequence
+ 1) {
1272 result
= rc_iter_next(iter
->ri_iter
, &ep
->re_node
,
1275 if (result
== REP_PROTOCOL_SUCCESS
)
1276 iter
->ri_sequence
++;
1286 return (REP_PROTOCOL_FAIL_MISORDERED
);
1291 iter_read_value(repcache_client_t
*cp
, const void *in
, size_t insz
,
1292 void *out_arg
, size_t *outsz
, void *arg
)
1294 const struct rep_protocol_iter_read_value
*rpr
= in
;
1295 struct rep_protocol_value_response
*out
= out_arg
;
1296 rep_protocol_responseid_t result
;
1298 repcache_iter_t
*iter
;
1302 assert(*outsz
== sizeof (*out
));
1304 iter
= iter_find(cp
, rpr
->rpr_iterid
);
1307 result
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1311 sequence
= rpr
->rpr_sequence
;
1313 if (iter
->ri_sequence
== 0) {
1315 result
= REP_PROTOCOL_FAIL_NOT_SET
;
1319 repeat
= (sequence
== iter
->ri_sequence
);
1321 if (sequence
== 1 || (!repeat
&& sequence
!= iter
->ri_sequence
+ 1)) {
1323 result
= REP_PROTOCOL_FAIL_MISORDERED
;
1327 result
= rc_iter_next_value(iter
->ri_iter
, out
, outsz
, repeat
);
1329 if (!repeat
&& result
== REP_PROTOCOL_SUCCESS
)
1330 iter
->ri_sequence
++;
1336 * If we fail, we only return the response code.
1337 * If we succeed, rc_iter_next_value has shortened *outsz
1338 * to only include the value bytes needed.
1340 if (result
!= REP_PROTOCOL_SUCCESS
&& result
!= REP_PROTOCOL_DONE
)
1341 *outsz
= sizeof (out
->rpr_response
);
1343 out
->rpr_response
= result
;
1347 iter_reset(repcache_client_t
*cp
, struct rep_protocol_iter_request
*rpr
)
1349 repcache_iter_t
*iter
= iter_find(cp
, rpr
->rpr_iterid
);
1352 return (REP_PROTOCOL_FAIL_UNKNOWN_ID
);
1354 if (iter
->ri_sequence
!= 0) {
1355 iter
->ri_sequence
= 0;
1356 rc_iter_destroy(&iter
->ri_iter
);
1359 return (REP_PROTOCOL_SUCCESS
);
1362 static rep_protocol_responseid_t
1363 iter_teardown(repcache_client_t
*cp
, struct rep_protocol_iter_request
*rpr
)
1365 iter_remove(cp
, rpr
->rpr_iterid
);
1367 return (REP_PROTOCOL_SUCCESS
);
1370 static rep_protocol_responseid_t
1371 tx_start(repcache_client_t
*cp
, struct rep_protocol_transaction_start
*rpr
)
1373 repcache_entity_t
*tx
;
1374 repcache_entity_t
*ep
;
1375 rep_protocol_responseid_t result
;
1377 uint32_t txid
= rpr
->rpr_entityid_tx
;
1378 uint32_t epid
= rpr
->rpr_entityid
;
1380 result
= entity_find2(cp
, txid
, &tx
, epid
, &ep
);
1381 if (result
!= REP_PROTOCOL_SUCCESS
)
1384 if (tx
->re_txstate
== REPCACHE_TX_SETUP
) {
1385 result
= REP_PROTOCOL_SUCCESS
;
1388 if (tx
->re_txstate
!= REPCACHE_TX_INIT
) {
1389 result
= REP_PROTOCOL_FAIL_MISORDERED
;
1393 result
= rc_node_setup_tx(&ep
->re_node
, &tx
->re_node
);
1396 if (result
== REP_PROTOCOL_SUCCESS
)
1397 tx
->re_txstate
= REPCACHE_TX_SETUP
;
1399 rc_node_clear(&tx
->re_node
, 0);
1408 tx_commit(repcache_client_t
*cp
, const void *in
, size_t insz
,
1409 void *out_arg
, size_t *outsz
, void *arg
)
1411 struct rep_protocol_response
*out
= out_arg
;
1412 const struct rep_protocol_transaction_commit
*rpr
= in
;
1413 repcache_entity_t
*tx
;
1415 assert(*outsz
== sizeof (*out
));
1416 assert(insz
>= REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE
);
1418 if (rpr
->rpr_size
!= insz
) {
1419 out
->rpr_response
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
1423 tx
= entity_find(cp
, rpr
->rpr_entityid
);
1426 out
->rpr_response
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1430 switch (tx
->re_txstate
) {
1431 case REPCACHE_TX_INIT
:
1432 out
->rpr_response
= REP_PROTOCOL_FAIL_MISORDERED
;
1435 case REPCACHE_TX_SETUP
:
1436 out
->rpr_response
= rc_tx_commit(&tx
->re_node
, rpr
->rpr_cmd
,
1437 insz
- REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE
);
1439 if (out
->rpr_response
== REP_PROTOCOL_SUCCESS
) {
1440 tx
->re_txstate
= REPCACHE_TX_COMMITTED
;
1441 rc_node_clear(&tx
->re_node
, 0);
1445 case REPCACHE_TX_COMMITTED
:
1446 out
->rpr_response
= REP_PROTOCOL_SUCCESS
;
1449 assert(0); /* CAN'T HAPPEN */
1456 static rep_protocol_responseid_t
1457 next_snaplevel(repcache_client_t
*cp
, struct rep_protocol_entity_pair
*rpr
)
1459 repcache_entity_t
*src
;
1460 repcache_entity_t
*dest
;
1462 uint32_t srcid
= rpr
->rpr_entity_src
;
1463 uint32_t destid
= rpr
->rpr_entity_dst
;
1467 result
= entity_find2(cp
, srcid
, &src
, destid
, &dest
);
1468 if (result
!= REP_PROTOCOL_SUCCESS
)
1471 result
= rc_node_next_snaplevel(&src
->re_node
, &dest
->re_node
);
1473 entity_release(src
);
1474 entity_release(dest
);
1479 static rep_protocol_responseid_t
1480 snapshot_take(repcache_client_t
*cp
, struct rep_protocol_snapshot_take
*rpr
)
1482 repcache_entity_t
*src
;
1483 uint32_t srcid
= rpr
->rpr_entityid_src
;
1484 repcache_entity_t
*dest
;
1485 uint32_t destid
= rpr
->rpr_entityid_dest
;
1489 result
= entity_find2(cp
, srcid
, &src
, destid
, &dest
);
1490 if (result
!= REP_PROTOCOL_SUCCESS
)
1493 if (dest
->re_type
!= REP_PROTOCOL_ENTITY_SNAPSHOT
) {
1494 result
= REP_PROTOCOL_FAIL_TYPE_MISMATCH
;
1496 rpr
->rpr_name
[sizeof (rpr
->rpr_name
) - 1] = 0;
1498 if (rpr
->rpr_flags
== REP_SNAPSHOT_NEW
)
1499 result
= rc_snapshot_take_new(&src
->re_node
, NULL
,
1500 NULL
, rpr
->rpr_name
, &dest
->re_node
);
1501 else if (rpr
->rpr_flags
== REP_SNAPSHOT_ATTACH
&&
1502 rpr
->rpr_name
[0] == 0)
1503 result
= rc_snapshot_take_attach(&src
->re_node
,
1506 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
1508 entity_release(src
);
1509 entity_release(dest
);
1514 static rep_protocol_responseid_t
1515 snapshot_take_named(repcache_client_t
*cp
,
1516 struct rep_protocol_snapshot_take_named
*rpr
)
1518 repcache_entity_t
*src
;
1519 uint32_t srcid
= rpr
->rpr_entityid_src
;
1520 repcache_entity_t
*dest
;
1521 uint32_t destid
= rpr
->rpr_entityid_dest
;
1525 result
= entity_find2(cp
, srcid
, &src
, destid
, &dest
);
1526 if (result
!= REP_PROTOCOL_SUCCESS
)
1529 if (dest
->re_type
!= REP_PROTOCOL_ENTITY_SNAPSHOT
) {
1530 result
= REP_PROTOCOL_FAIL_TYPE_MISMATCH
;
1532 rpr
->rpr_svcname
[sizeof (rpr
->rpr_svcname
) - 1] = 0;
1533 rpr
->rpr_instname
[sizeof (rpr
->rpr_instname
) - 1] = 0;
1534 rpr
->rpr_name
[sizeof (rpr
->rpr_name
) - 1] = 0;
1536 result
= rc_snapshot_take_new(&src
->re_node
, rpr
->rpr_svcname
,
1537 rpr
->rpr_instname
, rpr
->rpr_name
, &dest
->re_node
);
1539 entity_release(src
);
1540 entity_release(dest
);
1545 static rep_protocol_responseid_t
1546 snapshot_attach(repcache_client_t
*cp
, struct rep_protocol_snapshot_attach
*rpr
)
1548 repcache_entity_t
*src
;
1549 uint32_t srcid
= rpr
->rpr_entityid_src
;
1550 repcache_entity_t
*dest
;
1551 uint32_t destid
= rpr
->rpr_entityid_dest
;
1555 result
= entity_find2(cp
, srcid
, &src
, destid
, &dest
);
1556 if (result
!= REP_PROTOCOL_SUCCESS
)
1559 result
= rc_snapshot_attach(&src
->re_node
, &dest
->re_node
);
1561 entity_release(src
);
1562 entity_release(dest
);
1569 property_get_type(repcache_client_t
*cp
, const void *in
, size_t insz
,
1570 void *out_arg
, size_t *outsz
, void *arg
)
1572 const struct rep_protocol_property_request
*rpr
= in
;
1573 struct rep_protocol_integer_response
*out
= out_arg
;
1574 repcache_entity_t
*ep
;
1575 rep_protocol_value_type_t t
= 0;
1577 assert(*outsz
== sizeof (*out
));
1579 ep
= entity_find(cp
, rpr
->rpr_entityid
);
1582 out
->rpr_response
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1583 *outsz
= sizeof (out
->rpr_response
);
1587 out
->rpr_response
= rc_node_get_property_type(&ep
->re_node
, &t
);
1591 if (out
->rpr_response
!= REP_PROTOCOL_SUCCESS
)
1592 *outsz
= sizeof (out
->rpr_response
);
1599 * _UNKNOWN_ID - an id does not designate an active register
1600 * _NOT_SET - The property is not set
1601 * _DELETED - The property has been deleted
1602 * _TYPE_MISMATCH - The object is not a property
1603 * _NOT_FOUND - The property has no values.
1606 * _SUCCESS - The property has 1 value.
1607 * _TRUNCATED - The property has >1 value.
1611 property_get_value(repcache_client_t
*cp
, const void *in
, size_t insz
,
1612 void *out_arg
, size_t *outsz
, void *arg
)
1614 const struct rep_protocol_property_request
*rpr
= in
;
1615 struct rep_protocol_value_response
*out
= out_arg
;
1616 repcache_entity_t
*ep
;
1618 assert(*outsz
== sizeof (*out
));
1620 ep
= entity_find(cp
, rpr
->rpr_entityid
);
1622 out
->rpr_response
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1623 *outsz
= sizeof (out
->rpr_response
);
1627 out
->rpr_response
= rc_node_get_property_value(&ep
->re_node
, out
,
1633 * If we fail, we only return the response code.
1634 * If we succeed, rc_node_get_property_value has shortened *outsz
1635 * to only include the value bytes needed.
1637 if (out
->rpr_response
!= REP_PROTOCOL_SUCCESS
&&
1638 out
->rpr_response
!= REP_PROTOCOL_FAIL_TRUNCATED
)
1639 *outsz
= sizeof (out
->rpr_response
);
1642 static rep_protocol_responseid_t
1643 propertygrp_notify(repcache_client_t
*cp
,
1644 struct rep_protocol_propertygrp_request
*rpr
, int *out_fd
)
1649 rep_protocol_responseid_t result
;
1650 repcache_entity_t
*ep
;
1653 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
1658 if ((ep
= entity_find(cp
, rpr
->rpr_entityid
)) == NULL
) {
1659 result
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1664 * While the following can race with other threads setting up a
1665 * notification, the worst that can happen is that our fd has
1666 * already been closed before we return.
1668 result
= rc_pg_notify_setup(&cp
->rc_pg_notify
, &ep
->re_node
,
1673 if (result
!= REP_PROTOCOL_SUCCESS
)
1677 return (REP_PROTOCOL_SUCCESS
);
1681 (void) close(theirs
);
1686 static rep_protocol_responseid_t
1687 client_add_notify(repcache_client_t
*cp
,
1688 struct rep_protocol_notify_request
*rpr
)
1690 rpr
->rpr_pattern
[sizeof (rpr
->rpr_pattern
) - 1] = 0;
1692 switch (rpr
->rpr_type
) {
1693 case REP_PROTOCOL_NOTIFY_PGNAME
:
1694 return (rc_notify_info_add_name(&cp
->rc_notify_info
,
1697 case REP_PROTOCOL_NOTIFY_PGTYPE
:
1698 return (rc_notify_info_add_type(&cp
->rc_notify_info
,
1702 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1708 client_wait(repcache_client_t
*cp
, const void *in
, size_t insz
,
1709 void *out_arg
, size_t *outsz
, void *arg
)
1712 repcache_entity_t
*ep
;
1713 const struct rep_protocol_wait_request
*rpr
= in
;
1714 struct rep_protocol_fmri_response
*out
= out_arg
;
1716 assert(*outsz
== sizeof (*out
));
1718 (void) pthread_mutex_lock(&cp
->rc_lock
);
1719 if (cp
->rc_notify_thr
!= 0) {
1720 (void) pthread_mutex_unlock(&cp
->rc_lock
);
1721 out
->rpr_response
= REP_PROTOCOL_FAIL_EXISTS
;
1722 *outsz
= sizeof (out
->rpr_response
);
1725 cp
->rc_notify_thr
= pthread_self();
1726 (void) pthread_mutex_unlock(&cp
->rc_lock
);
1728 result
= rc_notify_info_wait(&cp
->rc_notify_info
, &cp
->rc_notify_ptr
,
1729 out
->rpr_fmri
, sizeof (out
->rpr_fmri
));
1731 if (result
== REP_PROTOCOL_SUCCESS
) {
1732 if ((ep
= entity_find(cp
, rpr
->rpr_entityid
)) != NULL
) {
1733 if (ep
->re_type
== REP_PROTOCOL_ENTITY_PROPERTYGRP
) {
1734 rc_node_ptr_assign(&ep
->re_node
,
1735 &cp
->rc_notify_ptr
);
1737 result
= REP_PROTOCOL_FAIL_TYPE_MISMATCH
;
1741 result
= REP_PROTOCOL_FAIL_UNKNOWN_ID
;
1743 rc_node_clear(&cp
->rc_notify_ptr
, 0);
1746 (void) pthread_mutex_lock(&cp
->rc_lock
);
1747 assert(cp
->rc_notify_thr
== pthread_self());
1748 cp
->rc_notify_thr
= 0;
1749 (void) pthread_mutex_unlock(&cp
->rc_lock
);
1751 out
->rpr_response
= result
;
1752 if (result
!= REP_PROTOCOL_SUCCESS
)
1753 *outsz
= sizeof (out
->rpr_response
);
1758 * _PERMISSION_DENIED not enough privileges to do request.
1759 * _BAD_REQUEST name is not valid or reserved
1760 * _TRUNCATED name is too long for current repository path
1761 * _UNKNOWN failed for unknown reason (details written to
1763 * _BACKEND_READONLY backend is not writable
1764 * _NO_RESOURCES out of memory
1765 * _SUCCESS Backup completed successfully.
1767 static rep_protocol_responseid_t
1768 backup_repository(repcache_client_t
*cp
,
1769 struct rep_protocol_backup_request
*rpr
)
1771 rep_protocol_responseid_t result
;
1772 ucred_t
*uc
= get_ucred();
1774 if (!client_is_privileged() && (uc
== NULL
|| ucred_geteuid(uc
) != 0))
1775 return (REP_PROTOCOL_FAIL_PERMISSION_DENIED
);
1777 rpr
->rpr_name
[REP_PROTOCOL_NAME_LEN
- 1] = 0;
1778 if (strcmp(rpr
->rpr_name
, REPOSITORY_BOOT_BACKUP
) == 0)
1779 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1781 (void) pthread_mutex_lock(&cp
->rc_lock
);
1782 if (rpr
->rpr_changeid
!= cp
->rc_changeid
) {
1783 result
= backend_create_backup(rpr
->rpr_name
);
1784 if (result
== REP_PROTOCOL_SUCCESS
)
1785 cp
->rc_changeid
= rpr
->rpr_changeid
;
1787 result
= REP_PROTOCOL_SUCCESS
;
1789 (void) pthread_mutex_unlock(&cp
->rc_lock
);
1795 * This function captures the information that will be used for an
1796 * annotation audit event. Specifically, it captures the operation to be
1797 * performed and the name of the file that is being used. These values are
1798 * copied from the rep_protocol_annotation request at rpr to the client
1799 * structure. If both these values are null, the client is turning
1803 * _NO_RESOURCES - unable to allocate memory
1805 static rep_protocol_responseid_t
1806 set_annotation(repcache_client_t
*cp
, struct rep_protocol_annotation
*rpr
)
1809 const char *file
= NULL
;
1810 const char *old_ptrs
[2];
1811 const char *operation
= NULL
;
1812 rep_protocol_responseid_t rc
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1813 au_asid_t sessionid
;
1815 (void) memset(old_ptrs
, 0, sizeof (old_ptrs
));
1817 /* Copy rpr_operation and rpr_file if they are not empty strings. */
1818 if (rpr
->rpr_operation
[0] != 0) {
1820 * Make sure that client did not send us an unterminated buffer.
1822 rpr
->rpr_operation
[sizeof (rpr
->rpr_operation
) - 1] = 0;
1823 if ((operation
= strdup(rpr
->rpr_operation
)) == NULL
)
1826 if (rpr
->rpr_file
[0] != 0) {
1828 * Make sure that client did not send us an unterminated buffer.
1830 rpr
->rpr_file
[sizeof (rpr
->rpr_file
) - 1] = 0;
1831 if ((file
= strdup(rpr
->rpr_file
)) == NULL
)
1835 (void) pthread_mutex_lock(&cp
->rc_annotate_lock
);
1836 /* Save addresses of memory to free when not locked */
1837 old_ptrs
[0] = cp
->rc_operation
;
1838 old_ptrs
[1] = cp
->rc_file
;
1840 /* Save pointers to annotation strings. */
1841 cp
->rc_operation
= operation
;
1845 * Set annotation flag. Annotations should be turned on if either
1846 * operation or file are not NULL.
1848 cp
->rc_annotate
= (operation
!= NULL
) || (file
!= NULL
);
1849 (void) pthread_mutex_unlock(&cp
->rc_annotate_lock
);
1852 * operation and file pointers are saved in cp, so don't free them
1857 rc
= REP_PROTOCOL_SUCCESS
;
1860 * Native builds are done to create svc.configd-native. This
1861 * program runs only on the Open Solaris build machines to create
1862 * the seed repository. Until the SMF auditing code is distributed
1863 * to the Open Solaris build machines, adt_get_unique_id() in the
1864 * following code is not a global function in libbsm. Hence the
1865 * following conditional compilation.
1867 #ifndef NATIVE_BUILD
1869 * Set the appropriate audit session id.
1871 if (cp
->rc_annotate
) {
1873 * We're starting a group of annotated audit events, so
1874 * create and set an audit session ID for this annotation.
1876 adt_get_auid(cp
->rc_adt_session
, &audit_uid
);
1877 sessionid
= adt_get_unique_id(audit_uid
);
1880 * Annotation is done so restore our client audit session
1883 sessionid
= cp
->rc_adt_sessionid
;
1885 adt_set_asid(cp
->rc_adt_session
, sessionid
);
1886 #endif /* NATIVE_BUILD */
1889 if (operation
!= NULL
)
1890 free((void *)operation
);
1893 free((void *)old_ptrs
[0]);
1894 free((void *)old_ptrs
[1]);
1899 * Determine if an annotation event needs to be generated. If it does
1900 * provide the operation and file name that should be used in the event.
1903 * 0 No annotation event needed or buffers are not large
1904 * enough. Either way an event should not be
1906 * 1 Generate annotation event.
1909 client_annotation_needed(char *operation
, size_t oper_sz
,
1910 char *file
, size_t file_sz
)
1912 thread_info_t
*ti
= thread_self();
1913 repcache_client_t
*cp
= ti
->ti_active_client
;
1916 (void) pthread_mutex_lock(&cp
->rc_annotate_lock
);
1917 if (cp
->rc_annotate
) {
1919 if (cp
->rc_operation
== NULL
) {
1923 if (strlcpy(operation
, cp
->rc_operation
, oper_sz
) >=
1925 /* Buffer overflow, so do not generate event */
1929 if (cp
->rc_file
== NULL
) {
1932 } else if (rc
== 1) {
1933 if (strlcpy(file
, cp
->rc_file
, file_sz
) >= file_sz
) {
1934 /* Buffer overflow, so do not generate event */
1939 (void) pthread_mutex_unlock(&cp
->rc_annotate_lock
);
1944 client_annotation_finished()
1946 thread_info_t
*ti
= thread_self();
1947 repcache_client_t
*cp
= ti
->ti_active_client
;
1949 (void) pthread_mutex_lock(&cp
->rc_annotate_lock
);
1950 cp
->rc_annotate
= 0;
1951 (void) pthread_mutex_unlock(&cp
->rc_annotate_lock
);
1954 #ifndef NATIVE_BUILD
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
);
2014 * Handle switch client request
2016 * This routine can return:
2018 * _PERMISSION_DENIED not enough privileges to do request.
2019 * _UNKNOWN file operation error (details written to
2021 * _SUCCESS switch operation is completed.
2022 * _BACKEND_ACCESS backend access fails.
2023 * _NO_RESOURCES out of memory.
2024 * _BACKEND_READONLY backend is not writable.
2026 static rep_protocol_responseid_t
2027 repository_switch(repcache_client_t
*cp
,
2028 struct rep_protocol_switch_request
*rpr
)
2030 rep_protocol_responseid_t result
;
2031 ucred_t
*uc
= get_ucred();
2033 if (!client_is_privileged() && (uc
== NULL
||
2034 ucred_geteuid(uc
) != 0)) {
2035 return (REP_PROTOCOL_FAIL_PERMISSION_DENIED
);
2038 (void) pthread_mutex_lock(&cp
->rc_lock
);
2039 if (rpr
->rpr_changeid
!= cp
->rc_changeid
) {
2040 if ((result
= backend_switch(rpr
->rpr_flag
)) ==
2041 REP_PROTOCOL_SUCCESS
)
2042 cp
->rc_changeid
= rpr
->rpr_changeid
;
2044 result
= REP_PROTOCOL_SUCCESS
;
2046 (void) pthread_mutex_unlock(&cp
->rc_lock
);
2051 typedef rep_protocol_responseid_t
protocol_simple_f(repcache_client_t
*cp
,
2056 simple_handler(repcache_client_t
*cp
, const void *in
, size_t insz
,
2057 void *out_arg
, size_t *outsz
, void *arg
)
2059 protocol_simple_f
*f
= (protocol_simple_f
*)arg
;
2060 rep_protocol_response_t
*out
= out_arg
;
2062 assert(*outsz
== sizeof (*out
));
2065 out
->rpr_response
= (*f
)(cp
, in
);
2068 typedef rep_protocol_responseid_t
protocol_simple_fd_f(repcache_client_t
*cp
,
2069 const void *rpr
, int *out_fd
);
2073 simple_fd_handler(repcache_client_t
*cp
, const void *in
, size_t insz
,
2074 void *out_arg
, size_t *outsz
, void *arg
, int *out_fd
)
2076 protocol_simple_fd_f
*f
= (protocol_simple_fd_f
*)arg
;
2077 rep_protocol_response_t
*out
= out_arg
;
2079 assert(*outsz
== sizeof (*out
));
2082 out
->rpr_response
= (*f
)(cp
, in
, out_fd
);
2085 typedef void protocol_handler_f(repcache_client_t
*, const void *in
,
2086 size_t insz
, void *out
, size_t *outsz
, void *arg
);
2088 typedef void protocol_handler_fdret_f(repcache_client_t
*, const void *in
,
2089 size_t insz
, void *out
, size_t *outsz
, void *arg
, int *fd_out
);
2091 #define PROTO(p, f, in) { \
2092 p, #p, simple_handler, (void *)(&f), NULL, \
2093 sizeof (in), sizeof (rep_protocol_response_t), 0 \
2096 #define PROTO_FD_OUT(p, f, in) { \
2097 p, #p, NULL, (void *)(&f), simple_fd_handler, \
2099 sizeof (rep_protocol_response_t), \
2103 #define PROTO_VARIN(p, f, insz) { \
2104 p, #p, &(f), NULL, NULL, \
2105 insz, sizeof (rep_protocol_response_t), \
2106 PROTO_FLAG_VARINPUT \
2109 #define PROTO_UINT_OUT(p, f, in) { \
2110 p, #p, &(f), NULL, NULL, \
2112 sizeof (struct rep_protocol_integer_response), 0 \
2115 #define PROTO_NAME_OUT(p, f, in) { \
2116 p, #p, &(f), NULL, NULL, \
2118 sizeof (struct rep_protocol_name_response), 0 \
2121 #define PROTO_FMRI_OUT(p, f, in) { \
2122 p, #p, &(f), NULL, NULL, \
2124 sizeof (struct rep_protocol_fmri_response), 0 \
2127 #define PROTO_VALUE_OUT(p, f, in) { \
2128 p, #p, &(f), NULL, NULL, \
2130 sizeof (struct rep_protocol_value_response), 0 \
2133 #define PROTO_PANIC(p) { p, #p, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC }
2134 #define PROTO_END() { 0, NULL, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC }
2136 #define PROTO_FLAG_PANIC 0x00000001 /* should never be called */
2137 #define PROTO_FLAG_VARINPUT 0x00000004 /* in_size is minimum size */
2138 #define PROTO_FLAG_RETFD 0x00000008 /* can also return an FD */
2140 #define PROTO_ALL_FLAGS 0x0000000f /* all flags */
2142 static struct protocol_entry
{
2143 enum rep_protocol_requestid pt_request
;
2144 const char *pt_name
;
2145 protocol_handler_f
*pt_handler
;
2147 protocol_handler_fdret_f
*pt_fd_handler
;
2151 } protocol_table
[] = {
2152 PROTO_PANIC(REP_PROTOCOL_CLOSE
), /* special case */
2154 PROTO(REP_PROTOCOL_ENTITY_SETUP
, entity_setup
,
2155 struct rep_protocol_entity_setup
),
2156 PROTO_NAME_OUT(REP_PROTOCOL_ENTITY_NAME
, entity_name
,
2157 struct rep_protocol_entity_name
),
2158 PROTO_UINT_OUT(REP_PROTOCOL_ENTITY_PARENT_TYPE
, entity_parent_type
,
2159 struct rep_protocol_entity_parent_type
),
2160 PROTO(REP_PROTOCOL_ENTITY_GET_CHILD
, entity_get_child
,
2161 struct rep_protocol_entity_get_child
),
2162 PROTO(REP_PROTOCOL_ENTITY_GET_PARENT
, entity_get_parent
,
2163 struct rep_protocol_entity_parent
),
2164 PROTO(REP_PROTOCOL_ENTITY_GET
, entity_get
,
2165 struct rep_protocol_entity_get
),
2166 PROTO(REP_PROTOCOL_ENTITY_UPDATE
, entity_update
,
2167 struct rep_protocol_entity_update
),
2168 PROTO(REP_PROTOCOL_ENTITY_CREATE_CHILD
, entity_create_child
,
2169 struct rep_protocol_entity_create_child
),
2170 PROTO(REP_PROTOCOL_ENTITY_CREATE_PG
, entity_create_pg
,
2171 struct rep_protocol_entity_create_pg
),
2172 PROTO(REP_PROTOCOL_ENTITY_DELETE
, entity_delete
,
2173 struct rep_protocol_entity_delete
),
2174 PROTO(REP_PROTOCOL_ENTITY_RESET
, entity_reset
,
2175 struct rep_protocol_entity_reset
),
2176 PROTO(REP_PROTOCOL_ENTITY_TEARDOWN
, entity_teardown
,
2177 struct rep_protocol_entity_teardown
),
2179 PROTO(REP_PROTOCOL_ITER_SETUP
, iter_setup
,
2180 struct rep_protocol_iter_request
),
2181 PROTO(REP_PROTOCOL_ITER_START
, iter_start
,
2182 struct rep_protocol_iter_start
),
2183 PROTO(REP_PROTOCOL_ITER_READ
, iter_read
,
2184 struct rep_protocol_iter_read
),
2185 PROTO_VALUE_OUT(REP_PROTOCOL_ITER_READ_VALUE
, iter_read_value
,
2186 struct rep_protocol_iter_read_value
),
2187 PROTO(REP_PROTOCOL_ITER_RESET
, iter_reset
,
2188 struct rep_protocol_iter_request
),
2189 PROTO(REP_PROTOCOL_ITER_TEARDOWN
, iter_teardown
,
2190 struct rep_protocol_iter_request
),
2192 PROTO(REP_PROTOCOL_NEXT_SNAPLEVEL
, next_snaplevel
,
2193 struct rep_protocol_entity_pair
),
2195 PROTO(REP_PROTOCOL_SNAPSHOT_TAKE
, snapshot_take
,
2196 struct rep_protocol_snapshot_take
),
2197 PROTO(REP_PROTOCOL_SNAPSHOT_TAKE_NAMED
, snapshot_take_named
,
2198 struct rep_protocol_snapshot_take_named
),
2199 PROTO(REP_PROTOCOL_SNAPSHOT_ATTACH
, snapshot_attach
,
2200 struct rep_protocol_snapshot_attach
),
2202 PROTO_UINT_OUT(REP_PROTOCOL_PROPERTY_GET_TYPE
, property_get_type
,
2203 struct rep_protocol_property_request
),
2204 PROTO_VALUE_OUT(REP_PROTOCOL_PROPERTY_GET_VALUE
, property_get_value
,
2205 struct rep_protocol_property_request
),
2207 PROTO_FD_OUT(REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT
, propertygrp_notify
,
2208 struct rep_protocol_propertygrp_request
),
2209 PROTO(REP_PROTOCOL_PROPERTYGRP_TX_START
, tx_start
,
2210 struct rep_protocol_transaction_start
),
2211 PROTO_VARIN(REP_PROTOCOL_PROPERTYGRP_TX_COMMIT
, tx_commit
,
2212 REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE
),
2214 PROTO(REP_PROTOCOL_CLIENT_ADD_NOTIFY
, client_add_notify
,
2215 struct rep_protocol_notify_request
),
2216 PROTO_FMRI_OUT(REP_PROTOCOL_CLIENT_WAIT
, client_wait
,
2217 struct rep_protocol_wait_request
),
2219 PROTO(REP_PROTOCOL_BACKUP
, backup_repository
,
2220 struct rep_protocol_backup_request
),
2222 PROTO(REP_PROTOCOL_SET_AUDIT_ANNOTATION
, set_annotation
,
2223 struct rep_protocol_annotation
),
2225 PROTO(REP_PROTOCOL_SWITCH
, repository_switch
,
2226 struct rep_protocol_switch_request
),
2231 #undef PROTO_FMRI_OUT
2232 #undef PROTO_NAME_OUT
2233 #undef PROTO_UINT_OUT
2238 * The number of entries, sans PROTO_END()
2240 #define PROTOCOL_ENTRIES \
2241 (sizeof (protocol_table) / sizeof (*protocol_table) - 1)
2243 #define PROTOCOL_PREFIX "REP_PROTOCOL_"
2249 struct protocol_entry
*e
;
2251 if (!client_hash_init())
2254 if (request_log_size
> 0) {
2255 request_log
= uu_zalloc(request_log_size
*
2256 sizeof (request_log_entry_t
));
2260 * update the names to not include REP_PROTOCOL_
2262 for (i
= 0; i
< PROTOCOL_ENTRIES
; i
++) {
2263 e
= &protocol_table
[i
];
2264 assert(strncmp(e
->pt_name
, PROTOCOL_PREFIX
,
2265 strlen(PROTOCOL_PREFIX
)) == 0);
2266 e
->pt_name
+= strlen(PROTOCOL_PREFIX
);
2269 * verify the protocol table is consistent
2271 for (i
= 0; i
< PROTOCOL_ENTRIES
; i
++) {
2272 e
= &protocol_table
[i
];
2273 assert(e
->pt_request
== (REP_PROTOCOL_BASE
+ i
));
2275 assert((e
->pt_flags
& ~PROTO_ALL_FLAGS
) == 0);
2277 if (e
->pt_flags
& PROTO_FLAG_PANIC
)
2278 assert(e
->pt_in_size
== 0 && e
->pt_out_max
== 0 &&
2279 e
->pt_handler
== NULL
);
2281 assert(e
->pt_in_size
!= 0 && e
->pt_out_max
!= 0 &&
2282 (e
->pt_handler
!= NULL
||
2283 e
->pt_fd_handler
!= NULL
));
2285 assert((REP_PROTOCOL_BASE
+ i
) == REP_PROTOCOL_MAX_REQUEST
);
2287 assert(protocol_table
[i
].pt_request
== 0);
2293 client_switcher(void *cookie
, char *argp
, size_t arg_size
, door_desc_t
*desc_in
,
2296 thread_info_t
*ti
= thread_self();
2298 repcache_client_t
*cp
;
2299 uint32_t id
= (uint32_t)cookie
;
2300 enum rep_protocol_requestid request_code
;
2302 rep_protocol_responseid_t result
= INVALID_RESULT
;
2304 struct protocol_entry
*e
;
2306 char *retval
= NULL
;
2311 request_log_entry_t
*rlp
;
2313 rlp
= start_log(id
);
2316 uu_die("can't happen: %d descriptors @%p (cookie %p)",
2317 n_desc
, desc_in
, cookie
);
2319 if (argp
== DOOR_UNREF_DATA
) {
2324 thread_newstate(ti
, TI_CLIENT_CALL
);
2327 * To simplify returning just a result code, we set up for
2330 retval
= (char *)&result
;
2331 retsize
= sizeof (result
);
2333 if (arg_size
< sizeof (request_code
)) {
2334 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
2338 ti
->ti_client_request
= (void *)argp
;
2340 /* LINTED alignment */
2341 request_code
= *(uint32_t *)argp
;
2344 rlp
->rl_request
= request_code
;
2347 * In order to avoid locking problems on removal, we handle the
2348 * "close" case before doing a lookup.
2350 if (request_code
== REP_PROTOCOL_CLOSE
) {
2352 result
= REP_PROTOCOL_SUCCESS
;
2356 cp
= client_lookup(id
);
2365 rlp
->rl_client
= cp
;
2367 ti
->ti_active_client
= cp
;
2369 if (request_code
< REP_PROTOCOL_BASE
||
2370 request_code
>= REP_PROTOCOL_BASE
+ PROTOCOL_ENTRIES
) {
2371 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
2375 e
= &protocol_table
[request_code
- REP_PROTOCOL_BASE
];
2377 assert(!(e
->pt_flags
& PROTO_FLAG_PANIC
));
2379 if (e
->pt_flags
& PROTO_FLAG_VARINPUT
) {
2380 if (arg_size
< e
->pt_in_size
) {
2381 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
2384 } else if (arg_size
!= e
->pt_in_size
) {
2385 result
= REP_PROTOCOL_FAIL_BAD_REQUEST
;
2389 if (retsize
!= e
->pt_out_max
) {
2390 retsize
= e
->pt_out_max
;
2391 retval
= alloca(retsize
);
2394 if (e
->pt_flags
& PROTO_FLAG_RETFD
)
2395 e
->pt_fd_handler(cp
, argp
, arg_size
, retval
, &retsize
,
2398 e
->pt_handler(cp
, argp
, arg_size
, retval
, &retsize
, e
->pt_arg
);
2401 ti
->ti_active_client
= NULL
;
2406 /* LINTED alignment */
2407 rlp
->rl_response
= *(uint32_t *)retval
;
2411 ti
->ti_client_request
= NULL
;
2412 thread_newstate(ti
, TI_DOOR_RETURN
);
2414 if (retval
== (char *)&result
) {
2415 assert(result
!= INVALID_RESULT
&& retsize
== sizeof (result
));
2417 /* LINTED alignment */
2418 result
= *(uint32_t *)retval
;
2421 desc
.d_attributes
= DOOR_DESCRIPTOR
| DOOR_RELEASE
;
2422 desc
.d_data
.d_desc
.d_descriptor
= retfd
;
2423 (void) door_return(retval
, retsize
, &desc
, 1);
2425 (void) door_return(retval
, retsize
, NULL
, 0);
2429 rlp
->rl_response
= -1;
2433 (void) door_return(NULL
, 0, NULL
, 0);
2437 create_client(pid_t pid
, uint32_t debugflags
, int privileged
, int *out_fd
)
2441 repcache_client_t
*cp
;
2443 struct door_info info
;
2445 int door_flags
= DOOR_UNREF
| DOOR_REFUSE_DESC
;
2446 #ifdef DOOR_NO_CANCEL
2447 door_flags
|= DOOR_NO_CANCEL
;
2450 cp
= client_alloc();
2452 return (REPOSITORY_DOOR_FAIL_NO_RESOURCES
);
2454 (void) pthread_mutex_lock(&client_lock
);
2455 cp
->rc_id
= ++client_maxid
;
2456 (void) pthread_mutex_unlock(&client_lock
);
2458 cp
->rc_all_auths
= privileged
;
2460 cp
->rc_debug
= debugflags
;
2462 #ifndef NATIVE_BUILD
2463 start_audit_session(cp
);
2466 cp
->rc_doorfd
= door_create(client_switcher
, (void *)cp
->rc_id
,
2469 if (cp
->rc_doorfd
< 0) {
2471 return (REPOSITORY_DOOR_FAIL_NO_RESOURCES
);
2473 #ifdef DOOR_PARAM_DATA_MIN
2474 (void) door_setparam(cp
->rc_doorfd
, DOOR_PARAM_DATA_MIN
,
2475 sizeof (enum rep_protocol_requestid
));
2478 if ((fd
= dup(cp
->rc_doorfd
)) < 0 ||
2479 door_info(cp
->rc_doorfd
, &info
) < 0) {
2482 (void) door_revoke(cp
->rc_doorfd
);
2485 return (REPOSITORY_DOOR_FAIL_NO_RESOURCES
);
2488 rc_pg_notify_init(&cp
->rc_pg_notify
);
2489 rc_notify_info_init(&cp
->rc_notify_info
);
2493 cp
->rc_doorid
= info
.di_uniquifier
;
2496 return (REPOSITORY_DOOR_SUCCESS
);