2 * Copyright (c) 1999-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
28 #include <mach/mach.h>
29 #include <servers/bootstrap.h>
39 #include "netdb_async.h"
40 #include "DSlibinfoMIG.h"
41 #include "DSlibinfoMIGAsyncReply.h"
43 #define MAX_LOOKUP_ATTEMPTS 10
44 #define _LU_MAXLUSTRLEN 256
45 #define QBUF_SIZE 16384
46 #define KVBUF_START_SIZE 128
48 #define LI_MESSAGE_SEND_ID 4241776
49 #define LI_MESSAGE_REPLY_ID 4241876
51 #define ILS_MAGIC_SIZE 8
52 #define ILS_MAGIC "ILSMAGIC"
54 #define L1_CACHE_NOTIFICATION_KEY_GLOBAL "com.apple.system.DirectoryService.InvalidateCache"
55 #define L1_CACHE_NOTIFICATION_KEY_GROUP "com.apple.system.DirectoryService.InvalidateCache.group"
56 #define L1_CACHE_NOTIFICATION_KEY_HOST "com.apple.system.DirectoryService.InvalidateCache.host"
57 #define L1_CACHE_NOTIFICATION_KEY_SERVICE "com.apple.system.DirectoryService.InvalidateCache.service"
58 #define L1_CACHE_NOTIFICATION_KEY_USER "com.apple.system.DirectoryService.InvalidateCache.user"
61 uint32_t gL1CacheEnabled
= 1;
63 static const uint32_t align_32
[] = { 0, 1, 2, 0, 4, 0, 0, 0, 4 };
64 static const uint32_t align_64
[] = { 0, 1, 2, 0, 4, 0, 0, 0, 8 };
66 static pthread_key_t _info_key
= 0;
67 static pthread_once_t _info_key_initialized
= PTHREAD_ONCE_INIT
;
69 static pthread_mutex_t _notify_lock
= PTHREAD_MUTEX_INITIALIZER
;
70 static int _L1_notify_token
[] =
86 typedef struct _li_async_request_s
88 mach_port_t reply_port
;
93 char request
[MAX_MIG_INLINE_DATA
];
94 mach_msg_type_number_t requestCnt
;
95 char reply
[MAX_MIG_INLINE_DATA
];
96 mach_msg_type_number_t replyCnt
;
98 mach_msg_type_number_t ooreplyCnt
;
99 security_token_t token
;
100 struct _li_async_request_s
*next
;
101 } _li_async_request_t
;
103 static pthread_mutex_t _li_worklist_lock
= PTHREAD_MUTEX_INITIALIZER
;
104 static _li_async_request_t
*_li_worklist
= NULL
;
106 /* Send an asynchronous query message. */
108 _LI_async_send(_li_async_request_t
*r
)
110 mach_msg_return_t status
;
111 mach_vm_address_t cb
;
113 if (r
== NULL
) return KERN_FAILURE
;
115 if (r
->retry
== 0) return MIG_SERVER_DIED
;
118 cb
= (mach_vm_address_t
)(r
->callback
);
119 status
= libinfoDSmig_Query_async(_ds_port
, r
->reply_port
, r
->proc
, r
->request
, r
->requestCnt
, cb
);
121 if (status
== MACH_SEND_INVALID_REPLY
)
123 mach_port_mod_refs(mach_task_self(), r
->reply_port
, MACH_PORT_RIGHT_RECEIVE
, -1);
124 r
->reply_port
= MACH_PORT_NULL
;
130 static _li_async_request_t
*
131 _LI_worklist_remove(mach_port_t p
)
133 _li_async_request_t
*r
, *n
;
135 if (p
== MACH_PORT_NULL
) return NULL
;
136 if (_li_worklist
== NULL
) return NULL
;
138 pthread_mutex_lock(&_li_worklist_lock
);
140 if (_li_worklist
->reply_port
== p
)
143 _li_worklist
= r
->next
;
144 pthread_mutex_unlock(&_li_worklist_lock
);
148 for (r
= _li_worklist
; r
!= NULL
; r
= r
->next
)
151 if (n
== NULL
) break;
153 if (n
->reply_port
== p
)
156 pthread_mutex_unlock(&_li_worklist_lock
);
161 pthread_mutex_unlock(&_li_worklist_lock
);
165 static _li_async_request_t
*
166 _LI_worklist_find(mach_port_t p
)
168 _li_async_request_t
*r
;
170 if (p
== MACH_PORT_NULL
) return NULL
;
171 if (_li_worklist
== NULL
) return NULL
;
173 pthread_mutex_lock(&_li_worklist_lock
);
175 for (r
= _li_worklist
; r
!= NULL
; r
= r
->next
)
177 if (r
->reply_port
== p
)
179 pthread_mutex_unlock(&_li_worklist_lock
);
184 pthread_mutex_unlock(&_li_worklist_lock
);
189 _LI_free_request(_li_async_request_t
*r
)
191 if (r
== NULL
) return;
193 if (r
->reply_port
!= MACH_PORT_NULL
) mach_port_mod_refs(mach_task_self(), r
->reply_port
, MACH_PORT_RIGHT_RECEIVE
, -1);
194 r
->reply_port
= MACH_PORT_NULL
;
200 * This is a callback for DSLibinfoMIGAsyncReplyServer.c
202 __private_extern__ kern_return_t
203 libinfoDSmig_do_Response_async(mach_port_t server
, char *reply
, mach_msg_type_number_t replyCnt
, vm_offset_t ooreply
, mach_msg_type_number_t ooreplyCnt
, mach_vm_address_t callbackAddr
, security_token_t servertoken
)
205 _li_async_request_t
*r
;
207 r
= _LI_worklist_find(server
);
211 r
->ooreply
= ooreply
;
212 r
->ooreplyCnt
= ooreplyCnt
;
213 if (replyCnt
> 0) memcpy(r
->reply
, reply
, replyCnt
);
214 r
->replyCnt
= replyCnt
;
215 r
->token
= servertoken
;
217 else if (ooreplyCnt
!= 0)
219 vm_deallocate(mach_task_self(), ooreply
, ooreplyCnt
);
225 /* Receive an asynchronous reply message. */
227 LI_async_receive(mach_port_t p
, kvarray_t
**reply
)
229 kern_return_t status
;
230 _li_async_request_t
*r
;
234 flags
= MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT
) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
);
236 /* use mach_msg_server_once to do the work here */
237 status
= mach_msg_server_once(DSlibinfoMIGAsyncReply_server
, 65536, p
, flags
);
239 if (status
!= KERN_SUCCESS
) return status
;
241 r
= _LI_worklist_remove(p
);
242 if (r
== NULL
) return KERN_FAILURE
;
244 out
= (kvbuf_t
*)calloc(1, sizeof(kvbuf_t
));
247 if (r
->ooreplyCnt
> 0) vm_deallocate(mach_task_self(), r
->ooreply
, r
->ooreplyCnt
);
251 if (r
->ooreplyCnt
> 0)
253 out
->datalen
= r
->ooreplyCnt
;
254 out
->databuf
= malloc(r
->ooreplyCnt
);
255 if (out
->databuf
== NULL
)
259 vm_deallocate(mach_task_self(), r
->ooreply
, r
->ooreplyCnt
);
263 memcpy(out
->databuf
, (char *)r
->ooreply
, r
->ooreplyCnt
);
264 vm_deallocate(mach_task_self(), r
->ooreply
, r
->ooreplyCnt
);
266 else if (r
->replyCnt
> 0)
268 out
->datalen
= r
->replyCnt
;
269 out
->databuf
= malloc(r
->replyCnt
);
270 if (out
->databuf
== NULL
)
277 memcpy(out
->databuf
, r
->reply
, r
->replyCnt
);
280 *reply
= kvbuf_decode(out
);
283 /* DS returned no data */
294 _LI_worklist_append(_li_async_request_t
*r
)
296 _li_async_request_t
*p
;
298 if (r
== NULL
) return;
300 pthread_mutex_lock(&_li_worklist_lock
);
302 if (_li_worklist
== NULL
)
305 pthread_mutex_unlock(&_li_worklist_lock
);
309 for (p
= _li_worklist
; p
->next
!= NULL
; p
= p
->next
);
312 pthread_mutex_unlock(&_li_worklist_lock
);
316 LI_async_call_cancel(mach_port_t p
, void **context
)
318 _li_async_request_t
*req
;
320 req
= _LI_worklist_remove(p
);
324 if (context
!= NULL
) *context
= req
->context
;
325 _LI_free_request(req
);
327 else if (p
!= MACH_PORT_NULL
)
329 mach_port_mod_refs(mach_task_self(), p
, MACH_PORT_RIGHT_RECEIVE
, -1);
334 lu_async_call_cancel(mach_port_t p
)
336 LI_async_call_cancel(p
, NULL
);
339 static _li_async_request_t
*
340 _LI_create_request(uint32_t proc
, kvbuf_t
*query
, void *callback
, void *context
)
342 _li_async_request_t
*r
;
343 kern_return_t status
;
346 if (_ds_running() == 0) return NULL
;
347 if (query
== NULL
) return NULL
;
348 if (query
->datalen
> MAX_MIG_INLINE_DATA
) return NULL
;
350 r
= (_li_async_request_t
*)calloc(1, sizeof(_li_async_request_t
));
351 if (r
== NULL
) return NULL
;
353 status
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &(r
->reply_port
));
354 if (status
!= KERN_SUCCESS
)
360 target
= MACH_PORT_NULL
;
362 /* Request no-senders notification so we can tell when server dies */
363 mach_port_request_notification(mach_task_self(), r
->reply_port
, MACH_NOTIFY_NO_SENDERS
, 1, r
->reply_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &target
);
365 r
->retry
= MAX_LOOKUP_ATTEMPTS
;
367 r
->context
= context
;
368 r
->callback
= callback
;
371 memcpy(r
->request
, query
->databuf
, query
->datalen
);
372 r
->requestCnt
= query
->datalen
;
380 LI_async_start(mach_port_t
*p
, uint32_t proc
, kvbuf_t
*query
, void *callback
, void *context
)
382 _li_async_request_t
*r
;
383 kern_return_t status
;
386 if (p
== NULL
) return KERN_FAILURE
;
390 if (_ds_running() == 0) return KERN_FAILURE
;
391 if (_ds_port
== MACH_PORT_NULL
) return KERN_FAILURE
;
393 /* Make a request struct to keep track */
394 r
= _LI_create_request(proc
, query
, callback
, context
);
395 if (r
== NULL
) return KERN_FAILURE
;
397 status
= MIG_SERVER_DIED
;
398 for (retry
= 0; (status
== MIG_SERVER_DIED
) && (retry
< MAX_LOOKUP_ATTEMPTS
); retry
++)
400 status
= _LI_async_send(r
);
403 if (status
!= KERN_SUCCESS
)
409 /* Add request to worklist */
410 _LI_worklist_append(r
);
418 LI_async_send(mach_port_t
*p
, uint32_t proc
, kvbuf_t
*query
)
420 return LI_async_start(p
, proc
, query
, NULL
, NULL
);
424 LI_async_handle_reply(mach_msg_header_t
*msg
, kvarray_t
**reply
, void **callback
, void **context
)
426 _li_async_request_t
*req
;
428 kern_return_t status
;
430 mig_reply_error_t
*bufReply
;
432 if (msg
== NULL
) return -1;
434 /* If reply status was an error, resend */
435 if (msg
->msgh_id
== MACH_NOTIFY_NO_SENDERS
)
438 req
= _LI_worklist_find(msg
->msgh_local_port
);
439 if (req
== NULL
) return -1;
441 status
= MIG_SERVER_DIED
;
442 for (retry
= 0; (status
== MIG_SERVER_DIED
) && (retry
< MAX_LOOKUP_ATTEMPTS
); retry
++)
445 status
= _LI_async_send(req
);
448 if (status
!= KERN_SUCCESS
) return -1;
450 return MIG_REPLY_MISMATCH
;
453 /* need to implement the msg_server_once type code here */
454 mach_msg_size_t reply_alloc
= round_page(65536 + MAX_TRAILER_SIZE
);
456 status
= vm_allocate(mach_task_self(), (vm_address_t
*) &bufReply
, reply_alloc
, VM_MAKE_TAG(VM_MEMORY_MACH_MSG
) | TRUE
);
457 if (status
!= KERN_SUCCESS
) return status
;
459 status
= DSlibinfoMIGAsyncReply_server(msg
, (mach_msg_header_t
*)bufReply
);
461 /* we just destroy the reply, because there isn't one */
462 if (bufReply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) mach_msg_destroy(&bufReply
->Head
);
464 vm_deallocate(mach_task_self(), (vm_address_t
) bufReply
, reply_alloc
);
466 if (status
== FALSE
) return KERN_FAILURE
;
468 req
= _LI_worklist_remove(msg
->msgh_local_port
);
469 if (req
== NULL
) return KERN_FAILURE
;
471 *callback
= req
->callback
;
472 *context
= req
->context
;
474 out
= (kvbuf_t
*)calloc(1, sizeof(kvbuf_t
));
477 if (req
->ooreplyCnt
> 0) vm_deallocate(mach_task_self(), req
->ooreply
, req
->ooreplyCnt
);
481 if (req
->ooreplyCnt
> 0)
483 out
->datalen
= req
->ooreplyCnt
;
484 out
->databuf
= malloc(req
->ooreplyCnt
);
485 if (out
->databuf
== NULL
)
489 vm_deallocate(mach_task_self(), req
->ooreply
, req
->ooreplyCnt
);
493 memcpy(out
->databuf
, (char *)req
->ooreply
, req
->ooreplyCnt
);
494 vm_deallocate(mach_task_self(), req
->ooreply
, req
->ooreplyCnt
);
496 else if (req
->replyCnt
> 0)
498 out
->datalen
= req
->replyCnt
;
499 out
->databuf
= malloc(req
->replyCnt
);
500 if (out
->databuf
== NULL
)
507 memcpy(out
->databuf
, req
->reply
, req
->replyCnt
);
510 *reply
= kvbuf_decode(out
);
513 /* DS returned no data */
518 _LI_free_request(req
);
524 _LI_thread_info_free(void *x
)
526 struct li_thread_info
*tdata
;
528 if (x
== NULL
) return;
530 tdata
= (struct li_thread_info
*)x
;
531 LI_ils_free(tdata
->li_entry
, tdata
->li_entry_size
);
532 LI_data_free_kvarray(tdata
);
538 _LI_data_free(void *x
)
540 struct _li_data_s
*t
;
543 if (x
== NULL
) return;
545 t
= (struct _li_data_s
*)x
;
547 for (i
= 0; i
< t
->icount
; i
++)
549 _LI_thread_info_free(t
->idata
[i
]);
553 if (t
->ikey
!= NULL
) free(t
->ikey
);
556 if (t
->idata
!= NULL
) free(t
->idata
);
565 pthread_key_create(&_info_key
, _LI_data_free
);
569 static struct _li_data_s
*
572 struct _li_data_s
*libinfo_data
;
575 * Only one thread should create the _info_key
577 pthread_once(&_info_key_initialized
, _LI_data_init
);
579 /* Check if this thread already created libinfo_data */
580 libinfo_data
= pthread_getspecific(_info_key
);
581 if (libinfo_data
!= NULL
) return libinfo_data
;
583 libinfo_data
= (struct _li_data_s
*)calloc(1, sizeof(struct _li_data_s
));
584 if (libinfo_data
== NULL
) return NULL
;
586 pthread_setspecific(_info_key
, libinfo_data
);
590 __private_extern__
void *
591 LI_data_find_key(uint32_t key
)
593 struct _li_data_s
*libinfo_data
;
596 libinfo_data
= _LI_data_get();
597 if (libinfo_data
== NULL
) return NULL
;
599 for (i
= 0; i
< libinfo_data
->icount
; i
++)
601 if (libinfo_data
->ikey
[i
] == key
) return libinfo_data
->idata
[i
];
607 __private_extern__
void *
608 LI_data_create_key(uint32_t key
, size_t esize
)
610 struct _li_data_s
*libinfo_data
;
611 struct li_thread_info
*tdata
;
614 libinfo_data
= _LI_data_get();
615 if (libinfo_data
== NULL
) return NULL
;
617 for (i
= 0; i
< libinfo_data
->icount
; i
++)
619 if (libinfo_data
->ikey
[i
] == key
) return libinfo_data
->idata
[i
];
622 i
= libinfo_data
->icount
;
627 libinfo_data
->ikey
= (uint32_t *)malloc(sizeof(uint32_t));
628 libinfo_data
->idata
= (void **)malloc(sizeof(void *));
632 libinfo_data
->ikey
= (uint32_t *)reallocf(libinfo_data
->ikey
, n
* sizeof(uint32_t));
633 libinfo_data
->idata
= (void **)reallocf(libinfo_data
->idata
, n
* sizeof(void *));
636 if ((libinfo_data
->ikey
== NULL
) || (libinfo_data
->idata
== NULL
))
638 if (libinfo_data
->ikey
!= NULL
) free(libinfo_data
->ikey
);
639 libinfo_data
->ikey
= NULL
;
641 if (libinfo_data
->idata
!= NULL
) free(libinfo_data
->idata
);
642 libinfo_data
->idata
= NULL
;
647 tdata
= (struct li_thread_info
*)calloc(1, sizeof(struct li_thread_info
));
648 if (tdata
== NULL
) return NULL
;
650 tdata
->li_entry_size
= esize
;
652 libinfo_data
->ikey
[i
] = key
;
653 libinfo_data
->idata
[i
] = tdata
;
654 libinfo_data
->icount
++;
660 _LI_data_index(uint32_t key
, struct _li_data_s
*libinfo_data
)
664 if (libinfo_data
== NULL
) return (uint32_t)-1;
666 for (i
= 0; i
< libinfo_data
->icount
; i
++)
668 if (libinfo_data
->ikey
[i
] == key
) return i
;
675 _LI_data_set_key(uint32_t key
, void *data
)
677 struct _li_data_s
*libinfo_data
;
680 libinfo_data
= _LI_data_get();
681 if (libinfo_data
== NULL
) return;
683 i
= _LI_data_index(key
, libinfo_data
);
684 if (i
== (uint32_t)-1) return;
686 libinfo_data
->idata
[i
] = data
;
690 _LI_data_get_key(uint32_t key
)
692 struct _li_data_s
*libinfo_data
;
695 libinfo_data
= _LI_data_get();
696 if (libinfo_data
== NULL
) return NULL
;
698 i
= _LI_data_index(key
, libinfo_data
);
699 if (i
== (uint32_t)-1) return NULL
;
701 return libinfo_data
->idata
[i
];
704 __private_extern__
void
705 LI_data_free_kvarray(struct li_thread_info
*tdata
)
707 if (tdata
== NULL
) return;
708 if (tdata
->li_vm
== NULL
) return;
710 kvarray_free((kvarray_t
*)tdata
->li_vm
);
714 __private_extern__
void
715 LI_data_recycle(struct li_thread_info
*tdata
, void *entry
, size_t entrysize
)
717 if (tdata
== NULL
) return;
719 LI_ils_free(tdata
->li_entry
, entrysize
);
720 tdata
->li_entry
= entry
;
723 #define KVBUF_CHUNK 256
726 * kvbuf_t is a list of key/value dictionaries.
728 * First 4 bytes are the number of dictionaries.
729 * For each dictionary, first 4 bytes is the key / value list count.
730 * For each value list, first 4 bytes is the list length.
731 * Keys and values are a 4-byte length followed by a nul-terminated string
733 * When the databuf needs to grow, we add memory in KVBUF_CHUNK size
734 * increments to reduce malloc / realloc activity.
735 * The _size variable stores the actual allocated size.
736 * The datalen variable stores the used data size.
738 * The _dict variable holds an offset from the start of the buffer
739 * to the "current" dictionary. kvbuf_reset() resets this,
740 * and kvbuf_next_dict() bumps the offset so that databuf + _dict
741 * points to the next dictionary.
743 * The _key variable holds an offset from the start of the buffer
744 * to the "current" key. kvbuf_reset() resets this, and
745 * kvbuf_next_key() bumps the offset so that databuf + _key
746 * points to the next key.
748 * The _val variable holds an offset from the start of the buffer
749 * to the "current" value. kvbuf_reset() resets this, and
750 * kvbuf_next_val() bumps the offset so that databuf + _val
751 * points to the next value.
753 * The cache_entry_list_to_kvbuf() routine contains the only
754 * code that builds an array.
759 * kvbuf_query is a simple utility for constructing a
760 * kvbuf with a single dictionary. The format string may
761 * contain the chars "k", "s", "i", and "u". "k" denotes a key
762 * (keys are always strings), "s" denotes a string value,
763 * "i" denotes a 32 bit signed int, and "u" denotes an unsigned.
765 __private_extern__ kvbuf_t
*
766 kvbuf_query(char *fmt
, ...)
769 char *arg
, *f
, str
[32];
774 if (fmt
== NULL
) return NULL
;
777 if (kv
== NULL
) return NULL
;
782 for (f
= fmt
; (*f
) != '\0'; f
++)
786 arg
= va_arg(ap
, char *);
787 kvbuf_add_key(kv
, arg
);
791 arg
= va_arg(ap
, char *);
792 kvbuf_add_val(kv
, arg
);
796 iarg
= va_arg(ap
, int32_t);
797 snprintf(str
, sizeof(str
), "%d", iarg
);
798 kvbuf_add_val(kv
, str
);
802 uarg
= va_arg(ap
,uint32_t);
803 snprintf(str
, sizeof(str
), "%u", uarg
);
804 kvbuf_add_val(kv
, str
);
812 __private_extern__ kvbuf_t
*
813 kvbuf_query_key_val(const char *key
, const char *val
)
816 uint32_t x
, kl
, vl
, vc
;
819 if (key
== NULL
) return NULL
;
821 kl
= strlen(key
) + 1;
828 vl
= strlen(val
) + 1;
832 kv
= (kvbuf_t
*)calloc(1, sizeof(kvbuf_t
));
833 if (kv
== NULL
) return NULL
;
835 kv
->_size
= (5 * sizeof(uint32_t)) + kl
+ vl
;
836 kv
->datalen
= kv
->_size
;
838 kv
->databuf
= calloc(1, kv
->_size
);
839 if (kv
->databuf
== NULL
)
849 memcpy(p
, &x
, sizeof(uint32_t));
850 p
+= sizeof(uint32_t);
853 memcpy(p
, &x
, sizeof(uint32_t));
854 p
+= sizeof(uint32_t);
858 memcpy(p
, &x
, sizeof(uint32_t));
859 p
+= sizeof(uint32_t);
865 /* number of values */
867 memcpy(p
, &x
, sizeof(uint32_t));
868 p
+= sizeof(uint32_t);
874 memcpy(p
, &x
, sizeof(uint32_t));
875 p
+= sizeof(uint32_t);
884 __private_extern__ kvbuf_t
*
885 kvbuf_query_key_int(const char *key
, int32_t i
)
889 snprintf(str
, sizeof(str
), "%d", i
);
890 return kvbuf_query_key_val(key
, str
);
893 __private_extern__ kvbuf_t
*
894 kvbuf_query_key_uint(const char *key
, uint32_t u
)
898 snprintf(str
, sizeof(str
), "%u", u
);
899 return kvbuf_query_key_val(key
, str
);
907 kv
= (kvbuf_t
*)calloc(1, sizeof(kvbuf_t
));
908 if (kv
== NULL
) return NULL
;
910 kv
->_size
= KVBUF_START_SIZE
;
911 kv
->databuf
= calloc(1, kv
->_size
);
912 if (kv
->databuf
== NULL
)
918 kv
->datalen
= sizeof(uint32_t);
919 kv
->_dict
= kv
->datalen
;
925 kvbuf_init(char *buffer
, uint32_t length
)
929 kv
= (kvbuf_t
*)calloc(1, sizeof(kvbuf_t
));
930 if (kv
== NULL
) return NULL
;
933 kv
->datalen
= length
;
934 kv
->databuf
= calloc(1, length
);
935 if (kv
->databuf
== NULL
)
942 memcpy(kv
->databuf
, buffer
, length
);
949 kvbuf_grow(kvbuf_t
*kv
, uint32_t delta
)
954 if (kv
== NULL
) return;
955 if (delta
== 0) return;
957 if (kv
->databuf
== NULL
) delta
+= sizeof(uint32_t);
959 n
= (delta
+ KVBUF_CHUNK
- 1) / KVBUF_CHUNK
;
960 newlen
= kv
->datalen
+ (n
* KVBUF_CHUNK
);
962 if (newlen
<= kv
->_size
) return;
966 if (kv
->databuf
== NULL
)
968 kv
->databuf
= calloc(1, kv
->_size
);
969 if (kv
->databuf
== NULL
)
971 memset(kv
, 0, sizeof(kvbuf_t
));
975 kv
->datalen
= sizeof(uint32_t);
976 kv
->_dict
= sizeof(uint32_t);
980 kv
->databuf
= reallocf(kv
->databuf
, kv
->_size
);
981 if (kv
->databuf
== NULL
)
983 memset(kv
, 0, sizeof(kvbuf_t
));
987 p
= kv
->databuf
+ kv
->datalen
;
988 memset(p
, 0, kv
->_size
- kv
->datalen
);
993 kvbuf_add_dict(kvbuf_t
*kv
)
996 uint32_t x
, dict_count
;
998 if (kv
== NULL
) return;
1000 /* Add a key count */
1001 kvbuf_grow(kv
, sizeof(uint32_t));
1002 if (kv
->databuf
== NULL
) return;
1004 kv
->_dict
= kv
->datalen
;
1005 kv
->datalen
+= sizeof(uint32_t);
1007 kv
->_key
= kv
->datalen
;
1011 /* increment and rewrite the dict count */
1015 memcpy(&x
, p
, sizeof(uint32_t));
1016 dict_count
= ntohl(x
);
1019 x
= htonl(dict_count
);
1020 memcpy(p
, &x
, sizeof(uint32_t));
1024 kvbuf_add_key(kvbuf_t
*kv
, const char *key
)
1026 uint32_t kl
, x
, key_count
, delta
;
1029 if (kv
== NULL
) return;
1030 if (key
== NULL
) return;
1032 kl
= strlen(key
) + 1;
1034 /* Grow to hold key len, key, and value list count. */
1035 delta
= (2 * sizeof(uint32_t)) + kl
;
1036 kvbuf_grow(kv
, delta
);
1038 if (kv
->databuf
== NULL
) return;
1040 /* increment and rewrite the key count for the current dictionary */
1041 p
= kv
->databuf
+ kv
->_dict
;
1044 memcpy(&x
, p
, sizeof(uint32_t));
1045 key_count
= ntohl(x
);
1047 if (key_count
== 0) kv
->_key
= kv
->_dict
+ sizeof(uint32_t);
1048 else kv
->_key
= kv
->datalen
;
1051 x
= htonl(key_count
);
1052 memcpy(p
, &x
, sizeof(uint32_t));
1054 /* append key to data buffer */
1055 p
= kv
->databuf
+ kv
->datalen
;
1058 memcpy(p
, &x
, sizeof(uint32_t));
1059 p
+= sizeof(uint32_t);
1063 kv
->_vlist
= kv
->datalen
+ sizeof(uint32_t) + kl
;
1066 memcpy(p
, &x
, sizeof(uint32_t));
1068 kv
->datalen
+= delta
;
1069 kv
->_val
= kv
->datalen
;
1073 kvbuf_add_val_len(kvbuf_t
*kv
, const char *val
, uint32_t len
)
1075 uint32_t x
, val_count
, delta
;
1078 if (kv
== NULL
) return;
1079 if (val
== NULL
) return;
1080 if (len
== 0) return;
1082 /* Grow to hold val len and value. */
1083 delta
= sizeof(uint32_t) + len
;
1084 kvbuf_grow(kv
, delta
);
1086 if (kv
->databuf
== NULL
) return;
1088 /* increment and rewrite the value count for the value_list dictionary */
1089 p
= kv
->databuf
+ kv
->_vlist
;
1092 memcpy(&x
, p
, sizeof(uint32_t));
1093 val_count
= ntohl(x
);
1095 x
= htonl(val_count
);
1096 memcpy(p
, &x
, sizeof(uint32_t));
1098 /* append val to data buffer */
1099 p
= kv
->databuf
+ kv
->_val
;
1102 memcpy(p
, &x
, sizeof(uint32_t));
1103 p
+= sizeof(uint32_t);
1104 memcpy(p
, val
, len
);
1107 kv
->datalen
+= delta
;
1108 kv
->_val
= kv
->datalen
;
1112 * WARNING! Kludge Alert!
1114 * This call just looks for the buffer length encoded into a serialized kvbuf_t,
1115 * which preceeds a pointer to a key or value. Obviously, calling it with anything
1116 * other than a pointer value which is embedded in a kvbuf_t is asking for trouble.
1119 kvbuf_get_len(const char *p
)
1124 memcpy(&x
, p
- sizeof(uint32_t), sizeof(uint32_t));
1129 kvbuf_add_val(kvbuf_t
*kv
, const char *val
)
1131 if (kv
== NULL
) return;
1132 if (val
== NULL
) return;
1134 kvbuf_add_val_len(kv
, val
, strlen(val
) + 1);
1138 kvbuf_free(kvbuf_t
*kv
)
1140 if (kv
== NULL
) return;
1141 if (kv
->databuf
!= NULL
) free(kv
->databuf
);
1142 memset(kv
, 0, sizeof(kvbuf_t
));
1146 /* appends a kvbuf to an existing kvbuf */
1148 kvbuf_append_kvbuf(kvbuf_t
*kv
, const kvbuf_t
*kv2
)
1150 uint32_t curr_count
, new_count
, temp
;
1152 if (kv
== NULL
) return;
1153 if (kv2
== NULL
) return;
1158 memcpy(&temp
, kv
->databuf
, sizeof(uint32_t));
1159 curr_count
= ntohl(temp
);
1161 memcpy(&temp
, kv2
->databuf
, sizeof(uint32_t));
1162 new_count
= ntohl(temp
);
1165 if (new_count
== 0) return;
1167 /* add the dictionary count to the current dictionary counts */
1168 curr_count
+= new_count
;
1170 temp
= htonl(curr_count
);
1171 memcpy(kv
->databuf
, &temp
, sizeof(uint32_t));
1173 /* grow the current buffer so we can append the new buffer */
1174 temp
= kv2
->datalen
- sizeof(uint32_t);
1176 kvbuf_grow(kv
, temp
);
1178 memcpy(kv
->databuf
+ kv
->datalen
, kv2
->databuf
+ sizeof(uint32_t), temp
);
1179 kv
->datalen
+= temp
;
1182 /* returns number of dictionaries */
1184 kvbuf_reset(kvbuf_t
*kv
)
1188 if (kv
== NULL
) return 0;
1189 if (kv
->databuf
== NULL
) return 0;
1196 if (kv
->datalen
< sizeof(uint32_t)) return 0;
1199 memcpy(&x
, kv
->databuf
, sizeof(uint32_t));
1203 /* advance to next dictionary, returns key count */
1205 kvbuf_next_dict(kvbuf_t
*kv
)
1207 uint32_t x
, k
, v
, kcount
, vcount
, kl
, vl
;
1210 if (kv
== NULL
) return 0;
1211 if (kv
->databuf
== NULL
) return 0;
1220 if (kv
->datalen
< sizeof(uint32_t)) return 0;
1221 kv
->_dict
= sizeof(uint32_t);
1223 if (kv
->datalen
< (kv
->_dict
+ sizeof(uint32_t))) return 0;
1225 p
= kv
->databuf
+ kv
->_dict
;
1227 memcpy(&x
, p
, sizeof(uint32_t));
1233 p
= kv
->databuf
+ kv
->_dict
;
1236 memcpy(&x
, p
, sizeof(uint32_t));
1237 p
+= sizeof(uint32_t);
1238 kv
->_dict
+= sizeof(uint32_t);
1241 for (k
= 0; k
< kcount
; k
++)
1244 memcpy(&x
, p
, sizeof(uint32_t));
1245 p
+= sizeof(uint32_t);
1246 kv
->_dict
+= sizeof(uint32_t);
1252 memcpy(&x
, p
, sizeof(uint32_t));
1253 p
+= sizeof(uint32_t);
1254 kv
->_dict
+= sizeof(uint32_t);
1257 for (v
= 0; v
< vcount
; v
++)
1260 memcpy(&x
, p
, sizeof(uint32_t));
1261 p
+= sizeof(uint32_t);
1262 kv
->_dict
+= sizeof(uint32_t);
1269 if (kv
->datalen
< (kv
->_dict
+ sizeof(uint32_t))) return 0;
1271 p
= kv
->databuf
+ kv
->_dict
;
1273 memcpy(&x
, p
, sizeof(uint32_t));
1279 /* advance to next key, returns key and sets val_count */
1281 kvbuf_next_key(kvbuf_t
*kv
, uint32_t *val_count
)
1283 uint32_t x
, kl
, v
, vl
, vc
;
1286 if (kv
== NULL
) return NULL
;
1287 if (val_count
== NULL
) return NULL
;
1291 if (kv
->databuf
== NULL
) return NULL
;
1292 if (kv
->_dict
== 0) return NULL
;
1300 if (kv
->datalen
< (kv
->_dict
+ sizeof(uint32_t))) return NULL
;
1301 kv
->_key
= kv
->_dict
+ sizeof(uint32_t);
1305 p
= kv
->databuf
+ kv
->_key
;
1308 memcpy(&x
, p
, sizeof(uint32_t));
1311 if (kv
->datalen
< (kv
->_key
+ sizeof(uint32_t) + kl
)) return NULL
;
1313 p
+= (sizeof(uint32_t) + kl
);
1314 kv
->_key
+= (sizeof(uint32_t) + kl
);
1316 /* skip over values */
1317 if (kv
->datalen
< (kv
->_key
+ sizeof(uint32_t))) return NULL
;
1320 memcpy(&x
, p
, sizeof(uint32_t));
1323 p
+= sizeof(uint32_t);
1324 kv
->_key
+= sizeof(uint32_t);
1326 for (v
= 0; v
< vc
; v
++)
1328 if (kv
->datalen
< (kv
->_key
+ sizeof(uint32_t))) return NULL
;
1331 memcpy(&x
, p
, sizeof(uint32_t));
1334 if (kv
->datalen
< (kv
->_key
+ kl
)) return NULL
;
1336 p
+= (sizeof(uint32_t) + vl
);
1337 kv
->_key
+= (sizeof(uint32_t) + vl
);
1341 if (kv
->datalen
< (kv
->_key
+ sizeof(uint32_t))) return NULL
;
1343 p
= kv
->databuf
+ kv
->_key
;
1345 memcpy(&x
, p
, sizeof(uint32_t));
1348 p
+= sizeof(uint32_t);
1351 kv
->_vlist
= kv
->_key
+ sizeof(uint32_t) + kl
;
1352 if (kv
->datalen
< (kv
->_vlist
+ sizeof(uint32_t)))
1358 p
= kv
->databuf
+ kv
->_vlist
;
1360 memcpy(&x
, p
, sizeof(uint32_t));
1361 *val_count
= ntohl(x
);
1367 kvbuf_next_val(kvbuf_t
*kv
)
1369 return kvbuf_next_val_len(kv
, NULL
);
1373 kvbuf_next_val_len(kvbuf_t
*kv
, uint32_t *len
)
1376 uint32_t vltemp
= 0;
1379 if (kv
== NULL
) return NULL
;
1380 if (kv
->databuf
== NULL
) return NULL
;
1381 if (kv
->_vlist
== 0) return NULL
;
1386 if (kv
->datalen
< (kv
->_vlist
+ sizeof(uint32_t))) return NULL
;
1387 kv
->_val
= kv
->_vlist
+ sizeof(uint32_t);
1389 p
= kv
->databuf
+ kv
->_val
;
1391 memcpy(&x
, p
, sizeof(uint32_t));
1396 p
= kv
->databuf
+ kv
->_val
;
1398 memcpy(&x
, p
, sizeof(uint32_t));
1401 if (kv
->datalen
< (kv
->_val
+ sizeof(uint32_t) + vltemp
)) return NULL
;
1403 p
+= (sizeof(uint32_t) + vltemp
);
1404 kv
->_val
+= (sizeof(uint32_t) + vltemp
);
1407 if (kv
->datalen
< (kv
->_val
+ sizeof(uint32_t))) return NULL
;
1409 if (len
!= NULL
) (*len
) = vltemp
;
1410 p
= kv
->databuf
+ kv
->_val
+ sizeof(uint32_t);
1415 * Builds a kvarray_t / kvdict_t structure on top of a kvbuf_t.
1416 * It allocates the appropriate number of kvdict_t structures
1417 * for the array, sets all the counters, and fills in pointers
1418 * for keys and valuse. The pointers are NOT to newly allocated
1419 * strings: they just point into the kvbuf data buffer.
1421 * To dispose of the kvarray_t and all of the associated
1422 * memory AND to free the original kvbuf, clients only
1423 * need to call kvarray_free().
1426 kvbuf_decode(kvbuf_t
*kv
)
1429 uint32_t x
, d
, k
, v
;
1432 if (kv
== NULL
) return NULL
;
1433 if (kv
->databuf
== NULL
) return NULL
;
1435 if (kv
->datalen
< sizeof(uint32_t)) return NULL
;
1438 kv
->_size
= kv
->datalen
;
1442 memcpy(&x
, p
, sizeof(uint32_t));
1443 p
+= sizeof(uint32_t);
1444 kv
->_size
-= sizeof(uint32_t);
1447 if (x
== 0) return NULL
;
1449 a
= (kvarray_t
*)calloc(1, sizeof(kvarray_t
));
1450 if (a
== NULL
) return NULL
;
1453 a
->dict
= (kvdict_t
*)calloc(a
->count
, sizeof(kvdict_t
));
1454 if (a
->dict
== NULL
)
1460 for (d
= 0; d
< a
->count
; d
++)
1462 if (kv
->_size
< sizeof(uint32_t))
1470 memcpy(&x
, p
, sizeof(uint32_t));
1471 p
+= sizeof(uint32_t);
1472 kv
->_size
-= sizeof(uint32_t);
1473 a
->dict
[d
].kcount
= ntohl(x
);
1475 if (a
->dict
[d
].kcount
> 0)
1477 a
->dict
[d
].key
= (const char **)calloc(a
->dict
[d
].kcount
, sizeof(const char *));
1478 if (a
->dict
[d
].key
== NULL
)
1484 a
->dict
[d
].vcount
= (uint32_t *)calloc(a
->dict
[d
].kcount
, sizeof(uint32_t));
1485 if (a
->dict
[d
].vcount
== NULL
)
1491 a
->dict
[d
].val
= (const char ***)calloc(a
->dict
[d
].kcount
, sizeof(char **));
1492 if (a
->dict
[d
].val
== NULL
)
1499 for (k
= 0; k
< a
->dict
[d
].kcount
; k
++)
1502 if (kv
->_size
< sizeof(uint32_t))
1510 memcpy(&x
, p
, sizeof(uint32_t));
1511 p
+= sizeof(uint32_t);
1512 kv
->_size
-= sizeof(uint32_t);
1522 a
->dict
[d
].key
[k
] = p
;
1527 if (kv
->_size
< sizeof(uint32_t))
1535 memcpy(&x
, p
, sizeof(uint32_t));
1536 p
+= sizeof(uint32_t);
1537 kv
->_size
-= sizeof(uint32_t);
1538 a
->dict
[d
].vcount
[k
] = ntohl(x
);
1540 if (a
->dict
[d
].vcount
[k
] > 0)
1542 /* N.B. we add a NULL pointer at the end of the list */
1543 a
->dict
[d
].val
[k
] = (const char **)calloc(a
->dict
[d
].vcount
[k
] + 1, sizeof(const char *));
1544 if (a
->dict
[d
].val
[k
] == NULL
)
1551 for (v
= 0; v
< a
->dict
[d
].vcount
[k
]; v
++)
1554 if (kv
->_size
< sizeof(uint32_t))
1562 memcpy(&x
, p
, sizeof(uint32_t));
1563 p
+= sizeof(uint32_t);
1564 kv
->_size
-= sizeof(uint32_t);
1574 a
->dict
[d
].val
[k
][v
] = p
;
1587 kvarray_free(kvarray_t
*a
)
1591 if (a
== NULL
) return;
1593 for (d
= 0; d
< a
->count
; d
++)
1595 for (k
= 0; k
< a
->dict
[d
].kcount
; k
++)
1597 if (a
->dict
[d
].val
== NULL
) continue;
1598 if (a
->dict
[d
].val
[k
] != NULL
) free(a
->dict
[d
].val
[k
]);
1601 if (a
->dict
[d
].key
!= NULL
) free(a
->dict
[d
].key
);
1602 if (a
->dict
[d
].vcount
!= NULL
) free(a
->dict
[d
].vcount
);
1603 if (a
->dict
[d
].val
!= NULL
) free(a
->dict
[d
].val
);
1608 if (a
->dict
!= NULL
) free(a
->dict
);
1611 if (a
->kv
!= NULL
) kvbuf_free(a
->kv
);
1618 LI_DSLookupGetProcedureNumber(const char *name
, int32_t *procno
)
1620 kern_return_t status
;
1621 security_token_t token
;
1624 if (name
== NULL
) return KERN_FAILURE
;
1626 len
= strlen(name
) + 1;
1627 if (len
== 1) return KERN_FAILURE
;
1632 if (_ds_running() == 0) return KERN_FAILURE
;
1633 if (_ds_port
== MACH_PORT_NULL
) return KERN_FAILURE
;
1635 status
= MIG_SERVER_DIED
;
1636 for (n
= 0; (_ds_port
!= MACH_PORT_NULL
) && (status
== MIG_SERVER_DIED
) && (n
< MAX_LOOKUP_ATTEMPTS
); n
++)
1638 status
= libinfoDSmig_GetProcedureNumber(_ds_port
, (char *)name
, procno
, &token
);
1640 if (status
== MACH_SEND_INVALID_DEST
)
1642 mach_port_mod_refs(mach_task_self(), _ds_port
, MACH_PORT_RIGHT_SEND
, -1);
1643 status
= bootstrap_look_up(bootstrap_port
, kDSStdMachDSLookupPortName
, &_ds_port
);
1644 if ((status
!= BOOTSTRAP_SUCCESS
) && (status
!= BOOTSTRAP_UNKNOWN_SERVICE
)) _ds_port
= MACH_PORT_NULL
;
1645 status
= MIG_SERVER_DIED
;
1649 if (status
!= KERN_SUCCESS
)
1652 asl_log(NULL
, NULL
, ASL_LEVEL_DEBUG
, "_DSLookupGetProcedureNumber %s status %u", name
, status
);
1657 if (token
.val
[0] != 0)
1660 asl_log(NULL
, NULL
, ASL_LEVEL_DEBUG
, "_DSLookupGetProcedureNumber %s auth failure uid=%d", name
, token
.val
[0]);
1662 return KERN_FAILURE
;
1666 asl_log(NULL
, NULL
, ASL_LEVEL_DEBUG
, "_DSLookupGetProcedureNumber %s = %d", name
, *procno
);
1671 __private_extern__ kern_return_t
1672 LI_DSLookupQuery(int32_t procno
, kvbuf_t
*request
, kvarray_t
**reply
)
1674 kern_return_t status
;
1675 security_token_t token
;
1677 mach_msg_type_number_t illen
, oolen
;
1678 char ilbuf
[MAX_MIG_INLINE_DATA
];
1682 if (reply
== NULL
) return KERN_FAILURE
;
1683 if ((request
!= NULL
) && ((request
->databuf
== NULL
) || (request
->datalen
== 0))) return KERN_FAILURE
;
1689 if (_ds_running() == 0) return KERN_FAILURE
;
1690 if (_ds_port
== MACH_PORT_NULL
) return KERN_FAILURE
;
1692 status
= MIG_SERVER_DIED
;
1693 for (n
= 0; (_ds_port
!= MACH_PORT_NULL
) && (status
== MIG_SERVER_DIED
) && (n
< MAX_LOOKUP_ATTEMPTS
); n
++)
1699 if (request
!= NULL
)
1701 status
= libinfoDSmig_Query(_ds_port
, procno
, request
->databuf
, request
->datalen
, ilbuf
, &illen
, &oobuf
, &oolen
, &token
);
1705 status
= libinfoDSmig_Query(_ds_port
, procno
, "", 0, ilbuf
, &illen
, &oobuf
, &oolen
, &token
);
1708 if (status
== MACH_SEND_INVALID_DEST
)
1710 mach_port_mod_refs(mach_task_self(), _ds_port
, MACH_PORT_RIGHT_SEND
, -1);
1711 status
= bootstrap_look_up(bootstrap_port
, kDSStdMachDSLookupPortName
, &_ds_port
);
1712 if ((status
!= BOOTSTRAP_SUCCESS
) && (status
!= BOOTSTRAP_UNKNOWN_SERVICE
)) _ds_port
= MACH_PORT_NULL
;
1713 status
= MIG_SERVER_DIED
;
1717 if (status
!= KERN_SUCCESS
)
1720 asl_log(NULL
, NULL
, ASL_LEVEL_DEBUG
, "_DSLookupQuery %d status %u", procno
, status
);
1725 if (token
.val
[0] != 0)
1728 asl_log(NULL
, NULL
, ASL_LEVEL_DEBUG
, "_DSLookupQuery %d auth failure uid=%d", procno
, token
.val
[0]);
1730 if (oolen
> 0) vm_deallocate(mach_task_self(), (vm_address_t
)oobuf
, oolen
);
1731 return KERN_FAILURE
;
1734 out
= (kvbuf_t
*)calloc(1, sizeof(kvbuf_t
));
1737 if (oolen
> 0) vm_deallocate(mach_task_self(), (vm_address_t
)oobuf
, oolen
);
1738 return KERN_FAILURE
;
1743 out
->datalen
= oolen
;
1744 out
->databuf
= malloc(oolen
);
1745 if (out
->databuf
== NULL
)
1749 vm_deallocate(mach_task_self(), (vm_address_t
)oobuf
, oolen
);
1750 return KERN_FAILURE
;
1753 memcpy(out
->databuf
, (char *)oobuf
, oolen
);
1754 vm_deallocate(mach_task_self(), (vm_address_t
)oobuf
, oolen
);
1758 out
->datalen
= illen
;
1759 out
->databuf
= malloc(illen
);
1760 if (out
->databuf
== NULL
)
1764 return KERN_FAILURE
;
1767 memcpy(out
->databuf
, ilbuf
, illen
);
1770 *reply
= kvbuf_decode(out
);
1773 /* DS returned no data */
1779 asl_log(NULL
, NULL
, ASL_LEVEL_DEBUG
, "_DSLookupQuery %d status OK", procno
);
1785 * Get an entry from a kvarray.
1786 * Calls the system information daemon if the list doesn't exist (first call),
1787 * or extracts the next entry if the list has been fetched.
1789 __private_extern__
void *
1790 LI_getent(const char *procname
, int *procnum
, void *(*extract
)(kvarray_t
*), int tkey
, size_t esize
)
1793 struct li_thread_info
*tdata
;
1795 kern_return_t status
;
1797 tdata
= LI_data_create_key(tkey
, esize
);
1798 if (tdata
== NULL
) return NULL
;
1800 if (tdata
->li_vm
== NULL
)
1804 status
= LI_DSLookupGetProcedureNumber(procname
, procnum
);
1805 if (status
!= KERN_SUCCESS
)
1807 LI_data_free_kvarray(tdata
);
1808 tdata
->li_vm
= NULL
;
1814 status
= LI_DSLookupQuery(*procnum
, NULL
, &reply
);
1816 if (status
!= KERN_SUCCESS
)
1818 LI_data_free_kvarray(tdata
);
1819 tdata
->li_vm
= NULL
;
1823 tdata
->li_vm
= (char *)reply
;
1826 entry
= extract((kvarray_t
*)(tdata
->li_vm
));
1829 LI_data_free_kvarray(tdata
);
1830 tdata
->li_vm
= NULL
;
1837 __private_extern__
void *
1838 LI_getone(const char *procname
, int *procnum
, void *(*extract
)(kvarray_t
*), const char *key
, const char *val
)
1843 kern_return_t status
;
1847 status
= LI_DSLookupGetProcedureNumber(procname
, procnum
);
1848 if (status
!= KERN_SUCCESS
) return NULL
;
1851 request
= kvbuf_query_key_val(key
, val
);
1852 if (request
== NULL
) return NULL
;
1855 status
= LI_DSLookupQuery(*procnum
, request
, &reply
);
1856 kvbuf_free(request
);
1858 if (status
!= KERN_SUCCESS
) return NULL
;
1860 entry
= extract(reply
);
1861 kvarray_free(reply
);
1867 int LI_L1_cache_check(int tkey
)
1870 const char *notify_key
;
1872 /* check if L1 cache is disabled */
1873 if (gL1CacheEnabled
== 0) return LI_L1_CACHE_DISABLED
;
1875 /* Initialize on first call */
1876 if (_L1_notify_token
[0] == -1)
1878 pthread_mutex_lock(&_notify_lock
);
1879 if (_L1_notify_token
[0] == -1) notify_register_check(L1_CACHE_NOTIFICATION_KEY_GLOBAL
, &(_L1_notify_token
[0]));
1880 pthread_mutex_unlock(&_notify_lock
);
1883 if (_L1_notify_token
[0] == -1) return LI_L1_CACHE_FAILED
;
1886 if (notify_check(_L1_notify_token
[0], &check
) != 0) return LI_L1_CACHE_FAILED
;
1887 if (check
== 1) return LI_L1_CACHE_STALE
;
1894 case _li_data_key_group
:
1897 notify_key
= L1_CACHE_NOTIFICATION_KEY_GROUP
;
1900 case _li_data_key_host
:
1903 notify_key
= L1_CACHE_NOTIFICATION_KEY_HOST
;
1906 case _li_data_key_service
:
1909 notify_key
= L1_CACHE_NOTIFICATION_KEY_SERVICE
;
1912 case _li_data_key_user
:
1915 notify_key
= L1_CACHE_NOTIFICATION_KEY_USER
;
1921 if ((x
!= 0) && (notify_key
!= NULL
))
1923 /* Initialize on first call */
1924 if (_L1_notify_token
[x
] == -1)
1926 pthread_mutex_lock(&_notify_lock
);
1927 if (_L1_notify_token
[x
] == -1) notify_register_check(notify_key
, &(_L1_notify_token
[x
]));
1928 pthread_mutex_unlock(&_notify_lock
);
1931 if (_L1_notify_token
[x
] == -1) return LI_L1_CACHE_FAILED
;
1934 if (notify_check(_L1_notify_token
[x
], &check
) != 0) return LI_L1_CACHE_FAILED
;
1935 if (check
== 1) return LI_L1_CACHE_STALE
;
1938 return LI_L1_CACHE_OK
;
1942 padsize(size_t curr
, size_t item
, const uint32_t *align
)
1946 if (item
> 8) item
= 8;
1949 if (na
== 0) return 0;
1952 if (diff
== 0) return 0;
1959 * Create a structure using in-line memory (i.e. all one blob).
1960 * This reduces malloc/free workload.
1962 * Structutre components may be strings, 1, 2, 4, or 8-byte values,
1963 * lists of strings, or lists of 4, 8, or 16-byte values.
1966 * s NUL terminated string
1971 * L long (32 or 64 bits, depending on architecture)
1972 * * NULL-terminated list of strings
1973 * a NULL-terminated list of 4-byte values
1974 * b NULL-terminated list of 8-byte values
1975 * c NULL-terminated list of 16-byte values
1978 __private_extern__
void *
1979 LI_ils_create(char *fmt
, ...)
1984 void *hp
, *dp
, *lp
, *ils
;
1987 uint32_t u32
, i
, pad
;
1990 size_t memsize
, hsize
, csize
, slen
, largest
;
1991 const uint32_t *align
;
1993 if (fmt
== NULL
) return NULL
;
1997 if (sizeof(char *) == 8) align
= align_64
;
1999 /* first pass: calculate size */
2000 memsize
= ILS_MAGIC_SIZE
;
2005 for (f
= fmt
; (*f
) != '\0'; f
++)
2012 if (largest
< sizeof(char *)) largest
= sizeof(char *);
2014 csize
= sizeof(char *) + padsize(hsize
, sizeof(char *), align
);
2015 arg
= va_arg(ap
, char *);
2016 if (arg
!= NULL
) slen
= strlen(arg
) + 1;
2020 if (largest
< 1) largest
= 1;
2023 u8
= va_arg(ap
, int);
2027 if (largest
< 2) largest
= 2;
2029 csize
= 2 + padsize(hsize
, 2, align
);
2030 u16
= va_arg(ap
, int);
2034 if (largest
< 4) largest
= 4;
2036 csize
= 4 + padsize(hsize
, 4, align
);
2037 u32
= va_arg(ap
, uint32_t);
2041 if (largest
< 8) largest
= 8;
2043 csize
= 8 + padsize(hsize
, 8, align
);
2044 u64
= va_arg(ap
, uint64_t);
2048 if (largest
< sizeof(unsigned long)) largest
= sizeof(unsigned long);
2050 csize
= sizeof(unsigned long) + padsize(hsize
, sizeof(unsigned long), align
);
2051 l
= va_arg(ap
, unsigned long);
2055 /* NULL-terminated list of strings */
2056 if (largest
< sizeof(char *)) largest
= sizeof(char *);
2058 csize
= sizeof(char *) + padsize(hsize
, sizeof(char *), align
);
2059 list
= va_arg(ap
, char **);
2062 for (i
= 0; list
[i
] != NULL
; i
++)
2064 slen
+= sizeof(char *);
2065 slen
+= (strlen(list
[i
]) + 1);
2068 slen
+= sizeof(char *);
2073 /* NULL-terminated list of 4-byte values */
2074 if (largest
< sizeof(char *)) largest
= sizeof(char *);
2076 csize
= sizeof(char *) + padsize(hsize
, sizeof(char *), align
);
2077 list
= va_arg(ap
, char **);
2080 for (i
= 0; list
[i
] != NULL
; i
++)
2082 slen
+= sizeof(char *);
2086 slen
+= sizeof(char *);
2091 /* NULL-terminated list of 8-byte values */
2092 if (largest
< sizeof(char *)) largest
= sizeof(char *);
2094 csize
= sizeof(char *) + padsize(hsize
, sizeof(char *), align
);
2095 list
= va_arg(ap
, char **);
2098 for (i
= 0; list
[i
] != NULL
; i
++)
2100 slen
+= sizeof(char *);
2104 slen
+= sizeof(char *);
2109 /* NULL-terminated list of 16-byte values */
2110 if (largest
< sizeof(char *)) largest
= sizeof(char *);
2112 csize
= sizeof(char *) + padsize(hsize
, sizeof(char *), align
);
2113 list
= va_arg(ap
, char **);
2116 for (i
= 0; list
[i
] != NULL
; i
++)
2118 slen
+= sizeof(char *);
2122 slen
+= sizeof(char *);
2134 pad
= padsize(hsize
, largest
, align
);
2138 ils
= malloc(memsize
);
2145 /* insert magic cookie */
2147 memcpy(dp
, ILS_MAGIC
, ILS_MAGIC_SIZE
);
2148 dp
+= ILS_MAGIC_SIZE
;
2153 /* second pass: copy data */
2155 for (f
= fmt
; (*f
) != '\0'; f
++)
2159 pad
= padsize(hsize
, sizeof(char *), align
);
2167 arg
= va_arg(ap
, char *);
2170 memset(hp
, 0, sizeof(char *));
2174 memcpy(hp
, &dp
, sizeof(char *));
2175 slen
= strlen(arg
) + 1;
2176 memcpy(dp
, arg
, slen
);
2180 hp
+= sizeof(char *);
2181 hsize
+= sizeof(char *);
2185 u8
= va_arg(ap
, int);
2186 memcpy(hp
, &u8
, sizeof(uint8_t));
2187 hp
+= sizeof(uint8_t);
2191 pad
= padsize(hsize
, 2, align
);
2199 u16
= va_arg(ap
, int);
2200 memcpy(hp
, &u16
, sizeof(uint16_t));
2202 hp
+= sizeof(uint16_t);
2203 hsize
+= sizeof(uint16_t);
2207 pad
= padsize(hsize
, 4, align
);
2215 u32
= va_arg(ap
, uint32_t);
2216 memcpy(hp
, &u32
, sizeof(uint32_t));
2218 hp
+= sizeof(uint32_t);
2219 hsize
+= sizeof(uint32_t);
2223 pad
= padsize(hsize
, 8, align
);
2231 u64
= va_arg(ap
, uint64_t);
2232 memcpy(hp
, &u64
, sizeof(uint64_t));
2234 hp
+= sizeof(uint64_t);
2235 hsize
+= sizeof(uint64_t);
2239 pad
= padsize(hsize
, sizeof(unsigned long), align
);
2247 l
= va_arg(ap
, unsigned long);
2248 memcpy(hp
, &l
, sizeof(unsigned long));
2250 hp
+= sizeof(unsigned long);
2251 hsize
+= sizeof(unsigned long);
2255 pad
= padsize(hsize
, sizeof(char *), align
);
2263 list
= va_arg(ap
, char **);
2267 memset(hp
, 0, sizeof(char *));
2271 memcpy(hp
, &dp
, sizeof(char *));
2273 for (i
= 0; list
[i
] != NULL
; i
++);
2276 dp
+= ((i
+ 1) * sizeof(char *));
2278 for (i
= 0; list
[i
] != NULL
; i
++)
2280 memcpy(lp
, &dp
, sizeof(char *));
2281 lp
+= sizeof(char *);
2282 slen
= strlen(list
[i
]) + 1;
2283 memcpy(dp
, list
[i
], slen
);
2287 memset(lp
, 0, sizeof(char *));
2290 hp
+= sizeof(char *);
2291 hsize
+= sizeof(char *);
2295 pad
= padsize(hsize
, sizeof(char *), align
);
2303 list
= va_arg(ap
, char **);
2307 memset(hp
, 0, sizeof(char *));
2311 memcpy(hp
, &dp
, sizeof(char *));
2313 for (i
= 0; list
[i
] != NULL
; i
++);
2316 dp
+= ((i
+ 1) * sizeof(char *));
2318 for (i
= 0; list
[i
] != NULL
; i
++)
2320 memcpy(lp
, &dp
, sizeof(char *));
2321 lp
+= sizeof(char *);
2323 memcpy(dp
, list
[i
], slen
);
2327 memset(lp
, 0, sizeof(char *));
2330 hp
+= sizeof(char *);
2331 hsize
+= sizeof(char *);
2335 pad
= padsize(hsize
, sizeof(char *), align
);
2343 list
= va_arg(ap
, char **);
2347 memset(hp
, 0, sizeof(char *));
2351 memcpy(hp
, &dp
, sizeof(char *));
2353 for (i
= 0; list
[i
] != NULL
; i
++);
2356 dp
+= ((i
+ 1) * sizeof(char *));
2358 for (i
= 0; list
[i
] != NULL
; i
++)
2360 memcpy(lp
, &dp
, sizeof(char *));
2361 lp
+= sizeof(char *);
2363 memcpy(dp
, list
[i
], slen
);
2367 memset(lp
, 0, sizeof(char *));
2370 hp
+= sizeof(char *);
2371 hsize
+= sizeof(char *);
2375 pad
= padsize(hsize
, sizeof(char *), align
);
2383 list
= va_arg(ap
, char **);
2387 memset(hp
, 0, sizeof(char *));
2391 memcpy(hp
, &dp
, sizeof(char *));
2393 for (i
= 0; list
[i
] != NULL
; i
++);
2396 dp
+= ((i
+ 1) * sizeof(char *));
2398 for (i
= 0; list
[i
] != NULL
; i
++)
2400 memcpy(lp
, &dp
, sizeof(char *));
2401 lp
+= sizeof(char *);
2403 memcpy(dp
, list
[i
], slen
);
2407 memset(lp
, 0, sizeof(char *));
2410 hp
+= sizeof(char *);
2411 hsize
+= sizeof(char *);
2417 pad
= padsize(hsize
, largest
, align
);
2418 if (pad
> 0) memset(hp
, 0, pad
);
2423 __private_extern__
int
2424 LI_ils_free(void *ils
, size_t len
)
2428 if (ils
== NULL
) return 0;
2431 if (memcmp(p
, ILS_MAGIC
, ILS_MAGIC_SIZE
) != 0) return -1;
2439 _lookup_link(mach_port_t server
, char *name
, int *procno
)
2441 syslog(LOG_ERR
, "RED ALERT! lookupd call %s from pid %u", name
, getpid());
2442 return KERN_FAILURE
;
2446 _lookup_one(mach_port_t server
, int proc
, char *indata
, mach_msg_type_number_t indataCnt
, char *outdata
, mach_msg_type_number_t
*outdataCnt
)
2448 return KERN_FAILURE
;
2452 _lookup_all(mach_port_t server
, int proc
, char *indata
, mach_msg_type_number_t indataCnt
, char **outdata
, mach_msg_type_number_t
*outdataCnt
)
2454 return KERN_FAILURE
;
2458 _lookup_ooall(mach_port_t server
, int proc
, char *indata
, mach_msg_type_number_t indataCnt
, char **outdata
, mach_msg_type_number_t
*outdataCnt
)
2460 return KERN_FAILURE
;